[clang] [llvm] [HLSL] Implement `reflect` HLSL function (PR #122992)

2025-01-14 Thread Deric Cheung via cfe-commits

https://github.com/Icohedron edited 
https://github.com/llvm/llvm-project/pull/122992
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [HLSL] Implement `reflect` HLSL function (PR #122992)

2025-01-14 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-hlsl

Author: Deric Cheung (Icohedron)


Changes

Fixes #99152

Tasks completed:

- Implement `reflect` in `clang/lib/Headers/hlsl/hlsl_intrinsics.h`
- Implement the `reflect` SPIR-V target built-in in 
`clang/include/clang/Basic/BuiltinsSPIRV.td`
- Add a SPIR-V fast path in `clang/lib/Headers/hlsl/hlsl_detail.h` in the form
 ```c++
#if (__has_builtin(__builtin_spirv_reflect))
  return __builtin_spirv_reflect(...);
 #else
   return ...; // regular behavior
 #endif
 ```
- Add codegen for the SPIR-V `reflect` built-in to `EmitSPIRVBuiltinExpr` in 
`clang/lib/CodeGen/CGBuiltin.cpp`
- Add HLSL codegen tests to `clang/test/CodeGenHLSL/builtins/reflect.hlsl`
- Add SPIR-V built-in codegen tests to 
`clang/test/CodeGenSPIRV/Builtins/reflect.c`
- Add sema tests to `clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl`
- Add SPIR-V sema tests to `clang/test/CodeGenSPIRV/Builtins/reflect-errors.c`
- Create the `int_spv_reflect` intrinsic in 
`llvm/include/llvm/IR/IntrinsicsSPIRV.td`
- In `llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp` create the `reflect` 
lowering and map it to `int_spv_reflect` in 
`SPIRVInstructionSelector::selectIntrinsic`
- Create a SPIR-V backend test case in 
`llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll`

Additional tasks completed:

- Implement sema check for the `reflect` SPIR-V built-in in 
`clang/lib/Sema/SemaSPIRV.cpp`
  - Required for HLSL codegen to work via the SPIR-V fast path, otherwise the 
test  `clang/test/CodeGenHLSL/builtins/reflect.hlsl` outright fails to compile

Incomplete tasks:

- Create SPIR-V backend test case in llvm/test/CodeGen/SPIRV/opencl/reflect.ll
  - I do not think an OpenCL test is applicable in this case because the 
[OpenCL SPIR-V extended instruction 
set](https://registry.khronos.org/SPIR-V/specs/unified1/OpenCL.ExtendedInstructionSet.100.html)
 does not include a `reflect` function

---

Patch is 29.45 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/122992.diff


12 Files Affected:

- (modified) clang/include/clang/Basic/BuiltinsSPIRV.td (+6) 
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+13) 
- (modified) clang/lib/Headers/hlsl/hlsl_detail.h (+17) 
- (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+43) 
- (modified) clang/lib/Sema/SemaSPIRV.cpp (+32) 
- (added) clang/test/CodeGenHLSL/builtins/reflect.hlsl (+195) 
- (added) clang/test/CodeGenSPIRV/Builtins/reflect.c (+32) 
- (added) clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl (+33) 
- (added) clang/test/SemaSPIRV/BuiltIns/reflect-errors.c (+23) 
- (modified) llvm/include/llvm/IR/IntrinsicsSPIRV.td (+1) 
- (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+2) 
- (added) llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll (+33) 


``diff
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td 
b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 1e66939b822ef8..ce00459fc8ede7 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -13,3 +13,9 @@ def SPIRVDistance : Builtin {
   let Attributes = [NoThrow, Const];
   let Prototype = "void(...)";
 }
+
+def SPIRVReflect : Builtin {
+  let Spellings = ["__builtin_spirv_reflect"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 1b25d365932c30..b9e680685b05e0 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20487,6 +20487,19 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned 
BuiltinID,
 /*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_distance,
 ArrayRef{X, Y}, nullptr, "spv.distance");
   }
+  case SPIRV::BI__builtin_spirv_reflect: {
+Value *I = EmitScalarExpr(E->getArg(0));
+Value *N = EmitScalarExpr(E->getArg(1));
+assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+   E->getArg(1)->getType()->hasFloatingRepresentation() &&
+   "Reflect operands must have a float representation");
+assert(E->getArg(0)->getType()->isVectorType() &&
+   E->getArg(1)->getType()->isVectorType() &&
+   "Reflect operands must be a vector");
+return Builder.CreateIntrinsic(
+/*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
+ArrayRef{I, N}, nullptr, "spv.reflect");
+  }
   }
   return nullptr;
 }
diff --git a/clang/lib/Headers/hlsl/hlsl_detail.h 
b/clang/lib/Headers/hlsl/hlsl_detail.h
index 19d83ea5471c7c..624a7b05b56ad0 100644
--- a/clang/lib/Headers/hlsl/hlsl_detail.h
+++ b/clang/lib/Headers/hlsl/hlsl_detail.h
@@ -68,6 +68,23 @@ distance_vec_impl(vector X, vector Y) {
   return length_vec_impl(X - Y);
 #endif
 }
+
+template 
+constexpr enable_if_t::value || is_same::value, T>
+reflect_impl(T I, T N) {
+  return I - 2 * N * I * N;
+}
+
+template 
+constexpr enable_if_t::value || is_same::value, T>
+reflect_vec_impl(vector I, vector N) {
+#if 

[clang] [llvm] [HLSL] Implement `reflect` HLSL function (PR #122992)

2025-01-14 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Deric Cheung (Icohedron)


Changes

Fixes #99152

Tasks completed:

- Implement `reflect` in `clang/lib/Headers/hlsl/hlsl_intrinsics.h`
- Implement the `reflect` SPIR-V target built-in in 
`clang/include/clang/Basic/BuiltinsSPIRV.td`
- Add a SPIR-V fast path in `clang/lib/Headers/hlsl/hlsl_detail.h` in the form
 ```c++
#if (__has_builtin(__builtin_spirv_reflect))
  return __builtin_spirv_reflect(...);
 #else
   return ...; // regular behavior
 #endif
 ```
- Add codegen for the SPIR-V `reflect` built-in to `EmitSPIRVBuiltinExpr` in 
`clang/lib/CodeGen/CGBuiltin.cpp`
- Add HLSL codegen tests to `clang/test/CodeGenHLSL/builtins/reflect.hlsl`
- Add SPIR-V built-in codegen tests to 
`clang/test/CodeGenSPIRV/Builtins/reflect.c`
- Add sema tests to `clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl`
- Add SPIR-V sema tests to `clang/test/CodeGenSPIRV/Builtins/reflect-errors.c`
- Create the `int_spv_reflect` intrinsic in 
`llvm/include/llvm/IR/IntrinsicsSPIRV.td`
- In `llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp` create the `reflect` 
lowering and map it to `int_spv_reflect` in 
`SPIRVInstructionSelector::selectIntrinsic`
- Create a SPIR-V backend test case in 
`llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll`

Additional tasks completed:

- Implement sema check for the `reflect` SPIR-V built-in in 
`clang/lib/Sema/SemaSPIRV.cpp`
  - Required for HLSL codegen to work via the SPIR-V fast path, otherwise the 
test  `clang/test/CodeGenHLSL/builtins/reflect.hlsl` outright fails to compile

Incomplete tasks:

- Create SPIR-V backend test case in llvm/test/CodeGen/SPIRV/opencl/reflect.ll
  - I do not think an OpenCL test is applicable in this case because the 
[OpenCL SPIR-V extended instruction 
set](https://registry.khronos.org/SPIR-V/specs/unified1/OpenCL.ExtendedInstructionSet.100.html)
 does not include a `reflect` function

---

Patch is 29.45 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/122992.diff


12 Files Affected:

- (modified) clang/include/clang/Basic/BuiltinsSPIRV.td (+6) 
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+13) 
- (modified) clang/lib/Headers/hlsl/hlsl_detail.h (+17) 
- (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+43) 
- (modified) clang/lib/Sema/SemaSPIRV.cpp (+32) 
- (added) clang/test/CodeGenHLSL/builtins/reflect.hlsl (+195) 
- (added) clang/test/CodeGenSPIRV/Builtins/reflect.c (+32) 
- (added) clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl (+33) 
- (added) clang/test/SemaSPIRV/BuiltIns/reflect-errors.c (+23) 
- (modified) llvm/include/llvm/IR/IntrinsicsSPIRV.td (+1) 
- (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+2) 
- (added) llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll (+33) 


``diff
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td 
b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 1e66939b822ef8..ce00459fc8ede7 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -13,3 +13,9 @@ def SPIRVDistance : Builtin {
   let Attributes = [NoThrow, Const];
   let Prototype = "void(...)";
 }
+
+def SPIRVReflect : Builtin {
+  let Spellings = ["__builtin_spirv_reflect"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 1b25d365932c30..b9e680685b05e0 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20487,6 +20487,19 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned 
BuiltinID,
 /*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_distance,
 ArrayRef{X, Y}, nullptr, "spv.distance");
   }
+  case SPIRV::BI__builtin_spirv_reflect: {
+Value *I = EmitScalarExpr(E->getArg(0));
+Value *N = EmitScalarExpr(E->getArg(1));
+assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+   E->getArg(1)->getType()->hasFloatingRepresentation() &&
+   "Reflect operands must have a float representation");
+assert(E->getArg(0)->getType()->isVectorType() &&
+   E->getArg(1)->getType()->isVectorType() &&
+   "Reflect operands must be a vector");
+return Builder.CreateIntrinsic(
+/*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
+ArrayRef{I, N}, nullptr, "spv.reflect");
+  }
   }
   return nullptr;
 }
diff --git a/clang/lib/Headers/hlsl/hlsl_detail.h 
b/clang/lib/Headers/hlsl/hlsl_detail.h
index 19d83ea5471c7c..624a7b05b56ad0 100644
--- a/clang/lib/Headers/hlsl/hlsl_detail.h
+++ b/clang/lib/Headers/hlsl/hlsl_detail.h
@@ -68,6 +68,23 @@ distance_vec_impl(vector X, vector Y) {
   return length_vec_impl(X - Y);
 #endif
 }
+
+template 
+constexpr enable_if_t::value || is_same::value, T>
+reflect_impl(T I, T N) {
+  return I - 2 * N * I * N;
+}
+
+template 
+constexpr enable_if_t::value || is_same::value, T>
+reflect_vec_impl(vector I, vector N) {
+#if 

[clang] [llvm] [HLSL] Implement `reflect` HLSL function (PR #122992)

2025-01-14 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-codegen

Author: Deric Cheung (Icohedron)


Changes

Fixes #99152

Tasks completed:

- Implement `reflect` in `clang/lib/Headers/hlsl/hlsl_intrinsics.h`
- Implement the `reflect` SPIR-V target built-in in 
`clang/include/clang/Basic/BuiltinsSPIRV.td`
- Add a SPIR-V fast path in `clang/lib/Headers/hlsl/hlsl_detail.h` in the form
 ```c++
#if (__has_builtin(__builtin_spirv_reflect))
  return __builtin_spirv_reflect(...);
 #else
   return ...; // regular behavior
 #endif
 ```
- Add codegen for the SPIR-V `reflect` built-in to `EmitSPIRVBuiltinExpr` in 
`clang/lib/CodeGen/CGBuiltin.cpp`
- Add HLSL codegen tests to `clang/test/CodeGenHLSL/builtins/reflect.hlsl`
- Add SPIR-V built-in codegen tests to 
`clang/test/CodeGenSPIRV/Builtins/reflect.c`
- Add sema tests to `clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl`
- Add SPIR-V sema tests to `clang/test/CodeGenSPIRV/Builtins/reflect-errors.c`
- Create the `int_spv_reflect` intrinsic in 
`llvm/include/llvm/IR/IntrinsicsSPIRV.td`
- In `llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp` create the `reflect` 
lowering and map it to `int_spv_reflect` in 
`SPIRVInstructionSelector::selectIntrinsic`
- Create a SPIR-V backend test case in 
`llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll`

Additional tasks completed:

- Implement sema check for the `reflect` SPIR-V built-in in 
`clang/lib/Sema/SemaSPIRV.cpp`
  - Required for HLSL codegen to work via the SPIR-V fast path, otherwise the 
test  `clang/test/CodeGenHLSL/builtins/reflect.hlsl` outright fails to compile

Incomplete tasks:

- Create SPIR-V backend test case in llvm/test/CodeGen/SPIRV/opencl/reflect.ll
  - I do not think an OpenCL test is applicable in this case because the 
[OpenCL SPIR-V extended instruction 
set](https://registry.khronos.org/SPIR-V/specs/unified1/OpenCL.ExtendedInstructionSet.100.html)
 does not include a `reflect` function

---

Patch is 29.45 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/122992.diff


12 Files Affected:

- (modified) clang/include/clang/Basic/BuiltinsSPIRV.td (+6) 
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+13) 
- (modified) clang/lib/Headers/hlsl/hlsl_detail.h (+17) 
- (modified) clang/lib/Headers/hlsl/hlsl_intrinsics.h (+43) 
- (modified) clang/lib/Sema/SemaSPIRV.cpp (+32) 
- (added) clang/test/CodeGenHLSL/builtins/reflect.hlsl (+195) 
- (added) clang/test/CodeGenSPIRV/Builtins/reflect.c (+32) 
- (added) clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl (+33) 
- (added) clang/test/SemaSPIRV/BuiltIns/reflect-errors.c (+23) 
- (modified) llvm/include/llvm/IR/IntrinsicsSPIRV.td (+1) 
- (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+2) 
- (added) llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll (+33) 


``diff
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td 
b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 1e66939b822ef8..ce00459fc8ede7 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -13,3 +13,9 @@ def SPIRVDistance : Builtin {
   let Attributes = [NoThrow, Const];
   let Prototype = "void(...)";
 }
+
+def SPIRVReflect : Builtin {
+  let Spellings = ["__builtin_spirv_reflect"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 1b25d365932c30..b9e680685b05e0 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20487,6 +20487,19 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned 
BuiltinID,
 /*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_distance,
 ArrayRef{X, Y}, nullptr, "spv.distance");
   }
+  case SPIRV::BI__builtin_spirv_reflect: {
+Value *I = EmitScalarExpr(E->getArg(0));
+Value *N = EmitScalarExpr(E->getArg(1));
+assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+   E->getArg(1)->getType()->hasFloatingRepresentation() &&
+   "Reflect operands must have a float representation");
+assert(E->getArg(0)->getType()->isVectorType() &&
+   E->getArg(1)->getType()->isVectorType() &&
+   "Reflect operands must be a vector");
+return Builder.CreateIntrinsic(
+/*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
+ArrayRef{I, N}, nullptr, "spv.reflect");
+  }
   }
   return nullptr;
 }
diff --git a/clang/lib/Headers/hlsl/hlsl_detail.h 
b/clang/lib/Headers/hlsl/hlsl_detail.h
index 19d83ea5471c7c..624a7b05b56ad0 100644
--- a/clang/lib/Headers/hlsl/hlsl_detail.h
+++ b/clang/lib/Headers/hlsl/hlsl_detail.h
@@ -68,6 +68,23 @@ distance_vec_impl(vector X, vector Y) {
   return length_vec_impl(X - Y);
 #endif
 }
+
+template 
+constexpr enable_if_t::value || is_same::value, T>
+reflect_impl(T I, T N) {
+  return I - 2 * N * I * N;
+}
+
+template 
+constexpr enable_if_t::value || is_same::value, T>
+reflect_vec_impl(vector I, vector N) {
+#if 

[clang] [llvm] [HLSL] Implement `reflect` HLSL function (PR #122992)

2025-01-14 Thread Deric Cheung via cfe-commits

https://github.com/Icohedron created 
https://github.com/llvm/llvm-project/pull/122992

Fixes #99152

Tasks completed:

- Implement `reflect` in `clang/lib/Headers/hlsl/hlsl_intrinsics.h`
- Implement the `reflect` SPIR-V target built-in in 
`clang/include/clang/Basic/BuiltinsSPIRV.td`
- Add a SPIR-V fast path in `clang/lib/Headers/hlsl/hlsl_detail.h` in the form
 ```c++
#if (__has_builtin(__builtin_spirv_reflect))
  return __builtin_spirv_reflect(...);
 #else
   return ...; // regular behavior
 #endif
 ```
- Add codegen for the SPIR-V `reflect` built-in to `EmitSPIRVBuiltinExpr` in 
`clang/lib/CodeGen/CGBuiltin.cpp`
- Add HLSL codegen tests to `clang/test/CodeGenHLSL/builtins/reflect.hlsl`
- Add SPIR-V built-in codegen tests to 
`clang/test/CodeGenSPIRV/Builtins/reflect.c`
- Add sema tests to `clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl`
- Add SPIR-V sema tests to `clang/test/CodeGenSPIRV/Builtins/reflect-errors.c`
- Create the `int_spv_reflect` intrinsic in 
`llvm/include/llvm/IR/IntrinsicsSPIRV.td`
- In `llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp` create the `reflect` 
lowering and map it to `int_spv_reflect` in 
`SPIRVInstructionSelector::selectIntrinsic`
- Create a SPIR-V backend test case in 
`llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll`

Additional tasks completed:

- Implement sema check for the `reflect` SPIR-V built-in in 
`clang/lib/Sema/SemaSPIRV.cpp`
  - Required for HLSL codegen to work via the SPIR-V fast path, otherwise the 
test  `clang/test/CodeGenHLSL/builtins/reflect.hlsl` outright fails to compile

Incomplete tasks:

- Create SPIR-V backend test case in llvm/test/CodeGen/SPIRV/opencl/reflect.ll
  - I do not think an OpenCL test is applicable in this case because the 
[OpenCL SPIR-V extended instruction 
set](https://registry.khronos.org/SPIR-V/specs/unified1/OpenCL.ExtendedInstructionSet.100.html)
 does not include a `reflect` function

>From 3f3b8c75c14bb9b3ed611c9cddec49d0e9339705 Mon Sep 17 00:00:00 2001
From: Icohedron 
Date: Mon, 13 Jan 2025 21:23:31 +
Subject: [PATCH] Implement `reflect` HLSL function

---
 clang/include/clang/Basic/BuiltinsSPIRV.td|   6 +
 clang/lib/CodeGen/CGBuiltin.cpp   |  13 ++
 clang/lib/Headers/hlsl/hlsl_detail.h  |  17 ++
 clang/lib/Headers/hlsl/hlsl_intrinsics.h  |  43 
 clang/lib/Sema/SemaSPIRV.cpp  |  32 +++
 clang/test/CodeGenHLSL/builtins/reflect.hlsl  | 195 ++
 clang/test/CodeGenSPIRV/Builtins/reflect.c|  32 +++
 .../SemaHLSL/BuiltIns/reflect-errors.hlsl |  33 +++
 .../test/SemaSPIRV/BuiltIns/reflect-errors.c  |  23 +++
 llvm/include/llvm/IR/IntrinsicsSPIRV.td   |   1 +
 .../Target/SPIRV/SPIRVInstructionSelector.cpp |   2 +
 .../CodeGen/SPIRV/hlsl-intrinsics/reflect.ll  |  33 +++
 12 files changed, 430 insertions(+)
 create mode 100644 clang/test/CodeGenHLSL/builtins/reflect.hlsl
 create mode 100644 clang/test/CodeGenSPIRV/Builtins/reflect.c
 create mode 100644 clang/test/SemaHLSL/BuiltIns/reflect-errors.hlsl
 create mode 100644 clang/test/SemaSPIRV/BuiltIns/reflect-errors.c
 create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reflect.ll

diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td 
b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 1e66939b822ef8..ce00459fc8ede7 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -13,3 +13,9 @@ def SPIRVDistance : Builtin {
   let Attributes = [NoThrow, Const];
   let Prototype = "void(...)";
 }
+
+def SPIRVReflect : Builtin {
+  let Spellings = ["__builtin_spirv_reflect"];
+  let Attributes = [NoThrow, Const];
+  let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 1b25d365932c30..b9e680685b05e0 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20487,6 +20487,19 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned 
BuiltinID,
 /*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_distance,
 ArrayRef{X, Y}, nullptr, "spv.distance");
   }
+  case SPIRV::BI__builtin_spirv_reflect: {
+Value *I = EmitScalarExpr(E->getArg(0));
+Value *N = EmitScalarExpr(E->getArg(1));
+assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+   E->getArg(1)->getType()->hasFloatingRepresentation() &&
+   "Reflect operands must have a float representation");
+assert(E->getArg(0)->getType()->isVectorType() &&
+   E->getArg(1)->getType()->isVectorType() &&
+   "Reflect operands must be a vector");
+return Builder.CreateIntrinsic(
+/*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
+ArrayRef{I, N}, nullptr, "spv.reflect");
+  }
   }
   return nullptr;
 }
diff --git a/clang/lib/Headers/hlsl/hlsl_detail.h 
b/clang/lib/Headers/hlsl/hlsl_detail.h
index 19d83ea5471c7c..624a7b05b56ad0 100644
--- a/clang/lib/Headers/hlsl/hlsl_detail.h
+++