diff options
Diffstat (limited to 'src/gallium/auxiliary/gallivm/storagesoa.cpp')
-rw-r--r-- | src/gallium/auxiliary/gallivm/storagesoa.cpp | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/src/gallium/auxiliary/gallivm/storagesoa.cpp b/src/gallium/auxiliary/gallivm/storagesoa.cpp new file mode 100644 index 0000000000..4984ce985c --- /dev/null +++ b/src/gallium/auxiliary/gallivm/storagesoa.cpp @@ -0,0 +1,438 @@ +/************************************************************************** + * + * 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 "storagesoa.h" + +#include "gallivm_p.h" + +#include "pipe/p_shader_tokens.h" +#include "util/u_debug.h" + +#include <llvm/BasicBlock.h> +#include <llvm/Module.h> +#include <llvm/Value.h> + +#include <llvm/CallingConv.h> +#include <llvm/Constants.h> +#include <llvm/DerivedTypes.h> +#include <llvm/InstrTypes.h> +#include <llvm/Instructions.h> + +using namespace llvm; + + +StorageSoa::StorageSoa(llvm::BasicBlock *block, + llvm::Value *input, + llvm::Value *output, + llvm::Value *consts) + : m_block(block), + m_input(input), + m_output(output), + m_consts(consts), + m_immediates(0), + m_idx(0) +{ +} + +void StorageSoa::addImmediate(float *vec) +{ + std::vector<float> vals(4); + vals[0] = vec[0]; + vals[1] = vec[1]; + vals[2] = vec[2]; + vals[3] = vec[3]; + m_immediatesToFlush.push_back(vals); +} + +void StorageSoa::declareImmediates() +{ + if (m_immediatesToFlush.empty()) + return; + + VectorType *vectorType = VectorType::get(Type::FloatTy, 4); + ArrayType *vectorChannels = ArrayType::get(vectorType, 4); + ArrayType *arrayType = ArrayType::get(vectorChannels, m_immediatesToFlush.size()); + + m_immediates = new GlobalVariable( + /*Type=*/arrayType, + /*isConstant=*/false, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Initializer=*/0, // has initializer, specified below + /*Name=*/name("immediates"), + currentModule()); + + std::vector<Constant*> arrayVals; + for (unsigned int i = 0; i < m_immediatesToFlush.size(); ++i) { + std::vector<float> vec = m_immediatesToFlush[i]; + std::vector<float> vals(4); + std::vector<Constant*> channelArray; + + vals[0] = vec[0]; vals[1] = vec[1]; vals[2] = vec[2]; vals[3] = vec[3]; + llvm::Constant *xChannel = createConstGlobalVector(vals); + + vals[0] = vec[1]; vals[1] = vec[1]; vals[2] = vec[1]; vals[3] = vec[1]; + llvm::Constant *yChannel = createConstGlobalVector(vals); + + vals[0] = vec[2]; vals[1] = vec[2]; vals[2] = vec[2]; vals[3] = vec[2]; + llvm::Constant *zChannel = createConstGlobalVector(vals); + + vals[0] = vec[3]; vals[1] = vec[3]; vals[2] = vec[3]; vals[3] = vec[3]; + llvm::Constant *wChannel = createConstGlobalVector(vals); + channelArray.push_back(xChannel); + channelArray.push_back(yChannel); + channelArray.push_back(zChannel); + channelArray.push_back(wChannel); + Constant *constChannels = ConstantArray::get(vectorChannels, + channelArray); + arrayVals.push_back(constChannels); + } + Constant *constArray = ConstantArray::get(arrayType, arrayVals); + m_immediates->setInitializer(constArray); + + m_immediatesToFlush.clear(); +} + +llvm::Value *StorageSoa::addrElement(int idx) const +{ + std::map<int, llvm::Value*>::const_iterator itr = m_addresses.find(idx); + if (itr == m_addresses.end()) { + debug_printf("Trying to access invalid shader 'address'\n"); + return 0; + } + llvm::Value * res = (*itr).second; + + res = new LoadInst(res, name("addr"), false, m_block); + + return res; +} + +std::vector<llvm::Value*> StorageSoa::inputElement(llvm::Value *idx) +{ + std::vector<llvm::Value*> res(4); + + res[0] = element(m_input, idx, 0); + res[1] = element(m_input, idx, 1); + res[2] = element(m_input, idx, 2); + res[3] = element(m_input, idx, 3); + + return res; +} + +llvm::Value* StorageSoa::unpackConstElement(llvm::IRBuilder<>* m_builder, llvm::Value* vector, int cc) +{ + std::vector<llvm::Value*> x(4); + x[0] = m_builder->CreateExtractElement(vector, + constantInt(cc), + name("x")); + + VectorType *vectorType = VectorType::get(Type::FloatTy, 4); + Constant *constVector = Constant::getNullValue(vectorType); + Value *res = m_builder->CreateInsertElement(constVector, x[0], + constantInt(0), + name("vecx")); + res = m_builder->CreateInsertElement(res, x[0], constantInt(1), + name("vecxx")); + res = m_builder->CreateInsertElement(res, x[0], constantInt(2), + name("vecxxx")); + res = m_builder->CreateInsertElement(res, x[0], constantInt(3), + name("vecxxxx")); + return res; +} + +std::vector<llvm::Value*> StorageSoa::constElement(llvm::IRBuilder<>* m_builder, llvm::Value *idx) +{ + llvm::Value* res; + std::vector<llvm::Value*> res2(4); + llvm::Value *xChannel; + + xChannel = elementPointer(m_consts, idx, 0); + + res = alignedArrayLoad(xChannel); + + res2[0]=unpackConstElement(m_builder, res,0); + res2[1]=unpackConstElement(m_builder, res,1); + res2[2]=unpackConstElement(m_builder, res,2); + res2[3]=unpackConstElement(m_builder, res,3); + + return res2; +} + +std::vector<llvm::Value*> StorageSoa::outputElement(llvm::Value *idx) +{ + std::vector<llvm::Value*> res(4); + + res[0] = element(m_output, idx, 0); + res[1] = element(m_output, idx, 1); + res[2] = element(m_output, idx, 2); + res[3] = element(m_output, idx, 3); + + return res; +} + +std::vector<llvm::Value*> StorageSoa::tempElement(llvm::IRBuilder<>* m_builder, int idx) +{ + std::vector<llvm::Value*> res(4); + llvm::Value *temp = m_temps[idx]; + + res[0] = element(temp, constantInt(0), 0); + res[1] = element(temp, constantInt(0), 1); + res[2] = element(temp, constantInt(0), 2); + res[3] = element(temp, constantInt(0), 3); + + return res; +} + +std::vector<llvm::Value*> StorageSoa::immediateElement(llvm::Value *idx) +{ + std::vector<llvm::Value*> res(4); + + res[0] = element(m_immediates, idx, 0); + res[1] = element(m_immediates, idx, 1); + res[2] = element(m_immediates, idx, 2); + res[3] = element(m_immediates, idx, 3); + + return res; +} + +llvm::Value * StorageSoa::elementPointer(llvm::Value *ptr, llvm::Value *index, + int channel) const +{ + std::vector<Value*> indices; + if (m_immediates == ptr) + indices.push_back(constantInt(0)); + indices.push_back(index); + indices.push_back(constantInt(channel)); + + GetElementPtrInst *getElem = GetElementPtrInst::Create(ptr, + indices.begin(), + indices.end(), + name("ptr"), + m_block); + return getElem; +} + +llvm::Value * StorageSoa::element(llvm::Value *ptr, llvm::Value *index, + int channel) const +{ + llvm::Value *res = elementPointer(ptr, index, channel); + LoadInst *load = new LoadInst(res, name("element"), false, m_block); + //load->setAlignment(8); + return load; +} + +const char * StorageSoa::name(const char *prefix) const +{ + ++m_idx; + snprintf(m_name, 32, "%s%d", prefix, m_idx); + return m_name; +} + +llvm::ConstantInt * StorageSoa::constantInt(int idx) const +{ + if (m_constInts.find(idx) != m_constInts.end()) { + return m_constInts[idx]; + } + ConstantInt *constInt = ConstantInt::get(APInt(32, idx)); + m_constInts[idx] = constInt; + return constInt; +} + +llvm::Value *StorageSoa::alignedArrayLoad(llvm::Value *val) +{ + VectorType *vectorType = VectorType::get(Type::FloatTy, 4); + PointerType *vectorPtr = PointerType::get(vectorType, 0); + + CastInst *cast = new BitCastInst(val, vectorPtr, name("toVector"), m_block); + LoadInst *load = new LoadInst(cast, name("alignLoad"), false, m_block); + load->setAlignment(8); + return load; +} + +llvm::Module * StorageSoa::currentModule() const +{ + if (!m_block || !m_block->getParent()) + return 0; + + return m_block->getParent()->getParent(); +} + +llvm::Constant * StorageSoa::createConstGlobalFloat(const float val) +{ + Constant*c = ConstantFP::get(APFloat(val)); + return c; +} + +llvm::Constant * StorageSoa::createConstGlobalVector(const std::vector<float> &vec) +{ + VectorType *vectorType = VectorType::get(Type::FloatTy, 4); + std::vector<Constant*> immValues; + ConstantFP *constx = ConstantFP::get(APFloat(vec[0])); + ConstantFP *consty = ConstantFP::get(APFloat(vec[1])); + ConstantFP *constz = ConstantFP::get(APFloat(vec[2])); + ConstantFP *constw = ConstantFP::get(APFloat(vec[3])); + immValues.push_back(constx); + immValues.push_back(consty); + immValues.push_back(constz); + immValues.push_back(constw); + Constant *constVector = ConstantVector::get(vectorType, immValues); + + return constVector; +} + +std::vector<llvm::Value*> StorageSoa::load(enum tgsi_file_type type, int idx, int swizzle, + llvm::IRBuilder<>* m_builder,llvm::Value *indIdx) +{ + std::vector<llvm::Value*> val(4); + + //if we have an indirect index, always use that + // if not use the integer offset to create one + llvm::Value *realIndex = 0; + if (indIdx) + realIndex = indIdx; + else + realIndex = constantInt(idx); + debug_printf("XXXXXXXXX realIdx = %p, indIdx = %p\n", realIndex, indIdx); + + switch(type) { + case TGSI_FILE_INPUT: + val = inputElement(realIndex); + break; + case TGSI_FILE_OUTPUT: + val = outputElement(realIndex); + break; + case TGSI_FILE_TEMPORARY: + val = tempElement(m_builder, idx); + break; + case TGSI_FILE_CONSTANT: + val = constElement(m_builder, realIndex); + break; + case TGSI_FILE_IMMEDIATE: + val = immediateElement(realIndex); + break; + case TGSI_FILE_ADDRESS: + debug_printf("Address not handled in the load phase!\n"); + assert(0); + break; + default: + debug_printf("Unknown load!\n"); + assert(0); + break; + } + if (!gallivm_is_swizzle(swizzle)) + return val; + + std::vector<llvm::Value*> res(4); + + res[0] = val[gallivm_x_swizzle(swizzle)]; + res[1] = val[gallivm_y_swizzle(swizzle)]; + res[2] = val[gallivm_z_swizzle(swizzle)]; + res[3] = val[gallivm_w_swizzle(swizzle)]; + return res; +} + +llvm::Value * StorageSoa::allocaTemp(llvm::IRBuilder<>* m_builder) +{ + VectorType *vector = VectorType::get(Type::FloatTy, 4); + ArrayType *vecArray = ArrayType::get(vector, 4); + AllocaInst *alloca = new AllocaInst(vecArray, "temp", + m_builder->GetInsertBlock()); + + return alloca; +} + + +void StorageSoa::store(enum tgsi_file_type type, int idx, const std::vector<llvm::Value*> &val, + int mask, llvm::IRBuilder<>* m_builder) +{ + llvm::Value *out = 0; + llvm::Value *realIndex = 0; + switch(type) { + case TGSI_FILE_OUTPUT: + out = m_output; + realIndex = constantInt(idx); + break; + case TGSI_FILE_TEMPORARY: + // if that temp doesn't already exist, alloca it + if (m_temps.find(idx) == m_temps.end()) + m_temps[idx] = allocaTemp(m_builder); + + out = m_temps[idx]; + + realIndex = constantInt(0); + break; + case TGSI_FILE_INPUT: + out = m_input; + realIndex = constantInt(idx); + break; + case TGSI_FILE_ADDRESS: { + llvm::Value *addr = m_addresses[idx]; + if (!addr) { + addAddress(idx); + addr = m_addresses[idx]; + assert(addr); + } + new StoreInst(val[0], addr, false, m_block); + return; + break; + } + default: + debug_printf("Can't save output of this type: %d !\n", type); + assert(0); + break; + } + if ((mask & TGSI_WRITEMASK_X)) { + llvm::Value *xChannel = elementPointer(out, realIndex, 0); + new StoreInst(val[0], xChannel, false, m_block); + } + if ((mask & TGSI_WRITEMASK_Y)) { + llvm::Value *yChannel = elementPointer(out, realIndex, 1); + new StoreInst(val[1], yChannel, false, m_block); + } + if ((mask & TGSI_WRITEMASK_Z)) { + llvm::Value *zChannel = elementPointer(out, realIndex, 2); + new StoreInst(val[2], zChannel, false, m_block); + } + if ((mask & TGSI_WRITEMASK_W)) { + llvm::Value *wChannel = elementPointer(out, realIndex, 3); + new StoreInst(val[3], wChannel, false, m_block); + } +} + +void StorageSoa::addAddress(int idx) +{ + GlobalVariable *val = new GlobalVariable( + /*Type=*/IntegerType::get(32), + /*isConstant=*/false, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Initializer=*/0, // has initializer, specified below + /*Name=*/name("address"), + currentModule()); + val->setInitializer(Constant::getNullValue(IntegerType::get(32))); + + debug_printf("adding to %d\n", idx); + m_addresses[idx] = val; +} |