-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[SPARC] Prevent RESTORE from sourcing from %o7 in call delay slots #172593
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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`.
|
@llvm/pr-subscribers-backend-sparc Author: Koakuma (koachan) ChangesCombining 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 Patch is 25.74 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/172593.diff 3 Files Affected:
diff --git a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
index 024030d196ee3..c8caf7dffad2a 100644
--- a/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
+++ b/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
@@ -390,10 +390,10 @@ 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]
//
@@ -403,6 +403,21 @@ static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI,
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();
+
+ // Check whether it uses %o7 as its source.
+ if (IsCall && AddMI->getOpcode() == SP::ADDrr &&
+ (AddMI->getOperand(1).getReg() == SP::O7 ||
+ AddMI->getOperand(2).getReg() == SP::O7))
+ return false;
+
+ if (IsCall && AddMI->getOpcode() == SP::ADDri &&
+ AddMI->getOperand(1).getReg() == SP::O7)
+ return false;
+
// Erase RESTORE.
RestoreMI->eraseFromParent();
@@ -417,10 +432,10 @@ 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,
@@ -442,6 +457,20 @@ 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->getOperand(1).getReg() == SP::O7 ||
+ OrMI->getOperand(2).getReg() == SP::O7))
+ return false;
+
+ if (IsCall && OrMI->getOpcode() == SP::ORrr &&
+ OrMI->getOperand(1).getReg() == SP::O7)
+ return false;
+
// Erase RESTORE.
RestoreMI->eraseFromParent();
@@ -520,9 +549,13 @@ 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);
+ break;
case SP::ORrr:
- case SP::ORri: return combineRestoreOR(MBBI, PrevInst, TII); break;
+ case SP::ORri:
+ return combineRestoreOR(MBB, MBBI, PrevInst, TII);
+ break;
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 107817fcab6df..c08599402daa8 100644
--- a/llvm/lib/Target/Sparc/SparcInstrInfo.td
+++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td
@@ -1589,7 +1589,7 @@ let Uses = [O6], isCall = 1, hasDelaySlot = 1 in
// Instructions for tail calls.
//===----------------------------------------------------------------------===//
let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1,
- isTerminator = 1, isBarrier = 1 in {
+ isTerminator = 1, isBarrier = 1, isCall = 1 in {
def TAIL_CALL : InstSP<(outs), (ins calltarget:$disp, variable_ops),
"call $disp",
[(tailcall tglobaladdr:$disp)]> {
@@ -1603,7 +1603,7 @@ def : Pat<(tailcall (iPTR texternalsym:$dst)),
(TAIL_CALL texternalsym:$dst)>;
let isCodeGenOnly = 1, isReturn = 1, hasDelaySlot = 1, isTerminator = 1,
- isBarrier = 1, rd = 0 in {
+ 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 767ef7eb510e6..518020bc9ca3a 100644
--- a/llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
+++ b/llvm/test/CodeGen/SPARC/2011-01-19-DelaySlot.ll
@@ -1,32 +1,110 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
;RUN: llc -mtriple=sparc < %s -verify-machineinstrs | FileCheck %s
;RUN: llc -mtriple=sparc -O0 < %s -verify-machineinstrs | FileCheck %s -check-prefix=UNOPT
target triple = "sparc-unknown-linux-gnu"
define i32 @test(i32 %a) #0 {
+; CHECK-LABEL: test:
+; CHECK: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: call bar
+; CHECK-NEXT: mov %i0, %o0
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %g0, %o0, %o0
+;
+; UNOPT-LABEL: test:
+; UNOPT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -96, %sp
+; UNOPT-NEXT: call bar
+; UNOPT-NEXT: mov %i0, %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %g0, %o0, %o0
entry:
-; CHECK: test
-; CHECK: call bar
-; CHECK-NOT: nop
-; CHECK: ret
-; CHECK-NEXT: restore
%0 = tail call i32 @bar(i32 %a) nounwind
ret i32 %0
}
define i32 @test_jmpl(ptr nocapture %f, i32 %a, i32 %b) #0 {
+; CHECK-LABEL: test_jmpl:
+; CHECK: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: mov %i2, %o1
+; CHECK-NEXT: call %i0
+; CHECK-NEXT: mov %i1, %o0
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %g0, %o0, %o0
+;
+; UNOPT-LABEL: test_jmpl:
+; UNOPT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -96, %sp
+; UNOPT-NEXT: mov %i2, %o1
+; UNOPT-NEXT: call %i0
+; UNOPT-NEXT: mov %i1, %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %g0, %o0, %o0
entry:
-; CHECK: test_jmpl
-; CHECK: call
-; CHECK-NOT: nop
-; CHECK: ret
-; CHECK-NEXT: restore
%0 = tail call i32 %f(i32 %a, i32 %b) nounwind
ret i32 %0
}
define i32 @test_loop(i32 %a, i32 %b) nounwind readnone {
-; CHECK: test_loop
+; CHECK-LABEL: test_loop:
+; CHECK: ! %bb.0: ! %entry
+; CHECK-NEXT: cmp %o1, 1
+; CHECK-NEXT: bl .LBB2_3
+; CHECK-NEXT: nop
+; CHECK-NEXT: ! %bb.1: ! %bb.preheader
+; CHECK-NEXT: mov %g0, %o2
+; CHECK-NEXT: mov %g0, %o3
+; CHECK-NEXT: mov 1, %o4
+; CHECK-NEXT: .LBB2_2: ! %bb
+; CHECK-NEXT: ! =>This Inner Loop Header: Depth=1
+; CHECK-NEXT: andn %o4, %o3, %o5
+; CHECK-NEXT: sll %o2, %o5, %o5
+; CHECK-NEXT: add %o5, %o0, %o0
+; CHECK-NEXT: add %o3, 1, %o3
+; CHECK-NEXT: cmp %o1, %o3
+; CHECK-NEXT: bne .LBB2_2
+; CHECK-NEXT: add %o2, %o1, %o2
+; CHECK-NEXT: .LBB2_3: ! %bb5
+; CHECK-NEXT: retl
+; CHECK-NEXT: nop
+;
+; UNOPT-LABEL: test_loop:
+; UNOPT: ! %bb.0: ! %entry
+; UNOPT-NEXT: add %sp, -104, %sp
+; UNOPT-NEXT: mov %o1, %o2
+; UNOPT-NEXT: st %o2, [%sp+92] ! 4-byte Folded Spill
+; UNOPT-NEXT: mov %o0, %o1
+; UNOPT-NEXT: mov %g0, %o0
+; UNOPT-NEXT: cmp %o2, 1
+; UNOPT-NEXT: st %o1, [%sp+96] ! 4-byte Folded Spill
+; UNOPT-NEXT: bl .LBB2_2
+; UNOPT-NEXT: st %o0, [%sp+100]
+; UNOPT-NEXT: ba .LBB2_1
+; UNOPT-NEXT: nop
+; UNOPT-NEXT: .LBB2_1: ! %bb
+; UNOPT-NEXT: ! =>This Inner Loop Header: Depth=1
+; UNOPT-NEXT: ld [%sp+100], %o0 ! 4-byte Folded Reload
+; UNOPT-NEXT: ld [%sp+96], %o3 ! 4-byte Folded Reload
+; UNOPT-NEXT: ld [%sp+92], %o2 ! 4-byte Folded Reload
+; UNOPT-NEXT: smul %o0, %o2, %o1
+; UNOPT-NEXT: mov 1, %o4
+; UNOPT-NEXT: andn %o4, %o0, %o4
+; UNOPT-NEXT: sll %o1, %o4, %o1
+; UNOPT-NEXT: add %o1, %o3, %o1
+; UNOPT-NEXT: add %o0, 1, %o0
+; UNOPT-NEXT: cmp %o0, %o2
+; UNOPT-NEXT: st %o1, [%sp+96] ! 4-byte Folded Spill
+; UNOPT-NEXT: bne .LBB2_1
+; UNOPT-NEXT: st %o0, [%sp+100]
+; UNOPT-NEXT: ba .LBB2_2
+; UNOPT-NEXT: nop
+; UNOPT-NEXT: .LBB2_2: ! %bb5
+; UNOPT-NEXT: ld [%sp+96], %o0 ! 4-byte Folded Reload
+; UNOPT-NEXT: retl
+; UNOPT-NEXT: add %sp, 104, %sp
entry:
%0 = icmp sgt i32 %b, 0
br i1 %0, label %bb, label %bb5
@@ -41,26 +119,59 @@ bb: ; preds = %entry, %bb
%a_addr.0 = add i32 %.pn, %a_addr.18
%3 = add nsw i32 %1, 1
%exitcond = icmp eq i32 %3, %b
-;CHECK: cmp
-;CHECK: bne
-;CHECK-NOT: nop
br i1 %exitcond, label %bb5, label %bb
bb5: ; preds = %bb, %entry
%a_addr.1.lcssa = phi i32 [ %a, %entry ], [ %a_addr.0, %bb ]
-;CHECK: retl
-;CHECK-NOT: restore
ret i32 %a_addr.1.lcssa
}
define i32 @test_inlineasm(i32 %a) #0 {
+; CHECK-LABEL: test_inlineasm:
+; CHECK: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: mov %i0, %o0
+; CHECK-NEXT: cmp %i0, -1
+; CHECK-NEXT: !APP
+; CHECK-NEXT: sethi 0, %g0
+; CHECK-NEXT: !NO_APP
+; CHECK-NEXT: ble .LBB3_2
+; CHECK-NEXT: nop
+; CHECK-NEXT: ! %bb.1: ! %bb1
+; CHECK-NEXT: call bar
+; CHECK-NEXT: nop
+; CHECK-NEXT: ba .LBB3_3
+; CHECK-NEXT: nop
+; CHECK-NEXT: .LBB3_2: ! %bb
+; CHECK-NEXT: call foo
+; CHECK-NEXT: nop
+; CHECK-NEXT: .LBB3_3: ! %bb
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %g0, %o0, %o0
+;
+; UNOPT-LABEL: test_inlineasm:
+; UNOPT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -96, %sp
+; UNOPT-NEXT: st %i0, [%fp+-4] ! 4-byte Folded Spill
+; UNOPT-NEXT: !APP
+; UNOPT-NEXT: sethi 0, %g0
+; UNOPT-NEXT: !NO_APP
+; UNOPT-NEXT: cmp %i0, -1
+; UNOPT-NEXT: bg .LBB3_2
+; UNOPT-NEXT: nop
+; UNOPT-NEXT: ba .LBB3_1
+; UNOPT-NEXT: nop
+; UNOPT-NEXT: .LBB3_1: ! %bb
+; UNOPT-NEXT: call foo
+; UNOPT-NEXT: ld [%fp+-4], %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %g0, %o0, %o0
+; UNOPT-NEXT: .LBB3_2: ! %bb1
+; UNOPT-NEXT: call bar
+; UNOPT-NEXT: ld [%fp+-4], %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %g0, %o0, %o0
entry:
-;CHECK-LABEL: test_inlineasm:
-;CHECK: cmp
-;CHECK: sethi
-;CHECK: !NO_APP
-;CHECK-NEXT: ble
-;CHECK-NEXT: nop
tail call void asm sideeffect "sethi 0, %g0", ""() nounwind
%0 = icmp slt i32 %a, 0
br i1 %0, label %bb, label %bb1
@@ -80,22 +191,57 @@ declare i32 @bar(i32)
define i32 @test_implicit_def() #0 {
+; CHECK-LABEL: test_implicit_def:
+; CHECK: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: call func
+; CHECK-NEXT: nop
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %g0, %g0, %o0
+;
+; UNOPT-LABEL: test_implicit_def:
+; UNOPT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -96, %sp
+; UNOPT-NEXT: ! implicit-def: $o0
+; UNOPT-NEXT: call func
+; UNOPT-NEXT: nop
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %g0, %g0, %o0
entry:
-;UNOPT-LABEL: test_implicit_def:
-;UNOPT: call func
-;UNOPT-NEXT: nop
%0 = tail call i32 @func(ptr undef) nounwind
ret i32 0
}
define i32 @prevent_o7_in_call_delay_slot(i32 %i0) #0 {
+; CHECK-LABEL: prevent_o7_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, %o0
+; CHECK-NEXT: call bar
+; CHECK-NEXT: nop
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %g0, %o0, %o0
+;
+; UNOPT-LABEL: prevent_o7_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: add %i0, %i1, %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %g0, %o0, %o0
entry:
-;CHECK-LABEL: prevent_o7_in_call_delay_slot:
-;CHECK: add %i0, 2, %o5
-;CHECK: add %i0, 3, %o7
-;CHECK: add %o5, %o7, %o0
-;CHECK: call bar
-;CHECK-NEXT: nop
%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)
@@ -104,46 +250,187 @@ entry:
ret i32 %3
}
+define i32 @prevent_o7_in_restore_add_in_call_delay_slot(i32 %i0) #0 {
+; 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: mov %i0, %o0
+; CHECK-NEXT: ret
+; 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: add %i0, %i1, %i0
+; UNOPT-NEXT: call bar
+; UNOPT-NEXT: mov %i0, %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore
+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 %2
+}
+
+define i32 @prevent_o7_in_restore_or_in_call_delay_slot(i32 %i0) #0 {
+; 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, %o0
+; CHECK-NEXT: call bar
+; CHECK-NEXT: nop
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %g0, %o0, %o0
+;
+; 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: call bar
+; UNOPT-NEXT: ld [%fp+-4], %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %g0, %o0, %o0
+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)
define i32 @restore_add(i32 %a, i32 %b) {
+; CHECK-LABEL: restore_add:
+; CHECK: .cfi_startproc
+; CHECK-NEXT: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: .cfi_def_cfa_register %fp
+; CHECK-NEXT: .cfi_window_save
+; CHECK-NEXT: .cfi_register %o7, %i7
+; CHECK-NEXT: call bar
+; CHECK-NEXT: mov %i0, %o0
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %o0, %i1, %o0
+;
+; UNOPT-LABEL: restore_add:
+; UNOPT: .cfi_startproc
+; UNOPT-NEXT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -96, %sp
+; UNOPT-NEXT: .cfi_def_cfa_register %fp
+; UNOPT-NEXT: .cfi_window_save
+; UNOPT-NEXT: .cfi_register %o7, %i7
+; UNOPT-NEXT: call bar
+; UNOPT-NEXT: mov %i0, %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %o0, %i1, %o0
entry:
-;CHECK-LABEL: restore_add:
-;CHECK: ret
-;CHECK: restore %o0, %i1, %o0
%0 = tail call i32 @bar(i32 %a) nounwind
%1 = add nsw i32 %0, %b
ret i32 %1
}
define i32 @restore_add_imm(i32 %a) {
+; CHECK-LABEL: restore_add_imm:
+; CHECK: .cfi_startproc
+; CHECK-NEXT: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: .cfi_def_cfa_register %fp
+; CHECK-NEXT: .cfi_window_save
+; CHECK-NEXT: .cfi_register %o7, %i7
+; CHECK-NEXT: call bar
+; CHECK-NEXT: mov %i0, %o0
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %o0, 20, %o0
+;
+; UNOPT-LABEL: restore_add_imm:
+; UNOPT: .cfi_startproc
+; UNOPT-NEXT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -96, %sp
+; UNOPT-NEXT: .cfi_def_cfa_register %fp
+; UNOPT-NEXT: .cfi_window_save
+; UNOPT-NEXT: .cfi_register %o7, %i7
+; UNOPT-NEXT: call bar
+; UNOPT-NEXT: mov %i0, %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %o0, 20, %o0
entry:
-;CHECK-LABEL: restore_add_imm:
-;CHECK: ret
-;CHECK: restore %o0, 20, %o0
%0 = tail call i32 @bar(i32 %a) nounwind
%1 = add nsw i32 %0, 20
ret i32 %1
}
define i32 @restore_or(i32 %a) #0 {
+; CHECK-LABEL: restore_or:
+; CHECK: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: call bar
+; CHECK-NEXT: mov %i0, %o0
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %g0, %o0, %o0
+;
+; UNOPT-LABEL: restore_or:
+; UNOPT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -96, %sp
+; UNOPT-NEXT: call bar
+; UNOPT-NEXT: mov %i0, %o0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore %g0, %o0, %o0
entry:
-;CHECK-LABEL: restore_or:
-;CHECK: ret
-;CHECK: restore %g0, %o0, %o0
%0 = tail call i32 @bar(i32 %a) nounwind
ret i32 %0
}
define i32 @restore_or_imm(i32 %a) {
+; CHECK-LABEL: restore_or_imm:
+; CHECK: .cfi_startproc
+; CHECK-NEXT: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: .cfi_def_cfa_register %fp
+; CHECK-NEXT: .cfi_window_save
+; CHECK-NEXT: .cfi_register %o7, %i7
+; CHECK-NEXT: call bar
+; CHECK-NEXT: mov %i0, %o0
+; CHECK-NEXT: or %o0, 20, %i0
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore
+;
+; UNOPT-LABEL: restore_or_imm:
+; UNOPT: .cfi_startproc
+; UNOPT-NEXT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -96, %sp
+; UNOPT-NEXT: .cfi_def_cfa_register %fp
+; UNOPT-NEXT: .cfi_window_save
+; UNOPT-NEXT: .cfi_register %o7, %i7
+; UNOPT-NEXT: call bar
+; UNOPT-NEXT: mov %i0, %o0
+; UNOPT-NEXT: or %o0, 20, %i0
+; UNOPT-NEXT: ret
+; UNOPT-NEXT: restore
entry:
-;CHECK-LABEL: restore_or_imm:
-;CHECK: or %o0, 20, %i0
-;CHECK: ret
-;CHECK-NOT: restore %g0, %g0, %g0
-;CHECK: restore
%0 = tail call i32 @bar(i32 %a) nounwind
%1 = or i32 %0, 20
ret i32 %1
@@ -151,10 +438,48 @@ entry:
define i32 @restore_sethi(i32 %a) {
+; CHECK-LABEL: restore_sethi:
+; CHECK: .cfi_startproc
+; CHECK-NEXT: ! %bb.0: ! %entry
+; CHECK-NEXT: save %sp, -96, %sp
+; CHECK-NEXT: .cfi_def_cfa_register %fp
+; CHECK-NEXT: .cfi_window_save
+; CHECK-NEXT: .cfi_register %o7, %i7
+; CHECK-NEXT: call bar
+; CHECK-NEXT: mov %i0, %o0
+; CHECK-NEXT: cmp %o0, 0
+; CHECK-NEXT: bne .LBB12_2
+; CHECK-NEXT: nop
+; CHECK-NEXT: ! %bb.1: ! %entry
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %g0, %g0, %o0
+; CHECK-NEXT: .LBB12_2:
+; CHECK-NEXT: ret
+; CHECK-NEXT: restore %g0, 3072, %o0
+;
+; UNOPT-LABEL: restore_sethi:
+; UNOPT: .cfi_startproc
+; UNOPT-NEXT: ! %bb.0: ! %entry
+; UNOPT-NEXT: save %sp, -104, %sp
+; UNOPT-NEXT: .cfi_def_cfa_register %fp
+; UNOPT-NEXT: .cfi_window_save
+; UNOPT-NEXT: .cfi_register %o7, %i7
+; UNOPT-NEXT: call bar
+; UNOPT-NEXT: mov %i0, %o0
+; UNOPT-NEXT: mov %g0, %i0
+; UNOPT-NEXT: ...
[truncated]
|
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
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.