mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-08 19:20:12 +01:00
Implement basic opcode translation and storage translation.
This commit is contained in:
parent
fa2962d148
commit
3975f34fd3
5 changed files with 350 additions and 27 deletions
162
src/mesa/pipe/llvm/instructions.cpp
Normal file
162
src/mesa/pipe/llvm/instructions.cpp
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
#include "instructions.h"
|
||||
|
||||
#include <llvm/CallingConv.h>
|
||||
#include <llvm/Constants.h>
|
||||
#include <llvm/DerivedTypes.h>
|
||||
#include <llvm/InstrTypes.h>
|
||||
#include <llvm/Instructions.h>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
Instructions::Instructions(llvm::Module *mod, llvm::BasicBlock *block)
|
||||
: m_mod(mod), m_block(block), m_idx(0)
|
||||
{
|
||||
m_floatVecType = VectorType::get(Type::FloatTy, 4);
|
||||
m_llvmFSqrt = 0;
|
||||
m_llvmFAbs = 0;
|
||||
}
|
||||
|
||||
llvm::Value * Instructions::add(llvm::Value *in1, llvm::Value *in2)
|
||||
{
|
||||
BinaryOperator *res = BinaryOperator::create(Instruction::Add, in1, in2,
|
||||
name("add"),
|
||||
m_block);
|
||||
return res;
|
||||
}
|
||||
|
||||
llvm::Value * Instructions::madd(llvm::Value *in1, llvm::Value *in2,
|
||||
llvm::Value *in3)
|
||||
{
|
||||
Value *mulRes = mul(in1, in2);
|
||||
return add(mulRes, in3);
|
||||
}
|
||||
|
||||
llvm::Value * Instructions::mul(llvm::Value *in1, llvm::Value *in2)
|
||||
{
|
||||
BinaryOperator *res = BinaryOperator::create(Instruction::Mul, in1, in2,
|
||||
name("mul"),
|
||||
m_block);
|
||||
return res;
|
||||
}
|
||||
|
||||
const char * Instructions::name(const char *prefix)
|
||||
{
|
||||
++m_idx;
|
||||
snprintf(m_name, 32, "%s%d", prefix, m_idx);
|
||||
return m_name;
|
||||
}
|
||||
|
||||
llvm::Value * Instructions::dp3(llvm::Value *in1, llvm::Value *in2)
|
||||
{
|
||||
Value *mulRes = mul(in1, in2);
|
||||
ExtractElementInst *x = new ExtractElementInst(mulRes, unsigned(0),
|
||||
name("extractx"),
|
||||
m_block);
|
||||
ExtractElementInst *y = new ExtractElementInst(mulRes, unsigned(1),
|
||||
name("extracty"),
|
||||
m_block);
|
||||
ExtractElementInst *z = new ExtractElementInst(mulRes, unsigned(2),
|
||||
name("extractz"),
|
||||
m_block);
|
||||
BinaryOperator *xy = BinaryOperator::create(Instruction::Add, x, y,
|
||||
name("xy"),
|
||||
m_block);
|
||||
BinaryOperator *dot3 = BinaryOperator::create(Instruction::Add, xy, z,
|
||||
name("dot3"),
|
||||
m_block);
|
||||
return vectorFromVals(dot3, dot3, dot3, dot3);
|
||||
}
|
||||
|
||||
llvm::Value *Instructions::callFSqrt(llvm::Value *val)
|
||||
{
|
||||
if (!m_llvmFSqrt) {
|
||||
// predeclare the intrinsic
|
||||
std::vector<const Type*> fsqrtArgs;
|
||||
fsqrtArgs.push_back(Type::FloatTy);
|
||||
ParamAttrsList *fsqrtPal = 0;
|
||||
FunctionType* fsqrtType = FunctionType::get(
|
||||
/*Result=*/Type::FloatTy,
|
||||
/*Params=*/fsqrtArgs,
|
||||
/*isVarArg=*/false,
|
||||
/*ParamAttrs=*/fsqrtPal);
|
||||
m_llvmFSqrt = new Function(
|
||||
/*Type=*/fsqrtType,
|
||||
/*Linkage=*/GlobalValue::ExternalLinkage,
|
||||
/*Name=*/"llvm.sqrt.f32", m_mod);
|
||||
m_llvmFSqrt->setCallingConv(CallingConv::C);
|
||||
}
|
||||
CallInst *call = new CallInst(m_llvmFSqrt, val,
|
||||
name("sqrt"),
|
||||
m_block);
|
||||
call->setCallingConv(CallingConv::C);
|
||||
call->setTailCall(false);
|
||||
return call;
|
||||
}
|
||||
|
||||
llvm::Value * Instructions::rsq(llvm::Value *in1)
|
||||
{
|
||||
ExtractElementInst *x = new ExtractElementInst(in1, unsigned(0),
|
||||
name("extractx"),
|
||||
m_block);
|
||||
Value *abs = callFAbs(x);
|
||||
Value *sqrt = callFSqrt(abs);
|
||||
|
||||
BinaryOperator *rsqrt = BinaryOperator::create(Instruction::FDiv,
|
||||
ConstantFP::get(Type::FloatTy,
|
||||
APFloat(1.f)),
|
||||
sqrt,
|
||||
name("rsqrt"),
|
||||
m_block);
|
||||
return vectorFromVals(rsqrt, rsqrt, rsqrt, rsqrt);
|
||||
}
|
||||
|
||||
llvm::Value * Instructions::vectorFromVals(llvm::Value *x, llvm::Value *y,
|
||||
llvm::Value *z, llvm::Value *w)
|
||||
{
|
||||
Constant *const_vec = Constant::getNullValue(m_floatVecType);
|
||||
InsertElementInst *res = new InsertElementInst(const_vec, x, unsigned(0),
|
||||
name("vecx"), m_block);
|
||||
res = new InsertElementInst(res, y, unsigned(1),
|
||||
name("vecxy"),
|
||||
m_block);
|
||||
res = new InsertElementInst(res, z, unsigned(2),
|
||||
name("vecxyz"),
|
||||
m_block);
|
||||
if (w)
|
||||
res = new InsertElementInst(res, w, unsigned(3),
|
||||
name("vecxyw"),
|
||||
m_block);
|
||||
return res;
|
||||
}
|
||||
|
||||
llvm::Value *Instructions::callFAbs(llvm::Value *val)
|
||||
{
|
||||
if (!m_llvmFAbs) {
|
||||
// predeclare the intrinsic
|
||||
std::vector<const Type*> fabsArgs;
|
||||
fabsArgs.push_back(Type::FloatTy);
|
||||
ParamAttrsList *fabsPal = 0;
|
||||
FunctionType* fabsType = FunctionType::get(
|
||||
/*Result=*/Type::FloatTy,
|
||||
/*Params=*/fabsArgs,
|
||||
/*isVarArg=*/false,
|
||||
/*ParamAttrs=*/fabsPal);
|
||||
m_llvmFAbs = new Function(
|
||||
/*Type=*/fabsType,
|
||||
/*Linkage=*/GlobalValue::ExternalLinkage,
|
||||
/*Name=*/"fabs", m_mod);
|
||||
m_llvmFAbs->setCallingConv(CallingConv::C);
|
||||
}
|
||||
CallInst *call = new CallInst(m_llvmFAbs, val,
|
||||
name("fabs"),
|
||||
m_block);
|
||||
call->setCallingConv(CallingConv::C);
|
||||
call->setTailCall(false);
|
||||
return call;
|
||||
}
|
||||
|
||||
llvm::Value * Instructions::lit(llvm::Value *in1)
|
||||
{
|
||||
return in1;
|
||||
}
|
||||
|
||||
43
src/mesa/pipe/llvm/instructions.h
Normal file
43
src/mesa/pipe/llvm/instructions.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef INSTRUCTIONS_H
|
||||
#define INSTRUCTIONS_H
|
||||
|
||||
#include <llvm/BasicBlock.h>
|
||||
#include <llvm/Module.h>
|
||||
#include <llvm/Value.h>
|
||||
|
||||
namespace llvm {
|
||||
class VectorType;
|
||||
}
|
||||
|
||||
class Instructions
|
||||
{
|
||||
public:
|
||||
Instructions(llvm::Module *mod, llvm::BasicBlock *block);
|
||||
|
||||
llvm::Value *add(llvm::Value *in1, llvm::Value *in2);
|
||||
llvm::Value *dp3(llvm::Value *in1, llvm::Value *in2);
|
||||
llvm::Value *lit(llvm::Value *in1);
|
||||
llvm::Value *madd(llvm::Value *in1, llvm::Value *in2,
|
||||
llvm::Value *in2);
|
||||
llvm::Value *mul(llvm::Value *in1, llvm::Value *in2);
|
||||
llvm::Value *rsq(llvm::Value *in1);
|
||||
private:
|
||||
const char *name(const char *prefix);
|
||||
|
||||
llvm::Value *callFSqrt(llvm::Value *val);
|
||||
llvm::Value *callFAbs(llvm::Value *val);
|
||||
|
||||
llvm::Value *vectorFromVals(llvm::Value *x, llvm::Value *y,
|
||||
llvm::Value *z, llvm::Value *w=0);
|
||||
private:
|
||||
llvm::Module *m_mod;
|
||||
char m_name[32];
|
||||
llvm::BasicBlock *m_block;
|
||||
int m_idx;
|
||||
llvm::Function *m_llvmFSqrt;
|
||||
llvm::Function *m_llvmFAbs;
|
||||
|
||||
llvm::VectorType *m_floatVecType;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
#include <llvm/Bitcode/ReaderWriter.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "instructions.h"
|
||||
using namespace llvm;
|
||||
#include "llvm_base_shader.cpp"
|
||||
#include "tgsillvmbuilder.cpp"
|
||||
|
|
@ -117,31 +118,82 @@ translate_immediate(llvm::Module *module,
|
|||
|
||||
static void
|
||||
translate_instruction(llvm::Module *module,
|
||||
VertexShaderBuilder *builder,
|
||||
Storage *storage,
|
||||
Instructions *instr,
|
||||
struct tgsi_full_instruction *inst,
|
||||
struct tgsi_full_instruction *fi)
|
||||
{
|
||||
llvm::Value *inputs[4];
|
||||
for (int i = 0; i < inst->Instruction.NumSrcRegs; ++i) {
|
||||
struct tgsi_full_src_register *src = &inst->FullSrcRegisters[i];
|
||||
llvm::Value *val = 0;
|
||||
if (src->SrcRegister.File == TGSI_FILE_CONSTANT) {
|
||||
val = storage->constElement(src->SrcRegister.Index);
|
||||
} else if (src->SrcRegister.File == TGSI_FILE_INPUT) {
|
||||
val = storage->inputElement(src->SrcRegister.Index);
|
||||
} else if (src->SrcRegister.File == TGSI_FILE_TEMPORARY) {
|
||||
val = storage->tempElement(src->SrcRegister.Index);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: not support llvm source\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (src->SrcRegister.Extended) {
|
||||
if (src->SrcRegisterExtSwz.ExtSwizzleX != TGSI_EXTSWIZZLE_X ||
|
||||
src->SrcRegisterExtSwz.ExtSwizzleY != TGSI_EXTSWIZZLE_Y ||
|
||||
src->SrcRegisterExtSwz.ExtSwizzleZ != TGSI_EXTSWIZZLE_Z ||
|
||||
src->SrcRegisterExtSwz.ExtSwizzleW != TGSI_EXTSWIZZLE_W) {
|
||||
int swizzle = src->SrcRegisterExtSwz.ExtSwizzleX * 1000;
|
||||
swizzle += src->SrcRegisterExtSwz.ExtSwizzleY * 100;
|
||||
swizzle += src->SrcRegisterExtSwz.ExtSwizzleZ * 10;
|
||||
swizzle += src->SrcRegisterExtSwz.ExtSwizzleW * 1;
|
||||
val = storage->shuffleVector(val, swizzle);
|
||||
}
|
||||
} else if (src->SrcRegister.SwizzleX != TGSI_SWIZZLE_X ||
|
||||
src->SrcRegister.SwizzleY != TGSI_SWIZZLE_Y ||
|
||||
src->SrcRegister.SwizzleZ != TGSI_SWIZZLE_Z ||
|
||||
src->SrcRegister.SwizzleW != TGSI_SWIZZLE_W) {
|
||||
int swizzle = src->SrcRegister.SwizzleX * 1000;
|
||||
swizzle += src->SrcRegister.SwizzleY * 100;
|
||||
swizzle += src->SrcRegister.SwizzleZ * 10;
|
||||
swizzle += src->SrcRegister.SwizzleW * 1;
|
||||
val = storage->shuffleVector(val, swizzle);
|
||||
}
|
||||
inputs[i] = val;
|
||||
}
|
||||
|
||||
llvm::Value *out = 0;
|
||||
switch (inst->Instruction.Opcode) {
|
||||
case TGSI_OPCODE_ARL:
|
||||
break;
|
||||
case TGSI_OPCODE_MOV:
|
||||
case TGSI_OPCODE_MOV: {
|
||||
out = inputs[0];
|
||||
}
|
||||
break;
|
||||
case TGSI_OPCODE_LIT:
|
||||
case TGSI_OPCODE_LIT: {
|
||||
//out = instr->lit(inputs[0]);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TGSI_OPCODE_RCP:
|
||||
break;
|
||||
case TGSI_OPCODE_RSQ:
|
||||
case TGSI_OPCODE_RSQ: {
|
||||
out = instr->rsq(inputs[0]);
|
||||
}
|
||||
break;
|
||||
case TGSI_OPCODE_EXP:
|
||||
break;
|
||||
case TGSI_OPCODE_LOG:
|
||||
break;
|
||||
case TGSI_OPCODE_MUL:
|
||||
|
||||
case TGSI_OPCODE_MUL: {
|
||||
out = instr->mul(inputs[0], inputs[1]);
|
||||
}
|
||||
break;
|
||||
case TGSI_OPCODE_ADD:
|
||||
break;
|
||||
case TGSI_OPCODE_DP3:
|
||||
case TGSI_OPCODE_DP3: {
|
||||
out = instr->dp3(inputs[0], inputs[1]);
|
||||
}
|
||||
break;
|
||||
case TGSI_OPCODE_DP4:
|
||||
break;
|
||||
|
|
@ -155,7 +207,9 @@ translate_instruction(llvm::Module *module,
|
|||
break;
|
||||
case TGSI_OPCODE_SGE:
|
||||
break;
|
||||
case TGSI_OPCODE_MAD:
|
||||
case TGSI_OPCODE_MAD: {
|
||||
out = instr->madd(inputs[0], inputs[1], inputs[2]);
|
||||
}
|
||||
break;
|
||||
case TGSI_OPCODE_SUB:
|
||||
break;
|
||||
|
|
@ -400,6 +454,7 @@ translate_instruction(llvm::Module *module,
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
switch( inst->Instruction.Saturate ) {
|
||||
case TGSI_SAT_NONE:
|
||||
break;
|
||||
|
|
@ -412,6 +467,31 @@ translate_instruction(llvm::Module *module,
|
|||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
|
||||
for (int i = 0; i < inst->Instruction.NumDstRegs; ++i) {
|
||||
struct tgsi_full_dst_register *dst = &inst->FullDstRegisters[i];
|
||||
|
||||
if (dst->DstRegister.File == TGSI_FILE_OUTPUT) {
|
||||
storage->store(dst->DstRegister.Index, out);
|
||||
} else if (dst->DstRegister.File == TGSI_FILE_TEMPORARY) {
|
||||
storage->setTempElement(dst->DstRegister.Index, out);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: unsupported LLVM destination!");
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (dst->DstRegister.WriteMask != TGSI_WRITEMASK_XYZW) {
|
||||
if (dst->DstRegister.WriteMask & TGSI_WRITEMASK_X) {
|
||||
}
|
||||
if (dst->DstRegister.WriteMask & TGSI_WRITEMASK_Y) {
|
||||
}
|
||||
if (dst->DstRegister.WriteMask & TGSI_WRITEMASK_Z) {
|
||||
}
|
||||
if (dst->DstRegister.WriteMask & TGSI_WRITEMASK_W) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -450,7 +530,8 @@ tgsi_to_llvm(const struct tgsi_token *tokens)
|
|||
|
||||
fi = tgsi_default_full_instruction();
|
||||
fd = tgsi_default_full_declaration();
|
||||
VertexShaderBuilder builder(label_entry, ptr_IN, ptr_CONST);
|
||||
Storage storage(label_entry, ptr_OUT, ptr_IN, ptr_CONST);
|
||||
Instructions instr(mod, label_entry);
|
||||
while(!tgsi_parse_end_of_tokens(&parse)) {
|
||||
tgsi_parse_token(&parse);
|
||||
|
||||
|
|
@ -469,7 +550,7 @@ tgsi_to_llvm(const struct tgsi_token *tokens)
|
|||
break;
|
||||
|
||||
case TGSI_TOKEN_TYPE_INSTRUCTION:
|
||||
translate_instruction(mod, &builder,
|
||||
translate_instruction(mod, &storage, &instr,
|
||||
&parse.FullToken.FullInstruction,
|
||||
&fi);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,41 +1,52 @@
|
|||
|
||||
#include <map>
|
||||
|
||||
class VertexShaderBuilder
|
||||
class Storage
|
||||
{
|
||||
typedef std::map<int, llvm::LoadInst*> LoadMap;
|
||||
public:
|
||||
VertexShaderBuilder(llvm::BasicBlock *block, llvm::Value *in, llvm::Value *consts);
|
||||
Storage(llvm::BasicBlock *block,
|
||||
llvm::Value *out,
|
||||
llvm::Value *in, llvm::Value *consts);
|
||||
|
||||
llvm::ConstantInt *constantInt(int);
|
||||
llvm::Constant *shuffleMask(int vec);
|
||||
llvm::Value *inputElement(int idx);
|
||||
llvm::Value *constElement(int idx);
|
||||
|
||||
llvm::Value *tempElement(int idx) const;
|
||||
void setTempElement(int idx, llvm::Value *val);
|
||||
|
||||
llvm::Value *shuffleVector(llvm::Value *vec, int shuffle);
|
||||
|
||||
|
||||
void store(int dstIdx, llvm::Value *val);
|
||||
private:
|
||||
llvm::BasicBlock *m_block;
|
||||
llvm::Value *m_OUT;
|
||||
llvm::Value *m_IN;
|
||||
llvm::Value *m_CONST;
|
||||
|
||||
std::map<int, llvm::ConstantInt*> m_constInts;
|
||||
std::map<int, llvm::Constant*> m_intVecs;
|
||||
LoadMap m_inputs;
|
||||
LoadMap m_consts;
|
||||
std::map<int, llvm::Constant*> m_intVecs;
|
||||
std::vector<llvm::Value*> m_temps;
|
||||
LoadMap m_inputs;
|
||||
LoadMap m_consts;
|
||||
|
||||
VectorType *m_floatVecType;
|
||||
VectorType *m_intVecType;
|
||||
llvm::VectorType *m_floatVecType;
|
||||
llvm::VectorType *m_intVecType;
|
||||
|
||||
Value *m_undefFloatVec;
|
||||
Value *m_undefIntVec;
|
||||
llvm::Value *m_undefFloatVec;
|
||||
llvm::Value *m_undefIntVec;
|
||||
|
||||
int m_shuffleId;
|
||||
};
|
||||
|
||||
VertexShaderBuilder::VertexShaderBuilder(llvm::BasicBlock *block, llvm::Value *in, llvm::Value *consts)
|
||||
: m_block(block), m_IN(in), m_CONST(consts)
|
||||
Storage::Storage(llvm::BasicBlock *block, llvm::Value *out,
|
||||
llvm::Value *in, llvm::Value *consts)
|
||||
: m_block(block), m_OUT(out),
|
||||
m_IN(in), m_CONST(consts),
|
||||
m_temps(32)
|
||||
{
|
||||
m_floatVecType = VectorType::get(Type::FloatTy, 4);
|
||||
m_intVecType = VectorType::get(IntegerType::get(32), 4);
|
||||
|
|
@ -47,7 +58,7 @@ VertexShaderBuilder::VertexShaderBuilder(llvm::BasicBlock *block, llvm::Value *i
|
|||
}
|
||||
|
||||
//can only build vectors with all members in the [0, 9] range
|
||||
llvm::Constant *VertexShaderBuilder::shuffleMask(int vec)
|
||||
llvm::Constant *Storage::shuffleMask(int vec)
|
||||
{
|
||||
if (m_intVecs.find(vec) != m_intVecs.end()) {
|
||||
return m_intVecs[vec];
|
||||
|
|
@ -73,7 +84,7 @@ llvm::Constant *VertexShaderBuilder::shuffleMask(int vec)
|
|||
return const_vec;
|
||||
}
|
||||
|
||||
llvm::ConstantInt *VertexShaderBuilder::constantInt(int idx)
|
||||
llvm::ConstantInt *Storage::constantInt(int idx)
|
||||
{
|
||||
if (m_constInts.find(idx) != m_constInts.end()) {
|
||||
return m_constInts[idx];
|
||||
|
|
@ -83,7 +94,7 @@ llvm::ConstantInt *VertexShaderBuilder::constantInt(int idx)
|
|||
return const_int;
|
||||
}
|
||||
|
||||
llvm::Value *VertexShaderBuilder::inputElement(int idx)
|
||||
llvm::Value *Storage::inputElement(int idx)
|
||||
{
|
||||
if (m_inputs.find(idx) != m_inputs.end()) {
|
||||
return m_inputs[idx];
|
||||
|
|
@ -102,7 +113,7 @@ llvm::Value *VertexShaderBuilder::inputElement(int idx)
|
|||
return load;
|
||||
}
|
||||
|
||||
llvm::Value *VertexShaderBuilder::constElement(int idx)
|
||||
llvm::Value *Storage::constElement(int idx)
|
||||
{
|
||||
if (m_consts.find(idx) != m_consts.end()) {
|
||||
return m_consts[idx];
|
||||
|
|
@ -121,7 +132,7 @@ llvm::Value *VertexShaderBuilder::constElement(int idx)
|
|||
return load;
|
||||
}
|
||||
|
||||
llvm::Value *VertexShaderBuilder::shuffleVector(llvm::Value *vec, int shuffle)
|
||||
llvm::Value *Storage::shuffleVector(llvm::Value *vec, int shuffle)
|
||||
{
|
||||
Constant *mask = shuffleMask(shuffle);
|
||||
++m_shuffleId;
|
||||
|
|
@ -132,3 +143,28 @@ llvm::Value *VertexShaderBuilder::shuffleVector(llvm::Value *vec, int shuffle)
|
|||
name, m_block);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
llvm::Value *Storage::tempElement(int idx) const
|
||||
{
|
||||
Value *ret = m_temps[idx];
|
||||
if (!ret)
|
||||
return m_undefFloatVec;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Storage::setTempElement(int idx, llvm::Value *val)
|
||||
{
|
||||
m_temps[idx] = val;
|
||||
}
|
||||
|
||||
void Storage::store(int dstIdx, llvm::Value *val)
|
||||
{
|
||||
char ptrName[13];
|
||||
snprintf(ptrName, 13, "out_ptr%d", dstIdx);
|
||||
GetElementPtrInst *getElem = new GetElementPtrInst(m_OUT,
|
||||
constantInt(dstIdx),
|
||||
ptrName,
|
||||
m_block);
|
||||
new StoreInst(val, getElem, false, m_block);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,7 +191,8 @@ TGSIMESA_SOURCES = \
|
|||
|
||||
ifeq ($(MESA_NO_LLVM),0)
|
||||
LLVMTGSI_SOURCES = \
|
||||
pipe/llvm/llvmtgsi.cpp
|
||||
pipe/llvm/llvmtgsi.cpp \
|
||||
pipe/llvm/instructions.cpp
|
||||
endif
|
||||
|
||||
STATECACHE_SOURCES = \
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue