Skip to content

Commit 363b460

Browse files
authored
[202x] Add support for bit-precise float suffixes (#8478)
This updates the literal parser to handle bit-precise float suffixes for 16, 32, and 64-bit types. These changes reflect the latest updates to the conforming literals proposal (PR: hlsl-tc57/tc57#52).
1 parent c207c7b commit 363b460

7 files changed

Lines changed: 226 additions & 0 deletions

File tree

tools/clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,4 +808,5 @@ def HLSLAvailabilityConstant: DiagGroup<"hlsl-availability-constant">;
808808
def HLSLBarrier : DiagGroup<"hlsl-barrier">;
809809
def HLSLLegacyLiterals : DiagGroup<"hlsl-legacy-literal">;
810810
def HLSLGroupshared202x : DiagGroup<"hlsl-groupshared-202x">;
811+
def HLSL202xExtensions : DiagGroup<"hlsl-202x-extensions", [HLSLGroupshared202x]>;
811812
// HLSL Change Ends

tools/clang/include/clang/Basic/DiagnosticLexKinds.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,4 +658,12 @@ def err_pp_eof_in_assume_nonnull : Error<
658658

659659
}
660660

661+
// HLSL Change Begin - fixed-size floating-point literal suffixes
662+
def ext_hlsl_fixed_size_float_suffix_202x : ExtWarn<
663+
"fixed-size floating-point literal suffix '%0' is a HLSL 202x extension">,
664+
InGroup<HLSL202xExtensions>;
665+
def err_hlsl_16bit_suffix_requires_native_16bit : Error<
666+
"16-bit floating-point literal suffix '%0' requires '-enable-16bit-types'">;
667+
// HLSL Change End
668+
661669
}

tools/clang/lib/Lex/LiteralSupport.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,42 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
609609
case 'F':
610610
if (!isFPConstant) break; // Error for integer constant.
611611
if (isFloat || isLong) break; // FF, LF invalid.
612+
// HLSL Change Begin - fixed-size float suffixes f16/f32/f64
613+
if (PP.getLangOpts().HLSL && (s + 2) < ThisTokEnd) {
614+
unsigned Width = 0;
615+
if (s[1] == '1' && s[2] == '6')
616+
Width = 16;
617+
else if (s[1] == '3' && s[2] == '2')
618+
Width = 32;
619+
else if (s[1] == '6' && s[2] == '4')
620+
Width = 64;
621+
if (Width != 0) {
622+
StringRef SuffixStr(s, 3);
623+
if (PP.getLangOpts().HLSLVersion < hlsl::LangStd::v202x) {
624+
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
625+
diag::ext_hlsl_fixed_size_float_suffix_202x)
626+
<< SuffixStr;
627+
}
628+
if (Width == 16 && PP.getLangOpts().UseMinPrecision) {
629+
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
630+
diag::err_hlsl_16bit_suffix_requires_native_16bit)
631+
<< SuffixStr;
632+
hadError = true;
633+
}
634+
// Reuse existing width flags: f16 acts like 'h' (half), f32 like
635+
// 'f' (float), f64 like 'l' (double in HLSL). The source token is
636+
// preserved if anything later needs to distinguish the spellings.
637+
if (Width == 16)
638+
isHalf = true;
639+
else if (Width == 32)
640+
isFloat = true;
641+
else
642+
isLong = true;
643+
s += 2; // The outer loop's ++s consumes the leading 'f'/'F'.
644+
continue;
645+
}
646+
}
647+
// HLSL Change End
612648
isFloat = true;
613649
continue; // Success.
614650
// HLSL Change Starts
@@ -718,6 +754,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
718754
isUnsigned = false;
719755
isLongLong = false;
720756
isFloat = false;
757+
isHalf = false; // HLSL Change
721758
isImaginary = false;
722759
MicrosoftInteger = 0;
723760

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: %dxc -T lib_6_3 -HV 202x -enable-16bit-types -verify %s
2+
3+
// Verify that float literal suffixes that look like fixed-size width
4+
// suffixes but specify an unsupported width are rejected. Only 16, 32 and
5+
// 64 are valid widths; everything else must produce an
6+
// "invalid suffix on floating constant" error.
7+
8+
float plausible_f8() {
9+
// 'f8' would be an 8-bit float, which we don't support.
10+
// expected-error@+1{{invalid suffix 'f8' on floating constant}}
11+
return 1.0f8;
12+
}
13+
14+
float plausible_F8() {
15+
// expected-error@+1{{invalid suffix 'F8' on floating constant}}
16+
return 1.0F8;
17+
}
18+
19+
float plausible_f128() {
20+
// 'f128' would be a 128-bit float, which we don't support.
21+
// expected-error@+1{{invalid suffix 'f128' on floating constant}}
22+
return 1.0f128;
23+
}
24+
25+
float plausible_F128() {
26+
// expected-error@+1{{invalid suffix 'F128' on floating constant}}
27+
return 1.0F128;
28+
}
29+
30+
float implausible_f23() {
31+
// 'f23' is not a meaningful width but the parser should still reject it.
32+
// expected-error@+1{{invalid suffix 'f23' on floating constant}}
33+
return 1.0f23;
34+
}
35+
36+
float implausible_f7() {
37+
// 'f7' is not a meaningful width but the parser should still reject it.
38+
// expected-error@+1{{invalid suffix 'f7' on floating constant}}
39+
return 1.0f7;
40+
}
41+
42+
float implausible_f0() {
43+
// expected-error@+1{{invalid suffix 'f0' on floating constant}}
44+
return 1.0f0;
45+
}
46+
47+
float implausible_f31() {
48+
// One off from a valid width.
49+
// expected-error@+1{{invalid suffix 'f31' on floating constant}}
50+
return 1.0f31;
51+
}
52+
53+
float implausible_f33() {
54+
// expected-error@+1{{invalid suffix 'f33' on floating constant}}
55+
return 1.0f33;
56+
}
57+
58+
float trailing_garbage_after_valid_width() {
59+
// A valid fixed-size suffix followed by extra characters is still an
60+
// invalid suffix.
61+
// expected-error@+1{{invalid suffix 'f32x' on floating constant}}
62+
return 1.0f32x;
63+
}
64+
65+
float trailing_number_after_valid_width() {
66+
// A valid fixed-size suffix followed by an extra number is still an invalid
67+
// suffix.
68+
// expected-error@+1{{invalid suffix 'f324' on floating constant}}
69+
return 1.0f324;
70+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: %dxc -T lib_6_3 -HV 2021 -verify %s
2+
3+
// In HLSL 2021 and earlier, the fixed-size float suffixes f16/f32/f64 should
4+
// still work, but produce an extension warning. With -enable-16bit-types not
5+
// passed, the 16-bit suffix should also error.
6+
7+
template <typename T, typename U>
8+
struct is_same {
9+
static const bool value = false;
10+
};
11+
12+
template <typename T>
13+
struct is_same<T, T> {
14+
static const bool value = true;
15+
};
16+
17+
float test_f32() {
18+
// expected-warning@+1{{fixed-size floating-point literal suffix 'f32' is a HLSL 202x extension}}
19+
return 1.0f32;
20+
}
21+
22+
float test_F32() {
23+
// expected-warning@+1{{fixed-size floating-point literal suffix 'F32' is a HLSL 202x extension}}
24+
return 1.0F32;
25+
}
26+
27+
double test_f64() {
28+
// expected-warning@+1{{fixed-size floating-point literal suffix 'f64' is a HLSL 202x extension}}
29+
return 1.0f64;
30+
}
31+
32+
double test_F64() {
33+
// expected-warning@+1{{fixed-size floating-point literal suffix 'F64' is a HLSL 202x extension}}
34+
return 1.0F64;
35+
}
36+
37+
// Without -enable-16bit-types the 16-bit suffix must error (in addition to the
38+
// extension warning).
39+
min16float test_f16() {
40+
// expected-warning@+2{{fixed-size floating-point literal suffix 'f16' is a HLSL 202x extension}}
41+
// expected-error@+1{{16-bit floating-point literal suffix 'f16' requires '-enable-16bit-types'}}
42+
return 1.0f16;
43+
}
44+
45+
min16float test_F16() {
46+
// expected-warning@+2{{fixed-size floating-point literal suffix 'F16' is a HLSL 202x extension}}
47+
// expected-error@+1{{16-bit floating-point literal suffix 'F16' requires '-enable-16bit-types'}}
48+
return 1.0F16;
49+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %dxc -T lib_6_3 -HV 202x -verify %s
2+
3+
// In HLSL 202x mode without -enable-16bit-types, the 16-bit suffix must error
4+
// while f32/f64 are accepted silently.
5+
6+
float test_f32() {
7+
return 1.0f32; // no diagnostic
8+
}
9+
10+
double test_f64() {
11+
return 1.0f64; // no diagnostic
12+
}
13+
14+
min16float test_f16() {
15+
// expected-error@+1{{16-bit floating-point literal suffix 'f16' requires '-enable-16bit-types'}}
16+
return 1.0f16;
17+
}
18+
19+
min16float test_F16() {
20+
// expected-error@+1{{16-bit floating-point literal suffix 'F16' requires '-enable-16bit-types'}}
21+
return 1.0F16;
22+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %dxc -T lib_6_3 -HV 202x -enable-16bit-types -verify %s
2+
3+
// Verify that f16/F16/f32/F32/f64/F64 produce the expected types in HLSL 202x
4+
// with native 16-bit types enabled.
5+
6+
template <typename T, typename U>
7+
struct is_same {
8+
static const bool value = false;
9+
};
10+
11+
template <typename T>
12+
struct is_same<T, T> {
13+
static const bool value = true;
14+
};
15+
16+
// expected-no-diagnostics
17+
18+
// 16-bit suffix -> float16_t (a.k.a. half / HalfTy).
19+
_Static_assert(is_same<__decltype(1.0f16), half>::value, "1.0f16 is half");
20+
_Static_assert(is_same<__decltype(1.0F16), half>::value, "1.0F16 is half");
21+
_Static_assert(is_same<__decltype(2.5e1f16), half>::value, "2.5e1f16 is half");
22+
23+
// 32-bit suffix -> float, regardless of UseMinPrecision.
24+
_Static_assert(is_same<__decltype(1.0f32), float>::value, "1.0f32 is float");
25+
_Static_assert(is_same<__decltype(1.0F32), float>::value, "1.0F32 is float");
26+
_Static_assert(is_same<__decltype(0.5e0f32), float>::value, "0.5e0f32 is float");
27+
28+
// 64-bit suffix -> double.
29+
_Static_assert(is_same<__decltype(1.0f64), double>::value, "1.0f64 is double");
30+
_Static_assert(is_same<__decltype(1.0F64), double>::value, "1.0F64 is double");
31+
_Static_assert(is_same<__decltype(0.5e0f64), double>::value, "0.5e0f64 is double");
32+
33+
// Sanity check: the plain 'f' and 'h' suffixes still work.
34+
_Static_assert(is_same<__decltype(1.0f), float>::value, "1.0f is float");
35+
_Static_assert(is_same<__decltype(1.0h), half>::value, "1.0h is half");
36+
_Static_assert(is_same<__decltype(1.0l), double>::value, "1.0l is double");
37+
38+
// The fixed-size suffix must not collide with an integer suffix.
39+
_Static_assert(is_same<__decltype(1.f32), float>::value, ".f32 with no fraction digits is float");

0 commit comments

Comments
 (0)