forked from OSchip/llvm-project
[VE] (conditional) branch modification & isel patterns
Summary: InstInfo for branch modification, (conditional) branch isel patterns and tests. Reviewed By: arsenm Differential Revision: https://reviews.llvm.org/D73632
This commit is contained in:
parent
b63629a58d
commit
fef80a2946
|
@ -44,6 +44,7 @@ public:
|
|||
void Select(SDNode *N) override;
|
||||
|
||||
// Complex Pattern Selectors.
|
||||
bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
|
||||
bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
|
||||
|
||||
StringRef getPassName() const override {
|
||||
|
@ -55,6 +56,29 @@ public:
|
|||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
bool VEDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
|
||||
if (Addr.getOpcode() == ISD::FrameIndex)
|
||||
return false;
|
||||
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
||||
Addr.getOpcode() == ISD::TargetGlobalAddress ||
|
||||
Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
|
||||
return false; // direct calls.
|
||||
|
||||
if (Addr.getOpcode() == ISD::ADD) {
|
||||
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
|
||||
if (isInt<13>(CN->getSExtValue()))
|
||||
return false; // Let the reg+imm pattern catch this!
|
||||
if (Addr.getOperand(0).getOpcode() == VEISD::Lo ||
|
||||
Addr.getOperand(1).getOpcode() == VEISD::Lo)
|
||||
return false; // Let the reg+imm pattern catch this!
|
||||
R1 = Addr.getOperand(0);
|
||||
R2 = Addr.getOperand(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // Let the reg+imm pattern catch this!
|
||||
}
|
||||
|
||||
bool VEDAGToDAGISel::SelectADDRri(SDValue Addr, SDValue &Base,
|
||||
SDValue &Offset) {
|
||||
auto AddrTy = Addr->getValueType(0);
|
||||
|
|
|
@ -497,8 +497,9 @@ VETargetLowering::VETargetLowering(const TargetMachine &TM,
|
|||
addRegisterClass(MVT::f32, &VE::F32RegClass);
|
||||
addRegisterClass(MVT::f64, &VE::I64RegClass);
|
||||
|
||||
// Custom legalize GlobalAddress nodes into LO/HI parts.
|
||||
// Custom legalize address nodes into LO/HI parts.
|
||||
MVT PtrVT = MVT::getIntegerVT(TM.getPointerSizeInBits(0));
|
||||
setOperationAction(ISD::BlockAddress, PtrVT, Custom);
|
||||
setOperationAction(ISD::GlobalAddress, PtrVT, Custom);
|
||||
|
||||
// VE has no REM or DIVREM operations.
|
||||
|
@ -554,6 +555,10 @@ SDValue VETargetLowering::withTargetFlags(SDValue Op, unsigned TF,
|
|||
return DAG.getTargetGlobalAddress(GA->getGlobal(), SDLoc(GA),
|
||||
GA->getValueType(0), GA->getOffset(), TF);
|
||||
|
||||
if (const BlockAddressSDNode *BA = dyn_cast<BlockAddressSDNode>(Op))
|
||||
return DAG.getTargetBlockAddress(BA->getBlockAddress(), Op.getValueType(),
|
||||
0, TF);
|
||||
|
||||
llvm_unreachable("Unhandled address SDNode");
|
||||
}
|
||||
|
||||
|
@ -594,10 +599,17 @@ SDValue VETargetLowering::LowerGlobalAddress(SDValue Op,
|
|||
return makeAddress(Op, DAG);
|
||||
}
|
||||
|
||||
SDValue VETargetLowering::LowerBlockAddress(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
return makeAddress(Op, DAG);
|
||||
}
|
||||
|
||||
SDValue VETargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
switch (Op.getOpcode()) {
|
||||
default:
|
||||
llvm_unreachable("Should not custom lower this!");
|
||||
case ISD::BlockAddress:
|
||||
return LowerBlockAddress(Op, DAG);
|
||||
case ISD::GlobalAddress:
|
||||
return LowerGlobalAddress(Op, DAG);
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ public:
|
|||
/// Custom Lower {
|
||||
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
|
||||
|
||||
SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
/// } Custom Lower
|
||||
|
||||
|
|
|
@ -38,6 +38,243 @@ VEInstrInfo::VEInstrInfo(VESubtarget &ST)
|
|||
: VEGenInstrInfo(VE::ADJCALLSTACKDOWN, VE::ADJCALLSTACKUP), RI(),
|
||||
Subtarget(ST) {}
|
||||
|
||||
static bool IsIntegerCC(unsigned CC) { return (CC < VECC::CC_AF); }
|
||||
|
||||
static VECC::CondCodes GetOppositeBranchCondition(VECC::CondCodes CC) {
|
||||
switch(CC) {
|
||||
case VECC::CC_IG: return VECC::CC_ILE;
|
||||
case VECC::CC_IL: return VECC::CC_IGE;
|
||||
case VECC::CC_INE: return VECC::CC_IEQ;
|
||||
case VECC::CC_IEQ: return VECC::CC_INE;
|
||||
case VECC::CC_IGE: return VECC::CC_IL;
|
||||
case VECC::CC_ILE: return VECC::CC_IG;
|
||||
case VECC::CC_AF: return VECC::CC_AT;
|
||||
case VECC::CC_G: return VECC::CC_LENAN;
|
||||
case VECC::CC_L: return VECC::CC_GENAN;
|
||||
case VECC::CC_NE: return VECC::CC_EQNAN;
|
||||
case VECC::CC_EQ: return VECC::CC_NENAN;
|
||||
case VECC::CC_GE: return VECC::CC_LNAN;
|
||||
case VECC::CC_LE: return VECC::CC_GNAN;
|
||||
case VECC::CC_NUM: return VECC::CC_NAN;
|
||||
case VECC::CC_NAN: return VECC::CC_NUM;
|
||||
case VECC::CC_GNAN: return VECC::CC_LE;
|
||||
case VECC::CC_LNAN: return VECC::CC_GE;
|
||||
case VECC::CC_NENAN: return VECC::CC_EQ;
|
||||
case VECC::CC_EQNAN: return VECC::CC_NE;
|
||||
case VECC::CC_GENAN: return VECC::CC_L;
|
||||
case VECC::CC_LENAN: return VECC::CC_G;
|
||||
case VECC::CC_AT: return VECC::CC_AF;
|
||||
}
|
||||
llvm_unreachable("Invalid cond code");
|
||||
}
|
||||
|
||||
// Treat br.l [BCR AT] as unconditional branch
|
||||
static bool isUncondBranchOpcode(int Opc) {
|
||||
return Opc == VE::BCRLa || Opc == VE::BCRWa ||
|
||||
Opc == VE::BCRDa || Opc == VE::BCRSa;
|
||||
}
|
||||
|
||||
static bool isCondBranchOpcode(int Opc) {
|
||||
return Opc == VE::BCRLrr || Opc == VE::BCRLir ||
|
||||
Opc == VE::BCRLrm0 || Opc == VE::BCRLrm1 ||
|
||||
Opc == VE::BCRLim0 || Opc == VE::BCRLim1 ||
|
||||
Opc == VE::BCRWrr || Opc == VE::BCRWir ||
|
||||
Opc == VE::BCRWrm0 || Opc == VE::BCRWrm1 ||
|
||||
Opc == VE::BCRWim0 || Opc == VE::BCRWim1 ||
|
||||
Opc == VE::BCRDrr || Opc == VE::BCRDir ||
|
||||
Opc == VE::BCRDrm0 || Opc == VE::BCRDrm1 ||
|
||||
Opc == VE::BCRDim0 || Opc == VE::BCRDim1 ||
|
||||
Opc == VE::BCRSrr || Opc == VE::BCRSir ||
|
||||
Opc == VE::BCRSrm0 || Opc == VE::BCRSrm1 ||
|
||||
Opc == VE::BCRSim0 || Opc == VE::BCRSim1;
|
||||
}
|
||||
|
||||
static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target,
|
||||
SmallVectorImpl<MachineOperand> &Cond) {
|
||||
Cond.push_back(MachineOperand::CreateImm(LastInst->getOperand(0).getImm()));
|
||||
Cond.push_back(LastInst->getOperand(1));
|
||||
Cond.push_back(LastInst->getOperand(2));
|
||||
Target = LastInst->getOperand(3).getMBB();
|
||||
}
|
||||
|
||||
bool VEInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock *&TBB,
|
||||
MachineBasicBlock *&FBB,
|
||||
SmallVectorImpl<MachineOperand> &Cond,
|
||||
bool AllowModify) const {
|
||||
MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
|
||||
if (I == MBB.end())
|
||||
return false;
|
||||
|
||||
if (!isUnpredicatedTerminator(*I))
|
||||
return false;
|
||||
|
||||
// Get the last instruction in the block.
|
||||
MachineInstr *LastInst = &*I;
|
||||
unsigned LastOpc = LastInst->getOpcode();
|
||||
|
||||
// If there is only one terminator instruction, process it.
|
||||
if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
|
||||
if (isUncondBranchOpcode(LastOpc)) {
|
||||
TBB = LastInst->getOperand(0).getMBB();
|
||||
return false;
|
||||
}
|
||||
if (isCondBranchOpcode(LastOpc)) {
|
||||
// Block ends with fall-through condbranch.
|
||||
parseCondBranch(LastInst, TBB, Cond);
|
||||
return false;
|
||||
}
|
||||
return true; // Can't handle indirect branch.
|
||||
}
|
||||
|
||||
// Get the instruction before it if it is a terminator.
|
||||
MachineInstr *SecondLastInst = &*I;
|
||||
unsigned SecondLastOpc = SecondLastInst->getOpcode();
|
||||
|
||||
// If AllowModify is true and the block ends with two or more unconditional
|
||||
// branches, delete all but the first unconditional branch.
|
||||
if (AllowModify && isUncondBranchOpcode(LastOpc)) {
|
||||
while (isUncondBranchOpcode(SecondLastOpc)) {
|
||||
LastInst->eraseFromParent();
|
||||
LastInst = SecondLastInst;
|
||||
LastOpc = LastInst->getOpcode();
|
||||
if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) {
|
||||
// Return now the only terminator is an unconditional branch.
|
||||
TBB = LastInst->getOperand(0).getMBB();
|
||||
return false;
|
||||
}
|
||||
SecondLastInst = &*I;
|
||||
SecondLastOpc = SecondLastInst->getOpcode();
|
||||
}
|
||||
}
|
||||
|
||||
// If there are three terminators, we don't know what sort of block this is.
|
||||
if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(*--I))
|
||||
return true;
|
||||
|
||||
// If the block ends with a B and a Bcc, handle it.
|
||||
if (isCondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
|
||||
parseCondBranch(SecondLastInst, TBB, Cond);
|
||||
FBB = LastInst->getOperand(0).getMBB();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the block ends with two unconditional branches, handle it. The second
|
||||
// one is not executed.
|
||||
if (isUncondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
|
||||
TBB = SecondLastInst->getOperand(0).getMBB();
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO ...likewise if it ends with an indirect branch followed by an unconditional
|
||||
// branch.
|
||||
// if (isIndirectBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) {
|
||||
// I = LastInst;
|
||||
// if (AllowModify)
|
||||
// I->eraseFromParent();
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// Otherwise, can't handle this.
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned VEInstrInfo::insertBranch(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock *TBB,
|
||||
MachineBasicBlock *FBB,
|
||||
ArrayRef<MachineOperand> Cond,
|
||||
const DebugLoc &DL,
|
||||
int *BytesAdded) const {
|
||||
assert(TBB && "insertBranch must not be told to insert a fallthrough");
|
||||
assert((Cond.size() == 3 || Cond.size() == 0) &&
|
||||
"VE branch conditions should have three component!");
|
||||
assert(!BytesAdded && "code size not handled");
|
||||
if (Cond.empty()) {
|
||||
// Uncondition branch
|
||||
assert(!FBB && "Unconditional branch with multiple successors!");
|
||||
BuildMI(&MBB, DL, get(VE::BCRLa))
|
||||
.addMBB(TBB);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Conditional branch
|
||||
// (BCRir CC sy sz addr)
|
||||
assert(Cond[0].isImm() && Cond[2].isReg() && "not implemented");
|
||||
|
||||
unsigned opc[2];
|
||||
const TargetRegisterInfo *TRI = &getRegisterInfo();
|
||||
MachineFunction *MF = MBB.getParent();
|
||||
const MachineRegisterInfo &MRI = MF->getRegInfo();
|
||||
unsigned Reg = Cond[2].getReg();
|
||||
if (IsIntegerCC(Cond[0].getImm())) {
|
||||
if (TRI->getRegSizeInBits(Reg, MRI) == 32) {
|
||||
opc[0] = VE::BCRWir;
|
||||
opc[1] = VE::BCRWrr;
|
||||
} else {
|
||||
opc[0] = VE::BCRLir;
|
||||
opc[1] = VE::BCRLrr;
|
||||
}
|
||||
} else {
|
||||
if (TRI->getRegSizeInBits(Reg, MRI) == 32) {
|
||||
opc[0] = VE::BCRSir;
|
||||
opc[1] = VE::BCRSrr;
|
||||
} else {
|
||||
opc[0] = VE::BCRDir;
|
||||
opc[1] = VE::BCRDrr;
|
||||
}
|
||||
}
|
||||
if (Cond[1].isImm()) {
|
||||
BuildMI(&MBB, DL, get(opc[0]))
|
||||
.add(Cond[0]) // condition code
|
||||
.add(Cond[1]) // lhs
|
||||
.add(Cond[2]) // rhs
|
||||
.addMBB(TBB);
|
||||
} else {
|
||||
BuildMI(&MBB, DL, get(opc[1]))
|
||||
.add(Cond[0])
|
||||
.add(Cond[1])
|
||||
.add(Cond[2])
|
||||
.addMBB(TBB);
|
||||
}
|
||||
|
||||
if (!FBB)
|
||||
return 1;
|
||||
|
||||
BuildMI(&MBB, DL, get(VE::BCRLa))
|
||||
.addMBB(FBB);
|
||||
return 2;
|
||||
}
|
||||
|
||||
unsigned VEInstrInfo::removeBranch(MachineBasicBlock &MBB,
|
||||
int *BytesRemoved) const {
|
||||
assert(!BytesRemoved && "code size not handled");
|
||||
|
||||
MachineBasicBlock::iterator I = MBB.end();
|
||||
unsigned Count = 0;
|
||||
while (I != MBB.begin()) {
|
||||
--I;
|
||||
|
||||
if (I->isDebugValue())
|
||||
continue;
|
||||
|
||||
if (!isUncondBranchOpcode(I->getOpcode()) &&
|
||||
!isCondBranchOpcode(I->getOpcode()))
|
||||
break; // Not a branch
|
||||
|
||||
I->eraseFromParent();
|
||||
I = MBB.end();
|
||||
++Count;
|
||||
}
|
||||
return Count;
|
||||
}
|
||||
|
||||
bool VEInstrInfo::reverseBranchCondition(
|
||||
SmallVectorImpl<MachineOperand> &Cond) const {
|
||||
VECC::CondCodes CC = static_cast<VECC::CondCodes>(Cond[0].getImm());
|
||||
Cond[0].setImm(GetOppositeBranchCondition(CC));
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsAliasOfSX(Register Reg) {
|
||||
return VE::I8RegClass.contains(Reg) || VE::I16RegClass.contains(Reg) ||
|
||||
VE::I32RegClass.contains(Reg) || VE::I64RegClass.contains(Reg) ||
|
||||
|
|
|
@ -37,6 +37,25 @@ public:
|
|||
///
|
||||
const VERegisterInfo &getRegisterInfo() const { return RI; }
|
||||
|
||||
|
||||
/// Branch Analysis & Modification {
|
||||
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
|
||||
MachineBasicBlock *&FBB,
|
||||
SmallVectorImpl<MachineOperand> &Cond,
|
||||
bool AllowModify = false) const override;
|
||||
|
||||
unsigned removeBranch(MachineBasicBlock &MBB,
|
||||
int *BytesRemoved = nullptr) const override;
|
||||
|
||||
unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
|
||||
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
|
||||
const DebugLoc &DL,
|
||||
int *BytesAdded = nullptr) const override;
|
||||
|
||||
bool
|
||||
reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
|
||||
/// } Branch Analysis & Modification
|
||||
|
||||
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg,
|
||||
bool KillSrc) const override;
|
||||
|
|
|
@ -131,9 +131,15 @@ def fcond2cc : SDNodeXForm<cond, [{
|
|||
}]>;
|
||||
|
||||
// Addressing modes.
|
||||
def ADDRrr : ComplexPattern<iPTR, 2, "SelectADDRrr", [], []>;
|
||||
def ADDRri : ComplexPattern<iPTR, 2, "SelectADDRri", [frameindex], []>;
|
||||
|
||||
// ASX format of memory address
|
||||
def MEMrr : Operand<iPTR> {
|
||||
let PrintMethod = "printMemASXOperand";
|
||||
let MIOperandInfo = (ops ptr_rc, ptr_rc);
|
||||
}
|
||||
|
||||
def MEMri : Operand<iPTR> {
|
||||
let PrintMethod = "printMemASXOperand";
|
||||
let MIOperandInfo = (ops ptr_rc, i64imm);
|
||||
|
@ -539,6 +545,55 @@ multiclass BCRm<string opcStr, string opcStrAt, bits<8> opc,
|
|||
let cz = 1;
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
def ir : CF<
|
||||
opc, (outs),
|
||||
(ins CCOp:$cf, immOp:$sy, RC:$sz, brtarget32:$imm32),
|
||||
!strconcat(opcStr, " $sy, $sz, $imm32")> {
|
||||
let cy = 0;
|
||||
let cz = 1;
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
def rm0 : CF<
|
||||
opc, (outs), (ins CCOp:$cf, RC:$sy, immOp2:$sz, brtarget32:$imm32),
|
||||
!strconcat(opcStr, " $sy, (${sz})0, $imm32"), []> {
|
||||
let cy = 1;
|
||||
let cz = 0;
|
||||
let sz{6} = 1;
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
def rm1 : CF<
|
||||
opc, (outs), (ins CCOp:$cf, RC:$sy, immOp2:$sz, brtarget32:$imm32),
|
||||
!strconcat(opcStr, " $sy, (${sz})1, $imm32"), []> {
|
||||
let cy = 1;
|
||||
let cz = 0;
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
def im0 : CF<
|
||||
opc, (outs), (ins CCOp:$cf, immOp:$sy, immOp2:$sz, brtarget32:$imm32),
|
||||
!strconcat(opcStr, " $sy, (${sz})0, $imm32"), []> {
|
||||
let cy = 0;
|
||||
let cz = 0;
|
||||
let sz{6} = 1;
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
def im1 : CF<
|
||||
opc, (outs), (ins CCOp:$cf, immOp:$sy, immOp2:$sz, brtarget32:$imm32),
|
||||
!strconcat(opcStr, " $sy, (${sz})1, $imm32"), []> {
|
||||
let cy = 0;
|
||||
let cz = 0;
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
def a : CF<
|
||||
opc, (outs), (ins brtarget32:$imm32),
|
||||
!strconcat(opcStrAt, " $imm32"), []> {
|
||||
let cy = 0;
|
||||
let sy = 0;
|
||||
let cz = 0;
|
||||
let sz = 0;
|
||||
let cf = 15; /* AT */
|
||||
let isBarrier = 1;
|
||||
let hasSideEffects = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Multiclass for floating point conversion instructions.
|
||||
|
@ -866,6 +921,39 @@ def ST1Bri : RM<
|
|||
def : Pat<(f64 (load ADDRri:$addr)), (LDSri ADDRri:$addr)>;
|
||||
def : Pat<(store f64:$sx, ADDRri:$addr), (STSri ADDRri:$addr, $sx)>;
|
||||
|
||||
// Control-flow
|
||||
|
||||
// Jump instruction
|
||||
let cx = 0, cx2 = 0, bpf = 0 /* NONE */, cy = 1, cz = 1,
|
||||
isBranch = 1, isTerminator = 1, hasDelaySlot = 1, hasSideEffects = 0 in
|
||||
def BC : CF<
|
||||
0x19, (outs), (ins CCOp:$cf, I64:$sy, brtarget32:$imm32),
|
||||
"b.${cf}.l $sy, $imm32">;
|
||||
|
||||
// Jump always instruction is treated as a special case of jump in order
|
||||
// to make finding unconditional jump easy.
|
||||
let cx = 0, cx2 = 0, bpf = 0 /* NONE */, cf = 15 /* AT */, cy = 0, sy = 0,
|
||||
cz = 1,
|
||||
isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1,
|
||||
hasDelaySlot = 1, isCodeGenOnly = 1, hasSideEffects = 0 in {
|
||||
def BArr : CF<
|
||||
0x19, (outs), (ins MEMrr:$addr),
|
||||
"b.l $addr",
|
||||
[(brind ADDRrr:$addr)]>;
|
||||
def BAri : CF<
|
||||
0x19, (outs), (ins MEMri:$addr),
|
||||
"b.l $addr",
|
||||
[(brind ADDRri:$addr)]>;
|
||||
}
|
||||
|
||||
// Jump never instruction is also a special case of jump.
|
||||
let cx = 0, cx2 = 0, bpf = 0 /* NONE */, cf = 0 /* AF */, cy = 1, sy = 0,
|
||||
cz = 1,
|
||||
isBranch = 1, isTerminator = 1, hasDelaySlot = 1, hasSideEffects = 0 in
|
||||
def BN : CF<
|
||||
0x19, (outs), (ins brtarget32:$imm32),
|
||||
"b.af.l $imm32">;
|
||||
|
||||
// Return instruction is also a special case of jump.
|
||||
let cx = 0, cx2 = 0, bpf = 0 /* NONE */, cf = 15 /* AT */, cy = 0, sy = 0,
|
||||
cz = 1, sz = 0x10 /* SX10 */, imm32 = 0, Uses = [SX10],
|
||||
|
@ -879,6 +967,12 @@ def RET : CF<
|
|||
// Branch instruction
|
||||
let cx = 0, cx2 = 0, bpf = 0 /* NONE */ in
|
||||
defm BCRL : BCRm<"br${cf}.l", "br.l", 0x18, I64, i64, simm7Op64, uimm6Op64>;
|
||||
let cx = 1, cx2 = 0, bpf = 0 /* NONE */ in
|
||||
defm BCRW : BCRm<"br${cf}.w", "br.w", 0x18, I32, i32, simm7Op32, uimm6Op32>;
|
||||
let cx = 0, cx2 = 1, bpf = 0 /* NONE */ in
|
||||
defm BCRD : BCRm<"br${cf}.d", "br.d", 0x18, I64, f64, simm7Op64, uimm6Op64>;
|
||||
let cx = 1, cx2 = 1, bpf = 0 /* NONE */ in
|
||||
defm BCRS : BCRm<"br${cf}.s", "br.s", 0x18, F32, f32, simm7Op32, uimm6Op32>;
|
||||
|
||||
let cx = 0, cy = 0, cz = 1, hasSideEffects = 0 in {
|
||||
let sy = 3 in
|
||||
|
@ -1041,6 +1135,22 @@ def : Pat<(call tglobaladdr:$dst),
|
|||
def : Pat<(call i64:$dst),
|
||||
(CALLr i64:$dst)>;
|
||||
|
||||
// Branches
|
||||
def : Pat<(br bb:$addr), (BCRLa bb:$addr)>;
|
||||
|
||||
// brcc
|
||||
def : Pat<(brcc CCSIOp:$cond, i32:$l, i32:$r, bb:$addr),
|
||||
(BCRWrr (icond2cc $cond), $l, $r, bb:$addr)>;
|
||||
def : Pat<(brcc CCUIOp:$cond, i32:$l, i32:$r, bb:$addr),
|
||||
(BCRWir (icond2cc $cond), 0, (CMPUWrr $r, $l), bb:$addr)>;
|
||||
def : Pat<(brcc CCSIOp:$cond, i64:$l, i64:$r, bb:$addr),
|
||||
(BCRLrr (icond2cc $cond), $l, $r, bb:$addr)>;
|
||||
def : Pat<(brcc CCUIOp:$cond, i64:$l, i64:$r, bb:$addr),
|
||||
(BCRLir (icond2cc $cond), 0, (CMPrr $r, $l), bb:$addr)>;
|
||||
def : Pat<(brcc cond:$cond, f32:$l, f32:$r, bb:$addr),
|
||||
(BCRSrr (fcond2cc $cond), $l, $r, bb:$addr)>;
|
||||
def : Pat<(brcc cond:$cond, f64:$l, f64:$r, bb:$addr),
|
||||
(BCRDrr (fcond2cc $cond), $l, $r, bb:$addr)>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pseudo Instructions
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
; RUN: llc < %s -mtriple=ve-unknown-unknown | FileCheck %s
|
||||
|
||||
define signext i8 @func1(i8 signext %a, i8 signext %b) {
|
||||
; CHECK-LABEL: func1:
|
||||
; CHECK: .LBB{{[0-9]+}}_5:
|
||||
; CHECK-NEXT: brle.w %s0, %s1, .LBB0_1
|
||||
; CHECK-NEXT: # %bb.2:
|
||||
; CHECK-NEXT: lea %s0, ret@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, ret@hi(%s0)
|
||||
; CHECK-NEXT: or %s0, 2, (0)1
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: br.l .LBB0_3
|
||||
; CHECK: .LBB{{[0-9]+}}_1:
|
||||
; CHECK-NEXT: or %s0, 0, (0)1
|
||||
; CHECK: .LBB{{[0-9]+}}_3:
|
||||
; CHECK-NEXT: sla.w.sx %s0, %s0, 24
|
||||
; CHECK-NEXT: sra.w.sx %s0, %s0, 24
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
entry:
|
||||
%cmp = icmp sgt i8 %a, %b
|
||||
br i1 %cmp, label %on.true, label %join
|
||||
|
||||
on.true:
|
||||
%ret.val = tail call i32 @ret(i32 2)
|
||||
%r8 = trunc i32 %ret.val to i8
|
||||
br label %join
|
||||
|
||||
join:
|
||||
%r = phi i8 [ %r8, %on.true ], [ 0, %entry ]
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
declare i32 @ret(i32)
|
||||
|
||||
define i32 @func2(i16 signext %a, i16 signext %b) {
|
||||
; CHECK-LABEL: func2:
|
||||
; CHECK: .LBB{{[0-9]+}}_5:
|
||||
; CHECK-NEXT: brle.w %s0, %s1, .LBB1_1
|
||||
; CHECK-NEXT: # %bb.2:
|
||||
; CHECK-NEXT: lea %s0, ret@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, ret@hi(%s0)
|
||||
; CHECK-NEXT: or %s0, 2, (0)1
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: br.l .LBB1_3
|
||||
; CHECK: .LBB{{[0-9]+}}_1:
|
||||
; CHECK-NEXT: or %s0, 0, (0)1
|
||||
; CHECK: .LBB{{[0-9]+}}_3:
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
entry:
|
||||
%cmp = icmp sgt i16 %a, %b
|
||||
br i1 %cmp, label %on.true, label %join
|
||||
|
||||
on.true:
|
||||
%ret.val = tail call i32 @ret(i32 2)
|
||||
br label %join
|
||||
|
||||
join:
|
||||
%r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
define i32 @func3(i32 %a, i32 %b) {
|
||||
; CHECK-LABEL: func3:
|
||||
; CHECK: .LBB{{[0-9]+}}_5:
|
||||
; CHECK-NEXT: brle.w %s0, %s1, .LBB2_1
|
||||
; CHECK-NEXT: # %bb.2:
|
||||
; CHECK-NEXT: lea %s0, ret@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, ret@hi(%s0)
|
||||
; CHECK-NEXT: or %s0, 2, (0)1
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: br.l .LBB2_3
|
||||
; CHECK: .LBB{{[0-9]+}}_1:
|
||||
; CHECK-NEXT: or %s0, 0, (0)1
|
||||
; CHECK: .LBB{{[0-9]+}}_3:
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
entry:
|
||||
%cmp = icmp sgt i32 %a, %b
|
||||
br i1 %cmp, label %on.true, label %join
|
||||
|
||||
on.true:
|
||||
%ret.val = tail call i32 @ret(i32 2)
|
||||
br label %join
|
||||
|
||||
join:
|
||||
%r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
define i32 @func4(i64 %a, i64 %b) {
|
||||
; CHECK-LABEL: func4:
|
||||
; CHECK: .LBB{{[0-9]+}}_5:
|
||||
; CHECK-NEXT: brle.l %s0, %s1, .LBB3_1
|
||||
; CHECK-NEXT: # %bb.2:
|
||||
; CHECK-NEXT: lea %s0, ret@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, ret@hi(%s0)
|
||||
; CHECK-NEXT: or %s0, 2, (0)1
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: br.l .LBB3_3
|
||||
; CHECK: .LBB{{[0-9]+}}_1:
|
||||
; CHECK-NEXT: or %s0, 0, (0)1
|
||||
; CHECK: .LBB{{[0-9]+}}_3:
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
entry:
|
||||
%cmp = icmp sgt i64 %a, %b
|
||||
br i1 %cmp, label %on.true, label %join
|
||||
|
||||
on.true:
|
||||
%ret.val = tail call i32 @ret(i32 2)
|
||||
br label %join
|
||||
|
||||
join:
|
||||
%r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
define i32 @func5(i8 zeroext %a, i8 zeroext %b) {
|
||||
; CHECK-LABEL: func5:
|
||||
; CHECK: .LBB{{[0-9]+}}_5:
|
||||
; CHECK-NEXT: cmpu.w %s0, %s1, %s0
|
||||
; CHECK-NEXT: brle.w 0, %s0, .LBB4_1
|
||||
; CHECK-NEXT: # %bb.2:
|
||||
; CHECK-NEXT: lea %s0, ret@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, ret@hi(%s0)
|
||||
; CHECK-NEXT: or %s0, 2, (0)1
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: br.l .LBB4_3
|
||||
; CHECK: .LBB{{[0-9]+}}_1:
|
||||
; CHECK-NEXT: or %s0, 0, (0)1
|
||||
; CHECK: .LBB{{[0-9]+}}_3:
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
entry:
|
||||
%cmp = icmp ugt i8 %a, %b
|
||||
br i1 %cmp, label %on.true, label %join
|
||||
|
||||
on.true:
|
||||
%ret.val = tail call i32 @ret(i32 2)
|
||||
br label %join
|
||||
|
||||
join:
|
||||
%r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
define i32 @func6(i16 zeroext %a, i16 zeroext %b) {
|
||||
; CHECK-LABEL: func6:
|
||||
; CHECK: .LBB{{[0-9]+}}_5:
|
||||
; CHECK-NEXT: cmpu.w %s0, %s1, %s0
|
||||
; CHECK-NEXT: brle.w 0, %s0, .LBB5_1
|
||||
; CHECK-NEXT: # %bb.2:
|
||||
; CHECK-NEXT: lea %s0, ret@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, ret@hi(%s0)
|
||||
; CHECK-NEXT: or %s0, 2, (0)1
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: br.l .LBB5_3
|
||||
; CHECK: .LBB{{[0-9]+}}_1:
|
||||
; CHECK-NEXT: or %s0, 0, (0)1
|
||||
; CHECK: .LBB{{[0-9]+}}_3:
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
entry:
|
||||
%cmp = icmp ugt i16 %a, %b
|
||||
br i1 %cmp, label %on.true, label %join
|
||||
|
||||
on.true:
|
||||
%ret.val = tail call i32 @ret(i32 2)
|
||||
br label %join
|
||||
|
||||
join:
|
||||
%r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
define i32 @func7(i32 %a, i32 %b) {
|
||||
; CHECK-LABEL: func7:
|
||||
; CHECK: .LBB{{[0-9]+}}_5:
|
||||
; CHECK-NEXT: cmpu.w %s0, %s1, %s0
|
||||
; CHECK-NEXT: brle.w 0, %s0, .LBB6_1
|
||||
; CHECK-NEXT: # %bb.2:
|
||||
; CHECK-NEXT: lea %s0, ret@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, ret@hi(%s0)
|
||||
; CHECK-NEXT: or %s0, 2, (0)1
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: br.l .LBB6_3
|
||||
; CHECK: .LBB{{[0-9]+}}_1:
|
||||
; CHECK-NEXT: or %s0, 0, (0)1
|
||||
; CHECK: .LBB{{[0-9]+}}_3:
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
entry:
|
||||
%cmp = icmp ugt i32 %a, %b
|
||||
br i1 %cmp, label %on.true, label %join
|
||||
|
||||
on.true:
|
||||
%ret.val = tail call i32 @ret(i32 2)
|
||||
br label %join
|
||||
|
||||
join:
|
||||
%r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
define i32 @func8(float %a, float %b) {
|
||||
; CHECK-LABEL: func8:
|
||||
; CHECK: .LBB{{[0-9]+}}_5:
|
||||
; CHECK-NEXT: brlenan.s %s0, %s1, .LBB7_1
|
||||
; CHECK-NEXT: # %bb.2:
|
||||
; CHECK-NEXT: lea %s0, ret@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, ret@hi(%s0)
|
||||
; CHECK-NEXT: or %s0, 2, (0)1
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: br.l .LBB7_3
|
||||
; CHECK: .LBB{{[0-9]+}}_1:
|
||||
; CHECK-NEXT: or %s0, 0, (0)1
|
||||
; CHECK: .LBB{{[0-9]+}}_3:
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
entry:
|
||||
%cmp = fcmp ogt float %a, %b
|
||||
br i1 %cmp, label %on.true, label %join
|
||||
|
||||
on.true:
|
||||
%ret.val = tail call i32 @ret(i32 2)
|
||||
br label %join
|
||||
|
||||
join:
|
||||
%r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
define i32 @func9(double %a, double %b) {
|
||||
; CHECK-LABEL: func9:
|
||||
; CHECK: .LBB{{[0-9]+}}_5:
|
||||
; CHECK-NEXT: brlenan.d %s0, %s1, .LBB8_1
|
||||
; CHECK-NEXT: # %bb.2:
|
||||
; CHECK-NEXT: lea %s0, ret@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, ret@hi(%s0)
|
||||
; CHECK-NEXT: or %s0, 2, (0)1
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: br.l .LBB8_3
|
||||
; CHECK: .LBB{{[0-9]+}}_1:
|
||||
; CHECK-NEXT: or %s0, 0, (0)1
|
||||
; CHECK: .LBB{{[0-9]+}}_3:
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
entry:
|
||||
%cmp = fcmp ogt double %a, %b
|
||||
br i1 %cmp, label %on.true, label %join
|
||||
|
||||
on.true:
|
||||
%ret.val = tail call i32 @ret(i32 2)
|
||||
br label %join
|
||||
|
||||
join:
|
||||
%r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
define i32 @func10(double %a, double %b) {
|
||||
; CHECK-LABEL: func10:
|
||||
; CHECK: .LBB{{[0-9]+}}_5:
|
||||
; CHECK-NEXT: lea.sl %s1, 1075052544
|
||||
; CHECK-NEXT: brlenan.d %s0, %s1, .LBB9_1
|
||||
; CHECK-NEXT: # %bb.2:
|
||||
; CHECK-NEXT: lea %s0, ret@lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s12, ret@hi(%s0)
|
||||
; CHECK-NEXT: or %s0, 2, (0)1
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: br.l .LBB9_3
|
||||
; CHECK: .LBB{{[0-9]+}}_1:
|
||||
; CHECK-NEXT: or %s0, 0, (0)1
|
||||
; CHECK: .LBB{{[0-9]+}}_3:
|
||||
; CHECK-NEXT: or %s11, 0, %s9
|
||||
entry:
|
||||
%cmp = fcmp ogt double %a, 5.000000e+00
|
||||
br i1 %cmp, label %on.true, label %join
|
||||
|
||||
on.true:
|
||||
%ret.val = tail call i32 @ret(i32 2)
|
||||
br label %join
|
||||
|
||||
join:
|
||||
%r = phi i32 [ %ret.val, %on.true ], [ 0, %entry ]
|
||||
ret i32 %r
|
||||
}
|
Loading…
Reference in New Issue