Commit 103db674 by Zachary Snow

constant folding for size casts of number literals

- standardize number casting
- fix extension of casts of unsized literals to 32 bits
parent 3eefd03c
......@@ -109,22 +109,12 @@ traverseExprM other =
traverseSinglyNestedExprsM traverseExprM other
convertCastM :: Expr -> Expr -> Bool -> ST Expr
convertCastM (RawNum size) (RawNum val) signed =
return $ Number $ Decimal (fromIntegral size) signed val'
where val' = val `mod` (2 ^ size)
convertCastM (RawNum size) (Number (Based 1 True Binary a b)) signed =
return $ Number $ Based (fromIntegral size) signed Binary
(val * a) (val * b)
where val = (2 ^ size) - 1
convertCastM (RawNum size) (Number (UnbasedUnsized bit)) signed =
convertCastM (RawNum size) (Number num) signed
where
num = Based 1 True Binary a b
(a, b) = case bit of
Bit0 -> (0, 0)
Bit1 -> (1, 0)
BitX -> (0, 1)
BitZ -> (1, 1)
convertCastM (Number size) (Number value) signed =
return $ Number $
case numberToInteger size of
Just size' -> numberCast signed (fromIntegral size') value
Nothing -> error $ "size cast width " ++ show size
++ " is not an integer"
convertCastM size value signed = do
value' <- traverseExprM value
useFn <- embedScopes canUseCastFn size
......
......@@ -391,10 +391,8 @@ typeCastUnneeded t1 t2 =
-- explicitly sizes top level numbers used in arithmetic expressions
makeExplicit :: Expr -> Expr
makeExplicit (Number (Decimal size signed values)) =
Number $ Decimal (abs size) signed values
makeExplicit (Number (Based size base signed values kinds)) =
Number $ Based (abs size) base signed values kinds
makeExplicit (Number n) =
Number $ numberCast (numberIsSigned n) (fromIntegral $ numberBitLength n) n
makeExplicit (BinOp op e1 e2) =
BinOp op (makeExplicit e1) (makeExplicit e2)
makeExplicit (UniOp op e) =
......
......@@ -13,6 +13,7 @@ module Language.SystemVerilog.AST.Number
, numberIsSigned
, numberIsSized
, numberToInteger
, numberCast
, bitToVK
) where
......@@ -332,10 +333,7 @@ instance Semigroup Number where
where
size = size1 + size2
signed = False
base =
if kinds1 == 0 && kinds2 == 0
then min base1 base2
else Binary
base = selectBase (min base1 base2) values kinds
trim = flip mod . (2 ^)
values = trim size2 values2 + shiftL (trim size1 values1) size2
kinds = trim size2 kinds2 + shiftL (trim size1 kinds1) size2
......@@ -351,3 +349,67 @@ instance Semigroup Number where
Based size signed Hex num 0
toBased (UnbasedUnsized bit) =
uncurry (Based 1 False Binary) (bitToVK bit)
-- size cast raw bits with optional sign extension
rawCast :: Bool -> Int -> Int -> Integer -> Integer
rawCast signed inSize outSize val =
if outSize <= inSize then
val `mod` (2 ^ outSize)
else if signed && val >= 2 ^ (inSize - 1) then
valTrim + 2 ^ outSize - 2 ^ inSize
else
valTrim
where valTrim = val `mod` (2 ^ inSize)
-- check if the based number is valid under the given base
checkBase :: Integer -> Integer -> Integer -> Bool
checkBase _ _ 0 = True
checkBase base v k =
-- kind bits in this chunk must all be the same
(rK == 0 || rK == base - 1) &&
-- if the X/Z, it must be all X or all Z
(rK == 0 || rV == 0 || rV == base - 1) &&
-- check the next chunk
checkBase base qV qK
where
(qV, rV) = v `divMod` base
(qK, rK) = k `divMod` base
-- select the maximal valid base
selectBase :: Base -> Integer -> Integer -> Base
selectBase Binary _ _ = Binary
selectBase Octal v k =
if checkBase 8 v k
then Octal
else Binary
selectBase Hex v k =
if checkBase 16 v k
then Hex
else selectBase Octal v k
-- utility for size and/or sign casting a number
numberCast :: Bool -> Int -> Number -> Number
numberCast outSigned outSize (Decimal inSizeRaw inSigned inVal) =
Decimal outSize outSigned outVal
where
inSize = abs inSizeRaw
outVal = rawCast inSigned inSize outSize inVal
numberCast outSigned outSize (Based inSizeRaw inSigned inBase inVal inKnd) =
Based outSize outSigned outBase outVal outKnd
where
inSize = abs inSizeRaw
-- sign extend signed inputs, or unsized literals with a leading X/Z
doExtend = inSigned || inKnd >= 2 ^ (inSize - 1) && inSizeRaw < 0
outVal = rawCast doExtend inSize outSize inVal
outKnd = rawCast doExtend inSize outSize inKnd
-- note that we could try patching the upper bits of the result to allow
-- the use of a higher base as in 5'(6'ozx), but this should be rare
outBase = selectBase inBase outVal outKnd
numberCast signed size (UnbasedUnsized bit) =
numberCast signed size $
uncurry (Based 1 True Binary) $
case bit of
Bit0 -> (0, 0)
Bit1 -> (1, 0)
BitX -> (0, 1)
BitZ -> (1, 1)
`define TEST(size, literal) \
$display(`"size'(literal) = %b`", size'(literal));
module top;
initial begin
`include "cast_literal.vh"
end
endmodule
`define TEST(size, literal) \
tmp``size = literal; \
$display(`"size'(literal) = %b`", tmp``size);
module top;
initial begin : blk
reg [0:0] tmp1; reg [1:0] tmp2; reg [2:0] tmp3; reg [3:0] tmp4; reg [4:0] tmp5;
reg [5:0] tmp6; reg [6:0] tmp7; reg [7:0] tmp8; reg [8:0] tmp9; reg [9:0] tmp10;
reg [10:0] tmp11; reg [11:0] tmp12; reg [12:0] tmp13; reg [13:0] tmp14; reg [14:0] tmp15;
reg [15:0] tmp16; reg [16:0] tmp17; reg [17:0] tmp18; reg [18:0] tmp19; reg [19:0] tmp20;
reg [20:0] tmp21; reg [21:0] tmp22; reg [22:0] tmp23; reg [23:0] tmp24; reg [24:0] tmp25;
reg [25:0] tmp26; reg [26:0] tmp27; reg [27:0] tmp28; reg [28:0] tmp29; reg [29:0] tmp30;
reg [30:0] tmp31; reg [31:0] tmp32; reg [32:0] tmp33; reg [33:0] tmp34; reg [34:0] tmp35;
`include "cast_literal.vh"
end
endmodule
`define TEST_ALL(literal) \
`TEST(1, literal) `TEST(2, literal) `TEST(3, literal) `TEST(4, literal) `TEST(5, literal) \
`TEST(6, literal) `TEST(7, literal) `TEST(8, literal) `TEST(9, literal) `TEST(10, literal) \
`TEST(11, literal) `TEST(12, literal) `TEST(13, literal) `TEST(14, literal) `TEST(15, literal) \
`TEST(16, literal) `TEST(17, literal) `TEST(18, literal) `TEST(19, literal) `TEST(20, literal) \
`TEST(21, literal) `TEST(22, literal) `TEST(23, literal) `TEST(24, literal) `TEST(25, literal) \
`TEST(26, literal) `TEST(27, literal) `TEST(28, literal) `TEST(29, literal) `TEST(30, literal) \
`TEST(31, literal) `TEST(32, literal) `TEST(33, literal) `TEST(34, literal) `TEST(35, literal)
`TEST_ALL('d1)
`TEST_ALL('sd1)
`TEST_ALL(1'sd1)
`TEST_ALL(32'sd1)
`TEST_ALL('d123)
`TEST_ALL('sd123)
`TEST_ALL(14'sd123)
`TEST_ALL(15'sd123)
`TEST_ALL('b1)
`TEST_ALL('sb1)
`TEST_ALL('b10)
`TEST_ALL('sb10)
`TEST_ALL(1'b1)
`TEST_ALL(1'sb1)
`TEST_ALL(2'sb1)
`TEST_ALL(2'sb11)
`TEST_ALL(1'sbx)
`TEST_ALL(2'sbx)
`TEST_ALL(2'sb0x)
`TEST_ALL(2'sbx1)
`TEST_ALL(2'sbz0)
`TEST_ALL(1'so1)
`TEST_ALL(2'so1)
`TEST_ALL(4'so11)
`TEST_ALL(1'sox)
`TEST_ALL(2'sox)
`TEST_ALL(4'so0x)
`TEST_ALL(4'sox1)
`TEST_ALL(4'soz0)
`TEST_ALL(5'so0x)
`TEST_ALL(5'sox1)
`TEST_ALL(5'soz0)
`TEST_ALL(6'so0x)
`TEST_ALL(6'sox1)
`TEST_ALL(6'soz0)
`TEST_ALL(7'so0x)
`TEST_ALL(7'sox1)
`TEST_ALL(7'soz0)
`TEST_ALL('bx)
`TEST_ALL('ozx)
`TEST_ALL('hxz)
`TEST_ALL(1'bx)
`TEST_ALL(5'ozx)
`TEST_ALL(6'ozx)
`TEST_ALL(7'hxz)
`TEST_ALL('bzzz1)
`TEST_ALL('ozzz1)
`TEST_ALL('hzzz1)
`TEST_ALL(1'ox)
`TEST_ALL(1'oz)
`TEST_ALL(4'ox0)
`TEST_ALL(4'ox1)
`TEST_ALL(4'ox2)
`TEST_ALL(4'ox3)
`TEST_ALL(4'ox4)
`TEST_ALL(4'ox5)
`TEST_ALL(4'ox6)
`TEST_ALL(4'ox7)
`TEST_ALL(4'oxx)
`TEST_ALL(4'oxz)
`TEST_ALL(4'oz0)
`TEST_ALL(4'oz1)
`TEST_ALL(4'oz2)
`TEST_ALL(4'oz3)
`TEST_ALL(4'oz4)
`TEST_ALL(4'oz5)
`TEST_ALL(4'oz6)
`TEST_ALL(4'oz7)
`TEST_ALL(4'ozx)
`TEST_ALL(4'ozz)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment