From e4c8d2b11b4be71885532cb14434511b6c47866c Mon Sep 17 00:00:00 2001 From: "wolfgang.thaller@gmx.net" Date: Wed, 13 Dec 2006 13:38:08 +0000 Subject: [PATCH] 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 --- compiler/nativeGen/AsmCodeGen.lhs | 42 +++++++++++++++++++++++++++++++++++- compiler/nativeGen/MachInstrs.hs | 19 +++++++++++++++- compiler/nativeGen/PprMach.hs | 13 +++++++++++ compiler/nativeGen/RegAllocInfo.hs | 4 ++++ 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/compiler/nativeGen/AsmCodeGen.lhs b/compiler/nativeGen/AsmCodeGen.lhs index 85fb437..109054f 100644 --- a/compiler/nativeGen/AsmCodeGen.lhs +++ b/compiler/nativeGen/AsmCodeGen.lhs @@ -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 diff --git a/compiler/nativeGen/MachInstrs.hs b/compiler/nativeGen/MachInstrs.hs index 9c0e71c..a9b04db 100644 --- a/compiler/nativeGen/MachInstrs.hs +++ b/compiler/nativeGen/MachInstrs.hs @@ -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 diff --git a/compiler/nativeGen/PprMach.hs b/compiler/nativeGen/PprMach.hs index 6965bbf..5016726 100644 --- a/compiler/nativeGen/PprMach.hs +++ b/compiler/nativeGen/PprMach.hs @@ -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"), diff --git a/compiler/nativeGen/RegAllocInfo.hs b/compiler/nativeGen/RegAllocInfo.hs index d526641..2c3ab6b 100644 --- a/compiler/nativeGen/RegAllocInfo.hs +++ b/compiler/nativeGen/RegAllocInfo.hs @@ -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 -- 1.7.10.4