182 lines
6.2 KiB
C++
182 lines
6.2 KiB
C++
|
//===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- C++ -*-===//
|
||
|
//
|
||
|
// 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 ARC target.
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "ARC.h"
|
||
|
#include "ARCTargetMachine.h"
|
||
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||
|
#include "llvm/CodeGen/MachineFunction.h"
|
||
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||
|
#include "llvm/CodeGen/SelectionDAG.h"
|
||
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
||
|
#include "llvm/CodeGen/TargetLowering.h"
|
||
|
#include "llvm/IR/CallingConv.h"
|
||
|
#include "llvm/IR/Constants.h"
|
||
|
#include "llvm/IR/DerivedTypes.h"
|
||
|
#include "llvm/IR/Function.h"
|
||
|
#include "llvm/IR/Intrinsics.h"
|
||
|
#include "llvm/IR/LLVMContext.h"
|
||
|
#include "llvm/Support/Compiler.h"
|
||
|
#include "llvm/Support/Debug.h"
|
||
|
#include "llvm/Support/ErrorHandling.h"
|
||
|
#include "llvm/Support/raw_ostream.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
/// ARCDAGToDAGISel - ARC specific code to select ARC machine
|
||
|
/// instructions for SelectionDAG operations.
|
||
|
namespace {
|
||
|
|
||
|
class ARCDAGToDAGISel : public SelectionDAGISel {
|
||
|
public:
|
||
|
ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOpt::Level OptLevel)
|
||
|
: SelectionDAGISel(TM, OptLevel) {}
|
||
|
|
||
|
void Select(SDNode *N) override;
|
||
|
|
||
|
// Complex Pattern Selectors.
|
||
|
bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset);
|
||
|
bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset);
|
||
|
bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset);
|
||
|
bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset);
|
||
|
bool SelectCMOVPred(SDValue N, SDValue &Pred, SDValue &Reg) {
|
||
|
const ConstantSDNode *CN = cast<ConstantSDNode>(N);
|
||
|
Pred = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), MVT::i32);
|
||
|
Reg = CurDAG->getRegister(ARC::STATUS32, MVT::i32);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
StringRef getPassName() const override {
|
||
|
return "ARC DAG->DAG Pattern Instruction Selection";
|
||
|
}
|
||
|
|
||
|
// Include the pieces autogenerated from the target description.
|
||
|
#include "ARCGenDAGISel.inc"
|
||
|
};
|
||
|
|
||
|
} // end anonymous namespace
|
||
|
|
||
|
/// This pass converts a legalized DAG into a ARC-specific DAG, ready for
|
||
|
/// instruction scheduling.
|
||
|
FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM,
|
||
|
CodeGenOpt::Level OptLevel) {
|
||
|
return new ARCDAGToDAGISel(TM, OptLevel);
|
||
|
}
|
||
|
|
||
|
bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base,
|
||
|
SDValue &Offset) {
|
||
|
if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
|
||
|
Base = Addr.getOperand(0);
|
||
|
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base,
|
||
|
SDValue &Offset) {
|
||
|
if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB &&
|
||
|
!CurDAG->isBaseWithConstantOffset(Addr)) {
|
||
|
if (Addr.getOpcode() == ISD::FrameIndex) {
|
||
|
// Match frame index.
|
||
|
int FI = cast<FrameIndexSDNode>(Addr)->getIndex();
|
||
|
Base = CurDAG->getTargetFrameIndex(
|
||
|
FI, TLI->getPointerTy(CurDAG->getDataLayout()));
|
||
|
} else {
|
||
|
Base = Addr;
|
||
|
}
|
||
|
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
|
||
|
int32_t RHSC = RHS->getSExtValue();
|
||
|
if (Addr.getOpcode() == ISD::SUB)
|
||
|
RHSC = -RHSC;
|
||
|
|
||
|
// Do we need more than 9 bits to encode?
|
||
|
if (!isInt<9>(RHSC))
|
||
|
return false;
|
||
|
Base = Addr.getOperand(0);
|
||
|
if (Base.getOpcode() == ISD::FrameIndex) {
|
||
|
int FI = cast<FrameIndexSDNode>(Base)->getIndex();
|
||
|
Base = CurDAG->getTargetFrameIndex(
|
||
|
FI, TLI->getPointerTy(CurDAG->getDataLayout()));
|
||
|
}
|
||
|
Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
|
||
|
return true;
|
||
|
}
|
||
|
Base = Addr;
|
||
|
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base,
|
||
|
SDValue &Offset) {
|
||
|
if (SelectAddrModeS9(Addr, Base, Offset))
|
||
|
return false;
|
||
|
if (Addr.getOpcode() == ARCISD::GAWRAPPER) {
|
||
|
return false;
|
||
|
}
|
||
|
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
|
||
|
int32_t RHSC = RHS->getSExtValue();
|
||
|
if (Addr.getOpcode() == ISD::SUB)
|
||
|
RHSC = -RHSC;
|
||
|
Base = Addr.getOperand(0);
|
||
|
Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32);
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Is this a legal frame index addressing expression.
|
||
|
bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base,
|
||
|
SDValue &Offset) {
|
||
|
FrameIndexSDNode *FIN = nullptr;
|
||
|
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
|
||
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
||
|
Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
|
||
|
return true;
|
||
|
}
|
||
|
if (Addr.getOpcode() == ISD::ADD) {
|
||
|
ConstantSDNode *CN = nullptr;
|
||
|
if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) &&
|
||
|
(CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) &&
|
||
|
(CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
|
||
|
// Constant positive word offset from frame index
|
||
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
||
|
Offset =
|
||
|
CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void ARCDAGToDAGISel::Select(SDNode *N) {
|
||
|
switch (N->getOpcode()) {
|
||
|
case ISD::Constant: {
|
||
|
uint64_t CVal = cast<ConstantSDNode>(N)->getZExtValue();
|
||
|
ReplaceNode(N, CurDAG->getMachineNode(
|
||
|
isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm,
|
||
|
SDLoc(N), MVT::i32,
|
||
|
CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32)));
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
SelectCode(N);
|
||
|
}
|