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 (srcTypeSize == targetTypeSize)
269 uint64_t shiftAmount = srcTypeSize - targetTypeSize;
270 auto shiftConstant = LLVM::ConstantOp::create(
273 builder.
createOrFold<LLVM::LShrOp>(loc, srcValue, shiftConstant);
293 "expected that the compatibility was checked before");
296 if (slotTypeSize == valueTypeSize)
309 uint64_t sizeDifference = slotTypeSize - valueTypeSize;
314 Value bigEndianShift = LLVM::ConstantOp::create(
318 builder.
createOrFold<LLVM::ShlOp>(loc, valueAsInt, bigEndianShift);
327 maskValue = APInt::getAllOnes(sizeDifference).zext(slotTypeSize);
331 maskValue = APInt::getAllOnes(valueTypeSize).zext(slotTypeSize);
332 maskValue.flipAllBits();
336 Value mask = LLVM::ConstantOp::create(
351 "expected the reaching definition's type to match the slot's type");
356bool LLVM::LoadOp::canUsesBeRemoved(
360 if (blockingUses.size() != 1)
362 Value blockingUse = (*blockingUses.begin())->get();
366 return blockingUse == slot.
ptr && getAddr() == slot.
ptr &&
379 getResult().
getType(), dataLayout);
380 getResult().replaceAllUsesWith(newResult);
384bool LLVM::StoreOp::canUsesBeRemoved(
388 if (blockingUses.size() != 1)
390 Value blockingUse = (*blockingUses.begin())->get();
394 return blockingUse == slot.
ptr && getAddr() == slot.
ptr &&
395 getValue() != slot.
ptr &&
416LogicalResult LLVM::LoadOp::ensureOnlySafeAccesses(
423LogicalResult LLVM::StoreOp::ensureOnlySafeAccesses(
433 auto subelementIndexMap =
434 cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap();
435 if (!subelementIndexMap)
437 assert(!subelementIndexMap->empty());
440 return subelementIndexMap->lookup(
index);
460 usedIndices.insert(
index);
469 auto it = subslots.find(
index);
470 assert(it != subslots.end());
472 getAddrMutable().set(it->getSecond().ptr);
484 if (getValue() == slot.
ptr)
498 usedIndices.insert(
index);
507 auto it = subslots.find(
index);
508 assert(it != subslots.end());
510 getAddrMutable().set(it->getSecond().ptr);
523 newBlockingUses.push_back(&use);
527bool LLVM::BitcastOp::canUsesBeRemoved(
539bool LLVM::AddrSpaceCastOp::canUsesBeRemoved(
551bool LLVM::LifetimeStartOp::canUsesBeRemoved(
563bool LLVM::LifetimeEndOp::canUsesBeRemoved(
575bool LLVM::InvariantStartOp::canUsesBeRemoved(
587bool LLVM::InvariantEndOp::canUsesBeRemoved(
599bool LLVM::LaunderInvariantGroupOp::canUsesBeRemoved(
606DeletionKind LLVM::LaunderInvariantGroupOp::removeBlockingUses(
611bool LLVM::StripInvariantGroupOp::canUsesBeRemoved(
618DeletionKind LLVM::StripInvariantGroupOp::removeBlockingUses(
623bool LLVM::DbgDeclareOp::canUsesBeRemoved(
635bool LLVM::DbgValueOp::canUsesBeRemoved(
640 if (blockingUses.size() != 1)
643 return (*blockingUses.begin())->get() == getValue();
655 UndefOp::create(builder, getValue().getLoc(), getValue().
getType());
656 getValueMutable().assign(undef);
660bool LLVM::DbgDeclareOp::requiresReplacedValues() {
return true; }
662void LLVM::DbgDeclareOp::visitReplacedValues(
664 for (
auto [op, value] : definitions) {
666 LLVM::DbgValueOp::create(builder, getLoc(), value, getVarInfo(),
676 return llvm::all_of(gepOp.getIndices(), [](
auto index) {
677 auto indexAttr = llvm::dyn_cast_if_present<IntegerAttr>(index);
678 return indexAttr && indexAttr.getValue() == 0;
682bool LLVM::GEPOp::canUsesBeRemoved(
703 for (
auto index : gep.getIndices()) {
704 auto constIndex = dyn_cast<IntegerAttr>(
index);
707 int64_t gepIndex = constIndex.getInt();
714 Type currentType = gep.getElemType();
720 .Case([&](LLVM::LLVMArrayType arrayType) {
723 currentType = arrayType.getElementType();
726 .Case([&](LLVM::LLVMStructType structType) {
728 assert(
index < body.size() &&
"expected valid struct indexing");
729 for (uint32_t i : llvm::seq(
index)) {
730 if (!structType.isPacked())
731 offset = llvm::alignTo(
737 if (!structType.isPacked())
738 offset = llvm::alignTo(
740 currentType = body[
index];
743 .Default([&](
Type type) {
744 LDBG() <<
"[sroa] Unsupported type for offset computations"
759struct SubslotAccessInfo {
763 uint64_t subslotOffset;
771static std::optional<SubslotAccessInfo>
773 const DataLayout &dataLayout, LLVM::GEPOp gep) {
781 auto isOutOfBoundsGEPIndex = [](uint64_t
index) {
789 .Case([&](LLVM::LLVMArrayType arrayType)
790 -> std::optional<SubslotAccessInfo> {
792 uint64_t elemSize = dataLayout.
getTypeSize(arrayType.getElementType());
793 uint64_t
index = *offset / elemSize;
794 if (isOutOfBoundsGEPIndex(
index))
796 return SubslotAccessInfo{
static_cast<uint32_t
>(
index),
797 *offset - (
index * elemSize)};
799 .Case([&](LLVM::LLVMStructType structType)
800 -> std::optional<SubslotAccessInfo> {
801 uint64_t distanceToStart = 0;
804 for (
auto [
index, elem] : llvm::enumerate(structType.getBody())) {
806 if (!structType.isPacked()) {
807 distanceToStart = llvm::alignTo(
810 if (offset < distanceToStart)
814 if (offset < distanceToStart + elemSize) {
815 if (isOutOfBoundsGEPIndex(
index))
819 return SubslotAccessInfo{
static_cast<uint32_t
>(
index),
820 *offset - distanceToStart};
825 distanceToStart += elemSize;
835 auto byteType = IntegerType::get(context, 8);
836 return LLVM::LLVMArrayType::get(context, byteType, size);
839LogicalResult LLVM::GEPOp::ensureOnlySafeAccesses(
844 std::optional<uint64_t> gepOffset =
gepToByteOffset(dataLayout, *
this);
849 if (*gepOffset >= slotSize)
867 std::optional<SubslotAccessInfo> accessInfo =
872 IntegerAttr::get(IntegerType::get(
getContext(), 32), accessInfo->index);
874 usedIndices.insert(indexAttr);
879 uint64_t slotSize = dataLayout.
getTypeSize(subslotType);
880 LLVM::LLVMArrayType remainingSlotType =
882 mustBeSafelyUsed.emplace_back<
MemorySlot>({getRes(), remainingSlotType});
891 std::optional<SubslotAccessInfo> accessInfo =
893 assert(accessInfo &&
"expected access info to be checked before");
895 IntegerAttr::get(IntegerType::get(
getContext(), 32), accessInfo->index);
896 const MemorySlot &newSlot = subslots.at(indexAttr);
898 auto byteType = IntegerType::get(builder.
getContext(), 8);
900 getLoc(), getResult().getType(), byteType, newSlot.
ptr,
902 getResult().replaceAllUsesWith(newPtr);
914template <
class MemIntr>
915std::optional<uint64_t> getStaticMemIntrLen(MemIntr op) {
919 if (memIntrLen.getBitWidth() > 64)
921 return memIntrLen.getZExtValue();
929std::optional<uint64_t> getStaticMemIntrLen(LLVM::MemcpyInlineOp op) {
930 APInt memIntrLen = op.getLen();
931 if (memIntrLen.getBitWidth() > 64)
933 return memIntrLen.getZExtValue();
941std::optional<uint64_t> getStaticMemIntrLen(LLVM::MemsetInlineOp op) {
942 APInt memIntrLen = op.getLen();
943 if (memIntrLen.getBitWidth() > 64)
945 return memIntrLen.getZExtValue();
949template <
class MemsetIntr>
950IntegerAttr createMemsetLenAttr(MemsetIntr op) {
951 IntegerAttr memsetLenAttr;
952 bool successfulMatch =
954 (
void)successfulMatch;
955 assert(successfulMatch);
956 return memsetLenAttr;
963IntegerAttr createMemsetLenAttr(LLVM::MemsetInlineOp op) {
964 return op.getLenAttr();
970template <
class MemsetIntr>
971void createMemsetIntr(
OpBuilder &builder, MemsetIntr toReplace,
972 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
977void createMemsetIntr(
OpBuilder &builder, LLVM::MemsetOp toReplace,
978 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
981 Value newMemsetSizeValue =
982 LLVM::ConstantOp::create(
983 builder, toReplace.getLen().getLoc(),
984 IntegerAttr::get(memsetLenAttr.getType(), newMemsetSize))
987 LLVM::MemsetOp::create(builder, toReplace.getLoc(), subslots.at(
index).ptr,
988 toReplace.getVal(), newMemsetSizeValue,
989 toReplace.getIsVolatile());
993void createMemsetIntr(
OpBuilder &builder, LLVM::MemsetInlineOp toReplace,
994 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
997 auto newMemsetSizeValue =
998 IntegerAttr::get(memsetLenAttr.getType(), newMemsetSize);
1000 LLVM::MemsetInlineOp::create(builder, toReplace.getLoc(),
1001 subslots.at(
index).ptr, toReplace.getVal(),
1002 newMemsetSizeValue, toReplace.getIsVolatile());
1009template <
class MemIntr>
1012 if (!isa<LLVM::LLVMPointerType>(slot.
ptr.
getType()) ||
1013 op.getDst() != slot.
ptr)
1016 std::optional<uint64_t> memIntrLen = getStaticMemIntrLen(op);
1026 auto intIndex = dyn_cast<IntegerAttr>(index);
1027 return intIndex && intIndex.getType() == i32;
1035template <
class MemsetIntr>
1043 if (op.getIsVolatile())
1046 if (!cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap())
1055template <
class MemsetIntr>
1060 auto buildMemsetValue = [&](
unsigned width) ->
Value {
1061 assert(width % 8 == 0);
1062 auto intType = IntegerType::get(op.getContext(), width);
1066 IntegerAttr constantPattern;
1068 assert(constantPattern.getValue().getBitWidth() == 8);
1069 APInt memsetVal(width, 0);
1070 for (
unsigned loBit = 0; loBit < width; loBit += 8)
1071 memsetVal.insertBits(constantPattern.getValue(), loBit);
1072 return LLVM::ConstantOp::create(builder, op.getLoc(),
1073 IntegerAttr::get(intType, memsetVal));
1082 uint64_t coveredBits = 8;
1083 Value currentValue =
1084 LLVM::ZExtOp::create(builder, op.getLoc(), intType, op.getVal());
1085 while (coveredBits < width) {
1087 LLVM::ConstantOp::create(builder, op.getLoc(), intType, coveredBits);
1089 LLVM::ShlOp::create(builder, op.getLoc(), currentValue, shiftBy);
1091 LLVM::OrOp::create(builder, op.getLoc(), currentValue, shifted);
1095 return currentValue;
1098 .Case([&](IntegerType type) ->
Value {
1099 return buildMemsetValue(type.getWidth());
1101 .Case([&](FloatType type) ->
Value {
1102 Value intVal = buildMemsetValue(type.getWidth());
1103 return LLVM::BitcastOp::create(builder, op.getLoc(), type, intVal);
1105 .DefaultUnreachable(
1106 "getStored should not be called on memset to unsupported type");
1109template <
class MemsetIntr>
1115 bool canConvertType =
1117 .Case<IntegerType, FloatType>([](
auto type) {
1118 return type.getWidth() % 8 == 0 && type.getWidth() > 0;
1121 if (!canConvertType)
1124 if (op.getIsVolatile())
1130template <
class MemsetIntr>
1136 std::optional<DenseMap<Attribute, Type>> types =
1137 cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap();
1139 IntegerAttr memsetLenAttr = createMemsetLenAttr(op);
1141 bool packed =
false;
1142 if (
auto structType = dyn_cast<LLVM::LLVMStructType>(slot.
elemType))
1143 packed = structType.isPacked();
1145 Type i32 = IntegerType::get(op.getContext(), 32);
1146 uint64_t memsetLen = memsetLenAttr.getValue().getZExtValue();
1147 uint64_t covered = 0;
1148 for (
size_t i = 0; i < types->size(); i++) {
1152 uint64_t typeSize = dataLayout.
getTypeSize(elemType);
1158 if (covered >= memsetLen)
1163 if (subslots.contains(
index)) {
1164 uint64_t newMemsetSize = std::min(memsetLen - covered, typeSize);
1165 createMemsetIntr(builder, op, memsetLenAttr, newMemsetSize, subslots,
1169 covered += typeSize;
1175bool LLVM::MemsetOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1177bool LLVM::MemsetOp::storesTo(
const MemorySlot &slot) {
1178 return getDst() == slot.
ptr;
1187bool LLVM::MemsetOp::canUsesBeRemoved(
1202LogicalResult LLVM::MemsetOp::ensureOnlySafeAccesses(
1220 return memsetRewire(*
this, slot, subslots, builder, dataLayout);
1223bool LLVM::MemsetInlineOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1225bool LLVM::MemsetInlineOp::storesTo(
const MemorySlot &slot) {
1226 return getDst() == slot.
ptr;
1235bool LLVM::MemsetInlineOp::canUsesBeRemoved(
1250LogicalResult LLVM::MemsetInlineOp::ensureOnlySafeAccesses(
1256bool LLVM::MemsetInlineOp::canRewire(
1269 return memsetRewire(*
this, slot, subslots, builder, dataLayout);
1276template <
class MemcpyLike>
1278 return op.getSrc() == slot.
ptr;
1281template <
class MemcpyLike>
1283 return op.getDst() == slot.
ptr;
1286template <
class MemcpyLike>
1289 return LLVM::LoadOp::create(builder, op.getLoc(), slot.
elemType, op.getSrc());
1292template <
class MemcpyLike>
1301 if (op.getDst() == op.getSrc())
1304 if (op.getIsVolatile())
1310template <
class MemcpyLike>
1315 if (op.loadsFrom(slot))
1316 LLVM::StoreOp::create(builder, op.getLoc(), reachingDefinition,
1321template <
class MemcpyLike>
1332template <
class MemcpyLike>
1337 if (op.getIsVolatile())
1340 if (!cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap())
1350 if (op.getSrc() == slot.
ptr)
1351 usedIndices.insert_range(llvm::make_first_range(slot.
subelementTypes));
1358template <
class MemcpyLike>
1361 Type toCpy,
bool isVolatile) {
1363 LLVM::ConstantOp::create(builder, toReplace.getLoc(),
1364 IntegerAttr::get(toReplace.getLen().getType(),
1366 MemcpyLike::create(builder, toReplace.getLoc(), dst, src, memcpySize,
1372 LLVM::MemcpyInlineOp toReplace,
Value dst,
1373 Value src,
Type toCpy,
bool isVolatile) {
1374 Type lenType = IntegerType::get(toReplace->getContext(),
1375 toReplace.getLen().getBitWidth());
1376 LLVM::MemcpyInlineOp::create(
1377 builder, toReplace.getLoc(), dst, src,
1378 IntegerAttr::get(lenType, layout.
getTypeSize(toCpy)), isVolatile);
1385template <
class MemcpyLike>
1390 if (subslots.empty())
1393 assert((slot.
ptr == op.getDst()) != (slot.
ptr == op.getSrc()));
1394 bool isDst = slot.
ptr == op.getDst();
1397 size_t slotsTreated = 0;
1402 Type indexType = cast<IntegerAttr>(subslots.begin()->first).getType();
1405 if (!subslots.contains(
index))
1416 0,
static_cast<int32_t
>(
1417 cast<IntegerAttr>(
index).getValue().getZExtValue())};
1418 Value subslotPtrInOther = LLVM::GEPOp::create(
1419 builder, op.getLoc(), LLVM::LLVMPointerType::get(op.getContext()),
1420 slot.
elemType, isDst ? op.getSrc() : op.getDst(), gepIndices);
1423 createMemcpyLikeToReplace(builder, dataLayout, op,
1424 isDst ? subslot.
ptr : subslotPtrInOther,
1425 isDst ? subslotPtrInOther : subslot.
ptr,
1426 subslot.
elemType, op.getIsVolatile());
1429 assert(subslots.size() == slotsTreated);
1434bool LLVM::MemcpyOp::loadsFrom(
const MemorySlot &slot) {
1438bool LLVM::MemcpyOp::storesTo(
const MemorySlot &slot) {
1448bool LLVM::MemcpyOp::canUsesBeRemoved(
1461 reachingDefinition);
1464LogicalResult LLVM::MemcpyOp::ensureOnlySafeAccesses(
1482 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1485bool LLVM::MemcpyInlineOp::loadsFrom(
const MemorySlot &slot) {
1489bool LLVM::MemcpyInlineOp::storesTo(
const MemorySlot &slot) {
1499bool LLVM::MemcpyInlineOp::canUsesBeRemoved(
1512 reachingDefinition);
1515LogicalResult LLVM::MemcpyInlineOp::ensureOnlySafeAccesses(
1521bool LLVM::MemcpyInlineOp::canRewire(
1534 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1537bool LLVM::MemmoveOp::loadsFrom(
const MemorySlot &slot) {
1541bool LLVM::MemmoveOp::storesTo(
const MemorySlot &slot) {
1551bool LLVM::MemmoveOp::canUsesBeRemoved(
1564 reachingDefinition);
1567LogicalResult LLVM::MemmoveOp::ensureOnlySafeAccesses(
1585 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1592std::optional<DenseMap<Attribute, Type>>
1593LLVM::LLVMStructType::getSubelementIndexMap()
const {
1595 if (getBody().empty())
1596 return std::nullopt;
1599 for (
const auto &[
index, elemType] : llvm::enumerate(getBody()))
1600 destructured.insert({IntegerAttr::get(i32,
index), elemType});
1601 return destructured;
1605 auto indexAttr = llvm::dyn_cast<IntegerAttr>(
index);
1606 if (!indexAttr || !indexAttr.getType().isInteger(32))
1608 int32_t indexInt = indexAttr.getInt();
1610 if (indexInt < 0 || body.size() <=
static_cast<uint32_t
>(indexInt))
1612 return body[indexInt];
1615std::optional<DenseMap<Attribute, Type>>
1616LLVM::LLVMArrayType::getSubelementIndexMap()
const {
1617 constexpr size_t maxArraySizeForDestructuring = 16;
1625 destructured.insert({IntegerAttr::get(i32, index), getElementType()});
1626 return destructured;
1630 auto indexAttr = llvm::dyn_cast<IntegerAttr>(
index);
1631 if (!indexAttr || !indexAttr.getType().isInteger(32))
1633 int32_t indexInt = indexAttr.getInt();
1634 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 Type getElementType(Type type)
Determine the element type of type.
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`
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.