[llvm] r274807 - [lanai] Use peephole optimizer to generate more conditional ALU operations.
Jacques Pienaar via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 7 16:36:04 PDT 2016
Author: jpienaar
Date: Thu Jul 7 18:36:04 2016
New Revision: 274807
URL: http://llvm.org/viewvc/llvm-project?rev=274807&view=rev
Log:
[lanai] Use peephole optimizer to generate more conditional ALU operations.
Summary:
* Similiar to the ARM backend yse the peephole optimizer to generate more conditional ALU operations;
* Add predicated type with default always true to RR instructions in LanaiInstrInfo.td;
* Move LanaiSetflagAluCombiner into optimizeCompare;
* The ASM parser can currently only handle explicitly specified CC, so specify ".t" (true) where needed in the ASM test;
* Remove unused MachineOperand flags;
Reviewers: eliben
Subscribers: aemerson
Differential Revision: http://reviews.llvm.org/D22072
Added:
llvm/trunk/test/CodeGen/Lanai/sub-cmp-peephole.ll
llvm/trunk/test/CodeGen/MIR/Lanai/
llvm/trunk/test/CodeGen/MIR/Lanai/lit.local.cfg
llvm/trunk/test/CodeGen/MIR/Lanai/peephole-compare.mir
Removed:
llvm/trunk/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp
llvm/trunk/test/CodeGen/Lanai/combined_alu_setcc.ll
Modified:
llvm/trunk/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
llvm/trunk/lib/Target/Lanai/CMakeLists.txt
llvm/trunk/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp
llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
llvm/trunk/lib/Target/Lanai/LanaiAsmPrinter.cpp
llvm/trunk/lib/Target/Lanai/LanaiISelLowering.cpp
llvm/trunk/lib/Target/Lanai/LanaiISelLowering.h
llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.cpp
llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.h
llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.td
llvm/trunk/lib/Target/Lanai/LanaiRegisterInfo.cpp
llvm/trunk/lib/Target/Lanai/LanaiTargetMachine.cpp
llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h
llvm/trunk/test/MC/Lanai/v11.s
Modified: llvm/trunk/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp Thu Jul 7 18:36:04 2016
@@ -357,6 +357,20 @@ public:
return isInt<10>(Value);
}
+ bool isCondCode() {
+ if (!isImm())
+ return false;
+
+ const MCConstantExpr *ConstExpr = dyn_cast<MCConstantExpr>(Imm.Value);
+ if (!ConstExpr)
+ return false;
+ uint64_t Value = ConstExpr->getValue();
+ // The condition codes are between 0 (ICC_T) and 15 (ICC_LE). If the
+ // unsigned value of the immediate is less than LPCC::UNKNOWN (16) then
+ // value corresponds to a valid condition code.
+ return Value < LPCC::UNKNOWN;
+ }
+
void addExpr(MCInst &Inst, const MCExpr *Expr) const {
// Add as immediates where possible. Null MCExpr = 0
if (Expr == nullptr)
@@ -388,6 +402,11 @@ public:
addExpr(Inst, getImm());
}
+ void addCondCodeOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ addExpr(Inst, getImm());
+ }
+
void addMemImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const MCExpr *Expr = getMemOffset();
@@ -1031,7 +1050,16 @@ StringRef LanaiAsmParser::splitMnemonic(
LPCC::CondCode CondCode = LPCC::suffixToLanaiCondCode(Mnemonic);
if (CondCode != LPCC::UNKNOWN) {
size_t Next = Mnemonic.rfind('.', Name.size());
- Mnemonic = Mnemonic.substr(0, Next + 1);
+ // 'sel' doesn't use a predicate operand whose printer adds the period,
+ // but instead has the period as part of the identifier (i.e., 'sel.' is
+ // expected by the generated matcher). If the mnemonic starts with 'sel'
+ // then include the period as part of the mnemonic, else don't include it
+ // as part of the mnemonic.
+ if (Mnemonic.startswith("sel")) {
+ Mnemonic = Mnemonic.substr(0, Next + 1);
+ } else {
+ Mnemonic = Mnemonic.substr(0, Next);
+ }
Operands->push_back(LanaiOperand::CreateToken(Mnemonic, NameLoc));
Operands->push_back(LanaiOperand::createImm(
MCConstantExpr::create(CondCode, getContext()), NameLoc, NameLoc));
Modified: llvm/trunk/lib/Target/Lanai/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/CMakeLists.txt?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/CMakeLists.txt (original)
+++ llvm/trunk/lib/Target/Lanai/CMakeLists.txt Thu Jul 7 18:36:04 2016
@@ -23,7 +23,6 @@ add_llvm_target(LanaiCodeGen
LanaiMemAluCombiner.cpp
LanaiRegisterInfo.cpp
LanaiSelectionDAGInfo.cpp
- LanaiSetflagAluCombiner.cpp
LanaiSubtarget.cpp
LanaiTargetMachine.cpp
LanaiTargetObjectFile.cpp
Modified: llvm/trunk/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp Thu Jul 7 18:36:04 2016
@@ -62,6 +62,10 @@ static DecodeStatus decodeSplsValue(MCIn
static DecodeStatus decodeBranch(MCInst &Inst, unsigned Insn, uint64_t Address,
const void *Decoder);
+static DecodeStatus decodePredicateOperand(MCInst &Inst, unsigned Val,
+ uint64_t Address,
+ const void *Decoder);
+
static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn,
uint64_t Address, const void *Decoder);
@@ -226,3 +230,12 @@ static DecodeStatus decodeShiftImm(MCIns
return MCDisassembler::Success;
}
+
+static DecodeStatus decodePredicateOperand(MCInst &Inst, unsigned Val,
+ uint64_t Address,
+ const void *Decoder) {
+ if (Val >= LPCC::UNKNOWN)
+ return MCDisassembler::Fail;
+ Inst.addOperand(MCOperand::createImm(Val));
+ return MCDisassembler::Success;
+}
Modified: llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp Thu Jul 7 18:36:04 2016
@@ -284,6 +284,22 @@ void LanaiInstPrinter::printMemSplsOpera
void LanaiInstPrinter::printCCOperand(const MCInst *MI, int OpNo,
raw_ostream &OS) {
- const int CC = static_cast<const int>(MI->getOperand(OpNo).getImm());
- OS << lanaiCondCodeToString(static_cast<LPCC::CondCode>(CC));
+ LPCC::CondCode CC =
+ static_cast<LPCC::CondCode>(MI->getOperand(OpNo).getImm());
+ // Handle the undefined value here for printing so we don't abort().
+ if (CC >= LPCC::UNKNOWN)
+ OS << "<und>";
+ else
+ OS << lanaiCondCodeToString(CC);
+}
+
+void LanaiInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo,
+ raw_ostream &OS) {
+ LPCC::CondCode CC =
+ static_cast<LPCC::CondCode>(MI->getOperand(OpNo).getImm());
+ // Handle the undefined value here for printing so we don't abort().
+ if (CC >= LPCC::UNKNOWN)
+ OS << "<und>";
+ else if (CC != LPCC::ICC_T)
+ OS << "." << lanaiCondCodeToString(CC);
}
Modified: llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h (original)
+++ llvm/trunk/lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h Thu Jul 7 18:36:04 2016
@@ -29,6 +29,7 @@ public:
const MCSubtargetInfo &STI) override;
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O,
const char *Modifier = 0);
+ void printPredicateOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printMemRiOperand(const MCInst *MI, int OpNo, raw_ostream &O,
const char *Modifier = 0);
void printMemRrOperand(const MCInst *MI, int OpNo, raw_ostream &O,
Modified: llvm/trunk/lib/Target/Lanai/LanaiAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiAsmPrinter.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiAsmPrinter.cpp Thu Jul 7 18:36:04 2016
@@ -65,7 +65,6 @@ private:
void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
raw_ostream &O, const char *Modifier) {
const MachineOperand &MO = MI->getOperand(OpNum);
- unsigned TF = MO.getTargetFlags();
switch (MO.getType()) {
case MachineOperand::MO_Register:
@@ -81,10 +80,7 @@ void LanaiAsmPrinter::printOperand(const
break;
case MachineOperand::MO_GlobalAddress:
- if (TF == LanaiII::MO_PLT)
- O << "plt(" << *getSymbol(MO.getGlobal()) << ")";
- else
- O << *getSymbol(MO.getGlobal());
+ O << *getSymbol(MO.getGlobal());
break;
case MachineOperand::MO_BlockAddress: {
@@ -94,10 +90,7 @@ void LanaiAsmPrinter::printOperand(const
}
case MachineOperand::MO_ExternalSymbol:
- if (TF == LanaiII::MO_PLT)
- O << "plt(" << *GetExternalSymbolSymbol(MO.getSymbolName()) << ")";
- else
- O << *GetExternalSymbolSymbol(MO.getSymbolName());
+ O << *GetExternalSymbolSymbol(MO.getSymbolName());
break;
case MachineOperand::MO_JumpTableIndex:
@@ -116,7 +109,6 @@ void LanaiAsmPrinter::printOperand(const
}
// PrintAsmOperand - Print out an operand for an inline asm expression.
-//
bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode, raw_ostream &O) {
Modified: llvm/trunk/lib/Target/Lanai/LanaiISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiISelLowering.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiISelLowering.cpp Thu Jul 7 18:36:04 2016
@@ -124,6 +124,12 @@ LanaiTargetLowering::LanaiTargetLowering
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);
}
+ setTargetDAGCombine(ISD::ADD);
+ setTargetDAGCombine(ISD::SUB);
+ setTargetDAGCombine(ISD::AND);
+ setTargetDAGCombine(ISD::OR);
+ setTargetDAGCombine(ISD::XOR);
+
// Function alignments (log2)
setMinFunctionAlignment(2);
setPrefFunctionAlignment(2);
@@ -1268,3 +1274,167 @@ SDValue LanaiTargetLowering::LowerSRL_PA
SDValue Ops[2] = {Lo, Hi};
return DAG.getMergeValues(Ops, dl);
}
+
+// Helper function that checks if N is a null or all ones constant.
+static inline bool isZeroOrAllOnes(SDValue N, bool AllOnes) {
+ return AllOnes ? isAllOnesConstant(N) : isNullConstant(N);
+}
+
+// Return true if N is conditionally 0 or all ones.
+// Detects these expressions where cc is an i1 value:
+//
+// (select cc 0, y) [AllOnes=0]
+// (select cc y, 0) [AllOnes=0]
+// (zext cc) [AllOnes=0]
+// (sext cc) [AllOnes=0/1]
+// (select cc -1, y) [AllOnes=1]
+// (select cc y, -1) [AllOnes=1]
+//
+// * AllOnes determines whether to check for an all zero (AllOnes false) or an
+// all ones operand (AllOnes true).
+// * Invert is set when N is the all zero/ones constant when CC is false.
+// * OtherOp is set to the alternative value of N.
+//
+// For example, for (select cc X, Y) and AllOnes = 0 if:
+// * X = 0, Invert = False and OtherOp = Y
+// * Y = 0, Invert = True and OtherOp = X
+static bool isConditionalZeroOrAllOnes(SDNode *N, bool AllOnes, SDValue &CC,
+ bool &Invert, SDValue &OtherOp,
+ SelectionDAG &DAG) {
+ switch (N->getOpcode()) {
+ default:
+ return false;
+ case ISD::SELECT: {
+ CC = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+ SDValue N2 = N->getOperand(2);
+ if (isZeroOrAllOnes(N1, AllOnes)) {
+ Invert = false;
+ OtherOp = N2;
+ return true;
+ }
+ if (isZeroOrAllOnes(N2, AllOnes)) {
+ Invert = true;
+ OtherOp = N1;
+ return true;
+ }
+ return false;
+ }
+ case ISD::ZERO_EXTEND: {
+ // (zext cc) can never be the all ones value.
+ if (AllOnes)
+ return false;
+ CC = N->getOperand(0);
+ if (CC.getValueType() != MVT::i1)
+ return false;
+ SDLoc dl(N);
+ EVT VT = N->getValueType(0);
+ OtherOp = DAG.getConstant(1, dl, VT);
+ Invert = true;
+ return true;
+ }
+ case ISD::SIGN_EXTEND: {
+ CC = N->getOperand(0);
+ if (CC.getValueType() != MVT::i1)
+ return false;
+ SDLoc dl(N);
+ EVT VT = N->getValueType(0);
+ Invert = !AllOnes;
+ if (AllOnes)
+ // When looking for an AllOnes constant, N is an sext, and the 'other'
+ // value is 0.
+ OtherOp = DAG.getConstant(0, dl, VT);
+ else
+ OtherOp =
+ DAG.getConstant(APInt::getAllOnesValue(VT.getSizeInBits()), dl, VT);
+ return true;
+ }
+ }
+}
+
+// Combine a constant select operand into its use:
+//
+// (add (select cc, 0, c), x) -> (select cc, x, (add, x, c))
+// (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c))
+// (and (select cc, -1, c), x) -> (select cc, x, (and, x, c)) [AllOnes=1]
+// (or (select cc, 0, c), x) -> (select cc, x, (or, x, c))
+// (xor (select cc, 0, c), x) -> (select cc, x, (xor, x, c))
+//
+// The transform is rejected if the select doesn't have a constant operand that
+// is null, or all ones when AllOnes is set.
+//
+// Also recognize sext/zext from i1:
+//
+// (add (zext cc), x) -> (select cc (add x, 1), x)
+// (add (sext cc), x) -> (select cc (add x, -1), x)
+//
+// These transformations eventually create predicated instructions.
+static SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp,
+ TargetLowering::DAGCombinerInfo &DCI,
+ bool AllOnes) {
+ SelectionDAG &DAG = DCI.DAG;
+ EVT VT = N->getValueType(0);
+ SDValue NonConstantVal;
+ SDValue CCOp;
+ bool SwapSelectOps;
+ if (!isConditionalZeroOrAllOnes(Slct.getNode(), AllOnes, CCOp, SwapSelectOps,
+ NonConstantVal, DAG))
+ return SDValue();
+
+ // Slct is now know to be the desired identity constant when CC is true.
+ SDValue TrueVal = OtherOp;
+ SDValue FalseVal =
+ DAG.getNode(N->getOpcode(), SDLoc(N), VT, OtherOp, NonConstantVal);
+ // Unless SwapSelectOps says CC should be false.
+ if (SwapSelectOps)
+ std::swap(TrueVal, FalseVal);
+
+ return DAG.getNode(ISD::SELECT, SDLoc(N), VT, CCOp, TrueVal, FalseVal);
+}
+
+// Attempt combineSelectAndUse on each operand of a commutative operator N.
+static SDValue
+combineSelectAndUseCommutative(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
+ bool AllOnes) {
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+ if (N0.getNode()->hasOneUse())
+ if (SDValue Result = combineSelectAndUse(N, N0, N1, DCI, AllOnes))
+ return Result;
+ if (N1.getNode()->hasOneUse())
+ if (SDValue Result = combineSelectAndUse(N, N1, N0, DCI, AllOnes))
+ return Result;
+ return SDValue();
+}
+
+// PerformSUBCombine - Target-specific dag combine xforms for ISD::SUB.
+static SDValue PerformSUBCombine(SDNode *N,
+ TargetLowering::DAGCombinerInfo &DCI) {
+ SDValue N0 = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+
+ // fold (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c))
+ if (N1.getNode()->hasOneUse())
+ if (SDValue Result = combineSelectAndUse(N, N1, N0, DCI, /*AllOnes=*/false))
+ return Result;
+
+ return SDValue();
+}
+
+SDValue LanaiTargetLowering::PerformDAGCombine(SDNode *N,
+ DAGCombinerInfo &DCI) const {
+ switch (N->getOpcode()) {
+ default:
+ break;
+ case ISD::ADD:
+ case ISD::OR:
+ case ISD::XOR:
+ return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/false);
+ case ISD::AND:
+ return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/true);
+ case ISD::SUB:
+ return PerformSUBCombine(N, DCI);
+ }
+
+ return SDValue();
+}
Modified: llvm/trunk/lib/Target/Lanai/LanaiISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiISelLowering.h?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiISelLowering.h (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiISelLowering.h Thu Jul 7 18:36:04 2016
@@ -103,6 +103,8 @@ public:
std::vector<SDValue> &Ops,
SelectionDAG &DAG) const override;
+ SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override;
+
private:
SDValue LowerCCCCallTo(SDValue Chain, SDValue Callee,
CallingConv::ID CallConv, bool IsVarArg,
Modified: llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.cpp Thu Jul 7 18:36:04 2016
@@ -122,7 +122,7 @@ bool LanaiInstrInfo::expandPostRAPseudo(
return false;
}
-static LPCC::CondCode GetOppositeBranchCondition(LPCC::CondCode CC) {
+static LPCC::CondCode getOppositeCondition(LPCC::CondCode CC) {
switch (CC) {
case LPCC::ICC_T: // true
return LPCC::ICC_F;
@@ -161,6 +161,397 @@ static LPCC::CondCode GetOppositeBranchC
}
}
+std::pair<unsigned, unsigned>
+LanaiInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
+ return std::make_pair(TF, 0u);
+}
+
+ArrayRef<std::pair<unsigned, const char *>>
+LanaiInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
+ using namespace LanaiII;
+ static const std::pair<unsigned, const char *> TargetFlags[] = {
+ {MO_ABS_HI, "lanai-hi"},
+ {MO_ABS_LO, "lanai-lo"},
+ {MO_NO_FLAG, "lanai-nf"}};
+ return makeArrayRef(TargetFlags);
+}
+
+bool LanaiInstrInfo::analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
+ unsigned &SrcReg2, int &CmpMask,
+ int &CmpValue) const {
+ switch (MI.getOpcode()) {
+ default:
+ break;
+ case Lanai::SFSUB_F_RI_LO:
+ case Lanai::SFSUB_F_RI_HI:
+ SrcReg = MI.getOperand(0).getReg();
+ SrcReg2 = 0;
+ CmpMask = ~0;
+ CmpValue = MI.getOperand(1).getImm();
+ return true;
+ case Lanai::SFSUB_F_RR:
+ SrcReg = MI.getOperand(0).getReg();
+ SrcReg2 = MI.getOperand(1).getReg();
+ CmpMask = ~0;
+ CmpValue = 0;
+ return true;
+ }
+
+ return false;
+}
+
+// isRedundantFlagInstr - check whether the first instruction, whose only
+// purpose is to update flags, can be made redundant.
+// * SFSUB_F_RR can be made redundant by SUB_RI if the operands are the same.
+// * SFSUB_F_RI can be made redundant by SUB_I if the operands are the same.
+inline static bool isRedundantFlagInstr(MachineInstr *CmpI, unsigned SrcReg,
+ unsigned SrcReg2, int ImmValue,
+ MachineInstr *OI) {
+ if (CmpI->getOpcode() == Lanai::SFSUB_F_RR &&
+ OI->getOpcode() == Lanai::SUB_R &&
+ ((OI->getOperand(1).getReg() == SrcReg &&
+ OI->getOperand(2).getReg() == SrcReg2) ||
+ (OI->getOperand(1).getReg() == SrcReg2 &&
+ OI->getOperand(2).getReg() == SrcReg)))
+ return true;
+
+ if (((CmpI->getOpcode() == Lanai::SFSUB_F_RI_LO &&
+ OI->getOpcode() == Lanai::SUB_I_LO) ||
+ (CmpI->getOpcode() == Lanai::SFSUB_F_RI_HI &&
+ OI->getOpcode() == Lanai::SUB_I_HI)) &&
+ OI->getOperand(1).getReg() == SrcReg &&
+ OI->getOperand(2).getImm() == ImmValue)
+ return true;
+ return false;
+}
+
+inline static unsigned flagSettingOpcodeVariant(unsigned OldOpcode) {
+ switch (OldOpcode) {
+ case Lanai::ADD_I_HI:
+ return Lanai::ADD_F_I_HI;
+ case Lanai::ADD_I_LO:
+ return Lanai::ADD_F_I_LO;
+ case Lanai::ADD_R:
+ return Lanai::ADD_F_R;
+ case Lanai::ADDC_I_HI:
+ return Lanai::ADDC_F_I_HI;
+ case Lanai::ADDC_I_LO:
+ return Lanai::ADDC_F_I_LO;
+ case Lanai::ADDC_R:
+ return Lanai::ADDC_F_R;
+ case Lanai::AND_I_HI:
+ return Lanai::AND_F_I_HI;
+ case Lanai::AND_I_LO:
+ return Lanai::AND_F_I_LO;
+ case Lanai::AND_R:
+ return Lanai::AND_F_R;
+ case Lanai::OR_I_HI:
+ return Lanai::OR_F_I_HI;
+ case Lanai::OR_I_LO:
+ return Lanai::OR_F_I_LO;
+ case Lanai::OR_R:
+ return Lanai::OR_F_R;
+ case Lanai::SL_I:
+ return Lanai::SL_F_I;
+ case Lanai::SRL_R:
+ return Lanai::SRL_F_R;
+ case Lanai::SA_I:
+ return Lanai::SA_F_I;
+ case Lanai::SRA_R:
+ return Lanai::SRA_F_R;
+ case Lanai::SUB_I_HI:
+ return Lanai::SUB_F_I_HI;
+ case Lanai::SUB_I_LO:
+ return Lanai::SUB_F_I_LO;
+ case Lanai::SUB_R:
+ return Lanai::SUB_F_R;
+ case Lanai::SUBB_I_HI:
+ return Lanai::SUBB_F_I_HI;
+ case Lanai::SUBB_I_LO:
+ return Lanai::SUBB_F_I_LO;
+ case Lanai::SUBB_R:
+ return Lanai::SUBB_F_R;
+ case Lanai::XOR_I_HI:
+ return Lanai::XOR_F_I_HI;
+ case Lanai::XOR_I_LO:
+ return Lanai::XOR_F_I_LO;
+ case Lanai::XOR_R:
+ return Lanai::XOR_F_R;
+ default:
+ return Lanai::NOP;
+ }
+}
+
+bool LanaiInstrInfo::optimizeCompareInstr(
+ MachineInstr &CmpInstr, unsigned SrcReg, unsigned SrcReg2, int CmpMask,
+ int CmpValue, const MachineRegisterInfo *MRI) const {
+ // Get the unique definition of SrcReg.
+ MachineInstr *MI = MRI->getUniqueVRegDef(SrcReg);
+ if (!MI)
+ return false;
+
+ // Get ready to iterate backward from CmpInstr.
+ MachineBasicBlock::iterator I = CmpInstr, E = MI,
+ B = CmpInstr.getParent()->begin();
+
+ // Early exit if CmpInstr is at the beginning of the BB.
+ if (I == B)
+ return false;
+
+ // There are two possible candidates which can be changed to set SR:
+ // One is MI, the other is a SUB instruction.
+ // * For SFSUB_F_RR(r1,r2), we are looking for SUB(r1,r2) or SUB(r2,r1).
+ // * For SFSUB_F_RI(r1, CmpValue), we are looking for SUB(r1, CmpValue).
+ MachineInstr *Sub = nullptr;
+ if (SrcReg2 != 0)
+ // MI is not a candidate to transform into a flag setting instruction.
+ MI = nullptr;
+ else if (MI->getParent() != CmpInstr.getParent() || CmpValue != 0) {
+ // Conservatively refuse to convert an instruction which isn't in the same
+ // BB as the comparison. Don't return if SFSUB_F_RI and CmpValue != 0 as Sub
+ // may still be a candidate.
+ if (CmpInstr.getOpcode() == Lanai::SFSUB_F_RI_LO)
+ MI = nullptr;
+ else
+ return false;
+ }
+
+ // Check that SR isn't set between the comparison instruction and the
+ // instruction we want to change while searching for Sub.
+ const TargetRegisterInfo *TRI = &getRegisterInfo();
+ for (--I; I != E; --I) {
+ const MachineInstr &Instr = *I;
+
+ if (Instr.modifiesRegister(Lanai::SR, TRI) ||
+ Instr.readsRegister(Lanai::SR, TRI))
+ // This instruction modifies or uses SR after the one we want to change.
+ // We can't do this transformation.
+ return false;
+
+ // Check whether CmpInstr can be made redundant by the current instruction.
+ if (isRedundantFlagInstr(&CmpInstr, SrcReg, SrcReg2, CmpValue, &*I)) {
+ Sub = &*I;
+ break;
+ }
+
+ // Don't search outside the containing basic block.
+ if (I == B)
+ return false;
+ }
+
+ // Return false if no candidates exist.
+ if (!MI && !Sub)
+ return false;
+
+ // The single candidate is called MI.
+ if (!MI)
+ MI = Sub;
+
+ if (flagSettingOpcodeVariant(MI->getOpcode()) != Lanai::NOP) {
+ bool isSafe = false;
+
+ SmallVector<std::pair<MachineOperand *, LPCC::CondCode>, 4>
+ OperandsToUpdate;
+ I = CmpInstr;
+ E = CmpInstr.getParent()->end();
+ while (!isSafe && ++I != E) {
+ const MachineInstr &Instr = *I;
+ for (unsigned IO = 0, EO = Instr.getNumOperands(); !isSafe && IO != EO;
+ ++IO) {
+ const MachineOperand &MO = Instr.getOperand(IO);
+ if (MO.isRegMask() && MO.clobbersPhysReg(Lanai::SR)) {
+ isSafe = true;
+ break;
+ }
+ if (!MO.isReg() || MO.getReg() != Lanai::SR)
+ continue;
+ if (MO.isDef()) {
+ isSafe = true;
+ break;
+ }
+ // Condition code is after the operand before SR.
+ LPCC::CondCode CC;
+ CC = (LPCC::CondCode)Instr.getOperand(IO - 1).getImm();
+
+ if (Sub) {
+ LPCC::CondCode NewCC = getOppositeCondition(CC);
+ if (NewCC == LPCC::ICC_T)
+ return false;
+ // If we have SUB(r1, r2) and CMP(r2, r1), the condition code based on
+ // CMP needs to be updated to be based on SUB. Push the condition
+ // code operands to OperandsToUpdate. If it is safe to remove
+ // CmpInstr, the condition code of these operands will be modified.
+ if (SrcReg2 != 0 && Sub->getOperand(1).getReg() == SrcReg2 &&
+ Sub->getOperand(2).getReg() == SrcReg) {
+ OperandsToUpdate.push_back(
+ std::make_pair(&((*I).getOperand(IO - 1)), NewCC));
+ }
+ } else {
+ // No Sub, so this is x = <op> y, z; cmp x, 0.
+ switch (CC) {
+ case LPCC::ICC_EQ: // Z
+ case LPCC::ICC_NE: // Z
+ case LPCC::ICC_MI: // N
+ case LPCC::ICC_PL: // N
+ case LPCC::ICC_F: // none
+ case LPCC::ICC_T: // none
+ // SR can be used multiple times, we should continue.
+ break;
+ case LPCC::ICC_CS: // C
+ case LPCC::ICC_CC: // C
+ case LPCC::ICC_VS: // V
+ case LPCC::ICC_VC: // V
+ case LPCC::ICC_HI: // C Z
+ case LPCC::ICC_LS: // C Z
+ case LPCC::ICC_GE: // N V
+ case LPCC::ICC_LT: // N V
+ case LPCC::ICC_GT: // Z N V
+ case LPCC::ICC_LE: // Z N V
+ // The instruction uses the V bit or C bit which is not safe.
+ return false;
+ case LPCC::UNKNOWN:
+ return false;
+ }
+ }
+ }
+ }
+
+ // If SR is not killed nor re-defined, we should check whether it is
+ // live-out. If it is live-out, do not optimize.
+ if (!isSafe) {
+ MachineBasicBlock *MBB = CmpInstr.getParent();
+ for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(),
+ SE = MBB->succ_end();
+ SI != SE; ++SI)
+ if ((*SI)->isLiveIn(Lanai::SR))
+ return false;
+ }
+
+ // Toggle the optional operand to SR.
+ MI->setDesc(get(flagSettingOpcodeVariant(MI->getOpcode())));
+ MI->addRegisterDefined(Lanai::SR);
+ CmpInstr.eraseFromParent();
+ return true;
+ }
+
+ return false;
+}
+
+bool LanaiInstrInfo::analyzeSelect(const MachineInstr &MI,
+ SmallVectorImpl<MachineOperand> &Cond,
+ unsigned &TrueOp, unsigned &FalseOp,
+ bool &Optimizable) const {
+ assert(MI.getOpcode() == Lanai::SELECT && "unknown select instruction");
+ // Select operands:
+ // 0: Def.
+ // 1: True use.
+ // 2: False use.
+ // 3: Condition code.
+ TrueOp = 1;
+ FalseOp = 2;
+ Cond.push_back(MI.getOperand(3));
+ Optimizable = true;
+ return false;
+}
+
+// Identify instructions that can be folded into a SELECT instruction, and
+// return the defining instruction.
+static MachineInstr *canFoldIntoSelect(unsigned Reg,
+ const MachineRegisterInfo &MRI,
+ const TargetInstrInfo *TII) {
+ if (!TargetRegisterInfo::isVirtualRegister(Reg))
+ return nullptr;
+ if (!MRI.hasOneNonDBGUse(Reg))
+ return nullptr;
+ MachineInstr *MI = MRI.getVRegDef(Reg);
+ if (!MI)
+ return nullptr;
+ // MI is folded into the SELECT by predicating it.
+ if (!MI->isPredicable())
+ return nullptr;
+ // Check if MI has any non-dead defs or physreg uses. This also detects
+ // predicated instructions which will be reading SR.
+ for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) {
+ const MachineOperand &MO = MI->getOperand(i);
+ // Reject frame index operands.
+ if (MO.isFI() || MO.isCPI() || MO.isJTI())
+ return nullptr;
+ if (!MO.isReg())
+ continue;
+ // MI can't have any tied operands, that would conflict with predication.
+ if (MO.isTied())
+ return nullptr;
+ if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
+ return nullptr;
+ if (MO.isDef() && !MO.isDead())
+ return nullptr;
+ }
+ bool DontMoveAcrossStores = true;
+ if (!MI->isSafeToMove(/*AliasAnalysis=*/nullptr, DontMoveAcrossStores))
+ return nullptr;
+ return MI;
+}
+
+MachineInstr *
+LanaiInstrInfo::optimizeSelect(MachineInstr &MI,
+ SmallPtrSetImpl<MachineInstr *> &SeenMIs,
+ bool PreferFalse) const {
+ assert(MI.getOpcode() == Lanai::SELECT && "unknown select instruction");
+ MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
+ MachineInstr *DefMI = canFoldIntoSelect(MI.getOperand(1).getReg(), MRI, this);
+ bool Invert = !DefMI;
+ if (!DefMI)
+ DefMI = canFoldIntoSelect(MI.getOperand(2).getReg(), MRI, this);
+ if (!DefMI)
+ return nullptr;
+
+ // Find new register class to use.
+ MachineOperand FalseReg = MI.getOperand(Invert ? 1 : 2);
+ unsigned DestReg = MI.getOperand(0).getReg();
+ const TargetRegisterClass *PreviousClass = MRI.getRegClass(FalseReg.getReg());
+ if (!MRI.constrainRegClass(DestReg, PreviousClass))
+ return nullptr;
+
+ // Create a new predicated version of DefMI.
+ MachineInstrBuilder NewMI =
+ BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), DefMI->getDesc(), DestReg);
+
+ // Copy all the DefMI operands, excluding its (null) predicate.
+ const MCInstrDesc &DefDesc = DefMI->getDesc();
+ for (unsigned i = 1, e = DefDesc.getNumOperands();
+ i != e && !DefDesc.OpInfo[i].isPredicate(); ++i)
+ NewMI.addOperand(DefMI->getOperand(i));
+
+ unsigned CondCode = MI.getOperand(3).getImm();
+ if (Invert)
+ NewMI.addImm(getOppositeCondition(LPCC::CondCode(CondCode)));
+ else
+ NewMI.addImm(CondCode);
+ NewMI.copyImplicitOps(MI);
+
+ // The output register value when the predicate is false is an implicit
+ // register operand tied to the first def. The tie makes the register
+ // allocator ensure the FalseReg is allocated the same register as operand 0.
+ FalseReg.setImplicit();
+ NewMI.addOperand(FalseReg);
+ NewMI->tieOperands(0, NewMI->getNumOperands() - 1);
+
+ // Update SeenMIs set: register newly created MI and erase removed DefMI.
+ SeenMIs.insert(NewMI);
+ SeenMIs.erase(DefMI);
+
+ // If MI is inside a loop, and DefMI is outside the loop, then kill flags on
+ // DefMI would be invalid when transferred inside the loop. Checking for a
+ // loop is expensive, but at least remove kill flags if they are in different
+ // BBs.
+ if (DefMI->getParent() != MI.getParent())
+ NewMI->clearKillInfo();
+
+ // The caller will erase MI, but not DefMI.
+ DefMI->eraseFromParent();
+ return NewMI;
+}
+
// The AnalyzeBranch function is used to examine conditional instructions and
// remove unnecessary instructions. This method is used by BranchFolder and
// IfConverter machine function passes to improve the CFG.
@@ -262,7 +653,7 @@ bool LanaiInstrInfo::ReverseBranchCondit
LPCC::CondCode BranchCond =
static_cast<LPCC::CondCode>(Condition[0].getImm());
- Condition[0].setImm(GetOppositeBranchCondition(BranchCond));
+ Condition[0].setImm(getOppositeCondition(BranchCond));
return false;
}
Modified: llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.h?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.h (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.h Thu Jul 7 18:36:04 2016
@@ -75,6 +75,12 @@ public:
int64_t &Offset, unsigned &Width,
const TargetRegisterInfo *TRI) const;
+ std::pair<unsigned, unsigned>
+ decomposeMachineOperandsTargetFlags(unsigned TF) const override;
+
+ ArrayRef<std::pair<unsigned, const char *>>
+ getSerializableDirectMachineOperandTargetFlags() const override;
+
bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TrueBlock,
MachineBasicBlock *&FalseBlock,
SmallVectorImpl<MachineOperand> &Condition,
@@ -82,6 +88,47 @@ public:
unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
+ // For a comparison instruction, return the source registers in SrcReg and
+ // SrcReg2 if having two register operands, and the value it compares against
+ // in CmpValue. Return true if the comparison instruction can be analyzed.
+ bool analyzeCompare(const MachineInstr &MI, unsigned &SrcReg,
+ unsigned &SrcReg2, int &CmpMask,
+ int &CmpValue) const override;
+
+ // See if the comparison instruction can be converted into something more
+ // efficient. E.g., on Lanai register-register instructions can set the flag
+ // register, obviating the need for a separate compare.
+ bool optimizeCompareInstr(MachineInstr &CmpInstr, unsigned SrcReg,
+ unsigned SrcReg2, int CmpMask, int CmpValue,
+ const MachineRegisterInfo *MRI) const override;
+
+ // Analyze the given select instruction, returning true if it cannot be
+ // understood. It is assumed that MI->isSelect() is true.
+ //
+ // When successful, return the controlling condition and the operands that
+ // determine the true and false result values.
+ //
+ // Result = SELECT Cond, TrueOp, FalseOp
+ //
+ // Lanai can optimize certain select instructions, for example by predicating
+ // the instruction defining one of the operands and sets Optimizable to true.
+ bool analyzeSelect(const MachineInstr &MI,
+ SmallVectorImpl<MachineOperand> &Cond, unsigned &TrueOp,
+ unsigned &FalseOp, bool &Optimizable) const override;
+
+ // Given a select instruction that was understood by analyzeSelect and
+ // returned Optimizable = true, attempt to optimize MI by merging it with one
+ // of its operands. Returns NULL on failure.
+ //
+ // When successful, returns the new select instruction. The client is
+ // responsible for deleting MI.
+ //
+ // If both sides of the select can be optimized, the TrueOp is modifed.
+ // PreferFalse is not used.
+ MachineInstr *optimizeSelect(MachineInstr &MI,
+ SmallPtrSetImpl<MachineInstr *> &SeenMIs,
+ bool PreferFalse) const override;
+
bool ReverseBranchCondition(
SmallVectorImpl<MachineOperand> &Condition) const override;
Modified: llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.td?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.td (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiInstrInfo.td Thu Jul 7 18:36:04 2016
@@ -235,6 +235,15 @@ def CCOp : Operand<i32> {
let PrintMethod = "printCCOperand";
}
+// Predicate operand. Default to 0 = true.
+def CondCodeOperand : AsmOperandClass { let Name = "CondCode"; }
+
+def pred : PredicateOperand<i32, (ops i32imm), (ops (i32 0))> {
+ let PrintMethod = "printPredicateOperand";
+ let ParserMatchClass = CondCodeOperand;
+ let DecoderMethod = "decodePredicateOperand";
+}
+
let hasSideEffects = 0, Inst = 0x00000001 in
def NOP : InstLanai<(outs), (ins), "nop", []>;
@@ -283,16 +292,10 @@ multiclass ALUarith<bits<3> subOp, strin
defm I_ : ALUbase<subOp, AsmStr, OpNode, LoExt, HiExt, [], []>;
// Register Register
- let JJJJJ = 0, DDDI = 0 in
- def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2),
- !strconcat(AsmStr, "\t$Rs1, $Rs2, $Rd"),
+ let JJJJJ = 0 in
+ def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2, pred:$DDDI),
+ !strconcat(AsmStr, "$DDDI\t$Rs1, $Rs2, $Rd"),
[(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>;
- // RR Conditional
- let JJJJJ = 0, Uses = [SR] in
- def R_CC : InstRR<subOp, (outs GPR:$Rd),
- (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI),
- !strconcat(AsmStr, ".$DDDI\t$Rs1, $Rs2, $Rd"),
- []>;
}
multiclass ALUlogic<bits<3> subOp, string AsmStr, SDNode OpNode,
@@ -302,16 +305,10 @@ multiclass ALUlogic<bits<3> subOp, strin
[(set GPR:$Rd, (OpNode GPR:$Rs1, HiExt:$imm16))]>;
// Register Register
- let JJJJJ = 0, DDDI = 0 in
- def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2),
- !strconcat(AsmStr, "\t$Rs1, $Rs2, $Rd"),
+ let JJJJJ = 0 in
+ def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2, pred:$DDDI),
+ !strconcat(AsmStr, "$DDDI\t$Rs1, $Rs2, $Rd"),
[(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>;
- // RR Conditional
- let JJJJJ = 0, Uses = [SR] in
- def R_CC : InstRR<subOp, (outs GPR:$Rd),
- (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI),
- !strconcat(AsmStr, ".$DDDI\t$Rs1, $Rs2, $Rd"),
- []>;
}
// Non flag setting ALU operations
@@ -407,7 +404,7 @@ def : Pat<(LanaiSubbF GPR:$Rs1, i32lo16z
def : Pat<(LanaiSubbF GPR:$Rs1, i32hi16:$imm),
(SUBB_F_I_HI GPR:$Rs1, i32hi16:$imm)>;
-def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0)>;
+def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0, 0)>;
let isAsCheapAsAMove = 1, Rs1 = R0.Num, isCodeGenOnly = 1, H = 1, F = 0,
isReMaterializable = 1 in
@@ -716,11 +713,15 @@ multiclass SF<bits<3> op2Val, string Asm
!strconcat(AsmStr, "\t$Rs1, $Rs2, %r0"),
[(LanaiSetFlag (i32 GPR:$Rs1), (i32 GPR:$Rs2))]>;
let F = 1, Rd = R0.Num, H = 0, Defs = [SR] in
- def _RI : InstRI<op2Val, (outs), (ins GPR:$Rs1, i32lo16z:$imm16),
+ def _RI_LO : InstRI<op2Val, (outs), (ins GPR:$Rs1, i32lo16z:$imm16),
!strconcat(AsmStr, "\t$Rs1, $imm16, %r0"),
[(LanaiSetFlag (i32 GPR:$Rs1), i32lo16z:$imm16)]>;
+ let F = 1, Rd = R0.Num, H = 1, Defs = [SR] in
+ def _RI_HI : InstRI<op2Val, (outs), (ins GPR:$Rs1, i32hi16:$imm16),
+ !strconcat(AsmStr, "\t$Rs1, $imm16, %r0"),
+ [(LanaiSetFlag (i32 GPR:$Rs1), i32hi16:$imm16)]>;
}
-let isCodeGenOnly = 1 in {
+let isCodeGenOnly = 1, isCompare = 1 in {
defm SFSUB_F : SF<0b010, "sub.f">;
}
Modified: llvm/trunk/lib/Target/Lanai/LanaiRegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiRegisterInfo.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiRegisterInfo.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiRegisterInfo.cpp Thu Jul 7 18:36:04 2016
@@ -197,11 +197,16 @@ void LanaiRegisterInfo::eliminateFrameIn
}
// Reg = FrameReg OP Reg
if (MI.getOpcode() == Lanai::ADD_I_LO) {
- if (HasNegOffset)
- MI.setDesc(TII->get(Lanai::SUB_R));
- else
- MI.setDesc(TII->get(Lanai::ADD_R));
- } else if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) {
+ BuildMI(*MI.getParent(), II, DL,
+ HasNegOffset ? TII->get(Lanai::SUB_R) : TII->get(Lanai::ADD_R),
+ MI.getOperand(0).getReg())
+ .addReg(FrameReg)
+ .addReg(Reg)
+ .addImm(LPCC::ICC_T);
+ MI.eraseFromParent();
+ return;
+ }
+ if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) {
MI.setDesc(TII->get(getRRMOpcodeVariant(MI.getOpcode())));
if (HasNegOffset) {
// Change the ALU op (operand 3) from LPAC::ADD (the default) to
Removed: llvm/trunk/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp?rev=274806&view=auto
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp (removed)
@@ -1,294 +0,0 @@
-//===-- LanaiSetflagAluCombiner.cpp - Pass to combine set flag & ALU ops --===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "Lanai.h"
-#include "LanaiTargetMachine.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/RegisterScavenging.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Target/TargetInstrInfo.h"
-
-using namespace llvm;
-
-#define DEBUG_TYPE "lanai-setflag-alu-combiner"
-
-STATISTIC(NumSetflagAluCombined,
- "Number of SET_FLAG and ALU instructions combined");
-
-static llvm::cl::opt<bool> DisableSetflagAluCombiner(
- "disable-lanai-setflag-alu-combiner", llvm::cl::init(false),
- llvm::cl::desc("Do not combine SET_FLAG and ALU operators"),
- llvm::cl::Hidden);
-
-namespace llvm {
-void initializeLanaiSetflagAluCombinerPass(PassRegistry &);
-} // namespace llvm
-
-namespace {
-typedef MachineBasicBlock::iterator MbbIterator;
-typedef MachineFunction::iterator MfIterator;
-
-class LanaiSetflagAluCombiner : public MachineFunctionPass {
-public:
- static char ID;
- LanaiSetflagAluCombiner() : MachineFunctionPass(ID) {
- initializeLanaiSetflagAluCombinerPass(*PassRegistry::getPassRegistry());
- }
-
- const char *getPassName() const override {
- return "Lanai SET_FLAG ALU combiner pass";
- }
-
- bool runOnMachineFunction(MachineFunction &F) override;
-
- MachineFunctionProperties getRequiredProperties() const override {
- return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::AllVRegsAllocated);
- }
-
-private:
- bool CombineSetflagAluInBasicBlock(MachineFunction *MF,
- MachineBasicBlock *BB);
-};
-} // namespace
-
-char LanaiSetflagAluCombiner::ID = 0;
-
-INITIALIZE_PASS(LanaiSetflagAluCombiner, DEBUG_TYPE,
- "Lanai SET_FLAG ALU combiner pass", false, false)
-
-namespace {
-
-const unsigned kInvalid = -1;
-
-static unsigned flagSettingOpcodeVariant(unsigned OldOpcode) {
- switch (OldOpcode) {
- case Lanai::ADD_I_HI:
- return Lanai::ADD_F_I_HI;
- case Lanai::ADD_I_LO:
- return Lanai::ADD_F_I_LO;
- case Lanai::ADD_R:
- return Lanai::ADD_F_R;
- case Lanai::ADD_R_CC:
- return Lanai::ADD_F_R_CC;
- case Lanai::ADDC_I_HI:
- return Lanai::ADDC_F_I_HI;
- case Lanai::ADDC_I_LO:
- return Lanai::ADDC_F_I_LO;
- case Lanai::ADDC_R:
- return Lanai::ADDC_F_R;
- case Lanai::ADDC_R_CC:
- return Lanai::ADDC_F_R_CC;
- case Lanai::AND_I_HI:
- return Lanai::AND_F_I_HI;
- case Lanai::AND_I_LO:
- return Lanai::AND_F_I_LO;
- case Lanai::AND_R:
- return Lanai::AND_F_R;
- case Lanai::AND_R_CC:
- return Lanai::AND_F_R_CC;
- case Lanai::OR_I_HI:
- return Lanai::OR_F_I_HI;
- case Lanai::OR_I_LO:
- return Lanai::OR_F_I_LO;
- case Lanai::OR_R:
- return Lanai::OR_F_R;
- case Lanai::OR_R_CC:
- return Lanai::OR_F_R_CC;
- case Lanai::SL_I:
- return Lanai::SL_F_I;
- case Lanai::SRL_R:
- return Lanai::SRL_F_R;
- case Lanai::SA_I:
- return Lanai::SA_F_I;
- case Lanai::SRA_R:
- return Lanai::SRA_F_R;
- case Lanai::SUB_I_HI:
- return Lanai::SUB_F_I_HI;
- case Lanai::SUB_I_LO:
- return Lanai::SUB_F_I_LO;
- case Lanai::SUB_R:
- return Lanai::SUB_F_R;
- case Lanai::SUB_R_CC:
- return Lanai::SUB_F_R_CC;
- case Lanai::SUBB_I_HI:
- return Lanai::SUBB_F_I_HI;
- case Lanai::SUBB_I_LO:
- return Lanai::SUBB_F_I_LO;
- case Lanai::SUBB_R:
- return Lanai::SUBB_F_R;
- case Lanai::SUBB_R_CC:
- return Lanai::SUBB_F_R_CC;
- case Lanai::XOR_I_HI:
- return Lanai::XOR_F_I_HI;
- case Lanai::XOR_I_LO:
- return Lanai::XOR_F_I_LO;
- case Lanai::XOR_R:
- return Lanai::XOR_F_R;
- case Lanai::XOR_R_CC:
- return Lanai::XOR_F_R_CC;
- default:
- return kInvalid;
- }
-}
-
-// Returns whether opcode corresponds to instruction that sets flags.
-static bool isFlagSettingInstruction(MbbIterator Instruction) {
- return Instruction->killsRegister(Lanai::SR);
-}
-
-// Return the Conditional Code operand for a given instruction kind. For
-// example, operand at index 1 of a BRIND_CC instruction is the conditional code
-// (eq, ne, etc.). Returns -1 if the instruction does not have a conditional
-// code.
-static int getCCOperandPosition(unsigned Opcode) {
- switch (Opcode) {
- case Lanai::BRIND_CC:
- case Lanai::BRIND_CCA:
- case Lanai::BRR:
- case Lanai::BRCC:
- case Lanai::SCC:
- return 1;
- case Lanai::SELECT:
- case Lanai::ADDC_F_R_CC:
- case Lanai::ADDC_R_CC:
- case Lanai::ADD_F_R_CC:
- case Lanai::ADD_R_CC:
- case Lanai::AND_F_R_CC:
- case Lanai::AND_R_CC:
- case Lanai::OR_F_R_CC:
- case Lanai::OR_R_CC:
- case Lanai::SUBB_F_R_CC:
- case Lanai::SUBB_R_CC:
- case Lanai::SUB_F_R_CC:
- case Lanai::SUB_R_CC:
- case Lanai::XOR_F_R_CC:
- case Lanai::XOR_R_CC:
- return 3;
- default:
- return -1;
- }
-}
-
-// Returns true if instruction is a lowered SET_FLAG instruction with 0/R0 as
-// the first operand and whose conditional code is such that it can be merged
-// (i.e., EQ, NE, PL and MI).
-static bool isSuitableSetflag(MbbIterator Instruction, MbbIterator End) {
- unsigned Opcode = Instruction->getOpcode();
- if (Opcode == Lanai::SFSUB_F_RI || Opcode == Lanai::SFSUB_F_RR) {
- const MachineOperand &Operand = Instruction->getOperand(1);
- if (Operand.isReg() && Operand.getReg() != Lanai::R0)
- return false;
- if (Operand.isImm() && Operand.getImm() != 0)
- return false;
-
- MbbIterator SCCUserIter = Instruction;
- while (SCCUserIter != End) {
- ++SCCUserIter;
- if (SCCUserIter == End)
- break;
- // Skip debug instructions. Debug instructions don't affect codegen.
- if (SCCUserIter->isDebugValue())
- continue;
- // Early exit when encountering flag setting or return instruction.
- if (isFlagSettingInstruction(SCCUserIter))
- // Only return true if flags are set post the flag setting instruction
- // tested or a return is executed.
- return true;
- int CCIndex = getCCOperandPosition(SCCUserIter->getOpcode());
- if (CCIndex != -1) {
- LPCC::CondCode CC = static_cast<LPCC::CondCode>(
- SCCUserIter->getOperand(CCIndex).getImm());
- // Return false if the flag is used outside of a EQ, NE, PL and MI.
- if (CC != LPCC::ICC_EQ && CC != LPCC::ICC_NE && CC != LPCC::ICC_PL &&
- CC != LPCC::ICC_MI)
- return false;
- }
- }
- }
-
- return false;
-}
-
-// Combines a SET_FLAG instruction comparing a register with 0 and an ALU
-// operation that sets the same register used in the comparison into a single
-// flag setting ALU instruction (both instructions combined are removed and new
-// flag setting ALU operation inserted where ALU instruction was).
-bool LanaiSetflagAluCombiner::CombineSetflagAluInBasicBlock(
- MachineFunction *MF, MachineBasicBlock *BB) {
- bool Modified = false;
- const TargetInstrInfo *TII =
- MF->getSubtarget<LanaiSubtarget>().getInstrInfo();
-
- MbbIterator SetflagIter = BB->begin();
- MbbIterator End = BB->end();
- MbbIterator Begin = BB->begin();
- while (SetflagIter != End) {
- bool Replaced = false;
- if (isSuitableSetflag(SetflagIter, End)) {
- MbbIterator AluIter = SetflagIter;
- while (AluIter != Begin) {
- --AluIter;
- // Skip debug instructions. Debug instructions don't affect codegen.
- if (AluIter->isDebugValue())
- continue;
- // Early exit when encountering flag setting instruction.
- if (isFlagSettingInstruction(AluIter))
- break;
- // Check that output of AluIter is equal to input of SetflagIter.
- if (AluIter->getNumOperands() > 1 && AluIter->getOperand(0).isReg() &&
- (AluIter->getOperand(0).getReg() ==
- SetflagIter->getOperand(0).getReg())) {
- unsigned NewOpc = flagSettingOpcodeVariant(AluIter->getOpcode());
- if (NewOpc == kInvalid)
- break;
-
- // Change the ALU instruction to the flag setting variant.
- AluIter->setDesc(TII->get(NewOpc));
- AluIter->addImplicitDefUseOperands(*MF);
-
- Replaced = true;
- ++NumSetflagAluCombined;
- break;
- }
- }
- // Erase the setflag instruction if merged.
- if (Replaced)
- BB->erase(SetflagIter++);
- }
-
- Modified |= Replaced;
- if (!Replaced)
- ++SetflagIter;
- }
-
- return Modified;
-}
-
-// Driver function that iterates over the machine basic building blocks of a
-// machine function
-bool LanaiSetflagAluCombiner::runOnMachineFunction(MachineFunction &MF) {
- if (DisableSetflagAluCombiner)
- return false;
-
- bool Modified = false;
- MfIterator End = MF.end();
- for (MfIterator MFI = MF.begin(); MFI != End; ++MFI) {
- Modified |= CombineSetflagAluInBasicBlock(&MF, &*MFI);
- }
- return Modified;
-}
-} // namespace
-
-FunctionPass *llvm::createLanaiSetflagAluCombinerPass() {
- return new LanaiSetflagAluCombiner();
-}
Modified: llvm/trunk/lib/Target/Lanai/LanaiTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/LanaiTargetMachine.cpp?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/LanaiTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/Lanai/LanaiTargetMachine.cpp Thu Jul 7 18:36:04 2016
@@ -28,7 +28,6 @@ using namespace llvm;
namespace llvm {
void initializeLanaiMemAluCombinerPass(PassRegistry &);
-void initializeLanaiSetflagAluCombinerPass(PassRegistry &);
} // namespace llvm
extern "C" void LLVMInitializeLanaiTarget() {
@@ -112,5 +111,4 @@ void LanaiPassConfig::addPreEmitPass() {
// scheduling pass.
void LanaiPassConfig::addPreSched2() {
addPass(createLanaiMemAluCombinerPass());
- addPass(createLanaiSetflagAluCombinerPass());
}
Modified: llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h (original)
+++ llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiBaseInfo.h Thu Jul 7 18:36:04 2016
@@ -24,7 +24,6 @@ namespace llvm {
// LanaiII - This namespace holds all of the target specific flags that
// instruction info tracks.
-//
namespace LanaiII {
// Target Operand Flag enum.
enum TOF {
@@ -36,31 +35,6 @@ enum TOF {
// address.
MO_ABS_HI,
MO_ABS_LO,
-
- // MO_PIC_BASE_OFFSET - On a symbol operand this indicates that the
- // immediate should get the value of the symbol minus the PIC base label:
- // SYMBOL_LABEL - PICBASELABEL
- MO_PIC_BASE_OFFSET,
-
- // MO_GOT - On a symbol operand this indicates that the immediate is the
- // offset to the GOT entry for the symbol name from the base of the GOT.
- MO_GOT,
-
- // MO_GOTOFFHI/MO_GOTOFFLO - On a symbol operand this indicates that the
- // immediate is the offset to the location of the symbol name from the
- // base of the GOT.
- MO_GOTOFFHI,
- MO_GOTOFFLO,
-
- // MO_GOTPCHI/MO_GOTPCLO - On a symbol operand this indicates that
- // the immediate is an offset to the GOT entry for the symbol name
- // from the current code location.
- MO_GOTPCHI,
- MO_GOTPCLO,
-
- // MO_PLT - On a symbol operand this indicates that the immediate is
- // offset to the PLT entry of symbol name from the current code location.
- MO_PLT
};
} // namespace LanaiII
Removed: llvm/trunk/test/CodeGen/Lanai/combined_alu_setcc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Lanai/combined_alu_setcc.ll?rev=274806&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Lanai/combined_alu_setcc.ll (original)
+++ llvm/trunk/test/CodeGen/Lanai/combined_alu_setcc.ll (removed)
@@ -1,170 +0,0 @@
-; RUN: llc < %s -march=lanai | FileCheck %s
-
-; Test the alu setcc combiner.
-
-; TODO: Enhance combiner to handle this case. This expands into:
-; sub %r7, %r6, %r3
-; sub.f %r7, %r6, %r0
-; sel.eq %r18, %r3, %rv
-; This is different from the pattern currently matched. If the lowered form had
-; been sub.f %r3, 0, %r0 then it would have matched.
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test0a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
- %sub = sub i32 %b, %a
- %cmp = icmp eq i32 %sub, 0
- %cond = select i1 %cmp, i32 %c, i32 %sub
- ret i32 %cond
-}
-; CHECK-LABEL: test0a
-; CHECK: sub.f %r7
-; CHECK: sel.eq
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test0b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
- %cmp = icmp eq i32 %b, %a
- %cond = select i1 %cmp, i32 %c, i32 %b
- ret i32 %cond
-}
-; CHECK-LABEL: test0b
-; CHECK: sub.f %r7, %r6, %r0
-; CHECK-NEXT: sel.eq
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test1a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
- %sub = sub i32 %b, %a
- %cmp = icmp slt i32 %sub, 0
- %cond = select i1 %cmp, i32 %c, i32 %d
- ret i32 %cond
-}
-; CHECK-LABEL: test1a
-; CHECK: sub.f %r7, %r6
-; CHECK-NEXT: sel.mi
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test1b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
- %sub = sub i32 %b, %a
- %cmp = icmp slt i32 %sub, 0
- %cond = select i1 %cmp, i32 %c, i32 %d
- ret i32 %cond
-}
-; CHECK-LABEL: test1b
-; CHECK: sub.f %r7, %r6
-; CHECK-NEXT: sel.mi
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test2a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
- %sub = sub i32 %b, %a
- %cmp = icmp sgt i32 %sub, -1
- %cond = select i1 %cmp, i32 %c, i32 %d
- ret i32 %cond
-}
-; CHECK-LABEL: test2a
-; CHECK: sub.f %r7, %r6
-; CHECK: sel.pl
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test2b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
- %sub = sub i32 %b, %a
- %cmp = icmp sgt i32 %sub, -1
- %cond = select i1 %cmp, i32 %c, i32 %d
- ret i32 %cond
-}
-; CHECK-LABEL: test2b
-; CHECK: sub.f %r7, %r6
-; CHECK: sel.pl
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test3(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
- %sub = sub i32 %b, %a
- %cmp = icmp slt i32 %sub, 1
- %cond = select i1 %cmp, i32 %c, i32 %d
- ret i32 %cond
-}
-
-; Function Attrs: norecurse nounwind readnone
-define i32 @test4(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) #0 {
-entry:
- %cmp = icmp ne i32 %a, 0
- %cmp1 = icmp ult i32 %a, %b
- %or.cond = and i1 %cmp, %cmp1
- br i1 %or.cond, label %return, label %if.end
-
-if.end: ; preds = %entry
- %cmp2 = icmp ne i32 %b, 0
- %cmp4 = icmp ult i32 %b, %c
- %or.cond29 = and i1 %cmp2, %cmp4
- br i1 %or.cond29, label %return, label %if.end6
-
-if.end6: ; preds = %if.end
- %cmp7 = icmp ne i32 %c, 0
- %cmp9 = icmp ult i32 %c, %d
- %or.cond30 = and i1 %cmp7, %cmp9
- br i1 %or.cond30, label %return, label %if.end11
-
-if.end11: ; preds = %if.end6
- %cmp12 = icmp ne i32 %d, 0
- %cmp14 = icmp ult i32 %d, %a
- %or.cond31 = and i1 %cmp12, %cmp14
- %b. = select i1 %or.cond31, i32 %b, i32 21
- ret i32 %b.
-
-return: ; preds = %if.end6, %if.end, %entry
- %retval.0 = phi i32 [ %c, %entry ], [ %d, %if.end ], [ %a, %if.end6 ]
- ret i32 %retval.0
-}
-; CHECK-LABEL: test4
-; TODO: Re-enable test. This test is disabled post making the combiner more
-; conservative.
-; DISABLED_CHECK: and.f
-
-; Test to avoid incorrect fusing that spans across basic blocks
- at a = global i32 -1, align 4
- at b = global i32 0, align 4
-
-; Function Attrs: nounwind
-define void @testBB() {
-entry:
- %0 = load i32, i32* @a, align 4, !tbaa !1
- %1 = load i32, i32* @b, align 4, !tbaa !1
- %sub.i = sub i32 %1, %0
- %tobool = icmp sgt i32 %sub.i, -1
- br i1 %tobool, label %if.end, label %if.then
-
-if.then: ; preds = %entry
- %call1 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
- br label %while.body
-
-while.body: ; preds = %if.then, %while.body
- br label %while.body
-
-if.end: ; preds = %entry
- %cmp.i = icmp slt i32 %sub.i, 1
- br i1 %cmp.i, label %if.then4, label %if.end7
-
-if.then4: ; preds = %if.end
- %call5 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
- br label %while.body6
-
-while.body6: ; preds = %if.then4, %while.body6
- br label %while.body6
-
-if.end7: ; preds = %if.end
- ret void
-}
-
-declare i32 @g(...)
-; CHECK-LABEL: testBB
-; CHECK: sub.f {{.*}}, %r0
-
-!1 = !{!2, !2, i64 0}
-!2 = !{!"int", !3, i64 0}
-!3 = !{!"omnipotent char", !4, i64 0}
-!4 = !{!"Simple C/C++ TBAA"}
Added: llvm/trunk/test/CodeGen/Lanai/sub-cmp-peephole.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Lanai/sub-cmp-peephole.ll?rev=274807&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Lanai/sub-cmp-peephole.ll (added)
+++ llvm/trunk/test/CodeGen/Lanai/sub-cmp-peephole.ll Thu Jul 7 18:36:04 2016
@@ -0,0 +1,109 @@
+; RUN: llc < %s -mtriple=lanai | FileCheck %s
+
+define i32 @f(i32 inreg %a, i32 inreg %b) nounwind ssp {
+entry:
+; CHECK-LABEL: f:
+; CHECK: sub.f %r6, %r7, [[IN:%.*]]
+; CHECK: sel.gt [[IN]], %r0, %rv
+ %cmp = icmp sgt i32 %a, %b
+ %sub = sub nsw i32 %a, %b
+ %sub. = select i1 %cmp, i32 %sub, i32 0
+ ret i32 %sub.
+}
+
+define i32 @g(i32 inreg %a, i32 inreg %b) nounwind ssp {
+entry:
+; CHECK-LABEL: g:
+; CHECK: sub.f %r7, %r6, [[IN:%.*]]
+; CHECK: sel.lt [[IN]], %r0, %rv
+ %cmp = icmp slt i32 %a, %b
+ %sub = sub nsw i32 %b, %a
+ %sub. = select i1 %cmp, i32 %sub, i32 0
+ ret i32 %sub.
+}
+
+define i32 @h(i32 inreg %a, i32 inreg %b) nounwind ssp {
+entry:
+; CHECK-LABEL: h:
+; CHECK: sub.f %r6, 0x3, [[IN:%.*]]
+; CHECK: sel.gt [[IN]], %r7, %rv
+ %cmp = icmp sgt i32 %a, 3
+ %sub = sub nsw i32 %a, 3
+ %sub. = select i1 %cmp, i32 %sub, i32 %b
+ ret i32 %sub.
+}
+
+define i32 @i(i32 inreg %a, i32 inreg %b) nounwind readnone ssp {
+entry:
+; CHECK-LABEL: i:
+; CHECK: sub.f %r7, %r6, [[IN:%.*]]
+; CHECK: sel.ult [[IN]], %r0, %rv
+ %cmp = icmp ult i32 %a, %b
+ %sub = sub i32 %b, %a
+ %sub. = select i1 %cmp, i32 %sub, i32 0
+ ret i32 %sub.
+}
+; If SR is live-out, we can't remove cmp if there exists a swapped sub.
+define i32 @j(i32 inreg %a, i32 inreg %b) nounwind {
+entry:
+; CHECK-LABEL: j:
+; CHECK: sub.f %r7, %r6, %r0
+; CHECK: sub %r6, %r7, %rv
+ %cmp = icmp eq i32 %b, %a
+ %sub = sub nsw i32 %a, %b
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %cmp2 = icmp sgt i32 %b, %a
+ %sel = select i1 %cmp2, i32 %sub, i32 %a
+ ret i32 %sel
+
+if.else:
+ ret i32 %sub
+}
+
+declare void @abort()
+declare void @exit(i32)
+ at t = common global i32 0
+
+; If the comparison uses the C bit (signed overflow/underflow), we can't
+; omit the comparison.
+define i32 @cmp_ult0(i32 inreg %a, i32 inreg %b, i32 inreg %x, i32 inreg %y) {
+entry:
+; CHECK-LABEL: cmp_ult0
+; CHECK: sub {{.*}}, 0x11, [[IN:%.*]]
+; CHECK: sub.f [[IN]], 0x0, %r0
+ %load = load i32, i32* @t, align 4
+ %sub = sub i32 %load, 17
+ %cmp = icmp ult i32 %sub, 0
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ call void @abort()
+ unreachable
+
+if.else:
+ call void @exit(i32 0)
+ unreachable
+}
+
+; Same for the V bit.
+; TODO: add test that exercises V bit individually (VC/VS).
+define i32 @cmp_gt0(i32 inreg %a, i32 inreg %b, i32 inreg %x, i32 inreg %y) {
+entry:
+; CHECK-LABEL: cmp_gt0
+; CHECK: sub {{.*}}, 0x11, [[IN:%.*]]
+; CHECK: sub.f [[IN]], 0x1, %r0
+ %load = load i32, i32* @t, align 4
+ %sub = sub i32 %load, 17
+ %cmp = icmp sgt i32 %sub, 0
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ call void @abort()
+ unreachable
+
+if.else:
+ call void @exit(i32 0)
+ unreachable
+}
Added: llvm/trunk/test/CodeGen/MIR/Lanai/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/MIR/Lanai/lit.local.cfg?rev=274807&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/MIR/Lanai/lit.local.cfg (added)
+++ llvm/trunk/test/CodeGen/MIR/Lanai/lit.local.cfg Thu Jul 7 18:36:04 2016
@@ -0,0 +1,2 @@
+if not 'Lanai' in config.root.targets:
+ config.unsupported = True
Added: llvm/trunk/test/CodeGen/MIR/Lanai/peephole-compare.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/MIR/Lanai/peephole-compare.mir?rev=274807&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/MIR/Lanai/peephole-compare.mir (added)
+++ llvm/trunk/test/CodeGen/MIR/Lanai/peephole-compare.mir Thu Jul 7 18:36:04 2016
@@ -0,0 +1,714 @@
+# RUN: llc -run-pass=peephole-opts %s -o /dev/null 2>&1 | FileCheck %s
+
+# Test the compare fold peephole.
+
+# CHECK-LABEL: name: test0a
+# TODO: Enhance combiner to handle this case. This expands into:
+# sub %r7, %r6, %r3
+# sub.f %r7, %r6, %r0
+# sel.eq %r18, %r3, %rv
+# This is different from the pattern currently matched. If the lowered form had
+# been sub.f %r3, 0, %r0 then it would have matched.
+
+# CHECK-LABEL: name: test1a
+# CHECK: [[IN1:%.*]] = COPY %r7
+# CHECK: [[IN2:%.*]] = COPY %r6
+# CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
+
+# CHECK-LABEL: name: test1b
+# CHECK: [[IN1:%.*]] = COPY %r7
+# CHECK: [[IN2:%.*]] = COPY %r6
+# CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
+
+# CHECK-LABEL: name: test2a
+# CHECK: [[IN1:%.*]] = COPY %r7
+# CHECK: [[IN2:%.*]] = COPY %r6
+# CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
+
+# CHECK-LABEL: name: test2b
+# CHECK: [[IN1:%.*]] = COPY %r7
+# CHECK: [[IN2:%.*]] = COPY %r6
+# CHECK: SUB_F_R [[IN1]], [[IN2]], 0, implicit-def %sr
+
+# CHECK-LABEL: name: test3
+# CHECK: AND_F_R
+# CHECK: AND_F_R
+# CHECK: AND_F_R
+
+--- |
+ target datalayout = "E-m:e-p:32:32-i64:64-a:0:32-n32-S64"
+ target triple = "lanai-unknown-unknown"
+
+ @a = global i32 -1, align 4
+ @b = global i32 0, align 4
+
+ define i32 @test0a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+ entry:
+ %sub = sub i32 %b, %a
+ %cmp = icmp eq i32 %sub, 0
+ %cond = select i1 %cmp, i32 %c, i32 %sub
+ ret i32 %cond
+ }
+
+ define i32 @test0b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+ entry:
+ %cmp = icmp eq i32 %b, %a
+ %cond = select i1 %cmp, i32 %c, i32 %b
+ ret i32 %cond
+ }
+
+ define i32 @test1a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+ entry:
+ %sub = sub i32 %b, %a
+ %cmp = icmp slt i32 %sub, 0
+ %cond = select i1 %cmp, i32 %c, i32 %d
+ ret i32 %cond
+ }
+
+ define i32 @test1b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+ entry:
+ %sub = sub i32 %b, %a
+ %cmp = icmp slt i32 %sub, 0
+ %cond = select i1 %cmp, i32 %c, i32 %d
+ ret i32 %cond
+ }
+
+ define i32 @test2a(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+ entry:
+ %sub = sub i32 %b, %a
+ %cmp = icmp sgt i32 %sub, -1
+ %cond = select i1 %cmp, i32 %c, i32 %d
+ ret i32 %cond
+ }
+
+ define i32 @test2b(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+ entry:
+ %sub = sub i32 %b, %a
+ %cmp = icmp sgt i32 %sub, -1
+ %cond = select i1 %cmp, i32 %c, i32 %d
+ ret i32 %cond
+ }
+
+ define i32 @test3(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+ entry:
+ %sub = sub i32 %b, %a
+ %cmp = icmp slt i32 %sub, 1
+ %cond = select i1 %cmp, i32 %c, i32 %d
+ ret i32 %cond
+ }
+
+ define i32 @test4(i32 inreg %a, i32 inreg %b, i32 inreg %c, i32 inreg %d) {
+ entry:
+ %cmp = icmp ne i32 %a, 0
+ %cmp1 = icmp ult i32 %a, %b
+ %or.cond = and i1 %cmp, %cmp1
+ br i1 %or.cond, label %return, label %if.end
+
+ if.end: ; preds = %entry
+ %cmp2 = icmp ne i32 %b, 0
+ %cmp4 = icmp ult i32 %b, %c
+ %or.cond29 = and i1 %cmp2, %cmp4
+ br i1 %or.cond29, label %return, label %if.end6
+
+ if.end6: ; preds = %if.end
+ %cmp7 = icmp ne i32 %c, 0
+ %cmp9 = icmp ult i32 %c, %d
+ %or.cond30 = and i1 %cmp7, %cmp9
+ br i1 %or.cond30, label %return, label %if.end11
+
+ if.end11: ; preds = %if.end6
+ %cmp12 = icmp ne i32 %d, 0
+ %cmp14 = icmp ult i32 %d, %a
+ %or.cond31 = and i1 %cmp12, %cmp14
+ %b. = select i1 %or.cond31, i32 %b, i32 21
+ ret i32 %b.
+
+ return: ; preds = %if.end6, %if.end, %entry
+ %retval.0 = phi i32 [ %c, %entry ], [ %d, %if.end ], [ %a, %if.end6 ]
+ ret i32 %retval.0
+ }
+
+ define void @testBB() {
+ entry:
+ %0 = load i32, i32* @a, align 4, !tbaa !0
+ %1 = load i32, i32* @b, align 4, !tbaa !0
+ %sub.i = sub i32 %1, %0
+ %tobool = icmp sgt i32 %sub.i, -1
+ br i1 %tobool, label %if.end, label %if.then
+
+ if.then: ; preds = %entry
+ %call1 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
+ br label %while.body
+
+ while.body: ; preds = %while.body, %if.then
+ br label %while.body
+
+ if.end: ; preds = %entry
+ %cmp.i = icmp slt i32 %sub.i, 1
+ br i1 %cmp.i, label %if.then4, label %if.end7
+
+ if.then4: ; preds = %if.end
+ %call5 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)()
+ br label %while.body6
+
+ while.body6: ; preds = %while.body6, %if.then4
+ br label %while.body6
+
+ if.end7: ; preds = %if.end
+ ret void
+ }
+
+ declare i32 @g(...)
+
+ ; Function Attrs: nounwind
+ declare void @llvm.stackprotector(i8*, i8**) #0
+
+ attributes #0 = { nounwind }
+
+ !0 = !{!1, !1, i64 0}
+ !1 = !{!"int", !2, i64 0}
+ !2 = !{!"omnipotent char", !3, i64 0}
+ !3 = !{!"Simple C/C++ TBAA"}
+
+...
+---
+name: test0a
+alignment: 2
+exposesReturnsTwice: false
+hasInlineAsm: false
+allVRegsAllocated: false
+isSSA: true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:
+ - { id: 0, class: gpr }
+ - { id: 1, class: gpr }
+ - { id: 2, class: gpr }
+ - { id: 3, class: gpr }
+ - { id: 4, class: gpr }
+ - { id: 5, class: gpr }
+liveins:
+ - { reg: '%r6', virtual-reg: '%0' }
+ - { reg: '%r7', virtual-reg: '%1' }
+ - { reg: '%r18', virtual-reg: '%2' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 0
+ adjustsStack: false
+ hasCalls: false
+ maxCallFrameSize: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+body: |
+ bb.0.entry:
+ liveins: %r6, %r7, %r18
+
+ %2 = COPY %r18
+ %1 = COPY %r7
+ %0 = COPY %r6
+ %4 = SUB_R %1, %0, 0
+ SFSUB_F_RI_LO %4, 0, implicit-def %sr
+ %5 = SELECT %2, %4, 7, implicit %sr
+ %rv = COPY %5
+ RET implicit %rca, implicit %rv
+
+...
+---
+name: test0b
+alignment: 2
+exposesReturnsTwice: false
+hasInlineAsm: false
+allVRegsAllocated: false
+isSSA: true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:
+ - { id: 0, class: gpr }
+ - { id: 1, class: gpr }
+ - { id: 2, class: gpr }
+ - { id: 3, class: gpr }
+ - { id: 4, class: gpr }
+liveins:
+ - { reg: '%r6', virtual-reg: '%0' }
+ - { reg: '%r7', virtual-reg: '%1' }
+ - { reg: '%r18', virtual-reg: '%2' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 0
+ adjustsStack: false
+ hasCalls: false
+ maxCallFrameSize: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+body: |
+ bb.0.entry:
+ liveins: %r6, %r7, %r18
+
+ %2 = COPY %r18
+ %1 = COPY %r7
+ %0 = COPY %r6
+ SFSUB_F_RR %1, %0, implicit-def %sr
+ %4 = SELECT %2, %1, 7, implicit %sr
+ %rv = COPY %4
+ RET implicit %rca, implicit %rv
+
+...
+---
+name: test1a
+alignment: 2
+exposesReturnsTwice: false
+hasInlineAsm: false
+allVRegsAllocated: false
+isSSA: true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:
+ - { id: 0, class: gpr }
+ - { id: 1, class: gpr }
+ - { id: 2, class: gpr }
+ - { id: 3, class: gpr }
+ - { id: 4, class: gpr }
+ - { id: 5, class: gpr }
+liveins:
+ - { reg: '%r6', virtual-reg: '%0' }
+ - { reg: '%r7', virtual-reg: '%1' }
+ - { reg: '%r18', virtual-reg: '%2' }
+ - { reg: '%r19', virtual-reg: '%3' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 0
+ adjustsStack: false
+ hasCalls: false
+ maxCallFrameSize: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+body: |
+ bb.0.entry:
+ liveins: %r6, %r7, %r18, %r19
+
+ %3 = COPY %r19
+ %2 = COPY %r18
+ %1 = COPY %r7
+ %0 = COPY %r6
+ %4 = SUB_R %1, %0, 0
+ SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
+ %5 = SELECT %2, %3, 11, implicit %sr
+ %rv = COPY %5
+ RET implicit %rca, implicit %rv
+
+...
+---
+name: test1b
+alignment: 2
+exposesReturnsTwice: false
+hasInlineAsm: false
+allVRegsAllocated: false
+isSSA: true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:
+ - { id: 0, class: gpr }
+ - { id: 1, class: gpr }
+ - { id: 2, class: gpr }
+ - { id: 3, class: gpr }
+ - { id: 4, class: gpr }
+ - { id: 5, class: gpr }
+liveins:
+ - { reg: '%r6', virtual-reg: '%0' }
+ - { reg: '%r7', virtual-reg: '%1' }
+ - { reg: '%r18', virtual-reg: '%2' }
+ - { reg: '%r19', virtual-reg: '%3' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 0
+ adjustsStack: false
+ hasCalls: false
+ maxCallFrameSize: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+body: |
+ bb.0.entry:
+ liveins: %r6, %r7, %r18, %r19
+
+ %3 = COPY %r19
+ %2 = COPY %r18
+ %1 = COPY %r7
+ %0 = COPY %r6
+ %4 = SUB_R %1, %0, 0
+ SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
+ %5 = SELECT %2, %3, 11, implicit %sr
+ %rv = COPY %5
+ RET implicit %rca, implicit %rv
+
+...
+---
+name: test2a
+alignment: 2
+exposesReturnsTwice: false
+hasInlineAsm: false
+allVRegsAllocated: false
+isSSA: true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:
+ - { id: 0, class: gpr }
+ - { id: 1, class: gpr }
+ - { id: 2, class: gpr }
+ - { id: 3, class: gpr }
+ - { id: 4, class: gpr }
+ - { id: 5, class: gpr }
+liveins:
+ - { reg: '%r6', virtual-reg: '%0' }
+ - { reg: '%r7', virtual-reg: '%1' }
+ - { reg: '%r18', virtual-reg: '%2' }
+ - { reg: '%r19', virtual-reg: '%3' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 0
+ adjustsStack: false
+ hasCalls: false
+ maxCallFrameSize: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+body: |
+ bb.0.entry:
+ liveins: %r6, %r7, %r18, %r19
+
+ %3 = COPY %r19
+ %2 = COPY %r18
+ %1 = COPY %r7
+ %0 = COPY %r6
+ %4 = SUB_R %1, %0, 0
+ SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
+ %5 = SELECT %2, %3, 10, implicit %sr
+ %rv = COPY %5
+ RET implicit %rca, implicit %rv
+
+...
+---
+name: test2b
+alignment: 2
+exposesReturnsTwice: false
+hasInlineAsm: false
+allVRegsAllocated: false
+isSSA: true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:
+ - { id: 0, class: gpr }
+ - { id: 1, class: gpr }
+ - { id: 2, class: gpr }
+ - { id: 3, class: gpr }
+ - { id: 4, class: gpr }
+ - { id: 5, class: gpr }
+liveins:
+ - { reg: '%r6', virtual-reg: '%0' }
+ - { reg: '%r7', virtual-reg: '%1' }
+ - { reg: '%r18', virtual-reg: '%2' }
+ - { reg: '%r19', virtual-reg: '%3' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 0
+ adjustsStack: false
+ hasCalls: false
+ maxCallFrameSize: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+body: |
+ bb.0.entry:
+ liveins: %r6, %r7, %r18, %r19
+
+ %3 = COPY %r19
+ %2 = COPY %r18
+ %1 = COPY %r7
+ %0 = COPY %r6
+ %4 = SUB_R %1, %0, 0
+ SFSUB_F_RI_LO killed %4, 0, implicit-def %sr
+ %5 = SELECT %2, %3, 10, implicit %sr
+ %rv = COPY %5
+ RET implicit %rca, implicit %rv
+
+...
+---
+name: test3
+alignment: 2
+exposesReturnsTwice: false
+hasInlineAsm: false
+allVRegsAllocated: false
+isSSA: true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:
+ - { id: 0, class: gpr }
+ - { id: 1, class: gpr }
+ - { id: 2, class: gpr }
+ - { id: 3, class: gpr }
+ - { id: 4, class: gpr }
+ - { id: 5, class: gpr }
+liveins:
+ - { reg: '%r6', virtual-reg: '%0' }
+ - { reg: '%r7', virtual-reg: '%1' }
+ - { reg: '%r18', virtual-reg: '%2' }
+ - { reg: '%r19', virtual-reg: '%3' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 0
+ adjustsStack: false
+ hasCalls: false
+ maxCallFrameSize: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+body: |
+ bb.0.entry:
+ liveins: %r6, %r7, %r18, %r19
+
+ %3 = COPY %r19
+ %2 = COPY %r18
+ %1 = COPY %r7
+ %0 = COPY %r6
+ %4 = SUB_R %1, %0, 0
+ SFSUB_F_RI_LO killed %4, 1, implicit-def %sr
+ %5 = SELECT %2, %3, 13, implicit %sr
+ %rv = COPY %5
+ RET implicit %rca, implicit %rv
+
+...
+---
+name: test4
+alignment: 2
+exposesReturnsTwice: false
+hasInlineAsm: false
+allVRegsAllocated: false
+isSSA: true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:
+ - { id: 0, class: gpr }
+ - { id: 1, class: gpr }
+ - { id: 2, class: gpr }
+ - { id: 3, class: gpr }
+ - { id: 4, class: gpr }
+ - { id: 5, class: gpr }
+ - { id: 6, class: gpr }
+ - { id: 7, class: gpr }
+ - { id: 8, class: gpr }
+ - { id: 9, class: gpr }
+ - { id: 10, class: gpr }
+ - { id: 11, class: gpr }
+ - { id: 12, class: gpr }
+ - { id: 13, class: gpr }
+ - { id: 14, class: gpr }
+ - { id: 15, class: gpr }
+ - { id: 16, class: gpr }
+ - { id: 17, class: gpr }
+ - { id: 18, class: gpr }
+ - { id: 19, class: gpr }
+ - { id: 20, class: gpr }
+ - { id: 21, class: gpr }
+ - { id: 22, class: gpr }
+liveins:
+ - { reg: '%r6', virtual-reg: '%1' }
+ - { reg: '%r7', virtual-reg: '%2' }
+ - { reg: '%r18', virtual-reg: '%3' }
+ - { reg: '%r19', virtual-reg: '%4' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 0
+ adjustsStack: false
+ hasCalls: false
+ maxCallFrameSize: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+body: |
+ bb.0.entry:
+ successors: %bb.4.return, %bb.1.if.end
+ liveins: %r6, %r7, %r18, %r19
+
+ %4 = COPY %r19
+ %3 = COPY %r18
+ %2 = COPY %r7
+ %1 = COPY %r6
+ SFSUB_F_RI_LO %1, 0, implicit-def %sr
+ %5 = SCC 6, implicit %sr
+ SFSUB_F_RR %1, %2, implicit-def %sr
+ %6 = SCC 4, implicit %sr
+ %7 = AND_R killed %5, killed %6, 0
+ %8 = SLI 1
+ %9 = AND_R killed %7, %8, 0
+ SFSUB_F_RI_LO killed %9, 0, implicit-def %sr
+ BRCC %bb.4.return, 6, implicit %sr
+ BT %bb.1.if.end
+
+ bb.1.if.end:
+ successors: %bb.4.return, %bb.2.if.end6
+
+ SFSUB_F_RI_LO %2, 0, implicit-def %sr
+ %10 = SCC 6, implicit %sr
+ SFSUB_F_RR %2, %3, implicit-def %sr
+ %11 = SCC 4, implicit %sr
+ %12 = AND_R killed %10, killed %11, 0
+ %14 = AND_R killed %12, %8, 0
+ SFSUB_F_RI_LO killed %14, 0, implicit-def %sr
+ BRCC %bb.4.return, 6, implicit %sr
+ BT %bb.2.if.end6
+
+ bb.2.if.end6:
+ successors: %bb.4.return, %bb.3.if.end11
+
+ SFSUB_F_RI_LO %3, 0, implicit-def %sr
+ %15 = SCC 6, implicit %sr
+ SFSUB_F_RR %3, %4, implicit-def %sr
+ %16 = SCC 4, implicit %sr
+ %17 = AND_R killed %15, killed %16, 0
+ %18 = SLI 1
+ %19 = AND_R killed %17, killed %18, 0
+ SFSUB_F_RI_LO killed %19, 0, implicit-def %sr
+ BRCC %bb.4.return, 6, implicit %sr
+ BT %bb.3.if.end11
+
+ bb.3.if.end11:
+ %20 = SLI 21
+ SFSUB_F_RR %4, %1, implicit-def %sr
+ %21 = SELECT %2, %20, 4, implicit %sr
+ SFSUB_F_RI_LO %4, 0, implicit-def %sr
+ %22 = SELECT killed %21, %20, 6, implicit %sr
+ %rv = COPY %22
+ RET implicit %rca, implicit %rv
+
+ bb.4.return:
+ %0 = PHI %3, %bb.0.entry, %4, %bb.1.if.end, %1, %bb.2.if.end6
+ %rv = COPY %0
+ RET implicit %rca, implicit %rv
+
+...
+---
+name: testBB
+alignment: 2
+exposesReturnsTwice: false
+hasInlineAsm: false
+allVRegsAllocated: false
+isSSA: true
+tracksRegLiveness: true
+tracksSubRegLiveness: false
+registers:
+ - { id: 0, class: gpr }
+ - { id: 1, class: gpr }
+ - { id: 2, class: gpr }
+ - { id: 3, class: gpr }
+ - { id: 4, class: gpr }
+ - { id: 5, class: gpr }
+ - { id: 6, class: gpr }
+ - { id: 7, class: gpr }
+ - { id: 8, class: gpr }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 0
+ adjustsStack: false
+ hasCalls: true
+ maxCallFrameSize: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+body: |
+ bb.0.entry:
+ successors: %bb.3.if.end, %bb.1.if.then
+
+ %1 = MOVHI target-flags(lanai-hi) @a
+ %2 = OR_I_LO killed %1, target-flags(lanai-lo) @a
+ %3 = LDW_RI killed %2, 0, 0 :: (load 4 from @a, !tbaa !0)
+ %4 = MOVHI target-flags(lanai-hi) @b
+ %5 = OR_I_LO killed %4, target-flags(lanai-lo) @b
+ %6 = LDW_RI killed %5, 0, 0 :: (load 4 from @b, !tbaa !0)
+ %0 = SUB_R killed %6, killed %3, 0
+ SFSUB_F_RI_LO %0, 0, implicit-def %sr
+ BRCC %bb.3.if.end, 10, implicit %sr
+ BT %bb.1.if.then
+
+ bb.1.if.then:
+ successors: %bb.2.while.body
+
+ ADJCALLSTACKDOWN 0, implicit-def dead %sp, implicit %sp
+ CALL @g, csr, implicit-def dead %rca, implicit %sp, implicit-def %sp, implicit-def %rv
+ ADJCALLSTACKUP 0, 0, implicit-def dead %sp, implicit %sp
+
+ bb.2.while.body:
+ successors: %bb.2.while.body
+
+ BT %bb.2.while.body
+
+ bb.3.if.end:
+ successors: %bb.4.if.then4, %bb.6.if.end7
+ liveins: %sr
+
+ BRCC %bb.6.if.end7, 14, implicit %sr
+ BT %bb.4.if.then4
+
+ bb.4.if.then4:
+ successors: %bb.5.while.body6
+
+ ADJCALLSTACKDOWN 0, implicit-def dead %sp, implicit %sp
+ CALL @g, csr, implicit-def dead %rca, implicit %sp, implicit-def %sp, implicit-def %rv
+ ADJCALLSTACKUP 0, 0, implicit-def dead %sp, implicit %sp
+
+ bb.5.while.body6:
+ successors: %bb.5.while.body6
+
+ BT %bb.5.while.body6
+
+ bb.6.if.end7:
+ RET implicit %rca
+
+...
Modified: llvm/trunk/test/MC/Lanai/v11.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/Lanai/v11.s?rev=274807&r1=274806&r2=274807&view=diff
==============================================================================
--- llvm/trunk/test/MC/Lanai/v11.s (original)
+++ llvm/trunk/test/MC/Lanai/v11.s Thu Jul 7 18:36:04 2016
@@ -12,13 +12,13 @@ add.f %r17, 0x00001234, %r21
! CHECK: 0x0a,0xc6,0x12,0x34
add.f %r17, 0x12340000, %r21
! CHECK: 0x0a,0xc7,0x12,0x34
-add %r17, %r18, %r21
+add.t %r17, %r18, %r21
! CHECK: 0xca,0xc4,0x90,0x00
-add.f %r17, %r18, %r21
+add.f.t %r17, %r18, %r21
! CHECK: 0xca,0xc6,0x90,0x00
-addc %r17, %r18, %r21
+addc.t %r17, %r18, %r21
! CHECK: 0xca,0xc4,0x91,0x00
-addc.f %r17, %r18, %r21
+addc.f.t %r17, %r18, %r21
! CHECK: 0xca,0xc6,0x91,0x00
addc %r17, 0, %r21
! CHECK: 0x1a,0xc4,0x00,0x00
@@ -40,9 +40,9 @@ and.f %r17, 0xffff1234, %r21
! CHECK: 0x4a,0xc6,0x12,0x34
and.f %r17, 0x1234ffff, %r21
! CHECK: 0x4a,0xc7,0x12,0x34
-and %r17, %r18, %r21
+and.t %r17, %r18, %r21
! CHECK: 0xca,0xc4,0x94,0x00
-and.f %r17, %r18, %r21
+and.f.t %r17, %r18, %r21
! CHECK: 0xca,0xc6,0x94,0x00
bt 0x123454
! CHECK: 0xe0,0x12,0x34,0x54
@@ -418,9 +418,9 @@ or.f %r17, 0x00001234, %r21
! CHECK: 0x5a,0xc6,0x12,0x34
or.f %r17, 0x12340000, %r21
! CHECK: 0x5a,0xc7,0x12,0x34
-or %r17, %r18, %r21
+or.t %r17, %r18, %r21
! CHECK: 0xca,0xc4,0x95,0x00
-or.f %r17, %r18, %r21
+or.f.t %r17, %r18, %r21
! CHECK: 0xca,0xc6,0x95,0x00
popc %r17, %r21
! CHECK: 0xda,0xc4,0x00,0x01
@@ -790,9 +790,9 @@ sub.f %r17, 0x00001234, %r21
! CHECK: 0x2a,0xc6,0x12,0x34
sub.f %r17, 0x12340000, %r21
! CHECK: 0x2a,0xc7,0x12,0x34
-sub %r17, %r18, %r21
+sub.t %r17, %r18, %r21
! CHECK: 0xca,0xc4,0x92,0x00
-sub.f %r17, %r18, %r21
+sub.f.t %r17, %r18, %r21
! CHECK: 0xca,0xc6,0x92,0x00
subb %r17, 0, %r21
! CHECK: 0x3a,0xc4,0x00,0x00
@@ -806,9 +806,9 @@ subb.f %r17, 0x00001234, %r21
! CHECK: 0x3a,0xc6,0x12,0x34
subb.f %r17, 0x12340000, %r21
! CHECK: 0x3a,0xc7,0x12,0x34
-subb %r17, %r18, %r21
+subb.t %r17, %r18, %r21
! CHECK: 0xca,0xc4,0x93,0x00
-subb.f %r17, %r18, %r21
+subb.f.t %r17, %r18, %r21
! CHECK: 0xca,0xc6,0x93,0x00
xor %r17, 0, %r21
! CHECK: 0x6a,0xc4,0x00,0x00
@@ -822,9 +822,21 @@ xor.f %r17, 0x00001234, %r21
! CHECK: 0x6a,0xc6,0x12,0x34
xor.f %r17, 0x12340000, %r21
! CHECK: 0x6a,0xc7,0x12,0x34
-xor %r17, %r18, %r21
+xor.t %r17, %r18, %r21
! CHECK: 0xca,0xc4,0x96,0x00
-xor.f %r17, %r18, %r21
+xor.f.t %r17, %r18, %r21
! CHECK: 0xca,0xc6,0x96,0x00
-
-
+sel.ne %r9, %r15, %r12
+! CHECK: 0xc6,0x24,0x7f,0x03
+sel.gt %r9, %r15, %r12
+! CHECK: 0xc6,0x24,0x7f,0x07
+xor.lt %r17, %r18, %r21
+! CHECK: 0xca,0xc5,0x96,0x06
+xor.f.eq %r17, %r18, %r21
+! CHECK: 0xca,0xc7,0x96,0x03
+add.ge %r13, %r14, %r18
+! CHECK: 0xc9,0x34,0x70,0x06
+spl %r19
+! CHECK: 0xea,0x4c,0x00,0x02
+bt 0x1234
+! CHECK: 0xe0,0x00,0x12,0x34
More information about the llvm-commits
mailing list