diff --git a/lib/Conversion/ImportVerilog/Statements.cpp b/lib/Conversion/ImportVerilog/Statements.cpp index fe1bc80f5d2c..bf5179c6aedd 100644 --- a/lib/Conversion/ImportVerilog/Statements.cpp +++ b/lib/Conversion/ImportVerilog/Statements.cpp @@ -34,6 +34,93 @@ struct StmtVisitor { return *block.release(); } + LogicalResult recursiveForeach(const slang::ast::ForeachLoopStatement &stmt, + uint32_t level) { + // find current dimension we are operate. + const auto &loopDim = stmt.loopDims[level]; + if (!loopDim.range.has_value()) { + emitError(loc) << "dynamic loop variable is unsupported"; + } + auto &exitBlock = createBlock(); + auto &stepBlock = createBlock(); + auto &bodyBlock = createBlock(); + auto &checkBlock = createBlock(); + + // Push the blocks onto the loop stack such that we can continue and break. + context.loopStack.push_back({&stepBlock, &exitBlock}); + auto done = llvm::make_scope_exit([&] { context.loopStack.pop_back(); }); + + const auto &iter = loopDim.loopVar; + auto type = context.convertType(*iter->getDeclaredType()); + if (!type) + return failure(); + + Value initial = builder.create( + loc, cast(type), loopDim.range->lower()); + + // Create loop varirable in this dimension + Value varOp = builder.create( + loc, moore::RefType::get(cast(type)), + builder.getStringAttr(iter->name), initial); + context.valueSymbols.insertIntoScope(context.valueSymbols.getCurScope(), + iter, varOp); + + builder.create(loc, &checkBlock); + builder.setInsertionPointToEnd(&checkBlock); + + // When the loop variable is greater than the upper bound, goto exit + auto upperBound = builder.create( + loc, cast(type), loopDim.range->upper()); + + auto var = builder.create(loc, varOp); + Value cond = builder.create(loc, var, upperBound); + if (!cond) + return failure(); + cond = builder.createOrFold(loc, cond); + cond = builder.create(loc, builder.getI1Type(), cond); + builder.create(loc, cond, &bodyBlock, &exitBlock); + + builder.setInsertionPointToEnd(&bodyBlock); + + // find next dimension in this foreach statement, it finded then recuersive + // resolve, else perform body statement + bool hasNext = false; + for (uint32_t nextLevel = level + 1; nextLevel < stmt.loopDims.size(); + nextLevel++) { + if (stmt.loopDims[nextLevel].loopVar) { + if (failed(recursiveForeach(stmt, nextLevel))) + return failure(); + hasNext = true; + break; + } + } + + if (!hasNext) { + if (failed(context.convertStatement(stmt.body))) + return failure(); + } + if (!isTerminated()) + builder.create(loc, &stepBlock); + + builder.setInsertionPointToEnd(&stepBlock); + + // add one to loop variable + var = builder.create(loc, varOp); + auto one = + builder.create(loc, cast(type), 1); + auto postValue = builder.create(loc, var, one).getResult(); + builder.create(loc, varOp, postValue); + builder.create(loc, &checkBlock); + + if (exitBlock.hasNoPredecessors()) { + exitBlock.erase(); + setTerminated(); + } else { + builder.setInsertionPointToEnd(&exitBlock); + } + return success(); + } + // Skip empty statements (stray semicolons). LogicalResult visit(const slang::ast::EmptyStatement &) { return success(); } @@ -309,6 +396,14 @@ struct StmtVisitor { return success(); } + LogicalResult visit(const slang::ast::ForeachLoopStatement &stmt) { + for (uint32_t level = 0; level < stmt.loopDims.size(); level++) { + if (stmt.loopDims[level].loopVar) + return recursiveForeach(stmt, level); + } + return failure(); + } + // Handle `repeat` loops. LogicalResult visit(const slang::ast::RepeatLoopStatement &stmt) { auto count = context.convertRvalueExpression(stmt.count); diff --git a/test/Conversion/ImportVerilog/basic.sv b/test/Conversion/ImportVerilog/basic.sv index 7959351f000c..736d3792e0fa 100644 --- a/test/Conversion/ImportVerilog/basic.sv +++ b/test/Conversion/ImportVerilog/basic.sv @@ -494,6 +494,66 @@ function void ForeverLoopStatements(bit x, bit y); forever dummyA(); endfunction +// CHECK: func.func private @ForeachStatements(%[[ARG0:.*]]: !moore.i32, %[[ARG1:.*]]: !moore.i1) { +function void ForeachStatements(int x, bit y); +// CHECK: %[[ARRAY:.*]] = moore.variable : >>>> + logic [7:0] array [3:1][4:2][5:3][6:-1]; +// CHECK: %[[C2:.*]] = moore.constant 2 : i32 +// CHECK: %[[I:.*]] = moore.variable %[[C2]] : +// CHECK: cf.br ^[[BB1:.*]] +// CHECK: ^[[BB1]]: +// CHECK: %[[C4:.*]] = moore.constant 4 : i32 +// CHECK: %[[I_VAL:.*]] = moore.read %[[I]] : +// CHECK: %[[CMP1:.*]] = moore.sle %[[I_VAL]], %[[C4]] : i32 -> i1 +// CHECK: %[[CONV1:.*]] = moore.conversion %[[CMP1]] : !moore.i1 -> i1 +// CHECK: cf.cond_br %[[CONV1]], ^[[BB2:.*]], ^[[BB10:.*]] +// CHECK: ^[[BB2]]: +// CHECK: %[[CM1:.*]] = moore.constant -1 : i32 +// CHECK: %[[J:.*]] = moore.variable %[[CM1]] : +// CHECK: cf.br ^[[BB3:.*]] +// CHECK: ^[[BB3]]: +// CHECK: %[[C6:.*]] = moore.constant 6 : i32 +// CHECK: %[[J_VAL:.*]] = moore.read %[[J]] : +// CHECK: %[[CMP2:.*]] = moore.sle %[[J_VAL]], %[[C6]] : i32 -> i1 +// CHECK: %[[CONV2:.*]] = moore.conversion %[[CMP2]] : !moore.i1 -> i1 +// CHECK: cf.cond_br %[[CONV2]], ^[[BB4:.*]], ^[[BB8:.*]] + foreach (array[, i, ,j]) begin +// CHECK: ^[[BB4]]: +// CHECK: %[[CONV3:.*]] = moore.conversion %[[ARG1]] : !moore.i1 -> i1 +// CHECK: cf.cond_br %[[CONV3]], ^[[BB5:.*]], ^[[BB6:.*]] + if (y) begin +// CHECK: ^[[BB5]]: +// CHECK: call @dummyA() : () -> () +// CHECK: cf.br ^[[BB8]] + dummyA(); + break; + end else begin +// CHECK: ^[[BB6]]: +// CHECK: call @dummyB() : () -> () +// CHECK: cf.br ^[[BB7:.*]] + dummyB(); + continue; + end +// CHECK: ^[[BB7]]: +// CHECK: %[[J_VAL2:.*]] = moore.read %[[J]] : +// CHECK: %[[C1_1:.*]] = moore.constant 1 : i32 +// CHECK: %[[ADD1:.*]] = moore.add %[[J_VAL2]], %[[C1_1]] : i32 +// CHECK: moore.blocking_assign %[[J]], %[[ADD1]] : i32 +// CHECK: cf.br ^[[BB3]] +// CHECK: ^[[BB8]]: +// CHECK: cf.br ^[[BB9:.*]] +// CHECK: ^[[BB9]]: +// CHECK: %[[I_VAL2:.*]] = moore.read %[[I]] : +// CHECK: %[[C1_2:.*]] = moore.constant 1 : i32 +// CHECK: %[[ADD2:.*]] = moore.add %[[I_VAL2]], %[[C1_2]] : i32 +// CHECK: moore.blocking_assign %[[I]], %[[ADD2]] : i32 +// CHECK: cf.br ^[[BB1]] +// CHECK: ^[[BB10]]: +// CHECK: return + end +endfunction + + // CHECK-LABEL: func.func private @WhileLoopStatements( // CHECK-SAME: %arg0: !moore.i1 // CHECK-SAME: %arg1: !moore.i1