-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[HLSL] add loop unroll #93879
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
[HLSL] add loop unroll #93879
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,39 @@ 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) { | ||
|
||
if (A.getSemanticSpelling() == HLSLLoopHintAttr::Spelling::Microsoft_loop && | ||
!A.checkAtMostNumArgs(S, 0)) | ||
return nullptr; | ||
|
||
unsigned UnrollFactor = 0; | ||
if (A.getNumArgs() == 1) { | ||
|
||
if (A.isArgIdent(0)) { | ||
S.Diag(A.getLoc(), diag::err_attribute_argument_type) | ||
farzonl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<< A << AANT_ArgumentIntegerConstant << A.getRange(); | ||
return nullptr; | ||
} | ||
|
||
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."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As stated in your comment, CheckLoopHintExpr will check each of these asserts, and return true in each case, so nullptr will be returned by this function on line 608. That said, is there really a purpose for these asserts? I don't see how they can trigger when CheckLoopHintExpr confirms these conditions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question. You are correct it is not needed, I added it as a form of future proofing. Let me explain my thinking.
As a thought experiment lets imagine a change to |
||
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 +652,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: | ||
|
farzonl marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ | ||
// RUN: dxil-pc-shadermodel6.3-library -disable-llvm-passes %s -emit-llvm -o - | FileCheck %s | ||
|
||
/*** for ***/ | ||
void for_count() | ||
{ | ||
// CHECK-LABEL: for_count | ||
farzonl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
[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:.*]] | ||
} | ||
|
||
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() | ||
{ | ||
// 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: ![[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]]} | ||
// 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]]} |
Uh oh!
There was an error while loading. Please reload this page.