------------------------------------------------------------------------------- |-- Module : Data.SBV.BitVectors.SignCast-- Copyright : (c) Levent Erkok-- License : BSD3-- Maintainer : erkokl@gmail.com-- Stability : experimental---- Implementation of casting between signed/unsigned variants of the-- same type.-----------------------------------------------------------------------------{-# LANGUAGE MultiParamTypeClasses #-}{-# LANGUAGE FunctionalDependencies #-}{-# LANGUAGE TypeSynonymInstances #-}{-# LANGUAGE PatternGuards #-}{-# LANGUAGE FlexibleInstances #-}moduleData.SBV.BitVectors.SignCast(SignCast(..))whereimportData.Word(Word8,Word16,Word32,Word64)importData.Int(Int8,Int16,Int32,Int64)importData.SBV.BitVectors.DataimportData.SBV.BitVectors.Model()-- instances only-- | Sign casting a value into another. This essentially-- means forgetting the sign bit and reinterpreting the bits-- accordingly when converting a signed value to an unsigned-- one. Similarly, when an unsigned quantity is converted to-- a signed one, the most significant bit is interpreted-- as the sign. We only define instances when the source-- and target types are precisely the same size.-- The idea is that 'signCast' and 'unsignCast' must form-- an isomorphism pair between the types @a@ and @b@, i.e., we-- expect the following two properties to hold:---- @-- signCast . unsignCast = id-- unsingCast . signCast = id-- @---- Note that one naive way to implement both these operations-- is simply to compute @fromBitsLE . blastLE@, i.e., first-- get all the bits of the word and then reconstruct in the target-- type. While this is semantically correct, it generates a lot-- of code (both during proofs via SMT-Lib, and when compiled to C).-- The goal of this class is to avoid that cost, so these operations-- can be compiled very efficiently, they will essentially become no-op's.---- Minimal complete definition: All, no defaults.classSignCastab|a->b,b->awhere-- | Interpret as a signed wordsignCast::a->b-- | Interpret as an unsigned wordunsignCast::b->a-- concrete instancesinstanceSignCastWord64Int64wheresignCast=fromIntegralunsignCast=fromIntegralinstanceSignCastWord32Int32wheresignCast=fromIntegralunsignCast=fromIntegralinstanceSignCastWord16Int16wheresignCast=fromIntegralunsignCast=fromIntegralinstanceSignCastWord8Int8wheresignCast=fromIntegralunsignCast=fromIntegral-- A generic implementation can be along the following lines:-- fromBitsLE . blastLE-- However, we prefer this version as the above will generate-- a ton more code during compilation to SMT-Lib and CgenericSign::(Integrala,SymWorda,Numb,SymWordb)=>SBVa->SBVbgenericSignx|Justc<-unliteralx=literal$fromIntegralc|True=SBVk(Right(cachey))wherek=casekindOfxofKBoundedFalsen->KBoundedTruenKBoundedTrue_->error"Data.SBV.SignCast.genericSign: Called on signed value"KUnbounded->error"Data.SBV.SignCast.genericSign: Called on unbounded value"KReal->error"Data.SBV.SignCast.genericSign: Called on real value"KUninterpreteds->error$"Data.SBV.SignCast.genericSign: Called on unintepreted sort "++syst=doxsw<-sbvToSWstxnewExprstk(SBVApp(Extract(intSizeOfx-1)0)[xsw])-- Same comments as above, regarding the implementation.genericUnsign::(Integrala,SymWorda,Numb,SymWordb)=>SBVa->SBVbgenericUnsignx|Justc<-unliteralx=literal$fromIntegralc|True=SBVk(Right(cachey))wherek=casekindOfxofKBoundedTruen->KBoundedFalsenKBoundedFalse_->error"Data.SBV.SignCast.genericUnSign: Called on unsigned value"KUnbounded->error"Data.SBV.SignCast.genericUnSign: Called on unbounded value"KReal->error"Data.SBV.SignCast.genericUnSign: Called on real value"KUninterpreteds->error$"Data.SBV.SignCast.genericUnSign: Called on unintepreted sort "++syst=doxsw<-sbvToSWstxnewExprstk(SBVApp(Extract(intSizeOfx-1)0)[xsw])-- symbolic instancesinstanceSignCastSWord8SInt8wheresignCast=genericSignunsignCast=genericUnsigninstanceSignCastSWord16SInt16wheresignCast=genericSignunsignCast=genericUnsigninstanceSignCastSWord32SInt32wheresignCast=genericSignunsignCast=genericUnsigninstanceSignCastSWord64SInt64wheresignCast=genericSignunsignCast=genericUnsign