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::StripInvariantGroupOp::canUsesBeRemoved(
629DeletionKind LLVM::StripInvariantGroupOp::removeBlockingUses(
634bool LLVM::DbgDeclareOp::canUsesBeRemoved(
646bool LLVM::DbgValueOp::canUsesBeRemoved(
651 if (blockingUses.size() != 1)
654 return (*blockingUses.begin())->get() == getValue();
666 UndefOp::create(builder, getValue().getLoc(), getValue().
getType());
667 getValueMutable().assign(undef);
671bool LLVM::DbgDeclareOp::requiresReplacedValues() {
return true; }
673void LLVM::DbgDeclareOp::visitReplacedValues(
675 for (
auto [op, value] : definitions) {
677 LLVM::DbgValueOp::create(builder, getLoc(), value, getVarInfo(),
687 return llvm::all_of(gepOp.getIndices(), [](
auto index) {
688 auto indexAttr = llvm::dyn_cast_if_present<IntegerAttr>(index);
689 return indexAttr && indexAttr.getValue() == 0;
693bool LLVM::GEPOp::canUsesBeRemoved(
714 for (
auto index : gep.getIndices()) {
715 auto constIndex = dyn_cast<IntegerAttr>(
index);
718 int64_t gepIndex = constIndex.getInt();
725 Type currentType = gep.getElemType();
731 .Case([&](LLVM::LLVMArrayType arrayType) {
734 currentType = arrayType.getElementType();
737 .Case([&](LLVM::LLVMStructType structType) {
739 assert(
index < body.size() &&
"expected valid struct indexing");
740 for (uint32_t i : llvm::seq(
index)) {
741 if (!structType.isPacked())
742 offset = llvm::alignTo(
748 if (!structType.isPacked())
749 offset = llvm::alignTo(
751 currentType = body[
index];
754 .Default([&](
Type type) {
755 LDBG() <<
"[sroa] Unsupported type for offset computations"
770struct SubslotAccessInfo {
774 uint64_t subslotOffset;
782static std::optional<SubslotAccessInfo>
784 const DataLayout &dataLayout, LLVM::GEPOp gep) {
792 auto isOutOfBoundsGEPIndex = [](uint64_t
index) {
800 .Case([&](LLVM::LLVMArrayType arrayType)
801 -> std::optional<SubslotAccessInfo> {
803 uint64_t elemSize = dataLayout.
getTypeSize(arrayType.getElementType());
804 uint64_t
index = *offset / elemSize;
805 if (isOutOfBoundsGEPIndex(
index))
807 return SubslotAccessInfo{
static_cast<uint32_t
>(
index),
808 *offset - (
index * elemSize)};
810 .Case([&](LLVM::LLVMStructType structType)
811 -> std::optional<SubslotAccessInfo> {
812 uint64_t distanceToStart = 0;
815 for (
auto [
index, elem] : llvm::enumerate(structType.getBody())) {
817 if (!structType.isPacked()) {
818 distanceToStart = llvm::alignTo(
821 if (offset < distanceToStart)
825 if (offset < distanceToStart + elemSize) {
826 if (isOutOfBoundsGEPIndex(
index))
830 return SubslotAccessInfo{
static_cast<uint32_t
>(
index),
831 *offset - distanceToStart};
836 distanceToStart += elemSize;
846 auto byteType = IntegerType::get(context, 8);
847 return LLVM::LLVMArrayType::get(context, byteType, size);
850LogicalResult LLVM::GEPOp::ensureOnlySafeAccesses(
855 std::optional<uint64_t> gepOffset =
gepToByteOffset(dataLayout, *
this);
860 if (*gepOffset >= slotSize)
878 std::optional<SubslotAccessInfo> accessInfo =
883 IntegerAttr::get(IntegerType::get(
getContext(), 32), accessInfo->index);
885 usedIndices.insert(indexAttr);
890 uint64_t slotSize = dataLayout.
getTypeSize(subslotType);
891 LLVM::LLVMArrayType remainingSlotType =
893 mustBeSafelyUsed.emplace_back<
MemorySlot>({getRes(), remainingSlotType});
902 std::optional<SubslotAccessInfo> accessInfo =
904 assert(accessInfo &&
"expected access info to be checked before");
906 IntegerAttr::get(IntegerType::get(
getContext(), 32), accessInfo->index);
907 const MemorySlot &newSlot = subslots.at(indexAttr);
909 auto byteType = IntegerType::get(builder.
getContext(), 8);
911 getLoc(), getResult().getType(), byteType, newSlot.
ptr,
913 getResult().replaceAllUsesWith(newPtr);
925template <
class MemIntr>
926std::optional<uint64_t> getStaticMemIntrLen(MemIntr op) {
930 if (memIntrLen.getBitWidth() > 64)
932 return memIntrLen.getZExtValue();
940std::optional<uint64_t> getStaticMemIntrLen(LLVM::MemcpyInlineOp op) {
941 APInt memIntrLen = op.getLen();
942 if (memIntrLen.getBitWidth() > 64)
944 return memIntrLen.getZExtValue();
952std::optional<uint64_t> getStaticMemIntrLen(LLVM::MemsetInlineOp op) {
953 APInt memIntrLen = op.getLen();
954 if (memIntrLen.getBitWidth() > 64)
956 return memIntrLen.getZExtValue();
960template <
class MemsetIntr>
961IntegerAttr createMemsetLenAttr(MemsetIntr op) {
962 IntegerAttr memsetLenAttr;
963 bool successfulMatch =
965 (
void)successfulMatch;
966 assert(successfulMatch);
967 return memsetLenAttr;
974IntegerAttr createMemsetLenAttr(LLVM::MemsetInlineOp op) {
975 return op.getLenAttr();
981template <
class MemsetIntr>
982void createMemsetIntr(
OpBuilder &builder, MemsetIntr toReplace,
983 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
988void createMemsetIntr(
OpBuilder &builder, LLVM::MemsetOp toReplace,
989 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
992 Value newMemsetSizeValue =
993 LLVM::ConstantOp::create(
994 builder, toReplace.getLen().getLoc(),
995 IntegerAttr::get(memsetLenAttr.getType(), newMemsetSize))
998 LLVM::MemsetOp::create(builder, toReplace.getLoc(), subslots.at(
index).ptr,
999 toReplace.getVal(), newMemsetSizeValue,
1000 toReplace.getIsVolatile());
1004void createMemsetIntr(
OpBuilder &builder, LLVM::MemsetInlineOp toReplace,
1005 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
1008 auto newMemsetSizeValue =
1009 IntegerAttr::get(memsetLenAttr.getType(), newMemsetSize);
1011 LLVM::MemsetInlineOp::create(builder, toReplace.getLoc(),
1012 subslots.at(
index).ptr, toReplace.getVal(),
1013 newMemsetSizeValue, toReplace.getIsVolatile());
1020template <
class MemIntr>
1023 if (!isa<LLVM::LLVMPointerType>(slot.
ptr.
getType()) ||
1024 op.getDst() != slot.
ptr)
1027 std::optional<uint64_t> memIntrLen = getStaticMemIntrLen(op);
1037 auto intIndex = dyn_cast<IntegerAttr>(index);
1038 return intIndex && intIndex.getType() == i32;
1046template <
class MemsetIntr>
1054 if (op.getIsVolatile())
1057 if (!cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap())
1066template <
class MemsetIntr>
1071 auto buildMemsetValue = [&](
unsigned width) ->
Value {
1072 assert(width % 8 == 0);
1073 auto intType = IntegerType::get(op.getContext(), width);
1077 IntegerAttr constantPattern;
1079 assert(constantPattern.getValue().getBitWidth() == 8);
1080 APInt memsetVal(width, 0);
1081 for (
unsigned loBit = 0; loBit < width; loBit += 8)
1082 memsetVal.insertBits(constantPattern.getValue(), loBit);
1083 return LLVM::ConstantOp::create(builder, op.getLoc(),
1084 IntegerAttr::get(intType, memsetVal));
1093 uint64_t coveredBits = 8;
1094 Value currentValue =
1095 LLVM::ZExtOp::create(builder, op.getLoc(), intType, op.getVal());
1096 while (coveredBits < width) {
1098 LLVM::ConstantOp::create(builder, op.getLoc(), intType, coveredBits);
1100 LLVM::ShlOp::create(builder, op.getLoc(), currentValue, shiftBy);
1102 LLVM::OrOp::create(builder, op.getLoc(), currentValue, shifted);
1106 return currentValue;
1109 .Case([&](IntegerType type) ->
Value {
1110 return buildMemsetValue(type.getWidth());
1112 .Case([&](FloatType type) ->
Value {
1113 Value intVal = buildMemsetValue(type.getWidth());
1114 return LLVM::BitcastOp::create(builder, op.getLoc(), type, intVal);
1116 .DefaultUnreachable(
1117 "getStored should not be called on memset to unsupported type");
1120template <
class MemsetIntr>
1126 bool canConvertType =
1128 .Case<IntegerType, FloatType>([](
auto type) {
1129 return type.getWidth() % 8 == 0 && type.getWidth() > 0;
1132 if (!canConvertType)
1135 if (op.getIsVolatile())
1141template <
class MemsetIntr>
1147 std::optional<DenseMap<Attribute, Type>> types =
1148 cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap();
1150 IntegerAttr memsetLenAttr = createMemsetLenAttr(op);
1152 bool packed =
false;
1153 if (
auto structType = dyn_cast<LLVM::LLVMStructType>(slot.
elemType))
1154 packed = structType.isPacked();
1156 Type i32 = IntegerType::get(op.getContext(), 32);
1157 uint64_t memsetLen = memsetLenAttr.getValue().getZExtValue();
1158 uint64_t covered = 0;
1159 for (
size_t i = 0; i < types->size(); i++) {
1163 uint64_t typeSize = dataLayout.
getTypeSize(elemType);
1169 if (covered >= memsetLen)
1174 if (subslots.contains(
index)) {
1175 uint64_t newMemsetSize = std::min(memsetLen - covered, typeSize);
1176 createMemsetIntr(builder, op, memsetLenAttr, newMemsetSize, subslots,
1180 covered += typeSize;
1186bool LLVM::MemsetOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1188bool LLVM::MemsetOp::storesTo(
const MemorySlot &slot) {
1189 return getDst() == slot.
ptr;
1198bool LLVM::MemsetOp::canUsesBeRemoved(
1213LogicalResult LLVM::MemsetOp::ensureOnlySafeAccesses(
1231 return memsetRewire(*
this, slot, subslots, builder, dataLayout);
1234bool LLVM::MemsetInlineOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1236bool LLVM::MemsetInlineOp::storesTo(
const MemorySlot &slot) {
1237 return getDst() == slot.
ptr;
1246bool LLVM::MemsetInlineOp::canUsesBeRemoved(
1261LogicalResult LLVM::MemsetInlineOp::ensureOnlySafeAccesses(
1267bool LLVM::MemsetInlineOp::canRewire(
1280 return memsetRewire(*
this, slot, subslots, builder, dataLayout);
1287template <
class MemcpyLike>
1289 return op.getSrc() == slot.
ptr;
1292template <
class MemcpyLike>
1294 return op.getDst() == slot.
ptr;
1297template <
class MemcpyLike>
1300 return LLVM::LoadOp::create(builder, op.getLoc(), slot.
elemType, op.getSrc());
1303template <
class MemcpyLike>
1312 if (op.getDst() == op.getSrc())
1315 if (op.getIsVolatile())
1321template <
class MemcpyLike>
1326 if (op.loadsFrom(slot))
1327 LLVM::StoreOp::create(builder, op.getLoc(), reachingDefinition,
1332template <
class MemcpyLike>
1343template <
class MemcpyLike>
1348 if (op.getIsVolatile())
1351 if (!cast<DestructurableTypeInterface>(slot.
elemType).getSubelementIndexMap())
1361 if (op.getSrc() == slot.
ptr)
1362 usedIndices.insert_range(llvm::make_first_range(slot.
subelementTypes));
1369template <
class MemcpyLike>
1372 Type toCpy,
bool isVolatile) {
1374 LLVM::ConstantOp::create(builder, toReplace.getLoc(),
1375 IntegerAttr::get(toReplace.getLen().getType(),
1377 MemcpyLike::create(builder, toReplace.getLoc(), dst, src, memcpySize,
1383 LLVM::MemcpyInlineOp toReplace,
Value dst,
1384 Value src,
Type toCpy,
bool isVolatile) {
1385 Type lenType = IntegerType::get(toReplace->getContext(),
1386 toReplace.getLen().getBitWidth());
1387 LLVM::MemcpyInlineOp::create(
1388 builder, toReplace.getLoc(), dst, src,
1389 IntegerAttr::get(lenType, layout.
getTypeSize(toCpy)), isVolatile);
1396template <
class MemcpyLike>
1401 if (subslots.empty())
1404 assert((slot.
ptr == op.getDst()) != (slot.
ptr == op.getSrc()));
1405 bool isDst = slot.
ptr == op.getDst();
1408 size_t slotsTreated = 0;
1413 Type indexType = cast<IntegerAttr>(subslots.begin()->first).getType();
1416 if (!subslots.contains(
index))
1427 0,
static_cast<int32_t
>(
1428 cast<IntegerAttr>(
index).getValue().getZExtValue())};
1429 Value subslotPtrInOther = LLVM::GEPOp::create(
1430 builder, op.getLoc(), LLVM::LLVMPointerType::get(op.getContext()),
1431 slot.
elemType, isDst ? op.getSrc() : op.getDst(), gepIndices);
1434 createMemcpyLikeToReplace(builder, dataLayout, op,
1435 isDst ? subslot.
ptr : subslotPtrInOther,
1436 isDst ? subslotPtrInOther : subslot.
ptr,
1437 subslot.
elemType, op.getIsVolatile());
1440 assert(subslots.size() == slotsTreated);
1445bool LLVM::MemcpyOp::loadsFrom(
const MemorySlot &slot) {
1449bool LLVM::MemcpyOp::storesTo(
const MemorySlot &slot) {
1459bool LLVM::MemcpyOp::canUsesBeRemoved(
1472 reachingDefinition);
1475LogicalResult LLVM::MemcpyOp::ensureOnlySafeAccesses(
1493 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1496bool LLVM::MemcpyInlineOp::loadsFrom(
const MemorySlot &slot) {
1500bool LLVM::MemcpyInlineOp::storesTo(
const MemorySlot &slot) {
1510bool LLVM::MemcpyInlineOp::canUsesBeRemoved(
1523 reachingDefinition);
1526LogicalResult LLVM::MemcpyInlineOp::ensureOnlySafeAccesses(
1532bool LLVM::MemcpyInlineOp::canRewire(
1545 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1548bool LLVM::MemmoveOp::loadsFrom(
const MemorySlot &slot) {
1552bool LLVM::MemmoveOp::storesTo(
const MemorySlot &slot) {
1562bool LLVM::MemmoveOp::canUsesBeRemoved(
1575 reachingDefinition);
1578LogicalResult LLVM::MemmoveOp::ensureOnlySafeAccesses(
1596 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1603std::optional<DenseMap<Attribute, Type>>
1604LLVM::LLVMStructType::getSubelementIndexMap()
const {
1606 if (getBody().empty())
1607 return std::nullopt;
1610 for (
const auto &[
index, elemType] : llvm::enumerate(getBody()))
1611 destructured.insert({IntegerAttr::get(i32,
index), elemType});
1612 return destructured;
1616 auto indexAttr = llvm::dyn_cast<IntegerAttr>(
index);
1617 if (!indexAttr || !indexAttr.getType().isInteger(32))
1619 int32_t indexInt = indexAttr.getInt();
1621 if (indexInt < 0 || body.size() <=
static_cast<uint32_t
>(indexInt))
1623 return body[indexInt];
1626std::optional<DenseMap<Attribute, Type>>
1627LLVM::LLVMArrayType::getSubelementIndexMap()
const {
1628 constexpr size_t maxArraySizeForDestructuring = 16;
1636 destructured.insert({IntegerAttr::get(i32, index), getElementType()});
1637 return destructured;
1641 auto indexAttr = llvm::dyn_cast<IntegerAttr>(
index);
1642 if (!indexAttr || !indexAttr.getType().isInteger(32))
1644 int32_t indexInt = indexAttr.getInt();
1645 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.