[importverilog] Lvalue RangelSelect and ElementSelect to use range. (#8663)

This makes it uniform with how the RvalueExprVisitor handles it.

Resolves: #8657
This commit is contained in:
Jacques Pienaar 2025-07-08 10:07:12 -07:00 committed by GitHub
parent 9ef39afe15
commit b033712e91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 58 additions and 36 deletions

View File

@ -27,6 +27,36 @@ static FVInt convertSVIntToFVInt(const slang::SVInt &svint) {
return FVInt(APInt(svint.getBitWidth(), value));
}
static Value getSelectIndex(OpBuilder &builder, Location loc, Value index,
const slang::ConstantRange &range) {
auto indexType = cast<moore::UnpackedType>(index.getType());
auto bw = std::max(llvm::Log2_32_Ceil(std::max(std::abs(range.lower()),
std::abs(range.upper()))),
indexType.getBitSize().value());
auto intType =
moore::IntType::get(index.getContext(), bw, indexType.getDomain());
if (range.isLittleEndian()) {
if (range.lower() == 0)
return index;
Value newIndex =
builder.createOrFold<moore::ConversionOp>(loc, intType, index);
Value offset = builder.create<moore::ConstantOp>(
loc, intType, range.lower(), /*isSigned = */ range.lower() < 0);
return builder.createOrFold<moore::SubOp>(loc, newIndex, offset);
}
if (range.upper() == 0)
return builder.createOrFold<moore::NegOp>(loc, index);
Value newIndex =
builder.createOrFold<moore::ConversionOp>(loc, intType, index);
Value offset = builder.create<moore::ConstantOp>(
loc, intType, range.upper(), /* isSigned = */ range.upper() < 0);
return builder.createOrFold<moore::SubOp>(loc, offset, newIndex);
}
// NOLINTBEGIN(misc-no-recursion)
namespace {
struct RvalueExprVisitor {
@ -458,35 +488,6 @@ struct RvalueExprVisitor {
return builder.create<moore::ReplicateOp>(loc, type, value);
}
Value getSelectIndex(Value index, const slang::ConstantRange &range) const {
auto indexType = cast<moore::UnpackedType>(index.getType());
auto bw = std::max(llvm::Log2_32_Ceil(std::max(std::abs(range.lower()),
std::abs(range.upper()))),
indexType.getBitSize().value());
auto intType =
moore::IntType::get(index.getContext(), bw, indexType.getDomain());
if (range.isLittleEndian()) {
if (range.lower() == 0)
return index;
Value newIndex =
builder.createOrFold<moore::ConversionOp>(loc, intType, index);
Value offset = builder.create<moore::ConstantOp>(
loc, intType, range.lower(), /*isSigned = */ range.lower() < 0);
return builder.createOrFold<moore::SubOp>(loc, newIndex, offset);
}
if (range.upper() == 0)
return builder.createOrFold<moore::NegOp>(loc, index);
Value newIndex =
builder.createOrFold<moore::ConversionOp>(loc, intType, index);
Value offset = builder.create<moore::ConstantOp>(
loc, intType, range.upper(), /* isSigned = */ range.upper() < 0);
return builder.createOrFold<moore::SubOp>(loc, offset, newIndex);
}
// Handle single bit selections.
Value visit(const slang::ast::ElementSelectExpression &expr) {
auto type = context.convertType(*expr.type);
@ -505,8 +506,8 @@ struct RvalueExprVisitor {
auto lowBit = context.convertRvalueExpression(expr.selector());
if (!lowBit)
return {};
return builder.create<moore::DynExtractOp>(loc, type, value,
getSelectIndex(lowBit, range));
return builder.create<moore::DynExtractOp>(
loc, type, value, getSelectIndex(builder, loc, lowBit, range));
}
// Handle range bits selections.
@ -574,7 +575,7 @@ struct RvalueExprVisitor {
return builder.create<moore::ExtractOp>(
loc, type, value, range.translateIndex(constLowBit));
return builder.create<moore::DynExtractOp>(
loc, type, value, getSelectIndex(dynLowBit, range));
loc, type, value, getSelectIndex(builder, loc, dynLowBit, range));
}
Value visit(const slang::ast::MemberAccessExpression &expr) {
@ -1012,6 +1013,7 @@ struct LvalueExprVisitor {
auto value = context.convertLvalueExpression(expr.value());
if (!type || !value)
return {};
auto range = expr.value().type->getFixedRange();
if (auto *constValue = expr.selector().constant) {
assert(!constValue->hasUnknown());
assert(constValue->size() <= 32);
@ -1019,14 +1021,14 @@ struct LvalueExprVisitor {
auto lowBit = constValue->integer().as<uint32_t>().value();
return builder.create<moore::ExtractRefOp>(
loc, moore::RefType::get(cast<moore::UnpackedType>(type)), value,
lowBit);
range.translateIndex(lowBit));
}
auto lowBit = context.convertRvalueExpression(expr.selector());
if (!lowBit)
return {};
return builder.create<moore::DynExtractRefOp>(
loc, moore::RefType::get(cast<moore::UnpackedType>(type)), value,
lowBit);
getSelectIndex(builder, loc, lowBit, range));
}
// Handle range bits selections.
@ -1089,13 +1091,14 @@ struct LvalueExprVisitor {
else
dynLowBit = context.convertRvalueExpression(expr.left());
}
auto range = expr.value().type->getFixedRange();
if (leftConst && rightConst)
return builder.create<moore::ExtractRefOp>(
loc, moore::RefType::get(cast<moore::UnpackedType>(type)), value,
constLowBit);
range.translateIndex(constLowBit));
return builder.create<moore::DynExtractRefOp>(
loc, moore::RefType::get(cast<moore::UnpackedType>(type)), value,
dynLowBit);
getSelectIndex(builder, loc, dynLowBit, range));
}
Value visit(const slang::ast::StreamingConcatenationExpression &expr) {

View File

@ -2763,3 +2763,22 @@ function void seeminglyExhaustiveCase(logic [1:0] a);
default: z = 4'b1111;
endcase
endfunction
// Regression test for #8657.
// CHECK-LABEL: rvalueAndLvalueElementSelect
module rvalueAndLvalueElementSelect(
input wire [63:0] arg0,
output wire [63:0] result0
);
wire [0:1][31:0] arg0_unflattened;
// CHECK: moore.extract_ref {{.*}} from 1 : <array<2 x l32>> -> <l32>
assign arg0_unflattened[0] = arg0[31:0];
// CHECK: moore.extract_ref {{.*}} from 0 : <array<2 x l32>> -> <l32>
assign arg0_unflattened[1] = arg0[63:32];
// CHECK: moore.extract {{.*}} from 0 : array<2 x l32> -> l32
// CHECK: moore.extract {{.*}} from 1 : array<2 x l32> -> l32
assign result0 = {arg0_unflattened[1], arg0_unflattened[0]};
endmodule