mlir::Value gangStatic;
llvm::SmallVector<mlir::Value, 2> tileOperands, privateOperands,
reductionOperands;
- bool hasGang = false, hasVector = false, hasWorker = false;
+ std::int64_t executionMapping = mlir::acc::OpenACCExecMapping::NONE;
for (const Fortran::parser::AccClause &clause : accClauseList.v) {
mlir::Location clauseLocation = converter.genLocation(clause.source);
}
}
}
- hasGang = true;
+ executionMapping |= mlir::acc::OpenACCExecMapping::GANG;
} else if (const auto *workerClause =
std::get_if<Fortran::parser::AccClause::Worker>(&clause.u)) {
if (workerClause->v) {
workerNum = fir::getBase(converter.genExprValue(
*Fortran::semantics::GetExpr(*workerClause->v), stmtCtx));
}
- hasWorker = true;
+ executionMapping |= mlir::acc::OpenACCExecMapping::WORKER;
} else if (const auto *vectorClause =
std::get_if<Fortran::parser::AccClause::Vector>(&clause.u)) {
if (vectorClause->v) {
vectorNum = fir::getBase(converter.genExprValue(
*Fortran::semantics::GetExpr(*vectorClause->v), stmtCtx));
}
- hasVector = true;
+ executionMapping |= mlir::acc::OpenACCExecMapping::VECTOR;
} else if (const auto *tileClause =
std::get_if<Fortran::parser::AccClause::Tile>(&clause.u)) {
const Fortran::parser::AccTileExprList &accTileExprList = tileClause->v;
auto loopOp = createRegionOp<mlir::acc::LoopOp, mlir::acc::YieldOp>(
firOpBuilder, currentLocation, operands, operandSegments);
- if (hasGang)
- loopOp.setHasGangAttr(firOpBuilder.getUnitAttr());
- if (hasWorker)
- loopOp.setHasWorkerAttr(firOpBuilder.getUnitAttr());
- if (hasVector)
- loopOp.setHasVectorAttr(firOpBuilder.getUnitAttr());
+ loopOp.setExecMappingAttr(firOpBuilder.getI64IntegerAttr(executionMapping));
// Lower clauses mapped to attributes
for (const Fortran::parser::AccClause &clause : accClauseList.v) {
END DO
!CHECK: [[GANGNUM1:%.*]] = arith.constant 8 : i32
-!CHECK-NEXT: acc.loop gang(num=[[GANGNUM1]] : i32) {
+!CHECK-NEXT: acc.loop gang(num=[[GANGNUM1]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: [[GANGNUM2:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
-!CHECK-NEXT: acc.loop gang(num=[[GANGNUM2]] : i32) {
+!CHECK-NEXT: acc.loop gang(num=[[GANGNUM2]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
a(i) = b(i)
END DO
-!CHECK: acc.loop gang(num=%{{.*}} : i32, static=%{{.*}} : i32) {
+!CHECK: acc.loop gang(num=%{{.*}}: i32, static=%{{.*}}: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: [[CONSTANT128:%.*]] = arith.constant 128 : i32
-!CHECK: acc.loop vector([[CONSTANT128]] : i32) {
+!CHECK: acc.loop vector([[CONSTANT128]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: [[VECTORLENGTH:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
-!CHECK: acc.loop vector([[VECTORLENGTH]] : i32) {
+!CHECK: acc.loop vector([[VECTORLENGTH]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: [[WORKER128:%.*]] = arith.constant 128 : i32
-!CHECK: acc.loop worker([[WORKER128]] : i32) {
+!CHECK: acc.loop worker([[WORKER128]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
a(i) = b(i)
END DO
-!CHECK: acc.loop private(%{{.*}} : !fir.ref<!fir.array<10x10xf32>>) {
+!CHECK: acc.loop private(%{{.*}}: !fir.ref<!fir.array<10x10xf32>>) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
a(i) = b(i)
END DO
-!CHECK: acc.loop private(%{{.*}}, %{{.*}} : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) {
+!CHECK: acc.loop private(%{{.*}}: !fir.ref<!fir.array<10x10xf32>>, %{{.*}}: !fir.ref<!fir.array<10x10xf32>>) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
a(i) = b(i)
END DO
-!CHECK: acc.loop private(%{{.*}}, %{{.*}} : !fir.ref<!fir.array<10x10xf32>>, !fir.ref<!fir.array<10x10xf32>>) {
+!CHECK: acc.loop private(%{{.*}}: !fir.ref<!fir.array<10x10xf32>>, %{{.*}}: !fir.ref<!fir.array<10x10xf32>>) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
a(i) = b(i)
END DO
!CHECK: [[TILESIZE:%.*]] = arith.constant 2 : i32
-!CHECK: acc.loop tile([[TILESIZE]] : i32) {
+!CHECK: acc.loop tile([[TILESIZE]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
a(i) = b(i)
END DO
!CHECK: [[TILESIZEM1:%.*]] = arith.constant -1 : i32
-!CHECK: acc.loop tile([[TILESIZEM1]] : i32) {
+!CHECK: acc.loop tile([[TILESIZEM1]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: [[TILESIZE1:%.*]] = arith.constant 2 : i32
!CHECK: [[TILESIZE2:%.*]] = arith.constant 2 : i32
-!CHECK: acc.loop tile([[TILESIZE1]], [[TILESIZE2]] : i32, i32) {
+!CHECK: acc.loop tile([[TILESIZE1]]: i32, [[TILESIZE2]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
a(i) = b(i)
END DO
-!CHECK: acc.loop tile(%{{.*}} : i32) {
+!CHECK: acc.loop tile(%{{.*}}: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
END DO
-!CHECK: acc.loop tile(%{{.*}}, %{{.*}} : i32, i32) {
+!CHECK: acc.loop tile(%{{.*}}: i32, %{{.*}}: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: acc.parallel firstprivate([[B]] : !fir.ref<!fir.array<10xf32>>) private([[A]] : !fir.ref<!fir.array<10xf32>>) {
-!CHECK: acc.loop private([[A]] : !fir.ref<!fir.array<10xf32>>) {
+!CHECK: acc.loop private([[A]]: !fir.ref<!fir.array<10xf32>>) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.parallel {
!CHECK: [[GANGNUM1:%.*]] = arith.constant 8 : i32
-!CHECK-NEXT: acc.loop gang(num=[[GANGNUM1]] : i32) {
+!CHECK-NEXT: acc.loop gang(num=[[GANGNUM1]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.parallel {
!CHECK: [[GANGNUM2:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
-!CHECK-NEXT: acc.loop gang(num=[[GANGNUM2]] : i32) {
+!CHECK-NEXT: acc.loop gang(num=[[GANGNUM2]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: acc.parallel {
-!CHECK: acc.loop gang(num=%{{.*}} : i32, static=%{{.*}} : i32) {
+!CHECK: acc.loop gang(num=%{{.*}}: i32, static=%{{.*}}: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.parallel {
!CHECK: [[CONSTANT128:%.*]] = arith.constant 128 : i32
-!CHECK: acc.loop vector([[CONSTANT128]] : i32) {
+!CHECK: acc.loop vector([[CONSTANT128]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.parallel {
!CHECK: [[VECTORLENGTH:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
-!CHECK: acc.loop vector([[VECTORLENGTH]] : i32) {
+!CHECK: acc.loop vector([[VECTORLENGTH]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.parallel {
!CHECK: [[WORKER128:%.*]] = arith.constant 128 : i32
-!CHECK: acc.loop worker([[WORKER128]] : i32) {
+!CHECK: acc.loop worker([[WORKER128]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.parallel {
!CHECK: [[TILESIZE:%.*]] = arith.constant 2 : i32
-!CHECK: acc.loop tile([[TILESIZE]] : i32) {
+!CHECK: acc.loop tile([[TILESIZE]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.parallel {
!CHECK: [[TILESIZEM1:%.*]] = arith.constant -1 : i32
-!CHECK: acc.loop tile([[TILESIZEM1]] : i32) {
+!CHECK: acc.loop tile([[TILESIZEM1]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.parallel {
!CHECK: [[TILESIZE1:%.*]] = arith.constant 2 : i32
!CHECK: [[TILESIZE2:%.*]] = arith.constant 2 : i32
-!CHECK: acc.loop tile([[TILESIZE1]], [[TILESIZE2]] : i32, i32) {
+!CHECK: acc.loop tile([[TILESIZE1]]: i32, [[TILESIZE2]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: acc.parallel {
-!CHECK: acc.loop tile(%{{.*}} : i32) {
+!CHECK: acc.loop tile(%{{.*}}: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: acc.parallel {
-!CHECK: acc.loop tile(%{{.*}}, %{{.*}} : i32, i32) {
+!CHECK: acc.loop tile(%{{.*}}: i32, %{{.*}}: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: acc.serial firstprivate([[B]] : !fir.ref<!fir.array<10xf32>>) private([[A]] : !fir.ref<!fir.array<10xf32>>) {
-!CHECK: acc.loop private([[A]] : !fir.ref<!fir.array<10xf32>>) {
+!CHECK: acc.loop private([[A]]: !fir.ref<!fir.array<10xf32>>) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.serial {
!CHECK: [[GANGNUM1:%.*]] = arith.constant 8 : i32
-!CHECK-NEXT: acc.loop gang(num=[[GANGNUM1]] : i32) {
+!CHECK-NEXT: acc.loop gang(num=[[GANGNUM1]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.serial {
!CHECK: [[GANGNUM2:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
-!CHECK-NEXT: acc.loop gang(num=[[GANGNUM2]] : i32) {
+!CHECK-NEXT: acc.loop gang(num=[[GANGNUM2]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: acc.serial {
-!CHECK: acc.loop gang(num=%{{.*}} : i32, static=%{{.*}} : i32) {
+!CHECK: acc.loop gang(num=%{{.*}}: i32, static=%{{.*}}: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.serial {
!CHECK: [[CONSTANT128:%.*]] = arith.constant 128 : i32
-!CHECK: acc.loop vector([[CONSTANT128]] : i32) {
+!CHECK: acc.loop vector([[CONSTANT128]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.serial {
!CHECK: [[VECTORLENGTH:%.*]] = fir.load %{{.*}} : !fir.ref<i32>
-!CHECK: acc.loop vector([[VECTORLENGTH]] : i32) {
+!CHECK: acc.loop vector([[VECTORLENGTH]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.serial {
!CHECK: [[WORKER128:%.*]] = arith.constant 128 : i32
-!CHECK: acc.loop worker([[WORKER128]] : i32) {
+!CHECK: acc.loop worker([[WORKER128]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.serial {
!CHECK: [[TILESIZE:%.*]] = arith.constant 2 : i32
-!CHECK: acc.loop tile([[TILESIZE]] : i32) {
+!CHECK: acc.loop tile([[TILESIZE]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.serial {
!CHECK: [[TILESIZEM1:%.*]] = arith.constant -1 : i32
-!CHECK: acc.loop tile([[TILESIZEM1]] : i32) {
+!CHECK: acc.loop tile([[TILESIZEM1]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
!CHECK: acc.serial {
!CHECK: [[TILESIZE1:%.*]] = arith.constant 2 : i32
!CHECK: [[TILESIZE2:%.*]] = arith.constant 2 : i32
-!CHECK: acc.loop tile([[TILESIZE1]], [[TILESIZE2]] : i32, i32) {
+!CHECK: acc.loop tile([[TILESIZE1]]: i32, [[TILESIZE2]]: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: acc.serial {
-!CHECK: acc.loop tile(%{{.*}} : i32) {
+!CHECK: acc.loop tile(%{{.*}}: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
END DO
!CHECK: acc.serial {
-!CHECK: acc.loop tile(%{{.*}}, %{{.*}} : i32, i32) {
+!CHECK: acc.loop tile(%{{.*}}: i32, %{{.*}}: i32) {
!CHECK: fir.do_loop
!CHECK: acc.yield
!CHECK-NEXT: }{{$}}
UnitAttr:$seq,
UnitAttr:$independent,
UnitAttr:$auto_,
- UnitAttr:$hasGang,
- UnitAttr:$hasWorker,
- UnitAttr:$hasVector,
Variadic<IntOrIndex>:$tileOperands,
Variadic<AnyType>:$privateOperands,
OptionalAttr<OpenACC_ReductionOpAttr>:$reductionOp,
- Variadic<AnyType>:$reductionOperands);
+ Variadic<AnyType>:$reductionOperands,
+ DefaultValuedAttr<I64Attr, "0">:$exec_mapping);
let results = (outs Variadic<AnyType>:$results);
let regions = (region AnyRegion:$region);
let extraClassDeclaration = [{
+ static StringRef getCollapseAttrStrName() { return "collapse"; }
+ static StringRef getSeqAttrStrName() { return "seq"; }
+ static StringRef getIndependentAttrStrName() { return "independent"; }
static StringRef getAutoAttrStrName() { return "auto"; }
+ static StringRef getExecutionMappingAttrStrName() { return "exec_mapping"; }
+ static StringRef getGangKeyword() { return "gang"; }
static StringRef getGangNumKeyword() { return "num"; }
static StringRef getGangStaticKeyword() { return "static"; }
+ static StringRef getVectorKeyword() { return "vector"; }
+ static StringRef getWorkerKeyword() { return "worker"; }
+ static StringRef getTileKeyword() { return "tile"; }
+ static StringRef getPrivateKeyword() { return "private"; }
+ static StringRef getReductionKeyword() { return "reduction"; }
}];
-
let hasCustomAssemblyFormat = 1;
- let assemblyFormat = [{
- oilist(
- `gang` `` custom<GangClause>($gangNum, type($gangNum), $gangStatic, type($gangStatic), $hasGang)
- | `worker` `` custom<WorkerClause>($workerNum, type($workerNum), $hasWorker)
- | `vector` `` custom<VectorClause>($vectorLength, type($vectorLength), $hasVector)
- | `private` `(` $privateOperands `:` type($privateOperands) `)`
- | `tile` `(` $tileOperands `:` type($tileOperands) `)`
- | `reduction` `(` $reductionOperands `:` type($reductionOperands) `)`
- )
- $region
- ( `(` type($results)^ `)` )?
- attr-dict-with-keyword
- }];
-
let hasVerifier = 1;
}
return success();
}
+static ParseResult
+parseOperandList(OpAsmParser &parser, StringRef keyword,
+ SmallVectorImpl<OpAsmParser::UnresolvedOperand> &args,
+ SmallVectorImpl<Type> &argTypes, OperationState &result) {
+ if (failed(parser.parseOptionalKeyword(keyword)))
+ return success();
+
+ if (failed(parser.parseLParen()))
+ return failure();
+
+ // Exit early if the list is empty.
+ if (succeeded(parser.parseOptionalRParen()))
+ return success();
+
+ if (failed(parser.parseCommaSeparatedList([&]() {
+ OpAsmParser::UnresolvedOperand arg;
+ Type type;
+
+ if (parser.parseOperand(arg, /*allowResultNumber=*/false) ||
+ parser.parseColonType(type))
+ return failure();
+
+ args.push_back(arg);
+ argTypes.push_back(type);
+ return success();
+ })) ||
+ failed(parser.parseRParen()))
+ return failure();
+
+ return parser.resolveOperands(args, argTypes, parser.getCurrentLocation(),
+ result.operands);
+}
+
+static void printOperandList(Operation::operand_range operands,
+ StringRef listName, OpAsmPrinter &printer) {
+
+ if (!operands.empty()) {
+ printer << " " << listName << "(";
+ llvm::interleaveComma(operands, printer, [&](Value op) {
+ printer << op << ": " << op.getType();
+ });
+ printer << ")";
+ }
+}
+
+static ParseResult parseOperandAndType(OpAsmParser &parser,
+ OperationState &result) {
+ OpAsmParser::UnresolvedOperand operand;
+ Type type;
+ if (parser.parseOperand(operand) || parser.parseColonType(type) ||
+ parser.resolveOperand(operand, type, result.operands))
+ return failure();
+ return success();
+}
+
+/// Parse optional operand and its type wrapped in parenthesis.
+/// Example:
+/// `(` %vectorLength: i64 `)`
+static OptionalParseResult parseOptionalOperandAndType(OpAsmParser &parser,
+ OperationState &result) {
+ if (succeeded(parser.parseOptionalLParen())) {
+ return failure(parseOperandAndType(parser, result) || parser.parseRParen());
+ }
+ return std::nullopt;
+}
+
+/// Parse optional operand with its type prefixed with prefixKeyword `=`.
+/// Example:
+/// num=%gangNum: i32
+static OptionalParseResult parserOptionalOperandAndTypeWithPrefix(
+ OpAsmParser &parser, OperationState &result, StringRef prefixKeyword) {
+ if (succeeded(parser.parseOptionalKeyword(prefixKeyword))) {
+ if (parser.parseEqual() || parseOperandAndType(parser, result))
+ return failure();
+ return success();
+ }
+ return std::nullopt;
+}
+
static bool isComputeOperation(Operation *op) {
return isa<acc::ParallelOp>(op) || isa<acc::LoopOp>(op);
}
// LoopOp
//===----------------------------------------------------------------------===//
-static ParseResult
-parseGangClause(OpAsmParser &parser,
- std::optional<OpAsmParser::UnresolvedOperand> &gangNum,
- Type &gangNumType,
- std::optional<OpAsmParser::UnresolvedOperand> &gangStatic,
- Type &gangStaticType, UnitAttr &hasGang) {
- hasGang = UnitAttr::get(parser.getBuilder().getContext());
- // optional gang operands
+/// Parse acc.loop operation
+/// operation := `acc.loop`
+/// (`gang` ( `(` (`num=` value)? (`,` `static=` value `)`)? )? )?
+/// (`vector` ( `(` value `)` )? )? (`worker` (`(` value `)`)? )?
+/// (`vector_length` `(` value `)`)?
+/// (`tile` `(` value-list `)`)?
+/// (`private` `(` value-list `)`)?
+/// (`reduction` `(` value-list `)`)?
+/// region attr-dict?
+ParseResult LoopOp::parse(OpAsmParser &parser, OperationState &result) {
+ Builder &builder = parser.getBuilder();
+ unsigned executionMapping = OpenACCExecMapping::NONE;
+ SmallVector<Type, 8> operandTypes;
+ SmallVector<OpAsmParser::UnresolvedOperand, 8> privateOperands,
+ reductionOperands;
+ SmallVector<OpAsmParser::UnresolvedOperand, 8> tileOperands;
+ OptionalParseResult gangNum, gangStatic, worker, vector;
+
+ // gang?
+ if (succeeded(parser.parseOptionalKeyword(LoopOp::getGangKeyword())))
+ executionMapping |= OpenACCExecMapping::GANG;
+
+ // optional gang operand
if (succeeded(parser.parseOptionalLParen())) {
- if (succeeded(parser.parseOptionalKeyword(LoopOp::getGangNumKeyword()))) {
- if (parser.parseEqual())
- return failure();
- gangNum = OpAsmParser::UnresolvedOperand{};
- if (parser.parseOperand(*gangNum) || parser.parseColonType(gangNumType))
- return failure();
- } else {
- gangNum = std::nullopt;
- }
+ gangNum = parserOptionalOperandAndTypeWithPrefix(
+ parser, result, LoopOp::getGangNumKeyword());
+ if (gangNum.has_value() && failed(*gangNum))
+ return failure();
// FIXME: Comma should require subsequent operands.
(void)parser.parseOptionalComma();
- if (succeeded(
- parser.parseOptionalKeyword(LoopOp::getGangStaticKeyword()))) {
- gangStatic = OpAsmParser::UnresolvedOperand{};
- if (parser.parseEqual())
- return failure();
- gangStatic = OpAsmParser::UnresolvedOperand{};
- if (parser.parseOperand(*gangStatic) ||
- parser.parseColonType(gangStaticType))
- return failure();
- }
+ gangStatic = parserOptionalOperandAndTypeWithPrefix(
+ parser, result, LoopOp::getGangStaticKeyword());
+ if (gangStatic.has_value() && failed(*gangStatic))
+ return failure();
// FIXME: Why allow optional last commas?
(void)parser.parseOptionalComma();
if (failed(parser.parseRParen()))
return failure();
}
+
+ // worker?
+ if (succeeded(parser.parseOptionalKeyword(LoopOp::getWorkerKeyword())))
+ executionMapping |= OpenACCExecMapping::WORKER;
+
+ // optional worker operand
+ worker = parseOptionalOperandAndType(parser, result);
+ if (worker.has_value() && failed(*worker))
+ return failure();
+
+ // vector?
+ if (succeeded(parser.parseOptionalKeyword(LoopOp::getVectorKeyword())))
+ executionMapping |= OpenACCExecMapping::VECTOR;
+
+ // optional vector operand
+ vector = parseOptionalOperandAndType(parser, result);
+ if (vector.has_value() && failed(*vector))
+ return failure();
+
+ // tile()?
+ if (failed(parseOperandList(parser, LoopOp::getTileKeyword(), tileOperands,
+ operandTypes, result)))
+ return failure();
+
+ // private()?
+ if (failed(parseOperandList(parser, LoopOp::getPrivateKeyword(),
+ privateOperands, operandTypes, result)))
+ return failure();
+
+ // reduction()?
+ if (failed(parseOperandList(parser, LoopOp::getReductionKeyword(),
+ reductionOperands, operandTypes, result)))
+ return failure();
+
+ if (executionMapping != acc::OpenACCExecMapping::NONE)
+ result.addAttribute(LoopOp::getExecutionMappingAttrStrName(),
+ builder.getI64IntegerAttr(executionMapping));
+
+ // Parse optional results in case there is a reduce.
+ if (parser.parseOptionalArrowTypeList(result.types))
+ return failure();
+
+ if (failed(parseRegions<LoopOp>(parser, result)))
+ return failure();
+
+ result.addAttribute(LoopOp::getOperandSegmentSizeAttr(),
+ builder.getDenseI32ArrayAttr(
+ {static_cast<int32_t>(gangNum.has_value() ? 1 : 0),
+ static_cast<int32_t>(gangStatic.has_value() ? 1 : 0),
+ static_cast<int32_t>(worker.has_value() ? 1 : 0),
+ static_cast<int32_t>(vector.has_value() ? 1 : 0),
+ static_cast<int32_t>(tileOperands.size()),
+ static_cast<int32_t>(privateOperands.size()),
+ static_cast<int32_t>(reductionOperands.size())}));
+
+ if (failed(parser.parseOptionalAttrDictWithKeyword(result.attributes)))
+ return failure();
+
return success();
}
-void printGangClause(OpAsmPrinter &p, Operation *op, Value gangNum,
- Type gangNumType, Value gangStatic, Type gangStaticType,
- UnitAttr hasGang) {
- if (gangNum || gangStatic) {
- p << "(";
- if (gangNum) {
- p << LoopOp::getGangNumKeyword() << "=" << gangNum << " : "
- << gangNumType;
+void LoopOp::print(OpAsmPrinter &printer) {
+ unsigned execMapping = getExecMapping();
+ if (execMapping & OpenACCExecMapping::GANG) {
+ printer << " " << LoopOp::getGangKeyword();
+ Value gangNum = getGangNum();
+ Value gangStatic = getGangStatic();
+
+ // Print optional gang operands
+ if (gangNum || gangStatic) {
+ printer << "(";
+ if (gangNum) {
+ printer << LoopOp::getGangNumKeyword() << "=" << gangNum << ": "
+ << gangNum.getType();
+ if (gangStatic)
+ printer << ", ";
+ }
if (gangStatic)
- p << ", ";
+ printer << LoopOp::getGangStaticKeyword() << "=" << gangStatic << ": "
+ << gangStatic.getType();
+ printer << ")";
}
- if (gangStatic)
- p << LoopOp::getGangStaticKeyword() << "=" << gangStatic << " : "
- << gangStaticType;
- p << ")";
}
-}
-static ParseResult
-parseWorkerClause(OpAsmParser &parser,
- std::optional<OpAsmParser::UnresolvedOperand> &workerNum,
- Type &workerNumType, UnitAttr &hasWorker) {
- hasWorker = UnitAttr::get(parser.getBuilder().getContext());
- if (succeeded(parser.parseOptionalLParen())) {
- workerNum = OpAsmParser::UnresolvedOperand{};
- if (parser.parseOperand(*workerNum) ||
- parser.parseColonType(workerNumType) || parser.parseRParen())
- return failure();
+ if (execMapping & OpenACCExecMapping::WORKER) {
+ printer << " " << LoopOp::getWorkerKeyword();
+
+ // Print optional worker operand if present
+ if (Value workerNum = getWorkerNum())
+ printer << "(" << workerNum << ": " << workerNum.getType() << ")";
}
- return success();
-}
-void printWorkerClause(OpAsmPrinter &p, Operation *op, Value workerNum,
- Type workerNumType, UnitAttr hasWorker) {
- if (workerNum)
- p << "(" << workerNum << " : " << workerNumType << ")";
-}
+ if (execMapping & OpenACCExecMapping::VECTOR) {
+ printer << " " << LoopOp::getVectorKeyword();
-static ParseResult
-parseVectorClause(OpAsmParser &parser,
- std::optional<OpAsmParser::UnresolvedOperand> &vectorLength,
- Type &vectorLengthType, UnitAttr &hasVector) {
- hasVector = UnitAttr::get(parser.getBuilder().getContext());
- if (succeeded(parser.parseOptionalLParen())) {
- vectorLength = OpAsmParser::UnresolvedOperand{};
- if (parser.parseOperand(*vectorLength) ||
- parser.parseColonType(vectorLengthType) || parser.parseRParen())
- return failure();
+ // Print optional vector operand if present
+ if (Value vectorLength = this->getVectorLength())
+ printer << "(" << vectorLength << ": " << vectorLength.getType() << ")";
}
- return success();
-}
-void printVectorClause(OpAsmPrinter &p, Operation *op, Value vectorLength,
- Type vectorLengthType, UnitAttr hasVector) {
- if (vectorLength)
- p << "(" << vectorLength << " : " << vectorLengthType << ")";
+ // tile()?
+ printOperandList(getTileOperands(), LoopOp::getTileKeyword(), printer);
+
+ // private()?
+ printOperandList(getPrivateOperands(), LoopOp::getPrivateKeyword(), printer);
+
+ // reduction()?
+ printOperandList(getReductionOperands(), LoopOp::getReductionKeyword(),
+ printer);
+
+ if (getNumResults() > 0)
+ printer << " -> (" << getResultTypes() << ")";
+
+ printer << ' ';
+ printer.printRegion(getRegion(),
+ /*printEntryBlockArgs=*/false,
+ /*printBlockTerminators=*/true);
+
+ printer.printOptionalAttrDictWithKeyword(
+ (*this)->getAttrs(), {LoopOp::getExecutionMappingAttrStrName(),
+ LoopOp::getOperandSegmentSizeAttr()});
}
LogicalResult acc::LoopOp::verify() {
// auto, independent and seq attribute are mutually exclusive.
if ((getAuto_() && (getIndependent() || getSeq())) ||
(getIndependent() && getSeq())) {
- return emitError() << "only one of \"" << acc::LoopOp::getAutoAttrStrName()
- << "\", " << getIndependentAttrName() << ", "
- << getSeqAttrName()
- << " can be present at the same time";
+ return emitError("only one of " + acc::LoopOp::getAutoAttrStrName() + ", " +
+ acc::LoopOp::getIndependentAttrStrName() + ", " +
+ acc::LoopOp::getSeqAttrStrName() +
+ " can be present at the same time");
}
// Gang, worker and vector are incompatible with seq.
- if (getSeq() && (getHasGang() || getHasWorker() || getHasVector()))
+ if (getSeq() && getExecMapping() != OpenACCExecMapping::NONE)
return emitError("gang, worker or vector cannot appear with the seq attr");
// Check non-empty body().
// -----
-// expected-error@+1 {{only one of "auto", "independent", "seq" can be present at the same time}}
+// expected-error@+1 {{only one of auto, independent, seq can be present at the same time}}
acc.loop {
acc.yield
} attributes {auto_, seq}
"test.openacc_dummy_op"() : () -> ()
acc.yield
}
- acc.loop tile(%i64Value, %i64Value : i64, i64) {
+ acc.loop tile(%i64Value: i64, %i64Value: i64) {
"test.openacc_dummy_op"() : () -> ()
acc.yield
}
- acc.loop tile(%i32Value, %i32Value : i32, i32) {
+ acc.loop tile(%i32Value: i32, %i32Value: i32) {
"test.openacc_dummy_op"() : () -> ()
acc.yield
}
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop gang(num=[[I64VALUE]] : i64) {
+// CHECK: acc.loop gang(num=[[I64VALUE]]: i64) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop gang(static=[[I64VALUE]] : i64) {
+// CHECK: acc.loop gang(static=[[I64VALUE]]: i64) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop worker([[I64VALUE]] : i64) {
+// CHECK: acc.loop worker([[I64VALUE]]: i64) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop worker([[I32VALUE]] : i32) {
+// CHECK: acc.loop worker([[I32VALUE]]: i32) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop worker([[IDXVALUE]] : index) {
+// CHECK: acc.loop worker([[IDXVALUE]]: index) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop vector([[I64VALUE]] : i64) {
+// CHECK: acc.loop vector([[I64VALUE]]: i64) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop vector([[I32VALUE]] : i32) {
+// CHECK: acc.loop vector([[I32VALUE]]: i32) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop vector([[IDXVALUE]] : index) {
+// CHECK: acc.loop vector([[IDXVALUE]]: index) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop gang(num=[[I64VALUE]] : i64) worker vector {
+// CHECK: acc.loop gang(num=[[I64VALUE]]: i64) worker vector {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop gang(num=[[I64VALUE]] : i64, static=[[I64VALUE]] : i64) worker([[I64VALUE]] : i64) vector([[I64VALUE]] : i64) {
+// CHECK: acc.loop gang(num=[[I64VALUE]]: i64, static=[[I64VALUE]]: i64) worker([[I64VALUE]]: i64) vector([[I64VALUE]]: i64) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop gang(num=[[I32VALUE]] : i32, static=[[IDXVALUE]] : index) {
+// CHECK: acc.loop gang(num=[[I32VALUE]]: i32, static=[[IDXVALUE]]: index) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop tile([[I64VALUE]], [[I64VALUE]] : i64, i64) {
+// CHECK: acc.loop tile([[I64VALUE]]: i64, [[I64VALUE]]: i64) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }
-// CHECK: acc.loop tile([[I32VALUE]], [[I32VALUE]] : i32, i32) {
+// CHECK: acc.loop tile([[I32VALUE]]: i32, [[I32VALUE]]: i32) {
// CHECK-NEXT: "test.openacc_dummy_op"() : () -> ()
// CHECK-NEXT: acc.yield
// CHECK-NEXT: }