/************************************************************************** * * 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 "instructionssoa.h" #include "storagesoa.h" #include "pipe/p_shader_tokens.h" #include "util/u_memory.h" #include #include #include #include #include #include #include #include #include #include /* 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; } std::vector InstructionsSoa::arl(const std::vector in) { std::vector 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 InstructionsSoa::add(const std::vector in1, const std::vector in2) { std::vector 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 InstructionsSoa::mul(const std::vector in1, const std::vector in2) { std::vector 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; } void InstructionsSoa::end() { m_builder.CreateRetVoid(); } std::vector InstructionsSoa::madd(const std::vector in1, const std::vector in2, const std::vector in3) { std::vector res = mul(in1, in2); return add(res, in3); } std::vector InstructionsSoa::extractVector(llvm::Value *vector) { std::vector 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_POWER] = "pow"; m_functionsMap[TGSI_OPCODE_LIT] = "lit"; m_functionsMap[TGSI_OPCODE_RSQ] = "rsq"; m_functionsMap[TGSI_OPCODE_SLT] = "slt"; } void InstructionsSoa::createDependencies() { { std::vector powDeps(2); powDeps[0] = "powf"; powDeps[1] = "powvec"; m_builtinDependencies["pow"] = powDeps; } { std::vector absDeps(2); absDeps[0] = "fabsf"; absDeps[1] = "absvec"; m_builtinDependencies["abs"] = absDeps; } { std::vector maxDeps(1); maxDeps[0] = "maxvec"; m_builtinDependencies["max"] = maxDeps; } { std::vector minDeps(1); minDeps[0] = "minvec"; m_builtinDependencies["min"] = minDeps; } { std::vector litDeps(4); litDeps[0] = "minvec"; litDeps[1] = "maxvec"; litDeps[2] = "powf"; litDeps[3] = "powvec"; m_builtinDependencies["lit"] = litDeps; } { std::vector 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 = "< 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 = '"<getName()<<"'"<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() { MemoryBuffer *buffer = MemoryBuffer::getMemBuffer( (const char*)&soabuiltins_data[0], (const char*)&soabuiltins_data[Elements(soabuiltins_data)]); m_builtins = ParseBitcodeFile(buffer); std::cout<<"Builtins created at "< InstructionsSoa::abs(const std::vector in1) { llvm::Function *func = function(TGSI_OPCODE_ABS); return callBuiltin(func, in1); } std::vector InstructionsSoa::dp3(const std::vector in1, const std::vector in2) { llvm::Function *func = function(TGSI_OPCODE_DP3); return callBuiltin(func, in1, in2); } std::vector InstructionsSoa::slt(const std::vector in1, const std::vector in2) { llvm::Function *func = function(TGSI_OPCODE_SLT); return callBuiltin(func, in1, in2); } 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 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 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 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 InstructionsSoa::dp4(const std::vector in1, const std::vector in2) { llvm::Function *func = function(TGSI_OPCODE_DP4); return callBuiltin(func, in1, in2); } std::vector InstructionsSoa::callBuiltin(llvm::Function *func, const std::vector in1) { std::vector 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 InstructionsSoa::callBuiltin(llvm::Function *func, const std::vector in1, const std::vector in2) { std::vector 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 InstructionsSoa::callBuiltin(llvm::Function *func, const std::vector in1, const std::vector in2, const std::vector in3) { std::vector 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); } std::vector InstructionsSoa::pow(const std::vector in1, const std::vector in2) { llvm::Function *func = function(TGSI_OPCODE_POWER); return callBuiltin(func, in1, in2); } std::vector InstructionsSoa::min(const std::vector in1, const std::vector in2) { llvm::Function *func = function(TGSI_OPCODE_MIN); return callBuiltin(func, in1, in2); } std::vector InstructionsSoa::max(const std::vector in1, const std::vector in2) { llvm::Function *func = function(TGSI_OPCODE_MAX); return callBuiltin(func, in1, in2); } 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 = "<setOperand(op, V); } } } } void InstructionsSoa::injectFunction(llvm::Function *originalFunc, int op) { assert(originalFunc); std::cout << "injecting function originalFunc " <getName() <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 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 "<getFunction("powf") <<", with " <getFunction("powf")<getFunctionList().push_back(func); } if (op != TGSI_OPCODE_LAST) { m_functions[op] = func; } } std::vector InstructionsSoa::sub(const std::vector in1, const std::vector in2) { std::vector 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; } std::vector InstructionsSoa::lit(const std::vector in) { llvm::Function *func = function(TGSI_OPCODE_LIT); return callBuiltin(func, in); } std::vector InstructionsSoa::rsq(const std::vector in) { llvm::Function *func = function(TGSI_OPCODE_RSQ); return callBuiltin(func, in); }