Skip to content

Commit b26fd80

Browse files
[SPIR-V] Implement EvaluateAttribute* functions (microsoft#6945)
Emits SPIR-V InterpolateAt* instructions from the GLSL.std.450 extended instruction set for EvaluateAttribute*. Relies on the optimizer's copy propagate passes to ensure that these instructions are passed valid pointers in the Input storage class after legalization. Fixes microsoft#3649
1 parent b48341e commit b26fd80

File tree

7 files changed

+197
-1
lines changed

7 files changed

+197
-1
lines changed

tools/clang/lib/SPIRV/CapabilityVisitor.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,8 @@ bool CapabilityVisitor::visit(SpirvModule *, Visitor::Phase phase) {
895895
Extension::NV_shader_subgroup_partitioned,
896896
{spv::Capability::GroupNonUniformPartitionedNV});
897897

898+
addCapability(spv::Capability::InterpolationFunction);
899+
898900
return true;
899901
}
900902

tools/clang/lib/SPIRV/SpirvEmitter.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9366,6 +9366,12 @@ SpirvEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
93669366
case hlsl::IntrinsicOp::IOP_isfinite:
93679367
retVal = processIntrinsicIsFinite(callExpr);
93689368
break;
9369+
case hlsl::IntrinsicOp::IOP_EvaluateAttributeCentroid:
9370+
case hlsl::IntrinsicOp::IOP_EvaluateAttributeAtSample:
9371+
case hlsl::IntrinsicOp::IOP_EvaluateAttributeSnapped: {
9372+
retVal = processEvaluateAttributeAt(callExpr, hlslOpcode, srcLoc, srcRange);
9373+
break;
9374+
}
93699375
INTRINSIC_SPIRV_OP_CASE(ddx, DPdx, true);
93709376
INTRINSIC_SPIRV_OP_CASE(ddx_coarse, DPdxCoarse, false);
93719377
INTRINSIC_SPIRV_OP_CASE(ddx_fine, DPdxFine, false);
@@ -11939,6 +11945,44 @@ SpirvInstruction *SpirvEmitter::processIntrinsicUsingGLSLInst(
1193911945
return nullptr;
1194011946
}
1194111947

11948+
SpirvInstruction *SpirvEmitter::processEvaluateAttributeAt(
11949+
const CallExpr *callExpr, hlsl::IntrinsicOp opcode, SourceLocation loc,
11950+
SourceRange range) {
11951+
QualType returnType = callExpr->getType();
11952+
SpirvInstruction *arg0Instr = doExpr(callExpr->getArg(0));
11953+
SpirvInstruction *interpolant =
11954+
turnIntoLValue(callExpr->getType(), arg0Instr, callExpr->getExprLoc());
11955+
11956+
switch (opcode) {
11957+
case hlsl::IntrinsicOp::IOP_EvaluateAttributeCentroid:
11958+
return spvBuilder.createGLSLExtInst(
11959+
returnType, GLSLstd450InterpolateAtCentroid, {interpolant}, loc, range);
11960+
case hlsl::IntrinsicOp::IOP_EvaluateAttributeAtSample: {
11961+
SpirvInstruction *sample = doExpr(callExpr->getArg(1));
11962+
return spvBuilder.createGLSLExtInst(returnType,
11963+
GLSLstd450InterpolateAtSample,
11964+
{interpolant, sample}, loc, range);
11965+
}
11966+
case hlsl::IntrinsicOp::IOP_EvaluateAttributeSnapped: {
11967+
const Expr *arg1 = callExpr->getArg(1);
11968+
SpirvInstruction *arg1Inst = doExpr(arg1);
11969+
11970+
QualType float2Type = astContext.getExtVectorType(astContext.FloatTy, 2);
11971+
SpirvInstruction *offset =
11972+
castToFloat(arg1Inst, arg1->getType(), float2Type, arg1->getLocStart(),
11973+
arg1->getSourceRange());
11974+
11975+
return spvBuilder.createGLSLExtInst(returnType,
11976+
GLSLstd450InterpolateAtOffset,
11977+
{interpolant, offset}, loc, range);
11978+
}
11979+
default:
11980+
assert(false && "processEvaluateAttributeAt must be called with an "
11981+
"EvaluateAttribute* opcode");
11982+
return nullptr;
11983+
}
11984+
}
11985+
1194211986
SpirvInstruction *
1194311987
SpirvEmitter::processIntrinsicLog10(const CallExpr *callExpr) {
1194411988
// Since there is no log10 instruction in SPIR-V, we can use:

tools/clang/lib/SPIRV/SpirvEmitter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,12 @@ class SpirvEmitter : public ASTConsumer {
622622
SpirvInstruction *processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
623623
hlsl::IntrinsicOp opcode);
624624

625+
/// Processes EvaluateAttributeAt* intrinsic calls.
626+
SpirvInstruction *processEvaluateAttributeAt(const CallExpr *expr,
627+
hlsl::IntrinsicOp opcode,
628+
SourceLocation loc,
629+
SourceRange range);
630+
625631
/// Processes Interlocked* intrinsic functions.
626632
SpirvInstruction *processIntrinsicInterlockedMethod(const CallExpr *,
627633
hlsl::IntrinsicOp);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv -Vd | FileCheck %s
2+
3+
RWStructuredBuffer<float4> a;
4+
5+
[[vk::ext_builtin_input(/* PointCoord */ 16)]]
6+
static const float2 gl_PointCoord;
7+
8+
// CHECK: [[instSet:%[0-9]+]] = OpExtInstImport "GLSL.std.450"
9+
10+
void setValue(float4 input);
11+
12+
// CHECK: %src_main = OpFunction
13+
void main(float4 color : COLOR, float instance : SV_InstanceID) {
14+
// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %color
15+
// CHECK: OpStore %temp_var_v4float [[val]]
16+
// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtSample %temp_var_v4float %uint_0
17+
a[0] = EvaluateAttributeAtSample(color, 0);
18+
19+
setValue(color);
20+
21+
// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %c2
22+
// CHECK: OpStore %temp_var_v4float_0 [[val]]
23+
// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtSample %temp_var_v4float_0 %uint_2
24+
float4 c2 = color;
25+
a[2] = EvaluateAttributeAtSample(c2, 2);
26+
27+
// CHECK: [[val:%[0-9]+]] = OpLoad %float %instance
28+
// CHECK: OpStore %temp_var_float [[val]]
29+
// CHECK: OpExtInst %float [[instSet]] InterpolateAtSample %temp_var_float %uint_3
30+
a[3] = EvaluateAttributeAtSample(instance, 3);
31+
32+
// CHECK: [[val:%[0-9]+]] = OpLoad %v2float %gl_PointCoord
33+
// CHECK: OpStore %temp_var_v2float [[val]]
34+
// CHECK: OpExtInst %v2float [[instSet]] InterpolateAtSample %temp_var_v2float %uint_4
35+
a[4] = float4(EvaluateAttributeAtSample(gl_PointCoord, 4), 0, 0);
36+
}
37+
38+
// CHECK: %setValue = OpFunction
39+
void setValue(float4 input) {
40+
// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %input
41+
// CHECK: OpStore %temp_var_v4float_1 [[val]]
42+
// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtSample %temp_var_v4float_1 %uint_1
43+
a[1] = EvaluateAttributeAtSample(input, 1);
44+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv -Vd | FileCheck %s
2+
3+
RWStructuredBuffer<float4> a;
4+
5+
[[vk::ext_builtin_input(/* PointCoord */ 16)]]
6+
static const float2 gl_PointCoord;
7+
8+
// CHECK: [[instSet:%[0-9]+]] = OpExtInstImport "GLSL.std.450"
9+
10+
void setValue(float4 input);
11+
12+
// CHECK: %src_main = OpFunction
13+
void main(float4 color : COLOR, float instance : SV_InstanceID) {
14+
// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %color
15+
// CHECK: OpStore %temp_var_v4float [[val]]
16+
// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtCentroid %temp_var_v4float
17+
a[0] = EvaluateAttributeCentroid(color);
18+
19+
setValue(color);
20+
21+
// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %c2
22+
// CHECK: OpStore %temp_var_v4float_0 [[val]]
23+
// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtCentroid %temp_var_v4float_0
24+
float4 c2 = color;
25+
a[2] = EvaluateAttributeCentroid(c2);
26+
27+
// CHECK: [[val:%[0-9]+]] = OpLoad %float %instance
28+
// CHECK: OpStore %temp_var_float [[val]]
29+
// CHECK: OpExtInst %float [[instSet]] InterpolateAtCentroid %temp_var_float
30+
a[3] = EvaluateAttributeCentroid(instance);
31+
32+
// CHECK: [[val:%[0-9]+]] = OpLoad %v2float %gl_PointCoord
33+
// CHECK: OpStore %temp_var_v2float [[val]]
34+
// CHECK: OpExtInst %v2float [[instSet]] InterpolateAtCentroid %temp_var_v2float
35+
a[4] = float4(EvaluateAttributeCentroid(gl_PointCoord), 0, 0);
36+
}
37+
38+
39+
// CHECK: %setValue = OpFunction
40+
void setValue(float4 input) {
41+
// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %input
42+
// CHECK: OpStore %temp_var_v4float_1 [[val]]
43+
// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtCentroid %temp_var_v4float_1
44+
a[1] = EvaluateAttributeCentroid(input);
45+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %dxc -T ps_6_0 -E main -fcgl %s -spirv -Vd | FileCheck %s
2+
3+
RWStructuredBuffer<float4> a;
4+
5+
[[vk::ext_builtin_input(/* PointCoord */ 16)]]
6+
static const float2 gl_PointCoord;
7+
8+
// CHECK: [[instSet:%[0-9]+]] = OpExtInstImport "GLSL.std.450"
9+
10+
// CHECK: [[v2int_0_0:%[0-9]+]] = OpConstantComposite %v2int %int_0 %int_0
11+
// CHECK: [[v2int_2_2:%[0-9]+]] = OpConstantComposite %v2int %int_2 %int_2
12+
// CHECK: [[v2int_3_3:%[0-9]+]] = OpConstantComposite %v2int %int_3 %int_3
13+
// CHECK: [[v2int_4_4:%[0-9]+]] = OpConstantComposite %v2int %int_4 %int_4
14+
// CHECK: [[v2int_1_1:%[0-9]+]] = OpConstantComposite %v2int %int_1 %int_1
15+
16+
void setValue(float4 input);
17+
18+
// CHECK: %src_main = OpFunction
19+
void main(float4 color : COLOR, float instance : SV_InstanceID) {
20+
// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %color
21+
// CHECK: OpStore %temp_var_v4float [[val]]
22+
// CHECK: [[offset:%[0-9]+]] = OpConvertSToF %v2float [[v2int_0_0]]
23+
// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtOffset %temp_var_v4float [[offset]]
24+
a[0] = EvaluateAttributeSnapped(color, int2(0,0));
25+
26+
setValue(color);
27+
28+
// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %c2
29+
// CHECK: OpStore %temp_var_v4float_0 [[val]]
30+
// CHECK: [[offset:%[0-9]+]] = OpConvertSToF %v2float [[v2int_2_2]]
31+
// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtOffset %temp_var_v4float_0 [[offset]]
32+
float4 c2 = color;
33+
a[2] = EvaluateAttributeSnapped(c2, int2(2,2));
34+
35+
// CHECK: [[val:%[0-9]+]] = OpLoad %float %instance
36+
// CHECK: OpStore %temp_var_float [[val]]
37+
// CHECK: [[offset:%[0-9]+]] = OpConvertSToF %v2float [[v2int_3_3]]
38+
// CHECK: OpExtInst %float [[instSet]] InterpolateAtOffset %temp_var_float [[offset]]
39+
a[3] = EvaluateAttributeSnapped(instance, int2(3,3));
40+
41+
// CHECK: [[val:%[0-9]+]] = OpLoad %v2float %gl_PointCoord
42+
// CHECK: OpStore %temp_var_v2float [[val]]
43+
// CHECK: [[offset:%[0-9]+]] = OpConvertSToF %v2float [[v2int_4_4]]
44+
// CHECK: OpExtInst %v2float [[instSet]] InterpolateAtOffset %temp_var_v2float [[offset]]
45+
a[4] = float4(EvaluateAttributeSnapped(gl_PointCoord, int2(4, 4)), 0, 0);
46+
}
47+
48+
// CHECK: %setValue = OpFunction
49+
void setValue(float4 input) {
50+
// CHECK: [[val:%[0-9]+]] = OpLoad %v4float %input
51+
// CHECK: OpStore %temp_var_v4float_1 [[val]]
52+
// CHECK: [[offset:%[0-9]+]] = OpConvertSToF %v2float [[v2int_1_1]]
53+
// CHECK: OpExtInst %v4float [[instSet]] InterpolateAtOffset %temp_var_v4float_1 [[offset]]
54+
a[1] = EvaluateAttributeSnapped(input, int2(1,1));
55+
}

0 commit comments

Comments
 (0)