[clang] [llvm] [HLSL][SPIR-V] Add support for HLSL semantics (PR #149363)
Nathan Gauër via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 6 07:00:20 PDT 2025
https://github.com/Keenuts updated https://github.com/llvm/llvm-project/pull/149363
>From 4479503ecb540bb6ef9656db250db97e21c030e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Mon, 4 Aug 2025 16:58:14 +0200
Subject: [PATCH 1/2] [SPIR-V] Fix OpVectorShuffle undef emission
When an undef/poison value is lowered as a an immediate, it
becomes -1. When reaching the backend, the -1 was printed
as operand to OpVectorShuffle instead of the proper 0xFFFFFFFF.
>From the SPIR-V spec:
A Component literal may also be FFFFFFFF, which means the
corresponding result component has no source and is undefined.
Fixes #151691
---
.../Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp | 14 +++++++++++---
.../llvm-intrinsics/llvm-vector-reduce/add.ll | 8 ++++----
.../llvm-intrinsics/llvm-vector-reduce/and.ll | 8 ++++----
.../llvm-intrinsics/llvm-vector-reduce/mul.ll | 8 ++++----
.../SPIRV/llvm-intrinsics/llvm-vector-reduce/or.ll | 8 ++++----
.../llvm-intrinsics/llvm-vector-reduce/smax.ll | 8 ++++----
.../llvm-intrinsics/llvm-vector-reduce/smin.ll | 8 ++++----
.../llvm-intrinsics/llvm-vector-reduce/umax.ll | 8 ++++----
.../llvm-intrinsics/llvm-vector-reduce/umin.ll | 8 ++++----
.../llvm-intrinsics/llvm-vector-reduce/xor.ll | 8 ++++----
10 files changed, 47 insertions(+), 39 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index a7f6fbceffc3f..d78be27b9ae70 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -374,9 +374,17 @@ void SPIRVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isReg())
O << '%' << (getIDFromRegister(Op.getReg().id()) + 1);
- else if (Op.isImm())
- O << formatImm((int64_t)Op.getImm());
- else if (Op.isDFPImm())
+ else if (Op.isImm()) {
+ int64_t Imm = (int64_t)Op.getImm();
+ // For OpVectorShuffle:
+ // A Component literal may also be FFFFFFFF, which means the corresponding
+ // result component has no source and is undefined.
+ // LLVM representation of poison/undef becomes -1 when lowered to MI.
+ if (MI->getOpcode() == SPIRV::OpVectorShuffle && Imm == -1)
+ O << "0xFFFFFFFF";
+ else
+ O << formatImm(Imm);
+ } else if (Op.isDFPImm())
O << formatImm((double)Op.getDFPImm());
else if (Op.isExpr())
MAI.printExpr(O, *Op.getExpr());
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/add.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/add.ll
index ef9719e64586d..39cbd8726400a 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/add.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/add.ll
@@ -21,7 +21,7 @@
; CHECK-DAG: %[[LongVec3:.*]] = OpTypeVector %[[Long]] 3
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpIAdd %[[CharVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2CharR:.*]] = OpCompositeExtract %[[Char]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2CharR]]
@@ -38,7 +38,7 @@
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpIAdd %[[ShortVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2ShortR:.*]] = OpCompositeExtract %[[Short]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2ShortR]]
@@ -55,7 +55,7 @@
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpIAdd %[[IntVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2IntR:.*]] = OpCompositeExtract %[[Int]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2IntR]]
@@ -72,7 +72,7 @@
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpIAdd %[[LongVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2LongR:.*]] = OpCompositeExtract %[[Long]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2LongR]]
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/and.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/and.ll
index e9d9adba8f365..a911cdf094045 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/and.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/and.ll
@@ -21,7 +21,7 @@
; CHECK-DAG: %[[LongVec3:.*]] = OpTypeVector %[[Long]] 3
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseAnd %[[CharVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2CharR:.*]] = OpCompositeExtract %[[Char]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2CharR]]
@@ -38,7 +38,7 @@
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseAnd %[[ShortVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2ShortR:.*]] = OpCompositeExtract %[[Short]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2ShortR]]
@@ -55,7 +55,7 @@
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseAnd %[[IntVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2IntR:.*]] = OpCompositeExtract %[[Int]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2IntR]]
@@ -72,7 +72,7 @@
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseAnd %[[LongVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2LongR:.*]] = OpCompositeExtract %[[Long]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2LongR]]
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/mul.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/mul.ll
index 16455f2e21cb6..86e6d42de55d1 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/mul.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/mul.ll
@@ -20,7 +20,7 @@ target triple = "spir64-unknown-unknown"
; CHECK-DAG: %[[LongVec3:.*]] = OpTypeVector %[[Long]] 3
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpIMul %[[CharVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2CharR:.*]] = OpCompositeExtract %[[Char]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2CharR]]
@@ -37,7 +37,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpIMul %[[ShortVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2ShortR:.*]] = OpCompositeExtract %[[Short]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2ShortR]]
@@ -54,7 +54,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpIMul %[[IntVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2IntR:.*]] = OpCompositeExtract %[[Int]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2IntR]]
@@ -71,7 +71,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpIMul %[[LongVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2LongR:.*]] = OpCompositeExtract %[[Long]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2LongR]]
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/or.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/or.ll
index badfebc27072f..34e5272ecd629 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/or.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/or.ll
@@ -20,7 +20,7 @@ target triple = "spir64-unknown-unknown"
; CHECK-DAG: %[[LongVec3:.*]] = OpTypeVector %[[Long]] 3
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseOr %[[CharVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2CharR:.*]] = OpCompositeExtract %[[Char]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2CharR]]
@@ -37,7 +37,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseOr %[[ShortVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2ShortR:.*]] = OpCompositeExtract %[[Short]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2ShortR]]
@@ -54,7 +54,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseOr %[[IntVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2IntR:.*]] = OpCompositeExtract %[[Int]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2IntR]]
@@ -71,7 +71,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseOr %[[LongVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2LongR:.*]] = OpCompositeExtract %[[Long]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2LongR]]
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/smax.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/smax.ll
index 54afb3a25b4d6..eafd4e096a728 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/smax.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/smax.ll
@@ -20,7 +20,7 @@ target triple = "spir64-unknown-unknown"
; CHECK-DAG: %[[LongVec3:.*]] = OpTypeVector %[[Long]] 3
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[CharVec2]] %[[#]] s_max %[[#]] %[[#]]
; CHECK: %[[Vec2CharR:.*]] = OpCompositeExtract %[[Char]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2CharR]]
@@ -37,7 +37,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[ShortVec2]] %[[#]] s_max %[[#]] %[[#]]
; CHECK: %[[Vec2ShortR:.*]] = OpCompositeExtract %[[Short]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2ShortR]]
@@ -54,7 +54,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[IntVec2]] %[[#]] s_max %[[#]] %[[#]]
; CHECK: %[[Vec2IntR:.*]] = OpCompositeExtract %[[Int]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2IntR]]
@@ -71,7 +71,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[LongVec2]] %[[#]] s_max %[[#]] %[[#]]
; CHECK: %[[Vec2LongR:.*]] = OpCompositeExtract %[[Long]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2LongR]]
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/smin.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/smin.ll
index a95c2ea0bbbf6..bbd22d4c6d4c5 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/smin.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/smin.ll
@@ -20,7 +20,7 @@ target triple = "spir64-unknown-unknown"
; CHECK-DAG: %[[LongVec3:.*]] = OpTypeVector %[[Long]] 3
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[CharVec2]] %[[#]] s_min %[[#]] %[[#]]
; CHECK: %[[Vec2CharR:.*]] = OpCompositeExtract %[[Char]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2CharR]]
@@ -37,7 +37,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[ShortVec2]] %[[#]] s_min %[[#]] %[[#]]
; CHECK: %[[Vec2ShortR:.*]] = OpCompositeExtract %[[Short]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2ShortR]]
@@ -54,7 +54,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[IntVec2]] %[[#]] s_min %[[#]] %[[#]]
; CHECK: %[[Vec2IntR:.*]] = OpCompositeExtract %[[Int]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2IntR]]
@@ -71,7 +71,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[LongVec2]] %[[#]] s_min %[[#]] %[[#]]
; CHECK: %[[Vec2LongR:.*]] = OpCompositeExtract %[[Long]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2LongR]]
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/umax.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/umax.ll
index a742009cef011..80be288d0b941 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/umax.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/umax.ll
@@ -20,7 +20,7 @@ target triple = "spir64-unknown-unknown"
; CHECK-DAG: %[[LongVec3:.*]] = OpTypeVector %[[Long]] 3
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[CharVec2]] %[[#]] u_max %[[#]] %[[#]]
; CHECK: %[[Vec2CharR:.*]] = OpCompositeExtract %[[Char]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2CharR]]
@@ -37,7 +37,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[ShortVec2]] %[[#]] u_max %[[#]] %[[#]]
; CHECK: %[[Vec2ShortR:.*]] = OpCompositeExtract %[[Short]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2ShortR]]
@@ -54,7 +54,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[IntVec2]] %[[#]] u_max %[[#]] %[[#]]
; CHECK: %[[Vec2IntR:.*]] = OpCompositeExtract %[[Int]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2IntR]]
@@ -71,7 +71,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[LongVec2]] %[[#]] u_max %[[#]] %[[#]]
; CHECK: %[[Vec2LongR:.*]] = OpCompositeExtract %[[Long]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2LongR]]
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/umin.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/umin.ll
index 7844c205c7ab0..2c4832c877783 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/umin.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/umin.ll
@@ -20,7 +20,7 @@ target triple = "spir64-unknown-unknown"
; CHECK-DAG: %[[LongVec3:.*]] = OpTypeVector %[[Long]] 3
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[CharVec2]] %[[#]] u_min %[[#]] %[[#]]
; CHECK: %[[Vec2CharR:.*]] = OpCompositeExtract %[[Char]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2CharR]]
@@ -37,7 +37,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[ShortVec2]] %[[#]] u_min %[[#]] %[[#]]
; CHECK: %[[Vec2ShortR:.*]] = OpCompositeExtract %[[Short]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2ShortR]]
@@ -54,7 +54,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[IntVec2]] %[[#]] u_min %[[#]] %[[#]]
; CHECK: %[[Vec2IntR:.*]] = OpCompositeExtract %[[Int]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2IntR]]
@@ -71,7 +71,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpExtInst %[[LongVec2]] %[[#]] u_min %[[#]] %[[#]]
; CHECK: %[[Vec2LongR:.*]] = OpCompositeExtract %[[Long]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2LongR]]
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/xor.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/xor.ll
index 22f45a2c0bd6c..2532154cfc15c 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/xor.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/xor.ll
@@ -20,7 +20,7 @@ target triple = "spir64-unknown-unknown"
; CHECK-DAG: %[[LongVec3:.*]] = OpTypeVector %[[Long]] 3
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[CharVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseXor %[[CharVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2CharR:.*]] = OpCompositeExtract %[[Char]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2CharR]]
@@ -37,7 +37,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[ShortVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseXor %[[ShortVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2ShortR:.*]] = OpCompositeExtract %[[Short]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2ShortR]]
@@ -54,7 +54,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[IntVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseXor %[[IntVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2IntR:.*]] = OpCompositeExtract %[[Int]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2IntR]]
@@ -71,7 +71,7 @@ target triple = "spir64-unknown-unknown"
; CHECK: OpFunctionEnd
; CHECK: OpFunction
-; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 -1
+; CHECK: %[[Shuffle1:.*]] = OpVectorShuffle %[[LongVec2]] %[[#]] %[[#]] 1 0xFFFFFFFF
; CHECK: %[[Added1:.*]] = OpBitwiseXor %[[LongVec2]] %[[#]] %[[#]]
; CHECK: %[[Vec2LongR:.*]] = OpCompositeExtract %[[Long]] %[[Added1]] 0
; CHECK: OpReturnValue %[[Vec2LongR]]
>From 3072d771104755b8dc41a62b3f13a58ce754476c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Mon, 2 Jun 2025 14:33:23 +0200
Subject: [PATCH 2/2] [HLSL][SPIR-V] Add support for HLSL semantics
---
clang/include/clang/AST/Attr.h | 35 ++
clang/include/clang/Basic/Attr.td | 84 +--
clang/include/clang/Basic/AttrDocs.td | 36 +-
.../clang/Basic/DiagnosticFrontendKinds.td | 11 +
.../clang/Basic/DiagnosticParseKinds.td | 5 +-
.../clang/Basic/DiagnosticSemaKinds.td | 4 +
clang/include/clang/Parse/Parser.h | 8 +
clang/include/clang/Sema/SemaHLSL.h | 23 +-
clang/lib/Basic/Attributes.cpp | 7 +-
clang/lib/CodeGen/CGHLSLRuntime.cpp | 484 +++++++++++++++++-
clang/lib/CodeGen/CGHLSLRuntime.h | 81 ++-
clang/lib/Parse/ParseHLSL.cpp | 79 ++-
clang/lib/Sema/ParsedAttr.cpp | 1 +
clang/lib/Sema/SemaDeclAttr.cpp | 34 +-
clang/lib/Sema/SemaHLSL.cpp | 140 +++--
.../CodeGenHLSL/semantics/SV_Position.ps.hlsl | 10 +-
.../semantics/semantic.arbitrary.hlsl | 35 ++
.../semantics/semantic.array-output.hlsl | 35 ++
.../CodeGenHLSL/semantics/semantic.array.hlsl | 35 ++
.../semantic.explicit-mix-builtin-vs.hlsl | 16 +
.../semantic.explicit-mix-builtin.hlsl | 33 ++
.../semantic.explicit-mix-location-2.hlsl | 15 +
.../semantic.explicit-mix-location.hlsl | 15 +
.../semantics/semantic.struct.hlsl | 79 +++
clang/test/CodeGenHLSL/sret_output.hlsl | 27 +-
...a-attribute-supported-attributes-list.test | 1 +
clang/test/ParserHLSL/semantic_parsing.hlsl | 2 +-
clang/test/SemaHLSL/Semantics/groupindex.hlsl | 12 +-
.../Semantics/invalid_entry_parameter.hlsl | 32 +-
.../SemaHLSL/Semantics/position.ps.size.hlsl | 4 +-
.../test/SemaHLSL/Semantics/position.vs.hlsl | 2 +-
.../SemaHLSL/Semantics/semantics-invalid.hlsl | 17 +
.../SemaHLSL/Semantics/semantics-valid.hlsl | 42 ++
clang/utils/TableGen/ClangAttrEmitter.cpp | 9 +-
llvm/include/llvm/IR/IntrinsicsDirectX.td | 11 +
35 files changed, 1281 insertions(+), 183 deletions(-)
create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.array-output.hlsl
create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-builtin-vs.hlsl
create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-builtin.hlsl
create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-location-2.hlsl
create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-location.hlsl
create mode 100644 clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl
create mode 100644 clang/test/SemaHLSL/Semantics/semantics-invalid.hlsl
create mode 100644 clang/test/SemaHLSL/Semantics/semantics-valid.hlsl
diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index 994f236337b99..c313b5406f387 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -232,6 +232,41 @@ class HLSLAnnotationAttr : public InheritableAttr {
}
};
+class HLSLSemanticAttr : public HLSLAnnotationAttr {
+ unsigned SemanticIndex : 30;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned SemanticIndexable : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned SemanticExplicitIndex : 1;
+
+protected:
+ HLSLSemanticAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
+ attr::Kind AK, bool IsLateParsed,
+ bool InheritEvenIfAlreadyPresent, bool SemanticIndexable)
+ : HLSLAnnotationAttr(Context, CommonInfo, AK, IsLateParsed,
+ InheritEvenIfAlreadyPresent) {
+ this->SemanticIndexable = SemanticIndexable;
+ this->SemanticIndex = 0;
+ this->SemanticExplicitIndex = 0;
+ }
+
+public:
+ bool isSemanticIndexable() const { return SemanticIndexable; }
+
+ void setSemanticIndex(unsigned SemanticIndex) {
+ this->SemanticIndex = SemanticIndex;
+ this->SemanticExplicitIndex = true;
+ }
+
+ unsigned getSemanticIndex() const { return SemanticIndex; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ return A->getKind() >= attr::FirstHLSLSemanticAttr &&
+ A->getKind() <= attr::LastHLSLSemanticAttr;
+ }
+};
+
/// A parameter attribute which changes the argument-passing ABI rule
/// for the parameter.
class ParameterABIAttr : public InheritableParamAttr {
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index b3ff45b3e90a3..e739e86a7bb44 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -396,7 +396,7 @@ class ClangGCC<string name, bit allowInC = 1, int version = 1>
}
// HLSL Annotation spellings
-class HLSLAnnotation<string name> : Spelling<name, "HLSLAnnotation">;
+class HLSLAnnotation<string name> : Spelling<name, "HLSLAnnotation"> {}
class Accessor<string name, list<Spelling> spellings> {
string Name = name;
@@ -779,6 +779,16 @@ class DeclOrStmtAttr : InheritableAttr;
/// An attribute class for HLSL Annotations.
class HLSLAnnotationAttr : InheritableAttr;
+class HLSLSemanticAttr<bit Indexable> : HLSLAnnotationAttr {
+ bit SemanticIndexable = Indexable;
+ int SemanticIndex = 0;
+ bit SemanticExplicitIndex = 0;
+
+ let Spellings = [];
+ let Subjects = SubjectList<[ParmVar, Field, Function]>;
+ let LangOpts = [HLSL];
+}
+
/// A target-specific attribute. This class is meant to be used as a mixin
/// with InheritableAttr or Attr depending on the attribute's needs.
class TargetSpecificAttr<TargetSpec target> {
@@ -4873,27 +4883,6 @@ def HLSLNumThreads: InheritableAttr {
let Documentation = [NumThreadsDocs];
}
-def HLSLSV_GroupThreadID: HLSLAnnotationAttr {
- let Spellings = [HLSLAnnotation<"sv_groupthreadid">];
- let Subjects = SubjectList<[ParmVar, Field]>;
- let LangOpts = [HLSL];
- let Documentation = [HLSLSV_GroupThreadIDDocs];
-}
-
-def HLSLSV_GroupID: HLSLAnnotationAttr {
- let Spellings = [HLSLAnnotation<"sv_groupid">];
- let Subjects = SubjectList<[ParmVar, Field]>;
- let LangOpts = [HLSL];
- let Documentation = [HLSLSV_GroupIDDocs];
-}
-
-def HLSLSV_GroupIndex: HLSLAnnotationAttr {
- let Spellings = [HLSLAnnotation<"sv_groupindex">];
- let Subjects = SubjectList<[ParmVar, GlobalVar]>;
- let LangOpts = [HLSL];
- let Documentation = [HLSLSV_GroupIndexDocs];
-}
-
def HLSLResourceBinding: InheritableAttr {
let Spellings = [HLSLAnnotation<"register">];
let Subjects = SubjectList<[HLSLBufferObj, ExternalGlobalVar], ErrorDiag>;
@@ -4943,13 +4932,43 @@ def HLSLResourceBinding: InheritableAttr {
}];
}
-def HLSLSV_Position : HLSLAnnotationAttr {
- let Spellings = [HLSLAnnotation<"sv_position">];
- let Subjects = SubjectList<[ParmVar, Field]>;
+def HLSLUnparsedSemantic : HLSLAnnotationAttr {
+ let Spellings = [];
+ let Args = [DefaultIntArgument<"Index", 0>,
+ DefaultBoolArgument<"ExplicitIndex", 0>];
+ let Subjects = SubjectList<[ParmVar, Field, Function]>;
let LangOpts = [HLSL];
+ let Documentation = [InternalOnly];
+}
+
+def HLSLUserSemantic : HLSLSemanticAttr</* Indexable= */ 1> {
+ let Documentation = [InternalOnly];
+}
+
+def HLSLSV_Target : HLSLSemanticAttr</* Indexable= */ 1> {
+ let Documentation = [HLSLSV_TargetDocs];
+}
+
+def HLSLSV_Position : HLSLSemanticAttr</* Indexable= */ 1> {
let Documentation = [HLSLSV_PositionDocs];
}
+def HLSLSV_GroupThreadID : HLSLSemanticAttr</* Indexable= */ 0> {
+ let Documentation = [HLSLSV_GroupThreadIDDocs];
+}
+
+def HLSLSV_GroupID : HLSLSemanticAttr</* Indexable= */ 0> {
+ let Documentation = [HLSLSV_GroupIDDocs];
+}
+
+def HLSLSV_GroupIndex : HLSLSemanticAttr</* Indexable= */ 0> {
+ let Documentation = [HLSLSV_GroupIndexDocs];
+}
+
+def HLSLSV_DispatchThreadID : HLSLSemanticAttr</* Indexable= */ 0> {
+ let Documentation = [HLSLSV_DispatchThreadIDDocs];
+}
+
def HLSLPackOffset: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"packoffset">];
let LangOpts = [HLSL];
@@ -4962,13 +4981,6 @@ def HLSLPackOffset: HLSLAnnotationAttr {
}];
}
-def HLSLSV_DispatchThreadID: HLSLAnnotationAttr {
- let Spellings = [HLSLAnnotation<"sv_dispatchthreadid">];
- let Subjects = SubjectList<[ParmVar, Field]>;
- let LangOpts = [HLSL];
- let Documentation = [HLSLSV_DispatchThreadIDDocs];
-}
-
def HLSLShader : InheritableAttr {
let Spellings = [Microsoft<"shader">];
let Subjects = SubjectList<[HLSLEntry]>;
@@ -5072,6 +5084,14 @@ def HLSLVkConstantId : InheritableAttr {
let Documentation = [VkConstantIdDocs];
}
+def HLSLVkLocation : HLSLAnnotationAttr {
+ let Spellings = [CXX11<"vk", "location">];
+ let Args = [IntArgument<"Location">];
+ let Subjects = SubjectList<[ParmVar, Field, Function], ErrorDiag>;
+ let LangOpts = [HLSL];
+ let Documentation = [HLSLVkLocationDocs];
+}
+
def RandomizeLayout : InheritableAttr {
let Spellings = [GCC<"randomize_layout">];
let Subjects = SubjectList<[Record]>;
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 76747d2b11811..122c9b9b2d7bf 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -8462,6 +8462,16 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo
}];
}
+def HLSLSV_PositionDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{TODO}];
+}
+
+def HLSLSV_TargetDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{TODO}];
+}
+
def HLSLSV_GroupIDDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -8544,20 +8554,6 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo
}];
}
-def HLSLSV_PositionDocs : Documentation {
- let Category = DocCatFunction;
- let Content = [{
-The ``SV_Position`` semantic, when applied to an input parameter in a pixel
-shader, contains the location of the pixel center (x, y) in screen space.
-This semantic can be applied to the parameter, or a field in a struct used
-as an input parameter.
-This attribute is supported as an input in pixel, hull, domain and mesh shaders.
-This attribute is supported as an output in vertex, geometry and domain shaders.
-
-The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics
- }];
-}
-
def HLSLGroupSharedAddressSpaceDocs : Documentation {
let Category = DocCatVariable;
let Content = [{
@@ -8617,6 +8613,18 @@ https://github.com/microsoft/hlsl-specs/blob/main/proposals/0011-inline-spirv.md
}];
}
+def HLSLVkLocationDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+Attribute used for specifying the location number for the stage input/output
+variables. Allowed on function parameters, function returns, and struct
+fields. This parameter has no effect when used outside of an entrypoint
+parameter/parameter field/return value.
+
+This attribute maps to the 'Location' SPIR-V decoration.
+ }];
+}
+
def AnnotateTypeDocs : Documentation {
let Category = DocCatType;
let Heading = "annotate_type";
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 8a8db27490f06..a170dc43bacd0 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -393,6 +393,17 @@ def warn_hlsl_langstd_minimal :
"recommend using %1 instead">,
InGroup<HLSLDXCCompat>;
+def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">;
+
+def err_hlsl_semantic_indexing_not_supported
+ : Error<"semantic %0 does not allow indexing">;
+
+def err_hlsl_semantic_missing : Error<"semantic annotations must be present "
+ "for all input and outputs of an entry "
+ "function or patch constant function">;
+
+def note_hlsl_semantic_used_here : Note<"%0 used here">;
+
// ClangIR frontend errors
def err_cir_to_cir_transform_failed : Error<
"CIR-to-CIR transformation failed">, DefaultFatal;
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 165f01514e2b1..e8999d4bd7858 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1851,9 +1851,8 @@ def note_max_tokens_total_override : Note<"total token limit set here">;
def err_expected_semantic_identifier : Error<
"expected HLSL Semantic identifier">;
-def err_invalid_declaration_in_hlsl_buffer : Error<
- "invalid declaration inside %select{tbuffer|cbuffer}0">;
-def err_unknown_hlsl_semantic : Error<"unknown HLSL semantic %0">;
+def err_invalid_declaration_in_hlsl_buffer
+ : Error<"invalid declaration inside %select{tbuffer|cbuffer}0">;
def err_hlsl_separate_attr_arg_and_number : Error<"wrong argument format for hlsl attribute, use %0 instead">;
def ext_hlsl_access_specifiers : ExtWarn<
"access specifiers are a clang HLSL extension">,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 94b174c758a5c..f8cd4d8622194 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13058,6 +13058,9 @@ def err_hlsl_duplicate_parameter_modifier : Error<"duplicate parameter modifier
def err_hlsl_missing_semantic_annotation : Error<
"semantic annotations must be present for all parameters of an entry "
"function or patch constant function">;
+def err_hlsl_unknown_semantic : Error<"unknown HLSL semantic %0">;
+def err_hlsl_semantic_output_not_supported
+ : Error<"semantic %0 does not support output">;
def err_hlsl_init_priority_unsupported : Error<
"initializer priorities are not supported in HLSL">;
@@ -13533,4 +13536,5 @@ def warn_acc_var_referenced_lacks_op
// AMDGCN builtins diagnostics
def err_amdgcn_load_lds_size_invalid_value : Error<"invalid size value">;
def note_amdgcn_load_lds_size_valid_value : Note<"size must be %select{1, 2, or 4|1, 2, 4, 12 or 16}0">;
+
} // end of sema component.
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 683934321a449..f07b4ebe567e5 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -5188,6 +5188,14 @@ class Parser : public CodeCompletionHandler {
ParseHLSLAnnotations(Attrs, EndLoc);
}
+ struct ParsedSemantic {
+ StringRef Name;
+ unsigned Index;
+ bool Explicit;
+ };
+
+ ParsedSemantic ParseHLSLSemantic();
+
void ParseHLSLAnnotations(ParsedAttributes &Attrs,
SourceLocation *EndLoc = nullptr,
bool CouldBeBitField = false);
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index c0da80a70bb82..7b72f9bfe77c5 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -129,6 +129,7 @@ class SemaHLSL : public SemaBase {
bool ActOnUninitializedVarDecl(VarDecl *D);
void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU);
void CheckEntryPoint(FunctionDecl *FD);
+ bool isSemanticValid(FunctionDecl *FD, DeclaratorDecl *D);
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param,
const HLSLAnnotationAttr *AnnotationAttr);
void DiagnoseAttrStageMismatch(
@@ -161,17 +162,31 @@ class SemaHLSL : public SemaBase {
void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL);
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);
void handleVkConstantIdAttr(Decl *D, const ParsedAttr &AL);
- void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
- void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL);
- void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL);
- void handleSV_PositionAttr(Decl *D, const ParsedAttr &AL);
+ // void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
+ // void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL);
+ // void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL);
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL);
void handleShaderAttr(Decl *D, const ParsedAttr &AL);
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL);
bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL);
+ template <typename T>
+ T *createSemanticAttr(const ParsedAttr &AL,
+ std::optional<unsigned> Location) {
+ T *Attr = ::new (getASTContext()) T(getASTContext(), AL);
+ if (Attr->isSemanticIndexable())
+ Attr->setSemanticIndex(Location ? *Location : 0);
+ return Attr;
+ // FIXME
+ }
+
+ void diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL,
+ std::optional<unsigned> Index);
+ void handleSemanticAttr(Decl *D, const ParsedAttr &AL);
+
void handleVkExtBuiltinInputAttr(Decl *D, const ParsedAttr &AL);
+ void handleVkLocationAttr(Decl *D, const ParsedAttr &AL);
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
QualType ProcessResourceTypeAttributes(QualType Wrapped);
diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index 81b186f844b8a..5878a4e3f83a4 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -189,7 +189,12 @@ AttributeCommonInfo::Kind
AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
const IdentifierInfo *ScopeName,
Syntax SyntaxUsed) {
- return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
+ AttributeCommonInfo::Kind Kind =
+ ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
+ if (SyntaxUsed == AS_HLSLAnnotation &&
+ Kind == AttributeCommonInfo::Kind::UnknownAttribute)
+ return AttributeCommonInfo::Kind::AT_HLSLUnparsedSemantic;
+ return Kind;
}
AttributeCommonInfo::AttrArgsInfo
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index a47d1cc22980d..67d04fbd5e51f 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
#include "llvm/IR/Constants.h"
@@ -336,6 +337,16 @@ void clang::CodeGen::CGHLSLRuntime::setHLSLEntryAttributes(
WaveSizeAttr->getPreferred());
Fn->addFnAttr(WaveSizeKindStr, WaveSizeStr);
}
+
+ if (HLSLVkLocationAttr *LocationAttr = FD->getAttr<HLSLVkLocationAttr>()) {
+ // const StringRef NumThreadsKindStr = "hlsl.numthreads";
+ // std::string NumThreadsStr =
+ // formatv("{0},{1},{2}", NumThreadsAttr->getX(),
+ // NumThreadsAttr->getY(),
+ // NumThreadsAttr->getZ());
+ // Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
+ }
+
// HLSL entry functions are materialized for module functions with
// HLSLShaderAttr attribute. SetLLVMFunctionAttributesForDefinition called
// later in the compiler-flow for such module functions is not aware of and
@@ -370,6 +381,16 @@ static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV,
GV->addMetadata("spirv.Decorations", *Decoration);
}
+static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location) {
+ LLVMContext &Ctx = GV->getContext();
+ IRBuilder<> B(GV->getContext());
+ MDNode *Operands =
+ MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(/* Location */ 30)),
+ ConstantAsMetadata::get(B.getInt32(Location))});
+ MDNode *Decoration = MDNode::get(Ctx, {Operands});
+ GV->addMetadata("spirv.Decorations", *Decoration);
+}
+
static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
llvm::Type *Ty, const Twine &Name,
unsigned BuiltInID) {
@@ -383,47 +404,418 @@ static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M,
return B.CreateLoad(Ty, GV);
}
-llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
- const ParmVarDecl &D,
- llvm::Type *Ty) {
- assert(D.hasAttrs() && "Entry parameter missing annotation attribute!");
- if (D.hasAttr<HLSLSV_GroupIndexAttr>()) {
+static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M,
+ llvm::Type *Ty, unsigned Location,
+ StringRef Name = "") {
+ auto *GV = new llvm::GlobalVariable(
+ M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage,
+ /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr,
+ llvm::GlobalVariable::GeneralDynamicTLSModel,
+ /* AddressSpace */ 7, /* isExternallyInitialized= */ true);
+ GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ addLocationDecoration(GV, Location);
+ return B.CreateLoad(Ty, GV);
+}
+
+llvm::Value *
+CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ SemanticInfo &ActiveSemantic,
+ HLSLVkLocationAttr *LocAttr) {
+ Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName());
+ Twine VariableName = BaseName.concat(Twine(ActiveSemantic.Index));
+
+ const bool hasExplicitLocation = LocAttr != nullptr;
+ if (SPIRVUsingExplicitLocation.value_or(hasExplicitLocation) !=
+ hasExplicitLocation)
+ CGM.Error(ActiveSemantic.Semantic->getLocation(),
+ "partial explicit stage input location assignment via "
+ "vk::location(X) unsupported");
+ else if (!SPIRVUsingExplicitLocation.has_value())
+ SPIRVUsingExplicitLocation = hasExplicitLocation;
+ unsigned Location = hasExplicitLocation
+ ? LocAttr->getLocation()
+ : SPIRVLastAssignedInputSemanticLocation;
+
+ // DXC completely ignores the semantic/index pair. Location are assigned from
+ // the first semantic to the last.
+ llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type);
+ unsigned ElementCount = AT ? AT->getNumElements() : 1;
+ SPIRVLastAssignedInputSemanticLocation += ElementCount;
+
+ return createSPIRVLocationLoad(B, CGM.getModule(), Type, Location,
+ VariableName.str());
+ llvm_unreachable("Unsupported target for user-semantic load.");
+}
+
+llvm::Value *
+CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ SemanticInfo &ActiveSemantic) {
+ Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName());
+ Twine VariableName = BaseName.concat(Twine(ActiveSemantic.Index));
+
+ // DXIL packing rules etc shall be handled here.
+ // FIXME: generate proper sigpoint, index, col, row values.
+ // FIXME: also DXIL loads vectors element by element.
+ SmallVector<Value *> Args{B.getInt32(4), B.getInt32(0), B.getInt32(0),
+ B.getInt8(0),
+ llvm::PoisonValue::get(B.getInt32Ty())};
+
+ llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input;
+ llvm::Value *Value = B.CreateIntrinsic(/*ReturnType=*/Type, IntrinsicID, Args,
+ nullptr, VariableName);
+ return Value;
+}
+
+llvm::Value *
+CGHLSLRuntime::emitUserSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic) {
+ // assert(nullptr != dyn_cast<HLSLUserSemanticAttr>(ActiveSemantic.Semantic));
+ uint32_t Location = ActiveSemantic.Index;
+
+ llvm::Value *SemanticValue = nullptr;
+ if (CGM.getTarget().getTriple().isSPIRV())
+ SemanticValue = emitSPIRVUserSemanticLoad(
+ B, Type, ActiveSemantic, Decl->getAttr<HLSLVkLocationAttr>());
+ else if (CGM.getTarget().getTriple().isDXIL())
+ SemanticValue = emitDXILUserSemanticLoad(B, Type, ActiveSemantic);
+ else
+ llvm_unreachable("Unsupported target for user-semantic load.");
+
+ llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type);
+ unsigned ElementCount = AT ? AT->getNumElements() : 1;
+ ActiveSemantic.Index += ElementCount;
+
+ // Mark the semantic/index pair as active and detect collisions.
+ Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName());
+ for (unsigned I = 0; I < ElementCount; I++) {
+ Twine VariableName = BaseName.concat(Twine(Location + I));
+ auto [_, Inserted] = ActiveInputSemantics.insert(VariableName.str());
+ if (!Inserted) {
+ CGM.getDiags().Report(Decl->getInnerLocStart(),
+ diag::err_hlsl_semantic_index_overlap)
+ << VariableName.str();
+ return nullptr;
+ }
+ }
+
+ return SemanticValue;
+}
+
+llvm::Value *
+CGHLSLRuntime::emitSystemSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic) {
+
+#define CHECK_NO_INDEXING(Info) \
+ if ((Info).Index != 0) { \
+ CGM.getDiags().Report(Decl->getInnerLocStart(), \
+ diag::err_hlsl_semantic_indexing_not_supported) \
+ << (Info).Semantic; \
+ return nullptr; \
+ }
+
+ if (HLSLSV_GroupIndexAttr *S =
+ dyn_cast<HLSLSV_GroupIndexAttr>(ActiveSemantic.Semantic)) {
+ CHECK_NO_INDEXING(ActiveSemantic)
llvm::Function *GroupIndex =
CGM.getIntrinsic(getFlattenedThreadIdInGroupIntrinsic());
return B.CreateCall(FunctionCallee(GroupIndex));
}
- if (D.hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
+
+ if (HLSLSV_DispatchThreadIDAttr *S =
+ dyn_cast<HLSLSV_DispatchThreadIDAttr>(ActiveSemantic.Semantic)) {
+ CHECK_NO_INDEXING(ActiveSemantic)
llvm::Intrinsic::ID IntrinID = getThreadIdIntrinsic();
llvm::Function *ThreadIDIntrinsic =
llvm::Intrinsic::isOverloaded(IntrinID)
? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
: CGM.getIntrinsic(IntrinID);
- return buildVectorInput(B, ThreadIDIntrinsic, Ty);
+ return buildVectorInput(B, ThreadIDIntrinsic, Type);
}
- if (D.hasAttr<HLSLSV_GroupThreadIDAttr>()) {
+
+ if (HLSLSV_GroupThreadIDAttr *S =
+ dyn_cast<HLSLSV_GroupThreadIDAttr>(ActiveSemantic.Semantic)) {
+ CHECK_NO_INDEXING(ActiveSemantic)
llvm::Intrinsic::ID IntrinID = getGroupThreadIdIntrinsic();
llvm::Function *GroupThreadIDIntrinsic =
llvm::Intrinsic::isOverloaded(IntrinID)
? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
: CGM.getIntrinsic(IntrinID);
- return buildVectorInput(B, GroupThreadIDIntrinsic, Ty);
+ return buildVectorInput(B, GroupThreadIDIntrinsic, Type);
}
- if (D.hasAttr<HLSLSV_GroupIDAttr>()) {
+
+ if (HLSLSV_GroupIDAttr *S =
+ dyn_cast<HLSLSV_GroupIDAttr>(ActiveSemantic.Semantic)) {
+ CHECK_NO_INDEXING(ActiveSemantic)
llvm::Intrinsic::ID IntrinID = getGroupIdIntrinsic();
llvm::Function *GroupIDIntrinsic =
llvm::Intrinsic::isOverloaded(IntrinID)
? CGM.getIntrinsic(IntrinID, {CGM.Int32Ty})
: CGM.getIntrinsic(IntrinID);
- return buildVectorInput(B, GroupIDIntrinsic, Ty);
+ return buildVectorInput(B, GroupIDIntrinsic, Type);
}
- if (D.hasAttr<HLSLSV_PositionAttr>()) {
- if (getArch() == llvm::Triple::spirv)
- return createSPIRVBuiltinLoad(B, CGM.getModule(), Ty, "sv_position",
- /* BuiltIn::Position */ 0);
- llvm_unreachable("SV_Position semantic not implemented for this target.");
+
+#undef CHECK_NO_INDEXING
+
+ if (HLSLSV_PositionAttr *S =
+ dyn_cast<HLSLSV_PositionAttr>(ActiveSemantic.Semantic)) {
+ if (CGM.getTriple().getEnvironment() == Triple::EnvironmentType::Pixel)
+ return createSPIRVBuiltinLoad(B, CGM.getModule(), Type, "gl_FragCoord",
+ /* BuiltIn::FragCoord */ 15);
+ else
+ return emitUserSemanticLoad(B, Type, Decl, ActiveSemantic);
}
- assert(false && "Unhandled parameter attribute");
- return nullptr;
+
+ llvm_unreachable("non-handled system semantic. FIXME.");
+}
+
+llvm::Value *
+CGHLSLRuntime::handleScalarSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic) {
+
+ if (!ActiveSemantic.Semantic) {
+ ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>();
+ if (!ActiveSemantic.Semantic) {
+ CGM.getDiags().Report(Decl->getInnerLocStart(),
+ diag::err_hlsl_semantic_missing);
+ return nullptr;
+ }
+ ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
+ }
+
+ if (auto *UserSemantic =
+ dyn_cast<HLSLUserSemanticAttr>(ActiveSemantic.Semantic))
+ return emitUserSemanticLoad(B, Type, Decl, ActiveSemantic);
+ return emitSystemSemanticLoad(B, Type, Decl, ActiveSemantic);
+}
+
+llvm::Value *
+CGHLSLRuntime::handleStructSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic) {
+ const llvm::StructType *ST = cast<StructType>(Type);
+ const clang::RecordDecl *RD = Decl->getType()->getAsRecordDecl();
+
+ assert(std::distance(RD->field_begin(), RD->field_end()) ==
+ ST->getNumElements());
+
+ if (!ActiveSemantic.Semantic) {
+ ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>();
+ ActiveSemantic.Index = ActiveSemantic.Semantic
+ ? ActiveSemantic.Semantic->getSemanticIndex()
+ : 0;
+ }
+
+ llvm::Value *Aggregate = llvm::PoisonValue::get(Type);
+ auto FieldDecl = RD->field_begin();
+ for (unsigned I = 0; I < ST->getNumElements(); ++I) {
+ SemanticInfo Info = ActiveSemantic;
+ llvm::Value *ChildValue =
+ handleSemanticLoad(B, ST->getElementType(I), *FieldDecl, Info);
+ if (!ChildValue) {
+ CGM.getDiags().Report(Decl->getInnerLocStart(),
+ diag::note_hlsl_semantic_used_here)
+ << Decl;
+ return nullptr;
+ }
+ if (ActiveSemantic.Semantic)
+ ActiveSemantic = Info;
+
+ Aggregate = B.CreateInsertValue(Aggregate, ChildValue, I);
+ ++FieldDecl;
+ }
+
+ return Aggregate;
+}
+
+llvm::Value *
+CGHLSLRuntime::handleSemanticLoad(IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic) {
+
+ if (Type->isStructTy())
+ return handleStructSemanticLoad(B, Type, Decl, ActiveSemantic);
+ return handleScalarSemanticLoad(B, Type, Decl, ActiveSemantic);
+}
+
+static void createSPIRVLocationStore(IRBuilder<> &B, llvm::Module &M,
+ llvm::Value *Value, unsigned Location,
+ StringRef Name = "") {
+ auto *GV = new llvm::GlobalVariable(
+ M, Value->getType(), /* isConstant= */ false,
+ llvm::GlobalValue::ExternalLinkage,
+ /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr,
+ llvm::GlobalVariable::GeneralDynamicTLSModel,
+ /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
+ GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ addLocationDecoration(GV, Location);
+ B.CreateStore(Value, GV);
+}
+
+void CGHLSLRuntime::emitSPIRVUserSemanticStore(llvm::IRBuilder<> &B,
+ llvm::Value *Source,
+ SemanticInfo &ActiveSemantic) {
+ Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName());
+ Twine VariableName = BaseName.concat(Twine(ActiveSemantic.Index));
+ unsigned Location = SPIRVLastAssignedOutputSemanticLocation;
+
+ // DXC completely ignores the semantic/index pair. Location are assigned from
+ // the first semantic to the last.
+ llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Source->getType());
+ unsigned ElementCount = AT ? AT->getNumElements() : 1;
+ SPIRVLastAssignedOutputSemanticLocation += ElementCount;
+
+ createSPIRVLocationStore(B, CGM.getModule(), Source, Location,
+ VariableName.str());
+}
+
+void CGHLSLRuntime::emitDXILUserSemanticStore(llvm::IRBuilder<> &B,
+ llvm::Value *Source,
+ SemanticInfo &ActiveSemantic) {
+ // DXIL packing rules etc shall be handled here.
+ // FIXME: generate proper sigpoint, index, col, row values.
+ SmallVector<Value *> Args{B.getInt32(4),
+ B.getInt32(0),
+ B.getInt32(0),
+ B.getInt8(0),
+ llvm::PoisonValue::get(B.getInt32Ty()),
+ Source};
+
+ llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_store_output;
+ B.CreateIntrinsic(/*ReturnType=*/CGM.VoidTy, IntrinsicID, Args, nullptr);
+}
+
+void CGHLSLRuntime::emitUserSemanticStore(IRBuilder<> &B, llvm::Value *Source,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic) {
+ assert(nullptr != dyn_cast<HLSLUserSemanticAttr>(ActiveSemantic.Semantic));
+
+ uint32_t Location = ActiveSemantic.Index;
+ if (HLSLVkLocationAttr *LocationAttr = Decl->getAttr<HLSLVkLocationAttr>())
+ Location = LocationAttr->getLocation();
+
+ if (CGM.getTarget().getTriple().isSPIRV())
+ emitSPIRVUserSemanticStore(B, Source, ActiveSemantic);
+ else if (CGM.getTarget().getTriple().isDXIL())
+ emitDXILUserSemanticStore(B, Source, ActiveSemantic);
+ else
+ llvm_unreachable("Unsupported target for user-semantic load.");
+
+ llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Source->getType());
+ unsigned ElementCount = AT ? AT->getNumElements() : 1;
+ ActiveSemantic.Index += ElementCount;
+
+ // Mark the semantic/index pair as active and detect collisions.
+ Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName());
+ for (unsigned I = 0; I < ElementCount; I++) {
+ Twine VariableName = BaseName.concat(Twine(Location + I));
+ auto [_, Inserted] = ActiveOutputSemantics.insert(VariableName.str());
+ if (!Inserted) {
+ CGM.getDiags().Report(Decl->getInnerLocStart(),
+ diag::err_hlsl_semantic_index_overlap)
+ << VariableName.str();
+ return;
+ }
+ }
+}
+
+static void createSPIRVBuiltinStore(IRBuilder<> &B, llvm::Module &M,
+ llvm::Type *Ty, const Twine &Name,
+ unsigned BuiltInID, Value *V) {
+ auto *GV = new llvm::GlobalVariable(
+ M, Ty, /* isConstant= */ false, llvm::GlobalValue::ExternalLinkage,
+ /* Initializer= */ nullptr, Name, /* insertBefore= */ nullptr,
+ llvm::GlobalVariable::GeneralDynamicTLSModel,
+ /* AddressSpace */ 8, /* isExternallyInitialized= */ false);
+ addSPIRVBuiltinDecoration(GV, BuiltInID);
+ GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ B.CreateStore(V, GV);
+}
+
+void CGHLSLRuntime::emitSystemSemanticStore(IRBuilder<> &B, llvm::Value *Source,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic) {
+
+ if (!CGM.getTarget().getTriple().isSPIRV())
+ llvm::report_fatal_error("DXIL semantic storage not implemented.");
+
+ if (HLSLSV_TargetAttr *S =
+ dyn_cast<HLSLSV_TargetAttr>(ActiveSemantic.Semantic))
+ emitSPIRVUserSemanticStore(B, Source, ActiveSemantic);
+ else if (HLSLSV_PositionAttr *S =
+ dyn_cast<HLSLSV_PositionAttr>(ActiveSemantic.Semantic))
+ createSPIRVBuiltinStore(B, CGM.getModule(), Source->getType(), "Position",
+ /* BuiltIn::Position */ 0, Source);
+ else
+ llvm_unreachable("non-handled system semantic. FIXME.");
+}
+
+void CGHLSLRuntime::handleScalarSemanticStore(IRBuilder<> &B,
+ llvm::Value *Source,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic) {
+
+ if (!ActiveSemantic.Semantic) {
+ ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>();
+ if (!ActiveSemantic.Semantic) {
+ CGM.getDiags().Report(Decl->getInnerLocStart(),
+ diag::err_hlsl_semantic_missing);
+ return;
+ }
+ ActiveSemantic.Index = ActiveSemantic.Semantic->getSemanticIndex();
+ }
+
+ if (auto *UserSemantic =
+ dyn_cast<HLSLUserSemanticAttr>(ActiveSemantic.Semantic))
+ emitUserSemanticStore(B, Source, Decl, ActiveSemantic);
+ else
+ emitSystemSemanticStore(B, Source, Decl, ActiveSemantic);
+}
+
+void CGHLSLRuntime::handleStructSemanticStore(IRBuilder<> &B,
+ llvm::Value *Source,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic) {
+
+ const llvm::StructType *ST = cast<StructType>(Source->getType());
+
+ const clang::RecordDecl *RD = nullptr;
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
+ RD = FD->getDeclaredReturnType()->getAsRecordDecl();
+ else
+ RD = Decl->getType()->getAsRecordDecl();
+ assert(RD);
+
+ assert(std::distance(RD->field_begin(), RD->field_end()) ==
+ ST->getNumElements());
+
+ if (!ActiveSemantic.Semantic) {
+ ActiveSemantic.Semantic = Decl->getAttr<HLSLSemanticAttr>();
+ ActiveSemantic.Index = ActiveSemantic.Semantic
+ ? ActiveSemantic.Semantic->getSemanticIndex()
+ : 0;
+ }
+
+ auto FieldDecl = RD->field_begin();
+ for (unsigned I = 0; I < ST->getNumElements(); ++I) {
+ llvm::Value *Extract = B.CreateExtractValue(Source, I);
+ SemanticInfo Info = ActiveSemantic;
+ handleSemanticStore(B, Extract, *FieldDecl, Info);
+ ++FieldDecl;
+ if (ActiveSemantic.Semantic)
+ ActiveSemantic = Info;
+ }
+}
+
+void CGHLSLRuntime::handleSemanticStore(IRBuilder<> &B, llvm::Value *Source,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic) {
+ if (Source->getType()->isStructTy())
+ handleStructSemanticStore(B, Source, Decl, ActiveSemantic);
+ else
+ handleScalarSemanticStore(B, Source, Decl, ActiveSemantic);
}
void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
@@ -446,7 +838,6 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
IRBuilder<> B(BB);
- llvm::SmallVector<Value *> Args;
SmallVector<OperandBundleDef, 1> OB;
if (CGM.shouldEmitConvergenceTokens()) {
@@ -457,25 +848,64 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
OB.emplace_back("convergencectrl", bundleArgs);
}
- // FIXME: support struct parameters where semantics are on members.
- // See: https://github.com/llvm/llvm-project/issues/57874
+ std::unordered_map<const DeclaratorDecl *, llvm::Value *> OutputSemantic;
+
+ llvm::SmallVector<Value *> Args;
unsigned SRetOffset = 0;
for (const auto &Param : Fn->args()) {
+
if (Param.hasStructRetAttr()) {
- // FIXME: support output.
- // See: https://github.com/llvm/llvm-project/issues/57874
SRetOffset = 1;
- Args.emplace_back(PoisonValue::get(Param.getType()));
+ llvm::Type *VarType = Param.getParamStructRetType();
+ llvm::Value *Var = B.CreateAlloca(VarType);
+ Args.push_back(Var);
+ OutputSemantic.emplace(FD, Var);
continue;
}
+
const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
- Args.push_back(emitInputSemantic(B, *PD, Param.getType()));
+ llvm::Value *SemanticValue = nullptr;
+ if (HLSLParamModifierAttr *MA = PD->getAttr<HLSLParamModifierAttr>()) {
+ if (MA->isOut()) {
+ llvm::Type *VarType = CGM.getTypes().ConvertType(
+ cast<clang::ReferenceType>(PD->getType())->getPointeeType());
+ llvm::Value *Var = B.CreateAlloca(VarType);
+ SemanticValue = Var;
+ OutputSemantic.emplace(PD, Var);
+ } else
+ llvm_unreachable("Not handled yet");
+ } else {
+ llvm::Type *ParamType =
+ Param.hasByValAttr() ? Param.getParamByValType() : Param.getType();
+ SemanticInfo ActiveSemantic = {nullptr, 0};
+ SemanticValue = handleSemanticLoad(B, ParamType, PD, ActiveSemantic);
+ if (!SemanticValue)
+ return;
+ if (Param.hasByValAttr()) {
+ llvm::Value *Var = B.CreateAlloca(Param.getParamByValType());
+ B.CreateStore(SemanticValue, Var);
+ SemanticValue = Var;
+ }
+ }
+ Args.push_back(SemanticValue);
}
CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args, OB);
CI->setCallingConv(Fn->getCallingConv());
- // FIXME: Handle codegen for return type semantics.
- // See: https://github.com/llvm/llvm-project/issues/57875
+
+ if (Fn->getReturnType() != CGM.VoidTy)
+ OutputSemantic.emplace(FD, CI);
+
+ for (auto &[Decl, Source] : OutputSemantic) {
+ llvm::Value *SourceValue = nullptr;
+ if (AllocaInst *AI = dyn_cast<AllocaInst>(Source))
+ SourceValue = B.CreateLoad(AI->getAllocatedType(), Source);
+ else
+ SourceValue = Source;
+ SemanticInfo ActiveSemantic = {nullptr, 0};
+ handleSemanticStore(B, SourceValue, Decl, ActiveSemantic);
+ }
+
B.CreateRetVoid();
// Add and identify root signature to function, if applicable
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 89d2aff85d913..9f3491d439a9d 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -21,6 +21,8 @@
#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/IntrinsicsSPIRV.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/HLSLRuntime.h"
@@ -29,6 +31,7 @@
#include "llvm/Frontend/HLSL/HLSLResource.h"
#include <optional>
+#include <unordered_set>
#include <vector>
// A function generator macro for picking the right intrinsic
@@ -133,8 +136,75 @@ class CGHLSLRuntime {
protected:
CodeGenModule &CGM;
- llvm::Value *emitInputSemantic(llvm::IRBuilder<> &B, const ParmVarDecl &D,
- llvm::Type *Ty);
+ void collectInputSemantic(llvm::IRBuilder<> &B, const DeclaratorDecl *D,
+ llvm::Type *Type,
+ SmallVectorImpl<llvm::Value *> &Inputs);
+
+ struct SPIRVState {
+ uint32_t NextLocation;
+ };
+
+ struct SemanticInfo {
+ clang::HLSLSemanticAttr *Semantic;
+ uint32_t Index;
+ };
+
+ // llvm::Value *createDXILLocationLoad(llvm::IRBuilder<> &B, llvm::Module &M,
+ // llvm::Type *Ty, unsigned Location, StringRef Name = "");
+
+ llvm::Value *emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ SemanticInfo &ActiveSemantic,
+ HLSLVkLocationAttr *LocAttr);
+ llvm::Value *emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ SemanticInfo &ActiveSemantic);
+
+ llvm::Value *emitUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic);
+
+ llvm::Value *emitSystemSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic);
+
+ llvm::Value *handleScalarSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic);
+
+ llvm::Value *handleStructSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic);
+
+ llvm::Value *handleSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic);
+ ///
+
+ void emitSPIRVUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value,
+ SemanticInfo &ActiveSemantic);
+ void emitDXILUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value,
+ SemanticInfo &ActiveSemantic);
+
+ void emitUserSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic);
+
+ void emitSystemSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic);
+
+ void handleScalarSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic);
+
+ void handleStructSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic);
+
+ void handleSemanticStore(llvm::IRBuilder<> &B, llvm::Value *Value,
+ const clang::DeclaratorDecl *Decl,
+ SemanticInfo &ActiveSemantic);
+
+ ///
public:
CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
@@ -172,6 +242,13 @@ class CGHLSLRuntime {
llvm::Triple::ArchType getArch();
llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes;
+
+ std::unordered_set<std::string> ActiveInputSemantics;
+ std::unordered_set<std::string> ActiveOutputSemantics;
+
+ std::optional<bool> SPIRVUsingExplicitLocation = std::nullopt;
+ unsigned SPIRVLastAssignedInputSemanticLocation = 0;
+ unsigned SPIRVLastAssignedOutputSemanticLocation = 0;
};
} // namespace CodeGen
diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp
index e6caa81b309ca..72e1cc9eff63f 100644
--- a/clang/lib/Parse/ParseHLSL.cpp
+++ b/clang/lib/Parse/ParseHLSL.cpp
@@ -118,6 +118,48 @@ static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc,
Slot = new (Ctx) IdentifierLoc(ArgLoc, PP.getIdentifierInfo(FixedArg));
}
+Parser::ParsedSemantic Parser::ParseHLSLSemantic() {
+ assert(Tok.is(tok::identifier) && "Not a HLSL Annotation");
+
+ // Semantic pattern: [A-Za-z_]+[0-9]*
+ // The first part is the semantic name, the second is the optional
+ // semantic index.
+ bool Invalid = false;
+ SmallString<256> Buffer;
+ Buffer.resize(Tok.getLength() + 1);
+ StringRef Identifier = PP.getSpelling(Tok, Buffer);
+ if (Invalid) {
+ // FIXME: fix error message.
+ Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);
+ return {/* Name= */ "", /* Location= */ 0, /* Explicit= */ false};
+ }
+
+ unsigned I = 0;
+ for (; I < Identifier.size() && !isDigit(Identifier[I]); ++I)
+ continue;
+ StringRef SemanticName = Identifier.take_front(I);
+
+ if (SemanticName.size() == 0) {
+ // FIXME: fix error message.
+ Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);
+ return {/* Name= */ "", /* Location= */ 0, /* Explicit= */ false};
+ }
+
+ unsigned Index = 0;
+ bool Explicit = I < Identifier.size();
+ for (; I < Identifier.size() && isDigit(Identifier[I]); ++I)
+ Index = Index * 10 + Identifier[I] - '0';
+
+ // The attribute has letters after the index.
+ if (I != Identifier.size()) {
+ // FIXME: fix error message.
+ Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);
+ return {/* Name= */ "", /* Location= */ 0, /* Explicit= */ false};
+ }
+
+ return {SemanticName, Index, Explicit};
+}
+
void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
SourceLocation *EndLoc,
bool CouldBeBitField) {
@@ -141,11 +183,15 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
return;
}
+ ParsedAttr::Kind AttrKind =
+ ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLAnnotation);
+ Parser::ParsedSemantic Semantic;
+ if (AttrKind == ParsedAttr::AT_HLSLUnparsedSemantic)
+ Semantic = ParseHLSLSemantic();
+
SourceLocation Loc = ConsumeToken();
if (EndLoc)
*EndLoc = Tok.getLocation();
- ParsedAttr::Kind AttrKind =
- ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLAnnotation);
ArgsVector ArgExprs;
switch (AttrKind) {
@@ -282,19 +328,30 @@ void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs,
return;
}
} break;
- case ParsedAttr::UnknownAttribute:
- Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
- return;
- case ParsedAttr::AT_HLSLSV_GroupThreadID:
- case ParsedAttr::AT_HLSLSV_GroupID:
- case ParsedAttr::AT_HLSLSV_GroupIndex:
- case ParsedAttr::AT_HLSLSV_DispatchThreadID:
- case ParsedAttr::AT_HLSLSV_Position:
+ case ParsedAttr::UnknownAttribute: {
+ break;
+ }
+ case ParsedAttr::AT_HLSLUnparsedSemantic: {
+ ASTContext &Ctx = Actions.getASTContext();
+ ArgExprs.push_back(IntegerLiteral::Create(
+ Ctx, llvm::APInt(Ctx.getTypeSize(Ctx.IntTy), Semantic.Index), Ctx.IntTy,
+ SourceLocation()));
+ ArgExprs.push_back(IntegerLiteral::Create(
+ Ctx, llvm::APInt(1, Semantic.Explicit), Ctx.BoolTy, SourceLocation()));
+ II = PP.getIdentifierInfo(Semantic.Name.upper());
break;
- default:
+ }
+ // case ParsedAttr::AT_HLSLSV_GroupThreadID:
+ // case ParsedAttr::AT_HLSLSV_GroupID:
+ // case ParsedAttr::AT_HLSLSV_GroupIndex:
+ // case ParsedAttr::AT_HLSLSV_DispatchThreadID:
+ case ParsedAttr::AT_HLSLVkLocation:
+ break;
+ default: {
llvm_unreachable("invalid HLSL Annotation");
break;
}
+ }
Attrs.addNew(II, Loc, AttributeScopeInfo(), ArgExprs.data(), ArgExprs.size(),
ParsedAttr::Form::HLSLAnnotation());
diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp
index 294f88eae931c..e7c10d198f144 100644
--- a/clang/lib/Sema/ParsedAttr.cpp
+++ b/clang/lib/Sema/ParsedAttr.cpp
@@ -103,6 +103,7 @@ namespace {
} // namespace
const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
+
// If we have a ParsedAttrInfo for this ParsedAttr then return that.
if ((size_t)A.getParsedKind() < std::size(AttrInfoMap))
return *AttrInfoMap[A.getParsedKind()];
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 16b18bcb6a2a0..aa47bd677f688 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -6786,6 +6786,7 @@ static bool MustDelayAttributeArguments(const ParsedAttr &AL) {
static void
ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
const Sema::ProcessDeclAttributeOptions &Options) {
+
if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute)
return;
@@ -7432,30 +7433,27 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLWaveSize:
S.HLSL().handleWaveSizeAttr(D, AL);
break;
- case ParsedAttr::AT_HLSLSV_Position:
- S.HLSL().handleSV_PositionAttr(D, AL);
- break;
case ParsedAttr::AT_HLSLVkExtBuiltinInput:
S.HLSL().handleVkExtBuiltinInputAttr(D, AL);
break;
case ParsedAttr::AT_HLSLVkConstantId:
S.HLSL().handleVkConstantIdAttr(D, AL);
break;
- case ParsedAttr::AT_HLSLSV_GroupThreadID:
- S.HLSL().handleSV_GroupThreadIDAttr(D, AL);
- break;
- case ParsedAttr::AT_HLSLSV_GroupID:
- S.HLSL().handleSV_GroupIDAttr(D, AL);
- break;
- case ParsedAttr::AT_HLSLSV_GroupIndex:
- handleSimpleAttribute<HLSLSV_GroupIndexAttr>(S, D, AL);
- break;
+ // case ParsedAttr::AT_HLSLSV_GroupThreadID:
+ // S.HLSL().handleSV_GroupThreadIDAttr(D, AL);
+ // break;
+ // case ParsedAttr::AT_HLSLSV_GroupID:
+ // S.HLSL().handleSV_GroupIDAttr(D, AL);
+ // break;
+ // case ParsedAttr::AT_HLSLSV_GroupIndex:
+ // handleSimpleAttribute<HLSLSV_GroupIndexAttr>(S, D, AL);
+ // break;
+ // case ParsedAttr::AT_HLSLSV_DispatchThreadID:
+ // S.HLSL().handleSV_DispatchThreadIDAttr(D, AL);
+ // break;
case ParsedAttr::AT_HLSLGroupSharedAddressSpace:
handleSimpleAttribute<HLSLGroupSharedAddressSpaceAttr>(S, D, AL);
break;
- case ParsedAttr::AT_HLSLSV_DispatchThreadID:
- S.HLSL().handleSV_DispatchThreadIDAttr(D, AL);
- break;
case ParsedAttr::AT_HLSLPackOffset:
S.HLSL().handlePackOffsetAttr(D, AL);
break;
@@ -7468,6 +7466,12 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLParamModifier:
S.HLSL().handleParamModifierAttr(D, AL);
break;
+ case ParsedAttr::AT_HLSLVkLocation:
+ S.HLSL().handleVkLocationAttr(D, AL);
+ break;
+ case ParsedAttr::AT_HLSLUnparsedSemantic:
+ S.HLSL().handleSemanticAttr(D, AL);
+ break;
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 9276554bebf9d..9bfb8f2c21498 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -747,6 +747,28 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) {
}
}
+bool SemaHLSL::isSemanticValid(FunctionDecl *FD, DeclaratorDecl *D) {
+ const auto *AnnotationAttr = D->getAttr<HLSLAnnotationAttr>();
+ if (AnnotationAttr) {
+ CheckSemanticAnnotation(FD, D, AnnotationAttr);
+ return true;
+ }
+
+ const Type *T =
+ D->getType()
+ ->getUnqualifiedDesugaredType(); //.getDesugaredType(getASTContext());
+ const RecordType *RT = dyn_cast<RecordType>(T);
+ if (!RT)
+ return false;
+
+ const RecordDecl *RD = RT->getDecl();
+ for (FieldDecl *Field : RD->fields()) {
+ if (!isSemanticValid(FD, Field))
+ return false;
+ }
+ return true;
+}
+
void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
assert(ShaderAttr && "Entry point has no shader attribute");
@@ -808,15 +830,17 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) {
}
for (ParmVarDecl *Param : FD->parameters()) {
- if (const auto *AnnotationAttr = Param->getAttr<HLSLAnnotationAttr>()) {
- CheckSemanticAnnotation(FD, Param, AnnotationAttr);
- } else {
+ if (!isSemanticValid(FD, Param)) {
// FIXME: Handle struct parameters where annotations are on struct fields.
// See: https://github.com/llvm/llvm-project/issues/57875
Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation);
Diag(Param->getLocation(), diag::note_previous_decl) << Param;
FD->setInvalidDecl();
}
+ // if (const auto *AnnotationAttr = Param->getAttr<HLSLAnnotationAttr>()) {
+ // CheckSemanticAnnotation(FD, Param, AnnotationAttr);
+ // } else {
+ // }
}
// FIXME: Verify return type semantic annotation.
}
@@ -837,13 +861,23 @@ void SemaHLSL::CheckSemanticAnnotation(
return;
DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Compute});
break;
+ case attr::HLSLVkLocation:
+ if (ST == llvm::Triple::Pixel || ST == llvm::Triple::Vertex)
+ return;
+ DiagnoseAttrStageMismatch(AnnotationAttr, ST,
+ {llvm::Triple::Pixel, llvm::Triple::Vertex});
+ break;
case attr::HLSLSV_Position:
- // TODO(#143523): allow use on other shader types & output once the overall
- // semantic logic is implemented.
if (ST == llvm::Triple::Pixel)
return;
DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Pixel});
break;
+ case attr::HLSLSV_Target:
+ case attr::HLSLUserSemantic:
+ // FIXME: handle system & stage mismatch.
+ // DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Pixel,
+ // llvm::Triple::Vertex});
+ return;
default:
llvm_unreachable("Unknown HLSLAnnotationAttr");
}
@@ -1492,18 +1526,8 @@ bool SemaHLSL::diagnoseInputIDType(QualType T, const ParsedAttr &AL) {
return true;
}
-void SemaHLSL::handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL) {
- auto *VD = cast<ValueDecl>(D);
- if (!diagnoseInputIDType(VD->getType(), AL))
- return;
-
- D->addAttr(::new (getASTContext())
- HLSLSV_DispatchThreadIDAttr(getASTContext(), AL));
-}
-
bool SemaHLSL::diagnosePositionType(QualType T, const ParsedAttr &AL) {
const auto *VT = T->getAs<VectorType>();
-
if (!T->hasFloatingRepresentation() || (VT && VT->getNumElements() > 4)) {
Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
<< AL << "float/float1/float2/float3/float4";
@@ -1513,29 +1537,70 @@ bool SemaHLSL::diagnosePositionType(QualType T, const ParsedAttr &AL) {
return true;
}
-void SemaHLSL::handleSV_PositionAttr(Decl *D, const ParsedAttr &AL) {
- auto *VD = cast<ValueDecl>(D);
- if (!diagnosePositionType(VD->getType(), AL))
- return;
-
- D->addAttr(::new (getASTContext()) HLSLSV_PositionAttr(getASTContext(), AL));
-}
+void SemaHLSL::diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL,
+ std::optional<unsigned> Index) {
+ StringRef SemanticName = AL.getAttrName()->getName();
-void SemaHLSL::handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL) {
auto *VD = cast<ValueDecl>(D);
- if (!diagnoseInputIDType(VD->getType(), AL))
- return;
+ QualType ValueType = VD->getType();
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ ValueType = FD->getReturnType();
+
+ bool IsOutput = false;
+ if (HLSLParamModifierAttr *MA = D->getAttr<HLSLParamModifierAttr>()) {
+ if (MA->isOut()) {
+ IsOutput = true;
+ ValueType = cast<ReferenceType>(ValueType)->getPointeeType();
+ }
+ }
- D->addAttr(::new (getASTContext())
- HLSLSV_GroupThreadIDAttr(getASTContext(), AL));
+#define CHECK_OUTPUT_FORBIDDEN(AL) \
+ if (IsOutput) { \
+ Diag(AL.getLoc(), diag::err_hlsl_semantic_output_not_supported) << AL; \
+ }
+
+ if (SemanticName == "SV_DISPATCHTHREADID") {
+ diagnoseInputIDType(ValueType, AL);
+ CHECK_OUTPUT_FORBIDDEN(AL);
+ D->addAttr(createSemanticAttr<HLSLSV_DispatchThreadIDAttr>(AL, Index));
+ } else if (SemanticName == "SV_GROUPINDEX") {
+ // diagnoseInputIDType(ValueType, AL);
+ CHECK_OUTPUT_FORBIDDEN(AL);
+ D->addAttr(createSemanticAttr<HLSLSV_GroupIndexAttr>(AL, Index));
+ } else if (SemanticName == "SV_GROUPTHREADID") {
+ diagnoseInputIDType(ValueType, AL);
+ CHECK_OUTPUT_FORBIDDEN(AL);
+ D->addAttr(createSemanticAttr<HLSLSV_GroupThreadIDAttr>(AL, Index));
+ } else if (SemanticName == "SV_GROUPID") {
+ diagnoseInputIDType(ValueType, AL);
+ CHECK_OUTPUT_FORBIDDEN(AL);
+ D->addAttr(createSemanticAttr<HLSLSV_GroupIDAttr>(AL, Index));
+ } else if (SemanticName == "SV_TARGET" || SemanticName == "SV_POSITION") {
+ const auto *VT = ValueType->getAs<VectorType>();
+ if (!ValueType->hasFloatingRepresentation() ||
+ (VT && VT->getNumElements() > 4))
+ Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
+ << AL << "float/float1/float2/float3/float4";
+ if (SemanticName == "SV_POSITION")
+ D->addAttr(createSemanticAttr<HLSLSV_PositionAttr>(AL, Index));
+ else
+ D->addAttr(createSemanticAttr<HLSLSV_TargetAttr>(AL, Index));
+ } else
+ Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL;
}
-void SemaHLSL::handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL) {
- auto *VD = cast<ValueDecl>(D);
- if (!diagnoseInputIDType(VD->getType(), AL))
- return;
-
- D->addAttr(::new (getASTContext()) HLSLSV_GroupIDAttr(getASTContext(), AL));
+void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) {
+ uint32_t IndexValue, ExplicitIndex;
+ SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), IndexValue);
+ SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), ExplicitIndex);
+ assert(IndexValue > 0 ? ExplicitIndex : true);
+ std::optional<unsigned> Index =
+ ExplicitIndex ? std::optional<unsigned>(IndexValue) : std::nullopt;
+
+ if (AL.getAttrName()->getName().starts_with("SV_"))
+ diagnoseSystemSemanticAttr(D, AL, Index);
+ else
+ D->addAttr(createSemanticAttr<HLSLUserSemanticAttr>(AL, Index));
}
void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) {
@@ -1768,6 +1833,15 @@ bool SemaHLSL::handleResourceTypeAttr(QualType T, const ParsedAttr &AL) {
return true;
}
+void SemaHLSL::handleVkLocationAttr(Decl *D, const ParsedAttr &AL) {
+ uint32_t Location;
+ if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), Location))
+ return;
+
+ D->addAttr(::new (getASTContext())
+ HLSLVkLocationAttr(getASTContext(), AL, Location));
+}
+
// Combines all resource type attributes and creates HLSLAttributedResourceType.
QualType SemaHLSL::ProcessResourceTypeAttributes(QualType CurrentType) {
if (!HLSLResourcesTypeAttrs.size())
diff --git a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
index bdba38e028edd..deeda7452e5e0 100644
--- a/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
+++ b/clang/test/CodeGenHLSL/semantics/SV_Position.ps.hlsl
@@ -1,10 +1,14 @@
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s
-// CHECK: @sv_position = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations !0
+// CHECK: @gl_FragCoord = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_0:]]
+
// CHECK: define void @main() {{.*}} {
-float4 main(float4 p : SV_Position) {
- // CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @sv_position, align 16
+float4 main(float4 p : SV_Position) : SV_TARGET {
+ // CHECK: %[[#P:]] = load <4 x float>, ptr addrspace(7) @gl_FragCoord, align 16
// CHECK: %[[#R:]] = call spir_func <4 x float> @_Z4mainDv4_f(<4 x float> %[[#P]])
return p;
}
+
+// CHECK: ![[#MD_0]] = !{![[#MD_1:]]}
+// CHECK: ![[#MD_1]] = !{i32 11, i32 15}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
new file mode 100644
index 0000000000000..70585cf55262e
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
+
+// CHECK-SPIRV-DAG: @AAA0 = external hidden thread_local addrspace(7) externally_initialized constant float, !spirv.Decorations ![[#METADATA_0:]]
+// CHECK-SPIRV-DAG: @B0 = external hidden thread_local addrspace(7) externally_initialized constant i32, !spirv.Decorations ![[#METADATA_2:]]
+// CHECK-SPIRV-DAG: @CC0 = external hidden thread_local addrspace(7) externally_initialized constant <2 x float>, !spirv.Decorations ![[#METADATA_4:]]
+// CHECK-SPIRV-DAG: @DDDD0 = external hidden thread_local addrspace(8) global float, !spirv.Decorations ![[#METADATA_0:]]
+
+
+// FIXME: replace `float2 c` with a matrix when available.
+float main(float a : AAA, int b : B, float2 c : CC) : DDDD {
+ return a + b + c.x + c.y;
+}
+// CHECK-SPIRV: define internal spir_func noundef nofpclass(nan inf) float @_Z4mainfiDv2_f(float noundef nofpclass(nan inf) %a, i32 noundef %b, <2 x float> noundef nofpclass(nan inf) %c)
+
+// CHECK: define void @main()
+
+// CHECK-DXIL: %AAA0 = call float @llvm.dx.load.input.f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %B0 = call i32 @llvm.dx.load.input.i32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL %CC0 = call <2 x float> @llvm.dx.load.input.v2f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+// CHECK-DXIL: %[[#call:]] = call float @_Z4mainfiDv2_f(float %AAA0, i32 %B0, <2 x float> %CC0)
+// CHECK-DXIL: call void @llvm.dx.store.output.f32(i32 4, i32 0, i32 0, i8 0, i32 poison, float %[[#call]])
+
+// CHECK-SPIRV: %[[#AAA0:]] = load float, ptr addrspace(7) @AAA0, align 4
+// CHECK-SPIRV: %[[#B0:]] = load i32, ptr addrspace(7) @B0, align 4
+// CHECK-SPIRV: %[[#CC0:]] = load <2 x float>, ptr addrspace(7) @CC0, align 8
+// CHECK-SPIRV: %[[#call:]] = call spir_func float @_Z4mainfiDv2_f(float %[[#AAA0]], i32 %[[#B0]], <2 x float> %[[#CC0]]) [ "convergencectrl"(token %0) ]
+// CHECK-SPIRV: store float %[[#call]], ptr addrspace(8) @DDDD0, align 4
+
+// CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]}
+// CHECK-SPIRV-DAG: ![[#METADATA_1]] = !{i32 30, i32 0}
+// CHECK-SPIRV-DAG: ![[#METADATA_2]] = !{![[#METADATA_3:]]}
+// CHECK-SPIRV-DAG: ![[#METADATA_3]] = !{i32 30, i32 1}
+// CHECK-SPIRV-DAG: ![[#METADATA_4]] = !{![[#METADATA_5:]]}
+// CHECK-SPIRV-DAG: ![[#METADATA_5]] = !{i32 30, i32 2}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array-output.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array-output.hlsl
new file mode 100644
index 0000000000000..16dd30a295468
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array-output.hlsl
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv
+
+struct S0 {
+ float4 position[2];
+ float4 color;
+};
+
+// CHECK: %struct.S0 = type { [2 x <4 x float>], <4 x float> }
+
+// CHECK-SPIRV: @A0 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_0:]]
+// CHECK-SPIRV: @B0 = external hidden thread_local addrspace(8) global [2 x <4 x float>], !spirv.Decorations ![[#MD_0:]]
+// CHECK-SPIRV: @B2 = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations ![[#MD_2:]]
+
+// CHECK: define void @main0()
+// CHECK: %[[#OUT:]] = alloca %struct.S0, align 16
+// CHECK-SPIRV: %[[#ARG:]] = load <4 x float>, ptr addrspace(7) @A0, align 16
+// CHECK-SPIRV: call spir_func void @{{.*}}main0{{.*}}(ptr %[[#OUT]], <4 x float> %[[#ARG]])
+// CHECK: %[[#TMP:]] = load %struct.S0, ptr %[[#OUT]], align 16
+// CHECK: %[[#B0:]] = extractvalue %struct.S0 %[[#TMP]], 0
+// CHECK-SPIRV: store [2 x <4 x float>] %4, ptr addrspace(8) @B0, align 16
+// CHECK: %[[#B2:]] = extractvalue %struct.S0 %[[#TMP]], 1
+// CHECK-SPIRV: store <4 x float> %5, ptr addrspace(8) @B2, align 16
+[shader("vertex")]
+S0 main0(float4 input : A) : B {
+ S0 output;
+ output.position[0] = input;
+ output.position[1] = input;
+ output.color = input;
+ return output;
+}
+
+// CHECK-SPIRV: ![[#MD_0]] = !{![[#MD_1:]]}
+// CHECK-SPIRV: ![[#MD_1]] = !{i32 30, i32 0}
+// CHECK-SPIRV: ![[#MD_2]] = !{![[#MD_3:]]}
+// CHECK-SPIRV: ![[#MD_3]] = !{i32 30, i32 2}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
new file mode 100644
index 0000000000000..070a94fb84007
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv
+
+struct S0 {
+ float4 position[2];
+ float4 color;
+};
+
+// CHECK: %struct.S0 = type { [2 x <4 x float>], <4 x float> }
+
+// CHECK-SPIRV: @A0 = external hidden thread_local addrspace(7) externally_initialized constant [2 x <4 x float>], !spirv.Decorations ![[#MD_0:]]
+// CHECK-SPIRV: @A2 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_2:]]
+// CHECK-SPIRV: @SV_TARGET0 = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations ![[#MD_0]]
+
+// CHECK: define void @main0()
+// CHECK-DXIL: %[[#A0:]] = call [2 x <4 x float>] @llvm.dx.load.input.a2v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+// CHECK-SPIRV: %[[#A0:]] = load [2 x <4 x float>], ptr addrspace(7) @A0, align 16
+// CHECK: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#A0]], 0
+// CHECK-DXIL: %[[#A2:]] = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+// CHECK-SPIRV: %[[#A2:]] = load <4 x float>, ptr addrspace(7) @A2, align 16
+// CHECK: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %[[#A2]], 1
+
+// CHECK: %[[#ARG:]] = alloca %struct.S0, align 16
+// CHECK: store %struct.S0 %[[#TMP1]], ptr %[[#ARG]], align 16
+// CHECK-DXIL: %[[#RET:]] = call <4 x float> @{{.*}}main0{{.*}}(ptr %[[#ARG]])
+// CHECK-SPIRV: %[[#RET:]] = call spir_func <4 x float> @{{.*}}main0{{.*}}(ptr %[[#ARG]])
+// CHECK: store <4 x float> %[[#RET]], ptr addrspace(8) @SV_TARGET0, align 16
+[shader("pixel")]
+float4 main0(S0 p : A) : SV_Target {
+ return p.position[0] + p.position[1] + p.color;
+}
+
+// CHECK-SPIRV: ![[#MD_0]] = !{![[#MD_1:]]}
+// CHECK-SPIRV: ![[#MD_1]] = !{i32 30, i32 0}
+// CHECK-SPIRV: ![[#MD_2]] = !{![[#MD_3:]]}
+// CHECK-SPIRV: ![[#MD_3]] = !{i32 30, i32 2}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-builtin-vs.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-builtin-vs.hlsl
new file mode 100644
index 0000000000000..76bad34266e5f
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-builtin-vs.hlsl
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s -verify
+
+// This is almost the same as semantic.explicit-mix-builtin.hlsl, except this
+// time we build a vertex shader. This means the SV_Position semantic is not
+// a BuiltIn anymore, but a Location decorated variable. This means we mix
+// implicit and explicit location assignment.
+struct S1 {
+ float4 position : SV_Position;
+ [[vk::location(3)]] float4 color : A;
+ // expected-error at -1 {{partial explicit stage input location assignment via vk::location(X) unsupported}}
+};
+
+[shader("pixel")]
+float4 main1(S1 p) : A {
+ return p.position + p.color;
+}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-builtin.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-builtin.hlsl
new file mode 100644
index 0000000000000..4b7cc8549ff27
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-builtin.hlsl
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-pixel -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv
+
+// The following code is allowed because the `SV_Position` semantic is here
+// translated into a SPIR-V builtin. Meaning there is no implicit `Location`
+// assignment.
+
+struct S1 {
+ float4 position : SV_Position;
+ [[vk::location(3)]] float4 color : A;
+};
+
+// CHECK-SPIRV: @gl_FragCoord = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_0:]]
+// CHECK-SPIRV: @A0 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_2:]]
+// CHECK-SPIRV: @SV_TARGET0 = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations ![[#MD_4:]]
+
+[shader("pixel")]
+float4 main1(S1 p) : SV_Target {
+ return p.position + p.color;
+}
+// CHECK-SPIRV: %[[#SV_POS:]] = load <4 x float>, ptr addrspace(7) @gl_FragCoord, align 16
+// CHECK: %[[#TMP1:]] = insertvalue %struct.S1 poison, <4 x float> %[[#SV_POS]], 0
+// CHECK-SPIRV: %[[#A0:]] = load <4 x float>, ptr addrspace(7) @A0, align 16
+// CHECK: %[[#TMP2:]] = insertvalue %struct.S1 %[[#TMP1]], <4 x float> %[[#A0]], 1
+// CHECK: %[[#P:]] = alloca %struct.S1, align 16
+// CHECK: store %struct.S1 %[[#TMP2]], ptr %[[#P]], align 16
+// CHECK-SPIRV: call spir_func <4 x float> @_Z5main12S1(ptr %[[#P]])
+
+// CHECK-SPIRV: ![[#MD_0]] = !{![[#MD_1:]]}
+// CHECK-SPIRV: ![[#MD_1]] = !{i32 11, i32 15}
+// CHECK-SPIRV: ![[#MD_2]] = !{![[#MD_3:]]}
+// CHECK-SPIRV: ![[#MD_3]] = !{i32 30, i32 3}
+// CHECK-SPIRV: ![[#MD_4]] = !{![[#MD_5:]]}
+// CHECK-SPIRV: ![[#MD_5]] = !{i32 30, i32 0}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-location-2.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-location-2.hlsl
new file mode 100644
index 0000000000000..668a0d59f7a86
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-location-2.hlsl
@@ -0,0 +1,15 @@
+// RUN: %clang --driver-mode=dxc %s -T ps_6_8 -E main1 -O3 -spirv -Xclang -verify
+
+// The following code is not legal: both semantics A and B will be lowered
+// into a Location decoration. And mixing implicit and explicit Location
+// assignment is not supported.
+struct S1 {
+ [[vk::location(3)]] float4 color : B;
+ float4 position : A;
+ // expected-error at -1 {{partial explicit stage input location assignment via vk::location(X) unsupported}}
+};
+
+[shader("pixel")]
+float4 main1(S1 p) : SV_Target {
+ return p.position + p.color;
+}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-location.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-location.hlsl
new file mode 100644
index 0000000000000..2c519fda2424d
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.explicit-mix-location.hlsl
@@ -0,0 +1,15 @@
+// RUN: %clang --driver-mode=dxc %s -T ps_6_8 -E main1 -O3 -spirv -Xclang -verify
+
+// The following code is not legal: both semantics A and B will be lowered
+// into a Location decoration. And mixing implicit and explicit Location
+// assignment is not supported.
+struct S1 {
+ float4 position : A;
+ [[vk::location(3)]] float4 color : B;
+ // expected-error at -1 {{partial explicit stage input location assignment via vk::location(X) unsupported}}
+};
+
+[shader("pixel")]
+float4 main1(S1 p) : SV_Target {
+ return p.position + p.color;
+}
diff --git a/clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl
new file mode 100644
index 0000000000000..1c07941742a4f
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv
+
+struct S0 {
+ uint Idx : SV_DispatchThreadID;
+};
+
+// CHECK: define void @main0()
+// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
+// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
+// CHECK: %[[#TMP:]] = insertvalue %struct.S0 poison, i32 %[[#ID:]], 0
+// CHECK: %[[#ARG:]] = alloca %struct.S0, align 8
+// CHECK: store %struct.S0 %[[#TMP]], ptr %[[#ARG]], align 4
+// CHECK-DXIL: call void @{{.*}}main0{{.*}}(ptr %[[#ARG]])
+// CHECK-SPIRV: call spir_func void @{{.*}}main0{{.*}}(ptr %[[#ARG]])
+[shader("compute")]
+[numthreads(8,8,1)]
+void main0(S0 p) {}
+
+struct S1 {
+ uint a : SV_DispatchThreadID;
+ uint3 b : SV_GroupThreadID;
+};
+
+// CHECK: define void @main1()
+// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
+// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
+// CHECK: %[[#S1A_:]] = insertvalue %struct.S1 poison, i32 %[[#ID:]], 0
+// CHECK-DXIL: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0)
+// CHECK-SPIRV: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 0)
+// CHECK: %[[#ID_X_:]] = insertelement <3 x i32> poison, i32 %[[#ID_X]], i64 0
+// CHECK-DXIL: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1)
+// CHECK-SPIRV: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 1)
+// CHECK: %[[#ID_XY:]] = insertelement <3 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1
+// CHECK-DXIL: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 2)
+// CHECK-SPIRV: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 2)
+// CHECK: %[[#ID_XYZ:]] = insertelement <3 x i32> %[[#ID_XY]], i32 %[[#ID_Z]], i64 2
+// CHECK: %[[#S1AB:]] = insertvalue %struct.S1 %[[#S1A_]], <3 x i32> %[[#ID_XYZ:]], 1
+// CHECK: %[[#ARG:]] = alloca %struct.S1, align 8
+// CHECK: store %struct.S1 %[[#S1AB]], ptr %[[#ARG]], align 1
+// CHECK-DXIL: call void @{{.*}}main1{{.*}}(ptr %[[#ARG]])
+// CHECK-SPIRV: call spir_func void @{{.*}}main1{{.*}}(ptr %[[#ARG]])
+[shader("compute")]
+[numthreads(8,8,1)]
+void main1(S1 p) {}
+
+struct S2C {
+ uint3 b : SV_GroupThreadID;
+};
+
+struct S2 {
+ uint a : SV_DispatchThreadID;
+ S2C child;
+};
+
+// CHECK: define void @main2()
+// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0)
+// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0)
+// CHECK: %[[#S2A_:]] = insertvalue %struct.S2 poison, i32 %[[#ID:]], 0
+
+// CHECK-DXIL: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0)
+// CHECK-SPIRV: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 0)
+// CHECK: %[[#ID_X_:]] = insertelement <3 x i32> poison, i32 %[[#ID_X]], i64 0
+// CHECK-DXIL: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1)
+// CHECK-SPIRV: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 1)
+// CHECK: %[[#ID_XY:]] = insertelement <3 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1
+// CHECK-DXIL: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 2)
+// CHECK-SPIRV: %[[#ID_Z:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 2)
+// CHECK: %[[#ID_XYZ:]] = insertelement <3 x i32> %[[#ID_XY]], i32 %[[#ID_Z]], i64 2
+// CHECK: %[[#S2C:]] = insertvalue %struct.S2C poison, <3 x i32> %[[#ID_XYZ:]], 0
+
+// CHECK: %[[#S2AB:]] = insertvalue %struct.S2 %[[#S2A_]], %struct.S2C %[[#S2V:]], 1
+// CHECK: %[[#ARG:]] = alloca %struct.S2, align 8
+// CHECK: store %struct.S2 %[[#S2AB]], ptr %[[#ARG]], align 1
+// CHECK-DXIL: call void @{{.*}}main2{{.*}}(ptr %[[#ARG]])
+// CHECK-SPIRV: call spir_func void @{{.*}}main2{{.*}}(ptr %[[#ARG]])
+[shader("compute")]
+[numthreads(8,8,1)]
+void main2(S2 p) {}
diff --git a/clang/test/CodeGenHLSL/sret_output.hlsl b/clang/test/CodeGenHLSL/sret_output.hlsl
index eefc9dabab517..de1297ec467dc 100644
--- a/clang/test/CodeGenHLSL/sret_output.hlsl
+++ b/clang/test/CodeGenHLSL/sret_output.hlsl
@@ -1,21 +1,26 @@
-// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \
-// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple spirv-unknown-vulkan1.3-library %s \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV
+
+// CHECK: @SV_TARGET0 = external hidden thread_local addrspace(8) global <4 x float>, !spirv.Decorations !0
-// FIXME: add semantic to a.
-// See https://github.com/llvm/llvm-project/issues/57874
struct S {
- float a;
+ float4 a : SV_Target;
};
-// Make sure sret parameter is generated.
-// CHECK:define internal void @_Z7ps_mainv(ptr dead_on_unwind noalias writable sret(%struct.S) align 1 %agg.result)
-// FIXME: change it to real value instead of poison value once semantic is add to a.
-// Make sure the function with sret is called.
-// CHECK:call void @_Z7ps_mainv(ptr poison)
+// CHECK-SPIRV: define internal spir_func void @_Z7ps_mainv(ptr dead_on_unwind noalias writable sret(%struct.S) align 1 %agg.result)
+// CHECK: %a = getelementptr inbounds nuw %struct.S, ptr %agg.result, i32 0, i32 0
+// CHECK: store <4 x float> zeroinitializer, ptr %a, align 1
+
+// CHECK-SPIRV: define void @ps_main()
+// CHECK: %[[#VAR:]] = alloca %struct.S, align 16
+// CHECK-SPIRV: call spir_func void @_Z7ps_mainv(ptr %[[#VAR]])
+// CHECK: %[[#L1:]] = load %struct.S, ptr %[[#VAR]], align 16
+// CHECK: %[[#L2:]] = extractvalue %struct.S %[[#L1]], 0
+// CHECK: store <4 x float> %[[#L2]], ptr addrspace(8) @SV_TARGET0, align 16
[shader("pixel")]
S ps_main() {
S s;
- s.a = 0;
+ s.a = float4(0.f);
return s;
};
diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index 05693538252aa..f12a6890308b4 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -86,6 +86,7 @@
// CHECK-NEXT: FunctionReturnThunks (SubjectMatchRule_function)
// CHECK-NEXT: GNUInline (SubjectMatchRule_function)
// CHECK-NEXT: HIPManaged (SubjectMatchRule_variable)
+// CHECK-NEXT: HLSLVkLocation (SubjectMatchRule_variable_is_parameter, SubjectMatchRule_field, SubjectMatchRule_function)
// CHECK-NEXT: Hot (SubjectMatchRule_function)
// CHECK-NEXT: HybridPatchable (SubjectMatchRule_function)
// CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance)
diff --git a/clang/test/ParserHLSL/semantic_parsing.hlsl b/clang/test/ParserHLSL/semantic_parsing.hlsl
index 34df1805c5a95..1301c84e0211b 100644
--- a/clang/test/ParserHLSL/semantic_parsing.hlsl
+++ b/clang/test/ParserHLSL/semantic_parsing.hlsl
@@ -3,5 +3,5 @@
// expected-error at +1 {{expected HLSL Semantic identifier}}
void Entry(int GI : ) { }
-// expected-error at +1 {{unknown HLSL semantic 'SV_IWantAPony'}}
+// expected-error at +1 {{unknown HLSL semantic 'SV_IWANTAPONY'}}
void Pony(int GI : SV_IWantAPony) { }
diff --git a/clang/test/SemaHLSL/Semantics/groupindex.hlsl b/clang/test/SemaHLSL/Semantics/groupindex.hlsl
index a33e060c82906..8acdee8e85989 100644
--- a/clang/test/SemaHLSL/Semantics/groupindex.hlsl
+++ b/clang/test/SemaHLSL/Semantics/groupindex.hlsl
@@ -4,26 +4,26 @@
[shader("compute")][numthreads(32,1,1)]
void compute(int GI : SV_GroupIndex) {}
-// expected-error at +2 {{attribute 'SV_GroupIndex' is unsupported in 'pixel' shaders}}
+// expected-error at +2 {{attribute 'SV_GROUPINDEX' is unsupported in 'pixel' shaders}}
[shader("pixel")]
void pixel(int GI : SV_GroupIndex) {}
-// expected-error at +2 {{attribute 'SV_GroupIndex' is unsupported in 'vertex' shaders}}
+// expected-error at +2 {{attribute 'SV_GROUPINDEX' is unsupported in 'vertex' shaders}}
[shader("vertex")]
void vertex(int GI : SV_GroupIndex) {}
-// expected-error at +2 {{attribute 'SV_GroupIndex' is unsupported in 'geometry' shaders}}
+// expected-error at +2 {{attribute 'SV_GROUPINDEX' is unsupported in 'geometry' shaders}}
[shader("geometry")]
void geometry(int GI : SV_GroupIndex) {}
-// expected-error at +2 {{attribute 'SV_GroupIndex' is unsupported in 'domain' shaders}}
+// expected-error at +2 {{attribute 'SV_GROUPINDEX' is unsupported in 'domain' shaders}}
[shader("domain")]
void domain(int GI : SV_GroupIndex) {}
-// expected-error at +2 {{attribute 'SV_GroupIndex' is unsupported in 'amplification' shaders}}
+// expected-error at +2 {{attribute 'SV_GROUPINDEX' is unsupported in 'amplification' shaders}}
[shader("amplification")][numthreads(32,1,1)]
void amplification(int GI : SV_GroupIndex) {}
-// expected-error at +2 {{attribute 'SV_GroupIndex' is unsupported in 'mesh' shaders}}
+// expected-error at +2 {{attribute 'SV_GROUPINDEX' is unsupported in 'mesh' shaders}}
[shader("mesh")][numthreads(32,1,1)]
void mesh(int GI : SV_GroupIndex) {}
diff --git a/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl b/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl
index 1bb4ee5182d62..18bae5ee322df 100644
--- a/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl
+++ b/clang/test/SemaHLSL/Semantics/invalid_entry_parameter.hlsl
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -x hlsl -ast-dump -verify -o - %s
[numthreads(8,8,1)]
-// expected-error at +1 {{attribute 'SV_DispatchThreadID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
+// expected-error at +1 {{attribute 'SV_DISPATCHTHREADID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
void CSMain(float ID : SV_DispatchThreadID) {
}
@@ -11,71 +11,71 @@ struct ST {
float b;
};
[numthreads(8,8,1)]
-// expected-error at +1 {{attribute 'SV_DispatchThreadID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
+// expected-error at +1 {{attribute 'SV_DISPATCHTHREADID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
void CSMain2(ST ID : SV_DispatchThreadID) {
}
void foo() {
-// expected-warning at +1 {{'SV_DispatchThreadID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_DISPATCHTHREADID' attribute only applies to parameters, non-static data members, and functions}}
uint V : SV_DispatchThreadID;
}
struct ST2 {
-// expected-warning at +1 {{'SV_DispatchThreadID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_DISPATCHTHREADID' attribute only applies to parameters, non-static data members, and functions}}
static uint X : SV_DispatchThreadID;
uint s : SV_DispatchThreadID;
};
[numthreads(8,8,1)]
-// expected-error at +1 {{attribute 'SV_GroupID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
+// expected-error at +1 {{attribute 'SV_GROUPID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
void CSMain_GID(float ID : SV_GroupID) {
}
[numthreads(8,8,1)]
-// expected-error at +1 {{attribute 'SV_GroupID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
+// expected-error at +1 {{attribute 'SV_GROUPID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
void CSMain2_GID(ST GID : SV_GroupID) {
}
void foo_GID() {
-// expected-warning at +1 {{'SV_GroupID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_GROUPID' attribute only applies to parameters, non-static data members, and functions}}
uint GIS : SV_GroupID;
}
struct ST2_GID {
-// expected-warning at +1 {{'SV_GroupID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_GROUPID' attribute only applies to parameters, non-static data members, and functions}}
static uint GID : SV_GroupID;
uint s_gid : SV_GroupID;
};
[numthreads(8,8,1)]
-// expected-error at +1 {{attribute 'SV_GroupThreadID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
+// expected-error at +1 {{attribute 'SV_GROUPTHREADID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
void CSMain_GThreadID(float ID : SV_GroupThreadID) {
}
[numthreads(8,8,1)]
-// expected-error at +1 {{attribute 'SV_GroupThreadID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
+// expected-error at +1 {{attribute 'SV_GROUPTHREADID' only applies to a field or parameter of type 'uint/uint2/uint3'}}
void CSMain2_GThreadID(ST GID : SV_GroupThreadID) {
}
void foo_GThreadID() {
-// expected-warning at +1 {{'SV_GroupThreadID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_GROUPTHREADID' attribute only applies to parameters, non-static data members, and functions}}
uint GThreadIS : SV_GroupThreadID;
}
struct ST2_GThreadID {
-// expected-warning at +1 {{'SV_GroupThreadID' attribute only applies to parameters and non-static data members}}
+// expected-warning at +1 {{'SV_GROUPTHREADID' attribute only applies to parameters, non-static data members, and functions}}
static uint GThreadID : SV_GroupThreadID;
uint s_gthreadid : SV_GroupThreadID;
};
[shader("vertex")]
-// expected-error at +4 {{attribute 'SV_GroupIndex' is unsupported in 'vertex' shaders, requires compute}}
-// expected-error at +3 {{attribute 'SV_DispatchThreadID' is unsupported in 'vertex' shaders, requires compute}}
-// expected-error at +2 {{attribute 'SV_GroupID' is unsupported in 'vertex' shaders, requires compute}}
-// expected-error at +1 {{attribute 'SV_GroupThreadID' is unsupported in 'vertex' shaders, requires compute}}
+// expected-error at +4 {{attribute 'SV_GROUPINDEX' is unsupported in 'vertex' shaders, requires compute}}
+// expected-error at +3 {{attribute 'SV_DISPATCHTHREADID' is unsupported in 'vertex' shaders, requires compute}}
+// expected-error at +2 {{attribute 'SV_GROUPID' is unsupported in 'vertex' shaders, requires compute}}
+// expected-error at +1 {{attribute 'SV_GROUPTHREADID' is unsupported in 'vertex' shaders, requires compute}}
void vs_main(int GI : SV_GroupIndex, uint ID : SV_DispatchThreadID, uint GID : SV_GroupID, uint GThreadID : SV_GroupThreadID) {}
diff --git a/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl b/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl
index 124d401a9990c..b57ce4e325ca2 100644
--- a/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl
+++ b/clang/test/SemaHLSL/Semantics/position.ps.size.hlsl
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -finclude-default-header -o - %s -verify -verify-ignore-unexpected
// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-library -x hlsl -finclude-default-header -o - %s -verify -verify-ignore-unexpected
-// expected-error at +1 {{attribute 'SV_Position' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}}
+// expected-error at +1 {{attribute 'SV_POSITION' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}}
void main(vector<float, 5> a : SV_Position) {
}
-// expected-error at +1 {{attribute 'SV_Position' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}}
+// expected-error at +1 {{attribute 'SV_POSITION' only applies to a field or parameter of type 'float/float1/float2/float3/float4'}}
void main(int2 a : SV_Position) {
}
diff --git a/clang/test/SemaHLSL/Semantics/position.vs.hlsl b/clang/test/SemaHLSL/Semantics/position.vs.hlsl
index 19f781fa3757c..e5e8da2484d93 100644
--- a/clang/test/SemaHLSL/Semantics/position.vs.hlsl
+++ b/clang/test/SemaHLSL/Semantics/position.vs.hlsl
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-vertex -x hlsl -finclude-default-header -o - %s -verify
-// expected-error at +1 {{attribute 'SV_Position' is unsupported in 'vertex' shaders, requires pixel}}
+// expected-error at +1 {{attribute 'SV_POSITION' is unsupported in 'vertex' shaders, requires pixel}}
float4 main(float4 a : SV_Position) {
return a;
}
diff --git a/clang/test/SemaHLSL/Semantics/semantics-invalid.hlsl b/clang/test/SemaHLSL/Semantics/semantics-invalid.hlsl
new file mode 100644
index 0000000000000..fdba6f624d289
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/semantics-invalid.hlsl
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -fsyntax-only -hlsl-entry main -verify %s
+
+typedef float t_f : SEMANTIC; // expected-warning{{'SEMANTIC' attribute only applies to parameters, non-static data members, and functions}}
+
+struct semantic_on_struct : SEMANTIC { // expected-error{{expected class name}}
+ float a;
+};
+
+struct s_fields_multiple_semantics {
+ float a : semantic_a : semantic_c; // expected-error{{use of undeclared identifier 'semantic_c'}}
+ float b : semantic_b;
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+ float a : SEM_A; // expected-warning{{'SEM_A' attribute only applies to parameters, non-static data members, and functions}}
+}
diff --git a/clang/test/SemaHLSL/Semantics/semantics-valid.hlsl b/clang/test/SemaHLSL/Semantics/semantics-valid.hlsl
new file mode 100644
index 0000000000000..09fcbae552075
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/semantics-valid.hlsl
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -hlsl-entry CSMain -x hlsl -finclude-default-header -ast-dump -o - %s | FileCheck %s
+
+// FIXME: DXC accepts this.
+#if 0
+struct semantic_on_struct_instance {
+ float a;
+} g_struct : semantic;
+
+#endif
+
+
+struct s_fields {
+ float a : semantic_a;
+ float b : semantic_b;
+// CHECK: |-CXXRecordDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-3]]:8 struct s_fields definition
+// CHECK: | |-FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:9 a 'float'
+// CHECK: | | `-HLSLUserSemanticAttr 0x{{[0-9a-fA-F]+}} <col:13>
+// CHECK: | `-FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:9 b 'float'
+// CHECK: | `-HLSLUserSemanticAttr 0x{{[0-9a-fA-F]+}} <col:13>
+};
+
+float fn_foo1(float a : a, float b : b) : sem_ret { return 1.0f; }
+// CHECK: |-FunctionDecl {{.*}} <{{.*}}> col:7 fn_foo1 'float (float, float)'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} <{{.*}}> col:21 a 'float'
+// CHECK-NEXT: | | `-HLSLUserSemanticAttr {{.*}} <{{.*}}>
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} <{{.*}}> col:34 b 'float'
+// CHECK-NEXT: | | `-HLSLUserSemanticAttr {{.*}} <{{.*}}>
+// CHECK-NEXT: | |-CompoundStmt {{.*}} <{{.*}}>
+// CHECK-NEXT: | | `-ReturnStmt {{.*}} <{{.*}}>
+// CHECK-NEXT: | | `-FloatingLiteral {{.*}} <{{.*}}> 'float' 1.000000e+00
+// CHECK-NEXT: | `-HLSLUserSemanticAttr {{.*}} <{{.*}}>
+float fn_foo2(float a : a, float b : b) : sem_ret : also_ret { return 1.0f; }
+// CHECK: `-FunctionDecl {{.*}} <{{.*}}> col:7 fn_foo2 'float (float, float)'
+// CHECK-NEXT: |-ParmVarDecl {{.*}} <{{.*}}> col:21 a 'float'
+// CHECK-NEXT: | `-HLSLUserSemanticAttr {{.*}} <{{.*}}>
+// CHECK-NEXT: |-ParmVarDecl {{.*}} <{{.*}}> col:34 b 'float'
+// CHECK-NEXT: | `-HLSLUserSemanticAttr {{.*}} <{{.*}}>
+// CHECK-NEXT: |-CompoundStmt {{.*}} <{{.*}}>
+// CHECK-NEXT: | `-ReturnStmt {{.*}} <{{.*}}>
+// CHECK-NEXT: | `-FloatingLiteral {{.*}} <{{.*}}> 'float' 1.000000e+00
+// CHECK-NEXT: |-HLSLUserSemanticAttr {{.*}} <{{.*}}>
+// CHECK-NEXT: `-HLSLUserSemanticAttr {{.*}} <{{.*}}>
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index d63e79a5f5155..c4193110bee01 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -2725,12 +2725,15 @@ static void emitAttributes(const RecordKeeper &Records, raw_ostream &OS,
assert(!Supers.empty() && "Forgot to specify a superclass for the attr");
std::string SuperName;
bool Inheritable = false;
+ bool HLSLSemantic = false;
for (const Record *R : reverse(Supers)) {
if (R->getName() != "TargetSpecificAttr" &&
R->getName() != "DeclOrTypeAttr" && SuperName.empty())
SuperName = R->getName().str();
if (R->getName() == "InheritableAttr")
Inheritable = true;
+ if (R->getName() == "HLSLSemanticAttr")
+ HLSLSemantic = true;
}
if (Header)
@@ -3054,6 +3057,9 @@ static void emitAttributes(const RecordKeeper &Records, raw_ostream &OS,
<< (R.getValueAsBit("InheritEvenIfAlreadyPresent") ? "true"
: "false");
}
+ if (HLSLSemantic) {
+ OS << ", " << (R.getValueAsBit("SemanticIndexable") ? "true" : "false");
+ }
OS << ")\n";
for (auto const &ai : Args) {
@@ -3270,7 +3276,8 @@ static const AttrClassDescriptor AttrClassDescriptors[] = {
{"INHERITABLE_PARAM_ATTR", "InheritableParamAttr"},
{"INHERITABLE_PARAM_OR_STMT_ATTR", "InheritableParamOrStmtAttr"},
{"PARAMETER_ABI_ATTR", "ParameterABIAttr"},
- {"HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"}};
+ {"HLSL_ANNOTATION_ATTR", "HLSLAnnotationAttr"},
+ {"HLSL_SEMANTIC_ATTR", "HLSLSemanticAttr"}};
static void emitDefaultDefine(raw_ostream &OS, StringRef name,
const char *superName) {
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 68b31a899003b..5e98e2df1cd95 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -161,4 +161,15 @@ def int_dx_firstbitshigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0,
def int_dx_firstbitlow : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>;
def int_dx_group_memory_barrier_with_group_sync : DefaultAttrsIntrinsic<[], [], []>;
+
+def int_dx_load_input
+ : DefaultAttrsIntrinsic<[llvm_any_ty],
+ [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i8_ty,
+ llvm_i32_ty],
+ [IntrConvergent]>;
+def int_dx_store_output
+ : DefaultAttrsIntrinsic<[],
+ [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i8_ty,
+ llvm_i32_ty, llvm_any_ty],
+ [IntrConvergent]>;
}
More information about the llvm-commits
mailing list