forked from OSchip/llvm-project
1035 lines
46 KiB
C++
1035 lines
46 KiB
C++
//===-- OpenACC.cpp -- OpenACC directive lowering -------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "flang/Lower/OpenACC.h"
|
|
#include "flang/Common/idioms.h"
|
|
#include "flang/Lower/Bridge.h"
|
|
#include "flang/Lower/FIRBuilder.h"
|
|
#include "flang/Lower/PFTBuilder.h"
|
|
#include "flang/Lower/Support/BoxValue.h"
|
|
#include "flang/Lower/Todo.h"
|
|
#include "flang/Parser/parse-tree.h"
|
|
#include "flang/Semantics/tools.h"
|
|
#include "mlir/Dialect/OpenACC/OpenACC.h"
|
|
#include "llvm/Frontend/OpenACC/ACC.h.inc"
|
|
|
|
static const Fortran::parser::Name *
|
|
getDesignatorNameIfDataRef(const Fortran::parser::Designator &designator) {
|
|
const auto *dataRef{std::get_if<Fortran::parser::DataRef>(&designator.u)};
|
|
return dataRef ? std::get_if<Fortran::parser::Name>(&dataRef->u) : nullptr;
|
|
}
|
|
|
|
static void genObjectList(const Fortran::parser::AccObjectList &objectList,
|
|
Fortran::lower::AbstractConverter &converter,
|
|
SmallVectorImpl<Value> &operands) {
|
|
for (const auto &accObject : objectList.v) {
|
|
std::visit(
|
|
Fortran::common::visitors{
|
|
[&](const Fortran::parser::Designator &designator) {
|
|
if (const auto *name = getDesignatorNameIfDataRef(designator)) {
|
|
const auto variable = converter.getSymbolAddress(*name->symbol);
|
|
operands.push_back(variable);
|
|
}
|
|
},
|
|
[&](const Fortran::parser::Name &name) {
|
|
const auto variable = converter.getSymbolAddress(*name.symbol);
|
|
operands.push_back(variable);
|
|
}},
|
|
accObject.u);
|
|
}
|
|
}
|
|
|
|
template <typename Clause>
|
|
static void
|
|
genObjectListWithModifier(const Clause *x,
|
|
Fortran::lower::AbstractConverter &converter,
|
|
Fortran::parser::AccDataModifier::Modifier mod,
|
|
SmallVectorImpl<Value> &operandsWithModifier,
|
|
SmallVectorImpl<Value> &operands) {
|
|
const Fortran::parser::AccObjectListWithModifier &listWithModifier = x->v;
|
|
const Fortran::parser::AccObjectList &accObjectList =
|
|
std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
|
|
const auto &modifier =
|
|
std::get<std::optional<Fortran::parser::AccDataModifier>>(
|
|
listWithModifier.t);
|
|
if (modifier && (*modifier).v == mod) {
|
|
genObjectList(accObjectList, converter, operandsWithModifier);
|
|
} else {
|
|
genObjectList(accObjectList, converter, operands);
|
|
}
|
|
}
|
|
|
|
static void addOperands(SmallVectorImpl<Value> &operands,
|
|
SmallVectorImpl<int32_t> &operandSegments,
|
|
const SmallVectorImpl<Value> &clauseOperands) {
|
|
operands.append(clauseOperands.begin(), clauseOperands.end());
|
|
operandSegments.push_back(clauseOperands.size());
|
|
}
|
|
|
|
static void addOperand(SmallVectorImpl<Value> &operands,
|
|
SmallVectorImpl<int32_t> &operandSegments,
|
|
const Value &clauseOperand) {
|
|
if (clauseOperand) {
|
|
operands.push_back(clauseOperand);
|
|
operandSegments.push_back(1);
|
|
} else {
|
|
operandSegments.push_back(0);
|
|
}
|
|
}
|
|
|
|
template <typename Op, typename Terminator>
|
|
static Op createRegionOp(Fortran::lower::FirOpBuilder &builder,
|
|
mlir::Location loc,
|
|
const SmallVectorImpl<Value> &operands,
|
|
const SmallVectorImpl<int32_t> &operandSegments) {
|
|
llvm::ArrayRef<mlir::Type> argTy;
|
|
Op op = builder.create<Op>(loc, argTy, operands);
|
|
builder.createBlock(&op.getRegion());
|
|
auto &block = op.getRegion().back();
|
|
builder.setInsertionPointToStart(&block);
|
|
builder.create<Terminator>(loc);
|
|
|
|
op->setAttr(Op::getOperandSegmentSizeAttr(),
|
|
builder.getI32VectorAttr(operandSegments));
|
|
|
|
// Place the insertion point to the start of the first block.
|
|
builder.setInsertionPointToStart(&block);
|
|
|
|
return op;
|
|
}
|
|
|
|
template <typename Op>
|
|
static Op createSimpleOp(Fortran::lower::FirOpBuilder &builder,
|
|
mlir::Location loc,
|
|
const SmallVectorImpl<Value> &operands,
|
|
const SmallVectorImpl<int32_t> &operandSegments) {
|
|
llvm::ArrayRef<mlir::Type> argTy;
|
|
Op op = builder.create<Op>(loc, argTy, operands);
|
|
op->setAttr(Op::getOperandSegmentSizeAttr(),
|
|
builder.getI32VectorAttr(operandSegments));
|
|
return op;
|
|
}
|
|
|
|
static void genACC(Fortran::lower::AbstractConverter &converter,
|
|
Fortran::lower::pft::Evaluation &eval,
|
|
const Fortran::parser::OpenACCLoopConstruct &loopConstruct) {
|
|
|
|
const auto &beginLoopDirective =
|
|
std::get<Fortran::parser::AccBeginLoopDirective>(loopConstruct.t);
|
|
const auto &loopDirective =
|
|
std::get<Fortran::parser::AccLoopDirective>(beginLoopDirective.t);
|
|
|
|
if (loopDirective.v == llvm::acc::ACCD_loop) {
|
|
auto &firOpBuilder = converter.getFirOpBuilder();
|
|
auto currentLocation = converter.getCurrentLocation();
|
|
|
|
// Add attribute extracted from clauses.
|
|
const auto &accClauseList =
|
|
std::get<Fortran::parser::AccClauseList>(beginLoopDirective.t);
|
|
|
|
mlir::Value workerNum;
|
|
mlir::Value vectorLength;
|
|
mlir::Value gangNum;
|
|
mlir::Value gangStatic;
|
|
SmallVector<Value, 2> tileOperands, privateOperands, reductionOperands;
|
|
std::int64_t executionMapping = mlir::acc::OpenACCExecMapping::NONE;
|
|
|
|
// Lower clauses values mapped to operands.
|
|
for (const auto &clause : accClauseList.v) {
|
|
if (const auto *gangClause =
|
|
std::get_if<Fortran::parser::AccClause::Gang>(&clause.u)) {
|
|
if (gangClause->v) {
|
|
const Fortran::parser::AccGangArgument &x = *gangClause->v;
|
|
if (const auto &gangNumValue =
|
|
std::get<std::optional<Fortran::parser::ScalarIntExpr>>(
|
|
x.t)) {
|
|
gangNum = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(gangNumValue.value())));
|
|
}
|
|
if (const auto &gangStaticValue =
|
|
std::get<std::optional<Fortran::parser::AccSizeExpr>>(x.t)) {
|
|
const auto &expr =
|
|
std::get<std::optional<Fortran::parser::ScalarIntExpr>>(
|
|
gangStaticValue.value().t);
|
|
if (expr) {
|
|
gangStatic = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(*expr)));
|
|
} else {
|
|
// * was passed as value and will be represented as a -1 constant
|
|
// integer.
|
|
gangStatic = firOpBuilder.createIntegerConstant(
|
|
currentLocation, firOpBuilder.getIntegerType(32),
|
|
/* STAR */ -1);
|
|
}
|
|
}
|
|
}
|
|
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)));
|
|
}
|
|
executionMapping |= mlir::acc::OpenACCExecMapping::WORKER;
|
|
} else if (const auto *vectorClause =
|
|
std::get_if<Fortran::parser::AccClause::Vector>(
|
|
&clause.u)) {
|
|
if (vectorClause->v) {
|
|
vectorLength = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*vectorClause->v)));
|
|
}
|
|
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;
|
|
for (const auto &accTileExpr : accTileExprList.v) {
|
|
const auto &expr =
|
|
std::get<std::optional<Fortran::parser::ScalarIntConstantExpr>>(
|
|
accTileExpr.t);
|
|
if (expr) {
|
|
tileOperands.push_back(fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(*expr))));
|
|
} else {
|
|
// * was passed as value and will be represented as a -1 constant
|
|
// integer.
|
|
mlir::Value tileStar = firOpBuilder.createIntegerConstant(
|
|
currentLocation, firOpBuilder.getIntegerType(32),
|
|
/* STAR */ -1);
|
|
tileOperands.push_back(tileStar);
|
|
}
|
|
}
|
|
} else if (const auto *privateClause =
|
|
std::get_if<Fortran::parser::AccClause::Private>(
|
|
&clause.u)) {
|
|
genObjectList(privateClause->v, converter, privateOperands);
|
|
}
|
|
// Reduction clause is left out for the moment as the clause will probably
|
|
// end up having its own operation.
|
|
}
|
|
|
|
// Prepare the operand segement size attribute and the operands value range.
|
|
SmallVector<Value, 8> operands;
|
|
SmallVector<int32_t, 8> operandSegments;
|
|
addOperand(operands, operandSegments, gangNum);
|
|
addOperand(operands, operandSegments, gangStatic);
|
|
addOperand(operands, operandSegments, workerNum);
|
|
addOperand(operands, operandSegments, vectorLength);
|
|
addOperands(operands, operandSegments, tileOperands);
|
|
addOperands(operands, operandSegments, privateOperands);
|
|
addOperands(operands, operandSegments, reductionOperands);
|
|
|
|
auto loopOp = createRegionOp<mlir::acc::LoopOp, mlir::acc::YieldOp>(
|
|
firOpBuilder, currentLocation, operands, operandSegments);
|
|
|
|
loopOp->setAttr(mlir::acc::LoopOp::getExecutionMappingAttrName(),
|
|
firOpBuilder.getI64IntegerAttr(executionMapping));
|
|
|
|
// Lower clauses mapped to attributes
|
|
for (const auto &clause : accClauseList.v) {
|
|
if (const auto *collapseClause =
|
|
std::get_if<Fortran::parser::AccClause::Collapse>(&clause.u)) {
|
|
const auto *expr = Fortran::semantics::GetExpr(collapseClause->v);
|
|
const auto collapseValue = Fortran::evaluate::ToInt64(*expr);
|
|
if (collapseValue) {
|
|
loopOp->setAttr(mlir::acc::LoopOp::getCollapseAttrName(),
|
|
firOpBuilder.getI64IntegerAttr(*collapseValue));
|
|
}
|
|
} else if (std::get_if<Fortran::parser::AccClause::Seq>(&clause.u)) {
|
|
loopOp->setAttr(mlir::acc::LoopOp::getSeqAttrName(),
|
|
firOpBuilder.getUnitAttr());
|
|
} else if (std::get_if<Fortran::parser::AccClause::Independent>(
|
|
&clause.u)) {
|
|
loopOp->setAttr(mlir::acc::LoopOp::getIndependentAttrName(),
|
|
firOpBuilder.getUnitAttr());
|
|
} else if (std::get_if<Fortran::parser::AccClause::Auto>(&clause.u)) {
|
|
loopOp->setAttr(mlir::acc::LoopOp::getAutoAttrName(),
|
|
firOpBuilder.getUnitAttr());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
genACCParallelOp(Fortran::lower::AbstractConverter &converter,
|
|
const Fortran::parser::AccClauseList &accClauseList) {
|
|
mlir::Value async;
|
|
mlir::Value numGangs;
|
|
mlir::Value numWorkers;
|
|
mlir::Value vectorLength;
|
|
mlir::Value ifCond;
|
|
mlir::Value selfCond;
|
|
SmallVector<Value, 2> waitOperands, reductionOperands, copyOperands,
|
|
copyinOperands, copyinReadonlyOperands, copyoutOperands,
|
|
copyoutZeroOperands, createOperands, createZeroOperands, noCreateOperands,
|
|
presentOperands, devicePtrOperands, attachOperands, privateOperands,
|
|
firstprivateOperands;
|
|
|
|
// Async, wait and self clause have optional values but can be present with
|
|
// no value as well. When there is no value, the op has an attribute to
|
|
// represent the clause.
|
|
bool addAsyncAttr = false;
|
|
bool addWaitAttr = false;
|
|
bool addSelfAttr = false;
|
|
|
|
auto &firOpBuilder = converter.getFirOpBuilder();
|
|
auto currentLocation = converter.getCurrentLocation();
|
|
|
|
// Lower clauses values mapped to operands.
|
|
// Keep track of each group of operands separatly as clauses can appear
|
|
// more than once.
|
|
for (const auto &clause : accClauseList.v) {
|
|
if (const auto *asyncClause =
|
|
std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
|
|
const auto &asyncClauseValue = asyncClause->v;
|
|
if (asyncClauseValue) { // async has a value.
|
|
async = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*asyncClauseValue)));
|
|
} else {
|
|
addAsyncAttr = true;
|
|
}
|
|
} else if (const auto *waitClause =
|
|
std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
|
|
const auto &waitClauseValue = waitClause->v;
|
|
if (waitClauseValue) { // wait has a value.
|
|
const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
|
|
const std::list<Fortran::parser::ScalarIntExpr> &waitList =
|
|
std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
|
|
for (const Fortran::parser::ScalarIntExpr &value : waitList) {
|
|
Value v = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(value)));
|
|
waitOperands.push_back(v);
|
|
}
|
|
} else {
|
|
addWaitAttr = true;
|
|
}
|
|
} else if (const auto *numGangsClause =
|
|
std::get_if<Fortran::parser::AccClause::NumGangs>(
|
|
&clause.u)) {
|
|
numGangs = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(numGangsClause->v)));
|
|
} else if (const auto *numWorkersClause =
|
|
std::get_if<Fortran::parser::AccClause::NumWorkers>(
|
|
&clause.u)) {
|
|
numWorkers = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(numWorkersClause->v)));
|
|
} else if (const auto *vectorLengthClause =
|
|
std::get_if<Fortran::parser::AccClause::VectorLength>(
|
|
&clause.u)) {
|
|
vectorLength = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(vectorLengthClause->v)));
|
|
} else if (const auto *ifClause =
|
|
std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
|
|
Value cond = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
|
|
ifCond = firOpBuilder.createConvert(currentLocation,
|
|
firOpBuilder.getI1Type(), cond);
|
|
} else if (const auto *selfClause =
|
|
std::get_if<Fortran::parser::AccClause::Self>(&clause.u)) {
|
|
const Fortran::parser::AccSelfClause &accSelfClause = selfClause->v;
|
|
if (const auto *optCondition =
|
|
std::get_if<std::optional<Fortran::parser::ScalarLogicalExpr>>(
|
|
&accSelfClause.u)) {
|
|
if (*optCondition) {
|
|
Value cond = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*optCondition)));
|
|
selfCond = firOpBuilder.createConvert(currentLocation,
|
|
firOpBuilder.getI1Type(), cond);
|
|
} else {
|
|
addSelfAttr = true;
|
|
}
|
|
}
|
|
} else if (const auto *copyClause =
|
|
std::get_if<Fortran::parser::AccClause::Copy>(&clause.u)) {
|
|
genObjectList(copyClause->v, converter, copyOperands);
|
|
} else if (const auto *copyinClause =
|
|
std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) {
|
|
genObjectListWithModifier<Fortran::parser::AccClause::Copyin>(
|
|
copyinClause, converter,
|
|
Fortran::parser::AccDataModifier::Modifier::ReadOnly,
|
|
copyinReadonlyOperands, copyinOperands);
|
|
} else if (const auto *copyoutClause =
|
|
std::get_if<Fortran::parser::AccClause::Copyout>(
|
|
&clause.u)) {
|
|
genObjectListWithModifier<Fortran::parser::AccClause::Copyout>(
|
|
copyoutClause, converter,
|
|
Fortran::parser::AccDataModifier::Modifier::Zero, copyoutZeroOperands,
|
|
copyoutOperands);
|
|
} else if (const auto *createClause =
|
|
std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) {
|
|
genObjectListWithModifier<Fortran::parser::AccClause::Create>(
|
|
createClause, converter,
|
|
Fortran::parser::AccDataModifier::Modifier::Zero, createZeroOperands,
|
|
createOperands);
|
|
} else if (const auto *noCreateClause =
|
|
std::get_if<Fortran::parser::AccClause::NoCreate>(
|
|
&clause.u)) {
|
|
genObjectList(noCreateClause->v, converter, noCreateOperands);
|
|
} else if (const auto *presentClause =
|
|
std::get_if<Fortran::parser::AccClause::Present>(
|
|
&clause.u)) {
|
|
genObjectList(presentClause->v, converter, presentOperands);
|
|
} else if (const auto *devicePtrClause =
|
|
std::get_if<Fortran::parser::AccClause::Deviceptr>(
|
|
&clause.u)) {
|
|
genObjectList(devicePtrClause->v, converter, devicePtrOperands);
|
|
} else if (const auto *attachClause =
|
|
std::get_if<Fortran::parser::AccClause::Attach>(&clause.u)) {
|
|
genObjectList(attachClause->v, converter, attachOperands);
|
|
} else if (const auto *privateClause =
|
|
std::get_if<Fortran::parser::AccClause::Private>(
|
|
&clause.u)) {
|
|
genObjectList(privateClause->v, converter, privateOperands);
|
|
} else if (const auto *firstprivateClause =
|
|
std::get_if<Fortran::parser::AccClause::Firstprivate>(
|
|
&clause.u)) {
|
|
genObjectList(firstprivateClause->v, converter, firstprivateOperands);
|
|
}
|
|
}
|
|
|
|
// Prepare the operand segement size attribute and the operands value range.
|
|
SmallVector<Value, 8> operands;
|
|
SmallVector<int32_t, 8> operandSegments;
|
|
addOperand(operands, operandSegments, async);
|
|
addOperands(operands, operandSegments, waitOperands);
|
|
addOperand(operands, operandSegments, numGangs);
|
|
addOperand(operands, operandSegments, numWorkers);
|
|
addOperand(operands, operandSegments, vectorLength);
|
|
addOperand(operands, operandSegments, ifCond);
|
|
addOperand(operands, operandSegments, selfCond);
|
|
addOperands(operands, operandSegments, reductionOperands);
|
|
addOperands(operands, operandSegments, copyOperands);
|
|
addOperands(operands, operandSegments, copyinOperands);
|
|
addOperands(operands, operandSegments, copyinReadonlyOperands);
|
|
addOperands(operands, operandSegments, copyoutOperands);
|
|
addOperands(operands, operandSegments, copyoutZeroOperands);
|
|
addOperands(operands, operandSegments, createOperands);
|
|
addOperands(operands, operandSegments, createZeroOperands);
|
|
addOperands(operands, operandSegments, noCreateOperands);
|
|
addOperands(operands, operandSegments, presentOperands);
|
|
addOperands(operands, operandSegments, devicePtrOperands);
|
|
addOperands(operands, operandSegments, attachOperands);
|
|
addOperands(operands, operandSegments, privateOperands);
|
|
addOperands(operands, operandSegments, firstprivateOperands);
|
|
|
|
auto parallelOp = createRegionOp<mlir::acc::ParallelOp, mlir::acc::YieldOp>(
|
|
firOpBuilder, currentLocation, operands, operandSegments);
|
|
|
|
if (addAsyncAttr)
|
|
parallelOp->setAttr(mlir::acc::ParallelOp::getAsyncAttrName(),
|
|
firOpBuilder.getUnitAttr());
|
|
if (addWaitAttr)
|
|
parallelOp->setAttr(mlir::acc::ParallelOp::getWaitAttrName(),
|
|
firOpBuilder.getUnitAttr());
|
|
if (addSelfAttr)
|
|
parallelOp->setAttr(mlir::acc::ParallelOp::getSelfAttrName(),
|
|
firOpBuilder.getUnitAttr());
|
|
}
|
|
|
|
static void genACCDataOp(Fortran::lower::AbstractConverter &converter,
|
|
const Fortran::parser::AccClauseList &accClauseList) {
|
|
mlir::Value ifCond;
|
|
SmallVector<Value, 2> copyOperands, copyinOperands, copyinReadonlyOperands,
|
|
copyoutOperands, copyoutZeroOperands, createOperands, createZeroOperands,
|
|
noCreateOperands, presentOperands, deviceptrOperands, attachOperands;
|
|
|
|
auto &firOpBuilder = converter.getFirOpBuilder();
|
|
auto currentLocation = converter.getCurrentLocation();
|
|
|
|
// Lower clauses values mapped to operands.
|
|
// Keep track of each group of operands separatly as clauses can appear
|
|
// more than once.
|
|
for (const auto &clause : accClauseList.v) {
|
|
if (const auto *ifClause =
|
|
std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
|
|
Value cond = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
|
|
ifCond = firOpBuilder.createConvert(currentLocation,
|
|
firOpBuilder.getI1Type(), cond);
|
|
} else if (const auto *copyClause =
|
|
std::get_if<Fortran::parser::AccClause::Copy>(&clause.u)) {
|
|
genObjectList(copyClause->v, converter, copyOperands);
|
|
} else if (const auto *copyinClause =
|
|
std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) {
|
|
genObjectListWithModifier<Fortran::parser::AccClause::Copyin>(
|
|
copyinClause, converter,
|
|
Fortran::parser::AccDataModifier::Modifier::ReadOnly,
|
|
copyinReadonlyOperands, copyinOperands);
|
|
} else if (const auto *copyoutClause =
|
|
std::get_if<Fortran::parser::AccClause::Copyout>(
|
|
&clause.u)) {
|
|
genObjectListWithModifier<Fortran::parser::AccClause::Copyout>(
|
|
copyoutClause, converter,
|
|
Fortran::parser::AccDataModifier::Modifier::Zero, copyoutZeroOperands,
|
|
copyoutOperands);
|
|
} else if (const auto *createClause =
|
|
std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) {
|
|
genObjectListWithModifier<Fortran::parser::AccClause::Create>(
|
|
createClause, converter,
|
|
Fortran::parser::AccDataModifier::Modifier::Zero, createZeroOperands,
|
|
createOperands);
|
|
} else if (const auto *noCreateClause =
|
|
std::get_if<Fortran::parser::AccClause::NoCreate>(
|
|
&clause.u)) {
|
|
genObjectList(noCreateClause->v, converter, noCreateOperands);
|
|
} else if (const auto *presentClause =
|
|
std::get_if<Fortran::parser::AccClause::Present>(
|
|
&clause.u)) {
|
|
genObjectList(presentClause->v, converter, presentOperands);
|
|
} else if (const auto *deviceptrClause =
|
|
std::get_if<Fortran::parser::AccClause::Deviceptr>(
|
|
&clause.u)) {
|
|
genObjectList(deviceptrClause->v, converter, deviceptrOperands);
|
|
} else if (const auto *attachClause =
|
|
std::get_if<Fortran::parser::AccClause::Attach>(&clause.u)) {
|
|
genObjectList(attachClause->v, converter, attachOperands);
|
|
}
|
|
}
|
|
|
|
// Prepare the operand segement size attribute and the operands value range.
|
|
SmallVector<Value, 8> operands;
|
|
SmallVector<int32_t, 8> operandSegments;
|
|
addOperand(operands, operandSegments, ifCond);
|
|
addOperands(operands, operandSegments, copyOperands);
|
|
addOperands(operands, operandSegments, copyinOperands);
|
|
addOperands(operands, operandSegments, copyinReadonlyOperands);
|
|
addOperands(operands, operandSegments, copyoutOperands);
|
|
addOperands(operands, operandSegments, copyoutZeroOperands);
|
|
addOperands(operands, operandSegments, createOperands);
|
|
addOperands(operands, operandSegments, createZeroOperands);
|
|
addOperands(operands, operandSegments, noCreateOperands);
|
|
addOperands(operands, operandSegments, presentOperands);
|
|
addOperands(operands, operandSegments, deviceptrOperands);
|
|
addOperands(operands, operandSegments, attachOperands);
|
|
|
|
createRegionOp<mlir::acc::DataOp, mlir::acc::TerminatorOp>(
|
|
firOpBuilder, currentLocation, operands, operandSegments);
|
|
}
|
|
|
|
static void
|
|
genACC(Fortran::lower::AbstractConverter &converter,
|
|
Fortran::lower::pft::Evaluation &eval,
|
|
const Fortran::parser::OpenACCBlockConstruct &blockConstruct) {
|
|
const auto &beginBlockDirective =
|
|
std::get<Fortran::parser::AccBeginBlockDirective>(blockConstruct.t);
|
|
const auto &blockDirective =
|
|
std::get<Fortran::parser::AccBlockDirective>(beginBlockDirective.t);
|
|
const auto &accClauseList =
|
|
std::get<Fortran::parser::AccClauseList>(beginBlockDirective.t);
|
|
|
|
if (blockDirective.v == llvm::acc::ACCD_parallel) {
|
|
genACCParallelOp(converter, accClauseList);
|
|
} else if (blockDirective.v == llvm::acc::ACCD_data) {
|
|
genACCDataOp(converter, accClauseList);
|
|
}
|
|
}
|
|
|
|
static void
|
|
genACCEnterDataOp(Fortran::lower::AbstractConverter &converter,
|
|
const Fortran::parser::AccClauseList &accClauseList) {
|
|
mlir::Value ifCond, async, waitDevnum;
|
|
SmallVector<Value, 2> copyinOperands, createOperands, createZeroOperands,
|
|
attachOperands, waitOperands;
|
|
|
|
// Async, wait and self clause have optional values but can be present with
|
|
// no value as well. When there is no value, the op has an attribute to
|
|
// represent the clause.
|
|
bool addAsyncAttr = false;
|
|
bool addWaitAttr = false;
|
|
|
|
auto &firOpBuilder = converter.getFirOpBuilder();
|
|
auto currentLocation = converter.getCurrentLocation();
|
|
|
|
// Lower clauses values mapped to operands.
|
|
// Keep track of each group of operands separatly as clauses can appear
|
|
// more than once.
|
|
for (const auto &clause : accClauseList.v) {
|
|
if (const auto *ifClause =
|
|
std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
|
|
mlir::Value cond = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
|
|
ifCond = firOpBuilder.createConvert(currentLocation,
|
|
firOpBuilder.getI1Type(), cond);
|
|
} else if (const auto *asyncClause =
|
|
std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
|
|
const auto &asyncClauseValue = asyncClause->v;
|
|
if (asyncClauseValue) { // async has a value.
|
|
async = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*asyncClauseValue)));
|
|
} else {
|
|
addAsyncAttr = true;
|
|
}
|
|
} else if (const auto *waitClause =
|
|
std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
|
|
const auto &waitClauseValue = waitClause->v;
|
|
if (waitClauseValue) { // wait has a value.
|
|
const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
|
|
const std::list<Fortran::parser::ScalarIntExpr> &waitList =
|
|
std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
|
|
for (const Fortran::parser::ScalarIntExpr &value : waitList) {
|
|
mlir::Value v = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(value)));
|
|
waitOperands.push_back(v);
|
|
}
|
|
|
|
const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
|
|
std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
|
|
if (waitDevnumValue)
|
|
waitDevnum = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*waitDevnumValue)));
|
|
} else {
|
|
addWaitAttr = true;
|
|
}
|
|
} else if (const auto *copyinClause =
|
|
std::get_if<Fortran::parser::AccClause::Copyin>(&clause.u)) {
|
|
const Fortran::parser::AccObjectListWithModifier &listWithModifier =
|
|
copyinClause->v;
|
|
const Fortran::parser::AccObjectList &accObjectList =
|
|
std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
|
|
genObjectList(accObjectList, converter, copyinOperands);
|
|
} else if (const auto *createClause =
|
|
std::get_if<Fortran::parser::AccClause::Create>(&clause.u)) {
|
|
genObjectListWithModifier<Fortran::parser::AccClause::Create>(
|
|
createClause, converter,
|
|
Fortran::parser::AccDataModifier::Modifier::Zero, createZeroOperands,
|
|
createOperands);
|
|
} else if (const auto *attachClause =
|
|
std::get_if<Fortran::parser::AccClause::Attach>(&clause.u)) {
|
|
genObjectList(attachClause->v, converter, attachOperands);
|
|
} else {
|
|
llvm::report_fatal_error(
|
|
"Unknown clause in ENTER DATA directive lowering");
|
|
}
|
|
}
|
|
|
|
// Prepare the operand segement size attribute and the operands value range.
|
|
SmallVector<mlir::Value, 16> operands;
|
|
SmallVector<int32_t, 8> operandSegments;
|
|
addOperand(operands, operandSegments, ifCond);
|
|
addOperand(operands, operandSegments, async);
|
|
addOperand(operands, operandSegments, waitDevnum);
|
|
addOperands(operands, operandSegments, waitOperands);
|
|
addOperands(operands, operandSegments, copyinOperands);
|
|
addOperands(operands, operandSegments, createOperands);
|
|
addOperands(operands, operandSegments, createZeroOperands);
|
|
addOperands(operands, operandSegments, attachOperands);
|
|
|
|
auto enterDataOp = createSimpleOp<mlir::acc::EnterDataOp>(
|
|
firOpBuilder, currentLocation, operands, operandSegments);
|
|
|
|
if (addAsyncAttr)
|
|
enterDataOp.asyncAttr(firOpBuilder.getUnitAttr());
|
|
if (addWaitAttr)
|
|
enterDataOp.waitAttr(firOpBuilder.getUnitAttr());
|
|
}
|
|
|
|
static void
|
|
genACCExitDataOp(Fortran::lower::AbstractConverter &converter,
|
|
const Fortran::parser::AccClauseList &accClauseList) {
|
|
mlir::Value ifCond, async, waitDevnum;
|
|
SmallVector<Value, 2> copyoutOperands, deleteOperands, detachOperands,
|
|
waitOperands;
|
|
|
|
// Async and wait clause have optional values but can be present with
|
|
// no value as well. When there is no value, the op has an attribute to
|
|
// represent the clause.
|
|
bool addAsyncAttr = false;
|
|
bool addWaitAttr = false;
|
|
bool addFinalizeAttr = false;
|
|
|
|
auto &firOpBuilder = converter.getFirOpBuilder();
|
|
auto currentLocation = converter.getCurrentLocation();
|
|
|
|
// Lower clauses values mapped to operands.
|
|
// Keep track of each group of operands separatly as clauses can appear
|
|
// more than once.
|
|
for (const auto &clause : accClauseList.v) {
|
|
if (const auto *ifClause =
|
|
std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
|
|
Value cond = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
|
|
ifCond = firOpBuilder.createConvert(currentLocation,
|
|
firOpBuilder.getI1Type(), cond);
|
|
} else if (const auto *asyncClause =
|
|
std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
|
|
const auto &asyncClauseValue = asyncClause->v;
|
|
if (asyncClauseValue) { // async has a value.
|
|
async = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*asyncClauseValue)));
|
|
} else {
|
|
addAsyncAttr = true;
|
|
}
|
|
} else if (const auto *waitClause =
|
|
std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
|
|
const auto &waitClauseValue = waitClause->v;
|
|
if (waitClauseValue) { // wait has a value.
|
|
const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
|
|
const std::list<Fortran::parser::ScalarIntExpr> &waitList =
|
|
std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
|
|
for (const Fortran::parser::ScalarIntExpr &value : waitList) {
|
|
Value v = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(value)));
|
|
waitOperands.push_back(v);
|
|
}
|
|
|
|
const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
|
|
std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
|
|
if (waitDevnumValue)
|
|
waitDevnum = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*waitDevnumValue)));
|
|
} else {
|
|
addWaitAttr = true;
|
|
}
|
|
} else if (const auto *copyoutClause =
|
|
std::get_if<Fortran::parser::AccClause::Copyout>(
|
|
&clause.u)) {
|
|
const Fortran::parser::AccObjectListWithModifier &listWithModifier =
|
|
copyoutClause->v;
|
|
const Fortran::parser::AccObjectList &accObjectList =
|
|
std::get<Fortran::parser::AccObjectList>(listWithModifier.t);
|
|
genObjectList(accObjectList, converter, copyoutOperands);
|
|
} else if (const auto *deleteClause =
|
|
std::get_if<Fortran::parser::AccClause::Delete>(&clause.u)) {
|
|
genObjectList(deleteClause->v, converter, deleteOperands);
|
|
} else if (const auto *detachClause =
|
|
std::get_if<Fortran::parser::AccClause::Detach>(&clause.u)) {
|
|
genObjectList(detachClause->v, converter, detachOperands);
|
|
} else if (std::get_if<Fortran::parser::AccClause::Finalize>(&clause.u)) {
|
|
addFinalizeAttr = true;
|
|
}
|
|
}
|
|
|
|
// Prepare the operand segement size attribute and the operands value range.
|
|
SmallVector<mlir::Value, 14> operands;
|
|
SmallVector<int32_t, 7> operandSegments;
|
|
addOperand(operands, operandSegments, ifCond);
|
|
addOperand(operands, operandSegments, async);
|
|
addOperand(operands, operandSegments, waitDevnum);
|
|
addOperands(operands, operandSegments, waitOperands);
|
|
addOperands(operands, operandSegments, copyoutOperands);
|
|
addOperands(operands, operandSegments, deleteOperands);
|
|
addOperands(operands, operandSegments, detachOperands);
|
|
|
|
auto exitDataOp = createSimpleOp<mlir::acc::ExitDataOp>(
|
|
firOpBuilder, currentLocation, operands, operandSegments);
|
|
|
|
if (addAsyncAttr)
|
|
exitDataOp.asyncAttr(firOpBuilder.getUnitAttr());
|
|
if (addWaitAttr)
|
|
exitDataOp.waitAttr(firOpBuilder.getUnitAttr());
|
|
if (addFinalizeAttr)
|
|
exitDataOp.finalizeAttr(firOpBuilder.getUnitAttr());
|
|
}
|
|
|
|
template <typename Op>
|
|
static void
|
|
genACCInitShutdownOp(Fortran::lower::AbstractConverter &converter,
|
|
const Fortran::parser::AccClauseList &accClauseList) {
|
|
mlir::Value ifCond, deviceNum;
|
|
SmallVector<Value, 2> deviceTypeOperands;
|
|
|
|
auto &firOpBuilder = converter.getFirOpBuilder();
|
|
auto currentLocation = converter.getCurrentLocation();
|
|
|
|
// Lower clauses values mapped to operands.
|
|
// Keep track of each group of operands separatly as clauses can appear
|
|
// more than once.
|
|
for (const auto &clause : accClauseList.v) {
|
|
if (const auto *ifClause =
|
|
std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
|
|
mlir::Value cond = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
|
|
ifCond = firOpBuilder.createConvert(currentLocation,
|
|
firOpBuilder.getI1Type(), cond);
|
|
} else if (const auto *deviceNumClause =
|
|
std::get_if<Fortran::parser::AccClause::DeviceNum>(
|
|
&clause.u)) {
|
|
deviceNum = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(deviceNumClause->v)));
|
|
} else if (const auto *deviceTypeClause =
|
|
std::get_if<Fortran::parser::AccClause::DeviceType>(
|
|
&clause.u)) {
|
|
|
|
const auto &deviceTypeValue = deviceTypeClause->v;
|
|
if (deviceTypeValue) {
|
|
for (const auto &scalarIntExpr : *deviceTypeValue) {
|
|
mlir::Value expr = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(scalarIntExpr)));
|
|
deviceTypeOperands.push_back(expr);
|
|
}
|
|
} else {
|
|
// * was passed as value and will be represented as a -1 constant
|
|
// integer.
|
|
mlir::Value star = firOpBuilder.createIntegerConstant(
|
|
currentLocation, firOpBuilder.getIntegerType(32), /* STAR */ -1);
|
|
deviceTypeOperands.push_back(star);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Prepare the operand segement size attribute and the operands value range.
|
|
SmallVector<mlir::Value, 6> operands;
|
|
SmallVector<int32_t, 3> operandSegments;
|
|
addOperands(operands, operandSegments, deviceTypeOperands);
|
|
addOperand(operands, operandSegments, deviceNum);
|
|
addOperand(operands, operandSegments, ifCond);
|
|
|
|
createSimpleOp<Op>(firOpBuilder, currentLocation, operands, operandSegments);
|
|
}
|
|
|
|
static void
|
|
genACCUpdateOp(Fortran::lower::AbstractConverter &converter,
|
|
const Fortran::parser::AccClauseList &accClauseList) {
|
|
mlir::Value ifCond, async, waitDevnum;
|
|
SmallVector<Value, 2> hostOperands, deviceOperands, waitOperands,
|
|
deviceTypeOperands;
|
|
|
|
// Async and wait clause have optional values but can be present with
|
|
// no value as well. When there is no value, the op has an attribute to
|
|
// represent the clause.
|
|
bool addAsyncAttr = false;
|
|
bool addWaitAttr = false;
|
|
bool addIfPresentAttr = false;
|
|
|
|
auto &firOpBuilder = converter.getFirOpBuilder();
|
|
auto currentLocation = converter.getCurrentLocation();
|
|
|
|
// Lower clauses values mapped to operands.
|
|
// Keep track of each group of operands separatly as clauses can appear
|
|
// more than once.
|
|
for (const auto &clause : accClauseList.v) {
|
|
if (const auto *ifClause =
|
|
std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
|
|
mlir::Value cond = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
|
|
ifCond = firOpBuilder.createConvert(currentLocation,
|
|
firOpBuilder.getI1Type(), cond);
|
|
} else if (const auto *asyncClause =
|
|
std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
|
|
const auto &asyncClauseValue = asyncClause->v;
|
|
if (asyncClauseValue) { // async has a value.
|
|
async = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*asyncClauseValue)));
|
|
} else {
|
|
addAsyncAttr = true;
|
|
}
|
|
} else if (const auto *waitClause =
|
|
std::get_if<Fortran::parser::AccClause::Wait>(&clause.u)) {
|
|
const auto &waitClauseValue = waitClause->v;
|
|
if (waitClauseValue) { // wait has a value.
|
|
const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
|
|
const std::list<Fortran::parser::ScalarIntExpr> &waitList =
|
|
std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
|
|
for (const Fortran::parser::ScalarIntExpr &value : waitList) {
|
|
mlir::Value v = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(value)));
|
|
waitOperands.push_back(v);
|
|
}
|
|
|
|
const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
|
|
std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
|
|
if (waitDevnumValue)
|
|
waitDevnum = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*waitDevnumValue)));
|
|
} else {
|
|
addWaitAttr = true;
|
|
}
|
|
} else if (const auto *deviceTypeClause =
|
|
std::get_if<Fortran::parser::AccClause::DeviceType>(
|
|
&clause.u)) {
|
|
|
|
const auto &deviceTypeValue = deviceTypeClause->v;
|
|
if (deviceTypeValue) {
|
|
for (const auto &scalarIntExpr : *deviceTypeValue) {
|
|
mlir::Value expr = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(scalarIntExpr)));
|
|
deviceTypeOperands.push_back(expr);
|
|
}
|
|
} else {
|
|
// * was passed as value and will be represented as a -1 constant
|
|
// integer.
|
|
mlir::Value star = firOpBuilder.createIntegerConstant(
|
|
currentLocation, firOpBuilder.getIntegerType(32), /* STAR */ -1);
|
|
deviceTypeOperands.push_back(star);
|
|
}
|
|
} else if (const auto *hostClause =
|
|
std::get_if<Fortran::parser::AccClause::Host>(&clause.u)) {
|
|
genObjectList(hostClause->v, converter, hostOperands);
|
|
} else if (const auto *deviceClause =
|
|
std::get_if<Fortran::parser::AccClause::Device>(&clause.u)) {
|
|
genObjectList(deviceClause->v, converter, deviceOperands);
|
|
}
|
|
}
|
|
|
|
// Prepare the operand segement size attribute and the operands value range.
|
|
SmallVector<mlir::Value, 14> operands;
|
|
SmallVector<int32_t, 7> operandSegments;
|
|
addOperand(operands, operandSegments, async);
|
|
addOperand(operands, operandSegments, waitDevnum);
|
|
addOperands(operands, operandSegments, waitOperands);
|
|
addOperands(operands, operandSegments, deviceTypeOperands);
|
|
addOperand(operands, operandSegments, ifCond);
|
|
addOperands(operands, operandSegments, hostOperands);
|
|
addOperands(operands, operandSegments, deviceOperands);
|
|
|
|
auto updateOp = createSimpleOp<mlir::acc::UpdateOp>(
|
|
firOpBuilder, currentLocation, operands, operandSegments);
|
|
|
|
if (addAsyncAttr)
|
|
updateOp.asyncAttr(firOpBuilder.getUnitAttr());
|
|
if (addWaitAttr)
|
|
updateOp.waitAttr(firOpBuilder.getUnitAttr());
|
|
if (addIfPresentAttr)
|
|
updateOp.ifPresentAttr(firOpBuilder.getUnitAttr());
|
|
}
|
|
|
|
static void
|
|
genACC(Fortran::lower::AbstractConverter &converter,
|
|
Fortran::lower::pft::Evaluation &eval,
|
|
const Fortran::parser::OpenACCStandaloneConstruct &standaloneConstruct) {
|
|
const auto &standaloneDirective =
|
|
std::get<Fortran::parser::AccStandaloneDirective>(standaloneConstruct.t);
|
|
const auto &accClauseList =
|
|
std::get<Fortran::parser::AccClauseList>(standaloneConstruct.t);
|
|
|
|
if (standaloneDirective.v == llvm::acc::Directive::ACCD_enter_data) {
|
|
genACCEnterDataOp(converter, accClauseList);
|
|
} else if (standaloneDirective.v == llvm::acc::Directive::ACCD_exit_data) {
|
|
genACCExitDataOp(converter, accClauseList);
|
|
} else if (standaloneDirective.v == llvm::acc::Directive::ACCD_init) {
|
|
genACCInitShutdownOp<mlir::acc::InitOp>(converter, accClauseList);
|
|
} else if (standaloneDirective.v == llvm::acc::Directive::ACCD_shutdown) {
|
|
genACCInitShutdownOp<mlir::acc::ShutdownOp>(converter, accClauseList);
|
|
} else if (standaloneDirective.v == llvm::acc::Directive::ACCD_set) {
|
|
TODO(converter.genLocation(), "OpenACC set directive not lowered yet!");
|
|
} else if (standaloneDirective.v == llvm::acc::Directive::ACCD_update) {
|
|
genACCUpdateOp(converter, accClauseList);
|
|
}
|
|
}
|
|
|
|
static void genACC(Fortran::lower::AbstractConverter &converter,
|
|
Fortran::lower::pft::Evaluation &eval,
|
|
const Fortran::parser::OpenACCWaitConstruct &waitConstruct) {
|
|
|
|
const auto &waitArgument =
|
|
std::get<std::optional<Fortran::parser::AccWaitArgument>>(
|
|
waitConstruct.t);
|
|
const auto &accClauseList =
|
|
std::get<Fortran::parser::AccClauseList>(waitConstruct.t);
|
|
|
|
mlir::Value ifCond, asyncOperand, waitDevnum, async;
|
|
SmallVector<mlir::Value, 2> waitOperands;
|
|
|
|
// Async clause have optional values but can be present with
|
|
// no value as well. When there is no value, the op has an attribute to
|
|
// represent the clause.
|
|
bool addAsyncAttr = false;
|
|
|
|
auto &firOpBuilder = converter.getFirOpBuilder();
|
|
auto currentLocation = converter.getCurrentLocation();
|
|
|
|
if (waitArgument) { // wait has a value.
|
|
const Fortran::parser::AccWaitArgument &waitArg = *waitArgument;
|
|
const std::list<Fortran::parser::ScalarIntExpr> &waitList =
|
|
std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t);
|
|
for (const Fortran::parser::ScalarIntExpr &value : waitList) {
|
|
mlir::Value v = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(value)));
|
|
waitOperands.push_back(v);
|
|
}
|
|
|
|
const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
|
|
std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t);
|
|
if (waitDevnumValue)
|
|
waitDevnum = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*waitDevnumValue)));
|
|
}
|
|
|
|
// Lower clauses values mapped to operands.
|
|
// Keep track of each group of operands separatly as clauses can appear
|
|
// more than once.
|
|
for (const auto &clause : accClauseList.v) {
|
|
if (const auto *ifClause =
|
|
std::get_if<Fortran::parser::AccClause::If>(&clause.u)) {
|
|
mlir::Value cond = fir::getBase(
|
|
converter.genExprValue(*Fortran::semantics::GetExpr(ifClause->v)));
|
|
ifCond = firOpBuilder.createConvert(currentLocation,
|
|
firOpBuilder.getI1Type(), cond);
|
|
} else if (const auto *asyncClause =
|
|
std::get_if<Fortran::parser::AccClause::Async>(&clause.u)) {
|
|
const auto &asyncClauseValue = asyncClause->v;
|
|
if (asyncClauseValue) { // async has a value.
|
|
async = fir::getBase(converter.genExprValue(
|
|
*Fortran::semantics::GetExpr(*asyncClauseValue)));
|
|
} else {
|
|
addAsyncAttr = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Prepare the operand segement size attribute and the operands value range.
|
|
SmallVector<mlir::Value, 8> operands;
|
|
SmallVector<int32_t, 4> operandSegments;
|
|
addOperands(operands, operandSegments, waitOperands);
|
|
addOperand(operands, operandSegments, async);
|
|
addOperand(operands, operandSegments, waitDevnum);
|
|
addOperand(operands, operandSegments, ifCond);
|
|
|
|
auto waitOp = createSimpleOp<mlir::acc::WaitOp>(firOpBuilder, currentLocation,
|
|
operands, operandSegments);
|
|
|
|
if (addAsyncAttr)
|
|
waitOp.asyncAttr(firOpBuilder.getUnitAttr());
|
|
}
|
|
|
|
void Fortran::lower::genOpenACCConstruct(
|
|
Fortran::lower::AbstractConverter &converter,
|
|
Fortran::lower::pft::Evaluation &eval,
|
|
const Fortran::parser::OpenACCConstruct &accConstruct) {
|
|
|
|
std::visit(
|
|
common::visitors{
|
|
[&](const Fortran::parser::OpenACCBlockConstruct &blockConstruct) {
|
|
genACC(converter, eval, blockConstruct);
|
|
},
|
|
[&](const Fortran::parser::OpenACCCombinedConstruct
|
|
&combinedConstruct) {
|
|
TODO(converter.genLocation(),
|
|
"OpenACC Combined construct not lowered yet!");
|
|
},
|
|
[&](const Fortran::parser::OpenACCLoopConstruct &loopConstruct) {
|
|
genACC(converter, eval, loopConstruct);
|
|
},
|
|
[&](const Fortran::parser::OpenACCStandaloneConstruct
|
|
&standaloneConstruct) {
|
|
genACC(converter, eval, standaloneConstruct);
|
|
},
|
|
[&](const Fortran::parser::OpenACCRoutineConstruct
|
|
&routineConstruct) {
|
|
TODO(converter.genLocation(),
|
|
"OpenACC Routine construct not lowered yet!");
|
|
},
|
|
[&](const Fortran::parser::OpenACCCacheConstruct &cacheConstruct) {
|
|
TODO(converter.genLocation(),
|
|
"OpenACC Cache construct not lowered yet!");
|
|
},
|
|
[&](const Fortran::parser::OpenACCWaitConstruct &waitConstruct) {
|
|
genACC(converter, eval, waitConstruct);
|
|
},
|
|
[&](const Fortran::parser::OpenACCAtomicConstruct &atomicConstruct) {
|
|
TODO(converter.genLocation(),
|
|
"OpenACC Atomic construct not lowered yet!");
|
|
},
|
|
},
|
|
accConstruct.u);
|
|
}
|