Skip to content

Commit

Permalink
[HWLegalizeModules] Legalize aggregate constant (#4626)
Browse files Browse the repository at this point in the history
This PR extends HWLegalizeModules to support aggregate constants. 
Also `signalPassFailure` is called when we fail to legalize expressions.


Fix #4623.
  • Loading branch information
uenoku authored Feb 7, 2023
1 parent 05ca657 commit 2b612a2
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 16 deletions.
41 changes: 28 additions & 13 deletions lib/Dialect/SV/Transforms/HWLegalizeModules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,33 +56,46 @@ struct HWLegalizeModulesPass
/// This returns a replacement operation if lowering was successful, null
/// otherwise.
Operation *HWLegalizeModulesPass::tryLoweringArrayGet(hw::ArrayGetOp getOp) {
// If the operand is an array_create, then we can lower this into a casez.
auto createOp = getOp.getInput().getDefiningOp<hw::ArrayCreateOp>();
if (!createOp)
SmallVector<Value> caseValues;
OpBuilder builder(&thisHWModule.getBodyBlock()->front());
// If the operand is an array_create or aggregate constant, then we can lower
// this into a casez.
if (auto createOp = getOp.getInput().getDefiningOp<hw::ArrayCreateOp>())
caseValues = SmallVector<Value>(llvm::reverse(createOp.getOperands()));
else if (auto aggregateConstant =
getOp.getInput().getDefiningOp<hw::AggregateConstantOp>()) {
for (auto elem : llvm::reverse(aggregateConstant.getFields())) {
if (auto intAttr = dyn_cast<IntegerAttr>(elem))
caseValues.push_back(builder.create<hw::ConstantOp>(
aggregateConstant.getLoc(), intAttr));
else
caseValues.push_back(builder.create<hw::AggregateConstantOp>(
aggregateConstant.getLoc(), getOp.getType(),
elem.cast<ArrayAttr>()));
}
} else {
return nullptr;
}

// array_get(idx, array_create(a,b,c,d)) ==> casez(idx).
Value index = getOp.getIndex();

// Create the wire for the result of the casez in the hw.module.
OpBuilder builder(&thisHWModule.getBodyBlock()->front());

auto theWire = builder.create<sv::RegOp>(getOp.getLoc(), getOp.getType(),
builder.getStringAttr("casez_tmp"));
builder.setInsertionPoint(getOp);

auto loc = getOp.getInput().getDefiningOp()->getLoc();
// A casez is a procedural operation, so if we're in a non-procedural region
// we need to inject an always_comb block.
if (!getOp->getParentOp()->hasTrait<sv::ProceduralRegion>()) {
auto alwaysComb = builder.create<sv::AlwaysCombOp>(createOp.getLoc());
auto alwaysComb = builder.create<sv::AlwaysCombOp>(loc);
builder.setInsertionPointToEnd(alwaysComb.getBodyBlock());
}

// If we are missing elements in the array (it is non-power of two), then
// add a default 'X' value.
SmallVector<Value> caseValues(llvm::reverse(createOp.getOperands()));
if (1ULL << index.getType().getIntOrFloatBitWidth() !=
createOp.getNumOperands()) {
if (1ULL << index.getType().getIntOrFloatBitWidth() != caseValues.size()) {
caseValues.push_back(
builder.create<sv::ConstantXOp>(getOp.getLoc(), getOp.getType()));
}
Expand All @@ -92,7 +105,7 @@ Operation *HWLegalizeModulesPass::tryLoweringArrayGet(hw::ArrayGetOp getOp) {

// Create the casez itself.
builder.create<sv::CaseOp>(
createOp.getLoc(), CaseStmtType::CaseZStmt, index, caseValues.size(),
loc, CaseStmtType::CaseZStmt, index, caseValues.size(),
[&](size_t caseIdx) -> std::unique_ptr<sv::CasePattern> {
// Use a default pattern for the last value, even if we are complete.
// This avoids tools thinking they need to insert a latch due to
Expand All @@ -106,7 +119,7 @@ Operation *HWLegalizeModulesPass::tryLoweringArrayGet(hw::ArrayGetOp getOp) {
else
thePattern = std::make_unique<sv::CaseBitPattern>(caseValue, context);
++caseValue;
builder.create<sv::BPAssignOp>(createOp.getLoc(), theWire, theValue);
builder.create<sv::BPAssignOp>(loc, theWire, theValue);
return thePattern;
});

Expand Down Expand Up @@ -149,9 +162,10 @@ void HWLegalizeModulesPass::processPostOrder(Block &body) {
continue;
}

// If this is a dead array_create, then we can just delete it. This is
// If this is a dead array, then we can just delete it. This is
// probably left over from get/create lowering.
if (isa<hw::ArrayCreateOp>(op) && op.use_empty()) {
if (isa<hw::ArrayCreateOp, hw::AggregateConstantOp>(op) &&
op.use_empty()) {
op.erase();
continue;
}
Expand All @@ -163,6 +177,7 @@ void HWLegalizeModulesPass::processPostOrder(Block &body) {
for (auto value : op.getResults()) {
if (value.getType().isa<hw::ArrayType>()) {
op.emitError("unsupported packed array expression");
signalPassFailure();
}
}
}
Expand Down
34 changes: 31 additions & 3 deletions test/Dialect/SV/hw-legalize-modules-packed-arrays.mlir
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// RUN: circt-opt -hw-legalize-modules -verify-diagnostics %s | FileCheck %s
// RUN: circt-opt -split-input-file -hw-legalize-modules -verify-diagnostics %s | FileCheck %s

module attributes {circt.loweringOptions = "disallowPackedArrays"} {

// CHECK-LABEL: hw.module @reject_arrays
hw.module @reject_arrays(%arg0: i8, %arg1: i8, %arg2: i8,
%arg3: i8, %sel: i2, %clock: i1)
-> (a: !hw.array<4xi8>) {
Expand All @@ -19,7 +17,10 @@ hw.module @reject_arrays(%arg0: i8, %arg1: i8, %arg2: i8,
%1 = sv.read_inout %reg : !hw.inout<array<4xi8>>
hw.output %1 : !hw.array<4xi8>
}
}

// -----
module attributes {circt.loweringOptions = "disallowPackedArrays"} {
// CHECK-LABEL: hw.module @array_create_get_comb
hw.module @array_create_get_comb(%arg0: i8, %arg1: i8, %arg2: i8, %arg3: i8,
%sel: i2)
Expand Down Expand Up @@ -83,4 +84,31 @@ hw.module @array_create_get_default(%arg0: i8, %arg1: i8, %arg2: i8, %arg3: i8,
}
}

// CHECK-LABEL: hw.module @array_constant_get_comb
hw.module @array_constant_get_comb(%sel: i2)
-> (a: i8) {
// CHECK: %casez_tmp = sv.reg : !hw.inout<i8>
// CHECK: sv.alwayscomb {
// CHECK: sv.case casez %sel : i2
// CHECK: case b00: {
// CHECK: sv.bpassign %casez_tmp, %c3_i8 : i8
// CHECK: }
// CHECK: case b01: {
// CHECK: sv.bpassign %casez_tmp, %c2_i8 : i8
// CHECK: }
// CHECK: case b10: {
// CHECK: sv.bpassign %casez_tmp, %c1_i8 : i8
// CHECK: }
// CHECK: default: {
// CHECK: sv.bpassign %casez_tmp, %c0_i8 : i8
// CHECK: }
// CHECK: }
%0 = hw.aggregate_constant [0 : i8, 1 : i8, 2 : i8, 3 : i8] : !hw.array<4xi8>
// CHECK: %0 = sv.read_inout %casez_tmp : !hw.inout<i8>
%1 = hw.array_get %0[%sel] : !hw.array<4xi8>, i2

// CHECK: hw.output %0 : i8
hw.output %1 : i8
}

} // end builtin.module

0 comments on commit 2b612a2

Please sign in to comment.