llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-hlsl

Author: Chris B (llvm-beanz)

<details>
<summary>Changes</summary>

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

---
Full diff: https://github.com/llvm/llvm-project/pull/87270.diff


3 Files Affected:

- (modified) clang/lib/Sema/SemaExpr.cpp (+4-1) 
- (added) clang/test/SemaHLSL/literal_suffixes.hlsl (+59) 
- (added) clang/test/SemaHLSL/literal_suffixes_no_16bit.hlsl (+59) 


``````````diff
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 80b4257d9d83ed..541f7b8b446fef 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);
@@ -4125,6 +4126,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, 
Scope *UDLScope) {
       }
     } else if (Literal.isFloat)
       Ty = Context.FloatTy;
+    else if (getLangOpts().HLSL && Literal.isLong)
+      Ty = Context.DoubleTy;
     else if (Literal.isLong)
       Ty = Context.LongDoubleTy;
     else if (Literal.isFloat16)
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");

``````````

</details>


https://github.com/llvm/llvm-project/pull/87270
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to