| /************************************************************************** |
| * |
| * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| **************************************************************************/ |
| |
| #include <cstdio> |
| #include "instructionssoa.h" |
| |
| #include "storagesoa.h" |
| |
| #include "pipe/p_shader_tokens.h" |
| #include "util/u_memory.h" |
| |
| #include <llvm/CallingConv.h> |
| #include <llvm/Constants.h> |
| #include <llvm/Module.h> |
| #include <llvm/Function.h> |
| #include <llvm/Instructions.h> |
| #include <llvm/Transforms/Utils/Cloning.h> |
| #include <llvm/Attributes.h> |
| #include <llvm/Support/MemoryBuffer.h> |
| #include <llvm/Bitcode/ReaderWriter.h> |
| |
| |
| #include <iostream> |
| |
| |
| /* disable some warnings. this file is autogenerated */ |
| #if defined(__GNUC__) |
| #pragma GCC diagnostic ignored "-Wunused-variable" |
| #endif |
| using namespace llvm; |
| #include "gallivmsoabuiltins.cpp" |
| #if defined(__GNUC__) |
| #pragma GCC diagnostic warning "-Wunused-variable" |
| #endif |
| |
| InstructionsSoa::InstructionsSoa(llvm::Module *mod, llvm::Function *func, |
| llvm::BasicBlock *block, StorageSoa *storage) |
| : m_builder(block), |
| m_storage(storage), |
| m_idx(0) |
| { |
| createFunctionMap(); |
| createBuiltins(); |
| } |
| |
| const char * InstructionsSoa::name(const char *prefix) const |
| { |
| ++m_idx; |
| snprintf(m_name, 32, "%s%d", prefix, m_idx); |
| return m_name; |
| } |
| |
| llvm::Value * InstructionsSoa::vectorFromVals(llvm::Value *x, llvm::Value *y, |
| llvm::Value *z, llvm::Value *w) |
| { |
| VectorType *vectorType = VectorType::get(Type::FloatTy, 4); |
| Constant *constVector = Constant::getNullValue(vectorType); |
| Value *res = m_builder.CreateInsertElement(constVector, x, |
| m_storage->constantInt(0), |
| name("vecx")); |
| res = m_builder.CreateInsertElement(res, y, m_storage->constantInt(1), |
| name("vecxy")); |
| res = m_builder.CreateInsertElement(res, z, m_storage->constantInt(2), |
| name("vecxyz")); |
| if (w) |
| res = m_builder.CreateInsertElement(res, w, m_storage->constantInt(3), |
| name("vecxyzw")); |
| return res; |
| } |
| |
| void InstructionsSoa::end() |
| { |
| m_builder.CreateRetVoid(); |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::extractVector(llvm::Value *vector) |
| { |
| std::vector<llvm::Value*> res(4); |
| res[0] = m_builder.CreateExtractElement(vector, |
| m_storage->constantInt(0), |
| name("extract1X")); |
| res[1] = m_builder.CreateExtractElement(vector, |
| m_storage->constantInt(1), |
| name("extract2X")); |
| res[2] = m_builder.CreateExtractElement(vector, |
| m_storage->constantInt(2), |
| name("extract3X")); |
| res[3] = m_builder.CreateExtractElement(vector, |
| m_storage->constantInt(3), |
| name("extract4X")); |
| |
| return res; |
| } |
| |
| llvm::IRBuilder<>* InstructionsSoa::getIRBuilder() |
| { |
| return &m_builder; |
| } |
| |
| void InstructionsSoa::createFunctionMap() |
| { |
| m_functionsMap[TGSI_OPCODE_ABS] = "abs"; |
| m_functionsMap[TGSI_OPCODE_DP3] = "dp3"; |
| m_functionsMap[TGSI_OPCODE_DP4] = "dp4"; |
| m_functionsMap[TGSI_OPCODE_MIN] = "min"; |
| m_functionsMap[TGSI_OPCODE_MAX] = "max"; |
| m_functionsMap[TGSI_OPCODE_POW] = "pow"; |
| m_functionsMap[TGSI_OPCODE_LIT] = "lit"; |
| m_functionsMap[TGSI_OPCODE_RSQ] = "rsq"; |
| m_functionsMap[TGSI_OPCODE_SLT] = "slt"; |
| } |
| |
| void InstructionsSoa::createDependencies() |
| { |
| { |
| std::vector<std::string> powDeps(2); |
| powDeps[0] = "powf"; |
| powDeps[1] = "powvec"; |
| m_builtinDependencies["pow"] = powDeps; |
| } |
| { |
| std::vector<std::string> absDeps(2); |
| absDeps[0] = "fabsf"; |
| absDeps[1] = "absvec"; |
| m_builtinDependencies["abs"] = absDeps; |
| } |
| { |
| std::vector<std::string> maxDeps(1); |
| maxDeps[0] = "maxvec"; |
| m_builtinDependencies["max"] = maxDeps; |
| } |
| { |
| std::vector<std::string> minDeps(1); |
| minDeps[0] = "minvec"; |
| m_builtinDependencies["min"] = minDeps; |
| } |
| { |
| std::vector<std::string> litDeps(4); |
| litDeps[0] = "minvec"; |
| litDeps[1] = "maxvec"; |
| litDeps[2] = "powf"; |
| litDeps[3] = "powvec"; |
| m_builtinDependencies["lit"] = litDeps; |
| } |
| { |
| std::vector<std::string> rsqDeps(4); |
| rsqDeps[0] = "sqrtf"; |
| rsqDeps[1] = "sqrtvec"; |
| rsqDeps[2] = "fabsf"; |
| rsqDeps[3] = "absvec"; |
| m_builtinDependencies["rsq"] = rsqDeps; |
| } |
| } |
| |
| llvm::Function * InstructionsSoa::function(int op) |
| { |
| if (m_functions.find(op) != m_functions.end()) |
| return m_functions[op]; |
| |
| std::string name = m_functionsMap[op]; |
| |
| std::cout <<"For op = "<<op<<", func is '"<<name<<"'"<<std::endl; |
| |
| std::vector<std::string> deps = m_builtinDependencies[name]; |
| for (unsigned int i = 0; i < deps.size(); ++i) { |
| llvm::Function *func = m_builtins->getFunction(deps[i]); |
| std::cout <<"\tinjecting dep = '"<<func->getName()<<"'"<<std::endl; |
| injectFunction(func); |
| } |
| |
| llvm::Function *originalFunc = m_builtins->getFunction(name); |
| injectFunction(originalFunc, op); |
| return m_functions[op]; |
| } |
| |
| llvm::Module * InstructionsSoa::currentModule() const |
| { |
| BasicBlock *block = m_builder.GetInsertBlock(); |
| if (!block || !block->getParent()) |
| return 0; |
| |
| return block->getParent()->getParent(); |
| } |
| |
| void InstructionsSoa::createBuiltins() |
| { |
| std::string ErrMsg; |
| MemoryBuffer *buffer = MemoryBuffer::getMemBuffer( |
| (const char*)&soabuiltins_data[0], |
| (const char*)&soabuiltins_data[Elements(soabuiltins_data) - 1]); |
| m_builtins = ParseBitcodeFile(buffer, &ErrMsg); |
| std::cout<<"Builtins created at "<<m_builtins<<" ("<<ErrMsg<<")"<<std::endl; |
| assert(m_builtins); |
| createDependencies(); |
| } |
| |
| |
| std::vector<llvm::Value*> InstructionsSoa::abs(const std::vector<llvm::Value*> in1) |
| { |
| llvm::Function *func = function(TGSI_OPCODE_ABS); |
| return callBuiltin(func, in1); |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::add(const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2) |
| { |
| std::vector<llvm::Value*> res(4); |
| |
| res[0] = m_builder.CreateAdd(in1[0], in2[0], name("addx")); |
| res[1] = m_builder.CreateAdd(in1[1], in2[1], name("addy")); |
| res[2] = m_builder.CreateAdd(in1[2], in2[2], name("addz")); |
| res[3] = m_builder.CreateAdd(in1[3], in2[3], name("addw")); |
| |
| return res; |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::arl(const std::vector<llvm::Value*> in) |
| { |
| std::vector<llvm::Value*> res(4); |
| |
| //Extract x's |
| llvm::Value *x1 = m_builder.CreateExtractElement(in[0], |
| m_storage->constantInt(0), |
| name("extractX")); |
| //cast it to an unsigned int |
| x1 = m_builder.CreateFPToUI(x1, IntegerType::get(32), name("x1IntCast")); |
| |
| res[0] = x1;//vectorFromVals(x1, x2, x3, x4); |
| //only x is valid. the others shouldn't be necessary |
| /* |
| res[1] = Constant::getNullValue(m_floatVecType); |
| res[2] = Constant::getNullValue(m_floatVecType); |
| res[3] = Constant::getNullValue(m_floatVecType); |
| */ |
| |
| return res; |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::dp3(const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2) |
| { |
| llvm::Function *func = function(TGSI_OPCODE_DP3); |
| return callBuiltin(func, in1, in2); |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::lit(const std::vector<llvm::Value*> in) |
| { |
| llvm::Function *func = function(TGSI_OPCODE_LIT); |
| return callBuiltin(func, in); |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::madd(const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2, |
| const std::vector<llvm::Value*> in3) |
| { |
| std::vector<llvm::Value*> res = mul(in1, in2); |
| return add(res, in3); |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::max(const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2) |
| { |
| llvm::Function *func = function(TGSI_OPCODE_MAX); |
| return callBuiltin(func, in1, in2); |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::min(const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2) |
| { |
| llvm::Function *func = function(TGSI_OPCODE_MIN); |
| return callBuiltin(func, in1, in2); |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::mul(const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2) |
| { |
| std::vector<llvm::Value*> res(4); |
| |
| res[0] = m_builder.CreateMul(in1[0], in2[0], name("mulx")); |
| res[1] = m_builder.CreateMul(in1[1], in2[1], name("muly")); |
| res[2] = m_builder.CreateMul(in1[2], in2[2], name("mulz")); |
| res[3] = m_builder.CreateMul(in1[3], in2[3], name("mulw")); |
| |
| return res; |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::pow(const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2) |
| { |
| llvm::Function *func = function(TGSI_OPCODE_POW); |
| return callBuiltin(func, in1, in2); |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::rsq(const std::vector<llvm::Value*> in) |
| { |
| llvm::Function *func = function(TGSI_OPCODE_RSQ); |
| return callBuiltin(func, in); |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::slt(const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2) |
| { |
| llvm::Function *func = function(TGSI_OPCODE_SLT); |
| return callBuiltin(func, in1, in2); |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::sub(const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2) |
| { |
| std::vector<llvm::Value*> res(4); |
| |
| res[0] = m_builder.CreateSub(in1[0], in2[0], name("subx")); |
| res[1] = m_builder.CreateSub(in1[1], in2[1], name("suby")); |
| res[2] = m_builder.CreateSub(in1[2], in2[2], name("subz")); |
| res[3] = m_builder.CreateSub(in1[3], in2[3], name("subw")); |
| |
| return res; |
| } |
| |
| void checkFunction(Function *func) |
| { |
| for (Function::const_iterator BI = func->begin(), BE = func->end(); |
| BI != BE; ++BI) { |
| const BasicBlock &BB = *BI; |
| for (BasicBlock::const_iterator II = BB.begin(), IE = BB.end(); |
| II != IE; ++II) { |
| const Instruction &I = *II; |
| std::cout<< "Instr = "<<I; |
| for (unsigned op = 0, E = I.getNumOperands(); op != E; ++op) { |
| const Value *Op = I.getOperand(op); |
| std::cout<< "\top = "<<Op<<"("<<op<<")"<<std::endl; |
| //I->setOperand(op, V); |
| } |
| } |
| } |
| } |
| |
| llvm::Value * InstructionsSoa::allocaTemp() |
| { |
| VectorType *vector = VectorType::get(Type::FloatTy, 4); |
| ArrayType *vecArray = ArrayType::get(vector, 4); |
| AllocaInst *alloca = new AllocaInst(vecArray, name("tmpRes"), |
| m_builder.GetInsertBlock()); |
| |
| std::vector<Value*> indices; |
| indices.push_back(m_storage->constantInt(0)); |
| indices.push_back(m_storage->constantInt(0)); |
| GetElementPtrInst *getElem = GetElementPtrInst::Create(alloca, |
| indices.begin(), |
| indices.end(), |
| name("allocaPtr"), |
| m_builder.GetInsertBlock()); |
| return getElem; |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::allocaToResult(llvm::Value *allocaPtr) |
| { |
| GetElementPtrInst *xElemPtr = GetElementPtrInst::Create(allocaPtr, |
| m_storage->constantInt(0), |
| name("xPtr"), |
| m_builder.GetInsertBlock()); |
| GetElementPtrInst *yElemPtr = GetElementPtrInst::Create(allocaPtr, |
| m_storage->constantInt(1), |
| name("yPtr"), |
| m_builder.GetInsertBlock()); |
| GetElementPtrInst *zElemPtr = GetElementPtrInst::Create(allocaPtr, |
| m_storage->constantInt(2), |
| name("zPtr"), |
| m_builder.GetInsertBlock()); |
| GetElementPtrInst *wElemPtr = GetElementPtrInst::Create(allocaPtr, |
| m_storage->constantInt(3), |
| name("wPtr"), |
| m_builder.GetInsertBlock()); |
| |
| std::vector<llvm::Value*> res(4); |
| res[0] = new LoadInst(xElemPtr, name("xRes"), false, m_builder.GetInsertBlock()); |
| res[1] = new LoadInst(yElemPtr, name("yRes"), false, m_builder.GetInsertBlock()); |
| res[2] = new LoadInst(zElemPtr, name("zRes"), false, m_builder.GetInsertBlock()); |
| res[3] = new LoadInst(wElemPtr, name("wRes"), false, m_builder.GetInsertBlock()); |
| |
| return res; |
| } |
| |
| std::vector<llvm::Value*> InstructionsSoa::dp4(const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2) |
| { |
| llvm::Function *func = function(TGSI_OPCODE_DP4); |
| return callBuiltin(func, in1, in2); |
| } |
| |
| std::vector<Value*> InstructionsSoa::callBuiltin(llvm::Function *func, const std::vector<llvm::Value*> in1) |
| { |
| std::vector<Value*> params; |
| |
| llvm::Value *allocaPtr = allocaTemp(); |
| params.push_back(allocaPtr); |
| params.push_back(in1[0]); |
| params.push_back(in1[1]); |
| params.push_back(in1[2]); |
| params.push_back(in1[3]); |
| CallInst *call = m_builder.CreateCall(func, params.begin(), params.end()); |
| call->setCallingConv(CallingConv::C); |
| call->setTailCall(false); |
| |
| return allocaToResult(allocaPtr); |
| } |
| |
| std::vector<Value*> InstructionsSoa::callBuiltin(llvm::Function *func, const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2) |
| { |
| std::vector<Value*> params; |
| |
| llvm::Value *allocaPtr = allocaTemp(); |
| params.push_back(allocaPtr); |
| params.push_back(in1[0]); |
| params.push_back(in1[1]); |
| params.push_back(in1[2]); |
| params.push_back(in1[3]); |
| params.push_back(in2[0]); |
| params.push_back(in2[1]); |
| params.push_back(in2[2]); |
| params.push_back(in2[3]); |
| CallInst *call = m_builder.CreateCall(func, params.begin(), params.end()); |
| call->setCallingConv(CallingConv::C); |
| call->setTailCall(false); |
| |
| return allocaToResult(allocaPtr); |
| } |
| |
| std::vector<Value*> InstructionsSoa::callBuiltin(llvm::Function *func, const std::vector<llvm::Value*> in1, |
| const std::vector<llvm::Value*> in2, |
| const std::vector<llvm::Value*> in3) |
| { |
| std::vector<Value*> params; |
| |
| llvm::Value *allocaPtr = allocaTemp(); |
| params.push_back(allocaPtr); |
| params.push_back(in1[0]); |
| params.push_back(in1[1]); |
| params.push_back(in1[2]); |
| params.push_back(in1[3]); |
| params.push_back(in2[0]); |
| params.push_back(in2[1]); |
| params.push_back(in2[2]); |
| params.push_back(in2[3]); |
| params.push_back(in3[0]); |
| params.push_back(in3[1]); |
| params.push_back(in3[2]); |
| params.push_back(in3[3]); |
| CallInst *call = m_builder.CreateCall(func, params.begin(), params.end()); |
| call->setCallingConv(CallingConv::C); |
| call->setTailCall(false); |
| |
| return allocaToResult(allocaPtr); |
| } |
| |
| void InstructionsSoa::injectFunction(llvm::Function *originalFunc, int op) |
| { |
| assert(originalFunc); |
| std::cout << "injecting function originalFunc " <<originalFunc->getName() <<std::endl; |
| if (op != TGSI_OPCODE_LAST) { |
| /* in this case it's possible the function has been already |
| * injected as part of the dependency chain, which gets |
| * injected below */ |
| llvm::Function *func = currentModule()->getFunction(originalFunc->getName()); |
| if (func) { |
| m_functions[op] = func; |
| return; |
| } |
| } |
| llvm::Function *func = 0; |
| if (originalFunc->isDeclaration()) { |
| func = Function::Create(originalFunc->getFunctionType(), GlobalValue::ExternalLinkage, |
| originalFunc->getName(), currentModule()); |
| func->setCallingConv(CallingConv::C); |
| const AttrListPtr pal; |
| func->setAttributes(pal); |
| currentModule()->dump(); |
| } else { |
| DenseMap<const Value*, Value *> val; |
| val[m_builtins->getFunction("fabsf")] = currentModule()->getFunction("fabsf"); |
| val[m_builtins->getFunction("powf")] = currentModule()->getFunction("powf"); |
| val[m_builtins->getFunction("sqrtf")] = currentModule()->getFunction("sqrtf"); |
| func = CloneFunction(originalFunc, val); |
| #if 0 |
| std::cout <<" replacing "<<m_builtins->getFunction("powf") |
| <<", with " <<currentModule()->getFunction("powf")<<std::endl; |
| std::cout<<"1111-------------------------------"<<std::endl; |
| checkFunction(originalFunc); |
| std::cout<<"2222-------------------------------"<<std::endl; |
| checkFunction(func); |
| std::cout <<"XXXX = " <<val[m_builtins->getFunction("powf")]<<std::endl; |
| #endif |
| currentModule()->getFunctionList().push_back(func); |
| } |
| if (op != TGSI_OPCODE_LAST) { |
| m_functions[op] = func; |
| } |
| } |
| |
| |