Skip to content

Commit 3a32237

Browse files
committed
[Backport to 18][SPIR-V 1.4] Allow OpCopyMemorySized to have Memory Operands for both Source and Target
This change addresses p.4 of KhronosGroup#2460. No changes for OpCopyMemory as we currently don't use it in translation.
1 parent 1745c78 commit 3a32237

File tree

4 files changed

+70
-18
lines changed

4 files changed

+70
-18
lines changed

lib/SPIRV/SPIRVReader.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,8 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
18401840
CallInst *CI = nullptr;
18411841
llvm::Value *Dst = transValue(BC->getTarget(), F, BB);
18421842
MaybeAlign Align(BC->getAlignment());
1843+
MaybeAlign SrcAlign =
1844+
BC->getSrcAlignment() ? MaybeAlign(BC->getSrcAlignment()) : Align;
18431845
llvm::Value *Size = transValue(BC->getSize(), F, BB);
18441846
bool IsVolatile = BC->SPIRVMemoryAccess::isVolatile();
18451847
IRBuilder<> Builder(BB);
@@ -1852,7 +1854,7 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
18521854

18531855
// A ptr.annotation may have been generated for the source variable.
18541856
replaceOperandWithAnnotationIntrinsicCallResult(F, Src);
1855-
CI = Builder.CreateMemCpy(Dst, Align, Src, Align, Size, IsVolatile);
1857+
CI = Builder.CreateMemCpy(Dst, Align, Src, SrcAlign, Size, IsVolatile);
18561858
}
18571859
if (isFuncNoUnwind())
18581860
CI->getFunction()->addFnAttr(Attribute::NoUnwind);

lib/SPIRV/SPIRVWriter.cpp

+23-7
Original file line numberDiff line numberDiff line change
@@ -3919,19 +3919,30 @@ bool allowDecorateWithBufferLocationOrLatencyControlINTEL(IntrinsicInst *II) {
39193919

39203920
SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
39213921
SPIRVBasicBlock *BB) {
3922-
auto GetMemoryAccess = [](MemIntrinsic *MI) -> std::vector<SPIRVWord> {
3922+
auto GetMemoryAccess =
3923+
[](MemIntrinsic *MI,
3924+
bool AllowTwoMemAccessMasks) -> std::vector<SPIRVWord> {
39233925
std::vector<SPIRVWord> MemoryAccess(1, MemoryAccessMaskNone);
39243926
MaybeAlign DestAlignVal = MI->getDestAlign();
39253927
if (DestAlignVal) {
39263928
Align AlignVal = *DestAlignVal;
39273929
MemoryAccess[0] |= MemoryAccessAlignedMask;
3928-
if (auto *MTI = dyn_cast<MemTransferInst>(MI)) {
3930+
if (auto *MTI = dyn_cast<MemCpyInst>(MI)) {
39293931
MaybeAlign SourceAlignVal = MTI->getSourceAlign();
39303932
assert(SourceAlignVal && "Missed Source alignment!");
39313933

39323934
// In a case when alignment of source differs from dest one
3933-
// least value is guaranteed anyway.
3934-
AlignVal = std::min(*DestAlignVal, *SourceAlignVal);
3935+
// we either preserve both (allowed since SPIR-V 1.4), or the least
3936+
// value is guaranteed anyway.
3937+
if (AllowTwoMemAccessMasks) {
3938+
if (*DestAlignVal != *SourceAlignVal) {
3939+
MemoryAccess.push_back(DestAlignVal.valueOrOne().value());
3940+
MemoryAccess.push_back(MemoryAccessAlignedMask);
3941+
AlignVal = *SourceAlignVal;
3942+
}
3943+
} else {
3944+
AlignVal = std::min(*DestAlignVal, *SourceAlignVal);
3945+
}
39353946
}
39363947
MemoryAccess.push_back(AlignVal.value());
39373948
}
@@ -4425,14 +4436,19 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
44254436
transPointerType(Val->getType(), SPIRV::SPIRAS_Constant);
44264437
SPIRVValue *Source = BM->addUnaryInst(OpBitcast, SourceTy, Var, BB);
44274438
SPIRVValue *Target = transValue(MSI->getRawDest(), BB);
4428-
return BM->addCopyMemorySizedInst(Target, Source, CompositeTy->getLength(),
4429-
GetMemoryAccess(MSI), BB);
4439+
return BM->addCopyMemorySizedInst(
4440+
Target, Source, CompositeTy->getLength(),
4441+
GetMemoryAccess(MSI,
4442+
BM->isAllowedToUseVersion(VersionNumber::SPIRV_1_4)),
4443+
BB);
44304444
} break;
44314445
case Intrinsic::memcpy:
44324446
return BM->addCopyMemorySizedInst(
44334447
transValue(II->getOperand(0), BB), transValue(II->getOperand(1), BB),
44344448
transValue(II->getOperand(2), BB),
4435-
GetMemoryAccess(cast<MemIntrinsic>(II)), BB);
4449+
GetMemoryAccess(cast<MemIntrinsic>(II),
4450+
BM->isAllowedToUseVersion(VersionNumber::SPIRV_1_4)),
4451+
BB);
44364452
case Intrinsic::lifetime_start:
44374453
case Intrinsic::lifetime_end: {
44384454
Op OC = (II->getIntrinsicID() == Intrinsic::lifetime_start)

lib/SPIRV/libSPIRV/SPIRVInstruction.h

+26-5
Original file line numberDiff line numberDiff line change
@@ -378,14 +378,14 @@ class SPIRVInstTemplate : public BT {
378378
class SPIRVMemoryAccess {
379379
public:
380380
SPIRVMemoryAccess(const std::vector<SPIRVWord> &TheMemoryAccess)
381-
: TheMemoryAccessMask(0), Alignment(0), AliasScopeInstID(0),
382-
NoAliasInstID(0) {
381+
: TheMemoryAccessMask(0), Alignment(0), SrcAlignment(0),
382+
AliasScopeInstID(0), NoAliasInstID(0) {
383383
memoryAccessUpdate(TheMemoryAccess);
384384
}
385385

386386
SPIRVMemoryAccess()
387-
: TheMemoryAccessMask(0), Alignment(0), AliasScopeInstID(0),
388-
NoAliasInstID(0) {}
387+
: TheMemoryAccessMask(0), Alignment(0), SrcAlignment(0),
388+
AliasScopeInstID(0), NoAliasInstID(0) {}
389389

390390
void memoryAccessUpdate(const std::vector<SPIRVWord> &MemoryAccess) {
391391
if (!MemoryAccess.size())
@@ -406,7 +406,18 @@ class SPIRVMemoryAccess {
406406
if (MemoryAccess[0] & MemoryAccessNoAliasINTELMaskMask) {
407407
assert(MemoryAccess.size() > MemAccessNumParam &&
408408
"Aliasing operand is missing");
409-
NoAliasInstID = MemoryAccess[MemAccessNumParam];
409+
NoAliasInstID = MemoryAccess[MemAccessNumParam++];
410+
}
411+
412+
// Exit if there is no second memory operand mask
413+
if (MemoryAccess.size() == MemAccessNumParam)
414+
return;
415+
416+
size_t SecondMaskId = MemAccessNumParam++;
417+
if (MemoryAccess[SecondMaskId] & MemoryAccessAlignedMask) {
418+
assert(MemoryAccess.size() > MemAccessNumParam &&
419+
"Alignment operand is missing");
420+
SrcAlignment = MemoryAccess[MemAccessNumParam];
410421
}
411422
}
412423
SPIRVWord isVolatile() const {
@@ -423,12 +434,14 @@ class SPIRVMemoryAccess {
423434
}
424435
SPIRVWord getMemoryAccessMask() const { return TheMemoryAccessMask; }
425436
SPIRVWord getAlignment() const { return Alignment; }
437+
SPIRVWord getSrcAlignment() const { return SrcAlignment; }
426438
SPIRVWord getAliasScopeInstID() const { return AliasScopeInstID; }
427439
SPIRVWord getNoAliasInstID() const { return NoAliasInstID; }
428440

429441
protected:
430442
SPIRVWord TheMemoryAccessMask;
431443
SPIRVWord Alignment;
444+
SPIRVWord SrcAlignment;
432445
SPIRVId AliasScopeInstID;
433446
SPIRVId NoAliasInstID;
434447
};
@@ -2088,13 +2101,21 @@ class SPIRVCopyMemorySized : public SPIRVInstruction, public SPIRVMemoryAccess {
20882101
Size(TheSize->getId()) {
20892102
validate();
20902103
assert(TheBB && "Invalid BB");
2104+
updateModuleVersion();
20912105
}
20922106
// Incomplete constructor
20932107
SPIRVCopyMemorySized()
20942108
: SPIRVInstruction(OC), SPIRVMemoryAccess(), Target(SPIRVID_INVALID),
20952109
Source(SPIRVID_INVALID), Size(0) {
20962110
setHasNoId();
20972111
setHasNoType();
2112+
updateModuleVersion();
2113+
}
2114+
2115+
SPIRVWord getRequiredSPIRVVersion() const override {
2116+
if (getSrcAlignment())
2117+
return static_cast<SPIRVWord>(VersionNumber::SPIRV_1_4);
2118+
return static_cast<SPIRVWord>(VersionNumber::SPIRV_1_0);
20982119
}
20992120

21002121
SPIRVValue *getSource() { return getValue(Source); }

test/llvm-intrinsics/memcpy.align.ll

+18-5
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,21 @@
2525
; clang -cc1 -triple spir -disable-llvm-passes t.cl -emit-llvm -o t.ll
2626

2727
; RUN: llvm-as %s -o %t.bc
28-
; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt
28+
; RUN: llvm-spirv %t.bc --spirv-max-version=1.3 -spirv-text -o %t.txt
2929
; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV
30-
; RUN: llvm-spirv %t.bc -o %t.spv
30+
; RUN: llvm-spirv %t.bc --spirv-max-version=1.3 -o %t.spv
3131
; RUN: spirv-val %t.spv
3232
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
33-
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
33+
; RUN: llvm-dis %t.rev.bc
34+
; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM
35+
36+
; RUN: llvm-spirv %t.bc --spirv-max-version=1.4 -spirv-text -o %t.txt
37+
; RUN: FileCheck < %t.txt %s --check-prefix=ALIGN-MATCH-SPIRV
38+
; RUN: llvm-spirv %t.bc --spirv-max-version=1.4 -o %t.spv
39+
; RUN: spirv-val %t.spv
40+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
41+
; RUN: llvm-dis %t.rev.bc
42+
; RUN: FileCheck < %t.rev.ll %s --check-prefix=ALIGN-MATCH-LLVM
3443

3544
target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
3645
target triple = "spir"
@@ -53,8 +62,10 @@ entry:
5362
%b1 = getelementptr inbounds %struct.A, %struct.A* %agg.result, i32 0, i32 1
5463
%2 = bitcast %struct.B* %b1 to i8*
5564
%3 = bitcast %struct.B* %b to i8*
56-
; CHECK-SPIRV: CopyMemorySized {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} 4
65+
; CHECK-SPIRV: CopyMemorySized {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} 2 4
5766
; CHECK-LLVM: call void @llvm.memcpy.p0.p0.i32(ptr align 4 {{%[0-9]+}}, ptr align 4 {{%[0-9]+}}, i32 8, i1 false)
67+
; ALIGN-MATCH-SPIRV: CopyMemorySized {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} 2 8 2 4
68+
; ALIGN-MATCH-LLVM: call void @llvm.memcpy.p0.p0.i32(ptr align 8 {{%[0-9]+}}, ptr align 4 {{%[0-9]+}}, i32 8, i1 false)
5869
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %2, i8* align 4 %3, i32 8, i1 false), !tbaa.struct !4
5970
%4 = bitcast %struct.B* %b to i8*
6071
call void @llvm.lifetime.end.p0i8(i64 8, i8* %4) #2
@@ -85,8 +96,10 @@ entry:
8596
%b = getelementptr inbounds %struct.A, %struct.A* %a, i32 0, i32 1
8697
%2 = bitcast %struct.B* %agg.result to i8*
8798
%3 = bitcast %struct.B* %b to i8*
88-
; CHECK-SPIRV: CopyMemorySized {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} 4
99+
; CHECK-SPIRV: CopyMemorySized {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} 2 4
89100
; CHECK-LLVM: call void @llvm.memcpy.p0.p0.i32(ptr align 4 {{%[0-9]+}}, ptr align 4 {{%[0-9]+}}, i32 8, i1 false)
101+
; ALIGN-MATCH-SPIRV: CopyMemorySized {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} 2 4 2 8
102+
; ALIGN-MATCH-LLVM: call void @llvm.memcpy.p0.p0.i32(ptr align 4 {{%[0-9]+}}, ptr align 8 {{%[0-9]+}}, i32 8, i1 false)
90103
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %2, i8* align 8 %3, i32 8, i1 false), !tbaa.struct !4
91104
%4 = bitcast %struct.A* %a to i8*
92105
call void @llvm.lifetime.end.p0i8(i64 16, i8* %4) #2

0 commit comments

Comments
 (0)