From a64660a530538aeb8707fb0276fe16c2468869a2 Mon Sep 17 00:00:00 2001 From: Yilou Wang Date: Tue, 3 Dec 2024 13:57:50 +0100 Subject: [PATCH] Fix foreach mixed array (#5655) (#5656) --- src/V3Begin.cpp | 11 ++- test_regress/t/t_foreach_array.v | 115 ++++++++++++++++++++----------- 2 files changed, 82 insertions(+), 44 deletions(-) diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index f20ba4f6d..7d23f8489 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -424,6 +424,7 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) { AstNode* bodyPointp = new AstBegin{nodep->fileline(), "[EditWrapper]", nullptr}; AstNode* newp = nullptr; AstNode* lastp = nodep; + AstVar* nestedIndexp = nullptr; // subfromp used to traverse each dimension of multi-d variable-sized unpacked array (queue, // dyn-arr and associative-arr) AstNodeExpr* subfromp = fromp->cloneTreePure(false); @@ -456,8 +457,13 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) { } } else if (VN_IS(fromDtp, DynArrayDType) || VN_IS(fromDtp, QueueDType)) { AstConst* const leftp = new AstConst{fl, 0}; - AstNodeExpr* const rightp - = new AstCMethodHard{fl, subfromp->cloneTreePure(false), "size"}; + AstNodeExpr* const rightp = new AstCMethodHard{ + fl, + VN_IS(subfromp->dtypep(), NodeArrayDType) + ? new AstArraySel{fl, subfromp->cloneTreePure(false), + new AstVarRef{fl, nestedIndexp, VAccess::READ}} + : subfromp->cloneTreePure(false), + "size"}; AstVarRef* varRefp = new AstVarRef{fl, varp, VAccess::READ}; subfromp = new AstCMethodHard{fl, subfromp, "at", varRefp}; subfromp->dtypep(fromDtp); @@ -508,6 +514,7 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) { if (!newp) newp = loopp; } // Prep for next + nestedIndexp = varp; fromDtp = fromDtp->subDTypep(); } // The parser validates we don't have "foreach (array[,,,])" diff --git a/test_regress/t/t_foreach_array.v b/test_regress/t/t_foreach_array.v index 7b4a8eca6..2f4297c14 100755 --- a/test_regress/t/t_foreach_array.v +++ b/test_regress/t/t_foreach_array.v @@ -5,19 +5,30 @@ // SPDX-License-Identifier: CC0-1.0 module t_foreach_array; - + // Define various structures to test foreach behavior int dyn_arr[][]; int queue[$][$]; int unpacked_arr [3:1][9:8]; int associative_array_3d[string][string][string]; - int count_que; - int exp_count_que; - int count_dyn; - int exp_count_dyn; - int count_unp; - int exp_count_unp; + int queue_unp[$][3]; // Outer dynamic queue with fixed-size inner arrays + int unp_queue[3][$]; // Fixed-size outer array with dynamic inner queues + int dyn_queue[][]; // Fully dynamic 2D array + int queue_dyn[$][]; // Outer dynamic queue with dynamic inner queues + int dyn_unp[][3]; // Dynamic outer array with fixed-size inner arrays + int unp_dyn[3][]; // Fixed-size outer array with dynamic inner arrays + + // Define counter for various structures of array + int count_que, exp_count_que; + int count_dyn, exp_count_dyn; + int count_unp, exp_count_unp; int count_assoc; + int count_queue_unp, exp_count_queue_unp; + int count_unp_queue, exp_count_unp_queue; + int count_dyn_queue, exp_count_dyn_queue; + int count_queue_dyn, exp_count_queue_dyn; + int count_dyn_unp, exp_count_dyn_unp; + int count_unp_dyn, exp_count_unp_dyn; string k1, k2, k3; @@ -35,57 +46,77 @@ module t_foreach_array; associative_array_3d["key2"]["subkey1"]["subsubkey2"] = 8; associative_array_3d["key2"]["subkey3"]["subsubkey1"] = 9; + queue_unp = '{'{1, 2, 3}, '{4, 5, 6}, '{7, 8, 9}}; + unp_queue[0] = '{10, 11}; + unp_queue[1] = '{12, 13, 14}; + unp_queue[2] = '{15}; + dyn_queue = '{'{16, 17}, '{18, 19, 20}}; + queue_dyn = '{'{21, 22}, '{23, 24, 25}}; + dyn_unp = '{'{26, 27, 28}, '{29, 30, 31}}; + unp_dyn[0] = '{32, 33}; + unp_dyn[1] = '{34, 35, 36}; + unp_dyn[2] = '{37}; + + // Perform foreach loop counting and expected value calculation count_que = 0; - - foreach(queue[i, j]) begin - count_que++; - end - + foreach(queue[i, j]) count_que++; exp_count_que = 0; - foreach(queue[i]) begin - foreach(queue[i][j]) begin - exp_count_que++; - end - end + foreach(queue[i]) foreach(queue[i][j]) exp_count_que++; count_dyn = 0; - - foreach(dyn_arr[i, j]) begin - count_dyn++; - end - + foreach(dyn_arr[i, j]) count_dyn++; exp_count_dyn = 0; - - foreach(dyn_arr[i]) begin - foreach(dyn_arr[i][j]) begin - exp_count_dyn++; - end - end + foreach(dyn_arr[i]) foreach(dyn_arr[i][j]) exp_count_dyn++; count_unp = 0; - - foreach(unpacked_arr[i, j]) begin - count_unp++; - end - + foreach(unpacked_arr[i, j]) count_unp++; exp_count_unp = 0; - - foreach(unpacked_arr[i]) begin - foreach(unpacked_arr[i][j]) begin - exp_count_unp++; - end - end + foreach(unpacked_arr[i]) foreach(unpacked_arr[i][j]) exp_count_unp++; count_assoc = 0; + foreach(associative_array_3d[k1, k2, k3]) count_assoc++; - foreach(associative_array_3d[k1, k2, k3]) begin - count_assoc++; - end + count_queue_unp = 0; + foreach (queue_unp[i, j]) count_queue_unp++; + exp_count_queue_unp = 0; + foreach (queue_unp[i]) foreach (queue_unp[i][j]) exp_count_queue_unp++; + count_unp_queue = 0; + foreach (unp_queue[i, j]) count_unp_queue++; + exp_count_unp_queue = 0; + foreach (unp_queue[i]) foreach (unp_queue[i][j]) exp_count_unp_queue++; + + count_dyn_queue = 0; + foreach (dyn_queue[i, j]) count_dyn_queue++; + exp_count_dyn_queue = 0; + foreach (dyn_queue[i]) foreach (dyn_queue[i][j]) exp_count_dyn_queue++; + + count_queue_dyn = 0; + foreach (queue_dyn[i, j]) count_queue_dyn++; + exp_count_queue_dyn = 0; + foreach (queue_dyn[i]) foreach (queue_dyn[i][j]) exp_count_queue_dyn++; + + count_dyn_unp = 0; + foreach (dyn_unp[i, j]) count_dyn_unp++; + exp_count_dyn_unp = 0; + foreach (dyn_unp[i]) foreach (dyn_unp[i][j]) exp_count_dyn_unp++; + + count_unp_dyn = 0; + foreach (unp_dyn[i, j]) count_unp_dyn++; + exp_count_unp_dyn = 0; + foreach (unp_dyn[i]) foreach (unp_dyn[i][j]) exp_count_unp_dyn++; + + // Verification checks if (count_que != 6 || count_que != exp_count_que) $stop; if (count_dyn != 12 || count_dyn != exp_count_dyn) $stop; if (count_unp != 6 || count_unp != exp_count_unp) $stop; if (count_assoc != 9) $stop; + if (count_queue_unp != exp_count_queue_unp) $stop; + if (count_unp_queue != exp_count_unp_queue) $stop; + if (count_dyn_queue != exp_count_dyn_queue) $stop; + if (count_queue_dyn != exp_count_queue_dyn) $stop; + if (count_dyn_unp != exp_count_dyn_unp) $stop; + if (count_unp_dyn != exp_count_unp_dyn) $stop; $write("*-* All Finished *-*\\n"); $finish;