Skip to content

Commit 300ac16

Browse files
MrSidimsvmaksimo
authored andcommitted
Implement SPV_INTEL_memory_access_aliasing extension
* Implement SPV_INTEL_memory_access_aliasing extension This extension adds analogs of alias.scope and noalias metadata in SPIR-V. These metadata is being used to annotate non-aliasing memory accesses and being generated, for example, during inlining of functions with restrict pointer parameters. Spec: #3426 This patch also casually adds OpDecorateId in the translator flow. Signed-off-by: Dmitry Sidorov <dmitry.sidorov@intel.com> Original commit: KhronosGroup/SPIRV-LLVM-Translator@974749c
1 parent 2930cbe commit 300ac16

20 files changed

+834
-11
lines changed

llvm-spirv/include/LLVMSPIRVExtensions.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ EXT(SPV_INTEL_fpga_cluster_attributes)
3535
EXT(SPV_INTEL_loop_fuse)
3636
EXT(SPV_INTEL_long_constant_composite)
3737
EXT(SPV_INTEL_optnone)
38+
EXT(SPV_INTEL_memory_access_aliasing)

llvm-spirv/lib/SPIRV/SPIRVReader.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "SPIRVInstruction.h"
4646
#include "SPIRVInternal.h"
4747
#include "SPIRVMDBuilder.h"
48+
#include "SPIRVMemAliasingINTEL.h"
4849
#include "SPIRVModule.h"
4950
#include "SPIRVToLLVMDbgTran.h"
5051
#include "SPIRVType.h"
@@ -64,6 +65,7 @@
6465
#include "llvm/IR/Instructions.h"
6566
#include "llvm/IR/IntrinsicInst.h"
6667
#include "llvm/IR/LegacyPassManager.h"
68+
#include "llvm/IR/MDBuilder.h"
6769
#include "llvm/IR/Metadata.h"
6870
#include "llvm/IR/Module.h"
6971
#include "llvm/IR/Type.h"
@@ -1510,6 +1512,58 @@ static void replaceOperandWithAnnotationIntrinsicCallResult(Value *&V) {
15101512
}
15111513
}
15121514

1515+
// Translate aliasing memory access masks for SPIRVLoad and SPIRVStore
1516+
// instructions. These masks are mapped on alias.scope and noalias
1517+
// metadata in LLVM. Translation of optional string operand isn't yet supported
1518+
// in the translator.
1519+
template <typename SPIRVInstType>
1520+
void SPIRVToLLVM::transAliasingMemAccess(SPIRVInstType *BI, Instruction *I) {
1521+
static_assert(std::is_same<SPIRVInstType, SPIRVStore>::value ||
1522+
std::is_same<SPIRVInstType, SPIRVLoad>::value,
1523+
"Only stores and loads can be aliased by memory access mask");
1524+
bool IsAliasScope = BI->SPIRVMemoryAccess::isAliasScope();
1525+
bool IsNoAlias = BI->SPIRVMemoryAccess::isNoAlias();
1526+
if (!(IsAliasScope || IsNoAlias))
1527+
return;
1528+
uint32_t AliasMDKind = IsAliasScope ? LLVMContext::MD_alias_scope
1529+
: LLVMContext::MD_noalias;
1530+
SPIRVId AliasListId = BI->SPIRVMemoryAccess::getAliasing();
1531+
addMemAliasMetadata(I, AliasListId, AliasMDKind);
1532+
}
1533+
1534+
// Create and apply alias.scope/noalias metadata
1535+
void SPIRVToLLVM::addMemAliasMetadata(Instruction *I, SPIRVId AliasListId,
1536+
uint32_t AliasMDKind) {
1537+
SPIRVAliasScopeListDeclINTEL *AliasList =
1538+
BM->get<SPIRVAliasScopeListDeclINTEL>(AliasListId);
1539+
std::vector<SPIRVId> AliasScopeIds = AliasList->getArguments();
1540+
MDBuilder MDB(*Context);
1541+
SmallVector<Metadata *, 4> MDScopes;
1542+
for (const auto ScopeId : AliasScopeIds) {
1543+
SPIRVAliasScopeDeclINTEL *AliasScope =
1544+
BM->get<SPIRVAliasScopeDeclINTEL>(ScopeId);
1545+
std::vector<SPIRVId> AliasDomainIds = AliasScope->getArguments();
1546+
// Currently we expect exactly one argument for aliasing scope
1547+
// instruction.
1548+
// TODO: add translation of string scope and domain operand.
1549+
assert(AliasDomainIds.size() == 1 &&
1550+
"AliasScopeDeclINTEL must have exactly one argument");
1551+
SPIRVId AliasDomainId = AliasDomainIds[0];
1552+
// Create and store unique domain and scope metadata
1553+
MDAliasDomainMap.emplace(AliasDomainId,
1554+
MDB.createAnonymousAliasScopeDomain());
1555+
MDAliasScopeMap.emplace(ScopeId, MDB.createAnonymousAliasScope(
1556+
MDAliasDomainMap[AliasDomainId]));
1557+
MDScopes.emplace_back(MDAliasScopeMap[ScopeId]);
1558+
}
1559+
// Create and store unique alias.scope/noalias metadata
1560+
MDAliasListMap.emplace(
1561+
AliasListId,
1562+
MDNode::concatenate(I->getMetadata(LLVMContext::MD_alias_scope),
1563+
MDNode::get(*Context, MDScopes)));
1564+
I->setMetadata(AliasMDKind, MDAliasListMap[AliasListId]);
1565+
}
1566+
15131567
/// For instructions, this function assumes they are created in order
15141568
/// and appended to the given basic block. An instruction may use a
15151569
/// instruction from another BB which has not been translated. Such
@@ -1907,6 +1961,7 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
19071961
SI = new StoreInst(Src, Dst, isVolatile, Align(AlignValue), BB);
19081962
if (BS->SPIRVMemoryAccess::isNonTemporal())
19091963
transNonTemporalMetadata(SI);
1964+
transAliasingMemAccess<SPIRVStore>(BS, SI);
19101965
return mapValue(BV, SI);
19111966
}
19121967

@@ -1929,6 +1984,7 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
19291984
}
19301985
if (BL->SPIRVMemoryAccess::isNonTemporal())
19311986
transNonTemporalMetadata(LI);
1987+
transAliasingMemAccess<SPIRVLoad>(BL, LI);
19321988
return mapValue(BV, LI);
19331989
}
19341990

@@ -3749,6 +3805,32 @@ void SPIRVToLLVM::transIntelFPGADecorations(SPIRVValue *BV, Value *V) {
37493805
}
37503806
}
37513807

3808+
// Translate aliasing decorations applied to instructions. These decorations
3809+
// are mapped on alias.scope and noalias metadata in LLVM. Translation of
3810+
// optional string operand isn't yet supported in the translator.
3811+
void SPIRVToLLVM::transMemAliasingINTELDecorations(SPIRVValue *BV, Value *V) {
3812+
if (!BV->isInst())
3813+
return;
3814+
Instruction *Inst = dyn_cast<Instruction>(V);
3815+
if (!Inst)
3816+
return;
3817+
std::vector<SPIRVId> AliasListIds;
3818+
uint32_t AliasMDKind;
3819+
if (BV->hasDecorateId(internal::DecorationAliasScopeINTEL)) {
3820+
AliasMDKind = LLVMContext::MD_alias_scope;
3821+
AliasListIds =
3822+
BV->getDecorationIdLiterals(internal::DecorationAliasScopeINTEL);
3823+
} else if (BV->hasDecorateId(internal::DecorationNoAliasINTEL)) {
3824+
AliasMDKind = LLVMContext::MD_noalias;
3825+
AliasListIds =
3826+
BV->getDecorationIdLiterals(internal::DecorationNoAliasINTEL);
3827+
} else
3828+
return;
3829+
assert(AliasListIds.size() == 1 &&
3830+
"Memory aliasing decorations must have one argument");
3831+
addMemAliasMetadata(Inst, AliasListIds[0], AliasMDKind);
3832+
}
3833+
37523834
// Having UserSemantic decoration on Function is against the spec, but we allow
37533835
// this for various purposes (like prototyping new features when we need to
37543836
// attach some information on function and propagate that through SPIR-V and
@@ -3800,6 +3882,7 @@ bool SPIRVToLLVM::transDecoration(SPIRVValue *BV, Value *V) {
38003882
return false;
38013883

38023884
transIntelFPGADecorations(BV, V);
3885+
transMemAliasingINTELDecorations(BV, V);
38033886

38043887
DbgTran->transDbgInfo(BV, V);
38053888
return true;

llvm-spirv/lib/SPIRV/SPIRVReader.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ class SPIRVToLLVM {
115115
CallInst *transArbFloatInst(SPIRVInstruction *BI, BasicBlock *BB,
116116
bool IsBinaryInst = false);
117117
bool transNonTemporalMetadata(Instruction *I);
118+
template <typename SPIRVInstType>
119+
void transAliasingMemAccess(SPIRVInstType *BI, Instruction *I);
120+
void addMemAliasMetadata(Instruction *I, SPIRVId AliasListId,
121+
uint32_t AliasMDKind);
118122
void transSourceLanguage();
119123
bool transSourceExtension();
120124
void transGeneratorMD();
@@ -183,6 +187,7 @@ class SPIRVToLLVM {
183187
typedef DenseMap<SPIRVValue *, Value *> SPIRVBlockToLLVMStructMap;
184188
typedef DenseMap<SPIRVFunction *, Function *> SPIRVToLLVMFunctionMap;
185189
typedef DenseMap<GlobalVariable *, SPIRVBuiltinVariableKind> BuiltinVarMap;
190+
typedef std::unordered_map<SPIRVId, MDNode *> SPIRVToLLVMMDAliasInstMap;
186191

187192
// A SPIRV value may be translated to a load instruction of a placeholder
188193
// global variable. This map records load instruction of these placeholders
@@ -210,6 +215,12 @@ class SPIRVToLLVM {
210215
// metadata SPIR-V instruction in SPIR-V representation of this basic block.
211216
SPIRVToLLVMLoopMetadataMap FuncLoopMetadataMap;
212217

218+
// These storages are used to prevent duplication of alias.scope/noalias
219+
// metadata
220+
SPIRVToLLVMMDAliasInstMap MDAliasDomainMap;
221+
SPIRVToLLVMMDAliasInstMap MDAliasScopeMap;
222+
SPIRVToLLVMMDAliasInstMap MDAliasListMap;
223+
213224
Type *mapType(SPIRVType *BT, Type *T);
214225

215226
// If a value is mapped twice, the existing mapped value is a placeholder,
@@ -282,6 +293,7 @@ class SPIRVToLLVM {
282293
void createCXXStructor(const char *ListName,
283294
SmallVectorImpl<Function *> &Funcs);
284295
void transIntelFPGADecorations(SPIRVValue *BV, Value *V);
296+
void transMemAliasingINTELDecorations(SPIRVValue *BV, Value *V);
285297
}; // class SPIRVToLLVM
286298

287299
} // namespace SPIRV

llvm-spirv/lib/SPIRV/SPIRVWriter.cpp

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include "SPIRVInternal.h"
5151
#include "SPIRVLLVMUtil.h"
5252
#include "SPIRVMDWalker.h"
53+
#include "SPIRVMemAliasingINTEL.h"
5354
#include "SPIRVModule.h"
5455
#include "SPIRVType.h"
5556
#include "SPIRVUtil.h"
@@ -1228,6 +1229,46 @@ SPIRVValue *LLVMToSPIRV::transAtomicLoad(LoadInst *LD, SPIRVBasicBlock *BB) {
12281229
BB, transType(LD->getType())));
12291230
}
12301231

1232+
// Aliasing list MD contains several scope MD nodes whithin it. Each scope MD
1233+
// has a selfreference and an extra MD node for aliasing domain and also it
1234+
// can contain an optional string operand. Domain MD contains a self-reference
1235+
// with an optional string operand. Here we unfold the list, creating SPIR-V
1236+
// aliasing instructions.
1237+
// TODO: add support for an optional string operand.
1238+
SPIRVEntry *addMemAliasingINTELInstructions(SPIRVModule *M,
1239+
MDNode *AliasingListMD) {
1240+
assert(AliasingListMD->getNumOperands() > 0 &&
1241+
"Aliasing list MD must have at least one operand");
1242+
std::vector<SPIRVId> ListId;
1243+
for (const MDOperand &MDListOp : AliasingListMD->operands()) {
1244+
if (MDNode *ScopeMD = dyn_cast<MDNode>(MDListOp)) {
1245+
assert(ScopeMD->getNumOperands() > 1 &&
1246+
"Aliasing scope MD must have at least two operands");
1247+
MDNode *DomainMD = cast<MDNode>(ScopeMD->getOperand(1));
1248+
auto *Domain =
1249+
M->getOrAddAliasDomainDeclINTELInst(std::vector<SPIRVId>(), DomainMD);
1250+
auto *Scope =
1251+
M->getOrAddAliasScopeDeclINTELInst({Domain->getId()}, ScopeMD);
1252+
ListId.push_back(Scope->getId());
1253+
}
1254+
}
1255+
return M->getOrAddAliasScopeListDeclINTELInst(ListId, AliasingListMD);
1256+
}
1257+
1258+
1259+
// Translate alias.scope/noalias metadata attached to store and load
1260+
// instructions.
1261+
void transAliasingMemAccess(SPIRVModule *BM, MDNode *AliasingListMD,
1262+
std::vector<uint32_t> &MemoryAccess,
1263+
SPIRVWord MemAccessMask) {
1264+
if (!BM->isAllowedToUseExtension(
1265+
ExtensionID::SPV_INTEL_memory_access_aliasing))
1266+
return;
1267+
MemoryAccess[0] |= MemAccessMask;
1268+
auto *MemAliasList = addMemAliasingINTELInstructions(BM, AliasingListMD);
1269+
MemoryAccess.push_back(MemAliasList->getId());
1270+
}
1271+
12311272
/// An instruction may use an instruction from another BB which has not been
12321273
/// translated. SPIRVForward should be created as place holder for these
12331274
/// instructions and replaced later by the real instructions.
@@ -1380,6 +1421,8 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V,
13801421
if (ST->isAtomic())
13811422
return transAtomicStore(ST, BB);
13821423

1424+
// Keep this vector to store MemoryAccess operands for both Alignment and
1425+
// Aliasing information.
13831426
std::vector<SPIRVWord> MemoryAccess(1, 0);
13841427
if (ST->isVolatile())
13851428
MemoryAccess[0] |= MemoryAccessVolatileMask;
@@ -1389,6 +1432,13 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V,
13891432
}
13901433
if (ST->getMetadata(LLVMContext::MD_nontemporal))
13911434
MemoryAccess[0] |= MemoryAccessNontemporalMask;
1435+
if (MDNode *AliasingListMD = ST->getMetadata(LLVMContext::MD_alias_scope))
1436+
transAliasingMemAccess(BM, AliasingListMD, MemoryAccess,
1437+
internal::MemoryAccessAliasScopeINTELMask);
1438+
else if (MDNode *AliasingListMD =
1439+
ST->getMetadata(LLVMContext::MD_noalias))
1440+
transAliasingMemAccess(BM, AliasingListMD, MemoryAccess,
1441+
internal::MemoryAccessNoAliasINTELMask);
13921442
if (MemoryAccess.front() == 0)
13931443
MemoryAccess.clear();
13941444

@@ -1403,7 +1453,9 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V,
14031453
if (LD->isAtomic())
14041454
return transAtomicLoad(LD, BB);
14051455

1406-
std::vector<SPIRVWord> MemoryAccess(1, 0);
1456+
// Keep this vector to store MemoryAccess operands for both Alignment and
1457+
// Aliasing information.
1458+
std::vector<uint32_t> MemoryAccess(1, 0);
14071459
if (LD->isVolatile())
14081460
MemoryAccess[0] |= MemoryAccessVolatileMask;
14091461
if (LD->getAlignment()) {
@@ -1412,6 +1464,13 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V,
14121464
}
14131465
if (LD->getMetadata(LLVMContext::MD_nontemporal))
14141466
MemoryAccess[0] |= MemoryAccessNontemporalMask;
1467+
if (MDNode *AliasingListMD = LD->getMetadata(LLVMContext::MD_alias_scope))
1468+
transAliasingMemAccess(BM, AliasingListMD, MemoryAccess,
1469+
internal::MemoryAccessAliasScopeINTELMask);
1470+
else if (MDNode *AliasingListMD =
1471+
LD->getMetadata(LLVMContext::MD_noalias))
1472+
transAliasingMemAccess(BM, AliasingListMD, MemoryAccess,
1473+
internal::MemoryAccessNoAliasINTELMask);
14151474
if (MemoryAccess.front() == 0)
14161475
MemoryAccess.clear();
14171476
return mapValue(V, BM->addLoadInst(transValue(LD->getPointerOperand(), BB),
@@ -1789,6 +1848,7 @@ bool LLVMToSPIRV::transDecoration(Value *V, SPIRVValue *BV) {
17891848
BV->setFPFastMathMode(M);
17901849
}
17911850
}
1851+
transMemAliasingINTELDecorations(V, BV);
17921852

17931853
return true;
17941854
}
@@ -1805,6 +1865,35 @@ bool LLVMToSPIRV::transAlign(Value *V, SPIRVValue *BV) {
18051865
return true;
18061866
}
18071867

1868+
// Apply aliasing decorations to instructions annotated with aliasing metadata.
1869+
// Do it for any instruction but loads and stores.
1870+
void LLVMToSPIRV::transMemAliasingINTELDecorations(Value *V, SPIRVValue *BV) {
1871+
if (!BM->isAllowedToUseExtension(
1872+
ExtensionID::SPV_INTEL_memory_access_aliasing))
1873+
return;
1874+
// Loads and Stores are handled during memory access mask addition
1875+
if (isa<StoreInst>(V) || isa<LoadInst>(V))
1876+
return;
1877+
1878+
Instruction *Inst = dyn_cast<Instruction>(V);
1879+
if (!Inst)
1880+
return;
1881+
1882+
if (MDNode *AliasingListMD =
1883+
Inst->getMetadata(LLVMContext::MD_alias_scope)) {
1884+
auto *MemAliasList =
1885+
addMemAliasingINTELInstructions(BM, AliasingListMD);
1886+
BV->addDecorate(new SPIRVDecorateId(
1887+
internal::DecorationAliasScopeINTEL, BV, MemAliasList->getId()));
1888+
} else if (MDNode *AliasingListMD =
1889+
Inst->getMetadata(LLVMContext::MD_noalias)) {
1890+
auto *MemAliasList =
1891+
addMemAliasingINTELInstructions(BM, AliasingListMD);
1892+
BV->addDecorate(new SPIRVDecorateId(
1893+
internal::DecorationNoAliasINTEL, BV, MemAliasList->getId()));
1894+
}
1895+
}
1896+
18081897
/// Do this after source language is set.
18091898
bool LLVMToSPIRV::transBuiltinSet() {
18101899
SPIRVId EISId;

llvm-spirv/lib/SPIRV/SPIRVWriter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ class LLVMToSPIRV : public ModulePass {
112112
SPIRVValue *transAsmINTEL(InlineAsm *Asm);
113113
SPIRVValue *transAsmCallINTEL(CallInst *Call, SPIRVBasicBlock *BB);
114114
bool transDecoration(Value *V, SPIRVValue *BV);
115+
void transMemAliasingINTELDecorations(Value *V, SPIRVValue *BV);
115116
SPIRVWord transFunctionControlMask(Function *);
116117
SPIRVFunction *transFunctionDecl(Function *F);
117118
void transVectorComputeMetadata(Function *F);

llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC, SPIRVWord WC,
8080
validate();
8181
updateModuleVersion();
8282
}
83+
8384
SPIRVDecorateGeneric::SPIRVDecorateGeneric(Op OC)
8485
: SPIRVAnnotationGeneric(OC), Dec(DecorationRelaxedPrecision),
8586
Owner(nullptr) {}
@@ -151,6 +152,22 @@ void SPIRVDecorate::decode(std::istream &I) {
151152
getOrCreateTarget()->addDecorate(this);
152153
}
153154

155+
void SPIRVDecorateId::encode(spv_ostream &O) const {
156+
SPIRVEncoder Encoder = getEncoder(O);
157+
Encoder << Target << Dec << Literals;
158+
}
159+
160+
void SPIRVDecorateId::setWordCount(SPIRVWord Count) {
161+
WordCount = Count;
162+
Literals.resize(WordCount - FixedWC);
163+
}
164+
165+
void SPIRVDecorateId::decode(std::istream &I) {
166+
SPIRVDecoder Decoder = getDecoder(I);
167+
Decoder >> Target >> Dec >> Literals;
168+
getOrCreateTarget()->addDecorate(this);
169+
}
170+
154171
void SPIRVMemberDecorate::encode(spv_ostream &O) const {
155172
SPIRVEncoder Encoder = getEncoder(O);
156173
Encoder << Target << MemberNumber << Dec;

0 commit comments

Comments
 (0)