From 3edd3ff55ec3acdb5bab257168d1a794c7d4d430 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Wed, 24 Jun 2026 10:52:25 +0200 Subject: [PATCH 01/45] Made GetSetOpInterface accept types other than integer --- include/shortnail/Dialect/CoreDSL/CoreDSLInterfaces.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/shortnail/Dialect/CoreDSL/CoreDSLInterfaces.td b/include/shortnail/Dialect/CoreDSL/CoreDSLInterfaces.td index 87e2506..aedc547 100644 --- a/include/shortnail/Dialect/CoreDSL/CoreDSLInterfaces.td +++ b/include/shortnail/Dialect/CoreDSL/CoreDSLInterfaces.td @@ -43,7 +43,7 @@ def GetSetOpInterface : OpInterface<"GetSetOpInterface"> { InterfaceMethod< "Get the minimal required index width.", "unsigned", "getMinIndexWidth">, InterfaceMethod< - "Get the underlying element type of the memory.", "::mlir::IntegerType", + "Get the underlying element type of the memory.", "::mlir::Type", "getElementType"> ]; } From 3149a065f71ff50482e357b1f09b24b04a0919c2 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Wed, 24 Jun 2026 10:52:59 +0200 Subject: [PATCH 02/45] Made elementType also accept types other than IntegerTypes --- include/shortnail/Dialect/CoreDSL/CoreDSLOps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/shortnail/Dialect/CoreDSL/CoreDSLOps.h b/include/shortnail/Dialect/CoreDSL/CoreDSLOps.h index 65985a3..083ae39 100644 --- a/include/shortnail/Dialect/CoreDSL/CoreDSLOps.h +++ b/include/shortnail/Dialect/CoreDSL/CoreDSLOps.h @@ -26,7 +26,7 @@ struct MemInfo { uint64_t size; unsigned maxIdxWidth; unsigned minIdxWidth; - IntegerType elementType; + Type elementType; bool isConst; bool isVolatile; }; From 625d7d8515a7dadc6928269ed24429afeb381820 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Wed, 24 Jun 2026 10:53:51 +0200 Subject: [PATCH 03/45] Made Get and Set ops accept any type rather than only integer types --- include/shortnail/Dialect/CoreDSL/CoreDSLOps.td | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/shortnail/Dialect/CoreDSL/CoreDSLOps.td b/include/shortnail/Dialect/CoreDSL/CoreDSLOps.td index fae210a..19233ff 100644 --- a/include/shortnail/Dialect/CoreDSL/CoreDSLOps.td +++ b/include/shortnail/Dialect/CoreDSL/CoreDSLOps.td @@ -332,7 +332,7 @@ class CoreDSL_AccessOp getMemInfo();", /*isRangeAccessOptional=*/"true"> { let summary = "Reads from architectural state."; @@ -358,7 +358,7 @@ def CoreDSL_GetOp : CoreDSL_AccessOp<"get", "$sym", "`:` type($result) attr-dict } def CoreDSL_SetOp : CoreDSL_AccessOp<"set", "$sym", "`=` $value `:` type($value) attr-dict", - (ins FlatSymbolRefAttr:$sym, HWArithIntegerType:$value), + (ins FlatSymbolRefAttr:$sym, AnyType:$value), (outs), /*extraClassDecls=*/"Operation* resolveSymbol(); std::optional getMemInfo();", /*isRangeAccessOptional=*/"true", [], /*folderPrototype=*/"LogicalResult $cppClass::fold(FoldAdaptor adaptor, SmallVectorImpl &results)", From f240659aa1410eca140c3aef0819cdbf81a2be0c Mon Sep 17 00:00:00 2001 From: Benedikt Date: Wed, 24 Jun 2026 10:55:05 +0200 Subject: [PATCH 04/45] Updated getElementType to fit new GetSetOpInterface definition and added simple handling for struct types --- lib/Dialect/CoreDSL/CoreDSLOps.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/Dialect/CoreDSL/CoreDSLOps.cpp b/lib/Dialect/CoreDSL/CoreDSLOps.cpp index 2a1fc51..5fba5a3 100644 --- a/lib/Dialect/CoreDSL/CoreDSLOps.cpp +++ b/lib/Dialect/CoreDSL/CoreDSLOps.cpp @@ -12,6 +12,7 @@ #include "circt/Dialect/HWArith/HWArithOps.h" #include "circt/Dialect/HWArith/HWArithTypes.h" +#include "circt/Dialect/HW/HWOps.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinOps.h" @@ -384,8 +385,8 @@ unsigned AddressSpaceOp::getMinIndexWidth() { // TODO restrict to the address width? // return getAddrType()->getIntOrFloatBitWidth(); } -IntegerType AddressSpaceOp::getElementType() { - return cast(getResType()); +Type AddressSpaceOp::getElementType() { + return getResType(); } //===----------------------------------------------------------------------===// @@ -425,8 +426,8 @@ unsigned RegisterOp::getMaxIndexWidth() { return llvm::Log2_64_Ceil(getSize()); } unsigned RegisterOp::getMinIndexWidth() { return 0; } -IntegerType RegisterOp::getElementType() { - return cast(getRegType()); +Type RegisterOp::getElementType() { + return getRegType(); } LogicalResult RegisterOp::verify() { @@ -435,7 +436,7 @@ LogicalResult RegisterOp::verify() { return emitError("register fields of size 0 are invalid"); } - if (!isHWArithIntegerType(getRegType())) { + if (isa(getRegType()) && !isHWArithIntegerType(getRegType())) { return emitError("register type must be an arbitrary precision integer " "with signedness semantics"); } @@ -703,11 +704,18 @@ LogicalResult ConcatOp::inferReturnTypes( template static LogicalResult checkAccess(AccessOpTy op, Type requiredType) { if (auto info = op.getMemInfo()) { + Type expectedType; + if (auto intType = dyn_cast(info->elementType)) { + expectedType = IntegerType::get(op.getContext(), intType.getWidth() * op.getAccessWidth(), intType.getSignedness()); + } else if (auto structType = dyn_cast(info->elementType)) { + // TODO: Are accesses with access width > 1 supported by CoreDSL? + assert(op.getAccessWidth() == 1 && "Access with may only be 1 for struct types"); + expectedType = structType; + } else { + llvm_unreachable("Unexpected type"); + } // Calculate the expected type: element type width * access width while // keeping the signedness - Type expectedType = IntegerType::get( - op.getContext(), info->elementType.getWidth() * op.getAccessWidth(), - info->elementType.getSignedness()); if (expectedType != requiredType) { return op.emitError("type mismatch, referencing storage of type ") << info->elementType << " with access width of " From 487356098a4b16f93fb1cf3a012ebed91bc373b3 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Wed, 24 Jun 2026 10:55:20 +0200 Subject: [PATCH 05/45] Docs changes --- docs/CoreDSLDialect.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CoreDSLDialect.md b/docs/CoreDSLDialect.md index 990bbc6..540ee08 100644 --- a/docs/CoreDSLDialect.md +++ b/docs/CoreDSLDialect.md @@ -491,7 +491,7 @@ Examples: | Result | Description | | :----: | ----------- | -| `result` | an arbitrary precision integer with signedness semantics | +| `result` | any type | @@ -728,7 +728,7 @@ coredsl.set @MEM[%addr : ui32, 0:3] = %3 : ui32 // big-endian | Operand | Description | | :-----: | ----------- | | `base` | an arbitrary precision integer with signedness semantics and unsigned integer | -| `value` | an arbitrary precision integer with signedness semantics | +| `value` | any type | From ab32640c81437f4e037ff7e3022a38a55714be9e Mon Sep 17 00:00:00 2001 From: Benedikt Date: Wed, 15 Jul 2026 14:46:08 +0200 Subject: [PATCH 06/45] WIP: Exploding struct typed registers into multiple. Not working. Currently only for scalar registers, not register files --- include/shortnail/Conversion/Passes.td | 8 + lib/Conversion/CMakeLists.txt | 1 + .../CMakeLists.txt | 16 ++ .../CoreDSLExplodeStructRegisters.cpp | 203 ++++++++++++++++++ tools/shortnail-opt/CMakeLists.txt | 1 + 5 files changed, 229 insertions(+) create mode 100644 lib/Conversion/CoreDSLExplodeStructRegisters/CMakeLists.txt create mode 100644 lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp diff --git a/include/shortnail/Conversion/Passes.td b/include/shortnail/Conversion/Passes.td index 468aae0..cf6dca3 100644 --- a/include/shortnail/Conversion/Passes.td +++ b/include/shortnail/Conversion/Passes.td @@ -74,6 +74,14 @@ def CoreDSLLegalizeCF : Pass<"coredsl-legalize-cf", "::mlir::coredsl::ISAXOp"> { ]; } +def CoreDSLExplodeStructRegisters : Pass<"coredsl-explode-struct-registers", "::mlir::coredsl::ISAXOp"> { + let summary = "Divide struct registers into multiple scalar registers"; + let dependentDialects = [ + "::mlir::coredsl::CoreDSLDialect", + "::circt::hw::HWDialect", + ]; +} + def AnalyzeISAX : Pass<"analyze-isax", "mlir::ModuleOp"> { let summary = "Analyze CoreDSL ISAX MLIR and output structured YAML"; let description = [{ diff --git a/lib/Conversion/CMakeLists.txt b/lib/Conversion/CMakeLists.txt index a7dc9f0..1a856e8 100644 --- a/lib/Conversion/CMakeLists.txt +++ b/lib/Conversion/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(AnalyzeISAX) +add_subdirectory(CoreDSLExplodeStructRegisters) add_subdirectory(CoreDSLLegalizeCF) add_subdirectory(CoreDSLToPy) add_subdirectory(MergeISAX) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CMakeLists.txt b/lib/Conversion/CoreDSLExplodeStructRegisters/CMakeLists.txt new file mode 100644 index 0000000..b4c76c7 --- /dev/null +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CMakeLists.txt @@ -0,0 +1,16 @@ +add_shortnail_library(ShortnailCoreDSLExplodeStructRegisters + CoreDSLExplodeStructRegisters.cpp + + DEPENDS + MLIRConversionPassIncGen + + LINK_LIBS PUBLIC + MLIRIR + MLIRPass + MLIRSCFUtils + + CIRCTHW + CIRCTSupport + + ShortnailCoreDSL +) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp new file mode 100644 index 0000000..7f8dba0 --- /dev/null +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -0,0 +1,203 @@ +#include "mlir/Transforms/DialectConversion.h" +#include "shortnail/Conversion/Passes.h" +#include "shortnail/Dialect/CoreDSL/CoreDSLOps.h" + +#include "circt/Dialect/HW/HWOps.h" +#include "circt/Dialect/HW/HWTypes.h" + +namespace mlir { +namespace shortnail { +#define GEN_PASS_DEF_COREDSLEXPLODESTRUCTREGISTERS +#include "shortnail/Conversion/Passes.h.inc" +} // namespace shortnail +} // namespace mlir + +using namespace mlir; +using namespace mlir::shortnail; +using namespace circt; + +namespace { + +// IDEA: make pattern be applied recursively?!?! +// - Would generate more registers that are later deleted +// - may be easier + +// TODO: not sure if twine makes sense here, because we are appending here +template +void explodeRegs(StringRef regName, hw::StructType type, + ConversionPatternRewriter &rewriter, + ScalarValueAction scalarValueAction, + StructMemberAction structMemberAction) { + for (hw::StructType::FieldInfo fieldInfo : type.getElements()) { + //auto newRegName = regName + "_" + fieldInfo.name.getValue(); + auto newRegName = std::string(regName); + newRegName += "_"; + newRegName += fieldInfo.name.getValue(); + if (auto structType = llvm::dyn_cast(fieldInfo.type)) { + structMemberAction(structType, fieldInfo.name); + explodeRegs(newRegName, structType, rewriter, scalarValueAction, + structMemberAction); + } else { + scalarValueAction(newRegName, fieldInfo.name, + llvm::cast(fieldInfo.type)); + } + } +} + +struct StructExploderPattern : public OpConversionPattern { + // TODO: may not be necessary + llvm::StringMap &nameToRegMap; + StructExploderPattern(MLIRContext *ctx, + llvm::StringMap &nameToRegMap) + : OpConversionPattern(ctx), + nameToRegMap{nameToRegMap} {} + + LogicalResult + matchAndRewrite(coredsl::RegisterOp op, OpAdaptor, + ConversionPatternRewriter &rewriter) const override { + if (auto structType = llvm::dyn_cast(op.getRegType())) { + StringRef name = op.getName(); + rewriter.setInsertionPointAfter(op); + Location loc = op.getLoc(); + nameToRegMap.insert(std::make_pair(name, op)); + explodeRegs( + name, structType, rewriter, + [this, &rewriter, &loc, &op](StringRef newRegName, StringAttr fieldName, + IntegerType fieldType) { + auto ctx = rewriter.getContext(); + StringAttr symbolName = StringAttr::get(ctx, newRegName); + auto reg = coredsl::RegisterOp::create( + rewriter, loc, {}, symbolName, op.getIsConst(), op.getIsVolatile(), + /*numElements=*/nullptr, {}, + fieldType, + op.getAccessMode()); + + nameToRegMap.insert(std::make_pair(newRegName, reg)); + }, + [](hw::StructType, StringAttr) {}); + // TODO: not sure if this will work, as the reg is still used + rewriter.eraseOp(op); + return LogicalResult::success(); + } + return LogicalResult::failure(); + } +}; + +struct StructRewriteSetOps : public OpConversionPattern { + const llvm::StringMap &nameToRegMap; + + StructRewriteSetOps(MLIRContext *ctx, + const llvm::StringMap &nameToRegMap) + : OpConversionPattern(ctx), nameToRegMap{nameToRegMap} {} + + LogicalResult + matchAndRewrite(coredsl::SetOp op, OpAdaptor, + ConversionPatternRewriter &rewriter) const override { + auto value = op.getValue(); + if (auto structType = llvm::dyn_cast(value.getType())) { + StringRef symbolName = op.getSym(); + auto loc = op.getLoc(); + SmallVector opStack{op.getValue().getDefiningOp()}; + explodeRegs( + symbolName, structType, rewriter, + [&rewriter, &opStack, &loc](StringRef newRegName, + StringAttr fieldName, IntegerType type) { + auto writtenValue = opStack.back(); + auto op = coredsl::SetOp::create(rewriter, loc, nullptr, nullptr, nullptr, + newRegName, writtenValue->getResult(0)); + llvm::outs() << "New op: " << op << "\n"; + // TODO: this is writing struct inject + llvm::outs() << "Set val: " << *writtenValue << "\n"; + }, + [&rewriter, &opStack, &loc](hw::StructType type, + StringAttr fieldName) { + // TODO: emit hw.struct_extract and push result on stack + // TODO: get extracted value + auto toExtractFrom = opStack.back(); + Value structVal = toExtractFrom->getResult(0); + assert(llvm::isa(structVal.getType())); + auto extractOp = hw::StructExtractOp::create( + rewriter, loc, toExtractFrom->getResult(0), fieldName); + opStack.push_back(extractOp); + }); + rewriter.eraseOp(op); + return LogicalResult::success(); + } + return LogicalResult::failure(); + } +}; + +struct StructRewriteGetOps : public OpConversionPattern { + const llvm::StringMap &nameToRegMap; + + StructRewriteGetOps(MLIRContext *ctx, + const llvm::StringMap &nameToRegMap) + : OpConversionPattern(ctx), nameToRegMap{nameToRegMap} {} + + LogicalResult + matchAndRewrite(coredsl::GetOp op, OpAdaptor, + ConversionPatternRewriter &rewriter) const override { + auto type = op.getResult().getType(); + if (auto structType = llvm::dyn_cast(type)) { + StringRef symbolName = op.getSym(); + coredsl::RegisterOp accessedReg = nameToRegMap.find(symbolName)->second; + + auto loc = op.getLoc(); + SmallVector structMembers; + // TODO: need to combine the gotten vavlues into a struct + explodeRegs( + symbolName, structType, rewriter, + [&rewriter, &loc, &structMembers](StringRef newRegName, StringAttr fieldName, IntegerType type) { + auto gotValue = coredsl::GetOp::create(rewriter, loc, type, nullptr, nullptr, nullptr, newRegName); + structMembers.push_back(gotValue.getResult()); + }, + [&rewriter, &loc, &structMembers](hw::StructType type, StringAttr fieldName) { + // TODO: hope this does not scramble struct members + auto structVal = hw::StructCreateOp::create(rewriter, loc, type, structMembers); + structMembers.clear(); + structMembers.push_back(structVal.getResult()); + }); + // TODO: hope this does not scramble struct members + auto finalStruct = hw::StructCreateOp::create(rewriter, loc, accessedReg.getElementType(), structMembers); + rewriter.replaceOp(op, finalStruct.getResult()); + return LogicalResult::success(); + } + return LogicalResult::failure(); + } +}; + +struct CoreDSLExplodeStructRegisters + : public mlir::shortnail::impl::CoreDSLExplodeStructRegistersBase< + CoreDSLExplodeStructRegisters> { + using CoreDSLExplodeStructRegistersBase::CoreDSLExplodeStructRegistersBase; + + void runOnOperation() override { + coredsl::ISAXOp isax = getOperation(); + auto &ctx = getContext(); + RewritePatternSet patterns{&ctx}; + llvm::StringMap nameToRegMap; + patterns.insert(&ctx, nameToRegMap); + ConversionTarget target{ctx}; + target.addLegalDialect(); + target.addDynamicallyLegalOp([](coredsl::RegisterOp op){ + return op.getElementType().isInteger(); + }); + if (failed(applyPartialConversion(isax, target, std::move(patterns)))) { + return signalPassFailure(); + } + patterns.clear(); + target.addDynamicallyLegalOp([](coredsl::GetOp op){ + return op.getResult().getType().isInteger(); + }); + target.addDynamicallyLegalOp([](coredsl::SetOp op){ + return op.getValue().getType().isInteger(); + }); + patterns.insert(&ctx, + nameToRegMap); + if (failed(applyPartialConversion(isax, target, std::move(patterns)))) { + return signalPassFailure(); + } + } +}; + +} // namespace diff --git a/tools/shortnail-opt/CMakeLists.txt b/tools/shortnail-opt/CMakeLists.txt index 20fd942..f8a8da2 100644 --- a/tools/shortnail-opt/CMakeLists.txt +++ b/tools/shortnail-opt/CMakeLists.txt @@ -26,6 +26,7 @@ target_link_libraries(shortnail-opt ShortnailAnalyzeISAX ShortnailCoreDSL + ShortnailCoreDSLExplodeStructRegisters ShortnailCoreDSLLegalizeCF ShortnailCoreDSLToPy ShortnailMergeISAX From 0a39b9de5d5d3abb76a1e7d93cefb293e6d0cf45 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Fri, 17 Jul 2026 15:25:43 +0200 Subject: [PATCH 07/45] Fixed get and set functions (still only works for single registers, not register files) --- .../CoreDSLExplodeStructRegisters.cpp | 76 ++++++++----------- 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 7f8dba0..2f79ee7 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -18,25 +18,22 @@ using namespace circt; namespace { -// IDEA: make pattern be applied recursively?!?! -// - Would generate more registers that are later deleted -// - may be easier - -// TODO: not sure if twine makes sense here, because we are appending here -template +template void explodeRegs(StringRef regName, hw::StructType type, ConversionPatternRewriter &rewriter, ScalarValueAction scalarValueAction, - StructMemberAction structMemberAction) { + StructMemberEntryAction structMemberEntryAction, + StructMemberExitAction structMemberExitAction) { for (hw::StructType::FieldInfo fieldInfo : type.getElements()) { //auto newRegName = regName + "_" + fieldInfo.name.getValue(); auto newRegName = std::string(regName); newRegName += "_"; newRegName += fieldInfo.name.getValue(); if (auto structType = llvm::dyn_cast(fieldInfo.type)) { - structMemberAction(structType, fieldInfo.name); + structMemberEntryAction(structType, fieldInfo.name); explodeRegs(newRegName, structType, rewriter, scalarValueAction, - structMemberAction); + structMemberEntryAction, structMemberExitAction); + structMemberExitAction(structType, fieldInfo.name); } else { scalarValueAction(newRegName, fieldInfo.name, llvm::cast(fieldInfo.type)); @@ -45,12 +42,8 @@ void explodeRegs(StringRef regName, hw::StructType type, } struct StructExploderPattern : public OpConversionPattern { - // TODO: may not be necessary - llvm::StringMap &nameToRegMap; - StructExploderPattern(MLIRContext *ctx, - llvm::StringMap &nameToRegMap) - : OpConversionPattern(ctx), - nameToRegMap{nameToRegMap} {} + StructExploderPattern(MLIRContext *ctx) + : OpConversionPattern(ctx) {} LogicalResult matchAndRewrite(coredsl::RegisterOp op, OpAdaptor, @@ -59,10 +52,9 @@ struct StructExploderPattern : public OpConversionPattern { StringRef name = op.getName(); rewriter.setInsertionPointAfter(op); Location loc = op.getLoc(); - nameToRegMap.insert(std::make_pair(name, op)); explodeRegs( name, structType, rewriter, - [this, &rewriter, &loc, &op](StringRef newRegName, StringAttr fieldName, + [&rewriter, &loc, &op](StringRef newRegName, StringAttr fieldName, IntegerType fieldType) { auto ctx = rewriter.getContext(); StringAttr symbolName = StringAttr::get(ctx, newRegName); @@ -71,9 +63,8 @@ struct StructExploderPattern : public OpConversionPattern { /*numElements=*/nullptr, {}, fieldType, op.getAccessMode()); - - nameToRegMap.insert(std::make_pair(newRegName, reg)); }, + [](hw::StructType, StringAttr) {}, [](hw::StructType, StringAttr) {}); // TODO: not sure if this will work, as the reg is still used rewriter.eraseOp(op); @@ -84,11 +75,8 @@ struct StructExploderPattern : public OpConversionPattern { }; struct StructRewriteSetOps : public OpConversionPattern { - const llvm::StringMap &nameToRegMap; - - StructRewriteSetOps(MLIRContext *ctx, - const llvm::StringMap &nameToRegMap) - : OpConversionPattern(ctx), nameToRegMap{nameToRegMap} {} + StructRewriteSetOps(MLIRContext *ctx) + : OpConversionPattern(ctx) {} LogicalResult matchAndRewrite(coredsl::SetOp op, OpAdaptor, @@ -103,11 +91,9 @@ struct StructRewriteSetOps : public OpConversionPattern { [&rewriter, &opStack, &loc](StringRef newRegName, StringAttr fieldName, IntegerType type) { auto writtenValue = opStack.back(); - auto op = coredsl::SetOp::create(rewriter, loc, nullptr, nullptr, nullptr, - newRegName, writtenValue->getResult(0)); - llvm::outs() << "New op: " << op << "\n"; - // TODO: this is writing struct inject - llvm::outs() << "Set val: " << *writtenValue << "\n"; + auto extractOp = hw::StructExtractOp::create(rewriter, loc, writtenValue->getResult(0), fieldName); + coredsl::SetOp::create(rewriter, loc, nullptr, nullptr, nullptr, + newRegName, extractOp->getResult(0)); }, [&rewriter, &opStack, &loc](hw::StructType type, StringAttr fieldName) { @@ -119,7 +105,8 @@ struct StructRewriteSetOps : public OpConversionPattern { auto extractOp = hw::StructExtractOp::create( rewriter, loc, toExtractFrom->getResult(0), fieldName); opStack.push_back(extractOp); - }); + }, + [](hw::StructType, StringAttr) {}); rewriter.eraseOp(op); return LogicalResult::success(); } @@ -128,11 +115,8 @@ struct StructRewriteSetOps : public OpConversionPattern { }; struct StructRewriteGetOps : public OpConversionPattern { - const llvm::StringMap &nameToRegMap; - - StructRewriteGetOps(MLIRContext *ctx, - const llvm::StringMap &nameToRegMap) - : OpConversionPattern(ctx), nameToRegMap{nameToRegMap} {} + StructRewriteGetOps(MLIRContext *ctx) + : OpConversionPattern(ctx) {} LogicalResult matchAndRewrite(coredsl::GetOp op, OpAdaptor, @@ -140,10 +124,10 @@ struct StructRewriteGetOps : public OpConversionPattern { auto type = op.getResult().getType(); if (auto structType = llvm::dyn_cast(type)) { StringRef symbolName = op.getSym(); - coredsl::RegisterOp accessedReg = nameToRegMap.find(symbolName)->second; auto loc = op.getLoc(); SmallVector structMembers; + size_t structBeginIdx = 0; // TODO: need to combine the gotten vavlues into a struct explodeRegs( symbolName, structType, rewriter, @@ -151,14 +135,19 @@ struct StructRewriteGetOps : public OpConversionPattern { auto gotValue = coredsl::GetOp::create(rewriter, loc, type, nullptr, nullptr, nullptr, newRegName); structMembers.push_back(gotValue.getResult()); }, - [&rewriter, &loc, &structMembers](hw::StructType type, StringAttr fieldName) { + [&structBeginIdx, &structMembers](hw::StructType, StringAttr) { + structBeginIdx = structMembers.size(); + }, + [&rewriter, &loc, &structBeginIdx, &structMembers](hw::StructType type, StringAttr fieldName) { // TODO: hope this does not scramble struct members - auto structVal = hw::StructCreateOp::create(rewriter, loc, type, structMembers); - structMembers.clear(); + auto currStructMembers = ArrayRef(structMembers.begin() + structBeginIdx, structMembers.end()); + auto structVal = hw::StructCreateOp::create(rewriter, loc, type, currStructMembers); + structMembers.resize(structBeginIdx); structMembers.push_back(structVal.getResult()); }); // TODO: hope this does not scramble struct members - auto finalStruct = hw::StructCreateOp::create(rewriter, loc, accessedReg.getElementType(), structMembers); + // TODO: this crashes :( + auto finalStruct = hw::StructCreateOp::create(rewriter, loc, type, structMembers); rewriter.replaceOp(op, finalStruct.getResult()); return LogicalResult::success(); } @@ -176,7 +165,8 @@ struct CoreDSLExplodeStructRegisters auto &ctx = getContext(); RewritePatternSet patterns{&ctx}; llvm::StringMap nameToRegMap; - patterns.insert(&ctx, nameToRegMap); + llvm::StringMap nameToTypeMap; + patterns.insert(&ctx); ConversionTarget target{ctx}; target.addLegalDialect(); target.addDynamicallyLegalOp([](coredsl::RegisterOp op){ @@ -192,8 +182,8 @@ struct CoreDSLExplodeStructRegisters target.addDynamicallyLegalOp([](coredsl::SetOp op){ return op.getValue().getType().isInteger(); }); - patterns.insert(&ctx, - nameToRegMap); + patterns.insert(&ctx); + if (failed(applyPartialConversion(isax, target, std::move(patterns)))) { return signalPassFailure(); } From 9986c8901a1105ea28dd21773cf9bfc61c9940e7 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Fri, 17 Jul 2026 15:25:54 +0200 Subject: [PATCH 08/45] Added simple test --- .../explode_struct_registers.mlir | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir diff --git a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir new file mode 100644 index 0000000..2885908 --- /dev/null +++ b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir @@ -0,0 +1,84 @@ +// RUN: shortnail-opt %s -coredsl-explode-struct-registers -canonicalize | shortnail-opt | FileCheck %s + +coredsl.isax "StructRegisters" { + coredsl.register local @STRUCT_REG : !hw.struct + coredsl.register local @NESTED_STRUCT_REG : !hw.struct> + coredsl.instruction @StructRegDirectStore {lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { +// CHECK: %0 = hwarith.constant 0 : ui1 +// CHECK: %1 = hwarith.constant 255 : ui8 +// CHECK: %2 = hwarith.constant 7 : ui3 +// CHECK: %3 = hwarith.constant 1 : ui1 +// CHECK: %4 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 +// CHECK: %5 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %6 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %7 = coredsl.cast %4 : ui5 to ui32 +// CHECK: coredsl.set @STRUCT_REG_x = %7 : ui32 +// CHECK: coredsl.set @STRUCT_REG_y = %6 : ui32 +// CHECK: %8 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %9 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %10 = hwarith.sub %8, %3 : (ui32, ui1) -> si33 +// CHECK: %11 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %12 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %13 = coredsl.cast %10 : si33 to ui32 +// CHECK: coredsl.set @STRUCT_REG_x = %13 : ui32 +// CHECK: coredsl.set @STRUCT_REG_y = %12 : ui32 +// CHECK: %14 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 +// CHECK: %15 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: %16 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: %17 = coredsl.cast %2 : ui3 to ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %14 : si32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %17 : ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %16 : ui32 +// CHECK: %18 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %19 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %20 = coredsl.bitset %18[7:0] = %1 : (ui32, ui8) -> ui32 +// CHECK: coredsl.set @STRUCT_REG_x = %20 : ui32 +// CHECK: coredsl.set @STRUCT_REG_y = %19 : ui32 +// CHECK: %21 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 +// CHECK: %22 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: %23 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: %24 = coredsl.cast %0 : ui1 to ui4 +// CHECK: %25 = coredsl.bitset %23[3:0] = %24 : (ui32, ui4) -> ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %21 : si32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %22 : ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %25 : ui32 + %imm = coredsl.cast %TREENAIL_WAS_HERE_imm_11_0 : ui12 to ui12 + %rs1 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 + %rd = coredsl.cast %TREENAIL_WAS_HERE_rd_4_0 : ui5 to ui5 + %0 = coredsl.get @STRUCT_REG : !hw.struct + %1 = coredsl.cast %rs1 : ui5 to ui32 + %2 = hw.struct_inject %0["x"], %1 : !hw.struct + coredsl.set @STRUCT_REG = %2 : !hw.struct + %3 = hwarith.constant 1 : ui1 + %4 = coredsl.get @STRUCT_REG : !hw.struct + %5 = hw.struct_extract %4["x"] : !hw.struct + %6 = hwarith.sub %5, %3 : (ui32, ui1) -> si33 + %7 = coredsl.get @STRUCT_REG : !hw.struct + %8 = coredsl.cast %6 : si33 to ui32 + %9 = hw.struct_inject %7["x"], %8 : !hw.struct + coredsl.set @STRUCT_REG = %9 : !hw.struct + %10 = hwarith.constant 7 : ui3 + %11 = coredsl.get @NESTED_STRUCT_REG : !hw.struct> + %12 = hw.struct_extract %11["vec"] : !hw.struct> + %13 = coredsl.cast %10 : ui3 to ui32 + %14 = hw.struct_inject %12["x"], %13 : !hw.struct + %15 = hw.struct_inject %11["vec"], %14 : !hw.struct> + coredsl.set @NESTED_STRUCT_REG = %15 : !hw.struct> + %16 = hwarith.constant 255 : ui8 + %17 = coredsl.get @STRUCT_REG : !hw.struct + %18 = hw.struct_extract %17["x"] : !hw.struct + %19 = coredsl.bitset %18[7:0] = %16 : (ui32, ui8) -> ui32 + %20 = hw.struct_inject %17["x"], %19 : !hw.struct + coredsl.set @STRUCT_REG = %20 : !hw.struct + %21 = hwarith.constant 0 : ui1 + %22 = coredsl.get @NESTED_STRUCT_REG : !hw.struct> + %23 = hw.struct_extract %22["vec"] : !hw.struct> + %24 = hw.struct_extract %23["y"] : !hw.struct + %25 = coredsl.cast %21 : ui1 to ui4 + %26 = coredsl.bitset %24[3:0] = %25 : (ui32, ui4) -> ui32 + %27 = hw.struct_inject %23["y"], %26 : !hw.struct + %28 = hw.struct_inject %22["vec"], %27 : !hw.struct> + coredsl.set @NESTED_STRUCT_REG = %28 : !hw.struct> + coredsl.end + } +} From cc258b2996196ea502ee26b217a8002f915d2572 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Fri, 17 Jul 2026 15:29:28 +0200 Subject: [PATCH 09/45] Formatting and removed unused variable --- .../CoreDSLExplodeStructRegisters.cpp | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 2f79ee7..8445364 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -18,14 +18,15 @@ using namespace circt; namespace { -template +template void explodeRegs(StringRef regName, hw::StructType type, ConversionPatternRewriter &rewriter, ScalarValueAction scalarValueAction, StructMemberEntryAction structMemberEntryAction, StructMemberExitAction structMemberExitAction) { for (hw::StructType::FieldInfo fieldInfo : type.getElements()) { - //auto newRegName = regName + "_" + fieldInfo.name.getValue(); + // auto newRegName = regName + "_" + fieldInfo.name.getValue(); auto newRegName = std::string(regName); newRegName += "_"; newRegName += fieldInfo.name.getValue(); @@ -55,17 +56,15 @@ struct StructExploderPattern : public OpConversionPattern { explodeRegs( name, structType, rewriter, [&rewriter, &loc, &op](StringRef newRegName, StringAttr fieldName, - IntegerType fieldType) { + IntegerType fieldType) { auto ctx = rewriter.getContext(); StringAttr symbolName = StringAttr::get(ctx, newRegName); - auto reg = coredsl::RegisterOp::create( - rewriter, loc, {}, symbolName, op.getIsConst(), op.getIsVolatile(), - /*numElements=*/nullptr, {}, - fieldType, - op.getAccessMode()); + coredsl::RegisterOp::create(rewriter, loc, {}, symbolName, + op.getIsConst(), op.getIsVolatile(), + /*numElements=*/nullptr, {}, fieldType, + op.getAccessMode()); }, - [](hw::StructType, StringAttr) {}, - [](hw::StructType, StringAttr) {}); + [](hw::StructType, StringAttr) {}, [](hw::StructType, StringAttr) {}); // TODO: not sure if this will work, as the reg is still used rewriter.eraseOp(op); return LogicalResult::success(); @@ -91,7 +90,8 @@ struct StructRewriteSetOps : public OpConversionPattern { [&rewriter, &opStack, &loc](StringRef newRegName, StringAttr fieldName, IntegerType type) { auto writtenValue = opStack.back(); - auto extractOp = hw::StructExtractOp::create(rewriter, loc, writtenValue->getResult(0), fieldName); + auto extractOp = hw::StructExtractOp::create( + rewriter, loc, writtenValue->getResult(0), fieldName); coredsl::SetOp::create(rewriter, loc, nullptr, nullptr, nullptr, newRegName, extractOp->getResult(0)); }, @@ -131,23 +131,29 @@ struct StructRewriteGetOps : public OpConversionPattern { // TODO: need to combine the gotten vavlues into a struct explodeRegs( symbolName, structType, rewriter, - [&rewriter, &loc, &structMembers](StringRef newRegName, StringAttr fieldName, IntegerType type) { - auto gotValue = coredsl::GetOp::create(rewriter, loc, type, nullptr, nullptr, nullptr, newRegName); + [&rewriter, &loc, &structMembers]( + StringRef newRegName, StringAttr fieldName, IntegerType type) { + auto gotValue = coredsl::GetOp::create( + rewriter, loc, type, nullptr, nullptr, nullptr, newRegName); structMembers.push_back(gotValue.getResult()); }, [&structBeginIdx, &structMembers](hw::StructType, StringAttr) { structBeginIdx = structMembers.size(); }, - [&rewriter, &loc, &structBeginIdx, &structMembers](hw::StructType type, StringAttr fieldName) { + [&rewriter, &loc, &structBeginIdx, + &structMembers](hw::StructType type, StringAttr fieldName) { // TODO: hope this does not scramble struct members - auto currStructMembers = ArrayRef(structMembers.begin() + structBeginIdx, structMembers.end()); - auto structVal = hw::StructCreateOp::create(rewriter, loc, type, currStructMembers); + auto currStructMembers = ArrayRef( + structMembers.begin() + structBeginIdx, structMembers.end()); + auto structVal = hw::StructCreateOp::create(rewriter, loc, type, + currStructMembers); structMembers.resize(structBeginIdx); structMembers.push_back(structVal.getResult()); }); // TODO: hope this does not scramble struct members // TODO: this crashes :( - auto finalStruct = hw::StructCreateOp::create(rewriter, loc, type, structMembers); + auto finalStruct = + hw::StructCreateOp::create(rewriter, loc, type, structMembers); rewriter.replaceOp(op, finalStruct.getResult()); return LogicalResult::success(); } @@ -169,19 +175,16 @@ struct CoreDSLExplodeStructRegisters patterns.insert(&ctx); ConversionTarget target{ctx}; target.addLegalDialect(); - target.addDynamicallyLegalOp([](coredsl::RegisterOp op){ - return op.getElementType().isInteger(); - }); + target.addDynamicallyLegalOp( + [](coredsl::RegisterOp op) { return op.getElementType().isInteger(); }); if (failed(applyPartialConversion(isax, target, std::move(patterns)))) { return signalPassFailure(); } patterns.clear(); - target.addDynamicallyLegalOp([](coredsl::GetOp op){ - return op.getResult().getType().isInteger(); - }); - target.addDynamicallyLegalOp([](coredsl::SetOp op){ - return op.getValue().getType().isInteger(); - }); + target.addDynamicallyLegalOp( + [](coredsl::GetOp op) { return op.getResult().getType().isInteger(); }); + target.addDynamicallyLegalOp( + [](coredsl::SetOp op) { return op.getValue().getType().isInteger(); }); patterns.insert(&ctx); if (failed(applyPartialConversion(isax, target, std::move(patterns)))) { From aa55490877cd212bbc194fffb9f4022c09d2e7b6 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Fri, 17 Jul 2026 15:35:25 +0200 Subject: [PATCH 10/45] Added triple nested register and added CHECK statements for the exploded registers --- .../explode_struct_registers.mlir | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir index 2885908..86d3c4d 100644 --- a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir +++ b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir @@ -1,8 +1,20 @@ // RUN: shortnail-opt %s -coredsl-explode-struct-registers -canonicalize | shortnail-opt | FileCheck %s +// TODO: add test with triple nested struct coredsl.isax "StructRegisters" { coredsl.register local @STRUCT_REG : !hw.struct coredsl.register local @NESTED_STRUCT_REG : !hw.struct> + coredsl.register local @TRIPLE_NESTED_REG : !hw.struct>, intVal: ui32> +// CHECK: coredsl.register local @STRUCT_REG_x : ui32 +// CHECK: coredsl.register local @STRUCT_REG_y : ui32 +// CHECK: coredsl.register local @NESTED_STRUCT_REG_notNested : si32 +// CHECK: coredsl.register local @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: coredsl.register local @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_notNested : si32 +// CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_vec_x : ui32 +// CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_vec_y : ui32 +// CHECK: coredsl.register local @TRIPLE_NESTED_REG_intVal : ui32 + coredsl.instruction @StructRegDirectStore {lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { // CHECK: %0 = hwarith.constant 0 : ui1 // CHECK: %1 = hwarith.constant 255 : ui8 From f5130e14b4b502b9e526934c9a9a86163e6c0e4a Mon Sep 17 00:00:00 2001 From: Benedikt Date: Fri, 17 Jul 2026 15:38:26 +0200 Subject: [PATCH 11/45] Added docs --- docs/ConversionPasses.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/ConversionPasses.md b/docs/ConversionPasses.md index 924e5a0..493de78 100644 --- a/docs/ConversionPasses.md +++ b/docs/ConversionPasses.md @@ -15,6 +15,10 @@ The YAML is consumed by the Python patch generator (gen_patches.py). -output : Output path for the YAML analysis file ``` +### `-coredsl-explode-struct-registers` + +_Divide struct registers into multiple scalar registers_ + ### `-coredsl-legalize-cf` _Legalize cf operations by converting them to scf_ From 63a619624eb56ed9a9e7a753002f47e9374f7b58 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 27 Jul 2026 10:44:38 +0200 Subject: [PATCH 12/45] Removed code that was not relevant from test --- .../explode_struct_registers.mlir | 67 ++++++++----------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir index 86d3c4d..6a749ed 100644 --- a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir +++ b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir @@ -19,41 +19,34 @@ coredsl.isax "StructRegisters" { // CHECK: %0 = hwarith.constant 0 : ui1 // CHECK: %1 = hwarith.constant 255 : ui8 // CHECK: %2 = hwarith.constant 7 : ui3 -// CHECK: %3 = hwarith.constant 1 : ui1 -// CHECK: %4 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 -// CHECK: %5 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %6 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %7 = coredsl.cast %4 : ui5 to ui32 -// CHECK: coredsl.set @STRUCT_REG_x = %7 : ui32 -// CHECK: coredsl.set @STRUCT_REG_y = %6 : ui32 -// CHECK: %8 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %9 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %10 = hwarith.sub %8, %3 : (ui32, ui1) -> si33 -// CHECK: %11 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %12 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %13 = coredsl.cast %10 : si33 to ui32 -// CHECK: coredsl.set @STRUCT_REG_x = %13 : ui32 -// CHECK: coredsl.set @STRUCT_REG_y = %12 : ui32 -// CHECK: %14 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 -// CHECK: %15 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 -// CHECK: %16 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 -// CHECK: %17 = coredsl.cast %2 : ui3 to ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %14 : si32 +// CHECK: %3 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 +// CHECK: %4 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %5 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %6 = coredsl.cast %3 : ui5 to ui32 +// CHECK: coredsl.set @STRUCT_REG_x = %6 : ui32 +// CHECK: coredsl.set @STRUCT_REG_y = %5 : ui32 +// CHECK: %7 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %8 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %9 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 +// CHECK: %10 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: %11 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: %12 = coredsl.cast %2 : ui3 to ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %9 : si32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %12 : ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %11 : ui32 +// CHECK: %13 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %14 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %15 = coredsl.bitset %13[7:0] = %1 : (ui32, ui8) -> ui32 +// CHECK: coredsl.set @STRUCT_REG_x = %15 : ui32 +// CHECK: coredsl.set @STRUCT_REG_y = %14 : ui32 +// CHECK: %16 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 +// CHECK: %17 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: %18 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: %19 = coredsl.cast %0 : ui1 to ui4 +// CHECK: %20 = coredsl.bitset %18[3:0] = %19 : (ui32, ui4) -> ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %16 : si32 // CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %17 : ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %16 : ui32 -// CHECK: %18 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %19 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %20 = coredsl.bitset %18[7:0] = %1 : (ui32, ui8) -> ui32 -// CHECK: coredsl.set @STRUCT_REG_x = %20 : ui32 -// CHECK: coredsl.set @STRUCT_REG_y = %19 : ui32 -// CHECK: %21 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 -// CHECK: %22 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 -// CHECK: %23 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 -// CHECK: %24 = coredsl.cast %0 : ui1 to ui4 -// CHECK: %25 = coredsl.bitset %23[3:0] = %24 : (ui32, ui4) -> ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %21 : si32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %22 : ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %25 : ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %20 : ui32 %imm = coredsl.cast %TREENAIL_WAS_HERE_imm_11_0 : ui12 to ui12 %rs1 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 %rd = coredsl.cast %TREENAIL_WAS_HERE_rd_4_0 : ui5 to ui5 @@ -61,14 +54,8 @@ coredsl.isax "StructRegisters" { %1 = coredsl.cast %rs1 : ui5 to ui32 %2 = hw.struct_inject %0["x"], %1 : !hw.struct coredsl.set @STRUCT_REG = %2 : !hw.struct - %3 = hwarith.constant 1 : ui1 %4 = coredsl.get @STRUCT_REG : !hw.struct %5 = hw.struct_extract %4["x"] : !hw.struct - %6 = hwarith.sub %5, %3 : (ui32, ui1) -> si33 - %7 = coredsl.get @STRUCT_REG : !hw.struct - %8 = coredsl.cast %6 : si33 to ui32 - %9 = hw.struct_inject %7["x"], %8 : !hw.struct - coredsl.set @STRUCT_REG = %9 : !hw.struct %10 = hwarith.constant 7 : ui3 %11 = coredsl.get @NESTED_STRUCT_REG : !hw.struct> %12 = hw.struct_extract %11["vec"] : !hw.struct> From d00289ba8d93bb138389c8044bb726b6bf75c148 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 27 Jul 2026 10:56:43 +0200 Subject: [PATCH 13/45] Added another test with non-struct registers to test both non-struct registers and to see whether all struct operations are canonicalized out --- .../explode_struct_registers.mlir | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir index 6a749ed..4a78290 100644 --- a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir +++ b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir @@ -5,6 +5,8 @@ coredsl.isax "StructRegisters" { coredsl.register local @STRUCT_REG : !hw.struct coredsl.register local @NESTED_STRUCT_REG : !hw.struct> coredsl.register local @TRIPLE_NESTED_REG : !hw.struct>, intVal: ui32> + coredsl.register local @SCALAR_REG1 : ui32 + coredsl.register local @SCALAR_REG2 : ui32 // CHECK: coredsl.register local @STRUCT_REG_x : ui32 // CHECK: coredsl.register local @STRUCT_REG_y : ui32 // CHECK: coredsl.register local @NESTED_STRUCT_REG_notNested : si32 @@ -14,6 +16,8 @@ coredsl.isax "StructRegisters" { // CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_vec_x : ui32 // CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_vec_y : ui32 // CHECK: coredsl.register local @TRIPLE_NESTED_REG_intVal : ui32 +// CHECK: coredsl.register local @SCALAR_REG1 : ui32 +// CHECK: coredsl.register local @SCALAR_REG2 : ui32 coredsl.instruction @StructRegDirectStore {lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { // CHECK: %0 = hwarith.constant 0 : ui1 @@ -80,4 +84,22 @@ coredsl.isax "StructRegisters" { coredsl.set @NESTED_STRUCT_REG = %28 : !hw.struct> coredsl.end } + coredsl.instruction @TransferStructToScalarReg{lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { +// CHECK: %0 = hwarith.constant 1 : ui1 +// CHECK: %1 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %2 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %3 = hwarith.add %1, %0 : (ui32, ui1) -> ui33 +// CHECK: %4 = coredsl.cast %3 : ui33 to ui32 +// CHECK: coredsl.set @SCALAR_REG1 = %4 : ui32 +// CHECK: coredsl.set @SCALAR_REG2 = %2 : ui32 + %0 = coredsl.get @STRUCT_REG : !hw.struct + %1 = hw.struct_extract %0["x"] : !hw.struct + %2 = hw.struct_extract %0["y"] : !hw.struct + %3 = hwarith.constant 1 : ui1 + %4 = hwarith.add %1, %3 : (ui32, ui1) -> ui33 + %5 = coredsl.cast %4 : ui33 to ui32 + coredsl.set @SCALAR_REG1 = %5 : ui32 + coredsl.set @SCALAR_REG2 = %2 : ui32 + coredsl.end + } } From db9c39815d4c6465587e1d8f5ff6deb262ef64af Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 27 Jul 2026 11:01:35 +0200 Subject: [PATCH 14/45] Removed TODO comments --- .../CoreDSLExplodeStructRegisters.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 8445364..e9514eb 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -26,7 +26,6 @@ void explodeRegs(StringRef regName, hw::StructType type, StructMemberEntryAction structMemberEntryAction, StructMemberExitAction structMemberExitAction) { for (hw::StructType::FieldInfo fieldInfo : type.getElements()) { - // auto newRegName = regName + "_" + fieldInfo.name.getValue(); auto newRegName = std::string(regName); newRegName += "_"; newRegName += fieldInfo.name.getValue(); @@ -65,7 +64,6 @@ struct StructExploderPattern : public OpConversionPattern { op.getAccessMode()); }, [](hw::StructType, StringAttr) {}, [](hw::StructType, StringAttr) {}); - // TODO: not sure if this will work, as the reg is still used rewriter.eraseOp(op); return LogicalResult::success(); } @@ -97,8 +95,6 @@ struct StructRewriteSetOps : public OpConversionPattern { }, [&rewriter, &opStack, &loc](hw::StructType type, StringAttr fieldName) { - // TODO: emit hw.struct_extract and push result on stack - // TODO: get extracted value auto toExtractFrom = opStack.back(); Value structVal = toExtractFrom->getResult(0); assert(llvm::isa(structVal.getType())); @@ -128,7 +124,6 @@ struct StructRewriteGetOps : public OpConversionPattern { auto loc = op.getLoc(); SmallVector structMembers; size_t structBeginIdx = 0; - // TODO: need to combine the gotten vavlues into a struct explodeRegs( symbolName, structType, rewriter, [&rewriter, &loc, &structMembers]( @@ -142,7 +137,6 @@ struct StructRewriteGetOps : public OpConversionPattern { }, [&rewriter, &loc, &structBeginIdx, &structMembers](hw::StructType type, StringAttr fieldName) { - // TODO: hope this does not scramble struct members auto currStructMembers = ArrayRef( structMembers.begin() + structBeginIdx, structMembers.end()); auto structVal = hw::StructCreateOp::create(rewriter, loc, type, @@ -150,8 +144,6 @@ struct StructRewriteGetOps : public OpConversionPattern { structMembers.resize(structBeginIdx); structMembers.push_back(structVal.getResult()); }); - // TODO: hope this does not scramble struct members - // TODO: this crashes :( auto finalStruct = hw::StructCreateOp::create(rewriter, loc, type, structMembers); rewriter.replaceOp(op, finalStruct.getResult()); From 77399293ad46c74179430b10c68786a8ce722165 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 27 Jul 2026 13:26:32 +0200 Subject: [PATCH 15/45] Added triple nested load and store to test --- .../explode_struct_registers.mlir | 80 ++++++++++++------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir index 4a78290..91e09fe 100644 --- a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir +++ b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir @@ -20,37 +20,46 @@ coredsl.isax "StructRegisters" { // CHECK: coredsl.register local @SCALAR_REG2 : ui32 coredsl.instruction @StructRegDirectStore {lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { -// CHECK: %0 = hwarith.constant 0 : ui1 -// CHECK: %1 = hwarith.constant 255 : ui8 -// CHECK: %2 = hwarith.constant 7 : ui3 -// CHECK: %3 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 -// CHECK: %4 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %5 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %6 = coredsl.cast %3 : ui5 to ui32 -// CHECK: coredsl.set @STRUCT_REG_x = %6 : ui32 -// CHECK: coredsl.set @STRUCT_REG_y = %5 : ui32 -// CHECK: %7 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %8 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %9 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 -// CHECK: %10 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 -// CHECK: %11 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 -// CHECK: %12 = coredsl.cast %2 : ui3 to ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %9 : si32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %12 : ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %11 : ui32 -// CHECK: %13 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %14 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %15 = coredsl.bitset %13[7:0] = %1 : (ui32, ui8) -> ui32 -// CHECK: coredsl.set @STRUCT_REG_x = %15 : ui32 -// CHECK: coredsl.set @STRUCT_REG_y = %14 : ui32 -// CHECK: %16 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 -// CHECK: %17 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 -// CHECK: %18 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 -// CHECK: %19 = coredsl.cast %0 : ui1 to ui4 -// CHECK: %20 = coredsl.bitset %18[3:0] = %19 : (ui32, ui4) -> ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %16 : si32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %17 : ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %20 : ui32 +// CHECK: %0 = hwarith.constant -1 : si32 +// CHECK: %1 = hwarith.constant 0 : ui1 +// CHECK: %2 = hwarith.constant 255 : ui8 +// CHECK: %3 = hwarith.constant 7 : ui3 +// CHECK: %4 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 +// CHECK: %5 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %6 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %7 = coredsl.cast %4 : ui5 to ui32 +// CHECK: coredsl.set @STRUCT_REG_x = %7 : ui32 +// CHECK: coredsl.set @STRUCT_REG_y = %6 : ui32 +// CHECK: %8 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %9 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %10 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 +// CHECK: %11 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: %12 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: %13 = coredsl.cast %3 : ui3 to ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %10 : si32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %13 : ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %12 : ui32 +// CHECK: %14 = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %15 = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %16 = coredsl.bitset %14[7:0] = %2 : (ui32, ui8) -> ui32 +// CHECK: coredsl.set @STRUCT_REG_x = %16 : ui32 +// CHECK: coredsl.set @STRUCT_REG_y = %15 : ui32 +// CHECK: %17 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 +// CHECK: %18 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: %19 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: %20 = coredsl.cast %1 : ui1 to ui4 +// CHECK: %21 = coredsl.bitset %19[3:0] = %20 : (ui32, ui4) -> ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %17 : si32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %18 : ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %21 : ui32 +// CHECK: %22 = coredsl.get @TRIPLE_NESTED_REG_internalStruct_notNested : si32 +// CHECK: %23 = coredsl.get @TRIPLE_NESTED_REG_internalStruct_vec_x : ui32 +// CHECK: %24 = coredsl.get @TRIPLE_NESTED_REG_internalStruct_vec_y : ui32 +// CHECK: %25 = coredsl.get @TRIPLE_NESTED_REG_intVal : ui32 +// CHECK: coredsl.set @TRIPLE_NESTED_REG_internalStruct_notNested = %0 : si32 +// CHECK: coredsl.set @TRIPLE_NESTED_REG_internalStruct_vec_x = %21 : ui32 +// CHECK: coredsl.set @TRIPLE_NESTED_REG_internalStruct_vec_y = %24 : ui32 +// CHECK: coredsl.set @TRIPLE_NESTED_REG_intVal = %25 : ui32 %imm = coredsl.cast %TREENAIL_WAS_HERE_imm_11_0 : ui12 to ui12 %rs1 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 %rd = coredsl.cast %TREENAIL_WAS_HERE_rd_4_0 : ui5 to ui5 @@ -82,6 +91,15 @@ coredsl.isax "StructRegisters" { %27 = hw.struct_inject %23["y"], %26 : !hw.struct %28 = hw.struct_inject %22["vec"], %27 : !hw.struct> coredsl.set @NESTED_STRUCT_REG = %28 : !hw.struct> + %29 = coredsl.get @TRIPLE_NESTED_REG : !hw.struct>, intVal: ui32> + %30 = hw.struct_extract %29["internalStruct"] : !hw.struct>, intVal: ui32> + %31 = hwarith.constant -1 : si32 + %32 = hw.struct_inject %30["notNested"], %31 : !hw.struct> + %33 = hw.struct_extract %32["vec"] : !hw.struct> + %34 = hw.struct_inject %33["x"], %26 : !hw.struct + %35 = hw.struct_inject %32["vec"], %34 : !hw.struct> + %36 = hw.struct_inject %29["internalStruct"], %35 : !hw.struct>, intVal: ui32> + coredsl.set @TRIPLE_NESTED_REG = %36 : !hw.struct>, intVal: ui32> coredsl.end } coredsl.instruction @TransferStructToScalarReg{lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { From 93fecd7378be4a9f45a2812f1d2ef716b09ac015 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 27 Jul 2026 13:27:55 +0200 Subject: [PATCH 16/45] Fixed issues that happen when structs are nested deeper than 2 --- .../CoreDSLExplodeStructRegisters.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index e9514eb..4fbda35 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -102,7 +102,7 @@ struct StructRewriteSetOps : public OpConversionPattern { rewriter, loc, toExtractFrom->getResult(0), fieldName); opStack.push_back(extractOp); }, - [](hw::StructType, StringAttr) {}); + [&opStack](hw::StructType, StringAttr) { opStack.pop_back(); }); rewriter.eraseOp(op); return LogicalResult::success(); } @@ -123,7 +123,7 @@ struct StructRewriteGetOps : public OpConversionPattern { auto loc = op.getLoc(); SmallVector structMembers; - size_t structBeginIdx = 0; + SmallVector structBeginIndices = {0}; explodeRegs( symbolName, structType, rewriter, [&rewriter, &loc, &structMembers]( @@ -132,16 +132,18 @@ struct StructRewriteGetOps : public OpConversionPattern { rewriter, loc, type, nullptr, nullptr, nullptr, newRegName); structMembers.push_back(gotValue.getResult()); }, - [&structBeginIdx, &structMembers](hw::StructType, StringAttr) { - structBeginIdx = structMembers.size(); + [&structBeginIndices, &structMembers](hw::StructType, StringAttr) { + structBeginIndices.push_back(structMembers.size()); }, - [&rewriter, &loc, &structBeginIdx, + [&rewriter, &loc, &structBeginIndices, &structMembers](hw::StructType type, StringAttr fieldName) { + const size_t structBeginIdx = structBeginIndices.back(); auto currStructMembers = ArrayRef( structMembers.begin() + structBeginIdx, structMembers.end()); auto structVal = hw::StructCreateOp::create(rewriter, loc, type, currStructMembers); structMembers.resize(structBeginIdx); + structBeginIndices.pop_back(); structMembers.push_back(structVal.getResult()); }); auto finalStruct = From 419a0ce9eb3b7accf0e80240344a0c1743e5318f Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 27 Jul 2026 13:44:04 +0200 Subject: [PATCH 17/45] Ran generate-test-checks.py on test --- .../explode_struct_registers.mlir | 125 ++++++++++-------- 1 file changed, 67 insertions(+), 58 deletions(-) diff --git a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir index 91e09fe..05199f6 100644 --- a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir +++ b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir @@ -7,59 +7,8 @@ coredsl.isax "StructRegisters" { coredsl.register local @TRIPLE_NESTED_REG : !hw.struct>, intVal: ui32> coredsl.register local @SCALAR_REG1 : ui32 coredsl.register local @SCALAR_REG2 : ui32 -// CHECK: coredsl.register local @STRUCT_REG_x : ui32 -// CHECK: coredsl.register local @STRUCT_REG_y : ui32 -// CHECK: coredsl.register local @NESTED_STRUCT_REG_notNested : si32 -// CHECK: coredsl.register local @NESTED_STRUCT_REG_vec_x : ui32 -// CHECK: coredsl.register local @NESTED_STRUCT_REG_vec_y : ui32 -// CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_notNested : si32 -// CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_vec_x : ui32 -// CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_vec_y : ui32 -// CHECK: coredsl.register local @TRIPLE_NESTED_REG_intVal : ui32 -// CHECK: coredsl.register local @SCALAR_REG1 : ui32 -// CHECK: coredsl.register local @SCALAR_REG2 : ui32 coredsl.instruction @StructRegDirectStore {lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { -// CHECK: %0 = hwarith.constant -1 : si32 -// CHECK: %1 = hwarith.constant 0 : ui1 -// CHECK: %2 = hwarith.constant 255 : ui8 -// CHECK: %3 = hwarith.constant 7 : ui3 -// CHECK: %4 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 -// CHECK: %5 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %6 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %7 = coredsl.cast %4 : ui5 to ui32 -// CHECK: coredsl.set @STRUCT_REG_x = %7 : ui32 -// CHECK: coredsl.set @STRUCT_REG_y = %6 : ui32 -// CHECK: %8 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %9 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %10 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 -// CHECK: %11 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 -// CHECK: %12 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 -// CHECK: %13 = coredsl.cast %3 : ui3 to ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %10 : si32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %13 : ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %12 : ui32 -// CHECK: %14 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %15 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %16 = coredsl.bitset %14[7:0] = %2 : (ui32, ui8) -> ui32 -// CHECK: coredsl.set @STRUCT_REG_x = %16 : ui32 -// CHECK: coredsl.set @STRUCT_REG_y = %15 : ui32 -// CHECK: %17 = coredsl.get @NESTED_STRUCT_REG_notNested : si32 -// CHECK: %18 = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 -// CHECK: %19 = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 -// CHECK: %20 = coredsl.cast %1 : ui1 to ui4 -// CHECK: %21 = coredsl.bitset %19[3:0] = %20 : (ui32, ui4) -> ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %17 : si32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %18 : ui32 -// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %21 : ui32 -// CHECK: %22 = coredsl.get @TRIPLE_NESTED_REG_internalStruct_notNested : si32 -// CHECK: %23 = coredsl.get @TRIPLE_NESTED_REG_internalStruct_vec_x : ui32 -// CHECK: %24 = coredsl.get @TRIPLE_NESTED_REG_internalStruct_vec_y : ui32 -// CHECK: %25 = coredsl.get @TRIPLE_NESTED_REG_intVal : ui32 -// CHECK: coredsl.set @TRIPLE_NESTED_REG_internalStruct_notNested = %0 : si32 -// CHECK: coredsl.set @TRIPLE_NESTED_REG_internalStruct_vec_x = %21 : ui32 -// CHECK: coredsl.set @TRIPLE_NESTED_REG_internalStruct_vec_y = %24 : ui32 -// CHECK: coredsl.set @TRIPLE_NESTED_REG_intVal = %25 : ui32 %imm = coredsl.cast %TREENAIL_WAS_HERE_imm_11_0 : ui12 to ui12 %rs1 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 %rd = coredsl.cast %TREENAIL_WAS_HERE_rd_4_0 : ui5 to ui5 @@ -103,13 +52,6 @@ coredsl.isax "StructRegisters" { coredsl.end } coredsl.instruction @TransferStructToScalarReg{lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { -// CHECK: %0 = hwarith.constant 1 : ui1 -// CHECK: %1 = coredsl.get @STRUCT_REG_x : ui32 -// CHECK: %2 = coredsl.get @STRUCT_REG_y : ui32 -// CHECK: %3 = hwarith.add %1, %0 : (ui32, ui1) -> ui33 -// CHECK: %4 = coredsl.cast %3 : ui33 to ui32 -// CHECK: coredsl.set @SCALAR_REG1 = %4 : ui32 -// CHECK: coredsl.set @SCALAR_REG2 = %2 : ui32 %0 = coredsl.get @STRUCT_REG : !hw.struct %1 = hw.struct_extract %0["x"] : !hw.struct %2 = hw.struct_extract %0["y"] : !hw.struct @@ -121,3 +63,70 @@ coredsl.isax "StructRegisters" { coredsl.end } } + +// CHECK-LABEL: coredsl.isax "StructRegisters" { +// CHECK: coredsl.register local @STRUCT_REG_x : ui32 +// CHECK: coredsl.register local @STRUCT_REG_y : ui32 +// CHECK: coredsl.register local @NESTED_STRUCT_REG_notNested : si32 +// CHECK: coredsl.register local @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: coredsl.register local @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_notNested : si32 +// CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_vec_x : ui32 +// CHECK: coredsl.register local @TRIPLE_NESTED_REG_internalStruct_vec_y : ui32 +// CHECK: coredsl.register local @TRIPLE_NESTED_REG_intVal : ui32 +// CHECK: coredsl.register local @SCALAR_REG1 : ui32 +// CHECK: coredsl.register local @SCALAR_REG2 : ui32 +// CHECK: coredsl.instruction @StructRegDirectStore {lil.enc_immediates = {{\[\[}}["%[[VAL_0:.*]]", 11, 0, 0, "imm"]], {{\[\[}}"%[[VAL_1:.*]]", 4, 0, 0, "rs1"]], {{\[\[}}"%[[VAL_2:.*]]", 4, 0, 0, "rd"]]]}(%[[VAL_0]] : ui12, %[[VAL_1]] : ui5, "010", %[[VAL_2]] : ui5, "0000011"){ +// CHECK: %[[CONSTANT_0:.*]] = hwarith.constant -1 : si32 +// CHECK: %[[CONSTANT_1:.*]] = hwarith.constant 0 : ui1 +// CHECK: %[[CONSTANT_2:.*]] = hwarith.constant 255 : ui8 +// CHECK: %[[CONSTANT_3:.*]] = hwarith.constant 7 : ui3 +// CHECK: %[[CAST_0:.*]] = coredsl.cast %[[VAL_1]] : ui5 to ui5 +// CHECK: %[[GET_0:.*]] = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %[[GET_1:.*]] = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %[[CAST_1:.*]] = coredsl.cast %[[CAST_0]] : ui5 to ui32 +// CHECK: coredsl.set @STRUCT_REG_x = %[[CAST_1]] : ui32 +// CHECK: coredsl.set @STRUCT_REG_y = %[[GET_1]] : ui32 +// CHECK: %[[GET_2:.*]] = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %[[GET_3:.*]] = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %[[GET_4:.*]] = coredsl.get @NESTED_STRUCT_REG_notNested : si32 +// CHECK: %[[GET_5:.*]] = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: %[[GET_6:.*]] = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: %[[CAST_2:.*]] = coredsl.cast %[[CONSTANT_3]] : ui3 to ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %[[GET_4]] : si32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %[[CAST_2]] : ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %[[GET_6]] : ui32 +// CHECK: %[[GET_7:.*]] = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %[[GET_8:.*]] = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %[[BITSET_0:.*]] = coredsl.bitset %[[GET_7]][7:0] = %[[CONSTANT_2]] : (ui32, ui8) -> ui32 +// CHECK: coredsl.set @STRUCT_REG_x = %[[BITSET_0]] : ui32 +// CHECK: coredsl.set @STRUCT_REG_y = %[[GET_8]] : ui32 +// CHECK: %[[GET_9:.*]] = coredsl.get @NESTED_STRUCT_REG_notNested : si32 +// CHECK: %[[GET_10:.*]] = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: %[[GET_11:.*]] = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: %[[CAST_3:.*]] = coredsl.cast %[[CONSTANT_1]] : ui1 to ui4 +// CHECK: %[[BITSET_1:.*]] = coredsl.bitset %[[GET_11]][3:0] = %[[CAST_3]] : (ui32, ui4) -> ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_notNested = %[[GET_9]] : si32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_x = %[[GET_10]] : ui32 +// CHECK: coredsl.set @NESTED_STRUCT_REG_vec_y = %[[BITSET_1]] : ui32 +// CHECK: %[[GET_12:.*]] = coredsl.get @TRIPLE_NESTED_REG_internalStruct_notNested : si32 +// CHECK: %[[GET_13:.*]] = coredsl.get @TRIPLE_NESTED_REG_internalStruct_vec_x : ui32 +// CHECK: %[[GET_14:.*]] = coredsl.get @TRIPLE_NESTED_REG_internalStruct_vec_y : ui32 +// CHECK: %[[GET_15:.*]] = coredsl.get @TRIPLE_NESTED_REG_intVal : ui32 +// CHECK: coredsl.set @TRIPLE_NESTED_REG_internalStruct_notNested = %[[CONSTANT_0]] : si32 +// CHECK: coredsl.set @TRIPLE_NESTED_REG_internalStruct_vec_x = %[[BITSET_1]] : ui32 +// CHECK: coredsl.set @TRIPLE_NESTED_REG_internalStruct_vec_y = %[[GET_14]] : ui32 +// CHECK: coredsl.set @TRIPLE_NESTED_REG_intVal = %[[GET_15]] : ui32 +// CHECK: coredsl.end +// CHECK: } +// CHECK: coredsl.instruction @TransferStructToScalarReg {lil.enc_immediates = {{\[\[}}["%[[VAL_3:.*]]", 11, 0, 0, "imm"]], {{\[\[}}"%[[VAL_4:.*]]", 4, 0, 0, "rs1"]], {{\[\[}}"%[[VAL_5:.*]]", 4, 0, 0, "rd"]]]}(%[[VAL_3]] : ui12, %[[VAL_4]] : ui5, "010", %[[VAL_5]] : ui5, "0000011"){ +// CHECK: %[[CONSTANT_4:.*]] = hwarith.constant 1 : ui1 +// CHECK: %[[GET_16:.*]] = coredsl.get @STRUCT_REG_x : ui32 +// CHECK: %[[GET_17:.*]] = coredsl.get @STRUCT_REG_y : ui32 +// CHECK: %[[ADD_0:.*]] = hwarith.add %[[GET_16]], %[[CONSTANT_4]] : (ui32, ui1) -> ui33 +// CHECK: %[[CAST_4:.*]] = coredsl.cast %[[ADD_0]] : ui33 to ui32 +// CHECK: coredsl.set @SCALAR_REG1 = %[[CAST_4]] : ui32 +// CHECK: coredsl.set @SCALAR_REG2 = %[[GET_17]] : ui32 +// CHECK: coredsl.end +// CHECK: } +// CHECK: } From 6f3aeb4753b5cc3d954ef177d20e9a58a0da9561 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 27 Jul 2026 14:43:07 +0200 Subject: [PATCH 18/45] Added numElements to RegisterOp::create (still need to properly handle get and set operations with indices) --- .../CoreDSLExplodeStructRegisters.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 4fbda35..f0c02ca 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -49,18 +49,20 @@ struct StructExploderPattern : public OpConversionPattern { matchAndRewrite(coredsl::RegisterOp op, OpAdaptor, ConversionPatternRewriter &rewriter) const override { if (auto structType = llvm::dyn_cast(op.getRegType())) { + auto numElements = op.getNumElementsAttr(); StringRef name = op.getName(); rewriter.setInsertionPointAfter(op); Location loc = op.getLoc(); explodeRegs( name, structType, rewriter, - [&rewriter, &loc, &op](StringRef newRegName, StringAttr fieldName, - IntegerType fieldType) { + [&rewriter, &loc, &op, &numElements](StringRef newRegName, + StringAttr fieldName, + IntegerType fieldType) { auto ctx = rewriter.getContext(); StringAttr symbolName = StringAttr::get(ctx, newRegName); coredsl::RegisterOp::create(rewriter, loc, {}, symbolName, op.getIsConst(), op.getIsVolatile(), - /*numElements=*/nullptr, {}, fieldType, + numElements, {}, fieldType, op.getAccessMode()); }, [](hw::StructType, StringAttr) {}, [](hw::StructType, StringAttr) {}); From 89976e5b5c79b89cd6abcfdf56ad959ea7b05b37 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 27 Jul 2026 15:02:35 +0200 Subject: [PATCH 19/45] Added struct typed register file to test --- .../explode_struct_registers.mlir | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir index 05199f6..f96a16c 100644 --- a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir +++ b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir @@ -7,6 +7,7 @@ coredsl.isax "StructRegisters" { coredsl.register local @TRIPLE_NESTED_REG : !hw.struct>, intVal: ui32> coredsl.register local @SCALAR_REG1 : ui32 coredsl.register local @SCALAR_REG2 : ui32 + coredsl.register local @STRUCT_REGS[32] : !hw.struct> coredsl.instruction @StructRegDirectStore {lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { %imm = coredsl.cast %TREENAIL_WAS_HERE_imm_11_0 : ui12 to ui12 @@ -62,6 +63,18 @@ coredsl.isax "StructRegisters" { coredsl.set @SCALAR_REG2 = %2 : ui32 coredsl.end } + + coredsl.instruction @StructArrays{lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { + %rs1 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 + %21 = coredsl.get @NESTED_STRUCT_REG : !hw.struct> + coredsl.set @STRUCT_REGS[2] = %21 : !hw.struct> + %22 = hwarith.constant 10 : ui4 + %23 = coredsl.get @STRUCT_REGS[%rs1 : ui5] : !hw.struct> + %24 = coredsl.cast %22 : ui4 to si32 + %25 = hw.struct_inject %23["notNested"], %24 : !hw.struct> + coredsl.set @STRUCT_REGS[%rs1 : ui5] = %25 : !hw.struct> + coredsl.end + } } // CHECK-LABEL: coredsl.isax "StructRegisters" { @@ -76,6 +89,9 @@ coredsl.isax "StructRegisters" { // CHECK: coredsl.register local @TRIPLE_NESTED_REG_intVal : ui32 // CHECK: coredsl.register local @SCALAR_REG1 : ui32 // CHECK: coredsl.register local @SCALAR_REG2 : ui32 +// CHECK: coredsl.register local @STRUCT_REGS_notNested[32] : si32 +// CHECK: coredsl.register local @STRUCT_REGS_vec_x[32] : ui32 +// CHECK: coredsl.register local @STRUCT_REGS_vec_y[32] : ui32 // CHECK: coredsl.instruction @StructRegDirectStore {lil.enc_immediates = {{\[\[}}["%[[VAL_0:.*]]", 11, 0, 0, "imm"]], {{\[\[}}"%[[VAL_1:.*]]", 4, 0, 0, "rs1"]], {{\[\[}}"%[[VAL_2:.*]]", 4, 0, 0, "rd"]]]}(%[[VAL_0]] : ui12, %[[VAL_1]] : ui5, "010", %[[VAL_2]] : ui5, "0000011"){ // CHECK: %[[CONSTANT_0:.*]] = hwarith.constant -1 : si32 // CHECK: %[[CONSTANT_1:.*]] = hwarith.constant 0 : ui1 @@ -129,4 +145,22 @@ coredsl.isax "StructRegisters" { // CHECK: coredsl.set @SCALAR_REG2 = %[[GET_17]] : ui32 // CHECK: coredsl.end // CHECK: } +// CHECK: coredsl.instruction @StructArrays {lil.enc_immediates = {{\[\[}}["%[[VAL_6:.*]]", 11, 0, 0, "imm"]], {{\[\[}}"%[[VAL_7:.*]]", 4, 0, 0, "rs1"]], {{\[\[}}"%[[VAL_8:.*]]", 4, 0, 0, "rd"]]]}(%[[VAL_6]] : ui12, %[[VAL_7]] : ui5, "010", %[[VAL_8]] : ui5, "0000011"){ +// CHECK: %[[CONSTANT_5:.*]] = hwarith.constant 10 : ui4 +// CHECK: %[[CAST_5:.*]] = coredsl.cast %[[VAL_7]] : ui5 to ui5 +// CHECK: %[[GET_18:.*]] = coredsl.get @NESTED_STRUCT_REG_notNested : si32 +// CHECK: %[[GET_19:.*]] = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 +// CHECK: %[[GET_20:.*]] = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 +// CHECK: coredsl.set @STRUCT_REGS_notNested[2] = %[[GET_18]] : si32 +// CHECK: coredsl.set @STRUCT_REGS_vec_x[2] = %[[GET_19]] : ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_y[2] = %[[GET_20]] : ui32 +// CHECK: %[[GET_21:.*]] = coredsl.get @STRUCT_REGS_notNested{{\[}}%[[CAST_5]] : ui5] : si32 +// CHECK: %[[GET_22:.*]] = coredsl.get @STRUCT_REGS_vec_x{{\[}}%[[CAST_5]] : ui5] : ui32 +// CHECK: %[[GET_23:.*]] = coredsl.get @STRUCT_REGS_vec_y{{\[}}%[[CAST_5]] : ui5] : ui32 +// CHECK: %[[CAST_6:.*]] = coredsl.cast %[[CONSTANT_5]] : ui4 to si32 +// CHECK: coredsl.set @STRUCT_REGS_notNested{{\[}}%[[CAST_5]] : ui5] = %[[CAST_6]] : si32 +// CHECK: coredsl.set @STRUCT_REGS_vec_x{{\[}}%[[CAST_5]] : ui5] = %[[GET_22]] : ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_y{{\[}}%[[CAST_5]] : ui5] = %[[GET_23]] : ui32 +// CHECK: coredsl.end +// CHECK: } // CHECK: } From b9b939c7bf2543b8c6e6a95b212310c4a53ed10c Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 27 Jul 2026 15:02:53 +0200 Subject: [PATCH 20/45] Implemented register file access --- .../CoreDSLExplodeStructRegisters.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index f0c02ca..456c129 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -81,18 +81,21 @@ struct StructRewriteSetOps : public OpConversionPattern { matchAndRewrite(coredsl::SetOp op, OpAdaptor, ConversionPatternRewriter &rewriter) const override { auto value = op.getValue(); + auto base = op.getBase(); + auto from = op.getFromAttr(); + auto to = op.getToAttr(); if (auto structType = llvm::dyn_cast(value.getType())) { StringRef symbolName = op.getSym(); auto loc = op.getLoc(); SmallVector opStack{op.getValue().getDefiningOp()}; explodeRegs( symbolName, structType, rewriter, - [&rewriter, &opStack, &loc](StringRef newRegName, + [&rewriter, &opStack, &loc, &base, &from, &to](StringRef newRegName, StringAttr fieldName, IntegerType type) { auto writtenValue = opStack.back(); auto extractOp = hw::StructExtractOp::create( rewriter, loc, writtenValue->getResult(0), fieldName); - coredsl::SetOp::create(rewriter, loc, nullptr, nullptr, nullptr, + coredsl::SetOp::create(rewriter, loc, base, from, to, newRegName, extractOp->getResult(0)); }, [&rewriter, &opStack, &loc](hw::StructType type, @@ -123,15 +126,18 @@ struct StructRewriteGetOps : public OpConversionPattern { if (auto structType = llvm::dyn_cast(type)) { StringRef symbolName = op.getSym(); + auto base = op.getBase(); + auto from = op.getFromAttr(); + auto to = op.getToAttr(); auto loc = op.getLoc(); SmallVector structMembers; SmallVector structBeginIndices = {0}; explodeRegs( symbolName, structType, rewriter, - [&rewriter, &loc, &structMembers]( + [&rewriter, &loc, &structMembers, &base, &from, &to]( StringRef newRegName, StringAttr fieldName, IntegerType type) { auto gotValue = coredsl::GetOp::create( - rewriter, loc, type, nullptr, nullptr, nullptr, newRegName); + rewriter, loc, type, base, from, to, newRegName); structMembers.push_back(gotValue.getResult()); }, [&structBeginIndices, &structMembers](hw::StructType, StringAttr) { From daaa10f7e36db63b4a35c9d031b4b2350f282f5e Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 27 Jul 2026 15:03:19 +0200 Subject: [PATCH 21/45] Formatting --- .../CoreDSLExplodeStructRegisters.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 456c129..8605d54 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -90,13 +90,13 @@ struct StructRewriteSetOps : public OpConversionPattern { SmallVector opStack{op.getValue().getDefiningOp()}; explodeRegs( symbolName, structType, rewriter, - [&rewriter, &opStack, &loc, &base, &from, &to](StringRef newRegName, - StringAttr fieldName, IntegerType type) { + [&rewriter, &opStack, &loc, &base, &from, + &to](StringRef newRegName, StringAttr fieldName, IntegerType type) { auto writtenValue = opStack.back(); auto extractOp = hw::StructExtractOp::create( rewriter, loc, writtenValue->getResult(0), fieldName); - coredsl::SetOp::create(rewriter, loc, base, from, to, - newRegName, extractOp->getResult(0)); + coredsl::SetOp::create(rewriter, loc, base, from, to, newRegName, + extractOp->getResult(0)); }, [&rewriter, &opStack, &loc](hw::StructType type, StringAttr fieldName) { @@ -134,10 +134,10 @@ struct StructRewriteGetOps : public OpConversionPattern { SmallVector structBeginIndices = {0}; explodeRegs( symbolName, structType, rewriter, - [&rewriter, &loc, &structMembers, &base, &from, &to]( - StringRef newRegName, StringAttr fieldName, IntegerType type) { - auto gotValue = coredsl::GetOp::create( - rewriter, loc, type, base, from, to, newRegName); + [&rewriter, &loc, &structMembers, &base, &from, + &to](StringRef newRegName, StringAttr fieldName, IntegerType type) { + auto gotValue = coredsl::GetOp::create(rewriter, loc, type, base, + from, to, newRegName); structMembers.push_back(gotValue.getResult()); }, [&structBeginIndices, &structMembers](hw::StructType, StringAttr) { From e2ebd76d41c796cbb400688203bdc49d24d997b7 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 28 Jul 2026 11:50:11 +0200 Subject: [PATCH 22/45] Removed outdated TODO --- .../CoreDSLExplodeStructRegisters/explode_struct_registers.mlir | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir index f96a16c..2c3d03c 100644 --- a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir +++ b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir @@ -1,6 +1,5 @@ // RUN: shortnail-opt %s -coredsl-explode-struct-registers -canonicalize | shortnail-opt | FileCheck %s -// TODO: add test with triple nested struct coredsl.isax "StructRegisters" { coredsl.register local @STRUCT_REG : !hw.struct coredsl.register local @NESTED_STRUCT_REG : !hw.struct> From 7376f8a6409be874d13e535a16bdc8c68d8edcfd Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 10 Aug 2026 13:58:40 +0200 Subject: [PATCH 23/45] Added a canonicalization pattern that legalizes hw.constant operations of non-signless types. This fixes an error happening in longnail when inlining a function of a struct type. The canonicalizer tries to insert a hw.constant op if the struct members are constants. It does not respect signedeness, which causes this error --- include/shortnail/Dialect/CoreDSL/CoreDSL.td | 1 + lib/Dialect/CoreDSL/CoreDSLDialect.cpp | 35 ++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/shortnail/Dialect/CoreDSL/CoreDSL.td b/include/shortnail/Dialect/CoreDSL/CoreDSL.td index 7c21862..87936f2 100644 --- a/include/shortnail/Dialect/CoreDSL/CoreDSL.td +++ b/include/shortnail/Dialect/CoreDSL/CoreDSL.td @@ -98,6 +98,7 @@ def CoreDSL_Dialect : Dialect { "comb::CombDialect", ]; let cppNamespace = "::mlir::coredsl"; + let hasCanonicalizer = 1; } //===----------------------------------------------------------------------===// diff --git a/lib/Dialect/CoreDSL/CoreDSLDialect.cpp b/lib/Dialect/CoreDSL/CoreDSLDialect.cpp index e8c3dfd..b1c610f 100644 --- a/lib/Dialect/CoreDSL/CoreDSLDialect.cpp +++ b/lib/Dialect/CoreDSL/CoreDSLDialect.cpp @@ -11,7 +11,9 @@ #include "circt/Dialect/Comb/CombDialect.h" #include "circt/Dialect/HW/HWDialect.h" +#include "circt/Dialect/HW/HWOps.h" #include "circt/Dialect/HWArith/HWArithDialect.h" +#include "circt/Dialect/HWArith/HWArithOps.h" #include "mlir/Dialect/ControlFlow/IR/ControlFlow.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/SCF/IR/SCF.h" @@ -80,6 +82,7 @@ struct CoreDSLInlinerInterface : public DialectInlinerInterface { //===----------------------------------------------------------------------===// void CoreDSLDialect::initialize() { + auto dialect = getContext()->getLoadedDialect(); addOperations< #define GET_OP_LIST #include "shortnail/Dialect/CoreDSL/CoreDSL.cpp.inc" @@ -87,6 +90,38 @@ void CoreDSLDialect::initialize() { addInterfaces(); } +namespace { + +// This pattern is necessary because the canonicalizer will emit hw.constant ops +// when invoked by the inliner. It does not check if an integer is actually of a +// signless type, which causes the patterns invoked by the canonicalizer to fail +// The error happens when the canonicalizer folds a hw.struct_extract op that +// returns a non-signless integer type +struct ConvertNonSignlessHWConstantToHWArith + : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(hw::ConstantOp op, + PatternRewriter &rewriter) const override { + auto type = op.getResult().getType(); + auto intType = cast(type); + if (!intType.isSignless()) { + auto hwConst = hwarith::ConstantOp::create(rewriter, op.getLoc(), intType, + op.getValueAttr()); + rewriter.replaceOp(op, hwConst); + return success(); + } + return failure(); + } +}; + +} // namespace + +void CoreDSLDialect::getCanonicalizationPatterns( + RewritePatternSet &results) const { + results.add(getContext()); +} + #include "shortnail/Dialect/CoreDSL/CoreDSLDialect.cpp.inc" #include "shortnail/Dialect/CoreDSL/CoreDSLEnums.cpp.inc" #include "shortnail/Dialect/CoreDSL/CoreDSLInterfaces.cpp.inc" From fd93737fe32319e7b6f5a3ebcecde11625670a75 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 11 Aug 2026 10:09:11 +0200 Subject: [PATCH 24/45] Removed unused link libraries --- lib/Conversion/CoreDSLExplodeStructRegisters/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CMakeLists.txt b/lib/Conversion/CoreDSLExplodeStructRegisters/CMakeLists.txt index b4c76c7..74f0d15 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CMakeLists.txt +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CMakeLists.txt @@ -7,10 +7,8 @@ add_shortnail_library(ShortnailCoreDSLExplodeStructRegisters LINK_LIBS PUBLIC MLIRIR MLIRPass - MLIRSCFUtils CIRCTHW - CIRCTSupport ShortnailCoreDSL ) From 4e578755d08632fc68e03ed0ee6a6f86a0fa95bd Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 11 Aug 2026 11:06:06 +0200 Subject: [PATCH 25/45] Removed unused variable --- lib/Dialect/CoreDSL/CoreDSLDialect.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Dialect/CoreDSL/CoreDSLDialect.cpp b/lib/Dialect/CoreDSL/CoreDSLDialect.cpp index b1c610f..ea39ab7 100644 --- a/lib/Dialect/CoreDSL/CoreDSLDialect.cpp +++ b/lib/Dialect/CoreDSL/CoreDSLDialect.cpp @@ -82,7 +82,6 @@ struct CoreDSLInlinerInterface : public DialectInlinerInterface { //===----------------------------------------------------------------------===// void CoreDSLDialect::initialize() { - auto dialect = getContext()->getLoadedDialect(); addOperations< #define GET_OP_LIST #include "shortnail/Dialect/CoreDSL/CoreDSL.cpp.inc" From 1e6019b121cc1f76958bf9d14064bf47fb0abc1f Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 11 Aug 2026 11:23:49 +0200 Subject: [PATCH 26/45] Formatting --- lib/Dialect/CoreDSL/CoreDSLOps.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/Dialect/CoreDSL/CoreDSLOps.cpp b/lib/Dialect/CoreDSL/CoreDSLOps.cpp index 5fba5a3..fd147af 100644 --- a/lib/Dialect/CoreDSL/CoreDSLOps.cpp +++ b/lib/Dialect/CoreDSL/CoreDSLOps.cpp @@ -10,9 +10,9 @@ #include "shortnail/Dialect/CoreDSL/CoreDSLDialect.h" #include "shortnail/Dialect/CoreDSL/CoreDSLDirectives.h" +#include "circt/Dialect/HW/HWOps.h" #include "circt/Dialect/HWArith/HWArithOps.h" #include "circt/Dialect/HWArith/HWArithTypes.h" -#include "circt/Dialect/HW/HWOps.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinOps.h" @@ -385,9 +385,7 @@ unsigned AddressSpaceOp::getMinIndexWidth() { // TODO restrict to the address width? // return getAddrType()->getIntOrFloatBitWidth(); } -Type AddressSpaceOp::getElementType() { - return getResType(); -} +Type AddressSpaceOp::getElementType() { return getResType(); } //===----------------------------------------------------------------------===// // RegisterOp @@ -426,9 +424,7 @@ unsigned RegisterOp::getMaxIndexWidth() { return llvm::Log2_64_Ceil(getSize()); } unsigned RegisterOp::getMinIndexWidth() { return 0; } -Type RegisterOp::getElementType() { - return getRegType(); -} +Type RegisterOp::getElementType() { return getRegType(); } LogicalResult RegisterOp::verify() { // Regfield checks @@ -706,10 +702,14 @@ static LogicalResult checkAccess(AccessOpTy op, Type requiredType) { if (auto info = op.getMemInfo()) { Type expectedType; if (auto intType = dyn_cast(info->elementType)) { - expectedType = IntegerType::get(op.getContext(), intType.getWidth() * op.getAccessWidth(), intType.getSignedness()); - } else if (auto structType = dyn_cast(info->elementType)) { + expectedType = IntegerType::get(op.getContext(), + intType.getWidth() * op.getAccessWidth(), + intType.getSignedness()); + } else if (auto structType = + dyn_cast(info->elementType)) { // TODO: Are accesses with access width > 1 supported by CoreDSL? - assert(op.getAccessWidth() == 1 && "Access with may only be 1 for struct types"); + assert(op.getAccessWidth() == 1 && + "Access with may only be 1 for struct types"); expectedType = structType; } else { llvm_unreachable("Unexpected type"); From 4562b0e50e70fb1a16c7a5d5b76049acff469145 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 17 Aug 2026 15:48:43 +0200 Subject: [PATCH 27/45] Removed unused hash maps --- .../CoreDSLExplodeStructRegisters.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 8605d54..1a5ea86 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -172,8 +172,6 @@ struct CoreDSLExplodeStructRegisters coredsl::ISAXOp isax = getOperation(); auto &ctx = getContext(); RewritePatternSet patterns{&ctx}; - llvm::StringMap nameToRegMap; - llvm::StringMap nameToTypeMap; patterns.insert(&ctx); ConversionTarget target{ctx}; target.addLegalDialect(); From 9ae0103782f9f548c23041edf0dbc7280d3b7bbe Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 17 Aug 2026 15:56:08 +0200 Subject: [PATCH 28/45] Added a map to store the types of the removed registers (needed for ranged struct access) --- .../CoreDSLExplodeStructRegisters.cpp | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 1a5ea86..f472091 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -42,8 +42,10 @@ void explodeRegs(StringRef regName, hw::StructType type, } struct StructExploderPattern : public OpConversionPattern { - StructExploderPattern(MLIRContext *ctx) - : OpConversionPattern(ctx) {} + llvm::StringMap &structTypes; + + StructExploderPattern(MLIRContext *ctx, llvm::StringMap &structTypes) + : OpConversionPattern(ctx), structTypes{structTypes} {} LogicalResult matchAndRewrite(coredsl::RegisterOp op, OpAdaptor, @@ -66,6 +68,7 @@ struct StructExploderPattern : public OpConversionPattern { op.getAccessMode()); }, [](hw::StructType, StringAttr) {}, [](hw::StructType, StringAttr) {}); + structTypes.insert(std::make_pair(op.getSymName(), structType)); rewriter.eraseOp(op); return LogicalResult::success(); } @@ -74,17 +77,21 @@ struct StructExploderPattern : public OpConversionPattern { }; struct StructRewriteSetOps : public OpConversionPattern { - StructRewriteSetOps(MLIRContext *ctx) - : OpConversionPattern(ctx) {} + const llvm::StringMap &structTypes; + + StructRewriteSetOps(MLIRContext *ctx, llvm::StringMap &structTypes) + : OpConversionPattern(ctx), structTypes{structTypes} {} LogicalResult matchAndRewrite(coredsl::SetOp op, OpAdaptor, ConversionPatternRewriter &rewriter) const override { - auto value = op.getValue(); auto base = op.getBase(); auto from = op.getFromAttr(); auto to = op.getToAttr(); - if (auto structType = llvm::dyn_cast(value.getType())) { + // Check if the symbol is one of the removed ones + auto found = structTypes.find(op.getSym()); + if (found != structTypes.end()) { + auto structType = found->second; StringRef symbolName = op.getSym(); auto loc = op.getLoc(); SmallVector opStack{op.getValue().getDefiningOp()}; @@ -116,14 +123,19 @@ struct StructRewriteSetOps : public OpConversionPattern { }; struct StructRewriteGetOps : public OpConversionPattern { - StructRewriteGetOps(MLIRContext *ctx) - : OpConversionPattern(ctx) {} + const llvm::StringMap &structTypes; + + StructRewriteGetOps(MLIRContext *ctx, llvm::StringMap &structTypes) + : OpConversionPattern(ctx), structTypes{structTypes} {} LogicalResult matchAndRewrite(coredsl::GetOp op, OpAdaptor, ConversionPatternRewriter &rewriter) const override { auto type = op.getResult().getType(); - if (auto structType = llvm::dyn_cast(type)) { + // Check if sym is one of the exploded structs + auto found = structTypes.find(op.getSym()); + if (found != structTypes.end()) { + auto structType = found->second; StringRef symbolName = op.getSym(); auto base = op.getBase(); @@ -172,7 +184,8 @@ struct CoreDSLExplodeStructRegisters coredsl::ISAXOp isax = getOperation(); auto &ctx = getContext(); RewritePatternSet patterns{&ctx}; - patterns.insert(&ctx); + llvm::StringMap nameToTypeMap; + patterns.insert(&ctx, nameToTypeMap); ConversionTarget target{ctx}; target.addLegalDialect(); target.addDynamicallyLegalOp( @@ -185,7 +198,7 @@ struct CoreDSLExplodeStructRegisters [](coredsl::GetOp op) { return op.getResult().getType().isInteger(); }); target.addDynamicallyLegalOp( [](coredsl::SetOp op) { return op.getValue().getType().isInteger(); }); - patterns.insert(&ctx); + patterns.insert(&ctx, nameToTypeMap); if (failed(applyPartialConversion(isax, target, std::move(patterns)))) { return signalPassFailure(); From a38bda33ca26092f47248c6a47c2bbcf998104f6 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 18 Aug 2026 15:12:19 +0200 Subject: [PATCH 29/45] Support ranged access for structs --- lib/Dialect/CoreDSL/CoreDSLOps.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/Dialect/CoreDSL/CoreDSLOps.cpp b/lib/Dialect/CoreDSL/CoreDSLOps.cpp index fd147af..902e5ee 100644 --- a/lib/Dialect/CoreDSL/CoreDSLOps.cpp +++ b/lib/Dialect/CoreDSL/CoreDSLOps.cpp @@ -707,10 +707,15 @@ static LogicalResult checkAccess(AccessOpTy op, Type requiredType) { intType.getSignedness()); } else if (auto structType = dyn_cast(info->elementType)) { - // TODO: Are accesses with access width > 1 supported by CoreDSL? - assert(op.getAccessWidth() == 1 && - "Access with may only be 1 for struct types"); - expectedType = structType; + if (op.getAccessWidth() == 1) { + expectedType = structType; + } else { + // The structs get converted to integers with ranged accesses + expectedType = IntegerType::get(op.getContext(), + circt::hw::getBitWidth(structType) * + op.getAccessWidth(), + IntegerType::Unsigned); + } } else { llvm_unreachable("Unexpected type"); } From ce3ed2c6310e07226f92a26dcbc104b128ac4de4 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 18 Aug 2026 15:14:12 +0200 Subject: [PATCH 30/45] Implemented ranged access handling for get --- .../CoreDSLExplodeStructRegisters.cpp | 171 +++++++++++++----- 1 file changed, 124 insertions(+), 47 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index f472091..e1f46a5 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -2,8 +2,10 @@ #include "shortnail/Conversion/Passes.h" #include "shortnail/Dialect/CoreDSL/CoreDSLOps.h" +#include "circt/Dialect/Comb/CombOps.h" #include "circt/Dialect/HW/HWOps.h" #include "circt/Dialect/HW/HWTypes.h" +#include "circt/Dialect/HWArith/HWArithOps.h" namespace mlir { namespace shortnail { @@ -42,10 +44,15 @@ void explodeRegs(StringRef regName, hw::StructType type, } struct StructExploderPattern : public OpConversionPattern { - llvm::StringMap &structTypes; + llvm::StringMap &symNameToType; + llvm::StringMap &symNameToMaxIndexWidth; - StructExploderPattern(MLIRContext *ctx, llvm::StringMap &structTypes) - : OpConversionPattern(ctx), structTypes{structTypes} {} + StructExploderPattern(MLIRContext *ctx, + llvm::StringMap &structTypes, + llvm::StringMap &symNameToMaxIndexWidth) + : OpConversionPattern(ctx), + symNameToType{structTypes}, + symNameToMaxIndexWidth{symNameToMaxIndexWidth} {} LogicalResult matchAndRewrite(coredsl::RegisterOp op, OpAdaptor, @@ -68,7 +75,10 @@ struct StructExploderPattern : public OpConversionPattern { op.getAccessMode()); }, [](hw::StructType, StringAttr) {}, [](hw::StructType, StringAttr) {}); - structTypes.insert(std::make_pair(op.getSymName(), structType)); + symNameToType.insert(std::make_pair(op.getSymName(), structType)); + symNameToMaxIndexWidth.insert( + std::make_pair(op.getSymName(), op.getMaxIndexWidth())); + op.getMaxIndexWidth(); rewriter.eraseOp(op); return LogicalResult::success(); } @@ -77,10 +87,14 @@ struct StructExploderPattern : public OpConversionPattern { }; struct StructRewriteSetOps : public OpConversionPattern { - const llvm::StringMap &structTypes; + const llvm::StringMap &symNameToType; + const llvm::StringMap &symNameToMaxIndexWidth; - StructRewriteSetOps(MLIRContext *ctx, llvm::StringMap &structTypes) - : OpConversionPattern(ctx), structTypes{structTypes} {} + StructRewriteSetOps(MLIRContext *ctx, + llvm::StringMap &structTypes, + llvm::StringMap &symNameToMaxIndexWidth) + : OpConversionPattern(ctx), symNameToType{structTypes}, + symNameToMaxIndexWidth{symNameToMaxIndexWidth} {} LogicalResult matchAndRewrite(coredsl::SetOp op, OpAdaptor, @@ -89,8 +103,8 @@ struct StructRewriteSetOps : public OpConversionPattern { auto from = op.getFromAttr(); auto to = op.getToAttr(); // Check if the symbol is one of the removed ones - auto found = structTypes.find(op.getSym()); - if (found != structTypes.end()) { + auto found = symNameToType.find(op.getSym()); + if (found != symNameToType.end()) { auto structType = found->second; StringRef symbolName = op.getSym(); auto loc = op.getLoc(); @@ -123,18 +137,23 @@ struct StructRewriteSetOps : public OpConversionPattern { }; struct StructRewriteGetOps : public OpConversionPattern { - const llvm::StringMap &structTypes; + const llvm::StringMap &symNameToType; + const llvm::StringMap &symNameToMaxIndexWidth; - StructRewriteGetOps(MLIRContext *ctx, llvm::StringMap &structTypes) - : OpConversionPattern(ctx), structTypes{structTypes} {} + StructRewriteGetOps(MLIRContext *ctx, + llvm::StringMap &structTypes, + llvm::StringMap &symNameToMaxIndexWidth) + : OpConversionPattern(ctx), symNameToType{structTypes}, + symNameToMaxIndexWidth{symNameToMaxIndexWidth} {} LogicalResult matchAndRewrite(coredsl::GetOp op, OpAdaptor, ConversionPatternRewriter &rewriter) const override { + MLIRContext *ctx = getContext(); auto type = op.getResult().getType(); // Check if sym is one of the exploded structs - auto found = structTypes.find(op.getSym()); - if (found != structTypes.end()) { + auto found = symNameToType.find(op.getSym()); + if (found != symNameToType.end()) { auto structType = found->second; StringRef symbolName = op.getSym(); @@ -142,33 +161,83 @@ struct StructRewriteGetOps : public OpConversionPattern { auto from = op.getFromAttr(); auto to = op.getToAttr(); auto loc = op.getLoc(); - SmallVector structMembers; - SmallVector structBeginIndices = {0}; - explodeRegs( - symbolName, structType, rewriter, - [&rewriter, &loc, &structMembers, &base, &from, - &to](StringRef newRegName, StringAttr fieldName, IntegerType type) { - auto gotValue = coredsl::GetOp::create(rewriter, loc, type, base, - from, to, newRegName); - structMembers.push_back(gotValue.getResult()); - }, - [&structBeginIndices, &structMembers](hw::StructType, StringAttr) { - structBeginIndices.push_back(structMembers.size()); - }, - [&rewriter, &loc, &structBeginIndices, - &structMembers](hw::StructType type, StringAttr fieldName) { - const size_t structBeginIdx = structBeginIndices.back(); - auto currStructMembers = ArrayRef( - structMembers.begin() + structBeginIdx, structMembers.end()); - auto structVal = hw::StructCreateOp::create(rewriter, loc, type, - currStructMembers); - structMembers.resize(structBeginIdx); - structBeginIndices.pop_back(); - structMembers.push_back(structVal.getResult()); - }); - auto finalStruct = - hw::StructCreateOp::create(rewriter, loc, type, structMembers); - rewriter.replaceOp(op, finalStruct.getResult()); + Value replacement = nullptr; + if (to != nullptr) { + assert(from); + SmallVector toConcatenate; + const unsigned maxIndexWidth = + symNameToMaxIndexWidth.find(op.getSym())->second; + for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { + APInt val{64, (uint64_t)i, true}; + val = val.trunc(std::max(val.getActiveBits(), 1u)); + auto offsetType = + IntegerType::get(ctx, val.getBitWidth(), IntegerType::Signed); + auto offset = hwarith::ConstantOp::create( + rewriter, loc, offsetType, IntegerAttr::get(offsetType, val)); + // result needs to be unsigned and respect access size + auto addRes = hwarith::AddOp::create(rewriter, loc, {base, offset}); + auto idxType = IntegerType::get(ctx, std::min(addRes.getType().getWidth(), maxIndexWidth), IntegerType::Unsigned); + auto newBase = hwarith::CastOp::create( + rewriter, loc, idxType, addRes); + // TODO: are the values in the right order? + explodeRegs( + symbolName, structType, rewriter, + [&rewriter, &loc, &newBase, &toConcatenate, ctx](StringRef newRegName, + StringAttr fieldName, + IntegerType type) { + auto gotValue = coredsl::GetOp::create( + rewriter, loc, type, newBase, nullptr, nullptr, newRegName); + auto gotType = cast(gotValue.getType()); + Operation* result = gotValue; + if (gotType.getSignedness() != IntegerType::Signless) { + auto signlessType = IntegerType::get(ctx, gotType.getWidth(), IntegerType::Signless); + result = hwarith::CastOp::create(rewriter, loc, signlessType, gotValue); + } + toConcatenate.push_back(result->getResult(0)); + }, + [](hw::StructType, StringAttr) {}, + [](hw::StructType, StringAttr) {}); + } + // TODO: remove duplicate return + auto result = comb::ConcatOp::create(rewriter, loc, toConcatenate); + IntegerType resultSignlessType = cast(result.getType()); + auto resultCast = hwarith::CastOp::create( + rewriter, loc, + IntegerType::get(ctx, resultSignlessType.getWidth(), + IntegerType::Unsigned), + result); + replacement = resultCast.getResult(); + } else { + SmallVector structOps; + SmallVector structMembers; + SmallVector structBeginIndices = {0}; + explodeRegs( + symbolName, structType, rewriter, + [&rewriter, &loc, &structMembers, &base, &from, + &to](StringRef newRegName, StringAttr fieldName, IntegerType type) { + auto gotValue = coredsl::GetOp::create(rewriter, loc, type, base, + from, to, newRegName); + structMembers.push_back(gotValue.getResult()); + }, + [&structBeginIndices, &structMembers](hw::StructType, StringAttr) { + structBeginIndices.push_back(structMembers.size()); + }, + [&rewriter, &loc, &structBeginIndices, + &structMembers](hw::StructType type, StringAttr fieldName) { + const size_t structBeginIdx = structBeginIndices.back(); + auto currStructMembers = ArrayRef( + structMembers.begin() + structBeginIdx, structMembers.end()); + auto structVal = hw::StructCreateOp::create(rewriter, loc, type, + currStructMembers); + structMembers.resize(structBeginIdx); + structBeginIndices.pop_back(); + structMembers.push_back(structVal.getResult()); + }); + auto finalStruct = + hw::StructCreateOp::create(rewriter, loc, type, structMembers); + replacement = finalStruct.getResult(); + } + rewriter.replaceOp(op, replacement); return LogicalResult::success(); } return LogicalResult::failure(); @@ -184,10 +253,13 @@ struct CoreDSLExplodeStructRegisters coredsl::ISAXOp isax = getOperation(); auto &ctx = getContext(); RewritePatternSet patterns{&ctx}; - llvm::StringMap nameToTypeMap; - patterns.insert(&ctx, nameToTypeMap); + llvm::StringMap symToTypeMap; + llvm::StringMap symToMaxIndexWidthMap; + patterns.insert(&ctx, symToTypeMap, + symToMaxIndexWidthMap); ConversionTarget target{ctx}; - target.addLegalDialect(); + target.addLegalDialect(); target.addDynamicallyLegalOp( [](coredsl::RegisterOp op) { return op.getElementType().isInteger(); }); if (failed(applyPartialConversion(isax, target, std::move(patterns)))) { @@ -195,10 +267,15 @@ struct CoreDSLExplodeStructRegisters } patterns.clear(); target.addDynamicallyLegalOp( - [](coredsl::GetOp op) { return op.getResult().getType().isInteger(); }); + [&symToTypeMap](coredsl::GetOp op) { + return symToTypeMap.find(op.getSym()) == symToTypeMap.end(); + }); target.addDynamicallyLegalOp( - [](coredsl::SetOp op) { return op.getValue().getType().isInteger(); }); - patterns.insert(&ctx, nameToTypeMap); + [&symToTypeMap](coredsl::SetOp op) { + return symToTypeMap.find(op.getSym()) == symToTypeMap.end(); + }); + patterns.insert( + &ctx, symToTypeMap, symToMaxIndexWidthMap); if (failed(applyPartialConversion(isax, target, std::move(patterns)))) { return signalPassFailure(); From c817d5fae6173e4789d43e71ff5be585d3561bf5 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 24 Aug 2026 10:52:14 +0200 Subject: [PATCH 31/45] Made explodeRegs modify an std::string inplace instead of creating a new one in each function call, and formatting --- .../CoreDSLExplodeStructRegisters.cpp | 70 ++++++++++++------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index e1f46a5..706b1e0 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -20,29 +20,45 @@ using namespace circt; namespace { +// Traverses a struct typed register, calling callbacks during traversal +// The callbacks are called with a string that consists of the register name, +// concatenated with the member names, so we can either explode the struct, +// or reference the already exploded registers template -void explodeRegs(StringRef regName, hw::StructType type, - ConversionPatternRewriter &rewriter, +void explodeRegs(std::string ®Name, hw::StructType type, ScalarValueAction scalarValueAction, StructMemberEntryAction structMemberEntryAction, StructMemberExitAction structMemberExitAction) { + const size_t regNameSize = regName.size(); for (hw::StructType::FieldInfo fieldInfo : type.getElements()) { - auto newRegName = std::string(regName); - newRegName += "_"; - newRegName += fieldInfo.name.getValue(); + regName += "_"; + regName += fieldInfo.name.getValue(); if (auto structType = llvm::dyn_cast(fieldInfo.type)) { structMemberEntryAction(structType, fieldInfo.name); - explodeRegs(newRegName, structType, rewriter, scalarValueAction, + explodeRegs(regName, structType, scalarValueAction, structMemberEntryAction, structMemberExitAction); structMemberExitAction(structType, fieldInfo.name); } else { - scalarValueAction(newRegName, fieldInfo.name, + scalarValueAction(regName, fieldInfo.name, llvm::cast(fieldInfo.type)); } + // Reset the string for the next iteration + regName.resize(regNameSize); } } +template +void explodeRegs(StringRef regName, hw::StructType type, + ScalarValueAction scalarValueAction, + StructMemberEntryAction structMemberEntryAction, + StructMemberExitAction structMemberExitAction) { + auto nameString = std::string(regName); + return explodeRegs(nameString, type, scalarValueAction, + structMemberEntryAction, structMemberExitAction); +} + struct StructExploderPattern : public OpConversionPattern { llvm::StringMap &symNameToType; llvm::StringMap &symNameToMaxIndexWidth; @@ -63,7 +79,7 @@ struct StructExploderPattern : public OpConversionPattern { rewriter.setInsertionPointAfter(op); Location loc = op.getLoc(); explodeRegs( - name, structType, rewriter, + name, structType, [&rewriter, &loc, &op, &numElements](StringRef newRegName, StringAttr fieldName, IntegerType fieldType) { @@ -103,14 +119,14 @@ struct StructRewriteSetOps : public OpConversionPattern { auto from = op.getFromAttr(); auto to = op.getToAttr(); // Check if the symbol is one of the removed ones - auto found = symNameToType.find(op.getSym()); + StringRef symbolName = op.getSym(); + auto found = symNameToType.find(symbolName); if (found != symNameToType.end()) { auto structType = found->second; - StringRef symbolName = op.getSym(); auto loc = op.getLoc(); SmallVector opStack{op.getValue().getDefiningOp()}; explodeRegs( - symbolName, structType, rewriter, + symbolName, structType, [&rewriter, &opStack, &loc, &base, &from, &to](StringRef newRegName, StringAttr fieldName, IntegerType type) { auto writtenValue = opStack.back(); @@ -166,7 +182,7 @@ struct StructRewriteGetOps : public OpConversionPattern { assert(from); SmallVector toConcatenate; const unsigned maxIndexWidth = - symNameToMaxIndexWidth.find(op.getSym())->second; + symNameToMaxIndexWidth.find(symbolName)->second; for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { APInt val{64, (uint64_t)i, true}; val = val.trunc(std::max(val.getActiveBits(), 1u)); @@ -176,22 +192,26 @@ struct StructRewriteGetOps : public OpConversionPattern { rewriter, loc, offsetType, IntegerAttr::get(offsetType, val)); // result needs to be unsigned and respect access size auto addRes = hwarith::AddOp::create(rewriter, loc, {base, offset}); - auto idxType = IntegerType::get(ctx, std::min(addRes.getType().getWidth(), maxIndexWidth), IntegerType::Unsigned); - auto newBase = hwarith::CastOp::create( - rewriter, loc, idxType, addRes); + auto idxType = IntegerType::get( + ctx, std::min(addRes.getType().getWidth(), maxIndexWidth), + IntegerType::Unsigned); + auto newBase = + hwarith::CastOp::create(rewriter, loc, idxType, addRes); // TODO: are the values in the right order? explodeRegs( - symbolName, structType, rewriter, - [&rewriter, &loc, &newBase, &toConcatenate, ctx](StringRef newRegName, - StringAttr fieldName, - IntegerType type) { + symbolName, structType, + [&rewriter, &loc, &newBase, &toConcatenate, + ctx](StringRef newRegName, StringAttr fieldName, + IntegerType type) { auto gotValue = coredsl::GetOp::create( rewriter, loc, type, newBase, nullptr, nullptr, newRegName); auto gotType = cast(gotValue.getType()); - Operation* result = gotValue; + Operation *result = gotValue; if (gotType.getSignedness() != IntegerType::Signless) { - auto signlessType = IntegerType::get(ctx, gotType.getWidth(), IntegerType::Signless); - result = hwarith::CastOp::create(rewriter, loc, signlessType, gotValue); + auto signlessType = IntegerType::get(ctx, gotType.getWidth(), + IntegerType::Signless); + result = hwarith::CastOp::create(rewriter, loc, signlessType, + gotValue); } toConcatenate.push_back(result->getResult(0)); }, @@ -212,9 +232,9 @@ struct StructRewriteGetOps : public OpConversionPattern { SmallVector structMembers; SmallVector structBeginIndices = {0}; explodeRegs( - symbolName, structType, rewriter, - [&rewriter, &loc, &structMembers, &base, &from, - &to](StringRef newRegName, StringAttr fieldName, IntegerType type) { + symbolName, structType, + [&rewriter, &loc, &structMembers, &base, &from, &to]( + StringRef newRegName, StringAttr fieldName, IntegerType type) { auto gotValue = coredsl::GetOp::create(rewriter, loc, type, base, from, to, newRegName); structMembers.push_back(gotValue.getResult()); From 9ebb26034f1bfa18345ebd814d86f7ae73610e68 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 24 Aug 2026 16:01:58 +0200 Subject: [PATCH 32/45] Implemented coredsl.set for ranged access (still needs to be tested) --- .../CoreDSLExplodeStructRegisters.cpp | 95 +++++++++++++------ 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 706b1e0..caaf031 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -48,12 +48,14 @@ void explodeRegs(std::string ®Name, hw::StructType type, } } -template +static constexpr auto emptyStructMemberEntryExitAction = [](hw::StructType, StringAttr){}; + +template void explodeRegs(StringRef regName, hw::StructType type, ScalarValueAction scalarValueAction, - StructMemberEntryAction structMemberEntryAction, - StructMemberExitAction structMemberExitAction) { + StructMemberEntryAction structMemberEntryAction = emptyStructMemberEntryExitAction, + StructMemberExitAction structMemberExitAction = emptyStructMemberEntryExitAction) { auto nameString = std::string(regName); return explodeRegs(nameString, type, scalarValueAction, structMemberEntryAction, structMemberExitAction); @@ -115,36 +117,72 @@ struct StructRewriteSetOps : public OpConversionPattern { LogicalResult matchAndRewrite(coredsl::SetOp op, OpAdaptor, ConversionPatternRewriter &rewriter) const override { + auto ctx = getContext(); auto base = op.getBase(); auto from = op.getFromAttr(); auto to = op.getToAttr(); + auto loc = op.getLoc(); // Check if the symbol is one of the removed ones StringRef symbolName = op.getSym(); auto found = symNameToType.find(symbolName); if (found != symNameToType.end()) { auto structType = found->second; - auto loc = op.getLoc(); - SmallVector opStack{op.getValue().getDefiningOp()}; - explodeRegs( - symbolName, structType, - [&rewriter, &opStack, &loc, &base, &from, - &to](StringRef newRegName, StringAttr fieldName, IntegerType type) { - auto writtenValue = opStack.back(); - auto extractOp = hw::StructExtractOp::create( - rewriter, loc, writtenValue->getResult(0), fieldName); - coredsl::SetOp::create(rewriter, loc, base, from, to, newRegName, - extractOp->getResult(0)); - }, - [&rewriter, &opStack, &loc](hw::StructType type, - StringAttr fieldName) { - auto toExtractFrom = opStack.back(); - Value structVal = toExtractFrom->getResult(0); - assert(llvm::isa(structVal.getType())); - auto extractOp = hw::StructExtractOp::create( - rewriter, loc, toExtractFrom->getResult(0), fieldName); - opStack.push_back(extractOp); - }, - [&opStack](hw::StructType, StringAttr) { opStack.pop_back(); }); + if (to != nullptr) { + // Handle ranged access + auto value = op.getValue(); + auto idxType = IndexType::get(ctx); + size_t currBitPos = 0; + for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { + const IntegerAttr idxAttr = i == 0 ? IntegerAttr::get(IntegerType::get(ctx, 1, IntegerType::Unsigned), 0) : IntegerAttr::get(ctx, APSInt::get(i)); + assert(idxAttr.getType().getIntOrFloatBitWidth()); + // TODO: Type + auto offsetConstant = hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); + // TODO: type is probably wrong + auto offsetIdx = hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); + const unsigned maxIndexWidth = symNameToMaxIndexWidth.find(symbolName)->second; + auto regIdxType = IntegerType::get(ctx, std::min(offsetIdx.getType().getWidth(), maxIndexWidth), IntegerType::Unsigned); + auto idxVal = hwarith::CastOp::create(rewriter, loc, regIdxType, offsetIdx); + explodeRegs( + symbolName, structType, + [&rewriter, &currBitPos, &loc, &value, &idxVal, idxType, ctx](StringRef newRegName, StringAttr fieldName, IntegerType type) { + const size_t bitsBegin = currBitPos; + const size_t bitsEnd = currBitPos + type.getWidth() - 1; + const auto bitsBeginAttr = IntegerAttr::get(idxType, bitsBegin); + const auto bitsEndAttr = IntegerAttr::get(idxType, bitsEnd); + assert(!type.isSignless()); + IntegerType bitExtractResType = type.isSigned() ? IntegerType::get(ctx, type.getWidth(), IntegerType::Unsigned) : type; + auto extractedBits = coredsl::BitExtractOp::create(rewriter, loc, bitExtractResType, nullptr, bitsBeginAttr, bitsEndAttr, value); + Operation *valueToWrite = extractedBits; + if (bitExtractResType != type) { + valueToWrite = coredsl::CastOp::create(rewriter, loc, type, extractedBits); + } + coredsl::SetOp::create(rewriter, loc, idxVal, nullptr, nullptr, newRegName, valueToWrite->getResult(0)); + currBitPos += type.getWidth(); + }); + } + } else { + SmallVector opStack{op.getValue().getDefiningOp()}; + explodeRegs( + symbolName, structType, + [&rewriter, &opStack, &loc, &base, &from, + &to](StringRef newRegName, StringAttr fieldName, IntegerType type) { + auto writtenValue = opStack.back(); + auto extractOp = hw::StructExtractOp::create( + rewriter, loc, writtenValue->getResult(0), fieldName); + coredsl::SetOp::create(rewriter, loc, base, from, to, newRegName, + extractOp->getResult(0)); + }, + [&rewriter, &opStack, &loc](hw::StructType type, + StringAttr fieldName) { + auto toExtractFrom = opStack.back(); + Value structVal = toExtractFrom->getResult(0); + assert(llvm::isa(structVal.getType())); + auto extractOp = hw::StructExtractOp::create( + rewriter, loc, toExtractFrom->getResult(0), fieldName); + opStack.push_back(extractOp); + }, + [&opStack](hw::StructType, StringAttr) { opStack.pop_back(); }); + } rewriter.eraseOp(op); return LogicalResult::success(); } @@ -214,11 +252,8 @@ struct StructRewriteGetOps : public OpConversionPattern { gotValue); } toConcatenate.push_back(result->getResult(0)); - }, - [](hw::StructType, StringAttr) {}, - [](hw::StructType, StringAttr) {}); + }); } - // TODO: remove duplicate return auto result = comb::ConcatOp::create(rewriter, loc, toConcatenate); IntegerType resultSignlessType = cast(result.getType()); auto resultCast = hwarith::CastOp::create( From 3937606ad3681432809fef5fc14f4d78611fa485 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 24 Aug 2026 16:09:21 +0200 Subject: [PATCH 33/45] Added comment explaining what the ranged access operators do --- .../CoreDSLExplodeStructRegisters.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index caaf031..eb048a0 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -128,14 +128,14 @@ struct StructRewriteSetOps : public OpConversionPattern { if (found != symNameToType.end()) { auto structType = found->second; if (to != nullptr) { - // Handle ranged access + // Handle ranged access: Because the input value is an integer of size + // range-size * struct-size, we need to extract the relevant values + // manually and assign them to the right scalar register auto value = op.getValue(); auto idxType = IndexType::get(ctx); size_t currBitPos = 0; for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { const IntegerAttr idxAttr = i == 0 ? IntegerAttr::get(IntegerType::get(ctx, 1, IntegerType::Unsigned), 0) : IntegerAttr::get(ctx, APSInt::get(i)); - assert(idxAttr.getType().getIntOrFloatBitWidth()); - // TODO: Type auto offsetConstant = hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); // TODO: type is probably wrong auto offsetIdx = hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); @@ -217,6 +217,9 @@ struct StructRewriteGetOps : public OpConversionPattern { auto loc = op.getLoc(); Value replacement = nullptr; if (to != nullptr) { + // Handle ranged access: Because the return value is a scalar value in + // this case, read all scalar values from the exploded registers and + // concatenate them using comb.concat assert(from); SmallVector toConcatenate; const unsigned maxIndexWidth = From 6687afa802b0c34b50c09c9192f6c8555bd56c1b Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 24 Aug 2026 16:14:51 +0200 Subject: [PATCH 34/45] Formatting --- .../CoreDSLExplodeStructRegisters.cpp | 60 +++++++++++++------ 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index eb048a0..b9dd35d 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -48,14 +48,20 @@ void explodeRegs(std::string ®Name, hw::StructType type, } } -static constexpr auto emptyStructMemberEntryExitAction = [](hw::StructType, StringAttr){}; +static constexpr auto emptyStructMemberEntryExitAction = [](hw::StructType, + StringAttr) {}; -template +template void explodeRegs(StringRef regName, hw::StructType type, ScalarValueAction scalarValueAction, - StructMemberEntryAction structMemberEntryAction = emptyStructMemberEntryExitAction, - StructMemberExitAction structMemberExitAction = emptyStructMemberEntryExitAction) { + StructMemberEntryAction structMemberEntryAction = + emptyStructMemberEntryExitAction, + StructMemberExitAction structMemberExitAction = + emptyStructMemberEntryExitAction) { auto nameString = std::string(regName); return explodeRegs(nameString, type, scalarValueAction, structMemberEntryAction, structMemberExitAction); @@ -135,28 +141,46 @@ struct StructRewriteSetOps : public OpConversionPattern { auto idxType = IndexType::get(ctx); size_t currBitPos = 0; for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { - const IntegerAttr idxAttr = i == 0 ? IntegerAttr::get(IntegerType::get(ctx, 1, IntegerType::Unsigned), 0) : IntegerAttr::get(ctx, APSInt::get(i)); - auto offsetConstant = hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); + const IntegerAttr idxAttr = + i == 0 ? IntegerAttr::get( + IntegerType::get(ctx, 1, IntegerType::Unsigned), 0) + : IntegerAttr::get(ctx, APSInt::get(i)); + auto offsetConstant = hwarith::ConstantOp::create( + rewriter, loc, idxAttr.getType(), idxAttr); // TODO: type is probably wrong - auto offsetIdx = hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); - const unsigned maxIndexWidth = symNameToMaxIndexWidth.find(symbolName)->second; - auto regIdxType = IntegerType::get(ctx, std::min(offsetIdx.getType().getWidth(), maxIndexWidth), IntegerType::Unsigned); - auto idxVal = hwarith::CastOp::create(rewriter, loc, regIdxType, offsetIdx); + auto offsetIdx = + hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); + const unsigned maxIndexWidth = + symNameToMaxIndexWidth.find(symbolName)->second; + auto regIdxType = IntegerType::get( + ctx, std::min(offsetIdx.getType().getWidth(), maxIndexWidth), + IntegerType::Unsigned); + auto idxVal = + hwarith::CastOp::create(rewriter, loc, regIdxType, offsetIdx); explodeRegs( symbolName, structType, - [&rewriter, &currBitPos, &loc, &value, &idxVal, idxType, ctx](StringRef newRegName, StringAttr fieldName, IntegerType type) { + [&rewriter, &currBitPos, &loc, &value, &idxVal, idxType, + ctx](StringRef newRegName, StringAttr fieldName, + IntegerType type) { const size_t bitsBegin = currBitPos; const size_t bitsEnd = currBitPos + type.getWidth() - 1; const auto bitsBeginAttr = IntegerAttr::get(idxType, bitsBegin); const auto bitsEndAttr = IntegerAttr::get(idxType, bitsEnd); assert(!type.isSignless()); - IntegerType bitExtractResType = type.isSigned() ? IntegerType::get(ctx, type.getWidth(), IntegerType::Unsigned) : type; - auto extractedBits = coredsl::BitExtractOp::create(rewriter, loc, bitExtractResType, nullptr, bitsBeginAttr, bitsEndAttr, value); + IntegerType bitExtractResType = + type.isSigned() ? IntegerType::get(ctx, type.getWidth(), + IntegerType::Unsigned) + : type; + auto extractedBits = coredsl::BitExtractOp::create( + rewriter, loc, bitExtractResType, nullptr, bitsBeginAttr, + bitsEndAttr, value); Operation *valueToWrite = extractedBits; if (bitExtractResType != type) { - valueToWrite = coredsl::CastOp::create(rewriter, loc, type, extractedBits); + valueToWrite = coredsl::CastOp::create(rewriter, loc, type, + extractedBits); } - coredsl::SetOp::create(rewriter, loc, idxVal, nullptr, nullptr, newRegName, valueToWrite->getResult(0)); + coredsl::SetOp::create(rewriter, loc, idxVal, nullptr, nullptr, + newRegName, valueToWrite->getResult(0)); currBitPos += type.getWidth(); }); } @@ -164,8 +188,8 @@ struct StructRewriteSetOps : public OpConversionPattern { SmallVector opStack{op.getValue().getDefiningOp()}; explodeRegs( symbolName, structType, - [&rewriter, &opStack, &loc, &base, &from, - &to](StringRef newRegName, StringAttr fieldName, IntegerType type) { + [&rewriter, &opStack, &loc, &base, &from, &to]( + StringRef newRegName, StringAttr fieldName, IntegerType type) { auto writtenValue = opStack.back(); auto extractOp = hw::StructExtractOp::create( rewriter, loc, writtenValue->getResult(0), fieldName); From f3b2f7b369c436e5d65a16bcdd2a32932703dcb7 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 25 Aug 2026 11:53:46 +0200 Subject: [PATCH 35/45] Moved adding offset to index and truncating to maxIndexWidth into separate function, as it was needed by both Get and Set ops. (Also had different behaviour, so this unifies the behaviour for both) --- .../CoreDSLExplodeStructRegisters.cpp | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index b9dd35d..4a6660a 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -110,6 +110,21 @@ struct StructExploderPattern : public OpConversionPattern { } }; +static Value emitTruncatedOffset(ConversionPatternRewriter &rewriter, MLIRContext *ctx, Value base, int64_t offset, unsigned maxIndexWidth, Location loc) { + if (offset == 0) { + return base; + } + const auto idxAttr = IntegerAttr::get(ctx, APSInt::get(offset)); + auto offsetConstant = hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); + auto addRes = hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); + const unsigned neededWidth = std::min(addRes.getType().getWidth(), maxIndexWidth); + if (neededWidth == addRes.getType().getWidth()) { + return addRes; + } + auto idxType = IntegerType::get(ctx, neededWidth, IntegerType::Unsigned); + return hwarith::CastOp::create(rewriter, loc, idxType, addRes); +} + struct StructRewriteSetOps : public OpConversionPattern { const llvm::StringMap &symNameToType; const llvm::StringMap &symNameToMaxIndexWidth; @@ -140,23 +155,10 @@ struct StructRewriteSetOps : public OpConversionPattern { auto value = op.getValue(); auto idxType = IndexType::get(ctx); size_t currBitPos = 0; + const unsigned maxIndexWidth = + symNameToMaxIndexWidth.find(symbolName)->second; for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { - const IntegerAttr idxAttr = - i == 0 ? IntegerAttr::get( - IntegerType::get(ctx, 1, IntegerType::Unsigned), 0) - : IntegerAttr::get(ctx, APSInt::get(i)); - auto offsetConstant = hwarith::ConstantOp::create( - rewriter, loc, idxAttr.getType(), idxAttr); - // TODO: type is probably wrong - auto offsetIdx = - hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); - const unsigned maxIndexWidth = - symNameToMaxIndexWidth.find(symbolName)->second; - auto regIdxType = IntegerType::get( - ctx, std::min(offsetIdx.getType().getWidth(), maxIndexWidth), - IntegerType::Unsigned); - auto idxVal = - hwarith::CastOp::create(rewriter, loc, regIdxType, offsetIdx); + auto idxVal = emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); explodeRegs( symbolName, structType, [&rewriter, &currBitPos, &loc, &value, &idxVal, idxType, @@ -249,19 +251,7 @@ struct StructRewriteGetOps : public OpConversionPattern { const unsigned maxIndexWidth = symNameToMaxIndexWidth.find(symbolName)->second; for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { - APInt val{64, (uint64_t)i, true}; - val = val.trunc(std::max(val.getActiveBits(), 1u)); - auto offsetType = - IntegerType::get(ctx, val.getBitWidth(), IntegerType::Signed); - auto offset = hwarith::ConstantOp::create( - rewriter, loc, offsetType, IntegerAttr::get(offsetType, val)); - // result needs to be unsigned and respect access size - auto addRes = hwarith::AddOp::create(rewriter, loc, {base, offset}); - auto idxType = IntegerType::get( - ctx, std::min(addRes.getType().getWidth(), maxIndexWidth), - IntegerType::Unsigned); - auto newBase = - hwarith::CastOp::create(rewriter, loc, idxType, addRes); + auto newBase = emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); // TODO: are the values in the right order? explodeRegs( symbolName, structType, From 39131709ec40979585ae432dd2c071e0d2658e00 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 25 Aug 2026 11:54:53 +0200 Subject: [PATCH 36/45] Formatting --- .../CoreDSLExplodeStructRegisters.cpp | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 4a6660a..06088eb 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -110,19 +110,23 @@ struct StructExploderPattern : public OpConversionPattern { } }; -static Value emitTruncatedOffset(ConversionPatternRewriter &rewriter, MLIRContext *ctx, Value base, int64_t offset, unsigned maxIndexWidth, Location loc) { - if (offset == 0) { - return base; - } - const auto idxAttr = IntegerAttr::get(ctx, APSInt::get(offset)); - auto offsetConstant = hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); - auto addRes = hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); - const unsigned neededWidth = std::min(addRes.getType().getWidth(), maxIndexWidth); - if (neededWidth == addRes.getType().getWidth()) { - return addRes; - } - auto idxType = IntegerType::get(ctx, neededWidth, IntegerType::Unsigned); - return hwarith::CastOp::create(rewriter, loc, idxType, addRes); +static Value emitTruncatedOffset(ConversionPatternRewriter &rewriter, + MLIRContext *ctx, Value base, int64_t offset, + unsigned maxIndexWidth, Location loc) { + if (offset == 0) { + return base; + } + const auto idxAttr = IntegerAttr::get(ctx, APSInt::get(offset)); + auto offsetConstant = + hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); + auto addRes = hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); + const unsigned neededWidth = + std::min(addRes.getType().getWidth(), maxIndexWidth); + if (neededWidth == addRes.getType().getWidth()) { + return addRes; + } + auto idxType = IntegerType::get(ctx, neededWidth, IntegerType::Unsigned); + return hwarith::CastOp::create(rewriter, loc, idxType, addRes); } struct StructRewriteSetOps : public OpConversionPattern { @@ -158,7 +162,8 @@ struct StructRewriteSetOps : public OpConversionPattern { const unsigned maxIndexWidth = symNameToMaxIndexWidth.find(symbolName)->second; for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { - auto idxVal = emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); + auto idxVal = + emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); explodeRegs( symbolName, structType, [&rewriter, &currBitPos, &loc, &value, &idxVal, idxType, @@ -251,7 +256,8 @@ struct StructRewriteGetOps : public OpConversionPattern { const unsigned maxIndexWidth = symNameToMaxIndexWidth.find(symbolName)->second; for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { - auto newBase = emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); + auto newBase = + emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); // TODO: are the values in the right order? explodeRegs( symbolName, structType, From e3210ae119e7c0addda460b0899d171e0f4c52bd Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 25 Aug 2026 12:06:42 +0200 Subject: [PATCH 37/45] Added comment to emitTruncatedOffset --- .../CoreDSLExplodeStructRegisters.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 06088eb..9ef5938 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -110,6 +110,8 @@ struct StructExploderPattern : public OpConversionPattern { } }; +// Emits Add of base to offset, truncating to maxIndexWidth if the result type +// is larger static Value emitTruncatedOffset(ConversionPatternRewriter &rewriter, MLIRContext *ctx, Value base, int64_t offset, unsigned maxIndexWidth, Location loc) { From 13686378a07e65a0277c5124a8eb8c7500f75628 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 25 Aug 2026 12:18:09 +0200 Subject: [PATCH 38/45] Made emitTruncatedOffset properly handle a zero offset on an index that is larger than maxIndexWidth --- .../CoreDSLExplodeStructRegisters.cpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 9ef5938..ec1c7c6 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -115,20 +115,21 @@ struct StructExploderPattern : public OpConversionPattern { static Value emitTruncatedOffset(ConversionPatternRewriter &rewriter, MLIRContext *ctx, Value base, int64_t offset, unsigned maxIndexWidth, Location loc) { - if (offset == 0) { - return base; + Value offsetResult = base; + if (offset != 0) { + const auto idxAttr = IntegerAttr::get(ctx, APSInt::get(offset)); + auto offsetConstant = + hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); + offsetResult = + hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); } - const auto idxAttr = IntegerAttr::get(ctx, APSInt::get(offset)); - auto offsetConstant = - hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); - auto addRes = hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); const unsigned neededWidth = - std::min(addRes.getType().getWidth(), maxIndexWidth); - if (neededWidth == addRes.getType().getWidth()) { - return addRes; + std::min(offsetResult.getType().getIntOrFloatBitWidth(), maxIndexWidth); + if (neededWidth == offsetResult.getType().getIntOrFloatBitWidth()) { + return offsetResult; } auto idxType = IntegerType::get(ctx, neededWidth, IntegerType::Unsigned); - return hwarith::CastOp::create(rewriter, loc, idxType, addRes); + return hwarith::CastOp::create(rewriter, loc, idxType, offsetResult); } struct StructRewriteSetOps : public OpConversionPattern { From e687f5156b99d9da87d831167a85c0c4c9ca6384 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 25 Aug 2026 13:31:37 +0200 Subject: [PATCH 39/45] Changed emitTruncatedOffset to not add a cast when i == 0, as that case is impossible, because the op would be invalid if base was larger than maxIndexWidth --- .../CoreDSLExplodeStructRegisters.cpp | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index ec1c7c6..5ed9eb0 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -115,21 +115,22 @@ struct StructExploderPattern : public OpConversionPattern { static Value emitTruncatedOffset(ConversionPatternRewriter &rewriter, MLIRContext *ctx, Value base, int64_t offset, unsigned maxIndexWidth, Location loc) { - Value offsetResult = base; - if (offset != 0) { - const auto idxAttr = IntegerAttr::get(ctx, APSInt::get(offset)); - auto offsetConstant = - hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); - offsetResult = - hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); + if (offset == 0) { + // We don't need to insert a cast here, because if base is larger than + // maxIndexWidth, the original op was not valid in the first place + return base; } + const auto idxAttr = IntegerAttr::get(ctx, APSInt::get(offset)); + auto offsetConstant = + hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); + auto addRes = hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); const unsigned neededWidth = - std::min(offsetResult.getType().getIntOrFloatBitWidth(), maxIndexWidth); - if (neededWidth == offsetResult.getType().getIntOrFloatBitWidth()) { - return offsetResult; + std::min(addRes.getType().getWidth(), maxIndexWidth); + if (neededWidth == addRes.getType().getWidth()) { + return addRes; } auto idxType = IntegerType::get(ctx, neededWidth, IntegerType::Unsigned); - return hwarith::CastOp::create(rewriter, loc, idxType, offsetResult); + return hwarith::CastOp::create(rewriter, loc, idxType, addRes); } struct StructRewriteSetOps : public OpConversionPattern { From ba0d9f97342ea19240bd7832649ecf2aecb7edd6 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 25 Aug 2026 13:40:41 +0200 Subject: [PATCH 40/45] Added assertion that from < to for ranged struct accesses --- .../CoreDSLExplodeStructRegisters.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 5ed9eb0..969b50d 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -165,6 +165,7 @@ struct StructRewriteSetOps : public OpConversionPattern { size_t currBitPos = 0; const unsigned maxIndexWidth = symNameToMaxIndexWidth.find(symbolName)->second; + assert(from.getInt() <= to.getInt()); for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { auto idxVal = emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); @@ -259,6 +260,7 @@ struct StructRewriteGetOps : public OpConversionPattern { SmallVector toConcatenate; const unsigned maxIndexWidth = symNameToMaxIndexWidth.find(symbolName)->second; + assert(from.getInt() <= to.getInt()); for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { auto newBase = emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); From 6c6a34f2abed5fe33eba134d68ca508a83a415e5 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 25 Aug 2026 14:10:04 +0200 Subject: [PATCH 41/45] Corrected code that emits a constant with the exact needed size for the offset --- .../CoreDSLExplodeStructRegisters.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 969b50d..f6aa142 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -120,9 +120,12 @@ static Value emitTruncatedOffset(ConversionPatternRewriter &rewriter, // maxIndexWidth, the original op was not valid in the first place return base; } - const auto idxAttr = IntegerAttr::get(ctx, APSInt::get(offset)); - auto offsetConstant = - hwarith::ConstantOp::create(rewriter, loc, idxAttr.getType(), idxAttr); + const auto offsetType = + IntegerType::get(ctx, llvm::bit_width(static_cast(offset)) + 1, + IntegerType::Signed); + const auto offsetAttr = IntegerAttr::get(offsetType, offset); + auto offsetConstant = hwarith::ConstantOp::create( + rewriter, loc, offsetAttr.getType(), offsetAttr); auto addRes = hwarith::AddOp::create(rewriter, loc, {base, offsetConstant}); const unsigned neededWidth = std::min(addRes.getType().getWidth(), maxIndexWidth); From 387878472d9a25de9b4caec9c29eabb9444d6866 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 25 Aug 2026 14:10:28 +0200 Subject: [PATCH 42/45] Added test cases for ranged access with structs --- .../explode_struct_registers.mlir | 177 +++++++++++++++++- 1 file changed, 174 insertions(+), 3 deletions(-) diff --git a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir index 2c3d03c..a94ba14 100644 --- a/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir +++ b/test/Conversion/CoreDSLExplodeStructRegisters/explode_struct_registers.mlir @@ -7,6 +7,7 @@ coredsl.isax "StructRegisters" { coredsl.register local @SCALAR_REG1 : ui32 coredsl.register local @SCALAR_REG2 : ui32 coredsl.register local @STRUCT_REGS[32] : !hw.struct> + coredsl.register local @OTHER_STRUCT_REGS[16] : !hw.struct, notNested: si32>> coredsl.instruction @StructRegDirectStore {lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { %imm = coredsl.cast %TREENAIL_WAS_HERE_imm_11_0 : ui12 to ui12 @@ -65,6 +66,7 @@ coredsl.isax "StructRegisters" { coredsl.instruction @StructArrays{lil.enc_immediates = [[["%TREENAIL_WAS_HERE_imm_11_0", 11, 0, 0, "imm"]], [["%TREENAIL_WAS_HERE_rs1_4_0", 4, 0, 0, "rs1"]], [["%TREENAIL_WAS_HERE_rd_4_0", 4, 0, 0, "rd"]]]} (%TREENAIL_WAS_HERE_imm_11_0 : ui12, %TREENAIL_WAS_HERE_rs1_4_0 : ui5, "010", %TREENAIL_WAS_HERE_rd_4_0 : ui5, "0000011") { %rs1 = coredsl.cast %TREENAIL_WAS_HERE_rs1_4_0 : ui5 to ui5 + %rd = coredsl.cast %TREENAIL_WAS_HERE_rd_4_0 : ui5 to ui5 %21 = coredsl.get @NESTED_STRUCT_REG : !hw.struct> coredsl.set @STRUCT_REGS[2] = %21 : !hw.struct> %22 = hwarith.constant 10 : ui4 @@ -72,6 +74,12 @@ coredsl.isax "StructRegisters" { %24 = coredsl.cast %22 : ui4 to si32 %25 = hw.struct_inject %23["notNested"], %24 : !hw.struct> coredsl.set @STRUCT_REGS[%rs1 : ui5] = %25 : !hw.struct> + // Ranged access for structs: structs get converted to integer + %26 = coredsl.get @STRUCT_REGS[%rs1 : ui5, 0:4] : ui480 + coredsl.set @STRUCT_REGS[%rd : ui5, 0:4] = %26 : ui480 + // Nonzero offset + %27 = coredsl.get @OTHER_STRUCT_REGS[%22 : ui4, 5:7] : ui480 + coredsl.set @OTHER_STRUCT_REGS[%22 : ui4, 1:3] = %27 : ui480 coredsl.end } } @@ -91,6 +99,10 @@ coredsl.isax "StructRegisters" { // CHECK: coredsl.register local @STRUCT_REGS_notNested[32] : si32 // CHECK: coredsl.register local @STRUCT_REGS_vec_x[32] : ui32 // CHECK: coredsl.register local @STRUCT_REGS_vec_y[32] : ui32 +// CHECK: coredsl.register local @OTHER_STRUCT_REGS_aValue[16] : si64 +// CHECK: coredsl.register local @OTHER_STRUCT_REGS_aStruct_vec_x[16] : ui32 +// CHECK: coredsl.register local @OTHER_STRUCT_REGS_aStruct_vec_y[16] : ui32 +// CHECK: coredsl.register local @OTHER_STRUCT_REGS_aStruct_notNested[16] : si32 // CHECK: coredsl.instruction @StructRegDirectStore {lil.enc_immediates = {{\[\[}}["%[[VAL_0:.*]]", 11, 0, 0, "imm"]], {{\[\[}}"%[[VAL_1:.*]]", 4, 0, 0, "rs1"]], {{\[\[}}"%[[VAL_2:.*]]", 4, 0, 0, "rd"]]]}(%[[VAL_0]] : ui12, %[[VAL_1]] : ui5, "010", %[[VAL_2]] : ui5, "0000011"){ // CHECK: %[[CONSTANT_0:.*]] = hwarith.constant -1 : si32 // CHECK: %[[CONSTANT_1:.*]] = hwarith.constant 0 : ui1 @@ -145,8 +157,16 @@ coredsl.isax "StructRegisters" { // CHECK: coredsl.end // CHECK: } // CHECK: coredsl.instruction @StructArrays {lil.enc_immediates = {{\[\[}}["%[[VAL_6:.*]]", 11, 0, 0, "imm"]], {{\[\[}}"%[[VAL_7:.*]]", 4, 0, 0, "rs1"]], {{\[\[}}"%[[VAL_8:.*]]", 4, 0, 0, "rd"]]]}(%[[VAL_6]] : ui12, %[[VAL_7]] : ui5, "010", %[[VAL_8]] : ui5, "0000011"){ -// CHECK: %[[CONSTANT_5:.*]] = hwarith.constant 10 : ui4 +// CHECK: %[[CONSTANT_5:.*]] = hwarith.constant 7 : si4 +// CHECK: %[[CONSTANT_6:.*]] = hwarith.constant 6 : si4 +// CHECK: %[[CONSTANT_7:.*]] = hwarith.constant 5 : si4 +// CHECK: %[[CONSTANT_8:.*]] = hwarith.constant 4 : si4 +// CHECK: %[[CONSTANT_9:.*]] = hwarith.constant 3 : si3 +// CHECK: %[[CONSTANT_10:.*]] = hwarith.constant 2 : si3 +// CHECK: %[[CONSTANT_11:.*]] = hwarith.constant 1 : si2 +// CHECK: %[[CONSTANT_12:.*]] = hwarith.constant 10 : ui4 // CHECK: %[[CAST_5:.*]] = coredsl.cast %[[VAL_7]] : ui5 to ui5 +// CHECK: %[[CAST_6:.*]] = coredsl.cast %[[VAL_8]] : ui5 to ui5 // CHECK: %[[GET_18:.*]] = coredsl.get @NESTED_STRUCT_REG_notNested : si32 // CHECK: %[[GET_19:.*]] = coredsl.get @NESTED_STRUCT_REG_vec_x : ui32 // CHECK: %[[GET_20:.*]] = coredsl.get @NESTED_STRUCT_REG_vec_y : ui32 @@ -156,10 +176,161 @@ coredsl.isax "StructRegisters" { // CHECK: %[[GET_21:.*]] = coredsl.get @STRUCT_REGS_notNested{{\[}}%[[CAST_5]] : ui5] : si32 // CHECK: %[[GET_22:.*]] = coredsl.get @STRUCT_REGS_vec_x{{\[}}%[[CAST_5]] : ui5] : ui32 // CHECK: %[[GET_23:.*]] = coredsl.get @STRUCT_REGS_vec_y{{\[}}%[[CAST_5]] : ui5] : ui32 -// CHECK: %[[CAST_6:.*]] = coredsl.cast %[[CONSTANT_5]] : ui4 to si32 -// CHECK: coredsl.set @STRUCT_REGS_notNested{{\[}}%[[CAST_5]] : ui5] = %[[CAST_6]] : si32 +// CHECK: %[[CAST_7:.*]] = coredsl.cast %[[CONSTANT_12]] : ui4 to si32 +// CHECK: coredsl.set @STRUCT_REGS_notNested{{\[}}%[[CAST_5]] : ui5] = %[[CAST_7]] : si32 // CHECK: coredsl.set @STRUCT_REGS_vec_x{{\[}}%[[CAST_5]] : ui5] = %[[GET_22]] : ui32 // CHECK: coredsl.set @STRUCT_REGS_vec_y{{\[}}%[[CAST_5]] : ui5] = %[[GET_23]] : ui32 +// CHECK: %[[GET_24:.*]] = coredsl.get @STRUCT_REGS_notNested{{\[}}%[[CAST_5]] : ui5] : si32 +// CHECK: %[[CAST_8:.*]] = hwarith.cast %[[GET_24]] : (si32) -> i32 +// CHECK: %[[GET_25:.*]] = coredsl.get @STRUCT_REGS_vec_x{{\[}}%[[CAST_5]] : ui5] : ui32 +// CHECK: %[[CAST_9:.*]] = hwarith.cast %[[GET_25]] : (ui32) -> i32 +// CHECK: %[[GET_26:.*]] = coredsl.get @STRUCT_REGS_vec_y{{\[}}%[[CAST_5]] : ui5] : ui32 +// CHECK: %[[CAST_10:.*]] = hwarith.cast %[[GET_26]] : (ui32) -> i32 +// CHECK: %[[ADD_1:.*]] = hwarith.add %[[CAST_5]], %[[CONSTANT_11]] : (ui5, si2) -> si7 +// CHECK: %[[CAST_11:.*]] = hwarith.cast %[[ADD_1]] : (si7) -> ui5 +// CHECK: %[[GET_27:.*]] = coredsl.get @STRUCT_REGS_notNested{{\[}}%[[CAST_11]] : ui5] : si32 +// CHECK: %[[CAST_12:.*]] = hwarith.cast %[[GET_27]] : (si32) -> i32 +// CHECK: %[[GET_28:.*]] = coredsl.get @STRUCT_REGS_vec_x{{\[}}%[[CAST_11]] : ui5] : ui32 +// CHECK: %[[CAST_13:.*]] = hwarith.cast %[[GET_28]] : (ui32) -> i32 +// CHECK: %[[GET_29:.*]] = coredsl.get @STRUCT_REGS_vec_y{{\[}}%[[CAST_11]] : ui5] : ui32 +// CHECK: %[[CAST_14:.*]] = hwarith.cast %[[GET_29]] : (ui32) -> i32 +// CHECK: %[[ADD_2:.*]] = hwarith.add %[[CAST_5]], %[[CONSTANT_10]] : (ui5, si3) -> si7 +// CHECK: %[[CAST_15:.*]] = hwarith.cast %[[ADD_2]] : (si7) -> ui5 +// CHECK: %[[GET_30:.*]] = coredsl.get @STRUCT_REGS_notNested{{\[}}%[[CAST_15]] : ui5] : si32 +// CHECK: %[[CAST_16:.*]] = hwarith.cast %[[GET_30]] : (si32) -> i32 +// CHECK: %[[GET_31:.*]] = coredsl.get @STRUCT_REGS_vec_x{{\[}}%[[CAST_15]] : ui5] : ui32 +// CHECK: %[[CAST_17:.*]] = hwarith.cast %[[GET_31]] : (ui32) -> i32 +// CHECK: %[[GET_32:.*]] = coredsl.get @STRUCT_REGS_vec_y{{\[}}%[[CAST_15]] : ui5] : ui32 +// CHECK: %[[CAST_18:.*]] = hwarith.cast %[[GET_32]] : (ui32) -> i32 +// CHECK: %[[ADD_3:.*]] = hwarith.add %[[CAST_5]], %[[CONSTANT_9]] : (ui5, si3) -> si7 +// CHECK: %[[CAST_19:.*]] = hwarith.cast %[[ADD_3]] : (si7) -> ui5 +// CHECK: %[[GET_33:.*]] = coredsl.get @STRUCT_REGS_notNested{{\[}}%[[CAST_19]] : ui5] : si32 +// CHECK: %[[CAST_20:.*]] = hwarith.cast %[[GET_33]] : (si32) -> i32 +// CHECK: %[[GET_34:.*]] = coredsl.get @STRUCT_REGS_vec_x{{\[}}%[[CAST_19]] : ui5] : ui32 +// CHECK: %[[CAST_21:.*]] = hwarith.cast %[[GET_34]] : (ui32) -> i32 +// CHECK: %[[GET_35:.*]] = coredsl.get @STRUCT_REGS_vec_y{{\[}}%[[CAST_19]] : ui5] : ui32 +// CHECK: %[[CAST_22:.*]] = hwarith.cast %[[GET_35]] : (ui32) -> i32 +// CHECK: %[[ADD_4:.*]] = hwarith.add %[[CAST_5]], %[[CONSTANT_8]] : (ui5, si4) -> si7 +// CHECK: %[[CAST_23:.*]] = hwarith.cast %[[ADD_4]] : (si7) -> ui5 +// CHECK: %[[GET_36:.*]] = coredsl.get @STRUCT_REGS_notNested{{\[}}%[[CAST_23]] : ui5] : si32 +// CHECK: %[[CAST_24:.*]] = hwarith.cast %[[GET_36]] : (si32) -> i32 +// CHECK: %[[GET_37:.*]] = coredsl.get @STRUCT_REGS_vec_x{{\[}}%[[CAST_23]] : ui5] : ui32 +// CHECK: %[[CAST_25:.*]] = hwarith.cast %[[GET_37]] : (ui32) -> i32 +// CHECK: %[[GET_38:.*]] = coredsl.get @STRUCT_REGS_vec_y{{\[}}%[[CAST_23]] : ui5] : ui32 +// CHECK: %[[CAST_26:.*]] = hwarith.cast %[[GET_38]] : (ui32) -> i32 +// CHECK: %[[CONCAT_0:.*]] = comb.concat %[[CAST_8]], %[[CAST_9]], %[[CAST_10]], %[[CAST_12]], %[[CAST_13]], %[[CAST_14]], %[[CAST_16]], %[[CAST_17]], %[[CAST_18]], %[[CAST_20]], %[[CAST_21]], %[[CAST_22]], %[[CAST_24]], %[[CAST_25]], %[[CAST_26]] : i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 +// CHECK: %[[CAST_27:.*]] = hwarith.cast %[[CONCAT_0]] : (i480) -> ui480 +// CHECK: %[[BITEXTRACT_0:.*]] = coredsl.bitextract %[[CAST_27]][0:31] : (ui480) -> ui32 +// CHECK: %[[CAST_28:.*]] = coredsl.cast %[[BITEXTRACT_0]] : ui32 to si32 +// CHECK: coredsl.set @STRUCT_REGS_notNested{{\[}}%[[CAST_6]] : ui5] = %[[CAST_28]] : si32 +// CHECK: %[[BITEXTRACT_1:.*]] = coredsl.bitextract %[[CAST_27]][32:63] : (ui480) -> ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_x{{\[}}%[[CAST_6]] : ui5] = %[[BITEXTRACT_1]] : ui32 +// CHECK: %[[BITEXTRACT_2:.*]] = coredsl.bitextract %[[CAST_27]][64:95] : (ui480) -> ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_y{{\[}}%[[CAST_6]] : ui5] = %[[BITEXTRACT_2]] : ui32 +// CHECK: %[[ADD_5:.*]] = hwarith.add %[[CAST_6]], %[[CONSTANT_11]] : (ui5, si2) -> si7 +// CHECK: %[[CAST_29:.*]] = hwarith.cast %[[ADD_5]] : (si7) -> ui5 +// CHECK: %[[BITEXTRACT_3:.*]] = coredsl.bitextract %[[CAST_27]][96:127] : (ui480) -> ui32 +// CHECK: %[[CAST_30:.*]] = coredsl.cast %[[BITEXTRACT_3]] : ui32 to si32 +// CHECK: coredsl.set @STRUCT_REGS_notNested{{\[}}%[[CAST_29]] : ui5] = %[[CAST_30]] : si32 +// CHECK: %[[BITEXTRACT_4:.*]] = coredsl.bitextract %[[CAST_27]][128:159] : (ui480) -> ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_x{{\[}}%[[CAST_29]] : ui5] = %[[BITEXTRACT_4]] : ui32 +// CHECK: %[[BITEXTRACT_5:.*]] = coredsl.bitextract %[[CAST_27]][160:191] : (ui480) -> ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_y{{\[}}%[[CAST_29]] : ui5] = %[[BITEXTRACT_5]] : ui32 +// CHECK: %[[ADD_6:.*]] = hwarith.add %[[CAST_6]], %[[CONSTANT_10]] : (ui5, si3) -> si7 +// CHECK: %[[CAST_31:.*]] = hwarith.cast %[[ADD_6]] : (si7) -> ui5 +// CHECK: %[[BITEXTRACT_6:.*]] = coredsl.bitextract %[[CAST_27]][192:223] : (ui480) -> ui32 +// CHECK: %[[CAST_32:.*]] = coredsl.cast %[[BITEXTRACT_6]] : ui32 to si32 +// CHECK: coredsl.set @STRUCT_REGS_notNested{{\[}}%[[CAST_31]] : ui5] = %[[CAST_32]] : si32 +// CHECK: %[[BITEXTRACT_7:.*]] = coredsl.bitextract %[[CAST_27]][224:255] : (ui480) -> ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_x{{\[}}%[[CAST_31]] : ui5] = %[[BITEXTRACT_7]] : ui32 +// CHECK: %[[BITEXTRACT_8:.*]] = coredsl.bitextract %[[CAST_27]][256:287] : (ui480) -> ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_y{{\[}}%[[CAST_31]] : ui5] = %[[BITEXTRACT_8]] : ui32 +// CHECK: %[[ADD_7:.*]] = hwarith.add %[[CAST_6]], %[[CONSTANT_9]] : (ui5, si3) -> si7 +// CHECK: %[[CAST_33:.*]] = hwarith.cast %[[ADD_7]] : (si7) -> ui5 +// CHECK: %[[BITEXTRACT_9:.*]] = coredsl.bitextract %[[CAST_27]][288:319] : (ui480) -> ui32 +// CHECK: %[[CAST_34:.*]] = coredsl.cast %[[BITEXTRACT_9]] : ui32 to si32 +// CHECK: coredsl.set @STRUCT_REGS_notNested{{\[}}%[[CAST_33]] : ui5] = %[[CAST_34]] : si32 +// CHECK: %[[BITEXTRACT_10:.*]] = coredsl.bitextract %[[CAST_27]][320:351] : (ui480) -> ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_x{{\[}}%[[CAST_33]] : ui5] = %[[BITEXTRACT_10]] : ui32 +// CHECK: %[[BITEXTRACT_11:.*]] = coredsl.bitextract %[[CAST_27]][352:383] : (ui480) -> ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_y{{\[}}%[[CAST_33]] : ui5] = %[[BITEXTRACT_11]] : ui32 +// CHECK: %[[ADD_8:.*]] = hwarith.add %[[CAST_6]], %[[CONSTANT_8]] : (ui5, si4) -> si7 +// CHECK: %[[CAST_35:.*]] = hwarith.cast %[[ADD_8]] : (si7) -> ui5 +// CHECK: %[[BITEXTRACT_12:.*]] = coredsl.bitextract %[[CAST_27]][384:415] : (ui480) -> ui32 +// CHECK: %[[CAST_36:.*]] = coredsl.cast %[[BITEXTRACT_12]] : ui32 to si32 +// CHECK: coredsl.set @STRUCT_REGS_notNested{{\[}}%[[CAST_35]] : ui5] = %[[CAST_36]] : si32 +// CHECK: %[[BITEXTRACT_13:.*]] = coredsl.bitextract %[[CAST_27]][416:447] : (ui480) -> ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_x{{\[}}%[[CAST_35]] : ui5] = %[[BITEXTRACT_13]] : ui32 +// CHECK: %[[BITEXTRACT_14:.*]] = coredsl.bitextract %[[CAST_27]][448:479] : (ui480) -> ui32 +// CHECK: coredsl.set @STRUCT_REGS_vec_y{{\[}}%[[CAST_35]] : ui5] = %[[BITEXTRACT_14]] : ui32 +// CHECK: %[[ADD_9:.*]] = hwarith.add %[[CONSTANT_12]], %[[CONSTANT_7]] : (ui4, si4) -> si6 +// CHECK: %[[CAST_37:.*]] = hwarith.cast %[[ADD_9]] : (si6) -> ui4 +// CHECK: %[[GET_39:.*]] = coredsl.get @OTHER_STRUCT_REGS_aValue{{\[}}%[[CAST_37]] : ui4] : si64 +// CHECK: %[[CAST_38:.*]] = hwarith.cast %[[GET_39]] : (si64) -> i64 +// CHECK: %[[GET_40:.*]] = coredsl.get @OTHER_STRUCT_REGS_aStruct_vec_x{{\[}}%[[CAST_37]] : ui4] : ui32 +// CHECK: %[[CAST_39:.*]] = hwarith.cast %[[GET_40]] : (ui32) -> i32 +// CHECK: %[[GET_41:.*]] = coredsl.get @OTHER_STRUCT_REGS_aStruct_vec_y{{\[}}%[[CAST_37]] : ui4] : ui32 +// CHECK: %[[CAST_40:.*]] = hwarith.cast %[[GET_41]] : (ui32) -> i32 +// CHECK: %[[GET_42:.*]] = coredsl.get @OTHER_STRUCT_REGS_aStruct_notNested{{\[}}%[[CAST_37]] : ui4] : si32 +// CHECK: %[[CAST_41:.*]] = hwarith.cast %[[GET_42]] : (si32) -> i32 +// CHECK: %[[ADD_10:.*]] = hwarith.add %[[CONSTANT_12]], %[[CONSTANT_6]] : (ui4, si4) -> si6 +// CHECK: %[[CAST_42:.*]] = hwarith.cast %[[ADD_10]] : (si6) -> ui4 +// CHECK: %[[GET_43:.*]] = coredsl.get @OTHER_STRUCT_REGS_aValue{{\[}}%[[CAST_42]] : ui4] : si64 +// CHECK: %[[CAST_43:.*]] = hwarith.cast %[[GET_43]] : (si64) -> i64 +// CHECK: %[[GET_44:.*]] = coredsl.get @OTHER_STRUCT_REGS_aStruct_vec_x{{\[}}%[[CAST_42]] : ui4] : ui32 +// CHECK: %[[CAST_44:.*]] = hwarith.cast %[[GET_44]] : (ui32) -> i32 +// CHECK: %[[GET_45:.*]] = coredsl.get @OTHER_STRUCT_REGS_aStruct_vec_y{{\[}}%[[CAST_42]] : ui4] : ui32 +// CHECK: %[[CAST_45:.*]] = hwarith.cast %[[GET_45]] : (ui32) -> i32 +// CHECK: %[[GET_46:.*]] = coredsl.get @OTHER_STRUCT_REGS_aStruct_notNested{{\[}}%[[CAST_42]] : ui4] : si32 +// CHECK: %[[CAST_46:.*]] = hwarith.cast %[[GET_46]] : (si32) -> i32 +// CHECK: %[[ADD_11:.*]] = hwarith.add %[[CONSTANT_12]], %[[CONSTANT_5]] : (ui4, si4) -> si6 +// CHECK: %[[CAST_47:.*]] = hwarith.cast %[[ADD_11]] : (si6) -> ui4 +// CHECK: %[[GET_47:.*]] = coredsl.get @OTHER_STRUCT_REGS_aValue{{\[}}%[[CAST_47]] : ui4] : si64 +// CHECK: %[[CAST_48:.*]] = hwarith.cast %[[GET_47]] : (si64) -> i64 +// CHECK: %[[GET_48:.*]] = coredsl.get @OTHER_STRUCT_REGS_aStruct_vec_x{{\[}}%[[CAST_47]] : ui4] : ui32 +// CHECK: %[[CAST_49:.*]] = hwarith.cast %[[GET_48]] : (ui32) -> i32 +// CHECK: %[[GET_49:.*]] = coredsl.get @OTHER_STRUCT_REGS_aStruct_vec_y{{\[}}%[[CAST_47]] : ui4] : ui32 +// CHECK: %[[CAST_50:.*]] = hwarith.cast %[[GET_49]] : (ui32) -> i32 +// CHECK: %[[GET_50:.*]] = coredsl.get @OTHER_STRUCT_REGS_aStruct_notNested{{\[}}%[[CAST_47]] : ui4] : si32 +// CHECK: %[[CAST_51:.*]] = hwarith.cast %[[GET_50]] : (si32) -> i32 +// CHECK: %[[CONCAT_1:.*]] = comb.concat %[[CAST_38]], %[[CAST_39]], %[[CAST_40]], %[[CAST_41]], %[[CAST_43]], %[[CAST_44]], %[[CAST_45]], %[[CAST_46]], %[[CAST_48]], %[[CAST_49]], %[[CAST_50]], %[[CAST_51]] : i64, i32, i32, i32, i64, i32, i32, i32, i64, i32, i32, i32 +// CHECK: %[[CAST_52:.*]] = hwarith.cast %[[CONCAT_1]] : (i480) -> ui480 +// CHECK: %[[ADD_12:.*]] = hwarith.add %[[CONSTANT_12]], %[[CONSTANT_11]] : (ui4, si2) -> si6 +// CHECK: %[[CAST_53:.*]] = hwarith.cast %[[ADD_12]] : (si6) -> ui4 +// CHECK: %[[BITEXTRACT_15:.*]] = coredsl.bitextract %[[CAST_52]][0:63] : (ui480) -> ui64 +// CHECK: %[[CAST_54:.*]] = coredsl.cast %[[BITEXTRACT_15]] : ui64 to si64 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aValue{{\[}}%[[CAST_53]] : ui4] = %[[CAST_54]] : si64 +// CHECK: %[[BITEXTRACT_16:.*]] = coredsl.bitextract %[[CAST_52]][64:95] : (ui480) -> ui32 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aStruct_vec_x{{\[}}%[[CAST_53]] : ui4] = %[[BITEXTRACT_16]] : ui32 +// CHECK: %[[BITEXTRACT_17:.*]] = coredsl.bitextract %[[CAST_52]][96:127] : (ui480) -> ui32 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aStruct_vec_y{{\[}}%[[CAST_53]] : ui4] = %[[BITEXTRACT_17]] : ui32 +// CHECK: %[[BITEXTRACT_18:.*]] = coredsl.bitextract %[[CAST_52]][128:159] : (ui480) -> ui32 +// CHECK: %[[CAST_55:.*]] = coredsl.cast %[[BITEXTRACT_18]] : ui32 to si32 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aStruct_notNested{{\[}}%[[CAST_53]] : ui4] = %[[CAST_55]] : si32 +// CHECK: %[[ADD_13:.*]] = hwarith.add %[[CONSTANT_12]], %[[CONSTANT_10]] : (ui4, si3) -> si6 +// CHECK: %[[CAST_56:.*]] = hwarith.cast %[[ADD_13]] : (si6) -> ui4 +// CHECK: %[[BITEXTRACT_19:.*]] = coredsl.bitextract %[[CAST_52]][160:223] : (ui480) -> ui64 +// CHECK: %[[CAST_57:.*]] = coredsl.cast %[[BITEXTRACT_19]] : ui64 to si64 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aValue{{\[}}%[[CAST_56]] : ui4] = %[[CAST_57]] : si64 +// CHECK: %[[BITEXTRACT_20:.*]] = coredsl.bitextract %[[CAST_52]][224:255] : (ui480) -> ui32 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aStruct_vec_x{{\[}}%[[CAST_56]] : ui4] = %[[BITEXTRACT_20]] : ui32 +// CHECK: %[[BITEXTRACT_21:.*]] = coredsl.bitextract %[[CAST_52]][256:287] : (ui480) -> ui32 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aStruct_vec_y{{\[}}%[[CAST_56]] : ui4] = %[[BITEXTRACT_21]] : ui32 +// CHECK: %[[BITEXTRACT_22:.*]] = coredsl.bitextract %[[CAST_52]][288:319] : (ui480) -> ui32 +// CHECK: %[[CAST_58:.*]] = coredsl.cast %[[BITEXTRACT_22]] : ui32 to si32 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aStruct_notNested{{\[}}%[[CAST_56]] : ui4] = %[[CAST_58]] : si32 +// CHECK: %[[ADD_14:.*]] = hwarith.add %[[CONSTANT_12]], %[[CONSTANT_9]] : (ui4, si3) -> si6 +// CHECK: %[[CAST_59:.*]] = hwarith.cast %[[ADD_14]] : (si6) -> ui4 +// CHECK: %[[BITEXTRACT_23:.*]] = coredsl.bitextract %[[CAST_52]][320:383] : (ui480) -> ui64 +// CHECK: %[[CAST_60:.*]] = coredsl.cast %[[BITEXTRACT_23]] : ui64 to si64 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aValue{{\[}}%[[CAST_59]] : ui4] = %[[CAST_60]] : si64 +// CHECK: %[[BITEXTRACT_24:.*]] = coredsl.bitextract %[[CAST_52]][384:415] : (ui480) -> ui32 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aStruct_vec_x{{\[}}%[[CAST_59]] : ui4] = %[[BITEXTRACT_24]] : ui32 +// CHECK: %[[BITEXTRACT_25:.*]] = coredsl.bitextract %[[CAST_52]][416:447] : (ui480) -> ui32 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aStruct_vec_y{{\[}}%[[CAST_59]] : ui4] = %[[BITEXTRACT_25]] : ui32 +// CHECK: %[[BITEXTRACT_26:.*]] = coredsl.bitextract %[[CAST_52]][448:479] : (ui480) -> ui32 +// CHECK: %[[CAST_61:.*]] = coredsl.cast %[[BITEXTRACT_26]] : ui32 to si32 +// CHECK: coredsl.set @OTHER_STRUCT_REGS_aStruct_notNested{{\[}}%[[CAST_59]] : ui4] = %[[CAST_61]] : si32 // CHECK: coredsl.end // CHECK: } // CHECK: } From 031482ce735853da21d1357003b7aa5ab7638fe7 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Tue, 25 Aug 2026 14:11:58 +0200 Subject: [PATCH 43/45] Remove TODO --- .../CoreDSLExplodeStructRegisters.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index f6aa142..7e3946a 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -267,7 +267,6 @@ struct StructRewriteGetOps : public OpConversionPattern { for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { auto newBase = emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); - // TODO: are the values in the right order? explodeRegs( symbolName, structType, [&rewriter, &loc, &newBase, &toConcatenate, From 504678a148fe8488d7ba494b8187241afd17f3f7 Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 31 Aug 2026 10:38:34 +0200 Subject: [PATCH 44/45] Renamed symToTypeMap to align with its name in the pattern structs and added a comment explaining why we need it --- .../CoreDSLExplodeStructRegisters.cpp | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 7e3946a..031ec89 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -339,10 +339,13 @@ struct CoreDSLExplodeStructRegisters coredsl::ISAXOp isax = getOperation(); auto &ctx = getContext(); RewritePatternSet patterns{&ctx}; - llvm::StringMap symToTypeMap; - llvm::StringMap symToMaxIndexWidthMap; - patterns.insert(&ctx, symToTypeMap, - symToMaxIndexWidthMap); + // Because we are deleting the register ops when exploding the registers, + // we need to retain the struct type and the max index width for the passes + // that handle the get / set ops + llvm::StringMap symNameToType; + llvm::StringMap symNameToMaxIndexWidth; + patterns.insert(&ctx, symNameToType, + symNameToMaxIndexWidth); ConversionTarget target{ctx}; target.addLegalDialect(); @@ -353,15 +356,15 @@ struct CoreDSLExplodeStructRegisters } patterns.clear(); target.addDynamicallyLegalOp( - [&symToTypeMap](coredsl::GetOp op) { - return symToTypeMap.find(op.getSym()) == symToTypeMap.end(); + [&symNameToType](coredsl::GetOp op) { + return symNameToType.find(op.getSym()) == symNameToType.end(); }); target.addDynamicallyLegalOp( - [&symToTypeMap](coredsl::SetOp op) { - return symToTypeMap.find(op.getSym()) == symToTypeMap.end(); + [&symNameToType](coredsl::SetOp op) { + return symNameToType.find(op.getSym()) == symNameToType.end(); }); patterns.insert( - &ctx, symToTypeMap, symToMaxIndexWidthMap); + &ctx, symNameToType, symNameToMaxIndexWidth); if (failed(applyPartialConversion(isax, target, std::move(patterns)))) { return signalPassFailure(); From 379b119208d8609aab06126c56a23249a6bab7dd Mon Sep 17 00:00:00 2001 From: Benedikt Date: Mon, 31 Aug 2026 11:04:44 +0200 Subject: [PATCH 45/45] Renamed explodeRegs to traverseStructReg, because it does not do the exploding itself and is used in places where we are not exploding the structs --- .../CoreDSLExplodeStructRegisters.cpp | 61 ++++++++++--------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp index 031ec89..aa92f20 100644 --- a/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp +++ b/lib/Conversion/CoreDSLExplodeStructRegisters/CoreDSLExplodeStructRegisters.cpp @@ -20,24 +20,23 @@ using namespace circt; namespace { -// Traverses a struct typed register, calling callbacks during traversal // The callbacks are called with a string that consists of the register name, -// concatenated with the member names, so we can either explode the struct, -// or reference the already exploded registers +// concatenated with the member names, so we can either explode the register, +// or reference the already exploded registers by name template -void explodeRegs(std::string ®Name, hw::StructType type, - ScalarValueAction scalarValueAction, - StructMemberEntryAction structMemberEntryAction, - StructMemberExitAction structMemberExitAction) { +void traverseStructReg(std::string ®Name, hw::StructType type, + ScalarValueAction scalarValueAction, + StructMemberEntryAction structMemberEntryAction, + StructMemberExitAction structMemberExitAction) { const size_t regNameSize = regName.size(); for (hw::StructType::FieldInfo fieldInfo : type.getElements()) { regName += "_"; regName += fieldInfo.name.getValue(); if (auto structType = llvm::dyn_cast(fieldInfo.type)) { structMemberEntryAction(structType, fieldInfo.name); - explodeRegs(regName, structType, scalarValueAction, - structMemberEntryAction, structMemberExitAction); + traverseStructReg(regName, structType, scalarValueAction, + structMemberEntryAction, structMemberExitAction); structMemberExitAction(structType, fieldInfo.name); } else { scalarValueAction(regName, fieldInfo.name, @@ -56,15 +55,15 @@ template -void explodeRegs(StringRef regName, hw::StructType type, - ScalarValueAction scalarValueAction, - StructMemberEntryAction structMemberEntryAction = - emptyStructMemberEntryExitAction, - StructMemberExitAction structMemberExitAction = - emptyStructMemberEntryExitAction) { +void traverseStructReg(StringRef regName, hw::StructType type, + ScalarValueAction scalarValueAction, + StructMemberEntryAction structMemberEntryAction = + emptyStructMemberEntryExitAction, + StructMemberExitAction structMemberExitAction = + emptyStructMemberEntryExitAction) { auto nameString = std::string(regName); - return explodeRegs(nameString, type, scalarValueAction, - structMemberEntryAction, structMemberExitAction); + return traverseStructReg(nameString, type, scalarValueAction, + structMemberEntryAction, structMemberExitAction); } struct StructExploderPattern : public OpConversionPattern { @@ -86,7 +85,7 @@ struct StructExploderPattern : public OpConversionPattern { StringRef name = op.getName(); rewriter.setInsertionPointAfter(op); Location loc = op.getLoc(); - explodeRegs( + traverseStructReg( name, structType, [&rewriter, &loc, &op, &numElements](StringRef newRegName, StringAttr fieldName, @@ -97,8 +96,7 @@ struct StructExploderPattern : public OpConversionPattern { op.getIsConst(), op.getIsVolatile(), numElements, {}, fieldType, op.getAccessMode()); - }, - [](hw::StructType, StringAttr) {}, [](hw::StructType, StringAttr) {}); + }); symNameToType.insert(std::make_pair(op.getSymName(), structType)); symNameToMaxIndexWidth.insert( std::make_pair(op.getSymName(), op.getMaxIndexWidth())); @@ -110,7 +108,7 @@ struct StructExploderPattern : public OpConversionPattern { } }; -// Emits Add of base to offset, truncating to maxIndexWidth if the result type +// Emits add of base to offset, truncating to maxIndexWidth if the result type // is larger static Value emitTruncatedOffset(ConversionPatternRewriter &rewriter, MLIRContext *ctx, Value base, int64_t offset, @@ -172,7 +170,7 @@ struct StructRewriteSetOps : public OpConversionPattern { for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { auto idxVal = emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); - explodeRegs( + traverseStructReg( symbolName, structType, [&rewriter, &currBitPos, &loc, &value, &idxVal, idxType, ctx](StringRef newRegName, StringAttr fieldName, @@ -200,8 +198,10 @@ struct StructRewriteSetOps : public OpConversionPattern { }); } } else { + // Single element access: Extract the struct members and set the + // exploded scalar registers SmallVector opStack{op.getValue().getDefiningOp()}; - explodeRegs( + traverseStructReg( symbolName, structType, [&rewriter, &opStack, &loc, &base, &from, &to]( StringRef newRegName, StringAttr fieldName, IntegerType type) { @@ -256,8 +256,8 @@ struct StructRewriteGetOps : public OpConversionPattern { auto loc = op.getLoc(); Value replacement = nullptr; if (to != nullptr) { - // Handle ranged access: Because the return value is a scalar value in - // this case, read all scalar values from the exploded registers and + // Ranged access: Because the return value is a scalar value in this + // case, read all scalar values from the exploded registers and // concatenate them using comb.concat assert(from); SmallVector toConcatenate; @@ -267,7 +267,7 @@ struct StructRewriteGetOps : public OpConversionPattern { for (int64_t i = from.getInt(); i <= to.getInt(); ++i) { auto newBase = emitTruncatedOffset(rewriter, ctx, base, i, maxIndexWidth, loc); - explodeRegs( + traverseStructReg( symbolName, structType, [&rewriter, &loc, &newBase, &toConcatenate, ctx](StringRef newRegName, StringAttr fieldName, @@ -294,10 +294,13 @@ struct StructRewriteGetOps : public OpConversionPattern { result); replacement = resultCast.getResult(); } else { - SmallVector structOps; + // Single element access: Read the scalar values and bundle them into a + // struct SmallVector structMembers; - SmallVector structBeginIndices = {0}; - explodeRegs( + // Stores the indices in structMembers from which a nested struct's + // members begin, so they can be bundled into an intermediate struct + SmallVector structBeginIndices = {}; + traverseStructReg( symbolName, structType, [&rewriter, &loc, &structMembers, &base, &from, &to]( StringRef newRegName, StringAttr fieldName, IntegerType type) {