Skip to content

Commit ae4d39c

Browse files
committed
[SystemZ] Copy Access registers and CC with the correct register class.
On SystemZ there are a set of "access registers" that can be copied in and out of 32-bit GPRs with special instructions. These instructions can only perform the copy using low 32-bit parts of the 64-bit GPRs. However, the default register class for 32-bit integers is GRX32, which also contains the high 32-bit part registers. In order to never end up with a case of such a COPY into a high reg, this patch adds a new simple pre-RA pass that selects such COPYs into target instructions. This pass also handles COPYs from CC (Condition Code register), and COPYs to CC can now also be emitted from a high reg in copyPhysReg(). Fixes: https://bugs.llvm.org/show_bug.cgi?id=44254 Review: Ulrich Weigand. Differential Revision: https://reviews.llvm.org/D75014
1 parent 573e077 commit ae4d39c

File tree

9 files changed

+234
-17
lines changed

9 files changed

+234
-17
lines changed

llvm/lib/Target/SystemZ/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_llvm_target(SystemZCodeGen
1616
SystemZAsmPrinter.cpp
1717
SystemZCallingConv.cpp
1818
SystemZConstantPoolValue.cpp
19+
SystemZCopyPhysRegs.cpp
1920
SystemZElimCompare.cpp
2021
SystemZFrameLowering.cpp
2122
SystemZHazardRecognizer.cpp

llvm/lib/Target/SystemZ/SystemZ.h

+1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ FunctionPass *createSystemZElimComparePass(SystemZTargetMachine &TM);
193193
FunctionPass *createSystemZShortenInstPass(SystemZTargetMachine &TM);
194194
FunctionPass *createSystemZLongBranchPass(SystemZTargetMachine &TM);
195195
FunctionPass *createSystemZLDCleanupPass(SystemZTargetMachine &TM);
196+
FunctionPass *createSystemZCopyPhysRegsPass(SystemZTargetMachine &TM);
196197
FunctionPass *createSystemZPostRewritePass(SystemZTargetMachine &TM);
197198
FunctionPass *createSystemZTDCPass();
198199
} // end namespace llvm
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//===---------- SystemZPhysRegCopy.cpp - Handle phys reg copies -----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This pass makes sure that a COPY of a physical register will be
10+
// implementable after register allocation in copyPhysReg() (this could be
11+
// done in EmitInstrWithCustomInserter() instead if COPY instructions would
12+
// be passed to it).
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#include "SystemZMachineFunctionInfo.h"
17+
#include "SystemZTargetMachine.h"
18+
#include "llvm/CodeGen/MachineDominators.h"
19+
#include "llvm/CodeGen/MachineFunctionPass.h"
20+
#include "llvm/CodeGen/MachineInstrBuilder.h"
21+
#include "llvm/CodeGen/MachineRegisterInfo.h"
22+
#include "llvm/CodeGen/TargetInstrInfo.h"
23+
#include "llvm/CodeGen/TargetRegisterInfo.h"
24+
#include "llvm/Target/TargetMachine.h"
25+
26+
using namespace llvm;
27+
28+
#define SYSTEMZ_COPYPHYSREGS_NAME "SystemZ Copy Physregs"
29+
30+
namespace llvm {
31+
void initializeSystemZCopyPhysRegsPass(PassRegistry&);
32+
}
33+
34+
namespace {
35+
36+
class SystemZCopyPhysRegs : public MachineFunctionPass {
37+
public:
38+
static char ID;
39+
SystemZCopyPhysRegs()
40+
: MachineFunctionPass(ID), TII(nullptr), MRI(nullptr) {
41+
initializeSystemZCopyPhysRegsPass(*PassRegistry::getPassRegistry());
42+
}
43+
44+
StringRef getPassName() const override { return SYSTEMZ_COPYPHYSREGS_NAME; }
45+
46+
bool runOnMachineFunction(MachineFunction &MF) override;
47+
void getAnalysisUsage(AnalysisUsage &AU) const override;
48+
49+
private:
50+
51+
bool visitMBB(MachineBasicBlock &MBB);
52+
53+
const SystemZInstrInfo *TII;
54+
MachineRegisterInfo *MRI;
55+
};
56+
57+
char SystemZCopyPhysRegs::ID = 0;
58+
59+
} // end anonymous namespace
60+
61+
INITIALIZE_PASS(SystemZCopyPhysRegs, "systemz-copy-physregs",
62+
SYSTEMZ_COPYPHYSREGS_NAME, false, false)
63+
64+
FunctionPass *llvm::createSystemZCopyPhysRegsPass(SystemZTargetMachine &TM) {
65+
return new SystemZCopyPhysRegs();
66+
}
67+
68+
void SystemZCopyPhysRegs::getAnalysisUsage(AnalysisUsage &AU) const {
69+
AU.setPreservesCFG();
70+
MachineFunctionPass::getAnalysisUsage(AU);
71+
}
72+
73+
bool SystemZCopyPhysRegs::visitMBB(MachineBasicBlock &MBB) {
74+
bool Modified = false;
75+
76+
// Certain special registers can only be copied from a subset of the
77+
// default register class of the type. It is therefore necessary to create
78+
// the target copy instructions before regalloc instead of in copyPhysReg().
79+
for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
80+
MBBI != E; ) {
81+
MachineInstr *MI = &*MBBI++;
82+
if (!MI->isCopy())
83+
continue;
84+
85+
DebugLoc DL = MI->getDebugLoc();
86+
Register SrcReg = MI->getOperand(1).getReg();
87+
Register DstReg = MI->getOperand(0).getReg();
88+
if (DstReg.isVirtual() &&
89+
(SrcReg == SystemZ::CC || SystemZ::AR32BitRegClass.contains(SrcReg))) {
90+
Register Tmp = MRI->createVirtualRegister(&SystemZ::GR32BitRegClass);
91+
if (SrcReg == SystemZ::CC)
92+
BuildMI(MBB, MI, DL, TII->get(SystemZ::IPM), Tmp);
93+
else
94+
BuildMI(MBB, MI, DL, TII->get(SystemZ::EAR), Tmp).addReg(SrcReg);
95+
MI->getOperand(1).setReg(Tmp);
96+
Modified = true;
97+
}
98+
else if (SrcReg.isVirtual() &&
99+
SystemZ::AR32BitRegClass.contains(DstReg)) {
100+
Register Tmp = MRI->createVirtualRegister(&SystemZ::GR32BitRegClass);
101+
MI->getOperand(0).setReg(Tmp);
102+
BuildMI(MBB, MBBI, DL, TII->get(SystemZ::SAR), DstReg).addReg(Tmp);
103+
Modified = true;
104+
}
105+
}
106+
107+
return Modified;
108+
}
109+
110+
bool SystemZCopyPhysRegs::runOnMachineFunction(MachineFunction &F) {
111+
TII = static_cast<const SystemZInstrInfo *>(F.getSubtarget().getInstrInfo());
112+
MRI = &F.getRegInfo();
113+
114+
bool Modified = false;
115+
for (auto &MBB : F)
116+
Modified |= visitMBB(MBB);
117+
118+
return Modified;
119+
}
120+

llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp

+4-17
Original file line numberDiff line numberDiff line change
@@ -820,18 +820,11 @@ void SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
820820
return;
821821
}
822822

823-
// Move CC value from/to a GR32.
824-
if (SrcReg == SystemZ::CC) {
825-
auto MIB = BuildMI(MBB, MBBI, DL, get(SystemZ::IPM), DestReg);
826-
if (KillSrc) {
827-
const MachineFunction *MF = MBB.getParent();
828-
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
829-
MIB->addRegisterKilled(SrcReg, TRI);
830-
}
831-
return;
832-
}
823+
// Move CC value from a GR32.
833824
if (DestReg == SystemZ::CC) {
834-
BuildMI(MBB, MBBI, DL, get(SystemZ::TMLH))
825+
unsigned Opcode =
826+
SystemZ::GR32BitRegClass.contains(SrcReg) ? SystemZ::TMLH : SystemZ::TMHH;
827+
BuildMI(MBB, MBBI, DL, get(Opcode))
835828
.addReg(SrcReg, getKillRegState(KillSrc))
836829
.addImm(3 << (SystemZ::IPM_CC - 16));
837830
return;
@@ -856,12 +849,6 @@ void SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
856849
Opcode = SystemZ::VLR;
857850
else if (SystemZ::AR32BitRegClass.contains(DestReg, SrcReg))
858851
Opcode = SystemZ::CPYA;
859-
else if (SystemZ::AR32BitRegClass.contains(DestReg) &&
860-
SystemZ::GR32BitRegClass.contains(SrcReg))
861-
Opcode = SystemZ::SAR;
862-
else if (SystemZ::GR32BitRegClass.contains(DestReg) &&
863-
SystemZ::AR32BitRegClass.contains(SrcReg))
864-
Opcode = SystemZ::EAR;
865852
else
866853
llvm_unreachable("Impossible reg-to-reg copy");
867854

llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ class SystemZPassConfig : public TargetPassConfig {
222222
void addIRPasses() override;
223223
bool addInstSelector() override;
224224
bool addILPOpts() override;
225+
void addPreRegAlloc() override;
225226
void addPostRewrite() override;
226227
void addPostRegAlloc() override;
227228
void addPreSched2() override;
@@ -253,6 +254,10 @@ bool SystemZPassConfig::addILPOpts() {
253254
return true;
254255
}
255256

257+
void SystemZPassConfig::addPreRegAlloc() {
258+
addPass(createSystemZCopyPhysRegsPass(getSystemZTargetMachine()));
259+
}
260+
256261
void SystemZPassConfig::addPostRewrite() {
257262
addPass(createSystemZPostRewritePass(getSystemZTargetMachine()));
258263
}

llvm/test/CodeGen/SystemZ/tls-08.ll

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
; RUN: llc < %s -mcpu=z196 -mtriple=s390x-linux-gnu -O0 \
2+
; RUN: -stop-before=regallocfast 2>&1 | FileCheck %s
3+
; RUN: llc < %s -mcpu=z196 -mtriple=s390x-linux-gnu -O3 \
4+
; RUN: -stop-before=livevars 2>&1 | FileCheck %s
5+
;
6+
; Test that copies to/from access registers are handled before regalloc with
7+
; GR32 regs.
8+
9+
@x = dso_local thread_local global i32 0, align 4
10+
define weak_odr hidden i32* @fun0() {
11+
; CHECK: name: fun0
12+
; CHECK: {{%[0-9]+}}:gr32bit = EAR $a0
13+
; CHECK: {{%[0-9]+}}:gr32bit = EAR $a1
14+
ret i32* @x
15+
}
16+
17+
define i32 @fun1() {
18+
; CHECK: name: fun1
19+
; CHECK: [[VREG0:%[0-9]+]]:gr32bit = COPY %0
20+
; CHECK-NEXT: $a1 = SAR [[VREG0]]
21+
; CHECK: {{%[0-9]+}}:gr32bit = EAR $a0
22+
%val = call i32 asm "blah", "={a0}, {a1}" (i32 0)
23+
ret i32 %val
24+
}

llvm/test/CodeGen/SystemZ/tls-09.ll

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; RUN: llc < %s -mcpu=z196 -mtriple=s390x-linux-gnu -O0
2+
;
3+
; Test that a0 and a1 are copied successfully into GR32 registers.
4+
5+
@x = dso_local thread_local global i32 0, align 4
6+
define i32 @fun0(i32 signext, i32 signext, i32 signext, i32 signext, i32 signext, i32 signext, i32 signext) {
7+
%8 = alloca i32, align 4
8+
%9 = alloca i32, align 4
9+
%10 = alloca i32, align 4
10+
%11 = alloca i32, align 4
11+
%12 = alloca i32, align 4
12+
%13 = alloca i32, align 4
13+
%14 = alloca i32, align 4
14+
%15 = load i32, i32* @x, align 4
15+
store i32 %0, i32* %8, align 4
16+
store i32 %1, i32* %9, align 4
17+
store i32 %2, i32* %10, align 4
18+
store i32 %3, i32* %11, align 4
19+
store i32 %4, i32* %12, align 4
20+
store i32 %5, i32* %13, align 4
21+
store i32 %6, i32* %14, align 4
22+
%16 = load i32, i32* %8, align 4
23+
%17 = add nsw i32 %15, %16
24+
%18 = load i32, i32* %9, align 4
25+
%19 = add nsw i32 %17, %18
26+
%20 = load i32, i32* %10, align 4
27+
%21 = add nsw i32 %19, %20
28+
%22 = load i32, i32* %11, align 4
29+
%23 = add nsw i32 %21, %22
30+
%24 = load i32, i32* %12, align 4
31+
%25 = add nsw i32 %23, %24
32+
%26 = load i32, i32* %13, align 4
33+
%27 = add nsw i32 %25, %26
34+
%28 = load i32, i32* %14, align 4
35+
%29 = add nsw i32 %27, %28
36+
ret i32 %29
37+
}

llvm/test/CodeGen/SystemZ/tls-10.mir

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# RUN: llc -mtriple=s390x-linux-gnu -mcpu=z196 -O0 -start-after=finalize-isel \
2+
# RUN: -stop-before=regallocfast -o - %s | FileCheck %s
3+
# RUN: llc -mtriple=s390x-linux-gnu -mcpu=z196 -O3 -start-after=finalize-isel \
4+
# RUN: -stop-before=livevars -o - %s | FileCheck %s
5+
#
6+
# Test that a COPY from CC gets implemented with an IPM to a GR32 reg.
7+
8+
---
9+
name: fun0
10+
tracksRegLiveness: true
11+
registers:
12+
- { id: 0, class: grx32bit }
13+
body: |
14+
bb.0:
15+
liveins: $cc
16+
; CHECK-LABEL: name: fun0
17+
; CHECK: %1:gr32bit = IPM implicit $cc
18+
; CHECK-NEXT: %0:grx32bit = COPY %1
19+
; CHECK-NEXT: $r2l = COPY %0
20+
; CHECK-NEXT: Return implicit $r2l
21+
%0:grx32bit = COPY $cc
22+
$r2l = COPY %0
23+
Return implicit $r2l
24+
...

llvm/test/CodeGen/SystemZ/tls-11.mir

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# RUN: llc -mtriple=s390x-linux-gnu -mcpu=z196 -O0 -start-before=prologepilog \
2+
# RUN: -o - %s | FileCheck %s
3+
#
4+
# Test that a COPY to CC gets implemented with a tmlh or tmhh depending on
5+
# the source register.
6+
7+
---
8+
name: fun0
9+
tracksRegLiveness: true
10+
body: |
11+
bb.0:
12+
liveins: $r3l, $r4h
13+
; CHECK-LABEL: fun0
14+
; CHECK: tmlh %r3, 12288
15+
; CHECK: tmhh %r4, 12288
16+
$cc = COPY $r3l
17+
$cc = COPY $r4h
18+
...

0 commit comments

Comments
 (0)