Skip to content

Commit

Permalink
[lanai] Use peephole optimizer to generate more conditional ALU opera…
Browse files Browse the repository at this point in the history
…tions.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@274807 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
jpienaar committed Jul 7, 2016
1 parent 664a3a9 commit 261c94d
Show file tree
Hide file tree
Showing 20 changed files with 1,560 additions and 550 deletions.
30 changes: 29 additions & 1 deletion lib/Target/Lanai/AsmParser/LanaiAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,20 @@ struct LanaiOperand : public MCParsedAsmOperand {
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)
Expand Down Expand Up @@ -388,6 +402,11 @@ struct LanaiOperand : public MCParsedAsmOperand {
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();
Expand Down Expand Up @@ -1031,7 +1050,16 @@ StringRef LanaiAsmParser::splitMnemonic(StringRef Name, SMLoc NameLoc,
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));
Expand Down
1 change: 0 additions & 1 deletion lib/Target/Lanai/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ add_llvm_target(LanaiCodeGen
LanaiMemAluCombiner.cpp
LanaiRegisterInfo.cpp
LanaiSelectionDAGInfo.cpp
LanaiSetflagAluCombiner.cpp
LanaiSubtarget.cpp
LanaiTargetMachine.cpp
LanaiTargetObjectFile.cpp
Expand Down
13 changes: 13 additions & 0 deletions lib/Target/Lanai/Disassembler/LanaiDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ static DecodeStatus decodeSplsValue(MCInst &Inst, unsigned Insn,
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);

Expand Down Expand Up @@ -226,3 +230,12 @@ static DecodeStatus decodeShiftImm(MCInst &Inst, unsigned Insn,

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;
}
20 changes: 18 additions & 2 deletions lib/Target/Lanai/InstPrinter/LanaiInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,22 @@ void LanaiInstPrinter::printMemSplsOperand(const MCInst *MI, int OpNo,

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);
}
1 change: 1 addition & 0 deletions lib/Target/Lanai/InstPrinter/LanaiInstPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class LanaiInstPrinter : public MCInstPrinter {
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,
Expand Down
12 changes: 2 additions & 10 deletions lib/Target/Lanai/LanaiAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class LanaiAsmPrinter : public AsmPrinter {
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:
Expand All @@ -81,10 +80,7 @@ void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
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: {
Expand All @@ -94,10 +90,7 @@ void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
}

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:
Expand All @@ -116,7 +109,6 @@ void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
}

// 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) {
Expand Down
170 changes: 170 additions & 0 deletions lib/Target/Lanai/LanaiISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ LanaiTargetLowering::LanaiTargetLowering(const TargetMachine &TM,
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);
Expand Down Expand Up @@ -1268,3 +1274,167 @@ SDValue LanaiTargetLowering::LowerSRL_PARTS(SDValue Op,
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();
}
2 changes: 2 additions & 0 deletions lib/Target/Lanai/LanaiISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ class LanaiTargetLowering : public TargetLowering {
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,
Expand Down
Loading

0 comments on commit 261c94d

Please sign in to comment.