244 lines
7.7 KiB
C++
244 lines
7.7 KiB
C++
//===- XtensaISelDAGToDAG.cpp - A dag to dag inst selector for Xtensa -----===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines an instruction selector for the Xtensa target.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "MCTargetDesc/XtensaMCTargetDesc.h"
|
|
#include "Xtensa.h"
|
|
#include "XtensaTargetMachine.h"
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "xtensa-isel"
|
|
|
|
namespace {
|
|
|
|
class XtensaDAGToDAGISel : public SelectionDAGISel {
|
|
const XtensaSubtarget *Subtarget = nullptr;
|
|
|
|
public:
|
|
explicit XtensaDAGToDAGISel(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel)
|
|
: SelectionDAGISel(TM, OptLevel) {}
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override {
|
|
Subtarget = &MF.getSubtarget<XtensaSubtarget>();
|
|
return SelectionDAGISel::runOnMachineFunction(MF);
|
|
}
|
|
|
|
void Select(SDNode *Node) override;
|
|
|
|
bool SelectInlineAsmMemoryOperand(const SDValue &Op,
|
|
InlineAsm::ConstraintCode ConstraintID,
|
|
std::vector<SDValue> &OutOps) override;
|
|
|
|
// For load/store instructions generate (base+offset) pair from
|
|
// memory address. The offset must be a multiple of scale argument.
|
|
bool selectMemRegAddr(SDValue Addr, SDValue &Base, SDValue &Offset,
|
|
int Scale) {
|
|
EVT ValTy = Addr.getValueType();
|
|
|
|
// if Address is FI, get the TargetFrameIndex.
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
|
|
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), ValTy);
|
|
|
|
return true;
|
|
}
|
|
|
|
if (TM.isPositionIndependent()) {
|
|
CurDAG->getContext()->diagnose(DiagnosticInfoUnsupported(
|
|
CurDAG->getMachineFunction().getFunction(),
|
|
"PIC relocations are not supported", Addr.getDebugLoc()));
|
|
}
|
|
|
|
if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress))
|
|
return false;
|
|
|
|
// Addresses of the form FI+const
|
|
bool Valid = false;
|
|
if (CurDAG->isBaseWithConstantOffset(Addr)) {
|
|
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
|
|
int64_t OffsetVal = CN->getSExtValue();
|
|
|
|
Valid = Xtensa::isValidAddrOffset(Scale, OffsetVal);
|
|
|
|
if (Valid) {
|
|
// If the first operand is a FI, get the TargetFI Node.
|
|
if (FrameIndexSDNode *FIN =
|
|
dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
|
|
else
|
|
Base = Addr.getOperand(0);
|
|
|
|
Offset =
|
|
CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), ValTy);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Last case
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Addr.getValueType());
|
|
return true;
|
|
}
|
|
|
|
bool selectMemRegAddrISH1(SDValue Addr, SDValue &Base, SDValue &Offset) {
|
|
return selectMemRegAddr(Addr, Base, Offset, 1);
|
|
}
|
|
|
|
bool selectMemRegAddrISH2(SDValue Addr, SDValue &Base, SDValue &Offset) {
|
|
return selectMemRegAddr(Addr, Base, Offset, 2);
|
|
}
|
|
|
|
bool selectMemRegAddrISH4(SDValue Addr, SDValue &Base, SDValue &Offset) {
|
|
return selectMemRegAddr(Addr, Base, Offset, 4);
|
|
}
|
|
|
|
// Include the pieces autogenerated from the target description.
|
|
#include "XtensaGenDAGISel.inc"
|
|
}; // namespace
|
|
|
|
class XtensaDAGToDAGISelLegacy : public SelectionDAGISelLegacy {
|
|
public:
|
|
static char ID;
|
|
|
|
XtensaDAGToDAGISelLegacy(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel)
|
|
: SelectionDAGISelLegacy(
|
|
ID, std::make_unique<XtensaDAGToDAGISel>(TM, OptLevel)) {}
|
|
|
|
StringRef getPassName() const override {
|
|
return "Xtensa DAG->DAG Pattern Instruction Selection";
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
char XtensaDAGToDAGISelLegacy::ID = 0;
|
|
|
|
FunctionPass *llvm::createXtensaISelDag(XtensaTargetMachine &TM,
|
|
CodeGenOptLevel OptLevel) {
|
|
return new XtensaDAGToDAGISelLegacy(TM, OptLevel);
|
|
}
|
|
|
|
void XtensaDAGToDAGISel::Select(SDNode *Node) {
|
|
SDLoc DL(Node);
|
|
EVT VT = Node->getValueType(0);
|
|
|
|
// If we have a custom node, we already have selected!
|
|
if (Node->isMachineOpcode()) {
|
|
Node->setNodeId(-1);
|
|
return;
|
|
}
|
|
|
|
switch (Node->getOpcode()) {
|
|
case ISD::SHL: {
|
|
SDValue N0 = Node->getOperand(0);
|
|
SDValue N1 = Node->getOperand(1);
|
|
auto *C = dyn_cast<ConstantSDNode>(N1);
|
|
// If C is constant in range [1..31] then we can generate SLLI
|
|
// instruction using pattern matching, otherwise generate SLL.
|
|
if (!C || C->isZero()) {
|
|
SDNode *SSL = CurDAG->getMachineNode(Xtensa::SSL, DL, MVT::Glue, N1);
|
|
SDNode *SLL =
|
|
CurDAG->getMachineNode(Xtensa::SLL, DL, VT, N0, SDValue(SSL, 0));
|
|
ReplaceNode(Node, SLL);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case ISD::SRL: {
|
|
SDValue N0 = Node->getOperand(0);
|
|
SDValue N1 = Node->getOperand(1);
|
|
auto *C = dyn_cast<ConstantSDNode>(N1);
|
|
|
|
// If C is constant then we can generate SRLI
|
|
// instruction using pattern matching or EXTUI, otherwise generate SRL.
|
|
if (C) {
|
|
if (isUInt<4>(C->getZExtValue()))
|
|
break;
|
|
unsigned ShAmt = C->getZExtValue();
|
|
SDNode *EXTUI = CurDAG->getMachineNode(
|
|
Xtensa::EXTUI, DL, VT, N0, CurDAG->getTargetConstant(ShAmt, DL, VT),
|
|
CurDAG->getTargetConstant(32 - ShAmt, DL, VT));
|
|
ReplaceNode(Node, EXTUI);
|
|
return;
|
|
}
|
|
|
|
SDNode *SSR = CurDAG->getMachineNode(Xtensa::SSR, DL, MVT::Glue, N1);
|
|
SDNode *SRL =
|
|
CurDAG->getMachineNode(Xtensa::SRL, DL, VT, N0, SDValue(SSR, 0));
|
|
ReplaceNode(Node, SRL);
|
|
return;
|
|
}
|
|
case ISD::SRA: {
|
|
SDValue N0 = Node->getOperand(0);
|
|
SDValue N1 = Node->getOperand(1);
|
|
auto *C = dyn_cast<ConstantSDNode>(N1);
|
|
// If C is constant then we can generate SRAI
|
|
// instruction using pattern matching, otherwise generate SRA.
|
|
if (!C) {
|
|
SDNode *SSR = CurDAG->getMachineNode(Xtensa::SSR, DL, MVT::Glue, N1);
|
|
SDNode *SRA =
|
|
CurDAG->getMachineNode(Xtensa::SRA, DL, VT, N0, SDValue(SSR, 0));
|
|
ReplaceNode(Node, SRA);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case XtensaISD::SRCL: {
|
|
SDValue N0 = Node->getOperand(0);
|
|
SDValue N1 = Node->getOperand(1);
|
|
SDValue N2 = Node->getOperand(2);
|
|
SDNode *SSL = CurDAG->getMachineNode(Xtensa::SSL, DL, MVT::Glue, N2);
|
|
SDNode *SRC =
|
|
CurDAG->getMachineNode(Xtensa::SRC, DL, VT, N0, N1, SDValue(SSL, 0));
|
|
ReplaceNode(Node, SRC);
|
|
return;
|
|
}
|
|
case XtensaISD::SRCR: {
|
|
SDValue N0 = Node->getOperand(0);
|
|
SDValue N1 = Node->getOperand(1);
|
|
SDValue N2 = Node->getOperand(2);
|
|
SDNode *SSR = CurDAG->getMachineNode(Xtensa::SSR, DL, MVT::Glue, N2);
|
|
SDNode *SRC =
|
|
CurDAG->getMachineNode(Xtensa::SRC, DL, VT, N0, N1, SDValue(SSR, 0));
|
|
ReplaceNode(Node, SRC);
|
|
return;
|
|
}
|
|
}
|
|
|
|
SelectCode(Node);
|
|
}
|
|
|
|
bool XtensaDAGToDAGISel::SelectInlineAsmMemoryOperand(
|
|
const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,
|
|
std::vector<SDValue> &OutOps) {
|
|
switch (ConstraintID) {
|
|
default:
|
|
llvm_unreachable("Unexpected asm memory constraint");
|
|
case InlineAsm::ConstraintCode::m: {
|
|
SDValue Base, Offset;
|
|
|
|
selectMemRegAddr(Op, Base, Offset, 4);
|
|
OutOps.push_back(Base);
|
|
OutOps.push_back(Offset);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|