25#include "llvm/ADT/TypeSwitch.h"
26#include "llvm/Support/Debug.h"
33#define DEBUG_TYPE "acc-atomic-patterns"
42template <
typename AtomicOpTy>
51 accSupport(accSupport), getLoadAddress(getLoadAddress) {}
54 matchAndRewrite(AtomicOpTy op, OpAdaptor adaptor,
55 ConversionPatternRewriter &rewriter)
const override;
61 size_t getComplexStructElementSizeInBits(
Type ty)
const {
62 auto structType = dyn_cast<LLVM::LLVMStructType>(ty);
63 if (!structType || structType.getBody().size() != 2 ||
64 structType.getBody()[0] != structType.getBody()[1] ||
65 !structType.getBody()[0].isIntOrFloat())
67 size_t elementSizeInBits = structType.getBody()[0].getIntOrFloatBitWidth();
68 if (elementSizeInBits == 0 || elementSizeInBits > 64)
69 llvm_unreachable(
"unexpected complex type");
70 return elementSizeInBits;
74 Value serializeExpr(
Value expr, ConversionPatternRewriter &rewriter)
const {
75 size_t elementSizeInBits =
76 getComplexStructElementSizeInBits(expr.
getType());
77 if (!elementSizeInBits)
81 Value firstValue = LLVM::ExtractValueOp::create(rewriter, loc, expr, 0);
82 Value secondValue = LLVM::ExtractValueOp::create(rewriter, loc, expr, 1);
84 Type intCastTy = IntegerType::get(context, elementSizeInBits);
85 Type intTy = IntegerType::get(context, elementSizeInBits * 2);
86 firstValue = LLVM::BitcastOp::create(rewriter, loc, intCastTy, firstValue);
88 LLVM::BitcastOp::create(rewriter, loc, intCastTy, secondValue);
89 firstValue = LLVM::ZExtOp::create(rewriter, loc, intTy, firstValue);
90 secondValue = LLVM::ZExtOp::create(rewriter, loc, intTy, secondValue);
92 LLVM::ConstantOp::create(rewriter, loc, intTy, elementSizeInBits);
93 Value result = LLVM::ShlOp::create(rewriter, loc, secondValue, shlVal);
94 return LLVM::OrOp::create(rewriter, loc,
result, firstValue);
99 ConversionPatternRewriter &rewriter)
const {
100 size_t elementSizeInBits = getComplexStructElementSizeInBits(origTy);
101 if (!elementSizeInBits)
104 auto intTy = dyn_cast<IntegerType>(expr.
getType());
105 if (!intTy || intTy.getWidth() != elementSizeInBits * 2)
110 Type elemTy = IntegerType::get(context, elementSizeInBits);
111 Value low = LLVM::TruncOp::create(rewriter, loc, elemTy, expr);
113 LLVM::ConstantOp::create(rewriter, loc, intTy, elementSizeInBits);
114 Value highFull = LLVM::LShrOp::create(rewriter, loc, expr, shiftAmount);
115 Value high = LLVM::TruncOp::create(rewriter, loc, elemTy, highFull);
116 Type origElemTy = cast<LLVM::LLVMStructType>(origTy).getBody()[0];
117 if (origElemTy != elemTy) {
118 low = LLVM::BitcastOp::create(rewriter, loc, origElemTy, low);
119 high = LLVM::BitcastOp::create(rewriter, loc, origElemTy, high);
121 Value undefStruct = LLVM::UndefOp::create(rewriter, loc, origTy);
122 Value structWithLow = LLVM::InsertValueOp::create(
124 return LLVM::InsertValueOp::create(rewriter, loc, origTy, structWithLow,
128 uint64_t getAtomicSizeInBytes(
Type originalTy,
Type convertedTy,
129 ModuleOp module)
const {
130 std::optional<TypeSizeAndAlignment> sizeAndAlignment =
132 if (!sizeAndAlignment)
135 assert(sizeAndAlignment &&
"atomic type size is not computable");
136 return sizeAndAlignment->first.getFixedValue();
139 Type getAtomicType(
Type originalTy,
Type convertedTy, ModuleOp module)
const {
142 return IntegerType::get(
144 getAtomicSizeInBytes(originalTy, convertedTy, module) *
kBitsInByte);
147 Type getReferencedElementType(
Value ref, ModuleOp module =
nullptr)
const {
148 auto ptr = dyn_cast<PointerLikeType>(ref.
getType());
150 llvm_unreachable(
"unexpected type");
151 Type elementTy =
ptr.getElementType();
152 Type convertedTy = this->getTypeConverter()->convertType(elementTy);
154 return getAtomicType(elementTy, convertedTy, module);
161 ConversionPatternRewriter &rewriter)
const {
162 auto memrefTy = dyn_cast<MemRefType>(originalRef.
getType());
168 LLVM::ExtractValueOp::create(rewriter, loc, convertedPtr, 1);
169 Value offset = LLVM::ExtractValueOp::create(rewriter, loc, convertedPtr, 2);
170 Type elemPtrType = LLVM::LLVMPointerType::get(rewriter.getContext());
171 return LLVM::GEPOp::create(
172 rewriter, loc, elemPtrType,
173 this->getTypeConverter()->convertType(memrefTy.getElementType()),
178 ConversionPatternRewriter &rewriter)
const;
180 Value genUpdateCmpxchgLoop(AtomicUpdateOp update,
181 ConversionPatternRewriter &rewriter)
const;
185LogicalResult ACCAtomicOpConversion<AtomicReadOp>::matchAndRewrite(
186 AtomicReadOp read, OpAdaptor adaptor,
187 ConversionPatternRewriter &rewriter)
const {
189 Value xRef = read.getX();
190 Value xPtr = getAtomicPointer(xRef, adaptor.getX(), loc, rewriter);
191 ModuleOp mod = read->getParentOfType<ModuleOp>();
192 Type xType = getReferencedElementType(xRef, mod);
194 auto ordering = LLVM::AtomicOrdering::monotonic;
196 if (xType.isSignlessInteger()) {
197 Value zero = LLVM::ConstantOp::create(rewriter, loc, xType, 0);
198 storeVal = LLVM::AtomicRMWOp::create(rewriter, loc, LLVM::AtomicBinOp::_or,
199 xPtr, zero, ordering);
201 unsigned bitWidth = xType.getIntOrFloatBitWidth();
202 Type intType = IntegerType::get(rewriter.getContext(), bitWidth);
203 Value zero = LLVM::ConstantOp::create(rewriter, loc, intType, 0);
204 Value intVal = LLVM::AtomicRMWOp::create(
205 rewriter, loc, LLVM::AtomicBinOp::_or, xPtr, zero, ordering);
206 storeVal = LLVM::BitcastOp::create(rewriter, loc, xType, intVal);
209 Value vRef = read.getV();
210 Value vPtr = getAtomicPointer(vRef, adaptor.getV(), loc, rewriter);
211 Type vType = getReferencedElementType(vRef, mod);
213 if (xType != vType) {
215 auto vPtrType = cast<PointerLikeType>(vRef.
getType());
216 storeVal = vPtrType.genCast(rewriter, loc, storeVal, vType);
218 return rewriter.notifyMatchFailure(
219 read,
"failed to convert the loaded value to the destination type");
222 auto storeOp = LLVM::StoreOp::create(rewriter, loc, storeVal, vPtr);
223 rewriter.replaceOp(read, storeOp);
228LogicalResult ACCAtomicOpConversion<AtomicWriteOp>::matchAndRewrite(
229 AtomicWriteOp write, OpAdaptor adaptor,
230 ConversionPatternRewriter &rewriter)
const {
232 Value expr = serializeExpr(adaptor.getExpr(), rewriter);
233 Value xRef = write.getX();
234 Value xPtr = getAtomicPointer(xRef, adaptor.getX(), loc, rewriter);
235 ModuleOp mod = write->getParentOfType<ModuleOp>();
236 Type xType = getReferencedElementType(xRef, mod);
238 auto ordering = LLVM::AtomicOrdering::monotonic;
239 if (!xType.isSignlessInteger()) {
240 unsigned bitWidth = xType.getIntOrFloatBitWidth();
241 Type intType = IntegerType::get(rewriter.getContext(), bitWidth);
242 expr = LLVM::BitcastOp::create(rewriter, loc, intType, expr);
244 LLVM::AtomicRMWOp::create(rewriter, loc, LLVM::AtomicBinOp::xchg, xPtr, expr,
246 rewriter.eraseOp(write);
251template <
typename AtomicOpTy>
252Block *ACCAtomicOpConversion<AtomicOpTy>::constructCmpxchgLoop(
254 ConversionPatternRewriter &rewriter)
const {
256 Location loc = rewriter.getInsertionPoint()->getLoc();
257 Block *initBlock = rewriter.getInsertionBlock();
259 rewriter.splitBlock(initBlock, rewriter.getInsertionPoint());
262 rewriter.splitBlock(loopBlock, rewriter.getInsertionPoint());
265 rewriter.setInsertionPointToEnd(initBlock);
266 Value init = LLVM::LoadOp::create(rewriter, loc, type,
ptr);
267 LLVM::BrOp::create(rewriter, loc, init, loopBlock);
270 rewriter.setInsertionPointToStart(loopBlock);
273 Value result = serializeExpr(rewriter.getRemappedValue(expr), rewriter);
275 Type convertedExprType =
276 this->getTypeConverter()->convertType(expr.
getType());
277 Type exprType = getAtomicType(expr.
getType(), convertedExprType, mod);
281 Type tmpType = IntegerType::get(
282 rewriter.getContext(),
283 getAtomicSizeInBytes(expr.
getType(), convertedExprType, mod) *
285 result = LLVM::BitcastOp::create(rewriter, loc, tmpType,
result);
287 LLVM::BitcastOp::create(rewriter, loc, tmpType, loopArgument);
292 auto successOrdering = LLVM::AtomicOrdering::acq_rel;
293 auto failureOrdering = LLVM::AtomicOrdering::monotonic;
295 LLVM::AtomicCmpXchgOp::create(rewriter, loc,
ptr, loopArgument,
result,
296 successOrdering, failureOrdering);
298 Value newLoaded = LLVM::ExtractValueOp::create(rewriter, loc, cmpxchg, 0);
299 Value ok = LLVM::ExtractValueOp::create(rewriter, loc, cmpxchg, 1);
303 newLoaded = LLVM::BitcastOp::create(rewriter, loc, exprType, newLoaded);
307 loopBlock, newLoaded);
312static Value skipUnrealizedConversionOp(
Value v) {
314 dyn_cast_or_null<UnrealizedConversionCastOp>(v.
getDefiningOp()))
315 return skipUnrealizedConversionOp(convOp.getOperand(0));
320static Value getBaseStorage(
Value addr, ConversionPatternRewriter &rewriter) {
321 Operation *op = skipUnrealizedConversionOp(addr).getDefiningOp();
322 if (
auto gepOp = dyn_cast_or_null<LLVM::GEPOp>(op)) {
323 addr = gepOp.getBase();
326 if (
auto extractOp = dyn_cast_or_null<LLVM::ExtractValueOp>(op)) {
329 ArrayRef extractingPosition = extractOp.getPosition();
330 Value container = skipUnrealizedConversionOp(extractOp.getContainer());
331 Value remappedContainer = rewriter.getRemappedValue(container);
332 op = remappedContainer ? remappedContainer.
getDefiningOp() :
nullptr;
334 while (
auto insertValueOp = dyn_cast_or_null<LLVM::InsertValueOp>(op)) {
335 ArrayRef insertingPosition = insertValueOp.getPosition();
336 if (insertingPosition == extractingPosition) {
337 addr = insertValueOp.getValue();
341 op = insertValueOp.getContainer().getDefiningOp();
349 return skipUnrealizedConversionOp(addr);
356 ConversionPatternRewriter &rewriter,
358 Value vStorage = getBaseStorage(vPtr, rewriter);
361 Value vStorageRef = skipUnrealizedConversionOp(vRef);
363 llvm::dbgs() <<
"[acc-atomic] moveDependency\n";
364 llvm::dbgs() <<
" vPtr = " << vPtr <<
"\n";
365 llvm::dbgs() <<
" vStorage = " << vStorage <<
"\n";
366 llvm::dbgs() <<
" vStorageRef = " << vStorageRef <<
"\n";
367 llvm::dbgs() <<
" expr = " << expr <<
"\n";
370 std::set<std::pair<Operation *, std::set<Operation *>>> worklist;
371 std::set<Operation *> included;
372 Value mappedExpr = rewriter.getRemappedValue(expr);
373 remappedToOriginal[mappedExpr] = expr;
375 worklist.insert(std::pair{exprDef, std::set<Operation *>{}});
377 while (!worklist.empty()) {
378 auto [dep, post] = worklist.extract(worklist.begin()).value();
381 LLVM_DEBUG(llvm::dbgs() <<
" visit dep = " << *dep <<
"\n");
385 LLVM_DEBUG(llvm::dbgs() <<
" -> skipped: not in parental region\n");
390 if (
auto load = dyn_cast<LLVM::LoadOp>(dep)) {
391 addr =
load.getAddr();
392 }
else if (
auto load = dyn_cast<memref::LoadOp>(dep)) {
393 addr =
load.getMemref();
394 }
else if (getLoadAddress) {
395 addr = getLoadAddress(dep);
398 Value baseStorage = getBaseStorage(addr, rewriter);
400 llvm::dbgs() <<
" addr = " << addr <<
"\n";
401 llvm::dbgs() <<
" baseStorage = " << baseStorage <<
"\n";
402 llvm::dbgs() <<
" remapped = "
403 << rewriter.getRemappedValue(baseStorage) <<
"\n";
404 llvm::dbgs() <<
" matchRef=" << (baseStorage == vStorageRef)
406 << (rewriter.getRemappedValue(baseStorage) == vStorage)
409 if (baseStorage == vStorageRef ||
410 rewriter.getRemappedValue(baseStorage) == vStorage) {
414 rewriter.modifyOpInPlace(op, [&] {
415 op->replaceUsesOfWith(remappedToOriginal[
load], loopArgument);
420 replaceUses(&loopHead);
421 included.insert(post.begin(), post.end());
426 for (
Value operand : dep->getOperands()) {
427 Value mappedOperand = rewriter.getRemappedValue(operand);
430 if (
auto *op = operand.getDefiningOp()) {
431 remappedToOriginal[op->getResult(0)] = operand;
432 worklist.insert(std::pair{op, post});
435 remappedToOriginal[mappedOperand] = operand;
436 worklist.insert(std::pair{d, post});
445 if (included.find(op) != included.end())
446 includedInOrder.push_back(op);
449 d->moveBefore(&loopHead);
453template <
typename AtomicOpTy>
454Value ACCAtomicOpConversion<AtomicOpTy>::genUpdateCmpxchgLoop(
455 AtomicUpdateOp update, ConversionPatternRewriter &rewriter)
const {
457 Value xRef = update.getX();
459 getAtomicPointer(xRef, rewriter.getRemappedValue(xRef), loc, rewriter);
460 ModuleOp mod = update->getParentOfType<ModuleOp>();
461 Type xType = getReferencedElementType(xRef, mod);
462 Type xTypeOrig = getReferencedElementType(xRef);
464 Block &updateBlock = update.getRegion().
front();
469 Block *loopBlock = constructCmpxchgLoop(xPtr, xType, expr, rewriter);
473 rewriter.setInsertionPointToStart(loopBlock);
474 loopArgument = deserializeExpr(loopArgument, xTypeOrig, rewriter);
478 moveDependency(xRef, xPtr, expr, loopArgument, loopHead, rewriter,
481 rewriter.replaceAllUsesWith(cast<BlockArgument>(updateArgument),
486 rewriter.moveOpBefore(op, &loopHead);
489 if (
auto cmpxchg = dyn_cast<LLVM::AtomicCmpXchgOp>(loopHead))
490 return cmpxchg.getVal();
491 if (
auto bitcast = dyn_cast<LLVM::BitcastOp>(loopHead))
493 return bitcast.getArg();
494 if (
auto extract = dyn_cast<LLVM::ExtractValueOp>(loopHead))
496 return extract.getContainer();
497 llvm_unreachable(
"invalid cmpxchg loop");
502LogicalResult ACCAtomicOpConversion<AtomicUpdateOp>::matchAndRewrite(
503 AtomicUpdateOp update, OpAdaptor adaptor,
504 ConversionPatternRewriter &rewriter)
const {
505 Block &updateBlock = update.getRegion().
front();
509 std::set<Operation *> dependents;
511 worklist.push_back(updateArgument);
512 while (!worklist.empty()) {
513 Value value = worklist.back();
517 dependents.insert(useOp);
526 if (dependents.find(&op) == dependents.end()) {
528 llvm_unreachable(
"invalid update operation");
529 independent.push_back(&op);
533 rewriter.moveOpBefore(op, update);
552 auto getAtomicBinOp =
553 [](
Operation *op,
bool updateIsLhs) -> std::optional<LLVM::AtomicBinOp> {
555 .Case<arith::AddFOp>([](
auto) {
return LLVM::AtomicBinOp::fadd; })
556 .Case<arith::AddIOp>([](
auto) {
return LLVM::AtomicBinOp::add; })
557 .Case<arith::SubFOp>(
558 [updateIsLhs](
auto) -> std::optional<LLVM::AtomicBinOp> {
562 return LLVM::AtomicBinOp::fsub;
564 .Case<arith::SubIOp>(
565 [updateIsLhs](
auto) -> std::optional<LLVM::AtomicBinOp> {
569 return LLVM::AtomicBinOp::sub;
571 .Case<arith::AndIOp>([](
auto) {
return LLVM::AtomicBinOp::_and; })
572 .Case<arith::OrIOp>([](
auto) {
return LLVM::AtomicBinOp::_or; })
573 .Case<arith::XOrIOp>([](
auto) {
return LLVM::AtomicBinOp::_xor; })
574 .Case<arith::MaxSIOp>([](
auto) {
return LLVM::AtomicBinOp::max; })
575 .Case<arith::MinSIOp>([](
auto) {
return LLVM::AtomicBinOp::min; })
576 .Case<arith::MaxUIOp>([](
auto) {
return LLVM::AtomicBinOp::umax; })
577 .Case<arith::MinUIOp>([](
auto) {
return LLVM::AtomicBinOp::umin; })
578 .Case<arith::MaximumFOp>(
579 [](
auto) {
return LLVM::AtomicBinOp::fmaximum; })
580 .Case<arith::MinimumFOp>(
581 [](
auto) {
return LLVM::AtomicBinOp::fminimum; })
582 .Case<arith::MaxNumFOp>(
583 [](
auto) {
return LLVM::AtomicBinOp::fmaximumnum; })
584 .Case<arith::MinNumFOp>(
585 [](
auto) {
return LLVM::AtomicBinOp::fminimumnum; })
586 .Default([](
Operation *) {
return std::nullopt; });
590 std::optional<Value> val = std::nullopt;
591 std::optional<LLVM::AtomicBinOp> kind = std::nullopt;
598 bool updateIsLhs = firstOp.
getOperand(0) == updateArgument;
599 kind = getAtomicBinOp(&firstOp, updateIsLhs);
601 val = firstOp.
getOperand(updateIsLhs ? 1 : 0);
607 struct ComponentAtomic {
608 LLVM::AtomicBinOp kind;
615 Type convertedArgTy =
616 this->getTypeConverter()->convertType(updateArgument.
getType());
617 if (
auto structTy = dyn_cast<LLVM::LLVMStructType>(convertedArgTy)) {
618 if (structTy.getBody().size() == 2 &&
619 structTy.getBody()[0] == structTy.getBody()[1] &&
620 structTy.getBody()[0].isIntOrFloat() &&
621 structTy.getBody()[0].getIntOrFloatBitWidth() > 32) {
625 int32_t fieldIdx = -1;
626 Value externalVal =
nullptr;
627 bool updateIsLhs =
false;
628 for (
unsigned i = 0; i < 2; ++i) {
631 if (reOp.getOperand() == updateArgument) {
634 updateIsLhs = i == 0;
636 }
else if (
auto imOp = operand.
getDefiningOp<complex::ImOp>()) {
637 if (imOp.getOperand() == updateArgument) {
640 updateIsLhs = i == 0;
646 auto componentKind = getAtomicBinOp(&op, updateIsLhs);
649 componentAtomics.push_back({*componentKind, externalVal, fieldIdx});
656 Value xPtr = getAtomicPointer(update.getX(), adaptor.getX(), loc, rewriter);
660 bool hasDistinctComplexLanes =
false;
661 if (componentAtomics.size() == 2) {
663 for (
const ComponentAtomic &ca : componentAtomics) {
664 if (ca.fieldIdx == 0 || ca.fieldIdx == 1)
665 lanes |= 1u << ca.fieldIdx;
667 hasDistinctComplexLanes = lanes == 0b11;
671 auto ordering = LLVM::AtomicOrdering::monotonic;
672 LLVM::AtomicRMWOp::create(rewriter, loc, *kind, xPtr,
673 rewriter.getRemappedValue(*val), ordering);
674 }
else if (hasDistinctComplexLanes) {
675 auto structTy = cast<LLVM::LLVMStructType>(
676 this->getTypeConverter()->convertType(updateArgument.
getType()));
677 Type ptrType = LLVM::LLVMPointerType::get(rewriter.getContext());
678 auto ordering = LLVM::AtomicOrdering::monotonic;
679 for (ComponentAtomic &ca : componentAtomics) {
681 LLVM::GEPOp::create(rewriter, loc, ptrType, structTy, xPtr,
683 LLVM::AtomicRMWOp::create(rewriter, loc, ca.kind, elemPtr,
684 rewriter.getRemappedValue(ca.val), ordering);
688 genUpdateCmpxchgLoop(update, rewriter);
690 rewriter.eraseOp(update);
696LogicalResult ACCAtomicOpConversion<AtomicCaptureOp>::matchAndRewrite(
697 AtomicCaptureOp capture, OpAdaptor ,
698 ConversionPatternRewriter &rewriter)
const {
699 Operation *firstOp = capture.getFirstOp();
700 Operation *secondOp = capture.getSecondOp();
701 Value vPtr =
nullptr;
702 Value storeVal =
nullptr;
703 if (
auto firstReadStmt = dyn_cast<AtomicReadOp>(firstOp)) {
705 Value xRef = firstReadStmt.getX();
707 getAtomicPointer(xRef, rewriter.getRemappedValue(xRef), loc, rewriter);
708 ModuleOp mod = capture->getParentOfType<ModuleOp>();
709 Type xType = getReferencedElementType(xRef, mod);
710 Type xTypeOrig = getReferencedElementType(xRef);
711 Value vRef = firstReadStmt.getV();
713 getAtomicPointer(vRef, rewriter.getRemappedValue(vRef), loc, rewriter);
715 Value expr =
nullptr;
716 if (
auto secondWriteStmt = dyn_cast<AtomicWriteOp>(secondOp)) {
718 expr = secondWriteStmt.getExpr();
719 }
else if (
auto secondUpdateStmt = dyn_cast<AtomicUpdateOp>(secondOp)) {
721 Block &updateBlock = secondUpdateStmt.getRegion().
front();
726 Block *loopBlock = constructCmpxchgLoop(xPtr, xType, expr, rewriter);
729 auto condBr = cast<LLVM::CondBrOp>(loopBlock->
back());
730 storeVal = condBr.getFalseDestOperands()[0];
732 rewriter.setInsertionPointToStart(loopBlock);
733 loopArgument = deserializeExpr(loopArgument, xTypeOrig, rewriter);
736 if (
auto secondUpdateStmt = dyn_cast<AtomicUpdateOp>(secondOp)) {
737 Block &updateBlock = secondUpdateStmt.getRegion().
front();
742 rewriter.moveOpBefore(op, &loopHead);
745 moveDependency(vRef, vPtr, expr, loopArgument, loopHead, rewriter,
747 }
else if (
auto firstUpdateStmt = dyn_cast<AtomicUpdateOp>(firstOp)) {
748 if (
auto secondReadStmt = dyn_cast<AtomicReadOp>(secondOp)) {
750 storeVal = genUpdateCmpxchgLoop(firstUpdateStmt, rewriter);
752 Value vRef = secondReadStmt.getV();
753 vPtr = getAtomicPointer(vRef, rewriter.getRemappedValue(vRef),
754 capture.getLoc(), rewriter);
758 rewriter.setInsertionPoint(capture);
759 rewriter.replaceOpWithNewOp<LLVM::StoreOp>(capture, storeVal, vPtr);
768 target.addIllegalOp<AtomicReadOp, AtomicWriteOp, AtomicUpdateOp,
776 patterns.
add<ACCAtomicOpConversion<AtomicReadOp>,
777 ACCAtomicOpConversion<AtomicWriteOp>,
778 ACCAtomicOpConversion<AtomicUpdateOp>,
779 ACCAtomicOpConversion<AtomicCaptureOp>>(converter, accSupport,
constexpr static const uint64_t kBitsInByte
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
OpListType & getOperations()
RetT walk(FnT &&callback)
Walk all nested operations, blocks (including this block) or regions, depending on the type of callba...
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
typename SourceOp::Adaptor OpAdaptor
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...
MLIRContext is the top-level object for a collection of MLIR operations.
This class represents an operand of an operation.
This class provides the API for ops that are known to be terminators.
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
unsigned getNumOperands()
bool isAncestor(Operation *other)
Return true if this operation is an ancestor of the other operation.
unsigned getNumResults()
Return the number of results held by this operation.
ParentT getParentOfType()
Find the first parent operation of the given type, or nullptr if there is no ancestor operation.
RetT walk(FnT &&callback)
Walk all nested operations, blocks or regions (including this region), depending on the type of callb...
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...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
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.
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
void replaceAllUsesWith(Value newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Region * getParentRegion()
Return the Region in which this Value is defined.
std::optional< TypeSizeAndAlignment > getTypeSizeAndAlignment(Type ty, ModuleOp module, const DataLayout &dl, OpenACCSupport *support=nullptr)
Returns the size and ABI alignment in bytes.
Include the generated interface declarations.
void populateACCAtomicPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns, acc::OpenACCSupport &accSupport, ACCAtomicLoadAddressCallback getLoadAddress={})
Populate patterns that lower OpenACC atomic operations to LLVM dialect.
llvm::TypeSwitch< T, ResultT > TypeSwitch
std::function< Value(Operation *)> ACCAtomicLoadAddressCallback
Returns the address operand of a dialect-specific load operation.
void configureACCAtomicConversionLegality(ConversionTarget &target)
Configure conversion legality for OpenACC atomic operations.