// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Geza Lore.
// SPDX-License-Identifier: CC0-1.0

`define signal(name, expr) wire [$bits(expr)-1:0] ``name = expr

module t (
`include "portlist.vh" // Boilerplate generated by t_dfg_peephole.py
          rand_a, rand_b, srand_a, srand_b
          );

`include "portdecl.vh" // Boilerplate generated by t_dfg_peephole.py

   input rand_a;
   input rand_b;
   input srand_a;
   input srand_b;
   wire logic        [63:0] rand_a;
   wire logic        [63:0] rand_b;
   wire logic signed [63:0] srand_a;
   wire logic signed [63:0] srand_b;

   wire        logic randbit_a = rand_a[0];
   wire        logic [127:0] rand_ba = {rand_b, rand_a};
   wire        logic [127:0] rand_aa = {2{rand_a}};
   wire        logic [63:0] const_a;
   wire        logic [63:0] const_b;
   wire        logic signed [63:0] sconst_a;
   wire        logic signed [63:0] sconst_b;
   wire        logic [63:0] array [3:0];
   assign array[0] = (rand_a << 32) | (rand_a >> 32);
   assign array[1] = (rand_a << 16) | (rand_a >> 48);

   `signal(FOLD_UNARY_CLog2,       $clog2(const_a));
   `signal(FOLD_UNARY_CountOnes,   $countones(const_a));
   `signal(FOLD_UNARY_IsUnknown,   $isunknown(const_a));
   `signal(FOLD_UNARY_LogNot,      !const_a[0]);
   `signal(FOLD_UNARY_Negate,      -const_a);
   `signal(FOLD_UNARY_Not,         ~const_a);
   `signal(FOLD_UNARY_OneHot,      $onehot(const_a));
   `signal(FOLD_UNARY_OneHot0,     $onehot0(const_a));
   `signal(FOLD_UNARY_RedAnd,      &const_a);
   `signal(FOLD_UNARY_RedOr,       |const_a);
   `signal(FOLD_UNARY_RedXor,      ^const_a);
   // verilator lint_off WIDTH
   wire        logic        [79:0] tmp_FOLD_UNARY_Extend  = const_a;
   wire        logic signed [79:0] tmp_FOLD_UNARY_ExtendS = sconst_a;
   //verilator lint_on WIDTH
   `signal(FOLD_UNARY_Extend, tmp_FOLD_UNARY_Extend);
   `signal(FOLD_UNARY_ExtendS, tmp_FOLD_UNARY_ExtendS);

   `signal(FOLD_BINARY_Add,       const_a + const_b);
   `signal(FOLD_BINARY_And,       const_a & const_b);
   `signal(FOLD_BINARY_Concat,    {const_a, const_b});
   `signal(FOLD_BINARY_Div,       const_a / 64'd3);
   `signal(FOLD_BINARY_DivS,      sconst_a / 64'sd3);
   `signal(FOLD_BINARY_Eq,        const_a == const_b);
   `signal(FOLD_BINARY_Gt,        const_a > const_b);
   `signal(FOLD_BINARY_GtS,       sconst_a > sconst_b);
   `signal(FOLD_BINARY_Gte,       const_a >= const_b);
   `signal(FOLD_BINARY_GteS,      sconst_a >= sconst_b);
   `signal(FOLD_BINARY_LogAnd,    const_a[0] && const_b[0]);
   `signal(FOLD_BINARY_LogEq,     const_a[0] <-> const_b[0]);
   `signal(FOLD_BINARY_LogIf,     const_a[0] -> const_b[0]);
   `signal(FOLD_BINARY_LogOr,     const_a[0] || const_b[0]);
   `signal(FOLD_BINARY_Lt,        const_a < const_b);
   `signal(FOLD_BINARY_LtS,       sconst_a < sconst_b);
   `signal(FOLD_BINARY_Lte,       const_a <= const_b);
   `signal(FOLD_BINARY_LteS,      sconst_a <= sconst_b);
   `signal(FOLD_BINARY_ModDiv,    const_a % 64'd3);
   `signal(FOLD_BINARY_ModDivS,   sconst_a % 64'sd3);
   `signal(FOLD_BINARY_Mul,       const_a * 64'd3);
   `signal(FOLD_BINARY_MulS,      sconst_a * 64'sd3);
   `signal(FOLD_BINARY_Neq,       const_a != const_b);
   `signal(FOLD_BINARY_Or,        const_a | const_b);
   `signal(FOLD_BINARY_Pow,       const_a ** 64'd2);
   `signal(FOLD_BINARY_PowSS,     sconst_a ** 64'sd2);
   `signal(FOLD_BINARY_PowSU,     sconst_a ** 64'd2);
   `signal(FOLD_BINARY_PowUS,     const_a ** 64'sd2);
   `signal(FOLD_BINARY_Replicate, {2{const_a}});
   `signal(FOLD_BINARY_ShiftL,    const_a << 2);
   `signal(FOLD_BINARY_ShiftR,    const_a >> 2);
   `signal(FOLD_BINARY_ShiftRS,   sconst_a >>> 2);
   `signal(FOLD_BINARY_Sub,       const_a - const_b);
   `signal(FOLD_BINARY_Xor,       const_a ^ const_b);

   `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_And,    (const_a & (const_b & rand_a)));
   `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_Or,     (const_a | (const_b | rand_a)));
   `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_Xor,    (const_a ^ (const_b ^ rand_a)));
   `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_Add,    (const_a + (const_b + rand_a)));
   `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_Mul,    (const_a * (const_b * rand_a)));
   `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_MulS,   (sconst_a * (sconst_b * srand_a)));
   `signal(FOLD_ASSOC_BINARY_LHS_OF_RHS_Concat, {const_a, {const_b, rand_a}});

   `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_And,    ((rand_a & const_b) & const_a));
   `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_Or,     ((rand_a | const_b) | const_a));
   `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_Xor,    ((rand_a ^ const_b) ^ const_a));
   `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_Add,    ((rand_a + const_b) + const_a));
   `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_Mul,    ((rand_a * const_b) * const_a));
   `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_MulS,   ((srand_a * sconst_b) * sconst_a));
   `signal(FOLD_ASSOC_BINARY_RHS_OF_LHS_Concat, {{rand_a, const_b}, const_a});

   `signal(FOLD_SEL,              const_a[3:1]);

   `signal(SWAP_CONST_IN_COMMUTATIVE_BINARY, rand_a + const_a);
   `signal(SWAP_NOT_IN_COMMUTATIVE_BINARY, rand_a + ~rand_a);
   `signal(SWAP_VAR_IN_COMMUTATIVE_BINARY, rand_b + rand_a);
   `signal(PUSH_BITWISE_OP_THROUGH_CONCAT, 32'h12345678 ^ {8'h0, rand_a[23:0]});
   `signal(PUSH_BITWISE_OP_THROUGH_CONCAT_2, 32'h12345678 ^ {rand_b[7:0], rand_a[23:0]});
   `signal(PUSH_COMPARE_OP_THROUGH_CONCAT, 4'b1011 == {2'b10, rand_a[1:0]});
   `signal(PUSH_REDUCTION_THROUGH_COND_WITH_CONST_BRANCH, |(rand_a[32] ? rand_a[3:0] : 4'h0));
   `signal(REPLACE_REDUCTION_OF_CONST_AND, &const_a);
   `signal(REPLACE_REDUCTION_OF_CONST_OR,  |const_a);
   `signal(REPLACE_REDUCTION_OF_CONST_XOR, ^const_a);
   `signal(REPLACE_EXTEND, 4'(rand_a[0]));
   `signal(PUSH_NOT_THROUGH_COND, ~(rand_a[0] ? rand_a[4:0] : 5'hb));
   `signal(REMOVE_NOT_NOT, ~~rand_a);
   `signal(REPLACE_NOT_NEQ, ~(rand_a != rand_b));
   `signal(REPLACE_NOT_EQ, ~(srand_a == srand_b));
   `signal(REPLACE_NOT_OF_CONST, ~4'd0);
   `signal(REPLACE_AND_OF_NOT_AND_NOT, ~rand_a[1] & ~rand_b[1]);
   `signal(REPLACE_AND_OF_NOT_AND_NEQ, ~rand_a[2] & (rand_b != 64'd2));
   `signal(REPLACE_AND_OF_CONST_AND_CONST, const_a & const_b);
   `signal(REPLACE_AND_WITH_ZERO, 64'd0 & rand_a);
   `signal(REMOVE_AND_WITH_ONES, -64'd1 & rand_a);
   `signal(REPLACE_CONTRADICTORY_AND, rand_a & ~rand_a);
   `signal(REPLACE_OR_OF_NOT_AND_NOT, ~rand_a[3] | ~rand_b[3]);
   `signal(REPLACE_OR_OF_NOT_AND_NEQ, ~rand_a[4] | (rand_b != 64'd3));
   `signal(REPLACE_OR_OF_CONCAT_ZERO_LHS_AND_CONCAT_RHS_ZERO, {2'd0, rand_a[1:0]} | {rand_b[1:0], 2'd0});
   `signal(REPLACE_OR_OF_CONCAT_LHS_ZERO_AND_CONCAT_ZERO_RHS, {rand_a[1:0], 2'd0} | {2'd0, rand_b[1:0]});
   `signal(REPLACE_OR_OF_CONST_AND_CONST, const_a | const_b);
   `signal(REMOVE_OR_WITH_ZERO, 64'd0 | rand_a);
   `signal(REPLACE_OR_WITH_ONES, -64'd1 | rand_a);
   `signal(REPLACE_TAUTOLOGICAL_OR, rand_a | ~rand_a);
   `signal(REMOVE_SUB_ZERO, rand_a - 64'd0);
   `signal(REPLACE_SUB_WITH_NOT, rand_a[0] - 1'b1);
   `signal(REMOVE_REDUNDANT_ZEXT_ON_RHS_OF_SHIFT, rand_a << {2'b0, rand_a[2:0]});
   `signal(REPLACE_EQ_OF_CONST_AND_CONST, 4'd0 == 4'd1);
   `signal(REMOVE_FULL_WIDTH_SEL, rand_a[63:0]);
   `signal(REMOVE_SEL_FROM_RHS_OF_CONCAT, rand_ba[63:0]);
   `signal(REMOVE_SEL_FROM_LHS_OF_CONCAT, rand_ba[127:64]);
   `signal(PUSH_SEL_THROUGH_CONCAT, rand_ba[120:0]);
   `signal(PUSH_SEL_THROUGH_REPLICATE, rand_aa[0]);
   `signal(REPLACE_SEL_FROM_CONST, const_a[2]);
   `signal(REPLACE_CONCAT_OF_CONSTS, {const_a, const_b});
   `signal(REPLACE_CONCAT_ZERO_AND_SEL_TOP_WITH_SHIFTR, {62'd0, rand_a[63:62]});
   `signal(REPLACE_CONCAT_SEL_BOTTOM_AND_ZERO_WITH_SHIFTL, {rand_a[1:0], 62'd0});
   `signal(PUSH_CONCAT_THROUGH_NOTS, {~(rand_a+64'd101), ~(rand_b+64'd101)} );
   `signal(REMOVE_CONCAT_OF_ADJOINING_SELS, {rand_a[10:3], rand_a[2:1]});
   `signal(REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_LHS_CAT, {rand_a[2:1], rand_b});
   `signal(REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_RHS_CAT, {rand_b, rand_a[10:3]});
   `signal(REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_LHS, {rand_a[10:3], {rand_a[2:1], rand_b}});
   `signal(REPLACE_NESTED_CONCAT_OF_ADJOINING_SELS_ON_RHS, {{rand_b, rand_a[10:3]}, rand_a[2:1]});
   `signal(REMOVE_COND_WITH_FALSE_CONDITION, 1'd0 ? rand_a : rand_b);
   `signal(REMOVE_COND_WITH_TRUE_CONDITION, 1'd1 ? rand_a : rand_b);
   `signal(SWAP_COND_WITH_NOT_CONDITION, (~rand_a[0] & 1'd1) ? rand_a : rand_b);
   `signal(SWAP_COND_WITH_NEQ_CONDITION, rand_b != rand_a ? rand_a : rand_b);
   `signal(PULL_NOTS_THROUGH_COND, rand_a[0] ? ~rand_a[4:0] : ~rand_b[4:0]);
   `signal(REPLACE_COND_WITH_THEN_BRANCH_ZERO, rand_a[0] ? 1'd0 : rand_a[1]);
   `signal(REPLACE_COND_WITH_THEN_BRANCH_ONES, rand_a[0] ? 1'd1 : rand_a[1]);
   `signal(REPLACE_COND_WITH_ELSE_BRANCH_ZERO, rand_a[0] ? rand_a[1] : 1'd0);
   `signal(REPLACE_COND_WITH_ELSE_BRANCH_ONES, rand_a[0] ? rand_a[1] : 1'd1);
   `signal(INLINE_ARRAYSEL, array[0]);
   `signal(PUSH_BITWISE_THROUGH_REDUCTION_AND, (&(rand_a + 64'd105)) & (&(rand_b + 64'd108)));
   `signal(PUSH_BITWISE_THROUGH_REDUCTION_OR,  (|(rand_a + 64'd106)) | (|(rand_b + 64'd109)));
   `signal(PUSH_BITWISE_THROUGH_REDUCTION_XOR, (^(rand_a + 64'd107)) ^ (^(rand_b + 64'd110)));
   `signal(PUSH_REDUCTION_THROUGH_CONCAT_AND, &{1'd1, rand_b});
   `signal(PUSH_REDUCTION_THROUGH_CONCAT_OR,  |{1'd1, rand_b});
   `signal(PUSH_REDUCTION_THROUGH_CONCAT_XOR, ^{1'd1, rand_b});
   `signal(REMOVE_WIDTH_ONE_REDUCTION_AND, &rand_a[0]);
   `signal(REMOVE_WIDTH_ONE_REDUCTION_OR,  |rand_a[0]);
   `signal(REMOVE_WIDTH_ONE_REDUCTION_XOR, ^rand_a[0]);
   `signal(REMOVE_XOR_WITH_ZERO, 64'd0 ^ rand_a);
   `signal(REMOVE_XOR_WITH_ONES, -64'd1 ^ rand_a);
   `signal(REPLACE_COND_DEC, randbit_a ? rand_b - 64'b1 : rand_b);
   `signal(REPLACE_COND_INC, randbit_a ? rand_b + 64'b1 : rand_b);
   `signal(NO_REPLACE_COND_DEC, randbit_a ? rand_b - 64'hf000000000000000 : rand_b);
   `signal(NO_REPLACE_COND_INC, randbit_a ? rand_b + 64'hf000000000000000 : rand_b);
   `signal(RIGHT_LEANING_ASSOC, (((rand_a + rand_b) + rand_a) + rand_b));
   `signal(RIGHT_LEANING_CONCET, {{{rand_a, rand_b}, rand_a}, rand_b});

   // Operators that should work wiht mismatched widths
   `signal(MISMATCHED_ShiftL,const_a << 4'd2);
   `signal(MISMATCHED_ShiftR,const_a >> 4'd2);
   `signal(MISMATCHED_ShiftRS, const_a >> 4'd2);
   `signal(MISMATCHED_PowUU, rand_a ** 4'd5);
   `signal(MISMATCHED_PowSS, srand_a ** 4'sd5);
   `signal(MISMATCHED_PowSU, srand_b ** 4'd5);
   `signal(MISMATCHED_PowUS, rand_b ** 4'sd5);

   // Some selects need extra temporaries
   wire [63:0] sel_from_cond = rand_a[0] ? rand_a : const_a;
   wire [63:0] sel_from_shiftl = rand_a << 10;
   wire [31:0] sel_from_sel = rand_a[10+:32];

   `signal(PUSH_SEL_THROUGH_COND, sel_from_cond[2]);
   `signal(PUSH_SEL_THROUGH_SHIFTL, sel_from_shiftl[20:0]);
   `signal(REPLACE_SEL_FROM_SEL, sel_from_sel[4:3]);

   // Sel from not requires the operand to have a sinle sink, so can't use
   // the chekc due to the raw expression referencing the operand
   wire [63:0] sel_from_not_tmp = ~(rand_a >> rand_b[2:0] << rand_a[3:0]);
   wire        sel_from_not = sel_from_not_tmp[2];
   always @(posedge randbit_a) if ($c(0)) $display(sel_from_not); // Do not remove signal

   // Assigned at the end to avoid inlining by other passes
   assign const_a  = 64'h0123456789abcdef;
   assign const_b  = 64'h98badefc10325647;
   assign sconst_a = 64'hfedcba9876543210;
   assign sconst_b = 64'hba0123456789cdef;
endmodule
