PowerPC NCG: support conditional branches outside +-32KB
authorwolfgang.thaller@gmx.net <unknown>
Wed, 13 Dec 2006 13:38:08 +0000 (13:38 +0000)
committerwolfgang.thaller@gmx.net <unknown>
Wed, 13 Dec 2006 13:38:08 +0000 (13:38 +0000)
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
compiler/nativeGen/MachInstrs.hs
compiler/nativeGen/PprMach.hs
compiler/nativeGen/RegAllocInfo.hs

index 85fb437..109054f 100644 (file)
@@ -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
 
index 9c0e71c..a9b04db 100644 (file)
@@ -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
index 6965bbf..5016726 100644 (file)
@@ -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"),
index d526641..2c3ab6b 100644 (file)
@@ -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