Fixes a kernel panic for 4.4 LTS x86_64 Linux kernels.
Fixes: D79794
Link: https://github.com/ClangBuiltLinux/linux/issues/1085
Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
Differential D83523
MachineSink: permit sinking into INLINEASM_BR indirect targets nickdesaulniers on Jul 9 2020, 5:15 PM. Authored by
Details Fixes a kernel panic for 4.4 LTS x86_64 Linux kernels. Fixes: D79794
Diff Detail
Event TimelineComment Actions From the comment, there's obviously more we want to do here. Posting what I have for today since it's EOD. Will iterate on feedback tomorrow. Comment Actions I'm confused by this change. The original code *should* be correct. That it's resulting in this issue is another thing. My first question is, why are we trying to sink instructions into the entry block? Comment Actions Without this change, the "ADD64ri8" instruction is before the INLINEASM_BR before machine sinking. Comment Actions It looks like the issue shown in this test-case appears in Two-Address instruction pass, not Machine Sink. We go from: bb.0 (%ir-block.1): successors: %bb.2(0x80000000), %bb.1(0x00000000); %bb.2(100.00%), %bb.1(0.00%) liveins: $rdi %1:gr64 = COPY killed $rdi %0:gr64 = nuw ADD64ri8 %1:gr64(tied-def 0), 24, implicit-def dead $eflags INLINEASM_BR &"# $0 $1 $2" [sideeffect] [mayload] [maystore] [attdialect], $0:[mem:m], killed %1:gr64, 1, $noreg, 24, $noreg, $1:[imm], 1, $2:[imm], blockaddress(@klist_dec_and_del, %ir-block.4), $ 3:[clobber], implicit-def dead early-clobber $df, $4:[clobber], implicit-def early-clobber $fpsw, $5:[clobber], implicit-def dead early-clobber $eflags JMP_1 %bb.2 bb.1 (%ir-block.4, address-taken): ; predecessors: %bb.0 successors: %bb.2(0x80000000); %bb.2(100.00%) MOV64mi32 killed %0:gr64, 1, $noreg, -24, $noreg, 0 :: (store 8 into %ir.6) bb.2 (%ir-block.7): ; predecessors: %bb.0, %bb.1 RET 0, undef $eax then replace the ADD64ri8 with a LEA64r -- but place it _after_ the INLINEASM_BR, bb.0 (%ir-block.1): successors: %bb.2(0x80000000), %bb.1(0x00000000); %bb.2(100.00%), %bb.1(0.00%) liveins: $rdi %1:gr64 = COPY killed $rdi - %0:gr64 = nuw ADD64ri8 %1:gr64(tied-def 0), 24, implicit-def dead $eflags - INLINEASM_BR &"# $0 $1 $2" [sideeffect] [mayload] [maystore] [attdialect], $0:[mem:m], killed %1:gr64, 1, $noreg, 24, $noreg, $1:[imm], 1, $2:[imm], blockaddress(@klist_dec_and_del, %ir-block.4), $3:[clobber], implicit-def dead early-clobber $df, $4:[clobber], implicit-def early-clobber $fpsw, $5:[clobber], implicit-def dead early-clobber $eflags + INLINEASM_BR &"# $0 $1 $2" [sideeffect] [mayload] [maystore] [attdialect], $0:[mem:m], %1:gr64, 1, $noreg, 24, $noreg, $1:[imm], 1, $2:[imm], blockaddress(@klist_dec_and_del, %ir-block.4), $3:[clobber], implicit-def dead early-clobber $df, $4:[clobber], implicit-def early-clobber $fpsw, $5:[clobber], implicit-def dead early-clobber $eflags + %0:gr64 = LEA64r killed %1:gr64, 1, $noreg, 24, $noreg JMP_1 %bb.2 Comment Actions I think this might be a better fix: diff --git a/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp b/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp index de336abe607..d21407a60eb 100644 --- a/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp +++ b/llvm/lib/CodeGen/TwoAddressInstructionPass.cpp @@ -888,6 +888,7 @@ rescheduleMIBelowKill(MachineBasicBlock::iterator &mi, return false; if (KillMI->hasUnmodeledSideEffects() || KillMI->isCall() || + KillMI->getOpcode() == TargetOpcode::INLINEASM_BR || KillMI->isBranch() || KillMI->isTerminator()) // Don't move pass calls, etc. return false; @@ -948,6 +949,7 @@ rescheduleMIBelowKill(MachineBasicBlock::iterator &mi, return false; ++NumVisited; if (OtherMI.hasUnmodeledSideEffects() || OtherMI.isCall() || + OtherMI.getOpcode() == TargetOpcode::INLINEASM_BR || OtherMI.isBranch() || OtherMI.isTerminator()) // Don't move pass calls, etc. return false; @@ -1122,6 +1124,7 @@ rescheduleKillAboveMI(MachineBasicBlock::iterator &mi, return false; ++NumVisited; if (OtherMI.hasUnmodeledSideEffects() || OtherMI.isCall() || + OtherMI.getOpcode() == TargetOpcode::INLINEASM_BR || OtherMI.isBranch() || OtherMI.isTerminator()) // Don't move pass calls, etc. return false; Comment Actions Here are a few other places to contemplate similar changes: diff --git a/llvm/lib/CodeGen/MachineCSE.cpp b/llvm/lib/CodeGen/MachineCSE.cpp index 09531276bc1..a6873c7acba 100644 --- a/llvm/lib/CodeGen/MachineCSE.cpp +++ b/llvm/lib/CodeGen/MachineCSE.cpp @@ -404,6 +404,7 @@ bool MachineCSE::isCSECandidate(MachineInstr *MI) { // Ignore stuff that we obviously can't move. if (MI->mayStore() || MI->isCall() || MI->isTerminator() || + MI->getOpcode() == TargetOpcode::INLINEASM_BR || MI->mayRaiseFPException() || MI->hasUnmodeledSideEffects()) return false; diff --git a/llvm/lib/CodeGen/ReachingDefAnalysis.cpp b/llvm/lib/CodeGen/ReachingDefAnalysis.cpp index 5bd8b4b8e27..90e829c925e 100644 --- a/llvm/lib/CodeGen/ReachingDefAnalysis.cpp +++ b/llvm/lib/CodeGen/ReachingDefAnalysis.cpp @@ -519,6 +519,7 @@ MachineInstr* ReachingDefAnalysis::getLocalLiveOutMIDef(MachineBasicBlock *MBB, static bool mayHaveSideEffects(MachineInstr &MI) { return MI.mayLoadOrStore() || MI.mayRaiseFPException() || MI.hasUnmodeledSideEffects() || MI.isTerminator() || + MI.getOpcode() == TargetOpcode::INLINEASM_BR || MI.isCall() || MI.isBarrier() || MI.isBranch() || MI.isReturn(); } Comment Actions In https://github.com/ClangBuiltLinux/linux/issues/1085#issuecomment-656347490 @void suggested trying to mark INLINEASM_BR MCInsts as IsBarrier. Based on the latest recommendations, I'm wondering if IsCall is more appropriate? Comment Actions Ah, right, because the test case is still testing machinesink. Let me change it to twoaddressinstruction and retest. Comment Actions INLINEASM_BR already returns true for hasUnmodeledSideEffects(), so the diff above doesn't change anything. The bug is in TwoAddressInstructinoPass::sink3AddrInstruction, which doesn't query _ANY_ of these predicates. I've just uploaded https://reviews.llvm.org/D83708 to remove the function entirely. |