[clang] 788b2bd - [HLSL][Clang] Support SV_VertexID semantic (#184640)

via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 12 01:41:20 PDT 2026


Author: Nathan Gauër
Date: 2026-03-12T09:41:16+01:00
New Revision: 788b2bde7b31615fd22c906b1acf2ba2072acf6b

URL: https://github.com/llvm/llvm-project/commit/788b2bde7b31615fd22c906b1acf2ba2072acf6b
DIFF: https://github.com/llvm/llvm-project/commit/788b2bde7b31615fd22c906b1acf2ba2072acf6b.diff

LOG: [HLSL][Clang] Support SV_VertexID semantic (#184640)

VertexID semantic only allows uint as type. Looking at DXC, it seems the
uint16 variant is allowed, but that's not documented. Until we figure
out the real behavior, we restrict the type to only uint.

Added: 
    clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl
    clang/test/SemaHLSL/Semantics/vertexid.ps.hlsl
    clang/test/SemaHLSL/Semantics/vertexid.vs.hlsl

Modified: 
    clang/lib/CodeGen/CGHLSLRuntime.cpp
    clang/lib/Sema/SemaHLSL.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index b695d016c0524..2578157395b45 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -762,6 +762,17 @@ llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad(
     }
   }
 
+  if (SemanticName == "SV_VERTEXID") {
+    if (ST == Triple::EnvironmentType::Vertex) {
+      if (CGM.getTarget().getTriple().isSPIRV())
+        return createSPIRVBuiltinLoad(B, CGM.getModule(), Type,
+                                      Semantic->getAttrName()->getName(),
+                                      /* BuiltIn::VertexIndex */ 42);
+      else
+        return emitDXILUserSemanticLoad(B, Type, Semantic, Index);
+    }
+  }
+
   llvm_unreachable(
       "Load hasn't been implemented yet for this system semantic. FIXME");
 }

diff  --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 256fcb2da3947..413c602febf51 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -821,6 +821,8 @@ static bool isVkPipelineBuiltin(const ASTContext &AstContext, FunctionDecl *FD,
     return (ST == llvm::Triple::Vertex && !IsInput) ||
            (ST == llvm::Triple::Pixel && IsInput);
   }
+  if (SemanticName == "SV_VERTEXID")
+    return true;
 
   return false;
 }
@@ -1042,6 +1044,11 @@ void SemaHLSL::checkSemanticAnnotation(
                                    {llvm::Triple::Pixel, IOType::In}});
     return;
   }
+  if (SemanticName == "SV_VERTEXID") {
+    diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
+                                  {{llvm::Triple::Vertex, IOType::In}});
+    return;
+  }
 
   if (SemanticName == "SV_TARGET") {
     diagnoseSemanticStageMismatch(SemanticAttr, ST, SC.CurrentIOType,
@@ -1926,6 +1933,14 @@ void SemaHLSL::diagnoseSystemSemanticAttr(Decl *D, const ParsedAttr &AL,
     return;
   }
 
+  if (SemanticName == "SV_VERTEXID") {
+    uint64_t SizeInBits = SemaRef.Context.getTypeSize(ValueType);
+    if (!ValueType->isUnsignedIntegerType() || SizeInBits != 32)
+      Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) << AL << "uint";
+    D->addAttr(createSemanticAttr<HLSLParsedSemanticAttr>(AL, Index));
+    return;
+  }
+
   if (SemanticName == "SV_TARGET") {
     const auto *VT = ValueType->getAs<VectorType>();
     if (!ValueType->hasFloatingRepresentation() ||

diff  --git a/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl b/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl
new file mode 100644
index 0000000000000..e2c184ac7948c
--- /dev/null
+++ b/clang/test/CodeGenHLSL/semantics/SV_VertexID.vs.hlsl
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple dxil-unknown-shadermodel6.8-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck --check-prefix=CHECK-DXIL %s
+// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck --check-prefix=CHECK-SPIRV  %s
+
+// CHECK-SPIRV: @SV_VertexID = external hidden thread_local addrspace(7) externally_initialized constant i32, !spirv.Decorations ![[#MD_0:]]
+
+// CHECK: define void @main() {{.*}} {
+uint main(uint id : SV_VertexID) : A {
+  // CHECK-SPIRV: %[[#P:]] = load i32, ptr addrspace(7) @SV_VertexID, align 4
+  // CHECK-SPIRV:   %[[#]] = call spir_func i32 @_Z4mainj(i32 %[[#P]])
+
+  // CHECK-DXIL: %SV_VertexID0 = call i32 @llvm.dx.load.input.i32(i32 4, i32 0, i32 0, i8 0, i32 poison)
+  // CHECK-DXIL:        %[[#]] = call i32 @_Z4mainj(i32 %SV_VertexID0)
+  return id;
+}
+
+// CHECK-SPIRV-DAG: ![[#MD_0]] = !{![[#MD_1:]]}
+// CHECK-SPIRV-DAG: ![[#MD_1]] = !{i32 11, i32 42}
+//                                      |       `-> BuiltIn VertexIndex
+//                                      `-> SPIR-V decoration 'BuiltIn'

diff  --git a/clang/test/SemaHLSL/Semantics/vertexid.ps.hlsl b/clang/test/SemaHLSL/Semantics/vertexid.ps.hlsl
new file mode 100644
index 0000000000000..d205e099149cb
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/vertexid.ps.hlsl
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-pixel -finclude-default-header -x hlsl -verify -o - %s
+// RUN: %clang_cc1 -triple spirv-pc-vulkan1.3-pixel -finclude-default-header -x hlsl -verify -o - %s
+
+float4 main(uint id : SV_VertexID) : SV_Target {
+// expected-error at -1 {{attribute 'SV_VertexID' is unsupported in 'pixel' shaders, requires vertex}}
+  return float4(1, 1, 1, 1);
+}
+
+

diff  --git a/clang/test/SemaHLSL/Semantics/vertexid.vs.hlsl b/clang/test/SemaHLSL/Semantics/vertexid.vs.hlsl
new file mode 100644
index 0000000000000..e3e52db700455
--- /dev/null
+++ b/clang/test/SemaHLSL/Semantics/vertexid.vs.hlsl
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -fnative-half-type -fnative-int16-type -triple dxil-pc-shadermodel6.3-vertex -finclude-default-header -x hlsl -verify -o - %s
+// RUN: %clang_cc1 -fnative-half-type -fnative-int16-type -triple spirv-pc-vulkan1.3-vertex -finclude-default-header -x hlsl -verify -o - %s
+
+float bad_type_float(float id : SV_VertexID) : A {
+// expected-error at -1 {{attribute 'SV_VertexID' only applies to a field or parameter of type 'uint'}}
+  return id;
+}
+
+uint3 bad_type_vector(uint3 id : SV_VertexID) : A {
+// expected-error at -1 {{attribute 'SV_VertexID' only applies to a field or parameter of type 'uint'}}
+  return id;
+}
+
+int bad_type_signed(int id : SV_VertexID) : A {
+// expected-error at -1 {{attribute 'SV_VertexID' only applies to a field or parameter of type 'uint'}}
+  return id;
+}
+
+uint64_t bad_type_size(uint64_t id : SV_VertexID) : A {
+// expected-error at -1 {{attribute 'SV_VertexID' only applies to a field or parameter of type 'uint'}}
+  return id;
+}
+
+uint32_t ok(uint32_t id : SV_VertexID) : A {
+  return id;
+}
+
+uint16_t bad_type_size_2(uint16_t id : SV_VertexID) : A {
+// expected-error at -1 {{attribute 'SV_VertexID' only applies to a field or parameter of type 'uint'}}
+  return id;
+}
+
+char bad_type_size_2(char id : SV_VertexID) : A {
+// expected-error at -1 {{attribute 'SV_VertexID' only applies to a field or parameter of type 'uint'}}
+  return id;
+}


        


More information about the cfe-commits mailing list