diff options
author | Ben Gamari <ben@smart-cactus.org> | 2019-12-18 14:35:57 -0500 |
---|---|---|
committer | Ben Gamari <ben@well-typed.com> | 2020-01-17 19:28:12 -0500 |
commit | 9fe3f88d296256f4a9e96c53d341a725d5e2c419 (patch) | |
tree | a1f62e15faa1dc07891b67907ecb3f7ee1ba9a88 /compiler/nativeGen/X86/CodeGen.hs | |
parent | a71323ffebf7663c50025d2731bf9de2d04f82c3 (diff) | |
download | haskell-wip/T17588.tar.gz |
nativeGen/X86: Add UD2 instructions after indirect brancheswip/T17588
As noted in the Intel Software Optimization Manual (section 3.4.1.6,
Rule 14), the default prediction for indirect branches is to
fall-through. This means that the instruction decoder will attempt to
decode anything that follows indirect branches. This will inject
operations in to the pipeline that are doomed to fail (since our
indirect branches will never fallthrough), resulting in resource
conflicts.
Fixes #17588.
Diffstat (limited to 'compiler/nativeGen/X86/CodeGen.hs')
-rw-r--r-- | compiler/nativeGen/X86/CodeGen.hs | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/compiler/nativeGen/X86/CodeGen.hs b/compiler/nativeGen/X86/CodeGen.hs index 8cea28d920..616c23a657 100644 --- a/compiler/nativeGen/X86/CodeGen.hs +++ b/compiler/nativeGen/X86/CodeGen.hs @@ -180,11 +180,16 @@ verifyBasicBlock instrs CALL {} | atEnd -> faultyBlockWith i | not atEnd -> go atEnd instr -- All instructions ok, check if we reached the end and continue. - _ | not atEnd -> go (isJumpishInstr i) instr - -- Only jumps allowed at the end of basic blocks. - | otherwise -> if isJumpishInstr i - then go True instr - else faultyBlockWith i + _ | not atEnd -> go (isJumpishInstr i) instr + | isTerminalInstr i -> go True instr + | otherwise -> faultyBlockWith i + + -- Only jumps (or UD2, which always follows indirect jumps) + -- allowed at the end of basic blocks. + isTerminalInstr UD2 = True + isTerminalInstr i | isJumpishInstr i = True + isTerminalInstr _ = False + faultyBlockWith i = pprPanic "Non control flow instructions after end of basic block." (ppr i <+> text "in:" $$ vcat (map ppr instrs)) @@ -1766,19 +1771,28 @@ assignReg_FltCode _ reg src = do let platform = targetPlatform dflags return (src_code (getRegisterReg platform reg)) +-- Note [UD2 after indirect jumps] +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-- +-- We follow all indirect jumps with a UD2 instruction to ensure that the +-- instruction decoder doesn't attempt to decode the fallthrough path, which +-- can result in resource conflicts. See Intel Software Optimisation Manual +-- Section 3.4.1.6 (Branch Type Selection), Rule 14. genJump :: CmmExpr{-the branch target-} -> [Reg] -> NatM InstrBlock genJump (CmmLoad mem _) regs = do Amode target code <- getAmode mem - return (code `snocOL` JMP (OpAddr target) regs) + -- See Note [UD2 after indirect jumps] + return (code `snocOL` JMP (OpAddr target) regs `snocOL` UD2) genJump (CmmLit lit) regs = do return (unitOL (JMP (OpImm (litToImm lit)) regs)) genJump expr regs = do (reg,code) <- getSomeReg expr - return (code `snocOL` JMP (OpReg reg) regs) + -- See Note [UD2 after indirect jumps] + return (code `snocOL` JMP (OpReg reg) regs `snocOL` UD2) -- ----------------------------------------------------------------------------- |