22#include "llvm/ADT/STLExtras.h"
23#include "llvm/ADT/STLFunctionalExtras.h"
33 ConversionPatternRewriter &rewriter) {
34 Type i64Ty = IntegerType::get(rewriter.getContext(), 64);
37 return arith::TruncIOp::create(rewriter, loc, i64Ty, value);
39 return arith::ExtSIOp::create(rewriter, loc, i64Ty, value);
43static Value getAsyncQueue(WaitOp op, ConversionPatternRewriter &rewriter,
46 Type i64Ty = IntegerType::get(rewriter.getContext(), 64);
48 return LLVM::ConstantOp::create(rewriter, loc, i64Ty,
50 if (
Value asyncValue = op.getAsyncOperand()) {
51 asyncValue = rewriter.getRemappedValue(asyncValue);
52 return castToI64(loc, asyncValue, rewriter);
54 return LLVM::ConstantOp::create(rewriter, loc, i64Ty,
59 ConversionPatternRewriter &rewriter,
61 Block *parentBlock = rewriter.getInsertionBlock();
62 Block *continueBlock =
63 rewriter.splitBlock(parentBlock, rewriter.getInsertionPoint());
64 Block *thenBlock = rewriter.createBlock(
67 rewriter.setInsertionPointToEnd(parentBlock);
68 LLVM::CondBrOp::create(rewriter, loc, ifCond, thenBlock,
ValueRange{},
71 rewriter.setInsertionPointToStart(thenBlock);
72 LogicalResult
result = thenFn();
73 rewriter.setInsertionPointToEnd(thenBlock);
74 LLVM::BrOp::create(rewriter, loc,
ValueRange{}, continueBlock);
75 rewriter.setInsertionPointToStart(continueBlock);
80static LogicalResult emitGuardedByIfCond(
Location loc,
Value ifCond,
81 ConversionPatternRewriter &rewriter,
84 return createIfThen(loc, ifCond, rewriter, emitFn);
88template <
typename OpTy>
90 ACCExecutableDirectivePattern(
const LLVMTypeConverter &converter,
91 const ACCRuntimeCallConfig &config,
92 PatternBenefit benefit = 1)
93 : ConvertOpToLLVMPattern<OpTy>(converter, benefit), config(config) {}
95 ACCRuntimeCallConfig config;
98struct WaitOpLowering :
public ACCExecutableDirectivePattern<WaitOp> {
99 using ACCExecutableDirectivePattern<WaitOp>::ACCExecutableDirectivePattern;
102 matchAndRewrite(WaitOp op, WaitOp::Adaptor,
103 ConversionPatternRewriter &rewriter)
const override {
104 Location loc = op->getLoc();
105 ModuleOp module = op->getParentOfType<ModuleOp>();
106 Type i32Ty = rewriter.getI32Type();
107 Type i64Ty = rewriter.getI64Type();
108 Type ptrTy = LLVM::LLVMPointerType::get(rewriter.getContext());
110 auto emitWait = [&]() -> LogicalResult {
111 Value asyncQueue = getAsyncQueue(op, rewriter, config);
112 SmallVector<Value> waitValues;
113 for (Value operand : op.getWaitOperands())
114 waitValues.push_back(
115 castToI64(loc, rewriter.getRemappedValue(operand), rewriter));
117 unsigned size = waitValues.size();
118 Value waitNum = LLVM::ConstantOp::create(rewriter, loc, i32Ty, size);
121 waitList = LLVM::ZeroOp::create(rewriter, loc, ptrTy);
123 waitList = LLVM::AllocaOp::create(rewriter, loc, ptrTy, i64Ty, waitNum);
124 for (
auto [index, waitValue] : llvm::enumerate(waitValues)) {
125 Value idx = LLVM::ConstantOp::create(rewriter, loc, i32Ty,
126 static_cast<int64_t
>(index));
127 Value elementPtr = LLVM::GEPOp::create(
128 rewriter, loc, ptrTy, i64Ty, waitList, ArrayRef<Value>{idx});
129 LLVM::StoreOp::create(rewriter, loc, waitValue, elementPtr);
134 if (functionName.empty())
136 Value ident =
createIdent(loc, functionName, rewriter, module, config);
137 Value flags = LLVM::ConstantOp::create(rewriter, loc, i64Ty, 0);
138 Value deviceType = LLVM::ConstantOp::create(
139 rewriter, loc, i64Ty,
141 Value deviceNum = LLVM::ConstantOp::create(rewriter, loc, i32Ty, 0);
144 loc, rewriter, module, RuntimeFunction::ACCRTL_tgt_acc_wait, config,
145 {ident, flags, deviceType, deviceNum, waitNum, waitList, asyncQueue});
148 if (
failed(emitGuardedByIfCond(loc, op.getIfCond(), rewriter, emitWait)))
151 rewriter.eraseOp(op);
161 Value deviceNum, StringRef functionName,
162 ModuleOp module, ConversionPatternRewriter &rewriter,
164 Type i64Ty = rewriter.getI64Type();
165 Value deviceTypeValue = LLVM::ConstantOp::create(
168 Value flags = LLVM::ConstantOp::create(rewriter, loc, i64Ty, 0);
169 Value deviceNumValue =
170 deviceNum ? castToI64(loc, deviceNum, rewriter)
171 :
LLVM::ConstantOp::create(rewriter, loc, i64Ty, -1);
173 {ident, flags, deviceTypeValue, deviceNumValue});
176static LogicalResult rewriteInitOrShutdown(
Operation *op,
Value deviceNum,
178 Value ifCond,
bool isInit,
179 ConversionPatternRewriter &rewriter,
184 auto emitCalls = [&]() -> LogicalResult {
188 : RuntimeFunction::ACCRTL_tgt_acc_shutdown;
190 auto emitOne = [&](DeviceType deviceType) {
191 return emitDeviceOperationCall(loc, fn, deviceType, deviceNum,
192 functionName, module, rewriter, config);
195 if (!deviceTypesAttr)
196 return emitOne(DeviceType::None);
199 if (
auto typeAttr = dyn_cast<DeviceTypeAttr>(attr))
200 if (
failed(emitOne(typeAttr.getValue())))
206 if (
failed(emitGuardedByIfCond(loc, ifCond, rewriter, emitCalls)))
209 rewriter.eraseOp(op);
213struct InitOpLowering :
public ACCExecutableDirectivePattern<InitOp> {
214 using ACCExecutableDirectivePattern<InitOp>::ACCExecutableDirectivePattern;
217 matchAndRewrite(InitOp op, InitOp::Adaptor adaptor,
218 ConversionPatternRewriter &rewriter)
const override {
219 return rewriteInitOrShutdown(op, adaptor.getDeviceNum(),
220 op.getDeviceTypesAttr(), op.getIfCond(),
221 true, rewriter, config);
225struct ShutdownOpLowering :
public ACCExecutableDirectivePattern<ShutdownOp> {
226 using ACCExecutableDirectivePattern<
227 ShutdownOp>::ACCExecutableDirectivePattern;
230 matchAndRewrite(ShutdownOp op, ShutdownOp::Adaptor adaptor,
231 ConversionPatternRewriter &rewriter)
const override {
232 return rewriteInitOrShutdown(op, adaptor.getDeviceNum(),
233 op.getDeviceTypesAttr(), op.getIfCond(),
234 false, rewriter, config);
238struct SetOpLowering :
public ACCExecutableDirectivePattern<SetOp> {
239 using ACCExecutableDirectivePattern<SetOp>::ACCExecutableDirectivePattern;
242 matchAndRewrite(SetOp op, SetOp::Adaptor adaptor,
243 ConversionPatternRewriter &rewriter)
const override {
244 ModuleOp module = op->getParentOfType<ModuleOp>();
245 Location loc = op.getLoc();
246 Type i64Ty = rewriter.getI64Type();
248 auto emitSet = [&]() -> LogicalResult {
249 if (Value asyncValue = adaptor.getDefaultAsync()) {
250 asyncValue = castToI64(loc, asyncValue, rewriter);
252 rewriter, module, config);
254 loc, rewriter, module,
255 RuntimeFunction::ACCRTL_tgt_acc_set_default_async, config,
256 {ident, asyncValue})))
260 if (op.getDeviceNum()) {
261 Value deviceNum = adaptor.getDeviceNum();
262 DeviceType deviceType = DeviceType::None;
263 if (
auto deviceTypeAttr = op.getDeviceTypeAttr())
264 deviceType = deviceTypeAttr.getValue();
265 return emitDeviceOperationCall(
266 loc, RuntimeFunction::ACCRTL_tgt_acc_set_device_num, deviceType,
270 if (
auto deviceTypeAttr = op.getDeviceTypeAttr()) {
271 Value deviceTypeValue = LLVM::ConstantOp::create(
272 rewriter, loc, i64Ty,
274 Value ident =
createIdent(loc, StringRef(), rewriter, module, config);
275 Value flags = LLVM::ConstantOp::create(rewriter, loc, i64Ty, 0);
277 loc, rewriter, module,
278 RuntimeFunction::ACCRTL_tgt_acc_set_device_type, config,
279 {ident, flags, deviceTypeValue});
284 if (
failed(emitGuardedByIfCond(loc, op.getIfCond(), rewriter, emitSet)))
287 rewriter.eraseOp(op);
296 target.addIllegalOp<acc::InitOp, acc::ShutdownOp, acc::WaitOp, acc::SetOp>();
303 .
add<WaitOpLowering, InitOpLowering, ShutdownOpLowering, SetOpLowering>(
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
Conversion from types to the LLVM IR dialect.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Operation is the basic unit of execution within MLIR.
Location getLoc()
The source location the operation was defined or derived from.
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
BlockListType::iterator iterator
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Optional overrides for OpenACC to LLVM runtime lowering.
int64_t getAsyncNoValueRuntimeValue() const
int64_t getAsyncSyncRuntimeValue() const
int64_t getDeviceTypeRuntimeValue(DeviceType type) const
FailureOr< LLVM::CallOp > createRuntimeCall(Location loc, OpBuilder &builder, ModuleOp module, RuntimeFunction fn, const ACCRuntimeCallConfig &config, ArrayRef< Value > arguments)
Declares (if needed) and returns a call to the runtime function identified by fn using the name from ...
RuntimeFunction
IDs for OpenACC compiler-to-runtime entry points (__tgt_acc_*).
Value createIdent(Location loc, StringRef functionName, OpBuilder &builder, ModuleOp module, const ACCRuntimeCallConfig &config)
Returns a pointer to a constant global holding an ident_t for OpenACC runtime calls.
StringRef getParentFunctionName(Operation *op)
Returns the enclosing function symbol name for op.
Include the generated interface declarations.
void configureACCExecutableDirectiveConversionLegality(ConversionTarget &target)
Configure conversion legality for OpenACC executable directives lowered to runtime calls.
void populateACCExecutableDirectivePatterns(LLVMTypeConverter &converter, RewritePatternSet &patterns, const acc::ACCRuntimeCallConfig &config={})
Populate patterns that lower OpenACC executable directives (init, shutdown, wait, set) to LLVM runtim...
llvm::function_ref< Fn > function_ref