Skip to content

Commit

Permalink
[PowerPC] Eliminate integer compare instructions - vol. 1
Browse files Browse the repository at this point in the history
This patch is the first in a series of patches to provide code gen for
doing compares in GPRs when the compare result is required in a GPR.

It adds the infrastructure to select GPR sequences for i1->i32 and i1->i64
extensions. This first patch handles equality comparison on i32 operands with
the result sign or zero extended.

Differential Revision: https://reviews.llvm.org/D31847


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302810 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
nemanjai committed May 11, 2017
1 parent 44303fa commit 0470a16
Show file tree
Hide file tree
Showing 18 changed files with 1,942 additions and 11 deletions.
3 changes: 2 additions & 1 deletion lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ void PPCInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
return;
}

if (MI->getOpcode() == PPC::RLDICR) {
if (MI->getOpcode() == PPC::RLDICR ||
MI->getOpcode() == PPC::RLDICR_32) {
unsigned char SH = MI->getOperand(2).getImm();
unsigned char ME = MI->getOperand(3).getImm();
// rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
Expand Down
1 change: 1 addition & 0 deletions lib/Target/PowerPC/PPCFastISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2246,6 +2246,7 @@ bool PPCFastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
}

case PPC::EXTSW:
case PPC::EXTSW_32:
case PPC::EXTSW_32_64: {
if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8)
return false;
Expand Down
255 changes: 255 additions & 0 deletions lib/Target/PowerPC/PPCISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/ADT/Statistic.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
Expand All @@ -68,6 +69,14 @@ using namespace llvm;

#define DEBUG_TYPE "ppc-codegen"

STATISTIC(NumSextSetcc,
"Number of (sext(setcc)) nodes expanded into GPR sequence.");
STATISTIC(NumZextSetcc,
"Number of (zext(setcc)) nodes expanded into GPR sequence.");
STATISTIC(SignExtensionsAdded,
"Number of sign extensions for compare inputs added.");
STATISTIC(ZeroExtensionsAdded,
"Number of zero extensions for compare inputs added.");
// FIXME: Remove this once the bug has been fixed!
cl::opt<bool> ANDIGlueBug("expose-ppc-andi-glue-bug",
cl::desc("expose the ANDI glue bug on PPC"), cl::Hidden);
Expand Down Expand Up @@ -252,7 +261,28 @@ namespace {
#include "PPCGenDAGISel.inc"

private:
// Conversion type for interpreting results of a 32-bit instruction as
// a 64-bit value or vice versa.
enum ExtOrTruncConversion { Ext, Trunc };

// Modifiers to guide how an ISD::SETCC node's result is to be computed
// in a GPR.
// ZExtOrig - use the original condition code, zero-extend value
// ZExtInvert - invert the condition code, zero-extend value
// SExtOrig - use the original condition code, sign-extend value
// SExtInvert - invert the condition code, sign-extend value
enum SetccInGPROpts { ZExtOrig, ZExtInvert, SExtOrig, SExtInvert };

bool trySETCC(SDNode *N);
bool tryEXTEND(SDNode *N);
SDValue signExtendInputIfNeeded(SDValue Input);
SDValue zeroExtendInputIfNeeded(SDValue Input);
SDValue addExtOrTrunc(SDValue NatWidthRes, ExtOrTruncConversion Conv);
SDValue get32BitZExtCompare(SDValue LHS, SDValue RHS, ISD::CondCode CC,
int64_t RHSValue, SDLoc dl);
SDValue get32BitSExtCompare(SDValue LHS, SDValue RHS, ISD::CondCode CC,
int64_t RHSValue, SDLoc dl);
SDValue getSETCCInGPR(SDValue Compare, SetccInGPROpts ConvOpts);

void PeepholePPC64();
void PeepholePPC64ZExt();
Expand Down Expand Up @@ -2471,6 +2501,225 @@ bool PPCDAGToDAGISel::trySETCC(SDNode *N) {
return true;
}

/// If this node is a sign/zero extension of an integer comparison,
/// it can usually be computed in GPR's rather than using comparison
/// instructions and ISEL. We only do this on 64-bit targets for now
/// as the code is specialized for 64-bit (it uses 64-bit instructions
/// and assumes 64-bit registers).
bool PPCDAGToDAGISel::tryEXTEND(SDNode *N) {
if (TM.getOptLevel() == CodeGenOpt::None || !TM.isPPC64())
return false;
assert((N->getOpcode() == ISD::ZERO_EXTEND ||
N->getOpcode() == ISD::SIGN_EXTEND) &&
"Expecting a zero/sign extend node!");

if (N->getOperand(0).getOpcode() != ISD::SETCC)
return false;

SDValue WideRes =
getSETCCInGPR(N->getOperand(0),
N->getOpcode() == ISD::SIGN_EXTEND ?
SetccInGPROpts::SExtOrig : SetccInGPROpts::ZExtOrig);

if (!WideRes)
return false;

SDLoc dl(N);
bool Inputs32Bit = N->getOperand(0).getOperand(0).getValueType() == MVT::i32;
bool Output32Bit = N->getValueType(0) == MVT::i32;

NumSextSetcc += N->getOpcode() == ISD::SIGN_EXTEND ? 1 : 0;
NumZextSetcc += N->getOpcode() == ISD::SIGN_EXTEND ? 0 : 1;

SDValue ConvOp = WideRes;
if (Inputs32Bit != Output32Bit)
ConvOp = addExtOrTrunc(WideRes, Inputs32Bit ? ExtOrTruncConversion::Ext :
ExtOrTruncConversion::Trunc);
ReplaceNode(N, ConvOp.getNode());

return true;
}

/// If the value isn't guaranteed to be sign-extended to 64-bits, extend it.
/// Useful when emitting comparison code for 32-bit values without using
/// the compare instruction (which only considers the lower 32-bits).
SDValue PPCDAGToDAGISel::signExtendInputIfNeeded(SDValue Input) {
assert(Input.getValueType() == MVT::i32 &&
"Can only sign-extend 32-bit values here.");
unsigned Opc = Input.getOpcode();

// The value was sign extended and then truncated to 32-bits. No need to
// sign extend it again.
if (Opc == ISD::TRUNCATE &&
(Input.getOperand(0).getOpcode() == ISD::AssertSext ||
Input.getOperand(0).getOpcode() == ISD::SIGN_EXTEND))
return Input;

LoadSDNode *InputLoad = dyn_cast<LoadSDNode>(Input);
// The input is a sign-extending load. No reason to sign-extend.
if (InputLoad && InputLoad->getExtensionType() == ISD::SEXTLOAD)
return Input;

ConstantSDNode *InputConst = dyn_cast<ConstantSDNode>(Input);
// We don't sign-extend constants and already sign-extended values.
if (InputConst || Opc == ISD::AssertSext || Opc == ISD::SIGN_EXTEND_INREG ||
Opc == ISD::SIGN_EXTEND)
return Input;

SDLoc dl(Input);
SignExtensionsAdded++;
return SDValue(CurDAG->getMachineNode(PPC::EXTSW_32, dl, MVT::i32, Input), 0);
}

/// If the value isn't guaranteed to be zero-extended to 64-bits, extend it.
/// Useful when emitting comparison code for 32-bit values without using
/// the compare instruction (which only considers the lower 32-bits).
SDValue PPCDAGToDAGISel::zeroExtendInputIfNeeded(SDValue Input) {
assert(Input.getValueType() == MVT::i32 &&
"Can only zero-extend 32-bit values here.");
LoadSDNode *InputLoad = dyn_cast<LoadSDNode>(Input);
unsigned Opc = Input.getOpcode();

// No need to zero-extend loaded values (unless they're loaded with
// a sign-extending load).
if (InputLoad && InputLoad->getExtensionType() != ISD::SEXTLOAD)
return Input;

ConstantSDNode *InputConst = dyn_cast<ConstantSDNode>(Input);
bool InputZExtConst = InputConst && InputConst->getSExtValue() >= 0;
// An ISD::TRUNCATE will be lowered to an EXTRACT_SUBREG so we have
// to conservatively actually clear the high bits. We also don't need to
// zero-extend constants or values that are already zero-extended.
if (InputZExtConst || Opc == ISD::AssertZext || Opc == ISD::ZERO_EXTEND)
return Input;

SDLoc dl(Input);
ZeroExtensionsAdded++;
return SDValue(CurDAG->getMachineNode(PPC::RLDICL_32, dl, MVT::i32, Input,
getI64Imm(0, dl), getI64Imm(32, dl)),
0);
}

// Handle a 32-bit value in a 64-bit register and vice-versa. These are of
// course not actual zero/sign extensions that will generate machine code,
// they're just a way to reinterpret a 32 bit value in a register as a
// 64 bit value and vice-versa.
SDValue PPCDAGToDAGISel::addExtOrTrunc(SDValue NatWidthRes,
ExtOrTruncConversion Conv) {
SDLoc dl(NatWidthRes);

// For reinterpreting 32-bit values as 64 bit values, we generate
// INSERT_SUBREG IMPLICIT_DEF:i64, <input>, TargetConstant:i32<1>
if (Conv == ExtOrTruncConversion::Ext) {
SDValue ImDef(CurDAG->getMachineNode(PPC::IMPLICIT_DEF, dl, MVT::i64), 0);
SDValue SubRegIdx =
CurDAG->getTargetConstant(PPC::sub_32, dl, MVT::i32);
return SDValue(CurDAG->getMachineNode(PPC::INSERT_SUBREG, dl, MVT::i64,
ImDef, NatWidthRes, SubRegIdx), 0);
}

assert(Conv == ExtOrTruncConversion::Trunc &&
"Unknown convertion between 32 and 64 bit values.");
// For reinterpreting 64-bit values as 32-bit values, we just need to
// EXTRACT_SUBREG (i.e. extract the low word).
SDValue SubRegIdx =
CurDAG->getTargetConstant(PPC::sub_32, dl, MVT::i32);
return SDValue(CurDAG->getMachineNode(PPC::EXTRACT_SUBREG, dl, MVT::i32,
NatWidthRes, SubRegIdx), 0);
}

/// Produces a zero-extended result of comparing two 32-bit values according to
/// the passed condition code.
SDValue PPCDAGToDAGISel::get32BitZExtCompare(SDValue LHS, SDValue RHS,
ISD::CondCode CC,
int64_t RHSValue, SDLoc dl) {
bool IsRHSZero = RHSValue == 0;
switch (CC) {
default: return SDValue();
case ISD::SETEQ: {
// (zext (setcc %a, %b, seteq)) -> (lshr (cntlzw (xor %a, %b)), 5)
// (zext (setcc %a, 0, seteq)) -> (lshr (cntlzw %a), 5)
SDValue Xor = IsRHSZero ? LHS :
SDValue(CurDAG->getMachineNode(PPC::XOR, dl, MVT::i32, LHS, RHS), 0);
SDValue Clz =
SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, Xor), 0);
SDValue ShiftOps[] = { Clz, getI32Imm(27, dl), getI32Imm(5, dl),
getI32Imm(31, dl) };
return SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32,
ShiftOps), 0);
}
}
}

/// Produces a sign-extended result of comparing two 32-bit values according to
/// the passed condition code.
SDValue PPCDAGToDAGISel::get32BitSExtCompare(SDValue LHS, SDValue RHS,
ISD::CondCode CC,
int64_t RHSValue, SDLoc dl) {
bool IsRHSZero = RHSValue == 0;
switch (CC) {
default: return SDValue();
case ISD::SETEQ: {
// (sext (setcc %a, %b, seteq)) ->
// (ashr (shl (ctlz (xor %a, %b)), 58), 63)
// (sext (setcc %a, 0, seteq)) ->
// (ashr (shl (ctlz %a), 58), 63)
SDValue CountInput = IsRHSZero ? LHS :
SDValue(CurDAG->getMachineNode(PPC::XOR, dl, MVT::i32, LHS, RHS), 0);
SDValue Cntlzw =
SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, CountInput), 0);
SDValue SHLOps[] = { Cntlzw, getI32Imm(58, dl), getI32Imm(0, dl) };
SDValue Sldi =
SDValue(CurDAG->getMachineNode(PPC::RLDICR_32, dl, MVT::i32, SHLOps), 0);
return SDValue(CurDAG->getMachineNode(PPC::SRADI_32, dl, MVT::i32, Sldi,
getI32Imm(63, dl)), 0);
}
}
}

/// Returns an equivalent of a SETCC node but with the result the same width as
/// the inputs. This can nalso be used for SELECT_CC if either the true or false
/// values is a power of two while the other is zero.
SDValue PPCDAGToDAGISel::getSETCCInGPR(SDValue Compare,
SetccInGPROpts ConvOpts) {
assert((Compare.getOpcode() == ISD::SETCC ||
Compare.getOpcode() == ISD::SELECT_CC) &&
"An ISD::SETCC node required here.");

SDValue LHS = Compare.getOperand(0);
SDValue RHS = Compare.getOperand(1);

// The condition code is operand 2 for SETCC and operand 4 for SELECT_CC.
int CCOpNum = Compare.getOpcode() == ISD::SELECT_CC ? 4 : 2;
ISD::CondCode CC =
cast<CondCodeSDNode>(Compare.getOperand(CCOpNum))->get();
EVT InputVT = LHS.getValueType();
if (InputVT != MVT::i32)
return SDValue();

SDLoc dl(Compare);
ConstantSDNode *RHSConst = dyn_cast<ConstantSDNode>(RHS);
int64_t RHSValue = RHSConst ? RHSConst->getSExtValue() : INT64_MAX;

if (ConvOpts == SetccInGPROpts::ZExtInvert ||
ConvOpts == SetccInGPROpts::SExtInvert)
CC = ISD::getSetCCInverse(CC, true);

if (ISD::isSignedIntSetCC(CC)) {
LHS = signExtendInputIfNeeded(LHS);
RHS = signExtendInputIfNeeded(RHS);
} else if (ISD::isUnsignedIntSetCC(CC)) {
LHS = zeroExtendInputIfNeeded(LHS);
RHS = zeroExtendInputIfNeeded(RHS);
}

bool IsSext = ConvOpts == SetccInGPROpts::SExtOrig ||
ConvOpts == SetccInGPROpts::SExtInvert;
if (IsSext)
return get32BitSExtCompare(LHS, RHS, CC, RHSValue, dl);
return get32BitZExtCompare(LHS, RHS, CC, RHSValue, dl);
}

void PPCDAGToDAGISel::transferMemOperands(SDNode *N, SDNode *Result) {
// Transfer memoperands.
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
Expand Down Expand Up @@ -2508,6 +2757,12 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
}
break;

case ISD::ZERO_EXTEND:
case ISD::SIGN_EXTEND:
if (tryEXTEND(N))
return;
break;

case ISD::SETCC:
if (trySETCC(N))
return;
Expand Down
28 changes: 24 additions & 4 deletions lib/Target/PowerPC/PPCInstr64Bit.td
Original file line number Diff line number Diff line change
Expand Up @@ -634,10 +634,19 @@ let Interpretation64Bit = 1, isCodeGenOnly = 1 in
defm EXTSW_32_64 : XForm_11r<31, 986, (outs g8rc:$rA), (ins gprc:$rS),
"extsw", "$rA, $rS", IIC_IntSimple,
[(set i64:$rA, (sext i32:$rS))]>, isPPC64;
let isCodeGenOnly = 1 in
def EXTSW_32 : XForm_11<31, 986, (outs gprc:$rA), (ins gprc:$rS),
"extsw $rA, $rS", IIC_IntSimple,
[]>, isPPC64;

defm SRADI : XSForm_1rc<31, 413, (outs g8rc:$rA), (ins g8rc:$rS, u6imm:$SH),
"sradi", "$rA, $rS, $SH", IIC_IntRotateDI,
[(set i64:$rA, (sra i64:$rS, (i32 imm:$SH)))]>, isPPC64;
// For fast-isel:
let isCodeGenOnly = 1 in
def SRADI_32 : XSForm_1<31, 413, (outs gprc:$rA), (ins gprc:$rS, u6imm:$SH),
"sradi $rA, $rS, $SH", IIC_IntRotateDI, []>, isPPC64;

defm CNTLZD : XForm_11r<31, 58, (outs g8rc:$rA), (ins g8rc:$rS),
"cntlzd", "$rA, $rS", IIC_IntGeneral,
[(set i64:$rA, (ctlz i64:$rS))]>;
Expand Down Expand Up @@ -721,15 +730,26 @@ defm RLDICL : MDForm_1r<30, 0,
// For fast-isel:
let isCodeGenOnly = 1 in
def RLDICL_32_64 : MDForm_1<30, 0,
(outs g8rc:$rA),
(ins gprc:$rS, u6imm:$SH, u6imm:$MBE),
"rldicl $rA, $rS, $SH, $MBE", IIC_IntRotateDI,
[]>, isPPC64;
(outs g8rc:$rA),
(ins gprc:$rS, u6imm:$SH, u6imm:$MBE),
"rldicl $rA, $rS, $SH, $MBE", IIC_IntRotateDI,
[]>, isPPC64;
// End fast-isel.
let isCodeGenOnly = 1 in
def RLDICL_32 : MDForm_1<30, 0,
(outs gprc:$rA),
(ins gprc:$rS, u6imm:$SH, u6imm:$MBE),
"rldicl $rA, $rS, $SH, $MBE", IIC_IntRotateDI,
[]>, isPPC64;
defm RLDICR : MDForm_1r<30, 1,
(outs g8rc:$rA), (ins g8rc:$rS, u6imm:$SH, u6imm:$MBE),
"rldicr", "$rA, $rS, $SH, $MBE", IIC_IntRotateDI,
[]>, isPPC64;
let isCodeGenOnly = 1 in
def RLDICR_32 : MDForm_1<30, 1,
(outs gprc:$rA), (ins gprc:$rS, u6imm:$SH, u6imm:$MBE),
"rldicr $rA, $rS, $SH, $MBE", IIC_IntRotateDI,
[]>, isPPC64;
defm RLDIC : MDForm_1r<30, 2,
(outs g8rc:$rA), (ins g8rc:$rS, u6imm:$SH, u6imm:$MBE),
"rldic", "$rA, $rS, $SH, $MBE", IIC_IntRotateDI,
Expand Down
2 changes: 2 additions & 0 deletions lib/Target/PowerPC/PPCInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -4166,6 +4166,8 @@ def : InstAlias<"rotldi. $rA, $rS, $n", (RLDICLo g8rc:$rA, g8rc:$rS, u6imm:$n, 0
def : InstAlias<"rotld $rA, $rS, $rB", (RLDCL g8rc:$rA, g8rc:$rS, gprc:$rB, 0)>;
def : InstAlias<"rotld. $rA, $rS, $rB", (RLDCLo g8rc:$rA, g8rc:$rS, gprc:$rB, 0)>;
def : InstAlias<"clrldi $rA, $rS, $n", (RLDICL g8rc:$rA, g8rc:$rS, 0, u6imm:$n)>;
def : InstAlias<"clrldi $rA, $rS, $n",
(RLDICL_32 gprc:$rA, gprc:$rS, 0, u6imm:$n)>;
def : InstAlias<"clrldi. $rA, $rS, $n", (RLDICLo g8rc:$rA, g8rc:$rS, 0, u6imm:$n)>;

def RLWINMbm : PPCAsmPseudo<"rlwinm $rA, $rS, $n, $b",
Expand Down
Loading

0 comments on commit 0470a16

Please sign in to comment.