Skip to content

Commit b4415b2

Browse files
committed
- add sema checks for loop unroll, switch.
- Remove need for custom parsing by adding default val - Add nested loop tests
1 parent 2e0dd44 commit b4415b2

File tree

4 files changed

+98
-13
lines changed

4 files changed

+98
-13
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4120,12 +4120,11 @@ def HLSLLoopHint: StmtAttr {
41204120
/// [unroll(directive)]
41214121
/// [loop]
41224122
let Spellings = [Microsoft<"unroll">, Microsoft<"loop">];
4123-
let Args = [UnsignedArgument<"directive">];
4123+
let Args = [UnsignedArgument<"directive", /*opt*/1>];
41244124
let Subjects = SubjectList<[ForStmt, WhileStmt, DoStmt],
41254125
ErrorDiag, "'for', 'while', and 'do' statements">;
41264126
let LangOpts = [HLSL];
41274127
let Documentation = [HLSLLoopHintDocs, HLSLUnrollHintDocs];
4128-
let HasCustomParsing = 1;
41294128
}
41304129

41314130
def CapturedRecord : InheritableAttr {

clang/lib/Sema/SemaStmtAttr.cpp

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -587,27 +587,34 @@ static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
587587

588588
static Attr *handleHLSLLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
589589
SourceRange Range) {
590+
591+
if (A.getSemanticSpelling() == HLSLLoopHintAttr::Spelling::Microsoft_loop &&
592+
!A.checkAtMostNumArgs(S, 0))
593+
return nullptr;
594+
590595
unsigned UnrollFactor = 0;
591596
if (A.getNumArgs() == 1) {
592-
Expr *E = A.getArgAsExpr(0);
593-
std::optional<llvm::APSInt> ArgVal;
594597

595-
if (!(ArgVal = E->getIntegerConstantExpr(S.Context))) {
598+
if (A.isArgIdent(0)) {
596599
S.Diag(A.getLoc(), diag::err_attribute_argument_type)
597-
<< A << AANT_ArgumentIntegerConstant << E->getSourceRange();
600+
<< A << AANT_ArgumentIntegerConstant << A.getRange();
598601
return nullptr;
599602
}
600603

601-
int Val = ArgVal->getSExtValue();
602-
if (Val <= 0) {
603-
S.Diag(A.getRange().getBegin(),
604-
diag::err_attribute_requires_positive_integer)
605-
<< A << /* positive */ 0;
604+
Expr *E = A.getArgAsExpr(0);
605+
606+
if (S.CheckLoopHintExpr(E, St->getBeginLoc(),
607+
/*AllowZero=*/false))
606608
return nullptr;
607-
}
609+
610+
std::optional<llvm::APSInt> ArgVal = E->getIntegerConstantExpr(S.Context);
611+
// CheckLoopHintExpr handles non int const cases
612+
assert(ArgVal != std::nullopt && "ArgVal should be an integer constant.");
613+
int Val = ArgVal->getSExtValue();
614+
// CheckLoopHintExpr handles negative and zero cases
615+
assert(Val > 0 && "Val should be a positive integer greater than zero.");
608616
UnrollFactor = static_cast<unsigned>(Val);
609617
}
610-
611618
return ::new (S.Context) HLSLLoopHintAttr(S.Context, A, UnrollFactor);
612619
}
613620

clang/test/CodeGenHLSL/loops/unroll.hlsl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,34 @@ void for_enable()
2626
// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_ENABLE:.*]]
2727
}
2828

29+
void for_nested_one_unroll_enable()
30+
{
31+
// CHECK-LABEL: for_nested_one_unroll_enable
32+
int s = 0;
33+
[unroll]
34+
for( int i = 0; i < 1000; ++i) {
35+
for( int j = 0; j < 10; ++j)
36+
s += i + j;
37+
}
38+
// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_NESTED_ENABLE:.*]]
39+
// CHECK-NOT: br label %{{.*}}, !llvm.loop ![[FOR_NESTED_1_ENABLE:.*]]
40+
}
41+
42+
void for_nested_two_unroll_enable()
43+
{
44+
// CHECK-LABEL: for_nested_two_unroll_enable
45+
int s = 0;
46+
[unroll]
47+
for( int i = 0; i < 1000; ++i) {
48+
[unroll]
49+
for( int j = 0; j < 10; ++j)
50+
s += i + j;
51+
}
52+
// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_NESTED2_ENABLE:.*]]
53+
// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_NESTED2_1_ENABLE:.*]]
54+
}
55+
56+
2957
/*** while ***/
3058
void while_count()
3159
{
@@ -89,6 +117,9 @@ void do_enable()
89117
// CHECK: ![[DISABLE]] = !{!"llvm.loop.unroll.disable"}
90118
// CHECK: ![[FOR_ENABLE]] = distinct !{![[FOR_ENABLE]], ![[ENABLE:.*]]}
91119
// CHECK: ![[ENABLE]] = !{!"llvm.loop.unroll.enable"}
120+
// CHECK: ![[FOR_NESTED_ENABLE]] = distinct !{![[FOR_NESTED_ENABLE]], ![[ENABLE]]}
121+
// CHECK: ![[FOR_NESTED2_ENABLE]] = distinct !{![[FOR_NESTED2_ENABLE]], ![[ENABLE]]}
122+
// CHECK: ![[FOR_NESTED2_1_ENABLE]] = distinct !{![[FOR_NESTED2_1_ENABLE]], ![[ENABLE]]}
92123
// CHECK: ![[WHILE_DISTINCT]] = distinct !{![[WHILE_DISTINCT]], ![[WHILE_COUNT:.*]]}
93124
// CHECK: ![[WHILE_COUNT]] = !{!"llvm.loop.unroll.count", i32 4}
94125
// CHECK: ![[WHILE_DISABLE]] = distinct !{![[WHILE_DISABLE]], ![[DISABLE]]}

clang/test/SemaHLSL/Loops/unroll.hlsl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %clang_cc1 -O0 -finclude-default-header -fsyntax-only -triple dxil-pc-shadermodel6.6-library %s -verify
2+
void unroll_no_vars() {
3+
int I = 3;
4+
[unroll(I)] // expected-error {{'unroll' attribute requires an integer constant}}
5+
while (I--);
6+
}
7+
8+
void unroll_arg_count() {
9+
[unroll(2,4)] // expected-error {{'unroll' attribute takes one argument}}
10+
for(int i=0; i<100; i++);
11+
}
12+
13+
void loop_arg_count() {
14+
[loop(2)] // expected-error {{'loop' attribute takes no more than 0 argument}}
15+
for(int i=0; i<100; i++);
16+
}
17+
18+
void unroll_no_negative() {
19+
[unroll(-1)] // expected-error {{invalid value '-1'; must be positive}}
20+
for(int i=0; i<100; i++);
21+
}
22+
23+
void unroll_no_zero() {
24+
[unroll(0)] // expected-error {{invalid value '0'; must be positive}}
25+
for(int i=0; i<100; i++);
26+
}
27+
28+
void unroll_no_float() {
29+
[unroll(2.1)] // expected-error {{invalid argument of type 'float'; expected an integer type}}
30+
for(int i=0; i<100; i++);
31+
}
32+
33+
void unroll_no_bool_false() {
34+
[unroll(false)] // expected-error {{invalid argument of type 'bool'; expected an integer type}}
35+
for(int i=0; i<100; i++);
36+
}
37+
38+
void unroll_no_bool_true() {
39+
[unroll(true)] // expected-error {{invalid argument of type 'bool'; expected an integer type}}
40+
for(int i=0; i<100; i++);
41+
}
42+
43+
void unroll_loop_enforcement() {
44+
int x[10];
45+
[unroll(4)] // expected-error {{'unroll' attribute only applies to 'for', 'while', and 'do' statements}}
46+
if (x[0])
47+
x[0] = 15;
48+
}

0 commit comments

Comments
 (0)