Skip to content
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

[OClToSPIRV] Do not identify user defined functions as OpenCL builtins #2512

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions lib/SPIRV/OCLToSPIRV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -1370,8 +1371,9 @@ void OCLToSPIRVBase::visitCallScalToVec(CallInst *CI, StringRef MangledName,
Type *VecTy = CI->getOperand(VecPos[0])->getType();
auto VecElemCount = cast<VectorType>(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(
Expand Down
2 changes: 1 addition & 1 deletion lib/SPIRV/OCLTypeToSPIRV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 5 additions & 3 deletions lib/SPIRV/OCLUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)");
}
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion lib/SPIRV/OCLUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions lib/SPIRV/SPIRVInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> *Dec = nullptr);
Op getSPIRVFuncOC(StringRef Name, Function *F,
SmallVectorImpl<std::string> *Dec = nullptr);

/// Get SPIR-V builtin variable enum given the canonical builtin name
/// Assume \param Name is in format __spirv_BuiltIn{Name}
Expand All @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions lib/SPIRV/SPIRVToOCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
4 changes: 2 additions & 2 deletions lib/SPIRV/SPIRVTypeScavenger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
22 changes: 15 additions & 7 deletions lib/SPIRV/SPIRVUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,11 +412,11 @@ bool isNonMangledOCLBuiltin(StringRef Name) {
isPipeOrAddressSpaceCastBI(Name.drop_front(2));
}

Op getSPIRVFuncOC(StringRef S, SmallVectorImpl<std::string> *Dec) {
Op getSPIRVFuncOC(StringRef S, Function *F, SmallVectorImpl<std::string> *Dec) {
Op OC;
SmallVector<StringRef, 2> 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)) ||
Expand All @@ -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;
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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<StringRef, 2> Postfix;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down
14 changes: 7 additions & 7 deletions lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> *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');
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -5701,7 +5701,7 @@ void LLVMToSPIRVBase::oclGetMutatedArgumentTypesByBuiltin(
llvm::FunctionType *FT, std::unordered_map<unsigned, Type *> &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;
Expand All @@ -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) {
Expand Down Expand Up @@ -5743,7 +5743,7 @@ SPIRVInstruction *LLVMToSPIRVBase::transBuiltinToInst(StringRef DemangledName,
CallInst *CI,
SPIRVBasicBlock *BB) {
SmallVector<std::string, 2> Dec;
auto OC = getSPIRVFuncOC(DemangledName, &Dec);
auto OC = getSPIRVFuncOC(DemangledName, CI->getCalledFunction(), &Dec);

if (OC == OpNop)
return nullptr;
Expand Down
46 changes: 46 additions & 0 deletions test/check_ocl_builtin.ll
Original file line number Diff line number Diff line change
@@ -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)

Loading