[clang] [llvm] [SPIRV] add pre legalization instruction combine (PR #122839)
Farzon Lotfi via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 17 11:22:22 PST 2025
https://github.com/farzonl updated https://github.com/llvm/llvm-project/pull/122839
>From fb1c27ea34d42b9c141fe9a2d1a5ad8584dfa0a0 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Thu, 9 Jan 2025 19:19:27 -0500
Subject: [PATCH 1/7] [SPIRV] add pre legalization instruction combine - Add
the boilerplate to support instcombine in SPIRV - instcombine length(X-Y) to
distance(X,Y) - switch HLSL's distance intrinsic to not special case for
SPIRV. - fixes #122766
---
clang/include/clang/Basic/BuiltinsSPIRV.td | 6 +
clang/lib/CodeGen/CGBuiltin.cpp | 10 +
clang/lib/Headers/hlsl/hlsl_detail.h | 8 +-
clang/lib/Sema/SemaSPIRV.cpp | 18 ++
clang/test/CodeGenHLSL/builtins/distance.hlsl | 30 ++-
clang/test/CodeGenHLSL/builtins/length.hlsl | 95 +++++--
clang/test/CodeGenSPIRV/Builtins/length.c | 31 +++
clang/test/SemaSPIRV/BuiltIns/length-errors.c | 25 ++
llvm/lib/Target/SPIRV/CMakeLists.txt | 3 +
llvm/lib/Target/SPIRV/SPIRV.h | 2 +
llvm/lib/Target/SPIRV/SPIRV.td | 1 +
llvm/lib/Target/SPIRV/SPIRVCombine.td | 26 ++
.../SPIRV/SPIRVPreLegalizerCombiner.cpp | 252 ++++++++++++++++++
llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp | 2 +
.../CodeGen/SPIRV/hlsl-intrinsics/distance.ll | 77 +++---
llvm/test/CodeGen/SPIRV/opencl/distance.ll | 11 +
16 files changed, 525 insertions(+), 72 deletions(-)
create mode 100644 clang/test/CodeGenSPIRV/Builtins/length.c
create mode 100644 clang/test/SemaSPIRV/BuiltIns/length-errors.c
create mode 100644 llvm/lib/Target/SPIRV/SPIRVCombine.td
create mode 100644 llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index 1e66939b822ef8..f72c555921dfe6 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -13,3 +13,9 @@ def SPIRVDistance : Builtin {
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}
+
+def SPIRVLength : Builtin {
+ let Spellings = ["__builtin_spirv_length"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "void(...)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 2385f2a320b625..b80833fd91884d 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -20528,6 +20528,16 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_distance,
ArrayRef<Value *>{X, Y}, nullptr, "spv.distance");
}
+ case SPIRV::BI__builtin_spirv_length: {
+ Value *X = EmitScalarExpr(E->getArg(0));
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ "length operand must have a float representation");
+ assert(E->getArg(0)->getType()->isVectorType() &&
+ "length operand must be a vector");
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_length,
+ ArrayRef<Value *>{X}, nullptr, "spv.length");
+ }
}
return nullptr;
}
diff --git a/clang/lib/Headers/hlsl/hlsl_detail.h b/clang/lib/Headers/hlsl/hlsl_detail.h
index 3eb4a3dc861e36..b2c8cc6c5c3dbb 100644
--- a/clang/lib/Headers/hlsl/hlsl_detail.h
+++ b/clang/lib/Headers/hlsl/hlsl_detail.h
@@ -61,7 +61,11 @@ length_impl(T X) {
template <typename T, int N>
constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
length_vec_impl(vector<T, N> X) {
+#if (__has_builtin(__builtin_spirv_length))
+ return __builtin_spirv_length(X);
+#else
return __builtin_elementwise_sqrt(__builtin_hlsl_dot(X, X));
+#endif
}
template <typename T>
@@ -73,11 +77,7 @@ distance_impl(T X, T Y) {
template <typename T, int N>
constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
distance_vec_impl(vector<T, N> X, vector<T, N> Y) {
-#if (__has_builtin(__builtin_spirv_distance))
- return __builtin_spirv_distance(X, Y);
-#else
return length_vec_impl(X - Y);
-#endif
}
} // namespace __detail
} // namespace hlsl
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index d2de64826c6eb3..dc49fc79073572 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -51,6 +51,24 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
TheCall->setType(RetTy);
break;
}
+ case SPIRV::BI__builtin_spirv_length: {
+ if (SemaRef.checkArgCount(TheCall, 1))
+ return true;
+ ExprResult A = TheCall->getArg(0);
+ QualType ArgTyA = A.get()->getType();
+ auto *VTy = ArgTyA->getAs<VectorType>();
+ if (VTy == nullptr) {
+ SemaRef.Diag(A.get()->getBeginLoc(),
+ diag::err_typecheck_convert_incompatible)
+ << ArgTyA
+ << SemaRef.Context.getVectorType(ArgTyA, 2, VectorKind::Generic) << 1
+ << 0 << 0;
+ return true;
+ }
+ QualType RetTy = VTy->getElementType();
+ TheCall->setType(RetTy);
+ break;
+ }
}
return false;
}
diff --git a/clang/test/CodeGenHLSL/builtins/distance.hlsl b/clang/test/CodeGenHLSL/builtins/distance.hlsl
index 6952700a87f1df..e830903261c8cf 100644
--- a/clang/test/CodeGenHLSL/builtins/distance.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/distance.hlsl
@@ -33,8 +33,9 @@ half test_distance_half(half X, half Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half2Dv2_DhS_(
// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[X:%.*]], <2 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_DISTANCE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.distance.v2f16(<2 x half> [[X]], <2 x half> [[Y]])
-// SPVCHECK-NEXT: ret half [[SPV_DISTANCE_I]]
+// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x half> [[X]], [[Y]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v2f16(<2 x half> [[SUB_I]])
+// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
//
half test_distance_half2(half2 X, half2 Y) { return distance(X, Y); }
@@ -49,8 +50,9 @@ half test_distance_half2(half2 X, half2 Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half3Dv3_DhS_(
// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[X:%.*]], <3 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_DISTANCE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.distance.v3f16(<3 x half> [[X]], <3 x half> [[Y]])
-// SPVCHECK-NEXT: ret half [[SPV_DISTANCE_I]]
+// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x half> [[X]], [[Y]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v3f16(<3 x half> [[SUB_I]])
+// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
//
half test_distance_half3(half3 X, half3 Y) { return distance(X, Y); }
@@ -65,8 +67,9 @@ half test_distance_half3(half3 X, half3 Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z19test_distance_half4Dv4_DhS_(
// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[X:%.*]], <4 x half> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_DISTANCE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.distance.v4f16(<4 x half> [[X]], <4 x half> [[Y]])
-// SPVCHECK-NEXT: ret half [[SPV_DISTANCE_I]]
+// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x half> [[X]], [[Y]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v4f16(<4 x half> [[SUB_I]])
+// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
//
half test_distance_half4(half4 X, half4 Y) { return distance(X, Y); }
@@ -97,8 +100,9 @@ float test_distance_float(float X, float Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float2Dv2_fS_(
// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[X:%.*]], <2 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_DISTANCE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.distance.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
-// SPVCHECK-NEXT: ret float [[SPV_DISTANCE_I]]
+// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <2 x float> [[X]], [[Y]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v2f32(<2 x float> [[SUB_I]])
+// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
//
float test_distance_float2(float2 X, float2 Y) { return distance(X, Y); }
@@ -113,8 +117,9 @@ float test_distance_float2(float2 X, float2 Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float3Dv3_fS_(
// SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[X:%.*]], <3 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_DISTANCE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.distance.v3f32(<3 x float> [[X]], <3 x float> [[Y]])
-// SPVCHECK-NEXT: ret float [[SPV_DISTANCE_I]]
+// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <3 x float> [[X]], [[Y]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v3f32(<3 x float> [[SUB_I]])
+// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
//
float test_distance_float3(float3 X, float3 Y) { return distance(X, Y); }
@@ -129,7 +134,8 @@ float test_distance_float3(float3 X, float3 Y) { return distance(X, Y); }
// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z20test_distance_float4Dv4_fS_(
// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[X:%.*]], <4 x float> noundef nofpclass(nan inf) [[Y:%.*]]) local_unnamed_addr #[[ATTR0]] {
// SPVCHECK-NEXT: [[ENTRY:.*:]]
-// SPVCHECK-NEXT: [[SPV_DISTANCE_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.distance.v4f32(<4 x float> [[X]], <4 x float> [[Y]])
-// SPVCHECK-NEXT: ret float [[SPV_DISTANCE_I]]
+// SPVCHECK-NEXT: [[SUB_I:%.*]] = fsub reassoc nnan ninf nsz arcp afn <4 x float> [[X]], [[Y]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v4f32(<4 x float> [[SUB_I]])
+// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
//
float test_distance_float4(float4 X, float4 Y) { return distance(X, Y); }
diff --git a/clang/test/CodeGenHLSL/builtins/length.hlsl b/clang/test/CodeGenHLSL/builtins/length.hlsl
index fcf3ee76ba5bbd..2d4bbd995298f2 100644
--- a/clang/test/CodeGenHLSL/builtins/length.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/length.hlsl
@@ -1,114 +1,163 @@
-// RUN: %clang_cc1 -finclude-default-header -triple \
-// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
-// RUN: -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK,DXCHECK \
-// RUN: -DTARGET=dx
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
+// RUN: -emit-llvm -O1 -o - | FileCheck %s
// RUN: %clang_cc1 -finclude-default-header -triple \
// RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \
-// RUN: -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK,SPVCHECK \
-// RUN: -DTARGET=spv
+// RUN: -emit-llvm -O1 -o - | FileCheck %s --check-prefix=SPVCHECK
-// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z16test_length_halfDh(
// DXCHECK-LABEL: define noundef nofpclass(nan inf) half @_Z16test_length_halfDh(
+//
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z16test_length_halfDh(
// CHECK-SAME: half noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.fabs.f16(half [[P0]])
// CHECK-NEXT: ret half [[ELT_ABS_I]]
//
-
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z16test_length_halfDh(
+// SPVCHECK-SAME: half noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.fabs.f16(half [[P0]])
+// SPVCHECK-NEXT: ret half [[ELT_ABS_I]]
+//
half test_length_half(half p0)
{
return length(p0);
}
-// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half2Dv2_Dh(
// DXCHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half2Dv2_Dh(
+//
+
+
+// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half2Dv2_Dh(
// CHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.[[TARGET]].fdot.v2f16(<2 x half> [[P0]], <2 x half> [[P0]])
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v2f16(<2 x half> [[P0]], <2 x half> [[P0]])
// CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.sqrt.f16(half [[HLSL_DOT_I]])
// CHECK-NEXT: ret half [[TMP0]]
//
-
-
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half2Dv2_Dh(
+// SPVCHECK-SAME: <2 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v2f16(<2 x half> [[P0]])
+// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
+//
half test_length_half2(half2 p0)
{
return length(p0);
}
-// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half3Dv3_Dh(
// DXCHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half3Dv3_Dh(
+// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half3Dv3_Dh(
// CHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.[[TARGET]].fdot.v3f16(<3 x half> [[P0]], <3 x half> [[P0]])
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v3f16(<3 x half> [[P0]], <3 x half> [[P0]])
// CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.sqrt.f16(half [[HLSL_DOT_I]])
// CHECK-NEXT: ret half [[TMP0]]
//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half3Dv3_Dh(
+// SPVCHECK-SAME: <3 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v3f16(<3 x half> [[P0]])
+// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
+//
half test_length_half3(half3 p0)
{
return length(p0);
}
-// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half4Dv4_Dh(
// DXCHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half4Dv4_Dh(
+// CHECK-LABEL: define noundef nofpclass(nan inf) half @_Z17test_length_half4Dv4_Dh(
// CHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.[[TARGET]].fdot.v4f16(<4 x half> [[P0]], <4 x half> [[P0]])
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn half @llvm.dx.fdot.v4f16(<4 x half> [[P0]], <4 x half> [[P0]])
// CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.sqrt.f16(half [[HLSL_DOT_I]])
// CHECK-NEXT: ret half [[TMP0]]
//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) half @_Z17test_length_half4Dv4_Dh(
+// SPVCHECK-SAME: <4 x half> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.length.v4f16(<4 x half> [[P0]])
+// SPVCHECK-NEXT: ret half [[SPV_LENGTH_I]]
+//
half test_length_half4(half4 p0)
{
return length(p0);
}
-// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z17test_length_floatf(
// DXCHECK-LABEL: define noundef nofpclass(nan inf) float @_Z17test_length_floatf(
+// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z17test_length_floatf(
// CHECK-SAME: float noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.fabs.f32(float [[P0]])
// CHECK-NEXT: ret float [[ELT_ABS_I]]
//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z17test_length_floatf(
+// SPVCHECK-SAME: float noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[ELT_ABS_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.fabs.f32(float [[P0]])
+// SPVCHECK-NEXT: ret float [[ELT_ABS_I]]
+//
float test_length_float(float p0)
{
return length(p0);
}
-// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float2Dv2_f(
// DXCHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float2Dv2_f(
+// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float2Dv2_f(
// CHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].fdot.v2f32(<2 x float> [[P0]], <2 x float> [[P0]])
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v2f32(<2 x float> [[P0]], <2 x float> [[P0]])
// CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.sqrt.f32(float [[HLSL_DOT_I]])
// CHECK-NEXT: ret float [[TMP0]]
//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float2Dv2_f(
+// SPVCHECK-SAME: <2 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v2f32(<2 x float> [[P0]])
+// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
+//
float test_length_float2(float2 p0)
{
return length(p0);
}
-// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float3Dv3_f(
// DXCHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float3Dv3_f(
+// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float3Dv3_f(
// CHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].fdot.v3f32(<3 x float> [[P0]], <3 x float> [[P0]])
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v3f32(<3 x float> [[P0]], <3 x float> [[P0]])
// CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.sqrt.f32(float [[HLSL_DOT_I]])
// CHECK-NEXT: ret float [[TMP0]]
//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float3Dv3_f(
+// SPVCHECK-SAME: <3 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v3f32(<3 x float> [[P0]])
+// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
+//
float test_length_float3(float3 p0)
{
return length(p0);
}
-// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float4Dv4_f(
// DXCHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float4Dv4_f(
+// CHECK-LABEL: define noundef nofpclass(nan inf) float @_Z18test_length_float4Dv4_f(
// CHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
-// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.[[TARGET]].fdot.v4f32(<4 x float> [[P0]], <4 x float> [[P0]])
+// CHECK-NEXT: [[HLSL_DOT_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn float @llvm.dx.fdot.v4f32(<4 x float> [[P0]], <4 x float> [[P0]])
// CHECK-NEXT: [[TMP0:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.sqrt.f32(float [[HLSL_DOT_I]])
// CHECK-NEXT: ret float [[TMP0]]
//
+// SPVCHECK-LABEL: define spir_func noundef nofpclass(nan inf) float @_Z18test_length_float4Dv4_f(
+// SPVCHECK-SAME: <4 x float> noundef nofpclass(nan inf) [[P0:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// SPVCHECK-NEXT: [[ENTRY:.*:]]
+// SPVCHECK-NEXT: [[SPV_LENGTH_I:%.*]] = tail call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.length.v4f32(<4 x float> [[P0]])
+// SPVCHECK-NEXT: ret float [[SPV_LENGTH_I]]
+//
float test_length_float4(float4 p0)
{
return length(p0);
diff --git a/clang/test/CodeGenSPIRV/Builtins/length.c b/clang/test/CodeGenSPIRV/Builtins/length.c
new file mode 100644
index 00000000000000..59e7c298dd8167
--- /dev/null
+++ b/clang/test/CodeGenSPIRV/Builtins/length.c
@@ -0,0 +1,31 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+
+// RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-compute %s -emit-llvm -o - | FileCheck %s
+
+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-LABEL: define spir_func float @test_length_float2(
+// CHECK-SAME: <2 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_LENGTH:%.*]] = tail call float @llvm.spv.length.v2f32(<2 x float> [[X]])
+// CHECK-NEXT: ret float [[SPV_LENGTH]]
+//
+float test_length_float2(float2 X) { return __builtin_spirv_length(X); }
+
+// CHECK-LABEL: define spir_func float @test_length_float3(
+// CHECK-SAME: <3 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_LENGTH:%.*]] = tail call float @llvm.spv.length.v3f32(<3 x float> [[X]])
+// CHECK-NEXT: ret float [[SPV_LENGTH]]
+//
+float test_length_float3(float3 X) { return __builtin_spirv_length(X); }
+
+// CHECK-LABEL: define spir_func float @test_length_float4(
+// CHECK-SAME: <4 x float> noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: [[SPV_LENGTH:%.*]] = tail call float @llvm.spv.length.v4f32(<4 x float> [[X]])
+// CHECK-NEXT: ret float [[SPV_LENGTH]]
+//
+float test_length_float4(float4 X) { return __builtin_spirv_length(X); }
diff --git a/clang/test/SemaSPIRV/BuiltIns/length-errors.c b/clang/test/SemaSPIRV/BuiltIns/length-errors.c
new file mode 100644
index 00000000000000..3244bd6737f116
--- /dev/null
+++ b/clang/test/SemaSPIRV/BuiltIns/length-errors.c
@@ -0,0 +1,25 @@
+// 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_length();
+ // expected-error at -1 {{too few arguments to function call, expected 1, have 0}}
+}
+
+void test_too_many_arg(float2 p0)
+{
+ return __builtin_spirv_length(p0, p0);
+ // expected-error at -1 {{too many arguments to function call, expected 1, have 2}}
+}
+
+float test_double_scalar_inputs(double p0) {
+ return __builtin_spirv_length(p0);
+ // expected-error at -1 {{passing 'double' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(double)))) double' (vector of 2 'double' values)}}
+}
+
+float test_int_scalar_inputs(int p0) {
+ return __builtin_spirv_length(p0);
+ // expected-error at -1 {{passing 'int' to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(int)))) int' (vector of 2 'int' values)}}
+}
diff --git a/llvm/lib/Target/SPIRV/CMakeLists.txt b/llvm/lib/Target/SPIRV/CMakeLists.txt
index a79e19fcd753dc..efdd8c8d24fbd5 100644
--- a/llvm/lib/Target/SPIRV/CMakeLists.txt
+++ b/llvm/lib/Target/SPIRV/CMakeLists.txt
@@ -10,6 +10,8 @@ tablegen(LLVM SPIRVGenRegisterBank.inc -gen-register-bank)
tablegen(LLVM SPIRVGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM SPIRVGenSubtargetInfo.inc -gen-subtarget)
tablegen(LLVM SPIRVGenTables.inc -gen-searchable-tables)
+tablegen(LLVM SPIRVGenPreLegalizeGICombiner.inc -gen-global-isel-combiner
+ -combiners="SPIRVPreLegalizerCombiner")
add_public_tablegen_target(SPIRVCommonTableGen)
@@ -33,6 +35,7 @@ add_llvm_target(SPIRVCodeGen
SPIRVModuleAnalysis.cpp
SPIRVStructurizer.cpp
SPIRVPreLegalizer.cpp
+ SPIRVPreLegalizerCombiner.cpp
SPIRVPostLegalizer.cpp
SPIRVPrepareFunctions.cpp
SPIRVRegisterBankInfo.cpp
diff --git a/llvm/lib/Target/SPIRV/SPIRV.h b/llvm/lib/Target/SPIRV/SPIRV.h
index 81b57202644256..6d00a046ff7caa 100644
--- a/llvm/lib/Target/SPIRV/SPIRV.h
+++ b/llvm/lib/Target/SPIRV/SPIRV.h
@@ -24,6 +24,7 @@ FunctionPass *createSPIRVStructurizerPass();
FunctionPass *createSPIRVMergeRegionExitTargetsPass();
FunctionPass *createSPIRVStripConvergenceIntrinsicsPass();
FunctionPass *createSPIRVRegularizerPass();
+FunctionPass *createSPIRVPreLegalizerCombiner();
FunctionPass *createSPIRVPreLegalizerPass();
FunctionPass *createSPIRVPostLegalizerPass();
ModulePass *createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM);
@@ -36,6 +37,7 @@ createSPIRVInstructionSelector(const SPIRVTargetMachine &TM,
void initializeSPIRVModuleAnalysisPass(PassRegistry &);
void initializeSPIRVConvergenceRegionAnalysisWrapperPassPass(PassRegistry &);
void initializeSPIRVPreLegalizerPass(PassRegistry &);
+void initializeSPIRVPreLegalizerCombinerPass(PassRegistry &);
void initializeSPIRVPostLegalizerPass(PassRegistry &);
void initializeSPIRVStructurizerPass(PassRegistry &);
void initializeSPIRVEmitIntrinsicsPass(PassRegistry &);
diff --git a/llvm/lib/Target/SPIRV/SPIRV.td b/llvm/lib/Target/SPIRV/SPIRV.td
index 108c7e6d3861f0..39a4131c7f1bdf 100644
--- a/llvm/lib/Target/SPIRV/SPIRV.td
+++ b/llvm/lib/Target/SPIRV/SPIRV.td
@@ -11,6 +11,7 @@ include "llvm/Target/Target.td"
include "SPIRVRegisterInfo.td"
include "SPIRVRegisterBanks.td"
include "SPIRVInstrInfo.td"
+include "SPIRVCombine.td"
include "SPIRVBuiltins.td"
def SPIRVInstrInfo : InstrInfo;
diff --git a/llvm/lib/Target/SPIRV/SPIRVCombine.td b/llvm/lib/Target/SPIRV/SPIRVCombine.td
new file mode 100644
index 00000000000000..11851894e2f752
--- /dev/null
+++ b/llvm/lib/Target/SPIRV/SPIRVCombine.td
@@ -0,0 +1,26 @@
+//=- SPIRVCombine.td - Define SPIRV Combine Rules -------------*-tablegen -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+include "llvm/Target/GlobalISel/Combine.td"
+
+
+def vector_length_sub_to_distance_lowering : GICombineRule <
+ (defs root:$root),
+ (match (wip_match_opcode G_INTRINSIC):$root,
+ [{ return matchLengthToDistance(*${root}, MRI); }]),
+ (apply [{ applySPIRVDistance(*${root}, MRI, B); }])
+>;
+
+def SPIRVPreLegalizerCombiner
+ : GICombiner<"SPIRVPreLegalizerCombinerImpl",
+ [vector_length_sub_to_distance_lowering]> {
+ let CombineAllMethodName = "tryCombineAllImpl";
+}
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
new file mode 100644
index 00000000000000..54b65e8b04d622
--- /dev/null
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
@@ -0,0 +1,252 @@
+
+//===-- SPIRVPreLegalizerCombiner.cpp - combine legalization ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass does combining of machine instructions at the generic MI level,
+// before the legalizer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SPIRV.h"
+#include "SPIRVTargetMachine.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/CodeGen/GlobalISel/CSEInfo.h"
+#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
+#include "llvm/CodeGen/GlobalISel/Combiner.h"
+#include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
+#include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
+#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
+#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
+#include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
+#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
+#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/GlobalISel/Utils.h"
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetOpcodes.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/IntrinsicsSPIRV.h"
+#include "llvm/Support/Debug.h"
+
+#define GET_GICOMBINER_DEPS
+#include "SPIRVGenPreLegalizeGICombiner.inc"
+#undef GET_GICOMBINER_DEPS
+
+#define DEBUG_TYPE "spirv-prelegalizer-combiner"
+
+using namespace llvm;
+using namespace MIPatternMatch;
+
+namespace {
+
+#define GET_GICOMBINER_TYPES
+#include "SPIRVGenPreLegalizeGICombiner.inc"
+#undef GET_GICOMBINER_TYPES
+
+bool matchLengthToDistance(MachineInstr &MI, MachineRegisterInfo &MRI) {
+ if (MI.getOpcode() != TargetOpcode::G_INTRINSIC ||
+ cast<GIntrinsic>(MI).getIntrinsicID() != Intrinsic::spv_length)
+ return false;
+
+ // First operand of MI is `G_INTRINSIC` so start at operand 2.
+ Register SubAssignTypeReg = MI.getOperand(2).getReg();
+ MachineInstr *Sub1AssignTypeInst = MRI.getVRegDef(SubAssignTypeReg);
+ if (!Sub1AssignTypeInst ||
+ Sub1AssignTypeInst->getDesc().getOpcode() != SPIRV::ASSIGN_TYPE)
+ return false;
+
+ Register SubReg1 = Sub1AssignTypeInst->getOperand(1).getReg();
+ MachineInstr *SubInstr1 = MRI.getVRegDef(SubReg1);
+ if (!SubInstr1 || SubInstr1->getOpcode() != TargetOpcode::G_FSUB)
+ return false;
+
+ return true;
+}
+void applySPIRVDistance(MachineInstr &MI, MachineRegisterInfo &MRI,
+ MachineIRBuilder &B) {
+
+ // Extract the operands for X and Y from the match criteria.
+ Register SubAssignTypeReg = MI.getOperand(2).getReg();
+ MachineInstr *Sub1AssignTypeInst = MRI.getVRegDef(SubAssignTypeReg);
+ Register SubDestReg = Sub1AssignTypeInst->getOperand(1).getReg();
+ MachineInstr *SubInstr = MRI.getVRegDef(SubDestReg);
+ Register SubOperand1 = SubInstr->getOperand(1).getReg();
+ Register SubOperand2 = SubInstr->getOperand(2).getReg();
+
+ // Remove the original `spv_length` instruction.
+
+ Register ResultReg = MI.getOperand(0).getReg();
+ DebugLoc DL = MI.getDebugLoc();
+ MachineBasicBlock &MBB = *MI.getParent();
+ MachineBasicBlock::iterator InsertPt = MI.getIterator();
+
+ // Build the `spv_distance` intrinsic.
+ MachineInstrBuilder NewInstr =
+ BuildMI(MBB, InsertPt, DL, B.getTII().get(TargetOpcode::G_INTRINSIC));
+ NewInstr
+ .addDef(ResultReg) // Result register
+ .addIntrinsicID(Intrinsic::spv_distance) // Intrinsic ID
+ .addUse(SubOperand1) // Operand X
+ .addUse(SubOperand2); // Operand Y
+
+ auto RemoveAllUses = [&](Register Reg) {
+ for (auto &UseMI : MRI.use_instructions(Reg)) {
+ UseMI.eraseFromParent();
+ }
+ };
+
+ RemoveAllUses(
+ SubAssignTypeReg); // remove all uses of FSUB ASSIGN_TYPE register
+ MI.eraseFromParent(); // remove spv_length intrinsic
+ RemoveAllUses(SubDestReg); // remove all uses of FSUB Result
+ SubInstr->eraseFromParent(); // remove FSUB instruction
+}
+
+class SPIRVPreLegalizerCombinerImpl : public Combiner {
+protected:
+ const CombinerHelper Helper;
+ const SPIRVPreLegalizerCombinerImplRuleConfig &RuleConfig;
+ const SPIRVSubtarget &STI;
+
+public:
+ SPIRVPreLegalizerCombinerImpl(
+ MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
+ GISelKnownBits &KB, GISelCSEInfo *CSEInfo,
+ const SPIRVPreLegalizerCombinerImplRuleConfig &RuleConfig,
+ const SPIRVSubtarget &STI, MachineDominatorTree *MDT,
+ const LegalizerInfo *LI);
+
+ static const char *getName() { return "SPIRV00PreLegalizerCombiner"; }
+
+ bool tryCombineAll(MachineInstr &I) const override;
+
+ bool tryCombineAllImpl(MachineInstr &I) const;
+
+private:
+#define GET_GICOMBINER_CLASS_MEMBERS
+#include "SPIRVGenPreLegalizeGICombiner.inc"
+#undef GET_GICOMBINER_CLASS_MEMBERS
+};
+
+#define GET_GICOMBINER_IMPL
+#include "SPIRVGenPreLegalizeGICombiner.inc"
+#undef GET_GICOMBINER_IMPL
+
+SPIRVPreLegalizerCombinerImpl::SPIRVPreLegalizerCombinerImpl(
+ MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC,
+ GISelKnownBits &KB, GISelCSEInfo *CSEInfo,
+ const SPIRVPreLegalizerCombinerImplRuleConfig &RuleConfig,
+ const SPIRVSubtarget &STI, MachineDominatorTree *MDT,
+ const LegalizerInfo *LI)
+ : Combiner(MF, CInfo, TPC, &KB, CSEInfo),
+ Helper(Observer, B, /*IsPreLegalize*/ true, &KB, MDT, LI),
+ RuleConfig(RuleConfig), STI(STI),
+#define GET_GICOMBINER_CONSTRUCTOR_INITS
+#include "SPIRVGenPreLegalizeGICombiner.inc"
+#undef GET_GICOMBINER_CONSTRUCTOR_INITS
+{
+}
+
+bool SPIRVPreLegalizerCombinerImpl::tryCombineAll(MachineInstr &MI) const {
+ return tryCombineAllImpl(MI);
+}
+
+// Pass boilerplate
+// ================
+
+class SPIRVPreLegalizerCombiner : public MachineFunctionPass {
+public:
+ static char ID;
+
+ SPIRVPreLegalizerCombiner();
+
+ StringRef getPassName() const override { return "SPIRVPreLegalizerCombiner"; }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+ SPIRVPreLegalizerCombinerImplRuleConfig RuleConfig;
+};
+
+} // end anonymous namespace
+
+void SPIRVPreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addRequired<TargetPassConfig>();
+ AU.setPreservesCFG();
+ getSelectionDAGFallbackAnalysisUsage(AU);
+ AU.addRequired<GISelKnownBitsAnalysis>();
+ AU.addPreserved<GISelKnownBitsAnalysis>();
+ AU.addRequired<MachineDominatorTreeWrapperPass>();
+ AU.addPreserved<MachineDominatorTreeWrapperPass>();
+ AU.addRequired<GISelCSEAnalysisWrapperPass>();
+ AU.addPreserved<GISelCSEAnalysisWrapperPass>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+}
+
+SPIRVPreLegalizerCombiner::SPIRVPreLegalizerCombiner()
+ : MachineFunctionPass(ID) {
+ initializeSPIRVPreLegalizerCombinerPass(*PassRegistry::getPassRegistry());
+
+ if (!RuleConfig.parseCommandLineOption())
+ report_fatal_error("Invalid rule identifier");
+}
+
+bool SPIRVPreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
+ if (MF.getProperties().hasProperty(
+ MachineFunctionProperties::Property::FailedISel))
+ return false;
+ auto &TPC = getAnalysis<TargetPassConfig>();
+
+ // Enable CSE.
+ GISelCSEAnalysisWrapper &Wrapper =
+ getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
+ auto *CSEInfo = &Wrapper.get(TPC.getCSEConfig());
+
+ const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
+ const auto *LI = ST.getLegalizerInfo();
+
+ const Function &F = MF.getFunction();
+ bool EnableOpt =
+ MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !skipFunction(F);
+ GISelKnownBits *KB = &getAnalysis<GISelKnownBitsAnalysis>().get(MF);
+ MachineDominatorTree *MDT =
+ &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
+ CombinerInfo CInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false,
+ /*LegalizerInfo*/ nullptr, EnableOpt, F.hasOptSize(),
+ F.hasMinSize());
+ // Disable fixed-point iteration to reduce compile-time
+ CInfo.MaxIterations = 1;
+ CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
+ // This is the first Combiner, so the input IR might contain dead
+ // instructions.
+ CInfo.EnableFullDCE = true;
+ SPIRVPreLegalizerCombinerImpl Impl(MF, CInfo, &TPC, *KB, CSEInfo, RuleConfig,
+ ST, MDT, LI);
+ return Impl.combineMachineInstrs();
+}
+
+char SPIRVPreLegalizerCombiner::ID = 0;
+INITIALIZE_PASS_BEGIN(SPIRVPreLegalizerCombiner, DEBUG_TYPE,
+ "Combine SPIRV machine instrs before legalization", false,
+ false)
+INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
+INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis)
+INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)
+INITIALIZE_PASS_END(SPIRVPreLegalizerCombiner, DEBUG_TYPE,
+ "Combine SPIRV machine instrs before legalization", false,
+ false)
+
+namespace llvm {
+FunctionPass *createSPIRVPreLegalizerCombiner() {
+ return new SPIRVPreLegalizerCombiner();
+}
+} // end namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
index dca67cb6c632bd..c9cee09cafca3f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
@@ -48,6 +48,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() {
initializeSPIRVModuleAnalysisPass(PR);
initializeSPIRVConvergenceRegionAnalysisWrapperPassPass(PR);
initializeSPIRVStructurizerPass(PR);
+ initializeSPIRVPreLegalizerCombinerPass(PR);
}
static std::string computeDataLayout(const Triple &TT) {
@@ -218,6 +219,7 @@ bool SPIRVPassConfig::addIRTranslator() {
void SPIRVPassConfig::addPreLegalizeMachineIR() {
addPass(createSPIRVPreLegalizerPass());
+ addPass(createSPIRVPreLegalizerCombiner());
}
// Use the default legalizer.
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/distance.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/distance.ll
index 85a24a0127ae04..fac5d5f9fbd0d2 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/distance.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/distance.ll
@@ -1,33 +1,44 @@
-; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
-
-; Make sure SPIRV operation function calls for distance are lowered correctly.
-
-; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
-; 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 @distance_half4(<4 x half> noundef %a, <4 x half> noundef %b) {
-entry:
- ; CHECK: %[[#]] = OpFunction %[[#float_16]] None %[[#]]
- ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]]
- ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_16]]
- ; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] Distance %[[#arg0]] %[[#arg1]]
- %spv.distance = call half @llvm.spv.distance.f16(<4 x half> %a, <4 x half> %b)
- ret half %spv.distance
-}
-
-define noundef float @distance_float4(<4 x float> noundef %a, <4 x float> noundef %b) {
-entry:
- ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]]
- ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]]
- ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_32]]
- ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] Distance %[[#arg0]] %[[#arg1]]
- %spv.distance = call float @llvm.spv.distance.f32(<4 x float> %a, <4 x float> %b)
- ret float %spv.distance
-}
-
-declare half @llvm.spv.distance.f16(<4 x half>, <4 x half>)
-declare float @llvm.spv.distance.f32(<4 x float>, <4 x float>)
+; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Make sure SPIRV operation function calls for distance are lowered correctly.
+
+; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
+; 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 @distance_half4(<4 x half> noundef %a, <4 x half> noundef %b) {
+entry:
+ ; CHECK: %[[#]] = OpFunction %[[#float_16]] None %[[#]]
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]]
+ ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_16]]
+ ; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] Distance %[[#arg0]] %[[#arg1]]
+ %spv.distance = call half @llvm.spv.distance.f16(<4 x half> %a, <4 x half> %b)
+ ret half %spv.distance
+}
+
+define noundef float @distance_float4(<4 x float> noundef %a, <4 x float> noundef %b) {
+entry:
+ ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]]
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]]
+ ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_32]]
+ ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] Distance %[[#arg0]] %[[#arg1]]
+ %spv.distance = call float @llvm.spv.distance.f32(<4 x float> %a, <4 x float> %b)
+ ret float %spv.distance
+}
+
+define noundef float @distance_instcombine_float4(<4 x float> noundef %a, <4 x float> noundef %b) {
+entry:
+ ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]]
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]]
+ ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_32]]
+ ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] Distance %[[#arg0]] %[[#arg1]]
+ %delta = fsub <4 x float> %a, %b
+ %spv.length = call float @llvm.spv.length.f32(<4 x float> %delta)
+ ret float %spv.length
+}
+
+declare half @llvm.spv.distance.f16(<4 x half>, <4 x half>)
+declare float @llvm.spv.distance.f32(<4 x float>, <4 x float>)
diff --git a/llvm/test/CodeGen/SPIRV/opencl/distance.ll b/llvm/test/CodeGen/SPIRV/opencl/distance.ll
index ac18804c00c9ab..ed329175e9c07f 100644
--- a/llvm/test/CodeGen/SPIRV/opencl/distance.ll
+++ b/llvm/test/CodeGen/SPIRV/opencl/distance.ll
@@ -30,5 +30,16 @@ entry:
ret float %spv.distance
}
+define noundef float @distance_instcombine_float4(<4 x float> noundef %a, <4 x float> noundef %b) {
+entry:
+ ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]]
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]]
+ ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_32]]
+ ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_cl]] distance %[[#arg0]] %[[#arg1]]
+ %delta = fsub <4 x float> %a, %b
+ %spv.length = call float @llvm.spv.length.f32(<4 x float> %delta)
+ ret float %spv.length
+}
+
declare half @llvm.spv.distance.f16(<4 x half>, <4 x half>)
declare float @llvm.spv.distance.f32(<4 x float>, <4 x float>)
>From e6dd5ebaa37a827b222f2f990b4dfb405b7d0e2e Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Wed, 15 Jan 2025 13:12:25 -0500
Subject: [PATCH 2/7] address pr comments
---
llvm/lib/Target/SPIRV/SPIRVCombine.td | 4 ----
1 file changed, 4 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVCombine.td b/llvm/lib/Target/SPIRV/SPIRVCombine.td
index 11851894e2f752..6f726e024de525 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCombine.td
+++ b/llvm/lib/Target/SPIRV/SPIRVCombine.td
@@ -4,10 +4,6 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
-//===----------------------------------------------------------------------===//
-//
-//
-//===----------------------------------------------------------------------===//
include "llvm/Target/GlobalISel/Combine.td"
>From 763f6d41e951f81e6c3bb10f07f3c6b1258c689f Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Thu, 16 Jan 2025 14:07:44 -0500
Subject: [PATCH 3/7] address pr comments describing transformation
---
llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
index 54b65e8b04d622..fbe0c8ad9de5be 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
@@ -50,6 +50,14 @@ namespace {
#include "SPIRVGenPreLegalizeGICombiner.inc"
#undef GET_GICOMBINER_TYPES
+/// This match is part of a combine that
+/// rewrites length(X - Y) to distance(X, Y)
+/// (f32 (g_intrinsic length
+/// (g_fsub (vXf32 X) (vXf32 Y))))
+/// ->
+/// (f32 (g_intrinsic distance
+/// (vXf32 X) (vXf32 Y)))
+///
bool matchLengthToDistance(MachineInstr &MI, MachineRegisterInfo &MRI) {
if (MI.getOpcode() != TargetOpcode::G_INTRINSIC ||
cast<GIntrinsic>(MI).getIntrinsicID() != Intrinsic::spv_length)
>From a4e01af2d0a0ad4ecaafdb2b738439ba745257cd Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Thu, 16 Jan 2025 23:23:35 -0500
Subject: [PATCH 4/7] - Add llc-pipeline test to track pass run ordering - move
instcombine before spirv-prelegalizer simplifies the matcher - update
matcher and inst combine application - make SPIRVPreLegalizer preserve
previous passes.
---
llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp | 9 ++
.../SPIRV/SPIRVPreLegalizerCombiner.cpp | 32 ++--
llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp | 2 +-
llvm/test/CodeGen/SPIRV/llc-pipeline.ll | 140 ++++++++++++++++++
4 files changed, 162 insertions(+), 21 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/llc-pipeline.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index 5b4c84918ab48d..48aad9f5f420e1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -17,6 +17,8 @@
#include "SPIRVUtils.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/CodeGen/GlobalISel/CSEInfo.h"
+#include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
@@ -35,9 +37,16 @@ class SPIRVPreLegalizer : public MachineFunctionPass {
initializeSPIRVPreLegalizerPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
};
} // namespace
+void SPIRVPreLegalizer::getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addPreserved<GISelKnownBitsAnalysis>();
+ AU.addPreserved<GISelCSEAnalysisWrapperPass>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+}
+
static void
addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR,
const SPIRVSubtarget &STI,
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
index fbe0c8ad9de5be..0abe995ea9d4ae 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
@@ -64,15 +64,9 @@ bool matchLengthToDistance(MachineInstr &MI, MachineRegisterInfo &MRI) {
return false;
// First operand of MI is `G_INTRINSIC` so start at operand 2.
- Register SubAssignTypeReg = MI.getOperand(2).getReg();
- MachineInstr *Sub1AssignTypeInst = MRI.getVRegDef(SubAssignTypeReg);
- if (!Sub1AssignTypeInst ||
- Sub1AssignTypeInst->getDesc().getOpcode() != SPIRV::ASSIGN_TYPE)
- return false;
-
- Register SubReg1 = Sub1AssignTypeInst->getOperand(1).getReg();
- MachineInstr *SubInstr1 = MRI.getVRegDef(SubReg1);
- if (!SubInstr1 || SubInstr1->getOpcode() != TargetOpcode::G_FSUB)
+ Register SubReg = MI.getOperand(2).getReg();
+ MachineInstr *SubInstr = MRI.getVRegDef(SubReg);
+ if (!SubInstr || SubInstr->getOpcode() != TargetOpcode::G_FSUB)
return false;
return true;
@@ -81,9 +75,7 @@ void applySPIRVDistance(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &B) {
// Extract the operands for X and Y from the match criteria.
- Register SubAssignTypeReg = MI.getOperand(2).getReg();
- MachineInstr *Sub1AssignTypeInst = MRI.getVRegDef(SubAssignTypeReg);
- Register SubDestReg = Sub1AssignTypeInst->getOperand(1).getReg();
+ Register SubDestReg = MI.getOperand(2).getReg();
MachineInstr *SubInstr = MRI.getVRegDef(SubDestReg);
Register SubOperand1 = SubInstr->getOperand(1).getReg();
Register SubOperand2 = SubInstr->getOperand(2).getReg();
@@ -105,14 +97,14 @@ void applySPIRVDistance(MachineInstr &MI, MachineRegisterInfo &MRI,
.addUse(SubOperand2); // Operand Y
auto RemoveAllUses = [&](Register Reg) {
- for (auto &UseMI : MRI.use_instructions(Reg)) {
- UseMI.eraseFromParent();
- }
- };
+ SmallVector<MachineInstr *, 4> UsesToErase;
+ for (auto &UseMI : MRI.use_instructions(Reg))
+ UsesToErase.push_back(&UseMI);
- RemoveAllUses(
- SubAssignTypeReg); // remove all uses of FSUB ASSIGN_TYPE register
- MI.eraseFromParent(); // remove spv_length intrinsic
+ // calling eraseFromParent to early invalidates the iterator.
+ for (auto *MIToErase : UsesToErase)
+ MIToErase->eraseFromParent();
+ };
RemoveAllUses(SubDestReg); // remove all uses of FSUB Result
SubInstr->eraseFromParent(); // remove FSUB instruction
}
@@ -131,7 +123,7 @@ class SPIRVPreLegalizerCombinerImpl : public Combiner {
const SPIRVSubtarget &STI, MachineDominatorTree *MDT,
const LegalizerInfo *LI);
- static const char *getName() { return "SPIRV00PreLegalizerCombiner"; }
+ static const char *getName() { return "SPIRVPreLegalizerCombiner"; }
bool tryCombineAll(MachineInstr &I) const override;
diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
index c9cee09cafca3f..098c7a6fba50ed 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
@@ -218,8 +218,8 @@ bool SPIRVPassConfig::addIRTranslator() {
}
void SPIRVPassConfig::addPreLegalizeMachineIR() {
- addPass(createSPIRVPreLegalizerPass());
addPass(createSPIRVPreLegalizerCombiner());
+ addPass(createSPIRVPreLegalizerPass());
}
// Use the default legalizer.
diff --git a/llvm/test/CodeGen/SPIRV/llc-pipeline.ll b/llvm/test/CodeGen/SPIRV/llc-pipeline.ll
new file mode 100644
index 00000000000000..2c7d3fded25fba
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/llc-pipeline.ll
@@ -0,0 +1,140 @@
+; RUN: llc -mtriple=spirv-unknown-unknown -debug-pass=Structure < %s -o /dev/null 2>&1 | \
+; RUN: grep -v "Verify generated machine code" | FileCheck %s
+
+; REQUIRES: asserts
+
+
+; CHECK-LABEL: Pass Arguments:
+; CHECK-NEXT: Target Library Information
+; CHECK-NEXT: Target Pass Configuration
+; CHECK-NEXT: Machine Module Information
+; CHECK-NEXT: Target Transform Information
+; CHECK-NEXT: Type-Based Alias Analysis
+; CHECK-NEXT: Scoped NoAlias Alias Analysis
+; CHECK-NEXT: Assumption Cache Tracker
+; CHECK-NEXT: Profile summary info
+; CHECK-NEXT: Create Garbage Collector Module Metadata
+; CHECK-NEXT: Machine Branch Probability Analysis
+; CHECK-NEXT: ModulePass Manager
+; CHECK-NEXT: Pre-ISel Intrinsic Lowering
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Expand large div/rem
+; CHECK-NEXT: Expand large fp convert
+; CHECK-NEXT: Module Verifier
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
+; CHECK-NEXT: Natural Loop Information
+; CHECK-NEXT: Canonicalize natural loops
+; CHECK-NEXT: Scalar Evolution Analysis
+; CHECK-NEXT: Loop Pass Manager
+; CHECK-NEXT: Canonicalize Freeze Instructions in Loops
+; CHECK-NEXT: Induction Variable Users
+; CHECK-NEXT: Loop Strength Reduction
+; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
+; CHECK-NEXT: Function Alias Analysis Results
+; CHECK-NEXT: Merge contiguous icmps into a memcmp
+; CHECK-NEXT: Natural Loop Information
+; CHECK-NEXT: Lazy Branch Probability Analysis
+; CHECK-NEXT: Lazy Block Frequency Analysis
+; CHECK-NEXT: Expand memcmp() to load/stores
+; CHECK-NEXT: Lower Garbage Collection Instructions
+; CHECK-NEXT: Shadow Stack GC Lowering
+; CHECK-NEXT: Remove unreachable blocks from the CFG
+; CHECK-NEXT: Natural Loop Information
+; CHECK-NEXT: Post-Dominator Tree Construction
+; CHECK-NEXT: Branch Probability Analysis
+; CHECK-NEXT: Block Frequency Analysis
+; CHECK-NEXT: Constant Hoisting
+; CHECK-NEXT: Replace intrinsics with calls to vector library
+; CHECK-NEXT: Partially inline calls to library functions
+; CHECK-NEXT: Instrument function entry/exit with calls to e.g. mcount() (post inlining)
+; CHECK-NEXT: Scalarize Masked Memory Intrinsics
+; CHECK-NEXT: Expand reduction intrinsics
+; CHECK-NEXT: Natural Loop Information
+; CHECK-NEXT: Canonicalize natural loops
+; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
+; CHECK-NEXT: SPIRV convergence regions analysis
+; CHECK-NEXT: SPIRV split region exit blocks
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Natural Loop Information
+; CHECK-NEXT: structurize SPIRV
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Promote Memory to Register
+; CHECK-NEXT: SPIR-V Regularizer
+; CHECK-NEXT: SPIRV prepare functions
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: SPIRV strip convergent intrinsics
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Natural Loop Information
+; CHECK-NEXT: CodeGen Prepare
+; CHECK-NEXT: Lower invoke and unwind, for unwindless code generators
+; CHECK-NEXT: Remove unreachable blocks from the CFG
+; CHECK-NEXT: SPIRV emit intrinsics
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
+; CHECK-NEXT: Function Alias Analysis Results
+; CHECK-NEXT: ObjC ARC contraction
+; CHECK-NEXT: Prepare callbr
+; CHECK-NEXT: Safe Stack instrumentation pass
+; CHECK-NEXT: Insert stack protectors
+; CHECK-NEXT: Module Verifier
+; CHECK-NEXT: Analysis containing CSE Info
+; CHECK-NEXT: Natural Loop Information
+; CHECK-NEXT: Post-Dominator Tree Construction
+; CHECK-NEXT: Branch Probability Analysis
+; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
+; CHECK-NEXT: Function Alias Analysis Results
+; CHECK-NEXT: IRTranslator
+; CHECK-NEXT: Analysis for ComputingKnownBits
+; CHECK-NEXT: MachineDominator Tree Construction
+; CHECK-NEXT: Analysis containing CSE Info
+; CHECK-NEXT: SPIRVPreLegalizerCombiner
+; CHECK-NEXT: SPIRV pre legalizer
+; CHECK-NEXT: Legalizer
+; CHECK-NEXT: SPIRV post legalizer
+; CHECK-NEXT: Analysis for ComputingKnownBits
+; CHECK-NEXT: Lazy Branch Probability Analysis
+; CHECK-NEXT: Lazy Block Frequency Analysis
+; CHECK-NEXT: InstructionSelect
+; CHECK-NEXT: ResetMachineFunction
+; CHECK-NEXT: Finalize ISel and expand pseudo-instructions
+; CHECK-NEXT: Lazy Machine Block Frequency Analysis
+; CHECK-NEXT: Early Tail Duplication
+; CHECK-NEXT: Optimize machine instruction PHIs
+; CHECK-NEXT: Slot index numbering
+; CHECK-NEXT: Merge disjoint stack slots
+; CHECK-NEXT: Local Stack Slot Allocation
+; CHECK-NEXT: Remove dead machine instructions
+; CHECK-NEXT: MachineDominator Tree Construction
+; CHECK-NEXT: Machine Natural Loop Construction
+; CHECK-NEXT: Machine Block Frequency Analysis
+; CHECK-NEXT: Early Machine Loop Invariant Code Motion
+; CHECK-NEXT: MachineDominator Tree Construction
+; CHECK-NEXT: Machine Block Frequency Analysis
+; CHECK-NEXT: Machine Common Subexpression Elimination
+; CHECK-NEXT: MachinePostDominator Tree Construction
+; CHECK-NEXT: Machine Cycle Info Analysis
+; CHECK-NEXT: Machine code sinking
+; CHECK-NEXT: Peephole Optimizations
+; CHECK-NEXT: Remove dead machine instructions
+; CHECK-NEXT: Remove Redundant DEBUG_VALUE analysis
+; CHECK-NEXT: Fixup Statepoint Caller Saved
+; CHECK-NEXT: Lazy Machine Block Frequency Analysis
+; CHECK-NEXT: Machine Optimization Remark Emitter
+; CHECK-NEXT: Prologue/Epilogue Insertion & Frame Finalization
+; CHECK-NEXT: Tail Duplication
+; CHECK-NEXT: Post-RA pseudo instruction expansion pass
+; CHECK-NEXT: Analyze Machine Code For Garbage Collection
+; CHECK-NEXT: Insert fentry calls
+; CHECK-NEXT: Insert XRay ops
+; CHECK-NEXT: Machine Sanitizer Binary Metadata
+; CHECK-NEXT: Lazy Machine Block Frequency Analysis
+; CHECK-NEXT: Machine Optimization Remark Emitter
+; CHECK-NEXT: Stack Frame Layout Analysis
+; CHECK-NEXT: SPIRV module analysis
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Lazy Machine Block Frequency Analysis
+; CHECK-NEXT: Machine Optimization Remark Emitter
+; CHECK-NEXT: SPIRV Assembly Printer
+; CHECK-NEXT: Free MachineFunction
>From 1b36f2b8e28caca62dc79d53a7115960c4e18df6 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Fri, 17 Jan 2025 10:06:22 -0500
Subject: [PATCH 5/7] remove CSE pass dependency
---
llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp | 1 -
.../SPIRV/SPIRVPreLegalizerCombiner.cpp | 12 +-
llvm/test/CodeGen/SPIRV/llc-pipeline.ll | 140 ------------------
3 files changed, 2 insertions(+), 151 deletions(-)
delete mode 100644 llvm/test/CodeGen/SPIRV/llc-pipeline.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index 48aad9f5f420e1..b5ef8d2a9286f2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -43,7 +43,6 @@ class SPIRVPreLegalizer : public MachineFunctionPass {
void SPIRVPreLegalizer::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addPreserved<GISelKnownBitsAnalysis>();
- AU.addPreserved<GISelCSEAnalysisWrapperPass>();
MachineFunctionPass::getAnalysisUsage(AU);
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
index 0abe995ea9d4ae..5efebf02b705ab 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
@@ -187,8 +187,6 @@ void SPIRVPreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addPreserved<GISelKnownBitsAnalysis>();
AU.addRequired<MachineDominatorTreeWrapperPass>();
AU.addPreserved<MachineDominatorTreeWrapperPass>();
- AU.addRequired<GISelCSEAnalysisWrapperPass>();
- AU.addPreserved<GISelCSEAnalysisWrapperPass>();
MachineFunctionPass::getAnalysisUsage(AU);
}
@@ -206,11 +204,6 @@ bool SPIRVPreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
return false;
auto &TPC = getAnalysis<TargetPassConfig>();
- // Enable CSE.
- GISelCSEAnalysisWrapper &Wrapper =
- getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
- auto *CSEInfo = &Wrapper.get(TPC.getCSEConfig());
-
const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
const auto *LI = ST.getLegalizerInfo();
@@ -229,8 +222,8 @@ bool SPIRVPreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
// This is the first Combiner, so the input IR might contain dead
// instructions.
CInfo.EnableFullDCE = true;
- SPIRVPreLegalizerCombinerImpl Impl(MF, CInfo, &TPC, *KB, CSEInfo, RuleConfig,
- ST, MDT, LI);
+ SPIRVPreLegalizerCombinerImpl Impl(MF, CInfo, &TPC, *KB, /*CSEInfo*/ nullptr,
+ RuleConfig, ST, MDT, LI);
return Impl.combineMachineInstrs();
}
@@ -240,7 +233,6 @@ INITIALIZE_PASS_BEGIN(SPIRVPreLegalizerCombiner, DEBUG_TYPE,
false)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis)
-INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)
INITIALIZE_PASS_END(SPIRVPreLegalizerCombiner, DEBUG_TYPE,
"Combine SPIRV machine instrs before legalization", false,
false)
diff --git a/llvm/test/CodeGen/SPIRV/llc-pipeline.ll b/llvm/test/CodeGen/SPIRV/llc-pipeline.ll
deleted file mode 100644
index 2c7d3fded25fba..00000000000000
--- a/llvm/test/CodeGen/SPIRV/llc-pipeline.ll
+++ /dev/null
@@ -1,140 +0,0 @@
-; RUN: llc -mtriple=spirv-unknown-unknown -debug-pass=Structure < %s -o /dev/null 2>&1 | \
-; RUN: grep -v "Verify generated machine code" | FileCheck %s
-
-; REQUIRES: asserts
-
-
-; CHECK-LABEL: Pass Arguments:
-; CHECK-NEXT: Target Library Information
-; CHECK-NEXT: Target Pass Configuration
-; CHECK-NEXT: Machine Module Information
-; CHECK-NEXT: Target Transform Information
-; CHECK-NEXT: Type-Based Alias Analysis
-; CHECK-NEXT: Scoped NoAlias Alias Analysis
-; CHECK-NEXT: Assumption Cache Tracker
-; CHECK-NEXT: Profile summary info
-; CHECK-NEXT: Create Garbage Collector Module Metadata
-; CHECK-NEXT: Machine Branch Probability Analysis
-; CHECK-NEXT: ModulePass Manager
-; CHECK-NEXT: Pre-ISel Intrinsic Lowering
-; CHECK-NEXT: FunctionPass Manager
-; CHECK-NEXT: Expand large div/rem
-; CHECK-NEXT: Expand large fp convert
-; CHECK-NEXT: Module Verifier
-; CHECK-NEXT: Dominator Tree Construction
-; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
-; CHECK-NEXT: Natural Loop Information
-; CHECK-NEXT: Canonicalize natural loops
-; CHECK-NEXT: Scalar Evolution Analysis
-; CHECK-NEXT: Loop Pass Manager
-; CHECK-NEXT: Canonicalize Freeze Instructions in Loops
-; CHECK-NEXT: Induction Variable Users
-; CHECK-NEXT: Loop Strength Reduction
-; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
-; CHECK-NEXT: Function Alias Analysis Results
-; CHECK-NEXT: Merge contiguous icmps into a memcmp
-; CHECK-NEXT: Natural Loop Information
-; CHECK-NEXT: Lazy Branch Probability Analysis
-; CHECK-NEXT: Lazy Block Frequency Analysis
-; CHECK-NEXT: Expand memcmp() to load/stores
-; CHECK-NEXT: Lower Garbage Collection Instructions
-; CHECK-NEXT: Shadow Stack GC Lowering
-; CHECK-NEXT: Remove unreachable blocks from the CFG
-; CHECK-NEXT: Natural Loop Information
-; CHECK-NEXT: Post-Dominator Tree Construction
-; CHECK-NEXT: Branch Probability Analysis
-; CHECK-NEXT: Block Frequency Analysis
-; CHECK-NEXT: Constant Hoisting
-; CHECK-NEXT: Replace intrinsics with calls to vector library
-; CHECK-NEXT: Partially inline calls to library functions
-; CHECK-NEXT: Instrument function entry/exit with calls to e.g. mcount() (post inlining)
-; CHECK-NEXT: Scalarize Masked Memory Intrinsics
-; CHECK-NEXT: Expand reduction intrinsics
-; CHECK-NEXT: Natural Loop Information
-; CHECK-NEXT: Canonicalize natural loops
-; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
-; CHECK-NEXT: SPIRV convergence regions analysis
-; CHECK-NEXT: SPIRV split region exit blocks
-; CHECK-NEXT: Dominator Tree Construction
-; CHECK-NEXT: Natural Loop Information
-; CHECK-NEXT: structurize SPIRV
-; CHECK-NEXT: Dominator Tree Construction
-; CHECK-NEXT: Promote Memory to Register
-; CHECK-NEXT: SPIR-V Regularizer
-; CHECK-NEXT: SPIRV prepare functions
-; CHECK-NEXT: FunctionPass Manager
-; CHECK-NEXT: SPIRV strip convergent intrinsics
-; CHECK-NEXT: Dominator Tree Construction
-; CHECK-NEXT: Natural Loop Information
-; CHECK-NEXT: CodeGen Prepare
-; CHECK-NEXT: Lower invoke and unwind, for unwindless code generators
-; CHECK-NEXT: Remove unreachable blocks from the CFG
-; CHECK-NEXT: SPIRV emit intrinsics
-; CHECK-NEXT: FunctionPass Manager
-; CHECK-NEXT: Dominator Tree Construction
-; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
-; CHECK-NEXT: Function Alias Analysis Results
-; CHECK-NEXT: ObjC ARC contraction
-; CHECK-NEXT: Prepare callbr
-; CHECK-NEXT: Safe Stack instrumentation pass
-; CHECK-NEXT: Insert stack protectors
-; CHECK-NEXT: Module Verifier
-; CHECK-NEXT: Analysis containing CSE Info
-; CHECK-NEXT: Natural Loop Information
-; CHECK-NEXT: Post-Dominator Tree Construction
-; CHECK-NEXT: Branch Probability Analysis
-; CHECK-NEXT: Basic Alias Analysis (stateless AA impl)
-; CHECK-NEXT: Function Alias Analysis Results
-; CHECK-NEXT: IRTranslator
-; CHECK-NEXT: Analysis for ComputingKnownBits
-; CHECK-NEXT: MachineDominator Tree Construction
-; CHECK-NEXT: Analysis containing CSE Info
-; CHECK-NEXT: SPIRVPreLegalizerCombiner
-; CHECK-NEXT: SPIRV pre legalizer
-; CHECK-NEXT: Legalizer
-; CHECK-NEXT: SPIRV post legalizer
-; CHECK-NEXT: Analysis for ComputingKnownBits
-; CHECK-NEXT: Lazy Branch Probability Analysis
-; CHECK-NEXT: Lazy Block Frequency Analysis
-; CHECK-NEXT: InstructionSelect
-; CHECK-NEXT: ResetMachineFunction
-; CHECK-NEXT: Finalize ISel and expand pseudo-instructions
-; CHECK-NEXT: Lazy Machine Block Frequency Analysis
-; CHECK-NEXT: Early Tail Duplication
-; CHECK-NEXT: Optimize machine instruction PHIs
-; CHECK-NEXT: Slot index numbering
-; CHECK-NEXT: Merge disjoint stack slots
-; CHECK-NEXT: Local Stack Slot Allocation
-; CHECK-NEXT: Remove dead machine instructions
-; CHECK-NEXT: MachineDominator Tree Construction
-; CHECK-NEXT: Machine Natural Loop Construction
-; CHECK-NEXT: Machine Block Frequency Analysis
-; CHECK-NEXT: Early Machine Loop Invariant Code Motion
-; CHECK-NEXT: MachineDominator Tree Construction
-; CHECK-NEXT: Machine Block Frequency Analysis
-; CHECK-NEXT: Machine Common Subexpression Elimination
-; CHECK-NEXT: MachinePostDominator Tree Construction
-; CHECK-NEXT: Machine Cycle Info Analysis
-; CHECK-NEXT: Machine code sinking
-; CHECK-NEXT: Peephole Optimizations
-; CHECK-NEXT: Remove dead machine instructions
-; CHECK-NEXT: Remove Redundant DEBUG_VALUE analysis
-; CHECK-NEXT: Fixup Statepoint Caller Saved
-; CHECK-NEXT: Lazy Machine Block Frequency Analysis
-; CHECK-NEXT: Machine Optimization Remark Emitter
-; CHECK-NEXT: Prologue/Epilogue Insertion & Frame Finalization
-; CHECK-NEXT: Tail Duplication
-; CHECK-NEXT: Post-RA pseudo instruction expansion pass
-; CHECK-NEXT: Analyze Machine Code For Garbage Collection
-; CHECK-NEXT: Insert fentry calls
-; CHECK-NEXT: Insert XRay ops
-; CHECK-NEXT: Machine Sanitizer Binary Metadata
-; CHECK-NEXT: Lazy Machine Block Frequency Analysis
-; CHECK-NEXT: Machine Optimization Remark Emitter
-; CHECK-NEXT: Stack Frame Layout Analysis
-; CHECK-NEXT: SPIRV module analysis
-; CHECK-NEXT: FunctionPass Manager
-; CHECK-NEXT: Lazy Machine Block Frequency Analysis
-; CHECK-NEXT: Machine Optimization Remark Emitter
-; CHECK-NEXT: SPIRV Assembly Printer
-; CHECK-NEXT: Free MachineFunction
>From e27efa249bd40ff481b18af7d968881a86631673 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Fri, 17 Jan 2025 11:35:04 -0500
Subject: [PATCH 6/7] turn off DCE
---
llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
index 5efebf02b705ab..269524b2410c22 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp
@@ -221,7 +221,7 @@ bool SPIRVPreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
// This is the first Combiner, so the input IR might contain dead
// instructions.
- CInfo.EnableFullDCE = true;
+ CInfo.EnableFullDCE = false;
SPIRVPreLegalizerCombinerImpl Impl(MF, CInfo, &TPC, *KB, /*CSEInfo*/ nullptr,
RuleConfig, ST, MDT, LI);
return Impl.combineMachineInstrs();
>From 0a7e31a1d27592b949886856194f0995c429a832 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlotfi at microsoft.com>
Date: Fri, 17 Jan 2025 14:21:22 -0500
Subject: [PATCH 7/7] address pr comments add -verify-machineinstrs to
distance.ll Also add a MIR test to test the instcombine independent of other
passes.
---
...relegalizercombiner-length-to-distance.mir | 26 +++++++++++++++++++
.../CodeGen/SPIRV/hlsl-intrinsics/distance.ll | 2 +-
2 files changed, 27 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-length-to-distance.mir
diff --git a/llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-length-to-distance.mir b/llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-length-to-distance.mir
new file mode 100644
index 00000000000000..219b98ecca6f06
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-length-to-distance.mir
@@ -0,0 +1,26 @@
+# RUN: llc -verify-machineinstrs -O0 -mtriple spirv-unknown-unknown -run-pass=spirv-prelegalizer-combiner %s -o - | FileCheck %s
+# REQUIRES: asserts
+---
+name: distance_instcombine_float4
+tracksRegLiveness: true
+legalized: true
+body: |
+ bb.1.entry:
+ ; CHECK-LABEL: name: distance_instcombine_float4
+ ; CHECK-NOT: %6:_(<4 x s32>) = G_FSUB %2, %3
+ ; CHECK-NOT: %7:id(s32) = G_INTRINSIC intrinsic(@llvm.spv.length), %6(<4 x s32>)
+ ; CHECK: %7:id(s32) = G_INTRINSIC intrinsic(@llvm.spv.distance), %2(<4 x s32>), %3(<4 x s32>)
+ %0:type(s64) = OpTypeFloat 32
+ %1:type(s64) = OpTypeVector %0(s64), 4
+ OpName %2(<4 x s32>), 97
+ OpName %3(<4 x s32>), 98
+ %4:type(s64) = OpTypeFunction %0(s64), %1(s64), %1(s64)
+ %5:iid(s64) = OpFunction %0(s64), 0, %4(s64)
+ %2:vfid(<4 x s32>) = OpFunctionParameter %1(s64)
+ %3:vfid(<4 x s32>) = OpFunctionParameter %1(s64)
+ OpName %5(s64), 1953720676, 1701015137, 1936615775, 1836016500, 1701734754, 1869375071, 3437665
+ OpDecorate %5(s64), 41, 1953720676, 1701015137, 1936615775, 1836016500, 1701734754, 1869375071, 3437665, 0
+ %6:_(<4 x s32>) = G_FSUB %2, %3
+ %7:id(s32) = G_INTRINSIC intrinsic(@llvm.spv.length), %6(<4 x s32>)
+ OpReturnValue %7(s32)
+
\ No newline at end of file
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/distance.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/distance.ll
index fac5d5f9fbd0d2..cb92f775eef31c 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/distance.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/distance.ll
@@ -1,4 +1,4 @@
-; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; Make sure SPIRV operation function calls for distance are lowered correctly.
More information about the llvm-commits
mailing list