20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/TypeSwitch.h"
22#include "llvm/Support/DebugLog.h"
24#define DEBUG_TYPE "sroa"
33 if (!getOperation()->getBlock()->isEntryBlock())
36 return {
MemorySlot{getResult(), getElemType()}};
41 return LLVM::UndefOp::create(builder, getLoc(), slot.
elemType);
44void LLVM::AllocaOp::handleBlockArgument(
const MemorySlot &slot,
47 for (
Operation *user : getOperation()->getUsers())
48 if (
auto declareOp = llvm::dyn_cast<LLVM::DbgDeclareOp>(user))
49 LLVM::DbgValueOp::create(builder, declareOp.getLoc(), argument,
50 declareOp.getVarInfo(),
51 declareOp.getLocationExpr());
54std::optional<PromotableAllocationOpInterface>
55LLVM::AllocaOp::handlePromotionComplete(
const MemorySlot &slot,
58 if (defaultValue && defaultValue.
use_empty())
68 auto destructurable = dyn_cast<DestructurableTypeInterface>(getElemType());
72 std::optional<DenseMap<Attribute, Type>> destructuredType =
73 destructurable.getSubelementIndexMap();
74 if (!destructuredType)
85 assert(slot.
ptr == getResult());
88 auto destructurableType = cast<DestructurableTypeInterface>(getElemType());
95 if (!usedIndices.contains(
index))
97 Type elemType = destructurableType.getTypeAtIndex(
index);
98 assert(elemType &&
"used index must exist");
99 auto subAlloca = LLVM::AllocaOp::create(
100 builder, getLoc(), LLVM::LLVMPointerType::get(
getContext()), elemType,
102 newAllocators.push_back(subAlloca);
103 slotMap.try_emplace<
MemorySlot>(
index, {subAlloca.getResult(), elemType});
109std::optional<DestructurableAllocationOpInterface>
110LLVM::AllocaOp::handleDestructuringComplete(
112 assert(slot.
ptr == getResult());
121bool LLVM::LoadOp::loadsFrom(
const MemorySlot &slot) {
122 return getAddr() == slot.
ptr;
125bool LLVM::LoadOp::storesTo(
const MemorySlot &slot) {
return false; }
129 llvm_unreachable(
"getStored should not be called on LoadOp");
132bool LLVM::StoreOp::loadsFrom(
const MemorySlot &slot) {
return false; }
134bool LLVM::StoreOp::storesTo(
const MemorySlot &slot) {
135 return getAddr() == slot.
ptr;
141 if (isa<LLVM::LLVMStructType, LLVM::LLVMArrayType>(type))
144 if (
auto vectorType = dyn_cast<VectorType>(type)) {
146 if (isa<LLVM::LLVMPointerType>(vectorType.getElementType()))
149 return !vectorType.isScalable();
158 Type srcType,
bool narrowingConversion) {
159 if (targetType == srcType)
166 uint64_t targetSize = layout.
getTypeSize(targetType);
171 if (isa<LLVM::LLVMPointerType>(targetType) &&
172 isa<LLVM::LLVMPointerType>(srcType))
173 return targetSize == srcSize;
175 if (narrowingConversion)
176 return targetSize <= srcSize;
177 return targetSize >= srcSize;
182 auto endiannessStr = dyn_cast_or_null<StringAttr>(dataLayout.
getEndianness());
183 return endiannessStr && endiannessStr ==
"big";
192 "expected value to have a convertible type");
194 if (isa<IntegerType>(type))
198 IntegerType valueSizeInteger = builder.
getIntegerType(typeBitSize);
200 if (isa<LLVM::LLVMPointerType>(type))
201 return builder.
createOrFold<LLVM::PtrToIntOp>(loc, valueSizeInteger, val);
202 return builder.
createOrFold<LLVM::BitcastOp>(loc, valueSizeInteger, val);
208 assert(isa<IntegerType>(val.
getType()) &&
209 "expected value to have an integer type");
211 "expected the target type to be supported for conversions");
212 if (val.
getType() == targetType)
214 if (isa<LLVM::LLVMPointerType>(targetType))
215 return builder.
createOrFold<LLVM::IntToPtrOp>(loc, targetType, val);
216 return builder.
createOrFold<LLVM::BitcastOp>(loc, targetType, val);
227 "expected that the compatibility was checked before");
230 if (srcType == targetType)
237 if (isa<LLVM::LLVMPointerType>(targetType) &&
238 isa<LLVM::LLVMPointerType>(srcType))
239 return builder.
createOrFold<LLVM::AddrSpaceCastOp>(loc, targetType,
257 "expected that the compatibility was checked before");
261 if (srcType == targetType)
266 if (srcTypeSize == targetTypeSize)
274 uint64_t shiftAmount = srcTypeSize - targetTypeSize;
275 auto shiftConstant = LLVM::ConstantOp::create(
278 builder.
createOrFold<LLVM::LShrOp>(loc, srcValue, shiftConstant);
298 "expected that the compatibility was checked before");
307 if (slotTypeSize == valueTypeSize)
320 uint64_t sizeDifference = slotTypeSize - valueTypeSize;
325 Value bigEndianShift = LLVM::ConstantOp::create(
329 builder.
createOrFold<LLVM::ShlOp>(loc, valueAsInt, bigEndianShift);
338 maskValue = APInt::getAllOnes(sizeDifference).zext(slotTypeSize);
342 maskValue = APInt::getAllOnes(valueTypeSize).zext(slotTypeSize);
343 maskValue.flipAllBits();
347 Value mask = LLVM::ConstantOp::create(
362 "expected the reaching definition's type to match the slot's type");
367bool LLVM::LoadOp::canUsesBeRemoved(
371 if (blockingUses.size() != 1)
373 Value blockingUse = (*blockingUses.begin())->get();
377 return blockingUse == slot.
ptr && getAddr() == slot.
ptr &&
390 getResult().
getType(), dataLayout);
391 getResult().replaceAllUsesWith(newResult);
395bool LLVM::StoreOp::canUsesBeRemoved(
399 if (blockingUses.size() != 1)
401 Value blockingUse = (*blockingUses.begin())->get();
405 return blockingUse == slot.
ptr && getAddr() == slot.
ptr &&
406 getValue() != slot.
ptr &&
427LogicalResult LLVM::LoadOp::ensureOnlySafeAccesses(
434LogicalResult LLVM::StoreOp::ensureOnlySafeAccesses(
444 auto subelementIndexMap =
445 cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap();
446 if (!subelementIndexMap)
448 assert(!subelementIndexMap->empty());
451 return subelementIndexMap->lookup(
index);
471 usedIndices.insert(
index);
480 auto it = subslots.find(
index);
481 assert(it != subslots.end());
483 getAddrMutable().set(it->getSecond().ptr);
495 if (getValue() == slot.
ptr)
509 usedIndices.insert(
index);
518 auto it = subslots.find(
index);
519 assert(it != subslots.end());
521 getAddrMutable().set(it->getSecond().ptr);
534 newBlockingUses.push_back(&use);
538bool LLVM::BitcastOp::canUsesBeRemoved(
550bool LLVM::AddrSpaceCastOp::canUsesBeRemoved(
562bool LLVM::LifetimeStartOp::canUsesBeRemoved(
574bool LLVM::LifetimeEndOp::canUsesBeRemoved(
586bool LLVM::InvariantStartOp::canUsesBeRemoved(
598bool LLVM::InvariantEndOp::canUsesBeRemoved(
610bool LLVM::LaunderInvariantGroupOp::canUsesBeRemoved(
617DeletionKind LLVM::LaunderInvariantGroupOp::removeBlockingUses(
622bool LLVM::DbgDeclareOp::canUsesBeRemoved(
634bool LLVM::DbgValueOp::canUsesBeRemoved(
639 if (blockingUses.size() != 1)
642 return (*blockingUses.begin())->get() == getValue();
654 UndefOp::create(builder, getValue().getLoc(), getValue().
getType());
655 getValueMutable().assign(undef);
659bool LLVM::DbgDeclareOp::requiresReplacedValues() {
return true; }
661void LLVM::DbgDeclareOp::visitReplacedValues(
663 for (
auto [op, value] : definitions) {
665 LLVM::DbgValueOp::create(builder, getLoc(), value, getVarInfo(),
675 return llvm::all_of(gepOp.getIndices(), [](
auto index) {
676 auto indexAttr = llvm::dyn_cast_if_present<IntegerAttr>(index);
677 return indexAttr && indexAttr.getValue() == 0;
681bool LLVM::GEPOp::canUsesBeRemoved(
704 for (
auto index : gep.getIndices()) {
705 auto constIndex = dyn_cast<IntegerAttr>(
index);
708 int64_t gepIndex = constIndex.getInt();
715 Type currentType = gep.getElemType();
721 .Case([&](LLVM::LLVMArrayType arrayType) {
724 currentType = arrayType.getElementType();
727 .Case([&](LLVM::LLVMStructType structType) {
729 assert(
index < body.size() &&
"expected valid struct indexing");
730 for (uint32_t i : llvm::seq(
index)) {
731 if (!structType.isPacked())
732 offset = llvm::alignTo(
738 if (!structType.isPacked())
739 offset = llvm::alignTo(
741 currentType = body[
index];
744 .Default([&](
Type type) {
745 LDBG() <<
"[sroa] Unsupported type for offset computations"
760struct SubslotAccessInfo {
764 uint64_t subslotOffset;
772static std::optional<SubslotAccessInfo>
774 const DataLayout &dataLayout, LLVM::GEPOp gep) {
782 auto isOutOfBoundsGEPIndex = [](uint64_t
index) {
790 .Case([&](LLVM::LLVMArrayType arrayType)
791 -> std::optional<SubslotAccessInfo> {
793 uint64_t elemSize = dataLayout.
getTypeSize(arrayType.getElementType());
794 uint64_t
index = *offset / elemSize;
795 if (isOutOfBoundsGEPIndex(
index))
797 return SubslotAccessInfo{
static_cast<uint32_t
>(
index),
798 *offset - (
index * elemSize)};
800 .Case([&](LLVM::LLVMStructType structType)
801 -> std::optional<SubslotAccessInfo> {
802 uint64_t distanceToStart = 0;
805 for (
auto [
index, elem] : llvm::enumerate(structType.getBody())) {
807 if (!structType.isPacked()) {
808 distanceToStart = llvm::alignTo(
811 if (offset < distanceToStart)
815 if (offset < distanceToStart + elemSize) {
816 if (isOutOfBoundsGEPIndex(
index))
820 return SubslotAccessInfo{
static_cast<uint32_t
>(
index),
821 *offset - distanceToStart};
826 distanceToStart += elemSize;
836 auto byteType = IntegerType::get(context, 8);
837 return LLVM::LLVMArrayType::get(context, byteType, size);
840LogicalResult LLVM::GEPOp::ensureOnlySafeAccesses(
845 std::optional<uint64_t> gepOffset =
gepToByteOffset(dataLayout, *
this);
850 if (*gepOffset >= slotSize)
870 if (getInrangeAttr())
872 std::optional<SubslotAccessInfo> accessInfo =
877 IntegerAttr::get(IntegerType::get(
getContext(), 32), accessInfo->index);
879 usedIndices.insert(indexAttr);
884 uint64_t slotSize = dataLayout.
getTypeSize(subslotType);
885 LLVM::LLVMArrayType remainingSlotType =
887 mustBeSafelyUsed.emplace_back<
MemorySlot>({getRes(), remainingSlotType});
896 std::optional<SubslotAccessInfo> accessInfo =
898 assert(accessInfo &&
"expected access info to be checked before");
900 IntegerAttr::get(IntegerType::get(
getContext(), 32), accessInfo->index);
901 const MemorySlot &newSlot = subslots.at(indexAttr);
903 auto byteType = IntegerType::get(builder.
getContext(), 8);
905 getLoc(), getResult().getType(), byteType, newSlot.
ptr,
907 getResult().replaceAllUsesWith(newPtr);
919template <
class MemIntr>
920std::optional<uint64_t> getStaticMemIntrLen(MemIntr op) {
924 if (memIntrLen.getBitWidth() > 64)
926 return memIntrLen.getZExtValue();
934std::optional<uint64_t> getStaticMemIntrLen(LLVM::MemcpyInlineOp op) {
935 APInt memIntrLen = op.getLen();
936 if (memIntrLen.getBitWidth() > 64)
938 return memIntrLen.getZExtValue();
946std::optional<uint64_t> getStaticMemIntrLen(LLVM::MemsetInlineOp op) {
947 APInt memIntrLen = op.getLen();
948 if (memIntrLen.getBitWidth() > 64)
950 return memIntrLen.getZExtValue();
954template <
class MemsetIntr>
955IntegerAttr createMemsetLenAttr(MemsetIntr op) {
956 IntegerAttr memsetLenAttr;
957 bool successfulMatch =
959 (
void)successfulMatch;
960 assert(successfulMatch);
961 return memsetLenAttr;
968IntegerAttr createMemsetLenAttr(LLVM::MemsetInlineOp op) {
969 return op.getLenAttr();
975template <
class MemsetIntr>
976void createMemsetIntr(
OpBuilder &builder, MemsetIntr toReplace,
977 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
982void createMemsetIntr(
OpBuilder &builder, LLVM::MemsetOp toReplace,
983 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
986 Value newMemsetSizeValue =
987 LLVM::ConstantOp::create(
988 builder, toReplace.getLen().getLoc(),
989 IntegerAttr::get(memsetLenAttr.getType(), newMemsetSize))
992 LLVM::MemsetOp::create(builder, toReplace.getLoc(), subslots.at(
index).ptr,
993 toReplace.getVal(), newMemsetSizeValue,
994 toReplace.getIsVolatile());
998void createMemsetIntr(
OpBuilder &builder, LLVM::MemsetInlineOp toReplace,
999 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
1002 auto newMemsetSizeValue =
1003 IntegerAttr::get(memsetLenAttr.getType(), newMemsetSize);
1005 LLVM::MemsetInlineOp::create(builder, toReplace.getLoc(),
1006 subslots.at(
index).ptr, toReplace.getVal(),
1007 newMemsetSizeValue, toReplace.getIsVolatile());
1014template <
class MemIntr>
1017 if (!isa<LLVM::LLVMPointerType>(slot.
ptr.
getType()) ||
1018 op.getDst() != slot.
ptr)
1021 std::optional<uint64_t> memIntrLen = getStaticMemIntrLen(op);
1031 auto intIndex = dyn_cast<IntegerAttr>(index);
1032 return intIndex && intIndex.getType() == i32;
1040template <
class MemsetIntr>
1048 if (op.getIsVolatile())
1051 if (!cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap())
1060template <
class MemsetIntr>
1065 auto buildMemsetValue = [&](
unsigned width) ->
Value {
1066 assert(width % 8 == 0);
1067 auto intType = IntegerType::get(op.getContext(), width);
1071 IntegerAttr constantPattern;
1073 assert(constantPattern.getValue().getBitWidth() == 8);
1074 APInt memsetVal(width, 0);
1075 for (
unsigned loBit = 0; loBit < width; loBit += 8)
1076 memsetVal.insertBits(constantPattern.getValue(), loBit);
1077 return LLVM::ConstantOp::create(builder, op.getLoc(),
1078 IntegerAttr::get(intType, memsetVal));
1087 uint64_t coveredBits = 8;
1088 Value currentValue =
1089 LLVM::ZExtOp::create(builder, op.getLoc(), intType, op.getVal());
1090 while (coveredBits < width) {
1092 LLVM::ConstantOp::create(builder, op.getLoc(), intType, coveredBits);
1094 LLVM::ShlOp::create(builder, op.getLoc(), currentValue, shiftBy);
1096 LLVM::OrOp::create(builder, op.getLoc(), currentValue, shifted);
1100 return currentValue;
1103 .Case([&](IntegerType type) ->
Value {
1104 return buildMemsetValue(type.getWidth());
1106 .Case([&](FloatType type) ->
Value {
1107 Value intVal = buildMemsetValue(type.getWidth());
1108 return LLVM::BitcastOp::create(builder, op.getLoc(), type, intVal);
1110 .DefaultUnreachable(
1111 "getStored should not be called on memset to unsupported type");
1114template <
class MemsetIntr>
1120 bool canConvertType =
1122 .Case<IntegerType, FloatType>([](
auto type) {
1123 return type.getWidth() % 8 == 0 && type.getWidth() > 0;
1126 if (!canConvertType)
1129 if (op.getIsVolatile())
1135template <
class MemsetIntr>
1141 std::optional<DenseMap<Attribute, Type>> types =
1142 cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap();
1144 IntegerAttr memsetLenAttr = createMemsetLenAttr(op);
1146 bool packed =
false;
1147 if (
auto structType = dyn_cast<LLVM::LLVMStructType>(slot.
elemType))
1148 packed = structType.isPacked();
1150 Type i32 = IntegerType::get(op.getContext(), 32);
1151 uint64_t memsetLen = memsetLenAttr.getValue().getZExtValue();
1152 uint64_t covered = 0;
1153 for (
size_t i = 0; i < types->size(); i++) {
1157 uint64_t typeSize = dataLayout.
getTypeSize(elemType);
1163 if (covered >= memsetLen)
1168 if (subslots.contains(
index)) {
1169 uint64_t newMemsetSize = std::min(memsetLen - covered, typeSize);
1170 createMemsetIntr(builder, op, memsetLenAttr, newMemsetSize, subslots,
1174 covered += typeSize;
1180bool LLVM::MemsetOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1182bool LLVM::MemsetOp::storesTo(
const MemorySlot &slot) {
1183 return getDst() == slot.
ptr;
1192bool LLVM::MemsetOp::canUsesBeRemoved(
1207LogicalResult LLVM::MemsetOp::ensureOnlySafeAccesses(
1225 return memsetRewire(*
this, slot, subslots, builder, dataLayout);
1228bool LLVM::MemsetInlineOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1230bool LLVM::MemsetInlineOp::storesTo(
const MemorySlot &slot) {
1231 return getDst() == slot.
ptr;
1240bool LLVM::MemsetInlineOp::canUsesBeRemoved(
1255LogicalResult LLVM::MemsetInlineOp::ensureOnlySafeAccesses(
1261bool LLVM::MemsetInlineOp::canRewire(
1274 return memsetRewire(*
this, slot, subslots, builder, dataLayout);
1281template <
class MemcpyLike>
1283 return op.getSrc() == slot.
ptr;
1286template <
class MemcpyLike>
1288 return op.getDst() == slot.
ptr;
1291template <
class MemcpyLike>
1294 return LLVM::LoadOp::create(builder, op.getLoc(), slot.
elemType, op.getSrc());
1297template <
class MemcpyLike>
1306 if (op.getDst() == op.getSrc())
1309 if (op.getIsVolatile())
1315template <
class MemcpyLike>
1320 if (op.loadsFrom(slot))
1321 LLVM::StoreOp::create(builder, op.getLoc(), reachingDefinition,
1326template <
class MemcpyLike>
1337template <
class MemcpyLike>
1342 if (op.getIsVolatile())
1345 if (!cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap())
1355 if (op.getSrc() == slot.
ptr)
1356 usedIndices.insert_range(llvm::make_first_range(slot.
subelementTypes));
1363template <
class MemcpyLike>
1366 Type toCpy,
bool isVolatile) {
1368 LLVM::ConstantOp::create(builder, toReplace.getLoc(),
1369 IntegerAttr::get(toReplace.getLen().getType(),
1371 MemcpyLike::create(builder, toReplace.getLoc(), dst, src, memcpySize,
1377 LLVM::MemcpyInlineOp toReplace,
Value dst,
1378 Value src,
Type toCpy,
bool isVolatile) {
1379 Type lenType = IntegerType::get(toReplace->getContext(),
1380 toReplace.getLen().getBitWidth());
1381 LLVM::MemcpyInlineOp::create(
1382 builder, toReplace.getLoc(), dst, src,
1383 IntegerAttr::get(lenType, layout.
getTypeSize(toCpy)), isVolatile);
1390template <
class MemcpyLike>
1395 if (subslots.empty())
1398 assert((slot.
ptr == op.getDst()) != (slot.
ptr == op.getSrc()));
1399 bool isDst = slot.
ptr == op.getDst();
1402 size_t slotsTreated = 0;
1407 Type indexType = cast<IntegerAttr>(subslots.begin()->first).getType();
1410 if (!subslots.contains(
index))
1421 0,
static_cast<int32_t
>(
1422 cast<IntegerAttr>(
index).getValue().getZExtValue())};
1423 Value subslotPtrInOther = LLVM::GEPOp::create(
1424 builder, op.getLoc(), LLVM::LLVMPointerType::get(op.getContext()),
1425 slot.
elemType, isDst ? op.getSrc() : op.getDst(), gepIndices);
1428 createMemcpyLikeToReplace(builder, dataLayout, op,
1429 isDst ? subslot.
ptr : subslotPtrInOther,
1430 isDst ? subslotPtrInOther : subslot.
ptr,
1431 subslot.
elemType, op.getIsVolatile());
1434 assert(subslots.size() == slotsTreated);
1439bool LLVM::MemcpyOp::loadsFrom(
const MemorySlot &slot) {
1443bool LLVM::MemcpyOp::storesTo(
const MemorySlot &slot) {
1453bool LLVM::MemcpyOp::canUsesBeRemoved(
1466 reachingDefinition);
1469LogicalResult LLVM::MemcpyOp::ensureOnlySafeAccesses(
1487 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1490bool LLVM::MemcpyInlineOp::loadsFrom(
const MemorySlot &slot) {
1494bool LLVM::MemcpyInlineOp::storesTo(
const MemorySlot &slot) {
1504bool LLVM::MemcpyInlineOp::canUsesBeRemoved(
1517 reachingDefinition);
1520LogicalResult LLVM::MemcpyInlineOp::ensureOnlySafeAccesses(
1526bool LLVM::MemcpyInlineOp::canRewire(
1539 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1542bool LLVM::MemmoveOp::loadsFrom(
const MemorySlot &slot) {
1546bool LLVM::MemmoveOp::storesTo(
const MemorySlot &slot) {
1556bool LLVM::MemmoveOp::canUsesBeRemoved(
1569 reachingDefinition);
1572LogicalResult LLVM::MemmoveOp::ensureOnlySafeAccesses(
1590 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1597std::optional<DenseMap<Attribute, Type>>
1598LLVM::LLVMStructType::getSubelementIndexMap()
const {
1600 if (getBody().empty())
1601 return std::nullopt;
1604 for (
const auto &[
index, elemType] : llvm::enumerate(getBody()))
1605 destructured.insert({IntegerAttr::get(i32,
index), elemType});
1606 return destructured;
1610 auto indexAttr = llvm::dyn_cast<IntegerAttr>(
index);
1611 if (!indexAttr || !indexAttr.getType().isInteger(32))
1613 int32_t indexInt = indexAttr.getInt();
1615 if (indexInt < 0 || body.size() <=
static_cast<uint32_t
>(indexInt))
1617 return body[indexInt];
1620std::optional<DenseMap<Attribute, Type>>
1621LLVM::LLVMArrayType::getSubelementIndexMap()
const {
1622 constexpr size_t maxArraySizeForDestructuring = 16;
1630 destructured.insert({IntegerAttr::get(i32, index), getElementType()});
1631 return destructured;
1635 auto indexAttr = llvm::dyn_cast<IntegerAttr>(
index);
1636 if (!indexAttr || !indexAttr.getType().isInteger(32))
1638 int32_t indexInt = indexAttr.getInt();
1639 if (indexInt < 0 ||
getNumElements() <=
static_cast<uint32_t
>(indexInt))
static Value getBase(Value v)
Looks through known "view-like" ops to find the base memref.
static int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
static LLVM::LLVMArrayType getByteArrayType(MLIRContext *context, unsigned size)
Constructs a byte array type of the given size.
static LogicalResult memcpyEnsureOnlySafeAccesses(MemcpyLike op, const MemorySlot &slot, SmallVectorImpl< MemorySlot > &mustBeSafelyUsed)
static std::optional< SubslotAccessInfo > getSubslotAccessInfo(const DestructurableMemorySlot &slot, const DataLayout &dataLayout, LLVM::GEPOp gep)
Computes subslot access information for an access into slot with the given offset.
static bool areAllIndicesI32(const DestructurableMemorySlot &slot)
Checks whether all indices are i32.
static Value castToSameSizedInt(OpBuilder &builder, Location loc, Value val, const DataLayout &dataLayout)
Converts a value to an integer type of the same size.
static Value castSameSizedTypes(OpBuilder &builder, Location loc, Value srcValue, Type targetType, const DataLayout &dataLayout)
Constructs operations that convert srcValue into a new value of type targetType.
static bool memcpyStoresTo(MemcpyLike op, const MemorySlot &slot)
static DeletionKind memsetRewire(MemsetIntr op, const DestructurableMemorySlot &slot, DenseMap< Attribute, MemorySlot > &subslots, OpBuilder &builder, const DataLayout &dataLayout)
static Type getTypeAtIndex(const DestructurableMemorySlot &slot, Attribute index)
Returns the subslot's type at the requested index.
static bool areConversionCompatible(const DataLayout &layout, Type targetType, Type srcType, bool narrowingConversion)
Checks that rhs can be converted to lhs by a sequence of casts and truncations.
static bool forwardToUsers(Operation *op, SmallVectorImpl< OpOperand * > &newBlockingUses)
Conditions the deletion of the operation to the removal of all its uses.
static bool memsetCanUsesBeRemoved(MemsetIntr op, const MemorySlot &slot, const SmallPtrSetImpl< OpOperand * > &blockingUses, SmallVectorImpl< OpOperand * > &newBlockingUses, const DataLayout &dataLayout)
static bool memcpyLoadsFrom(MemcpyLike op, const MemorySlot &slot)
static bool isSupportedTypeForConversion(Type type)
Checks if type can be used in any kind of conversion sequences.
static Value createExtractAndCast(OpBuilder &builder, Location loc, Value srcValue, Type targetType, const DataLayout &dataLayout)
Constructs operations that convert srcValue into a new value of type targetType.
static Value createInsertAndCast(OpBuilder &builder, Location loc, Value srcValue, Value reachingDef, const DataLayout &dataLayout)
Constructs operations that insert the bits of srcValue into the "beginning" of reachingDef (beginning...
static DeletionKind memcpyRemoveBlockingUses(MemcpyLike op, const MemorySlot &slot, const SmallPtrSetImpl< OpOperand * > &blockingUses, OpBuilder &builder, Value reachingDefinition)
static bool memcpyCanUsesBeRemoved(MemcpyLike op, const MemorySlot &slot, const SmallPtrSetImpl< OpOperand * > &blockingUses, SmallVectorImpl< OpOperand * > &newBlockingUses, const DataLayout &dataLayout)
static bool isBigEndian(const DataLayout &dataLayout)
Checks if dataLayout describes a little endian layout.
static std::optional< uint64_t > gepToByteOffset(const DataLayout &dataLayout, LLVM::GEPOp gep)
Returns the amount of bytes the provided GEP elements will offset the pointer by.
static bool hasAllZeroIndices(LLVM::GEPOp gepOp)
static bool isValidAccessType(const MemorySlot &slot, Type accessType, const DataLayout &dataLayout)
Checks if slot can be accessed through the provided access type.
static Value memcpyGetStored(MemcpyLike op, const MemorySlot &slot, OpBuilder &builder)
static Value castIntValueToSameSizedType(OpBuilder &builder, Location loc, Value val, Type targetType)
Converts a value with an integer type to targetType.
static bool memsetCanRewire(MemsetIntr op, const DestructurableMemorySlot &slot, SmallPtrSetImpl< Attribute > &usedIndices, SmallVectorImpl< MemorySlot > &mustBeSafelyUsed, const DataLayout &dataLayout)
static DeletionKind memcpyRewire(MemcpyLike op, const DestructurableMemorySlot &slot, DenseMap< Attribute, MemorySlot > &subslots, OpBuilder &builder, const DataLayout &dataLayout)
Rewires a memcpy-like operation.
static Value memsetGetStored(MemsetIntr op, const MemorySlot &slot, OpBuilder &builder)
static bool definitelyWritesOnlyWithinSlot(MemIntr op, const MemorySlot &slot, const DataLayout &dataLayout)
Returns whether one can be sure the memory intrinsic does not write outside of the bounds of the give...
static bool memcpyCanRewire(MemcpyLike op, const DestructurableMemorySlot &slot, SmallPtrSetImpl< Attribute > &usedIndices, SmallVectorImpl< MemorySlot > &mustBeSafelyUsed, const DataLayout &dataLayout)
*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 the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
Attributes are known-constant values of operations.
This class represents an argument of a Block.
IntegerAttr getIntegerAttr(Type type, int64_t value)
IntegerType getIntegerType(unsigned width)
MLIRContext * getContext() const
The main mechanism for performing data layout queries.
static DataLayout closest(Operation *op)
Returns the layout of the closest parent operation carrying layout info.
llvm::TypeSize getTypeSize(Type t) const
Returns the size of the given type in the current scope.
uint64_t getTypeABIAlignment(Type t) const
Returns the required alignment of the given type in the current scope.
llvm::TypeSize getTypeSizeInBits(Type t) const
Returns the size in bits of the given type in the current scope.
Attribute getEndianness() const
Returns the specified endianness.
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 helps build Operations.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
void createOrFold(SmallVectorImpl< Value > &results, Location location, Args &&...args)
Create an operation of specific op type at the current insertion point, and immediately try to fold i...
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
This class represents an operand of an operation.
Operation is the basic unit of execution within MLIR.
result_range getResults()
void erase()
Remove this operation from its parent block and delete it.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Dialect & getDialect() const
Get the dialect this type is registered to.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
MLIRContext * getContext() const
Utility to get the associated MLIRContext that this value is defined in.
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
constexpr int kGEPConstantBitWidth
Bit-width of a 'GEPConstantIndex' within GEPArg.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
detail::constant_int_value_binder m_ConstantInt(IntegerAttr::ValueType *bind_value)
Matches a constant holding a scalar/vector/tensor integer (splat) and writes the integer value to bin...
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
detail::constant_int_predicate_matcher m_One()
Matches a constant scalar / vector splat / tensor splat integer one.
DeletionKind
Returned by operation promotion logic requesting the deletion of an operation.
@ Keep
Keep the operation after promotion.
@ Delete
Delete the operation after promotion.
llvm::TypeSwitch< T, ResultT > TypeSwitch
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
Memory slot attached with information about its destructuring procedure.
DenseMap< Attribute, Type > subelementTypes
Maps an index within the memory slot to the corresponding subelement type.
Represents a slot in memory.
Value ptr
Pointer to the memory slot, used by operations to refer to it.
Type elemType
Type of the value contained in the slot.