diff options
Diffstat (limited to 'llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp')
-rw-r--r-- | llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp index 947b574..2c3e087 100644 --- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -21,7 +21,9 @@ #include "llvm/IR/InstIterator.h" #include "llvm/IR/InstVisitor.h" #include "llvm/IR/IntrinsicsSPIRV.h" +#include "llvm/IR/PatternMatch.h" #include "llvm/IR/TypedPointerType.h" +#include "llvm/Transforms/Utils/Local.h" #include <queue> #include <unordered_set> @@ -187,6 +189,8 @@ class SPIRVEmitIntrinsics void applyDemangledPtrArgTypes(IRBuilder<> &B); + GetElementPtrInst *simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP); + bool runOnFunction(Function &F); bool postprocessTypes(Module &M); bool processFunctionPointers(Module &M); @@ -1458,6 +1462,24 @@ static void createSaturatedConversionDecoration(Instruction *I, createDecorationIntrinsic(I, SaturatedConversionNode, B); } +static void addSaturatedDecorationToIntrinsic(Instruction *I, IRBuilder<> &B) { + if (auto *CI = dyn_cast<CallInst>(I)) { + if (Function *Fu = CI->getCalledFunction()) { + if (Fu->isIntrinsic()) { + unsigned const int IntrinsicId = Fu->getIntrinsicID(); + switch (IntrinsicId) { + case Intrinsic::fptosi_sat: + case Intrinsic::fptoui_sat: + createSaturatedConversionDecoration(I, B); + break; + default: + break; + } + } + } + } +} + Instruction *SPIRVEmitIntrinsics::visitCallInst(CallInst &Call) { if (!Call.isInlineAsm()) return &Call; @@ -2543,6 +2565,30 @@ void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(IRBuilder<> &B) { } } +GetElementPtrInst * +SPIRVEmitIntrinsics::simplifyZeroLengthArrayGepInst(GetElementPtrInst *GEP) { + // getelementptr [0 x T], P, 0 (zero), I -> getelementptr T, P, I. + // If type is 0-length array and first index is 0 (zero), drop both the + // 0-length array type and the first index. This is a common pattern in the + // IR, e.g. when using a zero-length array as a placeholder for a flexible + // array such as unbound arrays. + assert(GEP && "GEP is null"); + Type *SrcTy = GEP->getSourceElementType(); + SmallVector<Value *, 8> Indices(GEP->indices()); + ArrayType *ArrTy = dyn_cast<ArrayType>(SrcTy); + if (ArrTy && ArrTy->getNumElements() == 0 && + PatternMatch::match(Indices[0], PatternMatch::m_Zero())) { + IRBuilder<> Builder(GEP); + Indices.erase(Indices.begin()); + SrcTy = ArrTy->getElementType(); + Value *NewGEP = Builder.CreateGEP(SrcTy, GEP->getPointerOperand(), Indices, + "", GEP->getNoWrapFlags()); + assert(llvm::isa<GetElementPtrInst>(NewGEP) && "NewGEP should be a GEP"); + return cast<GetElementPtrInst>(NewGEP); + } + return nullptr; +} + bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { if (Func.isDeclaration()) return false; @@ -2560,14 +2606,30 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { AggrConstTypes.clear(); AggrStores.clear(); - // fix GEP result types ahead of inference + // Fix GEP result types ahead of inference, and simplify if possible. + // Data structure for dead instructions that were simplified and replaced. + SmallPtrSet<Instruction *, 4> DeadInsts; for (auto &I : instructions(Func)) { auto *Ref = dyn_cast<GetElementPtrInst>(&I); if (!Ref || GR->findDeducedElementType(Ref)) continue; + + GetElementPtrInst *NewGEP = simplifyZeroLengthArrayGepInst(Ref); + if (NewGEP) { + Ref->replaceAllUsesWith(NewGEP); + if (isInstructionTriviallyDead(Ref)) + DeadInsts.insert(Ref); + + Ref = NewGEP; + } if (Type *GepTy = getGEPType(Ref)) GR->addDeducedElementType(Ref, normalizeType(GepTy)); } + // Remove dead instructions that were simplified and replaced. + for (auto *I : DeadInsts) { + assert(I->use_empty() && "Dead instruction should not have any uses left"); + I->eraseFromParent(); + } processParamTypesByFunHeader(CurrF, B); @@ -2640,6 +2702,7 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) { if (isConvergenceIntrinsic(I)) continue; + addSaturatedDecorationToIntrinsic(I, B); processInstrAfterVisit(I, B); } |