https://github.com/farzonl updated https://github.com/llvm/llvm-project/pull/93879
>From f1fc152552989f307ededc6076b1e97c18b25aa4 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Thu, 30 May 2024 13:51:35 -0400 Subject: [PATCH 1/4] [HLSL] add loop unroll - `Attr.td` - Define the HLSL loop attribute hints (unroll and loop) - `AttrDocs.td` - Add documentation for unroll and loop - `CGLoopInfo.cpp` - Add codegen for HLSL unroll that maps to clang unroll expectations - `ParseStmt.cpp` - For statements if HLSL define DeclSpecAttrs via MaybeParseMicrosoftAttributes - `SemaStmtAttr.cpp` - Add the HLSL loop unroll handeling --- clang/include/clang/Basic/Attr.td | 13 ++++ clang/include/clang/Basic/AttrDocs.td | 47 +++++++++++ clang/lib/CodeGen/CGLoopInfo.cpp | 15 +++- clang/lib/Parse/ParseStmt.cpp | 11 ++- clang/lib/Sema/SemaStmtAttr.cpp | 29 +++++++ clang/test/CodeGenHLSL/loops/unroll.hlsl | 99 ++++++++++++++++++++++++ 6 files changed, 208 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGenHLSL/loops/unroll.hlsl diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 2665b7353ca4a..e319db08ba168 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4114,6 +4114,19 @@ def LoopHint : Attr { let HasCustomParsing = 1; } +/// The HLSL loop attributes +def HLSLLoopHint: StmtAttr { + /// [unroll(directive)] + /// [loop] + let Spellings = [Microsoft<"unroll">, Microsoft<"loop">]; + let Args = [UnsignedArgument<"directive">]; + let Subjects = SubjectList<[ForStmt, WhileStmt, DoStmt], + ErrorDiag, "'for', 'while', and 'do' statements">; + let LangOpts = [HLSL]; + let Documentation = [HLSLLoopHintDocs, HLSLUnrollHintDocs]; + let HasCustomParsing = 1; +} + def CapturedRecord : InheritableAttr { // This attribute has no spellings as it is only ever created implicitly. let Spellings = []; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index a313e811c9d21..d84af9402d6db 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -7342,6 +7342,53 @@ where shaders must be compiled into a library and linked at runtime. }]; } +def HLSLLoopHintDocs : Documentation { + let Category = DocCatStmt; + let Heading = "#[loop]"; + let Content = [{ +The ``[loop]`` directive allows loop optimization hints to be +specified for the subsequent loop. The directive allows unrolling to +be disabled and is not compatible with [unroll(x)]. + +Specifying the parameter, ``[loop]``, directs the +unroller to not unroll the loop. + +.. code-block:: hlsl + + [loop] + for (...) { + ... + } + +See `hlsl loop extensions +<https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-for>`_ +for details. + }]; +} + +def HLSLUnrollHintDocs : Documentation { + let Category = DocCatStmt; + let Heading = "[unroll(x)]"; + let Content = [{ +Loop unrolling optimization hints can be specified with ``[unroll(x)]`` +. The attribute is placed immediately before a for, while, +or do-while. +Specifying the parameter, ``[unroll(_value_)]``, directs the +unroller to unroll the loop ``_value_`` times. Note: [unroll(x)] is not compatible with [loop]. + +.. code-block:: hlsl + + [unroll(4)] + for (...) { + ... + } +See +`hlsl loop extensions +<https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-for>`_ +for details. + }]; +} + def ClangRandomizeLayoutDocs : Documentation { let Category = DocCatDecl; let Heading = "randomize_layout, no_randomize_layout"; diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp index 0d4800b90a2f2..6b886bd6b6d2c 100644 --- a/clang/lib/CodeGen/CGLoopInfo.cpp +++ b/clang/lib/CodeGen/CGLoopInfo.cpp @@ -612,9 +612,9 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx, const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr); const OpenCLUnrollHintAttr *OpenCLHint = dyn_cast<OpenCLUnrollHintAttr>(Attr); - + const HLSLLoopHintAttr *HLSLLoopHint = dyn_cast<HLSLLoopHintAttr>(Attr); // Skip non loop hint attributes - if (!LH && !OpenCLHint) { + if (!LH && !OpenCLHint && !HLSLLoopHint) { continue; } @@ -635,6 +635,17 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx, Option = LoopHintAttr::UnrollCount; State = LoopHintAttr::Numeric; } + } else if (HLSLLoopHint) { + ValueInt = HLSLLoopHint->getDirective(); + if (HLSLLoopHint->getSemanticSpelling() == + HLSLLoopHintAttr::Spelling::Microsoft_unroll) { + if (ValueInt == 0) + State = LoopHintAttr::Enable; + if (ValueInt > 0) { + Option = LoopHintAttr::UnrollCount; + State = LoopHintAttr::Numeric; + } + } } else if (LH) { auto *ValueExpr = LH->getValue(); if (ValueExpr) { diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index c25203243ee49..b8a717820c418 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -114,18 +114,21 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, // here because we don't want to allow arbitrary orderings. ParsedAttributes CXX11Attrs(AttrFactory); MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true); - ParsedAttributes GNUAttrs(AttrFactory); + ParsedAttributes DeclSpecAttrs(AttrFactory); if (getLangOpts().OpenCL) - MaybeParseGNUAttributes(GNUAttrs); + MaybeParseGNUAttributes(DeclSpecAttrs); + + if (getLangOpts().HLSL) + MaybeParseMicrosoftAttributes(DeclSpecAttrs); StmtResult Res = ParseStatementOrDeclarationAfterAttributes( - Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs, GNUAttrs); + Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs, DeclSpecAttrs); MaybeDestroyTemplateIds(); // Attributes that are left should all go on the statement, so concatenate the // two lists. ParsedAttributes Attrs(AttrFactory); - takeAndConcatenateAttrs(CXX11Attrs, GNUAttrs, Attrs); + takeAndConcatenateAttrs(CXX11Attrs, DeclSpecAttrs, Attrs); assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) && "attributes on empty statement"); diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 6f538ed55cb72..35a20c113f628 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/StringExtras.h" @@ -584,6 +585,32 @@ static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A, return ::new (S.Context) OpenCLUnrollHintAttr(S.Context, A, UnrollFactor); } +static Attr *handleHLSLLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, + SourceRange Range) { + unsigned UnrollFactor = 0; + if (A.getNumArgs() == 1) { + Expr *E = A.getArgAsExpr(0); + std::optional<llvm::APSInt> ArgVal; + + if (!(ArgVal = E->getIntegerConstantExpr(S.Context))) { + S.Diag(A.getLoc(), diag::err_attribute_argument_type) + << A << AANT_ArgumentIntegerConstant << E->getSourceRange(); + return nullptr; + } + + int Val = ArgVal->getSExtValue(); + if (Val <= 0) { + S.Diag(A.getRange().getBegin(), + diag::err_attribute_requires_positive_integer) + << A << /* positive */ 0; + return nullptr; + } + UnrollFactor = static_cast<unsigned>(Val); + } + + return ::new (S.Context) HLSLLoopHintAttr(S.Context, A, UnrollFactor); +} + static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { if (A.isInvalid() || A.getKind() == ParsedAttr::IgnoredAttribute) @@ -618,6 +645,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, return handleFallThroughAttr(S, St, A, Range); case ParsedAttr::AT_LoopHint: return handleLoopHintAttr(S, St, A, Range); + case ParsedAttr::AT_HLSLLoopHint: + return handleHLSLLoopHintAttr(S, St, A, Range); case ParsedAttr::AT_OpenCLUnrollHint: return handleOpenCLUnrollHint(S, St, A, Range); case ParsedAttr::AT_Suppress: diff --git a/clang/test/CodeGenHLSL/loops/unroll.hlsl b/clang/test/CodeGenHLSL/loops/unroll.hlsl new file mode 100644 index 0000000000000..0ebe5b0e847e4 --- /dev/null +++ b/clang/test/CodeGenHLSL/loops/unroll.hlsl @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ +// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -o - | FileCheck %s + +/*** for ***/ +void for_count() +{ +// CHECK-LABEL: for_count + [unroll(8)] + for( int i = 0; i < 1000; ++i); +// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_DISTINCT:.*]] +} + +void for_disable() +{ +// CHECK-LABEL: for_disable + [loop] + for( int i = 0; i < 1000; ++i); +// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_DISABLE:.*]] +} + +void for_enable() +{ +// CHECK-LABEL: for_enable + [unroll] + for( int i = 0; i < 1000; ++i); +// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_ENABLE:.*]] +} + +/*** while ***/ +void while_count() +{ +// CHECK-LABEL: while_count + int i = 1000; + [unroll(4)] + while(i-->0); +// CHECK: br label %{{.*}}, !llvm.loop ![[WHILE_DISTINCT:.*]] +} + +void while_disable() +{ +// CHECK-LABEL: while_disable + int i = 1000; + [loop] + while(i-->0); +// CHECK: br label %{{.*}}, !llvm.loop ![[WHILE_DISABLE:.*]] +} + +void while_enable() +{ +// CHECK-LABEL: while_enable + int i = 1000; + [unroll] + while(i-->0); +// CHECK: br label %{{.*}}, !llvm.loop ![[WHILE_ENABLE:.*]] +} + +/*** do ***/ +void do_count() +{ +// CHECK-LABEL: do_count + int i = 1000; + [unroll(16)] + do {} while(i--> 0); +// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !llvm.loop ![[DO_DISTINCT:.*]] +} + +void do_disable() +{ +// CHECK-LABEL: do_disable + int i = 1000; + [loop] + do {} while(i--> 0); +// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !llvm.loop ![[DO_DISABLE:.*]] +} + +void do_enable() +{ +// CHECK-LABEL: do_enable + int i = 1000; + [unroll] + do {} while(i--> 0); +// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !llvm.loop ![[DO_ENABLE:.*]] +} + + +// CHECK: ![[FOR_DISTINCT]] = distinct !{![[FOR_DISTINCT]], ![[FOR_COUNT:.*]]} +// CHECK: ![[FOR_COUNT]] = !{!"llvm.loop.unroll.count", i32 8} +// CHECK: ![[FOR_DISABLE]] = distinct !{![[FOR_DISABLE]], ![[DISABLE:.*]]} +// CHECK: ![[DISABLE]] = !{!"llvm.loop.unroll.disable"} +// CHECK: ![[FOR_ENABLE]] = distinct !{![[FOR_ENABLE]], ![[ENABLE:.*]]} +// CHECK: ![[ENABLE]] = !{!"llvm.loop.unroll.enable"} +// CHECK: ![[WHILE_DISTINCT]] = distinct !{![[WHILE_DISTINCT]], ![[WHILE_COUNT:.*]]} +// CHECK: ![[WHILE_COUNT]] = !{!"llvm.loop.unroll.count", i32 4} +// CHECK: ![[WHILE_DISABLE]] = distinct !{![[WHILE_DISABLE]], ![[DISABLE]]} +// CHECK: ![[WHILE_ENABLE]] = distinct !{![[WHILE_ENABLE]], ![[ENABLE]]} +// CHECK: ![[DO_DISTINCT]] = distinct !{![[DO_DISTINCT]], ![[DO_COUNT:.*]]} +// CHECK: ![[DO_COUNT]] = !{!"llvm.loop.unroll.count", i32 16} +// CHECK: ![[DO_DISABLE]] = distinct !{![[DO_DISABLE]], ![[DISABLE]]} +// CHECK: ![[DO_ENABLE]] = distinct !{![[DO_ENABLE]], ![[ENABLE]]} >From 5b73b55a7655ae26e2c88eb9b62863a204fe7937 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Fri, 31 May 2024 14:31:26 -0400 Subject: [PATCH 2/4] fix documentation --- clang/include/clang/Basic/AttrDocs.td | 66 +++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index d84af9402d6db..2776ae9ead55c 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -7344,7 +7344,7 @@ where shaders must be compiled into a library and linked at runtime. def HLSLLoopHintDocs : Documentation { let Category = DocCatStmt; - let Heading = "#[loop]"; + let Heading = "[loop]"; let Content = [{ The ``[loop]`` directive allows loop optimization hints to be specified for the subsequent loop. The directive allows unrolling to @@ -7360,15 +7360,28 @@ unroller to not unroll the loop. ... } -See `hlsl loop extensions -<https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-for>`_ +.. code-block:: hlsl + + [loop] + while (...) { + ... + } + +.. code-block:: hlsl + + [loop] + do { + ... + } while (...) + +See `hlsl loop extensions <https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-for>`_ for details. }]; } def HLSLUnrollHintDocs : Documentation { let Category = DocCatStmt; - let Heading = "[unroll(x)]"; + let Heading = "[unroll(x)], [unroll]"; let Content = [{ Loop unrolling optimization hints can be specified with ``[unroll(x)]`` . The attribute is placed immediately before a for, while, @@ -7382,9 +7395,43 @@ unroller to unroll the loop ``_value_`` times. Note: [unroll(x)] is not compatib for (...) { ... } -See -`hlsl loop extensions -<https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-for>`_ + +.. code-block:: hlsl + + [unroll] + for (...) { + ... + } + +.. code-block:: hlsl + + [unroll(4)] + while (...) { + ... + } + +.. code-block:: hlsl + + [unroll] + while (...) { + ... + } + +.. code-block:: hlsl + + [unroll(4)] + do { + ... + } while (...) + +.. code-block:: hlsl + + [unroll] + do { + ... + } while (...) + +See `hlsl loop extensions <https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-for>`_ for details. }]; } @@ -7448,7 +7495,8 @@ b for constant buffer views (CBV). Register space is specified in the format ``space[number]`` and defaults to ``space0`` if omitted. Here're resource binding examples with and without space: -.. code-block:: c++ + +.. code-block:: hlsl RWBuffer<float> Uav : register(u3, space1); Buffer<float> Buf : register(t1); @@ -7466,7 +7514,7 @@ A subcomponent is a register number, which is an integer. A component is in the Examples: -.. code-block:: c++ +.. code-block:: hlsl cbuffer A { float3 a : packoffset(c0.y); >From 8d75c8c6a2f36232e93190003695a3ff805a05c6 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Mon, 3 Jun 2024 19:47:37 -0400 Subject: [PATCH 3/4] - add sema checks for loop unroll, switch. - Remove need for custom parsing by adding default val - Add nested loop tests --- clang/include/clang/Basic/Attr.td | 3 +- clang/lib/Sema/SemaStmtAttr.cpp | 29 ++++++++------ clang/test/CodeGenHLSL/loops/unroll.hlsl | 31 +++++++++++++++ clang/test/SemaHLSL/Loops/unroll.hlsl | 48 ++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 clang/test/SemaHLSL/Loops/unroll.hlsl diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index e319db08ba168..f1d8daa8f1e72 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4119,12 +4119,11 @@ def HLSLLoopHint: StmtAttr { /// [unroll(directive)] /// [loop] let Spellings = [Microsoft<"unroll">, Microsoft<"loop">]; - let Args = [UnsignedArgument<"directive">]; + let Args = [UnsignedArgument<"directive", /*opt*/1>]; let Subjects = SubjectList<[ForStmt, WhileStmt, DoStmt], ErrorDiag, "'for', 'while', and 'do' statements">; let LangOpts = [HLSL]; let Documentation = [HLSLLoopHintDocs, HLSLUnrollHintDocs]; - let HasCustomParsing = 1; } def CapturedRecord : InheritableAttr { diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 35a20c113f628..7f452d177c16f 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -587,27 +587,34 @@ static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A, static Attr *handleHLSLLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { + + if (A.getSemanticSpelling() == HLSLLoopHintAttr::Spelling::Microsoft_loop && + !A.checkAtMostNumArgs(S, 0)) + return nullptr; + unsigned UnrollFactor = 0; if (A.getNumArgs() == 1) { - Expr *E = A.getArgAsExpr(0); - std::optional<llvm::APSInt> ArgVal; - if (!(ArgVal = E->getIntegerConstantExpr(S.Context))) { + if (A.isArgIdent(0)) { S.Diag(A.getLoc(), diag::err_attribute_argument_type) - << A << AANT_ArgumentIntegerConstant << E->getSourceRange(); + << A << AANT_ArgumentIntegerConstant << A.getRange(); return nullptr; } - int Val = ArgVal->getSExtValue(); - if (Val <= 0) { - S.Diag(A.getRange().getBegin(), - diag::err_attribute_requires_positive_integer) - << A << /* positive */ 0; + Expr *E = A.getArgAsExpr(0); + + if (S.CheckLoopHintExpr(E, St->getBeginLoc(), + /*AllowZero=*/false)) return nullptr; - } + + std::optional<llvm::APSInt> ArgVal = E->getIntegerConstantExpr(S.Context); + // CheckLoopHintExpr handles non int const cases + assert(ArgVal != std::nullopt && "ArgVal should be an integer constant."); + int Val = ArgVal->getSExtValue(); + // CheckLoopHintExpr handles negative and zero cases + assert(Val > 0 && "Val should be a positive integer greater than zero."); UnrollFactor = static_cast<unsigned>(Val); } - return ::new (S.Context) HLSLLoopHintAttr(S.Context, A, UnrollFactor); } diff --git a/clang/test/CodeGenHLSL/loops/unroll.hlsl b/clang/test/CodeGenHLSL/loops/unroll.hlsl index 0ebe5b0e847e4..5693140e30d3c 100644 --- a/clang/test/CodeGenHLSL/loops/unroll.hlsl +++ b/clang/test/CodeGenHLSL/loops/unroll.hlsl @@ -26,6 +26,34 @@ void for_enable() // CHECK: br label %{{.*}}, !llvm.loop ![[FOR_ENABLE:.*]] } +void for_nested_one_unroll_enable() +{ +// CHECK-LABEL: for_nested_one_unroll_enable + int s = 0; + [unroll] + for( int i = 0; i < 1000; ++i) { + for( int j = 0; j < 10; ++j) + s += i + j; + } +// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_NESTED_ENABLE:.*]] +// CHECK-NOT: br label %{{.*}}, !llvm.loop ![[FOR_NESTED_1_ENABLE:.*]] +} + +void for_nested_two_unroll_enable() +{ +// CHECK-LABEL: for_nested_two_unroll_enable + int s = 0; + [unroll] + for( int i = 0; i < 1000; ++i) { + [unroll] + for( int j = 0; j < 10; ++j) + s += i + j; + } +// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_NESTED2_ENABLE:.*]] +// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_NESTED2_1_ENABLE:.*]] +} + + /*** while ***/ void while_count() { @@ -89,6 +117,9 @@ void do_enable() // CHECK: ![[DISABLE]] = !{!"llvm.loop.unroll.disable"} // CHECK: ![[FOR_ENABLE]] = distinct !{![[FOR_ENABLE]], ![[ENABLE:.*]]} // CHECK: ![[ENABLE]] = !{!"llvm.loop.unroll.enable"} +// CHECK: ![[FOR_NESTED_ENABLE]] = distinct !{![[FOR_NESTED_ENABLE]], ![[ENABLE]]} +// CHECK: ![[FOR_NESTED2_ENABLE]] = distinct !{![[FOR_NESTED2_ENABLE]], ![[ENABLE]]} +// CHECK: ![[FOR_NESTED2_1_ENABLE]] = distinct !{![[FOR_NESTED2_1_ENABLE]], ![[ENABLE]]} // CHECK: ![[WHILE_DISTINCT]] = distinct !{![[WHILE_DISTINCT]], ![[WHILE_COUNT:.*]]} // CHECK: ![[WHILE_COUNT]] = !{!"llvm.loop.unroll.count", i32 4} // CHECK: ![[WHILE_DISABLE]] = distinct !{![[WHILE_DISABLE]], ![[DISABLE]]} diff --git a/clang/test/SemaHLSL/Loops/unroll.hlsl b/clang/test/SemaHLSL/Loops/unroll.hlsl new file mode 100644 index 0000000000000..1f4ac9ff9ef9b --- /dev/null +++ b/clang/test/SemaHLSL/Loops/unroll.hlsl @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -O0 -finclude-default-header -fsyntax-only -triple dxil-pc-shadermodel6.6-library %s -verify +void unroll_no_vars() { + int I = 3; + [unroll(I)] // expected-error {{'unroll' attribute requires an integer constant}} + while (I--); +} + +void unroll_arg_count() { + [unroll(2,4)] // expected-error {{'unroll' attribute takes one argument}} + for(int i=0; i<100; i++); +} + +void loop_arg_count() { + [loop(2)] // expected-error {{'loop' attribute takes no more than 0 argument}} + for(int i=0; i<100; i++); +} + +void unroll_no_negative() { + [unroll(-1)] // expected-error {{invalid value '-1'; must be positive}} + for(int i=0; i<100; i++); +} + +void unroll_no_zero() { + [unroll(0)] // expected-error {{invalid value '0'; must be positive}} + for(int i=0; i<100; i++); +} + +void unroll_no_float() { + [unroll(2.1)] // expected-error {{invalid argument of type 'float'; expected an integer type}} + for(int i=0; i<100; i++); +} + +void unroll_no_bool_false() { + [unroll(false)] // expected-error {{invalid argument of type 'bool'; expected an integer type}} + for(int i=0; i<100; i++); +} + +void unroll_no_bool_true() { + [unroll(true)] // expected-error {{invalid argument of type 'bool'; expected an integer type}} + for(int i=0; i<100; i++); +} + +void unroll_loop_enforcement() { + int x[10]; + [unroll(4)] // expected-error {{'unroll' attribute only applies to 'for', 'while', and 'do' statements}} + if (x[0]) + x[0] = 15; +} >From 4486624c8d643fd1c56523887cac532b8a015ee6 Mon Sep 17 00:00:00 2001 From: Farzon Lotfi <farzonlo...@microsoft.com> Date: Mon, 3 Jun 2024 20:44:04 -0400 Subject: [PATCH 4/4] address pr comment, use a more appropriate name --- clang/lib/Parse/ParseStmt.cpp | 10 +++++----- clang/test/CodeGenHLSL/loops/unroll.hlsl | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index b8a717820c418..58800d0fa803c 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -114,21 +114,21 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, // here because we don't want to allow arbitrary orderings. ParsedAttributes CXX11Attrs(AttrFactory); MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true); - ParsedAttributes DeclSpecAttrs(AttrFactory); + ParsedAttributes GNUOrMSAttrs(AttrFactory); if (getLangOpts().OpenCL) - MaybeParseGNUAttributes(DeclSpecAttrs); + MaybeParseGNUAttributes(GNUOrMSAttrs); if (getLangOpts().HLSL) - MaybeParseMicrosoftAttributes(DeclSpecAttrs); + MaybeParseMicrosoftAttributes(GNUOrMSAttrs); StmtResult Res = ParseStatementOrDeclarationAfterAttributes( - Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs, DeclSpecAttrs); + Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs, GNUOrMSAttrs); MaybeDestroyTemplateIds(); // Attributes that are left should all go on the statement, so concatenate the // two lists. ParsedAttributes Attrs(AttrFactory); - takeAndConcatenateAttrs(CXX11Attrs, DeclSpecAttrs, Attrs); + takeAndConcatenateAttrs(CXX11Attrs, GNUOrMSAttrs, Attrs); assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) && "attributes on empty statement"); diff --git a/clang/test/CodeGenHLSL/loops/unroll.hlsl b/clang/test/CodeGenHLSL/loops/unroll.hlsl index 5693140e30d3c..65246cfbf2ec6 100644 --- a/clang/test/CodeGenHLSL/loops/unroll.hlsl +++ b/clang/test/CodeGenHLSL/loops/unroll.hlsl @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ -// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -o - | FileCheck %s +// RUN: dxil-pc-shadermodel6.3-library -O3 %s -emit-llvm -o - | FileCheck %s /*** for ***/ void for_count() _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits