From 22df7336355b6a966957bffdfcd7239cbca9998d Mon Sep 17 00:00:00 2001 From: Alex McKenna Date: Mon, 31 Jan 2022 12:25:17 +0100 Subject: [PATCH] Don't warn about integer primitives in enum ops To prevent Clash from warning about integer primitives in HDL that originate from uses of fromEnum / toEnum in user code, the functions are now primitives for the sized types in Clash. --- ...2_23_39+01_00_spurious_integer_warnings.md | 1 + .../src-ghc/Clash/GHC/Evaluator/Primitive.hs | 76 ++++++++++++++++++- .../Clash_Sized_Internal_BitVector.primitives | 23 ++++++ .../Clash_Sized_Internal_Index.primitives | 16 ++++ .../Clash_Sized_Internal_Signed.primitives | 16 ++++ .../Clash_Sized_Internal_Unsigned.primitives | 16 ++++ .../Clash_Sized_Internal_BitVector.primitives | 24 ++++++ .../Clash_Sized_Internal_Index.primitives | 16 ++++ .../Clash_Sized_Internal_Signed.primitives | 16 ++++ .../Clash_Sized_Internal_Unsigned.primitives | 16 ++++ .../src/Clash/Sized/Internal/BitVector.hs | 29 ++++++- .../src/Clash/Sized/Internal/Index.hs | 20 ++++- .../src/Clash/Sized/Internal/Signed.hs | 19 ++++- .../src/Clash/Sized/Internal/Unsigned.hs | 20 ++++- tests/Main.hs | 9 +++ tests/shouldwork/Issues/T2046.hs | 55 ++++++++++++++ tests/shouldwork/Issues/T2046B.hs | 33 ++++++++ tests/shouldwork/Issues/T2046BType.hs | 11 +++ 18 files changed, 402 insertions(+), 14 deletions(-) create mode 100644 changelog/2022-01-31T12_23_39+01_00_spurious_integer_warnings.md create mode 100644 tests/shouldwork/Issues/T2046.hs create mode 100644 tests/shouldwork/Issues/T2046B.hs create mode 100644 tests/shouldwork/Issues/T2046BType.hs diff --git a/changelog/2022-01-31T12_23_39+01_00_spurious_integer_warnings.md b/changelog/2022-01-31T12_23_39+01_00_spurious_integer_warnings.md new file mode 100644 index 0000000000..efb35a4b7a --- /dev/null +++ b/changelog/2022-01-31T12_23_39+01_00_spurious_integer_warnings.md @@ -0,0 +1 @@ +CHANGED: toEnum/fromEnum on sized types is now less eager to report warnings about integer functions being used [#2046](https://github.com/clash-lang/clash-compiler/issues/2046). diff --git a/clash-ghc/src-ghc/Clash/GHC/Evaluator/Primitive.hs b/clash-ghc/src-ghc/Clash/GHC/Evaluator/Primitive.hs index ca6580ab53..aa7c5b3d93 100644 --- a/clash-ghc/src-ghc/Clash/GHC/Evaluator/Primitive.hs +++ b/clash-ghc/src-ghc/Clash/GHC/Evaluator/Primitive.hs @@ -2,7 +2,7 @@ Copyright : (C) 2013-2016, University of Twente, 2016-2017, Myrtle Software Ltd, 2017 , QBayLogic, Google Inc., - 2021 , QBayLogic B.V. + 2021-2022, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. -} @@ -1929,6 +1929,12 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of "Clash.Sized.Internal.BitVector.le##" | [(0,i),(0,j)] <- bitLiterals args -> reduce (boolToBoolLiteral tcm ty (i <= j)) +-- Enum + "Clash.Sized.Internal.BitVector.toEnum##" + | [i] <- intLiterals' args + -> let Bit msk val = BitVector.toEnum## (fromInteger i) + in reduce (mkBitLit ty (toInteger msk) (toInteger val)) + -- Bits "Clash.Sized.Internal.BitVector.and##" | [i,j] <- bitLiterals args @@ -2131,6 +2137,18 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of , Just val <- reifyNat kn (liftBitVector2Bool BitVector.le# ty tcm args) -> reduce val +-- Enum + + "Clash.Sized.Internal.BitVector.toEnum#" + | let resTyInfo@(_,_,kn) = extractTySizeInfo tcm ty tys + , Just val <- reifyNat kn (liftInteger2BitVector (BitVector.toEnum# . fromInteger) resTyInfo args) + -> reduce val + + "Clash.Sized.Internal.BitVector.fromEnum#" + | Just (_, kn) <- extractKnownNat tcm tys + , Just val <- reifyNat kn (liftBitVector2Int (toInteger . BitVector.fromEnum#) args) + -> reduce val + -- Bounded "Clash.Sized.Internal.BitVector.minBound#" | Just (nTy,len) <- extractKnownNat tcm tys @@ -2303,6 +2321,16 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of | Just (i,j) <- indexLiterals args -> reduce (boolToBoolLiteral tcm ty (i <= j)) +-- Enum + "Clash.Sized.Internal.Index.toEnum#" + | [i] <- intLiterals' args + , Just (nTy, mb) <- extractKnownNat tcm tys + -> reduce (mkIndexLit ty nTy mb i) + + "Clash.Sized.Internal.Index.fromEnum#" + | [i] <- indexLiterals' args + -> reduce (integerToIntLiteral i) + -- Bounded "Clash.Sized.Internal.Index.maxBound#" | Just (nTy,mb) <- extractKnownNat tcm tys @@ -2409,6 +2437,16 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of "Clash.Sized.Internal.Signed.le#" | Just (i,j) <- signedLiterals args -> reduce (boolToBoolLiteral tcm ty (i <= j)) +-- Enum + "Clash.Sized.Internal.Signed.toEnum#" + | [i] <- intLiterals' args + , Just (litTy, mb) <- extractKnownNat tcm tys + -> reduce (mkSignedLit ty litTy mb i) + + "Clash.Sized.Internal.Signed.fromEnum#" + | [i] <- signedLiterals' args + -> reduce (integerToIntLiteral i) + -- Bounded "Clash.Sized.Internal.Signed.minBound#" | Just (litTy,mb) <- extractKnownNat tcm tys @@ -2616,6 +2654,16 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of "Clash.Sized.Internal.Unsigned.le#" | Just (i,j) <- unsignedLiterals args -> reduce (boolToBoolLiteral tcm ty (i <= j)) +-- Enum + "Clash.Sized.Internal.Unsigned.toEnum#" + | [i] <- intLiterals' args + , Just (litTy, mb) <- extractKnownNat tcm tys + -> reduce (mkUnsignedLit ty litTy mb i) + + "Clash.Sized.Internal.Unsigned.fromEnum#" + | [i] <- unsignedLiterals' args + -> reduce (integerToIntLiteral i) + -- Bounded "Clash.Sized.Internal.Unsigned.minBound#" | Just (nTy,len) <- extractKnownNat tcm tys @@ -4403,6 +4451,32 @@ liftBitVector2Bool f ty tcm args _p in Just $ boolToBoolLiteral tcm ty val | otherwise = Nothing +liftInteger2BitVector + :: KnownNat n + => (Integer -> BitVector n) + -> (Type, Type, Integer) + -> [Value] + -> (Proxy n -> Maybe Term) +liftInteger2BitVector f resTyInfo args _p + | [i] <- intLiterals' args + = let BV msk val = f i + in Just (mkBitVectorLit' resTyInfo (toInteger msk) (toInteger val)) + + | otherwise + = Nothing + +liftBitVector2Int + :: KnownNat n + => (BitVector n -> Integer) + -> [Value] + -> (Proxy n -> Maybe Term) +liftBitVector2Int f args _p + | [i] <- bitVectorLiterals' args + = let val = f (toBV i) + in Just $ integerToIntLiteral val + | otherwise + = Nothing + liftSized2 :: (KnownNat n, Integral (sized n)) => ([Value] -> [Integer]) -- ^ literal argument extraction function diff --git a/clash-lib/prims/commonverilog/Clash_Sized_Internal_BitVector.primitives b/clash-lib/prims/commonverilog/Clash_Sized_Internal_BitVector.primitives index e29e95e3ac..37bc689085 100644 --- a/clash-lib/prims/commonverilog/Clash_Sized_Internal_BitVector.primitives +++ b/clash-lib/prims/commonverilog/Clash_Sized_Internal_BitVector.primitives @@ -91,6 +91,14 @@ , "template" : "~VAR[i][0][0] ? 1'bx : ~VAR[i][1][0]" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.BitVector.toEnum##" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "toEnum## :: Int -> Bit" + , "template" : "~ARG[0][0]" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.BitVector.and##" , "kind" : "Expression" @@ -167,6 +175,13 @@ , "templateFunction" : "Clash.Primitives.Sized.ToInteger.bvToIntegerVerilog" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.BitVector.fromEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "fromEnum# :: KnownNat n => BitVector n -> Int" + , "template" : "~IF~SIZE[~TYP[1]]~THEN~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$unsigned(~VAR[bv][1][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[bv][1]})~FI~ELSE~SIZE[~TYPO]'sd0~FI" } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.BitVector.size#" , "workInfo" : "Constant" @@ -287,6 +302,14 @@ , "template" : "~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[2]]]~THEN$unsigned(~VAR[i][2][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[2]]) {1'b0}},~VAR[i][2]})~FI" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.BitVector.toEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "toEnum# :: KnownNat n => Int -> BitVector n" + , "template" : "~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$unsigned(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[i][1]})~FI" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.BitVector.plus#" , "kind" : "Declaration" diff --git a/clash-lib/prims/commonverilog/Clash_Sized_Internal_Index.primitives b/clash-lib/prims/commonverilog/Clash_Sized_Internal_Index.primitives index 4b0a1480df..43fe884cbb 100644 --- a/clash-lib/prims/commonverilog/Clash_Sized_Internal_Index.primitives +++ b/clash-lib/prims/commonverilog/Clash_Sized_Internal_Index.primitives @@ -64,6 +64,22 @@ , "template" : "~ARG[0]-~SIZE[~TYPO]'d1" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Index.fromEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "fromEnum# :: KnownNat n => Index n -> Int" + , "template" : "~IF~SIZE[~TYP[1]]~THEN~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$unsigned(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[i][1]})~FI~ELSE~SIZE[~TYPO]'sd0~FI" + } + } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Index.toEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "toEnum# :: KnownNat n => Int -> Index n" + , "template" : "~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$unsigned(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[i][1]})~FI" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.Index.+#" , "kind" : "Expression" diff --git a/clash-lib/prims/commonverilog/Clash_Sized_Internal_Signed.primitives b/clash-lib/prims/commonverilog/Clash_Sized_Internal_Signed.primitives index 425dce5c71..71f38dfe1f 100644 --- a/clash-lib/prims/commonverilog/Clash_Sized_Internal_Signed.primitives +++ b/clash-lib/prims/commonverilog/Clash_Sized_Internal_Signed.primitives @@ -46,6 +46,14 @@ , "templateFunction" : "Clash.Primitives.Sized.ToInteger.signedToIntegerVerilog" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Signed.fromEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "fromEnum# :: KnownNat n => Signed n -> Int" + , "template" : "~IF~SIZE[~TYP[1]]~THEN~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$signed(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$signed({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[i][1]})~FI~ELSE~SIZE[~TYPO]'sd0~FI" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.Signed.size#" , "workInfo" : "Constant" @@ -117,6 +125,14 @@ , "template" : "~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$signed(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$signed({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[i][1]})~FI" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Signed.toEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "toEnum# :: KnownNat n => Int -> Signed n" + , "template" : "~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$signed(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$signed({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[i][1]})~FI" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.Signed.plus#" , "kind" : "Declaration" diff --git a/clash-lib/prims/commonverilog/Clash_Sized_Internal_Unsigned.primitives b/clash-lib/prims/commonverilog/Clash_Sized_Internal_Unsigned.primitives index 0be2c82f08..e4fef99059 100644 --- a/clash-lib/prims/commonverilog/Clash_Sized_Internal_Unsigned.primitives +++ b/clash-lib/prims/commonverilog/Clash_Sized_Internal_Unsigned.primitives @@ -46,6 +46,14 @@ , "templateFunction" : "Clash.Primitives.Sized.ToInteger.unsignedToIntegerVerilog" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Unsigned.fromEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "fromEnum# :: KnownNat n => Unsigned n -> Int" + , "template" : "~IF~SIZE[~TYP[1]]~THEN~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$unsigned(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[i][1]})~FI~ELSE~SIZE[~TYPO]'sd0~FI" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.Unsigned.size#" , "workInfo" : "Constant" @@ -108,6 +116,14 @@ , "template" : "~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$unsigned(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[i][1]})~FI" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Unsigned.toEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "toEnum# :: KnownNat n => Int -> Unsigned n" + , "template" : "~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$unsigned(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$unsigned({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) {1'b0}},~VAR[i][1]})~FI" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.Unsigned.plus#" , "kind" : "Declaration" diff --git a/clash-lib/prims/vhdl/Clash_Sized_Internal_BitVector.primitives b/clash-lib/prims/vhdl/Clash_Sized_Internal_BitVector.primitives index 62090cec74..8529ef9ceb 100644 --- a/clash-lib/prims/vhdl/Clash_Sized_Internal_BitVector.primitives +++ b/clash-lib/prims/vhdl/Clash_Sized_Internal_BitVector.primitives @@ -86,6 +86,14 @@ , "template" : "~IF~LIT[0]~THEN'U'~ELSE~ARG[1](0)~FI" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.BitVector.toEnum##" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "toEnum## :: Int -> Bit" + , "template" : "~ARG[0](0)" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.BitVector.and##" , "kind" : "Expression" @@ -457,6 +465,22 @@ end process; , "template" : "std_logic_vector(resize(unsigned(std_logic_vector(~ARG[2])),~SIZE[~TYPO]))" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.BitVector.toEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "toEnum# :: KnownNat n => Int -> BitVector n" + , "template" : "std_logic_vector(resize(unsigned(std_logic_vector(~ARG[1])),~SIZE[~TYPO]))" + } + } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.BitVector.fromEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "fromEnum# :: KnownNat n => BitVector n -> Int" + , "template" : "~IF~SIZE[~TYP[1]]~THENsigned(std_logic_vector(resize(unsigned(~ARG[1]),~SIZE[~TYPO])))~ELSEto_signed(0,~SIZE[~TYPO])~FI" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.BitVector.plus#" , "kind" : "Expression" diff --git a/clash-lib/prims/vhdl/Clash_Sized_Internal_Index.primitives b/clash-lib/prims/vhdl/Clash_Sized_Internal_Index.primitives index e9f43c38dd..0251e358d3 100644 --- a/clash-lib/prims/vhdl/Clash_Sized_Internal_Index.primitives +++ b/clash-lib/prims/vhdl/Clash_Sized_Internal_Index.primitives @@ -64,6 +64,22 @@ , "template" : "to_unsigned(~LIT[0]-1,~SIZE[~TYPO])" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Index.toEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "toEnum# :: KnownNat n => Int -> Index n" + , "template" : "resize(unsigned(std_logic_vector(~ARG[1])),~SIZE[~TYPO])" + } + } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Index.fromEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "fromEnum# :: KnownNat n => Index n -> Int" + , "template" : "~IF~SIZE[~TYP[1]]~THENsigned(std_logic_vector(resize(~ARG[1],~SIZE[~TYPO])))~ELSEto_signed(0,~SIZE[~TYPO])~FI" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.Index.+#" , "kind" : "Expression" diff --git a/clash-lib/prims/vhdl/Clash_Sized_Internal_Signed.primitives b/clash-lib/prims/vhdl/Clash_Sized_Internal_Signed.primitives index 935c596c6e..5a55793f4f 100644 --- a/clash-lib/prims/vhdl/Clash_Sized_Internal_Signed.primitives +++ b/clash-lib/prims/vhdl/Clash_Sized_Internal_Signed.primitives @@ -112,6 +112,22 @@ , "templateFunction" : "Clash.Primitives.Sized.Signed.fromIntegerTF" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Signed.toEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "toEnum# :: KnownNat n => Int -> Signed n" + , "template" : "resize(signed(std_logic_vector(~ARG[1])),~SIZE[~TYPO])" + } + } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Signed.fromEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "fromEnum# :: KnownNat n => Signed n -> Int" + , "template" : "~IF~SIZE[~TYP[1]]~THENresize(~ARG[1],~SIZE[~TYPO])~ELSEto_signed(0,~SIZE[~TYPO])~FI" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.Signed.plus#" , "kind" : "Expression" diff --git a/clash-lib/prims/vhdl/Clash_Sized_Internal_Unsigned.primitives b/clash-lib/prims/vhdl/Clash_Sized_Internal_Unsigned.primitives index c92dc0e946..0d7b215155 100644 --- a/clash-lib/prims/vhdl/Clash_Sized_Internal_Unsigned.primitives +++ b/clash-lib/prims/vhdl/Clash_Sized_Internal_Unsigned.primitives @@ -102,6 +102,22 @@ , "template" : "resize(unsigned(std_logic_vector(~ARG[1])),~LIT[0])" } } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Unsigned.toEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "toEnum# :: KnownNat n => Int -> Unsigned n" + , "template" : "resize(unsigned(std_logic_vector(~ARG[1])),~SIZE[~TYPO])" + } + } +, { "BlackBox" : + { "name" : "Clash.Sized.Internal.Unsigned.fromEnum#" + , "workInfo" : "Never" + , "kind" : "Expression" + , "type" : "fromEnum# :: KnownNat n => Unsigned n -> Int" + , "template" : "~IF~SIZE[~TYP[1]]~THENsigned(std_logic_vector(resize(~ARG[1],~SIZE[~TYPO])))~ELSEto_signed(0,~SIZE[~TYPO])~FI" + } + } , { "BlackBox" : { "name" : "Clash.Sized.Internal.Unsigned.plus#" , "kind" : "Expression" diff --git a/clash-prelude/src/Clash/Sized/Internal/BitVector.hs b/clash-prelude/src/Clash/Sized/Internal/BitVector.hs index 7c7ed5fbd0..a25811b40d 100644 --- a/clash-prelude/src/Clash/Sized/Internal/BitVector.hs +++ b/clash-prelude/src/Clash/Sized/Internal/BitVector.hs @@ -2,7 +2,7 @@ Copyright : (C) 2013-2016, University of Twente, 2019 , Gergő Érdi 2016-2019, Myrtle Software Ltd, - 2021 , QBayLogic B.V. + 2021-2022, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. -} @@ -38,6 +38,8 @@ module Clash.Sized.Internal.BitVector , ge## , gt## , le## + -- *** Enum + , toEnum## -- *** Num , fromInteger## -- *** Bits @@ -80,6 +82,9 @@ module Clash.Sized.Internal.BitVector , ge# , gt# , le# + -- *** Enum + , toEnum# + , fromEnum# -- *** Enum (not synthesizable) , enumFrom# , enumFromThen# @@ -178,6 +183,7 @@ import Test.QuickCheck.Arbitrary (Arbitrary (..), CoArbitrary (..), arbitraryBoundedIntegral, coarbitraryIntegral, shrinkIntegral) +import Clash.Annotations.Primitive (hasBlackBox) import Clash.Class.Num (ExtendingNum (..), SaturatingNum (..), SaturationMode (..)) import Clash.Class.Resize (Resize (..)) @@ -306,9 +312,14 @@ le## b1 b2 = le# (pack# b1) (pack# b2) {-# NOINLINE le## #-} instance Enum Bit where - toEnum = fromInteger## 0## . toInteger + toEnum = toEnum## fromEnum b = if eq## b low then 0 else 1 +toEnum## :: Int -> Bit +toEnum## = fromInteger## 0## . toInteger +{-# NOINLINE toEnum## #-} +{-# ANN toEnum## hasBlackBox #-} + instance Bounded Bit where minBound = low maxBound = high @@ -537,13 +548,23 @@ le# bv1 bv2 = undefErrorI "<=" bv1 bv2 instance KnownNat n => Enum (BitVector n) where succ = (+# fromInteger# 0 1) pred = (-# fromInteger# 0 1) - toEnum = fromInteger# 0 . toInteger - fromEnum = fromEnum . toInteger# + toEnum = toEnum# + fromEnum = fromEnum# enumFrom = enumFrom# enumFromThen = enumFromThen# enumFromTo = enumFromTo# enumFromThenTo = enumFromThenTo# +toEnum# :: forall n. KnownNat n => Int -> BitVector n +toEnum# = fromInteger# 0 . toInteger +{-# NOINLINE toEnum# #-} +{-# ANN toEnum# hasBlackBox #-} + +fromEnum# :: forall n. KnownNat n => BitVector n -> Int +fromEnum# = fromEnum . toInteger# +{-# NOINLINE fromEnum# #-} +{-# ANN fromEnum# hasBlackBox #-} + enumFrom# :: forall n. KnownNat n => BitVector n -> [BitVector n] enumFrom# (BV 0 x) = map (BV 0 . (`mod` m)) [x .. unsafeToNatural (maxBound :: BitVector n)] #if MIN_VERSION_base(4,15,0) diff --git a/clash-prelude/src/Clash/Sized/Internal/Index.hs b/clash-prelude/src/Clash/Sized/Internal/Index.hs index 34e9d2e3fa..6fc5e92cec 100644 --- a/clash-prelude/src/Clash/Sized/Internal/Index.hs +++ b/clash-prelude/src/Clash/Sized/Internal/Index.hs @@ -1,7 +1,7 @@ {-| Copyright : (C) 2013-2016, University of Twente, 2016-2019, Myrtle Software Ltd, - 2021 , QBayLogic B.V. + 2021-2022, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. -} @@ -42,6 +42,9 @@ module Clash.Sized.Internal.Index , ge# , gt# , le# + -- ** Enum + , toEnum# + , fromEnum# -- ** Enum (not synthesizable) , enumFrom# , enumFromThen# @@ -98,6 +101,7 @@ import Test.QuickCheck.Arbitrary (Arbitrary (..), CoArbitrary (..), arbitraryBoundedIntegral, coarbitraryIntegral, shrinkIntegral) +import Clash.Annotations.Primitive (hasBlackBox) import Clash.Class.BitPack.Internal (BitPack (..), packXWith) import Clash.Class.Num (ExtendingNum (..), SaturatingNum (..), SaturationMode (..)) @@ -222,13 +226,23 @@ le# (I n) (I m) = n <= m instance KnownNat n => Enum (Index n) where succ = (+# fromInteger# 1) pred = (-# fromInteger# 1) - toEnum = fromInteger# . toInteger - fromEnum = fromEnum . toInteger# + toEnum = toEnum# + fromEnum = fromEnum# enumFrom = enumFrom# enumFromThen = enumFromThen# enumFromTo = enumFromTo# enumFromThenTo = enumFromThenTo# +toEnum# :: forall n. KnownNat n => Int -> Index n +toEnum# = fromInteger# . toInteger +{-# NOINLINE toEnum# #-} +{-# ANN toEnum# hasBlackBox #-} + +fromEnum# :: forall n. KnownNat n => Index n -> Int +fromEnum# = fromEnum . toInteger# +{-# NOINLINE fromEnum# #-} +{-# ANN fromEnum# hasBlackBox #-} + enumFrom# :: forall n. KnownNat n => Index n -> [Index n] enumFrom# x = [x .. maxBound] {-# NOINLINE enumFrom# #-} diff --git a/clash-prelude/src/Clash/Sized/Internal/Signed.hs b/clash-prelude/src/Clash/Sized/Internal/Signed.hs index 0b42d09e16..164cb67dcc 100644 --- a/clash-prelude/src/Clash/Sized/Internal/Signed.hs +++ b/clash-prelude/src/Clash/Sized/Internal/Signed.hs @@ -1,7 +1,7 @@ {-| Copyright : (C) 2013-2016, University of Twente, 2016 , Myrtle Software Ltd, - 2021 , QBayLogic B.V. + 2021-2022, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. -} @@ -39,6 +39,9 @@ module Clash.Sized.Internal.Signed , ge# , gt# , le# + -- ** Enum + , toEnum# + , fromEnum# -- ** Enum (not synthesizable) , enumFrom# , enumFromThen# @@ -111,6 +114,7 @@ import Test.QuickCheck.Arbitrary (Arbitrary (..), CoArbitrary (..), arbitraryBoundedIntegral, coarbitraryIntegral, shrinkIntegral) +import Clash.Annotations.Primitive (hasBlackBox) import Clash.Class.BitPack (BitPack (..), packXWith) import Clash.Class.Num (ExtendingNum (..), SaturatingNum (..), SaturationMode (..)) @@ -279,13 +283,22 @@ instance KnownNat n => Enum (Signed n) where <> "need other behavior." | otherwise = n -# fromInteger# 1 - toEnum = fromInteger# . toInteger - fromEnum = fromEnum . toInteger# + toEnum = toEnum# + fromEnum = fromEnum# enumFrom = enumFrom# enumFromThen = enumFromThen# enumFromTo = enumFromTo# enumFromThenTo = enumFromThenTo# +toEnum# :: forall n. KnownNat n => Int -> Signed n +toEnum# = fromInteger# . toInteger +{-# NOINLINE toEnum# #-} +{-# ANN toEnum# hasBlackBox #-} + +fromEnum# :: forall n. KnownNat n => Signed n -> Int +fromEnum# = fromEnum . toInteger# +{-# NOINLINE fromEnum# #-} +{-# ANN fromEnum# hasBlackBox #-} enumFrom# :: forall n. KnownNat n => Signed n -> [Signed n] enumFrom# x = map (fromInteger_INLINE sz mB mask) [unsafeToInteger x .. unsafeToInteger (maxBound :: Signed n)] diff --git a/clash-prelude/src/Clash/Sized/Internal/Unsigned.hs b/clash-prelude/src/Clash/Sized/Internal/Unsigned.hs index 7d379d8444..99a0194348 100644 --- a/clash-prelude/src/Clash/Sized/Internal/Unsigned.hs +++ b/clash-prelude/src/Clash/Sized/Internal/Unsigned.hs @@ -1,7 +1,7 @@ {-| Copyright : (C) 2013-2016, University of Twente, 2016 , Myrtle Software Ltd, - 2021 , QBayLogic B.V. + 2021-2022, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. -} @@ -38,6 +38,9 @@ module Clash.Sized.Internal.Unsigned , ge# , gt# , le# + -- ** Enum + , toEnum# + , fromEnum# -- ** Enum (not synthesizable) , enumFrom# , enumFromThen# @@ -125,6 +128,7 @@ import Test.QuickCheck.Arbitrary (Arbitrary (..), CoArbitrary (..), arbitraryBoundedIntegral, coarbitraryIntegral) +import Clash.Annotations.Primitive (hasBlackBox) import Clash.Class.BitPack (BitPack (..), packXWith, bitCoerce) import Clash.Class.Num (ExtendingNum (..), SaturatingNum (..), SaturationMode (..)) @@ -291,13 +295,23 @@ instance KnownNat n => Enum (Unsigned n) where <> "need other behavior." | otherwise = n -# fromInteger# 1 - toEnum = fromInteger# . toInteger - fromEnum = fromEnum . toInteger# + toEnum = toEnum# + fromEnum = fromEnum# enumFrom = enumFrom# enumFromThen = enumFromThen# enumFromTo = enumFromTo# enumFromThenTo = enumFromThenTo# +toEnum# :: forall n. KnownNat n => Int -> Unsigned n +toEnum# = fromInteger# . toInteger +{-# NOINLINE toEnum# #-} +{-# ANN toEnum# hasBlackBox #-} + +fromEnum# :: forall n. KnownNat n => Unsigned n -> Int +fromEnum# = fromEnum . toInteger# +{-# NOINLINE fromEnum# #-} +{-# ANN fromEnum# hasBlackBox #-} + enumFrom# :: forall n. KnownNat n => Unsigned n -> [Unsigned n] enumFrom# = \x -> map (U . (`mod` m)) [unsafeToNatural x .. unsafeToNatural (maxBound :: Unsigned n)] #if MIN_VERSION_base(4,15,0) diff --git a/tests/Main.hs b/tests/Main.hs index eda41851c9..8f31fced46 100755 --- a/tests/Main.hs +++ b/tests/Main.hs @@ -551,6 +551,15 @@ runClashTest = defaultMain $ clashTestRoot } , outputTest "T1996" def{hdlTargets=[VHDL]} , runTest "T2040" def{hdlTargets=[VHDL],clashFlags=["-fclash-compile-ultra"]} + -- TODO I wanted to call this T2046A since there are multiple tests + -- for T2046. However, doing so completely breaks HDL loading because + -- it completely ignores the BuildSpecific... + , runTest "T2046" def + { hdlSim=False + , clashFlags=["-Werror"] + , buildTargets=BuildSpecific["top_bit", "top_bitvector", "top_index", "top_signed", "top_unsigned"] + } + , runTest "T2046B" def{clashFlags=["-Werror"]} ] <> if compiledWith == Cabal then -- This tests fails without environment files present, which are only diff --git a/tests/shouldwork/Issues/T2046.hs b/tests/shouldwork/Issues/T2046.hs new file mode 100644 index 0000000000..cc58f6ba46 --- /dev/null +++ b/tests/shouldwork/Issues/T2046.hs @@ -0,0 +1,55 @@ +module T2046 where + +import Clash.Prelude +import Data.Proxy + +topGeneric + :: forall ix n + . Enum ix + => KnownNat n + => Proxy ix + -> Vec n Int + -> Int + -> Int +topGeneric Proxy x i = + x !! toEnum @ix i + +topBit + :: Vec 2 Int + -> Int + -> Int +topBit = topGeneric (Proxy @Bit) +{-# NOINLINE topBit #-} +{-# ANN topBit (defSyn "top_bit") #-} + +topBitVector + :: Vec 5 Int + -> Int + -> Int +topBitVector = topGeneric (Proxy @(BitVector 3)) +{-# NOINLINE topBitVector #-} +{-# ANN topBitVector (defSyn "top_bitvector") #-} + +topIndex + :: Vec 5 Int + -> Int + -> Int +topIndex = topGeneric (Proxy @(Index 5)) +{-# NOINLINE topIndex #-} +{-# ANN topIndex (defSyn "top_index") #-} + +topSigned + :: Vec 5 Int + -> Int + -> Int +topSigned = topGeneric (Proxy @(Signed 4)) +{-# NOINLINE topSigned #-} +{-# ANN topSigned (defSyn "top_signed") #-} + +topUnsigned + :: Vec 5 Int + -> Int + -> Int +topUnsigned = topGeneric (Proxy @(Unsigned 3)) +{-# NOINLINE topUnsigned #-} +{-# ANN topUnsigned (defSyn "top_unsigned") #-} diff --git a/tests/shouldwork/Issues/T2046B.hs b/tests/shouldwork/Issues/T2046B.hs new file mode 100644 index 0000000000..66f3bf1ace --- /dev/null +++ b/tests/shouldwork/Issues/T2046B.hs @@ -0,0 +1,33 @@ +{-# LANGUAGE ViewPatterns #-} + +module T2046B where + +import Clash.Prelude +import Clash.Explicit.Testbench + +import T2046BType (T2046B) + +topEntity :: T2046B -> T2046B +topEntity ((a, b), (c, d), (e, f), (g, h), i) = + ( (toEnum (fromEnum a), toEnum (fromEnum b)) + , (toEnum (fromEnum c), toEnum (fromEnum d)) + , (toEnum (fromEnum e), toEnum (fromEnum f)) + , (toEnum (fromEnum g), toEnum (fromEnum h)) + , toEnum (fromEnum i) + ) +{-# NOINLINE topEntity #-} + +testBench :: Signal System Bool +testBench = done + where + testInput = stimuliGenerator clk rst + $(listToVecTH [( (0, 0), (0, 0), (0, 0), (0, 0), 0) + , ((0, 1), (0, 1), (0, 1), (0, 1), 1) :: T2046B]) + + expectedOutput = outputVerifier' clk rst + $(listToVecTH [( (0, 0), (0, 0), (0, 0), (0, 0), 0) + , ((0, 1), (0, 1), (0, 1), (0, 1), 1) :: T2046B]) + + done = expectedOutput (topEntity <$> testInput) + clk = tbSystemClockGen (not <$> done) + rst = systemResetGen diff --git a/tests/shouldwork/Issues/T2046BType.hs b/tests/shouldwork/Issues/T2046BType.hs new file mode 100644 index 0000000000..eb13eebb9c --- /dev/null +++ b/tests/shouldwork/Issues/T2046BType.hs @@ -0,0 +1,11 @@ +module T2046BType where + +import Clash.Prelude + +type T2046B = + ( (Index 1, Index 2) + , (Unsigned 1, Unsigned 2) + , (Signed 1, Signed 2) + , (BitVector 1, BitVector 2) + , Bit + )