1804 lines · cpp
1//===-- XCoreISelLowering.cpp - XCore DAG Lowering Implementation ---------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the XCoreTargetLowering class.10//11//===----------------------------------------------------------------------===//12 13#include "XCoreISelLowering.h"14#include "XCore.h"15#include "XCoreMachineFunctionInfo.h"16#include "XCoreSubtarget.h"17#include "XCoreTargetMachine.h"18#include "XCoreTargetObjectFile.h"19#include "llvm/CodeGen/CallingConvLower.h"20#include "llvm/CodeGen/MachineFrameInfo.h"21#include "llvm/CodeGen/MachineFunction.h"22#include "llvm/CodeGen/MachineInstrBuilder.h"23#include "llvm/CodeGen/MachineJumpTableInfo.h"24#include "llvm/CodeGen/MachineRegisterInfo.h"25#include "llvm/CodeGen/ValueTypes.h"26#include "llvm/IR/CallingConv.h"27#include "llvm/IR/Constants.h"28#include "llvm/IR/DerivedTypes.h"29#include "llvm/IR/Function.h"30#include "llvm/IR/GlobalVariable.h"31#include "llvm/IR/Intrinsics.h"32#include "llvm/IR/IntrinsicsXCore.h"33#include "llvm/Support/Debug.h"34#include "llvm/Support/ErrorHandling.h"35#include "llvm/Support/KnownBits.h"36#include "llvm/Support/raw_ostream.h"37#include <algorithm>38 39using namespace llvm;40 41#define DEBUG_TYPE "xcore-lower"42 43XCoreTargetLowering::XCoreTargetLowering(const TargetMachine &TM,44 const XCoreSubtarget &Subtarget)45 : TargetLowering(TM, Subtarget), TM(TM), Subtarget(Subtarget) {46 47 // Set up the register classes.48 addRegisterClass(MVT::i32, &XCore::GRRegsRegClass);49 50 // Compute derived properties from the register classes51 computeRegisterProperties(Subtarget.getRegisterInfo());52 53 setStackPointerRegisterToSaveRestore(XCore::SP);54 55 setSchedulingPreference(Sched::Source);56 57 // Use i32 for setcc operations results (slt, sgt, ...).58 setBooleanContents(ZeroOrOneBooleanContent);59 setBooleanVectorContents(ZeroOrOneBooleanContent); // FIXME: Is this correct?60 61 // XCore does not have the NodeTypes below.62 setOperationAction(ISD::BR_CC, MVT::i32, Expand);63 setOperationAction(ISD::SELECT_CC, MVT::i32, Expand);64 65 // 64bit66 setOperationAction(ISD::ADD, MVT::i64, Custom);67 setOperationAction(ISD::SUB, MVT::i64, Custom);68 setOperationAction(ISD::SMUL_LOHI, MVT::i32, Custom);69 setOperationAction(ISD::UMUL_LOHI, MVT::i32, Custom);70 setOperationAction(ISD::MULHS, MVT::i32, Expand);71 setOperationAction(ISD::MULHU, MVT::i32, Expand);72 setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);73 setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);74 setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);75 76 // Bit Manipulation77 setOperationAction(ISD::CTPOP, MVT::i32, Expand);78 setOperationAction(ISD::ROTL , MVT::i32, Expand);79 setOperationAction(ISD::ROTR , MVT::i32, Expand);80 setOperationAction(ISD::BITREVERSE , MVT::i32, Legal);81 82 setOperationAction(ISD::TRAP, MVT::Other, Legal);83 84 // Jump tables.85 setOperationAction(ISD::BR_JT, MVT::Other, Custom);86 87 setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);88 setOperationAction(ISD::BlockAddress, MVT::i32 , Custom);89 90 // Conversion of i64 -> double produces constantpool nodes91 setOperationAction(ISD::ConstantPool, MVT::i32, Custom);92 93 // Loads94 for (MVT VT : MVT::integer_valuetypes()) {95 setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote);96 setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote);97 setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);98 99 setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i8, Expand);100 setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i16, Expand);101 }102 103 // Custom expand misaligned loads / stores.104 setOperationAction(ISD::LOAD, MVT::i32, Custom);105 setOperationAction(ISD::STORE, MVT::i32, Custom);106 107 // Varargs108 setOperationAction(ISD::VAEND, MVT::Other, Expand);109 setOperationAction(ISD::VACOPY, MVT::Other, Expand);110 setOperationAction(ISD::VAARG, MVT::Other, Custom);111 setOperationAction(ISD::VASTART, MVT::Other, Custom);112 113 // Dynamic stack114 setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);115 setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);116 setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand);117 118 // Exception handling119 setOperationAction(ISD::EH_RETURN, MVT::Other, Custom);120 setOperationAction(ISD::FRAME_TO_ARGS_OFFSET, MVT::i32, Custom);121 122 setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom);123 124 // TRAMPOLINE is custom lowered.125 setOperationAction(ISD::INIT_TRAMPOLINE, MVT::Other, Custom);126 setOperationAction(ISD::ADJUST_TRAMPOLINE, MVT::Other, Custom);127 128 // We want to custom lower some of our intrinsics.129 setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);130 131 MaxStoresPerMemset = MaxStoresPerMemsetOptSize = 4;132 MaxStoresPerMemmove = MaxStoresPerMemmoveOptSize133 = MaxStoresPerMemcpy = MaxStoresPerMemcpyOptSize = 2;134 135 // We have target-specific dag combine patterns for the following nodes:136 setTargetDAGCombine(137 {ISD::STORE, ISD::ADD, ISD::INTRINSIC_VOID, ISD::INTRINSIC_W_CHAIN});138 139 setMinFunctionAlignment(Align(2));140 setPrefFunctionAlignment(Align(4));141 142 // This target doesn't implement native atomics.143 setMaxAtomicSizeInBitsSupported(0);144}145 146bool XCoreTargetLowering::isZExtFree(SDValue Val, EVT VT2) const {147 if (Val.getOpcode() != ISD::LOAD)148 return false;149 150 EVT VT1 = Val.getValueType();151 if (!VT1.isSimple() || !VT1.isInteger() ||152 !VT2.isSimple() || !VT2.isInteger())153 return false;154 155 switch (VT1.getSimpleVT().SimpleTy) {156 default: break;157 case MVT::i8:158 return true;159 }160 161 return false;162}163 164SDValue XCoreTargetLowering::165LowerOperation(SDValue Op, SelectionDAG &DAG) const {166 switch (Op.getOpcode())167 {168 case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);169 case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);170 case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);171 case ISD::ConstantPool: return LowerConstantPool(Op, DAG);172 case ISD::BR_JT: return LowerBR_JT(Op, DAG);173 case ISD::LOAD: return LowerLOAD(Op, DAG);174 case ISD::STORE: return LowerSTORE(Op, DAG);175 case ISD::VAARG: return LowerVAARG(Op, DAG);176 case ISD::VASTART: return LowerVASTART(Op, DAG);177 case ISD::SMUL_LOHI: return LowerSMUL_LOHI(Op, DAG);178 case ISD::UMUL_LOHI: return LowerUMUL_LOHI(Op, DAG);179 // FIXME: Remove these when LegalizeDAGTypes lands.180 case ISD::ADD:181 case ISD::SUB: return ExpandADDSUB(Op.getNode(), DAG);182 case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);183 case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);184 case ISD::FRAME_TO_ARGS_OFFSET: return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);185 case ISD::INIT_TRAMPOLINE: return LowerINIT_TRAMPOLINE(Op, DAG);186 case ISD::ADJUST_TRAMPOLINE: return LowerADJUST_TRAMPOLINE(Op, DAG);187 case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);188 case ISD::ATOMIC_FENCE:189 return LowerATOMIC_FENCE(Op, DAG);190 default:191 llvm_unreachable("unimplemented operand");192 }193}194 195/// ReplaceNodeResults - Replace the results of node with an illegal result196/// type with new values built out of custom code.197void XCoreTargetLowering::ReplaceNodeResults(SDNode *N,198 SmallVectorImpl<SDValue>&Results,199 SelectionDAG &DAG) const {200 switch (N->getOpcode()) {201 default:202 llvm_unreachable("Don't know how to custom expand this!");203 case ISD::ADD:204 case ISD::SUB:205 Results.push_back(ExpandADDSUB(N, DAG));206 return;207 }208}209 210//===----------------------------------------------------------------------===//211// Misc Lower Operation implementation212//===----------------------------------------------------------------------===//213 214SDValue XCoreTargetLowering::getGlobalAddressWrapper(SDValue GA,215 const GlobalValue *GV,216 SelectionDAG &DAG) const {217 // FIXME there is no actual debug info here218 SDLoc dl(GA);219 220 if (GV->getValueType()->isFunctionTy())221 return DAG.getNode(XCoreISD::PCRelativeWrapper, dl, MVT::i32, GA);222 223 const auto *GVar = dyn_cast<GlobalVariable>(GV);224 if ((GV->hasSection() && GV->getSection().starts_with(".cp.")) ||225 (GVar && GVar->isConstant() && GV->hasLocalLinkage()))226 return DAG.getNode(XCoreISD::CPRelativeWrapper, dl, MVT::i32, GA);227 228 return DAG.getNode(XCoreISD::DPRelativeWrapper, dl, MVT::i32, GA);229}230 231static bool IsSmallObject(const GlobalValue *GV, const XCoreTargetLowering &XTL) {232 if (XTL.getTargetMachine().getCodeModel() == CodeModel::Small)233 return true;234 235 Type *ObjType = GV->getValueType();236 if (!ObjType->isSized())237 return false;238 239 auto &DL = GV->getDataLayout();240 unsigned ObjSize = DL.getTypeAllocSize(ObjType);241 return ObjSize < CodeModelLargeSize && ObjSize != 0;242}243 244SDValue XCoreTargetLowering::245LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const246{247 const GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Op);248 const GlobalValue *GV = GN->getGlobal();249 SDLoc DL(GN);250 int64_t Offset = GN->getOffset();251 if (IsSmallObject(GV, *this)) {252 // We can only fold positive offsets that are a multiple of the word size.253 int64_t FoldedOffset = std::max(Offset & ~3, (int64_t)0);254 SDValue GA = DAG.getTargetGlobalAddress(GV, DL, MVT::i32, FoldedOffset);255 GA = getGlobalAddressWrapper(GA, GV, DAG);256 // Handle the rest of the offset.257 if (Offset != FoldedOffset) {258 SDValue Remaining =259 DAG.getSignedConstant(Offset - FoldedOffset, DL, MVT::i32);260 GA = DAG.getNode(ISD::ADD, DL, MVT::i32, GA, Remaining);261 }262 return GA;263 } else {264 // Ideally we would not fold in offset with an index <= 11.265 Type *Ty = Type::getInt32Ty(*DAG.getContext());266 Constant *Idx = ConstantInt::get(Ty, Offset);267 Constant *GAI = ConstantExpr::getGetElementPtr(268 Type::getInt8Ty(*DAG.getContext()), const_cast<GlobalValue *>(GV), Idx);269 SDValue CP = DAG.getConstantPool(GAI, MVT::i32);270 return DAG.getLoad(getPointerTy(DAG.getDataLayout()), DL,271 DAG.getEntryNode(), CP, MachinePointerInfo());272 }273}274 275SDValue XCoreTargetLowering::276LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const277{278 SDLoc DL(Op);279 auto PtrVT = getPointerTy(DAG.getDataLayout());280 const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();281 SDValue Result = DAG.getTargetBlockAddress(BA, PtrVT);282 283 return DAG.getNode(XCoreISD::PCRelativeWrapper, DL, PtrVT, Result);284}285 286SDValue XCoreTargetLowering::287LowerConstantPool(SDValue Op, SelectionDAG &DAG) const288{289 ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op);290 // FIXME there isn't really debug info here291 SDLoc dl(CP);292 EVT PtrVT = Op.getValueType();293 SDValue Res;294 if (CP->isMachineConstantPoolEntry()) {295 Res = DAG.getTargetConstantPool(CP->getMachineCPVal(), PtrVT,296 CP->getAlign(), CP->getOffset());297 } else {298 Res = DAG.getTargetConstantPool(CP->getConstVal(), PtrVT, CP->getAlign(),299 CP->getOffset());300 }301 return DAG.getNode(XCoreISD::CPRelativeWrapper, dl, MVT::i32, Res);302}303 304unsigned XCoreTargetLowering::getJumpTableEncoding() const {305 return MachineJumpTableInfo::EK_Inline;306}307 308SDValue XCoreTargetLowering::309LowerBR_JT(SDValue Op, SelectionDAG &DAG) const310{311 SDValue Chain = Op.getOperand(0);312 SDValue Table = Op.getOperand(1);313 SDValue Index = Op.getOperand(2);314 SDLoc dl(Op);315 JumpTableSDNode *JT = cast<JumpTableSDNode>(Table);316 unsigned JTI = JT->getIndex();317 MachineFunction &MF = DAG.getMachineFunction();318 const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();319 SDValue TargetJT = DAG.getTargetJumpTable(JT->getIndex(), MVT::i32);320 321 unsigned NumEntries = MJTI->getJumpTables()[JTI].MBBs.size();322 if (NumEntries <= 32) {323 return DAG.getNode(XCoreISD::BR_JT, dl, MVT::Other, Chain, TargetJT, Index);324 }325 assert((NumEntries >> 31) == 0);326 SDValue ScaledIndex = DAG.getNode(ISD::SHL, dl, MVT::i32, Index,327 DAG.getConstant(1, dl, MVT::i32));328 return DAG.getNode(XCoreISD::BR_JT32, dl, MVT::Other, Chain, TargetJT,329 ScaledIndex);330}331 332SDValue XCoreTargetLowering::lowerLoadWordFromAlignedBasePlusOffset(333 const SDLoc &DL, SDValue Chain, SDValue Base, int64_t Offset,334 SelectionDAG &DAG) const {335 auto PtrVT = getPointerTy(DAG.getDataLayout());336 if ((Offset & 0x3) == 0) {337 return DAG.getLoad(PtrVT, DL, Chain, Base, MachinePointerInfo());338 }339 // Lower to pair of consecutive word aligned loads plus some bit shifting.340 int32_t HighOffset = alignTo(Offset, 4);341 int32_t LowOffset = HighOffset - 4;342 SDValue LowAddr, HighAddr;343 if (GlobalAddressSDNode *GASD =344 dyn_cast<GlobalAddressSDNode>(Base.getNode())) {345 LowAddr = DAG.getGlobalAddress(GASD->getGlobal(), DL, Base.getValueType(),346 LowOffset);347 HighAddr = DAG.getGlobalAddress(GASD->getGlobal(), DL, Base.getValueType(),348 HighOffset);349 } else {350 LowAddr = DAG.getNode(ISD::ADD, DL, MVT::i32, Base,351 DAG.getConstant(LowOffset, DL, MVT::i32));352 HighAddr = DAG.getNode(ISD::ADD, DL, MVT::i32, Base,353 DAG.getConstant(HighOffset, DL, MVT::i32));354 }355 SDValue LowShift = DAG.getConstant((Offset - LowOffset) * 8, DL, MVT::i32);356 SDValue HighShift = DAG.getConstant((HighOffset - Offset) * 8, DL, MVT::i32);357 358 SDValue Low = DAG.getLoad(PtrVT, DL, Chain, LowAddr, MachinePointerInfo());359 SDValue High = DAG.getLoad(PtrVT, DL, Chain, HighAddr, MachinePointerInfo());360 SDValue LowShifted = DAG.getNode(ISD::SRL, DL, MVT::i32, Low, LowShift);361 SDValue HighShifted = DAG.getNode(ISD::SHL, DL, MVT::i32, High, HighShift);362 SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, LowShifted, HighShifted);363 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Low.getValue(1),364 High.getValue(1));365 SDValue Ops[] = { Result, Chain };366 return DAG.getMergeValues(Ops, DL);367}368 369static bool isWordAligned(SDValue Value, SelectionDAG &DAG)370{371 KnownBits Known = DAG.computeKnownBits(Value);372 return Known.countMinTrailingZeros() >= 2;373}374 375SDValue XCoreTargetLowering::LowerLOAD(SDValue Op, SelectionDAG &DAG) const {376 const TargetLowering &TLI = DAG.getTargetLoweringInfo();377 LLVMContext &Context = *DAG.getContext();378 LoadSDNode *LD = cast<LoadSDNode>(Op);379 assert(LD->getExtensionType() == ISD::NON_EXTLOAD &&380 "Unexpected extension type");381 assert(LD->getMemoryVT() == MVT::i32 && "Unexpected load EVT");382 383 if (allowsMemoryAccessForAlignment(Context, DAG.getDataLayout(),384 LD->getMemoryVT(), *LD->getMemOperand()))385 return SDValue();386 387 SDValue Chain = LD->getChain();388 SDValue BasePtr = LD->getBasePtr();389 SDLoc DL(Op);390 391 if (!LD->isVolatile()) {392 const GlobalValue *GV;393 int64_t Offset = 0;394 if (DAG.isBaseWithConstantOffset(BasePtr) &&395 isWordAligned(BasePtr->getOperand(0), DAG)) {396 SDValue NewBasePtr = BasePtr->getOperand(0);397 Offset = cast<ConstantSDNode>(BasePtr->getOperand(1))->getSExtValue();398 return lowerLoadWordFromAlignedBasePlusOffset(DL, Chain, NewBasePtr,399 Offset, DAG);400 }401 if (TLI.isGAPlusOffset(BasePtr.getNode(), GV, Offset) &&402 GV->getPointerAlignment(DAG.getDataLayout()) >= 4) {403 SDValue NewBasePtr = DAG.getGlobalAddress(GV, DL,404 BasePtr->getValueType(0));405 return lowerLoadWordFromAlignedBasePlusOffset(DL, Chain, NewBasePtr,406 Offset, DAG);407 }408 }409 410 if (LD->getAlign() == Align(2)) {411 SDValue Low = DAG.getExtLoad(ISD::ZEXTLOAD, DL, MVT::i32, Chain, BasePtr,412 LD->getPointerInfo(), MVT::i16, Align(2),413 LD->getMemOperand()->getFlags());414 SDValue HighAddr = DAG.getNode(ISD::ADD, DL, MVT::i32, BasePtr,415 DAG.getConstant(2, DL, MVT::i32));416 SDValue High =417 DAG.getExtLoad(ISD::EXTLOAD, DL, MVT::i32, Chain, HighAddr,418 LD->getPointerInfo().getWithOffset(2), MVT::i16,419 Align(2), LD->getMemOperand()->getFlags());420 SDValue HighShifted = DAG.getNode(ISD::SHL, DL, MVT::i32, High,421 DAG.getConstant(16, DL, MVT::i32));422 SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Low, HighShifted);423 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Low.getValue(1),424 High.getValue(1));425 SDValue Ops[] = { Result, Chain };426 return DAG.getMergeValues(Ops, DL);427 }428 429 // Lower to a call to __misaligned_load(BasePtr).430 Type *IntPtrTy = DAG.getDataLayout().getIntPtrType(Context);431 TargetLowering::ArgListTy Args;432 Args.emplace_back(BasePtr, IntPtrTy);433 434 TargetLowering::CallLoweringInfo CLI(DAG);435 CLI.setDebugLoc(DL).setChain(Chain).setLibCallee(436 CallingConv::C, IntPtrTy,437 DAG.getExternalSymbol("__misaligned_load",438 getPointerTy(DAG.getDataLayout())),439 std::move(Args));440 441 std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI);442 SDValue Ops[] = { CallResult.first, CallResult.second };443 return DAG.getMergeValues(Ops, DL);444}445 446SDValue XCoreTargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG) const {447 LLVMContext &Context = *DAG.getContext();448 StoreSDNode *ST = cast<StoreSDNode>(Op);449 assert(!ST->isTruncatingStore() && "Unexpected store type");450 assert(ST->getMemoryVT() == MVT::i32 && "Unexpected store EVT");451 452 if (allowsMemoryAccessForAlignment(Context, DAG.getDataLayout(),453 ST->getMemoryVT(), *ST->getMemOperand()))454 return SDValue();455 456 SDValue Chain = ST->getChain();457 SDValue BasePtr = ST->getBasePtr();458 SDValue Value = ST->getValue();459 SDLoc dl(Op);460 461 if (ST->getAlign() == Align(2)) {462 SDValue Low = Value;463 SDValue High = DAG.getNode(ISD::SRL, dl, MVT::i32, Value,464 DAG.getConstant(16, dl, MVT::i32));465 SDValue StoreLow =466 DAG.getTruncStore(Chain, dl, Low, BasePtr, ST->getPointerInfo(),467 MVT::i16, Align(2), ST->getMemOperand()->getFlags());468 SDValue HighAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, BasePtr,469 DAG.getConstant(2, dl, MVT::i32));470 SDValue StoreHigh = DAG.getTruncStore(471 Chain, dl, High, HighAddr, ST->getPointerInfo().getWithOffset(2),472 MVT::i16, Align(2), ST->getMemOperand()->getFlags());473 return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, StoreLow, StoreHigh);474 }475 476 // Lower to a call to __misaligned_store(BasePtr, Value).477 Type *IntPtrTy = DAG.getDataLayout().getIntPtrType(Context);478 TargetLowering::ArgListTy Args;479 Args.emplace_back(BasePtr, IntPtrTy);480 Args.emplace_back(Value, IntPtrTy);481 482 TargetLowering::CallLoweringInfo CLI(DAG);483 CLI.setDebugLoc(dl).setChain(Chain).setCallee(484 CallingConv::C, Type::getVoidTy(Context),485 DAG.getExternalSymbol("__misaligned_store",486 getPointerTy(DAG.getDataLayout())),487 std::move(Args));488 489 std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI);490 return CallResult.second;491}492 493SDValue XCoreTargetLowering::494LowerSMUL_LOHI(SDValue Op, SelectionDAG &DAG) const495{496 assert(Op.getValueType() == MVT::i32 && Op.getOpcode() == ISD::SMUL_LOHI &&497 "Unexpected operand to lower!");498 SDLoc dl(Op);499 SDValue LHS = Op.getOperand(0);500 SDValue RHS = Op.getOperand(1);501 SDValue Zero = DAG.getConstant(0, dl, MVT::i32);502 SDValue Hi = DAG.getNode(XCoreISD::MACCS, dl,503 DAG.getVTList(MVT::i32, MVT::i32), Zero, Zero,504 LHS, RHS);505 SDValue Lo(Hi.getNode(), 1);506 SDValue Ops[] = { Lo, Hi };507 return DAG.getMergeValues(Ops, dl);508}509 510SDValue XCoreTargetLowering::511LowerUMUL_LOHI(SDValue Op, SelectionDAG &DAG) const512{513 assert(Op.getValueType() == MVT::i32 && Op.getOpcode() == ISD::UMUL_LOHI &&514 "Unexpected operand to lower!");515 SDLoc dl(Op);516 SDValue LHS = Op.getOperand(0);517 SDValue RHS = Op.getOperand(1);518 SDValue Zero = DAG.getConstant(0, dl, MVT::i32);519 SDValue Hi = DAG.getNode(XCoreISD::LMUL, dl,520 DAG.getVTList(MVT::i32, MVT::i32), LHS, RHS,521 Zero, Zero);522 SDValue Lo(Hi.getNode(), 1);523 SDValue Ops[] = { Lo, Hi };524 return DAG.getMergeValues(Ops, dl);525}526 527/// isADDADDMUL - Return whether Op is in a form that is equivalent to528/// add(add(mul(x,y),a),b). If requireIntermediatesHaveOneUse is true then529/// each intermediate result in the calculation must also have a single use.530/// If the Op is in the correct form the constituent parts are written to Mul0,531/// Mul1, Addend0 and Addend1.532static bool533isADDADDMUL(SDValue Op, SDValue &Mul0, SDValue &Mul1, SDValue &Addend0,534 SDValue &Addend1, bool requireIntermediatesHaveOneUse)535{536 if (Op.getOpcode() != ISD::ADD)537 return false;538 SDValue N0 = Op.getOperand(0);539 SDValue N1 = Op.getOperand(1);540 SDValue AddOp;541 SDValue OtherOp;542 if (N0.getOpcode() == ISD::ADD) {543 AddOp = N0;544 OtherOp = N1;545 } else if (N1.getOpcode() == ISD::ADD) {546 AddOp = N1;547 OtherOp = N0;548 } else {549 return false;550 }551 if (requireIntermediatesHaveOneUse && !AddOp.hasOneUse())552 return false;553 if (OtherOp.getOpcode() == ISD::MUL) {554 // add(add(a,b),mul(x,y))555 if (requireIntermediatesHaveOneUse && !OtherOp.hasOneUse())556 return false;557 Mul0 = OtherOp.getOperand(0);558 Mul1 = OtherOp.getOperand(1);559 Addend0 = AddOp.getOperand(0);560 Addend1 = AddOp.getOperand(1);561 return true;562 }563 if (AddOp.getOperand(0).getOpcode() == ISD::MUL) {564 // add(add(mul(x,y),a),b)565 if (requireIntermediatesHaveOneUse && !AddOp.getOperand(0).hasOneUse())566 return false;567 Mul0 = AddOp.getOperand(0).getOperand(0);568 Mul1 = AddOp.getOperand(0).getOperand(1);569 Addend0 = AddOp.getOperand(1);570 Addend1 = OtherOp;571 return true;572 }573 if (AddOp.getOperand(1).getOpcode() == ISD::MUL) {574 // add(add(a,mul(x,y)),b)575 if (requireIntermediatesHaveOneUse && !AddOp.getOperand(1).hasOneUse())576 return false;577 Mul0 = AddOp.getOperand(1).getOperand(0);578 Mul1 = AddOp.getOperand(1).getOperand(1);579 Addend0 = AddOp.getOperand(0);580 Addend1 = OtherOp;581 return true;582 }583 return false;584}585 586SDValue XCoreTargetLowering::587TryExpandADDWithMul(SDNode *N, SelectionDAG &DAG) const588{589 SDValue Mul;590 SDValue Other;591 if (N->getOperand(0).getOpcode() == ISD::MUL) {592 Mul = N->getOperand(0);593 Other = N->getOperand(1);594 } else if (N->getOperand(1).getOpcode() == ISD::MUL) {595 Mul = N->getOperand(1);596 Other = N->getOperand(0);597 } else {598 return SDValue();599 }600 SDLoc dl(N);601 SDValue LL, RL, AddendL, AddendH;602 LL = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,603 Mul.getOperand(0), DAG.getConstant(0, dl, MVT::i32));604 RL = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,605 Mul.getOperand(1), DAG.getConstant(0, dl, MVT::i32));606 AddendL = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,607 Other, DAG.getConstant(0, dl, MVT::i32));608 AddendH = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,609 Other, DAG.getConstant(1, dl, MVT::i32));610 APInt HighMask = APInt::getHighBitsSet(64, 32);611 unsigned LHSSB = DAG.ComputeNumSignBits(Mul.getOperand(0));612 unsigned RHSSB = DAG.ComputeNumSignBits(Mul.getOperand(1));613 if (DAG.MaskedValueIsZero(Mul.getOperand(0), HighMask) &&614 DAG.MaskedValueIsZero(Mul.getOperand(1), HighMask)) {615 // The inputs are both zero-extended.616 SDValue Hi = DAG.getNode(XCoreISD::MACCU, dl,617 DAG.getVTList(MVT::i32, MVT::i32), AddendH,618 AddendL, LL, RL);619 SDValue Lo(Hi.getNode(), 1);620 return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi);621 }622 if (LHSSB > 32 && RHSSB > 32) {623 // The inputs are both sign-extended.624 SDValue Hi = DAG.getNode(XCoreISD::MACCS, dl,625 DAG.getVTList(MVT::i32, MVT::i32), AddendH,626 AddendL, LL, RL);627 SDValue Lo(Hi.getNode(), 1);628 return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi);629 }630 SDValue LH, RH;631 LH = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,632 Mul.getOperand(0), DAG.getConstant(1, dl, MVT::i32));633 RH = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,634 Mul.getOperand(1), DAG.getConstant(1, dl, MVT::i32));635 SDValue Hi = DAG.getNode(XCoreISD::MACCU, dl,636 DAG.getVTList(MVT::i32, MVT::i32), AddendH,637 AddendL, LL, RL);638 SDValue Lo(Hi.getNode(), 1);639 RH = DAG.getNode(ISD::MUL, dl, MVT::i32, LL, RH);640 LH = DAG.getNode(ISD::MUL, dl, MVT::i32, LH, RL);641 Hi = DAG.getNode(ISD::ADD, dl, MVT::i32, Hi, RH);642 Hi = DAG.getNode(ISD::ADD, dl, MVT::i32, Hi, LH);643 return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi);644}645 646SDValue XCoreTargetLowering::647ExpandADDSUB(SDNode *N, SelectionDAG &DAG) const648{649 assert(N->getValueType(0) == MVT::i64 &&650 (N->getOpcode() == ISD::ADD || N->getOpcode() == ISD::SUB) &&651 "Unknown operand to lower!");652 653 if (N->getOpcode() == ISD::ADD)654 if (SDValue Result = TryExpandADDWithMul(N, DAG))655 return Result;656 657 SDLoc dl(N);658 659 // Extract components660 SDValue LHSL = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,661 N->getOperand(0),662 DAG.getConstant(0, dl, MVT::i32));663 SDValue LHSH = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,664 N->getOperand(0),665 DAG.getConstant(1, dl, MVT::i32));666 SDValue RHSL = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,667 N->getOperand(1),668 DAG.getConstant(0, dl, MVT::i32));669 SDValue RHSH = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,670 N->getOperand(1),671 DAG.getConstant(1, dl, MVT::i32));672 673 // Expand674 unsigned Opcode = (N->getOpcode() == ISD::ADD) ? XCoreISD::LADD :675 XCoreISD::LSUB;676 SDValue Zero = DAG.getConstant(0, dl, MVT::i32);677 SDValue Lo = DAG.getNode(Opcode, dl, DAG.getVTList(MVT::i32, MVT::i32),678 LHSL, RHSL, Zero);679 SDValue Carry(Lo.getNode(), 1);680 681 SDValue Hi = DAG.getNode(Opcode, dl, DAG.getVTList(MVT::i32, MVT::i32),682 LHSH, RHSH, Carry);683 SDValue Ignored(Hi.getNode(), 1);684 // Merge the pieces685 return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi);686}687 688SDValue XCoreTargetLowering::689LowerVAARG(SDValue Op, SelectionDAG &DAG) const690{691 // Whist llvm does not support aggregate varargs we can ignore692 // the possibility of the ValueType being an implicit byVal vararg.693 SDNode *Node = Op.getNode();694 EVT VT = Node->getValueType(0); // not an aggregate695 SDValue InChain = Node->getOperand(0);696 SDValue VAListPtr = Node->getOperand(1);697 EVT PtrVT = VAListPtr.getValueType();698 const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();699 SDLoc dl(Node);700 SDValue VAList =701 DAG.getLoad(PtrVT, dl, InChain, VAListPtr, MachinePointerInfo(SV));702 // Increment the pointer, VAList, to the next vararg703 SDValue nextPtr = DAG.getNode(ISD::ADD, dl, PtrVT, VAList,704 DAG.getIntPtrConstant(VT.getSizeInBits() / 8,705 dl));706 // Store the incremented VAList to the legalized pointer707 InChain = DAG.getStore(VAList.getValue(1), dl, nextPtr, VAListPtr,708 MachinePointerInfo(SV));709 // Load the actual argument out of the pointer VAList710 return DAG.getLoad(VT, dl, InChain, VAList, MachinePointerInfo());711}712 713SDValue XCoreTargetLowering::714LowerVASTART(SDValue Op, SelectionDAG &DAG) const715{716 SDLoc dl(Op);717 // vastart stores the address of the VarArgsFrameIndex slot into the718 // memory location argument719 MachineFunction &MF = DAG.getMachineFunction();720 XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();721 SDValue Addr = DAG.getFrameIndex(XFI->getVarArgsFrameIndex(), MVT::i32);722 return DAG.getStore(Op.getOperand(0), dl, Addr, Op.getOperand(1),723 MachinePointerInfo());724}725 726SDValue XCoreTargetLowering::LowerFRAMEADDR(SDValue Op,727 SelectionDAG &DAG) const {728 // This nodes represent llvm.frameaddress on the DAG.729 // It takes one operand, the index of the frame address to return.730 // An index of zero corresponds to the current function's frame address.731 // An index of one to the parent's frame address, and so on.732 // Depths > 0 not supported yet!733 if (Op.getConstantOperandVal(0) > 0)734 return SDValue();735 736 MachineFunction &MF = DAG.getMachineFunction();737 const TargetRegisterInfo *RegInfo = Subtarget.getRegisterInfo();738 return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(Op),739 RegInfo->getFrameRegister(MF), MVT::i32);740}741 742SDValue XCoreTargetLowering::743LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const {744 // This nodes represent llvm.returnaddress on the DAG.745 // It takes one operand, the index of the return address to return.746 // An index of zero corresponds to the current function's return address.747 // An index of one to the parent's return address, and so on.748 // Depths > 0 not supported yet!749 if (Op.getConstantOperandVal(0) > 0)750 return SDValue();751 752 MachineFunction &MF = DAG.getMachineFunction();753 XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();754 int FI = XFI->createLRSpillSlot(MF);755 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);756 return DAG.getLoad(getPointerTy(DAG.getDataLayout()), SDLoc(Op),757 DAG.getEntryNode(), FIN,758 MachinePointerInfo::getFixedStack(MF, FI));759}760 761SDValue XCoreTargetLowering::762LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const {763 // This node represents offset from frame pointer to first on-stack argument.764 // This is needed for correct stack adjustment during unwind.765 // However, we don't know the offset until after the frame has be finalised.766 // This is done during the XCoreFTAOElim pass.767 return DAG.getNode(XCoreISD::FRAME_TO_ARGS_OFFSET, SDLoc(Op), MVT::i32);768}769 770SDValue XCoreTargetLowering::771LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const {772 // OUTCHAIN = EH_RETURN(INCHAIN, OFFSET, HANDLER)773 // This node represents 'eh_return' gcc dwarf builtin, which is used to774 // return from exception. The general meaning is: adjust stack by OFFSET and775 // pass execution to HANDLER.776 MachineFunction &MF = DAG.getMachineFunction();777 SDValue Chain = Op.getOperand(0);778 SDValue Offset = Op.getOperand(1);779 SDValue Handler = Op.getOperand(2);780 SDLoc dl(Op);781 782 // Absolute SP = (FP + FrameToArgs) + Offset783 const TargetRegisterInfo *RegInfo = Subtarget.getRegisterInfo();784 SDValue Stack = DAG.getCopyFromReg(DAG.getEntryNode(), dl,785 RegInfo->getFrameRegister(MF), MVT::i32);786 SDValue FrameToArgs = DAG.getNode(XCoreISD::FRAME_TO_ARGS_OFFSET, dl,787 MVT::i32);788 Stack = DAG.getNode(ISD::ADD, dl, MVT::i32, Stack, FrameToArgs);789 Stack = DAG.getNode(ISD::ADD, dl, MVT::i32, Stack, Offset);790 791 // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister792 // which leaves 2 caller saved registers, R2 & R3 for us to use.793 unsigned StackReg = XCore::R2;794 unsigned HandlerReg = XCore::R3;795 796 SDValue OutChains[] = {797 DAG.getCopyToReg(Chain, dl, StackReg, Stack),798 DAG.getCopyToReg(Chain, dl, HandlerReg, Handler)799 };800 801 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);802 803 return DAG.getNode(XCoreISD::EH_RETURN, dl, MVT::Other, Chain,804 DAG.getRegister(StackReg, MVT::i32),805 DAG.getRegister(HandlerReg, MVT::i32));806 807}808 809SDValue XCoreTargetLowering::810LowerADJUST_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const {811 return Op.getOperand(0);812}813 814SDValue XCoreTargetLowering::815LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const {816 SDValue Chain = Op.getOperand(0);817 SDValue Trmp = Op.getOperand(1); // trampoline818 SDValue FPtr = Op.getOperand(2); // nested function819 SDValue Nest = Op.getOperand(3); // 'nest' parameter value820 821 const Value *TrmpAddr = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();822 823 // .align 4824 // LDAPF_u10 r11, nest825 // LDW_2rus r11, r11[0]826 // STWSP_ru6 r11, sp[0]827 // LDAPF_u10 r11, fptr828 // LDW_2rus r11, r11[0]829 // BAU_1r r11830 // nest:831 // .word nest832 // fptr:833 // .word fptr834 SDValue OutChains[5];835 836 SDValue Addr = Trmp;837 838 SDLoc dl(Op);839 OutChains[0] =840 DAG.getStore(Chain, dl, DAG.getConstant(0x0a3cd805, dl, MVT::i32), Addr,841 MachinePointerInfo(TrmpAddr));842 843 Addr = DAG.getNode(ISD::ADD, dl, MVT::i32, Trmp,844 DAG.getConstant(4, dl, MVT::i32));845 OutChains[1] =846 DAG.getStore(Chain, dl, DAG.getConstant(0xd80456c0, dl, MVT::i32), Addr,847 MachinePointerInfo(TrmpAddr, 4));848 849 Addr = DAG.getNode(ISD::ADD, dl, MVT::i32, Trmp,850 DAG.getConstant(8, dl, MVT::i32));851 OutChains[2] =852 DAG.getStore(Chain, dl, DAG.getConstant(0x27fb0a3c, dl, MVT::i32), Addr,853 MachinePointerInfo(TrmpAddr, 8));854 855 Addr = DAG.getNode(ISD::ADD, dl, MVT::i32, Trmp,856 DAG.getConstant(12, dl, MVT::i32));857 OutChains[3] =858 DAG.getStore(Chain, dl, Nest, Addr, MachinePointerInfo(TrmpAddr, 12));859 860 Addr = DAG.getNode(ISD::ADD, dl, MVT::i32, Trmp,861 DAG.getConstant(16, dl, MVT::i32));862 OutChains[4] =863 DAG.getStore(Chain, dl, FPtr, Addr, MachinePointerInfo(TrmpAddr, 16));864 865 return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);866}867 868SDValue XCoreTargetLowering::869LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const {870 SDLoc DL(Op);871 unsigned IntNo = Op.getConstantOperandVal(0);872 switch (IntNo) {873 case Intrinsic::xcore_crc8:874 EVT VT = Op.getValueType();875 SDValue Data =876 DAG.getNode(XCoreISD::CRC8, DL, DAG.getVTList(VT, VT),877 Op.getOperand(1), Op.getOperand(2) , Op.getOperand(3));878 SDValue Crc(Data.getNode(), 1);879 SDValue Results[] = { Crc, Data };880 return DAG.getMergeValues(Results, DL);881 }882 return SDValue();883}884 885SDValue XCoreTargetLowering::886LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) const {887 SDLoc DL(Op);888 return DAG.getNode(ISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0));889}890 891//===----------------------------------------------------------------------===//892// Calling Convention Implementation893//===----------------------------------------------------------------------===//894 895#include "XCoreGenCallingConv.inc"896 897//===----------------------------------------------------------------------===//898// Call Calling Convention Implementation899//===----------------------------------------------------------------------===//900 901/// XCore call implementation902SDValue903XCoreTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,904 SmallVectorImpl<SDValue> &InVals) const {905 SelectionDAG &DAG = CLI.DAG;906 SDLoc &dl = CLI.DL;907 SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;908 SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;909 SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;910 SDValue Chain = CLI.Chain;911 SDValue Callee = CLI.Callee;912 bool &isTailCall = CLI.IsTailCall;913 CallingConv::ID CallConv = CLI.CallConv;914 bool isVarArg = CLI.IsVarArg;915 916 // XCore target does not yet support tail call optimization.917 isTailCall = false;918 919 // For now, only CallingConv::C implemented920 switch (CallConv)921 {922 default:923 report_fatal_error("Unsupported calling convention");924 case CallingConv::Fast:925 case CallingConv::C:926 return LowerCCCCallTo(Chain, Callee, CallConv, isVarArg, isTailCall,927 Outs, OutVals, Ins, dl, DAG, InVals);928 }929}930 931/// LowerCallResult - Lower the result values of a call into the932/// appropriate copies out of appropriate physical registers / memory locations.933static SDValue LowerCallResult(SDValue Chain, SDValue InGlue,934 const SmallVectorImpl<CCValAssign> &RVLocs,935 const SDLoc &dl, SelectionDAG &DAG,936 SmallVectorImpl<SDValue> &InVals) {937 SmallVector<std::pair<int, unsigned>, 4> ResultMemLocs;938 // Copy results out of physical registers.939 for (const CCValAssign &VA : RVLocs) {940 if (VA.isRegLoc()) {941 Chain = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), VA.getValVT(),942 InGlue).getValue(1);943 InGlue = Chain.getValue(2);944 InVals.push_back(Chain.getValue(0));945 } else {946 assert(VA.isMemLoc());947 ResultMemLocs.push_back(std::make_pair(VA.getLocMemOffset(),948 InVals.size()));949 // Reserve space for this result.950 InVals.push_back(SDValue());951 }952 }953 954 // Copy results out of memory.955 SmallVector<SDValue, 4> MemOpChains;956 for (unsigned i = 0, e = ResultMemLocs.size(); i != e; ++i) {957 int offset = ResultMemLocs[i].first;958 unsigned index = ResultMemLocs[i].second;959 SDVTList VTs = DAG.getVTList(MVT::i32, MVT::Other);960 SDValue Ops[] = { Chain, DAG.getConstant(offset / 4, dl, MVT::i32) };961 SDValue load = DAG.getNode(XCoreISD::LDWSP, dl, VTs, Ops);962 InVals[index] = load;963 MemOpChains.push_back(load.getValue(1));964 }965 966 // Transform all loads nodes into one single node because967 // all load nodes are independent of each other.968 if (!MemOpChains.empty())969 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);970 971 return Chain;972}973 974/// LowerCCCCallTo - functions arguments are copied from virtual975/// regs to (physical regs)/(stack frame), CALLSEQ_START and976/// CALLSEQ_END are emitted.977/// TODO: isTailCall, sret.978SDValue XCoreTargetLowering::LowerCCCCallTo(979 SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool isVarArg,980 bool isTailCall, const SmallVectorImpl<ISD::OutputArg> &Outs,981 const SmallVectorImpl<SDValue> &OutVals,982 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,983 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {984 985 // Analyze operands of the call, assigning locations to each operand.986 SmallVector<CCValAssign, 16> ArgLocs;987 CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,988 *DAG.getContext());989 990 // The ABI dictates there should be one stack slot available to the callee991 // on function entry (for saving lr).992 CCInfo.AllocateStack(4, Align(4));993 994 CCInfo.AnalyzeCallOperands(Outs, CC_XCore);995 996 SmallVector<CCValAssign, 16> RVLocs;997 // Analyze return values to determine the number of bytes of stack required.998 CCState RetCCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,999 *DAG.getContext());1000 RetCCInfo.AllocateStack(CCInfo.getStackSize(), Align(4));1001 RetCCInfo.AnalyzeCallResult(Ins, RetCC_XCore);1002 1003 // Get a count of how many bytes are to be pushed on the stack.1004 unsigned NumBytes = RetCCInfo.getStackSize();1005 1006 Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl);1007 1008 SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass;1009 SmallVector<SDValue, 12> MemOpChains;1010 1011 // Walk the register/memloc assignments, inserting copies/loads.1012 for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {1013 CCValAssign &VA = ArgLocs[i];1014 SDValue Arg = OutVals[i];1015 1016 // Promote the value if needed.1017 switch (VA.getLocInfo()) {1018 default: llvm_unreachable("Unknown loc info!");1019 case CCValAssign::Full: break;1020 case CCValAssign::SExt:1021 Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);1022 break;1023 case CCValAssign::ZExt:1024 Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);1025 break;1026 case CCValAssign::AExt:1027 Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg);1028 break;1029 }1030 1031 // Arguments that can be passed on register must be kept at1032 // RegsToPass vector1033 if (VA.isRegLoc()) {1034 RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));1035 } else {1036 assert(VA.isMemLoc());1037 1038 int Offset = VA.getLocMemOffset();1039 1040 MemOpChains.push_back(DAG.getNode(XCoreISD::STWSP, dl, MVT::Other,1041 Chain, Arg,1042 DAG.getConstant(Offset/4, dl,1043 MVT::i32)));1044 }1045 }1046 1047 // Transform all store nodes into one single node because1048 // all store nodes are independent of each other.1049 if (!MemOpChains.empty())1050 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);1051 1052 // Build a sequence of copy-to-reg nodes chained together with token1053 // chain and flag operands which copy the outgoing args into registers.1054 // The InGlue in necessary since all emitted instructions must be1055 // stuck together.1056 SDValue InGlue;1057 for (const auto &[Reg, N] : RegsToPass) {1058 Chain = DAG.getCopyToReg(Chain, dl, Reg, N, InGlue);1059 InGlue = Chain.getValue(1);1060 }1061 1062 // If the callee is a GlobalAddress node (quite common, every direct call is)1063 // turn it into a TargetGlobalAddress node so that legalize doesn't hack it.1064 // Likewise ExternalSymbol -> TargetExternalSymbol.1065 if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))1066 Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32);1067 else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))1068 Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);1069 1070 // XCoreBranchLink = #chain, #target_address, #opt_in_flags...1071 // = Chain, Callee, Reg#1, Reg#2, ...1072 //1073 // Returns a chain & a flag for retval copy to use.1074 SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);1075 SmallVector<SDValue, 8> Ops;1076 Ops.push_back(Chain);1077 Ops.push_back(Callee);1078 1079 // Add argument registers to the end of the list so that they are1080 // known live into the call.1081 for (const auto &[Reg, N] : RegsToPass)1082 Ops.push_back(DAG.getRegister(Reg, N.getValueType()));1083 1084 if (InGlue.getNode())1085 Ops.push_back(InGlue);1086 1087 Chain = DAG.getNode(XCoreISD::BL, dl, NodeTys, Ops);1088 InGlue = Chain.getValue(1);1089 1090 // Create the CALLSEQ_END node.1091 Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, InGlue, dl);1092 InGlue = Chain.getValue(1);1093 1094 // Handle result values, copying them out of physregs into vregs that we1095 // return.1096 return LowerCallResult(Chain, InGlue, RVLocs, dl, DAG, InVals);1097}1098 1099//===----------------------------------------------------------------------===//1100// Formal Arguments Calling Convention Implementation1101//===----------------------------------------------------------------------===//1102 1103namespace {1104 struct ArgDataPair { SDValue SDV; ISD::ArgFlagsTy Flags; };1105}1106 1107/// XCore formal arguments implementation1108SDValue XCoreTargetLowering::LowerFormalArguments(1109 SDValue Chain, CallingConv::ID CallConv, bool isVarArg,1110 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,1111 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {1112 switch (CallConv)1113 {1114 default:1115 report_fatal_error("Unsupported calling convention");1116 case CallingConv::C:1117 case CallingConv::Fast:1118 return LowerCCCArguments(Chain, CallConv, isVarArg,1119 Ins, dl, DAG, InVals);1120 }1121}1122 1123/// LowerCCCArguments - transform physical registers into1124/// virtual registers and generate load operations for1125/// arguments places on the stack.1126/// TODO: sret1127SDValue XCoreTargetLowering::LowerCCCArguments(1128 SDValue Chain, CallingConv::ID CallConv, bool isVarArg,1129 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,1130 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {1131 MachineFunction &MF = DAG.getMachineFunction();1132 MachineFrameInfo &MFI = MF.getFrameInfo();1133 MachineRegisterInfo &RegInfo = MF.getRegInfo();1134 XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();1135 1136 // Assign locations to all of the incoming arguments.1137 SmallVector<CCValAssign, 16> ArgLocs;1138 CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,1139 *DAG.getContext());1140 1141 CCInfo.AnalyzeFormalArguments(Ins, CC_XCore);1142 1143 unsigned StackSlotSize = XCoreFrameLowering::stackSlotSize();1144 1145 unsigned LRSaveSize = StackSlotSize;1146 1147 if (!isVarArg)1148 XFI->setReturnStackOffset(CCInfo.getStackSize() + LRSaveSize);1149 1150 // All getCopyFromReg ops must precede any getMemcpys to prevent the1151 // scheduler clobbering a register before it has been copied.1152 // The stages are:1153 // 1. CopyFromReg (and load) arg & vararg registers.1154 // 2. Chain CopyFromReg nodes into a TokenFactor.1155 // 3. Memcpy 'byVal' args & push final InVals.1156 // 4. Chain mem ops nodes into a TokenFactor.1157 SmallVector<SDValue, 4> CFRegNode;1158 SmallVector<ArgDataPair, 4> ArgData;1159 SmallVector<SDValue, 4> MemOps;1160 1161 // 1a. CopyFromReg (and load) arg registers.1162 for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {1163 1164 CCValAssign &VA = ArgLocs[i];1165 SDValue ArgIn;1166 1167 if (VA.isRegLoc()) {1168 // Arguments passed in registers1169 EVT RegVT = VA.getLocVT();1170 switch (RegVT.getSimpleVT().SimpleTy) {1171 default:1172 {1173#ifndef NDEBUG1174 errs() << "LowerFormalArguments Unhandled argument type: "1175 << RegVT << "\n";1176#endif1177 llvm_unreachable(nullptr);1178 }1179 case MVT::i32:1180 Register VReg = RegInfo.createVirtualRegister(&XCore::GRRegsRegClass);1181 RegInfo.addLiveIn(VA.getLocReg(), VReg);1182 ArgIn = DAG.getCopyFromReg(Chain, dl, VReg, RegVT);1183 CFRegNode.push_back(ArgIn.getValue(ArgIn->getNumValues() - 1));1184 }1185 } else {1186 // Only arguments passed on the stack should make it here. 1187 assert(VA.isMemLoc());1188 // Load the argument to a virtual register1189 unsigned ObjSize = VA.getLocVT().getSizeInBits()/8;1190 if (ObjSize > StackSlotSize) {1191 errs() << "LowerFormalArguments Unhandled argument type: "1192 << VA.getLocVT() << "\n";1193 }1194 // Create the frame index object for this incoming parameter...1195 int FI = MFI.CreateFixedObject(ObjSize,1196 LRSaveSize + VA.getLocMemOffset(),1197 true);1198 1199 // Create the SelectionDAG nodes corresponding to a load1200 //from this parameter1201 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);1202 ArgIn = DAG.getLoad(VA.getLocVT(), dl, Chain, FIN,1203 MachinePointerInfo::getFixedStack(MF, FI));1204 }1205 const ArgDataPair ADP = { ArgIn, Ins[i].Flags };1206 ArgData.push_back(ADP);1207 }1208 1209 // 1b. CopyFromReg vararg registers.1210 if (isVarArg) {1211 // Argument registers1212 static const MCPhysReg ArgRegs[] = {1213 XCore::R0, XCore::R1, XCore::R2, XCore::R31214 };1215 XCoreFunctionInfo *XFI = MF.getInfo<XCoreFunctionInfo>();1216 unsigned FirstVAReg = CCInfo.getFirstUnallocated(ArgRegs);1217 if (FirstVAReg < std::size(ArgRegs)) {1218 int offset = 0;1219 // Save remaining registers, storing higher register numbers at a higher1220 // address1221 for (int i = std::size(ArgRegs) - 1; i >= (int)FirstVAReg; --i) {1222 // Create a stack slot1223 int FI = MFI.CreateFixedObject(4, offset, true);1224 if (i == (int)FirstVAReg) {1225 XFI->setVarArgsFrameIndex(FI);1226 }1227 offset -= StackSlotSize;1228 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);1229 // Move argument from phys reg -> virt reg1230 Register VReg = RegInfo.createVirtualRegister(&XCore::GRRegsRegClass);1231 RegInfo.addLiveIn(ArgRegs[i], VReg);1232 SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32);1233 CFRegNode.push_back(Val.getValue(Val->getNumValues() - 1));1234 // Move argument from virt reg -> stack1235 SDValue Store =1236 DAG.getStore(Val.getValue(1), dl, Val, FIN, MachinePointerInfo());1237 MemOps.push_back(Store);1238 }1239 } else {1240 // This will point to the next argument passed via stack.1241 XFI->setVarArgsFrameIndex(1242 MFI.CreateFixedObject(4, LRSaveSize + CCInfo.getStackSize(), true));1243 }1244 }1245 1246 // 2. chain CopyFromReg nodes into a TokenFactor.1247 if (!CFRegNode.empty())1248 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, CFRegNode);1249 1250 // 3. Memcpy 'byVal' args & push final InVals.1251 // Aggregates passed "byVal" need to be copied by the callee.1252 // The callee will use a pointer to this copy, rather than the original1253 // pointer.1254 for (const ArgDataPair &ArgDI : ArgData) {1255 if (ArgDI.Flags.isByVal() && ArgDI.Flags.getByValSize()) {1256 unsigned Size = ArgDI.Flags.getByValSize();1257 Align Alignment =1258 std::max(Align(StackSlotSize), ArgDI.Flags.getNonZeroByValAlign());1259 // Create a new object on the stack and copy the pointee into it.1260 int FI = MFI.CreateStackObject(Size, Alignment, false);1261 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);1262 InVals.push_back(FIN);1263 MemOps.push_back(DAG.getMemcpy(1264 Chain, dl, FIN, ArgDI.SDV, DAG.getConstant(Size, dl, MVT::i32),1265 Alignment, false, false, /*CI=*/nullptr, std::nullopt,1266 MachinePointerInfo(), MachinePointerInfo()));1267 } else {1268 InVals.push_back(ArgDI.SDV);1269 }1270 }1271 1272 // 4, chain mem ops nodes into a TokenFactor.1273 if (!MemOps.empty()) {1274 MemOps.push_back(Chain);1275 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps);1276 }1277 1278 return Chain;1279}1280 1281//===----------------------------------------------------------------------===//1282// Return Value Calling Convention Implementation1283//===----------------------------------------------------------------------===//1284 1285bool XCoreTargetLowering::1286CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF,1287 bool isVarArg,1288 const SmallVectorImpl<ISD::OutputArg> &Outs,1289 LLVMContext &Context, const Type *RetTy) const {1290 SmallVector<CCValAssign, 16> RVLocs;1291 CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context);1292 if (!CCInfo.CheckReturn(Outs, RetCC_XCore))1293 return false;1294 if (CCInfo.getStackSize() != 0 && isVarArg)1295 return false;1296 return true;1297}1298 1299SDValue1300XCoreTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,1301 bool isVarArg,1302 const SmallVectorImpl<ISD::OutputArg> &Outs,1303 const SmallVectorImpl<SDValue> &OutVals,1304 const SDLoc &dl, SelectionDAG &DAG) const {1305 1306 XCoreFunctionInfo *XFI =1307 DAG.getMachineFunction().getInfo<XCoreFunctionInfo>();1308 MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();1309 1310 // CCValAssign - represent the assignment of1311 // the return value to a location1312 SmallVector<CCValAssign, 16> RVLocs;1313 1314 // CCState - Info about the registers and stack slot.1315 CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,1316 *DAG.getContext());1317 1318 // Analyze return values.1319 if (!isVarArg)1320 CCInfo.AllocateStack(XFI->getReturnStackOffset(), Align(4));1321 1322 CCInfo.AnalyzeReturn(Outs, RetCC_XCore);1323 1324 SDValue Glue;1325 SmallVector<SDValue, 4> RetOps(1, Chain);1326 1327 // Return on XCore is always a "retsp 0"1328 RetOps.push_back(DAG.getConstant(0, dl, MVT::i32));1329 1330 SmallVector<SDValue, 4> MemOpChains;1331 // Handle return values that must be copied to memory.1332 for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {1333 CCValAssign &VA = RVLocs[i];1334 if (VA.isRegLoc())1335 continue;1336 assert(VA.isMemLoc());1337 if (isVarArg) {1338 report_fatal_error("Can't return value from vararg function in memory");1339 }1340 1341 int Offset = VA.getLocMemOffset();1342 unsigned ObjSize = VA.getLocVT().getSizeInBits() / 8;1343 // Create the frame index object for the memory location.1344 int FI = MFI.CreateFixedObject(ObjSize, Offset, false);1345 1346 // Create a SelectionDAG node corresponding to a store1347 // to this memory location.1348 SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);1349 MemOpChains.push_back(DAG.getStore(1350 Chain, dl, OutVals[i], FIN,1351 MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI)));1352 }1353 1354 // Transform all store nodes into one single node because1355 // all stores are independent of each other.1356 if (!MemOpChains.empty())1357 Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);1358 1359 // Now handle return values copied to registers.1360 for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {1361 CCValAssign &VA = RVLocs[i];1362 if (!VA.isRegLoc())1363 continue;1364 // Copy the result values into the output registers.1365 Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Glue);1366 1367 // guarantee that all emitted copies are1368 // stuck together, avoiding something bad1369 Glue = Chain.getValue(1);1370 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));1371 }1372 1373 RetOps[0] = Chain; // Update chain.1374 1375 // Add the glue if we have it.1376 if (Glue.getNode())1377 RetOps.push_back(Glue);1378 1379 return DAG.getNode(XCoreISD::RETSP, dl, MVT::Other, RetOps);1380}1381 1382//===----------------------------------------------------------------------===//1383// Other Lowering Code1384//===----------------------------------------------------------------------===//1385 1386MachineBasicBlock *1387XCoreTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,1388 MachineBasicBlock *BB) const {1389 const TargetInstrInfo &TII = *Subtarget.getInstrInfo();1390 DebugLoc dl = MI.getDebugLoc();1391 assert((MI.getOpcode() == XCore::SELECT_CC) &&1392 "Unexpected instr type to insert");1393 1394 // To "insert" a SELECT_CC instruction, we actually have to insert the diamond1395 // control-flow pattern. The incoming instruction knows the destination vreg1396 // to set, the condition code register to branch on, the true/false values to1397 // select between, and a branch opcode to use.1398 const BasicBlock *LLVM_BB = BB->getBasicBlock();1399 MachineFunction::iterator It = ++BB->getIterator();1400 1401 // thisMBB:1402 // ...1403 // TrueVal = ...1404 // cmpTY ccX, r1, r21405 // bCC copy1MBB1406 // fallthrough --> copy0MBB1407 MachineBasicBlock *thisMBB = BB;1408 MachineFunction *F = BB->getParent();1409 MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);1410 MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);1411 F->insert(It, copy0MBB);1412 F->insert(It, sinkMBB);1413 1414 // Transfer the remainder of BB and its successor edges to sinkMBB.1415 sinkMBB->splice(sinkMBB->begin(), BB,1416 std::next(MachineBasicBlock::iterator(MI)), BB->end());1417 sinkMBB->transferSuccessorsAndUpdatePHIs(BB);1418 1419 // Next, add the true and fallthrough blocks as its successors.1420 BB->addSuccessor(copy0MBB);1421 BB->addSuccessor(sinkMBB);1422 1423 BuildMI(BB, dl, TII.get(XCore::BRFT_lru6))1424 .addReg(MI.getOperand(1).getReg())1425 .addMBB(sinkMBB);1426 1427 // copy0MBB:1428 // %FalseValue = ...1429 // # fallthrough to sinkMBB1430 BB = copy0MBB;1431 1432 // Update machine-CFG edges1433 BB->addSuccessor(sinkMBB);1434 1435 // sinkMBB:1436 // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]1437 // ...1438 BB = sinkMBB;1439 BuildMI(*BB, BB->begin(), dl, TII.get(XCore::PHI), MI.getOperand(0).getReg())1440 .addReg(MI.getOperand(3).getReg())1441 .addMBB(copy0MBB)1442 .addReg(MI.getOperand(2).getReg())1443 .addMBB(thisMBB);1444 1445 MI.eraseFromParent(); // The pseudo instruction is gone now.1446 return BB;1447}1448 1449//===----------------------------------------------------------------------===//1450// Target Optimization Hooks1451//===----------------------------------------------------------------------===//1452 1453SDValue XCoreTargetLowering::PerformDAGCombine(SDNode *N,1454 DAGCombinerInfo &DCI) const {1455 SelectionDAG &DAG = DCI.DAG;1456 SDLoc dl(N);1457 switch (N->getOpcode()) {1458 default: break;1459 case ISD::INTRINSIC_VOID:1460 switch (N->getConstantOperandVal(1)) {1461 case Intrinsic::xcore_outt:1462 case Intrinsic::xcore_outct:1463 case Intrinsic::xcore_chkct: {1464 SDValue OutVal = N->getOperand(3);1465 // These instructions ignore the high bits.1466 if (OutVal.hasOneUse()) {1467 unsigned BitWidth = OutVal.getValueSizeInBits();1468 APInt DemandedMask = APInt::getLowBitsSet(BitWidth, 8);1469 KnownBits Known;1470 TargetLowering::TargetLoweringOpt TLO(DAG, !DCI.isBeforeLegalize(),1471 !DCI.isBeforeLegalizeOps());1472 const TargetLowering &TLI = DAG.getTargetLoweringInfo();1473 if (TLI.ShrinkDemandedConstant(OutVal, DemandedMask, TLO) ||1474 TLI.SimplifyDemandedBits(OutVal, DemandedMask, Known, TLO))1475 DCI.CommitTargetLoweringOpt(TLO);1476 }1477 break;1478 }1479 case Intrinsic::xcore_setpt: {1480 SDValue Time = N->getOperand(3);1481 // This instruction ignores the high bits.1482 if (Time.hasOneUse()) {1483 unsigned BitWidth = Time.getValueSizeInBits();1484 APInt DemandedMask = APInt::getLowBitsSet(BitWidth, 16);1485 KnownBits Known;1486 TargetLowering::TargetLoweringOpt TLO(DAG, !DCI.isBeforeLegalize(),1487 !DCI.isBeforeLegalizeOps());1488 const TargetLowering &TLI = DAG.getTargetLoweringInfo();1489 if (TLI.ShrinkDemandedConstant(Time, DemandedMask, TLO) ||1490 TLI.SimplifyDemandedBits(Time, DemandedMask, Known, TLO))1491 DCI.CommitTargetLoweringOpt(TLO);1492 }1493 break;1494 }1495 }1496 break;1497 case XCoreISD::LADD: {1498 SDValue N0 = N->getOperand(0);1499 SDValue N1 = N->getOperand(1);1500 SDValue N2 = N->getOperand(2);1501 ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);1502 ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);1503 EVT VT = N0.getValueType();1504 1505 // canonicalize constant to RHS1506 if (N0C && !N1C)1507 return DAG.getNode(XCoreISD::LADD, dl, DAG.getVTList(VT, VT), N1, N0, N2);1508 1509 // fold (ladd 0, 0, x) -> 0, x & 11510 if (N0C && N0C->isZero() && N1C && N1C->isZero()) {1511 SDValue Carry = DAG.getConstant(0, dl, VT);1512 SDValue Result = DAG.getNode(ISD::AND, dl, VT, N2,1513 DAG.getConstant(1, dl, VT));1514 SDValue Ops[] = { Result, Carry };1515 return DAG.getMergeValues(Ops, dl);1516 }1517 1518 // fold (ladd x, 0, y) -> 0, add x, y iff carry is unused and y has only the1519 // low bit set1520 if (N1C && N1C->isZero() && N->hasNUsesOfValue(0, 1)) {1521 APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(),1522 VT.getSizeInBits() - 1);1523 KnownBits Known = DAG.computeKnownBits(N2);1524 if ((Known.Zero & Mask) == Mask) {1525 SDValue Carry = DAG.getConstant(0, dl, VT);1526 SDValue Result = DAG.getNode(ISD::ADD, dl, VT, N0, N2);1527 SDValue Ops[] = { Result, Carry };1528 return DAG.getMergeValues(Ops, dl);1529 }1530 }1531 }1532 break;1533 case XCoreISD::LSUB: {1534 SDValue N0 = N->getOperand(0);1535 SDValue N1 = N->getOperand(1);1536 SDValue N2 = N->getOperand(2);1537 ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);1538 ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);1539 EVT VT = N0.getValueType();1540 1541 // fold (lsub 0, 0, x) -> x, -x iff x has only the low bit set1542 if (N0C && N0C->isZero() && N1C && N1C->isZero()) {1543 APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(),1544 VT.getSizeInBits() - 1);1545 KnownBits Known = DAG.computeKnownBits(N2);1546 if ((Known.Zero & Mask) == Mask) {1547 SDValue Borrow = N2;1548 SDValue Result = DAG.getNode(ISD::SUB, dl, VT,1549 DAG.getConstant(0, dl, VT), N2);1550 SDValue Ops[] = { Result, Borrow };1551 return DAG.getMergeValues(Ops, dl);1552 }1553 }1554 1555 // fold (lsub x, 0, y) -> 0, sub x, y iff borrow is unused and y has only the1556 // low bit set1557 if (N1C && N1C->isZero() && N->hasNUsesOfValue(0, 1)) {1558 APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(),1559 VT.getSizeInBits() - 1);1560 KnownBits Known = DAG.computeKnownBits(N2);1561 if ((Known.Zero & Mask) == Mask) {1562 SDValue Borrow = DAG.getConstant(0, dl, VT);1563 SDValue Result = DAG.getNode(ISD::SUB, dl, VT, N0, N2);1564 SDValue Ops[] = { Result, Borrow };1565 return DAG.getMergeValues(Ops, dl);1566 }1567 }1568 }1569 break;1570 case XCoreISD::LMUL: {1571 SDValue N0 = N->getOperand(0);1572 SDValue N1 = N->getOperand(1);1573 SDValue N2 = N->getOperand(2);1574 SDValue N3 = N->getOperand(3);1575 ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0);1576 ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);1577 EVT VT = N0.getValueType();1578 // Canonicalize multiplicative constant to RHS. If both multiplicative1579 // operands are constant canonicalize smallest to RHS.1580 if ((N0C && !N1C) ||1581 (N0C && N1C && N0C->getZExtValue() < N1C->getZExtValue()))1582 return DAG.getNode(XCoreISD::LMUL, dl, DAG.getVTList(VT, VT),1583 N1, N0, N2, N3);1584 1585 // lmul(x, 0, a, b)1586 if (N1C && N1C->isZero()) {1587 // If the high result is unused fold to add(a, b)1588 if (N->hasNUsesOfValue(0, 0)) {1589 SDValue Lo = DAG.getNode(ISD::ADD, dl, VT, N2, N3);1590 SDValue Ops[] = { Lo, Lo };1591 return DAG.getMergeValues(Ops, dl);1592 }1593 // Otherwise fold to ladd(a, b, 0)1594 SDValue Result =1595 DAG.getNode(XCoreISD::LADD, dl, DAG.getVTList(VT, VT), N2, N3, N1);1596 SDValue Carry(Result.getNode(), 1);1597 SDValue Ops[] = { Carry, Result };1598 return DAG.getMergeValues(Ops, dl);1599 }1600 }1601 break;1602 case ISD::ADD: {1603 // Fold 32 bit expressions such as add(add(mul(x,y),a),b) ->1604 // lmul(x, y, a, b). The high result of lmul will be ignored.1605 // This is only profitable if the intermediate results are unused1606 // elsewhere.1607 SDValue Mul0, Mul1, Addend0, Addend1;1608 if (N->getValueType(0) == MVT::i32 &&1609 isADDADDMUL(SDValue(N, 0), Mul0, Mul1, Addend0, Addend1, true)) {1610 SDValue Ignored = DAG.getNode(XCoreISD::LMUL, dl,1611 DAG.getVTList(MVT::i32, MVT::i32), Mul0,1612 Mul1, Addend0, Addend1);1613 SDValue Result(Ignored.getNode(), 1);1614 return Result;1615 }1616 APInt HighMask = APInt::getHighBitsSet(64, 32);1617 // Fold 64 bit expression such as add(add(mul(x,y),a),b) ->1618 // lmul(x, y, a, b) if all operands are zero-extended. We do this1619 // before type legalization as it is messy to match the operands after1620 // that.1621 if (N->getValueType(0) == MVT::i64 &&1622 isADDADDMUL(SDValue(N, 0), Mul0, Mul1, Addend0, Addend1, false) &&1623 DAG.MaskedValueIsZero(Mul0, HighMask) &&1624 DAG.MaskedValueIsZero(Mul1, HighMask) &&1625 DAG.MaskedValueIsZero(Addend0, HighMask) &&1626 DAG.MaskedValueIsZero(Addend1, HighMask)) {1627 SDValue Mul0L = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,1628 Mul0, DAG.getConstant(0, dl, MVT::i32));1629 SDValue Mul1L = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,1630 Mul1, DAG.getConstant(0, dl, MVT::i32));1631 SDValue Addend0L = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,1632 Addend0, DAG.getConstant(0, dl, MVT::i32));1633 SDValue Addend1L = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,1634 Addend1, DAG.getConstant(0, dl, MVT::i32));1635 SDValue Hi = DAG.getNode(XCoreISD::LMUL, dl,1636 DAG.getVTList(MVT::i32, MVT::i32), Mul0L, Mul1L,1637 Addend0L, Addend1L);1638 SDValue Lo(Hi.getNode(), 1);1639 return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi);1640 }1641 }1642 break;1643 case ISD::STORE: {1644 // Replace unaligned store of unaligned load with memmove.1645 StoreSDNode *ST = cast<StoreSDNode>(N);1646 if (!DCI.isBeforeLegalize() ||1647 allowsMemoryAccessForAlignment(*DAG.getContext(), DAG.getDataLayout(),1648 ST->getMemoryVT(),1649 *ST->getMemOperand()) ||1650 ST->isVolatile() || ST->isIndexed()) {1651 break;1652 }1653 SDValue Chain = ST->getChain();1654 1655 unsigned StoreBits = ST->getMemoryVT().getStoreSizeInBits();1656 assert((StoreBits % 8) == 0 &&1657 "Store size in bits must be a multiple of 8");1658 Align Alignment = ST->getAlign();1659 1660 if (LoadSDNode *LD = dyn_cast<LoadSDNode>(ST->getValue())) {1661 if (LD->hasNUsesOfValue(1, 0) && ST->getMemoryVT() == LD->getMemoryVT() &&1662 LD->getAlign() == Alignment &&1663 !LD->isVolatile() && !LD->isIndexed() &&1664 Chain.reachesChainWithoutSideEffects(SDValue(LD, 1))) {1665 bool isTail = isInTailCallPosition(DAG, ST, Chain);1666 return DAG.getMemmove(Chain, dl, ST->getBasePtr(), LD->getBasePtr(),1667 DAG.getConstant(StoreBits / 8, dl, MVT::i32),1668 Alignment, false, nullptr, isTail,1669 ST->getPointerInfo(), LD->getPointerInfo());1670 }1671 }1672 break;1673 }1674 }1675 return SDValue();1676}1677 1678void XCoreTargetLowering::computeKnownBitsForTargetNode(const SDValue Op,1679 KnownBits &Known,1680 const APInt &DemandedElts,1681 const SelectionDAG &DAG,1682 unsigned Depth) const {1683 Known.resetAll();1684 switch (Op.getOpcode()) {1685 default: break;1686 case XCoreISD::LADD:1687 case XCoreISD::LSUB:1688 if (Op.getResNo() == 1) {1689 // Top bits of carry / borrow are clear.1690 Known.Zero = APInt::getHighBitsSet(Known.getBitWidth(),1691 Known.getBitWidth() - 1);1692 }1693 break;1694 case ISD::INTRINSIC_W_CHAIN:1695 {1696 unsigned IntNo = Op.getConstantOperandVal(1);1697 switch (IntNo) {1698 case Intrinsic::xcore_getts:1699 // High bits are known to be zero.1700 Known.Zero =1701 APInt::getHighBitsSet(Known.getBitWidth(), Known.getBitWidth() - 16);1702 break;1703 case Intrinsic::xcore_int:1704 case Intrinsic::xcore_inct:1705 // High bits are known to be zero.1706 Known.Zero =1707 APInt::getHighBitsSet(Known.getBitWidth(), Known.getBitWidth() - 8);1708 break;1709 case Intrinsic::xcore_testct:1710 // Result is either 0 or 1.1711 Known.Zero =1712 APInt::getHighBitsSet(Known.getBitWidth(), Known.getBitWidth() - 1);1713 break;1714 case Intrinsic::xcore_testwct:1715 // Result is in the range 0 - 4.1716 Known.Zero =1717 APInt::getHighBitsSet(Known.getBitWidth(), Known.getBitWidth() - 3);1718 break;1719 }1720 }1721 break;1722 }1723}1724 1725//===----------------------------------------------------------------------===//1726// Addressing mode description hooks1727//===----------------------------------------------------------------------===//1728 1729static inline bool isImmUs(int64_t val)1730{1731 return (val >= 0 && val <= 11);1732}1733 1734static inline bool isImmUs2(int64_t val)1735{1736 return (val%2 == 0 && isImmUs(val/2));1737}1738 1739static inline bool isImmUs4(int64_t val)1740{1741 return (val%4 == 0 && isImmUs(val/4));1742}1743 1744/// isLegalAddressingMode - Return true if the addressing mode represented1745/// by AM is legal for this target, for a load/store of the specified type.1746bool XCoreTargetLowering::isLegalAddressingMode(const DataLayout &DL,1747 const AddrMode &AM, Type *Ty,1748 unsigned AS,1749 Instruction *I) const {1750 if (Ty->getTypeID() == Type::VoidTyID)1751 return AM.Scale == 0 && isImmUs(AM.BaseOffs) && isImmUs4(AM.BaseOffs);1752 1753 unsigned Size = DL.getTypeAllocSize(Ty);1754 if (AM.BaseGV) {1755 return Size >= 4 && !AM.HasBaseReg && AM.Scale == 0 &&1756 AM.BaseOffs%4 == 0;1757 }1758 1759 switch (Size) {1760 case 1:1761 // reg + imm1762 if (AM.Scale == 0) {1763 return isImmUs(AM.BaseOffs);1764 }1765 // reg + reg1766 return AM.Scale == 1 && AM.BaseOffs == 0;1767 case 2:1768 case 3:1769 // reg + imm1770 if (AM.Scale == 0) {1771 return isImmUs2(AM.BaseOffs);1772 }1773 // reg + reg<<11774 return AM.Scale == 2 && AM.BaseOffs == 0;1775 default:1776 // reg + imm1777 if (AM.Scale == 0) {1778 return isImmUs4(AM.BaseOffs);1779 }1780 // reg + reg<<21781 return AM.Scale == 4 && AM.BaseOffs == 0;1782 }1783}1784 1785//===----------------------------------------------------------------------===//1786// XCore Inline Assembly Support1787//===----------------------------------------------------------------------===//1788 1789std::pair<unsigned, const TargetRegisterClass *>1790XCoreTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,1791 StringRef Constraint,1792 MVT VT) const {1793 if (Constraint.size() == 1) {1794 switch (Constraint[0]) {1795 default : break;1796 case 'r':1797 return std::make_pair(0U, &XCore::GRRegsRegClass);1798 }1799 }1800 // Use the default implementation in TargetLowering to convert the register1801 // constraint into a member of a register class.1802 return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);1803}1804