Skip to content

Commit 0cec3c6

Browse files
authored
[SYCL] Fix alignment of emulated specialization constants (#6132)
This patch solves #6093, and finishes to fix #5911 It doesn't change anything for native specialization constants, but correctly aligns emulated specialization constants based on type requirements. Emulated specialization constant don't use the CompositeOffset mechanism, so this patch re-uses this field to communicate the necessary padding from the compiler pass in sycl-post-link to the runtime to ensure correct alignment. With this patch the SYCL-CTS specialization constant tests are all passing with the CUDA plugin: % ./bin/test_specialization_constants ======================= All tests passed (56 assertions in 46 test cases) Note this is on top of #6125
1 parent cb94c80 commit 0cec3c6

File tree

3 files changed

+89
-12
lines changed

3 files changed

+89
-12
lines changed

llvm/test/tools/sycl-post-link/spec-constants/SYCL-2020.ll

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ entry:
7272
; CHECK-RT: call half @_Z20__spirv_SpecConstantiDh(i32 [[#SCID0:]], half 0xH4000)
7373

7474
%call.i3 = tail call i32 @_Z37__sycl_getScalar2020SpecConstantValueIiET_PKcPvS3_(i8* getelementptr inbounds ([34 x i8], [34 x i8]* @__builtin_unique_stable_name._Z27get_specialization_constantIL_Z6id_intE17specialization_idIiEiET1_v, i64 0, i64 0), i8* bitcast (%class.specialization_id.0* @id_int to i8*), i8* null)
75-
; CHECK-DEF: %[[GEP1:[0-9a-z]+]] = getelementptr i8, i8* null, i32 2
75+
; CHECK-DEF: %[[GEP1:[0-9a-z]+]] = getelementptr i8, i8* null, i32 4
7676
; CHECK-DEF: %[[BITCAST1:[0-9a-z]+]] = bitcast i8* %[[GEP1]] to i32*
7777
; CHECK-DEF: %[[LOAD1:[0-9a-z]+]] = load i32, i32* %[[BITCAST1]], align 4
7878
;
@@ -96,7 +96,7 @@ entry:
9696
%0 = bitcast %struct.ComposConst* %tmp to i8*
9797
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %0) #3
9898
call void @_Z40__sycl_getComposite2020SpecConstantValueI11ComposConstET_PKcPvS4_(%struct.ComposConst* nonnull sret(%struct.ComposConst) align 8 %tmp, i8* getelementptr inbounds ([37 x i8], [37 x i8]* @__builtin_unique_stable_name._Z27get_specialization_constantIL_Z9id_composE17specialization_idI11ComposConstES1_ET1_v, i64 0, i64 0), i8* bitcast (%class.specialization_id.1* @id_compos to i8*), i8* null)
99-
; CHECK-DEF: %[[GEP:[0-9a-z]+]] = getelementptr i8, i8* null, i32 6
99+
; CHECK-DEF: %[[GEP:[0-9a-z]+]] = getelementptr i8, i8* null, i32 8
100100
; CHECK-DEF: %[[BITCAST:[0-9a-z]+]] = bitcast i8* %[[GEP]] to %struct.ComposConst*
101101
; CHECK-DEF: %[[C1:[0-9a-z]+]] = load %struct.ComposConst, %struct.ComposConst* %[[BITCAST]], align 8
102102
;
@@ -113,7 +113,7 @@ entry:
113113
%1 = getelementptr inbounds %struct.ComposConst2, %struct.ComposConst2* %tmp1, i64 0, i32 0
114114
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %1) #3
115115
call void @_Z40__sycl_getComposite2020SpecConstantValueI12ComposConst2ET_PKcPvS4_(%struct.ComposConst2* nonnull sret(%struct.ComposConst2) align 8 %tmp1, i8* getelementptr inbounds ([39 x i8], [39 x i8]* @__builtin_unique_stable_name._Z27get_specialization_constantIL_Z10id_compos2E17specialization_idI12ComposConst2ES1_ET1_v, i64 0, i64 0), i8* getelementptr inbounds (%class.specialization_id.2, %class.specialization_id.2* @id_compos2, i64 0, i32 0, i32 0), i8* null) call void @llvm.lifetime.end.p0i8(i64 24, i8* nonnull %1) #3
116-
; CHECK-DEF: %[[GEP1:[0-9a-z]+]] = getelementptr i8, i8* null, i32 30
116+
; CHECK-DEF: %[[GEP1:[0-9a-z]+]] = getelementptr i8, i8* null, i32 32
117117
; CHECK-DEF: %[[BITCAST1:[0-9a-z]+]] = bitcast i8* %[[GEP1]] to %struct.ComposConst2*
118118
; CHECK-DEF: %[[C2:[0-9a-z]+]] = load %struct.ComposConst2, %struct.ComposConst2* %[[BITCAST1]], align 8
119119
;
@@ -129,7 +129,7 @@ entry:
129129
%2 = bitcast %struct.ComposConst* %tmp2 to i8*
130130
call void @llvm.lifetime.start.p0i8(i64 24, i8* nonnull %2) #3
131131
call void @_Z40__sycl_getComposite2020SpecConstantValueI11ComposConstET_PKcPvS4_(%struct.ComposConst* nonnull sret(%struct.ComposConst) align 8 %tmp2, i8* getelementptr inbounds ([37 x i8], [37 x i8]* @__builtin_unique_stable_name._Z27get_specialization_constantIL_Z9id_composE17specialization_idI11ComposConstES1_ET1_v, i64 0, i64 0), i8* bitcast (%class.specialization_id.1* @id_compos to i8*), i8* null)
132-
; CHECK-DEF: %[[GEP2:[0-9a-z]+]] = getelementptr i8, i8* null, i32 6
132+
; CHECK-DEF: %[[GEP2:[0-9a-z]+]] = getelementptr i8, i8* null, i32 8
133133
; CHECK-DEF: %[[BITCAST2:[0-9a-z]+]] = bitcast i8* %[[GEP2]] to %struct.ComposConst*
134134
; CHECK-DEF: %[[C3:[0-9a-z]+]] = load %struct.ComposConst, %struct.ComposConst* %[[BITCAST2]], align 8
135135
;
@@ -148,7 +148,7 @@ entry:
148148
define void @test_zeroinit() {
149149
%tmp = alloca %struct.ComposConst3, align 4
150150
%1 = bitcast %struct.ComposConst3* %tmp to i8*
151-
; CHECK-DEF: %[[GEP3:[0-9a-z]+]] = getelementptr i8, i8* null, i32 54
151+
; CHECK-DEF: %[[GEP3:[0-9a-z]+]] = getelementptr i8, i8* null, i32 56
152152
; CHECK-DEF: %[[BITCAST3:[0-9a-z]+]] = bitcast i8* %[[GEP3]] to %struct.ComposConst3*
153153
; CHECK-DEF: %[[C3:[0-9a-z]+]] = load %struct.ComposConst3, %struct.ComposConst3* %[[BITCAST3]], align 4
154154
;
@@ -169,7 +169,7 @@ define void @test3() {
169169
%tmp3 = alloca %struct.MArrayConst3, align 8
170170
%tmp4 = alloca %struct.MArrayConst4, align 8
171171
%1 = bitcast %struct.VectorConst* %tmp to i8*
172-
; CHECK-DEF: %[[GEP1:[0-9a-z]+]] = getelementptr i8, i8* null, i32 70
172+
; CHECK-DEF: %[[GEP1:[0-9a-z]+]] = getelementptr i8, i8* null, i32 72
173173
; CHECK-DEF: %[[BITCAST1:[0-9a-z]+]] = bitcast i8* %[[GEP1]] to %struct.VectorConst*
174174
; CHECK-DEF: %[[C1:[0-9a-z]+]] = load %struct.VectorConst, %struct.VectorConst* %[[BITCAST1]], align 8
175175
;
@@ -179,7 +179,7 @@ define void @test3() {
179179
; CHECK-RT: call %struct.VectorConst @_Z29__spirv_SpecConstantCompositeDv2_i_Rstruct.VectorConst(<2 x i32> %[[#CE1]])
180180
call void @_Z40__sycl_getComposite2020SpecConstantValueI11VectorConstET_PKcPvS4_(%struct.VectorConst* nonnull sret(%struct.VectorConst) align 8 %tmp, i8* getelementptr inbounds ([38 x i8], [38 x i8]* @__builtin_unique_stable_name._Z27get_specialization_constantIL_Z10id_vectorE17specialization_idI11VectorConstES1_ET1_v, i64 0, i64 0), i8* bitcast (%class.specialization_id.3* @id_vector to i8*), i8* null)
181181
%2 = bitcast %struct.MArrayConst* %tmp1 to i8*
182-
; CHECK-DEF: %[[GEP2:[0-9a-z]+]] = getelementptr i8, i8* null, i32 78
182+
; CHECK-DEF: %[[GEP2:[0-9a-z]+]] = getelementptr i8, i8* null, i32 80
183183
; CHECK-DEF: %[[BITCAST2:[0-9a-z]+]] = bitcast i8* %[[GEP2]] to %struct.MArrayConst*
184184
; CHECK-DEF: %[[C2:[0-9a-z]+]] = load %struct.MArrayConst, %struct.MArrayConst* %[[BITCAST2]], align 4
185185
;
@@ -234,11 +234,14 @@ attributes #3 = { nounwind }
234234

235235
; CHECK: !sycl.specialization-constants = !{![[#ID0:]], ![[#ID1:]], ![[#ID2:]], ![[#ID3:]], ![[#ID_COMPOS3:]], ![[#ID4:]], ![[#ID5:]]
236236
;
237-
; CHECK-DEF: !sycl.specialization-constants-default-values = !{![[#ID4:]], ![[#ID5:]], ![[#ID6:]], ![[#ID7:]], ![[#ID_COMPOS3_DEFAULT:]], ![[#ID8:]], ![[#ID9:]]
237+
; CHECK-DEF: !sycl.specialization-constants-default-values = !{![[#ID4:]], ![[#ID5_PAD:]], ![[#ID5:]], ![[#ID6:]], ![[#ID7:]], ![[#ID_COMPOS3_DEFAULT:]], ![[#ID8:]], ![[#ID9:]]
238238
; CHECK-RT: !sycl.specialization-constants-default-values
239239
;
240-
; CHECK: ![[#ID0]] = !{!"_ZTS14name_generatorIL_Z9id_halfEE", i32 0, i32 0, i32 2}
241-
; CHECK: ![[#ID1]] = !{!"_ZTS14name_generatorIL_Z6id_intEE", i32 1, i32 0, i32 4}
240+
; Emulated spec constant may use an extra padding element to ensure alignment
241+
; CHECK-RT: ![[#ID0]] = !{!"_ZTS14name_generatorIL_Z9id_halfEE", i32 0, i32 0, i32 2}
242+
; CHECK-DEF: ![[#ID0]] = !{!"_ZTS14name_generatorIL_Z9id_halfEE", i32 0, i32 0, i32 2, i32 -1, i32 2, i32 2}
243+
;
244+
; CHECK: ![[#ID1]] = !{!"_ZTS14name_generatorIL_Z6id_intEE", i32 1, i32 0, i32 4}
242245
;
243246
; For composite types, the amount of metadata is a bit different between native and emulated spec constants
244247
;
@@ -256,6 +259,7 @@ attributes #3 = { nounwind }
256259
; CHECK-RT-SAME: i32 [[#SCID9]], i32 16, i32 8}
257260
;
258261
; CHECK-DEF: ![[#ID4]] = !{half 0xH4000}
262+
; CHECK-DEF: ![[#ID5_PAD]] = !{[2 x i8] zeroinitializer}
259263
; CHECK-DEF: ![[#ID5]] = !{i32 42}
260264
; CHECK-DEF: ![[#ID6]] = !{%struct.ComposConst { i32 1, double 2.000000e+00, %struct.myConst { i32 13, float 0x4020666660000000 } }}
261265
; CHECK-DEF: ![[#ID7]] = !{%struct.ComposConst2 { i8 1, %struct.myConst { i32 52, float 0x40479999A0000000 }, double 2.000000e+00 }}

llvm/test/tools/sycl-post-link/spec-constants/bool.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
; CHECK-LABEL: void @kernel_B
1515
; CHECK-RT: call i8 @_Z20__spirv_SpecConstantia(i32 [[#]], i8
1616
;
17-
; CHECK-DEF: %[[GEP:gep.*]] = getelementptr i8, i8 addrspace(4)* null, i32 1
17+
; CHECK-DEF: %[[GEP:gep.*]] = getelementptr i8, i8 addrspace(4)* null, i32 4
1818
; CHECK-DEF: %[[BC:bc.*]] = bitcast i8 addrspace(4)* %[[GEP]] to %struct.user_type addrspace(4)*
1919
; CHECK-DEF: %[[LOAD:load.*]] = load %struct.user_type, %struct.user_type addrspace(4)* %[[BC]], align 4
2020

llvm/tools/sycl-post-link/SpecConstants.cpp

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
724724
}
725725

726726
bool IsNewSpecConstant = false;
727+
unsigned Padding = 0;
727728
if (SetValAtRT) {
728729
// 2. Spec constant value will be set at run time - then add the literal
729730
// to a "spec const string literal ID" -> "vector of integer IDs" map,
@@ -772,6 +773,69 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
772773
unsigned CurrentOffset = Ins.first->second;
773774
if (IsNewSpecConstant) {
774775
unsigned Size = M.getDataLayout().getTypeStoreSize(SCTy);
776+
unsigned Align = M.getDataLayout().getABITypeAlignment(SCTy);
777+
778+
// Ensure correct alignment
779+
if (CurrentOffset % Align != 0) {
780+
// Compute necessary padding to correctly align the constant.
781+
Padding = Align - CurrentOffset % Align;
782+
783+
// Update offsets.
784+
NextOffset += Padding;
785+
CurrentOffset += Padding;
786+
OffsetMap[SymID] = NextOffset;
787+
788+
assert(CurrentOffset % Align == 0 &&
789+
"Alignment calculation error");
790+
791+
// The spec constant map can't be empty as the first offset is 0
792+
// and so it can't be misaligned.
793+
assert(!SCMetadata.empty() &&
794+
"Cannot add padding to first spec constant");
795+
796+
// To communicate the padding to the runtime, update the metadata
797+
// node of the previous spec constant to append a padding node. It
798+
// can't be added in front of the current spec constant, as doing
799+
// so would require the spec constant node to have a non-zero
800+
// CompositeOffset which breaks accessing it in the runtime.
801+
auto Prev = SCMetadata.back();
802+
803+
// Emulated spec constants don't use composite so should
804+
// always be formatted as (SymID, ID, Offset, Size), except when
805+
// they include padding, but since padding is added at insertion
806+
// of the next element, the last element of the map can never be
807+
// padded.
808+
assert(Prev.second->getNumOperands() == 4 &&
809+
"Incorrect emulated spec constant format");
810+
811+
LLVMContext &Ctx = M.getContext();
812+
auto *Int32Ty = Type::getInt32Ty(Ctx);
813+
SmallVector<Metadata *, 16> MDOps;
814+
815+
// Copy the existing metadata.
816+
MDOps.push_back(Prev.second->getOperand(0));
817+
MDOps.push_back(Prev.second->getOperand(1));
818+
MDOps.push_back(Prev.second->getOperand(2));
819+
auto &SizeOp = Prev.second->getOperand(3);
820+
MDOps.push_back(SizeOp);
821+
822+
// Extract the size of the previous node to use as CompositeOffset
823+
// for the padding node.
824+
auto PrevSize = mdconst::extract<ConstantInt>(SizeOp)->getValue();
825+
826+
// The max value is a magic value used for padding that the
827+
// runtime knows to skip.
828+
MDOps.push_back(ConstantAsMetadata::get(Constant::getIntegerValue(
829+
Int32Ty, APInt(32, std::numeric_limits<unsigned>::max()))));
830+
MDOps.push_back(ConstantAsMetadata::get(
831+
Constant::getIntegerValue(Int32Ty, PrevSize)));
832+
MDOps.push_back(ConstantAsMetadata::get(
833+
Constant::getIntegerValue(Int32Ty, APInt(32, Padding))));
834+
835+
// Replace previous metadata node with the node including the
836+
// padding.
837+
SCMetadata[Prev.first] = MDNode::get(Ctx, MDOps);
838+
}
775839

776840
SCMetadata[SymID] = generateSpecConstantMetadata(
777841
M, SymID, SCTy, NextID, /* is native spec constant */ false);
@@ -806,9 +870,18 @@ PreservedAnalyses SpecConstantsPass::run(Module &M,
806870
}
807871
}
808872

809-
if (IsNewSpecConstant && DefaultValue)
873+
if (IsNewSpecConstant && DefaultValue) {
874+
if (Padding != 0) {
875+
// Initialize the padding with null data
876+
LLVMContext &Ctx = DefaultValue->getContext();
877+
auto PadTy = ArrayType::get(Type::getInt8Ty(Ctx), Padding);
878+
DefaultsMetadata.push_back(MDNode::get(
879+
Ctx,
880+
ConstantAsMetadata::get(llvm::Constant::getNullValue(PadTy))));
881+
}
810882
DefaultsMetadata.push_back(
811883
generateSpecConstDefaultValueMetadata(SymID, DefaultValue));
884+
}
812885

813886
if (HasSretParameter) {
814887
// If __sycl_getCompositeSpecConstant returns through argument, then the

0 commit comments

Comments
 (0)