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.
valueType);
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 &&
391 getResult().
getType(), dataLayout);
392 getResult().replaceAllUsesWith(newResult);
396bool LLVM::StoreOp::canUsesBeRemoved(
400 if (blockingUses.size() != 1)
402 Value blockingUse = (*blockingUses.begin())->get();
406 return blockingUse == slot.
ptr && getAddr() == slot.
ptr &&
407 getValue() != slot.
ptr &&
428LogicalResult LLVM::LoadOp::ensureOnlySafeAccesses(
435LogicalResult LLVM::StoreOp::ensureOnlySafeAccesses(
445 auto subelementIndexMap =
446 cast<DestructurableTypeInterface>(slot.
valueType).getSubelementIndexMap();
447 if (!subelementIndexMap)
449 assert(!subelementIndexMap->empty());
452 return subelementIndexMap->lookup(
index);
472 usedIndices.insert(
index);
481 auto it = subslots.find(
index);
482 assert(it != subslots.end());
484 getAddrMutable().set(it->getSecond().ptr);
496 if (getValue() == slot.
ptr)
510 usedIndices.insert(
index);
519 auto it = subslots.find(
index);
520 assert(it != subslots.end());
522 getAddrMutable().set(it->getSecond().ptr);
535 newBlockingUses.push_back(&use);
539bool LLVM::BitcastOp::canUsesBeRemoved(
551bool LLVM::AddrSpaceCastOp::canUsesBeRemoved(
563bool LLVM::LifetimeStartOp::canUsesBeRemoved(
575bool LLVM::LifetimeEndOp::canUsesBeRemoved(
587bool LLVM::InvariantStartOp::canUsesBeRemoved(
599bool LLVM::InvariantEndOp::canUsesBeRemoved(
611bool LLVM::LaunderInvariantGroupOp::canUsesBeRemoved(
618DeletionKind LLVM::LaunderInvariantGroupOp::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(
705 for (
auto index : gep.getIndices()) {
706 auto constIndex = dyn_cast<IntegerAttr>(
index);
709 int64_t gepIndex = constIndex.getInt();
716 Type currentType = gep.getElemType();
722 .Case([&](LLVM::LLVMArrayType arrayType) {
725 currentType = arrayType.getElementType();
728 .Case([&](LLVM::LLVMStructType structType) {
729 offset += structType.getElementOffset(dataLayout,
index);
730 currentType = structType.getBody()[
index];
733 .Default([&](
Type type) {
734 LDBG() <<
"[sroa] Unsupported type for offset computations"
749struct SubslotAccessInfo {
753 uint64_t subslotOffset;
761static std::optional<SubslotAccessInfo>
763 const DataLayout &dataLayout, LLVM::GEPOp gep) {
771 auto isOutOfBoundsGEPIndex = [](uint64_t
index) {
779 .Case([&](LLVM::LLVMArrayType arrayType)
780 -> std::optional<SubslotAccessInfo> {
782 uint64_t elemSize = dataLayout.
getTypeSize(arrayType.getElementType());
783 uint64_t
index = *offset / elemSize;
784 if (isOutOfBoundsGEPIndex(
index))
786 return SubslotAccessInfo{
static_cast<uint32_t
>(
index),
787 *offset - (
index * elemSize)};
789 .Case([&](LLVM::LLVMStructType structType)
790 -> std::optional<SubslotAccessInfo> {
793 for (
auto [
index, elem] : llvm::enumerate(structType.getBody())) {
794 uint64_t elemOffset = structType.getElementOffset(dataLayout,
index);
796 if (*offset < elemOffset)
799 if (*offset < elemOffset + dataLayout.
getTypeSize(elem)) {
800 if (isOutOfBoundsGEPIndex(
index))
804 return SubslotAccessInfo{
static_cast<uint32_t
>(
index),
805 *offset - elemOffset};
816 auto byteType = IntegerType::get(context, 8);
817 return LLVM::LLVMArrayType::get(context, byteType, size);
820LogicalResult LLVM::GEPOp::ensureOnlySafeAccesses(
825 std::optional<uint64_t> gepOffset =
gepToByteOffset(dataLayout, *
this);
830 if (*gepOffset >= slotSize)
850 if (getInrangeAttr())
852 std::optional<SubslotAccessInfo> accessInfo =
857 IntegerAttr::get(IntegerType::get(
getContext(), 32), accessInfo->index);
859 usedIndices.insert(indexAttr);
864 uint64_t slotSize = dataLayout.
getTypeSize(subslotType);
865 LLVM::LLVMArrayType remainingSlotType =
867 mustBeSafelyUsed.emplace_back<
MemorySlot>({getRes(), remainingSlotType});
876 std::optional<SubslotAccessInfo> accessInfo =
878 assert(accessInfo &&
"expected access info to be checked before");
880 IntegerAttr::get(IntegerType::get(
getContext(), 32), accessInfo->index);
881 const MemorySlot &newSlot = subslots.at(indexAttr);
883 auto byteType = IntegerType::get(builder.
getContext(), 8);
885 getLoc(), getResult().getType(), byteType, newSlot.
ptr,
887 getResult().replaceAllUsesWith(newPtr);
899template <
class MemIntr>
900std::optional<uint64_t> getStaticMemIntrLen(MemIntr op) {
904 if (memIntrLen.getBitWidth() > 64)
906 return memIntrLen.getZExtValue();
914std::optional<uint64_t> getStaticMemIntrLen(LLVM::MemcpyInlineOp op) {
915 APInt memIntrLen = op.getLen();
916 if (memIntrLen.getBitWidth() > 64)
918 return memIntrLen.getZExtValue();
926std::optional<uint64_t> getStaticMemIntrLen(LLVM::MemsetInlineOp op) {
927 APInt memIntrLen = op.getLen();
928 if (memIntrLen.getBitWidth() > 64)
930 return memIntrLen.getZExtValue();
934template <
class MemsetIntr>
935IntegerAttr createMemsetLenAttr(MemsetIntr op) {
936 IntegerAttr memsetLenAttr;
937 bool successfulMatch =
939 (
void)successfulMatch;
940 assert(successfulMatch);
941 return memsetLenAttr;
948IntegerAttr createMemsetLenAttr(LLVM::MemsetInlineOp op) {
949 return op.getLenAttr();
955template <
class MemsetIntr>
956void createMemsetIntr(
OpBuilder &builder, MemsetIntr toReplace,
957 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
962void createMemsetIntr(
OpBuilder &builder, LLVM::MemsetOp toReplace,
963 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
966 Value newMemsetSizeValue =
967 LLVM::ConstantOp::create(
968 builder, toReplace.getLen().getLoc(),
969 IntegerAttr::get(memsetLenAttr.getType(), newMemsetSize))
972 LLVM::MemsetOp::create(builder, toReplace.getLoc(), subslots.at(
index).ptr,
973 toReplace.getVal(), newMemsetSizeValue,
974 toReplace.getIsVolatile());
978void createMemsetIntr(
OpBuilder &builder, LLVM::MemsetInlineOp toReplace,
979 IntegerAttr memsetLenAttr, uint64_t newMemsetSize,
982 auto newMemsetSizeValue =
983 IntegerAttr::get(memsetLenAttr.getType(), newMemsetSize);
985 LLVM::MemsetInlineOp::create(builder, toReplace.getLoc(),
986 subslots.at(
index).ptr, toReplace.getVal(),
987 newMemsetSizeValue, toReplace.getIsVolatile());
994template <
class MemIntr>
997 if (!isa<LLVM::LLVMPointerType>(slot.
ptr.
getType()) ||
998 op.getDst() != slot.
ptr)
1001 std::optional<uint64_t> memIntrLen = getStaticMemIntrLen(op);
1011 auto intIndex = dyn_cast<IntegerAttr>(index);
1012 return intIndex && intIndex.getType() == i32;
1020template <
class MemsetIntr>
1028 if (op.getIsVolatile())
1031 if (!cast<DestructurableTypeInterface>(slot.
valueType)
1032 .getSubelementIndexMap())
1041template <
class MemsetIntr>
1046 auto buildMemsetValue = [&](
unsigned width) ->
Value {
1047 assert(width % 8 == 0);
1048 auto intType = IntegerType::get(op.getContext(), width);
1052 IntegerAttr constantPattern;
1054 assert(constantPattern.getValue().getBitWidth() == 8);
1055 APInt memsetVal(width, 0);
1056 for (
unsigned loBit = 0; loBit < width; loBit += 8)
1057 memsetVal.insertBits(constantPattern.getValue(), loBit);
1058 return LLVM::ConstantOp::create(builder, op.getLoc(),
1059 IntegerAttr::get(intType, memsetVal));
1068 uint64_t coveredBits = 8;
1069 Value currentValue =
1070 LLVM::ZExtOp::create(builder, op.getLoc(), intType, op.getVal());
1071 while (coveredBits < width) {
1073 LLVM::ConstantOp::create(builder, op.getLoc(), intType, coveredBits);
1075 LLVM::ShlOp::create(builder, op.getLoc(), currentValue, shiftBy);
1077 LLVM::OrOp::create(builder, op.getLoc(), currentValue, shifted);
1081 return currentValue;
1084 .Case([&](IntegerType type) ->
Value {
1085 return buildMemsetValue(type.getWidth());
1087 .Case([&](FloatType type) ->
Value {
1088 Value intVal = buildMemsetValue(type.getWidth());
1089 return LLVM::BitcastOp::create(builder, op.getLoc(), type, intVal);
1091 .DefaultUnreachable(
1092 "getStored should not be called on memset to unsupported type");
1095template <
class MemsetIntr>
1101 bool canConvertType =
1103 .Case<IntegerType, FloatType>([](
auto type) {
1104 return type.getWidth() % 8 == 0 && type.getWidth() > 0;
1107 if (!canConvertType)
1110 if (op.getIsVolatile())
1116template <
class MemsetIntr>
1122 std::optional<DenseMap<Attribute, Type>> types =
1123 cast<DestructurableTypeInterface>(slot.
valueType).getSubelementIndexMap();
1125 IntegerAttr memsetLenAttr = createMemsetLenAttr(op);
1127 auto structType = dyn_cast<LLVM::LLVMStructType>(slot.
valueType);
1129 Type i32 = IntegerType::get(op.getContext(), 32);
1130 uint64_t memsetLen = memsetLenAttr.getValue().getZExtValue();
1131 for (
size_t i = 0; i < types->size(); i++) {
1135 uint64_t typeSize = dataLayout.
getTypeSize(elemType);
1136 uint64_t offset = structType ? structType.getElementOffset(dataLayout, i)
1138 if (offset >= memsetLen)
1142 if (subslots.contains(
index)) {
1143 uint64_t newMemsetSize = std::min(memsetLen - offset, typeSize);
1144 createMemsetIntr(builder, op, memsetLenAttr, newMemsetSize, subslots,
1152bool LLVM::MemsetOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1154bool LLVM::MemsetOp::storesTo(
const MemorySlot &slot) {
1155 return getDst() == slot.
ptr;
1164bool LLVM::MemsetOp::canUsesBeRemoved(
1179LogicalResult LLVM::MemsetOp::ensureOnlySafeAccesses(
1197 return memsetRewire(*
this, slot, subslots, builder, dataLayout);
1200bool LLVM::MemsetInlineOp::loadsFrom(
const MemorySlot &slot) {
return false; }
1202bool LLVM::MemsetInlineOp::storesTo(
const MemorySlot &slot) {
1203 return getDst() == slot.
ptr;
1212bool LLVM::MemsetInlineOp::canUsesBeRemoved(
1227LogicalResult LLVM::MemsetInlineOp::ensureOnlySafeAccesses(
1233bool LLVM::MemsetInlineOp::canRewire(
1246 return memsetRewire(*
this, slot, subslots, builder, dataLayout);
1253template <
class MemcpyLike>
1255 return op.getSrc() == slot.
ptr;
1258template <
class MemcpyLike>
1260 return op.getDst() == slot.
ptr;
1263template <
class MemcpyLike>
1266 return LLVM::LoadOp::create(builder, op.getLoc(), slot.
valueType,
1270template <
class MemcpyLike>
1279 if (op.getDst() == op.getSrc())
1282 if (op.getIsVolatile())
1288template <
class MemcpyLike>
1293 if (op.loadsFrom(slot))
1294 LLVM::StoreOp::create(builder, op.getLoc(), reachingDefinition,
1299template <
class MemcpyLike>
1310template <
class MemcpyLike>
1315 if (op.getIsVolatile())
1318 if (!cast<DestructurableTypeInterface>(slot.
valueType)
1319 .getSubelementIndexMap())
1329 if (op.getSrc() == slot.
ptr)
1330 usedIndices.insert_range(llvm::make_first_range(slot.
subelementTypes));
1337template <
class MemcpyLike>
1340 Type toCpy,
bool isVolatile) {
1342 LLVM::ConstantOp::create(builder, toReplace.getLoc(),
1343 IntegerAttr::get(toReplace.getLen().getType(),
1345 MemcpyLike::create(builder, toReplace.getLoc(), dst, src, memcpySize,
1351 LLVM::MemcpyInlineOp toReplace,
Value dst,
1352 Value src,
Type toCpy,
bool isVolatile) {
1353 Type lenType = IntegerType::get(toReplace->getContext(),
1354 toReplace.getLen().getBitWidth());
1355 LLVM::MemcpyInlineOp::create(
1356 builder, toReplace.getLoc(), dst, src,
1357 IntegerAttr::get(lenType, layout.
getTypeSize(toCpy)), isVolatile);
1364template <
class MemcpyLike>
1369 if (subslots.empty())
1372 assert((slot.
ptr == op.getDst()) != (slot.
ptr == op.getSrc()));
1373 bool isDst = slot.
ptr == op.getDst();
1376 size_t slotsTreated = 0;
1381 Type indexType = cast<IntegerAttr>(subslots.begin()->first).getType();
1384 if (!subslots.contains(
index))
1395 0,
static_cast<int32_t
>(
1396 cast<IntegerAttr>(
index).getValue().getZExtValue())};
1397 Value subslotPtrInOther = LLVM::GEPOp::create(
1398 builder, op.getLoc(), LLVM::LLVMPointerType::get(op.getContext()),
1399 slot.
valueType, isDst ? op.getSrc() : op.getDst(), gepIndices);
1402 createMemcpyLikeToReplace(builder, dataLayout, op,
1403 isDst ? subslot.
ptr : subslotPtrInOther,
1404 isDst ? subslotPtrInOther : subslot.
ptr,
1408 assert(subslots.size() == slotsTreated);
1413bool LLVM::MemcpyOp::loadsFrom(
const MemorySlot &slot) {
1417bool LLVM::MemcpyOp::storesTo(
const MemorySlot &slot) {
1427bool LLVM::MemcpyOp::canUsesBeRemoved(
1440 reachingDefinition);
1443LogicalResult LLVM::MemcpyOp::ensureOnlySafeAccesses(
1461 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1464bool LLVM::MemcpyInlineOp::loadsFrom(
const MemorySlot &slot) {
1468bool LLVM::MemcpyInlineOp::storesTo(
const MemorySlot &slot) {
1478bool LLVM::MemcpyInlineOp::canUsesBeRemoved(
1491 reachingDefinition);
1494LogicalResult LLVM::MemcpyInlineOp::ensureOnlySafeAccesses(
1500bool LLVM::MemcpyInlineOp::canRewire(
1513 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1516bool LLVM::MemmoveOp::loadsFrom(
const MemorySlot &slot) {
1520bool LLVM::MemmoveOp::storesTo(
const MemorySlot &slot) {
1530bool LLVM::MemmoveOp::canUsesBeRemoved(
1543 reachingDefinition);
1546LogicalResult LLVM::MemmoveOp::ensureOnlySafeAccesses(
1564 return memcpyRewire(*
this, slot, subslots, builder, dataLayout);
1571std::optional<DenseMap<Attribute, Type>>
1572LLVM::LLVMStructType::getSubelementIndexMap()
const {
1574 if (getBody().empty())
1575 return std::nullopt;
1578 for (
const auto &[
index, elemType] : llvm::enumerate(getBody()))
1579 destructured.insert({IntegerAttr::get(i32,
index), elemType});
1580 return destructured;
1584 auto indexAttr = llvm::dyn_cast<IntegerAttr>(
index);
1585 if (!indexAttr || !indexAttr.getType().isInteger(32))
1587 int32_t indexInt = indexAttr.getInt();
1589 if (indexInt < 0 || body.size() <=
static_cast<uint32_t
>(indexInt))
1591 return body[indexInt];
1594std::optional<DenseMap<Attribute, Type>>
1595LLVM::LLVMArrayType::getSubelementIndexMap()
const {
1596 constexpr size_t maxArraySizeForDestructuring = 16;
1604 destructured.insert({IntegerAttr::get(i32, index), getElementType()});
1605 return destructured;
1609 auto indexAttr = llvm::dyn_cast<IntegerAttr>(
index);
1610 if (!indexAttr || !indexAttr.getType().isInteger(32))
1612 int32_t indexInt = indexAttr.getInt();
1613 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.
llvm::TypeSize getTypeAllocSize(Type t) const
Returns the offset in bytes between successive objects 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.
Type valueType
Type of the value contained in the slot.
Value ptr
Pointer to the memory slot, used by operations to refer to it.