[clang] 0a0fccf - [HLSL] Implement floating literal suffixes (#87270)

via cfe-commits cfe-commits at lists.llvm.org
Fri Apr 5 11:46:17 PDT 2024


Author: Chris B
Date: 2024-04-05T13:46:14-05:00
New Revision: 0a0fccfc6c0519402a2566e1f63440410e524d17

URL: https://github.com/llvm/llvm-project/commit/0a0fccfc6c0519402a2566e1f63440410e524d17
DIFF: https://github.com/llvm/llvm-project/commit/0a0fccfc6c0519402a2566e1f63440410e524d17.diff

LOG: [HLSL] Implement floating literal suffixes (#87270)

This change implements the HLSL floating literal suffixes for half and
double literals. The PR for the HLSL language specification for this
behavior is https://github.com/microsoft/hlsl-specs/pull/175.

The TL;DR is that the `h` suffix on floating literals means `half`, and
the `l` suffix means `double`.

The expected behavior and diagnostics are different if native half is
supported. When native half is not enabled half is 32-bit so implicit
conversions to float do not lose precision and do not warn.

In all cases `half` and `float` are distinct types.

Resolves #85712

Added: 
    clang/test/SemaHLSL/literal_suffixes.hlsl
    clang/test/SemaHLSL/literal_suffixes_no_16bit.hlsl

Modified: 
    clang/lib/Sema/SemaExpr.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 6b2eb245d58263..ffe7e44e2387f4 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4117,7 +4117,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
   } else if (Literal.isFloatingLiteral()) {
     QualType Ty;
     if (Literal.isHalf){
-      if (getOpenCLOptions().isAvailableOption("cl_khr_fp16", getLangOpts()))
+      if (getLangOpts().HLSL ||
+          getOpenCLOptions().isAvailableOption("cl_khr_fp16", getLangOpts()))
         Ty = Context.HalfTy;
       else {
         Diag(Tok.getLocation(), diag::err_half_const_requires_fp16);
@@ -4126,7 +4127,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
     } else if (Literal.isFloat)
       Ty = Context.FloatTy;
     else if (Literal.isLong)
-      Ty = Context.LongDoubleTy;
+      Ty = !getLangOpts().HLSL ? Context.LongDoubleTy : Context.DoubleTy;
     else if (Literal.isFloat16)
       Ty = Context.Float16Ty;
     else if (Literal.isFloat128)

diff  --git a/clang/test/SemaHLSL/literal_suffixes.hlsl b/clang/test/SemaHLSL/literal_suffixes.hlsl
new file mode 100644
index 00000000000000..25a4d3b5103c48
--- /dev/null
+++ b/clang/test/SemaHLSL/literal_suffixes.hlsl
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-library -fnative-half-type -Wconversion -verify %s
+
+void literal_assignments() {
+  half h;
+
+  h = 2.0h; // No conversion, no diagnostic expected.
+
+  // Literal conversions that don't lose precision also don't cause diagnostics.
+  // Conversion from double (no diagnostic expected)
+  h = 2.0l;
+  h = 2.0;
+  h = 2.0f;
+
+  // Literal assignments with conversions that lose precision produce
+  // diagnostics under `-Wconversion`.
+
+  // Lose precision on assignment.
+  h = 3.1415926535897932384626433h; // No diagnostic expected because this isn't a conversion.
+
+  // Lose precision on assignment converting float to half.
+  h = 3.1415926535897932384626433f; // expected-warning {{implicit conversion loses floating-point precision: 'float' to 'half'}}
+
+  // Lose precision on assignment converting float to half.
+  h = 3.1415926535897932384626433f * 2.0f; // expected-warning {{implicit conversion loses floating-point precision: 'float' to 'half'}}
+
+  // Lose precision on assignment converting double to half.
+  h = 3.1415926535897932384626433l; // expected-warning {{implicit conversion loses floating-point precision: 'double' to 'half'}}
+
+  // Lose precision on assignment converting double to half.
+  h = 3.1415926535897932384626433l * 2.0l; // expected-warning {{implicit conversion loses floating-point precision: 'double' to 'half'}}
+
+  // Literal assinments of values out of the representable range produce
+  // warnings.
+
+  h = 66000.h; // expected-warning {{magnitude of floating-point constant too large for type 'half'; maximum is 65504}}
+  h = -66000.h; // expected-warning {{magnitude of floating-point constant too large for type 'half'; maximum is 65504}}
+
+  // The `h` suffix is invalid on integer literals.
+  h = 66000h; // expected-error {{invalid suffix 'h' on integer constant}}
+}
+
+template <typename T, typename U>
+struct is_same {
+  static const bool value = false;
+};
+
+template <typename T>
+struct is_same<T, T> {
+  static const bool value = true;
+};
+
+// The no-suffix behavior is currently wrong. The behavior in DXC is complicated
+// and undocumented. We have a language change planned to address this, and an
+// issue tracking: https://github.com/llvm/llvm-project/issues/85714.
+_Static_assert(is_same<double, __decltype(1.0)>::value, "1.0f literal is double (should be float)");
+
+_Static_assert(is_same<half, __decltype(1.0h)>::value, "1.0h literal is half");
+_Static_assert(is_same<float, __decltype(1.0f)>::value, "1.0f literal is float");
+_Static_assert(is_same<double, __decltype(1.0l)>::value, "1.0l literal is double");

diff  --git a/clang/test/SemaHLSL/literal_suffixes_no_16bit.hlsl b/clang/test/SemaHLSL/literal_suffixes_no_16bit.hlsl
new file mode 100644
index 00000000000000..73e57041329e88
--- /dev/null
+++ b/clang/test/SemaHLSL/literal_suffixes_no_16bit.hlsl
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-library -Wconversion -verify %s
+
+void literal_assignments() {
+  half h;
+
+  h = 2.0h; // No conversion, no diagnostic expected.
+
+  // Literal conversions that don't lose precision also don't cause diagnostics.
+  // Conversion from double (no diagnostic expected)
+  h = 2.0l;
+  h = 2.0;
+  h = 2.0f;
+
+  // Literal assignments with conversions that lose precision produce
+  // diagnostics under `-Wconversion`.
+
+  // Lose precision on assignment.
+  h = 3.1415926535897932384626433h; // No diagnostic expected because this isn't a conversion.
+
+  // Lose precision on assignment converting float to half.
+  h = 3.1415926535897932384626433f; // No diagnostic expected because half and float are the same size.
+
+  // Lose precision on assignment converting float to half.
+  h = 3.1415926535897932384626433f * 2.0f; // No diagnostic expected because half and float are the same size.
+
+  // Lose precision on assignment converting double to half.
+  h = 3.1415926535897932384626433l; // expected-warning {{implicit conversion loses floating-point precision: 'double' to 'half'}}
+
+  // Lose precision on assignment converting double to half.
+  h = 3.1415926535897932384626433l * 2.0l; // expected-warning {{implicit conversion loses floating-point precision: 'double' to 'half'}}
+
+  // Literal assinments of values out of the representable range produce
+  // warnings.
+
+  h = 66000.h; // No diagnostic expected because half is 32-bit.
+  h = -66000.h; // No diagnostic expected because half is 32-bit.
+
+  // The `h` suffix is invalid on integer literals.
+  h = 66000h; // expected-error {{invalid suffix 'h' on integer constant}}
+}
+
+template <typename T, typename U>
+struct is_same {
+  static const bool value = false;
+};
+
+template <typename T>
+struct is_same<T, T> {
+  static const bool value = true;
+};
+
+// The no-suffix behavior is currently wrong. The behavior in DXC is complicated
+// and undocumented. We have a language change planned to address this, and an
+// issue tracking: https://github.com/llvm/llvm-project/issues/85714.
+_Static_assert(is_same<double, __decltype(1.0)>::value, "1.0f literal is double (should be float)");
+
+_Static_assert(is_same<half, __decltype(1.0h)>::value, "1.0h literal is half");
+_Static_assert(is_same<float, __decltype(1.0f)>::value, "1.0f literal is float");
+_Static_assert(is_same<double, __decltype(1.0l)>::value, "1.0l literal is double");


        


More information about the cfe-commits mailing list