@@ -561,6 +561,33 @@ constant_exprt verilog_typecheck_exprt::right(const exprt &expr)
561561
562562/* ******************************************************************\
563563
564+ Function: verilog_typecheck_exprt::countones
565+
566+ Inputs:
567+
568+ Outputs:
569+
570+ Purpose:
571+
572+ \*******************************************************************/
573+
574+ constant_exprt verilog_typecheck_exprt::countones (const constant_exprt &expr)
575+ {
576+ // lower to popcount and try simplifier
577+ auto simplified =
578+ simplify_expr (popcount_exprt{expr, verilog_int_typet{}.lower ()}, ns);
579+
580+ if (!simplified.is_constant ())
581+ {
582+ throw errort{}.with_location (expr.source_location ())
583+ << " failed to simplify constant $countones" ;
584+ }
585+ else
586+ return to_constant_expr (simplified);
587+ }
588+
589+ /* ******************************************************************\
590+
564591Function: verilog_typecheck_exprt::increment
565592
566593 Inputs:
@@ -755,6 +782,19 @@ exprt verilog_typecheck_exprt::convert_system_function(
755782
756783 return std::move (expr);
757784 }
785+ else if (identifier == " $countones" ) // SystemVerilog
786+ {
787+ if (arguments.size () != 1 )
788+ {
789+ throw errort ().with_location (expr.source_location ())
790+ << " $countones takes one argument" ;
791+ }
792+
793+ // The return type is 'int'
794+ expr.type () = verilog_int_typet{}.lower ();
795+
796+ return std::move (expr);
797+ }
758798 else if (identifier==" $onehot" ) // SystemVerilog
759799 {
760800 if (arguments.size ()!=1 )
@@ -1586,6 +1626,17 @@ exprt verilog_typecheck_exprt::elaborate_constant_system_function_call(
15861626 DATA_INVARIANT (arguments.size () == 1 , " $increment has one argument" );
15871627 return increment (arguments[0 ]);
15881628 }
1629+ else if (identifier == " $countones" )
1630+ {
1631+ DATA_INVARIANT (arguments.size () == 1 , " $countones has one argument" );
1632+
1633+ auto op = elaborate_constant_expression (arguments[0 ]);
1634+
1635+ if (!op.is_constant ())
1636+ return std::move (expr); // give up
1637+
1638+ return countones (to_constant_expr (op));
1639+ }
15891640 else if (identifier == " $clog2" )
15901641 {
15911642 // the ceiling of the log with base 2 of the argument
0 commit comments