Skip to content

Add three missing llvm-spirv commits from Khronos #8306

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

Closed
wants to merge 3 commits into from
Closed
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
1 change: 1 addition & 0 deletions llvm-spirv/lib/SPIRV/SPIRVInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ const static char TranslateOCLMemScope[] = "__translate_ocl_memory_scope";
const static char TranslateSPIRVMemOrder[] = "__translate_spirv_memory_order";
const static char TranslateSPIRVMemScope[] = "__translate_spirv_memory_scope";
const static char TranslateSPIRVMemFence[] = "__translate_spirv_memory_fence";
const static char EntrypointPrefix[] = "__spirv_entry_";
} // namespace kSPIRVName

namespace kSPIRVPostfix {
Expand Down
108 changes: 65 additions & 43 deletions llvm-spirv/lib/SPIRV/SPIRVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2875,12 +2875,76 @@ bool SPIRVToLLVM::foreachFuncCtlMask(SourceTy Source, FuncTy Func) {
return true;
}

void SPIRVToLLVM::transFunctionAttrs(SPIRVFunction *BF, Function *F) {
if (BF->hasDecorate(DecorationReferencedIndirectlyINTEL))
F->addFnAttr("referenced-indirectly");
if (isFuncNoUnwind())
F->addFnAttr(Attribute::NoUnwind);
foreachFuncCtlMask(BF, [&](Attribute::AttrKind Attr) { F->addFnAttr(Attr); });

for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
++I) {
auto *BA = BF->getArgument(I->getArgNo());
mapValue(BA, &(*I));
setName(&(*I), BA);
BA->foreachAttr([&](SPIRVFuncParamAttrKind Kind) {
Attribute::AttrKind LLVMKind = SPIRSPIRVFuncParamAttrMap::rmap(Kind);
Type *AttrTy = nullptr;
switch (LLVMKind) {
case Attribute::AttrKind::ByVal:
case Attribute::AttrKind::StructRet:
AttrTy = transType(BA->getType()->getPointerElementType());
break;
default:
break; // do nothing
}
// Make sure to use a correct constructor for a typed/typeless attribute
auto A = AttrTy ? Attribute::get(*Context, LLVMKind, AttrTy)
: Attribute::get(*Context, LLVMKind);
I->addAttr(A);
});

AttrBuilder Builder(*Context);
SPIRVWord MaxOffset = 0;
if (BA->hasDecorate(DecorationMaxByteOffset, 0, &MaxOffset))
Builder.addDereferenceableAttr(MaxOffset);
SPIRVWord AlignmentBytes = 0;
if (BA->hasDecorate(DecorationAlignment, 0, &AlignmentBytes))
Builder.addAlignmentAttr(AlignmentBytes);
I->addAttrs(Builder);
}
BF->foreachReturnValueAttr([&](SPIRVFuncParamAttrKind Kind) {
if (Kind == FunctionParameterAttributeNoWrite)
return;
F->addRetAttr(SPIRSPIRVFuncParamAttrMap::rmap(Kind));
});
}

Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF) {
auto Loc = FuncMap.find(BF);
if (Loc != FuncMap.end())
return Loc->second;

auto IsKernel = isKernel(BF);

if (IsKernel) {
// search for a previous function with the same name
// upgrade it to a kernel and drop this if it's found
for (auto &I : FuncMap) {
auto BFName = I.getFirst()->getName();
if (BF->getName() == BFName) {
auto *F = I.getSecond();
F->setCallingConv(CallingConv::SPIR_KERNEL);
F->setLinkage(GlobalValue::ExternalLinkage);
F->setDSOLocal(false);
F = cast<Function>(mapValue(BF, F));
mapFunction(BF, F);
transFunctionAttrs(BF, F);
return F;
}
}
}

auto Linkage = IsKernel ? GlobalValue::ExternalLinkage : transLinkageType(BF);
FunctionType *FT = cast<FunctionType>(transType(BF->getFunctionType()));
std::string FuncName = BF->getName();
Expand Down Expand Up @@ -2924,49 +2988,7 @@ Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF) {

F->setCallingConv(IsKernel ? CallingConv::SPIR_KERNEL
: CallingConv::SPIR_FUNC);
if (BF->hasDecorate(DecorationReferencedIndirectlyINTEL))
F->addFnAttr("referenced-indirectly");
if (isFuncNoUnwind())
F->addFnAttr(Attribute::NoUnwind);
foreachFuncCtlMask(BF, [&](Attribute::AttrKind Attr) { F->addFnAttr(Attr); });

for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
++I) {
auto BA = BF->getArgument(I->getArgNo());
mapValue(BA, &(*I));
setName(&(*I), BA);
BA->foreachAttr([&](SPIRVFuncParamAttrKind Kind) {
Attribute::AttrKind LLVMKind = SPIRSPIRVFuncParamAttrMap::rmap(Kind);
Type *AttrTy = nullptr;
switch (LLVMKind) {
case Attribute::AttrKind::ByVal:
case Attribute::AttrKind::StructRet:
AttrTy = transType(BA->getType()->getPointerElementType());
break;
default:
break; // do nothing
}
// Make sure to use a correct constructor for a typed/typeless attribute
auto A = AttrTy ? Attribute::get(*Context, LLVMKind, AttrTy)
: Attribute::get(*Context, LLVMKind);
I->addAttr(A);
});

AttrBuilder Builder(*Context);
SPIRVWord MaxOffset = 0;
if (BA->hasDecorate(DecorationMaxByteOffset, 0, &MaxOffset))
Builder.addDereferenceableAttr(MaxOffset);
SPIRVWord AlignmentBytes = 0;
if (BA->hasDecorate(DecorationAlignment, 0, &AlignmentBytes))
Builder.addAlignmentAttr(AlignmentBytes);
I->addAttrs(Builder);
}
BF->foreachReturnValueAttr([&](SPIRVFuncParamAttrKind Kind) {
if (Kind == FunctionParameterAttributeNoWrite)
return;
F->addRetAttr(SPIRSPIRVFuncParamAttrMap::rmap(Kind));
});

transFunctionAttrs(BF, F);
// Creating all basic blocks before creating instructions.
for (size_t I = 0, E = BF->getNumBasicBlock(); I != E; ++I) {
transValue(BF->getBasicBlock(I), F, nullptr);
Expand Down
1 change: 1 addition & 0 deletions llvm-spirv/lib/SPIRV/SPIRVReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class SPIRVToLLVM : private BuiltinCallHelper {
std::vector<Value *> transValue(const std::vector<SPIRVValue *> &,
Function *F, BasicBlock *);
Function *transFunction(SPIRVFunction *F);
void transFunctionAttrs(SPIRVFunction *BF, Function *F);
Value *transBlockInvoke(SPIRVValue *Invoke, BasicBlock *BB);
Instruction *transWGSizeQueryBI(SPIRVInstruction *BI, BasicBlock *BB);
Instruction *transSGSizeQueryBI(SPIRVInstruction *BI, BasicBlock *BB);
Expand Down
65 changes: 65 additions & 0 deletions llvm-spirv/lib/SPIRV/SPIRVRegularizeLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "SPIRVRegularizeLLVM.h"
#include "OCLUtil.h"
#include "SPIRVInternal.h"
#include "SPIRVMDWalker.h"
#include "libSPIRV/SPIRVDebug.h"

#include "llvm/ADT/StringExtras.h" // llvm::isDigit
Expand Down Expand Up @@ -363,6 +364,7 @@ bool SPIRVRegularizeLLVMBase::runRegularizeLLVM(Module &Module) {
bool SPIRVRegularizeLLVMBase::regularize() {
eraseUselessFunctions(M);
expandSYCLTypeUsing(M);
addKernelEntryPoint(M);

for (auto I = M->begin(), E = M->end(); I != E;) {
Function *F = &(*I++);
Expand Down Expand Up @@ -522,6 +524,69 @@ bool SPIRVRegularizeLLVMBase::regularize() {
return true;
}

void SPIRVRegularizeLLVMBase::addKernelEntryPoint(Module *M) {
std::vector<Function *> Work;

// Get a list of all functions that have SPIR kernel calling conv
for (auto &F : *M) {
if (F.getCallingConv() == CallingConv::SPIR_KERNEL)
Work.push_back(&F);
}
for (auto &F : Work) {
// for declarations just make them into SPIR functions.
F->setCallingConv(CallingConv::SPIR_FUNC);
if (F->isDeclaration())
continue;

// Otherwise add a wrapper around the function to act as an entry point.
FunctionType *FType = F->getFunctionType();
std::string WrapName =
kSPIRVName::EntrypointPrefix + static_cast<std::string>(F->getName());
Function *WrapFn =
getOrCreateFunction(M, F->getReturnType(), FType->params(), WrapName);

auto *CallBB = BasicBlock::Create(M->getContext(), "", WrapFn);
IRBuilder<> Builder(CallBB);

Function::arg_iterator DestI = WrapFn->arg_begin();
for (const Argument &I : F->args()) {
DestI->setName(I.getName());
DestI++;
}
SmallVector<Value *, 1> Args;
for (Argument &I : WrapFn->args()) {
Args.emplace_back(&I);
}
auto *CI = CallInst::Create(F, ArrayRef<Value *>(Args), "", CallBB);
CI->setCallingConv(F->getCallingConv());
CI->setAttributes(F->getAttributes());

// copy over all the metadata (should it be removed from F?)
SmallVector<std::pair<unsigned, MDNode *>> MDs;
F->getAllMetadata(MDs);
WrapFn->setAttributes(F->getAttributes());
for (auto MD = MDs.begin(), End = MDs.end(); MD != End; ++MD) {
WrapFn->addMetadata(MD->first, *MD->second);
}
WrapFn->setCallingConv(CallingConv::SPIR_KERNEL);
WrapFn->setLinkage(llvm::GlobalValue::InternalLinkage);

Builder.CreateRet(F->getReturnType()->isVoidTy() ? nullptr : CI);

// Have to find the spir-v metadata for execution mode and transfer it to
// the wrapper.
if (auto NMD = SPIRVMDWalker(*M).getNamedMD(kSPIRVMD::ExecutionMode)) {
while (!NMD.atEnd()) {
Function *MDF = nullptr;
auto N = NMD.nextOp(); /* execution mode MDNode */
N.get(MDF);
if (MDF == F)
N.M->replaceOperandWith(0, ValueAsMetadata::get(WrapFn));
}
}
}
}

} // namespace SPIRV

INITIALIZE_PASS(SPIRVRegularizeLLVMLegacy, "spvregular",
Expand Down
5 changes: 5 additions & 0 deletions llvm-spirv/lib/SPIRV/SPIRVRegularizeLLVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ class SPIRVRegularizeLLVMBase {
// Lower functions
bool regularize();

// SPIR-V disallows functions being entrypoints and called
// LLVM doesn't. This adds a wrapper around the entry point
// that later SPIR-V writer renames.
void addKernelEntryPoint(llvm::Module *M);

/// Some LLVM intrinsics that have no SPIR-V counterpart may be wrapped in
/// @spirv.llvm_intrinsic_* function. During reverse translation from SPIR-V
/// to LLVM IR we can detect this @spirv.llvm_intrinsic_* function and
Expand Down
56 changes: 37 additions & 19 deletions llvm-spirv/lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,17 +860,21 @@ SPIRVFunction *LLVMToSPIRVBase::transFunctionDecl(Function *F) {
static_cast<SPIRVFunction *>(mapValue(F, BM->addFunction(BFT)));
BF->setFunctionControlMask(transFunctionControlMask(F));
if (F->hasName()) {
if (isUniformGroupOperation(F))
BM->getErrorLog().checkError(
BM->isAllowedToUseExtension(
ExtensionID::SPV_KHR_uniform_group_instructions),
SPIRVEC_RequiresExtension, "SPV_KHR_uniform_group_instructions\n");

BM->setName(BF, F->getName().str());
if (isKernel(F)) {
/* strip the prefix as the runtime will be looking for this name */
std::string Prefix = kSPIRVName::EntrypointPrefix;
std::string Name = F->getName().str();
BM->setName(BF, Name.substr(Prefix.size()));
} else {
if (isUniformGroupOperation(F))
BM->getErrorLog().checkError(
BM->isAllowedToUseExtension(
ExtensionID::SPV_KHR_uniform_group_instructions),
SPIRVEC_RequiresExtension, "SPV_KHR_uniform_group_instructions\n");
BM->setName(BF, F->getName().str());
}
}
if (isKernel(F))
BM->addEntryPoint(ExecutionModelKernel, BF->getId());
else if (F->getLinkage() != GlobalValue::InternalLinkage)
if (!isKernel(F) && F->getLinkage() != GlobalValue::InternalLinkage)
BF->setLinkageType(transLinkageType(F));

// Translate OpenCL/SYCL buffer_location metadata if it's attached to the
Expand Down Expand Up @@ -4965,12 +4969,20 @@ bool LLVMToSPIRVBase::isAnyFunctionReachableFromFunction(
return false;
}

void LLVMToSPIRVBase::collectInputOutputVariables(SPIRVFunction *SF,
Function *F) {
std::vector<SPIRVId>
LLVMToSPIRVBase::collectEntryPointInterfaces(SPIRVFunction *SF, Function *F) {
std::vector<SPIRVId> Interface;
for (auto &GV : M->globals()) {
const auto AS = GV.getAddressSpace();
SPIRVModule *BM = SF->getModule();
// TODO: intel/llvm customization
// GPU backend cannot handle EntryPoint Interface
// global variables
if (AS != SPIRAS_Input && AS != SPIRAS_Output)
continue;
if (!BM->isAllowedToUseVersion(VersionNumber::SPIRV_1_4))
if (AS != SPIRAS_Input && AS != SPIRAS_Output)
continue;

std::unordered_set<const Function *> Funcs;

Expand All @@ -4982,9 +4994,14 @@ void LLVMToSPIRVBase::collectInputOutputVariables(SPIRVFunction *SF,
}

if (isAnyFunctionReachableFromFunction(F, Funcs)) {
SF->addVariable(ValueMap[&GV]);
SPIRVWord ModuleVersion = static_cast<SPIRVWord>(BM->getSPIRVVersion());
if (AS != SPIRAS_Input && AS != SPIRAS_Output &&
ModuleVersion < static_cast<SPIRVWord>(VersionNumber::SPIRV_1_4))
BM->setMinSPIRVVersion(VersionNumber::SPIRV_1_4);
Interface.push_back(ValueMap[&GV]->getId());
}
}
return Interface;
}

void LLVMToSPIRVBase::mutateFuncArgType(
Expand Down Expand Up @@ -5185,10 +5202,10 @@ void LLVMToSPIRVBase::transFunction(Function *I) {
joinFPContract(I, FPContract::ENABLED);
fpContractUpdateRecursive(I, getFPContract(I));

bool IsKernelEntryPoint = isKernel(I);

if (IsKernelEntryPoint) {
collectInputOutputVariables(BF, I);
if (isKernel(I)) {
auto Interface = collectEntryPointInterfaces(BF, I);
BM->addEntryPoint(ExecutionModelKernel, BF->getId(), BF->getName(),
Interface);
}
}

Expand Down Expand Up @@ -5541,8 +5558,9 @@ bool LLVMToSPIRVBase::transMetadata() {
// Work around to translate kernel_arg_type and kernel_arg_type_qual metadata
static void transKernelArgTypeMD(SPIRVModule *BM, Function *F, MDNode *MD,
std::string MDName) {
std::string KernelArgTypesMDStr =
std::string(MDName) + "." + F->getName().str() + ".";
std::string Prefix = kSPIRVName::EntrypointPrefix;
std::string Name = F->getName().str().substr(Prefix.size());
std::string KernelArgTypesMDStr = std::string(MDName) + "." + Name + ".";
for (const auto &TyOp : MD->operands())
KernelArgTypesMDStr += cast<MDString>(TyOp)->getString().str() + ",";
BM->getString(KernelArgTypesMDStr);
Expand Down
3 changes: 2 additions & 1 deletion llvm-spirv/lib/SPIRV/SPIRVWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ class LLVMToSPIRVBase : protected BuiltinCallHelper {
bool isAnyFunctionReachableFromFunction(
const Function *FS,
const std::unordered_set<const Function *> Funcs) const;
void collectInputOutputVariables(SPIRVFunction *SF, Function *F);
std::vector<SPIRVId> collectEntryPointInterfaces(SPIRVFunction *BF,
Function *F);
};

class LLVMToSPIRVPass : public PassInfoMixin<LLVMToSPIRVPass> {
Expand Down
1 change: 0 additions & 1 deletion llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ class SPIRVDecorateLinkageAttr : public SPIRVDecorate {
#ifdef _SPIRV_SUPPORT_TEXT_FMT
if (SPIRVUseTextFormat) {
Encoder << getString(Literals.cbegin(), Literals.cend() - 1);
Encoder.OS << " ";
Encoder << (SPIRVLinkageTypeKind)Literals.back();
} else
#endif
Expand Down
6 changes: 4 additions & 2 deletions llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,9 +581,11 @@ void SPIRVEntryPoint::encode(spv_ostream &O) const {
}

void SPIRVEntryPoint::decode(std::istream &I) {
getDecoder(I) >> ExecModel >> Target >> Name >> Variables;
getDecoder(I) >> ExecModel >> Target >> Name;
Variables.resize(WordCount - FixedWC - getSizeInWords(Name) + 1);
getDecoder(I) >> Variables;
Module->setName(getOrCreateTarget(), Name);
Module->addEntryPoint(ExecModel, Target);
Module->addEntryPoint(ExecModel, Target, Name, Variables);
}

void SPIRVExecutionMode::encode(spv_ostream &O) const {
Expand Down
1 change: 1 addition & 0 deletions llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ template <Op OC> class SPIRVAnnotation : public SPIRVAnnotationGeneric {

class SPIRVEntryPoint : public SPIRVAnnotation<OpEntryPoint> {
public:
static const SPIRVWord FixedWC = 4;
SPIRVEntryPoint(SPIRVModule *TheModule, SPIRVExecutionModelKind,
SPIRVId TheId, const std::string &TheName,
std::vector<SPIRVId> Variables);
Expand Down
Loading