2013-05-06 18:15:19 +02:00
|
|
|
//===-- SystemZInstrInfo.cpp - SystemZ instruction information ------------===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2013-05-06 18:15:19 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file contains the SystemZ implementation of the TargetInstrInfo class.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-06 13:49:48 +02:00
|
|
|
#include "SystemZInstrInfo.h"
|
2017-01-24 23:10:43 +01:00
|
|
|
#include "MCTargetDesc/SystemZMCTargetDesc.h"
|
|
|
|
#include "SystemZ.h"
|
2013-05-06 18:15:19 +02:00
|
|
|
#include "SystemZInstrBuilder.h"
|
2017-01-24 23:10:43 +01:00
|
|
|
#include "SystemZSubtarget.h"
|
2017-11-10 09:46:26 +01:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2017-01-24 23:10:43 +01:00
|
|
|
#include "llvm/CodeGen/LiveInterval.h"
|
2017-12-13 03:51:04 +01:00
|
|
|
#include "llvm/CodeGen/LiveIntervals.h"
|
2017-01-24 23:10:43 +01:00
|
|
|
#include "llvm/CodeGen/LiveVariables.h"
|
|
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
|
|
#include "llvm/CodeGen/MachineMemOperand.h"
|
|
|
|
#include "llvm/CodeGen/MachineOperand.h"
|
2013-07-02 17:28:56 +02:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2017-01-24 23:10:43 +01:00
|
|
|
#include "llvm/CodeGen/SlotIndexes.h"
|
2017-11-08 02:01:31 +01:00
|
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
2017-11-17 02:07:10 +01:00
|
|
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
2017-01-24 23:10:43 +01:00
|
|
|
#include "llvm/MC/MCInstrDesc.h"
|
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
|
|
#include "llvm/Support/BranchProbability.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <iterator>
|
2013-05-06 18:15:19 +02:00
|
|
|
|
2014-04-22 04:03:14 +02:00
|
|
|
using namespace llvm;
|
|
|
|
|
2013-11-19 01:57:56 +01:00
|
|
|
#define GET_INSTRINFO_CTOR_DTOR
|
2013-05-06 18:15:19 +02:00
|
|
|
#define GET_INSTRMAP_INFO
|
|
|
|
#include "SystemZGenInstrInfo.inc"
|
|
|
|
|
2017-11-10 09:46:26 +01:00
|
|
|
#define DEBUG_TYPE "systemz-II"
|
|
|
|
|
2013-07-31 13:36:35 +02:00
|
|
|
// Return a mask with Count low bits set.
|
|
|
|
static uint64_t allOnes(unsigned int Count) {
|
|
|
|
return Count == 0 ? 0 : (uint64_t(1) << (Count - 1) << 1) - 1;
|
|
|
|
}
|
|
|
|
|
2013-11-19 01:57:56 +01:00
|
|
|
// Pin the vtable to this file.
|
|
|
|
void SystemZInstrInfo::anchor() {}
|
|
|
|
|
2014-06-27 09:01:17 +02:00
|
|
|
SystemZInstrInfo::SystemZInstrInfo(SystemZSubtarget &sti)
|
2021-05-14 22:15:08 +02:00
|
|
|
: SystemZGenInstrInfo(SystemZ::ADJCALLSTACKDOWN, SystemZ::ADJCALLSTACKUP),
|
|
|
|
RI(sti.getSpecialRegisters()->getReturnFunctionAddressRegister()),
|
|
|
|
STI(sti) {}
|
2013-05-06 18:15:19 +02:00
|
|
|
|
|
|
|
// MI is a 128-bit load or store. Split it into two 64-bit loads or stores,
|
|
|
|
// each having the opcode given by NewOpcode.
|
|
|
|
void SystemZInstrInfo::splitMove(MachineBasicBlock::iterator MI,
|
|
|
|
unsigned NewOpcode) const {
|
|
|
|
MachineBasicBlock *MBB = MI->getParent();
|
|
|
|
MachineFunction &MF = *MBB->getParent();
|
|
|
|
|
|
|
|
// Get two load or store instructions. Use the original instruction for one
|
2014-01-24 18:20:08 +01:00
|
|
|
// of them (arbitrarily the second here) and create a clone for the other.
|
2016-07-12 03:39:01 +02:00
|
|
|
MachineInstr *EarlierMI = MF.CloneMachineInstr(&*MI);
|
2013-05-06 18:15:19 +02:00
|
|
|
MBB->insert(MI, EarlierMI);
|
|
|
|
|
2017-03-17 07:47:08 +01:00
|
|
|
// Set up the two 64-bit registers and remember super reg and its flags.
|
2013-05-06 18:15:19 +02:00
|
|
|
MachineOperand &HighRegOp = EarlierMI->getOperand(0);
|
|
|
|
MachineOperand &LowRegOp = MI->getOperand(0);
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 21:22:08 +02:00
|
|
|
Register Reg128 = LowRegOp.getReg();
|
2017-03-17 07:47:08 +01:00
|
|
|
unsigned Reg128Killed = getKillRegState(LowRegOp.isKill());
|
|
|
|
unsigned Reg128Undef = getUndefRegState(LowRegOp.isUndef());
|
2013-09-30 12:28:35 +02:00
|
|
|
HighRegOp.setReg(RI.getSubReg(HighRegOp.getReg(), SystemZ::subreg_h64));
|
|
|
|
LowRegOp.setReg(RI.getSubReg(LowRegOp.getReg(), SystemZ::subreg_l64));
|
2013-05-06 18:15:19 +02:00
|
|
|
|
2017-03-17 07:47:08 +01:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2013-05-06 18:15:19 +02:00
|
|
|
// 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);
|
|
|
|
LowOffsetOp.setImm(LowOffsetOp.getImm() + 8);
|
|
|
|
|
2017-04-24 14:40:28 +02:00
|
|
|
// 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);
|
2015-10-10 09:14:24 +02:00
|
|
|
EarlierMI->getOperand(1).setIsKill(false);
|
2015-10-26 16:03:41 +01:00
|
|
|
EarlierMI->getOperand(3).setIsKill(false);
|
2015-10-10 09:14:24 +02:00
|
|
|
|
2013-05-06 18:15:19 +02:00
|
|
|
// Set the opcodes.
|
|
|
|
unsigned HighOpcode = getOpcodeForOffset(NewOpcode, HighOffsetOp.getImm());
|
|
|
|
unsigned LowOpcode = getOpcodeForOffset(NewOpcode, LowOffsetOp.getImm());
|
|
|
|
assert(HighOpcode && LowOpcode && "Both offsets should be in range");
|
|
|
|
|
|
|
|
EarlierMI->setDesc(get(HighOpcode));
|
|
|
|
MI->setDesc(get(LowOpcode));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Split ADJDYNALLOC instruction MI.
|
|
|
|
void SystemZInstrInfo::splitAdjDynAlloc(MachineBasicBlock::iterator MI) const {
|
|
|
|
MachineBasicBlock *MBB = MI->getParent();
|
|
|
|
MachineFunction &MF = *MBB->getParent();
|
2016-07-28 20:40:00 +02:00
|
|
|
MachineFrameInfo &MFFrame = MF.getFrameInfo();
|
2013-05-06 18:15:19 +02:00
|
|
|
MachineOperand &OffsetMO = MI->getOperand(2);
|
|
|
|
|
2016-07-28 20:40:00 +02:00
|
|
|
uint64_t Offset = (MFFrame.getMaxCallFrameSize() +
|
2021-03-09 20:34:48 +01:00
|
|
|
SystemZMC::ELFCallFrameSize +
|
2013-05-06 18:15:19 +02:00
|
|
|
OffsetMO.getImm());
|
|
|
|
unsigned NewOpcode = getOpcodeForOffset(SystemZ::LA, Offset);
|
|
|
|
assert(NewOpcode && "No support for huge argument lists yet");
|
|
|
|
MI->setDesc(get(NewOpcode));
|
|
|
|
OffsetMO.setImm(Offset);
|
|
|
|
}
|
|
|
|
|
2013-10-01 15:02:28 +02:00
|
|
|
// MI is an RI-style pseudo instruction. Replace it with LowOpcode
|
|
|
|
// if the first operand is a low GR32 and HighOpcode if the first operand
|
|
|
|
// is a high GR32. ConvertHigh is true if LowOpcode takes a signed operand
|
|
|
|
// and HighOpcode takes an unsigned 32-bit operand. In those cases,
|
|
|
|
// MI has the same kind of operand as LowOpcode, so needs to be converted
|
|
|
|
// if HighOpcode is used.
|
2016-06-30 02:01:54 +02:00
|
|
|
void SystemZInstrInfo::expandRIPseudo(MachineInstr &MI, unsigned LowOpcode,
|
2013-10-01 15:02:28 +02:00
|
|
|
unsigned HighOpcode,
|
|
|
|
bool ConvertHigh) const {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 21:22:08 +02:00
|
|
|
Register Reg = MI.getOperand(0).getReg();
|
2019-09-16 09:29:37 +02:00
|
|
|
bool IsHigh = SystemZ::isHighReg(Reg);
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.setDesc(get(IsHigh ? HighOpcode : LowOpcode));
|
2013-10-01 15:02:28 +02:00
|
|
|
if (IsHigh && ConvertHigh)
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.getOperand(1).setImm(uint32_t(MI.getOperand(1).getImm()));
|
2013-10-01 15:02:28 +02:00
|
|
|
}
|
|
|
|
|
2013-10-01 16:53:46 +02:00
|
|
|
// MI is a three-operand RIE-style pseudo instruction. Replace it with
|
2015-10-09 09:19:16 +02:00
|
|
|
// LowOpcodeK if the registers are both low GR32s, otherwise use a move
|
2013-10-01 16:53:46 +02:00
|
|
|
// followed by HighOpcode or LowOpcode, depending on whether the target
|
|
|
|
// is a high or low GR32.
|
2016-06-30 02:01:54 +02:00
|
|
|
void SystemZInstrInfo::expandRIEPseudo(MachineInstr &MI, unsigned LowOpcode,
|
2013-10-01 16:53:46 +02:00
|
|
|
unsigned LowOpcodeK,
|
|
|
|
unsigned HighOpcode) const {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 21:22:08 +02:00
|
|
|
Register DestReg = MI.getOperand(0).getReg();
|
|
|
|
Register SrcReg = MI.getOperand(1).getReg();
|
2019-09-16 09:29:37 +02:00
|
|
|
bool DestIsHigh = SystemZ::isHighReg(DestReg);
|
|
|
|
bool SrcIsHigh = SystemZ::isHighReg(SrcReg);
|
2013-10-01 16:53:46 +02:00
|
|
|
if (!DestIsHigh && !SrcIsHigh)
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.setDesc(get(LowOpcodeK));
|
2013-10-01 16:53:46 +02:00
|
|
|
else {
|
2019-06-18 14:10:02 +02:00
|
|
|
if (DestReg != SrcReg) {
|
|
|
|
emitGRX32Move(*MI.getParent(), MI, MI.getDebugLoc(), DestReg, SrcReg,
|
|
|
|
SystemZ::LR, 32, MI.getOperand(1).isKill(),
|
|
|
|
MI.getOperand(1).isUndef());
|
|
|
|
MI.getOperand(1).setReg(DestReg);
|
|
|
|
}
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.setDesc(get(DestIsHigh ? HighOpcode : LowOpcode));
|
|
|
|
MI.tieOperands(0, 1);
|
2013-10-01 16:53:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-01 13:26:28 +02:00
|
|
|
// MI is an RXY-style pseudo instruction. Replace it with LowOpcode
|
|
|
|
// if the first operand is a low GR32 and HighOpcode if the first operand
|
|
|
|
// is a high GR32.
|
2016-06-30 02:01:54 +02:00
|
|
|
void SystemZInstrInfo::expandRXYPseudo(MachineInstr &MI, unsigned LowOpcode,
|
2013-10-01 13:26:28 +02:00
|
|
|
unsigned HighOpcode) const {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 21:22:08 +02:00
|
|
|
Register Reg = MI.getOperand(0).getReg();
|
2019-09-16 09:29:37 +02:00
|
|
|
unsigned Opcode = getOpcodeForOffset(
|
|
|
|
SystemZ::isHighReg(Reg) ? HighOpcode : LowOpcode,
|
|
|
|
MI.getOperand(2).getImm());
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.setDesc(get(Opcode));
|
2013-10-01 13:26:28 +02:00
|
|
|
}
|
|
|
|
|
2016-11-28 14:34:08 +01:00
|
|
|
// MI is a load-on-condition pseudo instruction with a single register
|
|
|
|
// (source or destination) operand. Replace it with LowOpcode if the
|
|
|
|
// register is a low GR32 and HighOpcode if the register is a high GR32.
|
|
|
|
void SystemZInstrInfo::expandLOCPseudo(MachineInstr &MI, unsigned LowOpcode,
|
|
|
|
unsigned HighOpcode) const {
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 21:22:08 +02:00
|
|
|
Register Reg = MI.getOperand(0).getReg();
|
2019-09-16 09:29:37 +02:00
|
|
|
unsigned Opcode = SystemZ::isHighReg(Reg) ? HighOpcode : LowOpcode;
|
2016-11-28 14:34:08 +01:00
|
|
|
MI.setDesc(get(Opcode));
|
|
|
|
}
|
|
|
|
|
2013-10-01 14:49:07 +02:00
|
|
|
// MI is an RR-style pseudo instruction that zero-extends the low Size bits
|
|
|
|
// of one GRX32 into another. Replace it with LowOpcode if both operands
|
|
|
|
// are low registers, otherwise use RISB[LH]G.
|
2016-06-30 02:01:54 +02:00
|
|
|
void SystemZInstrInfo::expandZExtPseudo(MachineInstr &MI, unsigned LowOpcode,
|
2013-10-01 14:49:07 +02:00
|
|
|
unsigned Size) const {
|
2017-03-22 07:03:32 +01:00
|
|
|
MachineInstrBuilder MIB =
|
|
|
|
emitGRX32Move(*MI.getParent(), MI, MI.getDebugLoc(),
|
|
|
|
MI.getOperand(0).getReg(), MI.getOperand(1).getReg(), LowOpcode,
|
|
|
|
Size, MI.getOperand(1).isKill(), MI.getOperand(1).isUndef());
|
|
|
|
|
|
|
|
// Keep the remaining operands as-is.
|
|
|
|
for (unsigned I = 2; I < MI.getNumOperands(); ++I)
|
|
|
|
MIB.add(MI.getOperand(I));
|
|
|
|
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.eraseFromParent();
|
2013-10-01 14:49:07 +02:00
|
|
|
}
|
|
|
|
|
2016-04-24 15:57:49 +02:00
|
|
|
void SystemZInstrInfo::expandLoadStackGuard(MachineInstr *MI) const {
|
|
|
|
MachineBasicBlock *MBB = MI->getParent();
|
|
|
|
MachineFunction &MF = *MBB->getParent();
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 21:22:08 +02:00
|
|
|
const Register Reg64 = MI->getOperand(0).getReg();
|
|
|
|
const Register Reg32 = RI.getSubReg(Reg64, SystemZ::subreg_l32);
|
2016-04-24 15:57:49 +02:00
|
|
|
|
2017-05-24 15:15:48 +02:00
|
|
|
// EAR can only load the low subregister so us a shift for %a0 to produce
|
|
|
|
// the GR containing %a0 and %a1.
|
2016-04-24 15:57:49 +02:00
|
|
|
|
|
|
|
// ear <reg>, %a0
|
2017-05-24 15:15:48 +02:00
|
|
|
BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::EAR), Reg32)
|
|
|
|
.addReg(SystemZ::A0)
|
|
|
|
.addReg(Reg64, RegState::ImplicitDefine);
|
2016-04-24 15:57:49 +02:00
|
|
|
|
|
|
|
// sllg <reg>, <reg>, 32
|
2017-05-24 15:15:48 +02:00
|
|
|
BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::SLLG), Reg64)
|
|
|
|
.addReg(Reg64)
|
|
|
|
.addReg(0)
|
|
|
|
.addImm(32);
|
2016-04-24 15:57:49 +02:00
|
|
|
|
|
|
|
// ear <reg>, %a1
|
2017-05-24 15:15:48 +02:00
|
|
|
BuildMI(*MBB, MI, MI->getDebugLoc(), get(SystemZ::EAR), Reg32)
|
|
|
|
.addReg(SystemZ::A1);
|
2016-04-24 15:57:49 +02:00
|
|
|
|
|
|
|
// lg <reg>, 40(<reg>)
|
|
|
|
MI->setDesc(get(SystemZ::LG));
|
2017-05-24 15:15:48 +02:00
|
|
|
MachineInstrBuilder(MF, MI).addReg(Reg64).addImm(40).addReg(0);
|
2016-04-24 15:57:49 +02:00
|
|
|
}
|
|
|
|
|
2013-10-01 13:26:28 +02:00
|
|
|
// Emit a zero-extending move from 32-bit GPR SrcReg to 32-bit GPR
|
|
|
|
// DestReg before MBBI in MBB. Use LowLowOpcode when both DestReg and SrcReg
|
|
|
|
// are low registers, otherwise use RISB[LH]G. Size is the number of bits
|
|
|
|
// taken from the low end of SrcReg (8 for LLCR, 16 for LLHR and 32 for LR).
|
|
|
|
// KillSrc is true if this move is the last use of SrcReg.
|
2017-03-22 07:03:32 +01:00
|
|
|
MachineInstrBuilder
|
|
|
|
SystemZInstrInfo::emitGRX32Move(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock::iterator MBBI,
|
|
|
|
const DebugLoc &DL, unsigned DestReg,
|
|
|
|
unsigned SrcReg, unsigned LowLowOpcode,
|
|
|
|
unsigned Size, bool KillSrc,
|
|
|
|
bool UndefSrc) const {
|
2013-10-01 13:26:28 +02:00
|
|
|
unsigned Opcode;
|
2019-09-16 09:29:37 +02:00
|
|
|
bool DestIsHigh = SystemZ::isHighReg(DestReg);
|
|
|
|
bool SrcIsHigh = SystemZ::isHighReg(SrcReg);
|
2013-10-01 13:26:28 +02:00
|
|
|
if (DestIsHigh && SrcIsHigh)
|
|
|
|
Opcode = SystemZ::RISBHH;
|
|
|
|
else if (DestIsHigh && !SrcIsHigh)
|
|
|
|
Opcode = SystemZ::RISBHL;
|
|
|
|
else if (!DestIsHigh && SrcIsHigh)
|
|
|
|
Opcode = SystemZ::RISBLH;
|
|
|
|
else {
|
2017-03-22 07:03:32 +01:00
|
|
|
return BuildMI(MBB, MBBI, DL, get(LowLowOpcode), DestReg)
|
2017-01-18 09:32:54 +01:00
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc) | getUndefRegState(UndefSrc));
|
2013-10-01 13:26:28 +02:00
|
|
|
}
|
|
|
|
unsigned Rotate = (DestIsHigh != SrcIsHigh ? 32 : 0);
|
2017-03-22 07:03:32 +01:00
|
|
|
return BuildMI(MBB, MBBI, DL, get(Opcode), DestReg)
|
2013-10-01 13:26:28 +02:00
|
|
|
.addReg(DestReg, RegState::Undef)
|
2017-01-18 09:32:54 +01:00
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc) | getUndefRegState(UndefSrc))
|
2013-10-01 13:26:28 +02:00
|
|
|
.addImm(32 - Size).addImm(128 + 31).addImm(Rotate);
|
|
|
|
}
|
|
|
|
|
2016-11-28 14:34:08 +01:00
|
|
|
MachineInstr *SystemZInstrInfo::commuteInstructionImpl(MachineInstr &MI,
|
|
|
|
bool NewMI,
|
|
|
|
unsigned OpIdx1,
|
|
|
|
unsigned OpIdx2) const {
|
|
|
|
auto cloneIfNew = [NewMI](MachineInstr &MI) -> MachineInstr & {
|
|
|
|
if (NewMI)
|
|
|
|
return *MI.getParent()->getParent()->CloneMachineInstr(&MI);
|
|
|
|
return MI;
|
|
|
|
};
|
|
|
|
|
|
|
|
switch (MI.getOpcode()) {
|
2019-07-12 20:13:16 +02:00
|
|
|
case SystemZ::SELRMux:
|
|
|
|
case SystemZ::SELFHR:
|
|
|
|
case SystemZ::SELR:
|
|
|
|
case SystemZ::SELGR:
|
2016-11-28 14:34:08 +01:00
|
|
|
case SystemZ::LOCRMux:
|
|
|
|
case SystemZ::LOCFHR:
|
|
|
|
case SystemZ::LOCR:
|
|
|
|
case SystemZ::LOCGR: {
|
|
|
|
auto &WorkingMI = cloneIfNew(MI);
|
|
|
|
// Invert condition.
|
|
|
|
unsigned CCValid = WorkingMI.getOperand(3).getImm();
|
|
|
|
unsigned CCMask = WorkingMI.getOperand(4).getImm();
|
|
|
|
WorkingMI.getOperand(4).setImm(CCMask ^ CCValid);
|
|
|
|
return TargetInstrInfo::commuteInstructionImpl(WorkingMI, /*NewMI=*/false,
|
|
|
|
OpIdx1, OpIdx2);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return TargetInstrInfo::commuteInstructionImpl(MI, NewMI, OpIdx1, OpIdx2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-06 18:15:19 +02:00
|
|
|
// If MI is a simple load or store for a frame object, return the register
|
|
|
|
// it loads or stores and set FrameIndex to the index of the frame object.
|
|
|
|
// Return 0 otherwise.
|
|
|
|
//
|
|
|
|
// Flag is SimpleBDXLoad for loads and SimpleBDXStore for stores.
|
2016-06-30 02:01:54 +02:00
|
|
|
static int isSimpleMove(const MachineInstr &MI, int &FrameIndex,
|
2013-07-02 17:28:56 +02:00
|
|
|
unsigned Flag) {
|
2016-06-30 02:01:54 +02:00
|
|
|
const MCInstrDesc &MCID = MI.getDesc();
|
|
|
|
if ((MCID.TSFlags & Flag) && MI.getOperand(1).isFI() &&
|
|
|
|
MI.getOperand(2).getImm() == 0 && MI.getOperand(3).getReg() == 0) {
|
|
|
|
FrameIndex = MI.getOperand(1).getIndex();
|
|
|
|
return MI.getOperand(0).getReg();
|
2013-05-06 18:15:19 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-30 02:01:54 +02:00
|
|
|
unsigned SystemZInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
|
2013-05-06 18:15:19 +02:00
|
|
|
int &FrameIndex) const {
|
|
|
|
return isSimpleMove(MI, FrameIndex, SystemZII::SimpleBDXLoad);
|
|
|
|
}
|
|
|
|
|
2016-06-30 02:01:54 +02:00
|
|
|
unsigned SystemZInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
|
2013-05-06 18:15:19 +02:00
|
|
|
int &FrameIndex) const {
|
|
|
|
return isSimpleMove(MI, FrameIndex, SystemZII::SimpleBDXStore);
|
|
|
|
}
|
|
|
|
|
2016-06-30 02:01:54 +02:00
|
|
|
bool SystemZInstrInfo::isStackSlotCopy(const MachineInstr &MI,
|
2013-07-05 16:38:48 +02:00
|
|
|
int &DestFrameIndex,
|
|
|
|
int &SrcFrameIndex) const {
|
|
|
|
// Check for MVC 0(Length,FI1),0(FI2)
|
2016-07-28 20:40:00 +02:00
|
|
|
const MachineFrameInfo &MFI = MI.getParent()->getParent()->getFrameInfo();
|
2016-06-30 02:01:54 +02:00
|
|
|
if (MI.getOpcode() != SystemZ::MVC || !MI.getOperand(0).isFI() ||
|
|
|
|
MI.getOperand(1).getImm() != 0 || !MI.getOperand(3).isFI() ||
|
|
|
|
MI.getOperand(4).getImm() != 0)
|
2013-07-05 16:38:48 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check that Length covers the full slots.
|
2016-06-30 02:01:54 +02:00
|
|
|
int64_t Length = MI.getOperand(2).getImm();
|
|
|
|
unsigned FI1 = MI.getOperand(0).getIndex();
|
|
|
|
unsigned FI2 = MI.getOperand(3).getIndex();
|
2016-07-28 20:40:00 +02:00
|
|
|
if (MFI.getObjectSize(FI1) != Length ||
|
|
|
|
MFI.getObjectSize(FI2) != Length)
|
2013-07-05 16:38:48 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
DestFrameIndex = FI1;
|
|
|
|
SrcFrameIndex = FI2;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-15 16:41:04 +02:00
|
|
|
bool SystemZInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
|
2013-05-06 18:15:19 +02:00
|
|
|
MachineBasicBlock *&TBB,
|
|
|
|
MachineBasicBlock *&FBB,
|
|
|
|
SmallVectorImpl<MachineOperand> &Cond,
|
|
|
|
bool AllowModify) const {
|
|
|
|
// Most of the code and comments here are boilerplate.
|
|
|
|
|
|
|
|
// Start from the bottom of the block and work up, examining the
|
|
|
|
// terminator instructions.
|
|
|
|
MachineBasicBlock::iterator I = MBB.end();
|
|
|
|
while (I != MBB.begin()) {
|
|
|
|
--I;
|
2018-05-09 04:42:00 +02:00
|
|
|
if (I->isDebugInstr())
|
2013-05-06 18:15:19 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Working from the bottom, when we see a non-terminator instruction, we're
|
|
|
|
// done.
|
2016-02-23 03:46:52 +01:00
|
|
|
if (!isUnpredicatedTerminator(*I))
|
2013-05-06 18:15:19 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
// A terminator that isn't a branch can't easily be handled by this
|
2019-09-05 12:20:05 +02:00
|
|
|
// analysis.
|
|
|
|
if (!I->isBranch())
|
2013-05-06 18:15:19 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Can't handle indirect branches.
|
2016-06-30 02:01:54 +02:00
|
|
|
SystemZII::Branch Branch(getBranchInfo(*I));
|
2019-09-05 12:20:05 +02:00
|
|
|
if (!Branch.hasMBBTarget())
|
2013-05-06 18:15:19 +02:00
|
|
|
return true;
|
|
|
|
|
2013-05-28 12:41:11 +02:00
|
|
|
// Punt on compound branches.
|
|
|
|
if (Branch.Type != SystemZII::BranchNormal)
|
|
|
|
return true;
|
|
|
|
|
2013-05-28 12:13:54 +02:00
|
|
|
if (Branch.CCMask == SystemZ::CCMASK_ANY) {
|
2013-05-06 18:15:19 +02:00
|
|
|
// Handle unconditional branches.
|
|
|
|
if (!AllowModify) {
|
2019-09-05 12:20:05 +02:00
|
|
|
TBB = Branch.getMBBTarget();
|
2013-05-06 18:15:19 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the block has any instructions after a JMP, delete them.
|
2014-03-02 13:27:27 +01:00
|
|
|
while (std::next(I) != MBB.end())
|
|
|
|
std::next(I)->eraseFromParent();
|
2013-05-06 18:15:19 +02:00
|
|
|
|
|
|
|
Cond.clear();
|
2014-04-25 07:30:21 +02:00
|
|
|
FBB = nullptr;
|
2013-05-06 18:15:19 +02:00
|
|
|
|
|
|
|
// Delete the JMP if it's equivalent to a fall-through.
|
2019-09-05 12:20:05 +02:00
|
|
|
if (MBB.isLayoutSuccessor(Branch.getMBBTarget())) {
|
2014-04-25 07:30:21 +02:00
|
|
|
TBB = nullptr;
|
2013-05-06 18:15:19 +02:00
|
|
|
I->eraseFromParent();
|
|
|
|
I = MBB.end();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TBB is used to indicate the unconditinal destination.
|
2019-09-05 12:20:05 +02:00
|
|
|
TBB = Branch.getMBBTarget();
|
2013-05-06 18:15:19 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Working from the bottom, handle the first conditional branch.
|
|
|
|
if (Cond.empty()) {
|
|
|
|
// FIXME: add X86-style branch swap
|
|
|
|
FBB = TBB;
|
2019-09-05 12:20:05 +02:00
|
|
|
TBB = Branch.getMBBTarget();
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
Cond.push_back(MachineOperand::CreateImm(Branch.CCValid));
|
2013-05-28 12:13:54 +02:00
|
|
|
Cond.push_back(MachineOperand::CreateImm(Branch.CCMask));
|
2013-05-06 18:15:19 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle subsequent conditional branches.
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
assert(Cond.size() == 2 && TBB && "Should have seen a conditional branch");
|
2013-05-06 18:15:19 +02:00
|
|
|
|
|
|
|
// Only handle the case where all conditional branches branch to the same
|
|
|
|
// destination.
|
2019-09-05 12:20:05 +02:00
|
|
|
if (TBB != Branch.getMBBTarget())
|
2013-05-06 18:15:19 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// If the conditions are the same, we can leave them alone.
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
unsigned OldCCValid = Cond[0].getImm();
|
|
|
|
unsigned OldCCMask = Cond[1].getImm();
|
|
|
|
if (OldCCValid == Branch.CCValid && OldCCMask == Branch.CCMask)
|
2013-05-06 18:15:19 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// FIXME: Try combining conditions like X86 does. Should be easy on Z!
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
return false;
|
2013-05-06 18:15:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-14 22:43:16 +02:00
|
|
|
unsigned SystemZInstrInfo::removeBranch(MachineBasicBlock &MBB,
|
2016-09-14 19:23:48 +02:00
|
|
|
int *BytesRemoved) const {
|
|
|
|
assert(!BytesRemoved && "code size not handled");
|
|
|
|
|
2013-05-06 18:15:19 +02:00
|
|
|
// Most of the code and comments here are boilerplate.
|
|
|
|
MachineBasicBlock::iterator I = MBB.end();
|
|
|
|
unsigned Count = 0;
|
|
|
|
|
|
|
|
while (I != MBB.begin()) {
|
|
|
|
--I;
|
2018-05-09 04:42:00 +02:00
|
|
|
if (I->isDebugInstr())
|
2013-05-06 18:15:19 +02:00
|
|
|
continue;
|
2013-05-28 12:13:54 +02:00
|
|
|
if (!I->isBranch())
|
2013-05-06 18:15:19 +02:00
|
|
|
break;
|
2019-09-05 12:20:05 +02:00
|
|
|
if (!getBranchInfo(*I).hasMBBTarget())
|
2013-05-06 18:15:19 +02:00
|
|
|
break;
|
|
|
|
// Remove the branch.
|
|
|
|
I->eraseFromParent();
|
|
|
|
I = MBB.end();
|
|
|
|
++Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Count;
|
|
|
|
}
|
|
|
|
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
bool SystemZInstrInfo::
|
2016-09-14 22:43:16 +02:00
|
|
|
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const {
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
assert(Cond.size() == 2 && "Invalid condition");
|
|
|
|
Cond[1].setImm(Cond[1].getImm() ^ Cond[0].getImm());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-14 19:24:15 +02:00
|
|
|
unsigned SystemZInstrInfo::insertBranch(MachineBasicBlock &MBB,
|
2016-06-12 17:39:02 +02:00
|
|
|
MachineBasicBlock *TBB,
|
|
|
|
MachineBasicBlock *FBB,
|
|
|
|
ArrayRef<MachineOperand> Cond,
|
2016-09-14 19:23:48 +02:00
|
|
|
const DebugLoc &DL,
|
|
|
|
int *BytesAdded) const {
|
2013-05-06 18:15:19 +02:00
|
|
|
// In this function we output 32-bit branches, which should always
|
|
|
|
// have enough range. They can be shortened and relaxed by later code
|
|
|
|
// in the pipeline, if desired.
|
|
|
|
|
|
|
|
// Shouldn't be a fall through.
|
2016-09-14 19:24:15 +02:00
|
|
|
assert(TBB && "insertBranch must not be told to insert a fallthrough");
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
assert((Cond.size() == 2 || Cond.size() == 0) &&
|
2013-05-06 18:15:19 +02:00
|
|
|
"SystemZ branch conditions have one component!");
|
2016-09-14 19:23:48 +02:00
|
|
|
assert(!BytesAdded && "code size not handled");
|
2013-05-06 18:15:19 +02:00
|
|
|
|
|
|
|
if (Cond.empty()) {
|
|
|
|
// Unconditional branch?
|
|
|
|
assert(!FBB && "Unconditional branch with multiple successors!");
|
[SystemZ] Add long branch pass
Before this change, the SystemZ backend would use BRCL for all branches
and only consider shortening them to BRC when generating an object file.
E.g. a branch on equal would use the JGE alias of BRCL in assembly output,
but might be shortened to the JE alias of BRC in ELF output. This was
a useful first step, but it had two problems:
(1) The z assembler isn't traditionally supposed to perform branch shortening
or branch relaxation. We followed this rule by not relaxing branches
in assembler input, but that meant that generating assembly code and
then assembling it would not produce the same result as going directly
to object code; the former would give long branches everywhere, whereas
the latter would use short branches where possible.
(2) Other useful branches, like COMPARE AND BRANCH, do not have long forms.
We would need to do something else before supporting them.
(Although COMPARE AND BRANCH does not change the condition codes,
the plan is to model COMPARE AND BRANCH as a CC-clobbering instruction
during codegen, so that we can safely lower it to a separate compare
and long branch where necessary. This is not a valid transformation
for the assembler proper to make.)
This patch therefore moves branch relaxation to a pre-emit pass.
For now, calls are still shortened from BRASL to BRAS by the assembler,
although this too is not really the traditional behaviour.
The first test takes about 1.5s to run, and there are likely to be
more tests in this vein once further branch types are added. The feeling
on IRC was that 1.5s is a bit much for a single test, so I've restricted
it to SystemZ hosts for now.
The patch exposes (and fixes) some typos in the main CodeGen/SystemZ tests.
A later patch will remove the {{g}}s from that directory.
llvm-svn: 182274
2013-05-20 16:23:08 +02:00
|
|
|
BuildMI(&MBB, DL, get(SystemZ::J)).addMBB(TBB);
|
2013-05-06 18:15:19 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Conditional branch.
|
|
|
|
unsigned Count = 0;
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
unsigned CCValid = Cond[0].getImm();
|
|
|
|
unsigned CCMask = Cond[1].getImm();
|
|
|
|
BuildMI(&MBB, DL, get(SystemZ::BRC))
|
|
|
|
.addImm(CCValid).addImm(CCMask).addMBB(TBB);
|
2013-05-06 18:15:19 +02:00
|
|
|
++Count;
|
|
|
|
|
|
|
|
if (FBB) {
|
|
|
|
// Two-way Conditional branch. Insert the second branch.
|
[SystemZ] Add long branch pass
Before this change, the SystemZ backend would use BRCL for all branches
and only consider shortening them to BRC when generating an object file.
E.g. a branch on equal would use the JGE alias of BRCL in assembly output,
but might be shortened to the JE alias of BRC in ELF output. This was
a useful first step, but it had two problems:
(1) The z assembler isn't traditionally supposed to perform branch shortening
or branch relaxation. We followed this rule by not relaxing branches
in assembler input, but that meant that generating assembly code and
then assembling it would not produce the same result as going directly
to object code; the former would give long branches everywhere, whereas
the latter would use short branches where possible.
(2) Other useful branches, like COMPARE AND BRANCH, do not have long forms.
We would need to do something else before supporting them.
(Although COMPARE AND BRANCH does not change the condition codes,
the plan is to model COMPARE AND BRANCH as a CC-clobbering instruction
during codegen, so that we can safely lower it to a separate compare
and long branch where necessary. This is not a valid transformation
for the assembler proper to make.)
This patch therefore moves branch relaxation to a pre-emit pass.
For now, calls are still shortened from BRASL to BRAS by the assembler,
although this too is not really the traditional behaviour.
The first test takes about 1.5s to run, and there are likely to be
more tests in this vein once further branch types are added. The feeling
on IRC was that 1.5s is a bit much for a single test, so I've restricted
it to SystemZ hosts for now.
The patch exposes (and fixes) some typos in the main CodeGen/SystemZ tests.
A later patch will remove the {{g}}s from that directory.
llvm-svn: 182274
2013-05-20 16:23:08 +02:00
|
|
|
BuildMI(&MBB, DL, get(SystemZ::J)).addMBB(FBB);
|
2013-05-06 18:15:19 +02:00
|
|
|
++Count;
|
|
|
|
}
|
|
|
|
return Count;
|
|
|
|
}
|
|
|
|
|
2020-04-03 19:22:51 +02:00
|
|
|
bool SystemZInstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg,
|
|
|
|
Register &SrcReg2, int &Mask,
|
2016-06-30 02:01:54 +02:00
|
|
|
int &Value) const {
|
|
|
|
assert(MI.isCompare() && "Caller should have checked for a comparison");
|
2013-08-12 12:28:10 +02:00
|
|
|
|
2016-06-30 02:01:54 +02:00
|
|
|
if (MI.getNumExplicitOperands() == 2 && MI.getOperand(0).isReg() &&
|
|
|
|
MI.getOperand(1).isImm()) {
|
|
|
|
SrcReg = MI.getOperand(0).getReg();
|
2013-08-12 12:28:10 +02:00
|
|
|
SrcReg2 = 0;
|
2016-06-30 02:01:54 +02:00
|
|
|
Value = MI.getOperand(1).getImm();
|
2013-08-12 12:28:10 +02:00
|
|
|
Mask = ~0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-11-28 14:34:08 +01:00
|
|
|
bool SystemZInstrInfo::canInsertSelect(const MachineBasicBlock &MBB,
|
|
|
|
ArrayRef<MachineOperand> Pred,
|
2020-04-03 19:22:51 +02:00
|
|
|
Register DstReg, Register TrueReg,
|
|
|
|
Register FalseReg, int &CondCycles,
|
2020-01-17 23:34:26 +01:00
|
|
|
int &TrueCycles,
|
2016-11-28 14:34:08 +01:00
|
|
|
int &FalseCycles) const {
|
|
|
|
// Not all subtargets have LOCR instructions.
|
|
|
|
if (!STI.hasLoadStoreOnCond())
|
|
|
|
return false;
|
|
|
|
if (Pred.size() != 2)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check register classes.
|
|
|
|
const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
|
|
|
|
const TargetRegisterClass *RC =
|
|
|
|
RI.getCommonSubClass(MRI.getRegClass(TrueReg), MRI.getRegClass(FalseReg));
|
|
|
|
if (!RC)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// We have LOCR instructions for 32 and 64 bit general purpose registers.
|
|
|
|
if ((STI.hasLoadStoreOnCond2() &&
|
|
|
|
SystemZ::GRX32BitRegClass.hasSubClassEq(RC)) ||
|
|
|
|
SystemZ::GR32BitRegClass.hasSubClassEq(RC) ||
|
|
|
|
SystemZ::GR64BitRegClass.hasSubClassEq(RC)) {
|
|
|
|
CondCycles = 2;
|
|
|
|
TrueCycles = 2;
|
|
|
|
FalseCycles = 2;
|
|
|
|
return true;
|
2013-07-25 11:11:15 +02:00
|
|
|
}
|
2016-11-28 14:34:08 +01:00
|
|
|
|
|
|
|
// Can't do anything else.
|
|
|
|
return false;
|
2013-07-25 11:11:15 +02:00
|
|
|
}
|
|
|
|
|
2016-11-28 14:34:08 +01:00
|
|
|
void SystemZInstrInfo::insertSelect(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock::iterator I,
|
2020-04-03 19:22:51 +02:00
|
|
|
const DebugLoc &DL, Register DstReg,
|
2016-11-28 14:34:08 +01:00
|
|
|
ArrayRef<MachineOperand> Pred,
|
2020-04-03 19:22:51 +02:00
|
|
|
Register TrueReg,
|
|
|
|
Register FalseReg) const {
|
2016-11-28 14:34:08 +01:00
|
|
|
MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
|
|
|
|
const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
|
|
|
|
|
|
|
|
assert(Pred.size() == 2 && "Invalid condition");
|
|
|
|
unsigned CCValid = Pred[0].getImm();
|
|
|
|
unsigned CCMask = Pred[1].getImm();
|
|
|
|
|
|
|
|
unsigned Opc;
|
|
|
|
if (SystemZ::GRX32BitRegClass.hasSubClassEq(RC)) {
|
2019-07-12 20:13:16 +02:00
|
|
|
if (STI.hasMiscellaneousExtensions3())
|
|
|
|
Opc = SystemZ::SELRMux;
|
|
|
|
else if (STI.hasLoadStoreOnCond2())
|
2016-11-28 14:34:08 +01:00
|
|
|
Opc = SystemZ::LOCRMux;
|
|
|
|
else {
|
|
|
|
Opc = SystemZ::LOCR;
|
|
|
|
MRI.constrainRegClass(DstReg, &SystemZ::GR32BitRegClass);
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-15 21:22:08 +02:00
|
|
|
Register TReg = MRI.createVirtualRegister(&SystemZ::GR32BitRegClass);
|
|
|
|
Register FReg = MRI.createVirtualRegister(&SystemZ::GR32BitRegClass);
|
2017-03-31 16:06:59 +02:00
|
|
|
BuildMI(MBB, I, DL, get(TargetOpcode::COPY), TReg).addReg(TrueReg);
|
|
|
|
BuildMI(MBB, I, DL, get(TargetOpcode::COPY), FReg).addReg(FalseReg);
|
|
|
|
TrueReg = TReg;
|
|
|
|
FalseReg = FReg;
|
2016-11-28 14:34:08 +01:00
|
|
|
}
|
2019-07-12 20:13:16 +02:00
|
|
|
} else if (SystemZ::GR64BitRegClass.hasSubClassEq(RC)) {
|
|
|
|
if (STI.hasMiscellaneousExtensions3())
|
|
|
|
Opc = SystemZ::SELGR;
|
|
|
|
else
|
|
|
|
Opc = SystemZ::LOCGR;
|
|
|
|
} else
|
2016-11-28 14:34:08 +01:00
|
|
|
llvm_unreachable("Invalid register class");
|
|
|
|
|
|
|
|
BuildMI(MBB, I, DL, get(Opc), DstReg)
|
|
|
|
.addReg(FalseReg).addReg(TrueReg)
|
|
|
|
.addImm(CCValid).addImm(CCMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SystemZInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
|
2020-04-03 19:22:51 +02:00
|
|
|
Register Reg,
|
2016-11-28 14:34:08 +01:00
|
|
|
MachineRegisterInfo *MRI) const {
|
|
|
|
unsigned DefOpc = DefMI.getOpcode();
|
|
|
|
if (DefOpc != SystemZ::LHIMux && DefOpc != SystemZ::LHI &&
|
|
|
|
DefOpc != SystemZ::LGHI)
|
|
|
|
return false;
|
|
|
|
if (DefMI.getOperand(0).getReg() != Reg)
|
|
|
|
return false;
|
|
|
|
int32_t ImmVal = (int32_t)DefMI.getOperand(1).getImm();
|
|
|
|
|
|
|
|
unsigned UseOpc = UseMI.getOpcode();
|
|
|
|
unsigned NewUseOpc;
|
|
|
|
unsigned UseIdx;
|
|
|
|
int CommuteIdx = -1;
|
2019-07-12 20:13:16 +02:00
|
|
|
bool TieOps = false;
|
2016-11-28 14:34:08 +01:00
|
|
|
switch (UseOpc) {
|
2019-07-12 20:13:16 +02:00
|
|
|
case SystemZ::SELRMux:
|
|
|
|
TieOps = true;
|
2019-07-12 20:44:51 +02:00
|
|
|
LLVM_FALLTHROUGH;
|
2016-11-28 14:34:08 +01:00
|
|
|
case SystemZ::LOCRMux:
|
|
|
|
if (!STI.hasLoadStoreOnCond2())
|
|
|
|
return false;
|
|
|
|
NewUseOpc = SystemZ::LOCHIMux;
|
|
|
|
if (UseMI.getOperand(2).getReg() == Reg)
|
|
|
|
UseIdx = 2;
|
|
|
|
else if (UseMI.getOperand(1).getReg() == Reg)
|
|
|
|
UseIdx = 2, CommuteIdx = 1;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
break;
|
2019-07-12 20:13:16 +02:00
|
|
|
case SystemZ::SELGR:
|
|
|
|
TieOps = true;
|
2019-07-12 20:44:51 +02:00
|
|
|
LLVM_FALLTHROUGH;
|
2016-11-28 14:34:08 +01:00
|
|
|
case SystemZ::LOCGR:
|
|
|
|
if (!STI.hasLoadStoreOnCond2())
|
|
|
|
return false;
|
|
|
|
NewUseOpc = SystemZ::LOCGHI;
|
|
|
|
if (UseMI.getOperand(2).getReg() == Reg)
|
|
|
|
UseIdx = 2;
|
|
|
|
else if (UseMI.getOperand(1).getReg() == Reg)
|
|
|
|
UseIdx = 2, CommuteIdx = 1;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
2016-07-11 20:45:03 +02:00
|
|
|
}
|
2016-11-28 14:34:08 +01:00
|
|
|
|
|
|
|
if (CommuteIdx != -1)
|
|
|
|
if (!commuteInstruction(UseMI, false, CommuteIdx, UseIdx))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool DeleteDef = MRI->hasOneNonDBGUse(Reg);
|
|
|
|
UseMI.setDesc(get(NewUseOpc));
|
2019-07-12 20:13:16 +02:00
|
|
|
if (TieOps)
|
|
|
|
UseMI.tieOperands(0, 1);
|
2016-11-28 14:34:08 +01:00
|
|
|
UseMI.getOperand(UseIdx).ChangeToImmediate(ImmVal);
|
|
|
|
if (DeleteDef)
|
|
|
|
DefMI.eraseFromParent();
|
|
|
|
|
|
|
|
return true;
|
2016-07-11 20:45:03 +02:00
|
|
|
}
|
|
|
|
|
2017-03-03 19:30:54 +01:00
|
|
|
bool SystemZInstrInfo::isPredicable(const MachineInstr &MI) const {
|
2016-02-23 03:46:52 +01:00
|
|
|
unsigned Opcode = MI.getOpcode();
|
2016-04-08 19:22:19 +02:00
|
|
|
if (Opcode == SystemZ::Return ||
|
2016-06-10 21:58:10 +02:00
|
|
|
Opcode == SystemZ::Trap ||
|
2016-04-11 14:12:32 +02:00
|
|
|
Opcode == SystemZ::CallJG ||
|
|
|
|
Opcode == SystemZ::CallBR)
|
2016-04-07 18:11:44 +02:00
|
|
|
return true;
|
|
|
|
return false;
|
2013-07-25 11:11:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool SystemZInstrInfo::
|
|
|
|
isProfitableToIfCvt(MachineBasicBlock &MBB,
|
|
|
|
unsigned NumCycles, unsigned ExtraPredCycles,
|
2015-09-11 01:10:42 +02:00
|
|
|
BranchProbability Probability) const {
|
2016-04-07 18:11:44 +02:00
|
|
|
// Avoid using conditional returns at the end of a loop (since then
|
|
|
|
// we'd need to emit an unconditional branch to the beginning anyway,
|
|
|
|
// making the loop body longer). This doesn't apply for low-probability
|
|
|
|
// loops (eg. compare-and-swap retry), so just decide based on branch
|
|
|
|
// probability instead of looping structure.
|
2016-06-10 21:58:10 +02:00
|
|
|
// However, since Compare and Trap instructions cost the same as a regular
|
|
|
|
// Compare instruction, we should allow the if conversion to convert this
|
|
|
|
// into a Conditional Compare regardless of the branch probability.
|
|
|
|
if (MBB.getLastNonDebugInstr()->getOpcode() != SystemZ::Trap &&
|
|
|
|
MBB.succ_empty() && Probability < BranchProbability(1, 8))
|
2016-04-07 18:11:44 +02:00
|
|
|
return false;
|
2013-07-25 11:11:15 +02:00
|
|
|
// For now only convert single instructions.
|
|
|
|
return NumCycles == 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SystemZInstrInfo::
|
|
|
|
isProfitableToIfCvt(MachineBasicBlock &TMBB,
|
|
|
|
unsigned NumCyclesT, unsigned ExtraPredCyclesT,
|
|
|
|
MachineBasicBlock &FMBB,
|
|
|
|
unsigned NumCyclesF, unsigned ExtraPredCyclesF,
|
2015-09-11 01:10:42 +02:00
|
|
|
BranchProbability Probability) const {
|
2013-07-25 11:11:15 +02:00
|
|
|
// For now avoid converting mutually-exclusive cases.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-04-07 18:11:44 +02:00
|
|
|
bool SystemZInstrInfo::
|
|
|
|
isProfitableToDupForIfCvt(MachineBasicBlock &MBB, unsigned NumCycles,
|
|
|
|
BranchProbability Probability) const {
|
|
|
|
// For now only duplicate single instructions.
|
|
|
|
return NumCycles == 1;
|
|
|
|
}
|
|
|
|
|
2016-02-23 03:46:52 +01:00
|
|
|
bool SystemZInstrInfo::PredicateInstruction(
|
|
|
|
MachineInstr &MI, ArrayRef<MachineOperand> Pred) const {
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
assert(Pred.size() == 2 && "Invalid condition");
|
|
|
|
unsigned CCValid = Pred[0].getImm();
|
|
|
|
unsigned CCMask = Pred[1].getImm();
|
2013-07-25 11:11:15 +02:00
|
|
|
assert(CCMask > 0 && CCMask < 15 && "Invalid predicate");
|
2016-02-23 03:46:52 +01:00
|
|
|
unsigned Opcode = MI.getOpcode();
|
2016-06-10 21:58:10 +02:00
|
|
|
if (Opcode == SystemZ::Trap) {
|
|
|
|
MI.setDesc(get(SystemZ::CondTrap));
|
|
|
|
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
|
|
|
|
.addImm(CCValid).addImm(CCMask)
|
|
|
|
.addReg(SystemZ::CC, RegState::Implicit);
|
|
|
|
return true;
|
|
|
|
}
|
2016-04-07 18:11:44 +02:00
|
|
|
if (Opcode == SystemZ::Return) {
|
|
|
|
MI.setDesc(get(SystemZ::CondReturn));
|
|
|
|
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
|
|
|
|
.addImm(CCValid).addImm(CCMask)
|
|
|
|
.addReg(SystemZ::CC, RegState::Implicit);
|
|
|
|
return true;
|
|
|
|
}
|
2016-04-08 19:22:19 +02:00
|
|
|
if (Opcode == SystemZ::CallJG) {
|
2016-07-07 17:34:46 +02:00
|
|
|
MachineOperand FirstOp = MI.getOperand(0);
|
2016-04-08 19:22:19 +02:00
|
|
|
const uint32_t *RegMask = MI.getOperand(1).getRegMask();
|
|
|
|
MI.RemoveOperand(1);
|
|
|
|
MI.RemoveOperand(0);
|
|
|
|
MI.setDesc(get(SystemZ::CallBRCL));
|
|
|
|
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
|
2017-01-13 10:58:52 +01:00
|
|
|
.addImm(CCValid)
|
|
|
|
.addImm(CCMask)
|
|
|
|
.add(FirstOp)
|
|
|
|
.addRegMask(RegMask)
|
|
|
|
.addReg(SystemZ::CC, RegState::Implicit);
|
2016-04-08 19:22:19 +02:00
|
|
|
return true;
|
|
|
|
}
|
2016-04-11 14:12:32 +02:00
|
|
|
if (Opcode == SystemZ::CallBR) {
|
2020-12-15 16:18:43 +01:00
|
|
|
MachineOperand Target = MI.getOperand(0);
|
|
|
|
const uint32_t *RegMask = MI.getOperand(1).getRegMask();
|
|
|
|
MI.RemoveOperand(1);
|
2016-04-11 14:12:32 +02:00
|
|
|
MI.RemoveOperand(0);
|
|
|
|
MI.setDesc(get(SystemZ::CallBCR));
|
|
|
|
MachineInstrBuilder(*MI.getParent()->getParent(), MI)
|
|
|
|
.addImm(CCValid).addImm(CCMask)
|
2020-12-15 16:18:43 +01:00
|
|
|
.add(Target)
|
2016-04-11 14:12:32 +02:00
|
|
|
.addRegMask(RegMask)
|
|
|
|
.addReg(SystemZ::CC, RegState::Implicit);
|
|
|
|
return true;
|
|
|
|
}
|
2013-07-25 11:11:15 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-09-22 13:15:07 +02:00
|
|
|
void SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock::iterator MBBI,
|
2019-11-11 09:24:21 +01:00
|
|
|
const DebugLoc &DL, MCRegister DestReg,
|
|
|
|
MCRegister SrcReg, bool KillSrc) const {
|
2017-05-04 15:33:30 +02:00
|
|
|
// Split 128-bit GPR moves into two 64-bit moves. Add implicit uses of the
|
|
|
|
// super register in case one of the subregs is undefined.
|
|
|
|
// This handles ADDR128 too.
|
2013-05-06 18:15:19 +02:00
|
|
|
if (SystemZ::GR128BitRegClass.contains(DestReg, SrcReg)) {
|
2013-09-30 12:28:35 +02:00
|
|
|
copyPhysReg(MBB, MBBI, DL, RI.getSubReg(DestReg, SystemZ::subreg_h64),
|
|
|
|
RI.getSubReg(SrcReg, SystemZ::subreg_h64), KillSrc);
|
2017-05-04 15:33:30 +02:00
|
|
|
MachineInstrBuilder(*MBB.getParent(), std::prev(MBBI))
|
|
|
|
.addReg(SrcReg, RegState::Implicit);
|
2013-09-30 12:28:35 +02:00
|
|
|
copyPhysReg(MBB, MBBI, DL, RI.getSubReg(DestReg, SystemZ::subreg_l64),
|
|
|
|
RI.getSubReg(SrcReg, SystemZ::subreg_l64), KillSrc);
|
2017-05-04 15:33:30 +02:00
|
|
|
MachineInstrBuilder(*MBB.getParent(), std::prev(MBBI))
|
|
|
|
.addReg(SrcReg, (getKillRegState(KillSrc) | RegState::Implicit));
|
2013-05-06 18:15:19 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-10-01 13:26:28 +02:00
|
|
|
if (SystemZ::GRX32BitRegClass.contains(DestReg, SrcReg)) {
|
2017-01-18 09:32:54 +01:00
|
|
|
emitGRX32Move(MBB, MBBI, DL, DestReg, SrcReg, SystemZ::LR, 32, KillSrc,
|
|
|
|
false);
|
2013-10-01 13:26:28 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-17 19:44:20 +02:00
|
|
|
// Move 128-bit floating-point values between VR128 and FP128.
|
|
|
|
if (SystemZ::VR128BitRegClass.contains(DestReg) &&
|
|
|
|
SystemZ::FP128BitRegClass.contains(SrcReg)) {
|
2019-11-11 09:24:21 +01:00
|
|
|
MCRegister SrcRegHi =
|
|
|
|
RI.getMatchingSuperReg(RI.getSubReg(SrcReg, SystemZ::subreg_h64),
|
|
|
|
SystemZ::subreg_h64, &SystemZ::VR128BitRegClass);
|
|
|
|
MCRegister SrcRegLo =
|
|
|
|
RI.getMatchingSuperReg(RI.getSubReg(SrcReg, SystemZ::subreg_l64),
|
|
|
|
SystemZ::subreg_h64, &SystemZ::VR128BitRegClass);
|
2017-07-17 19:44:20 +02:00
|
|
|
|
|
|
|
BuildMI(MBB, MBBI, DL, get(SystemZ::VMRHG), DestReg)
|
|
|
|
.addReg(SrcRegHi, getKillRegState(KillSrc))
|
|
|
|
.addReg(SrcRegLo, getKillRegState(KillSrc));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (SystemZ::FP128BitRegClass.contains(DestReg) &&
|
|
|
|
SystemZ::VR128BitRegClass.contains(SrcReg)) {
|
2019-11-11 09:24:21 +01:00
|
|
|
MCRegister DestRegHi =
|
|
|
|
RI.getMatchingSuperReg(RI.getSubReg(DestReg, SystemZ::subreg_h64),
|
|
|
|
SystemZ::subreg_h64, &SystemZ::VR128BitRegClass);
|
|
|
|
MCRegister DestRegLo =
|
|
|
|
RI.getMatchingSuperReg(RI.getSubReg(DestReg, SystemZ::subreg_l64),
|
|
|
|
SystemZ::subreg_h64, &SystemZ::VR128BitRegClass);
|
2017-07-17 19:44:20 +02:00
|
|
|
|
|
|
|
if (DestRegHi != SrcReg)
|
|
|
|
copyPhysReg(MBB, MBBI, DL, DestRegHi, SrcReg, false);
|
|
|
|
BuildMI(MBB, MBBI, DL, get(SystemZ::VREPG), DestRegLo)
|
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc)).addImm(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-21 02:42:51 +01:00
|
|
|
// Move CC value from a GR32.
|
2018-04-30 19:52:32 +02:00
|
|
|
if (DestReg == SystemZ::CC) {
|
2020-02-21 02:42:51 +01:00
|
|
|
unsigned Opcode =
|
|
|
|
SystemZ::GR32BitRegClass.contains(SrcReg) ? SystemZ::TMLH : SystemZ::TMHH;
|
|
|
|
BuildMI(MBB, MBBI, DL, get(Opcode))
|
2018-04-30 19:52:32 +02:00
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc))
|
|
|
|
.addImm(3 << (SystemZ::IPM_CC - 16));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-06 18:15:19 +02:00
|
|
|
// Everything else needs only one instruction.
|
|
|
|
unsigned Opcode;
|
2013-10-01 13:26:28 +02:00
|
|
|
if (SystemZ::GR64BitRegClass.contains(DestReg, SrcReg))
|
2013-05-06 18:15:19 +02:00
|
|
|
Opcode = SystemZ::LGR;
|
|
|
|
else if (SystemZ::FP32BitRegClass.contains(DestReg, SrcReg))
|
2016-03-14 14:50:03 +01:00
|
|
|
// For z13 we prefer LDR over LER to avoid partial register dependencies.
|
|
|
|
Opcode = STI.hasVector() ? SystemZ::LDR32 : SystemZ::LER;
|
2013-05-06 18:15:19 +02:00
|
|
|
else if (SystemZ::FP64BitRegClass.contains(DestReg, SrcReg))
|
|
|
|
Opcode = SystemZ::LDR;
|
|
|
|
else if (SystemZ::FP128BitRegClass.contains(DestReg, SrcReg))
|
|
|
|
Opcode = SystemZ::LXR;
|
2015-05-05 21:28:34 +02:00
|
|
|
else if (SystemZ::VR32BitRegClass.contains(DestReg, SrcReg))
|
|
|
|
Opcode = SystemZ::VLR32;
|
|
|
|
else if (SystemZ::VR64BitRegClass.contains(DestReg, SrcReg))
|
|
|
|
Opcode = SystemZ::VLR64;
|
[SystemZ] Add CodeGen support for integer vector types
This the first of a series of patches to add CodeGen support exploiting
the instructions of the z13 vector facility. This patch adds support
for the native integer vector types (v16i8, v8i16, v4i32, v2i64).
When the vector facility is present, we default to the new vector ABI.
This is characterized by two major differences:
- Vector types are passed/returned in vector registers
(except for unnamed arguments of a variable-argument list function).
- Vector types are at most 8-byte aligned.
The reason for the choice of 8-byte vector alignment is that the hardware
is able to efficiently load vectors at 8-byte alignment, and the ABI only
guarantees 8-byte alignment of the stack pointer, so requiring any higher
alignment for vectors would require dynamic stack re-alignment code.
However, for compatibility with old code that may use vector types, when
*not* using the vector facility, the old alignment rules (vector types
are naturally aligned) remain in use.
These alignment rules are not only implemented at the C language level
(implemented in clang), but also at the LLVM IR level. This is done
by selecting a different DataLayout string depending on whether the
vector ABI is in effect or not.
Based on a patch by Richard Sandiford.
llvm-svn: 236521
2015-05-05 21:25:42 +02:00
|
|
|
else if (SystemZ::VR128BitRegClass.contains(DestReg, SrcReg))
|
|
|
|
Opcode = SystemZ::VLR;
|
2016-11-08 21:15:26 +01:00
|
|
|
else if (SystemZ::AR32BitRegClass.contains(DestReg, SrcReg))
|
|
|
|
Opcode = SystemZ::CPYA;
|
2013-05-06 18:15:19 +02:00
|
|
|
else
|
|
|
|
llvm_unreachable("Impossible reg-to-reg copy");
|
|
|
|
|
|
|
|
BuildMI(MBB, MBBI, DL, get(Opcode), DestReg)
|
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc));
|
|
|
|
}
|
|
|
|
|
2015-09-22 13:15:07 +02:00
|
|
|
void SystemZInstrInfo::storeRegToStackSlot(
|
[NFC] unsigned->Register in storeRegTo/loadRegFromStack
Summary:
This patch makes progress on the 'unsigned -> Register' rewrite for
`TargetInstrInfo::loadRegFromStack` and `TII::storeRegToStack`.
Reviewers: arsenm, craig.topper, uweigand, jpienaar, atanasyan, venkatra, robertlytton, dylanmckay, t.p.northover, kparzysz, tstellar, k-ishizaka
Reviewed By: arsenm
Subscribers: wuzish, merge_guards_bot, jyknight, sdardis, nemanjai, jvesely, wdng, nhaehnle, hiraditya, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, Jim, lenary, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73870
2020-02-03 14:22:06 +01:00
|
|
|
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg,
|
2015-09-22 13:15:07 +02:00
|
|
|
bool isKill, int FrameIdx, const TargetRegisterClass *RC,
|
|
|
|
const TargetRegisterInfo *TRI) const {
|
2013-05-06 18:15:19 +02:00
|
|
|
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
|
|
|
|
|
|
|
|
// Callers may expect a single instruction, so keep 128-bit moves
|
|
|
|
// together for now and lower them after register allocation.
|
|
|
|
unsigned LoadOpcode, StoreOpcode;
|
|
|
|
getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode);
|
|
|
|
addFrameReference(BuildMI(MBB, MBBI, DL, get(StoreOpcode))
|
2015-09-22 13:15:07 +02:00
|
|
|
.addReg(SrcReg, getKillRegState(isKill)),
|
|
|
|
FrameIdx);
|
2013-05-06 18:15:19 +02:00
|
|
|
}
|
|
|
|
|
2015-09-22 13:15:07 +02:00
|
|
|
void SystemZInstrInfo::loadRegFromStackSlot(
|
[NFC] unsigned->Register in storeRegTo/loadRegFromStack
Summary:
This patch makes progress on the 'unsigned -> Register' rewrite for
`TargetInstrInfo::loadRegFromStack` and `TII::storeRegToStack`.
Reviewers: arsenm, craig.topper, uweigand, jpienaar, atanasyan, venkatra, robertlytton, dylanmckay, t.p.northover, kparzysz, tstellar, k-ishizaka
Reviewed By: arsenm
Subscribers: wuzish, merge_guards_bot, jyknight, sdardis, nemanjai, jvesely, wdng, nhaehnle, hiraditya, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, Jim, lenary, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73870
2020-02-03 14:22:06 +01:00
|
|
|
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register DestReg,
|
2015-09-22 13:15:07 +02:00
|
|
|
int FrameIdx, const TargetRegisterClass *RC,
|
|
|
|
const TargetRegisterInfo *TRI) const {
|
2013-05-06 18:15:19 +02:00
|
|
|
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
|
|
|
|
|
|
|
|
// Callers may expect a single instruction, so keep 128-bit moves
|
|
|
|
// together for now and lower them after register allocation.
|
|
|
|
unsigned LoadOpcode, StoreOpcode;
|
|
|
|
getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode);
|
|
|
|
addFrameReference(BuildMI(MBB, MBBI, DL, get(LoadOpcode), DestReg),
|
|
|
|
FrameIdx);
|
|
|
|
}
|
|
|
|
|
2013-07-02 17:28:56 +02:00
|
|
|
// Return true if MI is a simple load or store with a 12-bit displacement
|
|
|
|
// and no index. Flag is SimpleBDXLoad for loads and SimpleBDXStore for stores.
|
|
|
|
static bool isSimpleBD12Move(const MachineInstr *MI, unsigned Flag) {
|
|
|
|
const MCInstrDesc &MCID = MI->getDesc();
|
|
|
|
return ((MCID.TSFlags & Flag) &&
|
|
|
|
isUInt<12>(MI->getOperand(2).getImm()) &&
|
|
|
|
MI->getOperand(3).getReg() == 0);
|
|
|
|
}
|
|
|
|
|
2013-07-31 13:36:35 +02:00
|
|
|
namespace {
|
2017-01-24 23:10:43 +01:00
|
|
|
|
2014-03-06 11:38:30 +01:00
|
|
|
struct LogicOp {
|
2017-01-24 23:10:43 +01:00
|
|
|
LogicOp() = default;
|
2014-03-06 11:38:30 +01:00
|
|
|
LogicOp(unsigned regSize, unsigned immLSB, unsigned immSize)
|
|
|
|
: RegSize(regSize), ImmLSB(immLSB), ImmSize(immSize) {}
|
2013-07-31 13:36:35 +02:00
|
|
|
|
2015-02-15 23:00:20 +01:00
|
|
|
explicit operator bool() const { return RegSize; }
|
2013-07-31 13:36:35 +02:00
|
|
|
|
2017-01-24 23:10:43 +01:00
|
|
|
unsigned RegSize = 0;
|
|
|
|
unsigned ImmLSB = 0;
|
|
|
|
unsigned ImmSize = 0;
|
2014-03-06 11:38:30 +01:00
|
|
|
};
|
2017-01-24 23:10:43 +01:00
|
|
|
|
2014-03-06 11:38:30 +01:00
|
|
|
} // end anonymous namespace
|
2013-07-31 13:36:35 +02:00
|
|
|
|
|
|
|
static LogicOp interpretAndImmediate(unsigned Opcode) {
|
|
|
|
switch (Opcode) {
|
2013-10-01 16:20:41 +02:00
|
|
|
case SystemZ::NILMux: return LogicOp(32, 0, 16);
|
|
|
|
case SystemZ::NIHMux: return LogicOp(32, 16, 16);
|
2013-09-25 13:11:53 +02:00
|
|
|
case SystemZ::NILL64: return LogicOp(64, 0, 16);
|
|
|
|
case SystemZ::NILH64: return LogicOp(64, 16, 16);
|
2013-10-01 16:20:41 +02:00
|
|
|
case SystemZ::NIHL64: return LogicOp(64, 32, 16);
|
|
|
|
case SystemZ::NIHH64: return LogicOp(64, 48, 16);
|
|
|
|
case SystemZ::NIFMux: return LogicOp(32, 0, 32);
|
2013-09-25 13:11:53 +02:00
|
|
|
case SystemZ::NILF64: return LogicOp(64, 0, 32);
|
2013-10-01 16:20:41 +02:00
|
|
|
case SystemZ::NIHF64: return LogicOp(64, 32, 32);
|
2013-07-31 13:36:35 +02:00
|
|
|
default: return LogicOp();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-02 11:37:40 +02:00
|
|
|
static void transferDeadCC(MachineInstr *OldMI, MachineInstr *NewMI) {
|
|
|
|
if (OldMI->registerDefIsDead(SystemZ::CC)) {
|
|
|
|
MachineOperand *CCDef = NewMI->findRegisterDefOperand(SystemZ::CC);
|
|
|
|
if (CCDef != nullptr)
|
|
|
|
CCDef->setIsDead(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-17 19:14:34 +01:00
|
|
|
static void transferMIFlag(MachineInstr *OldMI, MachineInstr *NewMI,
|
|
|
|
MachineInstr::MIFlag Flag) {
|
|
|
|
if (OldMI->getFlag(Flag))
|
|
|
|
NewMI->setFlag(Flag);
|
|
|
|
}
|
|
|
|
|
2016-06-30 02:01:54 +02:00
|
|
|
MachineInstr *SystemZInstrInfo::convertToThreeAddress(
|
|
|
|
MachineFunction::iterator &MFI, MachineInstr &MI, LiveVariables *LV) const {
|
|
|
|
MachineBasicBlock *MBB = MI.getParent();
|
2013-07-31 13:36:35 +02:00
|
|
|
|
|
|
|
// Try to convert an AND into an RISBG-type instruction.
|
2019-06-08 08:19:15 +02:00
|
|
|
// TODO: It might be beneficial to select RISBG and shorten to AND instead.
|
|
|
|
if (LogicOp And = interpretAndImmediate(MI.getOpcode())) {
|
2016-06-30 02:01:54 +02:00
|
|
|
uint64_t Imm = MI.getOperand(2).getImm() << And.ImmLSB;
|
2013-10-01 16:20:41 +02:00
|
|
|
// AND IMMEDIATE leaves the other bits of the register unchanged.
|
|
|
|
Imm |= allOnes(And.RegSize) & ~(allOnes(And.ImmSize) << And.ImmLSB);
|
|
|
|
unsigned Start, End;
|
|
|
|
if (isRxSBGMask(Imm, And.RegSize, Start, End)) {
|
|
|
|
unsigned NewOpcode;
|
2015-03-31 14:58:17 +02:00
|
|
|
if (And.RegSize == 64) {
|
2013-10-01 16:20:41 +02:00
|
|
|
NewOpcode = SystemZ::RISBG;
|
2015-03-31 14:58:17 +02:00
|
|
|
// Prefer RISBGN if available, since it does not clobber CC.
|
|
|
|
if (STI.hasMiscellaneousExtensions())
|
|
|
|
NewOpcode = SystemZ::RISBGN;
|
|
|
|
} else {
|
2013-10-01 16:20:41 +02:00
|
|
|
NewOpcode = SystemZ::RISBMux;
|
|
|
|
Start &= 31;
|
|
|
|
End &= 31;
|
2013-07-19 18:12:08 +02:00
|
|
|
}
|
2016-06-30 02:01:54 +02:00
|
|
|
MachineOperand &Dest = MI.getOperand(0);
|
|
|
|
MachineOperand &Src = MI.getOperand(1);
|
2013-10-01 16:20:41 +02:00
|
|
|
MachineInstrBuilder MIB =
|
2016-06-30 02:01:54 +02:00
|
|
|
BuildMI(*MBB, MI, MI.getDebugLoc(), get(NewOpcode))
|
2017-01-13 10:58:52 +01:00
|
|
|
.add(Dest)
|
2016-06-30 02:01:54 +02:00
|
|
|
.addReg(0)
|
|
|
|
.addReg(Src.getReg(), getKillRegState(Src.isKill()),
|
|
|
|
Src.getSubReg())
|
|
|
|
.addImm(Start)
|
|
|
|
.addImm(End + 128)
|
|
|
|
.addImm(0);
|
2019-06-08 08:19:15 +02:00
|
|
|
if (LV) {
|
|
|
|
unsigned NumOps = MI.getNumOperands();
|
|
|
|
for (unsigned I = 1; I < NumOps; ++I) {
|
|
|
|
MachineOperand &Op = MI.getOperand(I);
|
|
|
|
if (Op.isReg() && Op.isKill())
|
|
|
|
LV->replaceKillInstruction(Op.getReg(), MI, *MIB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
transferDeadCC(&MI, MIB);
|
|
|
|
return MIB;
|
2013-07-19 18:12:08 +02:00
|
|
|
}
|
|
|
|
}
|
2014-04-25 07:30:21 +02:00
|
|
|
return nullptr;
|
2013-07-19 18:12:08 +02:00
|
|
|
}
|
|
|
|
|
2015-06-08 22:09:58 +02:00
|
|
|
MachineInstr *SystemZInstrInfo::foldMemoryOperandImpl(
|
2016-06-30 02:01:54 +02:00
|
|
|
MachineFunction &MF, MachineInstr &MI, ArrayRef<unsigned> Ops,
|
2016-05-10 10:09:37 +02:00
|
|
|
MachineBasicBlock::iterator InsertPt, int FrameIndex,
|
2019-06-08 08:19:15 +02:00
|
|
|
LiveIntervals *LIS, VirtRegMap *VRM) const {
|
2016-05-10 10:09:37 +02:00
|
|
|
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
|
2020-03-18 18:11:56 +01:00
|
|
|
MachineRegisterInfo &MRI = MF.getRegInfo();
|
2016-07-28 20:40:00 +02:00
|
|
|
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
|
|
|
unsigned Size = MFI.getObjectSize(FrameIndex);
|
2016-06-30 02:01:54 +02:00
|
|
|
unsigned Opcode = MI.getOpcode();
|
2013-10-15 10:42:59 +02:00
|
|
|
|
2020-03-18 18:11:56 +01:00
|
|
|
// Check CC liveness if new instruction introduces a dead def of CC.
|
2020-11-04 22:28:13 +01:00
|
|
|
MCRegUnitIterator CCUnit(MCRegister::from(SystemZ::CC), TRI);
|
2020-03-18 18:11:56 +01:00
|
|
|
SlotIndex MISlot = SlotIndex();
|
|
|
|
LiveRange *CCLiveRange = nullptr;
|
|
|
|
bool CCLiveAtMI = true;
|
|
|
|
if (LIS) {
|
|
|
|
MISlot = LIS->getSlotIndexes()->getInstructionIndex(MI).getRegSlot();
|
|
|
|
CCLiveRange = &LIS->getRegUnit(*CCUnit);
|
|
|
|
CCLiveAtMI = CCLiveRange->liveAt(MISlot);
|
|
|
|
}
|
|
|
|
++CCUnit;
|
|
|
|
assert(!CCUnit.isValid() && "CC only has one reg unit.");
|
|
|
|
|
2013-10-15 10:42:59 +02:00
|
|
|
if (Ops.size() == 2 && Ops[0] == 0 && Ops[1] == 1) {
|
2020-03-18 18:11:56 +01:00
|
|
|
if (!CCLiveAtMI && (Opcode == SystemZ::LA || Opcode == SystemZ::LAY) &&
|
2016-06-30 02:01:54 +02:00
|
|
|
isInt<8>(MI.getOperand(2).getImm()) && !MI.getOperand(3).getReg()) {
|
2020-03-18 18:11:56 +01:00
|
|
|
// LA(Y) %reg, CONST(%reg) -> AGSI %mem, CONST
|
|
|
|
MachineInstr *BuiltMI = BuildMI(*InsertPt->getParent(), InsertPt,
|
|
|
|
MI.getDebugLoc(), get(SystemZ::AGSI))
|
|
|
|
.addFrameIndex(FrameIndex)
|
|
|
|
.addImm(0)
|
|
|
|
.addImm(MI.getOperand(2).getImm());
|
|
|
|
BuiltMI->findRegisterDefOperand(SystemZ::CC)->setIsDead(true);
|
|
|
|
CCLiveRange->createDeadDef(MISlot, LIS->getVNInfoAllocator());
|
|
|
|
return BuiltMI;
|
2013-10-15 10:42:59 +02:00
|
|
|
}
|
2014-04-25 07:30:21 +02:00
|
|
|
return nullptr;
|
2013-10-15 10:42:59 +02:00
|
|
|
}
|
2013-07-02 17:28:56 +02:00
|
|
|
|
2013-10-15 10:42:59 +02:00
|
|
|
// All other cases require a single operand.
|
2013-07-02 17:28:56 +02:00
|
|
|
if (Ops.size() != 1)
|
2014-04-25 07:30:21 +02:00
|
|
|
return nullptr;
|
2013-07-02 17:28:56 +02:00
|
|
|
|
|
|
|
unsigned OpNum = Ops[0];
|
2017-04-24 20:55:33 +02:00
|
|
|
assert(Size * 8 ==
|
|
|
|
TRI->getRegSizeInBits(*MF.getRegInfo()
|
|
|
|
.getRegClass(MI.getOperand(OpNum).getReg())) &&
|
2013-07-02 23:17:31 +02:00
|
|
|
"Invalid size combination");
|
2013-07-02 17:28:56 +02:00
|
|
|
|
2016-06-30 02:01:54 +02:00
|
|
|
if ((Opcode == SystemZ::AHI || Opcode == SystemZ::AGHI) && OpNum == 0 &&
|
|
|
|
isInt<8>(MI.getOperand(2).getImm())) {
|
2013-10-15 10:42:59 +02:00
|
|
|
// A(G)HI %reg, CONST -> A(G)SI %mem, CONST
|
|
|
|
Opcode = (Opcode == SystemZ::AHI ? SystemZ::ASI : SystemZ::AGSI);
|
2016-05-02 11:37:40 +02:00
|
|
|
MachineInstr *BuiltMI =
|
2016-06-30 02:01:54 +02:00
|
|
|
BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), get(Opcode))
|
|
|
|
.addFrameIndex(FrameIndex)
|
|
|
|
.addImm(0)
|
|
|
|
.addImm(MI.getOperand(2).getImm());
|
|
|
|
transferDeadCC(&MI, BuiltMI);
|
2019-12-17 19:14:34 +01:00
|
|
|
transferMIFlag(&MI, BuiltMI, MachineInstr::NoSWrap);
|
2016-05-02 11:37:40 +02:00
|
|
|
return BuiltMI;
|
2013-10-15 10:42:59 +02:00
|
|
|
}
|
|
|
|
|
2018-04-30 19:54:28 +02:00
|
|
|
if ((Opcode == SystemZ::ALFI && OpNum == 0 &&
|
|
|
|
isInt<8>((int32_t)MI.getOperand(2).getImm())) ||
|
|
|
|
(Opcode == SystemZ::ALGFI && OpNum == 0 &&
|
|
|
|
isInt<8>((int64_t)MI.getOperand(2).getImm()))) {
|
|
|
|
// AL(G)FI %reg, CONST -> AL(G)SI %mem, CONST
|
|
|
|
Opcode = (Opcode == SystemZ::ALFI ? SystemZ::ALSI : SystemZ::ALGSI);
|
|
|
|
MachineInstr *BuiltMI =
|
|
|
|
BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), get(Opcode))
|
|
|
|
.addFrameIndex(FrameIndex)
|
|
|
|
.addImm(0)
|
|
|
|
.addImm((int8_t)MI.getOperand(2).getImm());
|
|
|
|
transferDeadCC(&MI, BuiltMI);
|
|
|
|
return BuiltMI;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((Opcode == SystemZ::SLFI && OpNum == 0 &&
|
|
|
|
isInt<8>((int32_t)-MI.getOperand(2).getImm())) ||
|
|
|
|
(Opcode == SystemZ::SLGFI && OpNum == 0 &&
|
|
|
|
isInt<8>((int64_t)-MI.getOperand(2).getImm()))) {
|
|
|
|
// SL(G)FI %reg, CONST -> AL(G)SI %mem, -CONST
|
|
|
|
Opcode = (Opcode == SystemZ::SLFI ? SystemZ::ALSI : SystemZ::ALGSI);
|
|
|
|
MachineInstr *BuiltMI =
|
|
|
|
BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(), get(Opcode))
|
|
|
|
.addFrameIndex(FrameIndex)
|
|
|
|
.addImm(0)
|
|
|
|
.addImm((int8_t)-MI.getOperand(2).getImm());
|
|
|
|
transferDeadCC(&MI, BuiltMI);
|
|
|
|
return BuiltMI;
|
|
|
|
}
|
|
|
|
|
2020-03-11 15:18:35 +01:00
|
|
|
unsigned MemImmOpc = 0;
|
|
|
|
switch (Opcode) {
|
|
|
|
case SystemZ::LHIMux:
|
|
|
|
case SystemZ::LHI: MemImmOpc = SystemZ::MVHI; break;
|
|
|
|
case SystemZ::LGHI: MemImmOpc = SystemZ::MVGHI; break;
|
|
|
|
case SystemZ::CHIMux:
|
|
|
|
case SystemZ::CHI: MemImmOpc = SystemZ::CHSI; break;
|
|
|
|
case SystemZ::CGHI: MemImmOpc = SystemZ::CGHSI; break;
|
|
|
|
case SystemZ::CLFIMux:
|
|
|
|
case SystemZ::CLFI:
|
|
|
|
if (isUInt<16>(MI.getOperand(1).getImm()))
|
|
|
|
MemImmOpc = SystemZ::CLFHSI;
|
|
|
|
break;
|
|
|
|
case SystemZ::CLGFI:
|
|
|
|
if (isUInt<16>(MI.getOperand(1).getImm()))
|
|
|
|
MemImmOpc = SystemZ::CLGHSI;
|
|
|
|
break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
if (MemImmOpc)
|
|
|
|
return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(),
|
|
|
|
get(MemImmOpc))
|
|
|
|
.addFrameIndex(FrameIndex)
|
|
|
|
.addImm(0)
|
|
|
|
.addImm(MI.getOperand(1).getImm());
|
|
|
|
|
2013-07-12 10:37:17 +02:00
|
|
|
if (Opcode == SystemZ::LGDR || Opcode == SystemZ::LDGR) {
|
|
|
|
bool Op0IsGPR = (Opcode == SystemZ::LGDR);
|
|
|
|
bool Op1IsGPR = (Opcode == SystemZ::LDGR);
|
|
|
|
// If we're spilling the destination of an LDGR or LGDR, store the
|
|
|
|
// source register instead.
|
|
|
|
if (OpNum == 0) {
|
|
|
|
unsigned StoreOpcode = Op1IsGPR ? SystemZ::STG : SystemZ::STD;
|
2016-06-30 02:01:54 +02:00
|
|
|
return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(),
|
2015-06-08 22:09:58 +02:00
|
|
|
get(StoreOpcode))
|
2017-01-13 10:58:52 +01:00
|
|
|
.add(MI.getOperand(1))
|
2015-06-08 22:09:58 +02:00
|
|
|
.addFrameIndex(FrameIndex)
|
|
|
|
.addImm(0)
|
|
|
|
.addReg(0);
|
2013-07-12 10:37:17 +02:00
|
|
|
}
|
|
|
|
// If we're spilling the source of an LDGR or LGDR, load the
|
|
|
|
// destination register instead.
|
|
|
|
if (OpNum == 1) {
|
|
|
|
unsigned LoadOpcode = Op0IsGPR ? SystemZ::LG : SystemZ::LD;
|
2016-06-30 02:01:54 +02:00
|
|
|
return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(),
|
2017-03-21 06:49:40 +01:00
|
|
|
get(LoadOpcode))
|
|
|
|
.add(MI.getOperand(0))
|
|
|
|
.addFrameIndex(FrameIndex)
|
|
|
|
.addImm(0)
|
|
|
|
.addReg(0);
|
2013-07-12 10:37:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-02 17:28:56 +02:00
|
|
|
// Look for cases where the source of a simple store or the destination
|
|
|
|
// of a simple load is being spilled. Try to use MVC instead.
|
|
|
|
//
|
|
|
|
// Although MVC is in practice a fast choice in these cases, it is still
|
|
|
|
// logically a bytewise copy. This means that we cannot use it if the
|
2013-09-27 17:29:20 +02:00
|
|
|
// load or store is volatile. We also wouldn't be able to use MVC if
|
|
|
|
// the two memories partially overlap, but that case cannot occur here,
|
|
|
|
// because we know that one of the memories is a full frame index.
|
|
|
|
//
|
|
|
|
// For performance reasons, we also want to avoid using MVC if the addresses
|
|
|
|
// might be equal. We don't worry about that case here, because spill slot
|
|
|
|
// coloring happens later, and because we have special code to remove
|
|
|
|
// MVCs that turn out to be redundant.
|
2016-06-30 02:01:54 +02:00
|
|
|
if (OpNum == 0 && MI.hasOneMemOperand()) {
|
|
|
|
MachineMemOperand *MMO = *MI.memoperands_begin();
|
2019-02-24 01:45:09 +01:00
|
|
|
if (MMO->getSize() == Size && !MMO->isVolatile() && !MMO->isAtomic()) {
|
2013-07-02 17:28:56 +02:00
|
|
|
// Handle conversion of loads.
|
2016-06-30 02:01:54 +02:00
|
|
|
if (isSimpleBD12Move(&MI, SystemZII::SimpleBDXLoad)) {
|
|
|
|
return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(),
|
2015-06-08 22:09:58 +02:00
|
|
|
get(SystemZ::MVC))
|
|
|
|
.addFrameIndex(FrameIndex)
|
|
|
|
.addImm(0)
|
|
|
|
.addImm(Size)
|
2017-01-13 10:58:52 +01:00
|
|
|
.add(MI.getOperand(1))
|
2016-06-30 02:01:54 +02:00
|
|
|
.addImm(MI.getOperand(2).getImm())
|
2015-06-08 22:09:58 +02:00
|
|
|
.addMemOperand(MMO);
|
2013-07-02 17:28:56 +02:00
|
|
|
}
|
|
|
|
// Handle conversion of stores.
|
2016-06-30 02:01:54 +02:00
|
|
|
if (isSimpleBD12Move(&MI, SystemZII::SimpleBDXStore)) {
|
|
|
|
return BuildMI(*InsertPt->getParent(), InsertPt, MI.getDebugLoc(),
|
2015-06-08 22:09:58 +02:00
|
|
|
get(SystemZ::MVC))
|
2017-01-13 10:58:52 +01:00
|
|
|
.add(MI.getOperand(1))
|
2016-06-30 02:01:54 +02:00
|
|
|
.addImm(MI.getOperand(2).getImm())
|
2015-06-08 22:09:58 +02:00
|
|
|
.addImm(Size)
|
|
|
|
.addFrameIndex(FrameIndex)
|
|
|
|
.addImm(0)
|
|
|
|
.addMemOperand(MMO);
|
2013-07-02 17:28:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-08 08:19:15 +02:00
|
|
|
// If the spilled operand is the final one or the instruction is
|
2020-03-18 18:11:56 +01:00
|
|
|
// commutable, try to change <INSN>R into <INSN>. Don't introduce a def of
|
|
|
|
// CC if it is live and MI does not define it.
|
2019-06-08 08:19:15 +02:00
|
|
|
unsigned NumOps = MI.getNumExplicitOperands();
|
2013-07-12 10:37:17 +02:00
|
|
|
int MemOpcode = SystemZ::getMemOpcode(Opcode);
|
2020-03-18 18:11:56 +01:00
|
|
|
if (MemOpcode == -1 ||
|
|
|
|
(CCLiveAtMI && !MI.definesRegister(SystemZ::CC) &&
|
|
|
|
get(MemOpcode).hasImplicitDefOfPhysReg(SystemZ::CC)))
|
2019-11-05 14:28:13 +01:00
|
|
|
return nullptr;
|
|
|
|
|
2020-03-18 18:11:56 +01:00
|
|
|
// Check if all other vregs have a usable allocation in the case of vector
|
|
|
|
// to FP conversion.
|
|
|
|
const MCInstrDesc &MCID = MI.getDesc();
|
|
|
|
for (unsigned I = 0, E = MCID.getNumOperands(); I != E; ++I) {
|
|
|
|
const MCOperandInfo &MCOI = MCID.OpInfo[I];
|
|
|
|
if (MCOI.OperandType != MCOI::OPERAND_REGISTER || I == OpNum)
|
|
|
|
continue;
|
|
|
|
const TargetRegisterClass *RC = TRI->getRegClass(MCOI.RegClass);
|
|
|
|
if (RC == &SystemZ::VR32BitRegClass || RC == &SystemZ::VR64BitRegClass) {
|
|
|
|
Register Reg = MI.getOperand(I).getReg();
|
|
|
|
Register PhysReg = Register::isVirtualRegister(Reg)
|
2020-10-08 01:11:50 +02:00
|
|
|
? (VRM ? Register(VRM->getPhys(Reg)) : Register())
|
2020-03-18 18:11:56 +01:00
|
|
|
: Reg;
|
|
|
|
if (!PhysReg ||
|
|
|
|
!(SystemZ::FP32BitRegClass.contains(PhysReg) ||
|
|
|
|
SystemZ::FP64BitRegClass.contains(PhysReg) ||
|
|
|
|
SystemZ::VF128BitRegClass.contains(PhysReg)))
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Fused multiply and add/sub need to have the same dst and accumulator reg.
|
|
|
|
bool FusedFPOp = (Opcode == SystemZ::WFMADB || Opcode == SystemZ::WFMASB ||
|
|
|
|
Opcode == SystemZ::WFMSDB || Opcode == SystemZ::WFMSSB);
|
|
|
|
if (FusedFPOp) {
|
|
|
|
Register DstReg = VRM->getPhys(MI.getOperand(0).getReg());
|
|
|
|
Register AccReg = VRM->getPhys(MI.getOperand(3).getReg());
|
|
|
|
if (OpNum == 0 || OpNum == 3 || DstReg != AccReg)
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-11-05 14:28:13 +01:00
|
|
|
// Try to swap compare operands if possible.
|
|
|
|
bool NeedsCommute = false;
|
|
|
|
if ((MI.getOpcode() == SystemZ::CR || MI.getOpcode() == SystemZ::CGR ||
|
2020-03-18 18:11:56 +01:00
|
|
|
MI.getOpcode() == SystemZ::CLR || MI.getOpcode() == SystemZ::CLGR ||
|
|
|
|
MI.getOpcode() == SystemZ::WFCDB || MI.getOpcode() == SystemZ::WFCSB ||
|
|
|
|
MI.getOpcode() == SystemZ::WFKDB || MI.getOpcode() == SystemZ::WFKSB) &&
|
2019-11-05 14:28:13 +01:00
|
|
|
OpNum == 0 && prepareCompareSwapOperands(MI))
|
|
|
|
NeedsCommute = true;
|
|
|
|
|
|
|
|
bool CCOperands = false;
|
|
|
|
if (MI.getOpcode() == SystemZ::LOCRMux || MI.getOpcode() == SystemZ::LOCGR ||
|
|
|
|
MI.getOpcode() == SystemZ::SELRMux || MI.getOpcode() == SystemZ::SELGR) {
|
|
|
|
assert(MI.getNumOperands() == 6 && NumOps == 5 &&
|
|
|
|
"LOCR/SELR instruction operands corrupt?");
|
|
|
|
NumOps -= 2;
|
|
|
|
CCOperands = true;
|
|
|
|
}
|
2019-06-08 08:19:15 +02:00
|
|
|
|
|
|
|
// See if this is a 3-address instruction that is convertible to 2-address
|
|
|
|
// and suitable for folding below. Only try this with virtual registers
|
|
|
|
// and a provided VRM (during regalloc).
|
2020-03-17 13:19:30 +01:00
|
|
|
if (NumOps == 3 && SystemZ::getTargetMemOpcode(MemOpcode) != -1) {
|
2019-06-08 08:19:15 +02:00
|
|
|
if (VRM == nullptr)
|
2019-11-05 14:28:13 +01:00
|
|
|
return nullptr;
|
2019-06-08 08:19:15 +02:00
|
|
|
else {
|
2019-06-24 17:50:29 +02:00
|
|
|
Register DstReg = MI.getOperand(0).getReg();
|
|
|
|
Register DstPhys =
|
2020-10-08 01:11:50 +02:00
|
|
|
(Register::isVirtualRegister(DstReg) ? Register(VRM->getPhys(DstReg))
|
|
|
|
: DstReg);
|
2019-06-24 17:50:29 +02:00
|
|
|
Register SrcReg = (OpNum == 2 ? MI.getOperand(1).getReg()
|
2019-06-08 08:19:15 +02:00
|
|
|
: ((OpNum == 1 && MI.isCommutable())
|
|
|
|
? MI.getOperand(2).getReg()
|
2020-03-17 13:19:30 +01:00
|
|
|
: Register()));
|
2019-06-08 08:19:15 +02:00
|
|
|
if (DstPhys && !SystemZ::GRH32BitRegClass.contains(DstPhys) && SrcReg &&
|
2019-08-02 01:27:28 +02:00
|
|
|
Register::isVirtualRegister(SrcReg) &&
|
|
|
|
DstPhys == VRM->getPhys(SrcReg))
|
2019-06-08 08:19:15 +02:00
|
|
|
NeedsCommute = (OpNum == 1);
|
|
|
|
else
|
2019-11-05 14:28:13 +01:00
|
|
|
return nullptr;
|
2019-06-08 08:19:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-18 18:11:56 +01:00
|
|
|
if ((OpNum == NumOps - 1) || NeedsCommute || FusedFPOp) {
|
2019-11-05 14:28:13 +01:00
|
|
|
const MCInstrDesc &MemDesc = get(MemOpcode);
|
|
|
|
uint64_t AccessBytes = SystemZII::getAccessSize(MemDesc.TSFlags);
|
|
|
|
assert(AccessBytes != 0 && "Size of access should be known");
|
|
|
|
assert(AccessBytes <= Size && "Access outside the frame index");
|
|
|
|
uint64_t Offset = Size - AccessBytes;
|
|
|
|
MachineInstrBuilder MIB = BuildMI(*InsertPt->getParent(), InsertPt,
|
|
|
|
MI.getDebugLoc(), get(MemOpcode));
|
|
|
|
if (MI.isCompare()) {
|
|
|
|
assert(NumOps == 2 && "Expected 2 register operands for a compare.");
|
|
|
|
MIB.add(MI.getOperand(NeedsCommute ? 1 : 0));
|
|
|
|
}
|
2020-03-18 18:11:56 +01:00
|
|
|
else if (FusedFPOp) {
|
|
|
|
MIB.add(MI.getOperand(0));
|
|
|
|
MIB.add(MI.getOperand(3));
|
|
|
|
MIB.add(MI.getOperand(OpNum == 1 ? 2 : 1));
|
|
|
|
}
|
2019-11-05 14:28:13 +01:00
|
|
|
else {
|
2019-06-08 08:19:15 +02:00
|
|
|
MIB.add(MI.getOperand(0));
|
|
|
|
if (NeedsCommute)
|
|
|
|
MIB.add(MI.getOperand(2));
|
|
|
|
else
|
|
|
|
for (unsigned I = 1; I < OpNum; ++I)
|
|
|
|
MIB.add(MI.getOperand(I));
|
2013-07-03 12:10:02 +02:00
|
|
|
}
|
2019-11-05 14:28:13 +01:00
|
|
|
MIB.addFrameIndex(FrameIndex).addImm(Offset);
|
|
|
|
if (MemDesc.TSFlags & SystemZII::HasIndex)
|
|
|
|
MIB.addReg(0);
|
|
|
|
if (CCOperands) {
|
|
|
|
unsigned CCValid = MI.getOperand(NumOps).getImm();
|
|
|
|
unsigned CCMask = MI.getOperand(NumOps + 1).getImm();
|
|
|
|
MIB.addImm(CCValid);
|
|
|
|
MIB.addImm(NeedsCommute ? CCMask ^ CCValid : CCMask);
|
|
|
|
}
|
2020-03-18 18:11:56 +01:00
|
|
|
if (MIB->definesRegister(SystemZ::CC) &&
|
|
|
|
(!MI.definesRegister(SystemZ::CC) ||
|
|
|
|
MI.registerDefIsDead(SystemZ::CC))) {
|
|
|
|
MIB->addRegisterDead(SystemZ::CC, TRI);
|
|
|
|
if (CCLiveRange)
|
|
|
|
CCLiveRange->createDeadDef(MISlot, LIS->getVNInfoAllocator());
|
|
|
|
}
|
|
|
|
// Constrain the register classes if converted from a vector opcode. The
|
|
|
|
// allocated regs are in an FP reg-class per previous check above.
|
|
|
|
for (const MachineOperand &MO : MIB->operands())
|
|
|
|
if (MO.isReg() && Register::isVirtualRegister(MO.getReg())) {
|
|
|
|
unsigned Reg = MO.getReg();
|
|
|
|
if (MRI.getRegClass(Reg) == &SystemZ::VR32BitRegClass)
|
|
|
|
MRI.setRegClass(Reg, &SystemZ::FP32BitRegClass);
|
|
|
|
else if (MRI.getRegClass(Reg) == &SystemZ::VR64BitRegClass)
|
|
|
|
MRI.setRegClass(Reg, &SystemZ::FP64BitRegClass);
|
|
|
|
else if (MRI.getRegClass(Reg) == &SystemZ::VR128BitRegClass)
|
|
|
|
MRI.setRegClass(Reg, &SystemZ::VF128BitRegClass);
|
|
|
|
}
|
|
|
|
|
2019-11-05 14:28:13 +01:00
|
|
|
transferDeadCC(&MI, MIB);
|
|
|
|
transferMIFlag(&MI, MIB, MachineInstr::NoSWrap);
|
2020-03-18 18:11:56 +01:00
|
|
|
transferMIFlag(&MI, MIB, MachineInstr::NoFPExcept);
|
2019-11-05 14:28:13 +01:00
|
|
|
return MIB;
|
2013-07-03 12:10:02 +02:00
|
|
|
}
|
|
|
|
|
2014-04-25 07:30:21 +02:00
|
|
|
return nullptr;
|
2013-07-02 17:28:56 +02:00
|
|
|
}
|
|
|
|
|
2015-06-08 22:09:58 +02:00
|
|
|
MachineInstr *SystemZInstrInfo::foldMemoryOperandImpl(
|
2016-06-30 02:01:54 +02:00
|
|
|
MachineFunction &MF, MachineInstr &MI, ArrayRef<unsigned> Ops,
|
|
|
|
MachineBasicBlock::iterator InsertPt, MachineInstr &LoadMI,
|
2016-05-10 10:09:37 +02:00
|
|
|
LiveIntervals *LIS) const {
|
2014-04-25 07:30:21 +02:00
|
|
|
return nullptr;
|
2013-07-02 17:28:56 +02:00
|
|
|
}
|
|
|
|
|
2016-06-30 02:01:54 +02:00
|
|
|
bool SystemZInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
|
|
|
|
switch (MI.getOpcode()) {
|
2013-05-06 18:15:19 +02:00
|
|
|
case SystemZ::L128:
|
|
|
|
splitMove(MI, SystemZ::LG);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::ST128:
|
|
|
|
splitMove(MI, SystemZ::STG);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::LX:
|
|
|
|
splitMove(MI, SystemZ::LD);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::STX:
|
|
|
|
splitMove(MI, SystemZ::STD);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 14:11:47 +02:00
|
|
|
case SystemZ::LBMux:
|
|
|
|
expandRXYPseudo(MI, SystemZ::LB, SystemZ::LBH);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::LHMux:
|
|
|
|
expandRXYPseudo(MI, SystemZ::LH, SystemZ::LHH);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 14:49:07 +02:00
|
|
|
case SystemZ::LLCRMux:
|
|
|
|
expandZExtPseudo(MI, SystemZ::LLCR, 8);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::LLHRMux:
|
|
|
|
expandZExtPseudo(MI, SystemZ::LLHR, 16);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 14:19:08 +02:00
|
|
|
case SystemZ::LLCMux:
|
|
|
|
expandRXYPseudo(MI, SystemZ::LLC, SystemZ::LLCH);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::LLHMux:
|
|
|
|
expandRXYPseudo(MI, SystemZ::LLH, SystemZ::LLHH);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 13:26:28 +02:00
|
|
|
case SystemZ::LMux:
|
|
|
|
expandRXYPseudo(MI, SystemZ::L, SystemZ::LFH);
|
|
|
|
return true;
|
|
|
|
|
2016-11-28 14:34:08 +01:00
|
|
|
case SystemZ::LOCMux:
|
|
|
|
expandLOCPseudo(MI, SystemZ::LOC, SystemZ::LOCFH);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::LOCHIMux:
|
|
|
|
expandLOCPseudo(MI, SystemZ::LOCHI, SystemZ::LOCHHI);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 14:22:49 +02:00
|
|
|
case SystemZ::STCMux:
|
|
|
|
expandRXYPseudo(MI, SystemZ::STC, SystemZ::STCH);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::STHMux:
|
|
|
|
expandRXYPseudo(MI, SystemZ::STH, SystemZ::STHH);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 13:26:28 +02:00
|
|
|
case SystemZ::STMux:
|
|
|
|
expandRXYPseudo(MI, SystemZ::ST, SystemZ::STFH);
|
|
|
|
return true;
|
|
|
|
|
2016-11-28 14:34:08 +01:00
|
|
|
case SystemZ::STOCMux:
|
|
|
|
expandLOCPseudo(MI, SystemZ::STOC, SystemZ::STOCFH);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 15:02:28 +02:00
|
|
|
case SystemZ::LHIMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::LHI, SystemZ::IIHF, true);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::IIFMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::IILF, SystemZ::IIHF, false);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 15:18:56 +02:00
|
|
|
case SystemZ::IILMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::IILL, SystemZ::IIHL, false);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::IIHMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::IILH, SystemZ::IIHH, false);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 16:20:41 +02:00
|
|
|
case SystemZ::NIFMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::NILF, SystemZ::NIHF, false);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::NILMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::NILL, SystemZ::NIHL, false);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::NIHMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::NILH, SystemZ::NIHH, false);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 15:22:41 +02:00
|
|
|
case SystemZ::OIFMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::OILF, SystemZ::OIHF, false);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::OILMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::OILL, SystemZ::OIHL, false);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::OIHMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::OILH, SystemZ::OIHH, false);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 16:08:44 +02:00
|
|
|
case SystemZ::XIFMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::XILF, SystemZ::XIHF, false);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 16:41:52 +02:00
|
|
|
case SystemZ::TMLMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::TMLL, SystemZ::TMHL, false);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::TMHMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::TMLH, SystemZ::TMHH, false);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 16:53:46 +02:00
|
|
|
case SystemZ::AHIMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::AHI, SystemZ::AIH, false);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::AHIMuxK:
|
|
|
|
expandRIEPseudo(MI, SystemZ::AHI, SystemZ::AHIK, SystemZ::AIH);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::AFIMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::AFI, SystemZ::AIH, false);
|
|
|
|
return true;
|
|
|
|
|
2016-11-28 14:40:08 +01:00
|
|
|
case SystemZ::CHIMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::CHI, SystemZ::CIH, false);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 16:56:23 +02:00
|
|
|
case SystemZ::CFIMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::CFI, SystemZ::CIH, false);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::CLFIMux:
|
|
|
|
expandRIPseudo(MI, SystemZ::CLFI, SystemZ::CLIH, false);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 17:00:44 +02:00
|
|
|
case SystemZ::CMux:
|
|
|
|
expandRXYPseudo(MI, SystemZ::C, SystemZ::CHF);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
case SystemZ::CLMux:
|
|
|
|
expandRXYPseudo(MI, SystemZ::CL, SystemZ::CLHF);
|
|
|
|
return true;
|
|
|
|
|
2013-10-01 16:20:41 +02:00
|
|
|
case SystemZ::RISBMux: {
|
2019-09-16 09:29:37 +02:00
|
|
|
bool DestIsHigh = SystemZ::isHighReg(MI.getOperand(0).getReg());
|
|
|
|
bool SrcIsHigh = SystemZ::isHighReg(MI.getOperand(2).getReg());
|
2013-10-01 16:20:41 +02:00
|
|
|
if (SrcIsHigh == DestIsHigh)
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.setDesc(get(DestIsHigh ? SystemZ::RISBHH : SystemZ::RISBLL));
|
2013-10-01 16:20:41 +02:00
|
|
|
else {
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.setDesc(get(DestIsHigh ? SystemZ::RISBHL : SystemZ::RISBLH));
|
|
|
|
MI.getOperand(5).setImm(MI.getOperand(5).getImm() ^ 32);
|
2013-10-01 16:20:41 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-05-06 18:15:19 +02:00
|
|
|
case SystemZ::ADJDYNALLOC:
|
|
|
|
splitAdjDynAlloc(MI);
|
|
|
|
return true;
|
|
|
|
|
2016-04-24 15:57:49 +02:00
|
|
|
case TargetOpcode::LOAD_STACK_GUARD:
|
2016-06-30 02:01:54 +02:00
|
|
|
expandLoadStackGuard(&MI);
|
2016-04-24 15:57:49 +02:00
|
|
|
return true;
|
|
|
|
|
2013-05-06 18:15:19 +02:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-29 10:16:16 +02:00
|
|
|
unsigned SystemZInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
|
2019-02-04 22:24:13 +01:00
|
|
|
if (MI.isInlineAsm()) {
|
2016-06-30 02:01:54 +02:00
|
|
|
const MachineFunction *MF = MI.getParent()->getParent();
|
|
|
|
const char *AsmStr = MI.getOperand(0).getSymbolName();
|
[SystemZ] Add long branch pass
Before this change, the SystemZ backend would use BRCL for all branches
and only consider shortening them to BRC when generating an object file.
E.g. a branch on equal would use the JGE alias of BRCL in assembly output,
but might be shortened to the JE alias of BRC in ELF output. This was
a useful first step, but it had two problems:
(1) The z assembler isn't traditionally supposed to perform branch shortening
or branch relaxation. We followed this rule by not relaxing branches
in assembler input, but that meant that generating assembly code and
then assembling it would not produce the same result as going directly
to object code; the former would give long branches everywhere, whereas
the latter would use short branches where possible.
(2) Other useful branches, like COMPARE AND BRANCH, do not have long forms.
We would need to do something else before supporting them.
(Although COMPARE AND BRANCH does not change the condition codes,
the plan is to model COMPARE AND BRANCH as a CC-clobbering instruction
during codegen, so that we can safely lower it to a separate compare
and long branch where necessary. This is not a valid transformation
for the assembler proper to make.)
This patch therefore moves branch relaxation to a pre-emit pass.
For now, calls are still shortened from BRASL to BRAS by the assembler,
although this too is not really the traditional behaviour.
The first test takes about 1.5s to run, and there are likely to be
more tests in this vein once further branch types are added. The feeling
on IRC was that 1.5s is a bit much for a single test, so I've restricted
it to SystemZ hosts for now.
The patch exposes (and fixes) some typos in the main CodeGen/SystemZ tests.
A later patch will remove the {{g}}s from that directory.
llvm-svn: 182274
2013-05-20 16:23:08 +02:00
|
|
|
return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo());
|
|
|
|
}
|
2016-06-30 02:01:54 +02:00
|
|
|
return MI.getDesc().getSize();
|
[SystemZ] Add long branch pass
Before this change, the SystemZ backend would use BRCL for all branches
and only consider shortening them to BRC when generating an object file.
E.g. a branch on equal would use the JGE alias of BRCL in assembly output,
but might be shortened to the JE alias of BRC in ELF output. This was
a useful first step, but it had two problems:
(1) The z assembler isn't traditionally supposed to perform branch shortening
or branch relaxation. We followed this rule by not relaxing branches
in assembler input, but that meant that generating assembly code and
then assembling it would not produce the same result as going directly
to object code; the former would give long branches everywhere, whereas
the latter would use short branches where possible.
(2) Other useful branches, like COMPARE AND BRANCH, do not have long forms.
We would need to do something else before supporting them.
(Although COMPARE AND BRANCH does not change the condition codes,
the plan is to model COMPARE AND BRANCH as a CC-clobbering instruction
during codegen, so that we can safely lower it to a separate compare
and long branch where necessary. This is not a valid transformation
for the assembler proper to make.)
This patch therefore moves branch relaxation to a pre-emit pass.
For now, calls are still shortened from BRASL to BRAS by the assembler,
although this too is not really the traditional behaviour.
The first test takes about 1.5s to run, and there are likely to be
more tests in this vein once further branch types are added. The feeling
on IRC was that 1.5s is a bit much for a single test, so I've restricted
it to SystemZ hosts for now.
The patch exposes (and fixes) some typos in the main CodeGen/SystemZ tests.
A later patch will remove the {{g}}s from that directory.
llvm-svn: 182274
2013-05-20 16:23:08 +02:00
|
|
|
}
|
|
|
|
|
2013-05-28 12:13:54 +02:00
|
|
|
SystemZII::Branch
|
2016-06-30 02:01:54 +02:00
|
|
|
SystemZInstrInfo::getBranchInfo(const MachineInstr &MI) const {
|
|
|
|
switch (MI.getOpcode()) {
|
2013-05-06 18:15:19 +02:00
|
|
|
case SystemZ::BR:
|
2017-07-17 19:41:11 +02:00
|
|
|
case SystemZ::BI:
|
2013-05-06 18:15:19 +02:00
|
|
|
case SystemZ::J:
|
|
|
|
case SystemZ::JG:
|
2013-05-28 12:41:11 +02:00
|
|
|
return SystemZII::Branch(SystemZII::BranchNormal, SystemZ::CCMASK_ANY,
|
2016-06-30 02:01:54 +02:00
|
|
|
SystemZ::CCMASK_ANY, &MI.getOperand(0));
|
2013-05-06 18:15:19 +02:00
|
|
|
|
|
|
|
case SystemZ::BRC:
|
|
|
|
case SystemZ::BRCL:
|
2016-06-30 02:01:54 +02:00
|
|
|
return SystemZII::Branch(SystemZII::BranchNormal, MI.getOperand(0).getImm(),
|
|
|
|
MI.getOperand(1).getImm(), &MI.getOperand(2));
|
2013-05-28 12:41:11 +02:00
|
|
|
|
2013-08-05 13:23:46 +02:00
|
|
|
case SystemZ::BRCT:
|
2016-11-28 14:40:08 +01:00
|
|
|
case SystemZ::BRCTH:
|
2013-08-05 13:23:46 +02:00
|
|
|
return SystemZII::Branch(SystemZII::BranchCT, SystemZ::CCMASK_ICMP,
|
2016-06-30 02:01:54 +02:00
|
|
|
SystemZ::CCMASK_CMP_NE, &MI.getOperand(2));
|
2013-08-05 13:23:46 +02:00
|
|
|
|
|
|
|
case SystemZ::BRCTG:
|
|
|
|
return SystemZII::Branch(SystemZII::BranchCTG, SystemZ::CCMASK_ICMP,
|
2016-06-30 02:01:54 +02:00
|
|
|
SystemZ::CCMASK_CMP_NE, &MI.getOperand(2));
|
2013-08-05 13:23:46 +02:00
|
|
|
|
2013-05-29 13:58:52 +02:00
|
|
|
case SystemZ::CIJ:
|
2013-05-28 12:41:11 +02:00
|
|
|
case SystemZ::CRJ:
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
return SystemZII::Branch(SystemZII::BranchC, SystemZ::CCMASK_ICMP,
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.getOperand(2).getImm(), &MI.getOperand(3));
|
2013-05-28 12:41:11 +02:00
|
|
|
|
2013-09-18 11:56:40 +02:00
|
|
|
case SystemZ::CLIJ:
|
|
|
|
case SystemZ::CLRJ:
|
|
|
|
return SystemZII::Branch(SystemZII::BranchCL, SystemZ::CCMASK_ICMP,
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.getOperand(2).getImm(), &MI.getOperand(3));
|
2013-09-18 11:56:40 +02:00
|
|
|
|
2013-05-29 13:58:52 +02:00
|
|
|
case SystemZ::CGIJ:
|
2013-05-28 12:41:11 +02:00
|
|
|
case SystemZ::CGRJ:
|
[SystemZ] Be more careful about inverting CC masks
System z branches have a mask to select which of the 4 CC values should
cause the branch to be taken. We can invert a branch by inverting the mask.
However, not all instructions can produce all 4 CC values, so inverting
the branch like this can lead to some oddities. For example, integer
comparisons only produce a CC of 0 (equal), 1 (less) or 2 (greater).
If an integer EQ is reversed to NE before instruction selection,
the branch will test for 1 or 2. If instead the branch is reversed
after instruction selection (by inverting the mask), it will test for
1, 2 or 3. Both are correct, but the second isn't really canonical.
This patch therefore keeps track of which CC values are possible
and uses this when inverting a mask.
Although this is mostly cosmestic, it fixes undefined behavior
for the CIJNLH in branch-08.ll. Another fix would have been
to mask out bit 0 when generating the fused compare and branch,
but the point of this patch is that we shouldn't need to do that
in the first place.
The patch also makes it easier to reuse CC results from other instructions.
llvm-svn: 187495
2013-07-31 14:30:20 +02:00
|
|
|
return SystemZII::Branch(SystemZII::BranchCG, SystemZ::CCMASK_ICMP,
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.getOperand(2).getImm(), &MI.getOperand(3));
|
2013-05-06 18:15:19 +02:00
|
|
|
|
2013-09-18 11:56:40 +02:00
|
|
|
case SystemZ::CLGIJ:
|
|
|
|
case SystemZ::CLGRJ:
|
|
|
|
return SystemZII::Branch(SystemZII::BranchCLG, SystemZ::CCMASK_ICMP,
|
2016-06-30 02:01:54 +02:00
|
|
|
MI.getOperand(2).getImm(), &MI.getOperand(3));
|
2013-09-18 11:56:40 +02:00
|
|
|
|
2019-09-05 12:20:05 +02:00
|
|
|
case SystemZ::INLINEASM_BR:
|
|
|
|
// Don't try to analyze asm goto, so pass nullptr as branch target argument.
|
|
|
|
return SystemZII::Branch(SystemZII::AsmGoto, 0, 0, nullptr);
|
|
|
|
|
2013-05-06 18:15:19 +02:00
|
|
|
default:
|
2013-05-28 12:13:54 +02:00
|
|
|
llvm_unreachable("Unrecognized branch opcode");
|
2013-05-06 18:15:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SystemZInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC,
|
|
|
|
unsigned &LoadOpcode,
|
|
|
|
unsigned &StoreOpcode) const {
|
|
|
|
if (RC == &SystemZ::GR32BitRegClass || RC == &SystemZ::ADDR32BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::L;
|
2013-09-25 12:29:47 +02:00
|
|
|
StoreOpcode = SystemZ::ST;
|
2013-10-01 13:26:28 +02:00
|
|
|
} else if (RC == &SystemZ::GRH32BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::LFH;
|
|
|
|
StoreOpcode = SystemZ::STFH;
|
|
|
|
} else if (RC == &SystemZ::GRX32BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::LMux;
|
|
|
|
StoreOpcode = SystemZ::STMux;
|
2013-05-06 18:15:19 +02:00
|
|
|
} else if (RC == &SystemZ::GR64BitRegClass ||
|
|
|
|
RC == &SystemZ::ADDR64BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::LG;
|
|
|
|
StoreOpcode = SystemZ::STG;
|
|
|
|
} else if (RC == &SystemZ::GR128BitRegClass ||
|
|
|
|
RC == &SystemZ::ADDR128BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::L128;
|
|
|
|
StoreOpcode = SystemZ::ST128;
|
|
|
|
} else if (RC == &SystemZ::FP32BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::LE;
|
|
|
|
StoreOpcode = SystemZ::STE;
|
|
|
|
} else if (RC == &SystemZ::FP64BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::LD;
|
|
|
|
StoreOpcode = SystemZ::STD;
|
|
|
|
} else if (RC == &SystemZ::FP128BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::LX;
|
|
|
|
StoreOpcode = SystemZ::STX;
|
2015-05-05 21:28:34 +02:00
|
|
|
} else if (RC == &SystemZ::VR32BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::VL32;
|
|
|
|
StoreOpcode = SystemZ::VST32;
|
|
|
|
} else if (RC == &SystemZ::VR64BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::VL64;
|
|
|
|
StoreOpcode = SystemZ::VST64;
|
[SystemZ] Add CodeGen support for integer vector types
This the first of a series of patches to add CodeGen support exploiting
the instructions of the z13 vector facility. This patch adds support
for the native integer vector types (v16i8, v8i16, v4i32, v2i64).
When the vector facility is present, we default to the new vector ABI.
This is characterized by two major differences:
- Vector types are passed/returned in vector registers
(except for unnamed arguments of a variable-argument list function).
- Vector types are at most 8-byte aligned.
The reason for the choice of 8-byte vector alignment is that the hardware
is able to efficiently load vectors at 8-byte alignment, and the ABI only
guarantees 8-byte alignment of the stack pointer, so requiring any higher
alignment for vectors would require dynamic stack re-alignment code.
However, for compatibility with old code that may use vector types, when
*not* using the vector facility, the old alignment rules (vector types
are naturally aligned) remain in use.
These alignment rules are not only implemented at the C language level
(implemented in clang), but also at the LLVM IR level. This is done
by selecting a different DataLayout string depending on whether the
vector ABI is in effect or not.
Based on a patch by Richard Sandiford.
llvm-svn: 236521
2015-05-05 21:25:42 +02:00
|
|
|
} else if (RC == &SystemZ::VF128BitRegClass ||
|
|
|
|
RC == &SystemZ::VR128BitRegClass) {
|
|
|
|
LoadOpcode = SystemZ::VL;
|
|
|
|
StoreOpcode = SystemZ::VST;
|
2013-05-06 18:15:19 +02:00
|
|
|
} else
|
|
|
|
llvm_unreachable("Unsupported regclass to load or store");
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned SystemZInstrInfo::getOpcodeForOffset(unsigned Opcode,
|
|
|
|
int64_t Offset) const {
|
|
|
|
const MCInstrDesc &MCID = get(Opcode);
|
|
|
|
int64_t Offset2 = (MCID.TSFlags & SystemZII::Is128Bit ? Offset + 8 : Offset);
|
|
|
|
if (isUInt<12>(Offset) && isUInt<12>(Offset2)) {
|
|
|
|
// Get the instruction to use for unsigned 12-bit displacements.
|
|
|
|
int Disp12Opcode = SystemZ::getDisp12Opcode(Opcode);
|
|
|
|
if (Disp12Opcode >= 0)
|
|
|
|
return Disp12Opcode;
|
|
|
|
|
|
|
|
// All address-related instructions can use unsigned 12-bit
|
|
|
|
// displacements.
|
|
|
|
return Opcode;
|
|
|
|
}
|
|
|
|
if (isInt<20>(Offset) && isInt<20>(Offset2)) {
|
|
|
|
// Get the instruction to use for signed 20-bit displacements.
|
|
|
|
int Disp20Opcode = SystemZ::getDisp20Opcode(Opcode);
|
|
|
|
if (Disp20Opcode >= 0)
|
|
|
|
return Disp20Opcode;
|
|
|
|
|
|
|
|
// Check whether Opcode allows signed 20-bit displacements.
|
|
|
|
if (MCID.TSFlags & SystemZII::Has20BitOffset)
|
|
|
|
return Opcode;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-08-05 13:03:20 +02:00
|
|
|
unsigned SystemZInstrInfo::getLoadAndTest(unsigned Opcode) const {
|
|
|
|
switch (Opcode) {
|
2015-03-31 14:58:17 +02:00
|
|
|
case SystemZ::L: return SystemZ::LT;
|
|
|
|
case SystemZ::LY: return SystemZ::LT;
|
|
|
|
case SystemZ::LG: return SystemZ::LTG;
|
|
|
|
case SystemZ::LGF: return SystemZ::LTGF;
|
|
|
|
case SystemZ::LR: return SystemZ::LTR;
|
|
|
|
case SystemZ::LGFR: return SystemZ::LTGFR;
|
|
|
|
case SystemZ::LGR: return SystemZ::LTGR;
|
|
|
|
case SystemZ::LER: return SystemZ::LTEBR;
|
|
|
|
case SystemZ::LDR: return SystemZ::LTDBR;
|
|
|
|
case SystemZ::LXR: return SystemZ::LTXBR;
|
2015-10-01 20:12:28 +02:00
|
|
|
case SystemZ::LCDFR: return SystemZ::LCDBR;
|
|
|
|
case SystemZ::LPDFR: return SystemZ::LPDBR;
|
|
|
|
case SystemZ::LNDFR: return SystemZ::LNDBR;
|
|
|
|
case SystemZ::LCDFR_32: return SystemZ::LCEBR;
|
|
|
|
case SystemZ::LPDFR_32: return SystemZ::LPEBR;
|
|
|
|
case SystemZ::LNDFR_32: return SystemZ::LNEBR;
|
2015-03-31 14:58:17 +02:00
|
|
|
// On zEC12 we prefer to use RISBGN. But if there is a chance to
|
|
|
|
// actually use the condition code, we may turn it back into RISGB.
|
|
|
|
// Note that RISBG is not really a "load-and-test" instruction,
|
|
|
|
// but sets the same condition code values, so is OK to use here.
|
|
|
|
case SystemZ::RISBGN: return SystemZ::RISBG;
|
|
|
|
default: return 0;
|
2013-08-05 13:03:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-31 13:36:35 +02:00
|
|
|
// Return true if Mask matches the regexp 0*1+0*, given that zero masks
|
|
|
|
// have already been filtered out. Store the first set bit in LSB and
|
|
|
|
// the number of set bits in Length if so.
|
|
|
|
static bool isStringOfOnes(uint64_t Mask, unsigned &LSB, unsigned &Length) {
|
|
|
|
unsigned First = findFirstSet(Mask);
|
|
|
|
uint64_t Top = (Mask >> First) + 1;
|
|
|
|
if ((Top & -Top) == Top) {
|
|
|
|
LSB = First;
|
|
|
|
Length = findFirstSet(Top);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SystemZInstrInfo::isRxSBGMask(uint64_t Mask, unsigned BitSize,
|
|
|
|
unsigned &Start, unsigned &End) const {
|
|
|
|
// Reject trivial all-zero masks.
|
[SystemZ] Add CodeGen support for integer vector types
This the first of a series of patches to add CodeGen support exploiting
the instructions of the z13 vector facility. This patch adds support
for the native integer vector types (v16i8, v8i16, v4i32, v2i64).
When the vector facility is present, we default to the new vector ABI.
This is characterized by two major differences:
- Vector types are passed/returned in vector registers
(except for unnamed arguments of a variable-argument list function).
- Vector types are at most 8-byte aligned.
The reason for the choice of 8-byte vector alignment is that the hardware
is able to efficiently load vectors at 8-byte alignment, and the ABI only
guarantees 8-byte alignment of the stack pointer, so requiring any higher
alignment for vectors would require dynamic stack re-alignment code.
However, for compatibility with old code that may use vector types, when
*not* using the vector facility, the old alignment rules (vector types
are naturally aligned) remain in use.
These alignment rules are not only implemented at the C language level
(implemented in clang), but also at the LLVM IR level. This is done
by selecting a different DataLayout string depending on whether the
vector ABI is in effect or not.
Based on a patch by Richard Sandiford.
llvm-svn: 236521
2015-05-05 21:25:42 +02:00
|
|
|
Mask &= allOnes(BitSize);
|
2013-07-31 13:36:35 +02:00
|
|
|
if (Mask == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Handle the 1+0+ or 0+1+0* cases. Start then specifies the index of
|
|
|
|
// the msb and End specifies the index of the lsb.
|
|
|
|
unsigned LSB, Length;
|
|
|
|
if (isStringOfOnes(Mask, LSB, Length)) {
|
|
|
|
Start = 63 - (LSB + Length - 1);
|
|
|
|
End = 63 - LSB;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle the wrap-around 1+0+1+ cases. Start then specifies the msb
|
|
|
|
// of the low 1s and End specifies the lsb of the high 1s.
|
|
|
|
if (isStringOfOnes(Mask ^ allOnes(BitSize), LSB, Length)) {
|
|
|
|
assert(LSB > 0 && "Bottom bit must be set");
|
|
|
|
assert(LSB + Length < BitSize && "Top bit must be set");
|
|
|
|
Start = 63 - (LSB - 1);
|
|
|
|
End = 63 - (LSB + Length);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-10 21:58:10 +02:00
|
|
|
unsigned SystemZInstrInfo::getFusedCompare(unsigned Opcode,
|
|
|
|
SystemZII::FusedCompareType Type,
|
|
|
|
const MachineInstr *MI) const {
|
2013-05-28 12:41:11 +02:00
|
|
|
switch (Opcode) {
|
2013-05-29 13:58:52 +02:00
|
|
|
case SystemZ::CHI:
|
|
|
|
case SystemZ::CGHI:
|
2016-04-07 18:11:44 +02:00
|
|
|
if (!(MI && isInt<8>(MI->getOperand(1).getImm())))
|
|
|
|
return 0;
|
|
|
|
break;
|
2013-09-18 11:56:40 +02:00
|
|
|
case SystemZ::CLFI:
|
|
|
|
case SystemZ::CLGFI:
|
2016-04-07 18:11:44 +02:00
|
|
|
if (!(MI && isUInt<8>(MI->getOperand(1).getImm())))
|
|
|
|
return 0;
|
2016-11-11 13:48:26 +01:00
|
|
|
break;
|
|
|
|
case SystemZ::CL:
|
|
|
|
case SystemZ::CLG:
|
|
|
|
if (!STI.hasMiscellaneousExtensions())
|
|
|
|
return 0;
|
|
|
|
if (!(MI && MI->getOperand(3).getReg() == 0))
|
|
|
|
return 0;
|
|
|
|
break;
|
2016-04-07 18:11:44 +02:00
|
|
|
}
|
|
|
|
switch (Type) {
|
|
|
|
case SystemZII::CompareAndBranch:
|
|
|
|
switch (Opcode) {
|
|
|
|
case SystemZ::CR:
|
|
|
|
return SystemZ::CRJ;
|
|
|
|
case SystemZ::CGR:
|
|
|
|
return SystemZ::CGRJ;
|
|
|
|
case SystemZ::CHI:
|
|
|
|
return SystemZ::CIJ;
|
|
|
|
case SystemZ::CGHI:
|
|
|
|
return SystemZ::CGIJ;
|
|
|
|
case SystemZ::CLR:
|
|
|
|
return SystemZ::CLRJ;
|
|
|
|
case SystemZ::CLGR:
|
|
|
|
return SystemZ::CLGRJ;
|
|
|
|
case SystemZ::CLFI:
|
|
|
|
return SystemZ::CLIJ;
|
|
|
|
case SystemZ::CLGFI:
|
|
|
|
return SystemZ::CLGIJ;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
case SystemZII::CompareAndReturn:
|
|
|
|
switch (Opcode) {
|
|
|
|
case SystemZ::CR:
|
|
|
|
return SystemZ::CRBReturn;
|
|
|
|
case SystemZ::CGR:
|
|
|
|
return SystemZ::CGRBReturn;
|
|
|
|
case SystemZ::CHI:
|
|
|
|
return SystemZ::CIBReturn;
|
|
|
|
case SystemZ::CGHI:
|
|
|
|
return SystemZ::CGIBReturn;
|
|
|
|
case SystemZ::CLR:
|
|
|
|
return SystemZ::CLRBReturn;
|
|
|
|
case SystemZ::CLGR:
|
|
|
|
return SystemZ::CLGRBReturn;
|
|
|
|
case SystemZ::CLFI:
|
|
|
|
return SystemZ::CLIBReturn;
|
|
|
|
case SystemZ::CLGFI:
|
|
|
|
return SystemZ::CLGIBReturn;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
2016-04-11 14:12:32 +02:00
|
|
|
case SystemZII::CompareAndSibcall:
|
|
|
|
switch (Opcode) {
|
|
|
|
case SystemZ::CR:
|
|
|
|
return SystemZ::CRBCall;
|
|
|
|
case SystemZ::CGR:
|
|
|
|
return SystemZ::CGRBCall;
|
|
|
|
case SystemZ::CHI:
|
|
|
|
return SystemZ::CIBCall;
|
|
|
|
case SystemZ::CGHI:
|
|
|
|
return SystemZ::CGIBCall;
|
|
|
|
case SystemZ::CLR:
|
|
|
|
return SystemZ::CLRBCall;
|
|
|
|
case SystemZ::CLGR:
|
|
|
|
return SystemZ::CLGRBCall;
|
|
|
|
case SystemZ::CLFI:
|
|
|
|
return SystemZ::CLIBCall;
|
|
|
|
case SystemZ::CLGFI:
|
|
|
|
return SystemZ::CLGIBCall;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
2016-06-10 21:58:10 +02:00
|
|
|
case SystemZII::CompareAndTrap:
|
|
|
|
switch (Opcode) {
|
|
|
|
case SystemZ::CR:
|
|
|
|
return SystemZ::CRT;
|
|
|
|
case SystemZ::CGR:
|
|
|
|
return SystemZ::CGRT;
|
|
|
|
case SystemZ::CHI:
|
|
|
|
return SystemZ::CIT;
|
|
|
|
case SystemZ::CGHI:
|
|
|
|
return SystemZ::CGIT;
|
|
|
|
case SystemZ::CLR:
|
|
|
|
return SystemZ::CLRT;
|
|
|
|
case SystemZ::CLGR:
|
|
|
|
return SystemZ::CLGRT;
|
|
|
|
case SystemZ::CLFI:
|
|
|
|
return SystemZ::CLFIT;
|
|
|
|
case SystemZ::CLGFI:
|
|
|
|
return SystemZ::CLGIT;
|
2016-11-11 13:48:26 +01:00
|
|
|
case SystemZ::CL:
|
|
|
|
return SystemZ::CLT;
|
|
|
|
case SystemZ::CLG:
|
|
|
|
return SystemZ::CLGT;
|
2016-06-10 21:58:10 +02:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
2013-05-28 12:41:11 +02:00
|
|
|
}
|
2016-04-07 18:33:25 +02:00
|
|
|
return 0;
|
2013-05-28 12:41:11 +02:00
|
|
|
}
|
|
|
|
|
2019-11-05 14:28:13 +01:00
|
|
|
bool SystemZInstrInfo::
|
|
|
|
prepareCompareSwapOperands(MachineBasicBlock::iterator const MBBI) const {
|
|
|
|
assert(MBBI->isCompare() && MBBI->getOperand(0).isReg() &&
|
|
|
|
MBBI->getOperand(1).isReg() && !MBBI->mayLoad() &&
|
|
|
|
"Not a compare reg/reg.");
|
|
|
|
|
|
|
|
MachineBasicBlock *MBB = MBBI->getParent();
|
|
|
|
bool CCLive = true;
|
|
|
|
SmallVector<MachineInstr *, 4> CCUsers;
|
|
|
|
for (MachineBasicBlock::iterator Itr = std::next(MBBI);
|
|
|
|
Itr != MBB->end(); ++Itr) {
|
|
|
|
if (Itr->readsRegister(SystemZ::CC)) {
|
|
|
|
unsigned Flags = Itr->getDesc().TSFlags;
|
|
|
|
if ((Flags & SystemZII::CCMaskFirst) || (Flags & SystemZII::CCMaskLast))
|
|
|
|
CCUsers.push_back(&*Itr);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (Itr->definesRegister(SystemZ::CC)) {
|
|
|
|
CCLive = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (CCLive) {
|
|
|
|
LivePhysRegs LiveRegs(*MBB->getParent()->getSubtarget().getRegisterInfo());
|
|
|
|
LiveRegs.addLiveOuts(*MBB);
|
|
|
|
if (LiveRegs.contains(SystemZ::CC))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update all CC users.
|
|
|
|
for (unsigned Idx = 0; Idx < CCUsers.size(); ++Idx) {
|
|
|
|
unsigned Flags = CCUsers[Idx]->getDesc().TSFlags;
|
|
|
|
unsigned FirstOpNum = ((Flags & SystemZII::CCMaskFirst) ?
|
|
|
|
0 : CCUsers[Idx]->getNumExplicitOperands() - 2);
|
|
|
|
MachineOperand &CCMaskMO = CCUsers[Idx]->getOperand(FirstOpNum + 1);
|
|
|
|
unsigned NewCCMask = SystemZ::reverseCCMask(CCMaskMO.getImm());
|
|
|
|
CCMaskMO.setImm(NewCCMask);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned SystemZ::reverseCCMask(unsigned CCMask) {
|
|
|
|
return ((CCMask & SystemZ::CCMASK_CMP_EQ) |
|
|
|
|
(CCMask & SystemZ::CCMASK_CMP_GT ? SystemZ::CCMASK_CMP_LT : 0) |
|
|
|
|
(CCMask & SystemZ::CCMASK_CMP_LT ? SystemZ::CCMASK_CMP_GT : 0) |
|
|
|
|
(CCMask & SystemZ::CCMASK_CMP_UO));
|
|
|
|
}
|
|
|
|
|
2020-04-21 18:16:29 +02:00
|
|
|
MachineBasicBlock *SystemZ::emitBlockAfter(MachineBasicBlock *MBB) {
|
|
|
|
MachineFunction &MF = *MBB->getParent();
|
|
|
|
MachineBasicBlock *NewMBB = MF.CreateMachineBasicBlock(MBB->getBasicBlock());
|
|
|
|
MF.insert(std::next(MachineFunction::iterator(MBB)), NewMBB);
|
|
|
|
return NewMBB;
|
|
|
|
}
|
|
|
|
|
|
|
|
MachineBasicBlock *SystemZ::splitBlockAfter(MachineBasicBlock::iterator MI,
|
|
|
|
MachineBasicBlock *MBB) {
|
|
|
|
MachineBasicBlock *NewMBB = emitBlockAfter(MBB);
|
|
|
|
NewMBB->splice(NewMBB->begin(), MBB,
|
|
|
|
std::next(MachineBasicBlock::iterator(MI)), MBB->end());
|
|
|
|
NewMBB->transferSuccessorsAndUpdatePHIs(MBB);
|
|
|
|
return NewMBB;
|
|
|
|
}
|
|
|
|
|
|
|
|
MachineBasicBlock *SystemZ::splitBlockBefore(MachineBasicBlock::iterator MI,
|
|
|
|
MachineBasicBlock *MBB) {
|
|
|
|
MachineBasicBlock *NewMBB = emitBlockAfter(MBB);
|
|
|
|
NewMBB->splice(NewMBB->begin(), MBB, MI, MBB->end());
|
|
|
|
NewMBB->transferSuccessorsAndUpdatePHIs(MBB);
|
|
|
|
return NewMBB;
|
|
|
|
}
|
|
|
|
|
2016-11-28 14:59:22 +01:00
|
|
|
unsigned SystemZInstrInfo::getLoadAndTrap(unsigned Opcode) const {
|
|
|
|
if (!STI.hasLoadAndTrap())
|
|
|
|
return 0;
|
|
|
|
switch (Opcode) {
|
|
|
|
case SystemZ::L:
|
|
|
|
case SystemZ::LY:
|
|
|
|
return SystemZ::LAT;
|
|
|
|
case SystemZ::LG:
|
|
|
|
return SystemZ::LGAT;
|
|
|
|
case SystemZ::LFH:
|
|
|
|
return SystemZ::LFHAT;
|
|
|
|
case SystemZ::LLGF:
|
|
|
|
return SystemZ::LLGFAT;
|
|
|
|
case SystemZ::LLGT:
|
|
|
|
return SystemZ::LLGTAT;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-06 18:15:19 +02:00
|
|
|
void SystemZInstrInfo::loadImmediate(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock::iterator MBBI,
|
|
|
|
unsigned Reg, uint64_t Value) const {
|
|
|
|
DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
|
|
|
|
unsigned Opcode;
|
|
|
|
if (isInt<16>(Value))
|
|
|
|
Opcode = SystemZ::LGHI;
|
|
|
|
else if (SystemZ::isImmLL(Value))
|
|
|
|
Opcode = SystemZ::LLILL;
|
|
|
|
else if (SystemZ::isImmLH(Value)) {
|
|
|
|
Opcode = SystemZ::LLILH;
|
|
|
|
Value >>= 16;
|
|
|
|
} else {
|
|
|
|
assert(isInt<32>(Value) && "Huge values not handled yet");
|
|
|
|
Opcode = SystemZ::LGFI;
|
|
|
|
}
|
|
|
|
BuildMI(MBB, MBBI, DL, get(Opcode), Reg).addImm(Value);
|
|
|
|
}
|
2016-10-20 10:27:16 +02:00
|
|
|
|
2019-12-13 17:06:28 +01:00
|
|
|
bool SystemZInstrInfo::verifyInstruction(const MachineInstr &MI,
|
|
|
|
StringRef &ErrInfo) const {
|
|
|
|
const MCInstrDesc &MCID = MI.getDesc();
|
|
|
|
for (unsigned I = 0, E = MI.getNumOperands(); I != E; ++I) {
|
|
|
|
if (I >= MCID.getNumOperands())
|
|
|
|
break;
|
|
|
|
const MachineOperand &Op = MI.getOperand(I);
|
|
|
|
const MCOperandInfo &MCOI = MCID.OpInfo[I];
|
|
|
|
// Addressing modes have register and immediate operands. Op should be a
|
|
|
|
// register (or frame index) operand if MCOI.RegClass contains a valid
|
|
|
|
// register class, or an immediate otherwise.
|
|
|
|
if (MCOI.OperandType == MCOI::OPERAND_MEMORY &&
|
|
|
|
((MCOI.RegClass != -1 && !Op.isReg() && !Op.isFI()) ||
|
|
|
|
(MCOI.RegClass == -1 && !Op.isImm()))) {
|
|
|
|
ErrInfo = "Addressing mode operands corrupt!";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-10-20 10:27:16 +02:00
|
|
|
bool SystemZInstrInfo::
|
2019-04-19 11:08:38 +02:00
|
|
|
areMemAccessesTriviallyDisjoint(const MachineInstr &MIa,
|
2019-09-27 00:53:44 +02:00
|
|
|
const MachineInstr &MIb) const {
|
2016-10-20 10:27:16 +02:00
|
|
|
|
|
|
|
if (!MIa.hasOneMemOperand() || !MIb.hasOneMemOperand())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If mem-operands show that the same address Value is used by both
|
|
|
|
// instructions, check for non-overlapping offsets and widths. Not
|
|
|
|
// sure if a register based analysis would be an improvement...
|
|
|
|
|
|
|
|
MachineMemOperand *MMOa = *MIa.memoperands_begin();
|
|
|
|
MachineMemOperand *MMOb = *MIb.memoperands_begin();
|
|
|
|
const Value *VALa = MMOa->getValue();
|
|
|
|
const Value *VALb = MMOb->getValue();
|
|
|
|
bool SameVal = (VALa && VALb && (VALa == VALb));
|
|
|
|
if (!SameVal) {
|
|
|
|
const PseudoSourceValue *PSVa = MMOa->getPseudoValue();
|
|
|
|
const PseudoSourceValue *PSVb = MMOb->getPseudoValue();
|
|
|
|
if (PSVa && PSVb && (PSVa == PSVb))
|
|
|
|
SameVal = true;
|
|
|
|
}
|
|
|
|
if (SameVal) {
|
|
|
|
int OffsetA = MMOa->getOffset(), OffsetB = MMOb->getOffset();
|
|
|
|
int WidthA = MMOa->getSize(), WidthB = MMOb->getSize();
|
|
|
|
int LowOffset = OffsetA < OffsetB ? OffsetA : OffsetB;
|
|
|
|
int HighOffset = OffsetA < OffsetB ? OffsetB : OffsetA;
|
|
|
|
int LowWidth = (LowOffset == OffsetA) ? WidthA : WidthB;
|
|
|
|
if (LowOffset + LowWidth <= HighOffset)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|