|
13 | 13 | #include "CIRGenBuilder.h"
|
14 | 14 | #include "CIRGenFunction.h"
|
15 | 15 | #include "CIRGenOpenACCClause.h"
|
16 |
| -#include "mlir/Dialect/OpenACC/OpenACC.h" |
| 16 | + |
17 | 17 | #include "clang/AST/OpenACCClause.h"
|
18 | 18 | #include "clang/AST/StmtOpenACC.h"
|
19 | 19 |
|
| 20 | +#include "mlir/Dialect/OpenACC/OpenACC.h" |
| 21 | + |
20 | 22 | using namespace clang;
|
21 | 23 | using namespace clang::CIRGen;
|
22 | 24 | using namespace cir;
|
23 | 25 | using namespace mlir::acc;
|
24 | 26 |
|
25 | 27 | mlir::LogicalResult
|
26 | 28 | 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; |
29 | 115 | }
|
0 commit comments