summaryrefslogtreecommitdiff
path: root/compiler/llvmGen
diff options
context:
space:
mode:
authorErik de Castro Lopo <erikd@mega-nerd.com>2016-03-12 12:03:56 +0100
committerBen Gamari <ben@smart-cactus.org>2016-03-12 12:03:56 +0100
commit92821ec9a57817e1429ae94c756539259488b728 (patch)
treea8bd8a2dfbbee57b83bc5f832896d7851237e4ea /compiler/llvmGen
parent41051dd846c3a7fc01cbb8ad3b7dd2b4332f7f0b (diff)
downloadhaskell-92821ec9a57817e1429ae94c756539259488b728.tar.gz
LlvmCodeGen: Fix generation of malformed LLVM blocks
Commit 673efccb3b uncovered a bug in LLVM code generation that produced LLVM code that the LLVM compiler refused to compile: { clpH: br label %clpH } This may well be a bug in LLVM itself. The solution is to keep the existing entry label and rewrite the function as: { clpH: br label %nPV nPV: br label %nPV } Thanks to Ben Gamari for pointing me in the right direction on this one. Test Plan: Build GHC with BuildFlavour=quick-llvm Reviewers: hvr, austin, bgamari Reviewed By: bgamari Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1996 GHC Trac Issues: #11649
Diffstat (limited to 'compiler/llvmGen')
-rw-r--r--compiler/llvmGen/LlvmCodeGen.hs34
1 files changed, 33 insertions, 1 deletions
diff --git a/compiler/llvmGen/LlvmCodeGen.hs b/compiler/llvmGen/LlvmCodeGen.hs
index 3c63aa06d0..872ad8ce78 100644
--- a/compiler/llvmGen/LlvmCodeGen.hs
+++ b/compiler/llvmGen/LlvmCodeGen.hs
@@ -15,8 +15,10 @@ import LlvmCodeGen.Ppr
import LlvmCodeGen.Regs
import LlvmMangler
+import BlockId
import CgUtils ( fixStgRegisters )
import Cmm
+import CmmUtils
import Hoopl
import PprCmm
@@ -120,13 +122,43 @@ cmmDataLlvmGens statics
renderLlvm $ pprLlvmData (concat gss', concat tss)
+-- | LLVM can't handle entry blocks which loop back to themselves (could be
+-- seen as an LLVM bug) so we rearrange the code to keep the original entry
+-- label which branches to a newly generated second label that branches back
+-- to itself. See: Trac #11649
+fixBottom :: RawCmmDecl -> LlvmM RawCmmDecl
+fixBottom cp@(CmmProc hdr entry_lbl live g) =
+ maybe (pure cp) fix_block $ mapLookup (g_entry g) blk_map
+ where
+ blk_map = toBlockMap g
+
+ fix_block :: CmmBlock -> LlvmM RawCmmDecl
+ fix_block blk
+ | (CmmEntry e_lbl tickscp, middle, CmmBranch b_lbl) <- blockSplit blk
+ , isEmptyBlock middle
+ , e_lbl == b_lbl = do
+ new_lbl <- mkBlockId <$> getUniqueM
+
+ let fst_blk =
+ BlockCC (CmmEntry e_lbl tickscp) BNil (CmmBranch new_lbl)
+ snd_blk =
+ BlockCC (CmmEntry new_lbl tickscp) BNil (CmmBranch new_lbl)
+
+ pure . CmmProc hdr entry_lbl live . ofBlockMap (g_entry g)
+ $ mapFromList [(e_lbl, fst_blk), (new_lbl, snd_blk)]
+
+ fix_block _ = pure cp
+
+fixBottom rcd = pure rcd
+
-- | Complete LLVM code generation phase for a single top-level chunk of Cmm.
cmmLlvmGen ::RawCmmDecl -> LlvmM ()
cmmLlvmGen cmm@CmmProc{} = do
-- rewrite assignments to global regs
dflags <- getDynFlag id
- let fixed_cmm = {-# SCC "llvm_fix_regs" #-}
+ fixed_cmm <- fixBottom $
+ {-# SCC "llvm_fix_regs" #-}
fixStgRegisters dflags cmm
dumpIfSetLlvm Opt_D_dump_opt_cmm "Optimised Cmm" (pprCmmGroup [fixed_cmm])