Skip to content

Commit c788572

Browse files
committed
[OpenACC][CIR] Start work to lower 'loop'
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 e8ae779 commit c788572

File tree

4 files changed

+125
-11
lines changed

4 files changed

+125
-11
lines changed

clang/lib/CIR/CodeGen/CIRGenStmtOpenACCLoop.cpp

Lines changed: 90 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,104 @@
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+
22+
2023
using namespace clang;
2124
using namespace clang::CIRGen;
2225
using namespace cir;
2326
using namespace mlir::acc;
2427

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

clang/lib/Sema/SemaOpenACC.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,7 +1517,7 @@ void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc, const Stmt *First,
15171517
void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
15181518
const Stmt *OldRangeFor,
15191519
const Stmt *RangeFor) {
1520-
if (!getLangOpts().OpenACC)
1520+
if (!getLangOpts().OpenACC || OldRangeFor == nullptr || RangeFor == nullptr)
15211521
return;
15221522

15231523
ForStmtBeginChecker FSBC{*this, ForLoc,
@@ -1533,7 +1533,7 @@ void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
15331533

15341534
void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
15351535
const Stmt *RangeFor) {
1536-
if (!getLangOpts().OpenACC)
1536+
if (!getLangOpts().OpenACC || RangeFor == nullptr)
15371537
return;
15381538

15391539
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)