diff options
author | Erik de Castro Lopo <erikd@mega-nerd.com> | 2016-03-12 12:03:56 +0100 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2016-03-12 12:03:56 +0100 |
commit | 92821ec9a57817e1429ae94c756539259488b728 (patch) | |
tree | a8bd8a2dfbbee57b83bc5f832896d7851237e4ea /compiler/llvmGen | |
parent | 41051dd846c3a7fc01cbb8ad3b7dd2b4332f7f0b (diff) | |
download | haskell-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.hs | 34 |
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]) |