mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
d04a8d4b33
Sooooo many of these had incorrect or strange main module includes. I have manually inspected all of these, and fixed the main module include to be the nearest plausible thing I could find. If you own or care about any of these source files, I encourage you to take some time and check that these edits were sensible. I can't have broken anything (I strictly added headers, and reordered them, never removed), but they may not be the headers you'd really like to identify as containing the API being implemented. Many forward declarations and missing includes were added to a header files to allow them to parse cleanly when included first. The main module rule does in fact have its merits. =] git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@169131 91177308-0d34-0410-b5e6-96231b3b80d8
1522 lines
54 KiB
C++
1522 lines
54 KiB
C++
//===-- HexagonISelDAGToDAG.cpp - A dag to dag inst selector for Hexagon --===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines an instruction selector for the Hexagon target.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "hexagon-isel"
|
|
#include "Hexagon.h"
|
|
#include "HexagonISelLowering.h"
|
|
#include "HexagonTargetMachine.h"
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
#include "llvm/Intrinsics.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instruction Selector Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// HexagonDAGToDAGISel - Hexagon specific code to select Hexagon machine
|
|
/// instructions for SelectionDAG operations.
|
|
///
|
|
namespace {
|
|
class HexagonDAGToDAGISel : public SelectionDAGISel {
|
|
/// Subtarget - Keep a pointer to the Hexagon Subtarget around so that we can
|
|
/// make the right decision when generating code for different targets.
|
|
const HexagonSubtarget &Subtarget;
|
|
|
|
// Keep a reference to HexagonTargetMachine.
|
|
HexagonTargetMachine& TM;
|
|
const HexagonInstrInfo *TII;
|
|
|
|
public:
|
|
explicit HexagonDAGToDAGISel(HexagonTargetMachine &targetmachine)
|
|
: SelectionDAGISel(targetmachine),
|
|
Subtarget(targetmachine.getSubtarget<HexagonSubtarget>()),
|
|
TM(targetmachine),
|
|
TII(static_cast<const HexagonInstrInfo*>(TM.getInstrInfo())) {
|
|
|
|
}
|
|
|
|
SDNode *Select(SDNode *N);
|
|
|
|
// Complex Pattern Selectors.
|
|
bool SelectADDRri(SDValue& N, SDValue &R1, SDValue &R2);
|
|
bool SelectADDRriS11_0(SDValue& N, SDValue &R1, SDValue &R2);
|
|
bool SelectADDRriS11_1(SDValue& N, SDValue &R1, SDValue &R2);
|
|
bool SelectADDRriS11_2(SDValue& N, SDValue &R1, SDValue &R2);
|
|
bool SelectMEMriS11_2(SDValue& Addr, SDValue &Base, SDValue &Offset);
|
|
bool SelectADDRriS11_3(SDValue& N, SDValue &R1, SDValue &R2);
|
|
bool SelectADDRrr(SDValue &Addr, SDValue &Base, SDValue &Offset);
|
|
bool SelectADDRriU6_0(SDValue& N, SDValue &R1, SDValue &R2);
|
|
bool SelectADDRriU6_1(SDValue& N, SDValue &R1, SDValue &R2);
|
|
bool SelectADDRriU6_2(SDValue& N, SDValue &R1, SDValue &R2);
|
|
|
|
virtual const char *getPassName() const {
|
|
return "Hexagon DAG->DAG Pattern Instruction Selection";
|
|
}
|
|
|
|
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
|
|
/// inline asm expressions.
|
|
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op,
|
|
char ConstraintCode,
|
|
std::vector<SDValue> &OutOps);
|
|
bool SelectAddr(SDNode *Op, SDValue Addr, SDValue &Base, SDValue &Offset);
|
|
|
|
SDNode *SelectLoad(SDNode *N);
|
|
SDNode *SelectBaseOffsetLoad(LoadSDNode *LD, DebugLoc dl);
|
|
SDNode *SelectIndexedLoad(LoadSDNode *LD, DebugLoc dl);
|
|
SDNode *SelectIndexedLoadZeroExtend64(LoadSDNode *LD, unsigned Opcode,
|
|
DebugLoc dl);
|
|
SDNode *SelectIndexedLoadSignExtend64(LoadSDNode *LD, unsigned Opcode,
|
|
DebugLoc dl);
|
|
SDNode *SelectBaseOffsetStore(StoreSDNode *ST, DebugLoc dl);
|
|
SDNode *SelectIndexedStore(StoreSDNode *ST, DebugLoc dl);
|
|
SDNode *SelectStore(SDNode *N);
|
|
SDNode *SelectSHL(SDNode *N);
|
|
SDNode *SelectSelect(SDNode *N);
|
|
SDNode *SelectTruncate(SDNode *N);
|
|
SDNode *SelectMul(SDNode *N);
|
|
SDNode *SelectZeroExtend(SDNode *N);
|
|
SDNode *SelectIntrinsicWOChain(SDNode *N);
|
|
SDNode *SelectIntrinsicWChain(SDNode *N);
|
|
SDNode *SelectConstant(SDNode *N);
|
|
SDNode *SelectConstantFP(SDNode *N);
|
|
SDNode *SelectAdd(SDNode *N);
|
|
bool isConstExtProfitable(SDNode *N) const;
|
|
|
|
// Include the pieces autogenerated from the target description.
|
|
#include "HexagonGenDAGISel.inc"
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
|
|
/// createHexagonISelDag - This pass converts a legalized DAG into a
|
|
/// Hexagon-specific DAG, ready for instruction scheduling.
|
|
///
|
|
FunctionPass *llvm::createHexagonISelDag(HexagonTargetMachine &TM) {
|
|
return new HexagonDAGToDAGISel(TM);
|
|
}
|
|
|
|
static bool IsS11_0_Offset(SDNode * S) {
|
|
ConstantSDNode *N = cast<ConstantSDNode>(S);
|
|
|
|
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
|
|
// field.
|
|
int64_t v = (int64_t)N->getSExtValue();
|
|
return isInt<11>(v);
|
|
}
|
|
|
|
|
|
static bool IsS11_1_Offset(SDNode * S) {
|
|
ConstantSDNode *N = cast<ConstantSDNode>(S);
|
|
|
|
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
|
|
// field.
|
|
int64_t v = (int64_t)N->getSExtValue();
|
|
return isShiftedInt<11,1>(v);
|
|
}
|
|
|
|
|
|
static bool IsS11_2_Offset(SDNode * S) {
|
|
ConstantSDNode *N = cast<ConstantSDNode>(S);
|
|
|
|
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
|
|
// field.
|
|
int64_t v = (int64_t)N->getSExtValue();
|
|
return isShiftedInt<11,2>(v);
|
|
}
|
|
|
|
|
|
static bool IsS11_3_Offset(SDNode * S) {
|
|
ConstantSDNode *N = cast<ConstantSDNode>(S);
|
|
|
|
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
|
|
// field.
|
|
int64_t v = (int64_t)N->getSExtValue();
|
|
return isShiftedInt<11,3>(v);
|
|
}
|
|
|
|
|
|
static bool IsU6_0_Offset(SDNode * S) {
|
|
ConstantSDNode *N = cast<ConstantSDNode>(S);
|
|
|
|
// u6 predicate - True if the immediate fits in a 6-bit unsigned extended
|
|
// field.
|
|
int64_t v = (int64_t)N->getSExtValue();
|
|
return isUInt<6>(v);
|
|
}
|
|
|
|
|
|
static bool IsU6_1_Offset(SDNode * S) {
|
|
ConstantSDNode *N = cast<ConstantSDNode>(S);
|
|
|
|
// u6 predicate - True if the immediate fits in a 6-bit unsigned extended
|
|
// field.
|
|
int64_t v = (int64_t)N->getSExtValue();
|
|
return isShiftedUInt<6,1>(v);
|
|
}
|
|
|
|
|
|
static bool IsU6_2_Offset(SDNode * S) {
|
|
ConstantSDNode *N = cast<ConstantSDNode>(S);
|
|
|
|
// u6 predicate - True if the immediate fits in a 6-bit unsigned extended
|
|
// field.
|
|
int64_t v = (int64_t)N->getSExtValue();
|
|
return isShiftedUInt<6,2>(v);
|
|
}
|
|
|
|
|
|
// Intrinsics that return a a predicate.
|
|
static unsigned doesIntrinsicReturnPredicate(unsigned ID)
|
|
{
|
|
switch (ID) {
|
|
default:
|
|
return 0;
|
|
case Intrinsic::hexagon_C2_cmpeq:
|
|
case Intrinsic::hexagon_C2_cmpgt:
|
|
case Intrinsic::hexagon_C2_cmpgtu:
|
|
case Intrinsic::hexagon_C2_cmpgtup:
|
|
case Intrinsic::hexagon_C2_cmpgtp:
|
|
case Intrinsic::hexagon_C2_cmpeqp:
|
|
case Intrinsic::hexagon_C2_bitsset:
|
|
case Intrinsic::hexagon_C2_bitsclr:
|
|
case Intrinsic::hexagon_C2_cmpeqi:
|
|
case Intrinsic::hexagon_C2_cmpgti:
|
|
case Intrinsic::hexagon_C2_cmpgtui:
|
|
case Intrinsic::hexagon_C2_cmpgei:
|
|
case Intrinsic::hexagon_C2_cmpgeui:
|
|
case Intrinsic::hexagon_C2_cmplt:
|
|
case Intrinsic::hexagon_C2_cmpltu:
|
|
case Intrinsic::hexagon_C2_bitsclri:
|
|
case Intrinsic::hexagon_C2_and:
|
|
case Intrinsic::hexagon_C2_or:
|
|
case Intrinsic::hexagon_C2_xor:
|
|
case Intrinsic::hexagon_C2_andn:
|
|
case Intrinsic::hexagon_C2_not:
|
|
case Intrinsic::hexagon_C2_orn:
|
|
case Intrinsic::hexagon_C2_pxfer_map:
|
|
case Intrinsic::hexagon_C2_any8:
|
|
case Intrinsic::hexagon_C2_all8:
|
|
case Intrinsic::hexagon_A2_vcmpbeq:
|
|
case Intrinsic::hexagon_A2_vcmpbgtu:
|
|
case Intrinsic::hexagon_A2_vcmpheq:
|
|
case Intrinsic::hexagon_A2_vcmphgt:
|
|
case Intrinsic::hexagon_A2_vcmphgtu:
|
|
case Intrinsic::hexagon_A2_vcmpweq:
|
|
case Intrinsic::hexagon_A2_vcmpwgt:
|
|
case Intrinsic::hexagon_A2_vcmpwgtu:
|
|
case Intrinsic::hexagon_C2_tfrrp:
|
|
case Intrinsic::hexagon_S2_tstbit_i:
|
|
case Intrinsic::hexagon_S2_tstbit_r:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
// Intrinsics that have predicate operands.
|
|
static unsigned doesIntrinsicContainPredicate(unsigned ID)
|
|
{
|
|
switch (ID) {
|
|
default:
|
|
return 0;
|
|
case Intrinsic::hexagon_C2_tfrpr:
|
|
return Hexagon::TFR_RsPd;
|
|
case Intrinsic::hexagon_C2_and:
|
|
return Hexagon::AND_pp;
|
|
case Intrinsic::hexagon_C2_xor:
|
|
return Hexagon::XOR_pp;
|
|
case Intrinsic::hexagon_C2_or:
|
|
return Hexagon::OR_pp;
|
|
case Intrinsic::hexagon_C2_not:
|
|
return Hexagon::NOT_p;
|
|
case Intrinsic::hexagon_C2_any8:
|
|
return Hexagon::ANY_pp;
|
|
case Intrinsic::hexagon_C2_all8:
|
|
return Hexagon::ALL_pp;
|
|
case Intrinsic::hexagon_C2_vitpack:
|
|
return Hexagon::VITPACK_pp;
|
|
case Intrinsic::hexagon_C2_mask:
|
|
return Hexagon::MASK_p;
|
|
case Intrinsic::hexagon_C2_mux:
|
|
return Hexagon::MUX_rr;
|
|
|
|
// Mapping hexagon_C2_muxir to MUX_pri. This is pretty weird - but
|
|
// that's how it's mapped in q6protos.h.
|
|
case Intrinsic::hexagon_C2_muxir:
|
|
return Hexagon::MUX_ri;
|
|
|
|
// Mapping hexagon_C2_muxri to MUX_pir. This is pretty weird - but
|
|
// that's how it's mapped in q6protos.h.
|
|
case Intrinsic::hexagon_C2_muxri:
|
|
return Hexagon::MUX_ir;
|
|
|
|
case Intrinsic::hexagon_C2_muxii:
|
|
return Hexagon::MUX_ii;
|
|
case Intrinsic::hexagon_C2_vmux:
|
|
return Hexagon::VMUX_prr64;
|
|
case Intrinsic::hexagon_S2_valignrb:
|
|
return Hexagon::VALIGN_rrp;
|
|
case Intrinsic::hexagon_S2_vsplicerb:
|
|
return Hexagon::VSPLICE_rrp;
|
|
}
|
|
}
|
|
|
|
|
|
static bool OffsetFitsS11(EVT MemType, int64_t Offset) {
|
|
if (MemType == MVT::i64 && isShiftedInt<11,3>(Offset)) {
|
|
return true;
|
|
}
|
|
if (MemType == MVT::i32 && isShiftedInt<11,2>(Offset)) {
|
|
return true;
|
|
}
|
|
if (MemType == MVT::i16 && isShiftedInt<11,1>(Offset)) {
|
|
return true;
|
|
}
|
|
if (MemType == MVT::i8 && isInt<11>(Offset)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
//
|
|
// Try to lower loads of GlobalAdresses into base+offset loads. Custom
|
|
// lowering for GlobalAddress nodes has already turned it into a
|
|
// CONST32.
|
|
//
|
|
SDNode *HexagonDAGToDAGISel::SelectBaseOffsetLoad(LoadSDNode *LD, DebugLoc dl) {
|
|
SDValue Chain = LD->getChain();
|
|
SDNode* Const32 = LD->getBasePtr().getNode();
|
|
unsigned Opcode = 0;
|
|
|
|
if (Const32->getOpcode() == HexagonISD::CONST32 &&
|
|
ISD::isNormalLoad(LD)) {
|
|
SDValue Base = Const32->getOperand(0);
|
|
EVT LoadedVT = LD->getMemoryVT();
|
|
int64_t Offset = cast<GlobalAddressSDNode>(Base)->getOffset();
|
|
if (Offset != 0 && OffsetFitsS11(LoadedVT, Offset)) {
|
|
MVT PointerTy = TLI.getPointerTy();
|
|
const GlobalValue* GV =
|
|
cast<GlobalAddressSDNode>(Base)->getGlobal();
|
|
SDValue TargAddr =
|
|
CurDAG->getTargetGlobalAddress(GV, dl, PointerTy, 0);
|
|
SDNode* NewBase = CurDAG->getMachineNode(Hexagon::CONST32_set,
|
|
dl, PointerTy,
|
|
TargAddr);
|
|
// Figure out base + offset opcode
|
|
if (LoadedVT == MVT::i64) Opcode = Hexagon::LDrid_indexed;
|
|
else if (LoadedVT == MVT::i32) Opcode = Hexagon::LDriw_indexed;
|
|
else if (LoadedVT == MVT::i16) Opcode = Hexagon::LDrih_indexed;
|
|
else if (LoadedVT == MVT::i8) Opcode = Hexagon::LDrib_indexed;
|
|
else llvm_unreachable("unknown memory type");
|
|
|
|
// Build indexed load.
|
|
SDValue TargetConstOff = CurDAG->getTargetConstant(Offset, PointerTy);
|
|
SDNode* Result = CurDAG->getMachineNode(Opcode, dl,
|
|
LD->getValueType(0),
|
|
MVT::Other,
|
|
SDValue(NewBase,0),
|
|
TargetConstOff,
|
|
Chain);
|
|
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
|
|
MemOp[0] = LD->getMemOperand();
|
|
cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1);
|
|
ReplaceUses(LD, Result);
|
|
return Result;
|
|
}
|
|
}
|
|
|
|
return SelectCode(LD);
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectIndexedLoadSignExtend64(LoadSDNode *LD,
|
|
unsigned Opcode,
|
|
DebugLoc dl)
|
|
{
|
|
SDValue Chain = LD->getChain();
|
|
EVT LoadedVT = LD->getMemoryVT();
|
|
SDValue Base = LD->getBasePtr();
|
|
SDValue Offset = LD->getOffset();
|
|
SDNode *OffsetNode = Offset.getNode();
|
|
int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue();
|
|
SDValue N1 = LD->getOperand(1);
|
|
SDValue CPTmpN1_0;
|
|
SDValue CPTmpN1_1;
|
|
if (SelectADDRriS11_2(N1, CPTmpN1_0, CPTmpN1_1) &&
|
|
N1.getNode()->getValueType(0) == MVT::i32) {
|
|
if (TII->isValidAutoIncImm(LoadedVT, Val)) {
|
|
SDValue TargetConst = CurDAG->getTargetConstant(Val, MVT::i32);
|
|
SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::i32,
|
|
MVT::Other, Base, TargetConst,
|
|
Chain);
|
|
SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::SXTW, dl, MVT::i64,
|
|
SDValue(Result_1, 0));
|
|
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
|
|
MemOp[0] = LD->getMemOperand();
|
|
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
|
|
const SDValue Froms[] = { SDValue(LD, 0),
|
|
SDValue(LD, 1),
|
|
SDValue(LD, 2)
|
|
};
|
|
const SDValue Tos[] = { SDValue(Result_2, 0),
|
|
SDValue(Result_1, 1),
|
|
SDValue(Result_1, 2)
|
|
};
|
|
ReplaceUses(Froms, Tos, 3);
|
|
return Result_2;
|
|
}
|
|
SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32);
|
|
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32);
|
|
SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32,
|
|
MVT::Other, Base, TargetConst0,
|
|
Chain);
|
|
SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::SXTW, dl,
|
|
MVT::i64, SDValue(Result_1, 0));
|
|
SDNode* Result_3 = CurDAG->getMachineNode(Hexagon::ADD_ri, dl,
|
|
MVT::i32, Base, TargetConstVal,
|
|
SDValue(Result_1, 1));
|
|
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
|
|
MemOp[0] = LD->getMemOperand();
|
|
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
|
|
const SDValue Froms[] = { SDValue(LD, 0),
|
|
SDValue(LD, 1),
|
|
SDValue(LD, 2)
|
|
};
|
|
const SDValue Tos[] = { SDValue(Result_2, 0),
|
|
SDValue(Result_3, 0),
|
|
SDValue(Result_1, 1)
|
|
};
|
|
ReplaceUses(Froms, Tos, 3);
|
|
return Result_2;
|
|
}
|
|
return SelectCode(LD);
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectIndexedLoadZeroExtend64(LoadSDNode *LD,
|
|
unsigned Opcode,
|
|
DebugLoc dl)
|
|
{
|
|
SDValue Chain = LD->getChain();
|
|
EVT LoadedVT = LD->getMemoryVT();
|
|
SDValue Base = LD->getBasePtr();
|
|
SDValue Offset = LD->getOffset();
|
|
SDNode *OffsetNode = Offset.getNode();
|
|
int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue();
|
|
SDValue N1 = LD->getOperand(1);
|
|
SDValue CPTmpN1_0;
|
|
SDValue CPTmpN1_1;
|
|
if (SelectADDRriS11_2(N1, CPTmpN1_0, CPTmpN1_1) &&
|
|
N1.getNode()->getValueType(0) == MVT::i32) {
|
|
if (TII->isValidAutoIncImm(LoadedVT, Val)) {
|
|
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32);
|
|
SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32);
|
|
SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32,
|
|
MVT::i32, MVT::Other, Base,
|
|
TargetConstVal, Chain);
|
|
SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::TFRI, dl, MVT::i32,
|
|
TargetConst0);
|
|
SDNode *Result_3 = CurDAG->getMachineNode(Hexagon::COMBINE_rr, dl,
|
|
MVT::i64, MVT::Other,
|
|
SDValue(Result_2,0),
|
|
SDValue(Result_1,0));
|
|
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
|
|
MemOp[0] = LD->getMemOperand();
|
|
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
|
|
const SDValue Froms[] = { SDValue(LD, 0),
|
|
SDValue(LD, 1),
|
|
SDValue(LD, 2)
|
|
};
|
|
const SDValue Tos[] = { SDValue(Result_3, 0),
|
|
SDValue(Result_1, 1),
|
|
SDValue(Result_1, 2)
|
|
};
|
|
ReplaceUses(Froms, Tos, 3);
|
|
return Result_3;
|
|
}
|
|
|
|
// Generate an indirect load.
|
|
SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32);
|
|
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32);
|
|
SDNode *Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::i32,
|
|
MVT::Other,
|
|
Base, TargetConst0, Chain);
|
|
SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::TFRI, dl, MVT::i32,
|
|
TargetConst0);
|
|
SDNode *Result_3 = CurDAG->getMachineNode(Hexagon::COMBINE_rr, dl,
|
|
MVT::i64, MVT::Other,
|
|
SDValue(Result_2,0),
|
|
SDValue(Result_1,0));
|
|
// Add offset to base.
|
|
SDNode* Result_4 = CurDAG->getMachineNode(Hexagon::ADD_ri, dl, MVT::i32,
|
|
Base, TargetConstVal,
|
|
SDValue(Result_1, 1));
|
|
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
|
|
MemOp[0] = LD->getMemOperand();
|
|
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
|
|
const SDValue Froms[] = { SDValue(LD, 0),
|
|
SDValue(LD, 1),
|
|
SDValue(LD, 2)
|
|
};
|
|
const SDValue Tos[] = { SDValue(Result_3, 0), // Load value.
|
|
SDValue(Result_4, 0), // New address.
|
|
SDValue(Result_1, 1)
|
|
};
|
|
ReplaceUses(Froms, Tos, 3);
|
|
return Result_3;
|
|
}
|
|
|
|
return SelectCode(LD);
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectIndexedLoad(LoadSDNode *LD, DebugLoc dl) {
|
|
SDValue Chain = LD->getChain();
|
|
SDValue Base = LD->getBasePtr();
|
|
SDValue Offset = LD->getOffset();
|
|
SDNode *OffsetNode = Offset.getNode();
|
|
// Get the constant value.
|
|
int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue();
|
|
EVT LoadedVT = LD->getMemoryVT();
|
|
unsigned Opcode = 0;
|
|
|
|
// Check for zero ext loads.
|
|
bool zextval = (LD->getExtensionType() == ISD::ZEXTLOAD);
|
|
|
|
// Figure out the opcode.
|
|
if (LoadedVT == MVT::i64) {
|
|
if (TII->isValidAutoIncImm(LoadedVT, Val))
|
|
Opcode = Hexagon::POST_LDrid;
|
|
else
|
|
Opcode = Hexagon::LDrid;
|
|
} else if (LoadedVT == MVT::i32) {
|
|
if (TII->isValidAutoIncImm(LoadedVT, Val))
|
|
Opcode = Hexagon::POST_LDriw;
|
|
else
|
|
Opcode = Hexagon::LDriw;
|
|
} else if (LoadedVT == MVT::i16) {
|
|
if (TII->isValidAutoIncImm(LoadedVT, Val))
|
|
Opcode = zextval ? Hexagon::POST_LDriuh : Hexagon::POST_LDrih;
|
|
else
|
|
Opcode = zextval ? Hexagon::LDriuh : Hexagon::LDrih;
|
|
} else if (LoadedVT == MVT::i8) {
|
|
if (TII->isValidAutoIncImm(LoadedVT, Val))
|
|
Opcode = zextval ? Hexagon::POST_LDriub : Hexagon::POST_LDrib;
|
|
else
|
|
Opcode = zextval ? Hexagon::LDriub : Hexagon::LDrib;
|
|
} else
|
|
llvm_unreachable("unknown memory type");
|
|
|
|
// For zero ext i64 loads, we need to add combine instructions.
|
|
if (LD->getValueType(0) == MVT::i64 &&
|
|
LD->getExtensionType() == ISD::ZEXTLOAD) {
|
|
return SelectIndexedLoadZeroExtend64(LD, Opcode, dl);
|
|
}
|
|
if (LD->getValueType(0) == MVT::i64 &&
|
|
LD->getExtensionType() == ISD::SEXTLOAD) {
|
|
// Handle sign ext i64 loads.
|
|
return SelectIndexedLoadSignExtend64(LD, Opcode, dl);
|
|
}
|
|
if (TII->isValidAutoIncImm(LoadedVT, Val)) {
|
|
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32);
|
|
SDNode* Result = CurDAG->getMachineNode(Opcode, dl,
|
|
LD->getValueType(0),
|
|
MVT::i32, MVT::Other, Base,
|
|
TargetConstVal, Chain);
|
|
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
|
|
MemOp[0] = LD->getMemOperand();
|
|
cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1);
|
|
const SDValue Froms[] = { SDValue(LD, 0),
|
|
SDValue(LD, 1),
|
|
SDValue(LD, 2)
|
|
};
|
|
const SDValue Tos[] = { SDValue(Result, 0),
|
|
SDValue(Result, 1),
|
|
SDValue(Result, 2)
|
|
};
|
|
ReplaceUses(Froms, Tos, 3);
|
|
return Result;
|
|
} else {
|
|
SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32);
|
|
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32);
|
|
SDNode* Result_1 = CurDAG->getMachineNode(Opcode, dl,
|
|
LD->getValueType(0),
|
|
MVT::Other, Base, TargetConst0,
|
|
Chain);
|
|
SDNode* Result_2 = CurDAG->getMachineNode(Hexagon::ADD_ri, dl, MVT::i32,
|
|
Base, TargetConstVal,
|
|
SDValue(Result_1, 1));
|
|
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
|
|
MemOp[0] = LD->getMemOperand();
|
|
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
|
|
const SDValue Froms[] = { SDValue(LD, 0),
|
|
SDValue(LD, 1),
|
|
SDValue(LD, 2)
|
|
};
|
|
const SDValue Tos[] = { SDValue(Result_1, 0),
|
|
SDValue(Result_2, 0),
|
|
SDValue(Result_1, 1)
|
|
};
|
|
ReplaceUses(Froms, Tos, 3);
|
|
return Result_1;
|
|
}
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectLoad(SDNode *N) {
|
|
SDNode *result;
|
|
DebugLoc dl = N->getDebugLoc();
|
|
LoadSDNode *LD = cast<LoadSDNode>(N);
|
|
ISD::MemIndexedMode AM = LD->getAddressingMode();
|
|
|
|
// Handle indexed loads.
|
|
if (AM != ISD::UNINDEXED) {
|
|
result = SelectIndexedLoad(LD, dl);
|
|
} else {
|
|
result = SelectBaseOffsetLoad(LD, dl);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectIndexedStore(StoreSDNode *ST, DebugLoc dl) {
|
|
SDValue Chain = ST->getChain();
|
|
SDValue Base = ST->getBasePtr();
|
|
SDValue Offset = ST->getOffset();
|
|
SDValue Value = ST->getValue();
|
|
SDNode *OffsetNode = Offset.getNode();
|
|
// Get the constant value.
|
|
int32_t Val = cast<ConstantSDNode>(OffsetNode)->getSExtValue();
|
|
EVT StoredVT = ST->getMemoryVT();
|
|
|
|
// Offset value must be within representable range
|
|
// and must have correct alignment properties.
|
|
if (TII->isValidAutoIncImm(StoredVT, Val)) {
|
|
SDValue Ops[] = { Value, Base,
|
|
CurDAG->getTargetConstant(Val, MVT::i32), Chain};
|
|
unsigned Opcode = 0;
|
|
|
|
// Figure out the post inc version of opcode.
|
|
if (StoredVT == MVT::i64) Opcode = Hexagon::POST_STdri;
|
|
else if (StoredVT == MVT::i32) Opcode = Hexagon::POST_STwri;
|
|
else if (StoredVT == MVT::i16) Opcode = Hexagon::POST_SThri;
|
|
else if (StoredVT == MVT::i8) Opcode = Hexagon::POST_STbri;
|
|
else llvm_unreachable("unknown memory type");
|
|
|
|
// Build post increment store.
|
|
SDNode* Result = CurDAG->getMachineNode(Opcode, dl, MVT::i32,
|
|
MVT::Other, Ops, 4);
|
|
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
|
|
MemOp[0] = ST->getMemOperand();
|
|
cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1);
|
|
|
|
ReplaceUses(ST, Result);
|
|
ReplaceUses(SDValue(ST,1), SDValue(Result,1));
|
|
return Result;
|
|
}
|
|
|
|
// Note: Order of operands matches the def of instruction:
|
|
// def STrid : STInst<(outs), (ins MEMri:$addr, DoubleRegs:$src1), ...
|
|
// and it differs for POST_ST* for instance.
|
|
SDValue Ops[] = { Base, CurDAG->getTargetConstant(0, MVT::i32), Value,
|
|
Chain};
|
|
unsigned Opcode = 0;
|
|
|
|
// Figure out the opcode.
|
|
if (StoredVT == MVT::i64) Opcode = Hexagon::STrid;
|
|
else if (StoredVT == MVT::i32) Opcode = Hexagon::STriw_indexed;
|
|
else if (StoredVT == MVT::i16) Opcode = Hexagon::STrih;
|
|
else if (StoredVT == MVT::i8) Opcode = Hexagon::STrib;
|
|
else llvm_unreachable("unknown memory type");
|
|
|
|
// Build regular store.
|
|
SDValue TargetConstVal = CurDAG->getTargetConstant(Val, MVT::i32);
|
|
SDNode* Result_1 = CurDAG->getMachineNode(Opcode, dl, MVT::Other, Ops,
|
|
4);
|
|
// Build splitted incriment instruction.
|
|
SDNode* Result_2 = CurDAG->getMachineNode(Hexagon::ADD_ri, dl, MVT::i32,
|
|
Base,
|
|
TargetConstVal,
|
|
SDValue(Result_1, 0));
|
|
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
|
|
MemOp[0] = ST->getMemOperand();
|
|
cast<MachineSDNode>(Result_1)->setMemRefs(MemOp, MemOp + 1);
|
|
|
|
ReplaceUses(SDValue(ST,0), SDValue(Result_2,0));
|
|
ReplaceUses(SDValue(ST,1), SDValue(Result_1,0));
|
|
return Result_2;
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectBaseOffsetStore(StoreSDNode *ST,
|
|
DebugLoc dl) {
|
|
SDValue Chain = ST->getChain();
|
|
SDNode* Const32 = ST->getBasePtr().getNode();
|
|
SDValue Value = ST->getValue();
|
|
unsigned Opcode = 0;
|
|
|
|
// Try to lower stores of GlobalAdresses into indexed stores. Custom
|
|
// lowering for GlobalAddress nodes has already turned it into a
|
|
// CONST32. Avoid truncating stores for the moment. Post-inc stores
|
|
// do the same. Don't think there's a reason for it, so will file a
|
|
// bug to fix.
|
|
if ((Const32->getOpcode() == HexagonISD::CONST32) &&
|
|
!(Value.getValueType() == MVT::i64 && ST->isTruncatingStore())) {
|
|
SDValue Base = Const32->getOperand(0);
|
|
if (Base.getOpcode() == ISD::TargetGlobalAddress) {
|
|
EVT StoredVT = ST->getMemoryVT();
|
|
int64_t Offset = cast<GlobalAddressSDNode>(Base)->getOffset();
|
|
if (Offset != 0 && OffsetFitsS11(StoredVT, Offset)) {
|
|
MVT PointerTy = TLI.getPointerTy();
|
|
const GlobalValue* GV =
|
|
cast<GlobalAddressSDNode>(Base)->getGlobal();
|
|
SDValue TargAddr =
|
|
CurDAG->getTargetGlobalAddress(GV, dl, PointerTy, 0);
|
|
SDNode* NewBase = CurDAG->getMachineNode(Hexagon::CONST32_set,
|
|
dl, PointerTy,
|
|
TargAddr);
|
|
|
|
// Figure out base + offset opcode
|
|
if (StoredVT == MVT::i64) Opcode = Hexagon::STrid_indexed;
|
|
else if (StoredVT == MVT::i32) Opcode = Hexagon::STriw_indexed;
|
|
else if (StoredVT == MVT::i16) Opcode = Hexagon::STrih_indexed;
|
|
else if (StoredVT == MVT::i8) Opcode = Hexagon::STrib_indexed;
|
|
else llvm_unreachable("unknown memory type");
|
|
|
|
SDValue Ops[] = {SDValue(NewBase,0),
|
|
CurDAG->getTargetConstant(Offset,PointerTy),
|
|
Value, Chain};
|
|
// build indexed store
|
|
SDNode* Result = CurDAG->getMachineNode(Opcode, dl,
|
|
MVT::Other, Ops, 4);
|
|
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
|
|
MemOp[0] = ST->getMemOperand();
|
|
cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1);
|
|
ReplaceUses(ST, Result);
|
|
return Result;
|
|
}
|
|
}
|
|
}
|
|
|
|
return SelectCode(ST);
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectStore(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
StoreSDNode *ST = cast<StoreSDNode>(N);
|
|
ISD::MemIndexedMode AM = ST->getAddressingMode();
|
|
|
|
// Handle indexed stores.
|
|
if (AM != ISD::UNINDEXED) {
|
|
return SelectIndexedStore(ST, dl);
|
|
}
|
|
|
|
return SelectBaseOffsetStore(ST, dl);
|
|
}
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectMul(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
|
|
//
|
|
// %conv.i = sext i32 %tmp1 to i64
|
|
// %conv2.i = sext i32 %add to i64
|
|
// %mul.i = mul nsw i64 %conv2.i, %conv.i
|
|
//
|
|
// --- match with the following ---
|
|
//
|
|
// %mul.i = mpy (%tmp1, %add)
|
|
//
|
|
|
|
if (N->getValueType(0) == MVT::i64) {
|
|
// Shifting a i64 signed multiply.
|
|
SDValue MulOp0 = N->getOperand(0);
|
|
SDValue MulOp1 = N->getOperand(1);
|
|
|
|
SDValue OP0;
|
|
SDValue OP1;
|
|
|
|
// Handle sign_extend and sextload.
|
|
if (MulOp0.getOpcode() == ISD::SIGN_EXTEND) {
|
|
SDValue Sext0 = MulOp0.getOperand(0);
|
|
if (Sext0.getNode()->getValueType(0) != MVT::i32) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
OP0 = Sext0;
|
|
} else if (MulOp0.getOpcode() == ISD::LOAD) {
|
|
LoadSDNode *LD = cast<LoadSDNode>(MulOp0.getNode());
|
|
if (LD->getMemoryVT() != MVT::i32 ||
|
|
LD->getExtensionType() != ISD::SEXTLOAD ||
|
|
LD->getAddressingMode() != ISD::UNINDEXED) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
SDValue Chain = LD->getChain();
|
|
SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32);
|
|
OP0 = SDValue (CurDAG->getMachineNode(Hexagon::LDriw, dl, MVT::i32,
|
|
MVT::Other,
|
|
LD->getBasePtr(), TargetConst0,
|
|
Chain), 0);
|
|
} else {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
// Same goes for the second operand.
|
|
if (MulOp1.getOpcode() == ISD::SIGN_EXTEND) {
|
|
SDValue Sext1 = MulOp1.getOperand(0);
|
|
if (Sext1.getNode()->getValueType(0) != MVT::i32) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
OP1 = Sext1;
|
|
} else if (MulOp1.getOpcode() == ISD::LOAD) {
|
|
LoadSDNode *LD = cast<LoadSDNode>(MulOp1.getNode());
|
|
if (LD->getMemoryVT() != MVT::i32 ||
|
|
LD->getExtensionType() != ISD::SEXTLOAD ||
|
|
LD->getAddressingMode() != ISD::UNINDEXED) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
SDValue Chain = LD->getChain();
|
|
SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32);
|
|
OP1 = SDValue (CurDAG->getMachineNode(Hexagon::LDriw, dl, MVT::i32,
|
|
MVT::Other,
|
|
LD->getBasePtr(), TargetConst0,
|
|
Chain), 0);
|
|
} else {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
// Generate a mpy instruction.
|
|
SDNode *Result = CurDAG->getMachineNode(Hexagon::MPY64, dl, MVT::i64,
|
|
OP0, OP1);
|
|
ReplaceUses(N, Result);
|
|
return Result;
|
|
}
|
|
|
|
return SelectCode(N);
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectSelect(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
SDValue N0 = N->getOperand(0);
|
|
if (N0.getOpcode() == ISD::SETCC) {
|
|
SDValue N00 = N0.getOperand(0);
|
|
if (N00.getOpcode() == ISD::SIGN_EXTEND_INREG) {
|
|
SDValue N000 = N00.getOperand(0);
|
|
SDValue N001 = N00.getOperand(1);
|
|
if (cast<VTSDNode>(N001)->getVT() == MVT::i16) {
|
|
SDValue N01 = N0.getOperand(1);
|
|
SDValue N02 = N0.getOperand(2);
|
|
|
|
// Pattern: (select:i32 (setcc:i1 (sext_inreg:i32 IntRegs:i32:$src2,
|
|
// i16:Other),IntRegs:i32:$src1, SETLT:Other),IntRegs:i32:$src1,
|
|
// IntRegs:i32:$src2)
|
|
// Emits: (MAXh_rr:i32 IntRegs:i32:$src1, IntRegs:i32:$src2)
|
|
// Pattern complexity = 9 cost = 1 size = 0.
|
|
if (cast<CondCodeSDNode>(N02)->get() == ISD::SETLT) {
|
|
SDValue N1 = N->getOperand(1);
|
|
if (N01 == N1) {
|
|
SDValue N2 = N->getOperand(2);
|
|
if (N000 == N2 &&
|
|
N0.getNode()->getValueType(N0.getResNo()) == MVT::i1 &&
|
|
N00.getNode()->getValueType(N00.getResNo()) == MVT::i32) {
|
|
SDNode *SextNode = CurDAG->getMachineNode(Hexagon::SXTH, dl,
|
|
MVT::i32, N000);
|
|
SDNode *Result = CurDAG->getMachineNode(Hexagon::MAXw_rr, dl,
|
|
MVT::i32,
|
|
SDValue(SextNode, 0),
|
|
N1);
|
|
ReplaceUses(N, Result);
|
|
return Result;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pattern: (select:i32 (setcc:i1 (sext_inreg:i32 IntRegs:i32:$src2,
|
|
// i16:Other), IntRegs:i32:$src1, SETGT:Other), IntRegs:i32:$src1,
|
|
// IntRegs:i32:$src2)
|
|
// Emits: (MINh_rr:i32 IntRegs:i32:$src1, IntRegs:i32:$src2)
|
|
// Pattern complexity = 9 cost = 1 size = 0.
|
|
if (cast<CondCodeSDNode>(N02)->get() == ISD::SETGT) {
|
|
SDValue N1 = N->getOperand(1);
|
|
if (N01 == N1) {
|
|
SDValue N2 = N->getOperand(2);
|
|
if (N000 == N2 &&
|
|
N0.getNode()->getValueType(N0.getResNo()) == MVT::i1 &&
|
|
N00.getNode()->getValueType(N00.getResNo()) == MVT::i32) {
|
|
SDNode *SextNode = CurDAG->getMachineNode(Hexagon::SXTH, dl,
|
|
MVT::i32, N000);
|
|
SDNode *Result = CurDAG->getMachineNode(Hexagon::MINw_rr, dl,
|
|
MVT::i32,
|
|
SDValue(SextNode, 0),
|
|
N1);
|
|
ReplaceUses(N, Result);
|
|
return Result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return SelectCode(N);
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectTruncate(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
SDValue Shift = N->getOperand(0);
|
|
|
|
//
|
|
// %conv.i = sext i32 %tmp1 to i64
|
|
// %conv2.i = sext i32 %add to i64
|
|
// %mul.i = mul nsw i64 %conv2.i, %conv.i
|
|
// %shr5.i = lshr i64 %mul.i, 32
|
|
// %conv3.i = trunc i64 %shr5.i to i32
|
|
//
|
|
// --- match with the following ---
|
|
//
|
|
// %conv3.i = mpy (%tmp1, %add)
|
|
//
|
|
// Trunc to i32.
|
|
if (N->getValueType(0) == MVT::i32) {
|
|
// Trunc from i64.
|
|
if (Shift.getNode()->getValueType(0) == MVT::i64) {
|
|
// Trunc child is logical shift right.
|
|
if (Shift.getOpcode() != ISD::SRL) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
SDValue ShiftOp0 = Shift.getOperand(0);
|
|
SDValue ShiftOp1 = Shift.getOperand(1);
|
|
|
|
// Shift by const 32
|
|
if (ShiftOp1.getOpcode() != ISD::Constant) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
int32_t ShiftConst =
|
|
cast<ConstantSDNode>(ShiftOp1.getNode())->getSExtValue();
|
|
if (ShiftConst != 32) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
// Shifting a i64 signed multiply
|
|
SDValue Mul = ShiftOp0;
|
|
if (Mul.getOpcode() != ISD::MUL) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
SDValue MulOp0 = Mul.getOperand(0);
|
|
SDValue MulOp1 = Mul.getOperand(1);
|
|
|
|
SDValue OP0;
|
|
SDValue OP1;
|
|
|
|
// Handle sign_extend and sextload
|
|
if (MulOp0.getOpcode() == ISD::SIGN_EXTEND) {
|
|
SDValue Sext0 = MulOp0.getOperand(0);
|
|
if (Sext0.getNode()->getValueType(0) != MVT::i32) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
OP0 = Sext0;
|
|
} else if (MulOp0.getOpcode() == ISD::LOAD) {
|
|
LoadSDNode *LD = cast<LoadSDNode>(MulOp0.getNode());
|
|
if (LD->getMemoryVT() != MVT::i32 ||
|
|
LD->getExtensionType() != ISD::SEXTLOAD ||
|
|
LD->getAddressingMode() != ISD::UNINDEXED) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
SDValue Chain = LD->getChain();
|
|
SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32);
|
|
OP0 = SDValue (CurDAG->getMachineNode(Hexagon::LDriw, dl, MVT::i32,
|
|
MVT::Other,
|
|
LD->getBasePtr(),
|
|
TargetConst0, Chain), 0);
|
|
} else {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
// Same goes for the second operand.
|
|
if (MulOp1.getOpcode() == ISD::SIGN_EXTEND) {
|
|
SDValue Sext1 = MulOp1.getOperand(0);
|
|
if (Sext1.getNode()->getValueType(0) != MVT::i32)
|
|
return SelectCode(N);
|
|
|
|
OP1 = Sext1;
|
|
} else if (MulOp1.getOpcode() == ISD::LOAD) {
|
|
LoadSDNode *LD = cast<LoadSDNode>(MulOp1.getNode());
|
|
if (LD->getMemoryVT() != MVT::i32 ||
|
|
LD->getExtensionType() != ISD::SEXTLOAD ||
|
|
LD->getAddressingMode() != ISD::UNINDEXED) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
SDValue Chain = LD->getChain();
|
|
SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32);
|
|
OP1 = SDValue (CurDAG->getMachineNode(Hexagon::LDriw, dl, MVT::i32,
|
|
MVT::Other,
|
|
LD->getBasePtr(),
|
|
TargetConst0, Chain), 0);
|
|
} else {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
// Generate a mpy instruction.
|
|
SDNode *Result = CurDAG->getMachineNode(Hexagon::MPY, dl, MVT::i32,
|
|
OP0, OP1);
|
|
ReplaceUses(N, Result);
|
|
return Result;
|
|
}
|
|
}
|
|
|
|
return SelectCode(N);
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::SelectSHL(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
if (N->getValueType(0) == MVT::i32) {
|
|
SDValue Shl_0 = N->getOperand(0);
|
|
SDValue Shl_1 = N->getOperand(1);
|
|
// RHS is const.
|
|
if (Shl_1.getOpcode() == ISD::Constant) {
|
|
if (Shl_0.getOpcode() == ISD::MUL) {
|
|
SDValue Mul_0 = Shl_0.getOperand(0); // Val
|
|
SDValue Mul_1 = Shl_0.getOperand(1); // Const
|
|
// RHS of mul is const.
|
|
if (Mul_1.getOpcode() == ISD::Constant) {
|
|
int32_t ShlConst =
|
|
cast<ConstantSDNode>(Shl_1.getNode())->getSExtValue();
|
|
int32_t MulConst =
|
|
cast<ConstantSDNode>(Mul_1.getNode())->getSExtValue();
|
|
int32_t ValConst = MulConst << ShlConst;
|
|
SDValue Val = CurDAG->getTargetConstant(ValConst,
|
|
MVT::i32);
|
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Val.getNode()))
|
|
if (isInt<9>(CN->getSExtValue())) {
|
|
SDNode* Result =
|
|
CurDAG->getMachineNode(Hexagon::MPYI_ri, dl,
|
|
MVT::i32, Mul_0, Val);
|
|
ReplaceUses(N, Result);
|
|
return Result;
|
|
}
|
|
|
|
}
|
|
} else if (Shl_0.getOpcode() == ISD::SUB) {
|
|
SDValue Sub_0 = Shl_0.getOperand(0); // Const 0
|
|
SDValue Sub_1 = Shl_0.getOperand(1); // Val
|
|
if (Sub_0.getOpcode() == ISD::Constant) {
|
|
int32_t SubConst =
|
|
cast<ConstantSDNode>(Sub_0.getNode())->getSExtValue();
|
|
if (SubConst == 0) {
|
|
if (Sub_1.getOpcode() == ISD::SHL) {
|
|
SDValue Shl2_0 = Sub_1.getOperand(0); // Val
|
|
SDValue Shl2_1 = Sub_1.getOperand(1); // Const
|
|
if (Shl2_1.getOpcode() == ISD::Constant) {
|
|
int32_t ShlConst =
|
|
cast<ConstantSDNode>(Shl_1.getNode())->getSExtValue();
|
|
int32_t Shl2Const =
|
|
cast<ConstantSDNode>(Shl2_1.getNode())->getSExtValue();
|
|
int32_t ValConst = 1 << (ShlConst+Shl2Const);
|
|
SDValue Val = CurDAG->getTargetConstant(-ValConst, MVT::i32);
|
|
if (ConstantSDNode *CN =
|
|
dyn_cast<ConstantSDNode>(Val.getNode()))
|
|
if (isInt<9>(CN->getSExtValue())) {
|
|
SDNode* Result =
|
|
CurDAG->getMachineNode(Hexagon::MPYI_ri, dl, MVT::i32,
|
|
Shl2_0, Val);
|
|
ReplaceUses(N, Result);
|
|
return Result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return SelectCode(N);
|
|
}
|
|
|
|
|
|
//
|
|
// If there is an zero_extend followed an intrinsic in DAG (this means - the
|
|
// result of the intrinsic is predicate); convert the zero_extend to
|
|
// transfer instruction.
|
|
//
|
|
// Zero extend -> transfer is lowered here. Otherwise, zero_extend will be
|
|
// converted into a MUX as predicate registers defined as 1 bit in the
|
|
// compiler. Architecture defines them as 8-bit registers.
|
|
// We want to preserve all the lower 8-bits and, not just 1 LSB bit.
|
|
//
|
|
SDNode *HexagonDAGToDAGISel::SelectZeroExtend(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
SDNode *IsIntrinsic = N->getOperand(0).getNode();
|
|
if ((IsIntrinsic->getOpcode() == ISD::INTRINSIC_WO_CHAIN)) {
|
|
unsigned ID =
|
|
cast<ConstantSDNode>(IsIntrinsic->getOperand(0))->getZExtValue();
|
|
if (doesIntrinsicReturnPredicate(ID)) {
|
|
// Now we need to differentiate target data types.
|
|
if (N->getValueType(0) == MVT::i64) {
|
|
// Convert the zero_extend to Rs = Pd followed by COMBINE_rr(0,Rs).
|
|
SDValue TargetConst0 = CurDAG->getTargetConstant(0, MVT::i32);
|
|
SDNode *Result_1 = CurDAG->getMachineNode(Hexagon::TFR_RsPd, dl,
|
|
MVT::i32,
|
|
SDValue(IsIntrinsic, 0));
|
|
SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::TFRI, dl,
|
|
MVT::i32,
|
|
TargetConst0);
|
|
SDNode *Result_3 = CurDAG->getMachineNode(Hexagon::COMBINE_rr, dl,
|
|
MVT::i64, MVT::Other,
|
|
SDValue(Result_2, 0),
|
|
SDValue(Result_1, 0));
|
|
ReplaceUses(N, Result_3);
|
|
return Result_3;
|
|
}
|
|
if (N->getValueType(0) == MVT::i32) {
|
|
// Convert the zero_extend to Rs = Pd
|
|
SDNode* RsPd = CurDAG->getMachineNode(Hexagon::TFR_RsPd, dl,
|
|
MVT::i32,
|
|
SDValue(IsIntrinsic, 0));
|
|
ReplaceUses(N, RsPd);
|
|
return RsPd;
|
|
}
|
|
llvm_unreachable("Unexpected value type");
|
|
}
|
|
}
|
|
return SelectCode(N);
|
|
}
|
|
|
|
|
|
//
|
|
// Checking for intrinsics which have predicate registers as operand(s)
|
|
// and lowering to the actual intrinsic.
|
|
//
|
|
SDNode *HexagonDAGToDAGISel::SelectIntrinsicWOChain(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
unsigned ID = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue();
|
|
unsigned IntrinsicWithPred = doesIntrinsicContainPredicate(ID);
|
|
|
|
// We are concerned with only those intrinsics that have predicate registers
|
|
// as at least one of the operands.
|
|
if (IntrinsicWithPred) {
|
|
SmallVector<SDValue, 8> Ops;
|
|
const MCInstrDesc &MCID = TII->get(IntrinsicWithPred);
|
|
const TargetRegisterInfo *TRI = TM.getRegisterInfo();
|
|
|
|
// Iterate over all the operands of the intrinsics.
|
|
// For PredRegs, do the transfer.
|
|
// For Double/Int Regs, just preserve the value
|
|
// For immediates, lower it.
|
|
for (unsigned i = 1; i < N->getNumOperands(); ++i) {
|
|
SDNode *Arg = N->getOperand(i).getNode();
|
|
const TargetRegisterClass *RC = TII->getRegClass(MCID, i, TRI, *MF);
|
|
|
|
if (RC == &Hexagon::IntRegsRegClass ||
|
|
RC == &Hexagon::DoubleRegsRegClass) {
|
|
Ops.push_back(SDValue(Arg, 0));
|
|
} else if (RC == &Hexagon::PredRegsRegClass) {
|
|
// Do the transfer.
|
|
SDNode *PdRs = CurDAG->getMachineNode(Hexagon::TFR_PdRs, dl, MVT::i1,
|
|
SDValue(Arg, 0));
|
|
Ops.push_back(SDValue(PdRs,0));
|
|
} else if (RC == NULL && (dyn_cast<ConstantSDNode>(Arg) != NULL)) {
|
|
// This is immediate operand. Lower it here making sure that we DO have
|
|
// const SDNode for immediate value.
|
|
int32_t Val = cast<ConstantSDNode>(Arg)->getSExtValue();
|
|
SDValue SDVal = CurDAG->getTargetConstant(Val, MVT::i32);
|
|
Ops.push_back(SDVal);
|
|
} else {
|
|
llvm_unreachable("Unimplemented");
|
|
}
|
|
}
|
|
EVT ReturnValueVT = N->getValueType(0);
|
|
SDNode *Result = CurDAG->getMachineNode(IntrinsicWithPred, dl,
|
|
ReturnValueVT,
|
|
Ops.data(), Ops.size());
|
|
ReplaceUses(N, Result);
|
|
return Result;
|
|
}
|
|
return SelectCode(N);
|
|
}
|
|
|
|
//
|
|
// Map floating point constant values.
|
|
//
|
|
SDNode *HexagonDAGToDAGISel::SelectConstantFP(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N);
|
|
APFloat APF = CN->getValueAPF();
|
|
if (N->getValueType(0) == MVT::f32) {
|
|
return CurDAG->getMachineNode(Hexagon::TFRI_f, dl, MVT::f32,
|
|
CurDAG->getTargetConstantFP(APF.convertToFloat(), MVT::f32));
|
|
}
|
|
else if (N->getValueType(0) == MVT::f64) {
|
|
return CurDAG->getMachineNode(Hexagon::CONST64_Float_Real, dl, MVT::f64,
|
|
CurDAG->getTargetConstantFP(APF.convertToDouble(), MVT::f64));
|
|
}
|
|
|
|
return SelectCode(N);
|
|
}
|
|
|
|
|
|
//
|
|
// Map predicate true (encoded as -1 in LLVM) to a XOR.
|
|
//
|
|
SDNode *HexagonDAGToDAGISel::SelectConstant(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
if (N->getValueType(0) == MVT::i1) {
|
|
SDNode* Result;
|
|
int32_t Val = cast<ConstantSDNode>(N)->getSExtValue();
|
|
if (Val == -1) {
|
|
// Create the IntReg = 1 node.
|
|
SDNode* IntRegTFR =
|
|
CurDAG->getMachineNode(Hexagon::TFRI, dl, MVT::i32,
|
|
CurDAG->getTargetConstant(0, MVT::i32));
|
|
|
|
// Pd = IntReg
|
|
SDNode* Pd = CurDAG->getMachineNode(Hexagon::TFR_PdRs, dl, MVT::i1,
|
|
SDValue(IntRegTFR, 0));
|
|
|
|
// not(Pd)
|
|
SDNode* NotPd = CurDAG->getMachineNode(Hexagon::NOT_p, dl, MVT::i1,
|
|
SDValue(Pd, 0));
|
|
|
|
// xor(not(Pd))
|
|
Result = CurDAG->getMachineNode(Hexagon::XOR_pp, dl, MVT::i1,
|
|
SDValue(Pd, 0), SDValue(NotPd, 0));
|
|
|
|
// We have just built:
|
|
// Rs = Pd
|
|
// Pd = xor(not(Pd), Pd)
|
|
|
|
ReplaceUses(N, Result);
|
|
return Result;
|
|
}
|
|
}
|
|
|
|
return SelectCode(N);
|
|
}
|
|
|
|
|
|
//
|
|
// Map add followed by a asr -> asr +=.
|
|
//
|
|
SDNode *HexagonDAGToDAGISel::SelectAdd(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
if (N->getValueType(0) != MVT::i32) {
|
|
return SelectCode(N);
|
|
}
|
|
// Identify nodes of the form: add(asr(...)).
|
|
SDNode* Src1 = N->getOperand(0).getNode();
|
|
if (Src1->getOpcode() != ISD::SRA || !Src1->hasOneUse()
|
|
|| Src1->getValueType(0) != MVT::i32) {
|
|
return SelectCode(N);
|
|
}
|
|
|
|
// Build Rd = Rd' + asr(Rs, Rt). The machine constraints will ensure that
|
|
// Rd and Rd' are assigned to the same register
|
|
SDNode* Result = CurDAG->getMachineNode(Hexagon::ASR_ADD_rr, dl, MVT::i32,
|
|
N->getOperand(1),
|
|
Src1->getOperand(0),
|
|
Src1->getOperand(1));
|
|
ReplaceUses(N, Result);
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
SDNode *HexagonDAGToDAGISel::Select(SDNode *N) {
|
|
if (N->isMachineOpcode())
|
|
return NULL; // Already selected.
|
|
|
|
|
|
switch (N->getOpcode()) {
|
|
case ISD::Constant:
|
|
return SelectConstant(N);
|
|
|
|
case ISD::ConstantFP:
|
|
return SelectConstantFP(N);
|
|
|
|
case ISD::ADD:
|
|
return SelectAdd(N);
|
|
|
|
case ISD::SHL:
|
|
return SelectSHL(N);
|
|
|
|
case ISD::LOAD:
|
|
return SelectLoad(N);
|
|
|
|
case ISD::STORE:
|
|
return SelectStore(N);
|
|
|
|
case ISD::SELECT:
|
|
return SelectSelect(N);
|
|
|
|
case ISD::TRUNCATE:
|
|
return SelectTruncate(N);
|
|
|
|
case ISD::MUL:
|
|
return SelectMul(N);
|
|
|
|
case ISD::ZERO_EXTEND:
|
|
return SelectZeroExtend(N);
|
|
|
|
case ISD::INTRINSIC_WO_CHAIN:
|
|
return SelectIntrinsicWOChain(N);
|
|
}
|
|
|
|
return SelectCode(N);
|
|
}
|
|
|
|
|
|
//
|
|
// Hexagon_TODO: Five functions for ADDRri?! Surely there must be a better way
|
|
// to define these instructions.
|
|
//
|
|
bool HexagonDAGToDAGISel::SelectADDRri(SDValue& Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // Direct calls.
|
|
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return true;
|
|
}
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool HexagonDAGToDAGISel::SelectADDRriS11_0(SDValue& Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // Direct calls.
|
|
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsS11_0_Offset(Offset.getNode()));
|
|
}
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsS11_0_Offset(Offset.getNode()));
|
|
}
|
|
|
|
|
|
bool HexagonDAGToDAGISel::SelectADDRriS11_1(SDValue& Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // Direct calls.
|
|
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsS11_1_Offset(Offset.getNode()));
|
|
}
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsS11_1_Offset(Offset.getNode()));
|
|
}
|
|
|
|
|
|
bool HexagonDAGToDAGISel::SelectADDRriS11_2(SDValue& Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // Direct calls.
|
|
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsS11_2_Offset(Offset.getNode()));
|
|
}
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsS11_2_Offset(Offset.getNode()));
|
|
}
|
|
|
|
|
|
bool HexagonDAGToDAGISel::SelectADDRriU6_0(SDValue& Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // Direct calls.
|
|
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsU6_0_Offset(Offset.getNode()));
|
|
}
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsU6_0_Offset(Offset.getNode()));
|
|
}
|
|
|
|
|
|
bool HexagonDAGToDAGISel::SelectADDRriU6_1(SDValue& Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // Direct calls.
|
|
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsU6_1_Offset(Offset.getNode()));
|
|
}
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsU6_1_Offset(Offset.getNode()));
|
|
}
|
|
|
|
|
|
bool HexagonDAGToDAGISel::SelectADDRriU6_2(SDValue& Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // Direct calls.
|
|
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsU6_2_Offset(Offset.getNode()));
|
|
}
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsU6_2_Offset(Offset.getNode()));
|
|
}
|
|
|
|
|
|
bool HexagonDAGToDAGISel::SelectMEMriS11_2(SDValue& Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
|
|
if (Addr.getOpcode() != ISD::ADD) {
|
|
return(SelectADDRriS11_2(Addr, Base, Offset));
|
|
}
|
|
|
|
return SelectADDRriS11_2(Addr, Base, Offset);
|
|
}
|
|
|
|
|
|
bool HexagonDAGToDAGISel::SelectADDRriS11_3(SDValue& Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // Direct calls.
|
|
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsS11_3_Offset(Offset.getNode()));
|
|
}
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return (IsS11_3_Offset(Offset.getNode()));
|
|
}
|
|
|
|
bool HexagonDAGToDAGISel::SelectADDRrr(SDValue &Addr, SDValue &R1,
|
|
SDValue &R2) {
|
|
if (Addr.getOpcode() == ISD::FrameIndex) return false;
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // Direct calls.
|
|
|
|
if (Addr.getOpcode() == ISD::ADD) {
|
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
|
|
if (isInt<13>(CN->getSExtValue()))
|
|
return false; // Let the reg+imm pattern catch this!
|
|
R1 = Addr.getOperand(0);
|
|
R2 = Addr.getOperand(1);
|
|
return true;
|
|
}
|
|
|
|
R1 = Addr;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Handle generic address case. It is accessed from inlined asm =m constraints,
|
|
// which could have any kind of pointer.
|
|
bool HexagonDAGToDAGISel::SelectAddr(SDNode *Op, SDValue Addr,
|
|
SDValue &Base, SDValue &Offset) {
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // Direct calls.
|
|
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return true;
|
|
}
|
|
|
|
if (Addr.getOpcode() == ISD::ADD) {
|
|
Base = Addr.getOperand(0);
|
|
Offset = Addr.getOperand(1);
|
|
return true;
|
|
}
|
|
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool HexagonDAGToDAGISel::
|
|
SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
|
|
std::vector<SDValue> &OutOps) {
|
|
SDValue Op0, Op1;
|
|
|
|
switch (ConstraintCode) {
|
|
case 'o': // Offsetable.
|
|
case 'v': // Not offsetable.
|
|
default: return true;
|
|
case 'm': // Memory.
|
|
if (!SelectAddr(Op.getNode(), Op, Op0, Op1))
|
|
return true;
|
|
break;
|
|
}
|
|
|
|
OutOps.push_back(Op0);
|
|
OutOps.push_back(Op1);
|
|
return false;
|
|
}
|
|
|
|
bool HexagonDAGToDAGISel::isConstExtProfitable(SDNode *N) const {
|
|
unsigned UseCount = 0;
|
|
for (SDNode::use_iterator I = N->use_begin(), E = N->use_end(); I != E; ++I) {
|
|
UseCount++;
|
|
}
|
|
|
|
return (UseCount <= 1);
|
|
|
|
}
|