[clang] [HLSL] Implement floating literal suffixes (PR #87270)
Chris B via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 1 11:33:14 PDT 2024
https://github.com/llvm-beanz created https://github.com/llvm/llvm-project/pull/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
>From 63ae8d6a4748e8d8046975f39df315f778c6e512 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Mon, 1 Apr 2024 13:24:00 -0500
Subject: [PATCH] [HLSL] Implement floating literal suffixes
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
../clang/test/SemaHLSL/literal_suffixes_no_16bit.hlsl
---
clang/lib/Sema/SemaExpr.cpp | 5 +-
clang/test/SemaHLSL/literal_suffixes.hlsl | 59 +++++++++++++++++++
.../SemaHLSL/literal_suffixes_no_16bit.hlsl | 59 +++++++++++++++++++
3 files changed, 122 insertions(+), 1 deletion(-)
create mode 100644 clang/test/SemaHLSL/literal_suffixes.hlsl
create mode 100644 clang/test/SemaHLSL/literal_suffixes_no_16bit.hlsl
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");
More information about the cfe-commits
mailing list