https://github.com/farzonl updated https://github.com/llvm/llvm-project/pull/135125
>From cb40adc19bf488f73bfaa75c5417080bcb4b3967 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 10 Apr 2025 00:01:58 -0400 Subject: [PATCH 1/3] [HLSL] Add support for modulo of floating point scalar and vectors fixes #135122 SemaExpr.cpp - Make all doubles fail. Add sema support for float scalars and vectors when language mode is HLSL. CGExprScalar.cpp - Allow emit frem when language mode is HLSL. --- clang/lib/CodeGen/CGExprScalar.cpp | 2 + clang/lib/Sema/SemaExpr.cpp | 28 ++++- .../BasicFeatures/frem_modulo.hlsl | 110 ++++++++++++++++++ .../Operators/frem_modulo-errors.hlsl | 41 +++++++ 4 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 clang/test/CodeGenHLSL/BasicFeatures/frem_modulo.hlsl create mode 100644 clang/test/SemaHLSL/Operators/frem_modulo-errors.hlsl diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 28ae56058a7b4..3b25c79701b60 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -3964,6 +3964,8 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem"); + else if (CGF.getLangOpts().HLSL && Ops.Ty->hasFloatingRepresentation()) + return Builder.CreateFRem(Ops.LHS, Ops.RHS, "rem"); else return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e7f418ae6802e..25b7bd0e16942 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10695,10 +10695,30 @@ QualType Sema::CheckRemainderOperands( ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) { checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/false); + // Note: This check is here to simplify the double exclusions of + // scalar and vector HLSL checks. No getLangOpts().HLSL + // is needed since all languages exlcude doubles. + if (LHS.get()->getType()->isDoubleType() || + RHS.get()->getType()->isDoubleType() || + (LHS.get()->getType()->isVectorType() && LHS.get() + ->getType() + ->getAs<VectorType>() + ->getElementType() + ->isDoubleType()) || + (RHS.get()->getType()->isVectorType() && RHS.get() + ->getType() + ->getAs<VectorType>() + ->getElementType() + ->isDoubleType())) + return InvalidOperands(Loc, LHS, RHS); + if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { - if (LHS.get()->getType()->hasIntegerRepresentation() && - RHS.get()->getType()->hasIntegerRepresentation()) + if ((LHS.get()->getType()->hasIntegerRepresentation() && + RHS.get()->getType()->hasIntegerRepresentation()) || + (getLangOpts().HLSL && + (LHS.get()->getType()->hasFloatingRepresentation() || + RHS.get()->getType()->hasFloatingRepresentation()))) return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, /*AllowBothBool*/ getLangOpts().AltiVec, /*AllowBoolConversions*/ false, @@ -10722,7 +10742,9 @@ QualType Sema::CheckRemainderOperands( if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); - if (compType.isNull() || !compType->isIntegerType()) + if (compType.isNull() || + (!compType->isIntegerType() && + !(getLangOpts().HLSL && compType->isFloatingType()))) return InvalidOperands(Loc, LHS, RHS); DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, false /* IsDiv */); return compType; diff --git a/clang/test/CodeGenHLSL/BasicFeatures/frem_modulo.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/frem_modulo.hlsl new file mode 100644 index 0000000000000..edc28c5c80b51 --- /dev/null +++ b/clang/test/CodeGenHLSL/BasicFeatures/frem_modulo.hlsl @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-library %s \ +// RUN: -fnative-half-type -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s +// RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute %s \ +// RUN: -fnative-half-type -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s + + half2 half_vec_mod_by_int(half2 p1) { +// CHECK-LABEL: half_vec_mod_by_int +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}}, splat (half 0xH4000) + return p1 % 2; +} + + half2 half_vec_mod_by_float(half2 p1) { +// CHECK-LABEL: half_vec_mod_by_float +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}}, splat (half 0xH4000) + return p1 % (half)2.0; +} + + half2 half_vec_mod_by_half(half2 p1, half p2 ) { +// CHECK-LABEL: half_vec_mod_by_half +// CHECK: %splat.splatinsert = insertelement <2 x half> poison, half %{{.*}}, i64 0 +// CHECK: %splat.splat = shufflevector <2 x half> %splat.splatinsert, <2 x half> poison, <2 x i32> zeroinitializer +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}}, %splat.splat + return p1 % p2; +} + + half2 half_vec_mod_by_half_vec(half2 p1, half2 p2 ) { +// CHECK-LABEL: half_vec_mod_by_half_vec +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}}, %{{.*}} + return p1 % p2; +} + + half half_vec_mod_by_int(half p1) { +// CHECK-LABEL: half_vec_mod_by_int +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn half %{{.*}}, 0xH4000 + return p1 % 2; +} + + half half_mod_by_float(half p1) { +// CHECK-LABEL: half_mod_by_float +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn half %{{.*}}, 0xH4000 + return p1 % (half)2.0; +} + + half half_mod_by_half(half p1, half p2 ) { +// CHECK-LABEL: half_mod_by_half +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn half %{{.*}}, %{{.*}} + return p1 % p2; +} + + half half_mod_by_half_vec(half p1, half2 p2 ) { +// CHECK-LABEL: half_mod_by_half_vec +// CHECK: %splat.splatinsert = insertelement <2 x half> poison, half %{{.*}}, i64 0 +// CHECK: %splat.splat = shufflevector <2 x half> %splat.splatinsert, <2 x half> poison, <2 x i32> zeroinitializer +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn <2 x half> %splat.splat, %{{.*}} + return p1 % p2; +} + + float2 float_vec_mod_by_int(float2 p1) { +// CHECK-LABEL: float_vec_mod_by_int +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}}, splat (float 2.000000e+00) + return p1 % 2; +} + + float2 float_vec_mod_by_float_const(float2 p1) { +// CHECK-LABEL: float_vec_mod_by_float_const +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}}, splat (float 2.000000e+00) + return p1 % 2.0; +} + + float2 float_vec_mod_by_float(float2 p1, float p2 ) { +// CHECK-LABEL: float_vec_mod_by_float +// CHECK: %splat.splatinsert = insertelement <2 x float> poison, float %{{.*}}, i64 0 +// CHECK: %splat.splat = shufflevector <2 x float> %splat.splatinsert, <2 x float> poison, <2 x i32> zeroinitializer +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}}, %splat.splat + return p1 % p2; +} + + float2 float_vec_mod_by_float_vec(float2 p1, float2 p2 ) { +// CHECK-LABEL: float_vec_mod_by_float_vec +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}}, %{{.*}} + return p1 % p2; +} + + float float_mod_by_int(float p1) { +// CHECK-LABEL: float_mod_by_int +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn float %{{.*}}, 2.000000e+00 + return p1 % 2; +} + + float float_mod_by_float_const(float p1) { +// CHECK-LABEL: float_mod_by_float_const +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn float %{{.*}}, 2.000000e+00 + return p1 % 2.0; +} + + float float_mod_by_float(float p1, float p2 ) { +// CHECK-LABEL: float_mod_by_float +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn float %{{.*}}, %{{.*}} + return p1 % p2; +} + + float float_mod_by_float_vec(float p1, float2 p2 ) { +// CHECK-LABEL: float_mod_by_float_vec +// CHECK: %splat.splatinsert = insertelement <2 x float> poison, float %{{.*}}, i64 0 +// CHECK: %splat.splat = shufflevector <2 x float> %splat.splatinsert, <2 x float> poison, <2 x i32> zeroinitializer +// CHECK: %rem = frem reassoc nnan ninf nsz arcp afn <2 x float> %splat.splat, %{{.*}} + return p1 % p2; +} diff --git a/clang/test/SemaHLSL/Operators/frem_modulo-errors.hlsl b/clang/test/SemaHLSL/Operators/frem_modulo-errors.hlsl new file mode 100644 index 0000000000000..1c6e45693a12f --- /dev/null +++ b/clang/test/SemaHLSL/Operators/frem_modulo-errors.hlsl @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify + +export double2 double_vec_mod_by_int(double2 p1) { + return p1 % 2; + // expected-error@-1 {{invalid operands to binary expression ('double2' (aka 'vector<double, 2>') and 'int')}} +} + +export double2 double_vec_mod_by_float(double2 p1) { + return p1 % 2.0; + // expected-error@-1 {{invalid operands to binary expression ('double2' (aka 'vector<double, 2>') and 'float')}} +} + +export double2 double_vec_mod_by_double(double2 p1, double p2 ) { + return p1 % p2; + // expected-error@-1 {{invalid operands to binary expression ('double2' (aka 'vector<double, 2>') and 'double')}} +} + +export double2 double_vec_mod_by_double_vec(double2 p1, double2 p2 ) { + return p1 % p2; + // expected-error@-1 {{invalid operands to binary expression ('double2' (aka 'vector<double, 2>') and 'double2')}} +} + +export double double_mod_by_int(double p1) { + return p1 % 2; + // expected-error@-1 {{invalid operands to binary expression ('double' and 'int')}} +} + +export double double_mod_by_float(double p1) { + return p1 % 2.0; + // expected-error@-1 {{invalid operands to binary expression ('double' and 'float')}} +} + +export double double_mod_by_double(double p1, double p2 ) { + return p1 % p2; + // expected-error@-1 {{invalid operands to binary expression ('double' and 'double')}} +} + +export double double_mod_by_double_vec(double p1, double2 p2 ) { + return p1 % p2; + // expected-error@-1 {{invalid operands to binary expression ('double' and 'double2' (aka 'vector<double, 2>'))}} +} >From 22982a444c17bbba6b759b5853f69582ba881a2e Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 10 Apr 2025 11:24:22 -0400 Subject: [PATCH 2/3] address pr feedback --- clang/lib/CodeGen/CGExprScalar.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 3b25c79701b60..adaaae33128de 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -3964,10 +3964,13 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem"); - else if (CGF.getLangOpts().HLSL && Ops.Ty->hasFloatingRepresentation()) + + if (CGF.getLangOpts().HLSL && Ops.Ty->hasFloatingRepresentation()) return Builder.CreateFRem(Ops.LHS, Ops.RHS, "rem"); - else - return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); + + assert(Ops.Ty->hasSignedIntegerRepresentation() && + "Srem expected a signed integer representation."); + return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); } Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { >From 1e736777183db54c5baf58717d91ae8da2c62731 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 10 Apr 2025 12:34:21 -0400 Subject: [PATCH 3/3] remove signed int representation assert it breaks CodeGen/AArch64/sve-vector-arith-ops.c test case use of i8s --- clang/lib/CodeGen/CGExprScalar.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index adaaae33128de..e9a7ba509350c 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -3968,8 +3968,6 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { if (CGF.getLangOpts().HLSL && Ops.Ty->hasFloatingRepresentation()) return Builder.CreateFRem(Ops.LHS, Ops.RHS, "rem"); - assert(Ops.Ty->hasSignedIntegerRepresentation() && - "Srem expected a signed integer representation."); return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits