|  | //===- ARMISelLowering.cpp - ARM DAG Lowering Implementation --------------===// | 
|  | // | 
|  | // 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 the interfaces that ARM uses to lower LLVM code into a | 
|  | // selection DAG. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "ARMISelLowering.h" | 
|  | #include "ARMBaseInstrInfo.h" | 
|  | #include "ARMBaseRegisterInfo.h" | 
|  | #include "ARMCallingConv.h" | 
|  | #include "ARMConstantPoolValue.h" | 
|  | #include "ARMMachineFunctionInfo.h" | 
|  | #include "ARMPerfectShuffle.h" | 
|  | #include "ARMRegisterInfo.h" | 
|  | #include "ARMSelectionDAGInfo.h" | 
|  | #include "ARMSubtarget.h" | 
|  | #include "MCTargetDesc/ARMAddressingModes.h" | 
|  | #include "MCTargetDesc/ARMBaseInfo.h" | 
|  | #include "Utils/ARMBaseInfo.h" | 
|  | #include "llvm/ADT/APFloat.h" | 
|  | #include "llvm/ADT/APInt.h" | 
|  | #include "llvm/ADT/ArrayRef.h" | 
|  | #include "llvm/ADT/BitVector.h" | 
|  | #include "llvm/ADT/DenseMap.h" | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/ADT/SmallPtrSet.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/ADT/StringExtras.h" | 
|  | #include "llvm/ADT/StringRef.h" | 
|  | #include "llvm/ADT/StringSwitch.h" | 
|  | #include "llvm/ADT/Triple.h" | 
|  | #include "llvm/ADT/Twine.h" | 
|  | #include "llvm/Analysis/VectorUtils.h" | 
|  | #include "llvm/CodeGen/CallingConvLower.h" | 
|  | #include "llvm/CodeGen/ISDOpcodes.h" | 
|  | #include "llvm/CodeGen/IntrinsicLowering.h" | 
|  | #include "llvm/CodeGen/MachineBasicBlock.h" | 
|  | #include "llvm/CodeGen/MachineConstantPool.h" | 
|  | #include "llvm/CodeGen/MachineFrameInfo.h" | 
|  | #include "llvm/CodeGen/MachineFunction.h" | 
|  | #include "llvm/CodeGen/MachineInstr.h" | 
|  | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | #include "llvm/CodeGen/MachineJumpTableInfo.h" | 
|  | #include "llvm/CodeGen/MachineMemOperand.h" | 
|  | #include "llvm/CodeGen/MachineOperand.h" | 
|  | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  | #include "llvm/CodeGen/RuntimeLibcalls.h" | 
|  | #include "llvm/CodeGen/SelectionDAG.h" | 
|  | #include "llvm/CodeGen/SelectionDAGNodes.h" | 
|  | #include "llvm/CodeGen/TargetInstrInfo.h" | 
|  | #include "llvm/CodeGen/TargetLowering.h" | 
|  | #include "llvm/CodeGen/TargetOpcodes.h" | 
|  | #include "llvm/CodeGen/TargetRegisterInfo.h" | 
|  | #include "llvm/CodeGen/TargetSubtargetInfo.h" | 
|  | #include "llvm/CodeGen/ValueTypes.h" | 
|  | #include "llvm/IR/Attributes.h" | 
|  | #include "llvm/IR/CallingConv.h" | 
|  | #include "llvm/IR/Constant.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/IR/DataLayout.h" | 
|  | #include "llvm/IR/DebugLoc.h" | 
|  | #include "llvm/IR/DerivedTypes.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/GlobalAlias.h" | 
|  | #include "llvm/IR/GlobalValue.h" | 
|  | #include "llvm/IR/GlobalVariable.h" | 
|  | #include "llvm/IR/IRBuilder.h" | 
|  | #include "llvm/IR/InlineAsm.h" | 
|  | #include "llvm/IR/Instruction.h" | 
|  | #include "llvm/IR/Instructions.h" | 
|  | #include "llvm/IR/IntrinsicInst.h" | 
|  | #include "llvm/IR/Intrinsics.h" | 
|  | #include "llvm/IR/IntrinsicsARM.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "llvm/IR/PatternMatch.h" | 
|  | #include "llvm/IR/Type.h" | 
|  | #include "llvm/IR/User.h" | 
|  | #include "llvm/IR/Value.h" | 
|  | #include "llvm/MC/MCInstrDesc.h" | 
|  | #include "llvm/MC/MCInstrItineraries.h" | 
|  | #include "llvm/MC/MCRegisterInfo.h" | 
|  | #include "llvm/MC/MCSchedule.h" | 
|  | #include "llvm/Support/AtomicOrdering.h" | 
|  | #include "llvm/Support/BranchProbability.h" | 
|  | #include "llvm/Support/Casting.h" | 
|  | #include "llvm/Support/CodeGen.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  | #include "llvm/Support/Compiler.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include "llvm/Support/KnownBits.h" | 
|  | #include "llvm/Support/MachineValueType.h" | 
|  | #include "llvm/Support/MathExtras.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include "llvm/Target/TargetMachine.h" | 
|  | #include "llvm/Target/TargetOptions.h" | 
|  | #include <algorithm> | 
|  | #include <cassert> | 
|  | #include <cstdint> | 
|  | #include <cstdlib> | 
|  | #include <iterator> | 
|  | #include <limits> | 
|  | #include <string> | 
|  | #include <tuple> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace llvm::PatternMatch; | 
|  |  | 
|  | #define DEBUG_TYPE "arm-isel" | 
|  |  | 
|  | STATISTIC(NumTailCalls, "Number of tail calls"); | 
|  | STATISTIC(NumMovwMovt, "Number of GAs materialized with movw + movt"); | 
|  | STATISTIC(NumLoopByVals, "Number of loops generated for byval arguments"); | 
|  | STATISTIC(NumConstpoolPromoted, | 
|  | "Number of constants with their storage promoted into constant pools"); | 
|  |  | 
|  | static cl::opt<bool> | 
|  | ARMInterworking("arm-interworking", cl::Hidden, | 
|  | cl::desc("Enable / disable ARM interworking (for debugging only)"), | 
|  | cl::init(true)); | 
|  |  | 
|  | static cl::opt<bool> EnableConstpoolPromotion( | 
|  | "arm-promote-constant", cl::Hidden, | 
|  | cl::desc("Enable / disable promotion of unnamed_addr constants into " | 
|  | "constant pools"), | 
|  | cl::init(false)); // FIXME: set to true by default once PR32780 is fixed | 
|  | static cl::opt<unsigned> ConstpoolPromotionMaxSize( | 
|  | "arm-promote-constant-max-size", cl::Hidden, | 
|  | cl::desc("Maximum size of constant to promote into a constant pool"), | 
|  | cl::init(64)); | 
|  | static cl::opt<unsigned> ConstpoolPromotionMaxTotal( | 
|  | "arm-promote-constant-max-total", cl::Hidden, | 
|  | cl::desc("Maximum size of ALL constants to promote into a constant pool"), | 
|  | cl::init(128)); | 
|  |  | 
|  | static cl::opt<unsigned> | 
|  | MVEMaxSupportedInterleaveFactor("mve-max-interleave-factor", cl::Hidden, | 
|  | cl::desc("Maximum interleave factor for MVE VLDn to generate."), | 
|  | cl::init(2)); | 
|  |  | 
|  | // The APCS parameter registers. | 
|  | static const MCPhysReg GPRArgRegs[] = { | 
|  | ARM::R0, ARM::R1, ARM::R2, ARM::R3 | 
|  | }; | 
|  |  | 
|  | void ARMTargetLowering::addTypeForNEON(MVT VT, MVT PromotedLdStVT, | 
|  | MVT PromotedBitwiseVT) { | 
|  | if (VT != PromotedLdStVT) { | 
|  | setOperationAction(ISD::LOAD, VT, Promote); | 
|  | AddPromotedToType (ISD::LOAD, VT, PromotedLdStVT); | 
|  |  | 
|  | setOperationAction(ISD::STORE, VT, Promote); | 
|  | AddPromotedToType (ISD::STORE, VT, PromotedLdStVT); | 
|  | } | 
|  |  | 
|  | MVT ElemTy = VT.getVectorElementType(); | 
|  | if (ElemTy != MVT::f64) | 
|  | setOperationAction(ISD::SETCC, VT, Custom); | 
|  | setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom); | 
|  | setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Custom); | 
|  | if (ElemTy == MVT::i32) { | 
|  | setOperationAction(ISD::SINT_TO_FP, VT, Custom); | 
|  | setOperationAction(ISD::UINT_TO_FP, VT, Custom); | 
|  | setOperationAction(ISD::FP_TO_SINT, VT, Custom); | 
|  | setOperationAction(ISD::FP_TO_UINT, VT, Custom); | 
|  | } else { | 
|  | setOperationAction(ISD::SINT_TO_FP, VT, Expand); | 
|  | setOperationAction(ISD::UINT_TO_FP, VT, Expand); | 
|  | setOperationAction(ISD::FP_TO_SINT, VT, Expand); | 
|  | setOperationAction(ISD::FP_TO_UINT, VT, Expand); | 
|  | } | 
|  | setOperationAction(ISD::BUILD_VECTOR,      VT, Custom); | 
|  | setOperationAction(ISD::VECTOR_SHUFFLE,    VT, Custom); | 
|  | setOperationAction(ISD::CONCAT_VECTORS,    VT, Legal); | 
|  | setOperationAction(ISD::EXTRACT_SUBVECTOR, VT, Legal); | 
|  | setOperationAction(ISD::SELECT,            VT, Expand); | 
|  | setOperationAction(ISD::SELECT_CC,         VT, Expand); | 
|  | setOperationAction(ISD::VSELECT,           VT, Expand); | 
|  | setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand); | 
|  | if (VT.isInteger()) { | 
|  | setOperationAction(ISD::SHL, VT, Custom); | 
|  | setOperationAction(ISD::SRA, VT, Custom); | 
|  | setOperationAction(ISD::SRL, VT, Custom); | 
|  | } | 
|  |  | 
|  | // Promote all bit-wise operations. | 
|  | if (VT.isInteger() && VT != PromotedBitwiseVT) { | 
|  | setOperationAction(ISD::AND, VT, Promote); | 
|  | AddPromotedToType (ISD::AND, VT, PromotedBitwiseVT); | 
|  | setOperationAction(ISD::OR,  VT, Promote); | 
|  | AddPromotedToType (ISD::OR,  VT, PromotedBitwiseVT); | 
|  | setOperationAction(ISD::XOR, VT, Promote); | 
|  | AddPromotedToType (ISD::XOR, VT, PromotedBitwiseVT); | 
|  | } | 
|  |  | 
|  | // Neon does not support vector divide/remainder operations. | 
|  | setOperationAction(ISD::SDIV, VT, Expand); | 
|  | setOperationAction(ISD::UDIV, VT, Expand); | 
|  | setOperationAction(ISD::FDIV, VT, Expand); | 
|  | setOperationAction(ISD::SREM, VT, Expand); | 
|  | setOperationAction(ISD::UREM, VT, Expand); | 
|  | setOperationAction(ISD::FREM, VT, Expand); | 
|  |  | 
|  | if (!VT.isFloatingPoint() && | 
|  | VT != MVT::v2i64 && VT != MVT::v1i64) | 
|  | for (auto Opcode : {ISD::ABS, ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}) | 
|  | setOperationAction(Opcode, VT, Legal); | 
|  | if (!VT.isFloatingPoint()) | 
|  | for (auto Opcode : {ISD::SADDSAT, ISD::UADDSAT, ISD::SSUBSAT, ISD::USUBSAT}) | 
|  | setOperationAction(Opcode, VT, Legal); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::addDRTypeForNEON(MVT VT) { | 
|  | addRegisterClass(VT, &ARM::DPRRegClass); | 
|  | addTypeForNEON(VT, MVT::f64, MVT::v2i32); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::addQRTypeForNEON(MVT VT) { | 
|  | addRegisterClass(VT, &ARM::DPairRegClass); | 
|  | addTypeForNEON(VT, MVT::v2f64, MVT::v4i32); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::setAllExpand(MVT VT) { | 
|  | for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc) | 
|  | setOperationAction(Opc, VT, Expand); | 
|  |  | 
|  | // We support these really simple operations even on types where all | 
|  | // the actual arithmetic has to be broken down into simpler | 
|  | // operations or turned into library calls. | 
|  | setOperationAction(ISD::BITCAST, VT, Legal); | 
|  | setOperationAction(ISD::LOAD, VT, Legal); | 
|  | setOperationAction(ISD::STORE, VT, Legal); | 
|  | setOperationAction(ISD::UNDEF, VT, Legal); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::addAllExtLoads(const MVT From, const MVT To, | 
|  | LegalizeAction Action) { | 
|  | setLoadExtAction(ISD::EXTLOAD,  From, To, Action); | 
|  | setLoadExtAction(ISD::ZEXTLOAD, From, To, Action); | 
|  | setLoadExtAction(ISD::SEXTLOAD, From, To, Action); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::addMVEVectorTypes(bool HasMVEFP) { | 
|  | const MVT IntTypes[] = { MVT::v16i8, MVT::v8i16, MVT::v4i32 }; | 
|  |  | 
|  | for (auto VT : IntTypes) { | 
|  | addRegisterClass(VT, &ARM::MQPRRegClass); | 
|  | setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom); | 
|  | setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom); | 
|  | setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Custom); | 
|  | setOperationAction(ISD::BUILD_VECTOR, VT, Custom); | 
|  | setOperationAction(ISD::SHL, VT, Custom); | 
|  | setOperationAction(ISD::SRA, VT, Custom); | 
|  | setOperationAction(ISD::SRL, VT, Custom); | 
|  | setOperationAction(ISD::SMIN, VT, Legal); | 
|  | setOperationAction(ISD::SMAX, VT, Legal); | 
|  | setOperationAction(ISD::UMIN, VT, Legal); | 
|  | setOperationAction(ISD::UMAX, VT, Legal); | 
|  | setOperationAction(ISD::ABS, VT, Legal); | 
|  | setOperationAction(ISD::SETCC, VT, Custom); | 
|  | setOperationAction(ISD::MLOAD, VT, Custom); | 
|  | setOperationAction(ISD::MSTORE, VT, Legal); | 
|  | setOperationAction(ISD::CTLZ, VT, Legal); | 
|  | setOperationAction(ISD::CTTZ, VT, Custom); | 
|  | setOperationAction(ISD::BITREVERSE, VT, Legal); | 
|  | setOperationAction(ISD::BSWAP, VT, Legal); | 
|  | setOperationAction(ISD::SADDSAT, VT, Legal); | 
|  | setOperationAction(ISD::UADDSAT, VT, Legal); | 
|  | setOperationAction(ISD::SSUBSAT, VT, Legal); | 
|  | setOperationAction(ISD::USUBSAT, VT, Legal); | 
|  |  | 
|  | // No native support for these. | 
|  | setOperationAction(ISD::UDIV, VT, Expand); | 
|  | setOperationAction(ISD::SDIV, VT, Expand); | 
|  | setOperationAction(ISD::UREM, VT, Expand); | 
|  | setOperationAction(ISD::SREM, VT, Expand); | 
|  | setOperationAction(ISD::CTPOP, VT, Expand); | 
|  |  | 
|  | // Vector reductions | 
|  | setOperationAction(ISD::VECREDUCE_ADD, VT, Legal); | 
|  | setOperationAction(ISD::VECREDUCE_SMAX, VT, Legal); | 
|  | setOperationAction(ISD::VECREDUCE_UMAX, VT, Legal); | 
|  | setOperationAction(ISD::VECREDUCE_SMIN, VT, Legal); | 
|  | setOperationAction(ISD::VECREDUCE_UMIN, VT, Legal); | 
|  |  | 
|  | if (!HasMVEFP) { | 
|  | setOperationAction(ISD::SINT_TO_FP, VT, Expand); | 
|  | setOperationAction(ISD::UINT_TO_FP, VT, Expand); | 
|  | setOperationAction(ISD::FP_TO_SINT, VT, Expand); | 
|  | setOperationAction(ISD::FP_TO_UINT, VT, Expand); | 
|  | } | 
|  |  | 
|  | // Pre and Post inc are supported on loads and stores | 
|  | for (unsigned im = (unsigned)ISD::PRE_INC; | 
|  | im != (unsigned)ISD::LAST_INDEXED_MODE; ++im) { | 
|  | setIndexedLoadAction(im, VT, Legal); | 
|  | setIndexedStoreAction(im, VT, Legal); | 
|  | setIndexedMaskedLoadAction(im, VT, Legal); | 
|  | setIndexedMaskedStoreAction(im, VT, Legal); | 
|  | } | 
|  | } | 
|  |  | 
|  | const MVT FloatTypes[] = { MVT::v8f16, MVT::v4f32 }; | 
|  | for (auto VT : FloatTypes) { | 
|  | addRegisterClass(VT, &ARM::MQPRRegClass); | 
|  | if (!HasMVEFP) | 
|  | setAllExpand(VT); | 
|  |  | 
|  | // These are legal or custom whether we have MVE.fp or not | 
|  | setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom); | 
|  | setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom); | 
|  | setOperationAction(ISD::INSERT_VECTOR_ELT, VT.getVectorElementType(), Custom); | 
|  | setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Custom); | 
|  | setOperationAction(ISD::BUILD_VECTOR, VT, Custom); | 
|  | setOperationAction(ISD::BUILD_VECTOR, VT.getVectorElementType(), Custom); | 
|  | setOperationAction(ISD::SCALAR_TO_VECTOR, VT, Legal); | 
|  | setOperationAction(ISD::SETCC, VT, Custom); | 
|  | setOperationAction(ISD::MLOAD, VT, Custom); | 
|  | setOperationAction(ISD::MSTORE, VT, Legal); | 
|  |  | 
|  | // Pre and Post inc are supported on loads and stores | 
|  | for (unsigned im = (unsigned)ISD::PRE_INC; | 
|  | im != (unsigned)ISD::LAST_INDEXED_MODE; ++im) { | 
|  | setIndexedLoadAction(im, VT, Legal); | 
|  | setIndexedStoreAction(im, VT, Legal); | 
|  | setIndexedMaskedLoadAction(im, VT, Legal); | 
|  | setIndexedMaskedStoreAction(im, VT, Legal); | 
|  | } | 
|  |  | 
|  | if (HasMVEFP) { | 
|  | setOperationAction(ISD::FMINNUM, VT, Legal); | 
|  | setOperationAction(ISD::FMAXNUM, VT, Legal); | 
|  | setOperationAction(ISD::FROUND, VT, Legal); | 
|  |  | 
|  | // No native support for these. | 
|  | setOperationAction(ISD::FDIV, VT, Expand); | 
|  | setOperationAction(ISD::FREM, VT, Expand); | 
|  | setOperationAction(ISD::FSQRT, VT, Expand); | 
|  | setOperationAction(ISD::FSIN, VT, Expand); | 
|  | setOperationAction(ISD::FCOS, VT, Expand); | 
|  | setOperationAction(ISD::FPOW, VT, Expand); | 
|  | setOperationAction(ISD::FLOG, VT, Expand); | 
|  | setOperationAction(ISD::FLOG2, VT, Expand); | 
|  | setOperationAction(ISD::FLOG10, VT, Expand); | 
|  | setOperationAction(ISD::FEXP, VT, Expand); | 
|  | setOperationAction(ISD::FEXP2, VT, Expand); | 
|  | setOperationAction(ISD::FNEARBYINT, VT, Expand); | 
|  | } | 
|  | } | 
|  |  | 
|  | // We 'support' these types up to bitcast/load/store level, regardless of | 
|  | // MVE integer-only / float support. Only doing FP data processing on the FP | 
|  | // vector types is inhibited at integer-only level. | 
|  | const MVT LongTypes[] = { MVT::v2i64, MVT::v2f64 }; | 
|  | for (auto VT : LongTypes) { | 
|  | addRegisterClass(VT, &ARM::MQPRRegClass); | 
|  | setAllExpand(VT); | 
|  | setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom); | 
|  | setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Custom); | 
|  | setOperationAction(ISD::BUILD_VECTOR, VT, Custom); | 
|  | } | 
|  | // We can do bitwise operations on v2i64 vectors | 
|  | setOperationAction(ISD::AND, MVT::v2i64, Legal); | 
|  | setOperationAction(ISD::OR, MVT::v2i64, Legal); | 
|  | setOperationAction(ISD::XOR, MVT::v2i64, Legal); | 
|  |  | 
|  | // It is legal to extload from v4i8 to v4i16 or v4i32. | 
|  | addAllExtLoads(MVT::v8i16, MVT::v8i8, Legal); | 
|  | addAllExtLoads(MVT::v4i32, MVT::v4i16, Legal); | 
|  | addAllExtLoads(MVT::v4i32, MVT::v4i8, Legal); | 
|  |  | 
|  | // It is legal to sign extend from v4i8/v4i16 to v4i32 or v8i8 to v8i16. | 
|  | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v4i8,  Legal); | 
|  | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v4i16, Legal); | 
|  | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v4i32, Legal); | 
|  | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v8i8,  Legal); | 
|  | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v8i16, Legal); | 
|  |  | 
|  | // Some truncating stores are legal too. | 
|  | setTruncStoreAction(MVT::v4i32, MVT::v4i16, Legal); | 
|  | setTruncStoreAction(MVT::v4i32, MVT::v4i8,  Legal); | 
|  | setTruncStoreAction(MVT::v8i16, MVT::v8i8,  Legal); | 
|  |  | 
|  | // Pre and Post inc on these are legal, given the correct extends | 
|  | for (unsigned im = (unsigned)ISD::PRE_INC; | 
|  | im != (unsigned)ISD::LAST_INDEXED_MODE; ++im) { | 
|  | for (auto VT : {MVT::v8i8, MVT::v4i8, MVT::v4i16}) { | 
|  | setIndexedLoadAction(im, VT, Legal); | 
|  | setIndexedStoreAction(im, VT, Legal); | 
|  | setIndexedMaskedLoadAction(im, VT, Legal); | 
|  | setIndexedMaskedStoreAction(im, VT, Legal); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Predicate types | 
|  | const MVT pTypes[] = {MVT::v16i1, MVT::v8i1, MVT::v4i1}; | 
|  | for (auto VT : pTypes) { | 
|  | addRegisterClass(VT, &ARM::VCCRRegClass); | 
|  | setOperationAction(ISD::BUILD_VECTOR, VT, Custom); | 
|  | setOperationAction(ISD::VECTOR_SHUFFLE, VT, Custom); | 
|  | setOperationAction(ISD::EXTRACT_SUBVECTOR, VT, Custom); | 
|  | setOperationAction(ISD::CONCAT_VECTORS, VT, Custom); | 
|  | setOperationAction(ISD::INSERT_VECTOR_ELT, VT, Custom); | 
|  | setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT, Custom); | 
|  | setOperationAction(ISD::SETCC, VT, Custom); | 
|  | setOperationAction(ISD::SCALAR_TO_VECTOR, VT, Expand); | 
|  | setOperationAction(ISD::LOAD, VT, Custom); | 
|  | setOperationAction(ISD::STORE, VT, Custom); | 
|  | } | 
|  | } | 
|  |  | 
|  | ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM, | 
|  | const ARMSubtarget &STI) | 
|  | : TargetLowering(TM), Subtarget(&STI) { | 
|  | RegInfo = Subtarget->getRegisterInfo(); | 
|  | Itins = Subtarget->getInstrItineraryData(); | 
|  |  | 
|  | setBooleanContents(ZeroOrOneBooleanContent); | 
|  | setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); | 
|  |  | 
|  | if (!Subtarget->isTargetDarwin() && !Subtarget->isTargetIOS() && | 
|  | !Subtarget->isTargetWatchOS()) { | 
|  | bool IsHFTarget = TM.Options.FloatABIType == FloatABI::Hard; | 
|  | for (int LCID = 0; LCID < RTLIB::UNKNOWN_LIBCALL; ++LCID) | 
|  | setLibcallCallingConv(static_cast<RTLIB::Libcall>(LCID), | 
|  | IsHFTarget ? CallingConv::ARM_AAPCS_VFP | 
|  | : CallingConv::ARM_AAPCS); | 
|  | } | 
|  |  | 
|  | if (Subtarget->isTargetMachO()) { | 
|  | // Uses VFP for Thumb libfuncs if available. | 
|  | if (Subtarget->isThumb() && Subtarget->hasVFP2Base() && | 
|  | Subtarget->hasARMOps() && !Subtarget->useSoftFloat()) { | 
|  | static const struct { | 
|  | const RTLIB::Libcall Op; | 
|  | const char * const Name; | 
|  | const ISD::CondCode Cond; | 
|  | } LibraryCalls[] = { | 
|  | // Single-precision floating-point arithmetic. | 
|  | { RTLIB::ADD_F32, "__addsf3vfp", ISD::SETCC_INVALID }, | 
|  | { RTLIB::SUB_F32, "__subsf3vfp", ISD::SETCC_INVALID }, | 
|  | { RTLIB::MUL_F32, "__mulsf3vfp", ISD::SETCC_INVALID }, | 
|  | { RTLIB::DIV_F32, "__divsf3vfp", ISD::SETCC_INVALID }, | 
|  |  | 
|  | // Double-precision floating-point arithmetic. | 
|  | { RTLIB::ADD_F64, "__adddf3vfp", ISD::SETCC_INVALID }, | 
|  | { RTLIB::SUB_F64, "__subdf3vfp", ISD::SETCC_INVALID }, | 
|  | { RTLIB::MUL_F64, "__muldf3vfp", ISD::SETCC_INVALID }, | 
|  | { RTLIB::DIV_F64, "__divdf3vfp", ISD::SETCC_INVALID }, | 
|  |  | 
|  | // Single-precision comparisons. | 
|  | { RTLIB::OEQ_F32, "__eqsf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::UNE_F32, "__nesf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::OLT_F32, "__ltsf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::OLE_F32, "__lesf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::OGE_F32, "__gesf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::OGT_F32, "__gtsf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::UO_F32,  "__unordsf2vfp", ISD::SETNE }, | 
|  |  | 
|  | // Double-precision comparisons. | 
|  | { RTLIB::OEQ_F64, "__eqdf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::UNE_F64, "__nedf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::OLT_F64, "__ltdf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::OLE_F64, "__ledf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::OGE_F64, "__gedf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::OGT_F64, "__gtdf2vfp",    ISD::SETNE }, | 
|  | { RTLIB::UO_F64,  "__unorddf2vfp", ISD::SETNE }, | 
|  |  | 
|  | // Floating-point to integer conversions. | 
|  | // i64 conversions are done via library routines even when generating VFP | 
|  | // instructions, so use the same ones. | 
|  | { RTLIB::FPTOSINT_F64_I32, "__fixdfsivfp",    ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPTOUINT_F64_I32, "__fixunsdfsivfp", ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPTOSINT_F32_I32, "__fixsfsivfp",    ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPTOUINT_F32_I32, "__fixunssfsivfp", ISD::SETCC_INVALID }, | 
|  |  | 
|  | // Conversions between floating types. | 
|  | { RTLIB::FPROUND_F64_F32, "__truncdfsf2vfp",  ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPEXT_F32_F64,   "__extendsfdf2vfp", ISD::SETCC_INVALID }, | 
|  |  | 
|  | // Integer to floating-point conversions. | 
|  | // i64 conversions are done via library routines even when generating VFP | 
|  | // instructions, so use the same ones. | 
|  | // FIXME: There appears to be some naming inconsistency in ARM libgcc: | 
|  | // e.g., __floatunsidf vs. __floatunssidfvfp. | 
|  | { RTLIB::SINTTOFP_I32_F64, "__floatsidfvfp",    ISD::SETCC_INVALID }, | 
|  | { RTLIB::UINTTOFP_I32_F64, "__floatunssidfvfp", ISD::SETCC_INVALID }, | 
|  | { RTLIB::SINTTOFP_I32_F32, "__floatsisfvfp",    ISD::SETCC_INVALID }, | 
|  | { RTLIB::UINTTOFP_I32_F32, "__floatunssisfvfp", ISD::SETCC_INVALID }, | 
|  | }; | 
|  |  | 
|  | for (const auto &LC : LibraryCalls) { | 
|  | setLibcallName(LC.Op, LC.Name); | 
|  | if (LC.Cond != ISD::SETCC_INVALID) | 
|  | setCmpLibcallCC(LC.Op, LC.Cond); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // These libcalls are not available in 32-bit. | 
|  | setLibcallName(RTLIB::SHL_I128, nullptr); | 
|  | setLibcallName(RTLIB::SRL_I128, nullptr); | 
|  | setLibcallName(RTLIB::SRA_I128, nullptr); | 
|  |  | 
|  | // RTLIB | 
|  | if (Subtarget->isAAPCS_ABI() && | 
|  | (Subtarget->isTargetAEABI() || Subtarget->isTargetGNUAEABI() || | 
|  | Subtarget->isTargetMuslAEABI() || Subtarget->isTargetAndroid())) { | 
|  | static const struct { | 
|  | const RTLIB::Libcall Op; | 
|  | const char * const Name; | 
|  | const CallingConv::ID CC; | 
|  | const ISD::CondCode Cond; | 
|  | } LibraryCalls[] = { | 
|  | // Double-precision floating-point arithmetic helper functions | 
|  | // RTABI chapter 4.1.2, Table 2 | 
|  | { RTLIB::ADD_F64, "__aeabi_dadd", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::DIV_F64, "__aeabi_ddiv", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::MUL_F64, "__aeabi_dmul", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SUB_F64, "__aeabi_dsub", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  |  | 
|  | // Double-precision floating-point comparison helper functions | 
|  | // RTABI chapter 4.1.2, Table 3 | 
|  | { RTLIB::OEQ_F64, "__aeabi_dcmpeq", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  | { RTLIB::UNE_F64, "__aeabi_dcmpeq", CallingConv::ARM_AAPCS, ISD::SETEQ }, | 
|  | { RTLIB::OLT_F64, "__aeabi_dcmplt", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  | { RTLIB::OLE_F64, "__aeabi_dcmple", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  | { RTLIB::OGE_F64, "__aeabi_dcmpge", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  | { RTLIB::OGT_F64, "__aeabi_dcmpgt", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  | { RTLIB::UO_F64,  "__aeabi_dcmpun", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  |  | 
|  | // Single-precision floating-point arithmetic helper functions | 
|  | // RTABI chapter 4.1.2, Table 4 | 
|  | { RTLIB::ADD_F32, "__aeabi_fadd", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::DIV_F32, "__aeabi_fdiv", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::MUL_F32, "__aeabi_fmul", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SUB_F32, "__aeabi_fsub", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  |  | 
|  | // Single-precision floating-point comparison helper functions | 
|  | // RTABI chapter 4.1.2, Table 5 | 
|  | { RTLIB::OEQ_F32, "__aeabi_fcmpeq", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  | { RTLIB::UNE_F32, "__aeabi_fcmpeq", CallingConv::ARM_AAPCS, ISD::SETEQ }, | 
|  | { RTLIB::OLT_F32, "__aeabi_fcmplt", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  | { RTLIB::OLE_F32, "__aeabi_fcmple", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  | { RTLIB::OGE_F32, "__aeabi_fcmpge", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  | { RTLIB::OGT_F32, "__aeabi_fcmpgt", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  | { RTLIB::UO_F32,  "__aeabi_fcmpun", CallingConv::ARM_AAPCS, ISD::SETNE }, | 
|  |  | 
|  | // Floating-point to integer conversions. | 
|  | // RTABI chapter 4.1.2, Table 6 | 
|  | { RTLIB::FPTOSINT_F64_I32, "__aeabi_d2iz",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPTOUINT_F64_I32, "__aeabi_d2uiz", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPTOSINT_F64_I64, "__aeabi_d2lz",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPTOUINT_F64_I64, "__aeabi_d2ulz", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPTOSINT_F32_I32, "__aeabi_f2iz",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPTOUINT_F32_I32, "__aeabi_f2uiz", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPTOSINT_F32_I64, "__aeabi_f2lz",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPTOUINT_F32_I64, "__aeabi_f2ulz", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  |  | 
|  | // Conversions between floating types. | 
|  | // RTABI chapter 4.1.2, Table 7 | 
|  | { RTLIB::FPROUND_F64_F32, "__aeabi_d2f", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPROUND_F64_F16, "__aeabi_d2h", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::FPEXT_F32_F64,   "__aeabi_f2d", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  |  | 
|  | // Integer to floating-point conversions. | 
|  | // RTABI chapter 4.1.2, Table 8 | 
|  | { RTLIB::SINTTOFP_I32_F64, "__aeabi_i2d",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::UINTTOFP_I32_F64, "__aeabi_ui2d", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SINTTOFP_I64_F64, "__aeabi_l2d",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::UINTTOFP_I64_F64, "__aeabi_ul2d", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SINTTOFP_I32_F32, "__aeabi_i2f",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::UINTTOFP_I32_F32, "__aeabi_ui2f", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SINTTOFP_I64_F32, "__aeabi_l2f",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::UINTTOFP_I64_F32, "__aeabi_ul2f", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  |  | 
|  | // Long long helper functions | 
|  | // RTABI chapter 4.2, Table 9 | 
|  | { RTLIB::MUL_I64, "__aeabi_lmul", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SHL_I64, "__aeabi_llsl", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SRL_I64, "__aeabi_llsr", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SRA_I64, "__aeabi_lasr", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  |  | 
|  | // Integer division functions | 
|  | // RTABI chapter 4.3.1 | 
|  | { RTLIB::SDIV_I8,  "__aeabi_idiv",     CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SDIV_I16, "__aeabi_idiv",     CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SDIV_I32, "__aeabi_idiv",     CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::SDIV_I64, "__aeabi_ldivmod",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::UDIV_I8,  "__aeabi_uidiv",    CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::UDIV_I16, "__aeabi_uidiv",    CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::UDIV_I32, "__aeabi_uidiv",    CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::UDIV_I64, "__aeabi_uldivmod", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | }; | 
|  |  | 
|  | for (const auto &LC : LibraryCalls) { | 
|  | setLibcallName(LC.Op, LC.Name); | 
|  | setLibcallCallingConv(LC.Op, LC.CC); | 
|  | if (LC.Cond != ISD::SETCC_INVALID) | 
|  | setCmpLibcallCC(LC.Op, LC.Cond); | 
|  | } | 
|  |  | 
|  | // EABI dependent RTLIB | 
|  | if (TM.Options.EABIVersion == EABI::EABI4 || | 
|  | TM.Options.EABIVersion == EABI::EABI5) { | 
|  | static const struct { | 
|  | const RTLIB::Libcall Op; | 
|  | const char *const Name; | 
|  | const CallingConv::ID CC; | 
|  | const ISD::CondCode Cond; | 
|  | } MemOpsLibraryCalls[] = { | 
|  | // Memory operations | 
|  | // RTABI chapter 4.3.4 | 
|  | { RTLIB::MEMCPY,  "__aeabi_memcpy",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::MEMMOVE, "__aeabi_memmove", CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | { RTLIB::MEMSET,  "__aeabi_memset",  CallingConv::ARM_AAPCS, ISD::SETCC_INVALID }, | 
|  | }; | 
|  |  | 
|  | for (const auto &LC : MemOpsLibraryCalls) { | 
|  | setLibcallName(LC.Op, LC.Name); | 
|  | setLibcallCallingConv(LC.Op, LC.CC); | 
|  | if (LC.Cond != ISD::SETCC_INVALID) | 
|  | setCmpLibcallCC(LC.Op, LC.Cond); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Subtarget->isTargetWindows()) { | 
|  | static const struct { | 
|  | const RTLIB::Libcall Op; | 
|  | const char * const Name; | 
|  | const CallingConv::ID CC; | 
|  | } LibraryCalls[] = { | 
|  | { RTLIB::FPTOSINT_F32_I64, "__stoi64", CallingConv::ARM_AAPCS_VFP }, | 
|  | { RTLIB::FPTOSINT_F64_I64, "__dtoi64", CallingConv::ARM_AAPCS_VFP }, | 
|  | { RTLIB::FPTOUINT_F32_I64, "__stou64", CallingConv::ARM_AAPCS_VFP }, | 
|  | { RTLIB::FPTOUINT_F64_I64, "__dtou64", CallingConv::ARM_AAPCS_VFP }, | 
|  | { RTLIB::SINTTOFP_I64_F32, "__i64tos", CallingConv::ARM_AAPCS_VFP }, | 
|  | { RTLIB::SINTTOFP_I64_F64, "__i64tod", CallingConv::ARM_AAPCS_VFP }, | 
|  | { RTLIB::UINTTOFP_I64_F32, "__u64tos", CallingConv::ARM_AAPCS_VFP }, | 
|  | { RTLIB::UINTTOFP_I64_F64, "__u64tod", CallingConv::ARM_AAPCS_VFP }, | 
|  | }; | 
|  |  | 
|  | for (const auto &LC : LibraryCalls) { | 
|  | setLibcallName(LC.Op, LC.Name); | 
|  | setLibcallCallingConv(LC.Op, LC.CC); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Use divmod compiler-rt calls for iOS 5.0 and later. | 
|  | if (Subtarget->isTargetMachO() && | 
|  | !(Subtarget->isTargetIOS() && | 
|  | Subtarget->getTargetTriple().isOSVersionLT(5, 0))) { | 
|  | setLibcallName(RTLIB::SDIVREM_I32, "__divmodsi4"); | 
|  | setLibcallName(RTLIB::UDIVREM_I32, "__udivmodsi4"); | 
|  | } | 
|  |  | 
|  | // The half <-> float conversion functions are always soft-float on | 
|  | // non-watchos platforms, but are needed for some targets which use a | 
|  | // hard-float calling convention by default. | 
|  | if (!Subtarget->isTargetWatchABI()) { | 
|  | if (Subtarget->isAAPCS_ABI()) { | 
|  | setLibcallCallingConv(RTLIB::FPROUND_F32_F16, CallingConv::ARM_AAPCS); | 
|  | setLibcallCallingConv(RTLIB::FPROUND_F64_F16, CallingConv::ARM_AAPCS); | 
|  | setLibcallCallingConv(RTLIB::FPEXT_F16_F32, CallingConv::ARM_AAPCS); | 
|  | } else { | 
|  | setLibcallCallingConv(RTLIB::FPROUND_F32_F16, CallingConv::ARM_APCS); | 
|  | setLibcallCallingConv(RTLIB::FPROUND_F64_F16, CallingConv::ARM_APCS); | 
|  | setLibcallCallingConv(RTLIB::FPEXT_F16_F32, CallingConv::ARM_APCS); | 
|  | } | 
|  | } | 
|  |  | 
|  | // In EABI, these functions have an __aeabi_ prefix, but in GNUEABI they have | 
|  | // a __gnu_ prefix (which is the default). | 
|  | if (Subtarget->isTargetAEABI()) { | 
|  | static const struct { | 
|  | const RTLIB::Libcall Op; | 
|  | const char * const Name; | 
|  | const CallingConv::ID CC; | 
|  | } LibraryCalls[] = { | 
|  | { RTLIB::FPROUND_F32_F16, "__aeabi_f2h", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::FPROUND_F64_F16, "__aeabi_d2h", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::FPEXT_F16_F32, "__aeabi_h2f", CallingConv::ARM_AAPCS }, | 
|  | }; | 
|  |  | 
|  | for (const auto &LC : LibraryCalls) { | 
|  | setLibcallName(LC.Op, LC.Name); | 
|  | setLibcallCallingConv(LC.Op, LC.CC); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Subtarget->isThumb1Only()) | 
|  | addRegisterClass(MVT::i32, &ARM::tGPRRegClass); | 
|  | else | 
|  | addRegisterClass(MVT::i32, &ARM::GPRRegClass); | 
|  |  | 
|  | if (!Subtarget->useSoftFloat() && !Subtarget->isThumb1Only() && | 
|  | Subtarget->hasFPRegs()) { | 
|  | addRegisterClass(MVT::f32, &ARM::SPRRegClass); | 
|  | addRegisterClass(MVT::f64, &ARM::DPRRegClass); | 
|  | if (!Subtarget->hasVFP2Base()) | 
|  | setAllExpand(MVT::f32); | 
|  | if (!Subtarget->hasFP64()) | 
|  | setAllExpand(MVT::f64); | 
|  | } | 
|  |  | 
|  | if (Subtarget->hasFullFP16()) { | 
|  | addRegisterClass(MVT::f16, &ARM::HPRRegClass); | 
|  | setOperationAction(ISD::BITCAST, MVT::i16, Custom); | 
|  | setOperationAction(ISD::BITCAST, MVT::f16, Custom); | 
|  |  | 
|  | setOperationAction(ISD::FMINNUM, MVT::f16, Legal); | 
|  | setOperationAction(ISD::FMAXNUM, MVT::f16, Legal); | 
|  | } | 
|  |  | 
|  | for (MVT VT : MVT::fixedlen_vector_valuetypes()) { | 
|  | for (MVT InnerVT : MVT::fixedlen_vector_valuetypes()) { | 
|  | setTruncStoreAction(VT, InnerVT, Expand); | 
|  | addAllExtLoads(VT, InnerVT, Expand); | 
|  | } | 
|  |  | 
|  | setOperationAction(ISD::MULHS, VT, Expand); | 
|  | setOperationAction(ISD::SMUL_LOHI, VT, Expand); | 
|  | setOperationAction(ISD::MULHU, VT, Expand); | 
|  | setOperationAction(ISD::UMUL_LOHI, VT, Expand); | 
|  |  | 
|  | setOperationAction(ISD::BSWAP, VT, Expand); | 
|  | } | 
|  |  | 
|  | setOperationAction(ISD::ConstantFP, MVT::f32, Custom); | 
|  | setOperationAction(ISD::ConstantFP, MVT::f64, Custom); | 
|  |  | 
|  | setOperationAction(ISD::READ_REGISTER, MVT::i64, Custom); | 
|  | setOperationAction(ISD::WRITE_REGISTER, MVT::i64, Custom); | 
|  |  | 
|  | if (Subtarget->hasMVEIntegerOps()) | 
|  | addMVEVectorTypes(Subtarget->hasMVEFloatOps()); | 
|  |  | 
|  | // Combine low-overhead loop intrinsics so that we can lower i1 types. | 
|  | if (Subtarget->hasLOB()) { | 
|  | setTargetDAGCombine(ISD::BRCOND); | 
|  | setTargetDAGCombine(ISD::BR_CC); | 
|  | } | 
|  |  | 
|  | if (Subtarget->hasNEON()) { | 
|  | addDRTypeForNEON(MVT::v2f32); | 
|  | addDRTypeForNEON(MVT::v8i8); | 
|  | addDRTypeForNEON(MVT::v4i16); | 
|  | addDRTypeForNEON(MVT::v2i32); | 
|  | addDRTypeForNEON(MVT::v1i64); | 
|  |  | 
|  | addQRTypeForNEON(MVT::v4f32); | 
|  | addQRTypeForNEON(MVT::v2f64); | 
|  | addQRTypeForNEON(MVT::v16i8); | 
|  | addQRTypeForNEON(MVT::v8i16); | 
|  | addQRTypeForNEON(MVT::v4i32); | 
|  | addQRTypeForNEON(MVT::v2i64); | 
|  |  | 
|  | if (Subtarget->hasFullFP16()) { | 
|  | addQRTypeForNEON(MVT::v8f16); | 
|  | addDRTypeForNEON(MVT::v4f16); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Subtarget->hasMVEIntegerOps() || Subtarget->hasNEON()) { | 
|  | // v2f64 is legal so that QR subregs can be extracted as f64 elements, but | 
|  | // none of Neon, MVE or VFP supports any arithmetic operations on it. | 
|  | setOperationAction(ISD::FADD, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FSUB, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FMUL, MVT::v2f64, Expand); | 
|  | // FIXME: Code duplication: FDIV and FREM are expanded always, see | 
|  | // ARMTargetLowering::addTypeForNEON method for details. | 
|  | setOperationAction(ISD::FDIV, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FREM, MVT::v2f64, Expand); | 
|  | // FIXME: Create unittest. | 
|  | // In another words, find a way when "copysign" appears in DAG with vector | 
|  | // operands. | 
|  | setOperationAction(ISD::FCOPYSIGN, MVT::v2f64, Expand); | 
|  | // FIXME: Code duplication: SETCC has custom operation action, see | 
|  | // ARMTargetLowering::addTypeForNEON method for details. | 
|  | setOperationAction(ISD::SETCC, MVT::v2f64, Expand); | 
|  | // FIXME: Create unittest for FNEG and for FABS. | 
|  | setOperationAction(ISD::FNEG, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FABS, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FSQRT, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FSIN, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FCOS, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FPOW, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FLOG, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FLOG2, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FLOG10, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FEXP, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FEXP2, MVT::v2f64, Expand); | 
|  | // FIXME: Create unittest for FCEIL, FTRUNC, FRINT, FNEARBYINT, FFLOOR. | 
|  | setOperationAction(ISD::FCEIL, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FTRUNC, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FRINT, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FNEARBYINT, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FFLOOR, MVT::v2f64, Expand); | 
|  | setOperationAction(ISD::FMA, MVT::v2f64, Expand); | 
|  | } | 
|  |  | 
|  | if (Subtarget->hasNEON()) { | 
|  | // The same with v4f32. But keep in mind that vadd, vsub, vmul are natively | 
|  | // supported for v4f32. | 
|  | setOperationAction(ISD::FSQRT, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FSIN, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FCOS, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FPOW, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FLOG, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FLOG2, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FLOG10, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FEXP, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FEXP2, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FCEIL, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FTRUNC, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FRINT, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FNEARBYINT, MVT::v4f32, Expand); | 
|  | setOperationAction(ISD::FFLOOR, MVT::v4f32, Expand); | 
|  |  | 
|  | // Mark v2f32 intrinsics. | 
|  | setOperationAction(ISD::FSQRT, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FSIN, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FCOS, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FPOW, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FLOG, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FLOG2, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FLOG10, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FEXP, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FEXP2, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FCEIL, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FTRUNC, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FRINT, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FNEARBYINT, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FFLOOR, MVT::v2f32, Expand); | 
|  |  | 
|  | // Neon does not support some operations on v1i64 and v2i64 types. | 
|  | setOperationAction(ISD::MUL, MVT::v1i64, Expand); | 
|  | // Custom handling for some quad-vector types to detect VMULL. | 
|  | setOperationAction(ISD::MUL, MVT::v8i16, Custom); | 
|  | setOperationAction(ISD::MUL, MVT::v4i32, Custom); | 
|  | setOperationAction(ISD::MUL, MVT::v2i64, Custom); | 
|  | // Custom handling for some vector types to avoid expensive expansions | 
|  | setOperationAction(ISD::SDIV, MVT::v4i16, Custom); | 
|  | setOperationAction(ISD::SDIV, MVT::v8i8, Custom); | 
|  | setOperationAction(ISD::UDIV, MVT::v4i16, Custom); | 
|  | setOperationAction(ISD::UDIV, MVT::v8i8, Custom); | 
|  | // Neon does not have single instruction SINT_TO_FP and UINT_TO_FP with | 
|  | // a destination type that is wider than the source, and nor does | 
|  | // it have a FP_TO_[SU]INT instruction with a narrower destination than | 
|  | // source. | 
|  | setOperationAction(ISD::SINT_TO_FP, MVT::v4i16, Custom); | 
|  | setOperationAction(ISD::SINT_TO_FP, MVT::v8i16, Custom); | 
|  | setOperationAction(ISD::UINT_TO_FP, MVT::v4i16, Custom); | 
|  | setOperationAction(ISD::UINT_TO_FP, MVT::v8i16, Custom); | 
|  | setOperationAction(ISD::FP_TO_UINT, MVT::v4i16, Custom); | 
|  | setOperationAction(ISD::FP_TO_UINT, MVT::v8i16, Custom); | 
|  | setOperationAction(ISD::FP_TO_SINT, MVT::v4i16, Custom); | 
|  | setOperationAction(ISD::FP_TO_SINT, MVT::v8i16, Custom); | 
|  |  | 
|  | setOperationAction(ISD::FP_ROUND,   MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FP_EXTEND,  MVT::v2f64, Expand); | 
|  |  | 
|  | // NEON does not have single instruction CTPOP for vectors with element | 
|  | // types wider than 8-bits.  However, custom lowering can leverage the | 
|  | // v8i8/v16i8 vcnt instruction. | 
|  | setOperationAction(ISD::CTPOP,      MVT::v2i32, Custom); | 
|  | setOperationAction(ISD::CTPOP,      MVT::v4i32, Custom); | 
|  | setOperationAction(ISD::CTPOP,      MVT::v4i16, Custom); | 
|  | setOperationAction(ISD::CTPOP,      MVT::v8i16, Custom); | 
|  | setOperationAction(ISD::CTPOP,      MVT::v1i64, Custom); | 
|  | setOperationAction(ISD::CTPOP,      MVT::v2i64, Custom); | 
|  |  | 
|  | setOperationAction(ISD::CTLZ,       MVT::v1i64, Expand); | 
|  | setOperationAction(ISD::CTLZ,       MVT::v2i64, Expand); | 
|  |  | 
|  | // NEON does not have single instruction CTTZ for vectors. | 
|  | setOperationAction(ISD::CTTZ, MVT::v8i8, Custom); | 
|  | setOperationAction(ISD::CTTZ, MVT::v4i16, Custom); | 
|  | setOperationAction(ISD::CTTZ, MVT::v2i32, Custom); | 
|  | setOperationAction(ISD::CTTZ, MVT::v1i64, Custom); | 
|  |  | 
|  | setOperationAction(ISD::CTTZ, MVT::v16i8, Custom); | 
|  | setOperationAction(ISD::CTTZ, MVT::v8i16, Custom); | 
|  | setOperationAction(ISD::CTTZ, MVT::v4i32, Custom); | 
|  | setOperationAction(ISD::CTTZ, MVT::v2i64, Custom); | 
|  |  | 
|  | setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::v8i8, Custom); | 
|  | setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::v4i16, Custom); | 
|  | setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::v2i32, Custom); | 
|  | setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::v1i64, Custom); | 
|  |  | 
|  | setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::v16i8, Custom); | 
|  | setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::v8i16, Custom); | 
|  | setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::v4i32, Custom); | 
|  | setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::v2i64, Custom); | 
|  |  | 
|  | // NEON only has FMA instructions as of VFP4. | 
|  | if (!Subtarget->hasVFP4Base()) { | 
|  | setOperationAction(ISD::FMA, MVT::v2f32, Expand); | 
|  | setOperationAction(ISD::FMA, MVT::v4f32, Expand); | 
|  | } | 
|  |  | 
|  | setTargetDAGCombine(ISD::SHL); | 
|  | setTargetDAGCombine(ISD::SRL); | 
|  | setTargetDAGCombine(ISD::SRA); | 
|  | setTargetDAGCombine(ISD::FP_TO_SINT); | 
|  | setTargetDAGCombine(ISD::FP_TO_UINT); | 
|  | setTargetDAGCombine(ISD::FDIV); | 
|  | setTargetDAGCombine(ISD::LOAD); | 
|  |  | 
|  | // It is legal to extload from v4i8 to v4i16 or v4i32. | 
|  | for (MVT Ty : {MVT::v8i8, MVT::v4i8, MVT::v2i8, MVT::v4i16, MVT::v2i16, | 
|  | MVT::v2i32}) { | 
|  | for (MVT VT : MVT::integer_fixedlen_vector_valuetypes()) { | 
|  | setLoadExtAction(ISD::EXTLOAD, VT, Ty, Legal); | 
|  | setLoadExtAction(ISD::ZEXTLOAD, VT, Ty, Legal); | 
|  | setLoadExtAction(ISD::SEXTLOAD, VT, Ty, Legal); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Subtarget->hasNEON() || Subtarget->hasMVEIntegerOps()) { | 
|  | setTargetDAGCombine(ISD::BUILD_VECTOR); | 
|  | setTargetDAGCombine(ISD::VECTOR_SHUFFLE); | 
|  | setTargetDAGCombine(ISD::INSERT_VECTOR_ELT); | 
|  | setTargetDAGCombine(ISD::EXTRACT_VECTOR_ELT); | 
|  | setTargetDAGCombine(ISD::STORE); | 
|  | setTargetDAGCombine(ISD::SIGN_EXTEND); | 
|  | setTargetDAGCombine(ISD::ZERO_EXTEND); | 
|  | setTargetDAGCombine(ISD::ANY_EXTEND); | 
|  | setTargetDAGCombine(ISD::INTRINSIC_WO_CHAIN); | 
|  | setTargetDAGCombine(ISD::INTRINSIC_W_CHAIN); | 
|  | setTargetDAGCombine(ISD::INTRINSIC_VOID); | 
|  | setTargetDAGCombine(ISD::VECREDUCE_ADD); | 
|  | setTargetDAGCombine(ISD::ADD); | 
|  | setTargetDAGCombine(ISD::BITCAST); | 
|  | } | 
|  | if (Subtarget->hasMVEIntegerOps()) { | 
|  | setTargetDAGCombine(ISD::SMIN); | 
|  | setTargetDAGCombine(ISD::UMIN); | 
|  | setTargetDAGCombine(ISD::SMAX); | 
|  | setTargetDAGCombine(ISD::UMAX); | 
|  | } | 
|  |  | 
|  | if (!Subtarget->hasFP64()) { | 
|  | // When targeting a floating-point unit with only single-precision | 
|  | // operations, f64 is legal for the few double-precision instructions which | 
|  | // are present However, no double-precision operations other than moves, | 
|  | // loads and stores are provided by the hardware. | 
|  | setOperationAction(ISD::FADD,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FSUB,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FMUL,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FMA,        MVT::f64, Expand); | 
|  | setOperationAction(ISD::FDIV,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FREM,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FCOPYSIGN,  MVT::f64, Expand); | 
|  | setOperationAction(ISD::FGETSIGN,   MVT::f64, Expand); | 
|  | setOperationAction(ISD::FNEG,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FABS,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FSQRT,      MVT::f64, Expand); | 
|  | setOperationAction(ISD::FSIN,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FCOS,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FPOW,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FLOG,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FLOG2,      MVT::f64, Expand); | 
|  | setOperationAction(ISD::FLOG10,     MVT::f64, Expand); | 
|  | setOperationAction(ISD::FEXP,       MVT::f64, Expand); | 
|  | setOperationAction(ISD::FEXP2,      MVT::f64, Expand); | 
|  | setOperationAction(ISD::FCEIL,      MVT::f64, Expand); | 
|  | setOperationAction(ISD::FTRUNC,     MVT::f64, Expand); | 
|  | setOperationAction(ISD::FRINT,      MVT::f64, Expand); | 
|  | setOperationAction(ISD::FNEARBYINT, MVT::f64, Expand); | 
|  | setOperationAction(ISD::FFLOOR,     MVT::f64, Expand); | 
|  | setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom); | 
|  | setOperationAction(ISD::UINT_TO_FP, MVT::i32, Custom); | 
|  | setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); | 
|  | setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); | 
|  | setOperationAction(ISD::FP_TO_SINT, MVT::f64, Custom); | 
|  | setOperationAction(ISD::FP_TO_UINT, MVT::f64, Custom); | 
|  | setOperationAction(ISD::FP_ROUND,   MVT::f32, Custom); | 
|  | setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i32, Custom); | 
|  | setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::i32, Custom); | 
|  | setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::f64, Custom); | 
|  | setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::f64, Custom); | 
|  | setOperationAction(ISD::STRICT_FP_ROUND,   MVT::f32, Custom); | 
|  | } | 
|  |  | 
|  | if (!Subtarget->hasFP64() || !Subtarget->hasFPARMv8Base()) { | 
|  | setOperationAction(ISD::FP_EXTEND,  MVT::f64, Custom); | 
|  | setOperationAction(ISD::STRICT_FP_EXTEND, MVT::f64, Custom); | 
|  | if (Subtarget->hasFullFP16()) { | 
|  | setOperationAction(ISD::FP_ROUND,  MVT::f16, Custom); | 
|  | setOperationAction(ISD::STRICT_FP_ROUND, MVT::f16, Custom); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!Subtarget->hasFP16()) { | 
|  | setOperationAction(ISD::FP_EXTEND,  MVT::f32, Custom); | 
|  | setOperationAction(ISD::STRICT_FP_EXTEND, MVT::f32, Custom); | 
|  | } | 
|  |  | 
|  | computeRegisterProperties(Subtarget->getRegisterInfo()); | 
|  |  | 
|  | // ARM does not have floating-point extending loads. | 
|  | for (MVT VT : MVT::fp_valuetypes()) { | 
|  | setLoadExtAction(ISD::EXTLOAD, VT, MVT::f32, Expand); | 
|  | setLoadExtAction(ISD::EXTLOAD, VT, MVT::f16, Expand); | 
|  | } | 
|  |  | 
|  | // ... or truncating stores | 
|  | setTruncStoreAction(MVT::f64, MVT::f32, Expand); | 
|  | setTruncStoreAction(MVT::f32, MVT::f16, Expand); | 
|  | setTruncStoreAction(MVT::f64, MVT::f16, Expand); | 
|  |  | 
|  | // ARM does not have i1 sign extending load. | 
|  | for (MVT VT : MVT::integer_valuetypes()) | 
|  | setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); | 
|  |  | 
|  | // ARM supports all 4 flavors of integer indexed load / store. | 
|  | if (!Subtarget->isThumb1Only()) { | 
|  | for (unsigned im = (unsigned)ISD::PRE_INC; | 
|  | im != (unsigned)ISD::LAST_INDEXED_MODE; ++im) { | 
|  | setIndexedLoadAction(im,  MVT::i1,  Legal); | 
|  | setIndexedLoadAction(im,  MVT::i8,  Legal); | 
|  | setIndexedLoadAction(im,  MVT::i16, Legal); | 
|  | setIndexedLoadAction(im,  MVT::i32, Legal); | 
|  | setIndexedStoreAction(im, MVT::i1,  Legal); | 
|  | setIndexedStoreAction(im, MVT::i8,  Legal); | 
|  | setIndexedStoreAction(im, MVT::i16, Legal); | 
|  | setIndexedStoreAction(im, MVT::i32, Legal); | 
|  | } | 
|  | } else { | 
|  | // Thumb-1 has limited post-inc load/store support - LDM r0!, {r1}. | 
|  | setIndexedLoadAction(ISD::POST_INC, MVT::i32,  Legal); | 
|  | setIndexedStoreAction(ISD::POST_INC, MVT::i32,  Legal); | 
|  | } | 
|  |  | 
|  | setOperationAction(ISD::SADDO, MVT::i32, Custom); | 
|  | setOperationAction(ISD::UADDO, MVT::i32, Custom); | 
|  | setOperationAction(ISD::SSUBO, MVT::i32, Custom); | 
|  | setOperationAction(ISD::USUBO, MVT::i32, Custom); | 
|  |  | 
|  | setOperationAction(ISD::ADDCARRY, MVT::i32, Custom); | 
|  | setOperationAction(ISD::SUBCARRY, MVT::i32, Custom); | 
|  | if (Subtarget->hasDSP()) { | 
|  | setOperationAction(ISD::SADDSAT, MVT::i8, Custom); | 
|  | setOperationAction(ISD::SSUBSAT, MVT::i8, Custom); | 
|  | setOperationAction(ISD::SADDSAT, MVT::i16, Custom); | 
|  | setOperationAction(ISD::SSUBSAT, MVT::i16, Custom); | 
|  | } | 
|  | if (Subtarget->hasBaseDSP()) { | 
|  | setOperationAction(ISD::SADDSAT, MVT::i32, Legal); | 
|  | setOperationAction(ISD::SSUBSAT, MVT::i32, Legal); | 
|  | } | 
|  |  | 
|  | // i64 operation support. | 
|  | setOperationAction(ISD::MUL,     MVT::i64, Expand); | 
|  | setOperationAction(ISD::MULHU,   MVT::i32, Expand); | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); | 
|  | setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); | 
|  | } | 
|  | if (Subtarget->isThumb1Only() || !Subtarget->hasV6Ops() | 
|  | || (Subtarget->isThumb2() && !Subtarget->hasDSP())) | 
|  | setOperationAction(ISD::MULHS, MVT::i32, Expand); | 
|  |  | 
|  | setOperationAction(ISD::SHL_PARTS, MVT::i32, Custom); | 
|  | setOperationAction(ISD::SRA_PARTS, MVT::i32, Custom); | 
|  | setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom); | 
|  | setOperationAction(ISD::SRL,       MVT::i64, Custom); | 
|  | setOperationAction(ISD::SRA,       MVT::i64, Custom); | 
|  | setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); | 
|  | setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom); | 
|  | setOperationAction(ISD::LOAD, MVT::i64, Custom); | 
|  | setOperationAction(ISD::STORE, MVT::i64, Custom); | 
|  |  | 
|  | // MVE lowers 64 bit shifts to lsll and lsrl | 
|  | // assuming that ISD::SRL and SRA of i64 are already marked custom | 
|  | if (Subtarget->hasMVEIntegerOps()) | 
|  | setOperationAction(ISD::SHL, MVT::i64, Custom); | 
|  |  | 
|  | // Expand to __aeabi_l{lsl,lsr,asr} calls for Thumb1. | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); | 
|  | setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); | 
|  | setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); | 
|  | } | 
|  |  | 
|  | if (!Subtarget->isThumb1Only() && Subtarget->hasV6T2Ops()) | 
|  | setOperationAction(ISD::BITREVERSE, MVT::i32, Legal); | 
|  |  | 
|  | // ARM does not have ROTL. | 
|  | setOperationAction(ISD::ROTL, MVT::i32, Expand); | 
|  | for (MVT VT : MVT::fixedlen_vector_valuetypes()) { | 
|  | setOperationAction(ISD::ROTL, VT, Expand); | 
|  | setOperationAction(ISD::ROTR, VT, Expand); | 
|  | } | 
|  | setOperationAction(ISD::CTTZ,  MVT::i32, Custom); | 
|  | setOperationAction(ISD::CTPOP, MVT::i32, Expand); | 
|  | if (!Subtarget->hasV5TOps() || Subtarget->isThumb1Only()) { | 
|  | setOperationAction(ISD::CTLZ, MVT::i32, Expand); | 
|  | setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, LibCall); | 
|  | } | 
|  |  | 
|  | // @llvm.readcyclecounter requires the Performance Monitors extension. | 
|  | // Default to the 0 expansion on unsupported platforms. | 
|  | // FIXME: Technically there are older ARM CPUs that have | 
|  | // implementation-specific ways of obtaining this information. | 
|  | if (Subtarget->hasPerfMon()) | 
|  | setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Custom); | 
|  |  | 
|  | // Only ARMv6 has BSWAP. | 
|  | if (!Subtarget->hasV6Ops()) | 
|  | setOperationAction(ISD::BSWAP, MVT::i32, Expand); | 
|  |  | 
|  | bool hasDivide = Subtarget->isThumb() ? Subtarget->hasDivideInThumbMode() | 
|  | : Subtarget->hasDivideInARMMode(); | 
|  | if (!hasDivide) { | 
|  | // These are expanded into libcalls if the cpu doesn't have HW divider. | 
|  | setOperationAction(ISD::SDIV,  MVT::i32, LibCall); | 
|  | setOperationAction(ISD::UDIV,  MVT::i32, LibCall); | 
|  | } | 
|  |  | 
|  | if (Subtarget->isTargetWindows() && !Subtarget->hasDivideInThumbMode()) { | 
|  | setOperationAction(ISD::SDIV, MVT::i32, Custom); | 
|  | setOperationAction(ISD::UDIV, MVT::i32, Custom); | 
|  |  | 
|  | setOperationAction(ISD::SDIV, MVT::i64, Custom); | 
|  | setOperationAction(ISD::UDIV, MVT::i64, Custom); | 
|  | } | 
|  |  | 
|  | setOperationAction(ISD::SREM,  MVT::i32, Expand); | 
|  | setOperationAction(ISD::UREM,  MVT::i32, Expand); | 
|  |  | 
|  | // Register based DivRem for AEABI (RTABI 4.2) | 
|  | if (Subtarget->isTargetAEABI() || Subtarget->isTargetAndroid() || | 
|  | Subtarget->isTargetGNUAEABI() || Subtarget->isTargetMuslAEABI() || | 
|  | Subtarget->isTargetWindows()) { | 
|  | setOperationAction(ISD::SREM, MVT::i64, Custom); | 
|  | setOperationAction(ISD::UREM, MVT::i64, Custom); | 
|  | HasStandaloneRem = false; | 
|  |  | 
|  | if (Subtarget->isTargetWindows()) { | 
|  | const struct { | 
|  | const RTLIB::Libcall Op; | 
|  | const char * const Name; | 
|  | const CallingConv::ID CC; | 
|  | } LibraryCalls[] = { | 
|  | { RTLIB::SDIVREM_I8, "__rt_sdiv", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::SDIVREM_I16, "__rt_sdiv", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::SDIVREM_I32, "__rt_sdiv", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::SDIVREM_I64, "__rt_sdiv64", CallingConv::ARM_AAPCS }, | 
|  |  | 
|  | { RTLIB::UDIVREM_I8, "__rt_udiv", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::UDIVREM_I16, "__rt_udiv", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::UDIVREM_I32, "__rt_udiv", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::UDIVREM_I64, "__rt_udiv64", CallingConv::ARM_AAPCS }, | 
|  | }; | 
|  |  | 
|  | for (const auto &LC : LibraryCalls) { | 
|  | setLibcallName(LC.Op, LC.Name); | 
|  | setLibcallCallingConv(LC.Op, LC.CC); | 
|  | } | 
|  | } else { | 
|  | const struct { | 
|  | const RTLIB::Libcall Op; | 
|  | const char * const Name; | 
|  | const CallingConv::ID CC; | 
|  | } LibraryCalls[] = { | 
|  | { RTLIB::SDIVREM_I8, "__aeabi_idivmod", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::SDIVREM_I16, "__aeabi_idivmod", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::SDIVREM_I32, "__aeabi_idivmod", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::SDIVREM_I64, "__aeabi_ldivmod", CallingConv::ARM_AAPCS }, | 
|  |  | 
|  | { RTLIB::UDIVREM_I8, "__aeabi_uidivmod", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::UDIVREM_I16, "__aeabi_uidivmod", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::UDIVREM_I32, "__aeabi_uidivmod", CallingConv::ARM_AAPCS }, | 
|  | { RTLIB::UDIVREM_I64, "__aeabi_uldivmod", CallingConv::ARM_AAPCS }, | 
|  | }; | 
|  |  | 
|  | for (const auto &LC : LibraryCalls) { | 
|  | setLibcallName(LC.Op, LC.Name); | 
|  | setLibcallCallingConv(LC.Op, LC.CC); | 
|  | } | 
|  | } | 
|  |  | 
|  | setOperationAction(ISD::SDIVREM, MVT::i32, Custom); | 
|  | setOperationAction(ISD::UDIVREM, MVT::i32, Custom); | 
|  | setOperationAction(ISD::SDIVREM, MVT::i64, Custom); | 
|  | setOperationAction(ISD::UDIVREM, MVT::i64, Custom); | 
|  | } else { | 
|  | setOperationAction(ISD::SDIVREM, MVT::i32, Expand); | 
|  | setOperationAction(ISD::UDIVREM, MVT::i32, Expand); | 
|  | } | 
|  |  | 
|  | if (Subtarget->getTargetTriple().isOSMSVCRT()) { | 
|  | // MSVCRT doesn't have powi; fall back to pow | 
|  | setLibcallName(RTLIB::POWI_F32, nullptr); | 
|  | setLibcallName(RTLIB::POWI_F64, nullptr); | 
|  | } | 
|  |  | 
|  | setOperationAction(ISD::GlobalAddress, MVT::i32,   Custom); | 
|  | setOperationAction(ISD::ConstantPool,  MVT::i32,   Custom); | 
|  | setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); | 
|  | setOperationAction(ISD::BlockAddress, MVT::i32, Custom); | 
|  |  | 
|  | setOperationAction(ISD::TRAP, MVT::Other, Legal); | 
|  | setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); | 
|  |  | 
|  | // Use the default implementation. | 
|  | setOperationAction(ISD::VASTART,            MVT::Other, Custom); | 
|  | setOperationAction(ISD::VAARG,              MVT::Other, Expand); | 
|  | setOperationAction(ISD::VACOPY,             MVT::Other, Expand); | 
|  | setOperationAction(ISD::VAEND,              MVT::Other, Expand); | 
|  | setOperationAction(ISD::STACKSAVE,          MVT::Other, Expand); | 
|  | setOperationAction(ISD::STACKRESTORE,       MVT::Other, Expand); | 
|  |  | 
|  | if (Subtarget->isTargetWindows()) | 
|  | setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom); | 
|  | else | 
|  | setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); | 
|  |  | 
|  | // ARMv6 Thumb1 (except for CPUs that support dmb / dsb) and earlier use | 
|  | // the default expansion. | 
|  | InsertFencesForAtomic = false; | 
|  | if (Subtarget->hasAnyDataBarrier() && | 
|  | (!Subtarget->isThumb() || Subtarget->hasV8MBaselineOps())) { | 
|  | // ATOMIC_FENCE needs custom lowering; the others should have been expanded | 
|  | // to ldrex/strex loops already. | 
|  | setOperationAction(ISD::ATOMIC_FENCE,     MVT::Other, Custom); | 
|  | if (!Subtarget->isThumb() || !Subtarget->isMClass()) | 
|  | setOperationAction(ISD::ATOMIC_CMP_SWAP,  MVT::i64, Custom); | 
|  |  | 
|  | // On v8, we have particularly efficient implementations of atomic fences | 
|  | // if they can be combined with nearby atomic loads and stores. | 
|  | if (!Subtarget->hasAcquireRelease() || | 
|  | getTargetMachine().getOptLevel() == 0) { | 
|  | // Automatically insert fences (dmb ish) around ATOMIC_SWAP etc. | 
|  | InsertFencesForAtomic = true; | 
|  | } | 
|  | } else { | 
|  | // If there's anything we can use as a barrier, go through custom lowering | 
|  | // for ATOMIC_FENCE. | 
|  | // If target has DMB in thumb, Fences can be inserted. | 
|  | if (Subtarget->hasDataBarrier()) | 
|  | InsertFencesForAtomic = true; | 
|  |  | 
|  | setOperationAction(ISD::ATOMIC_FENCE,   MVT::Other, | 
|  | Subtarget->hasAnyDataBarrier() ? Custom : Expand); | 
|  |  | 
|  | // Set them all for expansion, which will force libcalls. | 
|  | setOperationAction(ISD::ATOMIC_CMP_SWAP,  MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_SWAP,      MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_LOAD_ADD,  MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_LOAD_SUB,  MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_LOAD_AND,  MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_LOAD_OR,   MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_LOAD_XOR,  MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_LOAD_MIN, MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_LOAD_MAX, MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, Expand); | 
|  | setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Expand); | 
|  | // Mark ATOMIC_LOAD and ATOMIC_STORE custom so we can handle the | 
|  | // Unordered/Monotonic case. | 
|  | if (!InsertFencesForAtomic) { | 
|  | setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Custom); | 
|  | setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Custom); | 
|  | } | 
|  | } | 
|  |  | 
|  | setOperationAction(ISD::PREFETCH,         MVT::Other, Custom); | 
|  |  | 
|  | // Requires SXTB/SXTH, available on v6 and up in both ARM and Thumb modes. | 
|  | if (!Subtarget->hasV6Ops()) { | 
|  | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); | 
|  | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8,  Expand); | 
|  | } | 
|  | setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); | 
|  |  | 
|  | if (!Subtarget->useSoftFloat() && Subtarget->hasFPRegs() && | 
|  | !Subtarget->isThumb1Only()) { | 
|  | // Turn f64->i64 into VMOVRRD, i64 -> f64 to VMOVDRR | 
|  | // iff target supports vfp2. | 
|  | setOperationAction(ISD::BITCAST, MVT::i64, Custom); | 
|  | setOperationAction(ISD::FLT_ROUNDS_, MVT::i32, Custom); | 
|  | } | 
|  |  | 
|  | // We want to custom lower some of our intrinsics. | 
|  | setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); | 
|  | setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom); | 
|  | setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom); | 
|  | setOperationAction(ISD::EH_SJLJ_SETUP_DISPATCH, MVT::Other, Custom); | 
|  | if (Subtarget->useSjLjEH()) | 
|  | setLibcallName(RTLIB::UNWIND_RESUME, "_Unwind_SjLj_Resume"); | 
|  |  | 
|  | setOperationAction(ISD::SETCC,     MVT::i32, Expand); | 
|  | setOperationAction(ISD::SETCC,     MVT::f32, Expand); | 
|  | setOperationAction(ISD::SETCC,     MVT::f64, Expand); | 
|  | setOperationAction(ISD::SELECT,    MVT::i32, Custom); | 
|  | setOperationAction(ISD::SELECT,    MVT::f32, Custom); | 
|  | setOperationAction(ISD::SELECT,    MVT::f64, Custom); | 
|  | setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); | 
|  | setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); | 
|  | setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); | 
|  | if (Subtarget->hasFullFP16()) { | 
|  | setOperationAction(ISD::SETCC,     MVT::f16, Expand); | 
|  | setOperationAction(ISD::SELECT,    MVT::f16, Custom); | 
|  | setOperationAction(ISD::SELECT_CC, MVT::f16, Custom); | 
|  | } | 
|  |  | 
|  | setOperationAction(ISD::SETCCCARRY, MVT::i32, Custom); | 
|  |  | 
|  | setOperationAction(ISD::BRCOND,    MVT::Other, Custom); | 
|  | setOperationAction(ISD::BR_CC,     MVT::i32,   Custom); | 
|  | if (Subtarget->hasFullFP16()) | 
|  | setOperationAction(ISD::BR_CC, MVT::f16,   Custom); | 
|  | setOperationAction(ISD::BR_CC,     MVT::f32,   Custom); | 
|  | setOperationAction(ISD::BR_CC,     MVT::f64,   Custom); | 
|  | setOperationAction(ISD::BR_JT,     MVT::Other, Custom); | 
|  |  | 
|  | // We don't support sin/cos/fmod/copysign/pow | 
|  | setOperationAction(ISD::FSIN,      MVT::f64, Expand); | 
|  | setOperationAction(ISD::FSIN,      MVT::f32, Expand); | 
|  | setOperationAction(ISD::FCOS,      MVT::f32, Expand); | 
|  | setOperationAction(ISD::FCOS,      MVT::f64, Expand); | 
|  | setOperationAction(ISD::FSINCOS,   MVT::f64, Expand); | 
|  | setOperationAction(ISD::FSINCOS,   MVT::f32, Expand); | 
|  | setOperationAction(ISD::FREM,      MVT::f64, Expand); | 
|  | setOperationAction(ISD::FREM,      MVT::f32, Expand); | 
|  | if (!Subtarget->useSoftFloat() && Subtarget->hasVFP2Base() && | 
|  | !Subtarget->isThumb1Only()) { | 
|  | setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); | 
|  | setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom); | 
|  | } | 
|  | setOperationAction(ISD::FPOW,      MVT::f64, Expand); | 
|  | setOperationAction(ISD::FPOW,      MVT::f32, Expand); | 
|  |  | 
|  | if (!Subtarget->hasVFP4Base()) { | 
|  | setOperationAction(ISD::FMA, MVT::f64, Expand); | 
|  | setOperationAction(ISD::FMA, MVT::f32, Expand); | 
|  | } | 
|  |  | 
|  | // Various VFP goodness | 
|  | if (!Subtarget->useSoftFloat() && !Subtarget->isThumb1Only()) { | 
|  | // FP-ARMv8 adds f64 <-> f16 conversion. Before that it should be expanded. | 
|  | if (!Subtarget->hasFPARMv8Base() || !Subtarget->hasFP64()) { | 
|  | setOperationAction(ISD::FP16_TO_FP, MVT::f64, Expand); | 
|  | setOperationAction(ISD::FP_TO_FP16, MVT::f64, Expand); | 
|  | } | 
|  |  | 
|  | // fp16 is a special v7 extension that adds f16 <-> f32 conversions. | 
|  | if (!Subtarget->hasFP16()) { | 
|  | setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand); | 
|  | setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand); | 
|  | } | 
|  |  | 
|  | // Strict floating-point comparisons need custom lowering. | 
|  | setOperationAction(ISD::STRICT_FSETCC,  MVT::f16, Custom); | 
|  | setOperationAction(ISD::STRICT_FSETCCS, MVT::f16, Custom); | 
|  | setOperationAction(ISD::STRICT_FSETCC,  MVT::f32, Custom); | 
|  | setOperationAction(ISD::STRICT_FSETCCS, MVT::f32, Custom); | 
|  | setOperationAction(ISD::STRICT_FSETCC,  MVT::f64, Custom); | 
|  | setOperationAction(ISD::STRICT_FSETCCS, MVT::f64, Custom); | 
|  | } | 
|  |  | 
|  | // Use __sincos_stret if available. | 
|  | if (getLibcallName(RTLIB::SINCOS_STRET_F32) != nullptr && | 
|  | getLibcallName(RTLIB::SINCOS_STRET_F64) != nullptr) { | 
|  | setOperationAction(ISD::FSINCOS, MVT::f64, Custom); | 
|  | setOperationAction(ISD::FSINCOS, MVT::f32, Custom); | 
|  | } | 
|  |  | 
|  | // FP-ARMv8 implements a lot of rounding-like FP operations. | 
|  | if (Subtarget->hasFPARMv8Base()) { | 
|  | setOperationAction(ISD::FFLOOR, MVT::f32, Legal); | 
|  | setOperationAction(ISD::FCEIL, MVT::f32, Legal); | 
|  | setOperationAction(ISD::FROUND, MVT::f32, Legal); | 
|  | setOperationAction(ISD::FTRUNC, MVT::f32, Legal); | 
|  | setOperationAction(ISD::FNEARBYINT, MVT::f32, Legal); | 
|  | setOperationAction(ISD::FRINT, MVT::f32, Legal); | 
|  | setOperationAction(ISD::FMINNUM, MVT::f32, Legal); | 
|  | setOperationAction(ISD::FMAXNUM, MVT::f32, Legal); | 
|  | if (Subtarget->hasNEON()) { | 
|  | setOperationAction(ISD::FMINNUM, MVT::v2f32, Legal); | 
|  | setOperationAction(ISD::FMAXNUM, MVT::v2f32, Legal); | 
|  | setOperationAction(ISD::FMINNUM, MVT::v4f32, Legal); | 
|  | setOperationAction(ISD::FMAXNUM, MVT::v4f32, Legal); | 
|  | } | 
|  |  | 
|  | if (Subtarget->hasFP64()) { | 
|  | setOperationAction(ISD::FFLOOR, MVT::f64, Legal); | 
|  | setOperationAction(ISD::FCEIL, MVT::f64, Legal); | 
|  | setOperationAction(ISD::FROUND, MVT::f64, Legal); | 
|  | setOperationAction(ISD::FTRUNC, MVT::f64, Legal); | 
|  | setOperationAction(ISD::FNEARBYINT, MVT::f64, Legal); | 
|  | setOperationAction(ISD::FRINT, MVT::f64, Legal); | 
|  | setOperationAction(ISD::FMINNUM, MVT::f64, Legal); | 
|  | setOperationAction(ISD::FMAXNUM, MVT::f64, Legal); | 
|  | } | 
|  | } | 
|  |  | 
|  | // FP16 often need to be promoted to call lib functions | 
|  | if (Subtarget->hasFullFP16()) { | 
|  | setOperationAction(ISD::FREM, MVT::f16, Promote); | 
|  | setOperationAction(ISD::FCOPYSIGN, MVT::f16, Expand); | 
|  | setOperationAction(ISD::FSIN, MVT::f16, Promote); | 
|  | setOperationAction(ISD::FCOS, MVT::f16, Promote); | 
|  | setOperationAction(ISD::FSINCOS, MVT::f16, Promote); | 
|  | setOperationAction(ISD::FPOWI, MVT::f16, Promote); | 
|  | setOperationAction(ISD::FPOW, MVT::f16, Promote); | 
|  | setOperationAction(ISD::FEXP, MVT::f16, Promote); | 
|  | setOperationAction(ISD::FEXP2, MVT::f16, Promote); | 
|  | setOperationAction(ISD::FLOG, MVT::f16, Promote); | 
|  | setOperationAction(ISD::FLOG10, MVT::f16, Promote); | 
|  | setOperationAction(ISD::FLOG2, MVT::f16, Promote); | 
|  |  | 
|  | setOperationAction(ISD::FROUND, MVT::f16, Legal); | 
|  | } | 
|  |  | 
|  | if (Subtarget->hasNEON()) { | 
|  | // vmin and vmax aren't available in a scalar form, so we can use | 
|  | // a NEON instruction with an undef lane instead.  This has a performance | 
|  | // penalty on some cores, so we don't do this unless we have been | 
|  | // asked to by the core tuning model. | 
|  | if (Subtarget->useNEONForSinglePrecisionFP()) { | 
|  | setOperationAction(ISD::FMINIMUM, MVT::f32, Legal); | 
|  | setOperationAction(ISD::FMAXIMUM, MVT::f32, Legal); | 
|  | setOperationAction(ISD::FMINIMUM, MVT::f16, Legal); | 
|  | setOperationAction(ISD::FMAXIMUM, MVT::f16, Legal); | 
|  | } | 
|  | setOperationAction(ISD::FMINIMUM, MVT::v2f32, Legal); | 
|  | setOperationAction(ISD::FMAXIMUM, MVT::v2f32, Legal); | 
|  | setOperationAction(ISD::FMINIMUM, MVT::v4f32, Legal); | 
|  | setOperationAction(ISD::FMAXIMUM, MVT::v4f32, Legal); | 
|  |  | 
|  | if (Subtarget->hasFullFP16()) { | 
|  | setOperationAction(ISD::FMINNUM, MVT::v4f16, Legal); | 
|  | setOperationAction(ISD::FMAXNUM, MVT::v4f16, Legal); | 
|  | setOperationAction(ISD::FMINNUM, MVT::v8f16, Legal); | 
|  | setOperationAction(ISD::FMAXNUM, MVT::v8f16, Legal); | 
|  |  | 
|  | setOperationAction(ISD::FMINIMUM, MVT::v4f16, Legal); | 
|  | setOperationAction(ISD::FMAXIMUM, MVT::v4f16, Legal); | 
|  | setOperationAction(ISD::FMINIMUM, MVT::v8f16, Legal); | 
|  | setOperationAction(ISD::FMAXIMUM, MVT::v8f16, Legal); | 
|  | } | 
|  | } | 
|  |  | 
|  | // We have target-specific dag combine patterns for the following nodes: | 
|  | // ARMISD::VMOVRRD  - No need to call setTargetDAGCombine | 
|  | setTargetDAGCombine(ISD::ADD); | 
|  | setTargetDAGCombine(ISD::SUB); | 
|  | setTargetDAGCombine(ISD::MUL); | 
|  | setTargetDAGCombine(ISD::AND); | 
|  | setTargetDAGCombine(ISD::OR); | 
|  | setTargetDAGCombine(ISD::XOR); | 
|  |  | 
|  | if (Subtarget->hasMVEIntegerOps()) | 
|  | setTargetDAGCombine(ISD::VSELECT); | 
|  |  | 
|  | if (Subtarget->hasV6Ops()) | 
|  | setTargetDAGCombine(ISD::SRL); | 
|  | if (Subtarget->isThumb1Only()) | 
|  | setTargetDAGCombine(ISD::SHL); | 
|  |  | 
|  | setStackPointerRegisterToSaveRestore(ARM::SP); | 
|  |  | 
|  | if (Subtarget->useSoftFloat() || Subtarget->isThumb1Only() || | 
|  | !Subtarget->hasVFP2Base() || Subtarget->hasMinSize()) | 
|  | setSchedulingPreference(Sched::RegPressure); | 
|  | else | 
|  | setSchedulingPreference(Sched::Hybrid); | 
|  |  | 
|  | //// temporary - rewrite interface to use type | 
|  | MaxStoresPerMemset = 8; | 
|  | MaxStoresPerMemsetOptSize = 4; | 
|  | MaxStoresPerMemcpy = 4; // For @llvm.memcpy -> sequence of stores | 
|  | MaxStoresPerMemcpyOptSize = 2; | 
|  | MaxStoresPerMemmove = 4; // For @llvm.memmove -> sequence of stores | 
|  | MaxStoresPerMemmoveOptSize = 2; | 
|  |  | 
|  | // On ARM arguments smaller than 4 bytes are extended, so all arguments | 
|  | // are at least 4 bytes aligned. | 
|  | setMinStackArgumentAlignment(Align(4)); | 
|  |  | 
|  | // Prefer likely predicted branches to selects on out-of-order cores. | 
|  | PredictableSelectIsExpensive = Subtarget->getSchedModel().isOutOfOrder(); | 
|  |  | 
|  | setPrefLoopAlignment(Align(1ULL << Subtarget->getPrefLoopLogAlignment())); | 
|  |  | 
|  | setMinFunctionAlignment(Subtarget->isThumb() ? Align(2) : Align(4)); | 
|  |  | 
|  | if (Subtarget->isThumb() || Subtarget->isThumb2()) | 
|  | setTargetDAGCombine(ISD::ABS); | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::useSoftFloat() const { | 
|  | return Subtarget->useSoftFloat(); | 
|  | } | 
|  |  | 
|  | // FIXME: It might make sense to define the representative register class as the | 
|  | // nearest super-register that has a non-null superset. For example, DPR_VFP2 is | 
|  | // a super-register of SPR, and DPR is a superset if DPR_VFP2. Consequently, | 
|  | // SPR's representative would be DPR_VFP2. This should work well if register | 
|  | // pressure tracking were modified such that a register use would increment the | 
|  | // pressure of the register class's representative and all of it's super | 
|  | // classes' representatives transitively. We have not implemented this because | 
|  | // of the difficulty prior to coalescing of modeling operand register classes | 
|  | // due to the common occurrence of cross class copies and subregister insertions | 
|  | // and extractions. | 
|  | std::pair<const TargetRegisterClass *, uint8_t> | 
|  | ARMTargetLowering::findRepresentativeClass(const TargetRegisterInfo *TRI, | 
|  | MVT VT) const { | 
|  | const TargetRegisterClass *RRC = nullptr; | 
|  | uint8_t Cost = 1; | 
|  | switch (VT.SimpleTy) { | 
|  | default: | 
|  | return TargetLowering::findRepresentativeClass(TRI, VT); | 
|  | // Use DPR as representative register class for all floating point | 
|  | // and vector types. Since there are 32 SPR registers and 32 DPR registers so | 
|  | // the cost is 1 for both f32 and f64. | 
|  | case MVT::f32: case MVT::f64: case MVT::v8i8: case MVT::v4i16: | 
|  | case MVT::v2i32: case MVT::v1i64: case MVT::v2f32: | 
|  | RRC = &ARM::DPRRegClass; | 
|  | // When NEON is used for SP, only half of the register file is available | 
|  | // because operations that define both SP and DP results will be constrained | 
|  | // to the VFP2 class (D0-D15). We currently model this constraint prior to | 
|  | // coalescing by double-counting the SP regs. See the FIXME above. | 
|  | if (Subtarget->useNEONForSinglePrecisionFP()) | 
|  | Cost = 2; | 
|  | break; | 
|  | case MVT::v16i8: case MVT::v8i16: case MVT::v4i32: case MVT::v2i64: | 
|  | case MVT::v4f32: case MVT::v2f64: | 
|  | RRC = &ARM::DPRRegClass; | 
|  | Cost = 2; | 
|  | break; | 
|  | case MVT::v4i64: | 
|  | RRC = &ARM::DPRRegClass; | 
|  | Cost = 4; | 
|  | break; | 
|  | case MVT::v8i64: | 
|  | RRC = &ARM::DPRRegClass; | 
|  | Cost = 8; | 
|  | break; | 
|  | } | 
|  | return std::make_pair(RRC, Cost); | 
|  | } | 
|  |  | 
|  | const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { | 
|  | switch ((ARMISD::NodeType)Opcode) { | 
|  | case ARMISD::FIRST_NUMBER:  break; | 
|  | case ARMISD::Wrapper:       return "ARMISD::Wrapper"; | 
|  | case ARMISD::WrapperPIC:    return "ARMISD::WrapperPIC"; | 
|  | case ARMISD::WrapperJT:     return "ARMISD::WrapperJT"; | 
|  | case ARMISD::COPY_STRUCT_BYVAL: return "ARMISD::COPY_STRUCT_BYVAL"; | 
|  | case ARMISD::CALL:          return "ARMISD::CALL"; | 
|  | case ARMISD::CALL_PRED:     return "ARMISD::CALL_PRED"; | 
|  | case ARMISD::CALL_NOLINK:   return "ARMISD::CALL_NOLINK"; | 
|  | case ARMISD::tSECALL:       return "ARMISD::tSECALL"; | 
|  | case ARMISD::BRCOND:        return "ARMISD::BRCOND"; | 
|  | case ARMISD::BR_JT:         return "ARMISD::BR_JT"; | 
|  | case ARMISD::BR2_JT:        return "ARMISD::BR2_JT"; | 
|  | case ARMISD::RET_FLAG:      return "ARMISD::RET_FLAG"; | 
|  | case ARMISD::SERET_FLAG:    return "ARMISD::SERET_FLAG"; | 
|  | case ARMISD::INTRET_FLAG:   return "ARMISD::INTRET_FLAG"; | 
|  | case ARMISD::PIC_ADD:       return "ARMISD::PIC_ADD"; | 
|  | case ARMISD::CMP:           return "ARMISD::CMP"; | 
|  | case ARMISD::CMN:           return "ARMISD::CMN"; | 
|  | case ARMISD::CMPZ:          return "ARMISD::CMPZ"; | 
|  | case ARMISD::CMPFP:         return "ARMISD::CMPFP"; | 
|  | case ARMISD::CMPFPE:        return "ARMISD::CMPFPE"; | 
|  | case ARMISD::CMPFPw0:       return "ARMISD::CMPFPw0"; | 
|  | case ARMISD::CMPFPEw0:      return "ARMISD::CMPFPEw0"; | 
|  | case ARMISD::BCC_i64:       return "ARMISD::BCC_i64"; | 
|  | case ARMISD::FMSTAT:        return "ARMISD::FMSTAT"; | 
|  |  | 
|  | case ARMISD::CMOV:          return "ARMISD::CMOV"; | 
|  | case ARMISD::SUBS:          return "ARMISD::SUBS"; | 
|  |  | 
|  | case ARMISD::SSAT:          return "ARMISD::SSAT"; | 
|  | case ARMISD::USAT:          return "ARMISD::USAT"; | 
|  |  | 
|  | case ARMISD::ASRL:          return "ARMISD::ASRL"; | 
|  | case ARMISD::LSRL:          return "ARMISD::LSRL"; | 
|  | case ARMISD::LSLL:          return "ARMISD::LSLL"; | 
|  |  | 
|  | case ARMISD::SRL_FLAG:      return "ARMISD::SRL_FLAG"; | 
|  | case ARMISD::SRA_FLAG:      return "ARMISD::SRA_FLAG"; | 
|  | case ARMISD::RRX:           return "ARMISD::RRX"; | 
|  |  | 
|  | case ARMISD::ADDC:          return "ARMISD::ADDC"; | 
|  | case ARMISD::ADDE:          return "ARMISD::ADDE"; | 
|  | case ARMISD::SUBC:          return "ARMISD::SUBC"; | 
|  | case ARMISD::SUBE:          return "ARMISD::SUBE"; | 
|  | case ARMISD::LSLS:          return "ARMISD::LSLS"; | 
|  |  | 
|  | case ARMISD::VMOVRRD:       return "ARMISD::VMOVRRD"; | 
|  | case ARMISD::VMOVDRR:       return "ARMISD::VMOVDRR"; | 
|  | case ARMISD::VMOVhr:        return "ARMISD::VMOVhr"; | 
|  | case ARMISD::VMOVrh:        return "ARMISD::VMOVrh"; | 
|  | case ARMISD::VMOVSR:        return "ARMISD::VMOVSR"; | 
|  |  | 
|  | case ARMISD::EH_SJLJ_SETJMP: return "ARMISD::EH_SJLJ_SETJMP"; | 
|  | case ARMISD::EH_SJLJ_LONGJMP: return "ARMISD::EH_SJLJ_LONGJMP"; | 
|  | case ARMISD::EH_SJLJ_SETUP_DISPATCH: return "ARMISD::EH_SJLJ_SETUP_DISPATCH"; | 
|  |  | 
|  | case ARMISD::TC_RETURN:     return "ARMISD::TC_RETURN"; | 
|  |  | 
|  | case ARMISD::THREAD_POINTER:return "ARMISD::THREAD_POINTER"; | 
|  |  | 
|  | case ARMISD::DYN_ALLOC:     return "ARMISD::DYN_ALLOC"; | 
|  |  | 
|  | case ARMISD::MEMBARRIER_MCR: return "ARMISD::MEMBARRIER_MCR"; | 
|  |  | 
|  | case ARMISD::PRELOAD:       return "ARMISD::PRELOAD"; | 
|  |  | 
|  | case ARMISD::LDRD:          return "ARMISD::LDRD"; | 
|  | case ARMISD::STRD:          return "ARMISD::STRD"; | 
|  |  | 
|  | case ARMISD::WIN__CHKSTK:   return "ARMISD::WIN__CHKSTK"; | 
|  | case ARMISD::WIN__DBZCHK:   return "ARMISD::WIN__DBZCHK"; | 
|  |  | 
|  | case ARMISD::PREDICATE_CAST: return "ARMISD::PREDICATE_CAST"; | 
|  | case ARMISD::VECTOR_REG_CAST: return "ARMISD::VECTOR_REG_CAST"; | 
|  | case ARMISD::VCMP:          return "ARMISD::VCMP"; | 
|  | case ARMISD::VCMPZ:         return "ARMISD::VCMPZ"; | 
|  | case ARMISD::VTST:          return "ARMISD::VTST"; | 
|  |  | 
|  | case ARMISD::VSHLs:         return "ARMISD::VSHLs"; | 
|  | case ARMISD::VSHLu:         return "ARMISD::VSHLu"; | 
|  | case ARMISD::VSHLIMM:       return "ARMISD::VSHLIMM"; | 
|  | case ARMISD::VSHRsIMM:      return "ARMISD::VSHRsIMM"; | 
|  | case ARMISD::VSHRuIMM:      return "ARMISD::VSHRuIMM"; | 
|  | case ARMISD::VRSHRsIMM:     return "ARMISD::VRSHRsIMM"; | 
|  | case ARMISD::VRSHRuIMM:     return "ARMISD::VRSHRuIMM"; | 
|  | case ARMISD::VRSHRNIMM:     return "ARMISD::VRSHRNIMM"; | 
|  | case ARMISD::VQSHLsIMM:     return "ARMISD::VQSHLsIMM"; | 
|  | case ARMISD::VQSHLuIMM:     return "ARMISD::VQSHLuIMM"; | 
|  | case ARMISD::VQSHLsuIMM:    return "ARMISD::VQSHLsuIMM"; | 
|  | case ARMISD::VQSHRNsIMM:    return "ARMISD::VQSHRNsIMM"; | 
|  | case ARMISD::VQSHRNuIMM:    return "ARMISD::VQSHRNuIMM"; | 
|  | case ARMISD::VQSHRNsuIMM:   return "ARMISD::VQSHRNsuIMM"; | 
|  | case ARMISD::VQRSHRNsIMM:   return "ARMISD::VQRSHRNsIMM"; | 
|  | case ARMISD::VQRSHRNuIMM:   return "ARMISD::VQRSHRNuIMM"; | 
|  | case ARMISD::VQRSHRNsuIMM:  return "ARMISD::VQRSHRNsuIMM"; | 
|  | case ARMISD::VSLIIMM:       return "ARMISD::VSLIIMM"; | 
|  | case ARMISD::VSRIIMM:       return "ARMISD::VSRIIMM"; | 
|  | case ARMISD::VGETLANEu:     return "ARMISD::VGETLANEu"; | 
|  | case ARMISD::VGETLANEs:     return "ARMISD::VGETLANEs"; | 
|  | case ARMISD::VMOVIMM:       return "ARMISD::VMOVIMM"; | 
|  | case ARMISD::VMVNIMM:       return "ARMISD::VMVNIMM"; | 
|  | case ARMISD::VMOVFPIMM:     return "ARMISD::VMOVFPIMM"; | 
|  | case ARMISD::VDUP:          return "ARMISD::VDUP"; | 
|  | case ARMISD::VDUPLANE:      return "ARMISD::VDUPLANE"; | 
|  | case ARMISD::VEXT:          return "ARMISD::VEXT"; | 
|  | case ARMISD::VREV64:        return "ARMISD::VREV64"; | 
|  | case ARMISD::VREV32:        return "ARMISD::VREV32"; | 
|  | case ARMISD::VREV16:        return "ARMISD::VREV16"; | 
|  | case ARMISD::VZIP:          return "ARMISD::VZIP"; | 
|  | case ARMISD::VUZP:          return "ARMISD::VUZP"; | 
|  | case ARMISD::VTRN:          return "ARMISD::VTRN"; | 
|  | case ARMISD::VTBL1:         return "ARMISD::VTBL1"; | 
|  | case ARMISD::VTBL2:         return "ARMISD::VTBL2"; | 
|  | case ARMISD::VMOVN:         return "ARMISD::VMOVN"; | 
|  | case ARMISD::VQMOVNs:       return "ARMISD::VQMOVNs"; | 
|  | case ARMISD::VQMOVNu:       return "ARMISD::VQMOVNu"; | 
|  | case ARMISD::VMULLs:        return "ARMISD::VMULLs"; | 
|  | case ARMISD::VMULLu:        return "ARMISD::VMULLu"; | 
|  | case ARMISD::VADDVs:        return "ARMISD::VADDVs"; | 
|  | case ARMISD::VADDVu:        return "ARMISD::VADDVu"; | 
|  | case ARMISD::VADDLVs:       return "ARMISD::VADDLVs"; | 
|  | case ARMISD::VADDLVu:       return "ARMISD::VADDLVu"; | 
|  | case ARMISD::VADDLVAs:      return "ARMISD::VADDLVAs"; | 
|  | case ARMISD::VADDLVAu:      return "ARMISD::VADDLVAu"; | 
|  | case ARMISD::VADDLVps:      return "ARMISD::VADDLVps"; | 
|  | case ARMISD::VADDLVpu:      return "ARMISD::VADDLVpu"; | 
|  | case ARMISD::VADDLVAps:     return "ARMISD::VADDLVAps"; | 
|  | case ARMISD::VADDLVApu:     return "ARMISD::VADDLVApu"; | 
|  | case ARMISD::VMLAVs:        return "ARMISD::VMLAVs"; | 
|  | case ARMISD::VMLAVu:        return "ARMISD::VMLAVu"; | 
|  | case ARMISD::VMLALVs:       return "ARMISD::VMLALVs"; | 
|  | case ARMISD::VMLALVu:       return "ARMISD::VMLALVu"; | 
|  | case ARMISD::VMLALVAs:      return "ARMISD::VMLALVAs"; | 
|  | case ARMISD::VMLALVAu:      return "ARMISD::VMLALVAu"; | 
|  | case ARMISD::UMAAL:         return "ARMISD::UMAAL"; | 
|  | case ARMISD::UMLAL:         return "ARMISD::UMLAL"; | 
|  | case ARMISD::SMLAL:         return "ARMISD::SMLAL"; | 
|  | case ARMISD::SMLALBB:       return "ARMISD::SMLALBB"; | 
|  | case ARMISD::SMLALBT:       return "ARMISD::SMLALBT"; | 
|  | case ARMISD::SMLALTB:       return "ARMISD::SMLALTB"; | 
|  | case ARMISD::SMLALTT:       return "ARMISD::SMLALTT"; | 
|  | case ARMISD::SMULWB:        return "ARMISD::SMULWB"; | 
|  | case ARMISD::SMULWT:        return "ARMISD::SMULWT"; | 
|  | case ARMISD::SMLALD:        return "ARMISD::SMLALD"; | 
|  | case ARMISD::SMLALDX:       return "ARMISD::SMLALDX"; | 
|  | case ARMISD::SMLSLD:        return "ARMISD::SMLSLD"; | 
|  | case ARMISD::SMLSLDX:       return "ARMISD::SMLSLDX"; | 
|  | case ARMISD::SMMLAR:        return "ARMISD::SMMLAR"; | 
|  | case ARMISD::SMMLSR:        return "ARMISD::SMMLSR"; | 
|  | case ARMISD::QADD16b:       return "ARMISD::QADD16b"; | 
|  | case ARMISD::QSUB16b:       return "ARMISD::QSUB16b"; | 
|  | case ARMISD::QADD8b:        return "ARMISD::QADD8b"; | 
|  | case ARMISD::QSUB8b:        return "ARMISD::QSUB8b"; | 
|  | case ARMISD::BUILD_VECTOR:  return "ARMISD::BUILD_VECTOR"; | 
|  | case ARMISD::BFI:           return "ARMISD::BFI"; | 
|  | case ARMISD::VORRIMM:       return "ARMISD::VORRIMM"; | 
|  | case ARMISD::VBICIMM:       return "ARMISD::VBICIMM"; | 
|  | case ARMISD::VBSL:          return "ARMISD::VBSL"; | 
|  | case ARMISD::MEMCPY:        return "ARMISD::MEMCPY"; | 
|  | case ARMISD::VLD1DUP:       return "ARMISD::VLD1DUP"; | 
|  | case ARMISD::VLD2DUP:       return "ARMISD::VLD2DUP"; | 
|  | case ARMISD::VLD3DUP:       return "ARMISD::VLD3DUP"; | 
|  | case ARMISD::VLD4DUP:       return "ARMISD::VLD4DUP"; | 
|  | case ARMISD::VLD1_UPD:      return "ARMISD::VLD1_UPD"; | 
|  | case ARMISD::VLD2_UPD:      return "ARMISD::VLD2_UPD"; | 
|  | case ARMISD::VLD3_UPD:      return "ARMISD::VLD3_UPD"; | 
|  | case ARMISD::VLD4_UPD:      return "ARMISD::VLD4_UPD"; | 
|  | case ARMISD::VLD2LN_UPD:    return "ARMISD::VLD2LN_UPD"; | 
|  | case ARMISD::VLD3LN_UPD:    return "ARMISD::VLD3LN_UPD"; | 
|  | case ARMISD::VLD4LN_UPD:    return "ARMISD::VLD4LN_UPD"; | 
|  | case ARMISD::VLD1DUP_UPD:   return "ARMISD::VLD1DUP_UPD"; | 
|  | case ARMISD::VLD2DUP_UPD:   return "ARMISD::VLD2DUP_UPD"; | 
|  | case ARMISD::VLD3DUP_UPD:   return "ARMISD::VLD3DUP_UPD"; | 
|  | case ARMISD::VLD4DUP_UPD:   return "ARMISD::VLD4DUP_UPD"; | 
|  | case ARMISD::VST1_UPD:      return "ARMISD::VST1_UPD"; | 
|  | case ARMISD::VST2_UPD:      return "ARMISD::VST2_UPD"; | 
|  | case ARMISD::VST3_UPD:      return "ARMISD::VST3_UPD"; | 
|  | case ARMISD::VST4_UPD:      return "ARMISD::VST4_UPD"; | 
|  | case ARMISD::VST2LN_UPD:    return "ARMISD::VST2LN_UPD"; | 
|  | case ARMISD::VST3LN_UPD:    return "ARMISD::VST3LN_UPD"; | 
|  | case ARMISD::VST4LN_UPD:    return "ARMISD::VST4LN_UPD"; | 
|  | case ARMISD::WLS:           return "ARMISD::WLS"; | 
|  | case ARMISD::LE:            return "ARMISD::LE"; | 
|  | case ARMISD::LOOP_DEC:      return "ARMISD::LOOP_DEC"; | 
|  | case ARMISD::CSINV:         return "ARMISD::CSINV"; | 
|  | case ARMISD::CSNEG:         return "ARMISD::CSNEG"; | 
|  | case ARMISD::CSINC:         return "ARMISD::CSINC"; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | EVT ARMTargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &, | 
|  | EVT VT) const { | 
|  | if (!VT.isVector()) | 
|  | return getPointerTy(DL); | 
|  |  | 
|  | // MVE has a predicate register. | 
|  | if (Subtarget->hasMVEIntegerOps() && | 
|  | (VT == MVT::v4i32 || VT == MVT::v8i16 || VT == MVT::v16i8)) | 
|  | return MVT::getVectorVT(MVT::i1, VT.getVectorElementCount()); | 
|  | return VT.changeVectorElementTypeToInteger(); | 
|  | } | 
|  |  | 
|  | /// getRegClassFor - Return the register class that should be used for the | 
|  | /// specified value type. | 
|  | const TargetRegisterClass * | 
|  | ARMTargetLowering::getRegClassFor(MVT VT, bool isDivergent) const { | 
|  | (void)isDivergent; | 
|  | // Map v4i64 to QQ registers but do not make the type legal. Similarly map | 
|  | // v8i64 to QQQQ registers. v4i64 and v8i64 are only used for REG_SEQUENCE to | 
|  | // load / store 4 to 8 consecutive NEON D registers, or 2 to 4 consecutive | 
|  | // MVE Q registers. | 
|  | if (Subtarget->hasNEON() || Subtarget->hasMVEIntegerOps()) { | 
|  | if (VT == MVT::v4i64) | 
|  | return &ARM::QQPRRegClass; | 
|  | if (VT == MVT::v8i64) | 
|  | return &ARM::QQQQPRRegClass; | 
|  | } | 
|  | return TargetLowering::getRegClassFor(VT); | 
|  | } | 
|  |  | 
|  | // memcpy, and other memory intrinsics, typically tries to use LDM/STM if the | 
|  | // source/dest is aligned and the copy size is large enough. We therefore want | 
|  | // to align such objects passed to memory intrinsics. | 
|  | bool ARMTargetLowering::shouldAlignPointerArgs(CallInst *CI, unsigned &MinSize, | 
|  | unsigned &PrefAlign) const { | 
|  | if (!isa<MemIntrinsic>(CI)) | 
|  | return false; | 
|  | MinSize = 8; | 
|  | // On ARM11 onwards (excluding M class) 8-byte aligned LDM is typically 1 | 
|  | // cycle faster than 4-byte aligned LDM. | 
|  | PrefAlign = (Subtarget->hasV6Ops() && !Subtarget->isMClass() ? 8 : 4); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Create a fast isel object. | 
|  | FastISel * | 
|  | ARMTargetLowering::createFastISel(FunctionLoweringInfo &funcInfo, | 
|  | const TargetLibraryInfo *libInfo) const { | 
|  | return ARM::createFastISel(funcInfo, libInfo); | 
|  | } | 
|  |  | 
|  | Sched::Preference ARMTargetLowering::getSchedulingPreference(SDNode *N) const { | 
|  | unsigned NumVals = N->getNumValues(); | 
|  | if (!NumVals) | 
|  | return Sched::RegPressure; | 
|  |  | 
|  | for (unsigned i = 0; i != NumVals; ++i) { | 
|  | EVT VT = N->getValueType(i); | 
|  | if (VT == MVT::Glue || VT == MVT::Other) | 
|  | continue; | 
|  | if (VT.isFloatingPoint() || VT.isVector()) | 
|  | return Sched::ILP; | 
|  | } | 
|  |  | 
|  | if (!N->isMachineOpcode()) | 
|  | return Sched::RegPressure; | 
|  |  | 
|  | // Load are scheduled for latency even if there instruction itinerary | 
|  | // is not available. | 
|  | const TargetInstrInfo *TII = Subtarget->getInstrInfo(); | 
|  | const MCInstrDesc &MCID = TII->get(N->getMachineOpcode()); | 
|  |  | 
|  | if (MCID.getNumDefs() == 0) | 
|  | return Sched::RegPressure; | 
|  | if (!Itins->isEmpty() && | 
|  | Itins->getOperandCycle(MCID.getSchedClass(), 0) > 2) | 
|  | return Sched::ILP; | 
|  |  | 
|  | return Sched::RegPressure; | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | // Lowering Code | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | static bool isSRL16(const SDValue &Op) { | 
|  | if (Op.getOpcode() != ISD::SRL) | 
|  | return false; | 
|  | if (auto Const = dyn_cast<ConstantSDNode>(Op.getOperand(1))) | 
|  | return Const->getZExtValue() == 16; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool isSRA16(const SDValue &Op) { | 
|  | if (Op.getOpcode() != ISD::SRA) | 
|  | return false; | 
|  | if (auto Const = dyn_cast<ConstantSDNode>(Op.getOperand(1))) | 
|  | return Const->getZExtValue() == 16; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool isSHL16(const SDValue &Op) { | 
|  | if (Op.getOpcode() != ISD::SHL) | 
|  | return false; | 
|  | if (auto Const = dyn_cast<ConstantSDNode>(Op.getOperand(1))) | 
|  | return Const->getZExtValue() == 16; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Check for a signed 16-bit value. We special case SRA because it makes it | 
|  | // more simple when also looking for SRAs that aren't sign extending a | 
|  | // smaller value. Without the check, we'd need to take extra care with | 
|  | // checking order for some operations. | 
|  | static bool isS16(const SDValue &Op, SelectionDAG &DAG) { | 
|  | if (isSRA16(Op)) | 
|  | return isSHL16(Op.getOperand(0)); | 
|  | return DAG.ComputeNumSignBits(Op) == 17; | 
|  | } | 
|  |  | 
|  | /// IntCCToARMCC - Convert a DAG integer condition code to an ARM CC | 
|  | static ARMCC::CondCodes IntCCToARMCC(ISD::CondCode CC) { | 
|  | switch (CC) { | 
|  | default: llvm_unreachable("Unknown condition code!"); | 
|  | case ISD::SETNE:  return ARMCC::NE; | 
|  | case ISD::SETEQ:  return ARMCC::EQ; | 
|  | case ISD::SETGT:  return ARMCC::GT; | 
|  | case ISD::SETGE:  return ARMCC::GE; | 
|  | case ISD::SETLT:  return ARMCC::LT; | 
|  | case ISD::SETLE:  return ARMCC::LE; | 
|  | case ISD::SETUGT: return ARMCC::HI; | 
|  | case ISD::SETUGE: return ARMCC::HS; | 
|  | case ISD::SETULT: return ARMCC::LO; | 
|  | case ISD::SETULE: return ARMCC::LS; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// FPCCToARMCC - Convert a DAG fp condition code to an ARM CC. | 
|  | static void FPCCToARMCC(ISD::CondCode CC, ARMCC::CondCodes &CondCode, | 
|  | ARMCC::CondCodes &CondCode2) { | 
|  | CondCode2 = ARMCC::AL; | 
|  | switch (CC) { | 
|  | default: llvm_unreachable("Unknown FP condition!"); | 
|  | case ISD::SETEQ: | 
|  | case ISD::SETOEQ: CondCode = ARMCC::EQ; break; | 
|  | case ISD::SETGT: | 
|  | case ISD::SETOGT: CondCode = ARMCC::GT; break; | 
|  | case ISD::SETGE: | 
|  | case ISD::SETOGE: CondCode = ARMCC::GE; break; | 
|  | case ISD::SETOLT: CondCode = ARMCC::MI; break; | 
|  | case ISD::SETOLE: CondCode = ARMCC::LS; break; | 
|  | case ISD::SETONE: CondCode = ARMCC::MI; CondCode2 = ARMCC::GT; break; | 
|  | case ISD::SETO:   CondCode = ARMCC::VC; break; | 
|  | case ISD::SETUO:  CondCode = ARMCC::VS; break; | 
|  | case ISD::SETUEQ: CondCode = ARMCC::EQ; CondCode2 = ARMCC::VS; break; | 
|  | case ISD::SETUGT: CondCode = ARMCC::HI; break; | 
|  | case ISD::SETUGE: CondCode = ARMCC::PL; break; | 
|  | case ISD::SETLT: | 
|  | case ISD::SETULT: CondCode = ARMCC::LT; break; | 
|  | case ISD::SETLE: | 
|  | case ISD::SETULE: CondCode = ARMCC::LE; break; | 
|  | case ISD::SETNE: | 
|  | case ISD::SETUNE: CondCode = ARMCC::NE; break; | 
|  | } | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //                      Calling Convention Implementation | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | /// getEffectiveCallingConv - Get the effective calling convention, taking into | 
|  | /// account presence of floating point hardware and calling convention | 
|  | /// limitations, such as support for variadic functions. | 
|  | CallingConv::ID | 
|  | ARMTargetLowering::getEffectiveCallingConv(CallingConv::ID CC, | 
|  | bool isVarArg) const { | 
|  | switch (CC) { | 
|  | default: | 
|  | report_fatal_error("Unsupported calling convention"); | 
|  | case CallingConv::ARM_AAPCS: | 
|  | case CallingConv::ARM_APCS: | 
|  | case CallingConv::GHC: | 
|  | case CallingConv::CFGuard_Check: | 
|  | return CC; | 
|  | case CallingConv::PreserveMost: | 
|  | return CallingConv::PreserveMost; | 
|  | case CallingConv::ARM_AAPCS_VFP: | 
|  | case CallingConv::Swift: | 
|  | return isVarArg ? CallingConv::ARM_AAPCS : CallingConv::ARM_AAPCS_VFP; | 
|  | case CallingConv::C: | 
|  | if (!Subtarget->isAAPCS_ABI()) | 
|  | return CallingConv::ARM_APCS; | 
|  | else if (Subtarget->hasVFP2Base() && !Subtarget->isThumb1Only() && | 
|  | getTargetMachine().Options.FloatABIType == FloatABI::Hard && | 
|  | !isVarArg) | 
|  | return CallingConv::ARM_AAPCS_VFP; | 
|  | else | 
|  | return CallingConv::ARM_AAPCS; | 
|  | case CallingConv::Fast: | 
|  | case CallingConv::CXX_FAST_TLS: | 
|  | if (!Subtarget->isAAPCS_ABI()) { | 
|  | if (Subtarget->hasVFP2Base() && !Subtarget->isThumb1Only() && !isVarArg) | 
|  | return CallingConv::Fast; | 
|  | return CallingConv::ARM_APCS; | 
|  | } else if (Subtarget->hasVFP2Base() && | 
|  | !Subtarget->isThumb1Only() && !isVarArg) | 
|  | return CallingConv::ARM_AAPCS_VFP; | 
|  | else | 
|  | return CallingConv::ARM_AAPCS; | 
|  | } | 
|  | } | 
|  |  | 
|  | CCAssignFn *ARMTargetLowering::CCAssignFnForCall(CallingConv::ID CC, | 
|  | bool isVarArg) const { | 
|  | return CCAssignFnForNode(CC, false, isVarArg); | 
|  | } | 
|  |  | 
|  | CCAssignFn *ARMTargetLowering::CCAssignFnForReturn(CallingConv::ID CC, | 
|  | bool isVarArg) const { | 
|  | return CCAssignFnForNode(CC, true, isVarArg); | 
|  | } | 
|  |  | 
|  | /// CCAssignFnForNode - Selects the correct CCAssignFn for the given | 
|  | /// CallingConvention. | 
|  | CCAssignFn *ARMTargetLowering::CCAssignFnForNode(CallingConv::ID CC, | 
|  | bool Return, | 
|  | bool isVarArg) const { | 
|  | switch (getEffectiveCallingConv(CC, isVarArg)) { | 
|  | default: | 
|  | report_fatal_error("Unsupported calling convention"); | 
|  | case CallingConv::ARM_APCS: | 
|  | return (Return ? RetCC_ARM_APCS : CC_ARM_APCS); | 
|  | case CallingConv::ARM_AAPCS: | 
|  | return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS); | 
|  | case CallingConv::ARM_AAPCS_VFP: | 
|  | return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP); | 
|  | case CallingConv::Fast: | 
|  | return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS); | 
|  | case CallingConv::GHC: | 
|  | return (Return ? RetCC_ARM_APCS : CC_ARM_APCS_GHC); | 
|  | case CallingConv::PreserveMost: | 
|  | return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS); | 
|  | case CallingConv::CFGuard_Check: | 
|  | return (Return ? RetCC_ARM_AAPCS : CC_ARM_Win32_CFGuard_Check); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// LowerCallResult - Lower the result values of a call into the | 
|  | /// appropriate copies out of appropriate physical registers. | 
|  | SDValue ARMTargetLowering::LowerCallResult( | 
|  | SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg, | 
|  | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, | 
|  | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals, bool isThisReturn, | 
|  | SDValue ThisVal) const { | 
|  | // Assign locations to each value returned by this call. | 
|  | SmallVector<CCValAssign, 16> RVLocs; | 
|  | CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs, | 
|  | *DAG.getContext()); | 
|  | CCInfo.AnalyzeCallResult(Ins, CCAssignFnForReturn(CallConv, isVarArg)); | 
|  |  | 
|  | // Copy all of the result registers out of their specified physreg. | 
|  | for (unsigned i = 0; i != RVLocs.size(); ++i) { | 
|  | CCValAssign VA = RVLocs[i]; | 
|  |  | 
|  | // Pass 'this' value directly from the argument to return value, to avoid | 
|  | // reg unit interference | 
|  | if (i == 0 && isThisReturn) { | 
|  | assert(!VA.needsCustom() && VA.getLocVT() == MVT::i32 && | 
|  | "unexpected return calling convention register assignment"); | 
|  | InVals.push_back(ThisVal); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | SDValue Val; | 
|  | if (VA.needsCustom()) { | 
|  | // Handle f64 or half of a v2f64. | 
|  | SDValue Lo = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), MVT::i32, | 
|  | InFlag); | 
|  | Chain = Lo.getValue(1); | 
|  | InFlag = Lo.getValue(2); | 
|  | VA = RVLocs[++i]; // skip ahead to next loc | 
|  | SDValue Hi = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), MVT::i32, | 
|  | InFlag); | 
|  | Chain = Hi.getValue(1); | 
|  | InFlag = Hi.getValue(2); | 
|  | if (!Subtarget->isLittle()) | 
|  | std::swap (Lo, Hi); | 
|  | Val = DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Lo, Hi); | 
|  |  | 
|  | if (VA.getLocVT() == MVT::v2f64) { | 
|  | SDValue Vec = DAG.getNode(ISD::UNDEF, dl, MVT::v2f64); | 
|  | Vec = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, Vec, Val, | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  |  | 
|  | VA = RVLocs[++i]; // skip ahead to next loc | 
|  | Lo = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), MVT::i32, InFlag); | 
|  | Chain = Lo.getValue(1); | 
|  | InFlag = Lo.getValue(2); | 
|  | VA = RVLocs[++i]; // skip ahead to next loc | 
|  | Hi = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), MVT::i32, InFlag); | 
|  | Chain = Hi.getValue(1); | 
|  | InFlag = Hi.getValue(2); | 
|  | if (!Subtarget->isLittle()) | 
|  | std::swap (Lo, Hi); | 
|  | Val = DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Lo, Hi); | 
|  | Val = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, Vec, Val, | 
|  | DAG.getConstant(1, dl, MVT::i32)); | 
|  | } | 
|  | } else { | 
|  | Val = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), VA.getLocVT(), | 
|  | InFlag); | 
|  | Chain = Val.getValue(1); | 
|  | InFlag = Val.getValue(2); | 
|  | } | 
|  |  | 
|  | switch (VA.getLocInfo()) { | 
|  | default: llvm_unreachable("Unknown loc info!"); | 
|  | case CCValAssign::Full: break; | 
|  | case CCValAssign::BCvt: | 
|  | Val = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), Val); | 
|  | break; | 
|  | } | 
|  |  | 
|  | InVals.push_back(Val); | 
|  | } | 
|  |  | 
|  | return Chain; | 
|  | } | 
|  |  | 
|  | /// LowerMemOpCallTo - Store the argument to the stack. | 
|  | SDValue ARMTargetLowering::LowerMemOpCallTo(SDValue Chain, SDValue StackPtr, | 
|  | SDValue Arg, const SDLoc &dl, | 
|  | SelectionDAG &DAG, | 
|  | const CCValAssign &VA, | 
|  | ISD::ArgFlagsTy Flags) const { | 
|  | unsigned LocMemOffset = VA.getLocMemOffset(); | 
|  | SDValue PtrOff = DAG.getIntPtrConstant(LocMemOffset, dl); | 
|  | PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(DAG.getDataLayout()), | 
|  | StackPtr, PtrOff); | 
|  | return DAG.getStore( | 
|  | Chain, dl, Arg, PtrOff, | 
|  | MachinePointerInfo::getStack(DAG.getMachineFunction(), LocMemOffset)); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::PassF64ArgInRegs(const SDLoc &dl, SelectionDAG &DAG, | 
|  | SDValue Chain, SDValue &Arg, | 
|  | RegsToPassVector &RegsToPass, | 
|  | CCValAssign &VA, CCValAssign &NextVA, | 
|  | SDValue &StackPtr, | 
|  | SmallVectorImpl<SDValue> &MemOpChains, | 
|  | ISD::ArgFlagsTy Flags) const { | 
|  | SDValue fmrrd = DAG.getNode(ARMISD::VMOVRRD, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), Arg); | 
|  | unsigned id = Subtarget->isLittle() ? 0 : 1; | 
|  | RegsToPass.push_back(std::make_pair(VA.getLocReg(), fmrrd.getValue(id))); | 
|  |  | 
|  | if (NextVA.isRegLoc()) | 
|  | RegsToPass.push_back(std::make_pair(NextVA.getLocReg(), fmrrd.getValue(1-id))); | 
|  | else { | 
|  | assert(NextVA.isMemLoc()); | 
|  | if (!StackPtr.getNode()) | 
|  | StackPtr = DAG.getCopyFromReg(Chain, dl, ARM::SP, | 
|  | getPointerTy(DAG.getDataLayout())); | 
|  |  | 
|  | MemOpChains.push_back(LowerMemOpCallTo(Chain, StackPtr, fmrrd.getValue(1-id), | 
|  | dl, DAG, NextVA, | 
|  | Flags)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// LowerCall - Lowering a call into a callseq_start <- | 
|  | /// ARMISD:CALL <- callseq_end chain. Also add input and output parameter | 
|  | /// nodes. | 
|  | SDValue | 
|  | ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, | 
|  | SmallVectorImpl<SDValue> &InVals) const { | 
|  | SelectionDAG &DAG                     = CLI.DAG; | 
|  | SDLoc &dl                             = CLI.DL; | 
|  | SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; | 
|  | SmallVectorImpl<SDValue> &OutVals     = CLI.OutVals; | 
|  | SmallVectorImpl<ISD::InputArg> &Ins   = CLI.Ins; | 
|  | SDValue Chain                         = CLI.Chain; | 
|  | SDValue Callee                        = CLI.Callee; | 
|  | bool &isTailCall                      = CLI.IsTailCall; | 
|  | CallingConv::ID CallConv              = CLI.CallConv; | 
|  | bool doesNotRet                       = CLI.DoesNotReturn; | 
|  | bool isVarArg                         = CLI.IsVarArg; | 
|  |  | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  | MachineFunction::CallSiteInfo CSInfo; | 
|  | bool isStructRet = (Outs.empty()) ? false : Outs[0].Flags.isSRet(); | 
|  | bool isThisReturn = false; | 
|  | bool isCmseNSCall   = false; | 
|  | bool PreferIndirect = false; | 
|  |  | 
|  | // Determine whether this is a non-secure function call. | 
|  | if (CLI.CB && CLI.CB->getAttributes().hasFnAttribute("cmse_nonsecure_call")) | 
|  | isCmseNSCall = true; | 
|  |  | 
|  | // Disable tail calls if they're not supported. | 
|  | if (!Subtarget->supportsTailCall()) | 
|  | isTailCall = false; | 
|  |  | 
|  | // For both the non-secure calls and the returns from a CMSE entry function, | 
|  | // the function needs to do some extra work afte r the call, or before the | 
|  | // return, respectively, thus it cannot end with atail call | 
|  | if (isCmseNSCall || AFI->isCmseNSEntryFunction()) | 
|  | isTailCall = false; | 
|  |  | 
|  | if (isa<GlobalAddressSDNode>(Callee)) { | 
|  | // If we're optimizing for minimum size and the function is called three or | 
|  | // more times in this block, we can improve codesize by calling indirectly | 
|  | // as BLXr has a 16-bit encoding. | 
|  | auto *GV = cast<GlobalAddressSDNode>(Callee)->getGlobal(); | 
|  | if (CLI.CB) { | 
|  | auto *BB = CLI.CB->getParent(); | 
|  | PreferIndirect = Subtarget->isThumb() && Subtarget->hasMinSize() && | 
|  | count_if(GV->users(), [&BB](const User *U) { | 
|  | return isa<Instruction>(U) && | 
|  | cast<Instruction>(U)->getParent() == BB; | 
|  | }) > 2; | 
|  | } | 
|  | } | 
|  | if (isTailCall) { | 
|  | // Check if it's really possible to do a tail call. | 
|  | isTailCall = IsEligibleForTailCallOptimization( | 
|  | Callee, CallConv, isVarArg, isStructRet, | 
|  | MF.getFunction().hasStructRetAttr(), Outs, OutVals, Ins, DAG, | 
|  | PreferIndirect); | 
|  | if (!isTailCall && CLI.CB && CLI.CB->isMustTailCall()) | 
|  | report_fatal_error("failed to perform tail call elimination on a call " | 
|  | "site marked musttail"); | 
|  | // We don't support GuaranteedTailCallOpt for ARM, only automatically | 
|  | // detected sibcalls. | 
|  | if (isTailCall) | 
|  | ++NumTailCalls; | 
|  | } | 
|  |  | 
|  | // Analyze operands of the call, assigning locations to each operand. | 
|  | SmallVector<CCValAssign, 16> ArgLocs; | 
|  | CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs, | 
|  | *DAG.getContext()); | 
|  | CCInfo.AnalyzeCallOperands(Outs, CCAssignFnForCall(CallConv, isVarArg)); | 
|  |  | 
|  | // Get a count of how many bytes are to be pushed on the stack. | 
|  | unsigned NumBytes = CCInfo.getNextStackOffset(); | 
|  |  | 
|  | if (isTailCall) { | 
|  | // For tail calls, memory operands are available in our caller's stack. | 
|  | NumBytes = 0; | 
|  | } else { | 
|  | // Adjust the stack pointer for the new arguments... | 
|  | // These operations are automatically eliminated by the prolog/epilog pass | 
|  | Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl); | 
|  | } | 
|  |  | 
|  | SDValue StackPtr = | 
|  | DAG.getCopyFromReg(Chain, dl, ARM::SP, getPointerTy(DAG.getDataLayout())); | 
|  |  | 
|  | RegsToPassVector RegsToPass; | 
|  | SmallVector<SDValue, 8> MemOpChains; | 
|  |  | 
|  | // Walk the register/memloc assignments, inserting copies/loads.  In the case | 
|  | // of tail call optimization, arguments are handled later. | 
|  | for (unsigned i = 0, realArgIdx = 0, e = ArgLocs.size(); | 
|  | i != e; | 
|  | ++i, ++realArgIdx) { | 
|  | CCValAssign &VA = ArgLocs[i]; | 
|  | SDValue Arg = OutVals[realArgIdx]; | 
|  | ISD::ArgFlagsTy Flags = Outs[realArgIdx].Flags; | 
|  | bool isByVal = Flags.isByVal(); | 
|  |  | 
|  | // Promote the value if needed. | 
|  | switch (VA.getLocInfo()) { | 
|  | default: llvm_unreachable("Unknown loc info!"); | 
|  | case CCValAssign::Full: break; | 
|  | case CCValAssign::SExt: | 
|  | Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); | 
|  | break; | 
|  | case CCValAssign::ZExt: | 
|  | Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); | 
|  | break; | 
|  | case CCValAssign::AExt: | 
|  | Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); | 
|  | break; | 
|  | case CCValAssign::BCvt: | 
|  | Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // f64 and v2f64 might be passed in i32 pairs and must be split into pieces | 
|  | if (VA.needsCustom()) { | 
|  | if (VA.getLocVT() == MVT::v2f64) { | 
|  | SDValue Op0 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, Arg, | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | SDValue Op1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, Arg, | 
|  | DAG.getConstant(1, dl, MVT::i32)); | 
|  |  | 
|  | PassF64ArgInRegs(dl, DAG, Chain, Op0, RegsToPass, | 
|  | VA, ArgLocs[++i], StackPtr, MemOpChains, Flags); | 
|  |  | 
|  | VA = ArgLocs[++i]; // skip ahead to next loc | 
|  | if (VA.isRegLoc()) { | 
|  | PassF64ArgInRegs(dl, DAG, Chain, Op1, RegsToPass, | 
|  | VA, ArgLocs[++i], StackPtr, MemOpChains, Flags); | 
|  | } else { | 
|  | assert(VA.isMemLoc()); | 
|  |  | 
|  | MemOpChains.push_back(LowerMemOpCallTo(Chain, StackPtr, Op1, | 
|  | dl, DAG, VA, Flags)); | 
|  | } | 
|  | } else { | 
|  | PassF64ArgInRegs(dl, DAG, Chain, Arg, RegsToPass, VA, ArgLocs[++i], | 
|  | StackPtr, MemOpChains, Flags); | 
|  | } | 
|  | } else if (VA.isRegLoc()) { | 
|  | if (realArgIdx == 0 && Flags.isReturned() && !Flags.isSwiftSelf() && | 
|  | Outs[0].VT == MVT::i32) { | 
|  | assert(VA.getLocVT() == MVT::i32 && | 
|  | "unexpected calling convention register assignment"); | 
|  | assert(!Ins.empty() && Ins[0].VT == MVT::i32 && | 
|  | "unexpected use of 'returned'"); | 
|  | isThisReturn = true; | 
|  | } | 
|  | const TargetOptions &Options = DAG.getTarget().Options; | 
|  | if (Options.EmitCallSiteInfo) | 
|  | CSInfo.emplace_back(VA.getLocReg(), i); | 
|  | RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); | 
|  | } else if (isByVal) { | 
|  | assert(VA.isMemLoc()); | 
|  | unsigned offset = 0; | 
|  |  | 
|  | // True if this byval aggregate will be split between registers | 
|  | // and memory. | 
|  | unsigned ByValArgsCount = CCInfo.getInRegsParamsCount(); | 
|  | unsigned CurByValIdx = CCInfo.getInRegsParamsProcessed(); | 
|  |  | 
|  | if (CurByValIdx < ByValArgsCount) { | 
|  |  | 
|  | unsigned RegBegin, RegEnd; | 
|  | CCInfo.getInRegsParamInfo(CurByValIdx, RegBegin, RegEnd); | 
|  |  | 
|  | EVT PtrVT = | 
|  | DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()); | 
|  | unsigned int i, j; | 
|  | for (i = 0, j = RegBegin; j < RegEnd; i++, j++) { | 
|  | SDValue Const = DAG.getConstant(4*i, dl, MVT::i32); | 
|  | SDValue AddArg = DAG.getNode(ISD::ADD, dl, PtrVT, Arg, Const); | 
|  | SDValue Load = | 
|  | DAG.getLoad(PtrVT, dl, Chain, AddArg, MachinePointerInfo(), | 
|  | DAG.InferPtrAlign(AddArg)); | 
|  | MemOpChains.push_back(Load.getValue(1)); | 
|  | RegsToPass.push_back(std::make_pair(j, Load)); | 
|  | } | 
|  |  | 
|  | // If parameter size outsides register area, "offset" value | 
|  | // helps us to calculate stack slot for remained part properly. | 
|  | offset = RegEnd - RegBegin; | 
|  |  | 
|  | CCInfo.nextInRegsParam(); | 
|  | } | 
|  |  | 
|  | if (Flags.getByValSize() > 4*offset) { | 
|  | auto PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | unsigned LocMemOffset = VA.getLocMemOffset(); | 
|  | SDValue StkPtrOff = DAG.getIntPtrConstant(LocMemOffset, dl); | 
|  | SDValue Dst = DAG.getNode(ISD::ADD, dl, PtrVT, StackPtr, StkPtrOff); | 
|  | SDValue SrcOffset = DAG.getIntPtrConstant(4*offset, dl); | 
|  | SDValue Src = DAG.getNode(ISD::ADD, dl, PtrVT, Arg, SrcOffset); | 
|  | SDValue SizeNode = DAG.getConstant(Flags.getByValSize() - 4*offset, dl, | 
|  | MVT::i32); | 
|  | SDValue AlignNode = | 
|  | DAG.getConstant(Flags.getNonZeroByValAlign().value(), dl, MVT::i32); | 
|  |  | 
|  | SDVTList VTs = DAG.getVTList(MVT::Other, MVT::Glue); | 
|  | SDValue Ops[] = { Chain, Dst, Src, SizeNode, AlignNode}; | 
|  | MemOpChains.push_back(DAG.getNode(ARMISD::COPY_STRUCT_BYVAL, dl, VTs, | 
|  | Ops)); | 
|  | } | 
|  | } else if (!isTailCall) { | 
|  | assert(VA.isMemLoc()); | 
|  |  | 
|  | MemOpChains.push_back(LowerMemOpCallTo(Chain, StackPtr, Arg, | 
|  | dl, DAG, VA, Flags)); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!MemOpChains.empty()) | 
|  | Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains); | 
|  |  | 
|  | // Build a sequence of copy-to-reg nodes chained together with token chain | 
|  | // and flag operands which copy the outgoing args into the appropriate regs. | 
|  | SDValue InFlag; | 
|  | for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { | 
|  | Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, | 
|  | RegsToPass[i].second, InFlag); | 
|  | InFlag = Chain.getValue(1); | 
|  | } | 
|  |  | 
|  | // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every | 
|  | // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol | 
|  | // node so that legalize doesn't hack it. | 
|  | bool isDirect = false; | 
|  |  | 
|  | const TargetMachine &TM = getTargetMachine(); | 
|  | const Module *Mod = MF.getFunction().getParent(); | 
|  | const GlobalValue *GV = nullptr; | 
|  | if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) | 
|  | GV = G->getGlobal(); | 
|  | bool isStub = | 
|  | !TM.shouldAssumeDSOLocal(*Mod, GV) && Subtarget->isTargetMachO(); | 
|  |  | 
|  | bool isARMFunc = !Subtarget->isThumb() || (isStub && !Subtarget->isMClass()); | 
|  | bool isLocalARMFunc = false; | 
|  | auto PtrVt = getPointerTy(DAG.getDataLayout()); | 
|  |  | 
|  | if (Subtarget->genLongCalls()) { | 
|  | assert((!isPositionIndependent() || Subtarget->isTargetWindows()) && | 
|  | "long-calls codegen is not position independent!"); | 
|  | // Handle a global address or an external symbol. If it's not one of | 
|  | // those, the target's already in a register, so we don't need to do | 
|  | // anything extra. | 
|  | if (isa<GlobalAddressSDNode>(Callee)) { | 
|  | // Create a constant pool entry for the callee address | 
|  | unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); | 
|  | ARMConstantPoolValue *CPV = | 
|  | ARMConstantPoolConstant::Create(GV, ARMPCLabelIndex, ARMCP::CPValue, 0); | 
|  |  | 
|  | // Get the address of the callee into a register | 
|  | SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVt, Align(4)); | 
|  | CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); | 
|  | Callee = DAG.getLoad( | 
|  | PtrVt, dl, DAG.getEntryNode(), CPAddr, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  | } else if (ExternalSymbolSDNode *S=dyn_cast<ExternalSymbolSDNode>(Callee)) { | 
|  | const char *Sym = S->getSymbol(); | 
|  |  | 
|  | // Create a constant pool entry for the callee address | 
|  | unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); | 
|  | ARMConstantPoolValue *CPV = | 
|  | ARMConstantPoolSymbol::Create(*DAG.getContext(), Sym, | 
|  | ARMPCLabelIndex, 0); | 
|  | // Get the address of the callee into a register | 
|  | SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVt, Align(4)); | 
|  | CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); | 
|  | Callee = DAG.getLoad( | 
|  | PtrVt, dl, DAG.getEntryNode(), CPAddr, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  | } | 
|  | } else if (isa<GlobalAddressSDNode>(Callee)) { | 
|  | if (!PreferIndirect) { | 
|  | isDirect = true; | 
|  | bool isDef = GV->isStrongDefinitionForLinker(); | 
|  |  | 
|  | // ARM call to a local ARM function is predicable. | 
|  | isLocalARMFunc = !Subtarget->isThumb() && (isDef || !ARMInterworking); | 
|  | // tBX takes a register source operand. | 
|  | if (isStub && Subtarget->isThumb1Only() && !Subtarget->hasV5TOps()) { | 
|  | assert(Subtarget->isTargetMachO() && "WrapperPIC use on non-MachO?"); | 
|  | Callee = DAG.getNode( | 
|  | ARMISD::WrapperPIC, dl, PtrVt, | 
|  | DAG.getTargetGlobalAddress(GV, dl, PtrVt, 0, ARMII::MO_NONLAZY)); | 
|  | Callee = DAG.getLoad( | 
|  | PtrVt, dl, DAG.getEntryNode(), Callee, | 
|  | MachinePointerInfo::getGOT(DAG.getMachineFunction()), | 
|  | /* Alignment = */ 0, MachineMemOperand::MODereferenceable | | 
|  | MachineMemOperand::MOInvariant); | 
|  | } else if (Subtarget->isTargetCOFF()) { | 
|  | assert(Subtarget->isTargetWindows() && | 
|  | "Windows is the only supported COFF target"); | 
|  | unsigned TargetFlags = ARMII::MO_NO_FLAG; | 
|  | if (GV->hasDLLImportStorageClass()) | 
|  | TargetFlags = ARMII::MO_DLLIMPORT; | 
|  | else if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV)) | 
|  | TargetFlags = ARMII::MO_COFFSTUB; | 
|  | Callee = DAG.getTargetGlobalAddress(GV, dl, PtrVt, /*offset=*/0, | 
|  | TargetFlags); | 
|  | if (TargetFlags & (ARMII::MO_DLLIMPORT | ARMII::MO_COFFSTUB)) | 
|  | Callee = | 
|  | DAG.getLoad(PtrVt, dl, DAG.getEntryNode(), | 
|  | DAG.getNode(ARMISD::Wrapper, dl, PtrVt, Callee), | 
|  | MachinePointerInfo::getGOT(DAG.getMachineFunction())); | 
|  | } else { | 
|  | Callee = DAG.getTargetGlobalAddress(GV, dl, PtrVt, 0, 0); | 
|  | } | 
|  | } | 
|  | } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { | 
|  | isDirect = true; | 
|  | // tBX takes a register source operand. | 
|  | const char *Sym = S->getSymbol(); | 
|  | if (isARMFunc && Subtarget->isThumb1Only() && !Subtarget->hasV5TOps()) { | 
|  | unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); | 
|  | ARMConstantPoolValue *CPV = | 
|  | ARMConstantPoolSymbol::Create(*DAG.getContext(), Sym, | 
|  | ARMPCLabelIndex, 4); | 
|  | SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVt, Align(4)); | 
|  | CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); | 
|  | Callee = DAG.getLoad( | 
|  | PtrVt, dl, DAG.getEntryNode(), CPAddr, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  | SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, dl, MVT::i32); | 
|  | Callee = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVt, Callee, PICLabel); | 
|  | } else { | 
|  | Callee = DAG.getTargetExternalSymbol(Sym, PtrVt, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (isCmseNSCall) { | 
|  | assert(!isARMFunc && !isDirect && | 
|  | "Cannot handle call to ARM function or direct call"); | 
|  | if (NumBytes > 0) { | 
|  | DiagnosticInfoUnsupported Diag(DAG.getMachineFunction().getFunction(), | 
|  | "call to non-secure function would " | 
|  | "require passing arguments on stack", | 
|  | dl.getDebugLoc()); | 
|  | DAG.getContext()->diagnose(Diag); | 
|  | } | 
|  | if (isStructRet) { | 
|  | DiagnosticInfoUnsupported Diag( | 
|  | DAG.getMachineFunction().getFunction(), | 
|  | "call to non-secure function would return value through pointer", | 
|  | dl.getDebugLoc()); | 
|  | DAG.getContext()->diagnose(Diag); | 
|  | } | 
|  | } | 
|  |  | 
|  | // FIXME: handle tail calls differently. | 
|  | unsigned CallOpc; | 
|  | if (Subtarget->isThumb()) { | 
|  | if (isCmseNSCall) | 
|  | CallOpc = ARMISD::tSECALL; | 
|  | else if ((!isDirect || isARMFunc) && !Subtarget->hasV5TOps()) | 
|  | CallOpc = ARMISD::CALL_NOLINK; | 
|  | else | 
|  | CallOpc = ARMISD::CALL; | 
|  | } else { | 
|  | if (!isDirect && !Subtarget->hasV5TOps()) | 
|  | CallOpc = ARMISD::CALL_NOLINK; | 
|  | else if (doesNotRet && isDirect && Subtarget->hasRetAddrStack() && | 
|  | // Emit regular call when code size is the priority | 
|  | !Subtarget->hasMinSize()) | 
|  | // "mov lr, pc; b _foo" to avoid confusing the RSP | 
|  | CallOpc = ARMISD::CALL_NOLINK; | 
|  | else | 
|  | CallOpc = isLocalARMFunc ? ARMISD::CALL_PRED : ARMISD::CALL; | 
|  | } | 
|  |  | 
|  | std::vector<SDValue> Ops; | 
|  | Ops.push_back(Chain); | 
|  | Ops.push_back(Callee); | 
|  |  | 
|  | // Add argument registers to the end of the list so that they are known live | 
|  | // into the call. | 
|  | for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) | 
|  | Ops.push_back(DAG.getRegister(RegsToPass[i].first, | 
|  | RegsToPass[i].second.getValueType())); | 
|  |  | 
|  | // Add a register mask operand representing the call-preserved registers. | 
|  | if (!isTailCall) { | 
|  | const uint32_t *Mask; | 
|  | const ARMBaseRegisterInfo *ARI = Subtarget->getRegisterInfo(); | 
|  | if (isThisReturn) { | 
|  | // For 'this' returns, use the R0-preserving mask if applicable | 
|  | Mask = ARI->getThisReturnPreservedMask(MF, CallConv); | 
|  | if (!Mask) { | 
|  | // Set isThisReturn to false if the calling convention is not one that | 
|  | // allows 'returned' to be modeled in this way, so LowerCallResult does | 
|  | // not try to pass 'this' straight through | 
|  | isThisReturn = false; | 
|  | Mask = ARI->getCallPreservedMask(MF, CallConv); | 
|  | } | 
|  | } else | 
|  | Mask = ARI->getCallPreservedMask(MF, CallConv); | 
|  |  | 
|  | assert(Mask && "Missing call preserved mask for calling convention"); | 
|  | Ops.push_back(DAG.getRegisterMask(Mask)); | 
|  | } | 
|  |  | 
|  | if (InFlag.getNode()) | 
|  | Ops.push_back(InFlag); | 
|  |  | 
|  | SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); | 
|  | if (isTailCall) { | 
|  | MF.getFrameInfo().setHasTailCall(); | 
|  | SDValue Ret = DAG.getNode(ARMISD::TC_RETURN, dl, NodeTys, Ops); | 
|  | DAG.addCallSiteInfo(Ret.getNode(), std::move(CSInfo)); | 
|  | return Ret; | 
|  | } | 
|  |  | 
|  | // Returns a chain and a flag for retval copy to use. | 
|  | Chain = DAG.getNode(CallOpc, dl, NodeTys, Ops); | 
|  | DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge); | 
|  | InFlag = Chain.getValue(1); | 
|  | DAG.addCallSiteInfo(Chain.getNode(), std::move(CSInfo)); | 
|  |  | 
|  | Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, dl, true), | 
|  | DAG.getIntPtrConstant(0, dl, true), InFlag, dl); | 
|  | if (!Ins.empty()) | 
|  | InFlag = Chain.getValue(1); | 
|  |  | 
|  | // Handle result values, copying them out of physregs into vregs that we | 
|  | // return. | 
|  | return LowerCallResult(Chain, InFlag, CallConv, isVarArg, Ins, dl, DAG, | 
|  | InVals, isThisReturn, | 
|  | isThisReturn ? OutVals[0] : SDValue()); | 
|  | } | 
|  |  | 
|  | /// HandleByVal - Every parameter *after* a byval parameter is passed | 
|  | /// on the stack.  Remember the next parameter register to allocate, | 
|  | /// and then confiscate the rest of the parameter registers to insure | 
|  | /// this. | 
|  | void ARMTargetLowering::HandleByVal(CCState *State, unsigned &Size, | 
|  | unsigned Align) const { | 
|  | // Byval (as with any stack) slots are always at least 4 byte aligned. | 
|  | Align = std::max(Align, 4U); | 
|  |  | 
|  | unsigned Reg = State->AllocateReg(GPRArgRegs); | 
|  | if (!Reg) | 
|  | return; | 
|  |  | 
|  | unsigned AlignInRegs = Align / 4; | 
|  | unsigned Waste = (ARM::R4 - Reg) % AlignInRegs; | 
|  | for (unsigned i = 0; i < Waste; ++i) | 
|  | Reg = State->AllocateReg(GPRArgRegs); | 
|  |  | 
|  | if (!Reg) | 
|  | return; | 
|  |  | 
|  | unsigned Excess = 4 * (ARM::R4 - Reg); | 
|  |  | 
|  | // Special case when NSAA != SP and parameter size greater than size of | 
|  | // all remained GPR regs. In that case we can't split parameter, we must | 
|  | // send it to stack. We also must set NCRN to R4, so waste all | 
|  | // remained registers. | 
|  | const unsigned NSAAOffset = State->getNextStackOffset(); | 
|  | if (NSAAOffset != 0 && Size > Excess) { | 
|  | while (State->AllocateReg(GPRArgRegs)) | 
|  | ; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // First register for byval parameter is the first register that wasn't | 
|  | // allocated before this method call, so it would be "reg". | 
|  | // If parameter is small enough to be saved in range [reg, r4), then | 
|  | // the end (first after last) register would be reg + param-size-in-regs, | 
|  | // else parameter would be splitted between registers and stack, | 
|  | // end register would be r4 in this case. | 
|  | unsigned ByValRegBegin = Reg; | 
|  | unsigned ByValRegEnd = std::min<unsigned>(Reg + Size / 4, ARM::R4); | 
|  | State->addInRegsParamInfo(ByValRegBegin, ByValRegEnd); | 
|  | // Note, first register is allocated in the beginning of function already, | 
|  | // allocate remained amount of registers we need. | 
|  | for (unsigned i = Reg + 1; i != ByValRegEnd; ++i) | 
|  | State->AllocateReg(GPRArgRegs); | 
|  | // A byval parameter that is split between registers and memory needs its | 
|  | // size truncated here. | 
|  | // In the case where the entire structure fits in registers, we set the | 
|  | // size in memory to zero. | 
|  | Size = std::max<int>(Size - Excess, 0); | 
|  | } | 
|  |  | 
|  | /// MatchingStackOffset - Return true if the given stack call argument is | 
|  | /// already available in the same position (relatively) of the caller's | 
|  | /// incoming argument stack. | 
|  | static | 
|  | bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags, | 
|  | MachineFrameInfo &MFI, const MachineRegisterInfo *MRI, | 
|  | const TargetInstrInfo *TII) { | 
|  | unsigned Bytes = Arg.getValueSizeInBits() / 8; | 
|  | int FI = std::numeric_limits<int>::max(); | 
|  | if (Arg.getOpcode() == ISD::CopyFromReg) { | 
|  | unsigned VR = cast<RegisterSDNode>(Arg.getOperand(1))->getReg(); | 
|  | if (!Register::isVirtualRegister(VR)) | 
|  | return false; | 
|  | MachineInstr *Def = MRI->getVRegDef(VR); | 
|  | if (!Def) | 
|  | return false; | 
|  | if (!Flags.isByVal()) { | 
|  | if (!TII->isLoadFromStackSlot(*Def, FI)) | 
|  | return false; | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  | } else if (LoadSDNode *Ld = dyn_cast<LoadSDNode>(Arg)) { | 
|  | if (Flags.isByVal()) | 
|  | // ByVal argument is passed in as a pointer but it's now being | 
|  | // dereferenced. e.g. | 
|  | // define @foo(%struct.X* %A) { | 
|  | //   tail call @bar(%struct.X* byval %A) | 
|  | // } | 
|  | return false; | 
|  | SDValue Ptr = Ld->getBasePtr(); | 
|  | FrameIndexSDNode *FINode = dyn_cast<FrameIndexSDNode>(Ptr); | 
|  | if (!FINode) | 
|  | return false; | 
|  | FI = FINode->getIndex(); | 
|  | } else | 
|  | return false; | 
|  |  | 
|  | assert(FI != std::numeric_limits<int>::max()); | 
|  | if (!MFI.isFixedObjectIndex(FI)) | 
|  | return false; | 
|  | return Offset == MFI.getObjectOffset(FI) && Bytes == MFI.getObjectSize(FI); | 
|  | } | 
|  |  | 
|  | /// IsEligibleForTailCallOptimization - Check whether the call is eligible | 
|  | /// for tail call optimization. Targets which want to do tail call | 
|  | /// optimization should implement this function. | 
|  | bool ARMTargetLowering::IsEligibleForTailCallOptimization( | 
|  | SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg, | 
|  | bool isCalleeStructRet, bool isCallerStructRet, | 
|  | const SmallVectorImpl<ISD::OutputArg> &Outs, | 
|  | const SmallVectorImpl<SDValue> &OutVals, | 
|  | const SmallVectorImpl<ISD::InputArg> &Ins, SelectionDAG &DAG, | 
|  | const bool isIndirect) const { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | const Function &CallerF = MF.getFunction(); | 
|  | CallingConv::ID CallerCC = CallerF.getCallingConv(); | 
|  |  | 
|  | assert(Subtarget->supportsTailCall()); | 
|  |  | 
|  | // Indirect tail calls cannot be optimized for Thumb1 if the args | 
|  | // to the call take up r0-r3. The reason is that there are no legal registers | 
|  | // left to hold the pointer to the function to be called. | 
|  | if (Subtarget->isThumb1Only() && Outs.size() >= 4 && | 
|  | (!isa<GlobalAddressSDNode>(Callee.getNode()) || isIndirect)) | 
|  | return false; | 
|  |  | 
|  | // Look for obvious safe cases to perform tail call optimization that do not | 
|  | // require ABI changes. This is what gcc calls sibcall. | 
|  |  | 
|  | // Exception-handling functions need a special set of instructions to indicate | 
|  | // a return to the hardware. Tail-calling another function would probably | 
|  | // break this. | 
|  | if (CallerF.hasFnAttribute("interrupt")) | 
|  | return false; | 
|  |  | 
|  | // Also avoid sibcall optimization if either caller or callee uses struct | 
|  | // return semantics. | 
|  | if (isCalleeStructRet || isCallerStructRet) | 
|  | return false; | 
|  |  | 
|  | // Externally-defined functions with weak linkage should not be | 
|  | // tail-called on ARM when the OS does not support dynamic | 
|  | // pre-emption of symbols, as the AAELF spec requires normal calls | 
|  | // to undefined weak functions to be replaced with a NOP or jump to the | 
|  | // next instruction. The behaviour of branch instructions in this | 
|  | // situation (as used for tail calls) is implementation-defined, so we | 
|  | // cannot rely on the linker replacing the tail call with a return. | 
|  | if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) { | 
|  | const GlobalValue *GV = G->getGlobal(); | 
|  | const Triple &TT = getTargetMachine().getTargetTriple(); | 
|  | if (GV->hasExternalWeakLinkage() && | 
|  | (!TT.isOSWindows() || TT.isOSBinFormatELF() || TT.isOSBinFormatMachO())) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Check that the call results are passed in the same way. | 
|  | LLVMContext &C = *DAG.getContext(); | 
|  | if (!CCState::resultsCompatible( | 
|  | getEffectiveCallingConv(CalleeCC, isVarArg), | 
|  | getEffectiveCallingConv(CallerCC, CallerF.isVarArg()), MF, C, Ins, | 
|  | CCAssignFnForReturn(CalleeCC, isVarArg), | 
|  | CCAssignFnForReturn(CallerCC, CallerF.isVarArg()))) | 
|  | return false; | 
|  | // The callee has to preserve all registers the caller needs to preserve. | 
|  | const ARMBaseRegisterInfo *TRI = Subtarget->getRegisterInfo(); | 
|  | const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC); | 
|  | if (CalleeCC != CallerCC) { | 
|  | const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC); | 
|  | if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // If Caller's vararg or byval argument has been split between registers and | 
|  | // stack, do not perform tail call, since part of the argument is in caller's | 
|  | // local frame. | 
|  | const ARMFunctionInfo *AFI_Caller = MF.getInfo<ARMFunctionInfo>(); | 
|  | if (AFI_Caller->getArgRegsSaveSize()) | 
|  | return false; | 
|  |  | 
|  | // If the callee takes no arguments then go on to check the results of the | 
|  | // call. | 
|  | if (!Outs.empty()) { | 
|  | // Check if stack adjustment is needed. For now, do not do this if any | 
|  | // argument is passed on the stack. | 
|  | SmallVector<CCValAssign, 16> ArgLocs; | 
|  | CCState CCInfo(CalleeCC, isVarArg, MF, ArgLocs, C); | 
|  | CCInfo.AnalyzeCallOperands(Outs, CCAssignFnForCall(CalleeCC, isVarArg)); | 
|  | if (CCInfo.getNextStackOffset()) { | 
|  | // Check if the arguments are already laid out in the right way as | 
|  | // the caller's fixed stack objects. | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | const MachineRegisterInfo *MRI = &MF.getRegInfo(); | 
|  | const TargetInstrInfo *TII = Subtarget->getInstrInfo(); | 
|  | for (unsigned i = 0, realArgIdx = 0, e = ArgLocs.size(); | 
|  | i != e; | 
|  | ++i, ++realArgIdx) { | 
|  | CCValAssign &VA = ArgLocs[i]; | 
|  | EVT RegVT = VA.getLocVT(); | 
|  | SDValue Arg = OutVals[realArgIdx]; | 
|  | ISD::ArgFlagsTy Flags = Outs[realArgIdx].Flags; | 
|  | if (VA.getLocInfo() == CCValAssign::Indirect) | 
|  | return false; | 
|  | if (VA.needsCustom()) { | 
|  | // f64 and vector types are split into multiple registers or | 
|  | // register/stack-slot combinations.  The types will not match | 
|  | // the registers; give up on memory f64 refs until we figure | 
|  | // out what to do about this. | 
|  | if (!VA.isRegLoc()) | 
|  | return false; | 
|  | if (!ArgLocs[++i].isRegLoc()) | 
|  | return false; | 
|  | if (RegVT == MVT::v2f64) { | 
|  | if (!ArgLocs[++i].isRegLoc()) | 
|  | return false; | 
|  | if (!ArgLocs[++i].isRegLoc()) | 
|  | return false; | 
|  | } | 
|  | } else if (!VA.isRegLoc()) { | 
|  | if (!MatchingStackOffset(Arg, VA.getLocMemOffset(), Flags, | 
|  | MFI, MRI, TII)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | const MachineRegisterInfo &MRI = MF.getRegInfo(); | 
|  | if (!parametersInCSRMatch(MRI, CallerPreserved, ArgLocs, OutVals)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool | 
|  | ARMTargetLowering::CanLowerReturn(CallingConv::ID CallConv, | 
|  | MachineFunction &MF, bool isVarArg, | 
|  | const SmallVectorImpl<ISD::OutputArg> &Outs, | 
|  | LLVMContext &Context) const { | 
|  | SmallVector<CCValAssign, 16> RVLocs; | 
|  | CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context); | 
|  | return CCInfo.CheckReturn(Outs, CCAssignFnForReturn(CallConv, isVarArg)); | 
|  | } | 
|  |  | 
|  | static SDValue LowerInterruptReturn(SmallVectorImpl<SDValue> &RetOps, | 
|  | const SDLoc &DL, SelectionDAG &DAG) { | 
|  | const MachineFunction &MF = DAG.getMachineFunction(); | 
|  | const Function &F = MF.getFunction(); | 
|  |  | 
|  | StringRef IntKind = F.getFnAttribute("interrupt").getValueAsString(); | 
|  |  | 
|  | // See ARM ARM v7 B1.8.3. On exception entry LR is set to a possibly offset | 
|  | // version of the "preferred return address". These offsets affect the return | 
|  | // instruction if this is a return from PL1 without hypervisor extensions. | 
|  | //    IRQ/FIQ: +4     "subs pc, lr, #4" | 
|  | //    SWI:     0      "subs pc, lr, #0" | 
|  | //    ABORT:   +4     "subs pc, lr, #4" | 
|  | //    UNDEF:   +4/+2  "subs pc, lr, #0" | 
|  | // UNDEF varies depending on where the exception came from ARM or Thumb | 
|  | // mode. Alongside GCC, we throw our hands up in disgust and pretend it's 0. | 
|  |  | 
|  | int64_t LROffset; | 
|  | if (IntKind == "" || IntKind == "IRQ" || IntKind == "FIQ" || | 
|  | IntKind == "ABORT") | 
|  | LROffset = 4; | 
|  | else if (IntKind == "SWI" || IntKind == "UNDEF") | 
|  | LROffset = 0; | 
|  | else | 
|  | report_fatal_error("Unsupported interrupt attribute. If present, value " | 
|  | "must be one of: IRQ, FIQ, SWI, ABORT or UNDEF"); | 
|  |  | 
|  | RetOps.insert(RetOps.begin() + 1, | 
|  | DAG.getConstant(LROffset, DL, MVT::i32, false)); | 
|  |  | 
|  | return DAG.getNode(ARMISD::INTRET_FLAG, DL, MVT::Other, RetOps); | 
|  | } | 
|  |  | 
|  | SDValue | 
|  | ARMTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, | 
|  | bool isVarArg, | 
|  | const SmallVectorImpl<ISD::OutputArg> &Outs, | 
|  | const SmallVectorImpl<SDValue> &OutVals, | 
|  | const SDLoc &dl, SelectionDAG &DAG) const { | 
|  | // CCValAssign - represent the assignment of the return value to a location. | 
|  | SmallVector<CCValAssign, 16> RVLocs; | 
|  |  | 
|  | // CCState - Info about the registers and stack slots. | 
|  | CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs, | 
|  | *DAG.getContext()); | 
|  |  | 
|  | // Analyze outgoing return values. | 
|  | CCInfo.AnalyzeReturn(Outs, CCAssignFnForReturn(CallConv, isVarArg)); | 
|  |  | 
|  | SDValue Flag; | 
|  | SmallVector<SDValue, 4> RetOps; | 
|  | RetOps.push_back(Chain); // Operand #0 = Chain (updated below) | 
|  | bool isLittleEndian = Subtarget->isLittle(); | 
|  |  | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  | AFI->setReturnRegsCount(RVLocs.size()); | 
|  |  | 
|  | // Report error if cmse entry function returns structure through first ptr arg. | 
|  | if (AFI->isCmseNSEntryFunction() && MF.getFunction().hasStructRetAttr()) { | 
|  | // Note: using an empty SDLoc(), as the first line of the function is a | 
|  | // better place to report than the last line. | 
|  | DiagnosticInfoUnsupported Diag( | 
|  | DAG.getMachineFunction().getFunction(), | 
|  | "secure entry function would return value through pointer", | 
|  | SDLoc().getDebugLoc()); | 
|  | DAG.getContext()->diagnose(Diag); | 
|  | } | 
|  |  | 
|  | // Copy the result values into the output registers. | 
|  | for (unsigned i = 0, realRVLocIdx = 0; | 
|  | i != RVLocs.size(); | 
|  | ++i, ++realRVLocIdx) { | 
|  | CCValAssign &VA = RVLocs[i]; | 
|  | assert(VA.isRegLoc() && "Can only return in registers!"); | 
|  |  | 
|  | SDValue Arg = OutVals[realRVLocIdx]; | 
|  | bool ReturnF16 = false; | 
|  |  | 
|  | if (Subtarget->hasFullFP16() && Subtarget->isTargetHardFloat()) { | 
|  | // Half-precision return values can be returned like this: | 
|  | // | 
|  | // t11 f16 = fadd ... | 
|  | // t12: i16 = bitcast t11 | 
|  | //   t13: i32 = zero_extend t12 | 
|  | // t14: f32 = bitcast t13  <~~~~~~~ Arg | 
|  | // | 
|  | // to avoid code generation for bitcasts, we simply set Arg to the node | 
|  | // that produces the f16 value, t11 in this case. | 
|  | // | 
|  | if (Arg.getValueType() == MVT::f32 && Arg.getOpcode() == ISD::BITCAST) { | 
|  | SDValue ZE = Arg.getOperand(0); | 
|  | if (ZE.getOpcode() == ISD::ZERO_EXTEND && ZE.getValueType() == MVT::i32) { | 
|  | SDValue BC = ZE.getOperand(0); | 
|  | if (BC.getOpcode() == ISD::BITCAST && BC.getValueType() == MVT::i16) { | 
|  | Arg = BC.getOperand(0); | 
|  | ReturnF16 = true; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | switch (VA.getLocInfo()) { | 
|  | default: llvm_unreachable("Unknown loc info!"); | 
|  | case CCValAssign::Full: break; | 
|  | case CCValAssign::BCvt: | 
|  | if (!ReturnF16) | 
|  | Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (VA.needsCustom()) { | 
|  | if (VA.getLocVT() == MVT::v2f64) { | 
|  | // Extract the first half and return it in two registers. | 
|  | SDValue Half = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, Arg, | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | SDValue HalfGPRs = DAG.getNode(ARMISD::VMOVRRD, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), Half); | 
|  |  | 
|  | Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), | 
|  | HalfGPRs.getValue(isLittleEndian ? 0 : 1), | 
|  | Flag); | 
|  | Flag = Chain.getValue(1); | 
|  | RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); | 
|  | VA = RVLocs[++i]; // skip ahead to next loc | 
|  | Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), | 
|  | HalfGPRs.getValue(isLittleEndian ? 1 : 0), | 
|  | Flag); | 
|  | Flag = Chain.getValue(1); | 
|  | RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); | 
|  | VA = RVLocs[++i]; // skip ahead to next loc | 
|  |  | 
|  | // Extract the 2nd half and fall through to handle it as an f64 value. | 
|  | Arg = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, Arg, | 
|  | DAG.getConstant(1, dl, MVT::i32)); | 
|  | } | 
|  | // Legalize ret f64 -> ret 2 x i32.  We always have fmrrd if f64 is | 
|  | // available. | 
|  | SDValue fmrrd = DAG.getNode(ARMISD::VMOVRRD, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), Arg); | 
|  | Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), | 
|  | fmrrd.getValue(isLittleEndian ? 0 : 1), | 
|  | Flag); | 
|  | Flag = Chain.getValue(1); | 
|  | RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); | 
|  | VA = RVLocs[++i]; // skip ahead to next loc | 
|  | Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), | 
|  | fmrrd.getValue(isLittleEndian ? 1 : 0), | 
|  | Flag); | 
|  | } else | 
|  | Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), Arg, Flag); | 
|  |  | 
|  | // Guarantee that all emitted copies are | 
|  | // stuck together, avoiding something bad. | 
|  | Flag = Chain.getValue(1); | 
|  | RetOps.push_back(DAG.getRegister(VA.getLocReg(), | 
|  | ReturnF16 ? MVT::f16 : VA.getLocVT())); | 
|  | } | 
|  | const ARMBaseRegisterInfo *TRI = Subtarget->getRegisterInfo(); | 
|  | const MCPhysReg *I = | 
|  | TRI->getCalleeSavedRegsViaCopy(&DAG.getMachineFunction()); | 
|  | if (I) { | 
|  | for (; *I; ++I) { | 
|  | if (ARM::GPRRegClass.contains(*I)) | 
|  | RetOps.push_back(DAG.getRegister(*I, MVT::i32)); | 
|  | else if (ARM::DPRRegClass.contains(*I)) | 
|  | RetOps.push_back(DAG.getRegister(*I, MVT::getFloatingPointVT(64))); | 
|  | else | 
|  | llvm_unreachable("Unexpected register class in CSRsViaCopy!"); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Update chain and glue. | 
|  | RetOps[0] = Chain; | 
|  | if (Flag.getNode()) | 
|  | RetOps.push_back(Flag); | 
|  |  | 
|  | // CPUs which aren't M-class use a special sequence to return from | 
|  | // exceptions (roughly, any instruction setting pc and cpsr simultaneously, | 
|  | // though we use "subs pc, lr, #N"). | 
|  | // | 
|  | // M-class CPUs actually use a normal return sequence with a special | 
|  | // (hardware-provided) value in LR, so the normal code path works. | 
|  | if (DAG.getMachineFunction().getFunction().hasFnAttribute("interrupt") && | 
|  | !Subtarget->isMClass()) { | 
|  | if (Subtarget->isThumb1Only()) | 
|  | report_fatal_error("interrupt attribute is not supported in Thumb1"); | 
|  | return LowerInterruptReturn(RetOps, dl, DAG); | 
|  | } | 
|  |  | 
|  | ARMISD::NodeType RetNode = AFI->isCmseNSEntryFunction() ? ARMISD::SERET_FLAG : | 
|  | ARMISD::RET_FLAG; | 
|  | return DAG.getNode(RetNode, dl, MVT::Other, RetOps); | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isUsedByReturnOnly(SDNode *N, SDValue &Chain) const { | 
|  | if (N->getNumValues() != 1) | 
|  | return false; | 
|  | if (!N->hasNUsesOfValue(1, 0)) | 
|  | return false; | 
|  |  | 
|  | SDValue TCChain = Chain; | 
|  | SDNode *Copy = *N->use_begin(); | 
|  | if (Copy->getOpcode() == ISD::CopyToReg) { | 
|  | // If the copy has a glue operand, we conservatively assume it isn't safe to | 
|  | // perform a tail call. | 
|  | if (Copy->getOperand(Copy->getNumOperands()-1).getValueType() == MVT::Glue) | 
|  | return false; | 
|  | TCChain = Copy->getOperand(0); | 
|  | } else if (Copy->getOpcode() == ARMISD::VMOVRRD) { | 
|  | SDNode *VMov = Copy; | 
|  | // f64 returned in a pair of GPRs. | 
|  | SmallPtrSet<SDNode*, 2> Copies; | 
|  | for (SDNode::use_iterator UI = VMov->use_begin(), UE = VMov->use_end(); | 
|  | UI != UE; ++UI) { | 
|  | if (UI->getOpcode() != ISD::CopyToReg) | 
|  | return false; | 
|  | Copies.insert(*UI); | 
|  | } | 
|  | if (Copies.size() > 2) | 
|  | return false; | 
|  |  | 
|  | for (SDNode::use_iterator UI = VMov->use_begin(), UE = VMov->use_end(); | 
|  | UI != UE; ++UI) { | 
|  | SDValue UseChain = UI->getOperand(0); | 
|  | if (Copies.count(UseChain.getNode())) | 
|  | // Second CopyToReg | 
|  | Copy = *UI; | 
|  | else { | 
|  | // We are at the top of this chain. | 
|  | // If the copy has a glue operand, we conservatively assume it | 
|  | // isn't safe to perform a tail call. | 
|  | if (UI->getOperand(UI->getNumOperands()-1).getValueType() == MVT::Glue) | 
|  | return false; | 
|  | // First CopyToReg | 
|  | TCChain = UseChain; | 
|  | } | 
|  | } | 
|  | } else if (Copy->getOpcode() == ISD::BITCAST) { | 
|  | // f32 returned in a single GPR. | 
|  | if (!Copy->hasOneUse()) | 
|  | return false; | 
|  | Copy = *Copy->use_begin(); | 
|  | if (Copy->getOpcode() != ISD::CopyToReg || !Copy->hasNUsesOfValue(1, 0)) | 
|  | return false; | 
|  | // If the copy has a glue operand, we conservatively assume it isn't safe to | 
|  | // perform a tail call. | 
|  | if (Copy->getOperand(Copy->getNumOperands()-1).getValueType() == MVT::Glue) | 
|  | return false; | 
|  | TCChain = Copy->getOperand(0); | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool HasRet = false; | 
|  | for (SDNode::use_iterator UI = Copy->use_begin(), UE = Copy->use_end(); | 
|  | UI != UE; ++UI) { | 
|  | if (UI->getOpcode() != ARMISD::RET_FLAG && | 
|  | UI->getOpcode() != ARMISD::INTRET_FLAG) | 
|  | return false; | 
|  | HasRet = true; | 
|  | } | 
|  |  | 
|  | if (!HasRet) | 
|  | return false; | 
|  |  | 
|  | Chain = TCChain; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const { | 
|  | if (!Subtarget->supportsTailCall()) | 
|  | return false; | 
|  |  | 
|  | if (!CI->isTailCall()) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Trying to write a 64 bit value so need to split into two 32 bit values first, | 
|  | // and pass the lower and high parts through. | 
|  | static SDValue LowerWRITE_REGISTER(SDValue Op, SelectionDAG &DAG) { | 
|  | SDLoc DL(Op); | 
|  | SDValue WriteValue = Op->getOperand(2); | 
|  |  | 
|  | // This function is only supposed to be called for i64 type argument. | 
|  | assert(WriteValue.getValueType() == MVT::i64 | 
|  | && "LowerWRITE_REGISTER called for non-i64 type argument."); | 
|  |  | 
|  | SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, WriteValue, | 
|  | DAG.getConstant(0, DL, MVT::i32)); | 
|  | SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, WriteValue, | 
|  | DAG.getConstant(1, DL, MVT::i32)); | 
|  | SDValue Ops[] = { Op->getOperand(0), Op->getOperand(1), Lo, Hi }; | 
|  | return DAG.getNode(ISD::WRITE_REGISTER, DL, MVT::Other, Ops); | 
|  | } | 
|  |  | 
|  | // ConstantPool, JumpTable, GlobalAddress, and ExternalSymbol are lowered as | 
|  | // their target counterpart wrapped in the ARMISD::Wrapper node. Suppose N is | 
|  | // one of the above mentioned nodes. It has to be wrapped because otherwise | 
|  | // Select(N) returns N. So the raw TargetGlobalAddress nodes, etc. can only | 
|  | // be used to form addressing mode. These wrapped nodes will be selected | 
|  | // into MOVi. | 
|  | SDValue ARMTargetLowering::LowerConstantPool(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | EVT PtrVT = Op.getValueType(); | 
|  | // FIXME there is no actual debug info here | 
|  | SDLoc dl(Op); | 
|  | ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op); | 
|  | SDValue Res; | 
|  |  | 
|  | // When generating execute-only code Constant Pools must be promoted to the | 
|  | // global data section. It's a bit ugly that we can't share them across basic | 
|  | // blocks, but this way we guarantee that execute-only behaves correct with | 
|  | // position-independent addressing modes. | 
|  | if (Subtarget->genExecuteOnly()) { | 
|  | auto AFI = DAG.getMachineFunction().getInfo<ARMFunctionInfo>(); | 
|  | auto T = const_cast<Type*>(CP->getType()); | 
|  | auto C = const_cast<Constant*>(CP->getConstVal()); | 
|  | auto M = const_cast<Module*>(DAG.getMachineFunction(). | 
|  | getFunction().getParent()); | 
|  | auto GV = new GlobalVariable( | 
|  | *M, T, /*isConstant=*/true, GlobalVariable::InternalLinkage, C, | 
|  | Twine(DAG.getDataLayout().getPrivateGlobalPrefix()) + "CP" + | 
|  | Twine(DAG.getMachineFunction().getFunctionNumber()) + "_" + | 
|  | Twine(AFI->createPICLabelUId()) | 
|  | ); | 
|  | SDValue GA = DAG.getTargetGlobalAddress(dyn_cast<GlobalValue>(GV), | 
|  | dl, PtrVT); | 
|  | return LowerGlobalAddress(GA, DAG); | 
|  | } | 
|  |  | 
|  | if (CP->isMachineConstantPoolEntry()) | 
|  | Res = | 
|  | DAG.getTargetConstantPool(CP->getMachineCPVal(), PtrVT, CP->getAlign()); | 
|  | else | 
|  | Res = DAG.getTargetConstantPool(CP->getConstVal(), PtrVT, CP->getAlign()); | 
|  | return DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Res); | 
|  | } | 
|  |  | 
|  | unsigned ARMTargetLowering::getJumpTableEncoding() const { | 
|  | return MachineJumpTableInfo::EK_Inline; | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  | unsigned ARMPCLabelIndex = 0; | 
|  | SDLoc DL(Op); | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress(); | 
|  | SDValue CPAddr; | 
|  | bool IsPositionIndependent = isPositionIndependent() || Subtarget->isROPI(); | 
|  | if (!IsPositionIndependent) { | 
|  | CPAddr = DAG.getTargetConstantPool(BA, PtrVT, Align(4)); | 
|  | } else { | 
|  | unsigned PCAdj = Subtarget->isThumb() ? 4 : 8; | 
|  | ARMPCLabelIndex = AFI->createPICLabelUId(); | 
|  | ARMConstantPoolValue *CPV = | 
|  | ARMConstantPoolConstant::Create(BA, ARMPCLabelIndex, | 
|  | ARMCP::CPBlockAddress, PCAdj); | 
|  | CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); | 
|  | } | 
|  | CPAddr = DAG.getNode(ARMISD::Wrapper, DL, PtrVT, CPAddr); | 
|  | SDValue Result = DAG.getLoad( | 
|  | PtrVT, DL, DAG.getEntryNode(), CPAddr, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  | if (!IsPositionIndependent) | 
|  | return Result; | 
|  | SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, DL, MVT::i32); | 
|  | return DAG.getNode(ARMISD::PIC_ADD, DL, PtrVT, Result, PICLabel); | 
|  | } | 
|  |  | 
|  | /// Convert a TLS address reference into the correct sequence of loads | 
|  | /// and calls to compute the variable's address for Darwin, and return an | 
|  | /// SDValue containing the final node. | 
|  |  | 
|  | /// Darwin only has one TLS scheme which must be capable of dealing with the | 
|  | /// fully general situation, in the worst case. This means: | 
|  | ///     + "extern __thread" declaration. | 
|  | ///     + Defined in a possibly unknown dynamic library. | 
|  | /// | 
|  | /// The general system is that each __thread variable has a [3 x i32] descriptor | 
|  | /// which contains information used by the runtime to calculate the address. The | 
|  | /// only part of this the compiler needs to know about is the first word, which | 
|  | /// contains a function pointer that must be called with the address of the | 
|  | /// entire descriptor in "r0". | 
|  | /// | 
|  | /// Since this descriptor may be in a different unit, in general access must | 
|  | /// proceed along the usual ARM rules. A common sequence to produce is: | 
|  | /// | 
|  | ///     movw rT1, :lower16:_var$non_lazy_ptr | 
|  | ///     movt rT1, :upper16:_var$non_lazy_ptr | 
|  | ///     ldr r0, [rT1] | 
|  | ///     ldr rT2, [r0] | 
|  | ///     blx rT2 | 
|  | ///     [...address now in r0...] | 
|  | SDValue | 
|  | ARMTargetLowering::LowerGlobalTLSAddressDarwin(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | assert(Subtarget->isTargetDarwin() && | 
|  | "This function expects a Darwin target"); | 
|  | SDLoc DL(Op); | 
|  |  | 
|  | // First step is to get the address of the actua global symbol. This is where | 
|  | // the TLS descriptor lives. | 
|  | SDValue DescAddr = LowerGlobalAddressDarwin(Op, DAG); | 
|  |  | 
|  | // The first entry in the descriptor is a function pointer that we must call | 
|  | // to obtain the address of the variable. | 
|  | SDValue Chain = DAG.getEntryNode(); | 
|  | SDValue FuncTLVGet = DAG.getLoad( | 
|  | MVT::i32, DL, Chain, DescAddr, | 
|  | MachinePointerInfo::getGOT(DAG.getMachineFunction()), | 
|  | /* Alignment = */ 4, | 
|  | MachineMemOperand::MONonTemporal | MachineMemOperand::MODereferenceable | | 
|  | MachineMemOperand::MOInvariant); | 
|  | Chain = FuncTLVGet.getValue(1); | 
|  |  | 
|  | MachineFunction &F = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = F.getFrameInfo(); | 
|  | MFI.setAdjustsStack(true); | 
|  |  | 
|  | // TLS calls preserve all registers except those that absolutely must be | 
|  | // trashed: R0 (it takes an argument), LR (it's a call) and CPSR (let's not be | 
|  | // silly). | 
|  | auto TRI = | 
|  | getTargetMachine().getSubtargetImpl(F.getFunction())->getRegisterInfo(); | 
|  | auto ARI = static_cast<const ARMRegisterInfo *>(TRI); | 
|  | const uint32_t *Mask = ARI->getTLSCallPreservedMask(DAG.getMachineFunction()); | 
|  |  | 
|  | // Finally, we can make the call. This is just a degenerate version of a | 
|  | // normal AArch64 call node: r0 takes the address of the descriptor, and | 
|  | // returns the address of the variable in this thread. | 
|  | Chain = DAG.getCopyToReg(Chain, DL, ARM::R0, DescAddr, SDValue()); | 
|  | Chain = | 
|  | DAG.getNode(ARMISD::CALL, DL, DAG.getVTList(MVT::Other, MVT::Glue), | 
|  | Chain, FuncTLVGet, DAG.getRegister(ARM::R0, MVT::i32), | 
|  | DAG.getRegisterMask(Mask), Chain.getValue(1)); | 
|  | return DAG.getCopyFromReg(Chain, DL, ARM::R0, MVT::i32, Chain.getValue(1)); | 
|  | } | 
|  |  | 
|  | SDValue | 
|  | ARMTargetLowering::LowerGlobalTLSAddressWindows(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | assert(Subtarget->isTargetWindows() && "Windows specific TLS lowering"); | 
|  |  | 
|  | SDValue Chain = DAG.getEntryNode(); | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | SDLoc DL(Op); | 
|  |  | 
|  | // Load the current TEB (thread environment block) | 
|  | SDValue Ops[] = {Chain, | 
|  | DAG.getTargetConstant(Intrinsic::arm_mrc, DL, MVT::i32), | 
|  | DAG.getTargetConstant(15, DL, MVT::i32), | 
|  | DAG.getTargetConstant(0, DL, MVT::i32), | 
|  | DAG.getTargetConstant(13, DL, MVT::i32), | 
|  | DAG.getTargetConstant(0, DL, MVT::i32), | 
|  | DAG.getTargetConstant(2, DL, MVT::i32)}; | 
|  | SDValue CurrentTEB = DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL, | 
|  | DAG.getVTList(MVT::i32, MVT::Other), Ops); | 
|  |  | 
|  | SDValue TEB = CurrentTEB.getValue(0); | 
|  | Chain = CurrentTEB.getValue(1); | 
|  |  | 
|  | // Load the ThreadLocalStoragePointer from the TEB | 
|  | // A pointer to the TLS array is located at offset 0x2c from the TEB. | 
|  | SDValue TLSArray = | 
|  | DAG.getNode(ISD::ADD, DL, PtrVT, TEB, DAG.getIntPtrConstant(0x2c, DL)); | 
|  | TLSArray = DAG.getLoad(PtrVT, DL, Chain, TLSArray, MachinePointerInfo()); | 
|  |  | 
|  | // The pointer to the thread's TLS data area is at the TLS Index scaled by 4 | 
|  | // offset into the TLSArray. | 
|  |  | 
|  | // Load the TLS index from the C runtime | 
|  | SDValue TLSIndex = | 
|  | DAG.getTargetExternalSymbol("_tls_index", PtrVT, ARMII::MO_NO_FLAG); | 
|  | TLSIndex = DAG.getNode(ARMISD::Wrapper, DL, PtrVT, TLSIndex); | 
|  | TLSIndex = DAG.getLoad(PtrVT, DL, Chain, TLSIndex, MachinePointerInfo()); | 
|  |  | 
|  | SDValue Slot = DAG.getNode(ISD::SHL, DL, PtrVT, TLSIndex, | 
|  | DAG.getConstant(2, DL, MVT::i32)); | 
|  | SDValue TLS = DAG.getLoad(PtrVT, DL, Chain, | 
|  | DAG.getNode(ISD::ADD, DL, PtrVT, TLSArray, Slot), | 
|  | MachinePointerInfo()); | 
|  |  | 
|  | // Get the offset of the start of the .tls section (section base) | 
|  | const auto *GA = cast<GlobalAddressSDNode>(Op); | 
|  | auto *CPV = ARMConstantPoolConstant::Create(GA->getGlobal(), ARMCP::SECREL); | 
|  | SDValue Offset = DAG.getLoad( | 
|  | PtrVT, DL, Chain, | 
|  | DAG.getNode(ARMISD::Wrapper, DL, MVT::i32, | 
|  | DAG.getTargetConstantPool(CPV, PtrVT, Align(4))), | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  |  | 
|  | return DAG.getNode(ISD::ADD, DL, PtrVT, TLS, Offset); | 
|  | } | 
|  |  | 
|  | // Lower ISD::GlobalTLSAddress using the "general dynamic" model | 
|  | SDValue | 
|  | ARMTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, | 
|  | SelectionDAG &DAG) const { | 
|  | SDLoc dl(GA); | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  | unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); | 
|  | ARMConstantPoolValue *CPV = | 
|  | ARMConstantPoolConstant::Create(GA->getGlobal(), ARMPCLabelIndex, | 
|  | ARMCP::CPValue, PCAdj, ARMCP::TLSGD, true); | 
|  | SDValue Argument = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); | 
|  | Argument = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Argument); | 
|  | Argument = DAG.getLoad( | 
|  | PtrVT, dl, DAG.getEntryNode(), Argument, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  | SDValue Chain = Argument.getValue(1); | 
|  |  | 
|  | SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, dl, MVT::i32); | 
|  | Argument = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Argument, PICLabel); | 
|  |  | 
|  | // call __tls_get_addr. | 
|  | ArgListTy Args; | 
|  | ArgListEntry Entry; | 
|  | Entry.Node = Argument; | 
|  | Entry.Ty = (Type *) Type::getInt32Ty(*DAG.getContext()); | 
|  | Args.push_back(Entry); | 
|  |  | 
|  | // FIXME: is there useful debug info available here? | 
|  | TargetLowering::CallLoweringInfo CLI(DAG); | 
|  | CLI.setDebugLoc(dl).setChain(Chain).setLibCallee( | 
|  | CallingConv::C, Type::getInt32Ty(*DAG.getContext()), | 
|  | DAG.getExternalSymbol("__tls_get_addr", PtrVT), std::move(Args)); | 
|  |  | 
|  | std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI); | 
|  | return CallResult.first; | 
|  | } | 
|  |  | 
|  | // Lower ISD::GlobalTLSAddress using the "initial exec" or | 
|  | // "local exec" model. | 
|  | SDValue | 
|  | ARMTargetLowering::LowerToTLSExecModels(GlobalAddressSDNode *GA, | 
|  | SelectionDAG &DAG, | 
|  | TLSModel::Model model) const { | 
|  | const GlobalValue *GV = GA->getGlobal(); | 
|  | SDLoc dl(GA); | 
|  | SDValue Offset; | 
|  | SDValue Chain = DAG.getEntryNode(); | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | // Get the Thread Pointer | 
|  | SDValue ThreadPointer = DAG.getNode(ARMISD::THREAD_POINTER, dl, PtrVT); | 
|  |  | 
|  | if (model == TLSModel::InitialExec) { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  | unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); | 
|  | // Initial exec model. | 
|  | unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; | 
|  | ARMConstantPoolValue *CPV = | 
|  | ARMConstantPoolConstant::Create(GA->getGlobal(), ARMPCLabelIndex, | 
|  | ARMCP::CPValue, PCAdj, ARMCP::GOTTPOFF, | 
|  | true); | 
|  | Offset = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); | 
|  | Offset = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Offset); | 
|  | Offset = DAG.getLoad( | 
|  | PtrVT, dl, Chain, Offset, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  | Chain = Offset.getValue(1); | 
|  |  | 
|  | SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, dl, MVT::i32); | 
|  | Offset = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Offset, PICLabel); | 
|  |  | 
|  | Offset = DAG.getLoad( | 
|  | PtrVT, dl, Chain, Offset, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  | } else { | 
|  | // local exec model | 
|  | assert(model == TLSModel::LocalExec); | 
|  | ARMConstantPoolValue *CPV = | 
|  | ARMConstantPoolConstant::Create(GV, ARMCP::TPOFF); | 
|  | Offset = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); | 
|  | Offset = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Offset); | 
|  | Offset = DAG.getLoad( | 
|  | PtrVT, dl, Chain, Offset, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  | } | 
|  |  | 
|  | // The address of the thread local variable is the add of the thread | 
|  | // pointer with the offset of the variable. | 
|  | return DAG.getNode(ISD::ADD, dl, PtrVT, ThreadPointer, Offset); | 
|  | } | 
|  |  | 
|  | SDValue | 
|  | ARMTargetLowering::LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { | 
|  | GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op); | 
|  | if (DAG.getTarget().useEmulatedTLS()) | 
|  | return LowerToTLSEmulatedModel(GA, DAG); | 
|  |  | 
|  | if (Subtarget->isTargetDarwin()) | 
|  | return LowerGlobalTLSAddressDarwin(Op, DAG); | 
|  |  | 
|  | if (Subtarget->isTargetWindows()) | 
|  | return LowerGlobalTLSAddressWindows(Op, DAG); | 
|  |  | 
|  | // TODO: implement the "local dynamic" model | 
|  | assert(Subtarget->isTargetELF() && "Only ELF implemented here"); | 
|  | TLSModel::Model model = getTargetMachine().getTLSModel(GA->getGlobal()); | 
|  |  | 
|  | switch (model) { | 
|  | case TLSModel::GeneralDynamic: | 
|  | case TLSModel::LocalDynamic: | 
|  | return LowerToTLSGeneralDynamicModel(GA, DAG); | 
|  | case TLSModel::InitialExec: | 
|  | case TLSModel::LocalExec: | 
|  | return LowerToTLSExecModels(GA, DAG, model); | 
|  | } | 
|  | llvm_unreachable("bogus TLS model"); | 
|  | } | 
|  |  | 
|  | /// Return true if all users of V are within function F, looking through | 
|  | /// ConstantExprs. | 
|  | static bool allUsersAreInFunction(const Value *V, const Function *F) { | 
|  | SmallVector<const User*,4> Worklist; | 
|  | for (auto *U : V->users()) | 
|  | Worklist.push_back(U); | 
|  | while (!Worklist.empty()) { | 
|  | auto *U = Worklist.pop_back_val(); | 
|  | if (isa<ConstantExpr>(U)) { | 
|  | for (auto *UU : U->users()) | 
|  | Worklist.push_back(UU); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | auto *I = dyn_cast<Instruction>(U); | 
|  | if (!I || I->getParent()->getParent() != F) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static SDValue promoteToConstantPool(const ARMTargetLowering *TLI, | 
|  | const GlobalValue *GV, SelectionDAG &DAG, | 
|  | EVT PtrVT, const SDLoc &dl) { | 
|  | // If we're creating a pool entry for a constant global with unnamed address, | 
|  | // and the global is small enough, we can emit it inline into the constant pool | 
|  | // to save ourselves an indirection. | 
|  | // | 
|  | // This is a win if the constant is only used in one function (so it doesn't | 
|  | // need to be duplicated) or duplicating the constant wouldn't increase code | 
|  | // size (implying the constant is no larger than 4 bytes). | 
|  | const Function &F = DAG.getMachineFunction().getFunction(); | 
|  |  | 
|  | // We rely on this decision to inline being idemopotent and unrelated to the | 
|  | // use-site. We know that if we inline a variable at one use site, we'll | 
|  | // inline it elsewhere too (and reuse the constant pool entry). Fast-isel | 
|  | // doesn't know about this optimization, so bail out if it's enabled else | 
|  | // we could decide to inline here (and thus never emit the GV) but require | 
|  | // the GV from fast-isel generated code. | 
|  | if (!EnableConstpoolPromotion || | 
|  | DAG.getMachineFunction().getTarget().Options.EnableFastISel) | 
|  | return SDValue(); | 
|  |  | 
|  | auto *GVar = dyn_cast<GlobalVariable>(GV); | 
|  | if (!GVar || !GVar->hasInitializer() || | 
|  | !GVar->isConstant() || !GVar->hasGlobalUnnamedAddr() || | 
|  | !GVar->hasLocalLinkage()) | 
|  | return SDValue(); | 
|  |  | 
|  | // If we inline a value that contains relocations, we move the relocations | 
|  | // from .data to .text. This is not allowed in position-independent code. | 
|  | auto *Init = GVar->getInitializer(); | 
|  | if ((TLI->isPositionIndependent() || TLI->getSubtarget()->isROPI()) && | 
|  | Init->needsRelocation()) | 
|  | return SDValue(); | 
|  |  | 
|  | // The constant islands pass can only really deal with alignment requests | 
|  | // <= 4 bytes and cannot pad constants itself. Therefore we cannot promote | 
|  | // any type wanting greater alignment requirements than 4 bytes. We also | 
|  | // can only promote constants that are multiples of 4 bytes in size or | 
|  | // are paddable to a multiple of 4. Currently we only try and pad constants | 
|  | // that are strings for simplicity. | 
|  | auto *CDAInit = dyn_cast<ConstantDataArray>(Init); | 
|  | unsigned Size = DAG.getDataLayout().getTypeAllocSize(Init->getType()); | 
|  | unsigned PrefAlign = DAG.getDataLayout().getPreferredAlignment(GVar); | 
|  | unsigned RequiredPadding = 4 - (Size % 4); | 
|  | bool PaddingPossible = | 
|  | RequiredPadding == 4 || (CDAInit && CDAInit->isString()); | 
|  | if (!PaddingPossible || PrefAlign > 4 || Size > ConstpoolPromotionMaxSize || | 
|  | Size == 0) | 
|  | return SDValue(); | 
|  |  | 
|  | unsigned PaddedSize = Size + ((RequiredPadding == 4) ? 0 : RequiredPadding); | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  |  | 
|  | // We can't bloat the constant pool too much, else the ConstantIslands pass | 
|  | // may fail to converge. If we haven't promoted this global yet (it may have | 
|  | // multiple uses), and promoting it would increase the constant pool size (Sz | 
|  | // > 4), ensure we have space to do so up to MaxTotal. | 
|  | if (!AFI->getGlobalsPromotedToConstantPool().count(GVar) && Size > 4) | 
|  | if (AFI->getPromotedConstpoolIncrease() + PaddedSize - 4 >= | 
|  | ConstpoolPromotionMaxTotal) | 
|  | return SDValue(); | 
|  |  | 
|  | // This is only valid if all users are in a single function; we can't clone | 
|  | // the constant in general. The LLVM IR unnamed_addr allows merging | 
|  | // constants, but not cloning them. | 
|  | // | 
|  | // We could potentially allow cloning if we could prove all uses of the | 
|  | // constant in the current function don't care about the address, like | 
|  | // printf format strings. But that isn't implemented for now. | 
|  | if (!allUsersAreInFunction(GVar, &F)) | 
|  | return SDValue(); | 
|  |  | 
|  | // We're going to inline this global. Pad it out if needed. | 
|  | if (RequiredPadding != 4) { | 
|  | StringRef S = CDAInit->getAsString(); | 
|  |  | 
|  | SmallVector<uint8_t,16> V(S.size()); | 
|  | std::copy(S.bytes_begin(), S.bytes_end(), V.begin()); | 
|  | while (RequiredPadding--) | 
|  | V.push_back(0); | 
|  | Init = ConstantDataArray::get(*DAG.getContext(), V); | 
|  | } | 
|  |  | 
|  | auto CPVal = ARMConstantPoolConstant::Create(GVar, Init); | 
|  | SDValue CPAddr = DAG.getTargetConstantPool(CPVal, PtrVT, Align(4)); | 
|  | if (!AFI->getGlobalsPromotedToConstantPool().count(GVar)) { | 
|  | AFI->markGlobalAsPromotedToConstantPool(GVar); | 
|  | AFI->setPromotedConstpoolIncrease(AFI->getPromotedConstpoolIncrease() + | 
|  | PaddedSize - 4); | 
|  | } | 
|  | ++NumConstpoolPromoted; | 
|  | return DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isReadOnly(const GlobalValue *GV) const { | 
|  | if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV)) | 
|  | if (!(GV = GA->getBaseObject())) | 
|  | return false; | 
|  | if (const auto *V = dyn_cast<GlobalVariable>(GV)) | 
|  | return V->isConstant(); | 
|  | return isa<Function>(GV); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerGlobalAddress(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | switch (Subtarget->getTargetTriple().getObjectFormat()) { | 
|  | default: llvm_unreachable("unknown object format"); | 
|  | case Triple::COFF: | 
|  | return LowerGlobalAddressWindows(Op, DAG); | 
|  | case Triple::ELF: | 
|  | return LowerGlobalAddressELF(Op, DAG); | 
|  | case Triple::MachO: | 
|  | return LowerGlobalAddressDarwin(Op, DAG); | 
|  | } | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | SDLoc dl(Op); | 
|  | const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); | 
|  | const TargetMachine &TM = getTargetMachine(); | 
|  | bool IsRO = isReadOnly(GV); | 
|  |  | 
|  | // promoteToConstantPool only if not generating XO text section | 
|  | if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV) && !Subtarget->genExecuteOnly()) | 
|  | if (SDValue V = promoteToConstantPool(this, GV, DAG, PtrVT, dl)) | 
|  | return V; | 
|  |  | 
|  | if (isPositionIndependent()) { | 
|  | bool UseGOT_PREL = !TM.shouldAssumeDSOLocal(*GV->getParent(), GV); | 
|  | SDValue G = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, | 
|  | UseGOT_PREL ? ARMII::MO_GOT : 0); | 
|  | SDValue Result = DAG.getNode(ARMISD::WrapperPIC, dl, PtrVT, G); | 
|  | if (UseGOT_PREL) | 
|  | Result = | 
|  | DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Result, | 
|  | MachinePointerInfo::getGOT(DAG.getMachineFunction())); | 
|  | return Result; | 
|  | } else if (Subtarget->isROPI() && IsRO) { | 
|  | // PC-relative. | 
|  | SDValue G = DAG.getTargetGlobalAddress(GV, dl, PtrVT); | 
|  | SDValue Result = DAG.getNode(ARMISD::WrapperPIC, dl, PtrVT, G); | 
|  | return Result; | 
|  | } else if (Subtarget->isRWPI() && !IsRO) { | 
|  | // SB-relative. | 
|  | SDValue RelAddr; | 
|  | if (Subtarget->useMovt()) { | 
|  | ++NumMovwMovt; | 
|  | SDValue G = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, ARMII::MO_SBREL); | 
|  | RelAddr = DAG.getNode(ARMISD::Wrapper, dl, PtrVT, G); | 
|  | } else { // use literal pool for address constant | 
|  | ARMConstantPoolValue *CPV = | 
|  | ARMConstantPoolConstant::Create(GV, ARMCP::SBREL); | 
|  | SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); | 
|  | CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); | 
|  | RelAddr = DAG.getLoad( | 
|  | PtrVT, dl, DAG.getEntryNode(), CPAddr, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  | } | 
|  | SDValue SB = DAG.getCopyFromReg(DAG.getEntryNode(), dl, ARM::R9, PtrVT); | 
|  | SDValue Result = DAG.getNode(ISD::ADD, dl, PtrVT, SB, RelAddr); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | // If we have T2 ops, we can materialize the address directly via movt/movw | 
|  | // pair. This is always cheaper. | 
|  | if (Subtarget->useMovt()) { | 
|  | ++NumMovwMovt; | 
|  | // FIXME: Once remat is capable of dealing with instructions with register | 
|  | // operands, expand this into two nodes. | 
|  | return DAG.getNode(ARMISD::Wrapper, dl, PtrVT, | 
|  | DAG.getTargetGlobalAddress(GV, dl, PtrVT)); | 
|  | } else { | 
|  | SDValue CPAddr = DAG.getTargetConstantPool(GV, PtrVT, Align(4)); | 
|  | CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); | 
|  | return DAG.getLoad( | 
|  | PtrVT, dl, DAG.getEntryNode(), CPAddr, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  | } | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerGlobalAddressDarwin(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | assert(!Subtarget->isROPI() && !Subtarget->isRWPI() && | 
|  | "ROPI/RWPI not currently supported for Darwin"); | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | SDLoc dl(Op); | 
|  | const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); | 
|  |  | 
|  | if (Subtarget->useMovt()) | 
|  | ++NumMovwMovt; | 
|  |  | 
|  | // FIXME: Once remat is capable of dealing with instructions with register | 
|  | // operands, expand this into multiple nodes | 
|  | unsigned Wrapper = | 
|  | isPositionIndependent() ? ARMISD::WrapperPIC : ARMISD::Wrapper; | 
|  |  | 
|  | SDValue G = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, ARMII::MO_NONLAZY); | 
|  | SDValue Result = DAG.getNode(Wrapper, dl, PtrVT, G); | 
|  |  | 
|  | if (Subtarget->isGVIndirectSymbol(GV)) | 
|  | Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Result, | 
|  | MachinePointerInfo::getGOT(DAG.getMachineFunction())); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerGlobalAddressWindows(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | assert(Subtarget->isTargetWindows() && "non-Windows COFF is not supported"); | 
|  | assert(Subtarget->useMovt() && | 
|  | "Windows on ARM expects to use movw/movt"); | 
|  | assert(!Subtarget->isROPI() && !Subtarget->isRWPI() && | 
|  | "ROPI/RWPI not currently supported for Windows"); | 
|  |  | 
|  | const TargetMachine &TM = getTargetMachine(); | 
|  | const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); | 
|  | ARMII::TOF TargetFlags = ARMII::MO_NO_FLAG; | 
|  | if (GV->hasDLLImportStorageClass()) | 
|  | TargetFlags = ARMII::MO_DLLIMPORT; | 
|  | else if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV)) | 
|  | TargetFlags = ARMII::MO_COFFSTUB; | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | SDValue Result; | 
|  | SDLoc DL(Op); | 
|  |  | 
|  | ++NumMovwMovt; | 
|  |  | 
|  | // FIXME: Once remat is capable of dealing with instructions with register | 
|  | // operands, expand this into two nodes. | 
|  | Result = DAG.getNode(ARMISD::Wrapper, DL, PtrVT, | 
|  | DAG.getTargetGlobalAddress(GV, DL, PtrVT, /*offset=*/0, | 
|  | TargetFlags)); | 
|  | if (TargetFlags & (ARMII::MO_DLLIMPORT | ARMII::MO_COFFSTUB)) | 
|  | Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Result, | 
|  | MachinePointerInfo::getGOT(DAG.getMachineFunction())); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | SDValue | 
|  | ARMTargetLowering::LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const { | 
|  | SDLoc dl(Op); | 
|  | SDValue Val = DAG.getConstant(0, dl, MVT::i32); | 
|  | return DAG.getNode(ARMISD::EH_SJLJ_SETJMP, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::Other), Op.getOperand(0), | 
|  | Op.getOperand(1), Val); | 
|  | } | 
|  |  | 
|  | SDValue | 
|  | ARMTargetLowering::LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const { | 
|  | SDLoc dl(Op); | 
|  | return DAG.getNode(ARMISD::EH_SJLJ_LONGJMP, dl, MVT::Other, Op.getOperand(0), | 
|  | Op.getOperand(1), DAG.getConstant(0, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerEH_SJLJ_SETUP_DISPATCH(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | SDLoc dl(Op); | 
|  | return DAG.getNode(ARMISD::EH_SJLJ_SETUP_DISPATCH, dl, MVT::Other, | 
|  | Op.getOperand(0)); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerINTRINSIC_VOID( | 
|  | SDValue Op, SelectionDAG &DAG, const ARMSubtarget *Subtarget) const { | 
|  | unsigned IntNo = | 
|  | cast<ConstantSDNode>( | 
|  | Op.getOperand(Op.getOperand(0).getValueType() == MVT::Other)) | 
|  | ->getZExtValue(); | 
|  | switch (IntNo) { | 
|  | default: | 
|  | return SDValue();  // Don't custom lower most intrinsics. | 
|  | case Intrinsic::arm_gnu_eabi_mcount: { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | SDLoc dl(Op); | 
|  | SDValue Chain = Op.getOperand(0); | 
|  | // call "\01__gnu_mcount_nc" | 
|  | const ARMBaseRegisterInfo *ARI = Subtarget->getRegisterInfo(); | 
|  | const uint32_t *Mask = | 
|  | ARI->getCallPreservedMask(DAG.getMachineFunction(), CallingConv::C); | 
|  | assert(Mask && "Missing call preserved mask for calling convention"); | 
|  | // Mark LR an implicit live-in. | 
|  | unsigned Reg = MF.addLiveIn(ARM::LR, getRegClassFor(MVT::i32)); | 
|  | SDValue ReturnAddress = | 
|  | DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, PtrVT); | 
|  | constexpr EVT ResultTys[] = {MVT::Other, MVT::Glue}; | 
|  | SDValue Callee = | 
|  | DAG.getTargetExternalSymbol("\01__gnu_mcount_nc", PtrVT, 0); | 
|  | SDValue RegisterMask = DAG.getRegisterMask(Mask); | 
|  | if (Subtarget->isThumb()) | 
|  | return SDValue( | 
|  | DAG.getMachineNode( | 
|  | ARM::tBL_PUSHLR, dl, ResultTys, | 
|  | {ReturnAddress, DAG.getTargetConstant(ARMCC::AL, dl, PtrVT), | 
|  | DAG.getRegister(0, PtrVT), Callee, RegisterMask, Chain}), | 
|  | 0); | 
|  | return SDValue( | 
|  | DAG.getMachineNode(ARM::BL_PUSHLR, dl, ResultTys, | 
|  | {ReturnAddress, Callee, RegisterMask, Chain}), | 
|  | 0); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | SDValue | 
|  | ARMTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) const { | 
|  | unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); | 
|  | SDLoc dl(Op); | 
|  | switch (IntNo) { | 
|  | default: return SDValue();    // Don't custom lower most intrinsics. | 
|  | case Intrinsic::thread_pointer: { | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | return DAG.getNode(ARMISD::THREAD_POINTER, dl, PtrVT); | 
|  | } | 
|  | case Intrinsic::arm_cls: { | 
|  | const SDValue &Operand = Op.getOperand(1); | 
|  | const EVT VTy = Op.getValueType(); | 
|  | SDValue SRA = | 
|  | DAG.getNode(ISD::SRA, dl, VTy, Operand, DAG.getConstant(31, dl, VTy)); | 
|  | SDValue XOR = DAG.getNode(ISD::XOR, dl, VTy, SRA, Operand); | 
|  | SDValue SHL = | 
|  | DAG.getNode(ISD::SHL, dl, VTy, XOR, DAG.getConstant(1, dl, VTy)); | 
|  | SDValue OR = | 
|  | DAG.getNode(ISD::OR, dl, VTy, SHL, DAG.getConstant(1, dl, VTy)); | 
|  | SDValue Result = DAG.getNode(ISD::CTLZ, dl, VTy, OR); | 
|  | return Result; | 
|  | } | 
|  | case Intrinsic::arm_cls64: { | 
|  | // cls(x) = if cls(hi(x)) != 31 then cls(hi(x)) | 
|  | //          else 31 + clz(if hi(x) == 0 then lo(x) else not(lo(x))) | 
|  | const SDValue &Operand = Op.getOperand(1); | 
|  | const EVT VTy = Op.getValueType(); | 
|  |  | 
|  | SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VTy, Operand, | 
|  | DAG.getConstant(1, dl, VTy)); | 
|  | SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VTy, Operand, | 
|  | DAG.getConstant(0, dl, VTy)); | 
|  | SDValue Constant0 = DAG.getConstant(0, dl, VTy); | 
|  | SDValue Constant1 = DAG.getConstant(1, dl, VTy); | 
|  | SDValue Constant31 = DAG.getConstant(31, dl, VTy); | 
|  | SDValue SRAHi = DAG.getNode(ISD::SRA, dl, VTy, Hi, Constant31); | 
|  | SDValue XORHi = DAG.getNode(ISD::XOR, dl, VTy, SRAHi, Hi); | 
|  | SDValue SHLHi = DAG.getNode(ISD::SHL, dl, VTy, XORHi, Constant1); | 
|  | SDValue ORHi = DAG.getNode(ISD::OR, dl, VTy, SHLHi, Constant1); | 
|  | SDValue CLSHi = DAG.getNode(ISD::CTLZ, dl, VTy, ORHi); | 
|  | SDValue CheckLo = | 
|  | DAG.getSetCC(dl, MVT::i1, CLSHi, Constant31, ISD::CondCode::SETEQ); | 
|  | SDValue HiIsZero = | 
|  | DAG.getSetCC(dl, MVT::i1, Hi, Constant0, ISD::CondCode::SETEQ); | 
|  | SDValue AdjustedLo = | 
|  | DAG.getSelect(dl, VTy, HiIsZero, Lo, DAG.getNOT(dl, Lo, VTy)); | 
|  | SDValue CLZAdjustedLo = DAG.getNode(ISD::CTLZ, dl, VTy, AdjustedLo); | 
|  | SDValue Result = | 
|  | DAG.getSelect(dl, VTy, CheckLo, | 
|  | DAG.getNode(ISD::ADD, dl, VTy, CLZAdjustedLo, Constant31), CLSHi); | 
|  | return Result; | 
|  | } | 
|  | case Intrinsic::eh_sjlj_lsda: { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  | unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | SDValue CPAddr; | 
|  | bool IsPositionIndependent = isPositionIndependent(); | 
|  | unsigned PCAdj = IsPositionIndependent ? (Subtarget->isThumb() ? 4 : 8) : 0; | 
|  | ARMConstantPoolValue *CPV = | 
|  | ARMConstantPoolConstant::Create(&MF.getFunction(), ARMPCLabelIndex, | 
|  | ARMCP::CPLSDA, PCAdj); | 
|  | CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, Align(4)); | 
|  | CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); | 
|  | SDValue Result = DAG.getLoad( | 
|  | PtrVT, dl, DAG.getEntryNode(), CPAddr, | 
|  | MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); | 
|  |  | 
|  | if (IsPositionIndependent) { | 
|  | SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, dl, MVT::i32); | 
|  | Result = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Result, PICLabel); | 
|  | } | 
|  | return Result; | 
|  | } | 
|  | case Intrinsic::arm_neon_vabs: | 
|  | return DAG.getNode(ISD::ABS, SDLoc(Op), Op.getValueType(), | 
|  | Op.getOperand(1)); | 
|  | case Intrinsic::arm_neon_vmulls: | 
|  | case Intrinsic::arm_neon_vmullu: { | 
|  | unsigned NewOpc = (IntNo == Intrinsic::arm_neon_vmulls) | 
|  | ? ARMISD::VMULLs : ARMISD::VMULLu; | 
|  | return DAG.getNode(NewOpc, SDLoc(Op), Op.getValueType(), | 
|  | Op.getOperand(1), Op.getOperand(2)); | 
|  | } | 
|  | case Intrinsic::arm_neon_vminnm: | 
|  | case Intrinsic::arm_neon_vmaxnm: { | 
|  | unsigned NewOpc = (IntNo == Intrinsic::arm_neon_vminnm) | 
|  | ? ISD::FMINNUM : ISD::FMAXNUM; | 
|  | return DAG.getNode(NewOpc, SDLoc(Op), Op.getValueType(), | 
|  | Op.getOperand(1), Op.getOperand(2)); | 
|  | } | 
|  | case Intrinsic::arm_neon_vminu: | 
|  | case Intrinsic::arm_neon_vmaxu: { | 
|  | if (Op.getValueType().isFloatingPoint()) | 
|  | return SDValue(); | 
|  | unsigned NewOpc = (IntNo == Intrinsic::arm_neon_vminu) | 
|  | ? ISD::UMIN : ISD::UMAX; | 
|  | return DAG.getNode(NewOpc, SDLoc(Op), Op.getValueType(), | 
|  | Op.getOperand(1), Op.getOperand(2)); | 
|  | } | 
|  | case Intrinsic::arm_neon_vmins: | 
|  | case Intrinsic::arm_neon_vmaxs: { | 
|  | // v{min,max}s is overloaded between signed integers and floats. | 
|  | if (!Op.getValueType().isFloatingPoint()) { | 
|  | unsigned NewOpc = (IntNo == Intrinsic::arm_neon_vmins) | 
|  | ? ISD::SMIN : ISD::SMAX; | 
|  | return DAG.getNode(NewOpc, SDLoc(Op), Op.getValueType(), | 
|  | Op.getOperand(1), Op.getOperand(2)); | 
|  | } | 
|  | unsigned NewOpc = (IntNo == Intrinsic::arm_neon_vmins) | 
|  | ? ISD::FMINIMUM : ISD::FMAXIMUM; | 
|  | return DAG.getNode(NewOpc, SDLoc(Op), Op.getValueType(), | 
|  | Op.getOperand(1), Op.getOperand(2)); | 
|  | } | 
|  | case Intrinsic::arm_neon_vtbl1: | 
|  | return DAG.getNode(ARMISD::VTBL1, SDLoc(Op), Op.getValueType(), | 
|  | Op.getOperand(1), Op.getOperand(2)); | 
|  | case Intrinsic::arm_neon_vtbl2: | 
|  | return DAG.getNode(ARMISD::VTBL2, SDLoc(Op), Op.getValueType(), | 
|  | Op.getOperand(1), Op.getOperand(2), Op.getOperand(3)); | 
|  | case Intrinsic::arm_mve_pred_i2v: | 
|  | case Intrinsic::arm_mve_pred_v2i: | 
|  | return DAG.getNode(ARMISD::PREDICATE_CAST, SDLoc(Op), Op.getValueType(), | 
|  | Op.getOperand(1)); | 
|  | case Intrinsic::arm_mve_vreinterpretq: | 
|  | return DAG.getNode(ARMISD::VECTOR_REG_CAST, SDLoc(Op), Op.getValueType(), | 
|  | Op.getOperand(1)); | 
|  | case Intrinsic::arm_mve_lsll: | 
|  | return DAG.getNode(ARMISD::LSLL, SDLoc(Op), Op->getVTList(), | 
|  | Op.getOperand(1), Op.getOperand(2), Op.getOperand(3)); | 
|  | case Intrinsic::arm_mve_asrl: | 
|  | return DAG.getNode(ARMISD::ASRL, SDLoc(Op), Op->getVTList(), | 
|  | Op.getOperand(1), Op.getOperand(2), Op.getOperand(3)); | 
|  | } | 
|  | } | 
|  |  | 
|  | static SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | SDLoc dl(Op); | 
|  | ConstantSDNode *SSIDNode = cast<ConstantSDNode>(Op.getOperand(2)); | 
|  | auto SSID = static_cast<SyncScope::ID>(SSIDNode->getZExtValue()); | 
|  | if (SSID == SyncScope::SingleThread) | 
|  | return Op; | 
|  |  | 
|  | if (!Subtarget->hasDataBarrier()) { | 
|  | // Some ARMv6 cpus can support data barriers with an mcr instruction. | 
|  | // Thumb1 and pre-v6 ARM mode use a libcall instead and should never get | 
|  | // here. | 
|  | assert(Subtarget->hasV6Ops() && !Subtarget->isThumb() && | 
|  | "Unexpected ISD::ATOMIC_FENCE encountered. Should be libcall!"); | 
|  | return DAG.getNode(ARMISD::MEMBARRIER_MCR, dl, MVT::Other, Op.getOperand(0), | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | ConstantSDNode *OrdN = cast<ConstantSDNode>(Op.getOperand(1)); | 
|  | AtomicOrdering Ord = static_cast<AtomicOrdering>(OrdN->getZExtValue()); | 
|  | ARM_MB::MemBOpt Domain = ARM_MB::ISH; | 
|  | if (Subtarget->isMClass()) { | 
|  | // Only a full system barrier exists in the M-class architectures. | 
|  | Domain = ARM_MB::SY; | 
|  | } else if (Subtarget->preferISHSTBarriers() && | 
|  | Ord == AtomicOrdering::Release) { | 
|  | // Swift happens to implement ISHST barriers in a way that's compatible with | 
|  | // Release semantics but weaker than ISH so we'd be fools not to use | 
|  | // it. Beware: other processors probably don't! | 
|  | Domain = ARM_MB::ISHST; | 
|  | } | 
|  |  | 
|  | return DAG.getNode(ISD::INTRINSIC_VOID, dl, MVT::Other, Op.getOperand(0), | 
|  | DAG.getConstant(Intrinsic::arm_dmb, dl, MVT::i32), | 
|  | DAG.getConstant(Domain, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | static SDValue LowerPREFETCH(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // ARM pre v5TE and Thumb1 does not have preload instructions. | 
|  | if (!(Subtarget->isThumb2() || | 
|  | (!Subtarget->isThumb1Only() && Subtarget->hasV5TEOps()))) | 
|  | // Just preserve the chain. | 
|  | return Op.getOperand(0); | 
|  |  | 
|  | SDLoc dl(Op); | 
|  | unsigned isRead = ~cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue() & 1; | 
|  | if (!isRead && | 
|  | (!Subtarget->hasV7Ops() || !Subtarget->hasMPExtension())) | 
|  | // ARMv7 with MP extension has PLDW. | 
|  | return Op.getOperand(0); | 
|  |  | 
|  | unsigned isData = cast<ConstantSDNode>(Op.getOperand(4))->getZExtValue(); | 
|  | if (Subtarget->isThumb()) { | 
|  | // Invert the bits. | 
|  | isRead = ~isRead & 1; | 
|  | isData = ~isData & 1; | 
|  | } | 
|  |  | 
|  | return DAG.getNode(ARMISD::PRELOAD, dl, MVT::Other, Op.getOperand(0), | 
|  | Op.getOperand(1), DAG.getConstant(isRead, dl, MVT::i32), | 
|  | DAG.getConstant(isData, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | ARMFunctionInfo *FuncInfo = MF.getInfo<ARMFunctionInfo>(); | 
|  |  | 
|  | // vastart just stores the address of the VarArgsFrameIndex slot into the | 
|  | // memory location argument. | 
|  | SDLoc dl(Op); | 
|  | EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()); | 
|  | SDValue FR = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT); | 
|  | const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); | 
|  | return DAG.getStore(Op.getOperand(0), dl, FR, Op.getOperand(1), | 
|  | MachinePointerInfo(SV)); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::GetF64FormalArgument(CCValAssign &VA, | 
|  | CCValAssign &NextVA, | 
|  | SDValue &Root, | 
|  | SelectionDAG &DAG, | 
|  | const SDLoc &dl) const { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  |  | 
|  | const TargetRegisterClass *RC; | 
|  | if (AFI->isThumb1OnlyFunction()) | 
|  | RC = &ARM::tGPRRegClass; | 
|  | else | 
|  | RC = &ARM::GPRRegClass; | 
|  |  | 
|  | // Transform the arguments stored in physical registers into virtual ones. | 
|  | unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC); | 
|  | SDValue ArgValue = DAG.getCopyFromReg(Root, dl, Reg, MVT::i32); | 
|  |  | 
|  | SDValue ArgValue2; | 
|  | if (NextVA.isMemLoc()) { | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | int FI = MFI.CreateFixedObject(4, NextVA.getLocMemOffset(), true); | 
|  |  | 
|  | // Create load node to retrieve arguments from the stack. | 
|  | SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); | 
|  | ArgValue2 = DAG.getLoad( | 
|  | MVT::i32, dl, Root, FIN, | 
|  | MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI)); | 
|  | } else { | 
|  | Reg = MF.addLiveIn(NextVA.getLocReg(), RC); | 
|  | ArgValue2 = DAG.getCopyFromReg(Root, dl, Reg, MVT::i32); | 
|  | } | 
|  | if (!Subtarget->isLittle()) | 
|  | std::swap (ArgValue, ArgValue2); | 
|  | return DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, ArgValue, ArgValue2); | 
|  | } | 
|  |  | 
|  | // The remaining GPRs hold either the beginning of variable-argument | 
|  | // data, or the beginning of an aggregate passed by value (usually | 
|  | // byval).  Either way, we allocate stack slots adjacent to the data | 
|  | // provided by our caller, and store the unallocated registers there. | 
|  | // If this is a variadic function, the va_list pointer will begin with | 
|  | // these values; otherwise, this reassembles a (byval) structure that | 
|  | // was split between registers and memory. | 
|  | // Return: The frame index registers were stored into. | 
|  | int ARMTargetLowering::StoreByValRegs(CCState &CCInfo, SelectionDAG &DAG, | 
|  | const SDLoc &dl, SDValue &Chain, | 
|  | const Value *OrigArg, | 
|  | unsigned InRegsParamRecordIdx, | 
|  | int ArgOffset, unsigned ArgSize) const { | 
|  | // Currently, two use-cases possible: | 
|  | // Case #1. Non-var-args function, and we meet first byval parameter. | 
|  | //          Setup first unallocated register as first byval register; | 
|  | //          eat all remained registers | 
|  | //          (these two actions are performed by HandleByVal method). | 
|  | //          Then, here, we initialize stack frame with | 
|  | //          "store-reg" instructions. | 
|  | // Case #2. Var-args function, that doesn't contain byval parameters. | 
|  | //          The same: eat all remained unallocated registers, | 
|  | //          initialize stack frame. | 
|  |  | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  | unsigned RBegin, REnd; | 
|  | if (InRegsParamRecordIdx < CCInfo.getInRegsParamsCount()) { | 
|  | CCInfo.getInRegsParamInfo(InRegsParamRecordIdx, RBegin, REnd); | 
|  | } else { | 
|  | unsigned RBeginIdx = CCInfo.getFirstUnallocated(GPRArgRegs); | 
|  | RBegin = RBeginIdx == 4 ? (unsigned)ARM::R4 : GPRArgRegs[RBeginIdx]; | 
|  | REnd = ARM::R4; | 
|  | } | 
|  |  | 
|  | if (REnd != RBegin) | 
|  | ArgOffset = -4 * (ARM::R4 - RBegin); | 
|  |  | 
|  | auto PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | int FrameIndex = MFI.CreateFixedObject(ArgSize, ArgOffset, false); | 
|  | SDValue FIN = DAG.getFrameIndex(FrameIndex, PtrVT); | 
|  |  | 
|  | SmallVector<SDValue, 4> MemOps; | 
|  | const TargetRegisterClass *RC = | 
|  | AFI->isThumb1OnlyFunction() ? &ARM::tGPRRegClass : &ARM::GPRRegClass; | 
|  |  | 
|  | for (unsigned Reg = RBegin, i = 0; Reg < REnd; ++Reg, ++i) { | 
|  | unsigned VReg = MF.addLiveIn(Reg, RC); | 
|  | SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32); | 
|  | SDValue Store = DAG.getStore(Val.getValue(1), dl, Val, FIN, | 
|  | MachinePointerInfo(OrigArg, 4 * i)); | 
|  | MemOps.push_back(Store); | 
|  | FIN = DAG.getNode(ISD::ADD, dl, PtrVT, FIN, DAG.getConstant(4, dl, PtrVT)); | 
|  | } | 
|  |  | 
|  | if (!MemOps.empty()) | 
|  | Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps); | 
|  | return FrameIndex; | 
|  | } | 
|  |  | 
|  | // Setup stack frame, the va_list pointer will start from. | 
|  | void ARMTargetLowering::VarArgStyleRegisters(CCState &CCInfo, SelectionDAG &DAG, | 
|  | const SDLoc &dl, SDValue &Chain, | 
|  | unsigned ArgOffset, | 
|  | unsigned TotalArgRegsSaveSize, | 
|  | bool ForceMutable) const { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  |  | 
|  | // Try to store any remaining integer argument regs | 
|  | // to their spots on the stack so that they may be loaded by dereferencing | 
|  | // the result of va_next. | 
|  | // If there is no regs to be stored, just point address after last | 
|  | // argument passed via stack. | 
|  | int FrameIndex = StoreByValRegs(CCInfo, DAG, dl, Chain, nullptr, | 
|  | CCInfo.getInRegsParamsCount(), | 
|  | CCInfo.getNextStackOffset(), | 
|  | std::max(4U, TotalArgRegsSaveSize)); | 
|  | AFI->setVarArgsFrameIndex(FrameIndex); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerFormalArguments( | 
|  | SDValue Chain, CallingConv::ID CallConv, bool isVarArg, | 
|  | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, | 
|  | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  |  | 
|  | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | 
|  |  | 
|  | // Assign locations to all of the incoming arguments. | 
|  | SmallVector<CCValAssign, 16> ArgLocs; | 
|  | CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs, | 
|  | *DAG.getContext()); | 
|  | CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, isVarArg)); | 
|  |  | 
|  | SmallVector<SDValue, 16> ArgValues; | 
|  | SDValue ArgValue; | 
|  | Function::const_arg_iterator CurOrigArg = MF.getFunction().arg_begin(); | 
|  | unsigned CurArgIdx = 0; | 
|  |  | 
|  | // Initially ArgRegsSaveSize is zero. | 
|  | // Then we increase this value each time we meet byval parameter. | 
|  | // We also increase this value in case of varargs function. | 
|  | AFI->setArgRegsSaveSize(0); | 
|  |  | 
|  | // Calculate the amount of stack space that we need to allocate to store | 
|  | // byval and variadic arguments that are passed in registers. | 
|  | // We need to know this before we allocate the first byval or variadic | 
|  | // argument, as they will be allocated a stack slot below the CFA (Canonical | 
|  | // Frame Address, the stack pointer at entry to the function). | 
|  | unsigned ArgRegBegin = ARM::R4; | 
|  | for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { | 
|  | if (CCInfo.getInRegsParamsProcessed() >= CCInfo.getInRegsParamsCount()) | 
|  | break; | 
|  |  | 
|  | CCValAssign &VA = ArgLocs[i]; | 
|  | unsigned Index = VA.getValNo(); | 
|  | ISD::ArgFlagsTy Flags = Ins[Index].Flags; | 
|  | if (!Flags.isByVal()) | 
|  | continue; | 
|  |  | 
|  | assert(VA.isMemLoc() && "unexpected byval pointer in reg"); | 
|  | unsigned RBegin, REnd; | 
|  | CCInfo.getInRegsParamInfo(CCInfo.getInRegsParamsProcessed(), RBegin, REnd); | 
|  | ArgRegBegin = std::min(ArgRegBegin, RBegin); | 
|  |  | 
|  | CCInfo.nextInRegsParam(); | 
|  | } | 
|  | CCInfo.rewindByValRegsInfo(); | 
|  |  | 
|  | int lastInsIndex = -1; | 
|  | if (isVarArg && MFI.hasVAStart()) { | 
|  | unsigned RegIdx = CCInfo.getFirstUnallocated(GPRArgRegs); | 
|  | if (RegIdx != array_lengthof(GPRArgRegs)) | 
|  | ArgRegBegin = std::min(ArgRegBegin, (unsigned)GPRArgRegs[RegIdx]); | 
|  | } | 
|  |  | 
|  | unsigned TotalArgRegsSaveSize = 4 * (ARM::R4 - ArgRegBegin); | 
|  | AFI->setArgRegsSaveSize(TotalArgRegsSaveSize); | 
|  | auto PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  |  | 
|  | for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { | 
|  | CCValAssign &VA = ArgLocs[i]; | 
|  | if (Ins[VA.getValNo()].isOrigArg()) { | 
|  | std::advance(CurOrigArg, | 
|  | Ins[VA.getValNo()].getOrigArgIndex() - CurArgIdx); | 
|  | CurArgIdx = Ins[VA.getValNo()].getOrigArgIndex(); | 
|  | } | 
|  | // Arguments stored in registers. | 
|  | if (VA.isRegLoc()) { | 
|  | EVT RegVT = VA.getLocVT(); | 
|  |  | 
|  | if (VA.needsCustom()) { | 
|  | // f64 and vector types are split up into multiple registers or | 
|  | // combinations of registers and stack slots. | 
|  | if (VA.getLocVT() == MVT::v2f64) { | 
|  | SDValue ArgValue1 = GetF64FormalArgument(VA, ArgLocs[++i], | 
|  | Chain, DAG, dl); | 
|  | VA = ArgLocs[++i]; // skip ahead to next loc | 
|  | SDValue ArgValue2; | 
|  | if (VA.isMemLoc()) { | 
|  | int FI = MFI.CreateFixedObject(8, VA.getLocMemOffset(), true); | 
|  | SDValue FIN = DAG.getFrameIndex(FI, PtrVT); | 
|  | ArgValue2 = DAG.getLoad(MVT::f64, dl, Chain, FIN, | 
|  | MachinePointerInfo::getFixedStack( | 
|  | DAG.getMachineFunction(), FI)); | 
|  | } else { | 
|  | ArgValue2 = GetF64FormalArgument(VA, ArgLocs[++i], | 
|  | Chain, DAG, dl); | 
|  | } | 
|  | ArgValue = DAG.getNode(ISD::UNDEF, dl, MVT::v2f64); | 
|  | ArgValue = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, | 
|  | ArgValue, ArgValue1, | 
|  | DAG.getIntPtrConstant(0, dl)); | 
|  | ArgValue = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, | 
|  | ArgValue, ArgValue2, | 
|  | DAG.getIntPtrConstant(1, dl)); | 
|  | } else | 
|  | ArgValue = GetF64FormalArgument(VA, ArgLocs[++i], Chain, DAG, dl); | 
|  | } else { | 
|  | const TargetRegisterClass *RC; | 
|  |  | 
|  |  | 
|  | if (RegVT == MVT::f16) | 
|  | RC = &ARM::HPRRegClass; | 
|  | else if (RegVT == MVT::f32) | 
|  | RC = &ARM::SPRRegClass; | 
|  | else if (RegVT == MVT::f64 || RegVT == MVT::v4f16) | 
|  | RC = &ARM::DPRRegClass; | 
|  | else if (RegVT == MVT::v2f64 || RegVT == MVT::v8f16) | 
|  | RC = &ARM::QPRRegClass; | 
|  | else if (RegVT == MVT::i32) | 
|  | RC = AFI->isThumb1OnlyFunction() ? &ARM::tGPRRegClass | 
|  | : &ARM::GPRRegClass; | 
|  | else | 
|  | llvm_unreachable("RegVT not supported by FORMAL_ARGUMENTS Lowering"); | 
|  |  | 
|  | // Transform the arguments in physical registers into virtual ones. | 
|  | unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC); | 
|  | ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT); | 
|  |  | 
|  | // If this value is passed in r0 and has the returned attribute (e.g. | 
|  | // C++ 'structors), record this fact for later use. | 
|  | if (VA.getLocReg() == ARM::R0 && Ins[VA.getValNo()].Flags.isReturned()) { | 
|  | AFI->setPreservesR0(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // If this is an 8 or 16-bit value, it is really passed promoted | 
|  | // to 32 bits.  Insert an assert[sz]ext to capture this, then | 
|  | // truncate to the right size. | 
|  | switch (VA.getLocInfo()) { | 
|  | default: llvm_unreachable("Unknown loc info!"); | 
|  | case CCValAssign::Full: break; | 
|  | case CCValAssign::BCvt: | 
|  | ArgValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), ArgValue); | 
|  | break; | 
|  | case CCValAssign::SExt: | 
|  | ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue, | 
|  | DAG.getValueType(VA.getValVT())); | 
|  | ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); | 
|  | break; | 
|  | case CCValAssign::ZExt: | 
|  | ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue, | 
|  | DAG.getValueType(VA.getValVT())); | 
|  | ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); | 
|  | break; | 
|  | } | 
|  |  | 
|  | InVals.push_back(ArgValue); | 
|  | } else { // VA.isRegLoc() | 
|  | // sanity check | 
|  | assert(VA.isMemLoc()); | 
|  | assert(VA.getValVT() != MVT::i64 && "i64 should already be lowered"); | 
|  |  | 
|  | int index = VA.getValNo(); | 
|  |  | 
|  | // Some Ins[] entries become multiple ArgLoc[] entries. | 
|  | // Process them only once. | 
|  | if (index != lastInsIndex) | 
|  | { | 
|  | ISD::ArgFlagsTy Flags = Ins[index].Flags; | 
|  | // FIXME: For now, all byval parameter objects are marked mutable. | 
|  | // This can be changed with more analysis. | 
|  | // In case of tail call optimization mark all arguments mutable. | 
|  | // Since they could be overwritten by lowering of arguments in case of | 
|  | // a tail call. | 
|  | if (Flags.isByVal()) { | 
|  | assert(Ins[index].isOrigArg() && | 
|  | "Byval arguments cannot be implicit"); | 
|  | unsigned CurByValIndex = CCInfo.getInRegsParamsProcessed(); | 
|  |  | 
|  | int FrameIndex = StoreByValRegs( | 
|  | CCInfo, DAG, dl, Chain, &*CurOrigArg, CurByValIndex, | 
|  | VA.getLocMemOffset(), Flags.getByValSize()); | 
|  | InVals.push_back(DAG.getFrameIndex(FrameIndex, PtrVT)); | 
|  | CCInfo.nextInRegsParam(); | 
|  | } else { | 
|  | unsigned FIOffset = VA.getLocMemOffset(); | 
|  | int FI = MFI.CreateFixedObject(VA.getLocVT().getSizeInBits()/8, | 
|  | FIOffset, true); | 
|  |  | 
|  | // Create load nodes to retrieve arguments from the stack. | 
|  | SDValue FIN = DAG.getFrameIndex(FI, PtrVT); | 
|  | InVals.push_back(DAG.getLoad(VA.getValVT(), dl, Chain, FIN, | 
|  | MachinePointerInfo::getFixedStack( | 
|  | DAG.getMachineFunction(), FI))); | 
|  | } | 
|  | lastInsIndex = index; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // varargs | 
|  | if (isVarArg && MFI.hasVAStart()) | 
|  | VarArgStyleRegisters(CCInfo, DAG, dl, Chain, | 
|  | CCInfo.getNextStackOffset(), | 
|  | TotalArgRegsSaveSize); | 
|  |  | 
|  | AFI->setArgumentStackSize(CCInfo.getNextStackOffset()); | 
|  |  | 
|  | return Chain; | 
|  | } | 
|  |  | 
|  | /// isFloatingPointZero - Return true if this is +0.0. | 
|  | static bool isFloatingPointZero(SDValue Op) { | 
|  | if (ConstantFPSDNode *CFP = dyn_cast<ConstantFPSDNode>(Op)) | 
|  | return CFP->getValueAPF().isPosZero(); | 
|  | else if (ISD::isEXTLoad(Op.getNode()) || ISD::isNON_EXTLoad(Op.getNode())) { | 
|  | // Maybe this has already been legalized into the constant pool? | 
|  | if (Op.getOperand(1).getOpcode() == ARMISD::Wrapper) { | 
|  | SDValue WrapperOp = Op.getOperand(1).getOperand(0); | 
|  | if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(WrapperOp)) | 
|  | if (const ConstantFP *CFP = dyn_cast<ConstantFP>(CP->getConstVal())) | 
|  | return CFP->getValueAPF().isPosZero(); | 
|  | } | 
|  | } else if (Op->getOpcode() == ISD::BITCAST && | 
|  | Op->getValueType(0) == MVT::f64) { | 
|  | // Handle (ISD::BITCAST (ARMISD::VMOVIMM (ISD::TargetConstant 0)) MVT::f64) | 
|  | // created by LowerConstantFP(). | 
|  | SDValue BitcastOp = Op->getOperand(0); | 
|  | if (BitcastOp->getOpcode() == ARMISD::VMOVIMM && | 
|  | isNullConstant(BitcastOp->getOperand(0))) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// Returns appropriate ARM CMP (cmp) and corresponding condition code for | 
|  | /// the given operands. | 
|  | SDValue ARMTargetLowering::getARMCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, | 
|  | SDValue &ARMcc, SelectionDAG &DAG, | 
|  | const SDLoc &dl) const { | 
|  | if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS.getNode())) { | 
|  | unsigned C = RHSC->getZExtValue(); | 
|  | if (!isLegalICmpImmediate((int32_t)C)) { | 
|  | // Constant does not fit, try adjusting it by one. | 
|  | switch (CC) { | 
|  | default: break; | 
|  | case ISD::SETLT: | 
|  | case ISD::SETGE: | 
|  | if (C != 0x80000000 && isLegalICmpImmediate(C-1)) { | 
|  | CC = (CC == ISD::SETLT) ? ISD::SETLE : ISD::SETGT; | 
|  | RHS = DAG.getConstant(C - 1, dl, MVT::i32); | 
|  | } | 
|  | break; | 
|  | case ISD::SETULT: | 
|  | case ISD::SETUGE: | 
|  | if (C != 0 && isLegalICmpImmediate(C-1)) { | 
|  | CC = (CC == ISD::SETULT) ? ISD::SETULE : ISD::SETUGT; | 
|  | RHS = DAG.getConstant(C - 1, dl, MVT::i32); | 
|  | } | 
|  | break; | 
|  | case ISD::SETLE: | 
|  | case ISD::SETGT: | 
|  | if (C != 0x7fffffff && isLegalICmpImmediate(C+1)) { | 
|  | CC = (CC == ISD::SETLE) ? ISD::SETLT : ISD::SETGE; | 
|  | RHS = DAG.getConstant(C + 1, dl, MVT::i32); | 
|  | } | 
|  | break; | 
|  | case ISD::SETULE: | 
|  | case ISD::SETUGT: | 
|  | if (C != 0xffffffff && isLegalICmpImmediate(C+1)) { | 
|  | CC = (CC == ISD::SETULE) ? ISD::SETULT : ISD::SETUGE; | 
|  | RHS = DAG.getConstant(C + 1, dl, MVT::i32); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | } else if ((ARM_AM::getShiftOpcForNode(LHS.getOpcode()) != ARM_AM::no_shift) && | 
|  | (ARM_AM::getShiftOpcForNode(RHS.getOpcode()) == ARM_AM::no_shift)) { | 
|  | // In ARM and Thumb-2, the compare instructions can shift their second | 
|  | // operand. | 
|  | CC = ISD::getSetCCSwappedOperands(CC); | 
|  | std::swap(LHS, RHS); | 
|  | } | 
|  |  | 
|  | // Thumb1 has very limited immediate modes, so turning an "and" into a | 
|  | // shift can save multiple instructions. | 
|  | // | 
|  | // If we have (x & C1), and C1 is an appropriate mask, we can transform it | 
|  | // into "((x << n) >> n)".  But that isn't necessarily profitable on its | 
|  | // own. If it's the operand to an unsigned comparison with an immediate, | 
|  | // we can eliminate one of the shifts: we transform | 
|  | // "((x << n) >> n) == C2" to "(x << n) == (C2 << n)". | 
|  | // | 
|  | // We avoid transforming cases which aren't profitable due to encoding | 
|  | // details: | 
|  | // | 
|  | // 1. C2 fits into the immediate field of a cmp, and the transformed version | 
|  | // would not; in that case, we're essentially trading one immediate load for | 
|  | // another. | 
|  | // 2. C1 is 255 or 65535, so we can use uxtb or uxth. | 
|  | // 3. C2 is zero; we have other code for this special case. | 
|  | // | 
|  | // FIXME: Figure out profitability for Thumb2; we usually can't save an | 
|  | // instruction, since the AND is always one instruction anyway, but we could | 
|  | // use narrow instructions in some cases. | 
|  | if (Subtarget->isThumb1Only() && LHS->getOpcode() == ISD::AND && | 
|  | LHS->hasOneUse() && isa<ConstantSDNode>(LHS.getOperand(1)) && | 
|  | LHS.getValueType() == MVT::i32 && isa<ConstantSDNode>(RHS) && | 
|  | !isSignedIntSetCC(CC)) { | 
|  | unsigned Mask = cast<ConstantSDNode>(LHS.getOperand(1))->getZExtValue(); | 
|  | auto *RHSC = cast<ConstantSDNode>(RHS.getNode()); | 
|  | uint64_t RHSV = RHSC->getZExtValue(); | 
|  | if (isMask_32(Mask) && (RHSV & ~Mask) == 0 && Mask != 255 && Mask != 65535) { | 
|  | unsigned ShiftBits = countLeadingZeros(Mask); | 
|  | if (RHSV && (RHSV > 255 || (RHSV << ShiftBits) <= 255)) { | 
|  | SDValue ShiftAmt = DAG.getConstant(ShiftBits, dl, MVT::i32); | 
|  | LHS = DAG.getNode(ISD::SHL, dl, MVT::i32, LHS.getOperand(0), ShiftAmt); | 
|  | RHS = DAG.getConstant(RHSV << ShiftBits, dl, MVT::i32); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // The specific comparison "(x<<c) > 0x80000000U" can be optimized to a | 
|  | // single "lsls x, c+1".  The shift sets the "C" and "Z" flags the same | 
|  | // way a cmp would. | 
|  | // FIXME: Add support for ARM/Thumb2; this would need isel patterns, and | 
|  | // some tweaks to the heuristics for the previous and->shift transform. | 
|  | // FIXME: Optimize cases where the LHS isn't a shift. | 
|  | if (Subtarget->isThumb1Only() && LHS->getOpcode() == ISD::SHL && | 
|  | isa<ConstantSDNode>(RHS) && | 
|  | cast<ConstantSDNode>(RHS)->getZExtValue() == 0x80000000U && | 
|  | CC == ISD::SETUGT && isa<ConstantSDNode>(LHS.getOperand(1)) && | 
|  | cast<ConstantSDNode>(LHS.getOperand(1))->getZExtValue() < 31) { | 
|  | unsigned ShiftAmt = | 
|  | cast<ConstantSDNode>(LHS.getOperand(1))->getZExtValue() + 1; | 
|  | SDValue Shift = DAG.getNode(ARMISD::LSLS, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), | 
|  | LHS.getOperand(0), | 
|  | DAG.getConstant(ShiftAmt, dl, MVT::i32)); | 
|  | SDValue Chain = DAG.getCopyToReg(DAG.getEntryNode(), dl, ARM::CPSR, | 
|  | Shift.getValue(1), SDValue()); | 
|  | ARMcc = DAG.getConstant(ARMCC::HI, dl, MVT::i32); | 
|  | return Chain.getValue(1); | 
|  | } | 
|  |  | 
|  | ARMCC::CondCodes CondCode = IntCCToARMCC(CC); | 
|  |  | 
|  | // If the RHS is a constant zero then the V (overflow) flag will never be | 
|  | // set. This can allow us to simplify GE to PL or LT to MI, which can be | 
|  | // simpler for other passes (like the peephole optimiser) to deal with. | 
|  | if (isNullConstant(RHS)) { | 
|  | switch (CondCode) { | 
|  | default: break; | 
|  | case ARMCC::GE: | 
|  | CondCode = ARMCC::PL; | 
|  | break; | 
|  | case ARMCC::LT: | 
|  | CondCode = ARMCC::MI; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | ARMISD::NodeType CompareType; | 
|  | switch (CondCode) { | 
|  | default: | 
|  | CompareType = ARMISD::CMP; | 
|  | break; | 
|  | case ARMCC::EQ: | 
|  | case ARMCC::NE: | 
|  | // Uses only Z Flag | 
|  | CompareType = ARMISD::CMPZ; | 
|  | break; | 
|  | } | 
|  | ARMcc = DAG.getConstant(CondCode, dl, MVT::i32); | 
|  | return DAG.getNode(CompareType, dl, MVT::Glue, LHS, RHS); | 
|  | } | 
|  |  | 
|  | /// Returns a appropriate VFP CMP (fcmp{s|d}+fmstat) for the given operands. | 
|  | SDValue ARMTargetLowering::getVFPCmp(SDValue LHS, SDValue RHS, | 
|  | SelectionDAG &DAG, const SDLoc &dl, | 
|  | bool Signaling) const { | 
|  | assert(Subtarget->hasFP64() || RHS.getValueType() != MVT::f64); | 
|  | SDValue Cmp; | 
|  | if (!isFloatingPointZero(RHS)) | 
|  | Cmp = DAG.getNode(Signaling ? ARMISD::CMPFPE : ARMISD::CMPFP, | 
|  | dl, MVT::Glue, LHS, RHS); | 
|  | else | 
|  | Cmp = DAG.getNode(Signaling ? ARMISD::CMPFPEw0 : ARMISD::CMPFPw0, | 
|  | dl, MVT::Glue, LHS); | 
|  | return DAG.getNode(ARMISD::FMSTAT, dl, MVT::Glue, Cmp); | 
|  | } | 
|  |  | 
|  | /// duplicateCmp - Glue values can have only one use, so this function | 
|  | /// duplicates a comparison node. | 
|  | SDValue | 
|  | ARMTargetLowering::duplicateCmp(SDValue Cmp, SelectionDAG &DAG) const { | 
|  | unsigned Opc = Cmp.getOpcode(); | 
|  | SDLoc DL(Cmp); | 
|  | if (Opc == ARMISD::CMP || Opc == ARMISD::CMPZ) | 
|  | return DAG.getNode(Opc, DL, MVT::Glue, Cmp.getOperand(0),Cmp.getOperand(1)); | 
|  |  | 
|  | assert(Opc == ARMISD::FMSTAT && "unexpected comparison operation"); | 
|  | Cmp = Cmp.getOperand(0); | 
|  | Opc = Cmp.getOpcode(); | 
|  | if (Opc == ARMISD::CMPFP) | 
|  | Cmp = DAG.getNode(Opc, DL, MVT::Glue, Cmp.getOperand(0),Cmp.getOperand(1)); | 
|  | else { | 
|  | assert(Opc == ARMISD::CMPFPw0 && "unexpected operand of FMSTAT"); | 
|  | Cmp = DAG.getNode(Opc, DL, MVT::Glue, Cmp.getOperand(0)); | 
|  | } | 
|  | return DAG.getNode(ARMISD::FMSTAT, DL, MVT::Glue, Cmp); | 
|  | } | 
|  |  | 
|  | // This function returns three things: the arithmetic computation itself | 
|  | // (Value), a comparison (OverflowCmp), and a condition code (ARMcc).  The | 
|  | // comparison and the condition code define the case in which the arithmetic | 
|  | // computation *does not* overflow. | 
|  | std::pair<SDValue, SDValue> | 
|  | ARMTargetLowering::getARMXALUOOp(SDValue Op, SelectionDAG &DAG, | 
|  | SDValue &ARMcc) const { | 
|  | assert(Op.getValueType() == MVT::i32 &&  "Unsupported value type"); | 
|  |  | 
|  | SDValue Value, OverflowCmp; | 
|  | SDValue LHS = Op.getOperand(0); | 
|  | SDValue RHS = Op.getOperand(1); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | // FIXME: We are currently always generating CMPs because we don't support | 
|  | // generating CMN through the backend. This is not as good as the natural | 
|  | // CMP case because it causes a register dependency and cannot be folded | 
|  | // later. | 
|  |  | 
|  | switch (Op.getOpcode()) { | 
|  | default: | 
|  | llvm_unreachable("Unknown overflow instruction!"); | 
|  | case ISD::SADDO: | 
|  | ARMcc = DAG.getConstant(ARMCC::VC, dl, MVT::i32); | 
|  | Value = DAG.getNode(ISD::ADD, dl, Op.getValueType(), LHS, RHS); | 
|  | OverflowCmp = DAG.getNode(ARMISD::CMP, dl, MVT::Glue, Value, LHS); | 
|  | break; | 
|  | case ISD::UADDO: | 
|  | ARMcc = DAG.getConstant(ARMCC::HS, dl, MVT::i32); | 
|  | // We use ADDC here to correspond to its use in LowerUnsignedALUO. | 
|  | // We do not use it in the USUBO case as Value may not be used. | 
|  | Value = DAG.getNode(ARMISD::ADDC, dl, | 
|  | DAG.getVTList(Op.getValueType(), MVT::i32), LHS, RHS) | 
|  | .getValue(0); | 
|  | OverflowCmp = DAG.getNode(ARMISD::CMP, dl, MVT::Glue, Value, LHS); | 
|  | break; | 
|  | case ISD::SSUBO: | 
|  | ARMcc = DAG.getConstant(ARMCC::VC, dl, MVT::i32); | 
|  | Value = DAG.getNode(ISD::SUB, dl, Op.getValueType(), LHS, RHS); | 
|  | OverflowCmp = DAG.getNode(ARMISD::CMP, dl, MVT::Glue, LHS, RHS); | 
|  | break; | 
|  | case ISD::USUBO: | 
|  | ARMcc = DAG.getConstant(ARMCC::HS, dl, MVT::i32); | 
|  | Value = DAG.getNode(ISD::SUB, dl, Op.getValueType(), LHS, RHS); | 
|  | OverflowCmp = DAG.getNode(ARMISD::CMP, dl, MVT::Glue, LHS, RHS); | 
|  | break; | 
|  | case ISD::UMULO: | 
|  | // We generate a UMUL_LOHI and then check if the high word is 0. | 
|  | ARMcc = DAG.getConstant(ARMCC::EQ, dl, MVT::i32); | 
|  | Value = DAG.getNode(ISD::UMUL_LOHI, dl, | 
|  | DAG.getVTList(Op.getValueType(), Op.getValueType()), | 
|  | LHS, RHS); | 
|  | OverflowCmp = DAG.getNode(ARMISD::CMP, dl, MVT::Glue, Value.getValue(1), | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | Value = Value.getValue(0); // We only want the low 32 bits for the result. | 
|  | break; | 
|  | case ISD::SMULO: | 
|  | // We generate a SMUL_LOHI and then check if all the bits of the high word | 
|  | // are the same as the sign bit of the low word. | 
|  | ARMcc = DAG.getConstant(ARMCC::EQ, dl, MVT::i32); | 
|  | Value = DAG.getNode(ISD::SMUL_LOHI, dl, | 
|  | DAG.getVTList(Op.getValueType(), Op.getValueType()), | 
|  | LHS, RHS); | 
|  | OverflowCmp = DAG.getNode(ARMISD::CMP, dl, MVT::Glue, Value.getValue(1), | 
|  | DAG.getNode(ISD::SRA, dl, Op.getValueType(), | 
|  | Value.getValue(0), | 
|  | DAG.getConstant(31, dl, MVT::i32))); | 
|  | Value = Value.getValue(0); // We only want the low 32 bits for the result. | 
|  | break; | 
|  | } // switch (...) | 
|  |  | 
|  | return std::make_pair(Value, OverflowCmp); | 
|  | } | 
|  |  | 
|  | SDValue | 
|  | ARMTargetLowering::LowerSignedALUO(SDValue Op, SelectionDAG &DAG) const { | 
|  | // Let legalize expand this if it isn't a legal type yet. | 
|  | if (!DAG.getTargetLoweringInfo().isTypeLegal(Op.getValueType())) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue Value, OverflowCmp; | 
|  | SDValue ARMcc; | 
|  | std::tie(Value, OverflowCmp) = getARMXALUOOp(Op, DAG, ARMcc); | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  | SDLoc dl(Op); | 
|  | // We use 0 and 1 as false and true values. | 
|  | SDValue TVal = DAG.getConstant(1, dl, MVT::i32); | 
|  | SDValue FVal = DAG.getConstant(0, dl, MVT::i32); | 
|  | EVT VT = Op.getValueType(); | 
|  |  | 
|  | SDValue Overflow = DAG.getNode(ARMISD::CMOV, dl, VT, TVal, FVal, | 
|  | ARMcc, CCR, OverflowCmp); | 
|  |  | 
|  | SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::i32); | 
|  | return DAG.getNode(ISD::MERGE_VALUES, dl, VTs, Value, Overflow); | 
|  | } | 
|  |  | 
|  | static SDValue ConvertBooleanCarryToCarryFlag(SDValue BoolCarry, | 
|  | SelectionDAG &DAG) { | 
|  | SDLoc DL(BoolCarry); | 
|  | EVT CarryVT = BoolCarry.getValueType(); | 
|  |  | 
|  | // This converts the boolean value carry into the carry flag by doing | 
|  | // ARMISD::SUBC Carry, 1 | 
|  | SDValue Carry = DAG.getNode(ARMISD::SUBC, DL, | 
|  | DAG.getVTList(CarryVT, MVT::i32), | 
|  | BoolCarry, DAG.getConstant(1, DL, CarryVT)); | 
|  | return Carry.getValue(1); | 
|  | } | 
|  |  | 
|  | static SDValue ConvertCarryFlagToBooleanCarry(SDValue Flags, EVT VT, | 
|  | SelectionDAG &DAG) { | 
|  | SDLoc DL(Flags); | 
|  |  | 
|  | // Now convert the carry flag into a boolean carry. We do this | 
|  | // using ARMISD:ADDE 0, 0, Carry | 
|  | return DAG.getNode(ARMISD::ADDE, DL, DAG.getVTList(VT, MVT::i32), | 
|  | DAG.getConstant(0, DL, MVT::i32), | 
|  | DAG.getConstant(0, DL, MVT::i32), Flags); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerUnsignedALUO(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | // Let legalize expand this if it isn't a legal type yet. | 
|  | if (!DAG.getTargetLoweringInfo().isTypeLegal(Op.getValueType())) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue LHS = Op.getOperand(0); | 
|  | SDValue RHS = Op.getOperand(1); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | EVT VT = Op.getValueType(); | 
|  | SDVTList VTs = DAG.getVTList(VT, MVT::i32); | 
|  | SDValue Value; | 
|  | SDValue Overflow; | 
|  | switch (Op.getOpcode()) { | 
|  | default: | 
|  | llvm_unreachable("Unknown overflow instruction!"); | 
|  | case ISD::UADDO: | 
|  | Value = DAG.getNode(ARMISD::ADDC, dl, VTs, LHS, RHS); | 
|  | // Convert the carry flag into a boolean value. | 
|  | Overflow = ConvertCarryFlagToBooleanCarry(Value.getValue(1), VT, DAG); | 
|  | break; | 
|  | case ISD::USUBO: { | 
|  | Value = DAG.getNode(ARMISD::SUBC, dl, VTs, LHS, RHS); | 
|  | // Convert the carry flag into a boolean value. | 
|  | Overflow = ConvertCarryFlagToBooleanCarry(Value.getValue(1), VT, DAG); | 
|  | // ARMISD::SUBC returns 0 when we have to borrow, so make it an overflow | 
|  | // value. So compute 1 - C. | 
|  | Overflow = DAG.getNode(ISD::SUB, dl, MVT::i32, | 
|  | DAG.getConstant(1, dl, MVT::i32), Overflow); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return DAG.getNode(ISD::MERGE_VALUES, dl, VTs, Value, Overflow); | 
|  | } | 
|  |  | 
|  | static SDValue LowerSADDSUBSAT(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | EVT VT = Op.getValueType(); | 
|  | if (!Subtarget->hasV6Ops() || !Subtarget->hasDSP()) | 
|  | return SDValue(); | 
|  | if (!VT.isSimple()) | 
|  | return SDValue(); | 
|  |  | 
|  | unsigned NewOpcode; | 
|  | bool IsAdd = Op->getOpcode() == ISD::SADDSAT; | 
|  | switch (VT.getSimpleVT().SimpleTy) { | 
|  | default: | 
|  | return SDValue(); | 
|  | case MVT::i8: | 
|  | NewOpcode = IsAdd ? ARMISD::QADD8b : ARMISD::QSUB8b; | 
|  | break; | 
|  | case MVT::i16: | 
|  | NewOpcode = IsAdd ? ARMISD::QADD16b : ARMISD::QSUB16b; | 
|  | break; | 
|  | } | 
|  |  | 
|  | SDLoc dl(Op); | 
|  | SDValue Add = | 
|  | DAG.getNode(NewOpcode, dl, MVT::i32, | 
|  | DAG.getSExtOrTrunc(Op->getOperand(0), dl, MVT::i32), | 
|  | DAG.getSExtOrTrunc(Op->getOperand(1), dl, MVT::i32)); | 
|  | return DAG.getNode(ISD::TRUNCATE, dl, VT, Add); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const { | 
|  | SDValue Cond = Op.getOperand(0); | 
|  | SDValue SelectTrue = Op.getOperand(1); | 
|  | SDValue SelectFalse = Op.getOperand(2); | 
|  | SDLoc dl(Op); | 
|  | unsigned Opc = Cond.getOpcode(); | 
|  |  | 
|  | if (Cond.getResNo() == 1 && | 
|  | (Opc == ISD::SADDO || Opc == ISD::UADDO || Opc == ISD::SSUBO || | 
|  | Opc == ISD::USUBO)) { | 
|  | if (!DAG.getTargetLoweringInfo().isTypeLegal(Cond->getValueType(0))) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue Value, OverflowCmp; | 
|  | SDValue ARMcc; | 
|  | std::tie(Value, OverflowCmp) = getARMXALUOOp(Cond, DAG, ARMcc); | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  | EVT VT = Op.getValueType(); | 
|  |  | 
|  | return getCMOV(dl, VT, SelectTrue, SelectFalse, ARMcc, CCR, | 
|  | OverflowCmp, DAG); | 
|  | } | 
|  |  | 
|  | // Convert: | 
|  | // | 
|  | //   (select (cmov 1, 0, cond), t, f) -> (cmov t, f, cond) | 
|  | //   (select (cmov 0, 1, cond), t, f) -> (cmov f, t, cond) | 
|  | // | 
|  | if (Cond.getOpcode() == ARMISD::CMOV && Cond.hasOneUse()) { | 
|  | const ConstantSDNode *CMOVTrue = | 
|  | dyn_cast<ConstantSDNode>(Cond.getOperand(0)); | 
|  | const ConstantSDNode *CMOVFalse = | 
|  | dyn_cast<ConstantSDNode>(Cond.getOperand(1)); | 
|  |  | 
|  | if (CMOVTrue && CMOVFalse) { | 
|  | unsigned CMOVTrueVal = CMOVTrue->getZExtValue(); | 
|  | unsigned CMOVFalseVal = CMOVFalse->getZExtValue(); | 
|  |  | 
|  | SDValue True; | 
|  | SDValue False; | 
|  | if (CMOVTrueVal == 1 && CMOVFalseVal == 0) { | 
|  | True = SelectTrue; | 
|  | False = SelectFalse; | 
|  | } else if (CMOVTrueVal == 0 && CMOVFalseVal == 1) { | 
|  | True = SelectFalse; | 
|  | False = SelectTrue; | 
|  | } | 
|  |  | 
|  | if (True.getNode() && False.getNode()) { | 
|  | EVT VT = Op.getValueType(); | 
|  | SDValue ARMcc = Cond.getOperand(2); | 
|  | SDValue CCR = Cond.getOperand(3); | 
|  | SDValue Cmp = duplicateCmp(Cond.getOperand(4), DAG); | 
|  | assert(True.getValueType() == VT); | 
|  | return getCMOV(dl, VT, True, False, ARMcc, CCR, Cmp, DAG); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // ARM's BooleanContents value is UndefinedBooleanContent. Mask out the | 
|  | // undefined bits before doing a full-word comparison with zero. | 
|  | Cond = DAG.getNode(ISD::AND, dl, Cond.getValueType(), Cond, | 
|  | DAG.getConstant(1, dl, Cond.getValueType())); | 
|  |  | 
|  | return DAG.getSelectCC(dl, Cond, | 
|  | DAG.getConstant(0, dl, Cond.getValueType()), | 
|  | SelectTrue, SelectFalse, ISD::SETNE); | 
|  | } | 
|  |  | 
|  | static void checkVSELConstraints(ISD::CondCode CC, ARMCC::CondCodes &CondCode, | 
|  | bool &swpCmpOps, bool &swpVselOps) { | 
|  | // Start by selecting the GE condition code for opcodes that return true for | 
|  | // 'equality' | 
|  | if (CC == ISD::SETUGE || CC == ISD::SETOGE || CC == ISD::SETOLE || | 
|  | CC == ISD::SETULE || CC == ISD::SETGE  || CC == ISD::SETLE) | 
|  | CondCode = ARMCC::GE; | 
|  |  | 
|  | // and GT for opcodes that return false for 'equality'. | 
|  | else if (CC == ISD::SETUGT || CC == ISD::SETOGT || CC == ISD::SETOLT || | 
|  | CC == ISD::SETULT || CC == ISD::SETGT  || CC == ISD::SETLT) | 
|  | CondCode = ARMCC::GT; | 
|  |  | 
|  | // Since we are constrained to GE/GT, if the opcode contains 'less', we need | 
|  | // to swap the compare operands. | 
|  | if (CC == ISD::SETOLE || CC == ISD::SETULE || CC == ISD::SETOLT || | 
|  | CC == ISD::SETULT || CC == ISD::SETLE  || CC == ISD::SETLT) | 
|  | swpCmpOps = true; | 
|  |  | 
|  | // Both GT and GE are ordered comparisons, and return false for 'unordered'. | 
|  | // If we have an unordered opcode, we need to swap the operands to the VSEL | 
|  | // instruction (effectively negating the condition). | 
|  | // | 
|  | // This also has the effect of swapping which one of 'less' or 'greater' | 
|  | // returns true, so we also swap the compare operands. It also switches | 
|  | // whether we return true for 'equality', so we compensate by picking the | 
|  | // opposite condition code to our original choice. | 
|  | if (CC == ISD::SETULE || CC == ISD::SETULT || CC == ISD::SETUGE || | 
|  | CC == ISD::SETUGT) { | 
|  | swpCmpOps = !swpCmpOps; | 
|  | swpVselOps = !swpVselOps; | 
|  | CondCode = CondCode == ARMCC::GT ? ARMCC::GE : ARMCC::GT; | 
|  | } | 
|  |  | 
|  | // 'ordered' is 'anything but unordered', so use the VS condition code and | 
|  | // swap the VSEL operands. | 
|  | if (CC == ISD::SETO) { | 
|  | CondCode = ARMCC::VS; | 
|  | swpVselOps = true; | 
|  | } | 
|  |  | 
|  | // 'unordered or not equal' is 'anything but equal', so use the EQ condition | 
|  | // code and swap the VSEL operands. Also do this if we don't care about the | 
|  | // unordered case. | 
|  | if (CC == ISD::SETUNE || CC == ISD::SETNE) { | 
|  | CondCode = ARMCC::EQ; | 
|  | swpVselOps = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::getCMOV(const SDLoc &dl, EVT VT, SDValue FalseVal, | 
|  | SDValue TrueVal, SDValue ARMcc, SDValue CCR, | 
|  | SDValue Cmp, SelectionDAG &DAG) const { | 
|  | if (!Subtarget->hasFP64() && VT == MVT::f64) { | 
|  | FalseVal = DAG.getNode(ARMISD::VMOVRRD, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), FalseVal); | 
|  | TrueVal = DAG.getNode(ARMISD::VMOVRRD, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), TrueVal); | 
|  |  | 
|  | SDValue TrueLow = TrueVal.getValue(0); | 
|  | SDValue TrueHigh = TrueVal.getValue(1); | 
|  | SDValue FalseLow = FalseVal.getValue(0); | 
|  | SDValue FalseHigh = FalseVal.getValue(1); | 
|  |  | 
|  | SDValue Low = DAG.getNode(ARMISD::CMOV, dl, MVT::i32, FalseLow, TrueLow, | 
|  | ARMcc, CCR, Cmp); | 
|  | SDValue High = DAG.getNode(ARMISD::CMOV, dl, MVT::i32, FalseHigh, TrueHigh, | 
|  | ARMcc, CCR, duplicateCmp(Cmp, DAG)); | 
|  |  | 
|  | return DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Low, High); | 
|  | } else { | 
|  | return DAG.getNode(ARMISD::CMOV, dl, VT, FalseVal, TrueVal, ARMcc, CCR, | 
|  | Cmp); | 
|  | } | 
|  | } | 
|  |  | 
|  | static bool isGTorGE(ISD::CondCode CC) { | 
|  | return CC == ISD::SETGT || CC == ISD::SETGE; | 
|  | } | 
|  |  | 
|  | static bool isLTorLE(ISD::CondCode CC) { | 
|  | return CC == ISD::SETLT || CC == ISD::SETLE; | 
|  | } | 
|  |  | 
|  | // See if a conditional (LHS CC RHS ? TrueVal : FalseVal) is lower-saturating. | 
|  | // All of these conditions (and their <= and >= counterparts) will do: | 
|  | //          x < k ? k : x | 
|  | //          x > k ? x : k | 
|  | //          k < x ? x : k | 
|  | //          k > x ? k : x | 
|  | static bool isLowerSaturate(const SDValue LHS, const SDValue RHS, | 
|  | const SDValue TrueVal, const SDValue FalseVal, | 
|  | const ISD::CondCode CC, const SDValue K) { | 
|  | return (isGTorGE(CC) && | 
|  | ((K == LHS && K == TrueVal) || (K == RHS && K == FalseVal))) || | 
|  | (isLTorLE(CC) && | 
|  | ((K == RHS && K == TrueVal) || (K == LHS && K == FalseVal))); | 
|  | } | 
|  |  | 
|  | // Similar to isLowerSaturate(), but checks for upper-saturating conditions. | 
|  | static bool isUpperSaturate(const SDValue LHS, const SDValue RHS, | 
|  | const SDValue TrueVal, const SDValue FalseVal, | 
|  | const ISD::CondCode CC, const SDValue K) { | 
|  | return (isGTorGE(CC) && | 
|  | ((K == RHS && K == TrueVal) || (K == LHS && K == FalseVal))) || | 
|  | (isLTorLE(CC) && | 
|  | ((K == LHS && K == TrueVal) || (K == RHS && K == FalseVal))); | 
|  | } | 
|  |  | 
|  | // Check if two chained conditionals could be converted into SSAT or USAT. | 
|  | // | 
|  | // SSAT can replace a set of two conditional selectors that bound a number to an | 
|  | // interval of type [k, ~k] when k + 1 is a power of 2. Here are some examples: | 
|  | // | 
|  | //     x < -k ? -k : (x > k ? k : x) | 
|  | //     x < -k ? -k : (x < k ? x : k) | 
|  | //     x > -k ? (x > k ? k : x) : -k | 
|  | //     x < k ? (x < -k ? -k : x) : k | 
|  | //     etc. | 
|  | // | 
|  | // USAT works similarily to SSAT but bounds on the interval [0, k] where k + 1 is | 
|  | // a power of 2. | 
|  | // | 
|  | // It returns true if the conversion can be done, false otherwise. | 
|  | // Additionally, the variable is returned in parameter V, the constant in K and | 
|  | // usat is set to true if the conditional represents an unsigned saturation | 
|  | static bool isSaturatingConditional(const SDValue &Op, SDValue &V, | 
|  | uint64_t &K, bool &usat) { | 
|  | SDValue LHS1 = Op.getOperand(0); | 
|  | SDValue RHS1 = Op.getOperand(1); | 
|  | SDValue TrueVal1 = Op.getOperand(2); | 
|  | SDValue FalseVal1 = Op.getOperand(3); | 
|  | ISD::CondCode CC1 = cast<CondCodeSDNode>(Op.getOperand(4))->get(); | 
|  |  | 
|  | const SDValue Op2 = isa<ConstantSDNode>(TrueVal1) ? FalseVal1 : TrueVal1; | 
|  | if (Op2.getOpcode() != ISD::SELECT_CC) | 
|  | return false; | 
|  |  | 
|  | SDValue LHS2 = Op2.getOperand(0); | 
|  | SDValue RHS2 = Op2.getOperand(1); | 
|  | SDValue TrueVal2 = Op2.getOperand(2); | 
|  | SDValue FalseVal2 = Op2.getOperand(3); | 
|  | ISD::CondCode CC2 = cast<CondCodeSDNode>(Op2.getOperand(4))->get(); | 
|  |  | 
|  | // Find out which are the constants and which are the variables | 
|  | // in each conditional | 
|  | SDValue *K1 = isa<ConstantSDNode>(LHS1) ? &LHS1 : isa<ConstantSDNode>(RHS1) | 
|  | ? &RHS1 | 
|  | : nullptr; | 
|  | SDValue *K2 = isa<ConstantSDNode>(LHS2) ? &LHS2 : isa<ConstantSDNode>(RHS2) | 
|  | ? &RHS2 | 
|  | : nullptr; | 
|  | SDValue K2Tmp = isa<ConstantSDNode>(TrueVal2) ? TrueVal2 : FalseVal2; | 
|  | SDValue V1Tmp = (K1 && *K1 == LHS1) ? RHS1 : LHS1; | 
|  | SDValue V2Tmp = (K2 && *K2 == LHS2) ? RHS2 : LHS2; | 
|  | SDValue V2 = (K2Tmp == TrueVal2) ? FalseVal2 : TrueVal2; | 
|  |  | 
|  | // We must detect cases where the original operations worked with 16- or | 
|  | // 8-bit values. In such case, V2Tmp != V2 because the comparison operations | 
|  | // must work with sign-extended values but the select operations return | 
|  | // the original non-extended value. | 
|  | SDValue V2TmpReg = V2Tmp; | 
|  | if (V2Tmp->getOpcode() == ISD::SIGN_EXTEND_INREG) | 
|  | V2TmpReg = V2Tmp->getOperand(0); | 
|  |  | 
|  | // Check that the registers and the constants have the correct values | 
|  | // in both conditionals | 
|  | if (!K1 || !K2 || *K1 == Op2 || *K2 != K2Tmp || V1Tmp != V2Tmp || | 
|  | V2TmpReg != V2) | 
|  | return false; | 
|  |  | 
|  | // Figure out which conditional is saturating the lower/upper bound. | 
|  | const SDValue *LowerCheckOp = | 
|  | isLowerSaturate(LHS1, RHS1, TrueVal1, FalseVal1, CC1, *K1) | 
|  | ? &Op | 
|  | : isLowerSaturate(LHS2, RHS2, TrueVal2, FalseVal2, CC2, *K2) | 
|  | ? &Op2 | 
|  | : nullptr; | 
|  | const SDValue *UpperCheckOp = | 
|  | isUpperSaturate(LHS1, RHS1, TrueVal1, FalseVal1, CC1, *K1) | 
|  | ? &Op | 
|  | : isUpperSaturate(LHS2, RHS2, TrueVal2, FalseVal2, CC2, *K2) | 
|  | ? &Op2 | 
|  | : nullptr; | 
|  |  | 
|  | if (!UpperCheckOp || !LowerCheckOp || LowerCheckOp == UpperCheckOp) | 
|  | return false; | 
|  |  | 
|  | // Check that the constant in the lower-bound check is | 
|  | // the opposite of the constant in the upper-bound check | 
|  | // in 1's complement. | 
|  | int64_t Val1 = cast<ConstantSDNode>(*K1)->getSExtValue(); | 
|  | int64_t Val2 = cast<ConstantSDNode>(*K2)->getSExtValue(); | 
|  | int64_t PosVal = std::max(Val1, Val2); | 
|  | int64_t NegVal = std::min(Val1, Val2); | 
|  |  | 
|  | if (((Val1 > Val2 && UpperCheckOp == &Op) || | 
|  | (Val1 < Val2 && UpperCheckOp == &Op2)) && | 
|  | isPowerOf2_64(PosVal + 1)) { | 
|  |  | 
|  | // Handle the difference between USAT (unsigned) and SSAT (signed) saturation | 
|  | if (Val1 == ~Val2) | 
|  | usat = false; | 
|  | else if (NegVal == 0) | 
|  | usat = true; | 
|  | else | 
|  | return false; | 
|  |  | 
|  | V = V2; | 
|  | K = (uint64_t)PosVal; // At this point, PosVal is guaranteed to be positive | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Check if a condition of the type x < k ? k : x can be converted into a | 
|  | // bit operation instead of conditional moves. | 
|  | // Currently this is allowed given: | 
|  | // - The conditions and values match up | 
|  | // - k is 0 or -1 (all ones) | 
|  | // This function will not check the last condition, thats up to the caller | 
|  | // It returns true if the transformation can be made, and in such case | 
|  | // returns x in V, and k in SatK. | 
|  | static bool isLowerSaturatingConditional(const SDValue &Op, SDValue &V, | 
|  | SDValue &SatK) | 
|  | { | 
|  | SDValue LHS = Op.getOperand(0); | 
|  | SDValue RHS = Op.getOperand(1); | 
|  | ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); | 
|  | SDValue TrueVal = Op.getOperand(2); | 
|  | SDValue FalseVal = Op.getOperand(3); | 
|  |  | 
|  | SDValue *K = isa<ConstantSDNode>(LHS) ? &LHS : isa<ConstantSDNode>(RHS) | 
|  | ? &RHS | 
|  | : nullptr; | 
|  |  | 
|  | // No constant operation in comparison, early out | 
|  | if (!K) | 
|  | return false; | 
|  |  | 
|  | SDValue KTmp = isa<ConstantSDNode>(TrueVal) ? TrueVal : FalseVal; | 
|  | V = (KTmp == TrueVal) ? FalseVal : TrueVal; | 
|  | SDValue VTmp = (K && *K == LHS) ? RHS : LHS; | 
|  |  | 
|  | // If the constant on left and right side, or variable on left and right, | 
|  | // does not match, early out | 
|  | if (*K != KTmp || V != VTmp) | 
|  | return false; | 
|  |  | 
|  | if (isLowerSaturate(LHS, RHS, TrueVal, FalseVal, CC, *K)) { | 
|  | SatK = *K; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isUnsupportedFloatingType(EVT VT) const { | 
|  | if (VT == MVT::f32) | 
|  | return !Subtarget->hasVFP2Base(); | 
|  | if (VT == MVT::f64) | 
|  | return !Subtarget->hasFP64(); | 
|  | if (VT == MVT::f16) | 
|  | return !Subtarget->hasFullFP16(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const { | 
|  | EVT VT = Op.getValueType(); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | // Try to convert two saturating conditional selects into a single SSAT | 
|  | SDValue SatValue; | 
|  | uint64_t SatConstant; | 
|  | bool SatUSat; | 
|  | if (((!Subtarget->isThumb() && Subtarget->hasV6Ops()) || Subtarget->isThumb2()) && | 
|  | isSaturatingConditional(Op, SatValue, SatConstant, SatUSat)) { | 
|  | if (SatUSat) | 
|  | return DAG.getNode(ARMISD::USAT, dl, VT, SatValue, | 
|  | DAG.getConstant(countTrailingOnes(SatConstant), dl, VT)); | 
|  | else | 
|  | return DAG.getNode(ARMISD::SSAT, dl, VT, SatValue, | 
|  | DAG.getConstant(countTrailingOnes(SatConstant), dl, VT)); | 
|  | } | 
|  |  | 
|  | // Try to convert expressions of the form x < k ? k : x (and similar forms) | 
|  | // into more efficient bit operations, which is possible when k is 0 or -1 | 
|  | // On ARM and Thumb-2 which have flexible operand 2 this will result in | 
|  | // single instructions. On Thumb the shift and the bit operation will be two | 
|  | // instructions. | 
|  | // Only allow this transformation on full-width (32-bit) operations | 
|  | SDValue LowerSatConstant; | 
|  | if (VT == MVT::i32 && | 
|  | isLowerSaturatingConditional(Op, SatValue, LowerSatConstant)) { | 
|  | SDValue ShiftV = DAG.getNode(ISD::SRA, dl, VT, SatValue, | 
|  | DAG.getConstant(31, dl, VT)); | 
|  | if (isNullConstant(LowerSatConstant)) { | 
|  | SDValue NotShiftV = DAG.getNode(ISD::XOR, dl, VT, ShiftV, | 
|  | DAG.getAllOnesConstant(dl, VT)); | 
|  | return DAG.getNode(ISD::AND, dl, VT, SatValue, NotShiftV); | 
|  | } else if (isAllOnesConstant(LowerSatConstant)) | 
|  | return DAG.getNode(ISD::OR, dl, VT, SatValue, ShiftV); | 
|  | } | 
|  |  | 
|  | SDValue LHS = Op.getOperand(0); | 
|  | SDValue RHS = Op.getOperand(1); | 
|  | ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); | 
|  | SDValue TrueVal = Op.getOperand(2); | 
|  | SDValue FalseVal = Op.getOperand(3); | 
|  | ConstantSDNode *CFVal = dyn_cast<ConstantSDNode>(FalseVal); | 
|  | ConstantSDNode *CTVal = dyn_cast<ConstantSDNode>(TrueVal); | 
|  |  | 
|  | if (Subtarget->hasV8_1MMainlineOps() && CFVal && CTVal && | 
|  | LHS.getValueType() == MVT::i32 && RHS.getValueType() == MVT::i32) { | 
|  | unsigned TVal = CTVal->getZExtValue(); | 
|  | unsigned FVal = CFVal->getZExtValue(); | 
|  | unsigned Opcode = 0; | 
|  |  | 
|  | if (TVal == ~FVal) { | 
|  | Opcode = ARMISD::CSINV; | 
|  | } else if (TVal == ~FVal + 1) { | 
|  | Opcode = ARMISD::CSNEG; | 
|  | } else if (TVal + 1 == FVal) { | 
|  | Opcode = ARMISD::CSINC; | 
|  | } else if (TVal == FVal + 1) { | 
|  | Opcode = ARMISD::CSINC; | 
|  | std::swap(TrueVal, FalseVal); | 
|  | std::swap(TVal, FVal); | 
|  | CC = ISD::getSetCCInverse(CC, LHS.getValueType()); | 
|  | } | 
|  |  | 
|  | if (Opcode) { | 
|  | // If one of the constants is cheaper than another, materialise the | 
|  | // cheaper one and let the csel generate the other. | 
|  | if (Opcode != ARMISD::CSINC && | 
|  | HasLowerConstantMaterializationCost(FVal, TVal, Subtarget)) { | 
|  | std::swap(TrueVal, FalseVal); | 
|  | std::swap(TVal, FVal); | 
|  | CC = ISD::getSetCCInverse(CC, LHS.getValueType()); | 
|  | } | 
|  |  | 
|  | // Attempt to use ZR checking TVal is 0, possibly inverting the condition | 
|  | // to get there. CSINC not is invertable like the other two (~(~a) == a, | 
|  | // -(-a) == a, but (a+1)+1 != a). | 
|  | if (FVal == 0 && Opcode != ARMISD::CSINC) { | 
|  | std::swap(TrueVal, FalseVal); | 
|  | std::swap(TVal, FVal); | 
|  | CC = ISD::getSetCCInverse(CC, LHS.getValueType()); | 
|  | } | 
|  | if (TVal == 0) | 
|  | TrueVal = DAG.getRegister(ARM::ZR, MVT::i32); | 
|  |  | 
|  | // Drops F's value because we can get it by inverting/negating TVal. | 
|  | FalseVal = TrueVal; | 
|  |  | 
|  | SDValue ARMcc; | 
|  | SDValue Cmp = getARMCmp(LHS, RHS, CC, ARMcc, DAG, dl); | 
|  | EVT VT = TrueVal.getValueType(); | 
|  | return DAG.getNode(Opcode, dl, VT, TrueVal, FalseVal, ARMcc, Cmp); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (isUnsupportedFloatingType(LHS.getValueType())) { | 
|  | DAG.getTargetLoweringInfo().softenSetCCOperands( | 
|  | DAG, LHS.getValueType(), LHS, RHS, CC, dl, LHS, RHS); | 
|  |  | 
|  | // If softenSetCCOperands only returned one value, we should compare it to | 
|  | // zero. | 
|  | if (!RHS.getNode()) { | 
|  | RHS = DAG.getConstant(0, dl, LHS.getValueType()); | 
|  | CC = ISD::SETNE; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (LHS.getValueType() == MVT::i32) { | 
|  | // Try to generate VSEL on ARMv8. | 
|  | // The VSEL instruction can't use all the usual ARM condition | 
|  | // codes: it only has two bits to select the condition code, so it's | 
|  | // constrained to use only GE, GT, VS and EQ. | 
|  | // | 
|  | // To implement all the various ISD::SETXXX opcodes, we sometimes need to | 
|  | // swap the operands of the previous compare instruction (effectively | 
|  | // inverting the compare condition, swapping 'less' and 'greater') and | 
|  | // sometimes need to swap the operands to the VSEL (which inverts the | 
|  | // condition in the sense of firing whenever the previous condition didn't) | 
|  | if (Subtarget->hasFPARMv8Base() && (TrueVal.getValueType() == MVT::f16 || | 
|  | TrueVal.getValueType() == MVT::f32 || | 
|  | TrueVal.getValueType() == MVT::f64)) { | 
|  | ARMCC::CondCodes CondCode = IntCCToARMCC(CC); | 
|  | if (CondCode == ARMCC::LT || CondCode == ARMCC::LE || | 
|  | CondCode == ARMCC::VC || CondCode == ARMCC::NE) { | 
|  | CC = ISD::getSetCCInverse(CC, LHS.getValueType()); | 
|  | std::swap(TrueVal, FalseVal); | 
|  | } | 
|  | } | 
|  |  | 
|  | SDValue ARMcc; | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  | SDValue Cmp = getARMCmp(LHS, RHS, CC, ARMcc, DAG, dl); | 
|  | // Choose GE over PL, which vsel does now support | 
|  | if (cast<ConstantSDNode>(ARMcc)->getZExtValue() == ARMCC::PL) | 
|  | ARMcc = DAG.getConstant(ARMCC::GE, dl, MVT::i32); | 
|  | return getCMOV(dl, VT, FalseVal, TrueVal, ARMcc, CCR, Cmp, DAG); | 
|  | } | 
|  |  | 
|  | ARMCC::CondCodes CondCode, CondCode2; | 
|  | FPCCToARMCC(CC, CondCode, CondCode2); | 
|  |  | 
|  | // Normalize the fp compare. If RHS is zero we prefer to keep it there so we | 
|  | // match CMPFPw0 instead of CMPFP, though we don't do this for f16 because we | 
|  | // must use VSEL (limited condition codes), due to not having conditional f16 | 
|  | // moves. | 
|  | if (Subtarget->hasFPARMv8Base() && | 
|  | !(isFloatingPointZero(RHS) && TrueVal.getValueType() != MVT::f16) && | 
|  | (TrueVal.getValueType() == MVT::f16 || | 
|  | TrueVal.getValueType() == MVT::f32 || | 
|  | TrueVal.getValueType() == MVT::f64)) { | 
|  | bool swpCmpOps = false; | 
|  | bool swpVselOps = false; | 
|  | checkVSELConstraints(CC, CondCode, swpCmpOps, swpVselOps); | 
|  |  | 
|  | if (CondCode == ARMCC::GT || CondCode == ARMCC::GE || | 
|  | CondCode == ARMCC::VS || CondCode == ARMCC::EQ) { | 
|  | if (swpCmpOps) | 
|  | std::swap(LHS, RHS); | 
|  | if (swpVselOps) | 
|  | std::swap(TrueVal, FalseVal); | 
|  | } | 
|  | } | 
|  |  | 
|  | SDValue ARMcc = DAG.getConstant(CondCode, dl, MVT::i32); | 
|  | SDValue Cmp = getVFPCmp(LHS, RHS, DAG, dl); | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  | SDValue Result = getCMOV(dl, VT, FalseVal, TrueVal, ARMcc, CCR, Cmp, DAG); | 
|  | if (CondCode2 != ARMCC::AL) { | 
|  | SDValue ARMcc2 = DAG.getConstant(CondCode2, dl, MVT::i32); | 
|  | // FIXME: Needs another CMP because flag can have but one use. | 
|  | SDValue Cmp2 = getVFPCmp(LHS, RHS, DAG, dl); | 
|  | Result = getCMOV(dl, VT, Result, TrueVal, ARMcc2, CCR, Cmp2, DAG); | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | /// canChangeToInt - Given the fp compare operand, return true if it is suitable | 
|  | /// to morph to an integer compare sequence. | 
|  | static bool canChangeToInt(SDValue Op, bool &SeenZero, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | SDNode *N = Op.getNode(); | 
|  | if (!N->hasOneUse()) | 
|  | // Otherwise it requires moving the value from fp to integer registers. | 
|  | return false; | 
|  | if (!N->getNumValues()) | 
|  | return false; | 
|  | EVT VT = Op.getValueType(); | 
|  | if (VT != MVT::f32 && !Subtarget->isFPBrccSlow()) | 
|  | // f32 case is generally profitable. f64 case only makes sense when vcmpe + | 
|  | // vmrs are very slow, e.g. cortex-a8. | 
|  | return false; | 
|  |  | 
|  | if (isFloatingPointZero(Op)) { | 
|  | SeenZero = true; | 
|  | return true; | 
|  | } | 
|  | return ISD::isNormalLoad(N); | 
|  | } | 
|  |  | 
|  | static SDValue bitcastf32Toi32(SDValue Op, SelectionDAG &DAG) { | 
|  | if (isFloatingPointZero(Op)) | 
|  | return DAG.getConstant(0, SDLoc(Op), MVT::i32); | 
|  |  | 
|  | if (LoadSDNode *Ld = dyn_cast<LoadSDNode>(Op)) | 
|  | return DAG.getLoad(MVT::i32, SDLoc(Op), Ld->getChain(), Ld->getBasePtr(), | 
|  | Ld->getPointerInfo(), Ld->getAlignment(), | 
|  | Ld->getMemOperand()->getFlags()); | 
|  |  | 
|  | llvm_unreachable("Unknown VFP cmp argument!"); | 
|  | } | 
|  |  | 
|  | static void expandf64Toi32(SDValue Op, SelectionDAG &DAG, | 
|  | SDValue &RetVal1, SDValue &RetVal2) { | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | if (isFloatingPointZero(Op)) { | 
|  | RetVal1 = DAG.getConstant(0, dl, MVT::i32); | 
|  | RetVal2 = DAG.getConstant(0, dl, MVT::i32); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (LoadSDNode *Ld = dyn_cast<LoadSDNode>(Op)) { | 
|  | SDValue Ptr = Ld->getBasePtr(); | 
|  | RetVal1 = | 
|  | DAG.getLoad(MVT::i32, dl, Ld->getChain(), Ptr, Ld->getPointerInfo(), | 
|  | Ld->getAlignment(), Ld->getMemOperand()->getFlags()); | 
|  |  | 
|  | EVT PtrType = Ptr.getValueType(); | 
|  | unsigned NewAlign = MinAlign(Ld->getAlignment(), 4); | 
|  | SDValue NewPtr = DAG.getNode(ISD::ADD, dl, | 
|  | PtrType, Ptr, DAG.getConstant(4, dl, PtrType)); | 
|  | RetVal2 = DAG.getLoad(MVT::i32, dl, Ld->getChain(), NewPtr, | 
|  | Ld->getPointerInfo().getWithOffset(4), NewAlign, | 
|  | Ld->getMemOperand()->getFlags()); | 
|  | return; | 
|  | } | 
|  |  | 
|  | llvm_unreachable("Unknown VFP cmp argument!"); | 
|  | } | 
|  |  | 
|  | /// OptimizeVFPBrcond - With -enable-unsafe-fp-math, it's legal to optimize some | 
|  | /// f32 and even f64 comparisons to integer ones. | 
|  | SDValue | 
|  | ARMTargetLowering::OptimizeVFPBrcond(SDValue Op, SelectionDAG &DAG) const { | 
|  | SDValue Chain = Op.getOperand(0); | 
|  | ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); | 
|  | SDValue LHS = Op.getOperand(2); | 
|  | SDValue RHS = Op.getOperand(3); | 
|  | SDValue Dest = Op.getOperand(4); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | bool LHSSeenZero = false; | 
|  | bool LHSOk = canChangeToInt(LHS, LHSSeenZero, Subtarget); | 
|  | bool RHSSeenZero = false; | 
|  | bool RHSOk = canChangeToInt(RHS, RHSSeenZero, Subtarget); | 
|  | if (LHSOk && RHSOk && (LHSSeenZero || RHSSeenZero)) { | 
|  | // If unsafe fp math optimization is enabled and there are no other uses of | 
|  | // the CMP operands, and the condition code is EQ or NE, we can optimize it | 
|  | // to an integer comparison. | 
|  | if (CC == ISD::SETOEQ) | 
|  | CC = ISD::SETEQ; | 
|  | else if (CC == ISD::SETUNE) | 
|  | CC = ISD::SETNE; | 
|  |  | 
|  | SDValue Mask = DAG.getConstant(0x7fffffff, dl, MVT::i32); | 
|  | SDValue ARMcc; | 
|  | if (LHS.getValueType() == MVT::f32) { | 
|  | LHS = DAG.getNode(ISD::AND, dl, MVT::i32, | 
|  | bitcastf32Toi32(LHS, DAG), Mask); | 
|  | RHS = DAG.getNode(ISD::AND, dl, MVT::i32, | 
|  | bitcastf32Toi32(RHS, DAG), Mask); | 
|  | SDValue Cmp = getARMCmp(LHS, RHS, CC, ARMcc, DAG, dl); | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  | return DAG.getNode(ARMISD::BRCOND, dl, MVT::Other, | 
|  | Chain, Dest, ARMcc, CCR, Cmp); | 
|  | } | 
|  |  | 
|  | SDValue LHS1, LHS2; | 
|  | SDValue RHS1, RHS2; | 
|  | expandf64Toi32(LHS, DAG, LHS1, LHS2); | 
|  | expandf64Toi32(RHS, DAG, RHS1, RHS2); | 
|  | LHS2 = DAG.getNode(ISD::AND, dl, MVT::i32, LHS2, Mask); | 
|  | RHS2 = DAG.getNode(ISD::AND, dl, MVT::i32, RHS2, Mask); | 
|  | ARMCC::CondCodes CondCode = IntCCToARMCC(CC); | 
|  | ARMcc = DAG.getConstant(CondCode, dl, MVT::i32); | 
|  | SDVTList VTList = DAG.getVTList(MVT::Other, MVT::Glue); | 
|  | SDValue Ops[] = { Chain, ARMcc, LHS1, LHS2, RHS1, RHS2, Dest }; | 
|  | return DAG.getNode(ARMISD::BCC_i64, dl, VTList, Ops); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const { | 
|  | SDValue Chain = Op.getOperand(0); | 
|  | SDValue Cond = Op.getOperand(1); | 
|  | SDValue Dest = Op.getOperand(2); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | // Optimize {s|u}{add|sub|mul}.with.overflow feeding into a branch | 
|  | // instruction. | 
|  | unsigned Opc = Cond.getOpcode(); | 
|  | bool OptimizeMul = (Opc == ISD::SMULO || Opc == ISD::UMULO) && | 
|  | !Subtarget->isThumb1Only(); | 
|  | if (Cond.getResNo() == 1 && | 
|  | (Opc == ISD::SADDO || Opc == ISD::UADDO || Opc == ISD::SSUBO || | 
|  | Opc == ISD::USUBO || OptimizeMul)) { | 
|  | // Only lower legal XALUO ops. | 
|  | if (!DAG.getTargetLoweringInfo().isTypeLegal(Cond->getValueType(0))) | 
|  | return SDValue(); | 
|  |  | 
|  | // The actual operation with overflow check. | 
|  | SDValue Value, OverflowCmp; | 
|  | SDValue ARMcc; | 
|  | std::tie(Value, OverflowCmp) = getARMXALUOOp(Cond, DAG, ARMcc); | 
|  |  | 
|  | // Reverse the condition code. | 
|  | ARMCC::CondCodes CondCode = | 
|  | (ARMCC::CondCodes)cast<const ConstantSDNode>(ARMcc)->getZExtValue(); | 
|  | CondCode = ARMCC::getOppositeCondition(CondCode); | 
|  | ARMcc = DAG.getConstant(CondCode, SDLoc(ARMcc), MVT::i32); | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  |  | 
|  | return DAG.getNode(ARMISD::BRCOND, dl, MVT::Other, Chain, Dest, ARMcc, CCR, | 
|  | OverflowCmp); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { | 
|  | SDValue Chain = Op.getOperand(0); | 
|  | ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); | 
|  | SDValue LHS = Op.getOperand(2); | 
|  | SDValue RHS = Op.getOperand(3); | 
|  | SDValue Dest = Op.getOperand(4); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | if (isUnsupportedFloatingType(LHS.getValueType())) { | 
|  | DAG.getTargetLoweringInfo().softenSetCCOperands( | 
|  | DAG, LHS.getValueType(), LHS, RHS, CC, dl, LHS, RHS); | 
|  |  | 
|  | // If softenSetCCOperands only returned one value, we should compare it to | 
|  | // zero. | 
|  | if (!RHS.getNode()) { | 
|  | RHS = DAG.getConstant(0, dl, LHS.getValueType()); | 
|  | CC = ISD::SETNE; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Optimize {s|u}{add|sub|mul}.with.overflow feeding into a branch | 
|  | // instruction. | 
|  | unsigned Opc = LHS.getOpcode(); | 
|  | bool OptimizeMul = (Opc == ISD::SMULO || Opc == ISD::UMULO) && | 
|  | !Subtarget->isThumb1Only(); | 
|  | if (LHS.getResNo() == 1 && (isOneConstant(RHS) || isNullConstant(RHS)) && | 
|  | (Opc == ISD::SADDO || Opc == ISD::UADDO || Opc == ISD::SSUBO || | 
|  | Opc == ISD::USUBO || OptimizeMul) && | 
|  | (CC == ISD::SETEQ || CC == ISD::SETNE)) { | 
|  | // Only lower legal XALUO ops. | 
|  | if (!DAG.getTargetLoweringInfo().isTypeLegal(LHS->getValueType(0))) | 
|  | return SDValue(); | 
|  |  | 
|  | // The actual operation with overflow check. | 
|  | SDValue Value, OverflowCmp; | 
|  | SDValue ARMcc; | 
|  | std::tie(Value, OverflowCmp) = getARMXALUOOp(LHS.getValue(0), DAG, ARMcc); | 
|  |  | 
|  | if ((CC == ISD::SETNE) != isOneConstant(RHS)) { | 
|  | // Reverse the condition code. | 
|  | ARMCC::CondCodes CondCode = | 
|  | (ARMCC::CondCodes)cast<const ConstantSDNode>(ARMcc)->getZExtValue(); | 
|  | CondCode = ARMCC::getOppositeCondition(CondCode); | 
|  | ARMcc = DAG.getConstant(CondCode, SDLoc(ARMcc), MVT::i32); | 
|  | } | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  |  | 
|  | return DAG.getNode(ARMISD::BRCOND, dl, MVT::Other, Chain, Dest, ARMcc, CCR, | 
|  | OverflowCmp); | 
|  | } | 
|  |  | 
|  | if (LHS.getValueType() == MVT::i32) { | 
|  | SDValue ARMcc; | 
|  | SDValue Cmp = getARMCmp(LHS, RHS, CC, ARMcc, DAG, dl); | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  | return DAG.getNode(ARMISD::BRCOND, dl, MVT::Other, | 
|  | Chain, Dest, ARMcc, CCR, Cmp); | 
|  | } | 
|  |  | 
|  | if (getTargetMachine().Options.UnsafeFPMath && | 
|  | (CC == ISD::SETEQ || CC == ISD::SETOEQ || | 
|  | CC == ISD::SETNE || CC == ISD::SETUNE)) { | 
|  | if (SDValue Result = OptimizeVFPBrcond(Op, DAG)) | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | ARMCC::CondCodes CondCode, CondCode2; | 
|  | FPCCToARMCC(CC, CondCode, CondCode2); | 
|  |  | 
|  | SDValue ARMcc = DAG.getConstant(CondCode, dl, MVT::i32); | 
|  | SDValue Cmp = getVFPCmp(LHS, RHS, DAG, dl); | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  | SDVTList VTList = DAG.getVTList(MVT::Other, MVT::Glue); | 
|  | SDValue Ops[] = { Chain, Dest, ARMcc, CCR, Cmp }; | 
|  | SDValue Res = DAG.getNode(ARMISD::BRCOND, dl, VTList, Ops); | 
|  | if (CondCode2 != ARMCC::AL) { | 
|  | ARMcc = DAG.getConstant(CondCode2, dl, MVT::i32); | 
|  | SDValue Ops[] = { Res, Dest, ARMcc, CCR, Res.getValue(1) }; | 
|  | Res = DAG.getNode(ARMISD::BRCOND, dl, VTList, Ops); | 
|  | } | 
|  | return Res; | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const { | 
|  | SDValue Chain = Op.getOperand(0); | 
|  | SDValue Table = Op.getOperand(1); | 
|  | SDValue Index = Op.getOperand(2); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | EVT PTy = getPointerTy(DAG.getDataLayout()); | 
|  | JumpTableSDNode *JT = cast<JumpTableSDNode>(Table); | 
|  | SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PTy); | 
|  | Table = DAG.getNode(ARMISD::WrapperJT, dl, MVT::i32, JTI); | 
|  | Index = DAG.getNode(ISD::MUL, dl, PTy, Index, DAG.getConstant(4, dl, PTy)); | 
|  | SDValue Addr = DAG.getNode(ISD::ADD, dl, PTy, Table, Index); | 
|  | if (Subtarget->isThumb2() || (Subtarget->hasV8MBaselineOps() && Subtarget->isThumb())) { | 
|  | // Thumb2 and ARMv8-M use a two-level jump. That is, it jumps into the jump table | 
|  | // which does another jump to the destination. This also makes it easier | 
|  | // to translate it to TBB / TBH later (Thumb2 only). | 
|  | // FIXME: This might not work if the function is extremely large. | 
|  | return DAG.getNode(ARMISD::BR2_JT, dl, MVT::Other, Chain, | 
|  | Addr, Op.getOperand(2), JTI); | 
|  | } | 
|  | if (isPositionIndependent() || Subtarget->isROPI()) { | 
|  | Addr = | 
|  | DAG.getLoad((EVT)MVT::i32, dl, Chain, Addr, | 
|  | MachinePointerInfo::getJumpTable(DAG.getMachineFunction())); | 
|  | Chain = Addr.getValue(1); | 
|  | Addr = DAG.getNode(ISD::ADD, dl, PTy, Table, Addr); | 
|  | return DAG.getNode(ARMISD::BR_JT, dl, MVT::Other, Chain, Addr, JTI); | 
|  | } else { | 
|  | Addr = | 
|  | DAG.getLoad(PTy, dl, Chain, Addr, | 
|  | MachinePointerInfo::getJumpTable(DAG.getMachineFunction())); | 
|  | Chain = Addr.getValue(1); | 
|  | return DAG.getNode(ARMISD::BR_JT, dl, MVT::Other, Chain, Addr, JTI); | 
|  | } | 
|  | } | 
|  |  | 
|  | static SDValue LowerVectorFP_TO_INT(SDValue Op, SelectionDAG &DAG) { | 
|  | EVT VT = Op.getValueType(); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | if (Op.getValueType().getVectorElementType() == MVT::i32) { | 
|  | if (Op.getOperand(0).getValueType().getVectorElementType() == MVT::f32) | 
|  | return Op; | 
|  | return DAG.UnrollVectorOp(Op.getNode()); | 
|  | } | 
|  |  | 
|  | const bool HasFullFP16 = | 
|  | static_cast<const ARMSubtarget&>(DAG.getSubtarget()).hasFullFP16(); | 
|  |  | 
|  | EVT NewTy; | 
|  | const EVT OpTy = Op.getOperand(0).getValueType(); | 
|  | if (OpTy == MVT::v4f32) | 
|  | NewTy = MVT::v4i32; | 
|  | else if (OpTy == MVT::v4f16 && HasFullFP16) | 
|  | NewTy = MVT::v4i16; | 
|  | else if (OpTy == MVT::v8f16 && HasFullFP16) | 
|  | NewTy = MVT::v8i16; | 
|  | else | 
|  | llvm_unreachable("Invalid type for custom lowering!"); | 
|  |  | 
|  | if (VT != MVT::v4i16 && VT != MVT::v8i16) | 
|  | return DAG.UnrollVectorOp(Op.getNode()); | 
|  |  | 
|  | Op = DAG.getNode(Op.getOpcode(), dl, NewTy, Op.getOperand(0)); | 
|  | return DAG.getNode(ISD::TRUNCATE, dl, VT, Op); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) const { | 
|  | EVT VT = Op.getValueType(); | 
|  | if (VT.isVector()) | 
|  | return LowerVectorFP_TO_INT(Op, DAG); | 
|  |  | 
|  | bool IsStrict = Op->isStrictFPOpcode(); | 
|  | SDValue SrcVal = Op.getOperand(IsStrict ? 1 : 0); | 
|  |  | 
|  | if (isUnsupportedFloatingType(SrcVal.getValueType())) { | 
|  | RTLIB::Libcall LC; | 
|  | if (Op.getOpcode() == ISD::FP_TO_SINT || | 
|  | Op.getOpcode() == ISD::STRICT_FP_TO_SINT) | 
|  | LC = RTLIB::getFPTOSINT(SrcVal.getValueType(), | 
|  | Op.getValueType()); | 
|  | else | 
|  | LC = RTLIB::getFPTOUINT(SrcVal.getValueType(), | 
|  | Op.getValueType()); | 
|  | SDLoc Loc(Op); | 
|  | MakeLibCallOptions CallOptions; | 
|  | SDValue Chain = IsStrict ? Op.getOperand(0) : SDValue(); | 
|  | SDValue Result; | 
|  | std::tie(Result, Chain) = makeLibCall(DAG, LC, Op.getValueType(), SrcVal, | 
|  | CallOptions, Loc, Chain); | 
|  | return IsStrict ? DAG.getMergeValues({Result, Chain}, Loc) : Result; | 
|  | } | 
|  |  | 
|  | // FIXME: Remove this when we have strict fp instruction selection patterns | 
|  | if (IsStrict) { | 
|  | SDLoc Loc(Op); | 
|  | SDValue Result = | 
|  | DAG.getNode(Op.getOpcode() == ISD::STRICT_FP_TO_SINT ? ISD::FP_TO_SINT | 
|  | : ISD::FP_TO_UINT, | 
|  | Loc, Op.getValueType(), SrcVal); | 
|  | return DAG.getMergeValues({Result, Op.getOperand(0)}, Loc); | 
|  | } | 
|  |  | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | static SDValue LowerVectorINT_TO_FP(SDValue Op, SelectionDAG &DAG) { | 
|  | EVT VT = Op.getValueType(); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | if (Op.getOperand(0).getValueType().getVectorElementType() == MVT::i32) { | 
|  | if (VT.getVectorElementType() == MVT::f32) | 
|  | return Op; | 
|  | return DAG.UnrollVectorOp(Op.getNode()); | 
|  | } | 
|  |  | 
|  | assert((Op.getOperand(0).getValueType() == MVT::v4i16 || | 
|  | Op.getOperand(0).getValueType() == MVT::v8i16) && | 
|  | "Invalid type for custom lowering!"); | 
|  |  | 
|  | const bool HasFullFP16 = | 
|  | static_cast<const ARMSubtarget&>(DAG.getSubtarget()).hasFullFP16(); | 
|  |  | 
|  | EVT DestVecType; | 
|  | if (VT == MVT::v4f32) | 
|  | DestVecType = MVT::v4i32; | 
|  | else if (VT == MVT::v4f16 && HasFullFP16) | 
|  | DestVecType = MVT::v4i16; | 
|  | else if (VT == MVT::v8f16 && HasFullFP16) | 
|  | DestVecType = MVT::v8i16; | 
|  | else | 
|  | return DAG.UnrollVectorOp(Op.getNode()); | 
|  |  | 
|  | unsigned CastOpc; | 
|  | unsigned Opc; | 
|  | switch (Op.getOpcode()) { | 
|  | default: llvm_unreachable("Invalid opcode!"); | 
|  | case ISD::SINT_TO_FP: | 
|  | CastOpc = ISD::SIGN_EXTEND; | 
|  | Opc = ISD::SINT_TO_FP; | 
|  | break; | 
|  | case ISD::UINT_TO_FP: | 
|  | CastOpc = ISD::ZERO_EXTEND; | 
|  | Opc = ISD::UINT_TO_FP; | 
|  | break; | 
|  | } | 
|  |  | 
|  | Op = DAG.getNode(CastOpc, dl, DestVecType, Op.getOperand(0)); | 
|  | return DAG.getNode(Opc, dl, VT, Op); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) const { | 
|  | EVT VT = Op.getValueType(); | 
|  | if (VT.isVector()) | 
|  | return LowerVectorINT_TO_FP(Op, DAG); | 
|  | if (isUnsupportedFloatingType(VT)) { | 
|  | RTLIB::Libcall LC; | 
|  | if (Op.getOpcode() == ISD::SINT_TO_FP) | 
|  | LC = RTLIB::getSINTTOFP(Op.getOperand(0).getValueType(), | 
|  | Op.getValueType()); | 
|  | else | 
|  | LC = RTLIB::getUINTTOFP(Op.getOperand(0).getValueType(), | 
|  | Op.getValueType()); | 
|  | MakeLibCallOptions CallOptions; | 
|  | return makeLibCall(DAG, LC, Op.getValueType(), Op.getOperand(0), | 
|  | CallOptions, SDLoc(Op)).first; | 
|  | } | 
|  |  | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const { | 
|  | // Implement fcopysign with a fabs and a conditional fneg. | 
|  | SDValue Tmp0 = Op.getOperand(0); | 
|  | SDValue Tmp1 = Op.getOperand(1); | 
|  | SDLoc dl(Op); | 
|  | EVT VT = Op.getValueType(); | 
|  | EVT SrcVT = Tmp1.getValueType(); | 
|  | bool InGPR = Tmp0.getOpcode() == ISD::BITCAST || | 
|  | Tmp0.getOpcode() == ARMISD::VMOVDRR; | 
|  | bool UseNEON = !InGPR && Subtarget->hasNEON(); | 
|  |  | 
|  | if (UseNEON) { | 
|  | // Use VBSL to copy the sign bit. | 
|  | unsigned EncodedVal = ARM_AM::createVMOVModImm(0x6, 0x80); | 
|  | SDValue Mask = DAG.getNode(ARMISD::VMOVIMM, dl, MVT::v2i32, | 
|  | DAG.getTargetConstant(EncodedVal, dl, MVT::i32)); | 
|  | EVT OpVT = (VT == MVT::f32) ? MVT::v2i32 : MVT::v1i64; | 
|  | if (VT == MVT::f64) | 
|  | Mask = DAG.getNode(ARMISD::VSHLIMM, dl, OpVT, | 
|  | DAG.getNode(ISD::BITCAST, dl, OpVT, Mask), | 
|  | DAG.getConstant(32, dl, MVT::i32)); | 
|  | else /*if (VT == MVT::f32)*/ | 
|  | Tmp0 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v2f32, Tmp0); | 
|  | if (SrcVT == MVT::f32) { | 
|  | Tmp1 = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v2f32, Tmp1); | 
|  | if (VT == MVT::f64) | 
|  | Tmp1 = DAG.getNode(ARMISD::VSHLIMM, dl, OpVT, | 
|  | DAG.getNode(ISD::BITCAST, dl, OpVT, Tmp1), | 
|  | DAG.getConstant(32, dl, MVT::i32)); | 
|  | } else if (VT == MVT::f32) | 
|  | Tmp1 = DAG.getNode(ARMISD::VSHRuIMM, dl, MVT::v1i64, | 
|  | DAG.getNode(ISD::BITCAST, dl, MVT::v1i64, Tmp1), | 
|  | DAG.getConstant(32, dl, MVT::i32)); | 
|  | Tmp0 = DAG.getNode(ISD::BITCAST, dl, OpVT, Tmp0); | 
|  | Tmp1 = DAG.getNode(ISD::BITCAST, dl, OpVT, Tmp1); | 
|  |  | 
|  | SDValue AllOnes = DAG.getTargetConstant(ARM_AM::createVMOVModImm(0xe, 0xff), | 
|  | dl, MVT::i32); | 
|  | AllOnes = DAG.getNode(ARMISD::VMOVIMM, dl, MVT::v8i8, AllOnes); | 
|  | SDValue MaskNot = DAG.getNode(ISD::XOR, dl, OpVT, Mask, | 
|  | DAG.getNode(ISD::BITCAST, dl, OpVT, AllOnes)); | 
|  |  | 
|  | SDValue Res = DAG.getNode(ISD::OR, dl, OpVT, | 
|  | DAG.getNode(ISD::AND, dl, OpVT, Tmp1, Mask), | 
|  | DAG.getNode(ISD::AND, dl, OpVT, Tmp0, MaskNot)); | 
|  | if (VT == MVT::f32) { | 
|  | Res = DAG.getNode(ISD::BITCAST, dl, MVT::v2f32, Res); | 
|  | Res = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f32, Res, | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | } else { | 
|  | Res = DAG.getNode(ISD::BITCAST, dl, MVT::f64, Res); | 
|  | } | 
|  |  | 
|  | return Res; | 
|  | } | 
|  |  | 
|  | // Bitcast operand 1 to i32. | 
|  | if (SrcVT == MVT::f64) | 
|  | Tmp1 = DAG.getNode(ARMISD::VMOVRRD, dl, DAG.getVTList(MVT::i32, MVT::i32), | 
|  | Tmp1).getValue(1); | 
|  | Tmp1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Tmp1); | 
|  |  | 
|  | // Or in the signbit with integer operations. | 
|  | SDValue Mask1 = DAG.getConstant(0x80000000, dl, MVT::i32); | 
|  | SDValue Mask2 = DAG.getConstant(0x7fffffff, dl, MVT::i32); | 
|  | Tmp1 = DAG.getNode(ISD::AND, dl, MVT::i32, Tmp1, Mask1); | 
|  | if (VT == MVT::f32) { | 
|  | Tmp0 = DAG.getNode(ISD::AND, dl, MVT::i32, | 
|  | DAG.getNode(ISD::BITCAST, dl, MVT::i32, Tmp0), Mask2); | 
|  | return DAG.getNode(ISD::BITCAST, dl, MVT::f32, | 
|  | DAG.getNode(ISD::OR, dl, MVT::i32, Tmp0, Tmp1)); | 
|  | } | 
|  |  | 
|  | // f64: Or the high part with signbit and then combine two parts. | 
|  | Tmp0 = DAG.getNode(ARMISD::VMOVRRD, dl, DAG.getVTList(MVT::i32, MVT::i32), | 
|  | Tmp0); | 
|  | SDValue Lo = Tmp0.getValue(0); | 
|  | SDValue Hi = DAG.getNode(ISD::AND, dl, MVT::i32, Tmp0.getValue(1), Mask2); | 
|  | Hi = DAG.getNode(ISD::OR, dl, MVT::i32, Hi, Tmp1); | 
|  | return DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Lo, Hi); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const{ | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | MFI.setReturnAddressIsTaken(true); | 
|  |  | 
|  | if (verifyReturnAddressArgumentIsConstant(Op, DAG)) | 
|  | return SDValue(); | 
|  |  | 
|  | EVT VT = Op.getValueType(); | 
|  | SDLoc dl(Op); | 
|  | unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); | 
|  | if (Depth) { | 
|  | SDValue FrameAddr = LowerFRAMEADDR(Op, DAG); | 
|  | SDValue Offset = DAG.getConstant(4, dl, MVT::i32); | 
|  | return DAG.getLoad(VT, dl, DAG.getEntryNode(), | 
|  | DAG.getNode(ISD::ADD, dl, VT, FrameAddr, Offset), | 
|  | MachinePointerInfo()); | 
|  | } | 
|  |  | 
|  | // Return LR, which contains the return address. Mark it an implicit live-in. | 
|  | unsigned Reg = MF.addLiveIn(ARM::LR, getRegClassFor(MVT::i32)); | 
|  | return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, VT); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { | 
|  | const ARMBaseRegisterInfo &ARI = | 
|  | *static_cast<const ARMBaseRegisterInfo*>(RegInfo); | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | MFI.setFrameAddressIsTaken(true); | 
|  |  | 
|  | EVT VT = Op.getValueType(); | 
|  | SDLoc dl(Op);  // FIXME probably not meaningful | 
|  | unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); | 
|  | Register FrameReg = ARI.getFrameRegister(MF); | 
|  | SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT); | 
|  | while (Depth--) | 
|  | FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr, | 
|  | MachinePointerInfo()); | 
|  | return FrameAddr; | 
|  | } | 
|  |  | 
|  | // FIXME? Maybe this could be a TableGen attribute on some registers and | 
|  | // this table could be generated automatically from RegInfo. | 
|  | Register ARMTargetLowering::getRegisterByName(const char* RegName, LLT VT, | 
|  | const MachineFunction &MF) const { | 
|  | Register Reg = StringSwitch<unsigned>(RegName) | 
|  | .Case("sp", ARM::SP) | 
|  | .Default(0); | 
|  | if (Reg) | 
|  | return Reg; | 
|  | report_fatal_error(Twine("Invalid register name \"" | 
|  | + StringRef(RegName)  + "\".")); | 
|  | } | 
|  |  | 
|  | // Result is 64 bit value so split into two 32 bit values and return as a | 
|  | // pair of values. | 
|  | static void ExpandREAD_REGISTER(SDNode *N, SmallVectorImpl<SDValue> &Results, | 
|  | SelectionDAG &DAG) { | 
|  | SDLoc DL(N); | 
|  |  | 
|  | // This function is only supposed to be called for i64 type destination. | 
|  | assert(N->getValueType(0) == MVT::i64 | 
|  | && "ExpandREAD_REGISTER called for non-i64 type result."); | 
|  |  | 
|  | SDValue Read = DAG.getNode(ISD::READ_REGISTER, DL, | 
|  | DAG.getVTList(MVT::i32, MVT::i32, MVT::Other), | 
|  | N->getOperand(0), | 
|  | N->getOperand(1)); | 
|  |  | 
|  | Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Read.getValue(0), | 
|  | Read.getValue(1))); | 
|  | Results.push_back(Read.getOperand(0)); | 
|  | } | 
|  |  | 
|  | /// \p BC is a bitcast that is about to be turned into a VMOVDRR. | 
|  | /// When \p DstVT, the destination type of \p BC, is on the vector | 
|  | /// register bank and the source of bitcast, \p Op, operates on the same bank, | 
|  | /// it might be possible to combine them, such that everything stays on the | 
|  | /// vector register bank. | 
|  | /// \p return The node that would replace \p BT, if the combine | 
|  | /// is possible. | 
|  | static SDValue CombineVMOVDRRCandidateWithVecOp(const SDNode *BC, | 
|  | SelectionDAG &DAG) { | 
|  | SDValue Op = BC->getOperand(0); | 
|  | EVT DstVT = BC->getValueType(0); | 
|  |  | 
|  | // The only vector instruction that can produce a scalar (remember, | 
|  | // since the bitcast was about to be turned into VMOVDRR, the source | 
|  | // type is i64) from a vector is EXTRACT_VECTOR_ELT. | 
|  | // Moreover, we can do this combine only if there is one use. | 
|  | // Finally, if the destination type is not a vector, there is not | 
|  | // much point on forcing everything on the vector bank. | 
|  | if (!DstVT.isVector() || Op.getOpcode() != ISD::EXTRACT_VECTOR_ELT || | 
|  | !Op.hasOneUse()) | 
|  | return SDValue(); | 
|  |  | 
|  | // If the index is not constant, we will introduce an additional | 
|  | // multiply that will stick. | 
|  | // Give up in that case. | 
|  | ConstantSDNode *Index = dyn_cast<ConstantSDNode>(Op.getOperand(1)); | 
|  | if (!Index) | 
|  | return SDValue(); | 
|  | unsigned DstNumElt = DstVT.getVectorNumElements(); | 
|  |  | 
|  | // Compute the new index. | 
|  | const APInt &APIntIndex = Index->getAPIntValue(); | 
|  | APInt NewIndex(APIntIndex.getBitWidth(), DstNumElt); | 
|  | NewIndex *= APIntIndex; | 
|  | // Check if the new constant index fits into i32. | 
|  | if (NewIndex.getBitWidth() > 32) | 
|  | return SDValue(); | 
|  |  | 
|  | // vMTy bitcast(i64 extractelt vNi64 src, i32 index) -> | 
|  | // vMTy extractsubvector vNxMTy (bitcast vNi64 src), i32 index*M) | 
|  | SDLoc dl(Op); | 
|  | SDValue ExtractSrc = Op.getOperand(0); | 
|  | EVT VecVT = EVT::getVectorVT( | 
|  | *DAG.getContext(), DstVT.getScalarType(), | 
|  | ExtractSrc.getValueType().getVectorNumElements() * DstNumElt); | 
|  | SDValue BitCast = DAG.getNode(ISD::BITCAST, dl, VecVT, ExtractSrc); | 
|  | return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, DstVT, BitCast, | 
|  | DAG.getConstant(NewIndex.getZExtValue(), dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | /// ExpandBITCAST - If the target supports VFP, this function is called to | 
|  | /// expand a bit convert where either the source or destination type is i64 to | 
|  | /// use a VMOVDRR or VMOVRRD node.  This should not be done when the non-i64 | 
|  | /// operand type is illegal (e.g., v2f32 for a target that doesn't support | 
|  | /// vectors), since the legalizer won't know what to do with that. | 
|  | static SDValue ExpandBITCAST(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | SDLoc dl(N); | 
|  | SDValue Op = N->getOperand(0); | 
|  |  | 
|  | // This function is only supposed to be called for i16 and i64 types, either | 
|  | // as the source or destination of the bit convert. | 
|  | EVT SrcVT = Op.getValueType(); | 
|  | EVT DstVT = N->getValueType(0); | 
|  |  | 
|  | if (SrcVT == MVT::i16 && DstVT == MVT::f16) { | 
|  | if (!Subtarget->hasFullFP16()) | 
|  | return SDValue(); | 
|  | // f16 bitcast i16 -> VMOVhr | 
|  | return DAG.getNode(ARMISD::VMOVhr, SDLoc(N), MVT::f16, | 
|  | DAG.getNode(ISD::ZERO_EXTEND, SDLoc(N), MVT::i32, Op)); | 
|  | } | 
|  |  | 
|  | if (SrcVT == MVT::f16 && DstVT == MVT::i16) { | 
|  | if (!Subtarget->hasFullFP16()) | 
|  | return SDValue(); | 
|  | // i16 bitcast f16 -> VMOVrh | 
|  | return DAG.getNode(ISD::TRUNCATE, SDLoc(N), MVT::i16, | 
|  | DAG.getNode(ARMISD::VMOVrh, SDLoc(N), MVT::i32, Op)); | 
|  | } | 
|  |  | 
|  | if (!(SrcVT == MVT::i64 || DstVT == MVT::i64)) | 
|  | return SDValue(); | 
|  |  | 
|  | // Turn i64->f64 into VMOVDRR. | 
|  | if (SrcVT == MVT::i64 && TLI.isTypeLegal(DstVT)) { | 
|  | // Do not force values to GPRs (this is what VMOVDRR does for the inputs) | 
|  | // if we can combine the bitcast with its source. | 
|  | if (SDValue Val = CombineVMOVDRRCandidateWithVecOp(N, DAG)) | 
|  | return Val; | 
|  |  | 
|  | SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Op, | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Op, | 
|  | DAG.getConstant(1, dl, MVT::i32)); | 
|  | return DAG.getNode(ISD::BITCAST, dl, DstVT, | 
|  | DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Lo, Hi)); | 
|  | } | 
|  |  | 
|  | // Turn f64->i64 into VMOVRRD. | 
|  | if (DstVT == MVT::i64 && TLI.isTypeLegal(SrcVT)) { | 
|  | SDValue Cvt; | 
|  | if (DAG.getDataLayout().isBigEndian() && SrcVT.isVector() && | 
|  | SrcVT.getVectorNumElements() > 1) | 
|  | Cvt = DAG.getNode(ARMISD::VMOVRRD, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), | 
|  | DAG.getNode(ARMISD::VREV64, dl, SrcVT, Op)); | 
|  | else | 
|  | Cvt = DAG.getNode(ARMISD::VMOVRRD, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), Op); | 
|  | // Merge the pieces into a single i64 value. | 
|  | return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Cvt, Cvt.getValue(1)); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// getZeroVector - Returns a vector of specified type with all zero elements. | 
|  | /// Zero vectors are used to represent vector negation and in those cases | 
|  | /// will be implemented with the NEON VNEG instruction.  However, VNEG does | 
|  | /// not support i64 elements, so sometimes the zero vectors will need to be | 
|  | /// explicitly constructed.  Regardless, use a canonical VMOV to create the | 
|  | /// zero vector. | 
|  | static SDValue getZeroVector(EVT VT, SelectionDAG &DAG, const SDLoc &dl) { | 
|  | assert(VT.isVector() && "Expected a vector type"); | 
|  | // The canonical modified immediate encoding of a zero vector is....0! | 
|  | SDValue EncodedVal = DAG.getTargetConstant(0, dl, MVT::i32); | 
|  | EVT VmovVT = VT.is128BitVector() ? MVT::v4i32 : MVT::v2i32; | 
|  | SDValue Vmov = DAG.getNode(ARMISD::VMOVIMM, dl, VmovVT, EncodedVal); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, Vmov); | 
|  | } | 
|  |  | 
|  | /// LowerShiftRightParts - Lower SRA_PARTS, which returns two | 
|  | /// i32 values and take a 2 x i32 value to shift plus a shift amount. | 
|  | SDValue ARMTargetLowering::LowerShiftRightParts(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | assert(Op.getNumOperands() == 3 && "Not a double-shift!"); | 
|  | EVT VT = Op.getValueType(); | 
|  | unsigned VTBits = VT.getSizeInBits(); | 
|  | SDLoc dl(Op); | 
|  | SDValue ShOpLo = Op.getOperand(0); | 
|  | SDValue ShOpHi = Op.getOperand(1); | 
|  | SDValue ShAmt  = Op.getOperand(2); | 
|  | SDValue ARMcc; | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  | unsigned Opc = (Op.getOpcode() == ISD::SRA_PARTS) ? ISD::SRA : ISD::SRL; | 
|  |  | 
|  | assert(Op.getOpcode() == ISD::SRA_PARTS || Op.getOpcode() == ISD::SRL_PARTS); | 
|  |  | 
|  | SDValue RevShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, | 
|  | DAG.getConstant(VTBits, dl, MVT::i32), ShAmt); | 
|  | SDValue Tmp1 = DAG.getNode(ISD::SRL, dl, VT, ShOpLo, ShAmt); | 
|  | SDValue ExtraShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt, | 
|  | DAG.getConstant(VTBits, dl, MVT::i32)); | 
|  | SDValue Tmp2 = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, RevShAmt); | 
|  | SDValue LoSmallShift = DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2); | 
|  | SDValue LoBigShift = DAG.getNode(Opc, dl, VT, ShOpHi, ExtraShAmt); | 
|  | SDValue CmpLo = getARMCmp(ExtraShAmt, DAG.getConstant(0, dl, MVT::i32), | 
|  | ISD::SETGE, ARMcc, DAG, dl); | 
|  | SDValue Lo = DAG.getNode(ARMISD::CMOV, dl, VT, LoSmallShift, LoBigShift, | 
|  | ARMcc, CCR, CmpLo); | 
|  |  | 
|  | SDValue HiSmallShift = DAG.getNode(Opc, dl, VT, ShOpHi, ShAmt); | 
|  | SDValue HiBigShift = Opc == ISD::SRA | 
|  | ? DAG.getNode(Opc, dl, VT, ShOpHi, | 
|  | DAG.getConstant(VTBits - 1, dl, VT)) | 
|  | : DAG.getConstant(0, dl, VT); | 
|  | SDValue CmpHi = getARMCmp(ExtraShAmt, DAG.getConstant(0, dl, MVT::i32), | 
|  | ISD::SETGE, ARMcc, DAG, dl); | 
|  | SDValue Hi = DAG.getNode(ARMISD::CMOV, dl, VT, HiSmallShift, HiBigShift, | 
|  | ARMcc, CCR, CmpHi); | 
|  |  | 
|  | SDValue Ops[2] = { Lo, Hi }; | 
|  | return DAG.getMergeValues(Ops, dl); | 
|  | } | 
|  |  | 
|  | /// LowerShiftLeftParts - Lower SHL_PARTS, which returns two | 
|  | /// i32 values and take a 2 x i32 value to shift plus a shift amount. | 
|  | SDValue ARMTargetLowering::LowerShiftLeftParts(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | assert(Op.getNumOperands() == 3 && "Not a double-shift!"); | 
|  | EVT VT = Op.getValueType(); | 
|  | unsigned VTBits = VT.getSizeInBits(); | 
|  | SDLoc dl(Op); | 
|  | SDValue ShOpLo = Op.getOperand(0); | 
|  | SDValue ShOpHi = Op.getOperand(1); | 
|  | SDValue ShAmt  = Op.getOperand(2); | 
|  | SDValue ARMcc; | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  |  | 
|  | assert(Op.getOpcode() == ISD::SHL_PARTS); | 
|  | SDValue RevShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, | 
|  | DAG.getConstant(VTBits, dl, MVT::i32), ShAmt); | 
|  | SDValue Tmp1 = DAG.getNode(ISD::SRL, dl, VT, ShOpLo, RevShAmt); | 
|  | SDValue Tmp2 = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, ShAmt); | 
|  | SDValue HiSmallShift = DAG.getNode(ISD::OR, dl, VT, Tmp1, Tmp2); | 
|  |  | 
|  | SDValue ExtraShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt, | 
|  | DAG.getConstant(VTBits, dl, MVT::i32)); | 
|  | SDValue HiBigShift = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ExtraShAmt); | 
|  | SDValue CmpHi = getARMCmp(ExtraShAmt, DAG.getConstant(0, dl, MVT::i32), | 
|  | ISD::SETGE, ARMcc, DAG, dl); | 
|  | SDValue Hi = DAG.getNode(ARMISD::CMOV, dl, VT, HiSmallShift, HiBigShift, | 
|  | ARMcc, CCR, CmpHi); | 
|  |  | 
|  | SDValue CmpLo = getARMCmp(ExtraShAmt, DAG.getConstant(0, dl, MVT::i32), | 
|  | ISD::SETGE, ARMcc, DAG, dl); | 
|  | SDValue LoSmallShift = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ShAmt); | 
|  | SDValue Lo = DAG.getNode(ARMISD::CMOV, dl, VT, LoSmallShift, | 
|  | DAG.getConstant(0, dl, VT), ARMcc, CCR, CmpLo); | 
|  |  | 
|  | SDValue Ops[2] = { Lo, Hi }; | 
|  | return DAG.getMergeValues(Ops, dl); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerFLT_ROUNDS_(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | // The rounding mode is in bits 23:22 of the FPSCR. | 
|  | // The ARM rounding mode value to FLT_ROUNDS mapping is 0->1, 1->2, 2->3, 3->0 | 
|  | // The formula we use to implement this is (((FPSCR + 1 << 22) >> 22) & 3) | 
|  | // so that the shift + and get folded into a bitfield extract. | 
|  | SDLoc dl(Op); | 
|  | SDValue Chain = Op.getOperand(0); | 
|  | SDValue Ops[] = {Chain, | 
|  | DAG.getConstant(Intrinsic::arm_get_fpscr, dl, MVT::i32)}; | 
|  |  | 
|  | SDValue FPSCR = | 
|  | DAG.getNode(ISD::INTRINSIC_W_CHAIN, dl, {MVT::i32, MVT::Other}, Ops); | 
|  | Chain = FPSCR.getValue(1); | 
|  | SDValue FltRounds = DAG.getNode(ISD::ADD, dl, MVT::i32, FPSCR, | 
|  | DAG.getConstant(1U << 22, dl, MVT::i32)); | 
|  | SDValue RMODE = DAG.getNode(ISD::SRL, dl, MVT::i32, FltRounds, | 
|  | DAG.getConstant(22, dl, MVT::i32)); | 
|  | SDValue And = DAG.getNode(ISD::AND, dl, MVT::i32, RMODE, | 
|  | DAG.getConstant(3, dl, MVT::i32)); | 
|  | return DAG.getMergeValues({And, Chain}, dl); | 
|  | } | 
|  |  | 
|  | static SDValue LowerCTTZ(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | SDLoc dl(N); | 
|  | EVT VT = N->getValueType(0); | 
|  | if (VT.isVector() && ST->hasNEON()) { | 
|  |  | 
|  | // Compute the least significant set bit: LSB = X & -X | 
|  | SDValue X = N->getOperand(0); | 
|  | SDValue NX = DAG.getNode(ISD::SUB, dl, VT, getZeroVector(VT, DAG, dl), X); | 
|  | SDValue LSB = DAG.getNode(ISD::AND, dl, VT, X, NX); | 
|  |  | 
|  | EVT ElemTy = VT.getVectorElementType(); | 
|  |  | 
|  | if (ElemTy == MVT::i8) { | 
|  | // Compute with: cttz(x) = ctpop(lsb - 1) | 
|  | SDValue One = DAG.getNode(ARMISD::VMOVIMM, dl, VT, | 
|  | DAG.getTargetConstant(1, dl, ElemTy)); | 
|  | SDValue Bits = DAG.getNode(ISD::SUB, dl, VT, LSB, One); | 
|  | return DAG.getNode(ISD::CTPOP, dl, VT, Bits); | 
|  | } | 
|  |  | 
|  | if ((ElemTy == MVT::i16 || ElemTy == MVT::i32) && | 
|  | (N->getOpcode() == ISD::CTTZ_ZERO_UNDEF)) { | 
|  | // Compute with: cttz(x) = (width - 1) - ctlz(lsb), if x != 0 | 
|  | unsigned NumBits = ElemTy.getSizeInBits(); | 
|  | SDValue WidthMinus1 = | 
|  | DAG.getNode(ARMISD::VMOVIMM, dl, VT, | 
|  | DAG.getTargetConstant(NumBits - 1, dl, ElemTy)); | 
|  | SDValue CTLZ = DAG.getNode(ISD::CTLZ, dl, VT, LSB); | 
|  | return DAG.getNode(ISD::SUB, dl, VT, WidthMinus1, CTLZ); | 
|  | } | 
|  |  | 
|  | // Compute with: cttz(x) = ctpop(lsb - 1) | 
|  |  | 
|  | // Compute LSB - 1. | 
|  | SDValue Bits; | 
|  | if (ElemTy == MVT::i64) { | 
|  | // Load constant 0xffff'ffff'ffff'ffff to register. | 
|  | SDValue FF = DAG.getNode(ARMISD::VMOVIMM, dl, VT, | 
|  | DAG.getTargetConstant(0x1eff, dl, MVT::i32)); | 
|  | Bits = DAG.getNode(ISD::ADD, dl, VT, LSB, FF); | 
|  | } else { | 
|  | SDValue One = DAG.getNode(ARMISD::VMOVIMM, dl, VT, | 
|  | DAG.getTargetConstant(1, dl, ElemTy)); | 
|  | Bits = DAG.getNode(ISD::SUB, dl, VT, LSB, One); | 
|  | } | 
|  | return DAG.getNode(ISD::CTPOP, dl, VT, Bits); | 
|  | } | 
|  |  | 
|  | if (!ST->hasV6T2Ops()) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue rbit = DAG.getNode(ISD::BITREVERSE, dl, VT, N->getOperand(0)); | 
|  | return DAG.getNode(ISD::CTLZ, dl, VT, rbit); | 
|  | } | 
|  |  | 
|  | static SDValue LowerCTPOP(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | EVT VT = N->getValueType(0); | 
|  | SDLoc DL(N); | 
|  |  | 
|  | assert(ST->hasNEON() && "Custom ctpop lowering requires NEON."); | 
|  | assert((VT == MVT::v1i64 || VT == MVT::v2i64 || VT == MVT::v2i32 || | 
|  | VT == MVT::v4i32 || VT == MVT::v4i16 || VT == MVT::v8i16) && | 
|  | "Unexpected type for custom ctpop lowering"); | 
|  |  | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | EVT VT8Bit = VT.is64BitVector() ? MVT::v8i8 : MVT::v16i8; | 
|  | SDValue Res = DAG.getBitcast(VT8Bit, N->getOperand(0)); | 
|  | Res = DAG.getNode(ISD::CTPOP, DL, VT8Bit, Res); | 
|  |  | 
|  | // Widen v8i8/v16i8 CTPOP result to VT by repeatedly widening pairwise adds. | 
|  | unsigned EltSize = 8; | 
|  | unsigned NumElts = VT.is64BitVector() ? 8 : 16; | 
|  | while (EltSize != VT.getScalarSizeInBits()) { | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | Ops.push_back(DAG.getConstant(Intrinsic::arm_neon_vpaddlu, DL, | 
|  | TLI.getPointerTy(DAG.getDataLayout()))); | 
|  | Ops.push_back(Res); | 
|  |  | 
|  | EltSize *= 2; | 
|  | NumElts /= 2; | 
|  | MVT WidenVT = MVT::getVectorVT(MVT::getIntegerVT(EltSize), NumElts); | 
|  | Res = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, WidenVT, Ops); | 
|  | } | 
|  |  | 
|  | return Res; | 
|  | } | 
|  |  | 
|  | /// Getvshiftimm - Check if this is a valid build_vector for the immediate | 
|  | /// operand of a vector shift operation, where all the elements of the | 
|  | /// build_vector must have the same constant integer value. | 
|  | static bool getVShiftImm(SDValue Op, unsigned ElementBits, int64_t &Cnt) { | 
|  | // Ignore bit_converts. | 
|  | while (Op.getOpcode() == ISD::BITCAST) | 
|  | Op = Op.getOperand(0); | 
|  | BuildVectorSDNode *BVN = dyn_cast<BuildVectorSDNode>(Op.getNode()); | 
|  | APInt SplatBits, SplatUndef; | 
|  | unsigned SplatBitSize; | 
|  | bool HasAnyUndefs; | 
|  | if (!BVN || | 
|  | !BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs, | 
|  | ElementBits) || | 
|  | SplatBitSize > ElementBits) | 
|  | return false; | 
|  | Cnt = SplatBits.getSExtValue(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// isVShiftLImm - Check if this is a valid build_vector for the immediate | 
|  | /// operand of a vector shift left operation.  That value must be in the range: | 
|  | ///   0 <= Value < ElementBits for a left shift; or | 
|  | ///   0 <= Value <= ElementBits for a long left shift. | 
|  | static bool isVShiftLImm(SDValue Op, EVT VT, bool isLong, int64_t &Cnt) { | 
|  | assert(VT.isVector() && "vector shift count is not a vector type"); | 
|  | int64_t ElementBits = VT.getScalarSizeInBits(); | 
|  | if (!getVShiftImm(Op, ElementBits, Cnt)) | 
|  | return false; | 
|  | return (Cnt >= 0 && (isLong ? Cnt - 1 : Cnt) < ElementBits); | 
|  | } | 
|  |  | 
|  | /// isVShiftRImm - Check if this is a valid build_vector for the immediate | 
|  | /// operand of a vector shift right operation.  For a shift opcode, the value | 
|  | /// is positive, but for an intrinsic the value count must be negative. The | 
|  | /// absolute value must be in the range: | 
|  | ///   1 <= |Value| <= ElementBits for a right shift; or | 
|  | ///   1 <= |Value| <= ElementBits/2 for a narrow right shift. | 
|  | static bool isVShiftRImm(SDValue Op, EVT VT, bool isNarrow, bool isIntrinsic, | 
|  | int64_t &Cnt) { | 
|  | assert(VT.isVector() && "vector shift count is not a vector type"); | 
|  | int64_t ElementBits = VT.getScalarSizeInBits(); | 
|  | if (!getVShiftImm(Op, ElementBits, Cnt)) | 
|  | return false; | 
|  | if (!isIntrinsic) | 
|  | return (Cnt >= 1 && Cnt <= (isNarrow ? ElementBits / 2 : ElementBits)); | 
|  | if (Cnt >= -(isNarrow ? ElementBits / 2 : ElementBits) && Cnt <= -1) { | 
|  | Cnt = -Cnt; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static SDValue LowerShift(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | EVT VT = N->getValueType(0); | 
|  | SDLoc dl(N); | 
|  | int64_t Cnt; | 
|  |  | 
|  | if (!VT.isVector()) | 
|  | return SDValue(); | 
|  |  | 
|  | // We essentially have two forms here. Shift by an immediate and shift by a | 
|  | // vector register (there are also shift by a gpr, but that is just handled | 
|  | // with a tablegen pattern). We cannot easily match shift by an immediate in | 
|  | // tablegen so we do that here and generate a VSHLIMM/VSHRsIMM/VSHRuIMM. | 
|  | // For shifting by a vector, we don't have VSHR, only VSHL (which can be | 
|  | // signed or unsigned, and a negative shift indicates a shift right). | 
|  | if (N->getOpcode() == ISD::SHL) { | 
|  | if (isVShiftLImm(N->getOperand(1), VT, false, Cnt)) | 
|  | return DAG.getNode(ARMISD::VSHLIMM, dl, VT, N->getOperand(0), | 
|  | DAG.getConstant(Cnt, dl, MVT::i32)); | 
|  | return DAG.getNode(ARMISD::VSHLu, dl, VT, N->getOperand(0), | 
|  | N->getOperand(1)); | 
|  | } | 
|  |  | 
|  | assert((N->getOpcode() == ISD::SRA || N->getOpcode() == ISD::SRL) && | 
|  | "unexpected vector shift opcode"); | 
|  |  | 
|  | if (isVShiftRImm(N->getOperand(1), VT, false, false, Cnt)) { | 
|  | unsigned VShiftOpc = | 
|  | (N->getOpcode() == ISD::SRA ? ARMISD::VSHRsIMM : ARMISD::VSHRuIMM); | 
|  | return DAG.getNode(VShiftOpc, dl, VT, N->getOperand(0), | 
|  | DAG.getConstant(Cnt, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | // Other right shifts we don't have operations for (we use a shift left by a | 
|  | // negative number). | 
|  | EVT ShiftVT = N->getOperand(1).getValueType(); | 
|  | SDValue NegatedCount = DAG.getNode( | 
|  | ISD::SUB, dl, ShiftVT, getZeroVector(ShiftVT, DAG, dl), N->getOperand(1)); | 
|  | unsigned VShiftOpc = | 
|  | (N->getOpcode() == ISD::SRA ? ARMISD::VSHLs : ARMISD::VSHLu); | 
|  | return DAG.getNode(VShiftOpc, dl, VT, N->getOperand(0), NegatedCount); | 
|  | } | 
|  |  | 
|  | static SDValue Expand64BitShift(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | EVT VT = N->getValueType(0); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // We can get here for a node like i32 = ISD::SHL i32, i64 | 
|  | if (VT != MVT::i64) | 
|  | return SDValue(); | 
|  |  | 
|  | assert((N->getOpcode() == ISD::SRL || N->getOpcode() == ISD::SRA || | 
|  | N->getOpcode() == ISD::SHL) && | 
|  | "Unknown shift to lower!"); | 
|  |  | 
|  | unsigned ShOpc = N->getOpcode(); | 
|  | if (ST->hasMVEIntegerOps()) { | 
|  | SDValue ShAmt = N->getOperand(1); | 
|  | unsigned ShPartsOpc = ARMISD::LSLL; | 
|  | ConstantSDNode *Con = dyn_cast<ConstantSDNode>(ShAmt); | 
|  |  | 
|  | // If the shift amount is greater than 32 or has a greater bitwidth than 64 | 
|  | // then do the default optimisation | 
|  | if (ShAmt->getValueType(0).getSizeInBits() > 64 || | 
|  | (Con && (Con->getZExtValue() == 0 || Con->getZExtValue() >= 32))) | 
|  | return SDValue(); | 
|  |  | 
|  | // Extract the lower 32 bits of the shift amount if it's not an i32 | 
|  | if (ShAmt->getValueType(0) != MVT::i32) | 
|  | ShAmt = DAG.getZExtOrTrunc(ShAmt, dl, MVT::i32); | 
|  |  | 
|  | if (ShOpc == ISD::SRL) { | 
|  | if (!Con) | 
|  | // There is no t2LSRLr instruction so negate and perform an lsll if the | 
|  | // shift amount is in a register, emulating a right shift. | 
|  | ShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, | 
|  | DAG.getConstant(0, dl, MVT::i32), ShAmt); | 
|  | else | 
|  | // Else generate an lsrl on the immediate shift amount | 
|  | ShPartsOpc = ARMISD::LSRL; | 
|  | } else if (ShOpc == ISD::SRA) | 
|  | ShPartsOpc = ARMISD::ASRL; | 
|  |  | 
|  | // Lower 32 bits of the destination/source | 
|  | SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, N->getOperand(0), | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | // Upper 32 bits of the destination/source | 
|  | SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, N->getOperand(0), | 
|  | DAG.getConstant(1, dl, MVT::i32)); | 
|  |  | 
|  | // Generate the shift operation as computed above | 
|  | Lo = DAG.getNode(ShPartsOpc, dl, DAG.getVTList(MVT::i32, MVT::i32), Lo, Hi, | 
|  | ShAmt); | 
|  | // The upper 32 bits come from the second return value of lsll | 
|  | Hi = SDValue(Lo.getNode(), 1); | 
|  | return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi); | 
|  | } | 
|  |  | 
|  | // We only lower SRA, SRL of 1 here, all others use generic lowering. | 
|  | if (!isOneConstant(N->getOperand(1)) || N->getOpcode() == ISD::SHL) | 
|  | return SDValue(); | 
|  |  | 
|  | // If we are in thumb mode, we don't have RRX. | 
|  | if (ST->isThumb1Only()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Okay, we have a 64-bit SRA or SRL of 1.  Lower this to an RRX expr. | 
|  | SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, N->getOperand(0), | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, N->getOperand(0), | 
|  | DAG.getConstant(1, dl, MVT::i32)); | 
|  |  | 
|  | // First, build a SRA_FLAG/SRL_FLAG op, which shifts the top part by one and | 
|  | // captures the result into a carry flag. | 
|  | unsigned Opc = N->getOpcode() == ISD::SRL ? ARMISD::SRL_FLAG:ARMISD::SRA_FLAG; | 
|  | Hi = DAG.getNode(Opc, dl, DAG.getVTList(MVT::i32, MVT::Glue), Hi); | 
|  |  | 
|  | // The low part is an ARMISD::RRX operand, which shifts the carry in. | 
|  | Lo = DAG.getNode(ARMISD::RRX, dl, MVT::i32, Lo, Hi.getValue(1)); | 
|  |  | 
|  | // Merge the pieces into a single i64 value. | 
|  | return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi); | 
|  | } | 
|  |  | 
|  | static SDValue LowerVSETCC(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | bool Invert = false; | 
|  | bool Swap = false; | 
|  | unsigned Opc = ARMCC::AL; | 
|  |  | 
|  | SDValue Op0 = Op.getOperand(0); | 
|  | SDValue Op1 = Op.getOperand(1); | 
|  | SDValue CC = Op.getOperand(2); | 
|  | EVT VT = Op.getValueType(); | 
|  | ISD::CondCode SetCCOpcode = cast<CondCodeSDNode>(CC)->get(); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | EVT CmpVT; | 
|  | if (ST->hasNEON()) | 
|  | CmpVT = Op0.getValueType().changeVectorElementTypeToInteger(); | 
|  | else { | 
|  | assert(ST->hasMVEIntegerOps() && | 
|  | "No hardware support for integer vector comparison!"); | 
|  |  | 
|  | if (Op.getValueType().getVectorElementType() != MVT::i1) | 
|  | return SDValue(); | 
|  |  | 
|  | // Make sure we expand floating point setcc to scalar if we do not have | 
|  | // mve.fp, so that we can handle them from there. | 
|  | if (Op0.getValueType().isFloatingPoint() && !ST->hasMVEFloatOps()) | 
|  | return SDValue(); | 
|  |  | 
|  | CmpVT = VT; | 
|  | } | 
|  |  | 
|  | if (Op0.getValueType().getVectorElementType() == MVT::i64 && | 
|  | (SetCCOpcode == ISD::SETEQ || SetCCOpcode == ISD::SETNE)) { | 
|  | // Special-case integer 64-bit equality comparisons. They aren't legal, | 
|  | // but they can be lowered with a few vector instructions. | 
|  | unsigned CmpElements = CmpVT.getVectorNumElements() * 2; | 
|  | EVT SplitVT = EVT::getVectorVT(*DAG.getContext(), MVT::i32, CmpElements); | 
|  | SDValue CastOp0 = DAG.getNode(ISD::BITCAST, dl, SplitVT, Op0); | 
|  | SDValue CastOp1 = DAG.getNode(ISD::BITCAST, dl, SplitVT, Op1); | 
|  | SDValue Cmp = DAG.getNode(ISD::SETCC, dl, SplitVT, CastOp0, CastOp1, | 
|  | DAG.getCondCode(ISD::SETEQ)); | 
|  | SDValue Reversed = DAG.getNode(ARMISD::VREV64, dl, SplitVT, Cmp); | 
|  | SDValue Merged = DAG.getNode(ISD::AND, dl, SplitVT, Cmp, Reversed); | 
|  | Merged = DAG.getNode(ISD::BITCAST, dl, CmpVT, Merged); | 
|  | if (SetCCOpcode == ISD::SETNE) | 
|  | Merged = DAG.getNOT(dl, Merged, CmpVT); | 
|  | Merged = DAG.getSExtOrTrunc(Merged, dl, VT); | 
|  | return Merged; | 
|  | } | 
|  |  | 
|  | if (CmpVT.getVectorElementType() == MVT::i64) | 
|  | // 64-bit comparisons are not legal in general. | 
|  | return SDValue(); | 
|  |  | 
|  | if (Op1.getValueType().isFloatingPoint()) { | 
|  | switch (SetCCOpcode) { | 
|  | default: llvm_unreachable("Illegal FP comparison"); | 
|  | case ISD::SETUNE: | 
|  | case ISD::SETNE: | 
|  | if (ST->hasMVEFloatOps()) { | 
|  | Opc = ARMCC::NE; break; | 
|  | } else { | 
|  | Invert = true; LLVM_FALLTHROUGH; | 
|  | } | 
|  | case ISD::SETOEQ: | 
|  | case ISD::SETEQ:  Opc = ARMCC::EQ; break; | 
|  | case ISD::SETOLT: | 
|  | case ISD::SETLT: Swap = true; LLVM_FALLTHROUGH; | 
|  | case ISD::SETOGT: | 
|  | case ISD::SETGT:  Opc = ARMCC::GT; break; | 
|  | case ISD::SETOLE: | 
|  | case ISD::SETLE:  Swap = true; LLVM_FALLTHROUGH; | 
|  | case ISD::SETOGE: | 
|  | case ISD::SETGE: Opc = ARMCC::GE; break; | 
|  | case ISD::SETUGE: Swap = true; LLVM_FALLTHROUGH; | 
|  | case ISD::SETULE: Invert = true; Opc = ARMCC::GT; break; | 
|  | case ISD::SETUGT: Swap = true; LLVM_FALLTHROUGH; | 
|  | case ISD::SETULT: Invert = true; Opc = ARMCC::GE; break; | 
|  | case ISD::SETUEQ: Invert = true; LLVM_FALLTHROUGH; | 
|  | case ISD::SETONE: { | 
|  | // Expand this to (OLT | OGT). | 
|  | SDValue TmpOp0 = DAG.getNode(ARMISD::VCMP, dl, CmpVT, Op1, Op0, | 
|  | DAG.getConstant(ARMCC::GT, dl, MVT::i32)); | 
|  | SDValue TmpOp1 = DAG.getNode(ARMISD::VCMP, dl, CmpVT, Op0, Op1, | 
|  | DAG.getConstant(ARMCC::GT, dl, MVT::i32)); | 
|  | SDValue Result = DAG.getNode(ISD::OR, dl, CmpVT, TmpOp0, TmpOp1); | 
|  | if (Invert) | 
|  | Result = DAG.getNOT(dl, Result, VT); | 
|  | return Result; | 
|  | } | 
|  | case ISD::SETUO: Invert = true; LLVM_FALLTHROUGH; | 
|  | case ISD::SETO: { | 
|  | // Expand this to (OLT | OGE). | 
|  | SDValue TmpOp0 = DAG.getNode(ARMISD::VCMP, dl, CmpVT, Op1, Op0, | 
|  | DAG.getConstant(ARMCC::GT, dl, MVT::i32)); | 
|  | SDValue TmpOp1 = DAG.getNode(ARMISD::VCMP, dl, CmpVT, Op0, Op1, | 
|  | DAG.getConstant(ARMCC::GE, dl, MVT::i32)); | 
|  | SDValue Result = DAG.getNode(ISD::OR, dl, CmpVT, TmpOp0, TmpOp1); | 
|  | if (Invert) | 
|  | Result = DAG.getNOT(dl, Result, VT); | 
|  | return Result; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | // Integer comparisons. | 
|  | switch (SetCCOpcode) { | 
|  | default: llvm_unreachable("Illegal integer comparison"); | 
|  | case ISD::SETNE: | 
|  | if (ST->hasMVEIntegerOps()) { | 
|  | Opc = ARMCC::NE; break; | 
|  | } else { | 
|  | Invert = true; LLVM_FALLTHROUGH; | 
|  | } | 
|  | case ISD::SETEQ:  Opc = ARMCC::EQ; break; | 
|  | case ISD::SETLT:  Swap = true; LLVM_FALLTHROUGH; | 
|  | case ISD::SETGT:  Opc = ARMCC::GT; break; | 
|  | case ISD::SETLE:  Swap = true; LLVM_FALLTHROUGH; | 
|  | case ISD::SETGE:  Opc = ARMCC::GE; break; | 
|  | case ISD::SETULT: Swap = true; LLVM_FALLTHROUGH; | 
|  | case ISD::SETUGT: Opc = ARMCC::HI; break; | 
|  | case ISD::SETULE: Swap = true; LLVM_FALLTHROUGH; | 
|  | case ISD::SETUGE: Opc = ARMCC::HS; break; | 
|  | } | 
|  |  | 
|  | // Detect VTST (Vector Test Bits) = icmp ne (and (op0, op1), zero). | 
|  | if (ST->hasNEON() && Opc == ARMCC::EQ) { | 
|  | SDValue AndOp; | 
|  | if (ISD::isBuildVectorAllZeros(Op1.getNode())) | 
|  | AndOp = Op0; | 
|  | else if (ISD::isBuildVectorAllZeros(Op0.getNode())) | 
|  | AndOp = Op1; | 
|  |  | 
|  | // Ignore bitconvert. | 
|  | if (AndOp.getNode() && AndOp.getOpcode() == ISD::BITCAST) | 
|  | AndOp = AndOp.getOperand(0); | 
|  |  | 
|  | if (AndOp.getNode() && AndOp.getOpcode() == ISD::AND) { | 
|  | Op0 = DAG.getNode(ISD::BITCAST, dl, CmpVT, AndOp.getOperand(0)); | 
|  | Op1 = DAG.getNode(ISD::BITCAST, dl, CmpVT, AndOp.getOperand(1)); | 
|  | SDValue Result = DAG.getNode(ARMISD::VTST, dl, CmpVT, Op0, Op1); | 
|  | if (!Invert) | 
|  | Result = DAG.getNOT(dl, Result, VT); | 
|  | return Result; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Swap) | 
|  | std::swap(Op0, Op1); | 
|  |  | 
|  | // If one of the operands is a constant vector zero, attempt to fold the | 
|  | // comparison to a specialized compare-against-zero form. | 
|  | SDValue SingleOp; | 
|  | if (ISD::isBuildVectorAllZeros(Op1.getNode())) | 
|  | SingleOp = Op0; | 
|  | else if (ISD::isBuildVectorAllZeros(Op0.getNode())) { | 
|  | if (Opc == ARMCC::GE) | 
|  | Opc = ARMCC::LE; | 
|  | else if (Opc == ARMCC::GT) | 
|  | Opc = ARMCC::LT; | 
|  | SingleOp = Op1; | 
|  | } | 
|  |  | 
|  | SDValue Result; | 
|  | if (SingleOp.getNode()) { | 
|  | Result = DAG.getNode(ARMISD::VCMPZ, dl, CmpVT, SingleOp, | 
|  | DAG.getConstant(Opc, dl, MVT::i32)); | 
|  | } else { | 
|  | Result = DAG.getNode(ARMISD::VCMP, dl, CmpVT, Op0, Op1, | 
|  | DAG.getConstant(Opc, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | Result = DAG.getSExtOrTrunc(Result, dl, VT); | 
|  |  | 
|  | if (Invert) | 
|  | Result = DAG.getNOT(dl, Result, VT); | 
|  |  | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | static SDValue LowerSETCCCARRY(SDValue Op, SelectionDAG &DAG) { | 
|  | SDValue LHS = Op.getOperand(0); | 
|  | SDValue RHS = Op.getOperand(1); | 
|  | SDValue Carry = Op.getOperand(2); | 
|  | SDValue Cond = Op.getOperand(3); | 
|  | SDLoc DL(Op); | 
|  |  | 
|  | assert(LHS.getSimpleValueType().isInteger() && "SETCCCARRY is integer only."); | 
|  |  | 
|  | // ARMISD::SUBE expects a carry not a borrow like ISD::SUBCARRY so we | 
|  | // have to invert the carry first. | 
|  | Carry = DAG.getNode(ISD::SUB, DL, MVT::i32, | 
|  | DAG.getConstant(1, DL, MVT::i32), Carry); | 
|  | // This converts the boolean value carry into the carry flag. | 
|  | Carry = ConvertBooleanCarryToCarryFlag(Carry, DAG); | 
|  |  | 
|  | SDVTList VTs = DAG.getVTList(LHS.getValueType(), MVT::i32); | 
|  | SDValue Cmp = DAG.getNode(ARMISD::SUBE, DL, VTs, LHS, RHS, Carry); | 
|  |  | 
|  | SDValue FVal = DAG.getConstant(0, DL, MVT::i32); | 
|  | SDValue TVal = DAG.getConstant(1, DL, MVT::i32); | 
|  | SDValue ARMcc = DAG.getConstant( | 
|  | IntCCToARMCC(cast<CondCodeSDNode>(Cond)->get()), DL, MVT::i32); | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  | SDValue Chain = DAG.getCopyToReg(DAG.getEntryNode(), DL, ARM::CPSR, | 
|  | Cmp.getValue(1), SDValue()); | 
|  | return DAG.getNode(ARMISD::CMOV, DL, Op.getValueType(), FVal, TVal, ARMcc, | 
|  | CCR, Chain.getValue(1)); | 
|  | } | 
|  |  | 
|  | /// isVMOVModifiedImm - Check if the specified splat value corresponds to a | 
|  | /// valid vector constant for a NEON or MVE instruction with a "modified | 
|  | /// immediate" operand (e.g., VMOV).  If so, return the encoded value. | 
|  | static SDValue isVMOVModifiedImm(uint64_t SplatBits, uint64_t SplatUndef, | 
|  | unsigned SplatBitSize, SelectionDAG &DAG, | 
|  | const SDLoc &dl, EVT &VT, EVT VectorVT, | 
|  | VMOVModImmType type) { | 
|  | unsigned OpCmode, Imm; | 
|  | bool is128Bits = VectorVT.is128BitVector(); | 
|  |  | 
|  | // SplatBitSize is set to the smallest size that splats the vector, so a | 
|  | // zero vector will always have SplatBitSize == 8.  However, NEON modified | 
|  | // immediate instructions others than VMOV do not support the 8-bit encoding | 
|  | // of a zero vector, and the default encoding of zero is supposed to be the | 
|  | // 32-bit version. | 
|  | if (SplatBits == 0) | 
|  | SplatBitSize = 32; | 
|  |  | 
|  | switch (SplatBitSize) { | 
|  | case 8: | 
|  | if (type != VMOVModImm) | 
|  | return SDValue(); | 
|  | // Any 1-byte value is OK.  Op=0, Cmode=1110. | 
|  | assert((SplatBits & ~0xff) == 0 && "one byte splat value is too big"); | 
|  | OpCmode = 0xe; | 
|  | Imm = SplatBits; | 
|  | VT = is128Bits ? MVT::v16i8 : MVT::v8i8; | 
|  | break; | 
|  |  | 
|  | case 16: | 
|  | // NEON's 16-bit VMOV supports splat values where only one byte is nonzero. | 
|  | VT = is128Bits ? MVT::v8i16 : MVT::v4i16; | 
|  | if ((SplatBits & ~0xff) == 0) { | 
|  | // Value = 0x00nn: Op=x, Cmode=100x. | 
|  | OpCmode = 0x8; | 
|  | Imm = SplatBits; | 
|  | break; | 
|  | } | 
|  | if ((SplatBits & ~0xff00) == 0) { | 
|  | // Value = 0xnn00: Op=x, Cmode=101x. | 
|  | OpCmode = 0xa; | 
|  | Imm = SplatBits >> 8; | 
|  | break; | 
|  | } | 
|  | return SDValue(); | 
|  |  | 
|  | case 32: | 
|  | // NEON's 32-bit VMOV supports splat values where: | 
|  | // * only one byte is nonzero, or | 
|  | // * the least significant byte is 0xff and the second byte is nonzero, or | 
|  | // * the least significant 2 bytes are 0xff and the third is nonzero. | 
|  | VT = is128Bits ? MVT::v4i32 : MVT::v2i32; | 
|  | if ((SplatBits & ~0xff) == 0) { | 
|  | // Value = 0x000000nn: Op=x, Cmode=000x. | 
|  | OpCmode = 0; | 
|  | Imm = SplatBits; | 
|  | break; | 
|  | } | 
|  | if ((SplatBits & ~0xff00) == 0) { | 
|  | // Value = 0x0000nn00: Op=x, Cmode=001x. | 
|  | OpCmode = 0x2; | 
|  | Imm = SplatBits >> 8; | 
|  | break; | 
|  | } | 
|  | if ((SplatBits & ~0xff0000) == 0) { | 
|  | // Value = 0x00nn0000: Op=x, Cmode=010x. | 
|  | OpCmode = 0x4; | 
|  | Imm = SplatBits >> 16; | 
|  | break; | 
|  | } | 
|  | if ((SplatBits & ~0xff000000) == 0) { | 
|  | // Value = 0xnn000000: Op=x, Cmode=011x. | 
|  | OpCmode = 0x6; | 
|  | Imm = SplatBits >> 24; | 
|  | break; | 
|  | } | 
|  |  | 
|  | // cmode == 0b1100 and cmode == 0b1101 are not supported for VORR or VBIC | 
|  | if (type == OtherModImm) return SDValue(); | 
|  |  | 
|  | if ((SplatBits & ~0xffff) == 0 && | 
|  | ((SplatBits | SplatUndef) & 0xff) == 0xff) { | 
|  | // Value = 0x0000nnff: Op=x, Cmode=1100. | 
|  | OpCmode = 0xc; | 
|  | Imm = SplatBits >> 8; | 
|  | break; | 
|  | } | 
|  |  | 
|  | // cmode == 0b1101 is not supported for MVE VMVN | 
|  | if (type == MVEVMVNModImm) | 
|  | return SDValue(); | 
|  |  | 
|  | if ((SplatBits & ~0xffffff) == 0 && | 
|  | ((SplatBits | SplatUndef) & 0xffff) == 0xffff) { | 
|  | // Value = 0x00nnffff: Op=x, Cmode=1101. | 
|  | OpCmode = 0xd; | 
|  | Imm = SplatBits >> 16; | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Note: there are a few 32-bit splat values (specifically: 00ffff00, | 
|  | // ff000000, ff0000ff, and ffff00ff) that are valid for VMOV.I64 but not | 
|  | // VMOV.I32.  A (very) minor optimization would be to replicate the value | 
|  | // and fall through here to test for a valid 64-bit splat.  But, then the | 
|  | // caller would also need to check and handle the change in size. | 
|  | return SDValue(); | 
|  |  | 
|  | case 64: { | 
|  | if (type != VMOVModImm) | 
|  | return SDValue(); | 
|  | // NEON has a 64-bit VMOV splat where each byte is either 0 or 0xff. | 
|  | uint64_t BitMask = 0xff; | 
|  | uint64_t Val = 0; | 
|  | unsigned ImmMask = 1; | 
|  | Imm = 0; | 
|  | for (int ByteNum = 0; ByteNum < 8; ++ByteNum) { | 
|  | if (((SplatBits | SplatUndef) & BitMask) == BitMask) { | 
|  | Val |= BitMask; | 
|  | Imm |= ImmMask; | 
|  | } else if ((SplatBits & BitMask) != 0) { | 
|  | return SDValue(); | 
|  | } | 
|  | BitMask <<= 8; | 
|  | ImmMask <<= 1; | 
|  | } | 
|  |  | 
|  | if (DAG.getDataLayout().isBigEndian()) { | 
|  | // Reverse the order of elements within the vector. | 
|  | unsigned BytesPerElem = VectorVT.getScalarSizeInBits() / 8; | 
|  | unsigned Mask = (1 << BytesPerElem) - 1; | 
|  | unsigned NumElems = 8 / BytesPerElem; | 
|  | unsigned NewImm = 0; | 
|  | for (unsigned ElemNum = 0; ElemNum < NumElems; ++ElemNum) { | 
|  | unsigned Elem = ((Imm >> ElemNum * BytesPerElem) & Mask); | 
|  | NewImm |= Elem << (NumElems - ElemNum - 1) * BytesPerElem; | 
|  | } | 
|  | Imm = NewImm; | 
|  | } | 
|  |  | 
|  | // Op=1, Cmode=1110. | 
|  | OpCmode = 0x1e; | 
|  | VT = is128Bits ? MVT::v2i64 : MVT::v1i64; | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | llvm_unreachable("unexpected size for isVMOVModifiedImm"); | 
|  | } | 
|  |  | 
|  | unsigned EncodedVal = ARM_AM::createVMOVModImm(OpCmode, Imm); | 
|  | return DAG.getTargetConstant(EncodedVal, dl, MVT::i32); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerConstantFP(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) const { | 
|  | EVT VT = Op.getValueType(); | 
|  | bool IsDouble = (VT == MVT::f64); | 
|  | ConstantFPSDNode *CFP = cast<ConstantFPSDNode>(Op); | 
|  | const APFloat &FPVal = CFP->getValueAPF(); | 
|  |  | 
|  | // Prevent floating-point constants from using literal loads | 
|  | // when execute-only is enabled. | 
|  | if (ST->genExecuteOnly()) { | 
|  | // If we can represent the constant as an immediate, don't lower it | 
|  | if (isFPImmLegal(FPVal, VT)) | 
|  | return Op; | 
|  | // Otherwise, construct as integer, and move to float register | 
|  | APInt INTVal = FPVal.bitcastToAPInt(); | 
|  | SDLoc DL(CFP); | 
|  | switch (VT.getSimpleVT().SimpleTy) { | 
|  | default: | 
|  | llvm_unreachable("Unknown floating point type!"); | 
|  | break; | 
|  | case MVT::f64: { | 
|  | SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32); | 
|  | SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32); | 
|  | return DAG.getNode(ARMISD::VMOVDRR, DL, MVT::f64, Lo, Hi); | 
|  | } | 
|  | case MVT::f32: | 
|  | return DAG.getNode(ARMISD::VMOVSR, DL, VT, | 
|  | DAG.getConstant(INTVal, DL, MVT::i32)); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!ST->hasVFP3Base()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Use the default (constant pool) lowering for double constants when we have | 
|  | // an SP-only FPU | 
|  | if (IsDouble && !Subtarget->hasFP64()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Try splatting with a VMOV.f32... | 
|  | int ImmVal = IsDouble ? ARM_AM::getFP64Imm(FPVal) : ARM_AM::getFP32Imm(FPVal); | 
|  |  | 
|  | if (ImmVal != -1) { | 
|  | if (IsDouble || !ST->useNEONForSinglePrecisionFP()) { | 
|  | // We have code in place to select a valid ConstantFP already, no need to | 
|  | // do any mangling. | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | // It's a float and we are trying to use NEON operations where | 
|  | // possible. Lower it to a splat followed by an extract. | 
|  | SDLoc DL(Op); | 
|  | SDValue NewVal = DAG.getTargetConstant(ImmVal, DL, MVT::i32); | 
|  | SDValue VecConstant = DAG.getNode(ARMISD::VMOVFPIMM, DL, MVT::v2f32, | 
|  | NewVal); | 
|  | return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, VecConstant, | 
|  | DAG.getConstant(0, DL, MVT::i32)); | 
|  | } | 
|  |  | 
|  | // The rest of our options are NEON only, make sure that's allowed before | 
|  | // proceeding.. | 
|  | if (!ST->hasNEON() || (!IsDouble && !ST->useNEONForSinglePrecisionFP())) | 
|  | return SDValue(); | 
|  |  | 
|  | EVT VMovVT; | 
|  | uint64_t iVal = FPVal.bitcastToAPInt().getZExtValue(); | 
|  |  | 
|  | // It wouldn't really be worth bothering for doubles except for one very | 
|  | // important value, which does happen to match: 0.0. So make sure we don't do | 
|  | // anything stupid. | 
|  | if (IsDouble && (iVal & 0xffffffff) != (iVal >> 32)) | 
|  | return SDValue(); | 
|  |  | 
|  | // Try a VMOV.i32 (FIXME: i8, i16, or i64 could work too). | 
|  | SDValue NewVal = isVMOVModifiedImm(iVal & 0xffffffffU, 0, 32, DAG, SDLoc(Op), | 
|  | VMovVT, VT, VMOVModImm); | 
|  | if (NewVal != SDValue()) { | 
|  | SDLoc DL(Op); | 
|  | SDValue VecConstant = DAG.getNode(ARMISD::VMOVIMM, DL, VMovVT, | 
|  | NewVal); | 
|  | if (IsDouble) | 
|  | return DAG.getNode(ISD::BITCAST, DL, MVT::f64, VecConstant); | 
|  |  | 
|  | // It's a float: cast and extract a vector element. | 
|  | SDValue VecFConstant = DAG.getNode(ISD::BITCAST, DL, MVT::v2f32, | 
|  | VecConstant); | 
|  | return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, VecFConstant, | 
|  | DAG.getConstant(0, DL, MVT::i32)); | 
|  | } | 
|  |  | 
|  | // Finally, try a VMVN.i32 | 
|  | NewVal = isVMOVModifiedImm(~iVal & 0xffffffffU, 0, 32, DAG, SDLoc(Op), VMovVT, | 
|  | VT, VMVNModImm); | 
|  | if (NewVal != SDValue()) { | 
|  | SDLoc DL(Op); | 
|  | SDValue VecConstant = DAG.getNode(ARMISD::VMVNIMM, DL, VMovVT, NewVal); | 
|  |  | 
|  | if (IsDouble) | 
|  | return DAG.getNode(ISD::BITCAST, DL, MVT::f64, VecConstant); | 
|  |  | 
|  | // It's a float: cast and extract a vector element. | 
|  | SDValue VecFConstant = DAG.getNode(ISD::BITCAST, DL, MVT::v2f32, | 
|  | VecConstant); | 
|  | return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, MVT::f32, VecFConstant, | 
|  | DAG.getConstant(0, DL, MVT::i32)); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // check if an VEXT instruction can handle the shuffle mask when the | 
|  | // vector sources of the shuffle are the same. | 
|  | static bool isSingletonVEXTMask(ArrayRef<int> M, EVT VT, unsigned &Imm) { | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  |  | 
|  | // Assume that the first shuffle index is not UNDEF.  Fail if it is. | 
|  | if (M[0] < 0) | 
|  | return false; | 
|  |  | 
|  | Imm = M[0]; | 
|  |  | 
|  | // If this is a VEXT shuffle, the immediate value is the index of the first | 
|  | // element.  The other shuffle indices must be the successive elements after | 
|  | // the first one. | 
|  | unsigned ExpectedElt = Imm; | 
|  | for (unsigned i = 1; i < NumElts; ++i) { | 
|  | // Increment the expected index.  If it wraps around, just follow it | 
|  | // back to index zero and keep going. | 
|  | ++ExpectedElt; | 
|  | if (ExpectedElt == NumElts) | 
|  | ExpectedElt = 0; | 
|  |  | 
|  | if (M[i] < 0) continue; // ignore UNDEF indices | 
|  | if (ExpectedElt != static_cast<unsigned>(M[i])) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool isVEXTMask(ArrayRef<int> M, EVT VT, | 
|  | bool &ReverseVEXT, unsigned &Imm) { | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | ReverseVEXT = false; | 
|  |  | 
|  | // Assume that the first shuffle index is not UNDEF.  Fail if it is. | 
|  | if (M[0] < 0) | 
|  | return false; | 
|  |  | 
|  | Imm = M[0]; | 
|  |  | 
|  | // If this is a VEXT shuffle, the immediate value is the index of the first | 
|  | // element.  The other shuffle indices must be the successive elements after | 
|  | // the first one. | 
|  | unsigned ExpectedElt = Imm; | 
|  | for (unsigned i = 1; i < NumElts; ++i) { | 
|  | // Increment the expected index.  If it wraps around, it may still be | 
|  | // a VEXT but the source vectors must be swapped. | 
|  | ExpectedElt += 1; | 
|  | if (ExpectedElt == NumElts * 2) { | 
|  | ExpectedElt = 0; | 
|  | ReverseVEXT = true; | 
|  | } | 
|  |  | 
|  | if (M[i] < 0) continue; // ignore UNDEF indices | 
|  | if (ExpectedElt != static_cast<unsigned>(M[i])) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Adjust the index value if the source operands will be swapped. | 
|  | if (ReverseVEXT) | 
|  | Imm -= NumElts; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// isVREVMask - Check if a vector shuffle corresponds to a VREV | 
|  | /// instruction with the specified blocksize.  (The order of the elements | 
|  | /// within each block of the vector is reversed.) | 
|  | static bool isVREVMask(ArrayRef<int> M, EVT VT, unsigned BlockSize) { | 
|  | assert((BlockSize==16 || BlockSize==32 || BlockSize==64) && | 
|  | "Only possible block sizes for VREV are: 16, 32, 64"); | 
|  |  | 
|  | unsigned EltSz = VT.getScalarSizeInBits(); | 
|  | if (EltSz == 64) | 
|  | return false; | 
|  |  | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | unsigned BlockElts = M[0] + 1; | 
|  | // If the first shuffle index is UNDEF, be optimistic. | 
|  | if (M[0] < 0) | 
|  | BlockElts = BlockSize / EltSz; | 
|  |  | 
|  | if (BlockSize <= EltSz || BlockSize != BlockElts * EltSz) | 
|  | return false; | 
|  |  | 
|  | for (unsigned i = 0; i < NumElts; ++i) { | 
|  | if (M[i] < 0) continue; // ignore UNDEF indices | 
|  | if ((unsigned) M[i] != (i - i%BlockElts) + (BlockElts - 1 - i%BlockElts)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool isVTBLMask(ArrayRef<int> M, EVT VT) { | 
|  | // We can handle <8 x i8> vector shuffles. If the index in the mask is out of | 
|  | // range, then 0 is placed into the resulting vector. So pretty much any mask | 
|  | // of 8 elements can work here. | 
|  | return VT == MVT::v8i8 && M.size() == 8; | 
|  | } | 
|  |  | 
|  | static unsigned SelectPairHalf(unsigned Elements, ArrayRef<int> Mask, | 
|  | unsigned Index) { | 
|  | if (Mask.size() == Elements * 2) | 
|  | return Index / Elements; | 
|  | return Mask[Index] == 0 ? 0 : 1; | 
|  | } | 
|  |  | 
|  | // Checks whether the shuffle mask represents a vector transpose (VTRN) by | 
|  | // checking that pairs of elements in the shuffle mask represent the same index | 
|  | // in each vector, incrementing the expected index by 2 at each step. | 
|  | // e.g. For v1,v2 of type v4i32 a valid shuffle mask is: [0, 4, 2, 6] | 
|  | //  v1={a,b,c,d} => x=shufflevector v1, v2 shufflemask => x={a,e,c,g} | 
|  | //  v2={e,f,g,h} | 
|  | // WhichResult gives the offset for each element in the mask based on which | 
|  | // of the two results it belongs to. | 
|  | // | 
|  | // The transpose can be represented either as: | 
|  | // result1 = shufflevector v1, v2, result1_shuffle_mask | 
|  | // result2 = shufflevector v1, v2, result2_shuffle_mask | 
|  | // where v1/v2 and the shuffle masks have the same number of elements | 
|  | // (here WhichResult (see below) indicates which result is being checked) | 
|  | // | 
|  | // or as: | 
|  | // results = shufflevector v1, v2, shuffle_mask | 
|  | // where both results are returned in one vector and the shuffle mask has twice | 
|  | // as many elements as v1/v2 (here WhichResult will always be 0 if true) here we | 
|  | // want to check the low half and high half of the shuffle mask as if it were | 
|  | // the other case | 
|  | static bool isVTRNMask(ArrayRef<int> M, EVT VT, unsigned &WhichResult) { | 
|  | unsigned EltSz = VT.getScalarSizeInBits(); | 
|  | if (EltSz == 64) | 
|  | return false; | 
|  |  | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | if (M.size() != NumElts && M.size() != NumElts*2) | 
|  | return false; | 
|  |  | 
|  | // If the mask is twice as long as the input vector then we need to check the | 
|  | // upper and lower parts of the mask with a matching value for WhichResult | 
|  | // FIXME: A mask with only even values will be rejected in case the first | 
|  | // element is undefined, e.g. [-1, 4, 2, 6] will be rejected, because only | 
|  | // M[0] is used to determine WhichResult | 
|  | for (unsigned i = 0; i < M.size(); i += NumElts) { | 
|  | WhichResult = SelectPairHalf(NumElts, M, i); | 
|  | for (unsigned j = 0; j < NumElts; j += 2) { | 
|  | if ((M[i+j] >= 0 && (unsigned) M[i+j] != j + WhichResult) || | 
|  | (M[i+j+1] >= 0 && (unsigned) M[i+j+1] != j + NumElts + WhichResult)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (M.size() == NumElts*2) | 
|  | WhichResult = 0; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// isVTRN_v_undef_Mask - Special case of isVTRNMask for canonical form of | 
|  | /// "vector_shuffle v, v", i.e., "vector_shuffle v, undef". | 
|  | /// Mask is e.g., <0, 0, 2, 2> instead of <0, 4, 2, 6>. | 
|  | static bool isVTRN_v_undef_Mask(ArrayRef<int> M, EVT VT, unsigned &WhichResult){ | 
|  | unsigned EltSz = VT.getScalarSizeInBits(); | 
|  | if (EltSz == 64) | 
|  | return false; | 
|  |  | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | if (M.size() != NumElts && M.size() != NumElts*2) | 
|  | return false; | 
|  |  | 
|  | for (unsigned i = 0; i < M.size(); i += NumElts) { | 
|  | WhichResult = SelectPairHalf(NumElts, M, i); | 
|  | for (unsigned j = 0; j < NumElts; j += 2) { | 
|  | if ((M[i+j] >= 0 && (unsigned) M[i+j] != j + WhichResult) || | 
|  | (M[i+j+1] >= 0 && (unsigned) M[i+j+1] != j + WhichResult)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (M.size() == NumElts*2) | 
|  | WhichResult = 0; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Checks whether the shuffle mask represents a vector unzip (VUZP) by checking | 
|  | // that the mask elements are either all even and in steps of size 2 or all odd | 
|  | // and in steps of size 2. | 
|  | // e.g. For v1,v2 of type v4i32 a valid shuffle mask is: [0, 2, 4, 6] | 
|  | //  v1={a,b,c,d} => x=shufflevector v1, v2 shufflemask => x={a,c,e,g} | 
|  | //  v2={e,f,g,h} | 
|  | // Requires similar checks to that of isVTRNMask with | 
|  | // respect the how results are returned. | 
|  | static bool isVUZPMask(ArrayRef<int> M, EVT VT, unsigned &WhichResult) { | 
|  | unsigned EltSz = VT.getScalarSizeInBits(); | 
|  | if (EltSz == 64) | 
|  | return false; | 
|  |  | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | if (M.size() != NumElts && M.size() != NumElts*2) | 
|  | return false; | 
|  |  | 
|  | for (unsigned i = 0; i < M.size(); i += NumElts) { | 
|  | WhichResult = SelectPairHalf(NumElts, M, i); | 
|  | for (unsigned j = 0; j < NumElts; ++j) { | 
|  | if (M[i+j] >= 0 && (unsigned) M[i+j] != 2 * j + WhichResult) | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (M.size() == NumElts*2) | 
|  | WhichResult = 0; | 
|  |  | 
|  | // VUZP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. | 
|  | if (VT.is64BitVector() && EltSz == 32) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// isVUZP_v_undef_Mask - Special case of isVUZPMask for canonical form of | 
|  | /// "vector_shuffle v, v", i.e., "vector_shuffle v, undef". | 
|  | /// Mask is e.g., <0, 2, 0, 2> instead of <0, 2, 4, 6>, | 
|  | static bool isVUZP_v_undef_Mask(ArrayRef<int> M, EVT VT, unsigned &WhichResult){ | 
|  | unsigned EltSz = VT.getScalarSizeInBits(); | 
|  | if (EltSz == 64) | 
|  | return false; | 
|  |  | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | if (M.size() != NumElts && M.size() != NumElts*2) | 
|  | return false; | 
|  |  | 
|  | unsigned Half = NumElts / 2; | 
|  | for (unsigned i = 0; i < M.size(); i += NumElts) { | 
|  | WhichResult = SelectPairHalf(NumElts, M, i); | 
|  | for (unsigned j = 0; j < NumElts; j += Half) { | 
|  | unsigned Idx = WhichResult; | 
|  | for (unsigned k = 0; k < Half; ++k) { | 
|  | int MIdx = M[i + j + k]; | 
|  | if (MIdx >= 0 && (unsigned) MIdx != Idx) | 
|  | return false; | 
|  | Idx += 2; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (M.size() == NumElts*2) | 
|  | WhichResult = 0; | 
|  |  | 
|  | // VUZP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. | 
|  | if (VT.is64BitVector() && EltSz == 32) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Checks whether the shuffle mask represents a vector zip (VZIP) by checking | 
|  | // that pairs of elements of the shufflemask represent the same index in each | 
|  | // vector incrementing sequentially through the vectors. | 
|  | // e.g. For v1,v2 of type v4i32 a valid shuffle mask is: [0, 4, 1, 5] | 
|  | //  v1={a,b,c,d} => x=shufflevector v1, v2 shufflemask => x={a,e,b,f} | 
|  | //  v2={e,f,g,h} | 
|  | // Requires similar checks to that of isVTRNMask with respect the how results | 
|  | // are returned. | 
|  | static bool isVZIPMask(ArrayRef<int> M, EVT VT, unsigned &WhichResult) { | 
|  | unsigned EltSz = VT.getScalarSizeInBits(); | 
|  | if (EltSz == 64) | 
|  | return false; | 
|  |  | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | if (M.size() != NumElts && M.size() != NumElts*2) | 
|  | return false; | 
|  |  | 
|  | for (unsigned i = 0; i < M.size(); i += NumElts) { | 
|  | WhichResult = SelectPairHalf(NumElts, M, i); | 
|  | unsigned Idx = WhichResult * NumElts / 2; | 
|  | for (unsigned j = 0; j < NumElts; j += 2) { | 
|  | if ((M[i+j] >= 0 && (unsigned) M[i+j] != Idx) || | 
|  | (M[i+j+1] >= 0 && (unsigned) M[i+j+1] != Idx + NumElts)) | 
|  | return false; | 
|  | Idx += 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (M.size() == NumElts*2) | 
|  | WhichResult = 0; | 
|  |  | 
|  | // VZIP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. | 
|  | if (VT.is64BitVector() && EltSz == 32) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// isVZIP_v_undef_Mask - Special case of isVZIPMask for canonical form of | 
|  | /// "vector_shuffle v, v", i.e., "vector_shuffle v, undef". | 
|  | /// Mask is e.g., <0, 0, 1, 1> instead of <0, 4, 1, 5>. | 
|  | static bool isVZIP_v_undef_Mask(ArrayRef<int> M, EVT VT, unsigned &WhichResult){ | 
|  | unsigned EltSz = VT.getScalarSizeInBits(); | 
|  | if (EltSz == 64) | 
|  | return false; | 
|  |  | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | if (M.size() != NumElts && M.size() != NumElts*2) | 
|  | return false; | 
|  |  | 
|  | for (unsigned i = 0; i < M.size(); i += NumElts) { | 
|  | WhichResult = SelectPairHalf(NumElts, M, i); | 
|  | unsigned Idx = WhichResult * NumElts / 2; | 
|  | for (unsigned j = 0; j < NumElts; j += 2) { | 
|  | if ((M[i+j] >= 0 && (unsigned) M[i+j] != Idx) || | 
|  | (M[i+j+1] >= 0 && (unsigned) M[i+j+1] != Idx)) | 
|  | return false; | 
|  | Idx += 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (M.size() == NumElts*2) | 
|  | WhichResult = 0; | 
|  |  | 
|  | // VZIP.32 for 64-bit vectors is a pseudo-instruction alias for VTRN.32. | 
|  | if (VT.is64BitVector() && EltSz == 32) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// Check if \p ShuffleMask is a NEON two-result shuffle (VZIP, VUZP, VTRN), | 
|  | /// and return the corresponding ARMISD opcode if it is, or 0 if it isn't. | 
|  | static unsigned isNEONTwoResultShuffleMask(ArrayRef<int> ShuffleMask, EVT VT, | 
|  | unsigned &WhichResult, | 
|  | bool &isV_UNDEF) { | 
|  | isV_UNDEF = false; | 
|  | if (isVTRNMask(ShuffleMask, VT, WhichResult)) | 
|  | return ARMISD::VTRN; | 
|  | if (isVUZPMask(ShuffleMask, VT, WhichResult)) | 
|  | return ARMISD::VUZP; | 
|  | if (isVZIPMask(ShuffleMask, VT, WhichResult)) | 
|  | return ARMISD::VZIP; | 
|  |  | 
|  | isV_UNDEF = true; | 
|  | if (isVTRN_v_undef_Mask(ShuffleMask, VT, WhichResult)) | 
|  | return ARMISD::VTRN; | 
|  | if (isVUZP_v_undef_Mask(ShuffleMask, VT, WhichResult)) | 
|  | return ARMISD::VUZP; | 
|  | if (isVZIP_v_undef_Mask(ShuffleMask, VT, WhichResult)) | 
|  | return ARMISD::VZIP; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /// \return true if this is a reverse operation on an vector. | 
|  | static bool isReverseMask(ArrayRef<int> M, EVT VT) { | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | // Make sure the mask has the right size. | 
|  | if (NumElts != M.size()) | 
|  | return false; | 
|  |  | 
|  | // Look for <15, ..., 3, -1, 1, 0>. | 
|  | for (unsigned i = 0; i != NumElts; ++i) | 
|  | if (M[i] >= 0 && M[i] != (int) (NumElts - 1 - i)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool isVMOVNMask(ArrayRef<int> M, EVT VT, bool Top) { | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | // Make sure the mask has the right size. | 
|  | if (NumElts != M.size() || (VT != MVT::v8i16 && VT != MVT::v16i8)) | 
|  | return false; | 
|  |  | 
|  | // If Top | 
|  | //   Look for <0, N, 2, N+2, 4, N+4, ..>. | 
|  | //   This inserts Input2 into Input1 | 
|  | // else if not Top | 
|  | //   Look for <0, N+1, 2, N+3, 4, N+5, ..> | 
|  | //   This inserts Input1 into Input2 | 
|  | unsigned Offset = Top ? 0 : 1; | 
|  | for (unsigned i = 0; i < NumElts; i+=2) { | 
|  | if (M[i] >= 0 && M[i] != (int)i) | 
|  | return false; | 
|  | if (M[i+1] >= 0 && M[i+1] != (int)(NumElts + i + Offset)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // If N is an integer constant that can be moved into a register in one | 
|  | // instruction, return an SDValue of such a constant (will become a MOV | 
|  | // instruction).  Otherwise return null. | 
|  | static SDValue IsSingleInstrConstant(SDValue N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST, const SDLoc &dl) { | 
|  | uint64_t Val; | 
|  | if (!isa<ConstantSDNode>(N)) | 
|  | return SDValue(); | 
|  | Val = cast<ConstantSDNode>(N)->getZExtValue(); | 
|  |  | 
|  | if (ST->isThumb1Only()) { | 
|  | if (Val <= 255 || ~Val <= 255) | 
|  | return DAG.getConstant(Val, dl, MVT::i32); | 
|  | } else { | 
|  | if (ARM_AM::getSOImmVal(Val) != -1 || ARM_AM::getSOImmVal(~Val) != -1) | 
|  | return DAG.getConstant(Val, dl, MVT::i32); | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue LowerBUILD_VECTOR_i1(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | SDLoc dl(Op); | 
|  | EVT VT = Op.getValueType(); | 
|  |  | 
|  | assert(ST->hasMVEIntegerOps() && "LowerBUILD_VECTOR_i1 called without MVE!"); | 
|  |  | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | unsigned BoolMask; | 
|  | unsigned BitsPerBool; | 
|  | if (NumElts == 4) { | 
|  | BitsPerBool = 4; | 
|  | BoolMask = 0xf; | 
|  | } else if (NumElts == 8) { | 
|  | BitsPerBool = 2; | 
|  | BoolMask = 0x3; | 
|  | } else if (NumElts == 16) { | 
|  | BitsPerBool = 1; | 
|  | BoolMask = 0x1; | 
|  | } else | 
|  | return SDValue(); | 
|  |  | 
|  | // If this is a single value copied into all lanes (a splat), we can just sign | 
|  | // extend that single value | 
|  | SDValue FirstOp = Op.getOperand(0); | 
|  | if (!isa<ConstantSDNode>(FirstOp) && | 
|  | std::all_of(std::next(Op->op_begin()), Op->op_end(), | 
|  | [&FirstOp](SDUse &U) { | 
|  | return U.get().isUndef() || U.get() == FirstOp; | 
|  | })) { | 
|  | SDValue Ext = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, MVT::i32, FirstOp, | 
|  | DAG.getValueType(MVT::i1)); | 
|  | return DAG.getNode(ARMISD::PREDICATE_CAST, dl, Op.getValueType(), Ext); | 
|  | } | 
|  |  | 
|  | // First create base with bits set where known | 
|  | unsigned Bits32 = 0; | 
|  | for (unsigned i = 0; i < NumElts; ++i) { | 
|  | SDValue V = Op.getOperand(i); | 
|  | if (!isa<ConstantSDNode>(V) && !V.isUndef()) | 
|  | continue; | 
|  | bool BitSet = V.isUndef() ? false : cast<ConstantSDNode>(V)->getZExtValue(); | 
|  | if (BitSet) | 
|  | Bits32 |= BoolMask << (i * BitsPerBool); | 
|  | } | 
|  |  | 
|  | // Add in unknown nodes | 
|  | SDValue Base = DAG.getNode(ARMISD::PREDICATE_CAST, dl, VT, | 
|  | DAG.getConstant(Bits32, dl, MVT::i32)); | 
|  | for (unsigned i = 0; i < NumElts; ++i) { | 
|  | SDValue V = Op.getOperand(i); | 
|  | if (isa<ConstantSDNode>(V) || V.isUndef()) | 
|  | continue; | 
|  | Base = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, VT, Base, V, | 
|  | DAG.getConstant(i, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | return Base; | 
|  | } | 
|  |  | 
|  | // If this is a case we can't handle, return null and let the default | 
|  | // expansion code take care of it. | 
|  | SDValue ARMTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) const { | 
|  | BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Op.getNode()); | 
|  | SDLoc dl(Op); | 
|  | EVT VT = Op.getValueType(); | 
|  |  | 
|  | if (ST->hasMVEIntegerOps() && VT.getScalarSizeInBits() == 1) | 
|  | return LowerBUILD_VECTOR_i1(Op, DAG, ST); | 
|  |  | 
|  | APInt SplatBits, SplatUndef; | 
|  | unsigned SplatBitSize; | 
|  | bool HasAnyUndefs; | 
|  | if (BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs)) { | 
|  | if (SplatUndef.isAllOnesValue()) | 
|  | return DAG.getUNDEF(VT); | 
|  |  | 
|  | if ((ST->hasNEON() && SplatBitSize <= 64) || | 
|  | (ST->hasMVEIntegerOps() && SplatBitSize <= 64)) { | 
|  | // Check if an immediate VMOV works. | 
|  | EVT VmovVT; | 
|  | SDValue Val = | 
|  | isVMOVModifiedImm(SplatBits.getZExtValue(), SplatUndef.getZExtValue(), | 
|  | SplatBitSize, DAG, dl, VmovVT, VT, VMOVModImm); | 
|  |  | 
|  | if (Val.getNode()) { | 
|  | SDValue Vmov = DAG.getNode(ARMISD::VMOVIMM, dl, VmovVT, Val); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, Vmov); | 
|  | } | 
|  |  | 
|  | // Try an immediate VMVN. | 
|  | uint64_t NegatedImm = (~SplatBits).getZExtValue(); | 
|  | Val = isVMOVModifiedImm( | 
|  | NegatedImm, SplatUndef.getZExtValue(), SplatBitSize, DAG, dl, VmovVT, | 
|  | VT, ST->hasMVEIntegerOps() ? MVEVMVNModImm : VMVNModImm); | 
|  | if (Val.getNode()) { | 
|  | SDValue Vmov = DAG.getNode(ARMISD::VMVNIMM, dl, VmovVT, Val); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, Vmov); | 
|  | } | 
|  |  | 
|  | // Use vmov.f32 to materialize other v2f32 and v4f32 splats. | 
|  | if ((VT == MVT::v2f32 || VT == MVT::v4f32) && SplatBitSize == 32) { | 
|  | int ImmVal = ARM_AM::getFP32Imm(SplatBits); | 
|  | if (ImmVal != -1) { | 
|  | SDValue Val = DAG.getTargetConstant(ImmVal, dl, MVT::i32); | 
|  | return DAG.getNode(ARMISD::VMOVFPIMM, dl, VT, Val); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Scan through the operands to see if only one value is used. | 
|  | // | 
|  | // As an optimisation, even if more than one value is used it may be more | 
|  | // profitable to splat with one value then change some lanes. | 
|  | // | 
|  | // Heuristically we decide to do this if the vector has a "dominant" value, | 
|  | // defined as splatted to more than half of the lanes. | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | bool isOnlyLowElement = true; | 
|  | bool usesOnlyOneValue = true; | 
|  | bool hasDominantValue = false; | 
|  | bool isConstant = true; | 
|  |  | 
|  | // Map of the number of times a particular SDValue appears in the | 
|  | // element list. | 
|  | DenseMap<SDValue, unsigned> ValueCounts; | 
|  | SDValue Value; | 
|  | for (unsigned i = 0; i < NumElts; ++i) { | 
|  | SDValue V = Op.getOperand(i); | 
|  | if (V.isUndef()) | 
|  | continue; | 
|  | if (i > 0) | 
|  | isOnlyLowElement = false; | 
|  | if (!isa<ConstantFPSDNode>(V) && !isa<ConstantSDNode>(V)) | 
|  | isConstant = false; | 
|  |  | 
|  | ValueCounts.insert(std::make_pair(V, 0)); | 
|  | unsigned &Count = ValueCounts[V]; | 
|  |  | 
|  | // Is this value dominant? (takes up more than half of the lanes) | 
|  | if (++Count > (NumElts / 2)) { | 
|  | hasDominantValue = true; | 
|  | Value = V; | 
|  | } | 
|  | } | 
|  | if (ValueCounts.size() != 1) | 
|  | usesOnlyOneValue = false; | 
|  | if (!Value.getNode() && !ValueCounts.empty()) | 
|  | Value = ValueCounts.begin()->first; | 
|  |  | 
|  | if (ValueCounts.empty()) | 
|  | return DAG.getUNDEF(VT); | 
|  |  | 
|  | // Loads are better lowered with insert_vector_elt/ARMISD::BUILD_VECTOR. | 
|  | // Keep going if we are hitting this case. | 
|  | if (isOnlyLowElement && !ISD::isNormalLoad(Value.getNode())) | 
|  | return DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Value); | 
|  |  | 
|  | unsigned EltSize = VT.getScalarSizeInBits(); | 
|  |  | 
|  | // Use VDUP for non-constant splats.  For f32 constant splats, reduce to | 
|  | // i32 and try again. | 
|  | if (hasDominantValue && EltSize <= 32) { | 
|  | if (!isConstant) { | 
|  | SDValue N; | 
|  |  | 
|  | // If we are VDUPing a value that comes directly from a vector, that will | 
|  | // cause an unnecessary move to and from a GPR, where instead we could | 
|  | // just use VDUPLANE. We can only do this if the lane being extracted | 
|  | // is at a constant index, as the VDUP from lane instructions only have | 
|  | // constant-index forms. | 
|  | ConstantSDNode *constIndex; | 
|  | if (Value->getOpcode() == ISD::EXTRACT_VECTOR_ELT && | 
|  | (constIndex = dyn_cast<ConstantSDNode>(Value->getOperand(1)))) { | 
|  | // We need to create a new undef vector to use for the VDUPLANE if the | 
|  | // size of the vector from which we get the value is different than the | 
|  | // size of the vector that we need to create. We will insert the element | 
|  | // such that the register coalescer will remove unnecessary copies. | 
|  | if (VT != Value->getOperand(0).getValueType()) { | 
|  | unsigned index = constIndex->getAPIntValue().getLimitedValue() % | 
|  | VT.getVectorNumElements(); | 
|  | N =  DAG.getNode(ARMISD::VDUPLANE, dl, VT, | 
|  | DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, VT, DAG.getUNDEF(VT), | 
|  | Value, DAG.getConstant(index, dl, MVT::i32)), | 
|  | DAG.getConstant(index, dl, MVT::i32)); | 
|  | } else | 
|  | N = DAG.getNode(ARMISD::VDUPLANE, dl, VT, | 
|  | Value->getOperand(0), Value->getOperand(1)); | 
|  | } else | 
|  | N = DAG.getNode(ARMISD::VDUP, dl, VT, Value); | 
|  |  | 
|  | if (!usesOnlyOneValue) { | 
|  | // The dominant value was splatted as 'N', but we now have to insert | 
|  | // all differing elements. | 
|  | for (unsigned I = 0; I < NumElts; ++I) { | 
|  | if (Op.getOperand(I) == Value) | 
|  | continue; | 
|  | SmallVector<SDValue, 3> Ops; | 
|  | Ops.push_back(N); | 
|  | Ops.push_back(Op.getOperand(I)); | 
|  | Ops.push_back(DAG.getConstant(I, dl, MVT::i32)); | 
|  | N = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, VT, Ops); | 
|  | } | 
|  | } | 
|  | return N; | 
|  | } | 
|  | if (VT.getVectorElementType().isFloatingPoint()) { | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | MVT FVT = VT.getVectorElementType().getSimpleVT(); | 
|  | assert(FVT == MVT::f32 || FVT == MVT::f16); | 
|  | MVT IVT = (FVT == MVT::f32) ? MVT::i32 : MVT::i16; | 
|  | for (unsigned i = 0; i < NumElts; ++i) | 
|  | Ops.push_back(DAG.getNode(ISD::BITCAST, dl, IVT, | 
|  | Op.getOperand(i))); | 
|  | EVT VecVT = EVT::getVectorVT(*DAG.getContext(), IVT, NumElts); | 
|  | SDValue Val = DAG.getBuildVector(VecVT, dl, Ops); | 
|  | Val = LowerBUILD_VECTOR(Val, DAG, ST); | 
|  | if (Val.getNode()) | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, Val); | 
|  | } | 
|  | if (usesOnlyOneValue) { | 
|  | SDValue Val = IsSingleInstrConstant(Value, DAG, ST, dl); | 
|  | if (isConstant && Val.getNode()) | 
|  | return DAG.getNode(ARMISD::VDUP, dl, VT, Val); | 
|  | } | 
|  | } | 
|  |  | 
|  | // If all elements are constants and the case above didn't get hit, fall back | 
|  | // to the default expansion, which will generate a load from the constant | 
|  | // pool. | 
|  | if (isConstant) | 
|  | return SDValue(); | 
|  |  | 
|  | // Empirical tests suggest this is rarely worth it for vectors of length <= 2. | 
|  | if (NumElts >= 4) { | 
|  | SDValue shuffle = ReconstructShuffle(Op, DAG); | 
|  | if (shuffle != SDValue()) | 
|  | return shuffle; | 
|  | } | 
|  |  | 
|  | if (ST->hasNEON() && VT.is128BitVector() && VT != MVT::v2f64 && VT != MVT::v4f32) { | 
|  | // If we haven't found an efficient lowering, try splitting a 128-bit vector | 
|  | // into two 64-bit vectors; we might discover a better way to lower it. | 
|  | SmallVector<SDValue, 64> Ops(Op->op_begin(), Op->op_begin() + NumElts); | 
|  | EVT ExtVT = VT.getVectorElementType(); | 
|  | EVT HVT = EVT::getVectorVT(*DAG.getContext(), ExtVT, NumElts / 2); | 
|  | SDValue Lower = | 
|  | DAG.getBuildVector(HVT, dl, makeArrayRef(&Ops[0], NumElts / 2)); | 
|  | if (Lower.getOpcode() == ISD::BUILD_VECTOR) | 
|  | Lower = LowerBUILD_VECTOR(Lower, DAG, ST); | 
|  | SDValue Upper = DAG.getBuildVector( | 
|  | HVT, dl, makeArrayRef(&Ops[NumElts / 2], NumElts / 2)); | 
|  | if (Upper.getOpcode() == ISD::BUILD_VECTOR) | 
|  | Upper = LowerBUILD_VECTOR(Upper, DAG, ST); | 
|  | if (Lower && Upper) | 
|  | return DAG.getNode(ISD::CONCAT_VECTORS, dl, VT, Lower, Upper); | 
|  | } | 
|  |  | 
|  | // Vectors with 32- or 64-bit elements can be built by directly assigning | 
|  | // the subregisters.  Lower it to an ARMISD::BUILD_VECTOR so the operands | 
|  | // will be legalized. | 
|  | if (EltSize >= 32) { | 
|  | // Do the expansion with floating-point types, since that is what the VFP | 
|  | // registers are defined to use, and since i64 is not legal. | 
|  | EVT EltVT = EVT::getFloatingPointVT(EltSize); | 
|  | EVT VecVT = EVT::getVectorVT(*DAG.getContext(), EltVT, NumElts); | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | for (unsigned i = 0; i < NumElts; ++i) | 
|  | Ops.push_back(DAG.getNode(ISD::BITCAST, dl, EltVT, Op.getOperand(i))); | 
|  | SDValue Val = DAG.getNode(ARMISD::BUILD_VECTOR, dl, VecVT, Ops); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, Val); | 
|  | } | 
|  |  | 
|  | // If all else fails, just use a sequence of INSERT_VECTOR_ELT when we | 
|  | // know the default expansion would otherwise fall back on something even | 
|  | // worse. For a vector with one or two non-undef values, that's | 
|  | // scalar_to_vector for the elements followed by a shuffle (provided the | 
|  | // shuffle is valid for the target) and materialization element by element | 
|  | // on the stack followed by a load for everything else. | 
|  | if (!isConstant && !usesOnlyOneValue) { | 
|  | SDValue Vec = DAG.getUNDEF(VT); | 
|  | for (unsigned i = 0 ; i < NumElts; ++i) { | 
|  | SDValue V = Op.getOperand(i); | 
|  | if (V.isUndef()) | 
|  | continue; | 
|  | SDValue LaneIdx = DAG.getConstant(i, dl, MVT::i32); | 
|  | Vec = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, VT, Vec, V, LaneIdx); | 
|  | } | 
|  | return Vec; | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // Gather data to see if the operation can be modelled as a | 
|  | // shuffle in combination with VEXTs. | 
|  | SDValue ARMTargetLowering::ReconstructShuffle(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | assert(Op.getOpcode() == ISD::BUILD_VECTOR && "Unknown opcode!"); | 
|  | SDLoc dl(Op); | 
|  | EVT VT = Op.getValueType(); | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  |  | 
|  | struct ShuffleSourceInfo { | 
|  | SDValue Vec; | 
|  | unsigned MinElt = std::numeric_limits<unsigned>::max(); | 
|  | unsigned MaxElt = 0; | 
|  |  | 
|  | // We may insert some combination of BITCASTs and VEXT nodes to force Vec to | 
|  | // be compatible with the shuffle we intend to construct. As a result | 
|  | // ShuffleVec will be some sliding window into the original Vec. | 
|  | SDValue ShuffleVec; | 
|  |  | 
|  | // Code should guarantee that element i in Vec starts at element "WindowBase | 
|  | // + i * WindowScale in ShuffleVec". | 
|  | int WindowBase = 0; | 
|  | int WindowScale = 1; | 
|  |  | 
|  | ShuffleSourceInfo(SDValue Vec) : Vec(Vec), ShuffleVec(Vec) {} | 
|  |  | 
|  | bool operator ==(SDValue OtherVec) { return Vec == OtherVec; } | 
|  | }; | 
|  |  | 
|  | // First gather all vectors used as an immediate source for this BUILD_VECTOR | 
|  | // node. | 
|  | SmallVector<ShuffleSourceInfo, 2> Sources; | 
|  | for (unsigned i = 0; i < NumElts; ++i) { | 
|  | SDValue V = Op.getOperand(i); | 
|  | if (V.isUndef()) | 
|  | continue; | 
|  | else if (V.getOpcode() != ISD::EXTRACT_VECTOR_ELT) { | 
|  | // A shuffle can only come from building a vector from various | 
|  | // elements of other vectors. | 
|  | return SDValue(); | 
|  | } else if (!isa<ConstantSDNode>(V.getOperand(1))) { | 
|  | // Furthermore, shuffles require a constant mask, whereas extractelts | 
|  | // accept variable indices. | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // Add this element source to the list if it's not already there. | 
|  | SDValue SourceVec = V.getOperand(0); | 
|  | auto Source = llvm::find(Sources, SourceVec); | 
|  | if (Source == Sources.end()) | 
|  | Source = Sources.insert(Sources.end(), ShuffleSourceInfo(SourceVec)); | 
|  |  | 
|  | // Update the minimum and maximum lane number seen. | 
|  | unsigned EltNo = cast<ConstantSDNode>(V.getOperand(1))->getZExtValue(); | 
|  | Source->MinElt = std::min(Source->MinElt, EltNo); | 
|  | Source->MaxElt = std::max(Source->MaxElt, EltNo); | 
|  | } | 
|  |  | 
|  | // Currently only do something sane when at most two source vectors | 
|  | // are involved. | 
|  | if (Sources.size() > 2) | 
|  | return SDValue(); | 
|  |  | 
|  | // Find out the smallest element size among result and two sources, and use | 
|  | // it as element size to build the shuffle_vector. | 
|  | EVT SmallestEltTy = VT.getVectorElementType(); | 
|  | for (auto &Source : Sources) { | 
|  | EVT SrcEltTy = Source.Vec.getValueType().getVectorElementType(); | 
|  | if (SrcEltTy.bitsLT(SmallestEltTy)) | 
|  | SmallestEltTy = SrcEltTy; | 
|  | } | 
|  | unsigned ResMultiplier = | 
|  | VT.getScalarSizeInBits() / SmallestEltTy.getSizeInBits(); | 
|  | NumElts = VT.getSizeInBits() / SmallestEltTy.getSizeInBits(); | 
|  | EVT ShuffleVT = EVT::getVectorVT(*DAG.getContext(), SmallestEltTy, NumElts); | 
|  |  | 
|  | // If the source vector is too wide or too narrow, we may nevertheless be able | 
|  | // to construct a compatible shuffle either by concatenating it with UNDEF or | 
|  | // extracting a suitable range of elements. | 
|  | for (auto &Src : Sources) { | 
|  | EVT SrcVT = Src.ShuffleVec.getValueType(); | 
|  |  | 
|  | if (SrcVT.getSizeInBits() == VT.getSizeInBits()) | 
|  | continue; | 
|  |  | 
|  | // This stage of the search produces a source with the same element type as | 
|  | // the original, but with a total width matching the BUILD_VECTOR output. | 
|  | EVT EltVT = SrcVT.getVectorElementType(); | 
|  | unsigned NumSrcElts = VT.getSizeInBits() / EltVT.getSizeInBits(); | 
|  | EVT DestVT = EVT::getVectorVT(*DAG.getContext(), EltVT, NumSrcElts); | 
|  |  | 
|  | if (SrcVT.getSizeInBits() < VT.getSizeInBits()) { | 
|  | if (2 * SrcVT.getSizeInBits() != VT.getSizeInBits()) | 
|  | return SDValue(); | 
|  | // We can pad out the smaller vector for free, so if it's part of a | 
|  | // shuffle... | 
|  | Src.ShuffleVec = | 
|  | DAG.getNode(ISD::CONCAT_VECTORS, dl, DestVT, Src.ShuffleVec, | 
|  | DAG.getUNDEF(Src.ShuffleVec.getValueType())); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (SrcVT.getSizeInBits() != 2 * VT.getSizeInBits()) | 
|  | return SDValue(); | 
|  |  | 
|  | if (Src.MaxElt - Src.MinElt >= NumSrcElts) { | 
|  | // Span too large for a VEXT to cope | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | if (Src.MinElt >= NumSrcElts) { | 
|  | // The extraction can just take the second half | 
|  | Src.ShuffleVec = | 
|  | DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, DestVT, Src.ShuffleVec, | 
|  | DAG.getConstant(NumSrcElts, dl, MVT::i32)); | 
|  | Src.WindowBase = -NumSrcElts; | 
|  | } else if (Src.MaxElt < NumSrcElts) { | 
|  | // The extraction can just take the first half | 
|  | Src.ShuffleVec = | 
|  | DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, DestVT, Src.ShuffleVec, | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | } else { | 
|  | // An actual VEXT is needed | 
|  | SDValue VEXTSrc1 = | 
|  | DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, DestVT, Src.ShuffleVec, | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | SDValue VEXTSrc2 = | 
|  | DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, DestVT, Src.ShuffleVec, | 
|  | DAG.getConstant(NumSrcElts, dl, MVT::i32)); | 
|  |  | 
|  | Src.ShuffleVec = DAG.getNode(ARMISD::VEXT, dl, DestVT, VEXTSrc1, | 
|  | VEXTSrc2, | 
|  | DAG.getConstant(Src.MinElt, dl, MVT::i32)); | 
|  | Src.WindowBase = -Src.MinElt; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Another possible incompatibility occurs from the vector element types. We | 
|  | // can fix this by bitcasting the source vectors to the same type we intend | 
|  | // for the shuffle. | 
|  | for (auto &Src : Sources) { | 
|  | EVT SrcEltTy = Src.ShuffleVec.getValueType().getVectorElementType(); | 
|  | if (SrcEltTy == SmallestEltTy) | 
|  | continue; | 
|  | assert(ShuffleVT.getVectorElementType() == SmallestEltTy); | 
|  | Src.ShuffleVec = DAG.getNode(ARMISD::VECTOR_REG_CAST, dl, ShuffleVT, Src.ShuffleVec); | 
|  | Src.WindowScale = SrcEltTy.getSizeInBits() / SmallestEltTy.getSizeInBits(); | 
|  | Src.WindowBase *= Src.WindowScale; | 
|  | } | 
|  |  | 
|  | // Final sanity check before we try to actually produce a shuffle. | 
|  | LLVM_DEBUG(for (auto Src | 
|  | : Sources) | 
|  | assert(Src.ShuffleVec.getValueType() == ShuffleVT);); | 
|  |  | 
|  | // The stars all align, our next step is to produce the mask for the shuffle. | 
|  | SmallVector<int, 8> Mask(ShuffleVT.getVectorNumElements(), -1); | 
|  | int BitsPerShuffleLane = ShuffleVT.getScalarSizeInBits(); | 
|  | for (unsigned i = 0; i < VT.getVectorNumElements(); ++i) { | 
|  | SDValue Entry = Op.getOperand(i); | 
|  | if (Entry.isUndef()) | 
|  | continue; | 
|  |  | 
|  | auto Src = llvm::find(Sources, Entry.getOperand(0)); | 
|  | int EltNo = cast<ConstantSDNode>(Entry.getOperand(1))->getSExtValue(); | 
|  |  | 
|  | // EXTRACT_VECTOR_ELT performs an implicit any_ext; BUILD_VECTOR an implicit | 
|  | // trunc. So only std::min(SrcBits, DestBits) actually get defined in this | 
|  | // segment. | 
|  | EVT OrigEltTy = Entry.getOperand(0).getValueType().getVectorElementType(); | 
|  | int BitsDefined = std::min(OrigEltTy.getSizeInBits(), | 
|  | VT.getScalarSizeInBits()); | 
|  | int LanesDefined = BitsDefined / BitsPerShuffleLane; | 
|  |  | 
|  | // This source is expected to fill ResMultiplier lanes of the final shuffle, | 
|  | // starting at the appropriate offset. | 
|  | int *LaneMask = &Mask[i * ResMultiplier]; | 
|  |  | 
|  | int ExtractBase = EltNo * Src->WindowScale + Src->WindowBase; | 
|  | ExtractBase += NumElts * (Src - Sources.begin()); | 
|  | for (int j = 0; j < LanesDefined; ++j) | 
|  | LaneMask[j] = ExtractBase + j; | 
|  | } | 
|  |  | 
|  |  | 
|  | // We can't handle more than two sources. This should have already | 
|  | // been checked before this point. | 
|  | assert(Sources.size() <= 2 && "Too many sources!"); | 
|  |  | 
|  | SDValue ShuffleOps[] = { DAG.getUNDEF(ShuffleVT), DAG.getUNDEF(ShuffleVT) }; | 
|  | for (unsigned i = 0; i < Sources.size(); ++i) | 
|  | ShuffleOps[i] = Sources[i].ShuffleVec; | 
|  |  | 
|  | SDValue Shuffle = buildLegalVectorShuffle(ShuffleVT, dl, ShuffleOps[0], | 
|  | ShuffleOps[1], Mask, DAG); | 
|  | if (!Shuffle) | 
|  | return SDValue(); | 
|  | return DAG.getNode(ARMISD::VECTOR_REG_CAST, dl, VT, Shuffle); | 
|  | } | 
|  |  | 
|  | enum ShuffleOpCodes { | 
|  | OP_COPY = 0, // Copy, used for things like <u,u,u,3> to say it is <0,1,2,3> | 
|  | OP_VREV, | 
|  | OP_VDUP0, | 
|  | OP_VDUP1, | 
|  | OP_VDUP2, | 
|  | OP_VDUP3, | 
|  | OP_VEXT1, | 
|  | OP_VEXT2, | 
|  | OP_VEXT3, | 
|  | OP_VUZPL, // VUZP, left result | 
|  | OP_VUZPR, // VUZP, right result | 
|  | OP_VZIPL, // VZIP, left result | 
|  | OP_VZIPR, // VZIP, right result | 
|  | OP_VTRNL, // VTRN, left result | 
|  | OP_VTRNR  // VTRN, right result | 
|  | }; | 
|  |  | 
|  | static bool isLegalMVEShuffleOp(unsigned PFEntry) { | 
|  | unsigned OpNum = (PFEntry >> 26) & 0x0F; | 
|  | switch (OpNum) { | 
|  | case OP_COPY: | 
|  | case OP_VREV: | 
|  | case OP_VDUP0: | 
|  | case OP_VDUP1: | 
|  | case OP_VDUP2: | 
|  | case OP_VDUP3: | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// isShuffleMaskLegal - Targets can use this to indicate that they only | 
|  | /// support *some* VECTOR_SHUFFLE operations, those with specific masks. | 
|  | /// By default, if a target supports the VECTOR_SHUFFLE node, all mask values | 
|  | /// are assumed to be legal. | 
|  | bool ARMTargetLowering::isShuffleMaskLegal(ArrayRef<int> M, EVT VT) const { | 
|  | if (VT.getVectorNumElements() == 4 && | 
|  | (VT.is128BitVector() || VT.is64BitVector())) { | 
|  | unsigned PFIndexes[4]; | 
|  | for (unsigned i = 0; i != 4; ++i) { | 
|  | if (M[i] < 0) | 
|  | PFIndexes[i] = 8; | 
|  | else | 
|  | PFIndexes[i] = M[i]; | 
|  | } | 
|  |  | 
|  | // Compute the index in the perfect shuffle table. | 
|  | unsigned PFTableIndex = | 
|  | PFIndexes[0]*9*9*9+PFIndexes[1]*9*9+PFIndexes[2]*9+PFIndexes[3]; | 
|  | unsigned PFEntry = PerfectShuffleTable[PFTableIndex]; | 
|  | unsigned Cost = (PFEntry >> 30); | 
|  |  | 
|  | if (Cost <= 4 && (Subtarget->hasNEON() || isLegalMVEShuffleOp(PFEntry))) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ReverseVEXT, isV_UNDEF; | 
|  | unsigned Imm, WhichResult; | 
|  |  | 
|  | unsigned EltSize = VT.getScalarSizeInBits(); | 
|  | if (EltSize >= 32 || | 
|  | ShuffleVectorSDNode::isSplatMask(&M[0], VT) || | 
|  | ShuffleVectorInst::isIdentityMask(M) || | 
|  | isVREVMask(M, VT, 64) || | 
|  | isVREVMask(M, VT, 32) || | 
|  | isVREVMask(M, VT, 16)) | 
|  | return true; | 
|  | else if (Subtarget->hasNEON() && | 
|  | (isVEXTMask(M, VT, ReverseVEXT, Imm) || | 
|  | isVTBLMask(M, VT) || | 
|  | isNEONTwoResultShuffleMask(M, VT, WhichResult, isV_UNDEF))) | 
|  | return true; | 
|  | else if (Subtarget->hasNEON() && (VT == MVT::v8i16 || VT == MVT::v16i8) && | 
|  | isReverseMask(M, VT)) | 
|  | return true; | 
|  | else if (Subtarget->hasMVEIntegerOps() && | 
|  | (isVMOVNMask(M, VT, 0) || isVMOVNMask(M, VT, 1))) | 
|  | return true; | 
|  | else | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// GeneratePerfectShuffle - Given an entry in the perfect-shuffle table, emit | 
|  | /// the specified operations to build the shuffle. | 
|  | static SDValue GeneratePerfectShuffle(unsigned PFEntry, SDValue LHS, | 
|  | SDValue RHS, SelectionDAG &DAG, | 
|  | const SDLoc &dl) { | 
|  | unsigned OpNum = (PFEntry >> 26) & 0x0F; | 
|  | unsigned LHSID = (PFEntry >> 13) & ((1 << 13)-1); | 
|  | unsigned RHSID = (PFEntry >>  0) & ((1 << 13)-1); | 
|  |  | 
|  | if (OpNum == OP_COPY) { | 
|  | if (LHSID == (1*9+2)*9+3) return LHS; | 
|  | assert(LHSID == ((4*9+5)*9+6)*9+7 && "Illegal OP_COPY!"); | 
|  | return RHS; | 
|  | } | 
|  |  | 
|  | SDValue OpLHS, OpRHS; | 
|  | OpLHS = GeneratePerfectShuffle(PerfectShuffleTable[LHSID], LHS, RHS, DAG, dl); | 
|  | OpRHS = GeneratePerfectShuffle(PerfectShuffleTable[RHSID], LHS, RHS, DAG, dl); | 
|  | EVT VT = OpLHS.getValueType(); | 
|  |  | 
|  | switch (OpNum) { | 
|  | default: llvm_unreachable("Unknown shuffle opcode!"); | 
|  | case OP_VREV: | 
|  | // VREV divides the vector in half and swaps within the half. | 
|  | if (VT.getVectorElementType() == MVT::i32 || | 
|  | VT.getVectorElementType() == MVT::f32) | 
|  | return DAG.getNode(ARMISD::VREV64, dl, VT, OpLHS); | 
|  | // vrev <4 x i16> -> VREV32 | 
|  | if (VT.getVectorElementType() == MVT::i16) | 
|  | return DAG.getNode(ARMISD::VREV32, dl, VT, OpLHS); | 
|  | // vrev <4 x i8> -> VREV16 | 
|  | assert(VT.getVectorElementType() == MVT::i8); | 
|  | return DAG.getNode(ARMISD::VREV16, dl, VT, OpLHS); | 
|  | case OP_VDUP0: | 
|  | case OP_VDUP1: | 
|  | case OP_VDUP2: | 
|  | case OP_VDUP3: | 
|  | return DAG.getNode(ARMISD::VDUPLANE, dl, VT, | 
|  | OpLHS, DAG.getConstant(OpNum-OP_VDUP0, dl, MVT::i32)); | 
|  | case OP_VEXT1: | 
|  | case OP_VEXT2: | 
|  | case OP_VEXT3: | 
|  | return DAG.getNode(ARMISD::VEXT, dl, VT, | 
|  | OpLHS, OpRHS, | 
|  | DAG.getConstant(OpNum - OP_VEXT1 + 1, dl, MVT::i32)); | 
|  | case OP_VUZPL: | 
|  | case OP_VUZPR: | 
|  | return DAG.getNode(ARMISD::VUZP, dl, DAG.getVTList(VT, VT), | 
|  | OpLHS, OpRHS).getValue(OpNum-OP_VUZPL); | 
|  | case OP_VZIPL: | 
|  | case OP_VZIPR: | 
|  | return DAG.getNode(ARMISD::VZIP, dl, DAG.getVTList(VT, VT), | 
|  | OpLHS, OpRHS).getValue(OpNum-OP_VZIPL); | 
|  | case OP_VTRNL: | 
|  | case OP_VTRNR: | 
|  | return DAG.getNode(ARMISD::VTRN, dl, DAG.getVTList(VT, VT), | 
|  | OpLHS, OpRHS).getValue(OpNum-OP_VTRNL); | 
|  | } | 
|  | } | 
|  |  | 
|  | static SDValue LowerVECTOR_SHUFFLEv8i8(SDValue Op, | 
|  | ArrayRef<int> ShuffleMask, | 
|  | SelectionDAG &DAG) { | 
|  | // Check to see if we can use the VTBL instruction. | 
|  | SDValue V1 = Op.getOperand(0); | 
|  | SDValue V2 = Op.getOperand(1); | 
|  | SDLoc DL(Op); | 
|  |  | 
|  | SmallVector<SDValue, 8> VTBLMask; | 
|  | for (ArrayRef<int>::iterator | 
|  | I = ShuffleMask.begin(), E = ShuffleMask.end(); I != E; ++I) | 
|  | VTBLMask.push_back(DAG.getConstant(*I, DL, MVT::i32)); | 
|  |  | 
|  | if (V2.getNode()->isUndef()) | 
|  | return DAG.getNode(ARMISD::VTBL1, DL, MVT::v8i8, V1, | 
|  | DAG.getBuildVector(MVT::v8i8, DL, VTBLMask)); | 
|  |  | 
|  | return DAG.getNode(ARMISD::VTBL2, DL, MVT::v8i8, V1, V2, | 
|  | DAG.getBuildVector(MVT::v8i8, DL, VTBLMask)); | 
|  | } | 
|  |  | 
|  | static SDValue LowerReverse_VECTOR_SHUFFLEv16i8_v8i16(SDValue Op, | 
|  | SelectionDAG &DAG) { | 
|  | SDLoc DL(Op); | 
|  | SDValue OpLHS = Op.getOperand(0); | 
|  | EVT VT = OpLHS.getValueType(); | 
|  |  | 
|  | assert((VT == MVT::v8i16 || VT == MVT::v16i8) && | 
|  | "Expect an v8i16/v16i8 type"); | 
|  | OpLHS = DAG.getNode(ARMISD::VREV64, DL, VT, OpLHS); | 
|  | // For a v16i8 type: After the VREV, we have got <8, ...15, 8, ..., 0>. Now, | 
|  | // extract the first 8 bytes into the top double word and the last 8 bytes | 
|  | // into the bottom double word. The v8i16 case is similar. | 
|  | unsigned ExtractNum = (VT == MVT::v16i8) ? 8 : 4; | 
|  | return DAG.getNode(ARMISD::VEXT, DL, VT, OpLHS, OpLHS, | 
|  | DAG.getConstant(ExtractNum, DL, MVT::i32)); | 
|  | } | 
|  |  | 
|  | static EVT getVectorTyFromPredicateVector(EVT VT) { | 
|  | switch (VT.getSimpleVT().SimpleTy) { | 
|  | case MVT::v4i1: | 
|  | return MVT::v4i32; | 
|  | case MVT::v8i1: | 
|  | return MVT::v8i16; | 
|  | case MVT::v16i1: | 
|  | return MVT::v16i8; | 
|  | default: | 
|  | llvm_unreachable("Unexpected vector predicate type"); | 
|  | } | 
|  | } | 
|  |  | 
|  | static SDValue PromoteMVEPredVector(SDLoc dl, SDValue Pred, EVT VT, | 
|  | SelectionDAG &DAG) { | 
|  | // Converting from boolean predicates to integers involves creating a vector | 
|  | // of all ones or all zeroes and selecting the lanes based upon the real | 
|  | // predicate. | 
|  | SDValue AllOnes = | 
|  | DAG.getTargetConstant(ARM_AM::createVMOVModImm(0xe, 0xff), dl, MVT::i32); | 
|  | AllOnes = DAG.getNode(ARMISD::VMOVIMM, dl, MVT::v16i8, AllOnes); | 
|  |  | 
|  | SDValue AllZeroes = | 
|  | DAG.getTargetConstant(ARM_AM::createVMOVModImm(0xe, 0x0), dl, MVT::i32); | 
|  | AllZeroes = DAG.getNode(ARMISD::VMOVIMM, dl, MVT::v16i8, AllZeroes); | 
|  |  | 
|  | // Get full vector type from predicate type | 
|  | EVT NewVT = getVectorTyFromPredicateVector(VT); | 
|  |  | 
|  | SDValue RecastV1; | 
|  | // If the real predicate is an v8i1 or v4i1 (not v16i1) then we need to recast | 
|  | // this to a v16i1. This cannot be done with an ordinary bitcast because the | 
|  | // sizes are not the same. We have to use a MVE specific PREDICATE_CAST node, | 
|  | // since we know in hardware the sizes are really the same. | 
|  | if (VT != MVT::v16i1) | 
|  | RecastV1 = DAG.getNode(ARMISD::PREDICATE_CAST, dl, MVT::v16i1, Pred); | 
|  | else | 
|  | RecastV1 = Pred; | 
|  |  | 
|  | // Select either all ones or zeroes depending upon the real predicate bits. | 
|  | SDValue PredAsVector = | 
|  | DAG.getNode(ISD::VSELECT, dl, MVT::v16i8, RecastV1, AllOnes, AllZeroes); | 
|  |  | 
|  | // Recast our new predicate-as-integer v16i8 vector into something | 
|  | // appropriate for the shuffle, i.e. v4i32 for a real v4i1 predicate. | 
|  | return DAG.getNode(ISD::BITCAST, dl, NewVT, PredAsVector); | 
|  | } | 
|  |  | 
|  | static SDValue LowerVECTOR_SHUFFLE_i1(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | EVT VT = Op.getValueType(); | 
|  | ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(Op.getNode()); | 
|  | ArrayRef<int> ShuffleMask = SVN->getMask(); | 
|  |  | 
|  | assert(ST->hasMVEIntegerOps() && | 
|  | "No support for vector shuffle of boolean predicates"); | 
|  |  | 
|  | SDValue V1 = Op.getOperand(0); | 
|  | SDLoc dl(Op); | 
|  | if (isReverseMask(ShuffleMask, VT)) { | 
|  | SDValue cast = DAG.getNode(ARMISD::PREDICATE_CAST, dl, MVT::i32, V1); | 
|  | SDValue rbit = DAG.getNode(ISD::BITREVERSE, dl, MVT::i32, cast); | 
|  | SDValue srl = DAG.getNode(ISD::SRL, dl, MVT::i32, rbit, | 
|  | DAG.getConstant(16, dl, MVT::i32)); | 
|  | return DAG.getNode(ARMISD::PREDICATE_CAST, dl, VT, srl); | 
|  | } | 
|  |  | 
|  | // Until we can come up with optimised cases for every single vector | 
|  | // shuffle in existence we have chosen the least painful strategy. This is | 
|  | // to essentially promote the boolean predicate to a 8-bit integer, where | 
|  | // each predicate represents a byte. Then we fall back on a normal integer | 
|  | // vector shuffle and convert the result back into a predicate vector. In | 
|  | // many cases the generated code might be even better than scalar code | 
|  | // operating on bits. Just imagine trying to shuffle 8 arbitrary 2-bit | 
|  | // fields in a register into 8 other arbitrary 2-bit fields! | 
|  | SDValue PredAsVector = PromoteMVEPredVector(dl, V1, VT, DAG); | 
|  | EVT NewVT = PredAsVector.getValueType(); | 
|  |  | 
|  | // Do the shuffle! | 
|  | SDValue Shuffled = DAG.getVectorShuffle(NewVT, dl, PredAsVector, | 
|  | DAG.getUNDEF(NewVT), ShuffleMask); | 
|  |  | 
|  | // Now return the result of comparing the shuffled vector with zero, | 
|  | // which will generate a real predicate, i.e. v4i1, v8i1 or v16i1. | 
|  | return DAG.getNode(ARMISD::VCMPZ, dl, VT, Shuffled, | 
|  | DAG.getConstant(ARMCC::NE, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | static SDValue LowerVECTOR_SHUFFLEUsingMovs(SDValue Op, | 
|  | ArrayRef<int> ShuffleMask, | 
|  | SelectionDAG &DAG) { | 
|  | // Attempt to lower the vector shuffle using as many whole register movs as | 
|  | // possible. This is useful for types smaller than 32bits, which would | 
|  | // often otherwise become a series for grp movs. | 
|  | SDLoc dl(Op); | 
|  | EVT VT = Op.getValueType(); | 
|  | if (VT.getScalarSizeInBits() >= 32) | 
|  | return SDValue(); | 
|  |  | 
|  | assert((VT == MVT::v8i16 || VT == MVT::v8f16 || VT == MVT::v16i8) && | 
|  | "Unexpected vector type"); | 
|  | int NumElts = VT.getVectorNumElements(); | 
|  | int QuarterSize = NumElts / 4; | 
|  | // The four final parts of the vector, as i32's | 
|  | SDValue Parts[4]; | 
|  |  | 
|  | // Look for full lane vmovs like <0,1,2,3> or <u,5,6,7> etc, (but not | 
|  | // <u,u,u,u>), returning the vmov lane index | 
|  | auto getMovIdx = [](ArrayRef<int> ShuffleMask, int Start, int Length) { | 
|  | // Detect which mov lane this would be from the first non-undef element. | 
|  | int MovIdx = -1; | 
|  | for (int i = 0; i < Length; i++) { | 
|  | if (ShuffleMask[Start + i] >= 0) { | 
|  | if (ShuffleMask[Start + i] % Length != i) | 
|  | return -1; | 
|  | MovIdx = ShuffleMask[Start + i] / Length; | 
|  | break; | 
|  | } | 
|  | } | 
|  | // If all items are undef, leave this for other combines | 
|  | if (MovIdx == -1) | 
|  | return -1; | 
|  | // Check the remaining values are the correct part of the same mov | 
|  | for (int i = 1; i < Length; i++) { | 
|  | if (ShuffleMask[Start + i] >= 0 && | 
|  | (ShuffleMask[Start + i] / Length != MovIdx || | 
|  | ShuffleMask[Start + i] % Length != i)) | 
|  | return -1; | 
|  | } | 
|  | return MovIdx; | 
|  | }; | 
|  |  | 
|  | for (int Part = 0; Part < 4; ++Part) { | 
|  | // Does this part look like a mov | 
|  | int Elt = getMovIdx(ShuffleMask, Part * QuarterSize, QuarterSize); | 
|  | if (Elt != -1) { | 
|  | SDValue Input = Op->getOperand(0); | 
|  | if (Elt >= 4) { | 
|  | Input = Op->getOperand(1); | 
|  | Elt -= 4; | 
|  | } | 
|  | SDValue BitCast = DAG.getBitcast(MVT::v4i32, Input); | 
|  | Parts[Part] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i32, BitCast, | 
|  | DAG.getConstant(Elt, dl, MVT::i32)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Nothing interesting found, just return | 
|  | if (!Parts[0] && !Parts[1] && !Parts[2] && !Parts[3]) | 
|  | return SDValue(); | 
|  |  | 
|  | // The other parts need to be built with the old shuffle vector, cast to a | 
|  | // v4i32 and extract_vector_elts | 
|  | if (!Parts[0] || !Parts[1] || !Parts[2] || !Parts[3]) { | 
|  | SmallVector<int, 16> NewShuffleMask; | 
|  | for (int Part = 0; Part < 4; ++Part) | 
|  | for (int i = 0; i < QuarterSize; i++) | 
|  | NewShuffleMask.push_back( | 
|  | Parts[Part] ? -1 : ShuffleMask[Part * QuarterSize + i]); | 
|  | SDValue NewShuffle = DAG.getVectorShuffle( | 
|  | VT, dl, Op->getOperand(0), Op->getOperand(1), NewShuffleMask); | 
|  | SDValue BitCast = DAG.getBitcast(MVT::v4i32, NewShuffle); | 
|  |  | 
|  | for (int Part = 0; Part < 4; ++Part) | 
|  | if (!Parts[Part]) | 
|  | Parts[Part] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i32, | 
|  | BitCast, DAG.getConstant(Part, dl, MVT::i32)); | 
|  | } | 
|  | // Build a vector out of the various parts and bitcast it back to the original | 
|  | // type. | 
|  | SDValue NewVec = DAG.getBuildVector(MVT::v4i32, dl, Parts); | 
|  | return DAG.getBitcast(VT, NewVec); | 
|  | } | 
|  |  | 
|  | static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | SDValue V1 = Op.getOperand(0); | 
|  | SDValue V2 = Op.getOperand(1); | 
|  | SDLoc dl(Op); | 
|  | EVT VT = Op.getValueType(); | 
|  | ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(Op.getNode()); | 
|  | unsigned EltSize = VT.getScalarSizeInBits(); | 
|  |  | 
|  | if (ST->hasMVEIntegerOps() && EltSize == 1) | 
|  | return LowerVECTOR_SHUFFLE_i1(Op, DAG, ST); | 
|  |  | 
|  | // Convert shuffles that are directly supported on NEON to target-specific | 
|  | // DAG nodes, instead of keeping them as shuffles and matching them again | 
|  | // during code selection.  This is more efficient and avoids the possibility | 
|  | // of inconsistencies between legalization and selection. | 
|  | // FIXME: floating-point vectors should be canonicalized to integer vectors | 
|  | // of the same time so that they get CSEd properly. | 
|  | ArrayRef<int> ShuffleMask = SVN->getMask(); | 
|  |  | 
|  | if (EltSize <= 32) { | 
|  | if (SVN->isSplat()) { | 
|  | int Lane = SVN->getSplatIndex(); | 
|  | // If this is undef splat, generate it via "just" vdup, if possible. | 
|  | if (Lane == -1) Lane = 0; | 
|  |  | 
|  | // Test if V1 is a SCALAR_TO_VECTOR. | 
|  | if (Lane == 0 && V1.getOpcode() == ISD::SCALAR_TO_VECTOR) { | 
|  | return DAG.getNode(ARMISD::VDUP, dl, VT, V1.getOperand(0)); | 
|  | } | 
|  | // Test if V1 is a BUILD_VECTOR which is equivalent to a SCALAR_TO_VECTOR | 
|  | // (and probably will turn into a SCALAR_TO_VECTOR once legalization | 
|  | // reaches it). | 
|  | if (Lane == 0 && V1.getOpcode() == ISD::BUILD_VECTOR && | 
|  | !isa<ConstantSDNode>(V1.getOperand(0))) { | 
|  | bool IsScalarToVector = true; | 
|  | for (unsigned i = 1, e = V1.getNumOperands(); i != e; ++i) | 
|  | if (!V1.getOperand(i).isUndef()) { | 
|  | IsScalarToVector = false; | 
|  | break; | 
|  | } | 
|  | if (IsScalarToVector) | 
|  | return DAG.getNode(ARMISD::VDUP, dl, VT, V1.getOperand(0)); | 
|  | } | 
|  | return DAG.getNode(ARMISD::VDUPLANE, dl, VT, V1, | 
|  | DAG.getConstant(Lane, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | bool ReverseVEXT = false; | 
|  | unsigned Imm = 0; | 
|  | if (ST->hasNEON() && isVEXTMask(ShuffleMask, VT, ReverseVEXT, Imm)) { | 
|  | if (ReverseVEXT) | 
|  | std::swap(V1, V2); | 
|  | return DAG.getNode(ARMISD::VEXT, dl, VT, V1, V2, | 
|  | DAG.getConstant(Imm, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | if (isVREVMask(ShuffleMask, VT, 64)) | 
|  | return DAG.getNode(ARMISD::VREV64, dl, VT, V1); | 
|  | if (isVREVMask(ShuffleMask, VT, 32)) | 
|  | return DAG.getNode(ARMISD::VREV32, dl, VT, V1); | 
|  | if (isVREVMask(ShuffleMask, VT, 16)) | 
|  | return DAG.getNode(ARMISD::VREV16, dl, VT, V1); | 
|  |  | 
|  | if (ST->hasNEON() && V2->isUndef() && isSingletonVEXTMask(ShuffleMask, VT, Imm)) { | 
|  | return DAG.getNode(ARMISD::VEXT, dl, VT, V1, V1, | 
|  | DAG.getConstant(Imm, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | // Check for Neon shuffles that modify both input vectors in place. | 
|  | // If both results are used, i.e., if there are two shuffles with the same | 
|  | // source operands and with masks corresponding to both results of one of | 
|  | // these operations, DAG memoization will ensure that a single node is | 
|  | // used for both shuffles. | 
|  | unsigned WhichResult = 0; | 
|  | bool isV_UNDEF = false; | 
|  | if (ST->hasNEON()) { | 
|  | if (unsigned ShuffleOpc = isNEONTwoResultShuffleMask( | 
|  | ShuffleMask, VT, WhichResult, isV_UNDEF)) { | 
|  | if (isV_UNDEF) | 
|  | V2 = V1; | 
|  | return DAG.getNode(ShuffleOpc, dl, DAG.getVTList(VT, VT), V1, V2) | 
|  | .getValue(WhichResult); | 
|  | } | 
|  | } | 
|  | if (ST->hasMVEIntegerOps()) { | 
|  | if (isVMOVNMask(ShuffleMask, VT, 0)) | 
|  | return DAG.getNode(ARMISD::VMOVN, dl, VT, V2, V1, | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | if (isVMOVNMask(ShuffleMask, VT, 1)) | 
|  | return DAG.getNode(ARMISD::VMOVN, dl, VT, V1, V2, | 
|  | DAG.getConstant(1, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | // Also check for these shuffles through CONCAT_VECTORS: we canonicalize | 
|  | // shuffles that produce a result larger than their operands with: | 
|  | //   shuffle(concat(v1, undef), concat(v2, undef)) | 
|  | // -> | 
|  | //   shuffle(concat(v1, v2), undef) | 
|  | // because we can access quad vectors (see PerformVECTOR_SHUFFLECombine). | 
|  | // | 
|  | // This is useful in the general case, but there are special cases where | 
|  | // native shuffles produce larger results: the two-result ops. | 
|  | // | 
|  | // Look through the concat when lowering them: | 
|  | //   shuffle(concat(v1, v2), undef) | 
|  | // -> | 
|  | //   concat(VZIP(v1, v2):0, :1) | 
|  | // | 
|  | if (ST->hasNEON() && V1->getOpcode() == ISD::CONCAT_VECTORS && V2->isUndef()) { | 
|  | SDValue SubV1 = V1->getOperand(0); | 
|  | SDValue SubV2 = V1->getOperand(1); | 
|  | EVT SubVT = SubV1.getValueType(); | 
|  |  | 
|  | // We expect these to have been canonicalized to -1. | 
|  | assert(llvm::all_of(ShuffleMask, [&](int i) { | 
|  | return i < (int)VT.getVectorNumElements(); | 
|  | }) && "Unexpected shuffle index into UNDEF operand!"); | 
|  |  | 
|  | if (unsigned ShuffleOpc = isNEONTwoResultShuffleMask( | 
|  | ShuffleMask, SubVT, WhichResult, isV_UNDEF)) { | 
|  | if (isV_UNDEF) | 
|  | SubV2 = SubV1; | 
|  | assert((WhichResult == 0) && | 
|  | "In-place shuffle of concat can only have one result!"); | 
|  | SDValue Res = DAG.getNode(ShuffleOpc, dl, DAG.getVTList(SubVT, SubVT), | 
|  | SubV1, SubV2); | 
|  | return DAG.getNode(ISD::CONCAT_VECTORS, dl, VT, Res.getValue(0), | 
|  | Res.getValue(1)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // If the shuffle is not directly supported and it has 4 elements, use | 
|  | // the PerfectShuffle-generated table to synthesize it from other shuffles. | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | if (NumElts == 4) { | 
|  | unsigned PFIndexes[4]; | 
|  | for (unsigned i = 0; i != 4; ++i) { | 
|  | if (ShuffleMask[i] < 0) | 
|  | PFIndexes[i] = 8; | 
|  | else | 
|  | PFIndexes[i] = ShuffleMask[i]; | 
|  | } | 
|  |  | 
|  | // Compute the index in the perfect shuffle table. | 
|  | unsigned PFTableIndex = | 
|  | PFIndexes[0]*9*9*9+PFIndexes[1]*9*9+PFIndexes[2]*9+PFIndexes[3]; | 
|  | unsigned PFEntry = PerfectShuffleTable[PFTableIndex]; | 
|  | unsigned Cost = (PFEntry >> 30); | 
|  |  | 
|  | if (Cost <= 4) { | 
|  | if (ST->hasNEON()) | 
|  | return GeneratePerfectShuffle(PFEntry, V1, V2, DAG, dl); | 
|  | else if (isLegalMVEShuffleOp(PFEntry)) { | 
|  | unsigned LHSID = (PFEntry >> 13) & ((1 << 13)-1); | 
|  | unsigned RHSID = (PFEntry >>  0) & ((1 << 13)-1); | 
|  | unsigned PFEntryLHS = PerfectShuffleTable[LHSID]; | 
|  | unsigned PFEntryRHS = PerfectShuffleTable[RHSID]; | 
|  | if (isLegalMVEShuffleOp(PFEntryLHS) && isLegalMVEShuffleOp(PFEntryRHS)) | 
|  | return GeneratePerfectShuffle(PFEntry, V1, V2, DAG, dl); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Implement shuffles with 32- or 64-bit elements as ARMISD::BUILD_VECTORs. | 
|  | if (EltSize >= 32) { | 
|  | // Do the expansion with floating-point types, since that is what the VFP | 
|  | // registers are defined to use, and since i64 is not legal. | 
|  | EVT EltVT = EVT::getFloatingPointVT(EltSize); | 
|  | EVT VecVT = EVT::getVectorVT(*DAG.getContext(), EltVT, NumElts); | 
|  | V1 = DAG.getNode(ISD::BITCAST, dl, VecVT, V1); | 
|  | V2 = DAG.getNode(ISD::BITCAST, dl, VecVT, V2); | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | for (unsigned i = 0; i < NumElts; ++i) { | 
|  | if (ShuffleMask[i] < 0) | 
|  | Ops.push_back(DAG.getUNDEF(EltVT)); | 
|  | else | 
|  | Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, | 
|  | ShuffleMask[i] < (int)NumElts ? V1 : V2, | 
|  | DAG.getConstant(ShuffleMask[i] & (NumElts-1), | 
|  | dl, MVT::i32))); | 
|  | } | 
|  | SDValue Val = DAG.getNode(ARMISD::BUILD_VECTOR, dl, VecVT, Ops); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, Val); | 
|  | } | 
|  |  | 
|  | if (ST->hasNEON() && (VT == MVT::v8i16 || VT == MVT::v16i8) && isReverseMask(ShuffleMask, VT)) | 
|  | return LowerReverse_VECTOR_SHUFFLEv16i8_v8i16(Op, DAG); | 
|  |  | 
|  | if (ST->hasNEON() && VT == MVT::v8i8) | 
|  | if (SDValue NewOp = LowerVECTOR_SHUFFLEv8i8(Op, ShuffleMask, DAG)) | 
|  | return NewOp; | 
|  |  | 
|  | if (ST->hasMVEIntegerOps()) | 
|  | if (SDValue NewOp = LowerVECTOR_SHUFFLEUsingMovs(Op, ShuffleMask, DAG)) | 
|  | return NewOp; | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue LowerINSERT_VECTOR_ELT_i1(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | EVT VecVT = Op.getOperand(0).getValueType(); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | assert(ST->hasMVEIntegerOps() && | 
|  | "LowerINSERT_VECTOR_ELT_i1 called without MVE!"); | 
|  |  | 
|  | SDValue Conv = | 
|  | DAG.getNode(ARMISD::PREDICATE_CAST, dl, MVT::i32, Op->getOperand(0)); | 
|  | unsigned Lane = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue(); | 
|  | unsigned LaneWidth = | 
|  | getVectorTyFromPredicateVector(VecVT).getScalarSizeInBits() / 8; | 
|  | unsigned Mask = ((1 << LaneWidth) - 1) << Lane * LaneWidth; | 
|  | SDValue Ext = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, MVT::i32, | 
|  | Op.getOperand(1), DAG.getValueType(MVT::i1)); | 
|  | SDValue BFI = DAG.getNode(ARMISD::BFI, dl, MVT::i32, Conv, Ext, | 
|  | DAG.getConstant(~Mask, dl, MVT::i32)); | 
|  | return DAG.getNode(ARMISD::PREDICATE_CAST, dl, Op.getValueType(), BFI); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerINSERT_VECTOR_ELT(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | // INSERT_VECTOR_ELT is legal only for immediate indexes. | 
|  | SDValue Lane = Op.getOperand(2); | 
|  | if (!isa<ConstantSDNode>(Lane)) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue Elt = Op.getOperand(1); | 
|  | EVT EltVT = Elt.getValueType(); | 
|  |  | 
|  | if (Subtarget->hasMVEIntegerOps() && | 
|  | Op.getValueType().getScalarSizeInBits() == 1) | 
|  | return LowerINSERT_VECTOR_ELT_i1(Op, DAG, Subtarget); | 
|  |  | 
|  | if (getTypeAction(*DAG.getContext(), EltVT) == | 
|  | TargetLowering::TypePromoteFloat) { | 
|  | // INSERT_VECTOR_ELT doesn't want f16 operands promoting to f32, | 
|  | // but the type system will try to do that if we don't intervene. | 
|  | // Reinterpret any such vector-element insertion as one with the | 
|  | // corresponding integer types. | 
|  |  | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | EVT IEltVT = MVT::getIntegerVT(EltVT.getScalarSizeInBits()); | 
|  | assert(getTypeAction(*DAG.getContext(), IEltVT) != | 
|  | TargetLowering::TypePromoteFloat); | 
|  |  | 
|  | SDValue VecIn = Op.getOperand(0); | 
|  | EVT VecVT = VecIn.getValueType(); | 
|  | EVT IVecVT = EVT::getVectorVT(*DAG.getContext(), IEltVT, | 
|  | VecVT.getVectorNumElements()); | 
|  |  | 
|  | SDValue IElt = DAG.getNode(ISD::BITCAST, dl, IEltVT, Elt); | 
|  | SDValue IVecIn = DAG.getNode(ISD::BITCAST, dl, IVecVT, VecIn); | 
|  | SDValue IVecOut = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, IVecVT, | 
|  | IVecIn, IElt, Lane); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VecVT, IVecOut); | 
|  | } | 
|  |  | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | static SDValue LowerEXTRACT_VECTOR_ELT_i1(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | EVT VecVT = Op.getOperand(0).getValueType(); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | assert(ST->hasMVEIntegerOps() && | 
|  | "LowerINSERT_VECTOR_ELT_i1 called without MVE!"); | 
|  |  | 
|  | SDValue Conv = | 
|  | DAG.getNode(ARMISD::PREDICATE_CAST, dl, MVT::i32, Op->getOperand(0)); | 
|  | unsigned Lane = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue(); | 
|  | unsigned LaneWidth = | 
|  | getVectorTyFromPredicateVector(VecVT).getScalarSizeInBits() / 8; | 
|  | SDValue Shift = DAG.getNode(ISD::SRL, dl, MVT::i32, Conv, | 
|  | DAG.getConstant(Lane * LaneWidth, dl, MVT::i32)); | 
|  | return Shift; | 
|  | } | 
|  |  | 
|  | static SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | // EXTRACT_VECTOR_ELT is legal only for immediate indexes. | 
|  | SDValue Lane = Op.getOperand(1); | 
|  | if (!isa<ConstantSDNode>(Lane)) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue Vec = Op.getOperand(0); | 
|  | EVT VT = Vec.getValueType(); | 
|  |  | 
|  | if (ST->hasMVEIntegerOps() && VT.getScalarSizeInBits() == 1) | 
|  | return LowerEXTRACT_VECTOR_ELT_i1(Op, DAG, ST); | 
|  |  | 
|  | if (Op.getValueType() == MVT::i32 && Vec.getScalarValueSizeInBits() < 32) { | 
|  | SDLoc dl(Op); | 
|  | return DAG.getNode(ARMISD::VGETLANEu, dl, MVT::i32, Vec, Lane); | 
|  | } | 
|  |  | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | static SDValue LowerCONCAT_VECTORS_i1(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | SDValue V1 = Op.getOperand(0); | 
|  | SDValue V2 = Op.getOperand(1); | 
|  | SDLoc dl(Op); | 
|  | EVT VT = Op.getValueType(); | 
|  | EVT Op1VT = V1.getValueType(); | 
|  | EVT Op2VT = V2.getValueType(); | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  |  | 
|  | assert(Op1VT == Op2VT && "Operand types don't match!"); | 
|  | assert(VT.getScalarSizeInBits() == 1 && | 
|  | "Unexpected custom CONCAT_VECTORS lowering"); | 
|  | assert(ST->hasMVEIntegerOps() && | 
|  | "CONCAT_VECTORS lowering only supported for MVE"); | 
|  |  | 
|  | SDValue NewV1 = PromoteMVEPredVector(dl, V1, Op1VT, DAG); | 
|  | SDValue NewV2 = PromoteMVEPredVector(dl, V2, Op2VT, DAG); | 
|  |  | 
|  | // We now have Op1 + Op2 promoted to vectors of integers, where v8i1 gets | 
|  | // promoted to v8i16, etc. | 
|  |  | 
|  | MVT ElType = getVectorTyFromPredicateVector(VT).getScalarType().getSimpleVT(); | 
|  |  | 
|  | // Extract the vector elements from Op1 and Op2 one by one and truncate them | 
|  | // to be the right size for the destination. For example, if Op1 is v4i1 then | 
|  | // the promoted vector is v4i32. The result of concatentation gives a v8i1, | 
|  | // which when promoted is v8i16. That means each i32 element from Op1 needs | 
|  | // truncating to i16 and inserting in the result. | 
|  | EVT ConcatVT = MVT::getVectorVT(ElType, NumElts); | 
|  | SDValue ConVec = DAG.getNode(ISD::UNDEF, dl, ConcatVT); | 
|  | auto ExractInto = [&DAG, &dl](SDValue NewV, SDValue ConVec, unsigned &j) { | 
|  | EVT NewVT = NewV.getValueType(); | 
|  | EVT ConcatVT = ConVec.getValueType(); | 
|  | for (unsigned i = 0, e = NewVT.getVectorNumElements(); i < e; i++, j++) { | 
|  | SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i32, NewV, | 
|  | DAG.getIntPtrConstant(i, dl)); | 
|  | ConVec = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, ConcatVT, ConVec, Elt, | 
|  | DAG.getConstant(j, dl, MVT::i32)); | 
|  | } | 
|  | return ConVec; | 
|  | }; | 
|  | unsigned j = 0; | 
|  | ConVec = ExractInto(NewV1, ConVec, j); | 
|  | ConVec = ExractInto(NewV2, ConVec, j); | 
|  |  | 
|  | // Now return the result of comparing the subvector with zero, | 
|  | // which will generate a real predicate, i.e. v4i1, v8i1 or v16i1. | 
|  | return DAG.getNode(ARMISD::VCMPZ, dl, VT, ConVec, | 
|  | DAG.getConstant(ARMCC::NE, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | static SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | EVT VT = Op->getValueType(0); | 
|  | if (ST->hasMVEIntegerOps() && VT.getScalarSizeInBits() == 1) | 
|  | return LowerCONCAT_VECTORS_i1(Op, DAG, ST); | 
|  |  | 
|  | // The only time a CONCAT_VECTORS operation can have legal types is when | 
|  | // two 64-bit vectors are concatenated to a 128-bit vector. | 
|  | assert(Op.getValueType().is128BitVector() && Op.getNumOperands() == 2 && | 
|  | "unexpected CONCAT_VECTORS"); | 
|  | SDLoc dl(Op); | 
|  | SDValue Val = DAG.getUNDEF(MVT::v2f64); | 
|  | SDValue Op0 = Op.getOperand(0); | 
|  | SDValue Op1 = Op.getOperand(1); | 
|  | if (!Op0.isUndef()) | 
|  | Val = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, Val, | 
|  | DAG.getNode(ISD::BITCAST, dl, MVT::f64, Op0), | 
|  | DAG.getIntPtrConstant(0, dl)); | 
|  | if (!Op1.isUndef()) | 
|  | Val = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, Val, | 
|  | DAG.getNode(ISD::BITCAST, dl, MVT::f64, Op1), | 
|  | DAG.getIntPtrConstant(1, dl)); | 
|  | return DAG.getNode(ISD::BITCAST, dl, Op.getValueType(), Val); | 
|  | } | 
|  |  | 
|  | static SDValue LowerEXTRACT_SUBVECTOR(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | SDValue V1 = Op.getOperand(0); | 
|  | SDValue V2 = Op.getOperand(1); | 
|  | SDLoc dl(Op); | 
|  | EVT VT = Op.getValueType(); | 
|  | EVT Op1VT = V1.getValueType(); | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | unsigned Index = cast<ConstantSDNode>(V2)->getZExtValue(); | 
|  |  | 
|  | assert(VT.getScalarSizeInBits() == 1 && | 
|  | "Unexpected custom EXTRACT_SUBVECTOR lowering"); | 
|  | assert(ST->hasMVEIntegerOps() && | 
|  | "EXTRACT_SUBVECTOR lowering only supported for MVE"); | 
|  |  | 
|  | SDValue NewV1 = PromoteMVEPredVector(dl, V1, Op1VT, DAG); | 
|  |  | 
|  | // We now have Op1 promoted to a vector of integers, where v8i1 gets | 
|  | // promoted to v8i16, etc. | 
|  |  | 
|  | MVT ElType = getVectorTyFromPredicateVector(VT).getScalarType().getSimpleVT(); | 
|  |  | 
|  | EVT SubVT = MVT::getVectorVT(ElType, NumElts); | 
|  | SDValue SubVec = DAG.getNode(ISD::UNDEF, dl, SubVT); | 
|  | for (unsigned i = Index, j = 0; i < (Index + NumElts); i++, j++) { | 
|  | SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i32, NewV1, | 
|  | DAG.getIntPtrConstant(i, dl)); | 
|  | SubVec = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, SubVT, SubVec, Elt, | 
|  | DAG.getConstant(j, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | // Now return the result of comparing the subvector with zero, | 
|  | // which will generate a real predicate, i.e. v4i1, v8i1 or v16i1. | 
|  | return DAG.getNode(ARMISD::VCMPZ, dl, VT, SubVec, | 
|  | DAG.getConstant(ARMCC::NE, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | /// isExtendedBUILD_VECTOR - Check if N is a constant BUILD_VECTOR where each | 
|  | /// element has been zero/sign-extended, depending on the isSigned parameter, | 
|  | /// from an integer type half its size. | 
|  | static bool isExtendedBUILD_VECTOR(SDNode *N, SelectionDAG &DAG, | 
|  | bool isSigned) { | 
|  | // A v2i64 BUILD_VECTOR will have been legalized to a BITCAST from v4i32. | 
|  | EVT VT = N->getValueType(0); | 
|  | if (VT == MVT::v2i64 && N->getOpcode() == ISD::BITCAST) { | 
|  | SDNode *BVN = N->getOperand(0).getNode(); | 
|  | if (BVN->getValueType(0) != MVT::v4i32 || | 
|  | BVN->getOpcode() != ISD::BUILD_VECTOR) | 
|  | return false; | 
|  | unsigned LoElt = DAG.getDataLayout().isBigEndian() ? 1 : 0; | 
|  | unsigned HiElt = 1 - LoElt; | 
|  | ConstantSDNode *Lo0 = dyn_cast<ConstantSDNode>(BVN->getOperand(LoElt)); | 
|  | ConstantSDNode *Hi0 = dyn_cast<ConstantSDNode>(BVN->getOperand(HiElt)); | 
|  | ConstantSDNode *Lo1 = dyn_cast<ConstantSDNode>(BVN->getOperand(LoElt+2)); | 
|  | ConstantSDNode *Hi1 = dyn_cast<ConstantSDNode>(BVN->getOperand(HiElt+2)); | 
|  | if (!Lo0 || !Hi0 || !Lo1 || !Hi1) | 
|  | return false; | 
|  | if (isSigned) { | 
|  | if (Hi0->getSExtValue() == Lo0->getSExtValue() >> 32 && | 
|  | Hi1->getSExtValue() == Lo1->getSExtValue() >> 32) | 
|  | return true; | 
|  | } else { | 
|  | if (Hi0->isNullValue() && Hi1->isNullValue()) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (N->getOpcode() != ISD::BUILD_VECTOR) | 
|  | return false; | 
|  |  | 
|  | for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { | 
|  | SDNode *Elt = N->getOperand(i).getNode(); | 
|  | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Elt)) { | 
|  | unsigned EltSize = VT.getScalarSizeInBits(); | 
|  | unsigned HalfSize = EltSize / 2; | 
|  | if (isSigned) { | 
|  | if (!isIntN(HalfSize, C->getSExtValue())) | 
|  | return false; | 
|  | } else { | 
|  | if (!isUIntN(HalfSize, C->getZExtValue())) | 
|  | return false; | 
|  | } | 
|  | continue; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// isSignExtended - Check if a node is a vector value that is sign-extended | 
|  | /// or a constant BUILD_VECTOR with sign-extended elements. | 
|  | static bool isSignExtended(SDNode *N, SelectionDAG &DAG) { | 
|  | if (N->getOpcode() == ISD::SIGN_EXTEND || ISD::isSEXTLoad(N)) | 
|  | return true; | 
|  | if (isExtendedBUILD_VECTOR(N, DAG, true)) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// isZeroExtended - Check if a node is a vector value that is zero-extended | 
|  | /// or a constant BUILD_VECTOR with zero-extended elements. | 
|  | static bool isZeroExtended(SDNode *N, SelectionDAG &DAG) { | 
|  | if (N->getOpcode() == ISD::ZERO_EXTEND || ISD::isZEXTLoad(N)) | 
|  | return true; | 
|  | if (isExtendedBUILD_VECTOR(N, DAG, false)) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static EVT getExtensionTo64Bits(const EVT &OrigVT) { | 
|  | if (OrigVT.getSizeInBits() >= 64) | 
|  | return OrigVT; | 
|  |  | 
|  | assert(OrigVT.isSimple() && "Expecting a simple value type"); | 
|  |  | 
|  | MVT::SimpleValueType OrigSimpleTy = OrigVT.getSimpleVT().SimpleTy; | 
|  | switch (OrigSimpleTy) { | 
|  | default: llvm_unreachable("Unexpected Vector Type"); | 
|  | case MVT::v2i8: | 
|  | case MVT::v2i16: | 
|  | return MVT::v2i32; | 
|  | case MVT::v4i8: | 
|  | return  MVT::v4i16; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// AddRequiredExtensionForVMULL - Add a sign/zero extension to extend the total | 
|  | /// value size to 64 bits. We need a 64-bit D register as an operand to VMULL. | 
|  | /// We insert the required extension here to get the vector to fill a D register. | 
|  | static SDValue AddRequiredExtensionForVMULL(SDValue N, SelectionDAG &DAG, | 
|  | const EVT &OrigTy, | 
|  | const EVT &ExtTy, | 
|  | unsigned ExtOpcode) { | 
|  | // The vector originally had a size of OrigTy. It was then extended to ExtTy. | 
|  | // We expect the ExtTy to be 128-bits total. If the OrigTy is less than | 
|  | // 64-bits we need to insert a new extension so that it will be 64-bits. | 
|  | assert(ExtTy.is128BitVector() && "Unexpected extension size"); | 
|  | if (OrigTy.getSizeInBits() >= 64) | 
|  | return N; | 
|  |  | 
|  | // Must extend size to at least 64 bits to be used as an operand for VMULL. | 
|  | EVT NewVT = getExtensionTo64Bits(OrigTy); | 
|  |  | 
|  | return DAG.getNode(ExtOpcode, SDLoc(N), NewVT, N); | 
|  | } | 
|  |  | 
|  | /// SkipLoadExtensionForVMULL - return a load of the original vector size that | 
|  | /// does not do any sign/zero extension. If the original vector is less | 
|  | /// than 64 bits, an appropriate extension will be added after the load to | 
|  | /// reach a total size of 64 bits. We have to add the extension separately | 
|  | /// because ARM does not have a sign/zero extending load for vectors. | 
|  | static SDValue SkipLoadExtensionForVMULL(LoadSDNode *LD, SelectionDAG& DAG) { | 
|  | EVT ExtendedTy = getExtensionTo64Bits(LD->getMemoryVT()); | 
|  |  | 
|  | // The load already has the right type. | 
|  | if (ExtendedTy == LD->getMemoryVT()) | 
|  | return DAG.getLoad(LD->getMemoryVT(), SDLoc(LD), LD->getChain(), | 
|  | LD->getBasePtr(), LD->getPointerInfo(), | 
|  | LD->getAlignment(), LD->getMemOperand()->getFlags()); | 
|  |  | 
|  | // We need to create a zextload/sextload. We cannot just create a load | 
|  | // followed by a zext/zext node because LowerMUL is also run during normal | 
|  | // operation legalization where we can't create illegal types. | 
|  | return DAG.getExtLoad(LD->getExtensionType(), SDLoc(LD), ExtendedTy, | 
|  | LD->getChain(), LD->getBasePtr(), LD->getPointerInfo(), | 
|  | LD->getMemoryVT(), LD->getAlignment(), | 
|  | LD->getMemOperand()->getFlags()); | 
|  | } | 
|  |  | 
|  | /// SkipExtensionForVMULL - For a node that is a SIGN_EXTEND, ZERO_EXTEND, | 
|  | /// extending load, or BUILD_VECTOR with extended elements, return the | 
|  | /// unextended value. The unextended vector should be 64 bits so that it can | 
|  | /// be used as an operand to a VMULL instruction. If the original vector size | 
|  | /// before extension is less than 64 bits we add a an extension to resize | 
|  | /// the vector to 64 bits. | 
|  | static SDValue SkipExtensionForVMULL(SDNode *N, SelectionDAG &DAG) { | 
|  | if (N->getOpcode() == ISD::SIGN_EXTEND || N->getOpcode() == ISD::ZERO_EXTEND) | 
|  | return AddRequiredExtensionForVMULL(N->getOperand(0), DAG, | 
|  | N->getOperand(0)->getValueType(0), | 
|  | N->getValueType(0), | 
|  | N->getOpcode()); | 
|  |  | 
|  | if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) { | 
|  | assert((ISD::isSEXTLoad(LD) || ISD::isZEXTLoad(LD)) && | 
|  | "Expected extending load"); | 
|  |  | 
|  | SDValue newLoad = SkipLoadExtensionForVMULL(LD, DAG); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(LD, 1), newLoad.getValue(1)); | 
|  | unsigned Opcode = ISD::isSEXTLoad(LD) ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND; | 
|  | SDValue extLoad = | 
|  | DAG.getNode(Opcode, SDLoc(newLoad), LD->getValueType(0), newLoad); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(LD, 0), extLoad); | 
|  |  | 
|  | return newLoad; | 
|  | } | 
|  |  | 
|  | // Otherwise, the value must be a BUILD_VECTOR.  For v2i64, it will | 
|  | // have been legalized as a BITCAST from v4i32. | 
|  | if (N->getOpcode() == ISD::BITCAST) { | 
|  | SDNode *BVN = N->getOperand(0).getNode(); | 
|  | assert(BVN->getOpcode() == ISD::BUILD_VECTOR && | 
|  | BVN->getValueType(0) == MVT::v4i32 && "expected v4i32 BUILD_VECTOR"); | 
|  | unsigned LowElt = DAG.getDataLayout().isBigEndian() ? 1 : 0; | 
|  | return DAG.getBuildVector( | 
|  | MVT::v2i32, SDLoc(N), | 
|  | {BVN->getOperand(LowElt), BVN->getOperand(LowElt + 2)}); | 
|  | } | 
|  | // Construct a new BUILD_VECTOR with elements truncated to half the size. | 
|  | assert(N->getOpcode() == ISD::BUILD_VECTOR && "expected BUILD_VECTOR"); | 
|  | EVT VT = N->getValueType(0); | 
|  | unsigned EltSize = VT.getScalarSizeInBits() / 2; | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | MVT TruncVT = MVT::getIntegerVT(EltSize); | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | SDLoc dl(N); | 
|  | for (unsigned i = 0; i != NumElts; ++i) { | 
|  | ConstantSDNode *C = cast<ConstantSDNode>(N->getOperand(i)); | 
|  | const APInt &CInt = C->getAPIntValue(); | 
|  | // Element types smaller than 32 bits are not legal, so use i32 elements. | 
|  | // The values are implicitly truncated so sext vs. zext doesn't matter. | 
|  | Ops.push_back(DAG.getConstant(CInt.zextOrTrunc(32), dl, MVT::i32)); | 
|  | } | 
|  | return DAG.getBuildVector(MVT::getVectorVT(TruncVT, NumElts), dl, Ops); | 
|  | } | 
|  |  | 
|  | static bool isAddSubSExt(SDNode *N, SelectionDAG &DAG) { | 
|  | unsigned Opcode = N->getOpcode(); | 
|  | if (Opcode == ISD::ADD || Opcode == ISD::SUB) { | 
|  | SDNode *N0 = N->getOperand(0).getNode(); | 
|  | SDNode *N1 = N->getOperand(1).getNode(); | 
|  | return N0->hasOneUse() && N1->hasOneUse() && | 
|  | isSignExtended(N0, DAG) && isSignExtended(N1, DAG); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool isAddSubZExt(SDNode *N, SelectionDAG &DAG) { | 
|  | unsigned Opcode = N->getOpcode(); | 
|  | if (Opcode == ISD::ADD || Opcode == ISD::SUB) { | 
|  | SDNode *N0 = N->getOperand(0).getNode(); | 
|  | SDNode *N1 = N->getOperand(1).getNode(); | 
|  | return N0->hasOneUse() && N1->hasOneUse() && | 
|  | isZeroExtended(N0, DAG) && isZeroExtended(N1, DAG); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) { | 
|  | // Multiplications are only custom-lowered for 128-bit vectors so that | 
|  | // VMULL can be detected.  Otherwise v2i64 multiplications are not legal. | 
|  | EVT VT = Op.getValueType(); | 
|  | assert(VT.is128BitVector() && VT.isInteger() && | 
|  | "unexpected type for custom-lowering ISD::MUL"); | 
|  | SDNode *N0 = Op.getOperand(0).getNode(); | 
|  | SDNode *N1 = Op.getOperand(1).getNode(); | 
|  | unsigned NewOpc = 0; | 
|  | bool isMLA = false; | 
|  | bool isN0SExt = isSignExtended(N0, DAG); | 
|  | bool isN1SExt = isSignExtended(N1, DAG); | 
|  | if (isN0SExt && isN1SExt) | 
|  | NewOpc = ARMISD::VMULLs; | 
|  | else { | 
|  | bool isN0ZExt = isZeroExtended(N0, DAG); | 
|  | bool isN1ZExt = isZeroExtended(N1, DAG); | 
|  | if (isN0ZExt && isN1ZExt) | 
|  | NewOpc = ARMISD::VMULLu; | 
|  | else if (isN1SExt || isN1ZExt) { | 
|  | // Look for (s/zext A + s/zext B) * (s/zext C). We want to turn these | 
|  | // into (s/zext A * s/zext C) + (s/zext B * s/zext C) | 
|  | if (isN1SExt && isAddSubSExt(N0, DAG)) { | 
|  | NewOpc = ARMISD::VMULLs; | 
|  | isMLA = true; | 
|  | } else if (isN1ZExt && isAddSubZExt(N0, DAG)) { | 
|  | NewOpc = ARMISD::VMULLu; | 
|  | isMLA = true; | 
|  | } else if (isN0ZExt && isAddSubZExt(N1, DAG)) { | 
|  | std::swap(N0, N1); | 
|  | NewOpc = ARMISD::VMULLu; | 
|  | isMLA = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!NewOpc) { | 
|  | if (VT == MVT::v2i64) | 
|  | // Fall through to expand this.  It is not legal. | 
|  | return SDValue(); | 
|  | else | 
|  | // Other vector multiplications are legal. | 
|  | return Op; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Legalize to a VMULL instruction. | 
|  | SDLoc DL(Op); | 
|  | SDValue Op0; | 
|  | SDValue Op1 = SkipExtensionForVMULL(N1, DAG); | 
|  | if (!isMLA) { | 
|  | Op0 = SkipExtensionForVMULL(N0, DAG); | 
|  | assert(Op0.getValueType().is64BitVector() && | 
|  | Op1.getValueType().is64BitVector() && | 
|  | "unexpected types for extended operands to VMULL"); | 
|  | return DAG.getNode(NewOpc, DL, VT, Op0, Op1); | 
|  | } | 
|  |  | 
|  | // Optimizing (zext A + zext B) * C, to (VMULL A, C) + (VMULL B, C) during | 
|  | // isel lowering to take advantage of no-stall back to back vmul + vmla. | 
|  | //   vmull q0, d4, d6 | 
|  | //   vmlal q0, d5, d6 | 
|  | // is faster than | 
|  | //   vaddl q0, d4, d5 | 
|  | //   vmovl q1, d6 | 
|  | //   vmul  q0, q0, q1 | 
|  | SDValue N00 = SkipExtensionForVMULL(N0->getOperand(0).getNode(), DAG); | 
|  | SDValue N01 = SkipExtensionForVMULL(N0->getOperand(1).getNode(), DAG); | 
|  | EVT Op1VT = Op1.getValueType(); | 
|  | return DAG.getNode(N0->getOpcode(), DL, VT, | 
|  | DAG.getNode(NewOpc, DL, VT, | 
|  | DAG.getNode(ISD::BITCAST, DL, Op1VT, N00), Op1), | 
|  | DAG.getNode(NewOpc, DL, VT, | 
|  | DAG.getNode(ISD::BITCAST, DL, Op1VT, N01), Op1)); | 
|  | } | 
|  |  | 
|  | static SDValue LowerSDIV_v4i8(SDValue X, SDValue Y, const SDLoc &dl, | 
|  | SelectionDAG &DAG) { | 
|  | // TODO: Should this propagate fast-math-flags? | 
|  |  | 
|  | // Convert to float | 
|  | // float4 xf = vcvt_f32_s32(vmovl_s16(a.lo)); | 
|  | // float4 yf = vcvt_f32_s32(vmovl_s16(b.lo)); | 
|  | X = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, X); | 
|  | Y = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, Y); | 
|  | X = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, X); | 
|  | Y = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, Y); | 
|  | // Get reciprocal estimate. | 
|  | // float4 recip = vrecpeq_f32(yf); | 
|  | Y = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, | 
|  | DAG.getConstant(Intrinsic::arm_neon_vrecpe, dl, MVT::i32), | 
|  | Y); | 
|  | // Because char has a smaller range than uchar, we can actually get away | 
|  | // without any newton steps.  This requires that we use a weird bias | 
|  | // of 0xb000, however (again, this has been exhaustively tested). | 
|  | // float4 result = as_float4(as_int4(xf*recip) + 0xb000); | 
|  | X = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, X, Y); | 
|  | X = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, X); | 
|  | Y = DAG.getConstant(0xb000, dl, MVT::v4i32); | 
|  | X = DAG.getNode(ISD::ADD, dl, MVT::v4i32, X, Y); | 
|  | X = DAG.getNode(ISD::BITCAST, dl, MVT::v4f32, X); | 
|  | // Convert back to short. | 
|  | X = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::v4i32, X); | 
|  | X = DAG.getNode(ISD::TRUNCATE, dl, MVT::v4i16, X); | 
|  | return X; | 
|  | } | 
|  |  | 
|  | static SDValue LowerSDIV_v4i16(SDValue N0, SDValue N1, const SDLoc &dl, | 
|  | SelectionDAG &DAG) { | 
|  | // TODO: Should this propagate fast-math-flags? | 
|  |  | 
|  | SDValue N2; | 
|  | // Convert to float. | 
|  | // float4 yf = vcvt_f32_s32(vmovl_s16(y)); | 
|  | // float4 xf = vcvt_f32_s32(vmovl_s16(x)); | 
|  | N0 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, N0); | 
|  | N1 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, N1); | 
|  | N0 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N0); | 
|  | N1 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N1); | 
|  |  | 
|  | // Use reciprocal estimate and one refinement step. | 
|  | // float4 recip = vrecpeq_f32(yf); | 
|  | // recip *= vrecpsq_f32(yf, recip); | 
|  | N2 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, | 
|  | DAG.getConstant(Intrinsic::arm_neon_vrecpe, dl, MVT::i32), | 
|  | N1); | 
|  | N1 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, | 
|  | DAG.getConstant(Intrinsic::arm_neon_vrecps, dl, MVT::i32), | 
|  | N1, N2); | 
|  | N2 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N1, N2); | 
|  | // Because short has a smaller range than ushort, we can actually get away | 
|  | // with only a single newton step.  This requires that we use a weird bias | 
|  | // of 89, however (again, this has been exhaustively tested). | 
|  | // float4 result = as_float4(as_int4(xf*recip) + 0x89); | 
|  | N0 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N0, N2); | 
|  | N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, N0); | 
|  | N1 = DAG.getConstant(0x89, dl, MVT::v4i32); | 
|  | N0 = DAG.getNode(ISD::ADD, dl, MVT::v4i32, N0, N1); | 
|  | N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4f32, N0); | 
|  | // Convert back to integer and return. | 
|  | // return vmovn_s32(vcvt_s32_f32(result)); | 
|  | N0 = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::v4i32, N0); | 
|  | N0 = DAG.getNode(ISD::TRUNCATE, dl, MVT::v4i16, N0); | 
|  | return N0; | 
|  | } | 
|  |  | 
|  | static SDValue LowerSDIV(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | EVT VT = Op.getValueType(); | 
|  | assert((VT == MVT::v4i16 || VT == MVT::v8i8) && | 
|  | "unexpected type for custom-lowering ISD::SDIV"); | 
|  |  | 
|  | SDLoc dl(Op); | 
|  | SDValue N0 = Op.getOperand(0); | 
|  | SDValue N1 = Op.getOperand(1); | 
|  | SDValue N2, N3; | 
|  |  | 
|  | if (VT == MVT::v8i8) { | 
|  | N0 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v8i16, N0); | 
|  | N1 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v8i16, N1); | 
|  |  | 
|  | N2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, | 
|  | DAG.getIntPtrConstant(4, dl)); | 
|  | N3 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, | 
|  | DAG.getIntPtrConstant(4, dl)); | 
|  | N0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, | 
|  | DAG.getIntPtrConstant(0, dl)); | 
|  | N1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, | 
|  | DAG.getIntPtrConstant(0, dl)); | 
|  |  | 
|  | N0 = LowerSDIV_v4i8(N0, N1, dl, DAG); // v4i16 | 
|  | N2 = LowerSDIV_v4i8(N2, N3, dl, DAG); // v4i16 | 
|  |  | 
|  | N0 = DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v8i16, N0, N2); | 
|  | N0 = LowerCONCAT_VECTORS(N0, DAG, ST); | 
|  |  | 
|  | N0 = DAG.getNode(ISD::TRUNCATE, dl, MVT::v8i8, N0); | 
|  | return N0; | 
|  | } | 
|  | return LowerSDIV_v4i16(N0, N1, dl, DAG); | 
|  | } | 
|  |  | 
|  | static SDValue LowerUDIV(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | // TODO: Should this propagate fast-math-flags? | 
|  | EVT VT = Op.getValueType(); | 
|  | assert((VT == MVT::v4i16 || VT == MVT::v8i8) && | 
|  | "unexpected type for custom-lowering ISD::UDIV"); | 
|  |  | 
|  | SDLoc dl(Op); | 
|  | SDValue N0 = Op.getOperand(0); | 
|  | SDValue N1 = Op.getOperand(1); | 
|  | SDValue N2, N3; | 
|  |  | 
|  | if (VT == MVT::v8i8) { | 
|  | N0 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v8i16, N0); | 
|  | N1 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v8i16, N1); | 
|  |  | 
|  | N2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, | 
|  | DAG.getIntPtrConstant(4, dl)); | 
|  | N3 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, | 
|  | DAG.getIntPtrConstant(4, dl)); | 
|  | N0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, | 
|  | DAG.getIntPtrConstant(0, dl)); | 
|  | N1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, | 
|  | DAG.getIntPtrConstant(0, dl)); | 
|  |  | 
|  | N0 = LowerSDIV_v4i16(N0, N1, dl, DAG); // v4i16 | 
|  | N2 = LowerSDIV_v4i16(N2, N3, dl, DAG); // v4i16 | 
|  |  | 
|  | N0 = DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v8i16, N0, N2); | 
|  | N0 = LowerCONCAT_VECTORS(N0, DAG, ST); | 
|  |  | 
|  | N0 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v8i8, | 
|  | DAG.getConstant(Intrinsic::arm_neon_vqmovnsu, dl, | 
|  | MVT::i32), | 
|  | N0); | 
|  | return N0; | 
|  | } | 
|  |  | 
|  | // v4i16 sdiv ... Convert to float. | 
|  | // float4 yf = vcvt_f32_s32(vmovl_u16(y)); | 
|  | // float4 xf = vcvt_f32_s32(vmovl_u16(x)); | 
|  | N0 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v4i32, N0); | 
|  | N1 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v4i32, N1); | 
|  | N0 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N0); | 
|  | SDValue BN1 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N1); | 
|  |  | 
|  | // Use reciprocal estimate and two refinement steps. | 
|  | // float4 recip = vrecpeq_f32(yf); | 
|  | // recip *= vrecpsq_f32(yf, recip); | 
|  | // recip *= vrecpsq_f32(yf, recip); | 
|  | N2 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, | 
|  | DAG.getConstant(Intrinsic::arm_neon_vrecpe, dl, MVT::i32), | 
|  | BN1); | 
|  | N1 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, | 
|  | DAG.getConstant(Intrinsic::arm_neon_vrecps, dl, MVT::i32), | 
|  | BN1, N2); | 
|  | N2 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N1, N2); | 
|  | N1 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, | 
|  | DAG.getConstant(Intrinsic::arm_neon_vrecps, dl, MVT::i32), | 
|  | BN1, N2); | 
|  | N2 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N1, N2); | 
|  | // Simply multiplying by the reciprocal estimate can leave us a few ulps | 
|  | // too low, so we add 2 ulps (exhaustive testing shows that this is enough, | 
|  | // and that it will never cause us to return an answer too large). | 
|  | // float4 result = as_float4(as_int4(xf*recip) + 2); | 
|  | N0 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N0, N2); | 
|  | N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, N0); | 
|  | N1 = DAG.getConstant(2, dl, MVT::v4i32); | 
|  | N0 = DAG.getNode(ISD::ADD, dl, MVT::v4i32, N0, N1); | 
|  | N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4f32, N0); | 
|  | // Convert back to integer and return. | 
|  | // return vmovn_u32(vcvt_s32_f32(result)); | 
|  | N0 = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::v4i32, N0); | 
|  | N0 = DAG.getNode(ISD::TRUNCATE, dl, MVT::v4i16, N0); | 
|  | return N0; | 
|  | } | 
|  |  | 
|  | static SDValue LowerADDSUBCARRY(SDValue Op, SelectionDAG &DAG) { | 
|  | SDNode *N = Op.getNode(); | 
|  | EVT VT = N->getValueType(0); | 
|  | SDVTList VTs = DAG.getVTList(VT, MVT::i32); | 
|  |  | 
|  | SDValue Carry = Op.getOperand(2); | 
|  |  | 
|  | SDLoc DL(Op); | 
|  |  | 
|  | SDValue Result; | 
|  | if (Op.getOpcode() == ISD::ADDCARRY) { | 
|  | // This converts the boolean value carry into the carry flag. | 
|  | Carry = ConvertBooleanCarryToCarryFlag(Carry, DAG); | 
|  |  | 
|  | // Do the addition proper using the carry flag we wanted. | 
|  | Result = DAG.getNode(ARMISD::ADDE, DL, VTs, Op.getOperand(0), | 
|  | Op.getOperand(1), Carry); | 
|  |  | 
|  | // Now convert the carry flag into a boolean value. | 
|  | Carry = ConvertCarryFlagToBooleanCarry(Result.getValue(1), VT, DAG); | 
|  | } else { | 
|  | // ARMISD::SUBE expects a carry not a borrow like ISD::SUBCARRY so we | 
|  | // have to invert the carry first. | 
|  | Carry = DAG.getNode(ISD::SUB, DL, MVT::i32, | 
|  | DAG.getConstant(1, DL, MVT::i32), Carry); | 
|  | // This converts the boolean value carry into the carry flag. | 
|  | Carry = ConvertBooleanCarryToCarryFlag(Carry, DAG); | 
|  |  | 
|  | // Do the subtraction proper using the carry flag we wanted. | 
|  | Result = DAG.getNode(ARMISD::SUBE, DL, VTs, Op.getOperand(0), | 
|  | Op.getOperand(1), Carry); | 
|  |  | 
|  | // Now convert the carry flag into a boolean value. | 
|  | Carry = ConvertCarryFlagToBooleanCarry(Result.getValue(1), VT, DAG); | 
|  | // But the carry returned by ARMISD::SUBE is not a borrow as expected | 
|  | // by ISD::SUBCARRY, so compute 1 - C. | 
|  | Carry = DAG.getNode(ISD::SUB, DL, MVT::i32, | 
|  | DAG.getConstant(1, DL, MVT::i32), Carry); | 
|  | } | 
|  |  | 
|  | // Return both values. | 
|  | return DAG.getNode(ISD::MERGE_VALUES, DL, N->getVTList(), Result, Carry); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerFSINCOS(SDValue Op, SelectionDAG &DAG) const { | 
|  | assert(Subtarget->isTargetDarwin()); | 
|  |  | 
|  | // For iOS, we want to call an alternative entry point: __sincos_stret, | 
|  | // return values are passed via sret. | 
|  | SDLoc dl(Op); | 
|  | SDValue Arg = Op.getOperand(0); | 
|  | EVT ArgVT = Arg.getValueType(); | 
|  | Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); | 
|  | auto PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  |  | 
|  | MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  |  | 
|  | // Pair of floats / doubles used to pass the result. | 
|  | Type *RetTy = StructType::get(ArgTy, ArgTy); | 
|  | auto &DL = DAG.getDataLayout(); | 
|  |  | 
|  | ArgListTy Args; | 
|  | bool ShouldUseSRet = Subtarget->isAPCS_ABI(); | 
|  | SDValue SRet; | 
|  | if (ShouldUseSRet) { | 
|  | // Create stack object for sret. | 
|  | const uint64_t ByteSize = DL.getTypeAllocSize(RetTy); | 
|  | const unsigned StackAlign = DL.getPrefTypeAlignment(RetTy); | 
|  | int FrameIdx = MFI.CreateStackObject(ByteSize, StackAlign, false); | 
|  | SRet = DAG.getFrameIndex(FrameIdx, TLI.getPointerTy(DL)); | 
|  |  | 
|  | ArgListEntry Entry; | 
|  | Entry.Node = SRet; | 
|  | Entry.Ty = RetTy->getPointerTo(); | 
|  | Entry.IsSExt = false; | 
|  | Entry.IsZExt = false; | 
|  | Entry.IsSRet = true; | 
|  | Args.push_back(Entry); | 
|  | RetTy = Type::getVoidTy(*DAG.getContext()); | 
|  | } | 
|  |  | 
|  | ArgListEntry Entry; | 
|  | Entry.Node = Arg; | 
|  | Entry.Ty = ArgTy; | 
|  | Entry.IsSExt = false; | 
|  | Entry.IsZExt = false; | 
|  | Args.push_back(Entry); | 
|  |  | 
|  | RTLIB::Libcall LC = | 
|  | (ArgVT == MVT::f64) ? RTLIB::SINCOS_STRET_F64 : RTLIB::SINCOS_STRET_F32; | 
|  | const char *LibcallName = getLibcallName(LC); | 
|  | CallingConv::ID CC = getLibcallCallingConv(LC); | 
|  | SDValue Callee = DAG.getExternalSymbol(LibcallName, getPointerTy(DL)); | 
|  |  | 
|  | TargetLowering::CallLoweringInfo CLI(DAG); | 
|  | CLI.setDebugLoc(dl) | 
|  | .setChain(DAG.getEntryNode()) | 
|  | .setCallee(CC, RetTy, Callee, std::move(Args)) | 
|  | .setDiscardResult(ShouldUseSRet); | 
|  | std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI); | 
|  |  | 
|  | if (!ShouldUseSRet) | 
|  | return CallResult.first; | 
|  |  | 
|  | SDValue LoadSin = | 
|  | DAG.getLoad(ArgVT, dl, CallResult.second, SRet, MachinePointerInfo()); | 
|  |  | 
|  | // Address of cos field. | 
|  | SDValue Add = DAG.getNode(ISD::ADD, dl, PtrVT, SRet, | 
|  | DAG.getIntPtrConstant(ArgVT.getStoreSize(), dl)); | 
|  | SDValue LoadCos = | 
|  | DAG.getLoad(ArgVT, dl, LoadSin.getValue(1), Add, MachinePointerInfo()); | 
|  |  | 
|  | SDVTList Tys = DAG.getVTList(ArgVT, ArgVT); | 
|  | return DAG.getNode(ISD::MERGE_VALUES, dl, Tys, | 
|  | LoadSin.getValue(0), LoadCos.getValue(0)); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerWindowsDIVLibCall(SDValue Op, SelectionDAG &DAG, | 
|  | bool Signed, | 
|  | SDValue &Chain) const { | 
|  | EVT VT = Op.getValueType(); | 
|  | assert((VT == MVT::i32 || VT == MVT::i64) && | 
|  | "unexpected type for custom lowering DIV"); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | const auto &DL = DAG.getDataLayout(); | 
|  | const auto &TLI = DAG.getTargetLoweringInfo(); | 
|  |  | 
|  | const char *Name = nullptr; | 
|  | if (Signed) | 
|  | Name = (VT == MVT::i32) ? "__rt_sdiv" : "__rt_sdiv64"; | 
|  | else | 
|  | Name = (VT == MVT::i32) ? "__rt_udiv" : "__rt_udiv64"; | 
|  |  | 
|  | SDValue ES = DAG.getExternalSymbol(Name, TLI.getPointerTy(DL)); | 
|  |  | 
|  | ARMTargetLowering::ArgListTy Args; | 
|  |  | 
|  | for (auto AI : {1, 0}) { | 
|  | ArgListEntry Arg; | 
|  | Arg.Node = Op.getOperand(AI); | 
|  | Arg.Ty = Arg.Node.getValueType().getTypeForEVT(*DAG.getContext()); | 
|  | Args.push_back(Arg); | 
|  | } | 
|  |  | 
|  | CallLoweringInfo CLI(DAG); | 
|  | CLI.setDebugLoc(dl) | 
|  | .setChain(Chain) | 
|  | .setCallee(CallingConv::ARM_AAPCS_VFP, VT.getTypeForEVT(*DAG.getContext()), | 
|  | ES, std::move(Args)); | 
|  |  | 
|  | return LowerCallTo(CLI).first; | 
|  | } | 
|  |  | 
|  | // This is a code size optimisation: return the original SDIV node to | 
|  | // DAGCombiner when we don't want to expand SDIV into a sequence of | 
|  | // instructions, and an empty node otherwise which will cause the | 
|  | // SDIV to be expanded in DAGCombine. | 
|  | SDValue | 
|  | ARMTargetLowering::BuildSDIVPow2(SDNode *N, const APInt &Divisor, | 
|  | SelectionDAG &DAG, | 
|  | SmallVectorImpl<SDNode *> &Created) const { | 
|  | // TODO: Support SREM | 
|  | if (N->getOpcode() != ISD::SDIV) | 
|  | return SDValue(); | 
|  |  | 
|  | const auto &ST = static_cast<const ARMSubtarget&>(DAG.getSubtarget()); | 
|  | const bool MinSize = ST.hasMinSize(); | 
|  | const bool HasDivide = ST.isThumb() ? ST.hasDivideInThumbMode() | 
|  | : ST.hasDivideInARMMode(); | 
|  |  | 
|  | // Don't touch vector types; rewriting this may lead to scalarizing | 
|  | // the int divs. | 
|  | if (N->getOperand(0).getValueType().isVector()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Bail if MinSize is not set, and also for both ARM and Thumb mode we need | 
|  | // hwdiv support for this to be really profitable. | 
|  | if (!(MinSize && HasDivide)) | 
|  | return SDValue(); | 
|  |  | 
|  | // ARM mode is a bit simpler than Thumb: we can handle large power | 
|  | // of 2 immediates with 1 mov instruction; no further checks required, | 
|  | // just return the sdiv node. | 
|  | if (!ST.isThumb()) | 
|  | return SDValue(N, 0); | 
|  |  | 
|  | // In Thumb mode, immediates larger than 128 need a wide 4-byte MOV, | 
|  | // and thus lose the code size benefits of a MOVS that requires only 2. | 
|  | // TargetTransformInfo and 'getIntImmCodeSizeCost' could be helpful here, | 
|  | // but as it's doing exactly this, it's not worth the trouble to get TTI. | 
|  | if (Divisor.sgt(128)) | 
|  | return SDValue(); | 
|  |  | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerDIV_Windows(SDValue Op, SelectionDAG &DAG, | 
|  | bool Signed) const { | 
|  | assert(Op.getValueType() == MVT::i32 && | 
|  | "unexpected type for custom lowering DIV"); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | SDValue DBZCHK = DAG.getNode(ARMISD::WIN__DBZCHK, dl, MVT::Other, | 
|  | DAG.getEntryNode(), Op.getOperand(1)); | 
|  |  | 
|  | return LowerWindowsDIVLibCall(Op, DAG, Signed, DBZCHK); | 
|  | } | 
|  |  | 
|  | static SDValue WinDBZCheckDenominator(SelectionDAG &DAG, SDNode *N, SDValue InChain) { | 
|  | SDLoc DL(N); | 
|  | SDValue Op = N->getOperand(1); | 
|  | if (N->getValueType(0) == MVT::i32) | 
|  | return DAG.getNode(ARMISD::WIN__DBZCHK, DL, MVT::Other, InChain, Op); | 
|  | SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, Op, | 
|  | DAG.getConstant(0, DL, MVT::i32)); | 
|  | SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, Op, | 
|  | DAG.getConstant(1, DL, MVT::i32)); | 
|  | return DAG.getNode(ARMISD::WIN__DBZCHK, DL, MVT::Other, InChain, | 
|  | DAG.getNode(ISD::OR, DL, MVT::i32, Lo, Hi)); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::ExpandDIV_Windows( | 
|  | SDValue Op, SelectionDAG &DAG, bool Signed, | 
|  | SmallVectorImpl<SDValue> &Results) const { | 
|  | const auto &DL = DAG.getDataLayout(); | 
|  | const auto &TLI = DAG.getTargetLoweringInfo(); | 
|  |  | 
|  | assert(Op.getValueType() == MVT::i64 && | 
|  | "unexpected type for custom lowering DIV"); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | SDValue DBZCHK = WinDBZCheckDenominator(DAG, Op.getNode(), DAG.getEntryNode()); | 
|  |  | 
|  | SDValue Result = LowerWindowsDIVLibCall(Op, DAG, Signed, DBZCHK); | 
|  |  | 
|  | SDValue Lower = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Result); | 
|  | SDValue Upper = DAG.getNode(ISD::SRL, dl, MVT::i64, Result, | 
|  | DAG.getConstant(32, dl, TLI.getPointerTy(DL))); | 
|  | Upper = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Upper); | 
|  |  | 
|  | Results.push_back(DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lower, Upper)); | 
|  | } | 
|  |  | 
|  | static SDValue LowerPredicateLoad(SDValue Op, SelectionDAG &DAG) { | 
|  | LoadSDNode *LD = cast<LoadSDNode>(Op.getNode()); | 
|  | EVT MemVT = LD->getMemoryVT(); | 
|  | assert((MemVT == MVT::v4i1 || MemVT == MVT::v8i1 || MemVT == MVT::v16i1) && | 
|  | "Expected a predicate type!"); | 
|  | assert(MemVT == Op.getValueType()); | 
|  | assert(LD->getExtensionType() == ISD::NON_EXTLOAD && | 
|  | "Expected a non-extending load"); | 
|  | assert(LD->isUnindexed() && "Expected a unindexed load"); | 
|  |  | 
|  | // The basic MVE VLDR on a v4i1/v8i1 actually loads the entire 16bit | 
|  | // predicate, with the "v4i1" bits spread out over the 16 bits loaded. We | 
|  | // need to make sure that 8/4 bits are actually loaded into the correct | 
|  | // place, which means loading the value and then shuffling the values into | 
|  | // the bottom bits of the predicate. | 
|  | // Equally, VLDR for an v16i1 will actually load 32bits (so will be incorrect | 
|  | // for BE). | 
|  |  | 
|  | SDLoc dl(Op); | 
|  | SDValue Load = DAG.getExtLoad( | 
|  | ISD::EXTLOAD, dl, MVT::i32, LD->getChain(), LD->getBasePtr(), | 
|  | EVT::getIntegerVT(*DAG.getContext(), MemVT.getSizeInBits()), | 
|  | LD->getMemOperand()); | 
|  | SDValue Pred = DAG.getNode(ARMISD::PREDICATE_CAST, dl, MVT::v16i1, Load); | 
|  | if (MemVT != MVT::v16i1) | 
|  | Pred = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MemVT, Pred, | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | return DAG.getMergeValues({Pred, Load.getValue(1)}, dl); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::LowerLOAD(SDNode *N, SmallVectorImpl<SDValue> &Results, | 
|  | SelectionDAG &DAG) const { | 
|  | LoadSDNode *LD = cast<LoadSDNode>(N); | 
|  | EVT MemVT = LD->getMemoryVT(); | 
|  | assert(LD->isUnindexed() && "Loads should be unindexed at this point."); | 
|  |  | 
|  | if (MemVT == MVT::i64 && Subtarget->hasV5TEOps() && | 
|  | !Subtarget->isThumb1Only() && LD->isVolatile()) { | 
|  | SDLoc dl(N); | 
|  | SDValue Result = DAG.getMemIntrinsicNode( | 
|  | ARMISD::LDRD, dl, DAG.getVTList({MVT::i32, MVT::i32, MVT::Other}), | 
|  | {LD->getChain(), LD->getBasePtr()}, MemVT, LD->getMemOperand()); | 
|  | SDValue Lo = Result.getValue(DAG.getDataLayout().isLittleEndian() ? 0 : 1); | 
|  | SDValue Hi = Result.getValue(DAG.getDataLayout().isLittleEndian() ? 1 : 0); | 
|  | SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi); | 
|  | Results.append({Pair, Result.getValue(2)}); | 
|  | } | 
|  | } | 
|  |  | 
|  | static SDValue LowerPredicateStore(SDValue Op, SelectionDAG &DAG) { | 
|  | StoreSDNode *ST = cast<StoreSDNode>(Op.getNode()); | 
|  | EVT MemVT = ST->getMemoryVT(); | 
|  | assert((MemVT == MVT::v4i1 || MemVT == MVT::v8i1 || MemVT == MVT::v16i1) && | 
|  | "Expected a predicate type!"); | 
|  | assert(MemVT == ST->getValue().getValueType()); | 
|  | assert(!ST->isTruncatingStore() && "Expected a non-extending store"); | 
|  | assert(ST->isUnindexed() && "Expected a unindexed store"); | 
|  |  | 
|  | // Only store the v4i1 or v8i1 worth of bits, via a buildvector with top bits | 
|  | // unset and a scalar store. | 
|  | SDLoc dl(Op); | 
|  | SDValue Build = ST->getValue(); | 
|  | if (MemVT != MVT::v16i1) { | 
|  | SmallVector<SDValue, 16> Ops; | 
|  | for (unsigned I = 0; I < MemVT.getVectorNumElements(); I++) | 
|  | Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i32, Build, | 
|  | DAG.getConstant(I, dl, MVT::i32))); | 
|  | for (unsigned I = MemVT.getVectorNumElements(); I < 16; I++) | 
|  | Ops.push_back(DAG.getUNDEF(MVT::i32)); | 
|  | Build = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v16i1, Ops); | 
|  | } | 
|  | SDValue GRP = DAG.getNode(ARMISD::PREDICATE_CAST, dl, MVT::i32, Build); | 
|  | return DAG.getTruncStore( | 
|  | ST->getChain(), dl, GRP, ST->getBasePtr(), | 
|  | EVT::getIntegerVT(*DAG.getContext(), MemVT.getSizeInBits()), | 
|  | ST->getMemOperand()); | 
|  | } | 
|  |  | 
|  | static SDValue LowerSTORE(SDValue Op, SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | StoreSDNode *ST = cast<StoreSDNode>(Op.getNode()); | 
|  | EVT MemVT = ST->getMemoryVT(); | 
|  | assert(ST->isUnindexed() && "Stores should be unindexed at this point."); | 
|  |  | 
|  | if (MemVT == MVT::i64 && Subtarget->hasV5TEOps() && | 
|  | !Subtarget->isThumb1Only() && ST->isVolatile()) { | 
|  | SDNode *N = Op.getNode(); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | SDValue Lo = DAG.getNode( | 
|  | ISD::EXTRACT_ELEMENT, dl, MVT::i32, ST->getValue(), | 
|  | DAG.getTargetConstant(DAG.getDataLayout().isLittleEndian() ? 0 : 1, dl, | 
|  | MVT::i32)); | 
|  | SDValue Hi = DAG.getNode( | 
|  | ISD::EXTRACT_ELEMENT, dl, MVT::i32, ST->getValue(), | 
|  | DAG.getTargetConstant(DAG.getDataLayout().isLittleEndian() ? 1 : 0, dl, | 
|  | MVT::i32)); | 
|  |  | 
|  | return DAG.getMemIntrinsicNode(ARMISD::STRD, dl, DAG.getVTList(MVT::Other), | 
|  | {ST->getChain(), Lo, Hi, ST->getBasePtr()}, | 
|  | MemVT, ST->getMemOperand()); | 
|  | } else if (Subtarget->hasMVEIntegerOps() && | 
|  | ((MemVT == MVT::v4i1 || MemVT == MVT::v8i1 || | 
|  | MemVT == MVT::v16i1))) { | 
|  | return LowerPredicateStore(Op, DAG); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static bool isZeroVector(SDValue N) { | 
|  | return (ISD::isBuildVectorAllZeros(N.getNode()) || | 
|  | (N->getOpcode() == ARMISD::VMOVIMM && | 
|  | isNullConstant(N->getOperand(0)))); | 
|  | } | 
|  |  | 
|  | static SDValue LowerMLOAD(SDValue Op, SelectionDAG &DAG) { | 
|  | MaskedLoadSDNode *N = cast<MaskedLoadSDNode>(Op.getNode()); | 
|  | MVT VT = Op.getSimpleValueType(); | 
|  | SDValue Mask = N->getMask(); | 
|  | SDValue PassThru = N->getPassThru(); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | if (isZeroVector(PassThru)) | 
|  | return Op; | 
|  |  | 
|  | // MVE Masked loads use zero as the passthru value. Here we convert undef to | 
|  | // zero too, and other values are lowered to a select. | 
|  | SDValue ZeroVec = DAG.getNode(ARMISD::VMOVIMM, dl, VT, | 
|  | DAG.getTargetConstant(0, dl, MVT::i32)); | 
|  | SDValue NewLoad = DAG.getMaskedLoad( | 
|  | VT, dl, N->getChain(), N->getBasePtr(), N->getOffset(), Mask, ZeroVec, | 
|  | N->getMemoryVT(), N->getMemOperand(), N->getAddressingMode(), | 
|  | N->getExtensionType(), N->isExpandingLoad()); | 
|  | SDValue Combo = NewLoad; | 
|  | bool PassThruIsCastZero = (PassThru.getOpcode() == ISD::BITCAST || | 
|  | PassThru.getOpcode() == ARMISD::VECTOR_REG_CAST) && | 
|  | isZeroVector(PassThru->getOperand(0)); | 
|  | if (!PassThru.isUndef() && !PassThruIsCastZero) | 
|  | Combo = DAG.getNode(ISD::VSELECT, dl, VT, Mask, NewLoad, PassThru); | 
|  | return DAG.getMergeValues({Combo, NewLoad.getValue(1)}, dl); | 
|  | } | 
|  |  | 
|  | static SDValue LowerAtomicLoadStore(SDValue Op, SelectionDAG &DAG) { | 
|  | if (isStrongerThanMonotonic(cast<AtomicSDNode>(Op)->getOrdering())) | 
|  | // Acquire/Release load/store is not legal for targets without a dmb or | 
|  | // equivalent available. | 
|  | return SDValue(); | 
|  |  | 
|  | // Monotonic load/store is legal for all targets. | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | static void ReplaceREADCYCLECOUNTER(SDNode *N, | 
|  | SmallVectorImpl<SDValue> &Results, | 
|  | SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | SDLoc DL(N); | 
|  | // Under Power Management extensions, the cycle-count is: | 
|  | //    mrc p15, #0, <Rt>, c9, c13, #0 | 
|  | SDValue Ops[] = { N->getOperand(0), // Chain | 
|  | DAG.getTargetConstant(Intrinsic::arm_mrc, DL, MVT::i32), | 
|  | DAG.getTargetConstant(15, DL, MVT::i32), | 
|  | DAG.getTargetConstant(0, DL, MVT::i32), | 
|  | DAG.getTargetConstant(9, DL, MVT::i32), | 
|  | DAG.getTargetConstant(13, DL, MVT::i32), | 
|  | DAG.getTargetConstant(0, DL, MVT::i32) | 
|  | }; | 
|  |  | 
|  | SDValue Cycles32 = DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL, | 
|  | DAG.getVTList(MVT::i32, MVT::Other), Ops); | 
|  | Results.push_back(DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Cycles32, | 
|  | DAG.getConstant(0, DL, MVT::i32))); | 
|  | Results.push_back(Cycles32.getValue(1)); | 
|  | } | 
|  |  | 
|  | static SDValue createGPRPairNode(SelectionDAG &DAG, SDValue V) { | 
|  | SDLoc dl(V.getNode()); | 
|  | SDValue VLo = DAG.getAnyExtOrTrunc(V, dl, MVT::i32); | 
|  | SDValue VHi = DAG.getAnyExtOrTrunc( | 
|  | DAG.getNode(ISD::SRL, dl, MVT::i64, V, DAG.getConstant(32, dl, MVT::i32)), | 
|  | dl, MVT::i32); | 
|  | bool isBigEndian = DAG.getDataLayout().isBigEndian(); | 
|  | if (isBigEndian) | 
|  | std::swap (VLo, VHi); | 
|  | SDValue RegClass = | 
|  | DAG.getTargetConstant(ARM::GPRPairRegClassID, dl, MVT::i32); | 
|  | SDValue SubReg0 = DAG.getTargetConstant(ARM::gsub_0, dl, MVT::i32); | 
|  | SDValue SubReg1 = DAG.getTargetConstant(ARM::gsub_1, dl, MVT::i32); | 
|  | const SDValue Ops[] = { RegClass, VLo, SubReg0, VHi, SubReg1 }; | 
|  | return SDValue( | 
|  | DAG.getMachineNode(TargetOpcode::REG_SEQUENCE, dl, MVT::Untyped, Ops), 0); | 
|  | } | 
|  |  | 
|  | static void ReplaceCMP_SWAP_64Results(SDNode *N, | 
|  | SmallVectorImpl<SDValue> & Results, | 
|  | SelectionDAG &DAG) { | 
|  | assert(N->getValueType(0) == MVT::i64 && | 
|  | "AtomicCmpSwap on types less than 64 should be legal"); | 
|  | SDValue Ops[] = {N->getOperand(1), | 
|  | createGPRPairNode(DAG, N->getOperand(2)), | 
|  | createGPRPairNode(DAG, N->getOperand(3)), | 
|  | N->getOperand(0)}; | 
|  | SDNode *CmpSwap = DAG.getMachineNode( | 
|  | ARM::CMP_SWAP_64, SDLoc(N), | 
|  | DAG.getVTList(MVT::Untyped, MVT::i32, MVT::Other), Ops); | 
|  |  | 
|  | MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand(); | 
|  | DAG.setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp}); | 
|  |  | 
|  | bool isBigEndian = DAG.getDataLayout().isBigEndian(); | 
|  |  | 
|  | SDValue Lo = | 
|  | DAG.getTargetExtractSubreg(isBigEndian ? ARM::gsub_1 : ARM::gsub_0, | 
|  | SDLoc(N), MVT::i32, SDValue(CmpSwap, 0)); | 
|  | SDValue Hi = | 
|  | DAG.getTargetExtractSubreg(isBigEndian ? ARM::gsub_0 : ARM::gsub_1, | 
|  | SDLoc(N), MVT::i32, SDValue(CmpSwap, 0)); | 
|  | Results.push_back(DAG.getNode(ISD::BUILD_PAIR, SDLoc(N), MVT::i64, Lo, Hi)); | 
|  | Results.push_back(SDValue(CmpSwap, 2)); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerFSETCC(SDValue Op, SelectionDAG &DAG) const { | 
|  | SDLoc dl(Op); | 
|  | EVT VT = Op.getValueType(); | 
|  | SDValue Chain = Op.getOperand(0); | 
|  | SDValue LHS = Op.getOperand(1); | 
|  | SDValue RHS = Op.getOperand(2); | 
|  | ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(3))->get(); | 
|  | bool IsSignaling = Op.getOpcode() == ISD::STRICT_FSETCCS; | 
|  |  | 
|  | // If we don't have instructions of this float type then soften to a libcall | 
|  | // and use SETCC instead. | 
|  | if (isUnsupportedFloatingType(LHS.getValueType())) { | 
|  | DAG.getTargetLoweringInfo().softenSetCCOperands( | 
|  | DAG, LHS.getValueType(), LHS, RHS, CC, dl, LHS, RHS, Chain, IsSignaling); | 
|  | if (!RHS.getNode()) { | 
|  | RHS = DAG.getConstant(0, dl, LHS.getValueType()); | 
|  | CC = ISD::SETNE; | 
|  | } | 
|  | SDValue Result = DAG.getNode(ISD::SETCC, dl, VT, LHS, RHS, | 
|  | DAG.getCondCode(CC)); | 
|  | return DAG.getMergeValues({Result, Chain}, dl); | 
|  | } | 
|  |  | 
|  | ARMCC::CondCodes CondCode, CondCode2; | 
|  | FPCCToARMCC(CC, CondCode, CondCode2); | 
|  |  | 
|  | // FIXME: Chain is not handled correctly here. Currently the FPSCR is implicit | 
|  | // in CMPFP and CMPFPE, but instead it should be made explicit by these | 
|  | // instructions using a chain instead of glue. This would also fix the problem | 
|  | // here (and also in LowerSELECT_CC) where we generate two comparisons when | 
|  | // CondCode2 != AL. | 
|  | SDValue True = DAG.getConstant(1, dl, VT); | 
|  | SDValue False =  DAG.getConstant(0, dl, VT); | 
|  | SDValue ARMcc = DAG.getConstant(CondCode, dl, MVT::i32); | 
|  | SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); | 
|  | SDValue Cmp = getVFPCmp(LHS, RHS, DAG, dl, IsSignaling); | 
|  | SDValue Result = getCMOV(dl, VT, False, True, ARMcc, CCR, Cmp, DAG); | 
|  | if (CondCode2 != ARMCC::AL) { | 
|  | ARMcc = DAG.getConstant(CondCode2, dl, MVT::i32); | 
|  | Cmp = getVFPCmp(LHS, RHS, DAG, dl, IsSignaling); | 
|  | Result = getCMOV(dl, VT, Result, True, ARMcc, CCR, Cmp, DAG); | 
|  | } | 
|  | return DAG.getMergeValues({Result, Chain}, dl); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { | 
|  | LLVM_DEBUG(dbgs() << "Lowering node: "; Op.dump()); | 
|  | switch (Op.getOpcode()) { | 
|  | default: llvm_unreachable("Don't know how to custom lower this!"); | 
|  | case ISD::WRITE_REGISTER: return LowerWRITE_REGISTER(Op, DAG); | 
|  | case ISD::ConstantPool: return LowerConstantPool(Op, DAG); | 
|  | case ISD::BlockAddress:  return LowerBlockAddress(Op, DAG); | 
|  | case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); | 
|  | case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); | 
|  | case ISD::SELECT:        return LowerSELECT(Op, DAG); | 
|  | case ISD::SELECT_CC:     return LowerSELECT_CC(Op, DAG); | 
|  | case ISD::BRCOND:        return LowerBRCOND(Op, DAG); | 
|  | case ISD::BR_CC:         return LowerBR_CC(Op, DAG); | 
|  | case ISD::BR_JT:         return LowerBR_JT(Op, DAG); | 
|  | case ISD::VASTART:       return LowerVASTART(Op, DAG); | 
|  | case ISD::ATOMIC_FENCE:  return LowerATOMIC_FENCE(Op, DAG, Subtarget); | 
|  | case ISD::PREFETCH:      return LowerPREFETCH(Op, DAG, Subtarget); | 
|  | case ISD::SINT_TO_FP: | 
|  | case ISD::UINT_TO_FP:    return LowerINT_TO_FP(Op, DAG); | 
|  | case ISD::STRICT_FP_TO_SINT: | 
|  | case ISD::STRICT_FP_TO_UINT: | 
|  | case ISD::FP_TO_SINT: | 
|  | case ISD::FP_TO_UINT:    return LowerFP_TO_INT(Op, DAG); | 
|  | case ISD::FCOPYSIGN:     return LowerFCOPYSIGN(Op, DAG); | 
|  | case ISD::RETURNADDR:    return LowerRETURNADDR(Op, DAG); | 
|  | case ISD::FRAMEADDR:     return LowerFRAMEADDR(Op, DAG); | 
|  | case ISD::EH_SJLJ_SETJMP: return LowerEH_SJLJ_SETJMP(Op, DAG); | 
|  | case ISD::EH_SJLJ_LONGJMP: return LowerEH_SJLJ_LONGJMP(Op, DAG); | 
|  | case ISD::EH_SJLJ_SETUP_DISPATCH: return LowerEH_SJLJ_SETUP_DISPATCH(Op, DAG); | 
|  | case ISD::INTRINSIC_VOID: return LowerINTRINSIC_VOID(Op, DAG, Subtarget); | 
|  | case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG, | 
|  | Subtarget); | 
|  | case ISD::BITCAST:       return ExpandBITCAST(Op.getNode(), DAG, Subtarget); | 
|  | case ISD::SHL: | 
|  | case ISD::SRL: | 
|  | case ISD::SRA:           return LowerShift(Op.getNode(), DAG, Subtarget); | 
|  | case ISD::SREM:          return LowerREM(Op.getNode(), DAG); | 
|  | case ISD::UREM:          return LowerREM(Op.getNode(), DAG); | 
|  | case ISD::SHL_PARTS:     return LowerShiftLeftParts(Op, DAG); | 
|  | case ISD::SRL_PARTS: | 
|  | case ISD::SRA_PARTS:     return LowerShiftRightParts(Op, DAG); | 
|  | case ISD::CTTZ: | 
|  | case ISD::CTTZ_ZERO_UNDEF: return LowerCTTZ(Op.getNode(), DAG, Subtarget); | 
|  | case ISD::CTPOP:         return LowerCTPOP(Op.getNode(), DAG, Subtarget); | 
|  | case ISD::SETCC:         return LowerVSETCC(Op, DAG, Subtarget); | 
|  | case ISD::SETCCCARRY:    return LowerSETCCCARRY(Op, DAG); | 
|  | case ISD::ConstantFP:    return LowerConstantFP(Op, DAG, Subtarget); | 
|  | case ISD::BUILD_VECTOR:  return LowerBUILD_VECTOR(Op, DAG, Subtarget); | 
|  | case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG, Subtarget); | 
|  | case ISD::EXTRACT_SUBVECTOR: return LowerEXTRACT_SUBVECTOR(Op, DAG, Subtarget); | 
|  | case ISD::INSERT_VECTOR_ELT: return LowerINSERT_VECTOR_ELT(Op, DAG); | 
|  | case ISD::EXTRACT_VECTOR_ELT: return LowerEXTRACT_VECTOR_ELT(Op, DAG, Subtarget); | 
|  | case ISD::CONCAT_VECTORS: return LowerCONCAT_VECTORS(Op, DAG, Subtarget); | 
|  | case ISD::FLT_ROUNDS_:   return LowerFLT_ROUNDS_(Op, DAG); | 
|  | case ISD::MUL:           return LowerMUL(Op, DAG); | 
|  | case ISD::SDIV: | 
|  | if (Subtarget->isTargetWindows() && !Op.getValueType().isVector()) | 
|  | return LowerDIV_Windows(Op, DAG, /* Signed */ true); | 
|  | return LowerSDIV(Op, DAG, Subtarget); | 
|  | case ISD::UDIV: | 
|  | if (Subtarget->isTargetWindows() && !Op.getValueType().isVector()) | 
|  | return LowerDIV_Windows(Op, DAG, /* Signed */ false); | 
|  | return LowerUDIV(Op, DAG, Subtarget); | 
|  | case ISD::ADDCARRY: | 
|  | case ISD::SUBCARRY:      return LowerADDSUBCARRY(Op, DAG); | 
|  | case ISD::SADDO: | 
|  | case ISD::SSUBO: | 
|  | return LowerSignedALUO(Op, DAG); | 
|  | case ISD::UADDO: | 
|  | case ISD::USUBO: | 
|  | return LowerUnsignedALUO(Op, DAG); | 
|  | case ISD::SADDSAT: | 
|  | case ISD::SSUBSAT: | 
|  | return LowerSADDSUBSAT(Op, DAG, Subtarget); | 
|  | case ISD::LOAD: | 
|  | return LowerPredicateLoad(Op, DAG); | 
|  | case ISD::STORE: | 
|  | return LowerSTORE(Op, DAG, Subtarget); | 
|  | case ISD::MLOAD: | 
|  | return LowerMLOAD(Op, DAG); | 
|  | case ISD::ATOMIC_LOAD: | 
|  | case ISD::ATOMIC_STORE:  return LowerAtomicLoadStore(Op, DAG); | 
|  | case ISD::FSINCOS:       return LowerFSINCOS(Op, DAG); | 
|  | case ISD::SDIVREM: | 
|  | case ISD::UDIVREM:       return LowerDivRem(Op, DAG); | 
|  | case ISD::DYNAMIC_STACKALLOC: | 
|  | if (Subtarget->isTargetWindows()) | 
|  | return LowerDYNAMIC_STACKALLOC(Op, DAG); | 
|  | llvm_unreachable("Don't know how to custom lower this!"); | 
|  | case ISD::STRICT_FP_ROUND: | 
|  | case ISD::FP_ROUND: return LowerFP_ROUND(Op, DAG); | 
|  | case ISD::STRICT_FP_EXTEND: | 
|  | case ISD::FP_EXTEND: return LowerFP_EXTEND(Op, DAG); | 
|  | case ISD::STRICT_FSETCC: | 
|  | case ISD::STRICT_FSETCCS: return LowerFSETCC(Op, DAG); | 
|  | case ARMISD::WIN__DBZCHK: return SDValue(); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void ReplaceLongIntrinsic(SDNode *N, SmallVectorImpl<SDValue> &Results, | 
|  | SelectionDAG &DAG) { | 
|  | unsigned IntNo = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue(); | 
|  | unsigned Opc = 0; | 
|  | if (IntNo == Intrinsic::arm_smlald) | 
|  | Opc = ARMISD::SMLALD; | 
|  | else if (IntNo == Intrinsic::arm_smlaldx) | 
|  | Opc = ARMISD::SMLALDX; | 
|  | else if (IntNo == Intrinsic::arm_smlsld) | 
|  | Opc = ARMISD::SMLSLD; | 
|  | else if (IntNo == Intrinsic::arm_smlsldx) | 
|  | Opc = ARMISD::SMLSLDX; | 
|  | else | 
|  | return; | 
|  |  | 
|  | SDLoc dl(N); | 
|  | SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, | 
|  | N->getOperand(3), | 
|  | DAG.getConstant(0, dl, MVT::i32)); | 
|  | SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, | 
|  | N->getOperand(3), | 
|  | DAG.getConstant(1, dl, MVT::i32)); | 
|  |  | 
|  | SDValue LongMul = DAG.getNode(Opc, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), | 
|  | N->getOperand(1), N->getOperand(2), | 
|  | Lo, Hi); | 
|  | Results.push_back(DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, | 
|  | LongMul.getValue(0), LongMul.getValue(1))); | 
|  | } | 
|  |  | 
|  | /// ReplaceNodeResults - Replace the results of node with an illegal result | 
|  | /// type with new values built out of custom code. | 
|  | void ARMTargetLowering::ReplaceNodeResults(SDNode *N, | 
|  | SmallVectorImpl<SDValue> &Results, | 
|  | SelectionDAG &DAG) const { | 
|  | SDValue Res; | 
|  | switch (N->getOpcode()) { | 
|  | default: | 
|  | llvm_unreachable("Don't know how to custom expand this!"); | 
|  | case ISD::READ_REGISTER: | 
|  | ExpandREAD_REGISTER(N, Results, DAG); | 
|  | break; | 
|  | case ISD::BITCAST: | 
|  | Res = ExpandBITCAST(N, DAG, Subtarget); | 
|  | break; | 
|  | case ISD::SRL: | 
|  | case ISD::SRA: | 
|  | case ISD::SHL: | 
|  | Res = Expand64BitShift(N, DAG, Subtarget); | 
|  | break; | 
|  | case ISD::SREM: | 
|  | case ISD::UREM: | 
|  | Res = LowerREM(N, DAG); | 
|  | break; | 
|  | case ISD::SDIVREM: | 
|  | case ISD::UDIVREM: | 
|  | Res = LowerDivRem(SDValue(N, 0), DAG); | 
|  | assert(Res.getNumOperands() == 2 && "DivRem needs two values"); | 
|  | Results.push_back(Res.getValue(0)); | 
|  | Results.push_back(Res.getValue(1)); | 
|  | return; | 
|  | case ISD::SADDSAT: | 
|  | case ISD::SSUBSAT: | 
|  | Res = LowerSADDSUBSAT(SDValue(N, 0), DAG, Subtarget); | 
|  | break; | 
|  | case ISD::READCYCLECOUNTER: | 
|  | ReplaceREADCYCLECOUNTER(N, Results, DAG, Subtarget); | 
|  | return; | 
|  | case ISD::UDIV: | 
|  | case ISD::SDIV: | 
|  | assert(Subtarget->isTargetWindows() && "can only expand DIV on Windows"); | 
|  | return ExpandDIV_Windows(SDValue(N, 0), DAG, N->getOpcode() == ISD::SDIV, | 
|  | Results); | 
|  | case ISD::ATOMIC_CMP_SWAP: | 
|  | ReplaceCMP_SWAP_64Results(N, Results, DAG); | 
|  | return; | 
|  | case ISD::INTRINSIC_WO_CHAIN: | 
|  | return ReplaceLongIntrinsic(N, Results, DAG); | 
|  | case ISD::ABS: | 
|  | lowerABS(N, Results, DAG); | 
|  | return ; | 
|  | case ISD::LOAD: | 
|  | LowerLOAD(N, Results, DAG); | 
|  | break; | 
|  | } | 
|  | if (Res.getNode()) | 
|  | Results.push_back(Res); | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //                           ARM Scheduler Hooks | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | /// SetupEntryBlockForSjLj - Insert code into the entry block that creates and | 
|  | /// registers the function context. | 
|  | void ARMTargetLowering::SetupEntryBlockForSjLj(MachineInstr &MI, | 
|  | MachineBasicBlock *MBB, | 
|  | MachineBasicBlock *DispatchBB, | 
|  | int FI) const { | 
|  | assert(!Subtarget->isROPI() && !Subtarget->isRWPI() && | 
|  | "ROPI/RWPI not currently supported with SjLj"); | 
|  | const TargetInstrInfo *TII = Subtarget->getInstrInfo(); | 
|  | DebugLoc dl = MI.getDebugLoc(); | 
|  | MachineFunction *MF = MBB->getParent(); | 
|  | MachineRegisterInfo *MRI = &MF->getRegInfo(); | 
|  | MachineConstantPool *MCP = MF->getConstantPool(); | 
|  | ARMFunctionInfo *AFI = MF->getInfo<ARMFunctionInfo>(); | 
|  | const Function &F = MF->getFunction(); | 
|  |  | 
|  | bool isThumb = Subtarget->isThumb(); | 
|  | bool isThumb2 = Subtarget->isThumb2(); | 
|  |  | 
|  | unsigned PCLabelId = AFI->createPICLabelUId(); | 
|  | unsigned PCAdj = (isThumb || isThumb2) ? 4 : 8; | 
|  | ARMConstantPoolValue *CPV = | 
|  | ARMConstantPoolMBB::Create(F.getContext(), DispatchBB, PCLabelId, PCAdj); | 
|  | unsigned CPI = MCP->getConstantPoolIndex(CPV, Align(4)); | 
|  |  | 
|  | const TargetRegisterClass *TRC = isThumb ? &ARM::tGPRRegClass | 
|  | : &ARM::GPRRegClass; | 
|  |  | 
|  | // Grab constant pool and fixed stack memory operands. | 
|  | MachineMemOperand *CPMMO = | 
|  | MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF), | 
|  | MachineMemOperand::MOLoad, 4, Align(4)); | 
|  |  | 
|  | MachineMemOperand *FIMMOSt = | 
|  | MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(*MF, FI), | 
|  | MachineMemOperand::MOStore, 4, Align(4)); | 
|  |  | 
|  | // Load the address of the dispatch MBB into the jump buffer. | 
|  | if (isThumb2) { | 
|  | // Incoming value: jbuf | 
|  | //   ldr.n  r5, LCPI1_1 | 
|  | //   orr    r5, r5, #1 | 
|  | //   add    r5, pc | 
|  | //   str    r5, [$jbuf, #+4] ; &jbuf[1] | 
|  | Register NewVReg1 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::t2LDRpci), NewVReg1) | 
|  | .addConstantPoolIndex(CPI) | 
|  | .addMemOperand(CPMMO) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | // Set the low bit because of thumb mode. | 
|  | Register NewVReg2 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::t2ORRri), NewVReg2) | 
|  | .addReg(NewVReg1, RegState::Kill) | 
|  | .addImm(0x01) | 
|  | .add(predOps(ARMCC::AL)) | 
|  | .add(condCodeOp()); | 
|  | Register NewVReg3 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::tPICADD), NewVReg3) | 
|  | .addReg(NewVReg2, RegState::Kill) | 
|  | .addImm(PCLabelId); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::t2STRi12)) | 
|  | .addReg(NewVReg3, RegState::Kill) | 
|  | .addFrameIndex(FI) | 
|  | .addImm(36) // &jbuf[1] :: pc | 
|  | .addMemOperand(FIMMOSt) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else if (isThumb) { | 
|  | // Incoming value: jbuf | 
|  | //   ldr.n  r1, LCPI1_4 | 
|  | //   add    r1, pc | 
|  | //   mov    r2, #1 | 
|  | //   orrs   r1, r2 | 
|  | //   add    r2, $jbuf, #+4 ; &jbuf[1] | 
|  | //   str    r1, [r2] | 
|  | Register NewVReg1 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::tLDRpci), NewVReg1) | 
|  | .addConstantPoolIndex(CPI) | 
|  | .addMemOperand(CPMMO) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | Register NewVReg2 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::tPICADD), NewVReg2) | 
|  | .addReg(NewVReg1, RegState::Kill) | 
|  | .addImm(PCLabelId); | 
|  | // Set the low bit because of thumb mode. | 
|  | Register NewVReg3 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::tMOVi8), NewVReg3) | 
|  | .addReg(ARM::CPSR, RegState::Define) | 
|  | .addImm(1) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | Register NewVReg4 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::tORR), NewVReg4) | 
|  | .addReg(ARM::CPSR, RegState::Define) | 
|  | .addReg(NewVReg2, RegState::Kill) | 
|  | .addReg(NewVReg3, RegState::Kill) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | Register NewVReg5 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::tADDframe), NewVReg5) | 
|  | .addFrameIndex(FI) | 
|  | .addImm(36); // &jbuf[1] :: pc | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::tSTRi)) | 
|  | .addReg(NewVReg4, RegState::Kill) | 
|  | .addReg(NewVReg5, RegState::Kill) | 
|  | .addImm(0) | 
|  | .addMemOperand(FIMMOSt) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else { | 
|  | // Incoming value: jbuf | 
|  | //   ldr  r1, LCPI1_1 | 
|  | //   add  r1, pc, r1 | 
|  | //   str  r1, [$jbuf, #+4] ; &jbuf[1] | 
|  | Register NewVReg1 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::LDRi12), NewVReg1) | 
|  | .addConstantPoolIndex(CPI) | 
|  | .addImm(0) | 
|  | .addMemOperand(CPMMO) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | Register NewVReg2 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::PICADD), NewVReg2) | 
|  | .addReg(NewVReg1, RegState::Kill) | 
|  | .addImm(PCLabelId) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | BuildMI(*MBB, MI, dl, TII->get(ARM::STRi12)) | 
|  | .addReg(NewVReg2, RegState::Kill) | 
|  | .addFrameIndex(FI) | 
|  | .addImm(36) // &jbuf[1] :: pc | 
|  | .addMemOperand(FIMMOSt) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI, | 
|  | MachineBasicBlock *MBB) const { | 
|  | const TargetInstrInfo *TII = Subtarget->getInstrInfo(); | 
|  | DebugLoc dl = MI.getDebugLoc(); | 
|  | MachineFunction *MF = MBB->getParent(); | 
|  | MachineRegisterInfo *MRI = &MF->getRegInfo(); | 
|  | MachineFrameInfo &MFI = MF->getFrameInfo(); | 
|  | int FI = MFI.getFunctionContextIndex(); | 
|  |  | 
|  | const TargetRegisterClass *TRC = Subtarget->isThumb() ? &ARM::tGPRRegClass | 
|  | : &ARM::GPRnopcRegClass; | 
|  |  | 
|  | // Get a mapping of the call site numbers to all of the landing pads they're | 
|  | // associated with. | 
|  | DenseMap<unsigned, SmallVector<MachineBasicBlock*, 2>> CallSiteNumToLPad; | 
|  | unsigned MaxCSNum = 0; | 
|  | for (MachineFunction::iterator BB = MF->begin(), E = MF->end(); BB != E; | 
|  | ++BB) { | 
|  | if (!BB->isEHPad()) continue; | 
|  |  | 
|  | // FIXME: We should assert that the EH_LABEL is the first MI in the landing | 
|  | // pad. | 
|  | for (MachineBasicBlock::iterator | 
|  | II = BB->begin(), IE = BB->end(); II != IE; ++II) { | 
|  | if (!II->isEHLabel()) continue; | 
|  |  | 
|  | MCSymbol *Sym = II->getOperand(0).getMCSymbol(); | 
|  | if (!MF->hasCallSiteLandingPad(Sym)) continue; | 
|  |  | 
|  | SmallVectorImpl<unsigned> &CallSiteIdxs = MF->getCallSiteLandingPad(Sym); | 
|  | for (SmallVectorImpl<unsigned>::iterator | 
|  | CSI = CallSiteIdxs.begin(), CSE = CallSiteIdxs.end(); | 
|  | CSI != CSE; ++CSI) { | 
|  | CallSiteNumToLPad[*CSI].push_back(&*BB); | 
|  | MaxCSNum = std::max(MaxCSNum, *CSI); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Get an ordered list of the machine basic blocks for the jump table. | 
|  | std::vector<MachineBasicBlock*> LPadList; | 
|  | SmallPtrSet<MachineBasicBlock*, 32> InvokeBBs; | 
|  | LPadList.reserve(CallSiteNumToLPad.size()); | 
|  | for (unsigned I = 1; I <= MaxCSNum; ++I) { | 
|  | SmallVectorImpl<MachineBasicBlock*> &MBBList = CallSiteNumToLPad[I]; | 
|  | for (SmallVectorImpl<MachineBasicBlock*>::iterator | 
|  | II = MBBList.begin(), IE = MBBList.end(); II != IE; ++II) { | 
|  | LPadList.push_back(*II); | 
|  | InvokeBBs.insert((*II)->pred_begin(), (*II)->pred_end()); | 
|  | } | 
|  | } | 
|  |  | 
|  | assert(!LPadList.empty() && | 
|  | "No landing pad destinations for the dispatch jump table!"); | 
|  |  | 
|  | // Create the jump table and associated information. | 
|  | MachineJumpTableInfo *JTI = | 
|  | MF->getOrCreateJumpTableInfo(MachineJumpTableInfo::EK_Inline); | 
|  | unsigned MJTI = JTI->createJumpTableIndex(LPadList); | 
|  |  | 
|  | // Create the MBBs for the dispatch code. | 
|  |  | 
|  | // Shove the dispatch's address into the return slot in the function context. | 
|  | MachineBasicBlock *DispatchBB = MF->CreateMachineBasicBlock(); | 
|  | DispatchBB->setIsEHPad(); | 
|  |  | 
|  | MachineBasicBlock *TrapBB = MF->CreateMachineBasicBlock(); | 
|  | unsigned trap_opcode; | 
|  | if (Subtarget->isThumb()) | 
|  | trap_opcode = ARM::tTRAP; | 
|  | else | 
|  | trap_opcode = Subtarget->useNaClTrap() ? ARM::TRAPNaCl : ARM::TRAP; | 
|  |  | 
|  | BuildMI(TrapBB, dl, TII->get(trap_opcode)); | 
|  | DispatchBB->addSuccessor(TrapBB); | 
|  |  | 
|  | MachineBasicBlock *DispContBB = MF->CreateMachineBasicBlock(); | 
|  | DispatchBB->addSuccessor(DispContBB); | 
|  |  | 
|  | // Insert and MBBs. | 
|  | MF->insert(MF->end(), DispatchBB); | 
|  | MF->insert(MF->end(), DispContBB); | 
|  | MF->insert(MF->end(), TrapBB); | 
|  |  | 
|  | // Insert code into the entry block that creates and registers the function | 
|  | // context. | 
|  | SetupEntryBlockForSjLj(MI, MBB, DispatchBB, FI); | 
|  |  | 
|  | MachineMemOperand *FIMMOLd = MF->getMachineMemOperand( | 
|  | MachinePointerInfo::getFixedStack(*MF, FI), | 
|  | MachineMemOperand::MOLoad | MachineMemOperand::MOVolatile, 4, Align(4)); | 
|  |  | 
|  | MachineInstrBuilder MIB; | 
|  | MIB = BuildMI(DispatchBB, dl, TII->get(ARM::Int_eh_sjlj_dispatchsetup)); | 
|  |  | 
|  | const ARMBaseInstrInfo *AII = static_cast<const ARMBaseInstrInfo*>(TII); | 
|  | const ARMBaseRegisterInfo &RI = AII->getRegisterInfo(); | 
|  |  | 
|  | // Add a register mask with no preserved registers.  This results in all | 
|  | // registers being marked as clobbered. This can't work if the dispatch block | 
|  | // is in a Thumb1 function and is linked with ARM code which uses the FP | 
|  | // registers, as there is no way to preserve the FP registers in Thumb1 mode. | 
|  | MIB.addRegMask(RI.getSjLjDispatchPreservedMask(*MF)); | 
|  |  | 
|  | bool IsPositionIndependent = isPositionIndependent(); | 
|  | unsigned NumLPads = LPadList.size(); | 
|  | if (Subtarget->isThumb2()) { | 
|  | Register NewVReg1 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::t2LDRi12), NewVReg1) | 
|  | .addFrameIndex(FI) | 
|  | .addImm(4) | 
|  | .addMemOperand(FIMMOLd) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | if (NumLPads < 256) { | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::t2CMPri)) | 
|  | .addReg(NewVReg1) | 
|  | .addImm(LPadList.size()) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else { | 
|  | Register VReg1 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::t2MOVi16), VReg1) | 
|  | .addImm(NumLPads & 0xFFFF) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | unsigned VReg2 = VReg1; | 
|  | if ((NumLPads & 0xFFFF0000) != 0) { | 
|  | VReg2 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::t2MOVTi16), VReg2) | 
|  | .addReg(VReg1) | 
|  | .addImm(NumLPads >> 16) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } | 
|  |  | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::t2CMPrr)) | 
|  | .addReg(NewVReg1) | 
|  | .addReg(VReg2) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } | 
|  |  | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::t2Bcc)) | 
|  | .addMBB(TrapBB) | 
|  | .addImm(ARMCC::HI) | 
|  | .addReg(ARM::CPSR); | 
|  |  | 
|  | Register NewVReg3 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::t2LEApcrelJT), NewVReg3) | 
|  | .addJumpTableIndex(MJTI) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | Register NewVReg4 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::t2ADDrs), NewVReg4) | 
|  | .addReg(NewVReg3, RegState::Kill) | 
|  | .addReg(NewVReg1) | 
|  | .addImm(ARM_AM::getSORegOpc(ARM_AM::lsl, 2)) | 
|  | .add(predOps(ARMCC::AL)) | 
|  | .add(condCodeOp()); | 
|  |  | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::t2BR_JT)) | 
|  | .addReg(NewVReg4, RegState::Kill) | 
|  | .addReg(NewVReg1) | 
|  | .addJumpTableIndex(MJTI); | 
|  | } else if (Subtarget->isThumb()) { | 
|  | Register NewVReg1 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::tLDRspi), NewVReg1) | 
|  | .addFrameIndex(FI) | 
|  | .addImm(1) | 
|  | .addMemOperand(FIMMOLd) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | if (NumLPads < 256) { | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::tCMPi8)) | 
|  | .addReg(NewVReg1) | 
|  | .addImm(NumLPads) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else { | 
|  | MachineConstantPool *ConstantPool = MF->getConstantPool(); | 
|  | Type *Int32Ty = Type::getInt32Ty(MF->getFunction().getContext()); | 
|  | const Constant *C = ConstantInt::get(Int32Ty, NumLPads); | 
|  |  | 
|  | // MachineConstantPool wants an explicit alignment. | 
|  | Align Alignment = MF->getDataLayout().getPrefTypeAlign(Int32Ty); | 
|  | unsigned Idx = ConstantPool->getConstantPoolIndex(C, Alignment); | 
|  |  | 
|  | Register VReg1 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::tLDRpci)) | 
|  | .addReg(VReg1, RegState::Define) | 
|  | .addConstantPoolIndex(Idx) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::tCMPr)) | 
|  | .addReg(NewVReg1) | 
|  | .addReg(VReg1) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } | 
|  |  | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::tBcc)) | 
|  | .addMBB(TrapBB) | 
|  | .addImm(ARMCC::HI) | 
|  | .addReg(ARM::CPSR); | 
|  |  | 
|  | Register NewVReg2 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::tLSLri), NewVReg2) | 
|  | .addReg(ARM::CPSR, RegState::Define) | 
|  | .addReg(NewVReg1) | 
|  | .addImm(2) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | Register NewVReg3 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::tLEApcrelJT), NewVReg3) | 
|  | .addJumpTableIndex(MJTI) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | Register NewVReg4 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::tADDrr), NewVReg4) | 
|  | .addReg(ARM::CPSR, RegState::Define) | 
|  | .addReg(NewVReg2, RegState::Kill) | 
|  | .addReg(NewVReg3) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | MachineMemOperand *JTMMOLd = | 
|  | MF->getMachineMemOperand(MachinePointerInfo::getJumpTable(*MF), | 
|  | MachineMemOperand::MOLoad, 4, Align(4)); | 
|  |  | 
|  | Register NewVReg5 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::tLDRi), NewVReg5) | 
|  | .addReg(NewVReg4, RegState::Kill) | 
|  | .addImm(0) | 
|  | .addMemOperand(JTMMOLd) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | unsigned NewVReg6 = NewVReg5; | 
|  | if (IsPositionIndependent) { | 
|  | NewVReg6 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::tADDrr), NewVReg6) | 
|  | .addReg(ARM::CPSR, RegState::Define) | 
|  | .addReg(NewVReg5, RegState::Kill) | 
|  | .addReg(NewVReg3) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } | 
|  |  | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::tBR_JTr)) | 
|  | .addReg(NewVReg6, RegState::Kill) | 
|  | .addJumpTableIndex(MJTI); | 
|  | } else { | 
|  | Register NewVReg1 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::LDRi12), NewVReg1) | 
|  | .addFrameIndex(FI) | 
|  | .addImm(4) | 
|  | .addMemOperand(FIMMOLd) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | if (NumLPads < 256) { | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::CMPri)) | 
|  | .addReg(NewVReg1) | 
|  | .addImm(NumLPads) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else if (Subtarget->hasV6T2Ops() && isUInt<16>(NumLPads)) { | 
|  | Register VReg1 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::MOVi16), VReg1) | 
|  | .addImm(NumLPads & 0xFFFF) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | unsigned VReg2 = VReg1; | 
|  | if ((NumLPads & 0xFFFF0000) != 0) { | 
|  | VReg2 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::MOVTi16), VReg2) | 
|  | .addReg(VReg1) | 
|  | .addImm(NumLPads >> 16) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } | 
|  |  | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::CMPrr)) | 
|  | .addReg(NewVReg1) | 
|  | .addReg(VReg2) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else { | 
|  | MachineConstantPool *ConstantPool = MF->getConstantPool(); | 
|  | Type *Int32Ty = Type::getInt32Ty(MF->getFunction().getContext()); | 
|  | const Constant *C = ConstantInt::get(Int32Ty, NumLPads); | 
|  |  | 
|  | // MachineConstantPool wants an explicit alignment. | 
|  | Align Alignment = MF->getDataLayout().getPrefTypeAlign(Int32Ty); | 
|  | unsigned Idx = ConstantPool->getConstantPoolIndex(C, Alignment); | 
|  |  | 
|  | Register VReg1 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::LDRcp)) | 
|  | .addReg(VReg1, RegState::Define) | 
|  | .addConstantPoolIndex(Idx) | 
|  | .addImm(0) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::CMPrr)) | 
|  | .addReg(NewVReg1) | 
|  | .addReg(VReg1, RegState::Kill) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } | 
|  |  | 
|  | BuildMI(DispatchBB, dl, TII->get(ARM::Bcc)) | 
|  | .addMBB(TrapBB) | 
|  | .addImm(ARMCC::HI) | 
|  | .addReg(ARM::CPSR); | 
|  |  | 
|  | Register NewVReg3 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::MOVsi), NewVReg3) | 
|  | .addReg(NewVReg1) | 
|  | .addImm(ARM_AM::getSORegOpc(ARM_AM::lsl, 2)) | 
|  | .add(predOps(ARMCC::AL)) | 
|  | .add(condCodeOp()); | 
|  | Register NewVReg4 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::LEApcrelJT), NewVReg4) | 
|  | .addJumpTableIndex(MJTI) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | MachineMemOperand *JTMMOLd = | 
|  | MF->getMachineMemOperand(MachinePointerInfo::getJumpTable(*MF), | 
|  | MachineMemOperand::MOLoad, 4, Align(4)); | 
|  | Register NewVReg5 = MRI->createVirtualRegister(TRC); | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::LDRrs), NewVReg5) | 
|  | .addReg(NewVReg3, RegState::Kill) | 
|  | .addReg(NewVReg4) | 
|  | .addImm(0) | 
|  | .addMemOperand(JTMMOLd) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | if (IsPositionIndependent) { | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::BR_JTadd)) | 
|  | .addReg(NewVReg5, RegState::Kill) | 
|  | .addReg(NewVReg4) | 
|  | .addJumpTableIndex(MJTI); | 
|  | } else { | 
|  | BuildMI(DispContBB, dl, TII->get(ARM::BR_JTr)) | 
|  | .addReg(NewVReg5, RegState::Kill) | 
|  | .addJumpTableIndex(MJTI); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Add the jump table entries as successors to the MBB. | 
|  | SmallPtrSet<MachineBasicBlock*, 8> SeenMBBs; | 
|  | for (std::vector<MachineBasicBlock*>::iterator | 
|  | I = LPadList.begin(), E = LPadList.end(); I != E; ++I) { | 
|  | MachineBasicBlock *CurMBB = *I; | 
|  | if (SeenMBBs.insert(CurMBB).second) | 
|  | DispContBB->addSuccessor(CurMBB); | 
|  | } | 
|  |  | 
|  | // N.B. the order the invoke BBs are processed in doesn't matter here. | 
|  | const MCPhysReg *SavedRegs = RI.getCalleeSavedRegs(MF); | 
|  | SmallVector<MachineBasicBlock*, 64> MBBLPads; | 
|  | for (MachineBasicBlock *BB : InvokeBBs) { | 
|  |  | 
|  | // Remove the landing pad successor from the invoke block and replace it | 
|  | // with the new dispatch block. | 
|  | SmallVector<MachineBasicBlock*, 4> Successors(BB->succ_begin(), | 
|  | BB->succ_end()); | 
|  | while (!Successors.empty()) { | 
|  | MachineBasicBlock *SMBB = Successors.pop_back_val(); | 
|  | if (SMBB->isEHPad()) { | 
|  | BB->removeSuccessor(SMBB); | 
|  | MBBLPads.push_back(SMBB); | 
|  | } | 
|  | } | 
|  |  | 
|  | BB->addSuccessor(DispatchBB, BranchProbability::getZero()); | 
|  | BB->normalizeSuccProbs(); | 
|  |  | 
|  | // Find the invoke call and mark all of the callee-saved registers as | 
|  | // 'implicit defined' so that they're spilled. This prevents code from | 
|  | // moving instructions to before the EH block, where they will never be | 
|  | // executed. | 
|  | for (MachineBasicBlock::reverse_iterator | 
|  | II = BB->rbegin(), IE = BB->rend(); II != IE; ++II) { | 
|  | if (!II->isCall()) continue; | 
|  |  | 
|  | DenseMap<unsigned, bool> DefRegs; | 
|  | for (MachineInstr::mop_iterator | 
|  | OI = II->operands_begin(), OE = II->operands_end(); | 
|  | OI != OE; ++OI) { | 
|  | if (!OI->isReg()) continue; | 
|  | DefRegs[OI->getReg()] = true; | 
|  | } | 
|  |  | 
|  | MachineInstrBuilder MIB(*MF, &*II); | 
|  |  | 
|  | for (unsigned i = 0; SavedRegs[i] != 0; ++i) { | 
|  | unsigned Reg = SavedRegs[i]; | 
|  | if (Subtarget->isThumb2() && | 
|  | !ARM::tGPRRegClass.contains(Reg) && | 
|  | !ARM::hGPRRegClass.contains(Reg)) | 
|  | continue; | 
|  | if (Subtarget->isThumb1Only() && !ARM::tGPRRegClass.contains(Reg)) | 
|  | continue; | 
|  | if (!Subtarget->isThumb() && !ARM::GPRRegClass.contains(Reg)) | 
|  | continue; | 
|  | if (!DefRegs[Reg]) | 
|  | MIB.addReg(Reg, RegState::ImplicitDefine | RegState::Dead); | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Mark all former landing pads as non-landing pads. The dispatch is the only | 
|  | // landing pad now. | 
|  | for (SmallVectorImpl<MachineBasicBlock*>::iterator | 
|  | I = MBBLPads.begin(), E = MBBLPads.end(); I != E; ++I) | 
|  | (*I)->setIsEHPad(false); | 
|  |  | 
|  | // The instruction is gone now. | 
|  | MI.eraseFromParent(); | 
|  | } | 
|  |  | 
|  | static | 
|  | MachineBasicBlock *OtherSucc(MachineBasicBlock *MBB, MachineBasicBlock *Succ) { | 
|  | for (MachineBasicBlock::succ_iterator I = MBB->succ_begin(), | 
|  | E = MBB->succ_end(); I != E; ++I) | 
|  | if (*I != Succ) | 
|  | return *I; | 
|  | llvm_unreachable("Expecting a BB with two successors!"); | 
|  | } | 
|  |  | 
|  | /// Return the load opcode for a given load size. If load size >= 8, | 
|  | /// neon opcode will be returned. | 
|  | static unsigned getLdOpcode(unsigned LdSize, bool IsThumb1, bool IsThumb2) { | 
|  | if (LdSize >= 8) | 
|  | return LdSize == 16 ? ARM::VLD1q32wb_fixed | 
|  | : LdSize == 8 ? ARM::VLD1d32wb_fixed : 0; | 
|  | if (IsThumb1) | 
|  | return LdSize == 4 ? ARM::tLDRi | 
|  | : LdSize == 2 ? ARM::tLDRHi | 
|  | : LdSize == 1 ? ARM::tLDRBi : 0; | 
|  | if (IsThumb2) | 
|  | return LdSize == 4 ? ARM::t2LDR_POST | 
|  | : LdSize == 2 ? ARM::t2LDRH_POST | 
|  | : LdSize == 1 ? ARM::t2LDRB_POST : 0; | 
|  | return LdSize == 4 ? ARM::LDR_POST_IMM | 
|  | : LdSize == 2 ? ARM::LDRH_POST | 
|  | : LdSize == 1 ? ARM::LDRB_POST_IMM : 0; | 
|  | } | 
|  |  | 
|  | /// Return the store opcode for a given store size. If store size >= 8, | 
|  | /// neon opcode will be returned. | 
|  | static unsigned getStOpcode(unsigned StSize, bool IsThumb1, bool IsThumb2) { | 
|  | if (StSize >= 8) | 
|  | return StSize == 16 ? ARM::VST1q32wb_fixed | 
|  | : StSize == 8 ? ARM::VST1d32wb_fixed : 0; | 
|  | if (IsThumb1) | 
|  | return StSize == 4 ? ARM::tSTRi | 
|  | : StSize == 2 ? ARM::tSTRHi | 
|  | : StSize == 1 ? ARM::tSTRBi : 0; | 
|  | if (IsThumb2) | 
|  | return StSize == 4 ? ARM::t2STR_POST | 
|  | : StSize == 2 ? ARM::t2STRH_POST | 
|  | : StSize == 1 ? ARM::t2STRB_POST : 0; | 
|  | return StSize == 4 ? ARM::STR_POST_IMM | 
|  | : StSize == 2 ? ARM::STRH_POST | 
|  | : StSize == 1 ? ARM::STRB_POST_IMM : 0; | 
|  | } | 
|  |  | 
|  | /// Emit a post-increment load operation with given size. The instructions | 
|  | /// will be added to BB at Pos. | 
|  | static void emitPostLd(MachineBasicBlock *BB, MachineBasicBlock::iterator Pos, | 
|  | const TargetInstrInfo *TII, const DebugLoc &dl, | 
|  | unsigned LdSize, unsigned Data, unsigned AddrIn, | 
|  | unsigned AddrOut, bool IsThumb1, bool IsThumb2) { | 
|  | unsigned LdOpc = getLdOpcode(LdSize, IsThumb1, IsThumb2); | 
|  | assert(LdOpc != 0 && "Should have a load opcode"); | 
|  | if (LdSize >= 8) { | 
|  | BuildMI(*BB, Pos, dl, TII->get(LdOpc), Data) | 
|  | .addReg(AddrOut, RegState::Define) | 
|  | .addReg(AddrIn) | 
|  | .addImm(0) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else if (IsThumb1) { | 
|  | // load + update AddrIn | 
|  | BuildMI(*BB, Pos, dl, TII->get(LdOpc), Data) | 
|  | .addReg(AddrIn) | 
|  | .addImm(0) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | BuildMI(*BB, Pos, dl, TII->get(ARM::tADDi8), AddrOut) | 
|  | .add(t1CondCodeOp()) | 
|  | .addReg(AddrIn) | 
|  | .addImm(LdSize) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else if (IsThumb2) { | 
|  | BuildMI(*BB, Pos, dl, TII->get(LdOpc), Data) | 
|  | .addReg(AddrOut, RegState::Define) | 
|  | .addReg(AddrIn) | 
|  | .addImm(LdSize) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else { // arm | 
|  | BuildMI(*BB, Pos, dl, TII->get(LdOpc), Data) | 
|  | .addReg(AddrOut, RegState::Define) | 
|  | .addReg(AddrIn) | 
|  | .addReg(0) | 
|  | .addImm(LdSize) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Emit a post-increment store operation with given size. The instructions | 
|  | /// will be added to BB at Pos. | 
|  | static void emitPostSt(MachineBasicBlock *BB, MachineBasicBlock::iterator Pos, | 
|  | const TargetInstrInfo *TII, const DebugLoc &dl, | 
|  | unsigned StSize, unsigned Data, unsigned AddrIn, | 
|  | unsigned AddrOut, bool IsThumb1, bool IsThumb2) { | 
|  | unsigned StOpc = getStOpcode(StSize, IsThumb1, IsThumb2); | 
|  | assert(StOpc != 0 && "Should have a store opcode"); | 
|  | if (StSize >= 8) { | 
|  | BuildMI(*BB, Pos, dl, TII->get(StOpc), AddrOut) | 
|  | .addReg(AddrIn) | 
|  | .addImm(0) | 
|  | .addReg(Data) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else if (IsThumb1) { | 
|  | // store + update AddrIn | 
|  | BuildMI(*BB, Pos, dl, TII->get(StOpc)) | 
|  | .addReg(Data) | 
|  | .addReg(AddrIn) | 
|  | .addImm(0) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | BuildMI(*BB, Pos, dl, TII->get(ARM::tADDi8), AddrOut) | 
|  | .add(t1CondCodeOp()) | 
|  | .addReg(AddrIn) | 
|  | .addImm(StSize) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else if (IsThumb2) { | 
|  | BuildMI(*BB, Pos, dl, TII->get(StOpc), AddrOut) | 
|  | .addReg(Data) | 
|  | .addReg(AddrIn) | 
|  | .addImm(StSize) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else { // arm | 
|  | BuildMI(*BB, Pos, dl, TII->get(StOpc), AddrOut) | 
|  | .addReg(Data) | 
|  | .addReg(AddrIn) | 
|  | .addReg(0) | 
|  | .addImm(StSize) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } | 
|  | } | 
|  |  | 
|  | MachineBasicBlock * | 
|  | ARMTargetLowering::EmitStructByval(MachineInstr &MI, | 
|  | MachineBasicBlock *BB) const { | 
|  | // This pseudo instruction has 3 operands: dst, src, size | 
|  | // We expand it to a loop if size > Subtarget->getMaxInlineSizeThreshold(). | 
|  | // Otherwise, we will generate unrolled scalar copies. | 
|  | const TargetInstrInfo *TII = Subtarget->getInstrInfo(); | 
|  | const BasicBlock *LLVM_BB = BB->getBasicBlock(); | 
|  | MachineFunction::iterator It = ++BB->getIterator(); | 
|  |  | 
|  | Register dest = MI.getOperand(0).getReg(); | 
|  | Register src = MI.getOperand(1).getReg(); | 
|  | unsigned SizeVal = MI.getOperand(2).getImm(); | 
|  | unsigned Alignment = MI.getOperand(3).getImm(); | 
|  | DebugLoc dl = MI.getDebugLoc(); | 
|  |  | 
|  | MachineFunction *MF = BB->getParent(); | 
|  | MachineRegisterInfo &MRI = MF->getRegInfo(); | 
|  | unsigned UnitSize = 0; | 
|  | const TargetRegisterClass *TRC = nullptr; | 
|  | const TargetRegisterClass *VecTRC = nullptr; | 
|  |  | 
|  | bool IsThumb1 = Subtarget->isThumb1Only(); | 
|  | bool IsThumb2 = Subtarget->isThumb2(); | 
|  | bool IsThumb = Subtarget->isThumb(); | 
|  |  | 
|  | if (Alignment & 1) { | 
|  | UnitSize = 1; | 
|  | } else if (Alignment & 2) { | 
|  | UnitSize = 2; | 
|  | } else { | 
|  | // Check whether we can use NEON instructions. | 
|  | if (!MF->getFunction().hasFnAttribute(Attribute::NoImplicitFloat) && | 
|  | Subtarget->hasNEON()) { | 
|  | if ((Alignment % 16 == 0) && SizeVal >= 16) | 
|  | UnitSize = 16; | 
|  | else if ((Alignment % 8 == 0) && SizeVal >= 8) | 
|  | UnitSize = 8; | 
|  | } | 
|  | // Can't use NEON instructions. | 
|  | if (UnitSize == 0) | 
|  | UnitSize = 4; | 
|  | } | 
|  |  | 
|  | // Select the correct opcode and register class for unit size load/store | 
|  | bool IsNeon = UnitSize >= 8; | 
|  | TRC = IsThumb ? &ARM::tGPRRegClass : &ARM::GPRRegClass; | 
|  | if (IsNeon) | 
|  | VecTRC = UnitSize == 16 ? &ARM::DPairRegClass | 
|  | : UnitSize == 8 ? &ARM::DPRRegClass | 
|  | : nullptr; | 
|  |  | 
|  | unsigned BytesLeft = SizeVal % UnitSize; | 
|  | unsigned LoopSize = SizeVal - BytesLeft; | 
|  |  | 
|  | if (SizeVal <= Subtarget->getMaxInlineSizeThreshold()) { | 
|  | // Use LDR and STR to copy. | 
|  | // [scratch, srcOut] = LDR_POST(srcIn, UnitSize) | 
|  | // [destOut] = STR_POST(scratch, destIn, UnitSize) | 
|  | unsigned srcIn = src; | 
|  | unsigned destIn = dest; | 
|  | for (unsigned i = 0; i < LoopSize; i+=UnitSize) { | 
|  | Register srcOut = MRI.createVirtualRegister(TRC); | 
|  | Register destOut = MRI.createVirtualRegister(TRC); | 
|  | Register scratch = MRI.createVirtualRegister(IsNeon ? VecTRC : TRC); | 
|  | emitPostLd(BB, MI, TII, dl, UnitSize, scratch, srcIn, srcOut, | 
|  | IsThumb1, IsThumb2); | 
|  | emitPostSt(BB, MI, TII, dl, UnitSize, scratch, destIn, destOut, | 
|  | IsThumb1, IsThumb2); | 
|  | srcIn = srcOut; | 
|  | destIn = destOut; | 
|  | } | 
|  |  | 
|  | // Handle the leftover bytes with LDRB and STRB. | 
|  | // [scratch, srcOut] = LDRB_POST(srcIn, 1) | 
|  | // [destOut] = STRB_POST(scratch, destIn, 1) | 
|  | for (unsigned i = 0; i < BytesLeft; i++) { | 
|  | Register srcOut = MRI.createVirtualRegister(TRC); | 
|  | Register destOut = MRI.createVirtualRegister(TRC); | 
|  | Register scratch = MRI.createVirtualRegister(TRC); | 
|  | emitPostLd(BB, MI, TII, dl, 1, scratch, srcIn, srcOut, | 
|  | IsThumb1, IsThumb2); | 
|  | emitPostSt(BB, MI, TII, dl, 1, scratch, destIn, destOut, | 
|  | IsThumb1, IsThumb2); | 
|  | srcIn = srcOut; | 
|  | destIn = destOut; | 
|  | } | 
|  | MI.eraseFromParent(); // The instruction is gone now. | 
|  | return BB; | 
|  | } | 
|  |  | 
|  | // Expand the pseudo op to a loop. | 
|  | // thisMBB: | 
|  | //   ... | 
|  | //   movw varEnd, # --> with thumb2 | 
|  | //   movt varEnd, # | 
|  | //   ldrcp varEnd, idx --> without thumb2 | 
|  | //   fallthrough --> loopMBB | 
|  | // loopMBB: | 
|  | //   PHI varPhi, varEnd, varLoop | 
|  | //   PHI srcPhi, src, srcLoop | 
|  | //   PHI destPhi, dst, destLoop | 
|  | //   [scratch, srcLoop] = LDR_POST(srcPhi, UnitSize) | 
|  | //   [destLoop] = STR_POST(scratch, destPhi, UnitSize) | 
|  | //   subs varLoop, varPhi, #UnitSize | 
|  | //   bne loopMBB | 
|  | //   fallthrough --> exitMBB | 
|  | // exitMBB: | 
|  | //   epilogue to handle left-over bytes | 
|  | //   [scratch, srcOut] = LDRB_POST(srcLoop, 1) | 
|  | //   [destOut] = STRB_POST(scratch, destLoop, 1) | 
|  | MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB); | 
|  | MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB); | 
|  | MF->insert(It, loopMBB); | 
|  | MF->insert(It, exitMBB); | 
|  |  | 
|  | // Transfer the remainder of BB and its successor edges to exitMBB. | 
|  | exitMBB->splice(exitMBB->begin(), BB, | 
|  | std::next(MachineBasicBlock::iterator(MI)), BB->end()); | 
|  | exitMBB->transferSuccessorsAndUpdatePHIs(BB); | 
|  |  | 
|  | // Load an immediate to varEnd. | 
|  | Register varEnd = MRI.createVirtualRegister(TRC); | 
|  | if (Subtarget->useMovt()) { | 
|  | unsigned Vtmp = varEnd; | 
|  | if ((LoopSize & 0xFFFF0000) != 0) | 
|  | Vtmp = MRI.createVirtualRegister(TRC); | 
|  | BuildMI(BB, dl, TII->get(IsThumb ? ARM::t2MOVi16 : ARM::MOVi16), Vtmp) | 
|  | .addImm(LoopSize & 0xFFFF) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | if ((LoopSize & 0xFFFF0000) != 0) | 
|  | BuildMI(BB, dl, TII->get(IsThumb ? ARM::t2MOVTi16 : ARM::MOVTi16), varEnd) | 
|  | .addReg(Vtmp) | 
|  | .addImm(LoopSize >> 16) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else { | 
|  | MachineConstantPool *ConstantPool = MF->getConstantPool(); | 
|  | Type *Int32Ty = Type::getInt32Ty(MF->getFunction().getContext()); | 
|  | const Constant *C = ConstantInt::get(Int32Ty, LoopSize); | 
|  |  | 
|  | // MachineConstantPool wants an explicit alignment. | 
|  | Align Alignment = MF->getDataLayout().getPrefTypeAlign(Int32Ty); | 
|  | unsigned Idx = ConstantPool->getConstantPoolIndex(C, Alignment); | 
|  | MachineMemOperand *CPMMO = | 
|  | MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF), | 
|  | MachineMemOperand::MOLoad, 4, Align(4)); | 
|  |  | 
|  | if (IsThumb) | 
|  | BuildMI(*BB, MI, dl, TII->get(ARM::tLDRpci)) | 
|  | .addReg(varEnd, RegState::Define) | 
|  | .addConstantPoolIndex(Idx) | 
|  | .add(predOps(ARMCC::AL)) | 
|  | .addMemOperand(CPMMO); | 
|  | else | 
|  | BuildMI(*BB, MI, dl, TII->get(ARM::LDRcp)) | 
|  | .addReg(varEnd, RegState::Define) | 
|  | .addConstantPoolIndex(Idx) | 
|  | .addImm(0) | 
|  | .add(predOps(ARMCC::AL)) | 
|  | .addMemOperand(CPMMO); | 
|  | } | 
|  | BB->addSuccessor(loopMBB); | 
|  |  | 
|  | // Generate the loop body: | 
|  | //   varPhi = PHI(varLoop, varEnd) | 
|  | //   srcPhi = PHI(srcLoop, src) | 
|  | //   destPhi = PHI(destLoop, dst) | 
|  | MachineBasicBlock *entryBB = BB; | 
|  | BB = loopMBB; | 
|  | Register varLoop = MRI.createVirtualRegister(TRC); | 
|  | Register varPhi = MRI.createVirtualRegister(TRC); | 
|  | Register srcLoop = MRI.createVirtualRegister(TRC); | 
|  | Register srcPhi = MRI.createVirtualRegister(TRC); | 
|  | Register destLoop = MRI.createVirtualRegister(TRC); | 
|  | Register destPhi = MRI.createVirtualRegister(TRC); | 
|  |  | 
|  | BuildMI(*BB, BB->begin(), dl, TII->get(ARM::PHI), varPhi) | 
|  | .addReg(varLoop).addMBB(loopMBB) | 
|  | .addReg(varEnd).addMBB(entryBB); | 
|  | BuildMI(BB, dl, TII->get(ARM::PHI), srcPhi) | 
|  | .addReg(srcLoop).addMBB(loopMBB) | 
|  | .addReg(src).addMBB(entryBB); | 
|  | BuildMI(BB, dl, TII->get(ARM::PHI), destPhi) | 
|  | .addReg(destLoop).addMBB(loopMBB) | 
|  | .addReg(dest).addMBB(entryBB); | 
|  |  | 
|  | //   [scratch, srcLoop] = LDR_POST(srcPhi, UnitSize) | 
|  | //   [destLoop] = STR_POST(scratch, destPhi, UnitSiz) | 
|  | Register scratch = MRI.createVirtualRegister(IsNeon ? VecTRC : TRC); | 
|  | emitPostLd(BB, BB->end(), TII, dl, UnitSize, scratch, srcPhi, srcLoop, | 
|  | IsThumb1, IsThumb2); | 
|  | emitPostSt(BB, BB->end(), TII, dl, UnitSize, scratch, destPhi, destLoop, | 
|  | IsThumb1, IsThumb2); | 
|  |  | 
|  | // Decrement loop variable by UnitSize. | 
|  | if (IsThumb1) { | 
|  | BuildMI(*BB, BB->end(), dl, TII->get(ARM::tSUBi8), varLoop) | 
|  | .add(t1CondCodeOp()) | 
|  | .addReg(varPhi) | 
|  | .addImm(UnitSize) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | } else { | 
|  | MachineInstrBuilder MIB = | 
|  | BuildMI(*BB, BB->end(), dl, | 
|  | TII->get(IsThumb2 ? ARM::t2SUBri : ARM::SUBri), varLoop); | 
|  | MIB.addReg(varPhi) | 
|  | .addImm(UnitSize) | 
|  | .add(predOps(ARMCC::AL)) | 
|  | .add(condCodeOp()); | 
|  | MIB->getOperand(5).setReg(ARM::CPSR); | 
|  | MIB->getOperand(5).setIsDef(true); | 
|  | } | 
|  | BuildMI(*BB, BB->end(), dl, | 
|  | TII->get(IsThumb1 ? ARM::tBcc : IsThumb2 ? ARM::t2Bcc : ARM::Bcc)) | 
|  | .addMBB(loopMBB).addImm(ARMCC::NE).addReg(ARM::CPSR); | 
|  |  | 
|  | // loopMBB can loop back to loopMBB or fall through to exitMBB. | 
|  | BB->addSuccessor(loopMBB); | 
|  | BB->addSuccessor(exitMBB); | 
|  |  | 
|  | // Add epilogue to handle BytesLeft. | 
|  | BB = exitMBB; | 
|  | auto StartOfExit = exitMBB->begin(); | 
|  |  | 
|  | //   [scratch, srcOut] = LDRB_POST(srcLoop, 1) | 
|  | //   [destOut] = STRB_POST(scratch, destLoop, 1) | 
|  | unsigned srcIn = srcLoop; | 
|  | unsigned destIn = destLoop; | 
|  | for (unsigned i = 0; i < BytesLeft; i++) { | 
|  | Register srcOut = MRI.createVirtualRegister(TRC); | 
|  | Register destOut = MRI.createVirtualRegister(TRC); | 
|  | Register scratch = MRI.createVirtualRegister(TRC); | 
|  | emitPostLd(BB, StartOfExit, TII, dl, 1, scratch, srcIn, srcOut, | 
|  | IsThumb1, IsThumb2); | 
|  | emitPostSt(BB, StartOfExit, TII, dl, 1, scratch, destIn, destOut, | 
|  | IsThumb1, IsThumb2); | 
|  | srcIn = srcOut; | 
|  | destIn = destOut; | 
|  | } | 
|  |  | 
|  | MI.eraseFromParent(); // The instruction is gone now. | 
|  | return BB; | 
|  | } | 
|  |  | 
|  | MachineBasicBlock * | 
|  | ARMTargetLowering::EmitLowered__chkstk(MachineInstr &MI, | 
|  | MachineBasicBlock *MBB) const { | 
|  | const TargetMachine &TM = getTargetMachine(); | 
|  | const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); | 
|  | DebugLoc DL = MI.getDebugLoc(); | 
|  |  | 
|  | assert(Subtarget->isTargetWindows() && | 
|  | "__chkstk is only supported on Windows"); | 
|  | assert(Subtarget->isThumb2() && "Windows on ARM requires Thumb-2 mode"); | 
|  |  | 
|  | // __chkstk takes the number of words to allocate on the stack in R4, and | 
|  | // returns the stack adjustment in number of bytes in R4.  This will not | 
|  | // clober any other registers (other than the obvious lr). | 
|  | // | 
|  | // Although, technically, IP should be considered a register which may be | 
|  | // clobbered, the call itself will not touch it.  Windows on ARM is a pure | 
|  | // thumb-2 environment, so there is no interworking required.  As a result, we | 
|  | // do not expect a veneer to be emitted by the linker, clobbering IP. | 
|  | // | 
|  | // Each module receives its own copy of __chkstk, so no import thunk is | 
|  | // required, again, ensuring that IP is not clobbered. | 
|  | // | 
|  | // Finally, although some linkers may theoretically provide a trampoline for | 
|  | // out of range calls (which is quite common due to a 32M range limitation of | 
|  | // branches for Thumb), we can generate the long-call version via | 
|  | // -mcmodel=large, alleviating the need for the trampoline which may clobber | 
|  | // IP. | 
|  |  | 
|  | switch (TM.getCodeModel()) { | 
|  | case CodeModel::Tiny: | 
|  | llvm_unreachable("Tiny code model not available on ARM."); | 
|  | case CodeModel::Small: | 
|  | case CodeModel::Medium: | 
|  | case CodeModel::Kernel: | 
|  | BuildMI(*MBB, MI, DL, TII.get(ARM::tBL)) | 
|  | .add(predOps(ARMCC::AL)) | 
|  | .addExternalSymbol("__chkstk") | 
|  | .addReg(ARM::R4, RegState::Implicit | RegState::Kill) | 
|  | .addReg(ARM::R4, RegState::Implicit | RegState::Define) | 
|  | .addReg(ARM::R12, | 
|  | RegState::Implicit | RegState::Define | RegState::Dead) | 
|  | .addReg(ARM::CPSR, | 
|  | RegState::Implicit | RegState::Define | RegState::Dead); | 
|  | break; | 
|  | case CodeModel::Large: { | 
|  | MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo(); | 
|  | Register Reg = MRI.createVirtualRegister(&ARM::rGPRRegClass); | 
|  |  | 
|  | BuildMI(*MBB, MI, DL, TII.get(ARM::t2MOVi32imm), Reg) | 
|  | .addExternalSymbol("__chkstk"); | 
|  | BuildMI(*MBB, MI, DL, TII.get(ARM::tBLXr)) | 
|  | .add(predOps(ARMCC::AL)) | 
|  | .addReg(Reg, RegState::Kill) | 
|  | .addReg(ARM::R4, RegState::Implicit | RegState::Kill) | 
|  | .addReg(ARM::R4, RegState::Implicit | RegState::Define) | 
|  | .addReg(ARM::R12, | 
|  | RegState::Implicit | RegState::Define | RegState::Dead) | 
|  | .addReg(ARM::CPSR, | 
|  | RegState::Implicit | RegState::Define | RegState::Dead); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | BuildMI(*MBB, MI, DL, TII.get(ARM::t2SUBrr), ARM::SP) | 
|  | .addReg(ARM::SP, RegState::Kill) | 
|  | .addReg(ARM::R4, RegState::Kill) | 
|  | .setMIFlags(MachineInstr::FrameSetup) | 
|  | .add(predOps(ARMCC::AL)) | 
|  | .add(condCodeOp()); | 
|  |  | 
|  | MI.eraseFromParent(); | 
|  | return MBB; | 
|  | } | 
|  |  | 
|  | MachineBasicBlock * | 
|  | ARMTargetLowering::EmitLowered__dbzchk(MachineInstr &MI, | 
|  | MachineBasicBlock *MBB) const { | 
|  | DebugLoc DL = MI.getDebugLoc(); | 
|  | MachineFunction *MF = MBB->getParent(); | 
|  | const TargetInstrInfo *TII = Subtarget->getInstrInfo(); | 
|  |  | 
|  | MachineBasicBlock *ContBB = MF->CreateMachineBasicBlock(); | 
|  | MF->insert(++MBB->getIterator(), ContBB); | 
|  | ContBB->splice(ContBB->begin(), MBB, | 
|  | std::next(MachineBasicBlock::iterator(MI)), MBB->end()); | 
|  | ContBB->transferSuccessorsAndUpdatePHIs(MBB); | 
|  | MBB->addSuccessor(ContBB); | 
|  |  | 
|  | MachineBasicBlock *TrapBB = MF->CreateMachineBasicBlock(); | 
|  | BuildMI(TrapBB, DL, TII->get(ARM::t__brkdiv0)); | 
|  | MF->push_back(TrapBB); | 
|  | MBB->addSuccessor(TrapBB); | 
|  |  | 
|  | BuildMI(*MBB, MI, DL, TII->get(ARM::tCMPi8)) | 
|  | .addReg(MI.getOperand(0).getReg()) | 
|  | .addImm(0) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | BuildMI(*MBB, MI, DL, TII->get(ARM::t2Bcc)) | 
|  | .addMBB(TrapBB) | 
|  | .addImm(ARMCC::EQ) | 
|  | .addReg(ARM::CPSR); | 
|  |  | 
|  | MI.eraseFromParent(); | 
|  | return ContBB; | 
|  | } | 
|  |  | 
|  | // The CPSR operand of SelectItr might be missing a kill marker | 
|  | // because there were multiple uses of CPSR, and ISel didn't know | 
|  | // which to mark. Figure out whether SelectItr should have had a | 
|  | // kill marker, and set it if it should. Returns the correct kill | 
|  | // marker value. | 
|  | static bool checkAndUpdateCPSRKill(MachineBasicBlock::iterator SelectItr, | 
|  | MachineBasicBlock* BB, | 
|  | const TargetRegisterInfo* TRI) { | 
|  | // Scan forward through BB for a use/def of CPSR. | 
|  | MachineBasicBlock::iterator miI(std::next(SelectItr)); | 
|  | for (MachineBasicBlock::iterator miE = BB->end(); miI != miE; ++miI) { | 
|  | const MachineInstr& mi = *miI; | 
|  | if (mi.readsRegister(ARM::CPSR)) | 
|  | return false; | 
|  | if (mi.definesRegister(ARM::CPSR)) | 
|  | break; // Should have kill-flag - update below. | 
|  | } | 
|  |  | 
|  | // If we hit the end of the block, check whether CPSR is live into a | 
|  | // successor. | 
|  | if (miI == BB->end()) { | 
|  | for (MachineBasicBlock::succ_iterator sItr = BB->succ_begin(), | 
|  | sEnd = BB->succ_end(); | 
|  | sItr != sEnd; ++sItr) { | 
|  | MachineBasicBlock* succ = *sItr; | 
|  | if (succ->isLiveIn(ARM::CPSR)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // We found a def, or hit the end of the basic block and CPSR wasn't live | 
|  | // out. SelectMI should have a kill flag on CPSR. | 
|  | SelectItr->addRegisterKilled(ARM::CPSR, TRI); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | MachineBasicBlock * | 
|  | ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, | 
|  | MachineBasicBlock *BB) const { | 
|  | const TargetInstrInfo *TII = Subtarget->getInstrInfo(); | 
|  | DebugLoc dl = MI.getDebugLoc(); | 
|  | bool isThumb2 = Subtarget->isThumb2(); | 
|  | switch (MI.getOpcode()) { | 
|  | default: { | 
|  | MI.print(errs()); | 
|  | llvm_unreachable("Unexpected instr type to insert"); | 
|  | } | 
|  |  | 
|  | // Thumb1 post-indexed loads are really just single-register LDMs. | 
|  | case ARM::tLDR_postidx: { | 
|  | MachineOperand Def(MI.getOperand(1)); | 
|  | BuildMI(*BB, MI, dl, TII->get(ARM::tLDMIA_UPD)) | 
|  | .add(Def)  // Rn_wb | 
|  | .add(MI.getOperand(2))  // Rn | 
|  | .add(MI.getOperand(3))  // PredImm | 
|  | .add(MI.getOperand(4))  // PredReg | 
|  | .add(MI.getOperand(0))  // Rt | 
|  | .cloneMemRefs(MI); | 
|  | MI.eraseFromParent(); | 
|  | return BB; | 
|  | } | 
|  |  | 
|  | // The Thumb2 pre-indexed stores have the same MI operands, they just | 
|  | // define them differently in the .td files from the isel patterns, so | 
|  | // they need pseudos. | 
|  | case ARM::t2STR_preidx: | 
|  | MI.setDesc(TII->get(ARM::t2STR_PRE)); | 
|  | return BB; | 
|  | case ARM::t2STRB_preidx: | 
|  | MI.setDesc(TII->get(ARM::t2STRB_PRE)); | 
|  | return BB; | 
|  | case ARM::t2STRH_preidx: | 
|  | MI.setDesc(TII->get(ARM::t2STRH_PRE)); | 
|  | return BB; | 
|  |  | 
|  | case ARM::STRi_preidx: | 
|  | case ARM::STRBi_preidx: { | 
|  | unsigned NewOpc = MI.getOpcode() == ARM::STRi_preidx ? ARM::STR_PRE_IMM | 
|  | : ARM::STRB_PRE_IMM; | 
|  | // Decode the offset. | 
|  | unsigned Offset = MI.getOperand(4).getImm(); | 
|  | bool isSub = ARM_AM::getAM2Op(Offset) == ARM_AM::sub; | 
|  | Offset = ARM_AM::getAM2Offset(Offset); | 
|  | if (isSub) | 
|  | Offset = -Offset; | 
|  |  | 
|  | MachineMemOperand *MMO = *MI.memoperands_begin(); | 
|  | BuildMI(*BB, MI, dl, TII->get(NewOpc)) | 
|  | .add(MI.getOperand(0)) // Rn_wb | 
|  | .add(MI.getOperand(1)) // Rt | 
|  | .add(MI.getOperand(2)) // Rn | 
|  | .addImm(Offset)        // offset (skip GPR==zero_reg) | 
|  | .add(MI.getOperand(5)) // pred | 
|  | .add(MI.getOperand(6)) | 
|  | .addMemOperand(MMO); | 
|  | MI.eraseFromParent(); | 
|  | return BB; | 
|  | } | 
|  | case ARM::STRr_preidx: | 
|  | case ARM::STRBr_preidx: | 
|  | case ARM::STRH_preidx: { | 
|  | unsigned NewOpc; | 
|  | switch (MI.getOpcode()) { | 
|  | default: llvm_unreachable("unexpected opcode!"); | 
|  | case ARM::STRr_preidx: NewOpc = ARM::STR_PRE_REG; break; | 
|  | case ARM::STRBr_preidx: NewOpc = ARM::STRB_PRE_REG; break; | 
|  | case ARM::STRH_preidx: NewOpc = ARM::STRH_PRE; break; | 
|  | } | 
|  | MachineInstrBuilder MIB = BuildMI(*BB, MI, dl, TII->get(NewOpc)); | 
|  | for (unsigned i = 0; i < MI.getNumOperands(); ++i) | 
|  | MIB.add(MI.getOperand(i)); | 
|  | MI.eraseFromParent(); | 
|  | return BB; | 
|  | } | 
|  |  | 
|  | case ARM::tMOVCCr_pseudo: { | 
|  | // To "insert" a SELECT_CC instruction, we actually have to insert the | 
|  | // diamond control-flow pattern.  The incoming instruction knows the | 
|  | // destination vreg to set, the condition code register to branch on, the | 
|  | // true/false values to select between, and a branch opcode to use. | 
|  | const BasicBlock *LLVM_BB = BB->getBasicBlock(); | 
|  | MachineFunction::iterator It = ++BB->getIterator(); | 
|  |  | 
|  | //  thisMBB: | 
|  | //  ... | 
|  | //   TrueVal = ... | 
|  | //   cmpTY ccX, r1, r2 | 
|  | //   bCC copy1MBB | 
|  | //   fallthrough --> copy0MBB | 
|  | MachineBasicBlock *thisMBB  = BB; | 
|  | MachineFunction *F = BB->getParent(); | 
|  | MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); | 
|  | MachineBasicBlock *sinkMBB  = F->CreateMachineBasicBlock(LLVM_BB); | 
|  | F->insert(It, copy0MBB); | 
|  | F->insert(It, sinkMBB); | 
|  |  | 
|  | // Check whether CPSR is live past the tMOVCCr_pseudo. | 
|  | const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); | 
|  | if (!MI.killsRegister(ARM::CPSR) && | 
|  | !checkAndUpdateCPSRKill(MI, thisMBB, TRI)) { | 
|  | copy0MBB->addLiveIn(ARM::CPSR); | 
|  | sinkMBB->addLiveIn(ARM::CPSR); | 
|  | } | 
|  |  | 
|  | // Transfer the remainder of BB and its successor edges to sinkMBB. | 
|  | sinkMBB->splice(sinkMBB->begin(), BB, | 
|  | std::next(MachineBasicBlock::iterator(MI)), BB->end()); | 
|  | sinkMBB->transferSuccessorsAndUpdatePHIs(BB); | 
|  |  | 
|  | BB->addSuccessor(copy0MBB); | 
|  | BB->addSuccessor(sinkMBB); | 
|  |  | 
|  | BuildMI(BB, dl, TII->get(ARM::tBcc)) | 
|  | .addMBB(sinkMBB) | 
|  | .addImm(MI.getOperand(3).getImm()) | 
|  | .addReg(MI.getOperand(4).getReg()); | 
|  |  | 
|  | //  copy0MBB: | 
|  | //   %FalseValue = ... | 
|  | //   # fallthrough to sinkMBB | 
|  | BB = copy0MBB; | 
|  |  | 
|  | // Update machine-CFG edges | 
|  | BB->addSuccessor(sinkMBB); | 
|  |  | 
|  | //  sinkMBB: | 
|  | //   %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] | 
|  | //  ... | 
|  | BB = sinkMBB; | 
|  | BuildMI(*BB, BB->begin(), dl, TII->get(ARM::PHI), MI.getOperand(0).getReg()) | 
|  | .addReg(MI.getOperand(1).getReg()) | 
|  | .addMBB(copy0MBB) | 
|  | .addReg(MI.getOperand(2).getReg()) | 
|  | .addMBB(thisMBB); | 
|  |  | 
|  | MI.eraseFromParent(); // The pseudo instruction is gone now. | 
|  | return BB; | 
|  | } | 
|  |  | 
|  | case ARM::BCCi64: | 
|  | case ARM::BCCZi64: { | 
|  | // If there is an unconditional branch to the other successor, remove it. | 
|  | BB->erase(std::next(MachineBasicBlock::iterator(MI)), BB->end()); | 
|  |  | 
|  | // Compare both parts that make up the double comparison separately for | 
|  | // equality. | 
|  | bool RHSisZero = MI.getOpcode() == ARM::BCCZi64; | 
|  |  | 
|  | Register LHS1 = MI.getOperand(1).getReg(); | 
|  | Register LHS2 = MI.getOperand(2).getReg(); | 
|  | if (RHSisZero) { | 
|  | BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri)) | 
|  | .addReg(LHS1) | 
|  | .addImm(0) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri)) | 
|  | .addReg(LHS2).addImm(0) | 
|  | .addImm(ARMCC::EQ).addReg(ARM::CPSR); | 
|  | } else { | 
|  | Register RHS1 = MI.getOperand(3).getReg(); | 
|  | Register RHS2 = MI.getOperand(4).getReg(); | 
|  | BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPrr : ARM::CMPrr)) | 
|  | .addReg(LHS1) | 
|  | .addReg(RHS1) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPrr : ARM::CMPrr)) | 
|  | .addReg(LHS2).addReg(RHS2) | 
|  | .addImm(ARMCC::EQ).addReg(ARM::CPSR); | 
|  | } | 
|  |  | 
|  | MachineBasicBlock *destMBB = MI.getOperand(RHSisZero ? 3 : 5).getMBB(); | 
|  | MachineBasicBlock *exitMBB = OtherSucc(BB, destMBB); | 
|  | if (MI.getOperand(0).getImm() == ARMCC::NE) | 
|  | std::swap(destMBB, exitMBB); | 
|  |  | 
|  | BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)) | 
|  | .addMBB(destMBB).addImm(ARMCC::EQ).addReg(ARM::CPSR); | 
|  | if (isThumb2) | 
|  | BuildMI(BB, dl, TII->get(ARM::t2B)) | 
|  | .addMBB(exitMBB) | 
|  | .add(predOps(ARMCC::AL)); | 
|  | else | 
|  | BuildMI(BB, dl, TII->get(ARM::B)) .addMBB(exitMBB); | 
|  |  | 
|  | MI.eraseFromParent(); // The pseudo instruction is gone now. | 
|  | return BB; | 
|  | } | 
|  |  | 
|  | case ARM::Int_eh_sjlj_setjmp: | 
|  | case ARM::Int_eh_sjlj_setjmp_nofp: | 
|  | case ARM::tInt_eh_sjlj_setjmp: | 
|  | case ARM::t2Int_eh_sjlj_setjmp: | 
|  | case ARM::t2Int_eh_sjlj_setjmp_nofp: | 
|  | return BB; | 
|  |  | 
|  | case ARM::Int_eh_sjlj_setup_dispatch: | 
|  | EmitSjLjDispatchBlock(MI, BB); | 
|  | return BB; | 
|  |  | 
|  | case ARM::ABS: | 
|  | case ARM::t2ABS: { | 
|  | // To insert an ABS instruction, we have to insert the | 
|  | // diamond control-flow pattern.  The incoming instruction knows the | 
|  | // source vreg to test against 0, the destination vreg to set, | 
|  | // the condition code register to branch on, the | 
|  | // true/false values to select between, and a branch opcode to use. | 
|  | // It transforms | 
|  | //     V1 = ABS V0 | 
|  | // into | 
|  | //     V2 = MOVS V0 | 
|  | //     BCC                      (branch to SinkBB if V0 >= 0) | 
|  | //     RSBBB: V3 = RSBri V2, 0  (compute ABS if V2 < 0) | 
|  | //     SinkBB: V1 = PHI(V2, V3) | 
|  | const BasicBlock *LLVM_BB = BB->getBasicBlock(); | 
|  | MachineFunction::iterator BBI = ++BB->getIterator(); | 
|  | MachineFunction *Fn = BB->getParent(); | 
|  | MachineBasicBlock *RSBBB = Fn->CreateMachineBasicBlock(LLVM_BB); | 
|  | MachineBasicBlock *SinkBB  = Fn->CreateMachineBasicBlock(LLVM_BB); | 
|  | Fn->insert(BBI, RSBBB); | 
|  | Fn->insert(BBI, SinkBB); | 
|  |  | 
|  | Register ABSSrcReg = MI.getOperand(1).getReg(); | 
|  | Register ABSDstReg = MI.getOperand(0).getReg(); | 
|  | bool ABSSrcKIll = MI.getOperand(1).isKill(); | 
|  | bool isThumb2 = Subtarget->isThumb2(); | 
|  | MachineRegisterInfo &MRI = Fn->getRegInfo(); | 
|  | // In Thumb mode S must not be specified if source register is the SP or | 
|  | // PC and if destination register is the SP, so restrict register class | 
|  | Register NewRsbDstReg = MRI.createVirtualRegister( | 
|  | isThumb2 ? &ARM::rGPRRegClass : &ARM::GPRRegClass); | 
|  |  | 
|  | // Transfer the remainder of BB and its successor edges to sinkMBB. | 
|  | SinkBB->splice(SinkBB->begin(), BB, | 
|  | std::next(MachineBasicBlock::iterator(MI)), BB->end()); | 
|  | SinkBB->transferSuccessorsAndUpdatePHIs(BB); | 
|  |  | 
|  | BB->addSuccessor(RSBBB); | 
|  | BB->addSuccessor(SinkBB); | 
|  |  | 
|  | // fall through to SinkMBB | 
|  | RSBBB->addSuccessor(SinkBB); | 
|  |  | 
|  | // insert a cmp at the end of BB | 
|  | BuildMI(BB, dl, TII->get(isThumb2 ? ARM::t2CMPri : ARM::CMPri)) | 
|  | .addReg(ABSSrcReg) | 
|  | .addImm(0) | 
|  | .add(predOps(ARMCC::AL)); | 
|  |  | 
|  | // insert a bcc with opposite CC to ARMCC::MI at the end of BB | 
|  | BuildMI(BB, dl, | 
|  | TII->get(isThumb2 ? ARM::t2Bcc : ARM::Bcc)).addMBB(SinkBB) | 
|  | .addImm(ARMCC::getOppositeCondition(ARMCC::MI)).addReg(ARM::CPSR); | 
|  |  | 
|  | // insert rsbri in RSBBB | 
|  | // Note: BCC and rsbri will be converted into predicated rsbmi | 
|  | // by if-conversion pass | 
|  | BuildMI(*RSBBB, RSBBB->begin(), dl, | 
|  | TII->get(isThumb2 ? ARM::t2RSBri : ARM::RSBri), NewRsbDstReg) | 
|  | .addReg(ABSSrcReg, ABSSrcKIll ? RegState::Kill : 0) | 
|  | .addImm(0) | 
|  | .add(predOps(ARMCC::AL)) | 
|  | .add(condCodeOp()); | 
|  |  | 
|  | // insert PHI in SinkBB, | 
|  | // reuse ABSDstReg to not change uses of ABS instruction | 
|  | BuildMI(*SinkBB, SinkBB->begin(), dl, | 
|  | TII->get(ARM::PHI), ABSDstReg) | 
|  | .addReg(NewRsbDstReg).addMBB(RSBBB) | 
|  | .addReg(ABSSrcReg).addMBB(BB); | 
|  |  | 
|  | // remove ABS instruction | 
|  | MI.eraseFromParent(); | 
|  |  | 
|  | // return last added BB | 
|  | return SinkBB; | 
|  | } | 
|  | case ARM::COPY_STRUCT_BYVAL_I32: | 
|  | ++NumLoopByVals; | 
|  | return EmitStructByval(MI, BB); | 
|  | case ARM::WIN__CHKSTK: | 
|  | return EmitLowered__chkstk(MI, BB); | 
|  | case ARM::WIN__DBZCHK: | 
|  | return EmitLowered__dbzchk(MI, BB); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Attaches vregs to MEMCPY that it will use as scratch registers | 
|  | /// when it is expanded into LDM/STM. This is done as a post-isel lowering | 
|  | /// instead of as a custom inserter because we need the use list from the SDNode. | 
|  | static void attachMEMCPYScratchRegs(const ARMSubtarget *Subtarget, | 
|  | MachineInstr &MI, const SDNode *Node) { | 
|  | bool isThumb1 = Subtarget->isThumb1Only(); | 
|  |  | 
|  | DebugLoc DL = MI.getDebugLoc(); | 
|  | MachineFunction *MF = MI.getParent()->getParent(); | 
|  | MachineRegisterInfo &MRI = MF->getRegInfo(); | 
|  | MachineInstrBuilder MIB(*MF, MI); | 
|  |  | 
|  | // If the new dst/src is unused mark it as dead. | 
|  | if (!Node->hasAnyUseOfValue(0)) { | 
|  | MI.getOperand(0).setIsDead(true); | 
|  | } | 
|  | if (!Node->hasAnyUseOfValue(1)) { | 
|  | MI.getOperand(1).setIsDead(true); | 
|  | } | 
|  |  | 
|  | // The MEMCPY both defines and kills the scratch registers. | 
|  | for (unsigned I = 0; I != MI.getOperand(4).getImm(); ++I) { | 
|  | Register TmpReg = MRI.createVirtualRegister(isThumb1 ? &ARM::tGPRRegClass | 
|  | : &ARM::GPRRegClass); | 
|  | MIB.addReg(TmpReg, RegState::Define|RegState::Dead); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI, | 
|  | SDNode *Node) const { | 
|  | if (MI.getOpcode() == ARM::MEMCPY) { | 
|  | attachMEMCPYScratchRegs(Subtarget, MI, Node); | 
|  | return; | 
|  | } | 
|  |  | 
|  | const MCInstrDesc *MCID = &MI.getDesc(); | 
|  | // Adjust potentially 's' setting instructions after isel, i.e. ADC, SBC, RSB, | 
|  | // RSC. Coming out of isel, they have an implicit CPSR def, but the optional | 
|  | // operand is still set to noreg. If needed, set the optional operand's | 
|  | // register to CPSR, and remove the redundant implicit def. | 
|  | // | 
|  | // e.g. ADCS (..., implicit-def CPSR) -> ADC (... opt:def CPSR). | 
|  |  | 
|  | // Rename pseudo opcodes. | 
|  | unsigned NewOpc = convertAddSubFlagsOpcode(MI.getOpcode()); | 
|  | unsigned ccOutIdx; | 
|  | if (NewOpc) { | 
|  | const ARMBaseInstrInfo *TII = Subtarget->getInstrInfo(); | 
|  | MCID = &TII->get(NewOpc); | 
|  |  | 
|  | assert(MCID->getNumOperands() == | 
|  | MI.getDesc().getNumOperands() + 5 - MI.getDesc().getSize() | 
|  | && "converted opcode should be the same except for cc_out" | 
|  | " (and, on Thumb1, pred)"); | 
|  |  | 
|  | MI.setDesc(*MCID); | 
|  |  | 
|  | // Add the optional cc_out operand | 
|  | MI.addOperand(MachineOperand::CreateReg(0, /*isDef=*/true)); | 
|  |  | 
|  | // On Thumb1, move all input operands to the end, then add the predicate | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | for (unsigned c = MCID->getNumOperands() - 4; c--;) { | 
|  | MI.addOperand(MI.getOperand(1)); | 
|  | MI.RemoveOperand(1); | 
|  | } | 
|  |  | 
|  | // Restore the ties | 
|  | for (unsigned i = MI.getNumOperands(); i--;) { | 
|  | const MachineOperand& op = MI.getOperand(i); | 
|  | if (op.isReg() && op.isUse()) { | 
|  | int DefIdx = MCID->getOperandConstraint(i, MCOI::TIED_TO); | 
|  | if (DefIdx != -1) | 
|  | MI.tieOperands(DefIdx, i); | 
|  | } | 
|  | } | 
|  |  | 
|  | MI.addOperand(MachineOperand::CreateImm(ARMCC::AL)); | 
|  | MI.addOperand(MachineOperand::CreateReg(0, /*isDef=*/false)); | 
|  | ccOutIdx = 1; | 
|  | } else | 
|  | ccOutIdx = MCID->getNumOperands() - 1; | 
|  | } else | 
|  | ccOutIdx = MCID->getNumOperands() - 1; | 
|  |  | 
|  | // Any ARM instruction that sets the 's' bit should specify an optional | 
|  | // "cc_out" operand in the last operand position. | 
|  | if (!MI.hasOptionalDef() || !MCID->OpInfo[ccOutIdx].isOptionalDef()) { | 
|  | assert(!NewOpc && "Optional cc_out operand required"); | 
|  | return; | 
|  | } | 
|  | // Look for an implicit def of CPSR added by MachineInstr ctor. Remove it | 
|  | // since we already have an optional CPSR def. | 
|  | bool definesCPSR = false; | 
|  | bool deadCPSR = false; | 
|  | for (unsigned i = MCID->getNumOperands(), e = MI.getNumOperands(); i != e; | 
|  | ++i) { | 
|  | const MachineOperand &MO = MI.getOperand(i); | 
|  | if (MO.isReg() && MO.isDef() && MO.getReg() == ARM::CPSR) { | 
|  | definesCPSR = true; | 
|  | if (MO.isDead()) | 
|  | deadCPSR = true; | 
|  | MI.RemoveOperand(i); | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (!definesCPSR) { | 
|  | assert(!NewOpc && "Optional cc_out operand required"); | 
|  | return; | 
|  | } | 
|  | assert(deadCPSR == !Node->hasAnyUseOfValue(1) && "inconsistent dead flag"); | 
|  | if (deadCPSR) { | 
|  | assert(!MI.getOperand(ccOutIdx).getReg() && | 
|  | "expect uninitialized optional cc_out operand"); | 
|  | // Thumb1 instructions must have the S bit even if the CPSR is dead. | 
|  | if (!Subtarget->isThumb1Only()) | 
|  | return; | 
|  | } | 
|  |  | 
|  | // If this instruction was defined with an optional CPSR def and its dag node | 
|  | // had a live implicit CPSR def, then activate the optional CPSR def. | 
|  | MachineOperand &MO = MI.getOperand(ccOutIdx); | 
|  | MO.setReg(ARM::CPSR); | 
|  | MO.setIsDef(true); | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //                           ARM Optimization Hooks | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | // Helper function that checks if N is a null or all ones constant. | 
|  | static inline bool isZeroOrAllOnes(SDValue N, bool AllOnes) { | 
|  | return AllOnes ? isAllOnesConstant(N) : isNullConstant(N); | 
|  | } | 
|  |  | 
|  | // Return true if N is conditionally 0 or all ones. | 
|  | // Detects these expressions where cc is an i1 value: | 
|  | // | 
|  | //   (select cc 0, y)   [AllOnes=0] | 
|  | //   (select cc y, 0)   [AllOnes=0] | 
|  | //   (zext cc)          [AllOnes=0] | 
|  | //   (sext cc)          [AllOnes=0/1] | 
|  | //   (select cc -1, y)  [AllOnes=1] | 
|  | //   (select cc y, -1)  [AllOnes=1] | 
|  | // | 
|  | // Invert is set when N is the null/all ones constant when CC is false. | 
|  | // OtherOp is set to the alternative value of N. | 
|  | static bool isConditionalZeroOrAllOnes(SDNode *N, bool AllOnes, | 
|  | SDValue &CC, bool &Invert, | 
|  | SDValue &OtherOp, | 
|  | SelectionDAG &DAG) { | 
|  | switch (N->getOpcode()) { | 
|  | default: return false; | 
|  | case ISD::SELECT: { | 
|  | CC = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  | SDValue N2 = N->getOperand(2); | 
|  | if (isZeroOrAllOnes(N1, AllOnes)) { | 
|  | Invert = false; | 
|  | OtherOp = N2; | 
|  | return true; | 
|  | } | 
|  | if (isZeroOrAllOnes(N2, AllOnes)) { | 
|  | Invert = true; | 
|  | OtherOp = N1; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  | case ISD::ZERO_EXTEND: | 
|  | // (zext cc) can never be the all ones value. | 
|  | if (AllOnes) | 
|  | return false; | 
|  | LLVM_FALLTHROUGH; | 
|  | case ISD::SIGN_EXTEND: { | 
|  | SDLoc dl(N); | 
|  | EVT VT = N->getValueType(0); | 
|  | CC = N->getOperand(0); | 
|  | if (CC.getValueType() != MVT::i1 || CC.getOpcode() != ISD::SETCC) | 
|  | return false; | 
|  | Invert = !AllOnes; | 
|  | if (AllOnes) | 
|  | // When looking for an AllOnes constant, N is an sext, and the 'other' | 
|  | // value is 0. | 
|  | OtherOp = DAG.getConstant(0, dl, VT); | 
|  | else if (N->getOpcode() == ISD::ZERO_EXTEND) | 
|  | // When looking for a 0 constant, N can be zext or sext. | 
|  | OtherOp = DAG.getConstant(1, dl, VT); | 
|  | else | 
|  | OtherOp = DAG.getConstant(APInt::getAllOnesValue(VT.getSizeInBits()), dl, | 
|  | VT); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Combine a constant select operand into its use: | 
|  | // | 
|  | //   (add (select cc, 0, c), x)  -> (select cc, x, (add, x, c)) | 
|  | //   (sub x, (select cc, 0, c))  -> (select cc, x, (sub, x, c)) | 
|  | //   (and (select cc, -1, c), x) -> (select cc, x, (and, x, c))  [AllOnes=1] | 
|  | //   (or  (select cc, 0, c), x)  -> (select cc, x, (or, x, c)) | 
|  | //   (xor (select cc, 0, c), x)  -> (select cc, x, (xor, x, c)) | 
|  | // | 
|  | // The transform is rejected if the select doesn't have a constant operand that | 
|  | // is null, or all ones when AllOnes is set. | 
|  | // | 
|  | // Also recognize sext/zext from i1: | 
|  | // | 
|  | //   (add (zext cc), x) -> (select cc (add x, 1), x) | 
|  | //   (add (sext cc), x) -> (select cc (add x, -1), x) | 
|  | // | 
|  | // These transformations eventually create predicated instructions. | 
|  | // | 
|  | // @param N       The node to transform. | 
|  | // @param Slct    The N operand that is a select. | 
|  | // @param OtherOp The other N operand (x above). | 
|  | // @param DCI     Context. | 
|  | // @param AllOnes Require the select constant to be all ones instead of null. | 
|  | // @returns The new node, or SDValue() on failure. | 
|  | static | 
|  | SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | bool AllOnes = false) { | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | EVT VT = N->getValueType(0); | 
|  | SDValue NonConstantVal; | 
|  | SDValue CCOp; | 
|  | bool SwapSelectOps; | 
|  | if (!isConditionalZeroOrAllOnes(Slct.getNode(), AllOnes, CCOp, SwapSelectOps, | 
|  | NonConstantVal, DAG)) | 
|  | return SDValue(); | 
|  |  | 
|  | // Slct is now know to be the desired identity constant when CC is true. | 
|  | SDValue TrueVal = OtherOp; | 
|  | SDValue FalseVal = DAG.getNode(N->getOpcode(), SDLoc(N), VT, | 
|  | OtherOp, NonConstantVal); | 
|  | // Unless SwapSelectOps says CC should be false. | 
|  | if (SwapSelectOps) | 
|  | std::swap(TrueVal, FalseVal); | 
|  |  | 
|  | return DAG.getNode(ISD::SELECT, SDLoc(N), VT, | 
|  | CCOp, TrueVal, FalseVal); | 
|  | } | 
|  |  | 
|  | // Attempt combineSelectAndUse on each operand of a commutative operator N. | 
|  | static | 
|  | SDValue combineSelectAndUseCommutative(SDNode *N, bool AllOnes, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  | if (N0.getNode()->hasOneUse()) | 
|  | if (SDValue Result = combineSelectAndUse(N, N0, N1, DCI, AllOnes)) | 
|  | return Result; | 
|  | if (N1.getNode()->hasOneUse()) | 
|  | if (SDValue Result = combineSelectAndUse(N, N1, N0, DCI, AllOnes)) | 
|  | return Result; | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static bool IsVUZPShuffleNode(SDNode *N) { | 
|  | // VUZP shuffle node. | 
|  | if (N->getOpcode() == ARMISD::VUZP) | 
|  | return true; | 
|  |  | 
|  | // "VUZP" on i32 is an alias for VTRN. | 
|  | if (N->getOpcode() == ARMISD::VTRN && N->getValueType(0) == MVT::v2i32) | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static SDValue AddCombineToVPADD(SDNode *N, SDValue N0, SDValue N1, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // Look for ADD(VUZP.0, VUZP.1). | 
|  | if (!IsVUZPShuffleNode(N0.getNode()) || N0.getNode() != N1.getNode() || | 
|  | N0 == N1) | 
|  | return SDValue(); | 
|  |  | 
|  | // Make sure the ADD is a 64-bit add; there is no 128-bit VPADD. | 
|  | if (!N->getValueType(0).is64BitVector()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Generate vpadd. | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | SDLoc dl(N); | 
|  | SDNode *Unzip = N0.getNode(); | 
|  | EVT VT = N->getValueType(0); | 
|  |  | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | Ops.push_back(DAG.getConstant(Intrinsic::arm_neon_vpadd, dl, | 
|  | TLI.getPointerTy(DAG.getDataLayout()))); | 
|  | Ops.push_back(Unzip->getOperand(0)); | 
|  | Ops.push_back(Unzip->getOperand(1)); | 
|  |  | 
|  | return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, Ops); | 
|  | } | 
|  |  | 
|  | static SDValue AddCombineVUZPToVPADDL(SDNode *N, SDValue N0, SDValue N1, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // Check for two extended operands. | 
|  | if (!(N0.getOpcode() == ISD::SIGN_EXTEND && | 
|  | N1.getOpcode() == ISD::SIGN_EXTEND) && | 
|  | !(N0.getOpcode() == ISD::ZERO_EXTEND && | 
|  | N1.getOpcode() == ISD::ZERO_EXTEND)) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue N00 = N0.getOperand(0); | 
|  | SDValue N10 = N1.getOperand(0); | 
|  |  | 
|  | // Look for ADD(SEXT(VUZP.0), SEXT(VUZP.1)) | 
|  | if (!IsVUZPShuffleNode(N00.getNode()) || N00.getNode() != N10.getNode() || | 
|  | N00 == N10) | 
|  | return SDValue(); | 
|  |  | 
|  | // We only recognize Q register paddl here; this can't be reached until | 
|  | // after type legalization. | 
|  | if (!N00.getValueType().is64BitVector() || | 
|  | !N0.getValueType().is128BitVector()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Generate vpaddl. | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | SDLoc dl(N); | 
|  | EVT VT = N->getValueType(0); | 
|  |  | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | // Form vpaddl.sN or vpaddl.uN depending on the kind of extension. | 
|  | unsigned Opcode; | 
|  | if (N0.getOpcode() == ISD::SIGN_EXTEND) | 
|  | Opcode = Intrinsic::arm_neon_vpaddls; | 
|  | else | 
|  | Opcode = Intrinsic::arm_neon_vpaddlu; | 
|  | Ops.push_back(DAG.getConstant(Opcode, dl, | 
|  | TLI.getPointerTy(DAG.getDataLayout()))); | 
|  | EVT ElemTy = N00.getValueType().getVectorElementType(); | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | EVT ConcatVT = EVT::getVectorVT(*DAG.getContext(), ElemTy, NumElts * 2); | 
|  | SDValue Concat = DAG.getNode(ISD::CONCAT_VECTORS, SDLoc(N), ConcatVT, | 
|  | N00.getOperand(0), N00.getOperand(1)); | 
|  | Ops.push_back(Concat); | 
|  |  | 
|  | return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, Ops); | 
|  | } | 
|  |  | 
|  | // FIXME: This function shouldn't be necessary; if we lower BUILD_VECTOR in | 
|  | // an appropriate manner, we end up with ADD(VUZP(ZEXT(N))), which is | 
|  | // much easier to match. | 
|  | static SDValue | 
|  | AddCombineBUILD_VECTORToVPADDL(SDNode *N, SDValue N0, SDValue N1, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // Only perform optimization if after legalize, and if NEON is available. We | 
|  | // also expected both operands to be BUILD_VECTORs. | 
|  | if (DCI.isBeforeLegalize() || !Subtarget->hasNEON() | 
|  | || N0.getOpcode() != ISD::BUILD_VECTOR | 
|  | || N1.getOpcode() != ISD::BUILD_VECTOR) | 
|  | return SDValue(); | 
|  |  | 
|  | // Check output type since VPADDL operand elements can only be 8, 16, or 32. | 
|  | EVT VT = N->getValueType(0); | 
|  | if (!VT.isInteger() || VT.getVectorElementType() == MVT::i64) | 
|  | return SDValue(); | 
|  |  | 
|  | // Check that the vector operands are of the right form. | 
|  | // N0 and N1 are BUILD_VECTOR nodes with N number of EXTRACT_VECTOR | 
|  | // operands, where N is the size of the formed vector. | 
|  | // Each EXTRACT_VECTOR should have the same input vector and odd or even | 
|  | // index such that we have a pair wise add pattern. | 
|  |  | 
|  | // Grab the vector that all EXTRACT_VECTOR nodes should be referencing. | 
|  | if (N0->getOperand(0)->getOpcode() != ISD::EXTRACT_VECTOR_ELT) | 
|  | return SDValue(); | 
|  | SDValue Vec = N0->getOperand(0)->getOperand(0); | 
|  | SDNode *V = Vec.getNode(); | 
|  | unsigned nextIndex = 0; | 
|  |  | 
|  | // For each operands to the ADD which are BUILD_VECTORs, | 
|  | // check to see if each of their operands are an EXTRACT_VECTOR with | 
|  | // the same vector and appropriate index. | 
|  | for (unsigned i = 0, e = N0->getNumOperands(); i != e; ++i) { | 
|  | if (N0->getOperand(i)->getOpcode() == ISD::EXTRACT_VECTOR_ELT | 
|  | && N1->getOperand(i)->getOpcode() == ISD::EXTRACT_VECTOR_ELT) { | 
|  |  | 
|  | SDValue ExtVec0 = N0->getOperand(i); | 
|  | SDValue ExtVec1 = N1->getOperand(i); | 
|  |  | 
|  | // First operand is the vector, verify its the same. | 
|  | if (V != ExtVec0->getOperand(0).getNode() || | 
|  | V != ExtVec1->getOperand(0).getNode()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Second is the constant, verify its correct. | 
|  | ConstantSDNode *C0 = dyn_cast<ConstantSDNode>(ExtVec0->getOperand(1)); | 
|  | ConstantSDNode *C1 = dyn_cast<ConstantSDNode>(ExtVec1->getOperand(1)); | 
|  |  | 
|  | // For the constant, we want to see all the even or all the odd. | 
|  | if (!C0 || !C1 || C0->getZExtValue() != nextIndex | 
|  | || C1->getZExtValue() != nextIndex+1) | 
|  | return SDValue(); | 
|  |  | 
|  | // Increment index. | 
|  | nextIndex+=2; | 
|  | } else | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // Don't generate vpaddl+vmovn; we'll match it to vpadd later. Also make sure | 
|  | // we're using the entire input vector, otherwise there's a size/legality | 
|  | // mismatch somewhere. | 
|  | if (nextIndex != Vec.getValueType().getVectorNumElements() || | 
|  | Vec.getValueType().getVectorElementType() == VT.getVectorElementType()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Create VPADDL node. | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  |  | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // Build operand list. | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | Ops.push_back(DAG.getConstant(Intrinsic::arm_neon_vpaddls, dl, | 
|  | TLI.getPointerTy(DAG.getDataLayout()))); | 
|  |  | 
|  | // Input is the vector. | 
|  | Ops.push_back(Vec); | 
|  |  | 
|  | // Get widened type and narrowed type. | 
|  | MVT widenType; | 
|  | unsigned numElem = VT.getVectorNumElements(); | 
|  |  | 
|  | EVT inputLaneType = Vec.getValueType().getVectorElementType(); | 
|  | switch (inputLaneType.getSimpleVT().SimpleTy) { | 
|  | case MVT::i8: widenType = MVT::getVectorVT(MVT::i16, numElem); break; | 
|  | case MVT::i16: widenType = MVT::getVectorVT(MVT::i32, numElem); break; | 
|  | case MVT::i32: widenType = MVT::getVectorVT(MVT::i64, numElem); break; | 
|  | default: | 
|  | llvm_unreachable("Invalid vector element type for padd optimization."); | 
|  | } | 
|  |  | 
|  | SDValue tmp = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, widenType, Ops); | 
|  | unsigned ExtOp = VT.bitsGT(tmp.getValueType()) ? ISD::ANY_EXTEND : ISD::TRUNCATE; | 
|  | return DAG.getNode(ExtOp, dl, VT, tmp); | 
|  | } | 
|  |  | 
|  | static SDValue findMUL_LOHI(SDValue V) { | 
|  | if (V->getOpcode() == ISD::UMUL_LOHI || | 
|  | V->getOpcode() == ISD::SMUL_LOHI) | 
|  | return V; | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue AddCombineTo64BitSMLAL16(SDNode *AddcNode, SDNode *AddeNode, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (!Subtarget->hasBaseDSP()) | 
|  | return SDValue(); | 
|  |  | 
|  | // SMLALBB, SMLALBT, SMLALTB, SMLALTT multiply two 16-bit values and | 
|  | // accumulates the product into a 64-bit value. The 16-bit values will | 
|  | // be sign extended somehow or SRA'd into 32-bit values | 
|  | // (addc (adde (mul 16bit, 16bit), lo), hi) | 
|  | SDValue Mul = AddcNode->getOperand(0); | 
|  | SDValue Lo = AddcNode->getOperand(1); | 
|  | if (Mul.getOpcode() != ISD::MUL) { | 
|  | Lo = AddcNode->getOperand(0); | 
|  | Mul = AddcNode->getOperand(1); | 
|  | if (Mul.getOpcode() != ISD::MUL) | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue SRA = AddeNode->getOperand(0); | 
|  | SDValue Hi = AddeNode->getOperand(1); | 
|  | if (SRA.getOpcode() != ISD::SRA) { | 
|  | SRA = AddeNode->getOperand(1); | 
|  | Hi = AddeNode->getOperand(0); | 
|  | if (SRA.getOpcode() != ISD::SRA) | 
|  | return SDValue(); | 
|  | } | 
|  | if (auto Const = dyn_cast<ConstantSDNode>(SRA.getOperand(1))) { | 
|  | if (Const->getZExtValue() != 31) | 
|  | return SDValue(); | 
|  | } else | 
|  | return SDValue(); | 
|  |  | 
|  | if (SRA.getOperand(0) != Mul) | 
|  | return SDValue(); | 
|  |  | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDLoc dl(AddcNode); | 
|  | unsigned Opcode = 0; | 
|  | SDValue Op0; | 
|  | SDValue Op1; | 
|  |  | 
|  | if (isS16(Mul.getOperand(0), DAG) && isS16(Mul.getOperand(1), DAG)) { | 
|  | Opcode = ARMISD::SMLALBB; | 
|  | Op0 = Mul.getOperand(0); | 
|  | Op1 = Mul.getOperand(1); | 
|  | } else if (isS16(Mul.getOperand(0), DAG) && isSRA16(Mul.getOperand(1))) { | 
|  | Opcode = ARMISD::SMLALBT; | 
|  | Op0 = Mul.getOperand(0); | 
|  | Op1 = Mul.getOperand(1).getOperand(0); | 
|  | } else if (isSRA16(Mul.getOperand(0)) && isS16(Mul.getOperand(1), DAG)) { | 
|  | Opcode = ARMISD::SMLALTB; | 
|  | Op0 = Mul.getOperand(0).getOperand(0); | 
|  | Op1 = Mul.getOperand(1); | 
|  | } else if (isSRA16(Mul.getOperand(0)) && isSRA16(Mul.getOperand(1))) { | 
|  | Opcode = ARMISD::SMLALTT; | 
|  | Op0 = Mul->getOperand(0).getOperand(0); | 
|  | Op1 = Mul->getOperand(1).getOperand(0); | 
|  | } | 
|  |  | 
|  | if (!Op0 || !Op1) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue SMLAL = DAG.getNode(Opcode, dl, DAG.getVTList(MVT::i32, MVT::i32), | 
|  | Op0, Op1, Lo, Hi); | 
|  | // Replace the ADDs' nodes uses by the MLA node's values. | 
|  | SDValue HiMLALResult(SMLAL.getNode(), 1); | 
|  | SDValue LoMLALResult(SMLAL.getNode(), 0); | 
|  |  | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(AddcNode, 0), LoMLALResult); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(AddeNode, 0), HiMLALResult); | 
|  |  | 
|  | // Return original node to notify the driver to stop replacing. | 
|  | SDValue resNode(AddcNode, 0); | 
|  | return resNode; | 
|  | } | 
|  |  | 
|  | static SDValue AddCombineTo64bitMLAL(SDNode *AddeSubeNode, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // Look for multiply add opportunities. | 
|  | // The pattern is a ISD::UMUL_LOHI followed by two add nodes, where | 
|  | // each add nodes consumes a value from ISD::UMUL_LOHI and there is | 
|  | // a glue link from the first add to the second add. | 
|  | // If we find this pattern, we can replace the U/SMUL_LOHI, ADDC, and ADDE by | 
|  | // a S/UMLAL instruction. | 
|  | //                  UMUL_LOHI | 
|  | //                 / :lo    \ :hi | 
|  | //                V          \          [no multiline comment] | 
|  | //    loAdd ->  ADDC         | | 
|  | //                 \ :carry / | 
|  | //                  V      V | 
|  | //                    ADDE   <- hiAdd | 
|  | // | 
|  | // In the special case where only the higher part of a signed result is used | 
|  | // and the add to the low part of the result of ISD::UMUL_LOHI adds or subtracts | 
|  | // a constant with the exact value of 0x80000000, we recognize we are dealing | 
|  | // with a "rounded multiply and add" (or subtract) and transform it into | 
|  | // either a ARMISD::SMMLAR or ARMISD::SMMLSR respectively. | 
|  |  | 
|  | assert((AddeSubeNode->getOpcode() == ARMISD::ADDE || | 
|  | AddeSubeNode->getOpcode() == ARMISD::SUBE) && | 
|  | "Expect an ADDE or SUBE"); | 
|  |  | 
|  | assert(AddeSubeNode->getNumOperands() == 3 && | 
|  | AddeSubeNode->getOperand(2).getValueType() == MVT::i32 && | 
|  | "ADDE node has the wrong inputs"); | 
|  |  | 
|  | // Check that we are chained to the right ADDC or SUBC node. | 
|  | SDNode *AddcSubcNode = AddeSubeNode->getOperand(2).getNode(); | 
|  | if ((AddeSubeNode->getOpcode() == ARMISD::ADDE && | 
|  | AddcSubcNode->getOpcode() != ARMISD::ADDC) || | 
|  | (AddeSubeNode->getOpcode() == ARMISD::SUBE && | 
|  | AddcSubcNode->getOpcode() != ARMISD::SUBC)) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue AddcSubcOp0 = AddcSubcNode->getOperand(0); | 
|  | SDValue AddcSubcOp1 = AddcSubcNode->getOperand(1); | 
|  |  | 
|  | // Check if the two operands are from the same mul_lohi node. | 
|  | if (AddcSubcOp0.getNode() == AddcSubcOp1.getNode()) | 
|  | return SDValue(); | 
|  |  | 
|  | assert(AddcSubcNode->getNumValues() == 2 && | 
|  | AddcSubcNode->getValueType(0) == MVT::i32 && | 
|  | "Expect ADDC with two result values. First: i32"); | 
|  |  | 
|  | // Check that the ADDC adds the low result of the S/UMUL_LOHI. If not, it | 
|  | // maybe a SMLAL which multiplies two 16-bit values. | 
|  | if (AddeSubeNode->getOpcode() == ARMISD::ADDE && | 
|  | AddcSubcOp0->getOpcode() != ISD::UMUL_LOHI && | 
|  | AddcSubcOp0->getOpcode() != ISD::SMUL_LOHI && | 
|  | AddcSubcOp1->getOpcode() != ISD::UMUL_LOHI && | 
|  | AddcSubcOp1->getOpcode() != ISD::SMUL_LOHI) | 
|  | return AddCombineTo64BitSMLAL16(AddcSubcNode, AddeSubeNode, DCI, Subtarget); | 
|  |  | 
|  | // Check for the triangle shape. | 
|  | SDValue AddeSubeOp0 = AddeSubeNode->getOperand(0); | 
|  | SDValue AddeSubeOp1 = AddeSubeNode->getOperand(1); | 
|  |  | 
|  | // Make sure that the ADDE/SUBE operands are not coming from the same node. | 
|  | if (AddeSubeOp0.getNode() == AddeSubeOp1.getNode()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Find the MUL_LOHI node walking up ADDE/SUBE's operands. | 
|  | bool IsLeftOperandMUL = false; | 
|  | SDValue MULOp = findMUL_LOHI(AddeSubeOp0); | 
|  | if (MULOp == SDValue()) | 
|  | MULOp = findMUL_LOHI(AddeSubeOp1); | 
|  | else | 
|  | IsLeftOperandMUL = true; | 
|  | if (MULOp == SDValue()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Figure out the right opcode. | 
|  | unsigned Opc = MULOp->getOpcode(); | 
|  | unsigned FinalOpc = (Opc == ISD::SMUL_LOHI) ? ARMISD::SMLAL : ARMISD::UMLAL; | 
|  |  | 
|  | // Figure out the high and low input values to the MLAL node. | 
|  | SDValue *HiAddSub = nullptr; | 
|  | SDValue *LoMul = nullptr; | 
|  | SDValue *LowAddSub = nullptr; | 
|  |  | 
|  | // Ensure that ADDE/SUBE is from high result of ISD::xMUL_LOHI. | 
|  | if ((AddeSubeOp0 != MULOp.getValue(1)) && (AddeSubeOp1 != MULOp.getValue(1))) | 
|  | return SDValue(); | 
|  |  | 
|  | if (IsLeftOperandMUL) | 
|  | HiAddSub = &AddeSubeOp1; | 
|  | else | 
|  | HiAddSub = &AddeSubeOp0; | 
|  |  | 
|  | // Ensure that LoMul and LowAddSub are taken from correct ISD::SMUL_LOHI node | 
|  | // whose low result is fed to the ADDC/SUBC we are checking. | 
|  |  | 
|  | if (AddcSubcOp0 == MULOp.getValue(0)) { | 
|  | LoMul = &AddcSubcOp0; | 
|  | LowAddSub = &AddcSubcOp1; | 
|  | } | 
|  | if (AddcSubcOp1 == MULOp.getValue(0)) { | 
|  | LoMul = &AddcSubcOp1; | 
|  | LowAddSub = &AddcSubcOp0; | 
|  | } | 
|  |  | 
|  | if (!LoMul) | 
|  | return SDValue(); | 
|  |  | 
|  | // If HiAddSub is the same node as ADDC/SUBC or is a predecessor of ADDC/SUBC | 
|  | // the replacement below will create a cycle. | 
|  | if (AddcSubcNode == HiAddSub->getNode() || | 
|  | AddcSubcNode->isPredecessorOf(HiAddSub->getNode())) | 
|  | return SDValue(); | 
|  |  | 
|  | // Create the merged node. | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  |  | 
|  | // Start building operand list. | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | Ops.push_back(LoMul->getOperand(0)); | 
|  | Ops.push_back(LoMul->getOperand(1)); | 
|  |  | 
|  | // Check whether we can use SMMLAR, SMMLSR or SMMULR instead.  For this to be | 
|  | // the case, we must be doing signed multiplication and only use the higher | 
|  | // part of the result of the MLAL, furthermore the LowAddSub must be a constant | 
|  | // addition or subtraction with the value of 0x800000. | 
|  | if (Subtarget->hasV6Ops() && Subtarget->hasDSP() && Subtarget->useMulOps() && | 
|  | FinalOpc == ARMISD::SMLAL && !AddeSubeNode->hasAnyUseOfValue(1) && | 
|  | LowAddSub->getNode()->getOpcode() == ISD::Constant && | 
|  | static_cast<ConstantSDNode *>(LowAddSub->getNode())->getZExtValue() == | 
|  | 0x80000000) { | 
|  | Ops.push_back(*HiAddSub); | 
|  | if (AddcSubcNode->getOpcode() == ARMISD::SUBC) { | 
|  | FinalOpc = ARMISD::SMMLSR; | 
|  | } else { | 
|  | FinalOpc = ARMISD::SMMLAR; | 
|  | } | 
|  | SDValue NewNode = DAG.getNode(FinalOpc, SDLoc(AddcSubcNode), MVT::i32, Ops); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(AddeSubeNode, 0), NewNode); | 
|  |  | 
|  | return SDValue(AddeSubeNode, 0); | 
|  | } else if (AddcSubcNode->getOpcode() == ARMISD::SUBC) | 
|  | // SMMLS is generated during instruction selection and the rest of this | 
|  | // function can not handle the case where AddcSubcNode is a SUBC. | 
|  | return SDValue(); | 
|  |  | 
|  | // Finish building the operand list for {U/S}MLAL | 
|  | Ops.push_back(*LowAddSub); | 
|  | Ops.push_back(*HiAddSub); | 
|  |  | 
|  | SDValue MLALNode = DAG.getNode(FinalOpc, SDLoc(AddcSubcNode), | 
|  | DAG.getVTList(MVT::i32, MVT::i32), Ops); | 
|  |  | 
|  | // Replace the ADDs' nodes uses by the MLA node's values. | 
|  | SDValue HiMLALResult(MLALNode.getNode(), 1); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(AddeSubeNode, 0), HiMLALResult); | 
|  |  | 
|  | SDValue LoMLALResult(MLALNode.getNode(), 0); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(AddcSubcNode, 0), LoMLALResult); | 
|  |  | 
|  | // Return original node to notify the driver to stop replacing. | 
|  | return SDValue(AddeSubeNode, 0); | 
|  | } | 
|  |  | 
|  | static SDValue AddCombineTo64bitUMAAL(SDNode *AddeNode, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // UMAAL is similar to UMLAL except that it adds two unsigned values. | 
|  | // While trying to combine for the other MLAL nodes, first search for the | 
|  | // chance to use UMAAL. Check if Addc uses a node which has already | 
|  | // been combined into a UMLAL. The other pattern is UMLAL using Addc/Adde | 
|  | // as the addend, and it's handled in PerformUMLALCombine. | 
|  |  | 
|  | if (!Subtarget->hasV6Ops() || !Subtarget->hasDSP()) | 
|  | return AddCombineTo64bitMLAL(AddeNode, DCI, Subtarget); | 
|  |  | 
|  | // Check that we have a glued ADDC node. | 
|  | SDNode* AddcNode = AddeNode->getOperand(2).getNode(); | 
|  | if (AddcNode->getOpcode() != ARMISD::ADDC) | 
|  | return SDValue(); | 
|  |  | 
|  | // Find the converted UMAAL or quit if it doesn't exist. | 
|  | SDNode *UmlalNode = nullptr; | 
|  | SDValue AddHi; | 
|  | if (AddcNode->getOperand(0).getOpcode() == ARMISD::UMLAL) { | 
|  | UmlalNode = AddcNode->getOperand(0).getNode(); | 
|  | AddHi = AddcNode->getOperand(1); | 
|  | } else if (AddcNode->getOperand(1).getOpcode() == ARMISD::UMLAL) { | 
|  | UmlalNode = AddcNode->getOperand(1).getNode(); | 
|  | AddHi = AddcNode->getOperand(0); | 
|  | } else { | 
|  | return AddCombineTo64bitMLAL(AddeNode, DCI, Subtarget); | 
|  | } | 
|  |  | 
|  | // The ADDC should be glued to an ADDE node, which uses the same UMLAL as | 
|  | // the ADDC as well as Zero. | 
|  | if (!isNullConstant(UmlalNode->getOperand(3))) | 
|  | return SDValue(); | 
|  |  | 
|  | if ((isNullConstant(AddeNode->getOperand(0)) && | 
|  | AddeNode->getOperand(1).getNode() == UmlalNode) || | 
|  | (AddeNode->getOperand(0).getNode() == UmlalNode && | 
|  | isNullConstant(AddeNode->getOperand(1)))) { | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDValue Ops[] = { UmlalNode->getOperand(0), UmlalNode->getOperand(1), | 
|  | UmlalNode->getOperand(2), AddHi }; | 
|  | SDValue UMAAL =  DAG.getNode(ARMISD::UMAAL, SDLoc(AddcNode), | 
|  | DAG.getVTList(MVT::i32, MVT::i32), Ops); | 
|  |  | 
|  | // Replace the ADDs' nodes uses by the UMAAL node's values. | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(AddeNode, 0), SDValue(UMAAL.getNode(), 1)); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(AddcNode, 0), SDValue(UMAAL.getNode(), 0)); | 
|  |  | 
|  | // Return original node to notify the driver to stop replacing. | 
|  | return SDValue(AddeNode, 0); | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformUMLALCombine(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (!Subtarget->hasV6Ops() || !Subtarget->hasDSP()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Check that we have a pair of ADDC and ADDE as operands. | 
|  | // Both addends of the ADDE must be zero. | 
|  | SDNode* AddcNode = N->getOperand(2).getNode(); | 
|  | SDNode* AddeNode = N->getOperand(3).getNode(); | 
|  | if ((AddcNode->getOpcode() == ARMISD::ADDC) && | 
|  | (AddeNode->getOpcode() == ARMISD::ADDE) && | 
|  | isNullConstant(AddeNode->getOperand(0)) && | 
|  | isNullConstant(AddeNode->getOperand(1)) && | 
|  | (AddeNode->getOperand(2).getNode() == AddcNode)) | 
|  | return DAG.getNode(ARMISD::UMAAL, SDLoc(N), | 
|  | DAG.getVTList(MVT::i32, MVT::i32), | 
|  | {N->getOperand(0), N->getOperand(1), | 
|  | AddcNode->getOperand(0), AddcNode->getOperand(1)}); | 
|  | else | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformAddcSubcCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | SelectionDAG &DAG(DCI.DAG); | 
|  |  | 
|  | if (N->getOpcode() == ARMISD::SUBC) { | 
|  | // (SUBC (ADDE 0, 0, C), 1) -> C | 
|  | SDValue LHS = N->getOperand(0); | 
|  | SDValue RHS = N->getOperand(1); | 
|  | if (LHS->getOpcode() == ARMISD::ADDE && | 
|  | isNullConstant(LHS->getOperand(0)) && | 
|  | isNullConstant(LHS->getOperand(1)) && isOneConstant(RHS)) { | 
|  | return DCI.CombineTo(N, SDValue(N, 0), LHS->getOperand(2)); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | SDValue RHS = N->getOperand(1); | 
|  | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) { | 
|  | int32_t imm = C->getSExtValue(); | 
|  | if (imm < 0 && imm > std::numeric_limits<int>::min()) { | 
|  | SDLoc DL(N); | 
|  | RHS = DAG.getConstant(-imm, DL, MVT::i32); | 
|  | unsigned Opcode = (N->getOpcode() == ARMISD::ADDC) ? ARMISD::SUBC | 
|  | : ARMISD::ADDC; | 
|  | return DAG.getNode(Opcode, DL, N->getVTList(), N->getOperand(0), RHS); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformAddeSubeCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDValue RHS = N->getOperand(1); | 
|  | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) { | 
|  | int64_t imm = C->getSExtValue(); | 
|  | if (imm < 0) { | 
|  | SDLoc DL(N); | 
|  |  | 
|  | // The with-carry-in form matches bitwise not instead of the negation. | 
|  | // Effectively, the inverse interpretation of the carry flag already | 
|  | // accounts for part of the negation. | 
|  | RHS = DAG.getConstant(~imm, DL, MVT::i32); | 
|  |  | 
|  | unsigned Opcode = (N->getOpcode() == ARMISD::ADDE) ? ARMISD::SUBE | 
|  | : ARMISD::ADDE; | 
|  | return DAG.getNode(Opcode, DL, N->getVTList(), | 
|  | N->getOperand(0), RHS, N->getOperand(2)); | 
|  | } | 
|  | } | 
|  | } else if (N->getOperand(1)->getOpcode() == ISD::SMUL_LOHI) { | 
|  | return AddCombineTo64bitMLAL(N, DCI, Subtarget); | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformVSELECTCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // Transforms vselect(not(cond), lhs, rhs) into vselect(cond, rhs, lhs). | 
|  | // | 
|  | // We need to re-implement this optimization here as the implementation in the | 
|  | // Target-Independent DAGCombiner does not handle the kind of constant we make | 
|  | // (it calls isConstOrConstSplat with AllowTruncation set to false - and for | 
|  | // good reason, allowing truncation there would break other targets). | 
|  | // | 
|  | // Currently, this is only done for MVE, as it's the only target that benefits | 
|  | // from this transformation (e.g. VPNOT+VPSEL becomes a single VPSEL). | 
|  | if (!Subtarget->hasMVEIntegerOps()) | 
|  | return SDValue(); | 
|  |  | 
|  | if (N->getOperand(0).getOpcode() != ISD::XOR) | 
|  | return SDValue(); | 
|  | SDValue XOR = N->getOperand(0); | 
|  |  | 
|  | // Check if the XOR's RHS is either a 1, or a BUILD_VECTOR of 1s. | 
|  | // It is important to check with truncation allowed as the BUILD_VECTORs we | 
|  | // generate in those situations will truncate their operands. | 
|  | ConstantSDNode *Const = | 
|  | isConstOrConstSplat(XOR->getOperand(1), /*AllowUndefs*/ false, | 
|  | /*AllowTruncation*/ true); | 
|  | if (!Const || !Const->isOne()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Rewrite into vselect(cond, rhs, lhs). | 
|  | SDValue Cond = XOR->getOperand(0); | 
|  | SDValue LHS = N->getOperand(1); | 
|  | SDValue RHS = N->getOperand(2); | 
|  | EVT Type = N->getValueType(0); | 
|  | return DCI.DAG.getNode(ISD::VSELECT, SDLoc(N), Type, Cond, RHS, LHS); | 
|  | } | 
|  |  | 
|  | static SDValue PerformABSCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | SDValue res; | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  |  | 
|  | if (TLI.isOperationLegal(N->getOpcode(), N->getValueType(0))) | 
|  | return SDValue(); | 
|  |  | 
|  | if (!TLI.expandABS(N, res, DAG)) | 
|  | return SDValue(); | 
|  |  | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /// PerformADDECombine - Target-specific dag combine transform from | 
|  | /// ARMISD::ADDC, ARMISD::ADDE, and ISD::MUL_LOHI to MLAL or | 
|  | /// ARMISD::ADDC, ARMISD::ADDE and ARMISD::UMLAL to ARMISD::UMAAL | 
|  | static SDValue PerformADDECombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // Only ARM and Thumb2 support UMLAL/SMLAL. | 
|  | if (Subtarget->isThumb1Only()) | 
|  | return PerformAddeSubeCombine(N, DCI, Subtarget); | 
|  |  | 
|  | // Only perform the checks after legalize when the pattern is available. | 
|  | if (DCI.isBeforeLegalize()) return SDValue(); | 
|  |  | 
|  | return AddCombineTo64bitUMAAL(N, DCI, Subtarget); | 
|  | } | 
|  |  | 
|  | /// PerformADDCombineWithOperands - Try DAG combinations for an ADD with | 
|  | /// operands N0 and N1.  This is a helper for PerformADDCombine that is | 
|  | /// called with the default operands, and if that fails, with commuted | 
|  | /// operands. | 
|  | static SDValue PerformADDCombineWithOperands(SDNode *N, SDValue N0, SDValue N1, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget){ | 
|  | // Attempt to create vpadd for this add. | 
|  | if (SDValue Result = AddCombineToVPADD(N, N0, N1, DCI, Subtarget)) | 
|  | return Result; | 
|  |  | 
|  | // Attempt to create vpaddl for this add. | 
|  | if (SDValue Result = AddCombineVUZPToVPADDL(N, N0, N1, DCI, Subtarget)) | 
|  | return Result; | 
|  | if (SDValue Result = AddCombineBUILD_VECTORToVPADDL(N, N0, N1, DCI, | 
|  | Subtarget)) | 
|  | return Result; | 
|  |  | 
|  | // fold (add (select cc, 0, c), x) -> (select cc, x, (add, x, c)) | 
|  | if (N0.getNode()->hasOneUse()) | 
|  | if (SDValue Result = combineSelectAndUse(N, N0, N1, DCI)) | 
|  | return Result; | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformADDVecReduce(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (!Subtarget->hasMVEIntegerOps() || N->getValueType(0) != MVT::i64) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  |  | 
|  | // We are looking for a i64 add of a VADDLVx. Due to these being i64's, this | 
|  | // will look like: | 
|  | //   t1: i32,i32 = ARMISD::VADDLVs x | 
|  | //   t2: i64 = build_pair t1, t1:1 | 
|  | //   t3: i64 = add t2, y | 
|  | // We also need to check for sext / zext and commutitive adds. | 
|  | auto MakeVecReduce = [&](unsigned Opcode, unsigned OpcodeA, SDValue NA, | 
|  | SDValue NB) { | 
|  | if (NB->getOpcode() != ISD::BUILD_PAIR) | 
|  | return SDValue(); | 
|  | SDValue VecRed = NB->getOperand(0); | 
|  | if (VecRed->getOpcode() != Opcode || VecRed.getResNo() != 0 || | 
|  | NB->getOperand(1) != SDValue(VecRed.getNode(), 1)) | 
|  | return SDValue(); | 
|  |  | 
|  | SDLoc dl(N); | 
|  | SmallVector<SDValue, 4> Ops; | 
|  | Ops.push_back(DCI.DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, NA, | 
|  | DCI.DAG.getConstant(0, dl, MVT::i32))); | 
|  | Ops.push_back(DCI.DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, NA, | 
|  | DCI.DAG.getConstant(1, dl, MVT::i32))); | 
|  | for (unsigned i = 0, e = VecRed.getNumOperands(); i < e; i++) | 
|  | Ops.push_back(VecRed->getOperand(i)); | 
|  | SDValue Red = DCI.DAG.getNode(OpcodeA, dl, | 
|  | DCI.DAG.getVTList({MVT::i32, MVT::i32}), Ops); | 
|  | return DCI.DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Red, | 
|  | SDValue(Red.getNode(), 1)); | 
|  | }; | 
|  |  | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VADDLVs, ARMISD::VADDLVAs, N0, N1)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VADDLVu, ARMISD::VADDLVAu, N0, N1)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VADDLVs, ARMISD::VADDLVAs, N1, N0)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VADDLVu, ARMISD::VADDLVAu, N1, N0)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VADDLVps, ARMISD::VADDLVAps, N0, N1)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VADDLVpu, ARMISD::VADDLVApu, N0, N1)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VADDLVps, ARMISD::VADDLVAps, N1, N0)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VADDLVpu, ARMISD::VADDLVApu, N1, N0)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VMLALVs, ARMISD::VMLALVAs, N0, N1)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VMLALVu, ARMISD::VMLALVAu, N0, N1)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VMLALVs, ARMISD::VMLALVAs, N1, N0)) | 
|  | return M; | 
|  | if (SDValue M = MakeVecReduce(ARMISD::VMLALVu, ARMISD::VMLALVAu, N1, N0)) | 
|  | return M; | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | bool | 
|  | ARMTargetLowering::isDesirableToCommuteWithShift(const SDNode *N, | 
|  | CombineLevel Level) const { | 
|  | if (Level == BeforeLegalizeTypes) | 
|  | return true; | 
|  |  | 
|  | if (N->getOpcode() != ISD::SHL) | 
|  | return true; | 
|  |  | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | // Avoid making expensive immediates by commuting shifts. (This logic | 
|  | // only applies to Thumb1 because ARM and Thumb2 immediates can be shifted | 
|  | // for free.) | 
|  | if (N->getOpcode() != ISD::SHL) | 
|  | return true; | 
|  | SDValue N1 = N->getOperand(0); | 
|  | if (N1->getOpcode() != ISD::ADD && N1->getOpcode() != ISD::AND && | 
|  | N1->getOpcode() != ISD::OR && N1->getOpcode() != ISD::XOR) | 
|  | return true; | 
|  | if (auto *Const = dyn_cast<ConstantSDNode>(N1->getOperand(1))) { | 
|  | if (Const->getAPIntValue().ult(256)) | 
|  | return false; | 
|  | if (N1->getOpcode() == ISD::ADD && Const->getAPIntValue().slt(0) && | 
|  | Const->getAPIntValue().sgt(-256)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Turn off commute-with-shift transform after legalization, so it doesn't | 
|  | // conflict with PerformSHLSimplify.  (We could try to detect when | 
|  | // PerformSHLSimplify would trigger more precisely, but it isn't | 
|  | // really necessary.) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::shouldFoldConstantShiftPairToMask( | 
|  | const SDNode *N, CombineLevel Level) const { | 
|  | if (!Subtarget->isThumb1Only()) | 
|  | return true; | 
|  |  | 
|  | if (Level == BeforeLegalizeTypes) | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::preferIncOfAddToSubOfNot(EVT VT) const { | 
|  | if (!Subtarget->hasNEON()) { | 
|  | if (Subtarget->isThumb1Only()) | 
|  | return VT.getScalarSizeInBits() <= 32; | 
|  | return true; | 
|  | } | 
|  | return VT.isScalarInteger(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformSHLSimplify(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *ST) { | 
|  | // Allow the generic combiner to identify potential bswaps. | 
|  | if (DCI.isBeforeLegalize()) | 
|  | return SDValue(); | 
|  |  | 
|  | // DAG combiner will fold: | 
|  | // (shl (add x, c1), c2) -> (add (shl x, c2), c1 << c2) | 
|  | // (shl (or x, c1), c2) -> (or (shl x, c2), c1 << c2 | 
|  | // Other code patterns that can be also be modified have the following form: | 
|  | // b + ((a << 1) | 510) | 
|  | // b + ((a << 1) & 510) | 
|  | // b + ((a << 1) ^ 510) | 
|  | // b + ((a << 1) + 510) | 
|  |  | 
|  | // Many instructions can  perform the shift for free, but it requires both | 
|  | // the operands to be registers. If c1 << c2 is too large, a mov immediate | 
|  | // instruction will needed. So, unfold back to the original pattern if: | 
|  | // - if c1 and c2 are small enough that they don't require mov imms. | 
|  | // - the user(s) of the node can perform an shl | 
|  |  | 
|  | // No shifted operands for 16-bit instructions. | 
|  | if (ST->isThumb() && ST->isThumb1Only()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Check that all the users could perform the shl themselves. | 
|  | for (auto U : N->uses()) { | 
|  | switch(U->getOpcode()) { | 
|  | default: | 
|  | return SDValue(); | 
|  | case ISD::SUB: | 
|  | case ISD::ADD: | 
|  | case ISD::AND: | 
|  | case ISD::OR: | 
|  | case ISD::XOR: | 
|  | case ISD::SETCC: | 
|  | case ARMISD::CMP: | 
|  | // Check that the user isn't already using a constant because there | 
|  | // aren't any instructions that support an immediate operand and a | 
|  | // shifted operand. | 
|  | if (isa<ConstantSDNode>(U->getOperand(0)) || | 
|  | isa<ConstantSDNode>(U->getOperand(1))) | 
|  | return SDValue(); | 
|  |  | 
|  | // Check that it's not already using a shift. | 
|  | if (U->getOperand(0).getOpcode() == ISD::SHL || | 
|  | U->getOperand(1).getOpcode() == ISD::SHL) | 
|  | return SDValue(); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (N->getOpcode() != ISD::ADD && N->getOpcode() != ISD::OR && | 
|  | N->getOpcode() != ISD::XOR && N->getOpcode() != ISD::AND) | 
|  | return SDValue(); | 
|  |  | 
|  | if (N->getOperand(0).getOpcode() != ISD::SHL) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue SHL = N->getOperand(0); | 
|  |  | 
|  | auto *C1ShlC2 = dyn_cast<ConstantSDNode>(N->getOperand(1)); | 
|  | auto *C2 = dyn_cast<ConstantSDNode>(SHL.getOperand(1)); | 
|  | if (!C1ShlC2 || !C2) | 
|  | return SDValue(); | 
|  |  | 
|  | APInt C2Int = C2->getAPIntValue(); | 
|  | APInt C1Int = C1ShlC2->getAPIntValue(); | 
|  |  | 
|  | // Check that performing a lshr will not lose any information. | 
|  | APInt Mask = APInt::getHighBitsSet(C2Int.getBitWidth(), | 
|  | C2Int.getBitWidth() - C2->getZExtValue()); | 
|  | if ((C1Int & Mask) != C1Int) | 
|  | return SDValue(); | 
|  |  | 
|  | // Shift the first constant. | 
|  | C1Int.lshrInPlace(C2Int); | 
|  |  | 
|  | // The immediates are encoded as an 8-bit value that can be rotated. | 
|  | auto LargeImm = [](const APInt &Imm) { | 
|  | unsigned Zeros = Imm.countLeadingZeros() + Imm.countTrailingZeros(); | 
|  | return Imm.getBitWidth() - Zeros > 8; | 
|  | }; | 
|  |  | 
|  | if (LargeImm(C1Int) || LargeImm(C2Int)) | 
|  | return SDValue(); | 
|  |  | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDLoc dl(N); | 
|  | SDValue X = SHL.getOperand(0); | 
|  | SDValue BinOp = DAG.getNode(N->getOpcode(), dl, MVT::i32, X, | 
|  | DAG.getConstant(C1Int, dl, MVT::i32)); | 
|  | // Shift left to compensate for the lshr of C1Int. | 
|  | SDValue Res = DAG.getNode(ISD::SHL, dl, MVT::i32, BinOp, SHL.getOperand(1)); | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "Simplify shl use:\n"; SHL.getOperand(0).dump(); | 
|  | SHL.dump(); N->dump()); | 
|  | LLVM_DEBUG(dbgs() << "Into:\n"; X.dump(); BinOp.dump(); Res.dump()); | 
|  | return Res; | 
|  | } | 
|  |  | 
|  |  | 
|  | /// PerformADDCombine - Target-specific dag combine xforms for ISD::ADD. | 
|  | /// | 
|  | static SDValue PerformADDCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  |  | 
|  | // Only works one way, because it needs an immediate operand. | 
|  | if (SDValue Result = PerformSHLSimplify(N, DCI, Subtarget)) | 
|  | return Result; | 
|  |  | 
|  | if (SDValue Result = PerformADDVecReduce(N, DCI, Subtarget)) | 
|  | return Result; | 
|  |  | 
|  | // First try with the default operand order. | 
|  | if (SDValue Result = PerformADDCombineWithOperands(N, N0, N1, DCI, Subtarget)) | 
|  | return Result; | 
|  |  | 
|  | // If that didn't work, try again with the operands commuted. | 
|  | return PerformADDCombineWithOperands(N, N1, N0, DCI, Subtarget); | 
|  | } | 
|  |  | 
|  | /// PerformSUBCombine - Target-specific dag combine xforms for ISD::SUB. | 
|  | /// | 
|  | static SDValue PerformSUBCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  |  | 
|  | // fold (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) | 
|  | if (N1.getNode()->hasOneUse()) | 
|  | if (SDValue Result = combineSelectAndUse(N, N1, N0, DCI)) | 
|  | return Result; | 
|  |  | 
|  | if (!Subtarget->hasMVEIntegerOps() || !N->getValueType(0).isVector()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Fold (sub (ARMvmovImm 0), (ARMvdup x)) -> (ARMvdup (sub 0, x)) | 
|  | // so that we can readily pattern match more mve instructions which can use | 
|  | // a scalar operand. | 
|  | SDValue VDup = N->getOperand(1); | 
|  | if (VDup->getOpcode() != ARMISD::VDUP) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue VMov = N->getOperand(0); | 
|  | if (VMov->getOpcode() == ISD::BITCAST) | 
|  | VMov = VMov->getOperand(0); | 
|  |  | 
|  | if (VMov->getOpcode() != ARMISD::VMOVIMM || !isZeroVector(VMov)) | 
|  | return SDValue(); | 
|  |  | 
|  | SDLoc dl(N); | 
|  | SDValue Negate = DCI.DAG.getNode(ISD::SUB, dl, MVT::i32, | 
|  | DCI.DAG.getConstant(0, dl, MVT::i32), | 
|  | VDup->getOperand(0)); | 
|  | return DCI.DAG.getNode(ARMISD::VDUP, dl, N->getValueType(0), Negate); | 
|  | } | 
|  |  | 
|  | /// PerformVMULCombine | 
|  | /// Distribute (A + B) * C to (A * C) + (B * C) to take advantage of the | 
|  | /// special multiplier accumulator forwarding. | 
|  | ///   vmul d3, d0, d2 | 
|  | ///   vmla d3, d1, d2 | 
|  | /// is faster than | 
|  | ///   vadd d3, d0, d1 | 
|  | ///   vmul d3, d3, d2 | 
|  | //  However, for (A + B) * (A + B), | 
|  | //    vadd d2, d0, d1 | 
|  | //    vmul d3, d0, d2 | 
|  | //    vmla d3, d1, d2 | 
|  | //  is slower than | 
|  | //    vadd d2, d0, d1 | 
|  | //    vmul d3, d2, d2 | 
|  | static SDValue PerformVMULCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (!Subtarget->hasVMLxForwarding()) | 
|  | return SDValue(); | 
|  |  | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  | unsigned Opcode = N0.getOpcode(); | 
|  | if (Opcode != ISD::ADD && Opcode != ISD::SUB && | 
|  | Opcode != ISD::FADD && Opcode != ISD::FSUB) { | 
|  | Opcode = N1.getOpcode(); | 
|  | if (Opcode != ISD::ADD && Opcode != ISD::SUB && | 
|  | Opcode != ISD::FADD && Opcode != ISD::FSUB) | 
|  | return SDValue(); | 
|  | std::swap(N0, N1); | 
|  | } | 
|  |  | 
|  | if (N0 == N1) | 
|  | return SDValue(); | 
|  |  | 
|  | EVT VT = N->getValueType(0); | 
|  | SDLoc DL(N); | 
|  | SDValue N00 = N0->getOperand(0); | 
|  | SDValue N01 = N0->getOperand(1); | 
|  | return DAG.getNode(Opcode, DL, VT, | 
|  | DAG.getNode(ISD::MUL, DL, VT, N00, N1), | 
|  | DAG.getNode(ISD::MUL, DL, VT, N01, N1)); | 
|  | } | 
|  |  | 
|  | static SDValue PerformMVEVMULLCombine(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | EVT VT = N->getValueType(0); | 
|  | if (VT != MVT::v2i64) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  |  | 
|  | auto IsSignExt = [&](SDValue Op) { | 
|  | if (Op->getOpcode() != ISD::SIGN_EXTEND_INREG) | 
|  | return SDValue(); | 
|  | EVT VT = cast<VTSDNode>(Op->getOperand(1))->getVT(); | 
|  | if (VT.getScalarSizeInBits() == 32) | 
|  | return Op->getOperand(0); | 
|  | return SDValue(); | 
|  | }; | 
|  | auto IsZeroExt = [&](SDValue Op) { | 
|  | // Zero extends are a little more awkward. At the point we are matching | 
|  | // this, we are looking for an AND with a (-1, 0, -1, 0) buildvector mask. | 
|  | // That might be before of after a bitcast depending on how the and is | 
|  | // placed. Because this has to look through bitcasts, it is currently only | 
|  | // supported on LE. | 
|  | if (!Subtarget->isLittle()) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue And = Op; | 
|  | if (And->getOpcode() == ISD::BITCAST) | 
|  | And = And->getOperand(0); | 
|  | if (And->getOpcode() != ISD::AND) | 
|  | return SDValue(); | 
|  | SDValue Mask = And->getOperand(1); | 
|  | if (Mask->getOpcode() == ISD::BITCAST) | 
|  | Mask = Mask->getOperand(0); | 
|  |  | 
|  | if (Mask->getOpcode() != ISD::BUILD_VECTOR || | 
|  | Mask.getValueType() != MVT::v4i32) | 
|  | return SDValue(); | 
|  | if (isAllOnesConstant(Mask->getOperand(0)) && | 
|  | isNullConstant(Mask->getOperand(1)) && | 
|  | isAllOnesConstant(Mask->getOperand(2)) && | 
|  | isNullConstant(Mask->getOperand(3))) | 
|  | return And->getOperand(0); | 
|  | return SDValue(); | 
|  | }; | 
|  |  | 
|  | SDLoc dl(N); | 
|  | if (SDValue Op0 = IsSignExt(N0)) { | 
|  | if (SDValue Op1 = IsSignExt(N1)) { | 
|  | SDValue New0a = DAG.getNode(ARMISD::VECTOR_REG_CAST, dl, MVT::v4i32, Op0); | 
|  | SDValue New1a = DAG.getNode(ARMISD::VECTOR_REG_CAST, dl, MVT::v4i32, Op1); | 
|  | return DAG.getNode(ARMISD::VMULLs, dl, VT, New0a, New1a); | 
|  | } | 
|  | } | 
|  | if (SDValue Op0 = IsZeroExt(N0)) { | 
|  | if (SDValue Op1 = IsZeroExt(N1)) { | 
|  | SDValue New0a = DAG.getNode(ARMISD::VECTOR_REG_CAST, dl, MVT::v4i32, Op0); | 
|  | SDValue New1a = DAG.getNode(ARMISD::VECTOR_REG_CAST, dl, MVT::v4i32, Op1); | 
|  | return DAG.getNode(ARMISD::VMULLu, dl, VT, New0a, New1a); | 
|  | } | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformMULCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  |  | 
|  | EVT VT = N->getValueType(0); | 
|  | if (Subtarget->hasMVEIntegerOps() && VT == MVT::v2i64) | 
|  | return PerformMVEVMULLCombine(N, DAG, Subtarget); | 
|  |  | 
|  | if (Subtarget->isThumb1Only()) | 
|  | return SDValue(); | 
|  |  | 
|  | if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer()) | 
|  | return SDValue(); | 
|  |  | 
|  | if (VT.is64BitVector() || VT.is128BitVector()) | 
|  | return PerformVMULCombine(N, DCI, Subtarget); | 
|  | if (VT != MVT::i32) | 
|  | return SDValue(); | 
|  |  | 
|  | ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1)); | 
|  | if (!C) | 
|  | return SDValue(); | 
|  |  | 
|  | int64_t MulAmt = C->getSExtValue(); | 
|  | unsigned ShiftAmt = countTrailingZeros<uint64_t>(MulAmt); | 
|  |  | 
|  | ShiftAmt = ShiftAmt & (32 - 1); | 
|  | SDValue V = N->getOperand(0); | 
|  | SDLoc DL(N); | 
|  |  | 
|  | SDValue Res; | 
|  | MulAmt >>= ShiftAmt; | 
|  |  | 
|  | if (MulAmt >= 0) { | 
|  | if (isPowerOf2_32(MulAmt - 1)) { | 
|  | // (mul x, 2^N + 1) => (add (shl x, N), x) | 
|  | Res = DAG.getNode(ISD::ADD, DL, VT, | 
|  | V, | 
|  | DAG.getNode(ISD::SHL, DL, VT, | 
|  | V, | 
|  | DAG.getConstant(Log2_32(MulAmt - 1), DL, | 
|  | MVT::i32))); | 
|  | } else if (isPowerOf2_32(MulAmt + 1)) { | 
|  | // (mul x, 2^N - 1) => (sub (shl x, N), x) | 
|  | Res = DAG.getNode(ISD::SUB, DL, VT, | 
|  | DAG.getNode(ISD::SHL, DL, VT, | 
|  | V, | 
|  | DAG.getConstant(Log2_32(MulAmt + 1), DL, | 
|  | MVT::i32)), | 
|  | V); | 
|  | } else | 
|  | return SDValue(); | 
|  | } else { | 
|  | uint64_t MulAmtAbs = -MulAmt; | 
|  | if (isPowerOf2_32(MulAmtAbs + 1)) { | 
|  | // (mul x, -(2^N - 1)) => (sub x, (shl x, N)) | 
|  | Res = DAG.getNode(ISD::SUB, DL, VT, | 
|  | V, | 
|  | DAG.getNode(ISD::SHL, DL, VT, | 
|  | V, | 
|  | DAG.getConstant(Log2_32(MulAmtAbs + 1), DL, | 
|  | MVT::i32))); | 
|  | } else if (isPowerOf2_32(MulAmtAbs - 1)) { | 
|  | // (mul x, -(2^N + 1)) => - (add (shl x, N), x) | 
|  | Res = DAG.getNode(ISD::ADD, DL, VT, | 
|  | V, | 
|  | DAG.getNode(ISD::SHL, DL, VT, | 
|  | V, | 
|  | DAG.getConstant(Log2_32(MulAmtAbs - 1), DL, | 
|  | MVT::i32))); | 
|  | Res = DAG.getNode(ISD::SUB, DL, VT, | 
|  | DAG.getConstant(0, DL, MVT::i32), Res); | 
|  | } else | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | if (ShiftAmt != 0) | 
|  | Res = DAG.getNode(ISD::SHL, DL, VT, | 
|  | Res, DAG.getConstant(ShiftAmt, DL, MVT::i32)); | 
|  |  | 
|  | // Do not add new nodes to DAG combiner worklist. | 
|  | DCI.CombineTo(N, Res, false); | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue CombineANDShift(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // Allow DAGCombine to pattern-match before we touch the canonical form. | 
|  | if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer()) | 
|  | return SDValue(); | 
|  |  | 
|  | if (N->getValueType(0) != MVT::i32) | 
|  | return SDValue(); | 
|  |  | 
|  | ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1)); | 
|  | if (!N1C) | 
|  | return SDValue(); | 
|  |  | 
|  | uint32_t C1 = (uint32_t)N1C->getZExtValue(); | 
|  | // Don't transform uxtb/uxth. | 
|  | if (C1 == 255 || C1 == 65535) | 
|  | return SDValue(); | 
|  |  | 
|  | SDNode *N0 = N->getOperand(0).getNode(); | 
|  | if (!N0->hasOneUse()) | 
|  | return SDValue(); | 
|  |  | 
|  | if (N0->getOpcode() != ISD::SHL && N0->getOpcode() != ISD::SRL) | 
|  | return SDValue(); | 
|  |  | 
|  | bool LeftShift = N0->getOpcode() == ISD::SHL; | 
|  |  | 
|  | ConstantSDNode *N01C = dyn_cast<ConstantSDNode>(N0->getOperand(1)); | 
|  | if (!N01C) | 
|  | return SDValue(); | 
|  |  | 
|  | uint32_t C2 = (uint32_t)N01C->getZExtValue(); | 
|  | if (!C2 || C2 >= 32) | 
|  | return SDValue(); | 
|  |  | 
|  | // Clear irrelevant bits in the mask. | 
|  | if (LeftShift) | 
|  | C1 &= (-1U << C2); | 
|  | else | 
|  | C1 &= (-1U >> C2); | 
|  |  | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDLoc DL(N); | 
|  |  | 
|  | // We have a pattern of the form "(and (shl x, c2) c1)" or | 
|  | // "(and (srl x, c2) c1)", where c1 is a shifted mask. Try to | 
|  | // transform to a pair of shifts, to save materializing c1. | 
|  |  | 
|  | // First pattern: right shift, then mask off leading bits. | 
|  | // FIXME: Use demanded bits? | 
|  | if (!LeftShift && isMask_32(C1)) { | 
|  | uint32_t C3 = countLeadingZeros(C1); | 
|  | if (C2 < C3) { | 
|  | SDValue SHL = DAG.getNode(ISD::SHL, DL, MVT::i32, N0->getOperand(0), | 
|  | DAG.getConstant(C3 - C2, DL, MVT::i32)); | 
|  | return DAG.getNode(ISD::SRL, DL, MVT::i32, SHL, | 
|  | DAG.getConstant(C3, DL, MVT::i32)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // First pattern, reversed: left shift, then mask off trailing bits. | 
|  | if (LeftShift && isMask_32(~C1)) { | 
|  | uint32_t C3 = countTrailingZeros(C1); | 
|  | if (C2 < C3) { | 
|  | SDValue SHL = DAG.getNode(ISD::SRL, DL, MVT::i32, N0->getOperand(0), | 
|  | DAG.getConstant(C3 - C2, DL, MVT::i32)); | 
|  | return DAG.getNode(ISD::SHL, DL, MVT::i32, SHL, | 
|  | DAG.getConstant(C3, DL, MVT::i32)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Second pattern: left shift, then mask off leading bits. | 
|  | // FIXME: Use demanded bits? | 
|  | if (LeftShift && isShiftedMask_32(C1)) { | 
|  | uint32_t Trailing = countTrailingZeros(C1); | 
|  | uint32_t C3 = countLeadingZeros(C1); | 
|  | if (Trailing == C2 && C2 + C3 < 32) { | 
|  | SDValue SHL = DAG.getNode(ISD::SHL, DL, MVT::i32, N0->getOperand(0), | 
|  | DAG.getConstant(C2 + C3, DL, MVT::i32)); | 
|  | return DAG.getNode(ISD::SRL, DL, MVT::i32, SHL, | 
|  | DAG.getConstant(C3, DL, MVT::i32)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Second pattern, reversed: right shift, then mask off trailing bits. | 
|  | // FIXME: Handle other patterns of known/demanded bits. | 
|  | if (!LeftShift && isShiftedMask_32(C1)) { | 
|  | uint32_t Leading = countLeadingZeros(C1); | 
|  | uint32_t C3 = countTrailingZeros(C1); | 
|  | if (Leading == C2 && C2 + C3 < 32) { | 
|  | SDValue SHL = DAG.getNode(ISD::SRL, DL, MVT::i32, N0->getOperand(0), | 
|  | DAG.getConstant(C2 + C3, DL, MVT::i32)); | 
|  | return DAG.getNode(ISD::SHL, DL, MVT::i32, SHL, | 
|  | DAG.getConstant(C3, DL, MVT::i32)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // FIXME: Transform "(and (shl x, c2) c1)" -> | 
|  | // "(shl (and x, c1>>c2), c2)" if "c1 >> c2" is a cheaper immediate than | 
|  | // c1. | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformANDCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // Attempt to use immediate-form VBIC | 
|  | BuildVectorSDNode *BVN = dyn_cast<BuildVectorSDNode>(N->getOperand(1)); | 
|  | SDLoc dl(N); | 
|  | EVT VT = N->getValueType(0); | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  |  | 
|  | if(!DAG.getTargetLoweringInfo().isTypeLegal(VT)) | 
|  | return SDValue(); | 
|  |  | 
|  | APInt SplatBits, SplatUndef; | 
|  | unsigned SplatBitSize; | 
|  | bool HasAnyUndefs; | 
|  | if (BVN && (Subtarget->hasNEON() || Subtarget->hasMVEIntegerOps()) && | 
|  | BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs)) { | 
|  | if (SplatBitSize <= 64) { | 
|  | EVT VbicVT; | 
|  | SDValue Val = isVMOVModifiedImm((~SplatBits).getZExtValue(), | 
|  | SplatUndef.getZExtValue(), SplatBitSize, | 
|  | DAG, dl, VbicVT, VT, OtherModImm); | 
|  | if (Val.getNode()) { | 
|  | SDValue Input = | 
|  | DAG.getNode(ISD::BITCAST, dl, VbicVT, N->getOperand(0)); | 
|  | SDValue Vbic = DAG.getNode(ARMISD::VBICIMM, dl, VbicVT, Input, Val); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, Vbic); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!Subtarget->isThumb1Only()) { | 
|  | // fold (and (select cc, -1, c), x) -> (select cc, x, (and, x, c)) | 
|  | if (SDValue Result = combineSelectAndUseCommutative(N, true, DCI)) | 
|  | return Result; | 
|  |  | 
|  | if (SDValue Result = PerformSHLSimplify(N, DCI, Subtarget)) | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | if (Subtarget->isThumb1Only()) | 
|  | if (SDValue Result = CombineANDShift(N, DCI, Subtarget)) | 
|  | return Result; | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // Try combining OR nodes to SMULWB, SMULWT. | 
|  | static SDValue PerformORCombineToSMULWBT(SDNode *OR, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (!Subtarget->hasV6Ops() || | 
|  | (Subtarget->isThumb() && | 
|  | (!Subtarget->hasThumb2() || !Subtarget->hasDSP()))) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue SRL = OR->getOperand(0); | 
|  | SDValue SHL = OR->getOperand(1); | 
|  |  | 
|  | if (SRL.getOpcode() != ISD::SRL || SHL.getOpcode() != ISD::SHL) { | 
|  | SRL = OR->getOperand(1); | 
|  | SHL = OR->getOperand(0); | 
|  | } | 
|  | if (!isSRL16(SRL) || !isSHL16(SHL)) | 
|  | return SDValue(); | 
|  |  | 
|  | // The first operands to the shifts need to be the two results from the | 
|  | // same smul_lohi node. | 
|  | if ((SRL.getOperand(0).getNode() != SHL.getOperand(0).getNode()) || | 
|  | SRL.getOperand(0).getOpcode() != ISD::SMUL_LOHI) | 
|  | return SDValue(); | 
|  |  | 
|  | SDNode *SMULLOHI = SRL.getOperand(0).getNode(); | 
|  | if (SRL.getOperand(0) != SDValue(SMULLOHI, 0) || | 
|  | SHL.getOperand(0) != SDValue(SMULLOHI, 1)) | 
|  | return SDValue(); | 
|  |  | 
|  | // Now we have: | 
|  | // (or (srl (smul_lohi ?, ?), 16), (shl (smul_lohi ?, ?), 16))) | 
|  | // For SMUL[B|T] smul_lohi will take a 32-bit and a 16-bit arguments. | 
|  | // For SMUWB the 16-bit value will signed extended somehow. | 
|  | // For SMULWT only the SRA is required. | 
|  | // Check both sides of SMUL_LOHI | 
|  | SDValue OpS16 = SMULLOHI->getOperand(0); | 
|  | SDValue OpS32 = SMULLOHI->getOperand(1); | 
|  |  | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | if (!isS16(OpS16, DAG) && !isSRA16(OpS16)) { | 
|  | OpS16 = OpS32; | 
|  | OpS32 = SMULLOHI->getOperand(0); | 
|  | } | 
|  |  | 
|  | SDLoc dl(OR); | 
|  | unsigned Opcode = 0; | 
|  | if (isS16(OpS16, DAG)) | 
|  | Opcode = ARMISD::SMULWB; | 
|  | else if (isSRA16(OpS16)) { | 
|  | Opcode = ARMISD::SMULWT; | 
|  | OpS16 = OpS16->getOperand(0); | 
|  | } | 
|  | else | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue Res = DAG.getNode(Opcode, dl, MVT::i32, OpS32, OpS16); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(OR, 0), Res); | 
|  | return SDValue(OR, 0); | 
|  | } | 
|  |  | 
|  | static SDValue PerformORCombineToBFI(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // BFI is only available on V6T2+ | 
|  | if (Subtarget->isThumb1Only() || !Subtarget->hasV6T2Ops()) | 
|  | return SDValue(); | 
|  |  | 
|  | EVT VT = N->getValueType(0); | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDLoc DL(N); | 
|  | // 1) or (and A, mask), val => ARMbfi A, val, mask | 
|  | //      iff (val & mask) == val | 
|  | // | 
|  | // 2) or (and A, mask), (and B, mask2) => ARMbfi A, (lsr B, amt), mask | 
|  | //  2a) iff isBitFieldInvertedMask(mask) && isBitFieldInvertedMask(~mask2) | 
|  | //          && mask == ~mask2 | 
|  | //  2b) iff isBitFieldInvertedMask(~mask) && isBitFieldInvertedMask(mask2) | 
|  | //          && ~mask == mask2 | 
|  | //  (i.e., copy a bitfield value into another bitfield of the same width) | 
|  |  | 
|  | if (VT != MVT::i32) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue N00 = N0.getOperand(0); | 
|  |  | 
|  | // The value and the mask need to be constants so we can verify this is | 
|  | // actually a bitfield set. If the mask is 0xffff, we can do better | 
|  | // via a movt instruction, so don't use BFI in that case. | 
|  | SDValue MaskOp = N0.getOperand(1); | 
|  | ConstantSDNode *MaskC = dyn_cast<ConstantSDNode>(MaskOp); | 
|  | if (!MaskC) | 
|  | return SDValue(); | 
|  | unsigned Mask = MaskC->getZExtValue(); | 
|  | if (Mask == 0xffff) | 
|  | return SDValue(); | 
|  | SDValue Res; | 
|  | // Case (1): or (and A, mask), val => ARMbfi A, val, mask | 
|  | ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1); | 
|  | if (N1C) { | 
|  | unsigned Val = N1C->getZExtValue(); | 
|  | if ((Val & ~Mask) != Val) | 
|  | return SDValue(); | 
|  |  | 
|  | if (ARM::isBitFieldInvertedMask(Mask)) { | 
|  | Val >>= countTrailingZeros(~Mask); | 
|  |  | 
|  | Res = DAG.getNode(ARMISD::BFI, DL, VT, N00, | 
|  | DAG.getConstant(Val, DL, MVT::i32), | 
|  | DAG.getConstant(Mask, DL, MVT::i32)); | 
|  |  | 
|  | DCI.CombineTo(N, Res, false); | 
|  | // Return value from the original node to inform the combiner than N is | 
|  | // now dead. | 
|  | return SDValue(N, 0); | 
|  | } | 
|  | } else if (N1.getOpcode() == ISD::AND) { | 
|  | // case (2) or (and A, mask), (and B, mask2) => ARMbfi A, (lsr B, amt), mask | 
|  | ConstantSDNode *N11C = dyn_cast<ConstantSDNode>(N1.getOperand(1)); | 
|  | if (!N11C) | 
|  | return SDValue(); | 
|  | unsigned Mask2 = N11C->getZExtValue(); | 
|  |  | 
|  | // Mask and ~Mask2 (or reverse) must be equivalent for the BFI pattern | 
|  | // as is to match. | 
|  | if (ARM::isBitFieldInvertedMask(Mask) && | 
|  | (Mask == ~Mask2)) { | 
|  | // The pack halfword instruction works better for masks that fit it, | 
|  | // so use that when it's available. | 
|  | if (Subtarget->hasDSP() && | 
|  | (Mask == 0xffff || Mask == 0xffff0000)) | 
|  | return SDValue(); | 
|  | // 2a | 
|  | unsigned amt = countTrailingZeros(Mask2); | 
|  | Res = DAG.getNode(ISD::SRL, DL, VT, N1.getOperand(0), | 
|  | DAG.getConstant(amt, DL, MVT::i32)); | 
|  | Res = DAG.getNode(ARMISD::BFI, DL, VT, N00, Res, | 
|  | DAG.getConstant(Mask, DL, MVT::i32)); | 
|  | DCI.CombineTo(N, Res, false); | 
|  | // Return value from the original node to inform the combiner than N is | 
|  | // now dead. | 
|  | return SDValue(N, 0); | 
|  | } else if (ARM::isBitFieldInvertedMask(~Mask) && | 
|  | (~Mask == Mask2)) { | 
|  | // The pack halfword instruction works better for masks that fit it, | 
|  | // so use that when it's available. | 
|  | if (Subtarget->hasDSP() && | 
|  | (Mask2 == 0xffff || Mask2 == 0xffff0000)) | 
|  | return SDValue(); | 
|  | // 2b | 
|  | unsigned lsb = countTrailingZeros(Mask); | 
|  | Res = DAG.getNode(ISD::SRL, DL, VT, N00, | 
|  | DAG.getConstant(lsb, DL, MVT::i32)); | 
|  | Res = DAG.getNode(ARMISD::BFI, DL, VT, N1.getOperand(0), Res, | 
|  | DAG.getConstant(Mask2, DL, MVT::i32)); | 
|  | DCI.CombineTo(N, Res, false); | 
|  | // Return value from the original node to inform the combiner than N is | 
|  | // now dead. | 
|  | return SDValue(N, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (DAG.MaskedValueIsZero(N1, MaskC->getAPIntValue()) && | 
|  | N00.getOpcode() == ISD::SHL && isa<ConstantSDNode>(N00.getOperand(1)) && | 
|  | ARM::isBitFieldInvertedMask(~Mask)) { | 
|  | // Case (3): or (and (shl A, #shamt), mask), B => ARMbfi B, A, ~mask | 
|  | // where lsb(mask) == #shamt and masked bits of B are known zero. | 
|  | SDValue ShAmt = N00.getOperand(1); | 
|  | unsigned ShAmtC = cast<ConstantSDNode>(ShAmt)->getZExtValue(); | 
|  | unsigned LSB = countTrailingZeros(Mask); | 
|  | if (ShAmtC != LSB) | 
|  | return SDValue(); | 
|  |  | 
|  | Res = DAG.getNode(ARMISD::BFI, DL, VT, N1, N00.getOperand(0), | 
|  | DAG.getConstant(~Mask, DL, MVT::i32)); | 
|  |  | 
|  | DCI.CombineTo(N, Res, false); | 
|  | // Return value from the original node to inform the combiner than N is | 
|  | // now dead. | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static bool isValidMVECond(unsigned CC, bool IsFloat) { | 
|  | switch (CC) { | 
|  | case ARMCC::EQ: | 
|  | case ARMCC::NE: | 
|  | case ARMCC::LE: | 
|  | case ARMCC::GT: | 
|  | case ARMCC::GE: | 
|  | case ARMCC::LT: | 
|  | return true; | 
|  | case ARMCC::HS: | 
|  | case ARMCC::HI: | 
|  | return !IsFloat; | 
|  | default: | 
|  | return false; | 
|  | }; | 
|  | } | 
|  |  | 
|  | static ARMCC::CondCodes getVCMPCondCode(SDValue N) { | 
|  | if (N->getOpcode() == ARMISD::VCMP) | 
|  | return (ARMCC::CondCodes)N->getConstantOperandVal(2); | 
|  | else if (N->getOpcode() == ARMISD::VCMPZ) | 
|  | return (ARMCC::CondCodes)N->getConstantOperandVal(1); | 
|  | else | 
|  | llvm_unreachable("Not a VCMP/VCMPZ!"); | 
|  | } | 
|  |  | 
|  | static bool CanInvertMVEVCMP(SDValue N) { | 
|  | ARMCC::CondCodes CC = ARMCC::getOppositeCondition(getVCMPCondCode(N)); | 
|  | return isValidMVECond(CC, N->getOperand(0).getValueType().isFloatingPoint()); | 
|  | } | 
|  |  | 
|  | static SDValue PerformORCombine_i1(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // Try to invert "or A, B" -> "and ~A, ~B", as the "and" is easier to chain | 
|  | // together with predicates | 
|  | EVT VT = N->getValueType(0); | 
|  | SDLoc DL(N); | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  |  | 
|  | auto IsFreelyInvertable = [&](SDValue V) { | 
|  | if (V->getOpcode() == ARMISD::VCMP || V->getOpcode() == ARMISD::VCMPZ) | 
|  | return CanInvertMVEVCMP(V); | 
|  | return false; | 
|  | }; | 
|  |  | 
|  | // At least one operand must be freely invertable. | 
|  | if (!(IsFreelyInvertable(N0) || IsFreelyInvertable(N1))) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue NewN0 = DCI.DAG.getLogicalNOT(DL, N0, VT); | 
|  | SDValue NewN1 = DCI.DAG.getLogicalNOT(DL, N1, VT); | 
|  | SDValue And = DCI.DAG.getNode(ISD::AND, DL, VT, NewN0, NewN1); | 
|  | return DCI.DAG.getLogicalNOT(DL, And, VT); | 
|  | } | 
|  |  | 
|  | /// PerformORCombine - Target-specific dag combine xforms for ISD::OR | 
|  | static SDValue PerformORCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // Attempt to use immediate-form VORR | 
|  | BuildVectorSDNode *BVN = dyn_cast<BuildVectorSDNode>(N->getOperand(1)); | 
|  | SDLoc dl(N); | 
|  | EVT VT = N->getValueType(0); | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  |  | 
|  | if(!DAG.getTargetLoweringInfo().isTypeLegal(VT)) | 
|  | return SDValue(); | 
|  |  | 
|  | APInt SplatBits, SplatUndef; | 
|  | unsigned SplatBitSize; | 
|  | bool HasAnyUndefs; | 
|  | if (BVN && (Subtarget->hasNEON() || Subtarget->hasMVEIntegerOps()) && | 
|  | BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs)) { | 
|  | if (SplatBitSize <= 64) { | 
|  | EVT VorrVT; | 
|  | SDValue Val = | 
|  | isVMOVModifiedImm(SplatBits.getZExtValue(), SplatUndef.getZExtValue(), | 
|  | SplatBitSize, DAG, dl, VorrVT, VT, OtherModImm); | 
|  | if (Val.getNode()) { | 
|  | SDValue Input = | 
|  | DAG.getNode(ISD::BITCAST, dl, VorrVT, N->getOperand(0)); | 
|  | SDValue Vorr = DAG.getNode(ARMISD::VORRIMM, dl, VorrVT, Input, Val); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, Vorr); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!Subtarget->isThumb1Only()) { | 
|  | // fold (or (select cc, 0, c), x) -> (select cc, x, (or, x, c)) | 
|  | if (SDValue Result = combineSelectAndUseCommutative(N, false, DCI)) | 
|  | return Result; | 
|  | if (SDValue Result = PerformORCombineToSMULWBT(N, DCI, Subtarget)) | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  |  | 
|  | // (or (and B, A), (and C, ~A)) => (VBSL A, B, C) when A is a constant. | 
|  | if (Subtarget->hasNEON() && N1.getOpcode() == ISD::AND && VT.isVector() && | 
|  | DAG.getTargetLoweringInfo().isTypeLegal(VT)) { | 
|  |  | 
|  | // The code below optimizes (or (and X, Y), Z). | 
|  | // The AND operand needs to have a single user to make these optimizations | 
|  | // profitable. | 
|  | if (N0.getOpcode() != ISD::AND || !N0.hasOneUse()) | 
|  | return SDValue(); | 
|  |  | 
|  | APInt SplatUndef; | 
|  | unsigned SplatBitSize; | 
|  | bool HasAnyUndefs; | 
|  |  | 
|  | APInt SplatBits0, SplatBits1; | 
|  | BuildVectorSDNode *BVN0 = dyn_cast<BuildVectorSDNode>(N0->getOperand(1)); | 
|  | BuildVectorSDNode *BVN1 = dyn_cast<BuildVectorSDNode>(N1->getOperand(1)); | 
|  | // Ensure that the second operand of both ands are constants | 
|  | if (BVN0 && BVN0->isConstantSplat(SplatBits0, SplatUndef, SplatBitSize, | 
|  | HasAnyUndefs) && !HasAnyUndefs) { | 
|  | if (BVN1 && BVN1->isConstantSplat(SplatBits1, SplatUndef, SplatBitSize, | 
|  | HasAnyUndefs) && !HasAnyUndefs) { | 
|  | // Ensure that the bit width of the constants are the same and that | 
|  | // the splat arguments are logical inverses as per the pattern we | 
|  | // are trying to simplify. | 
|  | if (SplatBits0.getBitWidth() == SplatBits1.getBitWidth() && | 
|  | SplatBits0 == ~SplatBits1) { | 
|  | // Canonicalize the vector type to make instruction selection | 
|  | // simpler. | 
|  | EVT CanonicalVT = VT.is128BitVector() ? MVT::v4i32 : MVT::v2i32; | 
|  | SDValue Result = DAG.getNode(ARMISD::VBSL, dl, CanonicalVT, | 
|  | N0->getOperand(1), | 
|  | N0->getOperand(0), | 
|  | N1->getOperand(0)); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, Result); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Subtarget->hasMVEIntegerOps() && | 
|  | (VT == MVT::v4i1 || VT == MVT::v8i1 || VT == MVT::v16i1)) | 
|  | return PerformORCombine_i1(N, DCI, Subtarget); | 
|  |  | 
|  | // Try to use the ARM/Thumb2 BFI (bitfield insert) instruction when | 
|  | // reasonable. | 
|  | if (N0.getOpcode() == ISD::AND && N0.hasOneUse()) { | 
|  | if (SDValue Res = PerformORCombineToBFI(N, DCI, Subtarget)) | 
|  | return Res; | 
|  | } | 
|  |  | 
|  | if (SDValue Result = PerformSHLSimplify(N, DCI, Subtarget)) | 
|  | return Result; | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformXORCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | EVT VT = N->getValueType(0); | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  |  | 
|  | if(!DAG.getTargetLoweringInfo().isTypeLegal(VT)) | 
|  | return SDValue(); | 
|  |  | 
|  | if (!Subtarget->isThumb1Only()) { | 
|  | // fold (xor (select cc, 0, c), x) -> (select cc, x, (xor, x, c)) | 
|  | if (SDValue Result = combineSelectAndUseCommutative(N, false, DCI)) | 
|  | return Result; | 
|  |  | 
|  | if (SDValue Result = PerformSHLSimplify(N, DCI, Subtarget)) | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | if (Subtarget->hasMVEIntegerOps()) { | 
|  | // fold (xor(vcmp/z, 1)) into a vcmp with the opposite condition. | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDValue N1 = N->getOperand(1); | 
|  | const TargetLowering *TLI = Subtarget->getTargetLowering(); | 
|  | if (TLI->isConstTrueVal(N1.getNode()) && | 
|  | (N0->getOpcode() == ARMISD::VCMP || N0->getOpcode() == ARMISD::VCMPZ)) { | 
|  | if (CanInvertMVEVCMP(N0)) { | 
|  | SDLoc DL(N0); | 
|  | ARMCC::CondCodes CC = ARMCC::getOppositeCondition(getVCMPCondCode(N0)); | 
|  |  | 
|  | SmallVector<SDValue, 4> Ops; | 
|  | Ops.push_back(N0->getOperand(0)); | 
|  | if (N0->getOpcode() == ARMISD::VCMP) | 
|  | Ops.push_back(N0->getOperand(1)); | 
|  | Ops.push_back(DCI.DAG.getConstant(CC, DL, MVT::i32)); | 
|  | return DCI.DAG.getNode(N0->getOpcode(), DL, N0->getValueType(0), Ops); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // ParseBFI - given a BFI instruction in N, extract the "from" value (Rn) and return it, | 
|  | // and fill in FromMask and ToMask with (consecutive) bits in "from" to be extracted and | 
|  | // their position in "to" (Rd). | 
|  | static SDValue ParseBFI(SDNode *N, APInt &ToMask, APInt &FromMask) { | 
|  | assert(N->getOpcode() == ARMISD::BFI); | 
|  |  | 
|  | SDValue From = N->getOperand(1); | 
|  | ToMask = ~cast<ConstantSDNode>(N->getOperand(2))->getAPIntValue(); | 
|  | FromMask = APInt::getLowBitsSet(ToMask.getBitWidth(), ToMask.countPopulation()); | 
|  |  | 
|  | // If the Base came from a SHR #C, we can deduce that it is really testing bit | 
|  | // #C in the base of the SHR. | 
|  | if (From->getOpcode() == ISD::SRL && | 
|  | isa<ConstantSDNode>(From->getOperand(1))) { | 
|  | APInt Shift = cast<ConstantSDNode>(From->getOperand(1))->getAPIntValue(); | 
|  | assert(Shift.getLimitedValue() < 32 && "Shift too large!"); | 
|  | FromMask <<= Shift.getLimitedValue(31); | 
|  | From = From->getOperand(0); | 
|  | } | 
|  |  | 
|  | return From; | 
|  | } | 
|  |  | 
|  | // If A and B contain one contiguous set of bits, does A | B == A . B? | 
|  | // | 
|  | // Neither A nor B must be zero. | 
|  | static bool BitsProperlyConcatenate(const APInt &A, const APInt &B) { | 
|  | unsigned LastActiveBitInA =  A.countTrailingZeros(); | 
|  | unsigned FirstActiveBitInB = B.getBitWidth() - B.countLeadingZeros() - 1; | 
|  | return LastActiveBitInA - 1 == FirstActiveBitInB; | 
|  | } | 
|  |  | 
|  | static SDValue FindBFIToCombineWith(SDNode *N) { | 
|  | // We have a BFI in N. Follow a possible chain of BFIs and find a BFI it can combine with, | 
|  | // if one exists. | 
|  | APInt ToMask, FromMask; | 
|  | SDValue From = ParseBFI(N, ToMask, FromMask); | 
|  | SDValue To = N->getOperand(0); | 
|  |  | 
|  | // Now check for a compatible BFI to merge with. We can pass through BFIs that | 
|  | // aren't compatible, but not if they set the same bit in their destination as | 
|  | // we do (or that of any BFI we're going to combine with). | 
|  | SDValue V = To; | 
|  | APInt CombinedToMask = ToMask; | 
|  | while (V.getOpcode() == ARMISD::BFI) { | 
|  | APInt NewToMask, NewFromMask; | 
|  | SDValue NewFrom = ParseBFI(V.getNode(), NewToMask, NewFromMask); | 
|  | if (NewFrom != From) { | 
|  | // This BFI has a different base. Keep going. | 
|  | CombinedToMask |= NewToMask; | 
|  | V = V.getOperand(0); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Do the written bits conflict with any we've seen so far? | 
|  | if ((NewToMask & CombinedToMask).getBoolValue()) | 
|  | // Conflicting bits - bail out because going further is unsafe. | 
|  | return SDValue(); | 
|  |  | 
|  | // Are the new bits contiguous when combined with the old bits? | 
|  | if (BitsProperlyConcatenate(ToMask, NewToMask) && | 
|  | BitsProperlyConcatenate(FromMask, NewFromMask)) | 
|  | return V; | 
|  | if (BitsProperlyConcatenate(NewToMask, ToMask) && | 
|  | BitsProperlyConcatenate(NewFromMask, FromMask)) | 
|  | return V; | 
|  |  | 
|  | // We've seen a write to some bits, so track it. | 
|  | CombinedToMask |= NewToMask; | 
|  | // Keep going... | 
|  | V = V.getOperand(0); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformBFICombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | SDValue N1 = N->getOperand(1); | 
|  | if (N1.getOpcode() == ISD::AND) { | 
|  | // (bfi A, (and B, Mask1), Mask2) -> (bfi A, B, Mask2) iff | 
|  | // the bits being cleared by the AND are not demanded by the BFI. | 
|  | ConstantSDNode *N11C = dyn_cast<ConstantSDNode>(N1.getOperand(1)); | 
|  | if (!N11C) | 
|  | return SDValue(); | 
|  | unsigned InvMask = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(); | 
|  | unsigned LSB = countTrailingZeros(~InvMask); | 
|  | unsigned Width = (32 - countLeadingZeros(~InvMask)) - LSB; | 
|  | assert(Width < | 
|  | static_cast<unsigned>(std::numeric_limits<unsigned>::digits) && | 
|  | "undefined behavior"); | 
|  | unsigned Mask = (1u << Width) - 1; | 
|  | unsigned Mask2 = N11C->getZExtValue(); | 
|  | if ((Mask & (~Mask2)) == 0) | 
|  | return DCI.DAG.getNode(ARMISD::BFI, SDLoc(N), N->getValueType(0), | 
|  | N->getOperand(0), N1.getOperand(0), | 
|  | N->getOperand(2)); | 
|  | } else if (N->getOperand(0).getOpcode() == ARMISD::BFI) { | 
|  | // We have a BFI of a BFI. Walk up the BFI chain to see how long it goes. | 
|  | // Keep track of any consecutive bits set that all come from the same base | 
|  | // value. We can combine these together into a single BFI. | 
|  | SDValue CombineBFI = FindBFIToCombineWith(N); | 
|  | if (CombineBFI == SDValue()) | 
|  | return SDValue(); | 
|  |  | 
|  | // We've found a BFI. | 
|  | APInt ToMask1, FromMask1; | 
|  | SDValue From1 = ParseBFI(N, ToMask1, FromMask1); | 
|  |  | 
|  | APInt ToMask2, FromMask2; | 
|  | SDValue From2 = ParseBFI(CombineBFI.getNode(), ToMask2, FromMask2); | 
|  | assert(From1 == From2); | 
|  | (void)From2; | 
|  |  | 
|  | // First, unlink CombineBFI. | 
|  | DCI.DAG.ReplaceAllUsesWith(CombineBFI, CombineBFI.getOperand(0)); | 
|  | // Then create a new BFI, combining the two together. | 
|  | APInt NewFromMask = FromMask1 | FromMask2; | 
|  | APInt NewToMask = ToMask1 | ToMask2; | 
|  |  | 
|  | EVT VT = N->getValueType(0); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | if (NewFromMask[0] == 0) | 
|  | From1 = DCI.DAG.getNode( | 
|  | ISD::SRL, dl, VT, From1, | 
|  | DCI.DAG.getConstant(NewFromMask.countTrailingZeros(), dl, VT)); | 
|  | return DCI.DAG.getNode(ARMISD::BFI, dl, VT, N->getOperand(0), From1, | 
|  | DCI.DAG.getConstant(~NewToMask, dl, VT)); | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// PerformVMOVRRDCombine - Target-specific dag combine xforms for | 
|  | /// ARMISD::VMOVRRD. | 
|  | static SDValue PerformVMOVRRDCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // vmovrrd(vmovdrr x, y) -> x,y | 
|  | SDValue InDouble = N->getOperand(0); | 
|  | if (InDouble.getOpcode() == ARMISD::VMOVDRR && Subtarget->hasFP64()) | 
|  | return DCI.CombineTo(N, InDouble.getOperand(0), InDouble.getOperand(1)); | 
|  |  | 
|  | // vmovrrd(load f64) -> (load i32), (load i32) | 
|  | SDNode *InNode = InDouble.getNode(); | 
|  | if (ISD::isNormalLoad(InNode) && InNode->hasOneUse() && | 
|  | InNode->getValueType(0) == MVT::f64 && | 
|  | InNode->getOperand(1).getOpcode() == ISD::FrameIndex && | 
|  | !cast<LoadSDNode>(InNode)->isVolatile()) { | 
|  | // TODO: Should this be done for non-FrameIndex operands? | 
|  | LoadSDNode *LD = cast<LoadSDNode>(InNode); | 
|  |  | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDLoc DL(LD); | 
|  | SDValue BasePtr = LD->getBasePtr(); | 
|  | SDValue NewLD1 = | 
|  | DAG.getLoad(MVT::i32, DL, LD->getChain(), BasePtr, LD->getPointerInfo(), | 
|  | LD->getAlignment(), LD->getMemOperand()->getFlags()); | 
|  |  | 
|  | SDValue OffsetPtr = DAG.getNode(ISD::ADD, DL, MVT::i32, BasePtr, | 
|  | DAG.getConstant(4, DL, MVT::i32)); | 
|  |  | 
|  | SDValue NewLD2 = DAG.getLoad(MVT::i32, DL, LD->getChain(), OffsetPtr, | 
|  | LD->getPointerInfo().getWithOffset(4), | 
|  | std::min(4U, LD->getAlignment()), | 
|  | LD->getMemOperand()->getFlags()); | 
|  |  | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(LD, 1), NewLD2.getValue(1)); | 
|  | if (DCI.DAG.getDataLayout().isBigEndian()) | 
|  | std::swap (NewLD1, NewLD2); | 
|  | SDValue Result = DCI.CombineTo(N, NewLD1, NewLD2); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// PerformVMOVDRRCombine - Target-specific dag combine xforms for | 
|  | /// ARMISD::VMOVDRR.  This is also used for BUILD_VECTORs with 2 operands. | 
|  | static SDValue PerformVMOVDRRCombine(SDNode *N, SelectionDAG &DAG) { | 
|  | // N=vmovrrd(X); vmovdrr(N:0, N:1) -> bit_convert(X) | 
|  | SDValue Op0 = N->getOperand(0); | 
|  | SDValue Op1 = N->getOperand(1); | 
|  | if (Op0.getOpcode() == ISD::BITCAST) | 
|  | Op0 = Op0.getOperand(0); | 
|  | if (Op1.getOpcode() == ISD::BITCAST) | 
|  | Op1 = Op1.getOperand(0); | 
|  | if (Op0.getOpcode() == ARMISD::VMOVRRD && | 
|  | Op0.getNode() == Op1.getNode() && | 
|  | Op0.getResNo() == 0 && Op1.getResNo() == 1) | 
|  | return DAG.getNode(ISD::BITCAST, SDLoc(N), | 
|  | N->getValueType(0), Op0.getOperand(0)); | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformVMOVhrCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { | 
|  | SDValue Op0 = N->getOperand(0); | 
|  |  | 
|  | // VMOVhr (VMOVrh (X)) -> X | 
|  | if (Op0->getOpcode() == ARMISD::VMOVrh) | 
|  | return Op0->getOperand(0); | 
|  |  | 
|  | // FullFP16: half values are passed in S-registers, and we don't | 
|  | // need any of the bitcast and moves: | 
|  | // | 
|  | //     t2: f32,ch = CopyFromReg t0, Register:f32 %0 | 
|  | //   t5: i32 = bitcast t2 | 
|  | // t18: f16 = ARMISD::VMOVhr t5 | 
|  | if (Op0->getOpcode() == ISD::BITCAST) { | 
|  | SDValue Copy = Op0->getOperand(0); | 
|  | if (Copy.getValueType() == MVT::f32 && | 
|  | Copy->getOpcode() == ISD::CopyFromReg) { | 
|  | SDValue Ops[] = {Copy->getOperand(0), Copy->getOperand(1)}; | 
|  | SDValue NewCopy = | 
|  | DCI.DAG.getNode(ISD::CopyFromReg, SDLoc(N), MVT::f16, Ops); | 
|  | return NewCopy; | 
|  | } | 
|  | } | 
|  |  | 
|  | // fold (VMOVhr (load x)) -> (load (f16*)x) | 
|  | if (LoadSDNode *LN0 = dyn_cast<LoadSDNode>(Op0)) { | 
|  | if (LN0->hasOneUse() && LN0->isUnindexed() && | 
|  | LN0->getMemoryVT() == MVT::i16) { | 
|  | SDValue Load = DCI.DAG.getLoad(MVT::f16, SDLoc(N), LN0->getChain(), | 
|  | LN0->getBasePtr(), LN0->getMemOperand()); | 
|  | DCI.DAG.ReplaceAllUsesOfValueWith(SDValue(N, 0), Load.getValue(0)); | 
|  | DCI.DAG.ReplaceAllUsesOfValueWith(Op0.getValue(1), Load.getValue(1)); | 
|  | return Load; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Only the bottom 16 bits of the source register are used. | 
|  | APInt DemandedMask = APInt::getLowBitsSet(32, 16); | 
|  | const TargetLowering &TLI = DCI.DAG.getTargetLoweringInfo(); | 
|  | if (TLI.SimplifyDemandedBits(Op0, DemandedMask, DCI)) | 
|  | return SDValue(N, 0); | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformVMOVrhCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | SDValue N0 = N->getOperand(0); | 
|  | EVT VT = N->getValueType(0); | 
|  |  | 
|  | // fold (VMOVrh (load x)) -> (zextload (i16*)x) | 
|  | if (ISD::isNormalLoad(N0.getNode()) && N0.hasOneUse()) { | 
|  | LoadSDNode *LN0 = cast<LoadSDNode>(N0); | 
|  |  | 
|  | SDValue Load = | 
|  | DCI.DAG.getExtLoad(ISD::ZEXTLOAD, SDLoc(N), VT, LN0->getChain(), | 
|  | LN0->getBasePtr(), MVT::i16, LN0->getMemOperand()); | 
|  | DCI.DAG.ReplaceAllUsesOfValueWith(SDValue(N, 0), Load.getValue(0)); | 
|  | DCI.DAG.ReplaceAllUsesOfValueWith(N0.getValue(1), Load.getValue(1)); | 
|  | return Load; | 
|  | } | 
|  |  | 
|  | // Fold VMOVrh(extract(x, n)) -> vgetlaneu(x, n) | 
|  | if (N0->getOpcode() == ISD::EXTRACT_VECTOR_ELT && | 
|  | isa<ConstantSDNode>(N0->getOperand(1))) | 
|  | return DCI.DAG.getNode(ARMISD::VGETLANEu, SDLoc(N), VT, N0->getOperand(0), | 
|  | N0->getOperand(1)); | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// hasNormalLoadOperand - Check if any of the operands of a BUILD_VECTOR node | 
|  | /// are normal, non-volatile loads.  If so, it is profitable to bitcast an | 
|  | /// i64 vector to have f64 elements, since the value can then be loaded | 
|  | /// directly into a VFP register. | 
|  | static bool hasNormalLoadOperand(SDNode *N) { | 
|  | unsigned NumElts = N->getValueType(0).getVectorNumElements(); | 
|  | for (unsigned i = 0; i < NumElts; ++i) { | 
|  | SDNode *Elt = N->getOperand(i).getNode(); | 
|  | if (ISD::isNormalLoad(Elt) && !cast<LoadSDNode>(Elt)->isVolatile()) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// PerformBUILD_VECTORCombine - Target-specific dag combine xforms for | 
|  | /// ISD::BUILD_VECTOR. | 
|  | static SDValue PerformBUILD_VECTORCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | // build_vector(N=ARMISD::VMOVRRD(X), N:1) -> bit_convert(X): | 
|  | // VMOVRRD is introduced when legalizing i64 types.  It forces the i64 value | 
|  | // into a pair of GPRs, which is fine when the value is used as a scalar, | 
|  | // but if the i64 value is converted to a vector, we need to undo the VMOVRRD. | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | if (N->getNumOperands() == 2) | 
|  | if (SDValue RV = PerformVMOVDRRCombine(N, DAG)) | 
|  | return RV; | 
|  |  | 
|  | // Load i64 elements as f64 values so that type legalization does not split | 
|  | // them up into i32 values. | 
|  | EVT VT = N->getValueType(0); | 
|  | if (VT.getVectorElementType() != MVT::i64 || !hasNormalLoadOperand(N)) | 
|  | return SDValue(); | 
|  | SDLoc dl(N); | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | for (unsigned i = 0; i < NumElts; ++i) { | 
|  | SDValue V = DAG.getNode(ISD::BITCAST, dl, MVT::f64, N->getOperand(i)); | 
|  | Ops.push_back(V); | 
|  | // Make the DAGCombiner fold the bitcast. | 
|  | DCI.AddToWorklist(V.getNode()); | 
|  | } | 
|  | EVT FloatVT = EVT::getVectorVT(*DAG.getContext(), MVT::f64, NumElts); | 
|  | SDValue BV = DAG.getBuildVector(FloatVT, dl, Ops); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, BV); | 
|  | } | 
|  |  | 
|  | /// Target-specific dag combine xforms for ARMISD::BUILD_VECTOR. | 
|  | static SDValue | 
|  | PerformARMBUILD_VECTORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { | 
|  | // ARMISD::BUILD_VECTOR is introduced when legalizing ISD::BUILD_VECTOR. | 
|  | // At that time, we may have inserted bitcasts from integer to float. | 
|  | // If these bitcasts have survived DAGCombine, change the lowering of this | 
|  | // BUILD_VECTOR in something more vector friendly, i.e., that does not | 
|  | // force to use floating point types. | 
|  |  | 
|  | // Make sure we can change the type of the vector. | 
|  | // This is possible iff: | 
|  | // 1. The vector is only used in a bitcast to a integer type. I.e., | 
|  | //    1.1. Vector is used only once. | 
|  | //    1.2. Use is a bit convert to an integer type. | 
|  | // 2. The size of its operands are 32-bits (64-bits are not legal). | 
|  | EVT VT = N->getValueType(0); | 
|  | EVT EltVT = VT.getVectorElementType(); | 
|  |  | 
|  | // Check 1.1. and 2. | 
|  | if (EltVT.getSizeInBits() != 32 || !N->hasOneUse()) | 
|  | return SDValue(); | 
|  |  | 
|  | // By construction, the input type must be float. | 
|  | assert(EltVT == MVT::f32 && "Unexpected type!"); | 
|  |  | 
|  | // Check 1.2. | 
|  | SDNode *Use = *N->use_begin(); | 
|  | if (Use->getOpcode() != ISD::BITCAST || | 
|  | Use->getValueType(0).isFloatingPoint()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Check profitability. | 
|  | // Model is, if more than half of the relevant operands are bitcast from | 
|  | // i32, turn the build_vector into a sequence of insert_vector_elt. | 
|  | // Relevant operands are everything that is not statically | 
|  | // (i.e., at compile time) bitcasted. | 
|  | unsigned NumOfBitCastedElts = 0; | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | unsigned NumOfRelevantElts = NumElts; | 
|  | for (unsigned Idx = 0; Idx < NumElts; ++Idx) { | 
|  | SDValue Elt = N->getOperand(Idx); | 
|  | if (Elt->getOpcode() == ISD::BITCAST) { | 
|  | // Assume only bit cast to i32 will go away. | 
|  | if (Elt->getOperand(0).getValueType() == MVT::i32) | 
|  | ++NumOfBitCastedElts; | 
|  | } else if (Elt.isUndef() || isa<ConstantSDNode>(Elt)) | 
|  | // Constants are statically casted, thus do not count them as | 
|  | // relevant operands. | 
|  | --NumOfRelevantElts; | 
|  | } | 
|  |  | 
|  | // Check if more than half of the elements require a non-free bitcast. | 
|  | if (NumOfBitCastedElts <= NumOfRelevantElts / 2) | 
|  | return SDValue(); | 
|  |  | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | // Create the new vector type. | 
|  | EVT VecVT = EVT::getVectorVT(*DAG.getContext(), MVT::i32, NumElts); | 
|  | // Check if the type is legal. | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | if (!TLI.isTypeLegal(VecVT)) | 
|  | return SDValue(); | 
|  |  | 
|  | // Combine: | 
|  | // ARMISD::BUILD_VECTOR E1, E2, ..., EN. | 
|  | // => BITCAST INSERT_VECTOR_ELT | 
|  | //                      (INSERT_VECTOR_ELT (...), (BITCAST EN-1), N-1), | 
|  | //                      (BITCAST EN), N. | 
|  | SDValue Vec = DAG.getUNDEF(VecVT); | 
|  | SDLoc dl(N); | 
|  | for (unsigned Idx = 0 ; Idx < NumElts; ++Idx) { | 
|  | SDValue V = N->getOperand(Idx); | 
|  | if (V.isUndef()) | 
|  | continue; | 
|  | if (V.getOpcode() == ISD::BITCAST && | 
|  | V->getOperand(0).getValueType() == MVT::i32) | 
|  | // Fold obvious case. | 
|  | V = V.getOperand(0); | 
|  | else { | 
|  | V = DAG.getNode(ISD::BITCAST, SDLoc(V), MVT::i32, V); | 
|  | // Make the DAGCombiner fold the bitcasts. | 
|  | DCI.AddToWorklist(V.getNode()); | 
|  | } | 
|  | SDValue LaneIdx = DAG.getConstant(Idx, dl, MVT::i32); | 
|  | Vec = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, VecVT, Vec, V, LaneIdx); | 
|  | } | 
|  | Vec = DAG.getNode(ISD::BITCAST, dl, VT, Vec); | 
|  | // Make the DAGCombiner fold the bitcasts. | 
|  | DCI.AddToWorklist(Vec.getNode()); | 
|  | return Vec; | 
|  | } | 
|  |  | 
|  | static SDValue | 
|  | PerformPREDICATE_CASTCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { | 
|  | EVT VT = N->getValueType(0); | 
|  | SDValue Op = N->getOperand(0); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // PREDICATE_CAST(PREDICATE_CAST(x)) == PREDICATE_CAST(x) | 
|  | if (Op->getOpcode() == ARMISD::PREDICATE_CAST) { | 
|  | // If the valuetypes are the same, we can remove the cast entirely. | 
|  | if (Op->getOperand(0).getValueType() == VT) | 
|  | return Op->getOperand(0); | 
|  | return DCI.DAG.getNode(ARMISD::PREDICATE_CAST, dl, VT, Op->getOperand(0)); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue | 
|  | PerformVECTOR_REG_CASTCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *ST) { | 
|  | EVT VT = N->getValueType(0); | 
|  | SDValue Op = N->getOperand(0); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // Under Little endian, a VECTOR_REG_CAST is equivalent to a BITCAST | 
|  | if (ST->isLittle()) | 
|  | return DCI.DAG.getNode(ISD::BITCAST, dl, VT, Op); | 
|  |  | 
|  | // VECTOR_REG_CAST(VECTOR_REG_CAST(x)) == VECTOR_REG_CAST(x) | 
|  | if (Op->getOpcode() == ARMISD::VECTOR_REG_CAST) { | 
|  | // If the valuetypes are the same, we can remove the cast entirely. | 
|  | if (Op->getOperand(0).getValueType() == VT) | 
|  | return Op->getOperand(0); | 
|  | return DCI.DAG.getNode(ARMISD::VECTOR_REG_CAST, dl, VT, Op->getOperand(0)); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformVCMPCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (!Subtarget->hasMVEIntegerOps()) | 
|  | return SDValue(); | 
|  |  | 
|  | EVT VT = N->getValueType(0); | 
|  | SDValue Op0 = N->getOperand(0); | 
|  | SDValue Op1 = N->getOperand(1); | 
|  | ARMCC::CondCodes Cond = | 
|  | (ARMCC::CondCodes)cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // vcmp X, 0, cc -> vcmpz X, cc | 
|  | if (isZeroVector(Op1)) | 
|  | return DCI.DAG.getNode(ARMISD::VCMPZ, dl, VT, Op0, | 
|  | N->getOperand(2)); | 
|  |  | 
|  | unsigned SwappedCond = getSwappedCondition(Cond); | 
|  | if (isValidMVECond(SwappedCond, VT.isFloatingPoint())) { | 
|  | // vcmp 0, X, cc -> vcmpz X, reversed(cc) | 
|  | if (isZeroVector(Op0)) | 
|  | return DCI.DAG.getNode(ARMISD::VCMPZ, dl, VT, Op1, | 
|  | DCI.DAG.getConstant(SwappedCond, dl, MVT::i32)); | 
|  | // vcmp vdup(Y), X, cc -> vcmp X, vdup(Y), reversed(cc) | 
|  | if (Op0->getOpcode() == ARMISD::VDUP && Op1->getOpcode() != ARMISD::VDUP) | 
|  | return DCI.DAG.getNode(ARMISD::VCMP, dl, VT, Op1, Op0, | 
|  | DCI.DAG.getConstant(SwappedCond, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// PerformInsertEltCombine - Target-specific dag combine xforms for | 
|  | /// ISD::INSERT_VECTOR_ELT. | 
|  | static SDValue PerformInsertEltCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | // Bitcast an i64 load inserted into a vector to f64. | 
|  | // Otherwise, the i64 value will be legalized to a pair of i32 values. | 
|  | EVT VT = N->getValueType(0); | 
|  | SDNode *Elt = N->getOperand(1).getNode(); | 
|  | if (VT.getVectorElementType() != MVT::i64 || | 
|  | !ISD::isNormalLoad(Elt) || cast<LoadSDNode>(Elt)->isVolatile()) | 
|  | return SDValue(); | 
|  |  | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDLoc dl(N); | 
|  | EVT FloatVT = EVT::getVectorVT(*DAG.getContext(), MVT::f64, | 
|  | VT.getVectorNumElements()); | 
|  | SDValue Vec = DAG.getNode(ISD::BITCAST, dl, FloatVT, N->getOperand(0)); | 
|  | SDValue V = DAG.getNode(ISD::BITCAST, dl, MVT::f64, N->getOperand(1)); | 
|  | // Make the DAGCombiner fold the bitcasts. | 
|  | DCI.AddToWorklist(Vec.getNode()); | 
|  | DCI.AddToWorklist(V.getNode()); | 
|  | SDValue InsElt = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, FloatVT, | 
|  | Vec, V, N->getOperand(2)); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, InsElt); | 
|  | } | 
|  |  | 
|  | static SDValue PerformExtractEltCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | SDValue Op0 = N->getOperand(0); | 
|  | EVT VT = N->getValueType(0); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // extract (vdup x) -> x | 
|  | if (Op0->getOpcode() == ARMISD::VDUP) { | 
|  | SDValue X = Op0->getOperand(0); | 
|  | if (VT == MVT::f16 && X.getValueType() == MVT::i32) | 
|  | return DCI.DAG.getNode(ARMISD::VMOVhr, dl, VT, X); | 
|  | if (VT == MVT::i32 && X.getValueType() == MVT::f16) | 
|  | return DCI.DAG.getNode(ARMISD::VMOVrh, dl, VT, X); | 
|  |  | 
|  | while (X.getValueType() != VT && X->getOpcode() == ISD::BITCAST) | 
|  | X = X->getOperand(0); | 
|  | if (X.getValueType() == VT) | 
|  | return X; | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// PerformVECTOR_SHUFFLECombine - Target-specific dag combine xforms for | 
|  | /// ISD::VECTOR_SHUFFLE. | 
|  | static SDValue PerformVECTOR_SHUFFLECombine(SDNode *N, SelectionDAG &DAG) { | 
|  | // The LLVM shufflevector instruction does not require the shuffle mask | 
|  | // length to match the operand vector length, but ISD::VECTOR_SHUFFLE does | 
|  | // have that requirement.  When translating to ISD::VECTOR_SHUFFLE, if the | 
|  | // operands do not match the mask length, they are extended by concatenating | 
|  | // them with undef vectors.  That is probably the right thing for other | 
|  | // targets, but for NEON it is better to concatenate two double-register | 
|  | // size vector operands into a single quad-register size vector.  Do that | 
|  | // transformation here: | 
|  | //   shuffle(concat(v1, undef), concat(v2, undef)) -> | 
|  | //   shuffle(concat(v1, v2), undef) | 
|  | SDValue Op0 = N->getOperand(0); | 
|  | SDValue Op1 = N->getOperand(1); | 
|  | if (Op0.getOpcode() != ISD::CONCAT_VECTORS || | 
|  | Op1.getOpcode() != ISD::CONCAT_VECTORS || | 
|  | Op0.getNumOperands() != 2 || | 
|  | Op1.getNumOperands() != 2) | 
|  | return SDValue(); | 
|  | SDValue Concat0Op1 = Op0.getOperand(1); | 
|  | SDValue Concat1Op1 = Op1.getOperand(1); | 
|  | if (!Concat0Op1.isUndef() || !Concat1Op1.isUndef()) | 
|  | return SDValue(); | 
|  | // Skip the transformation if any of the types are illegal. | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | EVT VT = N->getValueType(0); | 
|  | if (!TLI.isTypeLegal(VT) || | 
|  | !TLI.isTypeLegal(Concat0Op1.getValueType()) || | 
|  | !TLI.isTypeLegal(Concat1Op1.getValueType())) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue NewConcat = DAG.getNode(ISD::CONCAT_VECTORS, SDLoc(N), VT, | 
|  | Op0.getOperand(0), Op1.getOperand(0)); | 
|  | // Translate the shuffle mask. | 
|  | SmallVector<int, 16> NewMask; | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | unsigned HalfElts = NumElts/2; | 
|  | ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(N); | 
|  | for (unsigned n = 0; n < NumElts; ++n) { | 
|  | int MaskElt = SVN->getMaskElt(n); | 
|  | int NewElt = -1; | 
|  | if (MaskElt < (int)HalfElts) | 
|  | NewElt = MaskElt; | 
|  | else if (MaskElt >= (int)NumElts && MaskElt < (int)(NumElts + HalfElts)) | 
|  | NewElt = HalfElts + MaskElt - NumElts; | 
|  | NewMask.push_back(NewElt); | 
|  | } | 
|  | return DAG.getVectorShuffle(VT, SDLoc(N), NewConcat, | 
|  | DAG.getUNDEF(VT), NewMask); | 
|  | } | 
|  |  | 
|  | /// CombineBaseUpdate - Target-specific DAG combine function for VLDDUP, | 
|  | /// NEON load/store intrinsics, and generic vector load/stores, to merge | 
|  | /// base address updates. | 
|  | /// For generic load/stores, the memory type is assumed to be a vector. | 
|  | /// The caller is assumed to have checked legality. | 
|  | static SDValue CombineBaseUpdate(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | const bool isIntrinsic = (N->getOpcode() == ISD::INTRINSIC_VOID || | 
|  | N->getOpcode() == ISD::INTRINSIC_W_CHAIN); | 
|  | const bool isStore = N->getOpcode() == ISD::STORE; | 
|  | const unsigned AddrOpIdx = ((isIntrinsic || isStore) ? 2 : 1); | 
|  | SDValue Addr = N->getOperand(AddrOpIdx); | 
|  | MemSDNode *MemN = cast<MemSDNode>(N); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // Search for a use of the address operand that is an increment. | 
|  | for (SDNode::use_iterator UI = Addr.getNode()->use_begin(), | 
|  | UE = Addr.getNode()->use_end(); UI != UE; ++UI) { | 
|  | SDNode *User = *UI; | 
|  | if (User->getOpcode() != ISD::ADD || | 
|  | UI.getUse().getResNo() != Addr.getResNo()) | 
|  | continue; | 
|  |  | 
|  | // Check that the add is independent of the load/store.  Otherwise, folding | 
|  | // it would create a cycle. We can avoid searching through Addr as it's a | 
|  | // predecessor to both. | 
|  | SmallPtrSet<const SDNode *, 32> Visited; | 
|  | SmallVector<const SDNode *, 16> Worklist; | 
|  | Visited.insert(Addr.getNode()); | 
|  | Worklist.push_back(N); | 
|  | Worklist.push_back(User); | 
|  | if (SDNode::hasPredecessorHelper(N, Visited, Worklist) || | 
|  | SDNode::hasPredecessorHelper(User, Visited, Worklist)) | 
|  | continue; | 
|  |  | 
|  | // Find the new opcode for the updating load/store. | 
|  | bool isLoadOp = true; | 
|  | bool isLaneOp = false; | 
|  | unsigned NewOpc = 0; | 
|  | unsigned NumVecs = 0; | 
|  | if (isIntrinsic) { | 
|  | unsigned IntNo = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue(); | 
|  | switch (IntNo) { | 
|  | default: llvm_unreachable("unexpected intrinsic for Neon base update"); | 
|  | case Intrinsic::arm_neon_vld1:     NewOpc = ARMISD::VLD1_UPD; | 
|  | NumVecs = 1; break; | 
|  | case Intrinsic::arm_neon_vld2:     NewOpc = ARMISD::VLD2_UPD; | 
|  | NumVecs = 2; break; | 
|  | case Intrinsic::arm_neon_vld3:     NewOpc = ARMISD::VLD3_UPD; | 
|  | NumVecs = 3; break; | 
|  | case Intrinsic::arm_neon_vld4:     NewOpc = ARMISD::VLD4_UPD; | 
|  | NumVecs = 4; break; | 
|  | case Intrinsic::arm_neon_vld2dup: | 
|  | case Intrinsic::arm_neon_vld3dup: | 
|  | case Intrinsic::arm_neon_vld4dup: | 
|  | // TODO: Support updating VLDxDUP nodes. For now, we just skip | 
|  | // combining base updates for such intrinsics. | 
|  | continue; | 
|  | case Intrinsic::arm_neon_vld2lane: NewOpc = ARMISD::VLD2LN_UPD; | 
|  | NumVecs = 2; isLaneOp = true; break; | 
|  | case Intrinsic::arm_neon_vld3lane: NewOpc = ARMISD::VLD3LN_UPD; | 
|  | NumVecs = 3; isLaneOp = true; break; | 
|  | case Intrinsic::arm_neon_vld4lane: NewOpc = ARMISD::VLD4LN_UPD; | 
|  | NumVecs = 4; isLaneOp = true; break; | 
|  | case Intrinsic::arm_neon_vst1:     NewOpc = ARMISD::VST1_UPD; | 
|  | NumVecs = 1; isLoadOp = false; break; | 
|  | case Intrinsic::arm_neon_vst2:     NewOpc = ARMISD::VST2_UPD; | 
|  | NumVecs = 2; isLoadOp = false; break; | 
|  | case Intrinsic::arm_neon_vst3:     NewOpc = ARMISD::VST3_UPD; | 
|  | NumVecs = 3; isLoadOp = false; break; | 
|  | case Intrinsic::arm_neon_vst4:     NewOpc = ARMISD::VST4_UPD; | 
|  | NumVecs = 4; isLoadOp = false; break; | 
|  | case Intrinsic::arm_neon_vst2lane: NewOpc = ARMISD::VST2LN_UPD; | 
|  | NumVecs = 2; isLoadOp = false; isLaneOp = true; break; | 
|  | case Intrinsic::arm_neon_vst3lane: NewOpc = ARMISD::VST3LN_UPD; | 
|  | NumVecs = 3; isLoadOp = false; isLaneOp = true; break; | 
|  | case Intrinsic::arm_neon_vst4lane: NewOpc = ARMISD::VST4LN_UPD; | 
|  | NumVecs = 4; isLoadOp = false; isLaneOp = true; break; | 
|  | } | 
|  | } else { | 
|  | isLaneOp = true; | 
|  | switch (N->getOpcode()) { | 
|  | default: llvm_unreachable("unexpected opcode for Neon base update"); | 
|  | case ARMISD::VLD1DUP: NewOpc = ARMISD::VLD1DUP_UPD; NumVecs = 1; break; | 
|  | case ARMISD::VLD2DUP: NewOpc = ARMISD::VLD2DUP_UPD; NumVecs = 2; break; | 
|  | case ARMISD::VLD3DUP: NewOpc = ARMISD::VLD3DUP_UPD; NumVecs = 3; break; | 
|  | case ARMISD::VLD4DUP: NewOpc = ARMISD::VLD4DUP_UPD; NumVecs = 4; break; | 
|  | case ISD::LOAD:       NewOpc = ARMISD::VLD1_UPD; | 
|  | NumVecs = 1; isLaneOp = false; break; | 
|  | case ISD::STORE:      NewOpc = ARMISD::VST1_UPD; | 
|  | NumVecs = 1; isLaneOp = false; isLoadOp = false; break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Find the size of memory referenced by the load/store. | 
|  | EVT VecTy; | 
|  | if (isLoadOp) { | 
|  | VecTy = N->getValueType(0); | 
|  | } else if (isIntrinsic) { | 
|  | VecTy = N->getOperand(AddrOpIdx+1).getValueType(); | 
|  | } else { | 
|  | assert(isStore && "Node has to be a load, a store, or an intrinsic!"); | 
|  | VecTy = N->getOperand(1).getValueType(); | 
|  | } | 
|  |  | 
|  | unsigned NumBytes = NumVecs * VecTy.getSizeInBits() / 8; | 
|  | if (isLaneOp) | 
|  | NumBytes /= VecTy.getVectorNumElements(); | 
|  |  | 
|  | // If the increment is a constant, it must match the memory ref size. | 
|  | SDValue Inc = User->getOperand(User->getOperand(0) == Addr ? 1 : 0); | 
|  | ConstantSDNode *CInc = dyn_cast<ConstantSDNode>(Inc.getNode()); | 
|  | if (NumBytes >= 3 * 16 && (!CInc || CInc->getZExtValue() != NumBytes)) { | 
|  | // VLD3/4 and VST3/4 for 128-bit vectors are implemented with two | 
|  | // separate instructions that make it harder to use a non-constant update. | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // OK, we found an ADD we can fold into the base update. | 
|  | // Now, create a _UPD node, taking care of not breaking alignment. | 
|  |  | 
|  | EVT AlignedVecTy = VecTy; | 
|  | unsigned Alignment = MemN->getAlignment(); | 
|  |  | 
|  | // If this is a less-than-standard-aligned load/store, change the type to | 
|  | // match the standard alignment. | 
|  | // The alignment is overlooked when selecting _UPD variants; and it's | 
|  | // easier to introduce bitcasts here than fix that. | 
|  | // There are 3 ways to get to this base-update combine: | 
|  | // - intrinsics: they are assumed to be properly aligned (to the standard | 
|  | //   alignment of the memory type), so we don't need to do anything. | 
|  | // - ARMISD::VLDx nodes: they are only generated from the aforementioned | 
|  | //   intrinsics, so, likewise, there's nothing to do. | 
|  | // - generic load/store instructions: the alignment is specified as an | 
|  | //   explicit operand, rather than implicitly as the standard alignment | 
|  | //   of the memory type (like the intrisics).  We need to change the | 
|  | //   memory type to match the explicit alignment.  That way, we don't | 
|  | //   generate non-standard-aligned ARMISD::VLDx nodes. | 
|  | if (isa<LSBaseSDNode>(N)) { | 
|  | if (Alignment == 0) | 
|  | Alignment = 1; | 
|  | if (Alignment < VecTy.getScalarSizeInBits() / 8) { | 
|  | MVT EltTy = MVT::getIntegerVT(Alignment * 8); | 
|  | assert(NumVecs == 1 && "Unexpected multi-element generic load/store."); | 
|  | assert(!isLaneOp && "Unexpected generic load/store lane."); | 
|  | unsigned NumElts = NumBytes / (EltTy.getSizeInBits() / 8); | 
|  | AlignedVecTy = MVT::getVectorVT(EltTy, NumElts); | 
|  | } | 
|  | // Don't set an explicit alignment on regular load/stores that we want | 
|  | // to transform to VLD/VST 1_UPD nodes. | 
|  | // This matches the behavior of regular load/stores, which only get an | 
|  | // explicit alignment if the MMO alignment is larger than the standard | 
|  | // alignment of the memory type. | 
|  | // Intrinsics, however, always get an explicit alignment, set to the | 
|  | // alignment of the MMO. | 
|  | Alignment = 1; | 
|  | } | 
|  |  | 
|  | // Create the new updating load/store node. | 
|  | // First, create an SDVTList for the new updating node's results. | 
|  | EVT Tys[6]; | 
|  | unsigned NumResultVecs = (isLoadOp ? NumVecs : 0); | 
|  | unsigned n; | 
|  | for (n = 0; n < NumResultVecs; ++n) | 
|  | Tys[n] = AlignedVecTy; | 
|  | Tys[n++] = MVT::i32; | 
|  | Tys[n] = MVT::Other; | 
|  | SDVTList SDTys = DAG.getVTList(makeArrayRef(Tys, NumResultVecs+2)); | 
|  |  | 
|  | // Then, gather the new node's operands. | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | Ops.push_back(N->getOperand(0)); // incoming chain | 
|  | Ops.push_back(N->getOperand(AddrOpIdx)); | 
|  | Ops.push_back(Inc); | 
|  |  | 
|  | if (StoreSDNode *StN = dyn_cast<StoreSDNode>(N)) { | 
|  | // Try to match the intrinsic's signature | 
|  | Ops.push_back(StN->getValue()); | 
|  | } else { | 
|  | // Loads (and of course intrinsics) match the intrinsics' signature, | 
|  | // so just add all but the alignment operand. | 
|  | for (unsigned i = AddrOpIdx + 1; i < N->getNumOperands() - 1; ++i) | 
|  | Ops.push_back(N->getOperand(i)); | 
|  | } | 
|  |  | 
|  | // For all node types, the alignment operand is always the last one. | 
|  | Ops.push_back(DAG.getConstant(Alignment, dl, MVT::i32)); | 
|  |  | 
|  | // If this is a non-standard-aligned STORE, the penultimate operand is the | 
|  | // stored value.  Bitcast it to the aligned type. | 
|  | if (AlignedVecTy != VecTy && N->getOpcode() == ISD::STORE) { | 
|  | SDValue &StVal = Ops[Ops.size()-2]; | 
|  | StVal = DAG.getNode(ISD::BITCAST, dl, AlignedVecTy, StVal); | 
|  | } | 
|  |  | 
|  | EVT LoadVT = isLaneOp ? VecTy.getVectorElementType() : AlignedVecTy; | 
|  | SDValue UpdN = DAG.getMemIntrinsicNode(NewOpc, dl, SDTys, Ops, LoadVT, | 
|  | MemN->getMemOperand()); | 
|  |  | 
|  | // Update the uses. | 
|  | SmallVector<SDValue, 5> NewResults; | 
|  | for (unsigned i = 0; i < NumResultVecs; ++i) | 
|  | NewResults.push_back(SDValue(UpdN.getNode(), i)); | 
|  |  | 
|  | // If this is an non-standard-aligned LOAD, the first result is the loaded | 
|  | // value.  Bitcast it to the expected result type. | 
|  | if (AlignedVecTy != VecTy && N->getOpcode() == ISD::LOAD) { | 
|  | SDValue &LdVal = NewResults[0]; | 
|  | LdVal = DAG.getNode(ISD::BITCAST, dl, VecTy, LdVal); | 
|  | } | 
|  |  | 
|  | NewResults.push_back(SDValue(UpdN.getNode(), NumResultVecs+1)); // chain | 
|  | DCI.CombineTo(N, NewResults); | 
|  | DCI.CombineTo(User, SDValue(UpdN.getNode(), NumResultVecs)); | 
|  |  | 
|  | break; | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformVLDCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer()) | 
|  | return SDValue(); | 
|  |  | 
|  | return CombineBaseUpdate(N, DCI); | 
|  | } | 
|  |  | 
|  | static SDValue PerformMVEVLDCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer()) | 
|  | return SDValue(); | 
|  |  | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDValue Addr = N->getOperand(2); | 
|  | MemSDNode *MemN = cast<MemSDNode>(N); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // For the stores, where there are multiple intrinsics we only actually want | 
|  | // to post-inc the last of the them. | 
|  | unsigned IntNo = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue(); | 
|  | if (IntNo == Intrinsic::arm_mve_vst2q && | 
|  | cast<ConstantSDNode>(N->getOperand(5))->getZExtValue() != 1) | 
|  | return SDValue(); | 
|  | if (IntNo == Intrinsic::arm_mve_vst4q && | 
|  | cast<ConstantSDNode>(N->getOperand(7))->getZExtValue() != 3) | 
|  | return SDValue(); | 
|  |  | 
|  | // Search for a use of the address operand that is an increment. | 
|  | for (SDNode::use_iterator UI = Addr.getNode()->use_begin(), | 
|  | UE = Addr.getNode()->use_end(); | 
|  | UI != UE; ++UI) { | 
|  | SDNode *User = *UI; | 
|  | if (User->getOpcode() != ISD::ADD || | 
|  | UI.getUse().getResNo() != Addr.getResNo()) | 
|  | continue; | 
|  |  | 
|  | // Check that the add is independent of the load/store.  Otherwise, folding | 
|  | // it would create a cycle. We can avoid searching through Addr as it's a | 
|  | // predecessor to both. | 
|  | SmallPtrSet<const SDNode *, 32> Visited; | 
|  | SmallVector<const SDNode *, 16> Worklist; | 
|  | Visited.insert(Addr.getNode()); | 
|  | Worklist.push_back(N); | 
|  | Worklist.push_back(User); | 
|  | if (SDNode::hasPredecessorHelper(N, Visited, Worklist) || | 
|  | SDNode::hasPredecessorHelper(User, Visited, Worklist)) | 
|  | continue; | 
|  |  | 
|  | // Find the new opcode for the updating load/store. | 
|  | bool isLoadOp = true; | 
|  | unsigned NewOpc = 0; | 
|  | unsigned NumVecs = 0; | 
|  | switch (IntNo) { | 
|  | default: | 
|  | llvm_unreachable("unexpected intrinsic for MVE VLDn combine"); | 
|  | case Intrinsic::arm_mve_vld2q: | 
|  | NewOpc = ARMISD::VLD2_UPD; | 
|  | NumVecs = 2; | 
|  | break; | 
|  | case Intrinsic::arm_mve_vld4q: | 
|  | NewOpc = ARMISD::VLD4_UPD; | 
|  | NumVecs = 4; | 
|  | break; | 
|  | case Intrinsic::arm_mve_vst2q: | 
|  | NewOpc = ARMISD::VST2_UPD; | 
|  | NumVecs = 2; | 
|  | isLoadOp = false; | 
|  | break; | 
|  | case Intrinsic::arm_mve_vst4q: | 
|  | NewOpc = ARMISD::VST4_UPD; | 
|  | NumVecs = 4; | 
|  | isLoadOp = false; | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Find the size of memory referenced by the load/store. | 
|  | EVT VecTy; | 
|  | if (isLoadOp) { | 
|  | VecTy = N->getValueType(0); | 
|  | } else { | 
|  | VecTy = N->getOperand(3).getValueType(); | 
|  | } | 
|  |  | 
|  | unsigned NumBytes = NumVecs * VecTy.getSizeInBits() / 8; | 
|  |  | 
|  | // If the increment is a constant, it must match the memory ref size. | 
|  | SDValue Inc = User->getOperand(User->getOperand(0) == Addr ? 1 : 0); | 
|  | ConstantSDNode *CInc = dyn_cast<ConstantSDNode>(Inc.getNode()); | 
|  | if (!CInc || CInc->getZExtValue() != NumBytes) | 
|  | continue; | 
|  |  | 
|  | // Create the new updating load/store node. | 
|  | // First, create an SDVTList for the new updating node's results. | 
|  | EVT Tys[6]; | 
|  | unsigned NumResultVecs = (isLoadOp ? NumVecs : 0); | 
|  | unsigned n; | 
|  | for (n = 0; n < NumResultVecs; ++n) | 
|  | Tys[n] = VecTy; | 
|  | Tys[n++] = MVT::i32; | 
|  | Tys[n] = MVT::Other; | 
|  | SDVTList SDTys = DAG.getVTList(makeArrayRef(Tys, NumResultVecs + 2)); | 
|  |  | 
|  | // Then, gather the new node's operands. | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | Ops.push_back(N->getOperand(0)); // incoming chain | 
|  | Ops.push_back(N->getOperand(2)); // ptr | 
|  | Ops.push_back(Inc); | 
|  |  | 
|  | for (unsigned i = 3; i < N->getNumOperands(); ++i) | 
|  | Ops.push_back(N->getOperand(i)); | 
|  |  | 
|  | SDValue UpdN = DAG.getMemIntrinsicNode(NewOpc, dl, SDTys, Ops, VecTy, | 
|  | MemN->getMemOperand()); | 
|  |  | 
|  | // Update the uses. | 
|  | SmallVector<SDValue, 5> NewResults; | 
|  | for (unsigned i = 0; i < NumResultVecs; ++i) | 
|  | NewResults.push_back(SDValue(UpdN.getNode(), i)); | 
|  |  | 
|  | NewResults.push_back(SDValue(UpdN.getNode(), NumResultVecs + 1)); // chain | 
|  | DCI.CombineTo(N, NewResults); | 
|  | DCI.CombineTo(User, SDValue(UpdN.getNode(), NumResultVecs)); | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// CombineVLDDUP - For a VDUPLANE node N, check if its source operand is a | 
|  | /// vldN-lane (N > 1) intrinsic, and if all the other uses of that intrinsic | 
|  | /// are also VDUPLANEs.  If so, combine them to a vldN-dup operation and | 
|  | /// return true. | 
|  | static bool CombineVLDDUP(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | EVT VT = N->getValueType(0); | 
|  | // vldN-dup instructions only support 64-bit vectors for N > 1. | 
|  | if (!VT.is64BitVector()) | 
|  | return false; | 
|  |  | 
|  | // Check if the VDUPLANE operand is a vldN-dup intrinsic. | 
|  | SDNode *VLD = N->getOperand(0).getNode(); | 
|  | if (VLD->getOpcode() != ISD::INTRINSIC_W_CHAIN) | 
|  | return false; | 
|  | unsigned NumVecs = 0; | 
|  | unsigned NewOpc = 0; | 
|  | unsigned IntNo = cast<ConstantSDNode>(VLD->getOperand(1))->getZExtValue(); | 
|  | if (IntNo == Intrinsic::arm_neon_vld2lane) { | 
|  | NumVecs = 2; | 
|  | NewOpc = ARMISD::VLD2DUP; | 
|  | } else if (IntNo == Intrinsic::arm_neon_vld3lane) { | 
|  | NumVecs = 3; | 
|  | NewOpc = ARMISD::VLD3DUP; | 
|  | } else if (IntNo == Intrinsic::arm_neon_vld4lane) { | 
|  | NumVecs = 4; | 
|  | NewOpc = ARMISD::VLD4DUP; | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // First check that all the vldN-lane uses are VDUPLANEs and that the lane | 
|  | // numbers match the load. | 
|  | unsigned VLDLaneNo = | 
|  | cast<ConstantSDNode>(VLD->getOperand(NumVecs+3))->getZExtValue(); | 
|  | for (SDNode::use_iterator UI = VLD->use_begin(), UE = VLD->use_end(); | 
|  | UI != UE; ++UI) { | 
|  | // Ignore uses of the chain result. | 
|  | if (UI.getUse().getResNo() == NumVecs) | 
|  | continue; | 
|  | SDNode *User = *UI; | 
|  | if (User->getOpcode() != ARMISD::VDUPLANE || | 
|  | VLDLaneNo != cast<ConstantSDNode>(User->getOperand(1))->getZExtValue()) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Create the vldN-dup node. | 
|  | EVT Tys[5]; | 
|  | unsigned n; | 
|  | for (n = 0; n < NumVecs; ++n) | 
|  | Tys[n] = VT; | 
|  | Tys[n] = MVT::Other; | 
|  | SDVTList SDTys = DAG.getVTList(makeArrayRef(Tys, NumVecs+1)); | 
|  | SDValue Ops[] = { VLD->getOperand(0), VLD->getOperand(2) }; | 
|  | MemIntrinsicSDNode *VLDMemInt = cast<MemIntrinsicSDNode>(VLD); | 
|  | SDValue VLDDup = DAG.getMemIntrinsicNode(NewOpc, SDLoc(VLD), SDTys, | 
|  | Ops, VLDMemInt->getMemoryVT(), | 
|  | VLDMemInt->getMemOperand()); | 
|  |  | 
|  | // Update the uses. | 
|  | for (SDNode::use_iterator UI = VLD->use_begin(), UE = VLD->use_end(); | 
|  | UI != UE; ++UI) { | 
|  | unsigned ResNo = UI.getUse().getResNo(); | 
|  | // Ignore uses of the chain result. | 
|  | if (ResNo == NumVecs) | 
|  | continue; | 
|  | SDNode *User = *UI; | 
|  | DCI.CombineTo(User, SDValue(VLDDup.getNode(), ResNo)); | 
|  | } | 
|  |  | 
|  | // Now the vldN-lane intrinsic is dead except for its chain result. | 
|  | // Update uses of the chain. | 
|  | std::vector<SDValue> VLDDupResults; | 
|  | for (unsigned n = 0; n < NumVecs; ++n) | 
|  | VLDDupResults.push_back(SDValue(VLDDup.getNode(), n)); | 
|  | VLDDupResults.push_back(SDValue(VLDDup.getNode(), NumVecs)); | 
|  | DCI.CombineTo(VLD, VLDDupResults); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// PerformVDUPLANECombine - Target-specific dag combine xforms for | 
|  | /// ARMISD::VDUPLANE. | 
|  | static SDValue PerformVDUPLANECombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | SDValue Op = N->getOperand(0); | 
|  | EVT VT = N->getValueType(0); | 
|  |  | 
|  | // On MVE, we just convert the VDUPLANE to a VDUP with an extract. | 
|  | if (Subtarget->hasMVEIntegerOps()) { | 
|  | EVT ExtractVT = VT.getVectorElementType(); | 
|  | // We need to ensure we are creating a legal type. | 
|  | if (!DCI.DAG.getTargetLoweringInfo().isTypeLegal(ExtractVT)) | 
|  | ExtractVT = MVT::i32; | 
|  | SDValue Extract = DCI.DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(N), ExtractVT, | 
|  | N->getOperand(0), N->getOperand(1)); | 
|  | return DCI.DAG.getNode(ARMISD::VDUP, SDLoc(N), VT, Extract); | 
|  | } | 
|  |  | 
|  | // If the source is a vldN-lane (N > 1) intrinsic, and all the other uses | 
|  | // of that intrinsic are also VDUPLANEs, combine them to a vldN-dup operation. | 
|  | if (CombineVLDDUP(N, DCI)) | 
|  | return SDValue(N, 0); | 
|  |  | 
|  | // If the source is already a VMOVIMM or VMVNIMM splat, the VDUPLANE is | 
|  | // redundant.  Ignore bit_converts for now; element sizes are checked below. | 
|  | while (Op.getOpcode() == ISD::BITCAST) | 
|  | Op = Op.getOperand(0); | 
|  | if (Op.getOpcode() != ARMISD::VMOVIMM && Op.getOpcode() != ARMISD::VMVNIMM) | 
|  | return SDValue(); | 
|  |  | 
|  | // Make sure the VMOV element size is not bigger than the VDUPLANE elements. | 
|  | unsigned EltSize = Op.getScalarValueSizeInBits(); | 
|  | // The canonical VMOV for a zero vector uses a 32-bit element size. | 
|  | unsigned Imm = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); | 
|  | unsigned EltBits; | 
|  | if (ARM_AM::decodeVMOVModImm(Imm, EltBits) == 0) | 
|  | EltSize = 8; | 
|  | if (EltSize > VT.getScalarSizeInBits()) | 
|  | return SDValue(); | 
|  |  | 
|  | return DCI.DAG.getNode(ISD::BITCAST, SDLoc(N), VT, Op); | 
|  | } | 
|  |  | 
|  | /// PerformVDUPCombine - Target-specific dag combine xforms for ARMISD::VDUP. | 
|  | static SDValue PerformVDUPCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDValue Op = N->getOperand(0); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | if (Subtarget->hasMVEIntegerOps()) { | 
|  | // Convert VDUP f32 -> VDUP BITCAST i32 under MVE, as we know the value will | 
|  | // need to come from a GPR. | 
|  | if (Op.getValueType() == MVT::f32) | 
|  | return DCI.DAG.getNode(ARMISD::VDUP, dl, N->getValueType(0), | 
|  | DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op)); | 
|  | else if (Op.getValueType() == MVT::f16) | 
|  | return DCI.DAG.getNode(ARMISD::VDUP, dl, N->getValueType(0), | 
|  | DAG.getNode(ARMISD::VMOVrh, dl, MVT::i32, Op)); | 
|  | } | 
|  |  | 
|  | if (!Subtarget->hasNEON()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Match VDUP(LOAD) -> VLD1DUP. | 
|  | // We match this pattern here rather than waiting for isel because the | 
|  | // transform is only legal for unindexed loads. | 
|  | LoadSDNode *LD = dyn_cast<LoadSDNode>(Op.getNode()); | 
|  | if (LD && Op.hasOneUse() && LD->isUnindexed() && | 
|  | LD->getMemoryVT() == N->getValueType(0).getVectorElementType()) { | 
|  | SDValue Ops[] = { LD->getOperand(0), LD->getOperand(1), | 
|  | DAG.getConstant(LD->getAlignment(), SDLoc(N), MVT::i32) }; | 
|  | SDVTList SDTys = DAG.getVTList(N->getValueType(0), MVT::Other); | 
|  | SDValue VLDDup = DAG.getMemIntrinsicNode(ARMISD::VLD1DUP, SDLoc(N), SDTys, | 
|  | Ops, LD->getMemoryVT(), | 
|  | LD->getMemOperand()); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(LD, 1), VLDDup.getValue(1)); | 
|  | return VLDDup; | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformLOADCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | EVT VT = N->getValueType(0); | 
|  |  | 
|  | // If this is a legal vector load, try to combine it into a VLD1_UPD. | 
|  | if (ISD::isNormalLoad(N) && VT.isVector() && | 
|  | DCI.DAG.getTargetLoweringInfo().isTypeLegal(VT)) | 
|  | return CombineBaseUpdate(N, DCI); | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // Optimize trunc store (of multiple scalars) to shuffle and store.  First, | 
|  | // pack all of the elements in one place.  Next, store to memory in fewer | 
|  | // chunks. | 
|  | static SDValue PerformTruncatingStoreCombine(StoreSDNode *St, | 
|  | SelectionDAG &DAG) { | 
|  | SDValue StVal = St->getValue(); | 
|  | EVT VT = StVal.getValueType(); | 
|  | if (!St->isTruncatingStore() || !VT.isVector()) | 
|  | return SDValue(); | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | EVT StVT = St->getMemoryVT(); | 
|  | unsigned NumElems = VT.getVectorNumElements(); | 
|  | assert(StVT != VT && "Cannot truncate to the same type"); | 
|  | unsigned FromEltSz = VT.getScalarSizeInBits(); | 
|  | unsigned ToEltSz = StVT.getScalarSizeInBits(); | 
|  |  | 
|  | // From, To sizes and ElemCount must be pow of two | 
|  | if (!isPowerOf2_32(NumElems * FromEltSz * ToEltSz)) | 
|  | return SDValue(); | 
|  |  | 
|  | // We are going to use the original vector elt for storing. | 
|  | // Accumulated smaller vector elements must be a multiple of the store size. | 
|  | if (0 != (NumElems * FromEltSz) % ToEltSz) | 
|  | return SDValue(); | 
|  |  | 
|  | unsigned SizeRatio = FromEltSz / ToEltSz; | 
|  | assert(SizeRatio * NumElems * ToEltSz == VT.getSizeInBits()); | 
|  |  | 
|  | // Create a type on which we perform the shuffle. | 
|  | EVT WideVecVT = EVT::getVectorVT(*DAG.getContext(), StVT.getScalarType(), | 
|  | NumElems * SizeRatio); | 
|  | assert(WideVecVT.getSizeInBits() == VT.getSizeInBits()); | 
|  |  | 
|  | SDLoc DL(St); | 
|  | SDValue WideVec = DAG.getNode(ISD::BITCAST, DL, WideVecVT, StVal); | 
|  | SmallVector<int, 8> ShuffleVec(NumElems * SizeRatio, -1); | 
|  | for (unsigned i = 0; i < NumElems; ++i) | 
|  | ShuffleVec[i] = DAG.getDataLayout().isBigEndian() ? (i + 1) * SizeRatio - 1 | 
|  | : i * SizeRatio; | 
|  |  | 
|  | // Can't shuffle using an illegal type. | 
|  | if (!TLI.isTypeLegal(WideVecVT)) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue Shuff = DAG.getVectorShuffle( | 
|  | WideVecVT, DL, WideVec, DAG.getUNDEF(WideVec.getValueType()), ShuffleVec); | 
|  | // At this point all of the data is stored at the bottom of the | 
|  | // register. We now need to save it to mem. | 
|  |  | 
|  | // Find the largest store unit | 
|  | MVT StoreType = MVT::i8; | 
|  | for (MVT Tp : MVT::integer_valuetypes()) { | 
|  | if (TLI.isTypeLegal(Tp) && Tp.getSizeInBits() <= NumElems * ToEltSz) | 
|  | StoreType = Tp; | 
|  | } | 
|  | // Didn't find a legal store type. | 
|  | if (!TLI.isTypeLegal(StoreType)) | 
|  | return SDValue(); | 
|  |  | 
|  | // Bitcast the original vector into a vector of store-size units | 
|  | EVT StoreVecVT = | 
|  | EVT::getVectorVT(*DAG.getContext(), StoreType, | 
|  | VT.getSizeInBits() / EVT(StoreType).getSizeInBits()); | 
|  | assert(StoreVecVT.getSizeInBits() == VT.getSizeInBits()); | 
|  | SDValue ShuffWide = DAG.getNode(ISD::BITCAST, DL, StoreVecVT, Shuff); | 
|  | SmallVector<SDValue, 8> Chains; | 
|  | SDValue Increment = DAG.getConstant(StoreType.getSizeInBits() / 8, DL, | 
|  | TLI.getPointerTy(DAG.getDataLayout())); | 
|  | SDValue BasePtr = St->getBasePtr(); | 
|  |  | 
|  | // Perform one or more big stores into memory. | 
|  | unsigned E = (ToEltSz * NumElems) / StoreType.getSizeInBits(); | 
|  | for (unsigned I = 0; I < E; I++) { | 
|  | SDValue SubVec = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, StoreType, | 
|  | ShuffWide, DAG.getIntPtrConstant(I, DL)); | 
|  | SDValue Ch = | 
|  | DAG.getStore(St->getChain(), DL, SubVec, BasePtr, St->getPointerInfo(), | 
|  | St->getAlignment(), St->getMemOperand()->getFlags()); | 
|  | BasePtr = | 
|  | DAG.getNode(ISD::ADD, DL, BasePtr.getValueType(), BasePtr, Increment); | 
|  | Chains.push_back(Ch); | 
|  | } | 
|  | return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Chains); | 
|  | } | 
|  |  | 
|  | // Try taking a single vector store from an truncate (which would otherwise turn | 
|  | // into an expensive buildvector) and splitting it into a series of narrowing | 
|  | // stores. | 
|  | static SDValue PerformSplittingToNarrowingStores(StoreSDNode *St, | 
|  | SelectionDAG &DAG) { | 
|  | if (!St->isSimple() || St->isTruncatingStore() || !St->isUnindexed()) | 
|  | return SDValue(); | 
|  | SDValue Trunc = St->getValue(); | 
|  | if (Trunc->getOpcode() != ISD::TRUNCATE) | 
|  | return SDValue(); | 
|  | EVT FromVT = Trunc->getOperand(0).getValueType(); | 
|  | EVT ToVT = Trunc.getValueType(); | 
|  | if (!ToVT.isVector()) | 
|  | return SDValue(); | 
|  | assert(FromVT.getVectorNumElements() == ToVT.getVectorNumElements()); | 
|  | EVT ToEltVT = ToVT.getVectorElementType(); | 
|  | EVT FromEltVT = FromVT.getVectorElementType(); | 
|  |  | 
|  | unsigned NumElements = 0; | 
|  | if (FromEltVT == MVT::i32 && (ToEltVT == MVT::i16 || ToEltVT == MVT::i8)) | 
|  | NumElements = 4; | 
|  | if (FromEltVT == MVT::i16 && ToEltVT == MVT::i8) | 
|  | NumElements = 8; | 
|  | if (NumElements == 0 || FromVT.getVectorNumElements() == NumElements || | 
|  | FromVT.getVectorNumElements() % NumElements != 0) | 
|  | return SDValue(); | 
|  |  | 
|  | // Test if the Trunc will be convertable to a VMOVN with a shuffle, and if so | 
|  | // use the VMOVN over splitting the store. We are looking for patterns of: | 
|  | // !rev: 0 N 1 N+1 2 N+2 ... | 
|  | //  rev: N 0 N+1 1 N+2 2 ... | 
|  | auto isVMOVNOriginalMask = [&](ArrayRef<int> M, bool rev) { | 
|  | unsigned NumElts = ToVT.getVectorNumElements(); | 
|  | if (NumElts != M.size() || (ToVT != MVT::v8i16 && ToVT != MVT::v16i8)) | 
|  | return false; | 
|  |  | 
|  | unsigned Off0 = rev ? NumElts : 0; | 
|  | unsigned Off1 = rev ? 0 : NumElts; | 
|  |  | 
|  | for (unsigned i = 0; i < NumElts; i += 2) { | 
|  | if (M[i] >= 0 && M[i] != (int)(Off0 + i / 2)) | 
|  | return false; | 
|  | if (M[i + 1] >= 0 && M[i + 1] != (int)(Off1 + i / 2)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | if (auto *Shuffle = dyn_cast<ShuffleVectorSDNode>(Trunc->getOperand(0))) | 
|  | if (isVMOVNOriginalMask(Shuffle->getMask(), false) || | 
|  | isVMOVNOriginalMask(Shuffle->getMask(), true)) | 
|  | return SDValue(); | 
|  |  | 
|  | SDLoc DL(St); | 
|  | // Details about the old store | 
|  | SDValue Ch = St->getChain(); | 
|  | SDValue BasePtr = St->getBasePtr(); | 
|  | Align Alignment = St->getOriginalAlign(); | 
|  | MachineMemOperand::Flags MMOFlags = St->getMemOperand()->getFlags(); | 
|  | AAMDNodes AAInfo = St->getAAInfo(); | 
|  |  | 
|  | EVT NewFromVT = EVT::getVectorVT(*DAG.getContext(), FromEltVT, NumElements); | 
|  | EVT NewToVT = EVT::getVectorVT(*DAG.getContext(), ToEltVT, NumElements); | 
|  |  | 
|  | SmallVector<SDValue, 4> Stores; | 
|  | for (unsigned i = 0; i < FromVT.getVectorNumElements() / NumElements; i++) { | 
|  | unsigned NewOffset = i * NumElements * ToEltVT.getSizeInBits() / 8; | 
|  | SDValue NewPtr = DAG.getObjectPtrOffset(DL, BasePtr, NewOffset); | 
|  |  | 
|  | SDValue Extract = | 
|  | DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, NewFromVT, Trunc.getOperand(0), | 
|  | DAG.getConstant(i * NumElements, DL, MVT::i32)); | 
|  | SDValue Store = DAG.getTruncStore( | 
|  | Ch, DL, Extract, NewPtr, St->getPointerInfo().getWithOffset(NewOffset), | 
|  | NewToVT, Alignment.value(), MMOFlags, AAInfo); | 
|  | Stores.push_back(Store); | 
|  | } | 
|  | return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Stores); | 
|  | } | 
|  |  | 
|  | /// PerformSTORECombine - Target-specific dag combine xforms for | 
|  | /// ISD::STORE. | 
|  | static SDValue PerformSTORECombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | StoreSDNode *St = cast<StoreSDNode>(N); | 
|  | if (St->isVolatile()) | 
|  | return SDValue(); | 
|  | SDValue StVal = St->getValue(); | 
|  | EVT VT = StVal.getValueType(); | 
|  |  | 
|  | if (Subtarget->hasNEON()) | 
|  | if (SDValue Store = PerformTruncatingStoreCombine(St, DCI.DAG)) | 
|  | return Store; | 
|  |  | 
|  | if (Subtarget->hasMVEIntegerOps()) | 
|  | if (SDValue NewToken = PerformSplittingToNarrowingStores(St, DCI.DAG)) | 
|  | return NewToken; | 
|  |  | 
|  | if (!ISD::isNormalStore(St)) | 
|  | return SDValue(); | 
|  |  | 
|  | // Split a store of a VMOVDRR into two integer stores to avoid mixing NEON and | 
|  | // ARM stores of arguments in the same cache line. | 
|  | if (StVal.getNode()->getOpcode() == ARMISD::VMOVDRR && | 
|  | StVal.getNode()->hasOneUse()) { | 
|  | SelectionDAG  &DAG = DCI.DAG; | 
|  | bool isBigEndian = DAG.getDataLayout().isBigEndian(); | 
|  | SDLoc DL(St); | 
|  | SDValue BasePtr = St->getBasePtr(); | 
|  | SDValue NewST1 = DAG.getStore( | 
|  | St->getChain(), DL, StVal.getNode()->getOperand(isBigEndian ? 1 : 0), | 
|  | BasePtr, St->getPointerInfo(), St->getAlignment(), | 
|  | St->getMemOperand()->getFlags()); | 
|  |  | 
|  | SDValue OffsetPtr = DAG.getNode(ISD::ADD, DL, MVT::i32, BasePtr, | 
|  | DAG.getConstant(4, DL, MVT::i32)); | 
|  | return DAG.getStore(NewST1.getValue(0), DL, | 
|  | StVal.getNode()->getOperand(isBigEndian ? 0 : 1), | 
|  | OffsetPtr, St->getPointerInfo(), | 
|  | std::min(4U, St->getAlignment() / 2), | 
|  | St->getMemOperand()->getFlags()); | 
|  | } | 
|  |  | 
|  | if (StVal.getValueType() == MVT::i64 && | 
|  | StVal.getNode()->getOpcode() == ISD::EXTRACT_VECTOR_ELT) { | 
|  |  | 
|  | // Bitcast an i64 store extracted from a vector to f64. | 
|  | // Otherwise, the i64 value will be legalized to a pair of i32 values. | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDLoc dl(StVal); | 
|  | SDValue IntVec = StVal.getOperand(0); | 
|  | EVT FloatVT = EVT::getVectorVT(*DAG.getContext(), MVT::f64, | 
|  | IntVec.getValueType().getVectorNumElements()); | 
|  | SDValue Vec = DAG.getNode(ISD::BITCAST, dl, FloatVT, IntVec); | 
|  | SDValue ExtElt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, | 
|  | Vec, StVal.getOperand(1)); | 
|  | dl = SDLoc(N); | 
|  | SDValue V = DAG.getNode(ISD::BITCAST, dl, MVT::i64, ExtElt); | 
|  | // Make the DAGCombiner fold the bitcasts. | 
|  | DCI.AddToWorklist(Vec.getNode()); | 
|  | DCI.AddToWorklist(ExtElt.getNode()); | 
|  | DCI.AddToWorklist(V.getNode()); | 
|  | return DAG.getStore(St->getChain(), dl, V, St->getBasePtr(), | 
|  | St->getPointerInfo(), St->getAlignment(), | 
|  | St->getMemOperand()->getFlags(), St->getAAInfo()); | 
|  | } | 
|  |  | 
|  | // If this is a legal vector store, try to combine it into a VST1_UPD. | 
|  | if (Subtarget->hasNEON() && ISD::isNormalStore(N) && VT.isVector() && | 
|  | DCI.DAG.getTargetLoweringInfo().isTypeLegal(VT)) | 
|  | return CombineBaseUpdate(N, DCI); | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// PerformVCVTCombine - VCVT (floating-point to fixed-point, Advanced SIMD) | 
|  | /// can replace combinations of VMUL and VCVT (floating-point to integer) | 
|  | /// when the VMUL has a constant operand that is a power of 2. | 
|  | /// | 
|  | /// Example (assume d17 = <float 8.000000e+00, float 8.000000e+00>): | 
|  | ///  vmul.f32        d16, d17, d16 | 
|  | ///  vcvt.s32.f32    d16, d16 | 
|  | /// becomes: | 
|  | ///  vcvt.s32.f32    d16, d16, #3 | 
|  | static SDValue PerformVCVTCombine(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (!Subtarget->hasNEON()) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue Op = N->getOperand(0); | 
|  | if (!Op.getValueType().isVector() || !Op.getValueType().isSimple() || | 
|  | Op.getOpcode() != ISD::FMUL) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue ConstVec = Op->getOperand(1); | 
|  | if (!isa<BuildVectorSDNode>(ConstVec)) | 
|  | return SDValue(); | 
|  |  | 
|  | MVT FloatTy = Op.getSimpleValueType().getVectorElementType(); | 
|  | uint32_t FloatBits = FloatTy.getSizeInBits(); | 
|  | MVT IntTy = N->getSimpleValueType(0).getVectorElementType(); | 
|  | uint32_t IntBits = IntTy.getSizeInBits(); | 
|  | unsigned NumLanes = Op.getValueType().getVectorNumElements(); | 
|  | if (FloatBits != 32 || IntBits > 32 || (NumLanes != 4 && NumLanes != 2)) { | 
|  | // These instructions only exist converting from f32 to i32. We can handle | 
|  | // smaller integers by generating an extra truncate, but larger ones would | 
|  | // be lossy. We also can't handle anything other than 2 or 4 lanes, since | 
|  | // these intructions only support v2i32/v4i32 types. | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | BitVector UndefElements; | 
|  | BuildVectorSDNode *BV = cast<BuildVectorSDNode>(ConstVec); | 
|  | int32_t C = BV->getConstantFPSplatPow2ToLog2Int(&UndefElements, 33); | 
|  | if (C == -1 || C == 0 || C > 32) | 
|  | return SDValue(); | 
|  |  | 
|  | SDLoc dl(N); | 
|  | bool isSigned = N->getOpcode() == ISD::FP_TO_SINT; | 
|  | unsigned IntrinsicOpcode = isSigned ? Intrinsic::arm_neon_vcvtfp2fxs : | 
|  | Intrinsic::arm_neon_vcvtfp2fxu; | 
|  | SDValue FixConv = DAG.getNode( | 
|  | ISD::INTRINSIC_WO_CHAIN, dl, NumLanes == 2 ? MVT::v2i32 : MVT::v4i32, | 
|  | DAG.getConstant(IntrinsicOpcode, dl, MVT::i32), Op->getOperand(0), | 
|  | DAG.getConstant(C, dl, MVT::i32)); | 
|  |  | 
|  | if (IntBits < FloatBits) | 
|  | FixConv = DAG.getNode(ISD::TRUNCATE, dl, N->getValueType(0), FixConv); | 
|  |  | 
|  | return FixConv; | 
|  | } | 
|  |  | 
|  | /// PerformVDIVCombine - VCVT (fixed-point to floating-point, Advanced SIMD) | 
|  | /// can replace combinations of VCVT (integer to floating-point) and VDIV | 
|  | /// when the VDIV has a constant operand that is a power of 2. | 
|  | /// | 
|  | /// Example (assume d17 = <float 8.000000e+00, float 8.000000e+00>): | 
|  | ///  vcvt.f32.s32    d16, d16 | 
|  | ///  vdiv.f32        d16, d17, d16 | 
|  | /// becomes: | 
|  | ///  vcvt.f32.s32    d16, d16, #3 | 
|  | static SDValue PerformVDIVCombine(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (!Subtarget->hasNEON()) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue Op = N->getOperand(0); | 
|  | unsigned OpOpcode = Op.getNode()->getOpcode(); | 
|  | if (!N->getValueType(0).isVector() || !N->getValueType(0).isSimple() || | 
|  | (OpOpcode != ISD::SINT_TO_FP && OpOpcode != ISD::UINT_TO_FP)) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue ConstVec = N->getOperand(1); | 
|  | if (!isa<BuildVectorSDNode>(ConstVec)) | 
|  | return SDValue(); | 
|  |  | 
|  | MVT FloatTy = N->getSimpleValueType(0).getVectorElementType(); | 
|  | uint32_t FloatBits = FloatTy.getSizeInBits(); | 
|  | MVT IntTy = Op.getOperand(0).getSimpleValueType().getVectorElementType(); | 
|  | uint32_t IntBits = IntTy.getSizeInBits(); | 
|  | unsigned NumLanes = Op.getValueType().getVectorNumElements(); | 
|  | if (FloatBits != 32 || IntBits > 32 || (NumLanes != 4 && NumLanes != 2)) { | 
|  | // These instructions only exist converting from i32 to f32. We can handle | 
|  | // smaller integers by generating an extra extend, but larger ones would | 
|  | // be lossy. We also can't handle anything other than 2 or 4 lanes, since | 
|  | // these intructions only support v2i32/v4i32 types. | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | BitVector UndefElements; | 
|  | BuildVectorSDNode *BV = cast<BuildVectorSDNode>(ConstVec); | 
|  | int32_t C = BV->getConstantFPSplatPow2ToLog2Int(&UndefElements, 33); | 
|  | if (C == -1 || C == 0 || C > 32) | 
|  | return SDValue(); | 
|  |  | 
|  | SDLoc dl(N); | 
|  | bool isSigned = OpOpcode == ISD::SINT_TO_FP; | 
|  | SDValue ConvInput = Op.getOperand(0); | 
|  | if (IntBits < FloatBits) | 
|  | ConvInput = DAG.getNode(isSigned ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND, | 
|  | dl, NumLanes == 2 ? MVT::v2i32 : MVT::v4i32, | 
|  | ConvInput); | 
|  |  | 
|  | unsigned IntrinsicOpcode = isSigned ? Intrinsic::arm_neon_vcvtfxs2fp : | 
|  | Intrinsic::arm_neon_vcvtfxu2fp; | 
|  | return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, | 
|  | Op.getValueType(), | 
|  | DAG.getConstant(IntrinsicOpcode, dl, MVT::i32), | 
|  | ConvInput, DAG.getConstant(C, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | static SDValue PerformVECREDUCE_ADDCombine(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | if (!ST->hasMVEIntegerOps()) | 
|  | return SDValue(); | 
|  |  | 
|  | assert(N->getOpcode() == ISD::VECREDUCE_ADD); | 
|  | EVT ResVT = N->getValueType(0); | 
|  | SDValue N0 = N->getOperand(0); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // We are looking for something that will have illegal types if left alone, | 
|  | // but that we can convert to a single instruction undef MVE. For example | 
|  | // vecreduce_add(sext(A, v8i32)) => VADDV.s16 A | 
|  | // or | 
|  | // vecreduce_add(mul(zext(A, v16i32), zext(B, v16i32))) => VMLADAV.u8 A, B | 
|  |  | 
|  | // Cases: | 
|  | //   VADDV u/s 8/16/32 | 
|  | //   VMLAV u/s 8/16/32 | 
|  | //   VADDLV u/s 32 | 
|  | //   VMLALV u/s 16/32 | 
|  |  | 
|  | auto IsVADDV = [&](MVT RetTy, unsigned ExtendCode, ArrayRef<MVT> ExtTypes) { | 
|  | if (ResVT != RetTy || N0->getOpcode() != ExtendCode) | 
|  | return SDValue(); | 
|  | SDValue A = N0->getOperand(0); | 
|  | if (llvm::any_of(ExtTypes, [&A](MVT Ty) { return A.getValueType() == Ty; })) | 
|  | return A; | 
|  | return SDValue(); | 
|  | }; | 
|  | auto IsVMLAV = [&](MVT RetTy, unsigned ExtendCode, ArrayRef<MVT> ExtTypes, | 
|  | SDValue &A, SDValue &B) { | 
|  | if (ResVT != RetTy || N0->getOpcode() != ISD::MUL) | 
|  | return false; | 
|  | SDValue ExtA = N0->getOperand(0); | 
|  | SDValue ExtB = N0->getOperand(1); | 
|  | if (ExtA->getOpcode() != ExtendCode && ExtB->getOpcode() != ExtendCode) | 
|  | return false; | 
|  | A = ExtA->getOperand(0); | 
|  | B = ExtB->getOperand(0); | 
|  | if (A.getValueType() == B.getValueType() && | 
|  | llvm::any_of(ExtTypes, [&A](MVT Ty) { return A.getValueType() == Ty; })) | 
|  | return true; | 
|  | return false; | 
|  | }; | 
|  | auto Create64bitNode = [&](unsigned Opcode, ArrayRef<SDValue> Ops) { | 
|  | SDValue Node = DAG.getNode(Opcode, dl, {MVT::i32, MVT::i32}, Ops); | 
|  | return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Node, | 
|  | SDValue(Node.getNode(), 1)); | 
|  | }; | 
|  |  | 
|  | if (SDValue A = IsVADDV(MVT::i32, ISD::SIGN_EXTEND, {MVT::v8i16, MVT::v16i8})) | 
|  | return DAG.getNode(ARMISD::VADDVs, dl, ResVT, A); | 
|  | if (SDValue A = IsVADDV(MVT::i32, ISD::ZERO_EXTEND, {MVT::v8i16, MVT::v16i8})) | 
|  | return DAG.getNode(ARMISD::VADDVu, dl, ResVT, A); | 
|  | if (SDValue A = IsVADDV(MVT::i64, ISD::SIGN_EXTEND, {MVT::v4i32})) | 
|  | return Create64bitNode(ARMISD::VADDLVs, {A}); | 
|  | if (SDValue A = IsVADDV(MVT::i64, ISD::ZERO_EXTEND, {MVT::v4i32})) | 
|  | return Create64bitNode(ARMISD::VADDLVu, {A}); | 
|  |  | 
|  | SDValue A, B; | 
|  | if (IsVMLAV(MVT::i32, ISD::SIGN_EXTEND, {MVT::v8i16, MVT::v16i8}, A, B)) | 
|  | return DAG.getNode(ARMISD::VMLAVs, dl, ResVT, A, B); | 
|  | if (IsVMLAV(MVT::i32, ISD::ZERO_EXTEND, {MVT::v8i16, MVT::v16i8}, A, B)) | 
|  | return DAG.getNode(ARMISD::VMLAVu, dl, ResVT, A, B); | 
|  | if (IsVMLAV(MVT::i64, ISD::SIGN_EXTEND, {MVT::v8i16, MVT::v4i32}, A, B)) | 
|  | return Create64bitNode(ARMISD::VMLALVs, {A, B}); | 
|  | if (IsVMLAV(MVT::i64, ISD::ZERO_EXTEND, {MVT::v8i16, MVT::v4i32}, A, B)) | 
|  | return Create64bitNode(ARMISD::VMLALVu, {A, B}); | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformVMOVNCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | SDValue Op0 = N->getOperand(0); | 
|  | SDValue Op1 = N->getOperand(1); | 
|  | unsigned IsTop = N->getConstantOperandVal(2); | 
|  |  | 
|  | // VMOVNt(c, VQMOVNb(a, b)) => VQMOVNt(c, b) | 
|  | // VMOVNb(c, VQMOVNb(a, b)) => VQMOVNb(c, b) | 
|  | if ((Op1->getOpcode() == ARMISD::VQMOVNs || | 
|  | Op1->getOpcode() == ARMISD::VQMOVNu) && | 
|  | Op1->getConstantOperandVal(2) == 0) | 
|  | return DCI.DAG.getNode(Op1->getOpcode(), SDLoc(Op1), N->getValueType(0), | 
|  | Op0, Op1->getOperand(1), N->getOperand(2)); | 
|  |  | 
|  | // Only the bottom lanes from Qm (Op1) and either the top or bottom lanes from | 
|  | // Qd (Op0) are demanded from a VMOVN, depending on whether we are inserting | 
|  | // into the top or bottom lanes. | 
|  | unsigned NumElts = N->getValueType(0).getVectorNumElements(); | 
|  | APInt Op1DemandedElts = APInt::getSplat(NumElts, APInt::getLowBitsSet(2, 1)); | 
|  | APInt Op0DemandedElts = | 
|  | IsTop ? Op1DemandedElts | 
|  | : APInt::getSplat(NumElts, APInt::getHighBitsSet(2, 1)); | 
|  |  | 
|  | APInt KnownUndef, KnownZero; | 
|  | const TargetLowering &TLI = DCI.DAG.getTargetLoweringInfo(); | 
|  | if (TLI.SimplifyDemandedVectorElts(Op0, Op0DemandedElts, KnownUndef, | 
|  | KnownZero, DCI)) | 
|  | return SDValue(N, 0); | 
|  | if (TLI.SimplifyDemandedVectorElts(Op1, Op1DemandedElts, KnownUndef, | 
|  | KnownZero, DCI)) | 
|  | return SDValue(N, 0); | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformVQMOVNCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI) { | 
|  | SDValue Op0 = N->getOperand(0); | 
|  | unsigned IsTop = N->getConstantOperandVal(2); | 
|  |  | 
|  | unsigned NumElts = N->getValueType(0).getVectorNumElements(); | 
|  | APInt Op0DemandedElts = | 
|  | APInt::getSplat(NumElts, IsTop ? APInt::getLowBitsSet(2, 1) | 
|  | : APInt::getHighBitsSet(2, 1)); | 
|  |  | 
|  | APInt KnownUndef, KnownZero; | 
|  | const TargetLowering &TLI = DCI.DAG.getTargetLoweringInfo(); | 
|  | if (TLI.SimplifyDemandedVectorElts(Op0, Op0DemandedElts, KnownUndef, | 
|  | KnownZero, DCI)) | 
|  | return SDValue(N, 0); | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformLongShiftCombine(SDNode *N, SelectionDAG &DAG) { | 
|  | SDLoc DL(N); | 
|  | SDValue Op0 = N->getOperand(0); | 
|  | SDValue Op1 = N->getOperand(1); | 
|  |  | 
|  | // Turn X << -C -> X >> C and viceversa. The negative shifts can come up from | 
|  | // uses of the intrinsics. | 
|  | if (auto C = dyn_cast<ConstantSDNode>(N->getOperand(2))) { | 
|  | int ShiftAmt = C->getSExtValue(); | 
|  | if (ShiftAmt == 0) { | 
|  | SDValue Merge = DAG.getMergeValues({Op0, Op1}, DL); | 
|  | DAG.ReplaceAllUsesWith(N, Merge.getNode()); | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | if (ShiftAmt >= -32 && ShiftAmt < 0) { | 
|  | unsigned NewOpcode = | 
|  | N->getOpcode() == ARMISD::LSLL ? ARMISD::LSRL : ARMISD::LSLL; | 
|  | SDValue NewShift = DAG.getNode(NewOpcode, DL, N->getVTList(), Op0, Op1, | 
|  | DAG.getConstant(-ShiftAmt, DL, MVT::i32)); | 
|  | DAG.ReplaceAllUsesWith(N, NewShift.getNode()); | 
|  | return NewShift; | 
|  | } | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// PerformIntrinsicCombine - ARM-specific DAG combining for intrinsics. | 
|  | SDValue ARMTargetLowering::PerformIntrinsicCombine(SDNode *N, | 
|  | DAGCombinerInfo &DCI) const { | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | unsigned IntNo = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue(); | 
|  | switch (IntNo) { | 
|  | default: | 
|  | // Don't do anything for most intrinsics. | 
|  | break; | 
|  |  | 
|  | // Vector shifts: check for immediate versions and lower them. | 
|  | // Note: This is done during DAG combining instead of DAG legalizing because | 
|  | // the build_vectors for 64-bit vector element shift counts are generally | 
|  | // not legal, and it is hard to see their values after they get legalized to | 
|  | // loads from a constant pool. | 
|  | case Intrinsic::arm_neon_vshifts: | 
|  | case Intrinsic::arm_neon_vshiftu: | 
|  | case Intrinsic::arm_neon_vrshifts: | 
|  | case Intrinsic::arm_neon_vrshiftu: | 
|  | case Intrinsic::arm_neon_vrshiftn: | 
|  | case Intrinsic::arm_neon_vqshifts: | 
|  | case Intrinsic::arm_neon_vqshiftu: | 
|  | case Intrinsic::arm_neon_vqshiftsu: | 
|  | case Intrinsic::arm_neon_vqshiftns: | 
|  | case Intrinsic::arm_neon_vqshiftnu: | 
|  | case Intrinsic::arm_neon_vqshiftnsu: | 
|  | case Intrinsic::arm_neon_vqrshiftns: | 
|  | case Intrinsic::arm_neon_vqrshiftnu: | 
|  | case Intrinsic::arm_neon_vqrshiftnsu: { | 
|  | EVT VT = N->getOperand(1).getValueType(); | 
|  | int64_t Cnt; | 
|  | unsigned VShiftOpc = 0; | 
|  |  | 
|  | switch (IntNo) { | 
|  | case Intrinsic::arm_neon_vshifts: | 
|  | case Intrinsic::arm_neon_vshiftu: | 
|  | if (isVShiftLImm(N->getOperand(2), VT, false, Cnt)) { | 
|  | VShiftOpc = ARMISD::VSHLIMM; | 
|  | break; | 
|  | } | 
|  | if (isVShiftRImm(N->getOperand(2), VT, false, true, Cnt)) { | 
|  | VShiftOpc = (IntNo == Intrinsic::arm_neon_vshifts ? ARMISD::VSHRsIMM | 
|  | : ARMISD::VSHRuIMM); | 
|  | break; | 
|  | } | 
|  | return SDValue(); | 
|  |  | 
|  | case Intrinsic::arm_neon_vrshifts: | 
|  | case Intrinsic::arm_neon_vrshiftu: | 
|  | if (isVShiftRImm(N->getOperand(2), VT, false, true, Cnt)) | 
|  | break; | 
|  | return SDValue(); | 
|  |  | 
|  | case Intrinsic::arm_neon_vqshifts: | 
|  | case Intrinsic::arm_neon_vqshiftu: | 
|  | if (isVShiftLImm(N->getOperand(2), VT, false, Cnt)) | 
|  | break; | 
|  | return SDValue(); | 
|  |  | 
|  | case Intrinsic::arm_neon_vqshiftsu: | 
|  | if (isVShiftLImm(N->getOperand(2), VT, false, Cnt)) | 
|  | break; | 
|  | llvm_unreachable("invalid shift count for vqshlu intrinsic"); | 
|  |  | 
|  | case Intrinsic::arm_neon_vrshiftn: | 
|  | case Intrinsic::arm_neon_vqshiftns: | 
|  | case Intrinsic::arm_neon_vqshiftnu: | 
|  | case Intrinsic::arm_neon_vqshiftnsu: | 
|  | case Intrinsic::arm_neon_vqrshiftns: | 
|  | case Intrinsic::arm_neon_vqrshiftnu: | 
|  | case Intrinsic::arm_neon_vqrshiftnsu: | 
|  | // Narrowing shifts require an immediate right shift. | 
|  | if (isVShiftRImm(N->getOperand(2), VT, true, true, Cnt)) | 
|  | break; | 
|  | llvm_unreachable("invalid shift count for narrowing vector shift " | 
|  | "intrinsic"); | 
|  |  | 
|  | default: | 
|  | llvm_unreachable("unhandled vector shift"); | 
|  | } | 
|  |  | 
|  | switch (IntNo) { | 
|  | case Intrinsic::arm_neon_vshifts: | 
|  | case Intrinsic::arm_neon_vshiftu: | 
|  | // Opcode already set above. | 
|  | break; | 
|  | case Intrinsic::arm_neon_vrshifts: | 
|  | VShiftOpc = ARMISD::VRSHRsIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vrshiftu: | 
|  | VShiftOpc = ARMISD::VRSHRuIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vrshiftn: | 
|  | VShiftOpc = ARMISD::VRSHRNIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vqshifts: | 
|  | VShiftOpc = ARMISD::VQSHLsIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vqshiftu: | 
|  | VShiftOpc = ARMISD::VQSHLuIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vqshiftsu: | 
|  | VShiftOpc = ARMISD::VQSHLsuIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vqshiftns: | 
|  | VShiftOpc = ARMISD::VQSHRNsIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vqshiftnu: | 
|  | VShiftOpc = ARMISD::VQSHRNuIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vqshiftnsu: | 
|  | VShiftOpc = ARMISD::VQSHRNsuIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vqrshiftns: | 
|  | VShiftOpc = ARMISD::VQRSHRNsIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vqrshiftnu: | 
|  | VShiftOpc = ARMISD::VQRSHRNuIMM; | 
|  | break; | 
|  | case Intrinsic::arm_neon_vqrshiftnsu: | 
|  | VShiftOpc = ARMISD::VQRSHRNsuIMM; | 
|  | break; | 
|  | } | 
|  |  | 
|  | SDLoc dl(N); | 
|  | return DAG.getNode(VShiftOpc, dl, N->getValueType(0), | 
|  | N->getOperand(1), DAG.getConstant(Cnt, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | case Intrinsic::arm_neon_vshiftins: { | 
|  | EVT VT = N->getOperand(1).getValueType(); | 
|  | int64_t Cnt; | 
|  | unsigned VShiftOpc = 0; | 
|  |  | 
|  | if (isVShiftLImm(N->getOperand(3), VT, false, Cnt)) | 
|  | VShiftOpc = ARMISD::VSLIIMM; | 
|  | else if (isVShiftRImm(N->getOperand(3), VT, false, true, Cnt)) | 
|  | VShiftOpc = ARMISD::VSRIIMM; | 
|  | else { | 
|  | llvm_unreachable("invalid shift count for vsli/vsri intrinsic"); | 
|  | } | 
|  |  | 
|  | SDLoc dl(N); | 
|  | return DAG.getNode(VShiftOpc, dl, N->getValueType(0), | 
|  | N->getOperand(1), N->getOperand(2), | 
|  | DAG.getConstant(Cnt, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | case Intrinsic::arm_neon_vqrshifts: | 
|  | case Intrinsic::arm_neon_vqrshiftu: | 
|  | // No immediate versions of these to check for. | 
|  | break; | 
|  |  | 
|  | case Intrinsic::arm_mve_vqdmlah: | 
|  | case Intrinsic::arm_mve_vqdmlash: | 
|  | case Intrinsic::arm_mve_vqrdmlah: | 
|  | case Intrinsic::arm_mve_vqrdmlash: | 
|  | case Intrinsic::arm_mve_vmla_n_predicated: | 
|  | case Intrinsic::arm_mve_vmlas_n_predicated: | 
|  | case Intrinsic::arm_mve_vqdmlah_predicated: | 
|  | case Intrinsic::arm_mve_vqdmlash_predicated: | 
|  | case Intrinsic::arm_mve_vqrdmlah_predicated: | 
|  | case Intrinsic::arm_mve_vqrdmlash_predicated: { | 
|  | // These intrinsics all take an i32 scalar operand which is narrowed to the | 
|  | // size of a single lane of the vector type they return. So we don't need | 
|  | // any bits of that operand above that point, which allows us to eliminate | 
|  | // uxth/sxth. | 
|  | unsigned BitWidth = N->getValueType(0).getScalarSizeInBits(); | 
|  | APInt DemandedMask = APInt::getLowBitsSet(32, BitWidth); | 
|  | if (SimplifyDemandedBits(N->getOperand(3), DemandedMask, DCI)) | 
|  | return SDValue(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case Intrinsic::arm_mve_minv: | 
|  | case Intrinsic::arm_mve_maxv: | 
|  | case Intrinsic::arm_mve_minav: | 
|  | case Intrinsic::arm_mve_maxav: | 
|  | case Intrinsic::arm_mve_minv_predicated: | 
|  | case Intrinsic::arm_mve_maxv_predicated: | 
|  | case Intrinsic::arm_mve_minav_predicated: | 
|  | case Intrinsic::arm_mve_maxav_predicated: { | 
|  | // These intrinsics all take an i32 scalar operand which is narrowed to the | 
|  | // size of a single lane of the vector type they take as the other input. | 
|  | unsigned BitWidth = N->getOperand(2)->getValueType(0).getScalarSizeInBits(); | 
|  | APInt DemandedMask = APInt::getLowBitsSet(32, BitWidth); | 
|  | if (SimplifyDemandedBits(N->getOperand(1), DemandedMask, DCI)) | 
|  | return SDValue(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | case Intrinsic::arm_mve_addv: { | 
|  | // Turn this intrinsic straight into the appropriate ARMISD::VADDV node, | 
|  | // which allow PerformADDVecReduce to turn it into VADDLV when possible. | 
|  | bool Unsigned = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(); | 
|  | unsigned Opc = Unsigned ? ARMISD::VADDVu : ARMISD::VADDVs; | 
|  | return DAG.getNode(Opc, SDLoc(N), N->getVTList(), N->getOperand(1)); | 
|  | } | 
|  |  | 
|  | case Intrinsic::arm_mve_addlv: | 
|  | case Intrinsic::arm_mve_addlv_predicated: { | 
|  | // Same for these, but ARMISD::VADDLV has to be followed by a BUILD_PAIR | 
|  | // which recombines the two outputs into an i64 | 
|  | bool Unsigned = cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(); | 
|  | unsigned Opc = IntNo == Intrinsic::arm_mve_addlv ? | 
|  | (Unsigned ? ARMISD::VADDLVu : ARMISD::VADDLVs) : | 
|  | (Unsigned ? ARMISD::VADDLVpu : ARMISD::VADDLVps); | 
|  |  | 
|  | SmallVector<SDValue, 4> Ops; | 
|  | for (unsigned i = 1, e = N->getNumOperands(); i < e; i++) | 
|  | if (i != 2)                      // skip the unsigned flag | 
|  | Ops.push_back(N->getOperand(i)); | 
|  |  | 
|  | SDLoc dl(N); | 
|  | SDValue val = DAG.getNode(Opc, dl, {MVT::i32, MVT::i32}, Ops); | 
|  | return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, val.getValue(0), | 
|  | val.getValue(1)); | 
|  | } | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// PerformShiftCombine - Checks for immediate versions of vector shifts and | 
|  | /// lowers them.  As with the vector shift intrinsics, this is done during DAG | 
|  | /// combining instead of DAG legalizing because the build_vectors for 64-bit | 
|  | /// vector element shift counts are generally not legal, and it is hard to see | 
|  | /// their values after they get legalized to loads from a constant pool. | 
|  | static SDValue PerformShiftCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *ST) { | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | EVT VT = N->getValueType(0); | 
|  | if (N->getOpcode() == ISD::SRL && VT == MVT::i32 && ST->hasV6Ops()) { | 
|  | // Canonicalize (srl (bswap x), 16) to (rotr (bswap x), 16) if the high | 
|  | // 16-bits of x is zero. This optimizes rev + lsr 16 to rev16. | 
|  | SDValue N1 = N->getOperand(1); | 
|  | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N1)) { | 
|  | SDValue N0 = N->getOperand(0); | 
|  | if (C->getZExtValue() == 16 && N0.getOpcode() == ISD::BSWAP && | 
|  | DAG.MaskedValueIsZero(N0.getOperand(0), | 
|  | APInt::getHighBitsSet(32, 16))) | 
|  | return DAG.getNode(ISD::ROTR, SDLoc(N), VT, N0, N1); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ST->isThumb1Only() && N->getOpcode() == ISD::SHL && VT == MVT::i32 && | 
|  | N->getOperand(0)->getOpcode() == ISD::AND && | 
|  | N->getOperand(0)->hasOneUse()) { | 
|  | if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer()) | 
|  | return SDValue(); | 
|  | // Look for the pattern (shl (and x, AndMask), ShiftAmt). This doesn't | 
|  | // usually show up because instcombine prefers to canonicalize it to | 
|  | // (and (shl x, ShiftAmt) (shl AndMask, ShiftAmt)), but the shift can come | 
|  | // out of GEP lowering in some cases. | 
|  | SDValue N0 = N->getOperand(0); | 
|  | ConstantSDNode *ShiftAmtNode = dyn_cast<ConstantSDNode>(N->getOperand(1)); | 
|  | if (!ShiftAmtNode) | 
|  | return SDValue(); | 
|  | uint32_t ShiftAmt = static_cast<uint32_t>(ShiftAmtNode->getZExtValue()); | 
|  | ConstantSDNode *AndMaskNode = dyn_cast<ConstantSDNode>(N0->getOperand(1)); | 
|  | if (!AndMaskNode) | 
|  | return SDValue(); | 
|  | uint32_t AndMask = static_cast<uint32_t>(AndMaskNode->getZExtValue()); | 
|  | // Don't transform uxtb/uxth. | 
|  | if (AndMask == 255 || AndMask == 65535) | 
|  | return SDValue(); | 
|  | if (isMask_32(AndMask)) { | 
|  | uint32_t MaskedBits = countLeadingZeros(AndMask); | 
|  | if (MaskedBits > ShiftAmt) { | 
|  | SDLoc DL(N); | 
|  | SDValue SHL = DAG.getNode(ISD::SHL, DL, MVT::i32, N0->getOperand(0), | 
|  | DAG.getConstant(MaskedBits, DL, MVT::i32)); | 
|  | return DAG.getNode( | 
|  | ISD::SRL, DL, MVT::i32, SHL, | 
|  | DAG.getConstant(MaskedBits - ShiftAmt, DL, MVT::i32)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Nothing to be done for scalar shifts. | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | if (!VT.isVector() || !TLI.isTypeLegal(VT)) | 
|  | return SDValue(); | 
|  | if (ST->hasMVEIntegerOps() && VT == MVT::v2i64) | 
|  | return SDValue(); | 
|  |  | 
|  | int64_t Cnt; | 
|  |  | 
|  | switch (N->getOpcode()) { | 
|  | default: llvm_unreachable("unexpected shift opcode"); | 
|  |  | 
|  | case ISD::SHL: | 
|  | if (isVShiftLImm(N->getOperand(1), VT, false, Cnt)) { | 
|  | SDLoc dl(N); | 
|  | return DAG.getNode(ARMISD::VSHLIMM, dl, VT, N->getOperand(0), | 
|  | DAG.getConstant(Cnt, dl, MVT::i32)); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ISD::SRA: | 
|  | case ISD::SRL: | 
|  | if (isVShiftRImm(N->getOperand(1), VT, false, false, Cnt)) { | 
|  | unsigned VShiftOpc = | 
|  | (N->getOpcode() == ISD::SRA ? ARMISD::VSHRsIMM : ARMISD::VSHRuIMM); | 
|  | SDLoc dl(N); | 
|  | return DAG.getNode(VShiftOpc, dl, VT, N->getOperand(0), | 
|  | DAG.getConstant(Cnt, dl, MVT::i32)); | 
|  | } | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // Look for a sign/zero extend of a larger than legal load. This can be split | 
|  | // into two extending loads, which are simpler to deal with than an arbitrary | 
|  | // sign extend. | 
|  | static SDValue PerformSplittingToWideningLoad(SDNode *N, SelectionDAG &DAG) { | 
|  | SDValue N0 = N->getOperand(0); | 
|  | if (N0.getOpcode() != ISD::LOAD) | 
|  | return SDValue(); | 
|  | LoadSDNode *LD = cast<LoadSDNode>(N0.getNode()); | 
|  | if (!LD->isSimple() || !N0.hasOneUse() || LD->isIndexed() || | 
|  | LD->getExtensionType() != ISD::NON_EXTLOAD) | 
|  | return SDValue(); | 
|  | EVT FromVT = LD->getValueType(0); | 
|  | EVT ToVT = N->getValueType(0); | 
|  | if (!ToVT.isVector()) | 
|  | return SDValue(); | 
|  | assert(FromVT.getVectorNumElements() == ToVT.getVectorNumElements()); | 
|  | EVT ToEltVT = ToVT.getVectorElementType(); | 
|  | EVT FromEltVT = FromVT.getVectorElementType(); | 
|  |  | 
|  | unsigned NumElements = 0; | 
|  | if (ToEltVT == MVT::i32 && (FromEltVT == MVT::i16 || FromEltVT == MVT::i8)) | 
|  | NumElements = 4; | 
|  | if (ToEltVT == MVT::i16 && FromEltVT == MVT::i8) | 
|  | NumElements = 8; | 
|  | if (NumElements == 0 || | 
|  | FromVT.getVectorNumElements() == NumElements || | 
|  | FromVT.getVectorNumElements() % NumElements != 0 || | 
|  | !isPowerOf2_32(NumElements)) | 
|  | return SDValue(); | 
|  |  | 
|  | SDLoc DL(LD); | 
|  | // Details about the old load | 
|  | SDValue Ch = LD->getChain(); | 
|  | SDValue BasePtr = LD->getBasePtr(); | 
|  | Align Alignment = LD->getOriginalAlign(); | 
|  | MachineMemOperand::Flags MMOFlags = LD->getMemOperand()->getFlags(); | 
|  | AAMDNodes AAInfo = LD->getAAInfo(); | 
|  |  | 
|  | ISD::LoadExtType NewExtType = | 
|  | N->getOpcode() == ISD::SIGN_EXTEND ? ISD::SEXTLOAD : ISD::ZEXTLOAD; | 
|  | SDValue Offset = DAG.getUNDEF(BasePtr.getValueType()); | 
|  | EVT NewFromVT = FromVT.getHalfNumVectorElementsVT(*DAG.getContext()); | 
|  | EVT NewToVT = ToVT.getHalfNumVectorElementsVT(*DAG.getContext()); | 
|  | unsigned NewOffset = NewFromVT.getSizeInBits() / 8; | 
|  | SDValue NewPtr = DAG.getObjectPtrOffset(DL, BasePtr, NewOffset); | 
|  |  | 
|  | // Split the load in half, each side of which is extended separately. This | 
|  | // is good enough, as legalisation will take it from there. They are either | 
|  | // already legal or they will be split further into something that is | 
|  | // legal. | 
|  | SDValue NewLoad1 = DAG.getLoad( | 
|  | ISD::UNINDEXED, NewExtType, NewToVT, DL, Ch, BasePtr, Offset, | 
|  | LD->getPointerInfo(), NewFromVT, Alignment.value(), MMOFlags, AAInfo); | 
|  | SDValue NewLoad2 = | 
|  | DAG.getLoad(ISD::UNINDEXED, NewExtType, NewToVT, DL, Ch, NewPtr, Offset, | 
|  | LD->getPointerInfo().getWithOffset(NewOffset), NewFromVT, | 
|  | Alignment.value(), MMOFlags, AAInfo); | 
|  |  | 
|  | SDValue NewChain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, | 
|  | SDValue(NewLoad1.getNode(), 1), | 
|  | SDValue(NewLoad2.getNode(), 1)); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(LD, 1), NewChain); | 
|  | return DAG.getNode(ISD::CONCAT_VECTORS, DL, ToVT, NewLoad1, NewLoad2); | 
|  | } | 
|  |  | 
|  | /// PerformExtendCombine - Target-specific DAG combining for ISD::SIGN_EXTEND, | 
|  | /// ISD::ZERO_EXTEND, and ISD::ANY_EXTEND. | 
|  | static SDValue PerformExtendCombine(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | SDValue N0 = N->getOperand(0); | 
|  |  | 
|  | // Check for sign- and zero-extensions of vector extract operations of 8- and | 
|  | // 16-bit vector elements. NEON and MVE support these directly. They are | 
|  | // handled during DAG combining because type legalization will promote them | 
|  | // to 32-bit types and it is messy to recognize the operations after that. | 
|  | if ((ST->hasNEON() || ST->hasMVEIntegerOps()) && | 
|  | N0.getOpcode() == ISD::EXTRACT_VECTOR_ELT) { | 
|  | SDValue Vec = N0.getOperand(0); | 
|  | SDValue Lane = N0.getOperand(1); | 
|  | EVT VT = N->getValueType(0); | 
|  | EVT EltVT = N0.getValueType(); | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  |  | 
|  | if (VT == MVT::i32 && | 
|  | (EltVT == MVT::i8 || EltVT == MVT::i16) && | 
|  | TLI.isTypeLegal(Vec.getValueType()) && | 
|  | isa<ConstantSDNode>(Lane)) { | 
|  |  | 
|  | unsigned Opc = 0; | 
|  | switch (N->getOpcode()) { | 
|  | default: llvm_unreachable("unexpected opcode"); | 
|  | case ISD::SIGN_EXTEND: | 
|  | Opc = ARMISD::VGETLANEs; | 
|  | break; | 
|  | case ISD::ZERO_EXTEND: | 
|  | case ISD::ANY_EXTEND: | 
|  | Opc = ARMISD::VGETLANEu; | 
|  | break; | 
|  | } | 
|  | return DAG.getNode(Opc, SDLoc(N), VT, Vec, Lane); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ST->hasMVEIntegerOps()) | 
|  | if (SDValue NewLoad = PerformSplittingToWideningLoad(N, DAG)) | 
|  | return NewLoad; | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// PerformMinMaxCombine - Target-specific DAG combining for creating truncating | 
|  | /// saturates. | 
|  | static SDValue PerformMinMaxCombine(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | EVT VT = N->getValueType(0); | 
|  | SDValue N0 = N->getOperand(0); | 
|  | if (!ST->hasMVEIntegerOps()) | 
|  | return SDValue(); | 
|  |  | 
|  | if (VT != MVT::v4i32 && VT != MVT::v8i16) | 
|  | return SDValue(); | 
|  |  | 
|  | auto IsSignedSaturate = [&](SDNode *Min, SDNode *Max) { | 
|  | // Check one is a smin and the other is a smax | 
|  | if (Min->getOpcode() != ISD::SMIN) | 
|  | std::swap(Min, Max); | 
|  | if (Min->getOpcode() != ISD::SMIN || Max->getOpcode() != ISD::SMAX) | 
|  | return false; | 
|  |  | 
|  | APInt SaturateC; | 
|  | if (VT == MVT::v4i32) | 
|  | SaturateC = APInt(32, (1 << 15) - 1, true); | 
|  | else //if (VT == MVT::v8i16) | 
|  | SaturateC = APInt(16, (1 << 7) - 1, true); | 
|  |  | 
|  | APInt MinC, MaxC; | 
|  | if (!ISD::isConstantSplatVector(Min->getOperand(1).getNode(), MinC) || | 
|  | MinC != SaturateC) | 
|  | return false; | 
|  | if (!ISD::isConstantSplatVector(Max->getOperand(1).getNode(), MaxC) || | 
|  | MaxC != ~SaturateC) | 
|  | return false; | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | if (IsSignedSaturate(N, N0.getNode())) { | 
|  | SDLoc DL(N); | 
|  | MVT ExtVT, HalfVT; | 
|  | if (VT == MVT::v4i32) { | 
|  | HalfVT = MVT::v8i16; | 
|  | ExtVT = MVT::v4i16; | 
|  | } else { // if (VT == MVT::v8i16) | 
|  | HalfVT = MVT::v16i8; | 
|  | ExtVT = MVT::v8i8; | 
|  | } | 
|  |  | 
|  | // Create a VQMOVNB with undef top lanes, then signed extended into the top | 
|  | // half. That extend will hopefully be removed if only the bottom bits are | 
|  | // demanded (though a truncating store, for example). | 
|  | SDValue VQMOVN = | 
|  | DAG.getNode(ARMISD::VQMOVNs, DL, HalfVT, DAG.getUNDEF(HalfVT), | 
|  | N0->getOperand(0), DAG.getConstant(0, DL, MVT::i32)); | 
|  | SDValue Bitcast = DAG.getNode(ARMISD::VECTOR_REG_CAST, DL, VT, VQMOVN); | 
|  | return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, Bitcast, | 
|  | DAG.getValueType(ExtVT)); | 
|  | } | 
|  |  | 
|  | auto IsUnsignedSaturate = [&](SDNode *Min) { | 
|  | // For unsigned, we just need to check for <= 0xffff | 
|  | if (Min->getOpcode() != ISD::UMIN) | 
|  | return false; | 
|  |  | 
|  | APInt SaturateC; | 
|  | if (VT == MVT::v4i32) | 
|  | SaturateC = APInt(32, (1 << 16) - 1, true); | 
|  | else //if (VT == MVT::v8i16) | 
|  | SaturateC = APInt(16, (1 << 8) - 1, true); | 
|  |  | 
|  | APInt MinC; | 
|  | if (!ISD::isConstantSplatVector(Min->getOperand(1).getNode(), MinC) || | 
|  | MinC != SaturateC) | 
|  | return false; | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | if (IsUnsignedSaturate(N)) { | 
|  | SDLoc DL(N); | 
|  | MVT HalfVT; | 
|  | unsigned ExtConst; | 
|  | if (VT == MVT::v4i32) { | 
|  | HalfVT = MVT::v8i16; | 
|  | ExtConst = 0x0000FFFF; | 
|  | } else { //if (VT == MVT::v8i16) | 
|  | HalfVT = MVT::v16i8; | 
|  | ExtConst = 0x00FF; | 
|  | } | 
|  |  | 
|  | // Create a VQMOVNB with undef top lanes, then ZExt into the top half with | 
|  | // an AND. That extend will hopefully be removed if only the bottom bits are | 
|  | // demanded (though a truncating store, for example). | 
|  | SDValue VQMOVN = | 
|  | DAG.getNode(ARMISD::VQMOVNu, DL, HalfVT, DAG.getUNDEF(HalfVT), N0, | 
|  | DAG.getConstant(0, DL, MVT::i32)); | 
|  | SDValue Bitcast = DAG.getNode(ARMISD::VECTOR_REG_CAST, DL, VT, VQMOVN); | 
|  | return DAG.getNode(ISD::AND, DL, VT, Bitcast, | 
|  | DAG.getConstant(ExtConst, DL, VT)); | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static const APInt *isPowerOf2Constant(SDValue V) { | 
|  | ConstantSDNode *C = dyn_cast<ConstantSDNode>(V); | 
|  | if (!C) | 
|  | return nullptr; | 
|  | const APInt *CV = &C->getAPIntValue(); | 
|  | return CV->isPowerOf2() ? CV : nullptr; | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::PerformCMOVToBFICombine(SDNode *CMOV, SelectionDAG &DAG) const { | 
|  | // If we have a CMOV, OR and AND combination such as: | 
|  | //   if (x & CN) | 
|  | //     y |= CM; | 
|  | // | 
|  | // And: | 
|  | //   * CN is a single bit; | 
|  | //   * All bits covered by CM are known zero in y | 
|  | // | 
|  | // Then we can convert this into a sequence of BFI instructions. This will | 
|  | // always be a win if CM is a single bit, will always be no worse than the | 
|  | // TST&OR sequence if CM is two bits, and for thumb will be no worse if CM is | 
|  | // three bits (due to the extra IT instruction). | 
|  |  | 
|  | SDValue Op0 = CMOV->getOperand(0); | 
|  | SDValue Op1 = CMOV->getOperand(1); | 
|  | auto CCNode = cast<ConstantSDNode>(CMOV->getOperand(2)); | 
|  | auto CC = CCNode->getAPIntValue().getLimitedValue(); | 
|  | SDValue CmpZ = CMOV->getOperand(4); | 
|  |  | 
|  | // The compare must be against zero. | 
|  | if (!isNullConstant(CmpZ->getOperand(1))) | 
|  | return SDValue(); | 
|  |  | 
|  | assert(CmpZ->getOpcode() == ARMISD::CMPZ); | 
|  | SDValue And = CmpZ->getOperand(0); | 
|  | if (And->getOpcode() != ISD::AND) | 
|  | return SDValue(); | 
|  | const APInt *AndC = isPowerOf2Constant(And->getOperand(1)); | 
|  | if (!AndC) | 
|  | return SDValue(); | 
|  | SDValue X = And->getOperand(0); | 
|  |  | 
|  | if (CC == ARMCC::EQ) { | 
|  | // We're performing an "equal to zero" compare. Swap the operands so we | 
|  | // canonicalize on a "not equal to zero" compare. | 
|  | std::swap(Op0, Op1); | 
|  | } else { | 
|  | assert(CC == ARMCC::NE && "How can a CMPZ node not be EQ or NE?"); | 
|  | } | 
|  |  | 
|  | if (Op1->getOpcode() != ISD::OR) | 
|  | return SDValue(); | 
|  |  | 
|  | ConstantSDNode *OrC = dyn_cast<ConstantSDNode>(Op1->getOperand(1)); | 
|  | if (!OrC) | 
|  | return SDValue(); | 
|  | SDValue Y = Op1->getOperand(0); | 
|  |  | 
|  | if (Op0 != Y) | 
|  | return SDValue(); | 
|  |  | 
|  | // Now, is it profitable to continue? | 
|  | APInt OrCI = OrC->getAPIntValue(); | 
|  | unsigned Heuristic = Subtarget->isThumb() ? 3 : 2; | 
|  | if (OrCI.countPopulation() > Heuristic) | 
|  | return SDValue(); | 
|  |  | 
|  | // Lastly, can we determine that the bits defined by OrCI | 
|  | // are zero in Y? | 
|  | KnownBits Known = DAG.computeKnownBits(Y); | 
|  | if ((OrCI & Known.Zero) != OrCI) | 
|  | return SDValue(); | 
|  |  | 
|  | // OK, we can do the combine. | 
|  | SDValue V = Y; | 
|  | SDLoc dl(X); | 
|  | EVT VT = X.getValueType(); | 
|  | unsigned BitInX = AndC->logBase2(); | 
|  |  | 
|  | if (BitInX != 0) { | 
|  | // We must shift X first. | 
|  | X = DAG.getNode(ISD::SRL, dl, VT, X, | 
|  | DAG.getConstant(BitInX, dl, VT)); | 
|  | } | 
|  |  | 
|  | for (unsigned BitInY = 0, NumActiveBits = OrCI.getActiveBits(); | 
|  | BitInY < NumActiveBits; ++BitInY) { | 
|  | if (OrCI[BitInY] == 0) | 
|  | continue; | 
|  | APInt Mask(VT.getSizeInBits(), 0); | 
|  | Mask.setBit(BitInY); | 
|  | V = DAG.getNode(ARMISD::BFI, dl, VT, V, X, | 
|  | // Confusingly, the operand is an *inverted* mask. | 
|  | DAG.getConstant(~Mask, dl, VT)); | 
|  | } | 
|  |  | 
|  | return V; | 
|  | } | 
|  |  | 
|  | // Given N, the value controlling the conditional branch, search for the loop | 
|  | // intrinsic, returning it, along with how the value is used. We need to handle | 
|  | // patterns such as the following: | 
|  | // (brcond (xor (setcc (loop.decrement), 0, ne), 1), exit) | 
|  | // (brcond (setcc (loop.decrement), 0, eq), exit) | 
|  | // (brcond (setcc (loop.decrement), 0, ne), header) | 
|  | static SDValue SearchLoopIntrinsic(SDValue N, ISD::CondCode &CC, int &Imm, | 
|  | bool &Negate) { | 
|  | switch (N->getOpcode()) { | 
|  | default: | 
|  | break; | 
|  | case ISD::XOR: { | 
|  | if (!isa<ConstantSDNode>(N.getOperand(1))) | 
|  | return SDValue(); | 
|  | if (!cast<ConstantSDNode>(N.getOperand(1))->isOne()) | 
|  | return SDValue(); | 
|  | Negate = !Negate; | 
|  | return SearchLoopIntrinsic(N.getOperand(0), CC, Imm, Negate); | 
|  | } | 
|  | case ISD::SETCC: { | 
|  | auto *Const = dyn_cast<ConstantSDNode>(N.getOperand(1)); | 
|  | if (!Const) | 
|  | return SDValue(); | 
|  | if (Const->isNullValue()) | 
|  | Imm = 0; | 
|  | else if (Const->isOne()) | 
|  | Imm = 1; | 
|  | else | 
|  | return SDValue(); | 
|  | CC = cast<CondCodeSDNode>(N.getOperand(2))->get(); | 
|  | return SearchLoopIntrinsic(N->getOperand(0), CC, Imm, Negate); | 
|  | } | 
|  | case ISD::INTRINSIC_W_CHAIN: { | 
|  | unsigned IntOp = cast<ConstantSDNode>(N.getOperand(1))->getZExtValue(); | 
|  | if (IntOp != Intrinsic::test_set_loop_iterations && | 
|  | IntOp != Intrinsic::loop_decrement_reg) | 
|  | return SDValue(); | 
|  | return N; | 
|  | } | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue PerformHWLoopCombine(SDNode *N, | 
|  | TargetLowering::DAGCombinerInfo &DCI, | 
|  | const ARMSubtarget *ST) { | 
|  |  | 
|  | // The hwloop intrinsics that we're interested are used for control-flow, | 
|  | // either for entering or exiting the loop: | 
|  | // - test.set.loop.iterations will test whether its operand is zero. If it | 
|  | //   is zero, the proceeding branch should not enter the loop. | 
|  | // - loop.decrement.reg also tests whether its operand is zero. If it is | 
|  | //   zero, the proceeding branch should not branch back to the beginning of | 
|  | //   the loop. | 
|  | // So here, we need to check that how the brcond is using the result of each | 
|  | // of the intrinsics to ensure that we're branching to the right place at the | 
|  | // right time. | 
|  |  | 
|  | ISD::CondCode CC; | 
|  | SDValue Cond; | 
|  | int Imm = 1; | 
|  | bool Negate = false; | 
|  | SDValue Chain = N->getOperand(0); | 
|  | SDValue Dest; | 
|  |  | 
|  | if (N->getOpcode() == ISD::BRCOND) { | 
|  | CC = ISD::SETEQ; | 
|  | Cond = N->getOperand(1); | 
|  | Dest = N->getOperand(2); | 
|  | } else { | 
|  | assert(N->getOpcode() == ISD::BR_CC && "Expected BRCOND or BR_CC!"); | 
|  | CC = cast<CondCodeSDNode>(N->getOperand(1))->get(); | 
|  | Cond = N->getOperand(2); | 
|  | Dest = N->getOperand(4); | 
|  | if (auto *Const = dyn_cast<ConstantSDNode>(N->getOperand(3))) { | 
|  | if (!Const->isOne() && !Const->isNullValue()) | 
|  | return SDValue(); | 
|  | Imm = Const->getZExtValue(); | 
|  | } else | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue Int = SearchLoopIntrinsic(Cond, CC, Imm, Negate); | 
|  | if (!Int) | 
|  | return SDValue(); | 
|  |  | 
|  | if (Negate) | 
|  | CC = ISD::getSetCCInverse(CC, /* Integer inverse */ MVT::i32); | 
|  |  | 
|  | auto IsTrueIfZero = [](ISD::CondCode CC, int Imm) { | 
|  | return (CC == ISD::SETEQ && Imm == 0) || | 
|  | (CC == ISD::SETNE && Imm == 1) || | 
|  | (CC == ISD::SETLT && Imm == 1) || | 
|  | (CC == ISD::SETULT && Imm == 1); | 
|  | }; | 
|  |  | 
|  | auto IsFalseIfZero = [](ISD::CondCode CC, int Imm) { | 
|  | return (CC == ISD::SETEQ && Imm == 1) || | 
|  | (CC == ISD::SETNE && Imm == 0) || | 
|  | (CC == ISD::SETGT && Imm == 0) || | 
|  | (CC == ISD::SETUGT && Imm == 0) || | 
|  | (CC == ISD::SETGE && Imm == 1) || | 
|  | (CC == ISD::SETUGE && Imm == 1); | 
|  | }; | 
|  |  | 
|  | assert((IsTrueIfZero(CC, Imm) || IsFalseIfZero(CC, Imm)) && | 
|  | "unsupported condition"); | 
|  |  | 
|  | SDLoc dl(Int); | 
|  | SelectionDAG &DAG = DCI.DAG; | 
|  | SDValue Elements = Int.getOperand(2); | 
|  | unsigned IntOp = cast<ConstantSDNode>(Int->getOperand(1))->getZExtValue(); | 
|  | assert((N->hasOneUse() && N->use_begin()->getOpcode() == ISD::BR) | 
|  | && "expected single br user"); | 
|  | SDNode *Br = *N->use_begin(); | 
|  | SDValue OtherTarget = Br->getOperand(1); | 
|  |  | 
|  | // Update the unconditional branch to branch to the given Dest. | 
|  | auto UpdateUncondBr = [](SDNode *Br, SDValue Dest, SelectionDAG &DAG) { | 
|  | SDValue NewBrOps[] = { Br->getOperand(0), Dest }; | 
|  | SDValue NewBr = DAG.getNode(ISD::BR, SDLoc(Br), MVT::Other, NewBrOps); | 
|  | DAG.ReplaceAllUsesOfValueWith(SDValue(Br, 0), NewBr); | 
|  | }; | 
|  |  | 
|  | if (IntOp == Intrinsic::test_set_loop_iterations) { | 
|  | SDValue Res; | 
|  | // We expect this 'instruction' to branch when the counter is zero. | 
|  | if (IsTrueIfZero(CC, Imm)) { | 
|  | SDValue Ops[] = { Chain, Elements, Dest }; | 
|  | Res = DAG.getNode(ARMISD::WLS, dl, MVT::Other, Ops); | 
|  | } else { | 
|  | // The logic is the reverse of what we need for WLS, so find the other | 
|  | // basic block target: the target of the proceeding br. | 
|  | UpdateUncondBr(Br, Dest, DAG); | 
|  |  | 
|  | SDValue Ops[] = { Chain, Elements, OtherTarget }; | 
|  | Res = DAG.getNode(ARMISD::WLS, dl, MVT::Other, Ops); | 
|  | } | 
|  | DAG.ReplaceAllUsesOfValueWith(Int.getValue(1), Int.getOperand(0)); | 
|  | return Res; | 
|  | } else { | 
|  | SDValue Size = DAG.getTargetConstant( | 
|  | cast<ConstantSDNode>(Int.getOperand(3))->getZExtValue(), dl, MVT::i32); | 
|  | SDValue Args[] = { Int.getOperand(0), Elements, Size, }; | 
|  | SDValue LoopDec = DAG.getNode(ARMISD::LOOP_DEC, dl, | 
|  | DAG.getVTList(MVT::i32, MVT::Other), Args); | 
|  | DAG.ReplaceAllUsesWith(Int.getNode(), LoopDec.getNode()); | 
|  |  | 
|  | // We expect this instruction to branch when the count is not zero. | 
|  | SDValue Target = IsFalseIfZero(CC, Imm) ? Dest : OtherTarget; | 
|  |  | 
|  | // Update the unconditional branch to target the loop preheader if we've | 
|  | // found the condition has been reversed. | 
|  | if (Target == OtherTarget) | 
|  | UpdateUncondBr(Br, Dest, DAG); | 
|  |  | 
|  | Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, | 
|  | SDValue(LoopDec.getNode(), 1), Chain); | 
|  |  | 
|  | SDValue EndArgs[] = { Chain, SDValue(LoopDec.getNode(), 0), Target }; | 
|  | return DAG.getNode(ARMISD::LE, dl, MVT::Other, EndArgs); | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// PerformBRCONDCombine - Target-specific DAG combining for ARMISD::BRCOND. | 
|  | SDValue | 
|  | ARMTargetLowering::PerformBRCONDCombine(SDNode *N, SelectionDAG &DAG) const { | 
|  | SDValue Cmp = N->getOperand(4); | 
|  | if (Cmp.getOpcode() != ARMISD::CMPZ) | 
|  | // Only looking at NE cases. | 
|  | return SDValue(); | 
|  |  | 
|  | EVT VT = N->getValueType(0); | 
|  | SDLoc dl(N); | 
|  | SDValue LHS = Cmp.getOperand(0); | 
|  | SDValue RHS = Cmp.getOperand(1); | 
|  | SDValue Chain = N->getOperand(0); | 
|  | SDValue BB = N->getOperand(1); | 
|  | SDValue ARMcc = N->getOperand(2); | 
|  | ARMCC::CondCodes CC = | 
|  | (ARMCC::CondCodes)cast<ConstantSDNode>(ARMcc)->getZExtValue(); | 
|  |  | 
|  | // (brcond Chain BB ne CPSR (cmpz (and (cmov 0 1 CC CPSR Cmp) 1) 0)) | 
|  | // -> (brcond Chain BB CC CPSR Cmp) | 
|  | if (CC == ARMCC::NE && LHS.getOpcode() == ISD::AND && LHS->hasOneUse() && | 
|  | LHS->getOperand(0)->getOpcode() == ARMISD::CMOV && | 
|  | LHS->getOperand(0)->hasOneUse()) { | 
|  | auto *LHS00C = dyn_cast<ConstantSDNode>(LHS->getOperand(0)->getOperand(0)); | 
|  | auto *LHS01C = dyn_cast<ConstantSDNode>(LHS->getOperand(0)->getOperand(1)); | 
|  | auto *LHS1C = dyn_cast<ConstantSDNode>(LHS->getOperand(1)); | 
|  | auto *RHSC = dyn_cast<ConstantSDNode>(RHS); | 
|  | if ((LHS00C && LHS00C->getZExtValue() == 0) && | 
|  | (LHS01C && LHS01C->getZExtValue() == 1) && | 
|  | (LHS1C && LHS1C->getZExtValue() == 1) && | 
|  | (RHSC && RHSC->getZExtValue() == 0)) { | 
|  | return DAG.getNode( | 
|  | ARMISD::BRCOND, dl, VT, Chain, BB, LHS->getOperand(0)->getOperand(2), | 
|  | LHS->getOperand(0)->getOperand(3), LHS->getOperand(0)->getOperand(4)); | 
|  | } | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// PerformCMOVCombine - Target-specific DAG combining for ARMISD::CMOV. | 
|  | SDValue | 
|  | ARMTargetLowering::PerformCMOVCombine(SDNode *N, SelectionDAG &DAG) const { | 
|  | SDValue Cmp = N->getOperand(4); | 
|  | if (Cmp.getOpcode() != ARMISD::CMPZ) | 
|  | // Only looking at EQ and NE cases. | 
|  | return SDValue(); | 
|  |  | 
|  | EVT VT = N->getValueType(0); | 
|  | SDLoc dl(N); | 
|  | SDValue LHS = Cmp.getOperand(0); | 
|  | SDValue RHS = Cmp.getOperand(1); | 
|  | SDValue FalseVal = N->getOperand(0); | 
|  | SDValue TrueVal = N->getOperand(1); | 
|  | SDValue ARMcc = N->getOperand(2); | 
|  | ARMCC::CondCodes CC = | 
|  | (ARMCC::CondCodes)cast<ConstantSDNode>(ARMcc)->getZExtValue(); | 
|  |  | 
|  | // BFI is only available on V6T2+. | 
|  | if (!Subtarget->isThumb1Only() && Subtarget->hasV6T2Ops()) { | 
|  | SDValue R = PerformCMOVToBFICombine(N, DAG); | 
|  | if (R) | 
|  | return R; | 
|  | } | 
|  |  | 
|  | // Simplify | 
|  | //   mov     r1, r0 | 
|  | //   cmp     r1, x | 
|  | //   mov     r0, y | 
|  | //   moveq   r0, x | 
|  | // to | 
|  | //   cmp     r0, x | 
|  | //   movne   r0, y | 
|  | // | 
|  | //   mov     r1, r0 | 
|  | //   cmp     r1, x | 
|  | //   mov     r0, x | 
|  | //   movne   r0, y | 
|  | // to | 
|  | //   cmp     r0, x | 
|  | //   movne   r0, y | 
|  | /// FIXME: Turn this into a target neutral optimization? | 
|  | SDValue Res; | 
|  | if (CC == ARMCC::NE && FalseVal == RHS && FalseVal != LHS) { | 
|  | Res = DAG.getNode(ARMISD::CMOV, dl, VT, LHS, TrueVal, ARMcc, | 
|  | N->getOperand(3), Cmp); | 
|  | } else if (CC == ARMCC::EQ && TrueVal == RHS) { | 
|  | SDValue ARMcc; | 
|  | SDValue NewCmp = getARMCmp(LHS, RHS, ISD::SETNE, ARMcc, DAG, dl); | 
|  | Res = DAG.getNode(ARMISD::CMOV, dl, VT, LHS, FalseVal, ARMcc, | 
|  | N->getOperand(3), NewCmp); | 
|  | } | 
|  |  | 
|  | // (cmov F T ne CPSR (cmpz (cmov 0 1 CC CPSR Cmp) 0)) | 
|  | // -> (cmov F T CC CPSR Cmp) | 
|  | if (CC == ARMCC::NE && LHS.getOpcode() == ARMISD::CMOV && LHS->hasOneUse()) { | 
|  | auto *LHS0C = dyn_cast<ConstantSDNode>(LHS->getOperand(0)); | 
|  | auto *LHS1C = dyn_cast<ConstantSDNode>(LHS->getOperand(1)); | 
|  | auto *RHSC = dyn_cast<ConstantSDNode>(RHS); | 
|  | if ((LHS0C && LHS0C->getZExtValue() == 0) && | 
|  | (LHS1C && LHS1C->getZExtValue() == 1) && | 
|  | (RHSC && RHSC->getZExtValue() == 0)) { | 
|  | return DAG.getNode(ARMISD::CMOV, dl, VT, FalseVal, TrueVal, | 
|  | LHS->getOperand(2), LHS->getOperand(3), | 
|  | LHS->getOperand(4)); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!VT.isInteger()) | 
|  | return SDValue(); | 
|  |  | 
|  | // Materialize a boolean comparison for integers so we can avoid branching. | 
|  | if (isNullConstant(FalseVal)) { | 
|  | if (CC == ARMCC::EQ && isOneConstant(TrueVal)) { | 
|  | if (!Subtarget->isThumb1Only() && Subtarget->hasV5TOps()) { | 
|  | // If x == y then x - y == 0 and ARM's CLZ will return 32, shifting it | 
|  | // right 5 bits will make that 32 be 1, otherwise it will be 0. | 
|  | // CMOV 0, 1, ==, (CMPZ x, y) -> SRL (CTLZ (SUB x, y)), 5 | 
|  | SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS); | 
|  | Res = DAG.getNode(ISD::SRL, dl, VT, DAG.getNode(ISD::CTLZ, dl, VT, Sub), | 
|  | DAG.getConstant(5, dl, MVT::i32)); | 
|  | } else { | 
|  | // CMOV 0, 1, ==, (CMPZ x, y) -> | 
|  | //     (ADDCARRY (SUB x, y), t:0, t:1) | 
|  | // where t = (SUBCARRY 0, (SUB x, y), 0) | 
|  | // | 
|  | // The SUBCARRY computes 0 - (x - y) and this will give a borrow when | 
|  | // x != y. In other words, a carry C == 1 when x == y, C == 0 | 
|  | // otherwise. | 
|  | // The final ADDCARRY computes | 
|  | //     x - y + (0 - (x - y)) + C == C | 
|  | SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS); | 
|  | SDVTList VTs = DAG.getVTList(VT, MVT::i32); | 
|  | SDValue Neg = DAG.getNode(ISD::USUBO, dl, VTs, FalseVal, Sub); | 
|  | // ISD::SUBCARRY returns a borrow but we want the carry here | 
|  | // actually. | 
|  | SDValue Carry = | 
|  | DAG.getNode(ISD::SUB, dl, MVT::i32, | 
|  | DAG.getConstant(1, dl, MVT::i32), Neg.getValue(1)); | 
|  | Res = DAG.getNode(ISD::ADDCARRY, dl, VTs, Sub, Neg, Carry); | 
|  | } | 
|  | } else if (CC == ARMCC::NE && !isNullConstant(RHS) && | 
|  | (!Subtarget->isThumb1Only() || isPowerOf2Constant(TrueVal))) { | 
|  | // This seems pointless but will allow us to combine it further below. | 
|  | // CMOV 0, z, !=, (CMPZ x, y) -> CMOV (SUBS x, y), z, !=, (SUBS x, y):1 | 
|  | SDValue Sub = | 
|  | DAG.getNode(ARMISD::SUBS, dl, DAG.getVTList(VT, MVT::i32), LHS, RHS); | 
|  | SDValue CPSRGlue = DAG.getCopyToReg(DAG.getEntryNode(), dl, ARM::CPSR, | 
|  | Sub.getValue(1), SDValue()); | 
|  | Res = DAG.getNode(ARMISD::CMOV, dl, VT, Sub, TrueVal, ARMcc, | 
|  | N->getOperand(3), CPSRGlue.getValue(1)); | 
|  | FalseVal = Sub; | 
|  | } | 
|  | } else if (isNullConstant(TrueVal)) { | 
|  | if (CC == ARMCC::EQ && !isNullConstant(RHS) && | 
|  | (!Subtarget->isThumb1Only() || isPowerOf2Constant(FalseVal))) { | 
|  | // This seems pointless but will allow us to combine it further below | 
|  | // Note that we change == for != as this is the dual for the case above. | 
|  | // CMOV z, 0, ==, (CMPZ x, y) -> CMOV (SUBS x, y), z, !=, (SUBS x, y):1 | 
|  | SDValue Sub = | 
|  | DAG.getNode(ARMISD::SUBS, dl, DAG.getVTList(VT, MVT::i32), LHS, RHS); | 
|  | SDValue CPSRGlue = DAG.getCopyToReg(DAG.getEntryNode(), dl, ARM::CPSR, | 
|  | Sub.getValue(1), SDValue()); | 
|  | Res = DAG.getNode(ARMISD::CMOV, dl, VT, Sub, FalseVal, | 
|  | DAG.getConstant(ARMCC::NE, dl, MVT::i32), | 
|  | N->getOperand(3), CPSRGlue.getValue(1)); | 
|  | FalseVal = Sub; | 
|  | } | 
|  | } | 
|  |  | 
|  | // On Thumb1, the DAG above may be further combined if z is a power of 2 | 
|  | // (z == 2 ^ K). | 
|  | // CMOV (SUBS x, y), z, !=, (SUBS x, y):1 -> | 
|  | // t1 = (USUBO (SUB x, y), 1) | 
|  | // t2 = (SUBCARRY (SUB x, y), t1:0, t1:1) | 
|  | // Result = if K != 0 then (SHL t2:0, K) else t2:0 | 
|  | // | 
|  | // This also handles the special case of comparing against zero; it's | 
|  | // essentially, the same pattern, except there's no SUBS: | 
|  | // CMOV x, z, !=, (CMPZ x, 0) -> | 
|  | // t1 = (USUBO x, 1) | 
|  | // t2 = (SUBCARRY x, t1:0, t1:1) | 
|  | // Result = if K != 0 then (SHL t2:0, K) else t2:0 | 
|  | const APInt *TrueConst; | 
|  | if (Subtarget->isThumb1Only() && CC == ARMCC::NE && | 
|  | ((FalseVal.getOpcode() == ARMISD::SUBS && | 
|  | FalseVal.getOperand(0) == LHS && FalseVal.getOperand(1) == RHS) || | 
|  | (FalseVal == LHS && isNullConstant(RHS))) && | 
|  | (TrueConst = isPowerOf2Constant(TrueVal))) { | 
|  | SDVTList VTs = DAG.getVTList(VT, MVT::i32); | 
|  | unsigned ShiftAmount = TrueConst->logBase2(); | 
|  | if (ShiftAmount) | 
|  | TrueVal = DAG.getConstant(1, dl, VT); | 
|  | SDValue Subc = DAG.getNode(ISD::USUBO, dl, VTs, FalseVal, TrueVal); | 
|  | Res = DAG.getNode(ISD::SUBCARRY, dl, VTs, FalseVal, Subc, Subc.getValue(1)); | 
|  |  | 
|  | if (ShiftAmount) | 
|  | Res = DAG.getNode(ISD::SHL, dl, VT, Res, | 
|  | DAG.getConstant(ShiftAmount, dl, MVT::i32)); | 
|  | } | 
|  |  | 
|  | if (Res.getNode()) { | 
|  | KnownBits Known = DAG.computeKnownBits(SDValue(N,0)); | 
|  | // Capture demanded bits information that would be otherwise lost. | 
|  | if (Known.Zero == 0xfffffffe) | 
|  | Res = DAG.getNode(ISD::AssertZext, dl, MVT::i32, Res, | 
|  | DAG.getValueType(MVT::i1)); | 
|  | else if (Known.Zero == 0xffffff00) | 
|  | Res = DAG.getNode(ISD::AssertZext, dl, MVT::i32, Res, | 
|  | DAG.getValueType(MVT::i8)); | 
|  | else if (Known.Zero == 0xffff0000) | 
|  | Res = DAG.getNode(ISD::AssertZext, dl, MVT::i32, Res, | 
|  | DAG.getValueType(MVT::i16)); | 
|  | } | 
|  |  | 
|  | return Res; | 
|  | } | 
|  |  | 
|  | static SDValue PerformBITCASTCombine(SDNode *N, SelectionDAG &DAG, | 
|  | const ARMSubtarget *ST) { | 
|  | SDValue Src = N->getOperand(0); | 
|  | EVT DstVT = N->getValueType(0); | 
|  |  | 
|  | // Convert v4f32 bitcast (v4i32 vdup (i32)) -> v4f32 vdup (i32) under MVE. | 
|  | if (ST->hasMVEIntegerOps() && Src.getOpcode() == ARMISD::VDUP) { | 
|  | EVT SrcVT = Src.getValueType(); | 
|  | if (SrcVT.getScalarSizeInBits() == DstVT.getScalarSizeInBits()) | 
|  | return DAG.getNode(ARMISD::VDUP, SDLoc(N), DstVT, Src.getOperand(0)); | 
|  | } | 
|  |  | 
|  | // We may have a bitcast of something that has already had this bitcast | 
|  | // combine performed on it, so skip past any VECTOR_REG_CASTs. | 
|  | while (Src.getOpcode() == ARMISD::VECTOR_REG_CAST) | 
|  | Src = Src.getOperand(0); | 
|  |  | 
|  | // Bitcast from element-wise VMOV or VMVN doesn't need VREV if the VREV that | 
|  | // would be generated is at least the width of the element type. | 
|  | EVT SrcVT = Src.getValueType(); | 
|  | if ((Src.getOpcode() == ARMISD::VMOVIMM || | 
|  | Src.getOpcode() == ARMISD::VMVNIMM || | 
|  | Src.getOpcode() == ARMISD::VMOVFPIMM) && | 
|  | SrcVT.getScalarSizeInBits() <= DstVT.getScalarSizeInBits() && | 
|  | DAG.getDataLayout().isBigEndian()) | 
|  | return DAG.getNode(ARMISD::VECTOR_REG_CAST, SDLoc(N), DstVT, Src); | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N, | 
|  | DAGCombinerInfo &DCI) const { | 
|  | switch (N->getOpcode()) { | 
|  | default: break; | 
|  | case ISD::VSELECT:    return PerformVSELECTCombine(N, DCI, Subtarget); | 
|  | case ISD::ABS:        return PerformABSCombine(N, DCI, Subtarget); | 
|  | case ARMISD::ADDE:    return PerformADDECombine(N, DCI, Subtarget); | 
|  | case ARMISD::UMLAL:   return PerformUMLALCombine(N, DCI.DAG, Subtarget); | 
|  | case ISD::ADD:        return PerformADDCombine(N, DCI, Subtarget); | 
|  | case ISD::SUB:        return PerformSUBCombine(N, DCI, Subtarget); | 
|  | case ISD::MUL:        return PerformMULCombine(N, DCI, Subtarget); | 
|  | case ISD::OR:         return PerformORCombine(N, DCI, Subtarget); | 
|  | case ISD::XOR:        return PerformXORCombine(N, DCI, Subtarget); | 
|  | case ISD::AND:        return PerformANDCombine(N, DCI, Subtarget); | 
|  | case ISD::BRCOND: | 
|  | case ISD::BR_CC:      return PerformHWLoopCombine(N, DCI, Subtarget); | 
|  | case ARMISD::ADDC: | 
|  | case ARMISD::SUBC:    return PerformAddcSubcCombine(N, DCI, Subtarget); | 
|  | case ARMISD::SUBE:    return PerformAddeSubeCombine(N, DCI, Subtarget); | 
|  | case ARMISD::BFI:     return PerformBFICombine(N, DCI); | 
|  | case ARMISD::VMOVRRD: return PerformVMOVRRDCombine(N, DCI, Subtarget); | 
|  | case ARMISD::VMOVDRR: return PerformVMOVDRRCombine(N, DCI.DAG); | 
|  | case ARMISD::VMOVhr:  return PerformVMOVhrCombine(N, DCI); | 
|  | case ARMISD::VMOVrh:  return PerformVMOVrhCombine(N, DCI); | 
|  | case ISD::STORE:      return PerformSTORECombine(N, DCI, Subtarget); | 
|  | case ISD::BUILD_VECTOR: return PerformBUILD_VECTORCombine(N, DCI, Subtarget); | 
|  | case ISD::INSERT_VECTOR_ELT: return PerformInsertEltCombine(N, DCI); | 
|  | case ISD::EXTRACT_VECTOR_ELT: return PerformExtractEltCombine(N, DCI); | 
|  | case ISD::VECTOR_SHUFFLE: return PerformVECTOR_SHUFFLECombine(N, DCI.DAG); | 
|  | case ARMISD::VDUPLANE: return PerformVDUPLANECombine(N, DCI, Subtarget); | 
|  | case ARMISD::VDUP: return PerformVDUPCombine(N, DCI, Subtarget); | 
|  | case ISD::FP_TO_SINT: | 
|  | case ISD::FP_TO_UINT: | 
|  | return PerformVCVTCombine(N, DCI.DAG, Subtarget); | 
|  | case ISD::FDIV: | 
|  | return PerformVDIVCombine(N, DCI.DAG, Subtarget); | 
|  | case ISD::INTRINSIC_WO_CHAIN: | 
|  | return PerformIntrinsicCombine(N, DCI); | 
|  | case ISD::SHL: | 
|  | case ISD::SRA: | 
|  | case ISD::SRL: | 
|  | return PerformShiftCombine(N, DCI, Subtarget); | 
|  | case ISD::SIGN_EXTEND: | 
|  | case ISD::ZERO_EXTEND: | 
|  | case ISD::ANY_EXTEND: | 
|  | return PerformExtendCombine(N, DCI.DAG, Subtarget); | 
|  | case ISD::SMIN: | 
|  | case ISD::UMIN: | 
|  | case ISD::SMAX: | 
|  | case ISD::UMAX: | 
|  | return PerformMinMaxCombine(N, DCI.DAG, Subtarget); | 
|  | case ARMISD::CMOV: return PerformCMOVCombine(N, DCI.DAG); | 
|  | case ARMISD::BRCOND: return PerformBRCONDCombine(N, DCI.DAG); | 
|  | case ISD::LOAD:       return PerformLOADCombine(N, DCI); | 
|  | case ARMISD::VLD1DUP: | 
|  | case ARMISD::VLD2DUP: | 
|  | case ARMISD::VLD3DUP: | 
|  | case ARMISD::VLD4DUP: | 
|  | return PerformVLDCombine(N, DCI); | 
|  | case ARMISD::BUILD_VECTOR: | 
|  | return PerformARMBUILD_VECTORCombine(N, DCI); | 
|  | case ISD::BITCAST: | 
|  | return PerformBITCASTCombine(N, DCI.DAG, Subtarget); | 
|  | case ARMISD::PREDICATE_CAST: | 
|  | return PerformPREDICATE_CASTCombine(N, DCI); | 
|  | case ARMISD::VECTOR_REG_CAST: | 
|  | return PerformVECTOR_REG_CASTCombine(N, DCI, Subtarget); | 
|  | case ARMISD::VCMP: | 
|  | return PerformVCMPCombine(N, DCI, Subtarget); | 
|  | case ISD::VECREDUCE_ADD: | 
|  | return PerformVECREDUCE_ADDCombine(N, DCI.DAG, Subtarget); | 
|  | case ARMISD::VMOVN: | 
|  | return PerformVMOVNCombine(N, DCI); | 
|  | case ARMISD::VQMOVNs: | 
|  | case ARMISD::VQMOVNu: | 
|  | return PerformVQMOVNCombine(N, DCI); | 
|  | case ARMISD::ASRL: | 
|  | case ARMISD::LSRL: | 
|  | case ARMISD::LSLL: | 
|  | return PerformLongShiftCombine(N, DCI.DAG); | 
|  | case ARMISD::SMULWB: { | 
|  | unsigned BitWidth = N->getValueType(0).getSizeInBits(); | 
|  | APInt DemandedMask = APInt::getLowBitsSet(BitWidth, 16); | 
|  | if (SimplifyDemandedBits(N->getOperand(1), DemandedMask, DCI)) | 
|  | return SDValue(); | 
|  | break; | 
|  | } | 
|  | case ARMISD::SMULWT: { | 
|  | unsigned BitWidth = N->getValueType(0).getSizeInBits(); | 
|  | APInt DemandedMask = APInt::getHighBitsSet(BitWidth, 16); | 
|  | if (SimplifyDemandedBits(N->getOperand(1), DemandedMask, DCI)) | 
|  | return SDValue(); | 
|  | break; | 
|  | } | 
|  | case ARMISD::SMLALBB: | 
|  | case ARMISD::QADD16b: | 
|  | case ARMISD::QSUB16b: { | 
|  | unsigned BitWidth = N->getValueType(0).getSizeInBits(); | 
|  | APInt DemandedMask = APInt::getLowBitsSet(BitWidth, 16); | 
|  | if ((SimplifyDemandedBits(N->getOperand(0), DemandedMask, DCI)) || | 
|  | (SimplifyDemandedBits(N->getOperand(1), DemandedMask, DCI))) | 
|  | return SDValue(); | 
|  | break; | 
|  | } | 
|  | case ARMISD::SMLALBT: { | 
|  | unsigned LowWidth = N->getOperand(0).getValueType().getSizeInBits(); | 
|  | APInt LowMask = APInt::getLowBitsSet(LowWidth, 16); | 
|  | unsigned HighWidth = N->getOperand(1).getValueType().getSizeInBits(); | 
|  | APInt HighMask = APInt::getHighBitsSet(HighWidth, 16); | 
|  | if ((SimplifyDemandedBits(N->getOperand(0), LowMask, DCI)) || | 
|  | (SimplifyDemandedBits(N->getOperand(1), HighMask, DCI))) | 
|  | return SDValue(); | 
|  | break; | 
|  | } | 
|  | case ARMISD::SMLALTB: { | 
|  | unsigned HighWidth = N->getOperand(0).getValueType().getSizeInBits(); | 
|  | APInt HighMask = APInt::getHighBitsSet(HighWidth, 16); | 
|  | unsigned LowWidth = N->getOperand(1).getValueType().getSizeInBits(); | 
|  | APInt LowMask = APInt::getLowBitsSet(LowWidth, 16); | 
|  | if ((SimplifyDemandedBits(N->getOperand(0), HighMask, DCI)) || | 
|  | (SimplifyDemandedBits(N->getOperand(1), LowMask, DCI))) | 
|  | return SDValue(); | 
|  | break; | 
|  | } | 
|  | case ARMISD::SMLALTT: { | 
|  | unsigned BitWidth = N->getValueType(0).getSizeInBits(); | 
|  | APInt DemandedMask = APInt::getHighBitsSet(BitWidth, 16); | 
|  | if ((SimplifyDemandedBits(N->getOperand(0), DemandedMask, DCI)) || | 
|  | (SimplifyDemandedBits(N->getOperand(1), DemandedMask, DCI))) | 
|  | return SDValue(); | 
|  | break; | 
|  | } | 
|  | case ARMISD::QADD8b: | 
|  | case ARMISD::QSUB8b: { | 
|  | unsigned BitWidth = N->getValueType(0).getSizeInBits(); | 
|  | APInt DemandedMask = APInt::getLowBitsSet(BitWidth, 8); | 
|  | if ((SimplifyDemandedBits(N->getOperand(0), DemandedMask, DCI)) || | 
|  | (SimplifyDemandedBits(N->getOperand(1), DemandedMask, DCI))) | 
|  | return SDValue(); | 
|  | break; | 
|  | } | 
|  | case ISD::INTRINSIC_VOID: | 
|  | case ISD::INTRINSIC_W_CHAIN: | 
|  | switch (cast<ConstantSDNode>(N->getOperand(1))->getZExtValue()) { | 
|  | case Intrinsic::arm_neon_vld1: | 
|  | case Intrinsic::arm_neon_vld1x2: | 
|  | case Intrinsic::arm_neon_vld1x3: | 
|  | case Intrinsic::arm_neon_vld1x4: | 
|  | case Intrinsic::arm_neon_vld2: | 
|  | case Intrinsic::arm_neon_vld3: | 
|  | case Intrinsic::arm_neon_vld4: | 
|  | case Intrinsic::arm_neon_vld2lane: | 
|  | case Intrinsic::arm_neon_vld3lane: | 
|  | case Intrinsic::arm_neon_vld4lane: | 
|  | case Intrinsic::arm_neon_vld2dup: | 
|  | case Intrinsic::arm_neon_vld3dup: | 
|  | case Intrinsic::arm_neon_vld4dup: | 
|  | case Intrinsic::arm_neon_vst1: | 
|  | case Intrinsic::arm_neon_vst1x2: | 
|  | case Intrinsic::arm_neon_vst1x3: | 
|  | case Intrinsic::arm_neon_vst1x4: | 
|  | case Intrinsic::arm_neon_vst2: | 
|  | case Intrinsic::arm_neon_vst3: | 
|  | case Intrinsic::arm_neon_vst4: | 
|  | case Intrinsic::arm_neon_vst2lane: | 
|  | case Intrinsic::arm_neon_vst3lane: | 
|  | case Intrinsic::arm_neon_vst4lane: | 
|  | return PerformVLDCombine(N, DCI); | 
|  | case Intrinsic::arm_mve_vld2q: | 
|  | case Intrinsic::arm_mve_vld4q: | 
|  | case Intrinsic::arm_mve_vst2q: | 
|  | case Intrinsic::arm_mve_vst4q: | 
|  | return PerformMVEVLDCombine(N, DCI); | 
|  | default: break; | 
|  | } | 
|  | break; | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isDesirableToTransformToIntegerOp(unsigned Opc, | 
|  | EVT VT) const { | 
|  | return (VT == MVT::f32) && (Opc == ISD::LOAD || Opc == ISD::STORE); | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::allowsMisalignedMemoryAccesses(EVT VT, unsigned, | 
|  | unsigned Alignment, | 
|  | MachineMemOperand::Flags, | 
|  | bool *Fast) const { | 
|  | // Depends what it gets converted into if the type is weird. | 
|  | if (!VT.isSimple()) | 
|  | return false; | 
|  |  | 
|  | // The AllowsUnaligned flag models the SCTLR.A setting in ARM cpus | 
|  | bool AllowsUnaligned = Subtarget->allowsUnalignedMem(); | 
|  | auto Ty = VT.getSimpleVT().SimpleTy; | 
|  |  | 
|  | if (Ty == MVT::i8 || Ty == MVT::i16 || Ty == MVT::i32) { | 
|  | // Unaligned access can use (for example) LRDB, LRDH, LDR | 
|  | if (AllowsUnaligned) { | 
|  | if (Fast) | 
|  | *Fast = Subtarget->hasV7Ops(); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Ty == MVT::f64 || Ty == MVT::v2f64) { | 
|  | // For any little-endian targets with neon, we can support unaligned ld/st | 
|  | // of D and Q (e.g. {D0,D1}) registers by using vld1.i8/vst1.i8. | 
|  | // A big-endian target may also explicitly support unaligned accesses | 
|  | if (Subtarget->hasNEON() && (AllowsUnaligned || Subtarget->isLittle())) { | 
|  | if (Fast) | 
|  | *Fast = true; | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!Subtarget->hasMVEIntegerOps()) | 
|  | return false; | 
|  |  | 
|  | // These are for predicates | 
|  | if ((Ty == MVT::v16i1 || Ty == MVT::v8i1 || Ty == MVT::v4i1)) { | 
|  | if (Fast) | 
|  | *Fast = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // These are for truncated stores/narrowing loads. They are fine so long as | 
|  | // the alignment is at least the size of the item being loaded | 
|  | if ((Ty == MVT::v4i8 || Ty == MVT::v8i8 || Ty == MVT::v4i16) && | 
|  | Alignment >= VT.getScalarSizeInBits() / 8) { | 
|  | if (Fast) | 
|  | *Fast = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // In little-endian MVE, the store instructions VSTRB.U8, VSTRH.U16 and | 
|  | // VSTRW.U32 all store the vector register in exactly the same format, and | 
|  | // differ only in the range of their immediate offset field and the required | 
|  | // alignment. So there is always a store that can be used, regardless of | 
|  | // actual type. | 
|  | // | 
|  | // For big endian, that is not the case. But can still emit a (VSTRB.U8; | 
|  | // VREV64.8) pair and get the same effect. This will likely be better than | 
|  | // aligning the vector through the stack. | 
|  | if (Ty == MVT::v16i8 || Ty == MVT::v8i16 || Ty == MVT::v8f16 || | 
|  | Ty == MVT::v4i32 || Ty == MVT::v4f32 || Ty == MVT::v2i64 || | 
|  | Ty == MVT::v2f64) { | 
|  | if (Fast) | 
|  | *Fast = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  |  | 
|  | EVT ARMTargetLowering::getOptimalMemOpType( | 
|  | const MemOp &Op, const AttributeList &FuncAttributes) const { | 
|  | // See if we can use NEON instructions for this... | 
|  | if ((Op.isMemcpy() || Op.isZeroMemset()) && Subtarget->hasNEON() && | 
|  | !FuncAttributes.hasFnAttribute(Attribute::NoImplicitFloat)) { | 
|  | bool Fast; | 
|  | if (Op.size() >= 16 && | 
|  | (Op.isAligned(Align(16)) || | 
|  | (allowsMisalignedMemoryAccesses(MVT::v2f64, 0, 1, | 
|  | MachineMemOperand::MONone, &Fast) && | 
|  | Fast))) { | 
|  | return MVT::v2f64; | 
|  | } else if (Op.size() >= 8 && | 
|  | (Op.isAligned(Align(8)) || | 
|  | (allowsMisalignedMemoryAccesses( | 
|  | MVT::f64, 0, 1, MachineMemOperand::MONone, &Fast) && | 
|  | Fast))) { | 
|  | return MVT::f64; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Let the target-independent logic figure it out. | 
|  | return MVT::Other; | 
|  | } | 
|  |  | 
|  | // 64-bit integers are split into their high and low parts and held in two | 
|  | // different registers, so the trunc is free since the low register can just | 
|  | // be used. | 
|  | bool ARMTargetLowering::isTruncateFree(Type *SrcTy, Type *DstTy) const { | 
|  | if (!SrcTy->isIntegerTy() || !DstTy->isIntegerTy()) | 
|  | return false; | 
|  | unsigned SrcBits = SrcTy->getPrimitiveSizeInBits(); | 
|  | unsigned DestBits = DstTy->getPrimitiveSizeInBits(); | 
|  | return (SrcBits == 64 && DestBits == 32); | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isTruncateFree(EVT SrcVT, EVT DstVT) const { | 
|  | if (SrcVT.isVector() || DstVT.isVector() || !SrcVT.isInteger() || | 
|  | !DstVT.isInteger()) | 
|  | return false; | 
|  | unsigned SrcBits = SrcVT.getSizeInBits(); | 
|  | unsigned DestBits = DstVT.getSizeInBits(); | 
|  | return (SrcBits == 64 && DestBits == 32); | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isZExtFree(SDValue Val, EVT VT2) const { | 
|  | if (Val.getOpcode() != ISD::LOAD) | 
|  | return false; | 
|  |  | 
|  | EVT VT1 = Val.getValueType(); | 
|  | if (!VT1.isSimple() || !VT1.isInteger() || | 
|  | !VT2.isSimple() || !VT2.isInteger()) | 
|  | return false; | 
|  |  | 
|  | switch (VT1.getSimpleVT().SimpleTy) { | 
|  | default: break; | 
|  | case MVT::i1: | 
|  | case MVT::i8: | 
|  | case MVT::i16: | 
|  | // 8-bit and 16-bit loads implicitly zero-extend to 32-bits. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isFNegFree(EVT VT) const { | 
|  | if (!VT.isSimple()) | 
|  | return false; | 
|  |  | 
|  | // There are quite a few FP16 instructions (e.g. VNMLA, VNMLS, etc.) that | 
|  | // negate values directly (fneg is free). So, we don't want to let the DAG | 
|  | // combiner rewrite fneg into xors and some other instructions.  For f16 and | 
|  | // FullFP16 argument passing, some bitcast nodes may be introduced, | 
|  | // triggering this DAG combine rewrite, so we are avoiding that with this. | 
|  | switch (VT.getSimpleVT().SimpleTy) { | 
|  | default: break; | 
|  | case MVT::f16: | 
|  | return Subtarget->hasFullFP16(); | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// Check if Ext1 and Ext2 are extends of the same type, doubling the bitwidth | 
|  | /// of the vector elements. | 
|  | static bool areExtractExts(Value *Ext1, Value *Ext2) { | 
|  | auto areExtDoubled = [](Instruction *Ext) { | 
|  | return Ext->getType()->getScalarSizeInBits() == | 
|  | 2 * Ext->getOperand(0)->getType()->getScalarSizeInBits(); | 
|  | }; | 
|  |  | 
|  | if (!match(Ext1, m_ZExtOrSExt(m_Value())) || | 
|  | !match(Ext2, m_ZExtOrSExt(m_Value())) || | 
|  | !areExtDoubled(cast<Instruction>(Ext1)) || | 
|  | !areExtDoubled(cast<Instruction>(Ext2))) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// Check if sinking \p I's operands to I's basic block is profitable, because | 
|  | /// the operands can be folded into a target instruction, e.g. | 
|  | /// sext/zext can be folded into vsubl. | 
|  | bool ARMTargetLowering::shouldSinkOperands(Instruction *I, | 
|  | SmallVectorImpl<Use *> &Ops) const { | 
|  | if (!I->getType()->isVectorTy()) | 
|  | return false; | 
|  |  | 
|  | if (Subtarget->hasNEON()) { | 
|  | switch (I->getOpcode()) { | 
|  | case Instruction::Sub: | 
|  | case Instruction::Add: { | 
|  | if (!areExtractExts(I->getOperand(0), I->getOperand(1))) | 
|  | return false; | 
|  | Ops.push_back(&I->getOperandUse(0)); | 
|  | Ops.push_back(&I->getOperandUse(1)); | 
|  | return true; | 
|  | } | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!Subtarget->hasMVEIntegerOps()) | 
|  | return false; | 
|  |  | 
|  | auto IsFMSMul = [&](Instruction *I) { | 
|  | if (!I->hasOneUse()) | 
|  | return false; | 
|  | auto *Sub = cast<Instruction>(*I->users().begin()); | 
|  | return Sub->getOpcode() == Instruction::FSub && Sub->getOperand(1) == I; | 
|  | }; | 
|  | auto IsFMS = [&](Instruction *I) { | 
|  | if (match(I->getOperand(0), m_FNeg(m_Value())) || | 
|  | match(I->getOperand(1), m_FNeg(m_Value()))) | 
|  | return true; | 
|  | return false; | 
|  | }; | 
|  |  | 
|  | auto IsSinker = [&](Instruction *I, int Operand) { | 
|  | switch (I->getOpcode()) { | 
|  | case Instruction::Add: | 
|  | case Instruction::Mul: | 
|  | case Instruction::FAdd: | 
|  | case Instruction::ICmp: | 
|  | case Instruction::FCmp: | 
|  | return true; | 
|  | case Instruction::FMul: | 
|  | return !IsFMSMul(I); | 
|  | case Instruction::Sub: | 
|  | case Instruction::FSub: | 
|  | case Instruction::Shl: | 
|  | case Instruction::LShr: | 
|  | case Instruction::AShr: | 
|  | return Operand == 1; | 
|  | case Instruction::Call: | 
|  | if (auto *II = dyn_cast<IntrinsicInst>(I)) { | 
|  | switch (II->getIntrinsicID()) { | 
|  | case Intrinsic::fma: | 
|  | return !IsFMS(I); | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | }; | 
|  |  | 
|  | for (auto OpIdx : enumerate(I->operands())) { | 
|  | Instruction *Op = dyn_cast<Instruction>(OpIdx.value().get()); | 
|  | // Make sure we are not already sinking this operand | 
|  | if (!Op || any_of(Ops, [&](Use *U) { return U->get() == Op; })) | 
|  | continue; | 
|  |  | 
|  | Instruction *Shuffle = Op; | 
|  | if (Shuffle->getOpcode() == Instruction::BitCast) | 
|  | Shuffle = dyn_cast<Instruction>(Shuffle->getOperand(0)); | 
|  | // We are looking for a splat that can be sunk. | 
|  | if (!Shuffle || | 
|  | !match(Shuffle, m_Shuffle( | 
|  | m_InsertElt(m_Undef(), m_Value(), m_ZeroInt()), | 
|  | m_Undef(), m_ZeroMask()))) | 
|  | continue; | 
|  | if (!IsSinker(I, OpIdx.index())) | 
|  | continue; | 
|  |  | 
|  | // All uses of the shuffle should be sunk to avoid duplicating it across gpr | 
|  | // and vector registers | 
|  | for (Use &U : Op->uses()) { | 
|  | Instruction *Insn = cast<Instruction>(U.getUser()); | 
|  | if (!IsSinker(Insn, U.getOperandNo())) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Ops.push_back(&Shuffle->getOperandUse(0)); | 
|  | if (Shuffle != Op) | 
|  | Ops.push_back(&Op->getOperandUse(0)); | 
|  | Ops.push_back(&OpIdx.value()); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Type *ARMTargetLowering::shouldConvertSplatType(ShuffleVectorInst *SVI) const { | 
|  | if (!Subtarget->hasMVEIntegerOps()) | 
|  | return nullptr; | 
|  | Type *SVIType = SVI->getType(); | 
|  | Type *ScalarType = SVIType->getScalarType(); | 
|  |  | 
|  | if (ScalarType->isFloatTy()) | 
|  | return Type::getInt32Ty(SVIType->getContext()); | 
|  | if (ScalarType->isHalfTy()) | 
|  | return Type::getInt16Ty(SVIType->getContext()); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const { | 
|  | EVT VT = ExtVal.getValueType(); | 
|  |  | 
|  | if (!isTypeLegal(VT)) | 
|  | return false; | 
|  |  | 
|  | if (auto *Ld = dyn_cast<MaskedLoadSDNode>(ExtVal.getOperand(0))) { | 
|  | if (Ld->isExpandingLoad()) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (Subtarget->hasMVEIntegerOps()) | 
|  | return true; | 
|  |  | 
|  | // Don't create a loadext if we can fold the extension into a wide/long | 
|  | // instruction. | 
|  | // If there's more than one user instruction, the loadext is desirable no | 
|  | // matter what.  There can be two uses by the same instruction. | 
|  | if (ExtVal->use_empty() || | 
|  | !ExtVal->use_begin()->isOnlyUserOf(ExtVal.getNode())) | 
|  | return true; | 
|  |  | 
|  | SDNode *U = *ExtVal->use_begin(); | 
|  | if ((U->getOpcode() == ISD::ADD || U->getOpcode() == ISD::SUB || | 
|  | U->getOpcode() == ISD::SHL || U->getOpcode() == ARMISD::VSHLIMM)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::allowTruncateForTailCall(Type *Ty1, Type *Ty2) const { | 
|  | if (!Ty1->isIntegerTy() || !Ty2->isIntegerTy()) | 
|  | return false; | 
|  |  | 
|  | if (!isTypeLegal(EVT::getEVT(Ty1))) | 
|  | return false; | 
|  |  | 
|  | assert(Ty1->getPrimitiveSizeInBits() <= 64 && "i128 is probably not a noop"); | 
|  |  | 
|  | // Assuming the caller doesn't have a zeroext or signext return parameter, | 
|  | // truncation all the way down to i1 is valid. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | int ARMTargetLowering::getScalingFactorCost(const DataLayout &DL, | 
|  | const AddrMode &AM, Type *Ty, | 
|  | unsigned AS) const { | 
|  | if (isLegalAddressingMode(DL, AM, Ty, AS)) { | 
|  | if (Subtarget->hasFPAO()) | 
|  | return AM.Scale < 0 ? 1 : 0; // positive offsets execute faster | 
|  | return 0; | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /// isFMAFasterThanFMulAndFAdd - Return true if an FMA operation is faster | 
|  | /// than a pair of fmul and fadd instructions. fmuladd intrinsics will be | 
|  | /// expanded to FMAs when this method returns true, otherwise fmuladd is | 
|  | /// expanded to fmul + fadd. | 
|  | /// | 
|  | /// ARM supports both fused and unfused multiply-add operations; we already | 
|  | /// lower a pair of fmul and fadd to the latter so it's not clear that there | 
|  | /// would be a gain or that the gain would be worthwhile enough to risk | 
|  | /// correctness bugs. | 
|  | /// | 
|  | /// For MVE, we set this to true as it helps simplify the need for some | 
|  | /// patterns (and we don't have the non-fused floating point instruction). | 
|  | bool ARMTargetLowering::isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, | 
|  | EVT VT) const { | 
|  | if (!VT.isSimple()) | 
|  | return false; | 
|  |  | 
|  | switch (VT.getSimpleVT().SimpleTy) { | 
|  | case MVT::v4f32: | 
|  | case MVT::v8f16: | 
|  | return Subtarget->hasMVEFloatOps(); | 
|  | case MVT::f16: | 
|  | return Subtarget->useFPVFMx16(); | 
|  | case MVT::f32: | 
|  | return Subtarget->useFPVFMx(); | 
|  | case MVT::f64: | 
|  | return Subtarget->useFPVFMx64(); | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool isLegalT1AddressImmediate(int64_t V, EVT VT) { | 
|  | if (V < 0) | 
|  | return false; | 
|  |  | 
|  | unsigned Scale = 1; | 
|  | switch (VT.getSimpleVT().SimpleTy) { | 
|  | case MVT::i1: | 
|  | case MVT::i8: | 
|  | // Scale == 1; | 
|  | break; | 
|  | case MVT::i16: | 
|  | // Scale == 2; | 
|  | Scale = 2; | 
|  | break; | 
|  | default: | 
|  | // On thumb1 we load most things (i32, i64, floats, etc) with a LDR | 
|  | // Scale == 4; | 
|  | Scale = 4; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if ((V & (Scale - 1)) != 0) | 
|  | return false; | 
|  | return isUInt<5>(V / Scale); | 
|  | } | 
|  |  | 
|  | static bool isLegalT2AddressImmediate(int64_t V, EVT VT, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (!VT.isInteger() && !VT.isFloatingPoint()) | 
|  | return false; | 
|  | if (VT.isVector() && Subtarget->hasNEON()) | 
|  | return false; | 
|  | if (VT.isVector() && VT.isFloatingPoint() && Subtarget->hasMVEIntegerOps() && | 
|  | !Subtarget->hasMVEFloatOps()) | 
|  | return false; | 
|  |  | 
|  | bool IsNeg = false; | 
|  | if (V < 0) { | 
|  | IsNeg = true; | 
|  | V = -V; | 
|  | } | 
|  |  | 
|  | unsigned NumBytes = std::max((unsigned)VT.getSizeInBits() / 8, 1U); | 
|  |  | 
|  | // MVE: size * imm7 | 
|  | if (VT.isVector() && Subtarget->hasMVEIntegerOps()) { | 
|  | switch (VT.getSimpleVT().getVectorElementType().SimpleTy) { | 
|  | case MVT::i32: | 
|  | case MVT::f32: | 
|  | return isShiftedUInt<7,2>(V); | 
|  | case MVT::i16: | 
|  | case MVT::f16: | 
|  | return isShiftedUInt<7,1>(V); | 
|  | case MVT::i8: | 
|  | return isUInt<7>(V); | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | // half VLDR: 2 * imm8 | 
|  | if (VT.isFloatingPoint() && NumBytes == 2 && Subtarget->hasFPRegs16()) | 
|  | return isShiftedUInt<8, 1>(V); | 
|  | // VLDR and LDRD: 4 * imm8 | 
|  | if ((VT.isFloatingPoint() && Subtarget->hasVFP2Base()) || NumBytes == 8) | 
|  | return isShiftedUInt<8, 2>(V); | 
|  |  | 
|  | if (NumBytes == 1 || NumBytes == 2 || NumBytes == 4) { | 
|  | // + imm12 or - imm8 | 
|  | if (IsNeg) | 
|  | return isUInt<8>(V); | 
|  | return isUInt<12>(V); | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// isLegalAddressImmediate - Return true if the integer value can be used | 
|  | /// as the offset of the target addressing mode for load / store of the | 
|  | /// given type. | 
|  | static bool isLegalAddressImmediate(int64_t V, EVT VT, | 
|  | const ARMSubtarget *Subtarget) { | 
|  | if (V == 0) | 
|  | return true; | 
|  |  | 
|  | if (!VT.isSimple()) | 
|  | return false; | 
|  |  | 
|  | if (Subtarget->isThumb1Only()) | 
|  | return isLegalT1AddressImmediate(V, VT); | 
|  | else if (Subtarget->isThumb2()) | 
|  | return isLegalT2AddressImmediate(V, VT, Subtarget); | 
|  |  | 
|  | // ARM mode. | 
|  | if (V < 0) | 
|  | V = - V; | 
|  | switch (VT.getSimpleVT().SimpleTy) { | 
|  | default: return false; | 
|  | case MVT::i1: | 
|  | case MVT::i8: | 
|  | case MVT::i32: | 
|  | // +- imm12 | 
|  | return isUInt<12>(V); | 
|  | case MVT::i16: | 
|  | // +- imm8 | 
|  | return isUInt<8>(V); | 
|  | case MVT::f32: | 
|  | case MVT::f64: | 
|  | if (!Subtarget->hasVFP2Base()) // FIXME: NEON? | 
|  | return false; | 
|  | return isShiftedUInt<8, 2>(V); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isLegalT2ScaledAddressingMode(const AddrMode &AM, | 
|  | EVT VT) const { | 
|  | int Scale = AM.Scale; | 
|  | if (Scale < 0) | 
|  | return false; | 
|  |  | 
|  | switch (VT.getSimpleVT().SimpleTy) { | 
|  | default: return false; | 
|  | case MVT::i1: | 
|  | case MVT::i8: | 
|  | case MVT::i16: | 
|  | case MVT::i32: | 
|  | if (Scale == 1) | 
|  | return true; | 
|  | // r + r << imm | 
|  | Scale = Scale & ~1; | 
|  | return Scale == 2 || Scale == 4 || Scale == 8; | 
|  | case MVT::i64: | 
|  | // FIXME: What are we trying to model here? ldrd doesn't have an r + r | 
|  | // version in Thumb mode. | 
|  | // r + r | 
|  | if (Scale == 1) | 
|  | return true; | 
|  | // r * 2 (this can be lowered to r + r). | 
|  | if (!AM.HasBaseReg && Scale == 2) | 
|  | return true; | 
|  | return false; | 
|  | case MVT::isVoid: | 
|  | // Note, we allow "void" uses (basically, uses that aren't loads or | 
|  | // stores), because arm allows folding a scale into many arithmetic | 
|  | // operations.  This should be made more precise and revisited later. | 
|  |  | 
|  | // Allow r << imm, but the imm has to be a multiple of two. | 
|  | if (Scale & 1) return false; | 
|  | return isPowerOf2_32(Scale); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isLegalT1ScaledAddressingMode(const AddrMode &AM, | 
|  | EVT VT) const { | 
|  | const int Scale = AM.Scale; | 
|  |  | 
|  | // Negative scales are not supported in Thumb1. | 
|  | if (Scale < 0) | 
|  | return false; | 
|  |  | 
|  | // Thumb1 addressing modes do not support register scaling excepting the | 
|  | // following cases: | 
|  | // 1. Scale == 1 means no scaling. | 
|  | // 2. Scale == 2 this can be lowered to r + r if there is no base register. | 
|  | return (Scale == 1) || (!AM.HasBaseReg && Scale == 2); | 
|  | } | 
|  |  | 
|  | /// isLegalAddressingMode - Return true if the addressing mode represented | 
|  | /// by AM is legal for this target, for a load/store of the specified type. | 
|  | bool ARMTargetLowering::isLegalAddressingMode(const DataLayout &DL, | 
|  | const AddrMode &AM, Type *Ty, | 
|  | unsigned AS, Instruction *I) const { | 
|  | EVT VT = getValueType(DL, Ty, true); | 
|  | if (!isLegalAddressImmediate(AM.BaseOffs, VT, Subtarget)) | 
|  | return false; | 
|  |  | 
|  | // Can never fold addr of global into load/store. | 
|  | if (AM.BaseGV) | 
|  | return false; | 
|  |  | 
|  | switch (AM.Scale) { | 
|  | case 0:  // no scale reg, must be "r+i" or "r", or "i". | 
|  | break; | 
|  | default: | 
|  | // ARM doesn't support any R+R*scale+imm addr modes. | 
|  | if (AM.BaseOffs) | 
|  | return false; | 
|  |  | 
|  | if (!VT.isSimple()) | 
|  | return false; | 
|  |  | 
|  | if (Subtarget->isThumb1Only()) | 
|  | return isLegalT1ScaledAddressingMode(AM, VT); | 
|  |  | 
|  | if (Subtarget->isThumb2()) | 
|  | return isLegalT2ScaledAddressingMode(AM, VT); | 
|  |  | 
|  | int Scale = AM.Scale; | 
|  | switch (VT.getSimpleVT().SimpleTy) { | 
|  | default: return false; | 
|  | case MVT::i1: | 
|  | case MVT::i8: | 
|  | case MVT::i32: | 
|  | if (Scale < 0) Scale = -Scale; | 
|  | if (Scale == 1) | 
|  | return true; | 
|  | // r + r << imm | 
|  | return isPowerOf2_32(Scale & ~1); | 
|  | case MVT::i16: | 
|  | case MVT::i64: | 
|  | // r +/- r | 
|  | if (Scale == 1 || (AM.HasBaseReg && Scale == -1)) | 
|  | return true; | 
|  | // r * 2 (this can be lowered to r + r). | 
|  | if (!AM.HasBaseReg && Scale == 2) | 
|  | return true; | 
|  | return false; | 
|  |  | 
|  | case MVT::isVoid: | 
|  | // Note, we allow "void" uses (basically, uses that aren't loads or | 
|  | // stores), because arm allows folding a scale into many arithmetic | 
|  | // operations.  This should be made more precise and revisited later. | 
|  |  | 
|  | // Allow r << imm, but the imm has to be a multiple of two. | 
|  | if (Scale & 1) return false; | 
|  | return isPowerOf2_32(Scale); | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// isLegalICmpImmediate - Return true if the specified immediate is legal | 
|  | /// icmp immediate, that is the target has icmp instructions which can compare | 
|  | /// a register against the immediate without having to materialize the | 
|  | /// immediate into a register. | 
|  | bool ARMTargetLowering::isLegalICmpImmediate(int64_t Imm) const { | 
|  | // Thumb2 and ARM modes can use cmn for negative immediates. | 
|  | if (!Subtarget->isThumb()) | 
|  | return ARM_AM::getSOImmVal((uint32_t)Imm) != -1 || | 
|  | ARM_AM::getSOImmVal(-(uint32_t)Imm) != -1; | 
|  | if (Subtarget->isThumb2()) | 
|  | return ARM_AM::getT2SOImmVal((uint32_t)Imm) != -1 || | 
|  | ARM_AM::getT2SOImmVal(-(uint32_t)Imm) != -1; | 
|  | // Thumb1 doesn't have cmn, and only 8-bit immediates. | 
|  | return Imm >= 0 && Imm <= 255; | 
|  | } | 
|  |  | 
|  | /// isLegalAddImmediate - Return true if the specified immediate is a legal add | 
|  | /// *or sub* immediate, that is the target has add or sub instructions which can | 
|  | /// add a register with the immediate without having to materialize the | 
|  | /// immediate into a register. | 
|  | bool ARMTargetLowering::isLegalAddImmediate(int64_t Imm) const { | 
|  | // Same encoding for add/sub, just flip the sign. | 
|  | int64_t AbsImm = std::abs(Imm); | 
|  | if (!Subtarget->isThumb()) | 
|  | return ARM_AM::getSOImmVal(AbsImm) != -1; | 
|  | if (Subtarget->isThumb2()) | 
|  | return ARM_AM::getT2SOImmVal(AbsImm) != -1; | 
|  | // Thumb1 only has 8-bit unsigned immediate. | 
|  | return AbsImm >= 0 && AbsImm <= 255; | 
|  | } | 
|  |  | 
|  | static bool getARMIndexedAddressParts(SDNode *Ptr, EVT VT, | 
|  | bool isSEXTLoad, SDValue &Base, | 
|  | SDValue &Offset, bool &isInc, | 
|  | SelectionDAG &DAG) { | 
|  | if (Ptr->getOpcode() != ISD::ADD && Ptr->getOpcode() != ISD::SUB) | 
|  | return false; | 
|  |  | 
|  | if (VT == MVT::i16 || ((VT == MVT::i8 || VT == MVT::i1) && isSEXTLoad)) { | 
|  | // AddressingMode 3 | 
|  | Base = Ptr->getOperand(0); | 
|  | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Ptr->getOperand(1))) { | 
|  | int RHSC = (int)RHS->getZExtValue(); | 
|  | if (RHSC < 0 && RHSC > -256) { | 
|  | assert(Ptr->getOpcode() == ISD::ADD); | 
|  | isInc = false; | 
|  | Offset = DAG.getConstant(-RHSC, SDLoc(Ptr), RHS->getValueType(0)); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | isInc = (Ptr->getOpcode() == ISD::ADD); | 
|  | Offset = Ptr->getOperand(1); | 
|  | return true; | 
|  | } else if (VT == MVT::i32 || VT == MVT::i8 || VT == MVT::i1) { | 
|  | // AddressingMode 2 | 
|  | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Ptr->getOperand(1))) { | 
|  | int RHSC = (int)RHS->getZExtValue(); | 
|  | if (RHSC < 0 && RHSC > -0x1000) { | 
|  | assert(Ptr->getOpcode() == ISD::ADD); | 
|  | isInc = false; | 
|  | Offset = DAG.getConstant(-RHSC, SDLoc(Ptr), RHS->getValueType(0)); | 
|  | Base = Ptr->getOperand(0); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Ptr->getOpcode() == ISD::ADD) { | 
|  | isInc = true; | 
|  | ARM_AM::ShiftOpc ShOpcVal= | 
|  | ARM_AM::getShiftOpcForNode(Ptr->getOperand(0).getOpcode()); | 
|  | if (ShOpcVal != ARM_AM::no_shift) { | 
|  | Base = Ptr->getOperand(1); | 
|  | Offset = Ptr->getOperand(0); | 
|  | } else { | 
|  | Base = Ptr->getOperand(0); | 
|  | Offset = Ptr->getOperand(1); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | isInc = (Ptr->getOpcode() == ISD::ADD); | 
|  | Base = Ptr->getOperand(0); | 
|  | Offset = Ptr->getOperand(1); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // FIXME: Use VLDM / VSTM to emulate indexed FP load / store. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool getT2IndexedAddressParts(SDNode *Ptr, EVT VT, | 
|  | bool isSEXTLoad, SDValue &Base, | 
|  | SDValue &Offset, bool &isInc, | 
|  | SelectionDAG &DAG) { | 
|  | if (Ptr->getOpcode() != ISD::ADD && Ptr->getOpcode() != ISD::SUB) | 
|  | return false; | 
|  |  | 
|  | Base = Ptr->getOperand(0); | 
|  | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Ptr->getOperand(1))) { | 
|  | int RHSC = (int)RHS->getZExtValue(); | 
|  | if (RHSC < 0 && RHSC > -0x100) { // 8 bits. | 
|  | assert(Ptr->getOpcode() == ISD::ADD); | 
|  | isInc = false; | 
|  | Offset = DAG.getConstant(-RHSC, SDLoc(Ptr), RHS->getValueType(0)); | 
|  | return true; | 
|  | } else if (RHSC > 0 && RHSC < 0x100) { // 8 bit, no zero. | 
|  | isInc = Ptr->getOpcode() == ISD::ADD; | 
|  | Offset = DAG.getConstant(RHSC, SDLoc(Ptr), RHS->getValueType(0)); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool getMVEIndexedAddressParts(SDNode *Ptr, EVT VT, unsigned Align, | 
|  | bool isSEXTLoad, bool IsMasked, bool isLE, | 
|  | SDValue &Base, SDValue &Offset, | 
|  | bool &isInc, SelectionDAG &DAG) { | 
|  | if (Ptr->getOpcode() != ISD::ADD && Ptr->getOpcode() != ISD::SUB) | 
|  | return false; | 
|  | if (!isa<ConstantSDNode>(Ptr->getOperand(1))) | 
|  | return false; | 
|  |  | 
|  | // We allow LE non-masked loads to change the type (for example use a vldrb.8 | 
|  | // as opposed to a vldrw.32). This can allow extra addressing modes or | 
|  | // alignments for what is otherwise an equivalent instruction. | 
|  | bool CanChangeType = isLE && !IsMasked; | 
|  |  | 
|  | ConstantSDNode *RHS = cast<ConstantSDNode>(Ptr->getOperand(1)); | 
|  | int RHSC = (int)RHS->getZExtValue(); | 
|  |  | 
|  | auto IsInRange = [&](int RHSC, int Limit, int Scale) { | 
|  | if (RHSC < 0 && RHSC > -Limit * Scale && RHSC % Scale == 0) { | 
|  | assert(Ptr->getOpcode() == ISD::ADD); | 
|  | isInc = false; | 
|  | Offset = DAG.getConstant(-RHSC, SDLoc(Ptr), RHS->getValueType(0)); | 
|  | return true; | 
|  | } else if (RHSC > 0 && RHSC < Limit * Scale && RHSC % Scale == 0) { | 
|  | isInc = Ptr->getOpcode() == ISD::ADD; | 
|  | Offset = DAG.getConstant(RHSC, SDLoc(Ptr), RHS->getValueType(0)); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | }; | 
|  |  | 
|  | // Try to find a matching instruction based on s/zext, Alignment, Offset and | 
|  | // (in BE/masked) type. | 
|  | Base = Ptr->getOperand(0); | 
|  | if (VT == MVT::v4i16) { | 
|  | if (Align >= 2 && IsInRange(RHSC, 0x80, 2)) | 
|  | return true; | 
|  | } else if (VT == MVT::v4i8 || VT == MVT::v8i8) { | 
|  | if (IsInRange(RHSC, 0x80, 1)) | 
|  | return true; | 
|  | } else if (Align >= 4 && | 
|  | (CanChangeType || VT == MVT::v4i32 || VT == MVT::v4f32) && | 
|  | IsInRange(RHSC, 0x80, 4)) | 
|  | return true; | 
|  | else if (Align >= 2 && | 
|  | (CanChangeType || VT == MVT::v8i16 || VT == MVT::v8f16) && | 
|  | IsInRange(RHSC, 0x80, 2)) | 
|  | return true; | 
|  | else if ((CanChangeType || VT == MVT::v16i8) && IsInRange(RHSC, 0x80, 1)) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// getPreIndexedAddressParts - returns true by value, base pointer and | 
|  | /// offset pointer and addressing mode by reference if the node's address | 
|  | /// can be legally represented as pre-indexed load / store address. | 
|  | bool | 
|  | ARMTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base, | 
|  | SDValue &Offset, | 
|  | ISD::MemIndexedMode &AM, | 
|  | SelectionDAG &DAG) const { | 
|  | if (Subtarget->isThumb1Only()) | 
|  | return false; | 
|  |  | 
|  | EVT VT; | 
|  | SDValue Ptr; | 
|  | unsigned Align; | 
|  | bool isSEXTLoad = false; | 
|  | bool IsMasked = false; | 
|  | if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) { | 
|  | Ptr = LD->getBasePtr(); | 
|  | VT = LD->getMemoryVT(); | 
|  | Align = LD->getAlignment(); | 
|  | isSEXTLoad = LD->getExtensionType() == ISD::SEXTLOAD; | 
|  | } else if (StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) { | 
|  | Ptr = ST->getBasePtr(); | 
|  | VT = ST->getMemoryVT(); | 
|  | Align = ST->getAlignment(); | 
|  | } else if (MaskedLoadSDNode *LD = dyn_cast<MaskedLoadSDNode>(N)) { | 
|  | Ptr = LD->getBasePtr(); | 
|  | VT = LD->getMemoryVT(); | 
|  | Align = LD->getAlignment(); | 
|  | isSEXTLoad = LD->getExtensionType() == ISD::SEXTLOAD; | 
|  | IsMasked = true; | 
|  | } else if (MaskedStoreSDNode *ST = dyn_cast<MaskedStoreSDNode>(N)) { | 
|  | Ptr = ST->getBasePtr(); | 
|  | VT = ST->getMemoryVT(); | 
|  | Align = ST->getAlignment(); | 
|  | IsMasked = true; | 
|  | } else | 
|  | return false; | 
|  |  | 
|  | bool isInc; | 
|  | bool isLegal = false; | 
|  | if (VT.isVector()) | 
|  | isLegal = Subtarget->hasMVEIntegerOps() && | 
|  | getMVEIndexedAddressParts(Ptr.getNode(), VT, Align, isSEXTLoad, | 
|  | IsMasked, Subtarget->isLittle(), Base, | 
|  | Offset, isInc, DAG); | 
|  | else { | 
|  | if (Subtarget->isThumb2()) | 
|  | isLegal = getT2IndexedAddressParts(Ptr.getNode(), VT, isSEXTLoad, Base, | 
|  | Offset, isInc, DAG); | 
|  | else | 
|  | isLegal = getARMIndexedAddressParts(Ptr.getNode(), VT, isSEXTLoad, Base, | 
|  | Offset, isInc, DAG); | 
|  | } | 
|  | if (!isLegal) | 
|  | return false; | 
|  |  | 
|  | AM = isInc ? ISD::PRE_INC : ISD::PRE_DEC; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// getPostIndexedAddressParts - returns true by value, base pointer and | 
|  | /// offset pointer and addressing mode by reference if this node can be | 
|  | /// combined with a load / store to form a post-indexed load / store. | 
|  | bool ARMTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op, | 
|  | SDValue &Base, | 
|  | SDValue &Offset, | 
|  | ISD::MemIndexedMode &AM, | 
|  | SelectionDAG &DAG) const { | 
|  | EVT VT; | 
|  | SDValue Ptr; | 
|  | unsigned Align; | 
|  | bool isSEXTLoad = false, isNonExt; | 
|  | bool IsMasked = false; | 
|  | if (LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) { | 
|  | VT = LD->getMemoryVT(); | 
|  | Ptr = LD->getBasePtr(); | 
|  | Align = LD->getAlignment(); | 
|  | isSEXTLoad = LD->getExtensionType() == ISD::SEXTLOAD; | 
|  | isNonExt = LD->getExtensionType() == ISD::NON_EXTLOAD; | 
|  | } else if (StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) { | 
|  | VT = ST->getMemoryVT(); | 
|  | Ptr = ST->getBasePtr(); | 
|  | Align = ST->getAlignment(); | 
|  | isNonExt = !ST->isTruncatingStore(); | 
|  | } else if (MaskedLoadSDNode *LD = dyn_cast<MaskedLoadSDNode>(N)) { | 
|  | VT = LD->getMemoryVT(); | 
|  | Ptr = LD->getBasePtr(); | 
|  | Align = LD->getAlignment(); | 
|  | isSEXTLoad = LD->getExtensionType() == ISD::SEXTLOAD; | 
|  | isNonExt = LD->getExtensionType() == ISD::NON_EXTLOAD; | 
|  | IsMasked = true; | 
|  | } else if (MaskedStoreSDNode *ST = dyn_cast<MaskedStoreSDNode>(N)) { | 
|  | VT = ST->getMemoryVT(); | 
|  | Ptr = ST->getBasePtr(); | 
|  | Align = ST->getAlignment(); | 
|  | isNonExt = !ST->isTruncatingStore(); | 
|  | IsMasked = true; | 
|  | } else | 
|  | return false; | 
|  |  | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | // Thumb-1 can do a limited post-inc load or store as an updating LDM. It | 
|  | // must be non-extending/truncating, i32, with an offset of 4. | 
|  | assert(Op->getValueType(0) == MVT::i32 && "Non-i32 post-inc op?!"); | 
|  | if (Op->getOpcode() != ISD::ADD || !isNonExt) | 
|  | return false; | 
|  | auto *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1)); | 
|  | if (!RHS || RHS->getZExtValue() != 4) | 
|  | return false; | 
|  |  | 
|  | Offset = Op->getOperand(1); | 
|  | Base = Op->getOperand(0); | 
|  | AM = ISD::POST_INC; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool isInc; | 
|  | bool isLegal = false; | 
|  | if (VT.isVector()) | 
|  | isLegal = Subtarget->hasMVEIntegerOps() && | 
|  | getMVEIndexedAddressParts(Op, VT, Align, isSEXTLoad, IsMasked, | 
|  | Subtarget->isLittle(), Base, Offset, | 
|  | isInc, DAG); | 
|  | else { | 
|  | if (Subtarget->isThumb2()) | 
|  | isLegal = getT2IndexedAddressParts(Op, VT, isSEXTLoad, Base, Offset, | 
|  | isInc, DAG); | 
|  | else | 
|  | isLegal = getARMIndexedAddressParts(Op, VT, isSEXTLoad, Base, Offset, | 
|  | isInc, DAG); | 
|  | } | 
|  | if (!isLegal) | 
|  | return false; | 
|  |  | 
|  | if (Ptr != Base) { | 
|  | // Swap base ptr and offset to catch more post-index load / store when | 
|  | // it's legal. In Thumb2 mode, offset must be an immediate. | 
|  | if (Ptr == Offset && Op->getOpcode() == ISD::ADD && | 
|  | !Subtarget->isThumb2()) | 
|  | std::swap(Base, Offset); | 
|  |  | 
|  | // Post-indexed load / store update the base pointer. | 
|  | if (Ptr != Base) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | AM = isInc ? ISD::POST_INC : ISD::POST_DEC; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::computeKnownBitsForTargetNode(const SDValue Op, | 
|  | KnownBits &Known, | 
|  | const APInt &DemandedElts, | 
|  | const SelectionDAG &DAG, | 
|  | unsigned Depth) const { | 
|  | unsigned BitWidth = Known.getBitWidth(); | 
|  | Known.resetAll(); | 
|  | switch (Op.getOpcode()) { | 
|  | default: break; | 
|  | case ARMISD::ADDC: | 
|  | case ARMISD::ADDE: | 
|  | case ARMISD::SUBC: | 
|  | case ARMISD::SUBE: | 
|  | // Special cases when we convert a carry to a boolean. | 
|  | if (Op.getResNo() == 0) { | 
|  | SDValue LHS = Op.getOperand(0); | 
|  | SDValue RHS = Op.getOperand(1); | 
|  | // (ADDE 0, 0, C) will give us a single bit. | 
|  | if (Op->getOpcode() == ARMISD::ADDE && isNullConstant(LHS) && | 
|  | isNullConstant(RHS)) { | 
|  | Known.Zero |= APInt::getHighBitsSet(BitWidth, BitWidth - 1); | 
|  | return; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case ARMISD::CMOV: { | 
|  | // Bits are known zero/one if known on the LHS and RHS. | 
|  | Known = DAG.computeKnownBits(Op.getOperand(0), Depth+1); | 
|  | if (Known.isUnknown()) | 
|  | return; | 
|  |  | 
|  | KnownBits KnownRHS = DAG.computeKnownBits(Op.getOperand(1), Depth+1); | 
|  | Known.Zero &= KnownRHS.Zero; | 
|  | Known.One  &= KnownRHS.One; | 
|  | return; | 
|  | } | 
|  | case ISD::INTRINSIC_W_CHAIN: { | 
|  | ConstantSDNode *CN = cast<ConstantSDNode>(Op->getOperand(1)); | 
|  | Intrinsic::ID IntID = static_cast<Intrinsic::ID>(CN->getZExtValue()); | 
|  | switch (IntID) { | 
|  | default: return; | 
|  | case Intrinsic::arm_ldaex: | 
|  | case Intrinsic::arm_ldrex: { | 
|  | EVT VT = cast<MemIntrinsicSDNode>(Op)->getMemoryVT(); | 
|  | unsigned MemBits = VT.getScalarSizeInBits(); | 
|  | Known.Zero |= APInt::getHighBitsSet(BitWidth, BitWidth - MemBits); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  | case ARMISD::BFI: { | 
|  | // Conservatively, we can recurse down the first operand | 
|  | // and just mask out all affected bits. | 
|  | Known = DAG.computeKnownBits(Op.getOperand(0), Depth + 1); | 
|  |  | 
|  | // The operand to BFI is already a mask suitable for removing the bits it | 
|  | // sets. | 
|  | ConstantSDNode *CI = cast<ConstantSDNode>(Op.getOperand(2)); | 
|  | const APInt &Mask = CI->getAPIntValue(); | 
|  | Known.Zero &= Mask; | 
|  | Known.One &= Mask; | 
|  | return; | 
|  | } | 
|  | case ARMISD::VGETLANEs: | 
|  | case ARMISD::VGETLANEu: { | 
|  | const SDValue &SrcSV = Op.getOperand(0); | 
|  | EVT VecVT = SrcSV.getValueType(); | 
|  | assert(VecVT.isVector() && "VGETLANE expected a vector type"); | 
|  | const unsigned NumSrcElts = VecVT.getVectorNumElements(); | 
|  | ConstantSDNode *Pos = cast<ConstantSDNode>(Op.getOperand(1).getNode()); | 
|  | assert(Pos->getAPIntValue().ult(NumSrcElts) && | 
|  | "VGETLANE index out of bounds"); | 
|  | unsigned Idx = Pos->getZExtValue(); | 
|  | APInt DemandedElt = APInt::getOneBitSet(NumSrcElts, Idx); | 
|  | Known = DAG.computeKnownBits(SrcSV, DemandedElt, Depth + 1); | 
|  |  | 
|  | EVT VT = Op.getValueType(); | 
|  | const unsigned DstSz = VT.getScalarSizeInBits(); | 
|  | const unsigned SrcSz = VecVT.getVectorElementType().getSizeInBits(); | 
|  | (void)SrcSz; | 
|  | assert(SrcSz == Known.getBitWidth()); | 
|  | assert(DstSz > SrcSz); | 
|  | if (Op.getOpcode() == ARMISD::VGETLANEs) | 
|  | Known = Known.sext(DstSz); | 
|  | else { | 
|  | Known = Known.zext(DstSz); | 
|  | } | 
|  | assert(DstSz == Known.getBitWidth()); | 
|  | break; | 
|  | } | 
|  | case ARMISD::VMOVrh: { | 
|  | KnownBits KnownOp = DAG.computeKnownBits(Op->getOperand(0), Depth + 1); | 
|  | assert(KnownOp.getBitWidth() == 16); | 
|  | Known = KnownOp.zext(32); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool | 
|  | ARMTargetLowering::targetShrinkDemandedConstant(SDValue Op, | 
|  | const APInt &DemandedAPInt, | 
|  | TargetLoweringOpt &TLO) const { | 
|  | // Delay optimization, so we don't have to deal with illegal types, or block | 
|  | // optimizations. | 
|  | if (!TLO.LegalOps) | 
|  | return false; | 
|  |  | 
|  | // Only optimize AND for now. | 
|  | if (Op.getOpcode() != ISD::AND) | 
|  | return false; | 
|  |  | 
|  | EVT VT = Op.getValueType(); | 
|  |  | 
|  | // Ignore vectors. | 
|  | if (VT.isVector()) | 
|  | return false; | 
|  |  | 
|  | assert(VT == MVT::i32 && "Unexpected integer type"); | 
|  |  | 
|  | // Make sure the RHS really is a constant. | 
|  | ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op.getOperand(1)); | 
|  | if (!C) | 
|  | return false; | 
|  |  | 
|  | unsigned Mask = C->getZExtValue(); | 
|  |  | 
|  | unsigned Demanded = DemandedAPInt.getZExtValue(); | 
|  | unsigned ShrunkMask = Mask & Demanded; | 
|  | unsigned ExpandedMask = Mask | ~Demanded; | 
|  |  | 
|  | // If the mask is all zeros, let the target-independent code replace the | 
|  | // result with zero. | 
|  | if (ShrunkMask == 0) | 
|  | return false; | 
|  |  | 
|  | // If the mask is all ones, erase the AND. (Currently, the target-independent | 
|  | // code won't do this, so we have to do it explicitly to avoid an infinite | 
|  | // loop in obscure cases.) | 
|  | if (ExpandedMask == ~0U) | 
|  | return TLO.CombineTo(Op, Op.getOperand(0)); | 
|  |  | 
|  | auto IsLegalMask = [ShrunkMask, ExpandedMask](unsigned Mask) -> bool { | 
|  | return (ShrunkMask & Mask) == ShrunkMask && (~ExpandedMask & Mask) == 0; | 
|  | }; | 
|  | auto UseMask = [Mask, Op, VT, &TLO](unsigned NewMask) -> bool { | 
|  | if (NewMask == Mask) | 
|  | return true; | 
|  | SDLoc DL(Op); | 
|  | SDValue NewC = TLO.DAG.getConstant(NewMask, DL, VT); | 
|  | SDValue NewOp = TLO.DAG.getNode(ISD::AND, DL, VT, Op.getOperand(0), NewC); | 
|  | return TLO.CombineTo(Op, NewOp); | 
|  | }; | 
|  |  | 
|  | // Prefer uxtb mask. | 
|  | if (IsLegalMask(0xFF)) | 
|  | return UseMask(0xFF); | 
|  |  | 
|  | // Prefer uxth mask. | 
|  | if (IsLegalMask(0xFFFF)) | 
|  | return UseMask(0xFFFF); | 
|  |  | 
|  | // [1, 255] is Thumb1 movs+ands, legal immediate for ARM/Thumb2. | 
|  | // FIXME: Prefer a contiguous sequence of bits for other optimizations. | 
|  | if (ShrunkMask < 256) | 
|  | return UseMask(ShrunkMask); | 
|  |  | 
|  | // [-256, -2] is Thumb1 movs+bics, legal immediate for ARM/Thumb2. | 
|  | // FIXME: Prefer a contiguous sequence of bits for other optimizations. | 
|  | if ((int)ExpandedMask <= -2 && (int)ExpandedMask >= -256) | 
|  | return UseMask(ExpandedMask); | 
|  |  | 
|  | // Potential improvements: | 
|  | // | 
|  | // We could try to recognize lsls+lsrs or lsrs+lsls pairs here. | 
|  | // We could try to prefer Thumb1 immediates which can be lowered to a | 
|  | // two-instruction sequence. | 
|  | // We could try to recognize more legal ARM/Thumb2 immediates here. | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::SimplifyDemandedBitsForTargetNode( | 
|  | SDValue Op, const APInt &OriginalDemandedBits, | 
|  | const APInt &OriginalDemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, | 
|  | unsigned Depth) const { | 
|  | unsigned Opc = Op.getOpcode(); | 
|  |  | 
|  | switch (Opc) { | 
|  | case ARMISD::ASRL: | 
|  | case ARMISD::LSRL: { | 
|  | // If this is result 0 and the other result is unused, see if the demand | 
|  | // bits allow us to shrink this long shift into a standard small shift in | 
|  | // the opposite direction. | 
|  | if (Op.getResNo() == 0 && !Op->hasAnyUseOfValue(1) && | 
|  | isa<ConstantSDNode>(Op->getOperand(2))) { | 
|  | unsigned ShAmt = Op->getConstantOperandVal(2); | 
|  | if (ShAmt < 32 && OriginalDemandedBits.isSubsetOf( | 
|  | APInt::getAllOnesValue(32) << (32 - ShAmt))) | 
|  | return TLO.CombineTo( | 
|  | Op, TLO.DAG.getNode( | 
|  | ISD::SHL, SDLoc(Op), MVT::i32, Op.getOperand(1), | 
|  | TLO.DAG.getConstant(32 - ShAmt, SDLoc(Op), MVT::i32))); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return TargetLowering::SimplifyDemandedBitsForTargetNode( | 
|  | Op, OriginalDemandedBits, OriginalDemandedElts, Known, TLO, Depth); | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //                           ARM Inline Assembly Support | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | bool ARMTargetLowering::ExpandInlineAsm(CallInst *CI) const { | 
|  | // Looking for "rev" which is V6+. | 
|  | if (!Subtarget->hasV6Ops()) | 
|  | return false; | 
|  |  | 
|  | InlineAsm *IA = cast<InlineAsm>(CI->getCalledOperand()); | 
|  | std::string AsmStr = IA->getAsmString(); | 
|  | SmallVector<StringRef, 4> AsmPieces; | 
|  | SplitString(AsmStr, AsmPieces, ";\n"); | 
|  |  | 
|  | switch (AsmPieces.size()) { | 
|  | default: return false; | 
|  | case 1: | 
|  | AsmStr = std::string(AsmPieces[0]); | 
|  | AsmPieces.clear(); | 
|  | SplitString(AsmStr, AsmPieces, " \t,"); | 
|  |  | 
|  | // rev $0, $1 | 
|  | if (AsmPieces.size() == 3 && | 
|  | AsmPieces[0] == "rev" && AsmPieces[1] == "$0" && AsmPieces[2] == "$1" && | 
|  | IA->getConstraintString().compare(0, 4, "=l,l") == 0) { | 
|  | IntegerType *Ty = dyn_cast<IntegerType>(CI->getType()); | 
|  | if (Ty && Ty->getBitWidth() == 32) | 
|  | return IntrinsicLowering::LowerToByteSwap(CI); | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const char *ARMTargetLowering::LowerXConstraint(EVT ConstraintVT) const { | 
|  | // At this point, we have to lower this constraint to something else, so we | 
|  | // lower it to an "r" or "w". However, by doing this we will force the result | 
|  | // to be in register, while the X constraint is much more permissive. | 
|  | // | 
|  | // Although we are correct (we are free to emit anything, without | 
|  | // constraints), we might break use cases that would expect us to be more | 
|  | // efficient and emit something else. | 
|  | if (!Subtarget->hasVFP2Base()) | 
|  | return "r"; | 
|  | if (ConstraintVT.isFloatingPoint()) | 
|  | return "w"; | 
|  | if (ConstraintVT.isVector() && Subtarget->hasNEON() && | 
|  | (ConstraintVT.getSizeInBits() == 64 || | 
|  | ConstraintVT.getSizeInBits() == 128)) | 
|  | return "w"; | 
|  |  | 
|  | return "r"; | 
|  | } | 
|  |  | 
|  | /// getConstraintType - Given a constraint letter, return the type of | 
|  | /// constraint it is for this target. | 
|  | ARMTargetLowering::ConstraintType | 
|  | ARMTargetLowering::getConstraintType(StringRef Constraint) const { | 
|  | unsigned S = Constraint.size(); | 
|  | if (S == 1) { | 
|  | switch (Constraint[0]) { | 
|  | default:  break; | 
|  | case 'l': return C_RegisterClass; | 
|  | case 'w': return C_RegisterClass; | 
|  | case 'h': return C_RegisterClass; | 
|  | case 'x': return C_RegisterClass; | 
|  | case 't': return C_RegisterClass; | 
|  | case 'j': return C_Immediate; // Constant for movw. | 
|  | // An address with a single base register. Due to the way we | 
|  | // currently handle addresses it is the same as an 'r' memory constraint. | 
|  | case 'Q': return C_Memory; | 
|  | } | 
|  | } else if (S == 2) { | 
|  | switch (Constraint[0]) { | 
|  | default: break; | 
|  | case 'T': return C_RegisterClass; | 
|  | // All 'U+' constraints are addresses. | 
|  | case 'U': return C_Memory; | 
|  | } | 
|  | } | 
|  | return TargetLowering::getConstraintType(Constraint); | 
|  | } | 
|  |  | 
|  | /// Examine constraint type and operand type and determine a weight value. | 
|  | /// This object must already have been set up with the operand type | 
|  | /// and the current alternative constraint selected. | 
|  | TargetLowering::ConstraintWeight | 
|  | ARMTargetLowering::getSingleConstraintMatchWeight( | 
|  | AsmOperandInfo &info, const char *constraint) const { | 
|  | ConstraintWeight weight = CW_Invalid; | 
|  | Value *CallOperandVal = info.CallOperandVal; | 
|  | // If we don't have a value, we can't do a match, | 
|  | // but allow it at the lowest weight. | 
|  | if (!CallOperandVal) | 
|  | return CW_Default; | 
|  | Type *type = CallOperandVal->getType(); | 
|  | // Look at the constraint type. | 
|  | switch (*constraint) { | 
|  | default: | 
|  | weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint); | 
|  | break; | 
|  | case 'l': | 
|  | if (type->isIntegerTy()) { | 
|  | if (Subtarget->isThumb()) | 
|  | weight = CW_SpecificReg; | 
|  | else | 
|  | weight = CW_Register; | 
|  | } | 
|  | break; | 
|  | case 'w': | 
|  | if (type->isFloatingPointTy()) | 
|  | weight = CW_Register; | 
|  | break; | 
|  | } | 
|  | return weight; | 
|  | } | 
|  |  | 
|  | using RCPair = std::pair<unsigned, const TargetRegisterClass *>; | 
|  |  | 
|  | RCPair ARMTargetLowering::getRegForInlineAsmConstraint( | 
|  | const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { | 
|  | switch (Constraint.size()) { | 
|  | case 1: | 
|  | // GCC ARM Constraint Letters | 
|  | switch (Constraint[0]) { | 
|  | case 'l': // Low regs or general regs. | 
|  | if (Subtarget->isThumb()) | 
|  | return RCPair(0U, &ARM::tGPRRegClass); | 
|  | return RCPair(0U, &ARM::GPRRegClass); | 
|  | case 'h': // High regs or no regs. | 
|  | if (Subtarget->isThumb()) | 
|  | return RCPair(0U, &ARM::hGPRRegClass); | 
|  | break; | 
|  | case 'r': | 
|  | if (Subtarget->isThumb1Only()) | 
|  | return RCPair(0U, &ARM::tGPRRegClass); | 
|  | return RCPair(0U, &ARM::GPRRegClass); | 
|  | case 'w': | 
|  | if (VT == MVT::Other) | 
|  | break; | 
|  | if (VT == MVT::f32) | 
|  | return RCPair(0U, &ARM::SPRRegClass); | 
|  | if (VT.getSizeInBits() == 64) | 
|  | return RCPair(0U, &ARM::DPRRegClass); | 
|  | if (VT.getSizeInBits() == 128) | 
|  | return RCPair(0U, &ARM::QPRRegClass); | 
|  | break; | 
|  | case 'x': | 
|  | if (VT == MVT::Other) | 
|  | break; | 
|  | if (VT == MVT::f32) | 
|  | return RCPair(0U, &ARM::SPR_8RegClass); | 
|  | if (VT.getSizeInBits() == 64) | 
|  | return RCPair(0U, &ARM::DPR_8RegClass); | 
|  | if (VT.getSizeInBits() == 128) | 
|  | return RCPair(0U, &ARM::QPR_8RegClass); | 
|  | break; | 
|  | case 't': | 
|  | if (VT == MVT::Other) | 
|  | break; | 
|  | if (VT == MVT::f32 || VT == MVT::i32) | 
|  | return RCPair(0U, &ARM::SPRRegClass); | 
|  | if (VT.getSizeInBits() == 64) | 
|  | return RCPair(0U, &ARM::DPR_VFP2RegClass); | 
|  | if (VT.getSizeInBits() == 128) | 
|  | return RCPair(0U, &ARM::QPR_VFP2RegClass); | 
|  | break; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case 2: | 
|  | if (Constraint[0] == 'T') { | 
|  | switch (Constraint[1]) { | 
|  | default: | 
|  | break; | 
|  | case 'e': | 
|  | return RCPair(0U, &ARM::tGPREvenRegClass); | 
|  | case 'o': | 
|  | return RCPair(0U, &ARM::tGPROddRegClass); | 
|  | } | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (StringRef("{cc}").equals_lower(Constraint)) | 
|  | return std::make_pair(unsigned(ARM::CPSR), &ARM::CCRRegClass); | 
|  |  | 
|  | return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); | 
|  | } | 
|  |  | 
|  | /// LowerAsmOperandForConstraint - Lower the specified operand into the Ops | 
|  | /// vector.  If it is invalid, don't add anything to Ops. | 
|  | void ARMTargetLowering::LowerAsmOperandForConstraint(SDValue Op, | 
|  | std::string &Constraint, | 
|  | std::vector<SDValue>&Ops, | 
|  | SelectionDAG &DAG) const { | 
|  | SDValue Result; | 
|  |  | 
|  | // Currently only support length 1 constraints. | 
|  | if (Constraint.length() != 1) return; | 
|  |  | 
|  | char ConstraintLetter = Constraint[0]; | 
|  | switch (ConstraintLetter) { | 
|  | default: break; | 
|  | case 'j': | 
|  | case 'I': case 'J': case 'K': case 'L': | 
|  | case 'M': case 'N': case 'O': | 
|  | ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op); | 
|  | if (!C) | 
|  | return; | 
|  |  | 
|  | int64_t CVal64 = C->getSExtValue(); | 
|  | int CVal = (int) CVal64; | 
|  | // None of these constraints allow values larger than 32 bits.  Check | 
|  | // that the value fits in an int. | 
|  | if (CVal != CVal64) | 
|  | return; | 
|  |  | 
|  | switch (ConstraintLetter) { | 
|  | case 'j': | 
|  | // Constant suitable for movw, must be between 0 and | 
|  | // 65535. | 
|  | if (Subtarget->hasV6T2Ops() || (Subtarget->hasV8MBaselineOps())) | 
|  | if (CVal >= 0 && CVal <= 65535) | 
|  | break; | 
|  | return; | 
|  | case 'I': | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | // This must be a constant between 0 and 255, for ADD | 
|  | // immediates. | 
|  | if (CVal >= 0 && CVal <= 255) | 
|  | break; | 
|  | } else if (Subtarget->isThumb2()) { | 
|  | // A constant that can be used as an immediate value in a | 
|  | // data-processing instruction. | 
|  | if (ARM_AM::getT2SOImmVal(CVal) != -1) | 
|  | break; | 
|  | } else { | 
|  | // A constant that can be used as an immediate value in a | 
|  | // data-processing instruction. | 
|  | if (ARM_AM::getSOImmVal(CVal) != -1) | 
|  | break; | 
|  | } | 
|  | return; | 
|  |  | 
|  | case 'J': | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | // This must be a constant between -255 and -1, for negated ADD | 
|  | // immediates. This can be used in GCC with an "n" modifier that | 
|  | // prints the negated value, for use with SUB instructions. It is | 
|  | // not useful otherwise but is implemented for compatibility. | 
|  | if (CVal >= -255 && CVal <= -1) | 
|  | break; | 
|  | } else { | 
|  | // This must be a constant between -4095 and 4095. It is not clear | 
|  | // what this constraint is intended for. Implemented for | 
|  | // compatibility with GCC. | 
|  | if (CVal >= -4095 && CVal <= 4095) | 
|  | break; | 
|  | } | 
|  | return; | 
|  |  | 
|  | case 'K': | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | // A 32-bit value where only one byte has a nonzero value. Exclude | 
|  | // zero to match GCC. This constraint is used by GCC internally for | 
|  | // constants that can be loaded with a move/shift combination. | 
|  | // It is not useful otherwise but is implemented for compatibility. | 
|  | if (CVal != 0 && ARM_AM::isThumbImmShiftedVal(CVal)) | 
|  | break; | 
|  | } else if (Subtarget->isThumb2()) { | 
|  | // A constant whose bitwise inverse can be used as an immediate | 
|  | // value in a data-processing instruction. This can be used in GCC | 
|  | // with a "B" modifier that prints the inverted value, for use with | 
|  | // BIC and MVN instructions. It is not useful otherwise but is | 
|  | // implemented for compatibility. | 
|  | if (ARM_AM::getT2SOImmVal(~CVal) != -1) | 
|  | break; | 
|  | } else { | 
|  | // A constant whose bitwise inverse can be used as an immediate | 
|  | // value in a data-processing instruction. This can be used in GCC | 
|  | // with a "B" modifier that prints the inverted value, for use with | 
|  | // BIC and MVN instructions. It is not useful otherwise but is | 
|  | // implemented for compatibility. | 
|  | if (ARM_AM::getSOImmVal(~CVal) != -1) | 
|  | break; | 
|  | } | 
|  | return; | 
|  |  | 
|  | case 'L': | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | // This must be a constant between -7 and 7, | 
|  | // for 3-operand ADD/SUB immediate instructions. | 
|  | if (CVal >= -7 && CVal < 7) | 
|  | break; | 
|  | } else if (Subtarget->isThumb2()) { | 
|  | // A constant whose negation can be used as an immediate value in a | 
|  | // data-processing instruction. This can be used in GCC with an "n" | 
|  | // modifier that prints the negated value, for use with SUB | 
|  | // instructions. It is not useful otherwise but is implemented for | 
|  | // compatibility. | 
|  | if (ARM_AM::getT2SOImmVal(-CVal) != -1) | 
|  | break; | 
|  | } else { | 
|  | // A constant whose negation can be used as an immediate value in a | 
|  | // data-processing instruction. This can be used in GCC with an "n" | 
|  | // modifier that prints the negated value, for use with SUB | 
|  | // instructions. It is not useful otherwise but is implemented for | 
|  | // compatibility. | 
|  | if (ARM_AM::getSOImmVal(-CVal) != -1) | 
|  | break; | 
|  | } | 
|  | return; | 
|  |  | 
|  | case 'M': | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | // This must be a multiple of 4 between 0 and 1020, for | 
|  | // ADD sp + immediate. | 
|  | if ((CVal >= 0 && CVal <= 1020) && ((CVal & 3) == 0)) | 
|  | break; | 
|  | } else { | 
|  | // A power of two or a constant between 0 and 32.  This is used in | 
|  | // GCC for the shift amount on shifted register operands, but it is | 
|  | // useful in general for any shift amounts. | 
|  | if ((CVal >= 0 && CVal <= 32) || ((CVal & (CVal - 1)) == 0)) | 
|  | break; | 
|  | } | 
|  | return; | 
|  |  | 
|  | case 'N': | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | // This must be a constant between 0 and 31, for shift amounts. | 
|  | if (CVal >= 0 && CVal <= 31) | 
|  | break; | 
|  | } | 
|  | return; | 
|  |  | 
|  | case 'O': | 
|  | if (Subtarget->isThumb1Only()) { | 
|  | // This must be a multiple of 4 between -508 and 508, for | 
|  | // ADD/SUB sp = sp + immediate. | 
|  | if ((CVal >= -508 && CVal <= 508) && ((CVal & 3) == 0)) | 
|  | break; | 
|  | } | 
|  | return; | 
|  | } | 
|  | Result = DAG.getTargetConstant(CVal, SDLoc(Op), Op.getValueType()); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (Result.getNode()) { | 
|  | Ops.push_back(Result); | 
|  | return; | 
|  | } | 
|  | return TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); | 
|  | } | 
|  |  | 
|  | static RTLIB::Libcall getDivRemLibcall( | 
|  | const SDNode *N, MVT::SimpleValueType SVT) { | 
|  | assert((N->getOpcode() == ISD::SDIVREM || N->getOpcode() == ISD::UDIVREM || | 
|  | N->getOpcode() == ISD::SREM    || N->getOpcode() == ISD::UREM) && | 
|  | "Unhandled Opcode in getDivRemLibcall"); | 
|  | bool isSigned = N->getOpcode() == ISD::SDIVREM || | 
|  | N->getOpcode() == ISD::SREM; | 
|  | RTLIB::Libcall LC; | 
|  | switch (SVT) { | 
|  | default: llvm_unreachable("Unexpected request for libcall!"); | 
|  | case MVT::i8:  LC = isSigned ? RTLIB::SDIVREM_I8  : RTLIB::UDIVREM_I8;  break; | 
|  | case MVT::i16: LC = isSigned ? RTLIB::SDIVREM_I16 : RTLIB::UDIVREM_I16; break; | 
|  | case MVT::i32: LC = isSigned ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32; break; | 
|  | case MVT::i64: LC = isSigned ? RTLIB::SDIVREM_I64 : RTLIB::UDIVREM_I64; break; | 
|  | } | 
|  | return LC; | 
|  | } | 
|  |  | 
|  | static TargetLowering::ArgListTy getDivRemArgList( | 
|  | const SDNode *N, LLVMContext *Context, const ARMSubtarget *Subtarget) { | 
|  | assert((N->getOpcode() == ISD::SDIVREM || N->getOpcode() == ISD::UDIVREM || | 
|  | N->getOpcode() == ISD::SREM    || N->getOpcode() == ISD::UREM) && | 
|  | "Unhandled Opcode in getDivRemArgList"); | 
|  | bool isSigned = N->getOpcode() == ISD::SDIVREM || | 
|  | N->getOpcode() == ISD::SREM; | 
|  | TargetLowering::ArgListTy Args; | 
|  | TargetLowering::ArgListEntry Entry; | 
|  | for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { | 
|  | EVT ArgVT = N->getOperand(i).getValueType(); | 
|  | Type *ArgTy = ArgVT.getTypeForEVT(*Context); | 
|  | Entry.Node = N->getOperand(i); | 
|  | Entry.Ty = ArgTy; | 
|  | Entry.IsSExt = isSigned; | 
|  | Entry.IsZExt = !isSigned; | 
|  | Args.push_back(Entry); | 
|  | } | 
|  | if (Subtarget->isTargetWindows() && Args.size() >= 2) | 
|  | std::swap(Args[0], Args[1]); | 
|  | return Args; | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerDivRem(SDValue Op, SelectionDAG &DAG) const { | 
|  | assert((Subtarget->isTargetAEABI() || Subtarget->isTargetAndroid() || | 
|  | Subtarget->isTargetGNUAEABI() || Subtarget->isTargetMuslAEABI() || | 
|  | Subtarget->isTargetWindows()) && | 
|  | "Register-based DivRem lowering only"); | 
|  | unsigned Opcode = Op->getOpcode(); | 
|  | assert((Opcode == ISD::SDIVREM || Opcode == ISD::UDIVREM) && | 
|  | "Invalid opcode for Div/Rem lowering"); | 
|  | bool isSigned = (Opcode == ISD::SDIVREM); | 
|  | EVT VT = Op->getValueType(0); | 
|  | Type *Ty = VT.getTypeForEVT(*DAG.getContext()); | 
|  | SDLoc dl(Op); | 
|  |  | 
|  | // If the target has hardware divide, use divide + multiply + subtract: | 
|  | //     div = a / b | 
|  | //     rem = a - b * div | 
|  | //     return {div, rem} | 
|  | // This should be lowered into UDIV/SDIV + MLS later on. | 
|  | bool hasDivide = Subtarget->isThumb() ? Subtarget->hasDivideInThumbMode() | 
|  | : Subtarget->hasDivideInARMMode(); | 
|  | if (hasDivide && Op->getValueType(0).isSimple() && | 
|  | Op->getSimpleValueType(0) == MVT::i32) { | 
|  | unsigned DivOpcode = isSigned ? ISD::SDIV : ISD::UDIV; | 
|  | const SDValue Dividend = Op->getOperand(0); | 
|  | const SDValue Divisor = Op->getOperand(1); | 
|  | SDValue Div = DAG.getNode(DivOpcode, dl, VT, Dividend, Divisor); | 
|  | SDValue Mul = DAG.getNode(ISD::MUL, dl, VT, Div, Divisor); | 
|  | SDValue Rem = DAG.getNode(ISD::SUB, dl, VT, Dividend, Mul); | 
|  |  | 
|  | SDValue Values[2] = {Div, Rem}; | 
|  | return DAG.getNode(ISD::MERGE_VALUES, dl, DAG.getVTList(VT, VT), Values); | 
|  | } | 
|  |  | 
|  | RTLIB::Libcall LC = getDivRemLibcall(Op.getNode(), | 
|  | VT.getSimpleVT().SimpleTy); | 
|  | SDValue InChain = DAG.getEntryNode(); | 
|  |  | 
|  | TargetLowering::ArgListTy Args = getDivRemArgList(Op.getNode(), | 
|  | DAG.getContext(), | 
|  | Subtarget); | 
|  |  | 
|  | SDValue Callee = DAG.getExternalSymbol(getLibcallName(LC), | 
|  | getPointerTy(DAG.getDataLayout())); | 
|  |  | 
|  | Type *RetTy = StructType::get(Ty, Ty); | 
|  |  | 
|  | if (Subtarget->isTargetWindows()) | 
|  | InChain = WinDBZCheckDenominator(DAG, Op.getNode(), InChain); | 
|  |  | 
|  | TargetLowering::CallLoweringInfo CLI(DAG); | 
|  | CLI.setDebugLoc(dl).setChain(InChain) | 
|  | .setCallee(getLibcallCallingConv(LC), RetTy, Callee, std::move(Args)) | 
|  | .setInRegister().setSExtResult(isSigned).setZExtResult(!isSigned); | 
|  |  | 
|  | std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI); | 
|  | return CallInfo.first; | 
|  | } | 
|  |  | 
|  | // Lowers REM using divmod helpers | 
|  | // see RTABI section 4.2/4.3 | 
|  | SDValue ARMTargetLowering::LowerREM(SDNode *N, SelectionDAG &DAG) const { | 
|  | // Build return types (div and rem) | 
|  | std::vector<Type*> RetTyParams; | 
|  | Type *RetTyElement; | 
|  |  | 
|  | switch (N->getValueType(0).getSimpleVT().SimpleTy) { | 
|  | default: llvm_unreachable("Unexpected request for libcall!"); | 
|  | case MVT::i8:   RetTyElement = Type::getInt8Ty(*DAG.getContext());  break; | 
|  | case MVT::i16:  RetTyElement = Type::getInt16Ty(*DAG.getContext()); break; | 
|  | case MVT::i32:  RetTyElement = Type::getInt32Ty(*DAG.getContext()); break; | 
|  | case MVT::i64:  RetTyElement = Type::getInt64Ty(*DAG.getContext()); break; | 
|  | } | 
|  |  | 
|  | RetTyParams.push_back(RetTyElement); | 
|  | RetTyParams.push_back(RetTyElement); | 
|  | ArrayRef<Type*> ret = ArrayRef<Type*>(RetTyParams); | 
|  | Type *RetTy = StructType::get(*DAG.getContext(), ret); | 
|  |  | 
|  | RTLIB::Libcall LC = getDivRemLibcall(N, N->getValueType(0).getSimpleVT(). | 
|  | SimpleTy); | 
|  | SDValue InChain = DAG.getEntryNode(); | 
|  | TargetLowering::ArgListTy Args = getDivRemArgList(N, DAG.getContext(), | 
|  | Subtarget); | 
|  | bool isSigned = N->getOpcode() == ISD::SREM; | 
|  | SDValue Callee = DAG.getExternalSymbol(getLibcallName(LC), | 
|  | getPointerTy(DAG.getDataLayout())); | 
|  |  | 
|  | if (Subtarget->isTargetWindows()) | 
|  | InChain = WinDBZCheckDenominator(DAG, N, InChain); | 
|  |  | 
|  | // Lower call | 
|  | CallLoweringInfo CLI(DAG); | 
|  | CLI.setChain(InChain) | 
|  | .setCallee(CallingConv::ARM_AAPCS, RetTy, Callee, std::move(Args)) | 
|  | .setSExtResult(isSigned).setZExtResult(!isSigned).setDebugLoc(SDLoc(N)); | 
|  | std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI); | 
|  |  | 
|  | // Return second (rem) result operand (first contains div) | 
|  | SDNode *ResNode = CallResult.first.getNode(); | 
|  | assert(ResNode->getNumOperands() == 2 && "divmod should return two operands"); | 
|  | return ResNode->getOperand(1); | 
|  | } | 
|  |  | 
|  | SDValue | 
|  | ARMTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const { | 
|  | assert(Subtarget->isTargetWindows() && "unsupported target platform"); | 
|  | SDLoc DL(Op); | 
|  |  | 
|  | // Get the inputs. | 
|  | SDValue Chain = Op.getOperand(0); | 
|  | SDValue Size  = Op.getOperand(1); | 
|  |  | 
|  | if (DAG.getMachineFunction().getFunction().hasFnAttribute( | 
|  | "no-stack-arg-probe")) { | 
|  | unsigned Align = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue(); | 
|  | SDValue SP = DAG.getCopyFromReg(Chain, DL, ARM::SP, MVT::i32); | 
|  | Chain = SP.getValue(1); | 
|  | SP = DAG.getNode(ISD::SUB, DL, MVT::i32, SP, Size); | 
|  | if (Align) | 
|  | SP = DAG.getNode(ISD::AND, DL, MVT::i32, SP.getValue(0), | 
|  | DAG.getConstant(-(uint64_t)Align, DL, MVT::i32)); | 
|  | Chain = DAG.getCopyToReg(Chain, DL, ARM::SP, SP); | 
|  | SDValue Ops[2] = { SP, Chain }; | 
|  | return DAG.getMergeValues(Ops, DL); | 
|  | } | 
|  |  | 
|  | SDValue Words = DAG.getNode(ISD::SRL, DL, MVT::i32, Size, | 
|  | DAG.getConstant(2, DL, MVT::i32)); | 
|  |  | 
|  | SDValue Flag; | 
|  | Chain = DAG.getCopyToReg(Chain, DL, ARM::R4, Words, Flag); | 
|  | Flag = Chain.getValue(1); | 
|  |  | 
|  | SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); | 
|  | Chain = DAG.getNode(ARMISD::WIN__CHKSTK, DL, NodeTys, Chain, Flag); | 
|  |  | 
|  | SDValue NewSP = DAG.getCopyFromReg(Chain, DL, ARM::SP, MVT::i32); | 
|  | Chain = NewSP.getValue(1); | 
|  |  | 
|  | SDValue Ops[2] = { NewSP, Chain }; | 
|  | return DAG.getMergeValues(Ops, DL); | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerFP_EXTEND(SDValue Op, SelectionDAG &DAG) const { | 
|  | bool IsStrict = Op->isStrictFPOpcode(); | 
|  | SDValue SrcVal = Op.getOperand(IsStrict ? 1 : 0); | 
|  | const unsigned DstSz = Op.getValueType().getSizeInBits(); | 
|  | const unsigned SrcSz = SrcVal.getValueType().getSizeInBits(); | 
|  | assert(DstSz > SrcSz && DstSz <= 64 && SrcSz >= 16 && | 
|  | "Unexpected type for custom-lowering FP_EXTEND"); | 
|  |  | 
|  | assert((!Subtarget->hasFP64() || !Subtarget->hasFPARMv8Base()) && | 
|  | "With both FP DP and 16, any FP conversion is legal!"); | 
|  |  | 
|  | assert(!(DstSz == 32 && Subtarget->hasFP16()) && | 
|  | "With FP16, 16 to 32 conversion is legal!"); | 
|  |  | 
|  | // Converting from 32 -> 64 is valid if we have FP64. | 
|  | if (SrcSz == 32 && DstSz == 64 && Subtarget->hasFP64()) { | 
|  | // FIXME: Remove this when we have strict fp instruction selection patterns | 
|  | if (IsStrict) { | 
|  | SDLoc Loc(Op); | 
|  | SDValue Result = DAG.getNode(ISD::FP_EXTEND, | 
|  | Loc, Op.getValueType(), SrcVal); | 
|  | return DAG.getMergeValues({Result, Op.getOperand(0)}, Loc); | 
|  | } | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | // Either we are converting from 16 -> 64, without FP16 and/or | 
|  | // FP.double-precision or without Armv8-fp. So we must do it in two | 
|  | // steps. | 
|  | // Or we are converting from 32 -> 64 without fp.double-precision or 16 -> 32 | 
|  | // without FP16. So we must do a function call. | 
|  | SDLoc Loc(Op); | 
|  | RTLIB::Libcall LC; | 
|  | MakeLibCallOptions CallOptions; | 
|  | SDValue Chain = IsStrict ? Op.getOperand(0) : SDValue(); | 
|  | for (unsigned Sz = SrcSz; Sz <= 32 && Sz < DstSz; Sz *= 2) { | 
|  | bool Supported = (Sz == 16 ? Subtarget->hasFP16() : Subtarget->hasFP64()); | 
|  | MVT SrcVT = (Sz == 16 ? MVT::f16 : MVT::f32); | 
|  | MVT DstVT = (Sz == 16 ? MVT::f32 : MVT::f64); | 
|  | if (Supported) { | 
|  | if (IsStrict) { | 
|  | SrcVal = DAG.getNode(ISD::STRICT_FP_EXTEND, Loc, | 
|  | {DstVT, MVT::Other}, {Chain, SrcVal}); | 
|  | Chain = SrcVal.getValue(1); | 
|  | } else { | 
|  | SrcVal = DAG.getNode(ISD::FP_EXTEND, Loc, DstVT, SrcVal); | 
|  | } | 
|  | } else { | 
|  | LC = RTLIB::getFPEXT(SrcVT, DstVT); | 
|  | assert(LC != RTLIB::UNKNOWN_LIBCALL && | 
|  | "Unexpected type for custom-lowering FP_EXTEND"); | 
|  | std::tie(SrcVal, Chain) = makeLibCall(DAG, LC, DstVT, SrcVal, CallOptions, | 
|  | Loc, Chain); | 
|  | } | 
|  | } | 
|  |  | 
|  | return IsStrict ? DAG.getMergeValues({SrcVal, Chain}, Loc) : SrcVal; | 
|  | } | 
|  |  | 
|  | SDValue ARMTargetLowering::LowerFP_ROUND(SDValue Op, SelectionDAG &DAG) const { | 
|  | bool IsStrict = Op->isStrictFPOpcode(); | 
|  |  | 
|  | SDValue SrcVal = Op.getOperand(IsStrict ? 1 : 0); | 
|  | EVT SrcVT = SrcVal.getValueType(); | 
|  | EVT DstVT = Op.getValueType(); | 
|  | const unsigned DstSz = Op.getValueType().getSizeInBits(); | 
|  | const unsigned SrcSz = SrcVT.getSizeInBits(); | 
|  | (void)DstSz; | 
|  | assert(DstSz < SrcSz && SrcSz <= 64 && DstSz >= 16 && | 
|  | "Unexpected type for custom-lowering FP_ROUND"); | 
|  |  | 
|  | assert((!Subtarget->hasFP64() || !Subtarget->hasFPARMv8Base()) && | 
|  | "With both FP DP and 16, any FP conversion is legal!"); | 
|  |  | 
|  | SDLoc Loc(Op); | 
|  |  | 
|  | // Instruction from 32 -> 16 if hasFP16 is valid | 
|  | if (SrcSz == 32 && Subtarget->hasFP16()) | 
|  | return Op; | 
|  |  | 
|  | // Lib call from 32 -> 16 / 64 -> [32, 16] | 
|  | RTLIB::Libcall LC = RTLIB::getFPROUND(SrcVT, DstVT); | 
|  | assert(LC != RTLIB::UNKNOWN_LIBCALL && | 
|  | "Unexpected type for custom-lowering FP_ROUND"); | 
|  | MakeLibCallOptions CallOptions; | 
|  | SDValue Chain = IsStrict ? Op.getOperand(0) : SDValue(); | 
|  | SDValue Result; | 
|  | std::tie(Result, Chain) = makeLibCall(DAG, LC, DstVT, SrcVal, CallOptions, | 
|  | Loc, Chain); | 
|  | return IsStrict ? DAG.getMergeValues({Result, Chain}, Loc) : Result; | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::lowerABS(SDNode *N, SmallVectorImpl<SDValue> &Results, | 
|  | SelectionDAG &DAG) const { | 
|  | assert(N->getValueType(0) == MVT::i64 && "Unexpected type (!= i64) on ABS."); | 
|  | MVT HalfT = MVT::i32; | 
|  | SDLoc dl(N); | 
|  | SDValue Hi, Lo, Tmp; | 
|  |  | 
|  | if (!isOperationLegalOrCustom(ISD::ADDCARRY, HalfT) || | 
|  | !isOperationLegalOrCustom(ISD::UADDO, HalfT)) | 
|  | return ; | 
|  |  | 
|  | unsigned OpTypeBits = HalfT.getScalarSizeInBits(); | 
|  | SDVTList VTList = DAG.getVTList(HalfT, MVT::i1); | 
|  |  | 
|  | Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, HalfT, N->getOperand(0), | 
|  | DAG.getConstant(0, dl, HalfT)); | 
|  | Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, HalfT, N->getOperand(0), | 
|  | DAG.getConstant(1, dl, HalfT)); | 
|  |  | 
|  | Tmp = DAG.getNode(ISD::SRA, dl, HalfT, Hi, | 
|  | DAG.getConstant(OpTypeBits - 1, dl, | 
|  | getShiftAmountTy(HalfT, DAG.getDataLayout()))); | 
|  | Lo = DAG.getNode(ISD::UADDO, dl, VTList, Tmp, Lo); | 
|  | Hi = DAG.getNode(ISD::ADDCARRY, dl, VTList, Tmp, Hi, | 
|  | SDValue(Lo.getNode(), 1)); | 
|  | Hi = DAG.getNode(ISD::XOR, dl, HalfT, Tmp, Hi); | 
|  | Lo = DAG.getNode(ISD::XOR, dl, HalfT, Tmp, Lo); | 
|  |  | 
|  | Results.push_back(Lo); | 
|  | Results.push_back(Hi); | 
|  | } | 
|  |  | 
|  | bool | 
|  | ARMTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { | 
|  | // The ARM target isn't yet aware of offsets. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool ARM::isBitFieldInvertedMask(unsigned v) { | 
|  | if (v == 0xffffffff) | 
|  | return false; | 
|  |  | 
|  | // there can be 1's on either or both "outsides", all the "inside" | 
|  | // bits must be 0's | 
|  | return isShiftedMask_32(~v); | 
|  | } | 
|  |  | 
|  | /// isFPImmLegal - Returns true if the target can instruction select the | 
|  | /// specified FP immediate natively. If false, the legalizer will | 
|  | /// materialize the FP immediate as a load from a constant pool. | 
|  | bool ARMTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT, | 
|  | bool ForCodeSize) const { | 
|  | if (!Subtarget->hasVFP3Base()) | 
|  | return false; | 
|  | if (VT == MVT::f16 && Subtarget->hasFullFP16()) | 
|  | return ARM_AM::getFP16Imm(Imm) != -1; | 
|  | if (VT == MVT::f32) | 
|  | return ARM_AM::getFP32Imm(Imm) != -1; | 
|  | if (VT == MVT::f64 && Subtarget->hasFP64()) | 
|  | return ARM_AM::getFP64Imm(Imm) != -1; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// getTgtMemIntrinsic - Represent NEON load and store intrinsics as | 
|  | /// MemIntrinsicNodes.  The associated MachineMemOperands record the alignment | 
|  | /// specified in the intrinsic calls. | 
|  | bool ARMTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, | 
|  | const CallInst &I, | 
|  | MachineFunction &MF, | 
|  | unsigned Intrinsic) const { | 
|  | switch (Intrinsic) { | 
|  | case Intrinsic::arm_neon_vld1: | 
|  | case Intrinsic::arm_neon_vld2: | 
|  | case Intrinsic::arm_neon_vld3: | 
|  | case Intrinsic::arm_neon_vld4: | 
|  | case Intrinsic::arm_neon_vld2lane: | 
|  | case Intrinsic::arm_neon_vld3lane: | 
|  | case Intrinsic::arm_neon_vld4lane: | 
|  | case Intrinsic::arm_neon_vld2dup: | 
|  | case Intrinsic::arm_neon_vld3dup: | 
|  | case Intrinsic::arm_neon_vld4dup: { | 
|  | Info.opc = ISD::INTRINSIC_W_CHAIN; | 
|  | // Conservatively set memVT to the entire set of vectors loaded. | 
|  | auto &DL = I.getCalledFunction()->getParent()->getDataLayout(); | 
|  | uint64_t NumElts = DL.getTypeSizeInBits(I.getType()) / 64; | 
|  | Info.memVT = EVT::getVectorVT(I.getType()->getContext(), MVT::i64, NumElts); | 
|  | Info.ptrVal = I.getArgOperand(0); | 
|  | Info.offset = 0; | 
|  | Value *AlignArg = I.getArgOperand(I.getNumArgOperands() - 1); | 
|  | Info.align = MaybeAlign(cast<ConstantInt>(AlignArg)->getZExtValue()); | 
|  | // volatile loads with NEON intrinsics not supported | 
|  | Info.flags = MachineMemOperand::MOLoad; | 
|  | return true; | 
|  | } | 
|  | case Intrinsic::arm_neon_vld1x2: | 
|  | case Intrinsic::arm_neon_vld1x3: | 
|  | case Intrinsic::arm_neon_vld1x4: { | 
|  | Info.opc = ISD::INTRINSIC_W_CHAIN; | 
|  | // Conservatively set memVT to the entire set of vectors loaded. | 
|  | auto &DL = I.getCalledFunction()->getParent()->getDataLayout(); | 
|  | uint64_t NumElts = DL.getTypeSizeInBits(I.getType()) / 64; | 
|  | Info.memVT = EVT::getVectorVT(I.getType()->getContext(), MVT::i64, NumElts); | 
|  | Info.ptrVal = I.getArgOperand(I.getNumArgOperands() - 1); | 
|  | Info.offset = 0; | 
|  | Info.align.reset(); | 
|  | // volatile loads with NEON intrinsics not supported | 
|  | Info.flags = MachineMemOperand::MOLoad; | 
|  | return true; | 
|  | } | 
|  | case Intrinsic::arm_neon_vst1: | 
|  | case Intrinsic::arm_neon_vst2: | 
|  | case Intrinsic::arm_neon_vst3: | 
|  | case Intrinsic::arm_neon_vst4: | 
|  | case Intrinsic::arm_neon_vst2lane: | 
|  | case Intrinsic::arm_neon_vst3lane: | 
|  | case Intrinsic::arm_neon_vst4lane: { | 
|  | Info.opc = ISD::INTRINSIC_VOID; | 
|  | // Conservatively set memVT to the entire set of vectors stored. | 
|  | auto &DL = I.getCalledFunction()->getParent()->getDataLayout(); | 
|  | unsigned NumElts = 0; | 
|  | for (unsigned ArgI = 1, ArgE = I.getNumArgOperands(); ArgI < ArgE; ++ArgI) { | 
|  | Type *ArgTy = I.getArgOperand(ArgI)->getType(); | 
|  | if (!ArgTy->isVectorTy()) | 
|  | break; | 
|  | NumElts += DL.getTypeSizeInBits(ArgTy) / 64; | 
|  | } | 
|  | Info.memVT = EVT::getVectorVT(I.getType()->getContext(), MVT::i64, NumElts); | 
|  | Info.ptrVal = I.getArgOperand(0); | 
|  | Info.offset = 0; | 
|  | Value *AlignArg = I.getArgOperand(I.getNumArgOperands() - 1); | 
|  | Info.align = MaybeAlign(cast<ConstantInt>(AlignArg)->getZExtValue()); | 
|  | // volatile stores with NEON intrinsics not supported | 
|  | Info.flags = MachineMemOperand::MOStore; | 
|  | return true; | 
|  | } | 
|  | case Intrinsic::arm_neon_vst1x2: | 
|  | case Intrinsic::arm_neon_vst1x3: | 
|  | case Intrinsic::arm_neon_vst1x4: { | 
|  | Info.opc = ISD::INTRINSIC_VOID; | 
|  | // Conservatively set memVT to the entire set of vectors stored. | 
|  | auto &DL = I.getCalledFunction()->getParent()->getDataLayout(); | 
|  | unsigned NumElts = 0; | 
|  | for (unsigned ArgI = 1, ArgE = I.getNumArgOperands(); ArgI < ArgE; ++ArgI) { | 
|  | Type *ArgTy = I.getArgOperand(ArgI)->getType(); | 
|  | if (!ArgTy->isVectorTy()) | 
|  | break; | 
|  | NumElts += DL.getTypeSizeInBits(ArgTy) / 64; | 
|  | } | 
|  | Info.memVT = EVT::getVectorVT(I.getType()->getContext(), MVT::i64, NumElts); | 
|  | Info.ptrVal = I.getArgOperand(0); | 
|  | Info.offset = 0; | 
|  | Info.align.reset(); | 
|  | // volatile stores with NEON intrinsics not supported | 
|  | Info.flags = MachineMemOperand::MOStore; | 
|  | return true; | 
|  | } | 
|  | case Intrinsic::arm_mve_vld2q: | 
|  | case Intrinsic::arm_mve_vld4q: { | 
|  | Info.opc = ISD::INTRINSIC_W_CHAIN; | 
|  | // Conservatively set memVT to the entire set of vectors loaded. | 
|  | Type *VecTy = cast<StructType>(I.getType())->getElementType(1); | 
|  | unsigned Factor = Intrinsic == Intrinsic::arm_mve_vld2q ? 2 : 4; | 
|  | Info.memVT = EVT::getVectorVT(VecTy->getContext(), MVT::i64, Factor * 2); | 
|  | Info.ptrVal = I.getArgOperand(0); | 
|  | Info.offset = 0; | 
|  | Info.align = Align(VecTy->getScalarSizeInBits() / 8); | 
|  | // volatile loads with MVE intrinsics not supported | 
|  | Info.flags = MachineMemOperand::MOLoad; | 
|  | return true; | 
|  | } | 
|  | case Intrinsic::arm_mve_vst2q: | 
|  | case Intrinsic::arm_mve_vst4q: { | 
|  | Info.opc = ISD::INTRINSIC_VOID; | 
|  | // Conservatively set memVT to the entire set of vectors stored. | 
|  | Type *VecTy = I.getArgOperand(1)->getType(); | 
|  | unsigned Factor = Intrinsic == Intrinsic::arm_mve_vst2q ? 2 : 4; | 
|  | Info.memVT = EVT::getVectorVT(VecTy->getContext(), MVT::i64, Factor * 2); | 
|  | Info.ptrVal = I.getArgOperand(0); | 
|  | Info.offset = 0; | 
|  | Info.align = Align(VecTy->getScalarSizeInBits() / 8); | 
|  | // volatile stores with MVE intrinsics not supported | 
|  | Info.flags = MachineMemOperand::MOStore; | 
|  | return true; | 
|  | } | 
|  | case Intrinsic::arm_ldaex: | 
|  | case Intrinsic::arm_ldrex: { | 
|  | auto &DL = I.getCalledFunction()->getParent()->getDataLayout(); | 
|  | PointerType *PtrTy = cast<PointerType>(I.getArgOperand(0)->getType()); | 
|  | Info.opc = ISD::INTRINSIC_W_CHAIN; | 
|  | Info.memVT = MVT::getVT(PtrTy->getElementType()); | 
|  | Info.ptrVal = I.getArgOperand(0); | 
|  | Info.offset = 0; | 
|  | Info.align = DL.getABITypeAlign(PtrTy->getElementType()); | 
|  | Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOVolatile; | 
|  | return true; | 
|  | } | 
|  | case Intrinsic::arm_stlex: | 
|  | case Intrinsic::arm_strex: { | 
|  | auto &DL = I.getCalledFunction()->getParent()->getDataLayout(); | 
|  | PointerType *PtrTy = cast<PointerType>(I.getArgOperand(1)->getType()); | 
|  | Info.opc = ISD::INTRINSIC_W_CHAIN; | 
|  | Info.memVT = MVT::getVT(PtrTy->getElementType()); | 
|  | Info.ptrVal = I.getArgOperand(1); | 
|  | Info.offset = 0; | 
|  | Info.align = DL.getABITypeAlign(PtrTy->getElementType()); | 
|  | Info.flags = MachineMemOperand::MOStore | MachineMemOperand::MOVolatile; | 
|  | return true; | 
|  | } | 
|  | case Intrinsic::arm_stlexd: | 
|  | case Intrinsic::arm_strexd: | 
|  | Info.opc = ISD::INTRINSIC_W_CHAIN; | 
|  | Info.memVT = MVT::i64; | 
|  | Info.ptrVal = I.getArgOperand(2); | 
|  | Info.offset = 0; | 
|  | Info.align = Align(8); | 
|  | Info.flags = MachineMemOperand::MOStore | MachineMemOperand::MOVolatile; | 
|  | return true; | 
|  |  | 
|  | case Intrinsic::arm_ldaexd: | 
|  | case Intrinsic::arm_ldrexd: | 
|  | Info.opc = ISD::INTRINSIC_W_CHAIN; | 
|  | Info.memVT = MVT::i64; | 
|  | Info.ptrVal = I.getArgOperand(0); | 
|  | Info.offset = 0; | 
|  | Info.align = Align(8); | 
|  | Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOVolatile; | 
|  | return true; | 
|  |  | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// Returns true if it is beneficial to convert a load of a constant | 
|  | /// to just the constant itself. | 
|  | bool ARMTargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm, | 
|  | Type *Ty) const { | 
|  | assert(Ty->isIntegerTy()); | 
|  |  | 
|  | unsigned Bits = Ty->getPrimitiveSizeInBits(); | 
|  | if (Bits == 0 || Bits > 32) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isExtractSubvectorCheap(EVT ResVT, EVT SrcVT, | 
|  | unsigned Index) const { | 
|  | if (!isOperationLegalOrCustom(ISD::EXTRACT_SUBVECTOR, ResVT)) | 
|  | return false; | 
|  |  | 
|  | return (Index == 0 || Index == ResVT.getVectorNumElements()); | 
|  | } | 
|  |  | 
|  | Instruction* ARMTargetLowering::makeDMB(IRBuilder<> &Builder, | 
|  | ARM_MB::MemBOpt Domain) const { | 
|  | Module *M = Builder.GetInsertBlock()->getParent()->getParent(); | 
|  |  | 
|  | // First, if the target has no DMB, see what fallback we can use. | 
|  | if (!Subtarget->hasDataBarrier()) { | 
|  | // Some ARMv6 cpus can support data barriers with an mcr instruction. | 
|  | // Thumb1 and pre-v6 ARM mode use a libcall instead and should never get | 
|  | // here. | 
|  | if (Subtarget->hasV6Ops() && !Subtarget->isThumb()) { | 
|  | Function *MCR = Intrinsic::getDeclaration(M, Intrinsic::arm_mcr); | 
|  | Value* args[6] = {Builder.getInt32(15), Builder.getInt32(0), | 
|  | Builder.getInt32(0), Builder.getInt32(7), | 
|  | Builder.getInt32(10), Builder.getInt32(5)}; | 
|  | return Builder.CreateCall(MCR, args); | 
|  | } else { | 
|  | // Instead of using barriers, atomic accesses on these subtargets use | 
|  | // libcalls. | 
|  | llvm_unreachable("makeDMB on a target so old that it has no barriers"); | 
|  | } | 
|  | } else { | 
|  | Function *DMB = Intrinsic::getDeclaration(M, Intrinsic::arm_dmb); | 
|  | // Only a full system barrier exists in the M-class architectures. | 
|  | Domain = Subtarget->isMClass() ? ARM_MB::SY : Domain; | 
|  | Constant *CDomain = Builder.getInt32(Domain); | 
|  | return Builder.CreateCall(DMB, CDomain); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Based on http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html | 
|  | Instruction *ARMTargetLowering::emitLeadingFence(IRBuilder<> &Builder, | 
|  | Instruction *Inst, | 
|  | AtomicOrdering Ord) const { | 
|  | switch (Ord) { | 
|  | case AtomicOrdering::NotAtomic: | 
|  | case AtomicOrdering::Unordered: | 
|  | llvm_unreachable("Invalid fence: unordered/non-atomic"); | 
|  | case AtomicOrdering::Monotonic: | 
|  | case AtomicOrdering::Acquire: | 
|  | return nullptr; // Nothing to do | 
|  | case AtomicOrdering::SequentiallyConsistent: | 
|  | if (!Inst->hasAtomicStore()) | 
|  | return nullptr; // Nothing to do | 
|  | LLVM_FALLTHROUGH; | 
|  | case AtomicOrdering::Release: | 
|  | case AtomicOrdering::AcquireRelease: | 
|  | if (Subtarget->preferISHSTBarriers()) | 
|  | return makeDMB(Builder, ARM_MB::ISHST); | 
|  | // FIXME: add a comment with a link to documentation justifying this. | 
|  | else | 
|  | return makeDMB(Builder, ARM_MB::ISH); | 
|  | } | 
|  | llvm_unreachable("Unknown fence ordering in emitLeadingFence"); | 
|  | } | 
|  |  | 
|  | Instruction *ARMTargetLowering::emitTrailingFence(IRBuilder<> &Builder, | 
|  | Instruction *Inst, | 
|  | AtomicOrdering Ord) const { | 
|  | switch (Ord) { | 
|  | case AtomicOrdering::NotAtomic: | 
|  | case AtomicOrdering::Unordered: | 
|  | llvm_unreachable("Invalid fence: unordered/not-atomic"); | 
|  | case AtomicOrdering::Monotonic: | 
|  | case AtomicOrdering::Release: | 
|  | return nullptr; // Nothing to do | 
|  | case AtomicOrdering::Acquire: | 
|  | case AtomicOrdering::AcquireRelease: | 
|  | case AtomicOrdering::SequentiallyConsistent: | 
|  | return makeDMB(Builder, ARM_MB::ISH); | 
|  | } | 
|  | llvm_unreachable("Unknown fence ordering in emitTrailingFence"); | 
|  | } | 
|  |  | 
|  | // Loads and stores less than 64-bits are already atomic; ones above that | 
|  | // are doomed anyway, so defer to the default libcall and blame the OS when | 
|  | // things go wrong. Cortex M doesn't have ldrexd/strexd though, so don't emit | 
|  | // anything for those. | 
|  | bool ARMTargetLowering::shouldExpandAtomicStoreInIR(StoreInst *SI) const { | 
|  | unsigned Size = SI->getValueOperand()->getType()->getPrimitiveSizeInBits(); | 
|  | return (Size == 64) && !Subtarget->isMClass(); | 
|  | } | 
|  |  | 
|  | // Loads and stores less than 64-bits are already atomic; ones above that | 
|  | // are doomed anyway, so defer to the default libcall and blame the OS when | 
|  | // things go wrong. Cortex M doesn't have ldrexd/strexd though, so don't emit | 
|  | // anything for those. | 
|  | // FIXME: ldrd and strd are atomic if the CPU has LPAE (e.g. A15 has that | 
|  | // guarantee, see DDI0406C ARM architecture reference manual, | 
|  | // sections A8.8.72-74 LDRD) | 
|  | TargetLowering::AtomicExpansionKind | 
|  | ARMTargetLowering::shouldExpandAtomicLoadInIR(LoadInst *LI) const { | 
|  | unsigned Size = LI->getType()->getPrimitiveSizeInBits(); | 
|  | return ((Size == 64) && !Subtarget->isMClass()) ? AtomicExpansionKind::LLOnly | 
|  | : AtomicExpansionKind::None; | 
|  | } | 
|  |  | 
|  | // For the real atomic operations, we have ldrex/strex up to 32 bits, | 
|  | // and up to 64 bits on the non-M profiles | 
|  | TargetLowering::AtomicExpansionKind | 
|  | ARMTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { | 
|  | if (AI->isFloatingPointOperation()) | 
|  | return AtomicExpansionKind::CmpXChg; | 
|  |  | 
|  | unsigned Size = AI->getType()->getPrimitiveSizeInBits(); | 
|  | bool hasAtomicRMW = !Subtarget->isThumb() || Subtarget->hasV8MBaselineOps(); | 
|  | return (Size <= (Subtarget->isMClass() ? 32U : 64U) && hasAtomicRMW) | 
|  | ? AtomicExpansionKind::LLSC | 
|  | : AtomicExpansionKind::None; | 
|  | } | 
|  |  | 
|  | TargetLowering::AtomicExpansionKind | 
|  | ARMTargetLowering::shouldExpandAtomicCmpXchgInIR(AtomicCmpXchgInst *AI) const { | 
|  | // At -O0, fast-regalloc cannot cope with the live vregs necessary to | 
|  | // implement cmpxchg without spilling. If the address being exchanged is also | 
|  | // on the stack and close enough to the spill slot, this can lead to a | 
|  | // situation where the monitor always gets cleared and the atomic operation | 
|  | // can never succeed. So at -O0 we need a late-expanded pseudo-inst instead. | 
|  | bool HasAtomicCmpXchg = | 
|  | !Subtarget->isThumb() || Subtarget->hasV8MBaselineOps(); | 
|  | if (getTargetMachine().getOptLevel() != 0 && HasAtomicCmpXchg) | 
|  | return AtomicExpansionKind::LLSC; | 
|  | return AtomicExpansionKind::None; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::shouldInsertFencesForAtomic( | 
|  | const Instruction *I) const { | 
|  | return InsertFencesForAtomic; | 
|  | } | 
|  |  | 
|  | // This has so far only been implemented for MachO. | 
|  | bool ARMTargetLowering::useLoadStackGuardNode() const { | 
|  | return Subtarget->isTargetMachO(); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::insertSSPDeclarations(Module &M) const { | 
|  | if (!Subtarget->getTargetTriple().isWindowsMSVCEnvironment()) | 
|  | return TargetLowering::insertSSPDeclarations(M); | 
|  |  | 
|  | // MSVC CRT has a global variable holding security cookie. | 
|  | M.getOrInsertGlobal("__security_cookie", | 
|  | Type::getInt8PtrTy(M.getContext())); | 
|  |  | 
|  | // MSVC CRT has a function to validate security cookie. | 
|  | FunctionCallee SecurityCheckCookie = M.getOrInsertFunction( | 
|  | "__security_check_cookie", Type::getVoidTy(M.getContext()), | 
|  | Type::getInt8PtrTy(M.getContext())); | 
|  | if (Function *F = dyn_cast<Function>(SecurityCheckCookie.getCallee())) | 
|  | F->addAttribute(1, Attribute::AttrKind::InReg); | 
|  | } | 
|  |  | 
|  | Value *ARMTargetLowering::getSDagStackGuard(const Module &M) const { | 
|  | // MSVC CRT has a global variable holding security cookie. | 
|  | if (Subtarget->getTargetTriple().isWindowsMSVCEnvironment()) | 
|  | return M.getGlobalVariable("__security_cookie"); | 
|  | return TargetLowering::getSDagStackGuard(M); | 
|  | } | 
|  |  | 
|  | Function *ARMTargetLowering::getSSPStackGuardCheck(const Module &M) const { | 
|  | // MSVC CRT has a function to validate security cookie. | 
|  | if (Subtarget->getTargetTriple().isWindowsMSVCEnvironment()) | 
|  | return M.getFunction("__security_check_cookie"); | 
|  | return TargetLowering::getSSPStackGuardCheck(M); | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::canCombineStoreAndExtract(Type *VectorTy, Value *Idx, | 
|  | unsigned &Cost) const { | 
|  | // If we do not have NEON, vector types are not natively supported. | 
|  | if (!Subtarget->hasNEON()) | 
|  | return false; | 
|  |  | 
|  | // Floating point values and vector values map to the same register file. | 
|  | // Therefore, although we could do a store extract of a vector type, this is | 
|  | // better to leave at float as we have more freedom in the addressing mode for | 
|  | // those. | 
|  | if (VectorTy->isFPOrFPVectorTy()) | 
|  | return false; | 
|  |  | 
|  | // If the index is unknown at compile time, this is very expensive to lower | 
|  | // and it is not possible to combine the store with the extract. | 
|  | if (!isa<ConstantInt>(Idx)) | 
|  | return false; | 
|  |  | 
|  | assert(VectorTy->isVectorTy() && "VectorTy is not a vector type"); | 
|  | unsigned BitWidth = VectorTy->getPrimitiveSizeInBits().getFixedSize(); | 
|  | // We can do a store + vector extract on any vector that fits perfectly in a D | 
|  | // or Q register. | 
|  | if (BitWidth == 64 || BitWidth == 128) { | 
|  | Cost = 0; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isCheapToSpeculateCttz() const { | 
|  | return Subtarget->hasV6T2Ops(); | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isCheapToSpeculateCtlz() const { | 
|  | return Subtarget->hasV6T2Ops(); | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::shouldExpandShift(SelectionDAG &DAG, SDNode *N) const { | 
|  | return !Subtarget->hasMinSize() || Subtarget->isTargetWindows() || | 
|  | Subtarget->isTargetDarwin(); | 
|  | } | 
|  |  | 
|  | Value *ARMTargetLowering::emitLoadLinked(IRBuilder<> &Builder, Value *Addr, | 
|  | AtomicOrdering Ord) const { | 
|  | Module *M = Builder.GetInsertBlock()->getParent()->getParent(); | 
|  | Type *ValTy = cast<PointerType>(Addr->getType())->getElementType(); | 
|  | bool IsAcquire = isAcquireOrStronger(Ord); | 
|  |  | 
|  | // Since i64 isn't legal and intrinsics don't get type-lowered, the ldrexd | 
|  | // intrinsic must return {i32, i32} and we have to recombine them into a | 
|  | // single i64 here. | 
|  | if (ValTy->getPrimitiveSizeInBits() == 64) { | 
|  | Intrinsic::ID Int = | 
|  | IsAcquire ? Intrinsic::arm_ldaexd : Intrinsic::arm_ldrexd; | 
|  | Function *Ldrex = Intrinsic::getDeclaration(M, Int); | 
|  |  | 
|  | Addr = Builder.CreateBitCast(Addr, Type::getInt8PtrTy(M->getContext())); | 
|  | Value *LoHi = Builder.CreateCall(Ldrex, Addr, "lohi"); | 
|  |  | 
|  | Value *Lo = Builder.CreateExtractValue(LoHi, 0, "lo"); | 
|  | Value *Hi = Builder.CreateExtractValue(LoHi, 1, "hi"); | 
|  | if (!Subtarget->isLittle()) | 
|  | std::swap (Lo, Hi); | 
|  | Lo = Builder.CreateZExt(Lo, ValTy, "lo64"); | 
|  | Hi = Builder.CreateZExt(Hi, ValTy, "hi64"); | 
|  | return Builder.CreateOr( | 
|  | Lo, Builder.CreateShl(Hi, ConstantInt::get(ValTy, 32)), "val64"); | 
|  | } | 
|  |  | 
|  | Type *Tys[] = { Addr->getType() }; | 
|  | Intrinsic::ID Int = IsAcquire ? Intrinsic::arm_ldaex : Intrinsic::arm_ldrex; | 
|  | Function *Ldrex = Intrinsic::getDeclaration(M, Int, Tys); | 
|  |  | 
|  | return Builder.CreateTruncOrBitCast( | 
|  | Builder.CreateCall(Ldrex, Addr), | 
|  | cast<PointerType>(Addr->getType())->getElementType()); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::emitAtomicCmpXchgNoStoreLLBalance( | 
|  | IRBuilder<> &Builder) const { | 
|  | if (!Subtarget->hasV7Ops()) | 
|  | return; | 
|  | Module *M = Builder.GetInsertBlock()->getParent()->getParent(); | 
|  | Builder.CreateCall(Intrinsic::getDeclaration(M, Intrinsic::arm_clrex)); | 
|  | } | 
|  |  | 
|  | Value *ARMTargetLowering::emitStoreConditional(IRBuilder<> &Builder, Value *Val, | 
|  | Value *Addr, | 
|  | AtomicOrdering Ord) const { | 
|  | Module *M = Builder.GetInsertBlock()->getParent()->getParent(); | 
|  | bool IsRelease = isReleaseOrStronger(Ord); | 
|  |  | 
|  | // Since the intrinsics must have legal type, the i64 intrinsics take two | 
|  | // parameters: "i32, i32". We must marshal Val into the appropriate form | 
|  | // before the call. | 
|  | if (Val->getType()->getPrimitiveSizeInBits() == 64) { | 
|  | Intrinsic::ID Int = | 
|  | IsRelease ? Intrinsic::arm_stlexd : Intrinsic::arm_strexd; | 
|  | Function *Strex = Intrinsic::getDeclaration(M, Int); | 
|  | Type *Int32Ty = Type::getInt32Ty(M->getContext()); | 
|  |  | 
|  | Value *Lo = Builder.CreateTrunc(Val, Int32Ty, "lo"); | 
|  | Value *Hi = Builder.CreateTrunc(Builder.CreateLShr(Val, 32), Int32Ty, "hi"); | 
|  | if (!Subtarget->isLittle()) | 
|  | std::swap(Lo, Hi); | 
|  | Addr = Builder.CreateBitCast(Addr, Type::getInt8PtrTy(M->getContext())); | 
|  | return Builder.CreateCall(Strex, {Lo, Hi, Addr}); | 
|  | } | 
|  |  | 
|  | Intrinsic::ID Int = IsRelease ? Intrinsic::arm_stlex : Intrinsic::arm_strex; | 
|  | Type *Tys[] = { Addr->getType() }; | 
|  | Function *Strex = Intrinsic::getDeclaration(M, Int, Tys); | 
|  |  | 
|  | return Builder.CreateCall( | 
|  | Strex, {Builder.CreateZExtOrBitCast( | 
|  | Val, Strex->getFunctionType()->getParamType(0)), | 
|  | Addr}); | 
|  | } | 
|  |  | 
|  |  | 
|  | bool ARMTargetLowering::alignLoopsWithOptSize() const { | 
|  | return Subtarget->isMClass(); | 
|  | } | 
|  |  | 
|  | /// A helper function for determining the number of interleaved accesses we | 
|  | /// will generate when lowering accesses of the given type. | 
|  | unsigned | 
|  | ARMTargetLowering::getNumInterleavedAccesses(VectorType *VecTy, | 
|  | const DataLayout &DL) const { | 
|  | return (DL.getTypeSizeInBits(VecTy) + 127) / 128; | 
|  | } | 
|  |  | 
|  | bool ARMTargetLowering::isLegalInterleavedAccessType( | 
|  | unsigned Factor, FixedVectorType *VecTy, const DataLayout &DL) const { | 
|  |  | 
|  | unsigned VecSize = DL.getTypeSizeInBits(VecTy); | 
|  | unsigned ElSize = DL.getTypeSizeInBits(VecTy->getElementType()); | 
|  |  | 
|  | if (!Subtarget->hasNEON() && !Subtarget->hasMVEIntegerOps()) | 
|  | return false; | 
|  |  | 
|  | // Ensure the vector doesn't have f16 elements. Even though we could do an | 
|  | // i16 vldN, we can't hold the f16 vectors and will end up converting via | 
|  | // f32. | 
|  | if (Subtarget->hasNEON() && VecTy->getElementType()->isHalfTy()) | 
|  | return false; | 
|  | if (Subtarget->hasMVEIntegerOps() && Factor == 3) | 
|  | return false; | 
|  |  | 
|  | // Ensure the number of vector elements is greater than 1. | 
|  | if (VecTy->getNumElements() < 2) | 
|  | return false; | 
|  |  | 
|  | // Ensure the element type is legal. | 
|  | if (ElSize != 8 && ElSize != 16 && ElSize != 32) | 
|  | return false; | 
|  |  | 
|  | // Ensure the total vector size is 64 or a multiple of 128. Types larger than | 
|  | // 128 will be split into multiple interleaved accesses. | 
|  | if (Subtarget->hasNEON() && VecSize == 64) | 
|  | return true; | 
|  | return VecSize % 128 == 0; | 
|  | } | 
|  |  | 
|  | unsigned ARMTargetLowering::getMaxSupportedInterleaveFactor() const { | 
|  | if (Subtarget->hasNEON()) | 
|  | return 4; | 
|  | if (Subtarget->hasMVEIntegerOps()) | 
|  | return MVEMaxSupportedInterleaveFactor; | 
|  | return TargetLoweringBase::getMaxSupportedInterleaveFactor(); | 
|  | } | 
|  |  | 
|  | /// Lower an interleaved load into a vldN intrinsic. | 
|  | /// | 
|  | /// E.g. Lower an interleaved load (Factor = 2): | 
|  | ///        %wide.vec = load <8 x i32>, <8 x i32>* %ptr, align 4 | 
|  | ///        %v0 = shuffle %wide.vec, undef, <0, 2, 4, 6>  ; Extract even elements | 
|  | ///        %v1 = shuffle %wide.vec, undef, <1, 3, 5, 7>  ; Extract odd elements | 
|  | /// | 
|  | ///      Into: | 
|  | ///        %vld2 = { <4 x i32>, <4 x i32> } call llvm.arm.neon.vld2(%ptr, 4) | 
|  | ///        %vec0 = extractelement { <4 x i32>, <4 x i32> } %vld2, i32 0 | 
|  | ///        %vec1 = extractelement { <4 x i32>, <4 x i32> } %vld2, i32 1 | 
|  | bool ARMTargetLowering::lowerInterleavedLoad( | 
|  | LoadInst *LI, ArrayRef<ShuffleVectorInst *> Shuffles, | 
|  | ArrayRef<unsigned> Indices, unsigned Factor) const { | 
|  | assert(Factor >= 2 && Factor <= getMaxSupportedInterleaveFactor() && | 
|  | "Invalid interleave factor"); | 
|  | assert(!Shuffles.empty() && "Empty shufflevector input"); | 
|  | assert(Shuffles.size() == Indices.size() && | 
|  | "Unmatched number of shufflevectors and indices"); | 
|  |  | 
|  | auto *VecTy = cast<FixedVectorType>(Shuffles[0]->getType()); | 
|  | Type *EltTy = VecTy->getElementType(); | 
|  |  | 
|  | const DataLayout &DL = LI->getModule()->getDataLayout(); | 
|  |  | 
|  | // Skip if we do not have NEON and skip illegal vector types. We can | 
|  | // "legalize" wide vector types into multiple interleaved accesses as long as | 
|  | // the vector types are divisible by 128. | 
|  | if (!isLegalInterleavedAccessType(Factor, VecTy, DL)) | 
|  | return false; | 
|  |  | 
|  | unsigned NumLoads = getNumInterleavedAccesses(VecTy, DL); | 
|  |  | 
|  | // A pointer vector can not be the return type of the ldN intrinsics. Need to | 
|  | // load integer vectors first and then convert to pointer vectors. | 
|  | if (EltTy->isPointerTy()) | 
|  | VecTy = FixedVectorType::get(DL.getIntPtrType(EltTy), VecTy); | 
|  |  | 
|  | IRBuilder<> Builder(LI); | 
|  |  | 
|  | // The base address of the load. | 
|  | Value *BaseAddr = LI->getPointerOperand(); | 
|  |  | 
|  | if (NumLoads > 1) { | 
|  | // If we're going to generate more than one load, reset the sub-vector type | 
|  | // to something legal. | 
|  | VecTy = FixedVectorType::get(VecTy->getElementType(), | 
|  | VecTy->getNumElements() / NumLoads); | 
|  |  | 
|  | // We will compute the pointer operand of each load from the original base | 
|  | // address using GEPs. Cast the base address to a pointer to the scalar | 
|  | // element type. | 
|  | BaseAddr = Builder.CreateBitCast( | 
|  | BaseAddr, | 
|  | VecTy->getElementType()->getPointerTo(LI->getPointerAddressSpace())); | 
|  | } | 
|  |  | 
|  | assert(isTypeLegal(EVT::getEVT(VecTy)) && "Illegal vldN vector type!"); | 
|  |  | 
|  | auto createLoadIntrinsic = [&](Value *BaseAddr) { | 
|  | if (Subtarget->hasNEON()) { | 
|  | Type *Int8Ptr = Builder.getInt8PtrTy(LI->getPointerAddressSpace()); | 
|  | Type *Tys[] = {VecTy, Int8Ptr}; | 
|  | static const Intrinsic::ID LoadInts[3] = {Intrinsic::arm_neon_vld2, | 
|  | Intrinsic::arm_neon_vld3, | 
|  | Intrinsic::arm_neon_vld4}; | 
|  | Function *VldnFunc = | 
|  | Intrinsic::getDeclaration(LI->getModule(), LoadInts[Factor - 2], Tys); | 
|  |  | 
|  | SmallVector<Value *, 2> Ops; | 
|  | Ops.push_back(Builder.CreateBitCast(BaseAddr, Int8Ptr)); | 
|  | Ops.push_back(Builder.getInt32(LI->getAlignment())); | 
|  |  | 
|  | return Builder.CreateCall(VldnFunc, Ops, "vldN"); | 
|  | } else { | 
|  | assert((Factor == 2 || Factor == 4) && | 
|  | "expected interleave factor of 2 or 4 for MVE"); | 
|  | Intrinsic::ID LoadInts = | 
|  | Factor == 2 ? Intrinsic::arm_mve_vld2q : Intrinsic::arm_mve_vld4q; | 
|  | Type *VecEltTy = | 
|  | VecTy->getElementType()->getPointerTo(LI->getPointerAddressSpace()); | 
|  | Type *Tys[] = {VecTy, VecEltTy}; | 
|  | Function *VldnFunc = | 
|  | Intrinsic::getDeclaration(LI->getModule(), LoadInts, Tys); | 
|  |  | 
|  | SmallVector<Value *, 2> Ops; | 
|  | Ops.push_back(Builder.CreateBitCast(BaseAddr, VecEltTy)); | 
|  | return Builder.CreateCall(VldnFunc, Ops, "vldN"); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Holds sub-vectors extracted from the load intrinsic return values. The | 
|  | // sub-vectors are associated with the shufflevector instructions they will | 
|  | // replace. | 
|  | DenseMap<ShuffleVectorInst *, SmallVector<Value *, 4>> SubVecs; | 
|  |  | 
|  | for (unsigned LoadCount = 0; LoadCount < NumLoads; ++LoadCount) { | 
|  | // If we're generating more than one load, compute the base address of | 
|  | // subsequent loads as an offset from the previous. | 
|  | if (LoadCount > 0) | 
|  | BaseAddr = Builder.CreateConstGEP1_32(VecTy->getElementType(), BaseAddr, | 
|  | VecTy->getNumElements() * Factor); | 
|  |  | 
|  | CallInst *VldN = createLoadIntrinsic(BaseAddr); | 
|  |  | 
|  | // Replace uses of each shufflevector with the corresponding vector loaded | 
|  | // by ldN. | 
|  | for (unsigned i = 0; i < Shuffles.size(); i++) { | 
|  | ShuffleVectorInst *SV = Shuffles[i]; | 
|  | unsigned Index = Indices[i]; | 
|  |  | 
|  | Value *SubVec = Builder.CreateExtractValue(VldN, Index); | 
|  |  | 
|  | // Convert the integer vector to pointer vector if the element is pointer. | 
|  | if (EltTy->isPointerTy()) | 
|  | SubVec = Builder.CreateIntToPtr( | 
|  | SubVec, | 
|  | FixedVectorType::get(SV->getType()->getElementType(), VecTy)); | 
|  |  | 
|  | SubVecs[SV].push_back(SubVec); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Replace uses of the shufflevector instructions with the sub-vectors | 
|  | // returned by the load intrinsic. If a shufflevector instruction is | 
|  | // associated with more than one sub-vector, those sub-vectors will be | 
|  | // concatenated into a single wide vector. | 
|  | for (ShuffleVectorInst *SVI : Shuffles) { | 
|  | auto &SubVec = SubVecs[SVI]; | 
|  | auto *WideVec = | 
|  | SubVec.size() > 1 ? concatenateVectors(Builder, SubVec) : SubVec[0]; | 
|  | SVI->replaceAllUsesWith(WideVec); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /// Lower an interleaved store into a vstN intrinsic. | 
|  | /// | 
|  | /// E.g. Lower an interleaved store (Factor = 3): | 
|  | ///        %i.vec = shuffle <8 x i32> %v0, <8 x i32> %v1, | 
|  | ///                                  <0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11> | 
|  | ///        store <12 x i32> %i.vec, <12 x i32>* %ptr, align 4 | 
|  | /// | 
|  | ///      Into: | 
|  | ///        %sub.v0 = shuffle <8 x i32> %v0, <8 x i32> v1, <0, 1, 2, 3> | 
|  | ///        %sub.v1 = shuffle <8 x i32> %v0, <8 x i32> v1, <4, 5, 6, 7> | 
|  | ///        %sub.v2 = shuffle <8 x i32> %v0, <8 x i32> v1, <8, 9, 10, 11> | 
|  | ///        call void llvm.arm.neon.vst3(%ptr, %sub.v0, %sub.v1, %sub.v2, 4) | 
|  | /// | 
|  | /// Note that the new shufflevectors will be removed and we'll only generate one | 
|  | /// vst3 instruction in CodeGen. | 
|  | /// | 
|  | /// Example for a more general valid mask (Factor 3). Lower: | 
|  | ///        %i.vec = shuffle <32 x i32> %v0, <32 x i32> %v1, | 
|  | ///                 <4, 32, 16, 5, 33, 17, 6, 34, 18, 7, 35, 19> | 
|  | ///        store <12 x i32> %i.vec, <12 x i32>* %ptr | 
|  | /// | 
|  | ///      Into: | 
|  | ///        %sub.v0 = shuffle <32 x i32> %v0, <32 x i32> v1, <4, 5, 6, 7> | 
|  | ///        %sub.v1 = shuffle <32 x i32> %v0, <32 x i32> v1, <32, 33, 34, 35> | 
|  | ///        %sub.v2 = shuffle <32 x i32> %v0, <32 x i32> v1, <16, 17, 18, 19> | 
|  | ///        call void llvm.arm.neon.vst3(%ptr, %sub.v0, %sub.v1, %sub.v2, 4) | 
|  | bool ARMTargetLowering::lowerInterleavedStore(StoreInst *SI, | 
|  | ShuffleVectorInst *SVI, | 
|  | unsigned Factor) const { | 
|  | assert(Factor >= 2 && Factor <= getMaxSupportedInterleaveFactor() && | 
|  | "Invalid interleave factor"); | 
|  |  | 
|  | auto *VecTy = cast<FixedVectorType>(SVI->getType()); | 
|  | assert(VecTy->getNumElements() % Factor == 0 && "Invalid interleaved store"); | 
|  |  | 
|  | unsigned LaneLen = VecTy->getNumElements() / Factor; | 
|  | Type *EltTy = VecTy->getElementType(); | 
|  | auto *SubVecTy = FixedVectorType::get(EltTy, LaneLen); | 
|  |  | 
|  | const DataLayout &DL = SI->getModule()->getDataLayout(); | 
|  |  | 
|  | // Skip if we do not have NEON and skip illegal vector types. We can | 
|  | // "legalize" wide vector types into multiple interleaved accesses as long as | 
|  | // the vector types are divisible by 128. | 
|  | if (!isLegalInterleavedAccessType(Factor, SubVecTy, DL)) | 
|  | return false; | 
|  |  | 
|  | unsigned NumStores = getNumInterleavedAccesses(SubVecTy, DL); | 
|  |  | 
|  | Value *Op0 = SVI->getOperand(0); | 
|  | Value *Op1 = SVI->getOperand(1); | 
|  | IRBuilder<> Builder(SI); | 
|  |  | 
|  | // StN intrinsics don't support pointer vectors as arguments. Convert pointer | 
|  | // vectors to integer vectors. | 
|  | if (EltTy->isPointerTy()) { | 
|  | Type *IntTy = DL.getIntPtrType(EltTy); | 
|  |  | 
|  | // Convert to the corresponding integer vector. | 
|  | auto *IntVecTy = | 
|  | FixedVectorType::get(IntTy, cast<FixedVectorType>(Op0->getType())); | 
|  | Op0 = Builder.CreatePtrToInt(Op0, IntVecTy); | 
|  | Op1 = Builder.CreatePtrToInt(Op1, IntVecTy); | 
|  |  | 
|  | SubVecTy = FixedVectorType::get(IntTy, LaneLen); | 
|  | } | 
|  |  | 
|  | // The base address of the store. | 
|  | Value *BaseAddr = SI->getPointerOperand(); | 
|  |  | 
|  | if (NumStores > 1) { | 
|  | // If we're going to generate more than one store, reset the lane length | 
|  | // and sub-vector type to something legal. | 
|  | LaneLen /= NumStores; | 
|  | SubVecTy = FixedVectorType::get(SubVecTy->getElementType(), LaneLen); | 
|  |  | 
|  | // We will compute the pointer operand of each store from the original base | 
|  | // address using GEPs. Cast the base address to a pointer to the scalar | 
|  | // element type. | 
|  | BaseAddr = Builder.CreateBitCast( | 
|  | BaseAddr, | 
|  | SubVecTy->getElementType()->getPointerTo(SI->getPointerAddressSpace())); | 
|  | } | 
|  |  | 
|  | assert(isTypeLegal(EVT::getEVT(SubVecTy)) && "Illegal vstN vector type!"); | 
|  |  | 
|  | auto Mask = SVI->getShuffleMask(); | 
|  |  | 
|  | auto createStoreIntrinsic = [&](Value *BaseAddr, | 
|  | SmallVectorImpl<Value *> &Shuffles) { | 
|  | if (Subtarget->hasNEON()) { | 
|  | static const Intrinsic::ID StoreInts[3] = {Intrinsic::arm_neon_vst2, | 
|  | Intrinsic::arm_neon_vst3, | 
|  | Intrinsic::arm_neon_vst4}; | 
|  | Type *Int8Ptr = Builder.getInt8PtrTy(SI->getPointerAddressSpace()); | 
|  | Type *Tys[] = {Int8Ptr, SubVecTy}; | 
|  |  | 
|  | Function *VstNFunc = Intrinsic::getDeclaration( | 
|  | SI->getModule(), StoreInts[Factor - 2], Tys); | 
|  |  | 
|  | SmallVector<Value *, 6> Ops; | 
|  | Ops.push_back(Builder.CreateBitCast(BaseAddr, Int8Ptr)); | 
|  | for (auto S : Shuffles) | 
|  | Ops.push_back(S); | 
|  | Ops.push_back(Builder.getInt32(SI->getAlignment())); | 
|  | Builder.CreateCall(VstNFunc, Ops); | 
|  | } else { | 
|  | assert((Factor == 2 || Factor == 4) && | 
|  | "expected interleave factor of 2 or 4 for MVE"); | 
|  | Intrinsic::ID StoreInts = | 
|  | Factor == 2 ? Intrinsic::arm_mve_vst2q : Intrinsic::arm_mve_vst4q; | 
|  | Type *EltPtrTy = SubVecTy->getElementType()->getPointerTo( | 
|  | SI->getPointerAddressSpace()); | 
|  | Type *Tys[] = {EltPtrTy, SubVecTy}; | 
|  | Function *VstNFunc = | 
|  | Intrinsic::getDeclaration(SI->getModule(), StoreInts, Tys); | 
|  |  | 
|  | SmallVector<Value *, 6> Ops; | 
|  | Ops.push_back(Builder.CreateBitCast(BaseAddr, EltPtrTy)); | 
|  | for (auto S : Shuffles) | 
|  | Ops.push_back(S); | 
|  | for (unsigned F = 0; F < Factor; F++) { | 
|  | Ops.push_back(Builder.getInt32(F)); | 
|  | Builder.CreateCall(VstNFunc, Ops); | 
|  | Ops.pop_back(); | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | for (unsigned StoreCount = 0; StoreCount < NumStores; ++StoreCount) { | 
|  | // If we generating more than one store, we compute the base address of | 
|  | // subsequent stores as an offset from the previous. | 
|  | if (StoreCount > 0) | 
|  | BaseAddr = Builder.CreateConstGEP1_32(SubVecTy->getElementType(), | 
|  | BaseAddr, LaneLen * Factor); | 
|  |  | 
|  | SmallVector<Value *, 4> Shuffles; | 
|  |  | 
|  | // Split the shufflevector operands into sub vectors for the new vstN call. | 
|  | for (unsigned i = 0; i < Factor; i++) { | 
|  | unsigned IdxI = StoreCount * LaneLen * Factor + i; | 
|  | if (Mask[IdxI] >= 0) { | 
|  | Shuffles.push_back(Builder.CreateShuffleVector( | 
|  | Op0, Op1, createSequentialMask(Mask[IdxI], LaneLen, 0))); | 
|  | } else { | 
|  | unsigned StartMask = 0; | 
|  | for (unsigned j = 1; j < LaneLen; j++) { | 
|  | unsigned IdxJ = StoreCount * LaneLen * Factor + j; | 
|  | if (Mask[IdxJ * Factor + IdxI] >= 0) { | 
|  | StartMask = Mask[IdxJ * Factor + IdxI] - IdxJ; | 
|  | break; | 
|  | } | 
|  | } | 
|  | // Note: If all elements in a chunk are undefs, StartMask=0! | 
|  | // Note: Filling undef gaps with random elements is ok, since | 
|  | // those elements were being written anyway (with undefs). | 
|  | // In the case of all undefs we're defaulting to using elems from 0 | 
|  | // Note: StartMask cannot be negative, it's checked in | 
|  | // isReInterleaveMask | 
|  | Shuffles.push_back(Builder.CreateShuffleVector( | 
|  | Op0, Op1, createSequentialMask(StartMask, LaneLen, 0))); | 
|  | } | 
|  | } | 
|  |  | 
|  | createStoreIntrinsic(BaseAddr, Shuffles); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | enum HABaseType { | 
|  | HA_UNKNOWN = 0, | 
|  | HA_FLOAT, | 
|  | HA_DOUBLE, | 
|  | HA_VECT64, | 
|  | HA_VECT128 | 
|  | }; | 
|  |  | 
|  | static bool isHomogeneousAggregate(Type *Ty, HABaseType &Base, | 
|  | uint64_t &Members) { | 
|  | if (auto *ST = dyn_cast<StructType>(Ty)) { | 
|  | for (unsigned i = 0; i < ST->getNumElements(); ++i) { | 
|  | uint64_t SubMembers = 0; | 
|  | if (!isHomogeneousAggregate(ST->getElementType(i), Base, SubMembers)) | 
|  | return false; | 
|  | Members += SubMembers; | 
|  | } | 
|  | } else if (auto *AT = dyn_cast<ArrayType>(Ty)) { | 
|  | uint64_t SubMembers = 0; | 
|  | if (!isHomogeneousAggregate(AT->getElementType(), Base, SubMembers)) | 
|  | return false; | 
|  | Members += SubMembers * AT->getNumElements(); | 
|  | } else if (Ty->isFloatTy()) { | 
|  | if (Base != HA_UNKNOWN && Base != HA_FLOAT) | 
|  | return false; | 
|  | Members = 1; | 
|  | Base = HA_FLOAT; | 
|  | } else if (Ty->isDoubleTy()) { | 
|  | if (Base != HA_UNKNOWN && Base != HA_DOUBLE) | 
|  | return false; | 
|  | Members = 1; | 
|  | Base = HA_DOUBLE; | 
|  | } else if (auto *VT = dyn_cast<VectorType>(Ty)) { | 
|  | Members = 1; | 
|  | switch (Base) { | 
|  | case HA_FLOAT: | 
|  | case HA_DOUBLE: | 
|  | return false; | 
|  | case HA_VECT64: | 
|  | return VT->getPrimitiveSizeInBits().getFixedSize() == 64; | 
|  | case HA_VECT128: | 
|  | return VT->getPrimitiveSizeInBits().getFixedSize() == 128; | 
|  | case HA_UNKNOWN: | 
|  | switch (VT->getPrimitiveSizeInBits().getFixedSize()) { | 
|  | case 64: | 
|  | Base = HA_VECT64; | 
|  | return true; | 
|  | case 128: | 
|  | Base = HA_VECT128; | 
|  | return true; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return (Members > 0 && Members <= 4); | 
|  | } | 
|  |  | 
|  | /// Return the correct alignment for the current calling convention. | 
|  | Align ARMTargetLowering::getABIAlignmentForCallingConv(Type *ArgTy, | 
|  | DataLayout DL) const { | 
|  | const Align ABITypeAlign(DL.getABITypeAlignment(ArgTy)); | 
|  | if (!ArgTy->isVectorTy()) | 
|  | return ABITypeAlign; | 
|  |  | 
|  | // Avoid over-aligning vector parameters. It would require realigning the | 
|  | // stack and waste space for no real benefit. | 
|  | return std::min(ABITypeAlign, DL.getStackAlignment()); | 
|  | } | 
|  |  | 
|  | /// Return true if a type is an AAPCS-VFP homogeneous aggregate or one of | 
|  | /// [N x i32] or [N x i64]. This allows front-ends to skip emitting padding when | 
|  | /// passing according to AAPCS rules. | 
|  | bool ARMTargetLowering::functionArgumentNeedsConsecutiveRegisters( | 
|  | Type *Ty, CallingConv::ID CallConv, bool isVarArg) const { | 
|  | if (getEffectiveCallingConv(CallConv, isVarArg) != | 
|  | CallingConv::ARM_AAPCS_VFP) | 
|  | return false; | 
|  |  | 
|  | HABaseType Base = HA_UNKNOWN; | 
|  | uint64_t Members = 0; | 
|  | bool IsHA = isHomogeneousAggregate(Ty, Base, Members); | 
|  | LLVM_DEBUG(dbgs() << "isHA: " << IsHA << " "; Ty->dump()); | 
|  |  | 
|  | bool IsIntArray = Ty->isArrayTy() && Ty->getArrayElementType()->isIntegerTy(); | 
|  | return IsHA || IsIntArray; | 
|  | } | 
|  |  | 
|  | Register ARMTargetLowering::getExceptionPointerRegister( | 
|  | const Constant *PersonalityFn) const { | 
|  | // Platforms which do not use SjLj EH may return values in these registers | 
|  | // via the personality function. | 
|  | return Subtarget->useSjLjEH() ? Register() : ARM::R0; | 
|  | } | 
|  |  | 
|  | Register ARMTargetLowering::getExceptionSelectorRegister( | 
|  | const Constant *PersonalityFn) const { | 
|  | // Platforms which do not use SjLj EH may return values in these registers | 
|  | // via the personality function. | 
|  | return Subtarget->useSjLjEH() ? Register() : ARM::R1; | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::initializeSplitCSR(MachineBasicBlock *Entry) const { | 
|  | // Update IsSplitCSR in ARMFunctionInfo. | 
|  | ARMFunctionInfo *AFI = Entry->getParent()->getInfo<ARMFunctionInfo>(); | 
|  | AFI->setIsSplitCSR(true); | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::insertCopiesSplitCSR( | 
|  | MachineBasicBlock *Entry, | 
|  | const SmallVectorImpl<MachineBasicBlock *> &Exits) const { | 
|  | const ARMBaseRegisterInfo *TRI = Subtarget->getRegisterInfo(); | 
|  | const MCPhysReg *IStart = TRI->getCalleeSavedRegsViaCopy(Entry->getParent()); | 
|  | if (!IStart) | 
|  | return; | 
|  |  | 
|  | const TargetInstrInfo *TII = Subtarget->getInstrInfo(); | 
|  | MachineRegisterInfo *MRI = &Entry->getParent()->getRegInfo(); | 
|  | MachineBasicBlock::iterator MBBI = Entry->begin(); | 
|  | for (const MCPhysReg *I = IStart; *I; ++I) { | 
|  | const TargetRegisterClass *RC = nullptr; | 
|  | if (ARM::GPRRegClass.contains(*I)) | 
|  | RC = &ARM::GPRRegClass; | 
|  | else if (ARM::DPRRegClass.contains(*I)) | 
|  | RC = &ARM::DPRRegClass; | 
|  | else | 
|  | llvm_unreachable("Unexpected register class in CSRsViaCopy!"); | 
|  |  | 
|  | Register NewVR = MRI->createVirtualRegister(RC); | 
|  | // Create copy from CSR to a virtual register. | 
|  | // FIXME: this currently does not emit CFI pseudo-instructions, it works | 
|  | // fine for CXX_FAST_TLS since the C++-style TLS access functions should be | 
|  | // nounwind. If we want to generalize this later, we may need to emit | 
|  | // CFI pseudo-instructions. | 
|  | assert(Entry->getParent()->getFunction().hasFnAttribute( | 
|  | Attribute::NoUnwind) && | 
|  | "Function should be nounwind in insertCopiesSplitCSR!"); | 
|  | Entry->addLiveIn(*I); | 
|  | BuildMI(*Entry, MBBI, DebugLoc(), TII->get(TargetOpcode::COPY), NewVR) | 
|  | .addReg(*I); | 
|  |  | 
|  | // Insert the copy-back instructions right before the terminator. | 
|  | for (auto *Exit : Exits) | 
|  | BuildMI(*Exit, Exit->getFirstTerminator(), DebugLoc(), | 
|  | TII->get(TargetOpcode::COPY), *I) | 
|  | .addReg(NewVR); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ARMTargetLowering::finalizeLowering(MachineFunction &MF) const { | 
|  | MF.getFrameInfo().computeMaxCallFrameSize(MF); | 
|  | TargetLoweringBase::finalizeLowering(MF); | 
|  | } |