hsSyn/HsSyn.lhs
#define NOT_SO_BASICSRCS_LHS \
-basicTypes/Unique.lhs \
-basicTypes/UniqSupply.lhs \
-basicTypes/ProtoName.lhs \
-basicTypes/Name.lhs \
-basicTypes/NameTypes.lhs \
-basicTypes/SrcLoc.lhs \
+basicTypes/FieldLabel.lhs \
basicTypes/Id.lhs \
basicTypes/IdInfo.lhs \
basicTypes/IdUtils.lhs \
-basicTypes/PragmaInfo.lhs \
basicTypes/Literal.lhs \
+basicTypes/Name.lhs \
+basicTypes/NameTypes.lhs \
+basicTypes/PprEnv.lhs \
+basicTypes/PragmaInfo.lhs \
+basicTypes/ProtoName.lhs \
+basicTypes/SrcLoc.lhs \
+basicTypes/UniqSupply.lhs \
+basicTypes/Unique.lhs \
\
types/Class.lhs \
types/Kind.lhs \
coreSyn/CoreLift.lhs \
coreSyn/CoreLint.lhs
+#if GhcWithDeforester != YES
+#define __omit_deforester_flag -DOMIT_DEFORESTER=1
+#define DEFORESTER_SRCS_LHS /*none*/
+#else
+#define __omit_deforester_flag /*nope*/
+#define DEFORESTER_SRCS_LHS \
+deforest/DefSyn.lhs \
+deforest/Core2Def.lhs \
+deforest/Def2Core.lhs \
+deforest/Deforest.lhs \
+deforest/DefUtils.lhs \
+deforest/DefExpr.lhs \
+deforest/Cyclic.lhs \
+deforest/TreelessForm.lhs
+#endif /* GhcWithDeforester */
+
#define SIMPL_SRCS_LHS \
coreSyn/AnnCoreSyn.lhs \
coreSyn/FreeVars.lhs \
stranal/WwLib.lhs \
stranal/WorkWrap.lhs \
\
-profiling/SCCauto.lhs \
-profiling/SCCfinal.lhs
+profiling/SCCauto.lhs DEFORESTER_SRCS_LHS
-#if GhcWithDeforester != YES
-#define __omit_deforester_flag -DOMIT_DEFORESTER=1
-#define DEFORESTER_SRCS_LHS /*none*/
-#else
-#define __omit_deforester_flag /*nope*/
-#define DEFORESTER_SRCS_LHS \
-deforest/DefSyn.lhs \
-deforest/Core2Def.lhs \
-deforest/Def2Core.lhs \
-deforest/Deforest.lhs \
-deforest/DefUtils.lhs \
-deforest/DefExpr.lhs \
-deforest/Cyclic.lhs \
-deforest/TreelessForm.lhs
-#endif /* GhcWithDeforester */
-
-#define BACKSRCS_LHS \
+#define STG_SRCS_LHS \
stgSyn/CoreToStg.lhs \
stgSyn/StgSyn.lhs \
stgSyn/StgUtils.lhs \
stgSyn/StgLint.lhs \
+profiling/SCCfinal.lhs \
\
simplStg/SatStgRhs.lhs \
simplStg/LambdaLift.lhs \
simplStg/StgStats.lhs \
simplStg/StgSATMonad.lhs \
simplStg/StgSAT.lhs \
-simplStg/SimplStg.lhs \
-\
+simplStg/SimplStg.lhs
+
+#define BACKSRCS_LHS \
absCSyn/AbsCUtils.lhs \
absCSyn/AbsCSyn.lhs \
absCSyn/CLabel.lhs \
# define NATIVEGEN_SRCS_LHS /*none*/
#else
# define __omit_ncg_maybe /*none*/
-# if i386_TARGET_ARCH
-# define __machdep_nativegen_lhs \
-nativeGen/I386Desc.lhs \
-nativeGen/I386Code.lhs \
-nativeGen/I386Gen.lhs
-# endif
-# if sparc_TARGET_ARCH
-# define __machdep_nativegen_lhs \
-nativeGen/SparcDesc.lhs \
-nativeGen/SparcCode.lhs \
-nativeGen/SparcGen.lhs
-# endif
-# if alpha_TARGET_ARCH
-# define __machdep_nativegen_lhs \
-nativeGen/AlphaDesc.lhs \
-nativeGen/AlphaCode.lhs \
-nativeGen/AlphaGen.lhs
-# endif
# define NATIVEGEN_SRCS_LHS \
nativeGen/AbsCStixGen.lhs \
nativeGen/AsmCodeGen.lhs \
nativeGen/AsmRegAlloc.lhs \
-nativeGen/MachDesc.lhs \
+nativeGen/MachCode.lhs \
+nativeGen/MachMisc.lhs \
+nativeGen/MachRegs.lhs \
+nativeGen/PprMach.lhs \
+nativeGen/RegAllocInfo.lhs \
nativeGen/Stix.lhs \
nativeGen/StixInfo.lhs \
nativeGen/StixInteger.lhs \
nativeGen/StixPrim.lhs \
-nativeGen/StixMacro.lhs \
-__machdep_nativegen_lhs /*arch-specific ones */
+nativeGen/StixMacro.lhs
#endif
#define UTILSRCS_LHS \
ALLSRCS_HS = READERSRCS_HS
ALLSRCS_LHS = /* all pieces of the compiler */ \
-VBASICSRCS_LHS \
-NOT_SO_BASICSRCS_LHS \
-UTILSRCS_LHS \
-MAIN_SRCS_LHS \
-READERSRCS_LHS \
-RENAMERSRCS_LHS \
-TCSRCS_LHS \
-DSSRCS_LHS
+VBASICSRCS_LHS \
+NOT_SO_BASICSRCS_LHS \
+UTILSRCS_LHS \
+MAIN_SRCS_LHS \
+READERSRCS_LHS \
+RENAMERSRCS_LHS \
+TCSRCS_LHS \
+DSSRCS_LHS \
+SIMPL_SRCS_LHS \
+STG_SRCS_LHS \
+BACKSRCS_LHS NATIVEGEN_SRCS_LHS
/*
-SIMPL_SRCS_LHS
-BACKSRCS_LHS
*/
-
-/*
-NATIVEGEN_SRCS_LHS DEFORESTER_SRCS_LHS */
/* NB: all the ones that may be empty (e.g., NATIVEGEN_SRCS_LHS)
need to be on the last line.
*/
#define __version_sensitive_flags -fomit-reexported-instances
#endif
-#if GhcWithRegisterised == NO
- /* doing a raw boot from .hc files, presumably */
-#define __unreg_opts_maybe -O -unregisterised
-#else
-#define __unreg_opts_maybe /*none*/
-#endif
-
/* avoid use of AllProjectsHcOpts; then put in HcMaxHeapFlag "by hand" */
#undef AllProjectsHcOpts
#define AllProjectsHcOpts /**/
HC_OPTS = -cpp HcMaxHeapFlag -fhaskell-1.3 -fglasgow-exts -DCOMPILING_GHC \
-fomit-derived-read \
-I. -i$(SUBDIR_LIST) \
- use_DDEBUG __version_sensitive_flags __unreg_opts_maybe __omit_ncg_maybe
+ use_DDEBUG __version_sensitive_flags __omit_ncg_maybe __omit_deforester_flag
#undef __version_sensitive_flags
-#undef __unreg_opts_maybe
#undef __omit_ncg_maybe
#undef __omit_deforester_flag
utils/Ubiq.hi : utils/Ubiq.lhi
$(GHC_UNLIT) utils/Ubiq.lhi utils/Ubiq.hi
+absCSyn/AbsCLoop.hi : absCSyn/AbsCLoop.lhi
+ $(GHC_UNLIT) absCSyn/AbsCLoop.lhi absCSyn/AbsCLoop.hi
basicTypes/IdLoop.hi : basicTypes/IdLoop.lhi
$(GHC_UNLIT) basicTypes/IdLoop.lhi basicTypes/IdLoop.hi
basicTypes/NameLoop.hi : basicTypes/NameLoop.lhi
$(GHC_UNLIT) basicTypes/NameLoop.lhi basicTypes/NameLoop.hi
+codeGen/CgLoop1.hi : codeGen/CgLoop1.lhi
+ $(GHC_UNLIT) codeGen/CgLoop1.lhi codeGen/CgLoop1.hi
+codeGen/CgLoop2.hi : codeGen/CgLoop2.lhi
+ $(GHC_UNLIT) codeGen/CgLoop2.lhi codeGen/CgLoop2.hi
deSugar/DsLoop.hi : deSugar/DsLoop.lhi
$(GHC_UNLIT) deSugar/DsLoop.lhi deSugar/DsLoop.hi
hsSyn/HsLoop.hi : hsSyn/HsLoop.lhi
$(GHC_UNLIT) hsSyn/HsLoop.lhi hsSyn/HsLoop.hi
+nativeGen/NcgLoop.hi : nativeGen/NcgLoop.lhi
+ $(GHC_UNLIT) nativeGen/NcgLoop.lhi nativeGen/NcgLoop.hi
prelude/PrelLoop.hi : prelude/PrelLoop.lhi
$(GHC_UNLIT) prelude/PrelLoop.lhi prelude/PrelLoop.hi
reader/RdrLoop.hi : reader/RdrLoop.lhi
compile(hsSyn/HsTypes,lhs,)
compile(hsSyn/HsSyn,lhs,if_ghc(-fno-omit-reexported-instances))
+compile(basicTypes/FieldLabel,lhs,)
compile(basicTypes/Id,lhs,)
compile(basicTypes/IdInfo,lhs,-K2m)
compile(basicTypes/IdUtils,lhs,)
compile(basicTypes/Literal,lhs,)
compile(basicTypes/Name,lhs,)
compile(basicTypes/NameTypes,lhs,)
+compile(basicTypes/PprEnv,lhs,)
compile(basicTypes/PragmaInfo,lhs,)
compile(basicTypes/ProtoName,lhs,)
compile(basicTypes/SrcLoc,lhs,)
compile(nativeGen/AbsCStixGen,lhs,)
compile(nativeGen/AsmCodeGen,lhs,-I$(COMPINFO_DIR))
compile(nativeGen/AsmRegAlloc,lhs,-I$(COMPINFO_DIR))
-compile(nativeGen/MachDesc,lhs,)
+compile(nativeGen/MachCode,lhs,)
+compile(nativeGen/MachMisc,lhs,)
+compile(nativeGen/MachRegs,lhs,)
+compile(nativeGen/PprMach,lhs,)
+compile(nativeGen/RegAllocInfo,lhs,)
compile(nativeGen/Stix,lhs,)
compile(nativeGen/StixInfo,lhs,-I$(NATIVEGEN_DIR))
compile(nativeGen/StixInteger,lhs,)
compile(nativeGen/StixMacro,lhs,-I$(NATIVEGEN_DIR))
compile(nativeGen/StixPrim,lhs,)
-# if i386_TARGET_ARCH
-compile(nativeGen/I386Desc,lhs,)
-compile(nativeGen/I386Code,lhs,-I$(NATIVEGEN_DIR) if_ghc(-monly-4-regs))
-compile(nativeGen/I386Gen,lhs,)
-# endif
-# if sparc_TARGET_ARCH
-compile(nativeGen/SparcDesc,lhs,)
-compile(nativeGen/SparcCode,lhs,-I$(NATIVEGEN_DIR))
-compile(nativeGen/SparcGen,lhs,)
-# endif
-# if alpha_TARGET_ARCH
-compile(nativeGen/AlphaDesc,lhs,)
-compile(nativeGen/AlphaCode,lhs,-I$(NATIVEGEN_DIR))
-compile(nativeGen/AlphaGen,lhs,)
-# endif
#endif
compile(prelude/PrelInfo,lhs,)
/* *** misc *************************************************** */
-DEPSRCS = $(ALLSRCS_LHS) $(ALLSRCS_HS) SIMPL_SRCS_LHS
+DEPSRCS = $(ALLSRCS_LHS) $(ALLSRCS_HS)
#if GhcWithHscBuiltViaC == NO
MKDEPENDHS_OPTS= -I$(MAIN_INCLUDE_DIR) -I$(COMPINFO_DIR) -x HsVersions.h
--- /dev/null
+Breaks the loop caused by PprAbsC needing to
+see big swathes of ClosureInfo.
+
+Also from CLabel needing a couple of CgRetConv things.
+
+Also from HeapOffs needing some MachMisc things.
+
+\begin{code}
+interface AbsCLoop where
+import PreludeStdIO ( Maybe )
+
+import CgRetConv ( ctrlReturnConvAlg,
+ CtrlReturnConvention(..)
+ )
+import ClosureInfo ( closureKind, closureLabelFromCI,
+ closureNonHdrSize, closurePtrsSize,
+ closureSMRep, closureSemiTag,
+ closureSizeWithoutFixedHdr,
+ closureTypeDescr, closureUpdReqd,
+ infoTableLabelFromCI, maybeSelectorInfo,
+ entryLabelFromCI,fastLabelFromCI,
+ ClosureInfo
+ )
+import CLabel ( CLabel )
+import HeapOffs ( HeapOffset )
+import Id ( Id(..) )
+import MachMisc ( fixedHdrSizeInWords, varHdrSizeInWords )
+import SMRep ( SMRep )
+import TyCon ( TyCon )
+
+closureKind :: ClosureInfo -> [Char]
+closureLabelFromCI :: ClosureInfo -> CLabel
+closureNonHdrSize :: ClosureInfo -> Int
+closurePtrsSize :: ClosureInfo -> Int
+closureSMRep :: ClosureInfo -> SMRep
+closureSemiTag :: ClosureInfo -> Int
+closureSizeWithoutFixedHdr :: ClosureInfo -> HeapOffset
+closureTypeDescr :: ClosureInfo -> [Char]
+closureUpdReqd :: ClosureInfo -> Bool
+entryLabelFromCI :: ClosureInfo -> CLabel
+fastLabelFromCI :: ClosureInfo -> CLabel
+infoTableLabelFromCI :: ClosureInfo -> CLabel
+maybeSelectorInfo :: ClosureInfo -> Maybe (Id, Int)
+
+ctrlReturnConvAlg :: TyCon -> CtrlReturnConvention
+data CtrlReturnConvention = VectoredReturn Int | UnvectoredReturn Int
+
+fixedHdrSizeInWords :: Int
+varHdrSizeInWords :: SMRep -> Int
+\end{code}
\begin{code}
#include "HsVersions.h"
-module AbsCSyn (
+module AbsCSyn {- (
-- export everything
AbstractC(..),
CStmtMacro(..),
mkAbsCStmtList,
mkCCostCentre,
- -- HeapOffsets, plus some convenient synonyms...
- HeapOffset,
- zeroOff, intOff, fixedHdrSize, totHdrSize, varHdrSize,
- maxOff, addOff, subOff, intOffsetIntoGoods,
- isZeroOff, possiblyEqualHeapOffset,
- pprHeapOffset,
- VirtualHeapOffset(..), HpRelOffset(..),
- VirtualSpAOffset(..), VirtualSpBOffset(..),
- SpARelOffset(..), SpBRelOffset(..),
-
-- RegRelatives
RegRelative(..),
-- registers
MagicId(..), node, infoptr,
- isVolatileReg,
-
- -- closure info
- ClosureInfo, LambdaFormInfo, UpdateFlag, SMRep,
-
- -- stuff from AbsCUtils and PprAbsC...
- nonemptyAbsC, flattenAbsC, getAmodeRep,
- mixedTypeLocn, mixedPtrLocn,
- writeRealC,
- dumpRealC,
- kindFromMagicId,
- amodeCanSurviveGC
+ isVolatileReg, noLiveRegsMask, mkLiveRegsMask
#ifdef GRAN
, CostRes(Cost)
#endif
+ )-} where
- -- and stuff to make the interface self-sufficient
- ) where
-
-import AbsCUtils -- used, and re-exported
-import ClosureInfo -- ditto
-import Costs
-import PprAbsC -- ditto
-import HeapOffs hiding ( hpRelToInt )
+import Ubiq{-uitous-}
-import PrelInfo ( PrimOp
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
+import CgCompInfo ( mAX_Vanilla_REG, mAX_Float_REG,
+ mAX_Double_REG, lIVENESS_R1, lIVENESS_R2,
+ lIVENESS_R3, lIVENESS_R4, lIVENESS_R5,
+ lIVENESS_R6, lIVENESS_R7, lIVENESS_R8
)
-import Literal ( mkMachInt, mkMachWord, Literal(..) )
-import CLabel
-import CgCompInfo ( mAX_Vanilla_REG, mAX_Float_REG, mAX_Double_REG )
-import CostCentre -- for CostCentre type
-import Id ( Id, ConTag(..), DataCon(..) )
-import Maybes ( Maybe )
-import Outputable
-import PrimRep ( PrimRep(..) )
-import StgSyn ( GenStgExpr, GenStgArg, StgBinderInfo )
-import UniqSet ( UniqSet(..), UniqFM )
-import Unpretty -- ********** NOTE **********
-import Util
+import HeapOffs ( VirtualSpAOffset(..), VirtualSpBOffset(..),
+ VirtualHeapOffset(..)
+ )
+import Literal ( mkMachInt )
+import PrimRep ( isFollowableRep, PrimRep(..) )
\end{code}
@AbstractC@ is a list of Abstract~C statements, but the data structure
is tree-ish, for easier and more efficient putting-together.
\begin{code}
+absCNop = AbsCNop
+
data AbstractC
= AbsCNop
| AbsCStmts AbstractC AbstractC
= DirectReturn -- Jump directly, if possible
| StaticVectoredReturn Int -- Fixed tag, starting at zero
| DynamicVectoredReturn CAddrMode -- Dynamic tag given by amode, starting at zero
-
\end{code}
%************************************************************************
node = VanillaReg PtrRep ILIT(1) -- A convenient alias for Node
infoptr = VanillaReg DataPtrRep ILIT(2) -- An alias for InfoPtr
+
+--------------------
+noLiveRegsMask :: Int -- Mask indicating nothing live
+noLiveRegsMask = 0
+
+mkLiveRegsMask
+ :: [MagicId] -- Candidate live regs; depends what they have in them
+ -> Int
+
+mkLiveRegsMask regs
+ = foldl do_reg noLiveRegsMask regs
+ where
+ do_reg acc (VanillaReg kind reg_no)
+ | isFollowableRep kind
+ = acc + (reg_tbl !! IBOX(reg_no _SUB_ ILIT(1)))
+
+ do_reg acc anything_else = acc
+
+ reg_tbl -- ToDo: mk Array!
+ = [lIVENESS_R1, lIVENESS_R2, lIVENESS_R3, lIVENESS_R4,
+ lIVENESS_R5, lIVENESS_R6, lIVENESS_R7, lIVENESS_R8]
\end{code}
We need magical @Eq@ because @VanillaReg@s come in multiple flavors.
nonemptyAbsC,
mkAbstractCs, mkAbsCStmts,
mkAlgAltsCSwitch,
- kindFromMagicId,
+ magicIdPrimRep,
getAmodeRep, amodeCanSurviveGC,
mixedTypeLocn, mixedPtrLocn,
flattenAbsC,
mkAbsCStmtList
-- printing/forcing stuff comes from PprAbsC
-
- -- and for interface self-sufficiency...
) where
+import Ubiq{-uitous-}
+
import AbsCSyn
-import PrelInfo ( PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import Literal ( literalPrimRep )
-import CLabel ( CLabel, mkReturnPtLabel, mkVecTblLabel )
+import CLabel ( mkReturnPtLabel )
import Digraph ( stronglyConnComp )
-import Id ( fIRST_TAG, ConTag(..), DataCon(..), Id )
-import Maybes ( Maybe(..) )
-import PrimRep ( getPrimRepSize, retPrimRepSize, PrimRep(..) )
-import UniqSupply
-import StgSyn ( GenStgArg )
+import HeapOffs ( possiblyEqualHeapOffset )
+import Id ( fIRST_TAG, ConTag(..) )
+import Literal ( literalPrimRep, Literal(..) )
+import PrimRep ( getPrimRepSize, PrimRep(..) )
+import Unique ( Unique{-instance Eq-} )
+import UniqSupply ( getUnique, getUniques, splitUniqSupply )
+import Util ( panic )
infixr 9 `thenFlt`
\end{code}
%************************************************************************
\begin{code}
-kindFromMagicId BaseReg = PtrRep
-kindFromMagicId StkOReg = PtrRep
-kindFromMagicId (VanillaReg kind _) = kind
-kindFromMagicId (FloatReg _) = FloatRep
-kindFromMagicId (DoubleReg _) = DoubleRep
-kindFromMagicId TagReg = IntRep
-kindFromMagicId RetReg = RetRep
-kindFromMagicId SpA = PtrRep
-kindFromMagicId SuA = PtrRep
-kindFromMagicId SpB = PtrRep
-kindFromMagicId SuB = PtrRep
-kindFromMagicId Hp = PtrRep
-kindFromMagicId HpLim = PtrRep
-kindFromMagicId LivenessReg = IntRep
-kindFromMagicId StdUpdRetVecReg = PtrRep
-kindFromMagicId StkStubReg = PtrRep
-kindFromMagicId CurCostCentre = CostCentreRep
-kindFromMagicId VoidReg = VoidRep
+magicIdPrimRep BaseReg = PtrRep
+magicIdPrimRep StkOReg = PtrRep
+magicIdPrimRep (VanillaReg kind _) = kind
+magicIdPrimRep (FloatReg _) = FloatRep
+magicIdPrimRep (DoubleReg _) = DoubleRep
+magicIdPrimRep TagReg = IntRep
+magicIdPrimRep RetReg = RetRep
+magicIdPrimRep SpA = PtrRep
+magicIdPrimRep SuA = PtrRep
+magicIdPrimRep SpB = PtrRep
+magicIdPrimRep SuB = PtrRep
+magicIdPrimRep Hp = PtrRep
+magicIdPrimRep HpLim = PtrRep
+magicIdPrimRep LivenessReg = IntRep
+magicIdPrimRep StdUpdRetVecReg = PtrRep
+magicIdPrimRep StkStubReg = PtrRep
+magicIdPrimRep CurCostCentre = CostCentreRep
+magicIdPrimRep VoidReg = VoidRep
\end{code}
%************************************************************************
getAmodeRep (CVal _ kind) = kind
getAmodeRep (CAddr _) = PtrRep
-getAmodeRep (CReg magic_id) = kindFromMagicId magic_id
+getAmodeRep (CReg magic_id) = magicIdPrimRep magic_id
getAmodeRep (CTemp uniq kind) = kind
getAmodeRep (CLbl label kind) = kind
getAmodeRep (CUnVecLbl _ _) = PtrRep
needsCDecl, isReadOnly, isAsmTemp, externallyVisibleCLabel,
- pprCLabel
+ pprCLabel, pprCLabel_asm
#ifdef GRAN
, isSlowEntryCCodeBlock
#endif
-
- -- and to make the interface self-sufficient...
) where
import Ubiq{-uitous-}
+import AbsCLoop ( CtrlReturnConvention(..),
+ ctrlReturnConvAlg
+ )
+import NcgLoop ( underscorePrefix, fmtAsmLbl )
+import CStrings ( pp_cSEP )
import Id ( externallyVisibleId, cmpId_withSpecDataCon,
isDataCon, isDictFunId,
- isConstMethodId_maybe, isClassOpId,
+ isConstMethodId_maybe,
isDefaultMethodId_maybe,
isSuperDictSelId_maybe, fIRST_TAG,
- DataCon(..), ConTag(..), Id
+ ConTag(..), GenId{-instance Outputable-}
)
import Maybes ( maybeToBool )
+import PprStyle ( PprStyle(..) )
+import PprType ( showTyCon, GenType{-instance Outputable-} )
+import Pretty ( prettyToUn )
+import TyCon ( TyCon{-instance Eq-} )
+import Unique ( showUnique, pprUnique, Unique{-instance Eq-} )
import Unpretty -- NOTE!! ********************
-{-
-import Outputable
-import Pretty ( ppNil, ppChar, ppStr, ppPStr, ppDouble, ppInt,
- ppInteger, ppBeside, ppIntersperse, prettyToUn
- )
-#ifdef USE_ATTACK_PRAGMAS
-import CharSeq
-#endif
-import Unique ( pprUnique, showUnique, Unique )
-import Util
-
--- Sigh... Shouldn't this file (CLabel) live in codeGen?
-import CgRetConv ( CtrlReturnConvention(..), ctrlReturnConvAlg )
--}
+import Util ( assertPanic )
\end{code}
things we want to find out:
| isDataCon id = True
| is_ConstMethodId id = True -- These are here to ensure splitting works
| isDictFunId id = True -- when these values have not been exported
- | isClassOpId id = True
| is_DefaultMethodId id = True
| is_SuperDictSelId id = True
| otherwise = externallyVisibleId id
where
- is_ConstMethodId id = maybeToBool (isConstMethodId_maybe id)
+ is_ConstMethodId id = maybeToBool (isConstMethodId_maybe id)
is_DefaultMethodId id = maybeToBool (isDefaultMethodId_maybe id)
- is_SuperDictSelId id = maybeToBool (isSuperDictSelId_maybe id)
+ is_SuperDictSelId id = maybeToBool (isSuperDictSelId_maybe id)
\end{code}
These GRAN functions are needed for spitting out GRAN_FETCH() at the
@PprAbsC@).
\begin{code}
+-- specialised for PprAsm: saves lots of arg passing in NCG
+pprCLabel_asm = pprCLabel (PprForAsm underscorePrefix fmtAsmLbl)
+
pprCLabel :: PprStyle -> CLabel -> Unpretty
-pprCLabel (PprForAsm _ _ fmtAsmLbl) (AsmTempLabel u)
+pprCLabel (PprForAsm _ fmtAsmLbl) (AsmTempLabel u)
= uppStr (fmtAsmLbl (_UNPK_ (showUnique u)))
-pprCLabel (PprForAsm sw_chker prepend_cSEP _) lbl
+pprCLabel (PprForAsm prepend_cSEP _) lbl
= if prepend_cSEP
then uppBeside pp_cSEP prLbl
else prLbl
where
- prLbl = pprCLabel (PprForC sw_chker) lbl
+ prLbl = pprCLabel PprForC lbl
pprCLabel sty (TyConLabel tc UnvecConUpdCode)
= uppBesides [uppPStr SLIT("ret"), pp_cSEP, uppStr (showTyCon sty tc),
RednCounts -> uppPStr SLIT("ct")
)
\end{code}
-
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1994-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1994-1996
% Hans Wolfgang Loidl
%
% ---------------------------------------------------------------------------
addrModeCosts, CostRes(Cost), nullCosts, Side(..)
) where
-import AbsCUtils
+import Ubiq{-uitous-}
+
import AbsCSyn
-import PrelInfo
-import PrimOp
-import TyCon
-import Util
-- --------------------------------------------------------------------------
#ifndef GRAN
intOffsetIntoGoods,
-#if 0
#if ! OMIT_NATIVE_CODEGEN
hpRelToInt,
#endif
-#endif
VirtualHeapOffset(..), HpRelOffset(..),
VirtualSpAOffset(..), VirtualSpBOffset(..),
) where
import Ubiq{-uitous-}
+#if ! OMIT_NATIVE_CODEGEN
+import AbsCLoop ( fixedHdrSizeInWords, varHdrSizeInWords )
+#endif
-import ClosureInfo ( isSpecRep )
import Maybes ( catMaybes )
import SMRep
import Unpretty -- ********** NOTE **********
import Util ( panic )
-#if ! OMIT_NATIVE_CODEGEN
---import MachDesc ( Target )
-#endif
\end{code}
%************************************************************************
pprHeapOffset sty ZeroHeapOffset = uppChar '0'
pprHeapOffset sty (MaxHeapOffset off1 off2)
- = uppBesides [uppPStr SLIT("STG_MAX"), uppLparen,
- pprHeapOffset sty off1, uppComma, pprHeapOffset sty off2,
- uppRparen]
+ = uppBeside (uppPStr SLIT("STG_MAX"))
+ (uppParens (uppBesides [pprHeapOffset sty off1, uppComma, pprHeapOffset sty off2]))
+
pprHeapOffset sty (AddHeapOffset off1 off2)
- = uppBesides [uppLparen, pprHeapOffset sty off1, uppChar '+',
- pprHeapOffset sty off2, uppRparen]
+ = uppParens (uppBesides [pprHeapOffset sty off1, uppChar '+',
+ pprHeapOffset sty off2])
pprHeapOffset sty (SubHeapOffset off1 off2)
- = uppBesides [uppLparen, pprHeapOffset sty off1, uppChar '-',
- pprHeapOffset sty off2, uppRparen]
+ = uppParens (uppBesides [pprHeapOffset sty off1, uppChar '-',
+ pprHeapOffset sty off2])
pprHeapOffset sty (MkHeapOffset int_offs fxdhdr_offs varhdr_offs tothdr_offs)
= pprHeapOffsetPieces sty int_offs fxdhdr_offs varhdr_offs tothdr_offs
case (catMaybes [pp_tothdr_offs, pp_varhdr_offs, pp_fxdhdr_offs, pp_int_offs]) of
[] -> uppChar '0'
[pp] -> pp -- Each blob is parenthesised if necessary
- pps -> uppBesides [ uppLparen, uppIntersperse (uppChar '+') pps, uppRparen ]
+ pps -> uppParens (uppIntersperse (uppChar '+') pps)
where
pp_hdrs hdr_pp [] = Nothing
pp_hdrs hdr_pp [SMRI(rep, n)] | n _EQ_ ILIT(1) = Just (uppBeside (uppStr (show rep)) hdr_pp)
- pp_hdrs hdr_pp hdrs = Just (uppBesides [ uppLparen,
- uppInterleave (uppChar '+')
- (map (pp_hdr hdr_pp) hdrs),
- uppRparen ])
+ pp_hdrs hdr_pp hdrs = Just (uppParens (uppInterleave (uppChar '+')
+ (map (pp_hdr hdr_pp) hdrs)))
pp_hdr :: Unpretty -> SMRep__Int -> Unpretty
pp_hdr pp_str (SMRI(rep, n))
\end{code}
\begin{code}
-#if 0
#if ! OMIT_NATIVE_CODEGEN
-hpRelToInt :: Target -> HeapOffset -> Int
+hpRelToInt :: HeapOffset -> Int
-hpRelToInt target (MaxHeapOffset left right)
- = (hpRelToInt target left) `max` (hpRelToInt target right)
+hpRelToInt ZeroHeapOffset = 0
-hpRelToInt target (SubHeapOffset left right)
- = (hpRelToInt target left) - (hpRelToInt target right)
+hpRelToInt (MaxHeapOffset left right)
+ = hpRelToInt left `max` hpRelToInt right
-hpRelToInt target (AddHeapOffset left right)
- = (hpRelToInt target left) + (hpRelToInt target right)
+hpRelToInt (SubHeapOffset left right)
+ = hpRelToInt left - hpRelToInt right
-hpRelToInt target ZeroHeapOffset = 0
+hpRelToInt (AddHeapOffset left right)
+ = hpRelToInt left + hpRelToInt right
-hpRelToInt target (MkHeapOffset base fhs vhs ths)
+hpRelToInt (MkHeapOffset base fhs vhs ths)
= let
vhs_pieces, ths_pieces :: [Int]
fhs_off, vhs_off, ths_off :: Int
in
IBOX(base) + fhs_off + vhs_off + ths_off
where
- fhs_size = (fixedHeaderSize target) :: Int
- vhs_size r = (varHeaderSize target r) :: Int
+ fhs_size = fixedHdrSizeInWords
+ vhs_size r = varHdrSizeInWords r
#endif
-#endif {-0-}
\end{code}
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
%************************************************************************
%* *
module PprAbsC (
writeRealC,
- dumpRealC,
+ dumpRealC
#if defined(DEBUG)
- pprAmode, -- otherwise, not exported
+ , pprAmode -- otherwise, not exported
#endif
-
- -- and for interface self-sufficiency...
- AbstractC, CAddrMode, MagicId,
- PprStyle, CSeq
) where
-IMPORT_Trace -- ToDo: rm (debugging only)
+import Ubiq{-uitous-}
+import AbsCLoop -- break its dependence on ClosureInfo
import AbsCSyn
-import PrelInfo ( pprPrimOp, primOpNeedsWrapper, PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
+import AbsCUtils ( getAmodeRep, nonemptyAbsC,
+ mixedPtrLocn, mixedTypeLocn
)
-import Literal ( literalPrimRep, showLiteral )
-import CLabel -- lots of things
import CgCompInfo ( spARelToInt, spBRelToInt, mIN_UPD_SIZE )
-import CgRetConv ( noLiveRegsMask )
-import ClosureInfo -- quite a few things
-import Costs -- for GrAnSim; cost counting function -- HWL
-import CostCentre
-import FiniteMap
-import Maybes ( catMaybes, maybeToBool, Maybe(..) )
-import Outputable
-import Pretty ( codeStyle, prettyToUn )
-import PrimRep ( showPrimRep, isFloatingRep, PrimRep(..) )
-import StgSyn
-import UniqFM
+import CLabel ( externallyVisibleCLabel, mkErrorStdEntryLabel,
+ isReadOnly, needsCDecl, pprCLabel,
+ CLabel{-instance Ord-}
+ )
+import CmdLineOpts ( opt_SccProfilingOn )
+import CostCentre ( uppCostCentre, uppCostCentreDecl )
+import Costs ( costs, addrModeCosts, CostRes(..), Side(..) )
+import CStrings ( stringToC )
+import FiniteMap ( addToFM, emptyFM, lookupFM )
+import HeapOffs ( isZeroOff, subOff, pprHeapOffset )
+import Literal ( showLiteral, Literal(..) )
+import Maybes ( maybeToBool, catMaybes )
+import PprStyle ( PprStyle(..) )
+import Pretty ( prettyToUn )
+import PrimOp ( primOpNeedsWrapper, pprPrimOp, PrimOp(..) )
+import PrimRep ( isFloatingRep, showPrimRep, PrimRep(..) )
+import SMRep ( getSMInfoStr, getSMInitHdrStr, getSMUpdInplaceHdrStr,
+ isConstantRep, isSpecRep, isPhantomRep
+ )
+import Unique ( pprUnique, Unique{-instance NamedThing-} )
+import UniqSet ( emptyUniqSet, elementOfUniqSet,
+ addOneToUniqSet, UniqSet(..)
+ )
import Unpretty -- ********** NOTE **********
-import Util
+import Util ( nOfThem, panic, assertPanic )
infixr 9 `thenTE`
\end{code}
@pprAbsC@ has a new ``costs'' argument. %% HWL
\begin{code}
-writeRealC :: _FILE -> AbstractC -> PrimIO ()
+writeRealC :: _FILE -> AbstractC -> IO ()
-writeRealC sw_chker file absC
+writeRealC file absC
= uppAppendFile file 80 (
- uppAbove (pprAbsC (PprForC sw_chker) absC (costs absC)) (uppChar '\n')
+ uppAbove (pprAbsC PprForC absC (costs absC)) (uppChar '\n')
)
dumpRealC :: AbstractC -> String
-dumpRealC sw_chker absC
+dumpRealC absC
= uppShow 80 (
- uppAbove (pprAbsC (PprForC sw_chker) absC (costs absC)) (uppChar '\n')
+ uppAbove (pprAbsC PprForC absC (costs absC)) (uppChar '\n')
)
\end{code}
else "IFN_("),
pprCLabel sty label, uppStr ") {"],
case sty of
- PprForC _ -> uppAbove pp_exts pp_temps
+ PprForC -> uppAbove pp_exts pp_temps
_ -> uppNil,
uppNest 8 (uppPStr SLIT("FB_")),
uppNest 8 (pprAbsC sty abs_C (costs abs_C)),
= BIND (pprTempAndExternDecls stmt) _TO_ (_, pp_exts) ->
uppAboves [
case sty of
- PprForC _ -> pp_exts
+ PprForC -> pp_exts
_ -> uppNil,
uppBesides [
uppStr "SET_STATIC_HDR(",
= BIND (pprTempAndExternDecls stmt) _TO_ (_, pp_exts) ->
uppAboves [
case sty of
- PprForC _ -> pp_exts
+ PprForC -> pp_exts
_ -> uppNil,
uppBesides [ppLocalness label, uppPStr SLIT(" W_ "),
pprCLabel sty label, uppStr "[] = {"],
\begin{code}
if_profiling sty pretty
= case sty of
- PprForC sw_chker -> if sw_chker SccProfilingOn
- then pretty
- else uppChar '0' -- leave it out!
+ PprForC -> if opt_SccProfilingOn
+ then pretty
+ else uppChar '0' -- leave it out!
_ -> {-print it anyway-} pretty
= if (may_gc && liveness_mask /= noLiveRegsMask)
then panic ("Live register in _casm_GC_ \"" ++ casm_str ++ "\" " ++ (uppShow 80 (uppCat pp_non_void_args)) ++ "\n")
else
--- trace ("casm \"" ++ casm_str ++ "\" " ++ (uppShow 80 (uppCat localVars)) ++ (uppShow 80 (uppCat pp_non_void_args)))
uppAboves [
uppChar '{',
declare_local_vars, -- local var for *result*
case readDec other of
[(num,css)] ->
if 0 <= num && num < length args
- then uppBesides [uppLparen, args !! num, uppRparen,
- process ress args css]
+ then uppBeside (uppParens (args !! num))
+ (process ress args css)
else error ("process_casm: no such arg #:"++(show num)++" while processing \"" ++ string ++ "\".\n")
_ -> error ("process_casm: not %<num> while processing _casm_ \"" ++ string ++ "\".\n")
\begin{code}
pprAmode sty amode
| mixedTypeLocn amode
- = uppBesides [ uppLparen, pprPrimKind sty (getAmodeRep amode), uppStr ")(",
- ppr_amode sty amode, uppRparen]
+ = uppParens (uppBesides [ pprPrimKind sty (getAmodeRep amode), uppStr ")(",
+ ppr_amode sty amode ])
| otherwise -- No cast needed
= ppr_amode sty amode
\end{code}
ppr_amode sty (CVal reg_rel _)
= case (pprRegRelative sty False{-no sign wanted-} reg_rel) of
(pp_reg, Nothing) -> uppBeside (uppChar '*') pp_reg
- (pp_reg, Just offset) -> uppBesides [ pp_reg, uppLbrack, offset, uppRbrack ]
+ (pp_reg, Just offset) -> uppBesides [ pp_reg, uppBracket offset ]
ppr_amode sty (CAddr reg_rel)
= case (pprRegRelative sty True{-sign wanted-} reg_rel) of
= case (lookupFM labs x) of { Just _ -> True; Nothing -> False }
addToCLabelSet set x = addToFM set x ()
-type UniqueSet = UniqFM ()
-emptyUniqueSet = emptyUFM
-x `elementOfUniqueSet` us
- = case (lookupDirectlyUFM us x) of { Just _ -> True; Nothing -> False }
-addToUniqueSet set x = set `plusUFM` singletonDirectlyUFM x ()
-
-type TEenv = (UniqueSet, CLabelSet)
+type TEenv = (UniqSet Unique, CLabelSet)
type TeM result = TEenv -> (TEenv, result)
initTE :: TeM a -> a
initTE sa
- = case sa (emptyUniqueSet, emptyCLabelSet) of { (_, result) ->
+ = case sa (emptyUniqSet, emptyCLabelSet) of { (_, result) ->
result }
{-# INLINE thenTE #-}
tempSeenTE :: Unique -> TeM Bool
tempSeenTE uniq env@(seen_uniqs, seen_labels)
- = if (uniq `elementOfUniqueSet` seen_uniqs)
+ = if (uniq `elementOfUniqSet` seen_uniqs)
then (env, True)
- else ((addToUniqueSet seen_uniqs uniq,
+ else ((addOneToUniqSet seen_uniqs uniq,
seen_labels),
False)
pprTempDecl uniq kind
= uppBesides [ pprPrimKind PprDebug kind, uppSP, prettyToUn (pprUnique uniq), uppSemi ]
-ppr_for_C = PprForC ( \ x -> False ) -- pretend no special cmd-line flags
-
pprExternDecl :: CLabel -> PrimRep -> Unpretty
pprExternDecl clabel kind
_ -> ppLocalnessMacro False{-data-} clabel
) _TO_ pp_macro_str ->
- uppBesides [ pp_macro_str, uppLparen, pprCLabel ppr_for_C clabel, pp_paren_semi ]
+ uppBesides [ pp_macro_str, uppLparen, pprCLabel PprForC clabel, pp_paren_semi ]
BEND
\end{code}
--- /dev/null
+%
+% (c) The AQUA Project, Glasgow University, 1996
+%
+\section[FieldLabel]{The @FieldLabel@ type}
+
+\begin{code}
+#include "HsVersions.h"
+
+module FieldLabel where
+
+import Ubiq{-uitous-}
+
+import Name ( Name{-instance Eq/Outputable-} )
+import Type ( Type(..) )
+\end{code}
+
+\begin{code}
+data FieldLabel
+ = FieldLabel Name
+ Type
+ FieldLabelTag
+
+type FieldLabelTag = Int
+
+mkFieldLabel = FieldLabel
+
+firstFieldLabelTag :: FieldLabelTag
+firstFieldLabelTag = 1
+
+allFieldLabelTags :: [FieldLabelTag]
+allFieldLabelTags = [1..]
+
+fieldLabelName (FieldLabel n _ _) = n
+fieldLabelType (FieldLabel _ ty _) = ty
+fieldLabelTag (FieldLabel _ _ tag) = tag
+
+instance Eq FieldLabel where
+ (FieldLabel n1 _ _) == (FieldLabel n2 _ _) = n1 == n2
+
+instance Outputable FieldLabel where
+ ppr sty (FieldLabel n _ _) = ppr sty n
+
+instance NamedThing FieldLabel
+ -- ToDo: fill this in
+\end{code}
idType,
getIdInfo, replaceIdInfo,
getPragmaInfo,
- getIdPrimRep, getInstIdModule,
+ idPrimRep, getInstIdModule,
getMentionedTyConsAndClassesFromId,
- getDataConTag,
- getDataConSig, getInstantiatedDataConSig,
- getDataConTyCon,
+ dataConTag,
+ dataConSig, getInstantiatedDataConSig,
+ dataConTyCon, dataConArity,
+ dataConFieldLabels,
+
+ recordSelectorFieldLabel,
-- PREDICATES
isDataCon, isTupleCon,
-- not exported: apply_to_Id, -- please don't use this, generally
-- UNFOLDING, ARITY, UPDATE, AND STRICTNESS STUFF (etc)
- getIdArity, getDataConArity, addIdArity,
+ getIdArity, addIdArity,
getIdDemandInfo, addIdDemandInfo,
getIdSpecialisation, addIdSpecialisation,
getIdStrictness, addIdStrictness,
import Bag
import Class ( getClassOpString, Class(..), GenClass, ClassOp(..), GenClassOp )
+import CStrings ( identToC, cSEP )
import IdInfo
import Maybes ( maybeToBool )
import NameTypes ( mkShortName, fromPrelude, FullName, ShortName )
+import FieldLabel ( fieldLabelName, FieldLabel{-instances-} )
import Name ( Name(..) )
import Outputable ( isAvarop, isAconop, getLocalName,
isExported, ExportFlag(..) )
import PragmaInfo ( PragmaInfo(..) )
import PrelMods ( pRELUDE_BUILTIN )
-import PprType ( GenType, GenTyVar,
- getTypeString, typeMaybeString, specMaybeTysSuffix )
+import PprType ( getTypeString, typeMaybeString, specMaybeTysSuffix,
+ GenType, GenTyVar
+ )
import PprStyle
import Pretty
import SrcLoc ( mkBuiltinSrcLoc )
-import TyCon ( TyCon, mkTupleTyCon, getTyConDataCons )
+import TyCon ( TyCon, mkTupleTyCon, tyConDataCons )
import Type ( mkSigmaTy, mkTyVarTys, mkFunTys, mkDictTy,
applyTyCon, isPrimType, instantiateTy,
- tyVarsOfType,
+ tyVarsOfType, applyTypeEnvToTy, typePrimRep,
GenType, ThetaType(..), TauType(..), Type(..)
)
-import TyVar ( GenTyVar, alphaTyVars, isEmptyTyVarSet )
+import TyVar ( alphaTyVars, isEmptyTyVarSet, TyVarEnv(..) )
import UniqFM
import UniqSet -- practically all of it
-import Unique ( Unique, mkTupleDataConUnique, pprUnique, showUnique )
-import Util ( mapAccumL, nOfThem, panic, pprPanic, assertPanic )
+import UniqSupply ( getBuiltinUniques )
+import Unique ( mkTupleDataConUnique, pprUnique, showUnique,
+ Unique{-instance Ord3-}
+ )
+import Util ( mapAccumL, nOfThem,
+ panic, panic#, pprPanic, assertPanic
+ )
\end{code}
Here are the @Id@ and @IdDetails@ datatypes; also see the notes that
| DataConId FullName
ConTag
[StrictnessMark] -- Strict args; length = arity
+ [FieldLabel] -- Field labels for this constructor
[TyVar] [(Class,Type)] [Type] TyCon
-- the type is:
| TupleConId Int -- Its arity
+ | RecordSelectorId FieldLabel
+
---------------- Things to do with overloading
| SuperDictSelId -- Selector for superclass dictionary
| InstId ShortName -- An instance of a dictionary, class operation,
-- or overloaded value
+ Bool -- as for LocalId
| SpecId -- A specialisation of another Id
Id -- Id of which this is a specialisation
isDataCon id = is_data (unsafeGenId2Id id)
where
- is_data (Id _ _ (DataConId _ _ _ _ _ _ _) _ _) = True
- is_data (Id _ _ (TupleConId _) _ _) = True
- is_data (Id _ _ (SpecId unspec _ _) _ _) = is_data unspec
- is_data other = False
+ is_data (Id _ _ (DataConId _ _ _ _ _ _ _ _) _ _) = True
+ is_data (Id _ _ (TupleConId _) _ _) = True
+ is_data (Id _ _ (SpecId unspec _ _) _ _) = is_data unspec
+ is_data other = False
isTupleCon id = is_tuple (unsafeGenId2Id id)
toplevelishId (Id _ _ details _ _)
= chk details
where
- chk (DataConId _ _ _ _ _ _ _) = True
- chk (TupleConId _) = True
- chk (ImportedId _) = True
- chk (PreludeId _) = True
- chk (TopLevId _) = True -- NB: see notes
- chk (SuperDictSelId _ _) = True
- chk (MethodSelId _ _) = True
- chk (DefaultMethodId _ _ _) = True
- chk (DictFunId _ _ _ _) = True
- chk (ConstMethodId _ _ _ _ _) = True
- chk (SpecId unspec _ _) = toplevelishId unspec
- -- depends what the unspecialised thing is
- chk (WorkerId unwrkr) = toplevelishId unwrkr
- chk (InstId _) = False -- these are local
- chk (LocalId _ _) = False
- chk (SysLocalId _ _) = False
- chk (SpecPragmaId _ _ _) = False
+ chk (DataConId _ _ _ _ _ _ _ _) = True
+ chk (TupleConId _) = True
+ chk (RecordSelectorId _) = True
+ chk (ImportedId _) = True
+ chk (PreludeId _) = True
+ chk (TopLevId _) = True -- NB: see notes
+ chk (SuperDictSelId _ _) = True
+ chk (MethodSelId _ _) = True
+ chk (DefaultMethodId _ _ _) = True
+ chk (DictFunId _ _ _ _) = True
+ chk (ConstMethodId _ _ _ _ _) = True
+ chk (SpecId unspec _ _) = toplevelishId unspec
+ -- depends what the unspecialised thing is
+ chk (WorkerId unwrkr) = toplevelishId unwrkr
+ chk (InstId _ _) = False -- these are local
+ chk (LocalId _ _) = False
+ chk (SysLocalId _ _) = False
+ chk (SpecPragmaId _ _ _) = False
idHasNoFreeTyVars (Id _ _ details _ info)
= chk details
where
- chk (DataConId _ _ _ _ _ _ _) = True
+ chk (DataConId _ _ _ _ _ _ _ _) = True
chk (TupleConId _) = True
+ chk (RecordSelectorId _) = True
chk (ImportedId _) = True
chk (PreludeId _) = True
chk (TopLevId _) = True
chk (DictFunId _ _ _ _) = True
chk (ConstMethodId _ _ _ _ _) = True
chk (WorkerId unwrkr) = idHasNoFreeTyVars unwrkr
- chk (InstId _) = False -- these are local
+ chk (InstId _ no_free_tvs) = no_free_tvs
chk (SpecId _ _ no_free_tvs) = no_free_tvs
chk (LocalId _ no_free_tvs) = no_free_tvs
chk (SysLocalId _ no_free_tvs) = no_free_tvs
isImportedId (Id _ _ (ImportedId _) _ _) = True
isImportedId other = False
-isBottomingId (Id _ _ _ _ info) = panic "isBottomingId not implemented"
- -- LATER: bottomIsGuaranteed (getInfo info)
+isBottomingId (Id _ _ _ _ info) = bottomIsGuaranteed (getInfo info)
isSysLocalId (Id _ _ (SysLocalId _ _) _ _) = True
isSysLocalId other = False
else if v == nilDataCon then
ppPStr SLIT("_NIL_")
else if isTupleCon v then
- ppBeside (ppPStr SLIT("_TUP_")) (ppInt (getDataConArity v))
+ ppBeside (ppPStr SLIT("_TUP_")) (ppInt (dataConArity v))
-- ones to think about:
else
-- these ones' exportedness checked later...
TopLevId _ -> pp_full_name
- DataConId _ _ _ _ _ _ _ -> pp_full_name
+ DataConId _ _ _ _ _ _ _ _ -> pp_full_name
+
+ RecordSelectorId lbl -> ppr sty lbl
-- class-ish things: class already recorded as "mentioned"
SuperDictSelId c sc
-- TyVar(Templates) in the i/face; only a problem
-- if -fshow-pragma-name-errs; but we can do without the pain.
-- A HACK in any case (WDP 94/05/02)
- = --pprTrace "unfriendly1:" (ppCat [ppr PprDebug d, ppr PprDebug t]) (
- naughty_DictFunId dfun
- --)
+ = naughty_DictFunId dfun
unfoldingUnfriendlyId d@(Id _ _ dfun@(DictFunId _ t _ _) _ _)
- = --pprTrace "unfriendly2:" (ppCat [ppr PprDebug d, ppr PprDebug t]) (
- naughty_DictFunId dfun -- similar deal...
- --)
+ = naughty_DictFunId dfun -- similar deal...
unfoldingUnfriendlyId other_id = False -- is friendly in all other cases
\begin{code}
externallyVisibleId :: Id -> Bool
-externallyVisibleId id = panic "Id.externallyVisibleId"
-{-LATER:
-
externallyVisibleId id@(Id _ _ details _ _)
= if isLocallyDefined id then
toplevelishId id && isExported id && not (weird_datacon details)
-- of WeirdLocalType; but we need to know this when asked if
-- "Mumble" is externally visible...
- weird_datacon (DataConId _ _ _ _ _ _ tycon)
+{- LATER: if at all:
+ weird_datacon (DataConId _ _ _ _ _ _ _ tycon)
= maybeToBool (maybePurelyLocalTyCon tycon)
+-}
weird_datacon not_a_datacon_therefore_not_weird = False
weird_tuplecon (TupleConId arity)
= arity > 32 -- sigh || isBigTupleTyCon tycon -- generated *purely* for local use
weird_tuplecon _ = False
--}
\end{code}
\begin{code}
idWantsToBeINLINEd :: Id -> Bool
-idWantsToBeINLINEd id
- = panic "Id.idWantsToBeINLINEd"
-{- LATER:
- = case (getIdUnfolding id) of
- IWantToBeINLINEd _ -> True
- _ -> False
--}
+idWantsToBeINLINEd (Id _ _ _ IWantToBeINLINEd _) = True
+idWantsToBeINLINEd _ = False
\end{code}
For @unlocaliseId@: See the brief commentary in
Nothing -> Nothing
Just xx -> Just (Id u ty info (WorkerId xx))
-unlocaliseId mod (Id u ty info (InstId name))
+unlocaliseId mod (Id u ty info (InstId name no_ftvs))
= Just (Id u ty info (TopLevId full_name))
-- type might be wrong, but it hardly matters
-- at this stage (just before printing C) ToDo
former ``should be'' the usual crunch point.
\begin{code}
-{-LATER:
+type TypeEnv = TyVarEnv Type
+
applyTypeEnvToId :: TypeEnv -> Id -> Id
-applyTypeEnvToId type_env id@(Id u ty info details)
+applyTypeEnvToId type_env id@(Id _ ty _ _ _)
| idHasNoFreeTyVars id
= id
| otherwise
= apply_to_Id ( \ ty ->
applyTypeEnvToTy type_env ty
) id
--}
\end{code}
\begin{code}
-{-LATER:
apply_to_Id :: (Type -> Type)
-> Id
-> Id
-apply_to_Id ty_fn (Id u ty info details)
- = Id u (ty_fn ty) (apply_to_IdInfo ty_fn info) (apply_to_details details)
+apply_to_Id ty_fn (Id u ty details prag info)
+ = let
+ new_ty = ty_fn ty
+ in
+ Id u new_ty (apply_to_details details) prag (apply_to_IdInfo ty_fn info)
where
- apply_to_details (InstId inst)
- = let
- new_inst = apply_to_Inst ty_fn inst
- in
- InstId new_inst
-
apply_to_details (SpecId unspec ty_maybes no_ftvs)
= let
new_unspec = apply_to_Id ty_fn unspec
new_maybes = map apply_to_maybe ty_maybes
in
- SpecId new_unspec new_maybes no_ftvs
- -- ToDo: recalc no_ftvs????
+ SpecId new_unspec new_maybes (no_free_tvs ty)
+ -- ToDo: gratuitous recalc no_ftvs???? (also InstId)
where
apply_to_maybe Nothing = Nothing
apply_to_maybe (Just ty) = Just (ty_fn ty)
WorkerId new_unwrkr
apply_to_details other = other
--}
\end{code}
Sadly, I don't think the one using the magic typechecker substitution
case (apply_to_details s3 new_ty details) of { (s4, new_details) ->
(s4, Id u new_ty new_info new_details) }}}
where
- apply_to_details subst _ (InstId inst)
+ apply_to_details subst _ (InstId inst no_ftvs)
= case (applySubstToInst subst inst) of { (s2, new_inst) ->
- (s2, InstId new_inst) }
+ (s2, InstId new_inst no_ftvs{-ToDo:right???-}) }
apply_to_details subst new_ty (SpecId unspec ty_maybes _)
= case (applySubstToId subst unspec) of { (s2, new_unspec) ->
\begin{code}
getIdNamePieces :: Bool {-show Uniques-} -> GenId ty -> [FAST_STRING]
+
getIdNamePieces show_uniqs id
= get (unsafeGenId2Id id)
where
get (Id u _ details _ _)
= case details of
- DataConId n _ _ _ _ _ _ ->
+ DataConId n _ _ _ _ _ _ _ ->
case (getOrigName n) of { (mod, name) ->
if fromPrelude mod then [name] else [mod, name] }
TupleConId 0 -> [SLIT("()")]
TupleConId a -> [_PK_ ( "(" ++ nOfThem (a-1) ',' ++ ")" )]
+ RecordSelectorId lbl -> panic "getIdNamePieces:RecordSelectorId"
+
ImportedId n -> get_fullname_pieces n
PreludeId n -> get_fullname_pieces n
TopLevId n -> get_fullname_pieces n
LocalId n _ -> let local = getLocalName n in
if show_uniqs then [local, showUnique u] else [local]
- InstId n -> [getLocalName n, showUnique u]
+ InstId n _ -> [getLocalName n, showUnique u]
SysLocalId n _ -> [getLocalName n, showUnique u]
SpecPragmaId n _ _ -> [getLocalName n, showUnique u]
\end{code}
\begin{code}
---getIdPrimRep i = primRepFromType (idType i)
+idPrimRep i = typePrimRep (idType i)
\end{code}
\begin{code}
mkWorkerId u unwrkr ty info = Id u ty (WorkerId unwrkr) NoPragmaInfo info
-mkInstId uniq ty name = Id uniq ty (InstId name) NoPragmaInfo noIdInfo
+mkInstId uniq ty name = Id uniq ty (InstId name (no_free_tvs ty)) NoPragmaInfo noIdInfo
{-LATER:
getConstMethodId clas op ty
in
case (lookupConstMethodId (getIdSpecialisation sel_id) ty) of
Just xx -> xx
- Nothing -> error (ppShow 80 (ppAboves [
- ppCat [ppStr "ERROR: getConstMethodId:", ppr PprDebug op,
- ppr PprDebug ty, ppr PprDebug ops, ppr PprDebug op_ids,
+ Nothing -> pprError "ERROR: getConstMethodId:" (ppAboves [
+ ppCat [ppr PprDebug ty, ppr PprDebug ops, ppr PprDebug op_ids,
ppr PprDebug sel_id],
ppStr "(This can arise if an interface pragma refers to an instance",
ppStr "but there is no imported interface which *defines* that instance.",
ppStr "The info above, however ugly, should indicate what else you need to import."
- ]))
+ ])
-}
\end{code}
where
new_ty = specialiseTy ty ty_maybes 0
- -- pprTrace "SameSpecCon:Unique:"
- -- (ppSep (ppr PprDebug unspec: [pprMaybeTy PprDebug ty | ty <- ty_maybes]))
-
localiseId :: Id -> Id
localiseId id@(Id u ty info details)
= Id u ty info (LocalId (mkShortName name loc) (no_free_tvs ty))
where
name = getOccurrenceName id
loc = getSrcLoc id
+-}
--- this has to be one of the "local" flavours (LocalId, SysLocalId, InstId)
--- ToDo: it does??? WDP
mkIdWithNewUniq :: Id -> Unique -> Id
-mkIdWithNewUniq (Id _ ty info details) uniq
- = Id uniq ty info new_details
--}
+mkIdWithNewUniq (Id _ ty details prag info) uniq
+ = Id uniq ty details prag info
\end{code}
Make some local @Ids@ for a template @CoreExpr@. These have bogus
@Uniques@, but that's OK because the templates are supposed to be
instantiated before use.
\begin{code}
-{-LATER:
mkTemplateLocals :: [Type] -> [Id]
mkTemplateLocals tys
- = zipWith (\ u -> \ ty -> mkSysLocal SLIT("tpl") u ty mkUnknownSrcLoc)
+ = zipWith (\ u -> \ ty -> mkSysLocal SLIT("tpl") u ty mkBuiltinSrcLoc)
(getBuiltinUniques (length tys))
tys
--}
\end{code}
\begin{code}
getIdArity :: Id -> ArityInfo
getIdArity (Id _ _ _ _ id_info) = getInfo id_info
-getDataConArity :: DataCon -> Int
-getDataConArity id@(Id _ _ _ _ id_info)
+dataConArity :: DataCon -> Int
+dataConArity id@(Id _ _ _ _ id_info)
= ASSERT(isDataCon id)
case (arityMaybe (getInfo id_info)) of
- Nothing -> pprPanic "getDataConArity:Nothing:" (ppr PprDebug id)
+ Nothing -> pprPanic "dataConArity:Nothing:" (pprId PprDebug id)
Just i -> i
addIdArity :: Id -> Int -> Id
\begin{code}
mkDataCon :: Unique{-DataConKey-}
-> FullName
- -> [StrictnessMark]
+ -> [StrictnessMark] -> [FieldLabel]
-> [TyVar] -> ThetaType -> [TauType] -> TyCon
--ToDo: -> SpecEnv
-> Id
-- can get the tag and all the pieces of the type from the Type
-mkDataCon k n stricts tvs ctxt args_tys tycon
+mkDataCon k n stricts fields tvs ctxt args_tys tycon
= ASSERT(length stricts == length args_tys)
data_con
where
data_con
= Id k
type_of_constructor
- (DataConId n data_con_tag stricts tvs ctxt args_tys tycon)
+ (DataConId n data_con_tag stricts fields tvs ctxt args_tys tycon)
NoPragmaInfo
datacon_info
data_con_tag = position_within fIRST_TAG data_con_family
- data_con_family = getTyConDataCons tycon
+ data_con_family = tyConDataCons tycon
position_within :: Int -> [Id] -> Int
\end{code}
\begin{code}
-getDataConTag :: DataCon -> ConTag -- will panic if not a DataCon
-getDataConTag (Id _ _ (DataConId _ tag _ _ _ _ _) _ _) = tag
-getDataConTag (Id _ _ (TupleConId _) _ _) = fIRST_TAG
-getDataConTag (Id _ _ (SpecId unspec _ _) _ _) = getDataConTag unspec
+dataConTag :: DataCon -> ConTag -- will panic if not a DataCon
+dataConTag (Id _ _ (DataConId _ tag _ _ _ _ _ _) _ _) = tag
+dataConTag (Id _ _ (TupleConId _) _ _) = fIRST_TAG
+dataConTag (Id _ _ (SpecId unspec _ _) _ _) = dataConTag unspec
-getDataConTyCon :: DataCon -> TyCon -- will panic if not a DataCon
-getDataConTyCon (Id _ _ (DataConId _ _ _ _ _ _ tycon) _ _) = tycon
-getDataConTyCon (Id _ _ (TupleConId a) _ _) = mkTupleTyCon a
+dataConTyCon :: DataCon -> TyCon -- will panic if not a DataCon
+dataConTyCon (Id _ _ (DataConId _ _ _ _ _ _ _ tycon) _ _) = tycon
+dataConTyCon (Id _ _ (TupleConId a) _ _) = mkTupleTyCon a
-getDataConSig :: DataCon -> ([TyVar], ThetaType, [TauType], TyCon)
+dataConSig :: DataCon -> ([TyVar], ThetaType, [TauType], TyCon)
-- will panic if not a DataCon
-getDataConSig (Id _ _ (DataConId _ _ _ tyvars theta_ty arg_tys tycon) _ _)
+dataConSig (Id _ _ (DataConId _ _ _ _ tyvars theta_ty arg_tys tycon) _ _)
= (tyvars, theta_ty, arg_tys, tycon)
-getDataConSig (Id _ _ (TupleConId arity) _ _)
+dataConSig (Id _ _ (TupleConId arity) _ _)
= (tyvars, [], tyvar_tys, mkTupleTyCon arity)
where
tyvars = take arity alphaTyVars
tyvar_tys = mkTyVarTys tyvars
+
+dataConFieldLabels :: DataCon -> [FieldLabel]
+dataConFieldLabels (Id _ _ (DataConId _ _ _ fields _ _ _ _) _ _) = fields
+\end{code}
+
+\begin{code}
+mkRecordSelectorId field_label selector_ty
+ = Id (getItsUnique name)
+ selector_ty
+ (RecordSelectorId field_label)
+ NoPragmaInfo
+ noIdInfo
+ where
+ name = fieldLabelName field_label
+
+recordSelectorFieldLabel :: Id -> FieldLabel
+recordSelectorFieldLabel (Id _ _ (RecordSelectorId lbl) _ _) = lbl
\end{code}
{- LATER
-getDataConTyCon (Id _ _ _ (SpecId unspec tys _))
- = mkSpecTyCon (getDataConTyCon unspec) tys
+dataConTyCon (Id _ _ _ (SpecId unspec tys _))
+ = mkSpecTyCon (dataConTyCon unspec) tys
-getDataConSig (Id _ _ _ (SpecId unspec ty_maybes _))
+dataConSig (Id _ _ _ (SpecId unspec ty_maybes _))
= (spec_tyvars, spec_theta_ty, spec_arg_tys, spec_tycon)
where
- (tyvars, theta_ty, arg_tys, tycon) = getDataConSig unspec
+ (tyvars, theta_ty, arg_tys, tycon) = dataConSig unspec
ty_env = tyvars `zip` ty_maybes
spec_arg_tys = map (instantiateTauTy spec_env) arg_tys
spec_theta_ty = if null theta_ty then []
- else panic "getDataConSig:ThetaTy:SpecDataCon"
+ else panic "dataConSig:ThetaTy:SpecDataCon"
spec_tycon = mkSpecTyCon tycon ty_maybes
-}
\end{code}
getInstantiatedDataConSig data_con inst_tys
= ASSERT(isDataCon data_con)
let
- (tvs, theta, arg_tys, tycon) = getDataConSig data_con
+ (tvs, theta, arg_tys, tycon) = dataConSig data_con
inst_env = ASSERT(length tvs == length inst_tys)
tvs `zip` inst_tys
unspecialised counterpart.
\begin{code}
-{-LATER:
cmpId_withSpecDataCon :: Id -> Id -> TAG_
cmpId_withSpecDataCon id1 id2
cmp_ids = cmpId id1 id2
eq_ids = case cmp_ids of { EQ_ -> True; other -> False }
-cmpEqDataCon (Id _ _ _ (SpecId _ mtys1 _)) (Id _ _ _ (SpecId _ mtys2 _))
- = cmpUniTypeMaybeList mtys1 mtys2
-
-cmpEqDataCon unspec1 (Id _ _ _ (SpecId _ _ _))
- = LT_
-
-cmpEqDataCon (Id _ _ _ (SpecId _ _ _)) unspec2
- = GT_
+cmpEqDataCon (Id _ _ (SpecId _ mtys1 _) _ _) (Id _ _ (SpecId _ mtys2 _) _ _)
+ = panic# "Id.cmpEqDataCon:cmpUniTypeMaybeList mtys1 mtys2"
-cmpEqDataCon unspec1 unspec2
- = EQ_
--}
+cmpEqDataCon _ (Id _ _ (SpecId _ _ _) _ _) = LT_
+cmpEqDataCon (Id _ _ (SpecId _ _ _) _ _) _ = GT_
+cmpEqDataCon _ _ = EQ_
\end{code}
%************************************************************************
instance Outputable ty => Outputable (GenId ty) where
ppr sty id = pprId sty id
+-- and a SPECIALIZEd one:
+instance Outputable {-Id, i.e.:-}(GenId Type) where
+ ppr sty id = pprId sty id
+
showId :: PprStyle -> Id -> String
showId sty id = ppShow 80 (pprId sty id)
= let
pieces = getIdNamePieces (case other_sty of {PprForUser -> False; _ -> True}) id
- for_code = panic "pprId: for code"
- {- = let
+ for_code
+ = let
pieces_to_print -- maybe use Unique only
= if isSysLocalId id then tail pieces else pieces
in
ppIntersperse (ppPStr cSEP) (map identToC pieces_to_print)
- -}
in
case other_sty of
PprForC -> for_code
= ppBeside (pp_ubxd (ppIntersperse (ppChar '.') (map ppPStr pieces))) (pp_uniq id)
pp_uniq (Id _ _ (PreludeId _) _ _) = ppNil -- no uniq to add
- pp_uniq (Id _ _ (DataConId _ _ _ _ _ _ _) _ _) = ppNil
+ pp_uniq (Id _ _ (DataConId _ _ _ _ _ _ _ _) _ _) = ppNil
pp_uniq (Id _ _ (TupleConId _) _ _) = ppNil
pp_uniq (Id _ _ (LocalId _ _) _ _) = ppNil -- uniq printed elsewhere
pp_uniq (Id _ _ (SysLocalId _ _) _ _) = ppNil
pp_uniq (Id _ _ (SpecPragmaId _ _ _) _ _) = ppNil
- pp_uniq (Id _ _ (InstId _) _ _) = ppNil
+ pp_uniq (Id _ _ (InstId _ _) _ _) = ppNil
pp_uniq other_id = ppBesides [ppPStr SLIT("{-"), pprUnique (getItsUnique other_id), ppPStr SLIT("-}")]
-- print PprDebug Ids with # afterwards if they are of primitive type.
getExportFlag (Id _ _ details _ _)
= get details
where
- get (DataConId _ _ _ _ _ _ tc)= getExportFlag tc -- NB: don't use the FullName
+ get (DataConId _ _ _ _ _ _ _ tc)= getExportFlag tc -- NB: don't use the FullName
get (TupleConId _) = NotExported
+ get (RecordSelectorId l) = getExportFlag l
get (ImportedId n) = getExportFlag n
get (PreludeId n) = getExportFlag n
get (TopLevId n) = getExportFlag n
get (ConstMethodId c ty _ from_here _) = instance_export_flag c ty from_here
get (SpecId unspec _ _) = getExportFlag unspec
get (WorkerId unwrkr) = getExportFlag unwrkr
- get (InstId _) = NotExported
+ get (InstId _ _) = NotExported
get (LocalId _ _) = NotExported
get (SysLocalId _ _) = NotExported
get (SpecPragmaId _ _ _) = NotExported
isLocallyDefined this_id@(Id _ _ details _ _)
= get details
where
- get (DataConId _ _ _ _ _ _ tc)= isLocallyDefined tc -- NB: don't use the FullName
+ get (DataConId _ _ _ _ _ _ _ tc)= isLocallyDefined tc -- NB: don't use the FullName
get (TupleConId _) = False
get (ImportedId _) = False
get (PreludeId _) = False
+ get (RecordSelectorId l) = isLocallyDefined l
get (TopLevId n) = isLocallyDefined n
get (SuperDictSelId c _) = isLocallyDefined c
get (MethodSelId c _) = isLocallyDefined c
get (ConstMethodId c tyc _ from_here _) = from_here
get (SpecId unspec _ _) = isLocallyDefined unspec
get (WorkerId unwrkr) = isLocallyDefined unwrkr
- get (InstId _) = True
+ get (InstId _ _) = True
get (LocalId _ _) = True
get (SysLocalId _ _) = True
get (SpecPragmaId _ _ _) = True
getOrigName this_id@(Id u _ details _ _)
= get details
where
- get (DataConId n _ _ _ _ _ _) = getOrigName n
+ get (DataConId n _ _ _ _ _ _ _) = getOrigName n
get (TupleConId 0) = (pRELUDE_BUILTIN, SLIT("()"))
get (TupleConId a) = (pRELUDE_BUILTIN, _PK_ ( "(" ++ nOfThem (a-1) ',' ++ ")" ))
+ get (RecordSelectorId l)= getOrigName l
get (ImportedId n) = getOrigName n
get (PreludeId n) = getOrigName n
get (TopLevId n) = getOrigName n
BEND
-}
- get (InstId n) = (panic "NamedThing.Id.getOrigName (LocalId)",
+ get (InstId n _) = (panic "NamedThing.Id.getOrigName (LocalId)",
getLocalName n)
get (LocalId n _) = (panic "NamedThing.Id.getOrigName (LocalId)",
getLocalName n)
getOccurrenceName this_id@(Id _ _ details _ _)
= get details
where
- get (DataConId n _ _ _ _ _ _) = getOccurrenceName n
+ get (DataConId n _ _ _ _ _ _ _) = getOccurrenceName n
get (TupleConId 0) = SLIT("()")
get (TupleConId a) = _PK_ ( "(" ++ nOfThem (a-1) ',' ++ ")" )
+ get (RecordSelectorId l)= getOccurrenceName l
get (ImportedId n) = getOccurrenceName n
get (PreludeId n) = getOccurrenceName n
get (TopLevId n) = getOccurrenceName n
getSrcLoc (Id _ _ details _ id_info)
= get details
where
- get (DataConId n _ _ _ _ _ _) = getSrcLoc n
+ get (DataConId n _ _ _ _ _ _ _) = getSrcLoc n
get (TupleConId _) = mkBuiltinSrcLoc
+ get (RecordSelectorId l)= getSrcLoc l
get (ImportedId n) = getSrcLoc n
get (PreludeId n) = getSrcLoc n
get (TopLevId n) = getSrcLoc n
get (MethodSelId c _) = getSrcLoc c
get (SpecId unspec _ _) = getSrcLoc unspec
get (WorkerId unwrkr) = getSrcLoc unwrkr
- get (InstId n) = getSrcLoc n
+ get (InstId n _) = getSrcLoc n
get (LocalId n _) = getSrcLoc n
get (SysLocalId n _) = getSrcLoc n
get (SpecPragmaId n _ _)= getSrcLoc n
fromPreludeCore (Id _ _ details _ _)
= get details
where
- get (DataConId _ _ _ _ _ _ tc)= fromPreludeCore tc -- NB: not from the FullName
+ get (DataConId _ _ _ _ _ _ _ tc)= fromPreludeCore tc -- NB: not from the FullName
get (TupleConId _) = True
+ get (RecordSelectorId l) = fromPreludeCore l
get (ImportedId n) = fromPreludeCore n
get (PreludeId n) = fromPreludeCore n
get (TopLevId n) = fromPreludeCore n
get (ConstMethodId c t _ _ _) = fromPreludeCore c && is_prelude_core_ty t
get (SpecId unspec _ _) = fromPreludeCore unspec
get (WorkerId unwrkr) = fromPreludeCore unwrkr
- get (InstId _) = False
+ get (InstId _ _) = False
get (LocalId _ _) = False
get (SysLocalId _ _) = False
get (SpecPragmaId _ _ _) = False
mkIdEnv = listToUFM
nullIdEnv = emptyUFM
rngIdEnv = eltsUFM
-unitIdEnv = singletonUFM
+unitIdEnv = unitUFM
growIdEnvList env pairs = plusUFM env (listToUFM pairs)
isNullIdEnv env = sizeUFM env == 0
unionIdSets :: GenIdSet ty -> GenIdSet ty -> GenIdSet ty
unionManyIdSets :: [GenIdSet ty] -> GenIdSet ty
idSetToList :: GenIdSet ty -> [GenId ty]
-singletonIdSet :: GenId ty -> GenIdSet ty
+unitIdSet :: GenId ty -> GenIdSet ty
+addOneToIdSet :: GenIdSet ty -> GenId ty -> GenIdSet ty
elementOfIdSet :: GenId ty -> GenIdSet ty -> Bool
minusIdSet :: GenIdSet ty -> GenIdSet ty -> GenIdSet ty
isEmptyIdSet :: GenIdSet ty -> Bool
mkIdSet :: [GenId ty] -> GenIdSet ty
emptyIdSet = emptyUniqSet
-singletonIdSet = singletonUniqSet
+unitIdSet = unitUniqSet
+addOneToIdSet = addOneToUniqSet
intersectIdSets = intersectUniqSets
unionIdSets = unionUniqSets
unionManyIdSets = unionManyUniqSets
import CmdLineOpts ( opt_OmitInterfacePragmas )
import Maybes ( firstJust )
-import MatchEnv ( nullMEnv, mEnvToList )
+import MatchEnv ( nullMEnv, isEmptyMEnv, mEnvToList )
import Outputable ( ifPprInterface, Outputable(..){-instances-} )
import PprStyle ( PprStyle(..) )
import Pretty
import Util ( mapAccumL, panic, assertPanic, pprPanic )
applySubstToTy = panic "IdInfo.applySubstToTy"
-isUnboxedDataType = panic "IdInfo.isUnboxedDataType"
splitTypeWithDictsAsArgs = panic "IdInfo.splitTypeWithDictsAsArgs"
showTypeCategory = panic "IdInfo.showTypeCategory"
mkFormSummary = panic "IdInfo.mkFormSummary"
will in turn @apply_to_IdInfo@ of the self-same @IdInfo@. (A very
nasty loop, friends...)
\begin{code}
-apply_to_IdInfo ty_fn (IdInfo arity demand spec strictness unfold
+apply_to_IdInfo ty_fn idinfo@(IdInfo arity demand spec strictness unfold
update deforest arg_usage fb_ww srcloc)
+ | isEmptyMEnv spec
+ = idinfo
+ | otherwise
= panic "IdInfo:apply_to_IdInfo"
{- LATER:
let
)
import IdInfo ( IdInfo )
import Literal ( Literal )
-import MagicUFs ( MagicUnfoldingFun )
+import MagicUFs ( mkMagicUnfoldingFun, MagicUnfoldingFun )
import Outputable ( Outputable(..) )
import PprStyle ( PprStyle )
-import PprType ( pprParendType )
+import PprType ( pprParendGenType )
import Pretty ( PrettyRep )
import Type ( GenType )
import TyVar ( GenTyVar )
nullIdEnv :: UniqFM a
lookupIdEnv :: UniqFM b -> GenId a -> Maybe b
mAX_WORKER_ARGS :: Int
-pprParendType :: (Eq a, Outputable a, Eq b, Outputable b) => PprStyle -> GenType a b -> Int -> Bool -> PrettyRep
+pprParendGenType :: (Eq a, Outputable a, Eq b, Outputable b) => PprStyle -> GenType a b -> Int -> Bool -> PrettyRep
unTagBinders :: GenCoreExpr (GenId (GenType (GenTyVar (GenUsage Unique)) Unique), a) b c d -> GenCoreExpr (GenId (GenType (GenTyVar (GenUsage Unique)) Unique)) b c d
+mkMagicUnfoldingFun :: Unique -> MagicUnfoldingFun
+
type IdEnv a = UniqFM a
type CoreExpr = GenCoreExpr (GenId (GenType (GenTyVar (GenUsage Unique)) Unique))
(GenId (GenType (GenTyVar (GenUsage Unique)) Unique))
import Pretty
import PprStyle ( PprStyle(..) )
import SrcLoc ( mkBuiltinSrcLoc, mkUnknownSrcLoc )
-import TyCon ( TyCon, getSynTyConArity )
+import TyCon ( TyCon, synTyConArity )
import TyVar ( GenTyVar )
import Unique ( pprUnique, Unique )
import Util ( panic, panic#, pprPanic )
getSynNameArity :: Name -> Maybe Arity
getSynNameArity (TyConName _ _ arity False{-syn-} _) = Just arity
-getSynNameArity (WiredInTyCon tycon) = getSynTyConArity tycon
+getSynNameArity (WiredInTyCon tycon) = synTyConArity tycon
getSynNameArity other_name = Nothing
getNameShortName :: Name -> ShortName
--- /dev/null
+%
+% (c) The AQUA Project, Glasgow University, 1996
+%
+\section[PprEnv]{The @PprEnv@ type}
+
+\begin{code}
+#include "HsVersions.h"
+
+module PprEnv (
+ PprEnv{-abstract-},
+
+ initPprEnv,
+
+ pCon, pLit, pMajBndr, pMinBndr, pOcc, pPrim, pSCC, pStyle,
+ pTy, pTyVar, pUVar, pUse
+ ) where
+
+import Ubiq{-uitous-}
+
+import Id ( DataCon(..) )
+import Pretty ( Pretty(..) )
+import Util ( panic )
+\end{code}
+
+For tyvars and uvars, we {\em do} normally use these homogenized
+names; for values, we {\em don't}. In printing interfaces, though,
+we use homogenized value names, so that interfaces don't wobble
+uncontrollably from changing Unique-based names.
+
+\begin{code}
+data PprEnv tyvar uvar bndr occ
+ = PE PprStyle -- stored for safe keeping
+
+ (Literal -> Pretty) -- Doing these this way saves
+ (DataCon -> Pretty) -- carrying around a PprStyle
+ (PrimOp -> Pretty)
+ (CostCentre -> Pretty)
+
+ (tyvar -> Pretty) -- to print tyvars
+ (uvar -> Pretty) -- to print usage vars
+
+ (bndr -> Pretty) -- to print "major" val_bdrs
+ (bndr -> Pretty) -- to print "minor" val_bdrs
+ (occ -> Pretty) -- to print bindees
+
+ (GenType tyvar uvar -> Pretty)
+ (GenUsage uvar -> Pretty)
+\end{code}
+
+\begin{code}
+initPprEnv
+ :: PprStyle
+ -> Maybe (Literal -> Pretty)
+ -> Maybe (DataCon -> Pretty)
+ -> Maybe (PrimOp -> Pretty)
+ -> Maybe (CostCentre -> Pretty)
+ -> Maybe (tyvar -> Pretty)
+ -> Maybe (uvar -> Pretty)
+ -> Maybe (bndr -> Pretty)
+ -> Maybe (bndr -> Pretty)
+ -> Maybe (occ -> Pretty)
+ -> Maybe (GenType tyvar uvar -> Pretty)
+ -> Maybe (GenUsage uvar -> Pretty)
+ -> PprEnv tyvar uvar bndr occ
+
+-- you can specify all the printers individually; if
+-- you don't specify one, you get bottom
+
+initPprEnv sty l d p c tv uv maj_bndr min_bndr occ ty use
+ = PE sty
+ (demaybe l)
+ (demaybe d)
+ (demaybe p)
+ (demaybe c)
+ (demaybe tv)
+ (demaybe uv)
+ (demaybe maj_bndr)
+ (demaybe min_bndr)
+ (demaybe occ)
+ (demaybe ty)
+ (demaybe use)
+ where
+ demaybe Nothing = bottom
+ demaybe (Just x) = x
+
+ bottom = panic "PprEnv.initPprEnv: unspecified printing function"
+
+{-
+initPprEnv sty pmaj pmin pocc
+ = PE (ppr sty) -- for a Literal
+ (ppr sty) -- for a DataCon
+ (ppr sty) -- for a PrimOp
+ (\ cc -> ppStr (showCostCentre sty True cc)) -- CostCentre
+
+ (ppr sty) -- for a tyvar
+ (ppr sty) -- for a usage var
+
+ pmaj pmin pocc -- for GenIds in various guises
+
+ (ppr sty) -- for a Type
+ (ppr sty) -- for a Usage
+-}
+\end{code}
+
+\begin{code}
+pStyle (PE s _ _ _ _ _ _ _ _ _ _ _) = s
+pLit (PE _ pp _ _ _ _ _ _ _ _ _ _) = pp
+pCon (PE _ _ pp _ _ _ _ _ _ _ _ _) = pp
+pPrim (PE _ _ _ pp _ _ _ _ _ _ _ _) = pp
+pSCC (PE _ _ _ _ pp _ _ _ _ _ _ _) = pp
+
+pTyVar (PE _ _ _ _ _ pp _ _ _ _ _ _) = pp
+pUVar (PE _ _ _ _ _ _ pp _ _ _ _ _) = pp
+
+pMajBndr (PE _ _ _ _ _ _ _ pp _ _ _ _) = pp
+pMinBndr (PE _ _ _ _ _ _ _ _ pp _ _ _) = pp
+pOcc (PE _ _ _ _ _ _ _ _ _ pp _ _) = pp
+
+pTy (PE _ _ _ _ _ _ _ _ _ _ pp _) = pp
+pUse (PE _ _ _ _ _ _ _ _ _ _ _ pp) = pp
+\end{code}
UniqSM(..), -- type: unique supply monad
initUs, thenUs, returnUs,
mapUs, mapAndUnzipUs, mapAndUnzip3Us,
+ thenMaybeUs, mapAccumLUs,
mkSplitUniqSupply,
splitUniqSupply,
= f x `thenUs` \ (r1, r2, r3) ->
mapAndUnzip3Us f xs `thenUs` \ (rs1, rs2, rs3) ->
returnUs (r1:rs1, r2:rs2, r3:rs3)
+
+thenMaybeUs :: UniqSM (Maybe a) -> (a -> UniqSM (Maybe b)) -> UniqSM (Maybe b)
+thenMaybeUs m k
+ = m `thenUs` \ result ->
+ case result of
+ Nothing -> returnUs Nothing
+ Just x -> k x
+
+mapAccumLUs :: (acc -> x -> UniqSM (acc, y))
+ -> acc
+ -> [x]
+ -> UniqSM (acc, [y])
+
+mapAccumLUs f b [] = returnUs (b, [])
+mapAccumLUs f b (x:xs)
+ = f b x `thenUs` \ (b__2, x__2) ->
+ mapAccumLUs f b__2 xs `thenUs` \ (b__3, xs__2) ->
+ returnUs (b__3, x__2:xs__2)
\end{code}
%************************************************************************
module CgBindery (
CgBindings(..), CgIdInfo(..){-dubiously concrete-},
- StableLoc, VolatileLoc, LambdaFormInfo{-re-exported-},
+ StableLoc, VolatileLoc,
maybeAStkLoc, maybeBStkLoc,
bindNewToAStack, bindNewToBStack,
bindNewToNode, bindNewToReg, bindArgsToRegs,
bindNewToTemp, bindNewPrimToAmode,
- getAtomAmode, getAtomAmodes,
+ getArgAmode, getArgAmodes,
getCAddrModeAndInfo, getCAddrMode,
getCAddrModeIfVolatile, getVolatileRegs,
rebindToAStack, rebindToBStack
-
- -- and to make a self-sufficient interface...
) where
+import Ubiq{-uitous-}
+import CgLoop1 -- here for paranoia-checking
+
import AbsCSyn
import CgMonad
import CgUsages ( getHpRelOffset, getSpARelOffset, getSpBRelOffset )
-import CLabel ( mkClosureLabel, CLabel )
-import ClosureInfo
-import Id ( getIdPrimRep, toplevelishId, isDataCon, Id )
-import Maybes ( catMaybes, Maybe(..) )
-import UniqSet -- ( setToList )
-import StgSyn
-import Util
+import CLabel ( mkClosureLabel )
+import ClosureInfo ( mkLFImported, mkConLFInfo, mkLFArgument )
+import HeapOffs ( VirtualHeapOffset(..),
+ VirtualSpAOffset(..), VirtualSpBOffset(..)
+ )
+import Id ( idPrimRep, toplevelishId, isDataCon,
+ mkIdEnv, rngIdEnv, IdEnv(..),
+ idSetToList,
+ GenId{-instance NamedThing-}
+ )
+import Maybes ( catMaybes )
+import PprAbsC ( pprAmode )
+import PprStyle ( PprStyle(..) )
+import StgSyn ( StgArg(..), StgLiveVars(..), GenStgArg(..) )
+import Unpretty ( uppShow )
+import Util ( zipWithEqual, panic )
\end{code}
= (temp_amode, temp_idinfo)
where
uniq = getItsUnique name
- temp_amode = CTemp uniq (getIdPrimRep name)
+ temp_amode = CTemp uniq (idPrimRep name)
temp_idinfo = tempIdInfo name uniq lf_info
-idInfoToAmode :: PrimKind -> CgIdInfo -> FCode CAddrMode
+idInfoToAmode :: PrimRep -> CgIdInfo -> FCode CAddrMode
idInfoToAmode kind (MkCgIdInfo _ vol stab _) = idInfoPiecesToAmode kind vol stab
-idInfoPiecesToAmode :: PrimKind -> VolatileLoc -> StableLoc -> FCode CAddrMode
+idInfoPiecesToAmode :: PrimRep -> VolatileLoc -> StableLoc -> FCode CAddrMode
idInfoPiecesToAmode kind (TempVarLoc uniq) stable_loc = returnFC (CTemp uniq kind)
idInfoPiecesToAmode kind (RegLoc magic_id) stable_loc = returnFC (CReg magic_id)
returnFC (amode, lf_info)
where
global_amode = CLbl (mkClosureLabel name) kind
- kind = getIdPrimRep name
+ kind = idPrimRep name
getCAddrMode :: Id -> FCode CAddrMode
getCAddrMode name
= lookupBindC name `thenFC` \ ~(MkCgIdInfo _ volatile_loc stable_loc lf_info) ->
case stable_loc of
NoStableLoc -> -- Aha! So it is volatile!
- idInfoPiecesToAmode (getIdPrimRep name) volatile_loc NoStableLoc `thenFC` \ amode ->
+ idInfoPiecesToAmode (idPrimRep name) volatile_loc NoStableLoc `thenFC` \ amode ->
returnFC (Just amode)
a_stable_loc -> returnFC Nothing
getVolatileRegs :: StgLiveVars -> FCode [MagicId]
getVolatileRegs vars
- = mapFCs snaffle_it (uniqSetToList vars) `thenFC` \ stuff ->
+ = mapFCs snaffle_it (idSetToList vars) `thenFC` \ stuff ->
returnFC (catMaybes stuff)
where
snaffle_it var
\end{code}
\begin{code}
-getAtomAmodes :: [StgArg] -> FCode [CAddrMode]
-getAtomAmodes [] = returnFC []
-getAtomAmodes (atom:atoms)
- = getAtomAmode atom `thenFC` \ amode ->
- getAtomAmodes atoms `thenFC` \ amodes ->
+getArgAmodes :: [StgArg] -> FCode [CAddrMode]
+getArgAmodes [] = returnFC []
+getArgAmodes (atom:atoms)
+ = getArgAmode atom `thenFC` \ amode ->
+ getArgAmodes atoms `thenFC` \ amodes ->
returnFC ( amode : amodes )
-getAtomAmode :: StgArg -> FCode CAddrMode
+getArgAmode :: StgArg -> FCode CAddrMode
-getAtomAmode (StgVarArg var) = getCAddrMode var
-getAtomAmode (StgLitArg lit) = returnFC (CLit lit)
+getArgAmode (StgVarArg var) = getCAddrMode var
+getArgAmode (StgLitArg lit) = returnFC (CLit lit)
\end{code}
%************************************************************************
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
%********************************************************
%* *
\begin{code}
#include "HsVersions.h"
-module CgCase (
- cgCase,
- saveVolatileVarsAndRegs
+module CgCase ( cgCase, saveVolatileVarsAndRegs ) where
- -- and to make the interface self-sufficient...
- ) where
+import Ubiq{-uitous-}
+import CgLoop2 ( cgExpr, getPrimOpArgAmodes )
-import StgSyn
import CgMonad
+import StgSyn
import AbsCSyn
-import PrelInfo ( PrimOp(..), primOpCanTriggerGC
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
+import AbsCUtils ( mkAbstractCs, mkAbsCStmts, mkAlgAltsCSwitch,
+ magicIdPrimRep, getAmodeRep
)
-import Type ( primRepFromType, getTyConDataCons,
- getUniDataSpecTyCon, getUniDataSpecTyCon_maybe,
- isEnumerationTyCon,
- Type
+import CgBindery ( getVolatileRegs, getArgAmode, getArgAmodes,
+ bindNewToReg, bindNewToTemp,
+ bindNewPrimToAmode,
+ rebindToAStack, rebindToBStack,
+ getCAddrModeAndInfo, getCAddrModeIfVolatile,
+ idInfoToAmode
)
-import CgBindery -- all of it
import CgCon ( buildDynCon, bindConArgs )
-import CgExpr ( cgExpr, getPrimOpArgAmodes )
import CgHeapery ( heapCheck )
-import CgRetConv -- lots of stuff
-import CgStackery -- plenty
+import CgRetConv ( dataReturnConvAlg, dataReturnConvPrim,
+ ctrlReturnConvAlg,
+ DataReturnConvention(..), CtrlReturnConvention(..),
+ assignPrimOpResultRegs,
+ makePrimOpArgsRobust
+ )
+import CgStackery ( allocAStack, allocBStack )
import CgTailCall ( tailCallBusiness, performReturn )
-import CgUsages -- and even more
-import CLabel -- bunches of things...
-import ClosureInfo {-( blackHoleClosureInfo, mkConLFInfo, mkLFArgument,
- layOutDynCon
- )-}
-import CostCentre ( useCurrentCostCentre, CostCentre )
-import Literal ( literalPrimRep )
-import Id ( getDataConTag, getIdPrimRep, fIRST_TAG, isDataCon,
- toplevelishId, getInstantiatedDataConSig,
- ConTag(..), DataCon(..)
+import CgUsages ( getSpARelOffset, getSpBRelOffset, freeBStkSlot )
+import CLabel ( mkVecTblLabel, mkReturnPtLabel, mkDefaultLabel,
+ mkAltLabel, mkClosureLabel
+ )
+import ClosureInfo ( mkConLFInfo, mkLFArgument, layOutDynCon )
+import CmdLineOpts ( opt_SccProfilingOn )
+import CostCentre ( useCurrentCostCentre )
+import HeapOffs ( VirtualSpBOffset(..), VirtualHeapOffset(..) )
+import Id ( idPrimRep, toplevelishId,
+ dataConTag, fIRST_TAG, ConTag(..),
+ isDataCon, DataCon(..),
+ idSetToList, GenId{-instance NamedThing,Eq-}
)
-import Maybes ( catMaybes, Maybe(..) )
-import PrimRep ( getPrimRepSize, isFollowableRep, retPrimRepSize, PrimRep(..) )
-import UniqSet -- ( uniqSetToList, UniqSet(..) )
-import Util
+import Maybes ( catMaybes )
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-} )
+import PrimOp ( primOpCanTriggerGC, PrimOp(..) )
+import PrimRep ( getPrimRepSize, isFollowableRep, retPrimRepSize,
+ PrimRep(..)
+ )
+import TyCon ( isEnumerationTyCon )
+import Type ( typePrimRep,
+ getDataSpecTyCon, getDataSpecTyCon_maybe,
+ isEnumerationTyCon
+ )
+import Util ( sortLt, isIn, isn'tIn, zipEqual,
+ pprError, panic, assertPanic
+ )
+
+getDataSpecTyCon = panic "CgCase.getDataSpecTyCon (ToDo)"
+getDataSpecTyCon_maybe = panic "CgCase.getDataSpecTyCon_maybe (ToDo)"
\end{code}
\begin{code}
| otherwise -- *Can* trigger GC
= getPrimOpArgAmodes op args `thenFC` \ arg_amodes ->
---NO: getIntSwitchChkrC `thenFC` \ isw_chkr ->
-- Get amodes for the arguments and results, and assign to regs
-- (Can-trigger-gc primops guarantee to have their (nonRobust)
-- args in regs)
let
- op_result_regs = assignPrimOpResultRegs {-NO:isw_chkr-} op
+ op_result_regs = assignPrimOpResultRegs op
op_result_amodes = map CReg op_result_regs
(op_arg_amodes, liveness_mask, arg_assts)
- = makePrimOpArgsRobust {-NO:isw_chkr-} op arg_amodes
+ = makePrimOpArgsRobust op arg_amodes
liveness_arg = mkIntCLit liveness_mask
in
\begin{code}
cgCase (StgApp v [] _) live_in_whole_case live_in_alts uniq (StgPrimAlts ty alts deflt)
- = getAtomAmode v `thenFC` \ amode ->
+ = getArgAmode v `thenFC` \ amode ->
cgPrimAltsGivenScrutinee NoGC amode alts deflt
\end{code}
live_in_whole_case live_in_alts uniq alts@(StgAlgAlts _ _ _)
=
getCAddrModeAndInfo fun `thenFC` \ (fun_amode, lf_info) ->
- getAtomAmodes args `thenFC` \ arg_amodes ->
+ getArgAmodes args `thenFC` \ arg_amodes ->
-- Squish the environment
nukeDeadBindings live_in_alts `thenC`
-- A temporary variable to hold the tag; this is unaffected by GC because
-- the heap-checks in the branches occur after the switch
tag_amode = CTemp uniq IntRep
- (spec_tycon, _, _) = getUniDataSpecTyCon ty
+ (spec_tycon, _, _) = getDataSpecTyCon ty
getPrimAppResultAmodes uniq (StgAlgAlts ty alts other_default)
-- Default is either StgNoDefault or StgBindDefault with unused binder
-- Sort alternatives into canonical order; there must be a complete
-- set because there's no default case.
sorted_alts = sortLt lt alts
- (con1,_,_,_) `lt` (con2,_,_,_) = getDataConTag con1 < getDataConTag con2
+ (con1,_,_,_) `lt` (con2,_,_,_) = dataConTag con1 < dataConTag con2
arg_amodes :: [CAddrMode]
-- Turn them into amodes
arg_amodes = concat (map mk_amodes sorted_alts)
mk_amodes (con, args, use_mask, rhs)
- = [ CTemp (getItsUnique arg) (getIdPrimRep arg) | arg <- args ]
+ = [ CTemp (getItsUnique arg) (idPrimRep arg) | arg <- args ]
\end{code}
The situation is simpler for primitive
\begin{code}
getPrimAppResultAmodes uniq (StgPrimAlts ty _ _)
- = [CTemp uniq kind]
- where
- kind = primRepFromType ty
+ = [CTemp uniq (typePrimRep ty)]
\end{code}
cgEvalAlts cc_slot uniq (StgAlgAlts ty alts deflt)
= -- Generate the instruction to restore cost centre, if any
restoreCurrentCostCentre cc_slot `thenFC` \ cc_restore ->
- getIntSwitchChkrC `thenFC` \ isw_chkr ->
-- Generate sequel info for use downstream
-- At the moment, we only do it if the type is vector-returnable.
-- which is worse than having the alt code in the switch statement
let
- (spec_tycon, _, _) = getUniDataSpecTyCon ty
+ (spec_tycon, _, _) = getDataSpecTyCon ty
use_labelled_alts
= case ctrlReturnConvAlg spec_tycon of
= if not use_labelled_alts then
Nothing -- no semi-tagging info
else
- cgSemiTaggedAlts isw_chkr uniq alts deflt -- Just <something>
+ cgSemiTaggedAlts uniq alts deflt -- Just <something>
in
cgAlgAlts GCMayHappen uniq cc_restore use_labelled_alts ty alts deflt
`thenFC` \ (tagged_alt_absCs, deflt_absC) ->
\begin{code}
cgAlgAlts gc_flag uniq restore_cc semi_tagging
ty alts deflt@(StgBindDefault binder True{-used-} _)
- = getIntSwitchChkrC `thenFC` \ isw_chkr ->
- let
+ = let
extra_branches :: [FCode (ConTag, AbstractC)]
- extra_branches = catMaybes (map (mk_extra_branch isw_chkr) default_cons)
+ extra_branches = catMaybes (map mk_extra_branch default_cons)
must_label_default = semi_tagging || not (null extra_branches)
in
default_join_lbl = mkDefaultLabel uniq
jump_instruction = CJump (CLbl default_join_lbl CodePtrRep)
- (spec_tycon, _, spec_cons)
- = -- trace ("cgCase:tycon:"++(ppShow 80 (ppAboves [
- -- ppr PprDebug uniq,
- -- ppr PprDebug ty,
- -- ppr PprShowAll binder
- -- ]))) (
- getUniDataSpecTyCon ty
- -- )
+ (spec_tycon, _, spec_cons) = getDataSpecTyCon ty
alt_cons = [ con | (con,_,_,_) <- alts ]
-- nothing to do. Otherwise, we have a special case for a nullary constructor,
-- but in the general case we do an allocation and heap-check.
- mk_extra_branch :: IntSwitchChecker -> DataCon -> (Maybe (FCode (ConTag, AbstractC)))
+ mk_extra_branch :: DataCon -> (Maybe (FCode (ConTag, AbstractC)))
- mk_extra_branch isw_chkr con
+ mk_extra_branch con
= ASSERT(isDataCon con)
- case dataReturnConvAlg isw_chkr con of
+ case dataReturnConvAlg con of
ReturnInHeap -> Nothing
ReturnInRegs rs -> Just (getAbsC (alloc_code rs) `thenFC` \ abs_c ->
returnFC (tag, abs_c)
)
where
lf_info = mkConLFInfo con
- tag = getDataConTag con
+ tag = dataConTag con
closure_lbl = mkClosureLabel con
-- alloc_code generates code to allocate constructor con, whose args are
absC jump_instruction
)
where
- zero_size reg = getPrimRepSize (kindFromMagicId reg) == 0
+ zero_size reg = getPrimRepSize (magicIdPrimRep reg) == 0
\end{code}
Now comes the general case
in
returnFC (tag, final_abs_c)
where
- tag = getDataConTag con
+ tag = dataConTag con
lbl = mkAltLabel uniq tag
cgAlgAltRhs :: GCFlag -> Id -> [Id] -> [Bool] -> StgExpr -> Code
cgAlgAltRhs gc_flag con args use_mask rhs
- = getIntSwitchChkrC `thenFC` \ isw_chkr ->
- let
+ = let
(live_regs, node_reqd)
- = case (dataReturnConvAlg isw_chkr con) of
+ = case (dataReturnConvAlg con) of
ReturnInHeap -> ([], True)
ReturnInRegs regs -> ([reg | (reg,True) <- regs `zipEqual` use_mask], False)
-- Pick the live registers using the use_mask
algebraic case alternatives for semi-tagging.
\begin{code}
-cgSemiTaggedAlts :: IntSwitchChecker
- -> Unique
+cgSemiTaggedAlts :: Unique
-> [(Id, [Id], [Bool], StgExpr)]
-> GenStgCaseDefault Id Id
-> SemiTaggingStuff
-cgSemiTaggedAlts isw_chkr uniq alts deflt
- = Just (map (st_alt isw_chkr) alts, st_deflt deflt)
+cgSemiTaggedAlts uniq alts deflt
+ = Just (map st_alt alts, st_deflt deflt)
where
st_deflt StgNoDefault = Nothing
mkDefaultLabel uniq)
)
- st_alt isw_chkr (con, args, use_mask, _)
- = case (dataReturnConvAlg isw_chkr con) of
+ st_alt (con, args, use_mask, _)
+ = case (dataReturnConvAlg con) of
ReturnInHeap ->
-- Ha! Nothing to do; Node already points to the thing
-- We have to load the live registers from the constructor
-- pointed to by Node.
let
- (_, regs_w_offsets) = layOutDynCon con kindFromMagicId regs
+ (_, regs_w_offsets) = layOutDynCon con magicIdPrimRep regs
used_regs = selectByMask use_mask regs
CSimultaneous (mkAbstractCs (map move_to_reg used_regs_w_offsets))],
join_label))
where
- con_tag = getDataConTag con
+ con_tag = dataConTag con
join_label = mkAltLabel uniq con_tag
move_to_reg :: (MagicId, VirtualHeapOffset {-from Node-}) -> AbstractC
move_to_reg (reg, offset)
- = CAssign (CReg reg) (CVal (NodeRel offset) (kindFromMagicId reg))
+ = CAssign (CReg reg) (CVal (NodeRel offset) (magicIdPrimRep reg))
\end{code}
%************************************************************************
NoGC -> CTemp uniq kind
GCMayHappen -> CReg (dataReturnConvPrim kind)
- kind = primRepFromType ty
+ kind = typePrimRep ty
cgPrimAltsGivenScrutinee gc_flag scrutinee alts deflt
-> FCode AbstractC -- Assignments to to the saves
saveVolatileVars vars
- = save_em (uniqSetToList vars)
+ = save_em (idSetToList vars)
where
save_em [] = returnFC AbsCNop
-- AbsCNop if not lexical CCs
saveCurrentCostCentre
- = isSwitchSetC SccProfilingOn `thenFC` \ doing_profiling ->
+ = let
+ doing_profiling = opt_SccProfilingOn
+ in
if not doing_profiling then
returnFC (Nothing, AbsCNop)
else
-- )
where
- (spec_tycon,_,_) = case (getUniDataSpecTyCon_maybe ty) of -- *must* be a real "data" type constructor
+ (spec_tycon,_,_) = case (getDataSpecTyCon_maybe ty) of -- *must* be a real "data" type constructor
Just xx -> xx
- Nothing -> error ("ERROR: can't generate code for polymorphic case;\nprobably a mis-use of `seq' or `par';\nthe User's Guide has more details.\nOffending type: "++(ppShow 80 (ppr PprDebug ty)))
+ Nothing -> pprError "ERROR: can't generate code for polymorphic case;\nprobably a mis-use of `seq' or `par';\nthe User's Guide has more details.\nOffending type: " (ppr PprDebug ty)
vtbl_label = mkVecTblLabel uniq
ret_label = mkReturnPtLabel uniq
module CgClosure ( cgTopRhsClosure, cgRhsClosure ) where
-import StgSyn
+import Ubiq{-uitous-}
+import CgLoop2 ( cgExpr, cgSccExpr )
+
import CgMonad
import AbsCSyn
+import StgSyn
-import PrelInfo ( PrimOp(..), Name
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import Type ( isPrimType, isPrimTyCon,
- getTauType, showTypeCategory, getTyConDataCons
- )
-import CgBindery ( getCAddrMode, getAtomAmodes,
- getCAddrModeAndInfo,
- bindNewToNode, bindNewToAStack, bindNewToBStack,
- bindNewToReg, bindArgsToRegs
+import AbsCUtils ( mkAbstractCs, getAmodeRep )
+import CgBindery ( getCAddrMode, getArgAmodes,
+ getCAddrModeAndInfo, bindNewToNode,
+ bindNewToAStack, bindNewToBStack,
+ bindNewToReg, bindArgsToRegs,
+ stableAmodeIdInfo, heapIdInfo
)
import CgCompInfo ( spARelToInt, spBRelToInt )
-import CgExpr ( cgExpr, cgSccExpr )
import CgUpdate ( pushUpdateFrame )
import CgHeapery ( allocDynClosure, heapCheck
#ifdef GRAN
- , heapCheckOnly, fetchAndReschedule -- HWL
-#endif {- GRAN -}
+ , fetchAndReschedule -- HWL
+#endif
)
-import CgRetConv ( ctrlReturnConvAlg, dataReturnConvAlg, mkLiveRegsBitMask,
+import CgRetConv ( mkLiveRegsMask,
+ ctrlReturnConvAlg, dataReturnConvAlg,
CtrlReturnConvention(..), DataReturnConvention(..)
)
import CgStackery ( getFinalStackHW, mkVirtStkOffsets,
getSpARelOffset, getSpBRelOffset,
getHpRelOffset
)
-import CLabel
+import CLabel ( mkClosureLabel, mkConUpdCodePtrVecLabel,
+ mkStdUpdCodePtrVecLabel, mkStdUpdVecTblLabel,
+ mkErrorStdEntryLabel, mkRednCountsLabel
+ )
import ClosureInfo -- lots and lots of stuff
-import CostCentre
-import Id ( idType, getIdPrimRep, isSysLocalId, myWrapperMaybe,
- showId, getIdInfo, getIdStrictness,
- getDataConTag
+import CmdLineOpts ( opt_EmitArityChecks, opt_ForConcurrent,
+ opt_AsmTarget
+ )
+import CostCentre ( useCurrentCostCentre, currentOrSubsumedCosts,
+ noCostCentreAttached, costsAreSubsumed,
+ isCafCC, overheadCostCentre
+ )
+import HeapOffs ( VirtualHeapOffset(..) )
+import Id ( idType, idPrimRep,
+ showId, getIdStrictness, dataConTag,
+ emptyIdSet,
+ GenId{-instance Outputable-}
)
-import IdInfo
import ListSetOps ( minusList )
-import Maybes ( Maybe(..), maybeToBool )
-import PrimRep ( isFollowableRep )
-import UniqSet
-import Unpretty
-import Util
+import Maybes ( maybeToBool )
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-}, TyCon{-ditto-} )
+import Pretty ( prettyToUn, ppBesides, ppChar, ppPStr )
+import PrimRep ( isFollowableRep, PrimRep(..) )
+import TyCon ( isPrimTyCon, tyConDataCons )
+import Unpretty ( uppShow )
+import Util ( isIn, panic, pprPanic, assertPanic )
+
+myWrapperMaybe = panic "CgClosure.myWrapperMaybe (ToDo)"
+showTypeCategory = panic "CgClosure.showTypeCategory (ToDo)"
+getWrapperArgTypeCategories = panic "CgClosure.getWrapperArgTypeCategories (ToDo)"
\end{code}
%********************************************************
-- ToDo: check non-primitiveness (ASSERT)
= (
-- LAY OUT THE OBJECT
- getAtomAmodes std_thunk_payload `thenFC` \ amodes ->
+ getArgAmodes std_thunk_payload `thenFC` \ amodes ->
let
(closure_info, amodes_w_offsets)
= layOutDynClosure binder getAmodeRep amodes lf_info
amodes_w_offsets = [(amode,offset) | ((_, (amode,_)), offset) <- bind_details]
- get_kind (id, amode_and_info) = getIdPrimRep id
+ get_kind (id, amode_and_info) = idPrimRep id
in
-- BUILD ITS INFO TABLE AND CODE
forkClosureBody (
-- If f is not top-level, then f is one of the free variables too,
-- hence "payload_ids" isn't the same as "arg_ids".
--
- vap_entry_rhs = StgApp (StgVarArg fun) (map StgVarArg args) emptyUniqSet
+ vap_entry_rhs = StgApp (StgVarArg fun) (map StgVarArg args) emptyIdSet
-- Empty live vars
arg_ids_w_info = [(name,mkLFArgument) | name <- args]
-- let x = f p q -- x isn't top level!
-- in ...
- get_kind (id, info) = getIdPrimRep id
+ get_kind (id, info) = idPrimRep id
payload_bind_details :: [((Id, LambdaFormInfo), VirtualHeapOffset)]
(closure_info, payload_bind_details) = layOutDynClosure
#endif
getAbsC body_code `thenFC` \ body_absC ->
moduleName `thenFC` \ mod_name ->
- getIntSwitchChkrC `thenFC` \ isw_chkr ->
absC (CClosureInfoAndCode closure_info body_absC Nothing
stdUpd (cl_descr mod_name)
- (dataConLiveness isw_chkr closure_info))
+ (dataConLiveness closure_info))
where
cl_descr mod_name = closureDescription mod_name (closureId closure_info) [] body
\begin{code}
closureCodeBody binder_info closure_info cc all_args body
= getEntryConvention id lf_info
- (map getIdPrimRep all_args) `thenFC` \ entry_conv ->
-
- isSwitchSetC EmitArityChecks `thenFC` \ do_arity_chks ->
-
- isSwitchSetC ForConcurrent `thenFC` \ is_concurrent ->
-
- isStringSwitchSetC AsmTarget `thenFC` \ native_code ->
-
+ (map idPrimRep all_args) `thenFC` \ entry_conv ->
let
+ do_arity_chks = opt_EmitArityChecks
+ is_concurrent = opt_ForConcurrent
+ native_code = opt_AsmTarget
+
stg_arity = length all_args
-- Arg mapping for standard (slow) entry point; all args on stack
(spA_all_args, spB_all_args, all_bxd_w_offsets, all_ubxd_w_offsets)
= mkVirtStkOffsets
0 0 -- Initial virtual SpA, SpB
- getIdPrimRep
+ idPrimRep
all_args
-- Arg mapping for the fast entry point; as many args as poss in
(spA_stk_args, spB_stk_args, stk_bxd_w_offsets, stk_ubxd_w_offsets)
= mkVirtStkOffsets
0 0 -- Initial virtual SpA, SpB
- getIdPrimRep
+ idPrimRep
stk_args
-- HWL; Note: empty list of live regs in slow entry code
`thenFC` \ slow_abs_c ->
forkAbsC fast_entry_code `thenFC` \ fast_abs_c ->
moduleName `thenFC` \ mod_name ->
- getIntSwitchChkrC `thenFC` \ isw_chkr ->
-- Now either construct the info table, or put the fast code in alone
-- (We never have slow code without an info table)
if info_table_needed then
CClosureInfoAndCode closure_info slow_abs_c (Just fast_abs_c)
stdUpd (cl_descr mod_name)
- (dataConLiveness isw_chkr closure_info)
+ (dataConLiveness closure_info)
else
CCodeBlock fast_label fast_abs_c
)
if (isFollowableRep (getAmodeRep last_amode)) then
getSpARelOffset 0 `thenFC` \ (SpARel spA off) ->
+ let
+ lit = mkIntCLit (spARelToInt spA off)
+ in
if node_points then
- absC (CMacroStmt ARGS_CHK_A [mkIntCLit (spARelToInt spA off)])
+ absC (CMacroStmt ARGS_CHK_A [lit])
else
- absC (CMacroStmt ARGS_CHK_A_LOAD_NODE
- [mkIntCLit (spARelToInt spA off), set_Node_to_this])
+ absC (CMacroStmt ARGS_CHK_A_LOAD_NODE [lit, set_Node_to_this])
else
- getSpBRelOffset 0 `thenFC` \ b_rel_offset ->
+ getSpBRelOffset 0 `thenFC` \ (SpBRel spB off) ->
+ let
+ lit = mkIntCLit (spBRelToInt spB off)
+ in
if node_points then
- absC (CMacroStmt ARGS_CHK_B [mkIntCLit (spBRelToInt b_rel_offset)])
+ absC (CMacroStmt ARGS_CHK_B [lit])
else
- absC (CMacroStmt ARGS_CHK_B_LOAD_NODE
- [mkIntCLit (spBRelToInt b_rel_offset), set_Node_to_this])
+ absC (CMacroStmt ARGS_CHK_B_LOAD_NODE [lit, set_Node_to_this])
where
-- We must tell the arg-satis macro whether Node is pointing to
-- the closure or not. If it isn't so pointing, then we give to
)
where
all_regs = if node_reqd then node:regs else regs
- liveness_mask = mkLiveRegsBitMask all_regs
+ liveness_mask = mkLiveRegsMask all_regs
returns_prim_type = closureReturnsUnboxedType closure_info
\end{code}
setupUpdate closure_info code
= if (closureUpdReqd closure_info) then
link_caf_if_needed `thenFC` \ update_closure ->
- getIntSwitchChkrC `thenFC` \ isw_chkr ->
- pushUpdateFrame update_closure (vector isw_chkr) code
+ pushUpdateFrame update_closure vector code
else
profCtrC SLIT("UPDF_OMITTED") [] `thenC`
code
closure_label = mkClosureLabel (closureId closure_info)
- vector isw_chkr
+ vector
= case (closureType closure_info) of
Nothing -> CReg StdUpdRetVecReg
Just (spec_tycon, _, spec_datacons) ->
UnvectoredReturn 1 ->
let
spec_data_con = head spec_datacons
- only_tag = getDataConTag spec_data_con
+ only_tag = dataConTag spec_data_con
- direct = case (dataReturnConvAlg isw_chkr spec_data_con) of
+ direct = case (dataReturnConvAlg spec_data_con) of
ReturnInRegs _ -> mkConUpdCodePtrVecLabel spec_tycon only_tag
ReturnInHeap -> mkStdUpdCodePtrVecLabel spec_tycon only_tag
-- Not called for StgRhsCon which have global info tables built in
-- CgConTbls.lhs with a description generated from the data constructor
-closureDescription mod_name name args body =
- uppShow 0 (prettyToUn (
+closureDescription mod_name name args body
+ = uppShow 0 (prettyToUn (
ppBesides [ppChar '<',
ppPStr mod_name,
ppChar '.',
\begin{code}
-- THESE ARE DIRECTION SENSITIVE!
+spARelToInt :: Int{-VirtualSpAOffset-} -> Int{-VirtualSpAOffset-} -> Int
+spBRelToInt :: Int{-VirtualSpBOffset-} -> Int{-VirtualSpBOffset-} -> Int
+
spARelToInt spA off = spA - off -- equiv to: AREL(spA - off)
spBRelToInt spB off = off - spB -- equiv to: BREL(spB - off)
\end{code}
%
-% (c) The GRASP Project, Glasgow University, 1992-1995
+% (c) The GRASP Project, Glasgow University, 1992-1996
%
\section[CgCon]{Code generation for constructors}
#include "HsVersions.h"
module CgCon (
- -- it's all exported, actually...
cgTopRhsCon, buildDynCon,
bindConArgs,
cgReturnDataCon
-
- -- and to make the interface self-sufficient...
) where
-import StgSyn
+import Ubiq{-uitous-}
+
import CgMonad
import AbsCSyn
+import StgSyn
-import Type ( maybeCharLikeTyCon, maybeIntLikeTyCon, TyVar,
- TyCon, Class, Type
- )
-import CgBindery ( getAtomAmode, getAtomAmodes, bindNewToNode,
- bindArgsToRegs, newTempAmodeAndIdInfo, idInfoToAmode
+import AbsCUtils ( mkAbstractCs, getAmodeRep )
+import CgBindery ( getArgAmodes, bindNewToNode,
+ bindArgsToRegs, newTempAmodeAndIdInfo,
+ idInfoToAmode, stableAmodeIdInfo,
+ heapIdInfo
)
import CgClosure ( cgTopRhsClosure )
-import CgHeapery ( allocDynClosure, heapCheck
-#ifdef GRAN
- , fetchAndReschedule -- HWL
-#endif {- GRAN -}
- )
import CgCompInfo ( mAX_INTLIKE, mIN_INTLIKE )
-
-import CgRetConv ( dataReturnConvAlg, mkLiveRegsBitMask,
- CtrlReturnConvention(..), DataReturnConvention(..)
- )
+import CgHeapery ( allocDynClosure )
+import CgRetConv ( dataReturnConvAlg, DataReturnConvention(..) )
import CgTailCall ( performReturn, mkStaticAlgReturnCode )
-import CgUsages ( getHpRelOffset )
-import CLabel ( CLabel, mkClosureLabel, mkInfoTableLabel,
+import CLabel ( mkClosureLabel, mkInfoTableLabel,
mkPhantomInfoTableLabel,
mkConEntryLabel, mkStdEntryLabel
)
-import ClosureInfo -- hiding ( auxInfoTableLabelFromCI ) -- I hate pragmas
- {-( mkConLFInfo, mkLFArgument, closureLFInfo,
+import ClosureInfo ( mkClosureLFInfo, mkConLFInfo, mkLFArgument,
layOutDynCon, layOutDynClosure,
- layOutStaticClosure, UpdateFlag(..),
- mkClosureLFInfo, layOutStaticNoFVClosure
- )-}
-import Id ( getIdPrimRep, getDataConTag, getDataConTyCon,
- isDataCon, fIRST_TAG, DataCon(..), ConTag(..)
+ layOutStaticClosure
+ )
+import CostCentre ( currentOrSubsumedCosts, useCurrentCostCentre,
+ dontCareCostCentre
)
-import Maybes ( maybeToBool, Maybe(..) )
-import PrimRep ( PrimRep(..), isFloatingRep, getPrimRepSize )
-import CostCentre
-import UniqSet -- ( emptyUniqSet, UniqSet(..) )
-import Util
+import Id ( idPrimRep, dataConTag, dataConTyCon,
+ isDataCon, DataCon(..),
+ emptyIdSet
+ )
+import Literal ( Literal(..) )
+import Maybes ( maybeToBool )
+import PrimRep ( isFloatingRep, PrimRep(..) )
+import Util ( isIn, zipWithEqual, panic, assertPanic )
+
+maybeCharLikeTyCon = panic "CgCon.maybeCharLikeTyCon (ToDo)"
+maybeIntLikeTyCon = panic "CgCon.maybeIntLikeTyCon (ToDo)"
\end{code}
%************************************************************************
\begin{code}
cgTopRhsCon :: Id -- Name of thing bound to this RHS
-> DataCon -- Id
- -> [StgArg] -- Args
+ -> [StgArg] -- Args
-> Bool -- All zero-size args (see buildDynCon)
-> FCode (Id, CgIdInfo)
\end{code}
|| any isLitLitArg args
= cgTopRhsClosure name top_cc NoStgBinderInfo [] body lf_info
where
- body = StgCon con args emptyUniqSet{-emptyLiveVarSet-}
+ body = StgCon con args emptyIdSet{-emptyLiveVarSet-}
lf_info = mkClosureLFInfo True {- Top level -} [] ReEntrant [] body
\end{code}
ASSERT(isDataCon con)
-- LAY IT OUT
- getAtomAmodes args `thenFC` \ amodes ->
+ getArgAmodes args `thenFC` \ amodes ->
let
(closure_info, amodes_w_offsets)
-- RETURN
returnFC (name, stableAmodeIdInfo name (CLbl closure_label PtrRep) lf_info)
where
- con_tycon = getDataConTyCon con
- lf_info = mkConLFInfo con
+ con_tycon = dataConTyCon con
+ lf_info = mkConLFInfo con
- closure_label = mkClosureLabel name
+ closure_label = mkClosureLabel name
info_label = mkInfoTableLabel con
- con_entry_label = mkConEntryLabel con
- entry_label = mkStdEntryLabel name
+ con_entry_label = mkConEntryLabel con
+ entry_label = mkStdEntryLabel name
\end{code}
The general case is:
= ASSERT(isDataCon con)
returnFC (stableAmodeIdInfo binder (CIntLike arg_amode) (mkConLFInfo con))
where
- tycon = getDataConTyCon con
+ tycon = dataConTyCon con
(temp_amode, temp_id_info) = newTempAmodeAndIdInfo binder (mkConLFInfo con)
- in_range_int_lit (CLit (MachInt val _)) = (val <= mAX_INTLIKE) && (val >= mIN_INTLIKE)
+ in_range_int_lit (CLit (MachInt val _)) = val <= mAX_INTLIKE && val >= mIN_INTLIKE
in_range_int_lit other_amode = False
\end{code}
bindConArgs :: DataCon -> [Id] -> Code
bindConArgs con args
= ASSERT(isDataCon con)
- getIntSwitchChkrC `thenFC` \ isw_chkr ->
-
- case (dataReturnConvAlg isw_chkr con) of
+ case (dataReturnConvAlg con) of
ReturnInRegs rs -> bindArgsToRegs args rs
ReturnInHeap ->
let
- (_, args_w_offsets) = layOutDynCon con getIdPrimRep args
+ (_, args_w_offsets) = layOutDynCon con idPrimRep args
in
mapCs bind_arg args_w_offsets
where
cgReturnDataCon con amodes all_zero_size_args live_vars
= ASSERT(isDataCon con)
- getIntSwitchChkrC `thenFC` \ isw_chkr ->
getEndOfBlockInfo `thenFC` \ (EndOfBlockInfo args_spa args_spb sequel) ->
case sequel of
CaseAlts _ (Just (alts, Just (maybe_deflt_binder, (_,deflt_lbl))))
- | not (getDataConTag con `is_elem` map fst alts)
+ | not (dataConTag con `is_elem` map fst alts)
->
-- Special case! We're returning a constructor to the default case
-- of an enclosing case. For example:
-- Ignore the sequel: we've already looked at it above
other_sequel -> -- The usual case
- case (dataReturnConvAlg isw_chkr con) of
+ case (dataReturnConvAlg con) of
ReturnInHeap ->
-- BUILD THE OBJECT IN THE HEAP
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[CgConTbls]{Info tables and update bits for constructors}
\begin{code}
#include "HsVersions.h"
-module CgConTbls (
- genStaticConBits,
+module CgConTbls ( genStaticConBits ) where
- -- and to complete the interface...
- TCE(..), UniqFM, CompilationInfo, AbstractC
- ) where
-
-import Pretty -- ToDo: rm (debugging)
-import Outputable
+import Ubiq{-uitous-}
import AbsCSyn
import CgMonad
-import Type ( getTyConDataCons, primRepFromType,
- maybeIntLikeTyCon, mkSpecTyCon,
- TyVarTemplate, TyCon, Class,
- TauType(..), Type, ThetaType(..)
- )
+import AbsCUtils ( mkAbsCStmts, mkAbstractCs, magicIdPrimRep )
+import CgCompInfo ( uF_UPDATEE )
import CgHeapery ( heapCheck, allocDynClosure )
-import CgRetConv ( dataReturnConvAlg, ctrlReturnConvAlg,
- mkLiveRegsBitMask,
+import CgRetConv ( mkLiveRegsMask,
+ dataReturnConvAlg, ctrlReturnConvAlg,
CtrlReturnConvention(..),
DataReturnConvention(..)
)
import CgTailCall ( performReturn, mkStaticAlgReturnCode )
import CgUsages ( getHpRelOffset )
-import CLabel ( mkConEntryLabel, mkStaticConEntryLabel,
- mkClosureLabel,
- mkConUpdCodePtrVecLabel, mkStdUpdCodePtrVecLabel,
- mkStdUpdVecTblLabel, CLabel
+import CLabel ( mkConEntryLabel, mkClosureLabel,
+ mkConUpdCodePtrVecLabel,
+ mkStdUpdCodePtrVecLabel, mkStdUpdVecTblLabel
)
import ClosureInfo ( layOutStaticClosure, layOutDynCon,
- closureSizeWithoutFixedHdr, closurePtrsSize,
- fitsMinUpdSize, mkConLFInfo, layOutPhantomClosure,
+ layOutPhantomClosure, closurePtrsSize,
+ fitsMinUpdSize, mkConLFInfo,
infoTableLabelFromCI, dataConLiveness
)
-import FiniteMap
-import Id ( getDataConTag, getDataConSig, getDataConTyCon,
- mkSameSpecCon,
- getDataConArity, fIRST_TAG, ConTag(..),
- DataCon(..)
+import CostCentre ( dontCareCostCentre )
+import FiniteMap ( fmToList )
+import HeapOffs ( zeroOff, VirtualHeapOffset(..) )
+import Id ( dataConTag, dataConSig,
+ dataConArity, fIRST_TAG,
+ emptyIdSet,
+ GenId{-instance NamedThing-}
)
-import CgCompInfo ( uF_UPDATEE )
-import Maybes ( maybeToBool, Maybe(..) )
-import PrimRep ( getPrimRepSize, retPrimRepSize )
-import CostCentre
-import UniqSet -- ( emptyUniqSet, UniqSet(..) )
-import Util
+import PrimRep ( getPrimRepSize, PrimRep(..) )
+import TyCon ( tyConDataCons, mkSpecTyCon )
+import Type ( typePrimRep )
+import Util ( panic )
+
+maybeIntLikeTyCon = panic "CgConTbls.maybeIntLikeTyCon (ToDo)"
+mkSameSpecCon = panic "CgConTbls.mkSameSpecCon (ToDo)"
\end{code}
For every constructor we generate the following info tables:
`mkAbsCStmts`
maybe_tycon_vtbl
where
- data_cons = getTyConDataCons tycon
+ data_cons = tyConDataCons tycon
tycon_upd_label = mkStdUpdVecTblLabel tycon
maybe_tycon_vtbl =
`mkAbsCStmts`
maybe_spec_tycon_vtbl
where
- data_cons = getTyConDataCons tycon
+ data_cons = tyConDataCons tycon
spec_tycon = mkSpecTyCon tycon ty_maybes
spec_data_cons = map (mkSameSpecCon ty_maybes) data_cons
------------------
mk_upd_label tycon con
= CLbl
- (case (dataReturnConvAlg isw_chkr con) of
+ (case (dataReturnConvAlg con) of
ReturnInRegs _ -> mkConUpdCodePtrVecLabel tycon tag
ReturnInHeap -> mkStdUpdCodePtrVecLabel tycon tag)
CodePtrRep
where
- tag = getDataConTag con
-
- ------------------
- (MkCompInfo sw_chkr isw_chkr _) = comp_info
+ tag = dataConTag con
\end{code}
%************************************************************************
\begin{code}
genConInfo :: CompilationInfo -> TyCon -> Id -> AbstractC
-genConInfo comp_info@(MkCompInfo _ isw_chkr _) tycon data_con
+genConInfo comp_info tycon data_con
= mkAbstractCs [
CSplitMarker,
inregs_upd_maybe,
closure_maybe]
-- Order of things is to reduce forward references
where
- (closure_info, body_code) = mkConCodeAndInfo isw_chkr data_con
+ (closure_info, body_code) = mkConCodeAndInfo data_con
-- To allow the debuggers, interpreters, etc to cope with static
-- data structures (ie those built at compile time), we take care that
-- info-table contains the information we need.
- (static_ci,_) = layOutStaticClosure data_con primRepFromType arg_tys (mkConLFInfo data_con)
+ (static_ci,_) = layOutStaticClosure data_con typePrimRep arg_tys (mkConLFInfo data_con)
body = (initC comp_info (
profCtrC SLIT("ENT_CON") [CReg node] `thenC`
closure_code = CClosureInfoAndCode closure_info body Nothing
stdUpd con_descr
- (dataConLiveness isw_chkr closure_info)
+ (dataConLiveness closure_info)
static_code = CClosureInfoAndCode static_ci body Nothing
stdUpd con_descr
- (dataConLiveness isw_chkr static_ci)
+ (dataConLiveness static_ci)
inregs_upd_maybe = genPhantomUpdInfo comp_info tycon data_con
stdUpd = CLbl (mkStdUpdCodePtrVecLabel tycon tag) CodePtrRep
- tag = getDataConTag data_con
+ tag = dataConTag data_con
cost_centre = mkCCostCentre dontCareCostCentre -- not worried about static data costs
cost_centre
[{-No args! A slight lie for constrs with VoidRep args-}]
- zero_size arg_ty = getPrimRepSize (primRepFromType arg_ty) == 0
+ zero_size arg_ty = getPrimRepSize (typePrimRep arg_ty) == 0
- (_,_,arg_tys,_) = getDataConSig data_con
- con_arity = getDataConArity data_con
+ (_,_,arg_tys,_) = dataConSig data_con
+ con_arity = dataConArity data_con
entry_label = mkConEntryLabel data_con
closure_label = mkClosureLabel data_con
\end{code}
\begin{code}
-mkConCodeAndInfo :: IntSwitchChecker
- -> Id -- Data constructor
+mkConCodeAndInfo :: Id -- Data constructor
-> (ClosureInfo, Code) -- The info table
-mkConCodeAndInfo isw_chkr con
- = case (dataReturnConvAlg isw_chkr con) of
+mkConCodeAndInfo con
+ = case (dataReturnConvAlg con) of
ReturnInRegs regs ->
let
(closure_info, regs_w_offsets)
- = layOutDynCon con kindFromMagicId regs
+ = layOutDynCon con magicIdPrimRep regs
body_code
= profCtrC SLIT("RET_OLD_IN_REGS") [mkIntCLit (length regs_w_offsets)] `thenC`
performReturn (mkAbstractCs (map move_to_reg regs_w_offsets))
(mkStaticAlgReturnCode con Nothing {- Info-ptr already loaded-})
- emptyUniqSet{-no live vars-}
+ emptyIdSet{-no live vars-}
in
(closure_info, body_code)
ReturnInHeap ->
let
- (_, _, arg_tys, _) = getDataConSig con
+ (_, _, arg_tys, _) = dataConSig con
(closure_info, arg_things)
- = layOutDynCon con primRepFromType arg_tys
+ = layOutDynCon con typePrimRep arg_tys
body_code
= -- NB: We don't set CC when entering data (WDP 94/06)
performReturn AbsCNop -- Ptr to thing already in Node
(mkStaticAlgReturnCode con Nothing {- Info-ptr already loaded-})
- emptyUniqSet{-no live vars-}
+ emptyIdSet{-no live vars-}
in
(closure_info, body_code)
where
move_to_reg :: (MagicId, VirtualHeapOffset {-from Node-}) -> AbstractC
move_to_reg (reg, offset)
- = CAssign (CReg reg) (CVal (NodeRel offset) (kindFromMagicId reg))
+ = CAssign (CReg reg) (CVal (NodeRel offset) (magicIdPrimRep reg))
\end{code}
%************************************************************************
genPhantomUpdInfo :: CompilationInfo -> TyCon -> Id{-data con-} -> AbstractC
-genPhantomUpdInfo comp_info@(MkCompInfo _ isw_chkr _) tycon data_con
- = case (dataReturnConvAlg isw_chkr data_con) of
+genPhantomUpdInfo comp_info tycon data_con
+ = case (dataReturnConvAlg data_con) of
ReturnInHeap -> AbsCNop -- No need for a phantom update
let
phantom_itbl = CClosureInfoAndCode phantom_ci AbsCNop Nothing
upd_code con_descr
- (dataConLiveness isw_chkr phantom_ci)
+ (dataConLiveness phantom_ci)
phantom_ci = layOutPhantomClosure data_con (mkConLFInfo data_con)
con_descr = _UNPK_ (getOccurrenceName data_con)
- con_arity = getDataConArity data_con
+ con_arity = dataConArity data_con
upd_code = CLabelledCode upd_label (mkAbsCStmts build_closure perform_return)
upd_label = mkConUpdCodePtrVecLabel tycon tag
- tag = getDataConTag data_con
+ tag = dataConTag data_con
- updatee = CVal (SpBRel 0 (-uF_UPDATEE)) PtrRep
+ updatee = CVal (SpBRel 0 (- uF_UPDATEE)) PtrRep
perform_return = mkAbstractCs
[
blame_cc = use_cc -- who to blame for allocation
do_move (reg, virt_offset) =
- CAssign (CVal (NodeRel virt_offset) (kindFromMagicId reg)) (CReg reg)
+ CAssign (CVal (NodeRel virt_offset) (magicIdPrimRep reg)) (CReg reg)
-- Code for building a new constructor in place over the updatee
CAssign (CReg infoptr) (CLbl info_label DataPtrRep)
])
- (closure_info, regs_w_offsets) = layOutDynCon data_con kindFromMagicId regs
+ (closure_info, regs_w_offsets) = layOutDynCon data_con magicIdPrimRep regs
info_label = infoTableLabelFromCI closure_info
- liveness_mask = mkIntCLit (mkLiveRegsBitMask (node:regs))
+ liveness_mask = mkIntCLit (mkLiveRegsMask (node:regs))
build_closure =
if fitsMinUpdSize closure_info then
\begin{code}
#include "HsVersions.h"
-module CgExpr (
- cgExpr, cgSccExpr, getPrimOpArgAmodes
+module CgExpr ( cgExpr, cgSccExpr, getPrimOpArgAmodes ) where
- -- and to make the interface self-sufficient...
- ) where
+import Ubiq{-uitous-}
+import CgLoop2 -- here for paranoia-checking
import StgSyn
import CgMonad
import AbsCSyn
-import PrelInfo ( PrimOp(..), PrimOpResultInfo(..), HeapRequirement(..),
- primOpHeapReq, getPrimOpResultInfo, PrimRep,
- primOpCanTriggerGC
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import Type ( isPrimType, getTyConDataCons )
-import CLabel ( CLabel, mkPhantomInfoTableLabel, mkInfoTableVecTblLabel )
-import ClosureInfo ( LambdaFormInfo, mkClosureLFInfo )
-import CgBindery ( getAtomAmodes )
+import AbsCUtils ( mkAbsCStmts, mkAbstractCs )
+import CgBindery ( getArgAmodes )
import CgCase ( cgCase, saveVolatileVarsAndRegs )
import CgClosure ( cgRhsClosure )
import CgCon ( buildDynCon, cgReturnDataCon )
import CgHeapery ( allocHeap )
import CgLetNoEscape ( cgLetNoEscapeClosure )
-import CgRetConv -- various things...
-import CgTailCall ( cgTailCall, performReturn, mkDynamicAlgReturnCode,
- mkPrimReturnCode
+import CgRetConv ( dataReturnConvAlg, ctrlReturnConvAlg,
+ DataReturnConvention(..), CtrlReturnConvention(..),
+ assignPrimOpResultRegs, makePrimOpArgsRobust
+ )
+import CgTailCall ( cgTailCall, performReturn,
+ mkDynamicAlgReturnCode, mkPrimReturnCode
+ )
+import CLabel ( mkPhantomInfoTableLabel, mkInfoTableVecTblLabel )
+import ClosureInfo ( mkClosureLFInfo )
+import CostCentre ( setToAbleCostCentre, isDupdCC )
+import HeapOffs ( VirtualSpBOffset(..) )
+import Id ( mkIdSet, unionIdSets, GenId{-instance Outputable-} )
+import PprStyle ( PprStyle(..) )
+import PrimOp ( primOpCanTriggerGC, primOpHeapReq, HeapRequirement(..),
+ getPrimOpResultInfo, PrimOp(..), PrimOpResultInfo(..)
)
-import CostCentre ( setToAbleCostCentre, isDupdCC, CostCentre )
-import Maybes ( Maybe(..) )
-import PrimRep ( getPrimRepSize )
-import UniqSet
-import Util
+import PrimRep ( getPrimRepSize, PrimRep(..) )
+import TyCon ( tyConDataCons )
+import Util ( panic, pprPanic )
\end{code}
This module provides the support code for @StgToAbstractC@ to deal
\begin{code}
cgExpr (StgCon con args live_vars)
- = getAtomAmodes args `thenFC` \ amodes ->
+ = getArgAmodes args `thenFC` \ amodes ->
cgReturnDataCon con amodes (all zero_size args) live_vars
where
zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
\begin{code}
cgExpr x@(StgPrim op args live_vars)
- = getIntSwitchChkrC `thenFC` \ isw_chkr ->
- getPrimOpArgAmodes op args `thenFC` \ arg_amodes ->
+ = getPrimOpArgAmodes op args `thenFC` \ arg_amodes ->
let
- result_regs = assignPrimOpResultRegs {-NO:isw_chkr-} op
+ result_regs = assignPrimOpResultRegs op
result_amodes = map CReg result_regs
may_gc = primOpCanTriggerGC op
dyn_tag = head result_amodes
-- (Can-trigger-gc primops guarantee to have their args in regs)
let
(arg_robust_amodes, liveness_mask, arg_assts)
- = makePrimOpArgsRobust {-NO:isw_chkr-} op arg_amodes
+ = makePrimOpArgsRobust op arg_amodes
liveness_arg = mkIntCLit liveness_mask
in
vec_lbl = CTableEntry (CLbl (mkInfoTableVecTblLabel tycon) DataPtrRep)
dyn_tag DataPtrRep
- data_con = head (getTyConDataCons tycon)
+ data_con = head (tyConDataCons tycon)
(dir_lbl, num_of_fields)
- = case (dataReturnConvAlg fake_isw_chkr data_con) of
+ = case (dataReturnConvAlg data_con) of
ReturnInRegs rs
-> (CLbl (mkPhantomInfoTableLabel data_con) DataPtrRep,
mkIntCLit (length rs)) -- for ticky-ticky only
-> pprPanic "CgExpr: can't return prim in heap:" (ppr PprDebug data_con)
-- Never used, and no point in generating
-- the code for it!
-
- fake_isw_chkr x = Nothing
where
-- for all PrimOps except ccalls, we pin the liveness info
-- on as the first "argument"
-- the Id is passed along so a binding can be set up
cgRhs name (StgRhsCon maybe_cc con args)
- = getAtomAmodes args `thenFC` \ amodes ->
+ = getArgAmodes args `thenFC` \ amodes ->
buildDynCon name maybe_cc con amodes (all zero_size args)
`thenFC` \ idinfo ->
returnFC (name, idinfo)
where
-- We add the binders to the live-in-rhss set so that we don't
-- delete the bindings for the binder from the environment!
- full_live_in_rhss = live_in_rhss `unionUniqSets` (mkUniqSet [b | (b,r) <- pairs])
+ full_live_in_rhss = live_in_rhss `unionIdSets` (mkIdSet [b | (b,r) <- pairs])
cgLetNoEscapeRhs
:: StgLiveVars -- Live in rhss
\begin{code}
getPrimOpArgAmodes op args
- = getAtomAmodes args `thenFC` \ arg_amodes ->
+ = getArgAmodes args `thenFC` \ arg_amodes ->
case primOpHeapReq op of
-
FixedHeapRequired size -> allocHeap size `thenFC` \ amode ->
returnFC (amode : arg_amodes)
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1994
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[CgHeapery]{Heap management functions}
module CgHeapery (
heapCheck,
- allocHeap, allocDynClosure,
+ allocHeap, allocDynClosure
#ifdef GRAN
-- new for GrAnSim HWL
- heapCheckOnly, fetchAndReschedule,
+ , heapCheckOnly, fetchAndReschedule
#endif {- GRAN -}
-
- -- and to make the interface self-sufficient...
- AbstractC, CAddrMode, HeapOffset,
- CgState, ClosureInfo, Id
) where
+import Ubiq{-uitous-}
+
import AbsCSyn
import CgMonad
-import CgRetConv ( mkLiveRegsBitMask )
+import AbsCUtils ( mkAbstractCs, getAmodeRep )
+import CgRetConv ( mkLiveRegsMask )
import CgUsages ( getVirtAndRealHp, setVirtHp, setRealHp,
initHeapUsage
)
-import ClosureInfo ( closureSize, closureHdrSize, closureGoodStuffSize, slopSize,
- layOutDynClosure,
- allocProfilingMsg, closureKind
+import ClosureInfo ( closureSize, closureHdrSize, closureGoodStuffSize,
+ slopSize, allocProfilingMsg, closureKind
+ )
+import HeapOffs ( isZeroOff, addOff, intOff,
+ VirtualHeapOffset(..)
)
-import Util
+import PrimRep ( PrimRep(..) )
\end{code}
%************************************************************************
-- at once or not.
where
all_regs = if node_reqd then node:regs else regs
- liveness_mask = mkLiveRegsBitMask all_regs
+ liveness_mask = mkLiveRegsMask all_regs
checking_code = CMacroStmt HEAP_CHK [
mkIntCLit liveness_mask,
-- at once or not.
where
all_regs = if node_reqd then node:regs else regs
- liveness_mask = mkLiveRegsBitMask all_regs
+ liveness_mask = mkLiveRegsMask all_regs
maybe_context_switch = if do_context_switch
then context_switch_code
else absC AbsCNop
where
all_regs = if node_reqd then node:regs else regs
- liveness_mask = mkLiveRegsBitMask all_regs
+ liveness_mask = mkLiveRegsMask all_regs
reschedule_code = absC (CMacroStmt GRAN_RESCHEDULE [
mkIntCLit liveness_mask,
module CgLetNoEscape ( cgLetNoEscapeClosure ) where
+import Ubiq{-uitious-}
+import CgLoop2 ( cgExpr )
+
import StgSyn
import CgMonad
import AbsCSyn
-import CgBindery -- various things
-import CgExpr ( cgExpr )
+import CgBindery ( letNoEscapeIdInfo, bindArgsToRegs,
+ bindNewToAStack, bindNewToBStack
+ )
import CgHeapery ( heapCheck )
import CgRetConv ( assignRegs )
import CgStackery ( mkVirtStkOffsets )
import CgUsages ( setRealAndVirtualSps, getVirtSps )
-import CLabel ( mkStdEntryLabel )
+import CLabel ( mkStdEntryLabel )
import ClosureInfo ( mkLFLetNoEscape )
-import Id ( getIdPrimRep )
-import Util
+import HeapOffs ( VirtualSpBOffset(..) )
+import Id ( idPrimRep )
\end{code}
%************************************************************************
cgLetNoEscapeBody all_args rhs
= getVirtSps `thenFC` \ (vA, vB) ->
- getIntSwitchChkrC `thenFC` \ isw_chkr ->
let
- arg_kinds = map getIdPrimRep all_args
- (arg_regs, _) = assignRegs isw_chkr [{-nothing live-}] arg_kinds
+ arg_kinds = map idPrimRep all_args
+ (arg_regs, _) = assignRegs [{-nothing live-}] arg_kinds
stk_args = drop (length arg_regs) all_args
-- stk_args is the args which are passed on the stack at the fast-entry point
(spA_stk_args, spB_stk_args, stk_bxd_w_offsets, stk_ubxd_w_offsets)
= mkVirtStkOffsets
vA vB -- Initial virtual SpA, SpB
- getIdPrimRep
+ idPrimRep
stk_args
in
--- /dev/null
+\begin{code}
+interface CgLoop1 where
+import PreludeStdIO ( Maybe )
+
+import CgBindery ( CgBindings(..), CgIdInfo(..),
+ VolatileLoc, StableLoc,
+ nukeVolatileBinds,
+ maybeAStkLoc, maybeBStkLoc
+ )
+import CgUsages ( getSpBRelOffset )
+
+import AbsCSyn ( RegRelative )
+import CgMonad ( FCode(..) )
+import ClosureInfo ( LambdaFormInfo )
+import HeapOffs ( VirtualSpAOffset(..), VirtualSpBOffset(..) )
+import Id ( IdEnv(..), Id(..) )
+
+type CgBindings = IdEnv CgIdInfo
+
+data CgIdInfo
+ = MkCgIdInfo Id -- Id that this is the info for
+ VolatileLoc
+ StableLoc
+ LambdaFormInfo
+
+data VolatileLoc
+data StableLoc
+data LambdaFormInfo
+
+nukeVolatileBinds :: CgBindings -> CgBindings
+maybeAStkLoc :: StableLoc -> Maybe VirtualSpAOffset
+maybeBStkLoc :: StableLoc -> Maybe VirtualSpBOffset
+
+getSpBRelOffset :: VirtualSpBOffset -> FCode RegRelative
+\end{code}
--- /dev/null
+Break loops caused by cgExpr and getPrimOpArgAmodes.
+\begin{code}
+interface CgLoop2 where
+
+import CgExpr ( cgExpr, cgSccExpr, getPrimOpArgAmodes )
+
+import AbsCSyn ( CAddrMode )
+import CgMonad ( Code(..), FCode(..) )
+import PrimOp ( PrimOp )
+import StgSyn ( StgExpr(..), StgArg(..) )
+
+cgExpr :: StgExpr -> Code
+cgSccExpr :: StgExpr -> Code
+getPrimOpArgAmodes :: PrimOp -> [StgArg] -> FCode [CAddrMode]
+\end{code}
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[CgMonad]{The code generation monad}
-- addFreeASlots, -- no need to export it
addFreeBSlots, -- ToDo: Belong elsewhere
- isSwitchSetC, isStringSwitchSetC, getIntSwitchChkrC,
-
noBlackHolingFlag,
profCtrC,
sequelToAmode,
-- out of general friendliness, we also export ...
- CgBindings(..),
CgInfoDownwards(..), CgState(..), -- non-abstract
- CgIdInfo, -- abstract
- CompilationInfo(..), IntSwitchChecker(..),
-
- stableAmodeIdInfo, heapIdInfo
-
- -- and to make the interface self-sufficient...
+ CompilationInfo(..)
) where
+import Ubiq{-uitous-}
+import CgLoop1 -- stuff from CgBindery and CgUsages
+
import AbsCSyn
-import Type ( primRepFromType, Type
- IF_ATTACK_PRAGMAS(COMMA cmpUniType)
+import AbsCUtils ( mkAbsCStmts )
+import CmdLineOpts ( opt_SccProfilingOn, opt_DoTickyProfiling,
+ opt_OmitBlackHoling
+ )
+import HeapOffs ( maxOff,
+ VirtualSpAOffset(..), VirtualSpBOffset(..)
+ )
+import Id ( idType,
+ nullIdEnv, mkIdEnv, addOneToIdEnv,
+ modifyIdEnv, lookupIdEnv, rngIdEnv, IdEnv(..),
+ ConTag(..), GenId{-instance Outputable-}
)
-import CgBindery
-import CgUsages ( getSpBRelOffset )
-import CmdLineOpts ( GlobalSwitch(..) )
-import Id ( idType, ConTag(..), DataCon(..) )
-import Maybes ( catMaybes, maybeToBool, Maybe(..) )
-import Pretty -- debugging only?
-import PrimRep ( getPrimRepSize, retPrimRepSize )
-import UniqSet -- ( elementOfUniqSet, UniqSet(..) )
-import CostCentre -- profiling stuff
-import StgSyn ( StgArg(..), StgLiveVars(..) )
-import Util
+import Maybes ( maybeToBool )
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-} )
+import Pretty ( ppAboves, ppCat, ppStr )
+import PrimRep ( getPrimRepSize, PrimRep(..) )
+import StgSyn ( StgLiveVars(..) )
+import Type ( typePrimRep )
+import UniqSet ( elementOfUniqSet )
+import Util ( sortLt, panic, pprPanic )
infixr 9 `thenC` -- Right-associative!
infixr 9 `thenFC`
CgStksAndHeapUsage
\end{code}
-@EndOfBlockInfo@ tells what to do at the end of this block of code
-or, if the expression is a @case@, what to do at the end of each alternative.
+@EndOfBlockInfo@ tells what to do at the end of this block of code or,
+if the expression is a @case@, what to do at the end of each
+alternative.
\begin{code}
data EndOfBlockInfo
= EndOfBlockInfo
- VirtualSpAOffset -- Args SpA: trim the A stack to this point at a return;
- -- push arguments starting just above this point on
- -- a tail call.
-
- -- This is therefore the A-stk ptr as seen
- -- by a case alternative.
-
- -- Args SpA is used when we want to stub any
- -- currently-unstubbed dead A-stack (ptr) slots;
- -- we want to know what SpA in the continuation is
- -- so that we don't stub any slots which are off the
- -- top of the continuation's stack!
-
- VirtualSpBOffset -- Args SpB: Very similar to Args SpA.
-
- -- Two main differences:
- -- 1. If Sequel isn't OnStack, then Args SpB points
- -- just below the slot in which the return address
- -- should be put. In effect, the Sequel is
- -- a pending argument. If it is OnStack, Args SpB
- -- points to the top word of the return address.
- --
- -- 2. It ain't used for stubbing because there are
- -- no ptrs on B stk.
-
+ VirtualSpAOffset -- Args SpA: trim the A stack to this point at a
+ -- return; push arguments starting just
+ -- above this point on a tail call.
+
+ -- This is therefore the A-stk ptr as seen
+ -- by a case alternative.
+
+ -- Args SpA is used when we want to stub any
+ -- currently-unstubbed dead A-stack (ptr)
+ -- slots; we want to know what SpA in the
+ -- continuation is so that we don't stub any
+ -- slots which are off the top of the
+ -- continuation's stack!
+
+ VirtualSpBOffset -- Args SpB: Very similar to Args SpA.
+ -- Two main differences:
+ -- 1. If Sequel isn't OnStack, then Args SpB points
+ -- just below the slot in which the return address
+ -- should be put. In effect, the Sequel
+ -- is a pending argument. If it is
+ -- OnStack, Args SpB
+ -- points to the top word of the return
+ -- address.
+ --
+ -- 2. It ain't used for stubbing because there are
+ -- no ptrs on B stk.
Sequel
-
initEobInfo = EndOfBlockInfo 0 0 InRetReg
-
-
\end{code}
Any addressing modes inside @Sequel@ must be ``robust,'' in the sense
\begin{code}
data Sequel
- = InRetReg -- The continuation is in RetReg
-
- | OnStack VirtualSpBOffset
- -- Continuation is on the stack, at the
- -- specified location
+ = InRetReg -- The continuation is in RetReg
- | UpdateCode CAddrMode -- May be standard update code, or might be
- -- the data-type-specific one.
+ | OnStack VirtualSpBOffset
+ -- Continuation is on the stack, at the
+ -- specified location
- | CaseAlts
- CAddrMode -- Jump to this; if the continuation is for a vectored
- -- case this might be the label of a return vector
- -- Guaranteed to be a non-volatile addressing mode (I think)
+ | UpdateCode CAddrMode -- May be standard update code, or might be
+ -- the data-type-specific one.
- SemiTaggingStuff
+ | CaseAlts
+ CAddrMode -- Jump to this; if the continuation is for a vectored
+ -- case this might be the label of a return
+ -- vector Guaranteed to be a non-volatile
+ -- addressing mode (I think)
+ SemiTaggingStuff
type SemiTaggingStuff
= Maybe -- Maybe[1] we don't have any semi-tagging stuff...
type JoinDetails
= (AbstractC, CLabel) -- Code to load regs from heap object + profiling macros,
-- and join point label
--- The abstract C is executed only from a successful
--- semitagging venture, when a case has looked at a variable, found
--- that it's evaluated, and wants to load up the contents and go to the
--- join point.
+-- The abstract C is executed only from a successful semitagging
+-- venture, when a case has looked at a variable, found that it's
+-- evaluated, and wants to load up the contents and go to the join
+-- point.
-- DIRE WARNING.
--- The OnStack case of sequelToAmode delivers an Amode which is only valid
--- just before the final control transfer, because it assumes that
--- SpB is pointing to the top word of the return address.
--- This seems unclean but there you go.
+-- The OnStack case of sequelToAmode delivers an Amode which is only
+-- valid just before the final control transfer, because it assumes
+-- that SpB is pointing to the top word of the return address. This
+-- seems unclean but there you go.
sequelToAmode :: Sequel -> FCode CAddrMode
\begin{code}
costCentresC :: FAST_STRING -> [CAddrMode] -> Code
-costCentresC macro args (MkCgInfoDown (MkCompInfo sw_chkr _ _) _ _)
- state@(MkCgState absC binds usage)
- = if sw_chkr SccProfilingOn
+costCentresC macro args _ state@(MkCgState absC binds usage)
+ = if opt_SccProfilingOn
then MkCgState (mkAbsCStmts absC (CCallProfCCMacro macro args)) binds usage
else state
profCtrC :: FAST_STRING -> [CAddrMode] -> Code
-profCtrC macro args (MkCgInfoDown (MkCompInfo sw_chkr _ _) _ _)
- state@(MkCgState absC binds usage)
- = if not (sw_chkr DoTickyProfiling)
+profCtrC macro args _ state@(MkCgState absC binds usage)
+ = if not opt_DoTickyProfiling
then state
else MkCgState (mkAbsCStmts absC (CCallProfCtrMacro macro args)) binds usage
\begin{code}
noBlackHolingFlag, costCentresFlag :: FCode Bool
-noBlackHolingFlag (MkCgInfoDown (MkCompInfo sw_chkr _ _) _ _) state
- = (sw_chkr OmitBlackHoling, state)
-
-costCentresFlag (MkCgInfoDown (MkCompInfo sw_chkr _ _) _ _) state
- = (sw_chkr SccProfilingOn, state)
+noBlackHolingFlag _ state = (opt_OmitBlackHoling, state)
+costCentresFlag _ state = (opt_SccProfilingOn, state)
\end{code}
\begin{code}
moduleName :: FCode FAST_STRING
-moduleName (MkCgInfoDown (MkCompInfo _ _ mod_name) _ _) state
+moduleName (MkCgInfoDown (MkCompInfo mod_name) _ _) state
= (mod_name, state)
\end{code}
_ -> dead_slots live_vars fbs das dbs bs
where
size :: Int
- size = (getPrimRepSize . primRepFromType . idType) v
+ size = (getPrimRepSize . typePrimRep . idType) v
-- addFreeSlots expects *both* args to be in increasing order
addFreeASlots :: [(Int,StubFlag)] -> [(Int,StubFlag)] -> [(Int,StubFlag)]
ctrlReturnConvAlg,
dataReturnConvAlg,
- mkLiveRegsBitMask, noLiveRegsMask,
-
dataReturnConvPrim,
assignPrimOpResultRegs,
-- and to make the interface self-sufficient...
) where
-import AbsCSyn
+import Ubiq{-uitous-}
+import AbsCLoop -- paranoia checking
-import PrelInfo ( PrimOp(..), PrimOpResultInfo(..), primOpCanTriggerGC,
- getPrimOpResultInfo, integerDataCon
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
+import AbsCSyn -- quite a few things
+import AbsCUtils ( mkAbstractCs, getAmodeRep,
+ amodeCanSurviveGC
+ )
+import CgCompInfo ( mAX_FAMILY_SIZE_FOR_VEC_RETURNS,
+ mAX_Vanilla_REG, mAX_Float_REG,
+ mAX_Double_REG
+ )
+import CmdLineOpts ( opt_ReturnInRegsThreshold )
+import Id ( isDataCon, dataConSig,
+ DataCon(..), GenId{-instance Eq-}
)
-import Type ( getTyConFamilySize, primRepFromType, getTyConDataCons,
- TyVarTemplate, TyCon, Class,
- TauType(..), ThetaType(..), Type
+import Maybes ( catMaybes )
+import PprStyle ( PprStyle(..) )
+import PprType ( TyCon{-instance Outputable-} )
+import PrelInfo ( integerDataCon )
+import PrimOp ( primOpCanTriggerGC,
+ getPrimOpResultInfo, PrimOpResultInfo(..),
+ PrimOp{-instance Outputable-}
)
-import CgCompInfo -- various things
-import CgMonad ( IntSwitchChecker(..) )
-import CmdLineOpts ( GlobalSwitch(..) )
-import Id ( Id, getDataConSig, fIRST_TAG, isDataCon,
- DataCon(..), ConTag(..)
+import PrimRep ( isFloatingRep, PrimRep(..) )
+import TyCon ( tyConDataCons, tyConFamilySize )
+import Type ( typePrimRep )
+import Util ( zipWithEqual, mapAccumL, isn'tIn,
+ pprError, pprTrace, panic, assertPanic
)
-import Maybes ( catMaybes, Maybe(..) )
-import PrimRep
-import Util
-import Pretty
\end{code}
%************************************************************************
ctrlReturnConvAlg :: TyCon -> CtrlReturnConvention
ctrlReturnConvAlg tycon
- = case (getTyConFamilySize tycon) of
- Nothing -> -- pprPanic "ctrlReturnConvAlg:" (ppr PprDebug tycon)
- UnvectoredReturn 0 -- e.g., w/ "data Bin"
+ = case (tyConFamilySize tycon) of
+ 0 -> pprTrace "ctrlReturnConvAlg:" (ppr PprDebug tycon) $
+ UnvectoredReturn 0 -- e.g., w/ "data Bin"
- Just size -> -- we're supposed to know...
+ size -> -- we're supposed to know...
if (size > (1::Int) && size <= mAX_FAMILY_SIZE_FOR_VEC_RETURNS) then
VectoredReturn size
else
then it gives up, returning @ReturnInHeap@.
\begin{code}
-dataReturnConvAlg :: IntSwitchChecker -> DataCon -> DataReturnConvention
+dataReturnConvAlg :: DataCon -> DataReturnConvention
-dataReturnConvAlg isw_chkr data_con
+dataReturnConvAlg data_con
= ASSERT(isDataCon data_con)
case leftover_kinds of
[] -> ReturnInRegs reg_assignment
other -> ReturnInHeap -- Didn't fit in registers
where
- (_, _, arg_tys, _) = getDataConSig data_con
+ (_, _, arg_tys, _) = dataConSig data_con
(reg_assignment, leftover_kinds)
- = assignRegs isw_chkr_to_use
- [node, infoptr] -- taken...
- (map primRepFromType arg_tys)
-
- isw_chkr_to_use = isw_chkr
+ = assignRegs [node, infoptr] -- taken...
+ (map typePrimRep arg_tys)
is_prim_result_ty = data_con == integerDataCon -- ***HACK***! (WDP 95/11)
\end{code}
-\begin{code}
-noLiveRegsMask :: Int -- Mask indicating nothing live
-noLiveRegsMask = 0
-
-mkLiveRegsBitMask
- :: [MagicId] -- Candidate live regs; depends what they have in them
- -> Int
-
-mkLiveRegsBitMask regs
- = foldl do_reg noLiveRegsMask regs
- where
- do_reg acc (VanillaReg kind reg_no)
- | isFollowableRep kind
- = acc + (reg_tbl !! IBOX(reg_no _SUB_ ILIT(1)))
-
- do_reg acc anything_else = acc
-
- reg_tbl -- ToDo: mk Array!
- = [lIVENESS_R1, lIVENESS_R2, lIVENESS_R3, lIVENESS_R4,
- lIVENESS_R5, lIVENESS_R6, lIVENESS_R7, lIVENESS_R8]
-
-{-
--- Completely opaque code. ADR
--- What's wrong with: (untested)
-
-mkLiveRegsBitMask regs
- = foldl (+) noLiveRegsMask (map liveness_bit regs)
- where
- liveness_bit (VanillaReg kind reg_no)
- | isFollowableRep kind
- = reg_tbl !! (reg_no - 1)
-
- liveness_bit anything_else
- = noLiveRegsBitMask
-
- reg_tbl
- = [lIVENESS_R1, lIVENESS_R2, lIVENESS_R3, lIVENESS_R4,
- lIVENESS_R5, lIVENESS_R6, lIVENESS_R7, lIVENESS_R8]
--}
-\end{code}
-
-
%************************************************************************
%* *
\subsection[CgRetConv-prim]{Return conventions for primitive datatypes}
ReturnsAlg tycon
-> let
- cons = getTyConDataCons tycon
+ cons = tyConDataCons tycon
result_regs = concat (map get_return_regs cons)
in
-- As R1 is dead, it can hold the tag if necessary
other -> (VanillaReg IntRep ILIT(1)) : result_regs
where
get_return_regs con
- = case (dataReturnConvAlg fake_isw_chkr con) of
+ = case (dataReturnConvAlg con) of
ReturnInRegs regs -> regs
ReturnInHeap -> panic "getPrimOpAlgResultRegs"
-
- fake_isw_chkr :: IntSwitchChecker
- fake_isw_chkr x = Nothing
\end{code}
@assignPrimOpArgsRobust@ is used only for primitive ops which may
arg_kinds = map getAmodeRep non_robust_amodes
(arg_regs, extra_args)
- = assignRegs fake_isw_chkr [{-nothing live-}] arg_kinds
+ = assignRegs [{-nothing live-}] arg_kinds
-- Check that all the args fit before returning arg_regs
final_arg_regs = case extra_args of
[] -> arg_regs
- other -> error ("Cannot allocate enough registers for primop (try rearranging code or reducing number of arguments?) " ++ ppShow 80 (ppr PprDebug op))
+ other -> pprError "Cannot allocate enough registers for primop (try rearranging code or reducing number of arguments?)" (ppr PprDebug op)
arg_assts
= mkAbstractCs (zipWithEqual assign_to_reg final_arg_regs non_robust_amodes)
| otherwise = (tail regs, CReg (head regs))
safe_amodes = snd (mapAccumL safe_arg final_arg_regs arg_amodes)
- liveness_mask = mkLiveRegsBitMask final_arg_regs
+ liveness_mask = mkLiveRegsMask final_arg_regs
in
(safe_amodes, liveness_mask, arg_assts)
- where
- fake_isw_chkr :: IntSwitchChecker
- fake_isw_chkr x = Nothing
\end{code}
%************************************************************************
register); we just return immediately with the left-overs specified.
\begin{code}
-assignRegs :: IntSwitchChecker
- -> [MagicId] -- Unavailable registers
+assignRegs :: [MagicId] -- Unavailable registers
-> [PrimRep] -- Arg or result kinds to assign
-> ([MagicId], -- Register assignment in same order
-- for *initial segment of* input list
[PrimRep])-- leftover kinds
-assignRegs isw_chkr regs_in_use kinds
- = assign_reg kinds [] (mkRegTbl isw_chkr regs_in_use)
+assignRegs regs_in_use kinds
+ = assign_reg kinds [] (mkRegTbl regs_in_use)
where
assign_reg :: [PrimRep] -- arg kinds being scrutinized
floatRegNos = [1 .. mAX_Float_REG]
doubleRegNos = [1 .. mAX_Double_REG]
-mkRegTbl :: IntSwitchChecker -> [MagicId] -> ([Int], [Int], [Int])
+mkRegTbl :: [MagicId] -> ([Int], [Int], [Int])
-mkRegTbl isw_chkr regs_in_use
+mkRegTbl regs_in_use
= (ok_vanilla, ok_float, ok_double)
where
ok_vanilla = catMaybes (map (select (VanillaReg VoidRep)) (taker vanillaRegNos))
taker :: [Int] -> [Int]
taker rs
- = case (isw_chkr ReturnInRegsThreshold) of
+ = case (opt_ReturnInRegsThreshold) of
Nothing -> rs -- no flag set; use all of them
Just n -> take n rs
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[CgStackery]{Stack management functions}
allocAStack, allocBStack, allocUpdateFrame,
adjustRealSps, getFinalStackHW,
mkVirtStkOffsets, mkStkAmodes
-
- -- and to make the interface self-sufficient...
) where
-import StgSyn
+import Ubiq{-uitous-}
+
import CgMonad
import AbsCSyn
-import CgUsages ( getSpBRelOffset )
-import Maybes ( Maybe(..) )
-import PrimRep ( getPrimRepSize, retPrimRepSize, separateByPtrFollowness )
-import Util
+import AbsCUtils ( mkAbstractCs, mkAbsCStmts, getAmodeRep )
+import HeapOffs ( VirtualSpAOffset(..), VirtualSpBOffset(..) )
+import PrimRep ( getPrimRepSize, separateByPtrFollowness,
+ PrimRep(..)
+ )
+import Util ( mapAccumR, panic )
\end{code}
%************************************************************************
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
%********************************************************
%* *
mkPrimReturnCode,
tailCallBusiness
-
- -- and to make the interface self-sufficient...
) where
-IMPORT_Trace
-import Pretty -- Pretty/Outputable: rm (debugging only) ToDo
-import Outputable
+import Ubiq{-uitous-}
-import StgSyn
import CgMonad
import AbsCSyn
-import Type ( isPrimType, Type )
-import CgBindery ( getAtomAmodes, getCAddrMode, getCAddrModeAndInfo )
-import CgCompInfo ( oTHER_TAG, iND_TAG )
-import CgRetConv ( dataReturnConvPrim, ctrlReturnConvAlg, dataReturnConvAlg,
- mkLiveRegsBitMask,
- CtrlReturnConvention(..), DataReturnConvention(..)
+import AbsCUtils ( mkAbstractCs, mkAbsCStmts, getAmodeRep )
+import CgBindery ( getArgAmodes, getCAddrMode, getCAddrModeAndInfo )
+import CgRetConv ( dataReturnConvPrim, dataReturnConvAlg,
+ ctrlReturnConvAlg, CtrlReturnConvention(..),
+ DataReturnConvention(..)
)
import CgStackery ( adjustRealSps, mkStkAmodes )
-import CgUsages ( getSpARelOffset, getSpBRelOffset )
-import CLabel ( CLabel, mkStdUpdCodePtrVecLabel, mkConUpdCodePtrVecLabel )
-import ClosureInfo ( nodeMustPointToIt, getEntryConvention, EntryConvention(..) )
-import CmdLineOpts ( GlobalSwitch(..) )
-import Id ( getDataConTyCon, getDataConTag,
- idType, getIdPrimRep, fIRST_TAG, Id,
- ConTag(..)
+import CgUsages ( getSpARelOffset )
+import CLabel ( mkStdUpdCodePtrVecLabel, mkConUpdCodePtrVecLabel )
+import ClosureInfo ( nodeMustPointToIt,
+ getEntryConvention, EntryConvention(..)
+ )
+import CmdLineOpts ( opt_EmitArityChecks, opt_DoSemiTagging )
+import HeapOffs ( zeroOff, VirtualSpAOffset(..) )
+import Id ( idType, dataConTyCon, dataConTag,
+ fIRST_TAG
)
-import Maybes ( assocMaybe, maybeToBool, Maybe(..) )
-import PrimRep ( retPrimRepSize )
-import Util
+import Literal ( mkMachInt )
+import Maybes ( assocMaybe )
+import PrimRep ( PrimRep(..) )
+import StgSyn ( StgArg(..), GenStgArg(..), StgLiveVars(..) )
+import Type ( isPrimType )
+import Util ( zipWithEqual, panic, assertPanic )
\end{code}
%************************************************************************
-- Set the info pointer, and jump
set_info_ptr `thenC`
- getIntSwitchChkrC `thenFC` \ isw_chkr ->
- absC (CJump (CLbl (update_label isw_chkr) CodePtrRep))
+ absC (CJump (CLbl update_label CodePtrRep))
CaseAlts _ (Just (alts, _)) -> -- Ho! We know the constructor so
-- we can go right to the alternative
)
where
- tag = getDataConTag con
- tycon = getDataConTyCon con
+ tag = dataConTag con
+ tycon = dataConTyCon con
return_convention = ctrlReturnConvAlg tycon
zero_indexed_tag = tag - fIRST_TAG -- Adjust tag to be zero-indexed
-- cf AbsCUtils.mkAlgAltsCSwitch
- update_label isw_chkr
- = case (dataReturnConvAlg isw_chkr con) of
+ update_label
+ = case (dataReturnConvAlg con) of
ReturnInHeap -> mkStdUpdCodePtrVecLabel tycon tag
ReturnInRegs _ -> mkConUpdCodePtrVecLabel tycon tag
= -- Get all the info we have about the function and args and go on to
-- the business end
getCAddrModeAndInfo fun `thenFC` \ (fun_amode, lf_info) ->
- getAtomAmodes args `thenFC` \ arg_amodes ->
+ getArgAmodes args `thenFC` \ arg_amodes ->
tailCallBusiness
fun fun_amode lf_info arg_amodes
-> Code
tailCallBusiness fun fun_amode lf_info arg_amodes live_vars pending_assts
- = isSwitchSetC EmitArityChecks `thenFC` \ do_arity_chks ->
-
+ = let
+ do_arity_chks = opt_EmitArityChecks
+ in
nodeMustPointToIt lf_info `thenFC` \ node_points ->
getEntryConvention fun lf_info
(map getAmodeRep arg_amodes) `thenFC` \ entry_conv ->
adjustRealSps final_spa final_spb `thenC`
-- Now decide about semi-tagging
- isSwitchSetC DoSemiTagging `thenFC` \ semi_tagging_on ->
+ let
+ semi_tagging_on = opt_DoSemiTagging
+ in
case (semi_tagging_on, arg_amodes, node_points, sequel) of
--
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1994
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[CgUpdate]{Manipulating update frames}
module CgUpdate ( pushUpdateFrame ) where
-import StgSyn
+import Ubiq{-uitous-}
+
import CgMonad
import AbsCSyn
-import CgCompInfo ( sTD_UF_SIZE, cON_UF_SIZE,
- sCC_STD_UF_SIZE, sCC_CON_UF_SIZE,
- spARelToInt, spBRelToInt
- )
+import CgCompInfo ( sTD_UF_SIZE, sCC_STD_UF_SIZE )
import CgStackery ( allocUpdateFrame )
-import CgUsages
-import CmdLineOpts ( GlobalSwitch(..) )
-import Util
+import CmdLineOpts ( opt_SccProfilingOn )
+import Util ( assertPanic )
\end{code}
pushUpdateFrame :: CAddrMode -> CAddrMode -> Code -> Code
pushUpdateFrame updatee vector code
- = isSwitchSetC SccProfilingOn `thenFC` \ profiling_on ->
- let
+ = let
+ profiling_on = opt_SccProfilingOn
+
-- frame_size *includes* the return address
frame_size = if profiling_on
then sCC_STD_UF_SIZE
getHpRelOffset, getSpARelOffset, getSpBRelOffset,
- freeBStkSlot,
-
- -- and to make the interface self-sufficient...
- AbstractC, HeapOffset, RegRelative, CgState
+ freeBStkSlot
) where
-import AbsCSyn
+import Ubiq{-uitous-}
+import CgLoop1 -- here for paranoia-checking
+
+import AbsCSyn ( RegRelative(..), AbstractC, CAddrMode )
import CgMonad
-import Util
+import HeapOffs ( zeroOff,
+ VirtualHeapOffset(..),
+ VirtualSpAOffset(..),
+ VirtualSpBOffset(..)
+ )
+import Id ( IdEnv(..) )
\end{code}
%************************************************************************
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[ClosureInfo]{Data structures which describe closures}
closureKind, closureTypeDescr, -- profiling
- isConstantRep, isSpecRep, isPhantomRep, -- ToDo: Should be in SMRep, perhaps?
isStaticClosure, allocProfilingMsg,
blackHoleClosureInfo,
- getSMInfoStr, getSMInitHdrStr, getSMUpdInplaceHdrStr,
- ltSMRepHdr,
maybeSelectorInfo,
dataConLiveness -- concurrency
-
- -- and to make the interface self-sufficient...
) where
+import Ubiq{-uitous-}
+import AbsCLoop -- here for paranoia-checking
+
import AbsCSyn
-import CgMonad
-import SMRep
import StgSyn
+import CgMonad
-import Type
-import CgCompInfo -- some magic constants
-import CgRetConv
-import CLabel -- Lots of label-making things
-import CmdLineOpts ( GlobalSwitch(..) )
-import Id
-import IdInfo -- SIGH
-import Maybes ( maybeToBool, assocMaybe, Maybe(..) )
-import Outputable -- needed for INCLUDE_FRC_METHOD
-import Pretty -- ( ppStr, Pretty(..) )
-import PrimRep ( PrimRep, getPrimRepSize, separateByPtrFollowness )
-import Util
+import CgCompInfo ( mAX_SPEC_SELECTEE_SIZE,
+ mIN_UPD_SIZE, mIN_SIZE_NonUpdHeapObject,
+ mAX_SPEC_ALL_PTRS, mAX_SPEC_MIXED_FIELDS,
+ mAX_SPEC_ALL_NONPTRS,
+ oTHER_TAG
+ )
+import CgRetConv ( assignRegs, dataReturnConvAlg,
+ DataReturnConvention(..)
+ )
+import CLabel ( mkStdEntryLabel, mkFastEntryLabel,
+ mkPhantomInfoTableLabel, mkInfoTableLabel,
+ mkBlackHoleInfoTableLabel, mkVapInfoTableLabel,
+ mkStaticInfoTableLabel, mkStaticConEntryLabel,
+ mkConEntryLabel, mkClosureLabel, mkVapEntryLabel
+ )
+import CmdLineOpts ( opt_SccProfilingOn, opt_ForConcurrent )
+import HeapOffs ( intOff, addOff, totHdrSize, varHdrSize,
+ intOffsetIntoGoods,
+ VirtualHeapOffset(..)
+ )
+import Id ( idType, idPrimRep, getIdArity,
+ externallyVisibleId, dataConSig,
+ dataConTag, fIRST_TAG,
+ isDataCon, dataConArity, dataConTyCon,
+ isTupleCon, DataCon(..),
+ GenId{-instance Eq-}
+ )
+import IdInfo ( arityMaybe )
+import Maybes ( assocMaybe, maybeToBool )
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-} )
+import PrimRep ( getPrimRepSize, separateByPtrFollowness )
+import SMRep -- all of it
+import TyCon ( maybeTyConSingleCon, TyCon{-instance NamedThing-} )
+import Type ( isPrimType, splitForAllTy, splitFunTy, mkFunTys )
+import Util ( isIn, mapAccumL, panic, pprPanic, assertPanic )
+
+maybeCharLikeTyCon = panic "ClosureInfo.maybeCharLikeTyCon (ToDo)"
+maybeIntLikeTyCon = panic "ClosureInfo.maybeIntLikeTyCon (ToDo)"
+getDataSpecTyCon_maybe = panic "ClosureInfo.getDataSpecTyCon_maybe (ToDo)"
+getTyDescription = panic "ClosureInfo.getTyDescription (ToDo)"
\end{code}
The ``wrapper'' data type for closure information:
-- ASSERT(is_single_constructor) -- Should be true, by causes error for SpecTyCon
LFThunk False False True (SelectorThunk scrutinee con offset_into_int)
where
- (_, params_w_offsets) = layOutDynCon con getIdPrimRep params
+ (_, params_w_offsets) = layOutDynCon con idPrimRep params
maybe_offset = assocMaybe params_w_offsets selectee
Just the_offset = maybe_offset
offset_into_int_maybe = intOffsetIntoGoods the_offset
Just offset_into_int = offset_into_int_maybe
- is_single_constructor = maybeToBool (maybeSingleConstructorTyCon tycon)
- (_,_,_, tycon) = getDataConSig con
+ is_single_constructor = maybeToBool (maybeTyConSingleCon tycon)
+ (_,_,_, tycon) = dataConSig con
\end{code}
Same kind of thing, looking for vector-apply thunks, of the form:
mkConLFInfo con
= ASSERT(isDataCon con)
let
- arity = getDataConArity con
+ arity = dataConArity con
in
if isTupleCon con then
LFTuple con (arity == 0)
else if maybeToBool (maybeIntLikeTyCon tycon) then IntLikeRep
else SpecRep
where
- tycon = getDataConTyCon con
+ tycon = dataConTyCon con
_ -> SpecRep
in
the result list
\begin{code}
-mkVirtHeapOffsets :: SMRep -- Representation to be used by storage manager
+mkVirtHeapOffsets :: SMRep -- Representation to be used by storage manager
-> (a -> PrimRep) -- To be able to grab kinds;
- -- w/ a kind, we can find boxedness
- -> [a] -- Things to make offsets for
- -> (Int, -- *Total* number of words allocated
- Int, -- Number of words allocated for *pointers*
- [(a, VirtualHeapOffset)]) -- Things with their offsets from start of object
- -- in order of increasing offset
+ -- w/ a kind, we can find boxedness
+ -> [a] -- Things to make offsets for
+ -> (Int, -- *Total* number of words allocated
+ Int, -- Number of words allocated for *pointers*
+ [(a, VirtualHeapOffset)])
+ -- Things with their offsets from start of object
+ -- in order of increasing offset
-- First in list gets lowest offset, which is initial offset + 1.
\begin{code}
nodeMustPointToIt :: LambdaFormInfo -> FCode Bool
nodeMustPointToIt lf_info
- = isSwitchSetC SccProfilingOn `thenFC` \ do_profiling ->
-
+ = let
+ do_profiling = opt_SccProfilingOn
+ in
case lf_info of
LFReEntrant top arity no_fvs -> returnFC (
not no_fvs || -- Certainly if it has fvs we need to point to it
getEntryConvention id lf_info arg_kinds
= nodeMustPointToIt lf_info `thenFC` \ node_points ->
- isSwitchSetC ForConcurrent `thenFC` \ is_concurrent ->
- getIntSwitchChkrC `thenFC` \ isw_chkr ->
+ let
+ is_concurrent = opt_ForConcurrent
+ in
returnFC (
if (node_points && is_concurrent) then ViaNode else
else
DirectEntry (mkFastEntryLabel id arity) arity arg_regs
where
- (arg_regs, _) = assignRegs isw_chkr live_regs (take arity arg_kinds)
+ (arg_regs, _) = assignRegs live_regs (take arity arg_kinds)
live_regs = if node_points then [node] else []
LFCon con zero_arity
-> ASSERT(arity == length arg_kinds)
DirectEntry (mkStdEntryLabel id) arity arg_regs
where
- (arg_regs, _) = assignRegs isw_chkr live_regs arg_kinds
+ (arg_regs, _) = assignRegs live_regs arg_kinds
live_regs = if node_points then [node] else []
)
%************************************************************************
\begin{code}
-isConstantRep, isSpecRep, isStaticRep, isPhantomRep, isIntLikeRep :: SMRep -> Bool
-isConstantRep (SpecialisedRep ConstantRep _ _ _) = True
-isConstantRep other = False
-
-isSpecRep (SpecialisedRep kind _ _ _) = True -- All the kinds of Spec closures
-isSpecRep other = False -- True indicates that the _VHS is 0 !
-
-isStaticRep (StaticRep _ _) = True
-isStaticRep _ = False
-
-isPhantomRep PhantomRep = True
-isPhantomRep _ = False
-
-isIntLikeRep (SpecialisedRep IntLikeRep _ _ _) = True
-isIntLikeRep other = False
isStaticClosure :: ClosureInfo -> Bool
isStaticClosure (MkClosureInfo _ _ rep) = isStaticRep rep
-- rather than take it from the Id. The Id is probably just "f"!
closureType (MkClosureInfo id (LFThunk _ _ _ (VapThunk fun_id args _)) _)
- = getUniDataSpecTyCon_maybe (funResultTy de_foralld_ty (length args))
- where
- (_, de_foralld_ty) = splitForalls (idType fun_id)
+ = getDataSpecTyCon_maybe (fun_result_ty (length args) fun_id)
-closureType (MkClosureInfo id lf _) = getUniDataSpecTyCon_maybe (idType id)
+closureType (MkClosureInfo id lf _) = getDataSpecTyCon_maybe (idType id)
\end{code}
@closureReturnsUnboxedType@ is used to check whether a closure, {\em
closureReturnsUnboxedType :: ClosureInfo -> Bool
closureReturnsUnboxedType (MkClosureInfo fun_id (LFReEntrant _ arity _) _)
- = isPrimType (funResultTy de_foralld_ty arity)
- where
- (_, de_foralld_ty) = splitForalls (idType fun_id)
+ = isPrimType (fun_result_ty arity fun_id)
closureReturnsUnboxedType other_closure = False
-- All non-function closures aren't functions,
-- and hence are boxed, since they are heap alloc'd
+
+-- ToDo: need anything like this in Type.lhs?
+fun_result_ty arity id
+ = let
+ (_, de_foralld_ty) = splitForAllTy (idType id)
+ (arg_tys, res_ty) = splitFunTy{-w/ dicts as args?-} de_foralld_ty
+ in
+ ASSERT(arity >= 0 && length arg_tys >= arity)
+ mkFunTys (drop arity arg_tys) res_ty
\end{code}
\begin{code}
closureSemiTag (MkClosureInfo _ lf_info _)
= case lf_info of
- LFCon data_con _ -> getDataConTag data_con - fIRST_TAG
+ LFCon data_con _ -> dataConTag data_con - fIRST_TAG
LFTuple _ _ -> 0
_ -> fromInteger oTHER_TAG
\end{code}
LFImported -> panic "ALLOC_IMP"
\end{code}
-We need a black-hole closure info to pass to @allocDynClosure@
-when we want to allocate the black hole on entry to a CAF.
+We need a black-hole closure info to pass to @allocDynClosure@ when we
+want to allocate the black hole on entry to a CAF.
\begin{code}
-blackHoleClosureInfo (MkClosureInfo id _ _) = MkClosureInfo id LFBlackHole BlackHoleRep
+blackHoleClosureInfo (MkClosureInfo id _ _)
+ = MkClosureInfo id LFBlackHole BlackHoleRep
\end{code}
-The register liveness when returning from a constructor. For simplicity,
-we claim just [node] is live for all but PhantomRep's. In truth, this means
-that non-constructor info tables also claim node, but since their liveness
-information is never used, we don't care.
+The register liveness when returning from a constructor. For
+simplicity, we claim just [node] is live for all but PhantomRep's. In
+truth, this means that non-constructor info tables also claim node,
+but since their liveness information is never used, we don't care.
\begin{code}
-
-dataConLiveness isw_chkr (MkClosureInfo con _ PhantomRep)
- = case (dataReturnConvAlg isw_chkr con) of
- ReturnInRegs regs -> mkLiveRegsBitMask regs
+dataConLiveness (MkClosureInfo con _ PhantomRep)
+ = case (dataReturnConvAlg con) of
+ ReturnInRegs regs -> mkLiveRegsMask regs
ReturnInHeap -> panic "dataConLiveness:PhantomRep in heap???"
-dataConLiveness _ _ = mkLiveRegsBitMask [node]
+dataConLiveness _ = mkLiveRegsMask [node]
\end{code}
%************************************************************************
closureTypeDescr :: ClosureInfo -> String
closureTypeDescr (MkClosureInfo id lf _)
= if (isDataCon id) then -- DataCon has function types
- _UNPK_ (getOccurrenceName (getDataConTyCon id)) -- We want the TyCon not the ->
+ _UNPK_ (getOccurrenceName (dataConTyCon id)) -- We want the TyCon not the ->
else
- getUniTyDescription (idType id)
+ getTyDescription (idType id)
\end{code}
-
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[CodeGen]{@CodeGen@: main module of the code generator}
module CodeGen ( codeGen ) where
+import Ubiq{-uitous-}
+
import StgSyn
import CgMonad
import AbsCSyn
-import CLabel ( modnameToC )
+import AbsCUtils ( mkAbstractCs, mkAbsCStmts )
+import Bag ( foldBag )
import CgClosure ( cgTopRhsClosure )
import CgCon ( cgTopRhsCon )
-import CgConTbls ( genStaticConBits, TCE(..), UniqFM )
-import ClosureInfo ( LambdaFormInfo, mkClosureLFInfo )
-import CmdLineOpts
-import FiniteMap ( FiniteMap )
-import Maybes ( Maybe(..) )
-import Pretty -- debugging only
-import PrimRep ( getPrimRepSize )
-import Util
+import CgConTbls ( genStaticConBits )
+import ClosureInfo ( mkClosureLFInfo )
+import CmdLineOpts ( opt_SccProfilingOn, opt_CompilingPrelude,
+ opt_EnsureSplittableC, opt_SccGroup
+ )
+import CStrings ( modnameToC )
+import Maybes ( maybeToBool )
+import PrimRep ( getPrimRepSize, PrimRep(..) )
+import Util ( panic, assertPanic )
\end{code}
\begin{code}
codeGen :: FAST_STRING -- module name
-> ([CostCentre], -- local cost-centres needing declaring/registering
[CostCentre]) -- "extern" cost-centres needing declaring
- -> [FAST_STRING] -- import names
+ -> Bag FAST_STRING -- import names
-> [TyCon] -- tycons with data constructors to convert
-> FiniteMap TyCon [(Bool, [Maybe Type])]
-- tycon specialisation info
= let
doing_profiling = opt_SccProfilingOn
compiling_prelude = opt_CompilingPrelude
- maybe_split = if (switch_is_on (EnsureSplittableC (panic "codeGen:esc")))
+ maybe_split = if maybeToBool (opt_EnsureSplittableC)
then CSplitMarker
else AbsCNop
- cinfo = MkCompInfo switch_is_on int_switch_set mod_name
+ cinfo = MkCompInfo mod_name
in
if not doing_profiling then
mkAbstractCs [
initC cinfo (cgTopBindings maybe_split stg_pgm) ]
where
-----------------
- grp_name = case (stringSwitchSet sw_lookup_fn SccGroup) of
- Just xx -> _PK_ xx
+ grp_name = case opt_SccGroup of
+ Just xx -> xx
Nothing -> mod_name -- default: module name
-----------------
mkCcRegister ccs import_names
= let
register_ccs = mkAbstractCs (map mk_register ccs)
- register_imports = mkAbstractCs (map mk_import_register import_names)
+ register_imports
+ = foldBag mkAbsCStmts mk_import_register AbsCNop import_names
in
mkAbstractCs [
CCallProfCCMacro SLIT("START_REGISTER_CCS") [CLitLit (modnameToC (SLIT("_reg") _APPEND_ mod_name)) AddrRep],
module SMRep (
SMRep(..), SMSpecRepKind(..), SMUpdateKind(..),
getSMInfoStr, getSMInitHdrStr, getSMUpdInplaceHdrStr,
- ltSMRepHdr
+ ltSMRepHdr,
+ isConstantRep, isSpecRep, isStaticRep, isPhantomRep,
+ isIntLikeRep
) where
import Ubiq{-uitous-}
--jim
-}
+\end{code}
+
+\begin{code}
+isConstantRep, isSpecRep, isStaticRep, isPhantomRep, isIntLikeRep :: SMRep -> Bool
+isConstantRep (SpecialisedRep ConstantRep _ _ _) = True
+isConstantRep other = False
+
+isSpecRep (SpecialisedRep kind _ _ _) = True -- All the kinds of Spec closures
+isSpecRep other = False -- True indicates that the _VHS is 0 !
+
+isStaticRep (StaticRep _ _) = True
+isStaticRep _ = False
+isPhantomRep PhantomRep = True
+isPhantomRep _ = False
+
+isIntLikeRep (SpecialisedRep IntLikeRep _ _ _) = True
+isIntLikeRep other = False
+\end{code}
+
+\begin{code}
instance Eq SMRep where
(SpecialisedRep k1 a1 b1 _) == (SpecialisedRep k2 a2 b2 _) = (tagOf_SMSpecRepKind k1) _EQ_ (tagOf_SMSpecRepKind k2)
&& a1 == a2 && b1 == b2
GenId{-instances-}
)
import PrelInfo ( liftDataCon, mkLiftTy, statePrimTyCon )
-import TyCon ( TyCon{-instance-} )
+import TyCon ( isBoxedTyCon, TyCon{-instance-} )
import Type ( maybeAppDataTyCon, eqTy )
import UniqSupply ( getUnique, getUniques, splitUniqSupply, UniqSupply )
import Util ( zipEqual, zipWithEqual, assertPanic, panic )
infixr 9 `thenL`
updateIdType = panic "CoreLift.updateIdType"
-isBoxedTyCon = panic "CoreLift.isBoxedTyCon"
\end{code}
%************************************************************************
import Id ( idType, isBottomingId,
getInstantiatedDataConSig, GenId{-instances-}
)
+import Maybes ( catMaybes )
import Outputable ( Outputable(..) )
import PprCore
import PprStyle ( PprStyle(..) )
import Type ( mkFunTy,getFunTy_maybe,mkForAllTy,getForAllTy_maybe,
isPrimType,getTypeKind,instantiateTy,
mkForAllUsageTy,getForAllUsageTy,instantiateUsage,
- maybeAppDataTyCon, eqTy )
-import TyCon ( isPrimTyCon,isVisibleDataTyCon )
+ maybeAppDataTyCon, eqTy
+ )
+import TyCon ( isPrimTyCon, tyConFamilySize )
import TyVar ( getTyVarKind, GenTyVar{-instances-} )
import UniqSet ( emptyUniqSet, mkUniqSet, intersectUniqSets,
- unionUniqSets, elementOfUniqSet, UniqSet(..) )
+ unionUniqSets, elementOfUniqSet, UniqSet(..)
+ )
import Unique ( Unique )
import Usage ( GenUsage )
import Util ( zipEqual, pprTrace, pprPanic, assertPanic, panic )
ppStr ("*** Core Lint Errors: in " ++ whoDunnit ++ " ***"),
msg sty,
ppStr "*** Offending Program ***",
- ppAboves
- (map (pprCoreBinding sty (pprBigCoreBinder sty) (pprTypedCoreBinder sty) (ppr sty))
- binds),
+ ppAboves (map (pprCoreBinding sty) binds),
ppStr "*** End of Offense ***"
])
where
-> TyCon -- TyCon pinned on the case
-> LintM (Maybe Type) -- Type of alternatives
-lintCoreAlts (AlgAlts alts deflt) ty tycon
- = panic "CoreLint.lintCoreAlts"
-{- LATER:
- WDP: can't tell what type DNT wants here
+lintCoreAlts whole_alts@(AlgAlts alts deflt) ty tycon
= -- Check tycon is not a primitive tycon
addErrIfL (isPrimTyCon tycon) (mkCasePrimMsg tycon)
`seqL`
- -- Check we have a non-abstract data tycon
- addErrIfL (not (isVisibleDataTyCon tycon)) (mkCaseAbstractMsg tycon)
+ -- Check we are scrutinising a proper datatype
+ -- (ToDo: robustify)
+ addErrIfL (not (tyConFamilySize tycon >= 1)) (mkCaseAbstractMsg tycon)
`seqL`
lintDeflt deflt ty
`thenL` \maybe_deflt_ty ->
mapL (lintAlgAlt ty tycon) alts
`thenL` \maybe_alt_tys ->
- returnL (maybe_deflt_ty : maybe_alt_tys)
+ -- Check the result types
+ case catMaybes (maybe_deflt_ty : maybe_alt_tys) of
+ [] -> returnL Nothing
-lintCoreAlts (PrimAlts alts deflt) ty tycon
+ (first_ty:tys) -> mapL check tys `seqL`
+ returnL (Just first_ty)
+ where
+ check ty = checkTys first_ty ty (mkCaseAltMsg whole_alts)
+
+lintCoreAlts whole_alts@(PrimAlts alts deflt) ty tycon
= -- Check tycon is a primitive tycon
addErrIfL (not (isPrimTyCon tycon)) (mkCaseNotPrimMsg tycon)
`seqL`
`thenL` \maybe_alt_tys ->
lintDeflt deflt ty
`thenL` \maybe_deflt_ty ->
- returnL (maybe_deflt_ty : maybe_alt_tys)
-- Check the result types
--}
-{-
- `thenL` \ maybe_result_tys ->
- case catMaybes (maybe_result_tys) of
+ case catMaybes (maybe_deflt_ty : maybe_alt_tys) of
[] -> returnL Nothing
(first_ty:tys) -> mapL check tys `seqL`
returnL (Just first_ty)
where
- check ty = checkTys first_ty ty (mkCaseAltMsg alts)
--}
+ check ty = checkTys first_ty ty (mkCaseAltMsg whole_alts)
-lintAlgAlt scrut_ty (con,args,rhs)
+lintAlgAlt scrut_ty tycon{-ToDo: use it!-} (con,args,rhs)
= (case maybeAppDataTyCon scrut_ty of
Nothing ->
addErrL (mkAlgAltMsg1 scrut_ty)
mkCaseAbstractMsg :: TyCon -> ErrMsg
mkCaseAbstractMsg tycon sty
- = ppAbove (ppStr "An algebraic case on an abstract type:")
+ = ppAbove (ppStr "An algebraic case on some weird type:")
(ppr sty tycon)
mkDefltMsg :: CoreCaseDefault -> ErrMsg
mkApp, mkCon, mkPrim,
mkValLam, mkTyLam, mkUseLam,
mkLam,
- collectBinders,
+ collectBinders, isValBinder, notValBinder,
collectArgs, isValArg, notValArg, numValArgs,
import Ubiq{-uitous-}
import CostCentre ( showCostCentre, CostCentre )
-import Id ( idType )
+import Id ( idType, GenId{-instance Eq-} )
+import Type ( isUnboxedType )
import Usage ( UVar(..) )
import Util ( panic, assertPanic )
-
-isUnboxedDataType = panic "CoreSyn.isUnboxedDataType"
---eqId :: Id -> Id -> Bool
-eqId = panic "CoreSyn.eqId"
\end{code}
%************************************************************************
(unboxed bindings in a letrec are still prohibited)
\begin{code}
-mkCoLetAny :: GenCoreBinding val_bdr val_occ tyvar uvar
- -> GenCoreExpr val_bdr val_occ tyvar uvar
- -> GenCoreExpr val_bdr val_occ tyvar uvar
-mkCoLetsAny :: [GenCoreBinding val_bdr val_occ tyvar uvar] ->
- GenCoreExpr val_bdr val_occ tyvar uvar ->
- GenCoreExpr val_bdr val_occ tyvar uvar
+mkCoLetAny :: GenCoreBinding Id Id tyvar uvar
+ -> GenCoreExpr Id Id tyvar uvar
+ -> GenCoreExpr Id Id tyvar uvar
+mkCoLetsAny :: [GenCoreBinding Id Id tyvar uvar] ->
+ GenCoreExpr Id Id tyvar uvar ->
+ GenCoreExpr Id Id tyvar uvar
+
mkCoLetrecAny :: [(val_bdr, GenCoreExpr val_bdr val_occ tyvar uvar)]
-> GenCoreExpr val_bdr val_occ tyvar uvar
-> GenCoreExpr val_bdr val_occ tyvar uvar
mkCoLetAny bind@(Rec binds) body = mkCoLetrecAny binds body
mkCoLetAny bind@(NonRec binder rhs) body
= case body of
- Var binder2 | binder `eqId` binder2
+ Var binder2 | binder == binder2
-> rhs -- hey, I have the rhs
other
-> Let bind body
mkCoLetNoUnboxed bind@(Rec binds) body
= mkCoLetrecNoUnboxed binds body
mkCoLetNoUnboxed bind@(NonRec binder rhs) body
- = --ASSERT (not (isUnboxedDataType (idType binder)))
+ = --ASSERT (not (isUnboxedType (idType binder)))
case body of
- Var binder2 | binder `eqId` binder2
+ Var binder2 | binder == binder2
-> rhs -- hey, I have the rhs
other
-> Let bind body
Let (Rec binds) body
where
is_boxed_bind (binder, rhs)
- = (not . isUnboxedDataType . idType) binder
+ = (not . isUnboxedType . idType) binder
\end{code}
\begin{code}
= mkCoLetrecNoUnboxed binds body
mkCoLetUnboxedToCase bind@(NonRec binder rhs) body
= case body of
- Var binder2 | binder `eqId` binder2
+ Var binder2 | binder == binder2
-> rhs -- hey, I have the rhs
other
- -> if (not (isUnboxedDataType (idType binder))) then
+ -> if (not (isUnboxedType (idType binder))) then
Let bind body -- boxed...
else
Case rhs -- unboxed...
= ValBinder val_bdr
| TyBinder tyvar
| UsageBinder uvar
+
+isValBinder (ValBinder _) = True
+isValBinder _ = False
+
+notValBinder = not . isValBinder
\end{code}
Clump Lams together if possible.
GenCoreExpr val_bdr val_occ tyvar uvar ->
([uvar], [tyvar], [val_bdr], GenCoreExpr val_bdr val_occ tyvar uvar)
-collectBinders (Lam (UsageBinder u) body)
- = let
- (uvars, tyvars, args, final_body) = collectBinders body
- in
- (u:uvars, tyvars, args, final_body)
-
-collectBinders other
- = let
- (tyvars, args, body) = dig_for_tyvars other
- in
- ([], tyvars, args, body)
+collectBinders expr
+ = usages expr []
where
- dig_for_tyvars (Lam (TyBinder tv) body)
- = let
- (tyvars, args, body2) = dig_for_tyvars body
- in
- (tv : tyvars, args, body2)
-
- dig_for_tyvars body
- = ASSERT(not (usage_lambda body))
- let
- (args, body2) = dig_for_valvars body
- in
- ([], args, body2)
-
- ---------------------------------------
- dig_for_valvars (Lam (ValBinder v) body)
- = let
- (args, body2) = dig_for_valvars body
- in
- (v : args, body2)
-
- dig_for_valvars body
- = ASSERT(not (usage_lambda body))
- ASSERT(not (tyvar_lambda body))
- ([], body)
+ usages (Lam (UsageBinder u) body) uacc = usages body (u:uacc)
+ usages other uacc
+ = case (tyvars other []) of { (tacc, vacc, expr) ->
+ (reverse uacc, tacc, vacc, expr) }
+
+ tyvars (Lam (TyBinder t) body) tacc = tyvars body (t:tacc)
+ tyvars other tacc
+ = ASSERT(not (usage_lambda other))
+ case (valvars other []) of { (vacc, expr) ->
+ (reverse tacc, vacc, expr) }
+
+ valvars (Lam (ValBinder v) body) vacc = valvars body (v:vacc)
+ valvars other vacc
+ = ASSERT(not (usage_lambda other))
+ ASSERT(not (tyvar_lambda other))
+ (reverse vacc, other)
---------------------------------------
usage_lambda (Lam (UsageBinder _) _) = True
\begin{code}
collectArgs :: GenCoreExpr val_bdr val_occ tyvar uvar
-> (GenCoreExpr val_bdr val_occ tyvar uvar,
- [GenCoreArg val_occ tyvar uvar])
+ [GenUsage uvar],
+ [GenType tyvar uvar],
+ [GenCoreArg val_occ tyvar uvar]{-ValArgs-})
collectArgs expr
- = collect expr []
+ = usages expr []
where
- collect (App fun arg) args = collect fun (arg : args)
- collect fun args = (fun, args)
+ usages (App fun (UsageArg u)) uacc = usages fun (u:uacc)
+ usages fun uacc
+ = case (tyvars fun []) of { (expr, tacc, vacc) ->
+ (expr, uacc, tacc, vacc) }
+
+ tyvars (App fun (TyArg t)) tacc = tyvars fun (t:tacc)
+ tyvars fun tacc
+ = ASSERT(not (usage_app fun))
+ case (valvars fun []) of { (expr, vacc) ->
+ (expr, tacc, vacc) }
+
+ valvars (App fun v) vacc | isValArg v = valvars fun (v:vacc)
+ valvars fun vacc
+ = ASSERT(not (usage_app fun))
+ ASSERT(not (ty_app fun))
+ (fun, vacc)
+
+ ---------------------------------------
+ usage_app (App _ (UsageArg _)) = True
+ usage_app _ = False
+
+ ty_app (App _ (TyArg _)) = True
+ ty_app _ = False
\end{code}
%************************************************************************
) where
import Ubiq
-import IdLoop -- for paranoia checking
+import IdLoop -- for paranoia checking;
+ -- and also to get mkMagicUnfoldingFun
import PrelLoop -- for paranoia checking
import Bag ( emptyBag, unitBag, unionBags, Bag )
uNFOLDING_NOREP_LIT_COST
)
import CoreSyn
-import CoreUtils ( coreExprType )
+import CoreUtils ( coreExprType, manifestlyWHNF )
import CostCentre ( ccMentionsId )
import Id ( IdSet(..), GenId{-instances-} )
import IdInfo ( bottomIsGuaranteed )
import Literal ( isNoRepLit, isLitLitLit )
-import MagicUFs ( mkMagicUnfoldingFun, MagicUnfoldingFun )
import Pretty
-import PrimOp ( PrimOp(..) )
+import PrimOp ( primOpCanTriggerGC, PrimOp(..) )
+import TyCon ( tyConFamilySize )
import Type ( getAppDataTyCon )
-import UniqSet ( emptyUniqSet, singletonUniqSet, mkUniqSet,
- unionUniqSets
+import UniqSet ( emptyUniqSet, unitUniqSet, mkUniqSet,
+ addOneToUniqSet, unionUniqSets
)
import Usage ( UVar(..) )
import Util ( isIn, panic )
-manifestlyWHNF = panic "manifestlyWHNF (CoreUnfold)"
-primOpCanTriggerGC = panic "primOpCanTriggerGC (CoreUnfold)"
-getTyConFamilySize = panic "getTyConFamilySize (CoreUnfold)"
whatsMentionedInId = panic "whatsMentionedInId (CoreUnfold)"
getMentionedTyConsAndClassesFromType = panic "getMentionedTyConsAndClassesFromType (CoreUnfold)"
\end{code}
------------
size_up_alts scrut_ty (AlgAlts alts deflt)
= foldr (addSize . size_alg_alt) (size_up_deflt deflt) alts
- `addSizeN`
- (case (getTyConFamilySize tycon) of { Just n -> n })
+ `addSizeN` (tyConFamilySize tycon)
-- NB: we charge N for an alg. "case", where N is
-- the number of constructors in the thing being eval'd.
-- (You'll eventually get a "discount" of N if you
add_some :: IdSet -> [Id] -> IdSet
no_in_scopes = emptyUniqSet
-in_scopes `add1` x = in_scopes `unionUniqSets` singletonUniqSet x
+in_scopes `add1` x = addOneToUniqSet in_scopes x
in_scopes `add_some` xs = in_scopes `unionUniqSets` mkUniqSet xs
\end{code}
\begin{code}
ppr_uf_Binder :: Id -> Pretty
ppr_uf_Binder v
- = ppBesides [ppLparen, pprIdInUnfolding (singletonUniqSet v) v, ppPStr SLIT(" :: "),
+ = ppBesides [ppLparen, pprIdInUnfolding (unitUniqSet v) v, ppPStr SLIT(" :: "),
ppr ppr_Unfolding (idType v), ppRparen]
ppr_uf_Atom in_scopes (LitArg l) = ppr ppr_Unfolding l
module CoreUtils (
coreExprType, coreAltsType,
- substCoreExpr
+ substCoreExpr, substCoreBindings
, mkCoreIfThenElse
, mkErrorApp, escErrorMsg
, argToExpr
, unTagBinders, unTagBindersAlts
, manifestlyWHNF, manifestlyBottom
+ , maybeErrorApp
+ , nonErrorRHSs
+ , squashableDictishCcExpr
{- exprSmallEnoughToDup,
coreExprArity,
isWrapperFor,
- maybeErrorApp,
- nonErrorRHSs,
- squashableDictishCcExpr,
-} ) where
)
import IdInfo ( arityMaybe )
import Literal ( literalType, isNoRepLit, Literal(..) )
-import Maybes ( catMaybes )
+import Maybes ( catMaybes, maybeToBool )
import PprCore ( GenCoreExpr{-instances-}, GenCoreArg{-instances-} )
import PprStyle ( PprStyle(..) )
-import PprType ( GenType{-instances-}, GenTyVar{-instance-} )
+import PprType ( GenType{-instances-} )
import Pretty ( ppAboves )
import PrelInfo ( trueDataCon, falseDataCon,
augmentId, buildId,
)
import PrimOp ( primOpType, PrimOp(..) )
import SrcLoc ( mkUnknownSrcLoc )
-import TyVar ( isNullTyVarEnv, TyVarEnv(..), GenTyVar{-instances-} )
-import Type ( mkFunTys, mkForAllTy, mkForAllUsageTy,
- getFunTy_maybe, applyTy, splitSigmaTy
+import TyVar ( isNullTyVarEnv, TyVarEnv(..) )
+import Type ( mkFunTys, mkForAllTy, mkForAllUsageTy, mkTyVarTy,
+ getFunTy_maybe, applyTy, isPrimType,
+ splitSigmaTy, splitFunTy, eqTy, applyTypeEnvToTy
)
-import Unique ( Unique{-instances-} )
import UniqSupply ( initUs, returnUs, thenUs,
mapUs, mapAndUnzipUs,
UniqSM(..), UniqSupply
)
+import Usage ( UVar(..) )
import Util ( zipEqual, panic, pprPanic, assertPanic )
type TypeEnv = TyVarEnv Type
applyUsage = panic "CoreUtils.applyUsage:ToDo"
dup_binder = panic "CoreUtils.dup_binder"
-applyTypeEnvToTy = panic "CoreUtils.applyTypeEnvToTy"
\end{code}
%************************************************************************
exprSmallEnoughToDup (Lit lit) = not (isNoRepLit lit)
exprSmallEnoughToDup expr -- for now, just: <var> applied to <args>
- = case (collectArgs expr) of { (fun, args) ->
+ = case (collectArgs expr) of { (fun, _, _, vargs) ->
case fun of
Var v -> v /= buildId
&& v /= augmentId
- && length args <= 6 -- or 10 or 1 or 4 or anything smallish.
+ && length vargs <= 6 -- or 10 or 1 or 4 or anything smallish.
_ -> False
}
-}
manifestlyWHNF (Let _ e) = False
manifestlyWHNF (Case _ _) = False
-manifestlyWHNF (Lam (ValBinder _) _) = True
-manifestlyWHNF (Lam other_binder e) = manifestlyWHNF e
+manifestlyWHNF (Lam x e) = if isValBinder x then True else manifestlyWHNF e
manifestlyWHNF other_expr -- look for manifest partial application
- = case (collectArgs other_expr) of { (fun, args) ->
+ = case (collectArgs other_expr) of { (fun, _, _, vargs) ->
case fun of
Var f -> let
- num_val_args = numValArgs args
+ num_val_args = length vargs
in
num_val_args == 0 -- Just a type application of
-- a variable (f t1 t2 t3);
manifestlyBottom (Let _ e) = manifestlyBottom e
-- We do not assume \x.bottom == bottom:
-manifestlyBottom (Lam (ValBinder _) _) = False
-manifestlyBottom (Lam other_binder e) = manifestlyBottom e
+manifestlyBottom (Lam x e) = if isValBinder x then False else manifestlyBottom e
manifestlyBottom (Case e a)
= manifestlyBottom e
mbdef (BindDefault _ e') = manifestlyBottom e'
manifestlyBottom other_expr -- look for manifest partial application
- = case (collectArgs other_expr) of { (fun, args) ->
+ = case (collectArgs other_expr) of { (fun, _, _, _) ->
case fun of
Var f | isBottomingId f -> True
-- Application of a function which always gives
--------------
unravel_casing case_ables (Case scrut alts)
- = case (collectArgs scrut) of { (fun, args) ->
+ = case (collectArgs scrut) of { (fun, _, _, vargs) ->
case fun of
Var scrut_var -> let
answer =
- scrut_var /= var && all (doesn't_mention var) args
+ scrut_var /= var && all (doesn't_mention var) vargs
&& scrut_var `is_elem` case_ables
&& unravel_alts case_ables alts
in
}
unravel_casing case_ables other_expr
- = case (collectArgs other_expr) of { (fun, args) ->
+ = case (collectArgs other_expr) of { (fun, _, _, vargs) ->
case fun of
Var wrkr -> let
answer =
-- DOESN'T WORK: wrkr == var's_worker
wrkr /= var
&& isWorkerId wrkr
- && all (doesn't_mention var) args
- && all (only_from case_ables) args
+ && all (doesn't_mention var) vargs
+ && all (only_from case_ables) vargs
in
answer
Notice that the \tr{<alts>} don't get duplicated.
\begin{code}
-{- LATER:
-nonErrorRHSs :: GenCoreCaseAlts binder Id -> [GenCoreExpr binder Id]
+nonErrorRHSs :: GenCoreCaseAlts a Id TyVar UVar -> [GenCoreExpr a Id TyVar UVar]
-nonErrorRHSs alts = filter not_error_app (find_rhss alts)
+nonErrorRHSs alts
+ = filter not_error_app (find_rhss alts)
where
- find_rhss (AlgAlts alts deflt) = [rhs | (_,_,rhs) <- alts] ++ deflt_rhs deflt
- find_rhss (PrimAlts alts deflt) = [rhs | (_,rhs) <- alts] ++ deflt_rhs deflt
+ find_rhss (AlgAlts as deflt) = [rhs | (_,_,rhs) <- as] ++ deflt_rhs deflt
+ find_rhss (PrimAlts as deflt) = [rhs | (_,rhs) <- as] ++ deflt_rhs deflt
deflt_rhs NoDefault = []
deflt_rhs (BindDefault _ rhs) = [rhs]
- not_error_app rhs = case maybeErrorApp rhs Nothing of
- Just _ -> False
- Nothing -> True
+ not_error_app rhs
+ = case (maybeErrorApp rhs Nothing) of
+ Just _ -> False
+ Nothing -> True
\end{code}
-maybeErrorApp checkes whether an expression is of the form
+maybeErrorApp checks whether an expression is of the form
error ty args
===>
error ty' "Foo"
-where ty' is the type of any of the alternatives.
-You might think this never occurs, but see the comments on
-the definition of @singleAlt@.
+where ty' is the type of any of the alternatives. You might think
+this never occurs, but see the comments on the definition of
+@singleAlt@.
-Note: we *avoid* the case where ty' might end up as a
-primitive type: this is very uncool (totally wrong).
+Note: we *avoid* the case where ty' might end up as a primitive type:
+this is very uncool (totally wrong).
-NOTICE: in the example above we threw away e1 and e2, but
-not the string "Foo". How did we know to do that?
+NOTICE: in the example above we threw away e1 and e2, but not the
+string "Foo". How did we know to do that?
-Answer: for now anyway, we only handle the case of a function
-whose type is of form
+Answer: for now anyway, we only handle the case of a function whose
+type is of form
bottomingFn :: forall a. t1 -> ... -> tn -> a
^---------------------^ NB!
-Furthermore, we only count a bottomingApp if the function is
-applied to more than n args. If so, we transform:
+Furthermore, we only count a bottomingApp if the function is applied
+to more than n args. If so, we transform:
bottomingFn ty e1 ... en en+1 ... em
to
That is, we discard en+1 .. em
\begin{code}
-maybeErrorApp :: GenCoreExpr bndr Id -- Expr to look at
- -> Maybe Type -- Just ty => a result type *already cloned*;
- -- Nothing => don't know result ty; we
- -- *pretend* that the result ty won't be
- -- primitive -- somebody later must
- -- ensure this.
- -> Maybe (GenCoreExpr bndr Id)
+maybeErrorApp
+ :: GenCoreExpr a Id TyVar UVar -- Expr to look at
+ -> Maybe Type -- Just ty => a result type *already cloned*;
+ -- Nothing => don't know result ty; we
+ -- *pretend* that the result ty won't be
+ -- primitive -- somebody later must
+ -- ensure this.
+ -> Maybe (GenCoreExpr a Id TyVar UVar)
maybeErrorApp expr result_ty_maybe
- = case collectArgs expr of
- (Var fun, (TypeArg ty : other_args))
+ = case (collectArgs expr) of
+ (Var fun, [{-no usage???-}], [ty], other_args)
| isBottomingId fun
&& maybeToBool result_ty_maybe -- we *know* the result type
-- (otherwise: live a fairy-tale existence...)
&& not (isPrimType result_ty) ->
- case splitSigmaTy (idType fun) of
- ([tyvar_tmpl], [], tau_ty) ->
- case (splitTyArgs tau_ty) of { (arg_tys, res_ty) ->
+
+ case (splitSigmaTy (idType fun)) of
+ ([tyvar], [], tau_ty) ->
+ case (splitFunTy tau_ty) of { (arg_tys, res_ty) ->
let
n_args_to_keep = length arg_tys
args_to_keep = take n_args_to_keep other_args
in
- if res_ty == mkTyVarTemplateTy tyvar_tmpl &&
- n_args_to_keep <= length other_args
+ if (res_ty `eqTy` mkTyVarTy tyvar)
+ && n_args_to_keep <= length other_args
then
-- Phew! We're in business
- Just (mkGenApp (Var fun)
- (TypeArg result_ty : args_to_keep))
+ Just (mkGenApp (Var fun) (TyArg result_ty : args_to_keep))
else
Nothing
}
- other -> -- Function type wrong shape
- Nothing
+ other -> Nothing -- Function type wrong shape
other -> Nothing
where
Just result_ty = result_ty_maybe
\end{code}
\begin{code}
-squashableDictishCcExpr :: CostCentre -> GenCoreExpr a b -> Bool
+squashableDictishCcExpr :: CostCentre -> GenCoreExpr a b c d -> Bool
squashableDictishCcExpr cc expr
= if not (isDictCC cc) then
squashable expr -- note: quite like the "atomic_rhs" stuff in simplifier
where
squashable (Var _) = True
- squashable (CoTyApp f _) = squashable f
- squashable (Con _ _ _) = True -- I think so... WDP 94/09
- squashable (Prim _ _ _) = True -- ditto
- squashable other = False
--}
+ squashable (Con _ _) = True -- I think so... WDP 94/09
+ squashable (Prim _ _) = True -- ditto
+ squashable (App f a)
+ | notValArg a = squashable f
+ squashable other = False
\end{code}
%************************************************************************
%************************************************************************
\begin{code}
+substCoreBindings :: ValEnv
+ -> TypeEnv -- TyVar=>Type
+ -> [CoreBinding]
+ -> UniqSM [CoreBinding]
+
substCoreExpr :: ValEnv
-> TypeEnv -- TyVar=>Type
-> CoreExpr
-> UniqSM CoreExpr
-substCoreExpr venv tenv expr
+substCoreBindings venv tenv binds
-- if the envs are empty, then avoid doing anything
= if (isNullIdEnv venv && isNullTyVarEnv tenv) then
+ returnUs binds
+ else
+ do_CoreBindings venv tenv binds
+
+substCoreExpr venv tenv expr
+ = if (isNullIdEnv venv && isNullTyVarEnv tenv) then
returnUs expr
else
do_CoreExpr venv tenv expr
import CoreSyn
import Id ( idType, getIdArity, isBottomingId,
- emptyIdSet, singletonIdSet, mkIdSet,
+ emptyIdSet, unitIdSet, mkIdSet,
elementOfIdSet, minusIdSet, unionManyIdSets,
IdSet(..)
)
import IdInfo ( arityMaybe )
import PrimOp ( PrimOp(..) )
import Type ( tyVarsOfType )
-import TyVar ( emptyTyVarSet, singletonTyVarSet, minusTyVarSet,
+import TyVar ( emptyTyVarSet, unitTyVarSet, minusTyVarSet,
intersectTyVarSets,
TyVarSet(..)
)
noFreeIds = emptyIdSet
noFreeTyVars = emptyTyVarSet
noFreeAnything = (noFreeIds, noFreeTyVars)
-aFreeId i = singletonIdSet i
-aFreeTyVar t = singletonTyVarSet t
+aFreeId i = unitIdSet i
+aFreeTyVar t = unitTyVarSet t
is_among = elementOfIdSet
munge_id_ty i = tyVarsOfType (idType i)
combine = unionUniqSets -- used both for {Id,TyVar}Sets
= panic "fvExpr:Lam UsageBinder"
fvExpr id_cands tyvar_cands (Lam b@(ValBinder binder) body)
- = (FVInfo (freeVarsOf body2 `minusIdSet` singletonIdSet binder)
+ = (FVInfo (freeVarsOf body2 `minusIdSet` unitIdSet binder)
(freeTyVarsOf body2 `combine` munge_id_ty binder)
leakiness,
AnnLam b body2)
where
-- We need to collect free tyvars from the binders
- body2 = fvExpr (singletonIdSet binder `combine` id_cands) tyvar_cands body
+ body2 = fvExpr (unitIdSet binder `combine` id_cands) tyvar_cands body
leakiness = case leakinessOf body2 of
MightLeak -> LeakFree 1
TyBinder t -> (TyBinder t, emptyIdSet)
UsageBinder u -> (UsageBinder u, emptyIdSet)
ValBinder b -> (ValBinder (b, lam_fvs),
- singletonIdSet b)
+ unitIdSet b)
new_in_scope = in_scope `combine` binder_set
(new_body, body_fvs) = addExprFVs fv_cand new_in_scope body
pprCoreExpr,
pprCoreBinding,
pprBigCoreBinder,
- pprTypedCoreBinder,
- pprPlainCoreBinding
+ pprTypedCoreBinder
-- these are here to make the instances go in 0.26:
#if __GLASGOW_HASKELL__ <= 26
import IdInfo ( ppIdInfo, StrictnessInfo(..) )
import Literal ( Literal{-instances-} )
import Outputable -- quite a few things
-import PprType ( pprType_Internal,
- GenType{-instances-}, GenTyVar{-instance-}
- )
+import PprEnv
+import PprType ( GenType{-instances-}, GenTyVar{-instance-} )
import PprStyle ( PprStyle(..) )
import Pretty
import PrimOp ( PrimOp{-instances-} )
usually be called through some intermediary.
The binder/occ printers take the default ``homogenized'' (see
-@PrintEnv@...) @Pretty@ and the binder/occ. They can either use the
+@PprEnv@...) @Pretty@ and the binder/occ. They can either use the
homogenized one, or they can ignore it completely. In other words,
the things passed in act as ``hooks'', getting the last word on how to
print something.
@pprParendCoreExpr@ puts parens around non-atomic Core expressions.
\begin{code}
-pprPlainCoreBinding :: PprStyle -> CoreBinding -> Pretty
+pprCoreBinding :: PprStyle -> CoreBinding -> Pretty
-pprCoreBinding
+pprGenCoreBinding
:: (Eq tyvar, Outputable tyvar,
Eq uvar, Outputable uvar,
Outputable bndr,
-> GenCoreBinding bndr occ tyvar uvar
-> Pretty
-pprCoreBinding sty pbdr1 pbdr2 pocc bind
- = ppr_bind (initial_pe sty (Left (pbdr1, pbdr2, pocc))) bind
-
-pprPlainCoreBinding sty (NonRec binder expr)
+pprGenCoreBinding sty pbdr1 pbdr2 pocc bind
+ = ppr_bind (init_ppr_env sty pbdr1 pbdr2 pocc) bind
+
+init_ppr_env sty pbdr1 pbdr2 pocc
+ = initPprEnv sty
+ (Just (ppr sty)) -- literals
+ (Just (ppr sty)) -- data cons
+ (Just (ppr sty)) -- primops
+ (Just (\ cc -> ppStr (showCostCentre sty True cc)))
+ (Just (ppr sty)) -- tyvars
+ (Just (ppr sty)) -- usage vars
+ (Just pbdr1) (Just pbdr2) (Just pocc) -- value vars
+ (Just (ppr sty)) -- types
+ (Just (ppr sty)) -- usages
+
+--------------
+pprCoreBinding sty (NonRec binder expr)
= ppHang (ppCat [pprBigCoreBinder sty binder, ppEquals])
4 (pprCoreExpr sty (pprBigCoreBinder sty) (pprBabyCoreBinder sty) (ppr sty) expr)
-pprPlainCoreBinding sty (Rec binds)
+pprCoreBinding sty (Rec binds)
= ppAboves [ifPprDebug sty (ppStr "{- plain Rec -}"),
ppAboves (map ppr_bind binds),
ifPprDebug sty (ppStr "{- end plain Rec -}")]
\end{code}
\begin{code}
-pprCoreExpr, pprParendCoreExpr
+pprCoreExpr
+ :: PprStyle
+ -> (Id -> Pretty) -- to print "major" val_bdrs
+ -> (Id -> Pretty) -- to print "minor" val_bdrs
+ -> (Id -> Pretty) -- to print bindees
+ -> CoreExpr
+ -> Pretty
+pprCoreExpr = pprGenCoreExpr
+
+pprGenCoreExpr, pprParendCoreExpr
:: (Eq tyvar, Outputable tyvar, Eq uvar, Outputable uvar,
Outputable bndr,
Outputable occ)
-> GenCoreExpr bndr occ tyvar uvar
-> Pretty
-pprCoreExpr sty pbdr1 pbdr2 pocc expr
- = ppr_expr (initial_pe sty (Left (pbdr1, pbdr2, pocc))) expr
+pprGenCoreExpr sty pbdr1 pbdr2 pocc expr
+ = ppr_expr (init_ppr_env sty pbdr1 pbdr2 pocc) expr
pprParendCoreExpr sty pbdr1 pbdr2 pocc expr
= let
Lit _ -> id
_ -> ppParens -- wraps in parens
in
- parenify (pprCoreExpr sty pbdr1 pbdr2 pocc expr)
+ parenify (pprGenCoreExpr sty pbdr1 pbdr2 pocc expr)
ppr_core_arg sty pocc arg
- = ppr_arg (initial_pe sty (Left (pocc, pocc, pocc))) arg
+ = ppr_arg (init_ppr_env sty pocc pocc pocc) arg
ppr_core_alts sty pbdr1 pbdr2 pocc alts
- = ppr_alts (initial_pe sty (Left (pbdr1, pbdr2, pocc))) alts
+ = ppr_alts (init_ppr_env sty pbdr1 pbdr2 pocc) alts
ppr_core_default sty pbdr1 pbdr2 pocc deflt
- = ppr_default (initial_pe sty (Left (pbdr1, pbdr2, pocc))) deflt
+ = ppr_default (init_ppr_env sty pbdr1 pbdr2 pocc) deflt
\end{code}
%************************************************************************
Eq uvar, Outputable uvar)
=>
Outputable (GenCoreBinding bndr occ tyvar uvar) where
- ppr sty bind = pprCoreBinding sty (ppr sty) (ppr sty) (ppr sty) bind
+ ppr sty bind = pprGenCoreBinding sty (ppr sty) (ppr sty) (ppr sty) bind
instance
(Outputable bndr, Outputable occ, Eq tyvar, Outputable tyvar,
Eq uvar, Outputable uvar)
=>
Outputable (GenCoreExpr bndr occ tyvar uvar) where
- ppr sty expr = pprCoreExpr sty (ppr sty) (ppr sty) (ppr sty) expr
+ ppr sty expr = pprGenCoreExpr sty (ppr sty) (ppr sty) (ppr sty) expr
instance
(Outputable occ, Eq tyvar, Outputable tyvar, Eq uvar, Outputable uvar)
%************************************************************************
%* *
-\subsection{Core printing environment (purely local)}
-%* *
-%************************************************************************
-
-Similar to @VE@ in @PprType@. The ``values'' we print here
-are locally-defined nested-scope names; callers to @pprCoreBinding@,
-etc., can override these.
-
-For tyvars and uvars, we {\em do} normally use these homogenized
-names; for values, we {\em don't}. In printing interfaces, though,
-we use homogenized value names, so that interfaces don't wobble
-uncontrollably from changing Unique-based names.
-
-\begin{code}
-data PrintEnv tyvar uvar bndr occ
- = PE (Literal -> Pretty) -- Doing these this way saves
- (DataCon -> Pretty) -- carrying around a PprStyle
- (PrimOp -> Pretty)
- (CostCentre -> Pretty)
-
- [Pretty] -- Tyvar pretty names
- (tyvar -> Pretty) -- Tyvar lookup function
- [Pretty] -- Uvar pretty names
- (uvar -> Pretty) -- Uvar lookup function
-
- (GenType tyvar uvar -> Pretty)
- (GenUsage uvar -> Pretty)
-
- (ValPrinters bndr occ)
-
-data ValPrinters bndr occ
- = BOPE -- print binders/occs differently
- (bndr -> Pretty) -- to print "major" val_bdrs
- (bndr -> Pretty) -- to print "minor" val_bdrs
- (occ -> Pretty) -- to print bindees
-
- | VPE -- print all values the same way
- [Pretty] -- Value pretty names
- (bndr -> Pretty) -- Binder lookup function
- (occ -> Pretty) -- Occurrence lookup function
-\end{code}
-
-\begin{code}
-initial_pe :: (Eq tyvar, Outputable tyvar, Eq uvar, Outputable uvar,
- Outputable bndr, Outputable occ)
- => PprStyle
- -> Either
- (bndr -> Pretty, bndr -> Pretty, occ -> Pretty)
- ()
- -> PrintEnv tyvar uvar bndr occ
-
-initial_pe sty val_printing
- = PE (ppr sty) -- for a Literal
- (ppr sty) -- for a DataCon
- (ppr sty) -- for a PrimOp
- (\ cc -> ppStr (showCostCentre sty True cc)) -- CostCentre
-
- tv_pretties ppr_tv -- for a TyVar
- uv_pretties ppr_uv -- for a UsageVar
-
- (\ ty -> pprType_Internal sty tv_pretties ppr_tv uv_pretties ppr_uv ty)
- (ppr sty) -- for a Usage
-
- val_printing_stuff
- where
- ppr_tv = ppr sty -- to print a tyvar
- ppr_uv = ppr sty -- to print a uvar
-
- tv_pretties = map (\ c -> ppChar c ) ['a' .. 'h']
- ++
- map (\ n -> ppBeside (ppChar 'a') (ppInt n))
- ([0 .. ] :: [Int]) -- a0 ... aN
-
- uv_pretties = map (\ c -> ppChar c ) ['u' .. 'y']
- ++
- map (\ n -> ppBeside (ppChar 'u') (ppInt n))
- ([0 .. ] :: [Int]) -- u0 ... uN
-
- val_pretties = map (\ c -> ppChar c ) ['i' .. 'k']
- ++ map (\ n -> ppBeside (ppChar 'v') (ppInt n))
- ([0 .. ] :: [Int]) -- v0 ... vN
-
- ------------------------
- val_printing_stuff
- = case val_printing of
- Left (pbdr1, pbdr2, pocc) -> BOPE pbdr1 pbdr2 pocc
- Right () -> VPE val_pretties (ppr sty) (ppr sty)
-
-\end{code}
-
-\begin{code}
-plit (PE pp _ _ _ _ _ _ _ _ _ _) = pp
-pcon (PE _ pp _ _ _ _ _ _ _ _ _) = pp
-pprim (PE _ _ pp _ _ _ _ _ _ _ _) = pp
-pscc (PE _ _ _ pp _ _ _ _ _ _ _) = pp
-ptyvar (PE _ _ _ _ _ pp _ _ _ _ _) = pp
-puvar (PE _ _ _ _ _ _ _ pp _ _ _) = pp
-
-pty (PE _ _ _ _ _ _ _ _ pp _ _) = pp
-puse (PE _ _ _ _ _ _ _ _ _ pp _) = pp
-
-pmaj_bdr (PE _ _ _ _ _ _ _ _ _ _ (BOPE pp _ _)) = pp
-pmaj_bdr (PE _ _ _ _ _ _ _ _ _ _ (VPE _ pp _)) = pp
-
-pmin_bdr (PE _ _ _ _ _ _ _ _ _ _ (BOPE _ pp _)) = pp
-pmin_bdr (PE _ _ _ _ _ _ _ _ _ _ (VPE _ pp _)) = pp
-
-pocc (PE _ _ _ _ _ _ _ _ _ _ (BOPE _ _ pp)) = pp
-pocc (PE _ _ _ _ _ _ _ _ _ _ (VPE _ _ pp)) = pp
-\end{code}
-
-%************************************************************************
-%* *
\subsection{Workhorse routines (...????...)}
%* *
%************************************************************************
\begin{code}
ppr_bind pe (NonRec val_bdr expr)
- = ppHang (ppCat [pmaj_bdr pe val_bdr, ppEquals])
+ = ppHang (ppCat [pMajBndr pe val_bdr, ppEquals])
4 (ppr_expr pe expr)
ppr_bind pe (Rec binds)
ppStr "{- end Rec -}" ]
where
ppr_pair (val_bdr, expr)
- = ppHang (ppCat [pmaj_bdr pe val_bdr, ppEquals])
+ = ppHang (ppCat [pMajBndr pe val_bdr, ppEquals])
4 (ppr_expr pe expr)
\end{code}
\end{code}
\begin{code}
-ppr_expr pe (Var name) = pocc pe name
-ppr_expr pe (Lit lit) = plit pe lit
-ppr_expr pe (Con con []) = pcon pe con
+ppr_expr pe (Var name) = pOcc pe name
+ppr_expr pe (Lit lit) = pLit pe lit
+ppr_expr pe (Con con []) = pCon pe con
ppr_expr pe (Con con args)
- = ppHang (ppBesides [pcon pe con, ppChar '!'])
+ = ppHang (ppBesides [pCon pe con, ppChar '!'])
4 (ppSep (map (ppr_arg pe) args))
ppr_expr pe (Prim prim args)
- = ppHang (ppBesides [pprim pe prim, ppChar '!'])
+ = ppHang (ppBesides [pPrim pe prim, ppChar '!'])
4 (ppSep (map (ppr_arg pe) args))
ppr_expr pe expr@(Lam _ _)
= let
(uvars, tyvars, vars, body) = collectBinders expr
in
- ppHang (ppCat [pp_vars SLIT("_/u\\_") (puvar pe) uvars,
- pp_vars SLIT("_/\\_") (ptyvar pe) tyvars,
- pp_vars SLIT("\\") (pmin_bdr pe) vars])
+ ppHang (ppCat [pp_vars SLIT("_/u\\_") (pUVar pe) uvars,
+ pp_vars SLIT("_/\\_") (pTyVar pe) tyvars,
+ pp_vars SLIT("\\") (pMinBndr pe) vars])
4 (ppr_expr pe body)
where
pp_vars lam pp [] = ppNil
ppr_expr pe expr@(App _ _)
= let
- (fun, args) = collectArgs expr
+ (fun, uargs, targs, vargs) = collectArgs expr
in
ppHang (ppr_parend_expr pe fun)
- 4 (ppSep (map (ppr_arg pe) args))
+ 4 (ppSep [ ppInterleave ppNil (map (pUse pe) uargs)
+ , ppInterleave ppNil (map (pTy pe) targs)
+ , ppInterleave ppNil (map (ppr_arg pe) vargs)
+ ])
ppr_expr pe (Case expr alts)
= ppSep
ppr_expr pe (Let bind@(NonRec val_bdr rhs@(Let _ _)) body)
= ppAboves [
- ppCat [ppStr "let {", pmaj_bdr pe val_bdr, ppEquals],
+ ppCat [ppStr "let {", pMajBndr pe val_bdr, ppEquals],
ppNest 2 (ppr_expr pe rhs),
ppStr "} in",
ppr_expr pe body ]
ppr_expr pe (Let bind@(NonRec val_bdr rhs) expr@(Let _ _))
= ppAbove
(ppHang (ppStr "let {")
- 2 (ppCat [ppHang (ppCat [pmaj_bdr pe val_bdr, ppEquals])
+ 2 (ppCat [ppHang (ppCat [pMajBndr pe val_bdr, ppEquals])
4 (ppr_expr pe rhs),
ppStr "} in"]))
(ppr_expr pe expr)
ppHang (ppStr "} in ") 2 (ppr_expr pe expr)]
ppr_expr pe (SCC cc expr)
- = ppSep [ppCat [ppPStr SLIT("_scc_"), pscc pe cc],
+ = ppSep [ppCat [ppPStr SLIT("_scc_"), pSCC pe cc],
ppr_parend_expr pe expr ]
\end{code}
= ppAboves [ ppAboves (map ppr_alt alts), ppr_default pe deflt ]
where
ppr_alt (con, params, expr)
- = ppHang (ppCat [ppr_con con (pcon pe con),
- ppInterleave ppSP (map (pmin_bdr pe) params),
+ = ppHang (ppCat [ppr_con con (pCon pe con),
+ ppInterleave ppSP (map (pMinBndr pe) params),
ppStr "->"])
4 (ppr_expr pe expr)
where
= ppAboves [ ppAboves (map ppr_alt alts), ppr_default pe deflt ]
where
ppr_alt (lit, expr)
- = ppHang (ppCat [plit pe lit, ppStr "->"])
+ = ppHang (ppCat [pLit pe lit, ppStr "->"])
4 (ppr_expr pe expr)
\end{code}
ppr_default pe NoDefault = ppNil
ppr_default pe (BindDefault val_bdr expr)
- = ppHang (ppCat [pmin_bdr pe val_bdr, ppStr "->"])
+ = ppHang (ppCat [pMinBndr pe val_bdr, ppStr "->"])
4 (ppr_expr pe expr)
\end{code}
\begin{code}
-ppr_arg pe (LitArg lit) = plit pe lit
-ppr_arg pe (VarArg v) = pocc pe v
-ppr_arg pe (TyArg ty) = pty pe ty
-ppr_arg pe (UsageArg use) = puse pe use
+ppr_arg pe (LitArg lit) = pLit pe lit
+ppr_arg pe (VarArg v) = pOcc pe v
+ppr_arg pe (TyArg ty) = pTy pe ty
+ppr_arg pe (UsageArg use) = pUse pe use
\end{code}
Other printing bits-and-bobs used with the general @pprCoreBinding@
deSugar :: UniqSupply -- name supply
-> FAST_STRING -- module name
- -> (TypecheckedHsBinds, -- input: class, instance, and value
- TypecheckedHsBinds, -- bindings; see "tcModule" (which produces
+ -> (TypecheckedHsBinds, -- input: recsel, class, instance, and value
+ TypecheckedHsBinds, -- bindings; see "tcModule" (which produces
TypecheckedHsBinds, -- them)
+ TypecheckedHsBinds,
[(Id, TypecheckedHsExpr)])
-- ToDo: handling of const_inst thingies is certainly WRONG ***************************
-> ([CoreBinding], -- output
Bag DsMatchContext) -- Shadowing complaints
-deSugar us mod_name (clas_binds, inst_binds, val_binds, const_inst_pairs)
+deSugar us mod_name (recsel_binds, clas_binds, inst_binds, val_binds, const_inst_pairs)
= let
(us0, us0a) = splitUniqSupply us
(us1, us1a) = splitUniqSupply us0a
(us2, us2a) = splitUniqSupply us1a
- (us3, us4) = splitUniqSupply us2a
+ (us3, us3a) = splitUniqSupply us2a
+ (us4, us5) = splitUniqSupply us3a
((core_const_prs, consts_pairs), shadows1)
= initDs us0 nullIdEnv mod_name (dsInstBinds [] const_inst_pairs)
= initDs us3 consts_env mod_name (dsBinds val_binds)
core_val_pairs = pairsFromCoreBinds core_val_binds
+ (core_recsel_binds, shadows5)
+ = initDs us4 consts_env mod_name (dsBinds recsel_binds)
+ core_recsel_prs = pairsFromCoreBinds core_recsel_binds
+
final_binds
- = if (null core_clas_prs && null core_inst_prs && null core_const_prs) then
+ = if (null core_clas_prs && null core_inst_prs
+ && null core_recsel_prs {-???dont know???-} && null core_const_prs) then
-- we don't have to make the whole thing recursive
core_clas_binds ++ core_val_binds
else -- gotta make it recursive (sigh)
- [Rec (core_clas_prs ++ core_inst_prs ++ core_const_prs ++ core_val_pairs)]
+ [Rec (core_clas_prs ++ core_inst_prs
+ ++ core_const_prs ++ core_val_pairs ++ core_recsel_prs)]
- lift_final_binds = liftCoreBindings us4 final_binds
+ lift_final_binds = liftCoreBindings us5 final_binds
really_final_binds = if opt_DoCoreLinting
then lintCoreBindings PprDebug "Desugarer" False lift_final_binds
else lift_final_binds
- shadows = shadows1 `unionBags` shadows2 `unionBags` shadows3 `unionBags` shadows4
+ shadows = shadows1 `unionBags` shadows2 `unionBags`
+ shadows3 `unionBags` shadows4 `unionBags` shadows5
in
(really_final_binds, shadows)
\end{code}
import CostCentre ( mkAllDictsCC, preludeDictsCostCentre )
import Id ( idType, DictVar(..), GenId )
import ListSetOps ( minusList, intersectLists )
-import PprType ( GenType, GenTyVar )
+import PprType ( GenType )
import PprStyle ( PprStyle(..) )
import Pretty ( ppShow )
import Type ( mkTyVarTys, splitSigmaTy,
tyVarsOfType, tyVarsOfTypes
)
-import TyVar ( tyVarSetToList, GenTyVar )
-import Unique ( Unique )
+import TyVar ( tyVarSetToList, GenTyVar{-instance Eq-} )
import Util ( isIn, panic )
isDictTy = panic "DsBinds.isDictTy"
do_nothing = ([], []) -- out here to avoid dsInstBinds CAF (sigh)
prel_dicts_cc = preludeDictsCostCentre False{-not dupd-} -- ditto
-dsInstBinds tyvars []
- = returnDs do_nothing
-
-dsInstBinds _ _ = panic "DsBinds.dsInstBinds:maybe we want something different?"
-
-{- LATER
+dsInstBinds tyvars [] = returnDs do_nothing
dsInstBinds tyvars ((inst, expr@(HsVar _)) : bs)
- = dsExpr expr `thenDs` ( \ rhs ->
+ = dsExpr expr `thenDs` \ rhs ->
let -- Need to apply dsExpr to the variable in case it
-- has a substitution in the current environment
subst_item = (inst, rhs)
in
extendEnvDs [subst_item] (
dsInstBinds tyvars bs
- ) `thenDs` (\ (binds, subst_env) ->
+ ) `thenDs` \ (binds, subst_env) ->
returnDs (binds, subst_item : subst_env)
- ))
dsInstBinds tyvars ((inst, expr@(HsLit _)) : bs)
- = dsExpr expr `thenDs` ( \ core_lit ->
+ = dsExpr expr `thenDs` \ core_lit ->
let
subst_item = (inst, core_lit)
in
extendEnvDs [subst_item] (
dsInstBinds tyvars bs
- ) `thenDs` (\ (binds, subst_env) ->
+ ) `thenDs` \ (binds, subst_env) ->
returnDs (binds, subst_item : subst_env)
- ))
dsInstBinds tyvars ((inst, expr) : bs)
| null abs_tyvars
subst_item : subst_env)
where
inst_ty = idType inst
- abs_tyvars = tyVarsOfType inst_ty `intersectLists` tyvars
+ abs_tyvars = tyVarSetToList{-???sigh-} (tyVarsOfType inst_ty) `intersectLists` tyvars
abs_tys = mkTyVarTys abs_tyvars
(_, poly_inst_ty) = quantifyTy abs_tyvars inst_ty
-- Wrap a desugared expression in `_scc_ "DICT" <expr>' if
-- appropriate. Uses "inst"'s type.
+ -- if profiling, wrap the dict in "_scc_ DICT <dict>":
ds_dict_cc expr
- = -- if profiling, wrap the dict in "_scc_ DICT <dict>":
- let
- doing_profiling = opt_SccProfilingOn
- compiling_prelude = opt_CompilingPrelude
- in
- if not doing_profiling
- || not (isDictTy inst_ty) then -- that's easy: do nothing
- returnDs expr
- else if compiling_prelude then
- returnDs (SCC prel_dicts_cc expr)
- else
- getModuleAndGroupDs `thenDs` \ (mod_name, grp_name) ->
+ | not opt_SccProfilingOn ||
+ not (isDictTy inst_ty)
+ = returnDs expr -- that's easy: do nothing
+
+ | opt_CompilingPrelude
+ = returnDs (SCC prel_dicts_cc expr)
+
+ | otherwise
+ = getModuleAndGroupDs `thenDs` \ (mod_name, grp_name) ->
-- ToDo: do -dicts-all flag (mark dict things
-- with individual CCs)
- let
+ let
dict_cc = mkAllDictsCC mod_name grp_name False{-not dupd-}
- in
- returnDs (SCC dict_cc expr)
--}
+ in
+ returnDs (SCC dict_cc expr)
\end{code}
%************************************************************************
import Id ( getInstantiatedDataConSig, mkTupleCon )
import Maybes ( maybeToBool )
import PprStyle ( PprStyle(..) )
-import PprType ( GenType{-instances-}, GenTyVar{-instance-} )
+import PprType ( GenType{-instances-} )
import PrelInfo ( byteArrayPrimTy, getStatePairingConInfo,
packStringForCId, realWorldStatePrimTy,
realWorldStateTy, realWorldTy, stateDataCon,
import Pretty
import PrimOp ( PrimOp(..) )
import Type ( isPrimType, maybeAppDataTyCon, eqTy )
-import TyVar ( GenTyVar{-instance-} )
-import Unique ( Unique{-instances-} )
-import Util ( pprPanic, panic )
+import Util ( pprPanic, pprError, panic )
maybeBoxedPrimType = panic "DsCCall.maybeBoxedPrimType"
\end{code}
(data_con_arg_ty1 : data_con_arg_ty2 : _) = data_con_arg_tys
can't_see_datacons_error thing ty
- = error (ppShow 100 (ppBesides [ppStr "ERROR: Can't see the data constructor(s) for _ccall_/_casm_ ", ppStr thing, ppStr "; type: ", ppr PprForUser ty]))
+ = pprError "ERROR: Can't see the data constructor(s) for _ccall_/_casm_ "
+ (ppBesides [ppStr thing, ppStr "; type: ", ppr PprForUser ty])
\end{code}
import Literal ( mkMachInt, Literal(..) )
import MagicUFs ( MagicUnfoldingFun )
import PprStyle ( PprStyle(..) )
-import PprType ( GenType, GenTyVar )
+import PprType ( GenType )
import PrelInfo ( mkTupleTy, unitTy, nilDataCon, consDataCon,
charDataCon, charTy )
-import Pretty ( ppShow )
-import Type ( splitSigmaTy )
-import TyVar ( nullTyVarEnv, addOneToTyVarEnv, GenTyVar )
-import Unique ( Unique )
+import Pretty ( ppShow, ppBesides, ppPStr, ppStr )
+import Type ( splitSigmaTy, typePrimRep )
+import TyVar ( nullTyVarEnv, addOneToTyVarEnv )
import Usage ( UVar(..) )
-import Util ( panic )
+import Util ( pprError, panic )
-primRepFromType = panic "DsExpr.primRepFromType"
maybeBoxedPrimType = panic "DsExpr.maybeBoxedPrimType"
splitTyArgs = panic "DsExpr.splitTyArgs"
-- "str" ==> build (\ c n -> foldr charTy T c n "str")
{- LATER:
-dsExpr (HsLitOut (HsString str) _) =
- newTyVarsDs [alphaTyVar] `thenDs` \ [new_tyvar] ->
+dsExpr (HsLitOut (HsString str) _)
+ = newTyVarsDs [alphaTyVar] `thenDs` \ [new_tyvar] ->
let
new_ty = mkTyVarTy new_tyvar
in
where
(data_con, kind)
= case (maybeBoxedPrimType ty) of
- Nothing
- -> error ("ERROR: ``literal-literal'' not a single-constructor type: "++ _UNPK_ s ++"; type: "++(ppShow 80 (ppr PprDebug ty)))
Just (boxing_data_con, prim_ty)
- -> (boxing_data_con, primRepFromType prim_ty)
+ -> (boxing_data_con, typePrimRep prim_ty)
+ Nothing
+ -> pprError "ERROR: ``literal-literal'' not a single-constructor type: "
+ (ppBesides [ppPStr s, ppStr "; type: ", ppr PprDebug ty])
dsExpr (HsLitOut (HsInt i) _)
= returnDs (Lit (NoRepInteger i))
mkAppDs expr2 [] [from2, thn2, two2]
\end{code}
+
+Type lambda and application
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
\begin{code}
dsExpr (TyLam tyvars expr)
= dsExpr expr `thenDs` \ core_expr ->
dsExpr expr@(TyApp e tys) = dsApp expr []
\end{code}
+
+Record construction and update
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+\begin{code}
+{-
+dsExpr (RecordCon con_expr rbinds)
+ = dsExpr con_expr `thenDs` \ con_expr' ->
+ let
+ con_args = map mk_arg (arg_tys `zip` fieldLabelTags)
+ (arg_tys, data_ty) = splitFunTy (coreExprType con_expr')
+
+ mk_arg (arg_ty, tag) = case [ | (sel_id,rhs) <- rbinds,
+ fieldLabelTag (recordSelectorFieldLabel sel_id) == tag
+ ] of
+ (rhs:rhss) -> ASSERT( null rhss )
+ dsExpr rhs
+
+ [] -> returnDs ......GONE HOME!>>>>>
+
+ mkAppDs con_expr [] con_args
+-}
+\end{code}
+
+Dictionary lambda and application
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@DictLam@ and @DictApp@ turn into the regular old things.
(OLD:) @DictFunApp@ also becomes a curried application, albeit slightly more
complicated; reminiscent of fully-applied constructors.
import TcHsSyn ( TypecheckedGRHSsAndBinds(..), TypecheckedGRHS(..),
TypecheckedPat(..), TypecheckedHsBinds(..),
TypecheckedHsExpr(..) )
-import CoreSyn ( CoreBinding(..), CoreExpr(..) )
+import CoreSyn ( CoreBinding(..), CoreExpr(..), mkCoLetsAny )
import DsMonad
import DsUtils
-import CoreUtils ( escErrorMsg, mkErrorApp )
+import CoreUtils ( escErrorMsg, mkErrorApp, mkCoreIfThenElse )
import PrelInfo ( stringTy )
import PprStyle ( PprStyle(..) )
import Pretty ( ppShow )
import SrcLoc ( SrcLoc{-instance-} )
import Util ( panic )
-
-mkCoLetsAny = panic "DsGRHSs.mkCoLetsAny"
-mkCoreIfThenElse = panic "DsGRHSs.mkCoreIfThenElse"
\end{code}
@dsGuarded@ is used for both @case@ expressions and pattern bindings.
import CoreSyn ( CoreExpr(..) )
import CoreUtils ( substCoreExpr )
import HsSyn ( OutPat )
-import Id ( mkSysLocal, lookupIdEnv, growIdEnvList, GenId, IdEnv(..) )
+import Id ( mkSysLocal, mkIdWithNewUniq,
+ lookupIdEnv, growIdEnvList, GenId, IdEnv(..)
+ )
import PprType ( GenType, GenTyVar )
import PprStyle ( PprStyle(..) )
import Pretty
import SrcLoc ( unpackSrcLoc, mkUnknownSrcLoc, SrcLoc )
import TcHsSyn ( TypecheckedPat(..) )
-import TyVar ( nullTyVarEnv, GenTyVar )
+import TyVar ( nullTyVarEnv, cloneTyVar, GenTyVar{-instance Eq-} )
import Unique ( Unique{-instances-} )
import UniqSupply ( splitUniqSupply, getUnique, getUniques,
mapUs, thenUs, returnUs, UniqSM(..) )
-import Unique ( Unique )
import Util ( assoc, mapAccumL, zipWithEqual, panic )
infixr 9 `thenDs`
-
-cloneTyVar = panic "DsMonad.cloneTyVar"
-cloneTyVarFromTemplate = panic "DsMonad.cloneTyVarFromTemplate"
-mkIdWithNewUniq = panic "DsMonad.mkIdWithNewUniq"
\end{code}
Now the mondo monad magic (yes, @DsM@ is a silly name)---carry around
newTyVarsDs tyvar_tmpls us loc mod_and_grp env warns
= case (getUniques (length tyvar_tmpls) us) of { uniqs ->
- (zipWithEqual cloneTyVarFromTemplate tyvar_tmpls uniqs, warns) }
+ (zipWithEqual cloneTyVar tyvar_tmpls uniqs, warns) }
\end{code}
We can also reach out and either set/grab location information from
import Id ( idType, getInstantiatedDataConSig, mkTupleCon,
DataCon(..), DictVar(..), Id(..), GenId )
import TyCon ( mkTupleTyCon )
-import Type ( mkTyVarTys, mkRhoTy, mkFunTys,
- applyTyCon, getAppDataTyCon )
+import Type ( mkTyVarTys, mkRhoTy, mkFunTys, isUnboxedType,
+ applyTyCon, getAppDataTyCon
+ )
import UniqSet ( mkUniqSet, minusUniqSet, uniqSetToList, UniqSet(..) )
import Util ( panic, assertPanic )
-isUnboxedDataType = panic "DsUtils.isUnboxedDataType"
quantifyTy = panic "DsUtils.quantifyTy"
splitDictType = panic "DsUtils.splitDictType"
mkCoTyApps = panic "DsUtils.mkCoTyApps"
newSysLocalDs ty `thenDs` \ arg_id ->
continue_with (VarArg arg_id) `thenDs` \ body ->
returnDs (
- if isUnboxedDataType ty
+ if isUnboxedType ty
then Case arg_expr (PrimAlts [] (BindDefault arg_id body))
else Let (NonRec arg_id arg_expr) body
)
CoreExpr) -- Either the fail variable, or fail variable
-- applied to unit tuple
mkFailurePair ty
- | isUnboxedDataType ty
+ | isUnboxedType ty
= newFailLocalDs (mkFunTys [unit_ty] ty) `thenDs` \ fail_fun_var ->
newSysLocalDs unit_ty `thenDs` \ fail_fun_arg ->
returnDs (\ body ->
import MatchLit ( matchLiterals )
import CoreUtils ( escErrorMsg, mkErrorApp )
-import Id ( idType, mkTupleCon, GenId{-instance-} )
+import FieldLabel ( allFieldLabelTags, fieldLabelTag )
+import Id ( idType, mkTupleCon, dataConSig,
+ recordSelectorFieldLabel,
+ GenId{-instance-}
+ )
import PprStyle ( PprStyle(..) )
-import PprType ( GenTyVar{-instance-}, GenType{-instance-} )
+import PprType ( GenType{-instance-}, GenTyVar{-ditto-} )
import PrelInfo ( nilDataCon, consDataCon, mkTupleTy, mkListTy,
charTy, charDataCon, intTy, intDataCon,
floatTy, floatDataCon, doubleTy, doubleDataCon,
floatPrimTy, doublePrimTy, stringTy,
addrTy, addrPrimTy, addrDataCon,
wordTy, wordPrimTy, wordDataCon )
-import Type ( isPrimType, eqTy )
-import TyVar ( GenTyVar )
-import Unique ( Unique )
-import Util ( panic, pprPanic )
+import Type ( isPrimType, eqTy, getAppDataTyCon,
+ instantiateTauTy
+ )
+import TyVar ( GenTyVar{-instance Eq-} )
+import Unique ( Unique{-instance Eq-} )
+import Util ( panic, pprPanic, assertPanic )
\end{code}
The function @match@ is basically the same as in the Wadler chapter,
tidy1 v (ConOpPat pat1 id pat2 ty) match_result
= returnDs (ConPat id ty [pat1, pat2], match_result)
+tidy1 v (RecPat con_id pat_ty rpats) match_result
+ = returnDs (ConPat con_id pat_ty pats, match_result)
+ where
+ pats = map mk_pat tagged_arg_tys
+
+ -- Boring stuff to find the arg-tys of the constructor
+ (tyvars, _, arg_tys, _) = dataConSig con_id
+ (_, inst_tys, _) = getAppDataTyCon pat_ty
+ tenv = tyvars `zip` inst_tys
+ con_arg_tys' = map (instantiateTauTy tenv) arg_tys
+ tagged_arg_tys = con_arg_tys' `zip` allFieldLabelTags
+
+ -- mk_pat picks a WildPat of the appropriate type for absent fields,
+ -- and the specified pattern for present fields
+ mk_pat (arg_ty, tag) = case [pat | (sel_id,pat,_) <- rpats,
+ fieldLabelTag (recordSelectorFieldLabel sel_id) == tag
+ ] of
+ (pat:pats) -> ASSERT( null pats )
+ pat
+ [] -> WildPat arg_ty
+
tidy1 v (ListPat ty pats) match_result
= returnDs (list_ConPat, match_result)
where
mk_core_lit ty (HsFloatPrim f) = MachFloat f
mk_core_lit ty (HsDoublePrim d) = MachDouble d
mk_core_lit ty (HsLitLit s) = ASSERT(isPrimType ty)
- MachLitLit s (panic "MatchLit.matchLiterals:mk_core_lit:HsLitLit; primRepFromType???")
+ MachLitLit s (panic "MatchLit.matchLiterals:mk_core_lit:HsLitLit; typePrimRep???")
mk_core_lit ty other = panic "matchLiterals:mk_core_lit:unhandled"
\end{code}
> Let (NonRec (v,ManyOcc _) e) e'
> | isTrivial e -> c2d (addOneToIdEnv p v (c2d p e)) e'
> | otherwise ->
-> trace ("Not inlining ManyOcc " ++ ppShow 80 (ppr PprDebug v)) (
-> Let (NonRec v (c2d p e)) (c2d p e'))
+> pprTrace "Not inlining ManyOcc " (ppr PprDebug v) $
+> Let (NonRec v (c2d p e)) (c2d p e')
>
> Let (NonRec (v,DeadCode) e) e' ->
> panic "Core2Def(c2d): oops, unexpected DeadCode"
> Let (NonRec (v,OneOcc fun_or_arg dup_danger _ _ _) e) e'
> | isTrivial e -> inline_it
> | isDupDanger dup_danger ->
-> trace ("Not inlining DupDanger " ++ ppShow 80 (ppr PprDebug v))(
-> Let (NonRec v (c2d p e)) (c2d p e'))
+> pprTrace "Not inlining DupDanger " (ppr PprDebug v) $
+> Let (NonRec v (c2d p e)) (c2d p e')
> | isFun fun_or_arg ->
> panic "Core2Def(c2d): oops, unexpected Macro"
> | otherwise -> inline_it
> if not (null back_loops){- && not (f `elem` ls')-} then
> --if length back_loops > 1 then panic "barf!" else
> d2c (head back_loops) `thenUs` \core_e ->
-> trace ("Back Loop:\n" ++
-> ppShow 80 (ppr PprDebug core_e)) $
+> pprTrace "Back Loop:\n" (ppr PprDebug core_e) $
If we find a back-loop that also occurs where we would normally make a
new function...
--others:
import Id ( DictVar(..), Id(..), GenId )
import Outputable
-import PprType ( pprType )
import Pretty
import SrcLoc ( SrcLoc{-instances-} )
-import TyVar ( GenTyVar{-instances-} )
+--import TyVar ( GenTyVar{-instances-} )
\end{code}
%************************************************************************
SrcLoc
| RecConDecl name
- [(name, BangType name)] -- list of "fields"
+ [([name], BangType name)] -- list of "fields"
SrcLoc
| NewConDecl name -- newtype con decl
-- others:
import Id ( DictVar(..), GenId, Id(..) )
import Outputable
-import PprType ( pprType, pprParendType, GenType{-instance-}, GenTyVar{-instance-} )
+import PprType ( pprGenType, pprParendGenType, GenType{-instance-} )
import Pretty
import PprStyle ( PprStyle(..) )
import SrcLoc ( SrcLoc )
-import TyVar ( GenTyVar{-instances-} )
import Usage ( GenUsage{-instance-} )
-import Unique ( Unique{-instances-} )
import Util ( panic{-ToDo:rm eventually-} )
\end{code}
-- for tuples, we can get the types
-- direct from the components
- | RecordCon id -- record construction
- [(id, Maybe (HsExpr tyvar uvar id pat))]
+ -- Record construction
+ | RecordCon (HsExpr tyvar uvar id pat) -- Always (HsVar id) until type checker,
+ -- but the latter adds its type args too
+ (HsRecordBinds tyvar uvar id pat)
- | RecordUpd (HsExpr tyvar uvar id pat) -- record update
- [(id, Maybe (HsExpr tyvar uvar id pat))]
+ -- Record update
+ | RecordUpd (HsExpr tyvar uvar id pat)
+ (HsRecordBinds tyvar uvar id pat)
| ExprWithTySig -- signature binding
(HsExpr tyvar uvar id pat)
| SingleDict -- a simple special case of Dictionary
id -- local dictionary name
+
+type HsRecordBinds tyvar uvar id pat
+ = [(id, HsExpr tyvar uvar id pat, Bool)]
+ -- True <=> source code used "punning",
+ -- i.e. {op1, op2} rather than {op1=e1, op2=e2}
\end{code}
A @Dictionary@, unless of length 0 or 1, becomes a tuple. A
= ppBracket (ppInterleave ppComma (map (pprExpr sty) exprs))
pprExpr sty (ExplicitListOut ty exprs)
= ppBesides [ ppBracket (ppInterleave ppComma (map (pprExpr sty) exprs)),
- ifnotPprForUser sty (ppBeside ppSP (ppParens (pprType sty ty))) ]
+ ifnotPprForUser sty (ppBeside ppSP (ppParens (pprGenType sty ty))) ]
pprExpr sty (ExplicitTuple exprs)
= ppParens (ppInterleave ppComma (map (pprExpr sty) exprs))
4 (pprExpr sty expr)
pprExpr sty (TyApp expr [ty])
- = ppHang (pprExpr sty expr) 4 (pprParendType sty ty)
+ = ppHang (pprExpr sty expr) 4 (pprParendGenType sty ty)
pprExpr sty (TyApp expr tys)
= ppHang (pprExpr sty expr)
%************************************************************************
\begin{code}
+pp_rbinds :: (NamedThing id, Outputable id, Outputable pat,
+ Eq tyvar, Outputable tyvar, Eq uvar, Outputable uvar)
+ => PprStyle -> Pretty
+ -> HsRecordBinds tyvar uvar id pat -> Pretty
+
pp_rbinds sty thing rbinds
= ppHang thing 4
(ppBesides [ppChar '{', ppInterleave ppComma (map (pp_rbind sty) rbinds), ppChar '}'])
-
-pp_rbind :: (NamedThing id, Outputable id, Outputable pat,
- Eq tyvar, Outputable tyvar, Eq uvar, Outputable uvar)
- => PprStyle -> (id, Maybe (HsExpr tyvar uvar id pat)) -> Pretty
-
-pp_rbind sty (v, Nothing) = ppr sty v
-pp_rbind sty (v, Just e) = ppCat [ppr sty v, ppStr "<-", ppr sty e]
+ where
+ pp_rbind sty (v, _, True{-pun-}) = ppr sty v
+ pp_rbind sty (v, e, _) = ppCat [ppr sty v, ppStr "<-", ppr sty e]
\end{code}
%************************************************************************
import PprType
import Pretty
import SrcLoc ( SrcLoc{-instances-} )
-import TyVar ( GenTyVar{-instances-} )
-import Unique ( Unique{-instances-} )
import Util ( panic )
\end{code}
import HsLoop ( HsExpr )
-- others:
-import Id ( GenId, getDataConSig )
+import Id ( GenId, dataConSig )
import Maybes ( maybeToBool )
import Outputable
import PprStyle ( PprStyle(..) )
import Pretty
import TyCon ( maybeTyConSingleCon )
-import TyVar ( GenTyVar )
-import PprType ( GenType, GenTyVar )
-import Unique ( Unique )
-
+import PprType ( GenType )
\end{code}
Patterns come in distinct before- and after-typechecking flavo(u)rs.
| TuplePatIn [InPat name] -- tuple
| RecPatIn name -- record
- [(name, Maybe (InPat name))]
+ [(name, InPat name, Bool)] -- True <=> source used punning
data OutPat tyvar uvar id
= WildPat (GenType tyvar uvar) -- wild card
| TuplePat [(OutPat tyvar uvar id)] -- tuple
-- UnitPat is TuplePat []
- | RecPat id -- record
- [(id, Maybe (OutPat tyvar uvar id))]
+ | RecPat Id -- record constructor
+ (GenType tyvar uvar) -- the type of the pattern
+ [(id, OutPat tyvar uvar id, Bool)] -- True <=> source used punning
| LitPat -- Used for *non-overloaded* literal patterns:
-- Int#, Char#, Int, Char, String, etc.
pprInPat sty (RecPatIn con rpats)
= ppBesides [ppr sty con, ppSP, ppChar '{', ppInterleave ppComma (map pp_rpat rpats), ppChar '}']
where
- pp_rpat (v, Nothing) = ppr sty v
- pp_rpat (v, Just p) = ppCat [ppr sty v, ppStr "<-", ppr sty p]
+ pp_rpat (v, _, True{-pun-}) = ppr sty v
+ pp_rpat (v, p, _) = ppCat [ppr sty v, ppStr "<-", ppr sty p]
\end{code}
\begin{code}
pprOutPat sty (TuplePat pats)
= ppBesides [ppLparen, interpp'SP sty pats, ppRparen]
-pprOutPat sty (RecPat con rpats)
+pprOutPat sty (RecPat con ty rpats)
= ppBesides [ppr sty con, ppChar '{', ppInterleave ppComma (map pp_rpat rpats), ppChar '}']
where
- pp_rpat (v, Nothing) = ppr sty v
- pp_rpat (v, Just p) = ppBesides [ppr sty v, ppStr "<-", ppr sty p]
+-- pp_rpat (v, _, True{-pun-}) = ppr sty v
+ pp_rpat (v, p, _) = ppBesides [ppr sty v, ppStr "<-", ppr sty p]
pprOutPat sty (LitPat l ty) = ppr sty l -- ToDo: print more
pprOutPat sty (NPat l ty e) = ppr sty l -- ToDo: print more
only_con con = maybeToBool (maybeTyConSingleCon tycon)
where
- (_,_,_,tycon) = getDataConSig con
+ (_,_,_,tycon) = dataConSig con
\end{code}
This function @collectPatBinders@ works with the ``collectBinders''
Error(..),
addErrLoc, addShortErrLocLine,
- dontAddErrLoc, pprBagOfErrors,
-
- TcError(..), TcWarning(..), Message(..),
- mkTcErr, arityErr
+ dontAddErrLoc, pprBagOfErrors
) where
ppAboves (map (\ p -> ppAbove ppSP p) pretties)
\end{code}
-TypeChecking Errors
-~~~~~~~~~~~~~~~~~~~
-
-\begin{code}
-type Message = PprStyle -> Pretty
-type TcError = Message
-type TcWarning = Message
-
-
-mkTcErr :: SrcLoc -- Where
- -> [Message] -- Context
- -> Message -- What went wrong
- -> TcError -- The complete error report
-
-mkTcErr locn ctxt msg sty
- = ppHang (ppBesides [ppr PprForUser locn, ppStr ": ", msg sty])
- 4 (ppAboves [msg sty | msg <- ctxt])
-
-
-arityErr kind name n m sty =
- ppBesides [ ppStr "`", ppr sty name, ppStr "' should have ",
- n_arguments, ppStr ", but has been given ", ppInt m, ppChar '.']
- where
- errmsg = kind ++ " has too " ++ quantity ++ " arguments"
- quantity | m < n = "few"
- | otherwise = "many"
- n_arguments | n == 0 = ppStr "no arguments"
- | n == 1 = ppStr "1 argument"
- | True = ppCat [ppInt n, ppStr "arguments"]
-\end{code}
import Rename ( renameModule )
import Typecheck ( typecheckModule, InstInfo )
import Desugar ( deSugar, DsMatchContext, pprDsWarnings )
+import SimplCore ( core2core )
+import CoreToStg ( topCoreBindsToStg )
+import SimplStg ( stg2stg )
+import CodeGen ( codeGen )
+#if ! OMIT_NATIVE_CODEGEN
+import AsmCodeGen ( dumpRealAsm, writeRealAsm )
+#endif
+import AbsCSyn ( absCNop, AbstractC )
+import AbsCUtils ( flattenAbsC )
import Bag ( emptyBag, isEmptyBag )
import CmdLineOpts
import ErrUtils ( pprBagOfErrors )
-import Maybes ( MaybeErr(..) )
+import Maybes ( maybeToBool, MaybeErr(..) )
import PrelInfo ( builtinNameInfo )
import RdrHsSyn ( getRawExportees )
+import Specialise ( SpecialiseData(..) )
+import StgSyn ( pprPlainStgBinding, GenStgBinding )
-import PprCore ( pprPlainCoreBinding )
+import PprAbsC ( dumpRealC, writeRealC )
+import PprCore ( pprCoreBinding )
import PprStyle ( PprStyle(..) )
import Pretty
import Unique ( Unique) -- instances
{-
---import AbsCSyn
---import CodeGen ( codeGen )
---import CoreToStg ( topCoreBindsToStg )
---import MkIface ( mkInterface )
-
---import SimplCore ( core2core )
---import SimplStg ( stg2stg )
---import StgSyn ( pprPlainStgBinding, GenStgBinding, GenStgRhs, CostCentre,
- StgBinderInfo, StgBinding(..)
- )
+--import MkIface ( mkInterface )
-#if ! OMIT_NATIVE_CODEGEN
---import AsmCodeGen ( dumpRealAsm, writeRealAsm )
-#endif
-}
\end{code}
else ( -- No typechecking errors ...
case tc_results
- of { (typechecked_quad@(class_binds, inst_binds, val_binds, const_binds),
+ of { (typechecked_quint@(recsel_binds, class_binds, inst_binds, val_binds, const_binds),
interface_stuff@(_,_,_,_,_), -- @-pat just for strictness...
(local_tycons,local_classes), pragma_tycon_specs, ddump_deriv) ->
doDump opt_D_dump_tc "Typechecked:"
(pp_show (ppAboves [
+ ppr pprStyle recsel_binds,
ppr pprStyle class_binds,
ppr pprStyle inst_binds,
ppAboves (map (\ (i,e) -> ppr pprStyle (VarMonoBind i e)) const_binds),
doDump opt_D_dump_deriv "Derived instances:"
(pp_show (ddump_deriv pprStyle)) `thenMn_`
-
-- ******* DESUGARER
show_pass "DeSugar" `thenMn_`
let
(desugared,ds_warnings)
- = deSugar ds_uniqs ds_mod_name typechecked_quad
+ = deSugar ds_uniqs ds_mod_name typechecked_quint
in
(if isEmptyBag ds_warnings then
returnMn ()
) `thenMn_`
doDump opt_D_dump_ds "Desugared:" (pp_show (ppAboves
- (map (pprPlainCoreBinding pprStyle) desugared)))
+ (map (pprCoreBinding pprStyle) desugared)))
`thenMn_`
-{- LATER ...
-
-- ******* CORE-TO-CORE SIMPLIFICATION (NB: I/O op)
- core2core core_cmds switch_lookup_fn co_mod_name pprStyle
+ core2core core_cmds co_mod_name pprStyle
sm_uniqs local_tycons pragma_tycon_specs desugared
`thenMn`
SpecData _ _ _ gen_tycons all_tycon_specs _ _ _) ->
doDump opt_D_dump_simpl "Simplified:" (pp_show (ppAboves
- (map (pprPlainCoreBinding pprStyle) simplified)))
+ (map (pprCoreBinding pprStyle) simplified)))
`thenMn_`
-- ******* STG-TO-STG SIMPLIFICATION
in
show_pass "Stg2Stg" `thenMn_`
- stg2stg stg_cmds switch_lookup_fn st_mod_name pprStyle st_uniqs stg_binds
+ stg2stg stg_cmds st_mod_name pprStyle st_uniqs stg_binds
`thenMn`
\ (stg_binds2, cost_centre_info) ->
(pp_show (ppAboves (map (pprPlainStgBinding pprStyle) stg_binds2)))
`thenMn_`
+{- LATER ...
-- ******* INTERFACE GENERATION (needs STG output)
{- let
mod_name = "_TestName_"
if_inst_info = emptyBag
in
-}
+
show_pass "Interface" `thenMn_`
let
mod_interface
- = mkInterface switch_is_on if_mod_name export_list_fns
+ = mkInterface if_mod_name export_list_fns
inlinings_env all_tycon_specs
interface_stuff
stg_binds2
in
- doOutput ProduceHi ( \ file ->
+ doOutput opt_ProduceHi ( \ file ->
ppAppendFile file 1000{-pprCols-} mod_interface )
`thenMn_`
+-}
-- ******* "ABSTRACT", THEN "FLAT", THEN *REAL* C!
show_pass "CodeGen" `thenMn_`
abstractC = codeGen cc_mod_name -- module name for CC labelling
cost_centre_info
cc_import_names -- import names for CC registering
- switch_lookup_fn
gen_tycons -- type constructors generated locally
all_tycon_specs -- tycon specialisations
stg_binds2
flat_abstractC = flattenAbsC fl_uniqs abstractC
in
doDump opt_D_dump_absC "Abstract C:"
- (dumpRealC switch_is_on abstractC) `thenMn_`
+ (dumpRealC abstractC) `thenMn_`
doDump opt_D_dump_flatC "Flat Abstract C:"
- (dumpRealC switch_is_on flat_abstractC) `thenMn_`
+ (dumpRealC flat_abstractC) `thenMn_`
-- You can have C (c_output) or assembly-language (ncg_output),
-- but not both. [Allowing for both gives a space leak on
-- flat_abstractC. WDP 94/10]
let
(flat_absC_c, flat_absC_ncg) =
- case (string_switch_is_on ProduceC || switch_is_on D_dump_realC,
- string_switch_is_on ProduceS || switch_is_on D_dump_asm) of
- (True, False) -> (flat_abstractC, AbsCNop)
- (False, True) -> (AbsCNop, flat_abstractC)
- (False, False) -> (AbsCNop, AbsCNop)
+ case (maybeToBool opt_ProduceC || opt_D_dump_realC,
+ maybeToBool opt_ProduceS || opt_D_dump_asm) of
+ (True, False) -> (flat_abstractC, absCNop)
+ (False, True) -> (absCNop, flat_abstractC)
+ (False, False) -> (absCNop, absCNop)
(True, True) -> error "ERROR: Can't do both .hc and .s at the same time"
- c_output_d = dumpRealC switch_is_on flat_absC_c
- c_output_w = (\ f -> writeRealC switch_is_on f flat_absC_c)
+ c_output_d = dumpRealC flat_absC_c
+ c_output_w = (\ f -> writeRealC f flat_absC_c)
#if OMIT_NATIVE_CODEGEN
ncg_output_d = error "*** GHC not built with a native-code generator ***"
ncg_output_w = ncg_output_d
#else
- ncg_output_d = dumpRealAsm switch_lookup_fn flat_absC_ncg ncg_uniqs
- ncg_output_w = (\ f -> writeRealAsm switch_lookup_fn f flat_absC_ncg ncg_uniqs)
+ ncg_output_d = dumpRealAsm flat_absC_ncg ncg_uniqs
+ ncg_output_w = (\ f -> writeRealAsm f flat_absC_ncg ncg_uniqs)
#endif
in
doDump opt_D_dump_asm "" ncg_output_d `thenMn_`
- doOutput ProduceS ncg_output_w `thenMn_`
+ doOutput opt_ProduceS ncg_output_w `thenMn_`
doDump opt_D_dump_realC "" c_output_d `thenMn_`
- doOutput ProduceC c_output_w `thenMn_`
-
-LATER -}
+ doOutput opt_ProduceC c_output_w `thenMn_`
exitMn 0
} ) } } }
where
doOutput switch io_action
= case switch of
- Nothing -> returnMn ()
- Just fname ->
+ Nothing -> returnMn ()
+ Just fn -> let fname = _UNPK_ fn in
fopen fname "a+" `thenPrimIO` \ file ->
if (file == ``NULL'') then
error ("doOutput: failed to open:"++fname)
doDump switch hdr string
= if switch
- then writeMn stderr hdr `thenMn_`
- writeMn stderr ('\n': string) `thenMn_`
+ then writeMn stderr hdr `thenMn_`
+ writeMn stderr ('\n': string) `thenMn_`
writeMn stderr "\n"
else returnMn ()
-- mkInterface to do I/O (WDP 94/10)
error "Can't produce interface file because of errors!\n"
else
--- trace ("mkIface:Ids:"++(ppShow 80 (ppr PprDebug global_ids))) (
ppAboves
[ppPStr SLIT("{-# GHC_PRAGMA INTERFACE VERSION 7 #-}"),
ppCat [ppPStr SLIT("interface"), ppPStr modname, ppPStr SLIT("where")],
ppChar '\n'
]
--- )
where
any_purely_local tycons classes vals
= any bad_tc tycons || any bad_cl classes || any bad_id vals
ExportAbs -> orig_nm
NotExported -> orig_nm
- cons = getTyConDataCons tycon
+ cons = tyConDataCons tycon
in
(orig_mod, nm_to_print) }
ppPStr SLIT("#-}")]
in
ppAbove (ppCat [ppr_non_op name_str,
- ppPStr SLIT("::"), pprType sty val_ty])
+ ppPStr SLIT("::"), pprGenType sty val_ty])
pp_id_info
-- sadly duplicates Outputable.pprNonOp (ToDo)
%
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1996
%
\begin{code}
#include "HsVersions.h"
-module AbsCStixGen (
- genCodeAbstractC,
+module AbsCStixGen ( genCodeAbstractC ) where
- -- and, of course, that's not enough...
- AbstractC, Target, StixTree, UniqSupply, UniqSM(..)
- ) where
+import Ubiq{-uitous-}
import AbsCSyn
-import PrelInfo ( PrimOp(..), primOpNeedsWrapper, isCompareOp
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
+import Stix
+
+import MachMisc
+import MachRegs
+
+import AbsCUtils ( getAmodeRep, mixedTypeLocn,
+ nonemptyAbsC, mkAbsCStmts, mkAbsCStmtList
)
import CgCompInfo ( mIN_UPD_SIZE )
-import ClosureInfo ( infoTableLabelFromCI, entryLabelFromCI, fastLabelFromCI,
- closureUpdReqd
+import ClosureInfo ( infoTableLabelFromCI, entryLabelFromCI,
+ fastLabelFromCI, closureUpdReqd
)
-import MachDesc
-import Maybes ( Maybe(..), maybeToBool )
-import Outputable
-import PrimRep ( isFloatingRep )
-import SMRep ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..) )
-import Stix
+import HeapOffs ( hpRelToInt )
+import Literal ( Literal(..) )
+import Maybes ( maybeToBool )
+import OrdList ( OrdList )
+import PrimOp ( primOpNeedsWrapper, PrimOp(..) )
+import PrimRep ( isFloatingRep, PrimRep(..) )
import StixInfo ( genCodeInfoTable )
-import UniqSupply
-import Util
+import StixMacro ( macroCode )
+import StixPrim ( primCode, amodeToStix, amodeToStix' )
+import UniqSupply ( returnUs, thenUs, mapUs, getUnique, UniqSM(..) )
+import Util ( naturalMergeSortLe, panic )
\end{code}
-For each independent chunk of AbstractC code, we generate a list of @StixTree@s,
-where each tree corresponds to a single Stix instruction. We leave the chunks
-separated so that register allocation can be performed locally within the chunk.
+For each independent chunk of AbstractC code, we generate a list of
+@StixTree@s, where each tree corresponds to a single Stix instruction.
+We leave the chunks separated so that register allocation can be
+performed locally within the chunk.
\begin{code}
--- hacking with Uncle Will:
-#define target_STRICT target@(Target _ _ _ _ _ _ _ _)
+genCodeAbstractC :: AbstractC -> UniqSM [[StixTree]]
-genCodeAbstractC
- :: Target
- -> AbstractC
- -> UniqSM [[StixTree]]
-
-genCodeAbstractC target_STRICT absC =
- mapUs gentopcode (mkAbsCStmtList absC) `thenUs` \ trees ->
+genCodeAbstractC absC
+ = mapUs gentopcode (mkAbsCStmtList absC) `thenUs` \ trees ->
returnUs ([StComment SLIT("Native Code")] : trees)
where
- -- "target" munging things... ---
- a2stix = amodeToStix target
- a2stix' = amodeToStix' target
- volsaves = volatileSaves target
- volrestores = volatileRestores target
- p2stix = primToStix target
- macro_code = macroCode target
- hp_rel = hpRel target
+ a2stix = amodeToStix
+ a2stix' = amodeToStix'
+ volsaves = volatileSaves
+ volrestores = volatileRestores
+ p2stix = primCode
+ macro_code = macroCode
+ hp_rel = hpRelToInt
-- real code follows... ---------
\end{code}
\begin{code}
{-
genCodeTopAbsC
- :: Target
- -> AbstractC
+ :: AbstractC
-> UniqSM [StixTree]
-}
- gentopcode (CCodeBlock label absC) =
- gencode absC `thenUs` \ code ->
+ gentopcode (CCodeBlock label absC)
+ = gencode absC `thenUs` \ code ->
returnUs (StSegment TextSegment : StFunBegin label : code [StFunEnd label])
- gentopcode stmt@(CStaticClosure label _ _ _) =
- genCodeStaticClosure stmt `thenUs` \ code ->
+ gentopcode stmt@(CStaticClosure label _ _ _)
+ = genCodeStaticClosure stmt `thenUs` \ code ->
returnUs (StSegment DataSegment : StLabel label : code [])
gentopcode stmt@(CRetUnVector _ _) = returnUs []
- gentopcode stmt@(CFlatRetVector label _) =
- genCodeVecTbl stmt `thenUs` \ code ->
+ gentopcode stmt@(CFlatRetVector label _)
+ = genCodeVecTbl stmt `thenUs` \ code ->
returnUs (StSegment TextSegment : code [StLabel label])
gentopcode stmt@(CClosureInfoAndCode cl_info slow Nothing _ _ _)
| slow_is_empty
- = genCodeInfoTable hp_rel a2stix stmt `thenUs` \ itbl ->
+ = genCodeInfoTable stmt `thenUs` \ itbl ->
returnUs (StSegment TextSegment : itbl [])
| otherwise
- = genCodeInfoTable hp_rel a2stix stmt `thenUs` \ itbl ->
- gencode slow `thenUs` \ slow_code ->
+ = genCodeInfoTable stmt `thenUs` \ itbl ->
+ gencode slow `thenUs` \ slow_code ->
returnUs (StSegment TextSegment : itbl (StFunBegin slow_lbl :
slow_code [StFunEnd slow_lbl]))
where
gentopcode stmt@(CClosureInfoAndCode cl_info slow (Just fast) _ _ _) =
-- ToDo: what if this is empty? ------------------------^^^^
- genCodeInfoTable hp_rel a2stix stmt `thenUs` \ itbl ->
- gencode slow `thenUs` \ slow_code ->
- gencode fast `thenUs` \ fast_code ->
+ genCodeInfoTable stmt `thenUs` \ itbl ->
+ gencode slow `thenUs` \ slow_code ->
+ gencode fast `thenUs` \ fast_code ->
returnUs (StSegment TextSegment : itbl (StFunBegin slow_lbl :
slow_code (StFunEnd slow_lbl : StFunBegin fast_lbl :
fast_code [StFunEnd fast_lbl])))
slow_lbl = entryLabelFromCI cl_info
fast_lbl = fastLabelFromCI cl_info
- gentopcode absC =
- gencode absC `thenUs` \ code ->
+ gentopcode absC
+ = gencode absC `thenUs` \ code ->
returnUs (StSegment TextSegment : code [])
\end{code}
\begin{code}
{-
genCodeVecTbl
- :: Target
- -> AbstractC
+ :: AbstractC
-> UniqSM StixTreeList
-}
- genCodeVecTbl (CFlatRetVector label amodes) =
- returnUs (\xs -> vectbl : xs)
+ genCodeVecTbl (CFlatRetVector label amodes)
+ = returnUs (\xs -> vectbl : xs)
where
vectbl = StData PtrRep (reverse (map a2stix amodes))
\begin{code}
{-
genCodeStaticClosure
- :: Target
- -> AbstractC
+ :: AbstractC
-> UniqSM StixTreeList
-}
- genCodeStaticClosure (CStaticClosure _ cl_info cost_centre amodes) =
- returnUs (\xs -> table : xs)
+ genCodeStaticClosure (CStaticClosure _ cl_info cost_centre amodes)
+ = returnUs (\xs -> table : xs)
where
table = StData PtrRep (StCLbl info_lbl : body)
info_lbl = infoTableLabelFromCI cl_info
\begin{code}
{-
gencode
- :: Target
- -> AbstractC
+ :: AbstractC
-> UniqSM StixTreeList
-}
\end{code}
\begin{code}
- gencode (AbsCStmts c1 c2) =
- gencode c1 `thenUs` \ b1 ->
+ gencode (AbsCStmts c1 c2)
+ = gencode c1 `thenUs` \ b1 ->
gencode c2 `thenUs` \ b2 ->
returnUs (b1 . b2)
\begin{code}
- gencode (CInitHdr cl_info reg_rel _ _) =
- let
+ gencode (CInitHdr cl_info reg_rel _ _)
+ = let
lhs = a2stix (CVal reg_rel PtrRep)
lbl = infoTableLabelFromCI cl_info
in
gencode (CAssign lhs rhs)
| getAmodeRep lhs == VoidRep = returnUs id
- | otherwise =
- let pk = getAmodeRep lhs
+ | otherwise
+ = let pk = getAmodeRep lhs
pk' = if mixedTypeLocn lhs && not (isFloatingRep pk) then IntRep else pk
lhs' = a2stix lhs
rhs' = a2stix' rhs
\begin{code}
- gencode (CJump dest) =
- returnUs (\xs -> StJump (a2stix dest) : xs)
+ gencode (CJump dest)
+ = returnUs (\xs -> StJump (a2stix dest) : xs)
- gencode (CFallThrough (CLbl lbl _)) =
- returnUs (\xs -> StFallThrough lbl : xs)
+ gencode (CFallThrough (CLbl lbl _))
+ = returnUs (\xs -> StFallThrough lbl : xs)
- gencode (CReturn dest DirectReturn) =
- returnUs (\xs -> StJump (a2stix dest) : xs)
+ gencode (CReturn dest DirectReturn)
+ = returnUs (\xs -> StJump (a2stix dest) : xs)
- gencode (CReturn table (StaticVectoredReturn n)) =
- returnUs (\xs -> StJump dest : xs)
+ gencode (CReturn table (StaticVectoredReturn n))
+ = returnUs (\xs -> StJump dest : xs)
where
dest = StInd PtrRep (StIndex PtrRep (a2stix table)
(StInt (toInteger (-n-1))))
- gencode (CReturn table (DynamicVectoredReturn am)) =
- returnUs (\xs -> StJump dest : xs)
+ gencode (CReturn table (DynamicVectoredReturn am))
+ = returnUs (\xs -> StJump dest : xs)
where
dest = StInd PtrRep (StIndex PtrRep (a2stix table) dyn_off)
dyn_off = StPrim IntSubOp [StPrim IntNegOp [a2stix am], StInt 1]
gencode (COpStmt results op args liveness_mask vols)
-- ToDo (ADR?): use that liveness mask
- | primOpNeedsWrapper op =
- let
+ | primOpNeedsWrapper op
+ = let
saves = volsaves vols
restores = volrestores vols
in
gencode (CMacroStmt macro args) = macro_code macro args
- gencode (CCallProfCtrMacro macro _) =
- returnUs (\xs -> StComment macro : xs)
+ gencode (CCallProfCtrMacro macro _)
+ = returnUs (\xs -> StComment macro : xs)
- gencode (CCallProfCCMacro macro _) =
- returnUs (\xs -> StComment macro : xs)
+ gencode (CCallProfCCMacro macro _)
+ = returnUs (\xs -> StComment macro : xs)
\end{code}
{-
mkSimpleSwitches
- :: Target
- -> CAddrMode -> [(Literal,AbstractC)] -> AbstractC
+ :: CAddrMode -> [(Literal,AbstractC)] -> AbstractC
-> UniqSM StixTreeList
-}
- mkSimpleSwitches am alts absC =
- getUniqLabelNCG `thenUs` \ udlbl ->
+ mkSimpleSwitches am alts absC
+ = getUniqLabelNCG `thenUs` \ udlbl ->
getUniqLabelNCG `thenUs` \ ujlbl ->
let am' = a2stix am
joinedAlts = map (\ (tag,code) -> (tag, mkJoin code ujlbl)) alts
-- lowest and highest possible values the discriminant could take
lowest = if floating then targetMinDouble else targetMinInt
highest = if floating then targetMaxDouble else targetMaxInt
-
- -- These should come from somewhere else, depending on the target arch
- -- (Note that the floating point values aren't terribly important.)
- -- ToDo: Fix!(JSM)
- targetMinDouble = MachDouble (-1.7976931348623157e+308)
- targetMaxDouble = MachDouble (1.7976931348623157e+308)
- targetMinInt = mkMachInt (-2147483647)
- targetMaxInt = mkMachInt 2147483647
in
(
if not floating && choices > 4 && highTag - lowTag < toInteger (2 * choices) then
\end{code}
-We use jump tables when doing an integer switch on a relatively dense list of
-alternatives. We expect to be given a list of alternatives, sorted by tag,
-and a range of values for which we are to generate a table. Of course, the tags of
-the alternatives should lie within the indicated range. The alternatives need
-not cover the range; a default target is provided for the missing alternatives.
+We use jump tables when doing an integer switch on a relatively dense
+list of alternatives. We expect to be given a list of alternatives,
+sorted by tag, and a range of values for which we are to generate a
+table. Of course, the tags of the alternatives should lie within the
+indicated range. The alternatives need not cover the range; a default
+target is provided for the missing alternatives.
-If a join is necessary after the switch, the alternatives should already finish
-with a jump to the join point.
+If a join is necessary after the switch, the alternatives should
+already finish with a jump to the join point.
\begin{code}
{-
mkJumpTable
- :: Target
- -> StixTree -- discriminant
+ :: StixTree -- discriminant
-> [(Literal, AbstractC)] -- alternatives
-> Integer -- low tag
-> Integer -- high tag
-> UniqSM StixTreeList
-}
- mkJumpTable am alts lowTag highTag dflt =
- getUniqLabelNCG `thenUs` \ utlbl ->
+ mkJumpTable am alts lowTag highTag dflt
+ = getUniqLabelNCG `thenUs` \ utlbl ->
mapUs genLabel alts `thenUs` \ branches ->
let cjmpLo = StCondJump dflt (StPrim IntLtOp [am, StInt lowTag])
cjmpHi = StCondJump dflt (StPrim IntGtOp [am, StInt highTag])
\begin{code}
{-
mkBinaryTree
- :: Target
- -> StixTree -- discriminant
+ :: StixTree -- discriminant
-> Bool -- floating point?
-> [(Literal, AbstractC)] -- alternatives
-> Int -- number of choices
mkBinaryTree am floating [(tag,alt)] _ lowTag highTag udlbl
| rangeOfOne = gencode alt
- | otherwise =
- let tag' = a2stix (CLit tag)
+ | otherwise
+ = let tag' = a2stix (CLit tag)
cmpOp = if floating then DoubleNeOp else IntNeOp
test = StPrim cmpOp [am, tag']
cjmp = StCondJump udlbl test
rangeOfOne = not floating && intTag lowTag + 1 >= intTag highTag
-- When there is only one possible tag left in range, we skip the comparison
- mkBinaryTree am floating alts choices lowTag highTag udlbl =
- getUniqLabelNCG `thenUs` \ uhlbl ->
+ mkBinaryTree am floating alts choices lowTag highTag udlbl
+ = getUniqLabelNCG `thenUs` \ uhlbl ->
let tag' = a2stix (CLit splitTag)
cmpOp = if floating then DoubleGeOp else IntGeOp
test = StPrim cmpOp [am, tag']
\begin{code}
{-
mkIfThenElse
- :: Target
- -> CAddrMode -- discriminant
+ :: CAddrMode -- discriminant
-> Literal -- tag
-> AbstractC -- if-part
-> AbstractC -- else-part
-> UniqSM StixTreeList
-}
- mkIfThenElse discrim tag alt deflt =
- getUniqLabelNCG `thenUs` \ ujlbl ->
+ mkIfThenElse discrim tag alt deflt
+ = getUniqLabelNCG `thenUs` \ ujlbl ->
getUniqLabelNCG `thenUs` \ utlbl ->
let discrim' = a2stix discrim
tag' = a2stix (CLit tag)
ft _ if_empty = if_empty
{- Old algorithm, which called nonemptyAbsC for every subexpression! =========
-fallThroughAbsC (AbsCStmts c1 c2) =
- case nonemptyAbsC c2 of
+fallThroughAbsC (AbsCStmts c1 c2)
+ = case nonemptyAbsC c2 of
Nothing -> fallThroughAbsC c1
Just x -> fallThroughAbsC x
fallThroughAbsC (CJump _) = False
+++ /dev/null
-%
-% (c) The AQUA Project, Glasgow University, 1993-1995
-%
-
-\section[AlphaCode]{The Native (Alpha) Machine Code}
-
-\begin{code}
-#include "HsVersions.h"
-
-module AlphaCode (
- Addr(..),Cond(..),Imm(..),RI(..),Size(..),
- AlphaCode(..),AlphaInstr(..),AlphaRegs,
- strImmLab,
-
- printLabeledCodes,
-
- baseRegOffset, stgRegMap, callerSaves,
-
- kindToSize,
-
- v0, f0, sp, ra, pv, gp, zero, argRegs,
-
- freeRegs, reservedRegs
-
- -- and, for self-sufficiency ...
- ) where
-
-IMPORT_Trace
-
-import AbsCSyn ( MagicId(..) )
-import AsmRegAlloc ( MachineCode(..), MachineRegisters(..), FutureLive(..),
- Reg(..), RegUsage(..), RegLiveness(..)
- )
-import BitSet
-import CLabel ( CLabel, pprCLabel, externallyVisibleCLabel, charToC )
-import CgCompInfo ( mAX_Double_REG, mAX_Float_REG, mAX_Vanilla_REG )
-import FiniteMap
-import Maybes ( Maybe(..), maybeToBool )
-import OrdList ( OrdList, mkUnitList, flattenOrdList )
-import Outputable
-import PrimRep ( PrimRep(..) )
-import UniqSet
-import Stix
-import Unpretty
-import Util
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[AlphaReg]{The Native (Alpha) Machine Register Table}
-%* *
-%************************************************************************
-
-The alpha has 64 registers of interest; 32 integer registers and 32 floating
-point registers. The mapping of STG registers to alpha machine registers
-is defined in StgRegs.h. We are, of course, prepared for any eventuality.
-
-\begin{code}
-
-fReg :: Int -> Int
-fReg x = (32 + x)
-
-v0, f0, ra, pv, gp, sp, zero :: Reg
-v0 = realReg 0
-f0 = realReg (fReg 0)
-ra = FixedReg ILIT(26)
-pv = t12
-gp = FixedReg ILIT(29)
-sp = FixedReg ILIT(30)
-zero = FixedReg ILIT(31)
-
-t9, t10, t11, t12 :: Reg
-t9 = realReg 23
-t10 = realReg 24
-t11 = realReg 25
-t12 = realReg 27
-
-argRegs :: [(Reg, Reg)]
-argRegs = [(realReg i, realReg (fReg i)) | i <- [16..21]]
-
-realReg :: Int -> Reg
-realReg n@IBOX(i) = if _IS_TRUE_(freeReg i) then MappedReg i else FixedReg i
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[TheAlphaCode]{The datatype for alpha assembly language}
-%* *
-%************************************************************************
-
-Here is a definition of the Alpha assembly language.
-
-\begin{code}
-
-data Imm = ImmInt Int
- | ImmInteger Integer -- Sigh.
- | ImmCLbl CLabel -- AbstractC Label (with baggage)
- | ImmLab Unpretty -- Simple string label
- deriving ()
-
-strImmLab s = ImmLab (uppStr s)
-
-data Addr = AddrImm Imm
- | AddrReg Reg
- | AddrRegImm Reg Imm
- deriving ()
-
-data Cond = EQ -- For CMP and BI
- | LT -- For CMP and BI
- | LE -- For CMP and BI
- | ULT -- For CMP only
- | ULE -- For CMP only
- | NE -- For BI only
- | GT -- For BI only
- | GE -- For BI only
- | ALWAYS -- For BI (same as BR)
- | NEVER -- For BI (null instruction)
- deriving ()
-
-data RI = RIReg Reg
- | RIImm Imm
- deriving ()
-
-data Size = B
- | BU
- | W
- | WU
- | L
- | Q
- | FF
- | DF
- | GF
- | SF
- | TF
- deriving ()
-
-data AlphaInstr =
-
--- Loads and stores.
-
- LD Size Reg Addr -- size, dst, src
- | LDA Reg Addr -- dst, src
- | LDAH Reg Addr -- dst, src
- | LDGP Reg Addr -- dst, src
- | LDI Size Reg Imm -- size, dst, src
- | ST Size Reg Addr -- size, src, dst
-
--- Int Arithmetic.
-
- | CLR Reg -- dst
- | ABS Size RI Reg -- size, src, dst
- | NEG Size Bool RI Reg -- size, overflow, src, dst
- | ADD Size Bool Reg RI Reg -- size, overflow, src, src, dst
- | SADD Size Size Reg RI Reg -- size, scale, src, src, dst
- | SUB Size Bool Reg RI Reg -- size, overflow, src, src, dst
- | SSUB Size Size Reg RI Reg -- size, scale, src, src, dst
- | MUL Size Bool Reg RI Reg -- size, overflow, src, src, dst
- | DIV Size Bool Reg RI Reg -- size, unsigned, src, src, dst
- | REM Size Bool Reg RI Reg -- size, unsigned, src, src, dst
-
--- Simple bit-twiddling.
-
- | NOT RI Reg
- | AND Reg RI Reg
- | ANDNOT Reg RI Reg
- | OR Reg RI Reg
- | ORNOT Reg RI Reg
- | XOR Reg RI Reg
- | XORNOT Reg RI Reg
- | SLL Reg RI Reg
- | SRL Reg RI Reg
- | SRA Reg RI Reg
-
- | ZAP Reg RI Reg
- | ZAPNOT Reg RI Reg
-
- | NOP
-
--- Comparison
-
- | CMP Cond Reg RI Reg
-
--- Float Arithmetic.
-
- | FCLR Reg
- | FABS Reg Reg
- | FNEG Size Reg Reg
- | FADD Size Reg Reg Reg
- | FDIV Size Reg Reg Reg
- | FMUL Size Reg Reg Reg
- | FSUB Size Reg Reg Reg
- | CVTxy Size Size Reg Reg
- | FCMP Size Cond Reg Reg Reg
- | FMOV Reg Reg
-
--- Jumping around.
-
- | BI Cond Reg Imm
- | BF Cond Reg Imm
- | BR Imm
- | JMP Reg Addr Int
- | BSR Imm Int
- | JSR Reg Addr Int
-
--- Pseudo-ops.
-
- | LABEL CLabel
- | FUNBEGIN CLabel
- | FUNEND CLabel
- | COMMENT FAST_STRING
- | SEGMENT CodeSegment
- | ASCII Bool String -- needs backslash conversion?
- | DATA Size [Imm]
-
-type AlphaCode = OrdList AlphaInstr
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[TheAlphaPretty]{Pretty-printing the Alpha Assembly Language}
-%* *
-%************************************************************************
-
-\begin{code}
-
-printLabeledCodes :: PprStyle -> [AlphaInstr] -> Unpretty
-printLabeledCodes sty codes = uppAboves (map (pprAlphaInstr sty) codes)
-
-\end{code}
-
-Printing the pieces...
-
-\begin{code}
-
-pprReg :: Reg -> Unpretty
-
-pprReg (FixedReg i) = pprAlphaReg i
-pprReg (MappedReg i) = pprAlphaReg i
-pprReg other = uppStr (show other) -- should only happen when debugging
-
-pprAlphaReg :: FAST_INT -> Unpretty
-pprAlphaReg i = uppPStr
- (case i of {
- ILIT( 0) -> SLIT("$0"); ILIT( 1) -> SLIT("$1");
- ILIT( 2) -> SLIT("$2"); ILIT( 3) -> SLIT("$3");
- ILIT( 4) -> SLIT("$4"); ILIT( 5) -> SLIT("$5");
- ILIT( 6) -> SLIT("$6"); ILIT( 7) -> SLIT("$7");
- ILIT( 8) -> SLIT("$8"); ILIT( 9) -> SLIT("$9");
- ILIT(10) -> SLIT("$10"); ILIT(11) -> SLIT("$11");
- ILIT(12) -> SLIT("$12"); ILIT(13) -> SLIT("$13");
- ILIT(14) -> SLIT("$14"); ILIT(15) -> SLIT("$15");
- ILIT(16) -> SLIT("$16"); ILIT(17) -> SLIT("$17");
- ILIT(18) -> SLIT("$18"); ILIT(19) -> SLIT("$19");
- ILIT(20) -> SLIT("$20"); ILIT(21) -> SLIT("$21");
- ILIT(22) -> SLIT("$22"); ILIT(23) -> SLIT("$23");
- ILIT(24) -> SLIT("$24"); ILIT(25) -> SLIT("$25");
- ILIT(26) -> SLIT("$26"); ILIT(27) -> SLIT("$27");
- ILIT(28) -> SLIT("$28"); ILIT(29) -> SLIT("$29");
- ILIT(30) -> SLIT("$30"); ILIT(31) -> SLIT("$31");
- ILIT(32) -> SLIT("$f0"); ILIT(33) -> SLIT("$f1");
- ILIT(34) -> SLIT("$f2"); ILIT(35) -> SLIT("$f3");
- ILIT(36) -> SLIT("$f4"); ILIT(37) -> SLIT("$f5");
- ILIT(38) -> SLIT("$f6"); ILIT(39) -> SLIT("$f7");
- ILIT(40) -> SLIT("$f8"); ILIT(41) -> SLIT("$f9");
- ILIT(42) -> SLIT("$f10"); ILIT(43) -> SLIT("$f11");
- ILIT(44) -> SLIT("$f12"); ILIT(45) -> SLIT("$f13");
- ILIT(46) -> SLIT("$f14"); ILIT(47) -> SLIT("$f15");
- ILIT(48) -> SLIT("$f16"); ILIT(49) -> SLIT("$f17");
- ILIT(50) -> SLIT("$f18"); ILIT(51) -> SLIT("$f19");
- ILIT(52) -> SLIT("$f20"); ILIT(53) -> SLIT("$f21");
- ILIT(54) -> SLIT("$f22"); ILIT(55) -> SLIT("$f23");
- ILIT(56) -> SLIT("$f24"); ILIT(57) -> SLIT("$f25");
- ILIT(58) -> SLIT("$f26"); ILIT(59) -> SLIT("$f27");
- ILIT(60) -> SLIT("$f28"); ILIT(61) -> SLIT("$f29");
- ILIT(62) -> SLIT("$f30"); ILIT(63) -> SLIT("$f31");
- _ -> SLIT("very naughty alpha register")
- })
-
-pprCond :: Cond -> Unpretty
-pprCond EQ = uppPStr SLIT("eq")
-pprCond LT = uppPStr SLIT("lt")
-pprCond LE = uppPStr SLIT("le")
-pprCond ULT = uppPStr SLIT("ult")
-pprCond ULE = uppPStr SLIT("ule")
-pprCond NE = uppPStr SLIT("ne")
-pprCond GT = uppPStr SLIT("gt")
-pprCond GE = uppPStr SLIT("ge")
-
-pprImm :: PprStyle -> Imm -> Unpretty
-
-pprImm sty (ImmInt i) = uppInt i
-pprImm sty (ImmInteger i) = uppInteger i
-
-pprImm sty (ImmCLbl l) = pprCLabel sty l
-
-pprImm sty (ImmLab s) = s
-
-pprAddr :: PprStyle -> Addr -> Unpretty
-pprAddr sty (AddrReg reg) = uppBesides [uppLparen, pprReg reg, uppRparen]
-
-pprAddr sty (AddrImm imm) = pprImm sty imm
-
-pprAddr sty (AddrRegImm r1 imm) =
- uppBesides [
- pprImm sty imm,
- uppLparen,
- pprReg r1,
- uppRparen
- ]
-
-pprRI :: PprStyle -> RI -> Unpretty
-pprRI sty (RIReg r) = pprReg r
-pprRI sty (RIImm r) = pprImm sty r
-
-pprRegRIReg :: PprStyle -> FAST_STRING -> Reg -> RI -> Reg -> Unpretty
-pprRegRIReg sty name reg1 ri reg2 =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- uppChar '\t',
- pprReg reg1,
- uppComma,
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
-
-pprSizeRegRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Reg -> Unpretty
-pprSizeRegRegReg name size reg1 reg2 reg3 =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- pprSize size,
- uppChar '\t',
- pprReg reg1,
- uppComma,
- pprReg reg2,
- uppComma,
- pprReg reg3
- ]
-
-pprSize :: Size -> Unpretty
-pprSize x = uppPStr
- (case x of
- B -> SLIT("b")
- BU -> SLIT("bu")
- W -> SLIT("w")
- WU -> SLIT("wu")
- L -> SLIT("l")
- Q -> SLIT("q")
- FF -> SLIT("f")
- DF -> SLIT("d")
- GF -> SLIT("g")
- SF -> SLIT("s")
- TF -> SLIT("t")
- )
-
-pprAlphaInstr :: PprStyle -> AlphaInstr -> Unpretty
-
-pprAlphaInstr sty (LD size reg addr) =
- uppBesides [
- uppPStr SLIT("\tld"),
- pprSize size,
- uppChar '\t',
- pprReg reg,
- uppComma,
- pprAddr sty addr
- ]
-
-pprAlphaInstr sty (LDA reg addr) =
- uppBesides [
- uppPStr SLIT("\tlda\t"),
- pprReg reg,
- uppComma,
- pprAddr sty addr
- ]
-
-pprAlphaInstr sty (LDAH reg addr) =
- uppBesides [
- uppPStr SLIT("\tldah\t"),
- pprReg reg,
- uppComma,
- pprAddr sty addr
- ]
-
-pprAlphaInstr sty (LDGP reg addr) =
- uppBesides [
- uppPStr SLIT("\tldgp\t"),
- pprReg reg,
- uppComma,
- pprAddr sty addr
- ]
-
-pprAlphaInstr sty (LDI size reg imm) =
- uppBesides [
- uppPStr SLIT("\tldi"),
- pprSize size,
- uppChar '\t',
- pprReg reg,
- uppComma,
- pprImm sty imm
- ]
-
-pprAlphaInstr sty (ST size reg addr) =
- uppBesides [
- uppPStr SLIT("\tst"),
- pprSize size,
- uppChar '\t',
- pprReg reg,
- uppComma,
- pprAddr sty addr
- ]
-
-pprAlphaInstr sty (CLR reg) =
- uppBesides [
- uppPStr SLIT("\tclr\t"),
- pprReg reg
- ]
-
-pprAlphaInstr sty (ABS size ri reg) =
- uppBesides [
- uppPStr SLIT("\tabs"),
- pprSize size,
- uppChar '\t',
- pprRI sty ri,
- uppComma,
- pprReg reg
- ]
-
-pprAlphaInstr sty (NEG size ov ri reg) =
- uppBesides [
- uppPStr SLIT("\tneg"),
- pprSize size,
- if ov then uppPStr SLIT("v\t") else uppChar '\t',
- pprRI sty ri,
- uppComma,
- pprReg reg
- ]
-
-pprAlphaInstr sty (ADD size ov reg1 ri reg2) =
- uppBesides [
- uppPStr SLIT("\tadd"),
- pprSize size,
- if ov then uppPStr SLIT("v\t") else uppChar '\t',
- pprReg reg1,
- uppComma,
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (SADD size scale reg1 ri reg2) =
- uppBesides [
- uppPStr (case scale of {L -> SLIT("\ts4"); Q -> SLIT("\ts8")}),
- uppPStr SLIT("add"),
- pprSize size,
- uppChar '\t',
- pprReg reg1,
- uppComma,
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (SUB size ov reg1 ri reg2) =
- uppBesides [
- uppPStr SLIT("\tsub"),
- pprSize size,
- if ov then uppPStr SLIT("v\t") else uppChar '\t',
- pprReg reg1,
- uppComma,
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (SSUB size scale reg1 ri reg2) =
- uppBesides [
- uppPStr (case scale of {L -> SLIT("\ts4"); Q -> SLIT("\ts8")}),
- uppPStr SLIT("sub"),
- pprSize size,
- uppChar '\t',
- pprReg reg1,
- uppComma,
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (MUL size ov reg1 ri reg2) =
- uppBesides [
- uppPStr SLIT("\tmul"),
- pprSize size,
- if ov then uppPStr SLIT("v\t") else uppChar '\t',
- pprReg reg1,
- uppComma,
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (DIV size uns reg1 ri reg2) =
- uppBesides [
- uppPStr SLIT("\tdiv"),
- pprSize size,
- if uns then uppPStr SLIT("u\t") else uppChar '\t',
- pprReg reg1,
- uppComma,
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (REM size uns reg1 ri reg2) =
- uppBesides [
- uppPStr SLIT("\trem"),
- pprSize size,
- if uns then uppPStr SLIT("u\t") else uppChar '\t',
- pprReg reg1,
- uppComma,
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (NOT ri reg) =
- uppBesides [
- uppPStr SLIT("\tnot"),
- uppChar '\t',
- pprRI sty ri,
- uppComma,
- pprReg reg
- ]
-
-pprAlphaInstr sty (AND reg1 ri reg2) = pprRegRIReg sty SLIT("and") reg1 ri reg2
-pprAlphaInstr sty (ANDNOT reg1 ri reg2) = pprRegRIReg sty SLIT("andnot") reg1 ri reg2
-pprAlphaInstr sty (OR reg1 ri reg2) = pprRegRIReg sty SLIT("or") reg1 ri reg2
-pprAlphaInstr sty (ORNOT reg1 ri reg2) = pprRegRIReg sty SLIT("ornot") reg1 ri reg2
-pprAlphaInstr sty (XOR reg1 ri reg2) = pprRegRIReg sty SLIT("xor") reg1 ri reg2
-pprAlphaInstr sty (XORNOT reg1 ri reg2) = pprRegRIReg sty SLIT("xornot") reg1 ri reg2
-
-pprAlphaInstr sty (SLL reg1 ri reg2) = pprRegRIReg sty SLIT("sll") reg1 ri reg2
-pprAlphaInstr sty (SRL reg1 ri reg2) = pprRegRIReg sty SLIT("srl") reg1 ri reg2
-pprAlphaInstr sty (SRA reg1 ri reg2) = pprRegRIReg sty SLIT("sra") reg1 ri reg2
-
-pprAlphaInstr sty (ZAP reg1 ri reg2) = pprRegRIReg sty SLIT("zap") reg1 ri reg2
-pprAlphaInstr sty (ZAPNOT reg1 ri reg2) = pprRegRIReg sty SLIT("zapnot") reg1 ri reg2
-
-pprAlphaInstr sty (NOP) = uppPStr SLIT("\tnop")
-
-pprAlphaInstr sty (CMP cond reg1 ri reg2) =
- uppBesides [
- uppPStr SLIT("\tcmp"),
- pprCond cond,
- uppChar '\t',
- pprReg reg1,
- uppComma,
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (FCLR reg) =
- uppBesides [
- uppPStr SLIT("\tfclr\t"),
- pprReg reg
- ]
-
-pprAlphaInstr sty (FABS reg1 reg2) =
- uppBesides [
- uppPStr SLIT("\tfabs\t"),
- pprReg reg1,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (FNEG size reg1 reg2) =
- uppBesides [
- uppPStr SLIT("\tneg"),
- pprSize size,
- uppChar '\t',
- pprReg reg1,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (FADD size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("add") size reg1 reg2 reg3
-pprAlphaInstr sty (FDIV size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("div") size reg1 reg2 reg3
-pprAlphaInstr sty (FMUL size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("mul") size reg1 reg2 reg3
-pprAlphaInstr sty (FSUB size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("sub") size reg1 reg2 reg3
-
-pprAlphaInstr sty (CVTxy size1 size2 reg1 reg2) =
- uppBesides [
- uppPStr SLIT("\tcvt"),
- pprSize size1,
- case size2 of {Q -> uppPStr SLIT("qc"); _ -> pprSize size2},
- uppChar '\t',
- pprReg reg1,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (FCMP size cond reg1 reg2 reg3) =
- uppBesides [
- uppPStr SLIT("\tcmp"),
- pprSize size,
- pprCond cond,
- uppChar '\t',
- pprReg reg1,
- uppComma,
- pprReg reg2,
- uppComma,
- pprReg reg3
- ]
-
-pprAlphaInstr sty (FMOV reg1 reg2) =
- uppBesides [
- uppPStr SLIT("\tfmov\t"),
- pprReg reg1,
- uppComma,
- pprReg reg2
- ]
-
-pprAlphaInstr sty (BI ALWAYS reg lab) = pprAlphaInstr sty (BR lab)
-
-pprAlphaInstr sty (BI NEVER reg lab) = uppNil
-
-pprAlphaInstr sty (BI cond reg lab) =
- uppBesides [
- uppPStr SLIT("\tb"),
- pprCond cond,
- uppChar '\t',
- pprReg reg,
- uppComma,
- pprImm sty lab
- ]
-
-pprAlphaInstr sty (BF cond reg lab) =
- uppBesides [
- uppPStr SLIT("\tfb"),
- pprCond cond,
- uppChar '\t',
- pprReg reg,
- uppComma,
- pprImm sty lab
- ]
-
-pprAlphaInstr sty (BR lab) =
- uppBeside (uppPStr SLIT("\tbr\t")) (pprImm sty lab)
-
-pprAlphaInstr sty (JMP reg addr hint) =
- uppBesides [
- uppPStr SLIT("\tjmp\t"),
- pprReg reg,
- uppComma,
- pprAddr sty addr,
- uppComma,
- uppInt hint
- ]
-
-pprAlphaInstr sty (BSR imm n) =
- uppBeside (uppPStr SLIT("\tbsr\t")) (pprImm sty imm)
-
-pprAlphaInstr sty (JSR reg addr n) =
- uppBesides [
- uppPStr SLIT("\tjsr\t"),
- pprReg reg,
- uppComma,
- pprAddr sty addr
- ]
-
-pprAlphaInstr sty (LABEL clab) =
- uppBesides [
- if (externallyVisibleCLabel clab) then
- uppBesides [uppPStr SLIT("\t.globl\t"), pprLab, uppChar '\n']
- else
- uppNil,
- pprLab,
- uppChar ':'
- ]
- where pprLab = pprCLabel sty clab
-
-pprAlphaInstr sty (FUNBEGIN clab) =
- uppBesides [
- if (externallyVisibleCLabel clab) then
- uppBesides [uppPStr SLIT("\t.globl\t"), pprLab, uppChar '\n']
- else
- uppNil,
- uppPStr SLIT("\t.ent "),
- pprLab,
- uppChar '\n',
- pprLab,
- pp_ldgp,
- pprLab,
- pp_frame
- ]
- where
- pprLab = pprCLabel sty clab
-#ifdef USE_FAST_STRINGS
- pp_ldgp = uppPStr (_packCString (A# ":\n\tldgp $29,0($27)\n"#))
- pp_frame = uppPStr (_packCString (A# "..ng:\n\t.frame $30,4240,$26,0\n\t.prologue 1"#))
-#else
- pp_ldgp = uppStr ":\n\tldgp $29,0($27)\n"
- pp_frame = uppStr "..ng:\n\t.frame $30,4240,$26,0\n\t.prologue 1"
-#endif
-
-pprAlphaInstr sty (FUNEND clab) =
- uppBeside (uppPStr SLIT("\t.align 4\n\t.end ")) (pprCLabel sty clab)
-
-pprAlphaInstr sty (COMMENT s) = uppBeside (uppPStr SLIT("\t# ")) (uppPStr s)
-
-pprAlphaInstr sty (SEGMENT TextSegment)
- = uppPStr SLIT("\t.text\n\t.align 3")
-
-pprAlphaInstr sty (SEGMENT DataSegment)
- = uppPStr SLIT("\t.data\n\t.align 3")
-
-pprAlphaInstr sty (ASCII False str) =
- uppBesides [
- uppStr "\t.asciz \"",
- uppStr str,
- uppChar '"'
- ]
-
-pprAlphaInstr sty (ASCII True str) = uppBeside (uppStr "\t.ascii \"") (asciify str 60)
- where
- asciify :: String -> Int -> Unpretty
- asciify [] _ = uppStr ("\\0\"")
- asciify s n | n <= 0 = uppBeside (uppStr "\"\n\t.ascii \"") (asciify s 60)
- asciify ('\\':cs) n = uppBeside (uppStr "\\\\") (asciify cs (n-1))
- asciify ('\"':cs) n = uppBeside (uppStr "\\\"") (asciify cs (n-1))
- asciify (c:cs) n | isPrint c = uppBeside (uppChar c) (asciify cs (n-1))
- asciify [c] _ = uppBeside (uppStr (charToC c)) (uppStr ("\\0\""))
- asciify (c:(cs@(d:_))) n | isDigit d =
- uppBeside (uppStr (charToC c)) (asciify cs 0)
- | otherwise =
- uppBeside (uppStr (charToC c)) (asciify cs (n-1))
-
-pprAlphaInstr sty (DATA s xs) = uppInterleave (uppChar '\n') (map pp_item xs)
- where pp_item x = case s of
- B -> uppBeside (uppPStr SLIT("\t.byte\t")) (pprImm sty x)
- BU -> uppBeside (uppPStr SLIT("\t.byte\t")) (pprImm sty x)
- W -> uppBeside (uppPStr SLIT("\t.word\t")) (pprImm sty x)
- WU -> uppBeside (uppPStr SLIT("\t.word\t")) (pprImm sty x)
- L -> uppBeside (uppPStr SLIT("\t.long\t")) (pprImm sty x)
- Q -> uppBeside (uppPStr SLIT("\t.quad\t")) (pprImm sty x)
- FF -> uppBeside (uppPStr SLIT("\t.f_floating\t")) (pprImm sty x)
- DF -> uppBeside (uppPStr SLIT("\t.d_floating\t")) (pprImm sty x)
- GF -> uppBeside (uppPStr SLIT("\t.g_floating\t")) (pprImm sty x)
- SF -> uppBeside (uppPStr SLIT("\t.s_floating\t")) (pprImm sty x)
- TF -> uppBeside (uppPStr SLIT("\t.t_floating\t")) (pprImm sty x)
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[Schedule]{Register allocation information}
-%* *
-%************************************************************************
-
-\begin{code}
-
-data AlphaRegs = SRegs BitSet BitSet
-
-instance MachineRegisters AlphaRegs where
- mkMRegs xs = SRegs (mkBS ints) (mkBS floats')
- where
- (ints, floats) = partition (< 32) xs
- floats' = map (subtract 32) floats
-
- possibleMRegs FloatRep (SRegs _ floats) = [ x + 32 | x <- listBS floats]
- possibleMRegs DoubleRep (SRegs _ floats) = [ x + 32 | x <- listBS floats]
- possibleMRegs _ (SRegs ints _) = listBS ints
-
- useMReg (SRegs ints floats) n =
- if n _LT_ ILIT(32) then SRegs (ints `minusBS` singletonBS IBOX(n)) floats
- else SRegs ints (floats `minusBS` singletonBS (IBOX(n _SUB_ ILIT(32))))
-
- useMRegs (SRegs ints floats) xs =
- SRegs (ints `minusBS` ints')
- (floats `minusBS` floats')
- where
- SRegs ints' floats' = mkMRegs xs
-
- freeMReg (SRegs ints floats) n =
- if n _LT_ ILIT(32) then SRegs (ints `unionBS` singletonBS IBOX(n)) floats
- else SRegs ints (floats `unionBS` singletonBS (IBOX(n _SUB_ ILIT(32))))
-
- freeMRegs (SRegs ints floats) xs =
- SRegs (ints `unionBS` ints')
- (floats `unionBS` floats')
- where
- SRegs ints' floats' = mkMRegs xs
-
-instance MachineCode AlphaInstr where
- regUsage = alphaRegUsage
- regLiveness = alphaRegLiveness
- patchRegs = alphaPatchRegs
-
- -- We spill just below the frame pointer, leaving two words per spill location.
- spillReg dyn (MemoryReg i pk) = mkUnitList (ST (kindToSize pk) dyn (spRel i))
- loadReg (MemoryReg i pk) dyn = mkUnitList (LD (kindToSize pk) dyn (spRel i))
-
-spRel :: Int -> Addr
-spRel n = AddrRegImm sp (ImmInt (n * 8))
-
-kindToSize :: PrimRep -> Size
-kindToSize PtrRep = Q
-kindToSize CodePtrRep = Q
-kindToSize DataPtrRep = Q
-kindToSize RetRep = Q
-kindToSize CostCentreRep = Q
-kindToSize CharRep = BU
-kindToSize IntRep = Q
-kindToSize WordRep = Q
-kindToSize AddrRep = Q
-kindToSize FloatRep = TF
-kindToSize DoubleRep = TF
-kindToSize ArrayRep = Q
-kindToSize ByteArrayRep = Q
-kindToSize StablePtrRep = Q
-kindToSize MallocPtrRep = Q
-
-\end{code}
-
-@alphaRegUsage@ returns the sets of src and destination registers used by
-a particular instruction. Machine registers that are pre-allocated
-to stgRegs are filtered out, because they are uninteresting from a
-register allocation standpoint. (We wouldn't want them to end up on
-the free list!)
-
-\begin{code}
-
-alphaRegUsage :: AlphaInstr -> RegUsage
-alphaRegUsage instr = case instr of
- LD B reg addr -> usage (regAddr addr, [reg, t9])
- LD BU reg addr -> usage (regAddr addr, [reg, t9])
- LD W reg addr -> usage (regAddr addr, [reg, t9])
- LD WU reg addr -> usage (regAddr addr, [reg, t9])
- LD sz reg addr -> usage (regAddr addr, [reg])
- LDA reg addr -> usage (regAddr addr, [reg])
- LDAH reg addr -> usage (regAddr addr, [reg])
- LDGP reg addr -> usage (regAddr addr, [reg])
- LDI sz reg imm -> usage ([], [reg])
- ST B reg addr -> usage (reg : regAddr addr, [t9, t10])
- ST W reg addr -> usage (reg : regAddr addr, [t9, t10])
- ST sz reg addr -> usage (reg : regAddr addr, [])
- CLR reg -> usage ([], [reg])
- ABS sz ri reg -> usage (regRI ri, [reg])
- NEG sz ov ri reg -> usage (regRI ri, [reg])
- ADD sz ov r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SADD sz sc r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SUB sz ov r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SSUB sz sc r1 ar r2 -> usage (r1 : regRI ar, [r2])
- MUL sz ov r1 ar r2 -> usage (r1 : regRI ar, [r2])
- DIV sz un r1 ar r2 -> usage (r1 : regRI ar, [r2, t9, t10, t11, t12])
- REM sz un r1 ar r2 -> usage (r1 : regRI ar, [r2, t9, t10, t11, t12])
- NOT ri reg -> usage (regRI ri, [reg])
- AND r1 ar r2 -> usage (r1 : regRI ar, [r2])
- ANDNOT r1 ar r2 -> usage (r1 : regRI ar, [r2])
- OR r1 ar r2 -> usage (r1 : regRI ar, [r2])
- ORNOT r1 ar r2 -> usage (r1 : regRI ar, [r2])
- XOR r1 ar r2 -> usage (r1 : regRI ar, [r2])
- XORNOT r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SLL r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SRL r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SRA r1 ar r2 -> usage (r1 : regRI ar, [r2])
- ZAP r1 ar r2 -> usage (r1 : regRI ar, [r2])
- ZAPNOT r1 ar r2 -> usage (r1 : regRI ar, [r2])
- CMP co r1 ar r2 -> usage (r1 : regRI ar, [r2])
- FCLR reg -> usage ([], [reg])
- FABS r1 r2 -> usage ([r1], [r2])
- FNEG sz r1 r2 -> usage ([r1], [r2])
- FADD sz r1 r2 r3 -> usage ([r1, r2], [r3])
- FDIV sz r1 r2 r3 -> usage ([r1, r2], [r3])
- FMUL sz r1 r2 r3 -> usage ([r1, r2], [r3])
- FSUB sz r1 r2 r3 -> usage ([r1, r2], [r3])
- CVTxy sz1 sz2 r1 r2 -> usage ([r1], [r2])
- FCMP sz co r1 r2 r3 -> usage ([r1, r2], [r3])
- FMOV r1 r2 -> usage ([r1], [r2])
-
-
- -- We assume that all local jumps will be BI/BF/BR. JMP must be out-of-line.
- BI cond reg lbl -> usage ([reg], [])
- BF cond reg lbl -> usage ([reg], [])
- JMP reg addr hint -> RU (mkUniqSet (filter interesting (regAddr addr))) freeSet
-
- BSR _ n -> RU (argSet n) callClobberedSet
- JSR reg addr n -> RU (argSet n) callClobberedSet
-
- _ -> noUsage
-
- where
- usage (src, dst) = RU (mkUniqSet (filter interesting src))
- (mkUniqSet (filter interesting dst))
-
- interesting (FixedReg _) = False
- interesting _ = True
-
- regAddr (AddrReg r1) = [r1]
- regAddr (AddrRegImm r1 _) = [r1]
- regAddr (AddrImm _) = []
-
- regRI (RIReg r) = [r]
- regRI _ = []
-
-freeRegs :: [Reg]
-freeRegs = freeMappedRegs [0..63]
-
-freeMappedRegs :: [Int] -> [Reg]
-
-freeMappedRegs nums
- = foldr free [] nums
- where
- free IBOX(i) acc
- = if _IS_TRUE_(freeReg i) then (MappedReg i) : acc else acc
-
-freeSet :: UniqSet Reg
-freeSet = mkUniqSet freeRegs
-
-noUsage :: RegUsage
-noUsage = RU emptyUniqSet emptyUniqSet
-
--- Color me CAF-like
-argSet :: Int -> UniqSet Reg
-argSet 0 = emptyUniqSet
-argSet 1 = mkUniqSet (freeMappedRegs [16, fReg 16])
-argSet 2 = mkUniqSet (freeMappedRegs [16, 17, fReg 16, fReg 17])
-argSet 3 = mkUniqSet (freeMappedRegs [16, 17, 18, fReg 16, fReg 17, fReg 18])
-argSet 4 = mkUniqSet (freeMappedRegs [16, 17, 18, 19, fReg 16, fReg 17, fReg 18, fReg 19])
-argSet 5 = mkUniqSet (freeMappedRegs [16, 17, 18, 19, 20, fReg 16, fReg 17, fReg 18, fReg 19, fReg 20])
-argSet 6 = mkUniqSet (freeMappedRegs [16, 17, 18, 19, 20, 21, fReg 16, fReg 17, fReg 18, fReg 19, fReg 20, fReg 21])
-
-callClobberedSet :: UniqSet Reg
-callClobberedSet = mkUniqSet callClobberedRegs
- where
- callClobberedRegs
- = freeMappedRegs
- [0, 1, 2, 3, 4, 5, 6, 7, 8,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
- fReg 0, fReg 1, fReg 10, fReg 11, fReg 12, fReg 13, fReg 14, fReg 15,
- fReg 16, fReg 17, fReg 18, fReg 19, fReg 20, fReg 21, fReg 22, fReg 23,
- fReg 24, fReg 25, fReg 26, fReg 27, fReg 28, fReg 29, fReg 30]
-
-\end{code}
-
-@alphaRegLiveness@ takes future liveness information and modifies it according to
-the semantics of branches and labels. (An out-of-line branch clobbers the liveness
-passed back by the following instruction; a forward local branch passes back the
-liveness from the target label; a conditional branch merges the liveness from the
-target and the liveness from its successor; a label stashes away the current liveness
-in the future liveness environment).
-
-\begin{code}
-alphaRegLiveness :: AlphaInstr -> RegLiveness -> RegLiveness
-alphaRegLiveness instr info@(RL live future@(FL all env)) = case instr of
-
- -- We assume that all local jumps will be BI/BF. JMP must be out-of-line.
-
- BR (ImmCLbl lbl) -> RL (lookup lbl) future
- BI _ _ (ImmCLbl lbl) -> RL (lookup lbl `unionUniqSets` live) future
- BF _ _ (ImmCLbl lbl) -> RL (lookup lbl `unionUniqSets` live) future
- JMP _ _ _ -> RL emptyUniqSet future
- BSR _ _ -> RL live future
- JSR _ _ _ -> RL live future
- LABEL lbl -> RL live (FL (all `unionUniqSets` live) (addToFM env lbl live))
- _ -> info
-
- where
- lookup lbl = case lookupFM env lbl of
- Just regs -> regs
- Nothing -> trace ("Missing " ++ (uppShow 80 (pprCLabel (PprForAsm (\_->False) False id) lbl)) ++
- " in future?") emptyUniqSet
-
-\end{code}
-
-@alphaPatchRegs@ takes an instruction (possibly with
-MemoryReg/UnmappedReg registers) and changes all register references
-according to the supplied environment.
-
-\begin{code}
-
-alphaPatchRegs :: AlphaInstr -> (Reg -> Reg) -> AlphaInstr
-alphaPatchRegs instr env = case instr of
- LD sz reg addr -> LD sz (env reg) (fixAddr addr)
- LDA reg addr -> LDA (env reg) (fixAddr addr)
- LDAH reg addr -> LDAH (env reg) (fixAddr addr)
- LDGP reg addr -> LDGP (env reg) (fixAddr addr)
- LDI sz reg imm -> LDI sz (env reg) imm
- ST sz reg addr -> ST sz (env reg) (fixAddr addr)
- CLR reg -> CLR (env reg)
- ABS sz ar reg -> ABS sz (fixRI ar) (env reg)
- NEG sz ov ar reg -> NEG sz ov (fixRI ar) (env reg)
- ADD sz ov r1 ar r2 -> ADD sz ov (env r1) (fixRI ar) (env r2)
- SADD sz sc r1 ar r2 -> SADD sz sc (env r1) (fixRI ar) (env r2)
- SUB sz ov r1 ar r2 -> SUB sz ov (env r1) (fixRI ar) (env r2)
- SSUB sz sc r1 ar r2 -> SSUB sz sc (env r1) (fixRI ar) (env r2)
- MUL sz ov r1 ar r2 -> MUL sz ov (env r1) (fixRI ar) (env r2)
- DIV sz un r1 ar r2 -> DIV sz un (env r1) (fixRI ar) (env r2)
- REM sz un r1 ar r2 -> REM sz un (env r1) (fixRI ar) (env r2)
- NOT ar reg -> NOT (fixRI ar) (env reg)
- AND r1 ar r2 -> AND (env r1) (fixRI ar) (env r2)
- ANDNOT r1 ar r2 -> ANDNOT (env r1) (fixRI ar) (env r2)
- OR r1 ar r2 -> OR (env r1) (fixRI ar) (env r2)
- ORNOT r1 ar r2 -> ORNOT (env r1) (fixRI ar) (env r2)
- XOR r1 ar r2 -> XOR (env r1) (fixRI ar) (env r2)
- XORNOT r1 ar r2 -> XORNOT (env r1) (fixRI ar) (env r2)
- SLL r1 ar r2 -> SLL (env r1) (fixRI ar) (env r2)
- SRL r1 ar r2 -> SRL (env r1) (fixRI ar) (env r2)
- SRA r1 ar r2 -> SRA (env r1) (fixRI ar) (env r2)
- ZAP r1 ar r2 -> ZAP (env r1) (fixRI ar) (env r2)
- ZAPNOT r1 ar r2 -> ZAPNOT (env r1) (fixRI ar) (env r2)
- CMP co r1 ar r2 -> CMP co (env r1) (fixRI ar) (env r2)
- FCLR reg -> FCLR (env reg)
- FABS r1 r2 -> FABS (env r1) (env r2)
- FNEG s r1 r2 -> FNEG s (env r1) (env r2)
- FADD s r1 r2 r3 -> FADD s (env r1) (env r2) (env r3)
- FDIV s r1 r2 r3 -> FDIV s (env r1) (env r2) (env r3)
- FMUL s r1 r2 r3 -> FMUL s (env r1) (env r2) (env r3)
- FSUB s r1 r2 r3 -> FSUB s (env r1) (env r2) (env r3)
- CVTxy s1 s2 r1 r2 -> CVTxy s1 s2 (env r1) (env r2)
- FCMP s co r1 r2 r3 -> FCMP s co (env r1) (env r2) (env r3)
- FMOV r1 r2 -> FMOV (env r1) (env r2)
- BI cond reg lbl -> BI cond (env reg) lbl
- BF cond reg lbl -> BF cond (env reg) lbl
- JMP reg addr hint -> JMP (env reg) (fixAddr addr) hint
- JSR reg addr i -> JSR (env reg) (fixAddr addr) i
- _ -> instr
-
- where
- fixAddr (AddrReg r1) = AddrReg (env r1)
- fixAddr (AddrRegImm r1 i) = AddrRegImm (env r1) i
- fixAddr other = other
-
- fixRI (RIReg r) = RIReg (env r)
- fixRI other = other
-
-\end{code}
-
-If you value your sanity, do not venture below this line.
-
-\begin{code}
-
--- platform.h is generate and tells us what the target architecture is
-#include "../../includes/platform.h"
-#include "../../includes/MachRegs.h"
-#include "../../includes/alpha-dec-osf1.h"
-
--- Redefine the literals used for Alpha floating point register names
--- in the header files. Gag me with a spoon, eh?
-
-#define f0 32
-#define f1 33
-#define f2 34
-#define f3 35
-#define f4 36
-#define f5 37
-#define f6 38
-#define f7 39
-#define f8 40
-#define f9 41
-#define f10 42
-#define f11 43
-#define f12 44
-#define f13 45
-#define f14 46
-#define f15 47
-#define f16 48
-#define f17 49
-#define f18 50
-#define f19 51
-#define f20 52
-#define f21 53
-#define f22 54
-#define f23 55
-#define f24 56
-#define f25 57
-#define f26 58
-#define f27 59
-#define f28 60
-#define f29 61
-#define f30 62
-#define f31 63
-
-baseRegOffset :: MagicId -> Int
-baseRegOffset StkOReg = OFFSET_StkO
-baseRegOffset (VanillaReg _ ILIT(1)) = OFFSET_R1
-baseRegOffset (VanillaReg _ ILIT(2)) = OFFSET_R2
-baseRegOffset (VanillaReg _ ILIT(3)) = OFFSET_R3
-baseRegOffset (VanillaReg _ ILIT(4)) = OFFSET_R4
-baseRegOffset (VanillaReg _ ILIT(5)) = OFFSET_R5
-baseRegOffset (VanillaReg _ ILIT(6)) = OFFSET_R6
-baseRegOffset (VanillaReg _ ILIT(7)) = OFFSET_R7
-baseRegOffset (VanillaReg _ ILIT(8)) = OFFSET_R8
-baseRegOffset (FloatReg ILIT(1)) = OFFSET_Flt1
-baseRegOffset (FloatReg ILIT(2)) = OFFSET_Flt2
-baseRegOffset (FloatReg ILIT(3)) = OFFSET_Flt3
-baseRegOffset (FloatReg ILIT(4)) = OFFSET_Flt4
-baseRegOffset (DoubleReg ILIT(1)) = OFFSET_Dbl1
-baseRegOffset (DoubleReg ILIT(2)) = OFFSET_Dbl2
-baseRegOffset TagReg = OFFSET_Tag
-baseRegOffset RetReg = OFFSET_Ret
-baseRegOffset SpA = OFFSET_SpA
-baseRegOffset SuA = OFFSET_SuA
-baseRegOffset SpB = OFFSET_SpB
-baseRegOffset SuB = OFFSET_SuB
-baseRegOffset Hp = OFFSET_Hp
-baseRegOffset HpLim = OFFSET_HpLim
-baseRegOffset LivenessReg = OFFSET_Liveness
---baseRegOffset ActivityReg = OFFSET_Activity
-#ifdef DEBUG
-baseRegOffset BaseReg = panic "baseRegOffset:BaseReg"
-baseRegOffset StdUpdRetVecReg = panic "baseRegOffset:StgUpdRetVecReg"
-baseRegOffset StkStubReg = panic "baseRegOffset:StkStubReg"
-baseRegOffset CurCostCentre = panic "baseRegOffset:CurCostCentre"
-baseRegOffset VoidReg = panic "baseRegOffset:VoidReg"
-#endif
-
-callerSaves :: MagicId -> Bool
-#ifdef CALLER_SAVES_Base
-callerSaves BaseReg = True
-#endif
-#ifdef CALLER_SAVES_StkO
-callerSaves StkOReg = True
-#endif
-#ifdef CALLER_SAVES_R1
-callerSaves (VanillaReg _ ILIT(1)) = True
-#endif
-#ifdef CALLER_SAVES_R2
-callerSaves (VanillaReg _ ILIT(2)) = True
-#endif
-#ifdef CALLER_SAVES_R3
-callerSaves (VanillaReg _ ILIT(3)) = True
-#endif
-#ifdef CALLER_SAVES_R4
-callerSaves (VanillaReg _ ILIT(4)) = True
-#endif
-#ifdef CALLER_SAVES_R5
-callerSaves (VanillaReg _ ILIT(5)) = True
-#endif
-#ifdef CALLER_SAVES_R6
-callerSaves (VanillaReg _ ILIT(6)) = True
-#endif
-#ifdef CALLER_SAVES_R7
-callerSaves (VanillaReg _ ILIT(7)) = True
-#endif
-#ifdef CALLER_SAVES_R8
-callerSaves (VanillaReg _ ILIT(8)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg1
-callerSaves (FloatReg ILIT(1)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg2
-callerSaves (FloatReg ILIT(2)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg3
-callerSaves (FloatReg ILIT(3)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg4
-callerSaves (FloatReg ILIT(4)) = True
-#endif
-#ifdef CALLER_SAVES_DblReg1
-callerSaves (DoubleReg ILIT(1)) = True
-#endif
-#ifdef CALLER_SAVES_DblReg2
-callerSaves (DoubleReg ILIT(2)) = True
-#endif
-#ifdef CALLER_SAVES_Tag
-callerSaves TagReg = True
-#endif
-#ifdef CALLER_SAVES_Ret
-callerSaves RetReg = True
-#endif
-#ifdef CALLER_SAVES_SpA
-callerSaves SpA = True
-#endif
-#ifdef CALLER_SAVES_SuA
-callerSaves SuA = True
-#endif
-#ifdef CALLER_SAVES_SpB
-callerSaves SpB = True
-#endif
-#ifdef CALLER_SAVES_SuB
-callerSaves SuB = True
-#endif
-#ifdef CALLER_SAVES_Hp
-callerSaves Hp = True
-#endif
-#ifdef CALLER_SAVES_HpLim
-callerSaves HpLim = True
-#endif
-#ifdef CALLER_SAVES_Liveness
-callerSaves LivenessReg = True
-#endif
-#ifdef CALLER_SAVES_Activity
---callerSaves ActivityReg = True
-#endif
-#ifdef CALLER_SAVES_StdUpdRetVec
-callerSaves StdUpdRetVecReg = True
-#endif
-#ifdef CALLER_SAVES_StkStub
-callerSaves StkStubReg = True
-#endif
-callerSaves _ = False
-
-stgRegMap :: MagicId -> Maybe Reg
-#ifdef REG_Base
-stgRegMap BaseReg = Just (FixedReg ILIT(REG_Base))
-#endif
-#ifdef REG_StkO
-stgRegMap StkOReg = Just (FixedReg ILIT(REG_StkOReg))
-#endif
-#ifdef REG_R1
-stgRegMap (VanillaReg _ ILIT(1)) = Just (FixedReg ILIT(REG_R1))
-#endif
-#ifdef REG_R2
-stgRegMap (VanillaReg _ ILIT(2)) = Just (FixedReg ILIT(REG_R2))
-#endif
-#ifdef REG_R3
-stgRegMap (VanillaReg _ ILIT(3)) = Just (FixedReg ILIT(REG_R3))
-#endif
-#ifdef REG_R4
-stgRegMap (VanillaReg _ ILIT(4)) = Just (FixedReg ILIT(REG_R4))
-#endif
-#ifdef REG_R5
-stgRegMap (VanillaReg _ ILIT(5)) = Just (FixedReg ILIT(REG_R5))
-#endif
-#ifdef REG_R6
-stgRegMap (VanillaReg _ ILIT(6)) = Just (FixedReg ILIT(REG_R6))
-#endif
-#ifdef REG_R7
-stgRegMap (VanillaReg _ ILIT(7)) = Just (FixedReg ILIT(REG_R7))
-#endif
-#ifdef REG_R8
-stgRegMap (VanillaReg _ ILIT(8)) = Just (FixedReg ILIT(REG_R8))
-#endif
-#ifdef REG_Flt1
-stgRegMap (FloatReg ILIT(1)) = Just (FixedReg ILIT(REG_Flt1))
-#endif
-#ifdef REG_Flt2
-stgRegMap (FloatReg ILIT(2)) = Just (FixedReg ILIT(REG_Flt2))
-#endif
-#ifdef REG_Flt3
-stgRegMap (FloatReg ILIT(3)) = Just (FixedReg ILIT(REG_Flt3))
-#endif
-#ifdef REG_Flt4
-stgRegMap (FloatReg ILIT(4)) = Just (FixedReg ILIT(REG_Flt4))
-#endif
-#ifdef REG_Dbl1
-stgRegMap (DoubleReg ILIT(1)) = Just (FixedReg ILIT(REG_Dbl1))
-#endif
-#ifdef REG_Dbl2
-stgRegMap (DoubleReg ILIT(2)) = Just (FixedReg ILIT(REG_Dbl2))
-#endif
-#ifdef REG_Tag
-stgRegMap TagReg = Just (FixedReg ILIT(REG_TagReg))
-#endif
-#ifdef REG_Ret
-stgRegMap RetReg = Just (FixedReg ILIT(REG_Ret))
-#endif
-#ifdef REG_SpA
-stgRegMap SpA = Just (FixedReg ILIT(REG_SpA))
-#endif
-#ifdef REG_SuA
-stgRegMap SuA = Just (FixedReg ILIT(REG_SuA))
-#endif
-#ifdef REG_SpB
-stgRegMap SpB = Just (FixedReg ILIT(REG_SpB))
-#endif
-#ifdef REG_SuB
-stgRegMap SuB = Just (FixedReg ILIT(REG_SuB))
-#endif
-#ifdef REG_Hp
-stgRegMap Hp = Just (FixedReg ILIT(REG_Hp))
-#endif
-#ifdef REG_HpLim
-stgRegMap HpLim = Just (FixedReg ILIT(REG_HpLim))
-#endif
-#ifdef REG_Liveness
-stgRegMap LivenessReg = Just (FixedReg ILIT(REG_Liveness))
-#endif
-#ifdef REG_Activity
---stgRegMap ActivityReg = Just (FixedReg ILIT(REG_Activity))
-#endif
-#ifdef REG_StdUpdRetVec
-stgRegMap StdUpdRetVecReg = Just (FixedReg ILIT(REG_StdUpdRetVec))
-#endif
-#ifdef REG_StkStub
-stgRegMap StkStubReg = Just (FixedReg ILIT(REG_StkStub))
-#endif
-stgRegMap _ = Nothing
-
-\end{code}
-
-Here is the list of registers we can use in register allocation.
-
-With a per-instruction clobber list, we might be able to get some of
-these back, but it's probably not worth the hassle.
-
-\begin{code}
-
-freeReg :: FAST_INT -> FAST_BOOL
-
-freeReg ILIT(26) = _FALSE_ -- return address (ra)
-freeReg ILIT(28) = _FALSE_ -- reserved for the assembler (at)
-freeReg ILIT(29) = _FALSE_ -- global pointer (gp)
-freeReg ILIT(30) = _FALSE_ -- stack pointer (sp)
-freeReg ILIT(31) = _FALSE_ -- always zero (zero)
-freeReg ILIT(63) = _FALSE_ -- always zero (f31)
-
-#ifdef REG_Base
-freeReg ILIT(REG_Base) = _FALSE_
-#endif
-#ifdef REG_StkO
-freeReg ILIT(REG_StkO) = _FALSE_
-#endif
-#ifdef REG_R1
-freeReg ILIT(REG_R1) = _FALSE_
-#endif
-#ifdef REG_R2
-freeReg ILIT(REG_R2) = _FALSE_
-#endif
-#ifdef REG_R3
-freeReg ILIT(REG_R3) = _FALSE_
-#endif
-#ifdef REG_R4
-freeReg ILIT(REG_R4) = _FALSE_
-#endif
-#ifdef REG_R5
-freeReg ILIT(REG_R5) = _FALSE_
-#endif
-#ifdef REG_R6
-freeReg ILIT(REG_R6) = _FALSE_
-#endif
-#ifdef REG_R7
-freeReg ILIT(REG_R7) = _FALSE_
-#endif
-#ifdef REG_R8
-freeReg ILIT(REG_R8) = _FALSE_
-#endif
-#ifdef REG_Flt1
-freeReg ILIT(REG_Flt1) = _FALSE_
-#endif
-#ifdef REG_Flt2
-freeReg ILIT(REG_Flt2) = _FALSE_
-#endif
-#ifdef REG_Flt3
-freeReg ILIT(REG_Flt3) = _FALSE_
-#endif
-#ifdef REG_Flt4
-freeReg ILIT(REG_Flt4) = _FALSE_
-#endif
-#ifdef REG_Dbl1
-freeReg ILIT(REG_Dbl1) = _FALSE_
-#endif
-#ifdef REG_Dbl2
-freeReg ILIT(REG_Dbl2) = _FALSE_
-#endif
-#ifdef REG_Tag
-freeReg ILIT(REG_Tag) = _FALSE_
-#endif
-#ifdef REG_Ret
-freeReg ILIT(REG_Ret) = _FALSE_
-#endif
-#ifdef REG_SpA
-freeReg ILIT(REG_SpA) = _FALSE_
-#endif
-#ifdef REG_SuA
-freeReg ILIT(REG_SuA) = _FALSE_
-#endif
-#ifdef REG_SpB
-freeReg ILIT(REG_SpB) = _FALSE_
-#endif
-#ifdef REG_SuB
-freeReg ILIT(REG_SuB) = _FALSE_
-#endif
-#ifdef REG_Hp
-freeReg ILIT(REG_Hp) = _FALSE_
-#endif
-#ifdef REG_HpLim
-freeReg ILIT(REG_HpLim) = _FALSE_
-#endif
-#ifdef REG_Liveness
-freeReg ILIT(REG_Liveness) = _FALSE_
-#endif
-#ifdef REG_Activity
---freeReg ILIT(REG_Activity) = _FALSE_
-#endif
-#ifdef REG_StdUpdRetVec
-freeReg ILIT(REG_StdUpdRetVec) = _FALSE_
-#endif
-#ifdef REG_StkStub
-freeReg ILIT(REG_StkStub) = _FALSE_
-#endif
-freeReg _ = _TRUE_
-
-reservedRegs :: [Int]
-reservedRegs = [NCG_Reserved_I1, NCG_Reserved_I2, NCG_Reserved_F1, NCG_Reserved_F2]
-
-\end{code}
+++ /dev/null
-%
-% (c) The AQUA Project, Glasgow University, 1994-1995
-%
-\section[AlphaDesc]{The Alpha Machine Description}
-
-\begin{code}
-#include "HsVersions.h"
-
-module AlphaDesc (
- mkAlpha
-
- -- and assorted nonsense referenced by the class methods
- ) where
-
-import AbsCSyn
-import PrelInfo ( PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import AsmRegAlloc ( Reg, MachineCode(..), MachineRegisters(..),
- RegUsage(..), RegLiveness(..), FutureLive(..)
- )
-import CLabel ( CLabel )
-import CmdLineOpts ( GlobalSwitch(..), stringSwitchSet,
- switchIsOn, SwitchResult(..)
- )
-import HeapOffs ( hpRelToInt )
-import MachDesc
-import Maybes ( Maybe(..) )
-import OrdList
-import Outputable
-import PrimRep ( PrimRep(..) )
-import SMRep ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..) )
-import AlphaCode
-import AlphaGen ( alphaCodeGen )
-import Stix
-import StixMacro
-import StixPrim
-import UniqSupply
-import Util
-
-\end{code}
-
-Header sizes depend only on command-line options, not on the target
-architecture. (I think.)
-
-\begin{code}
-
-fhs :: (GlobalSwitch -> SwitchResult) -> Int
-
-fhs switches = 1 + profFHS + ageFHS
- where
- profFHS = if switchIsOn switches SccProfilingOn then 1 else 0
- ageFHS = if switchIsOn switches SccProfilingOn then 1 else 0
-
-vhs :: (GlobalSwitch -> SwitchResult) -> SMRep -> Int
-
-vhs switches sm = case sm of
- StaticRep _ _ -> 0
- SpecialisedRep _ _ _ _ -> 0
- GenericRep _ _ _ -> 0
- BigTupleRep _ -> 1
- MuTupleRep _ -> 2 {- (1 + GC_MUT_RESERVED_WORDS) -}
- DataRep _ -> 1
- DynamicRep -> 2
- BlackHoleRep -> 0
- PhantomRep -> panic "vhs:phantom"
-
-\end{code}
-
-Here we map STG registers onto appropriate Stix Trees. First, we
-handle the two constants, @STK_STUB_closure@ and @vtbl_StdUpdFrame@.
-The rest are either in real machine registers or stored as offsets
-from BaseReg.
-
-\begin{code}
-
-alphaReg :: (GlobalSwitch -> SwitchResult) -> MagicId -> RegLoc
-
-alphaReg switches x =
- case stgRegMap x of
- Just reg -> Save nonReg
- Nothing -> Always nonReg
- where nonReg = case x of
- StkStubReg -> sStLitLbl SLIT("STK_STUB_closure")
- StdUpdRetVecReg -> sStLitLbl SLIT("vtbl_StdUpdFrame")
- BaseReg -> sStLitLbl SLIT("MainRegTable")
- Hp -> StInd PtrRep (sStLitLbl SLIT("StorageMgrInfo"))
- HpLim -> StInd PtrRep (sStLitLbl SLIT("StorageMgrInfo+8"))
- TagReg -> StInd IntRep (StPrim IntSubOp [infoptr, StInt (1*8)])
- where
- r2 = VanillaReg PtrRep ILIT(2)
- infoptr = case alphaReg switches r2 of
- Always tree -> tree
- Save _ -> StReg (StixMagicId r2)
- _ -> StInd (kindFromMagicId x)
- (StPrim IntAddOp [baseLoc, StInt (toInteger (offset*8))])
- baseLoc = case stgRegMap BaseReg of
- Just _ -> StReg (StixMagicId BaseReg)
- Nothing -> sStLitLbl SLIT("MainRegTable")
- offset = baseRegOffset x
-
-\end{code}
-
-Sizes in bytes.
-
-\begin{code}
-
-size pk = case kindToSize pk of
- {B -> 1; BU -> 1; W -> 2; WU -> 2; L -> 4; FF -> 4; SF -> 4; _ -> 8}
-
-\end{code}
-
-Now the volatile saves and restores. We add the basic guys to the list of ``user''
-registers provided. Note that there are more basic registers on the restore list,
-because some are reloaded from constants.
-
-\begin{code}
-
-vsaves switches vols =
- map save ((filter callerSaves) ([BaseReg,SpA,SuA,SpB,SuB,Hp,HpLim,RetReg{-,ActivityReg-}] ++ vols))
- where
- save x = StAssign (kindFromMagicId x) loc reg
- where reg = StReg (StixMagicId x)
- loc = case alphaReg switches x of
- Save loc -> loc
- Always loc -> panic "vsaves"
-
-vrests switches vols =
- map restore ((filter callerSaves)
- ([BaseReg,SpA,SuA,SpB,SuB,Hp,HpLim,RetReg,{-ActivityReg,-}StkStubReg,StdUpdRetVecReg] ++ vols))
- where
- restore x = StAssign (kindFromMagicId x) reg loc
- where reg = StReg (StixMagicId x)
- loc = case alphaReg switches x of
- Save loc -> loc
- Always loc -> panic "vrests"
-
-\end{code}
-
-Static closure sizes.
-
-\begin{code}
-
-charLikeSize, intLikeSize :: Target -> Int
-
-charLikeSize target =
- size PtrRep * (fixedHeaderSize target + varHeaderSize target charLikeRep + 1)
- where charLikeRep = SpecialisedRep CharLikeRep 0 1 SMNormalForm
-
-intLikeSize target =
- size PtrRep * (fixedHeaderSize target + varHeaderSize target intLikeRep + 1)
- where intLikeRep = SpecialisedRep IntLikeRep 0 1 SMNormalForm
-
-mhs, dhs :: (GlobalSwitch -> SwitchResult) -> StixTree
-
-mhs switches = StInt (toInteger words)
- where
- words = fhs switches + vhs switches (MuTupleRep 0)
-
-dhs switches = StInt (toInteger words)
- where
- words = fhs switches + vhs switches (DataRep 0)
-
-\end{code}
-
-Setting up a alpha target.
-
-\begin{code}
-
-mkAlpha :: (GlobalSwitch -> SwitchResult)
- -> (Target,
- (PprStyle -> [[StixTree]] -> UniqSM Unpretty), -- codeGen
- Bool, -- underscore
- (String -> String)) -- fmtAsmLbl
-
-mkAlpha switches =
- let
- fhs' = fhs switches
- vhs' = vhs switches
- alphaReg' = alphaReg switches
- vsaves' = vsaves switches
- vrests' = vrests switches
- hprel = hpRelToInt target
- as = amodeCode target
- as' = amodeCode' target
- csz = charLikeSize target
- isz = intLikeSize target
- mhs' = mhs switches
- dhs' = dhs switches
- ps = genPrimCode target
- mc = genMacroCode target
- hc = doHeapCheck
- target = mkTarget {-switches-} fhs' vhs' alphaReg' {-id-} size
- hprel as as'
- (vsaves', vrests', csz, isz, mhs', dhs', ps, mc, hc)
- {-alphaCodeGen False mungeLabel-}
- in
- (target, alphaCodeGen, False, mungeLabel)
-\end{code}
-
-The alpha assembler likes temporary labels to look like \tr{$L123}
-instead of \tr{L123}. (Don't toss the \tr{L}, because then \tr{Lf28}
-turns into \tr{$f28}.)
-\begin{code}
-mungeLabel :: String -> String
-mungeLabel xs = '$' : xs
-\end{code}
+++ /dev/null
-%
-% (c) The AQUA Project, Glasgow University, 1993-1995
-%
-
-\begin{code}
-#include "HsVersions.h"
-
-module AlphaGen (
- alphaCodeGen,
-
- -- and, for self-sufficiency
- PprStyle, StixTree, CSeq
- ) where
-
-IMPORT_Trace
-
-import AbsCSyn ( AbstractC, MagicId(..), kindFromMagicId )
-import PrelInfo ( PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import AsmRegAlloc ( runRegAllocate, extractMappedRegNos, mkReg,
- Reg(..), RegLiveness(..), RegUsage(..), FutureLive(..),
- MachineRegisters(..), MachineCode(..)
- )
-import CLabel ( CLabel, isAsmTemp )
-import AlphaCode {- everything -}
-import MachDesc
-import Maybes ( maybeToBool, Maybe(..) )
-import OrdList -- ( mkEmptyList, mkUnitList, mkSeqList, mkParList, OrdList )
-import Outputable
-import AlphaDesc
-import Stix
-import UniqSupply
-import Pretty
-import Unpretty
-import Util
-
-type CodeBlock a = (OrdList a -> OrdList a)
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[AlphaCodeGen]{Generating Alpha Code}
-%* *
-%************************************************************************
-
-This is the top-level code-generation function for the Alpha.
-
-\begin{code}
-
-alphaCodeGen :: PprStyle -> [[StixTree]] -> UniqSM Unpretty
-alphaCodeGen sty trees =
- mapUs genAlphaCode trees `thenUs` \ dynamicCodes ->
- let
- staticCodes = scheduleAlphaCode dynamicCodes
- pretty = printLabeledCodes sty staticCodes
- in
- returnUs pretty
-
-\end{code}
-
-This bit does the code scheduling. The scheduler must also deal with
-register allocation of temporaries. Much parallelism can be exposed via
-the OrdList, but more might occur, so further analysis might be needed.
-
-\begin{code}
-
-scheduleAlphaCode :: [AlphaCode] -> [AlphaInstr]
-scheduleAlphaCode = concat . map (runRegAllocate freeAlphaRegs reservedRegs)
- where
- freeAlphaRegs :: AlphaRegs
- freeAlphaRegs = mkMRegs (extractMappedRegNos freeRegs)
-
-\end{code}
-
-Registers passed up the tree. If the stix code forces the register
-to live in a pre-decided machine register, it comes out as @Fixed@;
-otherwise, it comes out as @Any@, and the parent can decide which
-register to put it in.
-
-\begin{code}
-
-data Register
- = Fixed Reg PrimRep (CodeBlock AlphaInstr)
- | Any PrimRep (Reg -> (CodeBlock AlphaInstr))
-
-registerCode :: Register -> Reg -> CodeBlock AlphaInstr
-registerCode (Fixed _ _ code) reg = code
-registerCode (Any _ code) reg = code reg
-
-registerName :: Register -> Reg -> Reg
-registerName (Fixed reg _ _) _ = reg
-registerName (Any _ _) reg = reg
-
-registerKind :: Register -> PrimRep
-registerKind (Fixed _ pk _) = pk
-registerKind (Any pk _) = pk
-
-isFixed :: Register -> Bool
-isFixed (Fixed _ _ _) = True
-isFixed (Any _ _) = False
-
-\end{code}
-
-Memory addressing modes passed up the tree.
-
-\begin{code}
-
-data Amode = Amode Addr (CodeBlock AlphaInstr)
-
-amodeAddr (Amode addr _) = addr
-amodeCode (Amode _ code) = code
-
-\end{code}
-
-General things for putting together code sequences.
-
-\begin{code}
-
-asmVoid :: OrdList AlphaInstr
-asmVoid = mkEmptyList
-
-asmInstr :: AlphaInstr -> AlphaCode
-asmInstr i = mkUnitList i
-
-asmSeq :: [AlphaInstr] -> AlphaCode
-asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
-
-asmParThen :: [AlphaCode] -> CodeBlock AlphaInstr
-asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
-
-returnInstr :: AlphaInstr -> UniqSM (CodeBlock AlphaInstr)
-returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
-
-returnInstrs :: [AlphaInstr] -> UniqSM (CodeBlock AlphaInstr)
-returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
-
-returnSeq :: (CodeBlock AlphaInstr) -> [AlphaInstr] -> UniqSM (CodeBlock AlphaInstr)
-returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
-
-mkSeqInstr :: AlphaInstr -> (CodeBlock AlphaInstr)
-mkSeqInstr instr code = mkSeqList (asmInstr instr) code
-
-mkSeqInstrs :: [AlphaInstr] -> (CodeBlock AlphaInstr)
-mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
-
-\end{code}
-
-Top level alpha code generator for a chunk of stix code.
-
-\begin{code}
-
-genAlphaCode :: [StixTree] -> UniqSM (AlphaCode)
-
-genAlphaCode trees =
- mapUs getCode trees `thenUs` \ blocks ->
- returnUs (foldr (.) id blocks asmVoid)
-
-\end{code}
-
-Code extractor for an entire stix tree---stix statement level.
-
-\begin{code}
-
-getCode
- :: StixTree -- a stix statement
- -> UniqSM (CodeBlock AlphaInstr)
-
-getCode (StSegment seg) = returnInstr (SEGMENT seg)
-
-getCode (StAssign pk dst src)
- | isFloatingRep pk = assignFltCode pk dst src
- | otherwise = assignIntCode pk dst src
-
-getCode (StLabel lab) = returnInstr (LABEL lab)
-
-getCode (StFunBegin lab) = returnInstr (FUNBEGIN lab)
-
-getCode (StFunEnd lab) = returnInstr (FUNEND lab)
-
-getCode (StJump arg) = genJump arg
-
--- When falling through on the alpha, we still have to load pv with the
--- address of the next routine, so that it can load gp
-getCode (StFallThrough lbl) = returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
-
-getCode (StCondJump lbl arg) = genCondJump lbl arg
-
-getCode (StData kind args) =
- mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
- returnUs (\xs -> mkSeqList (asmInstr (DATA (kindToSize kind) imms))
- (foldr1 (.) codes xs))
- where
- getData :: StixTree -> UniqSM (CodeBlock AlphaInstr, Imm)
- getData (StInt i) = returnUs (id, ImmInteger i)
- getData (StDouble d) = returnUs (id, ImmLab (prettyToUn (ppRational d)))
- getData (StLitLbl s) = returnUs (id, ImmLab s)
- getData (StLitLit s) = returnUs (id, strImmLab (cvtLitLit (_UNPK_ s)))
- getData (StString s) =
- getUniqLabelNCG `thenUs` \ lbl ->
- returnUs (mkSeqInstrs [LABEL lbl, ASCII True (_UNPK_ s)], ImmCLbl lbl)
- getData (StCLbl l) = returnUs (id, ImmCLbl l)
-
-getCode (StCall fn VoidRep args) = genCCall fn VoidRep args
-
-getCode (StComment s) = returnInstr (COMMENT s)
-
-\end{code}
-
-Generate code to get a subtree into a register.
-
-\begin{code}
-
-getReg :: StixTree -> UniqSM Register
-
-getReg (StReg (StixMagicId stgreg)) =
- case stgRegMap stgreg of
- Just reg -> returnUs (Fixed reg (kindFromMagicId stgreg) id)
- -- cannae be Nothing
-
-getReg (StReg (StixTemp u pk)) = returnUs (Fixed (UnmappedReg u pk) pk id)
-
-getReg (StDouble d) =
- getUniqLabelNCG `thenUs` \ lbl ->
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- let code dst = mkSeqInstrs [
- SEGMENT DataSegment,
- LABEL lbl,
- DATA TF [ImmLab (prettyToUn (ppRational d))],
- SEGMENT TextSegment,
- LDA tmp (AddrImm (ImmCLbl lbl)),
- LD TF dst (AddrReg tmp)]
- in
- returnUs (Any DoubleRep code)
-
-getReg (StString s) =
- getUniqLabelNCG `thenUs` \ lbl ->
- let code dst = mkSeqInstrs [
- SEGMENT DataSegment,
- LABEL lbl,
- ASCII True (_UNPK_ s),
- SEGMENT TextSegment,
- LDA dst (AddrImm (ImmCLbl lbl))]
- in
- returnUs (Any PtrRep code)
-
-getReg (StLitLit s) | _HEAD_ s == '"' && last xs == '"' =
- getUniqLabelNCG `thenUs` \ lbl ->
- let code dst = mkSeqInstrs [
- SEGMENT DataSegment,
- LABEL lbl,
- ASCII False (init xs),
- SEGMENT TextSegment,
- LDA dst (AddrImm (ImmCLbl lbl))]
- in
- returnUs (Any PtrRep code)
- where
- xs = _UNPK_ (_TAIL_ s)
-
-getReg tree@(StIndex _ _ _) = getReg (mangleIndexTree tree)
-
-getReg (StCall fn kind args) =
- genCCall fn kind args `thenUs` \ call ->
- returnUs (Fixed reg kind call)
- where
- reg = if isFloatingRep kind then f0 else v0
-
-getReg (StPrim primop args) =
- case primop of
-
- CharGtOp -> case args of [x,y] -> trivialCode (CMP LT) [y,x]
- CharGeOp -> case args of [x,y] -> trivialCode (CMP LE) [y,x]
- CharEqOp -> trivialCode (CMP EQ) args
- CharNeOp -> intNECode args
- CharLtOp -> trivialCode (CMP LT) args
- CharLeOp -> trivialCode (CMP LE) args
-
- IntAddOp -> trivialCode (ADD Q False) args
-
- IntSubOp -> trivialCode (SUB Q False) args
- IntMulOp -> trivialCode (MUL Q False) args
- IntQuotOp -> trivialCode (DIV Q False) args
- IntRemOp -> trivialCode (REM Q False) args
- IntNegOp -> trivialUCode (NEG Q False) args
- IntAbsOp -> trivialUCode (ABS Q) args
-
- AndOp -> trivialCode AND args
- OrOp -> trivialCode OR args
- NotOp -> trivialUCode NOT args
- SllOp -> trivialCode SLL args
- SraOp -> trivialCode SRA args
- SrlOp -> trivialCode SRL args
- ISllOp -> panic "AlphaGen:isll"
- ISraOp -> panic "AlphaGen:isra"
- ISrlOp -> panic "AlphaGen:isrl"
-
- IntGtOp -> case args of [x,y] -> trivialCode (CMP LT) [y,x]
- IntGeOp -> case args of [x,y] -> trivialCode (CMP LE) [y,x]
- IntEqOp -> trivialCode (CMP EQ) args
- IntNeOp -> intNECode args
- IntLtOp -> trivialCode (CMP LT) args
- IntLeOp -> trivialCode (CMP LE) args
-
- WordGtOp -> case args of [x,y] -> trivialCode (CMP ULT) [y,x]
- WordGeOp -> case args of [x,y] -> trivialCode (CMP ULE) [y,x]
- WordEqOp -> trivialCode (CMP EQ) args
- WordNeOp -> intNECode args
- WordLtOp -> trivialCode (CMP ULT) args
- WordLeOp -> trivialCode (CMP ULE) args
-
- AddrGtOp -> case args of [x,y] -> trivialCode (CMP ULT) [y,x]
- AddrGeOp -> case args of [x,y] -> trivialCode (CMP ULE) [y,x]
- AddrEqOp -> trivialCode (CMP EQ) args
- AddrNeOp -> intNECode args
- AddrLtOp -> trivialCode (CMP ULT) args
- AddrLeOp -> trivialCode (CMP ULE) args
-
- FloatAddOp -> trivialFCode (FADD TF) args
- FloatSubOp -> trivialFCode (FSUB TF) args
- FloatMulOp -> trivialFCode (FMUL TF) args
- FloatDivOp -> trivialFCode (FDIV TF) args
- FloatNegOp -> trivialUFCode (FNEG TF) args
-
- FloatGtOp -> cmpFCode (FCMP TF LE) EQ args
- FloatGeOp -> cmpFCode (FCMP TF LT) EQ args
- FloatEqOp -> cmpFCode (FCMP TF EQ) NE args
- FloatNeOp -> cmpFCode (FCMP TF EQ) EQ args
- FloatLtOp -> cmpFCode (FCMP TF LT) NE args
- FloatLeOp -> cmpFCode (FCMP TF LE) NE args
-
- FloatExpOp -> call SLIT("exp") DoubleRep
- FloatLogOp -> call SLIT("log") DoubleRep
- FloatSqrtOp -> call SLIT("sqrt") DoubleRep
-
- FloatSinOp -> call SLIT("sin") DoubleRep
- FloatCosOp -> call SLIT("cos") DoubleRep
- FloatTanOp -> call SLIT("tan") DoubleRep
-
- FloatAsinOp -> call SLIT("asin") DoubleRep
- FloatAcosOp -> call SLIT("acos") DoubleRep
- FloatAtanOp -> call SLIT("atan") DoubleRep
-
- FloatSinhOp -> call SLIT("sinh") DoubleRep
- FloatCoshOp -> call SLIT("cosh") DoubleRep
- FloatTanhOp -> call SLIT("tanh") DoubleRep
-
- FloatPowerOp -> call SLIT("pow") DoubleRep
-
- DoubleAddOp -> trivialFCode (FADD TF) args
- DoubleSubOp -> trivialFCode (FSUB TF) args
- DoubleMulOp -> trivialFCode (FMUL TF) args
- DoubleDivOp -> trivialFCode (FDIV TF) args
- DoubleNegOp -> trivialUFCode (FNEG TF) args
-
- DoubleGtOp -> cmpFCode (FCMP TF LE) EQ args
- DoubleGeOp -> cmpFCode (FCMP TF LT) EQ args
- DoubleEqOp -> cmpFCode (FCMP TF EQ) NE args
- DoubleNeOp -> cmpFCode (FCMP TF EQ) EQ args
- DoubleLtOp -> cmpFCode (FCMP TF LT) NE args
- DoubleLeOp -> cmpFCode (FCMP TF LE) NE args
-
- DoubleExpOp -> call SLIT("exp") DoubleRep
- DoubleLogOp -> call SLIT("log") DoubleRep
- DoubleSqrtOp -> call SLIT("sqrt") DoubleRep
-
- DoubleSinOp -> call SLIT("sin") DoubleRep
- DoubleCosOp -> call SLIT("cos") DoubleRep
- DoubleTanOp -> call SLIT("tan") DoubleRep
-
- DoubleAsinOp -> call SLIT("asin") DoubleRep
- DoubleAcosOp -> call SLIT("acos") DoubleRep
- DoubleAtanOp -> call SLIT("atan") DoubleRep
-
- DoubleSinhOp -> call SLIT("sinh") DoubleRep
- DoubleCoshOp -> call SLIT("cosh") DoubleRep
- DoubleTanhOp -> call SLIT("tanh") DoubleRep
-
- DoublePowerOp -> call SLIT("pow") DoubleRep
-
- OrdOp -> coerceIntCode IntRep args
- ChrOp -> chrCode args
-
- Float2IntOp -> coerceFP2Int args
- Int2FloatOp -> coerceInt2FP args
- Double2IntOp -> coerceFP2Int args
- Int2DoubleOp -> coerceInt2FP args
-
- Double2FloatOp -> coerceFltCode args
- Float2DoubleOp -> coerceFltCode args
-
- where
- call fn pk = getReg (StCall fn pk args)
-
-getReg (StInd pk mem) =
- getAmode mem `thenUs` \ amode ->
- let
- code = amodeCode amode
- src = amodeAddr amode
- size = kindToSize pk
- code__2 dst = code . mkSeqInstr (LD size dst src)
- in
- returnUs (Any pk code__2)
-
-getReg (StInt i)
- | is8Bits i =
- let
- code dst = mkSeqInstr (OR zero (RIImm src) dst)
- in
- returnUs (Any IntRep code)
- | otherwise =
- let
- code dst = mkSeqInstr (LDI Q dst src)
- in
- returnUs (Any IntRep code)
- where
- src = ImmInt (fromInteger i)
-
-getReg leaf
- | maybeToBool imm =
- let
- code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
- in
- returnUs (Any PtrRep code)
- where
- imm = maybeImm leaf
- imm__2 = case imm of Just x -> x
-
-\end{code}
-
-Now, given a tree (the argument to an StInd) that references memory,
-produce a suitable addressing mode.
-
-\begin{code}
-
-getAmode :: StixTree -> UniqSM Amode
-
-getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
-
-getAmode (StPrim IntSubOp [x, StInt i]) =
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- getReg x `thenUs` \ register ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- off = ImmInt (-(fromInteger i))
- in
- returnUs (Amode (AddrRegImm reg off) code)
-
-
-getAmode (StPrim IntAddOp [x, StInt i]) =
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- getReg x `thenUs` \ register ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- off = ImmInt (fromInteger i)
- in
- returnUs (Amode (AddrRegImm reg off) code)
-
-getAmode leaf
- | maybeToBool imm =
- returnUs (Amode (AddrImm imm__2) id)
- where
- imm = maybeImm leaf
- imm__2 = case imm of Just x -> x
-
-getAmode other =
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- getReg other `thenUs` \ register ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- in
- returnUs (Amode (AddrReg reg) code)
-
-\end{code}
-
-Try to get a value into a specific register (or registers) for a call.
-The first 6 arguments go into the appropriate argument register
-(separate registers for integer and floating point arguments, but used
-in lock-step), and the remaining arguments are dumped to the stack,
-beginning at 0(sp). Our first argument is a pair of the list of
-remaining argument registers to be assigned for this call and the next
-stack offset to use for overflowing arguments. This way, @getCallArg@
-can be applied to all of a call's arguments using @mapAccumL@.
-
-\begin{code}
-
-getCallArg
- :: ([(Reg,Reg)],Int) -- Argument registers and stack offset (accumulator)
- -> StixTree -- Current argument
- -> UniqSM (([(Reg,Reg)],Int), CodeBlock AlphaInstr) -- Updated accumulator and code
-
--- We have to use up all of our argument registers first.
-
-getCallArg ((iDst,fDst):dsts, offset) arg =
- getReg arg `thenUs` \ register ->
- let
- reg = if isFloatingRep pk then fDst else iDst
- code = registerCode register reg
- src = registerName register reg
- pk = registerKind register
- in
- returnUs (
- if isFloatingRep pk then
- ((dsts, offset), if isFixed register then
- code . mkSeqInstr (FMOV src fDst)
- else code)
- else
- ((dsts, offset), if isFixed register then
- code . mkSeqInstr (OR src (RIReg src) iDst)
- else code))
-
--- Once we have run out of argument registers, we move to the stack
-
-getCallArg ([], offset) arg =
- getReg arg `thenUs` \ register ->
- getNewRegNCG (registerKind register)
- `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
- pk = registerKind register
- sz = kindToSize pk
- in
- returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
-
-\end{code}
-
-Assignments are really at the heart of the whole code generation business.
-Almost all top-level nodes of any real importance are assignments, which
-correspond to loads, stores, or register transfers. If we're really lucky,
-some of the register transfers will go away, because we can use the destination
-register to complete the code generation for the right hand side. This only
-fails when the right hand side is forced into a fixed register (e.g. the result
-of a call).
-
-\begin{code}
-
-assignIntCode :: PrimRep -> StixTree -> StixTree -> UniqSM (CodeBlock AlphaInstr)
-
-assignIntCode pk (StInd _ dst) src =
- getNewRegNCG IntRep `thenUs` \ tmp ->
- getAmode dst `thenUs` \ amode ->
- getReg src `thenUs` \ register ->
- let
- code1 = amodeCode amode asmVoid
- dst__2 = amodeAddr amode
- code2 = registerCode register tmp asmVoid
- src__2 = registerName register tmp
- sz = kindToSize pk
- code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
- in
- returnUs code__2
-
-assignIntCode pk dst src =
- getReg dst `thenUs` \ register1 ->
- getReg src `thenUs` \ register2 ->
- let
- dst__2 = registerName register1 zero
- code = registerCode register2 dst__2
- src__2 = registerName register2 dst__2
- code__2 = if isFixed register2 then
- code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
- else code
- in
- returnUs code__2
-
-assignFltCode :: PrimRep -> StixTree -> StixTree -> UniqSM (CodeBlock AlphaInstr)
-
-assignFltCode pk (StInd _ dst) src =
- getNewRegNCG pk `thenUs` \ tmp ->
- getAmode dst `thenUs` \ amode ->
- getReg src `thenUs` \ register ->
- let
- code1 = amodeCode amode asmVoid
- dst__2 = amodeAddr amode
- code2 = registerCode register tmp asmVoid
- src__2 = registerName register tmp
- sz = kindToSize pk
- code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
- in
- returnUs code__2
-
-assignFltCode pk dst src =
- getReg dst `thenUs` \ register1 ->
- getReg src `thenUs` \ register2 ->
- let
- dst__2 = registerName register1 zero
- code = registerCode register2 dst__2
- src__2 = registerName register2 dst__2
- code__2 = if isFixed register2 then
- code . mkSeqInstr (FMOV src__2 dst__2)
- else code
- in
- returnUs code__2
-
-\end{code}
-
-Generating an unconditional branch. We accept two types of targets:
-an immediate CLabel or a tree that gets evaluated into a register.
-Any CLabels which are AsmTemporaries are assumed to be in the local
-block of code, close enough for a branch instruction. Other CLabels
-are assumed to be far away, so we use jmp.
-
-\begin{code}
-
-genJump
- :: StixTree -- the branch target
- -> UniqSM (CodeBlock AlphaInstr)
-
-genJump (StCLbl lbl)
- | isAsmTemp lbl = returnInstr (BR target)
- | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zero (AddrReg pv) 0]
- where
- target = ImmCLbl lbl
-
-genJump tree =
- getReg tree `thenUs` \ register ->
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- let
- dst = registerName register pv
- code = registerCode register pv
- target = registerName register pv
- in
- if isFixed register then
- returnSeq code [OR dst (RIReg dst) pv, JMP zero (AddrReg pv) 0]
- else
- returnUs (code . mkSeqInstr (JMP zero (AddrReg pv) 0))
-
-\end{code}
-
-Conditional jumps are always to local labels, so we can use
-branch instructions. We peek at the arguments to decide what kind
-of comparison to do. For comparisons with 0, we're laughing, because
-we can just do the desired conditional branch.
-
-\begin{code}
-
-genCondJump
- :: CLabel -- the branch target
- -> StixTree -- the condition on which to branch
- -> UniqSM (CodeBlock AlphaInstr)
-
-genCondJump lbl (StPrim op [x, StInt 0]) =
- getReg x `thenUs` \ register ->
- getNewRegNCG (registerKind register)
- `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- value = registerName register tmp
- pk = registerKind register
- target = ImmCLbl lbl
- in
- returnSeq code [BI (cmpOp op) value target]
- where
- cmpOp CharGtOp = GT
- cmpOp CharGeOp = GE
- cmpOp CharEqOp = EQ
- cmpOp CharNeOp = NE
- cmpOp CharLtOp = LT
- cmpOp CharLeOp = LE
- cmpOp IntGtOp = GT
- cmpOp IntGeOp = GE
- cmpOp IntEqOp = EQ
- cmpOp IntNeOp = NE
- cmpOp IntLtOp = LT
- cmpOp IntLeOp = LE
- cmpOp WordGtOp = NE
- cmpOp WordGeOp = ALWAYS
- cmpOp WordEqOp = EQ
- cmpOp WordNeOp = NE
- cmpOp WordLtOp = NEVER
- cmpOp WordLeOp = EQ
- cmpOp AddrGtOp = NE
- cmpOp AddrGeOp = ALWAYS
- cmpOp AddrEqOp = EQ
- cmpOp AddrNeOp = NE
- cmpOp AddrLtOp = NEVER
- cmpOp AddrLeOp = EQ
-
-genCondJump lbl (StPrim op [x, StDouble 0.0]) =
- getReg x `thenUs` \ register ->
- getNewRegNCG (registerKind register)
- `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- value = registerName register tmp
- pk = registerKind register
- target = ImmCLbl lbl
- in
- returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
- where
- cmpOp FloatGtOp = GT
- cmpOp FloatGeOp = GE
- cmpOp FloatEqOp = EQ
- cmpOp FloatNeOp = NE
- cmpOp FloatLtOp = LT
- cmpOp FloatLeOp = LE
- cmpOp DoubleGtOp = GT
- cmpOp DoubleGeOp = GE
- cmpOp DoubleEqOp = EQ
- cmpOp DoubleNeOp = NE
- cmpOp DoubleLtOp = LT
- cmpOp DoubleLeOp = LE
-
-genCondJump lbl (StPrim op args)
- | fltCmpOp op =
- trivialFCode instr args `thenUs` \ register ->
- getNewRegNCG DoubleRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- result = registerName register tmp
- target = ImmCLbl lbl
- in
- returnUs (code . mkSeqInstr (BF cond result target))
- where
- fltCmpOp op = case op of
- FloatGtOp -> True
- FloatGeOp -> True
- FloatEqOp -> True
- FloatNeOp -> True
- FloatLtOp -> True
- FloatLeOp -> True
- DoubleGtOp -> True
- DoubleGeOp -> True
- DoubleEqOp -> True
- DoubleNeOp -> True
- DoubleLtOp -> True
- DoubleLeOp -> True
- _ -> False
- (instr, cond) = case op of
- FloatGtOp -> (FCMP TF LE, EQ)
- FloatGeOp -> (FCMP TF LT, EQ)
- FloatEqOp -> (FCMP TF EQ, NE)
- FloatNeOp -> (FCMP TF EQ, EQ)
- FloatLtOp -> (FCMP TF LT, NE)
- FloatLeOp -> (FCMP TF LE, NE)
- DoubleGtOp -> (FCMP TF LE, EQ)
- DoubleGeOp -> (FCMP TF LT, EQ)
- DoubleEqOp -> (FCMP TF EQ, NE)
- DoubleNeOp -> (FCMP TF EQ, EQ)
- DoubleLtOp -> (FCMP TF LT, NE)
- DoubleLeOp -> (FCMP TF LE, NE)
-
-genCondJump lbl (StPrim op args) =
- trivialCode instr args `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- result = registerName register tmp
- target = ImmCLbl lbl
- in
- returnUs (code . mkSeqInstr (BI cond result target))
- where
- (instr, cond) = case op of
- CharGtOp -> (CMP LE, EQ)
- CharGeOp -> (CMP LT, EQ)
- CharEqOp -> (CMP EQ, NE)
- CharNeOp -> (CMP EQ, EQ)
- CharLtOp -> (CMP LT, NE)
- CharLeOp -> (CMP LE, NE)
- IntGtOp -> (CMP LE, EQ)
- IntGeOp -> (CMP LT, EQ)
- IntEqOp -> (CMP EQ, NE)
- IntNeOp -> (CMP EQ, EQ)
- IntLtOp -> (CMP LT, NE)
- IntLeOp -> (CMP LE, NE)
- WordGtOp -> (CMP ULE, EQ)
- WordGeOp -> (CMP ULT, EQ)
- WordEqOp -> (CMP EQ, NE)
- WordNeOp -> (CMP EQ, EQ)
- WordLtOp -> (CMP ULT, NE)
- WordLeOp -> (CMP ULE, NE)
- AddrGtOp -> (CMP ULE, EQ)
- AddrGeOp -> (CMP ULT, EQ)
- AddrEqOp -> (CMP EQ, NE)
- AddrNeOp -> (CMP EQ, EQ)
- AddrLtOp -> (CMP ULT, NE)
- AddrLeOp -> (CMP ULE, NE)
-
-\end{code}
-
-Now the biggest nightmare---calls. Most of the nastiness is buried in
-getCallArg, which moves the arguments to the correct registers/stack
-locations. Apart from that, the code is easy.
-
-\begin{code}
-
-genCCall
- :: FAST_STRING -- function to call
- -> PrimRep -- type of the result
- -> [StixTree] -- arguments (of mixed type)
- -> UniqSM (CodeBlock AlphaInstr)
-
-genCCall fn kind args =
- mapAccumLNCG getCallArg (argRegs,stackArgLoc) args
- `thenUs` \ ((unused,_), argCode) ->
- let
- nRegs = length argRegs - length unused
- code = asmParThen (map ($ asmVoid) argCode)
- in
- returnSeq code [
- LDA pv (AddrImm (ImmLab (uppPStr fn))),
- JSR ra (AddrReg pv) nRegs,
- LDGP gp (AddrReg ra)]
- where
- mapAccumLNCG f b [] = returnUs (b, [])
- mapAccumLNCG f b (x:xs) =
- f b x `thenUs` \ (b__2, x__2) ->
- mapAccumLNCG f b__2 xs `thenUs` \ (b__3, xs__2) ->
- returnUs (b__3, x__2:xs__2)
-
-\end{code}
-
-Trivial (dyadic) instructions. Only look for constants on the right hand
-side, because that's where the generic optimizer will have put them.
-
-\begin{code}
-
-trivialCode
- :: (Reg -> RI -> Reg -> AlphaInstr)
- -> [StixTree]
- -> UniqSM Register
-
-trivialCode instr [x, StInt y]
- | is8Bits y =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src1 = registerName register tmp
- src2 = ImmInt (fromInteger y)
- code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
- in
- returnUs (Any IntRep code__2)
-
-trivialCode instr [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 dst = asmParThen [code1, code2] .
- mkSeqInstr (instr src1 (RIReg src2) dst)
- in
- returnUs (Any IntRep code__2)
-
-trivialFCode
- :: (Reg -> Reg -> Reg -> AlphaInstr)
- -> [StixTree]
- -> UniqSM Register
-
-trivialFCode instr [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
- getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
- let
- code1 = registerCode register1 tmp1
- src1 = registerName register1 tmp1
-
- code2 = registerCode register2 tmp2
- src2 = registerName register2 tmp2
-
- code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
- mkSeqInstr (instr src1 src2 dst)
- in
- returnUs (Any DoubleRep code__2)
-
-\end{code}
-
-Some bizarre special code for getting condition codes into registers.
-Integer non-equality is a test for equality followed by an XOR with 1.
-(Integer comparisons always set the result register to 0 or 1.) Floating
-point comparisons of any kind leave the result in a floating point register,
-so we need to wrangle an integer register out of things.
-
-\begin{code}
-intNECode
- :: [StixTree]
- -> UniqSM Register
-
-intNECode args =
- trivialCode (CMP EQ) args `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
- code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
- in
- returnUs (Any IntRep code__2)
-
-cmpFCode
- :: (Reg -> Reg -> Reg -> AlphaInstr)
- -> Cond
- -> [StixTree]
- -> UniqSM Register
-
-cmpFCode instr cond args =
- trivialFCode instr args `thenUs` \ register ->
- getNewRegNCG DoubleRep `thenUs` \ tmp ->
- getUniqLabelNCG `thenUs` \ lbl ->
- let
- code = registerCode register tmp
- result = registerName register tmp
-
- code__2 dst = code . mkSeqInstrs [
- OR zero (RIImm (ImmInt 1)) dst,
- BF cond result (ImmCLbl lbl),
- OR zero (RIReg zero) dst,
- LABEL lbl]
- in
- returnUs (Any IntRep code__2)
-
-\end{code}
-
-Trivial unary instructions. Note that we don't have to worry about
-matching an StInt as the argument, because genericOpt will already
-have handled the constant-folding.
-
-\begin{code}
-
-trivialUCode
- :: (RI -> Reg -> AlphaInstr)
- -> [StixTree]
- -> UniqSM Register
-
-trivialUCode instr [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
- code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
- in
- returnUs (Any IntRep code__2)
-
-trivialUFCode
- :: (Reg -> Reg -> AlphaInstr)
- -> [StixTree]
- -> UniqSM Register
-
-trivialUFCode instr [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG DoubleRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
- code__2 dst = code . mkSeqInstr (instr src dst)
- in
- returnUs (Any DoubleRep code__2)
-
-\end{code}
-
-Simple coercions that don't require any code to be generated.
-Here we just change the type on the register passed on up
-
-\begin{code}
-
-coerceIntCode :: PrimRep -> [StixTree] -> UniqSM Register
-coerceIntCode pk [x] =
- getReg x `thenUs` \ register ->
- case register of
- Fixed reg _ code -> returnUs (Fixed reg pk code)
- Any _ code -> returnUs (Any pk code)
-
-coerceFltCode :: [StixTree] -> UniqSM Register
-coerceFltCode [x] =
- getReg x `thenUs` \ register ->
- case register of
- Fixed reg _ code -> returnUs (Fixed reg DoubleRep code)
- Any _ code -> returnUs (Any DoubleRep code)
-
-\end{code}
-
-Integer to character conversion.
-
-\begin{code}
-
-chrCode [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ reg ->
- let
- code = registerCode register reg
- src = registerName register reg
- code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
- in
- returnUs (Any IntRep code__2)
-
-\end{code}
-
-More complicated integer/float conversions. Here we have to store
-temporaries in memory to move between the integer and the floating
-point register sets.
-
-\begin{code}
-
-coerceInt2FP :: [StixTree] -> UniqSM Register
-coerceInt2FP [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ reg ->
- let
- code = registerCode register reg
- src = registerName register reg
-
- code__2 dst = code . mkSeqInstrs [
- ST Q src (spRel 0),
- LD TF dst (spRel 0),
- CVTxy Q TF dst dst]
- in
- returnUs (Any DoubleRep code__2)
-
-coerceFP2Int :: [StixTree] -> UniqSM Register
-coerceFP2Int [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG DoubleRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
-
- code__2 dst = code . mkSeqInstrs [
- CVTxy TF Q src tmp,
- ST TF tmp (spRel 0),
- LD Q dst (spRel 0)]
- in
- returnUs (Any IntRep code__2)
-
-\end{code}
-
-Some random little helpers.
-
-\begin{code}
-
-is8Bits :: Integer -> Bool
-is8Bits i = i >= -256 && i < 256
-
-maybeImm :: StixTree -> Maybe Imm
-maybeImm (StInt i)
- | i >= toInteger minInt && i <= toInteger maxInt = Just (ImmInt (fromInteger i))
- | otherwise = Just (ImmInteger i)
-maybeImm (StLitLbl s) = Just (ImmLab s)
-maybeImm (StLitLit s) = Just (strImmLab (cvtLitLit (_UNPK_ s)))
-maybeImm (StCLbl l) = Just (ImmCLbl l)
-maybeImm _ = Nothing
-
-mangleIndexTree :: StixTree -> StixTree
-
-mangleIndexTree (StIndex pk base (StInt i)) =
- StPrim IntAddOp [base, off]
- where
- off = StInt (i * size pk)
- size :: PrimRep -> Integer
- size pk = case kindToSize pk of
- {B -> 1; BU -> 1; W -> 2; WU -> 2; L -> 4; FF -> 4; SF -> 4; _ -> 8}
-
-mangleIndexTree (StIndex pk base off) =
- case pk of
- CharRep -> StPrim IntAddOp [base, off]
- _ -> StPrim IntAddOp [base, off__2]
- where
- off__2 = StPrim SllOp [off, StInt 3]
-
-cvtLitLit :: String -> String
-cvtLitLit "stdin" = "_iob+0" -- This one is probably okay...
-cvtLitLit "stdout" = "_iob+56" -- but these next two are dodgy at best
-cvtLitLit "stderr" = "_iob+112"
-cvtLitLit s
- | isHex s = s
- | otherwise = error ("Native code generator can't handle ``" ++ s ++ "''")
- where
- isHex ('0':'x':xs) = all isHexDigit xs
- isHex _ = False
- -- Now, where have I seen this before?
- isHexDigit c = isDigit c || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'
-
-
-\end{code}
-
-spRel gives us a stack relative addressing mode for volatile temporaries
-and for excess call arguments.
-
-\begin{code}
-
-spRel
- :: Int -- desired stack offset in words, positive or negative
- -> Addr
-spRel n = AddrRegImm sp (ImmInt (n * 8))
-
-stackArgLoc = 0 :: Int -- where to stack extra call arguments (beyond 6)
-
-\end{code}
-
-\begin{code}
-
-getNewRegNCG :: PrimRep -> UniqSM Reg
-getNewRegNCG pk =
- getUnique `thenUs` \ u ->
- returnUs (mkReg u pk)
-
-\end{code}
%
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1996
%
\begin{code}
#include "HsVersions.h"
-#include "../../includes/platform.h"
-#include "../../includes/GhcConstants.h"
-
-module AsmCodeGen (
- writeRealAsm,
- dumpRealAsm,
-
- -- And, I guess we need these...
- AbstractC, GlobalSwitch, SwitchResult,
- UniqSupply, UniqSM(..)
- ) where
-
-import AbsCSyn ( AbstractC )
-import AbsCStixGen ( genCodeAbstractC )
-import PrelInfo ( PrimRep, PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import CmdLineOpts ( GlobalSwitch(..), stringSwitchSet, switchIsOn, SwitchResult(..) )
-import MachDesc
-import Maybes ( Maybe(..) )
-import Outputable
-#if alpha_TARGET_ARCH
-import AlphaDesc ( mkAlpha )
-#endif
-#if i386_TARGET_ARCH
-import I386Desc ( mkI386 )
-#endif
-#if sparc_TARGET_ARCH
-import SparcDesc ( mkSparc )
-#endif
-import Stix
-import UniqSupply
-import Unpretty
-import Util
+
+module AsmCodeGen ( writeRealAsm, dumpRealAsm ) where
+
+import Ubiq{-uitous-}
+
+import MachMisc
+import MachRegs
+import MachCode
+import PprMach
+
+import AbsCStixGen ( genCodeAbstractC )
+import AbsCSyn ( AbstractC, MagicId )
+import AsmRegAlloc ( runRegAllocate )
+import OrdList ( OrdList )
+import PrimOp ( commutableOp, PrimOp(..) )
+import PrimRep ( PrimRep{-instance Eq-} )
+import RegAllocInfo ( mkMRegsState, MRegsState )
+import Stix ( StixTree(..), StixReg(..), CodeSegment )
+import UniqSupply ( returnUs, thenUs, mapUs, UniqSM(..) )
+import Unpretty ( uppAppendFile, uppShow, uppAboves, Unpretty(..) )
\end{code}
-This is a generic assembly language generator for the Glasgow Haskell
-Compiler. It has been a long time in germinating, basically due to
-time constraints and the large spectrum of design possibilities.
-Presently it generates code for:
-\begin{itemize}
-\item Sparc
-\end{itemize}
-In the pipeline (sic) are plans and/or code for 680x0, 386/486.
-
-The code generator presumes the presence of a working C port. This is
-because any code that cannot be compiled (e.g. @casm@s) is re-directed
-via this route. It also help incremental development. Because this
-code generator is specially written for the Abstract C produced by the
-Glasgow Haskell Compiler, several optimisation opportunities are open
-to us that are not open to @gcc@. In particular, we know that the A
-and B stacks and the Heap are all mutually exclusive wrt. aliasing,
-and that expressions have no side effects (all state transformations
-are top level objects).
-
-There are two main components to the code generator.
-\begin{itemize}
-\item Abstract C is considered in statements,
- with a Twig-like system handling each statement in turn.
-\item A scheduler turns the tree of assembly language orderings
- into a sequence suitable for input to an assembler.
-\end{itemize}
-The @codeGenerate@ function returns the final assembly language output
-(as a String). We can return a string, because there is only one way
-of printing the output suitable for assembler consumption. It also
-allows limited abstraction of different machines from the Main module.
-
-The first part is the actual assembly language generation. First we
-split up the Abstract C into individual functions, then consider
-chunks in isolation, giving back an @OrdList@ of assembly language
-instructions. The generic algorithm is heavily inspired by Twig
-(ref), but also draws concepts from (ref). The basic idea is to
-(dynamically) walk the Abstract C syntax tree, annotating it with
-possible code matches. For example, on the Sparc, a possible match
-(with its translation) could be
-@
- :=
- / \
- i r2 => ST r2,[r1]
- |
- r1
-@
-where @r1,r2@ are registers, and @i@ is an indirection. The Twig
-bit twiddling algorithm for tree matching has been abandoned. It is
-replaced with a more direct scheme. This is because, after careful
-consideration it is felt that the overhead of handling many bit
-patterns would be heavier that simply looking at the syntax of the
-tree at the node being considered, and dynamically choosing and
-pruning rules.
-
-The ultimate result of the first part is a Set of ordering lists of
-ordering lists of assembly language instructions (yes, really!), where
-each element in the set is basic chunk. Now several (generic)
-simplifications and transformations can be performed. This includes
-ones that turn the the ordering of orderings into just a single
-ordering list. (The equivalent of applying @concat@ to a list of
-lists.) A lot of the re-ordering and optimisation is actually done
-(generically) here! The final part, the scheduler, can now be used on
-this structure. The code sequence is optimised (obviously) to avoid
-stalling the pipeline. This part {\em has} to be heavily machine
-dependent.
-
-[The above seems to describe mostly dreamware. -- JSM]
-
-The flag that needs to be added is -fasm-<platform> where platform is one of
-the choices below.
+The 96/03 native-code generator has machine-independent and
+machine-dependent modules (those \tr{#include}'ing \tr{NCG.h}).
+
+This module (@AsmCodeGen@) is the top-level machine-independent
+module. It uses @AbsCStixGen.genCodeAbstractC@ to produce @StixTree@s
+(defined in module @Stix@), using support code from @StixInfo@ (info
+tables), @StixPrim@ (primitive operations), @StixMacro@ (Abstract C
+macros), and @StixInteger@ (GMP arbitrary-precision operations).
+
+Before entering machine-dependent land, we do some machine-independent
+@genericOpt@imisations (defined below) on the @StixTree@s.
+
+We convert to the machine-specific @Instr@ datatype with
+@stmt2Instrs@, assuming an ``infinite'' supply of registers. We then
+use a machine-independent register allocator (@runRegAllocate@) to
+rejoin reality. Obviously, @runRegAllocate@ has machine-specific
+helper functions (see about @RegAllocInfo@ below).
+
+The machine-dependent bits break down as follows:
+\begin{description}
+\item[@MachRegs@:] Everything about the target platform's machine
+ registers (and immediate operands, and addresses, which tend to
+ intermingle/interact with registers).
+
+\item[@MachMisc@:] Includes the @Instr@ datatype (possibly should
+ have a module of its own), plus a miscellany of other things
+ (e.g., @targetDoubleSize@, @smStablePtrTable@, ...)
+
+\item[@MachCode@:] @stmt2Instrs@ is where @Stix@ stuff turns into
+ machine instructions.
+\item[@PprMach@:] @pprInstr@ turns an @Instr@ into text (well, really
+ an @Unpretty@).
+
+\item[@RegAllocInfo@:] In the register allocator, we manipulate
+ @MRegsState@s, which are @BitSet@s, one bit per machine register.
+ When we want to say something about a specific machine register
+ (e.g., ``it gets clobbered by this instruction''), we set/unset
+ its bit. Obviously, we do this @BitSet@ thing for efficiency
+ reasons.
+
+ The @RegAllocInfo@ module collects together the machine-specific
+ info needed to do register allocation.
+\end{description}
+
+So, here we go:
\begin{code}
-writeRealAsm :: (GlobalSwitch -> SwitchResult) -> _FILE -> AbstractC -> UniqSupply -> PrimIO ()
+writeRealAsm :: _FILE -> AbstractC -> UniqSupply -> IO ()
-writeRealAsm flags file absC uniq_supply
- = uppAppendFile file 80 (runNCG (code flags absC) uniq_supply)
+writeRealAsm file absC us
+ = uppAppendFile file 80 (runNCG absC us)
-dumpRealAsm :: (GlobalSwitch -> SwitchResult) -> AbstractC -> UniqSupply -> String
+dumpRealAsm :: AbstractC -> UniqSupply -> String
-dumpRealAsm flags absC uniq_supply = uppShow 80 (runNCG (code flags absC) uniq_supply)
+dumpRealAsm absC us = uppShow 80 (runNCG absC us)
-runNCG m uniq_supply = m uniq_supply
+runNCG absC
+ = genCodeAbstractC absC `thenUs` \ treelists ->
+ let
+ stix = map (map genericOpt) treelists
+ in
+ codeGen stix
+\end{code}
-code flags absC =
- genCodeAbstractC target absC `thenUs` \ treelists ->
+@codeGen@ is the top-level code-generation function:
+\begin{code}
+codeGen :: [[StixTree]] -> UniqSM Unpretty
+
+codeGen trees
+ = mapUs genMachCode trees `thenUs` \ dynamic_codes ->
let
- stix = map (map (genericOpt target)) treelists
+ static_instrs = scheduleMachCode dynamic_codes
in
- codeGen {-target-} sty stix
- where
- sty = PprForAsm (switchIsOn flags) (underscore {-target-}) (fmtAsmLbl {-target-})
-
- (target, codeGen, underscore, fmtAsmLbl)
- = case stringSwitchSet flags AsmTarget of
-#if ! OMIT_NATIVE_CODEGEN
-# if alpha_TARGET_ARCH
- Just _ {-???"alpha-dec-osf1"-} -> mkAlpha flags
-# endif
-# if i386_TARGET_ARCH
- Just _ {-???"i386_unknown_linuxaout"-} -> mkI386 True flags
-# endif
-# if sparc_sun_sunos4_TARGET
- Just _ {-???"sparc-sun-sunos4"-} -> mkSparc True flags
-# endif
-# if sparc_sun_solaris2_TARGET
- Just _ {-???"sparc-sun-solaris2"-} -> mkSparc False flags
-# endif
-#endif
- _ -> error
- ("ERROR:Trying to generate assembly language for an unsupported architecture\n"++
- "(or one for which this build is not configured).")
+ returnUs (uppAboves (map pprInstr static_instrs))
+\end{code}
+Top level code generator for a chunk of stix code:
+\begin{code}
+genMachCode :: [StixTree] -> UniqSM InstrList
+
+genMachCode stmts
+ = mapUs stmt2Instrs stmts `thenUs` \ blocks ->
+ returnUs (foldr (.) id blocks asmVoid)
+\end{code}
+
+The next bit does the code scheduling. The scheduler must also deal
+with register allocation of temporaries. Much parallelism can be
+exposed via the OrdList, but more might occur, so further analysis
+might be needed.
+
+\begin{code}
+scheduleMachCode :: [InstrList] -> [Instr]
+
+scheduleMachCode
+ = concat . map (runRegAllocate freeRegsState reservedRegs)
+ where
+ freeRegsState = mkMRegsState (extractMappedRegNos freeRegs)
\end{code}
%************************************************************************
%* *
%************************************************************************
-This is called between translating Abstract C to its Tree
-and actually using the Native Code Generator to generate
-the annotations. It's a chance to do some strength reductions.
+This is called between translating Abstract C to its Tree and actually
+using the Native Code Generator to generate the annotations. It's a
+chance to do some strength reductions.
** Remember these all have to be machine independent ***
-Note that constant-folding should have already happened, but we might have
-introduced some new opportunities for constant-folding wrt address manipulations.
+Note that constant-folding should have already happened, but we might
+have introduced some new opportunities for constant-folding wrt
+address manipulations.
\begin{code}
-
-genericOpt
- :: Target
- -> StixTree
- -> StixTree
-
+genericOpt :: StixTree -> StixTree
\end{code}
For most nodes, just optimize the children.
\begin{code}
--- hacking with Uncle Will:
-#define target_STRICT target@(Target _ _ _ _ _ _ _ _)
-
-genericOpt target_STRICT (StInd pk addr) =
- StInd pk (genericOpt target addr)
-
-genericOpt target (StAssign pk dst src) =
- StAssign pk (genericOpt target dst) (genericOpt target src)
+genericOpt (StInd pk addr) = StInd pk (genericOpt addr)
-genericOpt target (StJump addr) =
- StJump (genericOpt target addr)
+genericOpt (StAssign pk dst src)
+ = StAssign pk (genericOpt dst) (genericOpt src)
-genericOpt target (StCondJump addr test) =
- StCondJump addr (genericOpt target test)
+genericOpt (StJump addr) = StJump (genericOpt addr)
-genericOpt target (StCall fn pk args) =
- StCall fn pk (map (genericOpt target) args)
+genericOpt (StCondJump addr test)
+ = StCondJump addr (genericOpt test)
+genericOpt (StCall fn pk args)
+ = StCall fn pk (map genericOpt args)
\end{code}
-Fold indices together when the types match.
-
+Fold indices together when the types match:
\begin{code}
+genericOpt (StIndex pk (StIndex pk' base off) off')
+ | pk == pk'
+ = StIndex pk (genericOpt base)
+ (genericOpt (StPrim IntAddOp [off, off']))
-genericOpt target (StIndex pk (StIndex pk' base off) off')
- | pk == pk' =
- StIndex pk (genericOpt target base)
- (genericOpt target (StPrim IntAddOp [off, off']))
-
-genericOpt target (StIndex pk base off) =
- StIndex pk (genericOpt target base)
- (genericOpt target off)
-
+genericOpt (StIndex pk base off)
+ = StIndex pk (genericOpt base) (genericOpt off)
\end{code}
-For primOps, we first optimize the children, and then we try our hand
+For PrimOps, we first optimize the children, and then we try our hand
at some constant-folding.
\begin{code}
-
-genericOpt target (StPrim op args) =
- primOpt op (map (genericOpt target) args)
-
+genericOpt (StPrim op args) = primOpt op (map genericOpt args)
\end{code}
-Replace register leaves with appropriate StixTrees for the given target.
-(Oh, so this is why we've been hauling the target around!)
+Replace register leaves with appropriate StixTrees for the given
+target.
\begin{code}
+genericOpt leaf@(StReg (StixMagicId id))
+ = case (stgReg id) of
+ Always tree -> genericOpt tree
+ Save _ -> leaf
-genericOpt target leaf@(StReg (StixMagicId id)) =
- case stgReg target id of
- Always tree -> genericOpt target tree
- Save _ -> leaf
-
-genericOpt target other = other
-
+genericOpt other = other
\end{code}
-Now, try to constant-fold the primOps. The arguments have
-already been optimized and folded.
+Now, try to constant-fold the PrimOps. The arguments have already
+been optimized and folded.
\begin{code}
-
primOpt
:: PrimOp -- The operation from an StPrim
-> [StixTree] -- The optimized arguments
-> StixTree
-primOpt op arg@[StInt x] =
- case op of
+primOpt op arg@[StInt x]
+ = case op of
IntNegOp -> StInt (-x)
IntAbsOp -> StInt (abs x)
_ -> StPrim op arg
-primOpt op args@[StInt x, StInt y] =
- case op of
- CharGtOp -> StInt (if x > y then 1 else 0)
+primOpt op args@[StInt x, StInt y]
+ = case op of
+ CharGtOp -> StInt (if x > y then 1 else 0)
CharGeOp -> StInt (if x >= y then 1 else 0)
CharEqOp -> StInt (if x == y then 1 else 0)
CharNeOp -> StInt (if x /= y then 1 else 0)
- CharLtOp -> StInt (if x < y then 1 else 0)
+ CharLtOp -> StInt (if x < y then 1 else 0)
CharLeOp -> StInt (if x <= y then 1 else 0)
IntAddOp -> StInt (x + y)
IntSubOp -> StInt (x - y)
IntMulOp -> StInt (x * y)
IntQuotOp -> StInt (x `quot` y)
IntRemOp -> StInt (x `rem` y)
- IntGtOp -> StInt (if x > y then 1 else 0)
+ IntGtOp -> StInt (if x > y then 1 else 0)
IntGeOp -> StInt (if x >= y then 1 else 0)
IntEqOp -> StInt (if x == y then 1 else 0)
IntNeOp -> StInt (if x /= y then 1 else 0)
- IntLtOp -> StInt (if x < y then 1 else 0)
+ IntLtOp -> StInt (if x < y then 1 else 0)
IntLeOp -> StInt (if x <= y then 1 else 0)
_ -> StPrim op args
-
\end{code}
When possible, shift the constants to the right-hand side, so that we
can match for strength reductions. Note that the code generator will
-also assume that constants have been shifted to the right when possible.
+also assume that constants have been shifted to the right when
+possible.
\begin{code}
primOpt op [x@(StInt _), y] | commutableOp op = primOpt op [y, x]
We can often do something with constants of 0 and 1 ...
\begin{code}
-primOpt op args@[x, y@(StInt 0)] =
- case op of
+primOpt op args@[x, y@(StInt 0)]
+ = case op of
IntAddOp -> x
IntSubOp -> x
IntMulOp -> y
- AndOp -> y
- OrOp -> x
- SllOp -> x
- SraOp -> x
- SrlOp -> x
- ISllOp -> x
- ISraOp -> x
- ISrlOp -> x
- _ -> StPrim op args
-
-primOpt op args@[x, y@(StInt 1)] =
- case op of
- IntMulOp -> x
+ AndOp -> y
+ OrOp -> x
+ SllOp -> x
+ SraOp -> x
+ SrlOp -> x
+ ISllOp -> x
+ ISraOp -> x
+ ISrlOp -> x
+ _ -> StPrim op args
+
+primOpt op args@[x, y@(StInt 1)]
+ = case op of
+ IntMulOp -> x
IntQuotOp -> x
- IntRemOp -> StInt 0
- _ -> StPrim op args
+ IntRemOp -> StInt 0
+ _ -> StPrim op args
\end{code}
Now look for multiplication/division by powers of 2 (integers).
\begin{code}
-primOpt op args@[x, y@(StInt n)] =
- case op of
- IntMulOp -> case exact_log2 n of
+primOpt op args@[x, y@(StInt n)]
+ = case op of
+ IntMulOp -> case exactLog2 n of
Nothing -> StPrim op args
- Just p -> StPrim SllOp [x, StInt p]
- IntQuotOp -> case exact_log2 n of
+ Just p -> StPrim SllOp [x, StInt p]
+ IntQuotOp -> case exactLog2 n of
Nothing -> StPrim op args
- Just p -> StPrim SraOp [x, StInt p]
+ Just p -> StPrim SraOp [x, StInt p]
_ -> StPrim op args
\end{code}
\begin{code}
primOpt op args = StPrim op args
\end{code}
-
-The commutable ops are those for which we will try to move constants
-to the right hand side for strength reduction.
-
-\begin{code}
-commutableOp :: PrimOp -> Bool
-
-commutableOp CharEqOp = True
-commutableOp CharNeOp = True
-commutableOp IntAddOp = True
-commutableOp IntMulOp = True
-commutableOp AndOp = True
-commutableOp OrOp = True
-commutableOp IntEqOp = True
-commutableOp IntNeOp = True
-commutableOp IntegerAddOp = True
-commutableOp IntegerMulOp = True
-commutableOp FloatAddOp = True
-commutableOp FloatMulOp = True
-commutableOp FloatEqOp = True
-commutableOp FloatNeOp = True
-commutableOp DoubleAddOp = True
-commutableOp DoubleMulOp = True
-commutableOp DoubleEqOp = True
-commutableOp DoubleNeOp = True
-commutableOp _ = False
-\end{code}
-
-This algorithm for determining the $\log_2$ of exact powers of 2 comes
-from gcc. It requires bit manipulation primitives, so we have a ghc
-version and an hbc version. Other Haskell compilers are on their own.
-
-\begin{code}
-w2i x = word2Int# x
-i2w x = int2Word# x
-i2w_s x = (x::Int#)
-
-exact_log2 :: Integer -> Maybe Integer
-exact_log2 x
- | x <= 0 || x >= 2147483648 = Nothing
- | otherwise = case fromInteger x of
- I# x# -> if (w2i ((i2w x#) `and#` (i2w (0# -# x#))) /=# x#) then Nothing
- else Just (toInteger (I# (pow2 x#)))
-
- where pow2 x# | x# ==# 1# = 0#
- | otherwise = 1# +# pow2 (w2i (i2w x# `shiftr` i2w_s 1#))
-
- shiftr x y = shiftRA# x y
-\end{code}
%
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1996
%
+\section[AsmRegAlloc]{Register allocator}
\begin{code}
#include "HsVersions.h"
-#include "../../includes/platform.h"
-#include "../../includes/GhcConstants.h"
-module AsmRegAlloc (
- FutureLive(..), RegLiveness(..), RegUsage(..), Reg(..),
- MachineRegisters(..), MachineCode(..),
+module AsmRegAlloc ( runRegAllocate, runHairyRegAllocate ) where
- mkReg, runRegAllocate, runHairyRegAllocate,
- extractMappedRegNos
+import Ubiq{-uitous-}
- -- And, for self-sufficiency
- ) where
+import MachCode ( InstrList(..) )
+import MachMisc ( Instr )
+import MachRegs
+import RegAllocInfo
-import CLabel ( CLabel )
-import FiniteMap
-import MachDesc
-import Maybes ( maybeToBool, Maybe(..) )
-import OrdList -- ( mkUnitList, mkSeqList, mkParList, OrdList )
-import Outputable
-import Pretty
-import UniqSet
-import Unique ( Unique )
-import Util
-
-#if ! OMIT_NATIVE_CODEGEN
-
-# if alpha_TARGET_ARCH
-import AlphaCode -- ( AlphaInstr, AlphaRegs ) -- for specializing
-
-{-# SPECIALIZE
- runRegAllocate :: AlphaRegs -> [Int] -> (OrdList AlphaInstr) -> [AlphaInstr]
- #-}
-# endif
-
-# if i386_TARGET_ARCH
-import I386Code -- ( I386Instr, I386Regs ) -- for specializing
-
-{-# SPECIALIZE
- runRegAllocate :: I386Regs -> [Int] -> (OrdList I386Instr) -> [I386Instr]
- #-}
-# endif
-
-# if sparc_TARGET_ARCH
-import SparcCode -- ( SparcInstr, SparcRegs ) -- for specializing
-
-{-# SPECIALIZE
- runRegAllocate :: SparcRegs -> [Int] -> (OrdList SparcInstr) -> [SparcInstr]
- #-}
-# endif
-
-#endif
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[Reg]{Real registers}
-%* *
-%************************************************************************
-
-Static Registers correspond to actual machine registers. These should
-be avoided until the last possible moment.
-
-Dynamic registers are allocated on the fly, usually to represent a single
-value in the abstract assembly code (i.e. dynamic registers are usually
-single assignment). Ultimately, they are mapped to available machine
-registers before spitting out the code.
-
-\begin{code}
-
-data Reg = FixedReg FAST_INT -- A pre-allocated machine register
-
- | MappedReg FAST_INT -- A dynamically allocated machine register
-
- | MemoryReg Int PrimRep -- A machine "register" actually held in a memory
- -- allocated table of registers which didn't fit
- -- in real registers.
-
- | UnmappedReg Unique PrimRep -- One of an infinite supply of registers,
- -- always mapped to one of the earlier two
- -- before we're done.
- -- No thanks: deriving (Eq)
-
-mkReg :: Unique -> PrimRep -> Reg
-mkReg = UnmappedReg
-
-instance Text Reg where
- showsPrec _ (FixedReg i) = showString "%" . shows IBOX(i)
- showsPrec _ (MappedReg i) = showString "%" . shows IBOX(i)
- showsPrec _ (MemoryReg i _) = showString "%M" . shows i
- showsPrec _ (UnmappedReg i _) = showString "%U" . shows i
-
-#ifdef DEBUG
-instance Outputable Reg where
- ppr sty r = ppStr (show r)
-#endif
-
-cmpReg (FixedReg i) (FixedReg i') = cmp_ihash i i'
-cmpReg (MappedReg i) (MappedReg i') = cmp_ihash i i'
-cmpReg (MemoryReg i _) (MemoryReg i' _) = cmp_i i i'
-cmpReg (UnmappedReg u _) (UnmappedReg u' _) = cmp u u'
-cmpReg r1 r2 =
- let tag1 = tagReg r1
- tag2 = tagReg r2
- in
- if tag1 _LT_ tag2 then LT_ else GT_
- where
- tagReg (FixedReg _) = (ILIT(1) :: FAST_INT)
- tagReg (MappedReg _) = ILIT(2)
- tagReg (MemoryReg _ _) = ILIT(3)
- tagReg (UnmappedReg _ _) = ILIT(4)
-
-cmp_i :: Int -> Int -> TAG_
-cmp_i a1 a2 = if a1 == a2 then EQ_ else if a1 < a2 then LT_ else GT_
-
-cmp_ihash :: FAST_INT -> FAST_INT -> TAG_
-cmp_ihash a1 a2 = if a1 _EQ_ a2 then EQ_ else if a1 _LT_ a2 then LT_ else GT_
-
-instance Eq Reg where
- a == b = case cmpReg a b of { EQ_ -> True; _ -> False }
- a /= b = case cmpReg a b of { EQ_ -> False; _ -> True }
-
-instance Ord Reg where
- a <= b = case cmpReg a b of { LT_ -> True; EQ_ -> True; GT__ -> False }
- a < b = case cmpReg a b of { LT_ -> True; EQ_ -> False; GT__ -> False }
- a >= b = case cmpReg a b of { LT_ -> False; EQ_ -> True; GT__ -> True }
- a > b = case cmpReg a b of { LT_ -> False; EQ_ -> False; GT__ -> True }
- _tagCmp a b = case cmpReg a b of { LT_ -> _LT; EQ_ -> _EQ; GT__ -> _GT }
-
-instance NamedThing Reg where
- -- the *only* method that should be defined is "getItsUnique"!
- -- (so we can use UniqFMs/UniqSets on Regs
- getItsUnique (UnmappedReg u _) = u
- getItsUnique (FixedReg i) = mkPseudoUnique1 IBOX(i)
- getItsUnique (MappedReg i) = mkPseudoUnique2 IBOX(i)
- getItsUnique (MemoryReg i _) = mkPseudoUnique3 i
+import BitSet ( BitSet )
+import FiniteMap ( emptyFM, addListToFM, delListFromFM, lookupFM, keysFM )
+import Maybes ( maybeToBool )
+import OrdList ( mkEmptyList, mkUnitList, mkSeqList, mkParList,
+ flattenOrdList, OrdList
+ )
+import Stix ( StixTree )
+import UniqSupply ( mkBuiltinUnique )
+import Util ( mapAccumB, panic )
\end{code}
This is the generic register allocator.
-%************************************************************************
-%* *
-\subsection[RegPlace]{Map Stix registers to {\em real} registers}
-%* *
-%************************************************************************
-
-An important point: The @regUsage@ function for a particular assembly language
-must not refer to fixed registers, such as Hp, SpA, etc. The source and destination
-lists should only refer to dynamically allocated registers or static registers
-from the free list. As far as we are concerned, the fixed registers simply don't
-exist (for allocation purposes, anyway).
-
-\begin{code}
-
-class MachineRegisters a where
- mkMRegs :: [Int] -> a
- possibleMRegs :: PrimRep -> a -> [Int]
- useMReg :: a -> FAST_INT -> a
- useMRegs :: a -> [Int] -> a
- freeMReg :: a -> FAST_INT -> a
- freeMRegs :: a -> [Int] -> a
-
-type RegAssignment = FiniteMap Reg Reg
-type RegConflicts = FiniteMap Int (UniqSet Reg)
-
-data FutureLive
- = FL (UniqSet Reg)
- (FiniteMap CLabel (UniqSet Reg))
-fstFL (FL a b) = a
-
-data RegHistory a
- = RH a
- Int
- RegAssignment
-
-data RegFuture
- = RF (UniqSet Reg) -- in use
- FutureLive -- future
- RegConflicts
-
-data RegInfo a
- = RI (UniqSet Reg) -- in use
- (UniqSet Reg) -- sources
- (UniqSet Reg) -- destinations
- [Reg] -- last used
- RegConflicts
-
-data RegUsage
- = RU (UniqSet Reg)
- (UniqSet Reg)
-
-data RegLiveness
- = RL (UniqSet Reg)
- FutureLive
-
-class MachineCode a where
- regUsage :: a -> RegUsage
- regLiveness :: a -> RegLiveness -> RegLiveness
- patchRegs :: a -> (Reg -> Reg) -> a
- spillReg :: Reg -> Reg -> OrdList a
- loadReg :: Reg -> Reg -> OrdList a
-\end{code}
-
-First we try something extremely simple.
-If that fails, we have to do things the hard way.
+First we try something extremely simple. If that fails, we have to do
+things the hard way.
\begin{code}
runRegAllocate
- :: (MachineRegisters a, MachineCode b)
- => a
- -> [Int]
- -> (OrdList b)
- -> [b]
-
-runRegAllocate regs reserve_regs instrs =
- case simpleAlloc of
+ :: MRegsState
+ -> [RegNo]
+ -> InstrList
+ -> [Instr]
+
+runRegAllocate regs reserve_regs instrs
+ = case simpleAlloc of
Just x -> x
Nothing -> hairyAlloc
where
flatInstrs = flattenOrdList instrs
- simpleAlloc = simpleRegAlloc regs [] emptyFM flatInstrs
- hairyAlloc = hairyRegAlloc regs reserve_regs flatInstrs
+ simpleAlloc = simpleRegAlloc regs [] emptyFM flatInstrs
+ hairyAlloc = hairyRegAlloc regs reserve_regs flatInstrs
runHairyRegAllocate -- use only hairy for i386!
- :: (MachineRegisters a, MachineCode b)
- => a
- -> [Int]
- -> (OrdList b)
- -> [b]
+ :: MRegsState
+ -> [RegNo]
+ -> InstrList
+ -> [Instr]
runHairyRegAllocate regs reserve_regs instrs
= hairyRegAlloc regs reserve_regs flatInstrs
we generate.
\begin{code}
-
simpleRegAlloc
- :: (MachineRegisters a, MachineCode b)
- => a -- registers to select from
+ :: MRegsState -- registers to select from
-> [Reg] -- live static registers
-> RegAssignment -- mapping of dynamics to statics
- -> [b] -- code
- -> Maybe [b]
+ -> [Instr] -- code
+ -> Maybe [Instr]
simpleRegAlloc _ _ _ [] = Just []
-simpleRegAlloc free live env (instr:instrs) =
- if null deadSrcs && maybeToBool newAlloc && maybeToBool instrs2 then
+
+simpleRegAlloc free live env (instr:instrs)
+ = if null deadSrcs && maybeToBool newAlloc && maybeToBool instrs2 then
Just (instr3 : instrs3)
else
Nothing
where
instr3 = patchRegs instr (lookup env2)
- (srcs, dsts) = case regUsage instr of { RU s d -> (uniqSetToList s, uniqSetToList d) }
+ (srcs, dsts) = case regUsage instr of { RU s d -> (regSetToList s, regSetToList d) }
lookup env x = case lookupFM env x of {Just y -> y; Nothing -> x}
instrs3 = case instrs2 of Just x -> x
allocateNewReg
- :: MachineRegisters a
- => Reg
- -> Maybe (a, [(Reg, Reg)])
- -> Maybe (a, [(Reg, Reg)])
+ :: Reg
+ -> Maybe (MRegsState, [(Reg, Reg)])
+ -> Maybe (MRegsState, [(Reg, Reg)])
allocateNewReg _ Nothing = Nothing
reg = head choices
free2 = free `useMReg` (case reg of {IBOX(reg2) -> reg2} )
prs2 = ((d, MappedReg (case reg of {IBOX(reg2) -> reg2})) : prs)
-
\end{code}
Here is the ``clever'' bit. First go backward (i.e. left), looking for
registers with static placements.
\begin{code}
-
hairyRegAlloc
- :: (MachineRegisters a, MachineCode b)
- => a
- -> [Int]
- -> [b]
- -> [b]
-
-hairyRegAlloc regs reserve_regs instrs =
- case mapAccumB (doRegAlloc reserve_regs)
+ :: MRegsState
+ -> [RegNo]
+ -> [Instr]
+ -> [Instr]
+
+hairyRegAlloc regs reserve_regs instrs
+ = case mapAccumB (doRegAlloc reserve_regs)
(RH regs' 1 emptyFM) noFuture instrs
of (RH _ loc' _, _, instrs') ->
if loc' == 1 then instrs' else
of ((RH _ loc'' _),_,instrs'') ->
if loc'' == loc' then instrs'' else panic "runRegAllocate"
where
- regs' = regs `useMRegs` reserve_regs
- regs'' = mkMRegs reserve_regs `asTypeOf` regs
+ regs' = regs `useMRegs` reserve_regs
+ regs'' = mkMRegsState reserve_regs
do_RegAlloc_Nil = doRegAlloc [] -- out here to avoid CAF (sigh)
do_RegAlloc_Nil
- :: (MachineRegisters a, MachineCode b)
- => RegHistory a
+ :: RegHistory MRegsState
-> RegFuture
- -> b
- -> (RegHistory a, RegFuture, b)
+ -> Instr
+ -> (RegHistory MRegsState, RegFuture, Instr)
noFuture :: RegFuture
-noFuture = RF emptyUniqSet (FL emptyUniqSet emptyFM) emptyFM
+noFuture = RF emptyRegSet (FL emptyRegSet emptyFM) emptyFM
\end{code}
Here we patch instructions that reference ``registers'' which are really in
allocation again after all of this is said and done.
\begin{code}
-
-patchMem
- :: MachineCode a
- => [a]
- -> OrdList a
+patchMem :: [Instr] -> InstrList
patchMem cs = foldr (mkSeqList . patchMem') mkEmptyList cs
-patchMem'
- :: MachineCode a
- => a
- -> OrdList a
+patchMem' :: Instr -> InstrList
-patchMem' instr =
- if null memSrcs && null memDsts then mkUnitList instr
+patchMem' instr
+ = if null memSrcs && null memDsts then mkUnitList instr
else mkSeqList
(foldr mkParList mkEmptyList loadSrcs)
(mkSeqList instr'
memToDyn (MemoryReg i pk) = UnmappedReg (mkBuiltinUnique i) pk
memToDyn other = other
- memSrcs = [ r | r@(MemoryReg _ _) <- uniqSetToList srcs]
- memDsts = [ r | r@(MemoryReg _ _) <- uniqSetToList dsts]
+ memSrcs = [ r | r@(MemoryReg _ _) <- regSetToList srcs]
+ memDsts = [ r | r@(MemoryReg _ _) <- regSetToList dsts]
loadSrcs = map load memSrcs
spillDsts = map spill memDsts
spill mem = spillReg (memToDyn mem) mem
instr' = mkUnitList (patchRegs instr memToDyn)
-
\end{code}
\begin{code}
-
doRegAlloc
- :: (MachineRegisters a, MachineCode b)
- => [Int]
- -> RegHistory a
+ :: [RegNo]
+ -> RegHistory MRegsState
-> RegFuture
- -> b
- -> (RegHistory a, RegFuture, b)
+ -> Instr
+ -> (RegHistory MRegsState, RegFuture, Instr)
doRegAlloc reserved_regs free_env in_use instr = (free_env', in_use', instr')
where
(free_env', instr') = doRegAlloc' reserved_regs free_env info instr
(in_use', info) = getUsage in_use instr
-
\end{code}
\begin{code}
-
getUsage
- :: MachineCode a
- => RegFuture
- -> a
- -> (RegFuture, RegInfo a)
+ :: RegFuture
+ -> Instr
+ -> (RegFuture, RegInfo Instr)
-getUsage (RF next_in_use future reg_conflicts) instr =
- (RF in_use' future' reg_conflicts',
+getUsage (RF next_in_use future reg_conflicts) instr
+ = (RF in_use' future' reg_conflicts',
RI in_use' srcs dsts last_used reg_conflicts')
where (RU srcs dsts) = regUsage instr
(RL in_use future') = regLiveness instr (RL next_in_use future)
- live_through = in_use `minusUniqSet` dsts
- last_used = [ r | r <- uniqSetToList srcs,
- not (r `elementOfUniqSet` (fstFL future) || r `elementOfUniqSet` in_use)]
- in_use' = srcs `unionUniqSets` live_through
+ live_through = in_use `minusRegSet` dsts
+ last_used = [ r | r <- regSetToList srcs,
+ not (r `elementOfRegSet` (fstFL future) || r `elementOfRegSet` in_use)]
+ in_use' = srcs `unionRegSets` live_through
reg_conflicts' = case new_conflicts of
[] -> reg_conflicts
_ -> addListToFM reg_conflicts new_conflicts
- new_conflicts = if isEmptyUniqSet live_dynamics then []
+ new_conflicts = if isEmptyRegSet live_dynamics then []
else [ (r, merge_conflicts r)
- | r <- extractMappedRegNos (uniqSetToList dsts) ]
+ | r <- extractMappedRegNos (regSetToList dsts) ]
merge_conflicts reg = case lookupFM reg_conflicts reg of
Nothing -> live_dynamics
- Just conflicts -> conflicts `unionUniqSets` live_dynamics
- live_dynamics = mkUniqSet
- [ r | r@(UnmappedReg _ _) <- uniqSetToList live_through ]
+ Just conflicts -> conflicts `unionRegSets` live_dynamics
+ live_dynamics = mkRegSet
+ [ r | r@(UnmappedReg _ _) <- regSetToList live_through ]
doRegAlloc'
- :: (MachineRegisters a, MachineCode b)
- => [Int]
- -> RegHistory a
- -> RegInfo b
- -> b
- -> (RegHistory a, b)
+ :: [RegNo]
+ -> RegHistory MRegsState
+ -> RegInfo Instr
+ -> Instr
+ -> (RegHistory MRegsState, Instr)
doRegAlloc' reserved (RH frs loc env) (RI in_use srcs dsts lastu conflicts) instr =
where
-- free up new registers
- free :: [Int]
+ free :: [RegNo]
free = extractMappedRegNos (map dynToStatic lastu)
-- (1) free registers that are used last as source operands in this instruction
- frs_not_in_use = frs `useMRegs` (extractMappedRegNos (uniqSetToList in_use))
+ frs_not_in_use = frs `useMRegs` (extractMappedRegNos (regSetToList in_use))
frs' = (frs_not_in_use `freeMRegs` free) `useMRegs` reserved
-- (2) allocate new registers for the destination operands
-- allocate registers for new dynamics
- new_dynamix = [ r | r@(UnmappedReg _ _) <- uniqSetToList dsts, r `not_elem` keysFM env ]
+ new_dynamix = [ r | r@(UnmappedReg _ _) <- regSetToList dsts, r `not_elem` keysFM env ]
(frs'', loc', new) = foldr allocateNewRegs (frs', loc, []) new_dynamix
dynToStatic other = other
allocateNewRegs
- :: MachineRegisters a
- => Reg -> (a, Int, [(Reg, Reg)]) -> (a, Int, [(Reg, Reg)])
+ :: Reg -> (MRegsState, Int, [(Reg, Reg)]) -> (MRegsState, Int, [(Reg, Reg)])
allocateNewRegs d@(UnmappedReg _ pk) (fs, mem, lst) = (fs', mem', (d, f) : lst)
where (fs', f, mem') = case acceptable fs of
acceptable regs = filter no_conflict (possibleMRegs pk regs)
no_conflict reg = case lookupFM conflicts reg of
Nothing -> True
- Just conflicts -> not (d `elementOfUniqSet` conflicts)
-\end{code}
-
-\begin{code}
-extractMappedRegNos :: [Reg] -> [Int]
-
-extractMappedRegNos regs
- = foldr ex [] regs
- where
- ex (MappedReg i) acc = IBOX(i) : acc -- we'll take it
- ex _ acc = acc -- leave it out
+ Just conflicts -> not (d `elementOfRegSet` conflicts)
\end{code}
We keep a local copy of the Prelude function \tr{notElem},
+++ /dev/null
-%
-% (c) The AQUA Project, Glasgow University, 1993-1995
-%
-
-\section[I386Code]{The Native (I386) Machine Code}
-
-\begin{code}
-#define ILIT2(x) ILIT(x)
-#include "HsVersions.h"
-
-module I386Code (
- Addr(..),
- Cond(..), Imm(..), Operand(..), Size(..),
- Base(..), Index(..), Displacement(..),
- I386Code(..),I386Instr(..),I386Regs,
- strImmLit,
- spRel,
-
- printLabeledCodes,
-
- baseRegOffset, stgRegMap, callerSaves,
-
- is13Bits, offset,
-
- kindToSize,
-
- st0, st1, eax, ebx, ecx, edx, esi, edi, ebp, esp,
-
- freeRegs, reservedRegs
-
- -- and, for self-sufficiency ...
- ) where
-
-import AbsCSyn ( MagicId(..) )
-import AsmRegAlloc ( MachineCode(..), MachineRegisters(..), FutureLive(..),
- Reg(..), RegUsage(..), RegLiveness(..)
- )
-import BitSet
-import CgCompInfo ( mAX_Double_REG, mAX_Float_REG, mAX_Vanilla_REG )
-import CLabel ( CLabel, pprCLabel, externallyVisibleCLabel, charToC )
-import FiniteMap
-import Maybes ( Maybe(..), maybeToBool )
-import OrdList ( OrdList, mkUnitList, flattenOrdList )
-import Outputable
-import UniqSet
-import Stix
-import Unpretty
-import Util
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[I386Reg]{The Native (I386) Machine Register Table}
-%* *
-%************************************************************************
-
-- All registers except 7 (esp) are available for use.
-- Only ebx, esi, edi and esp are available across a C call (they are callee-saves).
-- Registers 0-7 have 16-bit counterparts (ax, bx etc.)
-- Registers 0-3 have 8 bit counterparts (ah, bh etc.)
-- Registers 8-15 hold extended floating point values.
-
-ToDo: Deal with stg registers that live as offsets from BaseReg!(JSM)
-
-\begin{code}
-
-gReg,fReg :: Int -> Int
-gReg x = x
-fReg x = (8 + x)
-
-st0, st1, st2, st3, st4, st5, st6, st7, eax, ebx, ecx, edx, esp :: Reg
-eax = case (gReg 0) of { IBOX(g0) -> FixedReg g0 }
-ebx = case (gReg 1) of { IBOX(g1) -> FixedReg g1 }
-ecx = case (gReg 2) of { IBOX(g2) -> FixedReg g2 }
-edx = case (gReg 3) of { IBOX(g3) -> FixedReg g3 }
-esi = case (gReg 4) of { IBOX(g4) -> FixedReg g4 }
-edi = case (gReg 5) of { IBOX(g5) -> FixedReg g5 }
-ebp = case (gReg 6) of { IBOX(g6) -> FixedReg g6 }
-esp = case (gReg 7) of { IBOX(g7) -> FixedReg g7 }
-st0 = realReg (fReg 0)
-st1 = realReg (fReg 1)
-st2 = realReg (fReg 2)
-st3 = realReg (fReg 3)
-st4 = realReg (fReg 4)
-st5 = realReg (fReg 5)
-st6 = realReg (fReg 6)
-st7 = realReg (fReg 7)
-
-realReg n@IBOX(i) = if _IS_TRUE_(freeReg i) then MappedReg i else FixedReg i
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[TheI386Code]{The datatype for i386 assembly language}
-%* *
-%************************************************************************
-
-Here is a definition of the I386 assembly language.
-
-\begin{code}
-
-data Imm = ImmInt Int
- | ImmInteger Integer -- Sigh.
- | ImmCLbl CLabel -- AbstractC Label (with baggage)
- | ImmLab Unpretty -- Simple string label (underscored)
- | ImmLit Unpretty -- Simple string
- deriving ()
-
-strImmLit s = ImmLit (uppStr s)
-
-data Cond = ALWAYS
- | GEU
- | LU
- | EQ
- | GT
- | GE
- | GU
- | LT
- | LE
- | LEU
- | NE
- | NEG
- | POS
- deriving ()
-
-
-data Size = B
- | HB
- | S -- unused ?
- | L
- | F
- | D
- deriving ()
-
-data Operand = OpReg Reg -- register
- | OpImm Imm -- immediate value
- | OpAddr Addr -- memory reference
- deriving ()
-
-data Addr = Addr Base Index Displacement
- | ImmAddr Imm Int
- -- deriving Eq
-
-type Base = Maybe Reg
-type Index = Maybe (Reg, Int) -- Int is 2, 4 or 8
-type Displacement = Imm
-
-data I386Instr =
-
--- Moves.
-
- MOV Size Operand Operand
- | MOVZX Size Operand Operand -- size is the size of operand 2
- | MOVSX Size Operand Operand -- size is the size of operand 2
-
--- Load effective address (also a very useful three-operand add instruction :-)
-
- | LEA Size Operand Operand
-
--- Int Arithmetic.
-
- | ADD Size Operand Operand
- | SUB Size Operand Operand
-
--- Multiplication (signed and unsigned), Division (signed and unsigned),
--- result in %eax, %edx.
-
- | IMUL Size Operand Operand
- | IDIV Size Operand
-
--- Simple bit-twiddling.
-
- | AND Size Operand Operand
- | OR Size Operand Operand
- | XOR Size Operand Operand
- | NOT Size Operand
- | NEGI Size Operand -- NEG instruction (name clash with Cond)
- | SHL Size Operand Operand -- 1st operand must be an Imm
- | SAR Size Operand Operand -- 1st operand must be an Imm
- | SHR Size Operand Operand -- 1st operand must be an Imm
- | NOP
-
--- Float Arithmetic. -- ToDo for 386
-
--- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions
--- right up until we spit them out.
-
- | SAHF -- stores ah into flags
- | FABS
- | FADD Size Operand -- src
- | FADDP
- | FIADD Size Addr -- src
- | FCHS
- | FCOM Size Operand -- src
- | FCOS
- | FDIV Size Operand -- src
- | FDIVP
- | FIDIV Size Addr -- src
- | FDIVR Size Operand -- src
- | FDIVRP
- | FIDIVR Size Addr -- src
- | FICOM Size Addr -- src
- | FILD Size Addr Reg -- src, dst
- | FIST Size Addr -- dst
- | FLD Size Operand -- src
- | FLD1
- | FLDZ
- | FMUL Size Operand -- src
- | FMULP
- | FIMUL Size Addr -- src
- | FRNDINT
- | FSIN
- | FSQRT
- | FST Size Operand -- dst
- | FSTP Size Operand -- dst
- | FSUB Size Operand -- src
- | FSUBP
- | FISUB Size Addr -- src
- | FSUBR Size Operand -- src
- | FSUBRP
- | FISUBR Size Addr -- src
- | FTST
- | FCOMP Size Operand -- src
- | FUCOMPP
- | FXCH
- | FNSTSW
- | FNOP
-
--- Comparison
-
- | TEST Size Operand Operand
- | CMP Size Operand Operand
- | SETCC Cond Operand
-
--- Stack Operations.
-
- | PUSH Size Operand
- | POP Size Operand
-
--- Jumping around.
-
- | JMP Operand -- target
- | JXX Cond CLabel -- target
- | CALL Imm
-
--- Other things.
-
- | CLTD -- sign extend %eax into %edx:%eax
-
--- Pseudo-ops.
-
- | LABEL CLabel
- | COMMENT FAST_STRING
- | SEGMENT CodeSegment
- | ASCII Bool String -- needs backslash conversion?
- | DATA Size [Imm]
-
-type I386Code = OrdList I386Instr
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[TheI386Pretty]{Pretty-printing the I386 Assembly Language}
-%* *
-%************************************************************************
-
-\begin{code}
-
-printLabeledCodes :: PprStyle -> [I386Instr] -> Unpretty
-printLabeledCodes sty codes = uppAboves (map (pprI386Instr sty) codes)
-
-\end{code}
-
-Printing the pieces...
-
-\begin{code}
-
-pprReg :: Size -> Reg -> Unpretty
-
-pprReg s (FixedReg i) = pprI386Reg s i
-pprReg s (MappedReg i) = pprI386Reg s i
-pprReg s other = uppStr (show other) -- should only happen when debugging
-
-pprI386Reg :: Size -> FAST_INT -> Unpretty
-pprI386Reg B i = uppPStr
- (case i of {
- ILIT( 0) -> SLIT("%al"); ILIT( 1) -> SLIT("%bl");
- ILIT( 2) -> SLIT("%cl"); ILIT( 3) -> SLIT("%dl");
- _ -> SLIT("very naughty I386 byte register")
- })
-
-pprI386Reg HB i = uppPStr
- (case i of {
- ILIT( 0) -> SLIT("%ah"); ILIT( 1) -> SLIT("%bh");
- ILIT( 2) -> SLIT("%ch"); ILIT( 3) -> SLIT("%dh");
- _ -> SLIT("very naughty I386 high byte register")
- })
-
-pprI386Reg S i = uppPStr
- (case i of {
- ILIT( 0) -> SLIT("%ax"); ILIT( 1) -> SLIT("%bx");
- ILIT( 2) -> SLIT("%cx"); ILIT( 3) -> SLIT("%dx");
- ILIT( 4) -> SLIT("%si"); ILIT( 5) -> SLIT("%di");
- ILIT( 6) -> SLIT("%bp"); ILIT( 7) -> SLIT("%sp");
- _ -> SLIT("very naughty I386 word register")
- })
-
-pprI386Reg L i = uppPStr
- (case i of {
- ILIT( 0) -> SLIT("%eax"); ILIT( 1) -> SLIT("%ebx");
- ILIT( 2) -> SLIT("%ecx"); ILIT( 3) -> SLIT("%edx");
- ILIT( 4) -> SLIT("%esi"); ILIT( 5) -> SLIT("%edi");
- ILIT( 6) -> SLIT("%ebp"); ILIT( 7) -> SLIT("%esp");
- _ -> SLIT("very naughty I386 double word register")
- })
-
-pprI386Reg F i = uppPStr
- (case i of {
---ToDo: rm these
- ILIT( 8) -> SLIT("%st(0)"); ILIT( 9) -> SLIT("%st(1)");
- ILIT(10) -> SLIT("%st(2)"); ILIT(11) -> SLIT("%st(3)");
- ILIT(12) -> SLIT("%st(4)"); ILIT(13) -> SLIT("%st(5)");
- ILIT(14) -> SLIT("%st(6)"); ILIT(15) -> SLIT("%st(7)");
- _ -> SLIT("very naughty I386 float register")
- })
-
-pprI386Reg D i = uppPStr
- (case i of {
---ToDo: rm these
- ILIT( 8) -> SLIT("%st(0)"); ILIT( 9) -> SLIT("%st(1)");
- ILIT(10) -> SLIT("%st(2)"); ILIT(11) -> SLIT("%st(3)");
- ILIT(12) -> SLIT("%st(4)"); ILIT(13) -> SLIT("%st(5)");
- ILIT(14) -> SLIT("%st(6)"); ILIT(15) -> SLIT("%st(7)");
- _ -> SLIT("very naughty I386 float register")
- })
-
-pprCond :: Cond -> Unpretty -- ToDo
-pprCond x = uppPStr
- (case x of {
- GEU -> SLIT("ae"); LU -> SLIT("b");
- EQ -> SLIT("e"); GT -> SLIT("g");
- GE -> SLIT("ge"); GU -> SLIT("a");
- LT -> SLIT("l"); LE -> SLIT("le");
- LEU -> SLIT("be"); NE -> SLIT("ne");
- NEG -> SLIT("s"); POS -> SLIT("ns");
- ALWAYS -> SLIT("mp"); -- hack
- _ -> error "Spix: iI386Code: unknown conditional!"
- })
-
-pprDollImm :: PprStyle -> Imm -> Unpretty
-
-pprDollImm sty i = uppBesides [ uppPStr SLIT("$"), pprImm sty i]
-
-pprImm :: PprStyle -> Imm -> Unpretty
-
-pprImm sty (ImmInt i) = uppInt i
-pprImm sty (ImmInteger i) = uppInteger i
-pprImm sty (ImmCLbl l) = pprCLabel sty l
-pprImm sty (ImmLab l) = l
-
---pprImm (PprForAsm _ False _) (ImmLab s) = s
---pprImm _ (ImmLab s) = uppBeside (uppChar '_') s
-
-pprImm sty (ImmLit s) = s
-
-pprAddr :: PprStyle -> Addr -> Unpretty
-pprAddr sty (ImmAddr imm off)
- = uppBesides [pprImm sty imm,
- if off > 0 then uppChar '+' else uppPStr SLIT(""),
- if off == 0 then uppPStr SLIT("") else uppInt off
- ]
-pprAddr sty (Addr Nothing Nothing displacement)
- = uppBesides [pprDisp sty displacement]
-pprAddr sty (Addr base index displacement)
- = uppBesides [pprDisp sty displacement,
- uppChar '(',
- pprBase base,
- pprIndex index,
- uppChar ')'
- ]
- where
- pprBase (Just r) = uppBesides [pprReg L r,
- case index of
- Nothing -> uppPStr SLIT("")
- _ -> uppChar ','
- ]
- pprBase _ = uppPStr SLIT("")
- pprIndex (Just (r,i)) = uppBesides [pprReg L r, uppChar ',', uppInt i]
- pprIndex _ = uppPStr SLIT("")
-
-pprDisp sty (ImmInt 0) = uppPStr SLIT("")
---pprDisp sty (ImmInteger 0) = uppPStr SLIT("")
-pprDisp sty d = pprImm sty d
-
-pprOperand :: PprStyle -> Size -> Operand -> Unpretty
-pprOperand sty s (OpReg r) = pprReg s r
-pprOperand sty s (OpImm i) = pprDollImm sty i
-pprOperand sty s (OpAddr ea) = pprAddr sty ea
-
-pprSize :: Size -> Unpretty
-pprSize x = uppPStr
- (case x of
- B -> SLIT("b")
- HB -> SLIT("b")
- S -> SLIT("w")
- L -> SLIT("l")
- F -> SLIT("s")
- D -> SLIT("l")
- )
-
-pprSizeOp :: PprStyle -> FAST_STRING -> Size -> Operand -> Unpretty
-pprSizeOp sty name size op1 =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- pprSize size,
- uppChar ' ',
- pprOperand sty size op1
- ]
-
-pprSizeOpOp :: PprStyle -> FAST_STRING -> Size -> Operand -> Operand -> Unpretty
-pprSizeOpOp sty name size op1 op2 =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- pprSize size,
- uppChar ' ',
- pprOperand sty size op1,
- uppComma,
- pprOperand sty size op2
- ]
-
-pprSizeOpReg :: PprStyle -> FAST_STRING -> Size -> Operand -> Reg -> Unpretty
-pprSizeOpReg sty name size op1 reg =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- pprSize size,
- uppChar ' ',
- pprOperand sty size op1,
- uppComma,
- pprReg size reg
- ]
-
-pprSizeAddr :: PprStyle -> FAST_STRING -> Size -> Addr -> Unpretty
-pprSizeAddr sty name size op =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- pprSize size,
- uppChar ' ',
- pprAddr sty op
- ]
-
-pprSizeAddrReg :: PprStyle -> FAST_STRING -> Size -> Addr -> Reg -> Unpretty
-pprSizeAddrReg sty name size op dst =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- pprSize size,
- uppChar ' ',
- pprAddr sty op,
- uppComma,
- pprReg size dst
- ]
-
-pprOpOp :: PprStyle -> FAST_STRING -> Size -> Operand -> Operand -> Unpretty
-pprOpOp sty name size op1 op2 =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- uppChar ' ',
- pprOperand sty size op1,
- uppComma,
- pprOperand sty size op2
- ]
-
-pprSizeOpOpCoerce :: PprStyle -> FAST_STRING -> Size -> Size -> Operand -> Operand -> Unpretty
-pprSizeOpOpCoerce sty name size1 size2 op1 op2 =
- uppBesides [ uppChar '\t', uppPStr name, uppChar ' ',
- pprOperand sty size1 op1,
- uppComma,
- pprOperand sty size2 op2
- ]
-
-pprCondInstr :: PprStyle -> FAST_STRING -> Cond -> Unpretty -> Unpretty
-pprCondInstr sty name cond arg =
- uppBesides [ uppChar '\t', uppPStr name, pprCond cond, uppChar ' ', arg]
-
-pprI386Instr :: PprStyle -> I386Instr -> Unpretty
-pprI386Instr sty (MOV size (OpReg src) (OpReg dst)) -- hack
- | src == dst
- = uppPStr SLIT("")
-pprI386Instr sty (MOV size src dst)
- = pprSizeOpOp sty SLIT("mov") size src dst
-pprI386Instr sty (MOVZX size src dst) = pprSizeOpOpCoerce sty SLIT("movzx") L size src dst
-pprI386Instr sty (MOVSX size src dst) = pprSizeOpOpCoerce sty SLIT("movxs") L size src dst
-
--- here we do some patching, since the physical registers are only set late
--- in the code generation.
-pprI386Instr sty (LEA size (OpAddr (Addr src1@(Just reg1) (Just (reg2,1)) (ImmInt 0))) dst@(OpReg reg3))
- | reg1 == reg3
- = pprSizeOpOp sty SLIT("add") size (OpReg reg2) dst
-pprI386Instr sty (LEA size (OpAddr (Addr src1@(Just reg1) (Just (reg2,1)) (ImmInt 0))) dst@(OpReg reg3))
- | reg2 == reg3
- = pprSizeOpOp sty SLIT("add") size (OpReg reg1) dst
-pprI386Instr sty (LEA size (OpAddr (Addr src1@(Just reg1) Nothing displ)) dst@(OpReg reg3))
- | reg1 == reg3
- = pprI386Instr sty (ADD size (OpImm displ) dst)
-pprI386Instr sty (LEA size src dst) = pprSizeOpOp sty SLIT("lea") size src dst
-
-pprI386Instr sty (ADD size (OpImm (ImmInt (-1))) dst)
- = pprSizeOp sty SLIT("dec") size dst
-pprI386Instr sty (ADD size (OpImm (ImmInt 1)) dst)
- = pprSizeOp sty SLIT("inc") size dst
-pprI386Instr sty (ADD size src dst)
- = pprSizeOpOp sty SLIT("add") size src dst
-pprI386Instr sty (SUB size src dst) = pprSizeOpOp sty SLIT("sub") size src dst
-pprI386Instr sty (IMUL size op1 op2) = pprSizeOpOp sty SLIT("imul") size op1 op2
-pprI386Instr sty (IDIV size op) = pprSizeOp sty SLIT("idiv") size op
-
-pprI386Instr sty (AND size src dst) = pprSizeOpOp sty SLIT("and") size src dst
-pprI386Instr sty (OR size src dst) = pprSizeOpOp sty SLIT("or") size src dst
-pprI386Instr sty (XOR size src dst) = pprSizeOpOp sty SLIT("xor") size src dst
-pprI386Instr sty (NOT size op) = pprSizeOp sty SLIT("not") size op
-pprI386Instr sty (NEGI size op) = pprSizeOp sty SLIT("neg") size op
-pprI386Instr sty (SHL size imm dst) = pprSizeOpOp sty SLIT("shl") size imm dst
-pprI386Instr sty (SAR size imm dst) = pprSizeOpOp sty SLIT("sar") size imm dst
-pprI386Instr sty (SHR size imm dst) = pprSizeOpOp sty SLIT("shr") size imm dst
-
-pprI386Instr sty (CMP size src dst) = pprSizeOpOp sty SLIT("cmp") size src dst
-pprI386Instr sty (TEST size src dst) = pprSizeOpOp sty SLIT("test") size src dst
-pprI386Instr sty (PUSH size op) = pprSizeOp sty SLIT("push") size op
-pprI386Instr sty (POP size op) = pprSizeOp sty SLIT("pop") size op
-
-pprI386Instr sty (NOP) = uppPStr SLIT("\tnop")
-pprI386Instr sty (CLTD) = uppPStr SLIT("\tcltd")
-
-pprI386Instr sty (SETCC cond op) = pprCondInstr sty SLIT("set") cond (pprOperand sty B op)
-
-pprI386Instr sty (JXX cond lab) = pprCondInstr sty SLIT("j") cond (pprCLabel sty lab)
-
-pprI386Instr sty (JMP (OpImm imm)) = uppBeside (uppPStr SLIT("\tjmp ")) (pprImm sty imm)
-pprI386Instr sty (JMP op) = uppBeside (uppPStr SLIT("\tjmp *")) (pprOperand sty L op)
-
-pprI386Instr sty (CALL imm) =
- uppBesides [ uppPStr SLIT("\tcall "), pprImm sty imm ]
-
-pprI386Instr sty SAHF = uppPStr SLIT("\tsahf")
-pprI386Instr sty FABS = uppPStr SLIT("\tfabs")
-
-pprI386Instr sty (FADD sz src@(OpAddr _))
- = uppBesides [uppPStr SLIT("\tfadd"), pprSize sz, uppChar ' ', pprOperand sty sz src]
-pprI386Instr sty (FADD sz src)
- = uppPStr SLIT("\tfadd")
-pprI386Instr sty FADDP
- = uppPStr SLIT("\tfaddp")
-pprI386Instr sty (FMUL sz src)
- = uppBesides [uppPStr SLIT("\tfmul"), pprSize sz, uppChar ' ', pprOperand sty sz src]
-pprI386Instr sty FMULP
- = uppPStr SLIT("\tfmulp")
-pprI386Instr sty (FIADD size op) = pprSizeAddr sty SLIT("fiadd") size op
-pprI386Instr sty FCHS = uppPStr SLIT("\tfchs")
-pprI386Instr sty (FCOM size op) = pprSizeOp sty SLIT("fcom") size op
-pprI386Instr sty FCOS = uppPStr SLIT("\tfcos")
-pprI386Instr sty (FIDIV size op) = pprSizeAddr sty SLIT("fidiv") size op
-pprI386Instr sty (FDIV sz src)
- = uppBesides [uppPStr SLIT("\tfdiv"), pprSize sz, uppChar ' ', pprOperand sty sz src]
-pprI386Instr sty FDIVP
- = uppPStr SLIT("\tfdivp")
-pprI386Instr sty (FDIVR sz src)
- = uppBesides [uppPStr SLIT("\tfdivr"), pprSize sz, uppChar ' ', pprOperand sty sz src]
-pprI386Instr sty FDIVRP
- = uppPStr SLIT("\tfdivpr")
-pprI386Instr sty (FIDIVR size op) = pprSizeAddr sty SLIT("fidivr") size op
-pprI386Instr sty (FICOM size op) = pprSizeAddr sty SLIT("ficom") size op
-pprI386Instr sty (FILD sz op reg) = pprSizeAddrReg sty SLIT("fild") sz op reg
-pprI386Instr sty (FIST size op) = pprSizeAddr sty SLIT("fist") size op
-pprI386Instr sty (FLD sz (OpImm (ImmCLbl src)))
- = uppBesides [uppPStr SLIT("\tfld"),pprSize sz,uppChar ' ',pprCLabel sty src]
-pprI386Instr sty (FLD sz src)
- = uppBesides [uppPStr SLIT("\tfld"),pprSize sz,uppChar ' ',pprOperand sty sz src]
-pprI386Instr sty FLD1 = uppPStr SLIT("\tfld1")
-pprI386Instr sty FLDZ = uppPStr SLIT("\tfldz")
-pprI386Instr sty (FIMUL size op) = pprSizeAddr sty SLIT("fimul") size op
-pprI386Instr sty FRNDINT = uppPStr SLIT("\tfrndint")
-pprI386Instr sty FSIN = uppPStr SLIT("\tfsin")
-pprI386Instr sty FSQRT = uppPStr SLIT("\tfsqrt")
-pprI386Instr sty (FST sz dst)
- = uppBesides [uppPStr SLIT("\tfst"), pprSize sz, uppChar ' ', pprOperand sty sz dst]
-pprI386Instr sty (FSTP sz dst)
- = uppBesides [uppPStr SLIT("\tfstp"), pprSize sz, uppChar ' ', pprOperand sty sz dst]
-pprI386Instr sty (FISUB size op) = pprSizeAddr sty SLIT("fisub") size op
-pprI386Instr sty (FSUB sz src)
- = uppBesides [uppPStr SLIT("\tfsub"), pprSize sz, uppChar ' ', pprOperand sty sz src]
-pprI386Instr sty FSUBP
- = uppPStr SLIT("\tfsubp")
-pprI386Instr sty (FSUBR size src)
- = pprSizeOp sty SLIT("fsubr") size src
-pprI386Instr sty FSUBRP
- = uppPStr SLIT("\tfsubpr")
-pprI386Instr sty (FISUBR size op)
- = pprSizeAddr sty SLIT("fisubr") size op
-pprI386Instr sty FTST = uppPStr SLIT("\tftst")
-pprI386Instr sty (FCOMP sz op)
- = uppBesides [uppPStr SLIT("\tfcomp"), pprSize sz, uppChar ' ', pprOperand sty sz op]
-pprI386Instr sty FUCOMPP = uppPStr SLIT("\tfucompp")
-pprI386Instr sty FXCH = uppPStr SLIT("\tfxch")
-pprI386Instr sty FNSTSW = uppPStr SLIT("\tfnstsw %ax")
-pprI386Instr sty FNOP = uppPStr SLIT("")
-
-pprI386Instr sty (LABEL clab) =
- uppBesides [
- if (externallyVisibleCLabel clab) then
- uppBesides [uppPStr SLIT(".globl "), pprLab, uppChar '\n']
- else
- uppNil,
- pprLab,
- uppChar ':'
- ]
- where pprLab = pprCLabel sty clab
-
-pprI386Instr sty (COMMENT s) = uppBeside (uppPStr SLIT("# ")) (uppPStr s)
-
-pprI386Instr sty (SEGMENT TextSegment)
- = uppPStr SLIT(".text\n\t.align 4")
-
-pprI386Instr sty (SEGMENT DataSegment)
- = uppPStr SLIT(".data\n\t.align 2")
-
-pprI386Instr sty (ASCII False str) =
- uppBesides [
- uppStr "\t.asciz \"",
- uppStr str,
- uppChar '"'
- ]
-
-pprI386Instr sty (ASCII True str) = uppBeside (uppStr "\t.ascii \"") (asciify str 60)
- where
- asciify :: String -> Int -> Unpretty
- asciify [] _ = uppStr ("\\0\"")
- asciify s n | n <= 0 = uppBeside (uppStr "\"\n\t.ascii \"") (asciify s 60)
- asciify ('\\':cs) n = uppBeside (uppStr "\\\\") (asciify cs (n-1))
- asciify ('\"':cs) n = uppBeside (uppStr "\\\"") (asciify cs (n-1))
- asciify (c:cs) n | isPrint c = uppBeside (uppChar c) (asciify cs (n-1))
- asciify [c] _ = uppBeside (uppStr (charToC c)) (uppStr ("\\0\""))
- asciify (c:(cs@(d:_))) n | isDigit d =
- uppBeside (uppStr (charToC c)) (asciify cs 0)
- | otherwise =
- uppBeside (uppStr (charToC c)) (asciify cs (n-1))
-
-pprI386Instr sty (DATA s xs) = uppInterleave (uppChar '\n') (map pp_item xs)
- where pp_item x = case s of
- B -> uppBeside (uppPStr SLIT("\t.byte\t")) (pprImm sty x)
- HB-> uppBeside (uppPStr SLIT("\t.byte\t")) (pprImm sty x)
- S -> uppBeside (uppPStr SLIT("\t.word\t")) (pprImm sty x)
- L -> uppBeside (uppPStr SLIT("\t.long\t")) (pprImm sty x)
- F -> uppBeside (uppPStr SLIT("\t.long\t")) (pprImm sty x)
- D -> uppBeside (uppPStr SLIT("\t.double\t")) (pprImm sty x)
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[Schedule]{Register allocation information}
-%* *
-%************************************************************************
-
-\begin{code}
-
-data I386Regs = SRegs BitSet BitSet
-
-instance MachineRegisters I386Regs where
- mkMRegs xs = SRegs (mkBS ints) (mkBS floats')
- where
- (ints, floats) = partition (< 8) xs
- floats' = map (subtract 8) floats
-
- possibleMRegs FloatRep (SRegs _ floats) = [ x + 8 | x <- listBS floats]
- possibleMRegs DoubleRep (SRegs _ floats) = [ x + 8 | x <- listBS floats]
- possibleMRegs _ (SRegs ints _) = listBS ints
-
- useMReg (SRegs ints floats) n =
- if n _LT_ ILIT(8) then SRegs (ints `minusBS` singletonBS IBOX(n)) floats
- else SRegs ints (floats `minusBS` singletonBS (IBOX(n _SUB_ ILIT(8))))
-
- useMRegs (SRegs ints floats) xs =
- SRegs (ints `minusBS` ints')
- (floats `minusBS` floats')
- where
- SRegs ints' floats' = mkMRegs xs
-
- freeMReg (SRegs ints floats) n =
- if n _LT_ ILIT(8) then SRegs (ints `unionBS` singletonBS IBOX(n)) floats
- else SRegs ints (floats `unionBS` singletonBS (IBOX(n _SUB_ ILIT(8))))
-
- freeMRegs (SRegs ints floats) xs =
- SRegs (ints `unionBS` ints')
- (floats `unionBS` floats')
- where
- SRegs ints' floats' = mkMRegs xs
-
-instance MachineCode I386Instr where
- regUsage = i386RegUsage
- regLiveness = i386RegLiveness
- patchRegs = i386PatchRegs
-
- -- We spill just below the stack pointer, leaving two words per spill location.
- spillReg dyn (MemoryReg i pk)
- = trace "spillsave"
- (mkUnitList (MOV (kindToSize pk) (OpReg dyn) (OpAddr (spRel (-2 * i)))))
- loadReg (MemoryReg i pk) dyn
- = trace "spillload"
- (mkUnitList (MOV (kindToSize pk) (OpAddr (spRel (-2 * i))) (OpReg dyn)))
-
---spRel gives us a stack relative addressing mode for volatile temporaries
---and for excess call arguments.
-
-spRel
- :: Int -- desired stack offset in words, positive or negative
- -> Addr
-spRel n = Addr (Just esp) Nothing (ImmInt (n * 4))
-
-kindToSize :: PrimRep -> Size
-kindToSize PtrRep = L
-kindToSize CodePtrRep = L
-kindToSize DataPtrRep = L
-kindToSize RetRep = L
-kindToSize CostCentreRep = L
-kindToSize CharRep = L
-kindToSize IntRep = L
-kindToSize WordRep = L
-kindToSize AddrRep = L
-kindToSize FloatRep = F
-kindToSize DoubleRep = D
-kindToSize ArrayRep = L
-kindToSize ByteArrayRep = L
-kindToSize StablePtrRep = L
-kindToSize MallocPtrRep = L
-
-\end{code}
-
-@i386RegUsage@ returns the sets of src and destination registers used by
-a particular instruction. Machine registers that are pre-allocated
-to stgRegs are filtered out, because they are uninteresting from a
-register allocation standpoint. (We wouldn't want them to end up on
-the free list!)
-
-\begin{code}
-
-i386RegUsage :: I386Instr -> RegUsage
-i386RegUsage instr = case instr of
- MOV sz src dst -> usage2 src dst
- MOVZX sz src dst -> usage2 src dst
- MOVSX sz src dst -> usage2 src dst
- LEA sz src dst -> usage2 src dst
- ADD sz src dst -> usage2 src dst
- SUB sz src dst -> usage2 src dst
- IMUL sz src dst -> usage2 src dst
- IDIV sz src -> usage (eax:edx:opToReg src) [eax,edx]
- AND sz src dst -> usage2 src dst
- OR sz src dst -> usage2 src dst
- XOR sz src dst -> usage2 src dst
- NOT sz op -> usage1 op
- NEGI sz op -> usage1 op
- SHL sz imm dst -> usage1 dst -- imm has to be an Imm
- SAR sz imm dst -> usage1 dst -- imm has to be an Imm
- SHR sz imm dst -> usage1 dst -- imm has to be an Imm
- PUSH sz op -> usage (opToReg op) []
- POP sz op -> usage [] (opToReg op)
- TEST sz src dst -> usage (opToReg src ++ opToReg dst) []
- CMP sz src dst -> usage (opToReg src ++ opToReg dst) []
- SETCC cond op -> usage [] (opToReg op)
- JXX cond label -> usage [] []
- JMP op -> usage (opToReg op) freeRegs
- CALL imm -> usage [] callClobberedRegs
- CLTD -> usage [eax] [edx]
- NOP -> usage [] []
- SAHF -> usage [eax] []
- FABS -> usage [st0] [st0]
- FADD sz src -> usage (st0:opToReg src) [st0] -- allFPRegs
- FADDP -> usage [st0,st1] [st0] -- allFPRegs
- FIADD sz asrc -> usage (addrToRegs asrc) [st0]
- FCHS -> usage [st0] [st0]
- FCOM sz src -> usage (st0:opToReg src) []
- FCOS -> usage [st0] [st0]
- FDIV sz src -> usage (st0:opToReg src) [st0]
- FDIVP -> usage [st0,st1] [st0]
- FDIVRP -> usage [st0,st1] [st0]
- FIDIV sz asrc -> usage (addrToRegs asrc) [st0]
- FDIVR sz src -> usage (st0:opToReg src) [st0]
- FIDIVR sz asrc -> usage (addrToRegs asrc) [st0]
- FICOM sz asrc -> usage (addrToRegs asrc) []
- FILD sz asrc dst -> usage (addrToRegs asrc) [dst] -- allFPRegs
- FIST sz adst -> usage (st0:addrToRegs adst) []
- FLD sz src -> usage (opToReg src) [st0] -- allFPRegs
- FLD1 -> usage [] [st0] -- allFPRegs
- FLDZ -> usage [] [st0] -- allFPRegs
- FMUL sz src -> usage (st0:opToReg src) [st0]
- FMULP -> usage [st0,st1] [st0]
- FIMUL sz asrc -> usage (addrToRegs asrc) [st0]
- FRNDINT -> usage [st0] [st0]
- FSIN -> usage [st0] [st0]
- FSQRT -> usage [st0] [st0]
- FST sz (OpReg r) -> usage [st0] [r]
- FST sz dst -> usage (st0:opToReg dst) []
- FSTP sz (OpReg r) -> usage [st0] [r] -- allFPRegs
- FSTP sz dst -> usage (st0:opToReg dst) [] -- allFPRegs
- FSUB sz src -> usage (st0:opToReg src) [st0] -- allFPRegs
- FSUBR sz src -> usage (st0:opToReg src) [st0] -- allFPRegs
- FISUB sz asrc -> usage (addrToRegs asrc) [st0]
- FSUBP -> usage [st0,st1] [st0] -- allFPRegs
- FSUBRP -> usage [st0,st1] [st0] -- allFPRegs
- FISUBR sz asrc -> usage (addrToRegs asrc) [st0]
- FTST -> usage [st0] []
- FCOMP sz op -> usage (st0:opToReg op) [st0] -- allFPRegs
- FUCOMPP -> usage [st0, st1] [] -- allFPRegs
- FXCH -> usage [st0, st1] [st0, st1]
- FNSTSW -> usage [] [eax]
- _ -> noUsage
-
- where
-
- usage2 :: Operand -> Operand -> RegUsage
- usage2 op (OpReg reg) = usage (opToReg op) [reg]
- usage2 op (OpAddr ea) = usage (opToReg op ++ addrToRegs ea) []
- usage2 op (OpImm imm) = usage (opToReg op) []
- usage1 :: Operand -> RegUsage
- usage1 (OpReg reg) = usage [reg] [reg]
- usage1 (OpAddr ea) = usage (addrToRegs ea) []
- allFPRegs = [st0,st1,st2,st3,st4,st5,st6,st7]
- --callClobberedRegs = [ eax, ecx, edx ] -- according to gcc, anyway.
- callClobberedRegs = [eax]
-
--- General purpose register collecting functions.
-
- opToReg (OpReg reg) = [reg]
- opToReg (OpImm imm) = []
- opToReg (OpAddr ea) = addrToRegs ea
-
- addrToRegs (Addr base index _) = baseToReg base ++ indexToReg index
- where baseToReg Nothing = []
- baseToReg (Just r) = [r]
- indexToReg Nothing = []
- indexToReg (Just (r,_)) = [r]
- addrToRegs (ImmAddr _ _) = []
-
- usage src dst = RU (mkUniqSet (filter interesting src))
- (mkUniqSet (filter interesting dst))
-
- interesting (FixedReg _) = False
- interesting _ = True
-
-freeRegs :: [Reg]
-freeRegs = freeMappedRegs (\ x -> x) [0..15]
-
-freeMappedRegs :: (Int -> Int) -> [Int] -> [Reg]
-
-freeMappedRegs modify nums
- = foldr free [] nums
- where
- free n acc
- = let
- modified_i = case (modify n) of { IBOX(x) -> x }
- in
- if _IS_TRUE_(freeReg modified_i) then (MappedReg modified_i) : acc else acc
-
-freeSet :: UniqSet Reg
-freeSet = mkUniqSet freeRegs
-
-noUsage :: RegUsage
-noUsage = RU emptyUniqSet emptyUniqSet
-
-endUsage :: RegUsage
-endUsage = RU emptyUniqSet freeSet
-
-\end{code}
-
-@i386RegLiveness@ takes future liveness information and modifies it according to
-the semantics of branches and labels. (An out-of-line branch clobbers the liveness
-passed back by the following instruction; a forward local branch passes back the
-liveness from the target label; a conditional branch merges the liveness from the
-target and the liveness from its successor; a label stashes away the current liveness
-in the future liveness environment).
-
-\begin{code}
-i386RegLiveness :: I386Instr -> RegLiveness -> RegLiveness
-i386RegLiveness instr info@(RL live future@(FL all env)) = case instr of
-
- JXX _ lbl -> RL (lookup lbl `unionUniqSets` live) future
- JMP _ -> RL emptyUniqSet future
- CALL _ -> RL live future
- LABEL lbl -> RL live (FL (all `unionUniqSets` live) (addToFM env lbl live))
- _ -> info
-
- where
- lookup lbl = case lookupFM env lbl of
- Just regs -> regs
- Nothing -> trace ("Missing " ++ (uppShow 80 (pprCLabel (PprForAsm (\_->False) False id) lbl)) ++
- " in future?") emptyUniqSet
-
-\end{code}
-
-@i386PatchRegs@ takes an instruction (possibly with MemoryReg/UnmappedReg registers) and
-changes all register references according to the supplied environment.
-
-\begin{code}
-
-i386PatchRegs :: I386Instr -> (Reg -> Reg) -> I386Instr
-i386PatchRegs instr env = case instr of
- MOV sz src dst -> patch2 (MOV sz) src dst
- MOVZX sz src dst -> patch2 (MOVZX sz) src dst
- MOVSX sz src dst -> patch2 (MOVSX sz) src dst
- LEA sz src dst -> patch2 (LEA sz) src dst
- ADD sz src dst -> patch2 (ADD sz) src dst
- SUB sz src dst -> patch2 (SUB sz) src dst
- IMUL sz src dst -> patch2 (IMUL sz) src dst
- IDIV sz src -> patch1 (IDIV sz) src
- AND sz src dst -> patch2 (AND sz) src dst
- OR sz src dst -> patch2 (OR sz) src dst
- XOR sz src dst -> patch2 (XOR sz) src dst
- NOT sz op -> patch1 (NOT sz) op
- NEGI sz op -> patch1 (NEGI sz) op
- SHL sz imm dst -> patch1 (SHL sz imm) dst
- SAR sz imm dst -> patch1 (SAR sz imm) dst
- SHR sz imm dst -> patch1 (SHR sz imm) dst
- TEST sz src dst -> patch2 (TEST sz) src dst
- CMP sz src dst -> patch2 (CMP sz) src dst
- PUSH sz op -> patch1 (PUSH sz) op
- POP sz op -> patch1 (POP sz) op
- SETCC cond op -> patch1 (SETCC cond) op
- JMP op -> patch1 JMP op
- FADD sz src -> FADD sz (patchOp src)
- FIADD sz asrc -> FIADD sz (lookupAddr asrc)
- FCOM sz src -> patch1 (FCOM sz) src
- FDIV sz src -> FDIV sz (patchOp src)
- --FDIVP sz src -> FDIVP sz (patchOp src)
- FIDIV sz asrc -> FIDIV sz (lookupAddr asrc)
- FDIVR sz src -> FDIVR sz (patchOp src)
- --FDIVRP sz src -> FDIVRP sz (patchOp src)
- FIDIVR sz asrc -> FIDIVR sz (lookupAddr asrc)
- FICOM sz asrc -> FICOM sz (lookupAddr asrc)
- FILD sz asrc dst -> FILD sz (lookupAddr asrc) (env dst)
- FIST sz adst -> FIST sz (lookupAddr adst)
- FLD sz src -> patch1 (FLD sz) (patchOp src)
- FMUL sz src -> FMUL sz (patchOp src)
- --FMULP sz src -> FMULP sz (patchOp src)
- FIMUL sz asrc -> FIMUL sz (lookupAddr asrc)
- FST sz dst -> FST sz (patchOp dst)
- FSTP sz dst -> FSTP sz (patchOp dst)
- FSUB sz src -> FSUB sz (patchOp src)
- --FSUBP sz src -> FSUBP sz (patchOp src)
- FISUB sz asrc -> FISUB sz (lookupAddr asrc)
- FSUBR sz src -> FSUBR sz (patchOp src)
- --FSUBRP sz src -> FSUBRP sz (patchOp src)
- FISUBR sz asrc -> FISUBR sz (lookupAddr asrc)
- FCOMP sz src -> FCOMP sz (patchOp src)
- _ -> instr
-
- where
- patch1 insn op = insn (patchOp op)
- patch2 insn src dst = insn (patchOp src) (patchOp dst)
-
- patchOp (OpReg reg) = OpReg (env reg)
- patchOp (OpImm imm) = OpImm imm
- patchOp (OpAddr ea) = OpAddr (lookupAddr ea)
-
- lookupAddr (Addr base index disp)
- = Addr (lookupBase base) (lookupIndex index) disp
- where lookupBase Nothing = Nothing
- lookupBase (Just r) = Just (env r)
- lookupIndex Nothing = Nothing
- lookupIndex (Just (r,i)) = Just (env r, i)
- lookupAddr (ImmAddr imm off)
- = ImmAddr imm off
-
-\end{code}
-
-Sometimes, we want to be able to modify addresses at compile time.
-(Okay, just for chrCode of a fetch.)
-
-\begin{code}
-{-# SPECIALIZE
- is13Bits :: Int -> Bool
- #-}
-{-# SPECIALIZE
- is13Bits :: Integer -> Bool
- #-}
-
-is13Bits :: Integral a => a -> Bool
-is13Bits x = x >= -4096 && x < 4096
-
-offset :: Addr -> Int -> Maybe Addr
-offset (Addr reg index (ImmInt n)) off
- = Just (Addr reg index (ImmInt n2))
- where n2 = n + off
-
-offset (Addr reg index (ImmInteger n)) off
- = Just (Addr reg index (ImmInt (fromInteger n2)))
- where n2 = n + toInteger off
-
-offset (ImmAddr imm off1) off2
- = Just (ImmAddr imm off3)
- where off3 = off1 + off2
-
-offset _ _ = Nothing
-\end{code}
-
-If you value your sanity, do not venture below this line.
-
-\begin{code}
-
--- platform.h is generate and tells us what the target architecture is
-#include "../../includes/platform.h"
-#define STOLEN_X86_REGS 5
-#include "../../includes/MachRegs.h"
-#include "../../includes/i386-unknown-linuxaout.h"
-
--- Redefine the literals used for I386 register names in the header
--- files. Gag me with a spoon, eh?
-
-#define eax 0
-#define ebx 1
-#define ecx 2
-#define edx 3
-#define esi 4
-#define edi 5
-#define ebp 6
-#define esp 7
-#define st0 8
-#define st1 9
-#define st2 10
-#define st3 11
-#define st4 12
-#define st5 13
-#define st6 14
-#define st7 15
-#define CALLER_SAVES_Hp
--- ToDo: rm when we give esp back
-#define REG_Hp esp
-#define REG_R2 ecx
-
-baseRegOffset :: MagicId -> Int
-baseRegOffset StkOReg = OFFSET_StkO
-baseRegOffset (VanillaReg _ ILIT2(1)) = OFFSET_R1
-baseRegOffset (VanillaReg _ ILIT2(2)) = OFFSET_R2
-baseRegOffset (VanillaReg _ ILIT2(3)) = OFFSET_R3
-baseRegOffset (VanillaReg _ ILIT2(4)) = OFFSET_R4
-baseRegOffset (VanillaReg _ ILIT2(5)) = OFFSET_R5
-baseRegOffset (VanillaReg _ ILIT2(6)) = OFFSET_R6
-baseRegOffset (VanillaReg _ ILIT2(7)) = OFFSET_R7
-baseRegOffset (VanillaReg _ ILIT2(8)) = OFFSET_R8
-baseRegOffset (FloatReg ILIT2(1)) = OFFSET_Flt1
-baseRegOffset (FloatReg ILIT2(2)) = OFFSET_Flt2
-baseRegOffset (FloatReg ILIT2(3)) = OFFSET_Flt3
-baseRegOffset (FloatReg ILIT2(4)) = OFFSET_Flt4
-baseRegOffset (DoubleReg ILIT2(1)) = OFFSET_Dbl1
-baseRegOffset (DoubleReg ILIT2(2)) = OFFSET_Dbl2
-baseRegOffset TagReg = OFFSET_Tag
-baseRegOffset RetReg = OFFSET_Ret
-baseRegOffset SpA = OFFSET_SpA
-baseRegOffset SuA = OFFSET_SuA
-baseRegOffset SpB = OFFSET_SpB
-baseRegOffset SuB = OFFSET_SuB
-baseRegOffset Hp = OFFSET_Hp
-baseRegOffset HpLim = OFFSET_HpLim
-baseRegOffset LivenessReg = OFFSET_Liveness
---baseRegOffset ActivityReg = OFFSET_Activity
-#ifdef DEBUG
-baseRegOffset BaseReg = panic "baseRegOffset:BaseReg"
-baseRegOffset StdUpdRetVecReg = panic "baseRegOffset:StgUpdRetVecReg"
-baseRegOffset StkStubReg = panic "baseRegOffset:StkStubReg"
-baseRegOffset CurCostCentre = panic "baseRegOffset:CurCostCentre"
-baseRegOffset VoidReg = panic "baseRegOffset:VoidReg"
-#endif
-
-callerSaves :: MagicId -> Bool
-#ifdef CALLER_SAVES_Base
-callerSaves BaseReg = True
-#endif
-#ifdef CALLER_SAVES_StkO
-callerSaves StkOReg = True
-#endif
-#ifdef CALLER_SAVES_R1
-callerSaves (VanillaReg _ ILIT2(1)) = True
-#endif
-#ifdef CALLER_SAVES_R2
-callerSaves (VanillaReg _ ILIT2(2)) = True
-#endif
-#ifdef CALLER_SAVES_R3
-callerSaves (VanillaReg _ ILIT2(3)) = True
-#endif
-#ifdef CALLER_SAVES_R4
-callerSaves (VanillaReg _ ILIT2(4)) = True
-#endif
-#ifdef CALLER_SAVES_R5
-callerSaves (VanillaReg _ ILIT2(5)) = True
-#endif
-#ifdef CALLER_SAVES_R6
-callerSaves (VanillaReg _ ILIT2(6)) = True
-#endif
-#ifdef CALLER_SAVES_R7
-callerSaves (VanillaReg _ ILIT2(7)) = True
-#endif
-#ifdef CALLER_SAVES_R8
-callerSaves (VanillaReg _ ILIT2(8)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg1
-callerSaves (FloatReg ILIT2(1)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg2
-callerSaves (FloatReg ILIT2(2)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg3
-callerSaves (FloatReg ILIT2(3)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg4
-callerSaves (FloatReg ILIT2(4)) = True
-#endif
-#ifdef CALLER_SAVES_DblReg1
-callerSaves (DoubleReg ILIT2(1)) = True
-#endif
-#ifdef CALLER_SAVES_DblReg2
-callerSaves (DoubleReg ILIT2(2)) = True
-#endif
-#ifdef CALLER_SAVES_Tag
-callerSaves TagReg = True
-#endif
-#ifdef CALLER_SAVES_Ret
-callerSaves RetReg = True
-#endif
-#ifdef CALLER_SAVES_SpA
-callerSaves SpA = True
-#endif
-#ifdef CALLER_SAVES_SuA
-callerSaves SuA = True
-#endif
-#ifdef CALLER_SAVES_SpB
-callerSaves SpB = True
-#endif
-#ifdef CALLER_SAVES_SuB
-callerSaves SuB = True
-#endif
-#ifdef CALLER_SAVES_Hp
-callerSaves Hp = True
-#endif
-#ifdef CALLER_SAVES_HpLim
-callerSaves HpLim = True
-#endif
-#ifdef CALLER_SAVES_Liveness
-callerSaves LivenessReg = True
-#endif
-#ifdef CALLER_SAVES_Activity
---callerSaves ActivityReg = True
-#endif
-#ifdef CALLER_SAVES_StdUpdRetVec
-callerSaves StdUpdRetVecReg = True
-#endif
-#ifdef CALLER_SAVES_StkStub
-callerSaves StkStubReg = True
-#endif
-callerSaves _ = False
-
-stgRegMap :: MagicId -> Maybe Reg
-
-#ifdef REG_Base
-stgRegMap BaseReg = Just (FixedReg ILIT(REG_Base))
-#endif
-#ifdef REG_StkO
-stgRegMap StkOReg = Just (FixedReg ILIT(REG_StkOReg))
-#endif
-#ifdef REG_R1
-stgRegMap (VanillaReg _ ILIT2(1)) = Just (FixedReg ILIT(REG_R1))
-#endif
-#ifdef REG_R2
-stgRegMap (VanillaReg _ ILIT2(2)) = Just (FixedReg ILIT(REG_R2))
-#endif
-#ifdef REG_R3
-stgRegMap (VanillaReg _ ILIT2(3)) = Just (FixedReg ILIT(REG_R3))
-#endif
-#ifdef REG_R4
-stgRegMap (VanillaReg _ ILIT2(4)) = Just (FixedReg ILIT(REG_R4))
-#endif
-#ifdef REG_R5
-stgRegMap (VanillaReg _ ILIT2(5)) = Just (FixedReg ILIT(REG_R5))
-#endif
-#ifdef REG_R6
-stgRegMap (VanillaReg _ ILIT2(6)) = Just (FixedReg ILIT(REG_R6))
-#endif
-#ifdef REG_R7
-stgRegMap (VanillaReg _ ILIT2(7)) = Just (FixedReg ILIT(REG_R7))
-#endif
-#ifdef REG_R8
-stgRegMap (VanillaReg _ ILIT2(8)) = Just (FixedReg ILIT(REG_R8))
-#endif
-#ifdef REG_Flt1
-stgRegMap (FloatReg ILIT2(1)) = Just (FixedReg ILIT(REG_Flt1))
-#endif
-#ifdef REG_Flt2
-stgRegMap (FloatReg ILIT2(2)) = Just (FixedReg ILIT(REG_Flt2))
-#endif
-#ifdef REG_Flt3
-stgRegMap (FloatReg ILIT2(3)) = Just (FixedReg ILIT(REG_Flt3))
-#endif
-#ifdef REG_Flt4
-stgRegMap (FloatReg ILIT2(4)) = Just (FixedReg ILIT(REG_Flt4))
-#endif
-#ifdef REG_Dbl1
-stgRegMap (DoubleReg ILIT2(1)) = Just (FixedReg ILIT(REG_Dbl1))
-#endif
-#ifdef REG_Dbl2
-stgRegMap (DoubleReg ILIT2(2)) = Just (FixedReg ILIT(REG_Dbl2))
-#endif
-#ifdef REG_Tag
-stgRegMap TagReg = Just (FixedReg ILIT(REG_TagReg))
-#endif
-#ifdef REG_Ret
-stgRegMap RetReg = Just (FixedReg ILIT(REG_Ret))
-#endif
-#ifdef REG_SpA
-stgRegMap SpA = Just (FixedReg ILIT(REG_SpA))
-#endif
-#ifdef REG_SuA
-stgRegMap SuA = Just (FixedReg ILIT(REG_SuA))
-#endif
-#ifdef REG_SpB
-stgRegMap SpB = Just (FixedReg ILIT(REG_SpB))
-#endif
-#ifdef REG_SuB
-stgRegMap SuB = Just (FixedReg ILIT(REG_SuB))
-#endif
-#ifdef REG_Hp
-stgRegMap Hp = Just (FixedReg ILIT(REG_Hp))
-#endif
-#ifdef REG_HpLim
-stgRegMap HpLim = Just (FixedReg ILIT(REG_HpLim))
-#endif
-#ifdef REG_Liveness
-stgRegMap LivenessReg = Just (FixedReg ILIT(REG_Liveness))
-#endif
-#ifdef REG_Activity
---stgRegMap ActivityReg = Just (FixedReg ILIT(REG_Activity))
-#endif
-#ifdef REG_StdUpdRetVec
-stgRegMap StdUpdRetVecReg = Just (FixedReg ILIT(REG_StdUpdRetVec))
-#endif
-#ifdef REG_StkStub
-stgRegMap StkStubReg = Just (FixedReg ILIT(REG_StkStub))
-#endif
-
-stgRegMap _ = Nothing
-
-\end{code}
-
-Here is the list of registers we can use in register allocation.
-
-\begin{code}
-freeReg :: FAST_INT -> FAST_BOOL
-
---freeReg ILIT(esp) = _FALSE_ -- %esp is our stack pointer.
-
-#ifdef REG_Base
-freeReg ILIT(REG_Base) = _FALSE_
-#endif
-#ifdef REG_StkO
-freeReg ILIT(REG_StkO) = _FALSE_
-#endif
-#ifdef REG_R1
-freeReg ILIT(REG_R1) = _FALSE_
-#endif
-#ifdef REG_R2
-freeReg ILIT(REG_R2) = _FALSE_
-#endif
-#ifdef REG_R3
-freeReg ILIT(REG_R3) = _FALSE_
-#endif
-#ifdef REG_R4
-freeReg ILIT(REG_R4) = _FALSE_
-#endif
-#ifdef REG_R5
-freeReg ILIT(REG_R5) = _FALSE_
-#endif
-#ifdef REG_R6
-freeReg ILIT(REG_R6) = _FALSE_
-#endif
-#ifdef REG_R7
-freeReg ILIT(REG_R7) = _FALSE_
-#endif
-#ifdef REG_R8
-freeReg ILIT(REG_R8) = _FALSE_
-#endif
-#ifdef REG_Flt1
-freeReg ILIT(REG_Flt1) = _FALSE_
-#endif
-#ifdef REG_Flt2
-freeReg ILIT(REG_Flt2) = _FALSE_
-#endif
-#ifdef REG_Flt3
-freeReg ILIT(REG_Flt3) = _FALSE_
-#endif
-#ifdef REG_Flt4
-freeReg ILIT(REG_Flt4) = _FALSE_
-#endif
-#ifdef REG_Dbl1
-freeReg ILIT(REG_Dbl1) = _FALSE_
-#endif
-#ifdef REG_Dbl2
-freeReg ILIT(REG_Dbl2) = _FALSE_
-#endif
-#ifdef REG_Tag
-freeReg ILIT(REG_Tag) = _FALSE_
-#endif
-#ifdef REG_Ret
-freeReg ILIT(REG_Ret) = _FALSE_
-#endif
-#ifdef REG_SpA
-freeReg ILIT(REG_SpA) = _FALSE_
-#endif
-#ifdef REG_SuA
-freeReg ILIT(REG_SuA) = _FALSE_
-#endif
-#ifdef REG_SpB
-freeReg ILIT(REG_SpB) = _FALSE_
-#endif
-#ifdef REG_SuB
-freeReg ILIT(REG_SuB) = _FALSE_
-#endif
-#ifdef REG_Hp
-freeReg ILIT(REG_Hp) = _FALSE_
-#endif
-#ifdef REG_HpLim
-freeReg ILIT(REG_HpLim) = _FALSE_
-#endif
-#ifdef REG_Liveness
-freeReg ILIT(REG_Liveness) = _FALSE_
-#endif
-#ifdef REG_Activity
---freeReg ILIT(REG_Activity) = _FALSE_
-#endif
-#ifdef REG_StdUpdRetVec
-freeReg ILIT(REG_StdUpdRetVec) = _FALSE_
-#endif
-#ifdef REG_StkStub
-freeReg ILIT(REG_StkStub) = _FALSE_
-#endif
-freeReg n
-#ifdef REG_Dbl1
- | n _EQ_ (ILIT(REG_Dbl1) _ADD_ ILIT(1)) = _FALSE_
-#endif
-#ifdef REG_Dbl2
- | n _EQ_ (ILIT(REG_Dbl2) _ADD_ ILIT(1)) = _FALSE_
-#endif
-
- | otherwise = _TRUE_
-
-reservedRegs :: [Int]
-reservedRegs = []
---reservedRegs = [NCG_Reserved_I1, NCG_Reserved_I2,
--- NCG_Reserved_F1, NCG_Reserved_F2,
--- NCG_Reserved_D1, NCG_Reserved_D2]
-
-\end{code}
-
+++ /dev/null
-%
-% (c) The AQUA Project, Glasgow University, 1994-1995
-%
-\section[I386Desc]{The I386 Machine Description}
-
-\begin{code}
-#include "HsVersions.h"
-
-module I386Desc (
- mkI386
-
- -- and assorted nonsense referenced by the class methods
- ) where
-
-import AbsCSyn
-import PrelInfo ( PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import AsmRegAlloc ( Reg, MachineCode(..), MachineRegisters(..),
- RegLiveness(..), RegUsage(..), FutureLive(..)
- )
-import CLabel ( CLabel )
-import CmdLineOpts ( GlobalSwitch(..), stringSwitchSet, switchIsOn, SwitchResult(..) )
-import HeapOffs ( hpRelToInt )
-import MachDesc
-import Maybes ( Maybe(..) )
-import OrdList
-import Outputable
-import SMRep ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..) )
-import I386Code
-import I386Gen ( i386CodeGen )
-import Stix
-import StixMacro
-import StixPrim
-import UniqSupply
-import Util
-\end{code}
-
-Header sizes depend only on command-line options, not on the target
-architecture. (I think.)
-
-\begin{code}
-
-fhs :: (GlobalSwitch -> SwitchResult) -> Int
-
-fhs switches = 1 + profFHS + ageFHS
- where
- profFHS = if switchIsOn switches SccProfilingOn then 1 else 0
- ageFHS = if switchIsOn switches SccProfilingOn then 1 else 0
-
-vhs :: (GlobalSwitch -> SwitchResult) -> SMRep -> Int
-
-vhs switches sm = case sm of
- StaticRep _ _ -> 0
- SpecialisedRep _ _ _ _ -> 0
- GenericRep _ _ _ -> 0
- BigTupleRep _ -> 1
- MuTupleRep _ -> 2 {- (1 + GC_MUT_RESERVED_WORDS) -}
- DataRep _ -> 1
- DynamicRep -> 2
- BlackHoleRep -> 0
- PhantomRep -> panic "vhs:phantom"
-
-\end{code}
-
-Here we map STG registers onto appropriate Stix Trees. First, we
-handle the two constants, @STK_STUB_closure@ and @vtbl_StdUpdFrame@.
-The rest are either in real machine registers or stored as offsets
-from BaseReg.
-
-\begin{code}
-
-i386Reg :: (GlobalSwitch -> SwitchResult) -> MagicId -> RegLoc
-
-i386Reg switches x =
- case stgRegMap x of
- Just reg -> Save nonReg
- Nothing -> Always nonReg
- where nonReg = case x of
- StkStubReg -> sStLitLbl SLIT("STK_STUB_closure")
- StdUpdRetVecReg -> sStLitLbl SLIT("vtbl_StdUpdFrame")
- BaseReg -> sStLitLbl SLIT("MainRegTable")
- --Hp -> StInd PtrRep (sStLitLbl SLIT("StorageMgrInfo"))
- --HpLim -> StInd PtrRep (sStLitLbl SLIT("StorageMgrInfo+4"))
- TagReg -> StInd IntRep (StPrim IntSubOp [infoptr, StInt (1*4)])
- where
- r2 = VanillaReg PtrRep ILIT(2)
- infoptr = case i386Reg switches r2 of
- Always tree -> tree
- Save _ -> StReg (StixMagicId r2)
- _ -> StInd (kindFromMagicId x)
- (StPrim IntAddOp [baseLoc, StInt (toInteger (offset*4))])
- baseLoc = case stgRegMap BaseReg of
- Just _ -> StReg (StixMagicId BaseReg)
- Nothing -> sStLitLbl SLIT("MainRegTable")
- offset = baseRegOffset x
-
-\end{code}
-
-Sizes in bytes.
-
-\begin{code}
-
-size pk = case kindToSize pk of
- {B -> 1; S -> 2; L -> 4; F -> 4; D -> 8 }
-
-\end{code}
-
-Now the volatile saves and restores. We add the basic guys to the list of ``user''
-registers provided. Note that there are more basic registers on the restore list,
-because some are reloaded from constants.
-
-\begin{code}
-
-vsaves switches vols =
- map save ((filter callerSaves) ([BaseReg,SpA,SuA,SpB,SuB,Hp,HpLim,RetReg{-,ActivityReg-}] ++ vols))
- where
- save x = StAssign (kindFromMagicId x) loc reg
- where reg = StReg (StixMagicId x)
- loc = case i386Reg switches x of
- Save loc -> loc
- Always loc -> panic "vsaves"
-
-vrests switches vols =
- map restore ((filter callerSaves)
- ([BaseReg,SpA,SuA,SpB,SuB,Hp,HpLim,RetReg{-,ActivityReg-},StkStubReg,StdUpdRetVecReg] ++ vols))
- where
- restore x = StAssign (kindFromMagicId x) reg loc
- where reg = StReg (StixMagicId x)
- loc = case i386Reg switches x of
- Save loc -> loc
- Always loc -> panic "vrests"
-
-\end{code}
-
-Static closure sizes.
-
-\begin{code}
-
-charLikeSize, intLikeSize :: Target -> Int
-
-charLikeSize target =
- size PtrRep * (fixedHeaderSize target + varHeaderSize target charLikeRep + 1)
- where charLikeRep = SpecialisedRep CharLikeRep 0 1 SMNormalForm
-
-intLikeSize target =
- size PtrRep * (fixedHeaderSize target + varHeaderSize target intLikeRep + 1)
- where intLikeRep = SpecialisedRep IntLikeRep 0 1 SMNormalForm
-
-mhs, dhs :: (GlobalSwitch -> SwitchResult) -> StixTree
-
-mhs switches = StInt (toInteger words)
- where
- words = fhs switches + vhs switches (MuTupleRep 0)
-
-dhs switches = StInt (toInteger words)
- where
- words = fhs switches + vhs switches (DataRep 0)
-
-\end{code}
-
-Setting up a i386 target.
-
-\begin{code}
-mkI386 :: Bool
- -> (GlobalSwitch -> SwitchResult)
- -> (Target,
- (PprStyle -> [[StixTree]] -> UniqSM Unpretty), -- codeGen
- Bool, -- underscore
- (String -> String)) -- fmtAsmLbl
-
-mkI386 decentOS switches =
- let fhs' = fhs switches
- vhs' = vhs switches
- i386Reg' = i386Reg switches
- vsaves' = vsaves switches
- vrests' = vrests switches
- hprel = hpRelToInt target
- as = amodeCode target
- as' = amodeCode' target
- csz = charLikeSize target
- isz = intLikeSize target
- mhs' = mhs switches
- dhs' = dhs switches
- ps = genPrimCode target
- mc = genMacroCode target
- hc = doHeapCheck
- target = mkTarget {-switches-} fhs' vhs' i386Reg' {-id-} size
- hprel as as'
- (vsaves', vrests', csz, isz, mhs', dhs', ps, mc, hc)
- {-i386CodeGen decentOS id-}
- in
- (target, i386CodeGen, decentOS, id)
-\end{code}
-
-
-
+++ /dev/null
-%
-% (c) The AQUA Project, Glasgow University, 1993-1995
-%
-
-\begin{code}
-#include "HsVersions.h"
-#include "../includes/i386-unknown-linuxaout.h"
-
-module I386Gen (
- i386CodeGen,
-
- -- and, for self-sufficiency
- PprStyle, StixTree, CSeq
- ) where
-
-IMPORT_Trace
-
-import AbsCSyn ( AbstractC, MagicId(..), kindFromMagicId )
-import PrelInfo ( PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import AsmRegAlloc ( runRegAllocate, mkReg, extractMappedRegNos,
- Reg(..), RegLiveness(..), RegUsage(..),
- FutureLive(..), MachineRegisters(..), MachineCode(..)
- )
-import CLabel ( CLabel, isAsmTemp )
-import I386Code {- everything -}
-import MachDesc
-import Maybes ( maybeToBool, Maybe(..) )
-import OrdList -- ( mkEmptyList, mkUnitList, mkSeqList, mkParList, OrdList )
-import Outputable
-import I386Desc
-import Stix
-import UniqSupply
-import Pretty
-import Unpretty
-import Util
-
-type CodeBlock a = (OrdList a -> OrdList a)
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[I386CodeGen]{Generating I386 Code}
-%* *
-%************************************************************************
-
-This is the top-level code-generation function for the I386.
-
-\begin{code}
-
-i386CodeGen :: PprStyle -> [[StixTree]] -> UniqSM Unpretty
-i386CodeGen sty trees =
- mapUs genI386Code trees `thenUs` \ dynamicCodes ->
- let
- staticCodes = scheduleI386Code dynamicCodes
- pretty = printLabeledCodes sty staticCodes
- in
- returnUs pretty
-
-\end{code}
-
-This bit does the code scheduling. The scheduler must also deal with
-register allocation of temporaries. Much parallelism can be exposed via
-the OrdList, but more might occur, so further analysis might be needed.
-
-\begin{code}
-
-scheduleI386Code :: [I386Code] -> [I386Instr]
-scheduleI386Code = concat . map (runRegAllocate freeI386Regs reservedRegs)
- where
- freeI386Regs :: I386Regs
- freeI386Regs = mkMRegs (extractMappedRegNos freeRegs)
-
-
-\end{code}
-
-Registers passed up the tree. If the stix code forces the register
-to live in a pre-decided machine register, it comes out as @Fixed@;
-otherwise, it comes out as @Any@, and the parent can decide which
-register to put it in.
-
-\begin{code}
-
-data Register
- = Fixed Reg PrimRep (CodeBlock I386Instr)
- | Any PrimRep (Reg -> (CodeBlock I386Instr))
-
-registerCode :: Register -> Reg -> CodeBlock I386Instr
-registerCode (Fixed _ _ code) reg = code
-registerCode (Any _ code) reg = code reg
-
-registerName :: Register -> Reg -> Reg
-registerName (Fixed reg _ _) _ = reg
-registerName (Any _ _) reg = reg
-
-registerKind :: Register -> PrimRep
-registerKind (Fixed _ pk _) = pk
-registerKind (Any pk _) = pk
-
-isFixed :: Register -> Bool
-isFixed (Fixed _ _ _) = True
-isFixed (Any _ _) = False
-
-\end{code}
-
-Memory addressing modes passed up the tree.
-
-\begin{code}
-
-data Amode = Amode Addr (CodeBlock I386Instr)
-
-amodeAddr (Amode addr _) = addr
-amodeCode (Amode _ code) = code
-
-\end{code}
-
-Condition codes passed up the tree.
-
-\begin{code}
-
-data Condition = Condition Bool Cond (CodeBlock I386Instr)
-
-condName (Condition _ cond _) = cond
-condFloat (Condition float _ _) = float
-condCode (Condition _ _ code) = code
-
-\end{code}
-
-General things for putting together code sequences.
-
-\begin{code}
-
-asmVoid :: OrdList I386Instr
-asmVoid = mkEmptyList
-
-asmInstr :: I386Instr -> I386Code
-asmInstr i = mkUnitList i
-
-asmSeq :: [I386Instr] -> I386Code
-asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
-
-asmParThen :: [I386Code] -> (CodeBlock I386Instr)
-asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
-
-returnInstr :: I386Instr -> UniqSM (CodeBlock I386Instr)
-returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
-
-returnInstrs :: [I386Instr] -> UniqSM (CodeBlock I386Instr)
-returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
-
-returnSeq :: (CodeBlock I386Instr) -> [I386Instr] -> UniqSM (CodeBlock I386Instr)
-returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
-
-mkSeqInstr :: I386Instr -> (CodeBlock I386Instr)
-mkSeqInstr instr code = mkSeqList (asmInstr instr) code
-
-mkSeqInstrs :: [I386Instr] -> (CodeBlock I386Instr)
-mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
-
-\end{code}
-
-Top level i386 code generator for a chunk of stix code.
-
-\begin{code}
-
-genI386Code :: [StixTree] -> UniqSM (I386Code)
-
-genI386Code trees =
- mapUs getCode trees `thenUs` \ blocks ->
- returnUs (foldr (.) id blocks asmVoid)
-
-\end{code}
-
-Code extractor for an entire stix tree---stix statement level.
-
-\begin{code}
-
-getCode
- :: StixTree -- a stix statement
- -> UniqSM (CodeBlock I386Instr)
-
-getCode (StSegment seg) = returnInstr (SEGMENT seg)
-
-getCode (StAssign pk dst src)
- | isFloatingRep pk = assignFltCode pk dst src
- | otherwise = assignIntCode pk dst src
-
-getCode (StLabel lab) = returnInstr (LABEL lab)
-
-getCode (StFunBegin lab) = returnInstr (LABEL lab)
-
-getCode (StFunEnd lab) = returnUs id
-
-getCode (StJump arg) = genJump arg
-
-getCode (StFallThrough lbl) = returnUs id
-
-getCode (StCondJump lbl arg) = genCondJump lbl arg
-
-getCode (StData kind args) =
- mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
- returnUs (\xs -> mkSeqList (asmInstr (DATA (kindToSize kind) imms))
- (foldr1 (.) codes xs))
- where
- getData :: StixTree -> UniqSM (CodeBlock I386Instr, Imm)
- getData (StInt i) = returnUs (id, ImmInteger i)
- getData (StDouble d) = returnUs (id, strImmLit ('0' : 'd' : ppShow 80 (ppRational d)))
- getData (StLitLbl s) = returnUs (id, ImmLit (uppBeside (uppChar '_') s))
- getData (StLitLit s) = returnUs (id, strImmLit (cvtLitLit (_UNPK_ s)))
- getData (StString s) =
- getUniqLabelNCG `thenUs` \ lbl ->
- returnUs (mkSeqInstrs [LABEL lbl, ASCII True (_UNPK_ s)], ImmCLbl lbl)
- getData (StCLbl l) = returnUs (id, ImmCLbl l)
-
-getCode (StCall fn VoidRep args) = genCCall fn VoidRep args
-
-getCode (StComment s) = returnInstr (COMMENT s)
-
-\end{code}
-
-Generate code to get a subtree into a register.
-
-\begin{code}
-
-getReg :: StixTree -> UniqSM Register
-
-getReg (StReg (StixMagicId stgreg)) =
- case stgRegMap stgreg of
- Just reg -> returnUs (Fixed reg (kindFromMagicId stgreg) id)
- -- cannot be Nothing
-
-getReg (StReg (StixTemp u pk)) = returnUs (Fixed (UnmappedReg u pk) pk id)
-
-getReg (StDouble 0.0)
- = let
- code dst = mkSeqInstrs [FLDZ]
- in
- returnUs (Any DoubleRep code)
-
-getReg (StDouble 1.0)
- = let
- code dst = mkSeqInstrs [FLD1]
- in
- returnUs (Any DoubleRep code)
-
-getReg (StDouble d) =
- getUniqLabelNCG `thenUs` \ lbl ->
- --getNewRegNCG PtrRep `thenUs` \ tmp ->
- let code dst = mkSeqInstrs [
- SEGMENT DataSegment,
- LABEL lbl,
- DATA D [strImmLit ('0' : 'd' :ppShow 80 (ppRational d))],
- SEGMENT TextSegment,
- FLD D (OpImm (ImmCLbl lbl))
- ]
- in
- returnUs (Any DoubleRep code)
-
-getReg (StString s) =
- getUniqLabelNCG `thenUs` \ lbl ->
- let code dst = mkSeqInstrs [
- SEGMENT DataSegment,
- LABEL lbl,
- ASCII True (_UNPK_ s),
- SEGMENT TextSegment,
- MOV L (OpImm (ImmCLbl lbl)) (OpReg dst)]
- in
- returnUs (Any PtrRep code)
-
-getReg (StLitLit s) | _HEAD_ s == '"' && last xs == '"' =
- getUniqLabelNCG `thenUs` \ lbl ->
- let code dst = mkSeqInstrs [
- SEGMENT DataSegment,
- LABEL lbl,
- ASCII False (init xs),
- SEGMENT TextSegment,
- MOV L (OpImm (ImmCLbl lbl)) (OpReg dst)]
- in
- returnUs (Any PtrRep code)
- where
- xs = _UNPK_ (_TAIL_ s)
-
-
-getReg tree@(StIndex _ _ _) = getReg (mangleIndexTree tree)
-
-getReg (StCall fn kind args) =
- genCCall fn kind args `thenUs` \ call ->
- returnUs (Fixed reg kind call)
- where
- reg = if isFloatingRep kind then st0 else eax
-
-getReg (StPrim primop args) =
- case primop of
-
- CharGtOp -> condIntReg GT args
- CharGeOp -> condIntReg GE args
- CharEqOp -> condIntReg EQ args
- CharNeOp -> condIntReg NE args
- CharLtOp -> condIntReg LT args
- CharLeOp -> condIntReg LE args
-
- IntAddOp -> -- this should be optimised by the generic Opts,
- -- I don't know why it is not (sometimes)!
- case args of
- [x, StInt 0] -> getReg x
- _ -> addCode L args
-
- IntSubOp -> subCode L args
- IntMulOp -> trivialCode (IMUL L) args True
- IntQuotOp -> divCode L args True -- division
- IntRemOp -> divCode L args False -- remainder
- IntNegOp -> trivialUCode (NEGI L) args
- IntAbsOp -> absIntCode args
-
- AndOp -> trivialCode (AND L) args True
- OrOp -> trivialCode (OR L) args True
- NotOp -> trivialUCode (NOT L) args
- SllOp -> trivialCode (SHL L) args False
- SraOp -> trivialCode (SAR L) args False
- SrlOp -> trivialCode (SHR L) args False
- ISllOp -> panic "I386Gen:isll"
- ISraOp -> panic "I386Gen:isra"
- ISrlOp -> panic "I386Gen:isrl"
-
- IntGtOp -> condIntReg GT args
- IntGeOp -> condIntReg GE args
- IntEqOp -> condIntReg EQ args
- IntNeOp -> condIntReg NE args
- IntLtOp -> condIntReg LT args
- IntLeOp -> condIntReg LE args
-
- WordGtOp -> condIntReg GU args
- WordGeOp -> condIntReg GEU args
- WordEqOp -> condIntReg EQ args
- WordNeOp -> condIntReg NE args
- WordLtOp -> condIntReg LU args
- WordLeOp -> condIntReg LEU args
-
- AddrGtOp -> condIntReg GU args
- AddrGeOp -> condIntReg GEU args
- AddrEqOp -> condIntReg EQ args
- AddrNeOp -> condIntReg NE args
- AddrLtOp -> condIntReg LU args
- AddrLeOp -> condIntReg LEU args
-
- FloatAddOp -> trivialFCode FloatRep FADD FADD FADDP FADDP args
- FloatSubOp -> trivialFCode FloatRep FSUB FSUBR FSUBP FSUBRP args
- FloatMulOp -> trivialFCode FloatRep FMUL FMUL FMULP FMULP args
- FloatDivOp -> trivialFCode FloatRep FDIV FDIVR FDIVP FDIVRP args
- FloatNegOp -> trivialUFCode FloatRep FCHS args
-
- FloatGtOp -> condFltReg GT args
- FloatGeOp -> condFltReg GE args
- FloatEqOp -> condFltReg EQ args
- FloatNeOp -> condFltReg NE args
- FloatLtOp -> condFltReg LT args
- FloatLeOp -> condFltReg LE args
-
- FloatExpOp -> promoteAndCall SLIT("exp") DoubleRep
- FloatLogOp -> promoteAndCall SLIT("log") DoubleRep
- FloatSqrtOp -> trivialUFCode FloatRep FSQRT args
-
- FloatSinOp -> promoteAndCall SLIT("sin") DoubleRep
- --trivialUFCode FloatRep FSIN args
- FloatCosOp -> promoteAndCall SLIT("cos") DoubleRep
- --trivialUFCode FloatRep FCOS args
- FloatTanOp -> promoteAndCall SLIT("tan") DoubleRep
-
- FloatAsinOp -> promoteAndCall SLIT("asin") DoubleRep
- FloatAcosOp -> promoteAndCall SLIT("acos") DoubleRep
- FloatAtanOp -> promoteAndCall SLIT("atan") DoubleRep
-
- FloatSinhOp -> promoteAndCall SLIT("sinh") DoubleRep
- FloatCoshOp -> promoteAndCall SLIT("cosh") DoubleRep
- FloatTanhOp -> promoteAndCall SLIT("tanh") DoubleRep
-
- FloatPowerOp -> promoteAndCall SLIT("pow") DoubleRep
-
- DoubleAddOp -> trivialFCode DoubleRep FADD FADD FADDP FADDP args
- DoubleSubOp -> trivialFCode DoubleRep FSUB FSUBR FSUBP FSUBRP args
- DoubleMulOp -> trivialFCode DoubleRep FMUL FMUL FMULP FMULP args
- DoubleDivOp -> trivialFCode DoubleRep FDIV FDIVR FDIVP FDIVRP args
- DoubleNegOp -> trivialUFCode DoubleRep FCHS args
-
- DoubleGtOp -> condFltReg GT args
- DoubleGeOp -> condFltReg GE args
- DoubleEqOp -> condFltReg EQ args
- DoubleNeOp -> condFltReg NE args
- DoubleLtOp -> condFltReg LT args
- DoubleLeOp -> condFltReg LE args
-
- DoubleExpOp -> call SLIT("exp") DoubleRep
- DoubleLogOp -> call SLIT("log") DoubleRep
- DoubleSqrtOp -> trivialUFCode DoubleRep FSQRT args
-
- DoubleSinOp -> call SLIT("sin") DoubleRep
- --trivialUFCode DoubleRep FSIN args
- DoubleCosOp -> call SLIT("cos") DoubleRep
- --trivialUFCode DoubleRep FCOS args
- DoubleTanOp -> call SLIT("tan") DoubleRep
-
- DoubleAsinOp -> call SLIT("asin") DoubleRep
- DoubleAcosOp -> call SLIT("acos") DoubleRep
- DoubleAtanOp -> call SLIT("atan") DoubleRep
-
- DoubleSinhOp -> call SLIT("sinh") DoubleRep
- DoubleCoshOp -> call SLIT("cosh") DoubleRep
- DoubleTanhOp -> call SLIT("tanh") DoubleRep
-
- DoublePowerOp -> call SLIT("pow") DoubleRep
-
- OrdOp -> coerceIntCode IntRep args
- ChrOp -> chrCode args
-
- Float2IntOp -> coerceFP2Int args
- Int2FloatOp -> coerceInt2FP FloatRep args
- Double2IntOp -> coerceFP2Int args
- Int2DoubleOp -> coerceInt2FP DoubleRep args
-
- Double2FloatOp -> coerceFltCode args
- Float2DoubleOp -> coerceFltCode args
-
- where
- call fn pk = getReg (StCall fn pk args)
- promoteAndCall fn pk = getReg (StCall fn pk (map promote args))
- where
- promote x = StPrim Float2DoubleOp [x]
-
-getReg (StInd pk mem) =
- getAmode mem `thenUs` \ amode ->
- let
- code = amodeCode amode
- src = amodeAddr amode
- size = kindToSize pk
- code__2 dst = code .
- if pk == DoubleRep || pk == FloatRep
- then mkSeqInstr (FLD {-D-} size (OpAddr src))
- else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
- in
- returnUs (Any pk code__2)
-
-
-getReg (StInt i)
- = let
- src = ImmInt (fromInteger i)
- code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
- in
- returnUs (Any IntRep code)
-
-getReg leaf
- | maybeToBool imm =
- let
- code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
- in
- returnUs (Any PtrRep code)
- where
- imm = maybeImm leaf
- imm__2 = case imm of Just x -> x
-
-\end{code}
-
-Now, given a tree (the argument to an StInd) that references memory,
-produce a suitable addressing mode.
-
-\begin{code}
-
-getAmode :: StixTree -> UniqSM Amode
-
-getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
-
-getAmode (StPrim IntSubOp [x, StInt i])
- =
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- getReg x `thenUs` \ register ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- off = ImmInt (-(fromInteger i))
- in
- returnUs (Amode (Addr (Just reg) Nothing off) code)
-
-getAmode (StPrim IntAddOp [x, StInt i])
- | maybeToBool imm
- = let
- code = mkSeqInstrs []
- in
- returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
- where
- imm = maybeImm x
- imm__2 = case imm of Just x -> x
-
-getAmode (StPrim IntAddOp [x, StInt i])
- =
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- getReg x `thenUs` \ register ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- off = ImmInt (fromInteger i)
- in
- returnUs (Amode (Addr (Just reg) Nothing off) code)
-
-getAmode (StPrim IntAddOp [x, y]) =
- getNewRegNCG PtrRep `thenUs` \ tmp1 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- reg1 = registerName register1 tmp1
- code2 = registerCode register2 tmp2 asmVoid
- reg2 = registerName register2 tmp2
- code__2 = asmParThen [code1, code2]
- in
- returnUs (Amode (Addr (Just reg1) (Just (reg2,4)) (ImmInt 0)) code__2)
-
-getAmode leaf
- | maybeToBool imm =
- let code = mkSeqInstrs []
- in
- returnUs (Amode (ImmAddr imm__2 0) code)
- where
- imm = maybeImm leaf
- imm__2 = case imm of Just x -> x
-
-getAmode other =
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- getReg other `thenUs` \ register ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- off = Nothing
- in
- returnUs (Amode (Addr (Just reg) Nothing (ImmInt 0)) code)
-
-\end{code}
-
-\begin{code}
-getOp
- :: StixTree
- -> UniqSM (CodeBlock I386Instr,Operand, Size) -- code, operator, size
-getOp (StInt i)
- = returnUs (asmParThen [], OpImm (ImmInt (fromInteger i)), L)
-
-getOp (StInd pk mem)
- = getAmode mem `thenUs` \ amode ->
- let
- code = amodeCode amode --asmVoid
- addr = amodeAddr amode
- sz = kindToSize pk
- in returnUs (code, OpAddr addr, sz)
-
-getOp op
- = getReg op `thenUs` \ register ->
- getNewRegNCG (registerKind register)
- `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- pk = registerKind register
- sz = kindToSize pk
- in
- returnUs (code, OpReg reg, sz)
-
-getOpRI
- :: StixTree
- -> UniqSM (CodeBlock I386Instr,Operand, Size) -- code, operator, size
-getOpRI op
- | maybeToBool imm
- = returnUs (asmParThen [], OpImm imm_op, L)
- where
- imm = maybeImm op
- imm_op = case imm of Just x -> x
-
-getOpRI op
- = getReg op `thenUs` \ register ->
- getNewRegNCG (registerKind register)
- `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- pk = registerKind register
- sz = kindToSize pk
- in
- returnUs (code, OpReg reg, sz)
-
-\end{code}
-
-Set up a condition code for a conditional branch.
-
-\begin{code}
-
-getCondition :: StixTree -> UniqSM Condition
-
-getCondition (StPrim primop args) =
- case primop of
-
- CharGtOp -> condIntCode GT args
- CharGeOp -> condIntCode GE args
- CharEqOp -> condIntCode EQ args
- CharNeOp -> condIntCode NE args
- CharLtOp -> condIntCode LT args
- CharLeOp -> condIntCode LE args
-
- IntGtOp -> condIntCode GT args
- IntGeOp -> condIntCode GE args
- IntEqOp -> condIntCode EQ args
- IntNeOp -> condIntCode NE args
- IntLtOp -> condIntCode LT args
- IntLeOp -> condIntCode LE args
-
- WordGtOp -> condIntCode GU args
- WordGeOp -> condIntCode GEU args
- WordEqOp -> condIntCode EQ args
- WordNeOp -> condIntCode NE args
- WordLtOp -> condIntCode LU args
- WordLeOp -> condIntCode LEU args
-
- AddrGtOp -> condIntCode GU args
- AddrGeOp -> condIntCode GEU args
- AddrEqOp -> condIntCode EQ args
- AddrNeOp -> condIntCode NE args
- AddrLtOp -> condIntCode LU args
- AddrLeOp -> condIntCode LEU args
-
- FloatGtOp -> condFltCode GT args
- FloatGeOp -> condFltCode GE args
- FloatEqOp -> condFltCode EQ args
- FloatNeOp -> condFltCode NE args
- FloatLtOp -> condFltCode LT args
- FloatLeOp -> condFltCode LE args
-
- DoubleGtOp -> condFltCode GT args
- DoubleGeOp -> condFltCode GE args
- DoubleEqOp -> condFltCode EQ args
- DoubleNeOp -> condFltCode NE args
- DoubleLtOp -> condFltCode LT args
- DoubleLeOp -> condFltCode LE args
-
-\end{code}
-
-Turn a boolean expression into a condition, to be passed
-back up the tree.
-
-\begin{code}
-
-condIntCode, condFltCode :: Cond -> [StixTree] -> UniqSM Condition
-condIntCode cond [StInd _ x, y]
- | maybeToBool imm
- = getAmode x `thenUs` \ amode ->
- let
- code1 = amodeCode amode asmVoid
- y__2 = amodeAddr amode
- code__2 = asmParThen [code1] .
- mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
- in
- returnUs (Condition False cond code__2)
- where
- imm = maybeImm y
- imm__2 = case imm of Just x -> x
-
-condIntCode cond [x, StInt 0]
- = getReg x `thenUs` \ register1 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code__2 = asmParThen [code1] .
- mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
- in
- returnUs (Condition False cond code__2)
-
-condIntCode cond [x, y]
- | maybeToBool imm
- = getReg x `thenUs` \ register1 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code__2 = asmParThen [code1] .
- mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
- in
- returnUs (Condition False cond code__2)
- where
- imm = maybeImm y
- imm__2 = case imm of Just x -> x
-
-condIntCode cond [StInd _ x, y]
- = getAmode x `thenUs` \ amode ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- code1 = amodeCode amode asmVoid
- src1 = amodeAddr amode
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 = asmParThen [code1, code2] .
- mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
- in
- returnUs (Condition False cond code__2)
-
-condIntCode cond [y, StInd _ x]
- = getAmode x `thenUs` \ amode ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- code1 = amodeCode amode asmVoid
- src1 = amodeAddr amode
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 = asmParThen [code1, code2] .
- mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
- in
- returnUs (Condition False cond code__2)
-
-condIntCode cond [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 = asmParThen [code1, code2] .
- mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
- in
- returnUs (Condition False cond code__2)
-
-condFltCode cond [x, StDouble 0.0] =
- getReg x `thenUs` \ register1 ->
- getNewRegNCG (registerKind register1)
- `thenUs` \ tmp1 ->
- let
- pk1 = registerKind register1
- code1 = registerCode register1 tmp1
- src1 = registerName register1 tmp1
-
- code__2 = asmParThen [code1 asmVoid] .
- mkSeqInstrs [FTST, FSTP D (OpReg st0), -- or FLDZ, FUCOMPP ?
- FNSTSW,
- --AND HB (OpImm (ImmInt 68)) (OpReg eax),
- --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
- SAHF
- ]
- in
- returnUs (Condition True (fixFPCond cond) code__2)
-
-condFltCode cond [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG (registerKind register1)
- `thenUs` \ tmp1 ->
- getNewRegNCG (registerKind register2)
- `thenUs` \ tmp2 ->
- let
- pk1 = registerKind register1
- code1 = registerCode register1 tmp1
- src1 = registerName register1 tmp1
-
- code2 = registerCode register2 tmp2
- src2 = registerName register2 tmp2
-
- code__2 = asmParThen [code2 asmVoid, code1 asmVoid] .
- mkSeqInstrs [FUCOMPP,
- FNSTSW,
- --AND HB (OpImm (ImmInt 68)) (OpReg eax),
- --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
- SAHF
- ]
- in
- returnUs (Condition True (fixFPCond cond) code__2)
-
-\end{code}
-
-Turn those condition codes into integers now (when they appear on
-the right hand side of an assignment).
-
-\begin{code}
-
-condIntReg :: Cond -> [StixTree] -> UniqSM Register
-condIntReg cond args =
- condIntCode cond args `thenUs` \ condition ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- --getReg dst `thenUs` \ register ->
- let
- --code2 = registerCode register tmp asmVoid
- --dst__2 = registerName register tmp
- code = condCode condition
- cond = condName condition
--- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
- code__2 dst = code . mkSeqInstrs [
- SETCC cond (OpReg tmp),
- AND L (OpImm (ImmInt 1)) (OpReg tmp),
- MOV L (OpReg tmp) (OpReg dst)]
- in
- returnUs (Any IntRep code__2)
-
-condFltReg :: Cond -> [StixTree] -> UniqSM Register
-
-condFltReg cond args =
- getUniqLabelNCG `thenUs` \ lbl1 ->
- getUniqLabelNCG `thenUs` \ lbl2 ->
- condFltCode cond args `thenUs` \ condition ->
- let
- code = condCode condition
- cond = condName condition
- code__2 dst = code . mkSeqInstrs [
- JXX cond lbl1,
- MOV L (OpImm (ImmInt 0)) (OpReg dst),
- JXX ALWAYS lbl2,
- LABEL lbl1,
- MOV L (OpImm (ImmInt 1)) (OpReg dst),
- LABEL lbl2]
- in
- returnUs (Any IntRep code__2)
-
-\end{code}
-
-Assignments are really at the heart of the whole code generation business.
-Almost all top-level nodes of any real importance are assignments, which
-correspond to loads, stores, or register transfers. If we're really lucky,
-some of the register transfers will go away, because we can use the destination
-register to complete the code generation for the right hand side. This only
-fails when the right hand side is forced into a fixed register (e.g. the result
-of a call).
-
-\begin{code}
-
-assignIntCode :: PrimRep -> StixTree -> StixTree -> UniqSM (CodeBlock I386Instr)
-assignIntCode pk (StInd _ dst) src
- = getAmode dst `thenUs` \ amode ->
- getOpRI src `thenUs` \ (codesrc, opsrc, sz) ->
- let
- code1 = amodeCode amode asmVoid
- dst__2 = amodeAddr amode
- code__2 = asmParThen [code1, codesrc asmVoid] .
- mkSeqInstr (MOV sz opsrc (OpAddr dst__2))
- in
- returnUs code__2
-
-assignIntCode pk dst (StInd _ src) =
- getNewRegNCG IntRep `thenUs` \ tmp ->
- getAmode src `thenUs` \ amode ->
- getReg dst `thenUs` \ register ->
- let
- code1 = amodeCode amode asmVoid
- src__2 = amodeAddr amode
- code2 = registerCode register tmp asmVoid
- dst__2 = registerName register tmp
- sz = kindToSize pk
- code__2 = asmParThen [code1, code2] .
- mkSeqInstr (MOV sz (OpAddr src__2) (OpReg dst__2))
- in
- returnUs code__2
-
-assignIntCode pk dst src =
- getReg dst `thenUs` \ register1 ->
- getReg src `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- dst__2 = registerName register1 tmp
- code = registerCode register2 dst__2
- src__2 = registerName register2 dst__2
- code__2 = if isFixed register2 && dst__2 /= src__2
- then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
- else
- code
- in
- returnUs code__2
-
-assignFltCode :: PrimRep -> StixTree -> StixTree -> UniqSM (CodeBlock I386Instr)
-assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
- = getNewRegNCG IntRep `thenUs` \ tmp ->
- getAmode src `thenUs` \ amodesrc ->
- getAmode dst `thenUs` \ amodedst ->
- --getReg src `thenUs` \ register ->
- let
- codesrc1 = amodeCode amodesrc asmVoid
- addrsrc1 = amodeAddr amodesrc
- codedst1 = amodeCode amodedst asmVoid
- addrdst1 = amodeAddr amodedst
- addrsrc2 = case (offset addrsrc1 4) of Just x -> x
- addrdst2 = case (offset addrdst1 4) of Just x -> x
-
- code__2 = asmParThen [codesrc1, codedst1] .
- mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
- MOV L (OpReg tmp) (OpAddr addrdst1)]
- ++
- if pk == DoubleRep
- then [MOV L (OpAddr addrsrc2) (OpReg tmp),
- MOV L (OpReg tmp) (OpAddr addrdst2)]
- else [])
- in
- returnUs code__2
-
-assignFltCode pk (StInd _ dst) src =
- --getNewRegNCG pk `thenUs` \ tmp ->
- getAmode dst `thenUs` \ amode ->
- getReg src `thenUs` \ register ->
- let
- sz = kindToSize pk
- dst__2 = amodeAddr amode
-
- code1 = amodeCode amode asmVoid
- code2 = registerCode register {-tmp-}st0 asmVoid
-
- --src__2 = registerName register tmp
- pk__2 = registerKind register
- sz__2 = kindToSize pk__2
-
- code__2 = asmParThen [code1, code2] .
- mkSeqInstr (FSTP sz (OpAddr dst__2))
- in
- returnUs code__2
-
-assignFltCode pk dst src =
- getReg dst `thenUs` \ register1 ->
- getReg src `thenUs` \ register2 ->
- --getNewRegNCG (registerKind register2)
- -- `thenUs` \ tmp ->
- let
- sz = kindToSize pk
- dst__2 = registerName register1 st0 --tmp
-
- code = registerCode register2 dst__2
- src__2 = registerName register2 dst__2
-
- code__2 = code
- in
- returnUs code__2
-
-\end{code}
-
-Generating an unconditional branch. We accept two types of targets:
-an immediate CLabel or a tree that gets evaluated into a register.
-Any CLabels which are AsmTemporaries are assumed to be in the local
-block of code, close enough for a branch instruction. Other CLabels
-are assumed to be far away, so we use call.
-
-Do not fill the delay slots here; you will confuse the register allocator.
-
-\begin{code}
-
-genJump
- :: StixTree -- the branch target
- -> UniqSM (CodeBlock I386Instr)
-
-{-
-genJump (StCLbl lbl)
- | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
- | otherwise = returnInstrs [JMP (OpImm target)]
- where
- target = ImmCLbl lbl
--}
-
-genJump (StInd pk mem) =
- getAmode mem `thenUs` \ amode ->
- let
- code = amodeCode amode
- target = amodeAddr amode
- in
- returnSeq code [JMP (OpAddr target)]
-
-genJump tree
- | maybeToBool imm
- = returnInstr (JMP (OpImm target))
- where
- imm = maybeImm tree
- target = case imm of Just x -> x
-
-
-genJump tree =
- getReg tree `thenUs` \ register ->
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- target = registerName register tmp
- in
- returnSeq code [JMP (OpReg target)]
-
-\end{code}
-
-Conditional jumps are always to local labels, so we can use
-branch instructions. First, we have to ensure that the condition
-codes are set according to the supplied comparison operation.
-
-\begin{code}
-
-genCondJump
- :: CLabel -- the branch target
- -> StixTree -- the condition on which to branch
- -> UniqSM (CodeBlock I386Instr)
-
-genCondJump lbl bool =
- getCondition bool `thenUs` \ condition ->
- let
- code = condCode condition
- cond = condName condition
- target = ImmCLbl lbl
- in
- returnSeq code [JXX cond lbl]
-
-\end{code}
-
-\begin{code}
-
-genCCall
- :: FAST_STRING -- function to call
- -> PrimRep -- type of the result
- -> [StixTree] -- arguments (of mixed type)
- -> UniqSM (CodeBlock I386Instr)
-
-genCCall fn kind [StInt i]
- | fn == SLIT ("PerformGC_wrapper")
- = getUniqLabelNCG `thenUs` \ lbl ->
- let
- call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
- MOV L (OpImm (ImmCLbl lbl))
- -- this is hardwired
- (OpAddr (Addr (Just ebx) Nothing (ImmInt 104))),
- JMP (OpImm (ImmLit (uppPStr (SLIT ("_PerformGC_wrapper"))))),
- LABEL lbl]
- in
- returnInstrs call
-
-genCCall fn kind args =
- mapUs getCallArg args `thenUs` \ argCode ->
- let
- nargs = length args
- code1 = asmParThen [asmSeq [ -- MOV L (OpReg esp) (OpAddr (Addr (Just ebx) Nothing (ImmInt 80))),
- MOV L (OpAddr (Addr (Just ebx) Nothing (ImmInt 100))) (OpReg esp)
- ]
- ]
- code2 = asmParThen (map ($ asmVoid) (reverse argCode))
- call = [CALL (ImmLit fn__2) -- ,
- -- ADD L (OpImm (ImmInt (nargs * 4))) (OpReg esp),
- -- MOV L (OpAddr (Addr (Just ebx) Nothing (ImmInt 80))) (OpReg esp)
- ]
- in
- returnSeq (code1 . code2) call
- where
- -- function names that begin with '.' are assumed to be special internally
- -- generated names like '.mul,' which don't get an underscore prefix
- fn__2 = case (_HEAD_ fn) of
- '.' -> uppPStr fn
- _ -> uppBeside (uppChar '_') (uppPStr fn)
-
- getCallArg
- :: StixTree -- Current argument
- -> UniqSM (CodeBlock I386Instr) -- code
- getCallArg arg =
- getOp arg `thenUs` \ (code, op, sz) ->
- returnUs (code . mkSeqInstr (PUSH sz op))
-\end{code}
-
-Trivial (dyadic) instructions. Only look for constants on the right hand
-side, because that's where the generic optimizer will have put them.
-
-\begin{code}
-
-trivialCode
- :: (Operand -> Operand -> I386Instr)
- -> [StixTree]
- -> Bool -- is the instr commutative?
- -> UniqSM Register
-
-trivialCode instr [x, y] _
- | maybeToBool imm
- = getReg x `thenUs` \ register1 ->
- --getNewRegNCG IntRep `thenUs` \ tmp1 ->
- let
- fixedname = registerName register1 eax
- code__2 dst = let code1 = registerCode register1 dst
- src1 = registerName register1 dst
- in code1 .
- if isFixed register1 && src1 /= dst
- then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
- instr (OpImm imm__2) (OpReg dst)]
- else
- mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
- in
- returnUs (Any IntRep code__2)
- where
- imm = maybeImm y
- imm__2 = case imm of Just x -> x
-
-trivialCode instr [x, y] _
- | maybeToBool imm
- = getReg y `thenUs` \ register1 ->
- --getNewRegNCG IntRep `thenUs` \ tmp1 ->
- let
- fixedname = registerName register1 eax
- code__2 dst = let code1 = registerCode register1 dst
- src1 = registerName register1 dst
- in code1 .
- if isFixed register1 && src1 /= dst
- then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
- instr (OpImm imm__2) (OpReg dst)]
- else
- mkSeqInstr (instr (OpImm imm__2) (OpReg src1))
- in
- returnUs (Any IntRep code__2)
- where
- imm = maybeImm x
- imm__2 = case imm of Just x -> x
-
-trivialCode instr [x, StInd pk mem] _
- = getReg x `thenUs` \ register ->
- --getNewRegNCG IntRep `thenUs` \ tmp ->
- getAmode mem `thenUs` \ amode ->
- let
- fixedname = registerName register eax
- code2 = amodeCode amode asmVoid
- src2 = amodeAddr amode
- code__2 dst = let code1 = registerCode register dst asmVoid
- src1 = registerName register dst
- in asmParThen [code1, code2] .
- if isFixed register && src1 /= dst
- then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
- instr (OpAddr src2) (OpReg dst)]
- else
- mkSeqInstr (instr (OpAddr src2) (OpReg src1))
- in
- returnUs (Any pk code__2)
-
-trivialCode instr [StInd pk mem, y] _
- = getReg y `thenUs` \ register ->
- --getNewRegNCG IntRep `thenUs` \ tmp ->
- getAmode mem `thenUs` \ amode ->
- let
- fixedname = registerName register eax
- code2 = amodeCode amode asmVoid
- src2 = amodeAddr amode
- code__2 dst = let
- code1 = registerCode register dst asmVoid
- src1 = registerName register dst
- in asmParThen [code1, code2] .
- if isFixed register && src1 /= dst
- then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
- instr (OpAddr src2) (OpReg dst)]
- else
- mkSeqInstr (instr (OpAddr src2) (OpReg src1))
- in
- returnUs (Any pk code__2)
-
-trivialCode instr [x, y] is_comm_op
- = getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- --getNewRegNCG IntRep `thenUs` \ tmp1 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- fixedname = registerName register1 eax
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 dst = let
- code1 = registerCode register1 dst asmVoid
- src1 = registerName register1 dst
- in asmParThen [code1, code2] .
- if isFixed register1 && src1 /= dst
- then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
- instr (OpReg src2) (OpReg dst)]
- else
- mkSeqInstr (instr (OpReg src2) (OpReg src1))
- in
- returnUs (Any IntRep code__2)
-
-addCode
- :: Size
- -> [StixTree]
- -> UniqSM Register
-addCode sz [x, StInt y]
- =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src1 = registerName register tmp
- src2 = ImmInt (fromInteger y)
- code__2 dst = code .
- mkSeqInstr (LEA sz (OpAddr (Addr (Just src1) Nothing src2)) (OpReg dst))
- in
- returnUs (Any IntRep code__2)
-
-addCode sz [x, StInd _ mem]
- = getReg x `thenUs` \ register1 ->
- --getNewRegNCG (registerKind register1)
- -- `thenUs` \ tmp1 ->
- getAmode mem `thenUs` \ amode ->
- let
- code2 = amodeCode amode
- src2 = amodeAddr amode
-
- fixedname = registerName register1 eax
- code__2 dst = let code1 = registerCode register1 dst
- src1 = registerName register1 dst
- in asmParThen [code2 asmVoid,code1 asmVoid] .
- if isFixed register1 && src1 /= dst
- then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
- ADD sz (OpAddr src2) (OpReg dst)]
- else
- mkSeqInstrs [ADD sz (OpAddr src2) (OpReg src1)]
- in
- returnUs (Any IntRep code__2)
-
-addCode sz [StInd _ mem, y]
- = getReg y `thenUs` \ register2 ->
- --getNewRegNCG (registerKind register2)
- -- `thenUs` \ tmp2 ->
- getAmode mem `thenUs` \ amode ->
- let
- code1 = amodeCode amode
- src1 = amodeAddr amode
-
- fixedname = registerName register2 eax
- code__2 dst = let code2 = registerCode register2 dst
- src2 = registerName register2 dst
- in asmParThen [code1 asmVoid,code2 asmVoid] .
- if isFixed register2 && src2 /= dst
- then mkSeqInstrs [MOV L (OpReg src2) (OpReg dst),
- ADD sz (OpAddr src1) (OpReg dst)]
- else
- mkSeqInstrs [ADD sz (OpAddr src1) (OpReg src2)]
- in
- returnUs (Any IntRep code__2)
-
-addCode sz [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 dst = asmParThen [code1, code2] .
- mkSeqInstr (LEA sz (OpAddr (Addr (Just src1) (Just (src2,1)) (ImmInt 0))) (OpReg dst))
- in
- returnUs (Any IntRep code__2)
-
-subCode
- :: Size
- -> [StixTree]
- -> UniqSM Register
-subCode sz [x, StInt y]
- = getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src1 = registerName register tmp
- src2 = ImmInt (-(fromInteger y))
- code__2 dst = code .
- mkSeqInstr (LEA sz (OpAddr (Addr (Just src1) Nothing src2)) (OpReg dst))
- in
- returnUs (Any IntRep code__2)
-
-subCode sz args = trivialCode (SUB sz) args False
-
-divCode
- :: Size
- -> [StixTree]
- -> Bool -- True => division, False => remainder operation
- -> UniqSM Register
-
--- x must go into eax, edx must be a sign-extension of eax,
--- and y should go in some other register (or memory),
--- so that we get edx:eax / reg -> eax (remainder in edx)
--- Currently we chose to put y in memory (if it is not there already)
-divCode sz [x, StInd pk mem] is_division
- = getReg x `thenUs` \ register1 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- getAmode mem `thenUs` \ amode ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code2 = amodeCode amode asmVoid
- src2 = amodeAddr amode
- code__2 = asmParThen [code1, code2] .
- mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
- CLTD,
- IDIV sz (OpAddr src2)]
- in
- returnUs (Fixed (if is_division then eax else edx) IntRep code__2)
-
-divCode sz [x, StInt i] is_division
- = getReg x `thenUs` \ register1 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- src2 = ImmInt (fromInteger i)
- code__2 = asmParThen [code1] .
- mkSeqInstrs [-- we put src2 in (ebx)
- MOV L (OpImm src2) (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1))),
- MOV L (OpReg src1) (OpReg eax),
- CLTD,
- IDIV sz (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1)))]
- in
- returnUs (Fixed (if is_division then eax else edx) IntRep code__2)
-
-divCode sz [x, y] is_division
- = getReg x `thenUs` \ register1 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 = asmParThen [code1, code2] .
- if src2 == ecx || src2 == esi
- then mkSeqInstrs [ MOV L (OpReg src1) (OpReg eax),
- CLTD,
- IDIV sz (OpReg src2)]
- else mkSeqInstrs [ -- we put src2 in (ebx)
- MOV L (OpReg src2) (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1))),
- MOV L (OpReg src1) (OpReg eax),
- CLTD,
- IDIV sz (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1)))]
- in
- returnUs (Fixed (if is_division then eax else edx) IntRep code__2)
-
-trivialFCode
- :: PrimRep
- -> (Size -> Operand -> I386Instr)
- -> (Size -> Operand -> I386Instr) -- reversed instr
- -> I386Instr -- pop
- -> I386Instr -- reversed instr, pop
- -> [StixTree]
- -> UniqSM Register
-trivialFCode pk _ instrr _ _ [StInd pk' mem, y]
- = getReg y `thenUs` \ register2 ->
- --getNewRegNCG (registerKind register2)
- -- `thenUs` \ tmp2 ->
- getAmode mem `thenUs` \ amode ->
- let
- code1 = amodeCode amode
- src1 = amodeAddr amode
-
- code__2 dst = let
- code2 = registerCode register2 dst
- src2 = registerName register2 dst
- in asmParThen [code1 asmVoid,code2 asmVoid] .
- mkSeqInstrs [instrr (kindToSize pk) (OpAddr src1)]
- in
- returnUs (Any pk code__2)
-
-trivialFCode pk instr _ _ _ [x, StInd pk' mem]
- = getReg x `thenUs` \ register1 ->
- --getNewRegNCG (registerKind register1)
- -- `thenUs` \ tmp1 ->
- getAmode mem `thenUs` \ amode ->
- let
- code2 = amodeCode amode
- src2 = amodeAddr amode
-
- code__2 dst = let
- code1 = registerCode register1 dst
- src1 = registerName register1 dst
- in asmParThen [code2 asmVoid,code1 asmVoid] .
- mkSeqInstrs [instr (kindToSize pk) (OpAddr src2)]
- in
- returnUs (Any pk code__2)
-
-trivialFCode pk _ _ _ instrpr [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- --getNewRegNCG (registerKind register1)
- -- `thenUs` \ tmp1 ->
- --getNewRegNCG (registerKind register2)
- -- `thenUs` \ tmp2 ->
- getNewRegNCG DoubleRep `thenUs` \ tmp ->
- let
- pk1 = registerKind register1
- code1 = registerCode register1 st0 --tmp1
- src1 = registerName register1 st0 --tmp1
-
- pk2 = registerKind register2
-
- code__2 dst = let
- code2 = registerCode register2 dst
- src2 = registerName register2 dst
- in asmParThen [code1 asmVoid, code2 asmVoid] .
- mkSeqInstr instrpr
- in
- returnUs (Any pk1 code__2)
-
-\end{code}
-
-Trivial unary instructions. Note that we don't have to worry about
-matching an StInt as the argument, because genericOpt will already
-have handled the constant-folding.
-
-\begin{code}
-
-trivialUCode
- :: (Operand -> I386Instr)
- -> [StixTree]
- -> UniqSM Register
-
-trivialUCode instr [x] =
- getReg x `thenUs` \ register ->
--- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
--- fixedname = registerName register eax
- code__2 dst = let
- code = registerCode register dst
- src = registerName register dst
- in code . if isFixed register && dst /= src
- then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
- instr (OpReg dst)]
- else mkSeqInstr (instr (OpReg src))
- in
- returnUs (Any IntRep code__2)
-
-trivialUFCode
- :: PrimRep
- -> I386Instr
- -> [StixTree]
- -> UniqSM Register
-
-trivialUFCode pk instr [StInd pk' mem] =
- getAmode mem `thenUs` \ amode ->
- let
- code = amodeCode amode
- src = amodeAddr amode
- code__2 dst = code . mkSeqInstrs [FLD (kindToSize pk) (OpAddr src),
- instr]
- in
- returnUs (Any pk code__2)
-
-trivialUFCode pk instr [x] =
- getReg x `thenUs` \ register ->
- --getNewRegNCG pk `thenUs` \ tmp ->
- let
- code__2 dst = let
- code = registerCode register dst
- src = registerName register dst
- in code . mkSeqInstrs [instr]
- in
- returnUs (Any pk code__2)
-\end{code}
-
-Absolute value on integers, mostly for gmp size check macros. Again,
-the argument cannot be an StInt, because genericOpt already folded
-constants.
-
-\begin{code}
-
-absIntCode :: [StixTree] -> UniqSM Register
-absIntCode [x] =
- getReg x `thenUs` \ register ->
- --getNewRegNCG IntRep `thenUs` \ reg ->
- getUniqLabelNCG `thenUs` \ lbl ->
- let
- code__2 dst = let code = registerCode register dst
- src = registerName register dst
- in code . if isFixed register && dst /= src
- then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
- TEST L (OpReg dst) (OpReg dst),
- JXX GE lbl,
- NEGI L (OpReg dst),
- LABEL lbl]
- else mkSeqInstrs [TEST L (OpReg src) (OpReg src),
- JXX GE lbl,
- NEGI L (OpReg src),
- LABEL lbl]
- in
- returnUs (Any IntRep code__2)
-
-\end{code}
-
-Simple integer coercions that don't require any code to be generated.
-Here we just change the type on the register passed on up
-
-\begin{code}
-
-coerceIntCode :: PrimRep -> [StixTree] -> UniqSM Register
-coerceIntCode pk [x] =
- getReg x `thenUs` \ register ->
- case register of
- Fixed reg _ code -> returnUs (Fixed reg pk code)
- Any _ code -> returnUs (Any pk code)
-
-coerceFltCode :: [StixTree] -> UniqSM Register
-coerceFltCode [x] =
- getReg x `thenUs` \ register ->
- case register of
- Fixed reg _ code -> returnUs (Fixed reg DoubleRep code)
- Any _ code -> returnUs (Any DoubleRep code)
-
-\end{code}
-
-Integer to character conversion. We try to do this in one step if
-the original object is in memory.
-
-\begin{code}
-chrCode :: [StixTree] -> UniqSM Register
-{-
-chrCode [StInd pk mem] =
- getAmode mem `thenUs` \ amode ->
- let
- code = amodeCode amode
- src = amodeAddr amode
- code__2 dst = code . mkSeqInstr (MOVZX L (OpAddr src) (OpReg dst))
- in
- returnUs (Any pk code__2)
--}
-chrCode [x] =
- getReg x `thenUs` \ register ->
- --getNewRegNCG IntRep `thenUs` \ reg ->
- let
- fixedname = registerName register eax
- code__2 dst = let
- code = registerCode register dst
- src = registerName register dst
- in code .
- if isFixed register && src /= dst
- then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
- AND L (OpImm (ImmInt 255)) (OpReg dst)]
- else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
- in
- returnUs (Any IntRep code__2)
-
-\end{code}
-
-More complicated integer/float conversions. Here we have to store
-temporaries in memory to move between the integer and the floating
-point register sets.
-
-\begin{code}
-coerceInt2FP :: PrimRep -> [StixTree] -> UniqSM Register
-coerceInt2FP pk [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ reg ->
- let
- code = registerCode register reg
- src = registerName register reg
-
- code__2 dst = code . mkSeqInstrs [
- -- to fix: should spill instead of using R1
- MOV L (OpReg src) (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1))),
- FILD (kindToSize pk) (Addr (Just ebx) Nothing (ImmInt OFFSET_R1)) dst]
- in
- returnUs (Any pk code__2)
-
-coerceFP2Int :: [StixTree] -> UniqSM Register
-coerceFP2Int [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG DoubleRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
- pk = registerKind register
-
- code__2 dst = let
- in code . mkSeqInstrs [
- FRNDINT,
- FIST L (Addr (Just ebx) Nothing (ImmInt OFFSET_R1)),
- MOV L (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1))) (OpReg dst)]
- in
- returnUs (Any IntRep code__2)
-\end{code}
-
-Some random little helpers.
-
-\begin{code}
-
-maybeImm :: StixTree -> Maybe Imm
-maybeImm (StInt i)
- | i >= toInteger minInt && i <= toInteger maxInt = Just (ImmInt (fromInteger i))
- | otherwise = Just (ImmInteger i)
-maybeImm (StLitLbl s) = Just (ImmLit (uppBeside (uppChar '_') s))
-maybeImm (StLitLit s) = Just (strImmLit (cvtLitLit (_UNPK_ s)))
-maybeImm (StCLbl l) = Just (ImmCLbl l)
-maybeImm _ = Nothing
-
-mangleIndexTree :: StixTree -> StixTree
-
-mangleIndexTree (StIndex pk base (StInt i)) =
- StPrim IntAddOp [base, off]
- where
- off = StInt (i * size pk)
- size :: PrimRep -> Integer
- size pk = case kindToSize pk of
- {B -> 1; S -> 2; L -> 4; F -> 4; D -> 8 }
-
-mangleIndexTree (StIndex pk base off) =
- case pk of
- CharRep -> StPrim IntAddOp [base, off]
- _ -> StPrim IntAddOp [base, off__2]
- where
- off__2 = StPrim SllOp [off, StInt (shift pk)]
- shift :: PrimRep -> Integer
- shift DoubleRep = 3
- shift _ = 2
-
-cvtLitLit :: String -> String
-cvtLitLit "stdin" = "_IO_stdin_"
-cvtLitLit "stdout" = "_IO_stdout_"
-cvtLitLit "stderr" = "_IO_stderr_"
-cvtLitLit s
- | isHex s = s
- | otherwise = error ("Native code generator can't handle ``" ++ s ++ "''")
- where
- isHex ('0':'x':xs) = all isHexDigit xs
- isHex _ = False
- -- Now, where have I seen this before?
- isHexDigit c = isDigit c || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'
-
-
-\end{code}
-
-\begin{code}
-
-stackArgLoc = 23 :: Int -- where to stack call arguments
-
-\end{code}
-
-\begin{code}
-
-getNewRegNCG :: PrimRep -> UniqSM Reg
-getNewRegNCG pk =
- getUnique `thenUs` \ u ->
- returnUs (mkReg u pk)
-
-fixFPCond :: Cond -> Cond
--- on the 486 the flags set by FP compare are the unsigned ones!
-fixFPCond GE = GEU
-fixFPCond GT = GU
-fixFPCond LT = LU
-fixFPCond LE = LEU
-fixFPCond any = any
-\end{code}
--- /dev/null
+%
+% (c) The AQUA Project, Glasgow University, 1996
+%
+\section[MachCode]{Generating machine code}
+
+This is a big module, but, if you pay attention to
+(a) the sectioning, (b) the type signatures, and
+(c) the \tr{#if blah_TARGET_ARCH} things, the
+structure should not be too overwhelming.
+
+\begin{code}
+#include "HsVersions.h"
+#include "nativeGen/NCG.h"
+
+module MachCode ( stmt2Instrs, asmVoid, InstrList(..) ) where
+
+import Ubiq{-uitious-}
+
+import MachMisc -- may differ per-platform
+import MachRegs
+
+import AbsCSyn ( MagicId )
+import AbsCUtils ( magicIdPrimRep )
+import CLabel ( isAsmTemp )
+import Maybes ( maybeToBool, expectJust )
+import OrdList -- quite a bit of it
+import Pretty ( prettyToUn, ppRational )
+import PrimRep ( isFloatingRep, PrimRep(..) )
+import PrimOp ( PrimOp(..) )
+import Stix ( getUniqLabelNCG, StixTree(..),
+ StixReg(..), CodeSegment(..)
+ )
+import UniqSupply ( returnUs, thenUs, mapUs, mapAndUnzipUs,
+ mapAccumLUs, UniqSM(..)
+ )
+import Unpretty ( uppPStr )
+import Util ( panic, assertPanic )
+\end{code}
+
+Code extractor for an entire stix tree---stix statement level.
+
+\begin{code}
+stmt2Instrs :: StixTree {- a stix statement -} -> UniqSM InstrBlock
+
+stmt2Instrs stmt = case stmt of
+ StComment s -> returnInstr (COMMENT s)
+ StSegment seg -> returnInstr (SEGMENT seg)
+ StFunBegin lab -> returnInstr (IF_ARCH_alpha(FUNBEGIN lab,LABEL lab))
+ StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
+ StLabel lab -> returnInstr (LABEL lab)
+
+ StJump arg -> genJump arg
+ StCondJump lab arg -> genCondJump lab arg
+ StCall fn VoidRep args -> genCCall fn VoidRep args
+
+ StAssign pk dst src
+ | isFloatingRep pk -> assignFltCode pk dst src
+ | otherwise -> assignIntCode pk dst src
+
+ StFallThrough lbl
+ -- When falling through on the Alpha, we still have to load pv
+ -- with the address of the next routine, so that it can load gp.
+ -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
+ ,returnUs id)
+
+ StData kind args
+ -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
+ returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
+ (foldr1 (.) codes xs))
+ where
+ getData :: StixTree -> UniqSM (InstrBlock, Imm)
+
+ getData (StInt i) = returnUs (id, ImmInteger i)
+ getData (StDouble d) = returnUs (id, dblImmLit d)
+ getData (StLitLbl s) = returnUs (id, ImmLab s)
+ getData (StLitLit s) = returnUs (id, strImmLit (cvtLitLit (_UNPK_ s)))
+ getData (StCLbl l) = returnUs (id, ImmCLbl l)
+ getData (StString s) =
+ getUniqLabelNCG `thenUs` \ lbl ->
+ returnUs (mkSeqInstrs [LABEL lbl,
+ ASCII True (_UNPK_ s)],
+ ImmCLbl lbl)
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{General things for putting together code sequences}
+%* *
+%************************************************************************
+
+\begin{code}
+type InstrList = OrdList Instr
+type InstrBlock = InstrList -> InstrList
+
+asmVoid :: InstrList
+asmVoid = mkEmptyList
+
+asmInstr :: Instr -> InstrList
+asmInstr i = mkUnitList i
+
+asmSeq :: [Instr] -> InstrList
+asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
+
+asmParThen :: [InstrList] -> InstrBlock
+asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
+
+returnInstr :: Instr -> UniqSM InstrBlock
+returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
+
+returnInstrs :: [Instr] -> UniqSM InstrBlock
+returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
+
+returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
+returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
+
+mkSeqInstr :: Instr -> InstrBlock
+mkSeqInstr instr code = mkSeqList (asmInstr instr) code
+
+mkSeqInstrs :: [Instr] -> InstrBlock
+mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
+\end{code}
+
+\begin{code}
+mangleIndexTree :: StixTree -> StixTree
+
+mangleIndexTree (StIndex pk base (StInt i))
+ = StPrim IntAddOp [base, off]
+ where
+ off = StInt (i * sizeOf pk)
+
+mangleIndexTree (StIndex pk base off)
+ = StPrim IntAddOp [base,
+ case pk of
+ CharRep -> off
+ _ -> let
+ s = shift pk
+ in
+ ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
+ StPrim SllOp [off, StInt s]
+ ]
+ where
+ shift DoubleRep = 3
+ shift _ = IF_ARCH_alpha(3,2)
+\end{code}
+
+\begin{code}
+maybeImm :: StixTree -> Maybe Imm
+
+maybeImm (StLitLbl s) = Just (ImmLab s)
+maybeImm (StLitLit s) = Just (strImmLit (cvtLitLit (_UNPK_ s)))
+maybeImm (StCLbl l) = Just (ImmCLbl l)
+
+maybeImm (StInt i)
+ | i >= toInteger minInt && i <= toInteger maxInt
+ = Just (ImmInt (fromInteger i))
+ | otherwise
+ = Just (ImmInteger i)
+
+maybeImm _ = Nothing
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{The @Register@ type}
+%* *
+%************************************************************************
+
+@Register@s passed up the tree. If the stix code forces the register
+to live in a pre-decided machine register, it comes out as @Fixed@;
+otherwise, it comes out as @Any@, and the parent can decide which
+register to put it in.
+
+\begin{code}
+data Register
+ = Fixed PrimRep Reg InstrBlock
+ | Any PrimRep (Reg -> InstrBlock)
+
+registerCode :: Register -> Reg -> InstrBlock
+registerCode (Fixed _ _ code) reg = code
+registerCode (Any _ code) reg = code reg
+
+registerName :: Register -> Reg -> Reg
+registerName (Fixed _ reg _) _ = reg
+registerName (Any _ _) reg = reg
+
+registerRep :: Register -> PrimRep
+registerRep (Fixed pk _ _) = pk
+registerRep (Any pk _) = pk
+
+isFixed :: Register -> Bool
+isFixed (Fixed _ _ _) = True
+isFixed (Any _ _) = False
+\end{code}
+
+Generate code to get a subtree into a @Register@:
+\begin{code}
+getRegister :: StixTree -> UniqSM Register
+
+getRegister (StReg (StixMagicId stgreg))
+ = case (magicIdRegMaybe stgreg) of
+ Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
+ -- cannae be Nothing
+
+getRegister (StReg (StixTemp u pk))
+ = returnUs (Fixed pk (UnmappedReg u pk) id)
+
+getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
+
+getRegister (StCall fn kind args)
+ = genCCall fn kind args `thenUs` \ call ->
+ returnUs (Fixed kind reg call)
+ where
+ reg = if isFloatingRep kind
+ then IF_ARCH_alpha( f0, IF_ARCH_i386( st0, IF_ARCH_sparc( f0,)))
+ else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
+
+getRegister (StString s)
+ = getUniqLabelNCG `thenUs` \ lbl ->
+ let
+ imm_lbl = ImmCLbl lbl
+
+ code dst = mkSeqInstrs [
+ SEGMENT DataSegment,
+ LABEL lbl,
+ ASCII True (_UNPK_ s),
+ SEGMENT TextSegment,
+#if alpha_TARGET_ARCH
+ LDA dst (AddrImm imm_lbl)
+#endif
+#if i386_TARGET_ARCH
+ MOV L (OpImm imm_lbl) (OpReg dst)
+#endif
+#if sparc_TARGET_ARCH
+ SETHI (HI imm_lbl) dst,
+ OR False dst (RIImm (LO imm_lbl)) dst
+#endif
+ ]
+ in
+ returnUs (Any PtrRep code)
+
+getRegister (StLitLit s) | _HEAD_ s == '"' && last xs == '"'
+ = getUniqLabelNCG `thenUs` \ lbl ->
+ let
+ imm_lbl = ImmCLbl lbl
+
+ code dst = mkSeqInstrs [
+ SEGMENT DataSegment,
+ LABEL lbl,
+ ASCII False (init xs),
+ SEGMENT TextSegment,
+#if alpha_TARGET_ARCH
+ LDA dst (AddrImm imm_lbl)
+#endif
+#if i386_TARGET_ARCH
+ MOV L (OpImm imm_lbl) (OpReg dst)
+#endif
+#if sparc_TARGET_ARCH
+ SETHI (HI imm_lbl) dst,
+ OR False dst (RIImm (LO imm_lbl)) dst
+#endif
+ ]
+ in
+ returnUs (Any PtrRep code)
+ where
+ xs = _UNPK_ (_TAIL_ s)
+
+-- end of machine-"independent" bit; here we go on the rest...
+
+#if alpha_TARGET_ARCH
+
+getRegister (StDouble d)
+ = getUniqLabelNCG `thenUs` \ lbl ->
+ getNewRegNCG PtrRep `thenUs` \ tmp ->
+ let code dst = mkSeqInstrs [
+ SEGMENT DataSegment,
+ LABEL lbl,
+ DATA TF [ImmLab (prettyToUn (ppRational d))],
+ SEGMENT TextSegment,
+ LDA tmp (AddrImm (ImmCLbl lbl)),
+ LD TF dst (AddrReg tmp)]
+ in
+ returnUs (Any DoubleRep code)
+
+getRegister (StPrim primop [x]) -- unary PrimOps
+ = case primop of
+ IntNegOp -> trivialUCode (NEG Q False) x
+ IntAbsOp -> trivialUCode (ABS Q) x
+
+ NotOp -> trivialUCode NOT x
+
+ FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
+ DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
+
+ OrdOp -> coerceIntCode IntRep x
+ ChrOp -> chrCode x
+
+ Float2IntOp -> coerceFP2Int x
+ Int2FloatOp -> coerceInt2FP pr x
+ Double2IntOp -> coerceFP2Int x
+ Int2DoubleOp -> coerceInt2FP pr x
+
+ Double2FloatOp -> coerceFltCode x
+ Float2DoubleOp -> coerceFltCode x
+
+ other_op -> getRegister (StCall fn DoubleRep [x])
+ where
+ fn = case other_op of
+ FloatExpOp -> SLIT("exp")
+ FloatLogOp -> SLIT("log")
+ FloatSqrtOp -> SLIT("sqrt")
+ FloatSinOp -> SLIT("sin")
+ FloatCosOp -> SLIT("cos")
+ FloatTanOp -> SLIT("tan")
+ FloatAsinOp -> SLIT("asin")
+ FloatAcosOp -> SLIT("acos")
+ FloatAtanOp -> SLIT("atan")
+ FloatSinhOp -> SLIT("sinh")
+ FloatCoshOp -> SLIT("cosh")
+ FloatTanhOp -> SLIT("tanh")
+ DoubleExpOp -> SLIT("exp")
+ DoubleLogOp -> SLIT("log")
+ DoubleSqrtOp -> SLIT("sqrt")
+ DoubleSinOp -> SLIT("sin")
+ DoubleCosOp -> SLIT("cos")
+ DoubleTanOp -> SLIT("tan")
+ DoubleAsinOp -> SLIT("asin")
+ DoubleAcosOp -> SLIT("acos")
+ DoubleAtanOp -> SLIT("atan")
+ DoubleSinhOp -> SLIT("sinh")
+ DoubleCoshOp -> SLIT("cosh")
+ DoubleTanhOp -> SLIT("tanh")
+ where
+ pr = panic "MachCode.getRegister: no primrep needed for Alpha"
+
+getRegister (StPrim primop [x, y]) -- dyadic PrimOps
+ = case primop of
+ CharGtOp -> trivialCode (CMP LT) y x
+ CharGeOp -> trivialCode (CMP LE) y x
+ CharEqOp -> trivialCode (CMP EQ) x y
+ CharNeOp -> int_NE_code x y
+ CharLtOp -> trivialCode (CMP LT) x y
+ CharLeOp -> trivialCode (CMP LE) x y
+
+ IntGtOp -> trivialCode (CMP LT) y x
+ IntGeOp -> trivialCode (CMP LE) y x
+ IntEqOp -> trivialCode (CMP EQ) x y
+ IntNeOp -> int_NE_code x y
+ IntLtOp -> trivialCode (CMP LT) x y
+ IntLeOp -> trivialCode (CMP LE) x y
+
+ WordGtOp -> trivialCode (CMP ULT) y x
+ WordGeOp -> trivialCode (CMP ULE) x y
+ WordEqOp -> trivialCode (CMP EQ) x y
+ WordNeOp -> int_NE_code x y
+ WordLtOp -> trivialCode (CMP ULT) x y
+ WordLeOp -> trivialCode (CMP ULE) x y
+
+ AddrGtOp -> trivialCode (CMP ULT) y x
+ AddrGeOp -> trivialCode (CMP ULE) y x
+ AddrEqOp -> trivialCode (CMP EQ) x y
+ AddrNeOp -> int_NE_code x y
+ AddrLtOp -> trivialCode (CMP ULT) x y
+ AddrLeOp -> trivialCode (CMP ULE) x y
+
+ FloatGtOp -> cmpF_code (FCMP TF LE) EQ x y
+ FloatGeOp -> cmpF_code (FCMP TF LT) EQ x y
+ FloatEqOp -> cmpF_code (FCMP TF EQ) NE x y
+ FloatNeOp -> cmpF_code (FCMP TF EQ) EQ x y
+ FloatLtOp -> cmpF_code (FCMP TF LT) NE x y
+ FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
+
+ DoubleGtOp -> cmpF_code (FCMP TF LE) EQ x y
+ DoubleGeOp -> cmpF_code (FCMP TF LT) EQ x y
+ DoubleEqOp -> cmpF_code (FCMP TF EQ) NE x y
+ DoubleNeOp -> cmpF_code (FCMP TF EQ) EQ x y
+ DoubleLtOp -> cmpF_code (FCMP TF LT) NE x y
+ DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
+
+ IntAddOp -> trivialCode (ADD Q False) x y
+ IntSubOp -> trivialCode (SUB Q False) x y
+ IntMulOp -> trivialCode (MUL Q False) x y
+ IntQuotOp -> trivialCode (DIV Q False) x y
+ IntRemOp -> trivialCode (REM Q False) x y
+
+ FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
+ FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
+ FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
+ FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
+
+ DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
+ DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
+ DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
+ DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
+
+ AndOp -> trivialCode AND x y
+ OrOp -> trivialCode OR x y
+ SllOp -> trivialCode SLL x y
+ SraOp -> trivialCode SRA x y
+ SrlOp -> trivialCode SRL x y
+
+ ISllOp -> panic "AlphaGen:isll"
+ ISraOp -> panic "AlphaGen:isra"
+ ISrlOp -> panic "AlphaGen:isrl"
+
+ FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x,y])
+ DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x,y])
+ where
+ {- ------------------------------------------------------------
+ Some bizarre special code for getting condition codes into
+ registers. Integer non-equality is a test for equality
+ followed by an XOR with 1. (Integer comparisons always set
+ the result register to 0 or 1.) Floating point comparisons of
+ any kind leave the result in a floating point register, so we
+ need to wrangle an integer register out of things.
+ -}
+ int_NE_code :: StixTree -> StixTree -> UniqSM Register
+
+ int_NE_code x y
+ = trivialCode (CMP EQ) x y `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+ code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
+ in
+ returnUs (Any IntRep code__2)
+
+ {- ------------------------------------------------------------
+ Comments for int_NE_code also apply to cmpF_code
+ -}
+ cmpF_code
+ :: (Reg -> Reg -> Reg -> Instr)
+ -> Cond
+ -> StixTree -> StixTree
+ -> UniqSM Register
+
+ cmpF_code instr cond x y
+ = trivialFCode pr instr x y `thenUs` \ register ->
+ getNewRegNCG DoubleRep `thenUs` \ tmp ->
+ getUniqLabelNCG `thenUs` \ lbl ->
+ let
+ code = registerCode register tmp
+ result = registerName register tmp
+
+ code__2 dst = code . mkSeqInstrs [
+ OR zero (RIImm (ImmInt 1)) dst,
+ BF cond result (ImmCLbl lbl),
+ OR zero (RIReg zero) dst,
+ LABEL lbl]
+ in
+ returnUs (Any IntRep code__2)
+ where
+ pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
+ ------------------------------------------------------------
+
+getRegister (StInd pk mem)
+ = getAmode mem `thenUs` \ amode ->
+ let
+ code = amodeCode amode
+ src = amodeAddr amode
+ size = primRepToSize pk
+ code__2 dst = code . mkSeqInstr (LD size dst src)
+ in
+ returnUs (Any pk code__2)
+
+getRegister (StInt i)
+ | fits8Bits i
+ = let
+ code dst = mkSeqInstr (OR zero (RIImm src) dst)
+ in
+ returnUs (Any IntRep code)
+ | otherwise
+ = let
+ code dst = mkSeqInstr (LDI Q dst src)
+ in
+ returnUs (Any IntRep code)
+ where
+ src = ImmInt (fromInteger i)
+
+getRegister leaf
+ | maybeToBool imm
+ = let
+ code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
+ in
+ returnUs (Any PtrRep code)
+ where
+ imm = maybeImm leaf
+ imm__2 = case imm of Just x -> x
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+getRegister (StReg (StixTemp u pk)) = returnUs (Fixed pk (UnmappedReg u pk) id)
+
+getRegister (StDouble 0.0)
+ = let
+ code dst = mkSeqInstrs [FLDZ]
+ in
+ returnUs (Any DoubleRep code)
+
+getRegister (StDouble 1.0)
+ = let
+ code dst = mkSeqInstrs [FLD1]
+ in
+ returnUs (Any DoubleRep code)
+
+getRegister (StDouble d)
+ = getUniqLabelNCG `thenUs` \ lbl ->
+ --getNewRegNCG PtrRep `thenUs` \ tmp ->
+ let code dst = mkSeqInstrs [
+ SEGMENT DataSegment,
+ LABEL lbl,
+ DATA DF [dblImmLit d],
+ SEGMENT TextSegment,
+ FLD DF (OpImm (ImmCLbl lbl))
+ ]
+ in
+ returnUs (Any DoubleRep code)
+
+getRegister (StPrim primop [x]) -- unary PrimOps
+ = case primop of
+ IntNegOp -> trivialUCode (NEGI L) x
+ IntAbsOp -> absIntCode x
+
+ NotOp -> trivialUCode (NOT L) x
+
+ FloatNegOp -> trivialUFCode FloatRep FCHS x
+ FloatSqrtOp -> trivialUFCode FloatRep FSQRT x
+ DoubleNegOp -> trivialUFCode DoubleRep FCHS x
+
+ DoubleSqrtOp -> trivialUFCode DoubleRep FSQRT x
+
+ OrdOp -> coerceIntCode IntRep x
+ ChrOp -> chrCode x
+
+ Float2IntOp -> coerceFP2Int x
+ Int2FloatOp -> coerceInt2FP FloatRep x
+ Double2IntOp -> coerceFP2Int x
+ Int2DoubleOp -> coerceInt2FP DoubleRep x
+
+ Double2FloatOp -> coerceFltCode x
+ Float2DoubleOp -> coerceFltCode x
+
+ other_op ->
+ let
+ fixed_x = if is_float_op -- promote to double
+ then StPrim Float2DoubleOp [x]
+ else x
+ in
+ getRegister (StCall fn DoubleRep [x])
+ where
+ (is_float_op, fn)
+ = case primop of
+ FloatExpOp -> (True, SLIT("exp"))
+ FloatLogOp -> (True, SLIT("log"))
+
+ FloatSinOp -> (True, SLIT("sin"))
+ FloatCosOp -> (True, SLIT("cos"))
+ FloatTanOp -> (True, SLIT("tan"))
+
+ FloatAsinOp -> (True, SLIT("asin"))
+ FloatAcosOp -> (True, SLIT("acos"))
+ FloatAtanOp -> (True, SLIT("atan"))
+
+ FloatSinhOp -> (True, SLIT("sinh"))
+ FloatCoshOp -> (True, SLIT("cosh"))
+ FloatTanhOp -> (True, SLIT("tanh"))
+
+ DoubleExpOp -> (False, SLIT("exp"))
+ DoubleLogOp -> (False, SLIT("log"))
+
+ DoubleSinOp -> (False, SLIT("sin"))
+ DoubleCosOp -> (False, SLIT("cos"))
+ DoubleTanOp -> (False, SLIT("tan"))
+
+ DoubleAsinOp -> (False, SLIT("asin"))
+ DoubleAcosOp -> (False, SLIT("acos"))
+ DoubleAtanOp -> (False, SLIT("atan"))
+
+ DoubleSinhOp -> (False, SLIT("sinh"))
+ DoubleCoshOp -> (False, SLIT("cosh"))
+ DoubleTanhOp -> (False, SLIT("tanh"))
+
+getRegister (StPrim primop [x, y]) -- dyadic PrimOps
+ = case primop of
+ CharGtOp -> condIntReg GT x y
+ CharGeOp -> condIntReg GE x y
+ CharEqOp -> condIntReg EQ x y
+ CharNeOp -> condIntReg NE x y
+ CharLtOp -> condIntReg LT x y
+ CharLeOp -> condIntReg LE x y
+
+ IntGtOp -> condIntReg GT x y
+ IntGeOp -> condIntReg GE x y
+ IntEqOp -> condIntReg EQ x y
+ IntNeOp -> condIntReg NE x y
+ IntLtOp -> condIntReg LT x y
+ IntLeOp -> condIntReg LE x y
+
+ WordGtOp -> condIntReg GU x y
+ WordGeOp -> condIntReg GEU x y
+ WordEqOp -> condIntReg EQ x y
+ WordNeOp -> condIntReg NE x y
+ WordLtOp -> condIntReg LU x y
+ WordLeOp -> condIntReg LEU x y
+
+ AddrGtOp -> condIntReg GU x y
+ AddrGeOp -> condIntReg GEU x y
+ AddrEqOp -> condIntReg EQ x y
+ AddrNeOp -> condIntReg NE x y
+ AddrLtOp -> condIntReg LU x y
+ AddrLeOp -> condIntReg LEU x y
+
+ FloatGtOp -> condFltReg GT x y
+ FloatGeOp -> condFltReg GE x y
+ FloatEqOp -> condFltReg EQ x y
+ FloatNeOp -> condFltReg NE x y
+ FloatLtOp -> condFltReg LT x y
+ FloatLeOp -> condFltReg LE x y
+
+ DoubleGtOp -> condFltReg GT x y
+ DoubleGeOp -> condFltReg GE x y
+ DoubleEqOp -> condFltReg EQ x y
+ DoubleNeOp -> condFltReg NE x y
+ DoubleLtOp -> condFltReg LT x y
+ DoubleLeOp -> condFltReg LE x y
+
+ IntAddOp -> {- ToDo: fix this, whatever it is (WDP 96/04)...
+ -- this should be optimised by the generic Opts,
+ -- I don't know why it is not (sometimes)!
+ case args of
+ [x, StInt 0] -> getRegister x
+ _ -> add_code L x y
+ -}
+ add_code L x y
+
+ IntSubOp -> sub_code L x y
+ IntQuotOp -> quot_code L x y True{-division-}
+ IntRemOp -> quot_code L x y False{-remainder-}
+ IntMulOp -> trivialCode (IMUL L) x y {-True-}
+
+ FloatAddOp -> trivialFCode FloatRep FADD FADD FADDP FADDP x y
+ FloatSubOp -> trivialFCode FloatRep FSUB FSUBR FSUBP FSUBRP x y
+ FloatMulOp -> trivialFCode FloatRep FMUL FMUL FMULP FMULP x y
+ FloatDivOp -> trivialFCode FloatRep FDIV FDIVR FDIVP FDIVRP x y
+
+ DoubleAddOp -> trivialFCode DoubleRep FADD FADD FADDP FADDP x y
+ DoubleSubOp -> trivialFCode DoubleRep FSUB FSUBR FSUBP FSUBRP x y
+ DoubleMulOp -> trivialFCode DoubleRep FMUL FMUL FMULP FMULP x y
+ DoubleDivOp -> trivialFCode DoubleRep FDIV FDIVR FDIVP FDIVRP x y
+
+ AndOp -> trivialCode (AND L) x y {-True-}
+ OrOp -> trivialCode (OR L) x y {-True-}
+ SllOp -> trivialCode (SHL L) x y {-False-}
+ SraOp -> trivialCode (SAR L) x y {-False-}
+ SrlOp -> trivialCode (SHR L) x y {-False-}
+
+ ISllOp -> panic "I386Gen:isll"
+ ISraOp -> panic "I386Gen:isra"
+ ISrlOp -> panic "I386Gen:isrl"
+
+ FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [promote x, promote y])
+ where promote x = StPrim Float2DoubleOp [x]
+ DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x, y])
+ where
+ add_code :: Size -> StixTree -> StixTree -> UniqSM Register
+
+ add_code sz x (StInt y)
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src1 = registerName register tmp
+ src2 = ImmInt (fromInteger y)
+ code__2 dst = code .
+ mkSeqInstr (LEA sz (OpAddr (Addr (Just src1) Nothing src2)) (OpReg dst))
+ in
+ returnUs (Any IntRep code__2)
+
+ add_code sz x (StInd _ mem)
+ = getRegister x `thenUs` \ register1 ->
+ --getNewRegNCG (registerRep register1)
+ -- `thenUs` \ tmp1 ->
+ getAmode mem `thenUs` \ amode ->
+ let
+ code2 = amodeCode amode
+ src2 = amodeAddr amode
+
+ fixedname = registerName register1 eax
+ code__2 dst = let code1 = registerCode register1 dst
+ src1 = registerName register1 dst
+ in asmParThen [code2 asmVoid,code1 asmVoid] .
+ if isFixed register1 && src1 /= dst
+ then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
+ ADD sz (OpAddr src2) (OpReg dst)]
+ else
+ mkSeqInstrs [ADD sz (OpAddr src2) (OpReg src1)]
+ in
+ returnUs (Any IntRep code__2)
+
+ add_code sz (StInd _ mem) y
+ = getRegister y `thenUs` \ register2 ->
+ --getNewRegNCG (registerRep register2)
+ -- `thenUs` \ tmp2 ->
+ getAmode mem `thenUs` \ amode ->
+ let
+ code1 = amodeCode amode
+ src1 = amodeAddr amode
+
+ fixedname = registerName register2 eax
+ code__2 dst = let code2 = registerCode register2 dst
+ src2 = registerName register2 dst
+ in asmParThen [code1 asmVoid,code2 asmVoid] .
+ if isFixed register2 && src2 /= dst
+ then mkSeqInstrs [MOV L (OpReg src2) (OpReg dst),
+ ADD sz (OpAddr src1) (OpReg dst)]
+ else
+ mkSeqInstrs [ADD sz (OpAddr src1) (OpReg src2)]
+ in
+ returnUs (Any IntRep code__2)
+
+ add_code sz x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 dst = asmParThen [code1, code2] .
+ mkSeqInstr (LEA sz (OpAddr (Addr (Just src1) (Just (src2,1)) (ImmInt 0))) (OpReg dst))
+ in
+ returnUs (Any IntRep code__2)
+
+ --------------------
+ sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
+
+ sub_code sz x (StInt y)
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src1 = registerName register tmp
+ src2 = ImmInt (-(fromInteger y))
+ code__2 dst = code .
+ mkSeqInstr (LEA sz (OpAddr (Addr (Just src1) Nothing src2)) (OpReg dst))
+ in
+ returnUs (Any IntRep code__2)
+
+ sub_code sz x y = trivialCode (SUB sz) x y {-False-}
+
+ --------------------
+ quot_code
+ :: Size
+ -> StixTree -> StixTree
+ -> Bool -- True => division, False => remainder operation
+ -> UniqSM Register
+
+ -- x must go into eax, edx must be a sign-extension of eax, and y
+ -- should go in some other register (or memory), so that we get
+ -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
+ -- put y in memory (if it is not there already)
+
+ quot_code sz x (StInd pk mem) is_division
+ = getRegister x `thenUs` \ register1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ getAmode mem `thenUs` \ amode ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code2 = amodeCode amode asmVoid
+ src2 = amodeAddr amode
+ code__2 = asmParThen [code1, code2] .
+ mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
+ CLTD,
+ IDIV sz (OpAddr src2)]
+ in
+ returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
+
+ quot_code sz x (StInt i) is_division
+ = getRegister x `thenUs` \ register1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ src2 = ImmInt (fromInteger i)
+ code__2 = asmParThen [code1] .
+ mkSeqInstrs [-- we put src2 in (ebx)
+ MOV L (OpImm src2) (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1))),
+ MOV L (OpReg src1) (OpReg eax),
+ CLTD,
+ IDIV sz (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1)))]
+ in
+ returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
+
+ quot_code sz x y is_division
+ = getRegister x `thenUs` \ register1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 = asmParThen [code1, code2] .
+ if src2 == ecx || src2 == esi
+ then mkSeqInstrs [ MOV L (OpReg src1) (OpReg eax),
+ CLTD,
+ IDIV sz (OpReg src2)]
+ else mkSeqInstrs [ -- we put src2 in (ebx)
+ MOV L (OpReg src2) (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1))),
+ MOV L (OpReg src1) (OpReg eax),
+ CLTD,
+ IDIV sz (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1)))]
+ in
+ returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
+ -----------------------
+
+getRegister (StInd pk mem)
+ = getAmode mem `thenUs` \ amode ->
+ let
+ code = amodeCode amode
+ src = amodeAddr amode
+ size = primRepToSize pk
+ code__2 dst = code .
+ if pk == DoubleRep || pk == FloatRep
+ then mkSeqInstr (FLD {-DF-} size (OpAddr src))
+ else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
+ in
+ returnUs (Any pk code__2)
+
+
+getRegister (StInt i)
+ = let
+ src = ImmInt (fromInteger i)
+ code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
+ in
+ returnUs (Any IntRep code)
+
+getRegister leaf
+ | maybeToBool imm
+ = let
+ code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
+ in
+ returnUs (Any PtrRep code)
+ where
+ imm = maybeImm leaf
+ imm__2 = case imm of Just x -> x
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+getRegister (StDouble d)
+ = getUniqLabelNCG `thenUs` \ lbl ->
+ getNewRegNCG PtrRep `thenUs` \ tmp ->
+ let code dst = mkSeqInstrs [
+ SEGMENT DataSegment,
+ LABEL lbl,
+ DATA DF [dblImmLit d],
+ SEGMENT TextSegment,
+ SETHI (HI (ImmCLbl lbl)) tmp,
+ LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
+ in
+ returnUs (Any DoubleRep code)
+
+getRegister (StPrim primop [x]) -- unary PrimOps
+ = case primop of
+ IntNegOp -> trivialUCode (SUB False False g0) x
+ IntAbsOp -> absIntCode x
+
+ NotOp -> trivialUCode (XNOR False g0) x
+
+ FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
+ DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
+
+ Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
+ Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
+
+ OrdOp -> coerceIntCode IntRep x
+ ChrOp -> chrCode x
+
+ Float2IntOp -> coerceFP2Int x
+ Int2FloatOp -> coerceInt2FP FloatRep x
+ Double2IntOp -> coerceFP2Int x
+ Int2DoubleOp -> coerceInt2FP DoubleRep x
+
+ other_op ->
+ let
+ fixed_x = if is_float_op -- promote to double
+ then StPrim Float2DoubleOp [x]
+ else x
+ in
+ getRegister (StCall fn DoubleRep [x])
+ where
+ (is_float_op, fn)
+ = case primop of
+ FloatExpOp -> (True, SLIT("exp"))
+ FloatLogOp -> (True, SLIT("log"))
+
+ FloatSinOp -> (True, SLIT("sin"))
+ FloatCosOp -> (True, SLIT("cos"))
+ FloatTanOp -> (True, SLIT("tan"))
+
+ FloatAsinOp -> (True, SLIT("asin"))
+ FloatAcosOp -> (True, SLIT("acos"))
+ FloatAtanOp -> (True, SLIT("atan"))
+
+ FloatSinhOp -> (True, SLIT("sinh"))
+ FloatCoshOp -> (True, SLIT("cosh"))
+ FloatTanhOp -> (True, SLIT("tanh"))
+
+ DoubleExpOp -> (False, SLIT("exp"))
+ DoubleLogOp -> (False, SLIT("log"))
+
+ DoubleSinOp -> (False, SLIT("sin"))
+ DoubleCosOp -> (False, SLIT("cos"))
+ DoubleTanOp -> (False, SLIT("tan"))
+
+ DoubleAsinOp -> (False, SLIT("asin"))
+ DoubleAcosOp -> (False, SLIT("acos"))
+ DoubleAtanOp -> (False, SLIT("atan"))
+
+ DoubleSinhOp -> (False, SLIT("sinh"))
+ DoubleCoshOp -> (False, SLIT("cosh"))
+ DoubleTanhOp -> (False, SLIT("tanh"))
+
+getRegister (StPrim primop [x, y]) -- dyadic PrimOps
+ = case primop of
+ CharGtOp -> condIntReg GT x y
+ CharGeOp -> condIntReg GE x y
+ CharEqOp -> condIntReg EQ x y
+ CharNeOp -> condIntReg NE x y
+ CharLtOp -> condIntReg LT x y
+ CharLeOp -> condIntReg LE x y
+
+ IntGtOp -> condIntReg GT x y
+ IntGeOp -> condIntReg GE x y
+ IntEqOp -> condIntReg EQ x y
+ IntNeOp -> condIntReg NE x y
+ IntLtOp -> condIntReg LT x y
+ IntLeOp -> condIntReg LE x y
+
+ WordGtOp -> condIntReg GU x y
+ WordGeOp -> condIntReg GEU x y
+ WordEqOp -> condIntReg EQ x y
+ WordNeOp -> condIntReg NE x y
+ WordLtOp -> condIntReg LU x y
+ WordLeOp -> condIntReg LEU x y
+
+ AddrGtOp -> condIntReg GU x y
+ AddrGeOp -> condIntReg GEU x y
+ AddrEqOp -> condIntReg EQ x y
+ AddrNeOp -> condIntReg NE x y
+ AddrLtOp -> condIntReg LU x y
+ AddrLeOp -> condIntReg LEU x y
+
+ FloatGtOp -> condFltReg GT x y
+ FloatGeOp -> condFltReg GE x y
+ FloatEqOp -> condFltReg EQ x y
+ FloatNeOp -> condFltReg NE x y
+ FloatLtOp -> condFltReg LT x y
+ FloatLeOp -> condFltReg LE x y
+
+ DoubleGtOp -> condFltReg GT x y
+ DoubleGeOp -> condFltReg GE x y
+ DoubleEqOp -> condFltReg EQ x y
+ DoubleNeOp -> condFltReg NE x y
+ DoubleLtOp -> condFltReg LT x y
+ DoubleLeOp -> condFltReg LE x y
+
+ IntAddOp -> trivialCode (ADD False False) x y
+ IntSubOp -> trivialCode (SUB False False) x y
+
+ -- ToDo: teach about V8+ SPARC mul/div instructions
+ IntMulOp -> imul_div SLIT(".umul") x y
+ IntQuotOp -> imul_div SLIT(".div") x y
+ IntRemOp -> imul_div SLIT(".rem") x y
+
+ FloatAddOp -> trivialFCode FloatRep FADD x y
+ FloatSubOp -> trivialFCode FloatRep FSUB x y
+ FloatMulOp -> trivialFCode FloatRep FMUL x y
+ FloatDivOp -> trivialFCode FloatRep FDIV x y
+
+ DoubleAddOp -> trivialFCode DoubleRep FADD x y
+ DoubleSubOp -> trivialFCode DoubleRep FSUB x y
+ DoubleMulOp -> trivialFCode DoubleRep FMUL x y
+ DoubleDivOp -> trivialFCode DoubleRep FDIV x y
+
+ AndOp -> trivialCode (AND False) x y
+ OrOp -> trivialCode (OR False) x y
+ SllOp -> trivialCode SLL x y
+ SraOp -> trivialCode SRA x y
+ SrlOp -> trivialCode SRL x y
+
+ ISllOp -> panic "SparcGen:isll"
+ ISraOp -> panic "SparcGen:isra"
+ ISrlOp -> panic "SparcGen:isrl"
+
+ FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [promote x, promote y])
+ where promote x = StPrim Float2DoubleOp [x]
+ DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x, y])
+ where
+ imul_div fn x y = getRegister (StCall fn IntRep [x, y])
+
+getRegister (StInd pk mem)
+ = getAmode mem `thenUs` \ amode ->
+ let
+ code = amodeCode amode
+ src = amodeAddr amode
+ size = primRepToSize pk
+ code__2 dst = code . mkSeqInstr (LD size src dst)
+ in
+ returnUs (Any pk code__2)
+
+getRegister (StInt i)
+ | fits13Bits i
+ = let
+ src = ImmInt (fromInteger i)
+ code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
+ in
+ returnUs (Any IntRep code)
+
+getRegister leaf
+ | maybeToBool imm
+ = let
+ code dst = mkSeqInstrs [
+ SETHI (HI imm__2) dst,
+ OR False dst (RIImm (LO imm__2)) dst]
+ in
+ returnUs (Any PtrRep code)
+ where
+ imm = maybeImm leaf
+ imm__2 = case imm of Just x -> x
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{The @Amode@ type}
+%* *
+%************************************************************************
+
+@Amode@s: Memory addressing modes passed up the tree.
+\begin{code}
+data Amode = Amode Addr InstrBlock
+
+amodeAddr (Amode addr _) = addr
+amodeCode (Amode _ code) = code
+\end{code}
+
+Now, given a tree (the argument to an StInd) that references memory,
+produce a suitable addressing mode.
+
+\begin{code}
+getAmode :: StixTree -> UniqSM Amode
+
+getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
+
+#if alpha_TARGET_ARCH
+
+getAmode (StPrim IntSubOp [x, StInt i])
+ = getNewRegNCG PtrRep `thenUs` \ tmp ->
+ getRegister x `thenUs` \ register ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ off = ImmInt (-(fromInteger i))
+ in
+ returnUs (Amode (AddrRegImm reg off) code)
+
+getAmode (StPrim IntAddOp [x, StInt i])
+ = getNewRegNCG PtrRep `thenUs` \ tmp ->
+ getRegister x `thenUs` \ register ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ off = ImmInt (fromInteger i)
+ in
+ returnUs (Amode (AddrRegImm reg off) code)
+
+getAmode leaf
+ | maybeToBool imm
+ = returnUs (Amode (AddrImm imm__2) id)
+ where
+ imm = maybeImm leaf
+ imm__2 = case imm of Just x -> x
+
+getAmode other
+ = getNewRegNCG PtrRep `thenUs` \ tmp ->
+ getRegister other `thenUs` \ register ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ in
+ returnUs (Amode (AddrReg reg) code)
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+getAmode (StPrim IntSubOp [x, StInt i])
+ = getNewRegNCG PtrRep `thenUs` \ tmp ->
+ getRegister x `thenUs` \ register ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ off = ImmInt (-(fromInteger i))
+ in
+ returnUs (Amode (Addr (Just reg) Nothing off) code)
+
+getAmode (StPrim IntAddOp [x, StInt i])
+ | maybeToBool imm
+ = let
+ code = mkSeqInstrs []
+ in
+ returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
+ where
+ imm = maybeImm x
+ imm__2 = case imm of Just x -> x
+
+getAmode (StPrim IntAddOp [x, StInt i])
+ = getNewRegNCG PtrRep `thenUs` \ tmp ->
+ getRegister x `thenUs` \ register ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ off = ImmInt (fromInteger i)
+ in
+ returnUs (Amode (Addr (Just reg) Nothing off) code)
+
+getAmode (StPrim IntAddOp [x, y])
+ = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ reg1 = registerName register1 tmp1
+ code2 = registerCode register2 tmp2 asmVoid
+ reg2 = registerName register2 tmp2
+ code__2 = asmParThen [code1, code2]
+ in
+ returnUs (Amode (Addr (Just reg1) (Just (reg2,4)) (ImmInt 0)) code__2)
+
+getAmode leaf
+ | maybeToBool imm
+ = let
+ code = mkSeqInstrs []
+ in
+ returnUs (Amode (ImmAddr imm__2 0) code)
+ where
+ imm = maybeImm leaf
+ imm__2 = case imm of Just x -> x
+
+getAmode other
+ = getNewRegNCG PtrRep `thenUs` \ tmp ->
+ getRegister other `thenUs` \ register ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ off = Nothing
+ in
+ returnUs (Amode (Addr (Just reg) Nothing (ImmInt 0)) code)
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+getAmode (StPrim IntSubOp [x, StInt i])
+ | fits13Bits (-i)
+ = getNewRegNCG PtrRep `thenUs` \ tmp ->
+ getRegister x `thenUs` \ register ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ off = ImmInt (-(fromInteger i))
+ in
+ returnUs (Amode (AddrRegImm reg off) code)
+
+
+getAmode (StPrim IntAddOp [x, StInt i])
+ | fits13Bits i
+ = getNewRegNCG PtrRep `thenUs` \ tmp ->
+ getRegister x `thenUs` \ register ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ off = ImmInt (fromInteger i)
+ in
+ returnUs (Amode (AddrRegImm reg off) code)
+
+getAmode (StPrim IntAddOp [x, y])
+ = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ reg1 = registerName register1 tmp1
+ code2 = registerCode register2 tmp2 asmVoid
+ reg2 = registerName register2 tmp2
+ code__2 = asmParThen [code1, code2]
+ in
+ returnUs (Amode (AddrRegReg reg1 reg2) code__2)
+
+getAmode leaf
+ | maybeToBool imm
+ = getNewRegNCG PtrRep `thenUs` \ tmp ->
+ let
+ code = mkSeqInstr (SETHI (HI imm__2) tmp)
+ in
+ returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
+ where
+ imm = maybeImm leaf
+ imm__2 = case imm of Just x -> x
+
+getAmode other
+ = getNewRegNCG PtrRep `thenUs` \ tmp ->
+ getRegister other `thenUs` \ register ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ off = ImmInt 0
+ in
+ returnUs (Amode (AddrRegImm reg off) code)
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{The @CondCode@ type}
+%* *
+%************************************************************************
+
+Condition codes passed up the tree.
+\begin{code}
+data CondCode = CondCode Bool Cond InstrBlock
+
+condName (CondCode _ cond _) = cond
+condFloat (CondCode is_float _ _) = is_float
+condCode (CondCode _ _ code) = code
+\end{code}
+
+Set up a condition code for a conditional branch.
+
+\begin{code}
+getCondCode :: StixTree -> UniqSM CondCode
+
+#if alpha_TARGET_ARCH
+getCondCode = panic "MachCode.getCondCode: not on Alphas"
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#if i386_TARGET_ARCH || sparc_TARGET_ARCH
+-- yes, they really do seem to want exactly the same!
+
+getCondCode (StPrim primop [x, y])
+ = case primop of
+ CharGtOp -> condIntCode GT x y
+ CharGeOp -> condIntCode GE x y
+ CharEqOp -> condIntCode EQ x y
+ CharNeOp -> condIntCode NE x y
+ CharLtOp -> condIntCode LT x y
+ CharLeOp -> condIntCode LE x y
+
+ IntGtOp -> condIntCode GT x y
+ IntGeOp -> condIntCode GE x y
+ IntEqOp -> condIntCode EQ x y
+ IntNeOp -> condIntCode NE x y
+ IntLtOp -> condIntCode LT x y
+ IntLeOp -> condIntCode LE x y
+
+ WordGtOp -> condIntCode GU x y
+ WordGeOp -> condIntCode GEU x y
+ WordEqOp -> condIntCode EQ x y
+ WordNeOp -> condIntCode NE x y
+ WordLtOp -> condIntCode LU x y
+ WordLeOp -> condIntCode LEU x y
+
+ AddrGtOp -> condIntCode GU x y
+ AddrGeOp -> condIntCode GEU x y
+ AddrEqOp -> condIntCode EQ x y
+ AddrNeOp -> condIntCode NE x y
+ AddrLtOp -> condIntCode LU x y
+ AddrLeOp -> condIntCode LEU x y
+
+ FloatGtOp -> condFltCode GT x y
+ FloatGeOp -> condFltCode GE x y
+ FloatEqOp -> condFltCode EQ x y
+ FloatNeOp -> condFltCode NE x y
+ FloatLtOp -> condFltCode LT x y
+ FloatLeOp -> condFltCode LE x y
+
+ DoubleGtOp -> condFltCode GT x y
+ DoubleGeOp -> condFltCode GE x y
+ DoubleEqOp -> condFltCode EQ x y
+ DoubleNeOp -> condFltCode NE x y
+ DoubleLtOp -> condFltCode LT x y
+ DoubleLeOp -> condFltCode LE x y
+
+#endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
+\end{code}
+
+% -----------------
+
+@cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
+passed back up the tree.
+
+\begin{code}
+condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
+
+#if alpha_TARGET_ARCH
+condIntCode = panic "MachCode.condIntCode: not on Alphas"
+condFltCode = panic "MachCode.condFltCode: not on Alphas"
+#endif {- alpha_TARGET_ARCH -}
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+condIntCode cond (StInd _ x) y
+ | maybeToBool imm
+ = getAmode x `thenUs` \ amode ->
+ let
+ code1 = amodeCode amode asmVoid
+ y__2 = amodeAddr amode
+ code__2 = asmParThen [code1] .
+ mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
+ in
+ returnUs (CondCode False cond code__2)
+ where
+ imm = maybeImm y
+ imm__2 = case imm of Just x -> x
+
+condIntCode cond x (StInt 0)
+ = getRegister x `thenUs` \ register1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code__2 = asmParThen [code1] .
+ mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
+ in
+ returnUs (CondCode False cond code__2)
+
+condIntCode cond x y
+ | maybeToBool imm
+ = getRegister x `thenUs` \ register1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code__2 = asmParThen [code1] .
+ mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
+ in
+ returnUs (CondCode False cond code__2)
+ where
+ imm = maybeImm y
+ imm__2 = case imm of Just x -> x
+
+condIntCode cond (StInd _ x) y
+ = getAmode x `thenUs` \ amode ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ code1 = amodeCode amode asmVoid
+ src1 = amodeAddr amode
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 = asmParThen [code1, code2] .
+ mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
+ in
+ returnUs (CondCode False cond code__2)
+
+condIntCode cond y (StInd _ x)
+ = getAmode x `thenUs` \ amode ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ code1 = amodeCode amode asmVoid
+ src1 = amodeAddr amode
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 = asmParThen [code1, code2] .
+ mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
+ in
+ returnUs (CondCode False cond code__2)
+
+condIntCode cond x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 = asmParThen [code1, code2] .
+ mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
+ in
+ returnUs (CondCode False cond code__2)
+
+-----------
+
+condFltCode cond x (StDouble 0.0)
+ = getRegister x `thenUs` \ register1 ->
+ getNewRegNCG (registerRep register1)
+ `thenUs` \ tmp1 ->
+ let
+ pk1 = registerRep register1
+ code1 = registerCode register1 tmp1
+ src1 = registerName register1 tmp1
+
+ code__2 = asmParThen [code1 asmVoid] .
+ mkSeqInstrs [FTST, FSTP DF (OpReg st0), -- or FLDZ, FUCOMPP ?
+ FNSTSW,
+ --AND HB (OpImm (ImmInt 68)) (OpReg eax),
+ --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
+ SAHF
+ ]
+ in
+ returnUs (CondCode True (fix_FP_cond cond) code__2)
+
+condFltCode cond x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG (registerRep register1)
+ `thenUs` \ tmp1 ->
+ getNewRegNCG (registerRep register2)
+ `thenUs` \ tmp2 ->
+ let
+ pk1 = registerRep register1
+ code1 = registerCode register1 tmp1
+ src1 = registerName register1 tmp1
+
+ code2 = registerCode register2 tmp2
+ src2 = registerName register2 tmp2
+
+ code__2 = asmParThen [code2 asmVoid, code1 asmVoid] .
+ mkSeqInstrs [FUCOMPP,
+ FNSTSW,
+ --AND HB (OpImm (ImmInt 68)) (OpReg eax),
+ --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
+ SAHF
+ ]
+ in
+ returnUs (CondCode True (fix_FP_cond cond) code__2)
+
+{- On the 486, the flags set by FP compare are the unsigned ones!
+ (This looks like a HACK to me. WDP 96/03)
+-}
+
+fix_FP_cond :: Cond -> Cond
+
+fix_FP_cond GE = GEU
+fix_FP_cond GT = GU
+fix_FP_cond LT = LU
+fix_FP_cond LE = LEU
+fix_FP_cond any = any
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+condIntCode cond x (StInt y)
+ | fits13Bits y
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src1 = registerName register tmp
+ src2 = ImmInt (fromInteger y)
+ code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
+ in
+ returnUs (CondCode False cond code__2)
+
+condIntCode cond x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 = asmParThen [code1, code2] .
+ mkSeqInstr (SUB False True src1 (RIReg src2) g0)
+ in
+ returnUs (CondCode False cond code__2)
+
+-----------
+condFltCode cond x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG (registerRep register1)
+ `thenUs` \ tmp1 ->
+ getNewRegNCG (registerRep register2)
+ `thenUs` \ tmp2 ->
+ getNewRegNCG DoubleRep `thenUs` \ tmp ->
+ let
+ promote x = asmInstr (FxTOy F DF x tmp)
+
+ pk1 = registerRep register1
+ code1 = registerCode register1 tmp1
+ src1 = registerName register1 tmp1
+
+ pk2 = registerRep register2
+ code2 = registerCode register2 tmp2
+ src2 = registerName register2 tmp2
+
+ code__2 =
+ if pk1 == pk2 then
+ asmParThen [code1 asmVoid, code2 asmVoid] .
+ mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
+ else if pk1 == FloatRep then
+ asmParThen [code1 (promote src1), code2 asmVoid] .
+ mkSeqInstr (FCMP True DF tmp src2)
+ else
+ asmParThen [code1 asmVoid, code2 (promote src2)] .
+ mkSeqInstr (FCMP True DF src1 tmp)
+ in
+ returnUs (CondCode True cond code__2)
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Generating assignments}
+%* *
+%************************************************************************
+
+Assignments are really at the heart of the whole code generation
+business. Almost all top-level nodes of any real importance are
+assignments, which correspond to loads, stores, or register transfers.
+If we're really lucky, some of the register transfers will go away,
+because we can use the destination register to complete the code
+generation for the right hand side. This only fails when the right
+hand side is forced into a fixed register (e.g. the result of a call).
+
+\begin{code}
+assignIntCode, assignFltCode
+ :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
+
+#if alpha_TARGET_ARCH
+
+assignIntCode pk (StInd _ dst) src
+ = getNewRegNCG IntRep `thenUs` \ tmp ->
+ getAmode dst `thenUs` \ amode ->
+ getRegister src `thenUs` \ register ->
+ let
+ code1 = amodeCode amode asmVoid
+ dst__2 = amodeAddr amode
+ code2 = registerCode register tmp asmVoid
+ src__2 = registerName register tmp
+ sz = primRepToSize pk
+ code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
+ in
+ returnUs code__2
+
+assignIntCode pk dst src
+ = getRegister dst `thenUs` \ register1 ->
+ getRegister src `thenUs` \ register2 ->
+ let
+ dst__2 = registerName register1 zero
+ code = registerCode register2 dst__2
+ src__2 = registerName register2 dst__2
+ code__2 = if isFixed register2
+ then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
+ else code
+ in
+ returnUs code__2
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+assignIntCode pk (StInd _ dst) src
+ = getAmode dst `thenUs` \ amode ->
+ get_op_RI src `thenUs` \ (codesrc, opsrc, sz) ->
+ let
+ code1 = amodeCode amode asmVoid
+ dst__2 = amodeAddr amode
+ code__2 = asmParThen [code1, codesrc asmVoid] .
+ mkSeqInstr (MOV sz opsrc (OpAddr dst__2))
+ in
+ returnUs code__2
+ where
+ get_op_RI
+ :: StixTree
+ -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
+
+ get_op_RI op
+ | maybeToBool imm
+ = returnUs (asmParThen [], OpImm imm_op, L)
+ where
+ imm = maybeImm op
+ imm_op = case imm of Just x -> x
+
+ get_op_RI op
+ = getRegister op `thenUs` \ register ->
+ getNewRegNCG (registerRep register)
+ `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ pk = registerRep register
+ sz = primRepToSize pk
+ in
+ returnUs (code, OpReg reg, sz)
+
+assignIntCode pk dst (StInd _ src)
+ = getNewRegNCG IntRep `thenUs` \ tmp ->
+ getAmode src `thenUs` \ amode ->
+ getRegister dst `thenUs` \ register ->
+ let
+ code1 = amodeCode amode asmVoid
+ src__2 = amodeAddr amode
+ code2 = registerCode register tmp asmVoid
+ dst__2 = registerName register tmp
+ sz = primRepToSize pk
+ code__2 = asmParThen [code1, code2] .
+ mkSeqInstr (MOV sz (OpAddr src__2) (OpReg dst__2))
+ in
+ returnUs code__2
+
+assignIntCode pk dst src
+ = getRegister dst `thenUs` \ register1 ->
+ getRegister src `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ dst__2 = registerName register1 tmp
+ code = registerCode register2 dst__2
+ src__2 = registerName register2 dst__2
+ code__2 = if isFixed register2 && dst__2 /= src__2
+ then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
+ else code
+ in
+ returnUs code__2
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+assignIntCode pk (StInd _ dst) src
+ = getNewRegNCG IntRep `thenUs` \ tmp ->
+ getAmode dst `thenUs` \ amode ->
+ getRegister src `thenUs` \ register ->
+ let
+ code1 = amodeCode amode asmVoid
+ dst__2 = amodeAddr amode
+ code2 = registerCode register tmp asmVoid
+ src__2 = registerName register tmp
+ sz = primRepToSize pk
+ code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
+ in
+ returnUs code__2
+
+assignIntCode pk dst src
+ = getRegister dst `thenUs` \ register1 ->
+ getRegister src `thenUs` \ register2 ->
+ let
+ dst__2 = registerName register1 g0
+ code = registerCode register2 dst__2
+ src__2 = registerName register2 dst__2
+ code__2 = if isFixed register2
+ then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
+ else code
+ in
+ returnUs code__2
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+% --------------------------------
+Floating-point assignments:
+% --------------------------------
+\begin{code}
+#if alpha_TARGET_ARCH
+
+assignFltCode pk (StInd _ dst) src
+ = getNewRegNCG pk `thenUs` \ tmp ->
+ getAmode dst `thenUs` \ amode ->
+ getRegister src `thenUs` \ register ->
+ let
+ code1 = amodeCode amode asmVoid
+ dst__2 = amodeAddr amode
+ code2 = registerCode register tmp asmVoid
+ src__2 = registerName register tmp
+ sz = primRepToSize pk
+ code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
+ in
+ returnUs code__2
+
+assignFltCode pk dst src
+ = getRegister dst `thenUs` \ register1 ->
+ getRegister src `thenUs` \ register2 ->
+ let
+ dst__2 = registerName register1 zero
+ code = registerCode register2 dst__2
+ src__2 = registerName register2 dst__2
+ code__2 = if isFixed register2
+ then code . mkSeqInstr (FMOV src__2 dst__2)
+ else code
+ in
+ returnUs code__2
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
+ = getNewRegNCG IntRep `thenUs` \ tmp ->
+ getAmode src `thenUs` \ amodesrc ->
+ getAmode dst `thenUs` \ amodedst ->
+ --getRegister src `thenUs` \ register ->
+ let
+ codesrc1 = amodeCode amodesrc asmVoid
+ addrsrc1 = amodeAddr amodesrc
+ codedst1 = amodeCode amodedst asmVoid
+ addrdst1 = amodeAddr amodedst
+ addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
+ addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
+
+ code__2 = asmParThen [codesrc1, codedst1] .
+ mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
+ MOV L (OpReg tmp) (OpAddr addrdst1)]
+ ++
+ if pk == DoubleRep
+ then [MOV L (OpAddr addrsrc2) (OpReg tmp),
+ MOV L (OpReg tmp) (OpAddr addrdst2)]
+ else [])
+ in
+ returnUs code__2
+
+assignFltCode pk (StInd _ dst) src
+ = --getNewRegNCG pk `thenUs` \ tmp ->
+ getAmode dst `thenUs` \ amode ->
+ getRegister src `thenUs` \ register ->
+ let
+ sz = primRepToSize pk
+ dst__2 = amodeAddr amode
+
+ code1 = amodeCode amode asmVoid
+ code2 = registerCode register {-tmp-}st0 asmVoid
+
+ --src__2= registerName register tmp
+ pk__2 = registerRep register
+ sz__2 = primRepToSize pk__2
+
+ code__2 = asmParThen [code1, code2] .
+ mkSeqInstr (FSTP sz (OpAddr dst__2))
+ in
+ returnUs code__2
+
+assignFltCode pk dst src
+ = getRegister dst `thenUs` \ register1 ->
+ getRegister src `thenUs` \ register2 ->
+ --getNewRegNCG (registerRep register2)
+ -- `thenUs` \ tmp ->
+ let
+ sz = primRepToSize pk
+ dst__2 = registerName register1 st0 --tmp
+
+ code = registerCode register2 dst__2
+ src__2 = registerName register2 dst__2
+
+ code__2 = code
+ in
+ returnUs code__2
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+assignFltCode pk (StInd _ dst) src
+ = getNewRegNCG pk `thenUs` \ tmp ->
+ getAmode dst `thenUs` \ amode ->
+ getRegister src `thenUs` \ register ->
+ let
+ sz = primRepToSize pk
+ dst__2 = amodeAddr amode
+
+ code1 = amodeCode amode asmVoid
+ code2 = registerCode register tmp asmVoid
+
+ src__2 = registerName register tmp
+ pk__2 = registerRep register
+ sz__2 = primRepToSize pk__2
+
+ code__2 = asmParThen [code1, code2] .
+ if pk == pk__2 then
+ mkSeqInstr (ST sz src__2 dst__2)
+ else
+ mkSeqInstrs [FxTOy sz__2 sz src__2 tmp, ST sz tmp dst__2]
+ in
+ returnUs code__2
+
+assignFltCode pk dst src
+ = getRegister dst `thenUs` \ register1 ->
+ getRegister src `thenUs` \ register2 ->
+ getNewRegNCG (registerRep register2)
+ `thenUs` \ tmp ->
+ let
+ sz = primRepToSize pk
+ dst__2 = registerName register1 g0 -- must be Fixed
+
+ reg__2 = if pk /= pk__2 then tmp else dst__2
+
+ code = registerCode register2 reg__2
+ src__2 = registerName register2 reg__2
+ pk__2 = registerRep register2
+ sz__2 = primRepToSize pk__2
+
+ code__2 = if pk /= pk__2 then
+ code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
+ else if isFixed register2 then
+ code . mkSeqInstr (FMOV sz src__2 dst__2)
+ else
+ code
+ in
+ returnUs code__2
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Generating an unconditional branch}
+%* *
+%************************************************************************
+
+We accept two types of targets: an immediate CLabel or a tree that
+gets evaluated into a register. Any CLabels which are AsmTemporaries
+are assumed to be in the local block of code, close enough for a
+branch instruction. Other CLabels are assumed to be far away.
+
+(If applicable) Do not fill the delay slots here; you will confuse the
+register allocator.
+
+\begin{code}
+genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
+
+#if alpha_TARGET_ARCH
+
+genJump (StCLbl lbl)
+ | isAsmTemp lbl = returnInstr (BR target)
+ | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zero (AddrReg pv) 0]
+ where
+ target = ImmCLbl lbl
+
+genJump tree
+ = getRegister tree `thenUs` \ register ->
+ getNewRegNCG PtrRep `thenUs` \ tmp ->
+ let
+ dst = registerName register pv
+ code = registerCode register pv
+ target = registerName register pv
+ in
+ if isFixed register then
+ returnSeq code [OR dst (RIReg dst) pv, JMP zero (AddrReg pv) 0]
+ else
+ returnUs (code . mkSeqInstr (JMP zero (AddrReg pv) 0))
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+{-
+genJump (StCLbl lbl)
+ | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
+ | otherwise = returnInstrs [JMP (OpImm target)]
+ where
+ target = ImmCLbl lbl
+-}
+
+genJump (StInd pk mem)
+ = getAmode mem `thenUs` \ amode ->
+ let
+ code = amodeCode amode
+ target = amodeAddr amode
+ in
+ returnSeq code [JMP (OpAddr target)]
+
+genJump tree
+ | maybeToBool imm
+ = returnInstr (JMP (OpImm target))
+
+ | otherwise
+ = getRegister tree `thenUs` \ register ->
+ getNewRegNCG PtrRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ target = registerName register tmp
+ in
+ returnSeq code [JMP (OpReg target)]
+ where
+ imm = maybeImm tree
+ target = case imm of Just x -> x
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+genJump (StCLbl lbl)
+ | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
+ | otherwise = returnInstrs [CALL target 0 True, NOP]
+ where
+ target = ImmCLbl lbl
+
+genJump tree
+ = getRegister tree `thenUs` \ register ->
+ getNewRegNCG PtrRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ target = registerName register tmp
+ in
+ returnSeq code [JMP (AddrRegReg target g0), NOP]
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Conditional jumps}
+%* *
+%************************************************************************
+
+Conditional jumps are always to local labels, so we can use branch
+instructions. We peek at the arguments to decide what kind of
+comparison to do.
+
+ALPHA: For comparisons with 0, we're laughing, because we can just do
+the desired conditional branch.
+
+I386: First, we have to ensure that the condition
+codes are set according to the supplied comparison operation.
+
+SPARC: First, we have to ensure that the condition codes are set
+according to the supplied comparison operation. We generate slightly
+different code for floating point comparisons, because a floating
+point operation cannot directly precede a @BF@. We assume the worst
+and fill that slot with a @NOP@.
+
+SPARC: Do not fill the delay slots here; you will confuse the register
+allocator.
+
+\begin{code}
+genCondJump
+ :: CLabel -- the branch target
+ -> StixTree -- the condition on which to branch
+ -> UniqSM InstrBlock
+
+#if alpha_TARGET_ARCH
+
+genCondJump lbl (StPrim op [x, StInt 0])
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG (registerRep register)
+ `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ value = registerName register tmp
+ pk = registerRep register
+ target = ImmCLbl lbl
+ in
+ returnSeq code [BI (cmpOp op) value target]
+ where
+ cmpOp CharGtOp = GT
+ cmpOp CharGeOp = GE
+ cmpOp CharEqOp = EQ
+ cmpOp CharNeOp = NE
+ cmpOp CharLtOp = LT
+ cmpOp CharLeOp = LE
+ cmpOp IntGtOp = GT
+ cmpOp IntGeOp = GE
+ cmpOp IntEqOp = EQ
+ cmpOp IntNeOp = NE
+ cmpOp IntLtOp = LT
+ cmpOp IntLeOp = LE
+ cmpOp WordGtOp = NE
+ cmpOp WordGeOp = ALWAYS
+ cmpOp WordEqOp = EQ
+ cmpOp WordNeOp = NE
+ cmpOp WordLtOp = NEVER
+ cmpOp WordLeOp = EQ
+ cmpOp AddrGtOp = NE
+ cmpOp AddrGeOp = ALWAYS
+ cmpOp AddrEqOp = EQ
+ cmpOp AddrNeOp = NE
+ cmpOp AddrLtOp = NEVER
+ cmpOp AddrLeOp = EQ
+
+genCondJump lbl (StPrim op [x, StDouble 0.0])
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG (registerRep register)
+ `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ value = registerName register tmp
+ pk = registerRep register
+ target = ImmCLbl lbl
+ in
+ returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
+ where
+ cmpOp FloatGtOp = GT
+ cmpOp FloatGeOp = GE
+ cmpOp FloatEqOp = EQ
+ cmpOp FloatNeOp = NE
+ cmpOp FloatLtOp = LT
+ cmpOp FloatLeOp = LE
+ cmpOp DoubleGtOp = GT
+ cmpOp DoubleGeOp = GE
+ cmpOp DoubleEqOp = EQ
+ cmpOp DoubleNeOp = NE
+ cmpOp DoubleLtOp = LT
+ cmpOp DoubleLeOp = LE
+
+genCondJump lbl (StPrim op [x, y])
+ | fltCmpOp op
+ = trivialFCode pr instr x y `thenUs` \ register ->
+ getNewRegNCG DoubleRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ result = registerName register tmp
+ target = ImmCLbl lbl
+ in
+ returnUs (code . mkSeqInstr (BF cond result target))
+ where
+ pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
+
+ fltCmpOp op = case op of
+ FloatGtOp -> True
+ FloatGeOp -> True
+ FloatEqOp -> True
+ FloatNeOp -> True
+ FloatLtOp -> True
+ FloatLeOp -> True
+ DoubleGtOp -> True
+ DoubleGeOp -> True
+ DoubleEqOp -> True
+ DoubleNeOp -> True
+ DoubleLtOp -> True
+ DoubleLeOp -> True
+ _ -> False
+ (instr, cond) = case op of
+ FloatGtOp -> (FCMP TF LE, EQ)
+ FloatGeOp -> (FCMP TF LT, EQ)
+ FloatEqOp -> (FCMP TF EQ, NE)
+ FloatNeOp -> (FCMP TF EQ, EQ)
+ FloatLtOp -> (FCMP TF LT, NE)
+ FloatLeOp -> (FCMP TF LE, NE)
+ DoubleGtOp -> (FCMP TF LE, EQ)
+ DoubleGeOp -> (FCMP TF LT, EQ)
+ DoubleEqOp -> (FCMP TF EQ, NE)
+ DoubleNeOp -> (FCMP TF EQ, EQ)
+ DoubleLtOp -> (FCMP TF LT, NE)
+ DoubleLeOp -> (FCMP TF LE, NE)
+
+genCondJump lbl (StPrim op [x, y])
+ = trivialCode instr x y `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ result = registerName register tmp
+ target = ImmCLbl lbl
+ in
+ returnUs (code . mkSeqInstr (BI cond result target))
+ where
+ (instr, cond) = case op of
+ CharGtOp -> (CMP LE, EQ)
+ CharGeOp -> (CMP LT, EQ)
+ CharEqOp -> (CMP EQ, NE)
+ CharNeOp -> (CMP EQ, EQ)
+ CharLtOp -> (CMP LT, NE)
+ CharLeOp -> (CMP LE, NE)
+ IntGtOp -> (CMP LE, EQ)
+ IntGeOp -> (CMP LT, EQ)
+ IntEqOp -> (CMP EQ, NE)
+ IntNeOp -> (CMP EQ, EQ)
+ IntLtOp -> (CMP LT, NE)
+ IntLeOp -> (CMP LE, NE)
+ WordGtOp -> (CMP ULE, EQ)
+ WordGeOp -> (CMP ULT, EQ)
+ WordEqOp -> (CMP EQ, NE)
+ WordNeOp -> (CMP EQ, EQ)
+ WordLtOp -> (CMP ULT, NE)
+ WordLeOp -> (CMP ULE, NE)
+ AddrGtOp -> (CMP ULE, EQ)
+ AddrGeOp -> (CMP ULT, EQ)
+ AddrEqOp -> (CMP EQ, NE)
+ AddrNeOp -> (CMP EQ, EQ)
+ AddrLtOp -> (CMP ULT, NE)
+ AddrLeOp -> (CMP ULE, NE)
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+genCondJump lbl bool
+ = getCondCode bool `thenUs` \ condition ->
+ let
+ code = condCode condition
+ cond = condName condition
+ target = ImmCLbl lbl
+ in
+ returnSeq code [JXX cond lbl]
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+genCondJump lbl bool
+ = getCondCode bool `thenUs` \ condition ->
+ let
+ code = condCode condition
+ cond = condName condition
+ target = ImmCLbl lbl
+ in
+ returnSeq code (
+ if condFloat condition then
+ [NOP, BF cond False target, NOP]
+ else
+ [BI cond False target, NOP]
+ )
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Generating C calls}
+%* *
+%************************************************************************
+
+Now the biggest nightmare---calls. Most of the nastiness is buried in
+@get_arg@, which moves the arguments to the correct registers/stack
+locations. Apart from that, the code is easy.
+
+(If applicable) Do not fill the delay slots here; you will confuse the
+register allocator.
+
+\begin{code}
+genCCall
+ :: FAST_STRING -- function to call
+ -> PrimRep -- type of the result
+ -> [StixTree] -- arguments (of mixed type)
+ -> UniqSM InstrBlock
+
+#if alpha_TARGET_ARCH
+
+genCCall fn kind args
+ = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
+ `thenUs` \ ((unused,_), argCode) ->
+ let
+ nRegs = length allArgRegs - length unused
+ code = asmParThen (map ($ asmVoid) argCode)
+ in
+ returnSeq code [
+ LDA pv (AddrImm (ImmLab (uppPStr fn))),
+ JSR ra (AddrReg pv) nRegs,
+ LDGP gp (AddrReg ra)]
+ where
+ ------------------------
+ {- Try to get a value into a specific register (or registers) for
+ a call. The first 6 arguments go into the appropriate
+ argument register (separate registers for integer and floating
+ point arguments, but used in lock-step), and the remaining
+ arguments are dumped to the stack, beginning at 0(sp). Our
+ first argument is a pair of the list of remaining argument
+ registers to be assigned for this call and the next stack
+ offset to use for overflowing arguments. This way,
+ @get_Arg@ can be applied to all of a call's arguments using
+ @mapAccumLUs@.
+ -}
+ get_arg
+ :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
+ -> StixTree -- Current argument
+ -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
+
+ -- We have to use up all of our argument registers first...
+
+ get_arg ((iDst,fDst):dsts, offset) arg
+ = getRegister arg `thenUs` \ register ->
+ let
+ reg = if isFloatingRep pk then fDst else iDst
+ code = registerCode register reg
+ src = registerName register reg
+ pk = registerRep register
+ in
+ returnUs (
+ if isFloatingRep pk then
+ ((dsts, offset), if isFixed register then
+ code . mkSeqInstr (FMOV src fDst)
+ else code)
+ else
+ ((dsts, offset), if isFixed register then
+ code . mkSeqInstr (OR src (RIReg src) iDst)
+ else code))
+
+ -- Once we have run out of argument registers, we move to the
+ -- stack...
+
+ get_arg ([], offset) arg
+ = getRegister arg `thenUs` \ register ->
+ getNewRegNCG (registerRep register)
+ `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+ pk = registerRep register
+ sz = primRepToSize pk
+ in
+ returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+genCCall fn kind [StInt i]
+ | fn == SLIT ("PerformGC_wrapper")
+ = getUniqLabelNCG `thenUs` \ lbl ->
+ let
+ call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
+ MOV L (OpImm (ImmCLbl lbl))
+ -- this is hardwired
+ (OpAddr (Addr (Just ebx) Nothing (ImmInt 104))),
+ JMP (OpImm (ImmLit (uppPStr (SLIT ("_PerformGC_wrapper"))))),
+ LABEL lbl]
+ in
+ returnInstrs call
+
+genCCall fn kind args
+ = mapUs get_call_arg args `thenUs` \ argCode ->
+ let
+ nargs = length args
+ code1 = asmParThen [asmSeq [ -- MOV L (OpReg esp) (OpAddr (Addr (Just ebx) Nothing (ImmInt 80))),
+ MOV L (OpAddr (Addr (Just ebx) Nothing (ImmInt 100))) (OpReg esp)
+ ]
+ ]
+ code2 = asmParThen (map ($ asmVoid) (reverse argCode))
+ call = [CALL fn__2 -- ,
+ -- ADD L (OpImm (ImmInt (nargs * 4))) (OpReg esp),
+ -- MOV L (OpAddr (Addr (Just ebx) Nothing (ImmInt 80))) (OpReg esp)
+ ]
+ in
+ returnSeq (code1 . code2) call
+ where
+ -- function names that begin with '.' are assumed to be special
+ -- internally generated names like '.mul,' which don't get an
+ -- underscore prefix
+ -- ToDo:needed (WDP 96/03) ???
+ fn__2 = case (_HEAD_ fn) of
+ '.' -> ImmLit (uppPStr fn)
+ _ -> ImmLab (uppPStr fn)
+
+ ------------
+ get_call_arg :: StixTree{-current argument-} -> UniqSM InstrBlock -- code
+
+ get_call_arg arg
+ = get_op arg `thenUs` \ (code, op, sz) ->
+ returnUs (code . mkSeqInstr (PUSH sz op))
+
+ ------------
+ get_op
+ :: StixTree
+ -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
+
+ get_op (StInt i)
+ = returnUs (asmParThen [], OpImm (ImmInt (fromInteger i)), L)
+
+ get_op (StInd pk mem)
+ = getAmode mem `thenUs` \ amode ->
+ let
+ code = amodeCode amode --asmVoid
+ addr = amodeAddr amode
+ sz = primRepToSize pk
+ in
+ returnUs (code, OpAddr addr, sz)
+
+ get_op op
+ = getRegister op `thenUs` \ register ->
+ getNewRegNCG (registerRep register)
+ `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ reg = registerName register tmp
+ pk = registerRep register
+ sz = primRepToSize pk
+ in
+ returnUs (code, OpReg reg, sz)
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+genCCall fn kind args
+ = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
+ `thenUs` \ ((unused,_), argCode) ->
+ let
+ nRegs = length allArgRegs - length unused
+ call = CALL fn__2 nRegs False
+ code = asmParThen (map ($ asmVoid) argCode)
+ in
+ returnSeq code [call, NOP]
+ where
+ -- function names that begin with '.' are assumed to be special
+ -- internally generated names like '.mul,' which don't get an
+ -- underscore prefix
+ -- ToDo:needed (WDP 96/03) ???
+ fn__2 = case (_HEAD_ fn) of
+ '.' -> ImmLit (uppPStr fn)
+ _ -> ImmLab (uppPStr fn)
+
+ ------------------------------------
+ {- Try to get a value into a specific register (or registers) for
+ a call. The SPARC calling convention is an absolute
+ nightmare. The first 6x32 bits of arguments are mapped into
+ %o0 through %o5, and the remaining arguments are dumped to the
+ stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
+ first argument is a pair of the list of remaining argument
+ registers to be assigned for this call and the next stack
+ offset to use for overflowing arguments. This way,
+ @get_arg@ can be applied to all of a call's arguments using
+ @mapAccumL@.
+ -}
+ get_arg
+ :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
+ -> StixTree -- Current argument
+ -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
+
+ -- We have to use up all of our argument registers first...
+
+ get_arg (dst:dsts, offset) arg
+ = getRegister arg `thenUs` \ register ->
+ getNewRegNCG (registerRep register)
+ `thenUs` \ tmp ->
+ let
+ reg = if isFloatingRep pk then tmp else dst
+ code = registerCode register reg
+ src = registerName register reg
+ pk = registerRep register
+ in
+ returnUs (case pk of
+ DoubleRep ->
+ case dsts of
+ [] -> (([], offset + 1), code . mkSeqInstrs [
+ -- conveniently put the second part in the right stack
+ -- location, and load the first part into %o5
+ ST DF src (spRel (offset - 1)),
+ LD W (spRel (offset - 1)) dst])
+ (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
+ ST DF src (spRel (-2)),
+ LD W (spRel (-2)) dst,
+ LD W (spRel (-1)) dst__2])
+ FloatRep -> ((dsts, offset), code . mkSeqInstrs [
+ ST F src (spRel (-2)),
+ LD W (spRel (-2)) dst])
+ _ -> ((dsts, offset), if isFixed register then
+ code . mkSeqInstr (OR False g0 (RIReg src) dst)
+ else code))
+
+ -- Once we have run out of argument registers, we move to the
+ -- stack...
+
+ get_arg ([], offset) arg
+ = getRegister arg `thenUs` \ register ->
+ getNewRegNCG (registerRep register)
+ `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+ pk = registerRep register
+ sz = primRepToSize pk
+ words = if pk == DoubleRep then 2 else 1
+ in
+ returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Support bits}
+%* *
+%************************************************************************
+
+%************************************************************************
+%* *
+\subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
+%* *
+%************************************************************************
+
+Turn those condition codes into integers now (when they appear on
+the right hand side of an assignment).
+
+(If applicable) Do not fill the delay slots here; you will confuse the
+register allocator.
+
+\begin{code}
+condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
+
+#if alpha_TARGET_ARCH
+condIntReg = panic "MachCode.condIntReg (not on Alpha)"
+condFltReg = panic "MachCode.condFltReg (not on Alpha)"
+#endif {- alpha_TARGET_ARCH -}
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+condIntReg cond x y
+ = condIntCode cond x y `thenUs` \ condition ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ --getRegister dst `thenUs` \ register ->
+ let
+ --code2 = registerCode register tmp asmVoid
+ --dst__2 = registerName register tmp
+ code = condCode condition
+ cond = condName condition
+ -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
+ code__2 dst = code . mkSeqInstrs [
+ SETCC cond (OpReg tmp),
+ AND L (OpImm (ImmInt 1)) (OpReg tmp),
+ MOV L (OpReg tmp) (OpReg dst)]
+ in
+ returnUs (Any IntRep code__2)
+
+condFltReg cond x y
+ = getUniqLabelNCG `thenUs` \ lbl1 ->
+ getUniqLabelNCG `thenUs` \ lbl2 ->
+ condFltCode cond x y `thenUs` \ condition ->
+ let
+ code = condCode condition
+ cond = condName condition
+ code__2 dst = code . mkSeqInstrs [
+ JXX cond lbl1,
+ MOV L (OpImm (ImmInt 0)) (OpReg dst),
+ JXX ALWAYS lbl2,
+ LABEL lbl1,
+ MOV L (OpImm (ImmInt 1)) (OpReg dst),
+ LABEL lbl2]
+ in
+ returnUs (Any IntRep code__2)
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+condIntReg EQ x (StInt 0)
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+ code__2 dst = code . mkSeqInstrs [
+ SUB False True g0 (RIReg src) g0,
+ SUB True False g0 (RIImm (ImmInt (-1))) dst]
+ in
+ returnUs (Any IntRep code__2)
+
+condIntReg EQ x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
+ XOR False src1 (RIReg src2) dst,
+ SUB False True g0 (RIReg dst) g0,
+ SUB True False g0 (RIImm (ImmInt (-1))) dst]
+ in
+ returnUs (Any IntRep code__2)
+
+condIntReg NE x (StInt 0)
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+ code__2 dst = code . mkSeqInstrs [
+ SUB False True g0 (RIReg src) g0,
+ ADD True False g0 (RIImm (ImmInt 0)) dst]
+ in
+ returnUs (Any IntRep code__2)
+
+condIntReg NE x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
+ XOR False src1 (RIReg src2) dst,
+ SUB False True g0 (RIReg dst) g0,
+ ADD True False g0 (RIImm (ImmInt 0)) dst]
+ in
+ returnUs (Any IntRep code__2)
+
+condIntReg cond x y
+ = getUniqLabelNCG `thenUs` \ lbl1 ->
+ getUniqLabelNCG `thenUs` \ lbl2 ->
+ condIntCode cond x y `thenUs` \ condition ->
+ let
+ code = condCode condition
+ cond = condName condition
+ code__2 dst = code . mkSeqInstrs [
+ BI cond False (ImmCLbl lbl1), NOP,
+ OR False g0 (RIImm (ImmInt 0)) dst,
+ BI ALWAYS False (ImmCLbl lbl2), NOP,
+ LABEL lbl1,
+ OR False g0 (RIImm (ImmInt 1)) dst,
+ LABEL lbl2]
+ in
+ returnUs (Any IntRep code__2)
+
+condFltReg cond x y
+ = getUniqLabelNCG `thenUs` \ lbl1 ->
+ getUniqLabelNCG `thenUs` \ lbl2 ->
+ condFltCode cond x y `thenUs` \ condition ->
+ let
+ code = condCode condition
+ cond = condName condition
+ code__2 dst = code . mkSeqInstrs [
+ NOP,
+ BF cond False (ImmCLbl lbl1), NOP,
+ OR False g0 (RIImm (ImmInt 0)) dst,
+ BI ALWAYS False (ImmCLbl lbl2), NOP,
+ LABEL lbl1,
+ OR False g0 (RIImm (ImmInt 1)) dst,
+ LABEL lbl2]
+ in
+ returnUs (Any IntRep code__2)
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsubsection{@trivial*Code@: deal with trivial instructions}
+%* *
+%************************************************************************
+
+Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
+@trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
+for constants on the right hand side, because that's where the generic
+optimizer will have put them.
+
+Similarly, for unary instructions, we don't have to worry about
+matching an StInt as the argument, because genericOpt will already
+have handled the constant-folding.
+
+\begin{code}
+trivialCode
+ :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
+ ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
+ ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
+ ,)))
+ -> StixTree -> StixTree -- the two arguments
+ -> UniqSM Register
+
+trivialFCode
+ :: PrimRep
+ -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
+ ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
+ ,IF_ARCH_i386 (
+ {-this bizarre type for i386 seems a little too weird (WDP 96/03)-}
+ (Size -> Operand -> Instr)
+ -> (Size -> Operand -> Instr) {-reversed instr-}
+ -> Instr {-pop-}
+ -> Instr {-reversed instr: pop-}
+ ,)))
+ -> StixTree -> StixTree -- the two arguments
+ -> UniqSM Register
+
+trivialUCode
+ :: IF_ARCH_alpha((RI -> Reg -> Instr)
+ ,IF_ARCH_i386 ((Operand -> Instr)
+ ,IF_ARCH_sparc((RI -> Reg -> Instr)
+ ,)))
+ -> StixTree -- the one argument
+ -> UniqSM Register
+
+trivialUFCode
+ :: PrimRep
+ -> IF_ARCH_alpha((Reg -> Reg -> Instr)
+ ,IF_ARCH_i386 (Instr
+ ,IF_ARCH_sparc((Reg -> Reg -> Instr)
+ ,)))
+ -> StixTree -- the one argument
+ -> UniqSM Register
+
+#if alpha_TARGET_ARCH
+
+trivialCode instr x (StInt y)
+ | fits8Bits y
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src1 = registerName register tmp
+ src2 = ImmInt (fromInteger y)
+ code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
+ in
+ returnUs (Any IntRep code__2)
+
+trivialCode instr x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 dst = asmParThen [code1, code2] .
+ mkSeqInstr (instr src1 (RIReg src2) dst)
+ in
+ returnUs (Any IntRep code__2)
+
+------------
+trivialUCode instr x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+ code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
+ in
+ returnUs (Any IntRep code__2)
+
+------------
+trivialFCode _ instr x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
+ getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
+ let
+ code1 = registerCode register1 tmp1
+ src1 = registerName register1 tmp1
+
+ code2 = registerCode register2 tmp2
+ src2 = registerName register2 tmp2
+
+ code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
+ mkSeqInstr (instr src1 src2 dst)
+ in
+ returnUs (Any DoubleRep code__2)
+
+trivialUFCode _ instr x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG DoubleRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+ code__2 dst = code . mkSeqInstr (instr src dst)
+ in
+ returnUs (Any DoubleRep code__2)
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+trivialCode instr x y
+ | maybeToBool imm
+ = getRegister x `thenUs` \ register1 ->
+ --getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ let
+ fixedname = registerName register1 eax
+ code__2 dst = let code1 = registerCode register1 dst
+ src1 = registerName register1 dst
+ in code1 .
+ if isFixed register1 && src1 /= dst
+ then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
+ instr (OpImm imm__2) (OpReg dst)]
+ else
+ mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
+ in
+ returnUs (Any IntRep code__2)
+ where
+ imm = maybeImm y
+ imm__2 = case imm of Just x -> x
+
+trivialCode instr x y
+ | maybeToBool imm
+ = getRegister y `thenUs` \ register1 ->
+ --getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ let
+ fixedname = registerName register1 eax
+ code__2 dst = let code1 = registerCode register1 dst
+ src1 = registerName register1 dst
+ in code1 .
+ if isFixed register1 && src1 /= dst
+ then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
+ instr (OpImm imm__2) (OpReg dst)]
+ else
+ mkSeqInstr (instr (OpImm imm__2) (OpReg src1))
+ in
+ returnUs (Any IntRep code__2)
+ where
+ imm = maybeImm x
+ imm__2 = case imm of Just x -> x
+
+trivialCode instr x (StInd pk mem)
+ = getRegister x `thenUs` \ register ->
+ --getNewRegNCG IntRep `thenUs` \ tmp ->
+ getAmode mem `thenUs` \ amode ->
+ let
+ fixedname = registerName register eax
+ code2 = amodeCode amode asmVoid
+ src2 = amodeAddr amode
+ code__2 dst = let code1 = registerCode register dst asmVoid
+ src1 = registerName register dst
+ in asmParThen [code1, code2] .
+ if isFixed register && src1 /= dst
+ then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
+ instr (OpAddr src2) (OpReg dst)]
+ else
+ mkSeqInstr (instr (OpAddr src2) (OpReg src1))
+ in
+ returnUs (Any pk code__2)
+
+trivialCode instr (StInd pk mem) y
+ = getRegister y `thenUs` \ register ->
+ --getNewRegNCG IntRep `thenUs` \ tmp ->
+ getAmode mem `thenUs` \ amode ->
+ let
+ fixedname = registerName register eax
+ code2 = amodeCode amode asmVoid
+ src2 = amodeAddr amode
+ code__2 dst = let
+ code1 = registerCode register dst asmVoid
+ src1 = registerName register dst
+ in asmParThen [code1, code2] .
+ if isFixed register && src1 /= dst
+ then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
+ instr (OpAddr src2) (OpReg dst)]
+ else
+ mkSeqInstr (instr (OpAddr src2) (OpReg src1))
+ in
+ returnUs (Any pk code__2)
+
+trivialCode instr x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ --getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ fixedname = registerName register1 eax
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 dst = let
+ code1 = registerCode register1 dst asmVoid
+ src1 = registerName register1 dst
+ in asmParThen [code1, code2] .
+ if isFixed register1 && src1 /= dst
+ then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
+ instr (OpReg src2) (OpReg dst)]
+ else
+ mkSeqInstr (instr (OpReg src2) (OpReg src1))
+ in
+ returnUs (Any IntRep code__2)
+
+-----------
+trivialUCode instr x
+ = getRegister x `thenUs` \ register ->
+-- getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+-- fixedname = registerName register eax
+ code__2 dst = let
+ code = registerCode register dst
+ src = registerName register dst
+ in code . if isFixed register && dst /= src
+ then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
+ instr (OpReg dst)]
+ else mkSeqInstr (instr (OpReg src))
+ in
+ returnUs (Any IntRep code__2)
+
+-----------
+trivialFCode pk _ instrr _ _ (StInd pk' mem) y
+ = getRegister y `thenUs` \ register2 ->
+ --getNewRegNCG (registerRep register2)
+ -- `thenUs` \ tmp2 ->
+ getAmode mem `thenUs` \ amode ->
+ let
+ code1 = amodeCode amode
+ src1 = amodeAddr amode
+
+ code__2 dst = let
+ code2 = registerCode register2 dst
+ src2 = registerName register2 dst
+ in asmParThen [code1 asmVoid,code2 asmVoid] .
+ mkSeqInstrs [instrr (primRepToSize pk) (OpAddr src1)]
+ in
+ returnUs (Any pk code__2)
+
+trivialFCode pk instr _ _ _ x (StInd pk' mem)
+ = getRegister x `thenUs` \ register1 ->
+ --getNewRegNCG (registerRep register1)
+ -- `thenUs` \ tmp1 ->
+ getAmode mem `thenUs` \ amode ->
+ let
+ code2 = amodeCode amode
+ src2 = amodeAddr amode
+
+ code__2 dst = let
+ code1 = registerCode register1 dst
+ src1 = registerName register1 dst
+ in asmParThen [code2 asmVoid,code1 asmVoid] .
+ mkSeqInstrs [instr (primRepToSize pk) (OpAddr src2)]
+ in
+ returnUs (Any pk code__2)
+
+trivialFCode pk _ _ _ instrpr x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ --getNewRegNCG (registerRep register1)
+ -- `thenUs` \ tmp1 ->
+ --getNewRegNCG (registerRep register2)
+ -- `thenUs` \ tmp2 ->
+ getNewRegNCG DoubleRep `thenUs` \ tmp ->
+ let
+ pk1 = registerRep register1
+ code1 = registerCode register1 st0 --tmp1
+ src1 = registerName register1 st0 --tmp1
+
+ pk2 = registerRep register2
+
+ code__2 dst = let
+ code2 = registerCode register2 dst
+ src2 = registerName register2 dst
+ in asmParThen [code1 asmVoid, code2 asmVoid] .
+ mkSeqInstr instrpr
+ in
+ returnUs (Any pk1 code__2)
+
+-------------
+trivialUFCode pk instr (StInd pk' mem)
+ = getAmode mem `thenUs` \ amode ->
+ let
+ code = amodeCode amode
+ src = amodeAddr amode
+ code__2 dst = code . mkSeqInstrs [FLD (primRepToSize pk) (OpAddr src),
+ instr]
+ in
+ returnUs (Any pk code__2)
+
+trivialUFCode pk instr x
+ = getRegister x `thenUs` \ register ->
+ --getNewRegNCG pk `thenUs` \ tmp ->
+ let
+ code__2 dst = let
+ code = registerCode register dst
+ src = registerName register dst
+ in code . mkSeqInstrs [instr]
+ in
+ returnUs (Any pk code__2)
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+trivialCode instr x (StInt y)
+ | fits13Bits y
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src1 = registerName register tmp
+ src2 = ImmInt (fromInteger y)
+ code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
+ in
+ returnUs (Any IntRep code__2)
+
+trivialCode instr x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG IntRep `thenUs` \ tmp1 ->
+ getNewRegNCG IntRep `thenUs` \ tmp2 ->
+ let
+ code1 = registerCode register1 tmp1 asmVoid
+ src1 = registerName register1 tmp1
+ code2 = registerCode register2 tmp2 asmVoid
+ src2 = registerName register2 tmp2
+ code__2 dst = asmParThen [code1, code2] .
+ mkSeqInstr (instr src1 (RIReg src2) dst)
+ in
+ returnUs (Any IntRep code__2)
+
+------------
+trivialFCode pk instr x y
+ = getRegister x `thenUs` \ register1 ->
+ getRegister y `thenUs` \ register2 ->
+ getNewRegNCG (registerRep register1)
+ `thenUs` \ tmp1 ->
+ getNewRegNCG (registerRep register2)
+ `thenUs` \ tmp2 ->
+ getNewRegNCG DoubleRep `thenUs` \ tmp ->
+ let
+ promote x = asmInstr (FxTOy F DF x tmp)
+
+ pk1 = registerRep register1
+ code1 = registerCode register1 tmp1
+ src1 = registerName register1 tmp1
+
+ pk2 = registerRep register2
+ code2 = registerCode register2 tmp2
+ src2 = registerName register2 tmp2
+
+ code__2 dst =
+ if pk1 == pk2 then
+ asmParThen [code1 asmVoid, code2 asmVoid] .
+ mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
+ else if pk1 == FloatRep then
+ asmParThen [code1 (promote src1), code2 asmVoid] .
+ mkSeqInstr (instr DF tmp src2 dst)
+ else
+ asmParThen [code1 asmVoid, code2 (promote src2)] .
+ mkSeqInstr (instr DF src1 tmp dst)
+ in
+ returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
+
+------------
+trivialUCode instr x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+ code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
+ in
+ returnUs (Any IntRep code__2)
+
+-------------
+trivialUFCode pk instr x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG pk `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+ code__2 dst = code . mkSeqInstr (instr src dst)
+ in
+ returnUs (Any pk code__2)
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsubsection{Coercing to/from integer/floating-point...}
+%* *
+%************************************************************************
+
+@coerce(Int|Flt)Code@ are simple coercions that don't require any code
+to be generated. Here we just change the type on the Register passed
+on up. The code is machine-independent.
+
+@coerce(Int2FP|FP2Int)@ are more complicated integer/float
+conversions. We have to store temporaries in memory to move
+between the integer and the floating point register sets.
+
+\begin{code}
+coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
+coerceFltCode :: StixTree -> UniqSM Register
+
+coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
+coerceFP2Int :: StixTree -> UniqSM Register
+
+coerceIntCode pk x
+ = getRegister x `thenUs` \ register ->
+ returnUs (
+ case register of
+ Fixed _ reg code -> Fixed pk reg code
+ Any _ code -> Any pk code
+ )
+
+-------------
+coerceFltCode x
+ = getRegister x `thenUs` \ register ->
+ returnUs (
+ case register of
+ Fixed _ reg code -> Fixed DoubleRep reg code
+ Any _ code -> Any DoubleRep code
+ )
+\end{code}
+
+\begin{code}
+#if alpha_TARGET_ARCH
+
+coerceInt2FP _ x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ reg ->
+ let
+ code = registerCode register reg
+ src = registerName register reg
+
+ code__2 dst = code . mkSeqInstrs [
+ ST Q src (spRel 0),
+ LD TF dst (spRel 0),
+ CVTxy Q TF dst dst]
+ in
+ returnUs (Any DoubleRep code__2)
+
+-------------
+coerceFP2Int x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG DoubleRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+
+ code__2 dst = code . mkSeqInstrs [
+ CVTxy TF Q src tmp,
+ ST TF tmp (spRel 0),
+ LD Q dst (spRel 0)]
+ in
+ returnUs (Any IntRep code__2)
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+coerceInt2FP pk x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ reg ->
+ let
+ code = registerCode register reg
+ src = registerName register reg
+
+ code__2 dst = code . mkSeqInstrs [
+ -- to fix: should spill instead of using R1
+ MOV L (OpReg src) (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1))),
+ FILD (primRepToSize pk) (Addr (Just ebx) Nothing (ImmInt OFFSET_R1)) dst]
+ in
+ returnUs (Any pk code__2)
+
+------------
+coerceFP2Int x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG DoubleRep `thenUs` \ tmp ->
+ let
+ code = registerCode register tmp
+ src = registerName register tmp
+ pk = registerRep register
+
+ code__2 dst = let
+ in code . mkSeqInstrs [
+ FRNDINT,
+ FIST L (Addr (Just ebx) Nothing (ImmInt OFFSET_R1)),
+ MOV L (OpAddr (Addr (Just ebx) Nothing (ImmInt OFFSET_R1))) (OpReg dst)]
+ in
+ returnUs (Any IntRep code__2)
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+coerceInt2FP pk x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ reg ->
+ let
+ code = registerCode register reg
+ src = registerName register reg
+
+ code__2 dst = code . mkSeqInstrs [
+ ST W src (spRel (-2)),
+ LD W (spRel (-2)) dst,
+ FxTOy W (primRepToSize pk) dst dst]
+ in
+ returnUs (Any pk code__2)
+
+------------
+coerceFP2Int x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ reg ->
+ getNewRegNCG FloatRep `thenUs` \ tmp ->
+ let
+ code = registerCode register reg
+ src = registerName register reg
+ pk = registerRep register
+
+ code__2 dst = code . mkSeqInstrs [
+ FxTOy (primRepToSize pk) W src tmp,
+ ST W tmp (spRel (-2)),
+ LD W (spRel (-2)) dst]
+ in
+ returnUs (Any IntRep code__2)
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsubsection{Coercing integer to @Char@...}
+%* *
+%************************************************************************
+
+Integer to character conversion. Where applicable, we try to do this
+in one step if the original object is in memory.
+
+\begin{code}
+chrCode :: StixTree -> UniqSM Register
+
+#if alpha_TARGET_ARCH
+
+chrCode x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ reg ->
+ let
+ code = registerCode register reg
+ src = registerName register reg
+ code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
+ in
+ returnUs (Any IntRep code__2)
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+chrCode x
+ = getRegister x `thenUs` \ register ->
+ --getNewRegNCG IntRep `thenUs` \ reg ->
+ let
+ fixedname = registerName register eax
+ code__2 dst = let
+ code = registerCode register dst
+ src = registerName register dst
+ in code .
+ if isFixed register && src /= dst
+ then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
+ AND L (OpImm (ImmInt 255)) (OpReg dst)]
+ else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
+ in
+ returnUs (Any IntRep code__2)
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+chrCode (StInd pk mem)
+ = getAmode mem `thenUs` \ amode ->
+ let
+ code = amodeCode amode
+ src = amodeAddr amode
+ src_off = addrOffset src 3
+ src__2 = case src_off of Just x -> x
+ code__2 dst = if maybeToBool src_off then
+ code . mkSeqInstr (LD BU src__2 dst)
+ else
+ code . mkSeqInstrs [
+ LD (primRepToSize pk) src dst,
+ AND False dst (RIImm (ImmInt 255)) dst]
+ in
+ returnUs (Any pk code__2)
+
+chrCode x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ reg ->
+ let
+ code = registerCode register reg
+ src = registerName register reg
+ code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
+ in
+ returnUs (Any IntRep code__2)
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsubsection{Absolute value on integers}
+%* *
+%************************************************************************
+
+Absolute value on integers, mostly for gmp size check macros. Again,
+the argument cannot be an StInt, because genericOpt already folded
+constants.
+
+If applicable, do not fill the delay slots here; you will confuse the
+register allocator.
+
+\begin{code}
+absIntCode :: StixTree -> UniqSM Register
+
+#if alpha_TARGET_ARCH
+absIntCode = panic "MachCode.absIntCode: not on Alphas"
+#endif {- alpha_TARGET_ARCH -}
+
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+absIntCode x
+ = getRegister x `thenUs` \ register ->
+ --getNewRegNCG IntRep `thenUs` \ reg ->
+ getUniqLabelNCG `thenUs` \ lbl ->
+ let
+ code__2 dst = let code = registerCode register dst
+ src = registerName register dst
+ in code . if isFixed register && dst /= src
+ then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
+ TEST L (OpReg dst) (OpReg dst),
+ JXX GE lbl,
+ NEGI L (OpReg dst),
+ LABEL lbl]
+ else mkSeqInstrs [TEST L (OpReg src) (OpReg src),
+ JXX GE lbl,
+ NEGI L (OpReg src),
+ LABEL lbl]
+ in
+ returnUs (Any IntRep code__2)
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+absIntCode x
+ = getRegister x `thenUs` \ register ->
+ getNewRegNCG IntRep `thenUs` \ reg ->
+ getUniqLabelNCG `thenUs` \ lbl ->
+ let
+ code = registerCode register reg
+ src = registerName register reg
+ code__2 dst = code . mkSeqInstrs [
+ SUB False True g0 (RIReg src) dst,
+ BI GE False (ImmCLbl lbl), NOP,
+ OR False g0 (RIReg src) dst,
+ LABEL lbl]
+ in
+ returnUs (Any IntRep code__2)
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+++ /dev/null
-%
-% (c) The AQUA Project, Glasgow University, 1993-1995
-%
-
-Machine- and flag- specific bits that the abstract code generator has
-to know about.
-
-No doubt there will be more...
-
-\begin{code}
-#include "HsVersions.h"
-
-module MachDesc (
- Target(..){-(..) for target_STRICT only-}, mkTarget, RegLoc(..),
-
- saveLoc,
-
- fixedHeaderSize, varHeaderSize, stgReg,
- sizeof, volatileSaves, volatileRestores, hpRel,
- amodeToStix, amodeToStix', charLikeClosureSize,
- intLikeClosureSize, mutHS, dataHS, primToStix, macroCode,
- heapCheck
-
- -- and, for self-sufficiency...
- ) where
-
-import AbsCSyn
-import CmdLineOpts ( GlobalSwitch(..), stringSwitchSet, switchIsOn, SwitchResult(..) )
-import Outputable
-import OrdList ( OrdList )
-import SMRep ( SMRep )
-import Stix
-import UniqSupply
-import Unique
-import Unpretty ( PprStyle, CSeq )
-import Util
-
-data RegLoc = Save StixTree | Always StixTree
-\end{code}
-
-Think of this as a big runtime class dictionary:
-\begin{code}
-data Target = Target
- Int -- fixedHeaderSize
- (SMRep -> Int) -- varHeaderSize
- (MagicId -> RegLoc) -- stgReg
- (PrimRep -> Int) -- sizeof
- (HeapOffset -> Int) -- hpRel
- (CAddrMode -> StixTree) -- amodeToStix
- (CAddrMode -> StixTree) -- amodeToStix'
- (
- ([MagicId] -> [StixTree]), -- volatileSaves
- ([MagicId] -> [StixTree]), -- volatileRestores
- Int, -- charLikeClosureSize
- Int, -- intLikeClosureSize
- StixTree, -- mutHS
- StixTree, -- dataHS
- ([CAddrMode] -> PrimOp -> [CAddrMode] -> UniqSM StixTreeList),
- -- primToStix
- (CStmtMacro -> [CAddrMode] -> UniqSM StixTreeList),
- -- macroCode
- (StixTree -> StixTree -> StixTree -> UniqSM StixTreeList)
- -- heapCheck
- )
-
-mkTarget = Target
-
-fixedHeaderSize (Target fhs vhs reg size hprel am am' ~(vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) = fhs
-varHeaderSize (Target fhs vhs reg size hprel am am' ~(vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x = vhs x
-stgReg (Target fhs vhs reg size hprel am am' ~(vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x = reg x
-sizeof (Target fhs vhs reg size hprel am am' ~(vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x = size x
--- used only for wrapper-hungry PrimOps:
-hpRel (Target fhs vhs reg size hprel am am' ~(vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x = hprel x
-amodeToStix (Target fhs vhs reg size hprel am am' ~(vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x = am x
-amodeToStix' (Target fhs vhs reg size hprel am am' ~(vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x = am' x
-
-volatileSaves (Target fhs vhs reg size hprel am am' (vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x = vsave x
--- used only for wrapper-hungry PrimOps:
-volatileRestores (Target fhs vhs reg size hprel am am' (vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x = vrest x
-charLikeClosureSize (Target fhs vhs reg size hprel am am' (vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) = csz
-intLikeClosureSize (Target fhs vhs reg size hprel am am' (vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) = isz
-mutHS (Target fhs vhs reg size hprel am am' (vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) = mhs
-dataHS (Target fhs vhs reg size hprel am am' (vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) = dhs
-primToStix (Target fhs vhs reg size hprel am am' (vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x y z = ps x y z
-macroCode (Target fhs vhs reg size hprel am am' (vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x y = mc x y
-heapCheck (Target fhs vhs reg size hprel am am' (vsave, vrest, csz, isz, mhs, dhs, ps, mc, hc) ) x y z = hc x y z
-\end{code}
-
-Trees for register save locations
-\begin{code}
-saveLoc :: Target -> MagicId -> StixTree
-
-saveLoc target reg = case stgReg target reg of {Always loc -> loc; Save loc -> loc}
-\end{code}
-
--- /dev/null
+%
+% (c) The AQUA Project, Glasgow University, 1993-1996
+%
+\section[MachMisc]{Description of various machine-specific things}
+
+\begin{code}
+#include "HsVersions.h"
+#include "nativeGen/NCG.h"
+
+module MachMisc (
+
+ fixedHdrSizeInWords, varHdrSizeInWords,
+ charLikeSize, intLikeSize, mutHS, dataHS,
+ sizeOf, primRepToSize,
+
+ eXTRA_STK_ARGS_HERE,
+
+ volatileSaves, volatileRestores,
+
+ storageMgrInfo, smCAFlist, smOldLim, smOldMutables,
+ smStablePtrTable,
+
+ targetMaxDouble, targetMaxInt, targetMinDouble, targetMinInt,
+
+ underscorePrefix,
+ fmtAsmLbl,
+ cvtLitLit,
+ exactLog2,
+
+ Instr(..), IF_ARCH_i386(Operand(..) COMMA,)
+ Cond(..),
+ Size(..)
+
+#if alpha_TARGET_ARCH
+ , RI(..)
+#endif
+#if i386_TARGET_ARCH
+#endif
+#if sparc_TARGET_ARCH
+ , RI(..), riZero
+#endif
+ ) where
+
+import Ubiq{-uitous-}
+import AbsCLoop ( fixedHdrSizeInWords, varHdrSizeInWords ) -- paranoia
+import NcgLoop ( underscorePrefix, fmtAsmLbl ) -- paranoia
+
+import AbsCSyn ( MagicId(..) )
+import AbsCUtils ( magicIdPrimRep )
+import CmdLineOpts ( opt_SccProfilingOn )
+import Literal ( mkMachInt, Literal(..) )
+import MachRegs ( stgReg, callerSaves, RegLoc(..),
+ Imm(..), Reg(..), Addr
+ )
+import OrdList ( OrdList )
+import PrimRep ( PrimRep(..) )
+import SMRep ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..) )
+import Stix ( StixTree(..), StixReg(..), sStLitLbl,
+ CodeSegment
+ )
+import Util ( panic )
+\end{code}
+
+\begin{code}
+underscorePrefix :: Bool -- leading underscore on labels?
+
+underscorePrefix
+ = IF_ARCH_alpha(False
+ ,{-else-} IF_ARCH_i386(
+ IF_OS_linuxaout(True
+ , IF_OS_freebsd(True
+ , IF_OS_bsdi(True
+ , {-otherwise-} False)))
+ ,{-else-}IF_ARCH_sparc(
+ IF_OS_sunos4(True, {-otherwise-} False)
+ ,)))
+
+---------------------------
+fmtAsmLbl :: String -> String -- for formatting labels
+
+fmtAsmLbl s
+ = IF_ARCH_alpha(
+ {- The alpha assembler likes temporary labels to look like $L123
+ instead of L123. (Don't toss the L, because then Lf28
+ turns into $f28.)
+ -}
+ '$' : s
+ ,{-otherwise-}
+ s
+ )
+
+---------------------------
+cvtLitLit :: String -> String
+
+-- ToDo: some kind of *careful* attention needed...
+
+cvtLitLit "stdin" = IF_ARCH_alpha("_iob+0" {-probably OK...-}
+ ,IF_ARCH_i386("_IO_stdin_"
+ ,IF_ARCH_sparc("__iob+0x0"{-probably OK...-}
+ ,)))
+cvtLitLit "stdout" = IF_ARCH_alpha("_iob+56"{-dodgy *at best*...-}
+ ,IF_ARCH_i386("_IO_stdout_"
+ ,IF_ARCH_sparc("__iob+0x14"{-dodgy *at best*...-}
+ ,)))
+cvtLitLit "stderr" = IF_ARCH_alpha("_iob+112"{-dodgy *at best*...-}
+ ,IF_ARCH_i386("_IO_stderr_"
+ ,IF_ARCH_sparc("__iob+0x28"{-dodgy *at best*...-}
+ ,)))
+cvtLitLit s
+ | isHex s = s
+ | otherwise = error ("Native code generator can't handle ``" ++ s ++ "''")
+ where
+ isHex ('0':'x':xs) = all isHexDigit xs
+ isHex _ = False
+ -- Now, where have I seen this before?
+ isHexDigit c = isDigit c || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'
+\end{code}
+
+% ----------------------------------------------------------------
+
+We (allegedly) put the first six C-call arguments in registers;
+where do we start putting the rest of them?
+\begin{code}
+eXTRA_STK_ARGS_HERE :: Int
+eXTRA_STK_ARGS_HERE
+ = IF_ARCH_alpha(0, IF_ARCH_i386(23{-6x4bytes-}, IF_ARCH_sparc(23,???)))
+\end{code}
+
+% ----------------------------------------------------------------
+
+@fixedHdrSizeInWords@ and @varHdrSizeInWords@: these are not dependent
+on target architecture.
+\begin{code}
+fixedHdrSizeInWords :: Int
+
+fixedHdrSizeInWords
+ = 1{-info ptr-} + profFHS + parFHS + tickyFHS
+ -- obviously, we aren't taking non-sequential too seriously yet
+ where
+ profFHS = if opt_SccProfilingOn then 1 else 0
+ parFHS = {-if PAR or GRAN then 1 else-} 0
+ tickyFHS = {-if ticky ... then 1 else-} 0
+
+varHdrSizeInWords :: SMRep -> Int{-in words-}
+
+varHdrSizeInWords sm
+ = case sm of
+ StaticRep _ _ -> 0
+ SpecialisedRep _ _ _ _ -> 0
+ GenericRep _ _ _ -> 0
+ BigTupleRep _ -> 1
+ MuTupleRep _ -> 2 {- (1 + GC_MUT_RESERVED_WORDS) -}
+ DataRep _ -> 1
+ DynamicRep -> 2
+ BlackHoleRep -> 0
+ PhantomRep -> panic "MachMisc.varHdrSizeInWords:phantom"
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Static closure sizes:
+\begin{code}
+charLikeSize, intLikeSize :: Int
+
+charLikeSize = blahLikeSize CharLikeRep
+intLikeSize = blahLikeSize IntLikeRep
+
+blahLikeSize blah
+ = fromInteger (sizeOf PtrRep)
+ * (fixedHdrSizeInWords + varHdrSizeInWords blahLikeRep + 1)
+ where
+ blahLikeRep = SpecialisedRep blah 0 1 SMNormalForm
+
+--------
+mutHS, dataHS :: StixTree
+
+mutHS = blah_hs (MuTupleRep 0)
+dataHS = blah_hs (DataRep 0)
+
+blah_hs blah
+ = StInt (toInteger words)
+ where
+ words = fixedHdrSizeInWords + varHdrSizeInWords blah
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Size of a @PrimRep@, in bytes.
+
+\begin{code}
+sizeOf :: PrimRep -> Integer{-in bytes-}
+ -- the result is an Integer only because it's more convenient
+
+sizeOf pr = case (primRepToSize pr) of
+ IF_ARCH_alpha({B -> 1; BU -> 1; {-W -> 2; WU -> 2; L -> 4; SF -> 4;-} _ -> 8},)
+ IF_ARCH_sparc({B -> 1; BU -> 1; {-HW -> 2; HWU -> 2;-} W -> 4; {-D -> 8;-} F -> 4; DF -> 8},)
+ IF_ARCH_i386( {B -> 1; {-S -> 2;-} L -> 4; F -> 4; DF -> 8 },)
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Now the volatile saves and restores. We add the basic guys to the
+list of ``user'' registers provided. Note that there are more basic
+registers on the restore list, because some are reloaded from
+constants.
+
+(@volatileRestores@ used only for wrapper-hungry PrimOps.)
+
+\begin{code}
+volatileSaves, volatileRestores :: [MagicId] -> [StixTree]
+
+save_cands = [BaseReg,SpA,SuA,SpB,SuB,Hp,HpLim,RetReg]
+restore_cands = save_cands ++ [StkStubReg,StdUpdRetVecReg]
+
+volatileSaves vols
+ = map save ((filter callerSaves) (save_cands ++ vols))
+ where
+ save x = StAssign (magicIdPrimRep x) loc reg
+ where
+ reg = StReg (StixMagicId x)
+ loc = case stgReg x of
+ Save loc -> loc
+ Always _ -> panic "volatileSaves"
+
+volatileRestores vols
+ = map restore ((filter callerSaves) (restore_cands ++ vols))
+ where
+ restore x = StAssign (magicIdPrimRep x) reg loc
+ where
+ reg = StReg (StixMagicId x)
+ loc = case stgReg x of
+ Save loc -> loc
+ Always _ -> panic "volatileRestores"
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Obviously slightly weedy
+(Note that the floating point values aren't terribly important.)
+ToDo: Fix!(JSM)
+\begin{code}
+targetMinDouble = MachDouble (-1.7976931348623157e+308)
+targetMaxDouble = MachDouble (1.7976931348623157e+308)
+targetMinInt = mkMachInt (-2147483647)
+targetMaxInt = mkMachInt 2147483647
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Storage manager nonsense. Note that the indices are dependent on
+the definition of the smInfo structure in SMinterface.lh
+
+\begin{code}
+storageMgrInfo, smCAFlist, smOldMutables, smOldLim :: StixTree
+
+storageMgrInfo = sStLitLbl SLIT("StorageMgrInfo")
+smCAFlist = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_CAFLIST))
+smOldMutables = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_OLDMUTABLES))
+smOldLim = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_OLDLIM))
+smStablePtrTable = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_STABLEPOINTERTABLE))
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+This algorithm for determining the $\log_2$ of exact powers of 2 comes
+from GCC. It requires bit manipulation primitives, and we use GHC
+extensions. Tough.
+
+\begin{code}
+w2i x = word2Int# x
+i2w x = int2Word# x
+i2w_s x = (x::Int#)
+
+exactLog2 :: Integer -> Maybe Integer
+exactLog2 x
+ = if (x <= 0 || x >= 2147483648) then
+ Nothing
+ else
+ case (fromInteger x) of { I# x# ->
+ if (w2i ((i2w x#) `and#` (i2w (0# -# x#))) /=# x#) then
+ Nothing
+ else
+ Just (toInteger (I# (pow2 x#)))
+ }
+ where
+ shiftr x y = shiftRA# x y
+
+ pow2 x# | x# ==# 1# = 0#
+ | otherwise = 1# +# pow2 (w2i (i2w x# `shiftr` i2w_s 1#))
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+\begin{code}
+data Cond
+#if alpha_TARGET_ARCH
+ = ALWAYS -- For BI (same as BR)
+ | EQ -- For CMP and BI
+ | GE -- For BI only
+ | GT -- For BI only
+ | LE -- For CMP and BI
+ | LT -- For CMP and BI
+ | NE -- For BI only
+ | NEVER -- For BI (null instruction)
+ | ULE -- For CMP only
+ | ULT -- For CMP only
+#endif
+#if i386_TARGET_ARCH
+ = ALWAYS -- What's really used? ToDo
+ | EQ
+ | GE
+ | GEU
+ | GT
+ | GU
+ | LE
+ | LEU
+ | LT
+ | LU
+ | NE
+ | NEG
+ | POS
+#endif
+#if sparc_TARGET_ARCH
+ = ALWAYS -- What's really used? ToDo
+ | EQ
+ | GE
+ | GEU
+ | GT
+ | GU
+ | LE
+ | LEU
+ | LT
+ | LU
+ | NE
+ | NEG
+ | NEVER
+ | POS
+ | VC
+ | VS
+#endif
+\end{code}
+
+\begin{code}
+data Size
+#if alpha_TARGET_ARCH
+ = B -- byte
+ | BU
+-- | W -- word (2 bytes): UNUSED
+-- | WU -- : UNUSED
+-- | L -- longword (4 bytes): UNUSED
+ | Q -- quadword (8 bytes)
+-- | FF -- VAX F-style floating pt: UNUSED
+-- | GF -- VAX G-style floating pt: UNUSED
+-- | DF -- VAX D-style floating pt: UNUSED
+-- | SF -- IEEE single-precision floating pt: UNUSED
+ | TF -- IEEE double-precision floating pt
+#endif
+#if i386_TARGET_ARCH
+ = B -- byte (lower)
+-- | HB -- higher byte **UNUSED**
+-- | S -- : UNUSED
+ | L
+ | F -- IEEE single-precision floating pt
+ | DF -- IEEE single-precision floating pt
+#endif
+#if sparc_TARGET_ARCH
+ = B -- byte (signed)
+ | BU -- byte (unsigned)
+-- | HW -- halfword, 2 bytes (signed): UNUSED
+-- | HWU -- halfword, 2 bytes (unsigned): UNUSED
+ | W -- word, 4 bytes
+-- | D -- doubleword, 8 bytes: UNUSED
+ | F -- IEEE single-precision floating pt
+ | DF -- IEEE single-precision floating pt
+#endif
+
+primRepToSize :: PrimRep -> Size
+
+primRepToSize PtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize CodePtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize DataPtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize RetRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize CostCentreRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize CharRep = IF_ARCH_alpha( BU, IF_ARCH_i386( L, IF_ARCH_sparc( BU,)))
+primRepToSize IntRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize WordRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize AddrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize FloatRep = IF_ARCH_alpha( TF, IF_ARCH_i386( F, IF_ARCH_sparc( F ,)))
+primRepToSize DoubleRep = IF_ARCH_alpha( TF, IF_ARCH_i386( DF,IF_ARCH_sparc( DF,)))
+primRepToSize ArrayRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize ByteArrayRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize StablePtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+primRepToSize MallocPtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,)))
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Machine's assembly language}
+%* *
+%************************************************************************
+
+We have a few common ``instructions'' (nearly all the pseudo-ops) but
+mostly all of @Instr@ is machine-specific.
+
+\begin{code}
+data Instr
+ = COMMENT FAST_STRING -- comment pseudo-op
+ | SEGMENT CodeSegment -- {data,text} segment pseudo-op
+ | LABEL CLabel -- global label pseudo-op
+ | ASCII Bool -- True <=> needs backslash conversion
+ String -- the literal string
+ | DATA Size
+ [Imm]
+\end{code}
+
+\begin{code}
+#if alpha_TARGET_ARCH
+
+-- data Instr continues...
+
+-- Loads and stores.
+
+ | LD Size Reg Addr -- size, dst, src
+ | LDA Reg Addr -- dst, src
+ | LDAH Reg Addr -- dst, src
+ | LDGP Reg Addr -- dst, src
+ | LDI Size Reg Imm -- size, dst, src
+ | ST Size Reg Addr -- size, src, dst
+
+-- Int Arithmetic.
+
+ | CLR Reg -- dst
+ | ABS Size RI Reg -- size, src, dst
+ | NEG Size Bool RI Reg -- size, overflow, src, dst
+ | ADD Size Bool Reg RI Reg -- size, overflow, src, src, dst
+ | SADD Size Size Reg RI Reg -- size, scale, src, src, dst
+ | SUB Size Bool Reg RI Reg -- size, overflow, src, src, dst
+ | SSUB Size Size Reg RI Reg -- size, scale, src, src, dst
+ | MUL Size Bool Reg RI Reg -- size, overflow, src, src, dst
+ | DIV Size Bool Reg RI Reg -- size, unsigned, src, src, dst
+ | REM Size Bool Reg RI Reg -- size, unsigned, src, src, dst
+
+-- Simple bit-twiddling.
+
+ | NOT RI Reg
+ | AND Reg RI Reg
+ | ANDNOT Reg RI Reg
+ | OR Reg RI Reg
+ | ORNOT Reg RI Reg
+ | XOR Reg RI Reg
+ | XORNOT Reg RI Reg
+ | SLL Reg RI Reg
+ | SRL Reg RI Reg
+ | SRA Reg RI Reg
+
+ | ZAP Reg RI Reg
+ | ZAPNOT Reg RI Reg
+
+ | NOP
+
+-- Comparison
+
+ | CMP Cond Reg RI Reg
+
+-- Float Arithmetic.
+
+ | FCLR Reg
+ | FABS Reg Reg
+ | FNEG Size Reg Reg
+ | FADD Size Reg Reg Reg
+ | FDIV Size Reg Reg Reg
+ | FMUL Size Reg Reg Reg
+ | FSUB Size Reg Reg Reg
+ | CVTxy Size Size Reg Reg
+ | FCMP Size Cond Reg Reg Reg
+ | FMOV Reg Reg
+
+-- Jumping around.
+
+ | BI Cond Reg Imm
+ | BF Cond Reg Imm
+ | BR Imm
+ | JMP Reg Addr Int
+ | BSR Imm Int
+ | JSR Reg Addr Int
+
+-- Alpha-specific pseudo-ops.
+
+ | FUNBEGIN CLabel
+ | FUNEND CLabel
+
+data RI
+ = RIReg Reg
+ | RIImm Imm
+
+#endif {- alpha_TARGET_ARCH -}
+\end{code}
+
+\begin{code}
+#if i386_TARGET_ARCH
+
+-- data Instr continues...
+
+-- Moves.
+
+ | MOV Size Operand Operand
+ | MOVZX Size Operand Operand -- size is the size of operand 2
+ | MOVSX Size Operand Operand -- size is the size of operand 2
+
+-- Load effective address (also a very useful three-operand add instruction :-)
+
+ | LEA Size Operand Operand
+
+-- Int Arithmetic.
+
+ | ADD Size Operand Operand
+ | SUB Size Operand Operand
+
+-- Multiplication (signed and unsigned), Division (signed and unsigned),
+-- result in %eax, %edx.
+
+ | IMUL Size Operand Operand
+ | IDIV Size Operand
+
+-- Simple bit-twiddling.
+
+ | AND Size Operand Operand
+ | OR Size Operand Operand
+ | XOR Size Operand Operand
+ | NOT Size Operand
+ | NEGI Size Operand -- NEG instruction (name clash with Cond)
+ | SHL Size Operand Operand -- 1st operand must be an Imm
+ | SAR Size Operand Operand -- 1st operand must be an Imm
+ | SHR Size Operand Operand -- 1st operand must be an Imm
+ | NOP
+
+-- Float Arithmetic. -- ToDo for 386
+
+-- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions
+-- right up until we spit them out.
+
+ | SAHF -- stores ah into flags
+ | FABS
+ | FADD Size Operand -- src
+ | FADDP
+ | FIADD Size Addr -- src
+ | FCHS
+ | FCOM Size Operand -- src
+ | FCOS
+ | FDIV Size Operand -- src
+ | FDIVP
+ | FIDIV Size Addr -- src
+ | FDIVR Size Operand -- src
+ | FDIVRP
+ | FIDIVR Size Addr -- src
+ | FICOM Size Addr -- src
+ | FILD Size Addr Reg -- src, dst
+ | FIST Size Addr -- dst
+ | FLD Size Operand -- src
+ | FLD1
+ | FLDZ
+ | FMUL Size Operand -- src
+ | FMULP
+ | FIMUL Size Addr -- src
+ | FRNDINT
+ | FSIN
+ | FSQRT
+ | FST Size Operand -- dst
+ | FSTP Size Operand -- dst
+ | FSUB Size Operand -- src
+ | FSUBP
+ | FISUB Size Addr -- src
+ | FSUBR Size Operand -- src
+ | FSUBRP
+ | FISUBR Size Addr -- src
+ | FTST
+ | FCOMP Size Operand -- src
+ | FUCOMPP
+ | FXCH
+ | FNSTSW
+ | FNOP
+
+-- Comparison
+
+ | TEST Size Operand Operand
+ | CMP Size Operand Operand
+ | SETCC Cond Operand
+
+-- Stack Operations.
+
+ | PUSH Size Operand
+ | POP Size Operand
+
+-- Jumping around.
+
+ | JMP Operand -- target
+ | JXX Cond CLabel -- target
+ | CALL Imm
+
+-- Other things.
+
+ | CLTD -- sign extend %eax into %edx:%eax
+
+data Operand
+ = OpReg Reg -- register
+ | OpImm Imm -- immediate value
+ | OpAddr Addr -- memory reference
+
+#endif {- i386_TARGET_ARCH -}
+\end{code}
+
+\begin{code}
+#if sparc_TARGET_ARCH
+
+-- data Instr continues...
+
+-- Loads and stores.
+
+ | LD Size Addr Reg -- size, src, dst
+ | ST Size Reg Addr -- size, src, dst
+
+-- Int Arithmetic.
+
+ | ADD Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
+ | SUB Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
+
+-- Simple bit-twiddling.
+
+ | AND Bool Reg RI Reg -- cc?, src1, src2, dst
+ | ANDN Bool Reg RI Reg -- cc?, src1, src2, dst
+ | OR Bool Reg RI Reg -- cc?, src1, src2, dst
+ | ORN Bool Reg RI Reg -- cc?, src1, src2, dst
+ | XOR Bool Reg RI Reg -- cc?, src1, src2, dst
+ | XNOR Bool Reg RI Reg -- cc?, src1, src2, dst
+ | SLL Reg RI Reg -- src1, src2, dst
+ | SRL Reg RI Reg -- src1, src2, dst
+ | SRA Reg RI Reg -- src1, src2, dst
+ | SETHI Imm Reg -- src, dst
+ | NOP -- Really SETHI 0, %g0, but worth an alias
+
+-- Float Arithmetic.
+
+-- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions
+-- right up until we spit them out.
+
+ | FABS Size Reg Reg -- src dst
+ | FADD Size Reg Reg Reg -- src1, src2, dst
+ | FCMP Bool Size Reg Reg -- exception?, src1, src2, dst
+ | FDIV Size Reg Reg Reg -- src1, src2, dst
+ | FMOV Size Reg Reg -- src, dst
+ | FMUL Size Reg Reg Reg -- src1, src2, dst
+ | FNEG Size Reg Reg -- src, dst
+ | FSQRT Size Reg Reg -- src, dst
+ | FSUB Size Reg Reg Reg -- src1, src2, dst
+ | FxTOy Size Size Reg Reg -- src, dst
+
+-- Jumping around.
+
+ | BI Cond Bool Imm -- cond, annul?, target
+ | BF Cond Bool Imm -- cond, annul?, target
+
+ | JMP Addr -- target
+ | CALL Imm Int Bool -- target, args, terminal
+
+data RI = RIReg Reg
+ | RIImm Imm
+
+riZero :: RI -> Bool
+
+riZero (RIImm (ImmInt 0)) = True
+riZero (RIImm (ImmInteger 0)) = True
+riZero (RIReg (FixedReg ILIT(0))) = True
+riZero _ = False
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
--- /dev/null
+%
+% (c) The AQUA Project, Glasgow University, 1996
+%
+\section[MachRegs]{Machine-specific info about registers}
+
+Also includes stuff about immediate operands, which are
+often/usually quite entangled with registers.
+
+(Immediates could be untangled from registers at some cost in tangled
+modules --- the pleasure has been foregone.)
+
+\begin{code}
+#include "HsVersions.h"
+#include "nativeGen/NCG.h"
+
+module MachRegs (
+
+ Reg(..),
+ Imm(..),
+ Addr(..),
+ RegLoc(..),
+ RegNo(..),
+
+ addrOffset,
+ argRegs,
+ baseRegOffset,
+ callClobberedRegs,
+ callerSaves,
+ dblImmLit,
+ extractMappedRegNos,
+ freeMappedRegs,
+ freeReg, freeRegs,
+ getNewRegNCG,
+ magicIdRegMaybe,
+ mkReg,
+ realReg,
+ reservedRegs,
+ saveLoc,
+ spRel,
+ stgReg,
+ strImmLit
+
+#if alpha_TARGET_ARCH
+ , allArgRegs
+ , fits8Bits
+ , fReg
+ , gp, pv, ra, sp, t9, t10, t11, t12, v0, f0, zero
+#endif
+#if i386_TARGET_ARCH
+ , eax, ebx, ecx, edx, esi, esp
+ , st0, st1, st2, st3, st4, st5, st6, st7
+#endif
+#if sparc_TARGET_ARCH
+ , allArgRegs
+ , fits13Bits
+ , fPair, fpRel, gReg, iReg, lReg, oReg, largeOffsetError
+ , fp, g0, o0, f0
+
+#endif
+ ) where
+
+import Ubiq{-uitous-}
+
+import AbsCSyn ( MagicId(..) )
+import AbsCUtils ( magicIdPrimRep )
+import Pretty ( ppStr, ppRational, ppShow )
+import PrimOp ( PrimOp(..) )
+import PrimRep ( PrimRep(..) )
+import Stix ( sStLitLbl, StixTree(..), StixReg(..),
+ CodeSegment
+ )
+import Unique ( Unique{-instance Ord3-} )
+import UniqSupply ( mkPseudoUnique1, mkPseudoUnique2, mkPseudoUnique3,
+ getUnique, returnUs, thenUs, UniqSM(..)
+ )
+import Unpretty ( uppStr, Unpretty(..) )
+import Util ( panic )
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+\begin{code}
+data Imm
+ = ImmInt Int
+ | ImmInteger Integer -- Sigh.
+ | ImmCLbl CLabel -- AbstractC Label (with baggage)
+ | ImmLab Unpretty -- Simple string label (underscore-able)
+ | ImmLit Unpretty -- Simple string
+ IF_ARCH_sparc(
+ | LO Imm -- Possible restrictions...
+ | HI Imm
+ ,)
+
+strImmLit s = ImmLit (uppStr s)
+dblImmLit r
+ = strImmLit (
+ IF_ARCH_alpha({-prepend nothing-}
+ ,IF_ARCH_i386( '0' : 'd' :
+ ,IF_ARCH_sparc('0' : 'r' :,)))
+ ppShow 80 (ppRational r))
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+\begin{code}
+data Addr
+#if alpha_TARGET_ARCH
+ = AddrImm Imm
+ | AddrReg Reg
+ | AddrRegImm Reg Imm
+#endif
+
+#if i386_TARGET_ARCH
+ = Addr Base Index Displacement
+ | ImmAddr Imm Int
+
+type Base = Maybe Reg
+type Index = Maybe (Reg, Int) -- Int is 2, 4 or 8
+type Displacement = Imm
+#endif
+
+#if sparc_TARGET_ARCH
+ = AddrRegReg Reg Reg
+ | AddrRegImm Reg Imm
+#endif
+
+addrOffset :: Addr -> Int -> Maybe Addr
+
+addrOffset addr off
+ = case addr of
+#if alpha_TARGET_ARCH
+ _ -> panic "MachMisc.addrOffset not defined for Alpha"
+#endif
+#if i386_TARGET_ARCH
+ ImmAddr i off0 -> Just (ImmAddr i (off0 + off))
+ Addr r i (ImmInt n) -> Just (Addr r i (ImmInt (n + off)))
+ Addr r i (ImmInteger n)
+ -> Just (Addr r i (ImmInt (fromInteger (n + toInteger off))))
+ _ -> Nothing
+#endif
+#if sparc_TARGET_ARCH
+ AddrRegImm r (ImmInt n)
+ | fits13Bits n2 -> Just (AddrRegImm r (ImmInt n2))
+ | otherwise -> Nothing
+ where n2 = n + off
+
+ AddrRegImm r (ImmInteger n)
+ | fits13Bits n2 -> Just (AddrRegImm r (ImmInt (fromInteger n2)))
+ | otherwise -> Nothing
+ where n2 = n + toInteger off
+
+ AddrRegReg r (FixedReg ILIT(0))
+ | fits13Bits off -> Just (AddrRegImm r (ImmInt off))
+ | otherwise -> Nothing
+
+ _ -> Nothing
+
+#endif {-sparc-}
+
+-----------------
+#if alpha_TARGET_ARCH
+
+fits8Bits :: Integer -> Bool
+fits8Bits i = i >= -256 && i < 256
+
+#endif
+
+#if sparc_TARGET_ARCH
+{-# SPECIALIZE
+ fits13Bits :: Int -> Bool
+ #-}
+{-# SPECIALIZE
+ fits13Bits :: Integer -> Bool
+ #-}
+
+fits13Bits :: Integral a => a -> Bool
+fits13Bits x = x >= -4096 && x < 4096
+
+-----------------
+largeOffsetError i
+ = error ("ERROR: SPARC native-code generator cannot handle large offset ("++show i++");\nprobably because of large constant data structures;\nworkaround: use -fvia-C on this module.\n")
+
+#endif {-sparc-}
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+@stgReg@: we map STG registers onto appropriate Stix Trees. First, we
+handle the two constants, @STK_STUB_closure@ and @vtbl_StdUpdFrame@.
+The rest are either in real machine registers or stored as offsets
+from BaseReg.
+
+\begin{code}
+data RegLoc = Save StixTree | Always StixTree
+\end{code}
+
+Trees for register save locations:
+\begin{code}
+saveLoc :: MagicId -> StixTree
+
+saveLoc reg = case (stgReg reg) of {Always loc -> loc; Save loc -> loc}
+\end{code}
+
+\begin{code}
+stgReg :: MagicId -> RegLoc
+
+stgReg x
+ = case (magicIdRegMaybe x) of
+ Just _ -> Save nonReg
+ Nothing -> Always nonReg
+ where
+ offset = baseRegOffset x
+
+ baseLoc = case (magicIdRegMaybe BaseReg) of
+ Just _ -> StReg (StixMagicId BaseReg)
+ Nothing -> sStLitLbl SLIT("MainRegTable")
+
+ nonReg = case x of
+ StkStubReg -> sStLitLbl SLIT("STK_STUB_closure")
+ StdUpdRetVecReg -> sStLitLbl SLIT("vtbl_StdUpdFrame")
+ BaseReg -> sStLitLbl SLIT("MainRegTable")
+ -- these Hp&HpLim cases perhaps should
+ -- not be here for i386 (???) WDP 96/03
+ Hp -> StInd PtrRep (sStLitLbl SLIT("StorageMgrInfo"))
+ HpLim -> StInd PtrRep (sStLitLbl
+ (_PK_ ("StorageMgrInfo+" ++ BYTES_PER_WORD_STR)))
+ TagReg -> StInd IntRep (StPrim IntSubOp [infoptr,
+ StInt (1*BYTES_PER_WORD)])
+ where
+ r2 = VanillaReg PtrRep ILIT(2)
+ infoptr = case (stgReg r2) of
+ Always t -> t
+ Save _ -> StReg (StixMagicId r2)
+ _ -> StInd (magicIdPrimRep x)
+ (StPrim IntAddOp [baseLoc,
+ StInt (toInteger (offset*BYTES_PER_WORD))])
+\end{code}
+
+% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+@spRel@ gives us a stack relative addressing mode for volatile
+temporaries and for excess call arguments. @fpRel@, where
+applicable, is the same but for the frame pointer.
+
+\begin{code}
+spRel :: Int -- desired stack offset in words, positive or negative
+ -> Addr
+
+spRel n
+#if i386_TARGET_ARCH
+ = Addr (Just esp) Nothing (ImmInt (n * BYTES_PER_WORD))
+#else
+ = AddrRegImm sp (ImmInt (n * BYTES_PER_WORD))
+#endif
+
+#if sparc_TARGET_ARCH
+fpRel :: Int -> Addr
+ -- Duznae work for offsets greater than 13 bits; we just hope for
+ -- the best
+fpRel n
+ = AddrRegImm fp (ImmInt (n * BYTES_PER_WORD))
+#endif
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[Reg]{Real registers}
+%* *
+%************************************************************************
+
+Static Registers correspond to actual machine registers. These should
+be avoided until the last possible moment.
+
+Dynamic registers are allocated on the fly, usually to represent a single
+value in the abstract assembly code (i.e. dynamic registers are usually
+single assignment). Ultimately, they are mapped to available machine
+registers before spitting out the code.
+
+\begin{code}
+data Reg
+ = FixedReg FAST_INT -- A pre-allocated machine register
+
+ | MappedReg FAST_INT -- A dynamically allocated machine register
+
+ | MemoryReg Int PrimRep -- A machine "register" actually held in
+ -- a memory allocated table of
+ -- registers which didn't fit in real
+ -- registers.
+
+ | UnmappedReg Unique PrimRep -- One of an infinite supply of registers,
+ -- always mapped to one of the earlier
+ -- two (?) before we're done.
+
+mkReg :: Unique -> PrimRep -> Reg
+mkReg = UnmappedReg
+
+getNewRegNCG :: PrimRep -> UniqSM Reg
+getNewRegNCG pk
+ = getUnique `thenUs` \ u ->
+ returnUs (UnmappedReg u pk)
+
+instance Text Reg where
+ showsPrec _ (FixedReg i) = showString "%" . shows IBOX(i)
+ showsPrec _ (MappedReg i) = showString "%" . shows IBOX(i)
+ showsPrec _ (MemoryReg i _) = showString "%M" . shows i
+ showsPrec _ (UnmappedReg i _) = showString "%U" . shows i
+
+#ifdef DEBUG
+instance Outputable Reg where
+ ppr sty r = ppStr (show r)
+#endif
+
+cmpReg (FixedReg i) (FixedReg i') = cmp_ihash i i'
+cmpReg (MappedReg i) (MappedReg i') = cmp_ihash i i'
+cmpReg (MemoryReg i _) (MemoryReg i' _) = cmp_i i i'
+cmpReg (UnmappedReg u _) (UnmappedReg u' _) = cmp u u'
+cmpReg r1 r2
+ = let tag1 = tagReg r1
+ tag2 = tagReg r2
+ in
+ if tag1 _LT_ tag2 then LT_ else GT_
+ where
+ tagReg (FixedReg _) = (ILIT(1) :: FAST_INT)
+ tagReg (MappedReg _) = ILIT(2)
+ tagReg (MemoryReg _ _) = ILIT(3)
+ tagReg (UnmappedReg _ _) = ILIT(4)
+
+cmp_i :: Int -> Int -> TAG_
+cmp_i a1 a2 = if a1 == a2 then EQ_ else if a1 < a2 then LT_ else GT_
+
+cmp_ihash :: FAST_INT -> FAST_INT -> TAG_
+cmp_ihash a1 a2 = if a1 _EQ_ a2 then EQ_ else if a1 _LT_ a2 then LT_ else GT_
+
+instance Eq Reg where
+ a == b = case cmpReg a b of { EQ_ -> True; _ -> False }
+ a /= b = case cmpReg a b of { EQ_ -> False; _ -> True }
+
+instance Ord Reg where
+ a <= b = case cmpReg a b of { LT_ -> True; EQ_ -> True; GT__ -> False }
+ a < b = case cmpReg a b of { LT_ -> True; EQ_ -> False; GT__ -> False }
+ a >= b = case cmpReg a b of { LT_ -> False; EQ_ -> True; GT__ -> True }
+ a > b = case cmpReg a b of { LT_ -> False; EQ_ -> False; GT__ -> True }
+ _tagCmp a b = case cmpReg a b of { LT_ -> _LT; EQ_ -> _EQ; GT__ -> _GT }
+
+instance NamedThing Reg where
+ -- the *only* method that should be defined is "getItsUnique"!
+ -- (so we can use UniqFMs/UniqSets on Regs
+ getItsUnique (UnmappedReg u _) = u
+ getItsUnique (FixedReg i) = mkPseudoUnique1 IBOX(i)
+ getItsUnique (MappedReg i) = mkPseudoUnique2 IBOX(i)
+ getItsUnique (MemoryReg i _) = mkPseudoUnique3 i
+\end{code}
+
+\begin{code}
+type RegNo = Int
+
+realReg :: RegNo -> Reg
+realReg n@IBOX(i)
+ = if _IS_TRUE_(freeReg i) then MappedReg i else FixedReg i
+
+extractMappedRegNos :: [Reg] -> [RegNo]
+
+extractMappedRegNos regs
+ = foldr ex [] regs
+ where
+ ex (MappedReg i) acc = IBOX(i) : acc -- we'll take it
+ ex _ acc = acc -- leave it out
+\end{code}
+
+** Machine-specific Reg stuff: **
+
+The Alpha has 64 registers of interest; 32 integer registers and 32 floating
+point registers. The mapping of STG registers to alpha machine registers
+is defined in StgRegs.h. We are, of course, prepared for any eventuality.
+\begin{code}
+#if alpha_TARGET_ARCH
+fReg :: Int -> Int
+fReg x = (32 + x)
+
+v0, f0, ra, pv, gp, sp, zero :: Reg
+v0 = realReg 0
+f0 = realReg (fReg 0)
+ra = FixedReg ILIT(26)
+pv = t12
+gp = FixedReg ILIT(29)
+sp = FixedReg ILIT(30)
+zero = FixedReg ILIT(31)
+
+t9, t10, t11, t12 :: Reg
+t9 = realReg 23
+t10 = realReg 24
+t11 = realReg 25
+t12 = realReg 27
+#endif
+\end{code}
+
+Intel x86 architecture:
+- All registers except 7 (esp) are available for use.
+- Only ebx, esi, edi and esp are available across a C call (they are callee-saves).
+- Registers 0-7 have 16-bit counterparts (ax, bx etc.)
+- Registers 0-3 have 8 bit counterparts (ah, bh etc.)
+- Registers 8-15 hold extended floating point values.
+\begin{code}
+#if i386_TARGET_ARCH
+
+gReg,fReg :: Int -> Int
+gReg x = x
+fReg x = (8 + x)
+
+st0, st1, st2, st3, st4, st5, st6, st7, eax, ebx, ecx, edx, esp :: Reg
+eax = case (gReg 0) of { IBOX(g0) -> FixedReg g0 }
+ebx = case (gReg 1) of { IBOX(g1) -> FixedReg g1 }
+ecx = case (gReg 2) of { IBOX(g2) -> FixedReg g2 }
+edx = case (gReg 3) of { IBOX(g3) -> FixedReg g3 }
+esi = case (gReg 4) of { IBOX(g4) -> FixedReg g4 }
+edi = case (gReg 5) of { IBOX(g5) -> FixedReg g5 }
+ebp = case (gReg 6) of { IBOX(g6) -> FixedReg g6 }
+esp = case (gReg 7) of { IBOX(g7) -> FixedReg g7 }
+st0 = realReg (fReg 0)
+st1 = realReg (fReg 1)
+st2 = realReg (fReg 2)
+st3 = realReg (fReg 3)
+st4 = realReg (fReg 4)
+st5 = realReg (fReg 5)
+st6 = realReg (fReg 6)
+st7 = realReg (fReg 7)
+
+#endif
+\end{code}
+
+The SPARC has 64 registers of interest; 32 integer registers and 32
+floating point registers. The mapping of STG registers to SPARC
+machine registers is defined in StgRegs.h. We are, of course,
+prepared for any eventuality.
+
+\begin{code}
+#if sparc_TARGET_ARCH
+
+gReg,lReg,iReg,oReg,fReg :: Int -> Int
+gReg x = x
+oReg x = (8 + x)
+lReg x = (16 + x)
+iReg x = (24 + x)
+fReg x = (32 + x)
+
+fPair :: Reg -> Reg
+fPair (FixedReg i) = FixedReg (i _ADD_ ILIT(1))
+fPair (MappedReg i) = MappedReg (i _ADD_ ILIT(1))
+
+g0, fp, sp, o0, f0 :: Reg
+g0 = case (gReg 0) of { IBOX(g0) -> FixedReg g0 }
+fp = case (iReg 6) of { IBOX(i6) -> FixedReg i6 }
+sp = case (oReg 6) of { IBOX(o6) -> FixedReg o6 }
+o0 = realReg (oReg 0)
+f0 = realReg (fReg 0)
+
+#endif
+\end{code}
+
+Redefine the literals used for machine-registers with non-numeric
+names in the header files. Gag me with a spoon, eh?
+\begin{code}
+#if alpha_TARGET_ARCH
+#define f0 32
+#define f1 33
+#define f2 34
+#define f3 35
+#define f4 36
+#define f5 37
+#define f6 38
+#define f7 39
+#define f8 40
+#define f9 41
+#define f10 42
+#define f11 43
+#define f12 44
+#define f13 45
+#define f14 46
+#define f15 47
+#define f16 48
+#define f17 49
+#define f18 50
+#define f19 51
+#define f20 52
+#define f21 53
+#define f22 54
+#define f23 55
+#define f24 56
+#define f25 57
+#define f26 58
+#define f27 59
+#define f28 60
+#define f29 61
+#define f30 62
+#define f31 63
+#endif
+#if i386_TARGET_ARCH
+#define eax 0
+#define ebx 1
+#define ecx 2
+#define edx 3
+#define esi 4
+#define edi 5
+#define ebp 6
+#define esp 7
+#define st0 8
+#define st1 9
+#define st2 10
+#define st3 11
+#define st4 12
+#define st5 13
+#define st6 14
+#define st7 15
+#endif
+#if sparc_TARGET_ARCH
+#define g0 0
+#define g1 1
+#define g2 2
+#define g3 3
+#define g4 4
+#define g5 5
+#define g6 6
+#define g7 7
+#define o0 8
+#define o1 9
+#define o2 10
+#define o3 11
+#define o4 12
+#define o5 13
+#define o6 14
+#define o7 15
+#define l0 16
+#define l1 17
+#define l2 18
+#define l3 19
+#define l4 20
+#define l5 21
+#define l6 22
+#define l7 23
+#define i0 24
+#define i1 25
+#define i2 26
+#define i3 27
+#define i4 28
+#define i5 29
+#define i6 30
+#define i7 31
+#define f0 32
+#define f1 33
+#define f2 34
+#define f3 35
+#define f4 36
+#define f5 37
+#define f6 38
+#define f7 39
+#define f8 40
+#define f9 41
+#define f10 42
+#define f11 43
+#define f12 44
+#define f13 45
+#define f14 46
+#define f15 47
+#define f16 48
+#define f17 49
+#define f18 50
+#define f19 51
+#define f20 52
+#define f21 53
+#define f22 54
+#define f23 55
+#define f24 56
+#define f25 57
+#define f26 58
+#define f27 59
+#define f28 60
+#define f29 61
+#define f30 62
+#define f31 63
+#endif
+\end{code}
+
+\begin{code}
+baseRegOffset :: MagicId -> Int
+
+baseRegOffset StkOReg = OFFSET_StkO
+baseRegOffset (VanillaReg _ ILIT(1)) = OFFSET_R1
+baseRegOffset (VanillaReg _ ILIT(2)) = OFFSET_R2
+baseRegOffset (VanillaReg _ ILIT(3)) = OFFSET_R3
+baseRegOffset (VanillaReg _ ILIT(4)) = OFFSET_R4
+baseRegOffset (VanillaReg _ ILIT(5)) = OFFSET_R5
+baseRegOffset (VanillaReg _ ILIT(6)) = OFFSET_R6
+baseRegOffset (VanillaReg _ ILIT(7)) = OFFSET_R7
+baseRegOffset (VanillaReg _ ILIT(8)) = OFFSET_R8
+baseRegOffset (FloatReg ILIT(1)) = OFFSET_Flt1
+baseRegOffset (FloatReg ILIT(2)) = OFFSET_Flt2
+baseRegOffset (FloatReg ILIT(3)) = OFFSET_Flt3
+baseRegOffset (FloatReg ILIT(4)) = OFFSET_Flt4
+baseRegOffset (DoubleReg ILIT(1)) = OFFSET_Dbl1
+baseRegOffset (DoubleReg ILIT(2)) = OFFSET_Dbl2
+baseRegOffset TagReg = OFFSET_Tag
+baseRegOffset RetReg = OFFSET_Ret
+baseRegOffset SpA = OFFSET_SpA
+baseRegOffset SuA = OFFSET_SuA
+baseRegOffset SpB = OFFSET_SpB
+baseRegOffset SuB = OFFSET_SuB
+baseRegOffset Hp = OFFSET_Hp
+baseRegOffset HpLim = OFFSET_HpLim
+baseRegOffset LivenessReg = OFFSET_Liveness
+#ifdef DEBUG
+baseRegOffset BaseReg = panic "baseRegOffset:BaseReg"
+baseRegOffset StdUpdRetVecReg = panic "baseRegOffset:StgUpdRetVecReg"
+baseRegOffset StkStubReg = panic "baseRegOffset:StkStubReg"
+baseRegOffset CurCostCentre = panic "baseRegOffset:CurCostCentre"
+baseRegOffset VoidReg = panic "baseRegOffset:VoidReg"
+#endif
+\end{code}
+
+\begin{code}
+callerSaves :: MagicId -> Bool
+
+#ifdef CALLER_SAVES_Base
+callerSaves BaseReg = True
+#endif
+#ifdef CALLER_SAVES_StkO
+callerSaves StkOReg = True
+#endif
+#ifdef CALLER_SAVES_R1
+callerSaves (VanillaReg _ ILIT(1)) = True
+#endif
+#ifdef CALLER_SAVES_R2
+callerSaves (VanillaReg _ ILIT(2)) = True
+#endif
+#ifdef CALLER_SAVES_R3
+callerSaves (VanillaReg _ ILIT(3)) = True
+#endif
+#ifdef CALLER_SAVES_R4
+callerSaves (VanillaReg _ ILIT(4)) = True
+#endif
+#ifdef CALLER_SAVES_R5
+callerSaves (VanillaReg _ ILIT(5)) = True
+#endif
+#ifdef CALLER_SAVES_R6
+callerSaves (VanillaReg _ ILIT(6)) = True
+#endif
+#ifdef CALLER_SAVES_R7
+callerSaves (VanillaReg _ ILIT(7)) = True
+#endif
+#ifdef CALLER_SAVES_R8
+callerSaves (VanillaReg _ ILIT(8)) = True
+#endif
+#ifdef CALLER_SAVES_FltReg1
+callerSaves (FloatReg ILIT(1)) = True
+#endif
+#ifdef CALLER_SAVES_FltReg2
+callerSaves (FloatReg ILIT(2)) = True
+#endif
+#ifdef CALLER_SAVES_FltReg3
+callerSaves (FloatReg ILIT(3)) = True
+#endif
+#ifdef CALLER_SAVES_FltReg4
+callerSaves (FloatReg ILIT(4)) = True
+#endif
+#ifdef CALLER_SAVES_DblReg1
+callerSaves (DoubleReg ILIT(1)) = True
+#endif
+#ifdef CALLER_SAVES_DblReg2
+callerSaves (DoubleReg ILIT(2)) = True
+#endif
+#ifdef CALLER_SAVES_Tag
+callerSaves TagReg = True
+#endif
+#ifdef CALLER_SAVES_Ret
+callerSaves RetReg = True
+#endif
+#ifdef CALLER_SAVES_SpA
+callerSaves SpA = True
+#endif
+#ifdef CALLER_SAVES_SuA
+callerSaves SuA = True
+#endif
+#ifdef CALLER_SAVES_SpB
+callerSaves SpB = True
+#endif
+#ifdef CALLER_SAVES_SuB
+callerSaves SuB = True
+#endif
+#ifdef CALLER_SAVES_Hp
+callerSaves Hp = True
+#endif
+#ifdef CALLER_SAVES_HpLim
+callerSaves HpLim = True
+#endif
+#ifdef CALLER_SAVES_Liveness
+callerSaves LivenessReg = True
+#endif
+#ifdef CALLER_SAVES_StdUpdRetVec
+callerSaves StdUpdRetVecReg = True
+#endif
+#ifdef CALLER_SAVES_StkStub
+callerSaves StkStubReg = True
+#endif
+callerSaves _ = False
+\end{code}
+
+\begin{code}
+magicIdRegMaybe :: MagicId -> Maybe Reg
+
+#ifdef REG_Base
+magicIdRegMaybe BaseReg = Just (FixedReg ILIT(REG_Base))
+#endif
+#ifdef REG_StkO
+magicIdRegMaybe StkOReg = Just (FixedReg ILIT(REG_StkOReg))
+#endif
+#ifdef REG_R1
+magicIdRegMaybe (VanillaReg _ ILIT(1)) = Just (FixedReg ILIT(REG_R1))
+#endif
+#ifdef REG_R2
+magicIdRegMaybe (VanillaReg _ ILIT(2)) = Just (FixedReg ILIT(REG_R2))
+#endif
+#ifdef REG_R3
+magicIdRegMaybe (VanillaReg _ ILIT(3)) = Just (FixedReg ILIT(REG_R3))
+#endif
+#ifdef REG_R4
+magicIdRegMaybe (VanillaReg _ ILIT(4)) = Just (FixedReg ILIT(REG_R4))
+#endif
+#ifdef REG_R5
+magicIdRegMaybe (VanillaReg _ ILIT(5)) = Just (FixedReg ILIT(REG_R5))
+#endif
+#ifdef REG_R6
+magicIdRegMaybe (VanillaReg _ ILIT(6)) = Just (FixedReg ILIT(REG_R6))
+#endif
+#ifdef REG_R7
+magicIdRegMaybe (VanillaReg _ ILIT(7)) = Just (FixedReg ILIT(REG_R7))
+#endif
+#ifdef REG_R8
+magicIdRegMaybe (VanillaReg _ ILIT(8)) = Just (FixedReg ILIT(REG_R8))
+#endif
+#ifdef REG_Flt1
+magicIdRegMaybe (FloatReg ILIT(1)) = Just (FixedReg ILIT(REG_Flt1))
+#endif
+#ifdef REG_Flt2
+magicIdRegMaybe (FloatReg ILIT(2)) = Just (FixedReg ILIT(REG_Flt2))
+#endif
+#ifdef REG_Flt3
+magicIdRegMaybe (FloatReg ILIT(3)) = Just (FixedReg ILIT(REG_Flt3))
+#endif
+#ifdef REG_Flt4
+magicIdRegMaybe (FloatReg ILIT(4)) = Just (FixedReg ILIT(REG_Flt4))
+#endif
+#ifdef REG_Dbl1
+magicIdRegMaybe (DoubleReg ILIT(1)) = Just (FixedReg ILIT(REG_Dbl1))
+#endif
+#ifdef REG_Dbl2
+magicIdRegMaybe (DoubleReg ILIT(2)) = Just (FixedReg ILIT(REG_Dbl2))
+#endif
+#ifdef REG_Tag
+magicIdRegMaybe TagReg = Just (FixedReg ILIT(REG_TagReg))
+#endif
+#ifdef REG_Ret
+magicIdRegMaybe RetReg = Just (FixedReg ILIT(REG_Ret))
+#endif
+#ifdef REG_SpA
+magicIdRegMaybe SpA = Just (FixedReg ILIT(REG_SpA))
+#endif
+#ifdef REG_SuA
+magicIdRegMaybe SuA = Just (FixedReg ILIT(REG_SuA))
+#endif
+#ifdef REG_SpB
+magicIdRegMaybe SpB = Just (FixedReg ILIT(REG_SpB))
+#endif
+#ifdef REG_SuB
+magicIdRegMaybe SuB = Just (FixedReg ILIT(REG_SuB))
+#endif
+#ifdef REG_Hp
+magicIdRegMaybe Hp = Just (FixedReg ILIT(REG_Hp))
+#endif
+#ifdef REG_HpLim
+magicIdRegMaybe HpLim = Just (FixedReg ILIT(REG_HpLim))
+#endif
+#ifdef REG_Liveness
+magicIdRegMaybe LivenessReg = Just (FixedReg ILIT(REG_Liveness))
+#endif
+#ifdef REG_StdUpdRetVec
+magicIdRegMaybe StdUpdRetVecReg = Just (FixedReg ILIT(REG_StdUpdRetVec))
+#endif
+#ifdef REG_StkStub
+magicIdRegMaybe StkStubReg = Just (FixedReg ILIT(REG_StkStub))
+#endif
+magicIdRegMaybe _ = Nothing
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Free, reserved, call-clobbered, and argument registers}
+%* *
+%************************************************************************
+
+@freeRegs@ is the list of registers we can use in register allocation.
+@freeReg@ (below) says if a particular register is free.
+
+With a per-instruction clobber list, we might be able to get some of
+these back, but it's probably not worth the hassle.
+
+@callClobberedRegs@ ... the obvious.
+
+@argRegs@: assuming a call with N arguments, what registers will be
+used to hold arguments? (NB: it doesn't know whether the arguments
+are integer or floating-point...)
+
+\begin{code}
+reservedRegs :: [RegNo]
+reservedRegs
+#if alpha_TARGET_ARCH
+ = [NCG_Reserved_I1, NCG_Reserved_I2,
+ NCG_Reserved_F1, NCG_Reserved_F2]
+#endif
+#if i386_TARGET_ARCH
+ = [{-certainly cannot afford any!-}]
+#endif
+#if sparc_TARGET_ARCH
+ = [NCG_Reserved_I1, NCG_Reserved_I2,
+ NCG_Reserved_F1, NCG_Reserved_F2,
+ NCG_Reserved_D1, NCG_Reserved_D2]
+#endif
+
+-------------------------------
+freeRegs :: [Reg]
+freeRegs
+ = freeMappedRegs IF_ARCH_alpha( [0..63],
+ IF_ARCH_i386( [0..15],
+ IF_ARCH_sparc( [0..63],)))
+
+-------------------------------
+callClobberedRegs :: [Reg]
+callClobberedRegs
+ = freeMappedRegs
+#if alpha_TARGET_ARCH
+ [0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ fReg 0, fReg 1, fReg 10, fReg 11, fReg 12, fReg 13, fReg 14, fReg 15,
+ fReg 16, fReg 17, fReg 18, fReg 19, fReg 20, fReg 21, fReg 22, fReg 23,
+ fReg 24, fReg 25, fReg 26, fReg 27, fReg 28, fReg 29, fReg 30]
+#endif {- alpha_TARGET_ARCH -}
+#if i386_TARGET_ARCH
+ [{-none-}]
+#endif {- i386_TARGET_ARCH -}
+#if sparc_TARGET_ARCH
+ ( oReg 7 :
+ [oReg i | i <- [0..5]] ++
+ [gReg i | i <- [1..7]] ++
+ [fReg i | i <- [0..31]] )
+#endif {- sparc_TARGET_ARCH -}
+
+-------------------------------
+argRegs :: Int -> [Reg]
+
+argRegs 0 = []
+#if alpha_TARGET_ARCH
+argRegs 1 = freeMappedRegs [16, fReg 16]
+argRegs 2 = freeMappedRegs [16, 17, fReg 16, fReg 17]
+argRegs 3 = freeMappedRegs [16, 17, 18, fReg 16, fReg 17, fReg 18]
+argRegs 4 = freeMappedRegs [16, 17, 18, 19, fReg 16, fReg 17, fReg 18, fReg 19]
+argRegs 5 = freeMappedRegs [16, 17, 18, 19, 20, fReg 16, fReg 17, fReg 18, fReg 19, fReg 20]
+argRegs 6 = freeMappedRegs [16, 17, 18, 19, 20, 21, fReg 16, fReg 17, fReg 18, fReg 19, fReg 20, fReg 21]
+#endif {- alpha_TARGET_ARCH -}
+#if i386_TARGET_ARCH
+argRegs _ = panic "MachRegs.argRegs: doesn't work on I386"
+#endif {- i386_TARGET_ARCH -}
+#if sparc_TARGET_ARCH
+argRegs 1 = freeMappedRegs (map oReg [0])
+argRegs 2 = freeMappedRegs (map oReg [0,1])
+argRegs 3 = freeMappedRegs (map oReg [0,1,2])
+argRegs 4 = freeMappedRegs (map oReg [0,1,2,3])
+argRegs 5 = freeMappedRegs (map oReg [0,1,2,3,4])
+argRegs 6 = freeMappedRegs (map oReg [0,1,2,3,4,5])
+#endif {- sparc_TARGET_ARCH -}
+argRegs _ = panic "MachRegs.argRegs: don't know about >6 arguments!"
+
+-------------------------------
+
+#if alpha_TARGET_ARCH
+allArgRegs :: [(Reg, Reg)]
+
+allArgRegs = [(realReg i, realReg (fReg i)) | i <- [16..21]]
+#endif {- alpha_TARGET_ARCH -}
+
+#if sparc_TARGET_ARCH
+allArgRegs :: [Reg]
+
+allArgRegs = map realReg [oReg i | i <- [0..5]]
+#endif {- sparc_TARGET_ARCH -}
+
+-------------------------------
+freeMappedRegs :: [Int] -> [Reg]
+
+freeMappedRegs nums
+ = foldr free [] nums
+ where
+ free IBOX(i) acc
+ = if _IS_TRUE_(freeReg i) then (MappedReg i) : acc else acc
+\end{code}
+
+\begin{code}
+freeReg :: FAST_INT -> FAST_BOOL
+
+#if alpha_TARGET_ARCH
+freeReg ILIT(26) = _FALSE_ -- return address (ra)
+freeReg ILIT(28) = _FALSE_ -- reserved for the assembler (at)
+freeReg ILIT(29) = _FALSE_ -- global pointer (gp)
+freeReg ILIT(30) = _FALSE_ -- stack pointer (sp)
+freeReg ILIT(31) = _FALSE_ -- always zero (zero)
+freeReg ILIT(63) = _FALSE_ -- always zero (f31)
+#endif
+
+#if i386_TARGET_ARCH
+freeReg ILIT(esp) = _FALSE_ -- %esp is the C stack pointer
+#endif
+
+#if sparc_TARGET_ARCH
+freeReg ILIT(g0) = _FALSE_ -- %g0 is always 0.
+freeReg ILIT(g5) = _FALSE_ -- %g5 is reserved (ABI).
+freeReg ILIT(g6) = _FALSE_ -- %g6 is reserved (ABI).
+freeReg ILIT(g7) = _FALSE_ -- %g7 is reserved (ABI).
+freeReg ILIT(i6) = _FALSE_ -- %i6 is our frame pointer.
+freeReg ILIT(o6) = _FALSE_ -- %o6 is our stack pointer.
+#endif
+
+#ifdef REG_Base
+freeReg ILIT(REG_Base) = _FALSE_
+#endif
+#ifdef REG_StkO
+freeReg ILIT(REG_StkO) = _FALSE_
+#endif
+#ifdef REG_R1
+freeReg ILIT(REG_R1) = _FALSE_
+#endif
+#ifdef REG_R2
+freeReg ILIT(REG_R2) = _FALSE_
+#endif
+#ifdef REG_R3
+freeReg ILIT(REG_R3) = _FALSE_
+#endif
+#ifdef REG_R4
+freeReg ILIT(REG_R4) = _FALSE_
+#endif
+#ifdef REG_R5
+freeReg ILIT(REG_R5) = _FALSE_
+#endif
+#ifdef REG_R6
+freeReg ILIT(REG_R6) = _FALSE_
+#endif
+#ifdef REG_R7
+freeReg ILIT(REG_R7) = _FALSE_
+#endif
+#ifdef REG_R8
+freeReg ILIT(REG_R8) = _FALSE_
+#endif
+#ifdef REG_Flt1
+freeReg ILIT(REG_Flt1) = _FALSE_
+#endif
+#ifdef REG_Flt2
+freeReg ILIT(REG_Flt2) = _FALSE_
+#endif
+#ifdef REG_Flt3
+freeReg ILIT(REG_Flt3) = _FALSE_
+#endif
+#ifdef REG_Flt4
+freeReg ILIT(REG_Flt4) = _FALSE_
+#endif
+#ifdef REG_Dbl1
+freeReg ILIT(REG_Dbl1) = _FALSE_
+#endif
+#ifdef REG_Dbl2
+freeReg ILIT(REG_Dbl2) = _FALSE_
+#endif
+#ifdef REG_Tag
+freeReg ILIT(REG_Tag) = _FALSE_
+#endif
+#ifdef REG_Ret
+freeReg ILIT(REG_Ret) = _FALSE_
+#endif
+#ifdef REG_SpA
+freeReg ILIT(REG_SpA) = _FALSE_
+#endif
+#ifdef REG_SuA
+freeReg ILIT(REG_SuA) = _FALSE_
+#endif
+#ifdef REG_SpB
+freeReg ILIT(REG_SpB) = _FALSE_
+#endif
+#ifdef REG_SuB
+freeReg ILIT(REG_SuB) = _FALSE_
+#endif
+#ifdef REG_Hp
+freeReg ILIT(REG_Hp) = _FALSE_
+#endif
+#ifdef REG_HpLim
+freeReg ILIT(REG_HpLim) = _FALSE_
+#endif
+#ifdef REG_Liveness
+freeReg ILIT(REG_Liveness) = _FALSE_
+#endif
+#ifdef REG_StdUpdRetVec
+freeReg ILIT(REG_StdUpdRetVec) = _FALSE_
+#endif
+#ifdef REG_StkStub
+freeReg ILIT(REG_StkStub) = _FALSE_
+#endif
+freeReg _ = _TRUE_
+freeReg n
+ -- we hang onto two double regs for dedicated
+ -- use; this is not necessary on Alphas and
+ -- may not be on other non-SPARCs.
+#ifdef REG_Dbl1
+ | n _EQ_ (ILIT(REG_Dbl1) _ADD_ ILIT(1)) = _FALSE_
+#endif
+#ifdef REG_Dbl2
+ | n _EQ_ (ILIT(REG_Dbl2) _ADD_ ILIT(1)) = _FALSE_
+#endif
+ | otherwise = _TRUE_
+\end{code}
--- /dev/null
+#ifndef NCG_H
+#define NCG_H
+
+#if 0
+
+IMPORTANT! If you put extra tabs/spaces in these macro definitions,
+you will screw up the layout where they are used in case expressions!
+
+(This is cpp-dependent, of course)
+
+** Convenience macros for writing the native-code generator **
+
+#endif
+
+#define FAST_REG_NO FAST_INT
+
+#include "../../includes/platform.h"
+
+#if 0
+{-testing only-}
+#undef sparc_TARGET_ARCH
+#undef sunos4_TARGET_OS
+#undef i386_TARGET_ARCH
+#define i386_TARGET_ARCH 1
+#undef linuxaout_TARGET_OS
+#define linuxaout_TARGET_OS 1
+#endif
+#if 0
+{-testing only-}
+#undef sparc_TARGET_ARCH
+#undef sunos4_TARGET_OS
+#undef alpha_TARGET_ARCH
+#define alpha_TARGET_ARCH 1
+#endif
+
+#if i386_TARGET_ARCH
+# define STOLEN_X86_REGS 4
+-- HACK: go for the max
+#endif
+#include "../../includes/MachRegs.h"
+
+#if alpha_TARGET_ARCH
+# define BYTES_PER_WORD 8
+# define BYTES_PER_WORD_STR "8"
+
+# include "../../includes/alpha-dec-osf1.h"
+#endif
+
+#if i386_TARGET_ARCH
+# define BYTES_PER_WORD 4
+# define BYTES_PER_WORD_STR "4"
+
+# if linuxaout_TARGET_OS
+# include "../../includes/i386-unknown-linuxaout.h"
+# endif
+# if linux_TARGET_OS
+# include "../../includes/i386-unknown-linux.h"
+# endif
+# if freebsd_TARGET_OS
+# include "../../includes/i386-unknown-freebsd.h"
+# endif
+# if netbsd_TARGET_OS
+# include "../../includes/i386-unknown-netbsd.h"
+# endif
+# if bsdi_TARGET_OS
+# include "../../includes/i386-unknown-bsdi.h"
+# endif
+# if solaris2_TARGET_OS
+# include "../../includes/i386-unknown-solaris2.h"
+# endif
+#endif
+
+#if sparc_TARGET_ARCH
+# define BYTES_PER_WORD 4
+# define BYTES_PER_WORD_STR "4"
+
+# if sunos4_TARGET_OS
+# include "../../includes/sparc-sun-sunos4.h"
+# endif
+# if solaris2_TARGET_OS
+# include "../../includes/sparc-sun-solaris2.h"
+# endif
+#endif
+
+---------------------------------------------
+
+#if alpha_TARGET_ARCH
+# define IF_ARCH_alpha(x,y) x
+#else
+# define IF_ARCH_alpha(x,y) y
+#endif
+
+---------------------------------------------
+
+#if i386_TARGET_ARCH
+# define IF_ARCH_i386(x,y) x
+#else
+# define IF_ARCH_i386(x,y) y
+#endif
+-- - - - - - - - - - - - - - - - - - - - - -
+#if freebsd_TARGET_OS
+# define IF_OS_freebsd(x,y) x
+#else
+# define IF_OS_freebsd(x,y) y
+#endif
+-- - - - - - - - - - - - - - - - - - - - - -
+#if netbsd_TARGET_OS
+# define IF_OS_netbsd(x,y) x
+#else
+# define IF_OS_netbsd(x,y) y
+#endif
+-- - - - - - - - - - - - - - - - - - - - - -
+#if linux_TARGET_OS
+# define IF_OS_linux(x,y) x
+#else
+# define IF_OS_linux(x,y) y
+#endif
+-- - - - - - - - - - - - - - - - - - - - - -
+#if linuxaout_TARGET_OS
+# define IF_OS_linuxaout(x,y) x
+#else
+# define IF_OS_linuxaout(x,y) y
+#endif
+-- - - - - - - - - - - - - - - - - - - - - -
+#if bsdi_TARGET_OS
+# define IF_OS_bsdi(x,y) x
+#else
+# define IF_OS_bsdi(x,y) y
+#endif
+---------------------------------------------
+#if sparc_TARGET_ARCH
+# define IF_ARCH_sparc(x,y) x
+#else
+# define IF_ARCH_sparc(x,y) y
+#endif
+-- - - - - - - - - - - - - - - - - - - - - -
+#if sunos4_TARGET_OS
+# define IF_OS_sunos4(x,y) x
+#else
+# define IF_OS_sunos4(x,y) y
+#endif
+-- - - - - - - - - - - - - - - - - - - - - -
+-- NB: this will catch i386-*-solaris2, too
+#if solaris2_TARGET_OS
+# define IF_OS_solaris2(x,y) x
+#else
+# define IF_OS_solaris2(x,y) y
+#endif
+---------------------------------------------
+#endif
--- /dev/null
+Breaks loops between Stix{Macro,Prim,Integer}.lhs.
+
+Also some CLabel dependencies on MachMisc.
+
+\begin{code}
+interface NcgLoop where
+
+import AbsCSyn ( CAddrMode )
+import Stix ( StixTree )
+import MachMisc ( underscorePrefix, fmtAsmLbl )
+import StixPrim ( amodeToStix )
+
+amodeToStix :: CAddrMode -> StixTree
+underscorePrefix :: Bool
+fmtAsmLbl :: [Char] -> [Char]
+\end{code}
--- /dev/null
+%
+% (c) The AQUA Project, Glasgow University, 1996
+%
+\section[PprMach]{Pretty-printing assembly language}
+
+We start with the @pprXXX@s with some cross-platform commonality
+(e.g., @pprReg@); we conclude with the no-commonality monster,
+@pprInstr@.
+
+\begin{code}
+#include "HsVersions.h"
+#include "nativeGen/NCG.h"
+
+module PprMach ( pprInstr ) where
+
+import Ubiq{-uitious-}
+
+import MachRegs -- may differ per-platform
+import MachMisc
+
+import CLabel ( pprCLabel_asm, externallyVisibleCLabel )
+import CStrings ( charToC )
+import Maybes ( maybeToBool )
+import OrdList ( OrdList )
+import Stix ( CodeSegment(..), StixTree )
+import Unpretty -- all of it
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{@pprReg@: print a @Reg@}
+%* *
+%************************************************************************
+
+For x86, the way we print a register name depends
+on which bit of it we care about. Yurgh.
+\begin{code}
+pprReg :: IF_ARCH_i386(Size ->,) Reg -> Unpretty
+
+pprReg IF_ARCH_i386(s,) r
+ = case r of
+ FixedReg i -> ppr_reg_no IF_ARCH_i386(s,) i
+ MappedReg i -> ppr_reg_no IF_ARCH_i386(s,) i
+ other -> uppStr (show other) -- should only happen when debugging
+ where
+#if alpha_TARGET_ARCH
+ ppr_reg_no :: FAST_REG_NO -> Unpretty
+ ppr_reg_no i = uppPStr
+ (case i of {
+ ILIT( 0) -> SLIT("$0"); ILIT( 1) -> SLIT("$1");
+ ILIT( 2) -> SLIT("$2"); ILIT( 3) -> SLIT("$3");
+ ILIT( 4) -> SLIT("$4"); ILIT( 5) -> SLIT("$5");
+ ILIT( 6) -> SLIT("$6"); ILIT( 7) -> SLIT("$7");
+ ILIT( 8) -> SLIT("$8"); ILIT( 9) -> SLIT("$9");
+ ILIT(10) -> SLIT("$10"); ILIT(11) -> SLIT("$11");
+ ILIT(12) -> SLIT("$12"); ILIT(13) -> SLIT("$13");
+ ILIT(14) -> SLIT("$14"); ILIT(15) -> SLIT("$15");
+ ILIT(16) -> SLIT("$16"); ILIT(17) -> SLIT("$17");
+ ILIT(18) -> SLIT("$18"); ILIT(19) -> SLIT("$19");
+ ILIT(20) -> SLIT("$20"); ILIT(21) -> SLIT("$21");
+ ILIT(22) -> SLIT("$22"); ILIT(23) -> SLIT("$23");
+ ILIT(24) -> SLIT("$24"); ILIT(25) -> SLIT("$25");
+ ILIT(26) -> SLIT("$26"); ILIT(27) -> SLIT("$27");
+ ILIT(28) -> SLIT("$28"); ILIT(29) -> SLIT("$29");
+ ILIT(30) -> SLIT("$30"); ILIT(31) -> SLIT("$31");
+ ILIT(32) -> SLIT("$f0"); ILIT(33) -> SLIT("$f1");
+ ILIT(34) -> SLIT("$f2"); ILIT(35) -> SLIT("$f3");
+ ILIT(36) -> SLIT("$f4"); ILIT(37) -> SLIT("$f5");
+ ILIT(38) -> SLIT("$f6"); ILIT(39) -> SLIT("$f7");
+ ILIT(40) -> SLIT("$f8"); ILIT(41) -> SLIT("$f9");
+ ILIT(42) -> SLIT("$f10"); ILIT(43) -> SLIT("$f11");
+ ILIT(44) -> SLIT("$f12"); ILIT(45) -> SLIT("$f13");
+ ILIT(46) -> SLIT("$f14"); ILIT(47) -> SLIT("$f15");
+ ILIT(48) -> SLIT("$f16"); ILIT(49) -> SLIT("$f17");
+ ILIT(50) -> SLIT("$f18"); ILIT(51) -> SLIT("$f19");
+ ILIT(52) -> SLIT("$f20"); ILIT(53) -> SLIT("$f21");
+ ILIT(54) -> SLIT("$f22"); ILIT(55) -> SLIT("$f23");
+ ILIT(56) -> SLIT("$f24"); ILIT(57) -> SLIT("$f25");
+ ILIT(58) -> SLIT("$f26"); ILIT(59) -> SLIT("$f27");
+ ILIT(60) -> SLIT("$f28"); ILIT(61) -> SLIT("$f29");
+ ILIT(62) -> SLIT("$f30"); ILIT(63) -> SLIT("$f31");
+ _ -> SLIT("very naughty alpha register")
+ })
+#endif
+#if i386_TARGET_ARCH
+ ppr_reg_no :: Size -> FAST_REG_NO -> Unpretty
+ ppr_reg_no B i = uppPStr
+ (case i of {
+ ILIT( 0) -> SLIT("%al"); ILIT( 1) -> SLIT("%bl");
+ ILIT( 2) -> SLIT("%cl"); ILIT( 3) -> SLIT("%dl");
+ _ -> SLIT("very naughty I386 byte register")
+ })
+
+ {- UNUSED:
+ ppr_reg_no HB i = uppPStr
+ (case i of {
+ ILIT( 0) -> SLIT("%ah"); ILIT( 1) -> SLIT("%bh");
+ ILIT( 2) -> SLIT("%ch"); ILIT( 3) -> SLIT("%dh");
+ _ -> SLIT("very naughty I386 high byte register")
+ })
+ -}
+
+{- UNUSED:
+ ppr_reg_no S i = uppPStr
+ (case i of {
+ ILIT( 0) -> SLIT("%ax"); ILIT( 1) -> SLIT("%bx");
+ ILIT( 2) -> SLIT("%cx"); ILIT( 3) -> SLIT("%dx");
+ ILIT( 4) -> SLIT("%si"); ILIT( 5) -> SLIT("%di");
+ ILIT( 6) -> SLIT("%bp"); ILIT( 7) -> SLIT("%sp");
+ _ -> SLIT("very naughty I386 word register")
+ })
+-}
+
+ ppr_reg_no L i = uppPStr
+ (case i of {
+ ILIT( 0) -> SLIT("%eax"); ILIT( 1) -> SLIT("%ebx");
+ ILIT( 2) -> SLIT("%ecx"); ILIT( 3) -> SLIT("%edx");
+ ILIT( 4) -> SLIT("%esi"); ILIT( 5) -> SLIT("%edi");
+ ILIT( 6) -> SLIT("%ebp"); ILIT( 7) -> SLIT("%esp");
+ _ -> SLIT("very naughty I386 double word register")
+ })
+
+ ppr_reg_no F i = uppPStr
+ (case i of {
+ --ToDo: rm these (???)
+ ILIT( 8) -> SLIT("%st(0)"); ILIT( 9) -> SLIT("%st(1)");
+ ILIT(10) -> SLIT("%st(2)"); ILIT(11) -> SLIT("%st(3)");
+ ILIT(12) -> SLIT("%st(4)"); ILIT(13) -> SLIT("%st(5)");
+ ILIT(14) -> SLIT("%st(6)"); ILIT(15) -> SLIT("%st(7)");
+ _ -> SLIT("very naughty I386 float register")
+ })
+
+ ppr_reg_no DF i = uppPStr
+ (case i of {
+ --ToDo: rm these (???)
+ ILIT( 8) -> SLIT("%st(0)"); ILIT( 9) -> SLIT("%st(1)");
+ ILIT(10) -> SLIT("%st(2)"); ILIT(11) -> SLIT("%st(3)");
+ ILIT(12) -> SLIT("%st(4)"); ILIT(13) -> SLIT("%st(5)");
+ ILIT(14) -> SLIT("%st(6)"); ILIT(15) -> SLIT("%st(7)");
+ _ -> SLIT("very naughty I386 float register")
+ })
+#endif
+#if sparc_TARGET_ARCH
+ ppr_reg_no :: FAST_REG_NO -> Unpretty
+ ppr_reg_no i = uppPStr
+ (case i of {
+ ILIT( 0) -> SLIT("%g0"); ILIT( 1) -> SLIT("%g1");
+ ILIT( 2) -> SLIT("%g2"); ILIT( 3) -> SLIT("%g3");
+ ILIT( 4) -> SLIT("%g4"); ILIT( 5) -> SLIT("%g5");
+ ILIT( 6) -> SLIT("%g6"); ILIT( 7) -> SLIT("%g7");
+ ILIT( 8) -> SLIT("%o0"); ILIT( 9) -> SLIT("%o1");
+ ILIT(10) -> SLIT("%o2"); ILIT(11) -> SLIT("%o3");
+ ILIT(12) -> SLIT("%o4"); ILIT(13) -> SLIT("%o5");
+ ILIT(14) -> SLIT("%o6"); ILIT(15) -> SLIT("%o7");
+ ILIT(16) -> SLIT("%l0"); ILIT(17) -> SLIT("%l1");
+ ILIT(18) -> SLIT("%l2"); ILIT(19) -> SLIT("%l3");
+ ILIT(20) -> SLIT("%l4"); ILIT(21) -> SLIT("%l5");
+ ILIT(22) -> SLIT("%l6"); ILIT(23) -> SLIT("%l7");
+ ILIT(24) -> SLIT("%i0"); ILIT(25) -> SLIT("%i1");
+ ILIT(26) -> SLIT("%i2"); ILIT(27) -> SLIT("%i3");
+ ILIT(28) -> SLIT("%i4"); ILIT(29) -> SLIT("%i5");
+ ILIT(30) -> SLIT("%i6"); ILIT(31) -> SLIT("%i7");
+ ILIT(32) -> SLIT("%f0"); ILIT(33) -> SLIT("%f1");
+ ILIT(34) -> SLIT("%f2"); ILIT(35) -> SLIT("%f3");
+ ILIT(36) -> SLIT("%f4"); ILIT(37) -> SLIT("%f5");
+ ILIT(38) -> SLIT("%f6"); ILIT(39) -> SLIT("%f7");
+ ILIT(40) -> SLIT("%f8"); ILIT(41) -> SLIT("%f9");
+ ILIT(42) -> SLIT("%f10"); ILIT(43) -> SLIT("%f11");
+ ILIT(44) -> SLIT("%f12"); ILIT(45) -> SLIT("%f13");
+ ILIT(46) -> SLIT("%f14"); ILIT(47) -> SLIT("%f15");
+ ILIT(48) -> SLIT("%f16"); ILIT(49) -> SLIT("%f17");
+ ILIT(50) -> SLIT("%f18"); ILIT(51) -> SLIT("%f19");
+ ILIT(52) -> SLIT("%f20"); ILIT(53) -> SLIT("%f21");
+ ILIT(54) -> SLIT("%f22"); ILIT(55) -> SLIT("%f23");
+ ILIT(56) -> SLIT("%f24"); ILIT(57) -> SLIT("%f25");
+ ILIT(58) -> SLIT("%f26"); ILIT(59) -> SLIT("%f27");
+ ILIT(60) -> SLIT("%f28"); ILIT(61) -> SLIT("%f29");
+ ILIT(62) -> SLIT("%f30"); ILIT(63) -> SLIT("%f31");
+ _ -> SLIT("very naughty sparc register")
+ })
+#endif
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{@pprSize@: print a @Size@}
+%* *
+%************************************************************************
+
+\begin{code}
+pprSize :: Size -> Unpretty
+
+pprSize x = uppPStr (case x of
+#if alpha_TARGET_ARCH
+ B -> SLIT("b")
+ BU -> SLIT("bu")
+-- W -> SLIT("w") UNUSED
+-- WU -> SLIT("wu") UNUSED
+-- L -> SLIT("l") UNUSED
+ Q -> SLIT("q")
+-- FF -> SLIT("f") UNUSED
+-- DF -> SLIT("d") UNUSED
+-- GF -> SLIT("g") UNUSED
+-- SF -> SLIT("s") UNUSED
+ TF -> SLIT("t")
+#endif
+#if i386_TARGET_ARCH
+ B -> SLIT("b")
+-- HB -> SLIT("b") UNUSED
+-- S -> SLIT("w") UNUSED
+ L -> SLIT("l")
+ F -> SLIT("s")
+ DF -> SLIT("l")
+#endif
+#if sparc_TARGET_ARCH
+ B -> SLIT("sb")
+-- HW -> SLIT("hw") UNUSED
+-- BU -> SLIT("ub") UNUSED
+-- HWU -> SLIT("uhw") UNUSED
+ W -> SLIT("")
+ F -> SLIT("")
+-- D -> SLIT("d") UNUSED
+ DF -> SLIT("d")
+#endif
+ )
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{@pprCond@: print a @Cond@}
+%* *
+%************************************************************************
+
+\begin{code}
+pprCond :: Cond -> Unpretty
+
+pprCond c = uppPStr (case c of {
+#if alpha_TARGET_ARCH
+ EQ -> SLIT("eq");
+ LT -> SLIT("lt");
+ LE -> SLIT("le");
+ ULT -> SLIT("ult");
+ ULE -> SLIT("ule");
+ NE -> SLIT("ne");
+ GT -> SLIT("gt");
+ GE -> SLIT("ge")
+#endif
+#if i386_TARGET_ARCH
+ GEU -> SLIT("ae"); LU -> SLIT("b");
+ EQ -> SLIT("e"); GT -> SLIT("g");
+ GE -> SLIT("ge"); GU -> SLIT("a");
+ LT -> SLIT("l"); LE -> SLIT("le");
+ LEU -> SLIT("be"); NE -> SLIT("ne");
+ NEG -> SLIT("s"); POS -> SLIT("ns");
+ ALWAYS -> SLIT("mp") -- hack
+#endif
+#if sparc_TARGET_ARCH
+ ALWAYS -> SLIT(""); NEVER -> SLIT("n");
+ GEU -> SLIT("geu"); LU -> SLIT("lu");
+ EQ -> SLIT("e"); GT -> SLIT("g");
+ GE -> SLIT("ge"); GU -> SLIT("gu");
+ LT -> SLIT("l"); LE -> SLIT("le");
+ LEU -> SLIT("leu"); NE -> SLIT("ne");
+ NEG -> SLIT("neg"); POS -> SLIT("pos");
+ VC -> SLIT("vc"); VS -> SLIT("vs")
+#endif
+ })
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{@pprImm@: print an @Imm@}
+%* *
+%************************************************************************
+
+\begin{code}
+pprImm :: Imm -> Unpretty
+
+pprImm (ImmInt i) = uppInt i
+pprImm (ImmInteger i) = uppInteger i
+pprImm (ImmCLbl l) = pprCLabel_asm l
+pprImm (ImmLit s) = s
+
+pprImm (ImmLab s) | underscorePrefix = uppBeside (uppChar '_') s
+ | otherwise = s
+
+#if sparc_TARGET_ARCH
+pprImm (LO i)
+ = uppBesides [ pp_lo, pprImm i, uppRparen ]
+ where
+ pp_lo = uppPStr (_packCString (A# "%lo("#))
+
+pprImm (HI i)
+ = uppBesides [ pp_hi, pprImm i, uppRparen ]
+ where
+ pp_hi = uppPStr (_packCString (A# "%hi("#))
+#endif
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{@pprAddr@: print an @Addr@}
+%* *
+%************************************************************************
+
+\begin{code}
+pprAddr :: Addr -> Unpretty
+
+#if alpha_TARGET_ARCH
+pprAddr (AddrReg r) = uppParens (pprReg r)
+pprAddr (AddrImm i) = pprImm i
+pprAddr (AddrRegImm r1 i)
+ = uppBeside (pprImm i) (uppParens (pprReg r1))
+#endif
+
+-------------------
+
+#if i386_TARGET_ARCH
+pprAddr (ImmAddr imm off)
+ = let
+ pp_imm = pprImm imm
+ in
+ if (off == 0) then
+ pp_imm
+ else if (off < 0) then
+ uppBeside pp_imm (uppInt off)
+ else
+ uppBesides [pp_imm, uppChar '+', uppInt off]
+
+pprAddr (Addr base index displacement)
+ = let
+ pp_disp = ppr_disp displacement
+ pp_off p = uppBeside pp_disp (uppParens p)
+ pp_reg r = pprReg L r
+ in
+ case (base,index) of
+ (Nothing, Nothing) -> pp_disp
+ (Just b, Nothing) -> pp_off (pp_reg b)
+ (Nothing, Just (r,i)) -> pp_off (uppBesides [pp_reg r, uppComma, uppInt i])
+ (Just b, Just (r,i)) -> pp_off (uppBesides [pp_reg b, uppComma, pp_reg r, uppComma, uppInt i])
+ where
+ ppr_disp (ImmInt 0) = uppNil
+ ppr_disp imm = pprImm imm
+#endif
+
+-------------------
+
+#if sparc_TARGET_ARCH
+pprAddr (AddrRegReg r1 (FixedReg ILIT(0))) = pprReg r1
+
+pprAddr (AddrRegReg r1 r2)
+ = uppBesides [ pprReg r1, uppChar '+', pprReg r2 ]
+
+pprAddr (AddrRegImm r1 (ImmInt i))
+ | i == 0 = pprReg r1
+ | not (fits13Bits i) = largeOffsetError i
+ | otherwise = uppBesides [ pprReg r1, pp_sign, uppInt i ]
+ where
+ pp_sign = if i > 0 then uppChar '+' else uppNil
+
+pprAddr (AddrRegImm r1 (ImmInteger i))
+ | i == 0 = pprReg r1
+ | not (fits13Bits i) = largeOffsetError i
+ | otherwise = uppBesides [ pprReg r1, pp_sign, uppInteger i ]
+ where
+ pp_sign = if i > 0 then uppChar '+' else uppNil
+
+pprAddr (AddrRegImm r1 imm)
+ = uppBesides [ pprReg r1, uppChar '+', pprImm imm ]
+#endif
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{@pprInstr@: print an @Instr@}
+%* *
+%************************************************************************
+
+\begin{code}
+pprInstr :: Instr -> Unpretty
+
+pprInstr (COMMENT s) = uppBeside (uppPStr SLIT("\t# ")) (uppPStr s)
+
+pprInstr (SEGMENT TextSegment)
+ = uppPStr
+ IF_ARCH_alpha(SLIT("\t.text\n\t.align 3") {-word boundary-}
+ ,IF_ARCH_sparc(SLIT("\t.text\n\t.align 4") {-word boundary-}
+ ,IF_ARCH_i386(SLIT(".text\n\t.align 2,0x90") {-needs per-OS variation!-}
+ ,)))
+
+pprInstr (SEGMENT DataSegment)
+ = uppPStr
+ IF_ARCH_alpha(SLIT("\t.data\n\t.align 3")
+ ,IF_ARCH_sparc(SLIT("\t.data\n\t.align 8") {-<8 will break double constants -}
+ ,IF_ARCH_i386(SLIT(".data\n\t.align 2")
+ ,)))
+
+pprInstr (LABEL clab)
+ = let
+ pp_lab = pprCLabel_asm clab
+ in
+ uppBesides [
+ if not (externallyVisibleCLabel clab) then
+ uppNil
+ else
+ uppBesides [uppPStr
+ IF_ARCH_alpha(SLIT("\t.globl\t")
+ ,IF_ARCH_i386(SLIT(".globl ")
+ ,IF_ARCH_sparc(SLIT("\t.global\t")
+ ,)))
+ , pp_lab, uppChar '\n'],
+ pp_lab,
+ uppChar ':'
+ ]
+
+pprInstr (ASCII False{-no backslash conversion-} str)
+ = uppBesides [ uppStr "\t.asciz \"", uppStr str, uppChar '"' ]
+
+pprInstr (ASCII True str)
+ = uppBeside (uppStr "\t.ascii \"") (asciify str 60)
+ where
+ asciify :: String -> Int -> Unpretty
+
+ asciify [] _ = uppStr ("\\0\"")
+ asciify s n | n <= 0 = uppBeside (uppStr "\"\n\t.ascii \"") (asciify s 60)
+ asciify ('\\':cs) n = uppBeside (uppStr "\\\\") (asciify cs (n-1))
+ asciify ('\"':cs) n = uppBeside (uppStr "\\\"") (asciify cs (n-1))
+ asciify (c:cs) n | isPrint c = uppBeside (uppChar c) (asciify cs (n-1))
+ asciify [c] _ = uppBeside (uppStr (charToC c)) (uppStr ("\\0\""))
+ asciify (c:(cs@(d:_))) n
+ | isDigit d = uppBeside (uppStr (charToC c)) (asciify cs 0)
+ | otherwise = uppBeside (uppStr (charToC c)) (asciify cs (n-1))
+
+pprInstr (DATA s xs)
+ = uppInterleave (uppChar '\n')
+ [uppBeside (uppPStr pp_size) (pprImm x) | x <- xs]
+ where
+ pp_size = case s of
+#if alpha_TARGET_ARCH
+ B -> SLIT("\t.byte\t")
+ BU -> SLIT("\t.byte\t")
+--UNUSED: W -> SLIT("\t.word\t")
+--UNUSED: WU -> SLIT("\t.word\t")
+--UNUSED: L -> SLIT("\t.long\t")
+ Q -> SLIT("\t.quad\t")
+--UNUSED: FF -> SLIT("\t.f_floating\t")
+--UNUSED: DF -> SLIT("\t.d_floating\t")
+--UNUSED: GF -> SLIT("\t.g_floating\t")
+--UNUSED: SF -> SLIT("\t.s_floating\t")
+ TF -> SLIT("\t.t_floating\t")
+#endif
+#if i386_TARGET_ARCH
+ B -> SLIT("\t.byte\t")
+--UNUSED: HB -> SLIT("\t.byte\t")
+--UNUSED: S -> SLIT("\t.word\t")
+ L -> SLIT("\t.long\t")
+ F -> SLIT("\t.long\t")
+ DF -> SLIT("\t.double\t")
+#endif
+#if sparc_TARGET_ARCH
+ B -> SLIT("\t.byte\t")
+ BU -> SLIT("\t.byte\t")
+ W -> SLIT("\t.word\t")
+ DF -> SLIT("\t.double\t")
+#endif
+
+-- fall through to rest of (machine-specific) pprInstr...
+\end{code}
+
+%************************************************************************
+%* *
+\subsubsection{@pprInstr@ for an Alpha}
+%* *
+%************************************************************************
+
+\begin{code}
+#if alpha_TARGET_ARCH
+
+pprInstr (LD size reg addr)
+ = uppBesides [
+ uppPStr SLIT("\tld"),
+ pprSize size,
+ uppChar '\t',
+ pprReg reg,
+ uppComma,
+ pprAddr addr
+ ]
+
+pprInstr (LDA reg addr)
+ = uppBesides [
+ uppPStr SLIT("\tlda\t"),
+ pprReg reg,
+ uppComma,
+ pprAddr addr
+ ]
+
+pprInstr (LDAH reg addr)
+ = uppBesides [
+ uppPStr SLIT("\tldah\t"),
+ pprReg reg,
+ uppComma,
+ pprAddr addr
+ ]
+
+pprInstr (LDGP reg addr)
+ = uppBesides [
+ uppPStr SLIT("\tldgp\t"),
+ pprReg reg,
+ uppComma,
+ pprAddr addr
+ ]
+
+pprInstr (LDI size reg imm)
+ = uppBesides [
+ uppPStr SLIT("\tldi"),
+ pprSize size,
+ uppChar '\t',
+ pprReg reg,
+ uppComma,
+ pprImm imm
+ ]
+
+pprInstr (ST size reg addr)
+ = uppBesides [
+ uppPStr SLIT("\tst"),
+ pprSize size,
+ uppChar '\t',
+ pprReg reg,
+ uppComma,
+ pprAddr addr
+ ]
+
+pprInstr (CLR reg)
+ = uppBesides [
+ uppPStr SLIT("\tclr\t"),
+ pprReg reg
+ ]
+
+pprInstr (ABS size ri reg)
+ = uppBesides [
+ uppPStr SLIT("\tabs"),
+ pprSize size,
+ uppChar '\t',
+ pprRI ri,
+ uppComma,
+ pprReg reg
+ ]
+
+pprInstr (NEG size ov ri reg)
+ = uppBesides [
+ uppPStr SLIT("\tneg"),
+ pprSize size,
+ if ov then uppPStr SLIT("v\t") else uppChar '\t',
+ pprRI ri,
+ uppComma,
+ pprReg reg
+ ]
+
+pprInstr (ADD size ov reg1 ri reg2)
+ = uppBesides [
+ uppPStr SLIT("\tadd"),
+ pprSize size,
+ if ov then uppPStr SLIT("v\t") else uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprRI ri,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (SADD size scale reg1 ri reg2)
+ = uppBesides [
+ uppPStr (case scale of {{-UNUSED:L -> SLIT("\ts4");-} Q -> SLIT("\ts8")}),
+ uppPStr SLIT("add"),
+ pprSize size,
+ uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprRI ri,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (SUB size ov reg1 ri reg2)
+ = uppBesides [
+ uppPStr SLIT("\tsub"),
+ pprSize size,
+ if ov then uppPStr SLIT("v\t") else uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprRI ri,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (SSUB size scale reg1 ri reg2)
+ = uppBesides [
+ uppPStr (case scale of {{-UNUSED:L -> SLIT("\ts4");-} Q -> SLIT("\ts8")}),
+ uppPStr SLIT("sub"),
+ pprSize size,
+ uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprRI ri,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (MUL size ov reg1 ri reg2)
+ = uppBesides [
+ uppPStr SLIT("\tmul"),
+ pprSize size,
+ if ov then uppPStr SLIT("v\t") else uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprRI ri,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (DIV size uns reg1 ri reg2)
+ = uppBesides [
+ uppPStr SLIT("\tdiv"),
+ pprSize size,
+ if uns then uppPStr SLIT("u\t") else uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprRI ri,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (REM size uns reg1 ri reg2)
+ = uppBesides [
+ uppPStr SLIT("\trem"),
+ pprSize size,
+ if uns then uppPStr SLIT("u\t") else uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprRI ri,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (NOT ri reg)
+ = uppBesides [
+ uppPStr SLIT("\tnot"),
+ uppChar '\t',
+ pprRI ri,
+ uppComma,
+ pprReg reg
+ ]
+
+pprInstr (AND reg1 ri reg2) = pprRegRIReg SLIT("and") reg1 ri reg2
+pprInstr (ANDNOT reg1 ri reg2) = pprRegRIReg SLIT("andnot") reg1 ri reg2
+pprInstr (OR reg1 ri reg2) = pprRegRIReg SLIT("or") reg1 ri reg2
+pprInstr (ORNOT reg1 ri reg2) = pprRegRIReg SLIT("ornot") reg1 ri reg2
+pprInstr (XOR reg1 ri reg2) = pprRegRIReg SLIT("xor") reg1 ri reg2
+pprInstr (XORNOT reg1 ri reg2) = pprRegRIReg SLIT("xornot") reg1 ri reg2
+
+pprInstr (SLL reg1 ri reg2) = pprRegRIReg SLIT("sll") reg1 ri reg2
+pprInstr (SRL reg1 ri reg2) = pprRegRIReg SLIT("srl") reg1 ri reg2
+pprInstr (SRA reg1 ri reg2) = pprRegRIReg SLIT("sra") reg1 ri reg2
+
+pprInstr (ZAP reg1 ri reg2) = pprRegRIReg SLIT("zap") reg1 ri reg2
+pprInstr (ZAPNOT reg1 ri reg2) = pprRegRIReg SLIT("zapnot") reg1 ri reg2
+
+pprInstr (NOP) = uppPStr SLIT("\tnop")
+
+pprInstr (CMP cond reg1 ri reg2)
+ = uppBesides [
+ uppPStr SLIT("\tcmp"),
+ pprCond cond,
+ uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprRI ri,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (FCLR reg)
+ = uppBesides [
+ uppPStr SLIT("\tfclr\t"),
+ pprReg reg
+ ]
+
+pprInstr (FABS reg1 reg2)
+ = uppBesides [
+ uppPStr SLIT("\tfabs\t"),
+ pprReg reg1,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (FNEG size reg1 reg2)
+ = uppBesides [
+ uppPStr SLIT("\tneg"),
+ pprSize size,
+ uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (FADD size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("add") size reg1 reg2 reg3
+pprInstr (FDIV size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("div") size reg1 reg2 reg3
+pprInstr (FMUL size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("mul") size reg1 reg2 reg3
+pprInstr (FSUB size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("sub") size reg1 reg2 reg3
+
+pprInstr (CVTxy size1 size2 reg1 reg2)
+ = uppBesides [
+ uppPStr SLIT("\tcvt"),
+ pprSize size1,
+ case size2 of {Q -> uppPStr SLIT("qc"); _ -> pprSize size2},
+ uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (FCMP size cond reg1 reg2 reg3)
+ = uppBesides [
+ uppPStr SLIT("\tcmp"),
+ pprSize size,
+ pprCond cond,
+ uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprReg reg2,
+ uppComma,
+ pprReg reg3
+ ]
+
+pprInstr (FMOV reg1 reg2)
+ = uppBesides [
+ uppPStr SLIT("\tfmov\t"),
+ pprReg reg1,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprInstr (BI ALWAYS reg lab) = pprInstr (BR lab)
+
+pprInstr (BI NEVER reg lab) = uppNil
+
+pprInstr (BI cond reg lab)
+ = uppBesides [
+ uppPStr SLIT("\tb"),
+ pprCond cond,
+ uppChar '\t',
+ pprReg reg,
+ uppComma,
+ pprImm lab
+ ]
+
+pprInstr (BF cond reg lab)
+ = uppBesides [
+ uppPStr SLIT("\tfb"),
+ pprCond cond,
+ uppChar '\t',
+ pprReg reg,
+ uppComma,
+ pprImm lab
+ ]
+
+pprInstr (BR lab)
+ = uppBeside (uppPStr SLIT("\tbr\t")) (pprImm lab)
+
+pprInstr (JMP reg addr hint)
+ = uppBesides [
+ uppPStr SLIT("\tjmp\t"),
+ pprReg reg,
+ uppComma,
+ pprAddr addr,
+ uppComma,
+ uppInt hint
+ ]
+
+pprInstr (BSR imm n)
+ = uppBeside (uppPStr SLIT("\tbsr\t")) (pprImm imm)
+
+pprInstr (JSR reg addr n)
+ = uppBesides [
+ uppPStr SLIT("\tjsr\t"),
+ pprReg reg,
+ uppComma,
+ pprAddr addr
+ ]
+
+pprInstr (FUNBEGIN clab)
+ = uppBesides [
+ if (externallyVisibleCLabel clab) then
+ uppBesides [uppPStr SLIT("\t.globl\t"), pp_lab, uppChar '\n']
+ else
+ uppNil,
+ uppPStr SLIT("\t.ent "),
+ pp_lab,
+ uppChar '\n',
+ pp_lab,
+ pp_ldgp,
+ pp_lab,
+ pp_frame
+ ]
+ where
+ pp_lab = pprCLabel_asm clab
+ pp_ldgp = uppPStr (_packCString (A# ":\n\tldgp $29,0($27)\n"#))
+ pp_frame = uppPStr (_packCString (A# "..ng:\n\t.frame $30,4240,$26,0\n\t.prologue 1"#))
+
+pprInstr (FUNEND clab)
+ = uppBeside (uppPStr SLIT("\t.align 4\n\t.end ")) (pprCLabel_asm clab)
+\end{code}
+
+Continue with Alpha-only printing bits and bobs:
+\begin{code}
+pprRI :: RI -> Unpretty
+
+pprRI (RIReg r) = pprReg r
+pprRI (RIImm r) = pprImm r
+
+pprRegRIReg :: FAST_STRING -> Reg -> RI -> Reg -> Unpretty
+
+pprRegRIReg name reg1 ri reg2
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprRI ri,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprSizeRegRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Reg -> Unpretty
+
+pprSizeRegRegReg name size reg1 reg2 reg3
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ pprSize size,
+ uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprReg reg2,
+ uppComma,
+ pprReg reg3
+ ]
+
+#endif {-alpha_TARGET_ARCH-}
+\end{code}
+
+%************************************************************************
+%* *
+\subsubsection{@pprInstr@ for an I386}
+%* *
+%************************************************************************
+
+\begin{code}
+#if i386_TARGET_ARCH
+
+pprInstr (MOV size (OpReg src) (OpReg dst)) -- hack
+ | src == dst
+ = uppPStr SLIT("")
+pprInstr (MOV size src dst)
+ = pprSizeOpOp SLIT("mov") size src dst
+pprInstr (MOVZX size src dst) = pprSizeOpOpCoerce SLIT("movzx") L size src dst
+pprInstr (MOVSX size src dst) = pprSizeOpOpCoerce SLIT("movxs") L size src dst
+
+-- here we do some patching, since the physical registers are only set late
+-- in the code generation.
+pprInstr (LEA size (OpAddr (Addr src1@(Just reg1) (Just (reg2,1)) (ImmInt 0))) dst@(OpReg reg3))
+ | reg1 == reg3
+ = pprSizeOpOp SLIT("add") size (OpReg reg2) dst
+pprInstr (LEA size (OpAddr (Addr src1@(Just reg1) (Just (reg2,1)) (ImmInt 0))) dst@(OpReg reg3))
+ | reg2 == reg3
+ = pprSizeOpOp SLIT("add") size (OpReg reg1) dst
+pprInstr (LEA size (OpAddr (Addr src1@(Just reg1) Nothing displ)) dst@(OpReg reg3))
+ | reg1 == reg3
+ = pprInstr (ADD size (OpImm displ) dst)
+pprInstr (LEA size src dst) = pprSizeOpOp SLIT("lea") size src dst
+
+pprInstr (ADD size (OpImm (ImmInt (-1))) dst)
+ = pprSizeOp SLIT("dec") size dst
+pprInstr (ADD size (OpImm (ImmInt 1)) dst)
+ = pprSizeOp SLIT("inc") size dst
+pprInstr (ADD size src dst)
+ = pprSizeOpOp SLIT("add") size src dst
+pprInstr (SUB size src dst) = pprSizeOpOp SLIT("sub") size src dst
+pprInstr (IMUL size op1 op2) = pprSizeOpOp SLIT("imul") size op1 op2
+pprInstr (IDIV size op) = pprSizeOp SLIT("idiv") size op
+
+pprInstr (AND size src dst) = pprSizeOpOp SLIT("and") size src dst
+pprInstr (OR size src dst) = pprSizeOpOp SLIT("or") size src dst
+pprInstr (XOR size src dst) = pprSizeOpOp SLIT("xor") size src dst
+pprInstr (NOT size op) = pprSizeOp SLIT("not") size op
+pprInstr (NEGI size op) = pprSizeOp SLIT("neg") size op
+pprInstr (SHL size imm dst) = pprSizeOpOp SLIT("shl") size imm dst
+pprInstr (SAR size imm dst) = pprSizeOpOp SLIT("sar") size imm dst
+pprInstr (SHR size imm dst) = pprSizeOpOp SLIT("shr") size imm dst
+
+pprInstr (CMP size src dst) = pprSizeOpOp SLIT("cmp") size src dst
+pprInstr (TEST size src dst) = pprSizeOpOp SLIT("test") size src dst
+pprInstr (PUSH size op) = pprSizeOp SLIT("push") size op
+pprInstr (POP size op) = pprSizeOp SLIT("pop") size op
+
+pprInstr (NOP) = uppPStr SLIT("\tnop")
+pprInstr (CLTD) = uppPStr SLIT("\tcltd")
+
+pprInstr (SETCC cond op) = pprCondInstr SLIT("set") cond (pprOperand B op)
+
+pprInstr (JXX cond lab) = pprCondInstr SLIT("j") cond (pprCLabel_asm lab)
+
+pprInstr (JMP (OpImm imm)) = uppBeside (uppPStr SLIT("\tjmp ")) (pprImm imm)
+pprInstr (JMP op) = uppBeside (uppPStr SLIT("\tjmp *")) (pprOperand L op)
+
+pprInstr (CALL imm)
+ = uppBesides [ uppPStr SLIT("\tcall "), pprImm imm ]
+
+pprInstr SAHF = uppPStr SLIT("\tsahf")
+pprInstr FABS = uppPStr SLIT("\tfabs")
+
+pprInstr (FADD sz src@(OpAddr _))
+ = uppBesides [uppPStr SLIT("\tfadd"), pprSize sz, uppSP, pprOperand sz src]
+pprInstr (FADD sz src)
+ = uppPStr SLIT("\tfadd")
+pprInstr FADDP
+ = uppPStr SLIT("\tfaddp")
+pprInstr (FMUL sz src)
+ = uppBesides [uppPStr SLIT("\tfmul"), pprSize sz, uppSP, pprOperand sz src]
+pprInstr FMULP
+ = uppPStr SLIT("\tfmulp")
+pprInstr (FIADD size op) = pprSizeAddr SLIT("fiadd") size op
+pprInstr FCHS = uppPStr SLIT("\tfchs")
+pprInstr (FCOM size op) = pprSizeOp SLIT("fcom") size op
+pprInstr FCOS = uppPStr SLIT("\tfcos")
+pprInstr (FIDIV size op) = pprSizeAddr SLIT("fidiv") size op
+pprInstr (FDIV sz src)
+ = uppBesides [uppPStr SLIT("\tfdiv"), pprSize sz, uppSP, pprOperand sz src]
+pprInstr FDIVP
+ = uppPStr SLIT("\tfdivp")
+pprInstr (FDIVR sz src)
+ = uppBesides [uppPStr SLIT("\tfdivr"), pprSize sz, uppSP, pprOperand sz src]
+pprInstr FDIVRP
+ = uppPStr SLIT("\tfdivpr")
+pprInstr (FIDIVR size op) = pprSizeAddr SLIT("fidivr") size op
+pprInstr (FICOM size op) = pprSizeAddr SLIT("ficom") size op
+pprInstr (FILD sz op reg) = pprSizeAddrReg SLIT("fild") sz op reg
+pprInstr (FIST size op) = pprSizeAddr SLIT("fist") size op
+pprInstr (FLD sz (OpImm (ImmCLbl src)))
+ = uppBesides [uppPStr SLIT("\tfld"),pprSize sz,uppSP,pprCLabel_asm src]
+pprInstr (FLD sz src)
+ = uppBesides [uppPStr SLIT("\tfld"),pprSize sz,uppSP,pprOperand sz src]
+pprInstr FLD1 = uppPStr SLIT("\tfld1")
+pprInstr FLDZ = uppPStr SLIT("\tfldz")
+pprInstr (FIMUL size op) = pprSizeAddr SLIT("fimul") size op
+pprInstr FRNDINT = uppPStr SLIT("\tfrndint")
+pprInstr FSIN = uppPStr SLIT("\tfsin")
+pprInstr FSQRT = uppPStr SLIT("\tfsqrt")
+pprInstr (FST sz dst)
+ = uppBesides [uppPStr SLIT("\tfst"), pprSize sz, uppSP, pprOperand sz dst]
+pprInstr (FSTP sz dst)
+ = uppBesides [uppPStr SLIT("\tfstp"), pprSize sz, uppSP, pprOperand sz dst]
+pprInstr (FISUB size op) = pprSizeAddr SLIT("fisub") size op
+pprInstr (FSUB sz src)
+ = uppBesides [uppPStr SLIT("\tfsub"), pprSize sz, uppSP, pprOperand sz src]
+pprInstr FSUBP
+ = uppPStr SLIT("\tfsubp")
+pprInstr (FSUBR size src)
+ = pprSizeOp SLIT("fsubr") size src
+pprInstr FSUBRP
+ = uppPStr SLIT("\tfsubpr")
+pprInstr (FISUBR size op)
+ = pprSizeAddr SLIT("fisubr") size op
+pprInstr FTST = uppPStr SLIT("\tftst")
+pprInstr (FCOMP sz op)
+ = uppBesides [uppPStr SLIT("\tfcomp"), pprSize sz, uppSP, pprOperand sz op]
+pprInstr FUCOMPP = uppPStr SLIT("\tfucompp")
+pprInstr FXCH = uppPStr SLIT("\tfxch")
+pprInstr FNSTSW = uppPStr SLIT("\tfnstsw %ax")
+pprInstr FNOP = uppPStr SLIT("")
+\end{code}
+
+Continue with I386-only printing bits and bobs:
+\begin{code}
+pprDollImm :: Imm -> Unpretty
+
+pprDollImm i = uppBesides [ uppPStr SLIT("$"), pprImm i]
+
+pprOperand :: Size -> Operand -> Unpretty
+pprOperand s (OpReg r) = pprReg s r
+pprOperand s (OpImm i) = pprDollImm i
+pprOperand s (OpAddr ea) = pprAddr ea
+
+pprSizeOp :: FAST_STRING -> Size -> Operand -> Unpretty
+pprSizeOp name size op1
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ pprSize size,
+ uppSP,
+ pprOperand size op1
+ ]
+
+pprSizeOpOp :: FAST_STRING -> Size -> Operand -> Operand -> Unpretty
+pprSizeOpOp name size op1 op2
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ pprSize size,
+ uppSP,
+ pprOperand size op1,
+ uppComma,
+ pprOperand size op2
+ ]
+
+pprSizeOpReg :: FAST_STRING -> Size -> Operand -> Reg -> Unpretty
+pprSizeOpReg name size op1 reg
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ pprSize size,
+ uppSP,
+ pprOperand size op1,
+ uppComma,
+ pprReg size reg
+ ]
+
+pprSizeAddr :: FAST_STRING -> Size -> Addr -> Unpretty
+pprSizeAddr name size op
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ pprSize size,
+ uppSP,
+ pprAddr op
+ ]
+
+pprSizeAddrReg :: FAST_STRING -> Size -> Addr -> Reg -> Unpretty
+pprSizeAddrReg name size op dst
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ pprSize size,
+ uppSP,
+ pprAddr op,
+ uppComma,
+ pprReg size dst
+ ]
+
+pprOpOp :: FAST_STRING -> Size -> Operand -> Operand -> Unpretty
+pprOpOp name size op1 op2
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name, uppSP,
+ pprOperand size op1,
+ uppComma,
+ pprOperand size op2
+ ]
+
+pprSizeOpOpCoerce :: FAST_STRING -> Size -> Size -> Operand -> Operand -> Unpretty
+pprSizeOpOpCoerce name size1 size2 op1 op2
+ = uppBesides [ uppChar '\t', uppPStr name, uppSP,
+ pprOperand size1 op1,
+ uppComma,
+ pprOperand size2 op2
+ ]
+
+pprCondInstr :: FAST_STRING -> Cond -> Unpretty -> Unpretty
+pprCondInstr name cond arg
+ = uppBesides [ uppChar '\t', uppPStr name, pprCond cond, uppSP, arg]
+
+#endif {-i386_TARGET_ARCH-}
+\end{code}
+
+%************************************************************************
+%* *
+\subsubsection{@pprInstr@ for a SPARC}
+%* *
+%************************************************************************
+
+\begin{code}
+#if sparc_TARGET_ARCH
+
+-- a clumsy hack for now, to handle possible double alignment problems
+
+pprInstr (LD DF addr reg) | maybeToBool off_addr
+ = uppBesides [
+ pp_ld_lbracket,
+ pprAddr addr,
+ pp_rbracket_comma,
+ pprReg reg,
+
+ uppChar '\n',
+ pp_ld_lbracket,
+ pprAddr addr2,
+ pp_rbracket_comma,
+ pprReg (fPair reg)
+ ]
+ where
+ off_addr = addrOffset addr 4
+ addr2 = case off_addr of Just x -> x
+
+pprInstr (LD size addr reg)
+ = uppBesides [
+ uppPStr SLIT("\tld"),
+ pprSize size,
+ uppChar '\t',
+ uppLbrack,
+ pprAddr addr,
+ pp_rbracket_comma,
+ pprReg reg
+ ]
+
+-- The same clumsy hack as above
+
+pprInstr (ST DF reg addr) | maybeToBool off_addr
+ = uppBesides [
+ uppPStr SLIT("\tst\t"),
+ pprReg reg,
+ pp_comma_lbracket,
+ pprAddr addr,
+
+ uppPStr SLIT("]\n\tst\t"),
+ pprReg (fPair reg),
+ pp_comma_lbracket,
+ pprAddr addr2,
+ uppRbrack
+ ]
+ where
+ off_addr = addrOffset addr 4
+ addr2 = case off_addr of Just x -> x
+
+pprInstr (ST size reg addr)
+ = uppBesides [
+ uppPStr SLIT("\tst"),
+ pprSize size,
+ uppChar '\t',
+ pprReg reg,
+ pp_comma_lbracket,
+ pprAddr addr,
+ uppRbrack
+ ]
+
+pprInstr (ADD x cc reg1 ri reg2)
+ | not x && not cc && riZero ri
+ = uppBesides [ uppPStr SLIT("\tmov\t"), pprReg reg1, uppComma, pprReg reg2 ]
+ | otherwise
+ = pprRegRIReg (if x then SLIT("addx") else SLIT("add")) cc reg1 ri reg2
+
+pprInstr (SUB x cc reg1 ri reg2)
+ | not x && cc && reg2 == g0
+ = uppBesides [ uppPStr SLIT("\tcmp\t"), pprReg reg1, uppComma, pprRI ri ]
+ | not x && not cc && riZero ri
+ = uppBesides [ uppPStr SLIT("\tmov\t"), pprReg reg1, uppComma, pprReg reg2 ]
+ | otherwise
+ = pprRegRIReg (if x then SLIT("subx") else SLIT("sub")) cc reg1 ri reg2
+
+pprInstr (AND b reg1 ri reg2) = pprRegRIReg SLIT("and") b reg1 ri reg2
+pprInstr (ANDN b reg1 ri reg2) = pprRegRIReg SLIT("andn") b reg1 ri reg2
+
+pprInstr (OR b reg1 ri reg2)
+ | not b && reg1 == g0
+ = uppBesides [ uppPStr SLIT("\tmov\t"), pprRI ri, uppComma, pprReg reg2 ]
+ | otherwise
+ = pprRegRIReg SLIT("or") b reg1 ri reg2
+
+pprInstr (ORN b reg1 ri reg2) = pprRegRIReg SLIT("orn") b reg1 ri reg2
+
+pprInstr (XOR b reg1 ri reg2) = pprRegRIReg SLIT("xor") b reg1 ri reg2
+pprInstr (XNOR b reg1 ri reg2) = pprRegRIReg SLIT("xnor") b reg1 ri reg2
+
+pprInstr (SLL reg1 ri reg2) = pprRegRIReg SLIT("sll") False reg1 ri reg2
+pprInstr (SRL reg1 ri reg2) = pprRegRIReg SLIT("srl") False reg1 ri reg2
+pprInstr (SRA reg1 ri reg2) = pprRegRIReg SLIT("sra") False reg1 ri reg2
+
+pprInstr (SETHI imm reg)
+ = uppBesides [
+ uppPStr SLIT("\tsethi\t"),
+ pprImm imm,
+ uppComma,
+ pprReg reg
+ ]
+
+pprInstr NOP = uppPStr SLIT("\tnop")
+
+pprInstr (FABS F reg1 reg2) = pprSizeRegReg SLIT("fabs") F reg1 reg2
+pprInstr (FABS DF reg1 reg2)
+ = uppBeside (pprSizeRegReg SLIT("fabs") F reg1 reg2)
+ (if (reg1 == reg2) then uppNil
+ else uppBeside (uppChar '\n')
+ (pprSizeRegReg SLIT("fmov") F (fPair reg1) (fPair reg2)))
+
+pprInstr (FADD size reg1 reg2 reg3)
+ = pprSizeRegRegReg SLIT("fadd") size reg1 reg2 reg3
+pprInstr (FCMP e size reg1 reg2)
+ = pprSizeRegReg (if e then SLIT("fcmpe") else SLIT("fcmp")) size reg1 reg2
+pprInstr (FDIV size reg1 reg2 reg3)
+ = pprSizeRegRegReg SLIT("fdiv") size reg1 reg2 reg3
+
+pprInstr (FMOV F reg1 reg2) = pprSizeRegReg SLIT("fmov") F reg1 reg2
+pprInstr (FMOV DF reg1 reg2)
+ = uppBeside (pprSizeRegReg SLIT("fmov") F reg1 reg2)
+ (if (reg1 == reg2) then uppNil
+ else uppBeside (uppChar '\n')
+ (pprSizeRegReg SLIT("fmov") F (fPair reg1) (fPair reg2)))
+
+pprInstr (FMUL size reg1 reg2 reg3)
+ = pprSizeRegRegReg SLIT("fmul") size reg1 reg2 reg3
+
+pprInstr (FNEG F reg1 reg2) = pprSizeRegReg SLIT("fneg") F reg1 reg2
+pprInstr (FNEG DF reg1 reg2)
+ = uppBeside (pprSizeRegReg SLIT("fneg") F reg1 reg2)
+ (if (reg1 == reg2) then uppNil
+ else uppBeside (uppChar '\n')
+ (pprSizeRegReg SLIT("fmov") F (fPair reg1) (fPair reg2)))
+
+pprInstr (FSQRT size reg1 reg2) = pprSizeRegReg SLIT("fsqrt") size reg1 reg2
+pprInstr (FSUB size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("fsub") size reg1 reg2 reg3
+pprInstr (FxTOy size1 size2 reg1 reg2)
+ = uppBesides [
+ uppPStr SLIT("\tf"),
+ uppPStr
+ (case size1 of
+ W -> SLIT("ito")
+ F -> SLIT("sto")
+ DF -> SLIT("dto")),
+ uppPStr
+ (case size2 of
+ W -> SLIT("i\t")
+ F -> SLIT("s\t")
+ DF -> SLIT("d\t")),
+ pprReg reg1, uppComma, pprReg reg2
+ ]
+
+
+pprInstr (BI cond b lab)
+ = uppBesides [
+ uppPStr SLIT("\tb"), pprCond cond,
+ if b then pp_comma_a else uppNil,
+ uppChar '\t',
+ pprImm lab
+ ]
+
+pprInstr (BF cond b lab)
+ = uppBesides [
+ uppPStr SLIT("\tfb"), pprCond cond,
+ if b then pp_comma_a else uppNil,
+ uppChar '\t',
+ pprImm lab
+ ]
+
+pprInstr (JMP addr) = uppBeside (uppPStr SLIT("\tjmp\t")) (pprAddr addr)
+
+pprInstr (CALL imm n _)
+ = uppBesides [ uppPStr SLIT("\tcall\t"), pprImm imm, uppComma, uppInt n ]
+\end{code}
+
+Continue with SPARC-only printing bits and bobs:
+\begin{code}
+pprRI :: RI -> Unpretty
+pprRI (RIReg r) = pprReg r
+pprRI (RIImm r) = pprImm r
+
+pprSizeRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Unpretty
+pprSizeRegReg name size reg1 reg2
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ (case size of
+ F -> uppPStr SLIT("s\t")
+ DF -> uppPStr SLIT("d\t")),
+ pprReg reg1,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprSizeRegRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Reg -> Unpretty
+pprSizeRegRegReg name size reg1 reg2 reg3
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ (case size of
+ F -> uppPStr SLIT("s\t")
+ DF -> uppPStr SLIT("d\t")),
+ pprReg reg1,
+ uppComma,
+ pprReg reg2,
+ uppComma,
+ pprReg reg3
+ ]
+
+pprRegRIReg :: FAST_STRING -> Bool -> Reg -> RI -> Reg -> Unpretty
+pprRegRIReg name b reg1 ri reg2
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ if b then uppPStr SLIT("cc\t") else uppChar '\t',
+ pprReg reg1,
+ uppComma,
+ pprRI ri,
+ uppComma,
+ pprReg reg2
+ ]
+
+pprRIReg :: FAST_STRING -> Bool -> RI -> Reg -> Unpretty
+pprRIReg name b ri reg1
+ = uppBesides [
+ uppChar '\t',
+ uppPStr name,
+ if b then uppPStr SLIT("cc\t") else uppChar '\t',
+ pprRI ri,
+ uppComma,
+ pprReg reg1
+ ]
+
+pp_ld_lbracket = uppPStr (_packCString (A# "\tld\t["#))
+pp_rbracket_comma = uppPStr (_packCString (A# "],"#))
+pp_comma_lbracket = uppPStr (_packCString (A# ",["#))
+pp_comma_a = uppPStr (_packCString (A# ",a"#))
+
+#endif {-sparc_TARGET_ARCH-}
+\end{code}
--- /dev/null
+%
+% (c) The AQUA Project, Glasgow University, 1996
+%
+\section[RegAllocInfo]{Machine-specific info used for register allocation}
+
+The (machine-independent) allocator itself is in @AsmRegAlloc@.
+
+\begin{code}
+#include "HsVersions.h"
+#include "nativeGen/NCG.h"
+
+module RegAllocInfo (
+ MRegsState(..),
+ mkMRegsState,
+ freeMReg,
+ freeMRegs,
+ possibleMRegs,
+ useMReg,
+ useMRegs,
+
+ RegUsage(..),
+ noUsage,
+ endUsage,
+ regUsage,
+
+ FutureLive(..),
+ RegAssignment(..),
+ RegConflicts(..),
+ RegFuture(..),
+ RegHistory(..),
+ RegInfo(..),
+ RegLiveness(..),
+
+ fstFL,
+ loadReg,
+ patchRegs,
+ regLiveness,
+ spillReg,
+
+ RegSet(..),
+ elementOfRegSet,
+ emptyRegSet,
+ isEmptyRegSet,
+ minusRegSet,
+ mkRegSet,
+ regSetToList,
+ unionRegSets,
+
+ argRegSet,
+ callClobberedRegSet,
+ freeRegSet
+ ) where
+
+import Ubiq{-uitous-}
+
+import MachMisc
+import MachRegs
+import MachCode ( InstrList(..) )
+
+import BitSet ( unitBS, mkBS, minusBS, unionBS, listBS, BitSet )
+import CLabel ( pprCLabel_asm, CLabel{-instance Ord-} )
+import FiniteMap ( addToFM, lookupFM )
+import OrdList ( mkUnitList, OrdList )
+import PrimRep ( PrimRep(..) )
+import Stix ( StixTree, CodeSegment )
+import UniqSet -- quite a bit of it
+import Unpretty ( uppShow )
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Register allocation information}
+%* *
+%************************************************************************
+
+\begin{code}
+type RegSet = UniqSet Reg
+
+mkRegSet :: [Reg] -> RegSet
+emptyRegSet :: RegSet
+unionRegSets, minusRegSet :: RegSet -> RegSet -> RegSet
+elementOfRegSet :: Reg -> RegSet -> Bool
+isEmptyRegSet :: RegSet -> Bool
+regSetToList :: RegSet -> [Reg]
+
+mkRegSet = mkUniqSet
+emptyRegSet = emptyUniqSet
+unionRegSets = unionUniqSets
+minusRegSet = minusUniqSet
+elementOfRegSet = elementOfUniqSet
+isEmptyRegSet = isEmptyUniqSet
+regSetToList = uniqSetToList
+
+freeRegSet, callClobberedRegSet :: RegSet
+argRegSet :: Int -> RegSet
+
+freeRegSet = mkRegSet freeRegs
+callClobberedRegSet = mkRegSet callClobberedRegs
+argRegSet n = mkRegSet (argRegs n)
+
+type RegAssignment = FiniteMap Reg Reg
+type RegConflicts = FiniteMap Int RegSet
+
+data FutureLive = FL RegSet (FiniteMap CLabel RegSet)
+
+fstFL (FL a b) = a
+
+data RegHistory a
+ = RH a
+ Int
+ RegAssignment
+
+data RegFuture
+ = RF RegSet -- in use
+ FutureLive -- future
+ RegConflicts
+
+data RegInfo a
+ = RI RegSet -- in use
+ RegSet -- sources
+ RegSet -- destinations
+ [Reg] -- last used
+ RegConflicts
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{Register allocation information}
+%* *
+%************************************************************************
+
+COMMENT ON THE EXTRA BitSet FOR SPARC MRegsState: Getting the conflicts
+right is a bit tedious for doubles. We'd have to add a conflict
+function to the MachineRegisters class, and we'd have to put a PrimRep
+in the MappedReg datatype, or use some kludge (e.g. register 64 + n is
+really the same as 32 + n, except that it's used for a double, so it
+also conflicts with 33 + n) to deal with it. It's just not worth the
+bother, so we just partition the free floating point registers into
+two sets: one for single precision and one for double precision. We
+never seem to run out of floating point registers anyway.
+
+\begin{code}
+data MRegsState
+ = MRs BitSet -- integer registers
+ BitSet -- floating-point registers
+ IF_ARCH_sparc(BitSet,) -- double registers handled separately
+\end{code}
+
+\begin{code}
+#if alpha_TARGET_ARCH
+# define INT_FLPT_CUTOFF 32
+#endif
+#if i386_TARGET_ARCH
+# define INT_FLPT_CUTOFF 8
+#endif
+#if sparc_TARGET_ARCH
+# define INT_FLPT_CUTOFF 32
+# define SNGL_DBL_CUTOFF 48
+#endif
+
+mkMRegsState :: [RegNo] -> MRegsState
+possibleMRegs :: PrimRep -> MRegsState -> [RegNo]
+useMReg :: MRegsState -> FAST_REG_NO -> MRegsState
+useMRegs :: MRegsState -> [RegNo] -> MRegsState
+freeMReg :: MRegsState -> FAST_REG_NO -> MRegsState
+freeMRegs :: MRegsState -> [RegNo] -> MRegsState
+
+mkMRegsState xs
+ = MRs (mkBS is) (mkBS fs2) IF_ARCH_sparc((mkBS ds2),)
+ where
+ (is, fs) = partition (< INT_FLPT_CUTOFF) xs
+#if sparc_TARGET_ARCH
+ (ss, ds) = partition (< SNGL_DBL_CUTOFF) fs
+ fs2 = map (subtract INT_FLPT_CUTOFF) ss
+ ds2 = map (subtract INT_FLPT_CUTOFF) (filter even ds)
+#else
+ fs2 = map (subtract INT_FLPT_CUTOFF) fs
+#endif
+
+------------------------------------------------
+#if sparc_TARGET_ARCH
+possibleMRegs FloatRep (MRs _ ss _) = [ x + INT_FLPT_CUTOFF | x <- listBS ss]
+possibleMRegs DoubleRep (MRs _ _ ds) = [ x + INT_FLPT_CUTOFF | x <- listBS ds]
+possibleMRegs _ (MRs is _ _) = listBS is
+#else
+possibleMRegs FloatRep (MRs _ fs) = [ x + INT_FLPT_CUTOFF | x <- listBS fs]
+possibleMRegs DoubleRep (MRs _ fs) = [ x + INT_FLPT_CUTOFF | x <- listBS fs]
+possibleMRegs _ (MRs is _) = listBS is
+#endif
+
+------------------------------------------------
+#if sparc_TARGET_ARCH
+useMReg (MRs is ss ds) n
+ = if (n _LT_ ILIT(INT_FLPT_CUTOFF)) then
+ MRs (is `minusBS` unitBS IBOX(n)) ss ds
+ else if (n _LT_ ILIT(SNGL_DBL_CUTOFF)) then
+ MRs is (ss `minusBS` unitBS (IBOX(n _SUB_ ILIT(INT_FLPT_CUTOFF)))) ds
+ else
+ MRs is ss (ds `minusBS` unitBS (IBOX(n _SUB_ ILIT(INT_FLPT_CUTOFF))))
+#else
+useMReg (MRs is fs) n
+ = if (n _LT_ ILIT(INT_FLPT_CUTOFF))
+ then MRs (is `minusBS` unitBS IBOX(n)) fs
+ else MRs is (fs `minusBS` unitBS (IBOX(n _SUB_ ILIT(INT_FLPT_CUTOFF))))
+#endif
+
+------------------------------------------------
+#if sparc_TARGET_ARCH
+useMRegs (MRs is ss ds) xs
+ = MRs (is `minusBS` is2) (ss `minusBS` ss2) (ds `minusBS` ds2)
+ where
+ MRs is2 ss2 ds2 = mkMRegsState xs
+#else
+useMRegs (MRs is fs) xs
+ = MRs (is `minusBS` is2) (fs `minusBS` fs2)
+ where
+ MRs is2 fs2 = mkMRegsState xs
+#endif
+
+------------------------------------------------
+#if sparc_TARGET_ARCH
+freeMReg (MRs is ss ds) n
+ = if (n _LT_ ILIT(INT_FLPT_CUTOFF)) then
+ MRs (is `unionBS` unitBS IBOX(n)) ss ds
+ else if (n _LT_ ILIT(SNGL_DBL_CUTOFF)) then
+ MRs is (ss `unionBS` unitBS (IBOX(n _SUB_ ILIT(INT_FLPT_CUTOFF)))) ds
+ else
+ MRs is ss (ds `unionBS` unitBS (IBOX(n _SUB_ ILIT(INT_FLPT_CUTOFF))))
+#else
+freeMReg (MRs is fs) n
+ = if (n _LT_ ILIT(INT_FLPT_CUTOFF))
+ then MRs (is `unionBS` unitBS IBOX(n)) fs
+ else MRs is (fs `unionBS` unitBS (IBOX(n _SUB_ ILIT(INT_FLPT_CUTOFF))))
+#endif
+
+------------------------------------------------
+#if sparc_TARGET_ARCH
+freeMRegs (MRs is ss ds) xs
+ = MRs (is `unionBS` is2) (ss `unionBS` ss2) (ds `unionBS` ds2)
+ where
+ MRs is2 ss2 ds2 = mkMRegsState xs
+#else
+freeMRegs (MRs is fs) xs
+ = MRs (is `unionBS` is2) (fs `unionBS` fs2)
+ where
+ MRs is2 fs2 = mkMRegsState xs
+#endif
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{@RegUsage@ type; @noUsage@, @endUsage@, @regUsage@ functions}
+%* *
+%************************************************************************
+
+@regUsage@ returns the sets of src and destination registers used by a
+particular instruction. Machine registers that are pre-allocated to
+stgRegs are filtered out, because they are uninteresting from a
+register allocation standpoint. (We wouldn't want them to end up on
+the free list!)
+
+An important point: The @regUsage@ function for a particular
+assembly language must not refer to fixed registers, such as Hp, SpA,
+etc. The source and destination MRegsStates should only refer to
+dynamically allocated registers or static registers from the free
+list. As far as we are concerned, the fixed registers simply don't
+exist (for allocation purposes, anyway).
+
+\begin{code}
+data RegUsage = RU RegSet RegSet
+
+noUsage, endUsage :: RegUsage
+noUsage = RU emptyRegSet emptyRegSet
+endUsage = RU emptyRegSet freeRegSet
+
+regUsage :: Instr -> RegUsage
+
+#if alpha_TARGET_ARCH
+
+regUsage instr = case instr of
+ LD B reg addr -> usage (regAddr addr, [reg, t9])
+ LD BU reg addr -> usage (regAddr addr, [reg, t9])
+-- LD W reg addr -> usage (regAddr addr, [reg, t9]) : UNUSED
+-- LD WU reg addr -> usage (regAddr addr, [reg, t9]) : UNUSED
+ LD sz reg addr -> usage (regAddr addr, [reg])
+ LDA reg addr -> usage (regAddr addr, [reg])
+ LDAH reg addr -> usage (regAddr addr, [reg])
+ LDGP reg addr -> usage (regAddr addr, [reg])
+ LDI sz reg imm -> usage ([], [reg])
+ ST B reg addr -> usage (reg : regAddr addr, [t9, t10])
+-- ST W reg addr -> usage (reg : regAddr addr, [t9, t10]) : UNUSED
+ ST sz reg addr -> usage (reg : regAddr addr, [])
+ CLR reg -> usage ([], [reg])
+ ABS sz ri reg -> usage (regRI ri, [reg])
+ NEG sz ov ri reg -> usage (regRI ri, [reg])
+ ADD sz ov r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SADD sz sc r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SUB sz ov r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SSUB sz sc r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ MUL sz ov r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ DIV sz un r1 ar r2 -> usage (r1 : regRI ar, [r2, t9, t10, t11, t12])
+ REM sz un r1 ar r2 -> usage (r1 : regRI ar, [r2, t9, t10, t11, t12])
+ NOT ri reg -> usage (regRI ri, [reg])
+ AND r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ ANDNOT r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ OR r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ ORNOT r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ XOR r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ XORNOT r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SLL r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SRL r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SRA r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ ZAP r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ ZAPNOT r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ CMP co r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ FCLR reg -> usage ([], [reg])
+ FABS r1 r2 -> usage ([r1], [r2])
+ FNEG sz r1 r2 -> usage ([r1], [r2])
+ FADD sz r1 r2 r3 -> usage ([r1, r2], [r3])
+ FDIV sz r1 r2 r3 -> usage ([r1, r2], [r3])
+ FMUL sz r1 r2 r3 -> usage ([r1, r2], [r3])
+ FSUB sz r1 r2 r3 -> usage ([r1, r2], [r3])
+ CVTxy sz1 sz2 r1 r2 -> usage ([r1], [r2])
+ FCMP sz co r1 r2 r3 -> usage ([r1, r2], [r3])
+ FMOV r1 r2 -> usage ([r1], [r2])
+
+
+ -- We assume that all local jumps will be BI/BF/BR. JMP must be out-of-line.
+ BI cond reg lbl -> usage ([reg], [])
+ BF cond reg lbl -> usage ([reg], [])
+ JMP reg addr hint -> RU (mkRegSet (filter interesting (regAddr addr))) freeRegSet
+
+ BSR _ n -> RU (argRegSet n) callClobberedRegSet
+ JSR reg addr n -> RU (argRegSet n) callClobberedRegSet
+
+ _ -> noUsage
+
+ where
+ usage (src, dst) = RU (mkRegSet (filter interesting src))
+ (mkRegSet (filter interesting dst))
+
+ interesting (FixedReg _) = False
+ interesting _ = True
+
+ regAddr (AddrReg r1) = [r1]
+ regAddr (AddrRegImm r1 _) = [r1]
+ regAddr (AddrImm _) = []
+
+ regRI (RIReg r) = [r]
+ regRI _ = []
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+regUsage instr = case instr of
+ MOV sz src dst -> usage2 src dst
+ MOVZX sz src dst -> usage2 src dst
+ MOVSX sz src dst -> usage2 src dst
+ LEA sz src dst -> usage2 src dst
+ ADD sz src dst -> usage2 src dst
+ SUB sz src dst -> usage2 src dst
+ IMUL sz src dst -> usage2 src dst
+ IDIV sz src -> usage (eax:edx:opToReg src) [eax,edx]
+ AND sz src dst -> usage2 src dst
+ OR sz src dst -> usage2 src dst
+ XOR sz src dst -> usage2 src dst
+ NOT sz op -> usage1 op
+ NEGI sz op -> usage1 op
+ SHL sz imm dst -> usage1 dst -- imm has to be an Imm
+ SAR sz imm dst -> usage1 dst -- imm has to be an Imm
+ SHR sz imm dst -> usage1 dst -- imm has to be an Imm
+ PUSH sz op -> usage (opToReg op) []
+ POP sz op -> usage [] (opToReg op)
+ TEST sz src dst -> usage (opToReg src ++ opToReg dst) []
+ CMP sz src dst -> usage (opToReg src ++ opToReg dst) []
+ SETCC cond op -> usage [] (opToReg op)
+ JXX cond label -> usage [] []
+ JMP op -> usage (opToReg op) freeRegs
+ CALL imm -> usage [] callClobberedRegs
+ CLTD -> usage [eax] [edx]
+ NOP -> usage [] []
+ SAHF -> usage [eax] []
+ FABS -> usage [st0] [st0]
+ FADD sz src -> usage (st0:opToReg src) [st0] -- allFPRegs
+ FADDP -> usage [st0,st1] [st0] -- allFPRegs
+ FIADD sz asrc -> usage (addrToRegs asrc) [st0]
+ FCHS -> usage [st0] [st0]
+ FCOM sz src -> usage (st0:opToReg src) []
+ FCOS -> usage [st0] [st0]
+ FDIV sz src -> usage (st0:opToReg src) [st0]
+ FDIVP -> usage [st0,st1] [st0]
+ FDIVRP -> usage [st0,st1] [st0]
+ FIDIV sz asrc -> usage (addrToRegs asrc) [st0]
+ FDIVR sz src -> usage (st0:opToReg src) [st0]
+ FIDIVR sz asrc -> usage (addrToRegs asrc) [st0]
+ FICOM sz asrc -> usage (addrToRegs asrc) []
+ FILD sz asrc dst -> usage (addrToRegs asrc) [dst] -- allFPRegs
+ FIST sz adst -> usage (st0:addrToRegs adst) []
+ FLD sz src -> usage (opToReg src) [st0] -- allFPRegs
+ FLD1 -> usage [] [st0] -- allFPRegs
+ FLDZ -> usage [] [st0] -- allFPRegs
+ FMUL sz src -> usage (st0:opToReg src) [st0]
+ FMULP -> usage [st0,st1] [st0]
+ FIMUL sz asrc -> usage (addrToRegs asrc) [st0]
+ FRNDINT -> usage [st0] [st0]
+ FSIN -> usage [st0] [st0]
+ FSQRT -> usage [st0] [st0]
+ FST sz (OpReg r) -> usage [st0] [r]
+ FST sz dst -> usage (st0:opToReg dst) []
+ FSTP sz (OpReg r) -> usage [st0] [r] -- allFPRegs
+ FSTP sz dst -> usage (st0:opToReg dst) [] -- allFPRegs
+ FSUB sz src -> usage (st0:opToReg src) [st0] -- allFPRegs
+ FSUBR sz src -> usage (st0:opToReg src) [st0] -- allFPRegs
+ FISUB sz asrc -> usage (addrToRegs asrc) [st0]
+ FSUBP -> usage [st0,st1] [st0] -- allFPRegs
+ FSUBRP -> usage [st0,st1] [st0] -- allFPRegs
+ FISUBR sz asrc -> usage (addrToRegs asrc) [st0]
+ FTST -> usage [st0] []
+ FCOMP sz op -> usage (st0:opToReg op) [st0] -- allFPRegs
+ FUCOMPP -> usage [st0, st1] [] -- allFPRegs
+ FXCH -> usage [st0, st1] [st0, st1]
+ FNSTSW -> usage [] [eax]
+ _ -> noUsage
+ where
+ usage2 :: Operand -> Operand -> RegUsage
+ usage2 op (OpReg reg) = usage (opToReg op) [reg]
+ usage2 op (OpAddr ea) = usage (opToReg op ++ addrToRegs ea) []
+ usage2 op (OpImm imm) = usage (opToReg op) []
+ usage1 :: Operand -> RegUsage
+ usage1 (OpReg reg) = usage [reg] [reg]
+ usage1 (OpAddr ea) = usage (addrToRegs ea) []
+ allFPRegs = [st0,st1,st2,st3,st4,st5,st6,st7]
+
+ --callClobberedRegs = [ eax, ecx, edx ] -- according to gcc, anyway.
+ callClobberedRegs = [eax]
+
+-- General purpose register collecting functions.
+
+ opToReg (OpReg reg) = [reg]
+ opToReg (OpImm imm) = []
+ opToReg (OpAddr ea) = addrToRegs ea
+
+ addrToRegs (Addr base index _) = baseToReg base ++ indexToReg index
+ where baseToReg Nothing = []
+ baseToReg (Just r) = [r]
+ indexToReg Nothing = []
+ indexToReg (Just (r,_)) = [r]
+ addrToRegs (ImmAddr _ _) = []
+
+ usage src dst = RU (mkRegSet (filter interesting src))
+ (mkRegSet (filter interesting dst))
+
+ interesting (FixedReg _) = False
+ interesting _ = True
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+regUsage instr = case instr of
+ LD sz addr reg -> usage (regAddr addr, [reg])
+ ST sz reg addr -> usage (reg : regAddr addr, [])
+ ADD x cc r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SUB x cc r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ AND b r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ ANDN b r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ OR b r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ ORN b r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ XOR b r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ XNOR b r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SLL r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SRL r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SRA r1 ar r2 -> usage (r1 : regRI ar, [r2])
+ SETHI imm reg -> usage ([], [reg])
+ FABS s r1 r2 -> usage ([r1], [r2])
+ FADD s r1 r2 r3 -> usage ([r1, r2], [r3])
+ FCMP e s r1 r2 -> usage ([r1, r2], [])
+ FDIV s r1 r2 r3 -> usage ([r1, r2], [r3])
+ FMOV s r1 r2 -> usage ([r1], [r2])
+ FMUL s r1 r2 r3 -> usage ([r1, r2], [r3])
+ FNEG s r1 r2 -> usage ([r1], [r2])
+ FSQRT s r1 r2 -> usage ([r1], [r2])
+ FSUB s r1 r2 r3 -> usage ([r1, r2], [r3])
+ FxTOy s1 s2 r1 r2 -> usage ([r1], [r2])
+
+ -- We assume that all local jumps will be BI/BF. JMP must be out-of-line.
+ JMP addr -> RU (mkRegSet (filter interesting (regAddr addr))) freeRegSet
+
+ CALL _ n True -> endUsage
+ CALL _ n False -> RU (argRegSet n) callClobberedRegSet
+
+ _ -> noUsage
+ where
+ usage (src, dst) = RU (mkRegSet (filter interesting src))
+ (mkRegSet (filter interesting dst))
+
+ interesting (FixedReg _) = False
+ interesting _ = True
+
+ regAddr (AddrRegReg r1 r2) = [r1, r2]
+ regAddr (AddrRegImm r1 _) = [r1]
+
+ regRI (RIReg r) = [r]
+ regRI _ = []
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{@RegLiveness@ type; @regLiveness@ function}
+%* *
+%************************************************************************
+
+@regLiveness@ takes future liveness information and modifies it
+according to the semantics of branches and labels. (An out-of-line
+branch clobbers the liveness passed back by the following instruction;
+a forward local branch passes back the liveness from the target label;
+a conditional branch merges the liveness from the target and the
+liveness from its successor; a label stashes away the current liveness
+in the future liveness environment).
+
+\begin{code}
+data RegLiveness = RL RegSet FutureLive
+
+regLiveness :: Instr -> RegLiveness -> RegLiveness
+
+regLiveness instr info@(RL live future@(FL all env))
+ = let
+ lookup lbl
+ = case (lookupFM env lbl) of
+ Just rs -> rs
+ Nothing -> trace ("Missing " ++ (uppShow 80 (pprCLabel_asm lbl)) ++
+ " in future?") emptyRegSet
+ in
+ case instr of -- the rest is machine-specific...
+
+#if alpha_TARGET_ARCH
+
+ -- We assume that all local jumps will be BI/BF. JMP must be out-of-line.
+
+ BR (ImmCLbl lbl) -> RL (lookup lbl) future
+ BI _ _ (ImmCLbl lbl) -> RL (lookup lbl `unionRegSets` live) future
+ BF _ _ (ImmCLbl lbl) -> RL (lookup lbl `unionRegSets` live) future
+ JMP _ _ _ -> RL emptyRegSet future
+ BSR _ _ -> RL live future
+ JSR _ _ _ -> RL live future
+ LABEL lbl -> RL live (FL (all `unionRegSets` live) (addToFM env lbl live))
+ _ -> info
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+ JXX _ lbl -> RL (lookup lbl `unionRegSets` live) future
+ JMP _ -> RL emptyRegSet future
+ CALL _ -> RL live future
+ LABEL lbl -> RL live (FL (all `unionRegSets` live) (addToFM env lbl live))
+ _ -> info
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+ -- We assume that all local jumps will be BI/BF. JMP must be out-of-line.
+
+ BI ALWAYS _ (ImmCLbl lbl) -> RL (lookup lbl) future
+ BI _ _ (ImmCLbl lbl) -> RL (lookup lbl `unionRegSets` live) future
+ BF ALWAYS _ (ImmCLbl lbl) -> RL (lookup lbl) future
+ BF _ _ (ImmCLbl lbl) -> RL (lookup lbl `unionRegSets` live) future
+ JMP _ -> RL emptyRegSet future
+ CALL _ i True -> RL emptyRegSet future
+ CALL _ i False -> RL live future
+ LABEL lbl -> RL live (FL (all `unionRegSets` live) (addToFM env lbl live))
+ _ -> info
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{@patchRegs@ function}
+%* *
+%************************************************************************
+
+@patchRegs@ takes an instruction (possibly with
+MemoryReg/UnmappedReg registers) and changes all register references
+according to the supplied environment.
+
+\begin{code}
+patchRegs :: Instr -> (Reg -> Reg) -> Instr
+
+#if alpha_TARGET_ARCH
+
+patchRegs instr env = case instr of
+ LD sz reg addr -> LD sz (env reg) (fixAddr addr)
+ LDA reg addr -> LDA (env reg) (fixAddr addr)
+ LDAH reg addr -> LDAH (env reg) (fixAddr addr)
+ LDGP reg addr -> LDGP (env reg) (fixAddr addr)
+ LDI sz reg imm -> LDI sz (env reg) imm
+ ST sz reg addr -> ST sz (env reg) (fixAddr addr)
+ CLR reg -> CLR (env reg)
+ ABS sz ar reg -> ABS sz (fixRI ar) (env reg)
+ NEG sz ov ar reg -> NEG sz ov (fixRI ar) (env reg)
+ ADD sz ov r1 ar r2 -> ADD sz ov (env r1) (fixRI ar) (env r2)
+ SADD sz sc r1 ar r2 -> SADD sz sc (env r1) (fixRI ar) (env r2)
+ SUB sz ov r1 ar r2 -> SUB sz ov (env r1) (fixRI ar) (env r2)
+ SSUB sz sc r1 ar r2 -> SSUB sz sc (env r1) (fixRI ar) (env r2)
+ MUL sz ov r1 ar r2 -> MUL sz ov (env r1) (fixRI ar) (env r2)
+ DIV sz un r1 ar r2 -> DIV sz un (env r1) (fixRI ar) (env r2)
+ REM sz un r1 ar r2 -> REM sz un (env r1) (fixRI ar) (env r2)
+ NOT ar reg -> NOT (fixRI ar) (env reg)
+ AND r1 ar r2 -> AND (env r1) (fixRI ar) (env r2)
+ ANDNOT r1 ar r2 -> ANDNOT (env r1) (fixRI ar) (env r2)
+ OR r1 ar r2 -> OR (env r1) (fixRI ar) (env r2)
+ ORNOT r1 ar r2 -> ORNOT (env r1) (fixRI ar) (env r2)
+ XOR r1 ar r2 -> XOR (env r1) (fixRI ar) (env r2)
+ XORNOT r1 ar r2 -> XORNOT (env r1) (fixRI ar) (env r2)
+ SLL r1 ar r2 -> SLL (env r1) (fixRI ar) (env r2)
+ SRL r1 ar r2 -> SRL (env r1) (fixRI ar) (env r2)
+ SRA r1 ar r2 -> SRA (env r1) (fixRI ar) (env r2)
+ ZAP r1 ar r2 -> ZAP (env r1) (fixRI ar) (env r2)
+ ZAPNOT r1 ar r2 -> ZAPNOT (env r1) (fixRI ar) (env r2)
+ CMP co r1 ar r2 -> CMP co (env r1) (fixRI ar) (env r2)
+ FCLR reg -> FCLR (env reg)
+ FABS r1 r2 -> FABS (env r1) (env r2)
+ FNEG s r1 r2 -> FNEG s (env r1) (env r2)
+ FADD s r1 r2 r3 -> FADD s (env r1) (env r2) (env r3)
+ FDIV s r1 r2 r3 -> FDIV s (env r1) (env r2) (env r3)
+ FMUL s r1 r2 r3 -> FMUL s (env r1) (env r2) (env r3)
+ FSUB s r1 r2 r3 -> FSUB s (env r1) (env r2) (env r3)
+ CVTxy s1 s2 r1 r2 -> CVTxy s1 s2 (env r1) (env r2)
+ FCMP s co r1 r2 r3 -> FCMP s co (env r1) (env r2) (env r3)
+ FMOV r1 r2 -> FMOV (env r1) (env r2)
+ BI cond reg lbl -> BI cond (env reg) lbl
+ BF cond reg lbl -> BF cond (env reg) lbl
+ JMP reg addr hint -> JMP (env reg) (fixAddr addr) hint
+ JSR reg addr i -> JSR (env reg) (fixAddr addr) i
+ _ -> instr
+ where
+ fixAddr (AddrReg r1) = AddrReg (env r1)
+ fixAddr (AddrRegImm r1 i) = AddrRegImm (env r1) i
+ fixAddr other = other
+
+ fixRI (RIReg r) = RIReg (env r)
+ fixRI other = other
+
+#endif {- alpha_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if i386_TARGET_ARCH
+
+patchRegs instr env = case instr of
+ MOV sz src dst -> patch2 (MOV sz) src dst
+ MOVZX sz src dst -> patch2 (MOVZX sz) src dst
+ MOVSX sz src dst -> patch2 (MOVSX sz) src dst
+ LEA sz src dst -> patch2 (LEA sz) src dst
+ ADD sz src dst -> patch2 (ADD sz) src dst
+ SUB sz src dst -> patch2 (SUB sz) src dst
+ IMUL sz src dst -> patch2 (IMUL sz) src dst
+ IDIV sz src -> patch1 (IDIV sz) src
+ AND sz src dst -> patch2 (AND sz) src dst
+ OR sz src dst -> patch2 (OR sz) src dst
+ XOR sz src dst -> patch2 (XOR sz) src dst
+ NOT sz op -> patch1 (NOT sz) op
+ NEGI sz op -> patch1 (NEGI sz) op
+ SHL sz imm dst -> patch1 (SHL sz imm) dst
+ SAR sz imm dst -> patch1 (SAR sz imm) dst
+ SHR sz imm dst -> patch1 (SHR sz imm) dst
+ TEST sz src dst -> patch2 (TEST sz) src dst
+ CMP sz src dst -> patch2 (CMP sz) src dst
+ PUSH sz op -> patch1 (PUSH sz) op
+ POP sz op -> patch1 (POP sz) op
+ SETCC cond op -> patch1 (SETCC cond) op
+ JMP op -> patch1 JMP op
+ FADD sz src -> FADD sz (patchOp src)
+ FIADD sz asrc -> FIADD sz (lookupAddr asrc)
+ FCOM sz src -> patch1 (FCOM sz) src
+ FDIV sz src -> FDIV sz (patchOp src)
+ --FDIVP sz src -> FDIVP sz (patchOp src)
+ FIDIV sz asrc -> FIDIV sz (lookupAddr asrc)
+ FDIVR sz src -> FDIVR sz (patchOp src)
+ --FDIVRP sz src -> FDIVRP sz (patchOp src)
+ FIDIVR sz asrc -> FIDIVR sz (lookupAddr asrc)
+ FICOM sz asrc -> FICOM sz (lookupAddr asrc)
+ FILD sz asrc dst -> FILD sz (lookupAddr asrc) (env dst)
+ FIST sz adst -> FIST sz (lookupAddr adst)
+ FLD sz src -> patch1 (FLD sz) (patchOp src)
+ FMUL sz src -> FMUL sz (patchOp src)
+ --FMULP sz src -> FMULP sz (patchOp src)
+ FIMUL sz asrc -> FIMUL sz (lookupAddr asrc)
+ FST sz dst -> FST sz (patchOp dst)
+ FSTP sz dst -> FSTP sz (patchOp dst)
+ FSUB sz src -> FSUB sz (patchOp src)
+ --FSUBP sz src -> FSUBP sz (patchOp src)
+ FISUB sz asrc -> FISUB sz (lookupAddr asrc)
+ FSUBR sz src -> FSUBR sz (patchOp src)
+ --FSUBRP sz src -> FSUBRP sz (patchOp src)
+ FISUBR sz asrc -> FISUBR sz (lookupAddr asrc)
+ FCOMP sz src -> FCOMP sz (patchOp src)
+ _ -> instr
+ where
+ patch1 insn op = insn (patchOp op)
+ patch2 insn src dst = insn (patchOp src) (patchOp dst)
+
+ patchOp (OpReg reg) = OpReg (env reg)
+ patchOp (OpImm imm) = OpImm imm
+ patchOp (OpAddr ea) = OpAddr (lookupAddr ea)
+
+ lookupAddr (ImmAddr imm off) = ImmAddr imm off
+ lookupAddr (Addr base index disp)
+ = Addr (lookupBase base) (lookupIndex index) disp
+ where
+ lookupBase Nothing = Nothing
+ lookupBase (Just r) = Just (env r)
+
+ lookupIndex Nothing = Nothing
+ lookupIndex (Just (r,i)) = Just (env r, i)
+
+#endif {- i386_TARGET_ARCH -}
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#if sparc_TARGET_ARCH
+
+patchRegs instr env = case instr of
+ LD sz addr reg -> LD sz (fixAddr addr) (env reg)
+ ST sz reg addr -> ST sz (env reg) (fixAddr addr)
+ ADD x cc r1 ar r2 -> ADD x cc (env r1) (fixRI ar) (env r2)
+ SUB x cc r1 ar r2 -> SUB x cc (env r1) (fixRI ar) (env r2)
+ AND b r1 ar r2 -> AND b (env r1) (fixRI ar) (env r2)
+ ANDN b r1 ar r2 -> ANDN b (env r1) (fixRI ar) (env r2)
+ OR b r1 ar r2 -> OR b (env r1) (fixRI ar) (env r2)
+ ORN b r1 ar r2 -> ORN b (env r1) (fixRI ar) (env r2)
+ XOR b r1 ar r2 -> XOR b (env r1) (fixRI ar) (env r2)
+ XNOR b r1 ar r2 -> XNOR b (env r1) (fixRI ar) (env r2)
+ SLL r1 ar r2 -> SLL (env r1) (fixRI ar) (env r2)
+ SRL r1 ar r2 -> SRL (env r1) (fixRI ar) (env r2)
+ SRA r1 ar r2 -> SRA (env r1) (fixRI ar) (env r2)
+ SETHI imm reg -> SETHI imm (env reg)
+ FABS s r1 r2 -> FABS s (env r1) (env r2)
+ FADD s r1 r2 r3 -> FADD s (env r1) (env r2) (env r3)
+ FCMP e s r1 r2 -> FCMP e s (env r1) (env r2)
+ FDIV s r1 r2 r3 -> FDIV s (env r1) (env r2) (env r3)
+ FMOV s r1 r2 -> FMOV s (env r1) (env r2)
+ FMUL s r1 r2 r3 -> FMUL s (env r1) (env r2) (env r3)
+ FNEG s r1 r2 -> FNEG s (env r1) (env r2)
+ FSQRT s r1 r2 -> FSQRT s (env r1) (env r2)
+ FSUB s r1 r2 r3 -> FSUB s (env r1) (env r2) (env r3)
+ FxTOy s1 s2 r1 r2 -> FxTOy s1 s2 (env r1) (env r2)
+ JMP addr -> JMP (fixAddr addr)
+ _ -> instr
+ where
+ fixAddr (AddrRegReg r1 r2) = AddrRegReg (env r1) (env r2)
+ fixAddr (AddrRegImm r1 i) = AddrRegImm (env r1) i
+
+ fixRI (RIReg r) = RIReg (env r)
+ fixRI other = other
+
+#endif {- sparc_TARGET_ARCH -}
+\end{code}
+
+%************************************************************************
+%* *
+\subsection{@spillReg@ and @loadReg@ functions}
+%* *
+%************************************************************************
+
+Spill to memory, and load it back...
+
+\begin{code}
+spillReg, loadReg :: Reg -> Reg -> InstrList
+
+spillReg dyn (MemoryReg i pk)
+ = let
+ sz = primRepToSize pk
+ in
+ mkUnitList (
+ {-Alpha: spill below the stack pointer (?)-}
+ IF_ARCH_alpha( ST sz dyn (spRel i)
+
+ {-I386: spill below stack pointer leaving 2 words/spill-}
+ ,IF_ARCH_i386 ( MOV sz (OpReg dyn) (OpAddr (spRel (-2 * i)))
+
+ {-SPARC: spill below frame pointer leaving 2 words/spill-}
+ ,IF_ARCH_sparc( ST sz dyn (fpRel (-2 * i))
+ ,)))
+ )
+
+----------------------------
+loadReg (MemoryReg i pk) dyn
+ = let
+ sz = primRepToSize pk
+ in
+ mkUnitList (
+ IF_ARCH_alpha( LD sz dyn (spRel i)
+ ,IF_ARCH_i386 ( MOV sz (OpAddr (spRel (-2 * i))) (OpReg dyn)
+ ,IF_ARCH_sparc( LD sz (fpRel (-2 * i)) dyn
+ ,)))
+ )
+\end{code}
+++ /dev/null
-%
-% (c) The AQUA Project, Glasgow University, 1993-1995
-%
-
-\section[SparcCode]{The Native (Sparc) Machine Code}
-
-\begin{code}
-#define ILIT2(x) ILIT(x)
-#include "HsVersions.h"
-
-module SparcCode (
- Addr(..),Cond(..),Imm(..),RI(..),Size(..),
- SparcCode(..),SparcInstr(..),SparcRegs,
- strImmLit,
-
- printLabeledCodes,
-
- baseRegOffset, stgRegMap, callerSaves,
-
- is13Bits, offset,
-
- kindToSize,
-
- g0, o0, f0, fp, sp, argRegs,
-
- freeRegs, reservedRegs
-
- -- and, for self-sufficiency ...
- ) where
-
-IMPORT_Trace
-
-import AbsCSyn ( MagicId(..) )
-import AsmRegAlloc ( MachineCode(..), MachineRegisters(..), FutureLive(..),
- Reg(..), RegUsage(..), RegLiveness(..)
- )
-import BitSet
-import CgCompInfo ( mAX_Double_REG, mAX_Float_REG, mAX_Vanilla_REG )
-import CLabel ( CLabel, pprCLabel, externallyVisibleCLabel, charToC )
-import FiniteMap
-import Maybes ( Maybe(..), maybeToBool )
-import OrdList ( OrdList, mkUnitList, flattenOrdList )
-import Outputable
-import UniqSet
-import Stix
-import Unpretty
-import Util
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[SparcReg]{The Native (Sparc) Machine Register Table}
-%* *
-%************************************************************************
-
-The sparc has 64 registers of interest; 32 integer registers and 32 floating
-point registers. The mapping of STG registers to sparc machine registers
-is defined in StgRegs.h. We are, of course, prepared for any eventuality.
-
-ToDo: Deal with stg registers that live as offsets from BaseReg!(JSM)
-
-\begin{code}
-
-gReg,lReg,iReg,oReg,fReg :: Int -> Int
-gReg x = x
-oReg x = (8 + x)
-lReg x = (16 + x)
-iReg x = (24 + x)
-fReg x = (32 + x)
-
-fPair :: Reg -> Reg
-fPair (FixedReg i) = FixedReg (i _ADD_ ILIT(1))
-fPair (MappedReg i) = MappedReg (i _ADD_ ILIT(1))
-
-g0, fp, sp, o0, f0 :: Reg
-g0 = case (gReg 0) of { IBOX(g0) -> FixedReg g0 }
-fp = case (iReg 6) of { IBOX(i6) -> FixedReg i6 }
-sp = case (oReg 6) of { IBOX(o6) -> FixedReg o6 }
-o0 = realReg (oReg 0)
-f0 = realReg (fReg 0)
-
-argRegs :: [Reg]
-argRegs = map realReg [oReg i | i <- [0..5]]
-
-realReg n@IBOX(i) = if _IS_TRUE_(freeReg i) then MappedReg i else FixedReg i
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[TheSparcCode]{The datatype for sparc assembly language}
-%* *
-%************************************************************************
-
-Here is a definition of the Sparc assembly language.
-
-\begin{code}
-
-data Imm = ImmInt Int
- | ImmInteger Integer -- Sigh.
- | ImmCLbl CLabel -- AbstractC Label (with baggage)
- | ImmLab Unpretty -- Simple string label (underscored)
- | ImmLit Unpretty -- Simple string
- | LO Imm -- Possible restrictions
- | HI Imm
- deriving ()
-
-strImmLit s = ImmLit (uppStr s)
-
-data Addr = AddrRegReg Reg Reg
- | AddrRegImm Reg Imm
- deriving ()
-
-data Cond = ALWAYS
- | NEVER
- | GEU
- | LU
- | EQ
- | GT
- | GE
- | GU
- | LT
- | LE
- | LEU
- | NE
- | NEG
- | POS
- | VC
- | VS
- deriving ()
-
-data RI = RIReg Reg
- | RIImm Imm
- deriving ()
-
-riZero :: RI -> Bool
-riZero (RIImm (ImmInt 0)) = True
-riZero (RIImm (ImmInteger 0)) = True
-riZero (RIReg (FixedReg ILIT(0))) = True
-riZero _ = False
-
-data Size = SB
- | HW
- | UB
- | UHW
- | W
- | D
- | F
- | DF
- deriving ()
-
-data SparcInstr =
-
--- Loads and stores.
-
- LD Size Addr Reg -- size, src, dst
- | ST Size Reg Addr -- size, src, dst
-
--- Int Arithmetic.
-
- | ADD Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
- | SUB Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst
-
--- Simple bit-twiddling.
-
- | AND Bool Reg RI Reg -- cc?, src1, src2, dst
- | ANDN Bool Reg RI Reg -- cc?, src1, src2, dst
- | OR Bool Reg RI Reg -- cc?, src1, src2, dst
- | ORN Bool Reg RI Reg -- cc?, src1, src2, dst
- | XOR Bool Reg RI Reg -- cc?, src1, src2, dst
- | XNOR Bool Reg RI Reg -- cc?, src1, src2, dst
- | SLL Reg RI Reg -- src1, src2, dst
- | SRL Reg RI Reg -- src1, src2, dst
- | SRA Reg RI Reg -- src1, src2, dst
- | SETHI Imm Reg -- src, dst
- | NOP -- Really SETHI 0, %g0, but worth an alias
-
--- Float Arithmetic.
-
--- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions
--- right up until we spit them out.
-
- | FABS Size Reg Reg -- src dst
- | FADD Size Reg Reg Reg -- src1, src2, dst
- | FCMP Bool Size Reg Reg -- exception?, src1, src2, dst
- | FDIV Size Reg Reg Reg -- src1, src2, dst
- | FMOV Size Reg Reg -- src, dst
- | FMUL Size Reg Reg Reg -- src1, src2, dst
- | FNEG Size Reg Reg -- src, dst
- | FSQRT Size Reg Reg -- src, dst
- | FSUB Size Reg Reg Reg -- src1, src2, dst
- | FxTOy Size Size Reg Reg -- src, dst
-
--- Jumping around.
-
- | BI Cond Bool Imm -- cond, annul?, target
- | BF Cond Bool Imm -- cond, annul?, target
-
- | JMP Addr -- target
- | CALL Imm Int Bool -- target, args, terminal
-
--- Pseudo-ops.
-
- | LABEL CLabel
- | COMMENT FAST_STRING
- | SEGMENT CodeSegment
- | ASCII Bool String -- needs backslash conversion?
- | DATA Size [Imm]
-
-type SparcCode = OrdList SparcInstr
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[TheSparcPretty]{Pretty-printing the Sparc Assembly Language}
-%* *
-%************************************************************************
-
-\begin{code}
-
-printLabeledCodes :: PprStyle -> [SparcInstr] -> Unpretty
-printLabeledCodes sty codes = uppAboves (map (pprSparcInstr sty) codes)
-
-\end{code}
-
-Printing the pieces...
-
-\begin{code}
-
-pprReg :: Reg -> Unpretty
-
-pprReg (FixedReg i) = pprSparcReg i
-pprReg (MappedReg i) = pprSparcReg i
-pprReg other = uppStr (show other) -- should only happen when debugging
-
-pprSparcReg :: FAST_INT -> Unpretty
-pprSparcReg i = uppPStr
- (case i of {
- ILIT( 0) -> SLIT("%g0"); ILIT( 1) -> SLIT("%g1");
- ILIT( 2) -> SLIT("%g2"); ILIT( 3) -> SLIT("%g3");
- ILIT( 4) -> SLIT("%g4"); ILIT( 5) -> SLIT("%g5");
- ILIT( 6) -> SLIT("%g6"); ILIT( 7) -> SLIT("%g7");
- ILIT( 8) -> SLIT("%o0"); ILIT( 9) -> SLIT("%o1");
- ILIT(10) -> SLIT("%o2"); ILIT(11) -> SLIT("%o3");
- ILIT(12) -> SLIT("%o4"); ILIT(13) -> SLIT("%o5");
- ILIT(14) -> SLIT("%o6"); ILIT(15) -> SLIT("%o7");
- ILIT(16) -> SLIT("%l0"); ILIT(17) -> SLIT("%l1");
- ILIT(18) -> SLIT("%l2"); ILIT(19) -> SLIT("%l3");
- ILIT(20) -> SLIT("%l4"); ILIT(21) -> SLIT("%l5");
- ILIT(22) -> SLIT("%l6"); ILIT(23) -> SLIT("%l7");
- ILIT(24) -> SLIT("%i0"); ILIT(25) -> SLIT("%i1");
- ILIT(26) -> SLIT("%i2"); ILIT(27) -> SLIT("%i3");
- ILIT(28) -> SLIT("%i4"); ILIT(29) -> SLIT("%i5");
- ILIT(30) -> SLIT("%i6"); ILIT(31) -> SLIT("%i7");
- ILIT(32) -> SLIT("%f0"); ILIT(33) -> SLIT("%f1");
- ILIT(34) -> SLIT("%f2"); ILIT(35) -> SLIT("%f3");
- ILIT(36) -> SLIT("%f4"); ILIT(37) -> SLIT("%f5");
- ILIT(38) -> SLIT("%f6"); ILIT(39) -> SLIT("%f7");
- ILIT(40) -> SLIT("%f8"); ILIT(41) -> SLIT("%f9");
- ILIT(42) -> SLIT("%f10"); ILIT(43) -> SLIT("%f11");
- ILIT(44) -> SLIT("%f12"); ILIT(45) -> SLIT("%f13");
- ILIT(46) -> SLIT("%f14"); ILIT(47) -> SLIT("%f15");
- ILIT(48) -> SLIT("%f16"); ILIT(49) -> SLIT("%f17");
- ILIT(50) -> SLIT("%f18"); ILIT(51) -> SLIT("%f19");
- ILIT(52) -> SLIT("%f20"); ILIT(53) -> SLIT("%f21");
- ILIT(54) -> SLIT("%f22"); ILIT(55) -> SLIT("%f23");
- ILIT(56) -> SLIT("%f24"); ILIT(57) -> SLIT("%f25");
- ILIT(58) -> SLIT("%f26"); ILIT(59) -> SLIT("%f27");
- ILIT(60) -> SLIT("%f28"); ILIT(61) -> SLIT("%f29");
- ILIT(62) -> SLIT("%f30"); ILIT(63) -> SLIT("%f31");
- _ -> SLIT("very naughty sparc register")
- })
-
-pprCond :: Cond -> Unpretty
-pprCond x = uppPStr
- (case x of {
- ALWAYS -> SLIT(""); NEVER -> SLIT("n");
- GEU -> SLIT("geu"); LU -> SLIT("lu");
- EQ -> SLIT("e"); GT -> SLIT("g");
- GE -> SLIT("ge"); GU -> SLIT("gu");
- LT -> SLIT("l"); LE -> SLIT("le");
- LEU -> SLIT("leu"); NE -> SLIT("ne");
- NEG -> SLIT("neg"); POS -> SLIT("pos");
- VC -> SLIT("vc"); VS -> SLIT("vs")
- })
-
-pprImm :: PprStyle -> Imm -> Unpretty
-
-pprImm sty (ImmInt i) = uppInt i
-pprImm sty (ImmInteger i) = uppInteger i
-
-pprImm sty (LO i) =
- uppBesides [
- pp_lo,
- pprImm sty i,
- uppRparen
- ]
- where
-#ifdef USE_FAST_STRINGS
- pp_lo = uppPStr (_packCString (A# "%lo("#))
-#else
- pp_lo = uppStr "%lo("
-#endif
-
-pprImm sty (HI i) =
- uppBesides [
- pp_hi,
- pprImm sty i,
- uppRparen
- ]
- where
-#ifdef USE_FAST_STRINGS
- pp_hi = uppPStr (_packCString (A# "%hi("#))
-#else
- pp_hi = uppStr "%hi("
-#endif
-
-pprImm sty (ImmCLbl l) = pprCLabel sty l
-
-pprImm (PprForAsm _ False _) (ImmLab s) = s
-pprImm _ (ImmLab s) = uppBeside (uppChar '_') s
-
-pprImm sty (ImmLit s) = s
-
-pprAddr :: PprStyle -> Addr -> Unpretty
-pprAddr sty (AddrRegReg r1 (FixedReg ILIT(0))) = pprReg r1
-
-pprAddr sty (AddrRegReg r1 r2) =
- uppBesides [
- pprReg r1,
- uppChar '+',
- pprReg r2
- ]
-
-pprAddr sty (AddrRegImm r1 (ImmInt i))
- | i == 0 = pprReg r1
- | i < -4096 || i > 4095 = large_offset_error i
- | i < 0 =
- uppBesides [
- pprReg r1,
- uppChar '-',
- uppInt (-i)
- ]
-
-pprAddr sty (AddrRegImm r1 (ImmInteger i))
- | i == 0 = pprReg r1
- | i < -4096 || i > 4095 = large_offset_error i
- | i < 0 =
- uppBesides [
- pprReg r1,
- uppChar '-',
- uppInteger (-i)
- ]
-
-pprAddr sty (AddrRegImm r1 imm) =
- uppBesides [
- pprReg r1,
- uppChar '+',
- pprImm sty imm
- ]
-
-large_offset_error i
- = error ("ERROR: SPARC native-code generator cannot handle large offset ("++show i++");\nprobably because of large constant data structures;\nworkaround: use -fvia-C on this module.\n")
-
-pprRI :: PprStyle -> RI -> Unpretty
-pprRI sty (RIReg r) = pprReg r
-pprRI sty (RIImm r) = pprImm sty r
-
-pprSizeRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Unpretty
-pprSizeRegReg name size reg1 reg2 =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- (case size of
- F -> uppPStr SLIT("s\t")
- DF -> uppPStr SLIT("d\t")),
- pprReg reg1,
- uppComma,
- pprReg reg2
- ]
-
-pprSizeRegRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Reg -> Unpretty
-pprSizeRegRegReg name size reg1 reg2 reg3 =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- (case size of
- F -> uppPStr SLIT("s\t")
- DF -> uppPStr SLIT("d\t")),
- pprReg reg1,
- uppComma,
- pprReg reg2,
- uppComma,
- pprReg reg3
- ]
-
-pprRegRIReg :: PprStyle -> FAST_STRING -> Bool -> Reg -> RI -> Reg -> Unpretty
-pprRegRIReg sty name b reg1 ri reg2 =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- if b then uppPStr SLIT("cc\t") else uppChar '\t',
- pprReg reg1,
- uppComma,
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
-
-pprRIReg :: PprStyle -> FAST_STRING -> Bool -> RI -> Reg -> Unpretty
-pprRIReg sty name b ri reg1 =
- uppBesides [
- uppChar '\t',
- uppPStr name,
- if b then uppPStr SLIT("cc\t") else uppChar '\t',
- pprRI sty ri,
- uppComma,
- pprReg reg1
- ]
-
-pprSize :: Size -> Unpretty
-pprSize x = uppPStr
- (case x of
- SB -> SLIT("sb")
- HW -> SLIT("hw")
- UB -> SLIT("ub")
- UHW -> SLIT("uhw")
- W -> SLIT("")
- F -> SLIT("")
- D -> SLIT("d")
- DF -> SLIT("d")
- )
-
-#ifdef USE_FAST_STRINGS
-pp_ld_lbracket = uppPStr (_packCString (A# "\tld\t["#))
-pp_rbracket_comma = uppPStr (_packCString (A# "],"#))
-pp_comma_lbracket = uppPStr (_packCString (A# ",["#))
-pp_comma_a = uppPStr (_packCString (A# ",a"#))
-#else
-pp_ld_lbracket = uppStr "\tld\t["
-pp_rbracket_comma = uppStr "],"
-pp_comma_lbracket = uppStr ",["
-pp_comma_a = uppStr ",a"
-#endif
-
-pprSparcInstr :: PprStyle -> SparcInstr -> Unpretty
-
--- a clumsy hack for now, to handle possible alignment problems
-
-pprSparcInstr sty (LD DF addr reg) | maybeToBool addrOff =
- uppBesides [
- pp_ld_lbracket,
- pprAddr sty addr,
- pp_rbracket_comma,
- pprReg reg,
-
- uppChar '\n',
- pp_ld_lbracket,
- pprAddr sty addr2,
- pp_rbracket_comma,
- pprReg (fPair reg)
- ]
- where
- addrOff = offset addr 4
- addr2 = case addrOff of Just x -> x
-
-pprSparcInstr sty (LD size addr reg) =
- uppBesides [
- uppPStr SLIT("\tld"),
- pprSize size,
- uppChar '\t',
- uppLbrack,
- pprAddr sty addr,
- pp_rbracket_comma,
- pprReg reg
- ]
-
--- The same clumsy hack as above
-
-pprSparcInstr sty (ST DF reg addr) | maybeToBool addrOff =
- uppBesides [
- uppPStr SLIT("\tst\t"),
- pprReg reg,
- pp_comma_lbracket,
- pprAddr sty addr,
-
- uppPStr SLIT("]\n\tst\t"),
- pprReg (fPair reg),
- pp_comma_lbracket,
- pprAddr sty addr2,
- uppRbrack
- ]
- where
- addrOff = offset addr 4
- addr2 = case addrOff of Just x -> x
-
-pprSparcInstr sty (ST size reg addr) =
- uppBesides [
- uppPStr SLIT("\tst"),
- pprSize size,
- uppChar '\t',
- pprReg reg,
- pp_comma_lbracket,
- pprAddr sty addr,
- uppRbrack
- ]
-
-pprSparcInstr sty (ADD x cc reg1 ri reg2)
- | not x && not cc && riZero ri =
- uppBesides [
- uppPStr SLIT("\tmov\t"),
- pprReg reg1,
- uppComma,
- pprReg reg2
- ]
- | otherwise = pprRegRIReg sty (if x then SLIT("addx") else SLIT("add")) cc reg1 ri reg2
-
-pprSparcInstr sty (SUB x cc reg1 ri reg2)
- | not x && cc && reg2 == g0 =
- uppBesides [
- uppPStr SLIT("\tcmp\t"),
- pprReg reg1,
- uppComma,
- pprRI sty ri
- ]
- | not x && not cc && riZero ri =
- uppBesides [
- uppPStr SLIT("\tmov\t"),
- pprReg reg1,
- uppComma,
- pprReg reg2
- ]
- | otherwise = pprRegRIReg sty (if x then SLIT("subx") else SLIT("sub")) cc reg1 ri reg2
-
-pprSparcInstr sty (AND b reg1 ri reg2) = pprRegRIReg sty SLIT("and") b reg1 ri reg2
-pprSparcInstr sty (ANDN b reg1 ri reg2) = pprRegRIReg sty SLIT("andn") b reg1 ri reg2
-
-pprSparcInstr sty (OR b reg1 ri reg2)
- | not b && reg1 == g0 =
- uppBesides [
- uppPStr SLIT("\tmov\t"),
- pprRI sty ri,
- uppComma,
- pprReg reg2
- ]
- | otherwise = pprRegRIReg sty SLIT("or") b reg1 ri reg2
-
-pprSparcInstr sty (ORN b reg1 ri reg2) = pprRegRIReg sty SLIT("orn") b reg1 ri reg2
-
-pprSparcInstr sty (XOR b reg1 ri reg2) = pprRegRIReg sty SLIT("xor") b reg1 ri reg2
-pprSparcInstr sty (XNOR b reg1 ri reg2) = pprRegRIReg sty SLIT("xnor") b reg1 ri reg2
-
-pprSparcInstr sty (SLL reg1 ri reg2) = pprRegRIReg sty SLIT("sll") False reg1 ri reg2
-pprSparcInstr sty (SRL reg1 ri reg2) = pprRegRIReg sty SLIT("srl") False reg1 ri reg2
-pprSparcInstr sty (SRA reg1 ri reg2) = pprRegRIReg sty SLIT("sra") False reg1 ri reg2
-
-pprSparcInstr sty (SETHI imm reg) =
- uppBesides [
- uppPStr SLIT("\tsethi\t"),
- pprImm sty imm,
- uppComma,
- pprReg reg
- ]
-
-pprSparcInstr sty (NOP) = uppPStr SLIT("\tnop")
-
-pprSparcInstr sty (FABS F reg1 reg2) = pprSizeRegReg SLIT("fabs") F reg1 reg2
-pprSparcInstr sty (FABS DF reg1 reg2) =
- uppBeside (pprSizeRegReg SLIT("fabs") F reg1 reg2)
- (if (reg1 == reg2) then uppNil
- else uppBeside (uppChar '\n')
- (pprSizeRegReg SLIT("fmov") F (fPair reg1) (fPair reg2)))
-
-pprSparcInstr sty (FADD size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("fadd") size reg1 reg2 reg3
-pprSparcInstr sty (FCMP e size reg1 reg2) =
- pprSizeRegReg (if e then SLIT("fcmpe") else SLIT("fcmp")) size reg1 reg2
-pprSparcInstr sty (FDIV size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("fdiv") size reg1 reg2 reg3
-
-pprSparcInstr sty (FMOV F reg1 reg2) = pprSizeRegReg SLIT("fmov") F reg1 reg2
-pprSparcInstr sty (FMOV DF reg1 reg2) =
- uppBeside (pprSizeRegReg SLIT("fmov") F reg1 reg2)
- (if (reg1 == reg2) then uppNil
- else uppBeside (uppChar '\n')
- (pprSizeRegReg SLIT("fmov") F (fPair reg1) (fPair reg2)))
-
-pprSparcInstr sty (FMUL size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("fmul") size reg1 reg2 reg3
-
-pprSparcInstr sty (FNEG F reg1 reg2) = pprSizeRegReg SLIT("fneg") F reg1 reg2
-pprSparcInstr sty (FNEG DF reg1 reg2) =
- uppBeside (pprSizeRegReg SLIT("fneg") F reg1 reg2)
- (if (reg1 == reg2) then uppNil
- else uppBeside (uppChar '\n')
- (pprSizeRegReg SLIT("fmov") F (fPair reg1) (fPair reg2)))
-
-pprSparcInstr sty (FSQRT size reg1 reg2) = pprSizeRegReg SLIT("fsqrt") size reg1 reg2
-pprSparcInstr sty (FSUB size reg1 reg2 reg3) = pprSizeRegRegReg SLIT("fsub") size reg1 reg2 reg3
-pprSparcInstr sty (FxTOy size1 size2 reg1 reg2) =
- uppBesides [
- uppPStr SLIT("\tf"),
- uppPStr
- (case size1 of
- W -> SLIT("ito")
- F -> SLIT("sto")
- DF -> SLIT("dto")),
- uppPStr
- (case size2 of
- W -> SLIT("i\t")
- F -> SLIT("s\t")
- DF -> SLIT("d\t")),
- pprReg reg1,
- uppComma,
- pprReg reg2
- ]
-
-
-pprSparcInstr sty (BI cond b lab) =
- uppBesides [
- uppPStr SLIT("\tb"), pprCond cond,
- if b then pp_comma_a else uppNil,
- uppChar '\t',
- pprImm sty lab
- ]
-
-pprSparcInstr sty (BF cond b lab) =
- uppBesides [
- uppPStr SLIT("\tfb"), pprCond cond,
- if b then pp_comma_a else uppNil,
- uppChar '\t',
- pprImm sty lab
- ]
-
-pprSparcInstr sty (JMP addr) = uppBeside (uppPStr SLIT("\tjmp\t")) (pprAddr sty addr)
-
-pprSparcInstr sty (CALL imm n _) =
- uppBesides [
- uppPStr SLIT("\tcall\t"),
- pprImm sty imm,
- uppComma,
- uppInt n
- ]
-
-pprSparcInstr sty (LABEL clab) =
- uppBesides [
- if (externallyVisibleCLabel clab) then
- uppBesides [uppPStr SLIT("\t.global\t"), pprLab, uppChar '\n']
- else
- uppNil,
- pprLab,
- uppChar ':'
- ]
- where pprLab = pprCLabel sty clab
-
-pprSparcInstr sty (COMMENT s) = uppBeside (uppPStr SLIT("! ")) (uppPStr s)
-
-pprSparcInstr sty (SEGMENT TextSegment)
- = uppPStr SLIT("\t.text\n\t.align 4")
-
-pprSparcInstr sty (SEGMENT DataSegment)
- = uppPStr SLIT("\t.data\n\t.align 8") -- Less than 8 will break double constants
-
-pprSparcInstr sty (ASCII False str) =
- uppBesides [
- uppStr "\t.asciz \"",
- uppStr str,
- uppChar '"'
- ]
-
-pprSparcInstr sty (ASCII True str) = uppBeside (uppStr "\t.ascii \"") (asciify str 60)
- where
- asciify :: String -> Int -> Unpretty
- asciify [] _ = uppStr ("\\0\"")
- asciify s n | n <= 0 = uppBeside (uppStr "\"\n\t.ascii \"") (asciify s 60)
- asciify ('\\':cs) n = uppBeside (uppStr "\\\\") (asciify cs (n-1))
- asciify ('\"':cs) n = uppBeside (uppStr "\\\"") (asciify cs (n-1))
- asciify (c:cs) n | isPrint c = uppBeside (uppChar c) (asciify cs (n-1))
- asciify [c] _ = uppBeside (uppStr (charToC c)) (uppStr ("\\0\""))
- asciify (c:(cs@(d:_))) n | isDigit d =
- uppBeside (uppStr (charToC c)) (asciify cs 0)
- | otherwise =
- uppBeside (uppStr (charToC c)) (asciify cs (n-1))
-
-pprSparcInstr sty (DATA s xs) = uppInterleave (uppChar '\n') (map pp_item xs)
- where pp_item x = case s of
- SB -> uppBeside (uppPStr SLIT("\t.byte\t")) (pprImm sty x)
- UB -> uppBeside (uppPStr SLIT("\t.byte\t")) (pprImm sty x)
- W -> uppBeside (uppPStr SLIT("\t.word\t")) (pprImm sty x)
- DF -> uppBeside (uppPStr SLIT("\t.double\t")) (pprImm sty x)
-
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[Schedule]{Register allocation information}
-%* *
-%************************************************************************
-
-Getting the conflicts right is a bit tedious for doubles. We'd have to
-add a conflict function to the MachineRegisters class, and we'd have to
-put a PrimRep in the MappedReg datatype, or use some kludge (e.g. register
-64 + n is really the same as 32 + n, except that it's used for a double,
-so it also conflicts with 33 + n) to deal with it. It's just not worth the
-bother, so we just partition the free floating point registers into two
-sets: one for single precision and one for double precision. We never seem
-to run out of floating point registers anyway.
-
-\begin{code}
-
-data SparcRegs = SRegs BitSet BitSet BitSet
-
-instance MachineRegisters SparcRegs where
- mkMRegs xs = SRegs (mkBS ints) (mkBS singles') (mkBS doubles')
- where
- (ints, floats) = partition (< 32) xs
- (singles, doubles) = partition (< 48) floats
- singles' = map (subtract 32) singles
- doubles' = map (subtract 32) (filter even doubles)
-
- possibleMRegs FloatRep (SRegs _ singles _) = [ x + 32 | x <- listBS singles]
- possibleMRegs DoubleRep (SRegs _ _ doubles) = [ x + 32 | x <- listBS doubles]
- possibleMRegs _ (SRegs ints _ _) = listBS ints
-
- useMReg (SRegs ints singles doubles) n =
- if n _LT_ ILIT(32) then SRegs (ints `minusBS` singletonBS IBOX(n)) singles doubles
- else if n _LT_ ILIT(48) then SRegs ints (singles `minusBS` singletonBS (IBOX(n _SUB_ ILIT(32)))) doubles
- else SRegs ints singles (doubles `minusBS` singletonBS (IBOX(n _SUB_ ILIT(32))))
-
- useMRegs (SRegs ints singles doubles) xs =
- SRegs (ints `minusBS` ints')
- (singles `minusBS` singles')
- (doubles `minusBS` doubles')
- where
- SRegs ints' singles' doubles' = mkMRegs xs
-
- freeMReg (SRegs ints singles doubles) n =
- if n _LT_ ILIT(32) then SRegs (ints `unionBS` singletonBS IBOX(n)) singles doubles
- else if n _LT_ ILIT(48) then SRegs ints (singles `unionBS` singletonBS (IBOX(n _SUB_ ILIT(32)))) doubles
- else SRegs ints singles (doubles `unionBS` singletonBS (IBOX(n _SUB_ ILIT(32))))
-
- freeMRegs (SRegs ints singles doubles) xs =
- SRegs (ints `unionBS` ints')
- (singles `unionBS` singles')
- (doubles `unionBS` doubles')
- where
- SRegs ints' singles' doubles' = mkMRegs xs
-
-instance MachineCode SparcInstr where
- regUsage = sparcRegUsage
- regLiveness = sparcRegLiveness
- patchRegs = sparcPatchRegs
-
- -- We spill just below the frame pointer, leaving two words per spill location.
- spillReg dyn (MemoryReg i pk) = mkUnitList (ST (kindToSize pk) dyn (fpRel (-2 * i)))
- loadReg (MemoryReg i pk) dyn = mkUnitList (LD (kindToSize pk) (fpRel (-2 * i)) dyn)
-
--- Duznae work for offsets greater than 13 bits; we just hope for the best
-fpRel :: Int -> Addr
-fpRel n = AddrRegImm fp (ImmInt (n * 4))
-
-kindToSize :: PrimRep -> Size
-kindToSize PtrRep = W
-kindToSize CodePtrRep = W
-kindToSize DataPtrRep = W
-kindToSize RetRep = W
-kindToSize CostCentreRep = W
-kindToSize CharRep = UB
-kindToSize IntRep = W
-kindToSize WordRep = W
-kindToSize AddrRep = W
-kindToSize FloatRep = F
-kindToSize DoubleRep = DF
-kindToSize ArrayRep = W
-kindToSize ByteArrayRep = W
-kindToSize StablePtrRep = W
-kindToSize MallocPtrRep = W
-
-\end{code}
-
-@sparcRegUsage@ returns the sets of src and destination registers used by
-a particular instruction. Machine registers that are pre-allocated
-to stgRegs are filtered out, because they are uninteresting from a
-register allocation standpoint. (We wouldn't want them to end up on
-the free list!)
-
-\begin{code}
-
-sparcRegUsage :: SparcInstr -> RegUsage
-sparcRegUsage instr = case instr of
- LD sz addr reg -> usage (regAddr addr, [reg])
- ST sz reg addr -> usage (reg : regAddr addr, [])
- ADD x cc r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SUB x cc r1 ar r2 -> usage (r1 : regRI ar, [r2])
- AND b r1 ar r2 -> usage (r1 : regRI ar, [r2])
- ANDN b r1 ar r2 -> usage (r1 : regRI ar, [r2])
- OR b r1 ar r2 -> usage (r1 : regRI ar, [r2])
- ORN b r1 ar r2 -> usage (r1 : regRI ar, [r2])
- XOR b r1 ar r2 -> usage (r1 : regRI ar, [r2])
- XNOR b r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SLL r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SRL r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SRA r1 ar r2 -> usage (r1 : regRI ar, [r2])
- SETHI imm reg -> usage ([], [reg])
- FABS s r1 r2 -> usage ([r1], [r2])
- FADD s r1 r2 r3 -> usage ([r1, r2], [r3])
- FCMP e s r1 r2 -> usage ([r1, r2], [])
- FDIV s r1 r2 r3 -> usage ([r1, r2], [r3])
- FMOV s r1 r2 -> usage ([r1], [r2])
- FMUL s r1 r2 r3 -> usage ([r1, r2], [r3])
- FNEG s r1 r2 -> usage ([r1], [r2])
- FSQRT s r1 r2 -> usage ([r1], [r2])
- FSUB s r1 r2 r3 -> usage ([r1, r2], [r3])
- FxTOy s1 s2 r1 r2 -> usage ([r1], [r2])
-
- -- We assume that all local jumps will be BI/BF. JMP must be out-of-line.
- JMP addr -> RU (mkUniqSet (filter interesting (regAddr addr))) freeSet
-
- CALL _ n True -> endUsage
- CALL _ n False -> RU (argSet n) callClobberedSet
-
- _ -> noUsage
-
- where
- usage (src, dst) = RU (mkUniqSet (filter interesting src))
- (mkUniqSet (filter interesting dst))
-
- interesting (FixedReg _) = False
- interesting _ = True
-
- regAddr (AddrRegReg r1 r2) = [r1, r2]
- regAddr (AddrRegImm r1 _) = [r1]
-
- regRI (RIReg r) = [r]
- regRI _ = []
-
-freeRegs :: [Reg]
-freeRegs = freeMappedRegs (\ x -> x) [0..63]
-
-freeMappedRegs :: (Int -> Int) -> [Int] -> [Reg]
-
-freeMappedRegs modify nums
- = foldr free [] nums
- where
- free n acc
- = let
- modified_i = case (modify n) of { IBOX(x) -> x }
- in
- if _IS_TRUE_(freeReg modified_i) then (MappedReg modified_i) : acc else acc
-
-freeSet :: UniqSet Reg
-freeSet = mkUniqSet freeRegs
-
-noUsage :: RegUsage
-noUsage = RU emptyUniqSet emptyUniqSet
-
-endUsage :: RegUsage
-endUsage = RU emptyUniqSet freeSet
-
--- Color me CAF-like
-argSet :: Int -> UniqSet Reg
-argSet 0 = emptyUniqSet
-argSet 1 = mkUniqSet (freeMappedRegs oReg [0])
-argSet 2 = mkUniqSet (freeMappedRegs oReg [0,1])
-argSet 3 = mkUniqSet (freeMappedRegs oReg [0,1,2])
-argSet 4 = mkUniqSet (freeMappedRegs oReg [0,1,2,3])
-argSet 5 = mkUniqSet (freeMappedRegs oReg [0,1,2,3,4])
-argSet 6 = mkUniqSet (freeMappedRegs oReg [0,1,2,3,4,5])
-
-callClobberedSet :: UniqSet Reg
-callClobberedSet = mkUniqSet callClobberedRegs
- where
- callClobberedRegs = freeMappedRegs (\x -> x)
- ( oReg 7 :
- [oReg i | i <- [0..5]] ++
- [gReg i | i <- [1..7]] ++
- [fReg i | i <- [0..31]] )
-
-\end{code}
-
-@sparcRegLiveness@ takes future liveness information and modifies it according to
-the semantics of branches and labels. (An out-of-line branch clobbers the liveness
-passed back by the following instruction; a forward local branch passes back the
-liveness from the target label; a conditional branch merges the liveness from the
-target and the liveness from its successor; a label stashes away the current liveness
-in the future liveness environment).
-
-\begin{code}
-sparcRegLiveness :: SparcInstr -> RegLiveness -> RegLiveness
-sparcRegLiveness instr info@(RL live future@(FL all env)) = case instr of
-
- -- We assume that all local jumps will be BI/BF. JMP must be out-of-line.
-
- BI ALWAYS _ (ImmCLbl lbl) -> RL (lookup lbl) future
- BI _ _ (ImmCLbl lbl) -> RL (lookup lbl `unionUniqSets` live) future
- BF ALWAYS _ (ImmCLbl lbl) -> RL (lookup lbl) future
- BF _ _ (ImmCLbl lbl) -> RL (lookup lbl `unionUniqSets` live) future
- JMP _ -> RL emptyUniqSet future
- CALL _ i True -> RL emptyUniqSet future
- CALL _ i False -> RL live future
- LABEL lbl -> RL live (FL (all `unionUniqSets` live) (addToFM env lbl live))
- _ -> info
-
- where
- lookup lbl = case lookupFM env lbl of
- Just regs -> regs
- Nothing -> trace ("Missing " ++ (uppShow 80 (pprCLabel (PprForAsm (\_->False) False id) lbl)) ++
- " in future?") emptyUniqSet
-
-\end{code}
-
-@sparcPatchRegs@ takes an instruction (possibly with MemoryReg/UnmappedReg registers) and
-changes all register references according to the supplied environment.
-
-\begin{code}
-
-sparcPatchRegs :: SparcInstr -> (Reg -> Reg) -> SparcInstr
-sparcPatchRegs instr env = case instr of
- LD sz addr reg -> LD sz (fixAddr addr) (env reg)
- ST sz reg addr -> ST sz (env reg) (fixAddr addr)
- ADD x cc r1 ar r2 -> ADD x cc (env r1) (fixRI ar) (env r2)
- SUB x cc r1 ar r2 -> SUB x cc (env r1) (fixRI ar) (env r2)
- AND b r1 ar r2 -> AND b (env r1) (fixRI ar) (env r2)
- ANDN b r1 ar r2 -> ANDN b (env r1) (fixRI ar) (env r2)
- OR b r1 ar r2 -> OR b (env r1) (fixRI ar) (env r2)
- ORN b r1 ar r2 -> ORN b (env r1) (fixRI ar) (env r2)
- XOR b r1 ar r2 -> XOR b (env r1) (fixRI ar) (env r2)
- XNOR b r1 ar r2 -> XNOR b (env r1) (fixRI ar) (env r2)
- SLL r1 ar r2 -> SLL (env r1) (fixRI ar) (env r2)
- SRL r1 ar r2 -> SRL (env r1) (fixRI ar) (env r2)
- SRA r1 ar r2 -> SRA (env r1) (fixRI ar) (env r2)
- SETHI imm reg -> SETHI imm (env reg)
- FABS s r1 r2 -> FABS s (env r1) (env r2)
- FADD s r1 r2 r3 -> FADD s (env r1) (env r2) (env r3)
- FCMP e s r1 r2 -> FCMP e s (env r1) (env r2)
- FDIV s r1 r2 r3 -> FDIV s (env r1) (env r2) (env r3)
- FMOV s r1 r2 -> FMOV s (env r1) (env r2)
- FMUL s r1 r2 r3 -> FMUL s (env r1) (env r2) (env r3)
- FNEG s r1 r2 -> FNEG s (env r1) (env r2)
- FSQRT s r1 r2 -> FSQRT s (env r1) (env r2)
- FSUB s r1 r2 r3 -> FSUB s (env r1) (env r2) (env r3)
- FxTOy s1 s2 r1 r2 -> FxTOy s1 s2 (env r1) (env r2)
- JMP addr -> JMP (fixAddr addr)
- _ -> instr
-
- where
- fixAddr (AddrRegReg r1 r2) = AddrRegReg (env r1) (env r2)
- fixAddr (AddrRegImm r1 i) = AddrRegImm (env r1) i
-
- fixRI (RIReg r) = RIReg (env r)
- fixRI other = other
-\end{code}
-
-Sometimes, we want to be able to modify addresses at compile time.
-(Okay, just for chrCode of a fetch.)
-
-\begin{code}
-{-# SPECIALIZE
- is13Bits :: Int -> Bool
- #-}
-{-# SPECIALIZE
- is13Bits :: Integer -> Bool
- #-}
-
-is13Bits :: Integral a => a -> Bool
-is13Bits x = x >= -4096 && x < 4096
-
-offset :: Addr -> Int -> Maybe Addr
-
-offset (AddrRegImm reg (ImmInt n)) off
- | is13Bits n2 = Just (AddrRegImm reg (ImmInt n2))
- | otherwise = Nothing
- where n2 = n + off
-
-offset (AddrRegImm reg (ImmInteger n)) off
- | is13Bits n2 = Just (AddrRegImm reg (ImmInt (fromInteger n2)))
- | otherwise = Nothing
- where n2 = n + toInteger off
-
-offset (AddrRegReg reg (FixedReg ILIT(0))) off
- | is13Bits off = Just (AddrRegImm reg (ImmInt off))
- | otherwise = Nothing
-
-offset _ _ = Nothing
-
-\end{code}
-
-If you value your sanity, do not venture below this line.
-
-\begin{code}
-
--- platform.h is generate and tells us what the target architecture is
-#include "../../includes/platform.h"
-#include "../../includes/MachRegs.h"
-#if sunos4_TARGET_OS
-#include "../../includes/sparc-sun-sunos4.h"
-#else
-#include "../../includes/sparc-sun-solaris2.h"
-#endif
-
--- Redefine the literals used for Sparc register names in the header
--- files. Gag me with a spoon, eh?
-
-#define g0 0
-#define g1 1
-#define g2 2
-#define g3 3
-#define g4 4
-#define g5 5
-#define g6 6
-#define g7 7
-#define o0 8
-#define o1 9
-#define o2 10
-#define o3 11
-#define o4 12
-#define o5 13
-#define o6 14
-#define o7 15
-#define l0 16
-#define l1 17
-#define l2 18
-#define l3 19
-#define l4 20
-#define l5 21
-#define l6 22
-#define l7 23
-#define i0 24
-#define i1 25
-#define i2 26
-#define i3 27
-#define i4 28
-#define i5 29
-#define i6 30
-#define i7 31
-#define f0 32
-#define f1 33
-#define f2 34
-#define f3 35
-#define f4 36
-#define f5 37
-#define f6 38
-#define f7 39
-#define f8 40
-#define f9 41
-#define f10 42
-#define f11 43
-#define f12 44
-#define f13 45
-#define f14 46
-#define f15 47
-#define f16 48
-#define f17 49
-#define f18 50
-#define f19 51
-#define f20 52
-#define f21 53
-#define f22 54
-#define f23 55
-#define f24 56
-#define f25 57
-#define f26 58
-#define f27 59
-#define f28 60
-#define f29 61
-#define f30 62
-#define f31 63
-
-baseRegOffset :: MagicId -> Int
-baseRegOffset StkOReg = OFFSET_StkO
-baseRegOffset (VanillaReg _ ILIT2(1)) = OFFSET_R1
-baseRegOffset (VanillaReg _ ILIT2(2)) = OFFSET_R2
-baseRegOffset (VanillaReg _ ILIT2(3)) = OFFSET_R3
-baseRegOffset (VanillaReg _ ILIT2(4)) = OFFSET_R4
-baseRegOffset (VanillaReg _ ILIT2(5)) = OFFSET_R5
-baseRegOffset (VanillaReg _ ILIT2(6)) = OFFSET_R6
-baseRegOffset (VanillaReg _ ILIT2(7)) = OFFSET_R7
-baseRegOffset (VanillaReg _ ILIT2(8)) = OFFSET_R8
-baseRegOffset (FloatReg ILIT2(1)) = OFFSET_Flt1
-baseRegOffset (FloatReg ILIT2(2)) = OFFSET_Flt2
-baseRegOffset (FloatReg ILIT2(3)) = OFFSET_Flt3
-baseRegOffset (FloatReg ILIT2(4)) = OFFSET_Flt4
-baseRegOffset (DoubleReg ILIT2(1)) = OFFSET_Dbl1
-baseRegOffset (DoubleReg ILIT2(2)) = OFFSET_Dbl2
-baseRegOffset TagReg = OFFSET_Tag
-baseRegOffset RetReg = OFFSET_Ret
-baseRegOffset SpA = OFFSET_SpA
-baseRegOffset SuA = OFFSET_SuA
-baseRegOffset SpB = OFFSET_SpB
-baseRegOffset SuB = OFFSET_SuB
-baseRegOffset Hp = OFFSET_Hp
-baseRegOffset HpLim = OFFSET_HpLim
-baseRegOffset LivenessReg = OFFSET_Liveness
---baseRegOffset ActivityReg = OFFSET_Activity
-#ifdef DEBUG
-baseRegOffset BaseReg = panic "baseRegOffset:BaseReg"
-baseRegOffset StdUpdRetVecReg = panic "baseRegOffset:StgUpdRetVecReg"
-baseRegOffset StkStubReg = panic "baseRegOffset:StkStubReg"
-baseRegOffset CurCostCentre = panic "baseRegOffset:CurCostCentre"
-baseRegOffset VoidReg = panic "baseRegOffset:VoidReg"
-#endif
-
-callerSaves :: MagicId -> Bool
-#ifdef CALLER_SAVES_Base
-callerSaves BaseReg = True
-#endif
-#ifdef CALLER_SAVES_StkO
-callerSaves StkOReg = True
-#endif
-#ifdef CALLER_SAVES_R1
-callerSaves (VanillaReg _ ILIT2(1)) = True
-#endif
-#ifdef CALLER_SAVES_R2
-callerSaves (VanillaReg _ ILIT2(2)) = True
-#endif
-#ifdef CALLER_SAVES_R3
-callerSaves (VanillaReg _ ILIT2(3)) = True
-#endif
-#ifdef CALLER_SAVES_R4
-callerSaves (VanillaReg _ ILIT2(4)) = True
-#endif
-#ifdef CALLER_SAVES_R5
-callerSaves (VanillaReg _ ILIT2(5)) = True
-#endif
-#ifdef CALLER_SAVES_R6
-callerSaves (VanillaReg _ ILIT2(6)) = True
-#endif
-#ifdef CALLER_SAVES_R7
-callerSaves (VanillaReg _ ILIT2(7)) = True
-#endif
-#ifdef CALLER_SAVES_R8
-callerSaves (VanillaReg _ ILIT2(8)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg1
-callerSaves (FloatReg ILIT2(1)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg2
-callerSaves (FloatReg ILIT2(2)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg3
-callerSaves (FloatReg ILIT2(3)) = True
-#endif
-#ifdef CALLER_SAVES_FltReg4
-callerSaves (FloatReg ILIT2(4)) = True
-#endif
-#ifdef CALLER_SAVES_DblReg1
-callerSaves (DoubleReg ILIT2(1)) = True
-#endif
-#ifdef CALLER_SAVES_DblReg2
-callerSaves (DoubleReg ILIT2(2)) = True
-#endif
-#ifdef CALLER_SAVES_Tag
-callerSaves TagReg = True
-#endif
-#ifdef CALLER_SAVES_Ret
-callerSaves RetReg = True
-#endif
-#ifdef CALLER_SAVES_SpA
-callerSaves SpA = True
-#endif
-#ifdef CALLER_SAVES_SuA
-callerSaves SuA = True
-#endif
-#ifdef CALLER_SAVES_SpB
-callerSaves SpB = True
-#endif
-#ifdef CALLER_SAVES_SuB
-callerSaves SuB = True
-#endif
-#ifdef CALLER_SAVES_Hp
-callerSaves Hp = True
-#endif
-#ifdef CALLER_SAVES_HpLim
-callerSaves HpLim = True
-#endif
-#ifdef CALLER_SAVES_Liveness
-callerSaves LivenessReg = True
-#endif
-#ifdef CALLER_SAVES_Activity
---callerSaves ActivityReg = True
-#endif
-#ifdef CALLER_SAVES_StdUpdRetVec
-callerSaves StdUpdRetVecReg = True
-#endif
-#ifdef CALLER_SAVES_StkStub
-callerSaves StkStubReg = True
-#endif
-callerSaves _ = False
-
-stgRegMap :: MagicId -> Maybe Reg
-#ifdef REG_Base
-stgRegMap BaseReg = Just (FixedReg ILIT(REG_Base))
-#endif
-#ifdef REG_StkO
-stgRegMap StkOReg = Just (FixedReg ILIT(REG_StkOReg))
-#endif
-#ifdef REG_R1
-stgRegMap (VanillaReg _ ILIT2(1)) = Just (FixedReg ILIT(REG_R1))
-#endif
-#ifdef REG_R2
-stgRegMap (VanillaReg _ ILIT2(2)) = Just (FixedReg ILIT(REG_R2))
-#endif
-#ifdef REG_R3
-stgRegMap (VanillaReg _ ILIT2(3)) = Just (FixedReg ILIT(REG_R3))
-#endif
-#ifdef REG_R4
-stgRegMap (VanillaReg _ ILIT2(4)) = Just (FixedReg ILIT(REG_R4))
-#endif
-#ifdef REG_R5
-stgRegMap (VanillaReg _ ILIT2(5)) = Just (FixedReg ILIT(REG_R5))
-#endif
-#ifdef REG_R6
-stgRegMap (VanillaReg _ ILIT2(6)) = Just (FixedReg ILIT(REG_R6))
-#endif
-#ifdef REG_R7
-stgRegMap (VanillaReg _ ILIT2(7)) = Just (FixedReg ILIT(REG_R7))
-#endif
-#ifdef REG_R8
-stgRegMap (VanillaReg _ ILIT2(8)) = Just (FixedReg ILIT(REG_R8))
-#endif
-#ifdef REG_Flt1
-stgRegMap (FloatReg ILIT2(1)) = Just (FixedReg ILIT(REG_Flt1))
-#endif
-#ifdef REG_Flt2
-stgRegMap (FloatReg ILIT2(2)) = Just (FixedReg ILIT(REG_Flt2))
-#endif
-#ifdef REG_Flt3
-stgRegMap (FloatReg ILIT2(3)) = Just (FixedReg ILIT(REG_Flt3))
-#endif
-#ifdef REG_Flt4
-stgRegMap (FloatReg ILIT2(4)) = Just (FixedReg ILIT(REG_Flt4))
-#endif
-#ifdef REG_Dbl1
-stgRegMap (DoubleReg ILIT2(1)) = Just (FixedReg ILIT(REG_Dbl1))
-#endif
-#ifdef REG_Dbl2
-stgRegMap (DoubleReg ILIT2(2)) = Just (FixedReg ILIT(REG_Dbl2))
-#endif
-#ifdef REG_Tag
-stgRegMap TagReg = Just (FixedReg ILIT(REG_TagReg))
-#endif
-#ifdef REG_Ret
-stgRegMap RetReg = Just (FixedReg ILIT(REG_Ret))
-#endif
-#ifdef REG_SpA
-stgRegMap SpA = Just (FixedReg ILIT(REG_SpA))
-#endif
-#ifdef REG_SuA
-stgRegMap SuA = Just (FixedReg ILIT(REG_SuA))
-#endif
-#ifdef REG_SpB
-stgRegMap SpB = Just (FixedReg ILIT(REG_SpB))
-#endif
-#ifdef REG_SuB
-stgRegMap SuB = Just (FixedReg ILIT(REG_SuB))
-#endif
-#ifdef REG_Hp
-stgRegMap Hp = Just (FixedReg ILIT(REG_Hp))
-#endif
-#ifdef REG_HpLim
-stgRegMap HpLim = Just (FixedReg ILIT(REG_HpLim))
-#endif
-#ifdef REG_Liveness
-stgRegMap LivenessReg = Just (FixedReg ILIT(REG_Liveness))
-#endif
-#ifdef REG_Activity
---stgRegMap ActivityReg = Just (FixedReg ILIT(REG_Activity))
-#endif
-#ifdef REG_StdUpdRetVec
-stgRegMap StdUpdRetVecReg = Just (FixedReg ILIT(REG_StdUpdRetVec))
-#endif
-#ifdef REG_StkStub
-stgRegMap StkStubReg = Just (FixedReg ILIT(REG_StkStub))
-#endif
-stgRegMap _ = Nothing
-
-\end{code}
-
-Here is the list of registers we can use in register allocation.
-
-\begin{code}
-
-freeReg :: FAST_INT -> FAST_BOOL
-
-freeReg ILIT(g0) = _FALSE_ -- %g0 is always 0.
-freeReg ILIT(g5) = _FALSE_ -- %g5 is reserved (ABI).
-freeReg ILIT(g6) = _FALSE_ -- %g6 is reserved (ABI).
-freeReg ILIT(g7) = _FALSE_ -- %g7 is reserved (ABI).
-freeReg ILIT(i6) = _FALSE_ -- %i6 is our frame pointer.
-freeReg ILIT(o6) = _FALSE_ -- %o6 is our stack pointer.
-
-#ifdef REG_Base
-freeReg ILIT(REG_Base) = _FALSE_
-#endif
-#ifdef REG_StkO
-freeReg ILIT(REG_StkO) = _FALSE_
-#endif
-#ifdef REG_R1
-freeReg ILIT(REG_R1) = _FALSE_
-#endif
-#ifdef REG_R2
-freeReg ILIT(REG_R2) = _FALSE_
-#endif
-#ifdef REG_R3
-freeReg ILIT(REG_R3) = _FALSE_
-#endif
-#ifdef REG_R4
-freeReg ILIT(REG_R4) = _FALSE_
-#endif
-#ifdef REG_R5
-freeReg ILIT(REG_R5) = _FALSE_
-#endif
-#ifdef REG_R6
-freeReg ILIT(REG_R6) = _FALSE_
-#endif
-#ifdef REG_R7
-freeReg ILIT(REG_R7) = _FALSE_
-#endif
-#ifdef REG_R8
-freeReg ILIT(REG_R8) = _FALSE_
-#endif
-#ifdef REG_Flt1
-freeReg ILIT(REG_Flt1) = _FALSE_
-#endif
-#ifdef REG_Flt2
-freeReg ILIT(REG_Flt2) = _FALSE_
-#endif
-#ifdef REG_Flt3
-freeReg ILIT(REG_Flt3) = _FALSE_
-#endif
-#ifdef REG_Flt4
-freeReg ILIT(REG_Flt4) = _FALSE_
-#endif
-#ifdef REG_Dbl1
-freeReg ILIT(REG_Dbl1) = _FALSE_
-#endif
-#ifdef REG_Dbl2
-freeReg ILIT(REG_Dbl2) = _FALSE_
-#endif
-#ifdef REG_Tag
-freeReg ILIT(REG_Tag) = _FALSE_
-#endif
-#ifdef REG_Ret
-freeReg ILIT(REG_Ret) = _FALSE_
-#endif
-#ifdef REG_SpA
-freeReg ILIT(REG_SpA) = _FALSE_
-#endif
-#ifdef REG_SuA
-freeReg ILIT(REG_SuA) = _FALSE_
-#endif
-#ifdef REG_SpB
-freeReg ILIT(REG_SpB) = _FALSE_
-#endif
-#ifdef REG_SuB
-freeReg ILIT(REG_SuB) = _FALSE_
-#endif
-#ifdef REG_Hp
-freeReg ILIT(REG_Hp) = _FALSE_
-#endif
-#ifdef REG_HpLim
-freeReg ILIT(REG_HpLim) = _FALSE_
-#endif
-#ifdef REG_Liveness
-freeReg ILIT(REG_Liveness) = _FALSE_
-#endif
-#ifdef REG_Activity
---freeReg ILIT(REG_Activity) = _FALSE_
-#endif
-#ifdef REG_StdUpdRetVec
-freeReg ILIT(REG_StdUpdRetVec) = _FALSE_
-#endif
-#ifdef REG_StkStub
-freeReg ILIT(REG_StkStub) = _FALSE_
-#endif
-freeReg n
-#ifdef REG_Dbl1
- | n _EQ_ (ILIT(REG_Dbl1) _ADD_ ILIT(1)) = _FALSE_
-#endif
-#ifdef REG_Dbl2
- | n _EQ_ (ILIT(REG_Dbl2) _ADD_ ILIT(1)) = _FALSE_
-#endif
- | otherwise = _TRUE_
-
-reservedRegs :: [Int]
-reservedRegs = [NCG_Reserved_I1, NCG_Reserved_I2,
- NCG_Reserved_F1, NCG_Reserved_F2,
- NCG_Reserved_D1, NCG_Reserved_D2]
-
-\end{code}
-
+++ /dev/null
-%
-% (c) The AQUA Project, Glasgow University, 1994-1995
-%
-\section[SparcDesc]{The Sparc Machine Description}
-
-\begin{code}
-#include "HsVersions.h"
-
-module SparcDesc (
- mkSparc
-
- -- and assorted nonsense referenced by the class methods
- ) where
-
-import AbsCSyn
-import PrelInfo ( PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import AsmRegAlloc ( Reg, MachineCode(..), MachineRegisters(..),
- RegLiveness(..), RegUsage(..), FutureLive(..)
- )
-import CLabel ( CLabel )
-import CmdLineOpts ( GlobalSwitch(..), stringSwitchSet, switchIsOn, SwitchResult(..) )
-import HeapOffs ( hpRelToInt )
-import MachDesc
-import Maybes ( Maybe(..) )
-import OrdList
-import Outputable
-import SMRep ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..) )
-import SparcCode
-import SparcGen ( sparcCodeGen )
-import Stix
-import StixMacro
-import StixPrim
-import UniqSupply
-import Util
-\end{code}
-
-Header sizes depend only on command-line options, not on the target
-architecture. (I think.)
-
-\begin{code}
-
-fhs :: (GlobalSwitch -> SwitchResult) -> Int
-
-fhs switches = 1 + profFHS + ageFHS
- where
- profFHS = if switchIsOn switches SccProfilingOn then 1 else 0
- ageFHS = if switchIsOn switches SccProfilingOn then 1 else 0
-
-vhs :: (GlobalSwitch -> SwitchResult) -> SMRep -> Int
-
-vhs switches sm = case sm of
- StaticRep _ _ -> 0
- SpecialisedRep _ _ _ _ -> 0
- GenericRep _ _ _ -> 0
- BigTupleRep _ -> 1
- MuTupleRep _ -> 2 {- (1 + GC_MUT_RESERVED_WORDS) -}
- DataRep _ -> 1
- DynamicRep -> 2
- BlackHoleRep -> 0
- PhantomRep -> panic "vhs:phantom"
-
-\end{code}
-
-Here we map STG registers onto appropriate Stix Trees. First, we
-handle the two constants, @STK_STUB_closure@ and @vtbl_StdUpdFrame@.
-The rest are either in real machine registers or stored as offsets
-from BaseReg.
-
-\begin{code}
-
-sparcReg :: (GlobalSwitch -> SwitchResult) -> MagicId -> RegLoc
-
-sparcReg switches x =
- case stgRegMap x of
- Just reg -> Save nonReg
- Nothing -> Always nonReg
- where nonReg = case x of
- StkStubReg -> sStLitLbl SLIT("STK_STUB_closure")
- StdUpdRetVecReg -> sStLitLbl SLIT("vtbl_StdUpdFrame")
- BaseReg -> sStLitLbl SLIT("MainRegTable")
- Hp -> StInd PtrRep (sStLitLbl SLIT("StorageMgrInfo"))
- HpLim -> StInd PtrRep (sStLitLbl SLIT("StorageMgrInfo+4"))
- TagReg -> StInd IntRep (StPrim IntSubOp [infoptr, StInt (1*4)])
- where
- r2 = VanillaReg PtrRep ILIT(2)
- infoptr = case sparcReg switches r2 of
- Always tree -> tree
- Save _ -> StReg (StixMagicId r2)
- _ -> StInd (kindFromMagicId x)
- (StPrim IntAddOp [baseLoc, StInt (toInteger (offset*4))])
- baseLoc = case stgRegMap BaseReg of
- Just _ -> StReg (StixMagicId BaseReg)
- Nothing -> sStLitLbl SLIT("MainRegTable")
- offset = baseRegOffset x
-
-\end{code}
-
-Sizes in bytes.
-
-\begin{code}
-
-size pk = case kindToSize pk of
- {SB -> 1; UB -> 1; HW -> 2; UHW -> 2; W -> 4; D -> 8; F -> 4; DF -> 8}
-
-\end{code}
-
-Now the volatile saves and restores. We add the basic guys to the list of ``user''
-registers provided. Note that there are more basic registers on the restore list,
-because some are reloaded from constants.
-
-\begin{code}
-
-vsaves switches vols =
- map save ((filter callerSaves) ([BaseReg,SpA,SuA,SpB,SuB,Hp,HpLim,RetReg{-,ActivityReg-}] ++ vols))
- where
- save x = StAssign (kindFromMagicId x) loc reg
- where reg = StReg (StixMagicId x)
- loc = case sparcReg switches x of
- Save loc -> loc
- Always loc -> panic "vsaves"
-
-vrests switches vols =
- map restore ((filter callerSaves)
- ([BaseReg,SpA,SuA,SpB,SuB,Hp,HpLim,RetReg{-,ActivityReg-},StkStubReg,StdUpdRetVecReg] ++ vols))
- where
- restore x = StAssign (kindFromMagicId x) reg loc
- where reg = StReg (StixMagicId x)
- loc = case sparcReg switches x of
- Save loc -> loc
- Always loc -> panic "vrests"
-
-\end{code}
-
-Static closure sizes.
-
-\begin{code}
-
-charLikeSize, intLikeSize :: Target -> Int
-
-charLikeSize target =
- size PtrRep * (fixedHeaderSize target + varHeaderSize target charLikeRep + 1)
- where charLikeRep = SpecialisedRep CharLikeRep 0 1 SMNormalForm
-
-intLikeSize target =
- size PtrRep * (fixedHeaderSize target + varHeaderSize target intLikeRep + 1)
- where intLikeRep = SpecialisedRep IntLikeRep 0 1 SMNormalForm
-
-mhs, dhs :: (GlobalSwitch -> SwitchResult) -> StixTree
-
-mhs switches = StInt (toInteger words)
- where
- words = fhs switches + vhs switches (MuTupleRep 0)
-
-dhs switches = StInt (toInteger words)
- where
- words = fhs switches + vhs switches (DataRep 0)
-
-\end{code}
-
-Setting up a sparc target.
-
-\begin{code}
-
-mkSparc :: Bool
- -> (GlobalSwitch -> SwitchResult)
- -> (Target,
- (PprStyle -> [[StixTree]] -> UniqSM Unpretty), -- codeGen
- Bool, -- underscore
- (String -> String)) -- fmtAsmLbl
-
-mkSparc decentOS switches =
- let
- fhs' = fhs switches
- vhs' = vhs switches
- sparcReg' = sparcReg switches
- vsaves' = vsaves switches
- vrests' = vrests switches
- hprel = hpRelToInt target
- as = amodeCode target
- as' = amodeCode' target
- csz = charLikeSize target
- isz = intLikeSize target
- mhs' = mhs switches
- dhs' = dhs switches
- ps = genPrimCode target
- mc = genMacroCode target
- hc = doHeapCheck
- target = mkTarget {-switches-} fhs' vhs' sparcReg' {-id-} size
- hprel as as'
- (vsaves', vrests', csz, isz, mhs', dhs', ps, mc, hc)
- {-sparcCodeGen decentOS id-}
- in
- (target, sparcCodeGen, decentOS, id)
-\end{code}
+++ /dev/null
-%
-% (c) The AQUA Project, Glasgow University, 1993-1995
-%
-
-\begin{code}
-#include "HsVersions.h"
-
-module SparcGen (
- sparcCodeGen,
-
- -- and, for self-sufficiency
- PprStyle, StixTree, CSeq
- ) where
-
-IMPORT_Trace
-
-import AbsCSyn ( AbstractC, MagicId(..), kindFromMagicId )
-import PrelInfo ( PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import AsmRegAlloc ( runRegAllocate, mkReg, extractMappedRegNos,
- Reg(..), RegLiveness(..), RegUsage(..),
- FutureLive(..), MachineRegisters(..), MachineCode(..)
- )
-import CLabel ( CLabel, isAsmTemp )
-import SparcCode {- everything -}
-import MachDesc
-import Maybes ( maybeToBool, Maybe(..) )
-import OrdList -- ( mkEmptyList, mkUnitList, mkSeqList, mkParList, OrdList )
-import Outputable
-import SparcDesc
-import Stix
-import UniqSupply
-import Pretty
-import Unpretty
-import Util
-
-type CodeBlock a = (OrdList a -> OrdList a)
-\end{code}
-
-%************************************************************************
-%* *
-\subsection[SparcCodeGen]{Generating Sparc Code}
-%* *
-%************************************************************************
-
-This is the top-level code-generation function for the Sparc.
-
-\begin{code}
-
-sparcCodeGen :: PprStyle -> [[StixTree]] -> UniqSM Unpretty
-sparcCodeGen sty trees =
- mapUs genSparcCode trees `thenUs` \ dynamicCodes ->
- let
- staticCodes = scheduleSparcCode dynamicCodes
- pretty = printLabeledCodes sty staticCodes
- in
- returnUs pretty
-
-\end{code}
-
-This bit does the code scheduling. The scheduler must also deal with
-register allocation of temporaries. Much parallelism can be exposed via
-the OrdList, but more might occur, so further analysis might be needed.
-
-\begin{code}
-
-scheduleSparcCode :: [SparcCode] -> [SparcInstr]
-scheduleSparcCode = concat . map (runRegAllocate freeSparcRegs reservedRegs)
- where
- freeSparcRegs :: SparcRegs
- freeSparcRegs = mkMRegs (extractMappedRegNos freeRegs)
-
-
-\end{code}
-
-Registers passed up the tree. If the stix code forces the register
-to live in a pre-decided machine register, it comes out as @Fixed@;
-otherwise, it comes out as @Any@, and the parent can decide which
-register to put it in.
-
-\begin{code}
-
-data Register
- = Fixed Reg PrimRep (CodeBlock SparcInstr)
- | Any PrimRep (Reg -> (CodeBlock SparcInstr))
-
-registerCode :: Register -> Reg -> CodeBlock SparcInstr
-registerCode (Fixed _ _ code) reg = code
-registerCode (Any _ code) reg = code reg
-
-registerName :: Register -> Reg -> Reg
-registerName (Fixed reg _ _) _ = reg
-registerName (Any _ _) reg = reg
-
-registerKind :: Register -> PrimRep
-registerKind (Fixed _ pk _) = pk
-registerKind (Any pk _) = pk
-
-isFixed :: Register -> Bool
-isFixed (Fixed _ _ _) = True
-isFixed (Any _ _) = False
-
-\end{code}
-
-Memory addressing modes passed up the tree.
-
-\begin{code}
-
-data Amode = Amode Addr (CodeBlock SparcInstr)
-
-amodeAddr (Amode addr _) = addr
-amodeCode (Amode _ code) = code
-
-\end{code}
-
-Condition codes passed up the tree.
-
-\begin{code}
-
-data Condition = Condition Bool Cond (CodeBlock SparcInstr)
-
-condName (Condition _ cond _) = cond
-condFloat (Condition float _ _) = float
-condCode (Condition _ _ code) = code
-
-\end{code}
-
-General things for putting together code sequences.
-
-\begin{code}
-
-asmVoid :: OrdList SparcInstr
-asmVoid = mkEmptyList
-
-asmInstr :: SparcInstr -> SparcCode
-asmInstr i = mkUnitList i
-
-asmSeq :: [SparcInstr] -> SparcCode
-asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
-
-asmParThen :: [SparcCode] -> (CodeBlock SparcInstr)
-asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
-
-returnInstr :: SparcInstr -> UniqSM (CodeBlock SparcInstr)
-returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
-
-returnInstrs :: [SparcInstr] -> UniqSM (CodeBlock SparcInstr)
-returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
-
-returnSeq :: (CodeBlock SparcInstr) -> [SparcInstr] -> UniqSM (CodeBlock SparcInstr)
-returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
-
-mkSeqInstr :: SparcInstr -> (CodeBlock SparcInstr)
-mkSeqInstr instr code = mkSeqList (asmInstr instr) code
-
-mkSeqInstrs :: [SparcInstr] -> (CodeBlock SparcInstr)
-mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
-
-\end{code}
-
-Top level sparc code generator for a chunk of stix code.
-
-\begin{code}
-
-genSparcCode :: [StixTree] -> UniqSM (SparcCode)
-
-genSparcCode trees =
- mapUs getCode trees `thenUs` \ blocks ->
- returnUs (foldr (.) id blocks asmVoid)
-
-\end{code}
-
-Code extractor for an entire stix tree---stix statement level.
-
-\begin{code}
-
-getCode
- :: StixTree -- a stix statement
- -> UniqSM (CodeBlock SparcInstr)
-
-getCode (StSegment seg) = returnInstr (SEGMENT seg)
-
-getCode (StAssign pk dst src)
- | isFloatingRep pk = assignFltCode pk dst src
- | otherwise = assignIntCode pk dst src
-
-getCode (StLabel lab) = returnInstr (LABEL lab)
-
-getCode (StFunBegin lab) = returnInstr (LABEL lab)
-
-getCode (StFunEnd lab) = returnUs id
-
-getCode (StJump arg) = genJump arg
-
-getCode (StFallThrough lbl) = returnUs id
-
-getCode (StCondJump lbl arg) = genCondJump lbl arg
-
-getCode (StData kind args) =
- mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
- returnUs (\xs -> mkSeqList (asmInstr (DATA (kindToSize kind) imms))
- (foldr1 (.) codes xs))
- where
- getData :: StixTree -> UniqSM (CodeBlock SparcInstr, Imm)
- getData (StInt i) = returnUs (id, ImmInteger i)
- getData (StDouble d) = returnUs (id, strImmLit ('0' : 'r' : ppShow 80 (ppRational d)))
- getData (StLitLbl s) = returnUs (id, ImmLab s)
- getData (StLitLit s) = returnUs (id, strImmLit (cvtLitLit (_UNPK_ s)))
- getData (StString s) =
- getUniqLabelNCG `thenUs` \ lbl ->
- returnUs (mkSeqInstrs [LABEL lbl, ASCII True (_UNPK_ s)], ImmCLbl lbl)
- getData (StCLbl l) = returnUs (id, ImmCLbl l)
-
-getCode (StCall fn VoidRep args) = genCCall fn VoidRep args
-
-getCode (StComment s) = returnInstr (COMMENT s)
-
-\end{code}
-
-Generate code to get a subtree into a register.
-
-\begin{code}
-
-getReg :: StixTree -> UniqSM Register
-
-getReg (StReg (StixMagicId stgreg)) =
- case stgRegMap stgreg of
- Just reg -> returnUs (Fixed reg (kindFromMagicId stgreg) id)
- -- cannae be Nothing
-
-getReg (StReg (StixTemp u pk)) = returnUs (Fixed (UnmappedReg u pk) pk id)
-
-getReg (StDouble d) =
- getUniqLabelNCG `thenUs` \ lbl ->
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- let code dst = mkSeqInstrs [
- SEGMENT DataSegment,
- LABEL lbl,
- DATA DF [strImmLit ('0' : 'r' : ppShow 80 (ppRational d))],
- SEGMENT TextSegment,
- SETHI (HI (ImmCLbl lbl)) tmp,
- LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
- in
- returnUs (Any DoubleRep code)
-
-getReg (StString s) =
- getUniqLabelNCG `thenUs` \ lbl ->
- let code dst = mkSeqInstrs [
- SEGMENT DataSegment,
- LABEL lbl,
- ASCII True (_UNPK_ s),
- SEGMENT TextSegment,
- SETHI (HI (ImmCLbl lbl)) dst,
- OR False dst (RIImm (LO (ImmCLbl lbl))) dst]
- in
- returnUs (Any PtrRep code)
-
-getReg (StLitLit s) | _HEAD_ s == '"' && last xs == '"' =
- getUniqLabelNCG `thenUs` \ lbl ->
- let code dst = mkSeqInstrs [
- SEGMENT DataSegment,
- LABEL lbl,
- ASCII False (init xs),
- SEGMENT TextSegment,
- SETHI (HI (ImmCLbl lbl)) dst,
- OR False dst (RIImm (LO (ImmCLbl lbl))) dst]
- in
- returnUs (Any PtrRep code)
- where
- xs = _UNPK_ (_TAIL_ s)
-
-getReg tree@(StIndex _ _ _) = getReg (mangleIndexTree tree)
-
-getReg (StCall fn kind args) =
- genCCall fn kind args `thenUs` \ call ->
- returnUs (Fixed reg kind call)
- where
- reg = if isFloatingRep kind then f0 else o0
-
-getReg (StPrim primop args) =
- case primop of
-
- CharGtOp -> condIntReg GT args
- CharGeOp -> condIntReg GE args
- CharEqOp -> condIntReg EQ args
- CharNeOp -> condIntReg NE args
- CharLtOp -> condIntReg LT args
- CharLeOp -> condIntReg LE args
-
- IntAddOp -> trivialCode (ADD False False) args
-
- IntSubOp -> trivialCode (SUB False False) args
- IntMulOp -> call SLIT(".umul") IntRep
- IntQuotOp -> call SLIT(".div") IntRep
- IntRemOp -> call SLIT(".rem") IntRep
- IntNegOp -> trivialUCode (SUB False False g0) args
- IntAbsOp -> absIntCode args
-
- AndOp -> trivialCode (AND False) args
- OrOp -> trivialCode (OR False) args
- NotOp -> trivialUCode (XNOR False g0) args
- SllOp -> trivialCode SLL args
- SraOp -> trivialCode SRA args
- SrlOp -> trivialCode SRL args
- ISllOp -> panic "SparcGen:isll"
- ISraOp -> panic "SparcGen:isra"
- ISrlOp -> panic "SparcGen:isrl"
-
- IntGtOp -> condIntReg GT args
- IntGeOp -> condIntReg GE args
- IntEqOp -> condIntReg EQ args
- IntNeOp -> condIntReg NE args
- IntLtOp -> condIntReg LT args
- IntLeOp -> condIntReg LE args
-
- WordGtOp -> condIntReg GU args
- WordGeOp -> condIntReg GEU args
- WordEqOp -> condIntReg EQ args
- WordNeOp -> condIntReg NE args
- WordLtOp -> condIntReg LU args
- WordLeOp -> condIntReg LEU args
-
- AddrGtOp -> condIntReg GU args
- AddrGeOp -> condIntReg GEU args
- AddrEqOp -> condIntReg EQ args
- AddrNeOp -> condIntReg NE args
- AddrLtOp -> condIntReg LU args
- AddrLeOp -> condIntReg LEU args
-
- FloatAddOp -> trivialFCode FloatRep FADD args
- FloatSubOp -> trivialFCode FloatRep FSUB args
- FloatMulOp -> trivialFCode FloatRep FMUL args
- FloatDivOp -> trivialFCode FloatRep FDIV args
- FloatNegOp -> trivialUFCode FloatRep (FNEG F) args
-
- FloatGtOp -> condFltReg GT args
- FloatGeOp -> condFltReg GE args
- FloatEqOp -> condFltReg EQ args
- FloatNeOp -> condFltReg NE args
- FloatLtOp -> condFltReg LT args
- FloatLeOp -> condFltReg LE args
-
- FloatExpOp -> promoteAndCall SLIT("exp") DoubleRep
- FloatLogOp -> promoteAndCall SLIT("log") DoubleRep
- FloatSqrtOp -> promoteAndCall SLIT("sqrt") DoubleRep
-
- FloatSinOp -> promoteAndCall SLIT("sin") DoubleRep
- FloatCosOp -> promoteAndCall SLIT("cos") DoubleRep
- FloatTanOp -> promoteAndCall SLIT("tan") DoubleRep
-
- FloatAsinOp -> promoteAndCall SLIT("asin") DoubleRep
- FloatAcosOp -> promoteAndCall SLIT("acos") DoubleRep
- FloatAtanOp -> promoteAndCall SLIT("atan") DoubleRep
-
- FloatSinhOp -> promoteAndCall SLIT("sinh") DoubleRep
- FloatCoshOp -> promoteAndCall SLIT("cosh") DoubleRep
- FloatTanhOp -> promoteAndCall SLIT("tanh") DoubleRep
-
- FloatPowerOp -> promoteAndCall SLIT("pow") DoubleRep
-
- DoubleAddOp -> trivialFCode DoubleRep FADD args
- DoubleSubOp -> trivialFCode DoubleRep FSUB args
- DoubleMulOp -> trivialFCode DoubleRep FMUL args
- DoubleDivOp -> trivialFCode DoubleRep FDIV args
- DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) args
-
- DoubleGtOp -> condFltReg GT args
- DoubleGeOp -> condFltReg GE args
- DoubleEqOp -> condFltReg EQ args
- DoubleNeOp -> condFltReg NE args
- DoubleLtOp -> condFltReg LT args
- DoubleLeOp -> condFltReg LE args
-
- DoubleExpOp -> call SLIT("exp") DoubleRep
- DoubleLogOp -> call SLIT("log") DoubleRep
- DoubleSqrtOp -> call SLIT("sqrt") DoubleRep
-
- DoubleSinOp -> call SLIT("sin") DoubleRep
- DoubleCosOp -> call SLIT("cos") DoubleRep
- DoubleTanOp -> call SLIT("tan") DoubleRep
-
- DoubleAsinOp -> call SLIT("asin") DoubleRep
- DoubleAcosOp -> call SLIT("acos") DoubleRep
- DoubleAtanOp -> call SLIT("atan") DoubleRep
-
- DoubleSinhOp -> call SLIT("sinh") DoubleRep
- DoubleCoshOp -> call SLIT("cosh") DoubleRep
- DoubleTanhOp -> call SLIT("tanh") DoubleRep
-
- DoublePowerOp -> call SLIT("pow") DoubleRep
-
- OrdOp -> coerceIntCode IntRep args
- ChrOp -> chrCode args
-
- Float2IntOp -> coerceFP2Int args
- Int2FloatOp -> coerceInt2FP FloatRep args
- Double2IntOp -> coerceFP2Int args
- Int2DoubleOp -> coerceInt2FP DoubleRep args
-
- Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) args
- Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) args
-
- where
- call fn pk = getReg (StCall fn pk args)
- promoteAndCall fn pk = getReg (StCall fn pk (map promote args))
- where
- promote x = StPrim Float2DoubleOp [x]
-
-getReg (StInd pk mem) =
- getAmode mem `thenUs` \ amode ->
- let
- code = amodeCode amode
- src = amodeAddr amode
- size = kindToSize pk
- code__2 dst = code . mkSeqInstr (LD size src dst)
- in
- returnUs (Any pk code__2)
-
-getReg (StInt i)
- | is13Bits i =
- let
- src = ImmInt (fromInteger i)
- code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
- in
- returnUs (Any IntRep code)
-
-getReg leaf
- | maybeToBool imm =
- let
- code dst = mkSeqInstrs [
- SETHI (HI imm__2) dst,
- OR False dst (RIImm (LO imm__2)) dst]
- in
- returnUs (Any PtrRep code)
- where
- imm = maybeImm leaf
- imm__2 = case imm of Just x -> x
-
-\end{code}
-
-Now, given a tree (the argument to an StInd) that references memory,
-produce a suitable addressing mode.
-
-\begin{code}
-
-getAmode :: StixTree -> UniqSM Amode
-
-getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
-
-getAmode (StPrim IntSubOp [x, StInt i])
- | is13Bits (-i) =
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- getReg x `thenUs` \ register ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- off = ImmInt (-(fromInteger i))
- in
- returnUs (Amode (AddrRegImm reg off) code)
-
-
-getAmode (StPrim IntAddOp [x, StInt i])
- | is13Bits i =
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- getReg x `thenUs` \ register ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- off = ImmInt (fromInteger i)
- in
- returnUs (Amode (AddrRegImm reg off) code)
-
-getAmode (StPrim IntAddOp [x, y]) =
- getNewRegNCG PtrRep `thenUs` \ tmp1 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- reg1 = registerName register1 tmp1
- code2 = registerCode register2 tmp2 asmVoid
- reg2 = registerName register2 tmp2
- code__2 = asmParThen [code1, code2]
- in
- returnUs (Amode (AddrRegReg reg1 reg2) code__2)
-
-getAmode leaf
- | maybeToBool imm =
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- let
- code = mkSeqInstr (SETHI (HI imm__2) tmp)
- in
- returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
- where
- imm = maybeImm leaf
- imm__2 = case imm of Just x -> x
-
-getAmode other =
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- getReg other `thenUs` \ register ->
- let
- code = registerCode register tmp
- reg = registerName register tmp
- off = ImmInt 0
- in
- returnUs (Amode (AddrRegImm reg off) code)
-
-\end{code}
-
-Try to get a value into a specific register (or registers) for a call. The Sparc
-calling convention is an absolute nightmare. The first 6x32 bits of arguments are
-mapped into %o0 through %o5, and the remaining arguments are dumped to the stack,
-beginning at [%sp+92]. (Note that %o6 == %sp.) Our first argument is a pair of
-the list of remaining argument registers to be assigned for this call and the next
-stack offset to use for overflowing arguments. This way, @getCallArg@ can be applied
-to all of a call's arguments using @mapAccumL@.
-
-\begin{code}
-
-getCallArg
- :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
- -> StixTree -- Current argument
- -> UniqSM (([Reg],Int), CodeBlock SparcInstr) -- Updated accumulator and code
-
--- We have to use up all of our argument registers first.
-
-getCallArg (dst:dsts, offset) arg =
- getReg arg `thenUs` \ register ->
- getNewRegNCG (registerKind register)
- `thenUs` \ tmp ->
- let
- reg = if isFloatingRep pk then tmp else dst
- code = registerCode register reg
- src = registerName register reg
- pk = registerKind register
- in
- returnUs (case pk of
- DoubleRep ->
- case dsts of
- [] -> (([], offset + 1), code . mkSeqInstrs [
- -- conveniently put the second part in the right stack
- -- location, and load the first part into %o5
- ST DF src (spRel (offset - 1)),
- LD W (spRel (offset - 1)) dst])
- (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
- ST DF src (spRel (-2)),
- LD W (spRel (-2)) dst,
- LD W (spRel (-1)) dst__2])
- FloatRep -> ((dsts, offset), code . mkSeqInstrs [
- ST F src (spRel (-2)),
- LD W (spRel (-2)) dst])
- _ -> ((dsts, offset), if isFixed register then
- code . mkSeqInstr (OR False g0 (RIReg src) dst)
- else code))
-
--- Once we have run out of argument registers, we move to the stack
-
-getCallArg ([], offset) arg =
- getReg arg `thenUs` \ register ->
- getNewRegNCG (registerKind register)
- `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
- pk = registerKind register
- sz = kindToSize pk
- words = if pk == DoubleRep then 2 else 1
- in
- returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
-
-\end{code}
-
-Set up a condition code for a conditional branch.
-
-\begin{code}
-
-getCondition :: StixTree -> UniqSM Condition
-
-getCondition (StPrim primop args) =
- case primop of
-
- CharGtOp -> condIntCode GT args
- CharGeOp -> condIntCode GE args
- CharEqOp -> condIntCode EQ args
- CharNeOp -> condIntCode NE args
- CharLtOp -> condIntCode LT args
- CharLeOp -> condIntCode LE args
-
- IntGtOp -> condIntCode GT args
- IntGeOp -> condIntCode GE args
- IntEqOp -> condIntCode EQ args
- IntNeOp -> condIntCode NE args
- IntLtOp -> condIntCode LT args
- IntLeOp -> condIntCode LE args
-
- WordGtOp -> condIntCode GU args
- WordGeOp -> condIntCode GEU args
- WordEqOp -> condIntCode EQ args
- WordNeOp -> condIntCode NE args
- WordLtOp -> condIntCode LU args
- WordLeOp -> condIntCode LEU args
-
- AddrGtOp -> condIntCode GU args
- AddrGeOp -> condIntCode GEU args
- AddrEqOp -> condIntCode EQ args
- AddrNeOp -> condIntCode NE args
- AddrLtOp -> condIntCode LU args
- AddrLeOp -> condIntCode LEU args
-
- FloatGtOp -> condFltCode GT args
- FloatGeOp -> condFltCode GE args
- FloatEqOp -> condFltCode EQ args
- FloatNeOp -> condFltCode NE args
- FloatLtOp -> condFltCode LT args
- FloatLeOp -> condFltCode LE args
-
- DoubleGtOp -> condFltCode GT args
- DoubleGeOp -> condFltCode GE args
- DoubleEqOp -> condFltCode EQ args
- DoubleNeOp -> condFltCode NE args
- DoubleLtOp -> condFltCode LT args
- DoubleLeOp -> condFltCode LE args
-
-\end{code}
-
-Turn a boolean expression into a condition, to be passed
-back up the tree.
-
-\begin{code}
-
-condIntCode, condFltCode :: Cond -> [StixTree] -> UniqSM Condition
-
-condIntCode cond [x, StInt y]
- | is13Bits y =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src1 = registerName register tmp
- src2 = ImmInt (fromInteger y)
- code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
- in
- returnUs (Condition False cond code__2)
-
-condIntCode cond [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 = asmParThen [code1, code2] .
- mkSeqInstr (SUB False True src1 (RIReg src2) g0)
- in
- returnUs (Condition False cond code__2)
-
-condFltCode cond [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG (registerKind register1)
- `thenUs` \ tmp1 ->
- getNewRegNCG (registerKind register2)
- `thenUs` \ tmp2 ->
- getNewRegNCG DoubleRep `thenUs` \ tmp ->
- let
- promote x = asmInstr (FxTOy F DF x tmp)
-
- pk1 = registerKind register1
- code1 = registerCode register1 tmp1
- src1 = registerName register1 tmp1
-
- pk2 = registerKind register2
- code2 = registerCode register2 tmp2
- src2 = registerName register2 tmp2
-
- code__2 =
- if pk1 == pk2 then
- asmParThen [code1 asmVoid, code2 asmVoid] .
- mkSeqInstr (FCMP True (kindToSize pk1) src1 src2)
- else if pk1 == FloatRep then
- asmParThen [code1 (promote src1), code2 asmVoid] .
- mkSeqInstr (FCMP True DF tmp src2)
- else
- asmParThen [code1 asmVoid, code2 (promote src2)] .
- mkSeqInstr (FCMP True DF src1 tmp)
- in
- returnUs (Condition True cond code__2)
-
-\end{code}
-
-Turn those condition codes into integers now (when they appear on
-the right hand side of an assignment).
-
-Do not fill the delay slots here; you will confuse the register allocator.
-
-\begin{code}
-
-condIntReg :: Cond -> [StixTree] -> UniqSM Register
-
-condIntReg EQ [x, StInt 0] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
- code__2 dst = code . mkSeqInstrs [
- SUB False True g0 (RIReg src) g0,
- SUB True False g0 (RIImm (ImmInt (-1))) dst]
- in
- returnUs (Any IntRep code__2)
-
-condIntReg EQ [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
- XOR False src1 (RIReg src2) dst,
- SUB False True g0 (RIReg dst) g0,
- SUB True False g0 (RIImm (ImmInt (-1))) dst]
- in
- returnUs (Any IntRep code__2)
-
-condIntReg NE [x, StInt 0] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
- code__2 dst = code . mkSeqInstrs [
- SUB False True g0 (RIReg src) g0,
- ADD True False g0 (RIImm (ImmInt 0)) dst]
- in
- returnUs (Any IntRep code__2)
-
-condIntReg NE [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
- XOR False src1 (RIReg src2) dst,
- SUB False True g0 (RIReg dst) g0,
- ADD True False g0 (RIImm (ImmInt 0)) dst]
- in
- returnUs (Any IntRep code__2)
-
-condIntReg cond args =
- getUniqLabelNCG `thenUs` \ lbl1 ->
- getUniqLabelNCG `thenUs` \ lbl2 ->
- condIntCode cond args `thenUs` \ condition ->
- let
- code = condCode condition
- cond = condName condition
- code__2 dst = code . mkSeqInstrs [
- BI cond False (ImmCLbl lbl1), NOP,
- OR False g0 (RIImm (ImmInt 0)) dst,
- BI ALWAYS False (ImmCLbl lbl2), NOP,
- LABEL lbl1,
- OR False g0 (RIImm (ImmInt 1)) dst,
- LABEL lbl2]
- in
- returnUs (Any IntRep code__2)
-
-condFltReg :: Cond -> [StixTree] -> UniqSM Register
-
-condFltReg cond args =
- getUniqLabelNCG `thenUs` \ lbl1 ->
- getUniqLabelNCG `thenUs` \ lbl2 ->
- condFltCode cond args `thenUs` \ condition ->
- let
- code = condCode condition
- cond = condName condition
- code__2 dst = code . mkSeqInstrs [
- NOP,
- BF cond False (ImmCLbl lbl1), NOP,
- OR False g0 (RIImm (ImmInt 0)) dst,
- BI ALWAYS False (ImmCLbl lbl2), NOP,
- LABEL lbl1,
- OR False g0 (RIImm (ImmInt 1)) dst,
- LABEL lbl2]
- in
- returnUs (Any IntRep code__2)
-
-\end{code}
-
-Assignments are really at the heart of the whole code generation business.
-Almost all top-level nodes of any real importance are assignments, which
-correspond to loads, stores, or register transfers. If we're really lucky,
-some of the register transfers will go away, because we can use the destination
-register to complete the code generation for the right hand side. This only
-fails when the right hand side is forced into a fixed register (e.g. the result
-of a call).
-
-\begin{code}
-
-assignIntCode :: PrimRep -> StixTree -> StixTree -> UniqSM (CodeBlock SparcInstr)
-
-assignIntCode pk (StInd _ dst) src =
- getNewRegNCG IntRep `thenUs` \ tmp ->
- getAmode dst `thenUs` \ amode ->
- getReg src `thenUs` \ register ->
- let
- code1 = amodeCode amode asmVoid
- dst__2 = amodeAddr amode
- code2 = registerCode register tmp asmVoid
- src__2 = registerName register tmp
- sz = kindToSize pk
- code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
- in
- returnUs code__2
-
-assignIntCode pk dst src =
- getReg dst `thenUs` \ register1 ->
- getReg src `thenUs` \ register2 ->
- let
- dst__2 = registerName register1 g0
- code = registerCode register2 dst__2
- src__2 = registerName register2 dst__2
- code__2 = if isFixed register2 then
- code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
- else code
- in
- returnUs code__2
-
-assignFltCode :: PrimRep -> StixTree -> StixTree -> UniqSM (CodeBlock SparcInstr)
-
-assignFltCode pk (StInd _ dst) src =
- getNewRegNCG pk `thenUs` \ tmp ->
- getAmode dst `thenUs` \ amode ->
- getReg src `thenUs` \ register ->
- let
- sz = kindToSize pk
- dst__2 = amodeAddr amode
-
- code1 = amodeCode amode asmVoid
- code2 = registerCode register tmp asmVoid
-
- src__2 = registerName register tmp
- pk__2 = registerKind register
- sz__2 = kindToSize pk__2
-
- code__2 = asmParThen [code1, code2] .
- if pk == pk__2 then
- mkSeqInstr (ST sz src__2 dst__2)
- else
- mkSeqInstrs [FxTOy sz__2 sz src__2 tmp, ST sz tmp dst__2]
- in
- returnUs code__2
-
-assignFltCode pk dst src =
- getReg dst `thenUs` \ register1 ->
- getReg src `thenUs` \ register2 ->
- getNewRegNCG (registerKind register2)
- `thenUs` \ tmp ->
- let
- sz = kindToSize pk
- dst__2 = registerName register1 g0 -- must be Fixed
-
- reg__2 = if pk /= pk__2 then tmp else dst__2
-
- code = registerCode register2 reg__2
- src__2 = registerName register2 reg__2
- pk__2 = registerKind register2
- sz__2 = kindToSize pk__2
-
- code__2 = if pk /= pk__2 then code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
- else if isFixed register2 then code . mkSeqInstr (FMOV sz src__2 dst__2)
- else code
- in
- returnUs code__2
-
-\end{code}
-
-Generating an unconditional branch. We accept two types of targets:
-an immediate CLabel or a tree that gets evaluated into a register.
-Any CLabels which are AsmTemporaries are assumed to be in the local
-block of code, close enough for a branch instruction. Other CLabels
-are assumed to be far away, so we use call.
-
-Do not fill the delay slots here; you will confuse the register allocator.
-
-\begin{code}
-
-genJump
- :: StixTree -- the branch target
- -> UniqSM (CodeBlock SparcInstr)
-
-genJump (StCLbl lbl)
- | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
- | otherwise = returnInstrs [CALL target 0 True, NOP]
- where
- target = ImmCLbl lbl
-
-genJump tree =
- getReg tree `thenUs` \ register ->
- getNewRegNCG PtrRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- target = registerName register tmp
- in
- returnSeq code [JMP (AddrRegReg target g0), NOP]
-
-\end{code}
-
-Conditional jumps are always to local labels, so we can use
-branch instructions. First, we have to ensure that the condition
-codes are set according to the supplied comparison operation.
-We generate slightly different code for floating point comparisons,
-because a floating point operation cannot directly precede a @BF@.
-We assume the worst and fill that slot with a @NOP@.
-
-Do not fill the delay slots here; you will confuse the register allocator.
-
-\begin{code}
-
-genCondJump
- :: CLabel -- the branch target
- -> StixTree -- the condition on which to branch
- -> UniqSM (CodeBlock SparcInstr)
-
-genCondJump lbl bool =
- getCondition bool `thenUs` \ condition ->
- let
- code = condCode condition
- cond = condName condition
- target = ImmCLbl lbl
- in
- if condFloat condition then
- returnSeq code [NOP, BF cond False target, NOP]
- else
- returnSeq code [BI cond False target, NOP]
-
-\end{code}
-
-Now the biggest nightmare---calls. Most of the nastiness is buried in
-getCallArg, which moves the arguments to the correct registers/stack
-locations. Apart from that, the code is easy.
-
-Do not fill the delay slots here; you will confuse the register allocator.
-
-\begin{code}
-
-genCCall
- :: FAST_STRING -- function to call
- -> PrimRep -- type of the result
- -> [StixTree] -- arguments (of mixed type)
- -> UniqSM (CodeBlock SparcInstr)
-
-genCCall fn kind args =
- mapAccumLNCG getCallArg (argRegs,stackArgLoc) args
- `thenUs` \ ((unused,_), argCode) ->
- let
- nRegs = length argRegs - length unused
- call = CALL fn__2 nRegs False
- code = asmParThen (map ($ asmVoid) argCode)
- in
- returnSeq code [call, NOP]
- where
- -- function names that begin with '.' are assumed to be special internally
- -- generated names like '.mul,' which don't get an underscore prefix
- fn__2 = case (_HEAD_ fn) of
- '.' -> ImmLit (uppPStr fn)
- _ -> ImmLab (uppPStr fn)
-
- mapAccumLNCG f b [] = returnUs (b, [])
- mapAccumLNCG f b (x:xs) =
- f b x `thenUs` \ (b__2, x__2) ->
- mapAccumLNCG f b__2 xs `thenUs` \ (b__3, xs__2) ->
- returnUs (b__3, x__2:xs__2)
-
-\end{code}
-
-Trivial (dyadic) instructions. Only look for constants on the right hand
-side, because that's where the generic optimizer will have put them.
-
-\begin{code}
-
-trivialCode
- :: (Reg -> RI -> Reg -> SparcInstr)
- -> [StixTree]
- -> UniqSM Register
-
-trivialCode instr [x, StInt y]
- | is13Bits y =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src1 = registerName register tmp
- src2 = ImmInt (fromInteger y)
- code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
- in
- returnUs (Any IntRep code__2)
-
-trivialCode instr [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG IntRep `thenUs` \ tmp1 ->
- getNewRegNCG IntRep `thenUs` \ tmp2 ->
- let
- code1 = registerCode register1 tmp1 asmVoid
- src1 = registerName register1 tmp1
- code2 = registerCode register2 tmp2 asmVoid
- src2 = registerName register2 tmp2
- code__2 dst = asmParThen [code1, code2] .
- mkSeqInstr (instr src1 (RIReg src2) dst)
- in
- returnUs (Any IntRep code__2)
-
-trivialFCode
- :: PrimRep
- -> (Size -> Reg -> Reg -> Reg -> SparcInstr)
- -> [StixTree]
- -> UniqSM Register
-
-trivialFCode pk instr [x, y] =
- getReg x `thenUs` \ register1 ->
- getReg y `thenUs` \ register2 ->
- getNewRegNCG (registerKind register1)
- `thenUs` \ tmp1 ->
- getNewRegNCG (registerKind register2)
- `thenUs` \ tmp2 ->
- getNewRegNCG DoubleRep `thenUs` \ tmp ->
- let
- promote x = asmInstr (FxTOy F DF x tmp)
-
- pk1 = registerKind register1
- code1 = registerCode register1 tmp1
- src1 = registerName register1 tmp1
-
- pk2 = registerKind register2
- code2 = registerCode register2 tmp2
- src2 = registerName register2 tmp2
-
- code__2 dst =
- if pk1 == pk2 then
- asmParThen [code1 asmVoid, code2 asmVoid] .
- mkSeqInstr (instr (kindToSize pk) src1 src2 dst)
- else if pk1 == FloatRep then
- asmParThen [code1 (promote src1), code2 asmVoid] .
- mkSeqInstr (instr DF tmp src2 dst)
- else
- asmParThen [code1 asmVoid, code2 (promote src2)] .
- mkSeqInstr (instr DF src1 tmp dst)
- in
- returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
-
-\end{code}
-
-Trivial unary instructions. Note that we don't have to worry about
-matching an StInt as the argument, because genericOpt will already
-have handled the constant-folding.
-
-\begin{code}
-
-trivialUCode
- :: (RI -> Reg -> SparcInstr)
- -> [StixTree]
- -> UniqSM Register
-
-trivialUCode instr [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
- code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
- in
- returnUs (Any IntRep code__2)
-
-trivialUFCode
- :: PrimRep
- -> (Reg -> Reg -> SparcInstr)
- -> [StixTree]
- -> UniqSM Register
-
-trivialUFCode pk instr [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG pk `thenUs` \ tmp ->
- let
- code = registerCode register tmp
- src = registerName register tmp
- code__2 dst = code . mkSeqInstr (instr src dst)
- in
- returnUs (Any pk code__2)
-
-\end{code}
-
-Absolute value on integers, mostly for gmp size check macros. Again,
-the argument cannot be an StInt, because genericOpt already folded
-constants.
-
-Do not fill the delay slots here; you will confuse the register allocator.
-
-\begin{code}
-
-absIntCode :: [StixTree] -> UniqSM Register
-absIntCode [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ reg ->
- getUniqLabelNCG `thenUs` \ lbl ->
- let
- code = registerCode register reg
- src = registerName register reg
- code__2 dst = code . mkSeqInstrs [
- SUB False True g0 (RIReg src) dst,
- BI GE False (ImmCLbl lbl), NOP,
- OR False g0 (RIReg src) dst,
- LABEL lbl]
- in
- returnUs (Any IntRep code__2)
-
-\end{code}
-
-Simple integer coercions that don't require any code to be generated.
-Here we just change the type on the register passed on up
-
-\begin{code}
-
-coerceIntCode :: PrimRep -> [StixTree] -> UniqSM Register
-coerceIntCode pk [x] =
- getReg x `thenUs` \ register ->
- case register of
- Fixed reg _ code -> returnUs (Fixed reg pk code)
- Any _ code -> returnUs (Any pk code)
-
-\end{code}
-
-Integer to character conversion. We try to do this in one step if
-the original object is in memory.
-
-\begin{code}
-
-chrCode :: [StixTree] -> UniqSM Register
-chrCode [StInd pk mem] =
- getAmode mem `thenUs` \ amode ->
- let
- code = amodeCode amode
- src = amodeAddr amode
- srcOff = offset src 3
- src__2 = case srcOff of Just x -> x
- code__2 dst = if maybeToBool srcOff then
- code . mkSeqInstr (LD UB src__2 dst)
- else
- code . mkSeqInstrs [
- LD (kindToSize pk) src dst,
- AND False dst (RIImm (ImmInt 255)) dst]
- in
- returnUs (Any pk code__2)
-
-chrCode [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ reg ->
- let
- code = registerCode register reg
- src = registerName register reg
- code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
- in
- returnUs (Any IntRep code__2)
-
-\end{code}
-
-More complicated integer/float conversions. Here we have to store
-temporaries in memory to move between the integer and the floating
-point register sets.
-
-\begin{code}
-
-coerceInt2FP :: PrimRep -> [StixTree] -> UniqSM Register
-coerceInt2FP pk [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ reg ->
- let
- code = registerCode register reg
- src = registerName register reg
-
- code__2 dst = code . mkSeqInstrs [
- ST W src (spRel (-2)),
- LD W (spRel (-2)) dst,
- FxTOy W (kindToSize pk) dst dst]
- in
- returnUs (Any pk code__2)
-
-coerceFP2Int :: [StixTree] -> UniqSM Register
-coerceFP2Int [x] =
- getReg x `thenUs` \ register ->
- getNewRegNCG IntRep `thenUs` \ reg ->
- getNewRegNCG FloatRep `thenUs` \ tmp ->
- let
- code = registerCode register reg
- src = registerName register reg
- pk = registerKind register
-
- code__2 dst = code . mkSeqInstrs [
- FxTOy (kindToSize pk) W src tmp,
- ST W tmp (spRel (-2)),
- LD W (spRel (-2)) dst]
- in
- returnUs (Any IntRep code__2)
-
-\end{code}
-
-Some random little helpers.
-
-\begin{code}
-
-maybeImm :: StixTree -> Maybe Imm
-maybeImm (StInt i)
- | i >= toInteger minInt && i <= toInteger maxInt = Just (ImmInt (fromInteger i))
- | otherwise = Just (ImmInteger i)
-maybeImm (StLitLbl s) = Just (ImmLab s)
-maybeImm (StLitLit s) = Just (strImmLit (cvtLitLit (_UNPK_ s)))
-maybeImm (StCLbl l) = Just (ImmCLbl l)
-maybeImm _ = Nothing
-
-mangleIndexTree :: StixTree -> StixTree
-
-mangleIndexTree (StIndex pk base (StInt i)) =
- StPrim IntAddOp [base, off]
- where
- off = StInt (i * size pk)
- size :: PrimRep -> Integer
- size pk = case kindToSize pk of
- {SB -> 1; UB -> 1; HW -> 2; UHW -> 2; W -> 4; D -> 8; F -> 4; DF -> 8}
-
-mangleIndexTree (StIndex pk base off) =
- case pk of
- CharRep -> StPrim IntAddOp [base, off]
- _ -> StPrim IntAddOp [base, off__2]
- where
- off__2 = StPrim SllOp [off, StInt (shift pk)]
- shift :: PrimRep -> Integer
- shift DoubleRep = 3
- shift _ = 2
-
-cvtLitLit :: String -> String
-cvtLitLit "stdin" = "__iob+0x0" -- This one is probably okay...
-cvtLitLit "stdout" = "__iob+0x14" -- but these next two are dodgy at best
-cvtLitLit "stderr" = "__iob+0x28"
-cvtLitLit s
- | isHex s = s
- | otherwise = error ("Native code generator can't handle ``" ++ s ++ "''")
- where
- isHex ('0':'x':xs) = all isHexDigit xs
- isHex _ = False
- -- Now, where have I seen this before?
- isHexDigit c = isDigit c || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'
-
-
-\end{code}
-
-spRel gives us a stack relative addressing mode for volatile temporaries
-and for excess call arguments.
-
-\begin{code}
-
-spRel
- :: Int -- desired stack offset in words, positive or negative
- -> Addr
-spRel n = AddrRegImm sp (ImmInt (n * 4))
-
-stackArgLoc = 23 :: Int -- where to stack extra call arguments (beyond 6x32 bits)
-
-\end{code}
-
-\begin{code}
-
-getNewRegNCG :: PrimRep -> UniqSM Reg
-getNewRegNCG pk =
- getUnique `thenUs` \ u ->
- returnUs (mkReg u pk)
-
-\end{code}
%
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1996
%
\begin{code}
stgBaseReg, stgStkOReg, stgNode, stgTagReg, stgRetReg,
stgSpA, stgSuA, stgSpB, stgSuB, stgHp, stgHpLim, stgLivenessReg,
--- stgActivityReg,
stgStdUpdRetVecReg, stgStkStubReg,
getUniqLabelNCG
-
- -- And for self-sufficiency, by golly...
) where
-import AbsCSyn ( MagicId(..), kindFromMagicId, node, infoptr )
-import PrelInfo ( showPrimOp, PrimOp
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import CLabel ( CLabel, mkAsmTempLabel )
-import Outputable
-import UniqSupply
-import Unpretty
-import Util
+import Ubiq{-uitous-}
+
+import AbsCSyn ( node, infoptr, MagicId(..) )
+import AbsCUtils ( magicIdPrimRep )
+import CLabel ( mkAsmTempLabel )
+import UniqSupply ( returnUs, thenUs, getUnique, UniqSM(..) )
+import Unpretty ( uppPStr, Unpretty(..) )
\end{code}
Here is the tag at the nodes of our @StixTree@. Notice its
relationship with @PrimOp@ in prelude/PrimOp.
\begin{code}
+data StixTree
+ = -- Segment (text or data)
-data StixTree =
-
- -- Segment (text or data)
+ StSegment CodeSegment
- StSegment CodeSegment
+ -- We can tag the leaves with constants/immediates.
- -- We can tag the leaves with constants/immediates.
+ | StInt Integer -- ** add Kind at some point
+ | StDouble Rational
+ | StString FAST_STRING
+ | StLitLbl Unpretty -- literal labels
+ -- (will be _-prefixed on some machines)
+ | StLitLit FAST_STRING -- innards from CLitLit
+ | StCLbl CLabel -- labels that we might index into
- | StInt Integer -- ** add Kind at some point
- | StDouble Rational
- | StString FAST_STRING
- | StLitLbl Unpretty -- literal labels (will be _-prefixed on some machines)
- | StLitLit FAST_STRING -- innards from CLitLit
- | StCLbl CLabel -- labels that we might index into
+ -- Abstract registers of various kinds
- -- Abstract registers of various kinds
+ | StReg StixReg
- | StReg StixReg
+ -- A typed offset from a base location
- -- A typed offset from a base location
+ | StIndex PrimRep StixTree StixTree -- kind, base, offset
- | StIndex PrimRep StixTree StixTree -- kind, base, offset
+ -- An indirection from an address to its contents.
- -- An indirection from an address to its contents.
+ | StInd PrimRep StixTree
- | StInd PrimRep StixTree
+ -- Assignment is typed to determine size and register placement
- -- Assignment is typed to determine size and register placement
+ | StAssign PrimRep StixTree StixTree -- dst, src
- | StAssign PrimRep StixTree StixTree -- dst, src
+ -- A simple assembly label that we might jump to.
- -- A simple assembly label that we might jump to.
+ | StLabel CLabel
- | StLabel CLabel
+ -- A function header and footer
- -- A function header and footer
+ | StFunBegin CLabel
+ | StFunEnd CLabel
- | StFunBegin CLabel
- | StFunEnd CLabel
+ -- An unconditional jump. This instruction is terminal.
+ -- Dynamic targets are allowed
- -- An unconditional jump. This instruction is terminal.
- -- Dynamic targets are allowed
+ | StJump StixTree
- | StJump StixTree
+ -- A fall-through, from slow to fast
- -- A fall-through, from slow to fast
+ | StFallThrough CLabel
- | StFallThrough CLabel
+ -- A conditional jump. This instruction can be non-terminal :-)
+ -- Only static, local, forward labels are allowed
- -- A conditional jump. This instruction can be non-terminal :-)
- -- Only static, local, forward labels are allowed
+ | StCondJump CLabel StixTree
- | StCondJump CLabel StixTree
+ -- Raw data (as in an info table).
- -- Raw data (as in an info table).
+ | StData PrimRep [StixTree]
- | StData PrimRep [StixTree]
+ -- Primitive Operations
- -- Primitive Operations
+ | StPrim PrimOp [StixTree]
- | StPrim PrimOp [StixTree]
+ -- Calls to C functions
- -- Calls to C functions
+ | StCall FAST_STRING PrimRep [StixTree]
- | StCall FAST_STRING PrimRep [StixTree]
+ -- Assembly-language comments
- -- Comments, of course
-
- | StComment FAST_STRING -- For assembly comments
-
- deriving ()
+ | StComment FAST_STRING
sStLitLbl :: FAST_STRING -> StixTree
sStLitLbl s = StLitLbl (uppPStr s)
\end{code}
Stix registers can have two forms. They {\em may} or {\em may not}
-map to real, machine level registers.
+map to real, machine-level registers.
\begin{code}
+data StixReg
+ = StixMagicId MagicId -- Regs which are part of the abstract machine model
-data StixReg = StixMagicId MagicId -- Regs which are part of the abstract machine model
-
- | StixTemp Unique PrimRep -- "Regs" which model local variables (CTemps) in
+ | StixTemp Unique PrimRep -- "Regs" which model local variables (CTemps) in
-- the abstract C.
- deriving ()
-
\end{code}
We hope that every machine supports the idea of data segment and text
-segment (or that it has no segments at all, and we can lump these together).
+segment (or that it has no segments at all, and we can lump these
+together).
\begin{code}
-
-data CodeSegment = DataSegment | TextSegment deriving (Eq)
+data CodeSegment = DataSegment | TextSegment deriving Eq
type StixTreeList = [StixTree] -> [StixTree]
-
\end{code}
--- Stix Trees for STG registers
-
+Stix Trees for STG registers:
\begin{code}
-
-stgBaseReg, stgStkOReg, stgNode, stgTagReg, stgRetReg, stgSpA, stgSuA,
- stgSpB, stgSuB, stgHp, stgHpLim, stgLivenessReg{-, stgActivityReg-}, stgStdUpdRetVecReg,
- stgStkStubReg :: StixTree
-
-stgBaseReg = StReg (StixMagicId BaseReg)
-stgStkOReg = StReg (StixMagicId StkOReg)
-stgNode = StReg (StixMagicId node)
-stgInfoPtr = StReg (StixMagicId infoptr)
-stgTagReg = StReg (StixMagicId TagReg)
-stgRetReg = StReg (StixMagicId RetReg)
-stgSpA = StReg (StixMagicId SpA)
-stgSuA = StReg (StixMagicId SuA)
-stgSpB = StReg (StixMagicId SpB)
-stgSuB = StReg (StixMagicId SuB)
-stgHp = StReg (StixMagicId Hp)
-stgHpLim = StReg (StixMagicId HpLim)
-stgLivenessReg = StReg (StixMagicId LivenessReg)
---stgActivityReg = StReg (StixMagicId ActivityReg)
-stgStdUpdRetVecReg = StReg (StixMagicId StdUpdRetVecReg)
-stgStkStubReg = StReg (StixMagicId StkStubReg)
+stgBaseReg, stgStkOReg, stgNode, stgTagReg, stgRetReg, stgSpA,
+ stgSuA, stgSpB, stgSuB, stgHp, stgHpLim, stgLivenessReg,
+ stgStdUpdRetVecReg, stgStkStubReg :: StixTree
+
+stgBaseReg = StReg (StixMagicId BaseReg)
+stgStkOReg = StReg (StixMagicId StkOReg)
+stgNode = StReg (StixMagicId node)
+stgInfoPtr = StReg (StixMagicId infoptr)
+stgTagReg = StReg (StixMagicId TagReg)
+stgRetReg = StReg (StixMagicId RetReg)
+stgSpA = StReg (StixMagicId SpA)
+stgSuA = StReg (StixMagicId SuA)
+stgSpB = StReg (StixMagicId SpB)
+stgSuB = StReg (StixMagicId SuB)
+stgHp = StReg (StixMagicId Hp)
+stgHpLim = StReg (StixMagicId HpLim)
+stgLivenessReg = StReg (StixMagicId LivenessReg)
+stgStdUpdRetVecReg = StReg (StixMagicId StdUpdRetVecReg)
+stgStkStubReg = StReg (StixMagicId StkStubReg)
getUniqLabelNCG :: UniqSM CLabel
-getUniqLabelNCG =
- getUnique `thenUs` \ u ->
- returnUs (mkAsmTempLabel u)
-
+getUniqLabelNCG
+ = getUnique `thenUs` \ u ->
+ returnUs (mkAsmTempLabel u)
\end{code}
%
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1996
%
\begin{code}
#include "HsVersions.h"
-module StixInfo (
- genCodeInfoTable
- ) where
-
-import AbsCSyn
-import ClosureInfo
-import MachDesc
-import Maybes ( maybeToBool, Maybe(..) )
-import SMRep ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..) )
-import Stix
-import UniqSupply
-import Unpretty
-import Util
-
+module StixInfo ( genCodeInfoTable ) where
+
+import Ubiq{-uitious-}
+
+import AbsCSyn ( AbstractC(..), CAddrMode, ReturnInfo,
+ RegRelative, MagicId, CStmtMacro
+ )
+import ClosureInfo ( closurePtrsSize, closureSizeWithoutFixedHdr,
+ closureNonHdrSize, closureSemiTag, maybeSelectorInfo,
+ closureSMRep, closureLabelFromCI,
+ infoTableLabelFromCI
+ )
+import HeapOffs ( hpRelToInt )
+import Maybes ( maybeToBool )
+import PrimRep ( PrimRep(..) )
+import SMRep ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..),
+ isSpecRep
+ )
+import Stix -- all of it
+import StixPrim ( amodeToStix )
+import UniqSupply ( returnUs, UniqSM(..) )
+import Unpretty ( uppBesides, uppPStr, uppInt, uppChar )
\end{code}
Generating code for info tables (arrays of data).
dyn___rtbl = sStLitLbl SLIT("Dyn___rtbl")
genCodeInfoTable
- :: {-Target-}
- (HeapOffset -> Int) -- needed bit of Target
- -> (CAddrMode -> StixTree) -- ditto
- -> AbstractC
+ :: AbstractC
-> UniqSM StixTreeList
-genCodeInfoTable hp_rel amode2stix (CClosureInfoAndCode cl_info _ _ upd cl_descr _) =
- returnUs (\xs -> info : lbl : xs)
+genCodeInfoTable (CClosureInfoAndCode cl_info _ _ upd cl_descr _)
+ = returnUs (\xs -> info : lbl : xs)
where
info = StData PtrRep table
size = if isSpecRep sm_rep
then closureNonHdrSize cl_info
- else hp_rel (closureSizeWithoutFixedHdr cl_info)
+ else hpRelToInt (closureSizeWithoutFixedHdr cl_info)
ptrs = closurePtrsSize cl_info
- upd_code = amode2stix upd
+ upd_code = amodeToStix upd
info_unused = StInt (-1)
-
\end{code}
%
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1996
%
\begin{code}
#include "HsVersions.h"
module StixInteger (
- gmpTake1Return1, gmpTake2Return1, gmpTake2Return2,
- gmpCompare, gmpInteger2Int, gmpInt2Integer, gmpString2Integer,
+ gmpTake1Return1, gmpTake2Return1, gmpTake2Return2, gmpCompare,
+ gmpInteger2Int, gmpInt2Integer, gmpString2Integer,
encodeFloatingKind, decodeFloatingKind
) where
-IMPORT_Trace -- ToDo: rm debugging
-
-import AbsCSyn
-import CgCompInfo ( mIN_MP_INT_SIZE )
-import MachDesc
-import Pretty
-import PrelInfo ( PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import SMRep ( SMRep(..), SMSpecRepKind, SMUpdateKind(..) )
-import Stix
-import UniqSupply
-import Util
-
+import Ubiq{-uitous-}
+import NcgLoop ( amodeToStix )
+
+import MachMisc
+import MachRegs
+
+import AbsCSyn -- bits and bobs...
+import CgCompInfo ( mIN_MP_INT_SIZE )
+import Literal ( Literal(..) )
+import OrdList ( OrdList )
+import PrimOp ( PrimOp(..) )
+import PrimRep ( PrimRep(..) )
+import SMRep ( SMRep(..), SMSpecRepKind, SMUpdateKind )
+import Stix ( getUniqLabelNCG, sStLitLbl, stgHp, stgHpLim,
+ StixTree(..), StixTreeList(..),
+ CodeSegment, StixReg
+ )
+import StixMacro ( macroCode, heapCheck )
+import UniqSupply ( returnUs, thenUs, UniqSM(..) )
+import Util ( panic )
\end{code}
\begin{code}
-
gmpTake1Return1
- :: Target
- -> (CAddrMode,CAddrMode,CAddrMode) -- result (3 parts)
+ :: (CAddrMode,CAddrMode,CAddrMode) -- result (3 parts)
-> FAST_STRING -- function name
-> (CAddrMode, CAddrMode,CAddrMode,CAddrMode)
-- argument (4 parts)
init3 = StCall SLIT("mpz_init") VoidRep [result3]
init4 = StCall SLIT("mpz_init") VoidRep [result4]
--- hacking with Uncle Will:
-#define target_STRICT target@(Target _ _ _ _ _ _ _ _)
-
-gmpTake1Return1 target_STRICT res@(car,csr,cdr) rtn arg@(clive,caa,csa,cda) =
- let
- a2stix = amodeToStix target
- data_hs = dataHS target
-
- ar = a2stix car
- sr = a2stix csr
- dr = a2stix cdr
- liveness= a2stix clive
- aa = a2stix caa
- sa = a2stix csa
- da = a2stix cda
-
- space = mpSpace data_hs 2 1 [sa]
+gmpTake1Return1 res@(car,csr,cdr) rtn arg@(clive,caa,csa,cda)
+ = let
+ ar = amodeToStix car
+ sr = amodeToStix csr
+ dr = amodeToStix cdr
+ liveness= amodeToStix clive
+ aa = amodeToStix caa
+ sa = amodeToStix csa
+ da = amodeToStix cda
+
+ space = mpSpace 2 1 [sa]
oldHp = StIndex PtrRep stgHp (StPrim IntNegOp [space])
- safeHp = saveLoc target Hp
+ safeHp = saveLoc Hp
save = StAssign PtrRep safeHp oldHp
- (a1,a2,a3) = toStruct data_hs argument1 (aa,sa,da)
+ (a1,a2,a3) = toStruct argument1 (aa,sa,da)
mpz_op = StCall rtn VoidRep [result2, argument1]
restore = StAssign PtrRep stgHp safeHp
- (r1,r2,r3) = fromStruct data_hs result2 (ar,sr,dr)
+ (r1,r2,r3) = fromStruct result2 (ar,sr,dr)
in
- heapCheck target liveness space (StInt 0) `thenUs` \ heap_chk ->
+ heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
- returnUs (heap_chk .
- (\xs -> a1 : a2 : a3 : save : init2 : mpz_op : r1 : r2 : r3 : restore : xs))
+ returnUs (heap_chk .
+ (\xs -> a1 : a2 : a3 : save : init2 : mpz_op : r1 : r2 : r3 : restore : xs))
gmpTake2Return1
- :: Target
- -> (CAddrMode,CAddrMode,CAddrMode) -- result (3 parts)
+ :: (CAddrMode,CAddrMode,CAddrMode) -- result (3 parts)
-> FAST_STRING -- function name
-> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
-- liveness + 2 arguments (3 parts each)
-> UniqSM StixTreeList
-gmpTake2Return1 target_STRICT res@(car,csr,cdr) rtn args@(clive, caa1,csa1,cda1, caa2,csa2,cda2) =
- let
- a2stix = amodeToStix target
- data_hs = dataHS target
-
- ar = a2stix car
- sr = a2stix csr
- dr = a2stix cdr
- liveness= a2stix clive
- aa1 = a2stix caa1
- sa1 = a2stix csa1
- da1 = a2stix cda1
- aa2 = a2stix caa2
- sa2 = a2stix csa2
- da2 = a2stix cda2
-
- space = mpSpace data_hs 3 1 [sa1, sa2]
+gmpTake2Return1 res@(car,csr,cdr) rtn args@(clive, caa1,csa1,cda1, caa2,csa2,cda2)
+ = let
+ ar = amodeToStix car
+ sr = amodeToStix csr
+ dr = amodeToStix cdr
+ liveness= amodeToStix clive
+ aa1 = amodeToStix caa1
+ sa1 = amodeToStix csa1
+ da1 = amodeToStix cda1
+ aa2 = amodeToStix caa2
+ sa2 = amodeToStix csa2
+ da2 = amodeToStix cda2
+
+ space = mpSpace 3 1 [sa1, sa2]
oldHp = StIndex PtrRep stgHp (StPrim IntNegOp [space])
- safeHp = saveLoc target Hp
+ safeHp = saveLoc Hp
save = StAssign PtrRep safeHp oldHp
- (a1,a2,a3) = toStruct data_hs argument1 (aa1,sa1,da1)
- (a4,a5,a6) = toStruct data_hs argument2 (aa2,sa2,da2)
+ (a1,a2,a3) = toStruct argument1 (aa1,sa1,da1)
+ (a4,a5,a6) = toStruct argument2 (aa2,sa2,da2)
mpz_op = StCall rtn VoidRep [result3, argument1, argument2]
restore = StAssign PtrRep stgHp safeHp
- (r1,r2,r3) = fromStruct data_hs result3 (ar,sr,dr)
+ (r1,r2,r3) = fromStruct result3 (ar,sr,dr)
in
- heapCheck target liveness space (StInt 0) `thenUs` \ heap_chk ->
+ heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
- returnUs (heap_chk .
- (\xs -> a1 : a2 : a3 : a4 : a5 : a6
- : save : init3 : mpz_op : r1 : r2 : r3 : restore : xs))
+ returnUs (heap_chk .
+ (\xs -> a1 : a2 : a3 : a4 : a5 : a6
+ : save : init3 : mpz_op : r1 : r2 : r3 : restore : xs))
gmpTake2Return2
- :: Target
- -> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
+ :: (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
-- 2 results (3 parts each)
-> FAST_STRING -- function name
-> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
-- liveness + 2 arguments (3 parts each)
-> UniqSM StixTreeList
-gmpTake2Return2 target_STRICT res@(car1,csr1,cdr1, car2,csr2,cdr2)
- rtn args@(clive, caa1,csa1,cda1, caa2,csa2,cda2) =
- let
- a2stix = amodeToStix target
- data_hs = dataHS target
-
- ar1 = a2stix car1
- sr1 = a2stix csr1
- dr1 = a2stix cdr1
- ar2 = a2stix car2
- sr2 = a2stix csr2
- dr2 = a2stix cdr2
- liveness= a2stix clive
- aa1 = a2stix caa1
- sa1 = a2stix csa1
- da1 = a2stix cda1
- aa2 = a2stix caa2
- sa2 = a2stix csa2
- da2 = a2stix cda2
-
- space = StPrim IntMulOp [mpSpace data_hs 2 1 [sa1, sa2], StInt 2]
+gmpTake2Return2 res@(car1,csr1,cdr1, car2,csr2,cdr2)
+ rtn args@(clive, caa1,csa1,cda1, caa2,csa2,cda2)
+ = let
+ ar1 = amodeToStix car1
+ sr1 = amodeToStix csr1
+ dr1 = amodeToStix cdr1
+ ar2 = amodeToStix car2
+ sr2 = amodeToStix csr2
+ dr2 = amodeToStix cdr2
+ liveness= amodeToStix clive
+ aa1 = amodeToStix caa1
+ sa1 = amodeToStix csa1
+ da1 = amodeToStix cda1
+ aa2 = amodeToStix caa2
+ sa2 = amodeToStix csa2
+ da2 = amodeToStix cda2
+
+ space = StPrim IntMulOp [mpSpace 2 1 [sa1, sa2], StInt 2]
oldHp = StIndex PtrRep stgHp (StPrim IntNegOp [space])
- safeHp = saveLoc target Hp
+ safeHp = saveLoc Hp
save = StAssign PtrRep safeHp oldHp
- (a1,a2,a3) = toStruct data_hs argument1 (aa1,sa1,da1)
- (a4,a5,a6) = toStruct data_hs argument2 (aa2,sa2,da2)
+ (a1,a2,a3) = toStruct argument1 (aa1,sa1,da1)
+ (a4,a5,a6) = toStruct argument2 (aa2,sa2,da2)
mpz_op = StCall rtn VoidRep [result3, result4, argument1, argument2]
restore = StAssign PtrRep stgHp safeHp
- (r1,r2,r3) = fromStruct data_hs result3 (ar1,sr1,dr1)
- (r4,r5,r6) = fromStruct data_hs result4 (ar2,sr2,dr2)
+ (r1,r2,r3) = fromStruct result3 (ar1,sr1,dr1)
+ (r4,r5,r6) = fromStruct result4 (ar2,sr2,dr2)
in
- heapCheck target liveness space (StInt 0) `thenUs` \ heap_chk ->
-
- returnUs (heap_chk .
- (\xs -> a1 : a2 : a3 : a4 : a5 : a6
- : save : init3 : init4 : mpz_op
- : r1 : r2 : r3 : r4 : r5 : r6 : restore : xs))
+ heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
+ returnUs (heap_chk .
+ (\xs -> a1 : a2 : a3 : a4 : a5 : a6
+ : save : init3 : init4 : mpz_op
+ : r1 : r2 : r3 : r4 : r5 : r6 : restore : xs))
\end{code}
Although gmpCompare doesn't allocate space, it does temporarily use
available. (See ``primOpHeapRequired.'')
\begin{code}
-
gmpCompare
- :: Target
- -> CAddrMode -- result (boolean)
+ :: CAddrMode -- result (boolean)
-> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
-- alloc hp + 2 arguments (3 parts each)
-> UniqSM StixTreeList
-gmpCompare target_STRICT res args@(chp, caa1,csa1,cda1, caa2,csa2,cda2) =
- let
- a2stix = amodeToStix target
- data_hs = dataHS target
-
- result = a2stix res
- hp = a2stix chp
- aa1 = a2stix caa1
- sa1 = a2stix csa1
- da1 = a2stix cda1
- aa2 = a2stix caa2
- sa2 = a2stix csa2
- da2 = a2stix cda2
+gmpCompare res args@(chp, caa1,csa1,cda1, caa2,csa2,cda2)
+ = let
+ result = amodeToStix res
+ hp = amodeToStix chp
+ aa1 = amodeToStix caa1
+ sa1 = amodeToStix csa1
+ da1 = amodeToStix cda1
+ aa2 = amodeToStix caa2
+ sa2 = amodeToStix csa2
+ da2 = amodeToStix cda2
argument1 = hp
argument2 = StIndex IntRep hp (StInt (toInteger mpIntSize))
- (a1,a2,a3) = toStruct data_hs argument1 (aa1,sa1,da1)
- (a4,a5,a6) = toStruct data_hs argument2 (aa2,sa2,da2)
+ (a1,a2,a3) = toStruct argument1 (aa1,sa1,da1)
+ (a4,a5,a6) = toStruct argument2 (aa2,sa2,da2)
mpz_cmp = StCall SLIT("mpz_cmp") IntRep [argument1, argument2]
r1 = StAssign IntRep result mpz_cmp
in
- returnUs (\xs -> a1 : a2 : a3 : a4 : a5 : a6 : r1 : xs)
-
+ returnUs (\xs -> a1 : a2 : a3 : a4 : a5 : a6 : r1 : xs)
\end{code}
See the comment above regarding the heap check (or lack thereof).
\begin{code}
-
gmpInteger2Int
- :: Target
- -> CAddrMode -- result
+ :: CAddrMode -- result
-> (CAddrMode, CAddrMode,CAddrMode,CAddrMode) -- alloc hp + argument (3 parts)
-> UniqSM StixTreeList
-gmpInteger2Int target_STRICT res args@(chp, caa,csa,cda) =
- let
- a2stix = amodeToStix target
- data_hs = dataHS target
+gmpInteger2Int res args@(chp, caa,csa,cda)
+ = let
+ result = amodeToStix res
+ hp = amodeToStix chp
+ aa = amodeToStix caa
+ sa = amodeToStix csa
+ da = amodeToStix cda
- result = a2stix res
- hp = a2stix chp
- aa = a2stix caa
- sa = a2stix csa
- da = a2stix cda
-
- (a1,a2,a3) = toStruct data_hs hp (aa,sa,da)
+ (a1,a2,a3) = toStruct hp (aa,sa,da)
mpz_get_si = StCall SLIT("mpz_get_si") IntRep [hp]
r1 = StAssign IntRep result mpz_get_si
in
- returnUs (\xs -> a1 : a2 : a3 : r1 : xs)
+ returnUs (\xs -> a1 : a2 : a3 : r1 : xs)
arrayOfData_info = sStLitLbl SLIT("ArrayOfData_info")
+--------------
gmpInt2Integer
- :: Target
- -> (CAddrMode, CAddrMode, CAddrMode) -- result (3 parts)
+ :: (CAddrMode, CAddrMode, CAddrMode) -- result (3 parts)
-> (CAddrMode, CAddrMode) -- allocated heap, Int to convert
-> UniqSM StixTreeList
-gmpInt2Integer target_STRICT res@(car,csr,cdr) args@(chp, n) =
- getUniqLabelNCG `thenUs` \ zlbl ->
+gmpInt2Integer res@(car,csr,cdr) args@(chp, n)
+ = getUniqLabelNCG `thenUs` \ zlbl ->
getUniqLabelNCG `thenUs` \ nlbl ->
getUniqLabelNCG `thenUs` \ jlbl ->
let
- a2stix = amodeToStix target
-
- ar = a2stix car
- sr = a2stix csr
- dr = a2stix cdr
- hp = a2stix chp
- i = a2stix n
+ ar = amodeToStix car
+ sr = amodeToStix csr
+ dr = amodeToStix cdr
+ hp = amodeToStix chp
+ i = amodeToStix n
h1 = StAssign PtrRep (StInd PtrRep hp) arrayOfData_info
- size = varHeaderSize target (DataRep 0) + mIN_MP_INT_SIZE
+ size = varHdrSizeInWords (DataRep 0) + mIN_MP_INT_SIZE
h2 = StAssign IntRep (StInd IntRep (StIndex IntRep hp (StInt 1)))
(StInt (toInteger size))
- cts = StInd IntRep (StIndex IntRep hp (dataHS target))
+ cts = StInd IntRep (StIndex IntRep hp dataHS)
test1 = StPrim IntEqOp [i, StInt 0]
test2 = StPrim IntLtOp [i, StInt 0]
cjmp1 = StCondJump zlbl test1
a1 = StAssign IntRep ar (StInt 1)
a2 = StAssign PtrRep dr hp
in
- returnUs (\xs ->
- case n of
- CLit (MachInt c _) ->
- if c == 0 then h1 : h2 : z1 : a1 : a2 : xs
- else if c > 0 then h1 : h2 : p1 : p2 : a1 : a2 : xs
- else h1 : h2 : n1 : n2 : a1 : a2 : xs
- _ -> h1 : h2 : cjmp1 : cjmp2 : p1 : p2 : p3
- : n0 : n1 : n2 : n3 : z0 : z1
- : a0 : a1 : a2 : xs)
+ returnUs (\xs ->
+ case n of
+ CLit (MachInt c _) ->
+ if c == 0 then h1 : h2 : z1 : a1 : a2 : xs
+ else if c > 0 then h1 : h2 : p1 : p2 : a1 : a2 : xs
+ else h1 : h2 : n1 : n2 : a1 : a2 : xs
+ _ -> h1 : h2 : cjmp1 : cjmp2 : p1 : p2 : p3
+ : n0 : n1 : n2 : n3 : z0 : z1
+ : a0 : a1 : a2 : xs)
gmpString2Integer
- :: Target
- -> (CAddrMode, CAddrMode, CAddrMode) -- result (3 parts)
+ :: (CAddrMode, CAddrMode, CAddrMode) -- result (3 parts)
-> (CAddrMode, CAddrMode) -- liveness, string
-> UniqSM StixTreeList
-gmpString2Integer target_STRICT res@(car,csr,cdr) (liveness, str) =
- getUniqLabelNCG `thenUs` \ ulbl ->
+gmpString2Integer res@(car,csr,cdr) (liveness, str)
+ = getUniqLabelNCG `thenUs` \ ulbl ->
let
- a2stix = amodeToStix target
- data_hs = dataHS target
-
- ar = a2stix car
- sr = a2stix csr
- dr = a2stix cdr
+ ar = amodeToStix car
+ sr = amodeToStix csr
+ dr = amodeToStix cdr
len = case str of
(CString s) -> _LENGTH_ s
(CLit (MachStr s)) -> _LENGTH_ s
_ -> panic "String2Integer"
space = len `quot` 8 + 17 + mpIntSize +
- varHeaderSize target (DataRep 0) + fixedHeaderSize target
+ varHdrSizeInWords (DataRep 0) + fixedHdrSizeInWords
oldHp = StIndex PtrRep stgHp (StInt (toInteger (-space)))
- safeHp = saveLoc target Hp
+ safeHp = saveLoc Hp
save = StAssign PtrRep safeHp oldHp
result = StIndex IntRep stgHpLim (StInt (toInteger (-mpIntSize)))
set_str = StCall SLIT("mpz_init_set_str") IntRep
- [result, a2stix str, StInt 10]
+ [result, amodeToStix str, StInt 10]
test = StPrim IntEqOp [set_str, StInt 0]
cjmp = StCondJump ulbl test
abort = StCall SLIT("abort") VoidRep []
join = StLabel ulbl
restore = StAssign PtrRep stgHp safeHp
- (a1,a2,a3) = fromStruct data_hs result (ar,sr,dr)
+ (a1,a2,a3) = fromStruct result (ar,sr,dr)
in
- macroCode target HEAP_CHK [liveness, mkIntCLit space, mkIntCLit_0]
- `thenUs` \ heap_chk ->
+ macroCode HEAP_CHK [liveness, mkIntCLit space, mkIntCLit_0]
+ `thenUs` \ heap_chk ->
- returnUs (heap_chk .
- (\xs -> save : cjmp : abort : join : a1 : a2 : a3 : restore : xs))
+ returnUs (heap_chk .
+ (\xs -> save : cjmp : abort : join : a1 : a2 : a3 : restore : xs))
mkIntCLit_0 = mkIntCLit 0 -- out here to avoid CAF (sigh)
encodeFloatingKind
:: PrimRep
- -> Target
-> CAddrMode -- result
-> (CAddrMode,CAddrMode,CAddrMode,CAddrMode,CAddrMode)
-- heap pointer for result, integer argument (3 parts), exponent
-> UniqSM StixTreeList
-encodeFloatingKind pk target_STRICT res args@(chp, caa,csa,cda, cexpon) =
- let
- a2stix = amodeToStix target
- size_of = sizeof target
- data_hs = dataHS target
-
- result = a2stix res
- hp = a2stix chp
- aa = a2stix caa
- sa = a2stix csa
- da = a2stix cda
- expon = a2stix cexpon
-
- pk' = if size_of FloatRep == size_of DoubleRep
+encodeFloatingKind pk res args@(chp, caa,csa,cda, cexpon)
+ = let
+ result = amodeToStix res
+ hp = amodeToStix chp
+ aa = amodeToStix caa
+ sa = amodeToStix csa
+ da = amodeToStix cda
+ expon = amodeToStix cexpon
+
+ pk' = if sizeOf FloatRep == sizeOf DoubleRep
then DoubleRep
else pk
- (a1,a2,a3) = toStruct data_hs hp (aa,sa,da)
+ (a1,a2,a3) = toStruct hp (aa,sa,da)
fn = case pk' of
FloatRep -> SLIT("__encodeFloat")
DoubleRep -> SLIT("__encodeDouble")
encode = StCall fn pk' [hp, expon]
r1 = StAssign pk' result encode
in
- returnUs (\xs -> a1 : a2 : a3 : r1 : xs)
+ returnUs (\xs -> a1 : a2 : a3 : r1 : xs)
decodeFloatingKind
:: PrimRep
- -> Target
-> (CAddrMode, CAddrMode, CAddrMode, CAddrMode)
-- exponent result, integer result (3 parts)
-> (CAddrMode, CAddrMode)
-- heap pointer for exponent, floating argument
-> UniqSM StixTreeList
-decodeFloatingKind pk target_STRICT res@(cexponr,car,csr,cdr) args@(chp, carg) =
- let
- a2stix = amodeToStix target
- size_of = sizeof target
- data_hs = dataHS target
-
- exponr = a2stix cexponr
- ar = a2stix car
- sr = a2stix csr
- dr = a2stix cdr
- hp = a2stix chp
- arg = a2stix carg
-
- pk' = if size_of FloatRep == size_of DoubleRep
+decodeFloatingKind pk res@(cexponr,car,csr,cdr) args@(chp, carg)
+ = let
+ exponr = amodeToStix cexponr
+ ar = amodeToStix car
+ sr = amodeToStix csr
+ dr = amodeToStix cdr
+ hp = amodeToStix chp
+ arg = amodeToStix carg
+
+ pk' = if sizeOf FloatRep == sizeOf DoubleRep
then DoubleRep
else pk
setup = StAssign PtrRep mpData_mantissa (StIndex IntRep hp (StInt 1))
DoubleRep -> SLIT("__decodeDouble")
_ -> panic "decodeFloatingKind"
decode = StCall fn VoidRep [mantissa, hp, arg]
- (a1,a2,a3) = fromStruct data_hs mantissa (ar,sr,dr)
+ (a1,a2,a3) = fromStruct mantissa (ar,sr,dr)
a4 = StAssign IntRep exponr (StInd IntRep hp)
in
- returnUs (\xs -> setup : decode : a1 : a2 : a3 : a4 : xs)
+ returnUs (\xs -> setup : decode : a1 : a2 : a3 : a4 : xs)
mantissa = mpStruct 1 -- out here to avoid CAF (sigh)
mpData_mantissa = mpData mantissa
Support for the Gnu GMP multi-precision package.
\begin{code}
-
mpIntSize = 3 :: Int
mpAlloc, mpSize, mpData :: StixTree -> StixTree
mpData base = StInd PtrRep (StIndex IntRep base (StInt 2))
mpSpace
- :: StixTree -- dataHs from Target
- -> Int -- gmp structures needed
+ :: Int -- gmp structures needed
-> Int -- number of results
-> [StixTree] -- sizes to add for estimating result size
-> StixTree -- total space
-mpSpace data_hs gmp res sizes =
- foldr sum (StPrim IntAddOp [fixed, hdrs]) sizes
+mpSpace gmp res sizes
+ = foldr sum (StPrim IntAddOp [fixed, hdrs]) sizes
where
sum x y = StPrim IntAddOp [StPrim IntAbsOp [x], y]
fixed = StInt (toInteger (17 * res + gmp * mpIntSize))
- hdrs = StPrim IntMulOp [data_hs, StInt (toInteger res)]
-
+ hdrs = StPrim IntMulOp [dataHS, StInt (toInteger res)]
\end{code}
-We don't have a truly portable way of allocating local temporaries, so we
-cheat and use space at the end of the heap. (Thus, negative offsets from
-HpLim are our temporaries.) Note that you must have performed a heap check
-which includes the space needed for these temporaries before you use them.
+We don't have a truly portable way of allocating local temporaries, so
+we cheat and use space at the end of the heap. (Thus, negative
+offsets from HpLim are our temporaries.) Note that you must have
+performed a heap check which includes the space needed for these
+temporaries before you use them.
\begin{code}
mpStruct :: Int -> StixTree
mpStruct n = StIndex IntRep stgHpLim (StInt (toInteger (-(n * mpIntSize))))
toStruct
- :: StixTree -- dataHS, from Target
- -> StixTree
+ :: StixTree
-> (StixTree, StixTree, StixTree)
-> (StixTree, StixTree, StixTree)
-toStruct data_hs str (alloc,size,arr) =
- let
+toStruct str (alloc,size,arr)
+ = let
f1 = StAssign IntRep (mpAlloc str) alloc
f2 = StAssign IntRep (mpSize str) size
- f3 = StAssign PtrRep (mpData str) (StIndex PtrRep arr data_hs)
+ f3 = StAssign PtrRep (mpData str) (StIndex PtrRep arr dataHS)
in
- (f1, f2, f3)
+ (f1, f2, f3)
fromStruct
- :: StixTree -- dataHS, from Target
- -> StixTree
+ :: StixTree
-> (StixTree, StixTree, StixTree)
-> (StixTree, StixTree, StixTree)
-fromStruct data_hs str (alloc,size,arr) =
- let
+fromStruct str (alloc,size,arr)
+ = let
e1 = StAssign IntRep alloc (mpAlloc str)
e2 = StAssign IntRep size (mpSize str)
e3 = StAssign PtrRep arr (StIndex PtrRep (mpData str)
- (StPrim IntNegOp [data_hs]))
+ (StPrim IntNegOp [dataHS]))
in
- (e1, e2, e3)
+ (e1, e2, e3)
\end{code}
%
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1996
%
\begin{code}
#include "HsVersions.h"
-module StixMacro (
- genMacroCode, doHeapCheck, smStablePtrTable,
+module StixMacro ( macroCode, heapCheck ) where
- Target, StixTree, UniqSupply, CAddrMode, CExprMacro,
- CStmtMacro
- ) where
+import Ubiq{-uitious-}
+import NcgLoop ( amodeToStix )
-import AbsCSyn
-import PrelInfo ( PrimOp(..)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import MachDesc {- lots -}
-import CgCompInfo ( sTD_UF_SIZE, uF_RET, uF_SUA, uF_SUB, uF_UPDATEE )
+import MachMisc
+import MachRegs
+
+import AbsCSyn ( CStmtMacro(..), MagicId(..), mkIntCLit, CAddrMode )
+import CgCompInfo ( uF_RET, uF_SUA, uF_SUB, uF_UPDATEE,
+ sTD_UF_SIZE
+ )
+import OrdList ( OrdList )
+import PrimOp ( PrimOp(..) )
+import PrimRep ( PrimRep(..) )
import Stix
-import UniqSupply
-import Util
+import UniqSupply ( returnUs, thenUs, UniqSM(..) )
\end{code}
The @ARGS_CHK_A{_LOAD_NODE}@ macros check for sufficient arguments on
mkIntCLit_0 = mkIntCLit 0 -- out here to avoid CAF (sigh)
mkIntCLit_3 = mkIntCLit 3
--- hacking with Uncle Will:
-#define target_STRICT target@(Target _ _ _ _ _ _ _ _)
-
-genMacroCode
- :: Target
- -> CStmtMacro -- statement macro
+macroCode
+ :: CStmtMacro -- statement macro
-> [CAddrMode] -- args
-> UniqSM StixTreeList
-genMacroCode target_STRICT macro args
- = genmacro macro args
- where
- a2stix = amodeToStix target
- stg_reg = stgReg target
-
- -- real thing: here we go -----------------------
-
- genmacro ARGS_CHK_A_LOAD_NODE args =
- getUniqLabelNCG `thenUs` \ ulbl ->
- let [words, lbl] = map a2stix args
- temp = StIndex PtrRep stgSpA words
- test = StPrim AddrGeOp [stgSuA, temp]
- cjmp = StCondJump ulbl test
- assign = StAssign PtrRep stgNode lbl
- join = StLabel ulbl
+macroCode ARGS_CHK_A_LOAD_NODE args
+ = getUniqLabelNCG `thenUs` \ ulbl ->
+ let
+ [words, lbl] = map amodeToStix args
+ temp = StIndex PtrRep stgSpA words
+ test = StPrim AddrGeOp [stgSuA, temp]
+ cjmp = StCondJump ulbl test
+ assign = StAssign PtrRep stgNode lbl
+ join = StLabel ulbl
in
- returnUs (\xs -> cjmp : assign : updatePAP : join : xs)
+ returnUs (\xs -> cjmp : assign : updatePAP : join : xs)
- genmacro ARGS_CHK_A [words] =
- getUniqLabelNCG `thenUs` \ ulbl ->
- let temp = StIndex PtrRep stgSpA (a2stix words)
+macroCode ARGS_CHK_A [words]
+ = getUniqLabelNCG `thenUs` \ ulbl ->
+ let temp = StIndex PtrRep stgSpA (amodeToStix words)
test = StPrim AddrGeOp [stgSuA, temp]
cjmp = StCondJump ulbl test
join = StLabel ulbl
in
- returnUs (\xs -> cjmp : updatePAP : join : xs)
-
+ returnUs (\xs -> cjmp : updatePAP : join : xs)
\end{code}
Like the macros above, the @ARGS_CHK_B{_LOAD_NODE}@ macros check for
directions are swapped relative to the A stack.
\begin{code}
-
- genmacro ARGS_CHK_B_LOAD_NODE args =
- getUniqLabelNCG `thenUs` \ ulbl ->
- let [words, lbl] = map a2stix args
+macroCode ARGS_CHK_B_LOAD_NODE args
+ = getUniqLabelNCG `thenUs` \ ulbl ->
+ let
+ [words, lbl] = map amodeToStix args
temp = StIndex PtrRep stgSuB (StPrim IntNegOp [words])
test = StPrim AddrGeOp [stgSpB, temp]
cjmp = StCondJump ulbl test
assign = StAssign PtrRep stgNode lbl
join = StLabel ulbl
in
- returnUs (\xs -> cjmp : assign : updatePAP : join : xs)
+ returnUs (\xs -> cjmp : assign : updatePAP : join : xs)
- genmacro ARGS_CHK_B [words] =
- getUniqLabelNCG `thenUs` \ ulbl ->
- let temp = StIndex PtrRep stgSuB (StPrim IntNegOp [a2stix words])
+macroCode ARGS_CHK_B [words]
+ = getUniqLabelNCG `thenUs` \ ulbl ->
+ let
+ temp = StIndex PtrRep stgSuB (StPrim IntNegOp [amodeToStix words])
test = StPrim AddrGeOp [stgSpB, temp]
cjmp = StCondJump ulbl test
join = StLabel ulbl
in
- returnUs (\xs -> cjmp : updatePAP : join : xs)
-
+ returnUs (\xs -> cjmp : updatePAP : join : xs)
\end{code}
The @HEAP_CHK@ macro checks to see that there are enough words
available in the heap (before reaching @HpLim@). When a heap check
fails, it has to call @PerformGC@ via the @PerformGC_wrapper@. The
-call wrapper saves all of our volatile registers so that we don't have to.
+call wrapper saves all of our volatile registers so that we don't have
+to.
-Since there are @HEAP_CHK@s buried at unfortunate places in the integer
-primOps, this is just a wrapper.
+Since there are @HEAP_CHK@s buried at unfortunate places in the
+integer primOps, this is just a wrapper.
\begin{code}
-
- genmacro HEAP_CHK args =
- let [liveness,words,reenter] = map a2stix args
+macroCode HEAP_CHK args
+ = let [liveness,words,reenter] = map amodeToStix args
in
- doHeapCheck liveness words reenter
+ heapCheck liveness words reenter
\end{code}
The @STK_CHK@ macro checks for enough space on the stack between @SpA@
so we don't have to @callWrapper@ it.
\begin{code}
-
- genmacro STK_CHK [liveness, aWords, bWords, spa, spb, prim, reenter] =
+macroCode STK_CHK [liveness, aWords, bWords, spa, spb, prim, reenter]
+ =
{- Need to check to see if we are compiling with stack checks
- getUniqLabelNCG `thenUs` \ ulbl ->
+ getUniqLabelNCG `thenUs` \ ulbl ->
let words = StPrim IntNegOp
- [StPrim IntAddOp [a2stix aWords, a2stix bWords]]
+ [StPrim IntAddOp [amodeToStix aWords, amodeToStix bWords]]
temp = StIndex PtrRep stgSpA words
test = StPrim AddrGtOp [temp, stgSpB]
cjmp = StCondJump ulbl test
returnUs (\xs -> cjmp : stackOverflow : join : xs)
-}
returnUs id
-
\end{code}
-@UPD_CAF@ involves changing the info pointer of the closure, adding an indirection,
-and putting the new CAF on a linked list for the storage manager.
+@UPD_CAF@ involves changing the info pointer of the closure, adding an
+indirection, and putting the new CAF on a linked list for the storage
+manager.
\begin{code}
-
- genmacro UPD_CAF args =
- let [cafptr,bhptr] = map a2stix args
+macroCode UPD_CAF args
+ = let
+ [cafptr,bhptr] = map amodeToStix args
w0 = StInd PtrRep cafptr
w1 = StInd PtrRep (StIndex PtrRep cafptr (StInt 1))
w2 = StInd PtrRep (StIndex PtrRep cafptr (StInt 2))
a3 = StAssign PtrRep w2 bhptr
a4 = StAssign PtrRep smCAFlist cafptr
in
- returnUs (\xs -> a1 : a2 : a3 : a4 : xs)
-
+ returnUs (\xs -> a1 : a2 : a3 : a4 : xs)
\end{code}
@UPD_IND@ is complicated by the fact that we are supporting the
if we update an old generation object.
\begin{code}
-
- genmacro UPD_IND args =
- getUniqLabelNCG `thenUs` \ ulbl ->
- let [updptr, heapptr] = map a2stix args
+macroCode UPD_IND args
+ = getUniqLabelNCG `thenUs` \ ulbl ->
+ let
+ [updptr, heapptr] = map amodeToStix args
test = StPrim AddrGtOp [updptr, smOldLim]
cjmp = StCondJump ulbl test
updRoots = StAssign PtrRep smOldMutables updptr
upd2 = StAssign PtrRep (StInd PtrRep
(StIndex PtrRep updptr (StInt 2))) heapptr
in
- returnUs (\xs -> cjmp : upd1 : updRoots : join : upd0 : upd2 : xs)
-
+ returnUs (\xs -> cjmp : upd1 : updRoots : join : upd0 : upd2 : xs)
\end{code}
@UPD_INPLACE_NOPTRS@ is only needed for ticky-ticky profiling.
\begin{code}
-
- genmacro UPD_INPLACE_NOPTRS args = returnUs id
-
+macroCode UPD_INPLACE_NOPTRS args = returnUs id
\end{code}
@UPD_INPLACE_PTRS@ is complicated by the fact that we are supporting
-the Appel-style garbage collector by default. This means some extra work
-if we update an old generation object.
+the Appel-style garbage collector by default. This means some extra
+work if we update an old generation object.
\begin{code}
-
- genmacro UPD_INPLACE_PTRS [liveness] =
- getUniqLabelNCG `thenUs` \ ulbl ->
+macroCode UPD_INPLACE_PTRS [liveness]
+ = getUniqLabelNCG `thenUs` \ ulbl ->
let cjmp = StCondJump ulbl testOldLim
testOldLim = StPrim AddrGtOp [stgNode, smOldLim]
join = StLabel ulbl
updOldMutables = StAssign PtrRep smOldMutables stgNode
updUpdReg = StAssign PtrRep stgNode hpBack2
in
- genmacro HEAP_CHK [liveness, mkIntCLit_3, mkIntCLit_0]
- `thenUs` \ heap_chk ->
- returnUs (\xs -> (cjmp :
- heap_chk (updUpd0 : updUpd1 : updUpd2 :
- updOldMutables : updUpdReg : join : xs)))
-
+ macroCode HEAP_CHK [liveness, mkIntCLit_3, mkIntCLit_0]
+ `thenUs` \ heap_chk ->
+ returnUs (\xs -> (cjmp :
+ heap_chk (updUpd0 : updUpd1 : updUpd2 :
+ updOldMutables : updUpdReg : join : xs)))
\end{code}
@UPD_BH_UPDATABLE@ is only used when running concurrent threads (in
to handle @UPD_BH_SINGLE_ENTRY@ in all cases.
\begin{code}
+macroCode UPD_BH_UPDATABLE args = returnUs id
- genmacro UPD_BH_UPDATABLE args = returnUs id
-
- genmacro UPD_BH_SINGLE_ENTRY [arg] =
- let
- update = StAssign PtrRep (StInd PtrRep (a2stix arg)) bh_info
+macroCode UPD_BH_SINGLE_ENTRY [arg]
+ = let
+ update = StAssign PtrRep (StInd PtrRep (amodeToStix arg)) bh_info
in
- returnUs (\xs -> update : xs)
-
+ returnUs (\xs -> update : xs)
\end{code}
Push a four word update frame on the stack and slide the Su[AB]
registers to the current Sp[AB] locations.
\begin{code}
-
- genmacro PUSH_STD_UPD_FRAME args =
- let [bhptr, aWords, bWords] = map a2stix args
+macroCode PUSH_STD_UPD_FRAME args
+ = let
+ [bhptr, aWords, bWords] = map amodeToStix args
frame n = StInd PtrRep
(StIndex PtrRep stgSpB (StPrim IntAddOp
[bWords, StInt (toInteger (sTD_UF_SIZE - n))]))
updSuA = StAssign PtrRep
stgSuA (StIndex PtrRep stgSpA (StPrim IntNegOp [aWords]))
in
- returnUs (\xs -> a1 : a2 : a3 : a4 : updSuB : updSuA : xs)
-
+ returnUs (\xs -> a1 : a2 : a3 : a4 : updSuB : updSuA : xs)
\end{code}
Pop a standard update frame.
\begin{code}
-
- genmacro POP_STD_UPD_FRAME args =
- let frame n = StInd PtrRep (StIndex PtrRep stgSpB (StInt (toInteger (-n))))
+macroCode POP_STD_UPD_FRAME args
+ = let
+ frame n = StInd PtrRep (StIndex PtrRep stgSpB (StInt (toInteger (-n))))
grabRet = StAssign PtrRep stgRetReg (frame uF_RET)
grabSuB = StAssign PtrRep stgSuB (frame uF_SUB)
updSpB = StAssign PtrRep
stgSpB (StIndex PtrRep stgSpB (StInt (toInteger (-sTD_UF_SIZE))))
in
- returnUs (\xs -> grabRet : grabSuB : grabSuA : updSpB : xs)
-
+ returnUs (\xs -> grabRet : grabSuB : grabSuA : updSpB : xs)
\end{code}
The @SET_ARITY@ and @CHK_ARITY@ macros are disabled for ``normal''
compilation.
\begin{code}
- genmacro SET_ARITY args = returnUs id
- genmacro CHK_ARITY args = returnUs id
+macroCode SET_ARITY args = returnUs id
+macroCode CHK_ARITY args = returnUs id
\end{code}
This one only applies if we have a machine register devoted to TagReg.
\begin{code}
- genmacro SET_TAG [tag] =
- let set_tag = StAssign IntRep stgTagReg (a2stix tag)
+macroCode SET_TAG [tag]
+ = let set_tag = StAssign IntRep stgTagReg (amodeToStix tag)
in
- case stg_reg TagReg of
- Always _ -> returnUs id
- Save _ -> returnUs (\ xs -> set_tag : xs)
+ case stgReg TagReg of
+ Always _ -> returnUs id
+ Save _ -> returnUs (\ xs -> set_tag : xs)
\end{code}
Do the business for a @HEAP_CHK@, having converted the args to Trees
of StixOp.
\begin{code}
-
-doHeapCheck
- :: {- unused now: Target
- -> -}StixTree -- liveness
+heapCheck
+ :: StixTree -- liveness
-> StixTree -- words needed
-> StixTree -- always reenter node? (boolean)
-> UniqSM StixTreeList
-doHeapCheck {-target:unused now-} liveness words reenter =
- getUniqLabelNCG `thenUs` \ ulbl ->
+heapCheck liveness words reenter
+ = getUniqLabelNCG `thenUs` \ ulbl ->
let newHp = StIndex PtrRep stgHp words
assign = StAssign PtrRep stgHp newHp
test = StPrim AddrLeOp [stgHp, stgHpLim]
gc = StCall SLIT("PerformGC_wrapper") VoidRep [arg]
join = StLabel ulbl
in
- returnUs (\xs -> assign : cjmp : gc : join : xs)
-
+ returnUs (\xs -> assign : cjmp : gc : join : xs)
\end{code}
Let's make sure that these CAFs are lifted out, shall we?
\begin{code}
-
-- Some common labels
bh_info, caf_info, ind_info :: StixTree
updatePAP = StJump (sStLitLbl SLIT("UpdatePAP"))
stackOverflow = StCall SLIT("StackOverflow") VoidRep []
-
-\end{code}
-
-Storage manager nonsense. Note that the indices are dependent on
-the definition of the smInfo structure in SMinterface.lh
-
-\begin{code}
-
-#include "../../includes/platform.h"
-
-#if alpha_TARGET_ARCH
-#include "../../includes/alpha-dec-osf1.h"
-#else
-#if sunos4_TARGET_OS
-#include "../../includes/sparc-sun-sunos4.h"
-#else
-#include "../../includes/sparc-sun-solaris2.h"
-#endif
-#endif
-
-storageMgrInfo, smCAFlist, smOldMutables, smOldLim :: StixTree
-
-storageMgrInfo = sStLitLbl SLIT("StorageMgrInfo")
-smCAFlist = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_CAFLIST))
-smOldMutables = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_OLDMUTABLES))
-smOldLim = StInd PtrRep (StIndex PtrRep storageMgrInfo (StInt SM_OLDLIM))
-
-smStablePtrTable = StInd PtrRep
- (StIndex PtrRep storageMgrInfo (StInt SM_STABLEPOINTERTABLE))
-
\end{code}
%
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1996
%
\begin{code}
#include "HsVersions.h"
-module StixPrim (
- genPrimCode, amodeCode, amodeCode',
+module StixPrim ( primCode, amodeToStix, amodeToStix' ) where
- Target, CAddrMode, StixTree, PrimOp, UniqSupply
- ) where
+import Ubiq{-uitous-}
+import NcgLoop -- paranoia checking only
-IMPORT_Trace -- ToDo: rm debugging
+import MachMisc
+import MachRegs
import AbsCSyn
-import PrelInfo ( PrimOp(..), PrimOpResultInfo(..), TyCon,
- getPrimOpResultInfo, isCompareOp, showPrimOp
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
+import AbsCUtils ( getAmodeRep, mixedTypeLocn )
import CgCompInfo ( spARelToInt, spBRelToInt )
-import MachDesc
-import Pretty
-import PrimRep ( isFloatingRep )
-import CostCentre
-import SMRep ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..) )
+import CostCentre ( noCostCentreAttached )
+import HeapOffs ( hpRelToInt, subOff )
+import Literal ( Literal(..) )
+import PrimOp ( PrimOp(..), isCompareOp, showPrimOp,
+ getPrimOpResultInfo, PrimOpResultInfo(..)
+ )
+import PrimRep ( PrimRep(..), isFloatingRep )
+import OrdList ( OrdList )
+import PprStyle ( PprStyle(..) )
+import SMRep ( SMRep(..), SMSpecRepKind, SMUpdateKind )
import Stix
-import StixMacro ( smStablePtrTable )
+import StixMacro ( heapCheck, smStablePtrTable )
import StixInteger {- everything -}
-import UniqSupply
-import Unpretty
-import Util
-
+import UniqSupply ( returnUs, thenUs, UniqSM(..) )
+import Unpretty ( uppBeside, uppPStr, uppInt )
+import Util ( panic )
\end{code}
-The main honcho here is genPrimCode, which handles the guts of COpStmts.
+The main honcho here is primCode, which handles the guts of COpStmts.
\begin{code}
arrayOfData_info = sStLitLbl SLIT("ArrayOfData_info") -- out here to avoid CAF (sigh)
imMutArrayOfPtrs_info = sStLitLbl SLIT("ImMutArrayOfPtrs_info")
-genPrimCode
- :: Target
- -> [CAddrMode] -- results
+primCode
+ :: [CAddrMode] -- results
-> PrimOp -- op
-> [CAddrMode] -- args
-> UniqSM StixTreeList
-
\end{code}
First, the dreaded @ccall@. We can't handle @casm@s.
-Usually, this compiles to an assignment, but when the left-hand side is
-empty, we just perform the call and ignore the result.
+Usually, this compiles to an assignment, but when the left-hand side
+is empty, we just perform the call and ignore the result.
ToDo ADR: modify this to handle Malloc Ptrs.
btw Why not let programmer use casm to provide assembly code instead
of C code? ADR
-\begin{code}
--- hacking with Uncle Will:
-#define target_STRICT target@(Target _ _ _ _ _ _ _ _)
-
-genPrimCode target_STRICT res op args
- = genprim res op args
- where
- a2stix = amodeToStix target
- a2stix' = amodeToStix' target
- mut_hs = mutHS target
- data_hs = dataHS target
- heap_chkr = heapCheck target
- size_of = sizeof target
- fixed_hs = fixedHeaderSize target
- var_hs = varHeaderSize target
-
- --- real code will follow... -------------
-\end{code}
-
-The (MP) integer operations are a true nightmare. Since we don't have a
-convenient abstract way of allocating temporary variables on the (C) stack,
-we use the space just below HpLim for the @MP_INT@ structures, and modify our
-heap check accordingly.
+The (MP) integer operations are a true nightmare. Since we don't have
+a convenient abstract way of allocating temporary variables on the (C)
+stack, we use the space just below HpLim for the @MP_INT@ structures,
+and modify our heap check accordingly.
\begin{code}
- -- NB: ordering of clauses somewhere driven by
- -- the desire to getting sane patt-matching behavior
-
- genprim res@[ar1,sr1,dr1, ar2,sr2,dr2]
- IntegerQuotRemOp
- args@[liveness, aa1,sa1,da1, aa2,sa2,da2] =
- gmpTake2Return2 target (ar1,sr1,dr1, ar2,sr2,dr2) SLIT("mpz_divmod") (liveness, aa1,sa1,da1, aa2,sa2,da2)
-
- genprim res@[ar1,sr1,dr1, ar2,sr2,dr2]
- IntegerDivModOp
- args@[liveness, aa1,sa1,da1, aa2,sa2,da2] =
- gmpTake2Return2 target (ar1,sr1,dr1, ar2,sr2,dr2) SLIT("mpz_targetivmod") (liveness, aa1,sa1,da1, aa2,sa2,da2)
-
- genprim res@[ar,sr,dr] IntegerAddOp args@[liveness, aa1,sa1,da1, aa2,sa2,da2] =
- gmpTake2Return1 target (ar,sr,dr) SLIT("mpz_add") (liveness, aa1,sa1,da1, aa2,sa2,da2)
- genprim res@[ar,sr,dr] IntegerSubOp args@[liveness, aa1,sa1,da1, aa2,sa2,da2] =
- gmpTake2Return1 target (ar,sr,dr) SLIT("mpz_sub") (liveness, aa1,sa1,da1, aa2,sa2,da2)
- genprim res@[ar,sr,dr] IntegerMulOp args@[liveness, aa1,sa1,da1, aa2,sa2,da2] =
- gmpTake2Return1 target (ar,sr,dr) SLIT("mpz_mul") (liveness, aa1,sa1,da1, aa2,sa2,da2)
-
- genprim res@[ar,sr,dr] IntegerNegOp arg@[liveness,aa,sa,da] =
- gmpTake1Return1 target (ar,sr,dr) SLIT("mpz_neg") (liveness,aa,sa,da)
+-- NB: ordering of clauses somewhere driven by
+-- the desire to getting sane patt-matching behavior
+
+primCode res@[ar1,sr1,dr1, ar2,sr2,dr2]
+ IntegerQuotRemOp
+ args@[liveness, aa1,sa1,da1, aa2,sa2,da2]
+ = gmpTake2Return2 (ar1,sr1,dr1, ar2,sr2,dr2) SLIT("mpz_divmod") (liveness, aa1,sa1,da1, aa2,sa2,da2)
+
+primCode res@[ar1,sr1,dr1, ar2,sr2,dr2]
+ IntegerDivModOp
+ args@[liveness, aa1,sa1,da1, aa2,sa2,da2]
+ = gmpTake2Return2 (ar1,sr1,dr1, ar2,sr2,dr2) SLIT("mpz_targetivmod") (liveness, aa1,sa1,da1, aa2,sa2,da2)
+
+primCode res@[ar,sr,dr] IntegerAddOp args@[liveness, aa1,sa1,da1, aa2,sa2,da2]
+ = gmpTake2Return1 (ar,sr,dr) SLIT("mpz_add") (liveness, aa1,sa1,da1, aa2,sa2,da2)
+primCode res@[ar,sr,dr] IntegerSubOp args@[liveness, aa1,sa1,da1, aa2,sa2,da2]
+ = gmpTake2Return1 (ar,sr,dr) SLIT("mpz_sub") (liveness, aa1,sa1,da1, aa2,sa2,da2)
+primCode res@[ar,sr,dr] IntegerMulOp args@[liveness, aa1,sa1,da1, aa2,sa2,da2]
+ = gmpTake2Return1 (ar,sr,dr) SLIT("mpz_mul") (liveness, aa1,sa1,da1, aa2,sa2,da2)
+
+primCode res@[ar,sr,dr] IntegerNegOp arg@[liveness,aa,sa,da]
+ = gmpTake1Return1 (ar,sr,dr) SLIT("mpz_neg") (liveness,aa,sa,da)
\end{code}
-Since we are using the heap for intermediate @MP_INT@ structs, integer comparison
-{\em does} require a heap check in the native code implementation.
+Since we are using the heap for intermediate @MP_INT@ structs, integer
+comparison {\em does} require a heap check in the native code
+implementation.
\begin{code}
- genprim res@[exponr,ar,sr,dr] FloatDecodeOp args@[hp, arg] =
- decodeFloatingKind FloatRep target (exponr,ar,sr,dr) (hp, arg)
-
- genprim res@[exponr,ar,sr,dr] DoubleDecodeOp args@[hp, arg] =
- decodeFloatingKind DoubleRep target (exponr,ar,sr,dr) (hp, arg)
+primCode res@[exponr,ar,sr,dr] FloatDecodeOp args@[hp, arg]
+ = decodeFloatingKind FloatRep (exponr,ar,sr,dr) (hp, arg)
- genprim res@[ar,sr,dr] Int2IntegerOp args@[hp, n]
- = gmpInt2Integer target (ar,sr,dr) (hp, n)
+primCode res@[exponr,ar,sr,dr] DoubleDecodeOp args@[hp, arg]
+ = decodeFloatingKind DoubleRep (exponr,ar,sr,dr) (hp, arg)
- genprim res@[ar,sr,dr] Addr2IntegerOp args@[liveness,str]
- = gmpString2Integer target (ar,sr,dr) (liveness,str)
+primCode res@[ar,sr,dr] Int2IntegerOp args@[hp, n]
+ = gmpInt2Integer (ar,sr,dr) (hp, n)
- genprim [res] IntegerCmpOp args@[hp, aa1,sa1,da1, aa2,sa2,da2]
- = gmpCompare target res (hp, aa1,sa1,da1, aa2,sa2,da2)
+primCode res@[ar,sr,dr] Addr2IntegerOp args@[liveness,str]
+ = gmpString2Integer (ar,sr,dr) (liveness,str)
- genprim [res] Integer2IntOp arg@[hp, aa,sa,da]
- = gmpInteger2Int target res (hp, aa,sa,da)
+primCode [res] IntegerCmpOp args@[hp, aa1,sa1,da1, aa2,sa2,da2]
+ = gmpCompare res (hp, aa1,sa1,da1, aa2,sa2,da2)
- genprim [res] FloatEncodeOp args@[hp, aa,sa,da, expon] =
- encodeFloatingKind FloatRep target res (hp, aa,sa,da, expon)
+primCode [res] Integer2IntOp arg@[hp, aa,sa,da]
+ = gmpInteger2Int res (hp, aa,sa,da)
- genprim [res] DoubleEncodeOp args@[hp, aa,sa,da, expon] =
- encodeFloatingKind DoubleRep target res (hp, aa,sa,da, expon)
+primCode [res] FloatEncodeOp args@[hp, aa,sa,da, expon]
+ = encodeFloatingKind FloatRep res (hp, aa,sa,da, expon)
- genprim [res] Int2AddrOp [arg] =
- simpleCoercion AddrRep res arg
+primCode [res] DoubleEncodeOp args@[hp, aa,sa,da, expon]
+ = encodeFloatingKind DoubleRep res (hp, aa,sa,da, expon)
- genprim [res] Addr2IntOp [arg] =
- simpleCoercion IntRep res arg
+primCode [res] Int2AddrOp [arg]
+ = simpleCoercion AddrRep res arg
- genprim [res] Int2WordOp [arg] =
- simpleCoercion IntRep{-WordRep?-} res arg
+primCode [res] Addr2IntOp [arg]
+ = simpleCoercion IntRep res arg
- genprim [res] Word2IntOp [arg] =
- simpleCoercion IntRep res arg
+primCode [res] Int2WordOp [arg]
+ = simpleCoercion IntRep{-WordRep?-} res arg
+primCode [res] Word2IntOp [arg]
+ = simpleCoercion IntRep res arg
\end{code}
-The @ErrorIO@ primitive is actually a bit weird...assign a new value to the root
-closure, flush stdout and stderr, and jump to the @ErrorIO_innards@.
+The @ErrorIO@ primitive is actually a bit weird...assign a new value
+to the root closure, flush stdout and stderr, and jump to the
+@ErrorIO_innards@.
\begin{code}
-
- genprim [] ErrorIOPrimOp [rhs] =
- let changeTop = StAssign PtrRep topClosure (a2stix rhs)
+primCode [] ErrorIOPrimOp [rhs]
+ = let
+ changeTop = StAssign PtrRep topClosure (amodeToStix rhs)
in
- returnUs (\xs -> changeTop : flushStdout : flushStderr : errorIO : xs)
-
+ returnUs (\xs -> changeTop : flushStdout : flushStderr : errorIO : xs)
\end{code}
@newArray#@ ops allocate heap space.
\begin{code}
- genprim [res] NewArrayOp args =
- let [liveness, n, initial] = map a2stix args
- result = a2stix res
- space = StPrim IntAddOp [n, mut_hs]
+primCode [res] NewArrayOp args
+ = let
+ [liveness, n, initial] = map amodeToStix args
+ result = amodeToStix res
+ space = StPrim IntAddOp [n, mutHS]
loc = StIndex PtrRep stgHp
(StPrim IntNegOp [StPrim IntSubOp [space, StInt 1]])
assign = StAssign PtrRep result loc
initialise = StCall SLIT("newArrZh_init") VoidRep [result, n, initial]
in
- heap_chkr liveness space (StInt 0) `thenUs` \ heap_chk ->
-
- returnUs (heap_chk . (\xs -> assign : initialise : xs))
-
- genprim [res] (NewByteArrayOp pk) args =
- let [liveness, count] = map a2stix args
- result = a2stix res
- n = StPrim IntMulOp [count, StInt (toInteger (size_of pk))]
- slop = StPrim IntAddOp [n, StInt (toInteger (size_of IntRep - 1))]
- words = StPrim IntQuotOp [slop, StInt (toInteger (size_of IntRep))]
- space = StPrim IntAddOp [n, StPrim IntAddOp [words, data_hs]]
+ heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
+
+ returnUs (heap_chk . (\xs -> assign : initialise : xs))
+
+primCode [res] (NewByteArrayOp pk) args
+ = let
+ [liveness, count] = map amodeToStix args
+ result = amodeToStix res
+ n = StPrim IntMulOp [count, StInt (sizeOf pk)]
+ slop = StPrim IntAddOp [n, StInt (sizeOf IntRep - 1)]
+ words = StPrim IntQuotOp [slop, StInt (sizeOf IntRep)]
+ space = StPrim IntAddOp [n, StPrim IntAddOp [words, dataHS]]
loc = StIndex PtrRep stgHp
(StPrim IntNegOp [StPrim IntSubOp [space, StInt 1]])
assign = StAssign PtrRep result loc
init2 = StAssign IntRep
(StInd IntRep
(StIndex IntRep loc
- (StInt (toInteger fixed_hs))))
+ (StInt (toInteger fixedHdrSizeInWords))))
(StPrim IntAddOp [words,
- StInt (toInteger (var_hs (DataRep 0)))])
+ StInt (toInteger (varHdrSizeInWords (DataRep 0)))])
in
- heap_chkr liveness space (StInt 0) `thenUs` \ heap_chk ->
+ heapCheck liveness space (StInt 0) `thenUs` \ heap_chk ->
- returnUs (heap_chk . (\xs -> assign : init1 : init2 : xs))
+ returnUs (heap_chk . (\xs -> assign : init1 : init2 : xs))
- genprim [res] SameMutableArrayOp args =
- let compare = StPrim AddrEqOp (map a2stix args)
- assign = StAssign IntRep (a2stix res) compare
+primCode [res] SameMutableArrayOp args
+ = let
+ compare = StPrim AddrEqOp (map amodeToStix args)
+ assign = StAssign IntRep (amodeToStix res) compare
in
- returnUs (\xs -> assign : xs)
-
- genprim res@[_] SameMutableByteArrayOp args =
- genprim res SameMutableArrayOp args
+ returnUs (\xs -> assign : xs)
+primCode res@[_] SameMutableByteArrayOp args
+ = primCode res SameMutableArrayOp args
\end{code}
-Freezing an array of pointers is a double assignment. We fix the header of
-the ``new'' closure because the lhs is probably a better addressing mode for
-the indirection (most likely, it's a VanillaReg).
+Freezing an array of pointers is a double assignment. We fix the
+header of the ``new'' closure because the lhs is probably a better
+addressing mode for the indirection (most likely, it's a VanillaReg).
\begin{code}
- genprim [lhs] UnsafeFreezeArrayOp [rhs] =
- let lhs' = a2stix lhs
- rhs' = a2stix rhs
+primCode [lhs] UnsafeFreezeArrayOp [rhs]
+ = let
+ lhs' = amodeToStix lhs
+ rhs' = amodeToStix rhs
header = StInd PtrRep lhs'
assign = StAssign PtrRep lhs' rhs'
freeze = StAssign PtrRep header imMutArrayOfPtrs_info
in
- returnUs (\xs -> assign : freeze : xs)
-
- genprim [lhs] UnsafeFreezeByteArrayOp [rhs] =
- simpleCoercion PtrRep lhs rhs
+ returnUs (\xs -> assign : freeze : xs)
+primCode [lhs] UnsafeFreezeByteArrayOp [rhs]
+ = simpleCoercion PtrRep lhs rhs
\end{code}
Most other array primitives translate to simple indexing.
\begin{code}
- genprim lhs@[_] IndexArrayOp args =
- genprim lhs ReadArrayOp args
+primCode lhs@[_] IndexArrayOp args
+ = primCode lhs ReadArrayOp args
- genprim [lhs] ReadArrayOp [obj, ix] =
- let lhs' = a2stix lhs
- obj' = a2stix obj
- ix' = a2stix ix
- base = StIndex IntRep obj' mut_hs
+primCode [lhs] ReadArrayOp [obj, ix]
+ = let
+ lhs' = amodeToStix lhs
+ obj' = amodeToStix obj
+ ix' = amodeToStix ix
+ base = StIndex IntRep obj' mutHS
assign = StAssign PtrRep lhs' (StInd PtrRep (StIndex PtrRep base ix'))
in
- returnUs (\xs -> assign : xs)
-
- genprim [lhs] WriteArrayOp [obj, ix, v] =
- let obj' = a2stix obj
- ix' = a2stix ix
- v' = a2stix v
- base = StIndex IntRep obj' mut_hs
+ returnUs (\xs -> assign : xs)
+
+primCode [lhs] WriteArrayOp [obj, ix, v]
+ = let
+ obj' = amodeToStix obj
+ ix' = amodeToStix ix
+ v' = amodeToStix v
+ base = StIndex IntRep obj' mutHS
assign = StAssign PtrRep (StInd PtrRep (StIndex PtrRep base ix')) v'
in
- returnUs (\xs -> assign : xs)
+ returnUs (\xs -> assign : xs)
- genprim lhs@[_] (IndexByteArrayOp pk) args =
- genprim lhs (ReadByteArrayOp pk) args
+primCode lhs@[_] (IndexByteArrayOp pk) args
+ = primCode lhs (ReadByteArrayOp pk) args
-- NB: indexing in "pk" units, *not* in bytes (WDP 95/09)
- genprim [lhs] (ReadByteArrayOp pk) [obj, ix] =
- let lhs' = a2stix lhs
- obj' = a2stix obj
- ix' = a2stix ix
- base = StIndex IntRep obj' data_hs
+primCode [lhs] (ReadByteArrayOp pk) [obj, ix]
+ = let
+ lhs' = amodeToStix lhs
+ obj' = amodeToStix obj
+ ix' = amodeToStix ix
+ base = StIndex IntRep obj' dataHS
assign = StAssign pk lhs' (StInd pk (StIndex pk base ix'))
in
- returnUs (\xs -> assign : xs)
+ returnUs (\xs -> assign : xs)
- genprim [lhs] (IndexOffAddrOp pk) [obj, ix] =
- let lhs' = a2stix lhs
- obj' = a2stix obj
- ix' = a2stix ix
+primCode [lhs] (IndexOffAddrOp pk) [obj, ix]
+ = let
+ lhs' = amodeToStix lhs
+ obj' = amodeToStix obj
+ ix' = amodeToStix ix
assign = StAssign pk lhs' (StInd pk (StIndex pk obj' ix'))
in
- returnUs (\xs -> assign : xs)
-
- genprim [] (WriteByteArrayOp pk) [obj, ix, v] =
- let obj' = a2stix obj
- ix' = a2stix ix
- v' = a2stix v
- base = StIndex IntRep obj' data_hs
+ returnUs (\xs -> assign : xs)
+
+primCode [] (WriteByteArrayOp pk) [obj, ix, v]
+ = let
+ obj' = amodeToStix obj
+ ix' = amodeToStix ix
+ v' = amodeToStix v
+ base = StIndex IntRep obj' dataHS
assign = StAssign pk (StInd pk (StIndex pk base ix')) v'
in
- returnUs (\xs -> assign : xs)
+ returnUs (\xs -> assign : xs)
\end{code}
Stable pointer operations.
First the easy one.
-
\begin{code}
- genprim [lhs] DeRefStablePtrOp [sp] =
- let lhs' = a2stix lhs
+primCode [lhs] DeRefStablePtrOp [sp]
+ = let
+ lhs' = amodeToStix lhs
pk = getAmodeRep lhs
- sp' = a2stix sp
+ sp' = amodeToStix sp
call = StCall SLIT("deRefStablePointer") pk [sp', smStablePtrTable]
assign = StAssign pk lhs' call
in
- returnUs (\xs -> assign : xs)
-
+ returnUs (\xs -> assign : xs)
\end{code}
Now the hard one. For comparison, here's the code from StgMacros:
--JSM
\begin{pseudocode}
- genprim [lhs] MakeStablePtrOp args =
- let
+primCode [lhs] MakeStablePtrOp args
+ = let
-- some useful abbreviations (I'm sure these must exist already)
add = trPrim . IntAddOp
sub = trPrim . IntSubOp
inc x = trAssign IntRep [x, add [x, one]]
-- tedious hardwiring in of closure layout offsets (from SMClosures)
- dynHS = 2 + fixedHeaderSize md sty + varHeaderSize md sty DynamicRep
+ dynHS = 2 + fixedHdrSizeInWords + varHdrSizeInWords DynamicRep
spt_SIZE c = trIndex PtrRep [c, trInt [fhs + gc_reserved] ]
spt_NoPTRS c = trIndex PtrRep [c, trInt [fhs + gc_reserved + 1] ]
spt_SPTR c i = trIndex PtrRep [c, add [trInt [dynHS], i]]
]
-- now to get down to business
- lhs' = amodeCode sty md lhs
- [liveness, unstable] = map (amodeCode sty md) args
+ lhs' = amodeCode lhs
+ [liveness, unstable] = map amodeCode args
spt = smStablePtrTable
\end{pseudocode}
\begin{code}
- genprim res Word2IntegerOp args = panic "genPrimCode:Word2IntegerOp"
-
- genprim lhs (CCallOp fn is_asm may_gc arg_tys result_ty) rhs
- | is_asm = error "ERROR: Native code generator can't handle casm"
- | otherwise =
- case lhs of
- [] -> returnUs (\xs -> (StCall fn VoidRep args) : xs)
- [lhs] ->
- let lhs' = a2stix lhs
- pk = if isFloatingRep (getAmodeRep lhs) then DoubleRep else IntRep
- call = StAssign pk lhs' (StCall fn pk args)
- in
- returnUs (\xs -> call : xs)
- where
- args = map amodeCodeForCCall rhs
- amodeCodeForCCall x =
- let base = a2stix' x
- in
- case getAmodeRep x of
- ArrayRep -> StIndex PtrRep base mut_hs
- ByteArrayRep -> StIndex IntRep base data_hs
- MallocPtrRep -> error "ERROR: native-code generator can't handle Malloc Ptrs (yet): use -fvia-C!"
- _ -> base
+primCode res Word2IntegerOp args = panic "primCode:Word2IntegerOp"
+
+primCode lhs (CCallOp fn is_asm may_gc arg_tys result_ty) rhs
+ | is_asm = error "ERROR: Native code generator can't handle casm"
+ | otherwise
+ = case lhs of
+ [] -> returnUs (\xs -> (StCall fn VoidRep args) : xs)
+ [lhs] ->
+ let lhs' = amodeToStix lhs
+ pk = if isFloatingRep (getAmodeRep lhs) then DoubleRep else IntRep
+ call = StAssign pk lhs' (StCall fn pk args)
+ in
+ returnUs (\xs -> call : xs)
+ where
+ args = map amodeCodeForCCall rhs
+ amodeCodeForCCall x =
+ let base = amodeToStix' x
+ in
+ case getAmodeRep x of
+ ArrayRep -> StIndex PtrRep base mutHS
+ ByteArrayRep -> StIndex IntRep base dataHS
+ MallocPtrRep -> error "ERROR: native-code generator can't handle Malloc Ptrs (yet): use -fvia-C!"
+ _ -> base
\end{code}
Now the more mundane operations.
\begin{code}
- genprim lhs op rhs =
- let lhs' = map a2stix lhs
- rhs' = map a2stix' rhs
+primCode lhs op rhs
+ = let
+ lhs' = map amodeToStix lhs
+ rhs' = map amodeToStix' rhs
in
- returnUs (\ xs -> simplePrim lhs' op rhs' : xs)
-
- {-
- simpleCoercion
- :: Target
- -> PrimRep
- -> [CAddrMode]
- -> [CAddrMode]
+ returnUs (\ xs -> simplePrim lhs' op rhs' : xs)
+\end{code}
+
+\begin{code}
+simpleCoercion
+ :: PrimRep
+ -> CAddrMode
+ -> CAddrMode
-> UniqSM StixTreeList
- -}
- simpleCoercion pk lhs rhs =
- returnUs (\xs -> StAssign pk (a2stix lhs) (a2stix rhs) : xs)
+simpleCoercion pk lhs rhs
+ = returnUs (\xs -> StAssign pk (amodeToStix lhs) (amodeToStix rhs) : xs)
\end{code}
-Here we try to rewrite primitives into a form the code generator
-can understand. Any primitives not handled here must be handled
-at the level of the specific code generator.
+Here we try to rewrite primitives into a form the code generator can
+understand. Any primitives not handled here must be handled at the
+level of the specific code generator.
\begin{code}
- {-
- simplePrim
- :: Target
- -> [StixTree]
+simplePrim
+ :: [StixTree]
-> PrimOp
-> [StixTree]
-> StixTree
- -}
\end{code}
Now look for something more conventional.
\begin{code}
-
- simplePrim [lhs] op rest = StAssign pk lhs (StPrim op rest)
- where pk = if isCompareOp op then IntRep
- else case getPrimOpResultInfo op of
- ReturnsPrim pk -> pk
- _ -> simplePrim_error op
-
- simplePrim _ op _ = simplePrim_error op
-
- simplePrim_error op
+simplePrim [lhs] op rest
+ = StAssign pk lhs (StPrim op rest)
+ where
+ pk = if isCompareOp op then
+ IntRep
+ else
+ case getPrimOpResultInfo op of
+ ReturnsPrim pk -> pk
+ _ -> simplePrim_error op
+
+simplePrim _ op _ = simplePrim_error op
+
+simplePrim_error op
= error ("ERROR: primitive operation `"++showPrimOp PprDebug op++"'cannot be handled\nby the native-code generator. Workaround: use -fvia-C.\n(Perhaps you should report it as a GHC bug, also.)\n")
\end{code}
Here we generate the Stix code for CAddrModes.
-When a character is fetched from a mixed type location, we have to
-do an extra cast. This is reflected in amodeCode', which is for rhs
+When a character is fetched from a mixed type location, we have to do
+an extra cast. This is reflected in amodeCode', which is for rhs
amodes that might possibly need the extra cast.
\begin{code}
+amodeToStix, amodeToStix' :: CAddrMode -> StixTree
-amodeCode, amodeCode'
- :: Target
- -> CAddrMode
- -> StixTree
-
-amodeCode'{-'-} target_STRICT am@(CVal rr CharRep)
- | mixedTypeLocn am = StPrim ChrOp [amodeToStix target am]
- | otherwise = amodeToStix target am
-
-amodeCode' target am = amodeToStix target am
+amodeToStix'{-'-} am@(CVal rr CharRep)
+ | mixedTypeLocn am = StPrim ChrOp [amodeToStix am]
+ | otherwise = amodeToStix am
-amodeCode target_STRICT am
- = acode am
- where
- -- grab "target" things:
- hp_rel = hpRel target
- char_like = charLikeClosureSize target
- int_like = intLikeClosureSize target
- a2stix = amodeToStix target
+amodeToStix' am = amodeToStix am
- -- real code: ----------------------------------
- acode am@(CVal rr CharRep) | mixedTypeLocn am =
- StInd IntRep (acode (CAddr rr))
+-----------
+amodeToStix am@(CVal rr CharRep)
+ | mixedTypeLocn am
+ = StInd IntRep (amodeToStix (CAddr rr))
- acode (CVal rr pk) = StInd pk (acode (CAddr rr))
+amodeToStix (CVal rr pk) = StInd pk (amodeToStix (CAddr rr))
- acode (CAddr (SpARel spA off)) =
- StIndex PtrRep stgSpA (StInt (toInteger (spARelToInt spA off)))
+amodeToStix (CAddr (SpARel spA off))
+ = StIndex PtrRep stgSpA (StInt (toInteger (spARelToInt spA off)))
- acode (CAddr (SpBRel spB off)) =
- StIndex IntRep stgSpB (StInt (toInteger (spBRelToInt spB off)))
+amodeToStix (CAddr (SpBRel spB off))
+ = StIndex IntRep stgSpB (StInt (toInteger (spBRelToInt spB off)))
- acode (CAddr (HpRel hp off)) =
- StIndex IntRep stgHp (StInt (toInteger (-(hp_rel (hp `subOff` off)))))
+amodeToStix (CAddr (HpRel hp off))
+ = StIndex IntRep stgHp (StInt (toInteger (-(hpRelToInt (hp `subOff` off)))))
- acode (CAddr (NodeRel off)) =
- StIndex IntRep stgNode (StInt (toInteger (hp_rel off)))
+amodeToStix (CAddr (NodeRel off))
+ = StIndex IntRep stgNode (StInt (toInteger (hpRelToInt off)))
- acode (CReg magic) = StReg (StixMagicId magic)
- acode (CTemp uniq pk) = StReg (StixTemp uniq pk)
+amodeToStix (CReg magic) = StReg (StixMagicId magic)
+amodeToStix (CTemp uniq pk) = StReg (StixTemp uniq pk)
- acode (CLbl lbl _) = StCLbl lbl
+amodeToStix (CLbl lbl _) = StCLbl lbl
+amodeToStix (CUnVecLbl dir _) = StCLbl dir
- acode (CUnVecLbl dir _) = StCLbl dir
-
- acode (CTableEntry base off pk) =
- StInd pk (StIndex pk (acode base) (acode off))
+amodeToStix (CTableEntry base off pk)
+ = StInd pk (StIndex pk (amodeToStix base) (amodeToStix off))
-- For CharLike and IntLike, we attempt some trivial constant-folding here.
- acode (CCharLike (CLit (MachChar c))) =
- StLitLbl (uppBeside (uppPStr SLIT("CHARLIKE_closures+")) (uppInt off))
- where off = char_like * ord c
+amodeToStix (CCharLike (CLit (MachChar c)))
+ = StLitLbl (uppBeside (uppPStr SLIT("CHARLIKE_closures+")) (uppInt off))
+ where
+ off = charLikeSize * ord c
- acode (CCharLike x) =
- StPrim IntAddOp [charLike, off]
- where off = StPrim IntMulOp [acode x,
- StInt (toInteger (char_like))]
+amodeToStix (CCharLike x)
+ = StPrim IntAddOp [charLike, off]
+ where
+ off = StPrim IntMulOp [amodeToStix x, StInt (toInteger charLikeSize)]
- acode (CIntLike (CLit (MachInt i _))) =
- StPrim IntAddOp [intLikePtr, StInt off]
- where off = toInteger int_like * i
+amodeToStix (CIntLike (CLit (MachInt i _)))
+ = StPrim IntAddOp [intLikePtr, StInt off]
+ where
+ off = toInteger intLikeSize * i
- acode (CIntLike x) =
- StPrim IntAddOp [intLikePtr, off]
- where off = StPrim IntMulOp [acode x,
- StInt (toInteger int_like)]
+amodeToStix (CIntLike x)
+ = StPrim IntAddOp [intLikePtr, off]
+ where
+ off = StPrim IntMulOp [amodeToStix x, StInt (toInteger intLikeSize)]
-- A CString is just a (CLit . MachStr)
- acode (CString s) = StString s
-
- acode (CLit core) = case core of
- (MachChar c) -> StInt (toInteger (ord c))
- (MachStr s) -> StString s
- (MachAddr a) -> StInt a
- (MachInt i _) -> StInt i
- (MachLitLit s _) -> StLitLit s
- (MachFloat d) -> StDouble d
- (MachDouble d) -> StDouble d
- _ -> panic "amodeCode:core literal"
+amodeToStix (CString s) = StString s
+
+amodeToStix (CLit core)
+ = case core of
+ MachChar c -> StInt (toInteger (ord c))
+ MachStr s -> StString s
+ MachAddr a -> StInt a
+ MachInt i _ -> StInt i
+ MachLitLit s _ -> StLitLit s
+ MachFloat d -> StDouble d
+ MachDouble d -> StDouble d
+ _ -> panic "amodeToStix:core literal"
-- A CLitLit is just a (CLit . MachLitLit)
- acode (CLitLit s _) = StLitLit s
+amodeToStix (CLitLit s _) = StLitLit s
-- COffsets are in words, not bytes!
- acode (COffset off) = StInt (toInteger (hp_rel off))
-
- acode (CMacroExpr _ macro [arg]) =
- case macro of
- INFO_PTR -> StInd PtrRep (a2stix arg)
- ENTRY_CODE -> a2stix arg
- INFO_TAG -> tag
- EVAL_TAG -> StPrim IntGeOp [tag, StInt 0]
+amodeToStix (COffset off) = StInt (toInteger (hpRelToInt off))
+
+amodeToStix (CMacroExpr _ macro [arg])
+ = case macro of
+ INFO_PTR -> StInd PtrRep (amodeToStix arg)
+ ENTRY_CODE -> amodeToStix arg
+ INFO_TAG -> tag
+ EVAL_TAG -> StPrim IntGeOp [tag, StInt 0]
where
- tag = StInd IntRep (StIndex IntRep (a2stix arg) (StInt (-2)))
- -- That ``-2'' really bothers me. (JSM)
+ tag = StInd IntRep (StIndex IntRep (amodeToStix arg) (StInt (-2)))
+ -- That ``-2'' really bothers me. (JSM) (Replace w/ oTHER_TAG? [WDP])
- acode (CCostCentre cc print_as_string)
- = if noCostCentreAttached cc
- then StComment SLIT("") -- sigh
- else panic "amodeCode:CCostCentre"
+amodeToStix (CCostCentre cc print_as_string)
+ = if noCostCentreAttached cc
+ then StComment SLIT("") -- sigh
+ else panic "amodeToStix:CCostCentre"
\end{code}
-Sizes of the CharLike and IntLike closures that are arranged as arrays in the
-data segment. (These are in bytes.)
+Sizes of the CharLike and IntLike closures that are arranged as arrays
+in the data segment. (These are in bytes.)
\begin{code}
-
-- The INTLIKE base pointer
intLikePtr :: StixTree
flushStdout = StCall SLIT("fflush") VoidRep [StLitLit SLIT("stdout")]
flushStderr = StCall SLIT("fflush") VoidRep [StLitLit SLIT("stderr")]
errorIO = StJump (StInd PtrRep (sStLitLbl SLIT("ErrorIO_innards")))
-
\end{code}
U_constr.. ,
U_coresyn.. ,
U_entidt.. ,
- U_finfot.. ,
U_hpragma.. ,
U_list.. ,
U_literal.. ,
import U_constr
import U_coresyn
import U_entidt
-import U_finfot
import U_hpragma
import U_list
import U_literal
/* dle */ 0, 0, 0, 0, 0, 0, 0, 0,
/* can */ 0, 0, 0, 0, 0, 0, 0, 0,
/* sp */ _S, 0, 0, 0, 0, 0, 0, 0,
-/* '(' */ _C, 0, 0, 0, 0, 0, 0, 0, /* ( */
+/* '(' */ _C, 0, 0, 0, 0, 0, 0, 0,
/* '0' */ _D|_H|_O,_D|_H|_O,_D|_H|_O,_D|_H|_O,_D|_H|_O,_D|_H|_O,_D|_H|_O,_D|_H|_O,
/* '8' */ _D|_H, _D|_H, _C, 0, 0, 0, 0, 0,
/* '@' */ 0, _H|_C, _H|_C, _H|_C, _H|_C, _H|_C, _H|_C, _C,
/* 'H' */ _C, _C, _C, _C, _C, _C, _C, _C,
/* 'P' */ _C, _C, _C, _C, _C, _C, _C, _C,
-/* 'X' */ _C, _C, _C, _C, 0, 0, 0, 0, /* [ */
+/* 'X' */ _C, _C, _C, _C, 0, 0, 0, 0,
/* '`' */ 0, _H, _H, _H, _H, _H, _H, 0,
/* 'h' */ 0, 0, 0, 0, 0, 0, 0, 0,
/* 'p' */ 0, 0, 0, 0, 0, 0, 0, 0,
| gcon { $$ = mkident($1); }
| lit_constant { $$ = mklit($1); }
| OPAREN exp CPAREN { $$ = mkpar($2); } /* mkpar: stop infix parsing at ()'s */
+ | qcon OCURLY CCURLY { $$ = mkrecord($1,Lnil); }
| qcon OCURLY rbinds CCURLY { $$ = mkrecord($1,$3); } /* 1 S/R conflict on OCURLY -> shift */
| OBRACK list_exps CBRACK { $$ = mkllist($2); }
| OPAREN exp COMMA texps CPAREN { if (ttree($4) == tuple)
import Id ( mkTupleCon, GenId{-instances-} )
import Name ( Name(..) )
import NameTypes ( mkPreludeCoreName, FullName, ShortName )
-import TyCon ( getTyConDataCons, mkFunTyCon, mkTupleTyCon, TyCon{-instances-} )
+import TyCon ( tyConDataCons, mkFunTyCon, mkTupleTyCon, TyCon{-instances-} )
import Type
import Unique -- *Key stuff
import Util ( nOfThem, panic )
pcDataConNameInfo :: TyCon -> [(FAST_STRING, Name)]
pcDataConNameInfo tycon
= -- slurp out its data constructors...
- [ (getOccurrenceName con, WiredInVal con) | con <- getTyConDataCons tycon ]
+ [ (getOccurrenceName con, WiredInVal con) | con <- tyConDataCons tycon ]
\end{code}
import Ubiq
import IdLoop ( UnfoldingGuidance(..) )
+import Id ( Id(..), GenId, mkPreludeId, mkTemplateLocals )
import PrelLoop
-- friends:
import TyVar ( alphaTyVar, betaTyVar )
import Unique -- lots of *Keys
import Util ( panic )
+\end{code}
+
--- only used herein:
-mkPreludeId = panic "PrelVals:Id.mkPreludeId"
-mkSpecId = panic "PrelVals:Id.mkSpecId"
-mkTemplateLocals = panic "PrelVals:Id.mkTemplateLocals"
-specialiseTy = panic "PrelVals:specialiseTy"
+
+\begin{code}
+-- only used herein:
pcMiscPrelId :: Unique{-IdKey-} -> FAST_STRING -> FAST_STRING -> Type -> IdInfo -> Id
pcMiscPrelId key mod name ty info
tagOf_PrimOp, -- ToDo: rm
primOp_str, -- sigh
primOpType, isCompareOp,
+ commutableOp,
PrimOpResultInfo(..),
getPrimOpResultInfo,
---MOVE: primOpCanTriggerGC, primOpNeedsWrapper,
---MOVE: primOpOkForSpeculation, primOpIsCheap,
---MOVE: fragilePrimOp,
---MOVE: HeapRequirement(..), primOpHeapReq,
+ primOpCanTriggerGC, primOpNeedsWrapper,
+ primOpOkForSpeculation, primOpIsCheap,
+ fragilePrimOp,
+ HeapRequirement(..), primOpHeapReq,
-- export for the Native Code Generator
primOpInfo, -- needed for primOpNameInfo
PrimOpInfo(..),
pprPrimOp, showPrimOp
-
- -- and to make the interface self-sufficient....
) where
import Ubiq{-uitous-}
import CStrings ( identToC )
import CgCompInfo ( mIN_MP_INT_SIZE, mP_STRUCT_SIZE )
+import HeapOffs ( addOff, intOff, totHdrSize )
import NameTypes ( mkPreludeCoreName, FullName, ShortName )
import PprStyle ( codeStyle )
+import PprType ( pprParendGenType, GenTyVar{-instance Outputable-} )
import Pretty
import SMRep ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..) )
import TyCon ( TyCon{-instances-} )
import Type ( getAppDataTyCon, maybeAppDataTyCon,
- mkForAllTys, mkFunTys, applyTyCon )
-import TyVar ( alphaTyVar, betaTyVar )
+ mkForAllTys, mkFunTys, applyTyCon, typePrimRep
+ )
+import TyVar ( alphaTyVar, betaTyVar, GenTyVar{-instance Eq-} )
+import Unique ( Unique{-instance Eq-} )
import Util ( panic#, assoc, panic{-ToDo:rm-} )
-
-glueTyArgs = panic "PrimOp:glueTyArgs"
-pprParendType = panic "PrimOp:pprParendType"
-primRepFromType = panic "PrimOp:primRepFromType"
\end{code}
%************************************************************************
ops which can trigger GC).
\begin{code}
-{- MOVE:
data HeapRequirement
= NoHeapRequired
| FixedHeapRequired HeapOffset
#endif {-GRAN-}
primOpHeapReq other_op = NoHeapRequired
--}
\end{code}
Primops which can trigger GC have to be called carefully.
and a liveness mask tells which regs are live.
\begin{code}
-{- MOVE:
-primOpCanTriggerGC op =
- case op of
+primOpCanTriggerGC op
+ = case op of
TakeMVarOp -> True
ReadIVarOp -> True
DelayOp -> True
case primOpHeapReq op of
VariableHeapRequired -> True
_ -> False
--}
\end{code}
Sometimes we may choose to execute a PrimOp even though it isn't
of by data dependencies.
\begin{code}
-{- MOVE:
primOpOkForSpeculation :: PrimOp -> Bool
-- Int.
-- The default is "yes it's ok for speculation"
primOpOkForSpeculation other_op = True
--}
\end{code}
@primOpIsCheap@, as used in \tr{SimplUtils.lhs}. For now (HACK
WARNING), we just borrow some other predicates for a
what-should-be-good-enough test.
\begin{code}
-{-MOVE:
primOpIsCheap op
= primOpOkForSpeculation op && not (primOpCanTriggerGC op)
--}
\end{code}
And some primops have side-effects and so, for example, must not be
duplicated.
\begin{code}
-{- MOVE:
fragilePrimOp :: PrimOp -> Bool
fragilePrimOp ParOp = True
#endif {-GRAN-}
fragilePrimOp other = False
--}
\end{code}
Primitive operations that perform calls need wrappers to save any live variables
that are stored in caller-saves registers
\begin{code}
-{- MOVE:
primOpNeedsWrapper :: PrimOp -> Bool
primOpNeedsWrapper (CCallOp _ _ _ _ _) = True
primOpNeedsWrapper WaitOp = True
primOpNeedsWrapper other_op = False
--}
\end{code}
\begin{code}
Coerce str ty1 ty2 -> mkFunTys [ty1] ty2
PrimResult str tyvars arg_tys prim_tycon kind res_tys ->
- mkForAllTys tyvars (glueTyArgs arg_tys (applyTyCon prim_tycon res_tys))
+ mkForAllTys tyvars (mkFunTys arg_tys (applyTyCon prim_tycon res_tys))
AlgResult str tyvars arg_tys tycon res_tys ->
- mkForAllTys tyvars (glueTyArgs arg_tys (applyTyCon tycon res_tys))
+ mkForAllTys tyvars (mkFunTys arg_tys (applyTyCon tycon res_tys))
\end{code}
\begin{code}
getPrimOpResultInfo op
= case (primOpInfo op) of
- Dyadic _ ty -> ReturnsPrim (primRepFromType ty)
- Monadic _ ty -> ReturnsPrim (primRepFromType ty)
+ Dyadic _ ty -> ReturnsPrim (typePrimRep ty)
+ Monadic _ ty -> ReturnsPrim (typePrimRep ty)
Compare _ ty -> ReturnsAlg boolTyCon
- Coerce _ _ ty -> ReturnsPrim (primRepFromType ty)
+ Coerce _ _ ty -> ReturnsPrim (typePrimRep ty)
PrimResult _ _ _ _ kind _ -> ReturnsPrim kind
AlgResult _ _ _ tycon _ -> ReturnsAlg tycon
_ -> False
\end{code}
+The commutable ops are those for which we will try to move constants
+to the right hand side for strength reduction.
+
+\begin{code}
+commutableOp :: PrimOp -> Bool
+
+commutableOp CharEqOp = True
+commutableOp CharNeOp = True
+commutableOp IntAddOp = True
+commutableOp IntMulOp = True
+commutableOp AndOp = True
+commutableOp OrOp = True
+commutableOp IntEqOp = True
+commutableOp IntNeOp = True
+commutableOp IntegerAddOp = True
+commutableOp IntegerMulOp = True
+commutableOp FloatAddOp = True
+commutableOp FloatMulOp = True
+commutableOp FloatEqOp = True
+commutableOp FloatNeOp = True
+commutableOp DoubleAddOp = True
+commutableOp DoubleMulOp = True
+commutableOp DoubleEqOp = True
+commutableOp DoubleNeOp = True
+commutableOp _ = False
+\end{code}
+
Utils:
\begin{code}
dyadic_fun_ty ty = mkFunTys [ty, ty] ty
pp_tys
= ppBesides [ppStr " { [",
- ppIntersperse pp'SP{-'-} (map (pprParendType sty) arg_tys),
- ppRbrack, ppSP, pprParendType sty res_ty, ppStr " })"]
+ ppIntersperse pp'SP{-'-} (map (pprParendGenType sty) arg_tys),
+ ppRbrack, ppSP, pprParendGenType sty res_ty, ppStr " })"]
in
ppBesides [ppStr before, ppPStr fun, after, pp_tys]
import NameTypes ( mkPreludeCoreName, FullName )
import PrelMods ( pRELUDE_BUILTIN )
import PrimRep ( PrimRep(..) ) -- getPrimRepInfo uses PrimRep repn
-import TyCon ( mkPrimTyCon, mkDataTyCon,
- ConsVisible(..), NewOrData(..) )
+import TyCon ( mkPrimTyCon, mkDataTyCon, NewOrData(..) )
import TyVar ( GenTyVar(..), alphaTyVars )
import Type ( applyTyCon, mkTyVarTys )
import Usage ( usageOmega )
[{-no context-}]
[{-no data cons!-}] -- we tell you *nothing* about this guy
[{-no derivings-}]
- ConsInvisible
DataType
where
full_name = mkPreludeCoreName pRELUDE_BUILTIN SLIT("_RealWorld")
import Kind ( mkBoxedTypeKind, mkArrowKind )
import SrcLoc ( mkBuiltinSrcLoc )
import TyCon ( mkDataTyCon, mkTupleTyCon, mkSynTyCon,
- ConsVisible(..), NewOrData(..), TyCon )
+ NewOrData(..), TyCon
+ )
import Type ( mkTyConTy, applyTyCon, mkSynTy, mkSigmaTy,
mkFunTys, maybeAppDataTyCon,
GenType(..), ThetaType(..), TauType(..) )
pcDataTyCon key mod name tyvars cons
= mkDataTyCon key tycon_kind full_name tyvars
[{-no context-}] cons [{-no derivings-}]
- ConsVisible DataType
+ DataType
where
full_name = mkPreludeCoreName mod name
tycon_kind = foldr (mkArrowKind . getTyVarKind) mkBoxedTypeKind tyvars
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[SCCfinal]{Modify and collect code generation for final STG program}
module SCCfinal ( stgMassageForProfiling ) where
-import Pretty -- ToDo: rm (debugging only)
+import Ubiq{-uitous-}
-import Type ( isFunType, getTauType )
-import CmdLineOpts
-import CostCentre
-import Id ( mkSysLocal, idType )
-import SrcLoc ( mkUnknownSrcLoc )
import StgSyn
-import UniqSupply
-import UniqSet ( emptyUniqSet
- IF_ATTACK_PRAGMAS(COMMA emptyUFM)
+
+import CmdLineOpts ( opt_AutoSccsOnIndividualCafs,
+ opt_CompilingPrelude
)
-import Util
+import CostCentre -- lots of things
+import Id ( idType, mkSysLocal, emptyIdSet )
+import Maybes ( maybeToBool )
+import SrcLoc ( mkUnknownSrcLoc )
+import Type ( splitSigmaTy, getFunTy_maybe )
+import UniqSupply ( getUnique, splitUniqSupply )
+import Util ( removeDups, assertPanic )
infixr 9 `thenMM`, `thenMM_`
\end{code}
\begin{code}
-type CollectedCCs = ([CostCentre], -- locally defined ones
- [CostCentre]) -- ones needing "extern" decls
+type CollectedCCs = ([CostCentre], -- locally defined ones
+ [CostCentre]) -- ones needing "extern" decls
stgMassageForProfiling
- :: FAST_STRING -> FAST_STRING -- module name, group name
- -> UniqSupply -- unique supply
- -> (GlobalSwitch -> Bool) -- command-line opts checker
- -> [StgBinding] -- input
+ :: FAST_STRING -> FAST_STRING -- module name, group name
+ -> UniqSupply -- unique supply
+ -> [StgBinding] -- input
-> (CollectedCCs, [StgBinding])
-stgMassageForProfiling mod_name grp_name us sw_chkr stg_binds
+stgMassageForProfiling mod_name grp_name us stg_binds
= let
((local_ccs, extern_ccs),
stg_binds2)
in
((fixed_ccs ++ local_ccs_no_dups, extern_ccs_no_dups), stg_binds2)
where
- do_auto_sccs_on_cafs = sw_chkr AutoSccsOnIndividualCafs -- only use!
- doing_prelude = sw_chkr CompilingPrelude
+ do_auto_sccs_on_cafs = opt_AutoSccsOnIndividualCafs -- only use!
+ doing_prelude = opt_CompilingPrelude
all_cafs_cc = if doing_prelude
then preludeCafsCostCentre
in
returnMM ( (new_var, old_var) : bindings, StgVarArg new_var )
where
- is_fun_type ty = isFunType (getTauType ty)
+ is_fun_type ty
+ = case (splitSigmaTy ty) of { (_, _, tau_ty) ->
+ maybeToBool (getFunTy_maybe tau_ty) }
---------------
mk_stg_let :: CostCentre -> (Id, Id) -> StgExpr -> StgExpr
in
StgLet (StgNonRec new_var rhs) body
where
- bOGUS_LVs = emptyUniqSet -- easier to print than: panic "mk_stg_let: LVs"
+ bOGUS_LVs = emptyIdSet -- easier to print than: panic "mk_stg_let: LVs"
\end{code}
%************************************************************************
import PprStyle ( PprStyle(..) )
import Pretty
import ProtoName ( isConopPN, ProtoName(..) )
-import Util ( nOfThem, panic )
+import Util ( nOfThem, pprError, panic )
\end{code}
%************************************************************************
U_record con rbinds -> -- record construction
wlkQid con `thenUgn` \ rcon ->
wlkList rdRbind rbinds `thenUgn` \ recbinds ->
- returnUgn (RecordCon rcon recbinds)
+ returnUgn (RecordCon (HsVar rcon) recbinds)
U_rupdate updexp updbinds -> -- record update
wlkExpr updexp `thenUgn` \ aexp ->
= rdU_tree pt `thenUgn` \ (U_rbind var exp) ->
wlkQid var `thenUgn` \ rvar ->
wlkMaybe rdExpr exp `thenUgn` \ expr_maybe ->
- returnUgn (rvar, expr_maybe)
+ returnUgn (
+ case expr_maybe of
+ Nothing -> (rvar, HsVar rvar, True{-pun-})
+ Just re -> (rvar, re, False)
+ )
\end{code}
Patterns: just bear in mind that lists of patterns are represented as
ConPatIn x [] -> (x, lpats)
ConOpPatIn x op y -> (op, x:y:lpats)
_ -> -- sorry about the weedy msg; the parser missed this one
- error (ppShow 100 (ppCat [
- ppStr "ERROR: an illegal `application' of a pattern to another one:",
- ppInterleave ppSP (map (ppr PprForUser) (lpat:lpats))]))
+ pprError "ERROR: an illegal `application' of a pattern to another one:"
+ (ppInterleave ppSP (map (ppr PprForUser) (lpat:lpats)))
in
returnUgn (ConPatIn n arg_pats)
where
= rdU_tree pt `thenUgn` \ (U_rbind var pat) ->
wlkQid var `thenUgn` \ rvar ->
wlkMaybe rdPat pat `thenUgn` \ pat_maybe ->
- returnUgn (rvar, pat_maybe)
+ returnUgn (
+ case pat_maybe of
+ Nothing -> (rvar, VarPatIn rvar, True{-pun-})
+ Just rp -> (rvar, rp, False)
+ )
\end{code}
\begin{code}
mk_class_assertion (MonoTyApp name [(MonoTyVar tyname)]) = (name, tyname)
mk_class_assertion other
- = error ("ERROR: malformed type context: "++ppShow 80 (ppr PprForUser other)++"\n")
+ = pprError "ERROR: malformed type context: " (ppr PprForUser other)
-- regrettably, the parser does let some junk past
-- e.g., f :: Num {-nothing-} => a -> ...
\end{code}
= mkSrcLocUgn srcline `thenUgn` \ src_loc ->
wlkQid ccon `thenUgn` \ con ->
wlkList rd_field cfields `thenUgn` \ fields_lists ->
- returnUgn (RecConDecl con (concat fields_lists) src_loc)
+ returnUgn (RecConDecl con fields_lists src_loc)
where
- rd_field :: ParseTree -> UgnM [(ProtoName, BangType ProtoName)]
+ rd_field :: ParseTree -> UgnM ([ProtoName], BangType ProtoName)
rd_field pt
= rdU_constr pt `thenUgn` \ (U_field fvars fty) ->
wlkList rdQid fvars `thenUgn` \ vars ->
wlkBangType fty `thenUgn` \ ty ->
- returnUgn [ (var, ty) | var <- vars ]
+ returnUgn (vars, ty)
-----------------
rdBangType pt = rdU_ttype pt `thenUgn` \ ty -> wlkBangType ty
rnTopBinds, rnMethodBinds,
rnBinds,
FreeVars(..), DefinedVars(..)
-
- -- and to make the interface self-sufficient...
) where
import Ubiq{-uitous-}
import Pretty
import ProtoName ( elemByLocalNames, eqByLocalName, ProtoName{-instances-} )
import RnExpr4 -- OK to look here; but not the other way 'round
-import UniqSet ( emptyUniqSet, singletonUniqSet, mkUniqSet,
+import UniqSet ( emptyUniqSet, unitUniqSet, mkUniqSet,
unionUniqSets, unionManyUniqSets,
- elementOfUniqSet,
+ elementOfUniqSet, addOneToUniqSet,
uniqSetToList,
UniqSet(..)
)
returnRn4 (
uniq + 1,
[(uniq,
- singletonUniqSet name',
+ unitUniqSet name',
fvs `unionUniqSets` sigs_fvs,
FunMonoBind name' new_matches locn,
sigs_for_me
-- acct in the dependency analysis (or we get an
-- unexpected out-of-scope error)! WDP 95/07
-sig_fv (SpecSig _ _ (Just blah) _) acc = acc `unionUniqSets` singletonUniqSet blah
+sig_fv (SpecSig _ _ (Just blah) _) acc = addOneToUniqSet acc blah
sig_fv _ acc = acc
\end{code}
import Name ( Name(..) )
import NameTypes ( FullName{-instances-} )
import Outputable ( isConop )
-import UniqSet ( emptyUniqSet, singletonUniqSet,
+import UniqSet ( emptyUniqSet, unitUniqSet,
unionUniqSets, unionManyUniqSets,
UniqSet(..)
)
= lookupValue v `thenRn4` \ vname ->
returnRn4 (HsVar vname, fv_set vname)
where
- fv_set n@(Short uniq sname) = singletonUniqSet n
+ fv_set n@(Short uniq sname) = unitUniqSet n
fv_set n@(ValName uniq fname)
| isLocallyDefined fname
&& not (isConop (getOccurrenceName fname))
- = singletonUniqSet n
+ = unitUniqSet n
fv_set other = emptyUniqSet
rnExpr (HsLit lit) = returnRn4 (HsLit lit, emptyUniqSet)
type RenamedHsBinds = HsBinds Fake Fake Name RenamedPat
type RenamedHsExpr = HsExpr Fake Fake Name RenamedPat
type RenamedHsModule = HsModule Fake Fake Name RenamedPat
+type RenamedRecordBinds = HsRecordBinds Fake Fake Name RenamedPat
type RenamedImportedInterface = ImportedInterface Fake Fake Name RenamedPat
type RenamedInstDecl = InstDecl Fake Fake Name RenamedPat
type RenamedInstancePragmas = InstancePragmas Name
do_condecl cf_nf tc_nf (RecConDecl con fields src_loc)
= RecConDecl (cf_nf con) (map do_field fields) src_loc
where
- do_field (var, ty) = (cf_nf var, do_bang tc_nf ty)
+ do_field (vars, ty) = (map cf_nf vars, do_bang tc_nf ty)
--------------------------------------------
do_bang tc_nf (Banged ty) = Banged (doIfaceMonoType1 tc_nf ty)
in
mkTyVarNamesEnv src_loc tyvars `thenRn4` \ (tv_env,_) ->
lookupClass cname `thenRn4` \ cname' ->
- rnPolyType False{-no invisibles-} tv_env ty
+
+ rnPolyType False{-no invisibles-} [] ty
+ -- The "[]" was tv_env, but that means the InstDecl's tyvars aren't
+ -- pinned on the HsForAllType, which they should be.
+ -- Urgh! Improve in the new renamer!
+
`thenRn4` \ ty' ->
rnMethodBinds cname' mbinds `thenRn4` \ mbinds' ->
mapRn4 (rn_uprag cname') uprags `thenRn4` \ new_uprags ->
module AnalFBWW ( analFBWW ) where
-import Util
-import Id ( addIdFBTypeInfo )
-import IdInfo
-import PrelInfo ( foldrId, buildId,
- nilDataCon, consDataCon, mkListTy, mkFunTy,
- unpackCStringAppendId
- )
-import BinderInfo
-import SimplEnv -- everything
-import OccurAnal -- OLD: was NewOccurAnal
-import Maybes
-
+import Ubiq{-uitous-}
+
+import CoreSyn ( CoreBinding(..) )
+import Util ( panic{-ToDo:rm-} )
+
+--import Util
+--import Id ( addIdFBTypeInfo )
+--import IdInfo
+--import PrelInfo ( foldrId, buildId,
+-- nilDataCon, consDataCon, mkListTy, mkFunTy,
+-- unpackCStringAppendId
+-- )
+--import BinderInfo
+--import SimplEnv -- everything
+--import OccurAnal -- OLD: was NewOccurAnal
+--import Maybes
\end{code}
\begin{code}
analFBWW
- :: (GlobalSwitch -> Bool)
- -> [CoreBinding]
+ :: [CoreBinding]
-> [CoreBinding]
-analFBWW switch top_binds = trace "ANALFBWW" (snd anno)
+
+analFBWW = panic "analFBWW (ToDo)"
+
+{- LATER:
+analFBWW top_binds = trace "ANALFBWW" (snd anno)
where
anals :: [InBinding]
- anals = newOccurAnalyseBinds top_binds switch (const False)
+ anals = newOccurAnalyseBinds top_binds (const False)
anno = mapAccumL annotateBindingFBWW nullIdEnv anals
\end{code}
analExprFBWW (Let binds e) env = analExprFBWW e (analBind binds env)
analExprFBWW (Case e alts) env = foldl1 joinFBType (analAltsFBWW alts env)
-analAltsFBWW (AlgAlts alts deflt) env =
- case analDefFBWW deflt env of
+analAltsFBWW (AlgAlts alts deflt) env
+ = case analDefFBWW deflt env of
Just ty -> ty : tys
Nothing -> tys
where
tys = map (\(con,binders,e) -> analExprFBWW e (delManyFromIdEnv env (map fst binders))) alts
-analAltsFBWW (PrimAlts alts deflt) env =
- case analDefFBWW deflt env of
+analAltsFBWW (PrimAlts alts deflt) env
+ = case analDefFBWW deflt env of
Just ty -> ty : tys
Nothing -> tys
where
\begin{code}
analBindExpr :: BinderInfo -> InExpr -> IdEnv OurFBType -> OurFBType
-analBindExpr bnd expr env =
- case analExprFBWW expr env of
+analBindExpr bnd expr env
+ = case analExprFBWW expr env of
IsFB ty@(FBType [] _) ->
if oneSafeOcc False bnd
then IsFB ty
| not (null xs) -> pprTrace "ADDED to:" (ppr PprDebug v)
(addIdFBTypeInfo v (mkFBTypeInfo ty))
_ -> v)
+-}
\end{code}
where
whnf :: CoreExprWithFVs -> Bool
- whnf (_,AnnLit _) = True
- whnf (_,AnnCon _ _) = True
- whnf (_,AnnLam (ValBinder _) _) = True
- whnf (_,AnnLam _ e) = whnf e
- whnf (_,AnnSCC _ e) = whnf e
- whnf _ = False
+ whnf (_,AnnLit _) = True
+ whnf (_,AnnCon _ _) = True
+ whnf (_,AnnLam x e) = if isValBinder x then True else whnf e
+ whnf (_,AnnSCC _ e) = whnf e
+ whnf _ = False
\end{code}
Applications: we could float inside applications, but it's probably
module FoldrBuildWW ( mkFoldrBuildWW ) where
-IMPORT_Trace
-import Outputable
-import Pretty
-import Type ( cloneTyVarFromTemplate, mkTyVarTy,
- splitTypeWithDictsAsArgs, eqTyCon, mkForallTy )
-import TysPrim ( alphaTy )
-import TyVar ( alphaTyVar )
-
-import Type ( Type(..) ) -- **** CAN SEE THE CONSTRUCTORS ****
-import UniqSupply ( runBuiltinUs )
-import WwLib -- share the same monad (is this eticit ?)
-import PrelInfo ( listTyCon, mkListTy, nilDataCon, consDataCon,
- foldrId, buildId
- )
-import Id ( getIdFBTypeInfo, mkWorkerId, getIdInfo,
- replaceIdInfo, mkSysLocal, idType
- )
-import IdInfo
-import Maybes
-import SrcLoc ( mkUnknownSrcLoc, SrcLoc )
-import Util
+import Ubiq{-uitous-}
+
+import CoreSyn ( CoreBinding(..) )
+import Util ( panic{-ToDo:rm?-} )
+
+--import Type ( cloneTyVarFromTemplate, mkTyVarTy,
+-- splitTypeWithDictsAsArgs, eqTyCon, mkForallTy )
+--import TysPrim ( alphaTy )
+--import TyVar ( alphaTyVar )
+--
+--import Type ( Type(..) ) -- **** CAN SEE THE CONSTRUCTORS ****
+--import UniqSupply ( runBuiltinUs )
+--import WwLib -- share the same monad (is this eticit ?)
+--import PrelInfo ( listTyCon, mkListTy, nilDataCon, consDataCon,
+-- foldrId, buildId
+-- )
+--import Id ( getIdFBTypeInfo, mkWorkerId, getIdInfo,
+-- replaceIdInfo, mkSysLocal, idType
+-- )
+--import IdInfo
+--import Maybes
+--import SrcLoc ( mkUnknownSrcLoc, SrcLoc )
+--import Util
\end{code}
\begin{code}
mkFoldrBuildWW
- :: (GlobalSwitch -> Bool)
- -> UniqSupply
+ :: UniqSupply
-> [CoreBinding]
-> [CoreBinding]
-mkFoldrBuildWW switch us top_binds =
+
+mkFoldrBuildWW = panic "mkFoldrBuildWW (ToDo)"
+
+{- LATER:
+mkFoldrBuildWW us top_binds =
(mapWw wwBind top_binds `thenWw` \ top_binds2 ->
- returnWw (concat top_binds2)) us switch
+ returnWw (concat top_binds2)) us
\end{code}
\begin{code}
else
returnWw [(worker_id,worker_rhs),(wrapper_id,wrapper_rhs)]
_ -> returnWw [(id,expr')]
+-}
\end{code}
-
) where
import Ubiq{-uitous-}
+import IdLoop -- paranoia checking
import CoreSyn
import PrelInfo ( mkListTy )
foldr_fun _ _ = returnSmpl Nothing
isConsFun :: SimplEnv -> CoreArg -> Bool
-isConsFun env (VarArg v) =
- case lookupUnfolding env v of
+isConsFun env (VarArg v)
+ = case lookupUnfolding env v of
GenForm _ _ (Lam (x,_) (Lam (y,_)
(Con con tys [VarArg x',VarArg y']))) _
| con == consDataCon && x==x' && y==y'
isConsFun env _ = False
isNilForm :: SimplEnv -> CoreArg -> Bool
-isNilForm env (VarArg v) =
- case lookupUnfolding env v of
+isNilForm env (VarArg v)
+ = case lookupUnfolding env v of
GenForm _ _ (CoTyApp (Var id) _) _
| id == nilDataCon -> True
ConForm id _ _
isNilForm env _ = False
getBuildForm :: SimplEnv -> CoreArg -> Maybe Id
-getBuildForm env (VarArg v) =
- case lookupUnfolding env v of
+getBuildForm env (VarArg v)
+ = case lookupUnfolding env v of
GenForm False _ _ _ -> Nothing
-- not allowed to inline :-(
GenForm _ _ (App (CoTyApp (Var bld) _) (VarArg g)) _
getAugmentForm :: SimplEnv -> CoreArg -> Maybe (Id,CoreArg)
-getAugmentForm env (VarArg v) =
- case lookupUnfolding env v of
+getAugmentForm env (VarArg v)
+ = case lookupUnfolding env v of
GenForm False _ _ _ -> Nothing
-- not allowed to inline :-(
GenForm _ _ (App (App (CoTyApp (Var bld) _)
:: SimplEnv
-> CoreArg
-> Maybe ([CoreArg],CoreArg)
-getListForm env (VarArg v) =
- case lookupUnfolding env v of
+getListForm env (VarArg v)
+ = case lookupUnfolding env v of
ConForm id _ [head,tail]
| id == consDataCon ->
case getListForm env tail of
getListForm env _ = Nothing
isInterestingArg :: SimplEnv -> CoreArg -> Bool
-isInterestingArg env (VarArg v) =
- case lookupUnfolding env v of
+isInterestingArg env (VarArg v)
+ = case lookupUnfolding env v of
GenForm False _ _ UnfoldNever -> False
GenForm _ _ exp guide -> True
_ -> False
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
%************************************************************************
%* *
module OccurAnal (
occurAnalyseBinds, occurAnalyseExpr, occurAnalyseGlobalExpr
-
- -- and to make the interface self-sufficient...
) where
-import Type
+import Ubiq{-uitous-}
+
import BinderInfo
-import CmdLineOpts ( GlobalSwitch(..), SimplifierSwitch(..) )
+import CmdLineOpts ( opt_D_dump_occur_anal, SimplifierSwitch(..) )
+import CoreSyn
import Digraph ( stronglyConnComp )
-import Id ( eqId, idWantsToBeINLINEd, isConstMethodId,
- isSpecPragmaId_maybe, SpecInfo )
-import Maybes
-import UniqSet
-import Util
+import Id ( idWantsToBeINLINEd, isConstMethodId,
+ emptyIdSet, unionIdSets, mkIdSet,
+ unitIdSet, elementOfIdSet,
+ addOneToIdSet, IdSet(..),
+ nullIdEnv, unitIdEnv, combineIdEnvs,
+ delOneFromIdEnv, delManyFromIdEnv,
+ mapIdEnv, lookupIdEnv, IdEnv(..),
+ GenId{-instance Eq-}
+ )
+import Maybes ( maybeToBool )
+import Outputable ( isExported, Outputable(..){-instance * (,) -} )
+import PprCore
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-}, GenTyVar{-ditto-} )
+import Pretty ( ppAboves )
+import TyVar ( GenTyVar{-instance Eq-} )
+import Unique ( Unique{-instance Eq-} )
+import Util ( assoc, pprTrace, panic )
+
+isSpecPragmaId_maybe = panic "OccurAnal.isSpecPragmaId_maybe (ToDo)"
\end{code}
Bool -- IgnoreINLINEPragma flag
-- False <=> OK to use INLINEPragma information
-- True <=> ignore INLINEPragma information
- (UniqSet Id) -- Candidates
+ IdSet -- Candidates
addNewCands :: OccEnv -> [Id] -> OccEnv
addNewCands (OccEnv kd ks kc ip cands) ids
- = OccEnv kd ks kc ip (cands `unionUniqSets` mkUniqSet ids)
+ = OccEnv kd ks kc ip (cands `unionIdSets` mkIdSet ids)
addNewCand :: OccEnv -> Id -> OccEnv
addNewCand (OccEnv ks kd kc ip cands) id
- = OccEnv kd ks kc ip (cands `unionUniqSets` singletonUniqSet id)
+ = OccEnv kd ks kc ip (addOneToIdSet cands id)
isCandidate :: OccEnv -> Id -> Bool
-isCandidate (OccEnv _ _ _ _ cands) id = id `elementOfUniqSet` cands
+isCandidate (OccEnv _ _ _ _ cands) id = id `elementOfIdSet` cands
ignoreINLINEPragma :: OccEnv -> Bool
ignoreINLINEPragma (OccEnv _ _ _ ip _) = ip
:: UsageDetails -> UsageDetails -> UsageDetails
combineUsageDetails usage1 usage2
- = --BSCC("combineUsages")
- combineIdEnvs combineBinderInfo usage1 usage2
- --ESCC
+ = combineIdEnvs combineBinderInfo usage1 usage2
combineAltsUsageDetails usage1 usage2
- = --BSCC("combineUsages")
- combineIdEnvs combineAltsBinderInfo usage1 usage2
- --ESCC
+ = combineIdEnvs combineAltsBinderInfo usage1 usage2
addOneOcc :: UsageDetails -> Id -> BinderInfo -> UsageDetails
-addOneOcc usage id info = combineIdEnvs combineBinderInfo usage (unitIdEnv id info)
+addOneOcc usage id info
+ = combineIdEnvs combineBinderInfo usage (unitIdEnv id info)
-- ToDo: make this more efficient
emptyDetails = (nullIdEnv :: UsageDetails)
unitDetails id info = (unitIdEnv id info :: UsageDetails)
-tagBinders :: UsageDetails -- Of scope
- -> [Id] -- Binders
- -> (UsageDetails, -- Details with binders removed
- [(Id,BinderInfo)]) -- Tagged binders
+tagBinders :: UsageDetails -- Of scope
+ -> [Id] -- Binders
+ -> (UsageDetails, -- Details with binders removed
+ [(Id,BinderInfo)]) -- Tagged binders
tagBinders usage binders
= (usage `delManyFromIdEnv` binders,
- [(binder, usage_of usage binder) | binder <- binders]
+ [ (binder, usage_of usage binder) | binder <- binders ]
)
-tagBinder :: UsageDetails -- Of scope
- -> Id -- Binders
- -> (UsageDetails, -- Details with binders removed
- (Id,BinderInfo)) -- Tagged binders
+tagBinder :: UsageDetails -- Of scope
+ -> Id -- Binders
+ -> (UsageDetails, -- Details with binders removed
+ (Id,BinderInfo)) -- Tagged binders
tagBinder usage binder
= (usage `delOneFromIdEnv` binder,
usage_of usage binder
| isExported binder = ManyOcc 0 -- Exported things count as many
| otherwise
- = case lookupIdEnv usage binder of
+ = case (lookupIdEnv usage binder) of
Nothing -> DeadCode
Just info -> info
isNeeded env usage binder
- = case usage_of usage binder of
+ = case (usage_of usage binder) of
DeadCode -> keepUnusedBinding env binder -- Maybe keep it anyway
other -> True
\end{code}
\begin{code}
occurAnalyseBinds
:: [CoreBinding] -- input
- -> (GlobalSwitch -> Bool)
-> (SimplifierSwitch -> Bool)
-> [SimplifiableCoreBinding] -- output
-occurAnalyseBinds binds global_sw_chkr simplifier_sw_chkr
- | global_sw_chkr D_dump_occur_anal = pprTrace "OccurAnal:" (ppr PprDebug binds') binds'
- | otherwise = binds'
+occurAnalyseBinds binds simplifier_sw_chkr
+ | opt_D_dump_occur_anal = pprTrace "OccurAnal:"
+ (ppAboves (map (ppr PprDebug) binds'))
+ binds'
+ | otherwise = binds'
where
(_, binds') = do initial_env binds
(simplifier_sw_chkr KeepSpecPragmaIds)
(not (simplifier_sw_chkr SimplMayDeleteConjurableIds))
(simplifier_sw_chkr IgnoreINLINEPragma)
- emptyUniqSet
+ emptyIdSet
do env [] = (emptyDetails, [])
do env (bind:binds)
where
new_env = env `addNewCands` (bindersOf bind)
(binds_usage, the_rest) = do new_env binds
- (final_usage, new_binds) = --BSCC("occAnalBind1")
- occAnalBind env bind binds_usage
- --ESCC
+ (final_usage, new_binds) = occAnalBind env bind binds_usage
\end{code}
\begin{code}
-occurAnalyseExpr :: UniqSet Id -- Set of interesting free vars
+occurAnalyseExpr :: IdSet -- Set of interesting free vars
-> CoreExpr
- -> (IdEnv BinderInfo, -- Occ info for interesting free vars
+ -> (IdEnv BinderInfo, -- Occ info for interesting free vars
SimplifiableCoreExpr)
occurAnalyseExpr candidates expr
occurAnalyseGlobalExpr expr
= -- Top level expr, so no interesting free vars, and
-- discard occurence info returned
- expr' where (_, expr') = occurAnalyseExpr emptyUniqSet expr
+ expr' where (_, expr') = occurAnalyseExpr emptyIdSet expr
\end{code}
%************************************************************************
sccs :: [[Id]]
sccs = case binders of
[_] -> [binders] -- Singleton; no need to analyse
- other -> stronglyConnComp eqId edges binders
+ other -> stronglyConnComp (==) edges binders
---- stuff to "re-constitute" bindings from dependency-analysis info ------
\begin{code}
occAnalRhs :: OccEnv
- -> Id -- Binder
+ -> Id -- Binder
-> CoreExpr -- Rhs
-> (UsageDetails, SimplifiableCoreExpr)
\begin{code}
occAnal :: OccEnv
-> CoreExpr
- -> (UsageDetails, -- Gives info only about the "interesting" Ids
+ -> (UsageDetails, -- Gives info only about the "interesting" Ids
SimplifiableCoreExpr)
occAnal env (Var v)
= (emptyDetails, Var v)
occAnal env (Lit lit) = (emptyDetails, Lit lit)
-occAnal env (Con con tys args) = (occAnalAtoms env args, Con con tys args)
-occAnal env (Prim op tys args) = (occAnalAtoms env args, Prim op tys args)
+occAnal env (Con con args) = (occAnalArgs env args, Con con args)
+occAnal env (Prim op args) = (occAnalArgs env args, Prim op args)
occAnal env (SCC cc body)
= (mapIdEnv markInsideSCC usage, SCC cc body')
occAnal env (App fun arg)
= (fun_usage `combineUsageDetails` arg_usage, App fun' arg)
where
- (fun_usage, fun') = occAnal env fun
- arg_usage = occAnalAtom env arg
+ (fun_usage, fun') = occAnal env fun
+ arg_usage = occAnalArg env arg
-occAnal env (CoTyApp fun ty)
- = (fun_usage, CoTyApp fun' ty)
+occAnal env (Lam (ValBinder binder) body)
+ = (mapIdEnv markDangerousToDup final_usage,
+ Lam (ValBinder tagged_binder) body')
where
- (fun_usage, fun') = occAnal env fun
-
-occAnal env (Lam binder body)
- = (mapIdEnv markDangerousToDup final_usage, Lam tagged_binder body')
- where
- (body_usage, body') = occAnal (env `addNewCand` binder) body
+ (body_usage, body') = occAnal (env `addNewCand` binder) body
(final_usage, tagged_binder) = tagBinder body_usage binder
-- ANDY: WE MUST THINK ABOUT THIS! (ToDo)
-occAnal env (CoTyLam tyvar body)
- = (mapIdEnv markDangerousToDup body_usage, CoTyLam tyvar body')
+occAnal env (Lam (TyBinder tyvar) body)
+ = (mapIdEnv markDangerousToDup body_usage,
+ Lam (TyBinder tyvar) body')
where
(body_usage, body') = occAnal env body
+occAnal env (Lam (UsageBinder _) _) = panic "OccurAnal.occAnal Lam UsageBinder"
+
occAnal env (Case scrut alts)
= (scrut_usage `combineUsageDetails` alts_usage,
Case scrut' alts')
where
new_env = env `addNewCands` (bindersOf bind)
(body_usage, body') = occAnal new_env body
- (final_usage, new_binds) = --BSCC("occAnalBind2")
- occAnalBind env bind body_usage
- --ESCC
+ (final_usage, new_binds) = occAnalBind env bind body_usage
\end{code}
Case alternatives
Atoms
~~~~~
\begin{code}
-occAnalAtoms :: OccEnv -> [CoreArg] -> UsageDetails
+occAnalArgs :: OccEnv -> [CoreArg] -> UsageDetails
-occAnalAtoms env atoms
+occAnalArgs env atoms
= foldr do_one_atom emptyDetails atoms
where
- do_one_atom (LitArg lit) usage = usage
do_one_atom (VarArg v) usage
| isCandidate env v = addOneOcc usage v (argOccurrence 0)
| otherwise = usage
+ do_one_atom other_arg usage = usage
-occAnalAtom :: OccEnv -> CoreArg -> UsageDetails
+occAnalArg :: OccEnv -> CoreArg -> UsageDetails
-occAnalAtom env (LitArg lit) = emptyDetails
-occAnalAtom env (VarArg v)
+occAnalArg env (VarArg v)
| isCandidate env v = unitDetails v (argOccurrence 0)
| otherwise = emptyDetails
+occAnalArg _ _ = emptyDetails
\end{code}
%
-% (c) The AQUA Project, Glasgow University, 1994-1995
+% (c) The AQUA Project, Glasgow University, 1994-1996
%
\section[SimplCase]{Simplification of `case' expression}
module SimplCase ( simplCase, bindLargeRhs ) where
-import SimplMonad
-import SimplEnv
+import Ubiq{-uitous-}
+import SmplLoop ( simplBind, simplExpr, MagicUnfoldingFun )
-import PrelInfo ( getPrimOpResultInfo, PrimOpResultInfo(..), PrimOp,
- voidPrimTy, voidPrimId, mkFunTy, primOpOkForSpeculation
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
+import BinderInfo -- too boring to try to select things...
+import CmdLineOpts ( SimplifierSwitch(..) )
+import CoreSyn
+import CoreUnfold ( UnfoldingDetails(..), UnfoldingGuidance(..),
+ FormSummary(..)
)
-import Type ( splitSigmaTy, splitTyArgs, glueTyArgs,
- getTyConFamilySize, isPrimType,
- maybeAppDataTyCon
+import CoreUtils ( coreAltsType, nonErrorRHSs, maybeErrorApp,
+ unTagBindersAlts
)
-import Literal ( isNoRepLit, Literal )
-import CmdLineOpts ( SimplifierSwitch(..) )
-import Id
-import IdInfo
-import Maybes ( catMaybes, maybeToBool, Maybe(..) )
-import Simplify
-import SimplUtils
-import SimplVar ( completeVar )
-import Util
+import Id ( idType, isDataCon, getIdDemandInfo,
+ DataCon(..), GenId{-instance Eq-}
+ )
+import IdInfo ( willBeDemanded, DemandInfo )
+import Literal ( isNoRepLit, Literal{-instance Eq-} )
+import Maybes ( maybeToBool )
+import PrelInfo ( voidPrimTy, voidPrimId )
+import PrimOp ( primOpOkForSpeculation, PrimOp{-instance Eq-} )
+import SimplEnv
+import SimplMonad
+import SimplUtils ( mkValLamTryingEta )
+import Type ( isPrimType, maybeAppDataTyCon, mkFunTys, eqTy )
+import Unique ( Unique{-instance Eq-} )
+import Usage ( GenUsage{-instance Eq-} )
+import Util ( isIn, isSingleton, panic, assertPanic )
\end{code}
-
-
-
-
Float let out of case.
\begin{code}
-> InExpr -- Scrutinee
-> InAlts -- Alternatives
-> (SimplEnv -> InExpr -> SmplM OutExpr) -- Rhs handler
- -> OutUniType -- Type of result expression
+ -> OutType -- Type of result expression
-> SmplM OutExpr
simplCase env (Let bind body) alts rhs_c result_ty
tick KnownBranch `thenSmpl_`
completePrimCaseWithKnownLit env lit alts rhs_c
-completeCase env expr@(Con con tys con_args) alts rhs_c
+completeCase env expr@(Con con con_args) alts rhs_c
= -- Ha! Staring us in the face -- select the appropriate alternative
tick KnownBranch `thenSmpl_`
- completeAlgCaseWithKnownCon env con tys con_args alts rhs_c
+ completeAlgCaseWithKnownCon env con con_args alts rhs_c
\end{code}
Case elimination
not (alt_con `is_elem` not_these)]
#ifdef DEBUG
--- ConForm c t v -> pprPanic "completeCase!" (ppAbove (ppCat [ppr PprDebug c, ppr PprDebug t, ppr PprDebug v]) (ppr PprDebug alts))
+-- ConForm c v -> pprPanic "completeCase!" (ppAbove (ppCat [ppr PprDebug c, ppStr "<args>"]) (ppr PprDebug alts))
-- ConForm can't happen, since we'd have
-- inlined it, and be in completeCaseWithKnownCon by now
#endif
-- If the scrut is already eval'd then there's no worry about
-- eliminating the case
scrut_is_evald = case scrut_form of
- OtherLitForm _ -> True
- ConForm _ _ _ -> True
- OtherConForm _ -> True
- other -> False
+ OtherLitForm _ -> True
+ ConForm _ _ -> True
+ OtherConForm _ -> True
+ other -> False
scrut_is_eliminable_primitive
= case scrut of
- Prim op _ _ -> primOpOkForSpeculation op
- Var _ -> case alts of
- PrimAlts _ _ -> True -- Primitive, hence non-bottom
- AlgAlts _ _ -> False -- Not primitive
- other -> False
+ Prim op _ -> primOpOkForSpeculation op
+ Var _ -> case alts of
+ PrimAlts _ _ -> True -- Primitive, hence non-bottom
+ AlgAlts _ _ -> False -- Not primitive
+ other -> False
-- case v of w -> e{strict in w} ===> e[v/w]
scrut_is_var_and_single_strict_default
bindLargeAlts :: SimplEnv
-> InAlts
-> (SimplEnv -> InExpr -> SmplM OutExpr) -- Old rhs handler
- -> OutUniType -- Result type
+ -> OutType -- Result type
-> SmplM ([OutBinding], -- Extra bindings
InAlts) -- Modified alts
\begin{code}
bindLargeRhs :: SimplEnv
-> [InBinder] -- The args wrt which the rhs should be abstracted
- -> OutUniType
+ -> OutType
-> (SimplEnv -> SmplM OutExpr) -- Rhs handler
-> SmplM (OutBinding, -- New bindings (singleton or empty)
InExpr) -- Modified rhs
-- it's processed the OutId won't be found in the environment, so it
-- will be left unmodified.
where
- rhs_fun_ty :: OutUniType
- rhs_fun_ty = glueTyArgs [simplTy env (idType id) | (id,_) <- used_args] rhs_ty
+ rhs_fun_ty :: OutType
+ rhs_fun_ty = mkFunTys [simplTy env (idType id) | (id,_) <- used_args] rhs_ty
used_args = [arg | arg@(_,usage) <- args, not (dead usage)]
used_arg_atoms = [VarArg arg_id | (arg_id,_) <- used_args]
dead DeadCode = True
dead other = False
- prim_rhs_fun_ty = mkFunTy voidPrimTy rhs_ty
+ prim_rhs_fun_ty = mkFunTys [voidPrimTy] rhs_ty
\end{code}
Case alternatives when we don't know the scrutinee
let
env1 = extendIdEnvWithClones env con_args con_args'
new_env = case scrut of
- Var var -> _scc_ "euegC1" (extendUnfoldEnvGivenConstructor env1 var con con_args')
- other -> env1
+ Var v -> extendUnfoldEnvGivenConstructor env1 v con con_args'
+ other -> env1
in
rhs_c new_env rhs `thenSmpl` \ rhs' ->
returnSmpl (con, con_args', rhs')
do_alt (lit, rhs)
= let
new_env = case scrut of
- Var var -> _scc_ "euegFD1" (extendUnfoldEnvGivenFormDetails env var (LitForm lit))
- other -> env
+ Var v -> extendUnfoldEnvGivenFormDetails env v (LitForm lit)
+ other -> env
in
rhs_c new_env rhs `thenSmpl` \ rhs' ->
returnSmpl (lit, rhs')
final_form
= case (form_from_this_case, scrut_form) of
(OtherConForm cs, OtherConForm ds) -> OtherConForm (cs++ds)
- (OtherLitForm cs, OtherLitForm ds) -> OtherLitForm (cs++ds)
+ (OtherLitForm cs, OtherLitForm ds) -> OtherLitForm (cs++ds)
-- ConForm, LitForm impossible
-- (ASSERT? ASSERT? Hello? WDP 95/05)
- other -> form_from_this_case
+ other -> form_from_this_case
- env2 = _scc_ "euegFD2" (extendUnfoldEnvGivenFormDetails env1 binder' final_form)
+ env2 = extendUnfoldEnvGivenFormDetails env1 binder' final_form
-- Change unfold details for scrut var. We now want to unfold it
-- to binder'
= cloneId env binder `thenSmpl` \ binder' ->
let
env1 = extendIdEnvWithAtom env binder (VarArg binder')
- new_env = _scc_ "euegFD2" (extendUnfoldEnvGivenFormDetails env1 binder' form)
+ new_env = extendUnfoldEnvGivenFormDetails env1 binder' form
in
rhs_c new_env rhs `thenSmpl` \ rhs' ->
returnSmpl (BindDefault binder' rhs')
\begin{code}
completeAlgCaseWithKnownCon
:: SimplEnv
- -> DataCon -> [Type] -> [InAtom]
+ -> DataCon -> [InArg]
-- Scrutinee is (con, type, value arguments)
-> InAlts
-> (SimplEnv -> InExpr -> SmplM OutExpr) -- Rhs handler
-> SmplM OutExpr
-completeAlgCaseWithKnownCon env con tys con_args (AlgAlts alts deflt) rhs_c
+completeAlgCaseWithKnownCon env con con_args (AlgAlts alts deflt) rhs_c
= ASSERT(isDataCon con)
search_alts alts
where
cloneId env binder `thenSmpl` \ id' ->
let
env1 = extendIdEnvWithClone env binder id'
- new_env = _scc_ "euegFD3" (extendUnfoldEnvGivenFormDetails env1 id'
- (ConForm con tys con_args))
+ new_env = extendUnfoldEnvGivenFormDetails env1 id'
+ (ConForm con con_args)
in
rhs_c new_env rhs `thenSmpl` \ rhs' ->
- returnSmpl (Let (NonRec id' (Con con tys con_args)) rhs')
+ returnSmpl (Let (NonRec id' (Con con con_args)) rhs')
\end{code}
Case absorption and identity-case elimination
munge_alt (con, args, rhs) = (con, args, Let (NonRec deflt_var v) rhs)
where
v | scrut_is_var = Var scrut_var
- | otherwise = Con con arg_tys (map VarArg args)
+ | otherwise = Con con (map TyArg arg_tys ++ map VarArg args)
arg_tys = case maybeAppDataTyCon (idType deflt_var) of
Just (_, arg_tys, _) -> arg_tys
identity_alts (AlgAlts alts deflt) = all identity_alg_alt alts && identity_deflt deflt
identity_alts (PrimAlts alts deflt) = all identity_prim_alt alts && identity_deflt deflt
- identity_alg_alt (con, args, Con con' _ args')
+ identity_alg_alt (con, args, Con con' args')
= con == con'
&& and (zipWith eq_arg args args')
&& length args == length args'
\end{code}
\begin{code}
- -- A cheap equality test which bales out fast!
cheap_eq :: InExpr -> InExpr -> Bool
+ -- A cheap equality test which bales out fast!
+
cheap_eq (Var v1) (Var v2) = v1==v2
cheap_eq (Lit l1) (Lit l2) = l1==l2
-cheap_eq (Con con1 tys1 args1) (Con con2 tys2 args2) = (con1==con2) &&
- (args1 `eq_args` args2)
- -- Types bound to be equal
-cheap_eq (Prim op1 tys1 args1) (Prim op2 tys2 args2) = (op1==op2) &&
- (args1 `eq_args` args2)
- -- Types bound to be equal
-cheap_eq (App f1 a1) (App f2 a2) = (f1 `cheap_eq` f2) && (a1 `eq_atom` a2)
-cheap_eq (CoTyApp f1 t1) (CoTyApp f2 t2) = (f1 `cheap_eq` f2) && (t1 == t2)
+cheap_eq (Con con1 args1) (Con con2 args2)
+ = con1 == con2 && args1 `eq_args` args2
+
+cheap_eq (Prim op1 args1) (Prim op2 args2)
+ = op1 ==op2 && args1 `eq_args` args2
+
+cheap_eq (App f1 a1) (App f2 a2)
+ = f1 `cheap_eq` f2 && a1 `eq_arg` a2
+
cheap_eq _ _ = False
-- ToDo: make CoreArg an instance of Eq
-eq_args (arg1: args1) (arg2 : args2) = (arg1 `eq_atom` arg2) && (args1 `eq_args` args2)
-eq_args [] [] = True
-eq_args other1 other2 = False
-
-eq_atom (LitArg l1) (LitArg l2) = l1==l2
-eq_atom (VarArg v1) (VarArg v2) = v1==v2
-eq_atom other1 other2 = False
+eq_args (a1:as1) (a2:as2) = a1 `eq_arg` a2 && as1 `eq_args` as2
+eq_args [] [] = True
+eq_args _ _ = False
+
+eq_arg (LitArg l1) (LitArg l2) = l1 == l2
+eq_arg (VarArg v1) (VarArg v2) = v1 == v2
+eq_arg (TyArg t1) (TyArg t2) = t1 `eqTy` t2
+eq_arg (UsageArg u1) (UsageArg u2) = u1 == u2
+eq_arg _ _ = False
\end{code}
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[SimplCore]{Driver for simplifying @Core@ programs}
\begin{code}
#include "HsVersions.h"
-module SimplCore (
- core2core
- ) where
+module SimplCore ( core2core ) where
-import Type ( getTyConDataCons )
---SAVE:import ArityAnal ( arityAnalProgram )
-import Bag
-import BinderInfo ( BinderInfo) -- instances only
+import Ubiq{-uitous-}
+
+import AnalFBWW ( analFBWW )
+import Bag ( isEmptyBag, foldBag )
+import BinderInfo ( BinderInfo{-instance Outputable-} )
import CgCompInfo ( uNFOLDING_CREATION_THRESHOLD,
uNFOLDING_USE_THRESHOLD,
uNFOLDING_OVERRIDE_THRESHOLD,
uNFOLDING_CON_DISCOUNT_WEIGHT
)
-import CmdLineOpts
+import CmdLineOpts ( CoreToDo(..), SimplifierSwitch(..), switchIsOn,
+ opt_D_show_passes,
+ opt_D_simplifier_stats,
+ opt_D_verbose_core2core,
+ opt_DoCoreLinting,
+ opt_FoldrBuildOn,
+ opt_ReportWhyUnfoldingsDisallowed,
+ opt_ShowImportSpecs,
+ opt_UnfoldingCreationThreshold,
+ opt_UnfoldingOverrideThreshold,
+ opt_UnfoldingUseThreshold
+ )
import CoreLint ( lintCoreBindings )
+import CoreSyn
+import CoreUnfold
+import CoreUtils ( substCoreBindings, manifestlyWHNF )
import FloatIn ( floatInwards )
import FloatOut ( floatOutwards )
-import Id ( getIdUnfolding,
- idType, toplevelishId,
- idWantsToBeINLINEd,
- unfoldingUnfriendlyId, isWrapperId,
- mkTemplateLocals
+import FoldrBuildWW ( mkFoldrBuildWW )
+import Id ( idType, toplevelishId, idWantsToBeINLINEd,
+ unfoldingUnfriendlyId,
+ nullIdEnv, addOneToIdEnv, delOneFromIdEnv,
+ lookupIdEnv, IdEnv(..),
+ GenId{-instance Outputable-}
)
-import IdInfo
+import IdInfo ( mkUnfolding )
import LiberateCase ( liberateCase )
-import MainMonad
-import Maybes
+import MagicUFs ( MagicUnfoldingFun )
+import MainMonad ( writeMn, exitMn, thenMn, thenMn_, returnMn,
+ MainIO(..)
+ )
+import Maybes ( maybeToBool )
+import Outputable ( Outputable(..){-instance * (,) -} )
+import PprCore ( pprCoreBinding, GenCoreExpr{-instance Outputable-} )
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-}, GenTyVar{-ditto-} )
+import Pretty ( ppShow, ppAboves, ppAbove, ppCat, ppStr )
import SAT ( doStaticArgs )
-import SCCauto
---ANDY:
---import SimplHaskell ( coreToHaskell )
-import SimplMonad ( zeroSimplCount, showSimplCount, TickType, SimplCount )
+import SCCauto ( addAutoCostCentres )
+import SimplMonad ( zeroSimplCount, showSimplCount, SimplCount )
import SimplPgm ( simplifyPgm )
import SimplVar ( leastItCouldCost )
import Specialise
import SpecUtils ( pprSpecErrs )
import StrictAnal ( saWwTopBinds )
-import FoldrBuildWW
-import AnalFBWW
+import TyVar ( nullTyVarEnv, GenTyVar{-instance Eq-} )
+import Unique ( Unique{-instance Eq-} )
+import UniqSupply ( splitUniqSupply )
+import Util ( panic{-ToDo:rm-} )
+
#if ! OMIT_DEFORESTER
import Deforest ( deforestProgram )
import DefUtils ( deforestable )
#endif
-import UniqSupply
-import Util
+
+isWrapperFor = panic "SimplCore.isWrapperFor (ToDo)"
+isWrapperId = panic "SimplCore.isWrapperId (ToDo)"
\end{code}
\begin{code}
core2core :: [CoreToDo] -- spec of what core-to-core passes to do
- -> (GlobalSwitch->SwitchResult)-- "global" command-line info lookup fn
-> FAST_STRING -- module name (profiling only)
-> PprStyle -- printing style (for debugging only)
-> UniqSupply -- a name supply
IdEnv UnfoldingDetails, -- unfoldings to be exported from here
SpecialiseData) -- specialisation data
-core2core core_todos sw_chkr module_name ppr_style us local_tycons tycon_specs binds
+core2core core_todos module_name ppr_style us local_tycons tycon_specs binds
= BSCC("Core2Core")
if null core_todos then -- very rare, I suspect...
-- well, we still must do some renumbering
returnMn (
- (snd (instCoreBindings (mkUniqueSupplyGrimily us) binds), nullIdEnv, init_specdata)
+ (substCoreBindings nullIdEnv nullTyVarEnv binds us,
+ nullIdEnv,
+ init_specdata)
)
else
(if do_verbose_core2core then
core_todos
`thenMn` \ (processed_binds, _, inline_env, spec_data, simpl_stats) ->
- (if switch_is_on D_simplifier_stats
+ (if opt_D_simplifier_stats
then writeMn stderr ("\nSimplifier Stats:\n")
`thenMn_`
writeMn stderr (showSimplCount simpl_stats)
where
init_specdata = initSpecData local_tycons tycon_specs
- switch_is_on = switchIsOn sw_chkr
-
- do_verbose_core2core = switch_is_on D_verbose_core2core
+ do_verbose_core2core = opt_D_verbose_core2core
lib_case_threshold -- ToDo: HACK HACK HACK : FIX ME FIX ME FIX ME
-- Use 4x a known threshold
- = case (intSwitchSet sw_chkr UnfoldingOverrideThreshold) of
+ = case opt_UnfoldingOverrideThreshold of
Nothing -> 4 * uNFOLDING_USE_THRESHOLD
Just xx -> 4 * xx
-------------
- core_linter = if switch_is_on DoCoreLinting
+ core_linter = if opt_DoCoreLinting
then lintCoreBindings ppr_style
else ( \ whodunnit spec_done binds -> binds )
-> BSCC("CoreSimplify")
begin_pass ("Simplify" ++ if switchIsOn simpl_sw_chkr SimplDoFoldrBuild
then " (foldr/build)" else "") `thenMn_`
- case (simplifyPgm binds sw_chkr simpl_sw_chkr simpl_stats us1) of
+ case (simplifyPgm binds simpl_sw_chkr simpl_stats us1) of
(p, it_cnt, simpl_stats2)
-> end_pass False us2 p inline_env spec_data simpl_stats2
("Simplify (" ++ show it_cnt ++ ")"
CoreDoFoldrBuildWorkerWrapper
-> BSCC("CoreDoFoldrBuildWorkerWrapper")
begin_pass "FBWW" `thenMn_`
- case (mkFoldrBuildWW switch_is_on us1 binds) of { binds2 ->
+ case (mkFoldrBuildWW us1 binds) of { binds2 ->
end_pass False us2 binds2 inline_env spec_data simpl_stats "FBWW"
} ESCC
CoreDoFoldrBuildWWAnal
-> BSCC("CoreDoFoldrBuildWWAnal")
begin_pass "AnalFBWW" `thenMn_`
- case (analFBWW switch_is_on binds) of { binds2 ->
+ case (analFBWW binds) of { binds2 ->
end_pass False us2 binds2 inline_env spec_data simpl_stats "AnalFBWW"
} ESCC
CoreDoCalcInlinings1 -- avoid inlinings w/ cost-centres
-> BSCC("CoreInlinings1")
begin_pass "CalcInlinings" `thenMn_`
- case (calcInlinings False sw_chkr inline_env binds) of { inline_env2 ->
+ case (calcInlinings False inline_env binds) of { inline_env2 ->
end_pass False us2 binds inline_env2 spec_data simpl_stats "CalcInlinings"
} ESCC
CoreDoCalcInlinings2 -- allow inlinings w/ cost-centres
-> BSCC("CoreInlinings2")
begin_pass "CalcInlinings" `thenMn_`
- case (calcInlinings True sw_chkr inline_env binds) of { inline_env2 ->
+ case (calcInlinings True inline_env binds) of { inline_env2 ->
end_pass False us2 binds inline_env2 spec_data simpl_stats "CalcInlinings"
} ESCC
CoreDoFullLaziness
-> BSCC("CoreFloating")
begin_pass "FloatOut" `thenMn_`
- case (floatOutwards switch_is_on us1 binds) of { binds2 ->
+ case (floatOutwards us1 binds) of { binds2 ->
end_pass False us2 binds2 inline_env spec_data simpl_stats "FloatOut"
} ESCC
CoreDoStrictness
-> BSCC("CoreStranal")
begin_pass "StrAnal" `thenMn_`
- case (saWwTopBinds us1 switch_is_on binds) of { binds2 ->
+ case (saWwTopBinds us1 binds) of { binds2 ->
end_pass False us2 binds2 inline_env spec_data simpl_stats "StrAnal"
} ESCC
CoreDoSpecialising
-> BSCC("Specialise")
begin_pass "Specialise" `thenMn_`
- case (specProgram switch_is_on us1 binds spec_data) of {
+ case (specProgram us1 binds spec_data) of {
(p, spec_data2@(SpecData _ spec_noerrs _ _ _
spec_errs spec_warn spec_tyerrs)) ->
-- if we got errors, we die straight away
(if not spec_noerrs ||
- (switch_is_on ShowImportSpecs && not (isEmptyBag spec_warn)) then
+ (opt_ShowImportSpecs && not (isEmptyBag spec_warn)) then
writeMn stderr (ppShow 1000 {-pprCols-}
(pprSpecErrs module_name spec_errs spec_warn spec_tyerrs))
`thenMn_` writeMn stderr "\n"
#else
-> BSCC("Deforestation")
begin_pass "Deforestation" `thenMn_`
- case (deforestProgram sw_chkr binds us1) of { binds2 ->
+ case (deforestProgram binds us1) of { binds2 ->
end_pass False us2 binds2 inline_env spec_data simpl_stats "Deforestation"
}
ESCC
CoreDoAutoCostCentres
-> BSCC("AutoSCCs")
begin_pass "AutoSCCs" `thenMn_`
- case (addAutoCostCentres sw_chkr module_name binds) of { binds2 ->
+ case (addAutoCostCentres module_name binds) of { binds2 ->
end_pass False us2 binds2 inline_env spec_data simpl_stats "AutoSCCs"
}
ESCC
-------------------------------------------------
begin_pass
- = if switch_is_on D_show_passes
+ = if opt_D_show_passes
then \ what -> writeMn stderr ("*** Core2Core: "++what++"\n")
else \ what -> returnMn ()
writeMn stderr ("\n*** "++what++":\n")
`thenMn_`
writeMn stderr (ppShow 1000
- (ppAboves (map (pprPlainCoreBinding ppr_style) binds2)))
+ (ppAboves (map (pprCoreBinding ppr_style) binds2)))
`thenMn_`
writeMn stderr "\n"
else
\begin{code}
calcInlinings :: Bool -- True => inlinings with _scc_s are OK
- -> (GlobalSwitch -> SwitchResult)
-> IdEnv UnfoldingDetails
-> [CoreBinding]
-> IdEnv UnfoldingDetails
-calcInlinings scc_s_OK sw_chkr inline_env_so_far top_binds
+calcInlinings scc_s_OK inline_env_so_far top_binds
= let
result = foldl calci inline_env_so_far top_binds
in
= ppCat [ppr PprDebug binder, ppStr "=>", pp_det details]
where
pp_det NoUnfoldingDetails = ppStr "_N_"
- pp_det (IWantToBeINLINEd _) = ppStr "INLINE"
+--LATER: pp_det (IWantToBeINLINEd _) = ppStr "INLINE"
pp_det (GenForm _ _ expr guide)
= ppAbove (ppr PprDebug guide) (ppr PprDebug expr)
pp_det other = ppStr "???"
------------
- switch_is_on = switchIsOn sw_chkr
-
- my_trace = if (switch_is_on ReportWhyUnfoldingsDisallowed)
+ my_trace = if opt_ReportWhyUnfoldingsDisallowed
then trace
else \ msg stuff -> stuff
(unfolding_creation_threshold, explicit_creation_threshold)
- = case (intSwitchSet sw_chkr UnfoldingCreationThreshold) of
+ = case opt_UnfoldingCreationThreshold of
Nothing -> (uNFOLDING_CREATION_THRESHOLD, False)
Just xx -> (xx, True)
unfold_use_threshold
- = case (intSwitchSet sw_chkr UnfoldingUseThreshold) of
+ = case opt_UnfoldingUseThreshold of
Nothing -> uNFOLDING_USE_THRESHOLD
Just xx -> xx
unfold_override_threshold
- = case (intSwitchSet sw_chkr UnfoldingOverrideThreshold) of
+ = case opt_UnfoldingOverrideThreshold of
Nothing -> uNFOLDING_OVERRIDE_THRESHOLD
Just xx -> xx
which = if scc_s_OK then " (late):" else " (early):"
in
- --pprTrace "giving up on size:" (ppCat [ppr PprDebug binder, ppr PprDebug
- -- [rhs_mentions_an_unmentionable, explicit_INLINE_requested,
- -- rhs_looks_like_a_caf, guidance_says_don't, guidance_size_too_big]]) (
my_my_trace ("unfolding disallowed for"++which++(ppShow 80 (ppr PprDebug binder))) (
ignominious_defeat
)
- --)
| rhs `isWrapperFor` binder
-- Don't add an explicit "unfolding"; let the worker/wrapper
-- stuff do its thing. INLINE things don't get w/w'd, so
-- they will be OK.
- = --pprTrace "giving up on isWrapperFor:" (ppr PprDebug binder)
- ignominious_defeat
+ = ignominious_defeat
#if ! OMIT_DEFORESTER
-- For the deforester: bypass the barbed wire for recursive
rhs_looks_like_a_data_val
= case (collectBinders rhs) of
- (_, _, [], Con _ _ _) -> True
- other -> False
+ (_, _, [], Con _ _) -> True
+ other -> False
rhs_arg_tys
= case (collectBinders rhs) of
= mentionedInUnfolding (\x -> x) rhs
rhs_mentions_an_unmentionable
- = --pprTrace "mentions:" (ppCat [ppr PprDebug binder, ppr PprDebug [(i,unfoldingUnfriendlyId i) | i <- mentioned_ids ]]) (
- any unfoldingUnfriendlyId mentioned_ids
+ = foldBag (||) unfoldingUnfriendlyId False mentioned_ids
|| mentions_litlit
- --)
-- ToDo: probably need to chk tycons/classes...
- mentions_no_other_ids = null mentioned_ids
+ mentions_no_other_ids = isEmptyBag mentioned_ids
explicit_INLINE_requested
-- did it come from a user {-# INLINE ... #-}?
= let
new_env = addOneToIdEnv inline_env binder (mkUnfolding guidance rhs)
- foldr_building = switch_is_on FoldrBuildOn
+ foldr_building = opt_FoldrBuildOn
in
if (not have_inlining_already) then
-- Not in env: we take it no matter what
)
import FiniteMap -- lots of things
import Id ( idType, getIdUnfolding, getIdStrictness,
+ applyTypeEnvToId,
nullIdEnv, growIdEnvList, rngIdEnv, lookupIdEnv,
addOneToIdEnv, modifyIdEnv,
IdEnv(..), IdSet(..), GenId )
import PprStyle ( PprStyle(..) )
import PprType ( GenType, GenTyVar )
import Pretty
-import Type ( getAppDataTyCon )
+import Type ( getAppDataTyCon, applyTypeEnvToTy )
import TyVar ( nullTyVarEnv, addOneToIdEnv, addOneToTyVarEnv,
growTyVarEnvList,
- TyVarEnv(..), GenTyVar )
-import Unique ( Unique )
+ TyVarEnv(..), GenTyVar{-instance Eq-}
+ )
+import Unique ( Unique{-instance Outputable-} )
import UniqSet -- lots of things
import Usage ( UVar(..), GenUsage{-instances-} )
import Util ( zipEqual, panic, assertPanic )
type TypeEnv = TyVarEnv Type
addToUFM_Directly = panic "addToUFM_Directly (SimplEnv)"
-applyTypeEnvToId = panic "applyTypeEnvToId (SimplEnv)"
-applyTypeEnvToTy = panic "applyTypeEnvToTy (SimplEnv)"
bottomIsGuaranteed = panic "bottomIsGuaranteed (SimplEnv)"
cmpType = panic "cmpType (SimplEnv)"
exprSmallEnoughToDup = panic "exprSmallEnoughToDup (SimplEnv)"
-- Only interested in Ids which have a "dangerous" unfolding; that is
-- one that claims to have a single occurrence.
= UFE (addOneToIdEnv u_env id (UnfoldItem id uf_details encl_cc))
- (interesting_ids `unionUniqSets` singletonUniqSet id)
+ (addOneToUniqSet interesting_ids id)
con_apps
grow_unfold_env (UFE u_env interesting_ids con_apps) id uf_details encl_cc
new_ty_env = growTyVarEnvList ty_env pairs
simplTy (SimplEnv _ _ ty_env _ _) ty = applyTypeEnvToTy ty_env ty
-
simplTyInId (SimplEnv _ _ ty_env _ _) id = applyTypeEnvToId ty_env id
\end{code}
-- (This is brought to you by *ANDY* Magic Constants, Inc.)
is_really_small
= case collectArgs new_rhs of
- (Var _, xs) -> length xs < 10
+ (Var _, _, _, xs) -> length xs < 10
_ -> False
-}
\end{code}
import SmplLoop -- well, cheating sort of
-import Id ( mkSysLocal )
+import Id ( mkSysLocal, mkIdWithNewUniq )
import SimplEnv
import SrcLoc ( mkUnknownSrcLoc )
+import TyVar ( cloneTyVar )
import UniqSupply ( getUnique, getUniques, splitUniqSupply,
UniqSupply
)
import Util ( zipWithEqual, panic )
infixr 9 `thenSmpl`, `thenSmpl_`
-
-cloneTyVar = panic "cloneTyVar (SimplMonad)"
-mkIdWithNewUniq = panic "mkIdWithNewUniq (SimplMonad)"
\end{code}
%************************************************************************
%
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1996
%
-\section[SimplPgm]{Interface to the ``new'' simplifier}
+\section[SimplPgm]{Interface to the simplifier}
\begin{code}
#include "HsVersions.h"
module SimplPgm ( simplifyPgm ) where
-import Type ( getTyVarMaybe )
-import CmdLineOpts ( switchIsOn, intSwitchSet,
- GlobalSwitch(..), SimplifierSwitch(..)
+import Ubiq{-uitous-}
+
+import CmdLineOpts ( opt_D_verbose_core2core,
+ switchIsOn, intSwitchSet, SimplifierSwitch(..)
+ )
+import CoreSyn
+import CoreUtils ( substCoreExpr )
+import Id ( externallyVisibleId,
+ mkIdEnv, lookupIdEnv, IdEnv(..),
+ GenId{-instance Ord3-}
)
-import Id ( externallyVisibleId )
-import IdInfo
-import Maybes ( catMaybes, Maybe(..) )
-import Outputable
+import Maybes ( catMaybes )
+import OccurAnal ( occurAnalyseBinds )
+import Outputable ( isExported )
+import Pretty ( ppAboves, ppBesides, ppInt, ppChar, ppStr )
import SimplEnv
import SimplMonad
import Simplify ( simplTopBinds )
-import OccurAnal -- occurAnalyseBinds
-import UniqSupply
-import Util
+import TyVar ( nullTyVarEnv, TyVarEnv(..) )
+import UniqSupply ( thenUs, returnUs, mapUs, splitUniqSupply, UniqSM(..) )
+import Util ( isIn, isn'tIn, removeDups, pprTrace )
\end{code}
\begin{code}
-simplifyPgm :: [CoreBinding] -- input
- -> (GlobalSwitch->SwitchResult) -- switch lookup fns (global
- -> (SimplifierSwitch->SwitchResult) -- and this-simplification-specific)
- -> SimplCount -- info about how many times
- -- each transformation has occurred
+simplifyPgm :: [CoreBinding] -- input
+ -> (SimplifierSwitch->SwitchResult)
+ -> SimplCount -- info about how many times
+ -- each transformation has occurred
-> UniqSupply
-> ([CoreBinding], -- output
- Int, -- info about how much happened
- SimplCount) -- accumulated simpl stats
+ Int, -- info about how much happened
+ SimplCount) -- accumulated simpl stats
-simplifyPgm binds g_sw_chkr s_sw_chkr simpl_stats us
+simplifyPgm binds s_sw_chkr simpl_stats us
= case (splitUniqSupply us) of { (s1, s2) ->
case (initSmpl s1 (simpl_pgm 0 1 binds)) of { ((pgm2, it_count, simpl_stats2), _) ->
case (tidy_top pgm2 s2) of { pgm3 ->
(pgm3, it_count, combineSimplCounts simpl_stats simpl_stats2) }}}
where
- global_switch_is_on = switchIsOn g_sw_chkr
simpl_switch_is_on = switchIsOn s_sw_chkr
occur_anal = occurAnalyseBinds
simpl_pgm n iterations pgm
= -- find out what top-level binders are used,
-- and prepare to unfold all the "simple" bindings
- -- pprTrace ("\niteration "++show iterations++":\n") (ppr PprDebug pgm) (
let
- tagged_pgm = BSCC("OccurBinds")
- occur_anal pgm global_switch_is_on simpl_switch_is_on
- ESCC
+ tagged_pgm = occur_anal pgm simpl_switch_is_on
in
-- do the business
simplTopBinds (nullSimplEnv s_sw_chkr) tagged_pgm `thenSmpl` \ new_pgm ->
show_status = pprTrace "NewSimpl: " (ppAboves [
ppBesides [ppInt iterations, ppChar '/', ppInt max_simpl_iterations],
ppStr (showSimplCount dr)
---DEBUG: , ppAboves (map (pprPlainCoreBinding PprDebug) new_pgm)
+--DEBUG: , ppAboves (map (pprCoreBinding PprDebug) new_pgm)
])
in
- (if global_switch_is_on D_verbose_core2core
+ (if opt_D_verbose_core2core
|| simpl_switch_is_on ShowSimplifierProgress
then show_status
else id)
else
simpl_pgm r (iterations + 1) new_pgm
)
- -- )
\end{code}
In @tidy_top@, we look for things at the top-level of the form...
= if null blast_alist then
returnUs binds_in -- no joy there
else
- -- pprTrace "undup output length:" (ppInt (length blast_alist)) (
mapUs blast binds_in `thenUs` \ binds_maybe ->
returnUs (catMaybes binds_maybe)
- -- )
where
blast_alist = undup (foldl find_cand [] binds_in)
blast_id_env = mkIdEnv blast_alist
undup :: [(Id, Id)] -> [(Id, Id)]
undup blast_list
- = -- pprTrace "undup input length:" (ppInt (length blast_list)) (
- let
+ = let
(singles, dups) = removeDups compare blast_list
list_of_dups = concat dups
in
[ s | s <- singles, s `not_elem` list_of_dups ]
- -- )
where
compare (x,_) (y,_) = x `cmp` y
returnUs (Just (Rec blasted_pairs))
where
blast_pr (binder, rhs)
- = subst_CoreExprUS blast_val_env nullTyVarEnv rhs `thenUs` \ blasted_rhs ->
+ = substCoreExpr blast_val_env nullTyVarEnv rhs `thenUs` \ new_rhs ->
returnUs (
- case lookupIdEnv blast_id_env binder of
- Just exportee -> (exportee, blasted_rhs)
- Nothing -> (binder, blasted_rhs)
+ case (lookupIdEnv blast_id_env binder) of
+ Just exportee -> (exportee, new_rhs)
+ Nothing -> (binder, new_rhs)
)
blast (NonRec binder rhs)
= if binder `is_elem` blast_all_exps then
returnUs Nothing -- this binding dies!
else
- subst_CoreExprUS blast_val_env nullTyVarEnv rhs `thenUs` \ blasted_rhs ->
+ substCoreExpr blast_val_env nullTyVarEnv rhs `thenUs` \ new_rhs ->
returnUs (Just (
- case lookupIdEnv blast_id_env binder of
- Just exportee -> NonRec exportee blasted_rhs
- Nothing -> NonRec binder blasted_rhs
+ case (lookupIdEnv blast_id_env binder) of
+ Just exportee -> NonRec exportee new_rhs
+ Nothing -> NonRec binder new_rhs
))
where
is_elem = isIn "blast"
-
-subst_CoreExprUS e1 e2 rhs us = snd (substCoreExprUS e1 e2 rhs (mkUniqueSupplyGrimily us))
\end{code}
import Ubiq{-uitous-}
import BinderInfo
+import CmdLineOpts ( SimplifierSwitch(..) )
import CoreSyn
import CoreUtils ( manifestlyWHNF )
-import Id ( idType, isBottomingId, getIdArity )
+import Id ( idType, isBottomingId, idWantsToBeINLINEd,
+ getIdArity, GenId{-instance Eq-}
+ )
import IdInfo ( arityMaybe )
import Maybes ( maybeToBool )
import PrelInfo ( augmentId, buildId, realWorldStateTy )
+import PrimOp ( primOpIsCheap )
import SimplEnv
import SimplMonad
-import Type ( isPrimType, maybeAppDataTyCon, getTyVar_maybe )
+import Type ( eqTy, isPrimType, maybeAppDataTyCon, getTyVar_maybe )
+import TyVar ( GenTyVar{-instance Eq-} )
import Util ( isIn, panic )
-primOpIsCheap = panic "SimplUtils. (ToDo)"
+getInstantiatedDataConSig = panic "SimplUtils.getInstantiatedDataConSig (ToDo)"
\end{code}
:: Bool -- Float let(rec)s out of rhs
-> Bool -- Float cheap primops out of rhs
-> Bool -- OK to duplicate code
- -> GenCoreExpr bdr Id
+ -> GenCoreExpr bdr Id tyvar uvar
-> Bool
floatExposesHNF float_lets float_primops ok_to_dup rhs
= try rhs
where
- try (Case (Prim _ _ _) (PrimAlts alts deflt) )
+ try (Case (Prim _ _) (PrimAlts alts deflt) )
| float_primops && (null alts || ok_to_dup)
= or (try_deflt deflt : map try_alt alts)
reduce_it (id:ids) (App fun (VarArg arg))
| id == arg
- && idType id /= realWorldStateTy
+ && not (idType id `eqTy` realWorldStateTy)
-- *never* eta-reduce away a PrimIO state token! (WDP 94/11)
= reduce_it ids fun
100, to represent "infinity", which is a bit of a hack.
\begin{code}
-etaExpandCount :: GenCoreExpr bdr Id
+etaExpandCount :: GenCoreExpr bdr Id tyvar uvar
-> Int -- Number of extra args you can safely abstract
etaExpandCount (Lam (ValBinder _) body)
-- Case with non-whnf scrutinee
-----------------------------
-eta_fun :: GenCoreExpr bdr Id -- The function
- -> Int -- How many args it can safely be applied to
+eta_fun :: GenCoreExpr bdr Id tv uv -- The function
+ -> Int -- How many args it can safely be applied to
eta_fun (App fun arg) | notValArg arg = eta_fun fun
where op is a cheap primitive operator
\begin{code}
-manifestlyCheap :: GenCoreExpr bndr Id -> Bool
+manifestlyCheap :: GenCoreExpr bndr Id tv uv -> Bool
-manifestlyCheap (Var _) = True
-manifestlyCheap (Lit _) = True
-manifestlyCheap (Con _ _ _) = True
-manifestlyCheap (SCC _ e) = manifestlyCheap e
-
-manifestlyCheap (Lam (ValBinder _) _) = True
-manifestlyCheap (Lam other_binder e) = manifestlyCheap e
-
-manifestlyCheap (Prim op _ _) = primOpIsCheap op
+manifestlyCheap (Var _) = True
+manifestlyCheap (Lit _) = True
+manifestlyCheap (Con _ _) = True
+manifestlyCheap (SCC _ e) = manifestlyCheap e
+manifestlyCheap (Lam x e) = if isValBinder x then True else manifestlyCheap e
+manifestlyCheap (Prim op _) = primOpIsCheap op
manifestlyCheap (Let bind body)
= manifestlyCheap body && all manifestlyCheap (rhssOfBind bind)
= manifestlyCheap scrut && all manifestlyCheap (rhssOfAlts alts)
manifestlyCheap other_expr -- look for manifest partial application
- = case (collectArgs other_expr) of { (fun, args) ->
+ = case (collectArgs other_expr) of { (fun, _, _, vargs) ->
case fun of
Var f | isBottomingId f -> True -- Application of a function which
-- need to be shared!
Var f -> let
- num_val_args = numValArgs args
+ num_val_args = length vargs
in
num_val_args == 0 || -- Just a type application of
-- a variable (f t1 t2 t3)
in
returnSmpl (
AlgAlts
- [(data_con, new_binders, Con data_con ty_args (map VarArg new_bindees))]
+ [(data_con, new_binders, mkCon data_con [] ty_args (map VarArg new_bindees))]
NoDefault
)
leastItCouldCost
) where
-import SimplMonad
-import SimplEnv
-import Literal ( isNoRepLit )
+import Ubiq{-uitous-}
+import SmplLoop ( simplExpr )
-import Type ( getAppDataTyCon, maybeAppDataTyCon,
- getTyConFamilySize, isPrimType
- )
-import BinderInfo ( oneTextualOcc, oneSafeOcc )
import CgCompInfo ( uNFOLDING_USE_THRESHOLD,
uNFOLDING_CON_DISCOUNT_WEIGHT
)
-import CmdLineOpts ( switchIsOn, intSwitchSet, SimplifierSwitch(..) )
-import Id ( idType, getIdInfo )
-import IdInfo
-import Maybes ( maybeToBool, Maybe(..) )
-import Simplify ( simplExpr )
-import SimplUtils ( simplIdWantsToBeINLINEd )
-import MagicUFs
-import Pretty
-import Util
+import CmdLineOpts ( intSwitchSet, switchIsOn, SimplifierSwitch(..) )
+import CoreSyn
+import CoreUnfold ( UnfoldingDetails(..), UnfoldingGuidance(..),
+ FormSummary(..)
+ )
+import Id ( idType, getIdInfo,
+ GenId{-instance Outputable-}
+ )
+import IdInfo ( DeforestInfo(..) )
+import Literal ( isNoRepLit )
+import MagicUFs ( applyMagicUnfoldingFun, MagicUnfoldingFun )
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-} )
+import Pretty ( ppBesides, ppStr )
+import SimplEnv
+import SimplMonad
+import TyCon ( tyConFamilySize )
+import Type ( isPrimType, getAppDataTyCon, maybeAppDataTyCon )
+import Util ( pprTrace, assertPanic, panic )
\end{code}
%************************************************************************
-> ASSERT( null args )
returnSmpl (Lit lit)
- ConForm con ty_args val_args
+ ConForm con args
-- Always inline constructors.
-- See comments before completeLetBinding
-> ASSERT( null args )
- returnSmpl (Con con ty_args val_args)
+ returnSmpl (Con con args)
GenForm txt_occ form_summary template guidance
-> considerUnfolding env var args
tick MagicUnfold `thenSmpl_`
returnSmpl magic_result
- IWantToBeINLINEd _ -> returnSmpl boring_result
+-- LATER:
+-- IWantToBeINLINEd _ -> returnSmpl boring_result
other -> returnSmpl boring_result
\end{code}
= go_for_it
| (case form_summary of {BottomForm -> True; other -> False} &&
- not (any isPrimType [ ty | (TypeArg ty) <- args ]))
+ not (any isPrimType [ ty | (TyArg ty) <- args ]))
-- Always inline bottoming applications, unless
-- there's a primitive type lurking around...
= go_for_it
con_discount -- ToDo: ************ get from a switch *********
= uNFOLDING_CON_DISCOUNT_WEIGHT
- (tyargs, valargs, args_left) = decomposeArgs args
+ (_, _, tyargs, valargs) = collectArgs args_in_dummy_expr
no_tyargs = length tyargs
no_valargs = length valargs
+ args_in_dummy_expr = mkGenApp (Var (panic "SimplVar.dummy")) args
+ -- we concoct this dummy expr, just so we can use collectArgs
+ -- (rather than make up a special-purpose bit of code)
rhs_looks_like_a_Con
= let
(_,_,val_binders,body) = collectBinders template
in
case (val_binders, body) of
- ([], Con _ _ _) -> True
+ ([], Con _ _) -> True
other -> False
dont_go_for_it = returnSmpl (mkGenApp (Var var) args)
-> Int -- the size/cost of the expr
-> Int -- the number of val args (== length args)
-> ArgInfoVector -- what we know about the *use* of the arguments
- -> [OutAtom] -- *an actual set of value arguments*!
+ -> [OutArg] -- *an actual set of value arguments*!
-> Int
-- If we apply an expression (usually a function) of given "costs"
full_price = disc size
take_something_off v = let
(tycon, _, _) = getAppDataTyCon (idType v)
- no_cons = case (getTyConFamilySize tycon) of
- Just n -> n
+ no_cons = tyConFamilySize tycon
reduced_size
= size - (no_cons * con_discount_weight)
in
case arg of
LitArg _ -> full_price
VarArg v -> case lookupUnfolding env v of
- ConForm _ _ _ -> take_something_off v
- other_form -> full_price
+ ConForm _ _ -> take_something_off v
+ other_form -> full_price
) want_cons rest_args
\end{code}
= let
take_something_off tycon
= let
- no_cons = case (getTyConFamilySize tycon) of { Just n -> n }
+ no_cons = tyConFamilySize tycon
reduced_size
= size - (no_cons * con_discount_weight)
module Simplify ( simplTopBinds, simplExpr, simplBind ) where
-import Pretty -- these are for debugging only
-import Outputable
+import Ubiq{-uitous-}
+import SmplLoop -- paranoia checking
-import SimplMonad
-import SimplEnv
-
-import PrelInfo ( getPrimOpResultInfo, PrimOpResultInfo(..),
- primOpOkForSpeculation, PrimOp(..), PrimRep,
- realWorldStateTy
- IF_ATTACK_PRAGMAS(COMMA realWorldTy)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import Type ( maybeAppDataTyCon, mkTyVarTy, mkTyVarTys, applyTy,
- splitTyArgs, splitTypeWithDictsAsArgs,
- maybeUnpackFunTy, isPrimType
- )
-import Literal ( isNoRepLit, Literal(..) )
import BinderInfo
import CmdLineOpts ( SimplifierSwitch(..) )
import ConFold ( completePrim )
-import Id
-import IdInfo
-import Maybes ( Maybe(..), catMaybes, maybeToBool )
-import SimplCase
-import SimplUtils
+import CoreSyn
+import CoreUtils ( coreExprType, nonErrorRHSs, maybeErrorApp,
+ unTagBinders, squashableDictishCcExpr,
+ manifestlyWHNF
+ )
+import Id ( idType, idWantsToBeINLINEd,
+ getIdDemandInfo, addIdDemandInfo,
+ GenId{-instance NamedThing-}
+ )
+import IdInfo ( willBeDemanded, DemandInfo )
+import Literal ( isNoRepLit )
+import Maybes ( maybeToBool )
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-} )
+import PrelInfo ( realWorldStateTy )
+import Pretty ( ppAbove )
+import PrimOp ( primOpOkForSpeculation, PrimOp(..) )
+import SimplCase ( simplCase, bindLargeRhs )
+import SimplEnv
+import SimplMonad
import SimplVar ( completeVar )
-import Util
+import SimplUtils
+import Type ( mkTyVarTy, mkTyVarTys, mkAppTy,
+ splitFunTy, getFunTy_maybe, eqTy
+ )
+import Util ( isSingleton, panic, pprPanic, assertPanic )
\end{code}
The controlling flags, and what they do
f = \y -> ...y...y...y...
in f x
@
-Now, it seems that @x@ appears only once, but even so it is NOT safe to put @x@
-in the UnfoldEnv, because @f@ will be inlined, and will duplicate the references to
-@x@.
+Now, it seems that @x@ appears only once, but even so it is NOT safe
+to put @x@ in the UnfoldEnv, because @f@ will be inlined, and will
+duplicate the references to @x@.
-Becuase of this, the "unconditional-inline" mechanism above is the only way
-in which non-HNFs can get inlined.
+Because of this, the "unconditional-inline" mechanism above is the
+only way in which non-HNFs can get inlined.
INLINE pragmas
~~~~~~~~~~~~~~
simplTopBinds env (NonRec binder@(in_id, occ_info) rhs : binds)
| inlineUnconditionally ok_to_dup_code occ_info
- = --pprTrace "simplTopBinds (inline):" (ppr PprDebug in_id) (
- let
+ = let
new_env = extendIdEnvWithInlining env env binder rhs
in
simplTopBinds new_env binds
- --)
where
ok_to_dup_code = switchIsSet env SimplOkToDupCode
simplRhsExpr env binder rhs `thenSmpl` \ rhs' ->
let
new_env = case rhs' of
- Var var -> extendIdEnvWithAtom env binder (VarArg var)
- Lit lit | not (isNoRepLit lit) -> extendIdEnvWithAtom env binder (LitArg lit)
- other -> extendUnfoldEnvGivenRhs env binder in_id rhs'
+ Var v -> extendIdEnvWithAtom env binder (VarArg v)
+ Lit i | not (isNoRepLit i) -> extendIdEnvWithAtom env binder (LitArg i)
+ other -> extendUnfoldEnvGivenRhs env binder in_id rhs'
in
- --pprTrace "simplTopBinds (nonrec):" (ppCat [ppr PprDebug in_id, ppr PprDebug rhs']) (
-
-- Process the other bindings
simplTopBinds new_env binds `thenSmpl` \ binds' ->
-- an unused atom binding. This localises the decision about
-- discarding top-level bindings.
returnSmpl (NonRec in_id rhs' : binds')
- --)
simplTopBinds env (Rec pairs : binds)
= simplRecursiveGroup env triples `thenSmpl` \ (bind', new_env) ->
- --pprTrace "simplTopBinds (rec):" (ppCat [ppr PprDebug bind']) (
-
-- Process the other bindings
simplTopBinds new_env binds `thenSmpl` \ binds' ->
-- Glue together and return
returnSmpl (bind' : binds')
- --)
where
triples = [(id, (binder, rhs)) | (binder@(id,_), rhs) <- pairs]
-- No cloning necessary at top level
Variables
~~~~~~~~~
-Check if there's a macro-expansion, and if so rattle on. Otherwise
-do the more sophisticated stuff.
+Check if there's a macro-expansion, and if so rattle on. Otherwise do
+the more sophisticated stuff.
\begin{code}
simplExpr env (Var v) args
- = --pprTrace "simplExpr:Var:" (ppr PprDebug v) (
- case lookupId env v of
+ = case (lookupId env v) of
Nothing -> let
- new_v = simplTyInId env v
+ new_v = simplTyInId env v
in
completeVar env new_v args
InlineIt id_env ty_env in_expr -- A macro-expansion
-> simplExpr (replaceInEnvs env (ty_env, id_env)) in_expr args
- --)
\end{code}
Literals
-~~~~~~~~~
+~~~~~~~~
\begin{code}
simplExpr env (Lit l) [] = returnSmpl (Lit l)
+#ifdef DEBUG
simplExpr env (Lit l) _ = panic "simplExpr:Lit with argument"
+#endif
\end{code}
Primitive applications are simple.
saturated and not higher-order. ADR)
\begin{code}
-simplExpr env (Prim op tys prim_args) args
+simplExpr env (Prim op prim_args) args
= ASSERT (null args)
let
- tys' = [simplTy env ty | ty <- tys]
- prim_args' = [simplAtom env prim_arg | prim_arg <- prim_args]
+ prim_args' = [simplArg env prim_arg | prim_arg <- prim_args]
op' = simpl_op op
in
- completePrim env op' tys' prim_args'
+ completePrim env op' prim_args'
where
-- PrimOps just need any types in them renamed.
rhs of a let binding (see completeLetBinding).
\begin{code}
-simplExpr env (Con con tys con_args) args
+simplExpr env (Con con con_args) args
= ASSERT( null args )
- returnSmpl (Con con tys' con_args')
- where
- con_args' = [simplAtom env con_arg | con_arg <- con_args]
- tys' = [simplTy env ty | ty <- tys]
+ returnSmpl (Con con [simplArg env con_arg | con_arg <- con_args])
\end{code}
\begin{code}
simplExpr env (App fun arg) args
- = simplExpr env fun (ValArg (simplAtom env arg) : args)
-
-simplExpr env (CoTyApp fun ty) args
- = simplExpr env fun (TypeArg (simplTy env ty) : args)
+ = simplExpr env fun (simplArg env arg : args)
\end{code}
Type lambdas
we can pass them all to @mkTyLamTryingEta@.
\begin{code}
-simplExpr env (CoTyLam tyvar body) (TypeArg ty : args)
+simplExpr env (Lam (TyBinder tyvar) body) (TyArg ty : args)
= -- ASSERT(not (isPrimType ty))
let
new_env = extendTyEnv env tyvar ty
tick TyBetaReduction `thenSmpl_`
simplExpr new_env body args
-simplExpr env tylam@(CoTyLam tyvar body) []
+simplExpr env tylam@(Lam (TyBinder tyvar) body) []
= do_tylambdas env [] tylam
where
- do_tylambdas env tyvars' (CoTyLam tyvar body)
+ do_tylambdas env tyvars' (Lam (TyBinder tyvar) body)
= -- Clone the type variable
cloneTyVarSmpl tyvar `thenSmpl` \ tyvar' ->
let
returnSmpl (
(if switchIsSet env SimplDoEtaReduction
then mkTyLamTryingEta
- else mkCoTyLam) (reverse tyvars') body'
+ else mkTyLam) (reverse tyvars') body'
)
-simplExpr env (CoTyLam tyvar body) (ValArg _ : _)
- = panic "simplExpr:CoTyLam ValArg"
+#ifdef DEBUG
+simplExpr env (Lam (TyBinder _) _) (_ : _)
+ = panic "simplExpr:TyLam with non-TyArg"
+#endif
\end{code}
~~~~~~~~~~~~~~~~
\begin{code}
-simplExpr env (Lam binder body) args
+simplExpr env (Lam (ValBinder binder) body) args
| null leftover_binders
= -- The lambda is saturated (or over-saturated)
tick BetaReduction `thenSmpl_`
0 {- Guaranteed applied to at least 0 args! -}
where
- (binder_args_pairs, leftover_binders, leftover_args) = collect_val_args [binder] args
+ (binder_args_pairs, leftover_binders, leftover_args) = collect_val_args binder args
env_for_enough_args = extendIdEnvWithAtomList env binder_args_pairs
zapped_binder_args_pairs = [ ((id, markDangerousToDup occ_info), arg)
| ((id, occ_info), arg) <- binder_args_pairs ]
- collect_val_args :: [InBinder] -- Binders
- -> [OutArg] -- Arguments
- -> ([(InBinder,OutAtom)], -- Binder,arg pairs
- [InBinder], -- Leftover binders
- [OutArg]) -- Leftover args
+ collect_val_args :: InBinder -- Binder
+ -> [OutArg] -- Arguments
+ -> ([(InBinder,OutArg)], -- Binder,arg pairs (ToDo: a maybe?)
+ [InBinder], -- Leftover binders (ToDo: a maybe)
+ [OutArg]) -- Leftover args
-- collect_val_args strips off the leading ValArgs from
-- the current arg list, returning them along with the
-- depleted list
- collect_val_args [] args = ([], [], args)
- collect_val_args binders [] = ([], binders, [])
- collect_val_args (binder:binders) (ValArg val_arg : args)
- = ((binder,val_arg):rest_pairs, leftover_binders, leftover_args)
- where
- (rest_pairs, leftover_binders, leftover_args) = collect_val_args binders args
-
- collect_val_args (binder:binders) (other_val_arg : args) = panic "collect_val_args"
- -- TypeArg should never meet a Lam
+ collect_val_args binder [] = ([], [binder], [])
+ collect_val_args binder (arg : args) | isValArg arg
+ = ([(binder,arg)], [], args)
+
+#ifdef DEBUG
+ collect_val_args _ (other_val_arg : _) = panic "collect_val_args"
+ -- TyArg should never meet a Lam
+#endif
\end{code}
\begin{code}
simplExpr env (SCC cc (Lam binder body)) args
= simplExpr env (Lam binder (SCC cc body)) args
-
-simplExpr env (SCC cc (CoTyLam tyvar body)) args
- = simplExpr env (CoTyLam tyvar (SCC cc body)) args
\end{code}
Some other slightly turgid SCC tidying-up cases:
returnSmpl (
(if switchIsSet env SimplDoEtaReduction
then mkTyLamTryingEta
- else mkCoTyLam) tyvars' lambda'
+ else mkTyLam) tyvars' lambda'
)
where
-- Note from ANDY:
-- non-trivial.
dont_eta_expand (Lit _) = True
dont_eta_expand (Var _) = True
- dont_eta_expand (CoTyApp f _) = dont_eta_expand f
- dont_eta_expand (CoTyLam _ b) = dont_eta_expand b
- dont_eta_expand (Con _ _ _) = True
- dont_eta_expand _ = False
+ dont_eta_expand (Con _ _) = True
+ dont_eta_expand (App f a)
+ | notValArg a = dont_eta_expand f
+ dont_eta_expand (Lam x b)
+ | notValBinder x = dont_eta_expand b
+ dont_eta_expand _ = False
\end{code}
let
new_env = extendIdEnvWithClones env binders binders'
in
- newIds extra_binder_tys `thenSmpl` \ extra_binders' ->
- simplExpr new_env body (map (ValArg.VarArg) extra_binders') `thenSmpl` \ body' ->
+ newIds extra_binder_tys `thenSmpl` \ extra_binders' ->
+ simplExpr new_env body (map VarArg extra_binders') `thenSmpl` \ body' ->
returnSmpl (
(if switchIsSet new_env SimplDoEtaReduction
then mkValLamTryingEta
where
(potential_extra_binder_tys, res_ty)
- = splitTyArgs (simplTy env (coreExprType (unTagBinders body)))
+ = splitFunTy (simplTy env (coreExprType (unTagBinders body)))
-- Note: it's possible that simplLam will be applied to something
-- with a forall type. Eg when being applied to the rhs of
-- let x = wurble
-- but usually doesn't
`max`
case potential_extra_binder_tys of
- [ty] | ty == realWorldStateTy -> 1
- other -> 0
+ [ty] | ty `eqTy` realWorldStateTy -> 1
+ other -> 0
\end{code}
simplBind :: SimplEnv
-> InBinding
-> (SimplEnv -> SmplM OutExpr)
- -> OutUniType
+ -> OutType
-> SmplM OutExpr
\end{code}
(early_triples, late_triples)
= partition is_early_triple ordinary_triples
- is_early_triple (_, (_, Con _ _ _)) = True
- is_early_triple (i, _ ) = idWantsToBeINLINEd i
+ is_early_triple (_, (_, Con _ _)) = True
+ is_early_triple (i, _ ) = idWantsToBeINLINEd i
in
-- Process the early bindings first
mapSmpl (do_one_binding env_w_inlinings) early_triples `thenSmpl` \ early_triples' ->
-> InExpr -- Original RHS
-> OutExpr -- The simplified RHS
-> (SimplEnv -> SmplM OutExpr) -- Body handler
- -> OutUniType -- Type of body
+ -> OutType -- Type of body
-> SmplM OutExpr
completeLet env binder@(id,binder_info) old_rhs new_rhs body_c body_ty
= cloneId env binder `thenSmpl` \ id' ->
let
env1 = extendIdEnvWithClone env binder id'
- new_env = _scc_ "euegR2" (extendUnfoldEnvGivenRhs env1 binder id' new_rhs)
+ new_env = extendUnfoldEnvGivenRhs env1 binder id' new_rhs
in
body_c new_env `thenSmpl` \ body' ->
returnSmpl (Let (NonRec id' new_rhs) body')
Just (rhs_atom, atom_tick_type) = maybe_atomic_rhs
- maybe_atomic_rhs :: Maybe (OutAtom, TickType)
+ maybe_atomic_rhs :: Maybe (OutArg, TickType)
-- If the RHS is atomic, we return Just (atom, tick type)
-- otherwise Nothing
Lit lit | not (isNoRepLit lit)
-> Just (LitArg lit, AtomicRhs)
- Con con tys con_args
+ Con con con_args
| try_to_reuse_constr
-- Look out for
-- let v = C args
--- ...(let w = C same-args in ...)...
-- Then use v instead of w. This may save
-- re-constructing an existing constructor.
- -> case lookForConstructor env con tys con_args of
+ -> case (lookForConstructor env con con_args) of
Nothing -> Nothing
Just var -> Just (VarArg var, ConReused)
%************************************************************************
\begin{code}
-simplAtom :: SimplEnv -> InAtom -> OutAtom
+simplArg :: SimplEnv -> InArg -> OutArg
-simplAtom env (LitArg lit) = LitArg lit
+simplArg env (LitArg lit) = LitArg lit
+simplArg env (TyArg ty) = TyArg (simplTy env ty)
-simplAtom env (VarArg id)
+simplArg env (VarArg id)
| isLocallyDefined id
= case lookupId env id of
Just (ItsAnAtom atom) -> atom
- Just (InlineIt _ _ _) -> pprPanic "simplAtom InLineIt:" (ppAbove (ppr PprDebug id) (pprSimplEnv env))
+ Just (InlineIt _ _ _) -> pprPanic "simplArg InLineIt:" (ppAbove (ppr PprDebug id) (pprSimplEnv env))
Nothing -> VarArg id -- Must be an uncloned thing
| otherwise
un_demandify (id, occ_info) = (id `addIdDemandInfo` noInfo, occ_info)
-is_cheap_prim_app (Prim op tys args) = primOpOkForSpeculation op
-is_cheap_prim_app other = False
+is_cheap_prim_app (Prim op _) = primOpOkForSpeculation op
+is_cheap_prim_app other = False
-computeResultType :: SimplEnv -> InExpr -> [OutArg] -> OutUniType
+computeResultType :: SimplEnv -> InExpr -> [OutArg] -> OutType
computeResultType env expr args
- = do expr_ty' args
+ = go expr_ty' args
where
expr_ty = coreExprType (unTagBinders expr)
expr_ty' = simplTy env expr_ty
- do ty [] = ty
- do ty (TypeArg ty_arg : args) = do (applyTy ty ty_arg) args
- do ty (ValArg a : args) = case maybeUnpackFunTy ty of
- Just (_, res_ty) -> do res_ty args
- Nothing -> panic "computeResultType"
+ go ty [] = ty
+ go ty (TyArg ty_arg : args) = go (mkAppTy ty ty_arg) args
+ go ty (a:args) | isValArg a = case (getFunTy_maybe ty) of
+ Just (_, res_ty) -> go res_ty args
+ Nothing -> panic "computeResultType"
\end{code}
Breaks the loop between SimplEnv and MagicUFs, by telling SimplEnv all
it needs to know about MagicUFs (not much).
+Also break the loop between SimplVar/SimplCase (which use
+Simplify.simplExpr) and SimplExpr (which uses whatever
+SimplVar/SimplCase cough up).
+
\begin{code}
interface SmplLoop where
-import MagicUFs (MagicUnfoldingFun )
+import MagicUFs ( MagicUnfoldingFun )
+import SimplEnv ( SimplEnv, InBinding(..), InExpr(..),
+ OutArg(..), OutExpr(..), OutType(..)
+ )
+import Simplify ( simplExpr, simplBind )
+import SimplMonad ( SmplM(..) )
data MagicUnfoldingFun
+
+simplExpr :: SimplEnv -> InExpr -> [OutArg] -> SmplM OutExpr
+simplBind :: SimplEnv
+ -> InBinding
+ -> (SimplEnv -> SmplM OutExpr)
+ -> OutType
+ -> SmplM OutExpr
\end{code}
%
-% (c) The AQUA Project, Glasgow University, 1994-1995
+% (c) The AQUA Project, Glasgow University, 1994-1996
%
\section[LambdaLift]{A STG-code lambda lifter}
module LambdaLift ( liftProgram ) where
+import Ubiq{-uitous-}
+
import StgSyn
-import Type ( mkForallTy, splitForalls, glueTyArgs,
- Type, RhoType(..), TauType(..)
+import Bag ( emptyBag, unionBags, unitBag, snocBag, bagToList )
+import Id ( idType, mkSysLocal, addIdArity,
+ mkIdSet, unitIdSet, minusIdSet,
+ unionManyIdSets, idSetToList, IdSet(..),
+ nullIdEnv, growIdEnvList, lookupIdEnv, IdEnv(..)
)
-import Bag
-import Id ( mkSysLocal, idType, addIdArity, Id )
-import Maybes
-import UniqSupply
-import SrcLoc ( mkUnknownSrcLoc, SrcLoc )
-import UniqSet
-import Util
+import SrcLoc ( mkUnknownSrcLoc )
+import Type ( splitForAllTy, mkForAllTys, mkFunTys )
+import UniqSupply ( getUnique, splitUniqSupply )
+import Util ( zipEqual, panic, assertPanic )
\end{code}
This is the lambda lifter. It turns lambda abstractions into
let
-- Find the free vars of all the rhss,
-- excluding the binders themselves.
- rhs_free_vars = unionManyUniqSets (map rhsFreeVars rhss)
- `minusUniqSet`
- mkUniqSet binders
+ rhs_free_vars = unionManyIdSets (map rhsFreeVars rhss)
+ `minusIdSet`
+ mkIdSet binders
rhs_info = unionLiftInfos rhs_infos
in
isLiftableRec other_rhs = False
rhsFreeVars :: StgRhs -> IdSet
-rhsFreeVars (StgRhsClosure _ _ fvs _ _ _) = mkUniqSet fvs
+rhsFreeVars (StgRhsClosure _ _ fvs _ _ _) = mkIdSet fvs
rhsFreeVars other = panic "rhsFreeVars"
\end{code}
mkScPieces extra_arg_set (id, StgRhsClosure cc bi _ upd args body)
= ASSERT( n_args > 0 )
-- Construct the rhs of the supercombinator, and its Id
- -- this trace blackholes sometimes, don't use it
- -- trace ("LL " ++ show (length (uniqSetToList extra_arg_set))) (
newSupercombinator sc_ty arity `thenLM` \ sc_id ->
-
returnLM ((sc_id, extra_args), (sc_id, sc_rhs))
- --)
where
n_args = length args
- extra_args = uniqSetToList extra_arg_set
+ extra_args = idSetToList extra_arg_set
arity = n_args + length extra_args
-- Construct the supercombinator type
type_of_original_id = idType id
extra_arg_tys = map idType extra_args
- (tyvars, rest) = splitForalls type_of_original_id
- sc_ty = mkForallTy tyvars (glueTyArgs extra_arg_tys rest)
+ (tyvars, rest) = splitForAllTy type_of_original_id
+ sc_ty = mkForAllTys tyvars (mkFunTys extra_arg_tys rest)
sc_rhs = StgRhsClosure cc bi [] upd (extra_args ++ args) body
\end{code}
lookup :: Id -> LiftM (Id,[Id])
lookup v ci us idenv
- = case lookupIdEnv idenv v of
- Just result -> result
- Nothing -> (v, [])
+ = case (lookupIdEnv idenv v) of
+ Just result -> result
+ Nothing -> (v, [])
addScInlines :: [Id] -> [(Id,[Id])] -> LiftM a -> LiftM a
addScInlines ids values m ci us idenv
getFinalFreeVars :: IdSet -> LiftM IdSet
getFinalFreeVars free_vars ci us idenv
- = unionManyUniqSets (map munge_it (uniqSetToList free_vars))
+ = unionManyIdSets (map munge_it (idSetToList free_vars))
where
munge_it :: Id -> IdSet -- Takes a free var and maps it to the "real"
-- free var
- munge_it id = case lookupIdEnv idenv id of
- Just (_, args) -> mkUniqSet args
- Nothing -> singletonUniqSet id
-
+ munge_it id = case (lookupIdEnv idenv id) of
+ Just (_, args) -> mkIdSet args
+ Nothing -> unitIdSet id
\end{code}
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[SatStgRhs]{Saturates RHSs when they are partial applications}
+96/03: This is actually an essential module, as it sets arity info
+for the code generator.
\begin{display}
Subject: arg satis check
module SatStgRhs ( satStgRhs ) where
+import Ubiq{-uitous-}
+
import StgSyn
-import Type ( splitTypeWithDictsAsArgs, Class,
- TyVarTemplate, TauType(..)
+import CostCentre ( isCafCC, subsumedCosts, useCurrentCostCentre )
+import Id ( idType, getIdArity, addIdArity, mkSysLocal,
+ nullIdEnv, addOneToIdEnv, growIdEnvList,
+ lookupIdEnv, IdEnv(..)
)
-import CostCentre
-import Id ( mkSysLocal, idType, getIdArity, addIdArity )
-import IdInfo -- SIGH: ( arityMaybe, ArityInfo, OptIdInfo(..) )
-import SrcLoc ( mkUnknownSrcLoc, SrcLoc )
-import UniqSupply
-import Util
-import Maybes
-
-type Arity = Int
+import IdInfo ( arityMaybe )
+import SrcLoc ( mkUnknownSrcLoc )
+import UniqSupply ( returnUs, thenUs, mapUs, getUnique, UniqSM(..) )
+import Util ( panic, assertPanic )
+
+splitTypeWithDictsAsArgs = panic "SatStgRhs.splitTypeWithDictsAsArgs (ToDo)"
+
type Count = Int
type ExprArityInfo = Maybe Int -- Just n => This expression has a guaranteed
module SimplStg ( stg2stg ) where
-IMPORT_Trace
+import Ubiq{-uitous-}
import StgSyn
import StgUtils
import LambdaLift ( liftProgram )
import SCCfinal ( stgMassageForProfiling )
import SatStgRhs ( satStgRhs )
+import StgLint ( lintStgBindings )
+import StgSAT ( doStaticArgs )
import StgStats ( showStgStats )
import StgVarInfo ( setStgVarInfo )
import UpdAnal ( updateAnalyse )
-import CmdLineOpts
-import Id ( unlocaliseId )
-import MainMonad
-import Maybes ( maybeToBool, Maybe(..) )
-import Outputable
-import Pretty
-import StgLint ( lintStgBindings )
-import StgSAT ( doStaticArgs )
-import UniqSet
-import UniqSupply
-import Util
+import CmdLineOpts ( opt_EnsureSplittableC, opt_SccGroup,
+ opt_StgDoLetNoEscapes, opt_D_verbose_stg2stg,
+ StgToDo(..)
+ )
+import Id ( nullIdEnv, lookupIdEnv, addOneToIdEnv,
+ growIdEnvList, isNullIdEnv, IdEnv(..),
+ GenId{-instance Eq/Outputable -}
+ )
+import MainMonad ( writeMn, thenMn_, thenMn, returnMn, MainIO(..) )
+import Maybes ( maybeToBool )
+import Outputable ( isExported )
+import PprType ( GenType{-instance Outputable-} )
+import Pretty ( ppShow, ppAbove, ppAboves, ppStr )
+import UniqSupply ( splitUniqSupply )
+import Util ( mapAccumL, panic, assertPanic )
+
+unlocaliseId = panic "SimplStg.unlocaliseId (ToDo)"
\end{code}
\begin{code}
-stg2stg :: [StgToDo] -- spec of what stg-to-stg passes to do
- -> (GlobalSwitch -> SwitchResult)-- access to all global cmd-line opts
- -> FAST_STRING -- module name (profiling only)
- -> PprStyle -- printing style (for debugging only)
+stg2stg :: [StgToDo] -- spec of what stg-to-stg passes to do
+ -> FAST_STRING -- module name (profiling only)
+ -> PprStyle -- printing style (for debugging only)
-> UniqSupply -- a name supply
-> [StgBinding] -- input...
-> MainIO
- ([StgBinding], -- output program...
- ([CostCentre], -- local cost-centres that need to be decl'd
- [CostCentre])) -- "extern" cost-centres
+ ([StgBinding], -- output program...
+ ([CostCentre], -- local cost-centres that need to be decl'd
+ [CostCentre])) -- "extern" cost-centres
-stg2stg stg_todos sw_chkr module_name ppr_style us binds
+stg2stg stg_todos module_name ppr_style us binds
= BSCC("Stg2Stg")
case (splitUniqSupply us) of { (us4now, us4later) ->
}}
ESCC
where
- switch_is_on = switchIsOn sw_chkr
-
- do_let_no_escapes = switch_is_on StgDoLetNoEscapes
- do_verbose_stg2stg = switch_is_on D_verbose_stg2stg
+ do_let_no_escapes = opt_StgDoLetNoEscapes
+ do_verbose_stg2stg = opt_D_verbose_stg2stg
(do_unlocalising, unlocal_tag)
- = case (stringSwitchSet sw_chkr EnsureSplittableC) of
+ = case (opt_EnsureSplittableC) of
Nothing -> (False, panic "tag")
- Just tag -> (True, _PK_ tag)
+ Just tag -> (True, tag)
- grp_name = case (stringSwitchSet sw_chkr SccGroup) of
- Just xx -> _PK_ xx
+ grp_name = case (opt_SccGroup) of
+ Just xx -> xx
Nothing -> module_name -- default: module name
-------------
BSCC("ProfMassage")
let
(collected_CCs, binds3)
- = stgMassageForProfiling module_name grp_name us1 switch_is_on binds
+ = stgMassageForProfiling module_name grp_name us1 binds
in
end_pass us2 "ProfMassage" collected_CCs binds3
ESCC
module StgSAT ( doStaticArgs ) where
-import Maybes ( Maybe(..) )
+import Ubiq{-uitous-}
+
import StgSyn
-import SATMonad ( SATEnv(..), SATInfo(..), Arg(..), updSAEnv, insSAEnv,
- SatM(..), initSAT, thenSAT, thenSAT_,
- emptyEnvSAT, returnSAT, mapSAT )
-import StgSATMonad
-import UniqSupply
-import Util
+import UniqSupply ( UniqSM(..) )
+import Util ( panic )
\end{code}
\begin{code}
doStaticArgs :: [StgBinding] -> UniqSupply -> [StgBinding]
+doStaticArgs = panic "StgSAT.doStaticArgs"
+
+{- LATER: to end of file:
doStaticArgs binds
= initSAT (mapSAT sat_bind binds)
where
satRhs (StgRhsClosure cc bi fvs upd args body)
= satExpr body `thenSAT` \ body' ->
returnSAT (StgRhsClosure cc bi fvs upd args body')
+-}
\end{code}
-
\begin{code}
#include "HsVersions.h"
-module StgSATMonad (
- getArgLists, saTransform
- ) where
-
-import Type ( mkSigmaTy, TyVarTemplate,
- splitSigmaTy, splitTyArgs,
- glueTyArgs, instantiateTy, TauType(..),
- Class, ThetaType(..), SigmaType(..),
- InstTyEnv(..)
- )
-import Id ( mkSysLocal, idType, eqId )
-import Maybes ( Maybe(..) )
-import StgSyn
-import SATMonad ( SATEnv(..), SATInfo(..), Arg(..), updSAEnv, insSAEnv,
- SatM(..), initSAT, thenSAT, thenSAT_,
- emptyEnvSAT, returnSAT, mapSAT, isStatic, dropStatics,
- getSATInfo, newSATName )
-import SrcLoc ( SrcLoc, mkUnknownSrcLoc )
-import UniqSupply
-import UniqSet ( UniqSet(..), emptyUniqSet )
-import Util
+module StgSATMonad ( getArgLists, saTransform ) where
+import Ubiq{-uitous-}
+
+import Util ( panic )
+
+getArgLists = panic "StgSATMonad.getArgLists"
+saTransform = panic "StgSATMonad.saTransform"
\end{code}
%************************************************************************
%************************************************************************
\begin{code}
+{- LATER: to end of file:
+
newSATNames :: [Id] -> SatM [Id]
newSATNames [] = returnSAT []
newSATNames (id:ids) = newSATName id (idType id) `thenSAT` \ id' ->
= remove_static_args origs as
remove_static_args (NotStatic:origs) (a:as)
= substAtom a:remove_static_args origs as
+-}
\end{code}
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1994
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[StgStats]{Gathers statistical information about programs}
module StgStats ( showStgStats ) where
-import StgSyn
+import Ubiq{-uitous-}
-import FiniteMap
+import StgSyn
-import Util
+import FiniteMap ( emptyFM, plusFM_C, unitFM, fmToList )
\end{code}
\begin{code}
combineSEs = foldr combineSE emptySE
countOne :: CounterType -> StatEnv
-countOne c = singletonFM c 1
+countOne c = unitFM c 1
countN :: CounterType -> Int -> StatEnv
-countN = singletonFM
+countN = unitFM
\end{code}
%************************************************************************
module StgVarInfo ( setStgVarInfo ) where
-IMPORT_Trace -- ToDo: rm (debugging only)
-import Pretty
-import Outputable
+import Ubiq{-uitous-}
import StgSyn
-import Id ( getIdArity, externallyVisibleId )
-import IdInfo -- ( arityMaybe, ArityInfo )
-
-import Maybes ( maybeToBool, Maybe(..) )
-import UniqSet
-import Util
+import Id ( emptyIdSet, mkIdSet, minusIdSet,
+ unionIdSets, unionManyIdSets, isEmptyIdSet,
+ unitIdSet, intersectIdSets,
+ addOneToIdSet, IdSet(..),
+ nullIdEnv, growIdEnvList, lookupIdEnv,
+ unitIdEnv, combineIdEnvs, delManyFromIdEnv,
+ rngIdEnv, IdEnv(..),
+ GenId{-instance Eq-}
+ )
+import Maybes ( maybeToBool )
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-} )
+import Util ( panic, pprPanic, assertPanic )
infixr 9 `thenLne`, `thenLne_`
\end{code}
env_extension = [(b, LetrecBound
True {- top level -}
(rhsArity rhs)
- emptyUniqSet)
+ emptyIdSet)
| (b,rhs) <- pairs]
pairs = case bind of
= extendVarEnv [ (a, LambdaBound) | a <- args ] (
do_body args body `thenLne` \ (body2, body_fvs, body_escs) ->
let
- set_of_args = mkUniqSet args
+ set_of_args = mkIdSet args
rhs_fvs = body_fvs `minusFVBinders` args
- rhs_escs = body_escs `minusUniqSet` set_of_args
+ rhs_escs = body_escs `minusIdSet` set_of_args
binder_info = lookupFVInfo scope_fv_info binder
in
returnLne (StgRhsClosure cc binder_info (getFVs rhs_fvs) upd args body2,
\begin{code}
varsExpr (StgApp lit@(StgLitArg _) args _)
- = --(if null args then id else (trace (ppShow 80 (ppr PprShowAll args)))) (
- returnLne (StgApp lit [] emptyUniqSet, emptyFVInfo, emptyUniqSet)
- --)
+ = returnLne (StgApp lit [] emptyIdSet, emptyFVInfo, emptyIdSet)
varsExpr (StgApp fun@(StgVarArg f) args _) = varsApp Nothing f args
vars_alts alts `thenLne` \ (alts2, alts_fvs, alts_escs) ->
lookupLiveVarsForSet alts_fvs `thenLne` \ alts_lvs ->
let
- live_in_alts = live_in_cont `unionUniqSets` alts_lvs
+ live_in_alts = live_in_cont `unionIdSets` alts_lvs
in
-- we tell the scrutinee that everything live in the alts
-- is live in it, too.
) `thenLne` \ (scrut2, scrut_fvs, scrut_escs) ->
lookupLiveVarsForSet scrut_fvs `thenLne` \ scrut_lvs ->
let
- live_in_whole_case = live_in_alts `unionUniqSets` scrut_lvs
+ live_in_whole_case = live_in_alts `unionIdSets` scrut_lvs
in
returnLne (
StgCase scrut2 live_in_whole_case live_in_alts uniq alts2,
scrut_fvs `unionFVInfo` alts_fvs,
- alts_escs `unionUniqSets` (getFVSet scrut_fvs) -- All free vars in the scrutinee escape
+ alts_escs `unionIdSets` (getFVSet scrut_fvs) -- All free vars in the scrutinee escape
)
where
vars_alts (StgAlgAlts ty alts deflt)
`thenLne` \ (alts2, alts_fvs_list, alts_escs_list) ->
let
alts_fvs = unionFVInfos alts_fvs_list
- alts_escs = unionManyUniqSets alts_escs_list
+ alts_escs = unionManyIdSets alts_escs_list
in
vars_deflt deflt `thenLne` \ (deflt2, deflt_fvs, deflt_escs) ->
returnLne (
StgAlgAlts ty alts2 deflt2,
alts_fvs `unionFVInfo` deflt_fvs,
- alts_escs `unionUniqSets` deflt_escs
+ alts_escs `unionIdSets` deflt_escs
)
where
vars_alg_alt (con, binders, worthless_use_mask, rhs)
returnLne (
(con, binders, good_use_mask, rhs2),
rhs_fvs `minusFVBinders` binders,
- rhs_escs `minusUniqSet` mkUniqSet binders -- ToDo: remove the minusUniqSet;
+ rhs_escs `minusIdSet` mkIdSet binders -- ToDo: remove the minusIdSet;
-- since escs won't include
-- any of these binders
))
`thenLne` \ (alts2, alts_fvs_list, alts_escs_list) ->
let
alts_fvs = unionFVInfos alts_fvs_list
- alts_escs = unionManyUniqSets alts_escs_list
+ alts_escs = unionManyIdSets alts_escs_list
in
vars_deflt deflt `thenLne` \ (deflt2, deflt_fvs, deflt_escs) ->
returnLne (
StgPrimAlts ty alts2 deflt2,
alts_fvs `unionFVInfo` deflt_fvs,
- alts_escs `unionUniqSets` deflt_escs
+ alts_escs `unionIdSets` deflt_escs
)
where
vars_prim_alt (lit, rhs)
returnLne ((lit, rhs2), rhs_fvs, rhs_escs)
vars_deflt StgNoDefault
- = returnLne (StgNoDefault, emptyFVInfo, emptyUniqSet)
+ = returnLne (StgNoDefault, emptyFVInfo, emptyIdSet)
vars_deflt (StgBindDefault binder _ rhs)
= extendVarEnv [(binder, CaseBound)] (
returnLne (
StgBindDefault binder used_in_rhs rhs2,
rhs_fvs `minusFVBinders` [binder],
- rhs_escs `minusUniqSet` singletonUniqSet binder
+ rhs_escs `minusIdSet` unitIdSet binder
))
\end{code}
other -> NoStgBinderInfo
-- uninteresting variable
- myself = singletonUniqSet f
+ myself = unitIdSet f
fun_escs = case how_bound of
LetrecBound _ arity lvs ->
if arity == n_args then
- emptyUniqSet -- Function doesn't escape
+ emptyIdSet -- Function doesn't escape
else
myself -- Inexact application; it does escape
- other -> emptyUniqSet -- Only letrec-bound escapees
+ other -> emptyIdSet -- Only letrec-bound escapees
-- are interesting
-- At the moment of the call:
-- two regardless.
live_at_call
- = live_in_cont `unionUniqSets` case how_bound of
- LetrecBound _ _ lvs -> lvs `minusUniqSet` myself
- other -> emptyUniqSet
+ = live_in_cont `unionIdSets` case how_bound of
+ LetrecBound _ _ lvs -> lvs `minusIdSet` myself
+ other -> emptyIdSet
in
returnLne (
StgApp (StgVarArg f) args live_at_call,
fun_fvs `unionFVInfo` args_fvs,
- fun_escs `unionUniqSets` (getFVSet args_fvs)
+ fun_escs `unionIdSets` (getFVSet args_fvs)
-- All the free vars of the args are disqualified
-- from being let-no-escaped.
)
-- we ain't in a let-no-escape world
getVarsLiveInCont `thenLne` \ live_in_cont ->
setVarsLiveInCont
- (if let_no_escape then live_in_cont else emptyUniqSet)
+ (if let_no_escape then live_in_cont else emptyIdSet)
(vars_bind rec_bind_lvs rec_body_fvs bind)
`thenLne` \ (bind2, bind_fvs, bind_escs, env_ext) ->
-- together with the live_in_cont ones
lookupLiveVarsForSet (bind_fvs `minusFVBinders` binders) `thenLne` \ lvs_from_fvs ->
let
- bind_lvs = lvs_from_fvs `unionUniqSets` live_in_cont
+ bind_lvs = lvs_from_fvs `unionIdSets` live_in_cont
in
-- bind_fvs and bind_escs still include the binders of the let(rec)
= (bind_fvs `unionFVInfo` body_fvs) `minusFVBinders` binders
live_in_whole_let
- = bind_lvs `unionUniqSets` (body_lvs `minusUniqSet` set_of_binders)
+ = bind_lvs `unionIdSets` (body_lvs `minusIdSet` set_of_binders)
real_bind_escs = if let_no_escape then
bind_escs
getFVSet bind_fvs
-- Everything escapes which is free in the bindings
- let_escs = (real_bind_escs `unionUniqSets` body_escs) `minusUniqSet` set_of_binders
+ let_escs = (real_bind_escs `unionIdSets` body_escs) `minusIdSet` set_of_binders
- all_escs = bind_escs `unionUniqSets` body_escs -- Still includes binders of
+ all_escs = bind_escs `unionIdSets` body_escs -- Still includes binders of
-- this let(rec)
- no_binder_escapes = isEmptyUniqSet (set_of_binders `intersectUniqSets` all_escs)
+ no_binder_escapes = isEmptyIdSet (set_of_binders `intersectIdSets` all_escs)
-- Mustn't depend on the passed-in let_no_escape flag, since
-- no_binder_escapes is used by the caller to derive the flag!
in
binders = case bind of
StgNonRec binder rhs -> [binder]
StgRec pairs -> map fst pairs
- set_of_binders = mkUniqSet binders
+ set_of_binders = mkIdSet binders
mk_binding bind_lvs (binder,rhs)
= (binder,
)
where
live_vars = if let_no_escape then
- bind_lvs `unionUniqSets` singletonUniqSet binder
+ addOneToIdSet bind_lvs binder
else
- singletonUniqSet binder
+ unitIdSet binder
vars_bind :: StgLiveVars
-> FreeVarsInfo -- Free var info for body of binding
mapAndUnzip3Lne (varsRhs rec_scope_fvs) pairs `thenLne` \ (rhss2, fvss, escss) ->
let
fvs = unionFVInfos fvss
- escs = unionManyUniqSets escss
+ escs = unionManyIdSets escss
in
returnLne (StgRec (binders `zip` rhss2), fvs, escs, env_ext)
))
-> StgLiveVars -- vars live in continuation
-> a
-type Arity = Int
-
data HowBound
= ImportBound
| CaseBound
| LambdaBound
| LetrecBound
- Bool -- True <=> bound at top level
- Arity -- Arity
+ Bool -- True <=> bound at top level
+ Arity -- Arity
StgLiveVars -- Live vars... see notes below
\end{code}
The std monad functions:
\begin{code}
initLne :: Bool -> LneM a -> a
-initLne want_LNEs m = m want_LNEs nullIdEnv emptyUniqSet
+initLne want_LNEs m = m want_LNEs nullIdEnv emptyIdSet
{-# INLINE thenLne #-}
{-# INLINE thenLne_ #-}
lookupLiveVarsForSet :: FreeVarsInfo -> LneM StgLiveVars
lookupLiveVarsForSet fvs sw env lvs_cont
- = returnLne (unionManyUniqSets (map do_one (getFVs fvs)))
+ = returnLne (unionManyIdSets (map do_one (getFVs fvs)))
sw env lvs_cont
where
do_one v
= if isLocallyDefined v then
case (lookupIdEnv env v) of
- Just (LetrecBound _ _ lvs) -> lvs `unionUniqSets` singletonUniqSet v
- Just _ -> singletonUniqSet v
+ Just (LetrecBound _ _ lvs) -> addOneToIdSet lvs v
+ Just _ -> unitIdSet v
Nothing -> pprPanic "lookupVarEnv/do_one:" (ppr PprShowAll v)
else
- emptyUniqSet
+ emptyIdSet
\end{code}
--
-- The Bool is True <=> the Id is top level letrec bound
-type EscVarsSet = UniqSet Id
+type EscVarsSet = IdSet
\end{code}
\begin{code}
getFVs :: FreeVarsInfo -> [Id] -- Non-top-level things only
getFVs fvs = [id | (id,False,_) <- rngIdEnv fvs]
-getFVSet :: FreeVarsInfo -> UniqSet Id
-getFVSet fvs = mkUniqSet (getFVs fvs)
+getFVSet :: FreeVarsInfo -> IdSet
+getFVSet fvs = mkIdSet (getFVs fvs)
plusFVInfo (id1,top1,info1) (id2,top2,info2)
= ASSERT (id1 == id2 && top1 == top2)
\section{Update Avoidance Analyser} -*-haskell-literate-*-
(c) Simon Marlow, Andre Santos 1992-1993
-(c) The AQUA Project, Glasgow University, 1995
+(c) The AQUA Project, Glasgow University, 1995-1996
%-----------------------------------------------------------------------------
\subsection{Module Interface}
> module UpdAnal ( updateAnalyse ) where
>
-> import Type ( splitTyArgs, splitSigmaTy, Class, TyVarTemplate,
-> TauType(..)
-> )
-> import Id
-> import IdInfo
-> import Outputable ( isExported )
-> import Pretty
-> import SrcLoc ( mkUnknownSrcLoc )
+> import Ubiq{-uitous-}
+>
> import StgSyn
-> import UniqSet
-> import UniqSupply ( getBuiltinUniques )
-> import Util
+> import Util ( panic )
+>
+> updateAnalyse :: [StgBinding] -> [StgBinding] {- Exported -}
+> updateAnalyse = panic "UpdAnal.updateAnalyse"
+>
+> {- LATER: to end of file:
+> --import Type ( splitTyArgs, splitSigmaTy, Class, TyVarTemplate,
+> -- TauType(..)
+> -- )
+> --import Id
+> --import IdInfo
+> --import Outputable ( isExported )
+> --import Pretty
+> --import SrcLoc ( mkUnknownSrcLoc )
+> --import StgSyn
+> --import UniqSet
+> --import UniqSupply ( getBuiltinUniques )
+> --import Util
%-----------------------------------------------------------------------------
\subsection{Reverse application}
> addIdUpdateInfo v
> (mkUpdateInfo (mkUpdateSpec v c))
> | otherwise = v
+> -}
%-----------------------------------------------------------------------------
case (firstJust (map try spec_infos)) of
Just id -> id
- Nothing -> error ("ERROR: There is some confusion about a value specialised to a type;\ndetails follow (and more info in the User's Guide):\n\t"++(ppShow 80 (ppr PprDebug unspec_id)))
+ Nothing -> pprError "ERROR: There is some confusion about a value specialised to a type;\ndetails follow (and more info in the User's Guide):\n\t"
+ (ppr PprDebug unspec_id)
}
where
try (SpecInfo template_maybes _ id)
match [{-out of templates-}] [] = Just []
match (Nothing:ty_maybes) (spec_ty:spec_tys)
- = case (isUnboxedDataType spec_ty) of
+ = case (isUnboxedType spec_ty) of
True -> Nothing -- Can only match boxed type against
-- type argument which has not been
-- specialised on
pp_the_list (p:ps) = ppBesides [p, pp'SP{-'-}, pp_the_list ps]
pp_maybe Nothing = ifPprInterface sty pp_NONE
- pp_maybe (Just t) = pprParendType sty t
+ pp_maybe (Just t) = pprParendGenType sty t
\end{pseudocode}
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
%
\section[Specialise]{Stamping out overloading, and (optionally) polymorphism}
pprSpecErrs
) where
-import Type
-import Bag ( Bag, isEmptyBag, bagToList )
-import FiniteMap ( FiniteMap, emptyFM, addListToFM_C,
- plusFM_C, keysFM, lookupWithDefaultFM
+import Ubiq{-uitous-}
+
+import Bag ( isEmptyBag, bagToList )
+import Class ( getClassOpString, GenClass{-instance NamedThing-} )
+import FiniteMap ( emptyFM, addListToFM_C, plusFM_C, keysFM,
+ lookupWithDefaultFM
)
-import Id ( mkSameSpecCon, idType,
- isDictFunId, isConstMethodId_maybe,
+import Id ( idType, isDictFunId, isConstMethodId_maybe,
isDefaultMethodId_maybe,
- getInstIdModule, Id )
-import Maybes
-import Outputable
-import Pretty
-import Util
+ GenId {-instance NamedThing -}
+ )
+import Maybes ( maybeToBool, catMaybes, firstJust )
+import Outputable ( isAvarop, pprNonOp )
+import PprStyle ( PprStyle(..) )
+import PprType ( pprGenType, pprParendGenType, pprMaybeTy,
+ TyCon{-ditto-}, GenType{-ditto-}, GenTyVar
+ )
+import Pretty -- plenty of it
+import TyCon ( tyConTyVars, TyCon{-instance NamedThing-} )
+import Type ( splitSigmaTy, mkTyVarTy, mkForAllTys,
+ getTyVar_maybe, isUnboxedType
+ )
+import TyVar ( GenTyVar{-instance Eq-} )
+import Unique ( Unique{-instance Eq-} )
+import Util ( equivClasses, zipWithEqual, cmpPString,
+ assertPanic, panic{-ToDo:rm-}
+ )
+
+cmpType = panic "SpecUtils.cmpType (ToDo: get rid of)"
+mkSameSpecCon = panic "SpecUtils.mkSameSpecCon (ToDo)"
+getInstIdModule = panic "SpecUtils.getInstIdModule (ToDo)"
+specialiseTy :: Type -> [Maybe Type] -> Int -> Type
+specialiseTy = panic "SpecUtils.specialiseTy (ToDo)"
\end{code}
@specialiseCallTys@ works out which type args don't need to be specialised on,
specialiseCallTys False spec_unboxed spec_overloading cvec tys
= zipWithEqual spec_ty_other cvec tys
where
- spec_ty_other c ty | (spec_unboxed && isUnboxedDataType ty)
+ spec_ty_other c ty | (spec_unboxed && isUnboxedType ty)
|| (spec_overloading && c)
= Just ty
| otherwise
\begin{code}
getIdOverloading :: Id
- -> ([TyVarTemplate], [(Class,TyVarTemplate)])
+ -> ([TyVar], [(Class,TyVar)])
getIdOverloading id
= (tyvars, tyvar_part_of theta)
where
(tyvars, theta, _) = splitSigmaTy (idType id)
- tyvar_part_of [] = []
- tyvar_part_of ((clas,ty) : theta) = case getTyVarTemplateMaybe ty of
- Nothing -> []
- Just tyvar -> (clas, tyvar) : tyvar_part_of theta
+ tyvar_part_of [] = []
+ tyvar_part_of ((c,ty):theta) = case (getTyVar_maybe ty) of
+ Nothing -> []
+ Just tv -> (c, tv) : tyvar_part_of theta
\end{code}
\begin{code}
isUnboxedSpecialisation tys
= any is_unboxed tys
where
- is_unboxed (Just ty) = isUnboxedDataType ty
+ is_unboxed (Just ty) = isUnboxedType ty
is_unboxed Nothing = False
\end{code}
specialiseConstrTys tys
= map maybe_unboxed_ty tys
where
- maybe_unboxed_ty ty = case isUnboxedDataType ty of
+ maybe_unboxed_ty ty = case isUnboxedType ty of
True -> Just ty
False -> Nothing
\end{code}
then Nothing
else Just (ppSep [ppStr "Spec and Arg Types Inconsistent:",
ppStr "spectys=", ppSep [pprMaybeTy PprDebug ty | ty <- spec_tys],
- ppStr "argtys=", ppSep [pprParendType PprDebug ty | ty <- arg_tys]])
+ ppStr "argtys=", ppSep [pprParendGenType PprDebug ty | ty <- arg_tys]])
where
match (Nothing:spec_tys) (arg:arg_tys)
- = not (isUnboxedDataType arg) &&
+ = not (isUnboxedType arg) &&
match spec_tys arg_tys
match (Just spec:spec_tys) (arg:arg_tys)
- = case (cmpUniType True{-properly-} spec arg) of
+ = case (cmpType True{-properly-} spec arg) of
EQ_ -> match spec_tys arg_tys
other -> False
match [] [] = True
mod_tyspecs = lookupWithDefaultFM tyspecs_fm [] mod
mod_idspecs = lookupWithDefaultFM idspecs_fm [] mod
have_specs = not (null mod_tyspecs && null mod_idspecs)
- ty_sty = PprInterface (error "SpecUtils:PprInterface:sw_chkr")
+ ty_sty = PprInterface
pp_module mod
= ppBesides [ppPStr mod, ppStr ":"]
pp_tyspec sty pp_mod (_, tycon, tys)
= ppCat [pp_mod,
ppStr "{-# SPECIALIZE", ppStr "data",
- pprNonOp PprForUser tycon, ppCat (map (pprParendType sty) spec_tys),
+ pprNonOp PprForUser tycon, ppCat (map (pprParendGenType sty) spec_tys),
ppStr "#-}", ppStr "{- Essential -}"
]
where
- tvs = getTyConTyVarTemplates tycon
+ tvs = tyConTyVars tycon
(spec_args, tv_maybes) = unzip (map choose_ty (tvs `zip` tys))
- spec_tys = map (mkForallTy (catMaybes tv_maybes)) spec_args
+ spec_tys = map (mkForAllTys (catMaybes tv_maybes)) spec_args
- choose_ty (tv, Nothing) = (mkTyVarTemplateTy tv, Just tv)
+ choose_ty (tv, Nothing) = (mkTyVarTy tv, Just tv)
choose_ty (tv, Just ty) = (ty, Nothing)
pp_idspec :: PprStyle -> Pretty -> (FAST_STRING, Id, [Maybe Type], Bool) -> Pretty
= ppCat [pp_mod,
ppStr "{-# SPECIALIZE",
ppStr "instance",
- pprType sty spec_ty,
+ pprGenType sty spec_ty,
ppStr "#-}", pp_essential ]
| is_const_method_id
ppCat [pp_mod,
ppStr "{-# SPECIALIZE",
pp_clsop clsop_str, ppStr "::",
- pprType sty spec_ty,
+ pprGenType sty spec_ty,
ppStr "#-} {- IN instance",
- ppPStr cls_str, pprParendType sty clsty,
+ ppPStr cls_str, pprParendGenType sty clsty,
ppStr "-}", pp_essential ]
| is_default_method_id
ppPStr cls_str,
ppStr "EXPLICIT METHOD REQUIRED",
pp_clsop clsop_str, ppStr "::",
- pprType sty spec_ty,
+ pprGenType sty spec_ty,
ppStr "-}", pp_essential ]
| otherwise
= ppCat [pp_mod,
ppStr "{-# SPECIALIZE",
pprNonOp PprForUser id, ppStr "::",
- pprType sty spec_ty,
+ pprGenType sty spec_ty,
ppStr "#-}", pp_essential ]
where
spec_ty = specialiseTy (idType id) tys 100 -- HACK to drop all dicts!!!
) where
-import SpecUtils
+import Ubiq{-uitous-}
-import PrelInfo ( liftDataCon, PrimOp(..), PrimRep -- for CCallOp
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
+import Bag ( emptyBag, unitBag, isEmptyBag, unionBags,
+ partitionBag, listToBag, bagToList
+ )
+import Class ( GenClass{-instance Eq-} )
+import CmdLineOpts ( opt_SpecialiseImports, opt_D_simplifier_stats,
+ opt_CompilingPrelude, opt_SpecialiseTrace,
+ opt_SpecialiseOverloaded, opt_SpecialiseUnboxed,
+ opt_SpecialiseAll
)
-import Type
-import Bag
-import CmdLineOpts ( GlobalSwitch(..) )
import CoreLift ( mkLiftedId, liftExpr, bindUnlift, applyBindUnlifts )
-import FiniteMap
-import Id
-import IdInfo -- All of it
-import Maybes ( catMaybes, firstJust, maybeToBool, Maybe(..) )
-import UniqSet -- All of it
-import Util
-import UniqSupply
+import CoreSyn
+import CoreUtils ( coreExprType, squashableDictishCcExpr )
+import FiniteMap ( addListToFM_C )
+import Id ( idType, isDefaultMethodId_maybe, toplevelishId,
+ isSuperDictSelId_maybe, isBottomingId,
+ isConstMethodId_maybe, isDataCon,
+ isImportedId, mkIdWithNewUniq,
+ dataConTyCon, applyTypeEnvToId,
+ nullIdEnv, addOneToIdEnv, growIdEnvList,
+ lookupIdEnv, IdEnv(..),
+ emptyIdSet, mkIdSet, unitIdSet,
+ elementOfIdSet, minusIdSet,
+ unionIdSets, unionManyIdSets, IdSet(..),
+ GenId{-instance Eq-}
+ )
+import Literal ( Literal{-instance Outputable-} )
+import Maybes ( catMaybes, firstJust, maybeToBool )
+import Outputable ( interppSP, Outputable(..){-instance * []-} )
+import PprStyle ( PprStyle(..) )
+import PprType ( pprGenType, pprParendGenType, pprMaybeTy,
+ GenType{-instance Outputable-}, GenTyVar{-ditto-},
+ TyCon{-ditto-}
+ )
+import PrelInfo ( liftDataCon )
+import Pretty ( ppHang, ppCat, ppStr, ppAboves, ppBesides,
+ ppInt, ppSP, ppInterleave, ppNil, Pretty(..)
+ )
+import PrimOp ( PrimOp(..) )
+import SpecUtils
+import Type ( mkTyVarTy, mkTyVarTys, isTyVarTy, getAppDataTyCon,
+ tyVarsOfTypes, applyTypeEnvToTy, isUnboxedType
+ )
+import TyCon ( TyCon{-instance Eq-} )
+import TyVar ( cloneTyVar,
+ elementOfTyVarSet, TyVarSet(..),
+ nullTyVarEnv, growTyVarEnvList, TyVarEnv(..),
+ GenTyVar{-instance Eq-}
+ )
+import Unique ( Unique{-instance Eq-} )
+import UniqSet ( mkUniqSet, unionUniqSets, uniqSetToList )
+import UniqSupply ( splitUniqSupply, getUniques, getUnique )
+import Util ( equivClasses, mapAccumL, assoc, zipWithEqual,
+ panic, pprTrace, pprPanic, assertPanic
+ )
infixr 9 `thenSM`
+
+--ToDo:kill
+data SpecInfo = SpecInfo [Maybe Type] Int Id
+
+addIdSpecialisation = panic "Specialise.addIdSpecialisation (ToDo)"
+cmpUniTypeMaybeList = panic "Specialise.cmpUniTypeMaybeList (ToDo)"
+getIdSpecialisation = panic "Specialise.getIdSpecialisation (ToDo)"
+isClassOpId = panic "Specialise.isClassOpId (ToDo)"
+isDictTy = panic "Specialise.isDictTy (ToDo)"
+isLocalGenTyCon = panic "Specialise.isLocalGenTyCon (ToDo)"
+isLocalSpecTyCon = panic "Specialise.isLocalSpecTyCon (ToDo)"
+isSpecId_maybe = panic "Specialise.isSpecId_maybe (ToDo)"
+isSpecPragmaId_maybe = panic "Specialise.isSpecPragmaId_maybe (ToDo)"
+lookupClassInstAtSimpleType = panic "Specialise.lookupClassInstAtSimpleType (ToDo)"
+lookupSpecEnv = panic "Specialise.lookupSpecEnv (ToDo)"
+mkPolySysTyVar = panic "Specialise.mkPolySysTyVar (ToDo)"
+mkSpecEnv = panic "Specialise.mkSpecEnv (ToDo)"
+mkSpecId = panic "Specialise.mkSpecId (ToDo)"
+selectIdInfoForSpecId = panic "Specialise.selectIdInfoForSpecId (ToDo)"
+specialiseTy = panic "Specialise.specialiseTy (ToDo)"
\end{code}
%************************************************************************
%************************************************************************
\begin{code}
-type FreeVarsSet = UniqSet Id
-type FreeTyVarsSet = UniqSet TyVar
+type FreeVarsSet = IdSet
+type FreeTyVarsSet = TyVarSet
data CallInstance
= CallInstance
- Id -- This Id; *new* ie *cloned* id
- [Maybe Type] -- Specialised at these types (*new*, cloned)
- -- Nothing => no specialisation on this type arg
- -- is required (flag dependent).
- [CoreArg] -- And these dictionaries; all ValArgs
- FreeVarsSet -- Free vars of the dict-args in terms of *new* ids
- (Maybe SpecInfo) -- For specialisation with explicit SpecId
+ Id -- This Id; *new* ie *cloned* id
+ [Maybe Type] -- Specialised at these types (*new*, cloned)
+ -- Nothing => no specialisation on this type arg
+ -- is required (flag dependent).
+ [CoreArg] -- And these dictionaries; all ValArgs
+ FreeVarsSet -- Free vars of the dict-args in terms of *new* ids
+ (Maybe SpecInfo) -- For specialisation with explicit SpecId
\end{code}
\begin{code}
= ppHang (ppCat [ppStr "Call inst for", ppr PprDebug id])
4 (ppAboves [ppCat (ppStr "types" : [pprMaybeTy PprDebug ty | ty <- spec_tys]),
case maybe_specinfo of
- Nothing -> ppCat (ppStr "dicts" : [ppr PprDebug dict | dict <- dicts])
+ Nothing -> ppCat (ppStr "dicts" : [ppr_arg PprDebug dict | dict <- dicts])
Just (SpecInfo _ _ spec_id)
-> ppCat [ppStr "Explicit SpecId", ppr PprDebug spec_id]
])
+-- ToDo: instance Outputable CoreArg?
+ppr_arg sty (TyArg t) = ppr sty t
+ppr_arg sty (LitArg i) = ppr sty i
+ppr_arg sty (VarArg v) = ppr sty v
+
isUnboxedCI :: CallInstance -> Bool
isUnboxedCI (CallInstance _ spec_tys _ _ _)
- = any isUnboxedDataType (catMaybes spec_tys)
+ = any isUnboxedType (catMaybes spec_tys)
isExplicitCI :: CallInstance -> Bool
isExplicitCI (CallInstance _ _ _ _ (Just _))
isCIofTheseIds :: [Id] -> CallInstance -> Bool
isCIofTheseIds ids (CallInstance ci_id _ _ _ _)
- = any (eqId ci_id) ids
+ = any ((==) ci_id) ids
singleCI :: Id -> [Maybe Type] -> [CoreArg] -> UsageDetails
singleCI id tys dicts
= UsageDetails (unitBag (CallInstance id tys dicts fv_set Nothing))
- emptyBag [] emptyUniqSet 0 0
+ emptyBag [] emptyIdSet 0 0
where
- fv_set = mkUniqSet (id : [dict | ValArg (VarArg dict) <- dicts])
+ fv_set = mkIdSet (id : [dict | (VarArg dict) <- dicts])
explicitCI :: Id -> [Maybe Type] -> SpecInfo -> UsageDetails
explicitCI id tys specinfo
- = UsageDetails (unitBag call_inst) emptyBag [] emptyUniqSet 0 0
+ = UsageDetails (unitBag call_inst) emptyBag [] emptyIdSet 0 0
where
call_inst = CallInstance id tys dicts fv_set (Just specinfo)
dicts = panic "Specialise:explicitCI:dicts"
- fv_set = singletonUniqSet id
+ fv_set = unitIdSet id
-- We do not process the CIs for top-level dfuns or defms
-- Instead we require an explicit SPEC inst pragma for dfuns
cis_here_list = bagToList cis_here
in
-- pprTrace "getCIs:"
- -- (ppHang (ppBesides [ppStr "{", ppr PprDebug ids, ppStr "}"])
+ -- (ppHang (ppBesides [ppStr "{",
+ -- interppSP PprDebug ids,
+ -- ppStr "}"])
-- 4 (ppAboves (map pprCI cis_here_list)))
(cis_here_list, UsageDetails cis_not_here tycon_cis dbs fvs c i)
then
pprTrace ("dumpCIs: dumping CI which was not instantiated ... \n" ++
" (may be a non-HM recursive call)\n")
- (ppHang (ppBesides [ppStr "{", ppr PprDebug bound_ids, ppStr "}"])
+ (ppHang (ppBesides [ppStr "{",
+ interppSP PprDebug bound_ids,
+ ppStr "}"])
4 (ppAboves [ppStr "Dumping CIs:",
ppAboves (map pprCI (bagToList cis_of_bound_id)),
ppStr "Instantiating CIs:",
else
(if not (isEmptyBag cis_dump_unboxed)
then pprTrace "dumpCIs: bound dictionary arg ... WITH UNBOXED TYPES!\n"
- (ppHang (ppBesides [ppStr "{", ppr PprDebug full_ids, ppStr "}"])
+ (ppHang (ppBesides [ppStr "{",
+ interppSP PprDebug full_ids,
+ ppStr "}"])
4 (ppAboves (map pprCI (bagToList cis_dump))))
else id)
cis_keep_not_bound_id
= partitionBag ok_to_dump_ci cis_not_bound_id
ok_to_dump_ci (CallInstance _ _ _ fv_set _)
- = or [i `elementOfUniqSet` fv_set | i <- full_ids]
+ = any (\ i -> i `elementOfIdSet` fv_set) full_ids
(_, cis_of_bound_id_without_inst_cis) = partitionBag have_inst_ci cis_of_bound_id
have_inst_ci ci = any (eqCI_tys ci) inst_cis
singleTyConI :: TyCon -> [Maybe Type] -> UsageDetails
singleTyConI ty_con spec_tys
- = UsageDetails emptyBag (unitBag (TyConInstance ty_con spec_tys)) [] emptyUniqSet 0 0
+ = UsageDetails emptyBag (unitBag (TyConInstance ty_con spec_tys)) [] emptyIdSet 0 0
isTyConIofThisTyCon :: TyCon -> TyConInstance -> Bool
-isTyConIofThisTyCon ty_con (TyConInstance inst_ty_con _) = eqTyCon ty_con inst_ty_con
+isTyConIofThisTyCon ty_con (TyConInstance inst_ty_con _) = ty_con == inst_ty_con
isLocalSpecTyConI :: Bool -> TyConInstance -> Bool
isLocalSpecTyConI comp_prel (TyConInstance inst_ty_con _) = isLocalSpecTyCon comp_prel inst_ty_con
tickSpecInsts (UsageDetails cis ty_cis dbs fvs c i)
= UsageDetails cis ty_cis dbs fvs c (i+1)
-emptyUDs = UsageDetails emptyBag emptyBag [] emptyUniqSet 0 0
+emptyUDs = UsageDetails emptyBag emptyBag [] emptyIdSet 0 0
unionUDs (UsageDetails cis1 tycon_cis1 dbs1 fvs1 c1 i1) (UsageDetails cis2 tycon_cis2 dbs2 fvs2 c2 i2)
= UsageDetails (unionBags cis1 cis2) (unionBags tycon_cis1 tycon_cis2)
- (dbs1 ++ dbs2) (fvs1 `unionUniqSets` fvs2) (c1+c2) (i1+i2)
+ (dbs1 ++ dbs2) (fvs1 `unionIdSets` fvs2) (c1+c2) (i1+i2)
-- The append here is really redundant, since the bindings don't
-- scope over each other. ToDo.
unionUDList = foldr unionUDs emptyUDs
singleFvUDs (VarArg v) | not (isImportedId v)
- = UsageDetails emptyBag emptyBag [] (singletonUniqSet v) 0 0
+ = UsageDetails emptyBag emptyBag [] (unitIdSet v) 0 0
singleFvUDs other
= emptyUDs
-singleConUDs con = UsageDetails emptyBag emptyBag [] (singletonUniqSet con) 0 0
+singleConUDs con = UsageDetails emptyBag emptyBag [] (unitIdSet con) 0 0
dumpDBs :: [DictBindDetails]
-> Bool -- True <=> top level bound Ids
dumpDBs ((db@(DictBindDetails dbinders dbind db_fvs db_ftv)):dbs)
top_lev bound_tyvars bound_ids fvs
| top_lev
- || or [i `elementOfUniqSet` db_fvs | i <- bound_ids]
- || or [tv `elementOfUniqSet` db_ftv | tv <- bound_tyvars]
+ || any (\ i -> i `elementOfIdSet` db_fvs) bound_ids
+ || any (\ t -> t `elementOfTyVarSet` db_ftv) bound_tyvars
= let -- Ha! Dump it!
(dbinds_here, dbs_outer, full_bound_ids, full_fvs)
- = dumpDBs dbs top_lev bound_tyvars (dbinders ++ bound_ids) (db_fvs `unionUniqSets` fvs)
+ = dumpDBs dbs top_lev bound_tyvars (dbinders ++ bound_ids) (db_fvs `unionIdSets` fvs)
in
(dbind : dbinds_here, dbs_outer, full_bound_ids, full_fvs)
(dict_binds_here, dbs_outer, full_bound_ids, full_fvs)
= dumpDBs dbs top_lev tvs bound_ids fvs
cis_outer = dumpCIs cis top_lev floating inst_cis bound_ids full_bound_ids
- fvs_outer = full_fvs `minusUniqSet` (mkUniqSet full_bound_ids)
+ fvs_outer = full_fvs `minusIdSet` (mkIdSet full_bound_ids)
in
(dict_binds_here, UsageDetails cis_outer tycon_cis dbs_outer fvs_outer c i)
\end{code}
%************************************************************************
\begin{code}
-specProgram :: (GlobalSwitch -> Bool)
- -> UniqSupply
+specProgram :: UniqSupply
-> [CoreBinding] -- input ...
-> SpecialiseData
-> ([CoreBinding], -- main result
SpecialiseData) -- result specialise data
-specProgram sw_chker uniqs binds
+specProgram uniqs binds
(SpecData False _ local_tycons _ init_specs init_errs init_warn init_tyerrs)
- = case (initSM (specTyConsAndScope (specTopBinds binds)) sw_chker uniqs) of
+ = case (initSM (specTyConsAndScope (specTopBinds binds)) uniqs) of
(final_binds, tycon_specs_list,
UsageDetails import_cis import_tycis _ fvs spec_calls spec_insts)
-> let
used_conids = filter isDataCon (uniqSetToList fvs)
- used_tycons = map getDataConTyCon used_conids
+ used_tycons = map dataConTyCon used_conids
used_gen = filter isLocalGenTyCon used_tycons
- gen_tycons = setToList (mkSet local_tycons `union` mkSet used_gen)
+ gen_tycons = uniqSetToList (mkUniqSet local_tycons `unionUniqSets` mkUniqSet used_gen)
result_specs = addListToFM_C (++) init_specs tycon_specs_list
tycis_errs = init_tyerrs `unionBags` listToBag tycis_unboxed
no_errs = isEmptyBag cis_errs && isEmptyBag tycis_errs
- && (not (sw_chker SpecialiseImports) || isEmptyBag cis_warn)
+ && (not opt_SpecialiseImports || isEmptyBag cis_warn)
in
- (if sw_chker D_simplifier_stats then
+ (if opt_D_simplifier_stats then
pprTrace "\nSpecialiser Stats:\n" (ppAboves [
ppBesides [ppStr "SpecCalls ", ppInt spec_calls],
ppBesides [ppStr "SpecInsts ", ppInt spec_insts],
SpecData True no_errs local_tycons gen_tycons result_specs
cis_errs cis_warn tycis_errs)
-specProgram sw_chker uniqs binds (SpecData True _ _ _ _ _ _ _)
+specProgram uniqs binds (SpecData True _ _ _ _ _ _ _)
= panic "Specialise:specProgram: specialiser called more than once"
-- It may be possible safely to call the specialiser more than once,
specTyConsAndScope scopeM
= scopeM `thenSM` \ (binds, scope_uds) ->
- getSwitchCheckerSM `thenSM` \ sw_chkr ->
let
(tycons_cis, gotci_scope_uds)
- = getLocalSpecTyConIs (sw_chkr CompilingPrelude) scope_uds
+ = getLocalSpecTyConIs opt_CompilingPrelude scope_uds
tycon_specs_list = collectTyConSpecs tycons_cis
in
- (if sw_chkr SpecialiseTrace && not (null tycon_specs_list) then
+ (if opt_SpecialiseTrace && not (null tycon_specs_list) then
pprTrace "Specialising TyCons:\n"
(ppAboves [ if not (null specs) then
ppHang (ppCat [(ppr PprDebug tycon), ppStr "at types"])
(dbinders_s, dbinds, dfvs_s)
= unzip3 [(dbinders, dbind, dfvs) | DictBindDetails dbinders dbind dfvs _ <- dbind_details]
- full_fvs = fvs `unionUniqSets` unionManyUniqSets dfvs_s
- fvs_outer = full_fvs `minusUniqSet` (mkUniqSet (concat dbinders_s))
+ full_fvs = fvs `unionIdSets` unionManyIdSets dfvs_s
+ fvs_outer = full_fvs `minusIdSet` (mkIdSet (concat dbinders_s))
-- It is just to complex to try to sort out top-level dependencies
-- So we just place all the top-level binds in a *global* Rec and
\begin{code}
specExpr :: CoreExpr
-> [CoreArg] -- The arguments:
- -- TypeArgs are speced
- -- ValArgs are unprocessed
+ -- TypeArgs are speced
+ -- ValArgs are unprocessed
-> SpecM (CoreExpr, -- Result expression with specialised versions installed
- UsageDetails) -- Details of usage of enclosing binders in the result
- -- expression.
+ UsageDetails)-- Details of usage of enclosing binders in the result
+ -- expression.
specExpr (Var v) args
= lookupId v `thenSM` \ vlookup ->
returnSM (bindUnlift vl vu (Var vu), singleFvUDs (VarArg vl))
NoLift vatom@(VarArg new_v)
- -> mapSM specArg args `thenSM` \ arg_info ->
+ -> mapSM specOutArg args `thenSM` \ arg_info ->
mkCallInstance v new_v arg_info `thenSM` \ call_uds ->
mkCall new_v arg_info `thenSM` \ ~(speced, call) ->
let
= ASSERT (null null_args)
returnSM (expr, emptyUDs)
-specExpr (Con con tys args) null_args
+specExpr (Con con args) null_args
= ASSERT (null null_args)
- mapSM specTy tys `thenSM` \ tys ->
- mapAndUnzip3SM specAtom args `thenSM` \ (args, args_uds_s, unlifts) ->
- mkTyConInstance con tys `thenSM` \ con_uds ->
- returnSM (applyBindUnlifts unlifts (Con con tys args),
+ let
+ (targs, vargs) = partition_args args
+ in
+ mapAndUnzipSM specTyArg targs `thenSM` \ (targs, tys) ->
+ mapAndUnzip3SM specValArg vargs `thenSM` \ (vargs, args_uds_s, unlifts) ->
+ mkTyConInstance con tys `thenSM` \ con_uds ->
+ returnSM (applyBindUnlifts unlifts (Con con (targs ++ vargs)),
unionUDList args_uds_s `unionUDs` con_uds)
-specExpr (Prim op@(CCallOp str is_asm may_gc arg_tys res_ty) tys args) null_args
+specExpr (Prim op@(CCallOp str is_asm may_gc arg_tys res_ty) args) null_args
= ASSERT (null null_args)
- ASSERT (null tys)
- mapSM specTy arg_tys `thenSM` \ arg_tys ->
- specTy res_ty `thenSM` \ res_ty ->
- mapAndUnzip3SM specAtom args `thenSM` \ (args, args_uds_s, unlifts) ->
- returnSM (applyBindUnlifts unlifts (Prim (CCallOp str is_asm may_gc arg_tys res_ty) tys args),
+ let
+ (targs, vargs) = partition_args args
+ in
+ ASSERT (null targs)
+ mapSM specTy arg_tys `thenSM` \ arg_tys ->
+ specTy res_ty `thenSM` \ res_ty ->
+ mapAndUnzip3SM specValArg vargs `thenSM` \ (vargs, args_uds_s, unlifts) ->
+ returnSM (applyBindUnlifts unlifts (Prim (CCallOp str is_asm may_gc arg_tys res_ty) vargs),
unionUDList args_uds_s)
-specExpr (Prim prim tys args) null_args
+specExpr (Prim prim args) null_args
= ASSERT (null null_args)
- mapSM specTy tys `thenSM` \ tys ->
- mapAndUnzip3SM specAtom args `thenSM` \ (args, args_uds_s, unlifts) ->
+ let
+ (targs, vargs) = partition_args args
+ in
+ mapAndUnzipSM specTyArg targs `thenSM` \ (targs, tys) ->
+ mapAndUnzip3SM specValArg vargs `thenSM` \ (vargs, args_uds_s, unlifts) ->
-- specPrimOp prim tys `thenSM` \ (prim, tys, prim_uds) ->
- returnSM (applyBindUnlifts unlifts (Prim prim tys args),
+ returnSM (applyBindUnlifts unlifts (Prim prim (targs ++ vargs)),
unionUDList args_uds_s {-`unionUDs` prim_uds-} )
{- ToDo: specPrimOp
specExpr (App fun arg) args
- = -- Arg is passed on unprocessed
- specExpr fun (ValArg arg : args) `thenSM` \ (expr,uds) ->
+ = -- If TyArg, arg will be processed; otherwise, left alone
+ preSpecArg arg `thenSM` \ new_arg ->
+ specExpr fun (new_arg : args) `thenSM` \ (expr,uds) ->
returnSM (expr, uds)
-specExpr (CoTyApp fun ty) args
- = -- Spec the tyarg and pass it on
- specTy ty `thenSM` \ ty ->
- specExpr fun (TypeArg ty : args)
-
-specExpr (Lam binder body) (ValArg arg : args)
+specExpr (Lam (ValBinder binder) body) (arg : args) | isValArg arg
= lookup_arg arg `thenSM` \ arg ->
bindId binder arg (specExpr body args)
where
lookup_arg (LitArg l) = returnSM (NoLift (LitArg l))
lookup_arg (VarArg v) = lookupId v
-specExpr (Lam binder body) []
+specExpr (Lam (ValBinder binder) body) []
= specLambdaOrCaseBody [binder] body [] `thenSM` \ ([binder], body, uds) ->
- returnSM (Lam binder body, uds)
+ returnSM (Lam (ValBinder binder) body, uds)
-specExpr (CoTyLam tyvar body) (TypeArg ty : args)
+specExpr (Lam (TyBinder tyvar) body) (TyArg ty : args)
= -- Type lambda with argument; argument already spec'd
- bindTyVar tyvar ty (
- specExpr body args
- )
+ bindTyVar tyvar ty ( specExpr body args )
-specExpr (CoTyLam tyvar body) []
+specExpr (Lam (TyBinder tyvar) body) []
= -- No arguments
cloneTyVarSM tyvar `thenSM` \ new_tyvar ->
bindTyVar tyvar (mkTyVarTy new_tyvar) (
let
(binds_here, final_uds) = dumpUDs body_uds False False [] [] [new_tyvar]
in
- returnSM (CoTyLam new_tyvar (mkCoLetsNoUnboxed binds_here body), final_uds)
+ returnSM (Lam (TyBinder new_tyvar)
+ (mkCoLetsNoUnboxed binds_here body),
+ final_uds)
)
specExpr (Case scrutinee alts) args
where
scrutinee_type = coreExprType scrutinee
-
specExpr (Let bind body) args
= specBindAndScope False bind (
specExpr body args `thenSM` \ (body, body_uds) ->
returnSM (mkCoLetsUnboxedToCase binds body, all_uds)
specExpr (SCC cc expr) args
- = specExpr expr [] `thenSM` \ (expr, expr_uds) ->
- mapAndUnzip3SM specArg args `thenSM` \ (args, args_uds_s, unlifts) ->
+ = specExpr expr [] `thenSM` \ (expr, expr_uds) ->
+ mapAndUnzip3SM specOutArg args `thenSM` \ (args, args_uds_s, unlifts) ->
let
scc_expr
= if squashableDictishCcExpr cc expr -- can toss the _scc_
meth1 at {Int#}. But since meth1 was extracted from a dictionary we do
not have access to its code to create the specialised version.
-
If we specialise on overloaded types as well we specialise op1 at
{Int Int#} d.Foo.Int:
specDeflt deflt args `thenSM` \ (deflt, deflt_uds) ->
returnSM (AlgAlts alts deflt,
unionUDList alts_uds_s `unionUDs` deflt_uds)
-
where
- -- We use ty_args of scrutinee type to identify specialisation of alternatives
+ -- We use ty_args of scrutinee type to identify specialisation of
+ -- alternatives:
+
(_, ty_args, _) = getAppDataTyCon scrutinee_ty
specAlgAlt ty_args (con,binders,rhs)
%************************************************************************
\begin{code}
-specAtom :: CoreArg -> SpecM (CoreArg, UsageDetails,
- CoreExpr -> CoreExpr)
+partition_args :: [CoreArg] -> ([CoreArg], [CoreArg])
+partition_args args
+ = span is_ty_arg args
+ where
+ is_ty_arg (TyArg _) = True
+ is_ty_arg _ = False
+
+----------
+preSpecArg :: CoreArg -> SpecM CoreArg -- diddle TyArgs, but nothing else
-specAtom (LitArg lit)
+preSpecArg (TyArg ty)
+ = specTy ty `thenSM` \ new_ty ->
+ returnSM (TyArg new_ty)
+
+preSpecArg other = returnSM other
+
+--------------------
+specValArg :: CoreArg -> SpecM (CoreArg, UsageDetails,
+ CoreExpr -> CoreExpr)
+
+specValArg (LitArg lit)
= returnSM (LitArg lit, emptyUDs, id)
-specAtom (VarArg v)
+specValArg (VarArg v)
= lookupId v `thenSM` \ vlookup ->
case vlookup of
Lifted vl vu
-> returnSM (vatom, singleFvUDs vatom, id)
-specArg :: CoreArg -> SpecM (CoreArg, UsageDetails,
+------------------
+specTyArg (TyArg ty)
+ = specTy ty `thenSM` \ new_ty ->
+ returnSM (TyArg new_ty, new_ty)
+
+--------------
+specOutArg :: CoreArg -> SpecM (CoreArg, UsageDetails,
CoreExpr -> CoreExpr)
-specArg (ValArg arg) -- unprocessed; spec the atom
- = specAtom arg `thenSM` \ (arg, uds, unlift) ->
- returnSM (ValArg arg, uds, unlift)
+specOutArg (TyArg ty) -- already speced; no action
+ = returnSM (TyArg ty, emptyUDs, id)
-specArg (TypeArg ty) -- already speced; no action
- = returnSM (TypeArg ty, emptyUDs, id)
+specOutArg other_arg -- unprocessed; spec the atom
+ = specValArg other_arg
\end{code}
else if top_lev
then pprTrace "dumpCIs: not same overloading ... top level \n"
else (\ x y -> y)
- ) (ppHang (ppBesides [ppStr "{", ppr PprDebug new_ids, ppStr "}"])
- 4 (ppAboves [ppAboves (map (pprType PprDebug . idType) new_ids),
+ ) (ppHang (ppBesides [ppStr "{",
+ interppSP PprDebug new_ids,
+ ppStr "}"])
+ 4 (ppAboves [ppAboves (map (pprGenType PprDebug . idType) new_ids),
ppAboves (map pprCI (concat equiv_ciss))]))
(returnSM ([], emptyUDs, []))
where
(tyvar_tmpls, class_tyvar_pairs) = getIdOverloading first_binder
- tyvar_tmpl_tys = map mkTyVarTemplateTy tyvar_tmpls
+ tyvar_tmpl_tys = mkTyVarTys tyvar_tmpls
no_of_tyvars = length tyvar_tmpls
no_of_dicts = length class_tyvar_pairs
mkOneInst do_cis@(CallInstance _ spec_tys dict_args _ _) explicit_cis
no_of_dicts_to_specialise top_lev inst_cis new_ids orig_bind
- = getSwitchCheckerSM `thenSM` \ sw_chkr ->
- newSpecIds new_ids spec_tys no_of_dicts_to_specialise
+ = newSpecIds new_ids spec_tys no_of_dicts_to_specialise
`thenSM` \ spec_ids ->
newTyVars (length [() | Nothing <- spec_tys]) `thenSM` \ poly_tyvars ->
let
(_,arg_tys) = mapAccumL do_the_wotsit poly_tyvars spec_tys
args :: [CoreArg]
- args = map TypeArg arg_tys ++ dict_args
+ args = map TyArg arg_tys ++ dict_args
(new_id:_) = new_ids
(spec_id:_) = spec_ids
-- a specialised instance has been created but specialisation
-- "required" by one of the other Ids in the Rec
| top_lev && maybeToBool lookup_orig_spec
- = (if sw_chkr SpecialiseTrace
+ = (if opt_SpecialiseTrace
then trace_nospec " Exists: " exists_id
else id) (
-- Check for a (single) explicit call instance for this id
| not (null explicit_cis_for_this_id)
= ASSERT (length explicit_cis_for_this_id == 1)
- (if sw_chkr SpecialiseTrace
+ (if opt_SpecialiseTrace
then trace_nospec " Explicit: " explicit_id
else id) (
spec_info = Just (SpecInfo spec_tys no_of_dicts_to_specialise spec_id)
in
- if isUnboxedDataType (idType spec_id) then
+ if isUnboxedType (idType spec_id) then
ASSERT (null poly_tyvars)
liftId spec_id `thenSM` \ (lift_spec_id, unlift_spec_id) ->
mkTyConInstance liftDataCon [idType unlift_spec_id]
tickSpecInsts (final_uds `unionUDs` lift_uds), spec_info)
else
returnSM (Just (spec_id,
- mkCoLetsNoUnboxed local_dict_binds (mkCoTyLam poly_tyvars inst_rhs)),
+ mkCoLetsNoUnboxed local_dict_binds (mkTyLam poly_tyvars inst_rhs)),
tickSpecInsts final_uds, spec_info)
where
lookup_orig_spec = lookupSpecEnv (getIdSpecialisation orig_id) arg_tys
[CallInstance _ _ _ _ (Just explicit_spec_info)] = explicit_cis_for_this_id
SpecInfo _ _ explicit_id = explicit_spec_info
+ trace_nospec :: String -> Id -> a -> a
trace_nospec str spec_id
= pprTrace str
(ppCat [ppr PprDebug new_id, ppInterleave ppNil (map pp_ty arg_tys),
ppStr "==>", ppr PprDebug spec_id])
in
- (if sw_chkr SpecialiseTrace then
+ (if opt_SpecialiseTrace then
pprTrace "Specialising:"
- (ppHang (ppBesides [ppStr "{", ppr PprDebug new_ids, ppStr "}"])
+ (ppHang (ppBesides [ppStr "{",
+ interppSP PprDebug new_ids,
+ ppStr "}"])
4 (ppAboves [
ppBesides [ppStr "types: ", ppInterleave ppNil (map pp_ty arg_tys)],
if isExplicitCI do_cis then ppNil else
returnSM (maybe_inst_bind, inst_uds, spec_infos)
)
where
- pp_dict (ValArg d) = ppr PprDebug d
- pp_ty t = pprParendType PprDebug t
+ pp_dict d = ppr_arg PprDebug d
+ pp_ty t = pprParendGenType PprDebug t
do_the_wotsit (tyvar:tyvars) Nothing = (tyvars, mkTyVarTy tyvar)
do_the_wotsit tyvars (Just ty) = (tyvars, ty)
-- instances for a ConstMethodId extracted from its SpecEnv
| otherwise
- = getSwitchCheckerSM `thenSM` \ sw_chkr ->
- let
- spec_overloading = sw_chkr SpecialiseOverloaded
- spec_unboxed = sw_chkr SpecialiseUnboxed
- spec_all = sw_chkr SpecialiseAll
+ = let
+ spec_overloading = opt_SpecialiseOverloaded
+ spec_unboxed = opt_SpecialiseUnboxed
+ spec_all = opt_SpecialiseAll
(tyvars, class_tyvar_pairs) = getIdOverloading id
in
if (not enough_args) then
pprPanic "Specialise:recordCallInst: Unsaturated Type & Dict Application:\n\t"
- (ppCat [ppr PprDebug id, ppr PprDebug [arg | (arg,_,_) <- args] ])
+ (ppCat (ppr PprDebug id : map (ppr_arg PprDebug) [arg | (arg,_,_) <- args]))
else
case record_spec id tys of
(False, _, _)
(returnSM emptyUDs)
-take_type_args (_:tyvars) class_tyvar_pairs ((TypeArg ty,_,_):args)
- = case take_type_args tyvars class_tyvar_pairs args of
- Nothing -> Nothing
- Just (tys, dicts, others) -> Just (ty:tys, dicts, others)
-take_type_args (_:tyvars) class_tyvar_pairs []
- = Nothing
+take_type_args (_:tyvars) class_tyvar_pairs ((TyArg ty,_,_):args)
+ = case (take_type_args tyvars class_tyvar_pairs args) of
+ Nothing -> Nothing
+ Just (tys, dicts, others) -> Just (ty:tys, dicts, others)
+
+take_type_args (_:tyvars) class_tyvar_pairs [] = Nothing
+
take_type_args [] class_tyvar_pairs args
- = case take_dict_args class_tyvar_pairs args of
- Nothing -> Nothing
- Just (dicts, others) -> Just ([], dicts, others)
-
-take_dict_args (_:class_tyvar_pairs) ((dict@(ValArg _),_,_):args)
- = case take_dict_args class_tyvar_pairs args of
- Nothing -> Nothing
- Just (dicts, others) -> Just (dict:dicts, others)
-take_dict_args (_:class_tyvar_pairs) []
- = Nothing
-take_dict_args [] args
- = Just ([], args)
+ = case (take_dict_args class_tyvar_pairs args) of
+ Nothing -> Nothing
+ Just (dicts, others) -> Just ([], dicts, others)
+
+take_dict_args (_:class_tyvar_pairs) ((dict,_,_):args) | isValArg dict
+ = case (take_dict_args class_tyvar_pairs args) of
+ Nothing -> Nothing
+ Just (dicts, others) -> Just (dict:dicts, others)
+
+take_dict_args (_:class_tyvar_pairs) [] = Nothing
+
+take_dict_args [] args = Just ([], args)
\end{code}
\begin{code}
mkCall new_id args
| maybeToBool (isSuperDictSelId_maybe new_id)
- && any isUnboxedDataType ty_args
+ && any isUnboxedType ty_args
-- No specialisations for super-dict selectors
-- Specialise unboxed calls to SuperDictSelIds by extracting
-- the super class dictionary directly form the super class
-- These top level defns should have been lifted.
-- We must add code to unlift such a spec_id.
- if isUnboxedDataType (idType spec_id) then
+ if isUnboxedType (idType spec_id) then
ASSERT (null tys_left && null args_left)
if toplevelishId spec_id then
liftId spec_id `thenSM` \ (lift_spec_id, unlift_spec_id) ->
else
pprPanic "Specialise:mkCall: unboxed spec_id not top-level ...\n"
(ppCat [ppr PprDebug new_id,
- ppInterleave ppNil (map (pprParendType PprDebug) ty_args),
+ ppInterleave ppNil (map (pprParendGenType PprDebug) ty_args),
ppStr "==>",
ppr PprDebug spec_id])
else
let
(vals_left, _, unlifts_left) = unzip3 args_left
- applied_tys = mkCoTyApps (Var spec_id) tys_left
+ applied_tys = mkTyApp (Var spec_id) tys_left
applied_vals = mkGenApp applied_tys vals_left
in
returnSM (True, applyBindUnlifts unlifts_left applied_vals)
(ty_args, val_args) = get args
where
- get ((TypeArg ty,_,_) : args) = (ty : tys, rest) where (tys,rest) = get args
- get args = ([], args)
+ get ((TyArg ty,_,_) : args) = (ty : tys, rest) where (tys,rest) = get args
+ get args = ([], args)
-- toss_dicts chucks away dict args, checking that they ain't types!
- toss_dicts 0 args = args
- toss_dicts n ((ValArg _,_,_) : args) = toss_dicts (n-1) args
+ toss_dicts 0 args = args
+ toss_dicts n ((a,_,_) : args)
+ | isValArg a = toss_dicts (n-1) args
\end{code}
\begin{code}
checkUnspecOK :: Id -> [Type] -> a -> a
checkUnspecOK check_id tys
- = if isLocallyDefined check_id && any isUnboxedDataType tys
+ = if isLocallyDefined check_id && any isUnboxedType tys
then pprPanic "Specialise:checkUnspecOK: unboxed instance for local id not found\n"
(ppCat [ppr PprDebug check_id,
- ppInterleave ppNil (map (pprParendType PprDebug) tys)])
+ ppInterleave ppNil (map (pprParendGenType PprDebug) tys)])
else id
checkSpecOK :: Id -> [Type] -> Id -> [Type] -> a -> a
checkSpecOK check_id tys spec_id tys_left
- = if any isUnboxedDataType tys_left
+ = if any isUnboxedType tys_left
then pprPanic "Specialise:checkSpecOK: unboxed type args in specialised application\n"
(ppAboves [ppCat [ppr PprDebug check_id,
- ppInterleave ppNil (map (pprParendType PprDebug) tys)],
+ ppInterleave ppNil (map (pprParendGenType PprDebug) tys)],
ppCat [ppr PprDebug spec_id,
- ppInterleave ppNil (map (pprParendType PprDebug) tys_left)]])
+ ppInterleave ppNil (map (pprParendGenType PprDebug) tys_left)]])
else id
\end{code}
-- ppStr ")"]])
(returnSM (singleTyConI tycon spec_tys `unionUDs` singleConUDs con))
where
- tycon = getDataConTyCon con
+ tycon = dataConTyCon con
\end{code}
\begin{code}
threaded in and out: unique supply
\begin{code}
+type TypeEnv = TyVarEnv Type
+
type SpecM result
- = (GlobalSwitch -> Bool)
- -> TypeEnv
+ = TypeEnv
-> SpecIdEnv
-> UniqSupply
-> result
-initSM m sw_chker uniqs
- = m sw_chker nullTyVarEnv nullIdEnv uniqs
+initSM m uniqs
+ = m nullTyVarEnv nullIdEnv uniqs
returnSM :: a -> SpecM a
thenSM :: SpecM a -> (a -> SpecM b) -> SpecM b
fixSM :: (a -> SpecM a) -> SpecM a
-thenSM m k sw_chkr tvenv idenv us
+thenSM m k tvenv idenv us
= case splitUniqSupply us of { (s1, s2) ->
- case (m sw_chkr tvenv idenv s1) of { r ->
- k r sw_chkr tvenv idenv s2 }}
+ case (m tvenv idenv s1) of { r ->
+ k r tvenv idenv s2 }}
-returnSM r sw_chkr tvenv idenv us = r
+returnSM r tvenv idenv us = r
-fixSM k sw_chkr tvenv idenv us
+fixSM k tvenv idenv us
= r
where
- r = k r sw_chkr tvenv idenv us -- Recursive in r!
-\end{code}
-
-\begin{code}
-getSwitchCheckerSM sw_chkr tvenv idenv us = sw_chkr
+ r = k r tvenv idenv us -- Recursive in r!
\end{code}
The only interesting bit is figuring out the type of the SpecId!
-> Int -- No of dicts to specialise
-> SpecM [Id]
-newSpecIds new_ids maybe_tys dicts_to_ignore sw_chkr tvenv idenv us
+newSpecIds new_ids maybe_tys dicts_to_ignore tvenv idenv us
= [ mkSpecId uniq id maybe_tys (spec_id_ty id) (selectIdInfoForSpecId id)
| (id,uniq) <- new_ids `zip` uniqs ]
where
spec_id_ty id = specialiseTy (idType id) maybe_tys dicts_to_ignore
newTyVars :: Int -> SpecM [TyVar]
-newTyVars n sw_chkr tvenv idenv us
+newTyVars n tvenv idenv us
= map mkPolySysTyVar uniqs
where
uniqs = getUniques n us
cloneLambdaOrCaseBinders :: [Id] -- Old binders
-> SpecM ([Id], [CloneInfo]) -- New ones
-cloneLambdaOrCaseBinders old_ids sw_chkr tvenv idenv us
+cloneLambdaOrCaseBinders old_ids tvenv idenv us
= let
uniqs = getUniques (length old_ids) us
in
-> [Id] -- Old binders
-> SpecM ([Id], [CloneInfo]) -- New ones
-cloneLetBinders top_lev is_rec old_ids sw_chkr tvenv idenv us
+cloneLetBinders top_lev is_rec old_ids tvenv idenv us
= let
uniqs = getUniques (2 * length old_ids) us
in
-- (c) the thing is polymorphic so no need to subst
| otherwise
- = if (is_rec && isUnboxedDataType new_ty && not (isUnboxedDataType old_ty))
+ = if (is_rec && isUnboxedType new_ty && not (isUnboxedType old_ty))
then (lifted_id,
Lifted lifted_id unlifted_id) : clone_rest
else (new_id,
cloneTyVarSM :: TyVar -> SpecM TyVar
-cloneTyVarSM old_tyvar sw_chkr tvenv idenv us
+cloneTyVarSM old_tyvar tvenv idenv us
= let
uniq = getUnique us
in
bindId :: Id -> CloneInfo -> SpecM thing -> SpecM thing
-bindId id val specm sw_chkr tvenv idenv us
- = specm sw_chkr tvenv (addOneToIdEnv idenv id val) us
+bindId id val specm tvenv idenv us
+ = specm tvenv (addOneToIdEnv idenv id val) us
bindIds :: [Id] -> [CloneInfo] -> SpecM thing -> SpecM thing
-bindIds olds news specm sw_chkr tvenv idenv us
- = specm sw_chkr tvenv (growIdEnvList idenv (zip olds news)) us
+bindIds olds news specm tvenv idenv us
+ = specm tvenv (growIdEnvList idenv (zip olds news)) us
bindSpecIds :: [Id] -- Old
-> [(CloneInfo)] -- New
-> SpecM thing
-> SpecM thing
-bindSpecIds olds clones spec_infos specm sw_chkr tvenv idenv us
- = specm sw_chkr tvenv (growIdEnvList idenv old_to_clone) us
+bindSpecIds olds clones spec_infos specm tvenv idenv us
+ = specm tvenv (growIdEnvList idenv old_to_clone) us
where
old_to_clone = mk_old_to_clone olds clones spec_infos
bindTyVar :: TyVar -> Type -> SpecM thing -> SpecM thing
-bindTyVar tyvar ty specm sw_chkr tvenv idenv us
- = specm sw_chkr (growTyVarEnvList tvenv [(tyvar,ty)]) idenv us
+bindTyVar tyvar ty specm tvenv idenv us
+ = specm (growTyVarEnvList tvenv [(tyvar,ty)]) idenv us
\end{code}
\begin{code}
lookupId :: Id -> SpecM CloneInfo
-lookupId id sw_chkr tvenv idenv us
+lookupId id tvenv idenv us
= case lookupIdEnv idenv id of
Nothing -> NoLift (VarArg id)
Just info -> info
\begin{code}
specTy :: Type -> SpecM Type -- Apply the current type envt to the type
-specTy ty sw_chkr tvenv idenv us
+specTy ty tvenv idenv us
= applyTypeEnvToTy tvenv ty
\end{code}
\begin{code}
liftId :: Id -> SpecM (Id, Id)
-liftId id sw_chkr tvenv idenv us
+liftId id tvenv idenv us
= let
uniq = getUnique us
in
\begin{code}
#include "HsVersions.h"
-module CoreToStg (
- topCoreBindsToStg
+module CoreToStg ( topCoreBindsToStg ) where
- -- and to make the interface self-sufficient...
- ) where
+import Ubiq{-uitous-}
-import AnnCoreSyn -- intermediate form on which all work is done
+import CoreSyn -- input
import StgSyn -- output
-import UniqSupply
+import Bag ( emptyBag, unitBag, unionBags, unionManyBags, bagToList )
+import CoreUtils ( coreExprType )
+import CostCentre ( noCostCentre )
+import Id ( mkSysLocal, idType, isBottomingId,
+ nullIdEnv, addOneToIdEnv, lookupIdEnv,
+ IdEnv(..), GenId{-instance NamedThing-}
+ )
+import Literal ( mkMachInt, Literal(..) )
+import Outputable ( isExported )
import PrelInfo ( unpackCStringId, unpackCString2Id, stringTy,
integerTy, rationalTy, ratioDataCon,
- PrimOp(..), -- For Int2IntegerOp etc
integerZeroId, integerPlusOneId,
integerPlusTwoId, integerMinusOneId
- IF_ATTACK_PRAGMAS(COMMA mkListTy COMMA charTy)
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-
-import Type ( isPrimType, isLeakFreeType, getAppDataTyCon )
-import Bag -- Bag operations
-import Literal ( mkMachInt, Literal(..) ) -- ToDo: its use is ugly...
-import CostCentre ( noCostCentre, CostCentre )
-import Id ( mkSysLocal, idType, isBottomingId
- IF_ATTACK_PRAGMAS(COMMA bottomIsGuaranteed)
)
-import Maybes ( Maybe(..), catMaybes )
-import Outputable ( isExported )
-import Pretty -- debugging only!
+import PrimOp ( PrimOp(..) )
import SpecUtils ( mkSpecialisedCon )
-import SrcLoc ( SrcLoc, mkUnknownSrcLoc )
-import Util
+import SrcLoc ( mkUnknownSrcLoc )
+import Type ( getAppDataTyCon )
+import UniqSupply -- all of it, really
+import Util ( panic )
+
+isLeakFreeType = panic "CoreToStg.isLeakFreeType (ToDo)"
\end{code}
%************************************************************************
\begin{code}
-coreAtomToStg :: StgEnv -> CoreArg -> UniqSM (StgArg, Bag StgBinding)
+coreArgsToStg :: StgEnv -> [CoreArg] -> UniqSM ([Type], [StgArg], Bag StgBinding)
-coreAtomToStg env (VarArg var) = returnUs (stgLookup env var, emptyBag)
-coreAtomToStg env (LitArg lit) = litToStgArg lit
+coreArgsToStg env [] = returnUs ([], [], emptyBag)
+coreArgsToStg env (a:as)
+ = coreArgsToStg env as `thenUs` \ (tys, args, binds) ->
+ do_arg a tys args binds
+ where
+ do_arg a trest vrest binds
+ = case a of
+ TyArg t -> returnUs (t:trest, vrest, binds)
+ UsageArg u -> returnUs (trest, vrest, binds)
+ VarArg v -> returnUs (trest, stgLookup env v : vrest, binds)
+ LitArg i -> litToStgArg i `thenUs` \ (v, bs) ->
+ returnUs (trest, v:vrest, bs `unionBags` binds)
\end{code}
There's not anything interesting we can ASSERT about \tr{var} if it
coreExprToStg env (Var var)
= returnUs (StgApp (stgLookup env var) [] bOGUS_LVs, emptyBag)
-coreExprToStg env (Con con types args)
- = mapAndUnzipUs (coreAtomToStg env) args `thenUs` \ (stg_atoms, stg_binds) ->
- returnUs (StgCon spec_con stg_atoms bOGUS_LVs, unionManyBags stg_binds)
- where
- spec_con = mkSpecialisedCon con types
-
-coreExprToStg env (Prim op tys args)
- = mapAndUnzipUs (coreAtomToStg env) args `thenUs` \ (stg_atoms, stg_binds) ->
- returnUs (StgPrim op stg_atoms bOGUS_LVs, unionManyBags stg_binds)
-\end{code}
-
-%************************************************************************
-%* *
-\subsubsection[coreToStg-type-stuff]{Type application and abstraction}
-%* *
-%************************************************************************
-
-This type information dies in this Core-to-STG translation.
+coreExprToStg env (Con con args)
+ = coreArgsToStg env args `thenUs` \ (types, stg_atoms, stg_binds) ->
+ let
+ spec_con = mkSpecialisedCon con types
+ in
+ returnUs (StgCon spec_con stg_atoms bOGUS_LVs, stg_binds)
-\begin{code}
-coreExprToStg env (CoTyLam tyvar expr) = coreExprToStg env expr
-coreExprToStg env (CoTyApp expr ty) = coreExprToStg env expr
+coreExprToStg env (Prim op args)
+ = coreArgsToStg env args `thenUs` \ (_, stg_atoms, stg_binds) ->
+ returnUs (StgPrim op stg_atoms bOGUS_LVs, stg_binds)
\end{code}
%************************************************************************
\begin{code}
coreExprToStg env expr@(Lam _ _)
- = coreExprToStg env body `thenUs` \ (stg_body, binds) ->
+ = let
+ (_,_, binders, body) = collectBinders expr
+ in
+ coreExprToStg env body `thenUs` \ (stg_body, binds) ->
newStgVar (coreExprType expr) `thenUs` \ var ->
returnUs
(StgLet (StgNonRec var (StgRhsClosure noCostCentre
stg_body))
(StgApp (StgVarArg var) [] bOGUS_LVs),
binds)
- where
- (binders,body) = collect expr
-
- -- Collect lambda-bindings, discarding type abstractions and applications
- collect (Lam x e) = (x:binders, body) where (binders,body) = collect e
- collect (CoTyLam _ e) = collect e
- collect (CoTyApp e _) = collect e
- collect body = ([], body)
\end{code}
%************************************************************************
\begin{code}
coreExprToStg env expr@(App _ _)
- = -- Deal with the arguments
- mapAndUnzipUs (coreAtomToStg env) args `thenUs` \ (stg_args, arg_binds) ->
+ = let
+ (fun, _, _, args) = collectArgs expr
+ in
+ -- Deal with the arguments
+ coreArgsToStg env args `thenUs` \ (_, stg_args, arg_binds) ->
-- Now deal with the function
case fun of
- Var fun_id -> returnUs (StgApp (stgLookup env fun_id) stg_args bOGUS_LVs,
- unionManyBags arg_binds)
+ Var fun_id -> returnUs (StgApp (stgLookup env fun_id) stg_args bOGUS_LVs, arg_binds)
other -> -- A non-variable applied to things; better let-bind it.
newStgVar (coreExprType fun) `thenUs` \ fun_id ->
in
returnUs (StgLet (StgNonRec fun_id fun_rhs)
(StgApp (StgVarArg fun_id) stg_args bOGUS_LVs),
- unionManyBags arg_binds `unionBags`
- fun_binds)
- where
- (fun,args) = collect_args expr []
-
- -- Collect arguments, discarding type abstractions and applications
- collect_args (App fun arg) args = collect_args fun (arg:args)
- collect_args (CoTyLam _ e) args = collect_args e args
- collect_args (CoTyApp e _) args = collect_args e args
- collect_args fun args = (fun, args)
+ arg_binds `unionBags` fun_binds)
\end{code}
%************************************************************************
\begin{code}
-coreExprToStg env (Case discrim@(Prim op tys args) alts)
- | funnyParallelOp op =
- getUnique `thenUs` \ uniq ->
+coreExprToStg env (Case discrim@(Prim op _) alts)
+ | funnyParallelOp op
+ = getUnique `thenUs` \ uniq ->
coreExprToStg env discrim `thenUs` \ (stg_discrim, discrim_binds) ->
alts_to_stg alts `thenUs` \ (stg_alts, alts_binds) ->
returnUs (
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
%
\section[StgLint]{A ``lint'' pass to check for Stg correctness}
module StgLint ( lintStgBindings ) where
-import PrelInfo ( primOpType, mkFunTy, PrimOp(..), PrimRep
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
- )
-import Type
-import Bag
-import Literal ( literalType, Literal )
+import Ubiq{-uitous-}
+
+import StgSyn
+
+import Bag ( emptyBag, isEmptyBag, snocBag, foldBag )
import Id ( idType, isDataCon,
- getInstantiatedDataConSig
+ emptyIdSet, isEmptyIdSet, elementOfIdSet,
+ mkIdSet, intersectIdSets,
+ unionIdSets, idSetToList, IdSet(..),
+ GenId{-instanced NamedThing-}
)
-import Maybes
-import Outputable
-import Pretty
-import SrcLoc ( SrcLoc )
-import StgSyn
-import UniqSet
-import Util
+import Literal ( literalType, Literal{-instance Outputable-} )
+import Maybes ( catMaybes )
+import Outputable ( Outputable(..){-instance * []-} )
+import PprType ( GenType{-instance Outputable-}, TyCon )
+import Pretty -- quite a bit of it
+import PrimOp ( primOpType )
+import SrcLoc ( SrcLoc{-instance Outputable-} )
+import Type ( mkFunTys, splitFunTy, maybeAppDataTyCon,
+ isTyVarTy, eqTy
+ )
+import Util ( zipEqual, pprPanic, panic, panic# )
infixr 9 `thenL`, `thenL_`, `thenMaybeL`, `thenMaybeL_`
+
+getInstantiatedDataConSig = panic "StgLint.getInstantiatedDataConSig (ToDo)"
+splitTypeWithDictsAsArgs = panic "StgLint.splitTypeWithDictsAsArgs (ToDo)"
+unDictifyTy = panic "StgLint.unDictifyTy (ToDo)"
\end{code}
Checks for
= addLoc (LambdaBodyOf binders) (
addInScopeVars binders (
lintStgExpr expr `thenMaybeL` \ body_ty ->
- returnL (Just (foldr (mkFunTy . idType) body_ty binders))
+ returnL (Just (mkFunTys (map idType binders) body_ty))
))
lintStgRhs (StgRhsCon _ con args)
lintStgAlts alts scrut_ty case_tycon
= (case alts of
StgAlgAlts _ alg_alts deflt ->
- chk_non_abstract_type case_tycon `thenL_`
mapL (lintAlgAlt scrut_ty) alg_alts `thenL` \ maybe_alt_tys ->
lintDeflt deflt scrut_ty `thenL` \ maybe_deflt_ty ->
returnL (maybe_deflt_ty : maybe_alt_tys)
returnL (Just first_ty)
where
check ty = checkTys first_ty ty (mkCaseAltMsg alts)
- where
- chk_non_abstract_type tycon
- = case (getTyConFamilySize tycon) of
- Nothing -> addErrL (mkCaseAbstractMsg tycon)
- Just _ -> returnL () -- that's cool
lintAlgAlt scrut_ty (con, args, _, rhs)
= (case maybeAppDataTyCon scrut_ty of
\begin{code}
type LintM a = [LintLocInfo] -- Locations
- -> UniqSet Id -- Local vars in scope
+ -> IdSet -- Local vars in scope
-> Bag ErrMsg -- Error messages so far
-> (a, Bag ErrMsg) -- Result and error messages (if any)
\begin{code}
initL :: LintM a -> Maybe ErrMsg
initL m
- = case (m [] emptyUniqSet emptyBag) of { (_, errs) ->
+ = case (m [] emptyIdSet emptyBag) of { (_, errs) ->
if isEmptyBag errs then
Nothing
else
Just ( \ sty ->
- ppAboves [ msg sty | msg <- bagToList errs ]
+ foldBag ppAbove ( \ msg -> msg sty ) ppNil errs
)
}
-- For now, it's just a "trace"; we may make
-- a real error out of it...
let
- new_set = mkUniqSet ids
+ new_set = mkIdSet ids
- shadowed = scope `intersectUniqSets` new_set
+ shadowed = scope `intersectIdSets` new_set
in
-- After adding -fliberate-case, Simon decided he likes shadowed
-- names after all. WDP 94/07
--- (if isEmptyUniqSet shadowed
+-- (if isEmptyIdSet shadowed
-- then id
--- else pprTrace "Shadowed vars:" (ppr PprDebug (uniqSetToList shadowed))) (
- m loc (scope `unionUniqSets` new_set) errs
--- )
+-- else pprTrace "Shadowed vars:" (ppr PprDebug (idSetToList shadowed))) $
+ m loc (scope `unionIdSets` new_set) errs
\end{code}
\begin{code}
(_, expected_arg_tys, res_ty) = splitTypeWithDictsAsArgs fun_ty
cfa res_ty expected [] -- Args have run out; that's fine
- = (Just (glueTyArgs expected res_ty), errs)
+ = (Just (mkFunTys expected res_ty), errs)
cfa res_ty [] arg_tys -- Expected arg tys ran out first;
-- first see if res_ty is a tyvar template;
-- otherwise, maybe res_ty is a
-- dictionary type which is actually a function?
- | isTyVarTemplateTy res_ty
+ | isTyVarTy res_ty
= (Just res_ty, errs)
| otherwise
- = case splitTyArgs (unDictifyTy res_ty) of
+ = case splitFunTy (unDictifyTy res_ty) of
([], _) -> (Nothing, addErr errs msg loc) -- Too many args
(new_expected, new_res) -> cfa new_res new_expected arg_tys
cfa res_ty (expected_arg_ty:expected_arg_tys) (arg_ty:arg_tys)
- = case (sleazy_cmp_ty expected_arg_ty arg_ty) of
- EQ_ -> cfa res_ty expected_arg_tys arg_tys
- _ -> (Nothing, addErr errs msg loc) -- Arg mis-match
+ = if (sleazy_eq_ty expected_arg_ty arg_ty)
+ then cfa res_ty expected_arg_tys arg_tys
+ else (Nothing, addErr errs msg loc) -- Arg mis-match
\end{code}
\begin{code}
checkInScope :: Id -> LintM ()
checkInScope id loc scope errs
- = if isLocallyDefined id && not (isDataCon id) && not (id `elementOfUniqSet` scope) then
+ = if isLocallyDefined id && not (isDataCon id) && not (id `elementOfIdSet` scope) then
((), addErr errs (\ sty -> ppCat [ppr sty id, ppStr "is out of scope"]) loc)
else
((), errs)
checkTys :: Type -> Type -> ErrMsg -> LintM ()
checkTys ty1 ty2 msg loc scope errs
- = case (sleazy_cmp_ty ty1 ty2) of
- EQ_ -> ((), errs)
- other -> ((), addErr errs msg loc)
+ = if (sleazy_eq_ty ty1 ty2)
+ then ((), errs)
+ else ((), addErr errs msg loc)
\end{code}
\begin{code}
pp_expr :: PprStyle -> StgExpr -> Pretty
pp_expr sty expr = ppr sty expr
-sleazy_cmp_ty ty1 ty2
+sleazy_eq_ty ty1 ty2
-- NB: probably severe overkill (WDP 95/04)
= case (splitTypeWithDictsAsArgs ty1) of { (_,tyargs1,tyres1) ->
case (splitTypeWithDictsAsArgs ty2) of { (_,tyargs2,tyres2) ->
let
- ty11 = glueTyArgs tyargs1 tyres1
- ty22 = glueTyArgs tyargs2 tyres2
+ ty11 = mkFunTys tyargs1 tyres1
+ ty22 = mkFunTys tyargs2 tyres2
in
- cmpUniType False{-!!!NOT PROPERLY!!!-} ty11 ty22
+ trace "StgLint.sleazy_cmp_ty" $
+ ty11 `eqTy` ty22
}}
\end{code}
import Ubiq{-uitous-}
-{-
-import PrelInfo ( getPrimOpResultInfo, PrimOpResultInfo(..),
- PrimOp, PrimRep
- IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
- IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
+import CostCentre ( showCostCentre )
+import Id ( idPrimRep, GenId{-instance NamedThing-} )
+import Literal ( literalPrimRep, isLitLitLit, Literal{-instance Outputable-} )
+import Outputable ( isExported, isOpLexeme, ifPprDebug,
+ interppSP, interpp'SP,
+ Outputable(..){-instance * Bool-}
)
-import HsSyn ( HsBinds, HsExpr, GRHS, GRHSsAndBinds, InPat )
-import Type
-import Literal ( literalPrimRep, isLitLitLit,
- Literal(..) -- (..) for pragmas
- )
-import Id ( idType, getIdPrimRep, toplevelishId,
- isTopLevId, Id, IdInfo
- )
-import Maybes ( Maybe(..), catMaybes )
-import Outputable
-import Pretty
-import CostCentre ( showCostCentre, CostCentre )
-import UniqSet
-import Util
--}
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-} )
+import Pretty -- all of it
+import PrimOp ( PrimOp{-instance Outputable-} )
+import Unique ( pprUnique )
+import UniqSet ( isEmptyUniqSet, uniqSetToList, UniqSet(..) )
+import Util ( panic )
\end{code}
%************************************************************************
\end{code}
\begin{code}
-getArgPrimRep (StgVarArg local) = getIdPrimRep local
-getArgPrimRep (StgLitArg lit) = literalPrimRep lit
+getArgPrimRep (StgVarArg local) = idPrimRep local
+getArgPrimRep (StgLitArg lit) = literalPrimRep lit
isLitLitArg (StgLitArg x) = isLitLitLit x
isLitLitArg _ = False
x%
-% (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
%
\section[StgUtils]{Utility functions for @STG@ programs}
module StgUtils ( mapStgBindeesRhs ) where
-import StgSyn
+import Ubiq{-uitous-}
+import Id ( GenId{-instanced NamedThing-} )
+import StgSyn
import UniqSet
-
-import Util
\end{code}
This utility function simply applies the given function to every
(mapStgBindeesExpr fn expr)
mapStgBindeesRhs fn (StgRhsCon cc con atoms)
- = StgRhsCon cc con (map (mapStgBindeesAtom fn) atoms)
+ = StgRhsCon cc con (map (mapStgBindeesArg fn) atoms)
------------------
mapStgBindeesExpr :: (Id -> Id) -> StgExpr -> StgExpr
mapStgBindeesExpr fn (StgApp f args lvs)
- = StgApp (mapStgBindeesAtom fn f)
- (map (mapStgBindeesAtom fn) args)
+ = StgApp (mapStgBindeesArg fn f)
+ (map (mapStgBindeesArg fn) args)
(mapUniqSet fn lvs)
mapStgBindeesExpr fn (StgCon con atoms lvs)
- = StgCon con (map (mapStgBindeesAtom fn) atoms) (mapUniqSet fn lvs)
+ = StgCon con (map (mapStgBindeesArg fn) atoms) (mapUniqSet fn lvs)
mapStgBindeesExpr fn (StgPrim op atoms lvs)
- = StgPrim op (map (mapStgBindeesAtom fn) atoms) (mapUniqSet fn lvs)
+ = StgPrim op (map (mapStgBindeesArg fn) atoms) (mapUniqSet fn lvs)
mapStgBindeesExpr fn (StgLet bind expr)
= StgLet (mapStgBindeesBind fn bind) (mapStgBindeesExpr fn expr)
mapStgBindeesDeflt (StgBindDefault b used expr) = StgBindDefault b used (mapStgBindeesExpr fn expr)
------------------
-mapStgBindeesAtom :: (Id -> Id) -> StgArg -> StgArg
+mapStgBindeesArg :: (Id -> Id) -> StgArg -> StgArg
-mapStgBindeesAtom fn a@(StgLitArg _) = a
-mapStgBindeesAtom fn a@(StgVarArg id) = StgVarArg (fn id)
+mapStgBindeesArg fn a@(StgLitArg _) = a
+mapStgBindeesArg fn a@(StgVarArg id) = StgVarArg (fn id)
\end{code}
isBot
) where
-IMPORT_Trace -- ToDo: rm
-import Pretty
---import FiniteMap
-import Outputable
-
-import PrelInfo ( PrimOp(..),
- intTyCon, integerTyCon, doubleTyCon,
- floatTyCon, wordTyCon, addrTyCon,
- PrimRep
+import Ubiq{-uitous-}
+
+import CoreSyn
+import CoreUnfold ( UnfoldingDetails(..), FormSummary )
+import CoreUtils ( unTagBinders )
+import Id ( idType, getIdStrictness, getIdUnfolding,
+ dataConSig
)
-import Type ( isPrimType, maybeAppDataTyCon,
- maybeSingleConstructorTyCon,
- returnsRealWorld,
- isEnumerationTyCon, TyVarTemplate, TyCon
+import IdInfo ( StrictnessInfo(..), Demand(..),
+ wwPrim, wwStrict, wwEnum, wwUnpack
)
-import CoreUtils ( unTagBinders )
-import Id ( getIdStrictness, idType, getIdUnfolding,
- getDataConSig, getInstantiatedDataConSig,
- DataCon(..), isBottomingId
+import MagicUFs ( MagicUnfoldingFun )
+import Maybes ( maybeToBool )
+import Outputable ( Outputable(..){-instance * []-} )
+import PprStyle ( PprStyle(..) )
+import PrelInfo ( intTyCon, integerTyCon, doubleTyCon,
+ floatTyCon, wordTyCon, addrTyCon
)
-import IdInfo -- various bits
-import Maybes ( maybeToBool, Maybe(..) )
+import Pretty ( ppStr )
+import PrimOp ( PrimOp(..) )
import SaLib
-import Util
+import TyCon ( maybeTyConSingleCon, isEnumerationTyCon,
+ TyCon{-instance Eq-}
+ )
+import Type ( maybeAppDataTyCon, isPrimType )
+import Util ( isIn, isn'tIn, nOfThem, zipWithEqual,
+ pprTrace, panic, pprPanic, assertPanic
+ )
+
+getInstantiatedDataConSig = panic "SaAbsInt.getInstantiatedDataConSig (ToDo)"
+returnsRealWorld = panic "SaAbsInt.returnsRealWorld (ToDo)"
\end{code}
%************************************************************************
(Nothing, NoStrictnessInfo, LitForm _) ->
AbsTop -- Literals all terminate, and have no poison
- (Nothing, NoStrictnessInfo, ConForm _ _ _) ->
+ (Nothing, NoStrictnessInfo, ConForm _ _) ->
AbsTop -- An imported constructor won't have
-- bottom components, nor poison!
to make sure that any poison (?????)
\begin{code}
-absEval StrAnal (Prim SeqOp [t] [e]) env
- = if isBot (absEvalAtom StrAnal e env) then AbsBot else AbsTop
+absEval StrAnal (Prim SeqOp [TyArg _, e]) env
+ = ASSERT(isValArg e)
+ if isBot (absEvalAtom StrAnal e env) then AbsBot else AbsTop
-- This is a special case to ensure that seq# is strict in its argument.
-- The comments below (for most normal PrimOps) do not apply.
-absEval StrAnal (Prim op ts es) env = AbsTop
+absEval StrAnal (Prim op es) env = AbsTop
-- The arguments are all of unboxed type, so they will already
-- have been eval'd. If the boxed version was bottom, we'll
-- already have returned bottom.
-- uses boxed args and we don't know whether or not it's
-- strict, so we assume laziness. (JSM)
-absEval AbsAnal (Prim op ts as) env
- = if any anyBot [absEvalAtom AbsAnal a env | a <- as]
+absEval AbsAnal (Prim op as) env
+ = if any anyBot [absEvalAtom AbsAnal a env | a <- as, isValArg a]
then AbsBot
else AbsTop
-- For absence analysis, we want to see if the poison shows up...
-absEval anal (Con con ts as) env
+absEval anal (Con con as) env
| has_single_con
- = AbsProd [absEvalAtom anal a env | a <- as]
+ = AbsProd [absEvalAtom anal a env | a <- as, isValArg a]
| otherwise -- Not single-constructor
= case anal of
AbsAnal -> -- In the absence case we need to be more
-- careful: look to see if there's any
-- poison in the components
- if any anyBot [absEvalAtom AbsAnal a env | a <- as]
+ if any anyBot [absEvalAtom AbsAnal a env | a <- as, isValArg a]
then AbsBot
else AbsTop
where
- (_,_,_, tycon) = getDataConSig con
- has_single_con = maybeToBool (maybeSingleConstructorTyCon tycon)
+ (_,_,_, tycon) = dataConSig con
+ has_single_con = maybeToBool (maybeTyConSingleCon tycon)
\end{code}
\begin{code}
-absEval anal (Lam binder body) env
+absEval anal (Lam (ValBinder binder) body) env
= AbsFun [binder] body env
-absEval anal (CoTyLam ty expr) env
+absEval anal (Lam other_binder expr) env
= absEval anal expr env
-absEval anal (App e1 e2) env
- = absApply anal (absEval anal e1 env) (absEvalAtom anal e2 env)
-absEval anal (CoTyApp expr ty) env
+absEval anal (App f a) env | isValArg a
+ = absApply anal (absEval anal f env) (absEvalAtom anal a env)
+absEval anal (App expr _) env
= absEval anal expr env
\end{code}
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
%
\section[SaLib]{Basic datatypes, functions for the strictness analyser}
nullAbsValEnv, addOneToAbsValEnv, growAbsValEnvList,
lookupAbsValEnv,
absValFromStrictness
-
- -- and to make the interface self-sufficient...
) where
-import IdInfo
-import Outputable
-import Pretty
+import Ubiq{-uitous-}
+
+import CoreSyn ( CoreExpr(..) )
+import Id ( nullIdEnv, addOneToIdEnv, growIdEnvList,
+ lookupIdEnv, IdEnv(..),
+ GenId{-instance Outputable-}
+ )
+import IdInfo ( StrictnessInfo(..), Demand{-instance Outputable-} )
+import Outputable ( Outputable(..){-instance * []-} )
+import PprType ( GenType{-instance Outputable-} )
+import Pretty ( ppStr, ppCat )
\end{code}
%************************************************************************
module StrictAnal ( saWwTopBinds, saTopBinds ) where
-import Id ( addIdDemandInfo, isWrapperId, addIdStrictness,
- idType, getIdDemandInfo
+import Ubiq{-uitous-}
+
+import CmdLineOpts ( opt_AllStrict, opt_NumbersStrict,
+ opt_D_dump_stranal, opt_D_simplifier_stats
+ )
+import CoreSyn
+import Id ( idType, addIdStrictness,
+ getIdDemandInfo, addIdDemandInfo,
+ GenId{-instance Outputable-}
+ )
+import IdInfo ( mkStrictnessInfo, mkBottomStrictnessInfo,
+ mkDemandInfo, willBeDemanded, DemandInfo
)
-import IdInfo
+import PprCore ( pprCoreBinding, pprBigCoreBinder )
+import PprStyle ( PprStyle(..) )
+import PprType ( GenType{-instance Outputable-}, GenTyVar{-ditto-} )
+import Pretty ( ppBesides, ppStr, ppInt, ppChar, ppAboves )
import SaAbsInt
import SaLib
-import UniqSupply
-import Util
+import TyVar ( GenTyVar{-instance Eq-} )
import WorkWrap -- "back-end" of strictness analyser
-import WwLib ( WwM(..) )
+import Unique ( Unique{-instance Eq -} )
+import Util ( zipWith4Equal, pprTrace, panic{-ToDo:rm-} )
+
+isWrapperId = panic "StrictAnal.isWrapperId (ToDo)"
\end{code}
\begin{code}
saWwTopBinds :: UniqSupply
- -> (GlobalSwitch -> Bool)
-> [CoreBinding]
-> [CoreBinding]
-saWwTopBinds us switch_chker binds
+saWwTopBinds us binds
= let
- strflags = (switch_chker AllStrict, switch_chker NumbersStrict)
+ strflags = (opt_AllStrict, opt_NumbersStrict)
-- mark each binder with its strictness
#ifndef OMIT_STRANAL_STATS
#endif
in
-- possibly show what we decided about strictness...
- (if switch_chker D_dump_stranal
+ (if opt_D_dump_stranal
then pprTrace "Strictness:\n" (ppAboves (
- map (pprCoreBinding PprDebug pprBigCoreBinder pprBigCoreBinder ppr) binds_w_strictness))
+ map (pprCoreBinding PprDebug) binds_w_strictness))
else id
)
-- possibly show how many things we marked as demanded...
- ((if switch_chker D_simplifier_stats
+ ((if opt_D_simplifier_stats
#ifndef OMIT_STRANAL_STATS
then pp_stats sa_stats
#else
-- create worker/wrappers, and mark binders with their
-- "strictness info" [which encodes their
-- worker/wrapper-ness]
- (workersAndWrappers binds_w_strictness us switch_chker))
+ (workersAndWrappers binds_w_strictness us))
#ifndef OMIT_STRANAL_STATS
where
pp_stats (SaStats tlam dlam tc dc tlet dlet)
\begin{code}
saExpr :: StrictEnv -> AbsenceEnv -> CoreExpr -> SaM CoreExpr
-saExpr _ _ e@(Var _) = returnSa e
-saExpr _ _ e@(Lit _) = returnSa e
-saExpr _ _ e@(Con _ _ _) = returnSa e
-saExpr _ _ e@(Prim _ _ _) = returnSa e
+saExpr _ _ e@(Var _) = returnSa e
+saExpr _ _ e@(Lit _) = returnSa e
+saExpr _ _ e@(Con _ _) = returnSa e
+saExpr _ _ e@(Prim _ _) = returnSa e
-saExpr str_env abs_env (Lam arg body)
+saExpr str_env abs_env (Lam (ValBinder arg) body)
= saExpr str_env abs_env body `thenSa` \ new_body ->
let
new_arg = addDemandInfoToId str_env abs_env body arg
in
tickLambda new_arg `thenSa_` -- stats
- returnSa (Lam new_arg new_body)
+ returnSa (Lam (ValBinder new_arg) new_body)
-saExpr str_env abs_env (CoTyLam ty expr)
+saExpr str_env abs_env (Lam other_binder expr)
= saExpr str_env abs_env expr `thenSa` \ new_expr ->
- returnSa (CoTyLam ty new_expr)
+ returnSa (Lam other_binder new_expr)
saExpr str_env abs_env (App fun arg)
= saExpr str_env abs_env fun `thenSa` \ new_fun ->
returnSa (App new_fun arg)
-saExpr str_env abs_env (CoTyApp expr ty)
- = saExpr str_env abs_env expr `thenSa` \ new_expr ->
- returnSa (CoTyApp new_expr ty)
-
saExpr str_env abs_env (SCC cc expr)
= saExpr str_env abs_env expr `thenSa` \ new_expr ->
returnSa (SCC cc new_expr)
{-# INLINE thenSa_ #-}
{-# INLINE returnSa #-}
-tickLambda :: [Id] -> SaM ()
+tickLambda :: Id -> SaM ()
tickCases :: [Id] -> SaM ()
tickLet :: Id -> SaM ()
returnSa x stats = (x, stats)
tickLambda var (SaStats tlam dlam tc dc tlet dlet)
- = case (tick_demanded (0,0) var) of { (IBOX(tot), IBOX(demanded)) ->
+ = case (tick_demanded var (0,0)) of { (IBOX(tot), IBOX(demanded)) ->
((), SaStats (tlam _ADD_ tot) (dlam _ADD_ demanded) tc dc tlet dlet) }
tickCases vars (SaStats tlam dlam tc dc tlet dlet)
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
%
\section[WorkWrap]{Worker/wrapper-generating back-end of strictness analyser}
module WorkWrap ( workersAndWrappers ) where
-IMPORT_Trace
-import Outputable
-import Pretty
+import Ubiq{-uitous-}
-import Id ( idType, addIdStrictness, getIdStrictness,
- getIdUnfolding, mkWorkerId,
- replaceIdInfo, getIdInfo, idWantsToBeINLINEd
+import CoreSyn
+import CoreUnfold ( UnfoldingGuidance(..) )
+import CoreUtils ( coreExprType )
+import Id ( idWantsToBeINLINEd, getIdStrictness, mkWorkerId,
+ getIdInfo
+ )
+import IdInfo ( noIdInfo, addInfo_UF, indicatesWorker,
+ mkStrictnessInfo, StrictnessInfo(..)
)
-import IdInfo -- bits and pieces
-import Maybes ( maybeToBool, Maybe(..) )
import SaLib
-import SrcLoc ( mkUnknownSrcLoc, SrcLoc )
-import Util
+import UniqSupply ( returnUs, thenUs, mapUs, getUnique, UniqSM(..) )
import WwLib
+import Util ( panic{-ToDo:rm-} )
+
+replaceIdInfo = panic "WorkWrap.replaceIdInfo (ToDo)"
+iWantToBeINLINEd = panic "WorkWrap.iWantToBeINLINEd (ToDo)"
\end{code}
We take Core bindings whose binders have their strictness attached (by
\end{enumerate}
\begin{code}
-workersAndWrappers :: [CoreBinding] -> WwM [CoreBinding]
+workersAndWrappers :: [CoreBinding] -> UniqSM [CoreBinding]
workersAndWrappers top_binds
- = mapWw (wwBind True{-top-level-}) top_binds `thenWw` \ top_binds2 ->
+ = mapUs (wwBind True{-top-level-}) top_binds `thenUs` \ top_binds2 ->
let
top_binds3 = map make_top_binding top_binds2
in
- returnWw (concat top_binds3)
+ returnUs (concat top_binds3)
where
make_top_binding :: WwBinding -> [CoreBinding]
\begin{code}
wwBind :: Bool -- True <=> top-level binding
-> CoreBinding
- -> WwM WwBinding -- returns a WwBinding intermediate form;
+ -> UniqSM WwBinding -- returns a WwBinding intermediate form;
-- the caller will convert to Expr/Binding,
-- as appropriate.
wwBind top_level (NonRec binder rhs)
- = wwExpr rhs `thenWw` \ new_rhs ->
- tryWW binder new_rhs `thenWw` \ new_pairs ->
- returnWw (WwLet [NonRec b e | (b,e) <- new_pairs])
+ = wwExpr rhs `thenUs` \ new_rhs ->
+ tryWW binder new_rhs `thenUs` \ new_pairs ->
+ returnUs (WwLet [NonRec b e | (b,e) <- new_pairs])
-- Generated bindings must be non-recursive
-- because the original binding was.
------------------------------
wwBind top_level (Rec pairs)
- = mapWw do_one pairs `thenWw` \ new_pairs ->
- returnWw (WwLet [Rec (concat new_pairs)])
+ = mapUs do_one pairs `thenUs` \ new_pairs ->
+ returnUs (WwLet [Rec (concat new_pairs)])
where
- do_one (binder, rhs) = wwExpr rhs `thenWw` \ new_rhs ->
+ do_one (binder, rhs) = wwExpr rhs `thenUs` \ new_rhs ->
tryWW binder new_rhs
\end{code}
???????????????? ToDo
\begin{code}
-wwExpr :: CoreExpr -> WwM CoreExpr
-
-wwExpr e@(Var _) = returnWw e
-wwExpr e@(Lit _) = returnWw e
-wwExpr e@(Con _ _ _) = returnWw e
-wwExpr e@(Prim _ _ _) = returnWw e
-
-wwExpr (Lam binders expr)
- = wwExpr expr `thenWw` \ new_expr ->
- returnWw (Lam binders new_expr)
+wwExpr :: CoreExpr -> UniqSM CoreExpr
-wwExpr (CoTyLam ty expr)
- = wwExpr expr `thenWw` \ new_expr ->
- returnWw (CoTyLam ty new_expr)
+wwExpr e@(Var _) = returnUs e
+wwExpr e@(Lit _) = returnUs e
+wwExpr e@(Con _ _) = returnUs e
+wwExpr e@(Prim _ _) = returnUs e
-wwExpr (App e1 e2)
- = wwExpr e1 `thenWw` \ new_e1 ->
- returnWw (App new_e1 e2)
+wwExpr (Lam binder expr)
+ = wwExpr expr `thenUs` \ new_expr ->
+ returnUs (Lam binder new_expr)
-wwExpr (CoTyApp expr ty)
- = wwExpr expr `thenWw` \ new_expr ->
- returnWw (CoTyApp new_expr ty)
+wwExpr (App f a)
+ = wwExpr f `thenUs` \ new_f ->
+ returnUs (App new_f a)
wwExpr (SCC cc expr)
- = wwExpr expr `thenWw` \ new_expr ->
- returnWw (SCC cc new_expr)
+ = wwExpr expr `thenUs` \ new_expr ->
+ returnUs (SCC cc new_expr)
wwExpr (Let bind expr)
- = wwBind False{-not top-level-} bind `thenWw` \ intermediate_bind ->
- wwExpr expr `thenWw` \ new_expr ->
- returnWw (mash_ww_bind intermediate_bind new_expr)
+ = wwBind False{-not top-level-} bind `thenUs` \ intermediate_bind ->
+ wwExpr expr `thenUs` \ new_expr ->
+ returnUs (mash_ww_bind intermediate_bind new_expr)
where
mash_ww_bind (WwLet binds) body = mkCoLetsNoUnboxed binds body
mash_ww_bind (WwCase case_fn) body = case_fn body
wwExpr (Case expr alts)
- = wwExpr expr `thenWw` \ new_expr ->
- ww_alts alts `thenWw` \ new_alts ->
- returnWw (Case new_expr new_alts)
+ = wwExpr expr `thenUs` \ new_expr ->
+ ww_alts alts `thenUs` \ new_alts ->
+ returnUs (Case new_expr new_alts)
where
ww_alts (AlgAlts alts deflt)
- = mapWw ww_alg_alt alts `thenWw` \ new_alts ->
- ww_deflt deflt `thenWw` \ new_deflt ->
- returnWw (AlgAlts new_alts new_deflt)
+ = mapUs ww_alg_alt alts `thenUs` \ new_alts ->
+ ww_deflt deflt `thenUs` \ new_deflt ->
+ returnUs (AlgAlts new_alts new_deflt)
ww_alts (PrimAlts alts deflt)
- = mapWw ww_prim_alt alts `thenWw` \ new_alts ->
- ww_deflt deflt `thenWw` \ new_deflt ->
- returnWw (PrimAlts new_alts new_deflt)
+ = mapUs ww_prim_alt alts `thenUs` \ new_alts ->
+ ww_deflt deflt `thenUs` \ new_deflt ->
+ returnUs (PrimAlts new_alts new_deflt)
ww_alg_alt (con, binders, rhs)
- = wwExpr rhs `thenWw` \ new_rhs ->
- returnWw (con, binders, new_rhs)
+ = wwExpr rhs `thenUs` \ new_rhs ->
+ returnUs (con, binders, new_rhs)
ww_prim_alt (lit, rhs)
- = wwExpr rhs `thenWw` \ new_rhs ->
- returnWw (lit, new_rhs)
+ = wwExpr rhs `thenUs` \ new_rhs ->
+ returnUs (lit, new_rhs)
ww_deflt NoDefault
- = returnWw NoDefault
+ = returnUs NoDefault
ww_deflt (BindDefault binder rhs)
- = wwExpr rhs `thenWw` \ new_rhs ->
- returnWw (BindDefault binder new_rhs)
+ = wwExpr rhs `thenUs` \ new_rhs ->
+ returnUs (BindDefault binder new_rhs)
\end{code}
%************************************************************************
tryWW :: Id -- the fn binder
-> CoreExpr -- the bound rhs; its innards
-- are already ww'd
- -> WwM [(Id, CoreExpr)] -- either *one* or *two* pairs;
+ -> UniqSM [(Id, CoreExpr)] -- either *one* or *two* pairs;
-- if one, then no worker (only
-- the orig "wrapper" lives on);
-- if two, then a worker and a
(uvars, tyvars, args, body) = collectBinders rhs
body_ty = coreExprType body
in
- uniqSMtoWwM (mkWwBodies body_ty tyvars args args_info) `thenWw` \ result ->
+ mkWwBodies body_ty tyvars args args_info `thenUs` \ result ->
case result of
Nothing -> -- Very peculiar. This can only happen if we hit an
Just (wrapper_w_hole, worker_w_hole, worker_strictness, worker_ty_w_hole) ->
-- Terrific! It worked!
- getUniqueWw `thenWw` \ worker_uniq ->
+ getUnique `thenUs` \ worker_uniq ->
let
worker_ty = worker_ty_w_hole body_ty
-- NB! the "iWantToBeINLINEd" part adds an INLINE pragma to
-- the wrapper, which is of course what we want.
in
- returnWw [ (worker_id, worker_rhs), -- worker comes first
+ returnUs [ (worker_id, worker_rhs), -- worker comes first
(wrapper_id, wrapper_rhs) ] -- because wrapper mentions it
where
- do_nothing = returnWw [ (fn_id, rhs) ]
+ do_nothing = returnUs [ (fn_id, rhs) ]
\end{code}
module WwLib (
WwBinding(..),
- mkWwBodies, mAX_WORKER_ARGS,
-
- -- our friendly worker/wrapper monad:
- WwM(..),
- returnWw, thenWw, mapWw,
- getUniqueWw, uniqSMtoWwM
-
- -- and to make the interface self-sufficient...
+ mkWwBodies, mAX_WORKER_ARGS
) where
import Ubiq{-uitous-}
+import CoreSyn
+import Id ( idType, mkSysLocal )
+import IdInfo ( mkStrictnessInfo, nonAbsentArgs, Demand(..) )
import PrelInfo ( aBSENT_ERROR_ID )
-{-
-import Id ( mkWorkerId, mkSysLocal, idType,
- getInstantiatedDataConSig, getIdInfo,
- replaceIdInfo, addIdStrictness, DataCon(..)
- )
-import IdInfo -- lots of things
-import Maybes ( maybeToBool, Maybe(..), MaybeErr )
-import SaLib
import SrcLoc ( mkUnknownSrcLoc )
-import Type ( mkTyVarTys, mkFunTys, isPrimType,
- maybeAppDataTyCon, quantifyTy
+import Type ( isPrimType, mkTyVarTys, mkFunTys, maybeAppDataTyCon )
+import UniqSupply ( returnUs, thenUs, thenMaybeUs,
+ getUniques, UniqSM(..)
)
-import UniqSupply
--}
-import Util ( panic )
-
-infixr 9 `thenWw`
+import Util ( zipWithEqual, assertPanic, panic )
quantifyTy = panic "WwLib.quantifyTy"
+getInstantiatedDataConSig = panic "WwLib.getInstantiatedDataConSig"
\end{code}
%************************************************************************
else -- the rest...
mk_ww_arg_processing args arg_infos (mAX_WORKER_ARGS - nonAbsentArgs arg_infos)
- `thenUsMaybe` \ (wrap_frag, work_args_info, work_frag) ->
+ `thenMaybeUs` \ (wrap_frag, work_args_info, work_frag) ->
let
(work_args, wrkr_demands) = unzip work_args_info
wrapper_w_hole = \ worker_id ->
mkLam tyvars args (
wrap_frag (
- mkCoTyApps (Var worker_id) (mkTyVarTys tyvars)
+ mkTyApp (Var worker_id) (mkTyVarTys tyvars)
))
worker_w_hole = \ orig_body ->
mk_ww_arg_processing args infos max_extra_args
-- we've already discounted for absent args,
-- so we don't change max_extra_args
- `thenUsMaybe` \ (wrap_rest, work_args_info, work_rest) ->
+ `thenMaybeUs` \ (wrap_rest, work_args_info, work_rest) ->
-- wrapper doesn't pass this arg to worker:
returnUs (Just (
where
mk_absent_let arg arg_ty body
= if not (isPrimType arg_ty) then
- Let (NonRec arg (mkCoTyApp (Var aBSENT_ERROR_ID) arg_ty)) body
+ Let (NonRec arg (mkTyApp (Var aBSENT_ERROR_ID) [arg_ty])) body
else -- quite horrible
panic "WwLib: haven't done mk_absent_let for primitives yet"
-- In processing the rest, push the sub-component args
-- and infos on the front of the current bunch
mk_ww_arg_processing (unpk_args ++ args) (cmpnt_infos ++ infos) new_max_extra_args
- `thenUsMaybe` \ (wrap_rest, work_args_info, work_rest) ->
+ `thenMaybeUs` \ (wrap_rest, work_args_info, work_rest) ->
returnUs (Just (
-- wrapper: unpack the value
)
mk_pk_let arg boxing_con con_tys unpk_args body
- = Let (NonRec arg (Con boxing_con con_tys [VarArg a | a <- unpk_args]))
+ = Let (NonRec arg (Con boxing_con
+ (map TyArg con_tys ++ map VarArg unpk_args)))
body
mk_ww_arg_processing (arg : args) (arg_demand : infos) max_extra_args
-- Finish args to the right...
mk_ww_arg_processing args infos max_extra_args
- `thenUsMaybe` \ (wrap_rest, work_args_info, work_rest) ->
+ `thenMaybeUs` \ (wrap_rest, work_args_info, work_rest) ->
returnUs (Just (
-- wrapper:
))
--)
\end{code}
-
-%************************************************************************
-%* *
-\subsection[monad-WwLib]{Simple monad for worker/wrapper}
-%* *
-%************************************************************************
-
-In this monad, we thread a @UniqueSupply@, and we carry a
-@GlobalSwitch@-lookup function downwards.
-
-\begin{code}
-type WwM result
- = UniqSupply
- -> (GlobalSwitch -> Bool)
- -> result
-
-{-# INLINE thenWw #-}
-{-# INLINE returnWw #-}
-
-returnWw :: a -> WwM a
-thenWw :: WwM a -> (a -> WwM b) -> WwM b
-mapWw :: (a -> WwM b) -> [a] -> WwM [b]
-
-returnWw expr ns sw = expr
-
-thenWw m k us sw_chk
- = case splitUniqSupply us of { (s1, s2) ->
- case (m s1 sw_chk) of { m_res ->
- k m_res s2 sw_chk }}
-
-mapWw f [] = returnWw []
-mapWw f (x:xs)
- = f x `thenWw` \ x' ->
- mapWw f xs `thenWw` \ xs' ->
- returnWw (x':xs')
-\end{code}
-
-\begin{code}
-getUniqueWw :: WwM Unique
-uniqSMtoWwM :: UniqSM a -> WwM a
-
-getUniqueWw us sw_chk = getUnique us
-
-uniqSMtoWwM u_obj us sw_chk = u_obj us
-
-thenUsMaybe :: UniqSM (Maybe a) -> (a -> UniqSM (Maybe b)) -> UniqSM (Maybe b)
-thenUsMaybe m k
- = m `thenUs` \ result ->
- case result of
- Nothing -> returnUs Nothing
- Just x -> k x
-\end{code}
module GenSpecEtc (
TcSigInfo(..),
genBinds,
- checkSigTyVars, checkSigTyVarsGivenGlobals,
- specTy
+ checkSigTyVars, checkSigTyVarsGivenGlobals
) where
import Ubiq
import HsSyn ( HsBinds(..), Bind(..), MonoBinds(..), HsExpr, OutPat(..),
Sig, HsLit, ArithSeqInfo, InPat, GRHSsAndBinds, Match, Fake
)
-import TcHsSyn ( TcIdOcc(..), TcIdBndr(..), TcHsBinds(..), TcBind(..), TcExpr(..) )
+import TcHsSyn ( TcIdOcc(..), TcIdBndr(..), TcHsBinds(..), TcBind(..), TcExpr(..), tcIdType )
import Bag ( Bag, foldBag, bagToList, listToBag, isEmptyBag )
import Class ( GenClass )
-- BUILD THE NEW LOCALS
let
tyvars = tyVarSetToList reduced_tyvars_to_gen -- Commit to a particular order
- dict_tys = [idType d | TcId d <- dicts_bound] -- Slightly ugh-ish
+ dict_tys = map tcIdType dicts_bound
poly_tys = map (mkForAllTys tyvars . mkFunTys dict_tys) mono_id_types
poly_ids = zipWithEqual mk_poly binder_names poly_tys
mk_poly name ty = mkUserId name ty (prag_info_fn name)
now (ToDo).
\begin{code}
-checkSigMatch :: TcSigInfo s -> TcM s [TcTyVar s]
+checkSigMatch :: TcSigInfo s -> TcM s ()
checkSigMatch (TySigInfo id sig_tyvars _ tau_ty src_loc)
= tcAddSrcLoc src_loc $
tcAddErrCtxt (sigCtxt id) $
- checkSigTyVars sig_tyvars tau_ty (idType id)
+ checkSigTyVars sig_tyvars tau_ty
\end{code}
eg matching signature [(a,b)] against inferred type [(p,p)]
[then a and b will be unified together]
+BUT ACTUALLY THESE FIRST TWO ARE FORCED BY USING DontBind TYVARS
+
(c) not mentioned in the environment
eg the signature for f in this:
\begin{code}
checkSigTyVars :: [TcTyVar s] -- The original signature type variables
-> TcType s -- signature type (for err msg)
- -> TcType s -- inferred type (for err msg)
- -> TcM s [TcTyVar s] -- Post-substitution signature type variables
+ -> TcM s ()
-checkSigTyVars sig_tyvars sig_tau inferred_tau
+checkSigTyVars sig_tyvars sig_tau
= tcGetGlobalTyVars `thenNF_Tc` \ env_tyvars ->
- checkSigTyVarsGivenGlobals env_tyvars sig_tyvars sig_tau inferred_tau
+ checkSigTyVarsGivenGlobals env_tyvars sig_tyvars sig_tau
checkSigTyVarsGivenGlobals
:: TcTyVarSet s -- Consider these fully-zonked tyvars as global
-> [TcTyVar s] -- The original signature type variables
-> TcType s -- signature type (for err msg)
- -> TcType s -- inferred type (for err msg)
- -> TcM s [TcTyVar s] -- Post-substitution signature type variables
-
-checkSigTyVarsGivenGlobals globals sig_tyvars sig_tau inferred_tau
- = -- Check point (a) above
- mapNF_Tc (zonkTcType.mkTyVarTy) sig_tyvars `thenNF_Tc` \ sig_tys ->
- checkMaybeTcM (allMaybes (map getTyVar_maybe sig_tys)) match_err `thenTc` \ sig_tyvars' ->
-
- -- Check point (b)
- checkTcM (hasNoDups sig_tyvars') match_err `thenTc_`
+ -> TcM s ()
- -- Check point (c)
+checkSigTyVarsGivenGlobals globals sig_tyvars sig_tau
+ = -- Check point (c)
-- We want to report errors in terms of the original signature tyvars,
-- ie sig_tyvars, NOT sig_tyvars'. sig_tys and sig_tyvars' correspond
-- 1-1 with sig_tyvars, so we can just map back.
- let
- mono_tyvars = [ sig_tyvar
- | (sig_tyvar,sig_tyvar') <- zipEqual sig_tyvars sig_tyvars',
- sig_tyvar' `elementOfTyVarSet` globals
- ]
- in
checkTc (null mono_tyvars)
- (notAsPolyAsSigErr sig_tau mono_tyvars) `thenTc_`
-
- returnTc sig_tyvars'
+ (notAsPolyAsSigErr sig_tau mono_tyvars)
where
- match_err = zonkTcType inferred_tau `thenNF_Tc` \ inferred_tau' ->
- failTc (badMatchErr sig_tau inferred_tau')
+ mono_tyvars = filter (`elementOfTyVarSet` globals) sig_tyvars
\end{code}
-%************************************************************************
-%* *
-\subsection[GenEtc-SpecTy]{Instantiate a type and create new dicts for it}
-%* *
-%************************************************************************
-
-\begin{code}
-specTy :: InstOrigin s
- -> Type
- -> NF_TcM s ([TcTyVar s], LIE s, TcType s, [TcIdOcc s])
-
-specTy origin sigma_ty
- = tcInstType [] sigma_ty `thenNF_Tc` \ tc_sigma_ty ->
- let
- (tyvars, theta, tau) = splitSigmaTy tc_sigma_ty
- in
- -- Instantiate the dictionary types
- newDicts origin theta `thenNF_Tc` \ (dicts, dict_ids) ->
-
- -- Return the list of tyvars, the list of dicts and the tau type
- returnNF_Tc (tyvars, dicts, tau, dict_ids)
-\end{code}
-
Contexts and errors
Inst(..), -- Visible only to TcSimplify
InstOrigin(..), OverloadedLit(..),
- LIE(..), emptyLIE, unitLIE, plusLIE, consLIE, zonkLIE,
+ LIE(..), emptyLIE, unitLIE, plusLIE, consLIE, zonkLIE, plusLIEs,
InstanceMapper(..),
import TcType ( TcType(..), TcRhoType(..), TcMaybe, TcTyVarSet(..),
tcInstType, tcInstTcType, zonkTcType )
-import Bag ( Bag, emptyBag, unitBag, unionBags, listToBag, consBag )
+import Bag ( emptyBag, unitBag, unionBags, unionManyBags, listToBag, consBag )
import Class ( Class(..), GenClass, ClassInstEnv(..), getClassInstEnv )
import Id ( GenId, idType, mkInstId )
import MatchEnv ( lookupMEnv, insertMEnv )
unitLIE inst = unitBag inst
plusLIE lie1 lie2 = lie1 `unionBags` lie2
consLIE inst lie = inst `consBag` lie
+plusLIEs lies = unionManyBags lies
zonkLIE :: LIE s -> NF_TcM s (LIE s)
zonkLIE lie = mapBagNF_Tc zonkInst lie
-- If typechecking the binds fails, then return with each
-- binder given type (forall a.a), to minimise subsequent
-- error messages
- newTcTyVar Nothing mkBoxedTypeKind `thenNF_Tc` \ alpha_tv ->
+ newTcTyVar mkBoxedTypeKind `thenNF_Tc` \ alpha_tv ->
let
forall_a_a = mkForAllTy alpha_tv (mkTyVarTy alpha_tv)
poly_ids = [ mkUserId name forall_a_a (prag_info_fn name)
tcTySigs (Sig v ty _ src_loc : other_sigs)
= tcAddSrcLoc src_loc (
tcPolyType ty `thenTc` \ sigma_ty ->
- tcInstType [] sigma_ty `thenNF_Tc` \ tc_sigma_ty ->
+ tcInstType [] sigma_ty `thenNF_Tc` \ sigma_ty' ->
let
- (tyvars, theta, tau_ty) = splitSigmaTy tc_sigma_ty
+ (tyvars', theta', tau') = splitSigmaTy sigma_ty'
in
+
tcLookupLocalValueOK "tcSig1" v `thenNF_Tc` \ val ->
- unifyTauTy (idType val) tau_ty `thenTc_`
- returnTc (TySigInfo val tyvars theta tau_ty src_loc)
+ unifyTauTy (idType val) tau' `thenTc_`
+
+ returnTc (TySigInfo val tyvars' theta' tau' src_loc)
) `thenTc` \ sig_info1 ->
tcTySigs other_sigs `thenTc` \ sig_infos ->
-- Get and instantiate its alleged specialised type
tcPolyType poly_ty `thenTc` \ sig_sigma ->
- tcInstType [] (idType sig_sigma) `thenNF_Tc` \ sig_ty ->
+ tcInstType [] sig_sigma `thenNF_Tc` \ sig_ty ->
let
(sig_tyvars, sig_theta, sig_tau) = splitSigmaTy sig_ty
origin = ValSpecOrigin name
-- Check that the specialised type is indeed an instance of
-- the type of the main function.
- unifyTauTy sig_tau main_tau `thenTc_`
- checkSigTyVars sig_tyvars sig_tau main_tau `thenTc_`
+ unifyTauTy sig_tau main_tau `thenTc_`
+ checkSigTyVars sig_tyvars sig_tau `thenTc_`
-- Check that the type variables of the polymorphic function are
-- either left polymorphic, or instantiate to ground type.
-- Check that it has the correct type, and doesn't constrain the
-- signature variables at all
- unifyTauTy sig_tau spec_tau `thenTc_`
- checkSigTyVars sig_tyvars sig_tau spec_tau `thenTc_`
+ unifyTauTy sig_tau spec_tau `thenTc_`
+ checkSigTyVars sig_tyvars sig_tau `thenTc_`
-- Make a local SpecId to bind to applied spec_id
newSpecId main_id main_arg_tys sig_ty `thenNF_Tc` \ local_spec_id ->
mkHsTyApp, mkHsTyLam, mkHsDictApp, mkHsDictLam, unZonkId )
import TcMonad
-import GenSpecEtc ( specTy )
import Inst ( Inst, InstOrigin(..), LIE(..), emptyLIE, plusLIE, newDicts )
import TcEnv ( tcLookupClass, tcLookupTyVar, tcLookupTyCon, newLocalIds)
import TcInstDcls ( processInstBinds )
import TcKind ( unifyKind )
import TcMonoType ( tcMonoType, tcContext )
-import TcType ( TcTyVar(..), tcInstType, tcInstTyVar )
+import TcType ( TcType(..), TcTyVar(..), tcInstType, tcInstSigTyVars )
import TcKind ( TcKind )
import Bag ( foldBag )
tcClassDecl2 (ClassDecl context class_name
tyvar_name class_sigs default_binds pragmas src_loc)
+
+ | not (isLocallyDefined class_name)
+ = returnNF_Tc (emptyLIE, EmptyBinds)
+
+ | otherwise -- It is locally defined
= recoverNF_Tc (returnNF_Tc (emptyLIE, EmptyBinds)) $
tcAddSrcLoc src_loc $
(tyvar, scs, sc_sel_ids, ops, op_sel_ids, defm_ids)
= getClassBigSig clas
in
- tcInstTyVar tyvar `thenNF_Tc` \ clas_tyvar ->
+ tcInstSigTyVars [tyvar] `thenNF_Tc` \ ([clas_tyvar], _, _) ->
-- Generate bindings for the selector functions
- buildSelectors clas clas_tyvar scs sc_sel_ids ops op_sel_ids
- `thenNF_Tc` \ sel_binds ->
+ buildSelectors clas tyvar clas_tyvar scs sc_sel_ids ops op_sel_ids
+ `thenNF_Tc` \ sel_binds ->
-- Ditto for the methods
buildDefaultMethodBinds clas clas_tyvar defm_ids default_binds
- `thenTc` \ (const_insts, meth_binds) ->
+ `thenTc` \ (const_insts, meth_binds) ->
returnTc (const_insts, sel_binds `ThenBinds` meth_binds)
\end{code}
\begin{code}
buildSelectors :: Class -- The class object
- -> TcTyVar s -- Class type variable
+ -> TyVar -- Class type variable
+ -> TcTyVar s -- Instantiated class type variable (TyVarTy)
-> [Class] -> [Id] -- Superclasses and selectors
-> [ClassOp] -> [Id] -- Class ops and selectors
-> NF_TcM s (TcHsBinds s)
-buildSelectors clas clas_tyvar scs sc_sel_ids ops op_sel_ids
+buildSelectors clas clas_tyvar clas_tc_tyvar scs sc_sel_ids ops op_sel_ids
=
-- Make new Ids for the components of the dictionary
- mapNF_Tc (tcInstType [] . getClassOpLocalType) ops `thenNF_Tc` \ op_tys ->
-
+ let
+ clas_tyvar_ty = mkTyVarTy clas_tc_tyvar
+ mk_op_ty = tcInstType [(clas_tyvar, clas_tyvar_ty)] . getClassOpLocalType
+ in
+ mapNF_Tc mk_op_ty ops `thenNF_Tc` \ op_tys ->
newLocalIds (map getClassOpString ops) op_tys `thenNF_Tc` \ method_ids ->
newDicts ClassDeclOrigin
- [ (super_clas, mkTyVarTy clas_tyvar)
+ [ (super_clas, clas_tyvar_ty)
| super_clas <- scs ] `thenNF_Tc` \ (_,dict_ids) ->
newDicts ClassDeclOrigin
- [ (clas, mkTyVarTy clas_tyvar) ] `thenNF_Tc` \ (_,[clas_dict]) ->
+ [ (clas, clas_tyvar_ty) ] `thenNF_Tc` \ (_,[clas_dict]) ->
-- Make suitable bindings for the selectors
let
mk_sel sel_id method_or_dict
- = mkSelBind sel_id clas_tyvar clas_dict dict_ids method_ids method_or_dict
+ = mkSelBind sel_id clas_tc_tyvar clas_dict dict_ids method_ids method_or_dict
in
listNF_Tc (zipWithEqual mk_sel op_sel_ids method_ids) `thenNF_Tc` \ op_sel_binds ->
listNF_Tc (zipWithEqual mk_sel sc_sel_ids dict_ids) `thenNF_Tc` \ sc_sel_binds ->
= /\ a -> \ dfoo_a ->
let rec
op1 = defm.Foo.op1 [a] dfoo_list
- op2 = /\b -> defm.Foo.op2 [a] b dfoo_list
+ op2 = /\b -> \dord -> defm.Foo.op2 [a] b dfoo_list dord
dfoo_list = (op1, op2)
in
dfoo_list
-> NF_TcM s (TcExpr s)
makeClassDeclDefaultMethodRhs clas method_ids tag
- = specTy ClassDeclOrigin (idType method_id) `thenNF_Tc` \ (tyvars, dicts, tau, dict_ids) ->
+ = tcInstType [] (idType method_id) `thenNF_Tc` \ method_ty ->
+ let
+ (tyvars, theta, tau) = splitSigmaTy method_ty
+ in
+ newDicts ClassDeclOrigin theta `thenNF_Tc` \ (lie, dict_ids) ->
returnNF_Tc (mkHsTyLam tyvars (
mkHsDictLam dict_ids (
import Bag ( Bag, isEmptyBag, unionBags, listToBag )
import Class ( GenClass, getClassKey )
-import ErrUtils ( pprBagOfErrors, addErrLoc, TcError(..) )
-import Id ( getDataConSig, getDataConArity )
+import ErrUtils ( pprBagOfErrors, addErrLoc )
+import Id ( dataConSig, dataConArity )
import Maybes ( assocMaybe, maybeToBool, Maybe(..) )
import Name ( Name(..) )
import NameTypes ( mkPreludeCoreName, Provenance(..) )
import Pretty
import ProtoName ( eqProtoName, ProtoName(..), Name )
import SrcLoc ( mkGeneratedSrcLoc, mkUnknownSrcLoc, SrcLoc )
-import TyCon ( getTyConTyVars, getTyConDataCons, getTyConDerivings,
+import TyCon ( tyConTyVars, tyConDataCons, tyConDerivings,
maybeTyConSingleCon, isEnumerationTyCon, TyCon )
import Type ( GenType(..), TauType(..), mkTyVarTys, applyTyCon,
mkSigmaTy, mkDictTy, isPrimType, instantiateTy,
need_deriving tycons_to_consider
= foldr ( \ tycon acc ->
- case (getTyConDerivings tycon) of
+ case (tyConDerivings tycon) of
[] -> acc
cs -> [ (clas,tycon) | clas <- cs ] ++ acc
)
mk_eqn (clas, tycon)
= (clas, tycon, tyvars, constraints)
where
- tyvars = getTyConTyVars tycon -- ToDo: Do we need new tyvars ???
+ tyvars = tyConTyVars tycon -- ToDo: Do we need new tyvars ???
tyvar_tys = mkTyVarTys tyvars
- data_cons = getTyConDataCons tycon
+ data_cons = tyConDataCons tycon
constraints = concat (map mk_constraints data_cons)
mk_constraints data_con
not (isPrimType arg_ty) -- No constraints for primitive types
]
where
- (con_tyvars, _, arg_tys, _) = getDataConSig data_con
+ (con_tyvars, _, arg_tys, _) = dataConSig data_con
inst_env = con_tyvars `zipEqual` tyvar_tys
-- same number of tyvars in data constr and type constr!
\end{code}
where
do_con2tag acc_Names tycon
= if (we_are_deriving eqClassKey tycon
- && any ( (== 0).getDataConArity ) (getTyConDataCons tycon))
+ && any ( (== 0).dataConArity ) (tyConDataCons tycon))
|| (we_are_deriving ordClassKey tycon
&& not (maybeToBool (maybeTyConSingleCon tycon)))
|| (we_are_deriving enumClassKey tycon)
tcExtendGlobalValEnv, tcExtendLocalValEnv,
tcLookupLocalValue, tcLookupLocalValueOK, tcLookupLocalValueByKey,
- tcLookupGlobalValue, tcLookupGlobalValueByKey,
+ tcLookupGlobalValue, tcLookupGlobalValueByKey, tcGlobalOcc,
newMonoIds, newLocalIds, newLocalId,
tcGetGlobalTyVars
import Id ( Id(..), GenId, idType, mkUserLocal )
import TcHsSyn ( TcIdBndr(..), TcIdOcc(..) )
-import TcKind ( TcKind, newKindVars, tcKindToKind, kindToTcKind )
-import TcType ( TcType(..), TcMaybe, TcTyVar(..), TcTyVarSet(..), newTyVarTys, zonkTcTyVars )
+import TcKind ( TcKind, newKindVars, tcDefaultKind, kindToTcKind )
+import TcType ( TcType(..), TcMaybe, TcTyVar(..), TcTyVarSet(..),
+ newTyVarTys, tcInstTyVars, tcInstType, zonkTcTyVars
+ )
import TyVar ( mkTyVar, getTyVarKind, unionTyVarSets, emptyTyVarSet )
import Type ( tyVarsOfTypes )
-import TyCon ( TyCon, Arity(..), getTyConKind, getSynTyConArity )
+import TyCon ( TyCon, Arity(..), tyConKind, synTyConArity )
import Class ( Class(..), GenClass, getClassSig )
import TcMonad
import Name ( Name(..), getNameShortName )
import PprStyle
import Pretty
+import Type ( splitForAllTy )
import Unique ( Unique )
import UniqFM
-import Util ( zipWithEqual, zipWith3Equal, zipLazy, panic )
+import Util ( zipWithEqual, zipWith3Equal, zipLazy, panic, pprPanic )
\end{code}
Data type declarations
(thing_inside rec_tyvars) `thenTc` \ result ->
-- Get the tyvar's Kinds from their TcKinds
- mapNF_Tc tcKindToKind kinds `thenNF_Tc` \ kinds' ->
+ mapNF_Tc tcDefaultKind kinds `thenNF_Tc` \ kinds' ->
-- Construct the real TyVars
let
(kinds `zipLazy` tycons)
]
in
- tcSetEnv (TcEnv tve tce' ce gve lve gtvs) scope
+ tcSetEnv (TcEnv tve tce' ce gve lve gtvs) scope `thenTc` \ result ->
+ mapNF_Tc tcDefaultKind kinds `thenNF_Tc_`
+ returnTc result
+
tcExtendClassEnv :: [Name] -> [Class] -> TcM s r -> TcM s r
tcExtendClassEnv names classes scope
let
ce' = addListToUFM ce (names `zip` (kinds `zipLazy` classes))
in
- tcSetEnv (TcEnv tve tce ce' gve lve gtvs) scope
+ tcSetEnv (TcEnv tve tce ce' gve lve gtvs) scope `thenTc` \ result ->
+ mapNF_Tc tcDefaultKind kinds `thenNF_Tc_`
+ returnTc result
\end{code}
tcLookupTyCon (WiredInTyCon tc) -- wired in tycons
- = returnNF_Tc (kindToTcKind (getTyConKind tc), getSynTyConArity tc, tc)
+ = returnNF_Tc (kindToTcKind (tyConKind tc), synTyConArity tc, tc)
tcLookupTyCon name
= tcGetEnv `thenNF_Tc` \ (TcEnv tve tce ce gve lve gtvs) ->
tcLookupTyConByKey uniq
= tcGetEnv `thenNF_Tc` \ (TcEnv tve tce ce gve lve gtvs) ->
let
- (kind, arity, tycon) = lookupWithDefaultUFM_Directly tce (panic "tcLookupTyCon") uniq
+ (kind, arity, tycon) = lookupWithDefaultUFM_Directly tce
+ (pprPanic "tcLookupTyCon:" (ppr PprDebug uniq))
+ uniq
in
returnNF_Tc tycon
tcLookupClassByKey uniq
= tcGetEnv `thenNF_Tc` \ (TcEnv tve tce ce gve lve gtvs) ->
let
- (kind, clas) = lookupWithDefaultUFM_Directly ce (panic "tcLookupClas") uniq
+ (kind, clas) = lookupWithDefaultUFM_Directly ce
+ (pprPanic "tcLookupClas:" (ppr PprDebug uniq))
+ uniq
in
returnNF_Tc clas
\end{code}
returnNF_Tc (lookupWithDefaultUFM gve def name)
where
#ifdef DEBUG
- def = panic ("tcLookupGlobalValue:" ++ ppShow 1000 (ppr PprDebug name))
+ def = pprPanic "tcLookupGlobalValue:" (ppr PprDebug name)
#else
def = panic "tcLookupGlobalValue"
#endif
+-- A useful function that takes an occurrence of a global thing
+-- and instantiates its type with fresh type variables
+tcGlobalOcc :: Name
+ -> NF_TcM s (Id, -- The Id
+ [TcType s], -- Instance types
+ TcType s) -- Rest of its type
+
+tcGlobalOcc name
+ = tcLookupGlobalValue name `thenNF_Tc` \ id ->
+ let
+ (tyvars, rho) = splitForAllTy (idType id)
+ in
+ tcInstTyVars tyvars `thenNF_Tc` \ (tyvars', arg_tys, tenv) ->
+ tcInstType tenv rho `thenNF_Tc` \ rho' ->
+ returnNF_Tc (id, arg_tys, rho')
+
tcLookupGlobalValueByKey :: Unique -> NF_TcM s Id
tcLookupGlobalValueByKey uniq
returnNF_Tc (lookupWithDefaultUFM_Directly gve def uniq)
where
#ifdef DEBUG
- def = panic ("tcLookupGlobalValueByKey:" ++ ppShow 1000 (ppr PprDebug uniq))
+ def = pprPanic "tcLookupGlobalValueByKey:" (ppr PprDebug uniq)
#else
def = panic "tcLookupGlobalValueByKey"
#endif
ArithSeqInfo(..), HsLit(..), Sig, GRHSsAndBinds,
Match, Fake, InPat, OutPat, PolyType,
irrefutablePat, collectPatBinders )
-import RnHsSyn ( RenamedHsExpr(..), RenamedQual(..), RenamedStmt(..) )
-import TcHsSyn ( TcExpr(..), TcQual(..), TcStmt(..), TcIdOcc(..) )
+import RnHsSyn ( RenamedHsExpr(..), RenamedQual(..),
+ RenamedStmt(..), RenamedRecordBinds(..)
+ )
+import TcHsSyn ( TcExpr(..), TcQual(..), TcStmt(..),
+ TcIdOcc(..), TcRecordBinds(..),
+ mkHsTyApp
+ )
import TcMonad
import Inst ( Inst, InstOrigin(..), OverloadedLit(..),
- LIE(..), emptyLIE, plusLIE, newOverloadedLit,
+ LIE(..), emptyLIE, plusLIE, plusLIEs, newOverloadedLit,
newMethod, newMethodWithGivenTy, newDicts )
import TcBinds ( tcBindsAndThen )
import TcEnv ( tcLookupLocalValue, tcLookupGlobalValue, tcLookupClassByKey,
- tcLookupGlobalValueByKey, newMonoIds, tcGetGlobalTyVars )
+ tcLookupGlobalValueByKey, newMonoIds, tcGetGlobalTyVars,
+ tcGlobalOcc
+ )
import TcMatches ( tcMatchesCase, tcMatch )
import TcMonoType ( tcPolyType )
import TcPat ( tcPat )
import TcSimplify ( tcSimplifyAndCheck, tcSimplifyRank2 )
-import TcType ( TcType(..), TcMaybe(..), tcReadTyVar,
- tcInstType, tcInstTcType,
- tcInstTyVar, newTyVarTy, zonkTcTyVars )
+import TcType ( TcType(..), TcMaybe(..),
+ tcInstType, tcInstTcType, tcInstTyVars,
+ newTyVarTy, zonkTcTyVars, zonkTcType )
import TcKind ( TcKind )
import Class ( Class(..), getClassSig )
-import Id ( Id(..), GenId, idType )
-import Kind ( Kind, mkBoxedTypeKind, mkTypeKind )
-import GenSpecEtc ( checkSigTyVars, checkSigTyVarsGivenGlobals, specTy )
+import FieldLabel ( fieldLabelName )
+import Id ( Id(..), GenId, idType, dataConFieldLabels )
+import Kind ( Kind, mkBoxedTypeKind, mkTypeKind, mkArrowKind )
+import GenSpecEtc ( checkSigTyVars, checkSigTyVarsGivenGlobals )
import PrelInfo ( intPrimTy, charPrimTy, doublePrimTy,
floatPrimTy, addrPrimTy, addrTy,
boolTy, charTy, stringTy, mkListTy,
mkTupleTy, mkPrimIoTy )
import Type ( mkFunTy, mkAppTy, mkTyVarTy, mkTyVarTys,
getTyVar_maybe, getFunTy_maybe,
- splitForAllTy, splitRhoTy, splitSigmaTy,
- isTauTy, mkFunTys, tyVarsOfType, getForAllTy_maybe )
+ splitForAllTy, splitRhoTy, splitSigmaTy, splitFunTy,
+ isTauTy, mkFunTys, tyVarsOfType, getForAllTy_maybe,
+ maybeAppDataTyCon
+ )
import TyVar ( GenTyVar, TyVarSet(..), unionTyVarSets, mkTyVarSet )
-import Unify ( unifyTauTy, unifyTauTyList, unifyTauTyLists )
+import Unify ( unifyTauTy, unifyTauTyList, unifyTauTyLists, unifyFunTy )
import Unique ( Unique, cCallableClassKey, cReturnableClassKey,
enumFromClassOpKey, enumFromThenClassOpKey,
enumFromToClassOpKey, enumFromThenToClassOpKey,
monadClassKey, monadZeroClassKey )
import Name ( Name ) -- Instance
+import Outputable ( interpp'SP )
import PprType ( GenType, GenTyVar ) -- Instances
import Maybes ( maybeToBool )
import Pretty
= -- get the Monad and MonadZero classes
-- create type consisting of a fresh monad tyvar
tcAddSrcLoc src_loc $
- tcLookupClassByKey monadClassKey `thenNF_Tc` \ monadClass ->
- tcLookupClassByKey monadZeroClassKey `thenNF_Tc` \ monadZeroClass ->
- let
- (tv,_,_) = getClassSig monadClass
- in
- tcInstTyVar tv `thenNF_Tc` \ m_tyvar ->
- let
- m = mkTyVarTy m_tyvar
- in
- tcDoStmts False m stmts `thenTc` \ ((stmts',monad,mzero), lie, do_ty) ->
+ newTyVarTy monadKind `thenNF_Tc` \ m ->
+ tcDoStmts False m stmts `thenTc` \ ((stmts',monad,mzero), lie, do_ty) ->
-- create dictionaries for monad and possibly monadzero
(if monad then
+ tcLookupClassByKey monadClassKey `thenNF_Tc` \ monadClass ->
newDicts DoOrigin [(monadClass, m)]
else
returnNF_Tc (emptyLIE, [panic "TcExpr: MonadZero dictionary"])
) `thenNF_Tc` \ (m_lie, [m_id]) ->
(if mzero then
+ tcLookupClassByKey monadZeroClassKey `thenNF_Tc` \ monadZeroClass ->
newDicts DoOrigin [(monadZeroClass, m)]
else
returnNF_Tc (emptyLIE, [panic "TcExpr: MonadZero dictionary"])
returnTc (HsDoOut stmts' m_id mz_id src_loc,
lie `plusLIE` m_lie `plusLIE` mz_lie,
do_ty)
+ where
+ monadKind = mkArrowKind mkBoxedTypeKind mkBoxedTypeKind
\end{code}
\begin{code}
= tcExprs exprs `thenTc` \ (exprs', lie, tys) ->
returnTc (ExplicitTuple exprs', lie, mkTupleTy (length tys) tys)
-tcExpr (RecordCon con rbinds)
- = panic "tcExpr:RecordCon"
-tcExpr (RecordUpd exp rbinds)
- = panic "tcExpr:RecordUpd"
+tcExpr (RecordCon (HsVar con) rbinds)
+ = tcGlobalOcc con `thenNF_Tc` \ (con_id, arg_tys, con_rho) ->
+ let
+ (con_theta, con_tau) = splitRhoTy con_rho
+ (_, record_ty) = splitFunTy con_tau
+ con_expr = mkHsTyApp (HsVar (RealId con_id)) arg_tys
+ in
+ -- TEMPORARY ASSERT
+ ASSERT( null con_theta )
+
+ -- Con is syntactically constrained to be a data constructor
+ ASSERT( maybeToBool (maybeAppDataTyCon record_ty ) )
+
+ tcRecordBinds record_ty rbinds `thenTc` \ (rbinds', rbinds_lie) ->
+
+ checkTc (checkRecordFields rbinds con_id)
+ (badFieldsCon con rbinds) `thenTc_`
+
+ returnTc (RecordCon con_expr rbinds', panic "tcExpr:RecordCon:con_lie???" {-con_lie???-} `plusLIE` rbinds_lie, record_ty)
+
+tcExpr (RecordUpd record_expr rbinds)
+ = tcExpr record_expr `thenTc` \ (record_expr', record_lie, record_ty) ->
+ tcRecordBinds record_ty rbinds `thenTc` \ (rbinds', rbinds_lie) ->
+
+ -- Check that the field names are plausible
+ zonkTcType record_ty `thenNF_Tc` \ record_ty' ->
+ let
+ maybe_tycon_stuff = maybeAppDataTyCon record_ty'
+ Just (tycon, args_tys, data_cons) = maybe_tycon_stuff
+ in
+ checkTc (maybeToBool maybe_tycon_stuff)
+ (panic "TcExpr:Records:mystery error message") `thenTc_`
+ checkTc (any (checkRecordFields rbinds) data_cons)
+ (badFieldsUpd rbinds) `thenTc_`
+ returnTc (RecordUpd record_expr' rbinds', record_lie `plusLIE` rbinds_lie, record_ty)
tcExpr (ArithSeqIn seq@(From expr))
= tcExpr expr `thenTc` \ (expr', lie1, ty) ->
-- Check the tau-type part
tcSetErrCtxt (exprSigCtxt in_expr) $
- specTy SignatureOrigin sigma_sig `thenNF_Tc` \ (sig_tyvars, sig_dicts, sig_tau, _) ->
- unifyTauTy tau_ty sig_tau `thenTc_`
+ tcInstType [] sigma_sig `thenNF_Tc` \ sigma_sig' ->
+ let
+ (sig_tyvars', sig_theta', sig_tau') = splitSigmaTy sigma_sig'
+ in
+ unifyTauTy tau_ty sig_tau' `thenTc_`
-- Check the type variables of the signature
- checkSigTyVars sig_tyvars sig_tau tau_ty `thenTc` \ sig_tyvars' ->
+ checkSigTyVars sig_tyvars' sig_tau' `thenTc_`
-- Check overloading constraints
+ newDicts SignatureOrigin sig_theta' `thenNF_Tc` \ (sig_dicts, _) ->
tcSimplifyAndCheck
(mkTyVarSet sig_tyvars')
sig_dicts lie `thenTc_`
tcApp_help orig_fun arg_no fun_ty []
= returnTc ([], emptyLIE, fun_ty)
-tcApp_help orig_fun arg_no fun_ty (arg:args)
- | maybeToBool maybe_arrow_ty
- = -- The function's type is A->B
+tcApp_help orig_fun arg_no fun_ty all_args@(arg:args)
+ = -- Expect the function to have type A->B
+ tcAddErrCtxt (tooManyArgsCtxt orig_fun) (
+ unifyFunTy fun_ty
+ ) `thenTc` \ (expected_arg_ty, result_ty) ->
+
+ -- Type check the argument
tcAddErrCtxt (funAppCtxt orig_fun arg_no arg) (
- tcArg expected_arg_ty arg
- ) `thenTc` \ (arg', lie_arg) ->
+ tcArg expected_arg_ty arg
+ ) `thenTc` \ (arg', lie_arg) ->
+ -- Do the other args
tcApp_help orig_fun (arg_no+1) result_ty args `thenTc` \ (args', lie_args, res_ty) ->
- returnTc (arg':args', lie_arg `plusLIE` lie_args, res_ty)
-
- | maybeToBool maybe_tyvar_ty
- = -- The function's type is just a type variable
- tcReadTyVar fun_tyvar `thenNF_Tc` \ maybe_fun_ty ->
- case maybe_fun_ty of
-
- BoundTo new_fun_ty -> -- The tyvar in the corner of the function is bound
- -- to something ... so carry on ....
- tcApp_help orig_fun arg_no new_fun_ty (arg:args)
-
- UnBound -> -- Extra args match against an unbound type
- -- variable as the final result type, so unify the tyvar.
- newTyVarTy mkTypeKind `thenNF_Tc` \ result_ty ->
- tcExprs args `thenTc` \ (args', lie_args, arg_tys) ->
-
- -- Unification can't fail, since we're unifying against a tyvar
- unifyTauTy fun_ty (mkFunTys arg_tys result_ty) `thenTc_`
-
- returnTc (args', lie_args, result_ty)
-
- | otherwise
- = -- Must be an error: a lurking for-all, or (more commonly)
- -- a TyConTy... we've applied the function to too many args
- failTc (tooManyArgs orig_fun)
- where
- maybe_arrow_ty = getFunTy_maybe fun_ty
- Just (expected_arg_ty, result_ty) = maybe_arrow_ty
+ -- Done
+ returnTc (arg':args', lie_arg `plusLIE` lie_args, res_ty)
- maybe_tyvar_ty = getTyVar_maybe fun_ty
- Just fun_tyvar = maybe_tyvar_ty
\end{code}
\begin{code}
let
(expected_tyvars, expected_theta, expected_tau) = splitSigmaTy expected_arg_ty
in
- ASSERT( null expected_theta )
+ ASSERT( null expected_theta ) -- And expected_tyvars are all DontBind things
-- Type-check the arg and unify with expected type
tcExpr arg `thenTc` \ (arg', lie_arg, actual_arg_ty) ->
zonkTcTyVars (tyVarsOfType expected_arg_ty) `thenNF_Tc` \ free_tyvars ->
checkSigTyVarsGivenGlobals
(env_tyvars `unionTyVarSets` free_tyvars)
- expected_tyvars expected_tau actual_arg_ty `thenTc` \ arg_tyvars' ->
+ expected_tyvars expected_tau `thenTc_`
-- Check that there's no overloading involved
- -- Even if there isn't, there may be some Insts which mention the arg_tyvars,
+ -- Even if there isn't, there may be some Insts which mention the expected_tyvars,
-- but which, on simplification, don't actually need a dictionary involving
-- the tyvar. So we have to do a proper simplification right here.
- tcSimplifyRank2 (mkTyVarSet arg_tyvars')
+ tcSimplifyRank2 (mkTyVarSet expected_tyvars)
lie_arg `thenTc` \ (free_insts, inst_binds) ->
-- This HsLet binds any Insts which came out of the simplification.
-- It's a bit out of place here, but using AbsBind involves inventing
-- a couple of new names which seems worse.
- returnTc (TyLam arg_tyvars' (HsLet (mk_binds inst_binds) arg'), free_insts)
+ returnTc (TyLam expected_tyvars (HsLet (mk_binds inst_binds) arg'), free_insts)
)
where
tcId :: Name -> TcM s (TcExpr s, LIE s, TcType s)
tcId name
= -- Look up the Id and instantiate its type
- (tcLookupLocalValue name `thenNF_Tc` \ maybe_local ->
- case maybe_local of
- Just tc_id -> tcInstTcType [] (idType tc_id) `thenNF_Tc` \ ty ->
- returnNF_Tc (TcId tc_id, ty)
-
- Nothing -> tcLookupGlobalValue name `thenNF_Tc` \ id ->
- tcInstType [] (idType id) `thenNF_Tc` \ ty ->
- returnNF_Tc (RealId id, ty)
- ) `thenNF_Tc` \ (tc_id_occ, ty) ->
- let
- (tyvars, rho) = splitForAllTy ty
- (theta,tau) = splitRhoTy rho
- arg_tys = mkTyVarTys tyvars
- in
+ tcLookupLocalValue name `thenNF_Tc` \ maybe_local ->
+
+ (case maybe_local of
+ Just tc_id -> let
+ (tyvars, rho) = splitForAllTy (idType tc_id)
+ in
+ tcInstTyVars tyvars `thenNF_Tc` \ (tyvars', arg_tys', tenv) ->
+ tcInstTcType tenv rho `thenNF_Tc` \ rho' ->
+ returnNF_Tc (TcId tc_id, arg_tys', rho')
+
+ Nothing -> tcGlobalOcc name `thenNF_Tc` \ (id, arg_tys, rho) ->
+ returnNF_Tc (RealId id, arg_tys, rho)
+
+ ) `thenNF_Tc` \ (tc_id_occ, arg_tys, rho) ->
+
-- Is it overloaded?
- case theta of
- [] -> -- Not overloaded, so just make a type application
- returnTc (TyApp (HsVar tc_id_occ) arg_tys, emptyLIE, tau)
-
- _ -> -- Overloaded, so make a Method inst
- newMethodWithGivenTy (OccurrenceOf tc_id_occ)
- tc_id_occ arg_tys rho `thenNF_Tc` \ (lie, meth_id) ->
- returnTc (HsVar meth_id, lie, tau)
+ case splitRhoTy rho of
+ ([], tau) -> -- Not overloaded, so just make a type application
+ returnTc (mkHsTyApp (HsVar tc_id_occ) arg_tys, emptyLIE, tau)
+
+ (theta, tau) -> -- Overloaded, so make a Method inst
+ newMethodWithGivenTy (OccurrenceOf tc_id_occ)
+ tc_id_occ arg_tys rho `thenNF_Tc` \ (lie, meth_id) ->
+ returnTc (HsVar meth_id, lie, tau)
\end{code}
\end{code}
+Game plan for record bindings
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+For each binding
+ field = value
+1. look up "field", to find its selector Id, which must have type
+ forall a1..an. T a1 .. an -> tau
+ where tau is the type of the field.
+
+2. Instantiate this type
+
+3. Unify the (T a1 .. an) part with the "expected result type", which
+ is passed in. This checks that all the field labels come from the
+ same type.
+
+4. Type check the value using tcArg, passing tau as the expected
+ argument type.
+
+This extends OK when the field types are universally quantified.
+
+Actually, to save excessive creation of fresh type variables,
+we
+
+\begin{code}
+tcRecordBinds
+ :: TcType s -- Expected type of whole record
+ -> RenamedRecordBinds
+ -> TcM s (TcRecordBinds s, LIE s)
+
+tcRecordBinds expected_record_ty rbinds
+ = mapAndUnzipTc do_bind rbinds `thenTc` \ (rbinds', lies) ->
+ returnTc (rbinds', plusLIEs lies)
+ where
+ do_bind (field_label, rhs, pun_flag)
+ = tcGlobalOcc field_label `thenNF_Tc` \ (sel_id, _, tau) ->
+
+ -- Record selectors all have type
+ -- forall a1..an. T a1 .. an -> tau
+ ASSERT( maybeToBool (getFunTy_maybe tau) )
+ let
+ -- Selector must have type RecordType -> FieldType
+ Just (record_ty, field_ty) = getFunTy_maybe tau
+ in
+ unifyTauTy expected_record_ty record_ty `thenTc_`
+ tcArg field_ty rhs `thenTc` \ (rhs', lie) ->
+ returnTc ((RealId sel_id, rhs', pun_flag), lie)
+
+checkRecordFields :: RenamedRecordBinds -> Id -> Bool -- True iff all the fields in
+ -- RecordBinds are field of the
+ -- specified constructor
+checkRecordFields rbinds data_con
+ = all ok rbinds
+ where
+ data_con_fields = dataConFieldLabels data_con
+
+ ok (field_name, _, _) = any (match field_name) data_con_fields
+
+ match field_name field_label = field_name == fieldLabelName field_label
+\end{code}
+
%************************************************************************
%* *
\subsection{@tcExprs@ typechecks a {\em list} of expressions}
= ppHang (ppStr "In a do statement:")
4 (ppr sty stmt)
-tooManyArgs f sty
+tooManyArgsCtxt f sty
= ppHang (ppStr "Too many arguments in an application of the function")
4 (ppr sty f)
= ppHang (ppStr "In a polymorphic function argument:")
4 (ppSep [ppBeside (ppr sty arg) (ppStr " ::"),
ppr sty expected_arg_ty])
-\end{code}
+badFieldsUpd rbinds sty
+ = ppHang (ppStr "In a record update construct, no constructor has all these fields:")
+ 4 (interpp'SP sty fields)
+ where
+ fields = [field | (field, _, _) <- rbinds]
+
+badFieldsCon con rbinds sty
+ = ppHang (ppBesides [ppStr "Inconsistent constructor:", ppr sty con])
+ 4 (ppBesides [ppStr "and fields:", interpp'SP sty fields])
+ where
+ fields = [field | (field, _, _) <- rbinds]
+\end{code}
import RnMonad4 -- initRn4, etc.
import RnUtils
-import Id ( GenId, getDataConArity, getDataConTag,
- getDataConSig, fIRST_TAG,
+import Id ( GenId, dataConArity, dataConTag,
+ dataConSig, fIRST_TAG,
isDataCon, DataCon(..), ConTag(..) )
import IdUtils ( primOpId )
import Maybes ( maybeToBool )
import Pretty
import ProtoName ( ProtoName(..) )
import SrcLoc ( mkGeneratedSrcLoc )
-import TyCon ( TyCon, getTyConDataCons, isEnumerationTyCon, maybeTyConSingleCon )
+import TyCon ( TyCon, tyConDataCons, isEnumerationTyCon, maybeTyConSingleCon )
import Type ( eqTy, isPrimType )
import Unique
import Util
gen_Eq_binds :: TyCon -> ProtoNameMonoBinds
gen_Eq_binds tycon
- = case (partition (\ con -> getDataConArity con == 0)
- (getTyConDataCons tycon))
+ = case (partition (\ con -> dataConArity con == 0)
+ (tyConDataCons tycon))
of { (nullary_cons, nonnullary_cons) ->
let
rest
con2_pat = ConPatIn data_con_PN (map VarPatIn bs_needed)
data_con_PN = Prel (WiredInVal data_con)
- as_needed = take (getDataConArity data_con) as_PNs
- bs_needed = take (getDataConArity data_con) bs_PNs
- tys_needed = case (getDataConSig data_con) of
+ as_needed = take (dataConArity data_con) as_PNs
+ bs_needed = take (dataConArity data_con) bs_PNs
+ tys_needed = case (dataConSig data_con) of
(_,_, arg_tys, _) -> arg_tys
in
([con1_pat, con2_pat], nested_eq_expr tys_needed as_needed bs_needed)
(cmp_tags_Expr ltH_PN ah_PN bh_PN ltTag_Expr gtTag_Expr)))
(nullary_cons, nonnullary_cons)
- = partition (\ con -> getDataConArity con == 0) (getTyConDataCons tycon)
+ = partition (\ con -> dataConArity con == 0) (tyConDataCons tycon)
cmp_eq
= mk_FunMonoBind cmp_eq_PN (map pats_etc nonnullary_cons ++ deflt_pats_etc)
con2_pat = ConPatIn data_con_PN (map VarPatIn bs_needed)
data_con_PN = Prel (WiredInVal data_con)
- as_needed = take (getDataConArity data_con) as_PNs
- bs_needed = take (getDataConArity data_con) bs_PNs
- tys_needed = case (getDataConSig data_con) of
+ as_needed = take (dataConArity data_con) as_PNs
+ bs_needed = take (dataConArity data_con) bs_PNs
+ tys_needed = case (dataConSig data_con) of
(_,_, arg_tys, _) -> arg_tys
nested_compare_expr [ty] [a] [b]
= case maybeTyConSingleCon tycon of -- just checking...
Nothing -> panic "get_Ix_binds"
Just dc -> let
- (_, _, arg_tys, _) = getDataConSig dc
+ (_, _, arg_tys, _) = dataConSig dc
in
if any isPrimType arg_tys then
error ("ERROR: Can't derive Ix for a single-constructor type with primitive argument types: "++tycon_str)
else
dc
- con_arity = getDataConArity data_con
+ con_arity = dataConArity data_con
data_con_PN = Prel (WiredInVal data_con)
con_pat xs = ConPatIn data_con_PN (map VarPatIn xs)
con_expr xs = foldl HsApp (HsVar data_con_PN) (map HsVar xs)
- as_needed = take (getDataConArity data_con) as_PNs
- bs_needed = take (getDataConArity data_con) bs_PNs
- cs_needed = take (getDataConArity data_con) cs_PNs
+ as_needed = take (dataConArity data_con) as_PNs
+ bs_needed = take (dataConArity data_con) bs_PNs
+ cs_needed = take (dataConArity data_con) cs_PNs
--------------------------------------------------------------
single_con_range
reads_prec
= let
read_con_comprehensions
- = map read_con (getTyConDataCons tycon)
+ = map read_con (tyConDataCons tycon)
in
mk_easy_FunMonoBind readsPrec_PN [a_Pat, b_Pat] [] (
foldl1 append_Expr read_con_comprehensions
= let
data_con_PN = Prel (WiredInVal data_con)
data_con_str= snd (getOrigName data_con)
- as_needed = take (getDataConArity data_con) as_PNs
- bs_needed = take (getDataConArity data_con) bs_PNs
+ as_needed = take (dataConArity data_con) as_PNs
+ bs_needed = take (dataConArity data_con) bs_PNs
con_expr = foldl HsApp (HsVar data_con_PN) (map HsVar as_needed)
- nullary_con = getDataConArity data_con == 0
+ nullary_con = dataConArity data_con == 0
con_qual
= GeneratorQual
(HsApp (HsVar _showList_PN) (HsApp (HsVar showsPrec_PN) (HsLit (HsInt 0))))
-----------------------------------------------------------------------
shows_prec
- = mk_FunMonoBind showsPrec_PN (map pats_etc (getTyConDataCons tycon))
+ = mk_FunMonoBind showsPrec_PN (map pats_etc (tyConDataCons tycon))
where
pats_etc data_con
= let
data_con_PN = Prel (WiredInVal data_con)
- bs_needed = take (getDataConArity data_con) bs_PNs
+ bs_needed = take (dataConArity data_con) bs_PNs
con_pat = ConPatIn data_con_PN (map VarPatIn bs_needed)
- nullary_con = getDataConArity data_con == 0
+ nullary_con = dataConArity data_con == 0
show_con
= let (mod, nm) = getOrigName data_con
-> ProtoNameMonoBinds
gen_tag_n_con_monobind (pn, _, tycon, GenCon2Tag)
- = mk_FunMonoBind pn (map mk_stuff (getTyConDataCons tycon))
+ = mk_FunMonoBind pn (map mk_stuff (tyConDataCons tycon))
where
mk_stuff :: DataCon -> ([ProtoNamePat], ProtoNameHsExpr)
mk_stuff var
= ASSERT(isDataCon var)
- ([pat], HsLit (HsIntPrim (toInteger ((getDataConTag var) - fIRST_TAG))))
+ ([pat], HsLit (HsIntPrim (toInteger ((dataConTag var) - fIRST_TAG))))
where
- pat = ConPatIn var_PN (nOfThem (getDataConArity var) WildPatIn)
+ pat = ConPatIn var_PN (nOfThem (dataConArity var) WildPatIn)
var_PN = Prel (WiredInVal var)
gen_tag_n_con_monobind (pn, _, tycon, GenTag2Con)
- = mk_FunMonoBind pn (map mk_stuff (getTyConDataCons tycon))
+ = mk_FunMonoBind pn (map mk_stuff (tyConDataCons tycon))
where
mk_stuff :: DataCon -> ([ProtoNamePat], ProtoNameHsExpr)
= ASSERT(isDataCon var)
([lit_pat], HsVar var_PN)
where
- lit_pat = ConPatIn mkInt_PN [LitPatIn (HsIntPrim (toInteger ((getDataConTag var) - fIRST_TAG)))]
+ lit_pat = ConPatIn mkInt_PN [LitPatIn (HsIntPrim (toInteger ((dataConTag var) - fIRST_TAG)))]
var_PN = Prel (WiredInVal var)
gen_tag_n_con_monobind (pn, _, tycon, GenMaxTag)
= mk_easy_FunMonoBind pn [] [] (HsApp (HsVar mkInt_PN) (HsLit (HsIntPrim max_tag)))
where
- max_tag = case (getTyConDataCons tycon) of
+ max_tag = case (tyConDataCons tycon) of
data_cons -> toInteger ((length data_cons) - fIRST_TAG)
\end{code}
module TcHsSyn (
TcIdBndr(..), TcIdOcc(..),
- TcMonoBinds(..), TcHsBinds(..), TcBind(..), TcPat(..), TcExpr(..), TcGRHSsAndBinds(..),
- TcGRHS(..), TcMatch(..), TcQual(..), TcStmt(..), TcArithSeqInfo(..), TcHsModule(..),
+ TcMonoBinds(..), TcHsBinds(..), TcBind(..), TcPat(..),
+ TcExpr(..), TcGRHSsAndBinds(..), TcGRHS(..), TcMatch(..),
+ TcQual(..), TcStmt(..), TcArithSeqInfo(..), TcRecordBinds(..),
+ TcHsModule(..),
- TypecheckedHsBinds(..), TypecheckedBind(..), TypecheckedMonoBinds(..),
- TypecheckedPat(..), TypecheckedHsExpr(..), TypecheckedArithSeqInfo(..),
- TypecheckedQual(..), TypecheckedStmt(..), TypecheckedMatch(..),
- TypecheckedHsModule(..), TypecheckedGRHSsAndBinds(..), TypecheckedGRHS(..),
+ TypecheckedHsBinds(..), TypecheckedBind(..),
+ TypecheckedMonoBinds(..), TypecheckedPat(..),
+ TypecheckedHsExpr(..), TypecheckedArithSeqInfo(..),
+ TypecheckedQual(..), TypecheckedStmt(..),
+ TypecheckedMatch(..), TypecheckedHsModule(..),
+ TypecheckedGRHSsAndBinds(..), TypecheckedGRHS(..),
mkHsTyApp, mkHsDictApp,
mkHsTyLam, mkHsDictLam,
+ tcIdType,
zonkBinds,
zonkInst,
-- friends:
import HsSyn -- oodles of it
import Id ( GenId(..), IdDetails, PragmaInfo, -- Can meddle modestly with Ids
- DictVar(..)
+ DictVar(..), idType
)
-- others:
type TcQual s = Qual (TcTyVar s) UVar (TcIdOcc s) (TcPat s)
type TcStmt s = Stmt (TcTyVar s) UVar (TcIdOcc s) (TcPat s)
type TcArithSeqInfo s = ArithSeqInfo (TcTyVar s) UVar (TcIdOcc s) (TcPat s)
+type TcRecordBinds s = HsRecordBinds (TcTyVar s) UVar (TcIdOcc s) (TcPat s)
type TcHsModule s = HsModule (TcTyVar s) UVar (TcIdOcc s) (TcPat s)
type TypecheckedPat = OutPat TyVar UVar Id
mkHsDictLam [] expr = expr
mkHsDictLam dicts expr = DictLam dicts expr
+
+tcIdType :: TcIdOcc s -> TcType s
+tcIdType (TcId id) = idType id
+tcIdType other = panic "tcIdType"
\end{code}
RenamedInstDecl(..), RenamedFixityDecl(..),
RenamedSig(..), RenamedSpecInstSig(..) )
import TcHsSyn ( TcIdOcc(..), TcHsBinds(..),
- TcMonoBinds(..), TcExpr(..),
+ TcMonoBinds(..), TcExpr(..), tcIdType,
mkHsTyLam, mkHsTyApp,
mkHsDictLam, mkHsDictApp )
import TcMonad
-import GenSpecEtc ( checkSigTyVars, specTy )
+import GenSpecEtc ( checkSigTyVars )
import Inst ( Inst, InstOrigin(..), InstanceMapper(..),
newDicts, newMethod, LIE(..), emptyLIE, plusLIE )
import TcBinds ( tcPragmaSigs )
import TcMonoType ( tcContext, tcMonoTypeKind )
import TcSimplify ( tcSimplifyAndCheck, tcSimplifyThetas )
import TcType ( TcType(..), TcTyVar(..),
- tcInstTyVar, tcInstType, tcInstTheta )
+ tcInstSigTyVars, tcInstType, tcInstTheta
+ )
import Unify ( unifyTauTy )
import Outputable
import PrelInfo ( pAT_ERROR_ID )
import PprType ( GenType, GenTyVar, GenClass, GenClassOp, TyCon,
- pprParendType )
+ pprParendGenType )
import PprStyle
import Pretty
import RnUtils ( GlobalNameMappers(..), GlobalNameMapper(..) )
tcAddSrcLoc locn $
-- Get the class signature
- mapNF_Tc tcInstTyVar inst_tyvars `thenNF_Tc` \ inst_tyvars' ->
+ tcInstSigTyVars inst_tyvars `thenNF_Tc` \ (inst_tyvars', _, tenv) ->
let
- tenv = inst_tyvars `zip` (mkTyVarTys inst_tyvars')
-
(class_tyvar,
super_classes, sc_sel_ids,
class_ops, op_sel_ids, defm_ids) = getClassBigSig clas
mk_method_expr
= if opt_OmitDefaultInstanceMethods then
- makeInstanceDeclNoDefaultExpr origin clas meth_ids defm_ids inst_mod inst_ty'
+ makeInstanceDeclNoDefaultExpr origin meth_ids defm_ids inst_ty' clas inst_mod
else
- makeInstanceDeclDefaultMethodExpr origin this_dict_id class_ops defm_ids inst_ty'
+ makeInstanceDeclDefaultMethodExpr origin meth_ids defm_ids inst_ty' this_dict_id
in
processInstBinds mk_method_expr inst_tyvars' avail_insts meth_ids monobinds
`thenTc` \ (insts_needed, method_mbinds) ->
\begin{code}
makeInstanceDeclDefaultMethodExpr
:: InstOrigin s
- -> TcIdOcc s
- -> [ClassOp]
+ -> [TcIdOcc s]
-> [Id]
-> TcType s
+ -> TcIdOcc s
-> Int
-> NF_TcM s (TcExpr s)
-makeInstanceDeclDefaultMethodExpr origin this_dict class_ops defm_ids inst_ty tag
- = specTy origin (getClassOpLocalType class_op)
- `thenNF_Tc` \ (op_tyvars, op_lie, op_tau, op_dicts) ->
+makeInstanceDeclDefaultMethodExpr origin meth_ids defm_ids inst_ty this_dict tag
+ = newDicts origin op_theta `thenNF_Tc` \ (op_lie,op_dicts) ->
-- def_op_id = /\ op_tyvars -> \ op_dicts ->
-- defm_id inst_ty op_tyvars this_dict op_dicts
-
returnNF_Tc (
mkHsTyLam op_tyvars (
mkHsDictLam op_dicts (
(this_dict : op_dicts)
)))
where
- idx = tag - 1
- class_op = class_ops !! idx
- defm_id = defm_ids !! idx
+ idx = tag - 1
+ meth_id = meth_ids !! idx
+ defm_id = defm_ids !! idx
+ (op_tyvars, op_theta, op_tau) = splitSigmaTy (tcIdType meth_id)
makeInstanceDeclNoDefaultExpr
:: InstOrigin s
- -> Class
-> [TcIdOcc s]
-> [Id]
- -> FAST_STRING
-> TcType s
+ -> Class
+ -> FAST_STRING
-> Int
-> NF_TcM s (TcExpr s)
-makeInstanceDeclNoDefaultExpr origin clas method_occs defm_ids inst_mod inst_ty tag
- = let
- (op_tyvars,op_theta,op_tau) = splitSigmaTy (idType method_id)
- in
- newDicts origin op_theta `thenNF_Tc` \ (op_lie,op_dicts) ->
+makeInstanceDeclNoDefaultExpr origin meth_ids defm_ids inst_ty clas inst_mod tag
+ = newDicts origin op_theta `thenNF_Tc` \ (op_lie, op_dicts) ->
-- Produce a warning if the default instance method
-- has been omitted when one exists in the class
HsApp (mkHsTyApp (HsVar (RealId pAT_ERROR_ID)) [op_tau])
(HsLitOut (HsString (_PK_ error_msg)) stringTy))))
where
- idx = tag - 1
- method_occ = method_occs !! idx
- clas_op = (getClassOps clas) !! idx
- defm_id = defm_ids !! idx
+ idx = tag - 1
+ meth_id = meth_ids !! idx
+ clas_op = (getClassOps clas) !! idx
+ defm_id = defm_ids !! idx
+ (op_tyvars,op_theta,op_tau) = splitSigmaTy (tcIdType meth_id)
- TcId method_id = method_occ
Just (_, _, err_defm_ok) = isDefaultMethodId_maybe defm_id
error_msg = "%E" -- => No explicit method for \"
-- Type check the method itself
tcMethodBind method_id method_tau mbind `thenTc` \ (mbind', lieIop) ->
-
- -- Make sure that the instance tyvars havn't been
- -- unified with each other or with the method tyvars.
- tcSetErrCtxt (methodSigCtxt op method_tau) (
- checkSigTyVars inst_tyvars method_tau method_tau
- ) `thenTc_`
returnTc ([tag], lieIop, mbind')
other -> -- It's a locally-polymorphic and/or overloaded method; UGH!
-- Typecheck the method
tcMethodBind local_id method_tau mbind `thenTc` \ (mbind', lieIop) ->
- -- Make sure that the instance tyvars haven't been
- -- unified with each other or with the method tyvars.
- tcAddErrCtxt (methodSigCtxt op method_tau) (
- checkSigTyVars inst_method_tyvars method_tau method_tau
- ) `thenTc_`
-
-- Check the overloading part of the signature.
-- Simplify everything fully, even though some
-- constraints could "really" be left to the next
(ppAboves [ppCat [if null simpl_theta then ppNil else ppr PprDebug simpl_theta,
if null simpl_theta then ppNil else ppStr "=>",
ppr PprDebug clas,
- pprParendType PprDebug inst_ty],
+ pprParendGenType PprDebug inst_ty],
ppCat [ppStr " derived from:",
if null unspec_theta then ppNil else ppr PprDebug unspec_theta,
if null unspec_theta then ppNil else ppStr "=>",
ppr PprDebug clas,
- pprParendType PprDebug unspec_inst_ty]])
+ pprParendGenType PprDebug unspec_inst_ty]])
else id) (
returnTc (unitBag (InstInfo clas inst_tmpls inst_ty simpl_theta
omitDefaultMethodWarn clas_op clas_name inst_ty sty
= ppCat [ppStr "Warning: Omitted default method for",
ppr sty clas_op, ppStr "in instance",
- ppPStr clas_name, pprParendType sty inst_ty]
+ ppPStr clas_name, pprParendGenType sty inst_ty]
patMonoBindsCtxt pbind sty
unifyKind, -- TcKind s -> TcKind s -> TcM s ()
kindToTcKind, -- Kind -> TcKind s
- tcKindToKind -- TcKind s -> NF_TcM s Kind
+ tcDefaultKind -- TcKind s -> NF_TcM s Kind
) where
import Kind
unify_var uniq1 box1 kind2
= tcReadMutVar box1 `thenNF_Tc` \ maybe_kind1 ->
case maybe_kind1 of
- Just kind1 -> unify_kind kind1 kind1
+ Just kind1 -> unify_kind kind1 kind2
Nothing -> unify_unbound_var uniq1 box1 kind2
unify_unbound_var uniq1 box1 kind2@(TcVarKind uniq2 box2)
kindToTcKind (ArrowKind k1 k2) = TcArrowKind (kindToTcKind k1) (kindToTcKind k2)
-tcKindToKind :: TcKind s -> NF_TcM s Kind
+-- Default all unbound kinds to TcTypeKind, and return the
+-- corresponding Kind as well.
+tcDefaultKind :: TcKind s -> NF_TcM s Kind
-tcKindToKind TcTypeKind
- = returnNF_Tc TypeKind
+tcDefaultKind TcTypeKind
+ = returnNF_Tc BoxedTypeKind
-tcKindToKind (TcArrowKind kind1 kind2)
- = tcKindToKind kind1 `thenNF_Tc` \ k1 ->
- tcKindToKind kind2 `thenNF_Tc` \ k2 ->
+tcDefaultKind (TcArrowKind kind1 kind2)
+ = tcDefaultKind kind1 `thenNF_Tc` \ k1 ->
+ tcDefaultKind kind2 `thenNF_Tc` \ k2 ->
returnNF_Tc (ArrowKind k1 k2)
-- Here's where we "default" unbound kinds to BoxedTypeKind
-tcKindToKind (TcVarKind uniq box)
+tcDefaultKind (TcVarKind uniq box)
= tcReadMutVar box `thenNF_Tc` \ maybe_kind ->
case maybe_kind of
- Nothing -> returnNF_Tc BoxedTypeKind -- Default is kind Type for unbound
- Just kind -> tcKindToKind kind
+ Just kind -> tcDefaultKind kind
+
+ Nothing -> -- Default unbound variables to kind Type
+ tcWriteMutVar box (Just TcTypeKind) `thenNF_Tc_`
+ returnNF_Tc BoxedTypeKind
zonkTcKind :: TcKind s -> NF_TcM s (TcKind s)
-- Removes variables that have now been bound.
= ppHang (ppStr "Couldn't match the kind") 4
(ppSep [ppBesides [ppStr "`", ppr sty kind1, ppStr "'"],
ppStr "against",
- ppBesides [ppStr "`", ppr sty kind1, ppStr "'"]
+ ppBesides [ppStr "`", ppr sty kind2, ppStr "'"]
])
\end{code}
matchCtxt (MFun fun) match sty
= ppHang (ppBesides [ppStr "In an equation for function ", ppr sty fun, ppChar ':'])
- 4 (ppBesides [ppr sty fun, pprMatch sty False{-not case-} match])
+ 4 (ppBesides [ppr sty fun, ppSP, pprMatch sty False{-not case-} match])
\end{code}
\begin{code}
tcModule :: GlobalNameMappers -- final renamer info for derivings
-> RenamedHsModule -- input
- -> TcM s ((TypecheckedHsBinds, -- binds from class decls; does NOT
+ -> TcM s ((TypecheckedHsBinds, -- record selector binds
+ TypecheckedHsBinds, -- binds from class decls; does NOT
-- include default-methods bindings
TypecheckedHsBinds, -- binds from instance decls; INCLUDES
-- class default-methods binds
-- pragmas, which is done lazily [ie failure just drops the pragma
-- without having any global-failure effect].
- fixTc (\ ~(_, _, _, _, _, sig_ids) ->
+ fixTc (\ ~(_, _, _, _, _, _, sig_ids) ->
tcExtendGlobalValEnv sig_ids (
-- The knot for instance information. This isn't used at all
-- till we type-check value declarations
- fixTc ( \ ~(rec_inst_mapper, _, _, _, _) ->
+ fixTc ( \ ~(rec_inst_mapper, _, _, _, _, _) ->
-- Type-check the type and class decls
trace "tcTyAndClassDecls:" $
tcTyAndClassDecls1 rec_inst_mapper ty_decls_bag cls_decls_bag
- `thenTc` \ env ->
+ `thenTc` \ (env, record_binds) ->
-- Typecheck the instance decls, includes deriving
tcSetEnv env (
buildInstanceEnvs inst_info `thenTc` \ inst_mapper ->
- returnTc (inst_mapper, env, inst_info, deriv_binds, ddump_deriv)
+ returnTc (inst_mapper, env, record_binds, inst_info, deriv_binds, ddump_deriv)
- ) `thenTc` \ (_, env, inst_info, deriv_binds, ddump_deriv) ->
+ ) `thenTc` \ (_, env, record_binds, inst_info, deriv_binds, ddump_deriv) ->
tcSetEnv env (
-- Default declarations
-- we silently discard the pragma
tcInterfaceSigs sigs `thenTc` \ sig_ids ->
- returnTc (env, inst_info, deriv_binds, ddump_deriv, defaulting_tys, sig_ids)
+ returnTc (env, inst_info, record_binds, deriv_binds, ddump_deriv, defaulting_tys, sig_ids)
- )))) `thenTc` \ (env, inst_info, deriv_binds, ddump_deriv, defaulting_tys, _) ->
+ )))) `thenTc` \ (env, inst_info, record_binds, deriv_binds, ddump_deriv, defaulting_tys, _) ->
tcSetEnv env ( -- to the end...
tcSetDefaultTys defaulting_tys ( -- ditto
-- simplification step may have instantiated some
-- ambiguous types. So, sadly, we need to back-substitute
-- over the whole bunch of bindings.
+ zonkBinds record_binds `thenNF_Tc` \ record_binds' ->
zonkBinds val_binds `thenNF_Tc` \ val_binds' ->
zonkBinds inst_binds `thenNF_Tc` \ inst_binds' ->
zonkBinds cls_binds `thenNF_Tc` \ cls_binds' ->
-- FINISHED AT LAST
returnTc (
- (cls_binds', inst_binds', val_binds', const_insts'),
+ (record_binds', cls_binds', inst_binds', val_binds', const_insts'),
-- the next collection is just for mkInterface
(fixities, exported_ids', tycons, classes, inst_info),
rn4MtoTcM,
+ TcError(..), TcWarning(..), Message(..),
+ mkTcErr, arityErr,
+
-- For closure
MutableVar(..), _MutableArray
) where
import Type ( Type(..), GenType )
import TyVar ( TyVar(..), GenTyVar )
import Usage ( Usage(..), GenUsage )
-import ErrUtils ( Error(..), Message(..), ErrCtxt(..),
- TcWarning(..), TcError(..), mkTcErr )
import SST
import RnMonad4
import Bag ( Bag, emptyBag, isEmptyBag,
foldBag, unitBag, unionBags, snocBag )
import FiniteMap ( FiniteMap, emptyFM )
-import Pretty ( Pretty(..), PrettyRep )
-import PprStyle ( PprStyle )
import Outputable ( Outputable(..), NamedThing(..), ExportFlag )
+import ErrUtils ( Error(..) )
import Maybes ( MaybeErr(..) )
import Name ( Name )
import ProtoName ( ProtoName )
import UniqSupply ( UniqSupply, getUnique, getUniques, splitUniqSupply )
import Unique ( Unique )
import Util
+import Pretty
+import PprStyle ( PprStyle(..) )
infixr 9 `thenTc`, `thenTc_`, `thenNF_Tc`, `thenNF_Tc_`
\end{code}
\begin{code}
failTc :: Message -> TcM s a
failTc err_msg down env
- = readMutVarSST errs_var `thenSST` \ (warns,errs) ->
- foldr thenNF_Tc_ (returnNF_Tc []) ctxt down env `thenSST` \ ctxt_msgs ->
+ = readMutVarSST errs_var `thenSST` \ (warns,errs) ->
+ listNF_Tc ctxt down env `thenSST` \ ctxt_msgs ->
let
err = mkTcErr loc ctxt_msgs err_msg
in
where
u_var = getUniqSupplyVar down
\end{code}
+
+
+TypeChecking Errors
+~~~~~~~~~~~~~~~~~~~
+
+\begin{code}
+type Message = PprStyle -> Pretty
+type TcError = Message
+type TcWarning = Message
+
+
+mkTcErr :: SrcLoc -- Where
+ -> [Message] -- Context
+ -> Message -- What went wrong
+ -> TcError -- The complete error report
+
+mkTcErr locn ctxt msg sty
+ = ppHang (ppBesides [ppr PprForUser locn, ppStr ": ", msg sty])
+ 4 (ppAboves [msg sty | msg <- ctxt])
+
+
+arityErr kind name n m sty
+ = ppBesides [ ppStr "`", ppr sty name, ppStr "' should have ",
+ n_arguments, ppStr ", but has been given ", ppInt m, ppChar '.']
+ where
+ errmsg = kind ++ " has too " ++ quantity ++ " arguments"
+ quantity | m < n = "few"
+ | otherwise = "many"
+ n_arguments | n == 0 = ppStr "no arguments"
+ | n == 1 = ppStr "1 argument"
+ | True = ppCat [ppInt n, ppStr "arguments"]
+\end{code}
+
+
mkTcArrowKind, unifyKind, newKindVar,
kindToTcKind
)
-import ErrUtils ( arityErr )
import Type ( GenType, Type(..), ThetaType(..),
- mkTyVarTy, mkTyConTy, mkFunTy, mkAppTy,
+ mkTyVarTy, mkTyConTy, mkFunTy, mkAppTy, mkSynTy,
mkSigmaTy
)
import TyVar ( GenTyVar, TyVar(..), mkTyVar )
tcMonoType ty2 `thenTc` \ tau_ty2 ->
returnTc (mkTcTypeKind, mkFunTy tau_ty1 tau_ty2)
-tcMonoTypeKind (MonoTyApp name tys)
- = mapAndUnzipTc tcMonoTypeKind tys `thenTc` \ (arg_kinds, arg_tys) ->
-
- tc_mono_name name `thenNF_Tc` \ (fun_kind, maybe_arity, fun_ty) ->
-
- newKindVar `thenNF_Tc` \ result_kind ->
- unifyKind fun_kind (foldr mkTcArrowKind result_kind arg_kinds) `thenTc_`
-
- -- Check for saturated application in the special case of
- -- type synoyms.
- (case maybe_arity of
- Just arity | arity /= n_args -> failTc (err arity)
- other -> returnTc ()
- ) `thenTc_`
-
- returnTc (result_kind, foldl mkAppTy fun_ty arg_tys)
- where
- err arity = arityErr "Type synonym constructor" name arity n_args
- n_args = length tys
+tcMonoTypeKind (MonoTyApp name@(Short _ _) tys)
+ = -- Must be a type variable
+ tcLookupTyVar name `thenNF_Tc` \ (kind,tyvar) ->
+ tcMonoTyApp kind (mkTyVarTy tyvar) tys
+tcMonoTypeKind (MonoTyApp name tys)
+ | isTyConName name -- Must be a type constructor
+ = tcLookupTyCon name `thenNF_Tc` \ (kind,maybe_arity,tycon) ->
+ case maybe_arity of
+ Just arity -> tcSynApp name kind arity tycon tys -- synonum
+ Nothing -> tcMonoTyApp kind (mkTyConTy tycon) tys -- newtype or data
+
-- for unfoldings only:
tcMonoTypeKind (MonoForAllTy tyvars_w_kinds ty)
= tcTyVarScopeGivenKinds names tc_kinds (\ tyvars ->
tcLookupClass class_name `thenNF_Tc` \ (class_kind, clas) ->
unifyKind class_kind arg_kind `thenTc_`
returnTc (mkTcTypeKind, mkDictTy clas arg_ty)
+\end{code}
+Help functions for type applications
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+\begin{code}
+tcMonoTyApp fun_kind fun_ty tys
+ = mapAndUnzipTc tcMonoTypeKind tys `thenTc` \ (arg_kinds, arg_tys) ->
+ newKindVar `thenNF_Tc` \ result_kind ->
+ unifyKind fun_kind (foldr mkTcArrowKind result_kind arg_kinds) `thenTc_`
+ returnTc (result_kind, foldl mkAppTy fun_ty arg_tys)
-tc_mono_name :: Name -> NF_TcM s (TcKind s, Maybe Arity, Type)
-tc_mono_name name@(Short _ _) -- Must be a type variable
- = tcLookupTyVar name `thenNF_Tc` \ (kind,tyvar) ->
- returnNF_Tc (kind, Nothing, mkTyVarTy tyvar)
+tcSynApp name syn_kind arity tycon tys
+ = mapAndUnzipTc tcMonoTypeKind tys `thenTc` \ (arg_kinds, arg_tys) ->
+ newKindVar `thenNF_Tc` \ result_kind ->
+ unifyKind syn_kind (foldr mkTcArrowKind result_kind arg_kinds) `thenTc_`
-tc_mono_name name | isTyConName name -- Must be a type constructor
- = tcLookupTyCon name `thenNF_Tc` \ (kind,maybe_arity,tycon) ->
- returnNF_Tc (kind, maybe_arity, mkTyConTy tycon)
-
-tc_mono_name name -- Renamer should have got it right
- = panic ("tc_mono_name:" ++ ppShow 1000 (ppr PprDebug name))
+ -- Check that it's applied to the right number of arguments
+ checkTc (arity == n_args) (err arity) `thenTc_`
+ returnTc (result_kind, mkSynTy tycon arg_tys)
+ where
+ err arity = arityErr "Type synonym constructor" name arity n_args
+ n_args = length tys
\end{code}
import TcHsSyn ( TcPat(..), TcIdOcc(..) )
import TcMonad
-import Inst ( Inst, OverloadedLit(..), InstOrigin(..), LIE(..),
- emptyLIE, plusLIE, newMethod, newOverloadedLit )
+import Inst ( Inst, OverloadedLit(..), InstOrigin(..),
+ emptyLIE, plusLIE, plusLIEs, LIE(..),
+ newMethod, newOverloadedLit
+ )
import TcEnv ( tcLookupGlobalValue, tcLookupGlobalValueByKey,
- tcLookupLocalValueOK )
+ tcLookupLocalValueOK, tcGlobalOcc )
import TcType ( TcType(..), TcMaybe, tcInstType, newTyVarTy, newTyVarTys )
import Unify ( unifyTauTy, unifyTauTyList, unifyTauTyLists )
import Bag ( Bag )
import CmdLineOpts ( opt_IrrefutableTuples )
-import ErrUtils ( arityErr )
import Id ( GenId, idType )
import Kind ( Kind, mkBoxedTypeKind, mkTypeKind )
+import Maybes ( maybeToBool )
import Name ( Name )
import PprType ( GenType, GenTyVar )
import PrelInfo ( charPrimTy, intPrimTy, floatPrimTy,
doublePrimTy, charTy, stringTy, mkListTy,
mkTupleTy, addrTy, addrPrimTy )
import Pretty
-import Type ( Type(..), GenType, splitFunTy, splitSigmaTy )
+import Type ( splitFunTy, splitRhoTy, splitSigmaTy, mkTyVarTys,
+ getFunTy_maybe, maybeAppDataTyCon,
+ Type(..), GenType
+ )
import TyVar ( GenTyVar )
import Unique ( Unique, eqClassOpKey )
-
+import Util ( assertPanic, panic{-ToDo:rm-} )
\end{code}
\begin{code}
\begin{code}
tcPat pat_in@(ConPatIn name pats)
- = tcLookupGlobalValue name `thenNF_Tc` \ con_id ->
-
- tcPats pats `thenTc` \ (pats', lie, tys) ->
+ = tcPats pats `thenTc` \ (pats', lie, tys) ->
tcAddErrCtxt (patCtxt pat_in) $
- matchConArgTys con_id tys `thenTc` \ data_ty ->
+ matchConArgTys name tys `thenTc` \ (con_id, data_ty) ->
returnTc (ConPat con_id data_ty pats',
lie,
data_ty)
tcPat pat_in@(ConOpPatIn pat1 op pat2) -- & in binary-op form...
- = tcLookupGlobalValue op `thenNF_Tc` \ con_id ->
-
- tcPat pat1 `thenTc` \ (pat1', lie1, ty1) ->
+ = tcPat pat1 `thenTc` \ (pat1', lie1, ty1) ->
tcPat pat2 `thenTc` \ (pat2', lie2, ty2) ->
tcAddErrCtxt (patCtxt pat_in) $
- matchConArgTys con_id [ty1,ty2] `thenTc` \ data_ty ->
+ matchConArgTys op [ty1,ty2] `thenTc` \ (con_id, data_ty) ->
returnTc (ConOpPat pat1' con_id pat2' data_ty,
lie1 `plusLIE` lie2,
%************************************************************************
%* *
+\subsection{Records}
+%* *
+%************************************************************************
+
+\begin{code}
+tcPat pat_in@(RecPatIn name rpats)
+ = tcGlobalOcc name `thenNF_Tc` \ (con_id, _, con_rho) ->
+ let
+ (_, con_tau) = splitRhoTy con_rho
+ -- Ignore the con_theta; overloaded constructors only
+ -- behave differently when called, not when used for
+ -- matching.
+ (_, record_ty) = splitFunTy con_tau
+ in
+ -- Con is syntactically constrained to be a data constructor
+ ASSERT( maybeToBool (maybeAppDataTyCon record_ty ) )
+
+ mapAndUnzipTc (do_bind record_ty) rpats `thenTc` \ (rpats', lies) ->
+
+ returnTc (panic "tcPat:RecPatIn:avoid type errors"{-RecPat con_id record_ty rpats',
+ plusLIEs lies,
+ record_ty-})
+
+ where
+ do_bind expected_record_ty (field_label, rhs_pat, pun_flag)
+ = tcGlobalOcc field_label `thenNF_Tc` \ (sel_id, _, tau) ->
+
+ -- Record selectors all have type
+ -- forall a1..an. T a1 .. an -> tau
+ ASSERT( maybeToBool (getFunTy_maybe tau) )
+ let
+ -- Selector must have type RecordType -> FieldType
+ Just (record_ty, field_ty) = getFunTy_maybe tau
+ in
+ tcAddErrCtxt (recordLabel field_label) (
+ unifyTauTy expected_record_ty record_ty
+ ) `thenTc_`
+ tcPat rhs_pat `thenTc` \ (rhs_pat', lie, rhs_ty) ->
+ tcAddErrCtxt (recordRhs field_label rhs_pat) (
+ unifyTauTy field_ty rhs_ty
+ ) `thenTc_`
+ returnTc ((sel_id, rhs_pat', pun_flag), lie)
+\end{code}
+
+%************************************************************************
+%* *
\subsection{Non-overloaded literals}
%* *
%************************************************************************
unifies the actual args against the expected ones.
\begin{code}
-matchConArgTys :: Id -> [TcType s] -> TcM s (TcType s)
+matchConArgTys :: Name -> [TcType s] -> TcM s (Id, TcType s)
-matchConArgTys con_id arg_tys
- = tcInstType [] (idType con_id) `thenNF_Tc` \ con_ty ->
+matchConArgTys con arg_tys
+ = tcGlobalOcc con `thenNF_Tc` \ (con_id, _, con_rho) ->
let
- no_of_args = length arg_tys
- (con_tyvars, con_theta, con_tau) = splitSigmaTy con_ty
- -- Ignore the sig_theta; overloaded constructors only
+ (con_theta, con_tau) = splitRhoTy con_rho
+ -- Ignore the con_theta; overloaded constructors only
-- behave differently when called, not when used for
-- matching.
+
(con_args, con_result) = splitFunTy con_tau
con_arity = length con_args
+ no_of_args = length arg_tys
in
checkTc (con_arity == no_of_args)
(arityErr "Constructor" con_id con_arity no_of_args) `thenTc_`
unifyTauTyLists arg_tys con_args `thenTc_`
- returnTc con_result
+ returnTc (con_id, con_result)
\end{code}
~~~~~~~~~~~~~~~~~~~
\begin{code}
patCtxt pat sty = ppHang (ppStr "In the pattern:") 4 (ppr sty pat)
+
+recordLabel field_label sty
+ = ppHang (ppBesides [ppStr "When matching record field", ppr sty field_label])
+ 4 (ppBesides [ppStr "with its immediately enclosing constructor"])
+
+recordRhs field_label pat sty
+ = ppHang (ppStr "In the record field pattern")
+ 4 (ppSep [ppr sty field_label, ppStr "=", ppr sty pat])
\end{code}
(length new_tyvars) maybe_tys locn)
`thenB_Tc_`
- checkB_Tc (not (all isUnboxedDataType (catMaybes maybe_tys)))
+ checkB_Tc (not (all isUnboxedType (catMaybes maybe_tys)))
(badSpecialisationErr "data" "not all unboxed types"
(length new_tyvars) maybe_tys locn)
`thenB_Tc_`
import HsSyn ( TyDecl(..), ConDecl(..), BangType(..),
ClassDecl(..), MonoType(..), PolyType(..),
- Sig(..), MonoBinds, Fake, InPat )
+ Sig(..), MonoBinds, Fake, InPat, HsBinds(..), Bind, HsExpr )
import RnHsSyn ( RenamedTyDecl(..), RenamedClassDecl(..) )
+import TcHsSyn ( TcHsBinds(..), TcIdOcc(..) )
import TcMonad
import Inst ( InstanceMapper(..) )
tcExtendGlobalValEnv,
tcTyVarScope, tcGetEnv )
import TcKind ( TcKind, newKindVars )
-import TcTyDecls ( tcTyDecl )
+import TcTyDecls ( tcTyDecl, tcRecordSelectors )
import Bag
import Class ( Class(..), getClassSelIds )
import PprStyle
import Pretty
import UniqSet ( UniqSet(..), emptyUniqSet,
- singletonUniqSet, unionUniqSets,
+ unitUniqSet, unionUniqSets,
unionManyUniqSets, uniqSetToList )
import SrcLoc ( SrcLoc )
-import TyCon ( TyCon, getTyConDataCons )
+import TyCon ( TyCon, tyConDataCons )
import Unique ( Unique )
import Util ( panic, pprTrace )
tcTyAndClassDecls1 :: InstanceMapper
-> Bag RenamedTyDecl -> Bag RenamedClassDecl
- -> TcM s (TcEnv s)
+ -> TcM s (TcEnv s, TcHsBinds s)
tcTyAndClassDecls1 inst_mapper rnty_decls rncls_decls
= sortByDependency syn_decls cls_decls decls `thenTc` \ groups ->
tcGroups inst_mapper []
= tcGetEnv `thenNF_Tc` \ env ->
- returnTc env
+ returnTc (env, EmptyBinds)
tcGroups inst_mapper (group:groups)
- = tcGroup inst_mapper group `thenTc` \ new_env ->
+ = tcGroup inst_mapper group `thenTc` \ (new_env, binds1) ->
-- Extend the environment using the new tycons and classes
tcSetEnv new_env $
-- Do the remaining groups
- tcGroups inst_mapper groups
+ tcGroups inst_mapper groups `thenTc` \ (final_env, binds2) ->
+
+ returnTc (final_env, binds1 `ThenBinds` binds2)
\end{code}
Dealing with a group
~~~~~~~~~~~~~~~~~~~~
\begin{code}
-tcGroup :: InstanceMapper -> Bag Decl -> TcM s (TcEnv s)
+tcGroup :: InstanceMapper -> Bag Decl -> TcM s (TcEnv s, TcHsBinds s)
tcGroup inst_mapper decls
= pprTrace "tcGroup: " (ppCat (map (fst.fmt_decl) (bagToList decls))) $
-- extend-env things work properly. A bit UGH-ish.
tcExtendTyConEnv tycon_names_w_arities tycons $
tcExtendClassEnv class_names classes $
- tcExtendGlobalValEnv (concat (map getTyConDataCons tycons)) $
- tcExtendGlobalValEnv (concat (map getClassSelIds classes)) $
-
- -- SNAFFLE ENV TO RETURN
- tcGetEnv `thenNF_Tc` \ final_env ->
-- DEAL WITH TYPE VARIABLES
tcTyVarScope tyvar_names ( \ tyvars ->
foldBag combine (tcDecl inst_mapper)
(returnTc (emptyBag, emptyBag))
decls
- ) `thenTc` \ (tycons,classes) ->
+ ) `thenTc` \ (tycon_bag,class_bag) ->
+ let
+ tycons = bagToList tycon_bag
+ classes = bagToList class_bag
+ in
- returnTc (bagToList tycons, bagToList classes, final_env)
- ) `thenTc` \ (_, _, final_env) ->
- returnTc final_env
+ -- SNAFFLE ENV TO RETURN
+ tcGetEnv `thenNF_Tc` \ final_env ->
+
+ returnTc (tycons, classes, final_env)
+ ) `thenTc` \ (tycons, classes, final_env) ->
+
+
+ -- Create any necessary record selector Ids and their bindings
+ mapAndUnzipTc tcRecordSelectors tycons `thenTc` \ (sel_ids_s, binds) ->
+
+ -- Extend the global value environment with
+ -- a) constructors
+ -- b) record selectors
+ -- c) class op selectors
+
+ tcSetEnv final_env $
+ tcExtendGlobalValEnv (concat (map tyConDataCons tycons)) $
+ tcExtendGlobalValEnv (concat sel_ids_s) $
+ tcExtendGlobalValEnv (concat (map getClassSelIds classes)) $
+ tcGetEnv `thenNF_Tc` \ really_final_env ->
+
+ returnTc (really_final_env, foldr ThenBinds EmptyBinds binds)
where
(tyvar_names, tycon_names_w_arities, class_names) = get_binders decls
bag_acyclic (AcyclicSCC scc) = unitBag scc
bag_acyclic (CyclicSCC sccs) = sccs
-fmt_decl (TyD (TySynonym name _ _ _)) = (ppr PprForUser name, getSrcLoc name)
-fmt_decl (ClD (ClassDecl _ name _ _ _ _ _)) = (ppr PprForUser name, getSrcLoc name)
+fmt_decl decl
+ = (ppr PprForUser name, getSrcLoc name)
+ where
+ name = get_name decl
+ get_name (TyD (TyData _ name _ _ _ _ _)) = name
+ get_name (TyD (TyNew _ name _ _ _ _ _)) = name
+ get_name (TyD (TySynonym name _ _ _)) = name
+ get_name (ClD (ClassDecl _ name _ _ _ _ _)) = name
\end{code}
Edges in Type/Class decls
get_sig (ClassOpSig _ ty _ _) = get_pty ty
get_sig other = panic "TcTyClsDecls:get_sig"
-set_name name = singletonUniqSet (getItsUnique name)
+set_name name = unitUniqSet (getItsUnique name)
set_to_bag set = listToBag (uniqSetToList set)
\end{code}
module TcTyDecls (
tcTyDecl,
- tcConDecl
+ tcConDecl,
+ tcRecordSelectors
) where
import Ubiq{-uitous-}
-import HsSyn ( TyDecl(..), ConDecl(..), BangType(..), MonoType )
+import HsSyn ( TyDecl(..), ConDecl(..), BangType(..), HsExpr(..),
+ Match(..), GRHSsAndBinds(..), GRHS(..), OutPat(..),
+ HsBinds(..), HsLit, Stmt, Qual, ArithSeqInfo, PolyType,
+ Bind(..), MonoBinds(..), Sig,
+ MonoType )
import RnHsSyn ( RenamedTyDecl(..), RenamedConDecl(..) )
+import TcHsSyn ( TcHsBinds(..), TcIdOcc(..), mkHsTyLam )
import TcMonoType ( tcMonoTypeKind, tcMonoType, tcContext )
-import TcEnv ( tcLookupTyCon, tcLookupTyVar, tcLookupClass )
+import TcType ( tcInstTyVars, tcInstType )
+import TcEnv ( tcLookupTyCon, tcLookupTyVar, tcLookupClass,
+ newLocalId
+ )
import TcMonad
import TcKind ( TcKind, unifyKind, mkTcArrowKind, mkTcTypeKind )
-import Id ( mkDataCon, StrictnessMark(..) )
+import Id ( mkDataCon, dataConSig, mkRecordSelectorId,
+ dataConFieldLabels, StrictnessMark(..)
+ )
+import FieldLabel
import Kind ( Kind, mkArrowKind, mkBoxedTypeKind )
import SpecEnv ( SpecEnv(..), nullSpecEnv )
import Name ( getNameFullName, Name(..) )
import Pretty
-import TyCon ( TyCon, ConsVisible(..), NewOrData(..), mkSynTyCon, mkDataTyCon )
-import Type ( getTypeKind )
-import TyVar ( getTyVarKind )
-import Util ( panic )
-
+import TyCon ( TyCon, NewOrData(..), mkSynTyCon, mkDataTyCon, tyConDataCons )
+import Type ( getTypeKind, getTyVar, tyVarsOfTypes, eqTy, applyTyCon,
+ mkForAllTys, mkFunTy )
+import TyVar ( getTyVarKind, elementOfTyVarSet )
+import UniqSet ( emptyUniqSet, mkUniqSet, uniqSetToList, unionManyUniqSets, UniqSet(..) )
+import Util ( panic, equivClasses )
\end{code}
\begin{code}
(foldr mkTcArrowKind rhs_kind tyvar_kinds)
`thenTc_`
let
- -- Construct the tycon
+ -- Getting the TyCon's kind is a bit of a nuisance. We can't use the tycon_kind,
+ -- because that's a TcKind and may not yet be fully unified with other kinds.
+ -- We could have augmented the tycon environment with a knot-tied kind,
+ -- but the simplest thing to do seems to be to get the Kind by (lazily)
+ -- looking at the tyvars and rhs_ty.
result_kind, final_tycon_kind :: Kind -- NB not TcKind!
result_kind = getTypeKind rhs_ty
final_tycon_kind = foldr (mkArrowKind . getTyVarKind) result_kind rec_tyvars
+ -- Construct the tycon
tycon = mkSynTyCon (getItsUnique tycon_name)
(getNameFullName tycon_name)
final_tycon_kind
unifyKind tycon_kind
(foldr mkTcArrowKind mkTcTypeKind tyvar_kinds)
`thenTc_`
+
-- Walk the condecls
mapTc (tcConDecl rec_tycon rec_tyvars ctxt) con_decls
`thenTc` \ con_ids ->
ctxt
con_ids
derived_classes
- ConsVisible -- For now; if constrs are from pragma we are *abstract*
data_or_new
in
returnTc tycon
- where
- tc_derivs Nothing = returnNF_Tc []
- tc_derivs (Just ds) = mapNF_Tc tc_deriv ds
- tc_deriv name
- = tcLookupClass name `thenNF_Tc` \ (_, clas) ->
- returnNF_Tc clas
+tc_derivs Nothing = returnNF_Tc []
+tc_derivs (Just ds) = mapNF_Tc tc_deriv ds
+
+tc_deriv name
+ = tcLookupClass name `thenNF_Tc` \ (_, clas) ->
+ returnNF_Tc clas
\end{code}
+Generating selector bindings for record delarations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+\begin{code}
+tcRecordSelectors :: TyCon -> TcM s ([Id], TcHsBinds s)
+tcRecordSelectors tycon
+ = mapAndUnzipTc (tcRecordSelector tycon) groups `thenTc` \ (ids, binds) ->
+ returnTc (ids, SingleBind (NonRecBind (foldr AndMonoBinds EmptyMonoBinds binds)))
+ where
+ data_cons = tyConDataCons tycon
+ fields = [ (con, field) | con <- data_cons,
+ field <- dataConFieldLabels con
+ ]
+
+ -- groups is list of fields that share a common name
+ groups = equivClasses cmp_name fields
+ cmp_name (_, field1) (_, field2)
+ = fieldLabelName field1 `cmp` fieldLabelName field2
+\end{code}
+
+We're going to build a record selector that looks like this:
+
+ data T a b c = T1 { op :: a, ...}
+ | T2 { op :: a, ...}
+ | T3
+
+ sel :: forall a b c. T a b c -> a
+ sel = /\ a b c -> \ T1 { sel = x } -> x
+ T2 { sel = 2 } -> x
+
+Note that the selector Id itself is used as the field
+label; it has to be an Id, you see!
+
+\begin{code}
+tcRecordSelector tycon fields@((first_con, first_field_label) : other_fields)
+ = panic "tcRecordSelector: don't typecheck"
+{-
+ = let
+ field_ty = fieldLabelType first_field_label
+ field_name = fieldLabelName first_field_label
+ other_tys = [fieldLabelType fl | (_, fl) <- fields]
+ (tyvars, _, _, _) = dataConSig first_con
+ -- tyvars of first_con may be free in first_ty
+ in
+
+ -- Check that all the fields in the group have the same type
+ -- This check assumes that all the constructors of a given
+ -- data type use the same type variables
+ checkTc (all (eqTy field_ty) other_tys)
+ (fieldTypeMisMatch field_name) `thenTc_`
+
+ -- Create an Id for the field itself
+ tcInstTyVars tyvars `thenNF_Tc` \ (tyvars', tyvar_tys, tenv) ->
+ tcInstType tenv field_ty `thenNF_Tc` \ field_ty' ->
+ let
+ data_ty' = applyTyCon tycon tyvar_tys
+ in
+ newLocalId SLIT("x") field_ty' `thenNF_Tc` \ field_id ->
+ newLocalId SLIT("r") data_ty' `thenNF_Tc` \ record_id ->
+
+ -- Now build the selector
+ let
+ tycon_src_loc = getSrcLoc tycon
+
+ selector_ty = mkForAllTys tyvars' $
+ mkFunTy data_ty' $
+ field_ty'
+
+ selector_id = mkRecordSelectorId first_field_label selector_ty
+
+ -- HsSyn is dreadfully verbose for defining the selector!
+ selector_rhs = mkHsTyLam tyvars' $
+ HsLam $
+ PatMatch (VarPat record_id) $
+ GRHSMatch $
+ GRHSsAndBindsOut [OtherwiseGRHS selector_body tycon_src_loc]
+ EmptyBinds field_ty'
+
+ selector_body = HsCase (HsVar record_id) (map mk_match fields) tycon_src_loc
+
+ mk_match (con_id, field_label)
+ = PatMatch (RecPat con_id data_ty' [(selector_id, VarPat field_id, False)]) $
+ GRHSMatch $
+ GRHSsAndBindsOut [OtherwiseGRHS (HsVar field_id)
+ (getSrcLoc (fieldLabelName field_label))]
+ EmptyBinds
+ field_ty'
+ in
+ returnTc (selector_id, VarMonoBind selector_id selector_rhs)
+-}
+\end{code}
Constructors
~~~~~~~~~~~~
tcConDecl :: TyCon -> [TyVar] -> [(Class,Type)] -> RenamedConDecl -> TcM s Id
tcConDecl tycon tyvars ctxt (ConDecl name btys src_loc)
+ = tcDataCon tycon tyvars ctxt name btys src_loc
+
+tcConDecl tycon tyvars ctxt (ConOpDecl bty1 op bty2 src_loc)
+ = tcDataCon tycon tyvars ctxt op [bty1,bty2] src_loc
+
+tcConDecl tycon tyvars ctxt (NewConDecl name ty src_loc)
= tcAddSrcLoc src_loc $
- let
- (stricts, tys) = sep_bangs btys
- in
- mapTc tcMonoType tys `thenTc` \ arg_tys ->
+ tcMonoType ty `thenTc` \ arg_ty ->
let
data_con = mkDataCon (getItsUnique name)
(getNameFullName name)
- stricts
+ [NotMarkedStrict]
+ [{- No labelled fields -}]
tyvars
- [] -- ToDo: ctxt; limited to tyvars in arg_tys
- arg_tys
+ ctxt
+ [arg_ty]
tycon
-- nullSpecEnv
in
returnTc data_con
-tcConDecl tycon tyvars ctxt (ConOpDecl bty1 op bty2 src_loc)
+tcConDecl tycon tyvars ctxt (RecConDecl name fields src_loc)
= tcAddSrcLoc src_loc $
+ mapTc tcField fields `thenTc` \ field_label_infos_s ->
let
- (stricts, tys) = sep_bangs [bty1, bty2]
- in
- mapTc tcMonoType tys `thenTc` \ arg_tys ->
- let
- data_con = mkDataCon (getItsUnique op)
- (getNameFullName op)
+ field_label_infos = concat field_label_infos_s
+ stricts = [strict | (_, _, strict) <- field_label_infos]
+ arg_tys = [ty | (_, ty, _) <- field_label_infos]
+
+ field_labels = [ mkFieldLabel name ty tag
+ | ((name, ty, _), tag) <- field_label_infos `zip` allFieldLabelTags
+ ]
+
+ data_con = mkDataCon (getItsUnique name)
+ (getNameFullName name)
stricts
+ field_labels
tyvars
- [] -- ToDo: ctxt
+ (thinContext arg_tys ctxt)
arg_tys
tycon
-- nullSpecEnv
in
returnTc data_con
-tcConDecl tycon tyvars ctxt (NewConDecl name ty src_loc)
+tcField (field_label_names, bty)
+ = tcMonoType (get_ty bty) `thenTc` \ field_ty ->
+ returnTc [(name, field_ty, get_strictness bty) | name <- field_label_names]
+
+tcDataCon tycon tyvars ctxt name btys src_loc
= tcAddSrcLoc src_loc $
- tcMonoType ty `thenTc` \ arg_ty ->
+ let
+ stricts = map get_strictness btys
+ tys = map get_ty btys
+ in
+ mapTc tcMonoType tys `thenTc` \ arg_tys ->
let
data_con = mkDataCon (getItsUnique name)
(getNameFullName name)
- [NotMarkedStrict]
+ stricts
+ [{- No field labels -}]
tyvars
- [] -- ToDo: ctxt
- [arg_ty]
+ (thinContext arg_tys ctxt)
+ arg_tys
tycon
-- nullSpecEnv
in
returnTc data_con
-tcConDecl tycon tyvars ctxt (RecConDecl con fields src_loc)
- = panic "tcConDecls:RecConDecl"
-
-
-sep_bangs btys
- = unzip (map sep_bang btys)
- where
- sep_bang (Banged ty) = (MarkedStrict, ty)
- sep_bang (Unbanged ty) = (NotMarkedStrict, ty)
+-- The context for a data constructor should be limited to
+-- the type variables mentioned in the arg_tys
+thinContext arg_tys ctxt
+ = filter in_arg_tys ctxt
+ where
+ arg_tyvars = tyVarsOfTypes arg_tys
+ in_arg_tys (clas,ty) = getTyVar "tcDataCon" ty `elementOfTyVarSet` arg_tyvars
+
+get_strictness (Banged ty) = MarkedStrict
+get_strictness (Unbanged ty) = NotMarkedStrict
+
+get_ty (Banged ty) = ty
+get_ty (Unbanged ty) = ty
\end{code}
tyNewCtxt tycon_name sty
= ppCat [ppStr "In the newtype declaration for", ppr sty tycon_name]
+
+fieldTypeMisMatch field_name sty
+ = ppSep [ppStr "Declared types differ for field", ppr sty field_name]
\end{code}
tcReadTyVar, -- :: TcTyVar s -> NF_TcM (TcMaybe s)
- tcInstTyVar, -- TyVar -> NF_TcM s (TcTyVar s)
+ tcInstTyVars, -- TyVar -> NF_TcM s (TcTyVar s)
+ tcInstSigTyVars,
tcInstType, tcInstTcType, tcInstTheta,
--- zonkTcType, -- TcType s -> NF_TcM s (TcType s)
--- zonkTcTheta, -- TcThetaType s -> NF_TcM s (TcThetaType s)
-
zonkTcTyVars, -- TcTyVarSet s -> NF_TcM s (TcTyVarSet s)
zonkTcType, -- TcType s -> NF_TcM s (TcType s)
zonkTcTypeToType, -- TcType s -> NF_TcM s Type
import UniqFM ( UniqFM )
import Name ( getNameShortName )
import Maybes ( assocMaybe )
-import Util ( panic )
+import Util ( panic, pprPanic )
+
+import Outputable ( Outputable(..) ) -- Debugging messages
+import PprType ( GenTyVar, GenType )
+import Pretty -- ditto
+import PprStyle ( PprStyle(..) ) -- ditto
\end{code}
data TcMaybe s = UnBound
| BoundTo (TcType s)
+ | DontBind -- This variant is used for tyvars
+ -- arising from type signatures, or
+ -- existentially quantified tyvars;
+ -- The idea is that we must not unify
+ -- such tyvars with anything except
+ -- themselves.
-- Interestingly, you can't use (Maybe (TcType s)) instead of (TcMaybe s),
-- because you get a synonym loop if you do!
~~~~~~~~~~~~~~~~~~
\begin{code}
-newTcTyVar :: Maybe ShortName -> Kind -> NF_TcM s (TcTyVar s)
-newTcTyVar name kind
+newTcTyVar :: Kind -> NF_TcM s (TcTyVar s)
+newTcTyVar kind
= tcGetUnique `thenNF_Tc` \ uniq ->
tcNewMutVar UnBound `thenNF_Tc` \ box ->
- returnNF_Tc (TyVar uniq kind name box)
+ returnNF_Tc (TyVar uniq kind Nothing box)
newTyVarTy :: Kind -> NF_TcM s (TcType s)
newTyVarTy kind
- = newTcTyVar Nothing kind `thenNF_Tc` \ tc_tyvar ->
+ = newTcTyVar kind `thenNF_Tc` \ tc_tyvar ->
returnNF_Tc (TyVarTy tc_tyvar)
newTyVarTys :: Int -> Kind -> NF_TcM s [TcType s]
newTyVarTys n kind = mapNF_Tc newTyVarTy (take n (repeat kind))
-tcInstTyVar :: TyVar -> NF_TcM s (TcTyVar s)
-tcInstTyVar tyvar@(TyVar uniq kind name _)
- = newTcTyVar name kind
+
+
+-- For signature type variables, mark them as "DontBind"
+tcInstTyVars, tcInstSigTyVars
+ :: [GenTyVar flexi]
+ -> NF_TcM s ([TcTyVar s], [TcType s], [(GenTyVar flexi, TcType s)])
+tcInstTyVars tyvars = inst_tyvars UnBound tyvars
+tcInstSigTyVars tyvars = inst_tyvars DontBind tyvars
+
+
+inst_tyvars initial_cts tyvars
+ = mapNF_Tc (inst_tyvar initial_cts) tyvars `thenNF_Tc` \ tc_tyvars ->
+ let
+ tys = map TyVarTy tc_tyvars
+ in
+ returnNF_Tc (tc_tyvars, tys, tyvars `zip` tys)
+
+inst_tyvar initial_cts (TyVar _ kind name _)
+ = tcGetUnique `thenNF_Tc` \ uniq ->
+ tcNewMutVar initial_cts `thenNF_Tc` \ box ->
+ returnNF_Tc (TyVar uniq kind name box)
\end{code}
@tcInstType@ and @tcInstTcType@ both create a fresh instance of a
do env (DictTy clas ty usage)= do env ty `thenNF_Tc` \ ty' ->
returnNF_Tc (DictTy clas ty' usage)
- do env (TyVarTy (TyVar uniq kind name _))
+ do env (TyVarTy tv@(TyVar uniq kind name _))
= case assocMaybe env uniq of
Just tc_ty -> returnNF_Tc tc_ty
- Nothing -> panic "tcInstType"
+ Nothing -> pprPanic "tcInstType:" (ppAboves [ppr PprDebug tenv,
+ ppr PprDebug ty_to_inst, ppr PprDebug tv])
- do env (ForAllTy (TyVar uniq kind name _) ty)
- = newTcTyVar name kind `thenNF_Tc` \ tc_tyvar ->
+ do env (ForAllTy tyvar@(TyVar uniq kind name _) ty)
+ = inst_tyvar DontBind tyvar `thenNF_Tc` \ tc_tyvar ->
let
new_env = (uniq, TyVarTy tc_tyvar) : env
in
go (clas,ty) = tcInstType tenv ty `thenNF_Tc` \ tc_ty ->
returnNF_Tc (clas, tc_ty)
+--???tcSpecTy :: Type -> NF_TcM s (
+
tcInstTcType :: [(TcTyVar s,TcType s)] -> TcType s -> NF_TcM s (TcType s)
tcInstTcType tenv ty_to_inst
= do [(uniq,ty) | (TyVar uniq _ _ _, ty) <- tenv] ty_to_inst
Just tc_ty -> returnNF_Tc tc_ty
Nothing -> returnNF_Tc ty
- do env (ForAllTy (TyVar uniq kind name _) ty)
- = newTcTyVar name kind `thenNF_Tc` \ tc_tyvar ->
- let
- new_env = (uniq, TyVarTy tc_tyvar) : env
- in
- do new_env ty `thenNF_Tc` \ ty' ->
- returnNF_Tc (ForAllTy tc_tyvar ty')
+ do env (ForAllTy (TyVar uniq kind name _) ty) = panic "tcInstTcType"
-- ForAllUsage impossible
+
\end{code}
Reading and writing TcTyVars
tcReadTyVar (TyVar uniq kind name box)
= tcReadMutVar box `thenNF_Tc` \ maybe_ty ->
case maybe_ty of
- UnBound -> returnNF_Tc UnBound
BoundTo ty -> short_out ty `thenNF_Tc` \ ty' ->
tcWriteMutVar box (BoundTo ty') `thenNF_Tc_`
returnNF_Tc (BoundTo ty')
+ other -> returnNF_Tc other
+
short_out :: TcType s -> NF_TcM s (TcType s)
short_out ty@(TyVarTy (TyVar uniq kind name box))
= tcReadMutVar box `thenNF_Tc` \ maybe_ty ->
case maybe_ty of
- UnBound -> returnNF_Tc ty
BoundTo ty' -> short_out ty' `thenNF_Tc` \ ty' ->
tcWriteMutVar box (BoundTo ty') `thenNF_Tc_`
returnNF_Tc ty'
+ other -> returnNF_Tc ty
+
short_out other_ty = returnNF_Tc other_ty
\end{code}
zonk_tv tyvar_fn tyvar
= tcReadTyVar tyvar `thenNF_Tc` \ maybe_ty ->
case maybe_ty of
- UnBound -> returnNF_Tc (TyVarTy (tyvar_fn tyvar))
BoundTo ty -> zonk tyvar_fn ty
+ other -> returnNF_Tc (TyVarTy (tyvar_fn tyvar))
zonk_tv_to_tv tyvar_fn tyvar
import RnHsSyn
import TcHsSyn
-import ErrUtils ( TcWarning(..), TcError(..) )
import Pretty
import RnUtils ( GlobalNameMappers(..), GlobalNameMapper(..) )
import Maybes ( MaybeErr(..) )
-> -- OUTPUTS ...
MaybeErr
-- SUCCESS ...
- (((TypecheckedHsBinds, -- binds from class decls; does NOT
+ (((TypecheckedHsBinds, -- record selector definitions
+ TypecheckedHsBinds, -- binds from class decls; does NOT
-- include default-methods bindings
TypecheckedHsBinds, -- binds from instance decls; INCLUDES
-- class default-methods binds
\begin{code}
#include "HsVersions.h"
-module Unify ( unifyTauTy, unifyTauTyList, unifyTauTyLists ) where
+module Unify ( unifyTauTy, unifyTauTyList, unifyTauTyLists, unifyFunTy ) where
import Ubiq
-- friends:
import TcMonad
-import Type ( GenType(..), getTypeKind )
-import TyCon ( TyCon(..), ConsVisible, NewOrData )
-import TyVar ( GenTyVar(..), TyVar(..) )
+import Type ( GenType(..), getTypeKind, mkFunTy, getFunTy_maybe )
+import TyCon ( TyCon, mkFunTyCon )
+import TyVar ( GenTyVar(..), TyVar(..), getTyVarKind )
import TcType ( TcType(..), TcMaybe(..), TcTauType(..), TcTyVar(..),
- tcReadTyVar, tcWriteTyVar
+ newTyVarTy, tcReadTyVar, tcWriteTyVar, zonkTcType
)
-- others:
-import Kind ( Kind, isSubKindOf )
+import Kind ( Kind, isSubKindOf, mkTypeKind )
+import Usage ( duffUsage )
import PprType ( GenTyVar, GenType ) -- instances
import Pretty
import Unique ( Unique ) -- instances
\begin{code}
unifyTauTy :: TcTauType s -> TcTauType s -> TcM s ()
unifyTauTy ty1 ty2
- = tcAddErrCtxt (unifyCtxt ty1 ty2) $
+ = tcAddErrCtxtM (unifyCtxt ty1 ty2) $
uTys ty1 ty1 ty2 ty2
\end{code}
-- Applications and functions; just check the two parts
uTys _ (FunTy fun1 arg1 _) _ (FunTy fun2 arg2 _)
= uTys fun1 fun1 fun2 fun2 `thenTc_` uTys arg1 arg1 arg2 arg2
-uTys _ (AppTy fun1 arg1) _ (AppTy fun2 arg2)
- = uTys fun1 fun1 fun2 fun2 `thenTc_` uTys arg1 arg1 arg2 arg2
+uTys _ (AppTy s1 t1) _ (AppTy s2 t2)
+ = uTys s1 s1 s2 s2 `thenTc_` uTys t1 t1 t2 t2
+
+ -- Special case: converts a -> b to (->) a b
+uTys _ (AppTy s1 t1) _ (FunTy fun2 arg2 _)
+ = uTys s1 s1 s2 s2 `thenTc_` uTys t1 t1 t2 t2
+ where
+ s2 = AppTy (TyConTy mkFunTyCon duffUsage) fun2
+ t2 = arg2
+
+uTys _ (FunTy fun1 arg1 _) _ (AppTy s2 t2)
+ = uTys s1 s1 s2 s2 `thenTc_` uTys t1 t1 t2 t2
+ where
+ s1 = AppTy (TyConTy mkFunTyCon duffUsage) fun1
+ t1 = arg1
-- Type constructors must match
uTys ps_ty1 (TyConTy con1 _) ps_ty2 (TyConTy con2 _)
uTys ps_ty1 (SynTy con1 args1 ty1) ps_ty2 ty2 = uTys ps_ty1 ty1 ps_ty2 ty2
uTys ps_ty1 ty1 ps_ty2 (SynTy con2 args2 ty2) = uTys ps_ty1 ty1 ps_ty2 ty2
- -- Special case: converts (->) a b to a -> b
-uTys ps_ty1 (AppTy (AppTy (TyConTy FunTyCon u) fun) arg) ps_ty2 ty2
- = uTys ps_ty1 (FunTy fun arg u) ps_ty2 ty2
-uTys ps_ty1 ty1 ps_ty2 (AppTy (AppTy (TyConTy FunTyCon u) fun) arg)
- = uTys ps_ty1 ty1 ps_ty2 (FunTy fun arg u)
-
-- Anything else fails
uTys ps_ty1 ty1 ps_ty2 ty2 = failTc (unifyMisMatch ps_ty1 ps_ty2)
\end{code}
+Notes on synonyms
+~~~~~~~~~~~~~~~~~
+If you are tempted to make a short cut on synonyms, as in this
+pseudocode...
+
+\begin{verbatim}
+uTys (SynTy con1 args1 ty1) (SynTy con2 args2 ty2)
+ = if (con1 == con2) then
+ -- Good news! Same synonym constructors, so we can shortcut
+ -- by unifying their arguments and ignoring their expansions.
+ unifyTauTypeLists args1 args2
+ else
+ -- Never mind. Just expand them and try again
+ uTys ty1 ty2
+\end{verbatim}
+
+then THINK AGAIN. Here is the whole story, as detected and reported
+by Chris Okasaki \tr{<Chris_Okasaki@loch.mess.cs.cmu.edu>}:
+\begin{quotation}
+Here's a test program that should detect the problem:
+
+\begin{verbatim}
+ type Bogus a = Int
+ x = (1 :: Bogus Char) :: Bogus Bool
+\end{verbatim}
+
+The problem with [the attempted shortcut code] is that
+\begin{verbatim}
+ con1 == con2
+\end{verbatim}
+is not a sufficient condition to be able to use the shortcut!
+You also need to know that the type synonym actually USES all
+its arguments. For example, consider the following type synonym
+which does not use all its arguments.
+\begin{verbatim}
+ type Bogus a = Int
+\end{verbatim}
+
+If you ever tried unifying, say, \tr{Bogus Char} with \tr{Bogus Bool},
+the unifier would blithely try to unify \tr{Char} with \tr{Bool} and
+would fail, even though the expanded forms (both \tr{Int}) should
+match.
+
+Similarly, unifying \tr{Bogus Char} with \tr{Bogus t} would
+unnecessarily bind \tr{t} to \tr{Char}.
+
+... You could explicitly test for the problem synonyms and mark them
+somehow as needing expansion, perhaps also issuing a warning to the
+user.
+\end{quotation}
+
+
%************************************************************************
%* *
\subsection[Unify-uVar]{@uVar@: unifying with a type variable}
= tcReadTyVar tv1 `thenNF_Tc` \ maybe_ty1 ->
case maybe_ty1 of
BoundTo ty1 -> uTys ty1 ty1 ps_ty2 ty2
- UnBound -> uUnboundVar tv1 ps_ty2 ty2
+ other -> uUnboundVar tv1 maybe_ty1 ps_ty2 ty2
-- Expand synonyms
-uUnboundVar tv1 ps_ty2 (SynTy _ _ ty2) = uUnboundVar tv1 ps_ty2 ty2
+uUnboundVar tv1 maybe_ty1 ps_ty2 (SynTy _ _ ty2)
+ = uUnboundVar tv1 maybe_ty1 ps_ty2 ty2
-- The both-type-variable case
uUnboundVar tv1@(TyVar uniq1 kind1 name1 box1)
+ maybe_ty1
ps_ty2
ty2@(TyVarTy tv2@(TyVar uniq2 kind2 name2 box2))
= returnTc ()
-- Distinct type variables
+ -- ASSERT maybe_ty1 /= BoundTo
| otherwise
= tcReadTyVar tv2 `thenNF_Tc` \ maybe_ty2 ->
- case maybe_ty2 of
- BoundTo ty2' -> uUnboundVar tv1 ty2' ty2'
- UnBound -> if kind2 `isSubKindOf` kind1 then
- tcWriteTyVar tv1 ty2 `thenNF_Tc_` returnTc ()
- else if kind1 `isSubKindOf` kind2 then
- tcWriteTyVar tv2 (TyVarTy tv1) `thenNF_Tc_` returnTc ()
- else
- failTc (unifyKindErr tv1 ps_ty2)
+ case (maybe_ty1, maybe_ty2) of
+ (_, BoundTo ty2') -> uUnboundVar tv1 maybe_ty1 ty2' ty2'
+
+ (DontBind,DontBind)
+ -> failTc (unifyDontBindErr tv1 ps_ty2)
+
+ (UnBound, _) | kind2 `isSubKindOf` kind1
+ -> tcWriteTyVar tv1 ty2 `thenNF_Tc_` returnTc ()
+
+ (_, UnBound) | kind1 `isSubKindOf` kind2
+ -> tcWriteTyVar tv2 (TyVarTy tv1) `thenNF_Tc_` returnTc ()
+
+ other -> failTc (unifyKindErr tv1 ps_ty2)
-- Second one isn't a type variable
-uUnboundVar tv1@(TyVar uniq1 kind1 name1 box1) ps_ty2 non_var_ty2
- = occur_check non_var_ty2 `thenTc_`
- checkTc (getTypeKind non_var_ty2 `isSubKindOf` kind1)
- (unifyKindErr tv1 ps_ty2) `thenTc_`
- tcWriteTyVar tv1 non_var_ty2 `thenNF_Tc_`
- returnTc ()
+uUnboundVar tv1@(TyVar uniq1 kind1 name1 box1) maybe_ty1 ps_ty2 non_var_ty2
+ = case maybe_ty1 of
+ DontBind -> failTc (unifyDontBindErr tv1 ps_ty2)
+
+ UnBound | getTypeKind non_var_ty2 `isSubKindOf` kind1
+ -> occur_check non_var_ty2 `thenTc_`
+ tcWriteTyVar tv1 ps_ty2 `thenNF_Tc_`
+ returnTc ()
+
+ other -> failTc (unifyKindErr tv1 ps_ty2)
where
occur_check (TyVarTy tv2@(TyVar uniq2 _ _ box2))
| uniq1 == uniq2 -- Same tyvar; fail
= tcReadTyVar tv2 `thenNF_Tc` \ maybe_ty2 ->
case maybe_ty2 of
BoundTo ty2' -> occur_check ty2'
- UnBound -> returnTc ()
+ other -> returnTc ()
occur_check (AppTy fun arg) = occur_check fun `thenTc_` occur_check arg
occur_check (FunTy fun arg _) = occur_check fun `thenTc_` occur_check arg
occur_check other = panic "Unexpected Dict or ForAll in occurCheck"
\end{code}
-Notes on synonyms
-~~~~~~~~~~~~~~~~~
-If you are tempted to make a short cut on synonyms, as in this
-pseudocode...
+%************************************************************************
+%* *
+\subsection[Unify-fun]{@unifyFunTy@}
+%* *
+%************************************************************************
-\begin{verbatim}
-uTys (SynTy con1 args1 ty1) (SynTy con2 args2 ty2)
- = if (con1 == con2) then
- -- Good news! Same synonym constructors, so we can shortcut
- -- by unifying their arguments and ignoring their expansions.
- unifyTauTypeLists args1 args2
- else
- -- Never mind. Just expand them and try again
- uTys ty1 ty2
-\end{verbatim}
+@unifyFunTy@ is used to avoid the fruitless creation of type variables.
-then THINK AGAIN. Here is the whole story, as detected and reported
-by Chris Okasaki \tr{<Chris_Okasaki@loch.mess.cs.cmu.edu>}:
-\begin{quotation}
-Here's a test program that should detect the problem:
+\begin{code}
+unifyFunTy :: TcType s -- Fail if ty isn't a function type
+ -> TcM s (TcType s, TcType s) -- otherwise return arg and result types
-\begin{verbatim}
- type Bogus a = Int
- x = (1 :: Bogus Char) :: Bogus Bool
-\end{verbatim}
+unifyFunTy ty@(TyVarTy tyvar)
+ = tcReadTyVar tyvar `thenNF_Tc` \ maybe_ty ->
+ case maybe_ty of
+ BoundTo ty' -> unifyFunTy ty'
-The problem with [the attempted shortcut code] is that
-\begin{verbatim}
- con1 == con2
-\end{verbatim}
-is not a sufficient condition to be able to use the shortcut!
-You also need to know that the type synonym actually USES all
-its arguments. For example, consider the following type synonym
-which does not use all its arguments.
-\begin{verbatim}
- type Bogus a = Int
-\end{verbatim}
+ UnBound -> newTyVarTy mkTypeKind `thenNF_Tc` \ arg ->
+ newTyVarTy mkTypeKind `thenNF_Tc` \ res ->
+ tcWriteTyVar tyvar (mkFunTy arg res) `thenNF_Tc_`
+ returnTc (arg,res)
-If you ever tried unifying, say, \tr{Bogus Char} with \tr{Bogus Bool},
-the unifier would blithely try to unify \tr{Char} with \tr{Bool} and
-would fail, even though the expanded forms (both \tr{Int}) should
-match.
+ DontBind -> failTc (expectedFunErr ty)
-Similarly, unifying \tr{Bogus Char} with \tr{Bogus t} would
-unnecessarily bind \tr{t} to \tr{Char}.
+unifyFunTy other_ty
+ = case getFunTy_maybe other_ty of
+ Just arg_and_res -> returnTc arg_and_res
+ Nothing -> failTc (expectedFunErr other_ty)
+\end{code}
-... You could explicitly test for the problem synonyms and mark them
-somehow as needing expansion, perhaps also issuing a warning to the
-user.
-\end{quotation}
+%************************************************************************
+%* *
+\subsection[Unify-context]{Errors and contexts}
+%* *
+%************************************************************************
Errors
~~~~~~
\begin{code}
-unifyCtxt ty1 ty2 sty
- = ppAboves [
- ppCat [ppStr "Expected:", ppr sty ty1],
- ppCat [ppStr " Actual:", ppr sty ty2]
- ]
+unifyCtxt ty1 ty2
+ = zonkTcType ty1 `thenNF_Tc` \ ty1' ->
+ zonkTcType ty2 `thenNF_Tc` \ ty2' ->
+ returnNF_Tc (err ty1' ty2')
+ where
+ err ty1' ty2' sty = ppAboves [
+ ppCat [ppStr "When matching:", ppr sty ty1'],
+ ppCat [ppStr " against:", ppr sty ty2']
+ ]
unifyMisMatch ty1 ty2 sty
= ppHang (ppStr "Couldn't match the type")
4 (ppSep [ppr sty ty1, ppStr "against", ppr sty ty2])
+expectedFunErr ty sty
+ = ppHang (ppStr "Function type expected, but found the type")
+ 4 (ppr sty ty)
+
unifyKindErr tyvar ty sty
- = ppHang (ppStr "Kind mis-match between")
- 4 (ppSep [ppr sty tyvar, ppStr "and", ppr sty ty])
+ = ppHang (ppStr "Compiler bug: kind mis-match between")
+ 4 (ppSep [ppr sty tyvar, ppLparen, ppr sty (getTyVarKind tyvar), ppRparen,
+ ppStr "and",
+ ppr sty ty, ppLparen, ppr sty (getTypeKind ty), ppRparen])
+
+unifyDontBindErr tyvar ty sty
+ = ppHang (ppStr "Couldn't match the *signature/existential* type variable")
+ 4 (ppSep [ppr sty tyvar,
+ ppStr "with the type",
+ ppr sty ty])
unifyOccurCheck tyvar ty sty
- = ppHang (ppStr "Occur check: cannot construct the infinite type")
+ = ppHang (ppStr "Cannot construct the infinite type (occur check)")
4 (ppSep [ppr sty tyvar, ppStr "=", ppr sty ty])
\end{code}
import Ubiq{-uitous-}
import Util ( panic )
+import Outputable ( Outputable(..) )
+import Pretty
\end{code}
\begin{code}
argKind (ArrowKind arg_kind _) = arg_kind
argKind other_kind = panic "argKind"
\end{code}
+
+Printing
+~~~~~~~~
+\begin{code}
+instance Outputable Kind where
+ ppr sty kind = pprKind kind
+
+pprKind TypeKind = ppStr "*"
+pprKind BoxedTypeKind = ppStr "*b"
+pprKind UnboxedTypeKind = ppStr "*u"
+pprKind (ArrowKind k1 k2) = ppSep [pprKind_parend k1, ppStr "->", pprKind k2]
+
+pprKind_parend k@(ArrowKind _ _) = ppBesides [ppLparen, pprKind k, ppRparen]
+pprKind_parend k = pprKind k
+\end{code}
#include "HsVersions.h"
module PprType(
- GenTyVar, pprTyVar,
- TyCon, pprTyCon,
- GenType, pprType, pprParendType,
- pprType_Internal,
+ GenTyVar, pprGenTyVar,
+ TyCon, pprTyCon, showTyCon,
+ GenType,
+ pprGenType, pprParendGenType,
+ pprType, pprParendType,
+ pprMaybeTy,
getTypeString,
typeMaybeString,
specMaybeTysSuffix,
GenClass,
- GenClassOp, pprClassOp
+ GenClassOp, pprGenClassOp
) where
import Ubiq
import Type ( GenType(..), maybeAppTyCon,
splitForAllTy, splitSigmaTy, splitRhoTy, splitAppTy )
import TyVar ( GenTyVar(..) )
-import TyCon ( TyCon(..), ConsVisible, NewOrData )
+import TyCon ( TyCon(..), NewOrData )
import Class ( Class(..), GenClass(..),
ClassOp(..), GenClassOp(..) )
import Kind ( Kind(..) )
import Maybes ( maybeToBool )
import NameTypes ( ShortName, FullName )
import Outputable ( ifPprShowAll, isAvarop, interpp'SP )
-import PprStyle ( PprStyle(..), codeStyle )
+import PprStyle ( PprStyle(..), codeStyle, showUserishTypes )
import Pretty
import TysWiredIn ( listTyCon )
import Unique ( pprUnique10, pprUnique )
\begin{code}
instance (Eq tyvar, Outputable tyvar,
Eq uvar, Outputable uvar ) => Outputable (GenType tyvar uvar) where
- ppr sty ty = pprType sty ty
+ ppr sty ty = pprGenType sty ty
instance Outputable TyCon where
ppr sty tycon = pprTyCon sty tycon
ppr sty (Class u n _ _ _ _ _ _ _ _) = ppr sty n
instance Outputable ty => Outputable (GenClassOp ty) where
- ppr sty clsop = pprClassOp sty clsop
+ ppr sty clsop = pprGenClassOp sty clsop
instance Outputable (GenTyVar flexi) where
- ppr sty tv = pprTyVar sty tv
+ ppr sty tv = pprGenTyVar sty tv
+
+-- and two SPECIALIZEd ones:
+instance Outputable {-Type, i.e.:-}(GenType TyVar UVar) where
+ ppr sty ty = pprGenType sty ty
+
+instance Outputable {-TyVar, i.e.:-}(GenTyVar Usage) where
+ ppr sty ty = pprGenTyVar sty ty
\end{code}
%************************************************************************
%* *
%************************************************************************
-@pprType@ is the std @Type@ printer; the overloaded @ppr@ function is
-defined to use this. @pprParendType@ is the same, except it puts
-parens around the type, except for the atomic cases. @pprParendType@
+@pprGenType@ is the std @Type@ printer; the overloaded @ppr@ function is
+defined to use this. @pprParendGenType@ is the same, except it puts
+parens around the type, except for the atomic cases. @pprParendGenType@
works just by setting the initial context precedence very high.
\begin{code}
-pprType, pprParendType :: (Eq tyvar, Outputable tyvar, Eq uvar, Outputable uvar)
+pprGenType, pprParendGenType :: (Eq tyvar, Outputable tyvar, Eq uvar, Outputable uvar)
=> PprStyle -> GenType tyvar uvar -> Pretty
-pprType sty ty = ppr_ty sty (initial_ve sty) tOP_PREC ty
-pprParendType sty ty = ppr_ty sty (initial_ve sty) tYCON_PREC ty
+pprGenType sty ty = ppr_ty sty (initial_ve sty) tOP_PREC ty
+pprParendGenType sty ty = ppr_ty sty (initial_ve sty) tYCON_PREC ty
+
+pprType sty ty = ppr_ty sty (initial_ve sty) tOP_PREC (ty :: Type)
+pprParendType sty ty = ppr_ty sty (initial_ve sty) tYCON_PREC (ty :: Type)
pprMaybeTy :: (Eq tyvar, Outputable tyvar, Eq uvar, Outputable uvar)
=> PprStyle -> Maybe (GenType tyvar uvar) -> Pretty
pprMaybeTy sty Nothing = ppChar '*'
-pprMaybeTy sty (Just ty) = pprParendType sty ty
-\end{code}
-
-This somewhat sleazy interface is used when printing out Core syntax
-(see PprCore):
-\begin{code}
-pprType_Internal sty tvs ppr_tv uvs ppr_uv ty
- = ppr_ty sty (VE tvs ppr_tv uvs ppr_uv) tOP_PREC ty
+pprMaybeTy sty (Just ty) = pprParendGenType sty ty
\end{code}
\begin{code}
maybeParen ctxt_prec inner_prec pretty
| ctxt_prec < inner_prec = pretty
| otherwise = ppParens pretty
-
-
--- True means types like (Eq a, Text b) => a -> b
--- False means types like _forall_ a b => Eq a -> Text b -> a -> b
-showUserishTypes PprForUser = True
-showUserishTypes PprInterface = True
-showUserishTypes other = False
\end{code}
-
-
%************************************************************************
%* *
\subsection[TyVar]{@TyVar@}
%************************************************************************
\begin{code}
-pprTyVar sty (TyVar uniq kind name usage)
+pprGenTyVar sty (TyVar uniq kind name usage)
= ppBesides [pp_name, pprUnique10 uniq]
where
pp_name = case name of
pprTyCon sty (TupleTyCon arity) = ppBeside (ppPStr SLIT("Tuple")) (ppInt arity)
pprTyCon sty (PrimTyCon uniq name kind) = ppr sty name
-pprTyCon sty tycon@(DataTyCon uniq kind name tyvars ctxt cons derivings cv nd)
+pprTyCon sty tycon@(DataTyCon uniq kind name tyvars ctxt cons derivings nd)
= case sty of
PprDebug -> pp_tycon_and_uniq
PprShowAll -> pp_tycon_and_uniq
(ppCat [ ppStr " {-",
ppInt arity,
interpp'SP sty tyvars,
- pprParendType sty expansion,
+ pprParendGenType sty expansion,
ppStr "-}"]))
\end{code}
%************************************************************************
\begin{code}
-pprClassOp :: Outputable ty => PprStyle -> GenClassOp ty -> Pretty
+pprGenClassOp :: Outputable ty => PprStyle -> GenClassOp ty -> Pretty
-pprClassOp sty op = ppr_class_op sty [] op
+pprGenClassOp sty op = ppr_class_op sty [] op
ppr_class_op sty tyvars (ClassOp op_name i ty)
= case sty of
| otherwise = [mod, string]
where
string = _PK_ (tidy (ppShow 1000 ppr_t))
- ppr_t = pprType PprForC ty
+ ppr_t = pprGenType PprForC ty
-- PprForC expands type synonyms as it goes
(is_prelude_ty, mod)
ppCat [ppPStr SLIT("type"), ppr sty n, ppIntersperse ppSP pp_tyvars,
ppEquals, ppr_ty sty lookup_fn tOP_PREC exp]
-pprTyCon sty@PprInterface this_tycon@(DataTyCon k n a vs ctxt cons derivings unabstract data_or_new) specs
+pprTyCon sty@PprInterface this_tycon@(DataTyCon k n a vs ctxt cons derivings data_or_new) specs
= ppHang (ppCat [pp_data_or_new,
pprContext sty ctxt,
ppr sty n,
where
ppr_con con
= let
- (_, _, con_arg_tys, _) = getDataConSig con
+ (_, _, con_arg_tys, _) = dataConSig con
in
ppCat [pprNonOp PprForUser con, -- the data con's name...
ppIntersperse ppSP (map (ppr_ty sty lookup_fn tYCON_PREC) con_arg_tys)]
pp_the_list (p:ps) = ppAbove (ppBeside p ppComma) (pp_the_list ps)
pp_maybe Nothing = pp_NONE
- pp_maybe (Just ty) = pprParendType sty ty
+ pp_maybe (Just ty) = pprParendGenType sty ty
pp_NONE = ppPStr SLIT("_N_")
module TyCon(
TyCon(..), -- NB: some pals need to see representation
- Arity(..), ConsVisible(..), NewOrData(..),
+ Arity(..), NewOrData(..),
- isFunTyCon, isPrimTyCon, isVisibleDataTyCon,
+ isFunTyCon, isPrimTyCon, isBoxedTyCon,
+ isDataTyCon, isSynTyCon,
mkDataTyCon,
mkFunTyCon,
mkSynTyCon,
- getTyConKind,
- getTyConUnique,
- getTyConTyVars,
- getTyConDataCons,
- getTyConDerivings,
- getSynTyConArity,
+ tyConKind,
+ tyConUnique,
+ tyConTyVars,
+ tyConDataCons,
+ tyConFamilySize,
+ tyConDerivings,
+ tyConArity, synTyConArity,
+ getSynTyConDefn,
maybeTyConSingleCon,
isEnumerationTyCon,
import TyLoop ( Type(..), GenType,
Class(..), GenClass,
Id(..), GenId,
- mkTupleCon, getDataConSig,
+ mkTupleCon, dataConSig,
specMaybeTysSuffix
)
[(Class,Type)] -- Its context
[Id] -- Its data constructors, with fully polymorphic types
[Class] -- Classes which have derived instances
- ConsVisible
NewOrData
| TupleTyCon Arity -- just a special case of DataTyCon
-- Acts as a template for the expansion when
-- the tycon is applied to some types.
-data ConsVisible
- = ConsVisible -- whether or not data constructors are visible
- | ConsInvisible -- outside their TyCon's defining module.
-
data NewOrData
= NewType -- "newtype Blah ..."
| DataType -- "data Blah ..."
isPrimTyCon (PrimTyCon _ _ _) = True
isPrimTyCon _ = False
-isVisibleDataTyCon (DataTyCon _ _ _ _ _ _ _ ConsVisible _) = True
-isVisibleDataTyCon _ = False
+-- At present there are no unboxed non-primitive types, so
+-- isBoxedTyCon is just the negation of isPrimTyCon.
+isBoxedTyCon = not . isPrimTyCon
+
+-- isDataTyCon returns False for @newtype@.
+-- Not sure about this decision yet.
+isDataTyCon (DataTyCon _ _ _ _ _ _ _ DataType) = True
+isDataTyCon other = False
+
+isSynTyCon (SynTyCon _ _ _ _ _ _) = True
+isSynTyCon _ = False
\end{code}
\begin{code}
kind1 = mkBoxedTypeKind `mkArrowKind` mkBoxedTypeKind
kind2 = mkBoxedTypeKind `mkArrowKind` kind1
-getTyConKind :: TyCon -> Kind
-getTyConKind FunTyCon = kind2
-getTyConKind (DataTyCon _ kind _ _ _ _ _ _ _) = kind
-getTyConKind (PrimTyCon _ _ kind) = kind
+tyConKind :: TyCon -> Kind
+tyConKind FunTyCon = kind2
+tyConKind (DataTyCon _ kind _ _ _ _ _ _) = kind
+tyConKind (PrimTyCon _ _ kind) = kind
-getTyConKind (SpecTyCon tc tys)
- = spec (getTyConKind tc) tys
+tyConKind (SpecTyCon tc tys)
+ = spec (tyConKind tc) tys
where
spec kind [] = kind
spec kind (Just _ : tys) = spec (resultKind kind) tys
spec kind (Nothing : tys) =
argKind kind `mkArrowKind` spec (resultKind kind) tys
-getTyConKind (TupleTyCon n)
+tyConKind (TupleTyCon n)
= mkArrow n
where
mkArrow 0 = mkBoxedTypeKind
\end{code}
\begin{code}
-getTyConUnique :: TyCon -> Unique
-getTyConUnique FunTyCon = funTyConKey
-getTyConUnique (DataTyCon uniq _ _ _ _ _ _ _ _) = uniq
-getTyConUnique (TupleTyCon a) = mkTupleTyConUnique a
-getTyConUnique (PrimTyCon uniq _ _) = uniq
-getTyConUnique (SynTyCon uniq _ _ _ _ _) = uniq
-getTyConUnique (SpecTyCon _ _ ) = panic "getTyConUnique:SpecTyCon"
+tyConUnique :: TyCon -> Unique
+tyConUnique FunTyCon = funTyConKey
+tyConUnique (DataTyCon uniq _ _ _ _ _ _ _) = uniq
+tyConUnique (TupleTyCon a) = mkTupleTyConUnique a
+tyConUnique (PrimTyCon uniq _ _) = uniq
+tyConUnique (SynTyCon uniq _ _ _ _ _) = uniq
+tyConUnique (SpecTyCon _ _ ) = panic "tyConUnique:SpecTyCon"
+
+tyConArity :: TyCon -> Arity
+tyConArity FunTyCon = 2
+tyConArity (DataTyCon _ _ _ tvs _ _ _ _) = length tvs
+tyConArity (TupleTyCon arity) = arity
+tyConArity (PrimTyCon _ _ _) = 0 -- ??
+tyConArity (SpecTyCon _ _) = 0
+tyConArity (SynTyCon _ _ _ arity _ _) = arity
+
+synTyConArity :: TyCon -> Maybe Arity -- Nothing <=> not a syn tycon
+synTyConArity (SynTyCon _ _ _ arity _ _) = Just arity
+synTyConArity _ = Nothing
\end{code}
\begin{code}
-getTyConTyVars :: TyCon -> [TyVar]
-getTyConTyVars FunTyCon = [alphaTyVar,betaTyVar]
-getTyConTyVars (DataTyCon _ _ _ tvs _ _ _ _ _) = tvs
-getTyConTyVars (TupleTyCon arity) = take arity alphaTyVars
-getTyConTyVars (SynTyCon _ _ _ _ tvs _) = tvs
-getTyConTyVars (PrimTyCon _ _ _) = panic "getTyConTyVars:PrimTyCon"
-getTyConTyVars (SpecTyCon _ _ ) = panic "getTyConTyVars:SpecTyCon"
+tyConTyVars :: TyCon -> [TyVar]
+tyConTyVars FunTyCon = [alphaTyVar,betaTyVar]
+tyConTyVars (DataTyCon _ _ _ tvs _ _ _ _) = tvs
+tyConTyVars (TupleTyCon arity) = take arity alphaTyVars
+tyConTyVars (SynTyCon _ _ _ _ tvs _) = tvs
+tyConTyVars (PrimTyCon _ _ _) = panic "tyConTyVars:PrimTyCon"
+tyConTyVars (SpecTyCon _ _ ) = panic "tyConTyVars:SpecTyCon"
\end{code}
\begin{code}
-getTyConDataCons :: TyCon -> [Id]
-getTyConDataCons (DataTyCon _ _ _ _ _ data_cons _ _ _) = data_cons
-getTyConDataCons (TupleTyCon a) = [mkTupleCon a]
+tyConDataCons :: TyCon -> [Id]
+tyConFamilySize :: TyCon -> Int
+
+tyConDataCons (DataTyCon _ _ _ _ _ data_cons _ _) = data_cons
+tyConDataCons (TupleTyCon a) = [mkTupleCon a]
+tyConDataCons other = []
+ -- You may think this last equation should fail,
+ -- but it's quite convenient to return no constructors for
+ -- a synonym; see for example the call in TcTyClsDecls.
+
+tyConFamilySize (DataTyCon _ _ _ _ _ data_cons _ _) = length data_cons
+tyConFamilySize (TupleTyCon a) = 1
\end{code}
\begin{code}
-getTyConDerivings :: TyCon -> [Class]
-getTyConDerivings (DataTyCon _ _ _ _ _ _ derivs _ _) = derivs
+tyConDerivings :: TyCon -> [Class]
+tyConDerivings (DataTyCon _ _ _ _ _ _ derivs _) = derivs
+tyConDerivings other = []
\end{code}
\begin{code}
-getSynTyConArity :: TyCon -> Maybe Arity
-getSynTyConArity (SynTyCon _ _ _ arity _ _) = Just arity
-getSynTyConArity other = Nothing
+getSynTyConDefn :: TyCon -> ([TyVar], Type)
+getSynTyConDefn (SynTyCon _ _ _ _ tyvars ty) = (tyvars,ty)
\end{code}
\begin{code}
maybeTyConSingleCon :: TyCon -> Maybe Id
-maybeTyConSingleCon (TupleTyCon arity) = Just (mkTupleCon arity)
-maybeTyConSingleCon (DataTyCon _ _ _ _ _ [c] _ _ _) = Just c
-maybeTyConSingleCon (DataTyCon _ _ _ _ _ _ _ _ _) = Nothing
-maybeTyConSingleCon (PrimTyCon _ _ _) = Nothing
-maybeTyConSingleCon (SpecTyCon tc tys) = panic "maybeTyConSingleCon:SpecTyCon"
- -- requires DataCons of TyCon
+maybeTyConSingleCon (TupleTyCon arity) = Just (mkTupleCon arity)
+maybeTyConSingleCon (DataTyCon _ _ _ _ _ [c] _ _) = Just c
+maybeTyConSingleCon (DataTyCon _ _ _ _ _ _ _ _) = Nothing
+maybeTyConSingleCon (PrimTyCon _ _ _) = Nothing
+maybeTyConSingleCon (SpecTyCon tc tys) = panic "maybeTyConSingleCon:SpecTyCon"
+ -- requires DataCons of TyCon
isEnumerationTyCon (TupleTyCon arity)
= arity == 0
-isEnumerationTyCon (DataTyCon _ _ _ _ _ data_cons _ _ _)
+isEnumerationTyCon (DataTyCon _ _ _ _ _ data_cons _ _)
= not (null data_cons) && all is_nullary data_cons
where
- is_nullary con = case (getDataConSig con) of { (_,_, arg_tys, _) ->
+ is_nullary con = case (dataConSig con) of { (_,_, arg_tys, _) ->
null arg_tys }
\end{code}
\begin{code}
derivedFor :: Class -> TyCon -> Bool
-derivedFor clas (DataTyCon _ _ _ _ _ _ derivs _ _) = isIn "derivedFor" clas derivs
-derivedFor clas something_weird = False
+derivedFor clas (DataTyCon _ _ _ _ _ _ derivs _) = isIn "derivedFor" clas derivs
+derivedFor clas something_weird = False
\end{code}
%************************************************************************
\begin{code}
instance Ord3 TyCon where
- cmp FunTyCon FunTyCon = EQ_
- cmp (DataTyCon a _ _ _ _ _ _ _ _) (DataTyCon b _ _ _ _ _ _ _ _) = a `cmp` b
- cmp (SynTyCon a _ _ _ _ _) (SynTyCon b _ _ _ _ _) = a `cmp` b
- cmp (TupleTyCon a) (TupleTyCon b) = a `cmp` b
- cmp (PrimTyCon a _ _) (PrimTyCon b _ _) = a `cmp` b
- cmp (SpecTyCon tc1 mtys1) (SpecTyCon tc2 mtys2)
+ cmp FunTyCon FunTyCon = EQ_
+ cmp (DataTyCon a _ _ _ _ _ _ _) (DataTyCon b _ _ _ _ _ _ _) = a `cmp` b
+ cmp (SynTyCon a _ _ _ _ _) (SynTyCon b _ _ _ _ _) = a `cmp` b
+ cmp (TupleTyCon a) (TupleTyCon b) = a `cmp` b
+ cmp (PrimTyCon a _ _) (PrimTyCon b _ _) = a `cmp` b
+ cmp (SpecTyCon tc1 mtys1) (SpecTyCon tc2 mtys2)
= panic# "cmp on SpecTyCons" -- case (tc1 `cmp` tc2) of { EQ_ -> mtys1 `cmp` mtys2; xxx -> xxx }
-- now we *know* the tags are different, so...
where
tag1 = tag_TyCon other_1
tag2 = tag_TyCon other_2
- tag_TyCon FunTyCon = ILIT(1)
- tag_TyCon (DataTyCon _ _ _ _ _ _ _ _ _) = ILIT(2)
- tag_TyCon (TupleTyCon _) = ILIT(3)
- tag_TyCon (PrimTyCon _ _ _) = ILIT(4)
- tag_TyCon (SpecTyCon _ _) = ILIT(5)
+ tag_TyCon FunTyCon = ILIT(1)
+ tag_TyCon (DataTyCon _ _ _ _ _ _ _ _) = ILIT(2)
+ tag_TyCon (TupleTyCon _) = ILIT(3)
+ tag_TyCon (PrimTyCon _ _ _) = ILIT(4)
+ tag_TyCon (SpecTyCon _ _) = ILIT(5)
instance Eq TyCon where
a == b = case (a `cmp` b) of { EQ_ -> True; _ -> False }
Nothing -> mkBuiltinSrcLoc
Just name -> getSrcLoc name
- getItsUnique tycon = getTyConUnique tycon
+ getItsUnique tycon = tyConUnique tycon
fromPreludeCore tc = case get_name tc of
Nothing -> True
Emphatically un-exported:
\begin{code}
-get_name (DataTyCon _ _ n _ _ _ _ _ _) = Just n
-get_name (PrimTyCon _ n _) = Just n
-get_name (SpecTyCon tc _) = get_name tc
-get_name (SynTyCon _ n _ _ _ _) = Just n
-get_name other = Nothing
+get_name (DataTyCon _ _ n _ _ _ _ _) = Just n
+get_name (PrimTyCon _ n _) = Just n
+get_name (SpecTyCon tc _) = get_name tc
+get_name (SynTyCon _ n _ _ _ _) = Just n
+get_name other = Nothing
\end{code}
-
import Unique ( Unique )
import Id ( Id, GenId, StrictnessMark, mkTupleCon, mkDataCon,
- getDataConSig, getInstantiatedDataConSig )
+ dataConSig, getInstantiatedDataConSig )
import PprType ( specMaybeTysSuffix )
import NameTypes ( FullName )
import TyCon ( TyCon )
-- Needed in TyCon
mkTupleCon :: Int -> Id
-getDataConSig :: Id -> ([TyVar], [(Class, Type)], [Type], TyCon)
+dataConSig :: Id -> ([TyVar], [(Class, Type)], [Type], TyCon)
specMaybeTysSuffix :: [Maybe Type] -> _PackedString
instance Eq (GenClass a b)
GenTyVar(..), TyVar(..),
mkTyVar,
getTyVarKind, -- TyVar -> Kind
+ cloneTyVar,
alphaTyVars, alphaTyVar, betaTyVar, gammaTyVar, deltaTyVar,
growTyVarEnvList, isNullTyVarEnv, lookupTyVarEnv,
GenTyVarSet(..), TyVarSet(..),
- emptyTyVarSet, singletonTyVarSet, unionTyVarSets,
+ emptyTyVarSet, unitTyVarSet, unionTyVarSets,
unionManyTyVarSets, intersectTyVarSets, mkTyVarSet,
tyVarSetToList, elementOfTyVarSet, minusTyVarSet,
isEmptyTyVarSet
getTyVarKind :: GenTyVar flexi -> Kind
getTyVarKind (TyVar _ kind _ _) = kind
+
+cloneTyVar :: GenTyVar flexi -> Unique -> GenTyVar flexi
+cloneTyVar (TyVar _ k n x) u = TyVar u k n x
\end{code}
unionTyVarSets :: GenTyVarSet flexi -> GenTyVarSet flexi -> GenTyVarSet flexi
unionManyTyVarSets:: [GenTyVarSet flexi] -> GenTyVarSet flexi
tyVarSetToList :: GenTyVarSet flexi -> [GenTyVar flexi]
-singletonTyVarSet :: GenTyVar flexi -> GenTyVarSet flexi
+unitTyVarSet :: GenTyVar flexi -> GenTyVarSet flexi
elementOfTyVarSet :: GenTyVar flexi -> GenTyVarSet flexi -> Bool
minusTyVarSet :: GenTyVarSet flexi -> GenTyVarSet flexi -> GenTyVarSet flexi
isEmptyTyVarSet :: GenTyVarSet flexi -> Bool
mkTyVarSet :: [GenTyVar flexi] -> GenTyVarSet flexi
emptyTyVarSet = emptyUniqSet
-singletonTyVarSet = singletonUniqSet
+unitTyVarSet = unitUniqSet
intersectTyVarSets= intersectUniqSets
unionTyVarSets = unionUniqSets
unionManyTyVarSets= unionManyUniqSets
mkForAllUsageTy, getForAllUsageTy,
applyTy,
- isPrimType,
+ isPrimType, isUnboxedType, typePrimRep,
RhoType(..), SigmaType(..), ThetaType(..),
mkDictTy,
matchTy, matchTys, eqTy, eqSimpleTy, eqSimpleTheta,
- instantiateTy,instantiateUsage,
+ instantiateTy, instantiateTauTy, instantiateUsage,
+ applyTypeEnvToTy,
isTauTy,
-- friends:
import Class ( getClassSig, getClassOpLocalType, GenClass{-instances-} )
import Kind ( mkBoxedTypeKind, resultKind )
-import TyCon ( mkFunTyCon, mkTupleTyCon, isFunTyCon, isPrimTyCon,
- getTyConKind, getTyConDataCons, TyCon )
+import TyCon ( mkFunTyCon, mkTupleTyCon, isFunTyCon, isPrimTyCon, isDataTyCon, tyConArity,
+ tyConKind, tyConDataCons, getSynTyConDefn, TyCon )
import TyVar ( getTyVarKind, GenTyVar{-instances-}, GenTyVarSet(..),
emptyTyVarSet, unionTyVarSets, minusTyVarSet,
- singletonTyVarSet, nullTyVarEnv, lookupTyVarEnv,
+ unitTyVarSet, nullTyVarEnv, lookupTyVarEnv,
addOneToTyVarEnv, TyVarEnv(..) )
import Usage ( usageOmega, GenUsage, Usage(..), UVar(..), UVarEnv(..),
nullUVarEnv, addOneToUVarEnv, lookupUVarEnv, eqUVar,
eqUsage )
-- others
+import PrimRep ( PrimRep(..) )
import Util ( thenCmp, zipEqual, panic, panic#, assertPanic,
Ord3(..){-instances-}
)
\begin{code}
mkSynTy syn_tycon tys
- = SynTy syn_tycon tys (panic "Type.mkSynTy:expansion")
+ = SynTy syn_tycon tys (instantiateTauTy (zipEqual tyvars tys) body)
+ where
+ (tyvars, body) = getSynTyConDefn syn_tycon
\end{code}
Tau stuff
maybeAppDataTyCon ty
= case (getTyCon_maybe app_ty) of
- Nothing -> Nothing
- Just tycon | isFunTyCon tycon
- -> Nothing
- | otherwise
- -> Just (tycon, arg_tys, getTyConDataCons tycon)
+ Just tycon | isDataTyCon tycon &&
+ tyConArity tycon == length arg_tys
+ -- Must be saturated for ty to be a data type
+ -> Just (tycon, arg_tys, tyConDataCons tycon)
+
+ other -> Nothing
where
(app_ty, arg_tys) = splitAppTy ty
\begin{code}
getTypeKind :: GenType (GenTyVar any) u -> Kind
getTypeKind (TyVarTy tyvar) = getTyVarKind tyvar
-getTypeKind (TyConTy tycon usage) = getTyConKind tycon
+getTypeKind (TyConTy tycon usage) = tyConKind tycon
getTypeKind (SynTy _ _ ty) = getTypeKind ty
getTypeKind (FunTy fun arg _) = mkBoxedTypeKind
getTypeKind (DictTy clas arg _) = mkBoxedTypeKind
\begin{code}
tyVarsOfType :: GenType (GenTyVar flexi) uvar -> GenTyVarSet flexi
-tyVarsOfType (TyVarTy tv) = singletonTyVarSet tv
+tyVarsOfType (TyVarTy tv) = unitTyVarSet tv
tyVarsOfType (TyConTy tycon usage) = emptyTyVarSet
tyVarsOfType (SynTy _ tys ty) = tyVarsOfTypes tys
tyVarsOfType (FunTy arg res _) = tyVarsOfType arg `unionTyVarSets` tyVarsOfType res
tyVarsOfType (AppTy fun arg) = tyVarsOfType fun `unionTyVarSets` tyVarsOfType arg
tyVarsOfType (DictTy clas ty _) = tyVarsOfType ty
-tyVarsOfType (ForAllTy tyvar ty) = tyVarsOfType ty `minusTyVarSet` singletonTyVarSet tyvar
+tyVarsOfType (ForAllTy tyvar ty) = tyVarsOfType ty `minusTyVarSet` unitTyVarSet tyvar
tyVarsOfType (ForAllUsageTy _ _ ty) = tyVarsOfType ty
tyVarsOfTypes :: [GenType (GenTyVar flexi) uvar] -> GenTyVarSet flexi
go (ForAllUsageTy uvar bds ty) = ForAllUsageTy uvar bds (go ty)
+
+-- instantiateTauTy works only (a) on types with no ForAlls,
+-- and when (b) all the type variables are being instantiated
+-- In return it is more polymorphic than instantiateTy
+
+instantiateTauTy :: Eq t => [(t, GenType t' u)] -> GenType t u -> GenType t' u
+instantiateTauTy tenv ty
+ = go ty
+ where
+ go (TyVarTy tv) = case [ty | (tv',ty) <- tenv, tv==tv'] of
+ (ty:_) -> ty
+ [] -> panic "instantiateTauTy"
+ go (TyConTy tycon usage) = TyConTy tycon usage
+ go (SynTy tycon tys ty) = SynTy tycon (map go tys) (go ty)
+ go (FunTy arg res usage) = FunTy (go arg) (go res) usage
+ go (AppTy fun arg) = AppTy (go fun) (go arg)
+ go (DictTy clas ty usage) = DictTy clas (go ty) usage
+
instantiateUsage
:: Ord3 u => [(u, GenType t u')] -> GenType t u -> GenType t u'
instantiateUsage = error "instantiateUsage: not implemented"
\end{code}
\begin{code}
-isPrimType :: GenType tyvar uvar -> Bool
+type TypeEnv = TyVarEnv Type
+
+applyTypeEnvToTy :: TypeEnv -> SigmaType -> SigmaType
+applyTypeEnvToTy tenv ty
+ = mapOverTyVars v_fn ty
+ where
+ v_fn v = case (lookupTyVarEnv tenv v) of
+ Just ty -> ty
+ Nothing -> TyVarTy v
+\end{code}
+
+@mapOverTyVars@ is a local function which actually does the work. It
+does no cloning or other checks for shadowing, so be careful when
+calling this on types with Foralls in them.
+
+\begin{code}
+mapOverTyVars :: (TyVar -> Type) -> Type -> Type
+
+mapOverTyVars v_fn ty
+ = let
+ mapper = mapOverTyVars v_fn
+ in
+ case ty of
+ TyVarTy v -> v_fn v
+ SynTy c as e -> SynTy c (map mapper as) (mapper e)
+ FunTy a r u -> FunTy (mapper a) (mapper r) u
+ AppTy f a -> AppTy (mapper f) (mapper a)
+ DictTy c t u -> DictTy c (mapper t) u
+ ForAllTy v t -> ForAllTy v (mapper t)
+ tc@(TyConTy _ _) -> tc
+\end{code}
+
+At present there are no unboxed non-primitive types, so
+isUnboxedType is the same as isPrimType.
+
+\begin{code}
+isPrimType, isUnboxedType :: GenType tyvar uvar -> Bool
+
isPrimType (AppTy ty _) = isPrimType ty
isPrimType (SynTy _ _ ty) = isPrimType ty
isPrimType (TyConTy tycon _) = isPrimTyCon tycon
isPrimType _ = False
+
+isUnboxedType = isPrimType
+\end{code}
+
+This is *not* right: it is a placeholder (ToDo 96/03 WDP):
+\begin{code}
+typePrimRep :: GenType tyvar uvar -> PrimRep
+
+typePrimRep (SynTy _ _ ty) = typePrimRep ty
+typePrimRep (TyConTy tc _) = if isPrimTyCon tc then panic "typePrimRep:PrimTyCon" else PtrRep
+typePrimRep (AppTy ty _) = typePrimRep ty
+typePrimRep _ = PtrRep -- the "default"
\end{code}
%************************************************************************
module BitSet (
BitSet, -- abstract type
- mkBS, listBS, emptyBS, singletonBS,
+ mkBS, listBS, emptyBS, unitBS,
unionBS, minusBS
#if ! defined(COMPILING_GHC)
, elementBS, intersectBS, isEmptyBS
emptyBS = MkBS (int2Word# 0#)
mkBS :: [Int] -> BitSet
-mkBS xs = foldr (unionBS . singletonBS) emptyBS xs
+mkBS xs = foldr (unionBS . unitBS) emptyBS xs
-singletonBS :: Int -> BitSet
-singletonBS x = case x of
+unitBS :: Int -> BitSet
+unitBS x = case x of
I# i# -> MkBS ((int2Word# 1#) `shiftL#` i#)
unionBS :: BitSet -> BitSet -> BitSet
#if ! defined(COMPILING_GHC)
-- not used in GHC
isEmptyBS :: BitSet -> Bool
-isEmptyBS (MkBS s#) =
- case word2Int# s# of
+isEmptyBS (MkBS s#)
+ = case word2Int# s# of
0# -> True
_ -> False
emptyBS = MkBS 0
mkBS :: [Int] -> BitSet
-mkBS xs = foldr (unionBS . singletonBS) emptyBS xs
+mkBS xs = foldr (unionBS . unitBS) emptyBS xs
-singletonBS :: Int -> BitSet
-singletonBS x = MkBS (1 `ashInt` x)
+unitBS :: Int -> BitSet
+unitBS x = MkBS (1 `ashInt` x)
unionBS :: BitSet -> BitSet -> BitSet
unionBS (MkBS x) (MkBS y) = MkBS (x `logiorInt` y)
#if ! defined(COMPILING_GHC)
-- not used in GHC
isEmptyBS :: BitSet -> Bool
-isEmptyBS (MkBS s) =
- case s of
+isEmptyBS (MkBS s)
+ = case s of
0 -> True
_ -> False
intersectBS (MkBS x) (MkBS y) = MkBS (x `logandInt` y)
elementBS :: Int -> BitSet -> Bool
-elementBS x (MkBS s) =
- case logbitpInt x s of
+elementBS x (MkBS s)
+ = case logbitpInt x s of
0 -> False
_ -> True
#endif
emptyBS = MkBS 0
mkBS :: [Int] -> BitSet
-mkBS xs = foldr (unionBS . singletonBS) emptyBS xs
+mkBS xs = foldr (unionBS . unitBS) emptyBS xs
-singletonBS :: Int -> BitSet
-singletonBS x = MkBS (1 `bitLsh` x)
+unitBS :: Int -> BitSet
+unitBS x = MkBS (1 `bitLsh` x)
unionBS :: BitSet -> BitSet -> BitSet
unionBS (MkBS x) (MkBS y) = MkBS (x `bitOr` y)
#if ! defined(COMPILING_GHC)
-- not used in GHC
isEmptyBS :: BitSet -> Bool
-isEmptyBS (MkBS s) =
- case s of
+isEmptyBS (MkBS s)
+ = case s of
0 -> True
_ -> False
intersectBS (MkBS x) (MkBS y) = MkBS (x `bitAnd` y)
elementBS :: Int -> BitSet -> Bool
-elementBS x (MkBS s) =
- case (1 `bitLsh` x) `bitAnd` s of
+elementBS x (MkBS s)
+ = case (1 `bitLsh` x) `bitAnd` s of
0 -> False
_ -> True
#endif
cInt :: Int -> CSeq
#if defined(COMPILING_GHC)
-cAppendFile :: _FILE -> CSeq -> PrimIO ()
+cAppendFile :: _FILE -> CSeq -> IO ()
#endif
\end{code}
#if defined(COMPILING_GHC)
cAppendFile file_star seq
- = flattenIO file_star seq
+ = flattenIO file_star seq `seqPrimIO` return ()
#endif
\end{code}
module FiniteMap (
FiniteMap, -- abstract type
- emptyFM, singletonFM, listToFM,
+ emptyFM, unitFM, listToFM,
addToFM, addListToFM,
IF_NOT_GHC(addToFM_C COMMA)
\begin{code}
-- BUILDING
emptyFM :: FiniteMap key elt
-singletonFM :: key -> elt -> FiniteMap key elt
+unitFM :: key -> elt -> FiniteMap key elt
listToFM :: (Ord key OUTPUTABLE_key) => [(key,elt)] -> FiniteMap key elt
-- In the case of duplicates, the last is taken
-- #define EmptyFM (Branch _ _ IF_GHC(0#,0) _ _)
-singletonFM key elt = Branch key elt IF_GHC(1#,1) emptyFM emptyFM
+unitFM key elt = Branch key elt IF_GHC(1#,1) emptyFM emptyFM
listToFM key_elt_pairs = addListToFM emptyFM key_elt_pairs
\end{code}
\begin{code}
addToFM fm key elt = addToFM_C (\ old new -> new) fm key elt
-addToFM_C combiner EmptyFM key elt = singletonFM key elt
+addToFM_C combiner EmptyFM key elt = unitFM key elt
addToFM_C combiner (Branch key elt size fm_l fm_r) new_key new_elt
#ifdef __GLASGOW_HASKELL__
= case _tagCmp new_key key of
@mkBranch@ simply gets the size component right. This is the ONLY
(non-trivial) place the Branch object is built, so the ASSERTion
recursively checks consistency. (The trivial use of Branch is in
-@singletonFM@.)
+@unitFM@.)
\begin{code}
sIZE_RATIO :: Int
module MatchEnv (
MatchEnv, nullMEnv, mkMEnv,
- lookupMEnv, insertMEnv,
+ isEmptyMEnv, lookupMEnv, insertMEnv,
mEnvToList
) where
nullMEnv :: MatchEnv a b
nullMEnv = EmptyME
+isEmptyMEnv EmptyME = True
+isEmptyMEnv _ = False
+
mkMEnv :: [(key, value)] -> MatchEnv key value
+mkMEnv [] = EmptyME
mkMEnv stuff = ME stuff
mEnvToList :: MatchEnv key value -> [(key, value)]
-mEnvToList EmptyME = []
+mEnvToList EmptyME = []
mEnvToList (ME stuff) = stuff
\end{code}
module PprStyle (
PprStyle(..),
- codeStyle
+ codeStyle,
+ showUserishTypes
) where
CHK_Ubiq() -- debugging consistency check
codeStyle _ = False
\end{code}
+\begin{code}
+-- True means types like (Eq a, Text b) => a -> b
+-- False means types like _forall_ a b => Eq a -> Text b -> a -> b
+showUserishTypes PprForUser = True
+showUserishTypes PprInterface = True
+showUserishTypes other = False
+\end{code}
ppShow :: Int -> Pretty -> [Char]
#if defined(COMPILING_GHC)
-ppAppendFile :: _FILE -> Int -> Pretty -> PrimIO ()
+ppAppendFile :: _FILE -> Int -> Pretty -> IO ()
#endif
\end{code}
import Bag ( Bag )
import BinderInfo ( BinderInfo )
+import CgBindery ( CgIdInfo )
+import CharSeq ( CSeq )
+import CLabel ( CLabel )
import Class ( GenClass, GenClassOp, Class(..), ClassOp )
+import ClosureInfo ( ClosureInfo, LambdaFormInfo )
import CmdLineOpts ( SimplifierSwitch, SwitchResult )
import CoreSyn ( GenCoreArg, GenCoreBinder, GenCoreBinding, GenCoreExpr,
GenCoreCaseAlts, GenCoreCaseDefault
)
import CoreUnfold ( UnfoldingDetails, UnfoldingGuidance )
import CostCentre ( CostCentre )
+import FieldLabel ( FieldLabel )
import FiniteMap ( FiniteMap )
+import HeapOffs ( HeapOffset )
import HsCore ( UnfoldingCoreExpr )
import HsPat ( OutPat )
import HsPragmas ( ClassOpPragmas, ClassPragmas, DataPragmas, GenPragmas,
import PrimOp ( PrimOp )
import PrimRep ( PrimRep )
import ProtoName ( ProtoName )
+import SMRep ( SMRep )
import SrcLoc ( SrcLoc )
import TcType ( TcMaybe )
import TyCon ( TyCon, Arity(..) )
data ArityInfo
data Bag a
data BinderInfo
+data CgIdInfo
+data CLabel
data ClassOpPragmas a
data ClassPragmas a
+data ClosureInfo
data CostCentre
+data CSeq
data DataPragmas a
data DeforestInfo
data Demand
data ExportFlag
+data FieldLabel
data FiniteMap a b
data FullName -- NB: fails the optimisation criterion
data GenClass a b
data GenTyVar a -- NB: fails the optimisation criterion
data GenType a b
data GenUsage a
+data HeapOffset
data IdInfo
data InstancePragmas a
data Kind
+data LambdaFormInfo
data Literal
data MaybeErr a b
data MatchEnv a b
data ProtoName
data ShortName -- NB: fails the optimisation criterion
data SimplifierSwitch
+data SMRep
data SrcLoc
data StrictnessInfo
data StrictnessMark
UniqFM, -- abstract type
emptyUFM,
- singletonUFM,
- singletonDirectlyUFM,
+ unitUFM,
+ unitDirectlyUFM,
listToUFM,
listToUFM_Directly,
addToUFM,
\begin{code}
emptyUFM :: UniqFM elt
isNullUFM :: UniqFM elt -> Bool
-singletonUFM :: NamedThing key => key -> elt -> UniqFM elt
-singletonDirectlyUFM -- got the Unique already
+unitUFM :: NamedThing key => key -> elt -> UniqFM elt
+unitDirectlyUFM -- got the Unique already
:: Unique -> elt -> UniqFM elt
listToUFM :: NamedThing key => [(key,elt)] -> UniqFM elt
listToUFM_Directly
-- I don't think HBC was too happy about this (WDP 94/10)
{-# SPECIALIZE
- singletonUFM :: Id -> elt -> IdFinMap elt,
+ unitUFM :: Id -> elt -> IdFinMap elt,
TyVar -> elt -> TyVarFinMap elt,
Name -> elt -> NameFinMap elt
IF_NCG(COMMA Reg -> elt -> RegFinMap elt)
\begin{code}
emptyUFM = EmptyUFM
-singletonUFM key elt = mkLeafUFM (u2i (getItsUnique key)) elt
-singletonDirectlyUFM key elt = mkLeafUFM (u2i key) elt
+unitUFM key elt = mkLeafUFM (u2i (getItsUnique key)) elt
+unitDirectlyUFM key elt = mkLeafUFM (u2i key) elt
listToUFM key_elt_pairs
= addListToUFM_C use_snd EmptyUFM key_elt_pairs
module UniqSet (
UniqSet(..), -- abstract type: NOT
- mkUniqSet, uniqSetToList, emptyUniqSet, singletonUniqSet,
+ mkUniqSet, uniqSetToList, emptyUniqSet, unitUniqSet,
+ addOneToUniqSet,
unionUniqSets, unionManyUniqSets, minusUniqSet,
elementOfUniqSet, mapUniqSet, intersectUniqSets,
isEmptyUniqSet
emptyUniqSet :: UniqSet a
emptyUniqSet = MkUniqSet emptyUFM
-singletonUniqSet :: NamedThing a => a -> UniqSet a
-singletonUniqSet x = MkUniqSet (singletonUFM x x)
+unitUniqSet :: NamedThing a => a -> UniqSet a
+unitUniqSet x = MkUniqSet (unitUFM x x)
uniqSetToList :: UniqSet a -> [a]
uniqSetToList (MkUniqSet set) = eltsUFM set
mkUniqSet :: NamedThing a => [a] -> UniqSet a
mkUniqSet xs = MkUniqSet (listToUFM [ (x, x) | x <- xs])
+addOneToUniqSet :: NamedThing a => UniqSet a -> a -> UniqSet a
+addOneToUniqSet set x = set `unionUniqSets` unitUniqSet x
+
unionUniqSets :: UniqSet a -> UniqSet a -> UniqSet a
unionUniqSets (MkUniqSet set1) (MkUniqSet set2) = MkUniqSet (plusUFM set1 set2)
#if 0
#if __GLASGOW_HASKELL__
{-# SPECIALIZE
- singletonUniqSet :: GenId ty -> GenIdSet ty,
+ unitUniqSet :: GenId ty -> GenIdSet ty,
GenTyVar flexi -> GenTyVarSet flexi,
Name -> NameSet
IF_NCG(COMMA Reg -> RegSet)
uppSP, uppLbrack, uppRbrack, uppLparen, uppRparen,
uppSemi, uppComma, uppEquals,
+ uppBracket, uppParens,
uppCat, uppBeside, uppBesides, uppAbove, uppAboves,
uppNest, uppSep, uppInterleave, uppIntersperse,
uppShow,
uppInt :: Int -> Unpretty
uppInteger :: Integer -> Unpretty
+uppBracket :: Unpretty -> Unpretty -- put brackets around it
+uppParens :: Unpretty -> Unpretty -- put parens around it
+
uppBeside :: Unpretty -> Unpretty -> Unpretty
uppBesides :: [Unpretty] -> Unpretty
ppBesideSP :: Unpretty -> Unpretty -> Unpretty
uppShow :: Int -> Unpretty -> [Char]
-uppAppendFile :: _FILE -> Int -> Unpretty -> PrimIO ()
+uppAppendFile :: _FILE -> Int -> Unpretty -> IO ()
\end{code}
%************************************************
uppComma = cCh ','
uppEquals = cCh '='
+uppBracket p = uppBeside uppLbrack (uppBeside p uppRbrack)
+uppParens p = uppBeside uppLparen (uppBeside p uppRparen)
+
uppInterleave sep ps = uppSep (pi ps)
where
pi [] = []
-- error handling
#if defined(COMPILING_GHC)
- , panic, panic#, pprPanic, pprPanic#, pprTrace
+ , panic, panic#, pprPanic, pprPanic#, pprError, pprTrace
# ifdef DEBUG
, assertPanic
# endif
++ "to glasgow-haskell-bugs@dcs.glasgow.ac.uk.\n\n" )
pprPanic heading pretty_msg = panic (heading++(ppShow 80 pretty_msg))
+pprError heading pretty_msg = error (heading++(ppShow 80 pretty_msg))
pprTrace heading pretty_msg = trace (heading++(ppShow 80 pretty_msg))
-- #-versions because panic can't return an unboxed int, and that's