Path: blob/main/contrib/llvm-project/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp
35269 views
//=- LoongArchISelDAGToDAG.cpp - A dag to dag inst selector for LoongArch -===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines an instruction selector for the LoongArch target.9//10//===----------------------------------------------------------------------===//1112#include "LoongArchISelDAGToDAG.h"13#include "LoongArchISelLowering.h"14#include "MCTargetDesc/LoongArchMCTargetDesc.h"15#include "MCTargetDesc/LoongArchMatInt.h"16#include "llvm/Support/KnownBits.h"17#include "llvm/Support/raw_ostream.h"1819using namespace llvm;2021#define DEBUG_TYPE "loongarch-isel"22#define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection"2324char LoongArchDAGToDAGISelLegacy::ID;2526LoongArchDAGToDAGISelLegacy::LoongArchDAGToDAGISelLegacy(27LoongArchTargetMachine &TM)28: SelectionDAGISelLegacy(ID, std::make_unique<LoongArchDAGToDAGISel>(TM)) {}2930INITIALIZE_PASS(LoongArchDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false,31false)3233void LoongArchDAGToDAGISel::Select(SDNode *Node) {34// If we have a custom node, we have already selected.35if (Node->isMachineOpcode()) {36LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");37Node->setNodeId(-1);38return;39}4041// Instruction Selection not handled by the auto-generated tablegen selection42// should be handled here.43unsigned Opcode = Node->getOpcode();44MVT GRLenVT = Subtarget->getGRLenVT();45SDLoc DL(Node);46MVT VT = Node->getSimpleValueType(0);4748switch (Opcode) {49default:50break;51case ISD::Constant: {52int64_t Imm = cast<ConstantSDNode>(Node)->getSExtValue();53if (Imm == 0 && VT == GRLenVT) {54SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL,55LoongArch::R0, GRLenVT);56ReplaceNode(Node, New.getNode());57return;58}59SDNode *Result = nullptr;60SDValue SrcReg = CurDAG->getRegister(LoongArch::R0, GRLenVT);61// The instructions in the sequence are handled here.62for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) {63SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, GRLenVT);64if (Inst.Opc == LoongArch::LU12I_W)65Result = CurDAG->getMachineNode(LoongArch::LU12I_W, DL, GRLenVT, SDImm);66else67Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm);68SrcReg = SDValue(Result, 0);69}7071ReplaceNode(Node, Result);72return;73}74case ISD::FrameIndex: {75SDValue Imm = CurDAG->getTargetConstant(0, DL, GRLenVT);76int FI = cast<FrameIndexSDNode>(Node)->getIndex();77SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);78unsigned ADDIOp =79Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;80ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm));81return;82}83case ISD::BITCAST: {84if (VT.is128BitVector() || VT.is256BitVector()) {85ReplaceUses(SDValue(Node, 0), Node->getOperand(0));86CurDAG->RemoveDeadNode(Node);87return;88}89break;90}91case ISD::BUILD_VECTOR: {92// Select appropriate [x]vrepli.[bhwd] instructions for constant splats of93// 128/256-bit when LSX/LASX is enabled.94BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Node);95APInt SplatValue, SplatUndef;96unsigned SplatBitSize;97bool HasAnyUndefs;98unsigned Op;99EVT ViaVecTy;100bool Is128Vec = BVN->getValueType(0).is128BitVector();101bool Is256Vec = BVN->getValueType(0).is256BitVector();102103if (!Subtarget->hasExtLSX() || (!Is128Vec && !Is256Vec))104break;105if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,106HasAnyUndefs, 8))107break;108109switch (SplatBitSize) {110default:111break;112case 8:113Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B;114ViaVecTy = Is256Vec ? MVT::v32i8 : MVT::v16i8;115break;116case 16:117Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H;118ViaVecTy = Is256Vec ? MVT::v16i16 : MVT::v8i16;119break;120case 32:121Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W;122ViaVecTy = Is256Vec ? MVT::v8i32 : MVT::v4i32;123break;124case 64:125Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D;126ViaVecTy = Is256Vec ? MVT::v4i64 : MVT::v2i64;127break;128}129130SDNode *Res;131// If we have a signed 10 bit integer, we can splat it directly.132if (SplatValue.isSignedIntN(10)) {133SDValue Imm = CurDAG->getTargetConstant(SplatValue, DL,134ViaVecTy.getVectorElementType());135Res = CurDAG->getMachineNode(Op, DL, ViaVecTy, Imm);136ReplaceNode(Node, Res);137return;138}139break;140}141}142143// Select the default instruction.144SelectCode(Node);145}146147bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand(148const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,149std::vector<SDValue> &OutOps) {150SDValue Base = Op;151SDValue Offset =152CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT());153switch (ConstraintID) {154default:155llvm_unreachable("unexpected asm memory constraint");156// Reg+Reg addressing.157case InlineAsm::ConstraintCode::k:158Base = Op.getOperand(0);159Offset = Op.getOperand(1);160break;161// Reg+simm12 addressing.162case InlineAsm::ConstraintCode::m:163if (CurDAG->isBaseWithConstantOffset(Op)) {164ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));165if (isIntN(12, CN->getSExtValue())) {166Base = Op.getOperand(0);167Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),168Op.getValueType());169}170}171break;172// Reg+0 addressing.173case InlineAsm::ConstraintCode::ZB:174break;175// Reg+(simm14<<2) addressing.176case InlineAsm::ConstraintCode::ZC:177if (CurDAG->isBaseWithConstantOffset(Op)) {178ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1));179if (isIntN(16, CN->getSExtValue()) &&180isAligned(Align(4ULL), CN->getZExtValue())) {181Base = Op.getOperand(0);182Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op),183Op.getValueType());184}185}186break;187}188OutOps.push_back(Base);189OutOps.push_back(Offset);190return false;191}192193bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {194// If this is FrameIndex, select it directly. Otherwise just let it get195// selected to a register independently.196if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr))197Base =198CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT());199else200Base = Addr;201return true;202}203204// Fold constant addresses.205bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr, SDValue &Base,206SDValue &Offset) {207SDLoc DL(Addr);208MVT VT = Addr.getSimpleValueType();209210if (!isa<ConstantSDNode>(Addr))211return false;212213// If the constant is a simm12, we can fold the whole constant and use R0 as214// the base.215int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue();216if (!isInt<12>(CVal))217return false;218Base = CurDAG->getRegister(LoongArch::R0, VT);219Offset = CurDAG->getTargetConstant(SignExtend64<12>(CVal), DL, VT);220return true;221}222223bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) {224// If this is FrameIndex, don't select it.225if (isa<FrameIndexSDNode>(Addr))226return false;227Base = Addr;228return true;229}230231bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,232SDValue &ShAmt) {233// Shift instructions on LoongArch only read the lower 5 or 6 bits of the234// shift amount. If there is an AND on the shift amount, we can bypass it if235// it doesn't affect any of those bits.236if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) {237const APInt &AndMask = N->getConstantOperandAPInt(1);238239// Since the max shift amount is a power of 2 we can subtract 1 to make a240// mask that covers the bits needed to represent all shift amounts.241assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");242APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);243244if (ShMask.isSubsetOf(AndMask)) {245ShAmt = N.getOperand(0);246return true;247}248249// SimplifyDemandedBits may have optimized the mask so try restoring any250// bits that are known zero.251KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0));252if (ShMask.isSubsetOf(AndMask | Known.Zero)) {253ShAmt = N.getOperand(0);254return true;255}256} else if (N.getOpcode() == LoongArchISD::BSTRPICK) {257// Similar to the above AND, if there is a BSTRPICK on the shift amount, we258// can bypass it.259assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");260assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!");261assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!");262uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2);263if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) {264ShAmt = N.getOperand(0);265return true;266}267} else if (N.getOpcode() == ISD::SUB &&268isa<ConstantSDNode>(N.getOperand(0))) {269uint64_t Imm = N.getConstantOperandVal(0);270// If we are shifting by N-X where N == 0 mod Size, then just shift by -X to271// generate a NEG instead of a SUB of a constant.272if (Imm != 0 && Imm % ShiftWidth == 0) {273SDLoc DL(N);274EVT VT = N.getValueType();275SDValue Zero =276CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT);277unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;278MachineSDNode *Neg =279CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1));280ShAmt = SDValue(Neg, 0);281return true;282}283}284285ShAmt = N;286return true;287}288289bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) {290if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&291cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {292Val = N.getOperand(0);293return true;294}295if (N.getOpcode() == LoongArchISD::BSTRPICK &&296N.getConstantOperandVal(1) < UINT64_C(0X1F) &&297N.getConstantOperandVal(2) == UINT64_C(0)) {298Val = N;299return true;300}301MVT VT = N.getSimpleValueType();302if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {303Val = N;304return true;305}306307return false;308}309310bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) {311if (N.getOpcode() == ISD::AND) {312auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1));313if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) {314Val = N.getOperand(0);315return true;316}317}318MVT VT = N.getSimpleValueType();319APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32);320if (CurDAG->MaskedValueIsZero(N, Mask)) {321Val = N;322return true;323}324325return false;326}327328bool LoongArchDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm,329unsigned MinSizeInBits) const {330if (!Subtarget->hasExtLSX())331return false;332333BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N);334335if (!Node)336return false;337338APInt SplatValue, SplatUndef;339unsigned SplatBitSize;340bool HasAnyUndefs;341342if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,343MinSizeInBits, /*IsBigEndian=*/false))344return false;345346Imm = SplatValue;347348return true;349}350351template <unsigned ImmBitSize, bool IsSigned>352bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N, SDValue &SplatVal) {353APInt ImmValue;354EVT EltTy = N->getValueType(0).getVectorElementType();355356if (N->getOpcode() == ISD::BITCAST)357N = N->getOperand(0);358359if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&360ImmValue.getBitWidth() == EltTy.getSizeInBits()) {361if (IsSigned && ImmValue.isSignedIntN(ImmBitSize)) {362SplatVal = CurDAG->getTargetConstant(ImmValue.getSExtValue(), SDLoc(N),363Subtarget->getGRLenVT());364return true;365}366if (!IsSigned && ImmValue.isIntN(ImmBitSize)) {367SplatVal = CurDAG->getTargetConstant(ImmValue.getZExtValue(), SDLoc(N),368Subtarget->getGRLenVT());369return true;370}371}372373return false;374}375376bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N,377SDValue &SplatImm) const {378APInt ImmValue;379EVT EltTy = N->getValueType(0).getVectorElementType();380381if (N->getOpcode() == ISD::BITCAST)382N = N->getOperand(0);383384if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&385ImmValue.getBitWidth() == EltTy.getSizeInBits()) {386int32_t Log2 = (~ImmValue).exactLogBase2();387388if (Log2 != -1) {389SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);390return true;391}392}393394return false;395}396397bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N,398SDValue &SplatImm) const {399APInt ImmValue;400EVT EltTy = N->getValueType(0).getVectorElementType();401402if (N->getOpcode() == ISD::BITCAST)403N = N->getOperand(0);404405if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) &&406ImmValue.getBitWidth() == EltTy.getSizeInBits()) {407int32_t Log2 = ImmValue.exactLogBase2();408409if (Log2 != -1) {410SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy);411return true;412}413}414415return false;416}417418// This pass converts a legalized DAG into a LoongArch-specific DAG, ready419// for instruction scheduling.420FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) {421return new LoongArchDAGToDAGISelLegacy(TM);422}423424425