20#include <mlir/IR/Builders.h>
21#include <mlir/IR/BuiltinAttributes.h>
22#include <mlir/IR/Diagnostics.h>
23#include <mlir/IR/OpImplementation.h>
24#include <mlir/IR/OperationSupport.h>
25#include <mlir/Support/LLVM.h>
27#include <llvm/ADT/STLExtras.h>
28#include <llvm/ADT/SmallString.h>
29#include <llvm/ADT/SmallVectorExtras.h>
30#include <llvm/ADT/StringSet.h>
31#include <llvm/ADT/TypeSwitch.h>
32#include <llvm/Support/Debug.h>
53static void buildCommon(
54 OpBuilder &builder, OperationState &state, PodType result,
InitializedRecords initialValues
56 SmallVector<Value, 4> values;
57 SmallVector<StringRef, 4>
names;
59 for (
const auto &record : initialValues) {
60 names.push_back(record.name);
61 values.push_back(record.value);
65 state.addTypes(result);
66 state.addOperands(values);
72 OpBuilder &builder, OperationState &state, PodType result, ArrayRef<ValueRange> mapOperands,
75 buildCommon(builder, state, result, initialValues);
82 OpBuilder &builder, OperationState &state, PodType result,
InitializedRecords initialValues
84 buildCommon(builder, state, result, initialValues);
101 return {DestructurableMemorySlot {{
getResult(), podType}, std::move(*destructured)}};
108 const DestructurableMemorySlot &slot,
const SmallPtrSetImpl<Attribute> &usedIndices,
109 OpBuilder &builder, SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators
112 assert(slot.elemType == getType());
114 builder.setInsertionPointAfter(*
this);
117 DenseMap<Attribute, MemorySlot> slotMap;
118 for (Attribute index : usedIndices) {
119 auto recordName = llvm::dyn_cast<StringAttr>(index);
120 assert(recordName &&
"expected StringAttr");
122 Type destructAs = getType().getTypeAtIndex(recordName);
123 assert(destructAs == slot.subelementTypes.lookup(recordName));
125 auto destructAsPodTy = llvm::dyn_cast<PodType>(destructAs);
126 assert(destructAsPodTy &&
"expected PodType");
128 SmallVector<RecordValue, 1> initialValue;
130 if (record.name == recordName.getValue()) {
131 initialValue.push_back(record);
136 auto subNew =
NewPodOp::create(builder, getLoc(), destructAsPodTy, initialValue);
137 newAllocators.push_back(subNew);
138 slotMap.try_emplace<MemorySlot>(index, {subNew.getResult(), destructAs});
146 const DestructurableMemorySlot &slot, OpBuilder &
156static Value materializeValueCopyBefore(Operation *anchor, Value
source, OpBuilder &builder) {
160 OpBuilder::InsertionGuard guard(builder);
161 builder.setInsertionPoint(anchor);
163 assert(succeeded(copied) &&
"copy support must be checked before POD promotion");
168static bool canRemovePodAccess(
169 Value podRef, Type accessedType,
const MemorySlot &slot,
170 const SmallPtrSetImpl<OpOperand *> &blockingUses
172 if (blockingUses.size() != 1) {
175 Value blockingUse = (*blockingUses.begin())->get();
176 return blockingUse == slot.ptr && podRef == slot.ptr && accessedType == slot.elemType &&
184 llvm_unreachable(
"getStored() should not be called on ReadPodOp");
189 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
190 SmallVectorImpl<OpOperand *> & ,
const DataLayout &
197 const MemorySlot &,
const SmallPtrSetImpl<OpOperand *> &, OpBuilder &builder,
198 Value reachingDefinition,
const DataLayout &
200 getResult().replaceAllUsesWith(materializeValueCopyBefore(*
this, reachingDefinition, builder));
201 return DeletionKind::Delete;
206 return materializeValueCopyBefore(*
this,
getValue(), builder);
211 const MemorySlot &slot,
const SmallPtrSetImpl<OpOperand *> &blockingUses,
212 SmallVectorImpl<OpOperand *> & ,
const DataLayout &
220 const MemorySlot &,
const SmallPtrSetImpl<OpOperand *> &, OpBuilder &, Value,
const DataLayout &
222 return DeletionKind::Delete;
227 ArrayRef<RecordAttr> records = getType().getRecords();
231 return {MemorySlot {
getResult(), records.front().getType()}};
237 ArrayRef<RecordAttr> records = getType().getRecords();
238 assert(records.size() == 1 &&
"only single-record pods are promotable");
239 assert(records.front().getType() == slot.elemType);
241 StringRef recordName = records.front().getName().getValue();
243 if (record.name == recordName) {
244 return materializeValueCopyBefore(*
this, record.value, builder);
249 if (
auto podType = llvm::dyn_cast<PodType>(slot.elemType)) {
250 OpBuilder::InsertionGuard guard(builder);
251 builder.setInsertionPoint(*
this);
253 SmallVector<ValueRange> mapOperands(groups.begin(), groups.end());
265 const MemorySlot &slot, Value defaultValue, OpBuilder &
268 if (defaultValue && defaultValue.use_empty()) {
269 if (Operation *defOp = defaultValue.getDefiningOp()) {
270 if (llvm::isa<llzk::NonDetOp, NewPodOp>(defOp)) {
281 llvm::TypeSwitch<Type, void>(type)
288 for (
auto a : t.getDimensionSizes()) {
289 if (
auto m = llvm::dyn_cast<AffineMapAttr>(a)) {
290 mapAttrs.push_back(m);
295 if (ArrayAttr params = t.getParams()) {
296 for (
auto param : params) {
297 if (
auto m = llvm::dyn_cast<AffineMapAttr>(param)) {
298 mapAttrs.push_back(m);
302 }).Default([](Type) {});
315static LogicalResult verifyInitialValues(
316 ValueRange values, ArrayRef<Attribute>
names,
PodType retTy,
317 llvm::function_ref<InFlightDiagnostic()> emitError
320 if (
names.size() != values.size()) {
321 emitError() <<
"number of initialized records and initial values does not match ("
322 <<
names.size() <<
" != " << values.size() <<
')';
327 llvm::StringSet<> seenNames;
328 for (
auto [nameAttr, value] : llvm::zip_equal(
names, values)) {
329 auto name = llvm::cast<StringAttr>(nameAttr).getValue();
330 if (seenNames.contains(name)) {
331 emitError() <<
"found duplicated record name '" << name <<
'\'';
334 seenNames.insert(name);
336 if (!records.contains(name)) {
337 emitError() <<
"record '" << name <<
"' is not part of the struct";
342 auto valueTy = value.getType();
343 auto recordTy = records.at(name);
344 if (valueTy != recordTy) {
345 auto err = emitError();
346 err <<
"record '" << name <<
"' expected type " << recordTy <<
" but got " << valueTy;
349 <<
"types " << valueTy <<
" and " << recordTy
350 <<
" can be unified. Perhaps you can add a 'poly.unifiable_cast' operation?";
356 return failure(failed);
359static LogicalResult verifyAffineMapOperands(
NewPodOp *op, Type retTy) {
360 SmallVector<AffineMapAttr> mapAttrs;
363 op->getMapOperands(), op->getNumDimsPerMap(), mapAttrs, *op
371 failed = failed || mlir::failed(x); \
375 auto retTy = llvm::dyn_cast<PodType>(
getResult().getType());
381 return this->emitError();
384 check(verifyAffineMapOperands(
this, retTy));
386 return failure(failed);
395 if (failed(parser.parseSymbolName(name))) {
399 if (parser.parseEqual()) {
402 return parser.parseOperand(operand);
415 SmallVector<Attribute> initializedRecords;
418 llvm::StringMap<UnresolvedOp> initialValuesOperands;
419 auto parseElementFn = [&parser, &initializedRecords, &initialValuesOperands] {
425 initializedRecords.push_back(name);
426 initialValuesOperands.insert({name.getValue(), operand});
429 auto initialValuesLoc = parser.getCurrentLocation();
430 if (parser.parseCommaSeparatedList(AsmParser::Delimiter::OptionalBraces, parseElementFn)) {
433 SmallVector<int32_t> mapOperandsGroupSizes;
434 SmallVector<UnresolvedOp> allMapOperands;
435 Type indexTy = parser.getBuilder().getIndexType();
436 bool colonAlreadyParsed =
true;
437 auto mapOperandsLoc = parser.getCurrentLocation();
440 if (failed(parser.parseOptionalColon())) {
441 colonAlreadyParsed =
false;
442 SmallVector<SmallVector<UnresolvedOp>> mapOperands {};
447 mapOperandsGroupSizes.reserve(mapOperands.size());
448 for (
const auto &subRange : mapOperands) {
449 allMapOperands.append(subRange.begin(), subRange.end());
454 if (!colonAlreadyParsed && parser.parseColon()) {
459 if (parser.parseCustomTypeWithFallback(resultType)) {
464 for (
auto attr : initializedRecords) {
465 auto name = llvm::cast<StringAttr>(attr);
466 auto lookup = resultType.
getRecord(name.getValue(), [&parser, initialValuesLoc] {
467 return parser.emitError(initialValuesLoc);
469 if (failed(lookup)) {
472 const auto &operand = initialValuesOperands.at(name.getValue());
473 if (failed(parser.resolveOperands({operand}, *lookup, initialValuesLoc, result.operands))) {
477 props.operandSegmentSizes = {
481 props.mapOpGroupSizes = parser.getBuilder().getDenseI32ArrayAttr(mapOperandsGroupSizes);
482 props.initializedRecords = parser.getBuilder().getArrayAttr(initializedRecords);
483 result.addTypes({resultType});
485 if (failed(parser.resolveOperands(allMapOperands, indexTy, mapOperandsLoc, result.operands))) {
489 auto loc = parser.getCurrentLocation();
490 if (parser.parseOptionalAttrDict(result.attributes)) {
494 return parser.emitError(loc) <<
'\'' << result.name.getStringRef() <<
"' op ";
504 auto &os = printer.getStream();
506 if (!initializedRecords.empty()) {
508 llvm::interleaveComma(initializedRecords, os, [&os, &printer](
auto record) {
509 printer.printSymbolName(record.name);
511 printer.printOperand(record.value);
520 if (
auto validType = llvm::dyn_cast<PodType>(type)) {
521 printer.printStrippedAttrOrType(validType);
523 printer.printType(type);
526 printer.printOptionalAttrDict(
528 {
"initializedRecords",
"mapOpGroupSizes",
"numDimsPerMap",
"operandSegmentSizes"}
532SmallVector<RecordValue>
534 return llvm::map_to_vector(llvm::zip_equal(initialValues, initializedRecords), [](
auto pair) {
535 auto [value, name] = pair;
536 return RecordValue {.name = llvm::cast<StringAttr>(name).getValue(), .value = value};
550 const DestructurableMemorySlot &slot, SmallPtrSetImpl<Attribute> &usedIndices,
551 SmallVectorImpl<MemorySlot> & ,
const DataLayout &
558 if (!slot.subelementTypes.contains(recordName)) {
562 usedIndices.insert(recordName);
568 const DestructurableMemorySlot &slot, DenseMap<Attribute, MemorySlot> &subslots,
569 OpBuilder & ,
const DataLayout &
575 const MemorySlot &memorySlot = subslots.at(recordName);
578 return DeletionKind::Keep;
587LogicalResult readRecordNameProperty(DialectBytecodeReader &reader, StringAttr &recordName) {
588 auto versionOpt = reader.getDialectVersion<
PODDialect>();
589 if (succeeded(versionOpt)) {
591 if (ver.majorVersion < 3) {
593 FlatSymbolRefAttr attr;
594 if (failed(reader.readAttribute(attr))) {
597 recordName = attr.getAttr();
603 return reader.readAttribute(recordName);
606void writeRecordNameProperty(DialectBytecodeWriter &writer, StringAttr recordName) {
607 writer.writeAttribute(recordName);
613 auto &prop = state.getOrAddProperties<
Properties>();
614 return readRecordNameProperty(reader, prop.record_name);
618 writeRecordNameProperty(writer, getProperties().record_name);
622 auto podTy = llvm::dyn_cast<PodType>(
getPodRef().getType());
624 return emitError(
"reference operand expected a plain-old-data struct but got ")
628 auto lookup = podTy.getRecord(
getRecordName(), [
this]() {
return this->emitError(); });
629 if (failed(lookup)) {
634 return emitOpError() <<
"has wrong result type; expected " << *lookup <<
", got "
646 auto &prop = state.getOrAddProperties<
Properties>();
647 return readRecordNameProperty(reader, prop.record_name);
651 writeRecordNameProperty(writer, getProperties().record_name);
655 auto podTy = llvm::dyn_cast<PodType>(
getPodRef().getType());
657 return emitError() <<
"reference operand expected a plain-old-data struct but got "
661 auto lookup = podTy.getRecord(
getRecordName(), [
this]() {
return this->emitError(); });
662 if (failed(lookup)) {
666 if (
getValue().getType() != *lookup) {
667 return emitOpError() <<
"has wrong value type; expected " << *lookup <<
", got "
679 FlatSymbolRefAttr symRef;
680 auto result = parser.parseCustomAttributeWithFallback(symRef);
681 if (succeeded(result)) {
682 name = symRef.getAttr();
688 printer.printSymbolName(name.getValue());
within a display generated by the Derivative if and wherever such third party notices normally appear The contents of the NOTICE file are for informational purposes only and do not modify the License You may add Your own attribution notices within Derivative Works that You alongside or as an addendum to the NOTICE text from the provided that such additional attribution notices cannot be construed as modifying the License You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for or distribution of Your or for any such Derivative Works as a provided Your and distribution of the Work otherwise complies with the conditions stated in this License Submission of Contributions Unless You explicitly state any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this without any additional terms or conditions Notwithstanding the nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions Trademarks This License does not grant permission to use the trade names
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation source
static NonDetOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::mlir::Type res)
void print(::mlir::OpAsmPrinter &p)
static NewPodOp create(::mlir::OpBuilder &builder, ::mlir::Location location, ::llzk::pod::InitializedRecords initialValues={})
::mlir::Operation::operand_range getInitialValues()
::mlir::OperandRangeRange getMapOperands()
::mlir::SmallVector<::llzk::pod::RecordValue > getInitializedRecordValues()
static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::llzk::pod::InitializedRecords initialValues={})
::std::optional<::mlir::PromotableAllocationOpInterface > handlePromotionComplete(const ::mlir::MemorySlot &slot, ::mlir::Value defaultValue, ::mlir::OpBuilder &builder)
Required by PromotableAllocationOpInterface / mem2reg pass.
::llvm::SmallVector<::mlir::DestructurableMemorySlot > getDestructurableSlots()
Required by DestructurableAllocationOpInterface / SROA pass.
::llvm::SmallVector<::mlir::MemorySlot > getPromotableSlots()
Required by PromotableAllocationOpInterface / mem2reg pass.
::mlir::DenseI32ArrayAttr getNumDimsPerMapAttr()
::mlir::TypedValue<::llzk::pod::PodType > getResult()
::mlir::Value getDefaultValue(const ::mlir::MemorySlot &slot, ::mlir::OpBuilder &builder)
Required by PromotableAllocationOpInterface / mem2reg pass.
void getAsmResultNames(::mlir::OpAsmSetValueNameFn setNameFn)
FoldAdaptor::Properties Properties
::llvm::LogicalResult verifyInherentAttrs(::mlir::OperationName opName, ::mlir::NamedAttrList &attrs, llvm::function_ref<::mlir::InFlightDiagnostic()> emitError)
::llvm::LogicalResult verify()
::llvm::DenseMap<::mlir::Attribute, ::mlir::MemorySlot > destructure(const ::mlir::DestructurableMemorySlot &slot, const ::llvm::SmallPtrSetImpl<::mlir::Attribute > &usedIndices, ::mlir::OpBuilder &builder, ::mlir::SmallVectorImpl<::mlir::DestructurableAllocationOpInterface > &newAllocators)
Required by DestructurableAllocationOpInterface / SROA pass.
::std::optional<::mlir::DestructurableAllocationOpInterface > handleDestructuringComplete(const ::mlir::DestructurableMemorySlot &slot, ::mlir::OpBuilder &builder)
Required by DestructurableAllocationOpInterface / SROA pass.
::mlir::ArrayAttr getInitializedRecords()
::mlir::ParseResult parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result)
void handleBlockArgument(const ::mlir::MemorySlot &slot, ::mlir::BlockArgument argument, ::mlir::OpBuilder &builder)
Required by PromotableAllocationOpInterface / mem2reg pass.
Dialect for working with plain-old-data structs.
::mlir::OpOperand & getPodRefMutable()
Gets the mutable operand slot holding the SSA Value for the referenced pod.
::mlir::TypedValue<::llzk::pod::PodType > getPodRef()
Gets the SSA Value for the referenced pod.
inline ::llzk::pod::PodType getPodRefType()
Gets the type of the referenced pod.
::mlir::DeletionKind rewire(const ::mlir::DestructurableMemorySlot &slot, ::llvm::DenseMap<::mlir::Attribute, ::mlir::MemorySlot > &subslots, ::mlir::OpBuilder &builder, const ::mlir::DataLayout &dataLayout)
Required by companion interface DestructurableAccessorOpInterface / SROA pass.
::mlir::StringAttr getRecordNameAttr()
Gets the record name attribute from the pod access op.
bool canRewire(const ::mlir::DestructurableMemorySlot &slot, ::llvm::SmallPtrSetImpl<::mlir::Attribute > &usedIndices, ::mlir::SmallVectorImpl<::mlir::MemorySlot > &mustBeSafelyUsed, const ::mlir::DataLayout &dataLayout)
Required by companion interface DestructurableAccessorOpInterface / SROA pass.
::llvm::FailureOr<::mlir::Type > getRecord(::llvm::StringRef name, ::llvm::function_ref<::mlir::InFlightDiagnostic()>) const
Searches a record by name.
::llvm::StringMap<::mlir::Type > getRecordMap() const
Returns the records in map form.
::std::optional<::llvm::DenseMap<::mlir::Attribute, ::mlir::Type > > getSubelementIndexMap() const
Required by DestructurableTypeInterface / SROA pass.
::llvm::ArrayRef<::llzk::pod::RecordAttr > getRecords() const
::llvm::StringRef getRecordName()
::mlir::TypedValue<::mlir::Type > getResult()
bool canUsesBeRemoved(const ::mlir::MemorySlot &slot, const ::llvm::SmallPtrSetImpl<::mlir::OpOperand * > &blockingUses, ::llvm::SmallVectorImpl<::mlir::OpOperand * > &newBlockingUses, const ::mlir::DataLayout &datalayout)
Required by PromotableMemOpInterface / mem2reg pass.
void writeProperties(::mlir::DialectBytecodeWriter &writer)
::llvm::LogicalResult readProperties(::mlir::DialectBytecodeReader &reader, ::mlir::OperationState &state)
::llvm::LogicalResult verify()
FoldAdaptor::Properties Properties
::mlir::TypedValue<::llzk::pod::PodType > getPodRef()
::mlir::DeletionKind removeBlockingUses(const ::mlir::MemorySlot &slot, const ::llvm::SmallPtrSetImpl< mlir::OpOperand * > &blockingUses, ::mlir::OpBuilder &builder, ::mlir::Value reachingDefinition, const ::mlir::DataLayout &dataLayout)
Required by PromotableMemOpInterface / mem2reg pass.
::mlir::Value getStored(const ::mlir::MemorySlot &slot, ::mlir::OpBuilder &builder, ::mlir::Value reachingDef, const ::mlir::DataLayout &dataLayout)
Required by PromotableMemOpInterface / mem2reg pass.
bool canUsesBeRemoved(const ::mlir::MemorySlot &slot, const ::llvm::SmallPtrSetImpl<::mlir::OpOperand * > &blockingUses, ::llvm::SmallVectorImpl<::mlir::OpOperand * > &newBlockingUses, const ::mlir::DataLayout &datalayout)
Required by PromotableMemOpInterface / mem2reg pass.
::llvm::LogicalResult verify()
::llvm::LogicalResult readProperties(::mlir::DialectBytecodeReader &reader, ::mlir::OperationState &state)
::mlir::TypedValue<::mlir::Type > getValue()
::mlir::TypedValue<::llzk::pod::PodType > getPodRef()
FoldAdaptor::Properties Properties
::mlir::DeletionKind removeBlockingUses(const ::mlir::MemorySlot &slot, const ::llvm::SmallPtrSetImpl< mlir::OpOperand * > &blockingUses, ::mlir::OpBuilder &builder, ::mlir::Value reachingDefinition, const ::mlir::DataLayout &dataLayout)
Required by PromotableMemOpInterface / mem2reg pass.
::mlir::Value getStored(const ::mlir::MemorySlot &slot, ::mlir::OpBuilder &builder, ::mlir::Value reachingDef, const ::mlir::DataLayout &dataLayout)
Required by PromotableMemOpInterface / mem2reg pass.
void writeProperties(::mlir::DialectBytecodeWriter &writer)
::llvm::StringRef getRecordName()
OpClass::Properties & buildInstantiationAttrs(mlir::OpBuilder &odsBuilder, mlir::OperationState &odsState, mlir::ArrayRef< mlir::ValueRange > mapOperands, mlir::DenseI32ArrayAttr numDimsPerMap, int32_t firstSegmentSize=0)
Utility for build() functions that initializes the operandSegmentSizes, mapOpGroupSizes,...
LogicalResult verifyAffineMapInstantiations(OperandRangeRange mapOps, ArrayRef< int32_t > numDimsPerMap, ArrayRef< AffineMapAttr > mapAttrs, Operation *origin)
OpClass::Properties & buildInstantiationAttrsEmpty(mlir::OpBuilder &odsBuilder, mlir::OperationState &odsState, int32_t firstSegmentSize=0)
Utility for build() functions that initializes the operandSegmentSizes, mapOpGroupSizes,...
mlir::ArrayRef< RecordValue > InitializedRecords
OpAsmParser::UnresolvedOperand UnresolvedOp
void collectPodMapAttrs(Type type, SmallVector< AffineMapAttr > &mapAttrs)
ParseResult parseRecordInitialization(OpAsmParser &parser, StringAttr &name, UnresolvedOp &operand)
SmallVector< RecordValue > getInitializedRecordValues(ValueRange initialValues, ArrayAttr initializedRecords)
void printRecordName(AsmPrinter &printer, Operation *, StringAttr name)
ParseResult parseRecordName(AsmParser &parser, StringAttr &name)
constexpr T checkedCast(U u) noexcept
bool requiresUnsupportedValueCopy(mlir::Type type)
Return whether type requires a value copy that cannot currently be materialized.
FailureOr< Value > materializeValueCopy(OpBuilder &builder, Location loc, Value source)
bool requiresValueCopy(Type type)
void printMultiDimAndSymbolList(mlir::OpAsmPrinter &printer, mlir::Operation *op, mlir::OperandRangeRange multiMapOperands, mlir::DenseI32ArrayAttr numDimsPerMap)
bool typesUnify(Type lhs, Type rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
mlir::ParseResult parseMultiDimAndSymbolList(mlir::OpAsmParser &parser, mlir::SmallVector< mlir::SmallVector< mlir::OpAsmParser::UnresolvedOperand > > &multiMapOperands, mlir::DenseI32ArrayAttr &numDimsPerMap)
void setInitializedRecords(const ::mlir::ArrayAttr &propValue)