2014-07-22 00:55:33 +08:00
|
|
|
//===-- SIShrinkInstructions.cpp - Shrink Instructions --------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
/// The pass tries to use the 32-bit encoding for instructions when possible.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "AMDGPU.h"
|
2014-08-05 05:25:23 +08:00
|
|
|
#include "AMDGPUSubtarget.h"
|
2014-07-22 00:55:33 +08:00
|
|
|
#include "SIInstrInfo.h"
|
AMDGPU: Remove #include "MCTargetDesc/AMDGPUMCTargetDesc.h" from common headers
Summary:
MCTargetDesc/AMDGPUMCTargetDesc.h contains enums for all the instuction
and register defintions, which are huge so we only want to include
them where needed.
This will also make it easier if we want to split the R600 and GCN
definitions into separate tablegenerated files.
I was unable to remove AMDGPUMCTargetDesc.h from SIMachineFunctionInfo.h
because it uses some enums from the header to initialize default values
for the SIMachineFunction class, so I ended up having to remove includes of
SIMachineFunctionInfo.h from headers too.
Reviewers: arsenm, nhaehnle
Reviewed By: nhaehnle
Subscribers: MatzeB, kzhuravl, wdng, yaxunl, dstuttard, tpr, t-tye, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D46272
llvm-svn: 332930
2018-05-22 10:03:23 +08:00
|
|
|
#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
|
2014-07-22 00:55:33 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2014-08-01 08:32:33 +08:00
|
|
|
#include "llvm/IR/Constants.h"
|
2014-07-22 00:55:33 +08:00
|
|
|
#include "llvm/IR/Function.h"
|
2015-03-24 02:07:13 +08:00
|
|
|
#include "llvm/IR/LLVMContext.h"
|
2014-07-22 00:55:33 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
2015-03-24 02:07:13 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2014-07-22 00:55:33 +08:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "si-shrink-instructions"
|
|
|
|
|
|
|
|
STATISTIC(NumInstructionsShrunk,
|
|
|
|
"Number of 64-bit instruction reduced to 32-bit.");
|
2014-08-01 08:32:33 +08:00
|
|
|
STATISTIC(NumLiteralConstantsFolded,
|
|
|
|
"Number of literal constants folded into 32-bit instructions.");
|
2014-07-22 00:55:33 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class SIShrinkInstructions : public MachineFunctionPass {
|
|
|
|
public:
|
|
|
|
static char ID;
|
|
|
|
|
|
|
|
public:
|
|
|
|
SIShrinkInstructions() : MachineFunctionPass(ID) {
|
|
|
|
}
|
|
|
|
|
2014-08-31 00:48:34 +08:00
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
2014-07-22 00:55:33 +08:00
|
|
|
|
2016-10-01 10:56:57 +08:00
|
|
|
StringRef getPassName() const override { return "SI Shrink Instructions"; }
|
2014-07-22 00:55:33 +08:00
|
|
|
|
2014-08-31 00:48:34 +08:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
2014-07-22 00:55:33 +08:00
|
|
|
AU.setPreservesCFG();
|
|
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // End anonymous namespace.
|
|
|
|
|
2016-06-10 07:18:47 +08:00
|
|
|
INITIALIZE_PASS(SIShrinkInstructions, DEBUG_TYPE,
|
|
|
|
"SI Shrink Instructions", false, false)
|
2014-07-22 00:55:33 +08:00
|
|
|
|
|
|
|
char SIShrinkInstructions::ID = 0;
|
|
|
|
|
|
|
|
FunctionPass *llvm::createSIShrinkInstructionsPass() {
|
|
|
|
return new SIShrinkInstructions();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isVGPR(const MachineOperand *MO, const SIRegisterInfo &TRI,
|
|
|
|
const MachineRegisterInfo &MRI) {
|
|
|
|
if (!MO->isReg())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (TargetRegisterInfo::isVirtualRegister(MO->getReg()))
|
|
|
|
return TRI.hasVGPRs(MRI.getRegClass(MO->getReg()));
|
|
|
|
|
|
|
|
return TRI.hasVGPRs(TRI.getPhysRegClass(MO->getReg()));
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool canShrink(MachineInstr &MI, const SIInstrInfo *TII,
|
|
|
|
const SIRegisterInfo &TRI,
|
|
|
|
const MachineRegisterInfo &MRI) {
|
|
|
|
|
|
|
|
const MachineOperand *Src2 = TII->getNamedOperand(MI, AMDGPU::OpName::src2);
|
|
|
|
// Can't shrink instruction with three operands.
|
2015-03-11 00:16:44 +08:00
|
|
|
// FIXME: v_cndmask_b32 has 3 operands and is shrinkable, but we need to add
|
|
|
|
// a special case for it. It can only be shrunk if the third operand
|
|
|
|
// is vcc. We should handle this the same way we handle vopc, by addding
|
2017-01-12 06:35:17 +08:00
|
|
|
// a register allocation hint pre-regalloc and then do the shrinking
|
2015-03-11 00:16:44 +08:00
|
|
|
// post-regalloc.
|
2015-07-13 23:47:57 +08:00
|
|
|
if (Src2) {
|
2015-07-14 22:15:03 +08:00
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
default: return false;
|
2015-07-13 23:47:57 +08:00
|
|
|
|
2017-01-12 06:58:12 +08:00
|
|
|
case AMDGPU::V_ADDC_U32_e64:
|
|
|
|
case AMDGPU::V_SUBB_U32_e64:
|
2018-02-24 09:32:32 +08:00
|
|
|
case AMDGPU::V_SUBBREV_U32_e64:
|
|
|
|
if (!isVGPR(TII->getNamedOperand(MI, AMDGPU::OpName::src1), TRI, MRI))
|
2017-06-21 04:33:44 +08:00
|
|
|
return false;
|
2017-01-12 06:58:12 +08:00
|
|
|
// Additional verification is needed for sdst/src2.
|
|
|
|
return true;
|
|
|
|
|
2015-07-14 22:15:03 +08:00
|
|
|
case AMDGPU::V_MAC_F32_e64:
|
2016-11-13 15:01:11 +08:00
|
|
|
case AMDGPU::V_MAC_F16_e64:
|
2018-05-01 03:08:16 +08:00
|
|
|
case AMDGPU::V_FMAC_F32_e64:
|
2015-07-14 22:15:03 +08:00
|
|
|
if (!isVGPR(Src2, TRI, MRI) ||
|
|
|
|
TII->hasModifiersSet(MI, AMDGPU::OpName::src2_modifiers))
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AMDGPU::V_CNDMASK_B32_e64:
|
|
|
|
break;
|
|
|
|
}
|
2015-07-13 23:47:57 +08:00
|
|
|
}
|
2014-07-22 00:55:33 +08:00
|
|
|
|
|
|
|
const MachineOperand *Src1 = TII->getNamedOperand(MI, AMDGPU::OpName::src1);
|
2017-07-07 04:56:59 +08:00
|
|
|
if (Src1 && (!isVGPR(Src1, TRI, MRI) ||
|
|
|
|
TII->hasModifiersSet(MI, AMDGPU::OpName::src1_modifiers)))
|
2014-07-22 00:55:33 +08:00
|
|
|
return false;
|
|
|
|
|
2014-10-18 02:00:45 +08:00
|
|
|
// We don't need to check src0, all input types are legal, so just make sure
|
|
|
|
// src0 isn't using any modifiers.
|
|
|
|
if (TII->hasModifiersSet(MI, AMDGPU::OpName::src0_modifiers))
|
2014-07-22 00:55:33 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Check output modifiers
|
2017-07-07 04:56:59 +08:00
|
|
|
return !TII->hasModifiersSet(MI, AMDGPU::OpName::omod) &&
|
|
|
|
!TII->hasModifiersSet(MI, AMDGPU::OpName::clamp);
|
2014-07-22 00:55:33 +08:00
|
|
|
}
|
|
|
|
|
2018-05-01 23:54:18 +08:00
|
|
|
/// This function checks \p MI for operands defined by a move immediate
|
2014-08-01 08:32:33 +08:00
|
|
|
/// instruction and then folds the literal constant into the instruction if it
|
2017-07-11 03:53:57 +08:00
|
|
|
/// can. This function assumes that \p MI is a VOP1, VOP2, or VOPC instructions.
|
|
|
|
static bool foldImmediates(MachineInstr &MI, const SIInstrInfo *TII,
|
2014-08-01 08:32:33 +08:00
|
|
|
MachineRegisterInfo &MRI, bool TryToCommute = true) {
|
2015-10-20 12:35:43 +08:00
|
|
|
assert(TII->isVOP1(MI) || TII->isVOP2(MI) || TII->isVOPC(MI));
|
2014-08-01 08:32:33 +08:00
|
|
|
|
2015-02-14 03:05:03 +08:00
|
|
|
int Src0Idx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src0);
|
2014-08-01 08:32:33 +08:00
|
|
|
|
|
|
|
// Try to fold Src0
|
2016-12-10 08:39:12 +08:00
|
|
|
MachineOperand &Src0 = MI.getOperand(Src0Idx);
|
2017-07-11 03:53:57 +08:00
|
|
|
if (Src0.isReg()) {
|
2015-02-14 03:05:03 +08:00
|
|
|
unsigned Reg = Src0.getReg();
|
2017-07-11 03:53:57 +08:00
|
|
|
if (TargetRegisterInfo::isVirtualRegister(Reg) && MRI.hasOneUse(Reg)) {
|
|
|
|
MachineInstr *Def = MRI.getUniqueVRegDef(Reg);
|
|
|
|
if (Def && Def->isMoveImmediate()) {
|
|
|
|
MachineOperand &MovSrc = Def->getOperand(1);
|
|
|
|
bool ConstantFolded = false;
|
|
|
|
|
|
|
|
if (MovSrc.isImm() && (isInt<32>(MovSrc.getImm()) ||
|
|
|
|
isUInt<32>(MovSrc.getImm()))) {
|
|
|
|
// It's possible to have only one component of a super-reg defined by
|
|
|
|
// a single mov, so we need to clear any subregister flag.
|
|
|
|
Src0.setSubReg(0);
|
|
|
|
Src0.ChangeToImmediate(MovSrc.getImm());
|
|
|
|
ConstantFolded = true;
|
2017-07-11 04:04:35 +08:00
|
|
|
} else if (MovSrc.isFI()) {
|
|
|
|
Src0.setSubReg(0);
|
|
|
|
Src0.ChangeToFrameIndex(MovSrc.getIndex());
|
|
|
|
ConstantFolded = true;
|
2017-07-11 03:53:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ConstantFolded) {
|
|
|
|
assert(MRI.use_empty(Reg));
|
2014-08-01 08:32:33 +08:00
|
|
|
Def->eraseFromParent();
|
2017-07-11 03:53:57 +08:00
|
|
|
++NumLiteralConstantsFolded;
|
|
|
|
return true;
|
|
|
|
}
|
2014-08-01 08:32:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have failed to fold src0, so commute the instruction and try again.
|
2017-07-11 03:53:57 +08:00
|
|
|
if (TryToCommute && MI.isCommutable()) {
|
|
|
|
if (TII->commuteInstruction(MI)) {
|
|
|
|
if (foldImmediates(MI, TII, MRI, false))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Commute back.
|
|
|
|
TII->commuteInstruction(MI);
|
|
|
|
}
|
|
|
|
}
|
2014-08-01 08:32:33 +08:00
|
|
|
|
2017-07-11 03:53:57 +08:00
|
|
|
return false;
|
2014-08-01 08:32:33 +08:00
|
|
|
}
|
|
|
|
|
2015-08-08 08:41:45 +08:00
|
|
|
// Copy MachineOperand with all flags except setting it as implicit.
|
2016-06-21 02:34:00 +08:00
|
|
|
static void copyFlagsToImplicitVCC(MachineInstr &MI,
|
|
|
|
const MachineOperand &Orig) {
|
|
|
|
|
|
|
|
for (MachineOperand &Use : MI.implicit_operands()) {
|
2017-01-12 06:58:12 +08:00
|
|
|
if (Use.isUse() && Use.getReg() == AMDGPU::VCC) {
|
2016-06-21 02:34:00 +08:00
|
|
|
Use.setIsUndef(Orig.isUndef());
|
|
|
|
Use.setIsKill(Orig.isKill());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-08-08 08:41:45 +08:00
|
|
|
}
|
|
|
|
|
2016-04-16 09:46:49 +08:00
|
|
|
static bool isKImmOperand(const SIInstrInfo *TII, const MachineOperand &Src) {
|
2016-12-10 08:39:12 +08:00
|
|
|
return isInt<16>(Src.getImm()) &&
|
|
|
|
!TII->isInlineConstant(*Src.getParent(),
|
|
|
|
Src.getParent()->getOperandNo(&Src));
|
2016-04-16 09:46:49 +08:00
|
|
|
}
|
|
|
|
|
2016-09-17 05:41:16 +08:00
|
|
|
static bool isKUImmOperand(const SIInstrInfo *TII, const MachineOperand &Src) {
|
2016-12-10 08:39:12 +08:00
|
|
|
return isUInt<16>(Src.getImm()) &&
|
|
|
|
!TII->isInlineConstant(*Src.getParent(),
|
|
|
|
Src.getParent()->getOperandNo(&Src));
|
2016-09-17 05:41:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool isKImmOrKUImmOperand(const SIInstrInfo *TII,
|
|
|
|
const MachineOperand &Src,
|
|
|
|
bool &IsUnsigned) {
|
|
|
|
if (isInt<16>(Src.getImm())) {
|
|
|
|
IsUnsigned = false;
|
2016-12-10 08:39:12 +08:00
|
|
|
return !TII->isInlineConstant(Src);
|
2016-09-17 05:41:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isUInt<16>(Src.getImm())) {
|
|
|
|
IsUnsigned = true;
|
2016-12-10 08:39:12 +08:00
|
|
|
return !TII->isInlineConstant(Src);
|
2016-09-17 05:41:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-11-02 07:14:20 +08:00
|
|
|
/// \returns true if the constant in \p Src should be replaced with a bitreverse
|
|
|
|
/// of an inline immediate.
|
|
|
|
static bool isReverseInlineImm(const SIInstrInfo *TII,
|
|
|
|
const MachineOperand &Src,
|
|
|
|
int32_t &ReverseImm) {
|
2016-12-10 08:39:12 +08:00
|
|
|
if (!isInt<32>(Src.getImm()) || TII->isInlineConstant(Src))
|
2016-11-02 07:14:20 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
ReverseImm = reverseBits<int32_t>(static_cast<int32_t>(Src.getImm()));
|
|
|
|
return ReverseImm >= -16 && ReverseImm <= 64;
|
|
|
|
}
|
|
|
|
|
2016-09-04 01:25:39 +08:00
|
|
|
/// Copy implicit register operands from specified instruction to this
|
|
|
|
/// instruction that are not part of the instruction definition.
|
|
|
|
static void copyExtraImplicitOps(MachineInstr &NewMI, MachineFunction &MF,
|
|
|
|
const MachineInstr &MI) {
|
|
|
|
for (unsigned i = MI.getDesc().getNumOperands() +
|
|
|
|
MI.getDesc().getNumImplicitUses() +
|
|
|
|
MI.getDesc().getNumImplicitDefs(), e = MI.getNumOperands();
|
|
|
|
i != e; ++i) {
|
|
|
|
const MachineOperand &MO = MI.getOperand(i);
|
|
|
|
if ((MO.isReg() && MO.isImplicit()) || MO.isRegMask())
|
|
|
|
NewMI.addOperand(MF, MO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-17 05:41:16 +08:00
|
|
|
static void shrinkScalarCompare(const SIInstrInfo *TII, MachineInstr &MI) {
|
|
|
|
// cmpk instructions do scc = dst <cc op> imm16, so commute the instruction to
|
|
|
|
// get constants on the RHS.
|
|
|
|
if (!MI.getOperand(0).isReg())
|
|
|
|
TII->commuteInstruction(MI, false, 0, 1);
|
|
|
|
|
|
|
|
const MachineOperand &Src1 = MI.getOperand(1);
|
|
|
|
if (!Src1.isImm())
|
|
|
|
return;
|
|
|
|
|
|
|
|
int SOPKOpc = AMDGPU::getSOPKOp(MI.getOpcode());
|
|
|
|
if (SOPKOpc == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// eq/ne is special because the imm16 can be treated as signed or unsigned,
|
2016-09-30 09:50:20 +08:00
|
|
|
// and initially selectd to the unsigned versions.
|
|
|
|
if (SOPKOpc == AMDGPU::S_CMPK_EQ_U32 || SOPKOpc == AMDGPU::S_CMPK_LG_U32) {
|
2016-09-17 05:41:16 +08:00
|
|
|
bool HasUImm;
|
|
|
|
if (isKImmOrKUImmOperand(TII, Src1, HasUImm)) {
|
2016-09-30 09:50:20 +08:00
|
|
|
if (!HasUImm) {
|
|
|
|
SOPKOpc = (SOPKOpc == AMDGPU::S_CMPK_EQ_U32) ?
|
|
|
|
AMDGPU::S_CMPK_EQ_I32 : AMDGPU::S_CMPK_LG_I32;
|
2016-09-17 05:41:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
MI.setDesc(TII->get(SOPKOpc));
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const MCInstrDesc &NewDesc = TII->get(SOPKOpc);
|
|
|
|
|
|
|
|
if ((TII->sopkIsZext(SOPKOpc) && isKUImmOperand(TII, Src1)) ||
|
|
|
|
(!TII->sopkIsZext(SOPKOpc) && isKImmOperand(TII, Src1))) {
|
|
|
|
MI.setDesc(NewDesc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-22 00:55:33 +08:00
|
|
|
bool SIShrinkInstructions::runOnMachineFunction(MachineFunction &MF) {
|
2017-12-16 06:22:58 +08:00
|
|
|
if (skipFunction(MF.getFunction()))
|
2016-04-26 06:23:44 +08:00
|
|
|
return false;
|
|
|
|
|
2014-07-22 00:55:33 +08:00
|
|
|
MachineRegisterInfo &MRI = MF.getRegInfo();
|
2016-06-24 14:30:11 +08:00
|
|
|
const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
|
|
|
|
const SIInstrInfo *TII = ST.getInstrInfo();
|
2014-07-22 00:55:33 +08:00
|
|
|
const SIRegisterInfo &TRI = TII->getRegisterInfo();
|
2016-06-24 14:30:11 +08:00
|
|
|
|
2014-07-22 00:55:33 +08:00
|
|
|
std::vector<unsigned> I1Defs;
|
|
|
|
|
|
|
|
for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
|
|
|
|
BI != BE; ++BI) {
|
|
|
|
|
|
|
|
MachineBasicBlock &MBB = *BI;
|
|
|
|
MachineBasicBlock::iterator I, Next;
|
|
|
|
for (I = MBB.begin(); I != MBB.end(); I = Next) {
|
|
|
|
Next = std::next(I);
|
|
|
|
MachineInstr &MI = *I;
|
|
|
|
|
2016-03-11 15:42:49 +08:00
|
|
|
if (MI.getOpcode() == AMDGPU::V_MOV_B32_e32) {
|
|
|
|
// If this has a literal constant source that is the same as the
|
|
|
|
// reversed bits of an inline immediate, replace with a bitreverse of
|
|
|
|
// that constant. This saves 4 bytes in the common case of materializing
|
|
|
|
// sign bits.
|
|
|
|
|
|
|
|
// Test if we are after regalloc. We only want to do this after any
|
|
|
|
// optimizations happen because this will confuse them.
|
|
|
|
// XXX - not exactly a check for post-regalloc run.
|
|
|
|
MachineOperand &Src = MI.getOperand(1);
|
|
|
|
if (Src.isImm() &&
|
|
|
|
TargetRegisterInfo::isPhysicalRegister(MI.getOperand(0).getReg())) {
|
2016-11-02 07:14:20 +08:00
|
|
|
int32_t ReverseImm;
|
|
|
|
if (isReverseInlineImm(TII, Src, ReverseImm)) {
|
|
|
|
MI.setDesc(TII->get(AMDGPU::V_BFREV_B32_e32));
|
|
|
|
Src.setImm(ReverseImm);
|
|
|
|
continue;
|
2016-03-11 15:42:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-26 03:53:22 +08:00
|
|
|
// Combine adjacent s_nops to use the immediate operand encoding how long
|
|
|
|
// to wait.
|
|
|
|
//
|
|
|
|
// s_nop N
|
|
|
|
// s_nop M
|
|
|
|
// =>
|
|
|
|
// s_nop (N + M)
|
|
|
|
if (MI.getOpcode() == AMDGPU::S_NOP &&
|
|
|
|
Next != MBB.end() &&
|
|
|
|
(*Next).getOpcode() == AMDGPU::S_NOP) {
|
|
|
|
|
|
|
|
MachineInstr &NextMI = *Next;
|
|
|
|
// The instruction encodes the amount to wait with an offset of 1,
|
|
|
|
// i.e. 0 is wait 1 cycle. Convert both to cycles and then convert back
|
|
|
|
// after adding.
|
|
|
|
uint8_t Nop0 = MI.getOperand(0).getImm() + 1;
|
|
|
|
uint8_t Nop1 = NextMI.getOperand(0).getImm() + 1;
|
|
|
|
|
|
|
|
// Make sure we don't overflow the bounds.
|
|
|
|
if (Nop0 + Nop1 <= 8) {
|
|
|
|
NextMI.getOperand(0).setImm(Nop0 + Nop1 - 1);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-04-16 09:46:49 +08:00
|
|
|
// FIXME: We also need to consider movs of constant operands since
|
|
|
|
// immediate operands are not folded if they have more than one use, and
|
|
|
|
// the operand folding pass is unaware if the immediate will be free since
|
|
|
|
// it won't know if the src == dest constraint will end up being
|
|
|
|
// satisfied.
|
|
|
|
if (MI.getOpcode() == AMDGPU::S_ADD_I32 ||
|
|
|
|
MI.getOpcode() == AMDGPU::S_MUL_I32) {
|
2016-09-09 01:35:41 +08:00
|
|
|
const MachineOperand *Dest = &MI.getOperand(0);
|
|
|
|
MachineOperand *Src0 = &MI.getOperand(1);
|
|
|
|
MachineOperand *Src1 = &MI.getOperand(2);
|
|
|
|
|
|
|
|
if (!Src0->isReg() && Src1->isReg()) {
|
|
|
|
if (TII->commuteInstruction(MI, false, 1, 2))
|
|
|
|
std::swap(Src0, Src1);
|
|
|
|
}
|
2016-04-16 09:46:49 +08:00
|
|
|
|
|
|
|
// FIXME: This could work better if hints worked with subregisters. If
|
|
|
|
// we have a vector add of a constant, we usually don't get the correct
|
|
|
|
// allocation due to the subregister usage.
|
2016-09-09 01:35:41 +08:00
|
|
|
if (TargetRegisterInfo::isVirtualRegister(Dest->getReg()) &&
|
|
|
|
Src0->isReg()) {
|
|
|
|
MRI.setRegAllocationHint(Dest->getReg(), 0, Src0->getReg());
|
|
|
|
MRI.setRegAllocationHint(Src0->getReg(), 0, Dest->getReg());
|
2016-04-16 09:46:49 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-09-09 01:35:41 +08:00
|
|
|
if (Src0->isReg() && Src0->getReg() == Dest->getReg()) {
|
|
|
|
if (Src1->isImm() && isKImmOperand(TII, *Src1)) {
|
2016-04-16 09:46:49 +08:00
|
|
|
unsigned Opc = (MI.getOpcode() == AMDGPU::S_ADD_I32) ?
|
|
|
|
AMDGPU::S_ADDK_I32 : AMDGPU::S_MULK_I32;
|
|
|
|
|
|
|
|
MI.setDesc(TII->get(Opc));
|
|
|
|
MI.tieOperands(0, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-17 05:41:16 +08:00
|
|
|
// Try to use s_cmpk_*
|
|
|
|
if (MI.isCompare() && TII->isSOPC(MI)) {
|
|
|
|
shrinkScalarCompare(TII, MI);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-04-16 09:46:49 +08:00
|
|
|
// Try to use S_MOVK_I32, which will save 4 bytes for small immediates.
|
|
|
|
if (MI.getOpcode() == AMDGPU::S_MOV_B32) {
|
2016-11-02 07:14:20 +08:00
|
|
|
const MachineOperand &Dst = MI.getOperand(0);
|
|
|
|
MachineOperand &Src = MI.getOperand(1);
|
2016-04-16 09:46:49 +08:00
|
|
|
|
2016-11-02 07:14:20 +08:00
|
|
|
if (Src.isImm() &&
|
|
|
|
TargetRegisterInfo::isPhysicalRegister(Dst.getReg())) {
|
|
|
|
int32_t ReverseImm;
|
|
|
|
if (isKImmOperand(TII, Src))
|
|
|
|
MI.setDesc(TII->get(AMDGPU::S_MOVK_I32));
|
|
|
|
else if (isReverseInlineImm(TII, Src, ReverseImm)) {
|
|
|
|
MI.setDesc(TII->get(AMDGPU::S_BREV_B32));
|
|
|
|
Src.setImm(ReverseImm);
|
|
|
|
}
|
|
|
|
}
|
2016-04-16 09:46:49 +08:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-08-01 08:32:28 +08:00
|
|
|
if (!TII->hasVALU32BitEncoding(MI.getOpcode()))
|
2014-07-22 00:55:33 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!canShrink(MI, TII, TRI, MRI)) {
|
2014-09-17 02:00:23 +08:00
|
|
|
// Try commuting the instruction and see if that enables us to shrink
|
2014-07-22 00:55:33 +08:00
|
|
|
// it.
|
2016-06-30 08:01:54 +08:00
|
|
|
if (!MI.isCommutable() || !TII->commuteInstruction(MI) ||
|
2014-07-22 00:55:33 +08:00
|
|
|
!canShrink(MI, TII, TRI, MRI))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-01-16 02:42:51 +08:00
|
|
|
// getVOPe32 could be -1 here if we started with an instruction that had
|
2014-08-01 08:32:28 +08:00
|
|
|
// a 32-bit encoding and then commuted it to an instruction that did not.
|
2015-01-16 02:42:51 +08:00
|
|
|
if (!TII->hasVALU32BitEncoding(MI.getOpcode()))
|
2014-08-01 08:32:28 +08:00
|
|
|
continue;
|
|
|
|
|
2015-01-16 02:42:51 +08:00
|
|
|
int Op32 = AMDGPU::getVOPe32(MI.getOpcode());
|
|
|
|
|
2014-07-22 00:55:33 +08:00
|
|
|
if (TII->isVOPC(Op32)) {
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
if (TargetRegisterInfo::isVirtualRegister(DstReg)) {
|
2015-08-08 08:41:45 +08:00
|
|
|
// VOPC instructions can only write to the VCC register. We can't
|
|
|
|
// force them to use VCC here, because this is only one register and
|
|
|
|
// cannot deal with sequences which would require multiple copies of
|
|
|
|
// VCC, e.g. S_AND_B64 (vcc = V_CMP_...), (vcc = V_CMP_...)
|
2014-07-22 00:55:33 +08:00
|
|
|
//
|
2014-09-22 01:27:32 +08:00
|
|
|
// So, instead of forcing the instruction to write to VCC, we provide
|
2018-04-13 19:37:06 +08:00
|
|
|
// a hint to the register allocator to use VCC and then we will run
|
2014-09-22 01:27:32 +08:00
|
|
|
// this pass again after RA and shrink it if it outputs to VCC.
|
2014-07-22 00:55:33 +08:00
|
|
|
MRI.setRegAllocationHint(MI.getOperand(0).getReg(), 0, AMDGPU::VCC);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (DstReg != AMDGPU::VCC)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-07-14 22:15:03 +08:00
|
|
|
if (Op32 == AMDGPU::V_CNDMASK_B32_e32) {
|
|
|
|
// We shrink V_CNDMASK_B32_e64 using regalloc hints like we do for VOPC
|
|
|
|
// instructions.
|
|
|
|
const MachineOperand *Src2 =
|
|
|
|
TII->getNamedOperand(MI, AMDGPU::OpName::src2);
|
|
|
|
if (!Src2->isReg())
|
|
|
|
continue;
|
|
|
|
unsigned SReg = Src2->getReg();
|
|
|
|
if (TargetRegisterInfo::isVirtualRegister(SReg)) {
|
|
|
|
MRI.setRegAllocationHint(SReg, 0, AMDGPU::VCC);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (SReg != AMDGPU::VCC)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-01-12 06:35:17 +08:00
|
|
|
// Check for the bool flag output for instructions like V_ADD_I32_e64.
|
|
|
|
const MachineOperand *SDst = TII->getNamedOperand(MI,
|
|
|
|
AMDGPU::OpName::sdst);
|
|
|
|
|
2017-01-12 06:58:12 +08:00
|
|
|
// Check the carry-in operand for v_addc_u32_e64.
|
|
|
|
const MachineOperand *Src2 = TII->getNamedOperand(MI,
|
|
|
|
AMDGPU::OpName::src2);
|
|
|
|
|
|
|
|
if (SDst) {
|
|
|
|
if (SDst->getReg() != AMDGPU::VCC) {
|
|
|
|
if (TargetRegisterInfo::isVirtualRegister(SDst->getReg()))
|
|
|
|
MRI.setRegAllocationHint(SDst->getReg(), 0, AMDGPU::VCC);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// All of the instructions with carry outs also have an SGPR input in
|
|
|
|
// src2.
|
|
|
|
if (Src2 && Src2->getReg() != AMDGPU::VCC) {
|
|
|
|
if (TargetRegisterInfo::isVirtualRegister(Src2->getReg()))
|
|
|
|
MRI.setRegAllocationHint(Src2->getReg(), 0, AMDGPU::VCC);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2017-01-12 06:35:17 +08:00
|
|
|
}
|
|
|
|
|
2014-07-22 00:55:33 +08:00
|
|
|
// We can shrink this instruction
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "Shrinking " << MI);
|
2014-07-22 00:55:33 +08:00
|
|
|
|
2014-08-01 08:32:33 +08:00
|
|
|
MachineInstrBuilder Inst32 =
|
2014-07-22 00:55:33 +08:00
|
|
|
BuildMI(MBB, I, MI.getDebugLoc(), TII->get(Op32));
|
|
|
|
|
2016-02-17 02:14:56 +08:00
|
|
|
// Add the dst operand if the 32-bit encoding also has an explicit $vdst.
|
2015-08-08 08:41:48 +08:00
|
|
|
// For VOPC instructions, this is replaced by an implicit def of vcc.
|
2016-02-17 02:14:56 +08:00
|
|
|
int Op32DstIdx = AMDGPU::getNamedOperandIdx(Op32, AMDGPU::OpName::vdst);
|
2015-08-08 08:41:48 +08:00
|
|
|
if (Op32DstIdx != -1) {
|
|
|
|
// dst
|
2017-01-13 17:58:52 +08:00
|
|
|
Inst32.add(MI.getOperand(0));
|
2015-08-08 08:41:48 +08:00
|
|
|
} else {
|
|
|
|
assert(MI.getOperand(0).getReg() == AMDGPU::VCC &&
|
|
|
|
"Unexpected case");
|
|
|
|
}
|
|
|
|
|
2014-07-22 00:55:33 +08:00
|
|
|
|
2017-01-13 17:58:52 +08:00
|
|
|
Inst32.add(*TII->getNamedOperand(MI, AMDGPU::OpName::src0));
|
2014-07-22 00:55:33 +08:00
|
|
|
|
|
|
|
const MachineOperand *Src1 =
|
|
|
|
TII->getNamedOperand(MI, AMDGPU::OpName::src1);
|
|
|
|
if (Src1)
|
2017-01-13 17:58:52 +08:00
|
|
|
Inst32.add(*Src1);
|
2014-07-22 00:55:33 +08:00
|
|
|
|
2015-08-08 08:41:45 +08:00
|
|
|
if (Src2) {
|
|
|
|
int Op32Src2Idx = AMDGPU::getNamedOperandIdx(Op32, AMDGPU::OpName::src2);
|
|
|
|
if (Op32Src2Idx != -1) {
|
2017-01-13 17:58:52 +08:00
|
|
|
Inst32.add(*Src2);
|
2015-08-08 08:41:45 +08:00
|
|
|
} else {
|
|
|
|
// In the case of V_CNDMASK_B32_e32, the explicit operand src2 is
|
2016-06-21 02:34:00 +08:00
|
|
|
// replaced with an implicit read of vcc. This was already added
|
|
|
|
// during the initial BuildMI, so find it to preserve the flags.
|
|
|
|
copyFlagsToImplicitVCC(*Inst32, *Src2);
|
2015-08-08 08:41:45 +08:00
|
|
|
}
|
|
|
|
}
|
2015-07-13 23:47:57 +08:00
|
|
|
|
2014-07-22 00:55:33 +08:00
|
|
|
++NumInstructionsShrunk;
|
2014-08-01 08:32:33 +08:00
|
|
|
|
2016-07-19 08:35:03 +08:00
|
|
|
// Copy extra operands not present in the instruction definition.
|
2016-09-04 01:25:39 +08:00
|
|
|
copyExtraImplicitOps(*Inst32, MF, MI);
|
2016-07-19 08:35:03 +08:00
|
|
|
|
|
|
|
MI.eraseFromParent();
|
2014-08-01 08:32:33 +08:00
|
|
|
foldImmediates(*Inst32, TII, MRI);
|
2016-07-19 08:35:03 +08:00
|
|
|
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "e32 MI = " << *Inst32 << '\n');
|
2014-07-22 00:55:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|