mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-15 07:59:57 +00:00
[mips] MIPS32R6 compact branch support
Summary: MIPSR6 introduces a class of branches called compact branches. Unlike the traditional MIPS branches which have a delay slot, compact branches do not have a delay slot. The instruction following the compact branch is only executed if the branch is not taken and must not be a branch. It works by generating compact branches for MIPS32R6 when the delay slot filler cannot fill a delay slot. Then, inspecting the generated code for forbidden slot hazards (a compact branch with an adjacent branch or other CTI) and inserting nops to clear this hazard. Patch by Simon Dardis. Reviewers: vkalintiris, dsanders Subscribers: MatzeB, dsanders, llvm-commits Differential Revision: http://reviews.llvm.org/D16353 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263444 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
01d3696081
commit
eacb2ec057
@ -27,6 +27,7 @@ add_llvm_target(MipsCodeGen
|
||||
MipsConstantIslandPass.cpp
|
||||
MipsDelaySlotFiller.cpp
|
||||
MipsFastISel.cpp
|
||||
MipsHazardSchedule.cpp
|
||||
MipsInstrInfo.cpp
|
||||
MipsISelDAGToDAG.cpp
|
||||
MipsISelLowering.cpp
|
||||
|
@ -117,7 +117,12 @@ namespace MipsII {
|
||||
/// FrmOther - This form is for instructions that have no specific format.
|
||||
FrmOther = 6,
|
||||
|
||||
FormMask = 15
|
||||
FormMask = 15,
|
||||
/// IsCTI - Instruction is a Control Transfer Instruction.
|
||||
IsCTI = 1 << 4,
|
||||
/// HasForbiddenSlot - Instruction has a forbidden slot.
|
||||
HasForbiddenSlot = 1 << 5
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ namespace llvm {
|
||||
FunctionPass *createMipsModuleISelDagPass(MipsTargetMachine &TM);
|
||||
FunctionPass *createMipsOptimizePICCallPass(MipsTargetMachine &TM);
|
||||
FunctionPass *createMipsDelaySlotFillerPass(MipsTargetMachine &TM);
|
||||
FunctionPass *createMipsHazardSchedule(MipsTargetMachine &tm);
|
||||
FunctionPass *createMipsLongBranchPass(MipsTargetMachine &TM);
|
||||
FunctionPass *createMipsConstantIslandPass(MipsTargetMachine &tm);
|
||||
} // end namespace llvm;
|
||||
|
@ -182,6 +182,7 @@ class CMP_CONDN_DESC_BASE<string CondStr, string Typestr,
|
||||
dag InOperandList = (ins FGROpnd:$fs, FGROpnd:$ft);
|
||||
string AsmString = !strconcat("cmp.", CondStr, ".", Typestr, "\t$fd, $fs, $ft");
|
||||
list<dag> Pattern = [(set FGRCCOpnd:$fd, (Op FGROpnd:$fs, FGROpnd:$ft))];
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
multiclass CMP_CC_M <FIELD_CMP_FORMAT Format, string Typestr,
|
||||
@ -300,6 +301,7 @@ class BRANCH_DESC_BASE {
|
||||
bit isBranch = 1;
|
||||
bit isTerminator = 1;
|
||||
bit hasDelaySlot = 0;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class BC_DESC_BASE<string instr_asm, DAGOperand opnd> : BRANCH_DESC_BASE,
|
||||
@ -309,6 +311,7 @@ class BC_DESC_BASE<string instr_asm, DAGOperand opnd> : BRANCH_DESC_BASE,
|
||||
string AsmString = !strconcat(instr_asm, "\t$offset");
|
||||
bit isBarrier = 1;
|
||||
InstrItinClass Itinerary = II_BC;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class CMP_BC_DESC_BASE<string instr_asm, DAGOperand opnd,
|
||||
@ -318,6 +321,8 @@ class CMP_BC_DESC_BASE<string instr_asm, DAGOperand opnd,
|
||||
string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $offset");
|
||||
list<Register> Defs = [AT];
|
||||
InstrItinClass Itinerary = II_BCCC;
|
||||
bit hasForbiddenSlot = 1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class CMP_CBR_EQNE_Z_DESC_BASE<string instr_asm, DAGOperand opnd,
|
||||
@ -327,6 +332,8 @@ class CMP_CBR_EQNE_Z_DESC_BASE<string instr_asm, DAGOperand opnd,
|
||||
string AsmString = !strconcat(instr_asm, "\t$rs, $offset");
|
||||
list<Register> Defs = [AT];
|
||||
InstrItinClass Itinerary = II_BCCZC;
|
||||
bit hasForbiddenSlot = 1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class CMP_CBR_RT_Z_DESC_BASE<string instr_asm, DAGOperand opnd,
|
||||
@ -337,18 +344,22 @@ class CMP_CBR_RT_Z_DESC_BASE<string instr_asm, DAGOperand opnd,
|
||||
string AsmString = !strconcat(instr_asm, "\t$rt, $offset");
|
||||
list<Register> Defs = [AT];
|
||||
InstrItinClass Itinerary = II_BCCZC;
|
||||
bit hasForbiddenSlot = 1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class BAL_DESC : BC_DESC_BASE<"bal", brtarget> {
|
||||
bit isCall = 1;
|
||||
bit hasDelaySlot = 1;
|
||||
list<Register> Defs = [RA];
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class BALC_DESC : BC_DESC_BASE<"balc", brtarget26> {
|
||||
bit isCall = 1;
|
||||
list<Register> Defs = [RA];
|
||||
InstrItinClass Itinerary = II_BALC;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class BC_DESC : BC_DESC_BASE<"bc", brtarget26>;
|
||||
@ -385,6 +396,7 @@ class COP2_BCCZ_DESC_BASE<string instr_asm> : BRANCH_DESC_BASE {
|
||||
dag OutOperandList = (outs);
|
||||
string AsmString = instr_asm;
|
||||
bit hasDelaySlot = 1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class BC2EQZ_DESC : COP2_BCCZ_DESC_BASE<"bc2eqz $ct, $offset">;
|
||||
@ -403,6 +415,7 @@ class JMP_IDX_COMPACT_DESC_BASE<string opstr, DAGOperand opnd,
|
||||
bit isTerminator = 1;
|
||||
bit hasDelaySlot = 0;
|
||||
InstrItinClass Itinerary = itin;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class JIALC_DESC : JMP_IDX_COMPACT_DESC_BASE<"jialc", calloffset16,
|
||||
@ -423,6 +436,7 @@ class JR_HB_R6_DESC : JR_HB_DESC_BASE<"jr.hb", GPR32Opnd> {
|
||||
bit hasDelaySlot = 1;
|
||||
bit isTerminator=1;
|
||||
bit isBarrier=1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class BITSWAP_DESC_BASE<string instr_asm, RegisterOperand GPROpnd,
|
||||
@ -681,6 +695,7 @@ class SDBBP_R6_DESC {
|
||||
dag InOperandList = (ins uimm20:$code_);
|
||||
string AsmString = "sdbbp\t$code_";
|
||||
list<dag> Pattern = [];
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -507,23 +507,13 @@ getUnderlyingObjects(const MachineInstr &MI,
|
||||
// Replace Branch with the compact branch instruction.
|
||||
Iter Filler::replaceWithCompactBranch(MachineBasicBlock &MBB,
|
||||
Iter Branch, DebugLoc DL) {
|
||||
const MipsInstrInfo *TII =
|
||||
MBB.getParent()->getSubtarget<MipsSubtarget>().getInstrInfo();
|
||||
const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>();
|
||||
const MipsInstrInfo *TII = STI.getInstrInfo();
|
||||
|
||||
unsigned NewOpcode =
|
||||
(((unsigned) Branch->getOpcode()) == Mips::BEQ) ? Mips::BEQZC_MM
|
||||
: Mips::BNEZC_MM;
|
||||
|
||||
const MCInstrDesc &NewDesc = TII->get(NewOpcode);
|
||||
MachineInstrBuilder MIB = BuildMI(MBB, Branch, DL, NewDesc);
|
||||
|
||||
MIB.addReg(Branch->getOperand(0).getReg());
|
||||
MIB.addMBB(Branch->getOperand(2).getMBB());
|
||||
|
||||
Iter tmpIter = Branch;
|
||||
Branch = std::prev(Branch);
|
||||
MBB.erase(tmpIter);
|
||||
unsigned NewOpcode = TII->getEquivalentCompactForm(Branch);
|
||||
Branch = TII->genInstrWithNewOpc(NewOpcode, Branch);
|
||||
|
||||
std::next(Branch)->eraseFromParent();
|
||||
return Branch;
|
||||
}
|
||||
|
||||
@ -611,27 +601,27 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
|
||||
// If instruction is BEQ or BNE with one ZERO register, then instead of
|
||||
// adding NOP replace this instruction with the corresponding compact
|
||||
// branch instruction, i.e. BEQZC or BNEZC.
|
||||
unsigned Opcode = I->getOpcode();
|
||||
if (InMicroMipsMode) {
|
||||
switch (Opcode) {
|
||||
case Mips::BEQ:
|
||||
case Mips::BNE:
|
||||
if (((unsigned) I->getOperand(1).getReg()) == Mips::ZERO) {
|
||||
I = replaceWithCompactBranch(MBB, I, I->getDebugLoc());
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case Mips::JR:
|
||||
case Mips::PseudoReturn:
|
||||
case Mips::PseudoIndirectBranch:
|
||||
// For microMIPS the PseudoReturn and PseudoIndirectBranch are allways
|
||||
// expanded to JR_MM, so they can be replaced with JRC16_MM.
|
||||
I = replaceWithCompactJump(MBB, I, I->getDebugLoc());
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
if (TII->getEquivalentCompactForm(I)) {
|
||||
I = replaceWithCompactBranch(MBB, I, I->getDebugLoc());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (I->isIndirectBranch() || I->isReturn()) {
|
||||
// For microMIPS the PseudoReturn and PseudoIndirectBranch are always
|
||||
// expanded to JR_MM, so they can be replaced with JRC16_MM.
|
||||
I = replaceWithCompactJump(MBB, I, I->getDebugLoc());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// For MIPSR6 attempt to produce the corresponding compact (no delay slot)
|
||||
// form of the branch. This should save putting in a NOP.
|
||||
if ((STI.hasMips32r6()) && TII->getEquivalentCompactForm(I)) {
|
||||
I = replaceWithCompactBranch(MBB, I, I->getDebugLoc());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Bundle the NOP to the instruction with the delay slot.
|
||||
BuildMI(MBB, std::next(I), I->getDebugLoc(), TII->get(Mips::NOP));
|
||||
MIBundleBuilder(MBB, I, std::next(I, 2));
|
||||
|
136
lib/Target/Mips/MipsHazardSchedule.cpp
Normal file
136
lib/Target/Mips/MipsHazardSchedule.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
//===-- MipsHazardSchedule.cpp - Workaround pipeline hazards---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This pass is used to workaround certain pipeline hazards. For now, this covers
|
||||
/// compact branch hazards. In future this pass can be extended to other pipeline
|
||||
/// hazards, such as various MIPS1 hazards, processor errata that require
|
||||
/// instruction reorganization, etc.
|
||||
///
|
||||
/// This pass has to run after the delay slot filler as that pass can introduce
|
||||
/// pipeline hazards, hence the existing hazard recognizer is not suitable.
|
||||
///
|
||||
/// Hazards handled: forbidden slots for MIPSR6.
|
||||
///
|
||||
/// A forbidden slot hazard occurs when a compact branch instruction is executed
|
||||
/// and the adjacent instruction in memory is a control transfer instruction such
|
||||
/// as a branch or jump, ERET, ERETNC, DERET, WAIT and PAUSE.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// 0x8004 bnec a1,v0,<P+0x18>
|
||||
/// 0x8008 beqc a1,a2,<P+0x54>
|
||||
///
|
||||
/// In such cases, the processor is required to signal a Reserved Instruction
|
||||
/// exception.
|
||||
///
|
||||
/// Here, if the instruction at 0x8004 is executed, the processor will raise an
|
||||
/// exception as there is a control transfer instruction at 0x8008.
|
||||
///
|
||||
/// There are two sources of forbidden slot hazards:
|
||||
///
|
||||
/// A) A previous pass has created a compact branch directly.
|
||||
/// B) Transforming a delay slot branch into compact branch. This case can be
|
||||
/// difficult to process as lookahead for hazards is insufficent, as
|
||||
/// backwards delay slot fillling can also produce hazards in previously
|
||||
/// processed instuctions.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Mips.h"
|
||||
#include "MipsInstrInfo.h"
|
||||
#include "MipsSEInstrInfo.h"
|
||||
#include "MipsTargetMachine.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "mips-hazard-schedule"
|
||||
|
||||
STATISTIC(NumInsertedNops, "Number of nops inserted");
|
||||
|
||||
namespace {
|
||||
|
||||
typedef MachineBasicBlock::iterator Iter;
|
||||
typedef MachineBasicBlock::reverse_iterator ReverseIter;
|
||||
|
||||
class MipsHazardSchedule : public MachineFunctionPass {
|
||||
|
||||
public:
|
||||
MipsHazardSchedule(TargetMachine &tm) : MachineFunctionPass(ID), TM(tm) {}
|
||||
|
||||
const char *getPassName() const override { return "Mips Hazard Schedule"; }
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &F) override;
|
||||
|
||||
private:
|
||||
static char ID;
|
||||
const TargetMachine &TM;
|
||||
};
|
||||
|
||||
char MipsHazardSchedule::ID = 0;
|
||||
} // end of anonymous namespace
|
||||
|
||||
/// Returns a pass that clears pipeline hazards.
|
||||
FunctionPass *llvm::createMipsHazardSchedule(MipsTargetMachine &tm) {
|
||||
return new MipsHazardSchedule(tm);
|
||||
}
|
||||
|
||||
bool MipsHazardSchedule::runOnMachineFunction(MachineFunction &MF) {
|
||||
|
||||
const MipsSubtarget *STI =
|
||||
&static_cast<const MipsSubtarget &>(MF.getSubtarget());
|
||||
|
||||
// Forbidden slot hazards are only defined for MIPSR6.
|
||||
if (!STI->hasMips32r6() || STI->inMicroMipsMode())
|
||||
return false;
|
||||
|
||||
bool Changed = false;
|
||||
const MipsInstrInfo *TII = STI->getInstrInfo();
|
||||
|
||||
for (MachineFunction::iterator FI = MF.begin(); FI != MF.end(); ++FI) {
|
||||
for (Iter I = FI->begin(); I != FI->end(); ++I) {
|
||||
|
||||
// Forbidden slot hazard handling. Use lookahead over state.
|
||||
if (!TII->HasForbiddenSlot(*I))
|
||||
continue;
|
||||
|
||||
bool InsertNop = false;
|
||||
// Next instruction in the basic block.
|
||||
if (std::next(I) != FI->end() &&
|
||||
!TII->SafeInForbiddenSlot(*std::next(I))) {
|
||||
InsertNop = true;
|
||||
} else {
|
||||
// Next instruction in the physical successor basic block.
|
||||
for (auto *Succ : FI->successors()) {
|
||||
if (FI->isLayoutSuccessor(Succ) &&
|
||||
Succ->getFirstNonDebugInstr() != Succ->end() &&
|
||||
!TII->SafeInForbiddenSlot(*Succ->getFirstNonDebugInstr())) {
|
||||
InsertNop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (InsertNop) {
|
||||
Changed = true;
|
||||
MIBundleBuilder(I)
|
||||
.append(BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP)));
|
||||
NumInsertedNops++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Changed;
|
||||
}
|
@ -1064,6 +1064,8 @@ MipsTargetLowering::emitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB,
|
||||
DebugLoc DL = MI->getDebugLoc();
|
||||
unsigned LL, SC, AND, NOR, ZERO, BEQ;
|
||||
|
||||
// FIXME: The below code should check for the ISA to emit the correct 64bit
|
||||
// operations when the size is 4.
|
||||
if (Size == 4) {
|
||||
if (isMicroMips) {
|
||||
LL = Mips::LL_MM;
|
||||
|
@ -94,10 +94,15 @@ class MipsInst<dag outs, dag ins, string asmstr, list<dag> pattern,
|
||||
//
|
||||
// Attributes specific to Mips instructions...
|
||||
//
|
||||
bits<4> FormBits = Form.Value;
|
||||
bits<4> FormBits = Form.Value;
|
||||
bit isCTI = 0; // Any form of Control Transfer Instruction.
|
||||
// Required for MIPSR6
|
||||
bit hasForbiddenSlot = 0; // Instruction has a forbidden slot.
|
||||
|
||||
// TSFlags layout should be kept in sync with MipsInstrInfo.h.
|
||||
let TSFlags{3-0} = FormBits;
|
||||
let TSFlags{4} = isCTI;
|
||||
let TSFlags{5} = hasForbiddenSlot;
|
||||
|
||||
let DecoderNamespace = "Mips";
|
||||
|
||||
|
@ -256,6 +256,71 @@ MipsInstrInfo::BranchType MipsInstrInfo::AnalyzeBranch(
|
||||
return BT_CondUncond;
|
||||
}
|
||||
|
||||
/// Return the corresponding compact (no delay slot) form of a branch.
|
||||
unsigned MipsInstrInfo::getEquivalentCompactForm(
|
||||
const MachineBasicBlock::iterator I) const {
|
||||
unsigned Opcode = I->getOpcode();
|
||||
bool canUseShortMMBranches =
|
||||
Subtarget.inMicroMipsMode() &&
|
||||
(Opcode == Mips::BNE || Opcode == Mips::BEQ) &&
|
||||
I->getOperand(1).getReg() == Subtarget.getABI().GetZeroReg();
|
||||
|
||||
if (Subtarget.hasMips32r6() || canUseShortMMBranches) {
|
||||
switch (Opcode) {
|
||||
case Mips::B:
|
||||
return Mips::BC;
|
||||
case Mips::BAL:
|
||||
return Mips::BALC;
|
||||
case Mips::BEQ:
|
||||
if (canUseShortMMBranches)
|
||||
return Mips::BEQZC_MM;
|
||||
else
|
||||
return Mips::BEQC;
|
||||
case Mips::BNE:
|
||||
if (canUseShortMMBranches)
|
||||
return Mips::BNEZC_MM;
|
||||
else
|
||||
return Mips::BNEC;
|
||||
case Mips::BGE:
|
||||
return Mips::BGEC;
|
||||
case Mips::BGEU:
|
||||
return Mips::BGEUC;
|
||||
case Mips::BGEZ:
|
||||
return Mips::BGEZC;
|
||||
case Mips::BGTZ:
|
||||
return Mips::BGTZC;
|
||||
case Mips::BLEZ:
|
||||
return Mips::BLEZC;
|
||||
case Mips::BLT:
|
||||
return Mips::BLTC;
|
||||
case Mips::BLTU:
|
||||
return Mips::BLTUC;
|
||||
case Mips::BLTZ:
|
||||
return Mips::BLTZC;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Predicate for distingushing between control transfer instructions and all
|
||||
/// other instructions for handling forbidden slots. Consider inline assembly
|
||||
/// as unsafe as well.
|
||||
bool MipsInstrInfo::SafeInForbiddenSlot(const MachineInstr &MI) const {
|
||||
if (MI.isInlineAsm())
|
||||
return false;
|
||||
|
||||
return (MI.getDesc().TSFlags & MipsII::IsCTI) == 0;
|
||||
|
||||
}
|
||||
|
||||
/// Predicate for distingushing instructions that have forbidden slots.
|
||||
bool MipsInstrInfo::HasForbiddenSlot(const MachineInstr &MI) const {
|
||||
return (MI.getDesc().TSFlags & MipsII::HasForbiddenSlot) != 0;
|
||||
}
|
||||
|
||||
/// Return the number of bytes of code the specified instruction may be.
|
||||
unsigned MipsInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const {
|
||||
switch (MI->getOpcode()) {
|
||||
@ -277,10 +342,46 @@ MachineInstrBuilder
|
||||
MipsInstrInfo::genInstrWithNewOpc(unsigned NewOpc,
|
||||
MachineBasicBlock::iterator I) const {
|
||||
MachineInstrBuilder MIB;
|
||||
bool BranchWithZeroOperand = false;
|
||||
|
||||
// Certain branches have two forms: e.g beq $1, $zero, dst vs beqz $1, dest
|
||||
// Pick the zero form of the branch for readable assembly and for greater
|
||||
// branch distance in non-microMIPS mode.
|
||||
if (I->isBranch() && I->getOperand(1).isReg() &&
|
||||
// FIXME: Certain atomic sequences on mips64 generate 32bit references to
|
||||
// Mips::ZERO, which is incorrect. This test should be updated to use
|
||||
// Subtarget.getABI().GetZeroReg() when those atomic sequences and others
|
||||
// are fixed.
|
||||
(I->getOperand(1).getReg() == Mips::ZERO ||
|
||||
I->getOperand(1).getReg() == Mips::ZERO_64)) {
|
||||
BranchWithZeroOperand = true;
|
||||
switch (NewOpc) {
|
||||
case Mips::BEQC:
|
||||
NewOpc = Mips::BEQZC;
|
||||
break;
|
||||
case Mips::BNEC:
|
||||
NewOpc = Mips::BNEZC;
|
||||
break;
|
||||
case Mips::BGEC:
|
||||
NewOpc = Mips::BGEZC;
|
||||
break;
|
||||
case Mips::BLTC:
|
||||
NewOpc = Mips::BLTZC;
|
||||
break;
|
||||
case Mips::BNEZC_MM:
|
||||
case Mips::BEQZC_MM:
|
||||
break;
|
||||
default:
|
||||
BranchWithZeroOperand = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MIB = BuildMI(*I->getParent(), I, I->getDebugLoc(), get(NewOpc));
|
||||
|
||||
for (unsigned J = 0, E = I->getDesc().getNumOperands(); J < E; ++J)
|
||||
MIB.addOperand(I->getOperand(J));
|
||||
if (!(BranchWithZeroOperand && (J == 1)))
|
||||
MIB.addOperand(I->getOperand(J));
|
||||
|
||||
MIB.setMemRefs(I->memoperands_begin(), I->memoperands_end());
|
||||
return MIB;
|
||||
|
@ -70,6 +70,15 @@ public:
|
||||
bool AllowModify,
|
||||
SmallVectorImpl<MachineInstr*> &BranchInstrs) const;
|
||||
|
||||
/// Determine the opcode of a non-delay slot form for a branch if one exists.
|
||||
unsigned getEquivalentCompactForm(const MachineBasicBlock::iterator I) const;
|
||||
|
||||
/// Predicate to determine if an instruction can go in a forbidden slot.
|
||||
bool SafeInForbiddenSlot(const MachineInstr &MI) const;
|
||||
|
||||
/// Predicate to determine if an instruction has a forbidden slot.
|
||||
bool HasForbiddenSlot(const MachineInstr &MI) const;
|
||||
|
||||
/// Insert nop instruction when hazard condition is found
|
||||
void insertNoop(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI) const override;
|
||||
|
@ -348,14 +348,17 @@ class IsCommutable {
|
||||
|
||||
class IsBranch {
|
||||
bit isBranch = 1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class IsReturn {
|
||||
bit isReturn = 1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class IsCall {
|
||||
bit isCall = 1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class IsTailCall {
|
||||
@ -365,6 +368,7 @@ class IsTailCall {
|
||||
bit isBarrier = 1;
|
||||
bit hasExtraSrcRegAllocReq = 1;
|
||||
bit isCodeGenOnly = 1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class IsAsCheapAsAMove {
|
||||
@ -1068,6 +1072,7 @@ class CBranch<string opstr, DAGOperand opnd, PatFrag cond_op,
|
||||
let isTerminator = 1;
|
||||
let hasDelaySlot = DelaySlot;
|
||||
let Defs = [AT];
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class CBranchZero<string opstr, DAGOperand opnd, PatFrag cond_op,
|
||||
@ -1080,6 +1085,7 @@ class CBranchZero<string opstr, DAGOperand opnd, PatFrag cond_op,
|
||||
let isTerminator = 1;
|
||||
let hasDelaySlot = DelaySlot;
|
||||
let Defs = [AT];
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
// SetCC
|
||||
@ -1106,6 +1112,7 @@ class JumpFJ<DAGOperand opnd, string opstr, SDPatternOperator operator,
|
||||
let hasDelaySlot = 1;
|
||||
let DecoderMethod = "DecodeJumpTarget";
|
||||
let Defs = [AT];
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
// Unconditional branch
|
||||
@ -1118,10 +1125,11 @@ class UncondBranch<Instruction BEQInst> :
|
||||
let hasDelaySlot = 1;
|
||||
let AdditionalPredicates = [RelocPIC];
|
||||
let Defs = [AT];
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
// Base class for indirect branch and return instruction classes.
|
||||
let isTerminator=1, isBarrier=1, hasDelaySlot = 1 in
|
||||
let isTerminator=1, isBarrier=1, hasDelaySlot = 1, isCTI = 1 in
|
||||
class JumpFR<string opstr, RegisterOperand RO,
|
||||
SDPatternOperator operator = null_frag>:
|
||||
InstSE<(outs), (ins RO:$rs), "jr\t$rs", [(operator RO:$rs)], II_JR,
|
||||
@ -1134,7 +1142,7 @@ class IndirectBranch<string opstr, RegisterOperand RO> : JumpFR<opstr, RO> {
|
||||
}
|
||||
|
||||
// Jump and Link (Call)
|
||||
let isCall=1, hasDelaySlot=1, Defs = [RA] in {
|
||||
let isCall=1, hasDelaySlot=1, isCTI=1, Defs = [RA] in {
|
||||
class JumpLink<string opstr, DAGOperand opnd> :
|
||||
InstSE<(outs), (ins opnd:$target), !strconcat(opstr, "\t$target"),
|
||||
[(MipsJmpLink tglobaladdr:$target)], II_JAL, FrmJ, opstr> {
|
||||
@ -1160,7 +1168,7 @@ let isCall=1, hasDelaySlot=1, Defs = [RA] in {
|
||||
}
|
||||
|
||||
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, hasDelaySlot = 1,
|
||||
hasExtraSrcRegAllocReq = 1, Defs = [AT] in {
|
||||
hasExtraSrcRegAllocReq = 1, isCTI = 1, Defs = [AT] in {
|
||||
class TailCall<Instruction JumpInst> :
|
||||
PseudoSE<(outs), (ins calltarget:$target), [], II_J>,
|
||||
PseudoInstExpansion<(JumpInst jmptarget:$target)>;
|
||||
@ -1179,8 +1187,10 @@ class BAL_BR_Pseudo<Instruction RealInst> :
|
||||
let isBarrier = 1;
|
||||
let hasDelaySlot = 1;
|
||||
let Defs = [RA];
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
let isCTI = 1 in {
|
||||
// Syscall
|
||||
class SYS_FT<string opstr, Operand ImmOp> :
|
||||
InstSE<(outs), (ins ImmOp:$code_),
|
||||
@ -1196,15 +1206,16 @@ class ER_FT<string opstr> :
|
||||
InstSE<(outs), (ins),
|
||||
opstr, [], NoItinerary, FrmOther, opstr>;
|
||||
|
||||
// Wait
|
||||
class WAIT_FT<string opstr> :
|
||||
InstSE<(outs), (ins), opstr, [], NoItinerary, FrmOther, opstr>;
|
||||
}
|
||||
|
||||
// Interrupts
|
||||
class DEI_FT<string opstr, RegisterOperand RO> :
|
||||
InstSE<(outs RO:$rt), (ins),
|
||||
!strconcat(opstr, "\t$rt"), [], NoItinerary, FrmOther, opstr>;
|
||||
|
||||
// Wait
|
||||
class WAIT_FT<string opstr> :
|
||||
InstSE<(outs), (ins), opstr, [], NoItinerary, FrmOther, opstr>;
|
||||
|
||||
// Sync
|
||||
let hasSideEffects = 1 in
|
||||
class SYNC_FT<string opstr> :
|
||||
@ -1218,17 +1229,15 @@ class SYNCI_FT<string opstr> :
|
||||
let DecoderMethod = "DecodeSyncI";
|
||||
}
|
||||
|
||||
let hasSideEffects = 1, isCTI = 1 in {
|
||||
class TEQ_FT<string opstr, RegisterOperand RO, Operand ImmOp> :
|
||||
InstSE<(outs), (ins RO:$rs, RO:$rt, ImmOp:$code_),
|
||||
!strconcat(opstr, "\t$rs, $rt, $code_"), [], NoItinerary,
|
||||
FrmI, opstr> {
|
||||
let hasSideEffects = 1;
|
||||
}
|
||||
FrmI, opstr>;
|
||||
|
||||
class TEQI_FT<string opstr, RegisterOperand RO> :
|
||||
InstSE<(outs), (ins RO:$rs, simm16:$imm16),
|
||||
!strconcat(opstr, "\t$rs, $imm16"), [], NoItinerary, FrmOther, opstr> {
|
||||
let hasSideEffects = 1;
|
||||
!strconcat(opstr, "\t$rs, $imm16"), [], NoItinerary, FrmOther, opstr>;
|
||||
}
|
||||
|
||||
// Mul, Div
|
||||
@ -1392,6 +1401,7 @@ class TrapBase<Instruction RealInst>
|
||||
let isBarrier = 1;
|
||||
let isTerminator = 1;
|
||||
let isCodeGenOnly = 1;
|
||||
let isCTI = 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1399,11 +1409,13 @@ class TrapBase<Instruction RealInst>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Return RA.
|
||||
let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1 in
|
||||
def RetRA : PseudoSE<(outs), (ins), [(MipsRet)]>;
|
||||
let isReturn=1, isTerminator=1, isBarrier=1, hasCtrlDep=1, isCTI=1 in {
|
||||
let hasDelaySlot=1 in
|
||||
def RetRA : PseudoSE<(outs), (ins), [(MipsRet)]>;
|
||||
|
||||
let isReturn=1, isTerminator=1, isBarrier=1, hasCtrlDep=1, hasSideEffects=1 in
|
||||
def ERet : PseudoSE<(outs), (ins), [(MipsERet)]>;
|
||||
let hasSideEffects=1 in
|
||||
def ERet : PseudoSE<(outs), (ins), [(MipsERet)]>;
|
||||
}
|
||||
|
||||
let Defs = [SP], Uses = [SP], hasSideEffects = 1 in {
|
||||
def ADJCALLSTACKDOWN : MipsPseudo<(outs), (ins i32imm:$amt),
|
||||
@ -1703,6 +1715,7 @@ class PseudoIndirectBranchBase<RegisterOperand RO> :
|
||||
let hasDelaySlot = 1;
|
||||
let isBranch = 1;
|
||||
let isIndirectBranch = 1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
def PseudoIndirectBranch : PseudoIndirectBranchBase<GPR32Opnd>;
|
||||
@ -1720,6 +1733,7 @@ class PseudoReturnBase<RegisterOperand RO> : MipsPseudo<(outs), (ins RO:$rs),
|
||||
let isCodeGenOnly = 1;
|
||||
let hasCtrlDep = 1;
|
||||
let hasExtraSrcRegAllocReq = 1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
def PseudoReturn : PseudoReturnBase<GPR32Opnd>;
|
||||
@ -1737,7 +1751,7 @@ def SDT_MipsEHRET : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisPtrTy<1>]>;
|
||||
def MIPSehret : SDNode<"MipsISD::EH_RETURN", SDT_MipsEHRET,
|
||||
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
|
||||
|
||||
let Uses = [V0, V1], isTerminator = 1, isReturn = 1, isBarrier = 1 in {
|
||||
let Uses = [V0, V1], isTerminator = 1, isReturn = 1, isBarrier = 1, isCTI = 1 in {
|
||||
def MIPSeh_return32 : MipsPseudo<(outs), (ins GPR32:$spoff, GPR32:$dst),
|
||||
[(MIPSehret GPR32:$spoff, GPR32:$dst)]>;
|
||||
def MIPSeh_return64 : MipsPseudo<(outs), (ins GPR64:$spoff,
|
||||
@ -1845,6 +1859,8 @@ class Barrier<string asmstr> : InstSE<(outs), (ins), asmstr, [], NoItinerary,
|
||||
FrmOther, asmstr>;
|
||||
def SSNOP : MMRel, StdMMR6Rel, Barrier<"ssnop">, BARRIER_FM<1>;
|
||||
def EHB : MMRel, Barrier<"ehb">, BARRIER_FM<3>;
|
||||
|
||||
let isCTI = 1 in
|
||||
def PAUSE : MMRel, StdMMR6Rel, Barrier<"pause">, BARRIER_FM<5>, ISA_MIPS32R2;
|
||||
|
||||
// JR_HB and JALR_HB are defined here using the new style naming
|
||||
@ -1873,12 +1889,14 @@ class JR_HB_DESC : InstSE<(outs), (ins), "", [], NoItinerary, FrmJ>,
|
||||
let hasDelaySlot=1;
|
||||
let isTerminator=1;
|
||||
let isBarrier=1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class JALR_HB_DESC : InstSE<(outs), (ins), "", [], NoItinerary, FrmJ>,
|
||||
JALR_HB_DESC_BASE<"jalr.hb", GPR32Opnd> {
|
||||
let isIndirectBranch=1;
|
||||
let hasDelaySlot=1;
|
||||
bit isCTI = 1;
|
||||
}
|
||||
|
||||
class JR_HB_ENC : JR_HB_FM<8>;
|
||||
@ -2095,7 +2113,7 @@ def JalOneReg : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs),
|
||||
def NORImm : MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, GPR32Opnd:$rt, simm16:$imm),
|
||||
"nor\t$rs, $rt, $imm"> ;
|
||||
|
||||
let hasDelaySlot = 1 in {
|
||||
let hasDelaySlot = 1, isCTI = 1 in {
|
||||
def BneImm : MipsAsmPseudoInst<(outs GPR32Opnd:$rt),
|
||||
(ins imm64:$imm64, brtarget:$offset),
|
||||
"bne\t$rt, $imm64, $offset">;
|
||||
@ -2126,6 +2144,7 @@ def BLEUL: CondBranchPseudo<"bleul">, ISA_MIPS2_NOT_32R6_64R6;
|
||||
def BGEUL: CondBranchPseudo<"bgeul">, ISA_MIPS2_NOT_32R6_64R6;
|
||||
def BGTUL: CondBranchPseudo<"bgtul">, ISA_MIPS2_NOT_32R6_64R6;
|
||||
|
||||
let isCTI = 1 in
|
||||
class CondBranchImmPseudo<string instr_asm> :
|
||||
MipsAsmPseudoInst<(outs), (ins GPR32Opnd:$rs, imm64:$imm, brtarget:$offset),
|
||||
!strconcat(instr_asm, "\t$rs, $imm, $offset")>;
|
||||
|
@ -421,6 +421,14 @@ unsigned MipsSEInstrInfo::getOppositeBranchOpc(unsigned Opc) const {
|
||||
case Mips::BC1F: return Mips::BC1T;
|
||||
case Mips::BEQZC_MM: return Mips::BNEZC_MM;
|
||||
case Mips::BNEZC_MM: return Mips::BEQZC_MM;
|
||||
case Mips::BEQZC: return Mips::BNEZC;
|
||||
case Mips::BNEZC: return Mips::BEQZC;
|
||||
case Mips::BEQC: return Mips::BNEC;
|
||||
case Mips::BNEC: return Mips::BEQC;
|
||||
case Mips::BGTZC: return Mips::BLEZC;
|
||||
case Mips::BGEZC: return Mips::BLTZC;
|
||||
case Mips::BLTZC: return Mips::BGEZC;
|
||||
case Mips::BLEZC: return Mips::BGTZC;
|
||||
}
|
||||
}
|
||||
|
||||
@ -494,8 +502,12 @@ unsigned MipsSEInstrInfo::getAnalyzableBrOpc(unsigned Opc) const {
|
||||
Opc == Mips::BEQ64 || Opc == Mips::BNE64 || Opc == Mips::BGTZ64 ||
|
||||
Opc == Mips::BGEZ64 || Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 ||
|
||||
Opc == Mips::BC1T || Opc == Mips::BC1F || Opc == Mips::B ||
|
||||
Opc == Mips::J || Opc == Mips::BEQZC_MM || Opc == Mips::BNEZC_MM) ?
|
||||
Opc : 0;
|
||||
Opc == Mips::J || Opc == Mips::BEQZC_MM || Opc == Mips::BNEZC_MM ||
|
||||
Opc == Mips::BEQC || Opc == Mips::BNEC || Opc == Mips::BLTC ||
|
||||
Opc == Mips::BGEC || Opc == Mips::BLTUC || Opc == Mips::BGEUC ||
|
||||
Opc == Mips::BGTZC || Opc == Mips::BLEZC || Opc == Mips::BGEZC ||
|
||||
Opc == Mips::BGTZC || Opc == Mips::BEQZC || Opc == Mips::BNEZC ||
|
||||
Opc == Mips::BC) ? Opc : 0;
|
||||
}
|
||||
|
||||
void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB,
|
||||
|
@ -250,7 +250,13 @@ TargetIRAnalysis MipsTargetMachine::getTargetIRAnalysis() {
|
||||
// print out the code after the passes.
|
||||
void MipsPassConfig::addPreEmitPass() {
|
||||
MipsTargetMachine &TM = getMipsTargetMachine();
|
||||
|
||||
// The delay slot filler pass can potientially create forbidden slot (FS)
|
||||
// hazards for MIPSR6 which the hazard schedule pass (HSP) will fix. Any
|
||||
// (new) pass that creates compact branches after the HSP must handle FS
|
||||
// hazards itself or be pipelined before the HSP.
|
||||
addPass(createMipsDelaySlotFillerPass(TM));
|
||||
addPass(createMipsHazardSchedule(TM));
|
||||
addPass(createMipsLongBranchPass(TM));
|
||||
addPass(createMipsConstantIslandPass(TM));
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ entry:
|
||||
; GPR: cmp.lt.d $[[FGRCC:f[0-9]+]], $[[Z]], $f12
|
||||
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC]]
|
||||
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
|
||||
; GPR: bnez $[[GPRCC]], $BB
|
||||
; GPR: bnezc $[[GPRCC]], $BB
|
||||
|
||||
%cmp = fcmp ogt double %a, 0.000000e+00
|
||||
br i1 %cmp, label %if.end6, label %if.else
|
||||
@ -50,7 +50,8 @@ entry:
|
||||
; GPR: cmp.eq.s $[[FGRCC:f[0-9]+]], $f12, $[[Z]]
|
||||
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC]]
|
||||
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
|
||||
; GPR: beqz $[[GPRCC]], $BB
|
||||
; 64-GPR beqzc $[[GPRCC]], $BB
|
||||
; 32-GPR beqz $[[GPRCC]], $BB
|
||||
|
||||
%cmp = fcmp une float %f, 0.000000e+00
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
@ -1,10 +1,10 @@
|
||||
; RUN: llc -march=mipsel --disable-machine-licm -mcpu=mips32 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS32-ANY -check-prefix=NO-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
|
||||
; RUN: llc -march=mipsel --disable-machine-licm -mcpu=mips32r2 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS32-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
|
||||
; RUN: llc -march=mipsel --disable-machine-licm -mcpu=mips32r6 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS32-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
|
||||
; RUN: llc -march=mipsel --disable-machine-licm -mcpu=mips32r6 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS32-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=MIPSR6
|
||||
; RUN: llc -march=mips64el --disable-machine-licm -mcpu=mips4 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS64-ANY -check-prefix=NO-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
|
||||
; RUN: llc -march=mips64el --disable-machine-licm -mcpu=mips64 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS64-ANY -check-prefix=NO-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
|
||||
; RUN: llc -march=mips64el --disable-machine-licm -mcpu=mips64r2 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS64-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
|
||||
; RUN: llc -march=mips64el --disable-machine-licm -mcpu=mips64r6 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS64-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=NOT-MICROMIPS
|
||||
; RUN: llc -march=mips64el --disable-machine-licm -mcpu=mips64r6 < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS64-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=MIPSR6
|
||||
; RUN: llc -march=mipsel --disable-machine-licm -mcpu=mips32r2 -mattr=micromips < %s | FileCheck %s -check-prefix=ALL -check-prefix=MIPS32-ANY -check-prefix=HAS-SEB-SEH -check-prefix=CHECK-EL -check-prefix=MICROMIPS
|
||||
|
||||
; Keep one big-endian check so that we don't reduce testing, but don't add more
|
||||
@ -29,6 +29,7 @@ entry:
|
||||
; ALL: sc $[[R2]], 0($[[R0]])
|
||||
; NOT-MICROMIPS: beqz $[[R2]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R2]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R2]], $[[BB0]]
|
||||
}
|
||||
|
||||
define i32 @AtomicLoadNand32(i32 signext %incr) nounwind {
|
||||
@ -48,6 +49,7 @@ entry:
|
||||
; ALL: sc $[[R2]], 0($[[R0]])
|
||||
; NOT-MICROMIPS: beqz $[[R2]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R2]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R2]], $[[BB0]]
|
||||
}
|
||||
|
||||
define i32 @AtomicSwap32(i32 signext %newval) nounwind {
|
||||
@ -68,6 +70,7 @@ entry:
|
||||
; ALL: sc $[[R2:[0-9]+]], 0($[[R0]])
|
||||
; NOT-MICROMIPS: beqz $[[R2]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R2]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R2]], $[[BB0]]
|
||||
}
|
||||
|
||||
define i32 @AtomicCmpSwap32(i32 signext %oldval, i32 signext %newval) nounwind {
|
||||
@ -86,10 +89,13 @@ entry:
|
||||
|
||||
; ALL: $[[BB0:[A-Z_0-9]+]]:
|
||||
; ALL: ll $2, 0($[[R0]])
|
||||
; ALL: bne $2, $4, $[[BB1:[A-Z_0-9]+]]
|
||||
; NOT-MICROMIPS: bne $2, $4, $[[BB1:[A-Z_0-9]+]]
|
||||
; MICROMIPS: bne $2, $4, $[[BB1:[A-Z_0-9]+]]
|
||||
; MIPSR6: bnec $2, $4, $[[BB1:[A-Z_0-9]+]]
|
||||
; ALL: sc $[[R2:[0-9]+]], 0($[[R0]])
|
||||
; NOT-MICROMIPS: beqz $[[R2]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R2]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R2]], $[[BB0]]
|
||||
; ALL: $[[BB1]]:
|
||||
}
|
||||
|
||||
@ -127,6 +133,7 @@ entry:
|
||||
; ALL: sc $[[R14]], 0($[[R2]])
|
||||
; NOT-MICROMIPS: beqz $[[R14]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R14]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R14]], $[[BB0]]
|
||||
|
||||
; ALL: and $[[R15:[0-9]+]], $[[R10]], $[[R7]]
|
||||
; ALL: srlv $[[R16:[0-9]+]], $[[R15]], $[[R5]]
|
||||
@ -167,6 +174,7 @@ entry:
|
||||
; ALL: sc $[[R14]], 0($[[R2]])
|
||||
; NOT-MICROMIPS: beqz $[[R14]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R14]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R14]], $[[BB0]]
|
||||
|
||||
; ALL: and $[[R15:[0-9]+]], $[[R10]], $[[R7]]
|
||||
; ALL: srlv $[[R16:[0-9]+]], $[[R15]], $[[R5]]
|
||||
@ -208,6 +216,7 @@ entry:
|
||||
; ALL: sc $[[R14]], 0($[[R2]])
|
||||
; NOT-MICROMIPS: beqz $[[R14]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R14]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R14]], $[[BB0]]
|
||||
|
||||
; ALL: and $[[R15:[0-9]+]], $[[R10]], $[[R7]]
|
||||
; ALL: srlv $[[R16:[0-9]+]], $[[R15]], $[[R5]]
|
||||
@ -247,6 +256,7 @@ entry:
|
||||
; ALL: sc $[[R14]], 0($[[R2]])
|
||||
; NOT-MICROMIPS: beqz $[[R14]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R14]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R14]], $[[BB0]]
|
||||
|
||||
; ALL: and $[[R15:[0-9]+]], $[[R10]], $[[R7]]
|
||||
; ALL: srlv $[[R16:[0-9]+]], $[[R15]], $[[R5]]
|
||||
@ -286,13 +296,16 @@ entry:
|
||||
; ALL: $[[BB0:[A-Z_0-9]+]]:
|
||||
; ALL: ll $[[R13:[0-9]+]], 0($[[R2]])
|
||||
; ALL: and $[[R14:[0-9]+]], $[[R13]], $[[R7]]
|
||||
; ALL: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
|
||||
; NOT-MICROMIPS: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
|
||||
; MICROMIPS: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
|
||||
; MIPSR6: bnec $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
|
||||
|
||||
; ALL: and $[[R15:[0-9]+]], $[[R13]], $[[R8]]
|
||||
; ALL: or $[[R16:[0-9]+]], $[[R15]], $[[R12]]
|
||||
; ALL: sc $[[R16]], 0($[[R2]])
|
||||
; NOT-MICROMIPS: beqz $[[R16]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R16]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R16]], $[[BB0]]
|
||||
|
||||
; ALL: $[[BB1]]:
|
||||
; ALL: srlv $[[R17:[0-9]+]], $[[R14]], $[[R5]]
|
||||
@ -327,13 +340,16 @@ entry:
|
||||
; ALL: $[[BB0:[A-Z_0-9]+]]:
|
||||
; ALL: ll $[[R13:[0-9]+]], 0($[[R2]])
|
||||
; ALL: and $[[R14:[0-9]+]], $[[R13]], $[[R7]]
|
||||
; ALL: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
|
||||
; NOT-MICROMIPS: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
|
||||
; MICROMIPS: bne $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
|
||||
; MIPSR6: bnec $[[R14]], $[[R10]], $[[BB1:[A-Z_0-9]+]]
|
||||
|
||||
; ALL: and $[[R15:[0-9]+]], $[[R13]], $[[R8]]
|
||||
; ALL: or $[[R16:[0-9]+]], $[[R15]], $[[R12]]
|
||||
; ALL: sc $[[R16]], 0($[[R2]])
|
||||
; NOT-MICROMIPS: beqz $[[R16]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R16]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R16]], $[[BB0]]
|
||||
|
||||
; ALL: $[[BB1]]:
|
||||
; ALL: srlv $[[R17:[0-9]+]], $[[R14]], $[[R5]]
|
||||
@ -380,6 +396,7 @@ entry:
|
||||
; ALL: sc $[[R14]], 0($[[R2]])
|
||||
; NOT-MICROMIPS: beqz $[[R14]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R14]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R14]], $[[BB0]]
|
||||
|
||||
; ALL: and $[[R15:[0-9]+]], $[[R10]], $[[R7]]
|
||||
; ALL: srlv $[[R16:[0-9]+]], $[[R15]], $[[R5]]
|
||||
@ -444,4 +461,5 @@ entry:
|
||||
; ALL: sc $[[R2]], 0($[[PTR]])
|
||||
; NOT-MICROMIPS: beqz $[[R2]], $[[BB0]]
|
||||
; MICROMIPS: beqzc $[[R2]], $[[BB0]]
|
||||
; MIPSR6: beqzc $[[R2]], $[[BB0]]
|
||||
}
|
||||
|
155
test/CodeGen/Mips/compactbranches/compact-branches.ll
Normal file
155
test/CodeGen/Mips/compactbranches/compact-branches.ll
Normal file
@ -0,0 +1,155 @@
|
||||
; RUN: llc -march=mipsel -mcpu=mips32r6 -relocation-model=static < %s | FileCheck %s
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @l() {
|
||||
entry:
|
||||
%call = tail call i32 @k()
|
||||
%call1 = tail call i32 @j()
|
||||
%cmp = icmp eq i32 %call, %call1
|
||||
; CHECK: bnec
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry:
|
||||
; CHECK: nop
|
||||
; CHECK: jal
|
||||
tail call void @f(i32 signext -2)
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.then, %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @k()
|
||||
|
||||
declare i32 @j()
|
||||
|
||||
declare void @f(i32 signext)
|
||||
|
||||
; Function Attrs: define void @l2() {
|
||||
define void @l2() {
|
||||
entry:
|
||||
%call = tail call i32 @k()
|
||||
%call1 = tail call i32 @i()
|
||||
%cmp = icmp eq i32 %call, %call1
|
||||
; CHECK beqc
|
||||
br i1 %cmp, label %if.end, label %if.then
|
||||
|
||||
if.then: ; preds = %entry:
|
||||
; CHECK: nop
|
||||
; CHECK: jal
|
||||
tail call void @f(i32 signext -1)
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %entry, %if.then
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i32 @i()
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @l3() {
|
||||
entry:
|
||||
%call = tail call i32 @k()
|
||||
%cmp = icmp slt i32 %call, 0
|
||||
; CHECK : bgez
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry:
|
||||
; CHECK: nop
|
||||
; CHECK: jal
|
||||
tail call void @f(i32 signext 0)
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.then, %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @l4() {
|
||||
entry:
|
||||
%call = tail call i32 @k()
|
||||
%cmp = icmp slt i32 %call, 1
|
||||
; CHECK: bgtzc
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry:
|
||||
; CHECK: nop
|
||||
; CHECK: jal
|
||||
tail call void @f(i32 signext 1)
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.then, %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @l5() {
|
||||
entry:
|
||||
%call = tail call i32 @k()
|
||||
%cmp = icmp sgt i32 %call, 0
|
||||
; CHECK: blezc
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry:
|
||||
; CHECK: nop
|
||||
; CHECK: jal
|
||||
tail call void @f(i32 signext 2)
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.then, %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @l6() {
|
||||
entry:
|
||||
%call = tail call i32 @k()
|
||||
%cmp = icmp sgt i32 %call, -1
|
||||
; CHECK: bltzc
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry:
|
||||
; CHECK: nop
|
||||
; CHECK: jal
|
||||
tail call void @f(i32 signext 3)
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.then, %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @l7() {
|
||||
entry:
|
||||
%call = tail call i32 @k()
|
||||
%cmp = icmp eq i32 %call, 0
|
||||
; CHECK: bnezc
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry:
|
||||
; CHECK: nop
|
||||
; CHECK: jal
|
||||
tail call void @f(i32 signext 4)
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %if.then, %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @l8() {
|
||||
entry:
|
||||
%call = tail call i32 @k()
|
||||
%cmp = icmp eq i32 %call, 0
|
||||
; CHECK: beqzc
|
||||
br i1 %cmp, label %if.end, label %if.then
|
||||
|
||||
if.then: ; preds = %entry:
|
||||
; CHECK: nop
|
||||
; CHECK: jal
|
||||
tail call void @f(i32 signext 5)
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %entry, %if.then
|
||||
ret void
|
||||
}
|
@ -750,7 +750,7 @@ entry:
|
||||
; 32-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
|
||||
; FIXME: This instruction is redundant.
|
||||
; 32-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
|
||||
; 32-CMP-DAG: bnez $[[T4]],
|
||||
; 32-CMP-DAG: bnezc $[[T4]],
|
||||
|
||||
; 64-C-DAG: add.s $[[T0:f[0-9]+]], $f13, $f12
|
||||
; 64-C-DAG: lwc1 $[[T1:f[0-9]+]], %got_ofst($CPI32_0)(
|
||||
@ -763,7 +763,7 @@ entry:
|
||||
; 64-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
|
||||
; FIXME: This instruction is redundant.
|
||||
; 64-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
|
||||
; 64-CMP-DAG: bnez $[[T4]],
|
||||
; 64-CMP-DAG: bnezc $[[T4]],
|
||||
|
||||
%add = fadd fast float %at, %angle
|
||||
%cmp = fcmp ogt float %add, 1.000000e+00
|
||||
@ -794,7 +794,7 @@ entry:
|
||||
; 32-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
|
||||
; FIXME: This instruction is redundant.
|
||||
; 32-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
|
||||
; 32-CMP-DAG: bnez $[[T4]],
|
||||
; 32-CMP-DAG: bnezc $[[T4]],
|
||||
|
||||
; 64-C-DAG: add.d $[[T0:f[0-9]+]], $f13, $f12
|
||||
; 64-C-DAG: ldc1 $[[T1:f[0-9]+]], %got_ofst($CPI33_0)(
|
||||
@ -807,7 +807,7 @@ entry:
|
||||
; 64-CMP-DAG: mfc1 $[[T3:[0-9]+]], $[[T2]]
|
||||
; FIXME: This instruction is redundant.
|
||||
; 64-CMP-DAG: andi $[[T4:[0-9]+]], $[[T3]], 1
|
||||
; 64-CMP-DAG: bnez $[[T4]],
|
||||
; 64-CMP-DAG: bnezc $[[T4]],
|
||||
|
||||
%add = fadd fast double %at, %angle
|
||||
%cmp = fcmp ogt double %add, 1.000000e+00
|
||||
|
@ -18,7 +18,8 @@ entry:
|
||||
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
|
||||
; FIXME: We ought to be able to transform not+bnez -> beqz
|
||||
; GPR: not $[[GPRCC]], $[[GPRCC]]
|
||||
; GPR: bnez $[[GPRCC]], $BB0_2
|
||||
; 32-GPR: bnez $[[GPRCC]], $BB0_2
|
||||
; 64-GPR: bnezc $[[GPRCC]], $BB0_2
|
||||
|
||||
%cmp = fcmp oeq float %f2, %f3
|
||||
br i1 %cmp, label %if.then, label %if.else
|
||||
@ -51,7 +52,8 @@ entry:
|
||||
; 64-GPR: cmp.ule.s $[[FGRCC:f[0-9]+]], $f13, $f12
|
||||
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
|
||||
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
|
||||
; GPR: bnez $[[GPRCC]], $BB1_2
|
||||
; 32-GPR: bnez $[[GPRCC]], $BB1_2
|
||||
; 64-GPR: bnezc $[[GPRCC]], $BB1_2
|
||||
|
||||
%cmp = fcmp olt float %f2, %f3
|
||||
br i1 %cmp, label %if.then, label %if.else
|
||||
@ -80,7 +82,8 @@ entry:
|
||||
; 64-GPR: cmp.ult.s $[[FGRCC:f[0-9]+]], $f13, $f12
|
||||
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
|
||||
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
|
||||
; GPR: beqz $[[GPRCC]], $BB2_2
|
||||
; 32-GPR: beqz $[[GPRCC]], $BB2_2
|
||||
; 64-GPR: beqzc $[[GPRCC]], $BB2_2
|
||||
|
||||
%cmp = fcmp ugt float %f2, %f3
|
||||
br i1 %cmp, label %if.else, label %if.then
|
||||
@ -110,7 +113,8 @@ entry:
|
||||
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
|
||||
; FIXME: We ought to be able to transform not+bnez -> beqz
|
||||
; GPR: not $[[GPRCC]], $[[GPRCC]]
|
||||
; GPR: bnez $[[GPRCC]], $BB3_2
|
||||
; 32-GPR: bnez $[[GPRCC]], $BB3_2
|
||||
; 64-GPR: bnezc $[[GPRCC]], $BB3_2
|
||||
|
||||
%cmp = fcmp oeq double %f2, %f3
|
||||
br i1 %cmp, label %if.then, label %if.else
|
||||
@ -139,7 +143,8 @@ entry:
|
||||
; 64-GPR: cmp.ule.d $[[FGRCC:f[0-9]+]], $f13, $f12
|
||||
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
|
||||
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
|
||||
; GPR: bnez $[[GPRCC]], $BB4_2
|
||||
; 32-GPR: bnez $[[GPRCC]], $BB4_2
|
||||
; 64-GPR: bnezc $[[GPRCC]], $BB4_2
|
||||
|
||||
%cmp = fcmp olt double %f2, %f3
|
||||
br i1 %cmp, label %if.then, label %if.else
|
||||
@ -168,7 +173,8 @@ entry:
|
||||
; 64-GPR: cmp.ult.d $[[FGRCC:f[0-9]+]], $f13, $f12
|
||||
; GPR: mfc1 $[[GPRCC:[0-9]+]], $[[FGRCC:f[0-9]+]]
|
||||
; GPR-NOT: not $[[GPRCC]], $[[GPRCC]]
|
||||
; GPR: beqz $[[GPRCC]], $BB5_2
|
||||
; 32-GPR: beqz $[[GPRCC]], $BB5_2
|
||||
; 64-GPR: beqzc $[[GPRCC]], $BB5_2
|
||||
|
||||
%cmp = fcmp ugt double %f2, %f3
|
||||
br i1 %cmp, label %if.else, label %if.then
|
||||
|
Loading…
Reference in New Issue
Block a user