[Git][ghc/ghc][wip/sjakobi/T25233] X86 NCG: consolidate the bit-test equations in getRegister'
Simon Jakobi pushed to branch wip/sjakobi/T25233 at Glasgow Haskell Compiler / GHC Commits: 0a963358 by Simon Jakobi at 2026-09-02T13:17:59+02:00 X86 NCG: consolidate the bit-test equations in getRegister' Following review feedback on !16311, replace the twelve equations matching single-bit clear/set/complement patterns with one per MachOp, so that BTR, BTS and BTC each appear in a single equation. New helpers clearBitArgs_maybe/setBitArgs_maybe recognise the mask operand in either position — variable index or out-of-imm32-range literal — and genBitTestImmCode is folded into genBitTestCode via the new BitIndex type. Assisted-by: Claude Fable 5 - - - - - 1 changed file: - compiler/GHC/CmmToAsm/X86/CodeGen.hs Changes: ===================================== compiler/GHC/CmmToAsm/X86/CodeGen.hs ===================================== @@ -1443,59 +1443,20 @@ getRegister' platform is32Bit (CmmMachOp mop [x]) = do -- unary MachOps ) -- Use the bit-test instructions btr/bts/btc for clearing, setting and --- complementing a single, variable bit: e.g. x .&. complement (1 `shiftL` i) --- is btr. See Note [Bit-test instructions]. -getRegister' _ is32Bit (CmmMachOp (MO_And w) [x, CmmMachOp (MO_Not _) [y]]) - | Just i <- singleBit_maybe y, bitTestOpWidthOK is32Bit w - = genBitTestCode (intFormat w) BTR x i -getRegister' _ is32Bit (CmmMachOp (MO_And w) [CmmMachOp (MO_Not _) [y], x]) - | Just i <- singleBit_maybe y, bitTestOpWidthOK is32Bit w - = genBitTestCode (intFormat w) BTR x i -getRegister' _ is32Bit (CmmMachOp (MO_Or w) [x, y]) - | Just i <- singleBit_maybe y, bitTestOpWidthOK is32Bit w - = genBitTestCode (intFormat w) BTS x i -getRegister' _ is32Bit (CmmMachOp (MO_Or w) [y, x]) - | Just i <- singleBit_maybe y, bitTestOpWidthOK is32Bit w - = genBitTestCode (intFormat w) BTS x i -getRegister' _ is32Bit (CmmMachOp (MO_Xor w) [x, y]) - | Just i <- singleBit_maybe y, bitTestOpWidthOK is32Bit w - = genBitTestCode (intFormat w) BTC x i -getRegister' _ is32Bit (CmmMachOp (MO_Xor w) [y, x]) - | Just i <- singleBit_maybe y, bitTestOpWidthOK is32Bit w - = genBitTestCode (intFormat w) BTC x i - --- The same operations with a literal bit index: constant folding has turned --- the mask itself into a literal, so use a bit-test instruction whenever the --- mask does not fit in an imm32. See Note [Bit-test instructions]. -getRegister' platform is32Bit (CmmMachOp (MO_And w) [x, CmmLit lit@(CmmInt m _)]) - | Just i <- clearBitLit_maybe w m, bitTestOpWidthOK is32Bit w - , not (is32BitLit platform lit) - = genBitTestImmCode (intFormat w) BTR x i -getRegister' platform is32Bit (CmmMachOp (MO_Or w) [x, CmmLit lit@(CmmInt m _)]) - | Just i <- setBitLit_maybe w m, bitTestOpWidthOK is32Bit w - , not (is32BitLit platform lit) - = genBitTestImmCode (intFormat w) BTS x i -getRegister' platform is32Bit (CmmMachOp (MO_Xor w) [x, CmmLit lit@(CmmInt m _)]) - | Just i <- setBitLit_maybe w m, bitTestOpWidthOK is32Bit w - , not (is32BitLit platform lit) - = genBitTestImmCode (intFormat w) BTC x i - --- Mirrored versions with the literal mask on the left. Constant folding --- canonicalizes constants to the right (see GHC.Cmm.Opt.cmmMachOpFoldM), so --- these only fire on Cmm that reaches the NCG unfolded, e.g. hand-written --- .cmm code. -getRegister' platform is32Bit (CmmMachOp (MO_And w) [CmmLit lit@(CmmInt m _), x]) - | Just i <- clearBitLit_maybe w m, bitTestOpWidthOK is32Bit w - , not (is32BitLit platform lit) - = genBitTestImmCode (intFormat w) BTR x i -getRegister' platform is32Bit (CmmMachOp (MO_Or w) [CmmLit lit@(CmmInt m _), x]) - | Just i <- setBitLit_maybe w m, bitTestOpWidthOK is32Bit w - , not (is32BitLit platform lit) - = genBitTestImmCode (intFormat w) BTS x i -getRegister' platform is32Bit (CmmMachOp (MO_Xor w) [CmmLit lit@(CmmInt m _), x]) - | Just i <- setBitLit_maybe w m, bitTestOpWidthOK is32Bit w - , not (is32BitLit platform lit) - = genBitTestImmCode (intFormat w) BTC x i +-- complementing a single bit: e.g. x .&. complement (1 `shiftL` i) is btr. +-- See Note [Bit-test instructions]. +getRegister' platform is32Bit (CmmMachOp (MO_And w) [x, y]) + | bitTestOpWidthOK is32Bit w + , Just (opnd, ix) <- clearBitArgs_maybe platform w x y + = genBitTestCode (intFormat w) BTR opnd ix +getRegister' platform is32Bit (CmmMachOp (MO_Or w) [x, y]) + | bitTestOpWidthOK is32Bit w + , Just (opnd, ix) <- setBitArgs_maybe platform w x y + = genBitTestCode (intFormat w) BTS opnd ix +getRegister' platform is32Bit (CmmMachOp (MO_Xor w) [x, y]) + | bitTestOpWidthOK is32Bit w + , Just (opnd, ix) <- setBitArgs_maybe platform w x y + = genBitTestCode (intFormat w) BTC opnd ix getRegister' platform is32Bit (CmmMachOp mop [x, y]) = do -- dyadic MachOps sse4_1 <- sse4_1Enabled @@ -5998,14 +5959,62 @@ clearBitLit_maybe w m = setBitLit_maybe w (complement m) bitTestOpWidthOK :: Bool -> Width -> Bool bitTestOpWidthOK is32Bit w = w == W32 || (w == W64 && not is32Bit) +-- | The bit-offset operand of a bit-test instruction (btr/bts/btc). +data BitIndex + = BitIndexReg CmmExpr -- ^ variable index, computed into a register + | BitIndexImm Int -- ^ literal index, emitted as an immediate + +-- | Match the operands of a single-bit set or complement operation: one +-- operand is a mask @1 << i@, or a literal with exactly one bit set that +-- does not fit in an imm32. Returns the other operand and the bit index. +-- +-- Both operand orders are matched: constant folding canonicalizes literals +-- to the right (see 'GHC.Cmm.Opt.cmmMachOpFoldM'), but e.g. hand-written +-- .cmm code reaches the NCG unfolded. +-- +-- See Note [Bit-test instructions]. +setBitArgs_maybe :: Platform -> Width -> CmmExpr -> CmmExpr + -> Maybe (CmmExpr, BitIndex) +setBitArgs_maybe platform w x y = go x y `mplus` go y x + where + go opnd mask + | Just i <- singleBit_maybe mask + = Just (opnd, BitIndexReg i) + | CmmLit lit@(CmmInt m _) <- mask + , Just i <- setBitLit_maybe w m + , not (is32BitLit platform lit) + = Just (opnd, BitIndexImm i) + | otherwise + = Nothing + +-- | As 'setBitArgs_maybe', for a single-bit clear operation: the mask is +-- @~(1 << i)@, or a literal with exactly one bit clear. +clearBitArgs_maybe :: Platform -> Width -> CmmExpr -> CmmExpr + -> Maybe (CmmExpr, BitIndex) +clearBitArgs_maybe platform w x y = go x y `mplus` go y x + where + go opnd mask + | CmmMachOp (MO_Not _) [b] <- mask + , Just i <- singleBit_maybe b + = Just (opnd, BitIndexReg i) + | CmmLit lit@(CmmInt m _) <- mask + , Just i <- clearBitLit_maybe w m + , not (is32BitLit platform lit) + = Just (opnd, BitIndexImm i) + | otherwise + = Nothing + -- | Generate code for @dst := x@ followed by a bit-test instruction --- (btr/bts/btc) with bit offset @i@. +-- (btr/bts/btc). -- --- Analogous to 'genTrivialCode', but the offset operand must be a register, --- not memory. See Note [Bit-test instructions]. +-- See Note [Bit-test instructions]. genBitTestCode :: Format -> (Format -> Operand -> Operand -> Instr) - -> CmmExpr -> CmmExpr -> NatM Register -genBitTestCode rep instr x i = do + -> CmmExpr -> BitIndex -> NatM Register +genBitTestCode rep instr x (BitIndexImm i) = do + x_code <- getAnyReg x + let code dst = x_code dst `snocOL` instr rep (OpImm (ImmInt i)) (OpReg dst) + return (Any rep code) +genBitTestCode rep instr x (BitIndexReg i) = do (i_reg, i_code) <- getNonClobberedReg i x_code <- getAnyReg x tmp <- getNewRegNat rep @@ -6024,17 +6033,6 @@ genBitTestCode rep instr x i = do instr rep (OpReg i_reg) (OpReg dst) return (Any rep code) --- | Generate code for @dst := x@ followed by a bit-test instruction --- (btr/bts/btc) with an immediate bit offset. --- --- See Note [Bit-test instructions]. -genBitTestImmCode :: Format -> (Format -> Operand -> Operand -> Instr) - -> CmmExpr -> Int -> NatM Register -genBitTestImmCode rep instr x i = do - x_code <- getAnyReg x - let code dst = x_code dst `snocOL` instr rep (OpImm (ImmInt i)) (OpReg dst) - return (Any rep code) - regClashesWithOp :: Reg -> Operand -> Bool reg `regClashesWithOp` OpReg reg2 = reg == reg2 reg `regClashesWithOp` OpAddr amode = any (==reg) (addrModeRegs amode) View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0a963358ee96088a9a41da373d7371c8... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0a963358ee96088a9a41da373d7371c8... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
participants (1)
-
Simon Jakobi (@sjakobi)