1326938Sdim//===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- C++ -*-===// 2326938Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6326938Sdim// 7326938Sdim//===----------------------------------------------------------------------===// 8326938Sdim// 9326938Sdim// This file defines an instruction selector for the ARC target. 10326938Sdim// 11326938Sdim//===----------------------------------------------------------------------===// 12326938Sdim 13326938Sdim#include "ARC.h" 14326938Sdim#include "ARCTargetMachine.h" 15326938Sdim#include "llvm/CodeGen/MachineFrameInfo.h" 16326938Sdim#include "llvm/CodeGen/MachineFunction.h" 17326938Sdim#include "llvm/CodeGen/MachineInstrBuilder.h" 18326938Sdim#include "llvm/CodeGen/MachineRegisterInfo.h" 19326938Sdim#include "llvm/CodeGen/SelectionDAG.h" 20326938Sdim#include "llvm/CodeGen/SelectionDAGISel.h" 21326938Sdim#include "llvm/CodeGen/TargetLowering.h" 22326938Sdim#include "llvm/IR/CallingConv.h" 23326938Sdim#include "llvm/IR/Constants.h" 24326938Sdim#include "llvm/IR/DerivedTypes.h" 25326938Sdim#include "llvm/IR/Function.h" 26326938Sdim#include "llvm/IR/Intrinsics.h" 27326938Sdim#include "llvm/IR/LLVMContext.h" 28326938Sdim#include "llvm/Support/Compiler.h" 29326938Sdim#include "llvm/Support/Debug.h" 30326938Sdim#include "llvm/Support/ErrorHandling.h" 31326938Sdim#include "llvm/Support/raw_ostream.h" 32326938Sdim 33326938Sdimusing namespace llvm; 34326938Sdim 35326938Sdim/// ARCDAGToDAGISel - ARC specific code to select ARC machine 36326938Sdim/// instructions for SelectionDAG operations. 37326938Sdimnamespace { 38326938Sdim 39326938Sdimclass ARCDAGToDAGISel : public SelectionDAGISel { 40326938Sdimpublic: 41326938Sdim ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOpt::Level OptLevel) 42326938Sdim : SelectionDAGISel(TM, OptLevel) {} 43326938Sdim 44326938Sdim void Select(SDNode *N) override; 45326938Sdim 46326938Sdim // Complex Pattern Selectors. 47326938Sdim bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset); 48326938Sdim bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset); 49326938Sdim bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset); 50326938Sdim bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset); 51326938Sdim bool SelectCMOVPred(SDValue N, SDValue &Pred, SDValue &Reg) { 52326938Sdim const ConstantSDNode *CN = cast<ConstantSDNode>(N); 53326938Sdim Pred = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), MVT::i32); 54326938Sdim Reg = CurDAG->getRegister(ARC::STATUS32, MVT::i32); 55326938Sdim return true; 56326938Sdim } 57326938Sdim 58326938Sdim StringRef getPassName() const override { 59326938Sdim return "ARC DAG->DAG Pattern Instruction Selection"; 60326938Sdim } 61326938Sdim 62326938Sdim// Include the pieces autogenerated from the target description. 63326938Sdim#include "ARCGenDAGISel.inc" 64326938Sdim}; 65326938Sdim 66326938Sdim} // end anonymous namespace 67326938Sdim 68326938Sdim/// This pass converts a legalized DAG into a ARC-specific DAG, ready for 69326938Sdim/// instruction scheduling. 70326938SdimFunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM, 71326938Sdim CodeGenOpt::Level OptLevel) { 72326938Sdim return new ARCDAGToDAGISel(TM, OptLevel); 73326938Sdim} 74326938Sdim 75326938Sdimbool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base, 76326938Sdim SDValue &Offset) { 77326938Sdim if (Addr.getOpcode() == ARCISD::GAWRAPPER) { 78326938Sdim Base = Addr.getOperand(0); 79326938Sdim Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 80326938Sdim return true; 81326938Sdim } 82326938Sdim return false; 83326938Sdim} 84326938Sdim 85326938Sdimbool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base, 86326938Sdim SDValue &Offset) { 87326938Sdim if (Addr.getOpcode() == ARCISD::GAWRAPPER) { 88326938Sdim return false; 89326938Sdim } 90326938Sdim 91326938Sdim if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB && 92326938Sdim !CurDAG->isBaseWithConstantOffset(Addr)) { 93326938Sdim if (Addr.getOpcode() == ISD::FrameIndex) { 94326938Sdim // Match frame index. 95326938Sdim int FI = cast<FrameIndexSDNode>(Addr)->getIndex(); 96326938Sdim Base = CurDAG->getTargetFrameIndex( 97326938Sdim FI, TLI->getPointerTy(CurDAG->getDataLayout())); 98326938Sdim } else { 99326938Sdim Base = Addr; 100326938Sdim } 101326938Sdim Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 102326938Sdim return true; 103326938Sdim } 104326938Sdim 105326938Sdim if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { 106326938Sdim int32_t RHSC = RHS->getSExtValue(); 107326938Sdim if (Addr.getOpcode() == ISD::SUB) 108326938Sdim RHSC = -RHSC; 109326938Sdim 110326938Sdim // Do we need more than 9 bits to encode? 111326938Sdim if (!isInt<9>(RHSC)) 112326938Sdim return false; 113326938Sdim Base = Addr.getOperand(0); 114326938Sdim if (Base.getOpcode() == ISD::FrameIndex) { 115326938Sdim int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 116326938Sdim Base = CurDAG->getTargetFrameIndex( 117326938Sdim FI, TLI->getPointerTy(CurDAG->getDataLayout())); 118326938Sdim } 119326938Sdim Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); 120326938Sdim return true; 121326938Sdim } 122326938Sdim Base = Addr; 123326938Sdim Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 124326938Sdim return true; 125326938Sdim} 126326938Sdim 127326938Sdimbool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base, 128326938Sdim SDValue &Offset) { 129326938Sdim if (SelectAddrModeS9(Addr, Base, Offset)) 130326938Sdim return false; 131326938Sdim if (Addr.getOpcode() == ARCISD::GAWRAPPER) { 132326938Sdim return false; 133326938Sdim } 134326938Sdim if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { 135326938Sdim int32_t RHSC = RHS->getSExtValue(); 136326938Sdim if (Addr.getOpcode() == ISD::SUB) 137326938Sdim RHSC = -RHSC; 138326938Sdim Base = Addr.getOperand(0); 139326938Sdim Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); 140326938Sdim return true; 141326938Sdim } 142326938Sdim return false; 143326938Sdim} 144326938Sdim 145326938Sdim// Is this a legal frame index addressing expression. 146326938Sdimbool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base, 147326938Sdim SDValue &Offset) { 148326938Sdim FrameIndexSDNode *FIN = nullptr; 149326938Sdim if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) { 150326938Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 151326938Sdim Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 152326938Sdim return true; 153326938Sdim } 154326938Sdim if (Addr.getOpcode() == ISD::ADD) { 155326938Sdim ConstantSDNode *CN = nullptr; 156326938Sdim if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) && 157326938Sdim (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) && 158326938Sdim (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { 159326938Sdim // Constant positive word offset from frame index 160326938Sdim Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 161326938Sdim Offset = 162326938Sdim CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32); 163326938Sdim return true; 164326938Sdim } 165326938Sdim } 166326938Sdim return false; 167326938Sdim} 168326938Sdim 169326938Sdimvoid ARCDAGToDAGISel::Select(SDNode *N) { 170326938Sdim switch (N->getOpcode()) { 171326938Sdim case ISD::Constant: { 172326938Sdim uint64_t CVal = cast<ConstantSDNode>(N)->getZExtValue(); 173326938Sdim ReplaceNode(N, CurDAG->getMachineNode( 174326938Sdim isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm, 175326938Sdim SDLoc(N), MVT::i32, 176326938Sdim CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32))); 177326938Sdim return; 178326938Sdim } 179326938Sdim } 180326938Sdim SelectCode(N); 181326938Sdim} 182