Author: Farzon Lotfi Date: 2025-04-10T14:27:49-04:00 New Revision: 589e1c73d0fa2692cf997a7a9c2286996ad2fec7
URL: https://github.com/llvm/llvm-project/commit/589e1c73d0fa2692cf997a7a9c2286996ad2fec7 DIFF: https://github.com/llvm/llvm-project/commit/589e1c73d0fa2692cf997a7a9c2286996ad2fec7.diff LOG: [HLSL] Add support for modulo of floating point scalar and vectors (#135125) 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. Added: clang/test/CodeGenHLSL/BasicFeatures/frem_modulo.hlsl clang/test/SemaHLSL/Operators/frem_modulo-errors.hlsl Modified: clang/lib/CodeGen/CGExprScalar.cpp clang/lib/Sema/SemaExpr.cpp Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 28ae56058a7b4..e9a7ba509350c 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -3964,8 +3964,11 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem"); - else - return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); + + if (CGF.getLangOpts().HLSL && Ops.Ty->hasFloatingRepresentation()) + return Builder.CreateFRem(Ops.LHS, Ops.RHS, "rem"); + + return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); } Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2729c35b6fb2d..c25daaa022f49 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>'))}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits