Commit e4c8d2b1 authored by wolfgang.thaller@gmx.net's avatar wolfgang.thaller@gmx.net
Browse files

PowerPC NCG: support conditional branches outside +-32KB

Work around the PowerPC architecture's +-32KB limitation for conditional
branches by conditionally skipping an unconditional branch instead
(unconditional branches have a +-32MB range).

This requires an extra pass over the basic blocks for each CmmTop after
block sequencing, to determine which branches are "far".

Fixes ticket #709, "Fixup too large" error with -fasm on PowerPC
parent 4307b489
......@@ -245,7 +245,7 @@ cmmNativeGen dflags cmm
sequenceTop :: NatCmmTop -> NatCmmTop
sequenceTop top@(CmmData _ _) = top
sequenceTop (CmmProc info lbl params blocks) =
CmmProc info lbl params (sequenceBlocks blocks)
CmmProc info lbl params (makeFarBranches $ sequenceBlocks blocks)
-- The algorithm is very simple (and stupid): we make a graph out of
-- the blocks where there is an edge from one block to another iff the
......@@ -289,6 +289,46 @@ reorder id accum (b@(block,id',out) : rest)
| id == id' = (True, (block,id,out) : reverse accum ++ rest)
| otherwise = reorder id (b:accum) rest
-- -----------------------------------------------------------------------------
-- Making far branches
-- Conditional branches on PowerPC are limited to +-32KB; if our Procs get too
-- big, we have to work around this limitation.
makeFarBranches :: [NatBasicBlock] -> [NatBasicBlock]
#if powerpc_TARGET_ARCH
makeFarBranches blocks
| last blockAddresses < nearLimit = blocks
| otherwise = zipWith handleBlock blockAddresses blocks
where
blockAddresses = scanl (+) 0 $ map blockLen blocks
blockLen (BasicBlock _ instrs) = length instrs
handleBlock addr (BasicBlock id instrs)
= BasicBlock id (zipWith makeFar [addr..] instrs)
makeFar addr (BCC ALWAYS tgt) = BCC ALWAYS tgt
makeFar addr (BCC cond tgt)
| abs (addr - targetAddr) >= nearLimit
= BCCFAR cond tgt
| otherwise
= BCC cond tgt
where Just targetAddr = lookupUFM blockAddressMap tgt
makeFar addr other = other
nearLimit = 7000 -- 8192 instructions are allowed; let's keep some
-- distance, as we have a few pseudo-insns that are
-- pretty-printed as multiple instructions,
-- and it's just not worth the effort to calculate
-- things exactly
blockAddressMap = listToUFM $ zip (map blockId blocks) blockAddresses
#else
makeFarBranches = id
#endif
-- -----------------------------------------------------------------------------
-- Instruction selection
......
......@@ -15,7 +15,9 @@ module MachInstrs (
-- * Machine instructions
Instr(..),
Cond(..), condUnsigned, condToSigned, condToUnsigned,
#if powerpc_TARGET_ARCH
condNegate,
#endif
#if !powerpc_TARGET_ARCH && !i386_TARGET_ARCH && !x86_64_TARGET_ARCH
Size(..), machRepSize,
#endif
......@@ -140,6 +142,20 @@ condToUnsigned GE = GEU
condToUnsigned LE = LEU
condToUnsigned x = x
#if powerpc_TARGET_ARCH
condNegate ALWAYS = panic "condNegate: ALWAYS"
condNegate EQQ = NE
condNegate GE = LTT
condNegate GEU = LU
condNegate GTT = LE
condNegate GU = LEU
condNegate LE = GTT
condNegate LEU = GU
condNegate LTT = GE
condNegate LU = GEU
condNegate NE = EQQ
#endif
-- -----------------------------------------------------------------------------
-- Sizes on this architecture
......@@ -660,6 +676,7 @@ fPair other = pprPanic "fPair(sparc NCG)" (ppr other)
| CMPL MachRep Reg RI --- size, src1, src2
| BCC Cond BlockId
| BCCFAR Cond BlockId
| JMP CLabel -- same as branch,
-- but with CLabel instead of block ID
| MTCTR Reg
......
......@@ -2162,6 +2162,19 @@ pprInstr (BCC cond (BlockId id)) = hcat [
]
where lbl = mkAsmTempLabel id
pprInstr (BCCFAR cond (BlockId id)) = vcat [
hcat [
ptext SLIT("\tb"),
pprCond (condNegate cond),
ptext SLIT("\t$+8")
],
hcat [
ptext SLIT("\tb\t"),
pprCLabel_asm lbl
]
]
where lbl = mkAsmTempLabel id
pprInstr (JMP lbl) = hcat [ -- an alias for b that takes a CLabel
char '\t',
ptext SLIT("b"),
......
......@@ -333,6 +333,7 @@ regUsage instr = case instr of
CMP sz reg ri -> usage (reg : regRI ri,[])
CMPL sz reg ri -> usage (reg : regRI ri,[])
BCC cond lbl -> noUsage
BCCFAR cond lbl -> noUsage
MTCTR reg -> usage ([reg],[])
BCTR targets -> noUsage
BL imm params -> usage (params, callClobberedRegs)
......@@ -397,6 +398,7 @@ jumpDests insn acc
JMP_TBL _ ids -> ids ++ acc
#elif powerpc_TARGET_ARCH
BCC _ id -> id : acc
BCCFAR _ id -> id : acc
BCTR targets -> targets ++ acc
#endif
_other -> acc
......@@ -410,6 +412,7 @@ patchJump insn old new
JMP_TBL op ids -> error "Cannot patch JMP_TBL"
#elif powerpc_TARGET_ARCH
BCC cc id | id == old -> BCC cc new
BCCFAR cc id | id == old -> BCCFAR cc new
BCTR targets -> error "Cannot patch BCTR"
#endif
_other -> insn
......@@ -640,6 +643,7 @@ patchRegs instr env = case instr of
CMP sz reg ri -> CMP sz (env reg) (fixRI ri)
CMPL sz reg ri -> CMPL sz (env reg) (fixRI ri)
BCC cond lbl -> BCC cond lbl
BCCFAR cond lbl -> BCCFAR cond lbl
MTCTR reg -> MTCTR (env reg)
BCTR targets -> BCTR targets
BL imm argRegs -> BL imm argRegs -- argument regs
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment