From c9b69847ef7559bdabd9b75962111605bd357dc2 Mon Sep 17 00:00:00 2001
From: Ian Lynagh <igloo@earth.li>
Date: Sun, 29 Jan 2012 21:25:55 +0000
Subject: [PATCH] Implement quotRemInt# primop
This means we can do quotRem with only a single division instruction,
rather than both quot and rem doing duplicate divisions.
---
compiler/cmm/CmmLint.hs | 8 +++++
compiler/cmm/CmmMachOp.hs | 3 ++
compiler/cmm/CmmOpt.hs | 1 +
compiler/cmm/CmmType.hs | 15 +++++++++-
compiler/cmm/OldCmm.hs | 2 +
compiler/cmm/OldPprCmm.hs | 3 ++
compiler/cmm/PprC.hs | 5 +++
compiler/codeGen/CgPrimOp.hs | 5 +++
compiler/llvmGen/LlvmCodeGen/CodeGen.hs | 5 +++
compiler/nativeGen/PPC/CodeGen.hs | 2 +
compiler/nativeGen/SPARC/CodeGen.hs | 2 +
compiler/nativeGen/X86/CodeGen.hs | 47 +++++++++++++++++++++++++++++++
compiler/prelude/primops.txt.pp | 5 +++
13 files changed, 102 insertions(+), 1 deletions(-)
diff --git a/compiler/cmm/CmmLint.hs b/compiler/cmm/CmmLint.hs
index bed3b18..13f7429 100644
|
a
|
b
|
|
| 129 | 129 | if (erep `cmmEqType_ignoring_ptrhood` reg_ty) |
| 130 | 130 | then return () |
| 131 | 131 | else cmmLintAssignErr platform stmt erep reg_ty |
| | 132 | lint stmt@(CmmAssign2 reg1 reg2 expr) = do |
| | 133 | erep <- lintCmmExpr platform expr |
| | 134 | let reg1_ty = cmmRegType reg1 |
| | 135 | reg2_ty = cmmRegType reg2 |
| | 136 | reg_tys = cmmTypes [reg1_ty, reg2_ty] |
| | 137 | if (erep `cmmEqType_ignoring_ptrhood` reg_tys) |
| | 138 | then return () |
| | 139 | else cmmLintAssignErr platform stmt erep reg_tys |
| 132 | 140 | lint (CmmStore l r) = do |
| 133 | 141 | _ <- lintCmmExpr platform l |
| 134 | 142 | _ <- lintCmmExpr platform r |
diff --git a/compiler/cmm/CmmMachOp.hs b/compiler/cmm/CmmMachOp.hs
index 2effa3a..2aba6f3 100644
|
a
|
b
|
|
| 51 | 51 | | MO_S_MulMayOflo Width -- nonzero if signed multiply overflows |
| 52 | 52 | | MO_S_Quot Width -- signed / (same semantics as IntQuotOp) |
| 53 | 53 | | MO_S_Rem Width -- signed % (same semantics as IntRemOp) |
| | 54 | | MO_S_QuotRem Width -- signed / % (same semantics as IntQuotOp and IntRemOp) |
| 54 | 55 | | MO_S_Neg Width -- unary - |
| 55 | 56 | |
| 56 | 57 | -- Unsigned multiply/divide |
| … |
… |
|
| 295 | 296 | MO_S_MulMayOflo r -> cmmBits r |
| 296 | 297 | MO_S_Quot r -> cmmBits r |
| 297 | 298 | MO_S_Rem r -> cmmBits r |
| | 299 | MO_S_QuotRem r -> cmmTypes [cmmBits r, cmmBits r] |
| 298 | 300 | MO_S_Neg r -> cmmBits r |
| 299 | 301 | MO_U_MulMayOflo r -> cmmBits r |
| 300 | 302 | MO_U_Quot r -> cmmBits r |
| … |
… |
|
| 363 | 365 | MO_S_MulMayOflo r -> [r,r] |
| 364 | 366 | MO_S_Quot r -> [r,r] |
| 365 | 367 | MO_S_Rem r -> [r,r] |
| | 368 | MO_S_QuotRem r -> [r,r] |
| 366 | 369 | MO_S_Neg r -> [r] |
| 367 | 370 | MO_U_MulMayOflo r -> [r,r] |
| 368 | 371 | MO_U_Quot r -> [r,r] |
diff --git a/compiler/cmm/CmmOpt.hs b/compiler/cmm/CmmOpt.hs
index ae715a9..e9ce2bb 100644
|
a
|
b
|
|
| 58 | 58 | stmt m CmmNop = m |
| 59 | 59 | stmt m (CmmComment _) = m |
| 60 | 60 | stmt m (CmmAssign _ e) = expr m e |
| | 61 | stmt m (CmmAssign2 _ _ e) = expr m e |
| 61 | 62 | stmt m (CmmStore e1 e2) = expr (expr m e1) e2 |
| 62 | 63 | stmt m (CmmCall c _ as _) = f (actuals m as) c |
| 63 | 64 | where f m (CmmCallee e _) = expr m e |
diff --git a/compiler/cmm/CmmType.hs b/compiler/cmm/CmmType.hs
index 2727754..28afeae 100644
|
a
|
b
|
|
| 3 | 3 | ( CmmType -- Abstract |
| 4 | 4 | , b8, b16, b32, b64, f32, f64, bWord, bHalfWord, gcWord |
| 5 | 5 | , cInt, cLong |
| 6 | | , cmmBits, cmmFloat |
| | 6 | , cmmTypes, cmmBits, cmmFloat |
| 7 | 7 | , typeWidth, cmmEqType, cmmEqType_ignoring_ptrhood |
| 8 | 8 | , isFloatType, isGcPtrType, isWord32, isWord64, isFloat64, isFloat32 |
| 9 | 9 | |
| … |
… |
|
| 35 | 35 | |
| 36 | 36 | data CmmType -- The important one! |
| 37 | 37 | = CmmType CmmCat Width |
| | 38 | | CmmTypes [CmmType] |
| 38 | 39 | |
| 39 | 40 | data CmmCat -- "Category" (not exported) |
| 40 | 41 | = GcPtrCat -- GC pointer |
| … |
… |
|
| 45 | 46 | |
| 46 | 47 | instance Outputable CmmType where |
| 47 | 48 | ppr (CmmType cat wid) = ppr cat <> ppr (widthInBits wid) |
| | 49 | ppr (CmmTypes ts) = parens (ptext (sLit "CmmTypes") <+> sep (map ppr ts)) |
| 48 | 50 | |
| 49 | 51 | instance Outputable CmmCat where |
| 50 | 52 | ppr FloatCat = ptext $ sLit("F") |
| … |
… |
|
| 63 | 65 | -- So we use an explicit function to force you to think about it |
| 64 | 66 | cmmEqType :: CmmType -> CmmType -> Bool -- Exact equality |
| 65 | 67 | cmmEqType (CmmType c1 w1) (CmmType c2 w2) = c1==c2 && w1==w2 |
| | 68 | cmmEqType (CmmTypes ts1) (CmmTypes ts2) = and $ zipWith cmmEqType ts1 ts2 |
| | 69 | cmmEqType (CmmType {}) (CmmTypes {}) = False |
| | 70 | cmmEqType (CmmTypes {}) (CmmType {}) = False |
| 66 | 71 | |
| 67 | 72 | cmmEqType_ignoring_ptrhood :: CmmType -> CmmType -> Bool |
| 68 | 73 | -- This equality is temporary; used in CmmLint |
| … |
… |
|
| 74 | 79 | FloatCat `weak_eq` _other = False |
| 75 | 80 | _other `weak_eq` FloatCat = False |
| 76 | 81 | _word1 `weak_eq` _word2 = True -- Ignores GcPtr |
| | 82 | cmmEqType_ignoring_ptrhood (CmmTypes ts1) (CmmTypes ts2) |
| | 83 | = and $ zipWith cmmEqType_ignoring_ptrhood ts1 ts2 |
| | 84 | cmmEqType_ignoring_ptrhood (CmmType {}) (CmmTypes {}) = False |
| | 85 | cmmEqType_ignoring_ptrhood (CmmTypes {}) (CmmType {}) = False |
| 77 | 86 | |
| 78 | 87 | --- Simple operations on CmmType ----- |
| 79 | 88 | typeWidth :: CmmType -> Width |
| 80 | 89 | typeWidth (CmmType _ w) = w |
| | 90 | typeWidth _ = panic "XXX typeWidth" |
| | 91 | |
| | 92 | cmmTypes :: [CmmType] -> CmmType |
| | 93 | cmmTypes = CmmTypes |
| 81 | 94 | |
| 82 | 95 | cmmBits, cmmFloat :: Width -> CmmType |
| 83 | 96 | cmmBits = CmmType BitsCat |
diff --git a/compiler/cmm/OldCmm.hs b/compiler/cmm/OldCmm.hs
index 7b5917d..2c6460a 100644
|
a
|
b
|
|
| 147 | 147 | | CmmComment FastString |
| 148 | 148 | |
| 149 | 149 | | CmmAssign CmmReg CmmExpr -- Assign to register |
| | 150 | | CmmAssign2 CmmReg CmmReg CmmExpr -- Assign to 2 registers |
| 150 | 151 | |
| 151 | 152 | | CmmStore CmmExpr CmmExpr -- Assign to memory location. Size is |
| 152 | 153 | -- given by cmmExprType of the rhs. |
| … |
… |
|
| 210 | 211 | stmt (CmmNop) = id |
| 211 | 212 | stmt (CmmComment {}) = id |
| 212 | 213 | stmt (CmmAssign _ e) = gen e |
| | 214 | stmt (CmmAssign2 _ _ e) = gen e |
| 213 | 215 | stmt (CmmStore e1 e2) = gen e1 . gen e2 |
| 214 | 216 | stmt (CmmCall target _ es _) = gen target . gen es |
| 215 | 217 | stmt (CmmBranch _) = id |
diff --git a/compiler/cmm/OldPprCmm.hs b/compiler/cmm/OldPprCmm.hs
index 4b1da0b..e63ba44 100644
|
a
|
b
|
|
| 113 | 113 | -- reg = expr; |
| 114 | 114 | CmmAssign reg expr -> ppr reg <+> equals <+> pprPlatform platform expr <> semi |
| 115 | 115 | |
| | 116 | -- reg1, reg2 = expr; |
| | 117 | CmmAssign2 reg1 reg2 expr -> ppr reg1 <> comma <+> ppr reg2 <+> equals <+> pprPlatform platform expr <> semi |
| | 118 | |
| 116 | 119 | -- rep[lv] = expr; |
| 117 | 120 | CmmStore lv expr -> rep <> brackets(pprPlatform platform lv) <+> equals <+> pprPlatform platform expr <> semi |
| 118 | 121 | where |
diff --git a/compiler/cmm/PprC.hs b/compiler/cmm/PprC.hs
index 658e3ca..1b8b28c 100644
|
a
|
b
|
|
| 181 | 181 | -- large. |
| 182 | 182 | |
| 183 | 183 | CmmAssign dest src -> pprAssign platform dest src |
| | 184 | CmmAssign2 dest1 dest2 src -> pprAssign2 platform dest1 dest2 src |
| 184 | 185 | |
| 185 | 186 | CmmStore dest src |
| 186 | 187 | | typeWidth rep == W64 && wordWidth /= W64 |
| … |
… |
|
| 527 | 528 | |
| 528 | 529 | MO_S_Quot _ -> char '/' |
| 529 | 530 | MO_S_Rem _ -> char '%' |
| | 531 | MO_S_QuotRem _ -> panic "XXX pprMachOp_for_C" |
| 530 | 532 | MO_S_Neg _ -> char '-' |
| 531 | 533 | |
| 532 | 534 | MO_U_Quot _ -> char '/' |
| … |
… |
|
| 717 | 719 | then ptext (sLit "ASSIGN_BaseReg") <> parens x <> semi |
| 718 | 720 | else pprReg r1 <> ptext (sLit " = ") <> x <> semi |
| 719 | 721 | |
| | 722 | pprAssign2 :: Platform -> CmmReg -> CmmReg -> CmmExpr -> SDoc |
| | 723 | pprAssign2 = panic "XXX pprAssign2" |
| | 724 | |
| 720 | 725 | -- --------------------------------------------------------------------- |
| 721 | 726 | -- Registers |
| 722 | 727 | |
diff --git a/compiler/codeGen/CgPrimOp.hs b/compiler/codeGen/CgPrimOp.hs
index b0865d6..942bb50 100644
|
a
|
b
|
|
| 440 | 440 | = let stmt = CmmAssign (CmmLocal res) (CmmMachOp mop args) in |
| 441 | 441 | stmtC stmt |
| 442 | 442 | |
| | 443 | emitPrimOp [res_q, res_r] IntQuotRemOp args _ |
| | 444 | = let stmt = CmmAssign2 (CmmLocal res_q) (CmmLocal res_r) |
| | 445 | (CmmMachOp (MO_S_QuotRem wordWidth) args) |
| | 446 | in stmtC stmt |
| | 447 | |
| 443 | 448 | emitPrimOp _ op _ _ |
| 444 | 449 | = pprPanic "emitPrimOp: can't translate PrimOp" (ppr op) |
| 445 | 450 | |
diff --git a/compiler/llvmGen/LlvmCodeGen/CodeGen.hs b/compiler/llvmGen/LlvmCodeGen/CodeGen.hs
index d503782..32090d1 100644
|
a
|
b
|
|
| 117 | 117 | CmmComment _ -> return (env, nilOL, []) -- nuke comments |
| 118 | 118 | |
| 119 | 119 | CmmAssign reg src -> genAssign env reg src |
| | 120 | CmmAssign2 _ _ _ -> panic "XXX stmtToInstrs" |
| 120 | 121 | CmmStore addr src -> genStore env addr src |
| 121 | 122 | |
| 122 | 123 | CmmBranch id -> genBranch env id |
| … |
… |
|
| 458 | 459 | |
| 459 | 460 | (MO_PopCnt w) -> fsLit $ "llvm.ctpop." ++ show (widthToLlvmInt w) |
| 460 | 461 | |
| | 462 | -- MO_S_QuotRem _ -> panic "XXX LLVM MO_S_QuotRem" |
| | 463 | |
| 461 | 464 | MO_WriteBarrier -> |
| 462 | 465 | panic $ "cmmPrimOpFunctions: MO_WriteBarrier not supported here" |
| 463 | 466 | MO_Touch -> |
| … |
… |
|
| 766 | 769 | MO_S_MulMayOflo _ -> panicOp |
| 767 | 770 | MO_S_Quot _ -> panicOp |
| 768 | 771 | MO_S_Rem _ -> panicOp |
| | 772 | MO_S_QuotRem _ -> panic "XXX genMachOp" |
| 769 | 773 | MO_U_MulMayOflo _ -> panicOp |
| 770 | 774 | MO_U_Quot _ -> panicOp |
| 771 | 775 | MO_U_Rem _ -> panicOp |
| … |
… |
|
| 886 | 890 | |
| 887 | 891 | MO_S_Quot _ -> genBinMach LM_MO_SDiv |
| 888 | 892 | MO_S_Rem _ -> genBinMach LM_MO_SRem |
| | 893 | MO_S_QuotRem _ -> panic "XXX genMachOp_slow" |
| 889 | 894 | |
| 890 | 895 | MO_U_Quot _ -> genBinMach LM_MO_UDiv |
| 891 | 896 | MO_U_Rem _ -> genBinMach LM_MO_URem |
diff --git a/compiler/nativeGen/PPC/CodeGen.hs b/compiler/nativeGen/PPC/CodeGen.hs
index 7b704cb..490537f 100644
|
a
|
b
|
|
| 127 | 127 | where ty = cmmRegType reg |
| 128 | 128 | size = cmmTypeSize ty |
| 129 | 129 | |
| | 130 | CmmAssign2 _ _ _ -> panic "XXX PPC stmtToInstrs" |
| | 131 | |
| 130 | 132 | CmmStore addr src |
| 131 | 133 | | isFloatType ty -> assignMem_FltCode size addr src |
| 132 | 134 | | target32Bit (targetPlatform dflags) && |
diff --git a/compiler/nativeGen/SPARC/CodeGen.hs b/compiler/nativeGen/SPARC/CodeGen.hs
index 4c295f1..1c0effd 100644
|
a
|
b
|
|
| 128 | 128 | where ty = cmmRegType reg |
| 129 | 129 | size = cmmTypeSize ty |
| 130 | 130 | |
| | 131 | CmmAssign2 _ _ _ -> panic "XXX SPARC stmtToInstrs" |
| | 132 | |
| 131 | 133 | CmmStore addr src |
| 132 | 134 | | isFloatType ty -> assignMem_FltCode size addr src |
| 133 | 135 | | isWord64 ty -> assignMem_I64Code addr src |
diff --git a/compiler/nativeGen/X86/CodeGen.hs b/compiler/nativeGen/X86/CodeGen.hs
index c685195..d2d5f14 100644
|
a
|
b
|
|
| 153 | 153 | where ty = cmmRegType reg |
| 154 | 154 | size = cmmTypeSize ty |
| 155 | 155 | |
| | 156 | CmmAssign2 reg1 reg2 src |
| | 157 | -- XXX Should probably mirror the CmmAssign tests |
| | 158 | | otherwise -> assign2Reg_IntCode reg1 reg2 src |
| | 159 | |
| | 160 | |
| 156 | 161 | CmmStore addr src |
| 157 | 162 | | isFloatType ty -> assignMem_FltCode size addr src |
| 158 | 163 | | is32Bit && isWord64 ty -> assignMem_I64Code addr src |
| … |
… |
|
| 208 | 213 | = Fixed Size Reg InstrBlock |
| 209 | 214 | | Any Size (Reg -> InstrBlock) |
| 210 | 215 | |
| | 216 | data Register2 |
| | 217 | = Fixed2 Size Reg Reg InstrBlock |
| | 218 | | Any2 Size (Reg -> Reg -> InstrBlock) |
| | 219 | |
| 211 | 220 | |
| 212 | 221 | swizzleRegisterRep :: Register -> Size -> Register |
| 213 | 222 | swizzleRegisterRep (Fixed _ reg code) size = Fixed size reg code |
| … |
… |
|
| 890 | 899 | getRegister' _ other = do dflags <- getDynFlags |
| 891 | 900 | pprPanic "getRegister(x86)" (pprPlatform (targetPlatform dflags) other) |
| 892 | 901 | |
| | 902 | get2Register :: CmmExpr -> NatM Register2 |
| | 903 | get2Register (CmmMachOp (MO_S_QuotRem rep) [x, y]) = do |
| | 904 | div_code rep True x y |
| | 905 | where |
| | 906 | div_code width signed x y = do |
| | 907 | (y_op, y_code) <- getRegOrMem y -- cannot be clobbered |
| | 908 | x_code <- getAnyReg x |
| | 909 | let |
| | 910 | size = intSize width |
| | 911 | widen | signed = CLTD size |
| | 912 | | otherwise = XOR size (OpReg edx) (OpReg edx) |
| | 913 | |
| | 914 | instr | signed = IDIV |
| | 915 | | otherwise = DIV |
| | 916 | |
| | 917 | code = y_code `appOL` |
| | 918 | x_code eax `appOL` |
| | 919 | toOL [widen, instr size y_op] |
| | 920 | |
| | 921 | return (Fixed2 size eax edx code) |
| | 922 | get2Register _ = panic "XXX X86 get2Register" |
| | 923 | |
| 893 | 924 | |
| 894 | 925 | intLoadCode :: (Operand -> Operand -> Instr) -> CmmExpr |
| 895 | 926 | -> NatM (Reg -> InstrBlock) |
| … |
… |
|
| 904 | 935 | r <- getRegister expr |
| 905 | 936 | anyReg r |
| 906 | 937 | |
| | 938 | getAny2Reg :: CmmExpr -> NatM (Reg -> Reg -> InstrBlock) |
| | 939 | getAny2Reg expr = do |
| | 940 | r2 <- get2Register expr |
| | 941 | any2Reg r2 |
| | 942 | |
| 907 | 943 | anyReg :: Register -> NatM (Reg -> InstrBlock) |
| 908 | 944 | anyReg (Any _ code) = return code |
| 909 | 945 | anyReg (Fixed rep reg fcode) = return (\dst -> fcode `snocOL` reg2reg rep reg dst) |
| 910 | 946 | |
| | 947 | any2Reg :: Register2 -> NatM (Reg -> Reg -> InstrBlock) |
| | 948 | any2Reg (Any2 _ code) = return code |
| | 949 | any2Reg (Fixed2 rep reg1 reg2 fcode) = return (\dst1 dst2 -> fcode `snocOL` reg2reg rep reg1 dst1 `snocOL` reg2reg rep reg2 dst2) |
| | 950 | |
| 911 | 951 | -- A bit like getSomeReg, but we want a reg that can be byte-addressed. |
| 912 | 952 | -- Fixed registers might not be byte-addressable, so we make sure we've |
| 913 | 953 | -- got a temporary, inserting an extra reg copy if necessary. |
| … |
… |
|
| 1406 | 1446 | code <- getAnyReg src |
| 1407 | 1447 | return (code (getRegisterReg False{-no sse2-} reg)) |
| 1408 | 1448 | |
| | 1449 | assign2Reg_IntCode :: CmmReg -> CmmReg -> CmmExpr -> NatM InstrBlock |
| | 1450 | -- dsts are regs, but src could be anything |
| | 1451 | assign2Reg_IntCode reg1 reg2 src = do |
| | 1452 | code <- getAny2Reg src |
| | 1453 | return (code (getRegisterReg False{-no sse2-} reg1) |
| | 1454 | (getRegisterReg False{-no sse2-} reg2)) |
| | 1455 | |
| 1409 | 1456 | |
| 1410 | 1457 | -- Floating point assignment to memory |
| 1411 | 1458 | assignMem_FltCode pk addr src = do |
diff --git a/compiler/prelude/primops.txt.pp b/compiler/prelude/primops.txt.pp
index 48dd768..183bd35 100644
|
a
|
b
|
|
| 210 | 210 | {Satisfies \texttt{(quotInt\# x y) *\# y +\# (remInt\# x y) == x}.} |
| 211 | 211 | with can_fail = True |
| 212 | 212 | |
| | 213 | primop IntQuotRemOp "quotRemInt#" GenPrimOp |
| | 214 | Int# -> Int# -> (# Int#, Int# #) |
| | 215 | {Rounds towards zero.} |
| | 216 | with can_fail = True |
| | 217 | |
| 213 | 218 | primop IntNegOp "negateInt#" Monadic Int# -> Int# |
| 214 | 219 | primop IntAddCOp "addIntC#" GenPrimOp Int# -> Int# -> (# Int#, Int# #) |
| 215 | 220 | {Add with carry. First member of result is (wrapped) sum; |