diff --git a/lib/SPIRV/OCLToSPIRV.cpp b/lib/SPIRV/OCLToSPIRV.cpp index 6778b0cf32..de81361890 100644 --- a/lib/SPIRV/OCLToSPIRV.cpp +++ b/lib/SPIRV/OCLToSPIRV.cpp @@ -203,7 +203,7 @@ void OCLToSPIRVBase::visitCallInst(CallInst &CI) { auto MangledName = F->getName(); StringRef DemangledName; - if (!oclIsBuiltin(MangledName, DemangledName)) + if (!oclIsBuiltin(MangledName, DemangledName, F)) return; LLVM_DEBUG(dbgs() << "DemangledName: " << DemangledName << '\n'); @@ -926,7 +926,8 @@ void OCLToSPIRVBase::transBuiltin(CallInst *CI, OCLBuiltinTransInfo &Info) { } else { Info.UniqName = getSPIRVFuncName(OC); } - } else if ((ExtOp = getExtOp(Info.MangledName, Info.UniqName)) != ~0U) + } else if ((ExtOp = getExtOp(Info.MangledName, CI->getCalledFunction(), + Info.UniqName)) != ~0U) Info.UniqName = getSPIRVExtFuncName(SPIRVEIS_OpenCL, ExtOp); else if (SPIRSPIRVBuiltinVariableMap::find(Info.UniqName, &BVKind)) { // Map OCL work item builtins to SPV-IR work item builtins. @@ -1370,8 +1371,9 @@ void OCLToSPIRVBase::visitCallScalToVec(CallInst *CI, StringRef MangledName, Type *VecTy = CI->getOperand(VecPos[0])->getType(); auto VecElemCount = cast(VecTy)->getElementCount(); auto Mutator = mutateCallInst( - CI, getSPIRVExtFuncName(SPIRVEIS_OpenCL, - getExtOp(MangledName, DemangledName))); + CI, getSPIRVExtFuncName( + SPIRVEIS_OpenCL, + getExtOp(MangledName, CI->getCalledFunction(), DemangledName))); for (auto I : ScalarPos) Mutator.mapArg(I, [&](Value *V) { Instruction *Inst = InsertElementInst::Create( diff --git a/lib/SPIRV/OCLTypeToSPIRV.cpp b/lib/SPIRV/OCLTypeToSPIRV.cpp index 0c9f6f9a96..cda164cd25 100644 --- a/lib/SPIRV/OCLTypeToSPIRV.cpp +++ b/lib/SPIRV/OCLTypeToSPIRV.cpp @@ -199,7 +199,7 @@ void OCLTypeToSPIRVBase::adaptArgumentsBySamplerUse(Module &M) { continue; auto MangledName = F.getName(); StringRef DemangledName; - if (!oclIsBuiltin(MangledName, DemangledName, false)) + if (!oclIsBuiltin(MangledName, DemangledName, &F, false)) continue; if (DemangledName.find(kSPIRVName::SampledImage) == std::string::npos) continue; diff --git a/lib/SPIRV/OCLUtil.cpp b/lib/SPIRV/OCLUtil.cpp index 2e21568710..91b262faba 100644 --- a/lib/SPIRV/OCLUtil.cpp +++ b/lib/SPIRV/OCLUtil.cpp @@ -722,7 +722,8 @@ BarrierLiterals getBarrierLiterals(CallInst *CI) { StringRef DemangledName; assert(CI->getCalledFunction() && "Unexpected indirect call"); - if (!oclIsBuiltin(CI->getCalledFunction()->getName(), DemangledName)) { + if (!oclIsBuiltin(CI->getCalledFunction()->getName(), DemangledName, + CI->getCalledFunction())) { assert(0 && "call must a builtin (work_group_barrier or sub_group_barrier)"); } @@ -738,9 +739,10 @@ BarrierLiterals getBarrierLiterals(CallInst *CI) { Scope); } -unsigned getExtOp(StringRef OrigName, StringRef GivenDemangledName) { +unsigned getExtOp(StringRef OrigName, Function *F, + StringRef GivenDemangledName) { std::string DemangledName{GivenDemangledName}; - if (DemangledName.empty() || !oclIsBuiltin(OrigName, GivenDemangledName)) + if (DemangledName.empty() || !oclIsBuiltin(OrigName, GivenDemangledName, F)) return ~0U; LLVM_DEBUG(dbgs() << "getExtOp: demangled name: " << DemangledName << '\n'); OCLExtOpKind EOC; diff --git a/lib/SPIRV/OCLUtil.h b/lib/SPIRV/OCLUtil.h index 53cdfbd4b7..13a5e9ec61 100644 --- a/lib/SPIRV/OCLUtil.h +++ b/lib/SPIRV/OCLUtil.h @@ -411,7 +411,8 @@ const static char TypePrefix[] = "opencl.intel_sub_group_avc_"; /// not empty. /// \return instruction index of extended instruction if the OpenCL builtin /// function is translated to an extended instruction, otherwise ~0U. -unsigned getExtOp(StringRef MangledName, StringRef DemangledName = ""); +unsigned getExtOp(StringRef MangledName, Function *F, + StringRef DemangledName = ""); /// Get literal arguments of call of atomic_work_item_fence. AtomicWorkItemFenceLiterals getAtomicWorkItemFenceLiterals(CallInst *CI); diff --git a/lib/SPIRV/SPIRVInternal.h b/lib/SPIRV/SPIRVInternal.h index b2d8bb75ca..e7f33c8553 100644 --- a/lib/SPIRV/SPIRVInternal.h +++ b/lib/SPIRV/SPIRVInternal.h @@ -632,7 +632,8 @@ std::string getSPIRVExtFuncName(SPIRVExtInstSetKind Set, unsigned ExtOp, /// otherwise return OpNop. /// \param Dec contains decorations decoded from function name if it is /// not nullptr. -Op getSPIRVFuncOC(StringRef Name, SmallVectorImpl *Dec = nullptr); +Op getSPIRVFuncOC(StringRef Name, Function *F, + SmallVectorImpl *Dec = nullptr); /// Get SPIR-V builtin variable enum given the canonical builtin name /// Assume \param Name is in format __spirv_BuiltIn{Name} @@ -643,7 +644,8 @@ bool getSPIRVBuiltin(const std::string &Name, spv::BuiltIn &Builtin); /// \param DemangledName demanged name of the OpenCL built-in function /// \returns true if Name is the name of the OpenCL built-in function, /// false for other functions -bool oclIsBuiltin(StringRef Name, StringRef &DemangledName, bool IsCpp = false); +bool oclIsBuiltin(StringRef Name, StringRef &DemangledName, Function *F, + bool IsCpp = false); /// Check if a function returns void bool isVoidFuncTy(FunctionType *FT); diff --git a/lib/SPIRV/SPIRVToOCL.cpp b/lib/SPIRV/SPIRVToOCL.cpp index 87a89b945a..3d5c15098a 100644 --- a/lib/SPIRV/SPIRVToOCL.cpp +++ b/lib/SPIRV/SPIRVToOCL.cpp @@ -89,8 +89,8 @@ void SPIRVToOCLBase::visitCallInst(CallInst &CI) { StringRef DemangledName; Op OC = OpNop; SPIRVBuiltinVariableKind BuiltinKind = SPIRVBuiltinVariableKind::BuiltInMax; - if (!oclIsBuiltin(MangledName, DemangledName) || - ((OC = getSPIRVFuncOC(DemangledName)) == OpNop && + if (!oclIsBuiltin(MangledName, DemangledName, F) || + ((OC = getSPIRVFuncOC(DemangledName, F)) == OpNop && !getSPIRVBuiltin(DemangledName.str(), BuiltinKind))) return; LLVM_DEBUG(dbgs() << "DemangledName = " << DemangledName.str() << '\n' diff --git a/lib/SPIRV/SPIRVTypeScavenger.cpp b/lib/SPIRV/SPIRVTypeScavenger.cpp index 6116658036..6755c23b3f 100644 --- a/lib/SPIRV/SPIRVTypeScavenger.cpp +++ b/lib/SPIRV/SPIRVTypeScavenger.cpp @@ -446,9 +446,9 @@ bool SPIRVTypeScavenger::typeIntrinsicCall( }; StringRef DemangledName; - if (oclIsBuiltin(TargetFn->getName(), DemangledName) || + if (oclIsBuiltin(TargetFn->getName(), DemangledName, TargetFn) || isDecoratedSPIRVFunc(TargetFn, DemangledName)) { - Op OC = getSPIRVFuncOC(DemangledName); + Op OC = getSPIRVFuncOC(DemangledName, TargetFn); switch (OC) { case OpAtomicLoad: case OpAtomicExchange: diff --git a/lib/SPIRV/SPIRVUtil.cpp b/lib/SPIRV/SPIRVUtil.cpp index acc32b6361..04a21f555b 100644 --- a/lib/SPIRV/SPIRVUtil.cpp +++ b/lib/SPIRV/SPIRVUtil.cpp @@ -412,11 +412,11 @@ bool isNonMangledOCLBuiltin(StringRef Name) { isPipeOrAddressSpaceCastBI(Name.drop_front(2)); } -Op getSPIRVFuncOC(StringRef S, SmallVectorImpl *Dec) { +Op getSPIRVFuncOC(StringRef S, Function *F, SmallVectorImpl *Dec) { Op OC; SmallVector Postfix; StringRef Name; - if (!oclIsBuiltin(S, Name)) + if (!oclIsBuiltin(S, Name, F)) Name = S; StringRef R(Name); if ((!Name.starts_with(kSPIRVName::Prefix) && !isNonMangledOCLBuiltin(S)) || @@ -440,7 +440,13 @@ bool getSPIRVBuiltin(const std::string &OrigName, spv::BuiltIn &B) { // Demangled name is a substring of the name. The DemangledName is updated only // if true is returned -bool oclIsBuiltin(StringRef Name, StringRef &DemangledName, bool IsCpp) { +bool oclIsBuiltin(StringRef Name, StringRef &DemangledName, Function *F, + bool IsCpp) { + // Avoid user defined functions from being wrongly identified as OpenCL + // builtins. + // TODO: Avoid identifying user-declared functions as OpenCL builtins. + if (!F->isDeclaration()) + return false; if (Name == "printf") { DemangledName = Name; return true; @@ -1794,7 +1800,8 @@ bool hasLoopMetadata(const Module *M) { bool isSPIRVOCLExtInst(const CallInst *CI, OCLExtOpKind *ExtOp) { StringRef DemangledName; - if (!oclIsBuiltin(CI->getCalledFunction()->getName(), DemangledName)) + if (!oclIsBuiltin(CI->getCalledFunction()->getName(), DemangledName, + CI->getCalledFunction())) return false; StringRef S = DemangledName; if (!S.starts_with(kSPIRVName::Prefix)) @@ -2131,7 +2138,7 @@ bool lowerBuiltinCallsToVariables(Module *M) { if (!F.isDeclaration()) continue; StringRef DemangledName; - if (!oclIsBuiltin(F.getName(), DemangledName)) + if (!oclIsBuiltin(F.getName(), DemangledName, &F)) continue; LLVM_DEBUG(dbgs() << "Function demangled name: " << DemangledName << '\n'); SmallVector Postfix; @@ -2294,7 +2301,7 @@ bool postProcessBuiltinsReturningStruct(Module *M, bool IsCpp) { if (F.hasName() && F.isDeclaration()) { LLVM_DEBUG(dbgs() << "[postProcess sret] " << F << '\n'); if (F.getReturnType()->isStructTy() && - oclIsBuiltin(F.getName(), DemangledName, IsCpp)) { + oclIsBuiltin(F.getName(), DemangledName, &F, IsCpp)) { if (!postProcessBuiltinReturningStruct(&F)) return false; } @@ -2310,7 +2317,8 @@ bool postProcessBuiltinsWithArrayArguments(Module *M, bool IsCpp) { for (auto &F : make_early_inc_range(M->functions())) { if (F.hasName() && F.isDeclaration()) { LLVM_DEBUG(dbgs() << "[postProcess array arg] " << F << '\n'); - if (hasArrayArg(&F) && oclIsBuiltin(F.getName(), DemangledName, IsCpp)) + if (hasArrayArg(&F) && + oclIsBuiltin(F.getName(), DemangledName, &F, IsCpp)) if (!postProcessBuiltinWithArrayArguments(&F, DemangledName)) return false; } diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 619bf608be..734da655d2 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -256,19 +256,19 @@ bool LLVMToSPIRVBase::isKernel(Function *F) { bool LLVMToSPIRVBase::isBuiltinTransToInst(Function *F) { StringRef DemangledName; - if (!oclIsBuiltin(F->getName(), DemangledName) && + if (!oclIsBuiltin(F->getName(), DemangledName, F) && !isDecoratedSPIRVFunc(F, DemangledName)) return false; SPIRVDBG(spvdbgs() << "CallInst: demangled name: " << DemangledName.str() << '\n'); - return getSPIRVFuncOC(DemangledName) != OpNop; + return getSPIRVFuncOC(DemangledName, F) != OpNop; } bool LLVMToSPIRVBase::isBuiltinTransToExtInst( Function *F, SPIRVExtInstSetKind *ExtSet, SPIRVWord *ExtOp, SmallVectorImpl *Dec) { StringRef DemangledName; - if (!oclIsBuiltin(F->getName(), DemangledName)) + if (!oclIsBuiltin(F->getName(), DemangledName, F)) return false; LLVM_DEBUG(dbgs() << "[oclIsBuiltinTransToExtInst] CallInst: demangled name: " << DemangledName << '\n'); @@ -5109,7 +5109,7 @@ SPIRVValue *LLVMToSPIRVBase::transDirectCallInst(CallInst *CI, if (MangledName.starts_with(SPCV_CAST) || MangledName == SAMPLER_INIT) return oclTransSpvcCastSampler(CI, BB); - if (oclIsBuiltin(MangledName, DemangledName) || + if (oclIsBuiltin(MangledName, DemangledName, F) || isDecoratedSPIRVFunc(F, DemangledName)) { if (auto *BV = transBuiltinToConstant(DemangledName, CI)) return BV; @@ -5701,7 +5701,7 @@ void LLVMToSPIRVBase::oclGetMutatedArgumentTypesByBuiltin( llvm::FunctionType *FT, std::unordered_map &ChangedType, Function *F) { StringRef Demangled; - if (!oclIsBuiltin(F->getName(), Demangled)) + if (!oclIsBuiltin(F->getName(), Demangled, F)) return; if (Demangled.find(kSPIRVName::SampledImage) == std::string::npos) return; @@ -5711,7 +5711,7 @@ void LLVMToSPIRVBase::oclGetMutatedArgumentTypesByBuiltin( SPIRVValue *LLVMToSPIRVBase::transBuiltinToConstant(StringRef DemangledName, CallInst *CI) { - Op OC = getSPIRVFuncOC(DemangledName); + Op OC = getSPIRVFuncOC(DemangledName, CI->getCalledFunction()); if (!isSpecConstantOpCode(OC)) return nullptr; if (OC == spv::OpSpecConstantComposite) { @@ -5743,7 +5743,7 @@ SPIRVInstruction *LLVMToSPIRVBase::transBuiltinToInst(StringRef DemangledName, CallInst *CI, SPIRVBasicBlock *BB) { SmallVector Dec; - auto OC = getSPIRVFuncOC(DemangledName, &Dec); + auto OC = getSPIRVFuncOC(DemangledName, CI->getCalledFunction(), &Dec); if (OC == OpNop) return nullptr; diff --git a/test/check_ocl_builtin.ll b/test/check_ocl_builtin.ll new file mode 100644 index 0000000000..a50ad86e2e --- /dev/null +++ b/test/check_ocl_builtin.ll @@ -0,0 +1,46 @@ +; Do not identify user defined function as OpenCL builtin. +; OpenCL builtins always appear as function declarations in LLVM IR. + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64" +target triple = "spir64-unknown-unknown" + +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: spirv-val %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV: Name [[fname:[0-9]+]] "_Z27atomic_fetch_and_sub_uint32Pii" +; CHECK-SPIRV-DAG: FunctionCall {{[0-9]+}} {{[0-9]+}} [[fname]] {{[0-9]+}} {{[0-9]+}} + +; CHECK-LLVM: call spir_func i32 @_Z27atomic_fetch_and_sub_uint32Pii + +; Function Attrs: mustprogress norecurse nounwind +define weak_odr dso_local spir_kernel void @_ZTSN4test_ocl_builtin(ptr addrspace(4) noundef %arrayidx.i311) { +entry: + %call.i312 = call spir_func noundef i32 @_Z27atomic_fetch_and_sub_uint32Pii(ptr addrspace(4) noundef %arrayidx.i311, i32 noundef 1) + ret void +} + +; Function Attrs: convergent inlinehint mustprogress norecurse nounwind +define linkonce_odr dso_local spir_func noundef i32 @_Z27atomic_fetch_and_sub_uint32Pii(ptr addrspace(4) noundef %p, i32 noundef %x) { +entry: + %call.i.i.i.i.i.i = tail call spir_func noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(ptr addrspace(4) noundef %p, i32 noundef 5) + %0 = addrspacecast ptr addrspace(1) %call.i.i.i.i.i.i to ptr addrspace(4) + call spir_func void @__itt_offload_atomic_op_start(ptr addrspace(4) %0, i32 2, i32 0) + %call3.i.i = tail call spir_func noundef i32 @_Z18__spirv_AtomicISubPU3AS1iN5__spv5Scope4FlagENS1_19MemorySemanticsMask4FlagEi(ptr addrspace(1) noundef %call.i.i.i.i.i.i, i32 noundef 1, i32 noundef 896, i32 noundef %x) + %1 = addrspacecast ptr addrspace(1) %call.i.i.i.i.i.i to ptr addrspace(4) + call spir_func void @__itt_offload_atomic_op_finish(ptr addrspace(4) %1, i32 2, i32 0) + ret i32 %call3.i.i +} + +declare dso_local spir_func noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi(ptr addrspace(4) noundef, i32 noundef) + +declare dso_local spir_func void @__itt_offload_atomic_op_start(ptr addrspace(4) noundef %object, i32 noundef %op_type, i32 noundef %mem_order) + +declare dso_local spir_func noundef i32 @_Z18__spirv_AtomicISubPU3AS1iN5__spv5Scope4FlagENS1_19MemorySemanticsMask4FlagEi(ptr addrspace(1) noundef, i32 noundef, i32 noundef, i32 noundef) + +declare dso_local spir_func void @__itt_offload_atomic_op_finish(ptr addrspace(4) noundef %object, i32 noundef %op_type, i32 noundef %mem_order) +