diff --git a/Changes b/Changes index 77adf7ad4..6f6cb2cd0 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 5.047 devel **Other:** +* Fix wide conditional short circuiting (#7155). Verilator 5.046 2026-02-28 diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index e3e4534ff..d5fde472b 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -2792,10 +2792,9 @@ static inline void VL_SELASSIGN_WW(int rbits, int obits, WDataOutP iowp, WDataIn //====================================================================== // Triops -static inline WDataOutP VL_COND_WIWW(int obits, WDataOutP owp, int cond, WDataInP const w1p, - WDataInP const w2p) VL_MT_SAFE { - return VL_MEMCPY_W(owp, cond ? w1p : w2p, VL_WORDS_I(obits)); -} +// This must be a macro in order for short-circuiting of the values to work. +#define VL_COND_WIWW(obits, owp, cond, w1p, w2p) \ + VL_MEMCPY_W(owp, (cond) ? (w1p) : (w2p), VL_WORDS_I(obits)) //====================================================================== // Constification diff --git a/test_regress/t/t_cover_line_wide_ternary.out b/test_regress/t/t_cover_line_wide_ternary.out index 692bb31a9..ddbc770fd 100644 --- a/test_regress/t/t_cover_line_wide_ternary.out +++ b/test_regress/t/t_cover_line_wide_ternary.out @@ -39,37 +39,37 @@ -000009 point: type=line comment=block hier=top.t %000009 {intf_sel_ff.foo, intf_sel_ff.bar, intf_sel_ff.baz} <= -000009 point: type=line comment=block hier=top.t -%000009 cyc[0] ? --000009 point: type=branch comment=cond_then hier=top.t -%000009 {intfs[1].foo, intfs[1].bar, intfs[1].baz} : --000009 point: type=branch comment=cond_then hier=top.t --000009 point: type=branch comment=cond_else hier=top.t -%000009 {intfs[0].foo, intfs[0].bar, intfs[0].baz}; --000009 point: type=branch comment=cond_else hier=top.t +%000005 cyc[0] ? +-000005 point: type=branch comment=cond_then hier=top.t +%000005 {intfs[1].foo, intfs[1].bar, intfs[1].baz} : +-000005 point: type=branch comment=cond_then hier=top.t +-000004 point: type=branch comment=cond_else hier=top.t +%000004 {intfs[0].foo, intfs[0].bar, intfs[0].baz}; +-000004 point: type=branch comment=cond_else hier=top.t end 000010 always_comb begin +000010 point: type=line comment=block hier=top.t 000010 {intf_sel_comb.foo, intf_sel_comb.bar, intf_sel_comb.baz} = +000010 point: type=line comment=block hier=top.t - 000010 cyc[0] ? -+000010 point: type=branch comment=cond_then hier=top.t - 000010 {intfs[1].foo, intfs[1].bar, intfs[1].baz} : -+000010 point: type=branch comment=cond_then hier=top.t -+000010 point: type=branch comment=cond_else hier=top.t - 000010 {intfs[0].foo, intfs[0].bar, intfs[0].baz}; -+000010 point: type=branch comment=cond_else hier=top.t +%000005 cyc[0] ? +-000005 point: type=branch comment=cond_then hier=top.t +%000005 {intfs[1].foo, intfs[1].bar, intfs[1].baz} : +-000005 point: type=branch comment=cond_then hier=top.t +-000005 point: type=branch comment=cond_else hier=top.t +%000005 {intfs[0].foo, intfs[0].bar, intfs[0].baz}; +-000005 point: type=branch comment=cond_else hier=top.t end assign {intf_sel_assign.foo, intf_sel_assign.bar, intf_sel_assign.baz} = - 000010 cyc[0] ? -+000010 point: type=branch comment=cond_then hier=top.t - 000010 {intfs[1].foo, intfs[1].bar, intfs[1].baz} : -+000010 point: type=branch comment=cond_then hier=top.t -+000010 point: type=branch comment=cond_else hier=top.t - 000010 {intfs[0].foo, intfs[0].bar, intfs[0].baz}; -+000010 point: type=branch comment=cond_else hier=top.t +%000005 cyc[0] ? +-000005 point: type=branch comment=cond_then hier=top.t +%000005 {intfs[1].foo, intfs[1].bar, intfs[1].baz} : +-000005 point: type=branch comment=cond_then hier=top.t +-000005 point: type=branch comment=cond_else hier=top.t +%000005 {intfs[0].foo, intfs[0].bar, intfs[0].baz}; +-000005 point: type=branch comment=cond_else hier=top.t %000009 always @ (posedge clk) begin -000009 point: type=line comment=block hier=top.t diff --git a/test_regress/t/t_math_cond_short_circuit.py b/test_regress/t/t_math_cond_short_circuit.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_math_cond_short_circuit.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_math_cond_short_circuit.v b/test_regress/t/t_math_cond_short_circuit.v new file mode 100644 index 000000000..c86ab7097 --- /dev/null +++ b/test_regress/t/t_math_cond_short_circuit.v @@ -0,0 +1,91 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +`ifdef verilator + `define optimize_barrier $c("") +`else + `define optimize_barrier +`endif +// verilog_format: on + +module t; + + class Map; + virtual function bit [95:0] get_value(); + bit [95:0] result = 96'h11111111_22222222_33333333; + `optimize_barrier; + return result; + endfunction + endclass + + class Cls; + function bit [95:0] get_default(); + bit [95:0] result = 96'haaaaaaaa_bbbbbbbb_cccccccc; + `optimize_barrier; + return result; + endfunction + + function bit [95:0] compute_LL(Map map); + bit [95:0] result; + `optimize_barrier; + // Wide operation is required, as results in VL_COND call which evaluates + // arguments + result = map == null ? this.get_default() : map.get_value(); + `optimize_barrier; + return result; + endfunction + + function bit [95:0] compute_LC(Map map); + bit [95:0] result; + bit sel1 = map == null; + `optimize_barrier; + result = sel1 ? 96'hffffffff_ffffffff_ffffffff : map.get_value(); + `optimize_barrier; + return result; + endfunction + + function bit [95:0] compute_CL(Map map); + bit [95:0] result; + bit sel1 = map != null; + `optimize_barrier; + result = sel1 ? map.get_value() : 96'hffffffff_ffffffff_ffffffff; + `optimize_barrier; + return result; + endfunction + + endclass + + initial begin + Cls c; + Map mnull; + Map m; + bit [95:0] res; + + c = new; + m = new; + + res = c.compute_LL(mnull); + `checkh(res, 96'haaaaaaaa_bbbbbbbb_cccccccc); + res = c.compute_LL(m); + `checkh(res, 96'h11111111_22222222_33333333); + + res = c.compute_LC(mnull); + `checkh(res, 96'hffffffff_ffffffff_ffffffff); + res = c.compute_LC(m); + `checkh(res, 96'h11111111_22222222_33333333); + + res = c.compute_CL(mnull); + `checkh(res, 96'hffffffff_ffffffff_ffffffff); + res = c.compute_CL(m); + `checkh(res, 96'h11111111_22222222_33333333); + + $finish; + end + +endmodule