-
Notifications
You must be signed in to change notification settings - Fork 11.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SPIRV] Implement type deduction and reference to function declarations for indirect calls using SPV_INTEL_function_pointers #111159
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
✅ With the latest revision this PR passed the C/C++ code formatter. |
VyacheslavLevytskyy
force-pushed
the
fun_ptr_2
branch
from
October 4, 2024 18:21
40d35c1
to
5c611cc
Compare
VyacheslavLevytskyy
changed the title
[SPIRV] Fix indirect calls for function pointers
[SPIRV] Implement type deduction and reference to function declarations for indirect calls using SPV_INTEL_function_pointers
Oct 11, 2024
@llvm/pr-subscribers-backend-spir-v Author: Vyacheslav Levytskyy (VyacheslavLevytskyy) ChangesThis PR improves implementation of SPV_INTEL_function_pointers and type inference for phi-nodes and indirect calls. Patch is 31.89 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/111159.diff 9 Files Affected:
diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
index 55b41627802096..8210e20ce5b10e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
@@ -78,6 +78,11 @@ class SPIRVAsmPrinter : public AsmPrinter {
void outputExecutionMode(const Module &M);
void outputAnnotations(const Module &M);
void outputModuleSections();
+ bool isHidden() {
+ return MF->getFunction()
+ .getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME)
+ .isValid();
+ }
void emitInstruction(const MachineInstr *MI) override;
void emitFunctionEntryLabel() override {}
@@ -131,7 +136,7 @@ void SPIRVAsmPrinter::emitFunctionHeader() {
TII = ST->getInstrInfo();
const Function &F = MF->getFunction();
- if (isVerbose()) {
+ if (isVerbose() && !isHidden()) {
OutStreamer->getCommentOS()
<< "-- Begin function "
<< GlobalValue::dropLLVMManglingEscape(F.getName()) << '\n';
@@ -149,11 +154,18 @@ void SPIRVAsmPrinter::outputOpFunctionEnd() {
// Emit OpFunctionEnd at the end of MF and clear BBNumToRegMap.
void SPIRVAsmPrinter::emitFunctionBodyEnd() {
+ // Do not emit anything if it's an internal service function.
+ if (isHidden())
+ return;
outputOpFunctionEnd();
MAI->BBNumToRegMap.clear();
}
void SPIRVAsmPrinter::emitOpLabel(const MachineBasicBlock &MBB) {
+ // Do not emit anything if it's an internal service function.
+ if (isHidden())
+ return;
+
MCInst LabelInst;
LabelInst.setOpcode(SPIRV::OpLabel);
LabelInst.addOperand(MCOperand::createReg(MAI->getOrCreateMBBRegister(MBB)));
@@ -162,7 +174,9 @@ void SPIRVAsmPrinter::emitOpLabel(const MachineBasicBlock &MBB) {
}
void SPIRVAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) {
- assert(!MBB.empty() && "MBB is empty!");
+ // Do not emit anything if it's an internal service function.
+ if (MBB.empty())
+ return;
// If it's the first MBB in MF, it has OpFunction and OpFunctionParameter, so
// OpLabel should be output after them.
diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
index 27a9cb0ba9b8c0..f8ce02a13c0f67 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
@@ -36,6 +36,13 @@ bool SPIRVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
const Value *Val, ArrayRef<Register> VRegs,
FunctionLoweringInfo &FLI,
Register SwiftErrorVReg) const {
+ // Ignore if called from the internal service function
+ if (MIRBuilder.getMF()
+ .getFunction()
+ .getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME)
+ .isValid())
+ return true;
+
// Maybe run postponed production of types for function pointers
if (IndirectCalls.size() > 0) {
produceIndirectPtrTypes(MIRBuilder);
@@ -280,6 +287,10 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
const Function &F,
ArrayRef<ArrayRef<Register>> VRegs,
FunctionLoweringInfo &FLI) const {
+ // Discard the internal service function
+ if (F.getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME).isValid())
+ return true;
+
assert(GR && "Must initialize the SPIRV type registry before lowering args.");
GR->setCurrentFunc(MIRBuilder.getMF());
@@ -576,6 +587,16 @@ bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
lowerFormalArguments(FirstBlockBuilder, *CF, VRegArgs, FuncInfo);
}
+ // Ignore the call if it's called from the internal service function
+ if (MIRBuilder.getMF()
+ .getFunction()
+ .getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME)
+ .isValid()) {
+ // insert a no-op
+ MIRBuilder.buildTrap();
+ return true;
+ }
+
unsigned CallOp;
if (Info.CB->isIndirectCall()) {
if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 370df24bc7af9e..8b7e9c48de6c75 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -69,6 +69,7 @@ class SPIRVEmitIntrinsics
SPIRVGlobalRegistry *GR = nullptr;
Function *F = nullptr;
bool TrackConstants = true;
+ bool HaveFunPtrs = false;
DenseMap<Instruction *, Constant *> AggrConsts;
DenseMap<Instruction *, Type *> AggrConstTypes;
DenseSet<Instruction *> AggrStores;
@@ -147,6 +148,10 @@ class SPIRVEmitIntrinsics
void replaceWithPtrcasted(Instruction *CI, Type *NewElemTy, Type *KnownElemTy,
CallInst *AssignCI);
+ bool runOnFunction(Function &F);
+ bool postprocessTypes();
+ bool processFunctionPointers(Module &M);
+
public:
static char ID;
SPIRVEmitIntrinsics() : ModulePass(ID) {
@@ -173,8 +178,6 @@ class SPIRVEmitIntrinsics
StringRef getPassName() const override { return "SPIRV emit intrinsics"; }
bool runOnModule(Module &M) override;
- bool runOnFunction(Function &F);
- bool postprocessTypes();
void getAnalysisUsage(AnalysisUsage &AU) const override {
ModulePass::getAnalysisUsage(AU);
@@ -384,7 +387,8 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeByValueDeep(
// Traverse User instructions to deduce an element pointer type of the operand.
Type *SPIRVEmitIntrinsics::deduceElementTypeByUsersDeep(
Value *Op, std::unordered_set<Value *> &Visited, bool UnknownElemTypeI8) {
- if (!Op || !isPointerTy(Op->getType()))
+ if (!Op || !isPointerTy(Op->getType()) || isa<ConstantPointerNull>(Op) ||
+ isa<UndefValue>(Op))
return nullptr;
if (auto ElemTy = getPointeeType(Op->getType()))
@@ -481,12 +485,25 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
if (isPointerTy(Op->getType()))
Ty = deduceElementTypeHelper(Op, Visited, UnknownElemTypeI8);
} else if (auto *Ref = dyn_cast<PHINode>(I)) {
- for (unsigned i = 0; i < Ref->getNumIncomingValues(); i++) {
+ Type *BestTy = nullptr;
+ unsigned MaxN = 1;
+ DenseMap<Type *, unsigned> PhiTys;
+ for (int i = Ref->getNumIncomingValues() - 1; i >= 0; --i) {
Ty = deduceElementTypeByUsersDeep(Ref->getIncomingValue(i), Visited,
UnknownElemTypeI8);
- if (Ty)
- break;
+ if (!Ty)
+ continue;
+ auto It = PhiTys.try_emplace(Ty, 1);
+ if (!It.second) {
+ ++It.first->second;
+ if (It.first->second > MaxN) {
+ MaxN = It.first->second;
+ BestTy = Ty;
+ }
+ }
}
+ if (BestTy)
+ Ty = BestTy;
} else if (auto *Ref = dyn_cast<SelectInst>(I)) {
for (Value *Op : {Ref->getTrueValue(), Ref->getFalseValue()}) {
Ty = deduceElementTypeByUsersDeep(Op, Visited, UnknownElemTypeI8);
@@ -642,6 +659,93 @@ static inline Type *getAtomicElemTy(SPIRVGlobalRegistry *GR, Instruction *I,
return nullptr;
}
+// Try to deduce element type for a call base. Returns false if this is an
+// indirect function invocation, and true otherwise.
+static bool deduceOperandElementTypeCalledFunction(
+ SPIRVGlobalRegistry *GR, Instruction *I,
+ SPIRV::InstructionSet::InstructionSet InstrSet, CallInst *CI,
+ SmallVector<std::pair<Value *, unsigned>> &Ops, Type *&KnownElemTy) {
+ Function *CalledF = CI->getCalledFunction();
+ if (!CalledF)
+ return false;
+ std::string DemangledName =
+ getOclOrSpirvBuiltinDemangledName(CalledF->getName());
+ if (DemangledName.length() > 0 &&
+ !StringRef(DemangledName).starts_with("llvm.")) {
+ auto [Grp, Opcode, ExtNo] =
+ SPIRV::mapBuiltinToOpcode(DemangledName, InstrSet);
+ if (Opcode == SPIRV::OpGroupAsyncCopy) {
+ for (unsigned i = 0, PtrCnt = 0; i < CI->arg_size() && PtrCnt < 2; ++i) {
+ Value *Op = CI->getArgOperand(i);
+ if (!isPointerTy(Op->getType()))
+ continue;
+ ++PtrCnt;
+ if (Type *ElemTy = GR->findDeducedElementType(Op))
+ KnownElemTy = ElemTy; // src will rewrite dest if both are defined
+ Ops.push_back(std::make_pair(Op, i));
+ }
+ } else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
+ if (CI->arg_size() < 2)
+ return true;
+ Value *Op = CI->getArgOperand(0);
+ if (!isPointerTy(Op->getType()))
+ return true;
+ switch (Opcode) {
+ case SPIRV::OpAtomicLoad:
+ case SPIRV::OpAtomicCompareExchangeWeak:
+ case SPIRV::OpAtomicCompareExchange:
+ case SPIRV::OpAtomicExchange:
+ case SPIRV::OpAtomicIAdd:
+ case SPIRV::OpAtomicISub:
+ case SPIRV::OpAtomicOr:
+ case SPIRV::OpAtomicXor:
+ case SPIRV::OpAtomicAnd:
+ case SPIRV::OpAtomicUMin:
+ case SPIRV::OpAtomicUMax:
+ case SPIRV::OpAtomicSMin:
+ case SPIRV::OpAtomicSMax: {
+ KnownElemTy = getAtomicElemTy(GR, I, Op);
+ if (!KnownElemTy)
+ return true;
+ Ops.push_back(std::make_pair(Op, 0));
+ } break;
+ }
+ }
+ }
+ return true;
+}
+
+// Try to deduce element type for a function pointer.
+static void deduceOperandElementTypeFunctionPointer(
+ SPIRVGlobalRegistry *GR, Instruction *I, CallInst *CI,
+ SmallVector<std::pair<Value *, unsigned>> &Ops, Type *&KnownElemTy) {
+ Value *Op = CI->getCalledOperand();
+ if (!Op || !isPointerTy(Op->getType()))
+ return;
+ Ops.push_back(std::make_pair(Op, std::numeric_limits<unsigned>::max()));
+ FunctionType *FTy = CI->getFunctionType();
+ bool IsNewFTy = false;
+ SmallVector<Type *, 4> ArgTys;
+ for (Value *Arg : CI->args()) {
+ Type *ArgTy = Arg->getType();
+ if (ArgTy->isPointerTy())
+ if (Type *ElemTy = GR->findDeducedElementType(Arg)) {
+ IsNewFTy = true;
+ ArgTy = TypedPointerType::get(ElemTy, getPointerAddressSpace(ArgTy));
+ }
+ ArgTys.push_back(ArgTy);
+ }
+ Type *RetTy = FTy->getReturnType();
+ if (I->getType()->isPointerTy())
+ if (Type *ElemTy = GR->findDeducedElementType(I)) {
+ IsNewFTy = true;
+ RetTy =
+ TypedPointerType::get(ElemTy, getPointerAddressSpace(I->getType()));
+ }
+ KnownElemTy =
+ IsNewFTy ? FunctionType::get(RetTy, ArgTys, FTy->isVarArg()) : FTy;
+}
+
// If the Instruction has Pointer operands with unresolved types, this function
// tries to deduce them. If the Instruction has Pointer operands with known
// types which differ from expected, this function tries to insert a bitcast to
@@ -747,54 +851,12 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(Instruction *I,
KnownElemTy = ElemTy1;
Ops.push_back(std::make_pair(Op0, 0));
}
- } else if (auto *CI = dyn_cast<CallInst>(I)) {
- if (Function *CalledF = CI->getCalledFunction()) {
- std::string DemangledName =
- getOclOrSpirvBuiltinDemangledName(CalledF->getName());
- if (DemangledName.length() > 0 &&
- !StringRef(DemangledName).starts_with("llvm.")) {
- auto [Grp, Opcode, ExtNo] =
- SPIRV::mapBuiltinToOpcode(DemangledName, InstrSet);
- if (Opcode == SPIRV::OpGroupAsyncCopy) {
- for (unsigned i = 0, PtrCnt = 0; i < CI->arg_size() && PtrCnt < 2;
- ++i) {
- Value *Op = CI->getArgOperand(i);
- if (!isPointerTy(Op->getType()))
- continue;
- ++PtrCnt;
- if (Type *ElemTy = GR->findDeducedElementType(Op))
- KnownElemTy = ElemTy; // src will rewrite dest if both are defined
- Ops.push_back(std::make_pair(Op, i));
- }
- } else if (Grp == SPIRV::Atomic || Grp == SPIRV::AtomicFloating) {
- if (CI->arg_size() < 2)
- return;
- Value *Op = CI->getArgOperand(0);
- if (!isPointerTy(Op->getType()))
- return;
- switch (Opcode) {
- case SPIRV::OpAtomicLoad:
- case SPIRV::OpAtomicCompareExchangeWeak:
- case SPIRV::OpAtomicCompareExchange:
- case SPIRV::OpAtomicExchange:
- case SPIRV::OpAtomicIAdd:
- case SPIRV::OpAtomicISub:
- case SPIRV::OpAtomicOr:
- case SPIRV::OpAtomicXor:
- case SPIRV::OpAtomicAnd:
- case SPIRV::OpAtomicUMin:
- case SPIRV::OpAtomicUMax:
- case SPIRV::OpAtomicSMin:
- case SPIRV::OpAtomicSMax: {
- KnownElemTy = getAtomicElemTy(GR, I, Op);
- if (!KnownElemTy)
- return;
- Ops.push_back(std::make_pair(Op, 0));
- } break;
- }
- }
- }
- }
+ } else if (CallInst *CI = dyn_cast<CallInst>(I)) {
+ if (!CI->isIndirectCall())
+ deduceOperandElementTypeCalledFunction(GR, I, InstrSet, CI, Ops,
+ KnownElemTy);
+ else if (HaveFunPtrs)
+ deduceOperandElementTypeFunctionPointer(GR, I, CI, Ops, KnownElemTy);
}
// There is no enough info to deduce types or all is valid.
@@ -844,7 +906,10 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(Instruction *I,
B.getInt32(getPointerAddressSpace(OpTy))};
CallInst *PtrCastI =
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
- I->setOperand(OpIt.second, PtrCastI);
+ if (OpIt.second == std::numeric_limits<unsigned>::max())
+ dyn_cast<CallInst>(I)->setCalledOperand(PtrCastI);
+ else
+ I->setOperand(OpIt.second, PtrCastI);
buildAssignPtr(B, KnownElemTy, PtrCastI);
}
}
@@ -1671,6 +1736,82 @@ void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {
}
}
+static FunctionType *getFunctionPointerElemType(Function *F,
+ SPIRVGlobalRegistry *GR) {
+ FunctionType *FTy = F->getFunctionType();
+ bool IsNewFTy = false;
+ SmallVector<Type *, 4> ArgTys;
+ for (Argument &Arg : F->args()) {
+ Type *ArgTy = Arg.getType();
+ if (ArgTy->isPointerTy())
+ if (Type *ElemTy = GR->findDeducedElementType(&Arg)) {
+ IsNewFTy = true;
+ ArgTy = TypedPointerType::get(ElemTy, getPointerAddressSpace(ArgTy));
+ }
+ ArgTys.push_back(ArgTy);
+ }
+ return IsNewFTy
+ ? FunctionType::get(FTy->getReturnType(), ArgTys, FTy->isVarArg())
+ : FTy;
+}
+
+bool SPIRVEmitIntrinsics::processFunctionPointers(Module &M) {
+ SmallVector<Function *> Worklist;
+ for (auto &F : M) {
+ if (F.isIntrinsic())
+ continue;
+ if (F.isDeclaration()) {
+ for (User *U : F.users()) {
+ CallInst *CI = dyn_cast<CallInst>(U);
+ if (!CI || CI->getCalledFunction() != &F) {
+ Worklist.push_back(&F);
+ break;
+ }
+ }
+ } else {
+ if (F.user_empty())
+ continue;
+ Type *FPElemTy = GR->findDeducedElementType(&F);
+ if (!FPElemTy)
+ FPElemTy = getFunctionPointerElemType(&F, GR);
+ for (User *U : F.users()) {
+ IntrinsicInst *II = dyn_cast<IntrinsicInst>(U);
+ if (!II || II->arg_size() != 3 || II->getOperand(0) != &F)
+ continue;
+ if (II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
+ II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
+ updateAssignType(II, &F, PoisonValue::get(FPElemTy));
+ break;
+ }
+ }
+ }
+ }
+ if (Worklist.empty())
+ return false;
+
+ std::string ServiceFunName = SPIRV_BACKEND_SERVICE_FUN_NAME;
+ if (!getVacantFunctionName(M, ServiceFunName))
+ report_fatal_error(
+ "cannot allocate a name for the internal service function");
+ LLVMContext &Ctx = M.getContext();
+ Function *SF =
+ Function::Create(FunctionType::get(Type::getVoidTy(Ctx), {}, false),
+ GlobalValue::PrivateLinkage, ServiceFunName, M);
+ SF->addFnAttr(SPIRV_BACKEND_SERVICE_FUN_NAME, "");
+ BasicBlock *BB = BasicBlock::Create(Ctx, "entry", SF);
+ IRBuilder<> IRB(BB);
+
+ for (Function *F : Worklist) {
+ SmallVector<Value *> Args;
+ for (const auto &Arg : F->args())
+ Args.push_back(PoisonValue::get(Arg.getType()));
+ IRB.CreateCall(F, Args);
+ }
+ IRB.CreateRetVoid();
+
+ return true;
+}
+
bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
if (Func.isDeclaration())
return false;
@@ -1680,6 +1821,10 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
InstrSet = ST.isOpenCLEnv() ? SPIRV::InstructionSet::OpenCL_std
: SPIRV::InstructionSet::GLSL_std_450;
+ if (!F)
+ HaveFunPtrs =
+ ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
+
F = &Func;
IRBuilder<> B(Func.getContext());
AggrConsts.clear();
@@ -1825,6 +1970,8 @@ bool SPIRVEmitIntrinsics::runOnModule(Module &M) {
}
Changed |= postprocessTypes();
+ if (HaveFunPtrs)
+ Changed |= processFunctionPointers(M);
return Changed;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index d204a8ac7975d8..dff33b16b9cfcf 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -598,4 +598,18 @@ MachineInstr *getVRegDef(MachineRegisterInfo &MRI, Register Reg) {
return MaybeDef;
}
+bool getVacantFunctionName(Module &M, std::string &Name) {
+ // It's a bit of paranoia, but still we don't want to have even a chance that
+ // the loop will work for too long.
+ constexpr unsigned MaxIters = 1024;
+ for (unsigned I = 0; I < MaxIters; ++I) {
+ std::string OrdName = Name + Twine(I).str();
+ if (!M.getFunction(OrdName)) {
+ Name = OrdName;
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index f7e8a827c2767f..83e717e6ea58fd 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -341,5 +341,8 @@ inline const Type *unifyPtrType(const Type *Ty) {
MachineInstr *getVRegDef(MachineRegisterInfo &MRI, Register Reg);
+#define SPIRV_BACKEND_SERVICE_FUN_NAME "__spirv_backend_service_fun"
+bool getVacantFunctionName(Module &M, std::string &Name);
+
} // namespace llvm
#endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fp-simple-hierarchy.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fp-simple-hierarchy.ll
new file mode 100644
index 00000000000000..d5a8fb3e7baafa
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_function_pointers/fp-simple-hierarchy.ll
@@ -0,0 +1,88 @@
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_function_pointers %s -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: OpName %[[I9:.*]] "_ZN13BaseIncrement9incrementEPi"
+; CHECK-DAG: OpName %[[I29:.*]] "_ZN12IncrementBy29incrementEPi"
+; CHECK-DAG: OpName %[[I49:.*]] "_ZN12IncrementBy49incrementEPi"
+; CHECK-DAG: OpName %[[I89:.*]] "_ZN12IncrementBy89incrementEPi"
+
+; CHECK-DAG: %[[TyVoid:.*]] = OpTypeVoid
+; CHECK-DAG: %[[TyArr:.*]] = OpTypeArray
+; CHECK-DAG: %[[TyStruct1:.*]] = OpTypeStruct %[[TyArr]]
+; CHECK-DAG: %[[TyStruct2:.*]] = OpTypeStruct %[[TyStruct1]]
+; CHECK-DAG: %[[TyPtrStruct2:.*]] = OpTypePointer Generic %[[TyStruct2]]
+; CHECK-DAG: %[[TyFun:.*]] = OpTypeFunction %[[TyVoid]] %[[TyPtrStruct2]] %[[#]]
+; CHECK-DAG: %[[TyPtrFun:.*]] = OpTypePointer Generic %[[TyFun]]
+; CHECK-DAG: %[[TyPtrPtrFun:.*]] = OpTypePointer Generic %[[TyPtrFun]]
+
+; CHECK: %[[I9]] = OpFunction
+; CHECK: %[[I29]] = OpFunction
+; CHECK: %[[I49]] = OpFunction
+; CHECK: %[[I89]] = OpFunction
+
+; CHECK: %[[Arg1:.*]] = OpPhi %[[TyPtrStruct2]]
+; CHECK: %[[VTbl:.*]] = OpBitcast %[[TyPtrPtrFun]] %[[#]]
+; CHECK: %[[FP:.*]] = OpLoad %[[TyPtrFun]] %[[VTbl]]
+; CHECK: %[[#]] = OpFunctionPointerCallINTEL %[[TyVoid]] %[[FP]] %[[Arg1]] %[[#]]
+
+%"cls::id" = type { %"cls::detail::array" }
+%"cls::detail::array" = type { [1 x i64] }
+%struct.obj_storage_t = type { %"struct.aligned_storage<BaseIncrement, IncrementBy2, IncrementBy4, IncrementBy8>::type" }
+%"struct.aligned_storage<BaseIncrement, IncrementBy2, IncrementBy4, IncrementBy8>::type" = type { [8 x i8] }
+
+@...
[truncated]
|
VyacheslavLevytskyy
force-pushed
the
fun_ptr_2
branch
from
October 11, 2024 19:29
de86953
to
db9f367
Compare
michalpaszkowski
approved these changes
Oct 15, 2024
bricknerb
pushed a commit
to bricknerb/llvm-project
that referenced
this pull request
Oct 16, 2024
…ns for indirect calls using SPV_INTEL_function_pointers (llvm#111159) This PR improves implementation of SPV_INTEL_function_pointers and type inference for phi-nodes and indirect calls.
DanielCChen
pushed a commit
to DanielCChen/llvm-project
that referenced
this pull request
Oct 16, 2024
…ns for indirect calls using SPV_INTEL_function_pointers (llvm#111159) This PR improves implementation of SPV_INTEL_function_pointers and type inference for phi-nodes and indirect calls.
bricknerb
pushed a commit
to bricknerb/llvm-project
that referenced
this pull request
Oct 17, 2024
…ns for indirect calls using SPV_INTEL_function_pointers (llvm#111159) This PR improves implementation of SPV_INTEL_function_pointers and type inference for phi-nodes and indirect calls.
EricWF
pushed a commit
to efcs/llvm-project
that referenced
this pull request
Oct 22, 2024
…ns for indirect calls using SPV_INTEL_function_pointers (llvm#111159) This PR improves implementation of SPV_INTEL_function_pointers and type inference for phi-nodes and indirect calls.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR improves implementation of SPV_INTEL_function_pointers and type inference for phi-nodes and indirect calls.