From 3975f34fd36f8b04d499bb6b3d48eaeef5cab24e Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Wed, 17 Oct 2007 11:27:46 -0400 Subject: Implement basic opcode translation and storage translation. --- src/mesa/pipe/llvm/instructions.cpp | 162 +++++++++++++++++++++++++++++++++ src/mesa/pipe/llvm/instructions.h | 43 +++++++++ src/mesa/pipe/llvm/llvmtgsi.cpp | 101 ++++++++++++++++++-- src/mesa/pipe/llvm/tgsillvmbuilder.cpp | 68 ++++++++++---- src/mesa/sources | 3 +- 5 files changed, 350 insertions(+), 27 deletions(-) create mode 100644 src/mesa/pipe/llvm/instructions.cpp create mode 100644 src/mesa/pipe/llvm/instructions.h (limited to 'src/mesa') diff --git a/src/mesa/pipe/llvm/instructions.cpp b/src/mesa/pipe/llvm/instructions.cpp new file mode 100644 index 0000000000..147a1b64f2 --- /dev/null +++ b/src/mesa/pipe/llvm/instructions.cpp @@ -0,0 +1,162 @@ +#include "instructions.h" + +#include +#include +#include +#include +#include + +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 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 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; +} + diff --git a/src/mesa/pipe/llvm/instructions.h b/src/mesa/pipe/llvm/instructions.h new file mode 100644 index 0000000000..c6e77710ea --- /dev/null +++ b/src/mesa/pipe/llvm/instructions.h @@ -0,0 +1,43 @@ +#ifndef INSTRUCTIONS_H +#define INSTRUCTIONS_H + +#include +#include +#include + +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 diff --git a/src/mesa/pipe/llvm/llvmtgsi.cpp b/src/mesa/pipe/llvm/llvmtgsi.cpp index 375e61c0db..5cbd0ae89f 100644 --- a/src/mesa/pipe/llvm/llvmtgsi.cpp +++ b/src/mesa/pipe/llvm/llvmtgsi.cpp @@ -30,6 +30,7 @@ #include #include +#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; diff --git a/src/mesa/pipe/llvm/tgsillvmbuilder.cpp b/src/mesa/pipe/llvm/tgsillvmbuilder.cpp index 4088da11f8..ca70a46648 100644 --- a/src/mesa/pipe/llvm/tgsillvmbuilder.cpp +++ b/src/mesa/pipe/llvm/tgsillvmbuilder.cpp @@ -1,41 +1,52 @@ #include -class VertexShaderBuilder +class Storage { typedef std::map 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 m_constInts; - std::map m_intVecs; - LoadMap m_inputs; - LoadMap m_consts; + std::map m_intVecs; + std::vector 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); +} diff --git a/src/mesa/sources b/src/mesa/sources index c2544ed322..7e1d909e28 100644 --- a/src/mesa/sources +++ b/src/mesa/sources @@ -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 = \ -- cgit v1.2.3