summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/main/DriverPhases.hs59
-rw-r--r--compiler/main/DriverPipeline.hs149
-rw-r--r--compiler/main/DynFlags.hs60
-rw-r--r--compiler/main/GhcMake.hs4
-rw-r--r--compiler/main/HscMain.hs3
-rw-r--r--compiler/nativeGen/SPARC/Base.hs55
-rw-r--r--compiler/nativeGen/X86/CodeGen.hs12
-rw-r--r--compiler/prelude/PrelRules.lhs24
-rw-r--r--compiler/typecheck/TcForeign.lhs18
-rw-r--r--compiler/typecheck/TcValidity.lhs8
-rw-r--r--compiler/types/FunDeps.lhs66
11 files changed, 303 insertions, 155 deletions
diff --git a/compiler/main/DriverPhases.hs b/compiler/main/DriverPhases.hs
index a1eac536b6..2de19b9795 100644
--- a/compiler/main/DriverPhases.hs
+++ b/compiler/main/DriverPhases.hs
@@ -35,6 +35,7 @@ module DriverPhases (
#include "HsVersions.h"
+import {-# SOURCE #-} DynFlags
import Outputable
import Platform
import System.FilePath
@@ -131,33 +132,39 @@ eqPhase _ _ = False
-- Partial ordering on phases: we want to know which phases will occur before
-- which others. This is used for sanity checking, to ensure that the
-- pipeline will stop at some point (see DriverPipeline.runPipeline).
-happensBefore :: Phase -> Phase -> Bool
-StopLn `happensBefore` _ = False
-x `happensBefore` y = after_x `eqPhase` y || after_x `happensBefore` y
- where
- after_x = nextPhase x
+happensBefore :: DynFlags -> Phase -> Phase -> Bool
+happensBefore dflags p1 p2 = p1 `happensBefore'` p2
+ where StopLn `happensBefore'` _ = False
+ x `happensBefore'` y = after_x `eqPhase` y
+ || after_x `happensBefore'` y
+ where after_x = nextPhase dflags x
-nextPhase :: Phase -> Phase
--- A conservative approximation to the next phase, used in happensBefore
-nextPhase (Unlit sf) = Cpp sf
-nextPhase (Cpp sf) = HsPp sf
-nextPhase (HsPp sf) = Hsc sf
-nextPhase (Hsc _) = HCc
-nextPhase Splitter = SplitAs
-nextPhase LlvmOpt = LlvmLlc
-nextPhase LlvmLlc = LlvmMangle
-nextPhase LlvmMangle = As
-nextPhase SplitAs = MergeStub
-nextPhase As = MergeStub
-nextPhase Ccpp = As
-nextPhase Cc = As
-nextPhase Cobjc = As
-nextPhase Cobjcpp = As
-nextPhase CmmCpp = Cmm
-nextPhase Cmm = HCc
-nextPhase HCc = As
-nextPhase MergeStub = StopLn
-nextPhase StopLn = panic "nextPhase: nothing after StopLn"
+nextPhase :: DynFlags -> Phase -> Phase
+nextPhase dflags p
+ -- A conservative approximation to the next phase, used in happensBefore
+ = case p of
+ Unlit sf -> Cpp sf
+ Cpp sf -> HsPp sf
+ HsPp sf -> Hsc sf
+ Hsc _ -> maybeHCc
+ Splitter -> SplitAs
+ LlvmOpt -> LlvmLlc
+ LlvmLlc -> LlvmMangle
+ LlvmMangle -> As
+ SplitAs -> MergeStub
+ As -> MergeStub
+ Ccpp -> As
+ Cc -> As
+ Cobjc -> As
+ Cobjcpp -> As
+ CmmCpp -> Cmm
+ Cmm -> maybeHCc
+ HCc -> As
+ MergeStub -> StopLn
+ StopLn -> panic "nextPhase: nothing after StopLn"
+ where maybeHCc = if platformUnregisterised (targetPlatform dflags)
+ then HCc
+ else As
-- the first compilation phase for a given file is determined
-- by its suffix.
diff --git a/compiler/main/DriverPipeline.hs b/compiler/main/DriverPipeline.hs
index 849532de79..b128c1f107 100644
--- a/compiler/main/DriverPipeline.hs
+++ b/compiler/main/DriverPipeline.hs
@@ -503,70 +503,96 @@ runPipeline
-> IO (DynFlags, FilePath) -- ^ (final flags, output filename)
runPipeline stop_phase hsc_env0 (input_fn, mb_phase)
mb_basename output maybe_loc maybe_stub_o
- = do r <- runPipeline' stop_phase hsc_env0 (input_fn, mb_phase)
- mb_basename output maybe_loc maybe_stub_o
- let dflags = extractDynFlags hsc_env0
- whenCannotGenerateDynamicToo dflags $ do
+
+ = do let
+ dflags0 = hsc_dflags hsc_env0
+
+ -- Decide where dump files should go based on the pipeline output
+ dflags = dflags0 { dumpPrefix = Just (basename ++ ".") }
+ hsc_env = hsc_env0 {hsc_dflags = dflags}
+
+ (input_basename, suffix) = splitExtension input_fn
+ suffix' = drop 1 suffix -- strip off the .
+ basename | Just b <- mb_basename = b
+ | otherwise = input_basename
+
+ -- If we were given a -x flag, then use that phase to start from
+ start_phase = fromMaybe (startPhase suffix') mb_phase
+
+ isHaskell (Unlit _) = True
+ isHaskell (Cpp _) = True
+ isHaskell (HsPp _) = True
+ isHaskell (Hsc _) = True
+ isHaskell _ = False
+
+ isHaskellishFile = isHaskell start_phase
+
+ env = PipeEnv{ pe_isHaskellishFile = isHaskellishFile,
+ stop_phase,
+ src_basename = basename,
+ src_suffix = suffix',
+ output_spec = output }
+
+ -- We want to catch cases of "you can't get there from here" before
+ -- we start the pipeline, because otherwise it will just run off the
+ -- end.
+ --
+ -- There is a partial ordering on phases, where A < B iff A occurs
+ -- before B in a normal compilation pipeline.
+
+ let happensBefore' = happensBefore dflags
+ when (not (start_phase `happensBefore'` stop_phase)) $
+ throwGhcException (UsageError
+ ("cannot compile this file to desired target: "
+ ++ input_fn))
+
+ debugTraceMsg dflags 4 (text "Running the pipeline")
+ r <- runPipeline' start_phase stop_phase hsc_env env input_fn
+ output maybe_loc maybe_stub_o
+
+ -- If we are compiling a Haskell module, and doing
+ -- -dynamic-too, but couldn't do the -dynamic-too fast
+ -- path, then rerun the pipeline for the dyn way
+ let dflags = extractDynFlags hsc_env
+ when isHaskellishFile $ whenCannotGenerateDynamicToo dflags $ do
+ debugTraceMsg dflags 4
+ (text "Running the pipeline again for -dynamic-too")
let dflags' = doDynamicToo dflags
- hsc_env1 <- newHscEnv dflags'
- _ <- runPipeline' stop_phase hsc_env1 (input_fn, mb_phase)
- mb_basename output maybe_loc maybe_stub_o
+ -- TODO: This should use -dyno
+ output' = case output of
+ SpecificFile fn -> SpecificFile (replaceExtension fn (objectSuf dflags'))
+ Persistent -> Persistent
+ Temporary -> Temporary
+ hsc_env' <- newHscEnv dflags'
+ _ <- runPipeline' start_phase stop_phase hsc_env' env input_fn
+ output' maybe_loc maybe_stub_o
return ()
return r
runPipeline'
- :: Phase -- ^ When to stop
+ :: Phase -- ^ When to start
+ -> Phase -- ^ When to stop
-> HscEnv -- ^ Compilation environment
- -> (FilePath,Maybe Phase) -- ^ Input filename (and maybe -x suffix)
- -> Maybe FilePath -- ^ original basename (if different from ^^^)
+ -> PipeEnv
+ -> FilePath -- ^ Input filename
-> PipelineOutput -- ^ Output filename
-> Maybe ModLocation -- ^ A ModLocation, if this is a Haskell module
-> Maybe FilePath -- ^ stub object, if we have one
- -> IO (DynFlags, FilePath) -- ^ (final flags, output filename)
-runPipeline' stop_phase hsc_env0 (input_fn, mb_phase)
- mb_basename output maybe_loc maybe_stub_o
+ -> IO (DynFlags, FilePath) -- ^ (final flags, output filename)
+runPipeline' start_phase stop_phase hsc_env env input_fn
+ output maybe_loc maybe_stub_o
= do
- let dflags0 = hsc_dflags hsc_env0
- (input_basename, suffix) = splitExtension input_fn
- suffix' = drop 1 suffix -- strip off the .
- basename | Just b <- mb_basename = b
- | otherwise = input_basename
-
- -- Decide where dump files should go based on the pipeline output
- dflags = dflags0 { dumpPrefix = Just (basename ++ ".") }
- hsc_env = hsc_env0 {hsc_dflags = dflags}
-
- -- If we were given a -x flag, then use that phase to start from
- start_phase = fromMaybe (startPhase suffix') mb_phase
-
- -- We want to catch cases of "you can't get there from here" before
- -- we start the pipeline, because otherwise it will just run off the
- -- end.
- --
- -- There is a partial ordering on phases, where A < B iff A occurs
- -- before B in a normal compilation pipeline.
-
- when (not (start_phase `happensBefore` stop_phase)) $
- throwGhcException (UsageError
- ("cannot compile this file to desired target: "
- ++ input_fn))
-
-- this is a function which will be used to calculate output file names
-- as we go along (we partially apply it to some of its inputs here)
- let get_output_fn = getOutputFilename stop_phase output basename
+ let get_output_fn = getOutputFilename stop_phase output (src_basename env)
-- Execute the pipeline...
- let env = PipeEnv{ stop_phase,
- src_basename = basename,
- src_suffix = suffix',
- output_spec = output }
-
- state = PipeState{ hsc_env, maybe_loc, maybe_stub_o = maybe_stub_o }
+ let state = PipeState{ hsc_env, maybe_loc, maybe_stub_o = maybe_stub_o }
(state', output_fn) <- unP (pipeLoop start_phase input_fn) env state
let PipeState{ hsc_env=hsc_env', maybe_loc } = state'
- dflags' = hsc_dflags hsc_env'
+ dflags = hsc_dflags hsc_env'
-- Sometimes, a compilation phase doesn't actually generate any output
-- (eg. the CPP phase when -fcpp is not turned on). If we end on this
@@ -575,20 +601,21 @@ runPipeline' stop_phase hsc_env0 (input_fn, mb_phase)
-- further compilation stages can tell what the original filename was.
case output of
Temporary ->
- return (dflags', output_fn)
- _other ->
- do final_fn <- get_output_fn dflags' stop_phase maybe_loc
+ return (dflags, output_fn)
+ _ ->
+ do final_fn <- get_output_fn dflags stop_phase maybe_loc
when (final_fn /= output_fn) $ do
let msg = ("Copying `" ++ output_fn ++"' to `" ++ final_fn ++ "'")
line_prag = Just ("{-# LINE 1 \"" ++ input_fn ++ "\" #-}\n")
copyWithHeader dflags msg line_prag output_fn final_fn
- return (dflags', final_fn)
+ return (dflags, final_fn)
-- -----------------------------------------------------------------------------
-- The pipeline uses a monad to carry around various bits of information
-- PipeEnv: invariant information passed down
data PipeEnv = PipeEnv {
+ pe_isHaskellishFile :: Bool,
stop_phase :: Phase, -- ^ Stop just before this phase
src_basename :: String, -- ^ basename of original input source
src_suffix :: String, -- ^ its extension
@@ -656,12 +683,13 @@ phaseOutputFilename next_phase = do
pipeLoop :: Phase -> FilePath -> CompPipeline FilePath
pipeLoop phase input_fn = do
PipeEnv{stop_phase} <- getPipeEnv
- PipeState{hsc_env} <- getPipeState
+ dflags <- getDynFlags
+ let happensBefore' = happensBefore dflags
case () of
_ | phase `eqPhase` stop_phase -- All done
-> return input_fn
- | not (phase `happensBefore` stop_phase)
+ | not (phase `happensBefore'` stop_phase)
-- Something has gone wrong. We'll try to cover all the cases when
-- this could happen, so if we reach here it is a panic.
-- eg. it might happen if the -C flag is used on a source file that
@@ -670,9 +698,8 @@ pipeLoop phase input_fn = do
" but I wanted to stop at phase " ++ show stop_phase)
| otherwise
- -> do liftIO $ debugTraceMsg (hsc_dflags hsc_env) 4
+ -> do liftIO $ debugTraceMsg dflags 4
(ptext (sLit "Running phase") <+> ppr phase)
- dflags <- getDynFlags
(next_phase, output_fn) <- runPhase phase input_fn dflags
pipeLoop next_phase output_fn
@@ -1457,6 +1484,12 @@ runPhase MergeStub input_fn dflags
panic "runPhase(MergeStub): no stub"
Just stub_o -> do
liftIO $ joinObjectFiles dflags [input_fn, stub_o] output_fn
+ whenGeneratingDynamicToo dflags $ do
+ liftIO $ debugTraceMsg dflags 4
+ (text "Merging stub again for -dynamic-too")
+ let dyn_input_fn = replaceExtension input_fn (dynObjectSuf dflags)
+ dyn_output_fn = replaceExtension output_fn (dynObjectSuf dflags)
+ liftIO $ joinObjectFiles dflags [dyn_input_fn, stub_o] dyn_output_fn
return (StopLn, output_fn)
-- warning suppression
@@ -1956,12 +1989,20 @@ doCpp dflags raw include_cc_opts input_fn output_fn = do
-- remember, in code we *compile*, the HOST is the same our TARGET,
-- and BUILD is the same as our HOST.
+ let sse2 = isSse2Enabled dflags
+ sse4_2 = isSse4_2Enabled dflags
+ sse_defs =
+ [ "-D__SSE__=1" | sse2 || sse4_2 ] ++
+ [ "-D__SSE2__=1" | sse2 || sse4_2 ] ++
+ [ "-D__SSE4_2__=1" | sse4_2 ]
+
cpp_prog ( map SysTools.Option verbFlags
++ map SysTools.Option include_paths
++ map SysTools.Option hsSourceCppOpts
++ map SysTools.Option target_defs
++ map SysTools.Option hscpp_opts
++ map SysTools.Option cc_opts
+ ++ map SysTools.Option sse_defs
++ [ SysTools.Option "-x"
, SysTools.Option "c"
, SysTools.Option input_fn
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 35386296f0..4edeb23ef4 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -118,6 +118,10 @@ module DynFlags (
tAG_MASK,
mAX_PTR_TAG,
tARGET_MIN_INT, tARGET_MAX_INT, tARGET_MAX_WORD,
+
+ -- * SSE
+ isSse2Enabled,
+ isSse4_2Enabled,
) where
#include "HsVersions.h"
@@ -590,6 +594,7 @@ data DynFlags = DynFlags {
dynHiSuf :: String,
outputFile :: Maybe String,
+ dynOutputFile :: Maybe String,
outputHi :: Maybe String,
dynLibLoader :: DynLibLoader,
@@ -1144,6 +1149,7 @@ doDynamicToo :: DynFlags -> DynFlags
doDynamicToo dflags0 = let dflags1 = unSetGeneralFlag' Opt_Static dflags0
dflags2 = addWay' WayDyn dflags1
dflags3 = dflags2 {
+ outputFile = dynOutputFile dflags2,
hiSuf = dynHiSuf dflags2,
objectSuf = dynObjectSuf dflags2
}
@@ -1222,6 +1228,7 @@ defaultDynFlags mySettings =
pluginModNameOpts = [],
outputFile = Nothing,
+ dynOutputFile = Nothing,
outputHi = Nothing,
dynLibLoader = SystemDependent,
dumpPrefix = Nothing,
@@ -1594,7 +1601,7 @@ setObjectDir, setHiDir, setStubDir, setDumpDir, setOutputDir,
addCmdlineFramework, addHaddockOpts, addGhciScript,
setInteractivePrint
:: String -> DynFlags -> DynFlags
-setOutputFile, setOutputHi, setDumpPrefixForce
+setOutputFile, setDynOutputFile, setOutputHi, setDumpPrefixForce
:: Maybe String -> DynFlags -> DynFlags
setObjectDir f d = d{ objectDir = Just f}
@@ -1614,6 +1621,7 @@ setDynHiSuf f d = d{ dynHiSuf = f}
setHcSuf f d = d{ hcSuf = f}
setOutputFile f d = d{ outputFile = f}
+setDynOutputFile f d = d{ dynOutputFile = f}
setOutputHi f d = d{ outputHi = f}
addPluginModuleName :: String -> DynFlags -> DynFlags
@@ -1796,11 +1804,31 @@ parseDynamicFlagsFull activeFlags cmdline dflags0 args = do
throwGhcException (CmdLineError ("combination not supported: " ++
intercalate "/" (map wayDesc theWays)))
- let (dflags4, consistency_warnings) = makeDynFlagsConsistent dflags3
+ -- TODO: This is an ugly hack. Do something better.
+ -- -fPIC affects the CMM code we generate, so if
+ -- we are in -dynamic-too mode we need -fPIC to be on during the
+ -- shared part of the compilation.
+ let doingDynamicToo = gopt Opt_BuildDynamicToo dflags3
+ platform = targetPlatform dflags3
+ dflags4 = if doingDynamicToo
+ then foldr setGeneralFlag' dflags3
+ (wayGeneralFlags platform WayDyn)
+ else dflags3
+
+ {-
+ TODO: This test doesn't quite work: We don't want to give an error
+ when e.g. compiling a C file, only when compiling Haskell files.
+ when doingDynamicToo $
+ unless (isJust (outputFile dflags4) == isJust (dynOutputFile dflags4)) $
+ throwGhcException $ CmdLineError
+ "With -dynamic-too, must give -dyno iff giving -o"
+ -}
+
+ let (dflags5, consistency_warnings) = makeDynFlagsConsistent dflags4
- liftIO $ setUnsafeGlobalDynFlags dflags4
+ liftIO $ setUnsafeGlobalDynFlags dflags5
- return (dflags4, leftover, consistency_warnings ++ sh_warns ++ warns)
+ return (dflags5, leftover, consistency_warnings ++ sh_warns ++ warns)
updateWays :: DynFlags -> DynFlags
updateWays dflags
@@ -1992,6 +2020,7 @@ dynamic_flags = [
------- Output Redirection ------------------------------------------
, Flag "odir" (hasArg setObjectDir)
, Flag "o" (sepArg (setOutputFile . Just))
+ , Flag "dyno" (sepArg (setDynOutputFile . Just))
, Flag "ohi" (hasArg (setOutputHi . Just ))
, Flag "osuf" (hasArg setObjectSuf)
, Flag "dynosuf" (hasArg setDynObjectSuf)
@@ -2153,6 +2182,11 @@ dynamic_flags = [
, Flag "monly-4-regs" (NoArg (addWarn "The -monly-4-regs flag does nothing; it will be removed in a future GHC release"))
, Flag "msse2" (NoArg (setGeneralFlag Opt_SSE2))
, Flag "msse4.2" (NoArg (setGeneralFlag Opt_SSE4_2))
+ -- at some point we should probably have a single SSE flag that
+ -- contains the SSE version, instead of having a different flag
+ -- per version. That would make it easier to e.g. check if SSE2 is
+ -- enabled as you wouldn't have to check if either Opt_SSE2 or
+ -- Opt_SSE4_2 is set (as the latter implies the former).
------ Warning opts -------------------------------------------------
, Flag "W" (NoArg (mapM_ setWarningFlag minusWOpts))
@@ -3371,3 +3405,21 @@ makeDynFlagsConsistent dflags
arch = platformArch platform
os = platformOS platform
+-- -----------------------------------------------------------------------------
+-- SSE
+
+isSse2Enabled :: DynFlags -> Bool
+isSse2Enabled dflags = isSse4_2Enabled dflags || isSse2Enabled'
+ where
+ isSse2Enabled' = case platformArch (targetPlatform dflags) of
+ ArchX86_64 -> -- SSE2 is fixed on for x86_64. It would be
+ -- possible to make it optional, but we'd need to
+ -- fix at least the foreign call code where the
+ -- calling convention specifies the use of xmm regs,
+ -- and possibly other places.
+ True
+ ArchX86 -> gopt Opt_SSE2 dflags
+ _ -> False
+
+isSse4_2Enabled :: DynFlags -> Bool
+isSse4_2Enabled dflags = gopt Opt_SSE4_2 dflags
diff --git a/compiler/main/GhcMake.hs b/compiler/main/GhcMake.hs
index 34898a92a3..80227cd3f3 100644
--- a/compiler/main/GhcMake.hs
+++ b/compiler/main/GhcMake.hs
@@ -709,9 +709,9 @@ upsweep_mod hsc_env old_hpt (stable_obj, stable_bco) summary mod_index nmods
prevailing_target = hscTarget (hsc_dflags hsc_env)
local_target = hscTarget dflags
- -- If OPTIONS_GHC contains -fasm or -fvia-C, be careful that
+ -- If OPTIONS_GHC contains -fasm or -fllvm, be careful that
-- we don't do anything dodgy: these should only work to change
- -- from -fvia-C to -fasm and vice-versa, otherwise we could
+ -- from -fllvm to -fasm and vice-versa, otherwise we could
-- end up trying to link object code to byte code.
target = if prevailing_target /= local_target
&& (not (isObjectTarget prevailing_target)
diff --git a/compiler/main/HscMain.hs b/compiler/main/HscMain.hs
index 2a838168dd..3562f27d5c 100644
--- a/compiler/main/HscMain.hs
+++ b/compiler/main/HscMain.hs
@@ -1250,8 +1250,9 @@ hscWriteIface iface no_change mod_summary = do
-- TODO: We should do a no_change check for the dynamic
-- interface file too
let dynIfaceFile = replaceExtension ifaceFile (dynHiSuf dflags)
+ dynIfaceFile' = addBootSuffix_maybe (mi_boot iface) dynIfaceFile
dynDflags = doDynamicToo dflags
- writeIfaceFile dynDflags dynIfaceFile iface
+ writeIfaceFile dynDflags dynIfaceFile' iface
-- | Compile to hard-code.
hscGenHardCode :: CgGuts -> ModSummary
diff --git a/compiler/nativeGen/SPARC/Base.hs b/compiler/nativeGen/SPARC/Base.hs
index aa7b057e69..96fb5e7797 100644
--- a/compiler/nativeGen/SPARC/Base.hs
+++ b/compiler/nativeGen/SPARC/Base.hs
@@ -1,26 +1,19 @@
-- | Bits and pieces on the bottom of the module dependency tree.
--- Also import the required constants, so we know what we're using.
---
--- In the interests of cross-compilation, we want to free ourselves
--- from the autoconf generated modules like main/Constants
+-- Also import the required constants, so we know what we're using.
--
-{-# OPTIONS -fno-warn-tabs #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and
--- detab the module (please do the detabbing in a separate patch). See
--- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
--- for details
+-- In the interests of cross-compilation, we want to free ourselves
+-- from the autoconf generated modules like main/Constants
module SPARC.Base (
- wordLength,
- wordLengthInBits,
- spillAreaLength,
- spillSlotSize,
- extraStackArgsHere,
- fits13Bits,
- is32BitInteger,
- largeOffsetError
+ wordLength,
+ wordLengthInBits,
+ spillAreaLength,
+ spillSlotSize,
+ extraStackArgsHere,
+ fits13Bits,
+ is32BitInteger,
+ largeOffsetError
)
where
@@ -36,13 +29,13 @@ wordLength :: Int
wordLength = 4
wordLengthInBits :: Int
-wordLengthInBits
- = wordLength * 8
+wordLengthInBits
+ = wordLength * 8
-- Size of the available spill area
spillAreaLength :: DynFlags -> Int
spillAreaLength
- = rESERVED_C_STACK_BYTES
+ = rESERVED_C_STACK_BYTES
-- | We need 8 bytes because our largest registers are 64 bit.
spillSlotSize :: Int
@@ -50,7 +43,7 @@ spillSlotSize = 8
-- | We (allegedly) put the first six C-call arguments in registers;
--- where do we start putting the rest of them?
+-- where do we start putting the rest of them?
extraStackArgsHere :: Int
extraStackArgsHere = 23
@@ -61,22 +54,22 @@ fits13Bits :: Integral a => a -> Bool
fits13Bits x = x >= -4096 && x < 4096
-- | Check whether an integer will fit in 32 bits.
--- A CmmInt is intended to be truncated to the appropriate
--- number of bits, so here we truncate it to Int64. This is
--- important because e.g. -1 as a CmmInt might be either
--- -1 or 18446744073709551615.
+-- A CmmInt is intended to be truncated to the appropriate
+-- number of bits, so here we truncate it to Int64. This is
+-- important because e.g. -1 as a CmmInt might be either
+-- -1 or 18446744073709551615.
--
is32BitInteger :: Integer -> Bool
-is32BitInteger i
- = i64 <= 0x7fffffff && i64 >= -0x80000000
- where i64 = fromIntegral i :: Int64
+is32BitInteger i
+ = i64 <= 0x7fffffff && i64 >= -0x80000000
+ where i64 = fromIntegral i :: Int64
-- | Sadness.
largeOffsetError :: (Integral a, Show a) => a -> b
largeOffsetError i
= panic ("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")
+ ++ show i ++ ");\nprobably because of large constant data structures;" ++
+ "\nworkaround: use -fllvm on this module.\n")
diff --git a/compiler/nativeGen/X86/CodeGen.hs b/compiler/nativeGen/X86/CodeGen.hs
index 30cf060e74..d01470926b 100644
--- a/compiler/nativeGen/X86/CodeGen.hs
+++ b/compiler/nativeGen/X86/CodeGen.hs
@@ -71,20 +71,12 @@ is32BitPlatform = do
sse2Enabled :: NatM Bool
sse2Enabled = do
dflags <- getDynFlags
- case platformArch (targetPlatform dflags) of
- ArchX86_64 -> -- SSE2 is fixed on for x86_64. It would be
- -- possible to make it optional, but we'd need to
- -- fix at least the foreign call code where the
- -- calling convention specifies the use of xmm regs,
- -- and possibly other places.
- return True
- ArchX86 -> return (gopt Opt_SSE2 dflags || gopt Opt_SSE4_2 dflags)
- _ -> panic "sse2Enabled: Not an X86* arch"
+ return (isSse2Enabled dflags)
sse4_2Enabled :: NatM Bool
sse4_2Enabled = do
dflags <- getDynFlags
- return (gopt Opt_SSE4_2 dflags)
+ return (isSse4_2Enabled dflags)
if_sse2 :: NatM a -> NatM a -> NatM a
if_sse2 sse2 x87 = do
diff --git a/compiler/prelude/PrelRules.lhs b/compiler/prelude/PrelRules.lhs
index b58eb0a47e..b21d546ef7 100644
--- a/compiler/prelude/PrelRules.lhs
+++ b/compiler/prelude/PrelRules.lhs
@@ -142,28 +142,28 @@ primOpRules nm Int2WordOp = mkPrimOpRule nm 1 [ liftLitDynFlags int2WordLit
, inversePrimOp Word2IntOp ]
primOpRules nm Narrow8IntOp = mkPrimOpRule nm 1 [ liftLit narrow8IntLit
, subsumedByPrimOp Narrow8IntOp
- , subsumedByPrimOp Narrow16IntOp
- , subsumedByPrimOp Narrow32IntOp ]
+ , Narrow8IntOp `subsumesPrimOp` Narrow16IntOp
+ , Narrow8IntOp `subsumesPrimOp` Narrow32IntOp ]
primOpRules nm Narrow16IntOp = mkPrimOpRule nm 1 [ liftLit narrow16IntLit
- , Narrow16IntOp `subsumesPrimOp` Narrow8IntOp
+ , subsumedByPrimOp Narrow8IntOp
, subsumedByPrimOp Narrow16IntOp
- , subsumedByPrimOp Narrow32IntOp ]
+ , Narrow16IntOp `subsumesPrimOp` Narrow32IntOp ]
primOpRules nm Narrow32IntOp = mkPrimOpRule nm 1 [ liftLit narrow32IntLit
- , Narrow32IntOp `subsumesPrimOp` Narrow8IntOp
- , Narrow32IntOp `subsumesPrimOp` Narrow16IntOp
+ , subsumedByPrimOp Narrow8IntOp
+ , subsumedByPrimOp Narrow16IntOp
, subsumedByPrimOp Narrow32IntOp
, removeOp32 ]
primOpRules nm Narrow8WordOp = mkPrimOpRule nm 1 [ liftLit narrow8WordLit
, subsumedByPrimOp Narrow8WordOp
- , subsumedByPrimOp Narrow16WordOp
- , subsumedByPrimOp Narrow32WordOp ]
+ , Narrow8WordOp `subsumesPrimOp` Narrow16WordOp
+ , Narrow8WordOp `subsumesPrimOp` Narrow32WordOp ]
primOpRules nm Narrow16WordOp = mkPrimOpRule nm 1 [ liftLit narrow16WordLit
- , Narrow16WordOp `subsumesPrimOp` Narrow8WordOp
+ , subsumedByPrimOp Narrow8WordOp
, subsumedByPrimOp Narrow16WordOp
- , subsumedByPrimOp Narrow32WordOp ]
+ , Narrow16WordOp `subsumesPrimOp` Narrow32WordOp ]
primOpRules nm Narrow32WordOp = mkPrimOpRule nm 1 [ liftLit narrow32WordLit
- , Narrow32WordOp `subsumesPrimOp` Narrow8WordOp
- , Narrow32WordOp `subsumesPrimOp` Narrow16WordOp
+ , subsumedByPrimOp Narrow8WordOp
+ , subsumedByPrimOp Narrow16WordOp
, subsumedByPrimOp Narrow32WordOp
, removeOp32 ]
primOpRules nm OrdOp = mkPrimOpRule nm 1 [ liftLit char2IntLit
diff --git a/compiler/typecheck/TcForeign.lhs b/compiler/typecheck/TcForeign.lhs
index 4ac5f48dd6..b1aef2fd77 100644
--- a/compiler/typecheck/TcForeign.lhs
+++ b/compiler/typecheck/TcForeign.lhs
@@ -255,7 +255,7 @@ tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport cconv safety mh (CFunction ta
dflags <- getDynFlags
check (xopt Opt_GHCForeignImportPrim dflags)
(text "Use -XGHCForeignImportPrim to allow `foreign import prim'.")
- checkCg (checkCOrAsmOrLlvmOrDotNetOrInterp)
+ checkCg checkCOrAsmOrLlvmOrInterp
checkCTarget target
check (playSafe safety)
(text "The safe/unsafe annotation should not be used with `foreign import prim'.")
@@ -264,7 +264,7 @@ tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport cconv safety mh (CFunction ta
checkForeignRes nonIOok checkSafe (isFFIPrimResultTy dflags) res_ty
return idecl
| otherwise = do -- Normal foreign import
- checkCg checkCOrAsmOrLlvmOrDotNetOrInterp
+ checkCg checkCOrAsmOrLlvmOrInterp
cconv' <- checkCConv cconv
checkCTarget target
dflags <- getDynFlags
@@ -283,7 +283,7 @@ tcCheckFIType sig_ty arg_tys res_ty idecl@(CImport cconv safety mh (CFunction ta
-- that the C identifier is valid for C
checkCTarget :: CCallTarget -> TcM ()
checkCTarget (StaticTarget str _ _) = do
- checkCg checkCOrAsmOrLlvmOrDotNetOrInterp
+ checkCg checkCOrAsmOrLlvmOrInterp
check (isCLabelString str) (badCName str)
checkCTarget DynamicTarget = panic "checkCTarget DynamicTarget"
@@ -427,7 +427,7 @@ checkCOrAsmOrLlvm HscC = Nothing
checkCOrAsmOrLlvm HscAsm = Nothing
checkCOrAsmOrLlvm HscLlvm = Nothing
checkCOrAsmOrLlvm _
- = Just (text "requires via-C, llvm (-fllvm) or native code generation (-fvia-C)")
+ = Just (text "requires unregisterised, llvm (-fllvm) or native code generation (-fasm)")
checkCOrAsmOrLlvmOrInterp :: HscTarget -> Maybe SDoc
checkCOrAsmOrLlvmOrInterp HscC = Nothing
@@ -435,15 +435,7 @@ checkCOrAsmOrLlvmOrInterp HscAsm = Nothing
checkCOrAsmOrLlvmOrInterp HscLlvm = Nothing
checkCOrAsmOrLlvmOrInterp HscInterpreted = Nothing
checkCOrAsmOrLlvmOrInterp _
- = Just (text "requires interpreted, C, Llvm or native code generation")
-
-checkCOrAsmOrLlvmOrDotNetOrInterp :: HscTarget -> Maybe SDoc
-checkCOrAsmOrLlvmOrDotNetOrInterp HscC = Nothing
-checkCOrAsmOrLlvmOrDotNetOrInterp HscAsm = Nothing
-checkCOrAsmOrLlvmOrDotNetOrInterp HscLlvm = Nothing
-checkCOrAsmOrLlvmOrDotNetOrInterp HscInterpreted = Nothing
-checkCOrAsmOrLlvmOrDotNetOrInterp _
- = Just (text "requires interpreted, C, Llvm or native code generation")
+ = Just (text "requires interpreted, unregisterised, llvm or native code generation")
checkCg :: (HscTarget -> Maybe SDoc) -> TcM ()
checkCg check = do
diff --git a/compiler/typecheck/TcValidity.lhs b/compiler/typecheck/TcValidity.lhs
index 80e7aa0415..44d7d4c6db 100644
--- a/compiler/typecheck/TcValidity.lhs
+++ b/compiler/typecheck/TcValidity.lhs
@@ -827,7 +827,9 @@ checkValidInstance ctxt hs_type ty
-- in the constraint than in the head
; undecidable_ok <- xoptM Opt_UndecidableInstances
; if undecidable_ok
- then checkAmbiguity ctxt ty
+ then do checkAmbiguity ctxt ty
+ checkTc (checkInstLiberalCoverage clas theta inst_tys)
+ (instTypeErr clas inst_tys liberal_msg)
else do { checkInstTermination inst_tys theta
; checkTc (checkInstCoverage clas inst_tys)
(instTypeErr clas inst_tys msg) }
@@ -837,6 +839,10 @@ checkValidInstance ctxt hs_type ty
msg = parens (vcat [ptext (sLit "the Coverage Condition fails for one of the functional dependencies;"),
undecidableMsg])
+ liberal_msg = vcat
+ [ ptext $ sLit "Multiple uses of this instance may be inconsistent"
+ , ptext $ sLit "with the functional dependencies of the class."
+ ]
-- The location of the "head" of the instance
head_loc = case hs_type of
L _ (HsForAllTy _ _ _ (L loc _)) -> loc
diff --git a/compiler/types/FunDeps.lhs b/compiler/types/FunDeps.lhs
index 09d0be07bb..fe8781b1f8 100644
--- a/compiler/types/FunDeps.lhs
+++ b/compiler/types/FunDeps.lhs
@@ -19,7 +19,7 @@ module FunDeps (
FDEq (..),
Equation(..), pprEquation,
oclose, improveFromInstEnv, improveFromAnother,
- checkInstCoverage, checkFunDeps,
+ checkInstCoverage, checkInstLiberalCoverage, checkFunDeps,
pprFundeps
) where
@@ -145,6 +145,53 @@ oclose preds fixed_tvs
ClassPred cls tys -> [(cls, tys)]
TuplePred ts -> concatMap classesOfPredTy ts
_ -> []
+
+-- An alternative implementation of `oclose`. Differences:
+-- 1. The empty set of variables is allowed to determine stuff,
+-- 2. We also use equality predicates as FDs.
+--
+-- I (Iavor) believe that this is the correct implementation of oclose.
+-- For 1: the above argument about `t` being monomorphic seems incorrect.
+-- The correct behavior is to quantify over `t`, even though we know that
+-- it may be instantiated to at most one type. The point is that we might
+-- only find out what that type is later, at the call site to the function.
+-- In general, we should be quantifying all variables that are (i) not in
+-- mentioned in the environment, and (ii) not FD-determined by something in
+-- the environment.
+-- For 2: This is just a nicity, but it makes things a bit more general:
+-- if we have an assumption `t1 ~ t2`, then we use the fact that if we know
+-- `t1` we also know `t2` and the other way.
+
+oclose1 :: [PredType] -> TyVarSet -> TyVarSet
+oclose1 preds fixed_tvs
+ | null tv_fds = fixed_tvs -- Fast escape hatch for common case.
+ | otherwise = loop fixed_tvs
+ where
+ loop fixed_tvs
+ | new_fixed_tvs `subVarSet` fixed_tvs = fixed_tvs
+ | otherwise = loop new_fixed_tvs
+ where new_fixed_tvs = foldl extend fixed_tvs tv_fds
+
+ extend fixed_tvs (ls,rs)
+ | ls `subVarSet` fixed_tvs = fixed_tvs `unionVarSet` rs
+ | otherwise = fixed_tvs
+
+ tv_fds :: [(TyVarSet,TyVarSet)]
+ tv_fds = [ (tyVarsOfTypes xs, tyVarsOfTypes ys)
+ | (xs, ys) <- concatMap deterimned preds
+ ]
+
+ deterimned :: PredType -> [([Type],[Type])]
+ deterimned pred
+ = case classifyPredType pred of
+ ClassPred cls tys ->
+ do let (cls_tvs, cls_fds) = classTvsFds cls
+ fd <- cls_fds
+ return (instFD fd cls_tvs tys)
+ EqPred t1 t2 -> [([t1],[t2]), ([t2],[t1])]
+ TuplePred ts -> concatMap deterimned ts
+ _ -> []
+
\end{code}
@@ -471,6 +518,23 @@ checkInstCoverage clas inst_taus
fundep_ok fd = tyVarsOfTypes rs `subVarSet` tyVarsOfTypes ls
where
(ls,rs) = instFD fd tyvars inst_taus
+
+checkInstLiberalCoverage :: Class -> [PredType] -> [Type] -> Bool
+-- Check that the Liberal Coverage Condition is obeyed in an instance decl
+-- For example, if we have:
+-- class C a b | a -> b
+-- instance theta => C t1 t2
+-- Then we require fv(t2) `subset` oclose(fv(t1), theta)
+-- This ensures the self-consistency of the instance, but
+-- it does not guarantee termination.
+-- See Note [Coverage Condition] below
+
+checkInstLiberalCoverage clas theta inst_taus
+ = all fundep_ok fds
+ where
+ (tyvars, fds) = classTvsFds clas
+ fundep_ok fd = tyVarsOfTypes rs `subVarSet` oclose1 theta (tyVarsOfTypes ls)
+ where (ls,rs) = instFD fd tyvars inst_taus
\end{code}
Note [Coverage condition]