Author: Koakuma Date: 2026-01-21T08:06:58Z New Revision: 16fcbfb51be736dbb8059ed6c79100d9f1ea135d
URL: https://github.com/llvm/llvm-project/commit/16fcbfb51be736dbb8059ed6c79100d9f1ea135d DIFF: https://github.com/llvm/llvm-project/commit/16fcbfb51be736dbb8059ed6c79100d9f1ea135d.diff LOG: [SPARC] Prevent RESTORE from sourcing from %o7 in call delay slots (#172593) Combining instructions that reads from %o7 with a RESTORE in call delay slots will result in a RESTORE instruction that reads from %o7, which has been overwritten by the call instruction, resulting in junk values being produced. This should fix the issue with `test-suite::lencod.test`. (cherry picked from commit ab4adedd1c1ad9f30637291dfe94f9f0519ea2f5) Added: Modified: llvm/lib/Target/Sparc/DelaySlotFiller.cpp llvm/lib/Target/Sparc/SparcInstrInfo.td llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll Removed: ################################################################################ diff --git a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp index 024030d196ee3..7d7aa20869c20 100644 --- a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp +++ b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp @@ -303,15 +303,20 @@ void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI, SmallSet<unsigned, 32>& RegDefs, SmallSet<unsigned, 32>& RegUses) { - // Call defines o7, which is visible to the instruction in delay slot. - RegDefs.insert(SP::O7); - + // Regular calls define o7, which is visible to the instruction in delay slot. + // On the other hand, tail calls preserve it. switch(MI->getOpcode()) { default: llvm_unreachable("Unknown opcode."); case SP::CALL: + RegDefs.insert(SP::O7); + break; + case SP::TAIL_CALL: break; case SP::CALLrr: case SP::CALLri: + RegDefs.insert(SP::O7); + [[fallthrough]]; + case SP::TAIL_CALLri: assert(MI->getNumOperands() >= 2); const MachineOperand &Reg = MI->getOperand(0); assert(Reg.isReg() && "CALL first operand is not a register."); @@ -390,19 +395,33 @@ bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize) return true; } -static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI, +static bool combineRestoreADD(MachineBasicBlock &MBB, + MachineBasicBlock::iterator RestoreMI, MachineBasicBlock::iterator AddMI, - const TargetInstrInfo *TII) -{ + const TargetInstrInfo *TII) { // Before: add <op0>, <op1>, %i[0-7] // restore %g0, %g0, %i[0-7] // // After : restore <op0>, <op1>, %o[0-7] + const TargetRegisterInfo *TRI = &TII->getRegisterInfo(); Register reg = AddMI->getOperand(0).getReg(); if (reg < SP::I0 || reg > SP::I7) return false; + // Check whether it uses %o7 as its source and the corresponding branch + // instruction is a call. + MachineBasicBlock::iterator LastInst = MBB.getFirstTerminator(); + bool IsCall = LastInst != MBB.end() && LastInst->isCall(); + + if (IsCall && AddMI->getOpcode() == SP::ADDrr && + AddMI->readsRegister(SP::O7, TRI)) + return false; + + if (IsCall && AddMI->getOpcode() == SP::ADDri && + AddMI->readsRegister(SP::O7, TRI)) + return false; + // Erase RESTORE. RestoreMI->eraseFromParent(); @@ -417,16 +436,17 @@ static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI, return true; } -static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI, +static bool combineRestoreOR(MachineBasicBlock &MBB, + MachineBasicBlock::iterator RestoreMI, MachineBasicBlock::iterator OrMI, - const TargetInstrInfo *TII) -{ + const TargetInstrInfo *TII) { // Before: or <op0>, <op1>, %i[0-7] // restore %g0, %g0, %i[0-7] // and <op0> or <op1> is zero, // // After : restore <op0>, <op1>, %o[0-7] + const TargetRegisterInfo *TRI = &TII->getRegisterInfo(); Register reg = OrMI->getOperand(0).getReg(); if (reg < SP::I0 || reg > SP::I7) return false; @@ -442,6 +462,15 @@ static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI, && (!OrMI->getOperand(2).isImm() || OrMI->getOperand(2).getImm() != 0)) return false; + // Check whether it uses %o7 as its source and the corresponding branch + // instruction is a call. + MachineBasicBlock::iterator LastInst = MBB.getFirstTerminator(); + bool IsCall = LastInst != MBB.end() && LastInst->isCall(); + + if (IsCall && OrMI->getOpcode() == SP::ORrr && + OrMI->readsRegister(SP::O7, TRI)) + return false; + // Erase RESTORE. RestoreMI->eraseFromParent(); @@ -520,9 +549,11 @@ bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB, switch (PrevInst->getOpcode()) { default: break; case SP::ADDrr: - case SP::ADDri: return combineRestoreADD(MBBI, PrevInst, TII); break; + case SP::ADDri: + return combineRestoreADD(MBB, MBBI, PrevInst, TII); case SP::ORrr: - case SP::ORri: return combineRestoreOR(MBBI, PrevInst, TII); break; + case SP::ORri: + return combineRestoreOR(MBB, MBBI, PrevInst, TII); case SP::SETHIi: return combineRestoreSETHIi(MBBI, PrevInst, TII); break; } // It cannot combine with the previous instruction. diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td index 65d37599e6a8e..8717b9347210c 100644 --- a/llvm/lib/Target/Sparc/SparcInstrInfo.td +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -1095,7 +1095,7 @@ def CPBCONDA : CPBranchSPA<(ins brtarget:$imm22, CCOp:$cond), // Section B.24 - Call and Link Instruction, p. 125 // This is the only Format 1 instruction -let Uses = [O6], +let Uses = [O6], Defs = [O7], hasDelaySlot = 1, isCall = 1 in { def CALL : InstSP<(outs), (ins calltarget:$disp, variable_ops), "call $disp", @@ -1589,8 +1589,8 @@ let Uses = [O6], isCall = 1, hasDelaySlot = 1 in //===----------------------------------------------------------------------===// // Instructions for tail calls. //===----------------------------------------------------------------------===// -let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, - isTerminator = 1, isBarrier = 1 in { +let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, isTerminator = 1, + isBarrier = 1, isCall = 1 in { def TAIL_CALL : InstSP<(outs), (ins calltarget:$disp, variable_ops), "call $disp", [(tailcall tglobaladdr:$disp)]> { @@ -1603,8 +1603,8 @@ let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, def : Pat<(tailcall (iPTR texternalsym:$dst)), (TAIL_CALL texternalsym:$dst)>; -let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, isTerminator = 1, - isBarrier = 1, rd = 0 in { +let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, isTerminator = 1, + isBarrier = 1, isCall = 1, rd = 0 in { def TAIL_CALLri : F3_2<2, 0b111000, (outs), (ins (MEMri $rs1, $simm13):$addr, variable_ops), "jmp $addr", diff --git a/llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll b/llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll index 4a15e35e718fd..9863e9f743540 100644 --- a/llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll +++ b/llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll @@ -246,10 +246,100 @@ entry: %1 = add nsw i32 %i0, 3 tail call void asm sideeffect "", "r,r,~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o6},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7}"(i32 %0, i32 %1) %2 = add nsw i32 %0, %1 + %3 = call i32 @bar(i32 %2) + ret i32 %3 +} + +define i32 @prevent_o7_in_restore_add_in_call_delay_slot(i32 %i0) nounwind { +; CHECK-LABEL: prevent_o7_in_restore_add_in_call_delay_slot: +; CHECK: ! %bb.0: ! %entry +; CHECK-NEXT: save %sp, -96, %sp +; CHECK-NEXT: add %i0, 2, %o5 +; CHECK-NEXT: add %i0, 3, %o7 +; CHECK-NEXT: !APP +; CHECK-NEXT: !NO_APP +; CHECK-NEXT: add %o5, %o7, %i0 +; CHECK-NEXT: call bar +; CHECK-NEXT: restore +; +; UNOPT-LABEL: prevent_o7_in_restore_add_in_call_delay_slot: +; UNOPT: ! %bb.0: ! %entry +; UNOPT-NEXT: save %sp, -104, %sp +; UNOPT-NEXT: add %i0, 2, %o5 +; UNOPT-NEXT: st %o5, [%fp+-4] ! 4-byte Folded Spill +; UNOPT-NEXT: add %i0, 3, %o7 +; UNOPT-NEXT: st %o7, [%fp+-8] ! 4-byte Folded Spill +; UNOPT-NEXT: !APP +; UNOPT-NEXT: !NO_APP +; UNOPT-NEXT: ld [%fp+-8], %i1 ! 4-byte Folded Reload +; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload +; UNOPT-NEXT: call bar +; UNOPT-NEXT: restore %i0, %i1, %o0 +entry: + %0 = add nsw i32 %i0, 2 + %1 = add nsw i32 %i0, 3 + tail call void asm sideeffect "", "r,r,~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o6},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7}"(i32 %0, i32 %1) + %2 = add nsw i32 %0, %1 + %3 = tail call i32 @bar(i32 %2) + ret i32 %3 +} + +define i32 @prevent_o7_in_restore_add_ri_in_call_delay_slot(i32 %i0, i32 %i1) nounwind { +; CHECK-LABEL: prevent_o7_in_restore_add_ri_in_call_delay_slot: +; CHECK: ! %bb.0: ! %entry +; CHECK-NEXT: save %sp, -96, %sp +; CHECK-NEXT: add %i0, %i1, %o7 +; CHECK-NEXT: !APP +; CHECK-NEXT: !NO_APP +; CHECK-NEXT: add %o7, 1, %i0 +; CHECK-NEXT: call bar +; CHECK-NEXT: restore +; +; UNOPT-LABEL: prevent_o7_in_restore_add_ri_in_call_delay_slot: +; UNOPT: ! %bb.0: ! %entry +; UNOPT-NEXT: save %sp, -96, %sp +; UNOPT-NEXT: add %i0, %i1, %o7 +; UNOPT-NEXT: st %o7, [%fp+-4] ! 4-byte Folded Spill +; UNOPT-NEXT: !APP +; UNOPT-NEXT: !NO_APP +; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload +; UNOPT-NEXT: call bar +; UNOPT-NEXT: restore %i0, 1, %o0 +entry: + %0 = add nsw i32 %i0, %i1 + tail call void asm sideeffect "", "r,~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7}"(i32 %0) + %2 = add nsw i32 %0, 1 %3 = tail call i32 @bar(i32 %2) ret i32 %3 } +define i32 @prevent_o7_in_restore_or_in_call_delay_slot(i32 %i0) nounwind { +; CHECK-LABEL: prevent_o7_in_restore_or_in_call_delay_slot: +; CHECK: ! %bb.0: ! %entry +; CHECK-NEXT: save %sp, -96, %sp +; CHECK-NEXT: add %i0, 2, %o7 +; CHECK-NEXT: !APP +; CHECK-NEXT: !NO_APP +; CHECK-NEXT: mov %o7, %i0 +; CHECK-NEXT: call bar +; CHECK-NEXT: restore +; +; UNOPT-LABEL: prevent_o7_in_restore_or_in_call_delay_slot: +; UNOPT: ! %bb.0: ! %entry +; UNOPT-NEXT: save %sp, -96, %sp +; UNOPT-NEXT: add %i0, 2, %o7 +; UNOPT-NEXT: st %o7, [%fp+-4] ! 4-byte Folded Spill +; UNOPT-NEXT: !APP +; UNOPT-NEXT: !NO_APP +; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload +; UNOPT-NEXT: call bar +; UNOPT-NEXT: restore +entry: + %0 = add nsw i32 %i0, 2 + tail call void asm sideeffect "", "r,~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7}"(i32 %0) + %1 = tail call i32 @bar(i32 %0) + ret i32 %1 +} declare i32 @func(ptr) @@ -379,12 +469,12 @@ define i32 @restore_sethi(i32 %a) { ; CHECK-NEXT: call bar ; CHECK-NEXT: mov %i0, %o0 ; CHECK-NEXT: cmp %o0, 0 -; CHECK-NEXT: bne .LBB10_2 +; CHECK-NEXT: bne .LBB13_2 ; CHECK-NEXT: nop ; CHECK-NEXT: ! %bb.1: ! %entry ; CHECK-NEXT: ret ; CHECK-NEXT: restore %g0, %g0, %o0 -; CHECK-NEXT: .LBB10_2: +; CHECK-NEXT: .LBB13_2: ; CHECK-NEXT: ret ; CHECK-NEXT: restore %g0, 3072, %o0 ; @@ -401,12 +491,12 @@ define i32 @restore_sethi(i32 %a) { ; UNOPT-NEXT: st %i0, [%fp+-8] ! 4-byte Folded Spill ; UNOPT-NEXT: sethi 3, %i0 ; UNOPT-NEXT: cmp %o0, 0 -; UNOPT-NEXT: bne .LBB10_2 +; UNOPT-NEXT: bne .LBB13_2 ; UNOPT-NEXT: st %i0, [%fp+-4] ; UNOPT-NEXT: ! %bb.1: ! %entry ; UNOPT-NEXT: ld [%fp+-8], %i0 ! 4-byte Folded Reload ; UNOPT-NEXT: st %i0, [%fp+-4] ! 4-byte Folded Spill -; UNOPT-NEXT: .LBB10_2: ! %entry +; UNOPT-NEXT: .LBB13_2: ! %entry ; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload ; UNOPT-NEXT: ret ; UNOPT-NEXT: restore @@ -428,12 +518,12 @@ define i32 @restore_sethi_3bit(i32 %a) { ; CHECK-NEXT: call bar ; CHECK-NEXT: mov %i0, %o0 ; CHECK-NEXT: cmp %o0, 0 -; CHECK-NEXT: bne .LBB11_2 +; CHECK-NEXT: bne .LBB14_2 ; CHECK-NEXT: nop ; CHECK-NEXT: ! %bb.1: ! %entry ; CHECK-NEXT: ret ; CHECK-NEXT: restore %g0, %g0, %o0 -; CHECK-NEXT: .LBB11_2: +; CHECK-NEXT: .LBB14_2: ; CHECK-NEXT: sethi 6, %i0 ; CHECK-NEXT: ret ; CHECK-NEXT: restore @@ -451,12 +541,12 @@ define i32 @restore_sethi_3bit(i32 %a) { ; UNOPT-NEXT: st %i0, [%fp+-8] ! 4-byte Folded Spill ; UNOPT-NEXT: sethi 6, %i0 ; UNOPT-NEXT: cmp %o0, 0 -; UNOPT-NEXT: bne .LBB11_2 +; UNOPT-NEXT: bne .LBB14_2 ; UNOPT-NEXT: st %i0, [%fp+-4] ; UNOPT-NEXT: ! %bb.1: ! %entry ; UNOPT-NEXT: ld [%fp+-8], %i0 ! 4-byte Folded Reload ; UNOPT-NEXT: st %i0, [%fp+-4] ! 4-byte Folded Spill -; UNOPT-NEXT: .LBB11_2: ! %entry +; UNOPT-NEXT: .LBB14_2: ! %entry ; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload ; UNOPT-NEXT: ret ; UNOPT-NEXT: restore @@ -478,12 +568,12 @@ define i32 @restore_sethi_large(i32 %a) { ; CHECK-NEXT: call bar ; CHECK-NEXT: mov %i0, %o0 ; CHECK-NEXT: cmp %o0, 0 -; CHECK-NEXT: bne .LBB12_2 +; CHECK-NEXT: bne .LBB15_2 ; CHECK-NEXT: nop ; CHECK-NEXT: ! %bb.1: ! %entry ; CHECK-NEXT: ret ; CHECK-NEXT: restore %g0, %g0, %o0 -; CHECK-NEXT: .LBB12_2: +; CHECK-NEXT: .LBB15_2: ; CHECK-NEXT: sethi 4000, %i0 ; CHECK-NEXT: ret ; CHECK-NEXT: restore @@ -501,12 +591,12 @@ define i32 @restore_sethi_large(i32 %a) { ; UNOPT-NEXT: st %i0, [%fp+-8] ! 4-byte Folded Spill ; UNOPT-NEXT: sethi 4000, %i0 ; UNOPT-NEXT: cmp %o0, 0 -; UNOPT-NEXT: bne .LBB12_2 +; UNOPT-NEXT: bne .LBB15_2 ; UNOPT-NEXT: st %i0, [%fp+-4] ; UNOPT-NEXT: ! %bb.1: ! %entry ; UNOPT-NEXT: ld [%fp+-8], %i0 ! 4-byte Folded Reload ; UNOPT-NEXT: st %i0, [%fp+-4] ! 4-byte Folded Spill -; UNOPT-NEXT: .LBB12_2: ! %entry +; UNOPT-NEXT: .LBB15_2: ! %entry ; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload ; UNOPT-NEXT: ret ; UNOPT-NEXT: restore @@ -525,14 +615,14 @@ define i32 @test_generic_inst(i32 %arg) #0 { ; CHECK-NEXT: mov %i0, %o0 ; CHECK-NEXT: andcc %o0, 1, %g0 ; CHECK-NEXT: ! fake_use: $i0 -; CHECK-NEXT: bne .LBB13_2 +; CHECK-NEXT: bne .LBB16_2 ; CHECK-NEXT: nop ; CHECK-NEXT: ! %bb.1: ! %true ; CHECK-NEXT: call bar ; CHECK-NEXT: nop ; CHECK-NEXT: ret ; CHECK-NEXT: restore %g0, %o0, %o0 -; CHECK-NEXT: .LBB13_2: ! %false +; CHECK-NEXT: .LBB16_2: ! %false ; CHECK-NEXT: ret ; CHECK-NEXT: restore %o0, 1, %o0 ; @@ -547,21 +637,21 @@ define i32 @test_generic_inst(i32 %arg) #0 { ; UNOPT-NEXT: and %o0, 1, %i0 ; UNOPT-NEXT: ! fake_use: $i1 ; UNOPT-NEXT: cmp %i0, 0 -; UNOPT-NEXT: bne .LBB13_2 +; UNOPT-NEXT: bne .LBB16_2 ; UNOPT-NEXT: nop -; UNOPT-NEXT: ba .LBB13_1 +; UNOPT-NEXT: ba .LBB16_1 ; UNOPT-NEXT: nop -; UNOPT-NEXT: .LBB13_1: ! %true +; UNOPT-NEXT: .LBB16_1: ! %true ; UNOPT-NEXT: call bar ; UNOPT-NEXT: ld [%fp+-4], %o0 -; UNOPT-NEXT: ba .LBB13_3 +; UNOPT-NEXT: ba .LBB16_3 ; UNOPT-NEXT: st %o0, [%fp+-8] -; UNOPT-NEXT: .LBB13_2: ! %false +; UNOPT-NEXT: .LBB16_2: ! %false ; UNOPT-NEXT: ld [%fp+-4], %i0 ! 4-byte Folded Reload ; UNOPT-NEXT: add %i0, 1, %i0 -; UNOPT-NEXT: ba .LBB13_3 +; UNOPT-NEXT: ba .LBB16_3 ; UNOPT-NEXT: st %i0, [%fp+-8] -; UNOPT-NEXT: .LBB13_3: ! %cont +; UNOPT-NEXT: .LBB16_3: ! %cont ; UNOPT-NEXT: ld [%fp+-8], %i0 ! 4-byte Folded Reload ; UNOPT-NEXT: ret ; UNOPT-NEXT: restore _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
