10b57cec5SDimitry Andric //===-- LanaiISelLowering.cpp - Lanai DAG Lowering Implementation ---------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the LanaiTargetLowering class. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "LanaiISelLowering.h" 140b57cec5SDimitry Andric #include "Lanai.h" 150b57cec5SDimitry Andric #include "LanaiCondCode.h" 160b57cec5SDimitry Andric #include "LanaiMachineFunctionInfo.h" 170b57cec5SDimitry Andric #include "LanaiSubtarget.h" 180b57cec5SDimitry Andric #include "LanaiTargetObjectFile.h" 190b57cec5SDimitry Andric #include "MCTargetDesc/LanaiBaseInfo.h" 200b57cec5SDimitry Andric #include "llvm/ADT/APInt.h" 210b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 220b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 230b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 240b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h" 250b57cec5SDimitry Andric #include "llvm/CodeGen/CallingConvLower.h" 260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 30*0fca6ea1SDimitry Andric #include "llvm/CodeGen/RuntimeLibcallUtil.h" 310b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h" 320b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h" 330b57cec5SDimitry Andric #include "llvm/CodeGen/TargetCallingConv.h" 340b57cec5SDimitry Andric #include "llvm/CodeGen/ValueTypes.h" 35*0fca6ea1SDimitry Andric #include "llvm/CodeGenTypes/MachineValueType.h" 360b57cec5SDimitry Andric #include "llvm/IR/CallingConv.h" 370b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 380b57cec5SDimitry Andric #include "llvm/IR/Function.h" 390b57cec5SDimitry Andric #include "llvm/IR/GlobalValue.h" 400b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 410b57cec5SDimitry Andric #include "llvm/Support/CodeGen.h" 420b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 430b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 440b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 450b57cec5SDimitry Andric #include "llvm/Support/KnownBits.h" 460b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 470b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 480b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 490b57cec5SDimitry Andric #include <cassert> 500b57cec5SDimitry Andric #include <cmath> 510b57cec5SDimitry Andric #include <cstdint> 520b57cec5SDimitry Andric #include <cstdlib> 530b57cec5SDimitry Andric #include <utility> 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric #define DEBUG_TYPE "lanai-lower" 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric using namespace llvm; 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric // Limit on number of instructions the lowered multiplication may have before a 600b57cec5SDimitry Andric // call to the library function should be generated instead. The threshold is 610b57cec5SDimitry Andric // currently set to 14 as this was the smallest threshold that resulted in all 620b57cec5SDimitry Andric // constant multiplications being lowered. A threshold of 5 covered all cases 630b57cec5SDimitry Andric // except for one multiplication which required 14. mulsi3 requires 16 640b57cec5SDimitry Andric // instructions (including the prologue and epilogue but excluding instructions 650b57cec5SDimitry Andric // at call site). Until we can inline mulsi3, generating at most 14 instructions 660b57cec5SDimitry Andric // will be faster than invoking mulsi3. 670b57cec5SDimitry Andric static cl::opt<int> LanaiLowerConstantMulThreshold( 680b57cec5SDimitry Andric "lanai-constant-mul-threshold", cl::Hidden, 690b57cec5SDimitry Andric cl::desc("Maximum number of instruction to generate when lowering constant " 700b57cec5SDimitry Andric "multiplication instead of calling library function [default=14]"), 710b57cec5SDimitry Andric cl::init(14)); 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric LanaiTargetLowering::LanaiTargetLowering(const TargetMachine &TM, 740b57cec5SDimitry Andric const LanaiSubtarget &STI) 750b57cec5SDimitry Andric : TargetLowering(TM) { 760b57cec5SDimitry Andric // Set up the register classes. 770b57cec5SDimitry Andric addRegisterClass(MVT::i32, &Lanai::GPRRegClass); 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric // Compute derived properties from the register classes 800b57cec5SDimitry Andric TRI = STI.getRegisterInfo(); 810b57cec5SDimitry Andric computeRegisterProperties(TRI); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric setStackPointerRegisterToSaveRestore(Lanai::SP); 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric setOperationAction(ISD::BR_CC, MVT::i32, Custom); 860b57cec5SDimitry Andric setOperationAction(ISD::BR_JT, MVT::Other, Expand); 870b57cec5SDimitry Andric setOperationAction(ISD::BRCOND, MVT::Other, Expand); 880b57cec5SDimitry Andric setOperationAction(ISD::SETCC, MVT::i32, Custom); 890b57cec5SDimitry Andric setOperationAction(ISD::SELECT, MVT::i32, Expand); 900b57cec5SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); 930b57cec5SDimitry Andric setOperationAction(ISD::BlockAddress, MVT::i32, Custom); 940b57cec5SDimitry Andric setOperationAction(ISD::JumpTable, MVT::i32, Custom); 950b57cec5SDimitry Andric setOperationAction(ISD::ConstantPool, MVT::i32, Custom); 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom); 980b57cec5SDimitry Andric setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); 990b57cec5SDimitry Andric setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric setOperationAction(ISD::VASTART, MVT::Other, Custom); 1020b57cec5SDimitry Andric setOperationAction(ISD::VAARG, MVT::Other, Expand); 1030b57cec5SDimitry Andric setOperationAction(ISD::VACOPY, MVT::Other, Expand); 1040b57cec5SDimitry Andric setOperationAction(ISD::VAEND, MVT::Other, Expand); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric setOperationAction(ISD::SDIV, MVT::i32, Expand); 1070b57cec5SDimitry Andric setOperationAction(ISD::UDIV, MVT::i32, Expand); 1080b57cec5SDimitry Andric setOperationAction(ISD::SDIVREM, MVT::i32, Expand); 1090b57cec5SDimitry Andric setOperationAction(ISD::UDIVREM, MVT::i32, Expand); 1100b57cec5SDimitry Andric setOperationAction(ISD::SREM, MVT::i32, Expand); 1110b57cec5SDimitry Andric setOperationAction(ISD::UREM, MVT::i32, Expand); 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric setOperationAction(ISD::MUL, MVT::i32, Custom); 1140b57cec5SDimitry Andric setOperationAction(ISD::MULHU, MVT::i32, Expand); 1150b57cec5SDimitry Andric setOperationAction(ISD::MULHS, MVT::i32, Expand); 1160b57cec5SDimitry Andric setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); 1170b57cec5SDimitry Andric setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric setOperationAction(ISD::ROTR, MVT::i32, Expand); 1200b57cec5SDimitry Andric setOperationAction(ISD::ROTL, MVT::i32, Expand); 1210b57cec5SDimitry Andric setOperationAction(ISD::SHL_PARTS, MVT::i32, Custom); 1220b57cec5SDimitry Andric setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom); 1230b57cec5SDimitry Andric setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric setOperationAction(ISD::BSWAP, MVT::i32, Expand); 1260b57cec5SDimitry Andric setOperationAction(ISD::CTPOP, MVT::i32, Legal); 1270b57cec5SDimitry Andric setOperationAction(ISD::CTLZ, MVT::i32, Legal); 1280b57cec5SDimitry Andric setOperationAction(ISD::CTTZ, MVT::i32, Legal); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); 1310b57cec5SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); 1320b57cec5SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric // Extended load operations for i1 types must be promoted 1350b57cec5SDimitry Andric for (MVT VT : MVT::integer_valuetypes()) { 1360b57cec5SDimitry Andric setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); 1370b57cec5SDimitry Andric setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote); 1380b57cec5SDimitry Andric setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric 14181ad6265SDimitry Andric setTargetDAGCombine({ISD::ADD, ISD::SUB, ISD::AND, ISD::OR, ISD::XOR}); 1420b57cec5SDimitry Andric 1438bcb0991SDimitry Andric // Function alignments 1448bcb0991SDimitry Andric setMinFunctionAlignment(Align(4)); 1458bcb0991SDimitry Andric setPrefFunctionAlignment(Align(4)); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric setJumpIsExpensive(true); 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric // TODO: Setting the minimum jump table entries needed before a 1500b57cec5SDimitry Andric // switch is transformed to a jump table to 100 to avoid creating jump tables 1510b57cec5SDimitry Andric // as this was causing bad performance compared to a large group of if 1520b57cec5SDimitry Andric // statements. Re-evaluate this on new benchmarks. 1530b57cec5SDimitry Andric setMinimumJumpTableEntries(100); 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric // Use fast calling convention for library functions. 1560b57cec5SDimitry Andric for (int I = 0; I < RTLIB::UNKNOWN_LIBCALL; ++I) { 1570b57cec5SDimitry Andric setLibcallCallingConv(static_cast<RTLIB::Libcall>(I), CallingConv::Fast); 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric MaxStoresPerMemset = 16; // For @llvm.memset -> sequence of stores 1610b57cec5SDimitry Andric MaxStoresPerMemsetOptSize = 8; 1620b57cec5SDimitry Andric MaxStoresPerMemcpy = 16; // For @llvm.memcpy -> sequence of stores 1630b57cec5SDimitry Andric MaxStoresPerMemcpyOptSize = 8; 1640b57cec5SDimitry Andric MaxStoresPerMemmove = 16; // For @llvm.memmove -> sequence of stores 1650b57cec5SDimitry Andric MaxStoresPerMemmoveOptSize = 8; 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric // Booleans always contain 0 or 1. 1680b57cec5SDimitry Andric setBooleanContents(ZeroOrOneBooleanContent); 1691db9f3b2SDimitry Andric 1701db9f3b2SDimitry Andric setMaxAtomicSizeInBitsSupported(0); 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerOperation(SDValue Op, 1740b57cec5SDimitry Andric SelectionDAG &DAG) const { 1750b57cec5SDimitry Andric switch (Op.getOpcode()) { 1760b57cec5SDimitry Andric case ISD::MUL: 1770b57cec5SDimitry Andric return LowerMUL(Op, DAG); 1780b57cec5SDimitry Andric case ISD::BR_CC: 1790b57cec5SDimitry Andric return LowerBR_CC(Op, DAG); 1800b57cec5SDimitry Andric case ISD::ConstantPool: 1810b57cec5SDimitry Andric return LowerConstantPool(Op, DAG); 1820b57cec5SDimitry Andric case ISD::GlobalAddress: 1830b57cec5SDimitry Andric return LowerGlobalAddress(Op, DAG); 1840b57cec5SDimitry Andric case ISD::BlockAddress: 1850b57cec5SDimitry Andric return LowerBlockAddress(Op, DAG); 1860b57cec5SDimitry Andric case ISD::JumpTable: 1870b57cec5SDimitry Andric return LowerJumpTable(Op, DAG); 1880b57cec5SDimitry Andric case ISD::SELECT_CC: 1890b57cec5SDimitry Andric return LowerSELECT_CC(Op, DAG); 1900b57cec5SDimitry Andric case ISD::SETCC: 1910b57cec5SDimitry Andric return LowerSETCC(Op, DAG); 1920b57cec5SDimitry Andric case ISD::SHL_PARTS: 1930b57cec5SDimitry Andric return LowerSHL_PARTS(Op, DAG); 1940b57cec5SDimitry Andric case ISD::SRL_PARTS: 1950b57cec5SDimitry Andric return LowerSRL_PARTS(Op, DAG); 1960b57cec5SDimitry Andric case ISD::VASTART: 1970b57cec5SDimitry Andric return LowerVASTART(Op, DAG); 1980b57cec5SDimitry Andric case ISD::DYNAMIC_STACKALLOC: 1990b57cec5SDimitry Andric return LowerDYNAMIC_STACKALLOC(Op, DAG); 2000b57cec5SDimitry Andric case ISD::RETURNADDR: 2010b57cec5SDimitry Andric return LowerRETURNADDR(Op, DAG); 2020b57cec5SDimitry Andric case ISD::FRAMEADDR: 2030b57cec5SDimitry Andric return LowerFRAMEADDR(Op, DAG); 2040b57cec5SDimitry Andric default: 2050b57cec5SDimitry Andric llvm_unreachable("unimplemented operand"); 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2100b57cec5SDimitry Andric // Lanai Inline Assembly Support 2110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2120b57cec5SDimitry Andric 2138bcb0991SDimitry Andric Register LanaiTargetLowering::getRegisterByName( 214480093f4SDimitry Andric const char *RegName, LLT /*VT*/, 2158bcb0991SDimitry Andric const MachineFunction & /*MF*/) const { 2160b57cec5SDimitry Andric // Only unallocatable registers should be matched here. 2178bcb0991SDimitry Andric Register Reg = StringSwitch<unsigned>(RegName) 2180b57cec5SDimitry Andric .Case("pc", Lanai::PC) 2190b57cec5SDimitry Andric .Case("sp", Lanai::SP) 2200b57cec5SDimitry Andric .Case("fp", Lanai::FP) 2210b57cec5SDimitry Andric .Case("rr1", Lanai::RR1) 2220b57cec5SDimitry Andric .Case("r10", Lanai::R10) 2230b57cec5SDimitry Andric .Case("rr2", Lanai::RR2) 2240b57cec5SDimitry Andric .Case("r11", Lanai::R11) 2250b57cec5SDimitry Andric .Case("rca", Lanai::RCA) 2260b57cec5SDimitry Andric .Default(0); 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric if (Reg) 2290b57cec5SDimitry Andric return Reg; 2300b57cec5SDimitry Andric report_fatal_error("Invalid register name global variable"); 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric std::pair<unsigned, const TargetRegisterClass *> 2340b57cec5SDimitry Andric LanaiTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, 2350b57cec5SDimitry Andric StringRef Constraint, 2360b57cec5SDimitry Andric MVT VT) const { 2370b57cec5SDimitry Andric if (Constraint.size() == 1) 2380b57cec5SDimitry Andric // GCC Constraint Letters 2390b57cec5SDimitry Andric switch (Constraint[0]) { 2400b57cec5SDimitry Andric case 'r': // GENERAL_REGS 2410b57cec5SDimitry Andric return std::make_pair(0U, &Lanai::GPRRegClass); 2420b57cec5SDimitry Andric default: 2430b57cec5SDimitry Andric break; 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric // Examine constraint type and operand type and determine a weight value. 2500b57cec5SDimitry Andric // This object must already have been set up with the operand type 2510b57cec5SDimitry Andric // and the current alternative constraint selected. 2520b57cec5SDimitry Andric TargetLowering::ConstraintWeight 2530b57cec5SDimitry Andric LanaiTargetLowering::getSingleConstraintMatchWeight( 2540b57cec5SDimitry Andric AsmOperandInfo &Info, const char *Constraint) const { 2550b57cec5SDimitry Andric ConstraintWeight Weight = CW_Invalid; 2560b57cec5SDimitry Andric Value *CallOperandVal = Info.CallOperandVal; 2570b57cec5SDimitry Andric // If we don't have a value, we can't do a match, 2580b57cec5SDimitry Andric // but allow it at the lowest weight. 2590b57cec5SDimitry Andric if (CallOperandVal == nullptr) 2600b57cec5SDimitry Andric return CW_Default; 2610b57cec5SDimitry Andric // Look at the constraint type. 2620b57cec5SDimitry Andric switch (*Constraint) { 2630b57cec5SDimitry Andric case 'I': // signed 16 bit immediate 2640b57cec5SDimitry Andric case 'J': // integer zero 2650b57cec5SDimitry Andric case 'K': // unsigned 16 bit immediate 2660b57cec5SDimitry Andric case 'L': // immediate in the range 0 to 31 2670b57cec5SDimitry Andric case 'M': // signed 32 bit immediate where lower 16 bits are 0 2680b57cec5SDimitry Andric case 'N': // signed 26 bit immediate 2690b57cec5SDimitry Andric case 'O': // integer zero 2700b57cec5SDimitry Andric if (isa<ConstantInt>(CallOperandVal)) 2710b57cec5SDimitry Andric Weight = CW_Constant; 2720b57cec5SDimitry Andric break; 2730b57cec5SDimitry Andric default: 2740b57cec5SDimitry Andric Weight = TargetLowering::getSingleConstraintMatchWeight(Info, Constraint); 2750b57cec5SDimitry Andric break; 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric return Weight; 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // LowerAsmOperandForConstraint - Lower the specified operand into the Ops 2810b57cec5SDimitry Andric // vector. If it is invalid, don't add anything to Ops. 2820b57cec5SDimitry Andric void LanaiTargetLowering::LowerAsmOperandForConstraint( 2835f757f3fSDimitry Andric SDValue Op, StringRef Constraint, std::vector<SDValue> &Ops, 2840b57cec5SDimitry Andric SelectionDAG &DAG) const { 28504eeddc0SDimitry Andric SDValue Result; 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric // Only support length 1 constraints for now. 2885f757f3fSDimitry Andric if (Constraint.size() > 1) 2890b57cec5SDimitry Andric return; 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric char ConstraintLetter = Constraint[0]; 2920b57cec5SDimitry Andric switch (ConstraintLetter) { 2930b57cec5SDimitry Andric case 'I': // Signed 16 bit constant 2940b57cec5SDimitry Andric // If this fails, the parent routine will give an error 2950b57cec5SDimitry Andric if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { 2960b57cec5SDimitry Andric if (isInt<16>(C->getSExtValue())) { 2970b57cec5SDimitry Andric Result = DAG.getTargetConstant(C->getSExtValue(), SDLoc(C), 2980b57cec5SDimitry Andric Op.getValueType()); 2990b57cec5SDimitry Andric break; 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric return; 3030b57cec5SDimitry Andric case 'J': // integer zero 3040b57cec5SDimitry Andric case 'O': 3050b57cec5SDimitry Andric if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { 3060b57cec5SDimitry Andric if (C->getZExtValue() == 0) { 3070b57cec5SDimitry Andric Result = DAG.getTargetConstant(0, SDLoc(C), Op.getValueType()); 3080b57cec5SDimitry Andric break; 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric return; 3120b57cec5SDimitry Andric case 'K': // unsigned 16 bit immediate 3130b57cec5SDimitry Andric if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { 3140b57cec5SDimitry Andric if (isUInt<16>(C->getZExtValue())) { 3150b57cec5SDimitry Andric Result = DAG.getTargetConstant(C->getSExtValue(), SDLoc(C), 3160b57cec5SDimitry Andric Op.getValueType()); 3170b57cec5SDimitry Andric break; 3180b57cec5SDimitry Andric } 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric return; 3210b57cec5SDimitry Andric case 'L': // immediate in the range 0 to 31 3220b57cec5SDimitry Andric if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { 3230b57cec5SDimitry Andric if (C->getZExtValue() <= 31) { 3240b57cec5SDimitry Andric Result = DAG.getTargetConstant(C->getZExtValue(), SDLoc(C), 3250b57cec5SDimitry Andric Op.getValueType()); 3260b57cec5SDimitry Andric break; 3270b57cec5SDimitry Andric } 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric return; 3300b57cec5SDimitry Andric case 'M': // signed 32 bit immediate where lower 16 bits are 0 3310b57cec5SDimitry Andric if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { 3320b57cec5SDimitry Andric int64_t Val = C->getSExtValue(); 3330b57cec5SDimitry Andric if ((isInt<32>(Val)) && ((Val & 0xffff) == 0)) { 3340b57cec5SDimitry Andric Result = DAG.getTargetConstant(Val, SDLoc(C), Op.getValueType()); 3350b57cec5SDimitry Andric break; 3360b57cec5SDimitry Andric } 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric return; 3390b57cec5SDimitry Andric case 'N': // signed 26 bit immediate 3400b57cec5SDimitry Andric if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { 3410b57cec5SDimitry Andric int64_t Val = C->getSExtValue(); 3420b57cec5SDimitry Andric if ((Val >= -33554432) && (Val <= 33554431)) { 3430b57cec5SDimitry Andric Result = DAG.getTargetConstant(Val, SDLoc(C), Op.getValueType()); 3440b57cec5SDimitry Andric break; 3450b57cec5SDimitry Andric } 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric return; 3480b57cec5SDimitry Andric default: 3490b57cec5SDimitry Andric break; // This will fall through to the generic implementation 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric if (Result.getNode()) { 3530b57cec5SDimitry Andric Ops.push_back(Result); 3540b57cec5SDimitry Andric return; 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 3610b57cec5SDimitry Andric // Calling Convention Implementation 3620b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric #include "LanaiGenCallingConv.inc" 3650b57cec5SDimitry Andric 3660b57cec5SDimitry Andric static unsigned NumFixedArgs; 3670b57cec5SDimitry Andric static bool CC_Lanai32_VarArg(unsigned ValNo, MVT ValVT, MVT LocVT, 3680b57cec5SDimitry Andric CCValAssign::LocInfo LocInfo, 3690b57cec5SDimitry Andric ISD::ArgFlagsTy ArgFlags, CCState &State) { 3700b57cec5SDimitry Andric // Handle fixed arguments with default CC. 3710b57cec5SDimitry Andric // Note: Both the default and fast CC handle VarArg the same and hence the 3720b57cec5SDimitry Andric // calling convention of the function is not considered here. 3730b57cec5SDimitry Andric if (ValNo < NumFixedArgs) { 3740b57cec5SDimitry Andric return CC_Lanai32(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State); 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric // Promote i8/i16 args to i32 3780b57cec5SDimitry Andric if (LocVT == MVT::i8 || LocVT == MVT::i16) { 3790b57cec5SDimitry Andric LocVT = MVT::i32; 3800b57cec5SDimitry Andric if (ArgFlags.isSExt()) 3810b57cec5SDimitry Andric LocInfo = CCValAssign::SExt; 3820b57cec5SDimitry Andric else if (ArgFlags.isZExt()) 3830b57cec5SDimitry Andric LocInfo = CCValAssign::ZExt; 3840b57cec5SDimitry Andric else 3850b57cec5SDimitry Andric LocInfo = CCValAssign::AExt; 3860b57cec5SDimitry Andric } 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric // VarArgs get passed on stack 3895ffd83dbSDimitry Andric unsigned Offset = State.AllocateStack(4, Align(4)); 3900b57cec5SDimitry Andric State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); 3910b57cec5SDimitry Andric return false; 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerFormalArguments( 3950b57cec5SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 3960b57cec5SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 3970b57cec5SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 3980b57cec5SDimitry Andric switch (CallConv) { 3990b57cec5SDimitry Andric case CallingConv::C: 4000b57cec5SDimitry Andric case CallingConv::Fast: 4010b57cec5SDimitry Andric return LowerCCCArguments(Chain, CallConv, IsVarArg, Ins, DL, DAG, InVals); 4020b57cec5SDimitry Andric default: 4030b57cec5SDimitry Andric report_fatal_error("Unsupported calling convention"); 4040b57cec5SDimitry Andric } 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, 4080b57cec5SDimitry Andric SmallVectorImpl<SDValue> &InVals) const { 4090b57cec5SDimitry Andric SelectionDAG &DAG = CLI.DAG; 4100b57cec5SDimitry Andric SDLoc &DL = CLI.DL; 4110b57cec5SDimitry Andric SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; 4120b57cec5SDimitry Andric SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; 4130b57cec5SDimitry Andric SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; 4140b57cec5SDimitry Andric SDValue Chain = CLI.Chain; 4150b57cec5SDimitry Andric SDValue Callee = CLI.Callee; 4160b57cec5SDimitry Andric bool &IsTailCall = CLI.IsTailCall; 4170b57cec5SDimitry Andric CallingConv::ID CallConv = CLI.CallConv; 4180b57cec5SDimitry Andric bool IsVarArg = CLI.IsVarArg; 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric // Lanai target does not yet support tail call optimization. 4210b57cec5SDimitry Andric IsTailCall = false; 4220b57cec5SDimitry Andric 4230b57cec5SDimitry Andric switch (CallConv) { 4240b57cec5SDimitry Andric case CallingConv::Fast: 4250b57cec5SDimitry Andric case CallingConv::C: 4260b57cec5SDimitry Andric return LowerCCCCallTo(Chain, Callee, CallConv, IsVarArg, IsTailCall, Outs, 4270b57cec5SDimitry Andric OutVals, Ins, DL, DAG, InVals); 4280b57cec5SDimitry Andric default: 4290b57cec5SDimitry Andric report_fatal_error("Unsupported calling convention"); 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric } 4320b57cec5SDimitry Andric 4330b57cec5SDimitry Andric // LowerCCCArguments - transform physical registers into virtual registers and 4340b57cec5SDimitry Andric // generate load operations for arguments places on the stack. 4350b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerCCCArguments( 4360b57cec5SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 4370b57cec5SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 4380b57cec5SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 4390b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 4400b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 4410b57cec5SDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 4420b57cec5SDimitry Andric LanaiMachineFunctionInfo *LanaiMFI = MF.getInfo<LanaiMachineFunctionInfo>(); 4430b57cec5SDimitry Andric 4440b57cec5SDimitry Andric // Assign locations to all of the incoming arguments. 4450b57cec5SDimitry Andric SmallVector<CCValAssign, 16> ArgLocs; 4460b57cec5SDimitry Andric CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, 4470b57cec5SDimitry Andric *DAG.getContext()); 4480b57cec5SDimitry Andric if (CallConv == CallingConv::Fast) { 4490b57cec5SDimitry Andric CCInfo.AnalyzeFormalArguments(Ins, CC_Lanai32_Fast); 4500b57cec5SDimitry Andric } else { 4510b57cec5SDimitry Andric CCInfo.AnalyzeFormalArguments(Ins, CC_Lanai32); 4520b57cec5SDimitry Andric } 4530b57cec5SDimitry Andric 454*0fca6ea1SDimitry Andric for (const CCValAssign &VA : ArgLocs) { 4550b57cec5SDimitry Andric if (VA.isRegLoc()) { 4560b57cec5SDimitry Andric // Arguments passed in registers 4570b57cec5SDimitry Andric EVT RegVT = VA.getLocVT(); 4580b57cec5SDimitry Andric switch (RegVT.getSimpleVT().SimpleTy) { 4590b57cec5SDimitry Andric case MVT::i32: { 4608bcb0991SDimitry Andric Register VReg = RegInfo.createVirtualRegister(&Lanai::GPRRegClass); 4610b57cec5SDimitry Andric RegInfo.addLiveIn(VA.getLocReg(), VReg); 4620b57cec5SDimitry Andric SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, VReg, RegVT); 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric // If this is an 8/16-bit value, it is really passed promoted to 32 4650b57cec5SDimitry Andric // bits. Insert an assert[sz]ext to capture this, then truncate to the 4660b57cec5SDimitry Andric // right size. 4670b57cec5SDimitry Andric if (VA.getLocInfo() == CCValAssign::SExt) 4680b57cec5SDimitry Andric ArgValue = DAG.getNode(ISD::AssertSext, DL, RegVT, ArgValue, 4690b57cec5SDimitry Andric DAG.getValueType(VA.getValVT())); 4700b57cec5SDimitry Andric else if (VA.getLocInfo() == CCValAssign::ZExt) 4710b57cec5SDimitry Andric ArgValue = DAG.getNode(ISD::AssertZext, DL, RegVT, ArgValue, 4720b57cec5SDimitry Andric DAG.getValueType(VA.getValVT())); 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric if (VA.getLocInfo() != CCValAssign::Full) 4750b57cec5SDimitry Andric ArgValue = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), ArgValue); 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric InVals.push_back(ArgValue); 4780b57cec5SDimitry Andric break; 4790b57cec5SDimitry Andric } 4800b57cec5SDimitry Andric default: 4810b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "LowerFormalArguments Unhandled argument type: " 48206c3fb27SDimitry Andric << RegVT << "\n"); 4830b57cec5SDimitry Andric llvm_unreachable("unhandled argument type"); 4840b57cec5SDimitry Andric } 4850b57cec5SDimitry Andric } else { 486349cc55cSDimitry Andric // Only arguments passed on the stack should make it here. 4870b57cec5SDimitry Andric assert(VA.isMemLoc()); 4880b57cec5SDimitry Andric // Load the argument to a virtual register 4890b57cec5SDimitry Andric unsigned ObjSize = VA.getLocVT().getSizeInBits() / 8; 4900b57cec5SDimitry Andric // Check that the argument fits in stack slot 4910b57cec5SDimitry Andric if (ObjSize > 4) { 4920b57cec5SDimitry Andric errs() << "LowerFormalArguments Unhandled argument type: " 49306c3fb27SDimitry Andric << VA.getLocVT() << "\n"; 4940b57cec5SDimitry Andric } 4950b57cec5SDimitry Andric // Create the frame index object for this incoming parameter... 4960b57cec5SDimitry Andric int FI = MFI.CreateFixedObject(ObjSize, VA.getLocMemOffset(), true); 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric // Create the SelectionDAG nodes corresponding to a load 4990b57cec5SDimitry Andric // from this parameter 5000b57cec5SDimitry Andric SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); 5010b57cec5SDimitry Andric InVals.push_back(DAG.getLoad( 5020b57cec5SDimitry Andric VA.getLocVT(), DL, Chain, FIN, 5030b57cec5SDimitry Andric MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI))); 5040b57cec5SDimitry Andric } 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric // The Lanai ABI for returning structs by value requires that we copy 5080b57cec5SDimitry Andric // the sret argument into rv for the return. Save the argument into 5090b57cec5SDimitry Andric // a virtual register so that we can access it from the return points. 5100b57cec5SDimitry Andric if (MF.getFunction().hasStructRetAttr()) { 51104eeddc0SDimitry Andric Register Reg = LanaiMFI->getSRetReturnReg(); 5120b57cec5SDimitry Andric if (!Reg) { 5130b57cec5SDimitry Andric Reg = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i32)); 5140b57cec5SDimitry Andric LanaiMFI->setSRetReturnReg(Reg); 5150b57cec5SDimitry Andric } 5160b57cec5SDimitry Andric SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), DL, Reg, InVals[0]); 5170b57cec5SDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Copy, Chain); 5180b57cec5SDimitry Andric } 5190b57cec5SDimitry Andric 5200b57cec5SDimitry Andric if (IsVarArg) { 5210b57cec5SDimitry Andric // Record the frame index of the first variable argument 5220b57cec5SDimitry Andric // which is a value necessary to VASTART. 52306c3fb27SDimitry Andric int FI = MFI.CreateFixedObject(4, CCInfo.getStackSize(), true); 5240b57cec5SDimitry Andric LanaiMFI->setVarArgsFrameIndex(FI); 5250b57cec5SDimitry Andric } 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric return Chain; 5280b57cec5SDimitry Andric } 5290b57cec5SDimitry Andric 530349cc55cSDimitry Andric bool LanaiTargetLowering::CanLowerReturn( 531349cc55cSDimitry Andric CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, 532349cc55cSDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { 533349cc55cSDimitry Andric SmallVector<CCValAssign, 16> RVLocs; 534349cc55cSDimitry Andric CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); 535349cc55cSDimitry Andric 536349cc55cSDimitry Andric return CCInfo.CheckReturn(Outs, RetCC_Lanai32); 537349cc55cSDimitry Andric } 538349cc55cSDimitry Andric 5390b57cec5SDimitry Andric SDValue 5400b57cec5SDimitry Andric LanaiTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, 5410b57cec5SDimitry Andric bool IsVarArg, 5420b57cec5SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, 5430b57cec5SDimitry Andric const SmallVectorImpl<SDValue> &OutVals, 5440b57cec5SDimitry Andric const SDLoc &DL, SelectionDAG &DAG) const { 5450b57cec5SDimitry Andric // CCValAssign - represent the assignment of the return value to a location 5460b57cec5SDimitry Andric SmallVector<CCValAssign, 16> RVLocs; 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric // CCState - Info about the registers and stack slot. 5490b57cec5SDimitry Andric CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, 5500b57cec5SDimitry Andric *DAG.getContext()); 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric // Analize return values. 5530b57cec5SDimitry Andric CCInfo.AnalyzeReturn(Outs, RetCC_Lanai32); 5540b57cec5SDimitry Andric 55506c3fb27SDimitry Andric SDValue Glue; 5560b57cec5SDimitry Andric SmallVector<SDValue, 4> RetOps(1, Chain); 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric // Copy the result values into the output registers. 5590b57cec5SDimitry Andric for (unsigned i = 0; i != RVLocs.size(); ++i) { 5600b57cec5SDimitry Andric CCValAssign &VA = RVLocs[i]; 5610b57cec5SDimitry Andric assert(VA.isRegLoc() && "Can only return in registers!"); 5620b57cec5SDimitry Andric 56306c3fb27SDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Glue); 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric // Guarantee that all emitted copies are stuck together with flags. 56606c3fb27SDimitry Andric Glue = Chain.getValue(1); 5670b57cec5SDimitry Andric RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); 5680b57cec5SDimitry Andric } 5690b57cec5SDimitry Andric 5700b57cec5SDimitry Andric // The Lanai ABI for returning structs by value requires that we copy 5710b57cec5SDimitry Andric // the sret argument into rv for the return. We saved the argument into 5720b57cec5SDimitry Andric // a virtual register in the entry block, so now we copy the value out 5730b57cec5SDimitry Andric // and into rv. 5740b57cec5SDimitry Andric if (DAG.getMachineFunction().getFunction().hasStructRetAttr()) { 5750b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 5760b57cec5SDimitry Andric LanaiMachineFunctionInfo *LanaiMFI = MF.getInfo<LanaiMachineFunctionInfo>(); 57704eeddc0SDimitry Andric Register Reg = LanaiMFI->getSRetReturnReg(); 5780b57cec5SDimitry Andric assert(Reg && 5790b57cec5SDimitry Andric "SRetReturnReg should have been set in LowerFormalArguments()."); 5800b57cec5SDimitry Andric SDValue Val = 5810b57cec5SDimitry Andric DAG.getCopyFromReg(Chain, DL, Reg, getPointerTy(DAG.getDataLayout())); 5820b57cec5SDimitry Andric 58306c3fb27SDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, Lanai::RV, Val, Glue); 58406c3fb27SDimitry Andric Glue = Chain.getValue(1); 5850b57cec5SDimitry Andric RetOps.push_back( 5860b57cec5SDimitry Andric DAG.getRegister(Lanai::RV, getPointerTy(DAG.getDataLayout()))); 5870b57cec5SDimitry Andric } 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric RetOps[0] = Chain; // Update chain 5900b57cec5SDimitry Andric 59106c3fb27SDimitry Andric unsigned Opc = LanaiISD::RET_GLUE; 59206c3fb27SDimitry Andric if (Glue.getNode()) 59306c3fb27SDimitry Andric RetOps.push_back(Glue); 5940b57cec5SDimitry Andric 5950b57cec5SDimitry Andric // Return Void 5960b57cec5SDimitry Andric return DAG.getNode(Opc, DL, MVT::Other, 5970b57cec5SDimitry Andric ArrayRef<SDValue>(&RetOps[0], RetOps.size())); 5980b57cec5SDimitry Andric } 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric // LowerCCCCallTo - functions arguments are copied from virtual regs to 6010b57cec5SDimitry Andric // (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. 6020b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerCCCCallTo( 6030b57cec5SDimitry Andric SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool IsVarArg, 6040b57cec5SDimitry Andric bool /*IsTailCall*/, const SmallVectorImpl<ISD::OutputArg> &Outs, 6050b57cec5SDimitry Andric const SmallVectorImpl<SDValue> &OutVals, 6060b57cec5SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 6070b57cec5SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 6080b57cec5SDimitry Andric // Analyze operands of the call, assigning locations to each operand. 6090b57cec5SDimitry Andric SmallVector<CCValAssign, 16> ArgLocs; 6100b57cec5SDimitry Andric CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, 6110b57cec5SDimitry Andric *DAG.getContext()); 6120b57cec5SDimitry Andric GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee); 6130b57cec5SDimitry Andric MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andric NumFixedArgs = 0; 6160b57cec5SDimitry Andric if (IsVarArg && G) { 6170b57cec5SDimitry Andric const Function *CalleeFn = dyn_cast<Function>(G->getGlobal()); 6180b57cec5SDimitry Andric if (CalleeFn) 6190b57cec5SDimitry Andric NumFixedArgs = CalleeFn->getFunctionType()->getNumParams(); 6200b57cec5SDimitry Andric } 6210b57cec5SDimitry Andric if (NumFixedArgs) 6220b57cec5SDimitry Andric CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32_VarArg); 6230b57cec5SDimitry Andric else { 6240b57cec5SDimitry Andric if (CallConv == CallingConv::Fast) 6250b57cec5SDimitry Andric CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32_Fast); 6260b57cec5SDimitry Andric else 6270b57cec5SDimitry Andric CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32); 6280b57cec5SDimitry Andric } 6290b57cec5SDimitry Andric 6300b57cec5SDimitry Andric // Get a count of how many bytes are to be pushed on the stack. 63106c3fb27SDimitry Andric unsigned NumBytes = CCInfo.getStackSize(); 6320b57cec5SDimitry Andric 6330b57cec5SDimitry Andric // Create local copies for byval args. 6340b57cec5SDimitry Andric SmallVector<SDValue, 8> ByValArgs; 6350b57cec5SDimitry Andric for (unsigned I = 0, E = Outs.size(); I != E; ++I) { 6360b57cec5SDimitry Andric ISD::ArgFlagsTy Flags = Outs[I].Flags; 6370b57cec5SDimitry Andric if (!Flags.isByVal()) 6380b57cec5SDimitry Andric continue; 6390b57cec5SDimitry Andric 6400b57cec5SDimitry Andric SDValue Arg = OutVals[I]; 6410b57cec5SDimitry Andric unsigned Size = Flags.getByValSize(); 6425ffd83dbSDimitry Andric Align Alignment = Flags.getNonZeroByValAlign(); 6430b57cec5SDimitry Andric 6445ffd83dbSDimitry Andric int FI = MFI.CreateStackObject(Size, Alignment, false); 6450b57cec5SDimitry Andric SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 6460b57cec5SDimitry Andric SDValue SizeNode = DAG.getConstant(Size, DL, MVT::i32); 6470b57cec5SDimitry Andric 6485ffd83dbSDimitry Andric Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, 6490b57cec5SDimitry Andric /*IsVolatile=*/false, 6500b57cec5SDimitry Andric /*AlwaysInline=*/false, 651*0fca6ea1SDimitry Andric /*CI=*/nullptr, std::nullopt, MachinePointerInfo(), 6520b57cec5SDimitry Andric MachinePointerInfo()); 6530b57cec5SDimitry Andric ByValArgs.push_back(FIPtr); 6540b57cec5SDimitry Andric } 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, DL); 6570b57cec5SDimitry Andric 6580b57cec5SDimitry Andric SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass; 6590b57cec5SDimitry Andric SmallVector<SDValue, 12> MemOpChains; 6600b57cec5SDimitry Andric SDValue StackPtr; 6610b57cec5SDimitry Andric 6620b57cec5SDimitry Andric // Walk the register/memloc assignments, inserting copies/loads. 6630b57cec5SDimitry Andric for (unsigned I = 0, J = 0, E = ArgLocs.size(); I != E; ++I) { 6640b57cec5SDimitry Andric CCValAssign &VA = ArgLocs[I]; 6650b57cec5SDimitry Andric SDValue Arg = OutVals[I]; 6660b57cec5SDimitry Andric ISD::ArgFlagsTy Flags = Outs[I].Flags; 6670b57cec5SDimitry Andric 6680b57cec5SDimitry Andric // Promote the value if needed. 6690b57cec5SDimitry Andric switch (VA.getLocInfo()) { 6700b57cec5SDimitry Andric case CCValAssign::Full: 6710b57cec5SDimitry Andric break; 6720b57cec5SDimitry Andric case CCValAssign::SExt: 6730b57cec5SDimitry Andric Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg); 6740b57cec5SDimitry Andric break; 6750b57cec5SDimitry Andric case CCValAssign::ZExt: 6760b57cec5SDimitry Andric Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg); 6770b57cec5SDimitry Andric break; 6780b57cec5SDimitry Andric case CCValAssign::AExt: 6790b57cec5SDimitry Andric Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg); 6800b57cec5SDimitry Andric break; 6810b57cec5SDimitry Andric default: 6820b57cec5SDimitry Andric llvm_unreachable("Unknown loc info!"); 6830b57cec5SDimitry Andric } 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric // Use local copy if it is a byval arg. 6860b57cec5SDimitry Andric if (Flags.isByVal()) 6870b57cec5SDimitry Andric Arg = ByValArgs[J++]; 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric // Arguments that can be passed on register must be kept at RegsToPass 6900b57cec5SDimitry Andric // vector 6910b57cec5SDimitry Andric if (VA.isRegLoc()) { 6920b57cec5SDimitry Andric RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); 6930b57cec5SDimitry Andric } else { 6940b57cec5SDimitry Andric assert(VA.isMemLoc()); 6950b57cec5SDimitry Andric 6960b57cec5SDimitry Andric if (StackPtr.getNode() == nullptr) 6970b57cec5SDimitry Andric StackPtr = DAG.getCopyFromReg(Chain, DL, Lanai::SP, 6980b57cec5SDimitry Andric getPointerTy(DAG.getDataLayout())); 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric SDValue PtrOff = 7010b57cec5SDimitry Andric DAG.getNode(ISD::ADD, DL, getPointerTy(DAG.getDataLayout()), StackPtr, 7020b57cec5SDimitry Andric DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric MemOpChains.push_back( 7050b57cec5SDimitry Andric DAG.getStore(Chain, DL, Arg, PtrOff, MachinePointerInfo())); 7060b57cec5SDimitry Andric } 7070b57cec5SDimitry Andric } 7080b57cec5SDimitry Andric 7090b57cec5SDimitry Andric // Transform all store nodes into one single node because all store nodes are 7100b57cec5SDimitry Andric // independent of each other. 7110b57cec5SDimitry Andric if (!MemOpChains.empty()) 7120b57cec5SDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, 7130b57cec5SDimitry Andric ArrayRef<SDValue>(&MemOpChains[0], MemOpChains.size())); 7140b57cec5SDimitry Andric 71506c3fb27SDimitry Andric SDValue InGlue; 7160b57cec5SDimitry Andric 7170b57cec5SDimitry Andric // Build a sequence of copy-to-reg nodes chained together with token chain and 71806c3fb27SDimitry Andric // flag operands which copy the outgoing args into registers. The InGlue in 7190b57cec5SDimitry Andric // necessary since all emitted instructions must be stuck together. 7200b57cec5SDimitry Andric for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { 7210b57cec5SDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, RegsToPass[I].first, 72206c3fb27SDimitry Andric RegsToPass[I].second, InGlue); 72306c3fb27SDimitry Andric InGlue = Chain.getValue(1); 7240b57cec5SDimitry Andric } 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric // If the callee is a GlobalAddress node (quite common, every direct call is) 7270b57cec5SDimitry Andric // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. 7280b57cec5SDimitry Andric // Likewise ExternalSymbol -> TargetExternalSymbol. 7290b57cec5SDimitry Andric uint8_t OpFlag = LanaiII::MO_NO_FLAG; 7300b57cec5SDimitry Andric if (G) { 7310b57cec5SDimitry Andric Callee = DAG.getTargetGlobalAddress( 7320b57cec5SDimitry Andric G->getGlobal(), DL, getPointerTy(DAG.getDataLayout()), 0, OpFlag); 7330b57cec5SDimitry Andric } else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) { 7340b57cec5SDimitry Andric Callee = DAG.getTargetExternalSymbol( 7350b57cec5SDimitry Andric E->getSymbol(), getPointerTy(DAG.getDataLayout()), OpFlag); 7360b57cec5SDimitry Andric } 7370b57cec5SDimitry Andric 7380b57cec5SDimitry Andric // Returns a chain & a flag for retval copy to use. 7390b57cec5SDimitry Andric SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); 7400b57cec5SDimitry Andric SmallVector<SDValue, 8> Ops; 7410b57cec5SDimitry Andric Ops.push_back(Chain); 7420b57cec5SDimitry Andric Ops.push_back(Callee); 7430b57cec5SDimitry Andric 7440b57cec5SDimitry Andric // Add a register mask operand representing the call-preserved registers. 7450b57cec5SDimitry Andric // TODO: Should return-twice functions be handled? 7460b57cec5SDimitry Andric const uint32_t *Mask = 7470b57cec5SDimitry Andric TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv); 7480b57cec5SDimitry Andric assert(Mask && "Missing call preserved mask for calling convention"); 7490b57cec5SDimitry Andric Ops.push_back(DAG.getRegisterMask(Mask)); 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric // Add argument registers to the end of the list so that they are 7520b57cec5SDimitry Andric // known live into the call. 7530b57cec5SDimitry Andric for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) 7540b57cec5SDimitry Andric Ops.push_back(DAG.getRegister(RegsToPass[I].first, 7550b57cec5SDimitry Andric RegsToPass[I].second.getValueType())); 7560b57cec5SDimitry Andric 75706c3fb27SDimitry Andric if (InGlue.getNode()) 75806c3fb27SDimitry Andric Ops.push_back(InGlue); 7590b57cec5SDimitry Andric 7600b57cec5SDimitry Andric Chain = DAG.getNode(LanaiISD::CALL, DL, NodeTys, 7610b57cec5SDimitry Andric ArrayRef<SDValue>(&Ops[0], Ops.size())); 76206c3fb27SDimitry Andric InGlue = Chain.getValue(1); 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric // Create the CALLSEQ_END node. 76506c3fb27SDimitry Andric Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, InGlue, DL); 76606c3fb27SDimitry Andric InGlue = Chain.getValue(1); 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric // Handle result values, copying them out of physregs into vregs that we 7690b57cec5SDimitry Andric // return. 77006c3fb27SDimitry Andric return LowerCallResult(Chain, InGlue, CallConv, IsVarArg, Ins, DL, DAG, 7710b57cec5SDimitry Andric InVals); 7720b57cec5SDimitry Andric } 7730b57cec5SDimitry Andric 7740b57cec5SDimitry Andric // LowerCallResult - Lower the result values of a call into the 7750b57cec5SDimitry Andric // appropriate copies out of appropriate physical registers. 7760b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerCallResult( 77706c3fb27SDimitry Andric SDValue Chain, SDValue InGlue, CallingConv::ID CallConv, bool IsVarArg, 7780b57cec5SDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 7790b57cec5SDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 7800b57cec5SDimitry Andric // Assign locations to each value returned by this call. 7810b57cec5SDimitry Andric SmallVector<CCValAssign, 16> RVLocs; 7820b57cec5SDimitry Andric CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, 7830b57cec5SDimitry Andric *DAG.getContext()); 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric CCInfo.AnalyzeCallResult(Ins, RetCC_Lanai32); 7860b57cec5SDimitry Andric 7870b57cec5SDimitry Andric // Copy all of the result registers out of their specified physreg. 7880b57cec5SDimitry Andric for (unsigned I = 0; I != RVLocs.size(); ++I) { 7890b57cec5SDimitry Andric Chain = DAG.getCopyFromReg(Chain, DL, RVLocs[I].getLocReg(), 79006c3fb27SDimitry Andric RVLocs[I].getValVT(), InGlue) 7910b57cec5SDimitry Andric .getValue(1); 79206c3fb27SDimitry Andric InGlue = Chain.getValue(2); 7930b57cec5SDimitry Andric InVals.push_back(Chain.getValue(0)); 7940b57cec5SDimitry Andric } 7950b57cec5SDimitry Andric 7960b57cec5SDimitry Andric return Chain; 7970b57cec5SDimitry Andric } 7980b57cec5SDimitry Andric 7990b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8000b57cec5SDimitry Andric // Custom Lowerings 8010b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8020b57cec5SDimitry Andric 8030b57cec5SDimitry Andric static LPCC::CondCode IntCondCCodeToICC(SDValue CC, const SDLoc &DL, 8040b57cec5SDimitry Andric SDValue &RHS, SelectionDAG &DAG) { 8050b57cec5SDimitry Andric ISD::CondCode SetCCOpcode = cast<CondCodeSDNode>(CC)->get(); 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric // For integer, only the SETEQ, SETNE, SETLT, SETLE, SETGT, SETGE, SETULT, 8080b57cec5SDimitry Andric // SETULE, SETUGT, and SETUGE opcodes are used (see CodeGen/ISDOpcodes.h) 8090b57cec5SDimitry Andric // and Lanai only supports integer comparisons, so only provide definitions 8100b57cec5SDimitry Andric // for them. 8110b57cec5SDimitry Andric switch (SetCCOpcode) { 8120b57cec5SDimitry Andric case ISD::SETEQ: 8130b57cec5SDimitry Andric return LPCC::ICC_EQ; 8140b57cec5SDimitry Andric case ISD::SETGT: 8150b57cec5SDimitry Andric if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS)) 8160b57cec5SDimitry Andric if (RHSC->getZExtValue() == 0xFFFFFFFF) { 8170b57cec5SDimitry Andric // X > -1 -> X >= 0 -> is_plus(X) 8180b57cec5SDimitry Andric RHS = DAG.getConstant(0, DL, RHS.getValueType()); 8190b57cec5SDimitry Andric return LPCC::ICC_PL; 8200b57cec5SDimitry Andric } 8210b57cec5SDimitry Andric return LPCC::ICC_GT; 8220b57cec5SDimitry Andric case ISD::SETUGT: 8230b57cec5SDimitry Andric return LPCC::ICC_UGT; 8240b57cec5SDimitry Andric case ISD::SETLT: 8250b57cec5SDimitry Andric if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS)) 8260b57cec5SDimitry Andric if (RHSC->getZExtValue() == 0) 8270b57cec5SDimitry Andric // X < 0 -> is_minus(X) 8280b57cec5SDimitry Andric return LPCC::ICC_MI; 8290b57cec5SDimitry Andric return LPCC::ICC_LT; 8300b57cec5SDimitry Andric case ISD::SETULT: 8310b57cec5SDimitry Andric return LPCC::ICC_ULT; 8320b57cec5SDimitry Andric case ISD::SETLE: 8330b57cec5SDimitry Andric if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS)) 8340b57cec5SDimitry Andric if (RHSC->getZExtValue() == 0xFFFFFFFF) { 8350b57cec5SDimitry Andric // X <= -1 -> X < 0 -> is_minus(X) 8360b57cec5SDimitry Andric RHS = DAG.getConstant(0, DL, RHS.getValueType()); 8370b57cec5SDimitry Andric return LPCC::ICC_MI; 8380b57cec5SDimitry Andric } 8390b57cec5SDimitry Andric return LPCC::ICC_LE; 8400b57cec5SDimitry Andric case ISD::SETULE: 8410b57cec5SDimitry Andric return LPCC::ICC_ULE; 8420b57cec5SDimitry Andric case ISD::SETGE: 8430b57cec5SDimitry Andric if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS)) 8440b57cec5SDimitry Andric if (RHSC->getZExtValue() == 0) 8450b57cec5SDimitry Andric // X >= 0 -> is_plus(X) 8460b57cec5SDimitry Andric return LPCC::ICC_PL; 8470b57cec5SDimitry Andric return LPCC::ICC_GE; 8480b57cec5SDimitry Andric case ISD::SETUGE: 8490b57cec5SDimitry Andric return LPCC::ICC_UGE; 8500b57cec5SDimitry Andric case ISD::SETNE: 8510b57cec5SDimitry Andric return LPCC::ICC_NE; 8520b57cec5SDimitry Andric case ISD::SETONE: 8530b57cec5SDimitry Andric case ISD::SETUNE: 8540b57cec5SDimitry Andric case ISD::SETOGE: 8550b57cec5SDimitry Andric case ISD::SETOLE: 8560b57cec5SDimitry Andric case ISD::SETOLT: 8570b57cec5SDimitry Andric case ISD::SETOGT: 8580b57cec5SDimitry Andric case ISD::SETOEQ: 8590b57cec5SDimitry Andric case ISD::SETUEQ: 8600b57cec5SDimitry Andric case ISD::SETO: 8610b57cec5SDimitry Andric case ISD::SETUO: 8620b57cec5SDimitry Andric llvm_unreachable("Unsupported comparison."); 8630b57cec5SDimitry Andric default: 8640b57cec5SDimitry Andric llvm_unreachable("Unknown integer condition code!"); 8650b57cec5SDimitry Andric } 8660b57cec5SDimitry Andric } 8670b57cec5SDimitry Andric 8680b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { 8690b57cec5SDimitry Andric SDValue Chain = Op.getOperand(0); 8700b57cec5SDimitry Andric SDValue Cond = Op.getOperand(1); 8710b57cec5SDimitry Andric SDValue LHS = Op.getOperand(2); 8720b57cec5SDimitry Andric SDValue RHS = Op.getOperand(3); 8730b57cec5SDimitry Andric SDValue Dest = Op.getOperand(4); 8740b57cec5SDimitry Andric SDLoc DL(Op); 8750b57cec5SDimitry Andric 8760b57cec5SDimitry Andric LPCC::CondCode CC = IntCondCCodeToICC(Cond, DL, RHS, DAG); 8770b57cec5SDimitry Andric SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32); 87806c3fb27SDimitry Andric SDValue Glue = 8790b57cec5SDimitry Andric DAG.getNode(LanaiISD::SET_FLAG, DL, MVT::Glue, LHS, RHS, TargetCC); 8800b57cec5SDimitry Andric 8810b57cec5SDimitry Andric return DAG.getNode(LanaiISD::BR_CC, DL, Op.getValueType(), Chain, Dest, 88206c3fb27SDimitry Andric TargetCC, Glue); 8830b57cec5SDimitry Andric } 8840b57cec5SDimitry Andric 8850b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const { 8860b57cec5SDimitry Andric EVT VT = Op->getValueType(0); 8870b57cec5SDimitry Andric if (VT != MVT::i32) 8880b57cec5SDimitry Andric return SDValue(); 8890b57cec5SDimitry Andric 8900b57cec5SDimitry Andric ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op->getOperand(1)); 8910b57cec5SDimitry Andric if (!C) 8920b57cec5SDimitry Andric return SDValue(); 8930b57cec5SDimitry Andric 8940b57cec5SDimitry Andric int64_t MulAmt = C->getSExtValue(); 8950b57cec5SDimitry Andric int32_t HighestOne = -1; 8960b57cec5SDimitry Andric uint32_t NonzeroEntries = 0; 8970b57cec5SDimitry Andric int SignedDigit[32] = {0}; 8980b57cec5SDimitry Andric 8990b57cec5SDimitry Andric // Convert to non-adjacent form (NAF) signed-digit representation. 9000b57cec5SDimitry Andric // NAF is a signed-digit form where no adjacent digits are non-zero. It is the 9010b57cec5SDimitry Andric // minimal Hamming weight representation of a number (on average 1/3 of the 9020b57cec5SDimitry Andric // digits will be non-zero vs 1/2 for regular binary representation). And as 9030b57cec5SDimitry Andric // the non-zero digits will be the only digits contributing to the instruction 9040b57cec5SDimitry Andric // count, this is desirable. The next loop converts it to NAF (following the 9050b57cec5SDimitry Andric // approach in 'Guide to Elliptic Curve Cryptography' [ISBN: 038795273X]) by 9060b57cec5SDimitry Andric // choosing the non-zero coefficients such that the resulting quotient is 9070b57cec5SDimitry Andric // divisible by 2 which will cause the next coefficient to be zero. 9080b57cec5SDimitry Andric int64_t E = std::abs(MulAmt); 9090b57cec5SDimitry Andric int S = (MulAmt < 0 ? -1 : 1); 9100b57cec5SDimitry Andric int I = 0; 9110b57cec5SDimitry Andric while (E > 0) { 9120b57cec5SDimitry Andric int ZI = 0; 9130b57cec5SDimitry Andric if (E % 2 == 1) { 9140b57cec5SDimitry Andric ZI = 2 - (E % 4); 9150b57cec5SDimitry Andric if (ZI != 0) 9160b57cec5SDimitry Andric ++NonzeroEntries; 9170b57cec5SDimitry Andric } 9180b57cec5SDimitry Andric SignedDigit[I] = S * ZI; 9190b57cec5SDimitry Andric if (SignedDigit[I] == 1) 9200b57cec5SDimitry Andric HighestOne = I; 9210b57cec5SDimitry Andric E = (E - ZI) / 2; 9220b57cec5SDimitry Andric ++I; 9230b57cec5SDimitry Andric } 9240b57cec5SDimitry Andric 9250b57cec5SDimitry Andric // Compute number of instructions required. Due to differences in lowering 9260b57cec5SDimitry Andric // between the different processors this count is not exact. 9270b57cec5SDimitry Andric // Start by assuming a shift and a add/sub for every non-zero entry (hence 9280b57cec5SDimitry Andric // every non-zero entry requires 1 shift and 1 add/sub except for the first 9290b57cec5SDimitry Andric // entry). 9300b57cec5SDimitry Andric int32_t InstrRequired = 2 * NonzeroEntries - 1; 9310b57cec5SDimitry Andric // Correct possible over-adding due to shift by 0 (which is not emitted). 9320b57cec5SDimitry Andric if (std::abs(MulAmt) % 2 == 1) 9330b57cec5SDimitry Andric --InstrRequired; 9340b57cec5SDimitry Andric // Return if the form generated would exceed the instruction threshold. 9350b57cec5SDimitry Andric if (InstrRequired > LanaiLowerConstantMulThreshold) 9360b57cec5SDimitry Andric return SDValue(); 9370b57cec5SDimitry Andric 9380b57cec5SDimitry Andric SDValue Res; 9390b57cec5SDimitry Andric SDLoc DL(Op); 9400b57cec5SDimitry Andric SDValue V = Op->getOperand(0); 9410b57cec5SDimitry Andric 9420b57cec5SDimitry Andric // Initialize the running sum. Set the running sum to the maximal shifted 9430b57cec5SDimitry Andric // positive value (i.e., largest i such that zi == 1 and MulAmt has V<<i as a 9440b57cec5SDimitry Andric // term NAF). 9450b57cec5SDimitry Andric if (HighestOne == -1) 9460b57cec5SDimitry Andric Res = DAG.getConstant(0, DL, MVT::i32); 9470b57cec5SDimitry Andric else { 9480b57cec5SDimitry Andric Res = DAG.getNode(ISD::SHL, DL, VT, V, 9490b57cec5SDimitry Andric DAG.getConstant(HighestOne, DL, MVT::i32)); 9500b57cec5SDimitry Andric SignedDigit[HighestOne] = 0; 9510b57cec5SDimitry Andric } 9520b57cec5SDimitry Andric 9530b57cec5SDimitry Andric // Assemble multiplication from shift, add, sub using NAF form and running 9540b57cec5SDimitry Andric // sum. 955bdd1243dSDimitry Andric for (unsigned int I = 0; I < std::size(SignedDigit); ++I) { 9560b57cec5SDimitry Andric if (SignedDigit[I] == 0) 9570b57cec5SDimitry Andric continue; 9580b57cec5SDimitry Andric 9590b57cec5SDimitry Andric // Shifted multiplicand (v<<i). 9600b57cec5SDimitry Andric SDValue Op = 9610b57cec5SDimitry Andric DAG.getNode(ISD::SHL, DL, VT, V, DAG.getConstant(I, DL, MVT::i32)); 9620b57cec5SDimitry Andric if (SignedDigit[I] == 1) 9630b57cec5SDimitry Andric Res = DAG.getNode(ISD::ADD, DL, VT, Res, Op); 9640b57cec5SDimitry Andric else if (SignedDigit[I] == -1) 9650b57cec5SDimitry Andric Res = DAG.getNode(ISD::SUB, DL, VT, Res, Op); 9660b57cec5SDimitry Andric } 9670b57cec5SDimitry Andric return Res; 9680b57cec5SDimitry Andric } 9690b57cec5SDimitry Andric 9700b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { 9710b57cec5SDimitry Andric SDValue LHS = Op.getOperand(0); 9720b57cec5SDimitry Andric SDValue RHS = Op.getOperand(1); 9730b57cec5SDimitry Andric SDValue Cond = Op.getOperand(2); 9740b57cec5SDimitry Andric SDLoc DL(Op); 9750b57cec5SDimitry Andric 9760b57cec5SDimitry Andric LPCC::CondCode CC = IntCondCCodeToICC(Cond, DL, RHS, DAG); 9770b57cec5SDimitry Andric SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32); 97806c3fb27SDimitry Andric SDValue Glue = 9790b57cec5SDimitry Andric DAG.getNode(LanaiISD::SET_FLAG, DL, MVT::Glue, LHS, RHS, TargetCC); 9800b57cec5SDimitry Andric 98106c3fb27SDimitry Andric return DAG.getNode(LanaiISD::SETCC, DL, Op.getValueType(), TargetCC, Glue); 9820b57cec5SDimitry Andric } 9830b57cec5SDimitry Andric 9840b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerSELECT_CC(SDValue Op, 9850b57cec5SDimitry Andric SelectionDAG &DAG) const { 9860b57cec5SDimitry Andric SDValue LHS = Op.getOperand(0); 9870b57cec5SDimitry Andric SDValue RHS = Op.getOperand(1); 9880b57cec5SDimitry Andric SDValue TrueV = Op.getOperand(2); 9890b57cec5SDimitry Andric SDValue FalseV = Op.getOperand(3); 9900b57cec5SDimitry Andric SDValue Cond = Op.getOperand(4); 9910b57cec5SDimitry Andric SDLoc DL(Op); 9920b57cec5SDimitry Andric 9930b57cec5SDimitry Andric LPCC::CondCode CC = IntCondCCodeToICC(Cond, DL, RHS, DAG); 9940b57cec5SDimitry Andric SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32); 99506c3fb27SDimitry Andric SDValue Glue = 9960b57cec5SDimitry Andric DAG.getNode(LanaiISD::SET_FLAG, DL, MVT::Glue, LHS, RHS, TargetCC); 9970b57cec5SDimitry Andric 9980b57cec5SDimitry Andric SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); 9990b57cec5SDimitry Andric return DAG.getNode(LanaiISD::SELECT_CC, DL, VTs, TrueV, FalseV, TargetCC, 100006c3fb27SDimitry Andric Glue); 10010b57cec5SDimitry Andric } 10020b57cec5SDimitry Andric 10030b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { 10040b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 10050b57cec5SDimitry Andric LanaiMachineFunctionInfo *FuncInfo = MF.getInfo<LanaiMachineFunctionInfo>(); 10060b57cec5SDimitry Andric 10070b57cec5SDimitry Andric SDLoc DL(Op); 10080b57cec5SDimitry Andric SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), 10090b57cec5SDimitry Andric getPointerTy(DAG.getDataLayout())); 10100b57cec5SDimitry Andric 10110b57cec5SDimitry Andric // vastart just stores the address of the VarArgsFrameIndex slot into the 10120b57cec5SDimitry Andric // memory location argument. 10130b57cec5SDimitry Andric const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); 10140b57cec5SDimitry Andric return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1), 10150b57cec5SDimitry Andric MachinePointerInfo(SV)); 10160b57cec5SDimitry Andric } 10170b57cec5SDimitry Andric 10180b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, 10190b57cec5SDimitry Andric SelectionDAG &DAG) const { 10200b57cec5SDimitry Andric SDValue Chain = Op.getOperand(0); 10210b57cec5SDimitry Andric SDValue Size = Op.getOperand(1); 10220b57cec5SDimitry Andric SDLoc DL(Op); 10230b57cec5SDimitry Andric 1024e8d8bef9SDimitry Andric Register SPReg = getStackPointerRegisterToSaveRestore(); 10250b57cec5SDimitry Andric 10260b57cec5SDimitry Andric // Get a reference to the stack pointer. 10270b57cec5SDimitry Andric SDValue StackPointer = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32); 10280b57cec5SDimitry Andric 10290b57cec5SDimitry Andric // Subtract the dynamic size from the actual stack size to 10300b57cec5SDimitry Andric // obtain the new stack size. 10310b57cec5SDimitry Andric SDValue Sub = DAG.getNode(ISD::SUB, DL, MVT::i32, StackPointer, Size); 10320b57cec5SDimitry Andric 10330b57cec5SDimitry Andric // For Lanai, the outgoing memory arguments area should be on top of the 10340b57cec5SDimitry Andric // alloca area on the stack i.e., the outgoing memory arguments should be 10350b57cec5SDimitry Andric // at a lower address than the alloca area. Move the alloca area down the 10360b57cec5SDimitry Andric // stack by adding back the space reserved for outgoing arguments to SP 10370b57cec5SDimitry Andric // here. 10380b57cec5SDimitry Andric // 10390b57cec5SDimitry Andric // We do not know what the size of the outgoing args is at this point. 10400b57cec5SDimitry Andric // So, we add a pseudo instruction ADJDYNALLOC that will adjust the 10410b57cec5SDimitry Andric // stack pointer. We replace this instruction with on that has the correct, 10420b57cec5SDimitry Andric // known offset in emitPrologue(). 10430b57cec5SDimitry Andric SDValue ArgAdjust = DAG.getNode(LanaiISD::ADJDYNALLOC, DL, MVT::i32, Sub); 10440b57cec5SDimitry Andric 10450b57cec5SDimitry Andric // The Sub result contains the new stack start address, so it 10460b57cec5SDimitry Andric // must be placed in the stack pointer register. 10470b57cec5SDimitry Andric SDValue CopyChain = DAG.getCopyToReg(Chain, DL, SPReg, Sub); 10480b57cec5SDimitry Andric 10490b57cec5SDimitry Andric SDValue Ops[2] = {ArgAdjust, CopyChain}; 10500b57cec5SDimitry Andric return DAG.getMergeValues(Ops, DL); 10510b57cec5SDimitry Andric } 10520b57cec5SDimitry Andric 10530b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerRETURNADDR(SDValue Op, 10540b57cec5SDimitry Andric SelectionDAG &DAG) const { 10550b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 10560b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo(); 10570b57cec5SDimitry Andric MFI.setReturnAddressIsTaken(true); 10580b57cec5SDimitry Andric 10590b57cec5SDimitry Andric EVT VT = Op.getValueType(); 10600b57cec5SDimitry Andric SDLoc DL(Op); 1061647cbc5dSDimitry Andric unsigned Depth = Op.getConstantOperandVal(0); 10620b57cec5SDimitry Andric if (Depth) { 10630b57cec5SDimitry Andric SDValue FrameAddr = LowerFRAMEADDR(Op, DAG); 10640b57cec5SDimitry Andric const unsigned Offset = -4; 10650b57cec5SDimitry Andric SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, 10660b57cec5SDimitry Andric DAG.getIntPtrConstant(Offset, DL)); 10670b57cec5SDimitry Andric return DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo()); 10680b57cec5SDimitry Andric } 10690b57cec5SDimitry Andric 10700b57cec5SDimitry Andric // Return the link register, which contains the return address. 10710b57cec5SDimitry Andric // Mark it an implicit live-in. 107204eeddc0SDimitry Andric Register Reg = MF.addLiveIn(TRI->getRARegister(), getRegClassFor(MVT::i32)); 10730b57cec5SDimitry Andric return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, VT); 10740b57cec5SDimitry Andric } 10750b57cec5SDimitry Andric 10760b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerFRAMEADDR(SDValue Op, 10770b57cec5SDimitry Andric SelectionDAG &DAG) const { 10780b57cec5SDimitry Andric MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); 10790b57cec5SDimitry Andric MFI.setFrameAddressIsTaken(true); 10800b57cec5SDimitry Andric 10810b57cec5SDimitry Andric EVT VT = Op.getValueType(); 10820b57cec5SDimitry Andric SDLoc DL(Op); 10830b57cec5SDimitry Andric SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, Lanai::FP, VT); 1084647cbc5dSDimitry Andric unsigned Depth = Op.getConstantOperandVal(0); 10850b57cec5SDimitry Andric while (Depth--) { 10860b57cec5SDimitry Andric const unsigned Offset = -8; 10870b57cec5SDimitry Andric SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, 10880b57cec5SDimitry Andric DAG.getIntPtrConstant(Offset, DL)); 10890b57cec5SDimitry Andric FrameAddr = 10900b57cec5SDimitry Andric DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo()); 10910b57cec5SDimitry Andric } 10920b57cec5SDimitry Andric return FrameAddr; 10930b57cec5SDimitry Andric } 10940b57cec5SDimitry Andric 10950b57cec5SDimitry Andric const char *LanaiTargetLowering::getTargetNodeName(unsigned Opcode) const { 10960b57cec5SDimitry Andric switch (Opcode) { 10970b57cec5SDimitry Andric case LanaiISD::ADJDYNALLOC: 10980b57cec5SDimitry Andric return "LanaiISD::ADJDYNALLOC"; 109906c3fb27SDimitry Andric case LanaiISD::RET_GLUE: 110006c3fb27SDimitry Andric return "LanaiISD::RET_GLUE"; 11010b57cec5SDimitry Andric case LanaiISD::CALL: 11020b57cec5SDimitry Andric return "LanaiISD::CALL"; 11030b57cec5SDimitry Andric case LanaiISD::SELECT_CC: 11040b57cec5SDimitry Andric return "LanaiISD::SELECT_CC"; 11050b57cec5SDimitry Andric case LanaiISD::SETCC: 11060b57cec5SDimitry Andric return "LanaiISD::SETCC"; 11070b57cec5SDimitry Andric case LanaiISD::SUBBF: 11080b57cec5SDimitry Andric return "LanaiISD::SUBBF"; 11090b57cec5SDimitry Andric case LanaiISD::SET_FLAG: 11100b57cec5SDimitry Andric return "LanaiISD::SET_FLAG"; 11110b57cec5SDimitry Andric case LanaiISD::BR_CC: 11120b57cec5SDimitry Andric return "LanaiISD::BR_CC"; 11130b57cec5SDimitry Andric case LanaiISD::Wrapper: 11140b57cec5SDimitry Andric return "LanaiISD::Wrapper"; 11150b57cec5SDimitry Andric case LanaiISD::HI: 11160b57cec5SDimitry Andric return "LanaiISD::HI"; 11170b57cec5SDimitry Andric case LanaiISD::LO: 11180b57cec5SDimitry Andric return "LanaiISD::LO"; 11190b57cec5SDimitry Andric case LanaiISD::SMALL: 11200b57cec5SDimitry Andric return "LanaiISD::SMALL"; 11210b57cec5SDimitry Andric default: 11220b57cec5SDimitry Andric return nullptr; 11230b57cec5SDimitry Andric } 11240b57cec5SDimitry Andric } 11250b57cec5SDimitry Andric 11260b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerConstantPool(SDValue Op, 11270b57cec5SDimitry Andric SelectionDAG &DAG) const { 11280b57cec5SDimitry Andric SDLoc DL(Op); 11290b57cec5SDimitry Andric ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); 11300b57cec5SDimitry Andric const Constant *C = N->getConstVal(); 11310b57cec5SDimitry Andric const LanaiTargetObjectFile *TLOF = 11320b57cec5SDimitry Andric static_cast<const LanaiTargetObjectFile *>( 11330b57cec5SDimitry Andric getTargetMachine().getObjFileLowering()); 11340b57cec5SDimitry Andric 11350b57cec5SDimitry Andric // If the code model is small or constant will be placed in the small section, 11360b57cec5SDimitry Andric // then assume address will fit in 21-bits. 11370b57cec5SDimitry Andric if (getTargetMachine().getCodeModel() == CodeModel::Small || 11380b57cec5SDimitry Andric TLOF->isConstantInSmallSection(DAG.getDataLayout(), C)) { 11390b57cec5SDimitry Andric SDValue Small = DAG.getTargetConstantPool( 11405ffd83dbSDimitry Andric C, MVT::i32, N->getAlign(), N->getOffset(), LanaiII::MO_NO_FLAG); 11410b57cec5SDimitry Andric return DAG.getNode(ISD::OR, DL, MVT::i32, 11420b57cec5SDimitry Andric DAG.getRegister(Lanai::R0, MVT::i32), 11430b57cec5SDimitry Andric DAG.getNode(LanaiISD::SMALL, DL, MVT::i32, Small)); 11440b57cec5SDimitry Andric } else { 11450b57cec5SDimitry Andric uint8_t OpFlagHi = LanaiII::MO_ABS_HI; 11460b57cec5SDimitry Andric uint8_t OpFlagLo = LanaiII::MO_ABS_LO; 11470b57cec5SDimitry Andric 11485ffd83dbSDimitry Andric SDValue Hi = DAG.getTargetConstantPool(C, MVT::i32, N->getAlign(), 11490b57cec5SDimitry Andric N->getOffset(), OpFlagHi); 11505ffd83dbSDimitry Andric SDValue Lo = DAG.getTargetConstantPool(C, MVT::i32, N->getAlign(), 11510b57cec5SDimitry Andric N->getOffset(), OpFlagLo); 11520b57cec5SDimitry Andric Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); 11530b57cec5SDimitry Andric Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); 11540b57cec5SDimitry Andric SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); 11550b57cec5SDimitry Andric return Result; 11560b57cec5SDimitry Andric } 11570b57cec5SDimitry Andric } 11580b57cec5SDimitry Andric 11590b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerGlobalAddress(SDValue Op, 11600b57cec5SDimitry Andric SelectionDAG &DAG) const { 11610b57cec5SDimitry Andric SDLoc DL(Op); 11620b57cec5SDimitry Andric const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); 11630b57cec5SDimitry Andric int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset(); 11640b57cec5SDimitry Andric 11650b57cec5SDimitry Andric const LanaiTargetObjectFile *TLOF = 11660b57cec5SDimitry Andric static_cast<const LanaiTargetObjectFile *>( 11670b57cec5SDimitry Andric getTargetMachine().getObjFileLowering()); 11680b57cec5SDimitry Andric 11690b57cec5SDimitry Andric // If the code model is small or global variable will be placed in the small 11700b57cec5SDimitry Andric // section, then assume address will fit in 21-bits. 1171349cc55cSDimitry Andric const GlobalObject *GO = GV->getAliaseeObject(); 11720b57cec5SDimitry Andric if (TLOF->isGlobalInSmallSection(GO, getTargetMachine())) { 11730b57cec5SDimitry Andric SDValue Small = DAG.getTargetGlobalAddress( 11740b57cec5SDimitry Andric GV, DL, getPointerTy(DAG.getDataLayout()), Offset, LanaiII::MO_NO_FLAG); 11750b57cec5SDimitry Andric return DAG.getNode(ISD::OR, DL, MVT::i32, 11760b57cec5SDimitry Andric DAG.getRegister(Lanai::R0, MVT::i32), 11770b57cec5SDimitry Andric DAG.getNode(LanaiISD::SMALL, DL, MVT::i32, Small)); 11780b57cec5SDimitry Andric } else { 11790b57cec5SDimitry Andric uint8_t OpFlagHi = LanaiII::MO_ABS_HI; 11800b57cec5SDimitry Andric uint8_t OpFlagLo = LanaiII::MO_ABS_LO; 11810b57cec5SDimitry Andric 11820b57cec5SDimitry Andric // Create the TargetGlobalAddress node, folding in the constant offset. 11830b57cec5SDimitry Andric SDValue Hi = DAG.getTargetGlobalAddress( 11840b57cec5SDimitry Andric GV, DL, getPointerTy(DAG.getDataLayout()), Offset, OpFlagHi); 11850b57cec5SDimitry Andric SDValue Lo = DAG.getTargetGlobalAddress( 11860b57cec5SDimitry Andric GV, DL, getPointerTy(DAG.getDataLayout()), Offset, OpFlagLo); 11870b57cec5SDimitry Andric Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); 11880b57cec5SDimitry Andric Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); 11890b57cec5SDimitry Andric return DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); 11900b57cec5SDimitry Andric } 11910b57cec5SDimitry Andric } 11920b57cec5SDimitry Andric 11930b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerBlockAddress(SDValue Op, 11940b57cec5SDimitry Andric SelectionDAG &DAG) const { 11950b57cec5SDimitry Andric SDLoc DL(Op); 11960b57cec5SDimitry Andric const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress(); 11970b57cec5SDimitry Andric 11980b57cec5SDimitry Andric uint8_t OpFlagHi = LanaiII::MO_ABS_HI; 11990b57cec5SDimitry Andric uint8_t OpFlagLo = LanaiII::MO_ABS_LO; 12000b57cec5SDimitry Andric 12010b57cec5SDimitry Andric SDValue Hi = DAG.getBlockAddress(BA, MVT::i32, true, OpFlagHi); 12020b57cec5SDimitry Andric SDValue Lo = DAG.getBlockAddress(BA, MVT::i32, true, OpFlagLo); 12030b57cec5SDimitry Andric Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); 12040b57cec5SDimitry Andric Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); 12050b57cec5SDimitry Andric SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); 12060b57cec5SDimitry Andric return Result; 12070b57cec5SDimitry Andric } 12080b57cec5SDimitry Andric 12090b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerJumpTable(SDValue Op, 12100b57cec5SDimitry Andric SelectionDAG &DAG) const { 12110b57cec5SDimitry Andric SDLoc DL(Op); 12120b57cec5SDimitry Andric JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); 12130b57cec5SDimitry Andric 12140b57cec5SDimitry Andric // If the code model is small assume address will fit in 21-bits. 12150b57cec5SDimitry Andric if (getTargetMachine().getCodeModel() == CodeModel::Small) { 12160b57cec5SDimitry Andric SDValue Small = DAG.getTargetJumpTable( 12170b57cec5SDimitry Andric JT->getIndex(), getPointerTy(DAG.getDataLayout()), LanaiII::MO_NO_FLAG); 12180b57cec5SDimitry Andric return DAG.getNode(ISD::OR, DL, MVT::i32, 12190b57cec5SDimitry Andric DAG.getRegister(Lanai::R0, MVT::i32), 12200b57cec5SDimitry Andric DAG.getNode(LanaiISD::SMALL, DL, MVT::i32, Small)); 12210b57cec5SDimitry Andric } else { 12220b57cec5SDimitry Andric uint8_t OpFlagHi = LanaiII::MO_ABS_HI; 12230b57cec5SDimitry Andric uint8_t OpFlagLo = LanaiII::MO_ABS_LO; 12240b57cec5SDimitry Andric 12250b57cec5SDimitry Andric SDValue Hi = DAG.getTargetJumpTable( 12260b57cec5SDimitry Andric JT->getIndex(), getPointerTy(DAG.getDataLayout()), OpFlagHi); 12270b57cec5SDimitry Andric SDValue Lo = DAG.getTargetJumpTable( 12280b57cec5SDimitry Andric JT->getIndex(), getPointerTy(DAG.getDataLayout()), OpFlagLo); 12290b57cec5SDimitry Andric Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); 12300b57cec5SDimitry Andric Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); 12310b57cec5SDimitry Andric SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); 12320b57cec5SDimitry Andric return Result; 12330b57cec5SDimitry Andric } 12340b57cec5SDimitry Andric } 12350b57cec5SDimitry Andric 12360b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerSHL_PARTS(SDValue Op, 12370b57cec5SDimitry Andric SelectionDAG &DAG) const { 12380b57cec5SDimitry Andric EVT VT = Op.getValueType(); 12390b57cec5SDimitry Andric unsigned VTBits = VT.getSizeInBits(); 12400b57cec5SDimitry Andric SDLoc dl(Op); 12410b57cec5SDimitry Andric assert(Op.getNumOperands() == 3 && "Unexpected SHL!"); 12420b57cec5SDimitry Andric SDValue ShOpLo = Op.getOperand(0); 12430b57cec5SDimitry Andric SDValue ShOpHi = Op.getOperand(1); 12440b57cec5SDimitry Andric SDValue ShAmt = Op.getOperand(2); 12450b57cec5SDimitry Andric 12460b57cec5SDimitry Andric // Performs the following for (ShOpLo + (ShOpHi << 32)) << ShAmt: 12470b57cec5SDimitry Andric // LoBitsForHi = (ShAmt == 0) ? 0 : (ShOpLo >> (32-ShAmt)) 12480b57cec5SDimitry Andric // HiBitsForHi = ShOpHi << ShAmt 12490b57cec5SDimitry Andric // Hi = (ShAmt >= 32) ? (ShOpLo << (ShAmt-32)) : (LoBitsForHi | HiBitsForHi) 12500b57cec5SDimitry Andric // Lo = (ShAmt >= 32) ? 0 : (ShOpLo << ShAmt) 12510b57cec5SDimitry Andric // return (Hi << 32) | Lo; 12520b57cec5SDimitry Andric 12530b57cec5SDimitry Andric SDValue RevShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, 12540b57cec5SDimitry Andric DAG.getConstant(VTBits, dl, MVT::i32), ShAmt); 12550b57cec5SDimitry Andric SDValue LoBitsForHi = DAG.getNode(ISD::SRL, dl, VT, ShOpLo, RevShAmt); 12560b57cec5SDimitry Andric 12570b57cec5SDimitry Andric // If ShAmt == 0, we just calculated "(SRL ShOpLo, 32)" which is "undef". We 12580b57cec5SDimitry Andric // wanted 0, so CSEL it directly. 12590b57cec5SDimitry Andric SDValue Zero = DAG.getConstant(0, dl, MVT::i32); 12600b57cec5SDimitry Andric SDValue SetCC = DAG.getSetCC(dl, MVT::i32, ShAmt, Zero, ISD::SETEQ); 12610b57cec5SDimitry Andric LoBitsForHi = DAG.getSelect(dl, MVT::i32, SetCC, Zero, LoBitsForHi); 12620b57cec5SDimitry Andric 12630b57cec5SDimitry Andric SDValue ExtraShAmt = DAG.getNode(ISD::SUB, dl, MVT::i32, ShAmt, 12640b57cec5SDimitry Andric DAG.getConstant(VTBits, dl, MVT::i32)); 12650b57cec5SDimitry Andric SDValue HiBitsForHi = DAG.getNode(ISD::SHL, dl, VT, ShOpHi, ShAmt); 12660b57cec5SDimitry Andric SDValue HiForNormalShift = 12670b57cec5SDimitry Andric DAG.getNode(ISD::OR, dl, VT, LoBitsForHi, HiBitsForHi); 12680b57cec5SDimitry Andric 12690b57cec5SDimitry Andric SDValue HiForBigShift = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ExtraShAmt); 12700b57cec5SDimitry Andric 12710b57cec5SDimitry Andric SetCC = DAG.getSetCC(dl, MVT::i32, ExtraShAmt, Zero, ISD::SETGE); 12720b57cec5SDimitry Andric SDValue Hi = 12730b57cec5SDimitry Andric DAG.getSelect(dl, MVT::i32, SetCC, HiForBigShift, HiForNormalShift); 12740b57cec5SDimitry Andric 12750b57cec5SDimitry Andric // Lanai shifts of larger than register sizes are wrapped rather than 12760b57cec5SDimitry Andric // clamped, so we can't just emit "lo << b" if b is too big. 12770b57cec5SDimitry Andric SDValue LoForNormalShift = DAG.getNode(ISD::SHL, dl, VT, ShOpLo, ShAmt); 12780b57cec5SDimitry Andric SDValue Lo = DAG.getSelect( 12790b57cec5SDimitry Andric dl, MVT::i32, SetCC, DAG.getConstant(0, dl, MVT::i32), LoForNormalShift); 12800b57cec5SDimitry Andric 12810b57cec5SDimitry Andric SDValue Ops[2] = {Lo, Hi}; 12820b57cec5SDimitry Andric return DAG.getMergeValues(Ops, dl); 12830b57cec5SDimitry Andric } 12840b57cec5SDimitry Andric 12850b57cec5SDimitry Andric SDValue LanaiTargetLowering::LowerSRL_PARTS(SDValue Op, 12860b57cec5SDimitry Andric SelectionDAG &DAG) const { 12870b57cec5SDimitry Andric MVT VT = Op.getSimpleValueType(); 12880b57cec5SDimitry Andric unsigned VTBits = VT.getSizeInBits(); 12890b57cec5SDimitry Andric SDLoc dl(Op); 12900b57cec5SDimitry Andric SDValue ShOpLo = Op.getOperand(0); 12910b57cec5SDimitry Andric SDValue ShOpHi = Op.getOperand(1); 12920b57cec5SDimitry Andric SDValue ShAmt = Op.getOperand(2); 12930b57cec5SDimitry Andric 12940b57cec5SDimitry Andric // Performs the following for a >> b: 12950b57cec5SDimitry Andric // unsigned r_high = a_high >> b; 12960b57cec5SDimitry Andric // r_high = (32 - b <= 0) ? 0 : r_high; 12970b57cec5SDimitry Andric // 12980b57cec5SDimitry Andric // unsigned r_low = a_low >> b; 12990b57cec5SDimitry Andric // r_low = (32 - b <= 0) ? r_high : r_low; 13000b57cec5SDimitry Andric // r_low = (b == 0) ? r_low : r_low | (a_high << (32 - b)); 13010b57cec5SDimitry Andric // return (unsigned long long)r_high << 32 | r_low; 13020b57cec5SDimitry Andric // Note: This takes advantage of Lanai's shift behavior to avoid needing to 13030b57cec5SDimitry Andric // mask the shift amount. 13040b57cec5SDimitry Andric 13050b57cec5SDimitry Andric SDValue Zero = DAG.getConstant(0, dl, MVT::i32); 13060b57cec5SDimitry Andric SDValue NegatedPlus32 = DAG.getNode( 13070b57cec5SDimitry Andric ISD::SUB, dl, MVT::i32, DAG.getConstant(VTBits, dl, MVT::i32), ShAmt); 13080b57cec5SDimitry Andric SDValue SetCC = DAG.getSetCC(dl, MVT::i32, NegatedPlus32, Zero, ISD::SETLE); 13090b57cec5SDimitry Andric 13100b57cec5SDimitry Andric SDValue Hi = DAG.getNode(ISD::SRL, dl, MVT::i32, ShOpHi, ShAmt); 13110b57cec5SDimitry Andric Hi = DAG.getSelect(dl, MVT::i32, SetCC, Zero, Hi); 13120b57cec5SDimitry Andric 13130b57cec5SDimitry Andric SDValue Lo = DAG.getNode(ISD::SRL, dl, MVT::i32, ShOpLo, ShAmt); 13140b57cec5SDimitry Andric Lo = DAG.getSelect(dl, MVT::i32, SetCC, Hi, Lo); 13150b57cec5SDimitry Andric SDValue CarryBits = 13160b57cec5SDimitry Andric DAG.getNode(ISD::SHL, dl, MVT::i32, ShOpHi, NegatedPlus32); 13170b57cec5SDimitry Andric SDValue ShiftIsZero = DAG.getSetCC(dl, MVT::i32, ShAmt, Zero, ISD::SETEQ); 13180b57cec5SDimitry Andric Lo = DAG.getSelect(dl, MVT::i32, ShiftIsZero, Lo, 13190b57cec5SDimitry Andric DAG.getNode(ISD::OR, dl, MVT::i32, Lo, CarryBits)); 13200b57cec5SDimitry Andric 13210b57cec5SDimitry Andric SDValue Ops[2] = {Lo, Hi}; 13220b57cec5SDimitry Andric return DAG.getMergeValues(Ops, dl); 13230b57cec5SDimitry Andric } 13240b57cec5SDimitry Andric 13250b57cec5SDimitry Andric // Helper function that checks if N is a null or all ones constant. 13260b57cec5SDimitry Andric static inline bool isZeroOrAllOnes(SDValue N, bool AllOnes) { 13270b57cec5SDimitry Andric return AllOnes ? isAllOnesConstant(N) : isNullConstant(N); 13280b57cec5SDimitry Andric } 13290b57cec5SDimitry Andric 13300b57cec5SDimitry Andric // Return true if N is conditionally 0 or all ones. 13310b57cec5SDimitry Andric // Detects these expressions where cc is an i1 value: 13320b57cec5SDimitry Andric // 13330b57cec5SDimitry Andric // (select cc 0, y) [AllOnes=0] 13340b57cec5SDimitry Andric // (select cc y, 0) [AllOnes=0] 13350b57cec5SDimitry Andric // (zext cc) [AllOnes=0] 13360b57cec5SDimitry Andric // (sext cc) [AllOnes=0/1] 13370b57cec5SDimitry Andric // (select cc -1, y) [AllOnes=1] 13380b57cec5SDimitry Andric // (select cc y, -1) [AllOnes=1] 13390b57cec5SDimitry Andric // 13400b57cec5SDimitry Andric // * AllOnes determines whether to check for an all zero (AllOnes false) or an 13410b57cec5SDimitry Andric // all ones operand (AllOnes true). 13420b57cec5SDimitry Andric // * Invert is set when N is the all zero/ones constant when CC is false. 13430b57cec5SDimitry Andric // * OtherOp is set to the alternative value of N. 13440b57cec5SDimitry Andric // 13450b57cec5SDimitry Andric // For example, for (select cc X, Y) and AllOnes = 0 if: 13460b57cec5SDimitry Andric // * X = 0, Invert = False and OtherOp = Y 13470b57cec5SDimitry Andric // * Y = 0, Invert = True and OtherOp = X 13480b57cec5SDimitry Andric static bool isConditionalZeroOrAllOnes(SDNode *N, bool AllOnes, SDValue &CC, 13490b57cec5SDimitry Andric bool &Invert, SDValue &OtherOp, 13500b57cec5SDimitry Andric SelectionDAG &DAG) { 13510b57cec5SDimitry Andric switch (N->getOpcode()) { 13520b57cec5SDimitry Andric default: 13530b57cec5SDimitry Andric return false; 13540b57cec5SDimitry Andric case ISD::SELECT: { 13550b57cec5SDimitry Andric CC = N->getOperand(0); 13560b57cec5SDimitry Andric SDValue N1 = N->getOperand(1); 13570b57cec5SDimitry Andric SDValue N2 = N->getOperand(2); 13580b57cec5SDimitry Andric if (isZeroOrAllOnes(N1, AllOnes)) { 13590b57cec5SDimitry Andric Invert = false; 13600b57cec5SDimitry Andric OtherOp = N2; 13610b57cec5SDimitry Andric return true; 13620b57cec5SDimitry Andric } 13630b57cec5SDimitry Andric if (isZeroOrAllOnes(N2, AllOnes)) { 13640b57cec5SDimitry Andric Invert = true; 13650b57cec5SDimitry Andric OtherOp = N1; 13660b57cec5SDimitry Andric return true; 13670b57cec5SDimitry Andric } 13680b57cec5SDimitry Andric return false; 13690b57cec5SDimitry Andric } 13700b57cec5SDimitry Andric case ISD::ZERO_EXTEND: { 13710b57cec5SDimitry Andric // (zext cc) can never be the all ones value. 13720b57cec5SDimitry Andric if (AllOnes) 13730b57cec5SDimitry Andric return false; 13740b57cec5SDimitry Andric CC = N->getOperand(0); 13750b57cec5SDimitry Andric if (CC.getValueType() != MVT::i1) 13760b57cec5SDimitry Andric return false; 13770b57cec5SDimitry Andric SDLoc dl(N); 13780b57cec5SDimitry Andric EVT VT = N->getValueType(0); 13790b57cec5SDimitry Andric OtherOp = DAG.getConstant(1, dl, VT); 13800b57cec5SDimitry Andric Invert = true; 13810b57cec5SDimitry Andric return true; 13820b57cec5SDimitry Andric } 13830b57cec5SDimitry Andric case ISD::SIGN_EXTEND: { 13840b57cec5SDimitry Andric CC = N->getOperand(0); 13850b57cec5SDimitry Andric if (CC.getValueType() != MVT::i1) 13860b57cec5SDimitry Andric return false; 13870b57cec5SDimitry Andric SDLoc dl(N); 13880b57cec5SDimitry Andric EVT VT = N->getValueType(0); 13890b57cec5SDimitry Andric Invert = !AllOnes; 13900b57cec5SDimitry Andric if (AllOnes) 13910b57cec5SDimitry Andric // When looking for an AllOnes constant, N is an sext, and the 'other' 13920b57cec5SDimitry Andric // value is 0. 13930b57cec5SDimitry Andric OtherOp = DAG.getConstant(0, dl, VT); 13940b57cec5SDimitry Andric else 1395349cc55cSDimitry Andric OtherOp = DAG.getAllOnesConstant(dl, VT); 13960b57cec5SDimitry Andric return true; 13970b57cec5SDimitry Andric } 13980b57cec5SDimitry Andric } 13990b57cec5SDimitry Andric } 14000b57cec5SDimitry Andric 14010b57cec5SDimitry Andric // Combine a constant select operand into its use: 14020b57cec5SDimitry Andric // 14030b57cec5SDimitry Andric // (add (select cc, 0, c), x) -> (select cc, x, (add, x, c)) 14040b57cec5SDimitry Andric // (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) 14050b57cec5SDimitry Andric // (and (select cc, -1, c), x) -> (select cc, x, (and, x, c)) [AllOnes=1] 14060b57cec5SDimitry Andric // (or (select cc, 0, c), x) -> (select cc, x, (or, x, c)) 14070b57cec5SDimitry Andric // (xor (select cc, 0, c), x) -> (select cc, x, (xor, x, c)) 14080b57cec5SDimitry Andric // 14090b57cec5SDimitry Andric // The transform is rejected if the select doesn't have a constant operand that 14100b57cec5SDimitry Andric // is null, or all ones when AllOnes is set. 14110b57cec5SDimitry Andric // 14120b57cec5SDimitry Andric // Also recognize sext/zext from i1: 14130b57cec5SDimitry Andric // 14140b57cec5SDimitry Andric // (add (zext cc), x) -> (select cc (add x, 1), x) 14150b57cec5SDimitry Andric // (add (sext cc), x) -> (select cc (add x, -1), x) 14160b57cec5SDimitry Andric // 14170b57cec5SDimitry Andric // These transformations eventually create predicated instructions. 14180b57cec5SDimitry Andric static SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp, 14190b57cec5SDimitry Andric TargetLowering::DAGCombinerInfo &DCI, 14200b57cec5SDimitry Andric bool AllOnes) { 14210b57cec5SDimitry Andric SelectionDAG &DAG = DCI.DAG; 14220b57cec5SDimitry Andric EVT VT = N->getValueType(0); 14230b57cec5SDimitry Andric SDValue NonConstantVal; 14240b57cec5SDimitry Andric SDValue CCOp; 14250b57cec5SDimitry Andric bool SwapSelectOps; 14260b57cec5SDimitry Andric if (!isConditionalZeroOrAllOnes(Slct.getNode(), AllOnes, CCOp, SwapSelectOps, 14270b57cec5SDimitry Andric NonConstantVal, DAG)) 14280b57cec5SDimitry Andric return SDValue(); 14290b57cec5SDimitry Andric 14300b57cec5SDimitry Andric // Slct is now know to be the desired identity constant when CC is true. 14310b57cec5SDimitry Andric SDValue TrueVal = OtherOp; 14320b57cec5SDimitry Andric SDValue FalseVal = 14330b57cec5SDimitry Andric DAG.getNode(N->getOpcode(), SDLoc(N), VT, OtherOp, NonConstantVal); 14340b57cec5SDimitry Andric // Unless SwapSelectOps says CC should be false. 14350b57cec5SDimitry Andric if (SwapSelectOps) 14360b57cec5SDimitry Andric std::swap(TrueVal, FalseVal); 14370b57cec5SDimitry Andric 14380b57cec5SDimitry Andric return DAG.getNode(ISD::SELECT, SDLoc(N), VT, CCOp, TrueVal, FalseVal); 14390b57cec5SDimitry Andric } 14400b57cec5SDimitry Andric 14410b57cec5SDimitry Andric // Attempt combineSelectAndUse on each operand of a commutative operator N. 14420b57cec5SDimitry Andric static SDValue 14430b57cec5SDimitry Andric combineSelectAndUseCommutative(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, 14440b57cec5SDimitry Andric bool AllOnes) { 14450b57cec5SDimitry Andric SDValue N0 = N->getOperand(0); 14460b57cec5SDimitry Andric SDValue N1 = N->getOperand(1); 14470b57cec5SDimitry Andric if (N0.getNode()->hasOneUse()) 14480b57cec5SDimitry Andric if (SDValue Result = combineSelectAndUse(N, N0, N1, DCI, AllOnes)) 14490b57cec5SDimitry Andric return Result; 14500b57cec5SDimitry Andric if (N1.getNode()->hasOneUse()) 14510b57cec5SDimitry Andric if (SDValue Result = combineSelectAndUse(N, N1, N0, DCI, AllOnes)) 14520b57cec5SDimitry Andric return Result; 14530b57cec5SDimitry Andric return SDValue(); 14540b57cec5SDimitry Andric } 14550b57cec5SDimitry Andric 14560b57cec5SDimitry Andric // PerformSUBCombine - Target-specific dag combine xforms for ISD::SUB. 14570b57cec5SDimitry Andric static SDValue PerformSUBCombine(SDNode *N, 14580b57cec5SDimitry Andric TargetLowering::DAGCombinerInfo &DCI) { 14590b57cec5SDimitry Andric SDValue N0 = N->getOperand(0); 14600b57cec5SDimitry Andric SDValue N1 = N->getOperand(1); 14610b57cec5SDimitry Andric 14620b57cec5SDimitry Andric // fold (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) 14630b57cec5SDimitry Andric if (N1.getNode()->hasOneUse()) 14640b57cec5SDimitry Andric if (SDValue Result = combineSelectAndUse(N, N1, N0, DCI, /*AllOnes=*/false)) 14650b57cec5SDimitry Andric return Result; 14660b57cec5SDimitry Andric 14670b57cec5SDimitry Andric return SDValue(); 14680b57cec5SDimitry Andric } 14690b57cec5SDimitry Andric 14700b57cec5SDimitry Andric SDValue LanaiTargetLowering::PerformDAGCombine(SDNode *N, 14710b57cec5SDimitry Andric DAGCombinerInfo &DCI) const { 14720b57cec5SDimitry Andric switch (N->getOpcode()) { 14730b57cec5SDimitry Andric default: 14740b57cec5SDimitry Andric break; 14750b57cec5SDimitry Andric case ISD::ADD: 14760b57cec5SDimitry Andric case ISD::OR: 14770b57cec5SDimitry Andric case ISD::XOR: 14780b57cec5SDimitry Andric return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/false); 14790b57cec5SDimitry Andric case ISD::AND: 14800b57cec5SDimitry Andric return combineSelectAndUseCommutative(N, DCI, /*AllOnes=*/true); 14810b57cec5SDimitry Andric case ISD::SUB: 14820b57cec5SDimitry Andric return PerformSUBCombine(N, DCI); 14830b57cec5SDimitry Andric } 14840b57cec5SDimitry Andric 14850b57cec5SDimitry Andric return SDValue(); 14860b57cec5SDimitry Andric } 14870b57cec5SDimitry Andric 14880b57cec5SDimitry Andric void LanaiTargetLowering::computeKnownBitsForTargetNode( 14890b57cec5SDimitry Andric const SDValue Op, KnownBits &Known, const APInt &DemandedElts, 14900b57cec5SDimitry Andric const SelectionDAG &DAG, unsigned Depth) const { 14910b57cec5SDimitry Andric unsigned BitWidth = Known.getBitWidth(); 14920b57cec5SDimitry Andric switch (Op.getOpcode()) { 14930b57cec5SDimitry Andric default: 14940b57cec5SDimitry Andric break; 14950b57cec5SDimitry Andric case LanaiISD::SETCC: 14960b57cec5SDimitry Andric Known = KnownBits(BitWidth); 14970b57cec5SDimitry Andric Known.Zero.setBits(1, BitWidth); 14980b57cec5SDimitry Andric break; 14990b57cec5SDimitry Andric case LanaiISD::SELECT_CC: 15000b57cec5SDimitry Andric KnownBits Known2; 15010b57cec5SDimitry Andric Known = DAG.computeKnownBits(Op->getOperand(0), Depth + 1); 15020b57cec5SDimitry Andric Known2 = DAG.computeKnownBits(Op->getOperand(1), Depth + 1); 150306c3fb27SDimitry Andric Known = Known.intersectWith(Known2); 15040b57cec5SDimitry Andric break; 15050b57cec5SDimitry Andric } 15060b57cec5SDimitry Andric } 1507