Add MO_AddIntC, MO_SubIntC MachOps and implement in X86 backend
authorReid Barton <rwbarton@gmail.com>
Fri, 22 Aug 2014 22:57:50 +0000 (18:57 -0400)
committerReid Barton <rwbarton@gmail.com>
Sat, 23 Aug 2014 18:55:57 +0000 (14:55 -0400)
Summary:
These MachOps are used by addIntC# and subIntC#, which in turn are
used in integer-gmp when adding or subtracting small Integers. The
following benchmark shows a ~6% speedup after this commit on x86_64
(building GHC with BuildFlavour=perf).

    {-# LANGUAGE MagicHash #-}

    import GHC.Exts
    import Criterion.Main

    count :: Int -> Integer
    count (I# n#) = go n# 0
      where go :: Int# -> Integer -> Integer
            go 0# acc = acc
            go n# acc = go (n# -# 1#) $! acc + 1

    main = defaultMain [bgroup "count"
                          [bench "100" $ whnf count 100]]

Differential Revision: https://phabricator.haskell.org/D140

compiler/cmm/CmmMachOp.hs
compiler/cmm/PprC.hs
compiler/codeGen/StgCmmPrim.hs
compiler/llvmGen/LlvmCodeGen/CodeGen.hs
compiler/nativeGen/PPC/CodeGen.hs
compiler/nativeGen/SPARC/CodeGen.hs
compiler/nativeGen/X86/CodeGen.hs
compiler/nativeGen/X86/Instr.hs
compiler/nativeGen/X86/Ppr.hs

index a7b2c85..b84cb40 100644 (file)
@@ -526,6 +526,8 @@ data CallishMachOp
   | MO_U_QuotRem Width
   | MO_U_QuotRem2 Width
   | MO_Add2      Width
+  | MO_AddIntC   Width
+  | MO_SubIntC   Width
   | MO_U_Mul2    Width
 
   | MO_WriteBarrier
index 93a5d06..3b824f3 100644 (file)
@@ -765,6 +765,8 @@ pprCallishMachOp_for_C mop
         MO_U_QuotRem  {} -> unsupported
         MO_U_QuotRem2 {} -> unsupported
         MO_Add2       {} -> unsupported
+        MO_AddIntC    {} -> unsupported
+        MO_SubIntC    {} -> unsupported
         MO_U_Mul2     {} -> unsupported
         MO_Touch         -> unsupported
         (MO_Prefetch_Data _ ) -> unsupported
index 9e12427..e6f4e48 100644 (file)
@@ -806,9 +806,11 @@ callishPrimOpSupported dflags op
       WordAdd2Op     | ncg && x86ish  -> Left (MO_Add2       (wordWidth dflags))
                      | otherwise      -> Right genericWordAdd2Op
 
-      IntAddCOp                       -> Right genericIntAddCOp
+      IntAddCOp      | ncg && x86ish  -> Left (MO_AddIntC    (wordWidth dflags))
+                     | otherwise      -> Right genericIntAddCOp
 
-      IntSubCOp                       -> Right genericIntSubCOp
+      IntSubCOp      | ncg && x86ish  -> Left (MO_SubIntC    (wordWidth dflags))
+                     | otherwise      -> Right genericIntSubCOp
 
       WordMul2Op     | ncg && x86ish  -> Left (MO_U_Mul2     (wordWidth dflags))
                      | otherwise      -> Right genericWordMul2Op
index 2673eed..c4c2446 100644 (file)
@@ -572,6 +572,8 @@ cmmPrimOpFunctions mop = do
     MO_U_QuotRem {}  -> unsupported
     MO_U_QuotRem2 {} -> unsupported
     MO_Add2 {}       -> unsupported
+    MO_AddIntC {}    -> unsupported
+    MO_SubIntC {}    -> unsupported
     MO_U_Mul2 {}     -> unsupported
     MO_WriteBarrier  -> unsupported
     MO_Touch         -> unsupported
index 3d3dff2..ddf483a 100644 (file)
@@ -1162,6 +1162,8 @@ genCCall' dflags gcp target dest_regs args0
                     MO_U_QuotRem {}  -> unsupported
                     MO_U_QuotRem2 {} -> unsupported
                     MO_Add2 {}       -> unsupported
+                    MO_AddIntC {}    -> unsupported
+                    MO_SubIntC {}    -> unsupported
                     MO_U_Mul2 {}     -> unsupported
                     MO_WriteBarrier  -> unsupported
                     MO_Touch         -> unsupported
index c192b8b..864f87f 100644 (file)
@@ -665,6 +665,8 @@ outOfLineMachOp_table mop
         MO_U_QuotRem {}  -> unsupported
         MO_U_QuotRem2 {} -> unsupported
         MO_Add2 {}       -> unsupported
+        MO_AddIntC {}    -> unsupported
+        MO_SubIntC {}    -> unsupported
         MO_U_Mul2 {}     -> unsupported
         MO_WriteBarrier  -> unsupported
         MO_Touch         -> unsupported
index bc79e5e..9d7cb78 100644 (file)
@@ -1989,6 +1989,10 @@ genCCall _ is32Bit target dest_regs args = do
                           ADC size (OpImm (ImmInteger 0)) (OpReg reg_h)
                return code
         _ -> panic "genCCall: Wrong number of arguments/results for add2"
+    (PrimTarget (MO_AddIntC width), [res_r, res_c]) ->
+        addSubIntC platform ADD_CC (Just . ADD_CC) width res_r res_c args
+    (PrimTarget (MO_SubIntC width), [res_r, res_c]) ->
+        addSubIntC platform SUB_CC (const Nothing) width res_r res_c args
     (PrimTarget (MO_U_Mul2 width), [res_h, res_l]) ->
         case args of
         [arg_x, arg_y] ->
@@ -2042,6 +2046,20 @@ genCCall _ is32Bit target dest_regs args = do
         divOp _ _ _ _ _ _ _
             = panic "genCCall: Wrong number of results for divOp"
 
+        addSubIntC platform instr mrevinstr width res_r res_c [arg_x, arg_y]
+            = do let size = intSize width
+                 rCode <- anyReg =<< trivialCode width (instr size)
+                                       (mrevinstr size) arg_x arg_y
+                 reg_tmp <- getNewRegNat II8
+                 let reg_c = getRegisterReg platform True (CmmLocal res_c)
+                     reg_r = getRegisterReg platform True (CmmLocal res_r)
+                     code = rCode reg_r `snocOL`
+                            SETCC OFLO (OpReg reg_tmp) `snocOL`
+                            MOVZxL II8 (OpReg reg_tmp) (OpReg reg_c)
+                 return code
+        addSubIntC _ _ _ _ _ _ _
+            = panic "genCCall: Wrong number of arguments/results for addSubIntC"
+
 genCCall32' :: DynFlags
             -> ForeignTarget            -- function to call
             -> [CmmFormal]        -- where to put the result
@@ -2480,6 +2498,8 @@ outOfLineCmmOp mop res args
               MO_U_QuotRem {}  -> unsupported
               MO_U_QuotRem2 {} -> unsupported
               MO_Add2 {}       -> unsupported
+              MO_AddIntC {}    -> unsupported
+              MO_SubIntC {}    -> unsupported
               MO_U_Mul2 {}     -> unsupported
               MO_WriteBarrier  -> unsupported
               MO_Touch         -> unsupported
index ef0ceea..a43d42e 100644 (file)
@@ -210,6 +210,7 @@ data Instr
         -- Do not rewrite these instructions to "equivalent" ones that
         -- have different effect on the condition register! (See #9013.)
         | ADD_CC      Size Operand Operand
+        | SUB_CC      Size Operand Operand
 
         -- Simple bit-twiddling.
         | AND         Size Operand Operand
@@ -371,6 +372,7 @@ x86_regUsageOfInstr platform instr
     DIV    _ op -> mkRU (eax:edx:use_R op []) [eax,edx]
     IDIV   _ op -> mkRU (eax:edx:use_R op []) [eax,edx]
     ADD_CC _ src dst    -> usageRM src dst
+    SUB_CC _ src dst    -> usageRM src dst
     AND    _ src dst    -> usageRM src dst
     OR     _ src dst    -> usageRM src dst
 
@@ -548,6 +550,7 @@ x86_patchRegsOfInstr instr env
     IDIV sz op          -> patch1 (IDIV sz) op
     DIV sz op           -> patch1 (DIV sz) op
     ADD_CC sz src dst   -> patch2 (ADD_CC sz) src dst
+    SUB_CC sz src dst   -> patch2 (SUB_CC sz) src dst
     AND  sz src dst     -> patch2 (AND  sz) src dst
     OR   sz src dst     -> patch2 (OR   sz) src dst
     XOR  sz src dst     -> patch2 (XOR  sz) src dst
index 89bb0b0..7c65195 100644 (file)
@@ -568,6 +568,8 @@ pprInstr (IMUL size op1 op2) = pprSizeOpOp (sLit "imul") size op1 op2
 
 pprInstr (ADD_CC size src dst)
   = pprSizeOpOp (sLit "add") size src dst
+pprInstr (SUB_CC size src dst)
+  = pprSizeOpOp (sLit "sub") size src dst
 
 {- A hack.  The Intel documentation says that "The two and three
    operand forms [of IMUL] may also be used with unsigned operands