Skip to content
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

[SystemZ] Handle address clobbering in splitMove(). #92105

Merged
merged 1 commit into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 39 additions & 26 deletions llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,49 +70,62 @@ void SystemZInstrInfo::splitMove(MachineBasicBlock::iterator MI,
MachineBasicBlock *MBB = MI->getParent();
MachineFunction &MF = *MBB->getParent();

// Get two load or store instructions. Use the original instruction for one
// of them (arbitrarily the second here) and create a clone for the other.
MachineInstr *EarlierMI = MF.CloneMachineInstr(&*MI);
MBB->insert(MI, EarlierMI);
// Get two load or store instructions. Use the original instruction for
// one of them and create a clone for the other.
MachineInstr *HighPartMI = MF.CloneMachineInstr(&*MI);
MachineInstr *LowPartMI = &*MI;
MBB->insert(LowPartMI, HighPartMI);

// Set up the two 64-bit registers and remember super reg and its flags.
MachineOperand &HighRegOp = EarlierMI->getOperand(0);
MachineOperand &LowRegOp = MI->getOperand(0);
MachineOperand &HighRegOp = HighPartMI->getOperand(0);
MachineOperand &LowRegOp = LowPartMI->getOperand(0);
Register Reg128 = LowRegOp.getReg();
unsigned Reg128Killed = getKillRegState(LowRegOp.isKill());
unsigned Reg128Undef = getUndefRegState(LowRegOp.isUndef());
HighRegOp.setReg(RI.getSubReg(HighRegOp.getReg(), SystemZ::subreg_h64));
LowRegOp.setReg(RI.getSubReg(LowRegOp.getReg(), SystemZ::subreg_l64));

if (MI->mayStore()) {
// Add implicit uses of the super register in case one of the subregs is
// undefined. We could track liveness and skip storing an undefined
// subreg, but this is hopefully rare (discovered with llvm-stress).
// If Reg128 was killed, set kill flag on MI.
unsigned Reg128UndefImpl = (Reg128Undef | RegState::Implicit);
MachineInstrBuilder(MF, EarlierMI).addReg(Reg128, Reg128UndefImpl);
MachineInstrBuilder(MF, MI).addReg(Reg128, (Reg128UndefImpl | Reg128Killed));
}

// The address in the first (high) instruction is already correct.
// Adjust the offset in the second (low) instruction.
MachineOperand &HighOffsetOp = EarlierMI->getOperand(2);
MachineOperand &LowOffsetOp = MI->getOperand(2);
MachineOperand &HighOffsetOp = HighPartMI->getOperand(2);
MachineOperand &LowOffsetOp = LowPartMI->getOperand(2);
LowOffsetOp.setImm(LowOffsetOp.getImm() + 8);

// Clear the kill flags on the registers in the first instruction.
if (EarlierMI->getOperand(0).isReg() && EarlierMI->getOperand(0).isUse())
EarlierMI->getOperand(0).setIsKill(false);
EarlierMI->getOperand(1).setIsKill(false);
EarlierMI->getOperand(3).setIsKill(false);

// Set the opcodes.
unsigned HighOpcode = getOpcodeForOffset(NewOpcode, HighOffsetOp.getImm());
unsigned LowOpcode = getOpcodeForOffset(NewOpcode, LowOffsetOp.getImm());
assert(HighOpcode && LowOpcode && "Both offsets should be in range");
HighPartMI->setDesc(get(HighOpcode));
LowPartMI->setDesc(get(LowOpcode));

MachineInstr *FirstMI = HighPartMI;
if (MI->mayStore()) {
FirstMI->getOperand(0).setIsKill(false);
// Add implicit uses of the super register in case one of the subregs is
// undefined. We could track liveness and skip storing an undefined
// subreg, but this is hopefully rare (discovered with llvm-stress).
// If Reg128 was killed, set kill flag on MI.
unsigned Reg128UndefImpl = (Reg128Undef | RegState::Implicit);
MachineInstrBuilder(MF, HighPartMI).addReg(Reg128, Reg128UndefImpl);
MachineInstrBuilder(MF, LowPartMI).addReg(Reg128, (Reg128UndefImpl | Reg128Killed));
} else {
// If HighPartMI clobbers any of the address registers, it needs to come
// after LowPartMI.
auto overlapsAddressReg = [&](Register Reg) -> bool {
return RI.regsOverlap(Reg, MI->getOperand(1).getReg()) ||
RI.regsOverlap(Reg, MI->getOperand(3).getReg());
};
if (overlapsAddressReg(HighRegOp.getReg())) {
assert(!overlapsAddressReg(LowRegOp.getReg()) &&
"Both loads clobber address!");
MBB->splice(HighPartMI, MBB, LowPartMI);
FirstMI = LowPartMI;
}
}

EarlierMI->setDesc(get(HighOpcode));
MI->setDesc(get(LowOpcode));
// Clear the kill flags on the address registers in the first instruction.
FirstMI->getOperand(1).setIsKill(false);
FirstMI->getOperand(3).setIsKill(false);
}

// Split ADJDYNALLOC instruction MI.
Expand Down
26 changes: 26 additions & 0 deletions llvm/test/CodeGen/SystemZ/splitMove_addressReg.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# RUN: llc -mtriple=s390x-linux-gnu -run-pass=postrapseudos \
# RUN: %s -o - -verify-machineinstrs | FileCheck %s
#
# Test that a L128 reload do not overwrite an address register prematurely
# after being split into two LGs.

--- |
target triple = "s390x-unknown-unknown"

define void @fun() {
ret void
}

...

# CHECK: name: fun

---
name: 'fun'
body: |
bb.0:
liveins: $r4d, $r15d
$r4q = L128 $r15d, 14920, killed $r4d
Return

...
Loading