
The private clause is the first with 'recipes', so a lot of infrastructure is included here, including some MLIR dialect changes that allow simple adding of a privatization. We'll likely get similar for firstprivate and reduction. Also, we have quite a bit of infrastructure in clause lowering to make sure we have most cases we could think of covered. At the moment, ONLY private is implemented, so all it requires is an 'init' segment (that doesn't call any copy operations), and potentially a 'destroy' segment. However, actually calling 'init' functions on each of the elements in them are not properly implemented, and will be in a followup patch. This patch implements all of that, and adds tests in a way that will be useful for firstprivate as well.
132 lines
5.2 KiB
C++
132 lines
5.2 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Generic OpenACC lowering functions not Stmt, Decl, or clause specific.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CIRGenFunction.h"
|
|
#include "mlir/Dialect/Arith/IR/Arith.h"
|
|
#include "mlir/Dialect/OpenACC/OpenACC.h"
|
|
#include "clang/AST/ExprCXX.h"
|
|
|
|
using namespace clang;
|
|
using namespace clang::CIRGen;
|
|
|
|
namespace {
|
|
mlir::Value createBound(CIRGenFunction &cgf, CIRGen::CIRGenBuilderTy &builder,
|
|
mlir::Location boundLoc, mlir::Value lowerBound,
|
|
mlir::Value upperBound, mlir::Value extent) {
|
|
// Arrays always have a start-idx of 0.
|
|
mlir::Value startIdx = cgf.createOpenACCConstantInt(boundLoc, 64, 0);
|
|
// Stride is always 1 in C/C++.
|
|
mlir::Value stride = cgf.createOpenACCConstantInt(boundLoc, 64, 1);
|
|
|
|
auto bound =
|
|
builder.create<mlir::acc::DataBoundsOp>(boundLoc, lowerBound, upperBound);
|
|
bound.getStartIdxMutable().assign(startIdx);
|
|
if (extent)
|
|
bound.getExtentMutable().assign(extent);
|
|
bound.getStrideMutable().assign(stride);
|
|
|
|
return bound;
|
|
}
|
|
} // namespace
|
|
|
|
mlir::Value CIRGenFunction::emitOpenACCIntExpr(const Expr *intExpr) {
|
|
mlir::Value expr = emitScalarExpr(intExpr);
|
|
mlir::Location exprLoc = cgm.getLoc(intExpr->getBeginLoc());
|
|
|
|
mlir::IntegerType targetType = mlir::IntegerType::get(
|
|
&getMLIRContext(), getContext().getIntWidth(intExpr->getType()),
|
|
intExpr->getType()->isSignedIntegerOrEnumerationType()
|
|
? mlir::IntegerType::SignednessSemantics::Signed
|
|
: mlir::IntegerType::SignednessSemantics::Unsigned);
|
|
|
|
auto conversionOp = builder.create<mlir::UnrealizedConversionCastOp>(
|
|
exprLoc, targetType, expr);
|
|
return conversionOp.getResult(0);
|
|
}
|
|
|
|
mlir::Value CIRGenFunction::createOpenACCConstantInt(mlir::Location loc,
|
|
unsigned width,
|
|
int64_t value) {
|
|
mlir::IntegerType ty =
|
|
mlir::IntegerType::get(&getMLIRContext(), width,
|
|
mlir::IntegerType::SignednessSemantics::Signless);
|
|
auto constOp = builder.create<mlir::arith::ConstantOp>(
|
|
loc, builder.getIntegerAttr(ty, value));
|
|
|
|
return constOp.getResult();
|
|
}
|
|
|
|
CIRGenFunction::OpenACCDataOperandInfo
|
|
CIRGenFunction::getOpenACCDataOperandInfo(const Expr *e) {
|
|
const Expr *curVarExpr = e->IgnoreParenImpCasts();
|
|
|
|
mlir::Location exprLoc = cgm.getLoc(curVarExpr->getBeginLoc());
|
|
llvm::SmallVector<mlir::Value> bounds;
|
|
|
|
std::string exprString;
|
|
llvm::raw_string_ostream os(exprString);
|
|
e->printPretty(os, nullptr, getContext().getPrintingPolicy());
|
|
|
|
while (isa<ArraySectionExpr, ArraySubscriptExpr>(curVarExpr)) {
|
|
mlir::Location boundLoc = cgm.getLoc(curVarExpr->getBeginLoc());
|
|
mlir::Value lowerBound;
|
|
mlir::Value upperBound;
|
|
mlir::Value extent;
|
|
|
|
if (const auto *section = dyn_cast<ArraySectionExpr>(curVarExpr)) {
|
|
if (const Expr *lb = section->getLowerBound())
|
|
lowerBound = emitOpenACCIntExpr(lb);
|
|
else
|
|
lowerBound = createOpenACCConstantInt(boundLoc, 64, 0);
|
|
|
|
if (const Expr *len = section->getLength()) {
|
|
extent = emitOpenACCIntExpr(len);
|
|
} else {
|
|
QualType baseTy = ArraySectionExpr::getBaseOriginalType(
|
|
section->getBase()->IgnoreParenImpCasts());
|
|
// We know this is the case as implicit lengths are only allowed for
|
|
// array types with a constant size, or a dependent size. AND since
|
|
// we are codegen we know we're not dependent.
|
|
auto *arrayTy = getContext().getAsConstantArrayType(baseTy);
|
|
// Rather than trying to calculate the extent based on the
|
|
// lower-bound, we can just emit this as an upper bound.
|
|
upperBound = createOpenACCConstantInt(boundLoc, 64,
|
|
arrayTy->getLimitedSize() - 1);
|
|
}
|
|
|
|
curVarExpr = section->getBase()->IgnoreParenImpCasts();
|
|
} else {
|
|
const auto *subscript = cast<ArraySubscriptExpr>(curVarExpr);
|
|
|
|
lowerBound = emitOpenACCIntExpr(subscript->getIdx());
|
|
// Length of an array index is always 1.
|
|
extent = createOpenACCConstantInt(boundLoc, 64, 1);
|
|
curVarExpr = subscript->getBase()->IgnoreParenImpCasts();
|
|
}
|
|
|
|
bounds.push_back(createBound(*this, this->builder, boundLoc, lowerBound,
|
|
upperBound, extent));
|
|
}
|
|
|
|
if (const auto *memExpr = dyn_cast<MemberExpr>(curVarExpr))
|
|
return {exprLoc, emitMemberExpr(memExpr).getPointer(), exprString,
|
|
curVarExpr->getType(), std::move(bounds)};
|
|
|
|
// Sema has made sure that only 4 types of things can get here, array
|
|
// subscript, array section, member expr, or DRE to a var decl (or the
|
|
// former 3 wrapping a var-decl), so we should be able to assume this is
|
|
// right.
|
|
const auto *dre = cast<DeclRefExpr>(curVarExpr);
|
|
return {exprLoc, emitDeclRefLValue(dre).getPointer(), exprString,
|
|
curVarExpr->getType(), std::move(bounds)};
|
|
}
|