Skip to content

Commit f11e9d1

Browse files
authored
[ImportVerilog] Add foreach statement support. (#8017)
Add for loop statement support, due to the lack of dyn array support, currently static-length array is supported.
1 parent 375a8e0 commit f11e9d1

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

lib/Conversion/ImportVerilog/Statements.cpp

+95
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,93 @@ struct StmtVisitor {
3434
return *block.release();
3535
}
3636

37+
LogicalResult recursiveForeach(const slang::ast::ForeachLoopStatement &stmt,
38+
uint32_t level) {
39+
// find current dimension we are operate.
40+
const auto &loopDim = stmt.loopDims[level];
41+
if (!loopDim.range.has_value()) {
42+
emitError(loc) << "dynamic loop variable is unsupported";
43+
}
44+
auto &exitBlock = createBlock();
45+
auto &stepBlock = createBlock();
46+
auto &bodyBlock = createBlock();
47+
auto &checkBlock = createBlock();
48+
49+
// Push the blocks onto the loop stack such that we can continue and break.
50+
context.loopStack.push_back({&stepBlock, &exitBlock});
51+
auto done = llvm::make_scope_exit([&] { context.loopStack.pop_back(); });
52+
53+
const auto &iter = loopDim.loopVar;
54+
auto type = context.convertType(*iter->getDeclaredType());
55+
if (!type)
56+
return failure();
57+
58+
Value initial = builder.create<moore::ConstantOp>(
59+
loc, cast<moore::IntType>(type), loopDim.range->lower());
60+
61+
// Create loop varirable in this dimension
62+
Value varOp = builder.create<moore::VariableOp>(
63+
loc, moore::RefType::get(cast<moore::UnpackedType>(type)),
64+
builder.getStringAttr(iter->name), initial);
65+
context.valueSymbols.insertIntoScope(context.valueSymbols.getCurScope(),
66+
iter, varOp);
67+
68+
builder.create<cf::BranchOp>(loc, &checkBlock);
69+
builder.setInsertionPointToEnd(&checkBlock);
70+
71+
// When the loop variable is greater than the upper bound, goto exit
72+
auto upperBound = builder.create<moore::ConstantOp>(
73+
loc, cast<moore::IntType>(type), loopDim.range->upper());
74+
75+
auto var = builder.create<moore::ReadOp>(loc, varOp);
76+
Value cond = builder.create<moore::SleOp>(loc, var, upperBound);
77+
if (!cond)
78+
return failure();
79+
cond = builder.createOrFold<moore::BoolCastOp>(loc, cond);
80+
cond = builder.create<moore::ConversionOp>(loc, builder.getI1Type(), cond);
81+
builder.create<cf::CondBranchOp>(loc, cond, &bodyBlock, &exitBlock);
82+
83+
builder.setInsertionPointToEnd(&bodyBlock);
84+
85+
// find next dimension in this foreach statement, it finded then recuersive
86+
// resolve, else perform body statement
87+
bool hasNext = false;
88+
for (uint32_t nextLevel = level + 1; nextLevel < stmt.loopDims.size();
89+
nextLevel++) {
90+
if (stmt.loopDims[nextLevel].loopVar) {
91+
if (failed(recursiveForeach(stmt, nextLevel)))
92+
return failure();
93+
hasNext = true;
94+
break;
95+
}
96+
}
97+
98+
if (!hasNext) {
99+
if (failed(context.convertStatement(stmt.body)))
100+
return failure();
101+
}
102+
if (!isTerminated())
103+
builder.create<cf::BranchOp>(loc, &stepBlock);
104+
105+
builder.setInsertionPointToEnd(&stepBlock);
106+
107+
// add one to loop variable
108+
var = builder.create<moore::ReadOp>(loc, varOp);
109+
auto one =
110+
builder.create<moore::ConstantOp>(loc, cast<moore::IntType>(type), 1);
111+
auto postValue = builder.create<moore::AddOp>(loc, var, one).getResult();
112+
builder.create<moore::BlockingAssignOp>(loc, varOp, postValue);
113+
builder.create<cf::BranchOp>(loc, &checkBlock);
114+
115+
if (exitBlock.hasNoPredecessors()) {
116+
exitBlock.erase();
117+
setTerminated();
118+
} else {
119+
builder.setInsertionPointToEnd(&exitBlock);
120+
}
121+
return success();
122+
}
123+
37124
// Skip empty statements (stray semicolons).
38125
LogicalResult visit(const slang::ast::EmptyStatement &) { return success(); }
39126

@@ -309,6 +396,14 @@ struct StmtVisitor {
309396
return success();
310397
}
311398

399+
LogicalResult visit(const slang::ast::ForeachLoopStatement &stmt) {
400+
for (uint32_t level = 0; level < stmt.loopDims.size(); level++) {
401+
if (stmt.loopDims[level].loopVar)
402+
return recursiveForeach(stmt, level);
403+
}
404+
return success();
405+
}
406+
312407
// Handle `repeat` loops.
313408
LogicalResult visit(const slang::ast::RepeatLoopStatement &stmt) {
314409
auto count = context.convertRvalueExpression(stmt.count);

test/Conversion/ImportVerilog/basic.sv

+60
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,66 @@ function void ForeverLoopStatements(bit x, bit y);
494494
forever dummyA();
495495
endfunction
496496

497+
// CHECK: func.func private @ForeachStatements(%[[ARG0:.*]]: !moore.i32, %[[ARG1:.*]]: !moore.i1) {
498+
function void ForeachStatements(int x, bit y);
499+
// CHECK: %[[ARRAY:.*]] = moore.variable : <uarray<3 x uarray<3 x uarray<3 x uarray<8 x l8>>>>>
500+
logic [7:0] array [3:1][4:2][5:3][6:-1];
501+
// CHECK: %[[C2:.*]] = moore.constant 2 : i32
502+
// CHECK: %[[I:.*]] = moore.variable %[[C2]] : <i32>
503+
// CHECK: cf.br ^[[BB1:.*]]
504+
// CHECK: ^[[BB1]]:
505+
// CHECK: %[[C4:.*]] = moore.constant 4 : i32
506+
// CHECK: %[[I_VAL:.*]] = moore.read %[[I]] : <i32>
507+
// CHECK: %[[CMP1:.*]] = moore.sle %[[I_VAL]], %[[C4]] : i32 -> i1
508+
// CHECK: %[[CONV1:.*]] = moore.conversion %[[CMP1]] : !moore.i1 -> i1
509+
// CHECK: cf.cond_br %[[CONV1]], ^[[BB2:.*]], ^[[BB10:.*]]
510+
// CHECK: ^[[BB2]]:
511+
// CHECK: %[[CM1:.*]] = moore.constant -1 : i32
512+
// CHECK: %[[J:.*]] = moore.variable %[[CM1]] : <i32>
513+
// CHECK: cf.br ^[[BB3:.*]]
514+
// CHECK: ^[[BB3]]:
515+
// CHECK: %[[C6:.*]] = moore.constant 6 : i32
516+
// CHECK: %[[J_VAL:.*]] = moore.read %[[J]] : <i32>
517+
// CHECK: %[[CMP2:.*]] = moore.sle %[[J_VAL]], %[[C6]] : i32 -> i1
518+
// CHECK: %[[CONV2:.*]] = moore.conversion %[[CMP2]] : !moore.i1 -> i1
519+
// CHECK: cf.cond_br %[[CONV2]], ^[[BB4:.*]], ^[[BB8:.*]]
520+
foreach (array[, i, ,j]) begin
521+
// CHECK: ^[[BB4]]:
522+
// CHECK: %[[CONV3:.*]] = moore.conversion %[[ARG1]] : !moore.i1 -> i1
523+
// CHECK: cf.cond_br %[[CONV3]], ^[[BB5:.*]], ^[[BB6:.*]]
524+
if (y) begin
525+
// CHECK: ^[[BB5]]:
526+
// CHECK: call @dummyA() : () -> ()
527+
// CHECK: cf.br ^[[BB8]]
528+
dummyA();
529+
break;
530+
end else begin
531+
// CHECK: ^[[BB6]]:
532+
// CHECK: call @dummyB() : () -> ()
533+
// CHECK: cf.br ^[[BB7:.*]]
534+
dummyB();
535+
continue;
536+
end
537+
// CHECK: ^[[BB7]]:
538+
// CHECK: %[[J_VAL2:.*]] = moore.read %[[J]] : <i32>
539+
// CHECK: %[[C1_1:.*]] = moore.constant 1 : i32
540+
// CHECK: %[[ADD1:.*]] = moore.add %[[J_VAL2]], %[[C1_1]] : i32
541+
// CHECK: moore.blocking_assign %[[J]], %[[ADD1]] : i32
542+
// CHECK: cf.br ^[[BB3]]
543+
// CHECK: ^[[BB8]]:
544+
// CHECK: cf.br ^[[BB9:.*]]
545+
// CHECK: ^[[BB9]]:
546+
// CHECK: %[[I_VAL2:.*]] = moore.read %[[I]] : <i32>
547+
// CHECK: %[[C1_2:.*]] = moore.constant 1 : i32
548+
// CHECK: %[[ADD2:.*]] = moore.add %[[I_VAL2]], %[[C1_2]] : i32
549+
// CHECK: moore.blocking_assign %[[I]], %[[ADD2]] : i32
550+
// CHECK: cf.br ^[[BB1]]
551+
// CHECK: ^[[BB10]]:
552+
// CHECK: return
553+
end
554+
endfunction
555+
556+
497557
// CHECK-LABEL: func.func private @WhileLoopStatements(
498558
// CHECK-SAME: %arg0: !moore.i1
499559
// CHECK-SAME: %arg1: !moore.i1

0 commit comments

Comments
 (0)