Skip to content

Commit 7a44ff1

Browse files
authored
[SPIR-V] Add SPV_INTEL_memory_access_aliasing extension (llvm#129800)
Spec can be found here intel/llvm#15225 TODO for future patches: - During spec review need to decide whether only FunctionCall or Atomic instructions can be decorated and if not - move the code around adding handling for other instructions; - Handle optional string metadata; - Handle LLVM atomic instructions; - Handle SPIR-V friendly atomic calls returning via sret argument. Signed-off-by: Sidorov, Dmitry <dmitry.sidorov@intel.com>
1 parent 0ce4b68 commit 7a44ff1

22 files changed

+495
-11
lines changed

llvm/docs/SPIRVUsage.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
173173
- Adds decorations that can be applied to global (module scope) variables to help code generation for FPGA devices.
174174
* - ``SPV_INTEL_media_block_io``
175175
- Adds additional subgroup block read and write functionality that allow applications to flexibly specify the width and height of the block to read from or write to a 2D image.
176+
* - ``SPV_INTEL_memory_access_aliasing``
177+
- Adds instructions and decorations to specify memory access aliasing, similar to alias.scope and noalias LLVM metadata.
176178
* - ``SPV_INTEL_optnone``
177179
- Adds OptNoneINTEL value for Function Control mask that indicates a request to not optimize the function.
178180
* - ``SPV_INTEL_split_barrier``
@@ -301,6 +303,10 @@ SPIR-V backend, along with their descriptions and argument details.
301303
- None
302304
- `[Type, Metadata]`
303305
- Assigns decoration to values by associating them with metadatas. Not emitted directly but used to support SPIR-V representation in LLVM IR.
306+
* - `int_spv_assign_aliasing_decoration`
307+
- None
308+
- `[Type, 32-bit Integer, Metadata]`
309+
- Assigns one of two memory aliasing decorations (specified by the second argument) to instructions using original aliasing metadata node. Not emitted directly but used to support SPIR-V representation in LLVM IR.
304310
* - `int_spv_track_constant`
305311
- Type
306312
- `[Type, Metadata]`

llvm/include/llvm/IR/IntrinsicsSPIRV.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,7 @@ let TargetPrefix = "spv" in {
138138
def int_spv_resource_store_typedbuffer
139139
: DefaultAttrsIntrinsic<[], [llvm_any_ty, llvm_i32_ty, llvm_anyvector_ty]>;
140140

141+
// Memory aliasing intrinsics
142+
def int_spv_assign_aliasing_decoration : Intrinsic<[], [llvm_any_ty, llvm_i32_ty, llvm_metadata_ty], [ImmArg<ArgIndex<1>>]>;
143+
141144
}

llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,9 @@ void SPIRVAsmPrinter::outputModuleSections() {
611611
outputModuleSection(SPIRV::MB_DebugNames);
612612
// 7c. Debug: all OpModuleProcessed instructions.
613613
outputModuleSection(SPIRV::MB_DebugModuleProcessed);
614+
// xxx. SPV_INTEL_memory_access_aliasing instructions go before 8.
615+
// "All annotation instructions"
616+
outputModuleSection(SPIRV::MB_AliasingInsts);
614617
// 8. All annotation instructions (all decorations).
615618
outputAnnotations(*M);
616619
// 9. All type declarations (OpTypeXXX instructions), all constant

llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,20 @@ bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
695695
return false;
696696
MIB.addUse(Arg.Regs[0]);
697697
}
698+
699+
if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing)) {
700+
// Process aliasing metadata.
701+
const CallBase *CI = Info.CB;
702+
if (CI && CI->hasMetadata()) {
703+
if (MDNode *MD = CI->getMetadata(LLVMContext::MD_alias_scope))
704+
GR->buildMemAliasingOpDecorate(ResVReg, MIRBuilder,
705+
SPIRV::Decoration::AliasScopeINTEL, MD);
706+
if (MDNode *MD = CI->getMetadata(LLVMContext::MD_noalias))
707+
GR->buildMemAliasingOpDecorate(ResVReg, MIRBuilder,
708+
SPIRV::Decoration::NoAliasINTEL, MD);
709+
}
710+
}
711+
698712
return MIB.constrainAllUses(MIRBuilder.getTII(), *ST->getRegisterInfo(),
699713
*ST->getRegBankInfo());
700714
}

llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ static const std::map<std::string, SPIRV::Extension::Extension, std::less<>>
5353
SPIRV::Extension::Extension::SPV_INTEL_subgroups},
5454
{"SPV_INTEL_media_block_io",
5555
SPIRV::Extension::Extension::SPV_INTEL_media_block_io},
56+
{"SPV_INTEL_memory_access_aliasing",
57+
SPIRV::Extension::Extension::SPV_INTEL_memory_access_aliasing},
5658
{"SPV_INTEL_joint_matrix",
5759
SPIRV::Extension::Extension::SPV_INTEL_joint_matrix},
5860
{"SPV_KHR_uniform_group_instructions",

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ class SPIRVEmitIntrinsics
151151
unsigned OperandToReplace,
152152
IRBuilder<> &B);
153153
void insertPtrCastOrAssignTypeInstr(Instruction *I, IRBuilder<> &B);
154+
bool shouldTryToAddMemAliasingDecoration(Instruction *Inst);
154155
void insertSpirvDecorations(Instruction *I, IRBuilder<> &B);
155156
void processGlobalValue(GlobalVariable &GV, IRBuilder<> &B);
156157
void processParamTypes(Function *F, IRBuilder<> &B);
@@ -1169,6 +1170,7 @@ void SPIRVEmitIntrinsics::replaceMemInstrUses(Instruction *Old,
11691170
llvm_unreachable("illegal aggregate intrinsic user");
11701171
}
11711172
}
1173+
New->copyMetadata(*Old);
11721174
Old->eraseFromParent();
11731175
}
11741176

@@ -1752,6 +1754,7 @@ Instruction *SPIRVEmitIntrinsics::visitStoreInst(StoreInst &I) {
17521754
Intrinsic::spv_store, {I.getValueOperand()->getType(), PtrOp->getType()},
17531755
{I.getValueOperand(), PtrOp, B.getInt16(Flags),
17541756
B.getInt8(I.getAlign().value())});
1757+
NewI->copyMetadata(I);
17551758
I.eraseFromParent();
17561759
return NewI;
17571760
}
@@ -1955,13 +1958,64 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
19551958
}
19561959
}
19571960

1961+
bool SPIRVEmitIntrinsics::shouldTryToAddMemAliasingDecoration(
1962+
Instruction *Inst) {
1963+
const SPIRVSubtarget *STI = TM->getSubtargetImpl(*Inst->getFunction());
1964+
if (!STI->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing))
1965+
return false;
1966+
// Add aliasing decorations to internal load and store intrinsics
1967+
// and atomic instructions, skipping atomic store as it won't have ID to
1968+
// attach the decoration.
1969+
CallInst *CI = dyn_cast<CallInst>(Inst);
1970+
if (!CI)
1971+
return false;
1972+
if (Function *Fun = CI->getCalledFunction()) {
1973+
if (Fun->isIntrinsic()) {
1974+
switch (Fun->getIntrinsicID()) {
1975+
case Intrinsic::spv_load:
1976+
case Intrinsic::spv_store:
1977+
return true;
1978+
default:
1979+
return false;
1980+
}
1981+
}
1982+
std::string Name = getOclOrSpirvBuiltinDemangledName(Fun->getName());
1983+
const std::string Prefix = "__spirv_Atomic";
1984+
const bool IsAtomic = Name.find(Prefix) == 0;
1985+
1986+
if (!Fun->getReturnType()->isVoidTy() && IsAtomic)
1987+
return true;
1988+
}
1989+
return false;
1990+
}
1991+
19581992
void SPIRVEmitIntrinsics::insertSpirvDecorations(Instruction *I,
19591993
IRBuilder<> &B) {
19601994
if (MDNode *MD = I->getMetadata("spirv.Decorations")) {
19611995
setInsertPointAfterDef(B, I);
19621996
B.CreateIntrinsic(Intrinsic::spv_assign_decoration, {I->getType()},
19631997
{I, MetadataAsValue::get(I->getContext(), MD)});
19641998
}
1999+
// Lower alias.scope/noalias metadata
2000+
{
2001+
auto processMemAliasingDecoration = [&](unsigned Kind) {
2002+
if (MDNode *AliasListMD = I->getMetadata(Kind)) {
2003+
if (shouldTryToAddMemAliasingDecoration(I)) {
2004+
uint32_t Dec = Kind == LLVMContext::MD_alias_scope
2005+
? SPIRV::Decoration::AliasScopeINTEL
2006+
: SPIRV::Decoration::NoAliasINTEL;
2007+
SmallVector<Value *, 3> Args = {
2008+
I, ConstantInt::get(B.getInt32Ty(), Dec),
2009+
MetadataAsValue::get(I->getContext(), AliasListMD)};
2010+
setInsertPointAfterDef(B, I);
2011+
B.CreateIntrinsic(Intrinsic::spv_assign_aliasing_decoration,
2012+
{I->getType()}, {Args});
2013+
}
2014+
}
2015+
};
2016+
processMemAliasingDecoration(LLVMContext::MD_alias_scope);
2017+
processMemAliasingDecoration(LLVMContext::MD_noalias);
2018+
}
19652019
}
19662020

19672021
void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,75 @@ LLT SPIRVGlobalRegistry::getRegType(SPIRVType *SpvType) const {
17591759
return LLT::scalar(64);
17601760
}
17611761

1762+
// Aliasing list MD contains several scope MD nodes whithin it. Each scope MD
1763+
// has a selfreference and an extra MD node for aliasing domain and also it
1764+
// can contain an optional string operand. Domain MD contains a self-reference
1765+
// with an optional string operand. Here we unfold the list, creating SPIR-V
1766+
// aliasing instructions.
1767+
// TODO: add support for an optional string operand.
1768+
MachineInstr *SPIRVGlobalRegistry::getOrAddMemAliasingINTELInst(
1769+
MachineIRBuilder &MIRBuilder, const MDNode *AliasingListMD) {
1770+
if (AliasingListMD->getNumOperands() == 0)
1771+
return nullptr;
1772+
if (auto L = AliasInstMDMap.find(AliasingListMD); L != AliasInstMDMap.end())
1773+
return L->second;
1774+
1775+
SmallVector<MachineInstr *> ScopeList;
1776+
MachineRegisterInfo *MRI = MIRBuilder.getMRI();
1777+
for (const MDOperand &MDListOp : AliasingListMD->operands()) {
1778+
if (MDNode *ScopeMD = dyn_cast<MDNode>(MDListOp)) {
1779+
if (ScopeMD->getNumOperands() < 2)
1780+
return nullptr;
1781+
MDNode *DomainMD = dyn_cast<MDNode>(ScopeMD->getOperand(1));
1782+
if (!DomainMD)
1783+
return nullptr;
1784+
auto *Domain = [&] {
1785+
auto D = AliasInstMDMap.find(DomainMD);
1786+
if (D != AliasInstMDMap.end())
1787+
return D->second;
1788+
const Register Ret = MRI->createVirtualRegister(&SPIRV::IDRegClass);
1789+
auto MIB =
1790+
MIRBuilder.buildInstr(SPIRV::OpAliasDomainDeclINTEL).addDef(Ret);
1791+
return MIB.getInstr();
1792+
}();
1793+
AliasInstMDMap.insert(std::make_pair(DomainMD, Domain));
1794+
auto *Scope = [&] {
1795+
auto S = AliasInstMDMap.find(ScopeMD);
1796+
if (S != AliasInstMDMap.end())
1797+
return S->second;
1798+
const Register Ret = MRI->createVirtualRegister(&SPIRV::IDRegClass);
1799+
auto MIB = MIRBuilder.buildInstr(SPIRV::OpAliasScopeDeclINTEL)
1800+
.addDef(Ret)
1801+
.addUse(Domain->getOperand(0).getReg());
1802+
return MIB.getInstr();
1803+
}();
1804+
AliasInstMDMap.insert(std::make_pair(ScopeMD, Scope));
1805+
ScopeList.push_back(Scope);
1806+
}
1807+
}
1808+
1809+
const Register Ret = MRI->createVirtualRegister(&SPIRV::IDRegClass);
1810+
auto MIB =
1811+
MIRBuilder.buildInstr(SPIRV::OpAliasScopeListDeclINTEL).addDef(Ret);
1812+
for (auto *Scope : ScopeList)
1813+
MIB.addUse(Scope->getOperand(0).getReg());
1814+
auto List = MIB.getInstr();
1815+
AliasInstMDMap.insert(std::make_pair(AliasingListMD, List));
1816+
return List;
1817+
}
1818+
1819+
void SPIRVGlobalRegistry::buildMemAliasingOpDecorate(
1820+
Register Reg, MachineIRBuilder &MIRBuilder, uint32_t Dec,
1821+
const MDNode *AliasingListMD) {
1822+
MachineInstr *AliasList =
1823+
getOrAddMemAliasingINTELInst(MIRBuilder, AliasingListMD);
1824+
if (!AliasList)
1825+
return;
1826+
MIRBuilder.buildInstr(SPIRV::OpDecorate)
1827+
.addUse(Reg)
1828+
.addImm(Dec)
1829+
.addUse(AliasList->getOperand(0).getReg());
1830+
}
17621831
void SPIRVGlobalRegistry::replaceAllUsesWith(Value *Old, Value *New,
17631832
bool DeleteOld) {
17641833
Old->replaceAllUsesWith(New);

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ class SPIRVGlobalRegistry {
9292
// Maps OpVariable and OpFunction-related v-regs to its LLVM IR definition.
9393
DenseMap<std::pair<const MachineFunction *, Register>, const Value *> Reg2GO;
9494

95+
// map of aliasing decorations to aliasing metadata
96+
std::unordered_map<const MDNode *, MachineInstr *> AliasInstMDMap;
97+
9598
// Add a new OpTypeXXX instruction without checking for duplicates.
9699
SPIRVType *createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder,
97100
SPIRV::AccessQualifier::AccessQualifier AQ,
@@ -621,6 +624,10 @@ class SPIRVGlobalRegistry {
621624
const TargetRegisterClass *getRegClass(SPIRVType *SpvType) const;
622625
LLT getRegType(SPIRVType *SpvType) const;
623626

627+
MachineInstr *getOrAddMemAliasingINTELInst(MachineIRBuilder &MIRBuilder,
628+
const MDNode *AliasingListMD);
629+
void buildMemAliasingOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder,
630+
uint32_t Dec, const MDNode *GVarMD);
624631
// Replace all uses of a |Old| with |New| updates the global registry type
625632
// mappings.
626633
void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld = true);

llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@ bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const {
9797
}
9898
}
9999

100+
bool SPIRVInstrInfo::isAliasingInstr(const MachineInstr &MI) const {
101+
switch (MI.getOpcode()) {
102+
case SPIRV::OpAliasDomainDeclINTEL:
103+
case SPIRV::OpAliasScopeDeclINTEL:
104+
case SPIRV::OpAliasScopeListDeclINTEL:
105+
return true;
106+
default:
107+
return false;
108+
}
109+
}
110+
100111
bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const {
101112
switch (MI.getOpcode()) {
102113
case SPIRV::OpCapability:
@@ -115,7 +126,8 @@ bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const {
115126
case SPIRV::OpModuleProcessed:
116127
return true;
117128
default:
118-
return isTypeDeclInstr(MI) || isConstantInstr(MI) || isDecorationInstr(MI);
129+
return isTypeDeclInstr(MI) || isConstantInstr(MI) ||
130+
isDecorationInstr(MI) || isAliasingInstr(MI);
119131
}
120132
}
121133

llvm/lib/Target/SPIRV/SPIRVInstrInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class SPIRVInstrInfo : public SPIRVGenInstrInfo {
3434
bool isInlineAsmDefInstr(const MachineInstr &MI) const;
3535
bool isTypeDeclInstr(const MachineInstr &MI) const;
3636
bool isDecorationInstr(const MachineInstr &MI) const;
37+
bool isAliasingInstr(const MachineInstr &MI) const;
3738
bool canUseFastMathFlags(const MachineInstr &MI) const;
3839
bool canUseNSW(const MachineInstr &MI) const;
3940
bool canUseNUW(const MachineInstr &MI) const;

0 commit comments

Comments
 (0)