[clang] [HLSL] Implement 202x conforming literals (PR #91015)

Chris B via cfe-commits cfe-commits at lists.llvm.org
Fri May 3 14:13:33 PDT 2024


https://github.com/llvm-beanz created https://github.com/llvm/llvm-project/pull/91015

This implements the HLSL 202x conforming literals feature.

The feature proposal is available here:
https://github.com/microsoft/hlsl-specs/blob/main/proposals/0017-conform ing-literals.md

The language specification for this behavior is available in (poorly rendered) HTML or PDF:
https://microsoft.github.io/hlsl-specs/specs/hlsl.html#Lex.Literal.Float https://microsoft.github.io/hlsl-specs/specs/hlsl.pdf

The main implementation details are:
1) Unsuffixed floating literals are `float`.
2) The integer `ll` suffix specifies `int64_t (aka long)` which is 64-bit because HLSL has no defined `long` keyword or `long long` type.

Resolves #85714

>From 4511cd525a671e8c7ceec9ffc653b351d9b1a4d8 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Wed, 1 May 2024 14:10:58 -0500
Subject: [PATCH] [HLSL] Implement 202x conforming literals

This implements the HLSL 202x conforming literals feature.

The feature proposal is available here:
https://github.com/microsoft/hlsl-specs/blob/main/proposals/0017-conform
ing-literals.md

The language specification for this behavior is available in (poorly
rendered) HTML or PDF:
https://microsoft.github.io/hlsl-specs/specs/hlsl.html#Lex.Literal.Float
https://microsoft.github.io/hlsl-specs/specs/hlsl.pdf

The main implementation details are:
1) Unsuffixed floating literals are `float`.
2) The integer `ll` suffix specifies `int64_t (aka long)` which is
64-bit because HLSL has no defined `long` keyword or `long long` type.

Resolves #85714
---
 clang/lib/Sema/SemaExpr.cpp                   |  11 ++
 clang/test/AST/HLSL/vector-constructors.hlsl  | 135 ++++++++----------
 .../CodeGenHLSL/builtins/ScalarSwizzles.hlsl  |  17 ++-
 .../Arithmetic}/literal_suffixes.hlsl         |   5 +-
 .../Arithmetic/literal_suffixes_202x.hlsl     | 115 +++++++++++++++
 .../literal_suffixes_no_16bit.hlsl            |   5 +-
 .../Types/BuiltinVector/ScalarSwizzles.hlsl   |  13 +-
 7 files changed, 215 insertions(+), 86 deletions(-)
 rename clang/test/SemaHLSL/{ => Types/Arithmetic}/literal_suffixes.hlsl (87%)
 create mode 100644 clang/test/SemaHLSL/Types/Arithmetic/literal_suffixes_202x.hlsl
 rename clang/test/SemaHLSL/{ => Types/Arithmetic}/literal_suffixes_no_16bit.hlsl (86%)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7190e50b156f7b..5b42cf65cf80ff 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4103,6 +4103,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
       Ty = Context.Float16Ty;
     else if (Literal.isFloat128)
       Ty = Context.Float128Ty;
+    else if (getLangOpts().HLSL)
+      Ty = Context.FloatTy;
     else
       Ty = Context.DoubleTy;
 
@@ -4173,6 +4175,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
       // be an unsigned int.
       bool AllowUnsigned = Literal.isUnsigned || Literal.getRadix() != 10;
 
+      // HLSL doesn't really have `long` or `long long`. We support the `ll`
+      // suffix for portability of code with C++, but both `l` and `ll` are
+      // 64-bit integer types, and we want the type of `1l` and `1ll` to be the
+      // same.
+      if (getLangOpts().HLSL && !Literal.isLong && Literal.isLongLong) {
+        Literal.isLong = true;
+        Literal.isLongLong = false;
+      }
+
       // Check from smallest to largest, picking the smallest type we can.
       unsigned Width = 0;
 
diff --git a/clang/test/AST/HLSL/vector-constructors.hlsl b/clang/test/AST/HLSL/vector-constructors.hlsl
index 7861d5209b5d3e..5e0900bb623693 100644
--- a/clang/test/AST/HLSL/vector-constructors.hlsl
+++ b/clang/test/AST/HLSL/vector-constructors.hlsl
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s 
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s
 
 typedef float float2 __attribute__((ext_vector_type(2)));
 typedef float float3 __attribute__((ext_vector_type(3)));
@@ -11,41 +11,36 @@ void entry() {
 
 // For the float2 vector, we just expect a conversion from constructor
 // parameters to an initialization list
-// CHECK: VarDecl 0x{{[0-9a-fA-F]+}} <col:3, col:32> col:10 used Vec2 'float2':'float __attribute__((ext_vector_type(2)))' cinit
-// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:17, col:32> 'float2':'float __attribute__((ext_vector_type(2)))' functional cast to float2 <NoOp>
-// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:24, col:29> 'float2':'float __attribute__((ext_vector_type(2)))'
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' <FloatingCast>
-// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:24> 'double' 1.000000e+00
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:29> 'float' <FloatingCast>
-// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:29> 'double' 2.000000e+00
+// CHECK-LABEL: VarDecl 0x{{[0-9a-fA-F]+}} {{.*}} used Vec2 'float2':'float __attribute__((ext_vector_type(2)))' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float2':'float __attribute__((ext_vector_type(2)))' functional cast to float2 <NoOp>
+// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float2':'float __attribute__((ext_vector_type(2)))'
+// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'float' 2.000000e+00
 
 
 // For the float 3 things get fun...
 // Here we expect accesses to the vec2 to provide the first and second
 // components using ArraySubscriptExpr
-// CHECK: VarDecl 0x{{[0-9a-fA-F]+}} <col:3, col:33> col:10 Vec3 'float3':'float __attribute__((ext_vector_type(3)))' cinit
-// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:17, col:33> 'float3':'float __attribute__((ext_vector_type(3)))' functional cast to float3 <NoOp>
-// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:24, col:30> 'float3':'float __attribute__((ext_vector_type(3)))'
+// CHECK-LABEL: VarDecl 0x{{[0-9a-fA-F]+}} {{.*}} col:10 Vec3 'float3':'float __attribute__((ext_vector_type(3)))' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float3':'float __attribute__((ext_vector_type(3)))' functional cast to float3 <NoOp>
+// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float3':'float __attribute__((ext_vector_type(3)))'
 // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24, <invalid sloc>> 'float' <LValueToRValue>
 // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} <col:24, <invalid sloc>> 'float' lvalue
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float2':'float __attribute__((ext_vector_type(2)))' lvalue Var 0x{{[0-9a-fA-F]+}} 'Vec2' 'float2':'float __attribute__((ext_vector_type(2)))'
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float2':'float __attribute__((ext_vector_type(2)))' lvalue Var 0x{{[0-9a-fA-F]+}} 'Vec2' 'float2':'float __attribute__((ext_vector_type(2)))'
 // CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <<invalid sloc>> 'int' 0
 // CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24, <invalid sloc>> 'float' <LValueToRValue>
 // CHECK-NEXT: ArraySubscriptExpr 0x{{[0-9a-fA-F]+}} <col:24, <invalid sloc>> 'float' lvalue
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float2':'float __attribute__((ext_vector_type(2)))' lvalue Var 0x{{[0-9a-fA-F]+}} 'Vec2' 'float2':'float __attribute__((ext_vector_type(2)))'
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float2':'float __attribute__((ext_vector_type(2)))' lvalue Var 0x{{[0-9a-fA-F]+}} 'Vec2' 'float2':'float __attribute__((ext_vector_type(2)))'
 // CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <<invalid sloc>> 'int' 1
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:30> 'float' <FloatingCast>
-// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:30> 'double' 3.000000e+00
-
-// CHECK: VarDecl 0x{{[0-9a-fA-F]+}} <col:3, col:38> col:10 Vec3b 'float3':'float __attribute__((ext_vector_type(3)))' cinit
-// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} <col:18, col:38> 'float3':'float __attribute__((ext_vector_type(3)))' functional cast to float3 <NoOp>
-// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} <col:25, col:35> 'float3':'float __attribute__((ext_vector_type(3)))'
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:25> 'float' <FloatingCast>
-// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:25> 'double' 1.000000e+00
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:30> 'float' <FloatingCast>
-// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:30> 'double' 2.000000e+00
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:35> 'float' <FloatingCast>
-// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:35> 'double' 3.000000e+00
+// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'float' 3.000000e+00
+
+// CHECK: VarDecl 0x{{[0-9a-fA-F]+}} {{.*}} col:10 Vec3b 'float3':'float __attribute__((ext_vector_type(3)))' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float3':'float __attribute__((ext_vector_type(3)))' functional cast to float3 <NoOp>
+// CHECK-NEXT: InitListExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float3':'float __attribute__((ext_vector_type(3)))'
+
+// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'float' 2.000000e+00
+// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'float' 3.000000e+00
 
 // The tests above verify pretty explictily that the Initialization lists are
 // being constructed as expected. The next tests are bit sparser for brevity.
@@ -53,91 +48,85 @@ void entry() {
   float f = 1.0f, g = 2.0f;
   float2 foo0 = float2(f, g); // Non-literal
 
-// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:54:3, col:29>
-// CHECK-NEXT: VarDecl
+// CHECK-LABEL: VarDecl 0x{{[0-9a-fA-F]+}} {{.*}} foo0 'float2'
 // CHECK-NEXT: CXXFunctionalCastExpr
 // CHECK-NEXT: InitListExpr
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' <LValueToRValue>
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' lvalue Var  0x{{[0-9a-fA-F]+}} 'f' 'float'
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' <LValueToRValue>
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' lvalue Var  0x{{[0-9a-fA-F]+}} 'g' 'float'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' lvalue Var  0x{{[0-9a-fA-F]+}} 'f' 'float'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' lvalue Var  0x{{[0-9a-fA-F]+}} 'g' 'float'
 
   int i = 1, j = 2;
   float2 foo1 = float2(1, 2); // Integer literals
 
-// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:66:3, col:29>
-// CHECK-NEXT: VarDecl
+// CHECK-LABEL: VarDecl 0x{{[0-9a-fA-F]+}} {{.*}} foo1 'float2'
 // CHECK-NEXT: CXXFunctionalCastExpr
 // CHECK-NEXT: InitListExpr
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' <IntegralToFloating>
-// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:24> 'int' 1
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' <IntegralToFloating>
-// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} <col:27> 'int' 2
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'int' 1
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: IntegerLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'int' 2
 
   float2 foo2 = float2(i, j); // Integer non-literal
 
-// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:77:3, col:29>
-// CHECK-NEXT: VarDecl
+// CHECK-LABEL: VarDecl 0x{{[0-9a-fA-F]+}} {{.*}} foo2 'float2'
 // CHECK-NEXT: CXXFunctionalCastExpr
 // CHECK-NEXT: InitListExpr
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' <IntegralToFloating>
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'int' <LValueToRValue>
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> 'int' lvalue Var 0x{{[0-9a-fA-F]+}} 'i' 'int'
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' <IntegralToFloating>
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'int' <LValueToRValue>
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:27> 'int' lvalue Var 0x{{[0-9a-fA-F]+}} 'j' 'int'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'int' lvalue Var 0x{{[0-9a-fA-F]+}} 'i' 'int'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'int' lvalue Var 0x{{[0-9a-fA-F]+}} 'j' 'int'
 
   struct S { float f; } s;
   float2 foo4 = float2(s.f, s.f);
 
-// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:91:3, col:33>
-// CHECK-NEXT: VarDecl
+// CHECK-LABEL: VarDecl 0x{{[0-9a-fA-F]+}} {{.*}} foo4 'float2'
 // CHECK-NEXT: CXXFunctionalCastExpr
 // CHECK-NEXT: InitListExpr
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24, col:26> 'float' <LValueToRValue>
-// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} <col:24, col:26> 'float' lvalue .f 0x{{[0-9a-fA-F]+}}
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> 'struct S':'S' lvalue Var 0x{{[0-9a-fA-F]+}} 's' 'struct S':'S'
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:29, col:31> 'float' <LValueToRValue>
-// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} <col:29, col:31> 'float' lvalue .f 0x{{[0-9a-fA-F]+}}
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:29> 'struct S':'S' lvalue Var 0x{{[0-9a-fA-F]+}} 's' 'struct S':'S'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' lvalue .f 0x{{[0-9a-fA-F]+}}
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'struct S':'S' lvalue Var 0x{{[0-9a-fA-F]+}} 's' 'struct S':'S'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' lvalue .f 0x{{[0-9a-fA-F]+}}
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'struct S':'S' lvalue Var 0x{{[0-9a-fA-F]+}} 's' 'struct S':'S'
 
   struct T {
     operator float() const { return 1.0f; }
   } t;
   float2 foo5 = float2(t, t); // user-defined cast operator
 
-// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:107:3, col:29>
-// CHECK-NEXT: VarDecl
+// CHECK-LABEL: VarDecl 0x{{[0-9a-fA-F]+}} {{.*}} foo5 'float2'
 // CHECK-NEXT: CXXFunctionalCastExpr
 // CHECK-NEXT: InitListExpr
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float' <UserDefinedConversion>
-// CHECK-NEXT: CXXMemberCallExpr 0x{{[0-9a-fA-F]+}} <col:24> 'float'
-// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} <col:24> '<bound member function type>' .operator float 0x{{[0-9a-fA-F]+}}
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:24> 'const T' lvalue <NoOp>
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:24> 'struct T':'T' lvalue Var 0x{{[0-9a-fA-F]+}} 't' 'struct T':'T'
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float' <UserDefinedConversion>
-// CHECK-NEXT: CXXMemberCallExpr 0x{{[0-9a-fA-F]+}} <col:27> 'float'
-// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} <col:27> '<bound member function type>' .operator float 0x{{[0-9a-fA-F]+}}
-// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} <col:27> 'const T' lvalue <NoOp>
-// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} <col:27> 'struct T':'T' lvalue Var 0x{{[0-9a-fA-F]+}} 't' 'struct T':'T'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' <UserDefinedConversion>
+// CHECK-NEXT: CXXMemberCallExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float'
+// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} {{.*}} '<bound member function type>' .operator float 0x{{[0-9a-fA-F]+}}
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'const T' lvalue <NoOp>
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'struct T':'T' lvalue Var 0x{{[0-9a-fA-F]+}} 't' 'struct T':'T'
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float' <UserDefinedConversion>
+// CHECK-NEXT: CXXMemberCallExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'float'
+// CHECK-NEXT: MemberExpr 0x{{[0-9a-fA-F]+}} {{.*}} '<bound member function type>' .operator float 0x{{[0-9a-fA-F]+}}
+// CHECK-NEXT: ImplicitCastExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'const T' lvalue <NoOp>
+// CHECK-NEXT: DeclRefExpr 0x{{[0-9a-fA-F]+}} {{.*}} 'struct T':'T' lvalue Var 0x{{[0-9a-fA-F]+}} 't' 'struct T':'T'
 
   typedef float2 second_level_of_typedefs;
   second_level_of_typedefs foo6 = float2(1.0f, 2.0f);
 
-// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:125:3, col:53>
-// CHECK-NEXT: VarDecl
+
+// CHECK-LABEL: VarDecl 0x{{[0-9a-fA-F]+}} {{.*}} foo6 'second_level_of_typedefs'
 // CHECK-NEXT: CXXFunctionalCastExpr
 // CHECK-NEXT: InitListExpr
-// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:42> 'float' 1.000000e+00
-// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:48> 'float' 2.000000e+00
+// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'float' 2.000000e+00
 
   float2 foo7 = second_level_of_typedefs(1.0f, 2.0f);
 
-// CHECK: DeclStmt 0x{{[0-9a-fA-F]+}} <line:134:3, col:53>
-// CHECK-NEXT: VarDecl
+// CHECK-LABEL: VarDecl 0x{{[0-9a-fA-F]+}} {{.*}} foo7 'float2'
 // CHECK-NEXT: CXXFunctionalCastExpr
 // CHECK-NEXT: InitListExpr
-// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:42> 'float' 1.000000e+00
-// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} <col:48> 'float' 2.000000e+00
+// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral 0x{{[0-9a-fA-F]+}} {{.*}} 'float' 2.000000e+00
 
 }
diff --git a/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl b/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl
index 36f71f6860c06b..6395ddc2fee2a2 100644
--- a/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/ScalarSwizzles.hlsl
@@ -55,7 +55,7 @@ vector<uint64_t,4> FillOneUnsignedLong(){
 // CHECK: [[vec2:%.*]] = shufflevector <1 x double> [[vec1]], <1 x double> poison, <2 x i32> zeroinitializer
 // CHECK: ret <2 x double> [[vec2]]
 double2 FillTwoPointFive(){
-  return 2.5.rr;
+  return 2.5l.rr;
 }
 
 // CHECK-LABEL: FillOneHalf
@@ -65,7 +65,7 @@ double2 FillTwoPointFive(){
 // CHECK: [[vec3:%.*]] = shufflevector <1 x double> [[vec1]], <1 x double> poison, <3 x i32> zeroinitializer
 // CHECK: ret <3 x double> [[vec3]]
 double3 FillOneHalf(){
-  return .5.rrr;
+  return .5l.rrr;
 }
 
 // CHECK-LABEL: FillTwoPointFiveFloat
@@ -110,7 +110,7 @@ float2 HowManyFloats(float V) {
   return V.rr.rr;
 }
 
-// This codegen is gnarly because `1.` is a double, so this creates double
+// This codegen is gnarly because `1.l` is a double, so this creates double
 // vectors that need to be truncated down to floats. The optimizer cleans this
 // up nicely too.
 
@@ -123,6 +123,17 @@ float2 HowManyFloats(float V) {
 // CHECK: ret <3 x float> [[vec3f]]
 
 float3 AllRighty() {
+  return 1.l.rrr;
+}
+
+// CHECK-LABEL: AllRighty2
+// CHECK: [[vec1Ptr:%.*]] = alloca <1 x float>, align 4
+// CHECK: store <1 x float> <float 1.000000e+00>, ptr [[vec1Ptr]], align 4
+// CHECK: [[vec1:%.*]] = load <1 x float>, ptr [[vec1Ptr]], align 4
+// CHECK: [[vec3:%.*]] = shufflevector <1 x float> [[vec1]], <1 x float> poison, <3 x i32>
+// CHECK: ret <3 x float> [[vec3]]
+
+float3 AllRighty2() {
   return 1..rrr;
 }
 
diff --git a/clang/test/SemaHLSL/literal_suffixes.hlsl b/clang/test/SemaHLSL/Types/Arithmetic/literal_suffixes.hlsl
similarity index 87%
rename from clang/test/SemaHLSL/literal_suffixes.hlsl
rename to clang/test/SemaHLSL/Types/Arithmetic/literal_suffixes.hlsl
index 25a4d3b5103c48..91324e57ce69ea 100644
--- a/clang/test/SemaHLSL/literal_suffixes.hlsl
+++ b/clang/test/SemaHLSL/Types/Arithmetic/literal_suffixes.hlsl
@@ -49,10 +49,7 @@ 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<float, __decltype(1.0)>::value, "1.0 literal is 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");
diff --git a/clang/test/SemaHLSL/Types/Arithmetic/literal_suffixes_202x.hlsl b/clang/test/SemaHLSL/Types/Arithmetic/literal_suffixes_202x.hlsl
new file mode 100644
index 00000000000000..2aeb4047565d6a
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/Arithmetic/literal_suffixes_202x.hlsl
@@ -0,0 +1,115 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.4-library -finclude-default-header -verify %s
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.4-library -finclude-default-header -verify -fnative-half-type %s
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -finclude-default-header -verify %s
+// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -finclude-default-header -verify -fnative-half-type %s
+
+// This test is adapted from the test in DXC:
+// tools/clang/test/SemaHLSL/v202x/conforming-literals/valid-literals.hlsl
+
+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;
+};
+
+bool B; // Used for ternary operator tests below
+
+////////////////////////////////////////////////////////////////////////////////
+// Literals Without Suffixes
+////////////////////////////////////////////////////////////////////////////////
+
+_Static_assert(is_same<__decltype(1.0), float>::value, "Literals are now float");
+
+_Static_assert(is_same<__decltype(0), int>::value, "0 is int");
+_Static_assert(is_same<__decltype(1), int>::value, "1 is int");
+
+// Decimal literals are always signed.
+_Static_assert(is_same<__decltype(2147483647), int>::value, "2147483647 is int");
+_Static_assert(is_same<__decltype(2147483648), int64_t>::value, "2147483648 is int64_t");
+_Static_assert(is_same<__decltype(4294967296), int64_t>::value, "4294967296 is int64_t");
+
+// This is an anomaly that exists in C as well as HLSL. This value can't be
+// represented as a signed integer, but base-10 literals are always signed.
+// Clang emits a warning that it is interpreting it as unsigned because that is
+// not conforming to the C standard.
+
+// expected-warning at +1{{integer literal is too large to be represented in type 'long' and is subject to undefined behavior under C++98, interpreting as 'unsigned long'; this literal will be ill-formed in C++11 onwards}}
+static const uint64_t V = 9223372036854775808;
+
+_Static_assert(is_same<__decltype(0x0), int>::value, "0x0 is int");
+_Static_assert(is_same<__decltype(0x70000000), int>::value, "0x70000000 is int");
+_Static_assert(is_same<__decltype(0xF0000000), uint>::value, "0xF0000000 is uint");
+
+_Static_assert(is_same<__decltype(0x7000000000000000), int64_t>::value, "0x7000000000000000 is int64_t");
+_Static_assert(is_same<__decltype(0xF000000000000000), uint64_t>::value, "0xF000000000000000 is uint64_t");
+
+////////////////////////////////////////////////////////////////////////////////
+// Integer literals With Suffixes
+////////////////////////////////////////////////////////////////////////////////
+
+_Static_assert(is_same<__decltype(1l), int64_t>::value, "1l is int64_t");
+_Static_assert(is_same<__decltype(1ul), uint64_t>::value, "1ul is uint64_t");
+_Static_assert(is_same<__decltype(1lu), uint64_t>::value, "1lu is uint64_t");
+
+// HLSL 2021 does not define a `long long` type, so the suffix should be
+// invalid.
+_Static_assert(is_same<__decltype(1ll), int64_t>::value, "1ll is int64_t");
+_Static_assert(is_same<__decltype(1ull), uint64_t>::value, "1ull is uint64_t");
+_Static_assert(is_same<__decltype(1llu), uint64_t>::value, "1llu is uint64_t");
+
+// Verify that the size of `long long` is the same as the size of `int64_t`.
+_Static_assert(sizeof(__decltype(1ll)) == sizeof(int64_t), "sizeof(1ll) == sizeof(int64_t)");
+_Static_assert(sizeof(__decltype(1llu)) == sizeof(uint64_t), "sizeof(1llu) == sizeof(uint64_t)");
+
+////////////////////////////////////////////////////////////////////////////////
+// Ternary operators on integer literals
+////////////////////////////////////////////////////////////////////////////////
+
+_Static_assert(is_same<__decltype(B ? 1 : 1), int>::value, "B ? 1 : 1 is int");
+
+_Static_assert(is_same<__decltype(B ? 1l : 1), int64_t>::value, "B ? 1l : 1 is int64_t");
+_Static_assert(is_same<__decltype(B ? 1 : 1l), int64_t>::value, "B ? 1 : 1l is int64_t");
+
+_Static_assert(is_same<__decltype(B ? 1ul : 1), uint64_t>::value, "B ? 1ul : 1 is uint64_t");
+_Static_assert(is_same<__decltype(B ? 1 : 1ul), uint64_t>::value, "B ? 1 : 1ul is uint64_t");
+
+////////////////////////////////////////////////////////////////////////////////
+// Floating point literals With Suffixes
+////////////////////////////////////////////////////////////////////////////////
+
+_Static_assert(is_same<__decltype(1.0h), half>::value, "1.0h is half");
+_Static_assert(is_same<__decltype(1.0f), float>::value, "1.0f is float");
+_Static_assert(is_same<__decltype(1.0l), double>::value, "1.0l is double");
+
+////////////////////////////////////////////////////////////////////////////////
+// Ternary operators on floating point literals
+////////////////////////////////////////////////////////////////////////////////
+
+_Static_assert(is_same<__decltype(B ? 1.0 : 1.0), float>::value, "B ? 1.0 : 1.0 is float");
+
+_Static_assert(is_same<__decltype(B ? 1.0l : 1.0l), double>::value, "B ? 1.0l : 1.0l is double");
+_Static_assert(is_same<__decltype(B ? 1.0f : 1.0f), float>::value, "B ? 1.0f : 1.0f is float");
+
+
+_Static_assert(is_same<__decltype(B ? 1.0f : 1.0l), double>::value, "B ? 1.0f : 1.0l is double");
+_Static_assert(is_same<__decltype(B ? 1.0l : 1.0f), double>::value, "B ? 1.0l : 1.0f is double");
+
+_Static_assert(is_same<__decltype(B ? 1.0l : 1.0), double>::value, "B ? 1.0l : 1.0 is double");
+_Static_assert(is_same<__decltype(B ? 1.0 : 1.0l), double>::value, "B ? 1.0 : 1.0l is double");
+_Static_assert(is_same<__decltype(B ? 1.0f : 1.0), float>::value, "B ? 1.0f : 1.0 is float");
+_Static_assert(is_same<__decltype(B ? 1.0 : 1.0f), float>::value, "B ? 1.0 : 1.0f is float");
+
+_Static_assert(is_same<__decltype(B ? 1.0h : 1.0h), half>::value, "B ? 1.0h : 1.0h is half");
+
+_Static_assert(is_same<__decltype(B ? 1.0f : 1.0h), float>::value, "B ? 1.0f : 1.0h is float");
+_Static_assert(is_same<__decltype(B ? 1.0h : 1.0f), float>::value, "B ? 1.0h : 1.0f is float");
+
+_Static_assert(is_same<__decltype(B ? 1.0l : 1.0h), double>::value, "B ? 1.0l : 1.0h is double");
+_Static_assert(is_same<__decltype(B ? 1.0h : 1.0l), double>::value, "B ? 1.0h : 1.0l is double");
+
+_Static_assert(is_same<__decltype(B ? 1.0h : 1.0), float>::value, "B ? 1.0h : 1.0 is float");
+_Static_assert(is_same<__decltype(B ? 1.0 : 1.0h), float>::value, "B ? 1.0 : 1.0h is float");
diff --git a/clang/test/SemaHLSL/literal_suffixes_no_16bit.hlsl b/clang/test/SemaHLSL/Types/Arithmetic/literal_suffixes_no_16bit.hlsl
similarity index 86%
rename from clang/test/SemaHLSL/literal_suffixes_no_16bit.hlsl
rename to clang/test/SemaHLSL/Types/Arithmetic/literal_suffixes_no_16bit.hlsl
index 73e57041329e88..f7e3e6ba577d68 100644
--- a/clang/test/SemaHLSL/literal_suffixes_no_16bit.hlsl
+++ b/clang/test/SemaHLSL/Types/Arithmetic/literal_suffixes_no_16bit.hlsl
@@ -49,10 +49,7 @@ 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<float, __decltype(1.0)>::value, "1.0 literal is 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");
diff --git a/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl b/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
index a2e9a5f865ece1..4fa04f3d598898 100644
--- a/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
+++ b/clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzles.hlsl
@@ -54,7 +54,7 @@ vector<uint64_t,4> FillOneUnsignedLong(){
 // CHECK-NEXT: FloatingLiteral {{.*}} 'double' 2.500000e+00
 
 double2 FillTwoPointFive(){
-  return 2.5.rr;
+  return 2.5l.rr;
 }
 
 // CHECK-LABEL: FillOneHalf
@@ -63,7 +63,7 @@ double2 FillTwoPointFive(){
 // CHECK-NEXT: FloatingLiteral {{.*}} 'double' 5.000000e-01
 
 double3 FillOneHalf(){
-  return .5.rrr;
+  return .5l.rrr;
 }
 
 // CHECK-LABEL: FillTwoPointFiveFloat
@@ -119,5 +119,14 @@ int64_t4 HooBoy() {
 // CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.000000e+00
 
 float3 AllRighty() {
+  return 1.l.rrr;
+}
+
+// CHECK-LABEL: AllRighty2
+// CHECK: ExtVectorElementExpr {{.*}} 'float __attribute__((ext_vector_type(3)))' rrr
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float __attribute__((ext_vector_type(1)))' <VectorSplat>
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+
+float3 AllRighty2() {
   return 1..rrr;
 }



More information about the cfe-commits mailing list