Skip to content

[clang] Add __bf16 Type Support Macros With Literal Suffix Support #134214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

bassiounix
Copy link
Contributor

closes #133660.

I added the suffix support to this pr as the generated macros uses the BF16 suffix.

The only line I found in GCC which we don't seem to support as a macro is

#define __BFLT16_IS_IEC_60559__ 0

we don't have __*_IS_IEC_60559__ in our macro builder so I skipped it.

cc @AaronBallman @lntue @jhuber6

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Apr 3, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 3, 2025

@llvm/pr-subscribers-clang

Author: Muhammad Bassiouni (bassiounix)

Changes

closes #133660.

I added the suffix support to this pr as the generated macros uses the BF16 suffix.

The only line I found in GCC which we don't seem to support as a macro is

#define __BFLT16_IS_IEC_60559__ 0

we don't have __*_IS_IEC_60559__ in our macro builder so I skipped it.

cc @AaronBallman @lntue @jhuber6


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

4 Files Affected:

  • (modified) clang/include/clang/Lex/LiteralSupport.h (+1)
  • (modified) clang/lib/Frontend/InitPreprocessor.cpp (+17-8)
  • (modified) clang/lib/Lex/LiteralSupport.cpp (+16-1)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+2)
diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h
index ea5f63bc20399..1907cfc365d97 100644
--- a/clang/include/clang/Lex/LiteralSupport.h
+++ b/clang/include/clang/Lex/LiteralSupport.h
@@ -77,6 +77,7 @@ class NumericLiteralParser {
   bool isFloat : 1;         // 1.0f
   bool isImaginary : 1;     // 1.0i
   bool isFloat16 : 1;       // 1.0f16
+  bool isBFloat16 : 1;      // 1.0bf16
   bool isFloat128 : 1;      // 1.0q
   bool isFract : 1;         // 1.0hr/r/lr/uhr/ur/ulr
   bool isAccum : 1;         // 1.0hk/k/lk/uhk/uk/ulk
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 0b54665501c76..9bca74a8b4bd6 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -96,7 +96,7 @@ static void AddImplicitIncludePCH(MacroBuilder &Builder, Preprocessor &PP,
 template <typename T>
 static T PickFP(const llvm::fltSemantics *Sem, T IEEEHalfVal, T IEEESingleVal,
                 T IEEEDoubleVal, T X87DoubleExtendedVal, T PPCDoubleDoubleVal,
-                T IEEEQuadVal) {
+                T BFloatVal, T IEEEQuadVal) {
   if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEhalf())
     return IEEEHalfVal;
   if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEsingle())
@@ -107,6 +107,8 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEEHalfVal, T IEEESingleVal,
     return X87DoubleExtendedVal;
   if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::PPCDoubleDouble())
     return PPCDoubleDoubleVal;
+  if (Sem == (const llvm::fltSemantics*)&llvm::APFloat::BFloat())
+    return BFloatVal;
   assert(Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEquad());
   return IEEEQuadVal;
 }
@@ -117,29 +119,34 @@ static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix,
   NormMax = PickFP(Sem, "6.5504e+4", "3.40282347e+38",
                    "1.7976931348623157e+308", "1.18973149535723176502e+4932",
                    "8.98846567431157953864652595394501e+307",
+                   "3.38953138925153547590470800371487867e+38",
                    "1.18973149535723176508575932662800702e+4932");
   DenormMin = PickFP(Sem, "5.9604644775390625e-8", "1.40129846e-45",
                      "4.9406564584124654e-324", "3.64519953188247460253e-4951",
                      "4.94065645841246544176568792868221e-324",
+                     "9.18354961579912115600575419704879436e-41",
                      "6.47517511943802511092443895822764655e-4966");
-  int Digits = PickFP(Sem, 3, 6, 15, 18, 31, 33);
-  int DecimalDigits = PickFP(Sem, 5, 9, 17, 21, 33, 36);
+  int Digits = PickFP(Sem, 3, 6, 15, 18, 31, 2, 33);
+  int DecimalDigits = PickFP(Sem, 5, 9, 17, 21, 33, 4, 36);
   Epsilon = PickFP(Sem, "9.765625e-4", "1.19209290e-7",
                    "2.2204460492503131e-16", "1.08420217248550443401e-19",
                    "4.94065645841246544176568792868221e-324",
+                   "7.81250000000000000000000000000000000e-3",
                    "1.92592994438723585305597794258492732e-34");
-  int MantissaDigits = PickFP(Sem, 11, 24, 53, 64, 106, 113);
-  int Min10Exp = PickFP(Sem, -4, -37, -307, -4931, -291, -4931);
-  int Max10Exp = PickFP(Sem, 4, 38, 308, 4932, 308, 4932);
-  int MinExp = PickFP(Sem, -13, -125, -1021, -16381, -968, -16381);
-  int MaxExp = PickFP(Sem, 16, 128, 1024, 16384, 1024, 16384);
+  int MantissaDigits = PickFP(Sem, 11, 24, 53, 64, 106, 8, 113);
+  int Min10Exp = PickFP(Sem, -4, -37, -307, -4931, -291, -37, -4931);
+  int Max10Exp = PickFP(Sem, 4, 38, 308, 4932, 308, 38, 4932);
+  int MinExp = PickFP(Sem, -13, -125, -1021, -16381, -968, -125, -16381);
+  int MaxExp = PickFP(Sem, 16, 128, 1024, 16384, 1024, 128, 16384);
   Min = PickFP(Sem, "6.103515625e-5", "1.17549435e-38", "2.2250738585072014e-308",
                "3.36210314311209350626e-4932",
                "2.00416836000897277799610805135016e-292",
+               "1.17549435082228750796873653722224568e-38",
                "3.36210314311209350626267781732175260e-4932");
   Max = PickFP(Sem, "6.5504e+4", "3.40282347e+38", "1.7976931348623157e+308",
                "1.18973149535723176502e+4932",
                "1.79769313486231580793728971405301e+308",
+               "3.38953138925153547590470800371487867e+38",
                "1.18973149535723176508575932662800702e+4932");
 
   SmallString<32> DefPrefix;
@@ -1250,6 +1257,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
 
   if (TI.hasFloat16Type())
     DefineFloatMacros(Builder, "FLT16", &TI.getHalfFormat(), "F16");
+  if (TI.hasBFloat16Type())
+    DefineFloatMacros(Builder, "BFLT16", &TI.getBFloat16Format(), "BF16");
   DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F");
   DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), "");
   DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat(), "L");
diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index 20933cc8dee69..ab0d301a70fbd 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -917,6 +917,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
   isFloat = false;
   isImaginary = false;
   isFloat16 = false;
+  isBFloat16 = false;
   isFloat128 = false;
   MicrosoftInteger = 0;
   isFract = false;
@@ -973,11 +974,20 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
   bool isFPConstant = isFloatingLiteral();
   bool HasSize = false;
   bool DoubleUnderscore = false;
+  bool isBF16 = false;
 
   // Loop over all of the characters of the suffix.  If we see something bad,
   // we break out of the loop.
   for (; s != ThisTokEnd; ++s) {
     switch (*s) {
+    case 'b':
+    case 'B':
+      if (isBFloat16) break;
+      if (isBF16) break;
+      if (HasSize) break;
+
+      isBF16 = true;
+      continue;
     case 'R':
     case 'r':
       if (!LangOpts.FixedPoint)
@@ -1022,7 +1032,11 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
            (LangOpts.OpenMPIsTargetDevice && Target.getTriple().isNVPTX())) &&
           s + 2 < ThisTokEnd && s[1] == '1' && s[2] == '6') {
         s += 2; // success, eat up 2 characters.
-        isFloat16 = true;
+        if (isBF16) {
+          isBFloat16 = true;
+        } else {
+          isFloat16 = true;
+        }
         continue;
       }
 
@@ -1183,6 +1197,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
         isSizeT = false;
         isFloat = false;
         isFloat16 = false;
+        isBFloat16 = false;
         isHalf = false;
         isImaginary = false;
         isBitInt = false;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 3af6d6c23438f..b4210fc22ae52 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3878,6 +3878,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
       Ty = !getLangOpts().HLSL ? Context.LongDoubleTy : Context.DoubleTy;
     else if (Literal.isFloat16)
       Ty = Context.Float16Ty;
+    else if (Literal.isBFloat16)
+      Ty = Context.BFloat16Ty;
     else if (Literal.isFloat128)
       Ty = Context.Float128Ty;
     else if (getLangOpts().HLSL)

Copy link

github-actions bot commented Apr 3, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@bassiounix
Copy link
Contributor Author

I changed the commits and ran test at each step,
I'm not sure why the last commit made the test failing!
is APFloat::BFloat the reason? if so, how would I set the value?

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this! It's heading in the right direction. Some things which are still missing are;

  • a release note in clang/docs/ReleaseNotes.rst so users know about the new suffix and macros.
  • test coverage
    • clang/test/Lexer/ should get a test for the literal suffix support
    • clang/test/Preprocessor/ should get a test for the new predefined macros

As for the current test failures, they're both hitting the same failed assertion:

clang: /var/lib/buildkite-agent/builds/linux-56-59b8f5d88-bt7k7-1/llvm-project/github-pull-requests/clang/lib/Frontend/InitPreprocessor.cpp:112: T PickFP(const llvm::fltSemantics *, T, T, T, T, T, T, T) [T = const char *]: Assertion `Sem == (const llvm::fltSemantics*)&llvm::APFloat::IEEEquad()' failed.

It almost seems as though &TI.getBFloat16Format() is returning something other than &llvm::APFloat::BFloat() for a target and thus it falls into the quad assertion while not being a quad semantics. You'll likely have to hook up a debugger to see what's going on there.

Copy link
Member

@overmighty overmighty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR currently adds two suffixes: bf16 and just b. Is this intended? GCC seems to only support bf16: https://godbolt.org/z/hEfcrGrG1.

It currently also lets Clang accept the following C++ code if the target doesn't have bfloat16 but has float16:

auto foo = 1.0bf16;

And it lets Clang accept the following C++ code even if the target has neither bfloat16 nor float16:

auto foo = 1.0b;

It also looks like foo ends up being of type double either way (edit: nevermind, it was only happening with 1.0b, because it was only setting the isBF16 local variable and not isBFloat16):

TranslationUnitDecl 0x5f0373f42d48 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x5f0373f439d0 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x5f0373f43310 '__int128'
|-TypedefDecl 0x5f0373f43a40 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x5f0373f43330 'unsigned __int128'
|-TypedefDecl 0x5f0373f91f70 <<invalid sloc>> <invalid sloc> implicit __NSConstantString '__NSConstantString_tag'
| `-RecordType 0x5f0373f43b30 '__NSConstantString_tag'
|   `-CXXRecord 0x5f0373f43a98 '__NSConstantString_tag'
|-TypedefDecl 0x5f0373f43608 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x5f0373f435c0 'char *'
|   `-BuiltinType 0x5f0373f42df0 'char'
|-TypedefDecl 0x5f0373f43960 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag[1]'
| `-ConstantArrayType 0x5f0373f43910 '__va_list_tag[1]' 1
|   `-RecordType 0x5f0373f436f0 '__va_list_tag'
|     `-CXXRecord 0x5f0373f43660 '__va_list_tag'
`-VarDecl 0x5f0373f92018 <a.cpp:1:1, col:12> col:6 foo 'double' cinit
  `-FloatingLiteral 0x5f0373f920c8 <col:12> 'double' 1.000000e+00

@bassiounix
Copy link
Contributor Author

bassiounix commented Apr 4, 2025

Looks like that BFloat16Format for amdgcn-amd-amdhsa target is not properly initialized and the hasBFloat16Type method at clang/lib/Basic/Targets/AMDGPU.h is using a dummy check to that is based on the triple value only. Also there's no overrides for a full type support.

The global value of BFloat16Format in AMDGPUTI is properly initialized.

I think TargetInfo::adjust at clang/lib/Basic/TargetInfo.cpp may be the reason but I'm not sure

Edit: was just a "copy" problem

@bassiounix bassiounix requested a review from overmighty April 4, 2025 19:33
Comment on lines +982 to +999
case 'b': // FP Suffix for "__bf16"
case 'B':
if (!Target.hasBFloat16Type())
break;
if (!isFPConstant)
break; // Error for integer constant.
if (HasSize)
break;
HasSize = true;

if (s + 3 < ThisTokEnd &&
((s[0] == 'b' && s[1] == 'f') || (s[0] == 'B' && s[1] == 'F')) &&
s[2] == '1' && s[3] == '6') {
s += 3; // success, eat up 3 characters.
isBFloat16 = true;
continue;
}
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true for C++23. Do we want extension warnings in other language modes @AaronBallman?

As an aside, did anyone benchmark that the pattern we use in this function is actually faster than string_view
comparisons?

Copy link
Collaborator

@AaronBallman AaronBallman Apr 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we should have extension warnings in other language modes as well as the precompat warning for C++ before C++23.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[clang] __bf16 Type Support Macros
5 participants