[clang] [llvm] [HLSL] Move `normalize` implementation to header files (PR #216228)

Kaitlin Peng via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 17 06:25:35 PDT 2026


https://github.com/kmpeng updated https://github.com/llvm/llvm-project/pull/216228

>From 02c5c0955b27aea6ea25f9b554314a39eddfa85f Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Thu, 13 Aug 2026 18:49:05 -0700
Subject: [PATCH 1/2] move `normalize` implementation + add spirv builtin

---
 clang/include/clang/Basic/Builtins.td         |   6 -
 .../clang/Basic/BuiltinsSPIRVCommon.td        |   1 +
 clang/include/clang/Basic/HLSLIntrinsics.td   |   3 +-
 clang/lib/CodeGen/CGHLSLBuiltins.cpp          |  11 -
 clang/lib/CodeGen/CGHLSLRuntime.h             |   1 -
 clang/lib/CodeGen/TargetBuiltins/SPIR.cpp     |   8 +
 .../lib/Headers/hlsl/hlsl_intrinsic_helpers.h |   8 +
 clang/lib/Sema/SemaHLSL.cpp                   |  12 -
 clang/lib/Sema/SemaSPIRV.cpp                  |  17 ++
 .../builtins/normalize-builtin.hlsl           |  16 -
 .../builtins/normalize-overloads.hlsl         | 278 ++++++++++++------
 .../test/CodeGenHLSL/builtins/normalize.hlsl  | 115 +++++---
 clang/test/CodeGenSPIRV/Builtins/normalize.c  |  41 +++
 .../SemaHLSL/BuiltIns/normalize-errors.hlsl   |  31 --
 .../SemaSPIRV/BuiltIns/normalize-errors.c     |  23 ++
 llvm/include/llvm/IR/IntrinsicsDirectX.td     |   1 -
 .../Target/DirectX/DXILIntrinsicExpansion.cpp |  41 ---
 llvm/test/CodeGen/DirectX/normalize.ll        | 112 -------
 llvm/test/CodeGen/DirectX/normalize_error.ll  |  10 -
 .../SPIRV/hlsl-intrinsics/normalize.ll        |  20 ++
 llvm/test/CodeGen/SPIRV/opencl/normalize.ll   |  52 ++++
 21 files changed, 429 insertions(+), 378 deletions(-)
 delete mode 100644 clang/test/CodeGenHLSL/builtins/normalize-builtin.hlsl
 create mode 100644 clang/test/CodeGenSPIRV/Builtins/normalize.c
 delete mode 100644 clang/test/SemaHLSL/BuiltIns/normalize-errors.hlsl
 create mode 100644 clang/test/SemaSPIRV/BuiltIns/normalize-errors.c
 delete mode 100644 llvm/test/CodeGen/DirectX/normalize.ll
 delete mode 100644 llvm/test/CodeGen/DirectX/normalize_error.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/opencl/normalize.ll

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 88aa8aee01e4b..9f7aa9bdb9571 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5713,12 +5713,6 @@ def HLSLMul : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void(...)";
 }
 
-def HLSLNormalize : LangBuiltin<"HLSL_LANG"> {
-  let Spellings = ["__builtin_hlsl_normalize"];
-  let Attributes = [NoThrow, Const, CustomTypeChecking];
-  let Prototype = "void(...)";
-}
-
 def HLSLTranspose : LangBuiltin<"HLSL_LANG"> {
   let Spellings = ["__builtin_hlsl_transpose"];
   let Attributes = [NoThrow, Const, CustomTypeChecking];
diff --git a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
index 448223a176ab4..91ad12599971f 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
@@ -20,6 +20,7 @@ def subgroup_local_invocation_id : SPIRVBuiltin<"uint32_t()", [NoThrow, Const]>;
 
 def distance : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
 def length : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
+def normalize : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
 def smoothstep : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
 
 def group_barrier : SPIRVBuiltin<"void()", [NoThrow]>;
diff --git a/clang/include/clang/Basic/HLSLIntrinsics.td b/clang/include/clang/Basic/HLSLIntrinsics.td
index fa5cb896e795a..91a542cf269e8 100644
--- a/clang/include/clang/Basic/HLSLIntrinsics.td
+++ b/clang/include/clang/Basic/HLSLIntrinsics.td
@@ -1284,7 +1284,7 @@ The return value is the \a I parameter.
 }
 
 // Returns the normalized unit vector of the specified floating-point vector.
-def hlsl_normalize : HLSLOneArgBuiltin<"normalize", "__builtin_hlsl_normalize"> {
+def hlsl_normalize : HLSLOneArgDetail<"normalize", "normalize_impl"> {
   let Doc = [{
 \fn T normalize(T x)
 \brief Returns the normalized unit vector of the specified floating-point
@@ -1293,6 +1293,7 @@ vector.
 
 Normalize is based on the following formula: x / length(x).
 }];
+  let ParamNames = ["x"];
   let VaryingTypes = [HalfTy, FloatTy];
   let VaryingMatDims = [];
 }
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 83c0bb2ac684b..38c2b58cea0c6 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -1137,17 +1137,6 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
         CGM.getHLSLRuntime().getFirstBitLowIntrinsic(), ArrayRef<Value *>{X},
         nullptr, "hlsl.firstbitlow");
   }
-  case Builtin::BI__builtin_hlsl_normalize: {
-    Value *X = EmitScalarExpr(E->getArg(0));
-
-    assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
-           "normalize operand must have a float representation");
-
-    return Builder.CreateIntrinsic(
-        /*ReturnType=*/X->getType(),
-        CGM.getHLSLRuntime().getNormalizeIntrinsic(), ArrayRef<Value *>{X},
-        nullptr, "hlsl.normalize");
-  }
   case Builtin::BI__builtin_hlsl_elementwise_f16tof32: {
     return handleElementwiseF16ToF32(*this, E);
   }
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 0b282f19cfcbc..a4ac00893c532 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -128,7 +128,6 @@ class CGHLSLRuntime {
                                    flattened_thread_id_in_group)
   GENERATE_HLSL_INTRINSIC_FUNCTION(IsInf, isinf)
   GENERATE_HLSL_INTRINSIC_FUNCTION(IsNaN, isnan)
-  GENERATE_HLSL_INTRINSIC_FUNCTION(Normalize, normalize)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Rsqrt, rsqrt)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Saturate, saturate)
   GENERATE_HLSL_INTRINSIC_FUNCTION(Sign, sign)
diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
index b2732e2ae674e..66f22d28e2a13 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
@@ -45,6 +45,14 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
         /*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_length,
         ArrayRef<Value *>{X}, nullptr, "spv.length");
   }
+  case SPIRV::BI__builtin_spirv_normalize: {
+    Value *X = EmitScalarExpr(E->getArg(0));
+    assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+           "normalize operand must have a float representation");
+    return Builder.CreateIntrinsic(
+        /*ReturnType=*/X->getType(), Intrinsic::spv_normalize,
+        ArrayRef<Value *>{X}, nullptr, "spv.normalize");
+  }
   case SPIRV::BI__builtin_spirv_reflect: {
     Value *I = EmitScalarExpr(E->getArg(0));
     Value *N = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 977059a9fdae0..6d941231971c8 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -28,6 +28,14 @@ length_impl(vector<T, N> X) {
 #endif
 }
 
+template <typename T> constexpr T normalize_impl(T X) {
+#if (__has_builtin(__builtin_spirv_normalize))
+  return __builtin_spirv_normalize(X);
+#else
+  return X * rsqrt(dot(X, X));
+#endif
+}
+
 constexpr float dot2add_impl(half2 a, half2 b, float c) {
 #if (__has_builtin(__builtin_dx_dot2add))
   return __builtin_dx_dot2add(a, b, c);
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 184339044e5bf..7eca8cae1f27e 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -4514,18 +4514,6 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
     TheCall->setType(RetTy);
     break;
   }
-  case Builtin::BI__builtin_hlsl_normalize: {
-    if (SemaRef.checkArgCount(TheCall, 1))
-      return true;
-    if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
-                                   CheckFloatOrHalfRepresentation))
-      return true;
-    ExprResult A = TheCall->getArg(0);
-    QualType ArgTyA = A.get()->getType();
-    // return type is the same as the input type
-    TheCall->setType(ArgTyA);
-    break;
-  }
   case Builtin::BI__builtin_elementwise_fma: {
     if (SemaRef.checkArgCount(TheCall, 3) ||
         CheckAllArgsHaveSameType(&SemaRef, TheCall)) {
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index 8c2af5053bde2..7c1abcad17ac3 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -246,6 +246,23 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI,
     TheCall->setType(RetTy);
     break;
   }
+  case SPIRV::BI__builtin_spirv_normalize: {
+    if (SemaRef.checkArgCount(TheCall, 1))
+      return true;
+
+    ExprResult A = TheCall->getArg(0);
+    QualType ArgTyA = A.get()->getType();
+    if (!ArgTyA->hasFloatingRepresentation()) {
+      SemaRef.Diag(A.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+          << /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
+          << /* fp */ 1 << ArgTyA;
+      return true;
+    }
+
+    QualType RetTy = ArgTyA;
+    TheCall->setType(RetTy);
+    break;
+  }
   case SPIRV::BI__builtin_spirv_reflect: {
     if (SemaRef.checkArgCount(TheCall, 2))
       return true;
diff --git a/clang/test/CodeGenHLSL/builtins/normalize-builtin.hlsl b/clang/test/CodeGenHLSL/builtins/normalize-builtin.hlsl
deleted file mode 100644
index 46bfb44c9b2a1..0000000000000
--- a/clang/test/CodeGenHLSL/builtins/normalize-builtin.hlsl
+++ /dev/null
@@ -1,16 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -fnative-int16-type -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-
-// CHECK-LABEL: builtin_normalize_half
-// CHECK: %hlsl.normalize = call reassoc nnan ninf nsz arcp afn half @llvm.dx.normalize.f16(half %{{.*}})
-// CHECK: ret half  %hlsl.normalize
-half builtin_normalize_half(half p0) {
-  return __builtin_hlsl_normalize(p0);
-}
-
-// CHECK-LABEL: builtin_normalize_float
-// CHECK: %hlsl.normalize = call reassoc nnan ninf nsz arcp afn float @llvm.dx.normalize.f32(float %{{.*}})
-// CHECK: ret float  %hlsl.normalize
-float builtin_normalize_float (float p0) {
-  return __builtin_hlsl_normalize(p0);
-}
diff --git a/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl
index 8ed3ff26529d6..2256621892f04 100644
--- a/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl
@@ -1,199 +1,299 @@
 // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \
 // RUN:   dxil-pc-shadermodel6.3-library %s -emit-llvm \
-// RUN:   -Wdeprecated-declarations -o - | FileCheck %s --check-prefixes=CHECK \
-// RUN:   -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx
+// RUN:   -Wdeprecated-declarations -o - | FileCheck %s --check-prefixes=CHECK,DXCHECK
 // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple \
 // RUN:   spirv-unknown-vulkan-library %s -emit-llvm \
-// RUN:   -Wdeprecated-declarations -o - | FileCheck %s --check-prefixes=CHECK \
-// RUN:   -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv
+// RUN:   -Wdeprecated-declarations -o - | FileCheck %s --check-prefixes=CHECK,SPVCHECK
 // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s  \
 // RUN:   -verify -verify-ignore-unexpected=note
 // RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -x hlsl -triple spirv-unknown-vulkan-library %s  \
 // RUN:   -verify -verify-ignore-unexpected=note
 
-// CHECK: define [[FNATTRS]] float @_Z21test_normalize_doubled(
-// CHECK:    [[CONVI:%.*]] = fptrunc {{.*}} double %{{.*}} to float
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} float @llvm.[[TARGET]].normalize.f32(float [[CONVI]])
-// CHECK:    ret float [[HLSLNORMALIZEI]]
+// CHECK-LABEL: test_normalize_double
+// CHECK: [[CONVI:%.*]] = fptrunc {{.*}} double %{{.*}} to float
+// DXCHECK: [[MUL:%.*]] = fmul {{.*}} float %{{.*}}, %{{.*}}
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[MUL]])
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} float %{{.*}}, [[RSQRT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK-NEXT: ret float [[RET]]
 float test_normalize_double(double p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x 64 bit API lowering for normalize is deprecated. Explicitly cast parameters to 32 or 16 bit types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <2 x float> @_Z22test_normalize_double2Dv2_d(
-// CHECK:    [[CONVI:%.*]] = fptrunc {{.*}} <2 x double> %{{.*}} to <2 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <2 x float> @llvm.[[TARGET]].normalize.v2f32(<2 x float> [[CONVI]])
-// CHECK:    ret <2 x float> [[HLSLNORMALIZEI]]
+
+// CHECK-LABEL: test_normalize_double2
+// CHECK: [[CONVI:%.*]] = fptrunc {{.*}} <2 x double> %{{.*}} to <2 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_double2(double2 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x 64 bit API lowering for normalize is deprecated. Explicitly cast parameters to 32 or 16 bit types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <3 x float> @_Z22test_normalize_double3Dv3_d(
-// CHECK:    [[CONVI:%.*]] = fptrunc {{.*}} <3 x double> %{{.*}} to <3 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <3 x float> @llvm.[[TARGET]].normalize.v3f32(<3 x float> [[CONVI]])
-// CHECK:    ret <3 x float> [[HLSLNORMALIZEI]]
+
+// CHECK-LABEL: test_normalize_double3
+// CHECK: [[CONVI:%.*]] = fptrunc {{.*}} <3 x double> %{{.*}} to <3 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_double3(double3 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x 64 bit API lowering for normalize is deprecated. Explicitly cast parameters to 32 or 16 bit types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <4 x float> @_Z19test_length_double4Dv4_d(
-// CHECK:    [[CONVI:%.*]] = fptrunc {{.*}} <4 x double> %{{.*}} to <4 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <4 x float> @llvm.[[TARGET]].normalize.v4f32(<4 x float> [[CONVI]])
-// CHECK:    ret <4 x float> [[HLSLNORMALIZEI]]
-float4 test_length_double4(double4 p0)
+
+// CHECK-LABEL: test_normalize_double4
+// CHECK: [[CONVI:%.*]] = fptrunc {{.*}} <4 x double> %{{.*}} to <4 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: ret <4 x float> [[RET]]
+float4 test_normalize_double4(double4 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x 64 bit API lowering for normalize is deprecated. Explicitly cast parameters to 32 or 16 bit types.}}
     return normalize(p0);
 }
 
-// CHECK: define [[FNATTRS]] float @_Z18test_normalize_inti(
-// CHECK:    [[CONVI:%.*]] = sitofp {{.*}} i32 %{{.*}} to float
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} float @llvm.[[TARGET]].normalize.f32(float [[CONVI]])
-// CHECK:    ret float [[HLSLNORMALIZEI]]
+// CHECK-LABEL: test_normalize_int
+// CHECK: [[CONVI:%.*]] = sitofp {{.*}} i32 %{{.*}} to float
+// DXCHECK: [[MUL:%.*]] = fmul {{.*}} float %{{.*}}, %{{.*}}
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[MUL]])
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} float %{{.*}}, [[RSQRT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK-NEXT: ret float [[RET]]
 float test_normalize_int(int p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <2 x float> @_Z19test_normalize_int2Dv2_i(
-// CHECK:    [[CONVI:%.*]] = sitofp {{.*}} <2 x i32> %{{.*}} to <2 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <2 x float> @llvm.[[TARGET]].normalize.v2f32(<2 x float> [[CONVI]])
-// CHECK:    ret <2 x float> [[HLSLNORMALIZEI]]
+
+// CHECK-LABEL: test_normalize_int2
+// CHECK: [[CONVI:%.*]] = sitofp {{.*}} <2 x i32> %{{.*}} to <2 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_int2(int2 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <3 x float> @_Z19test_normalize_int3Dv3_i(
-// CHECK:    [[CONVI:%.*]] = sitofp {{.*}} <3 x i32> %{{.*}} to <3 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <3 x float> @llvm.[[TARGET]].normalize.v3f32(<3 x float> [[CONVI]])
-// CHECK:    ret <3 x float> [[HLSLNORMALIZEI]]
+
+// CHECK-LABEL: test_normalize_int3
+// CHECK: [[CONVI:%.*]] = sitofp {{.*}} <3 x i32> %{{.*}} to <3 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_int3(int3 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <4 x float> @_Z16test_length_int4Dv4_i(
-// CHECK:    [[CONVI:%.*]] = sitofp {{.*}} <4 x i32> %{{.*}} to <4 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <4 x float> @llvm.[[TARGET]].normalize.v4f32(<4 x float> [[CONVI]])
-// CHECK:    ret <4 x float> [[HLSLNORMALIZEI]]
-float4 test_length_int4(int4 p0)
+
+// CHECK-LABEL: test_normalize_int4
+// CHECK: [[CONVI:%.*]] = sitofp {{.*}} <4 x i32> %{{.*}} to <4 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: ret <4 x float> [[RET]]
+float4 test_normalize_int4(int4 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
 
-// CHECK: define [[FNATTRS]] float @_Z19test_normalize_uintj(
-// CHECK:    [[CONVI:%.*]] = uitofp {{.*}} i32 %{{.*}} to float
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} float @llvm.[[TARGET]].normalize.f32(float [[CONVI]])
-// CHECK:    ret float [[HLSLNORMALIZEI]]
+// CHECK-LABEL: test_normalize_uint
+// CHECK: [[CONVI:%.*]] = uitofp {{.*}} i32 %{{.*}} to float
+// DXCHECK: [[MUL:%.*]] = fmul {{.*}} float %{{.*}}, %{{.*}}
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[MUL]])
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} float %{{.*}}, [[RSQRT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK-NEXT: ret float [[RET]]
 float test_normalize_uint(uint p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
 
-// CHECK: define [[FNATTRS]] <2 x float> @_Z20test_normalize_uint2Dv2_j(
-// CHECK:    [[CONVI:%.*]] = uitofp {{.*}} <2 x i32> %{{.*}} to <2 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <2 x float> @llvm.[[TARGET]].normalize.v2f32(<2 x float> [[CONVI]])
-// CHECK:    ret <2 x float> [[HLSLNORMALIZEI]]
+// CHECK-LABEL: test_normalize_uint2
+// CHECK: [[CONVI:%.*]] = uitofp {{.*}} <2 x i32> %{{.*}} to <2 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_uint2(uint2 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <3 x float> @_Z20test_normalize_uint3Dv3_j(
-// CHECK:    [[CONVI:%.*]] = uitofp {{.*}} <3 x i32> %{{.*}} to <3 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <3 x float> @llvm.[[TARGET]].normalize.v3f32(<3 x float> [[CONVI]])
-// CHECK:    ret <3 x float> [[HLSLNORMALIZEI]]
+
+// CHECK-LABEL: test_normalize_uint3
+// CHECK: [[CONVI:%.*]] = uitofp {{.*}} <3 x i32> %{{.*}} to <3 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_uint3(uint3 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <4 x float> @_Z17test_length_uint4Dv4_j(
-// CHECK:    [[CONVI:%.*]] = uitofp {{.*}} <4 x i32> %{{.*}} to <4 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <4 x float> @llvm.[[TARGET]].normalize.v4f32(<4 x float> [[CONVI]])
-// CHECK:    ret <4 x float> [[HLSLNORMALIZEI]]
-float4 test_length_uint4(uint4 p0)
+
+// CHECK-LABEL: test_normalize_uint4
+// CHECK: [[CONVI:%.*]] = uitofp {{.*}} <4 x i32> %{{.*}} to <4 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: ret <4 x float> [[RET]]
+float4 test_normalize_uint4(uint4 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
 
-// CHECK: define [[FNATTRS]] float @_Z22test_normalize_int64_tl(
-// CHECK:    [[CONVI:%.*]] = sitofp {{.*}} i64 %{{.*}} to float
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} float @llvm.[[TARGET]].normalize.f32(float [[CONVI]])
-// CHECK:    ret float [[HLSLNORMALIZEI]]
+// CHECK-LABEL: test_normalize_int64_t
+// CHECK: [[CONVI:%.*]] = sitofp {{.*}} i64 %{{.*}} to float
+// DXCHECK: [[MUL:%.*]] = fmul {{.*}} float %{{.*}}, %{{.*}}
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[MUL]])
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} float %{{.*}}, [[RSQRT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK-NEXT: ret float [[RET]]
 float test_normalize_int64_t(int64_t p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
 
-// CHECK: define [[FNATTRS]] <2 x float> @_Z23test_normalize_int64_t2Dv2_l(
-// CHECK:    [[CONVI:%.*]] = sitofp {{.*}} <2 x i64> %{{.*}} to <2 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <2 x float> @llvm.[[TARGET]].normalize.v2f32(<2 x float> [[CONVI]])
-// CHECK:    ret <2 x float> [[HLSLNORMALIZEI]]
+// CHECK-LABEL: test_normalize_int64_t2
+// CHECK: [[CONVI:%.*]] = sitofp {{.*}} <2 x i64> %{{.*}} to <2 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_int64_t2(int64_t2 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <3 x float> @_Z23test_normalize_int64_t3Dv3_l(
-// CHECK:    [[CONVI:%.*]] = sitofp {{.*}} <3 x i64> %{{.*}} to <3 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <3 x float> @llvm.[[TARGET]].normalize.v3f32(<3 x float> [[CONVI]])
-// CHECK:    ret <3 x float> [[HLSLNORMALIZEI]]
+
+// CHECK-LABEL: test_normalize_int64_t3
+// CHECK: [[CONVI:%.*]] = sitofp {{.*}} <3 x i64> %{{.*}} to <3 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_int64_t3(int64_t3 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <4 x float> @_Z20test_length_int64_t4Dv4_l(
-// CHECK:    [[CONVI:%.*]] = sitofp {{.*}} <4 x i64> %{{.*}} to <4 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <4 x float> @llvm.[[TARGET]].normalize.v4f32(<4 x float> [[CONVI]])
-// CHECK:    ret <4 x float> [[HLSLNORMALIZEI]]
-float4 test_length_int64_t4(int64_t4 p0)
+
+// CHECK-LABEL: test_normalize_int64_t4
+// CHECK: [[CONVI:%.*]] = sitofp {{.*}} <4 x i64> %{{.*}} to <4 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: ret <4 x float> [[RET]]
+float4 test_normalize_int64_t4(int64_t4 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
 
-// CHECK: define [[FNATTRS]] float @_Z23test_normalize_uint64_tm(
-// CHECK:    [[CONVI:%.*]] = uitofp {{.*}} i64 %{{.*}} to float
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} float @llvm.[[TARGET]].normalize.f32(float [[CONVI]])
-// CHECK:    ret float [[HLSLNORMALIZEI]]
+// CHECK-LABEL: test_normalize_uint64_t
+// CHECK: [[CONVI:%.*]] = uitofp {{.*}} i64 %{{.*}} to float
+// DXCHECK: [[MUL:%.*]] = fmul {{.*}} float %{{.*}}, %{{.*}}
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[MUL]])
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} float %{{.*}}, [[RSQRT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK-NEXT: ret float [[RET]]
 float test_normalize_uint64_t(uint64_t p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
 
-// CHECK: define [[FNATTRS]] <2 x float> @_Z24test_normalize_uint64_t2Dv2_m(
-// CHECK:    [[CONVI:%.*]] = uitofp {{.*}} <2 x i64> %{{.*}} to <2 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <2 x float> @llvm.[[TARGET]].normalize.v2f32(<2 x float> [[CONVI]])
-// CHECK:    ret <2 x float> [[HLSLNORMALIZEI]]
+// CHECK-LABEL: test_normalize_uint64_t2
+// CHECK: [[CONVI:%.*]] = uitofp {{.*}} <2 x i64> %{{.*}} to <2 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_uint64_t2(uint64_t2 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <3 x float> @_Z24test_normalize_uint64_t3Dv3_m(
-// CHECK:    [[CONVI:%.*]] = uitofp {{.*}} <3 x i64> %{{.*}} to <3 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <3 x float> @llvm.[[TARGET]].normalize.v3f32(<3 x float> [[CONVI]])
-// CHECK:    ret <3 x float> [[HLSLNORMALIZEI]]
+
+// CHECK-LABEL: test_normalize_uint64_t3
+// CHECK: [[CONVI:%.*]] = uitofp {{.*}} <3 x i64> %{{.*}} to <3 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_uint64_t3(uint64_t3 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <4 x float> @_Z21test_length_uint64_t4Dv4_m(
-// CHECK:    [[CONVI:%.*]] = uitofp {{.*}} <4 x i64> %{{.*}} to <4 x float>
-// CHECK:    [[HLSLNORMALIZEI:%.*]] = call {{.*}} <4 x float> @llvm.[[TARGET]].normalize.v4f32(<4 x float> [[CONVI]])
-// CHECK:    ret <4 x float> [[HLSLNORMALIZEI]]
-float4 test_length_uint64_t4(uint64_t4 p0)
+
+// CHECK-LABEL: test_normalize_uint64_t4
+// CHECK: [[CONVI:%.*]] = uitofp {{.*}} <4 x i64> %{{.*}} to <4 x float>
+// DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call {{.*}} <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: ret <4 x float> [[RET]]
+float4 test_normalize_uint64_t4(uint64_t4 p0)
 {
 // expected-warning at +1 {{'normalize' is deprecated: In 202x int lowering for normalize is deprecated. Explicitly cast parameters to float types.}}
     return normalize(p0);
diff --git a/clang/test/CodeGenHLSL/builtins/normalize.hlsl b/clang/test/CodeGenHLSL/builtins/normalize.hlsl
index d40feede9cca6..5d10e94fd692c 100644
--- a/clang/test/CodeGenHLSL/builtins/normalize.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/normalize.hlsl
@@ -1,85 +1,106 @@
 // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
 // RUN:   dxil-pc-shadermodel6.3-library %s -fnative-half-type -fnative-int16-type \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
-// RUN:   --check-prefixes=CHECK,NATIVE_HALF \
-// RUN:   -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
-// RUN:   dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
-// RUN:   -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
-// RUN:   -DFNATTRS="hidden noundef nofpclass(nan inf)" -DTARGET=dx
+// RUN:   -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,DXCHECK
 // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
 // RUN:   spirv-unknown-vulkan-library %s -fnative-half-type -fnative-int16-type \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
-// RUN:   --check-prefixes=CHECK,NATIVE_HALF \
-// RUN:   -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
-// RUN:   spirv-unknown-vulkan-library %s -emit-llvm -disable-llvm-passes \
-// RUN:   -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
-// RUN:   -DFNATTRS="hidden spir_func noundef nofpclass(nan inf)" -DTARGET=spv
+// RUN:   -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,SPVCHECK
 
-// NATIVE_HALF: define [[FNATTRS]] half @
-// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn half @llvm.[[TARGET]].normalize.f16(half
-// NO_HALF: call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].normalize.f32(float
-// NATIVE_HALF: ret half
-// NO_HALF: ret float
+// CHECK-LABEL: test_normalize_half
+// DXCHECK: [[DOT:%.*]] = fmul reassoc nnan ninf nsz arcp afn half %{{.*}}, %{{.*}}
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.rsqrt.f16(half [[DOT]])
+// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn half %{{.*}}, [[RSQRT]]
+// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) half @llvm.spv.normalize.f16(half %{{.*}})
+// CHECK-NEXT: ret half [[RET]]
 half test_normalize_half(half p0)
 {
     return normalize(p0);
 }
-// NATIVE_HALF: define [[FNATTRS]] <2 x half> @
-// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <2 x half> @llvm.[[TARGET]].normalize.v2f16(<2 x half>
-// NO_HALF: call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.[[TARGET]].normalize.v2f32(<2 x float>
-// NATIVE_HALF: ret <2 x half> %hlsl.normalize
-// NO_HALF: ret <2 x float> %hlsl.normalize
+
+// CHECK-LABEL: test_normalize_half2
+// DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.rsqrt.f16(half [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x half> poison, half [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x half> [[SPLATINSERT]], <2 x half> poison, <2 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <2 x half> @llvm.spv.normalize.v2f16(<2 x half> %{{.*}})
+// CHECK-NEXT: ret <2 x half> [[RET]]
 half2 test_normalize_half2(half2 p0)
 {
     return normalize(p0);
 }
-// NATIVE_HALF: define [[FNATTRS]] <3 x half> @
-// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <3 x half> @llvm.[[TARGET]].normalize.v3f16(<3 x half>
-// NO_HALF: call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.[[TARGET]].normalize.v3f32(<3 x float>
-// NATIVE_HALF: ret <3 x half> %hlsl.normalize
-// NO_HALF: ret <3 x float> %hlsl.normalize
+
+// CHECK-LABEL: test_normalize_half3
+// DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v3f16(<3 x half> %{{.*}}, <3 x half> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.rsqrt.f16(half [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x half> poison, half [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x half> [[SPLATINSERT]], <3 x half> poison, <3 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <3 x half> @llvm.spv.normalize.v3f16(<3 x half> %{{.*}})
+// CHECK-NEXT: ret <3 x half> [[RET]]
 half3 test_normalize_half3(half3 p0)
 {
     return normalize(p0);
 }
-// NATIVE_HALF: define [[FNATTRS]] <4 x half> @
-// NATIVE_HALF: call reassoc nnan ninf nsz arcp afn <4 x half> @llvm.[[TARGET]].normalize.v4f16(<4 x half>
-// NO_HALF: call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.[[TARGET]].normalize.v4f32(<4 x float>
-// NATIVE_HALF: ret <4 x half> %hlsl.normalize
-// NO_HALF: ret <4 x float> %hlsl.normalize
+
+// CHECK-LABEL: test_normalize_half4
+// DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v4f16(<4 x half> %{{.*}}, <4 x half> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.rsqrt.f16(half [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x half> poison, half [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x half> [[SPLATINSERT]], <4 x half> poison, <4 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <4 x half> @llvm.spv.normalize.v4f16(<4 x half> %{{.*}})
+// CHECK-NEXT: ret <4 x half> [[RET]]
 half4 test_normalize_half4(half4 p0)
 {
     return normalize(p0);
 }
 
-// CHECK: define [[FNATTRS]] float @
-// CHECK: call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].normalize.f32(float
-// CHECK: ret float
+// CHECK-LABEL: test_normalize_float
+// DXCHECK: [[DOT:%.*]] = fmul reassoc nnan ninf nsz arcp afn float %{{.*}}, %{{.*}}
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn float %{{.*}}, [[RSQRT]]
+// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK-NEXT: ret float [[RET]]
 float test_normalize_float(float p0)
 {
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <2 x float> @
-// CHECK: %hlsl.normalize = call reassoc nnan ninf nsz arcp afn <2 x float> @llvm.[[TARGET]].normalize.v2f32(<2 x float>
 
-// CHECK: ret <2 x float> %hlsl.normalize
+// CHECK-LABEL: test_normalize_float2
+// DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_float2(float2 p0)
 {
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <3 x float> @
-// CHECK: %hlsl.normalize = call reassoc nnan ninf nsz arcp afn <3 x float> @llvm.[[TARGET]].normalize.v3f32(
-// CHECK: ret <3 x float> %hlsl.normalize
+
+// CHECK-LABEL: test_normalize_float3
+// DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_float3(float3 p0)
 {
     return normalize(p0);
 }
-// CHECK: define [[FNATTRS]] <4 x float> @
-// CHECK: %hlsl.normalize = call reassoc nnan ninf nsz arcp afn <4 x float> @llvm.[[TARGET]].normalize.v4f32(
-// CHECK: ret <4 x float> %hlsl.normalize
-float4 test_length_float4(float4 p0)
+
+// CHECK-LABEL: test_normalize_float4
+// DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
+// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.rsqrt.f32(float [[DOT]])
+// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
+// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x float> %{{.*}}, [[SPLAT]]
+// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: ret <4 x float> [[RET]]
+float4 test_normalize_float4(float4 p0)
 {
     return normalize(p0);
 }
diff --git a/clang/test/CodeGenSPIRV/Builtins/normalize.c b/clang/test/CodeGenSPIRV/Builtins/normalize.c
new file mode 100644
index 0000000000000..87640cb33e19e
--- /dev/null
+++ b/clang/test/CodeGenSPIRV/Builtins/normalize.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-compute %s -emit-llvm -o - | FileCheck %s
+
+typedef _Float16 half;
+typedef half half2 __attribute__((ext_vector_type(2)));
+typedef half half3 __attribute__((ext_vector_type(3)));
+typedef half half4 __attribute__((ext_vector_type(4)));
+typedef float float2 __attribute__((ext_vector_type(2)));
+typedef float float3 __attribute__((ext_vector_type(3)));
+typedef float float4 __attribute__((ext_vector_type(4)));
+
+// CHECK: [[NORM:%.*]] = tail call half @llvm.spv.normalize.f16(half {{%.*}})
+// CHECK: ret half [[NORM]]
+half test_normalize_half(half X) { return __builtin_spirv_normalize(X); }
+
+// CHECK: [[NORM:%.*]] = tail call <2 x half> @llvm.spv.normalize.v2f16(<2 x half> {{%.*}})
+// CHECK: ret <2 x half> [[NORM]]
+half2 test_normalize_half2(half2 X) { return __builtin_spirv_normalize(X); }
+
+// CHECK: [[NORM:%.*]] = tail call <3 x half> @llvm.spv.normalize.v3f16(<3 x half> {{%.*}})
+// CHECK: ret <3 x half> [[NORM]]
+half3 test_normalize_half3(half3 X) { return __builtin_spirv_normalize(X); }
+
+// CHECK: [[NORM:%.*]] = tail call <4 x half> @llvm.spv.normalize.v4f16(<4 x half> {{%.*}})
+// CHECK: ret <4 x half> [[NORM]]
+half4 test_normalize_half4(half4 X) { return __builtin_spirv_normalize(X); }
+
+// CHECK: [[NORM:%.*]] = tail call float @llvm.spv.normalize.f32(float {{%.*}})
+// CHECK: ret float [[NORM]]
+float test_normalize_float(float X) { return __builtin_spirv_normalize(X); }
+
+// CHECK: [[NORM:%.*]] = tail call <2 x float> @llvm.spv.normalize.v2f32(<2 x float> {{%.*}})
+// CHECK: ret <2 x float> [[NORM]]
+float2 test_normalize_float2(float2 X) { return __builtin_spirv_normalize(X); }
+
+// CHECK: [[NORM:%.*]] = tail call <3 x float> @llvm.spv.normalize.v3f32(<3 x float> {{%.*}})
+// CHECK: ret <3 x float> [[NORM]]
+float3 test_normalize_float3(float3 X) { return __builtin_spirv_normalize(X); }
+
+// CHECK: [[NORM:%.*]] = tail call <4 x float> @llvm.spv.normalize.v4f32(<4 x float> {{%.*}})
+// CHECK: ret <4 x float> [[NORM]]
+float4 test_normalize_float4(float4 X) { return __builtin_spirv_normalize(X); }
diff --git a/clang/test/SemaHLSL/BuiltIns/normalize-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/normalize-errors.hlsl
deleted file mode 100644
index 377c2d5e41a73..0000000000000
--- a/clang/test/SemaHLSL/BuiltIns/normalize-errors.hlsl
+++ /dev/null
@@ -1,31 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -fnative-int16-type -disable-llvm-passes -verify
-
-void test_too_few_arg()
-{
-  return __builtin_hlsl_normalize();
-  // expected-error at -1 {{too few arguments to function call, expected 1, have 0}}
-}
-
-void test_too_many_arg(float2 p0)
-{
-  return __builtin_hlsl_normalize(p0, p0);
-  // expected-error at -1 {{too many arguments to function call, expected 1, have 2}}
-}
-
-bool builtin_bool_to_float_type_promotion(bool p1)
-{
-  return __builtin_hlsl_normalize(p1);
-  // expected-error at -1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'bool')}}
-}
-
-bool builtin_normalize_int_to_float_promotion(int p1)
-{
-  return __builtin_hlsl_normalize(p1);
-  // expected-error at -1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'int')}}
-}
-
-bool2 builtin_normalize_int2_to_float2_promotion(int2 p1)
-{
-  return __builtin_hlsl_normalize(p1);
-  // expected-error at -1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'int2' (aka 'vector<int, 2>'))}}
-}
diff --git a/clang/test/SemaSPIRV/BuiltIns/normalize-errors.c b/clang/test/SemaSPIRV/BuiltIns/normalize-errors.c
new file mode 100644
index 0000000000000..7159bc8735279
--- /dev/null
+++ b/clang/test/SemaSPIRV/BuiltIns/normalize-errors.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -triple spirv-pc-vulkan-compute -verify
+
+typedef float float2 __attribute__((ext_vector_type(2)));
+
+void test_too_few_arg() {
+  return __builtin_spirv_normalize();
+  // expected-error at -1 {{too few arguments to function call, expected 1, have 0}}
+}
+
+float test_too_many_arg(float p0) {
+  return __builtin_spirv_normalize(p0, p0);
+  // expected-error at -1 {{too many arguments to function call, expected 1, have 2}}
+}
+
+float test_int_scalar_inputs(int p0) {
+  return __builtin_spirv_normalize(p0);
+  //  expected-error at -1 {{1st argument must be a scalar or vector of floating-point types (was 'int')}}
+}
+
+float test_mismatched_return(float2 p0) {
+  return __builtin_spirv_normalize(p0);
+  // expected-error at -1 {{returning 'float2' (vector of 2 'float' values) from a function with incompatible result type 'float'}}
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 9c9b2032035e3..4b895c1cfc8e9 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -255,7 +255,6 @@ def int_dx_legacyf32tof16 : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0
 
 def int_dx_imad : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, IntrTriviallyScalarizable]>;
 def int_dx_umad : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, IntrTriviallyScalarizable]>;
-def int_dx_normalize : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
 def int_dx_wave_prefix_bit_count : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i1_ty], [IntrConvergent, IntrNoMem]>;
 def int_dx_rsqrt  : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem, IntrTriviallyScalarizable]>;
 def int_dx_wave_active_countbits : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i1_ty], [IntrConvergent, IntrNoMem]>;
diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
index 8ecc7ddc4b64f..6ae641a5f2a03 100644
--- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
+++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
@@ -218,7 +218,6 @@ static bool isIntrinsicExpansion(Function &F) {
   case Intrinsic::dx_nclamp:
   case Intrinsic::dx_isinf:
   case Intrinsic::dx_isnan:
-  case Intrinsic::dx_normalize:
   case Intrinsic::dx_fdot:
   case Intrinsic::dx_sdot:
   case Intrinsic::dx_udot:
@@ -625,43 +624,6 @@ static Value *expandLog10Intrinsic(CallInst *Orig) {
   return expandLogIntrinsic(Orig, numbers::ln2f / numbers::ln10f);
 }
 
-// Use dot product of vector operand with itself to calculate the length.
-// Divide the vector by that length to normalize it.
-static Value *expandNormalizeIntrinsic(CallInst *Orig) {
-  Value *X = Orig->getOperand(0);
-  Type *Ty = Orig->getType();
-  Type *EltTy = Ty->getScalarType();
-  IRBuilder<> Builder(Orig);
-
-  auto *XVec = dyn_cast<FixedVectorType>(Ty);
-  if (!XVec) {
-    if (auto *constantFP = dyn_cast<ConstantFP>(X)) {
-      const APFloat &fpVal = constantFP->getValueAPF();
-      if (fpVal.isZero())
-        reportFatalUsageError("Invalid input scalar: length is zero");
-    }
-    return Builder.CreateFDiv(X, X);
-  }
-
-  Value *DotProduct = expandFloatDotIntrinsic(Orig, X, X);
-
-  // verify that the length is non-zero
-  // (if the dot product is non-zero, then the length is non-zero)
-  if (auto *constantFP = dyn_cast<ConstantFP>(DotProduct)) {
-    const APFloat &fpVal = constantFP->getValueAPF();
-    if (fpVal.isZero())
-      reportFatalUsageError("Invalid input vector: length is zero");
-  }
-
-  Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
-                                                ArrayRef<Value *>{DotProduct},
-                                                nullptr, "dx.rsqrt");
-
-  Value *MultiplicandVec =
-      Builder.CreateVectorSplat(XVec->getNumElements(), Multiplicand);
-  return Builder.CreateFMul(X, MultiplicandVec);
-}
-
 static Value *expandAtan2Intrinsic(CallInst *Orig) {
   Value *Y = Orig->getOperand(0);
   Value *X = Orig->getOperand(1);
@@ -1286,9 +1248,6 @@ static bool expandIntrinsic(Function &F, CallInst *Orig) {
   case Intrinsic::dx_isnan:
     Result = expand16BitIsNaN(Orig);
     break;
-  case Intrinsic::dx_normalize:
-    Result = expandNormalizeIntrinsic(Orig);
-    break;
   case Intrinsic::dx_fdot:
     Result = expandFloatDotIntrinsic(Orig);
     break;
diff --git a/llvm/test/CodeGen/DirectX/normalize.ll b/llvm/test/CodeGen/DirectX/normalize.ll
deleted file mode 100644
index db4a4900c0532..0000000000000
--- a/llvm/test/CodeGen/DirectX/normalize.ll
+++ /dev/null
@@ -1,112 +0,0 @@
-; RUN: opt -S  -dxil-intrinsic-expansion  < %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
-; RUN: opt -S  -dxil-intrinsic-expansion -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library < %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
-
-; Make sure dxil operation function calls for normalize are generated for half/float.
-
-declare half @llvm.dx.normalize.f16(half)
-declare <2 x half> @llvm.dx.normalize.v2f16(<2 x half>)
-declare <3 x half> @llvm.dx.normalize.v3f16(<3 x half>)
-declare <4 x half> @llvm.dx.normalize.v4f16(<4 x half>)
-
-declare float @llvm.dx.normalize.f32(float)
-declare <2 x float> @llvm.dx.normalize.v2f32(<2 x float>)
-declare <3 x float> @llvm.dx.normalize.v3f32(<3 x float>)
-declare <4 x float> @llvm.dx.normalize.v4f32(<4 x float>)
-
-define noundef half @test_normalize_half(half noundef %p0) {
-entry:
-  ; CHECK: fdiv half %p0, %p0
-  %hlsl.normalize = call half @llvm.dx.normalize.f16(half %p0)
-  ret half %hlsl.normalize
-}
-
-define noundef <2 x half> @test_normalize_half2(<2 x half> noundef %p0) {
-entry:
-  ; EXPCHECK: [[doth2:%.*]] = call half @llvm.dx.dot2.f16(half %{{.*}}, half %{{.*}}, half %{{.*}}, half %{{.*}})
-  ; DOPCHECK: [[doth2:%.*]] = call half @dx.op.dot2.f16(i32 54, half %{{.*}}, half %{{.*}}, half %{{.*}}, half %{{.*}})
-  ; EXPCHECK: [[rsqrt:%.*]] = call half @llvm.dx.rsqrt.f16(half [[doth2]])
-  ; DOPCHECK: [[rsqrt:%.*]] = call half @dx.op.unary.f16(i32 25, half [[doth2]])
-  ; CHECK: [[splatinserth2:%.*]] = insertelement <2 x half> poison, half [[rsqrt]], i64 0
-  ; CHECK: [[splat:%.*]] = shufflevector <2 x half> [[splatinserth2]], <2 x half> poison, <2 x i32> zeroinitializer
-  ; CHECK: fmul <2 x half> %p0, [[splat]]
-
-  %hlsl.normalize = call <2 x half> @llvm.dx.normalize.v2f16(<2 x half> %p0)
-  ret <2 x half> %hlsl.normalize
-}
-
-define noundef <3 x half> @test_normalize_half3(<3 x half> noundef %p0) {
-entry:
-  ; EXPCHECK: [[doth3:%.*]] = call half @llvm.dx.dot3.f16(half %{{.*}}, half %{{.*}}, half %{{.*}}, half %{{.*}})
-  ; DOPCHECK: [[doth3:%.*]] = call half @dx.op.dot3.f16(i32 55, half %{{.*}}, half %{{.*}}, half %{{.*}}, half %{{.*}})
-  ; EXPCHECK: [[rsqrt:%.*]] = call half @llvm.dx.rsqrt.f16(half [[doth3]])
-  ; DOPCHECK: [[rsqrt:%.*]] = call half @dx.op.unary.f16(i32 25, half [[doth3]])
-  ; CHECK: [[splatinserth3:%.*]] = insertelement <3 x half> poison, half [[rsqrt]], i64 0
-  ; CHECK: [[splat:%.*]] shufflevector <3 x half> [[splatinserth3]], <3 x half> poison, <3 x i32> zeroinitializer
-  ; CHECK: fmul <3 x half> %p0, %.splat
-
-  %hlsl.normalize = call <3 x half> @llvm.dx.normalize.v3f16(<3 x half> %p0)
-  ret <3 x half> %hlsl.normalize
-}
-
-define noundef <4 x half> @test_normalize_half4(<4 x half> noundef %p0) {
-entry:
-  ; EXPCHECK: [[doth4:%.*]] = call half @llvm.dx.dot4.f16(half %{{.*}}, half %{{.*}}, half %{{.*}}, half %{{.*}})
-  ; DOPCHECK: [[doth4:%.*]] = call half @dx.op.dot4.f16(i32 56, half %{{.*}}, half %{{.*}}, half %{{.*}}, half %{{.*}})
-  ; EXPCHECK: [[rsqrt:%.*]] = call half @llvm.dx.rsqrt.f16(half [[doth4]])
-  ; DOPCHECK: [[rsqrt:%.*]] = call half @dx.op.unary.f16(i32 25, half [[doth4]])
-  ; CHECK: [[splatinserth4:%.*]] = insertelement <4 x half> poison, half [[rsqrt]], i64 0
-  ; CHECK: [[splat:%.*]] shufflevector <4 x half> [[splatinserth4]], <4 x half> poison, <4 x i32> zeroinitializer
-  ; CHECK: fmul <4 x half> %p0, %.splat
-
-  %hlsl.normalize = call <4 x half> @llvm.dx.normalize.v4f16(<4 x half> %p0)
-  ret <4 x half> %hlsl.normalize
-}
-
-define noundef float @test_normalize_float(float noundef %p0) {
-entry:
-  ; CHECK: fdiv float %p0, %p0
-  %hlsl.normalize = call float @llvm.dx.normalize.f32(float %p0)
-  ret float %hlsl.normalize
-}
-
-define noundef <2 x float> @test_normalize_float2(<2 x float> noundef %p0) {
-entry:
-  ; EXPCHECK: [[dotf2:%.*]] = call float @llvm.dx.dot2.f32(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}})
-  ; DOPCHECK: [[dotf2:%.*]] = call float @dx.op.dot2.f32(i32 54, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}})
-  ; EXPCHECK: [[rsqrt:%.*]] = call float @llvm.dx.rsqrt.f32(float [[dotf2]])
-  ; DOPCHECK: [[rsqrt:%.*]] = call float @dx.op.unary.f32(i32 25, float [[dotf2]])
-  ; CHECK: [[splatinsertf2:%.*]] = insertelement <2 x float> poison, float [[rsqrt]], i64 0
-  ; CHECK: [[splat:%.*]] shufflevector <2 x float> [[splatinsertf2]], <2 x float> poison, <2 x i32> zeroinitializer
-  ; CHECK: fmul <2 x float> %p0, %.splat
-
-  %hlsl.normalize = call <2 x float> @llvm.dx.normalize.v2f32(<2 x float> %p0)
-  ret <2 x float> %hlsl.normalize
-}
-
-define noundef <3 x float> @test_normalize_float3(<3 x float> noundef %p0) {
-entry:
-  ; EXPCHECK: [[dotf3:%.*]] = call float @llvm.dx.dot3.f32(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}})
-  ; DOPCHECK: [[dotf3:%.*]] = call float @dx.op.dot3.f32(i32 55, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}})
-  ; EXPCHECK: [[rsqrt:%.*]] = call float @llvm.dx.rsqrt.f32(float [[dotf3]])
-  ; DOPCHECK: [[rsqrt:%.*]] = call float @dx.op.unary.f32(i32 25, float [[dotf3]])
-  ; CHECK: [[splatinsertf3:%.*]] = insertelement <3 x float> poison, float [[rsqrt]], i64 0
-  ; CHECK: [[splat:%.*]] shufflevector <3 x float> [[splatinsertf3]], <3 x float> poison, <3 x i32> zeroinitializer
-  ; CHECK: fmul <3 x float> %p0, %.splat
-
-  %hlsl.normalize = call <3 x float> @llvm.dx.normalize.v3f32(<3 x float> %p0)
-  ret <3 x float> %hlsl.normalize
-}
-
-define noundef <4 x float> @test_normalize_float4(<4 x float> noundef %p0) {
-entry:
-  ; EXPCHECK: [[dotf4:%.*]] = call float @llvm.dx.dot4.f32(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}})
-  ; DOPCHECK: [[dotf4:%.*]] = call float @dx.op.dot4.f32(i32 56, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}})
-  ; EXPCHECK: [[rsqrt:%.*]] = call float @llvm.dx.rsqrt.f32(float [[dotf4]])
-  ; DOPCHECK: [[rsqrt:%.*]] = call float @dx.op.unary.f32(i32 25, float [[dotf4]])
-  ; CHECK: [[splatinsertf4:%.*]] = insertelement <4 x float> poison, float [[rsqrt]], i64 0
-  ; CHECK: [[splat:%.*]] shufflevector <4 x float> [[splatinsertf4]], <4 x float> poison, <4 x i32> zeroinitializer
-  ; CHECK: fmul <4 x float> %p0, %.splat
-
-  %hlsl.normalize = call <4 x float> @llvm.dx.normalize.v4f32(<4 x float> %p0)
-  ret <4 x float> %hlsl.normalize
-}
diff --git a/llvm/test/CodeGen/DirectX/normalize_error.ll b/llvm/test/CodeGen/DirectX/normalize_error.ll
deleted file mode 100644
index 3041d2ecdd923..0000000000000
--- a/llvm/test/CodeGen/DirectX/normalize_error.ll
+++ /dev/null
@@ -1,10 +0,0 @@
-; RUN: not opt -S -dxil-intrinsic-expansion -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
-
-; DXIL operation normalize does not support double overload type
-; CHECK: Cannot create Dot2 operation: Invalid overload type
-
-define noundef <2 x double> @test_normalize_double2(<2 x double> noundef %p0) {
-entry:
-  %hlsl.normalize = call <2 x double> @llvm.dx.normalize.v2f32(<2 x double> %p0)
-  ret <2 x double> %hlsl.normalize
-}
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/normalize.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/normalize.ll
index 057f0c716ddca..d23aa69297c90 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/normalize.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/normalize.ll
@@ -9,6 +9,24 @@
 ; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
 ; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
 
+define noundef half @normalize_half(half noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#float_16]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_16]]
+  ; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] Normalize %[[#arg0]]
+  %hlsl.normalize = call half @llvm.spv.normalize.f16(half %a)
+  ret half %hlsl.normalize
+}
+
+define noundef float @normalize_float(float noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_32]]
+  ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] Normalize %[[#arg0]]
+  %hlsl.normalize = call float @llvm.spv.normalize.f32(float %a)
+  ret float %hlsl.normalize
+}
+
 define noundef <4 x half> @normalize_half4(<4 x half> noundef %a) {
 entry:
   ; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]]
@@ -27,5 +45,7 @@ entry:
   ret <4 x float> %hlsl.normalize
 }
 
+declare half @llvm.spv.normalize.f16(half)
+declare float @llvm.spv.normalize.f32(float)
 declare <4 x half> @llvm.spv.normalize.v4f16(<4 x half>)
 declare <4 x float> @llvm.spv.normalize.v4f32(<4 x float>)
diff --git a/llvm/test/CodeGen/SPIRV/opencl/normalize.ll b/llvm/test/CodeGen/SPIRV/opencl/normalize.ll
new file mode 100644
index 0000000000000..82055c38347d8
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/opencl/normalize.ll
@@ -0,0 +1,52 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#op_ext_cl:]] = OpExtInstImport "OpenCL.std"
+
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+
+define noundef half @normalize_half(half noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#float_16]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_16]]
+  ; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_cl]] normalize %[[#arg0]]
+  %spv.normalize = call half @llvm.spv.normalize.f16(half %a)
+  ret half %spv.normalize
+}
+
+define noundef float @normalize_float(float noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_32]]
+  ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_cl]] normalize %[[#arg0]]
+  %spv.normalize = call float @llvm.spv.normalize.f32(float %a)
+  ret float %spv.normalize
+}
+
+define noundef <4 x half> @normalize_half4(<4 x half> noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]]
+  ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_cl]] normalize %[[#arg0]]
+  %spv.normalize = call <4 x half> @llvm.spv.normalize.v4f16(<4 x half> %a)
+  ret <4 x half> %spv.normalize
+}
+
+define noundef <4 x float> @normalize_float4(<4 x float> noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#vec4_float_32]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]]
+  ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_cl]] normalize %[[#arg0]]
+  %spv.normalize = call <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %a)
+  ret <4 x float> %spv.normalize
+}
+
+declare half @llvm.spv.normalize.f16(half)
+declare float @llvm.spv.normalize.f32(float)
+declare <4 x half> @llvm.spv.normalize.v4f16(<4 x half>)
+declare <4 x float> @llvm.spv.normalize.v4f32(<4 x float>)

>From 366fec76cee6bb7b2a07fb625a236172834210cf Mon Sep 17 00:00:00 2001
From: kmpeng <kaitlinpeng at microsoft.com>
Date: Mon, 17 Aug 2026 06:25:16 -0700
Subject: [PATCH 2/2] remove spirv builtin, add pattern matching

---
 .../clang/Basic/BuiltinsSPIRVCommon.td        |   1 -
 clang/include/clang/Basic/HLSLIntrinsics.td   |   3 +-
 clang/lib/CodeGen/TargetBuiltins/SPIR.cpp     |   8 -
 .../lib/Headers/hlsl/hlsl_intrinsic_helpers.h |   8 -
 clang/lib/Sema/SemaSPIRV.cpp                  |  17 --
 .../builtins/normalize-overloads.hlsl         | 180 +++++++++---------
 .../test/CodeGenHLSL/builtins/normalize.hlsl  |  72 ++++---
 clang/test/CodeGenSPIRV/Builtins/normalize.c  |  41 ----
 .../SemaSPIRV/BuiltIns/normalize-errors.c     |  23 ---
 llvm/lib/Target/SPIRV/SPIRVCombine.td         |   8 +
 llvm/lib/Target/SPIRV/SPIRVCombinerHelper.cpp |  47 +++++
 llvm/lib/Target/SPIRV/SPIRVCombinerHelper.h   |   2 +
 ...prelegalizercombiner-fdiv-to-normalize.mir |  27 +++
 .../SPIRV/hlsl-intrinsics/normalize.ll        |  32 ++--
 llvm/test/CodeGen/SPIRV/opencl/normalize.ll   |  32 ++--
 15 files changed, 229 insertions(+), 272 deletions(-)
 delete mode 100644 clang/test/CodeGenSPIRV/Builtins/normalize.c
 delete mode 100644 clang/test/SemaSPIRV/BuiltIns/normalize-errors.c
 create mode 100644 llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-fdiv-to-normalize.mir

diff --git a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
index 91ad12599971f..448223a176ab4 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
@@ -20,7 +20,6 @@ def subgroup_local_invocation_id : SPIRVBuiltin<"uint32_t()", [NoThrow, Const]>;
 
 def distance : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
 def length : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
-def normalize : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
 def smoothstep : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
 
 def group_barrier : SPIRVBuiltin<"void()", [NoThrow]>;
diff --git a/clang/include/clang/Basic/HLSLIntrinsics.td b/clang/include/clang/Basic/HLSLIntrinsics.td
index 91a542cf269e8..46ecb7c95e014 100644
--- a/clang/include/clang/Basic/HLSLIntrinsics.td
+++ b/clang/include/clang/Basic/HLSLIntrinsics.td
@@ -1284,7 +1284,7 @@ The return value is the \a I parameter.
 }
 
 // Returns the normalized unit vector of the specified floating-point vector.
-def hlsl_normalize : HLSLOneArgDetail<"normalize", "normalize_impl"> {
+def hlsl_normalize : HLSLOneArgInlineBuiltin<"normalize"> {
   let Doc = [{
 \fn T normalize(T x)
 \brief Returns the normalized unit vector of the specified floating-point
@@ -1294,6 +1294,7 @@ vector.
 Normalize is based on the following formula: x / length(x).
 }];
   let ParamNames = ["x"];
+  let Body = "return x / __detail::length_impl(x);";
   let VaryingTypes = [HalfTy, FloatTy];
   let VaryingMatDims = [];
 }
diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
index 66f22d28e2a13..b2732e2ae674e 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
@@ -45,14 +45,6 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
         /*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_length,
         ArrayRef<Value *>{X}, nullptr, "spv.length");
   }
-  case SPIRV::BI__builtin_spirv_normalize: {
-    Value *X = EmitScalarExpr(E->getArg(0));
-    assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
-           "normalize operand must have a float representation");
-    return Builder.CreateIntrinsic(
-        /*ReturnType=*/X->getType(), Intrinsic::spv_normalize,
-        ArrayRef<Value *>{X}, nullptr, "spv.normalize");
-  }
   case SPIRV::BI__builtin_spirv_reflect: {
     Value *I = EmitScalarExpr(E->getArg(0));
     Value *N = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
index 6d941231971c8..977059a9fdae0 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h
@@ -28,14 +28,6 @@ length_impl(vector<T, N> X) {
 #endif
 }
 
-template <typename T> constexpr T normalize_impl(T X) {
-#if (__has_builtin(__builtin_spirv_normalize))
-  return __builtin_spirv_normalize(X);
-#else
-  return X * rsqrt(dot(X, X));
-#endif
-}
-
 constexpr float dot2add_impl(half2 a, half2 b, float c) {
 #if (__has_builtin(__builtin_dx_dot2add))
   return __builtin_dx_dot2add(a, b, c);
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index 7c1abcad17ac3..8c2af5053bde2 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -246,23 +246,6 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI,
     TheCall->setType(RetTy);
     break;
   }
-  case SPIRV::BI__builtin_spirv_normalize: {
-    if (SemaRef.checkArgCount(TheCall, 1))
-      return true;
-
-    ExprResult A = TheCall->getArg(0);
-    QualType ArgTyA = A.get()->getType();
-    if (!ArgTyA->hasFloatingRepresentation()) {
-      SemaRef.Diag(A.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-          << /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
-          << /* fp */ 1 << ArgTyA;
-      return true;
-    }
-
-    QualType RetTy = ArgTyA;
-    TheCall->setType(RetTy);
-    break;
-  }
   case SPIRV::BI__builtin_spirv_reflect: {
     if (SemaRef.checkArgCount(TheCall, 2))
       return true;
diff --git a/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl b/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl
index 2256621892f04..6c8d32c681b2b 100644
--- a/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/normalize-overloads.hlsl
@@ -11,10 +11,8 @@
 
 // CHECK-LABEL: test_normalize_double
 // CHECK: [[CONVI:%.*]] = fptrunc {{.*}} double %{{.*}} to float
-// DXCHECK: [[MUL:%.*]] = fmul {{.*}} float %{{.*}}, %{{.*}}
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[MUL]])
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} float %{{.*}}, [[RSQRT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK: [[ABS:%.*]] = call {{.*}} float @llvm.fabs.f32(float %{{.*}})
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} float %{{.*}}, [[ABS]]
 // CHECK-NEXT: ret float [[RET]]
 float test_normalize_double(double p0)
 {
@@ -25,11 +23,11 @@ float test_normalize_double(double p0)
 // CHECK-LABEL: test_normalize_double2
 // CHECK: [[CONVI:%.*]] = fptrunc {{.*}} <2 x double> %{{.*}} to <2 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_double2(double2 p0)
 {
@@ -40,11 +38,11 @@ float2 test_normalize_double2(double2 p0)
 // CHECK-LABEL: test_normalize_double3
 // CHECK: [[CONVI:%.*]] = fptrunc {{.*}} <3 x double> %{{.*}} to <3 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_double3(double3 p0)
 {
@@ -55,11 +53,11 @@ float3 test_normalize_double3(double3 p0)
 // CHECK-LABEL: test_normalize_double4
 // CHECK: [[CONVI:%.*]] = fptrunc {{.*}} <4 x double> %{{.*}} to <4 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <4 x float> [[RET]]
 float4 test_normalize_double4(double4 p0)
 {
@@ -69,10 +67,8 @@ float4 test_normalize_double4(double4 p0)
 
 // CHECK-LABEL: test_normalize_int
 // CHECK: [[CONVI:%.*]] = sitofp {{.*}} i32 %{{.*}} to float
-// DXCHECK: [[MUL:%.*]] = fmul {{.*}} float %{{.*}}, %{{.*}}
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[MUL]])
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} float %{{.*}}, [[RSQRT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK: [[ABS:%.*]] = call {{.*}} float @llvm.fabs.f32(float %{{.*}})
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} float %{{.*}}, [[ABS]]
 // CHECK-NEXT: ret float [[RET]]
 float test_normalize_int(int p0)
 {
@@ -83,11 +79,11 @@ float test_normalize_int(int p0)
 // CHECK-LABEL: test_normalize_int2
 // CHECK: [[CONVI:%.*]] = sitofp {{.*}} <2 x i32> %{{.*}} to <2 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_int2(int2 p0)
 {
@@ -98,11 +94,11 @@ float2 test_normalize_int2(int2 p0)
 // CHECK-LABEL: test_normalize_int3
 // CHECK: [[CONVI:%.*]] = sitofp {{.*}} <3 x i32> %{{.*}} to <3 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_int3(int3 p0)
 {
@@ -113,11 +109,11 @@ float3 test_normalize_int3(int3 p0)
 // CHECK-LABEL: test_normalize_int4
 // CHECK: [[CONVI:%.*]] = sitofp {{.*}} <4 x i32> %{{.*}} to <4 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <4 x float> [[RET]]
 float4 test_normalize_int4(int4 p0)
 {
@@ -127,10 +123,8 @@ float4 test_normalize_int4(int4 p0)
 
 // CHECK-LABEL: test_normalize_uint
 // CHECK: [[CONVI:%.*]] = uitofp {{.*}} i32 %{{.*}} to float
-// DXCHECK: [[MUL:%.*]] = fmul {{.*}} float %{{.*}}, %{{.*}}
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[MUL]])
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} float %{{.*}}, [[RSQRT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK: [[ABS:%.*]] = call {{.*}} float @llvm.fabs.f32(float %{{.*}})
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} float %{{.*}}, [[ABS]]
 // CHECK-NEXT: ret float [[RET]]
 float test_normalize_uint(uint p0)
 {
@@ -141,11 +135,11 @@ float test_normalize_uint(uint p0)
 // CHECK-LABEL: test_normalize_uint2
 // CHECK: [[CONVI:%.*]] = uitofp {{.*}} <2 x i32> %{{.*}} to <2 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_uint2(uint2 p0)
 {
@@ -156,11 +150,11 @@ float2 test_normalize_uint2(uint2 p0)
 // CHECK-LABEL: test_normalize_uint3
 // CHECK: [[CONVI:%.*]] = uitofp {{.*}} <3 x i32> %{{.*}} to <3 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_uint3(uint3 p0)
 {
@@ -171,11 +165,11 @@ float3 test_normalize_uint3(uint3 p0)
 // CHECK-LABEL: test_normalize_uint4
 // CHECK: [[CONVI:%.*]] = uitofp {{.*}} <4 x i32> %{{.*}} to <4 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <4 x float> [[RET]]
 float4 test_normalize_uint4(uint4 p0)
 {
@@ -185,10 +179,8 @@ float4 test_normalize_uint4(uint4 p0)
 
 // CHECK-LABEL: test_normalize_int64_t
 // CHECK: [[CONVI:%.*]] = sitofp {{.*}} i64 %{{.*}} to float
-// DXCHECK: [[MUL:%.*]] = fmul {{.*}} float %{{.*}}, %{{.*}}
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[MUL]])
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} float %{{.*}}, [[RSQRT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK: [[ABS:%.*]] = call {{.*}} float @llvm.fabs.f32(float %{{.*}})
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} float %{{.*}}, [[ABS]]
 // CHECK-NEXT: ret float [[RET]]
 float test_normalize_int64_t(int64_t p0)
 {
@@ -199,11 +191,11 @@ float test_normalize_int64_t(int64_t p0)
 // CHECK-LABEL: test_normalize_int64_t2
 // CHECK: [[CONVI:%.*]] = sitofp {{.*}} <2 x i64> %{{.*}} to <2 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_int64_t2(int64_t2 p0)
 {
@@ -214,11 +206,11 @@ float2 test_normalize_int64_t2(int64_t2 p0)
 // CHECK-LABEL: test_normalize_int64_t3
 // CHECK: [[CONVI:%.*]] = sitofp {{.*}} <3 x i64> %{{.*}} to <3 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_int64_t3(int64_t3 p0)
 {
@@ -229,11 +221,11 @@ float3 test_normalize_int64_t3(int64_t3 p0)
 // CHECK-LABEL: test_normalize_int64_t4
 // CHECK: [[CONVI:%.*]] = sitofp {{.*}} <4 x i64> %{{.*}} to <4 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <4 x float> [[RET]]
 float4 test_normalize_int64_t4(int64_t4 p0)
 {
@@ -243,10 +235,8 @@ float4 test_normalize_int64_t4(int64_t4 p0)
 
 // CHECK-LABEL: test_normalize_uint64_t
 // CHECK: [[CONVI:%.*]] = uitofp {{.*}} i64 %{{.*}} to float
-// DXCHECK: [[MUL:%.*]] = fmul {{.*}} float %{{.*}}, %{{.*}}
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[MUL]])
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} float %{{.*}}, [[RSQRT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK: [[ABS:%.*]] = call {{.*}} float @llvm.fabs.f32(float %{{.*}})
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} float %{{.*}}, [[ABS]]
 // CHECK-NEXT: ret float [[RET]]
 float test_normalize_uint64_t(uint64_t p0)
 {
@@ -257,11 +247,11 @@ float test_normalize_uint64_t(uint64_t p0)
 // CHECK-LABEL: test_normalize_uint64_t2
 // CHECK: [[CONVI:%.*]] = uitofp {{.*}} <2 x i64> %{{.*}} to <2 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <2 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_uint64_t2(uint64_t2 p0)
 {
@@ -272,11 +262,11 @@ float2 test_normalize_uint64_t2(uint64_t2 p0)
 // CHECK-LABEL: test_normalize_uint64_t3
 // CHECK: [[CONVI:%.*]] = uitofp {{.*}} <3 x i64> %{{.*}} to <3 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <3 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_uint64_t3(uint64_t3 p0)
 {
@@ -287,11 +277,11 @@ float3 test_normalize_uint64_t3(uint64_t3 p0)
 // CHECK-LABEL: test_normalize_uint64_t4
 // CHECK: [[CONVI:%.*]] = uitofp {{.*}} <4 x i64> %{{.*}} to <4 x float>
 // DXCHECK: [[DOT:%.*]] = call {{.*}} float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call {{.*}} float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call {{.*}} <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call {{.*}} float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call {{.*}} float @llvm.spv.length.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv {{.*}} <4 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <4 x float> [[RET]]
 float4 test_normalize_uint64_t4(uint64_t4 p0)
 {
diff --git a/clang/test/CodeGenHLSL/builtins/normalize.hlsl b/clang/test/CodeGenHLSL/builtins/normalize.hlsl
index 5d10e94fd692c..079c31ecc62ee 100644
--- a/clang/test/CodeGenHLSL/builtins/normalize.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/normalize.hlsl
@@ -6,10 +6,8 @@
 // RUN:   -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,SPVCHECK
 
 // CHECK-LABEL: test_normalize_half
-// DXCHECK: [[DOT:%.*]] = fmul reassoc nnan ninf nsz arcp afn half %{{.*}}, %{{.*}}
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.rsqrt.f16(half [[DOT]])
-// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn half %{{.*}}, [[RSQRT]]
-// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) half @llvm.spv.normalize.f16(half %{{.*}})
+// CHECK: [[ABS:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) half @llvm.fabs.f16(half %{{.*}})
+// CHECK-NEXT: [[RET:%.*]] = fdiv reassoc nnan ninf nsz arcp afn half %{{.*}}, [[ABS]]
 // CHECK-NEXT: ret half [[RET]]
 half test_normalize_half(half p0)
 {
@@ -18,11 +16,11 @@ half test_normalize_half(half p0)
 
 // CHECK-LABEL: test_normalize_half2
 // DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.rsqrt.f16(half [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x half> poison, half [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x half> [[SPLATINSERT]], <2 x half> poison, <2 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <2 x half> @llvm.spv.normalize.v2f16(<2 x half> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) half @llvm.sqrt.f16(half [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) half @llvm.spv.length.v2f16(<2 x half> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x half> poison, half [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x half> [[SPLATINSERT]], <2 x half> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <2 x half> [[RET]]
 half2 test_normalize_half2(half2 p0)
 {
@@ -31,11 +29,11 @@ half2 test_normalize_half2(half2 p0)
 
 // CHECK-LABEL: test_normalize_half3
 // DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v3f16(<3 x half> %{{.*}}, <3 x half> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.rsqrt.f16(half [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x half> poison, half [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x half> [[SPLATINSERT]], <3 x half> poison, <3 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x half> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <3 x half> @llvm.spv.normalize.v3f16(<3 x half> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) half @llvm.sqrt.f16(half [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) half @llvm.spv.length.v3f16(<3 x half> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x half> poison, half [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x half> [[SPLATINSERT]], <3 x half> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <3 x half> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <3 x half> [[RET]]
 half3 test_normalize_half3(half3 p0)
 {
@@ -44,11 +42,11 @@ half3 test_normalize_half3(half3 p0)
 
 // CHECK-LABEL: test_normalize_half4
 // DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v4f16(<4 x half> %{{.*}}, <4 x half> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn half @llvm.dx.rsqrt.f16(half [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x half> poison, half [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x half> [[SPLATINSERT]], <4 x half> poison, <4 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x half> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <4 x half> @llvm.spv.normalize.v4f16(<4 x half> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) half @llvm.sqrt.f16(half [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) half @llvm.spv.length.v4f16(<4 x half> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x half> poison, half [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x half> [[SPLATINSERT]], <4 x half> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <4 x half> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <4 x half> [[RET]]
 half4 test_normalize_half4(half4 p0)
 {
@@ -56,10 +54,8 @@ half4 test_normalize_half4(half4 p0)
 }
 
 // CHECK-LABEL: test_normalize_float
-// DXCHECK: [[DOT:%.*]] = fmul reassoc nnan ninf nsz arcp afn float %{{.*}}, %{{.*}}
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn float %{{.*}}, [[RSQRT]]
-// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) float @llvm.spv.normalize.f32(float %{{.*}})
+// CHECK: [[ABS:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) float @llvm.fabs.f32(float %{{.*}})
+// CHECK-NEXT: [[RET:%.*]] = fdiv reassoc nnan ninf nsz arcp afn float %{{.*}}, [[ABS]]
 // CHECK-NEXT: ret float [[RET]]
 float test_normalize_float(float p0)
 {
@@ -68,11 +64,11 @@ float test_normalize_float(float p0)
 
 // CHECK-LABEL: test_normalize_float2
 // DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <2 x float> @llvm.spv.normalize.v2f32(<2 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) float @llvm.spv.length.v2f32(<2 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <2 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <2 x float> [[SPLATINSERT]], <2 x float> poison, <2 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <2 x float> [[RET]]
 float2 test_normalize_float2(float2 p0)
 {
@@ -81,11 +77,11 @@ float2 test_normalize_float2(float2 p0)
 
 // CHECK-LABEL: test_normalize_float3
 // DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <3 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <3 x float> @llvm.spv.normalize.v3f32(<3 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) float @llvm.spv.length.v3f32(<3 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <3 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <3 x float> [[SPLATINSERT]], <3 x float> poison, <3 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <3 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <3 x float> [[RET]]
 float3 test_normalize_float3(float3 p0)
 {
@@ -94,11 +90,11 @@ float3 test_normalize_float3(float3 p0)
 
 // CHECK-LABEL: test_normalize_float4
 // DXCHECK: [[DOT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}})
-// DXCHECK-NEXT: [[RSQRT:%.*]] = call reassoc nnan ninf nsz arcp afn float @llvm.dx.rsqrt.f32(float [[DOT]])
-// DXCHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[RSQRT]], i64 0
-// DXCHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
-// DXCHECK-NEXT: [[RET:%.*]] = fmul reassoc nnan ninf nsz arcp afn <4 x float> %{{.*}}, [[SPLAT]]
-// SPVCHECK: [[RET:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) <4 x float> @llvm.spv.normalize.v4f32(<4 x float> %{{.*}})
+// DXCHECK-NEXT: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) float @llvm.sqrt.f32(float [[DOT]])
+// SPVCHECK: [[LEN:%.*]] = call reassoc nnan ninf nsz arcp afn noundef nofpclass(nan inf) float @llvm.spv.length.v4f32(<4 x float> %{{.*}})
+// CHECK-NEXT: [[SPLATINSERT:%.*]] = insertelement <4 x float> poison, float [[LEN]], i64 0
+// CHECK-NEXT: [[SPLAT:%.*]] = shufflevector <4 x float> [[SPLATINSERT]], <4 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT: [[RET:%.*]] = fdiv reassoc nnan ninf nsz arcp afn <4 x float> %{{.*}}, [[SPLAT]]
 // CHECK-NEXT: ret <4 x float> [[RET]]
 float4 test_normalize_float4(float4 p0)
 {
diff --git a/clang/test/CodeGenSPIRV/Builtins/normalize.c b/clang/test/CodeGenSPIRV/Builtins/normalize.c
deleted file mode 100644
index 87640cb33e19e..0000000000000
--- a/clang/test/CodeGenSPIRV/Builtins/normalize.c
+++ /dev/null
@@ -1,41 +0,0 @@
-// RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-compute %s -emit-llvm -o - | FileCheck %s
-
-typedef _Float16 half;
-typedef half half2 __attribute__((ext_vector_type(2)));
-typedef half half3 __attribute__((ext_vector_type(3)));
-typedef half half4 __attribute__((ext_vector_type(4)));
-typedef float float2 __attribute__((ext_vector_type(2)));
-typedef float float3 __attribute__((ext_vector_type(3)));
-typedef float float4 __attribute__((ext_vector_type(4)));
-
-// CHECK: [[NORM:%.*]] = tail call half @llvm.spv.normalize.f16(half {{%.*}})
-// CHECK: ret half [[NORM]]
-half test_normalize_half(half X) { return __builtin_spirv_normalize(X); }
-
-// CHECK: [[NORM:%.*]] = tail call <2 x half> @llvm.spv.normalize.v2f16(<2 x half> {{%.*}})
-// CHECK: ret <2 x half> [[NORM]]
-half2 test_normalize_half2(half2 X) { return __builtin_spirv_normalize(X); }
-
-// CHECK: [[NORM:%.*]] = tail call <3 x half> @llvm.spv.normalize.v3f16(<3 x half> {{%.*}})
-// CHECK: ret <3 x half> [[NORM]]
-half3 test_normalize_half3(half3 X) { return __builtin_spirv_normalize(X); }
-
-// CHECK: [[NORM:%.*]] = tail call <4 x half> @llvm.spv.normalize.v4f16(<4 x half> {{%.*}})
-// CHECK: ret <4 x half> [[NORM]]
-half4 test_normalize_half4(half4 X) { return __builtin_spirv_normalize(X); }
-
-// CHECK: [[NORM:%.*]] = tail call float @llvm.spv.normalize.f32(float {{%.*}})
-// CHECK: ret float [[NORM]]
-float test_normalize_float(float X) { return __builtin_spirv_normalize(X); }
-
-// CHECK: [[NORM:%.*]] = tail call <2 x float> @llvm.spv.normalize.v2f32(<2 x float> {{%.*}})
-// CHECK: ret <2 x float> [[NORM]]
-float2 test_normalize_float2(float2 X) { return __builtin_spirv_normalize(X); }
-
-// CHECK: [[NORM:%.*]] = tail call <3 x float> @llvm.spv.normalize.v3f32(<3 x float> {{%.*}})
-// CHECK: ret <3 x float> [[NORM]]
-float3 test_normalize_float3(float3 X) { return __builtin_spirv_normalize(X); }
-
-// CHECK: [[NORM:%.*]] = tail call <4 x float> @llvm.spv.normalize.v4f32(<4 x float> {{%.*}})
-// CHECK: ret <4 x float> [[NORM]]
-float4 test_normalize_float4(float4 X) { return __builtin_spirv_normalize(X); }
diff --git a/clang/test/SemaSPIRV/BuiltIns/normalize-errors.c b/clang/test/SemaSPIRV/BuiltIns/normalize-errors.c
deleted file mode 100644
index 7159bc8735279..0000000000000
--- a/clang/test/SemaSPIRV/BuiltIns/normalize-errors.c
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clang_cc1 %s -triple spirv-pc-vulkan-compute -verify
-
-typedef float float2 __attribute__((ext_vector_type(2)));
-
-void test_too_few_arg() {
-  return __builtin_spirv_normalize();
-  // expected-error at -1 {{too few arguments to function call, expected 1, have 0}}
-}
-
-float test_too_many_arg(float p0) {
-  return __builtin_spirv_normalize(p0, p0);
-  // expected-error at -1 {{too many arguments to function call, expected 1, have 2}}
-}
-
-float test_int_scalar_inputs(int p0) {
-  return __builtin_spirv_normalize(p0);
-  //  expected-error at -1 {{1st argument must be a scalar or vector of floating-point types (was 'int')}}
-}
-
-float test_mismatched_return(float2 p0) {
-  return __builtin_spirv_normalize(p0);
-  // expected-error at -1 {{returning 'float2' (vector of 2 'float' values) from a function with incompatible result type 'float'}}
-}
diff --git a/llvm/lib/Target/SPIRV/SPIRVCombine.td b/llvm/lib/Target/SPIRV/SPIRVCombine.td
index 7d69465de4ffb..1ac891ace01fd 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCombine.td
+++ b/llvm/lib/Target/SPIRV/SPIRVCombine.td
@@ -15,6 +15,13 @@ def vector_length_sub_to_distance_lowering : GICombineRule <
   (apply [{ Helper.applySPIRVDistance(*${root}); }])
 >;
 
+def vector_fdiv_length_to_normalize_lowering : GICombineRule <
+  (defs root:$root),
+  (match (wip_match_opcode G_FDIV):$root,
+          [{ return Helper.matchFDivToNormalize(*${root}); }]),
+  (apply [{ Helper.applySPIRVNormalize(*${root}); }])
+>;
+
 def vector_select_to_faceforward_lowering : GICombineRule <
   (defs root:$root),
   (match (wip_match_opcode G_SELECT):$root,
@@ -37,6 +44,7 @@ def matrix_multiply_lowering
 def SPIRVPreLegalizerCombiner
     : GICombiner<"SPIRVPreLegalizerCombinerImpl",
                  [vector_length_sub_to_distance_lowering,
+                  vector_fdiv_length_to_normalize_lowering,
                   vector_select_to_faceforward_lowering,
                   matrix_transpose_lowering, matrix_multiply_lowering]> {
   let CombineAllMethodName = "tryCombineAllImpl";
diff --git a/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.cpp b/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.cpp
index 0882970895452..57233367d8fb1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.cpp
@@ -63,6 +63,53 @@ void SPIRVCombinerHelper::applySPIRVDistance(MachineInstr &MI) const {
   MI.eraseFromParent();
 }
 
+/// This match is part of a combine that
+/// rewrites X / length(X) to normalize(X)
+///   (vXf32 (g_fdiv
+///             (vXf32 X)
+///             (vXf32 splat
+///                    (f32 (g_intrinsic length (vXf32 X))))))
+/// ->
+///   (vXf32 (g_intrinsic normalize (vXf32 X)))
+///
+bool SPIRVCombinerHelper::matchFDivToNormalize(MachineInstr &MI) const {
+  Register NumeratorReg = MI.getOperand(1).getReg();
+  Register DivisorReg = MI.getOperand(2).getReg();
+
+  // The divisor must be a splat (i.e. a shuffle whose all-zeros mask broadcasts
+  // lane 0 to every lane).
+  MachineInstr *ShuffleInstr = MRI.getVRegDef(DivisorReg);
+  if (ShuffleInstr->getOpcode() != TargetOpcode::G_SHUFFLE_VECTOR)
+    return false;
+  if (!all_of(cast<GShuffleVector>(ShuffleInstr)->getMask(),
+              [](int M) { return M == 0; }))
+    return false;
+  MachineInstr *InsertInstr =
+      MRI.getVRegDef(ShuffleInstr->getOperand(1).getReg());
+  if (!isSpvIntrinsic(*InsertInstr, Intrinsic::spv_insertelt))
+    return false;
+
+  MachineInstr *LengthInstr =
+      MRI.getVRegDef(InsertInstr->getOperand(3).getReg());
+  if (!isSpvIntrinsic(*LengthInstr, Intrinsic::spv_length))
+    return false;
+
+  // The numerator must be the same as length's argument.
+  return LengthInstr->getOperand(2).getReg() == NumeratorReg;
+}
+
+void SPIRVCombinerHelper::applySPIRVNormalize(MachineInstr &MI) const {
+  // Extract the operand for X from the match criteria.
+  Register NumeratorReg = MI.getOperand(1).getReg();
+  Register ResultReg = MI.getOperand(0).getReg();
+
+  Builder.setInstrAndDebugLoc(MI);
+  Builder.buildIntrinsic(Intrinsic::spv_normalize, ResultReg)
+      .addUse(NumeratorReg);
+
+  MI.eraseFromParent();
+}
+
 /// This match is part of a combine that
 /// rewrites select(fcmp(dot(I, Ng), 0), N, -N) to faceforward(N, I, Ng)
 ///   (vXf32 (g_select
diff --git a/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.h b/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.h
index 19e2a6901b8f0..cc52c5920a743 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.h
+++ b/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.h
@@ -31,6 +31,8 @@ class SPIRVCombinerHelper : public CombinerHelper {
 
   bool matchLengthToDistance(MachineInstr &MI) const;
   void applySPIRVDistance(MachineInstr &MI) const;
+  bool matchFDivToNormalize(MachineInstr &MI) const;
+  void applySPIRVNormalize(MachineInstr &MI) const;
   bool matchSelectToFaceForward(MachineInstr &MI) const;
   void applySPIRVFaceForward(MachineInstr &MI) const;
   bool matchMatrixTranspose(MachineInstr &MI) const;
diff --git a/llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-fdiv-to-normalize.mir b/llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-fdiv-to-normalize.mir
new file mode 100644
index 0000000000000..fb366cd6c4bf9
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-fdiv-to-normalize.mir
@@ -0,0 +1,27 @@
+# RUN: llc -verify-machineinstrs -O0 -mtriple spirv-unknown-unknown -run-pass=spirv-prelegalizer-combiner %s -o - | FileCheck %s
+---
+name:            normalize_instcombine_float4
+tracksRegLiveness: true
+legalized: true
+body:             |
+  bb.1.entry:
+    ; CHECK-LABEL: name: normalize_instcombine_float4
+    ; CHECK-NOT: %9:_(<4 x s32>) = G_SHUFFLE_VECTOR %8, %5, shufflemask(0, 0, 0, 0)
+    ; CHECK-NOT: %10:id(<4 x s32>) = G_FDIV %2, %9
+    ; CHECK: %10:id(<4 x s32>) = G_INTRINSIC intrinsic(@llvm.spv.normalize), %2(<4 x s32>)
+    %0:type(s64) = OpTypeFloat 32
+    %1:type(s64) = OpTypeVector %0(s64), 4
+    OpName %2(<4 x s32>), 97
+    %3:type(s64) = OpTypeFunction %1(s64), %1(s64)
+    %4:iid(s64) = OpFunction %1(s64), 0, %3(s64)
+    %2:vfid(<4 x s32>) = OpFunctionParameter %1(s64)
+    OpName %4(s64), 1836216174, 2053729377, 1852399461, 1868788851, 1852400237, 1818648421, 880042351, 0
+    OpDecorate %4(s64), 41, 1836216174, 2053729377, 1852399461, 1868788851, 1852400237, 1818648421, 880042351, 0, 0
+    %5:_(<4 x s32>) = G_IMPLICIT_DEF
+    %6:_(s64) = G_CONSTANT i64 0
+    %7:_(s32) = G_INTRINSIC intrinsic(@llvm.spv.length), %2(<4 x s32>)
+    %8:_(<4 x s32>) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.spv.insertelt), %5(<4 x s32>), %7(s32), %6(s64)
+    %9:_(<4 x s32>) = G_SHUFFLE_VECTOR %8(<4 x s32>), %5, shufflemask(0, 0, 0, 0)
+    %10:id(<4 x s32>) = G_FDIV %2, %9
+    OpReturnValue %10(<4 x s32>)
+...
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/normalize.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/normalize.ll
index d23aa69297c90..3eb8a55c976bc 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/normalize.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/normalize.ll
@@ -9,24 +9,6 @@
 ; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
 ; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
 
-define noundef half @normalize_half(half noundef %a) {
-entry:
-  ; CHECK: %[[#]] = OpFunction %[[#float_16]] None %[[#]]
-  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_16]]
-  ; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] Normalize %[[#arg0]]
-  %hlsl.normalize = call half @llvm.spv.normalize.f16(half %a)
-  ret half %hlsl.normalize
-}
-
-define noundef float @normalize_float(float noundef %a) {
-entry:
-  ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]]
-  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_32]]
-  ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] Normalize %[[#arg0]]
-  %hlsl.normalize = call float @llvm.spv.normalize.f32(float %a)
-  ret float %hlsl.normalize
-}
-
 define noundef <4 x half> @normalize_half4(<4 x half> noundef %a) {
 entry:
   ; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]]
@@ -45,7 +27,17 @@ entry:
   ret <4 x float> %hlsl.normalize
 }
 
-declare half @llvm.spv.normalize.f16(half)
-declare float @llvm.spv.normalize.f32(float)
+define noundef <4 x float> @normalize_instcombine_float4(<4 x float> noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#vec4_float_32]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]]
+  ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Normalize %[[#arg0]]
+  %spv.length = call float @llvm.spv.length.f32(<4 x float> %a)
+  %splatinsert = insertelement <4 x float> poison, float %spv.length, i64 0
+  %splat = shufflevector <4 x float> %splatinsert, <4 x float> poison, <4 x i32> zeroinitializer
+  %div = fdiv <4 x float> %a, %splat
+  ret <4 x float> %div
+}
+
 declare <4 x half> @llvm.spv.normalize.v4f16(<4 x half>)
 declare <4 x float> @llvm.spv.normalize.v4f32(<4 x float>)
diff --git a/llvm/test/CodeGen/SPIRV/opencl/normalize.ll b/llvm/test/CodeGen/SPIRV/opencl/normalize.ll
index 82055c38347d8..0bf187a85e01a 100644
--- a/llvm/test/CodeGen/SPIRV/opencl/normalize.ll
+++ b/llvm/test/CodeGen/SPIRV/opencl/normalize.ll
@@ -10,24 +10,6 @@
 ; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
 ; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
 
-define noundef half @normalize_half(half noundef %a) {
-entry:
-  ; CHECK: %[[#]] = OpFunction %[[#float_16]] None %[[#]]
-  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_16]]
-  ; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_cl]] normalize %[[#arg0]]
-  %spv.normalize = call half @llvm.spv.normalize.f16(half %a)
-  ret half %spv.normalize
-}
-
-define noundef float @normalize_float(float noundef %a) {
-entry:
-  ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]]
-  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_32]]
-  ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_cl]] normalize %[[#arg0]]
-  %spv.normalize = call float @llvm.spv.normalize.f32(float %a)
-  ret float %spv.normalize
-}
-
 define noundef <4 x half> @normalize_half4(<4 x half> noundef %a) {
 entry:
   ; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]]
@@ -46,7 +28,17 @@ entry:
   ret <4 x float> %spv.normalize
 }
 
-declare half @llvm.spv.normalize.f16(half)
-declare float @llvm.spv.normalize.f32(float)
+define noundef <4 x float> @normalize_instcombine_float4(<4 x float> noundef %a) {
+entry:
+  ; CHECK: %[[#]] = OpFunction %[[#vec4_float_32]] None %[[#]]
+  ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]]
+  ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_cl]] normalize %[[#arg0]]
+  %spv.length = call float @llvm.spv.length.f32(<4 x float> %a)
+  %splatinsert = insertelement <4 x float> poison, float %spv.length, i64 0
+  %splat = shufflevector <4 x float> %splatinsert, <4 x float> poison, <4 x i32> zeroinitializer
+  %div = fdiv <4 x float> %a, %splat
+  ret <4 x float> %div
+}
+
 declare <4 x half> @llvm.spv.normalize.v4f16(<4 x half>)
 declare <4 x float> @llvm.spv.normalize.v4f32(<4 x float>)



More information about the llvm-commits mailing list