19#include <mlir/IR/Builders.h>
20#include <mlir/IR/BuiltinAttributes.h>
21#include <mlir/IR/Diagnostics.h>
22#include <mlir/IR/OpImplementation.h>
23#include <mlir/IR/OperationSupport.h>
24#include <mlir/Support/LLVM.h>
26#include <llvm/ADT/STLExtras.h>
27#include <llvm/ADT/SmallString.h>
28#include <llvm/ADT/SmallVectorExtras.h>
29#include <llvm/ADT/StringSet.h>
30#include <llvm/ADT/TypeSwitch.h>
31#include <llvm/Support/Debug.h>
52static void buildCommon(
53 OpBuilder &builder, OperationState &state, PodType result,
InitializedRecords initialValues
55 SmallVector<Value, 4> values;
56 SmallVector<StringRef, 4>
names;
58 for (
const auto &record : initialValues) {
59 names.push_back(record.name);
60 values.push_back(record.value);
64 state.addTypes(result);
65 state.addOperands(values);
71 OpBuilder &builder, OperationState &state, PodType result, ArrayRef<ValueRange> mapOperands,
74 buildCommon(builder, state, result, initialValues);
81 OpBuilder &builder, OperationState &state, PodType result,
InitializedRecords initialValues
83 buildCommon(builder, state, result, initialValues);
100 return {DestructurableMemorySlot {{
getResult(), podType}, std::move(*destructured)}};
107 const DestructurableMemorySlot &slot,
const SmallPtrSetImpl<Attribute> &usedIndices,
108 OpBuilder &builder, SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators
111 assert(slot.elemType == getType());
113 builder.setInsertionPointAfter(*
this);
116 DenseMap<Attribute, MemorySlot> slotMap;
117 for (Attribute index : usedIndices) {
118 auto recordName = llvm::dyn_cast<StringAttr>(index);
119 assert(recordName &&
"expected StringAttr");
121 Type destructAs = getType().getTypeAtIndex(recordName);
122 assert(destructAs == slot.subelementTypes.lookup(recordName));
124 auto destructAsPodTy = llvm::dyn_cast<PodType>(destructAs);
125 assert(destructAsPodTy &&
"expected PodType");
127 SmallVector<RecordValue, 1> initialValue;
129 if (record.name == recordName.getValue()) {
130 initialValue.push_back(record);
135 auto subNew = builder.create<
NewPodOp>(getLoc(), destructAsPodTy, initialValue);
136 newAllocators.push_back(subNew);
137 slotMap.try_emplace<MemorySlot>(index, {subNew.getResult(), destructAs});
145 const DestructurableMemorySlot &slot, OpBuilder &
154 ArrayRef<RecordAttr> records = getType().getRecords();
155 if (records.size() != 1) {
158 return {MemorySlot {
getResult(), records.front().getType()}};
164 ArrayRef<RecordAttr> records = getType().getRecords();
165 assert(records.size() == 1 &&
"only single-record pods are promotable");
166 assert(records.front().getType() == slot.elemType);
168 StringRef recordName = records.front().getName().getValue();
170 if (record.name == recordName) {
182 const MemorySlot &slot, Value defaultValue, OpBuilder &
185 if (defaultValue && defaultValue.use_empty()) {
186 if (Operation *defOp = defaultValue.getDefiningOp()) {
187 if (llvm::isa<llzk::NonDetOp>(defOp)) {
198static void collectMapAttrs(Type type, SmallVector<AffineMapAttr> &mapAttrs) {
200 llvm::TypeSwitch<Type, void>(type)
203 collectMapAttrs(record.getType(), mapAttrs);
206 .Case([&mapAttrs](array::ArrayType t) {
207 for (
auto a : t.getDimensionSizes()) {
208 if (
auto m = llvm::dyn_cast<AffineMapAttr>(a)) {
209 mapAttrs.push_back(m);
213 .Case([&mapAttrs](component::StructType t) {
214 if (ArrayAttr params = t.getParams()) {
215 for (
auto param : params) {
216 if (
auto m = llvm::dyn_cast<AffineMapAttr>(param)) {
217 mapAttrs.push_back(m);
221 }).Default([](Type) {});
232static LogicalResult verifyInitialValues(
233 ValueRange values, ArrayRef<Attribute>
names,
PodType retTy,
234 llvm::function_ref<InFlightDiagnostic()> emitError
237 if (
names.size() != values.size()) {
238 emitError() <<
"number of initialized records and initial values does not match ("
239 <<
names.size() <<
" != " << values.size() <<
")";
243 llvm::StringMap<Type> records = retTy.getRecordMap();
244 llvm::StringSet<> seenNames;
245 for (
auto [nameAttr, value] : llvm::zip_equal(
names, values)) {
246 auto name = llvm::cast<StringAttr>(nameAttr).getValue();
247 if (seenNames.contains(name)) {
248 emitError() <<
"found duplicated record name '" << name <<
'\'';
251 seenNames.insert(name);
253 if (!records.contains(name)) {
254 emitError() <<
"record '" << name <<
"' is not part of the struct";
259 auto valueTy = value.getType();
260 auto recordTy = records.at(name);
261 if (valueTy != recordTy) {
262 auto err = emitError();
263 err <<
"record '" << name <<
"' expected type " << recordTy <<
" but got " << valueTy;
266 <<
"types " << valueTy <<
" and " << recordTy
267 <<
" can be unified. Perhaps you can add a 'poly.unifiable_cast' operation?";
273 return failure(failed);
276static LogicalResult verifyAffineMapOperands(
NewPodOp *op, Type retTy) {
277 SmallVector<AffineMapAttr> mapAttrs;
278 collectMapAttrs(retTy, mapAttrs);
280 op->getMapOperands(), op->getNumDimsPerMap(), mapAttrs, *op
288 failed = failed || mlir::failed(x); \
292 auto retTy = llvm::dyn_cast<PodType>(
getResult().getType());
298 return this->emitError();
301 check(verifyAffineMapOperands(
this, retTy));
303 return failure(failed);
312 if (failed(parser.parseSymbolName(name))) {
316 if (parser.parseEqual()) {
319 return parser.parseOperand(operand);
332 SmallVector<Attribute> initializedRecords;
335 llvm::StringMap<UnresolvedOp> initialValuesOperands;
336 auto parseElementFn = [&parser, &initializedRecords, &initialValuesOperands] {
342 initializedRecords.push_back(name);
343 initialValuesOperands.insert({name.getValue(), operand});
346 auto initialValuesLoc = parser.getCurrentLocation();
347 if (parser.parseCommaSeparatedList(AsmParser::Delimiter::OptionalBraces, parseElementFn)) {
350 SmallVector<int32_t> mapOperandsGroupSizes;
351 SmallVector<UnresolvedOp> allMapOperands;
352 Type indexTy = parser.getBuilder().getIndexType();
353 bool colonAlreadyParsed =
true;
354 auto mapOperandsLoc = parser.getCurrentLocation();
357 if (failed(parser.parseOptionalColon())) {
358 colonAlreadyParsed =
false;
359 SmallVector<SmallVector<UnresolvedOp>> mapOperands {};
364 mapOperandsGroupSizes.reserve(mapOperands.size());
365 for (
const auto &subRange : mapOperands) {
366 allMapOperands.append(subRange.begin(), subRange.end());
371 if (!colonAlreadyParsed && parser.parseColon()) {
376 if (parser.parseCustomTypeWithFallback(resultType)) {
381 for (
auto attr : initializedRecords) {
382 auto name = llvm::cast<StringAttr>(attr);
383 auto lookup = resultType.
getRecord(name.getValue(), [&parser, initialValuesLoc] {
384 return parser.emitError(initialValuesLoc);
386 if (failed(lookup)) {
389 const auto &operand = initialValuesOperands.at(name.getValue());
390 if (failed(parser.resolveOperands({operand}, *lookup, initialValuesLoc, result.operands))) {
394 props.operandSegmentSizes = {
398 props.mapOpGroupSizes = parser.getBuilder().getDenseI32ArrayAttr(mapOperandsGroupSizes);
399 props.initializedRecords = parser.getBuilder().getArrayAttr(initializedRecords);
400 result.addTypes({resultType});
402 if (failed(parser.resolveOperands(allMapOperands, indexTy, mapOperandsLoc, result.operands))) {
406 auto loc = parser.getCurrentLocation();
407 if (parser.parseOptionalAttrDict(result.attributes)) {
411 return parser.emitError(loc) <<
'\'' << result.name.getStringRef() <<
"' op ";
421 auto &os = printer.getStream();
423 if (!initializedRecords.empty()) {
425 llvm::interleaveComma(initializedRecords, os, [&os, &printer](
auto record) {
426 printer.printSymbolName(record.name);
428 printer.printOperand(record.value);
437 if (
auto validType = llvm::dyn_cast<PodType>(type)) {
438 printer.printStrippedAttrOrType(validType);
440 printer.printType(type);
443 printer.printOptionalAttrDict(
445 {
"initializedRecords",
"mapOpGroupSizes",
"numDimsPerMap",
"operandSegmentSizes"}
449SmallVector<RecordValue>
451 return llvm::map_to_vector(llvm::zip_equal(initialValues, initializedRecords), [](
auto pair) {
452 auto [value, name] = pair;
453 return RecordValue {.name = llvm::cast<StringAttr>(name).getValue(), .value = value};
467 const DestructurableMemorySlot &slot, SmallPtrSetImpl<Attribute> &usedIndices,
468 SmallVectorImpl<MemorySlot> & ,
const DataLayout &
475 if (!slot.subelementTypes.contains(recordName)) {
479 usedIndices.insert(recordName);
485 const DestructurableMemorySlot &slot, DenseMap<Attribute, MemorySlot> &subslots,
486 OpBuilder & ,
const DataLayout &
492 const MemorySlot &memorySlot = subslots.at(recordName);
495 return DeletionKind::Keep;
504LogicalResult readRecordNameProperty(DialectBytecodeReader &reader, StringAttr &recordName) {
505 auto versionOpt = reader.getDialectVersion<
PODDialect>();
506 if (succeeded(versionOpt)) {
508 if (ver.majorVersion < 3) {
510 FlatSymbolRefAttr attr;
511 if (failed(reader.readAttribute(attr))) {
514 recordName = attr.getAttr();
520 return reader.readAttribute(recordName);
523void writeRecordNameProperty(DialectBytecodeWriter &writer, StringAttr recordName) {
524 writer.writeAttribute(recordName);
530 auto &prop = state.getOrAddProperties<
Properties>();
531 return readRecordNameProperty(reader, prop.record_name);
535 writeRecordNameProperty(writer, getProperties().record_name);
539 auto podTy = llvm::dyn_cast<PodType>(
getPodRef().getType());
541 return emitError() <<
"reference operand expected a plain-old-data struct but got "
545 auto lookup = podTy.getRecord(
getRecordName(), [
this]() {
return this->emitError(); });
546 if (failed(lookup)) {
551 return emitError() <<
"operation result type and type of record do not match ("
552 <<
getResult().getType() <<
" != " << *lookup <<
")";
563 auto &prop = state.getOrAddProperties<
Properties>();
564 return readRecordNameProperty(reader, prop.record_name);
568 writeRecordNameProperty(writer, getProperties().record_name);
572 auto podTy = llvm::dyn_cast<PodType>(
getPodRef().getType());
574 return emitError() <<
"reference operand expected a plain-old-data struct but got "
578 auto lookup = podTy.getRecord(
getRecordName(), [
this]() {
return this->emitError(); });
579 if (failed(lookup)) {
583 if (
getValue().getType() != *lookup) {
584 return emitError() <<
"type of source value and type of record do not match ("
585 <<
getValue().getType() <<
" != " << *lookup <<
")";
596 FlatSymbolRefAttr symRef;
597 auto result = parser.parseCustomAttributeWithFallback(symRef);
598 if (succeeded(result)) {
599 name = symRef.getAttr();
605 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
void print(::mlir::OpAsmPrinter &p)
::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.
::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.
::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()
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()
::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
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
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
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)