@@ -744,6 +744,16 @@ def emit_assignments(case, cond):
744
744
emit_assignments (proc , _nir .Net .from_const (1 ))
745
745
assert pos == len (cell .assignments )
746
746
747
+ def shorten_operand (self , value , * , signed ):
748
+ value = list (value )
749
+ if signed :
750
+ while len (value ) > 1 and value [- 1 ] == value [- 2 ]:
751
+ value .pop ()
752
+ else :
753
+ while len (value ) > 0 and value [- 1 ] == _nir .Net .from_const (0 ):
754
+ value .pop ()
755
+ return _nir .Value (value )
756
+
747
757
def emit_operator (self , cell_idx , cell ):
748
758
UNARY_OPERATORS = {
749
759
"-" : "$neg" ,
@@ -782,17 +792,75 @@ def emit_operator(self, cell_idx, cell):
782
792
if len (cell .inputs ) == 1 :
783
793
cell_type = UNARY_OPERATORS [cell .operator ]
784
794
operand , = cell .inputs
795
+ signed = False
796
+ if cell .operator == "-" :
797
+ # For arithmetic operands, we trim the extra sign or zero extension on the operands
798
+ # to make the output prettier, and to fix inference problems in some not very smart
799
+ # synthesis tools.
800
+ operand_u = self .shorten_operand (operand , signed = False )
801
+ operand_s = self .shorten_operand (operand , signed = True )
802
+ # The operator will work when lowered with either signedness. Pick whichever
803
+ # is prettier.
804
+ if len (operand_s ) < len (operand_u ):
805
+ signed = True
806
+ operand = operand_s
807
+ else :
808
+ signed = False
809
+ operand = operand_u
785
810
self .builder .cell (cell_type , ports = {
786
811
"A" : self .sigspec (operand ),
787
812
"Y" : self .cell_wires [cell_idx ].name
788
813
}, parameters = {
789
- "A_SIGNED" : False ,
814
+ "A_SIGNED" : signed ,
790
815
"A_WIDTH" : len (operand ),
791
816
"Y_WIDTH" : cell .width ,
792
817
}, src_loc = cell .src_loc )
793
818
elif len (cell .inputs ) == 2 :
794
819
cell_type , a_signed , b_signed = BINARY_OPERATORS [cell .operator ]
795
820
operand_a , operand_b = cell .inputs
821
+ if cell .operator in ("+" , "-" , "*" , "==" , "!=" ):
822
+ # Arithmetic operators that will work with any signedness, but we have to choose
823
+ # a common one for both operands. Prefer signed in case of mixed signedness.
824
+ operand_a_u = self .shorten_operand (operand_a , signed = False )
825
+ operand_b_u = self .shorten_operand (operand_b , signed = False )
826
+ operand_a_s = self .shorten_operand (operand_a , signed = True )
827
+ operand_b_s = self .shorten_operand (operand_b , signed = True )
828
+ if operand_a .is_const :
829
+ # In case of constant operand, choose whichever shortens the other one better.
830
+ signed = len (operand_b_s ) < len (operand_b_u )
831
+ elif operand_b .is_const :
832
+ signed = len (operand_a_s ) < len (operand_a_u )
833
+ elif (len (operand_a_s ) < len (operand_a ) and len (operand_a_u ) == len (operand_a )):
834
+ # Operand A can only be shortened by signed. Pick it.
835
+ signed = True
836
+ elif (len (operand_b_s ) < len (operand_b ) and len (operand_b_u ) == len (operand_b )):
837
+ # Operand B can only be shortened by signed. Pick it.
838
+ signed = True
839
+ else :
840
+ # Otherwise, use unsigned shortening.
841
+ signed = False
842
+ if signed :
843
+ operand_a = operand_a_s
844
+ operand_b = operand_b_s
845
+ else :
846
+ operand_a = operand_a_u
847
+ operand_b = operand_b_u
848
+ a_signed = b_signed = signed
849
+ if cell .operator [0 ] in "us" :
850
+ # Signedness forced, just shorten.
851
+ operand_a = self .shorten_operand (operand_a , signed = a_signed )
852
+ operand_b = self .shorten_operand (operand_b , signed = b_signed )
853
+ if cell .operator == "<<" :
854
+ # We can pick the signedness for left operand, but right is fixed.
855
+ operand_a_u = self .shorten_operand (operand_a , signed = False )
856
+ operand_a_s = self .shorten_operand (operand_a , signed = True )
857
+ if len (operand_a_s ) < len (operand_a_u ):
858
+ a_signed = True
859
+ operand_a = operand_a_s
860
+ else :
861
+ a_signed = False
862
+ operand_a = operand_a_u
863
+ operand_b = self .shorten_operand (operand_b , signed = b_signed )
796
864
if cell .operator in ("u//" , "s//" , "u%" , "s%" ):
797
865
result = self .builder .wire (cell .width )
798
866
self .builder .cell (cell_type , ports = {
0 commit comments