@@ -69,6 +69,7 @@ class SPIRVEmitIntrinsics
69
69
SPIRVGlobalRegistry *GR = nullptr ;
70
70
Function *F = nullptr ;
71
71
bool TrackConstants = true ;
72
+ bool HaveFunPtrs = false ;
72
73
DenseMap<Instruction *, Constant *> AggrConsts;
73
74
DenseMap<Instruction *, Type *> AggrConstTypes;
74
75
DenseSet<Instruction *> AggrStores;
@@ -714,6 +715,37 @@ static bool deduceOperandElementTypeCalledFunction(
714
715
return true ;
715
716
}
716
717
718
+ // Try to deduce element type for a function pointer.
719
+ static void deduceOperandElementTypeFunctionPointer (
720
+ SPIRVGlobalRegistry *GR, Instruction *I, CallInst *CI,
721
+ SmallVector<std::pair<Value *, unsigned >> &Ops, Type *&KnownElemTy) {
722
+ Value *Op = CI->getCalledOperand ();
723
+ if (!Op || !isPointerTy (Op->getType ()))
724
+ return ;
725
+ Ops.push_back (std::make_pair (Op, std::numeric_limits<unsigned >::max ()));
726
+ FunctionType *FTy = CI->getFunctionType ();
727
+ bool IsNewFTy = false ;
728
+ SmallVector<Type *, 4 > ArgTys;
729
+ for (Value *Arg : CI->args ()) {
730
+ Type *ArgTy = Arg->getType ();
731
+ if (ArgTy->isPointerTy ())
732
+ if (Type *ElemTy = GR->findDeducedElementType (Arg)) {
733
+ IsNewFTy = true ;
734
+ ArgTy = TypedPointerType::get (ElemTy, getPointerAddressSpace (ArgTy));
735
+ }
736
+ ArgTys.push_back (ArgTy);
737
+ }
738
+ Type *RetTy = FTy->getReturnType ();
739
+ if (I->getType ()->isPointerTy ())
740
+ if (Type *ElemTy = GR->findDeducedElementType (I)) {
741
+ IsNewFTy = true ;
742
+ RetTy =
743
+ TypedPointerType::get (ElemTy, getPointerAddressSpace (I->getType ()));
744
+ }
745
+ KnownElemTy =
746
+ IsNewFTy ? FunctionType::get (RetTy, ArgTys, FTy->isVarArg ()) : FTy;
747
+ }
748
+
717
749
// If the Instruction has Pointer operands with unresolved types, this function
718
750
// tries to deduce them. If the Instruction has Pointer operands with known
719
751
// types which differ from expected, this function tries to insert a bitcast to
@@ -820,17 +852,11 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(Instruction *I,
820
852
Ops.push_back (std::make_pair (Op0, 0 ));
821
853
}
822
854
} else if (CallInst *CI = dyn_cast<CallInst>(I)) {
823
- if (!CI->isIndirectCall ()) {
855
+ if (!CI->isIndirectCall ())
824
856
deduceOperandElementTypeCalledFunction (GR, I, InstrSet, CI, Ops,
825
857
KnownElemTy);
826
- } else if (TM->getSubtarget <SPIRVSubtarget>(*F).canUseExtension (
827
- SPIRV::Extension::SPV_INTEL_function_pointers)) {
828
- Value *Op = CI->getCalledOperand ();
829
- if (!Op || !isPointerTy (Op->getType ()))
830
- return ;
831
- Ops.push_back (std::make_pair (Op, std::numeric_limits<unsigned >::max ()));
832
- KnownElemTy = CI->getFunctionType ();
833
- }
858
+ else if (HaveFunPtrs)
859
+ deduceOperandElementTypeFunctionPointer (GR, I, CI, Ops, KnownElemTy);
834
860
}
835
861
836
862
// There is no enough info to deduce types or all is valid.
@@ -1710,23 +1736,53 @@ void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {
1710
1736
}
1711
1737
}
1712
1738
1739
+ static FunctionType *getFunctionPointerElemType (Function *F,
1740
+ SPIRVGlobalRegistry *GR) {
1741
+ FunctionType *FTy = F->getFunctionType ();
1742
+ bool IsNewFTy = false ;
1743
+ SmallVector<Type *, 4 > ArgTys;
1744
+ for (Argument &Arg : F->args ()) {
1745
+ Type *ArgTy = Arg.getType ();
1746
+ if (ArgTy->isPointerTy ())
1747
+ if (Type *ElemTy = GR->findDeducedElementType (&Arg)) {
1748
+ IsNewFTy = true ;
1749
+ ArgTy = TypedPointerType::get (ElemTy, getPointerAddressSpace (ArgTy));
1750
+ }
1751
+ ArgTys.push_back (ArgTy);
1752
+ }
1753
+ return IsNewFTy
1754
+ ? FunctionType::get (FTy->getReturnType (), ArgTys, FTy->isVarArg ())
1755
+ : FTy;
1756
+ }
1757
+
1713
1758
bool SPIRVEmitIntrinsics::processFunctionPointers (Module &M) {
1714
- bool IsExt = false ;
1715
1759
SmallVector<Function *> Worklist;
1716
1760
for (auto &F : M) {
1717
- if (!IsExt) {
1718
- if (!TM->getSubtarget <SPIRVSubtarget>(F).canUseExtension (
1719
- SPIRV::Extension::SPV_INTEL_function_pointers))
1720
- return false ;
1721
- IsExt = true ;
1722
- }
1723
- if (!F.isDeclaration () || F.isIntrinsic ())
1761
+ if (F.isIntrinsic ())
1724
1762
continue ;
1725
- for (User *U : F.users ()) {
1726
- CallInst *CI = dyn_cast<CallInst>(U);
1727
- if (!CI || CI->getCalledFunction () != &F) {
1728
- Worklist.push_back (&F);
1729
- break ;
1763
+ if (F.isDeclaration ()) {
1764
+ for (User *U : F.users ()) {
1765
+ CallInst *CI = dyn_cast<CallInst>(U);
1766
+ if (!CI || CI->getCalledFunction () != &F) {
1767
+ Worklist.push_back (&F);
1768
+ break ;
1769
+ }
1770
+ }
1771
+ } else {
1772
+ if (F.user_empty ())
1773
+ continue ;
1774
+ Type *FPElemTy = GR->findDeducedElementType (&F);
1775
+ if (!FPElemTy)
1776
+ FPElemTy = getFunctionPointerElemType (&F, GR);
1777
+ for (User *U : F.users ()) {
1778
+ IntrinsicInst *II = dyn_cast<IntrinsicInst>(U);
1779
+ if (!II || II->arg_size () != 3 || II->getOperand (0 ) != &F)
1780
+ continue ;
1781
+ if (II->getIntrinsicID () == Intrinsic::spv_assign_ptr_type ||
1782
+ II->getIntrinsicID () == Intrinsic::spv_ptrcast) {
1783
+ updateAssignType (II, &F, PoisonValue::get (FPElemTy));
1784
+ break ;
1785
+ }
1730
1786
}
1731
1787
}
1732
1788
}
@@ -1765,6 +1821,10 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
1765
1821
InstrSet = ST.isOpenCLEnv () ? SPIRV::InstructionSet::OpenCL_std
1766
1822
: SPIRV::InstructionSet::GLSL_std_450;
1767
1823
1824
+ if (!F)
1825
+ HaveFunPtrs =
1826
+ ST.canUseExtension (SPIRV::Extension::SPV_INTEL_function_pointers);
1827
+
1768
1828
F = &Func;
1769
1829
IRBuilder<> B (Func.getContext ());
1770
1830
AggrConsts.clear ();
@@ -1910,7 +1970,8 @@ bool SPIRVEmitIntrinsics::runOnModule(Module &M) {
1910
1970
}
1911
1971
1912
1972
Changed |= postprocessTypes ();
1913
- Changed |= processFunctionPointers (M);
1973
+ if (HaveFunPtrs)
1974
+ Changed |= processFunctionPointers (M);
1914
1975
1915
1976
return Changed;
1916
1977
}
0 commit comments