//===-- AMDILMachineFunctionInfo.cpp - TODO: Add brief description -------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //==-----------------------------------------------------------------------===// #include "AMDILMachineFunctionInfo.h" #include "AMDILCompilerErrors.h" #include "AMDILModuleInfo.h" #include "AMDILSubtarget.h" #include "AMDILTargetMachine.h" #include "AMDILUtilityFunctions.h" #include "llvm/ADT/StringExtras.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/Instructions.h" #include "llvm/Support/FormattedStream.h" using namespace llvm; static const AMDILConstPtr *getConstPtr(const AMDILKernel *krnl, const std::string &arg) { llvm::SmallVector::const_iterator begin, end; for (begin = krnl->constPtr.begin(), end = krnl->constPtr.end(); begin != end; ++begin) { if (!strcmp(begin->name.data(),arg.c_str())) { return &(*begin); } } return NULL; } void PrintfInfo::addOperand(size_t idx, uint32_t size) { mOperands.resize((unsigned)(idx + 1)); mOperands[(unsigned)idx] = size; } uint32_t PrintfInfo::getPrintfID() { return mPrintfID; } void PrintfInfo::setPrintfID(uint32_t id) { mPrintfID = id; } size_t PrintfInfo::getNumOperands() { return mOperands.size(); } uint32_t PrintfInfo::getOperandID(uint32_t idx) { return mOperands[idx]; } AMDILMachineFunctionInfo::AMDILMachineFunctionInfo() : CalleeSavedFrameSize(0), BytesToPopOnReturn(0), DecorationStyle(None), ReturnAddrIndex(0), TailCallReturnAddrDelta(0), SRetReturnReg(0), UsesLDS(false), LDSArg(false), UsesGDS(false), GDSArg(false), mReservedLits(9) { for (uint32_t x = 0; x < AMDILDevice::MAX_IDS; ++x) { mUsedMem[x] = false; } mMF = NULL; mKernel = NULL; mScratchSize = -1; mArgSize = -1; mStackSize = -1; } AMDILMachineFunctionInfo::AMDILMachineFunctionInfo(MachineFunction& MF) : CalleeSavedFrameSize(0), BytesToPopOnReturn(0), DecorationStyle(None), ReturnAddrIndex(0), TailCallReturnAddrDelta(0), SRetReturnReg(0), UsesLDS(false), LDSArg(false), UsesGDS(false), GDSArg(false), mReservedLits(9) { for (uint32_t x = 0; x < AMDILDevice::MAX_IDS; ++x) { mUsedMem[x] = false; } const Function *F = MF.getFunction(); mMF = &MF; MachineModuleInfo &mmi = MF.getMMI(); const AMDILTargetMachine *TM = reinterpret_cast(&MF.getTarget()); AMDILModuleInfo *AMI = &(mmi.getObjFileInfo()); AMI->processModule(mmi.getModule(), TM); mSTM = TM->getSubtargetImpl(); mKernel = AMI->getKernel(F->getName()); mScratchSize = -1; mArgSize = -1; mStackSize = -1; } AMDILMachineFunctionInfo::~AMDILMachineFunctionInfo() { for (std::map::iterator pfb = printf_begin(), pfe = printf_end(); pfb != pfe; ++pfb) { delete pfb->second; } } unsigned int AMDILMachineFunctionInfo::getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; } void AMDILMachineFunctionInfo::setCalleeSavedFrameSize(unsigned int bytes) { CalleeSavedFrameSize = bytes; } unsigned int AMDILMachineFunctionInfo::getBytesToPopOnReturn() const { return BytesToPopOnReturn; } void AMDILMachineFunctionInfo::setBytesToPopOnReturn(unsigned int bytes) { BytesToPopOnReturn = bytes; } NameDecorationStyle AMDILMachineFunctionInfo::getDecorationStyle() const { return DecorationStyle; } void AMDILMachineFunctionInfo::setDecorationStyle(NameDecorationStyle style) { DecorationStyle = style; } int AMDILMachineFunctionInfo::getRAIndex() const { return ReturnAddrIndex; } void AMDILMachineFunctionInfo::setRAIndex(int index) { ReturnAddrIndex = index; } int AMDILMachineFunctionInfo::getTCReturnAddrDelta() const { return TailCallReturnAddrDelta; } void AMDILMachineFunctionInfo::setTCReturnAddrDelta(int delta) { TailCallReturnAddrDelta = delta; } unsigned int AMDILMachineFunctionInfo::getSRetReturnReg() const { return SRetReturnReg; } void AMDILMachineFunctionInfo::setSRetReturnReg(unsigned int reg) { SRetReturnReg = reg; } void AMDILMachineFunctionInfo::setUsesLocal() { UsesLDS = true; } bool AMDILMachineFunctionInfo::usesLocal() const { return UsesLDS; } void AMDILMachineFunctionInfo::setHasLocalArg() { LDSArg = true; } bool AMDILMachineFunctionInfo::hasLocalArg() const { return LDSArg; } void AMDILMachineFunctionInfo::setUsesRegion() { UsesGDS = true; } bool AMDILMachineFunctionInfo::usesRegion() const { return UsesGDS; } void AMDILMachineFunctionInfo::setHasRegionArg() { GDSArg = true; } bool AMDILMachineFunctionInfo::hasRegionArg() const { return GDSArg; } bool AMDILMachineFunctionInfo::usesHWConstant(std::string name) const { const AMDILConstPtr *curConst = getConstPtr(mKernel, name); if (curConst) { return curConst->usesHardware; } else { return false; } } uint32_t AMDILMachineFunctionInfo::getLocal(uint32_t dim) { if (mKernel && mKernel->sgv) { AMDILKernelAttr *sgv = mKernel->sgv; switch (dim) { default: break; case 0: case 1: case 2: return sgv->reqGroupSize[dim]; break; case 3: return sgv->reqGroupSize[0] * sgv->reqGroupSize[1] * sgv->reqGroupSize[2]; }; } switch (dim) { default: return 1; case 3: return mSTM->getDefaultSize(0) * mSTM->getDefaultSize(1) * mSTM->getDefaultSize(2); case 2: case 1: case 0: return mSTM->getDefaultSize(dim); break; }; return 1; } bool AMDILMachineFunctionInfo::isKernel() const { return mKernel != NULL && mKernel->mKernel; } AMDILKernel* AMDILMachineFunctionInfo::getKernel() { return mKernel; } std::string AMDILMachineFunctionInfo::getName() { if (mMF) { return mMF->getFunction()->getName(); } else { return ""; } } uint32_t AMDILMachineFunctionInfo::getArgSize() { if (mArgSize == -1) { Function::const_arg_iterator I = mMF->getFunction()->arg_begin(); Function::const_arg_iterator Ie = mMF->getFunction()->arg_end(); uint32_t Counter = 0; while (I != Ie) { Type* curType = I->getType(); if (curType->isIntegerTy() || curType->isFloatingPointTy()) { ++Counter; } else if (const VectorType *VT = dyn_cast(curType)) { Type *ET = VT->getElementType(); int numEle = VT->getNumElements(); switch (ET->getPrimitiveSizeInBits()) { default: if (numEle == 3) { Counter++; } else { Counter += ((numEle + 2) >> 2); } break; case 64: if (numEle == 3) { Counter += 2; } else { Counter += (numEle >> 1); } break; case 16: case 8: switch (numEle) { default: Counter += ((numEle + 2) >> 2); case 2: Counter++; break; } break; } } else if (const PointerType *PT = dyn_cast(curType)) { Type *CT = PT->getElementType(); const StructType *ST = dyn_cast(CT); if (ST && ST->isOpaque()) { bool i1d = ST->getName() == "struct._image1d_t"; bool i1da = ST->getName() == "struct._image1d_array_t"; bool i1db = ST->getName() == "struct._image1d_buffer_t"; bool i2d = ST->getName() == "struct._image2d_t"; bool i2da = ST->getName() == "struct._image2d_array_t"; bool i3d = ST->getName() == "struct._image3d_t"; bool is_image = i1d || i1da || i1db || i2d || i2da || i3d; if (is_image) { if (mSTM->device()->isSupported(AMDILDeviceInfo::Images)) { Counter += 2; } else { addErrorMsg(amd::CompilerErrorMessage[NO_IMAGE_SUPPORT]); } } else { Counter++; } } else if (CT->isStructTy() && PT->getAddressSpace() == AMDILAS::PRIVATE_ADDRESS) { StructType *ST = dyn_cast(CT); Counter += ((getTypeSize(ST) + 15) & ~15) >> 4; } else if (CT->isIntOrIntVectorTy() || CT->isFPOrFPVectorTy() || CT->isArrayTy() || CT->isPointerTy() || PT->getAddressSpace() != AMDILAS::PRIVATE_ADDRESS) { ++Counter; } else { assert(0 && "Current type is not supported!"); addErrorMsg(amd::CompilerErrorMessage[INTERNAL_ERROR]); } } else { assert(0 && "Current type is not supported!"); addErrorMsg(amd::CompilerErrorMessage[INTERNAL_ERROR]); } ++I; } // Convert from slots to bytes by multiplying by 16(shift by 4). mArgSize = Counter << 4; } return (uint32_t)mArgSize; } uint32_t AMDILMachineFunctionInfo::getScratchSize() { if (mScratchSize == -1) { mScratchSize = 0; Function::const_arg_iterator I = mMF->getFunction()->arg_begin(); Function::const_arg_iterator Ie = mMF->getFunction()->arg_end(); while (I != Ie) { Type *curType = I->getType(); mScratchSize += ((getTypeSize(curType) + 15) & ~15); ++I; } mScratchSize += ((mScratchSize + 15) & ~15); } return (uint32_t)mScratchSize; } uint32_t AMDILMachineFunctionInfo::getStackSize() { if (mStackSize == -1) { uint32_t privSize = 0; const MachineFrameInfo *MFI = mMF->getFrameInfo(); privSize = MFI->getOffsetAdjustment() + MFI->getStackSize(); const AMDILTargetMachine *TM = reinterpret_cast(&mMF->getTarget()); bool addStackSize = TM->getOptLevel() == CodeGenOpt::None; Function::const_arg_iterator I = mMF->getFunction()->arg_begin(); Function::const_arg_iterator Ie = mMF->getFunction()->arg_end(); while (I != Ie) { Type *curType = I->getType(); ++I; if (dyn_cast(curType)) { Type *CT = dyn_cast(curType)->getElementType(); if (CT->isStructTy() && dyn_cast(curType)->getAddressSpace() == AMDILAS::PRIVATE_ADDRESS) { addStackSize = true; } } } if (addStackSize) { privSize += getScratchSize(); } mStackSize = privSize; } return (uint32_t)mStackSize; } uint32_t AMDILMachineFunctionInfo::addi32Literal(uint32_t val, int Opcode) { // Since we have emulated 16/8/1 bit register types with a 32bit real // register, we need to sign extend the constants to 32bits in order for // comparisons against the constants to work correctly, this fixes some issues // we had in conformance failing for saturation. if (Opcode == AMDIL::LOADCONST_i16) { val = (((int32_t)val << 16) >> 16); } else if (Opcode == AMDIL::LOADCONST_i8) { val = (((int32_t)val << 24) >> 24); } if (mIntLits.find(val) == mIntLits.end()) { mIntLits[val] = getNumLiterals(); } return mIntLits[val]; } uint32_t AMDILMachineFunctionInfo::addi64Literal(uint64_t val) { if (mLongLits.find(val) == mLongLits.end()) { mLongLits[val] = getNumLiterals(); } return mLongLits[val]; } uint32_t AMDILMachineFunctionInfo::addi128Literal(uint64_t val_lo, uint64_t val_hi) { std::pair a; a.first = val_lo; a.second = val_hi; if (mVecLits.find(a) == mVecLits.end()) { mVecLits[a] = getNumLiterals(); } return mVecLits[a]; } uint32_t AMDILMachineFunctionInfo::addf32Literal(const ConstantFP *CFP) { uint32_t val = (uint32_t)CFP->getValueAPF().bitcastToAPInt().getZExtValue(); if (mIntLits.find(val) == mIntLits.end()) { mIntLits[val] = getNumLiterals(); } return mIntLits[val]; } uint32_t AMDILMachineFunctionInfo::addf64Literal(const ConstantFP *CFP) { union dtol_union { double d; uint64_t ul; } dval; const APFloat &APF = CFP->getValueAPF(); if (&APF.getSemantics() == (const llvm::fltSemantics *)&APFloat::IEEEsingle) { float fval = APF.convertToFloat(); dval.d = (double)fval; } else { dval.d = APF.convertToDouble(); } if (mLongLits.find(dval.ul) == mLongLits.end()) { mLongLits[dval.ul] = getNumLiterals(); } return mLongLits[dval.ul]; } uint32_t AMDILMachineFunctionInfo::getIntLits(uint32_t offset) { return mIntLits[offset]; } uint32_t AMDILMachineFunctionInfo::getLongLits(uint64_t offset) { return mLongLits[offset]; } uint32_t AMDILMachineFunctionInfo::getVecLits(uint64_t low64, uint64_t high64) { return mVecLits[std::pair(low64, high64)]; } size_t AMDILMachineFunctionInfo::getNumLiterals() const { return mLongLits.size() + mIntLits.size() + mVecLits.size() + mReservedLits; } void AMDILMachineFunctionInfo::addReservedLiterals(uint32_t size) { mReservedLits += size; } uint32_t AMDILMachineFunctionInfo::addSampler(std::string name, uint32_t val) { if (mSamplerMap.find(name) != mSamplerMap.end()) { SamplerInfo newVal = mSamplerMap[name]; assert(newVal.val == val && "Found a sampler with same name but different values!"); return mSamplerMap[name].idx; } else { SamplerInfo curVal; curVal.name = name; curVal.val = val; curVal.idx = mSamplerMap.size(); mSamplerMap[name] = curVal; return curVal.idx; } } void AMDILMachineFunctionInfo::setUsesMem(unsigned id) { assert(id < AMDILDevice::MAX_IDS && "Must set the ID to be less than MAX_IDS!"); mUsedMem[id] = true; } bool AMDILMachineFunctionInfo::usesMem(unsigned id) { assert(id < AMDILDevice::MAX_IDS && "Must set the ID to be less than MAX_IDS!"); return mUsedMem[id]; } void AMDILMachineFunctionInfo::addErrorMsg(const char *msg, ErrorMsgEnum val) { if (val == DEBUG_ONLY) { #if defined(DEBUG) || defined(_DEBUG) mErrors.insert(msg); #endif } else if (val == RELEASE_ONLY) { #if !defined(DEBUG) && !defined(_DEBUG) mErrors.insert(msg); #endif } else if (val == ALWAYS) { mErrors.insert(msg); } } uint32_t AMDILMachineFunctionInfo::addPrintfString(std::string &name, unsigned offset) { if (mPrintfMap.find(name) != mPrintfMap.end()) { return mPrintfMap[name]->getPrintfID(); } else { PrintfInfo *info = new PrintfInfo; info->setPrintfID(mPrintfMap.size() + offset); mPrintfMap[name] = info; return info->getPrintfID(); } } void AMDILMachineFunctionInfo::addPrintfOperand(std::string &name, size_t idx, uint32_t size) { mPrintfMap[name]->addOperand(idx, size); } void AMDILMachineFunctionInfo::addMetadata(const char *md, bool kernelOnly) { addMetadata(std::string(md), kernelOnly); } void AMDILMachineFunctionInfo::addMetadata(std::string md, bool kernelOnly) { if (kernelOnly) { mMetadataKernel.push_back(md); } else { mMetadataFunc.insert(md); } }