@@ -1909,14 +1909,15 @@ bool checkTypeForSPIRVExtendedInstLowering(IntrinsicInst *II, SPIRVModule *BM) {
1909
1909
return true ;
1910
1910
}
1911
1911
1912
- void setAttrByCalledFunc (CallInst *Call) {
1912
+ CallInst * setAttrByCalledFunc (CallInst *Call) {
1913
1913
Function *F = Call->getCalledFunction ();
1914
1914
assert (F);
1915
1915
if (F->isIntrinsic ()) {
1916
- return ;
1916
+ return Call ;
1917
1917
}
1918
1918
Call->setCallingConv (F->getCallingConv ());
1919
1919
Call->setAttributes (F->getAttributes ());
1920
+ return Call;
1920
1921
}
1921
1922
1922
1923
bool isSPIRVBuiltinVariable (GlobalVariable *GV,
@@ -1966,6 +1967,75 @@ bool isSPIRVBuiltinVariable(GlobalVariable *GV,
1966
1967
// %4 = call spir_func i64 @_Z13get_global_idj(i32 2) #1
1967
1968
// %5 = insertelement <3 x i64> %3, i64 %4, i32 2
1968
1969
// %6 = extractelement <3 x i64> %5, i32 0
1970
+
1971
+ // / Recursively look through the uses of a global variable, including casts or
1972
+ // / gep offsets, to find all loads of the variable. Gep offsets that are non-0
1973
+ // / are accumulated in the AccumulatedOffset parameter, which will eventually be
1974
+ // / used to figure out which index of a variable is being used.
1975
+ static void replaceUsesOfBuiltinVar (Value *V, const APInt &AccumulatedOffset,
1976
+ Function *ReplacementFunc) {
1977
+ const DataLayout &DL = ReplacementFunc->getParent ()->getDataLayout ();
1978
+ SmallVector<Instruction *, 4 > InstsToRemove;
1979
+ for (User *U : V->users ()) {
1980
+ if (auto *Cast = dyn_cast<CastInst>(U)) {
1981
+ replaceUsesOfBuiltinVar (Cast, AccumulatedOffset, ReplacementFunc);
1982
+ InstsToRemove.push_back (Cast);
1983
+ } else if (auto *GEP = dyn_cast<GetElementPtrInst>(U)) {
1984
+ APInt NewOffset = AccumulatedOffset.sextOrTrunc (
1985
+ DL.getIndexSizeInBits (GEP->getPointerAddressSpace ()));
1986
+ if (!GEP->accumulateConstantOffset (DL, NewOffset))
1987
+ llvm_unreachable (" Illegal GEP of a SPIR-V builtin variable" );
1988
+ replaceUsesOfBuiltinVar (GEP, NewOffset, ReplacementFunc);
1989
+ InstsToRemove.push_back (GEP);
1990
+ } else if (auto *Load = dyn_cast<LoadInst>(U)) {
1991
+ // Figure out which index the accumulated offset corresponds to. If we
1992
+ // have a weird offset (e.g., trying to load byte 7), bail out.
1993
+ Type *ScalarTy = ReplacementFunc->getReturnType ();
1994
+ APInt Index;
1995
+ uint64_t Remainder;
1996
+ APInt::udivrem (AccumulatedOffset, ScalarTy->getScalarSizeInBits () / 8 ,
1997
+ Index, Remainder);
1998
+ if (Remainder != 0 )
1999
+ llvm_unreachable (" Illegal GEP of a SPIR-V builtin variable" );
2000
+
2001
+ IRBuilder<> Builder (Load);
2002
+ Value *Replacement;
2003
+ if (ReplacementFunc->getFunctionType ()->getNumParams () == 0 ) {
2004
+ if (Load->getType () != ScalarTy)
2005
+ llvm_unreachable (" Illegal use of a SPIR-V builtin variable" );
2006
+ Replacement =
2007
+ setAttrByCalledFunc (Builder.CreateCall (ReplacementFunc, {}));
2008
+ } else {
2009
+ // The function has an index parameter.
2010
+ if (auto *VecTy = dyn_cast<FixedVectorType>(Load->getType ())) {
2011
+ if (!Index.isZero ())
2012
+ llvm_unreachable (" Illegal use of a SPIR-V builtin variable" );
2013
+ Replacement = UndefValue::get (VecTy);
2014
+ for (unsigned I = 0 ; I < VecTy->getNumElements (); I++) {
2015
+ Replacement = Builder.CreateInsertElement (
2016
+ Replacement,
2017
+ setAttrByCalledFunc (
2018
+ Builder.CreateCall (ReplacementFunc, {Builder.getInt32 (I)})),
2019
+ Builder.getInt32 (I));
2020
+ }
2021
+ } else if (Load->getType () == ScalarTy) {
2022
+ Replacement = setAttrByCalledFunc (Builder.CreateCall (
2023
+ ReplacementFunc, {Builder.getInt32 (Index.getZExtValue ())}));
2024
+ } else {
2025
+ llvm_unreachable (" Illegal load type of a SPIR-V builtin variable" );
2026
+ }
2027
+ }
2028
+ Load->replaceAllUsesWith (Replacement);
2029
+ InstsToRemove.push_back (Load);
2030
+ } else {
2031
+ llvm_unreachable (" Illegal use of a SPIR-V builtin variable" );
2032
+ }
2033
+ }
2034
+
2035
+ for (Instruction *I : InstsToRemove)
2036
+ I->eraseFromParent ();
2037
+ }
2038
+
1969
2039
bool lowerBuiltinVariableToCall (GlobalVariable *GV,
1970
2040
SPIRVBuiltinVariableKind Kind) {
1971
2041
// There might be dead constant users of GV (for example, SPIRVLowerConstExpr
@@ -2001,113 +2071,7 @@ bool lowerBuiltinVariableToCall(GlobalVariable *GV,
2001
2071
Func->setDoesNotAccessMemory ();
2002
2072
}
2003
2073
2004
- // Collect instructions in these containers to remove them later.
2005
- std::vector<Instruction *> Loads;
2006
- std::vector<Instruction *> Casts;
2007
- std::vector<Instruction *> GEPs;
2008
-
2009
- auto Replace = [&](std::vector<Value *> Arg, Instruction *I) {
2010
- auto *Call = CallInst::Create (Func, Arg, " " , I);
2011
- Call->takeName (I);
2012
- setAttrByCalledFunc (Call);
2013
- SPIRVDBG (dbgs () << " [lowerBuiltinVariableToCall] " << *I << " -> " << *Call
2014
- << ' \n ' ;)
2015
- I->replaceAllUsesWith (Call);
2016
- };
2017
-
2018
- // If HasIndexArg is true, we create 3 built-in calls and insertelement to
2019
- // get 3-element vector filled with ids and replace uses of Load instruction
2020
- // with this vector.
2021
- // If HasIndexArg is false, the result of the Load instruction is the value
2022
- // which should be replaced with the Func.
2023
- // Returns true if Load was replaced, false otherwise.
2024
- auto ReplaceIfLoad = [&](User *I) {
2025
- auto *LD = dyn_cast<LoadInst>(I);
2026
- if (!LD)
2027
- return false ;
2028
- std::vector<Value *> Vectors;
2029
- Loads.push_back (LD);
2030
- if (HasIndexArg) {
2031
- auto *VecTy = cast<FixedVectorType>(GVTy);
2032
- Value *EmptyVec = UndefValue::get (VecTy);
2033
- Vectors.push_back (EmptyVec);
2034
- const DebugLoc &DLoc = LD->getDebugLoc ();
2035
- for (unsigned I = 0 ; I < VecTy->getNumElements (); ++I) {
2036
- auto *Idx = ConstantInt::get (Type::getInt32Ty (C), I);
2037
- auto *Call = CallInst::Create (Func, {Idx}, " " , LD);
2038
- if (DLoc)
2039
- Call->setDebugLoc (DLoc);
2040
- setAttrByCalledFunc (Call);
2041
- auto *Insert = InsertElementInst::Create (Vectors.back (), Call, Idx);
2042
- if (DLoc)
2043
- Insert->setDebugLoc (DLoc);
2044
- Insert->insertAfter (Call);
2045
- Vectors.push_back (Insert);
2046
- }
2047
-
2048
- Value *Ptr = LD->getPointerOperand ();
2049
-
2050
- if (isa<FixedVectorType>(LD->getType ())) {
2051
- LD->replaceAllUsesWith (Vectors.back ());
2052
- } else {
2053
- auto *GEP = dyn_cast<GetElementPtrInst>(Ptr);
2054
- assert (GEP && " Unexpected pattern!" );
2055
- assert (GEP->getNumIndices () == 2 && " Unexpected pattern!" );
2056
- Value *Idx = GEP->getOperand (2 );
2057
- Value *Vec = Vectors.back ();
2058
- auto *NewExtract = ExtractElementInst::Create (Vec, Idx);
2059
- NewExtract->insertAfter (cast<Instruction>(Vec));
2060
- LD->replaceAllUsesWith (NewExtract);
2061
- }
2062
-
2063
- } else {
2064
- Replace ({}, LD);
2065
- }
2066
-
2067
- return true ;
2068
- };
2069
-
2070
- // Go over the GV users, find Load and ExtractElement instructions and
2071
- // replace them with the corresponding function call.
2072
- for (auto *UI : GV->users ()) {
2073
- // There might or might not be an addrspacecast instruction.
2074
- if (auto *ASCast = dyn_cast<AddrSpaceCastInst>(UI)) {
2075
- Casts.push_back (ASCast);
2076
- for (auto *CastUser : ASCast->users ()) {
2077
- if (ReplaceIfLoad (CastUser))
2078
- continue ;
2079
- if (auto *GEP = dyn_cast<GetElementPtrInst>(CastUser)) {
2080
- GEPs.push_back (GEP);
2081
- for (auto *GEPUser : GEP->users ()) {
2082
- if (!ReplaceIfLoad (GEPUser))
2083
- llvm_unreachable (" Unexpected pattern!" );
2084
- }
2085
- } else {
2086
- llvm_unreachable (" Unexpected pattern!" );
2087
- }
2088
- }
2089
- } else if (auto *GEP = dyn_cast<GetElementPtrInst>(UI)) {
2090
- GEPs.push_back (GEP);
2091
- for (auto *GEPUser : GEP->users ()) {
2092
- if (!ReplaceIfLoad (GEPUser))
2093
- llvm_unreachable (" Unexpected pattern!" );
2094
- }
2095
- } else if (!ReplaceIfLoad (UI)) {
2096
- llvm_unreachable (" Unexpected pattern!" );
2097
- }
2098
- }
2099
-
2100
- auto Erase = [](std::vector<Instruction *> &ToErase) {
2101
- for (Instruction *I : ToErase) {
2102
- assert (I->hasNUses (0 ));
2103
- I->eraseFromParent ();
2104
- }
2105
- };
2106
- // Order of erasing is important.
2107
- Erase (Loads);
2108
- Erase (GEPs);
2109
- Erase (Casts);
2110
-
2074
+ replaceUsesOfBuiltinVar (GV, APInt (64 , 0 ), Func);
2111
2075
return true ;
2112
2076
}
2113
2077
0 commit comments