blob: 145f2850363589055fb4d3d2395319458a55a6eb [file]
//===- 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 "Xtensa.h"
#include "XtensaTargetMachine.h"
#include "XtensaUtils.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 {
public:
XtensaDAGToDAGISel(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel)
: SelectionDAGISel(TM, OptLevel) {}
void Select(SDNode *Node) 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()) {
DiagnosticInfoUnsupported Diag(CurDAG->getMachineFunction().getFunction(),
"PIC relocations are not supported ",
Addr.getDebugLoc());
CurDAG->getContext()->diagnose(Diag);
}
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 = 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);
// If we have a custom node, we already have selected!
if (Node->isMachineOpcode()) {
Node->setNodeId(-1);
return;
}
SelectCode(Node);
}