[clang] [HLSL] Implement floating literal suffixes (PR #87270)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 1 11:33:44 PDT 2024
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
More information about the cfe-commits
mailing list