Skip to content

Commit 34ca6e4

Browse files
erichkeaneIanWood1
authored andcommitted
[OpenACC][CIR] Start work to lower 'loop' (llvm#137972)
As can be seen by the comment, this ends up being a construct that is going to be quite a lot of work in the future to make sure we properly identify the upperbound, lowerbound, and step. For now, we just treat the 'loop' as container so that we can put the 'for' loop into it. In the future, we'll have to teach the OpenACC dialect how to derive the upperbound, lowerbound, and step from the cir.for loop. Additionally, we'll probably have to add a few more options to it so that we can give it the recipes it needs to determine these for random access iterators. For Integer and Pointer values, these should already be known.
1 parent 62e1f09 commit 34ca6e4

File tree

4 files changed

+124
-11
lines changed

4 files changed

+124
-11
lines changed

clang/lib/CIR/CodeGen/CIRGenStmtOpenACCLoop.cpp

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,103 @@
1313
#include "CIRGenBuilder.h"
1414
#include "CIRGenFunction.h"
1515
#include "CIRGenOpenACCClause.h"
16-
#include "mlir/Dialect/OpenACC/OpenACC.h"
16+
1717
#include "clang/AST/OpenACCClause.h"
1818
#include "clang/AST/StmtOpenACC.h"
1919

20+
#include "mlir/Dialect/OpenACC/OpenACC.h"
21+
2022
using namespace clang;
2123
using namespace clang::CIRGen;
2224
using namespace cir;
2325
using namespace mlir::acc;
2426

2527
mlir::LogicalResult
2628
CIRGenFunction::emitOpenACCLoopConstruct(const OpenACCLoopConstruct &s) {
27-
cgm.errorNYI(s.getSourceRange(), "OpenACC Loop Construct");
28-
return mlir::failure();
29+
mlir::Location start = getLoc(s.getSourceRange().getBegin());
30+
mlir::Location end = getLoc(s.getSourceRange().getEnd());
31+
llvm::SmallVector<mlir::Type> retTy;
32+
llvm::SmallVector<mlir::Value> operands;
33+
auto op = builder.create<LoopOp>(start, retTy, operands);
34+
35+
// TODO(OpenACC): In the future we are going to need to come up with a
36+
// transformation here that can teach the acc.loop how to figure out the
37+
// 'lowerbound', 'upperbound', and 'step'.
38+
//
39+
// -'upperbound' should fortunately be pretty easy as it should be
40+
// in the initialization section of the cir.for loop. In Sema, we limit to
41+
// just the forms 'Var = init', `Type Var = init`, or `Var = init` (where it
42+
// is an operator= call)`. However, as those are all necessary to emit for
43+
// the init section of the for loop, they should be inside the initial
44+
// cir.scope.
45+
//
46+
// -'upperbound' should be somewhat easy to determine. Sema is limiting this
47+
// to: ==, <, >, !=, <=, >= builtin operators, the overloaded 'comparison'
48+
// operations, and member-call expressions.
49+
//
50+
// For the builtin comparison operators, we can pretty well deduce based on
51+
// the comparison what the 'end' object is going to be, and the inclusive
52+
// nature of it.
53+
//
54+
// For the overloaded operators, Sema will ensure that at least one side of
55+
// the operator is the init variable, so we can deduce the comparison there
56+
// too. The standard places no real bounds on WHAT the comparison operators do
57+
// for a `RandomAccessIterator` however, so we'll have to just 'assume' they
58+
// do the right thing? Note that this might be incrementing by a different
59+
// 'object', not an integral, so it isn't really clear to me what we can do to
60+
// determine the other side.
61+
//
62+
// Member-call expressions are the difficult ones. I don't think there is
63+
// anything we can deduce from this to determine the 'end', so we might end up
64+
// having to go back to Sema and make this ill-formed.
65+
//
66+
// HOWEVER: What ACC dialect REALLY cares about is the tripcount, which you
67+
// cannot get (in the case of `RandomAccessIterator`) from JUST 'upperbound'
68+
// and 'lowerbound'. We will likely have to provide a 'recipe' equivalent to
69+
// `std::distance` instead. In the case of integer/pointers, it is fairly
70+
// simple to find: it is just the mathematical subtraction. Howver, in the
71+
// case of `RandomAccessIterator`, we have to enable the use of `operator-`.
72+
// FORTUNATELY the standard requires this to work correctly for
73+
// `RandomAccessIterator`, so we don't have to implement a `std::distance`
74+
// that loops through, like we would for a forward/etc iterator.
75+
//
76+
// 'step': Sema is currently allowing builtin ++,--, +=, -=, *=, /=, and =
77+
// operators. Additionally, it allows the equivalent for the operator-call, as
78+
// well as member-call.
79+
//
80+
// For builtin operators, we perhaps should refine the assignment here. It
81+
// doesn't really help us know the 'step' count at all, but we could perhaps
82+
// do one more step of analysis in Sema to allow something like Var = Var + 1.
83+
// For the others, this should get us the step reasonably well.
84+
//
85+
// For the overloaded operators, we have the same problems as for
86+
// 'upperbound', plus not really knowing what they do. Member-call expressions
87+
// are again difficult, and we might want to reconsider allowing these in
88+
// Sema.
89+
//
90+
91+
// Emit all clauses.
92+
{
93+
mlir::OpBuilder::InsertionGuard guardCase(builder);
94+
// Sets insertion point before the 'op', since every new expression needs to
95+
// be before the operation.
96+
builder.setInsertionPoint(op);
97+
makeClauseEmitter(op, *this, builder, s.getDirectiveKind(),
98+
s.getDirectiveLoc())
99+
.VisitClauseList(s.clauses());
100+
}
101+
102+
mlir::LogicalResult stmtRes = mlir::success();
103+
// Emit body.
104+
{
105+
mlir::Block &block = op.getRegion().emplaceBlock();
106+
mlir::OpBuilder::InsertionGuard guardCase(builder);
107+
builder.setInsertionPointToEnd(&block);
108+
LexicalScope ls{*this, start, builder.getInsertionBlock()};
109+
110+
stmtRes = emitStmt(s.getLoop(), /*useCurrentScope=*/true);
111+
builder.create<mlir::acc::YieldOp>(end);
112+
}
113+
114+
return stmtRes;
29115
}

clang/lib/Sema/SemaOpenACC.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,7 +1560,7 @@ void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc, const Stmt *First,
15601560
void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
15611561
const Stmt *OldRangeFor,
15621562
const Stmt *RangeFor) {
1563-
if (!getLangOpts().OpenACC)
1563+
if (!getLangOpts().OpenACC || OldRangeFor == nullptr || RangeFor == nullptr)
15641564
return;
15651565

15661566
ForStmtBeginChecker FSBC{*this, ForLoc,
@@ -1576,7 +1576,7 @@ void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
15761576

15771577
void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
15781578
const Stmt *RangeFor) {
1579-
if (!getLangOpts().OpenACC)
1579+
if (!getLangOpts().OpenACC || RangeFor == nullptr)
15801580
return;
15811581

15821582
ForStmtBeginChecker FSBC = {*this, ForLoc,
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clang_cc1 -fopenacc -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir %s -o - | FileCheck %s
2+
3+
extern "C" void acc_loop(int *A, int *B, int *C, int N) {
4+
// CHECK: cir.func @acc_loop(%[[ARG_A:.*]]: !cir.ptr<!s32i> loc{{.*}}, %[[ARG_B:.*]]: !cir.ptr<!s32i> loc{{.*}}, %[[ARG_C:.*]]: !cir.ptr<!s32i> loc{{.*}}, %[[ARG_N:.*]]: !s32i loc{{.*}}) {
5+
// CHECK-NEXT: %[[ALLOCA_A:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["A", init]
6+
// CHECK-NEXT: %[[ALLOCA_B:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["B", init]
7+
// CHECK-NEXT: %[[ALLOCA_C:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["C", init]
8+
// CHECK-NEXT: %[[ALLOCA_N:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["N", init]
9+
// CHECK-NEXT: cir.store %[[ARG_A]], %[[ALLOCA_A]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
10+
// CHECK-NEXT: cir.store %[[ARG_B]], %[[ALLOCA_B]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
11+
// CHECK-NEXT: cir.store %[[ARG_C]], %[[ALLOCA_C]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
12+
// CHECK-NEXT: cir.store %[[ARG_N]], %[[ALLOCA_N]] : !s32i, !cir.ptr<!s32i>
13+
14+
15+
#pragma acc loop
16+
for (unsigned I = 0u; I < N; ++I) {
17+
A[I] = B[I] + C[I];
18+
}
19+
// CHECK-NEXT: acc.loop {
20+
// CHECK-NEXT: cir.scope {
21+
// CHECK: cir.for : cond {
22+
// CHECK: cir.condition
23+
// CHECK-NEXT: } body {
24+
// CHECK-NEXT: cir.scope {
25+
// CHECK: }
26+
// CHECK-NEXT: cir.yield
27+
// CHECK-NEXT: } step {
28+
// CHECK: cir.yield
29+
// CHECK-NEXT: } loc
30+
// CHECK-NEXT: } loc
31+
// CHECK-NEXT: acc.yield
32+
// CHECK-NEXT: } loc
33+
}

clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ void HelloWorld(int *A, int *B, int *C, int N) {
99
for (unsigned I = 0; I < N; ++I)
1010
A[I] = B[I] + C[I];
1111

12-
// expected-error@+2{{ClangIR code gen Not Yet Implemented: OpenACC Loop Construct}}
13-
// expected-error@+1{{ClangIR code gen Not Yet Implemented: statement}}
14-
#pragma acc loop
15-
for (unsigned I = 0; I < N; ++I)
16-
A[I] = B[I] + C[I];
17-
1812
// expected-error@+1{{ClangIR code gen Not Yet Implemented: OpenACC Declare Construct}}
1913
#pragma acc declare create(A)
2014
}

0 commit comments

Comments
 (0)