10b57cec5SDimitry Andric //===-- AVRISelLowering.cpp - AVR 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 defines the interfaces that AVR uses to lower LLVM code into a
100b57cec5SDimitry Andric // selection DAG.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "AVRISelLowering.h"
150b57cec5SDimitry Andric
1681ad6265SDimitry Andric #include "llvm/ADT/ArrayRef.h"
175ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h"
18349cc55cSDimitry Andric #include "llvm/ADT/StringSwitch.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/CallingConvLower.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
250b57cec5SDimitry Andric #include "llvm/IR/Function.h"
260b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric #include "AVR.h"
290b57cec5SDimitry Andric #include "AVRMachineFunctionInfo.h"
300b57cec5SDimitry Andric #include "AVRSubtarget.h"
310b57cec5SDimitry Andric #include "AVRTargetMachine.h"
320b57cec5SDimitry Andric #include "MCTargetDesc/AVRMCTargetDesc.h"
330b57cec5SDimitry Andric
340b57cec5SDimitry Andric namespace llvm {
350b57cec5SDimitry Andric
AVRTargetLowering(const AVRTargetMachine & TM,const AVRSubtarget & STI)360b57cec5SDimitry Andric AVRTargetLowering::AVRTargetLowering(const AVRTargetMachine &TM,
370b57cec5SDimitry Andric const AVRSubtarget &STI)
380b57cec5SDimitry Andric : TargetLowering(TM), Subtarget(STI) {
390b57cec5SDimitry Andric // Set up the register classes.
400b57cec5SDimitry Andric addRegisterClass(MVT::i8, &AVR::GPR8RegClass);
410b57cec5SDimitry Andric addRegisterClass(MVT::i16, &AVR::DREGSRegClass);
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric // Compute derived properties from the register classes.
440b57cec5SDimitry Andric computeRegisterProperties(Subtarget.getRegisterInfo());
450b57cec5SDimitry Andric
460b57cec5SDimitry Andric setBooleanContents(ZeroOrOneBooleanContent);
470b57cec5SDimitry Andric setBooleanVectorContents(ZeroOrOneBooleanContent);
480b57cec5SDimitry Andric setSchedulingPreference(Sched::RegPressure);
490b57cec5SDimitry Andric setStackPointerRegisterToSaveRestore(AVR::SP);
500b57cec5SDimitry Andric setSupportsUnalignedAtomics(true);
510b57cec5SDimitry Andric
520b57cec5SDimitry Andric setOperationAction(ISD::GlobalAddress, MVT::i16, Custom);
530b57cec5SDimitry Andric setOperationAction(ISD::BlockAddress, MVT::i16, Custom);
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
560b57cec5SDimitry Andric setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
570b57cec5SDimitry Andric setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i8, Expand);
580b57cec5SDimitry Andric setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i16, Expand);
590b57cec5SDimitry Andric
60bdd1243dSDimitry Andric setOperationAction(ISD::INLINEASM, MVT::Other, Custom);
61bdd1243dSDimitry Andric
620b57cec5SDimitry Andric for (MVT VT : MVT::integer_valuetypes()) {
630b57cec5SDimitry Andric for (auto N : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) {
640b57cec5SDimitry Andric setLoadExtAction(N, VT, MVT::i1, Promote);
650b57cec5SDimitry Andric setLoadExtAction(N, VT, MVT::i8, Expand);
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric setTruncStoreAction(MVT::i16, MVT::i8, Expand);
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric for (MVT VT : MVT::integer_valuetypes()) {
720b57cec5SDimitry Andric setOperationAction(ISD::ADDC, VT, Legal);
730b57cec5SDimitry Andric setOperationAction(ISD::SUBC, VT, Legal);
740b57cec5SDimitry Andric setOperationAction(ISD::ADDE, VT, Legal);
750b57cec5SDimitry Andric setOperationAction(ISD::SUBE, VT, Legal);
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric // sub (x, imm) gets canonicalized to add (x, -imm), so for illegal types
790b57cec5SDimitry Andric // revert into a sub since we don't have an add with immediate instruction.
800b57cec5SDimitry Andric setOperationAction(ISD::ADD, MVT::i32, Custom);
810b57cec5SDimitry Andric setOperationAction(ISD::ADD, MVT::i64, Custom);
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric // our shift instructions are only able to shift 1 bit at a time, so handle
840b57cec5SDimitry Andric // this in a custom way.
850b57cec5SDimitry Andric setOperationAction(ISD::SRA, MVT::i8, Custom);
860b57cec5SDimitry Andric setOperationAction(ISD::SHL, MVT::i8, Custom);
870b57cec5SDimitry Andric setOperationAction(ISD::SRL, MVT::i8, Custom);
880b57cec5SDimitry Andric setOperationAction(ISD::SRA, MVT::i16, Custom);
890b57cec5SDimitry Andric setOperationAction(ISD::SHL, MVT::i16, Custom);
900b57cec5SDimitry Andric setOperationAction(ISD::SRL, MVT::i16, Custom);
91bdd1243dSDimitry Andric setOperationAction(ISD::SRA, MVT::i32, Custom);
92bdd1243dSDimitry Andric setOperationAction(ISD::SHL, MVT::i32, Custom);
93bdd1243dSDimitry Andric setOperationAction(ISD::SRL, MVT::i32, Custom);
940b57cec5SDimitry Andric setOperationAction(ISD::SHL_PARTS, MVT::i16, Expand);
950b57cec5SDimitry Andric setOperationAction(ISD::SRA_PARTS, MVT::i16, Expand);
960b57cec5SDimitry Andric setOperationAction(ISD::SRL_PARTS, MVT::i16, Expand);
970b57cec5SDimitry Andric
980b57cec5SDimitry Andric setOperationAction(ISD::ROTL, MVT::i8, Custom);
990b57cec5SDimitry Andric setOperationAction(ISD::ROTL, MVT::i16, Expand);
1000b57cec5SDimitry Andric setOperationAction(ISD::ROTR, MVT::i8, Custom);
1010b57cec5SDimitry Andric setOperationAction(ISD::ROTR, MVT::i16, Expand);
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric setOperationAction(ISD::BR_CC, MVT::i8, Custom);
1040b57cec5SDimitry Andric setOperationAction(ISD::BR_CC, MVT::i16, Custom);
1050b57cec5SDimitry Andric setOperationAction(ISD::BR_CC, MVT::i32, Custom);
1060b57cec5SDimitry Andric setOperationAction(ISD::BR_CC, MVT::i64, Custom);
1070b57cec5SDimitry Andric setOperationAction(ISD::BRCOND, MVT::Other, Expand);
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::i8, Custom);
1100b57cec5SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::i16, Custom);
1110b57cec5SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::i32, Expand);
1120b57cec5SDimitry Andric setOperationAction(ISD::SELECT_CC, MVT::i64, Expand);
1130b57cec5SDimitry Andric setOperationAction(ISD::SETCC, MVT::i8, Custom);
1140b57cec5SDimitry Andric setOperationAction(ISD::SETCC, MVT::i16, Custom);
1150b57cec5SDimitry Andric setOperationAction(ISD::SETCC, MVT::i32, Custom);
1160b57cec5SDimitry Andric setOperationAction(ISD::SETCC, MVT::i64, Custom);
1170b57cec5SDimitry Andric setOperationAction(ISD::SELECT, MVT::i8, Expand);
1180b57cec5SDimitry Andric setOperationAction(ISD::SELECT, MVT::i16, Expand);
1190b57cec5SDimitry Andric
1200b57cec5SDimitry Andric setOperationAction(ISD::BSWAP, MVT::i16, Expand);
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric // Add support for postincrement and predecrement load/stores.
1230b57cec5SDimitry Andric setIndexedLoadAction(ISD::POST_INC, MVT::i8, Legal);
1240b57cec5SDimitry Andric setIndexedLoadAction(ISD::POST_INC, MVT::i16, Legal);
1250b57cec5SDimitry Andric setIndexedLoadAction(ISD::PRE_DEC, MVT::i8, Legal);
1260b57cec5SDimitry Andric setIndexedLoadAction(ISD::PRE_DEC, MVT::i16, Legal);
1270b57cec5SDimitry Andric setIndexedStoreAction(ISD::POST_INC, MVT::i8, Legal);
1280b57cec5SDimitry Andric setIndexedStoreAction(ISD::POST_INC, MVT::i16, Legal);
1290b57cec5SDimitry Andric setIndexedStoreAction(ISD::PRE_DEC, MVT::i8, Legal);
1300b57cec5SDimitry Andric setIndexedStoreAction(ISD::PRE_DEC, MVT::i16, Legal);
1310b57cec5SDimitry Andric
1320b57cec5SDimitry Andric setOperationAction(ISD::BR_JT, MVT::Other, Expand);
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric setOperationAction(ISD::VASTART, MVT::Other, Custom);
1350b57cec5SDimitry Andric setOperationAction(ISD::VAEND, MVT::Other, Expand);
1360b57cec5SDimitry Andric setOperationAction(ISD::VAARG, MVT::Other, Expand);
1370b57cec5SDimitry Andric setOperationAction(ISD::VACOPY, MVT::Other, Expand);
1380b57cec5SDimitry Andric
1390b57cec5SDimitry Andric // Atomic operations which must be lowered to rtlib calls
1400b57cec5SDimitry Andric for (MVT VT : MVT::integer_valuetypes()) {
1410b57cec5SDimitry Andric setOperationAction(ISD::ATOMIC_SWAP, VT, Expand);
1420b57cec5SDimitry Andric setOperationAction(ISD::ATOMIC_CMP_SWAP, VT, Expand);
1430b57cec5SDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_NAND, VT, Expand);
1440b57cec5SDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_MAX, VT, Expand);
1450b57cec5SDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_MIN, VT, Expand);
1460b57cec5SDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_UMAX, VT, Expand);
1470b57cec5SDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_UMIN, VT, Expand);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric // Division/remainder
1510b57cec5SDimitry Andric setOperationAction(ISD::UDIV, MVT::i8, Expand);
1520b57cec5SDimitry Andric setOperationAction(ISD::UDIV, MVT::i16, Expand);
1530b57cec5SDimitry Andric setOperationAction(ISD::UREM, MVT::i8, Expand);
1540b57cec5SDimitry Andric setOperationAction(ISD::UREM, MVT::i16, Expand);
1550b57cec5SDimitry Andric setOperationAction(ISD::SDIV, MVT::i8, Expand);
1560b57cec5SDimitry Andric setOperationAction(ISD::SDIV, MVT::i16, Expand);
1570b57cec5SDimitry Andric setOperationAction(ISD::SREM, MVT::i8, Expand);
1580b57cec5SDimitry Andric setOperationAction(ISD::SREM, MVT::i16, Expand);
1590b57cec5SDimitry Andric
1600b57cec5SDimitry Andric // Make division and modulus custom
1615ffd83dbSDimitry Andric setOperationAction(ISD::UDIVREM, MVT::i8, Custom);
1625ffd83dbSDimitry Andric setOperationAction(ISD::UDIVREM, MVT::i16, Custom);
1635ffd83dbSDimitry Andric setOperationAction(ISD::UDIVREM, MVT::i32, Custom);
1645ffd83dbSDimitry Andric setOperationAction(ISD::SDIVREM, MVT::i8, Custom);
1655ffd83dbSDimitry Andric setOperationAction(ISD::SDIVREM, MVT::i16, Custom);
1665ffd83dbSDimitry Andric setOperationAction(ISD::SDIVREM, MVT::i32, Custom);
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric // Do not use MUL. The AVR instructions are closer to SMUL_LOHI &co.
1690b57cec5SDimitry Andric setOperationAction(ISD::MUL, MVT::i8, Expand);
1700b57cec5SDimitry Andric setOperationAction(ISD::MUL, MVT::i16, Expand);
1710b57cec5SDimitry Andric
1720b57cec5SDimitry Andric // Expand 16 bit multiplications.
1730b57cec5SDimitry Andric setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand);
1740b57cec5SDimitry Andric setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand);
1750b57cec5SDimitry Andric
1760b57cec5SDimitry Andric // Expand multiplications to libcalls when there is
1770b57cec5SDimitry Andric // no hardware MUL.
1780b57cec5SDimitry Andric if (!Subtarget.supportsMultiplication()) {
1790b57cec5SDimitry Andric setOperationAction(ISD::SMUL_LOHI, MVT::i8, Expand);
1800b57cec5SDimitry Andric setOperationAction(ISD::UMUL_LOHI, MVT::i8, Expand);
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric
1830b57cec5SDimitry Andric for (MVT VT : MVT::integer_valuetypes()) {
1840b57cec5SDimitry Andric setOperationAction(ISD::MULHS, VT, Expand);
1850b57cec5SDimitry Andric setOperationAction(ISD::MULHU, VT, Expand);
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric for (MVT VT : MVT::integer_valuetypes()) {
1890b57cec5SDimitry Andric setOperationAction(ISD::CTPOP, VT, Expand);
1900b57cec5SDimitry Andric setOperationAction(ISD::CTLZ, VT, Expand);
1910b57cec5SDimitry Andric setOperationAction(ISD::CTTZ, VT, Expand);
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric
1940b57cec5SDimitry Andric for (MVT VT : MVT::integer_valuetypes()) {
1950b57cec5SDimitry Andric setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand);
1960b57cec5SDimitry Andric // TODO: The generated code is pretty poor. Investigate using the
1970b57cec5SDimitry Andric // same "shift and subtract with carry" trick that we do for
1980b57cec5SDimitry Andric // extending 8-bit to 16-bit. This may require infrastructure
1990b57cec5SDimitry Andric // improvements in how we treat 16-bit "registers" to be feasible.
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric
2020b57cec5SDimitry Andric // Division and modulus rtlib functions
2030b57cec5SDimitry Andric setLibcallName(RTLIB::SDIVREM_I8, "__divmodqi4");
2040b57cec5SDimitry Andric setLibcallName(RTLIB::SDIVREM_I16, "__divmodhi4");
2050b57cec5SDimitry Andric setLibcallName(RTLIB::SDIVREM_I32, "__divmodsi4");
2060b57cec5SDimitry Andric setLibcallName(RTLIB::UDIVREM_I8, "__udivmodqi4");
2070b57cec5SDimitry Andric setLibcallName(RTLIB::UDIVREM_I16, "__udivmodhi4");
2080b57cec5SDimitry Andric setLibcallName(RTLIB::UDIVREM_I32, "__udivmodsi4");
2090b57cec5SDimitry Andric
2100b57cec5SDimitry Andric // Several of the runtime library functions use a special calling conv
2110b57cec5SDimitry Andric setLibcallCallingConv(RTLIB::SDIVREM_I8, CallingConv::AVR_BUILTIN);
2120b57cec5SDimitry Andric setLibcallCallingConv(RTLIB::SDIVREM_I16, CallingConv::AVR_BUILTIN);
2130b57cec5SDimitry Andric setLibcallCallingConv(RTLIB::UDIVREM_I8, CallingConv::AVR_BUILTIN);
2140b57cec5SDimitry Andric setLibcallCallingConv(RTLIB::UDIVREM_I16, CallingConv::AVR_BUILTIN);
2150b57cec5SDimitry Andric
2160b57cec5SDimitry Andric // Trigonometric rtlib functions
2170b57cec5SDimitry Andric setLibcallName(RTLIB::SIN_F32, "sin");
2180b57cec5SDimitry Andric setLibcallName(RTLIB::COS_F32, "cos");
2190b57cec5SDimitry Andric
2208bcb0991SDimitry Andric setMinFunctionAlignment(Align(2));
2210b57cec5SDimitry Andric setMinimumJumpTableEntries(UINT_MAX);
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric
getTargetNodeName(unsigned Opcode) const2240b57cec5SDimitry Andric const char *AVRTargetLowering::getTargetNodeName(unsigned Opcode) const {
2250b57cec5SDimitry Andric #define NODE(name) \
2260b57cec5SDimitry Andric case AVRISD::name: \
2270b57cec5SDimitry Andric return #name
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric switch (Opcode) {
2300b57cec5SDimitry Andric default:
2310b57cec5SDimitry Andric return nullptr;
23206c3fb27SDimitry Andric NODE(RET_GLUE);
23306c3fb27SDimitry Andric NODE(RETI_GLUE);
2340b57cec5SDimitry Andric NODE(CALL);
2350b57cec5SDimitry Andric NODE(WRAPPER);
2360b57cec5SDimitry Andric NODE(LSL);
237bdd1243dSDimitry Andric NODE(LSLW);
2380b57cec5SDimitry Andric NODE(LSR);
239bdd1243dSDimitry Andric NODE(LSRW);
2400b57cec5SDimitry Andric NODE(ROL);
2410b57cec5SDimitry Andric NODE(ROR);
2420b57cec5SDimitry Andric NODE(ASR);
243bdd1243dSDimitry Andric NODE(ASRW);
2440b57cec5SDimitry Andric NODE(LSLLOOP);
2450b57cec5SDimitry Andric NODE(LSRLOOP);
2465ffd83dbSDimitry Andric NODE(ROLLOOP);
2475ffd83dbSDimitry Andric NODE(RORLOOP);
2480b57cec5SDimitry Andric NODE(ASRLOOP);
2490b57cec5SDimitry Andric NODE(BRCOND);
2500b57cec5SDimitry Andric NODE(CMP);
2510b57cec5SDimitry Andric NODE(CMPC);
2520b57cec5SDimitry Andric NODE(TST);
2530b57cec5SDimitry Andric NODE(SELECT_CC);
2540b57cec5SDimitry Andric #undef NODE
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric
getSetCCResultType(const DataLayout & DL,LLVMContext &,EVT VT) const2580b57cec5SDimitry Andric EVT AVRTargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &,
2590b57cec5SDimitry Andric EVT VT) const {
2600b57cec5SDimitry Andric assert(!VT.isVector() && "No AVR SetCC type for vectors!");
2610b57cec5SDimitry Andric return MVT::i8;
2620b57cec5SDimitry Andric }
2630b57cec5SDimitry Andric
LowerShifts(SDValue Op,SelectionDAG & DAG) const2640b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
2650b57cec5SDimitry Andric unsigned Opc8;
2660b57cec5SDimitry Andric const SDNode *N = Op.getNode();
2670b57cec5SDimitry Andric EVT VT = Op.getValueType();
2680b57cec5SDimitry Andric SDLoc dl(N);
26906c3fb27SDimitry Andric assert(llvm::has_single_bit<uint32_t>(VT.getSizeInBits()) &&
2705ffd83dbSDimitry Andric "Expected power-of-2 shift amount");
2710b57cec5SDimitry Andric
272bdd1243dSDimitry Andric if (VT.getSizeInBits() == 32) {
273bdd1243dSDimitry Andric if (!isa<ConstantSDNode>(N->getOperand(1))) {
274bdd1243dSDimitry Andric // 32-bit shifts are converted to a loop in IR.
275bdd1243dSDimitry Andric // This should be unreachable.
276bdd1243dSDimitry Andric report_fatal_error("Expected a constant shift amount!");
277bdd1243dSDimitry Andric }
278bdd1243dSDimitry Andric SDVTList ResTys = DAG.getVTList(MVT::i16, MVT::i16);
279bdd1243dSDimitry Andric SDValue SrcLo =
280bdd1243dSDimitry Andric DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i16, Op.getOperand(0),
281bdd1243dSDimitry Andric DAG.getConstant(0, dl, MVT::i16));
282bdd1243dSDimitry Andric SDValue SrcHi =
283bdd1243dSDimitry Andric DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i16, Op.getOperand(0),
284bdd1243dSDimitry Andric DAG.getConstant(1, dl, MVT::i16));
285647cbc5dSDimitry Andric uint64_t ShiftAmount = N->getConstantOperandVal(1);
286bdd1243dSDimitry Andric if (ShiftAmount == 16) {
287bdd1243dSDimitry Andric // Special case these two operations because they appear to be used by the
288bdd1243dSDimitry Andric // generic codegen parts to lower 32-bit numbers.
289bdd1243dSDimitry Andric // TODO: perhaps we can lower shift amounts bigger than 16 to a 16-bit
290bdd1243dSDimitry Andric // shift of a part of the 32-bit value?
291bdd1243dSDimitry Andric switch (Op.getOpcode()) {
292bdd1243dSDimitry Andric case ISD::SHL: {
293bdd1243dSDimitry Andric SDValue Zero = DAG.getConstant(0, dl, MVT::i16);
294bdd1243dSDimitry Andric return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i32, Zero, SrcLo);
295bdd1243dSDimitry Andric }
296bdd1243dSDimitry Andric case ISD::SRL: {
297bdd1243dSDimitry Andric SDValue Zero = DAG.getConstant(0, dl, MVT::i16);
298bdd1243dSDimitry Andric return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i32, SrcHi, Zero);
299bdd1243dSDimitry Andric }
300bdd1243dSDimitry Andric }
301bdd1243dSDimitry Andric }
302bdd1243dSDimitry Andric SDValue Cnt = DAG.getTargetConstant(ShiftAmount, dl, MVT::i8);
303bdd1243dSDimitry Andric unsigned Opc;
304bdd1243dSDimitry Andric switch (Op.getOpcode()) {
305bdd1243dSDimitry Andric default:
306bdd1243dSDimitry Andric llvm_unreachable("Invalid 32-bit shift opcode!");
307bdd1243dSDimitry Andric case ISD::SHL:
308bdd1243dSDimitry Andric Opc = AVRISD::LSLW;
309bdd1243dSDimitry Andric break;
310bdd1243dSDimitry Andric case ISD::SRL:
311bdd1243dSDimitry Andric Opc = AVRISD::LSRW;
312bdd1243dSDimitry Andric break;
313bdd1243dSDimitry Andric case ISD::SRA:
314bdd1243dSDimitry Andric Opc = AVRISD::ASRW;
315bdd1243dSDimitry Andric break;
316bdd1243dSDimitry Andric }
317bdd1243dSDimitry Andric SDValue Result = DAG.getNode(Opc, dl, ResTys, SrcLo, SrcHi, Cnt);
318bdd1243dSDimitry Andric return DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i32, Result.getValue(0),
319bdd1243dSDimitry Andric Result.getValue(1));
320bdd1243dSDimitry Andric }
321bdd1243dSDimitry Andric
3220b57cec5SDimitry Andric // Expand non-constant shifts to loops.
3230b57cec5SDimitry Andric if (!isa<ConstantSDNode>(N->getOperand(1))) {
3240b57cec5SDimitry Andric switch (Op.getOpcode()) {
3250b57cec5SDimitry Andric default:
3260b57cec5SDimitry Andric llvm_unreachable("Invalid shift opcode!");
3270b57cec5SDimitry Andric case ISD::SHL:
3280b57cec5SDimitry Andric return DAG.getNode(AVRISD::LSLLOOP, dl, VT, N->getOperand(0),
3290b57cec5SDimitry Andric N->getOperand(1));
3300b57cec5SDimitry Andric case ISD::SRL:
3310b57cec5SDimitry Andric return DAG.getNode(AVRISD::LSRLOOP, dl, VT, N->getOperand(0),
3320b57cec5SDimitry Andric N->getOperand(1));
3335ffd83dbSDimitry Andric case ISD::ROTL: {
3345ffd83dbSDimitry Andric SDValue Amt = N->getOperand(1);
3355ffd83dbSDimitry Andric EVT AmtVT = Amt.getValueType();
3365ffd83dbSDimitry Andric Amt = DAG.getNode(ISD::AND, dl, AmtVT, Amt,
3375ffd83dbSDimitry Andric DAG.getConstant(VT.getSizeInBits() - 1, dl, AmtVT));
3385ffd83dbSDimitry Andric return DAG.getNode(AVRISD::ROLLOOP, dl, VT, N->getOperand(0), Amt);
3395ffd83dbSDimitry Andric }
3405ffd83dbSDimitry Andric case ISD::ROTR: {
3415ffd83dbSDimitry Andric SDValue Amt = N->getOperand(1);
3425ffd83dbSDimitry Andric EVT AmtVT = Amt.getValueType();
3435ffd83dbSDimitry Andric Amt = DAG.getNode(ISD::AND, dl, AmtVT, Amt,
3445ffd83dbSDimitry Andric DAG.getConstant(VT.getSizeInBits() - 1, dl, AmtVT));
3455ffd83dbSDimitry Andric return DAG.getNode(AVRISD::RORLOOP, dl, VT, N->getOperand(0), Amt);
3465ffd83dbSDimitry Andric }
3470b57cec5SDimitry Andric case ISD::SRA:
3480b57cec5SDimitry Andric return DAG.getNode(AVRISD::ASRLOOP, dl, VT, N->getOperand(0),
3490b57cec5SDimitry Andric N->getOperand(1));
3500b57cec5SDimitry Andric }
3510b57cec5SDimitry Andric }
3520b57cec5SDimitry Andric
353647cbc5dSDimitry Andric uint64_t ShiftAmount = N->getConstantOperandVal(1);
3540b57cec5SDimitry Andric SDValue Victim = N->getOperand(0);
3550b57cec5SDimitry Andric
3560b57cec5SDimitry Andric switch (Op.getOpcode()) {
3570b57cec5SDimitry Andric case ISD::SRA:
3580b57cec5SDimitry Andric Opc8 = AVRISD::ASR;
3590b57cec5SDimitry Andric break;
3600b57cec5SDimitry Andric case ISD::ROTL:
3610b57cec5SDimitry Andric Opc8 = AVRISD::ROL;
3625ffd83dbSDimitry Andric ShiftAmount = ShiftAmount % VT.getSizeInBits();
3630b57cec5SDimitry Andric break;
3640b57cec5SDimitry Andric case ISD::ROTR:
3650b57cec5SDimitry Andric Opc8 = AVRISD::ROR;
3665ffd83dbSDimitry Andric ShiftAmount = ShiftAmount % VT.getSizeInBits();
3670b57cec5SDimitry Andric break;
3680b57cec5SDimitry Andric case ISD::SRL:
3690b57cec5SDimitry Andric Opc8 = AVRISD::LSR;
3700b57cec5SDimitry Andric break;
3710b57cec5SDimitry Andric case ISD::SHL:
3720b57cec5SDimitry Andric Opc8 = AVRISD::LSL;
3730b57cec5SDimitry Andric break;
3740b57cec5SDimitry Andric default:
3750b57cec5SDimitry Andric llvm_unreachable("Invalid shift opcode");
3760b57cec5SDimitry Andric }
3770b57cec5SDimitry Andric
378fe6060f1SDimitry Andric // Optimize int8/int16 shifts.
379e8d8bef9SDimitry Andric if (VT.getSizeInBits() == 8) {
380e8d8bef9SDimitry Andric if (Op.getOpcode() == ISD::SHL && 4 <= ShiftAmount && ShiftAmount < 7) {
381e8d8bef9SDimitry Andric // Optimize LSL when 4 <= ShiftAmount <= 6.
382e8d8bef9SDimitry Andric Victim = DAG.getNode(AVRISD::SWAP, dl, VT, Victim);
383e8d8bef9SDimitry Andric Victim =
384e8d8bef9SDimitry Andric DAG.getNode(ISD::AND, dl, VT, Victim, DAG.getConstant(0xf0, dl, VT));
385e8d8bef9SDimitry Andric ShiftAmount -= 4;
386e8d8bef9SDimitry Andric } else if (Op.getOpcode() == ISD::SRL && 4 <= ShiftAmount &&
387e8d8bef9SDimitry Andric ShiftAmount < 7) {
388e8d8bef9SDimitry Andric // Optimize LSR when 4 <= ShiftAmount <= 6.
389e8d8bef9SDimitry Andric Victim = DAG.getNode(AVRISD::SWAP, dl, VT, Victim);
390e8d8bef9SDimitry Andric Victim =
391e8d8bef9SDimitry Andric DAG.getNode(ISD::AND, dl, VT, Victim, DAG.getConstant(0x0f, dl, VT));
392e8d8bef9SDimitry Andric ShiftAmount -= 4;
393e8d8bef9SDimitry Andric } else if (Op.getOpcode() == ISD::SHL && ShiftAmount == 7) {
394e8d8bef9SDimitry Andric // Optimize LSL when ShiftAmount == 7.
395fe6060f1SDimitry Andric Victim = DAG.getNode(AVRISD::LSLBN, dl, VT, Victim,
396fe6060f1SDimitry Andric DAG.getConstant(7, dl, VT));
397e8d8bef9SDimitry Andric ShiftAmount = 0;
398e8d8bef9SDimitry Andric } else if (Op.getOpcode() == ISD::SRL && ShiftAmount == 7) {
399e8d8bef9SDimitry Andric // Optimize LSR when ShiftAmount == 7.
400fe6060f1SDimitry Andric Victim = DAG.getNode(AVRISD::LSRBN, dl, VT, Victim,
401fe6060f1SDimitry Andric DAG.getConstant(7, dl, VT));
402e8d8bef9SDimitry Andric ShiftAmount = 0;
40304eeddc0SDimitry Andric } else if (Op.getOpcode() == ISD::SRA && ShiftAmount == 6) {
40404eeddc0SDimitry Andric // Optimize ASR when ShiftAmount == 6.
40504eeddc0SDimitry Andric Victim = DAG.getNode(AVRISD::ASRBN, dl, VT, Victim,
40604eeddc0SDimitry Andric DAG.getConstant(6, dl, VT));
40704eeddc0SDimitry Andric ShiftAmount = 0;
408e8d8bef9SDimitry Andric } else if (Op.getOpcode() == ISD::SRA && ShiftAmount == 7) {
409e8d8bef9SDimitry Andric // Optimize ASR when ShiftAmount == 7.
410fe6060f1SDimitry Andric Victim = DAG.getNode(AVRISD::ASRBN, dl, VT, Victim,
411fe6060f1SDimitry Andric DAG.getConstant(7, dl, VT));
412e8d8bef9SDimitry Andric ShiftAmount = 0;
41306c3fb27SDimitry Andric } else if (Op.getOpcode() == ISD::ROTL && ShiftAmount == 3) {
41406c3fb27SDimitry Andric // Optimize left rotation 3 bits to swap then right rotation 1 bit.
41506c3fb27SDimitry Andric Victim = DAG.getNode(AVRISD::SWAP, dl, VT, Victim);
41606c3fb27SDimitry Andric Victim =
41706c3fb27SDimitry Andric DAG.getNode(AVRISD::ROR, dl, VT, Victim, DAG.getConstant(1, dl, VT));
41806c3fb27SDimitry Andric ShiftAmount = 0;
41906c3fb27SDimitry Andric } else if (Op.getOpcode() == ISD::ROTR && ShiftAmount == 3) {
42006c3fb27SDimitry Andric // Optimize right rotation 3 bits to swap then left rotation 1 bit.
42106c3fb27SDimitry Andric Victim = DAG.getNode(AVRISD::SWAP, dl, VT, Victim);
42206c3fb27SDimitry Andric Victim =
42306c3fb27SDimitry Andric DAG.getNode(AVRISD::ROL, dl, VT, Victim, DAG.getConstant(1, dl, VT));
42406c3fb27SDimitry Andric ShiftAmount = 0;
42506c3fb27SDimitry Andric } else if (Op.getOpcode() == ISD::ROTL && ShiftAmount == 7) {
42606c3fb27SDimitry Andric // Optimize left rotation 7 bits to right rotation 1 bit.
42706c3fb27SDimitry Andric Victim =
42806c3fb27SDimitry Andric DAG.getNode(AVRISD::ROR, dl, VT, Victim, DAG.getConstant(1, dl, VT));
42906c3fb27SDimitry Andric ShiftAmount = 0;
43006c3fb27SDimitry Andric } else if (Op.getOpcode() == ISD::ROTR && ShiftAmount == 7) {
43106c3fb27SDimitry Andric // Optimize right rotation 7 bits to left rotation 1 bit.
43206c3fb27SDimitry Andric Victim =
43306c3fb27SDimitry Andric DAG.getNode(AVRISD::ROL, dl, VT, Victim, DAG.getConstant(1, dl, VT));
43406c3fb27SDimitry Andric ShiftAmount = 0;
43506c3fb27SDimitry Andric } else if ((Op.getOpcode() == ISD::ROTR || Op.getOpcode() == ISD::ROTL) &&
43606c3fb27SDimitry Andric ShiftAmount >= 4) {
43706c3fb27SDimitry Andric // Optimize left/right rotation with the SWAP instruction.
43806c3fb27SDimitry Andric Victim = DAG.getNode(AVRISD::SWAP, dl, VT, Victim);
43906c3fb27SDimitry Andric ShiftAmount -= 4;
440e8d8bef9SDimitry Andric }
441fe6060f1SDimitry Andric } else if (VT.getSizeInBits() == 16) {
44281ad6265SDimitry Andric if (Op.getOpcode() == ISD::SRA)
44381ad6265SDimitry Andric // Special optimization for int16 arithmetic right shift.
44481ad6265SDimitry Andric switch (ShiftAmount) {
44581ad6265SDimitry Andric case 15:
44681ad6265SDimitry Andric Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim,
44781ad6265SDimitry Andric DAG.getConstant(15, dl, VT));
44881ad6265SDimitry Andric ShiftAmount = 0;
44981ad6265SDimitry Andric break;
45081ad6265SDimitry Andric case 14:
45181ad6265SDimitry Andric Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim,
45281ad6265SDimitry Andric DAG.getConstant(14, dl, VT));
45381ad6265SDimitry Andric ShiftAmount = 0;
45481ad6265SDimitry Andric break;
45581ad6265SDimitry Andric case 7:
45681ad6265SDimitry Andric Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim,
45781ad6265SDimitry Andric DAG.getConstant(7, dl, VT));
45881ad6265SDimitry Andric ShiftAmount = 0;
45981ad6265SDimitry Andric break;
46081ad6265SDimitry Andric default:
46181ad6265SDimitry Andric break;
46281ad6265SDimitry Andric }
463fe6060f1SDimitry Andric if (4 <= ShiftAmount && ShiftAmount < 8)
464fe6060f1SDimitry Andric switch (Op.getOpcode()) {
465fe6060f1SDimitry Andric case ISD::SHL:
466fe6060f1SDimitry Andric Victim = DAG.getNode(AVRISD::LSLWN, dl, VT, Victim,
467fe6060f1SDimitry Andric DAG.getConstant(4, dl, VT));
468fe6060f1SDimitry Andric ShiftAmount -= 4;
469fe6060f1SDimitry Andric break;
470fe6060f1SDimitry Andric case ISD::SRL:
471fe6060f1SDimitry Andric Victim = DAG.getNode(AVRISD::LSRWN, dl, VT, Victim,
472fe6060f1SDimitry Andric DAG.getConstant(4, dl, VT));
473fe6060f1SDimitry Andric ShiftAmount -= 4;
474fe6060f1SDimitry Andric break;
475fe6060f1SDimitry Andric default:
476fe6060f1SDimitry Andric break;
477fe6060f1SDimitry Andric }
478fe6060f1SDimitry Andric else if (8 <= ShiftAmount && ShiftAmount < 12)
479fe6060f1SDimitry Andric switch (Op.getOpcode()) {
480fe6060f1SDimitry Andric case ISD::SHL:
481fe6060f1SDimitry Andric Victim = DAG.getNode(AVRISD::LSLWN, dl, VT, Victim,
482fe6060f1SDimitry Andric DAG.getConstant(8, dl, VT));
483fe6060f1SDimitry Andric ShiftAmount -= 8;
48404eeddc0SDimitry Andric // Only operate on the higher byte for remaining shift bits.
48504eeddc0SDimitry Andric Opc8 = AVRISD::LSLHI;
486fe6060f1SDimitry Andric break;
487fe6060f1SDimitry Andric case ISD::SRL:
488fe6060f1SDimitry Andric Victim = DAG.getNode(AVRISD::LSRWN, dl, VT, Victim,
489fe6060f1SDimitry Andric DAG.getConstant(8, dl, VT));
490fe6060f1SDimitry Andric ShiftAmount -= 8;
49104eeddc0SDimitry Andric // Only operate on the lower byte for remaining shift bits.
49204eeddc0SDimitry Andric Opc8 = AVRISD::LSRLO;
493fe6060f1SDimitry Andric break;
494fe6060f1SDimitry Andric case ISD::SRA:
495fe6060f1SDimitry Andric Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim,
496fe6060f1SDimitry Andric DAG.getConstant(8, dl, VT));
497fe6060f1SDimitry Andric ShiftAmount -= 8;
49804eeddc0SDimitry Andric // Only operate on the lower byte for remaining shift bits.
49904eeddc0SDimitry Andric Opc8 = AVRISD::ASRLO;
500fe6060f1SDimitry Andric break;
501fe6060f1SDimitry Andric default:
502fe6060f1SDimitry Andric break;
503fe6060f1SDimitry Andric }
504fe6060f1SDimitry Andric else if (12 <= ShiftAmount)
505fe6060f1SDimitry Andric switch (Op.getOpcode()) {
506fe6060f1SDimitry Andric case ISD::SHL:
507fe6060f1SDimitry Andric Victim = DAG.getNode(AVRISD::LSLWN, dl, VT, Victim,
508fe6060f1SDimitry Andric DAG.getConstant(12, dl, VT));
509fe6060f1SDimitry Andric ShiftAmount -= 12;
51004eeddc0SDimitry Andric // Only operate on the higher byte for remaining shift bits.
51104eeddc0SDimitry Andric Opc8 = AVRISD::LSLHI;
512fe6060f1SDimitry Andric break;
513fe6060f1SDimitry Andric case ISD::SRL:
514fe6060f1SDimitry Andric Victim = DAG.getNode(AVRISD::LSRWN, dl, VT, Victim,
515fe6060f1SDimitry Andric DAG.getConstant(12, dl, VT));
516fe6060f1SDimitry Andric ShiftAmount -= 12;
51704eeddc0SDimitry Andric // Only operate on the lower byte for remaining shift bits.
51804eeddc0SDimitry Andric Opc8 = AVRISD::LSRLO;
51904eeddc0SDimitry Andric break;
52004eeddc0SDimitry Andric case ISD::SRA:
52104eeddc0SDimitry Andric Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim,
52204eeddc0SDimitry Andric DAG.getConstant(8, dl, VT));
52304eeddc0SDimitry Andric ShiftAmount -= 8;
52404eeddc0SDimitry Andric // Only operate on the lower byte for remaining shift bits.
52504eeddc0SDimitry Andric Opc8 = AVRISD::ASRLO;
526fe6060f1SDimitry Andric break;
527fe6060f1SDimitry Andric default:
528fe6060f1SDimitry Andric break;
529fe6060f1SDimitry Andric }
530e8d8bef9SDimitry Andric }
531e8d8bef9SDimitry Andric
5320b57cec5SDimitry Andric while (ShiftAmount--) {
5330b57cec5SDimitry Andric Victim = DAG.getNode(Opc8, dl, VT, Victim);
5340b57cec5SDimitry Andric }
5350b57cec5SDimitry Andric
5360b57cec5SDimitry Andric return Victim;
5370b57cec5SDimitry Andric }
5380b57cec5SDimitry Andric
LowerDivRem(SDValue Op,SelectionDAG & DAG) const5390b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerDivRem(SDValue Op, SelectionDAG &DAG) const {
5400b57cec5SDimitry Andric unsigned Opcode = Op->getOpcode();
5410b57cec5SDimitry Andric assert((Opcode == ISD::SDIVREM || Opcode == ISD::UDIVREM) &&
5420b57cec5SDimitry Andric "Invalid opcode for Div/Rem lowering");
5430b57cec5SDimitry Andric bool IsSigned = (Opcode == ISD::SDIVREM);
5440b57cec5SDimitry Andric EVT VT = Op->getValueType(0);
5450b57cec5SDimitry Andric Type *Ty = VT.getTypeForEVT(*DAG.getContext());
5460b57cec5SDimitry Andric
5470b57cec5SDimitry Andric RTLIB::Libcall LC;
5480b57cec5SDimitry Andric switch (VT.getSimpleVT().SimpleTy) {
5490b57cec5SDimitry Andric default:
5500b57cec5SDimitry Andric llvm_unreachable("Unexpected request for libcall!");
5510b57cec5SDimitry Andric case MVT::i8:
5520b57cec5SDimitry Andric LC = IsSigned ? RTLIB::SDIVREM_I8 : RTLIB::UDIVREM_I8;
5530b57cec5SDimitry Andric break;
5540b57cec5SDimitry Andric case MVT::i16:
5550b57cec5SDimitry Andric LC = IsSigned ? RTLIB::SDIVREM_I16 : RTLIB::UDIVREM_I16;
5560b57cec5SDimitry Andric break;
5570b57cec5SDimitry Andric case MVT::i32:
5580b57cec5SDimitry Andric LC = IsSigned ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
5590b57cec5SDimitry Andric break;
5600b57cec5SDimitry Andric }
5610b57cec5SDimitry Andric
5620b57cec5SDimitry Andric SDValue InChain = DAG.getEntryNode();
5630b57cec5SDimitry Andric
5640b57cec5SDimitry Andric TargetLowering::ArgListTy Args;
5650b57cec5SDimitry Andric TargetLowering::ArgListEntry Entry;
5660b57cec5SDimitry Andric for (SDValue const &Value : Op->op_values()) {
5670b57cec5SDimitry Andric Entry.Node = Value;
5680b57cec5SDimitry Andric Entry.Ty = Value.getValueType().getTypeForEVT(*DAG.getContext());
5690b57cec5SDimitry Andric Entry.IsSExt = IsSigned;
5700b57cec5SDimitry Andric Entry.IsZExt = !IsSigned;
5710b57cec5SDimitry Andric Args.push_back(Entry);
5720b57cec5SDimitry Andric }
5730b57cec5SDimitry Andric
5740b57cec5SDimitry Andric SDValue Callee = DAG.getExternalSymbol(getLibcallName(LC),
5750b57cec5SDimitry Andric getPointerTy(DAG.getDataLayout()));
5760b57cec5SDimitry Andric
5770b57cec5SDimitry Andric Type *RetTy = (Type *)StructType::get(Ty, Ty);
5780b57cec5SDimitry Andric
5790b57cec5SDimitry Andric SDLoc dl(Op);
5800b57cec5SDimitry Andric TargetLowering::CallLoweringInfo CLI(DAG);
5810b57cec5SDimitry Andric CLI.setDebugLoc(dl)
5820b57cec5SDimitry Andric .setChain(InChain)
5830b57cec5SDimitry Andric .setLibCallee(getLibcallCallingConv(LC), RetTy, Callee, std::move(Args))
5840b57cec5SDimitry Andric .setInRegister()
5850b57cec5SDimitry Andric .setSExtResult(IsSigned)
5860b57cec5SDimitry Andric .setZExtResult(!IsSigned);
5870b57cec5SDimitry Andric
5880b57cec5SDimitry Andric std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI);
5890b57cec5SDimitry Andric return CallInfo.first;
5900b57cec5SDimitry Andric }
5910b57cec5SDimitry Andric
LowerGlobalAddress(SDValue Op,SelectionDAG & DAG) const5920b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerGlobalAddress(SDValue Op,
5930b57cec5SDimitry Andric SelectionDAG &DAG) const {
5940b57cec5SDimitry Andric auto DL = DAG.getDataLayout();
5950b57cec5SDimitry Andric
5960b57cec5SDimitry Andric const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
5970b57cec5SDimitry Andric int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset();
5980b57cec5SDimitry Andric
5990b57cec5SDimitry Andric // Create the TargetGlobalAddress node, folding in the constant offset.
6000b57cec5SDimitry Andric SDValue Result =
6010b57cec5SDimitry Andric DAG.getTargetGlobalAddress(GV, SDLoc(Op), getPointerTy(DL), Offset);
6020b57cec5SDimitry Andric return DAG.getNode(AVRISD::WRAPPER, SDLoc(Op), getPointerTy(DL), Result);
6030b57cec5SDimitry Andric }
6040b57cec5SDimitry Andric
LowerBlockAddress(SDValue Op,SelectionDAG & DAG) const6050b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerBlockAddress(SDValue Op,
6060b57cec5SDimitry Andric SelectionDAG &DAG) const {
6070b57cec5SDimitry Andric auto DL = DAG.getDataLayout();
6080b57cec5SDimitry Andric const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
6090b57cec5SDimitry Andric
6100b57cec5SDimitry Andric SDValue Result = DAG.getTargetBlockAddress(BA, getPointerTy(DL));
6110b57cec5SDimitry Andric
6120b57cec5SDimitry Andric return DAG.getNode(AVRISD::WRAPPER, SDLoc(Op), getPointerTy(DL), Result);
6130b57cec5SDimitry Andric }
6140b57cec5SDimitry Andric
6150b57cec5SDimitry Andric /// IntCCToAVRCC - Convert a DAG integer condition code to an AVR CC.
intCCToAVRCC(ISD::CondCode CC)6160b57cec5SDimitry Andric static AVRCC::CondCodes intCCToAVRCC(ISD::CondCode CC) {
6170b57cec5SDimitry Andric switch (CC) {
6180b57cec5SDimitry Andric default:
6190b57cec5SDimitry Andric llvm_unreachable("Unknown condition code!");
6200b57cec5SDimitry Andric case ISD::SETEQ:
6210b57cec5SDimitry Andric return AVRCC::COND_EQ;
6220b57cec5SDimitry Andric case ISD::SETNE:
6230b57cec5SDimitry Andric return AVRCC::COND_NE;
6240b57cec5SDimitry Andric case ISD::SETGE:
6250b57cec5SDimitry Andric return AVRCC::COND_GE;
6260b57cec5SDimitry Andric case ISD::SETLT:
6270b57cec5SDimitry Andric return AVRCC::COND_LT;
6280b57cec5SDimitry Andric case ISD::SETUGE:
6290b57cec5SDimitry Andric return AVRCC::COND_SH;
6300b57cec5SDimitry Andric case ISD::SETULT:
6310b57cec5SDimitry Andric return AVRCC::COND_LO;
6320b57cec5SDimitry Andric }
6330b57cec5SDimitry Andric }
6340b57cec5SDimitry Andric
635e8d8bef9SDimitry Andric /// Returns appropriate CP/CPI/CPC nodes code for the given 8/16-bit operands.
getAVRCmp(SDValue LHS,SDValue RHS,SelectionDAG & DAG,SDLoc DL) const636e8d8bef9SDimitry Andric SDValue AVRTargetLowering::getAVRCmp(SDValue LHS, SDValue RHS,
637e8d8bef9SDimitry Andric SelectionDAG &DAG, SDLoc DL) const {
638e8d8bef9SDimitry Andric assert((LHS.getSimpleValueType() == RHS.getSimpleValueType()) &&
639e8d8bef9SDimitry Andric "LHS and RHS have different types");
640e8d8bef9SDimitry Andric assert(((LHS.getSimpleValueType() == MVT::i16) ||
641349cc55cSDimitry Andric (LHS.getSimpleValueType() == MVT::i8)) &&
642349cc55cSDimitry Andric "invalid comparison type");
643e8d8bef9SDimitry Andric
644e8d8bef9SDimitry Andric SDValue Cmp;
645e8d8bef9SDimitry Andric
646fe6060f1SDimitry Andric if (LHS.getSimpleValueType() == MVT::i16 && isa<ConstantSDNode>(RHS)) {
6471db9f3b2SDimitry Andric uint64_t Imm = RHS->getAsZExtVal();
64806c3fb27SDimitry Andric // Generate a CPI/CPC pair if RHS is a 16-bit constant. Use the zero
64906c3fb27SDimitry Andric // register for the constant RHS if its lower or higher byte is zero.
650e8d8bef9SDimitry Andric SDValue LHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHS,
651e8d8bef9SDimitry Andric DAG.getIntPtrConstant(0, DL));
652e8d8bef9SDimitry Andric SDValue LHShi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHS,
653e8d8bef9SDimitry Andric DAG.getIntPtrConstant(1, DL));
65406c3fb27SDimitry Andric SDValue RHSlo = (Imm & 0xff) == 0
65506c3fb27SDimitry Andric ? DAG.getRegister(Subtarget.getZeroRegister(), MVT::i8)
65606c3fb27SDimitry Andric : DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, RHS,
65706c3fb27SDimitry Andric DAG.getIntPtrConstant(0, DL));
65806c3fb27SDimitry Andric SDValue RHShi = (Imm & 0xff00) == 0
65906c3fb27SDimitry Andric ? DAG.getRegister(Subtarget.getZeroRegister(), MVT::i8)
66006c3fb27SDimitry Andric : DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, RHS,
66106c3fb27SDimitry Andric DAG.getIntPtrConstant(1, DL));
66206c3fb27SDimitry Andric Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHSlo, RHSlo);
66306c3fb27SDimitry Andric Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHShi, RHShi, Cmp);
66406c3fb27SDimitry Andric } else if (RHS.getSimpleValueType() == MVT::i16 && isa<ConstantSDNode>(LHS)) {
66506c3fb27SDimitry Andric // Generate a CPI/CPC pair if LHS is a 16-bit constant. Use the zero
66606c3fb27SDimitry Andric // register for the constant LHS if its lower or higher byte is zero.
6671db9f3b2SDimitry Andric uint64_t Imm = LHS->getAsZExtVal();
66806c3fb27SDimitry Andric SDValue LHSlo = (Imm & 0xff) == 0
66906c3fb27SDimitry Andric ? DAG.getRegister(Subtarget.getZeroRegister(), MVT::i8)
67006c3fb27SDimitry Andric : DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHS,
67106c3fb27SDimitry Andric DAG.getIntPtrConstant(0, DL));
67206c3fb27SDimitry Andric SDValue LHShi = (Imm & 0xff00) == 0
67306c3fb27SDimitry Andric ? DAG.getRegister(Subtarget.getZeroRegister(), MVT::i8)
67406c3fb27SDimitry Andric : DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHS,
67506c3fb27SDimitry Andric DAG.getIntPtrConstant(1, DL));
676e8d8bef9SDimitry Andric SDValue RHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, RHS,
677e8d8bef9SDimitry Andric DAG.getIntPtrConstant(0, DL));
678e8d8bef9SDimitry Andric SDValue RHShi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, RHS,
679e8d8bef9SDimitry Andric DAG.getIntPtrConstant(1, DL));
680e8d8bef9SDimitry Andric Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHSlo, RHSlo);
681e8d8bef9SDimitry Andric Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHShi, RHShi, Cmp);
682e8d8bef9SDimitry Andric } else {
683e8d8bef9SDimitry Andric // Generate ordinary 16-bit comparison.
684e8d8bef9SDimitry Andric Cmp = DAG.getNode(AVRISD::CMP, DL, MVT::Glue, LHS, RHS);
685e8d8bef9SDimitry Andric }
686e8d8bef9SDimitry Andric
687e8d8bef9SDimitry Andric return Cmp;
688e8d8bef9SDimitry Andric }
689e8d8bef9SDimitry Andric
6900b57cec5SDimitry Andric /// Returns appropriate AVR CMP/CMPC nodes and corresponding condition code for
6910b57cec5SDimitry Andric /// the given operands.
getAVRCmp(SDValue LHS,SDValue RHS,ISD::CondCode CC,SDValue & AVRcc,SelectionDAG & DAG,SDLoc DL) const6920b57cec5SDimitry Andric SDValue AVRTargetLowering::getAVRCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
6930b57cec5SDimitry Andric SDValue &AVRcc, SelectionDAG &DAG,
6940b57cec5SDimitry Andric SDLoc DL) const {
6950b57cec5SDimitry Andric SDValue Cmp;
6960b57cec5SDimitry Andric EVT VT = LHS.getValueType();
6970b57cec5SDimitry Andric bool UseTest = false;
6980b57cec5SDimitry Andric
6990b57cec5SDimitry Andric switch (CC) {
7000b57cec5SDimitry Andric default:
7010b57cec5SDimitry Andric break;
7020b57cec5SDimitry Andric case ISD::SETLE: {
7030b57cec5SDimitry Andric // Swap operands and reverse the branching condition.
7040b57cec5SDimitry Andric std::swap(LHS, RHS);
7050b57cec5SDimitry Andric CC = ISD::SETGE;
7060b57cec5SDimitry Andric break;
7070b57cec5SDimitry Andric }
7080b57cec5SDimitry Andric case ISD::SETGT: {
7090b57cec5SDimitry Andric if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
7100b57cec5SDimitry Andric switch (C->getSExtValue()) {
7110b57cec5SDimitry Andric case -1: {
7120b57cec5SDimitry Andric // When doing lhs > -1 use a tst instruction on the top part of lhs
7130b57cec5SDimitry Andric // and use brpl instead of using a chain of cp/cpc.
7140b57cec5SDimitry Andric UseTest = true;
7150b57cec5SDimitry Andric AVRcc = DAG.getConstant(AVRCC::COND_PL, DL, MVT::i8);
7160b57cec5SDimitry Andric break;
7170b57cec5SDimitry Andric }
7180b57cec5SDimitry Andric case 0: {
7190b57cec5SDimitry Andric // Turn lhs > 0 into 0 < lhs since 0 can be materialized with
7200b57cec5SDimitry Andric // __zero_reg__ in lhs.
7210b57cec5SDimitry Andric RHS = LHS;
7220b57cec5SDimitry Andric LHS = DAG.getConstant(0, DL, VT);
7230b57cec5SDimitry Andric CC = ISD::SETLT;
7240b57cec5SDimitry Andric break;
7250b57cec5SDimitry Andric }
7260b57cec5SDimitry Andric default: {
7270b57cec5SDimitry Andric // Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows
7280b57cec5SDimitry Andric // us to fold the constant into the cmp instruction.
7290b57cec5SDimitry Andric RHS = DAG.getConstant(C->getSExtValue() + 1, DL, VT);
7300b57cec5SDimitry Andric CC = ISD::SETGE;
7310b57cec5SDimitry Andric break;
7320b57cec5SDimitry Andric }
7330b57cec5SDimitry Andric }
7340b57cec5SDimitry Andric break;
7350b57cec5SDimitry Andric }
7360b57cec5SDimitry Andric // Swap operands and reverse the branching condition.
7370b57cec5SDimitry Andric std::swap(LHS, RHS);
7380b57cec5SDimitry Andric CC = ISD::SETLT;
7390b57cec5SDimitry Andric break;
7400b57cec5SDimitry Andric }
7410b57cec5SDimitry Andric case ISD::SETLT: {
7420b57cec5SDimitry Andric if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
7430b57cec5SDimitry Andric switch (C->getSExtValue()) {
7440b57cec5SDimitry Andric case 1: {
7450b57cec5SDimitry Andric // Turn lhs < 1 into 0 >= lhs since 0 can be materialized with
7460b57cec5SDimitry Andric // __zero_reg__ in lhs.
7470b57cec5SDimitry Andric RHS = LHS;
7480b57cec5SDimitry Andric LHS = DAG.getConstant(0, DL, VT);
7490b57cec5SDimitry Andric CC = ISD::SETGE;
7500b57cec5SDimitry Andric break;
7510b57cec5SDimitry Andric }
7520b57cec5SDimitry Andric case 0: {
7530b57cec5SDimitry Andric // When doing lhs < 0 use a tst instruction on the top part of lhs
7540b57cec5SDimitry Andric // and use brmi instead of using a chain of cp/cpc.
7550b57cec5SDimitry Andric UseTest = true;
7560b57cec5SDimitry Andric AVRcc = DAG.getConstant(AVRCC::COND_MI, DL, MVT::i8);
7570b57cec5SDimitry Andric break;
7580b57cec5SDimitry Andric }
7590b57cec5SDimitry Andric }
7600b57cec5SDimitry Andric }
7610b57cec5SDimitry Andric break;
7620b57cec5SDimitry Andric }
7630b57cec5SDimitry Andric case ISD::SETULE: {
7640b57cec5SDimitry Andric // Swap operands and reverse the branching condition.
7650b57cec5SDimitry Andric std::swap(LHS, RHS);
7660b57cec5SDimitry Andric CC = ISD::SETUGE;
7670b57cec5SDimitry Andric break;
7680b57cec5SDimitry Andric }
7690b57cec5SDimitry Andric case ISD::SETUGT: {
7700b57cec5SDimitry Andric // Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows us to
7710b57cec5SDimitry Andric // fold the constant into the cmp instruction.
7720b57cec5SDimitry Andric if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
7730b57cec5SDimitry Andric RHS = DAG.getConstant(C->getSExtValue() + 1, DL, VT);
7740b57cec5SDimitry Andric CC = ISD::SETUGE;
7750b57cec5SDimitry Andric break;
7760b57cec5SDimitry Andric }
7770b57cec5SDimitry Andric // Swap operands and reverse the branching condition.
7780b57cec5SDimitry Andric std::swap(LHS, RHS);
7790b57cec5SDimitry Andric CC = ISD::SETULT;
7800b57cec5SDimitry Andric break;
7810b57cec5SDimitry Andric }
7820b57cec5SDimitry Andric }
7830b57cec5SDimitry Andric
7840b57cec5SDimitry Andric // Expand 32 and 64 bit comparisons with custom CMP and CMPC nodes instead of
7850b57cec5SDimitry Andric // using the default and/or/xor expansion code which is much longer.
7860b57cec5SDimitry Andric if (VT == MVT::i32) {
7870b57cec5SDimitry Andric SDValue LHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS,
7880b57cec5SDimitry Andric DAG.getIntPtrConstant(0, DL));
7890b57cec5SDimitry Andric SDValue LHShi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS,
7900b57cec5SDimitry Andric DAG.getIntPtrConstant(1, DL));
7910b57cec5SDimitry Andric SDValue RHSlo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS,
7920b57cec5SDimitry Andric DAG.getIntPtrConstant(0, DL));
7930b57cec5SDimitry Andric SDValue RHShi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS,
7940b57cec5SDimitry Andric DAG.getIntPtrConstant(1, DL));
7950b57cec5SDimitry Andric
7960b57cec5SDimitry Andric if (UseTest) {
7970b57cec5SDimitry Andric // When using tst we only care about the highest part.
7980b57cec5SDimitry Andric SDValue Top = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHShi,
7990b57cec5SDimitry Andric DAG.getIntPtrConstant(1, DL));
8000b57cec5SDimitry Andric Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue, Top);
8010b57cec5SDimitry Andric } else {
802e8d8bef9SDimitry Andric Cmp = getAVRCmp(LHSlo, RHSlo, DAG, DL);
8030b57cec5SDimitry Andric Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHShi, RHShi, Cmp);
8040b57cec5SDimitry Andric }
8050b57cec5SDimitry Andric } else if (VT == MVT::i64) {
8060b57cec5SDimitry Andric SDValue LHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, LHS,
8070b57cec5SDimitry Andric DAG.getIntPtrConstant(0, DL));
8080b57cec5SDimitry Andric SDValue LHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, LHS,
8090b57cec5SDimitry Andric DAG.getIntPtrConstant(1, DL));
8100b57cec5SDimitry Andric
8110b57cec5SDimitry Andric SDValue LHS0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_0,
8120b57cec5SDimitry Andric DAG.getIntPtrConstant(0, DL));
8130b57cec5SDimitry Andric SDValue LHS1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_0,
8140b57cec5SDimitry Andric DAG.getIntPtrConstant(1, DL));
8150b57cec5SDimitry Andric SDValue LHS2 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_1,
8160b57cec5SDimitry Andric DAG.getIntPtrConstant(0, DL));
8170b57cec5SDimitry Andric SDValue LHS3 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, LHS_1,
8180b57cec5SDimitry Andric DAG.getIntPtrConstant(1, DL));
8190b57cec5SDimitry Andric
8200b57cec5SDimitry Andric SDValue RHS_0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, RHS,
8210b57cec5SDimitry Andric DAG.getIntPtrConstant(0, DL));
8220b57cec5SDimitry Andric SDValue RHS_1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, RHS,
8230b57cec5SDimitry Andric DAG.getIntPtrConstant(1, DL));
8240b57cec5SDimitry Andric
8250b57cec5SDimitry Andric SDValue RHS0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_0,
8260b57cec5SDimitry Andric DAG.getIntPtrConstant(0, DL));
8270b57cec5SDimitry Andric SDValue RHS1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_0,
8280b57cec5SDimitry Andric DAG.getIntPtrConstant(1, DL));
8290b57cec5SDimitry Andric SDValue RHS2 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_1,
8300b57cec5SDimitry Andric DAG.getIntPtrConstant(0, DL));
8310b57cec5SDimitry Andric SDValue RHS3 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i16, RHS_1,
8320b57cec5SDimitry Andric DAG.getIntPtrConstant(1, DL));
8330b57cec5SDimitry Andric
8340b57cec5SDimitry Andric if (UseTest) {
8350b57cec5SDimitry Andric // When using tst we only care about the highest part.
8360b57cec5SDimitry Andric SDValue Top = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8, LHS3,
8370b57cec5SDimitry Andric DAG.getIntPtrConstant(1, DL));
8380b57cec5SDimitry Andric Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue, Top);
8390b57cec5SDimitry Andric } else {
840e8d8bef9SDimitry Andric Cmp = getAVRCmp(LHS0, RHS0, DAG, DL);
8410b57cec5SDimitry Andric Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS1, RHS1, Cmp);
8420b57cec5SDimitry Andric Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS2, RHS2, Cmp);
8430b57cec5SDimitry Andric Cmp = DAG.getNode(AVRISD::CMPC, DL, MVT::Glue, LHS3, RHS3, Cmp);
8440b57cec5SDimitry Andric }
8450b57cec5SDimitry Andric } else if (VT == MVT::i8 || VT == MVT::i16) {
8460b57cec5SDimitry Andric if (UseTest) {
8470b57cec5SDimitry Andric // When using tst we only care about the highest part.
8480b57cec5SDimitry Andric Cmp = DAG.getNode(AVRISD::TST, DL, MVT::Glue,
8490b57cec5SDimitry Andric (VT == MVT::i8)
8500b57cec5SDimitry Andric ? LHS
8510b57cec5SDimitry Andric : DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i8,
8520b57cec5SDimitry Andric LHS, DAG.getIntPtrConstant(1, DL)));
8530b57cec5SDimitry Andric } else {
854e8d8bef9SDimitry Andric Cmp = getAVRCmp(LHS, RHS, DAG, DL);
8550b57cec5SDimitry Andric }
8560b57cec5SDimitry Andric } else {
8570b57cec5SDimitry Andric llvm_unreachable("Invalid comparison size");
8580b57cec5SDimitry Andric }
8590b57cec5SDimitry Andric
8600b57cec5SDimitry Andric // When using a test instruction AVRcc is already set.
8610b57cec5SDimitry Andric if (!UseTest) {
8620b57cec5SDimitry Andric AVRcc = DAG.getConstant(intCCToAVRCC(CC), DL, MVT::i8);
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric
8650b57cec5SDimitry Andric return Cmp;
8660b57cec5SDimitry Andric }
8670b57cec5SDimitry Andric
LowerBR_CC(SDValue Op,SelectionDAG & DAG) const8680b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
8690b57cec5SDimitry Andric SDValue Chain = Op.getOperand(0);
8700b57cec5SDimitry Andric ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
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 SDValue TargetCC;
8770b57cec5SDimitry Andric SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, dl);
8780b57cec5SDimitry Andric
8790b57cec5SDimitry Andric return DAG.getNode(AVRISD::BRCOND, dl, MVT::Other, Chain, Dest, TargetCC,
8800b57cec5SDimitry Andric Cmp);
8810b57cec5SDimitry Andric }
8820b57cec5SDimitry Andric
LowerSELECT_CC(SDValue Op,SelectionDAG & DAG) const8830b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
8840b57cec5SDimitry Andric SDValue LHS = Op.getOperand(0);
8850b57cec5SDimitry Andric SDValue RHS = Op.getOperand(1);
8860b57cec5SDimitry Andric SDValue TrueV = Op.getOperand(2);
8870b57cec5SDimitry Andric SDValue FalseV = Op.getOperand(3);
8880b57cec5SDimitry Andric ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
8890b57cec5SDimitry Andric SDLoc dl(Op);
8900b57cec5SDimitry Andric
8910b57cec5SDimitry Andric SDValue TargetCC;
8920b57cec5SDimitry Andric SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, dl);
8930b57cec5SDimitry Andric
8940b57cec5SDimitry Andric SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
8950b57cec5SDimitry Andric SDValue Ops[] = {TrueV, FalseV, TargetCC, Cmp};
8960b57cec5SDimitry Andric
8970b57cec5SDimitry Andric return DAG.getNode(AVRISD::SELECT_CC, dl, VTs, Ops);
8980b57cec5SDimitry Andric }
8990b57cec5SDimitry Andric
LowerSETCC(SDValue Op,SelectionDAG & DAG) const9000b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
9010b57cec5SDimitry Andric SDValue LHS = Op.getOperand(0);
9020b57cec5SDimitry Andric SDValue RHS = Op.getOperand(1);
9030b57cec5SDimitry Andric ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
9040b57cec5SDimitry Andric SDLoc DL(Op);
9050b57cec5SDimitry Andric
9060b57cec5SDimitry Andric SDValue TargetCC;
9070b57cec5SDimitry Andric SDValue Cmp = getAVRCmp(LHS, RHS, CC, TargetCC, DAG, DL);
9080b57cec5SDimitry Andric
9090b57cec5SDimitry Andric SDValue TrueV = DAG.getConstant(1, DL, Op.getValueType());
9100b57cec5SDimitry Andric SDValue FalseV = DAG.getConstant(0, DL, Op.getValueType());
9110b57cec5SDimitry Andric SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
9120b57cec5SDimitry Andric SDValue Ops[] = {TrueV, FalseV, TargetCC, Cmp};
9130b57cec5SDimitry Andric
9140b57cec5SDimitry Andric return DAG.getNode(AVRISD::SELECT_CC, DL, VTs, Ops);
9150b57cec5SDimitry Andric }
9160b57cec5SDimitry Andric
LowerVASTART(SDValue Op,SelectionDAG & DAG) const9170b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
9180b57cec5SDimitry Andric const MachineFunction &MF = DAG.getMachineFunction();
9190b57cec5SDimitry Andric const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
9200b57cec5SDimitry Andric const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
9210b57cec5SDimitry Andric auto DL = DAG.getDataLayout();
9220b57cec5SDimitry Andric SDLoc dl(Op);
9230b57cec5SDimitry Andric
9240b57cec5SDimitry Andric // Vastart just stores the address of the VarArgsFrameIndex slot into the
9250b57cec5SDimitry Andric // memory location argument.
9260b57cec5SDimitry Andric SDValue FI = DAG.getFrameIndex(AFI->getVarArgsFrameIndex(), getPointerTy(DL));
9270b57cec5SDimitry Andric
9280b57cec5SDimitry Andric return DAG.getStore(Op.getOperand(0), dl, FI, Op.getOperand(1),
929e8d8bef9SDimitry Andric MachinePointerInfo(SV));
9300b57cec5SDimitry Andric }
9310b57cec5SDimitry Andric
932bdd1243dSDimitry Andric // Modify the existing ISD::INLINEASM node to add the implicit zero register.
LowerINLINEASM(SDValue Op,SelectionDAG & DAG) const933bdd1243dSDimitry Andric SDValue AVRTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
934bdd1243dSDimitry Andric SDValue ZeroReg = DAG.getRegister(Subtarget.getZeroRegister(), MVT::i8);
935bdd1243dSDimitry Andric if (Op.getOperand(Op.getNumOperands() - 1) == ZeroReg ||
936bdd1243dSDimitry Andric Op.getOperand(Op.getNumOperands() - 2) == ZeroReg) {
937bdd1243dSDimitry Andric // Zero register has already been added. Don't add it again.
938bdd1243dSDimitry Andric // If this isn't handled, we get called over and over again.
939bdd1243dSDimitry Andric return Op;
940bdd1243dSDimitry Andric }
941bdd1243dSDimitry Andric
942bdd1243dSDimitry Andric // Get a list of operands to the new INLINEASM node. This is mostly a copy,
943bdd1243dSDimitry Andric // with some edits.
944bdd1243dSDimitry Andric // Add the following operands at the end (but before the glue node, if it's
945bdd1243dSDimitry Andric // there):
946bdd1243dSDimitry Andric // - The flags of the implicit zero register operand.
947bdd1243dSDimitry Andric // - The implicit zero register operand itself.
948bdd1243dSDimitry Andric SDLoc dl(Op);
949bdd1243dSDimitry Andric SmallVector<SDValue, 8> Ops;
950bdd1243dSDimitry Andric SDNode *N = Op.getNode();
951bdd1243dSDimitry Andric SDValue Glue;
952bdd1243dSDimitry Andric for (unsigned I = 0; I < N->getNumOperands(); I++) {
953bdd1243dSDimitry Andric SDValue Operand = N->getOperand(I);
954bdd1243dSDimitry Andric if (Operand.getValueType() == MVT::Glue) {
955bdd1243dSDimitry Andric // The glue operand always needs to be at the end, so we need to treat it
956bdd1243dSDimitry Andric // specially.
957bdd1243dSDimitry Andric Glue = Operand;
958bdd1243dSDimitry Andric } else {
959bdd1243dSDimitry Andric Ops.push_back(Operand);
960bdd1243dSDimitry Andric }
961bdd1243dSDimitry Andric }
9625f757f3fSDimitry Andric InlineAsm::Flag Flags(InlineAsm::Kind::RegUse, 1);
963bdd1243dSDimitry Andric Ops.push_back(DAG.getTargetConstant(Flags, dl, MVT::i32));
964bdd1243dSDimitry Andric Ops.push_back(ZeroReg);
965bdd1243dSDimitry Andric if (Glue) {
966bdd1243dSDimitry Andric Ops.push_back(Glue);
967bdd1243dSDimitry Andric }
968bdd1243dSDimitry Andric
969bdd1243dSDimitry Andric // Replace the current INLINEASM node with a new one that has the zero
970bdd1243dSDimitry Andric // register as implicit parameter.
971bdd1243dSDimitry Andric SDValue New = DAG.getNode(N->getOpcode(), dl, N->getVTList(), Ops);
972bdd1243dSDimitry Andric DAG.ReplaceAllUsesOfValueWith(Op, New);
973bdd1243dSDimitry Andric DAG.ReplaceAllUsesOfValueWith(Op.getValue(1), New.getValue(1));
974bdd1243dSDimitry Andric
975bdd1243dSDimitry Andric return New;
976bdd1243dSDimitry Andric }
977bdd1243dSDimitry Andric
LowerOperation(SDValue Op,SelectionDAG & DAG) const9780b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
9790b57cec5SDimitry Andric switch (Op.getOpcode()) {
9800b57cec5SDimitry Andric default:
9810b57cec5SDimitry Andric llvm_unreachable("Don't know how to custom lower this!");
9820b57cec5SDimitry Andric case ISD::SHL:
9830b57cec5SDimitry Andric case ISD::SRA:
9840b57cec5SDimitry Andric case ISD::SRL:
9850b57cec5SDimitry Andric case ISD::ROTL:
9860b57cec5SDimitry Andric case ISD::ROTR:
9870b57cec5SDimitry Andric return LowerShifts(Op, DAG);
9880b57cec5SDimitry Andric case ISD::GlobalAddress:
9890b57cec5SDimitry Andric return LowerGlobalAddress(Op, DAG);
9900b57cec5SDimitry Andric case ISD::BlockAddress:
9910b57cec5SDimitry Andric return LowerBlockAddress(Op, DAG);
9920b57cec5SDimitry Andric case ISD::BR_CC:
9930b57cec5SDimitry Andric return LowerBR_CC(Op, DAG);
9940b57cec5SDimitry Andric case ISD::SELECT_CC:
9950b57cec5SDimitry Andric return LowerSELECT_CC(Op, DAG);
9960b57cec5SDimitry Andric case ISD::SETCC:
9970b57cec5SDimitry Andric return LowerSETCC(Op, DAG);
9980b57cec5SDimitry Andric case ISD::VASTART:
9990b57cec5SDimitry Andric return LowerVASTART(Op, DAG);
10000b57cec5SDimitry Andric case ISD::SDIVREM:
10010b57cec5SDimitry Andric case ISD::UDIVREM:
10020b57cec5SDimitry Andric return LowerDivRem(Op, DAG);
1003bdd1243dSDimitry Andric case ISD::INLINEASM:
1004bdd1243dSDimitry Andric return LowerINLINEASM(Op, DAG);
10050b57cec5SDimitry Andric }
10060b57cec5SDimitry Andric
10070b57cec5SDimitry Andric return SDValue();
10080b57cec5SDimitry Andric }
10090b57cec5SDimitry Andric
10100b57cec5SDimitry Andric /// Replace a node with an illegal result type
10110b57cec5SDimitry Andric /// with a new node built out of custom code.
ReplaceNodeResults(SDNode * N,SmallVectorImpl<SDValue> & Results,SelectionDAG & DAG) const10120b57cec5SDimitry Andric void AVRTargetLowering::ReplaceNodeResults(SDNode *N,
10130b57cec5SDimitry Andric SmallVectorImpl<SDValue> &Results,
10140b57cec5SDimitry Andric SelectionDAG &DAG) const {
10150b57cec5SDimitry Andric SDLoc DL(N);
10160b57cec5SDimitry Andric
10170b57cec5SDimitry Andric switch (N->getOpcode()) {
10180b57cec5SDimitry Andric case ISD::ADD: {
10190b57cec5SDimitry Andric // Convert add (x, imm) into sub (x, -imm).
10200b57cec5SDimitry Andric if (const ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
10210b57cec5SDimitry Andric SDValue Sub = DAG.getNode(
10220b57cec5SDimitry Andric ISD::SUB, DL, N->getValueType(0), N->getOperand(0),
10230b57cec5SDimitry Andric DAG.getConstant(-C->getAPIntValue(), DL, C->getValueType(0)));
10240b57cec5SDimitry Andric Results.push_back(Sub);
10250b57cec5SDimitry Andric }
10260b57cec5SDimitry Andric break;
10270b57cec5SDimitry Andric }
10280b57cec5SDimitry Andric default: {
10290b57cec5SDimitry Andric SDValue Res = LowerOperation(SDValue(N, 0), DAG);
10300b57cec5SDimitry Andric
10310b57cec5SDimitry Andric for (unsigned I = 0, E = Res->getNumValues(); I != E; ++I)
10320b57cec5SDimitry Andric Results.push_back(Res.getValue(I));
10330b57cec5SDimitry Andric
10340b57cec5SDimitry Andric break;
10350b57cec5SDimitry Andric }
10360b57cec5SDimitry Andric }
10370b57cec5SDimitry Andric }
10380b57cec5SDimitry Andric
10390b57cec5SDimitry Andric /// Return true if the addressing mode represented
10400b57cec5SDimitry Andric /// by AM is legal for this target, for a load/store of the specified type.
isLegalAddressingMode(const DataLayout & DL,const AddrMode & AM,Type * Ty,unsigned AS,Instruction * I) const10410b57cec5SDimitry Andric bool AVRTargetLowering::isLegalAddressingMode(const DataLayout &DL,
10420b57cec5SDimitry Andric const AddrMode &AM, Type *Ty,
1043349cc55cSDimitry Andric unsigned AS,
1044349cc55cSDimitry Andric Instruction *I) const {
10450b57cec5SDimitry Andric int64_t Offs = AM.BaseOffs;
10460b57cec5SDimitry Andric
10470b57cec5SDimitry Andric // Allow absolute addresses.
10480b57cec5SDimitry Andric if (AM.BaseGV && !AM.HasBaseReg && AM.Scale == 0 && Offs == 0) {
10490b57cec5SDimitry Andric return true;
10500b57cec5SDimitry Andric }
10510b57cec5SDimitry Andric
10520b57cec5SDimitry Andric // Flash memory instructions only allow zero offsets.
10530b57cec5SDimitry Andric if (isa<PointerType>(Ty) && AS == AVR::ProgramMemory) {
10540b57cec5SDimitry Andric return false;
10550b57cec5SDimitry Andric }
10560b57cec5SDimitry Andric
10570b57cec5SDimitry Andric // Allow reg+<6bit> offset.
10580b57cec5SDimitry Andric if (Offs < 0)
10590b57cec5SDimitry Andric Offs = -Offs;
106004eeddc0SDimitry Andric if (AM.BaseGV == nullptr && AM.HasBaseReg && AM.Scale == 0 &&
106104eeddc0SDimitry Andric isUInt<6>(Offs)) {
10620b57cec5SDimitry Andric return true;
10630b57cec5SDimitry Andric }
10640b57cec5SDimitry Andric
10650b57cec5SDimitry Andric return false;
10660b57cec5SDimitry Andric }
10670b57cec5SDimitry Andric
10680b57cec5SDimitry Andric /// Returns true by value, base pointer and
10690b57cec5SDimitry Andric /// offset pointer and addressing mode by reference if the node's address
10700b57cec5SDimitry Andric /// can be legally represented as pre-indexed load / store address.
getPreIndexedAddressParts(SDNode * N,SDValue & Base,SDValue & Offset,ISD::MemIndexedMode & AM,SelectionDAG & DAG) const10710b57cec5SDimitry Andric bool AVRTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base,
10720b57cec5SDimitry Andric SDValue &Offset,
10730b57cec5SDimitry Andric ISD::MemIndexedMode &AM,
10740b57cec5SDimitry Andric SelectionDAG &DAG) const {
10750b57cec5SDimitry Andric EVT VT;
10760b57cec5SDimitry Andric const SDNode *Op;
10770b57cec5SDimitry Andric SDLoc DL(N);
10780b57cec5SDimitry Andric
10790b57cec5SDimitry Andric if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
10800b57cec5SDimitry Andric VT = LD->getMemoryVT();
10810b57cec5SDimitry Andric Op = LD->getBasePtr().getNode();
10820b57cec5SDimitry Andric if (LD->getExtensionType() != ISD::NON_EXTLOAD)
10830b57cec5SDimitry Andric return false;
10840b57cec5SDimitry Andric if (AVR::isProgramMemoryAccess(LD)) {
10850b57cec5SDimitry Andric return false;
10860b57cec5SDimitry Andric }
10870b57cec5SDimitry Andric } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
10880b57cec5SDimitry Andric VT = ST->getMemoryVT();
10890b57cec5SDimitry Andric Op = ST->getBasePtr().getNode();
10900b57cec5SDimitry Andric if (AVR::isProgramMemoryAccess(ST)) {
10910b57cec5SDimitry Andric return false;
10920b57cec5SDimitry Andric }
10930b57cec5SDimitry Andric } else {
10940b57cec5SDimitry Andric return false;
10950b57cec5SDimitry Andric }
10960b57cec5SDimitry Andric
10970b57cec5SDimitry Andric if (VT != MVT::i8 && VT != MVT::i16) {
10980b57cec5SDimitry Andric return false;
10990b57cec5SDimitry Andric }
11000b57cec5SDimitry Andric
11010b57cec5SDimitry Andric if (Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB) {
11020b57cec5SDimitry Andric return false;
11030b57cec5SDimitry Andric }
11040b57cec5SDimitry Andric
11050b57cec5SDimitry Andric if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) {
11060b57cec5SDimitry Andric int RHSC = RHS->getSExtValue();
11070b57cec5SDimitry Andric if (Op->getOpcode() == ISD::SUB)
11080b57cec5SDimitry Andric RHSC = -RHSC;
11090b57cec5SDimitry Andric
11100b57cec5SDimitry Andric if ((VT == MVT::i16 && RHSC != -2) || (VT == MVT::i8 && RHSC != -1)) {
11110b57cec5SDimitry Andric return false;
11120b57cec5SDimitry Andric }
11130b57cec5SDimitry Andric
11140b57cec5SDimitry Andric Base = Op->getOperand(0);
11150b57cec5SDimitry Andric Offset = DAG.getConstant(RHSC, DL, MVT::i8);
11160b57cec5SDimitry Andric AM = ISD::PRE_DEC;
11170b57cec5SDimitry Andric
11180b57cec5SDimitry Andric return true;
11190b57cec5SDimitry Andric }
11200b57cec5SDimitry Andric
11210b57cec5SDimitry Andric return false;
11220b57cec5SDimitry Andric }
11230b57cec5SDimitry Andric
11240b57cec5SDimitry Andric /// Returns true by value, base pointer and
11250b57cec5SDimitry Andric /// offset pointer and addressing mode by reference if this node can be
11260b57cec5SDimitry Andric /// combined with a load / store to form a post-indexed load / store.
getPostIndexedAddressParts(SDNode * N,SDNode * Op,SDValue & Base,SDValue & Offset,ISD::MemIndexedMode & AM,SelectionDAG & DAG) const11270b57cec5SDimitry Andric bool AVRTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
11280b57cec5SDimitry Andric SDValue &Base,
11290b57cec5SDimitry Andric SDValue &Offset,
11300b57cec5SDimitry Andric ISD::MemIndexedMode &AM,
11310b57cec5SDimitry Andric SelectionDAG &DAG) const {
11320b57cec5SDimitry Andric EVT VT;
11330b57cec5SDimitry Andric SDLoc DL(N);
11340b57cec5SDimitry Andric
11350b57cec5SDimitry Andric if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(N)) {
11360b57cec5SDimitry Andric VT = LD->getMemoryVT();
11370b57cec5SDimitry Andric if (LD->getExtensionType() != ISD::NON_EXTLOAD)
11380b57cec5SDimitry Andric return false;
11390b57cec5SDimitry Andric } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) {
11400b57cec5SDimitry Andric VT = ST->getMemoryVT();
114106c3fb27SDimitry Andric // We can not store to program memory.
114206c3fb27SDimitry Andric if (AVR::isProgramMemoryAccess(ST))
11430b57cec5SDimitry Andric return false;
114406c3fb27SDimitry Andric // Since the high byte need to be stored first, we can not emit
114506c3fb27SDimitry Andric // i16 post increment store like:
114606c3fb27SDimitry Andric // st X+, r24
114706c3fb27SDimitry Andric // st X+, r25
114806c3fb27SDimitry Andric if (VT == MVT::i16 && !Subtarget.hasLowByteFirst())
114906c3fb27SDimitry Andric return false;
11500b57cec5SDimitry Andric } else {
11510b57cec5SDimitry Andric return false;
11520b57cec5SDimitry Andric }
11530b57cec5SDimitry Andric
11540b57cec5SDimitry Andric if (VT != MVT::i8 && VT != MVT::i16) {
11550b57cec5SDimitry Andric return false;
11560b57cec5SDimitry Andric }
11570b57cec5SDimitry Andric
11580b57cec5SDimitry Andric if (Op->getOpcode() != ISD::ADD && Op->getOpcode() != ISD::SUB) {
11590b57cec5SDimitry Andric return false;
11600b57cec5SDimitry Andric }
11610b57cec5SDimitry Andric
11620b57cec5SDimitry Andric if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Op->getOperand(1))) {
11630b57cec5SDimitry Andric int RHSC = RHS->getSExtValue();
11640b57cec5SDimitry Andric if (Op->getOpcode() == ISD::SUB)
11650b57cec5SDimitry Andric RHSC = -RHSC;
11660b57cec5SDimitry Andric if ((VT == MVT::i16 && RHSC != 2) || (VT == MVT::i8 && RHSC != 1)) {
11670b57cec5SDimitry Andric return false;
11680b57cec5SDimitry Andric }
11690b57cec5SDimitry Andric
117006c3fb27SDimitry Andric // FIXME: We temporarily disable post increment load from program memory,
117106c3fb27SDimitry Andric // due to bug https://github.com/llvm/llvm-project/issues/59914.
117206c3fb27SDimitry Andric if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(N))
117306c3fb27SDimitry Andric if (AVR::isProgramMemoryAccess(LD))
117406c3fb27SDimitry Andric return false;
117506c3fb27SDimitry Andric
11760b57cec5SDimitry Andric Base = Op->getOperand(0);
11770b57cec5SDimitry Andric Offset = DAG.getConstant(RHSC, DL, MVT::i8);
11780b57cec5SDimitry Andric AM = ISD::POST_INC;
11790b57cec5SDimitry Andric
11800b57cec5SDimitry Andric return true;
11810b57cec5SDimitry Andric }
11820b57cec5SDimitry Andric
11830b57cec5SDimitry Andric return false;
11840b57cec5SDimitry Andric }
11850b57cec5SDimitry Andric
isOffsetFoldingLegal(const GlobalAddressSDNode * GA) const11860b57cec5SDimitry Andric bool AVRTargetLowering::isOffsetFoldingLegal(
11870b57cec5SDimitry Andric const GlobalAddressSDNode *GA) const {
11880b57cec5SDimitry Andric return true;
11890b57cec5SDimitry Andric }
11900b57cec5SDimitry Andric
11910b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11920b57cec5SDimitry Andric // Formal Arguments Calling Convention Implementation
11930b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11940b57cec5SDimitry Andric
11950b57cec5SDimitry Andric #include "AVRGenCallingConv.inc"
11960b57cec5SDimitry Andric
11975ffd83dbSDimitry Andric /// Registers for calling conventions, ordered in reverse as required by ABI.
11985ffd83dbSDimitry Andric /// Both arrays must be of the same length.
119981ad6265SDimitry Andric static const MCPhysReg RegList8AVR[] = {
12005ffd83dbSDimitry Andric AVR::R25, AVR::R24, AVR::R23, AVR::R22, AVR::R21, AVR::R20,
12015ffd83dbSDimitry Andric AVR::R19, AVR::R18, AVR::R17, AVR::R16, AVR::R15, AVR::R14,
12025ffd83dbSDimitry Andric AVR::R13, AVR::R12, AVR::R11, AVR::R10, AVR::R9, AVR::R8};
120381ad6265SDimitry Andric static const MCPhysReg RegList8Tiny[] = {AVR::R25, AVR::R24, AVR::R23,
120481ad6265SDimitry Andric AVR::R22, AVR::R21, AVR::R20};
120581ad6265SDimitry Andric static const MCPhysReg RegList16AVR[] = {
1206349cc55cSDimitry Andric AVR::R26R25, AVR::R25R24, AVR::R24R23, AVR::R23R22, AVR::R22R21,
1207349cc55cSDimitry Andric AVR::R21R20, AVR::R20R19, AVR::R19R18, AVR::R18R17, AVR::R17R16,
1208349cc55cSDimitry Andric AVR::R16R15, AVR::R15R14, AVR::R14R13, AVR::R13R12, AVR::R12R11,
1209349cc55cSDimitry Andric AVR::R11R10, AVR::R10R9, AVR::R9R8};
121081ad6265SDimitry Andric static const MCPhysReg RegList16Tiny[] = {AVR::R26R25, AVR::R25R24,
121181ad6265SDimitry Andric AVR::R24R23, AVR::R23R22,
121281ad6265SDimitry Andric AVR::R22R21, AVR::R21R20};
12130b57cec5SDimitry Andric
1214bdd1243dSDimitry Andric static_assert(std::size(RegList8AVR) == std::size(RegList16AVR),
121581ad6265SDimitry Andric "8-bit and 16-bit register arrays must be of equal length");
1216bdd1243dSDimitry Andric static_assert(std::size(RegList8Tiny) == std::size(RegList16Tiny),
12175ffd83dbSDimitry Andric "8-bit and 16-bit register arrays must be of equal length");
12180b57cec5SDimitry Andric
12190b57cec5SDimitry Andric /// Analyze incoming and outgoing function arguments. We need custom C++ code
12205ffd83dbSDimitry Andric /// to handle special constraints in the ABI.
12215ffd83dbSDimitry Andric /// In addition, all pieces of a certain argument have to be passed either
12225ffd83dbSDimitry Andric /// using registers or the stack but never mixing both.
12235ffd83dbSDimitry Andric template <typename ArgT>
analyzeArguments(TargetLowering::CallLoweringInfo * CLI,const Function * F,const DataLayout * TD,const SmallVectorImpl<ArgT> & Args,SmallVectorImpl<CCValAssign> & ArgLocs,CCState & CCInfo,bool Tiny)122481ad6265SDimitry Andric static void analyzeArguments(TargetLowering::CallLoweringInfo *CLI,
122581ad6265SDimitry Andric const Function *F, const DataLayout *TD,
122681ad6265SDimitry Andric const SmallVectorImpl<ArgT> &Args,
122781ad6265SDimitry Andric SmallVectorImpl<CCValAssign> &ArgLocs,
122881ad6265SDimitry Andric CCState &CCInfo, bool Tiny) {
122981ad6265SDimitry Andric // Choose the proper register list for argument passing according to the ABI.
123081ad6265SDimitry Andric ArrayRef<MCPhysReg> RegList8;
123181ad6265SDimitry Andric ArrayRef<MCPhysReg> RegList16;
123281ad6265SDimitry Andric if (Tiny) {
1233*0fca6ea1SDimitry Andric RegList8 = ArrayRef(RegList8Tiny);
1234*0fca6ea1SDimitry Andric RegList16 = ArrayRef(RegList16Tiny);
123581ad6265SDimitry Andric } else {
1236*0fca6ea1SDimitry Andric RegList8 = ArrayRef(RegList8AVR);
1237*0fca6ea1SDimitry Andric RegList16 = ArrayRef(RegList16AVR);
123881ad6265SDimitry Andric }
123981ad6265SDimitry Andric
12405ffd83dbSDimitry Andric unsigned NumArgs = Args.size();
12415ffd83dbSDimitry Andric // This is the index of the last used register, in RegList*.
12425ffd83dbSDimitry Andric // -1 means R26 (R26 is never actually used in CC).
12435ffd83dbSDimitry Andric int RegLastIdx = -1;
12445ffd83dbSDimitry Andric // Once a value is passed to the stack it will always be used
12455ffd83dbSDimitry Andric bool UseStack = false;
12465ffd83dbSDimitry Andric for (unsigned i = 0; i != NumArgs;) {
12475ffd83dbSDimitry Andric MVT VT = Args[i].VT;
12485ffd83dbSDimitry Andric // We have to count the number of bytes for each function argument, that is
12495ffd83dbSDimitry Andric // those Args with the same OrigArgIndex. This is important in case the
12505ffd83dbSDimitry Andric // function takes an aggregate type.
12515ffd83dbSDimitry Andric // Current argument will be between [i..j).
12525ffd83dbSDimitry Andric unsigned ArgIndex = Args[i].OrigArgIndex;
12535ffd83dbSDimitry Andric unsigned TotalBytes = VT.getStoreSize();
12545ffd83dbSDimitry Andric unsigned j = i + 1;
12555ffd83dbSDimitry Andric for (; j != NumArgs; ++j) {
12565ffd83dbSDimitry Andric if (Args[j].OrigArgIndex != ArgIndex)
12575ffd83dbSDimitry Andric break;
12585ffd83dbSDimitry Andric TotalBytes += Args[j].VT.getStoreSize();
12590b57cec5SDimitry Andric }
12605ffd83dbSDimitry Andric // Round up to even number of bytes.
12615ffd83dbSDimitry Andric TotalBytes = alignTo(TotalBytes, 2);
12625ffd83dbSDimitry Andric // Skip zero sized arguments
12635ffd83dbSDimitry Andric if (TotalBytes == 0)
12645ffd83dbSDimitry Andric continue;
12655ffd83dbSDimitry Andric // The index of the first register to be used
12665ffd83dbSDimitry Andric unsigned RegIdx = RegLastIdx + TotalBytes;
12675ffd83dbSDimitry Andric RegLastIdx = RegIdx;
12685ffd83dbSDimitry Andric // If there are not enough registers, use the stack
126981ad6265SDimitry Andric if (RegIdx >= RegList8.size()) {
12705ffd83dbSDimitry Andric UseStack = true;
12710b57cec5SDimitry Andric }
12725ffd83dbSDimitry Andric for (; i != j; ++i) {
12735ffd83dbSDimitry Andric MVT VT = Args[i].VT;
12740b57cec5SDimitry Andric
12755ffd83dbSDimitry Andric if (UseStack) {
12765ffd83dbSDimitry Andric auto evt = EVT(VT).getTypeForEVT(CCInfo.getContext());
12775ffd83dbSDimitry Andric unsigned Offset = CCInfo.AllocateStack(TD->getTypeAllocSize(evt),
12785ffd83dbSDimitry Andric TD->getABITypeAlign(evt));
12790b57cec5SDimitry Andric CCInfo.addLoc(
12805ffd83dbSDimitry Andric CCValAssign::getMem(i, VT, Offset, VT, CCValAssign::Full));
12810b57cec5SDimitry Andric } else {
12825ffd83dbSDimitry Andric unsigned Reg;
12835ffd83dbSDimitry Andric if (VT == MVT::i8) {
12845ffd83dbSDimitry Andric Reg = CCInfo.AllocateReg(RegList8[RegIdx]);
12855ffd83dbSDimitry Andric } else if (VT == MVT::i16) {
12865ffd83dbSDimitry Andric Reg = CCInfo.AllocateReg(RegList16[RegIdx]);
12870b57cec5SDimitry Andric } else {
12885ffd83dbSDimitry Andric llvm_unreachable(
12895ffd83dbSDimitry Andric "calling convention can only manage i8 and i16 types");
12905ffd83dbSDimitry Andric }
12915ffd83dbSDimitry Andric assert(Reg && "register not available in calling convention");
12925ffd83dbSDimitry Andric CCInfo.addLoc(CCValAssign::getReg(i, VT, Reg, VT, CCValAssign::Full));
12935ffd83dbSDimitry Andric // Registers inside a particular argument are sorted in increasing order
12945ffd83dbSDimitry Andric // (remember the array is reversed).
12955ffd83dbSDimitry Andric RegIdx -= VT.getStoreSize();
12965ffd83dbSDimitry Andric }
12975ffd83dbSDimitry Andric }
12980b57cec5SDimitry Andric }
12990b57cec5SDimitry Andric }
13000b57cec5SDimitry Andric
13015ffd83dbSDimitry Andric /// Count the total number of bytes needed to pass or return these arguments.
13025ffd83dbSDimitry Andric template <typename ArgT>
1303349cc55cSDimitry Andric static unsigned
getTotalArgumentsSizeInBytes(const SmallVectorImpl<ArgT> & Args)1304349cc55cSDimitry Andric getTotalArgumentsSizeInBytes(const SmallVectorImpl<ArgT> &Args) {
13055ffd83dbSDimitry Andric unsigned TotalBytes = 0;
13065ffd83dbSDimitry Andric
13075ffd83dbSDimitry Andric for (const ArgT &Arg : Args) {
13085ffd83dbSDimitry Andric TotalBytes += Arg.VT.getStoreSize();
13090b57cec5SDimitry Andric }
13105ffd83dbSDimitry Andric return TotalBytes;
13110b57cec5SDimitry Andric }
13125ffd83dbSDimitry Andric
13135ffd83dbSDimitry Andric /// Analyze incoming and outgoing value of returning from a function.
13145ffd83dbSDimitry Andric /// The algorithm is similar to analyzeArguments, but there can only be
13155ffd83dbSDimitry Andric /// one value, possibly an aggregate, and it is limited to 8 bytes.
13165ffd83dbSDimitry Andric template <typename ArgT>
analyzeReturnValues(const SmallVectorImpl<ArgT> & Args,CCState & CCInfo,bool Tiny)13175ffd83dbSDimitry Andric static void analyzeReturnValues(const SmallVectorImpl<ArgT> &Args,
131881ad6265SDimitry Andric CCState &CCInfo, bool Tiny) {
13195ffd83dbSDimitry Andric unsigned NumArgs = Args.size();
13205ffd83dbSDimitry Andric unsigned TotalBytes = getTotalArgumentsSizeInBytes(Args);
13215ffd83dbSDimitry Andric // CanLowerReturn() guarantees this assertion.
1322bdd1243dSDimitry Andric if (Tiny)
1323bdd1243dSDimitry Andric assert(TotalBytes <= 4 &&
1324bdd1243dSDimitry Andric "return values greater than 4 bytes cannot be lowered on AVRTiny");
1325bdd1243dSDimitry Andric else
1326349cc55cSDimitry Andric assert(TotalBytes <= 8 &&
1327bdd1243dSDimitry Andric "return values greater than 8 bytes cannot be lowered on AVR");
13285ffd83dbSDimitry Andric
132981ad6265SDimitry Andric // Choose the proper register list for argument passing according to the ABI.
133081ad6265SDimitry Andric ArrayRef<MCPhysReg> RegList8;
133181ad6265SDimitry Andric ArrayRef<MCPhysReg> RegList16;
133281ad6265SDimitry Andric if (Tiny) {
1333*0fca6ea1SDimitry Andric RegList8 = ArrayRef(RegList8Tiny);
1334*0fca6ea1SDimitry Andric RegList16 = ArrayRef(RegList16Tiny);
133581ad6265SDimitry Andric } else {
1336*0fca6ea1SDimitry Andric RegList8 = ArrayRef(RegList8AVR);
1337*0fca6ea1SDimitry Andric RegList16 = ArrayRef(RegList16AVR);
133881ad6265SDimitry Andric }
133981ad6265SDimitry Andric
13405ffd83dbSDimitry Andric // GCC-ABI says that the size is rounded up to the next even number,
13415ffd83dbSDimitry Andric // but actually once it is more than 4 it will always round up to 8.
13425ffd83dbSDimitry Andric if (TotalBytes > 4) {
13435ffd83dbSDimitry Andric TotalBytes = 8;
13445ffd83dbSDimitry Andric } else {
13455ffd83dbSDimitry Andric TotalBytes = alignTo(TotalBytes, 2);
13465ffd83dbSDimitry Andric }
13475ffd83dbSDimitry Andric
13485ffd83dbSDimitry Andric // The index of the first register to use.
13495ffd83dbSDimitry Andric int RegIdx = TotalBytes - 1;
13505ffd83dbSDimitry Andric for (unsigned i = 0; i != NumArgs; ++i) {
13515ffd83dbSDimitry Andric MVT VT = Args[i].VT;
13525ffd83dbSDimitry Andric unsigned Reg;
13535ffd83dbSDimitry Andric if (VT == MVT::i8) {
13545ffd83dbSDimitry Andric Reg = CCInfo.AllocateReg(RegList8[RegIdx]);
13555ffd83dbSDimitry Andric } else if (VT == MVT::i16) {
13565ffd83dbSDimitry Andric Reg = CCInfo.AllocateReg(RegList16[RegIdx]);
13575ffd83dbSDimitry Andric } else {
13585ffd83dbSDimitry Andric llvm_unreachable("calling convention can only manage i8 and i16 types");
13595ffd83dbSDimitry Andric }
13605ffd83dbSDimitry Andric assert(Reg && "register not available in calling convention");
13615ffd83dbSDimitry Andric CCInfo.addLoc(CCValAssign::getReg(i, VT, Reg, VT, CCValAssign::Full));
13625ffd83dbSDimitry Andric // Registers sort in increasing order
13635ffd83dbSDimitry Andric RegIdx -= VT.getStoreSize();
13640b57cec5SDimitry Andric }
13650b57cec5SDimitry Andric }
13660b57cec5SDimitry Andric
LowerFormalArguments(SDValue Chain,CallingConv::ID CallConv,bool isVarArg,const SmallVectorImpl<ISD::InputArg> & Ins,const SDLoc & dl,SelectionDAG & DAG,SmallVectorImpl<SDValue> & InVals) const13670b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerFormalArguments(
13680b57cec5SDimitry Andric SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
13695ffd83dbSDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
13705ffd83dbSDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
13710b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction();
13720b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo();
13730b57cec5SDimitry Andric auto DL = DAG.getDataLayout();
13740b57cec5SDimitry Andric
13750b57cec5SDimitry Andric // Assign locations to all of the incoming arguments.
13760b57cec5SDimitry Andric SmallVector<CCValAssign, 16> ArgLocs;
13770b57cec5SDimitry Andric CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
13780b57cec5SDimitry Andric *DAG.getContext());
13790b57cec5SDimitry Andric
13805ffd83dbSDimitry Andric // Variadic functions do not need all the analysis below.
13815ffd83dbSDimitry Andric if (isVarArg) {
13825ffd83dbSDimitry Andric CCInfo.AnalyzeFormalArguments(Ins, ArgCC_AVR_Vararg);
13835ffd83dbSDimitry Andric } else {
138481ad6265SDimitry Andric analyzeArguments(nullptr, &MF.getFunction(), &DL, Ins, ArgLocs, CCInfo,
138581ad6265SDimitry Andric Subtarget.hasTinyEncoding());
13865ffd83dbSDimitry Andric }
13870b57cec5SDimitry Andric
13880b57cec5SDimitry Andric SDValue ArgValue;
13890b57cec5SDimitry Andric for (CCValAssign &VA : ArgLocs) {
13900b57cec5SDimitry Andric
13910b57cec5SDimitry Andric // Arguments stored on registers.
13920b57cec5SDimitry Andric if (VA.isRegLoc()) {
13930b57cec5SDimitry Andric EVT RegVT = VA.getLocVT();
13940b57cec5SDimitry Andric const TargetRegisterClass *RC;
13950b57cec5SDimitry Andric if (RegVT == MVT::i8) {
13960b57cec5SDimitry Andric RC = &AVR::GPR8RegClass;
13970b57cec5SDimitry Andric } else if (RegVT == MVT::i16) {
13980b57cec5SDimitry Andric RC = &AVR::DREGSRegClass;
13990b57cec5SDimitry Andric } else {
14000b57cec5SDimitry Andric llvm_unreachable("Unknown argument type!");
14010b57cec5SDimitry Andric }
14020b57cec5SDimitry Andric
140304eeddc0SDimitry Andric Register Reg = MF.addLiveIn(VA.getLocReg(), RC);
14040b57cec5SDimitry Andric ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT);
14050b57cec5SDimitry Andric
14060b57cec5SDimitry Andric // :NOTE: Clang should not promote any i8 into i16 but for safety the
14070b57cec5SDimitry Andric // following code will handle zexts or sexts generated by other
14080b57cec5SDimitry Andric // front ends. Otherwise:
14090b57cec5SDimitry Andric // If this is an 8 bit value, it is really passed promoted
14100b57cec5SDimitry Andric // to 16 bits. Insert an assert[sz]ext to capture this, then
14110b57cec5SDimitry Andric // truncate to the right size.
14120b57cec5SDimitry Andric switch (VA.getLocInfo()) {
14130b57cec5SDimitry Andric default:
14140b57cec5SDimitry Andric llvm_unreachable("Unknown loc info!");
14150b57cec5SDimitry Andric case CCValAssign::Full:
14160b57cec5SDimitry Andric break;
14170b57cec5SDimitry Andric case CCValAssign::BCvt:
14180b57cec5SDimitry Andric ArgValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), ArgValue);
14190b57cec5SDimitry Andric break;
14200b57cec5SDimitry Andric case CCValAssign::SExt:
14210b57cec5SDimitry Andric ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue,
14220b57cec5SDimitry Andric DAG.getValueType(VA.getValVT()));
14230b57cec5SDimitry Andric ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
14240b57cec5SDimitry Andric break;
14250b57cec5SDimitry Andric case CCValAssign::ZExt:
14260b57cec5SDimitry Andric ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue,
14270b57cec5SDimitry Andric DAG.getValueType(VA.getValVT()));
14280b57cec5SDimitry Andric ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue);
14290b57cec5SDimitry Andric break;
14300b57cec5SDimitry Andric }
14310b57cec5SDimitry Andric
14320b57cec5SDimitry Andric InVals.push_back(ArgValue);
14330b57cec5SDimitry Andric } else {
1434349cc55cSDimitry Andric // Only arguments passed on the stack should make it here.
14350b57cec5SDimitry Andric assert(VA.isMemLoc());
14360b57cec5SDimitry Andric
14370b57cec5SDimitry Andric EVT LocVT = VA.getLocVT();
14380b57cec5SDimitry Andric
14390b57cec5SDimitry Andric // Create the frame index object for this incoming parameter.
14400b57cec5SDimitry Andric int FI = MFI.CreateFixedObject(LocVT.getSizeInBits() / 8,
14410b57cec5SDimitry Andric VA.getLocMemOffset(), true);
14420b57cec5SDimitry Andric
14430b57cec5SDimitry Andric // Create the SelectionDAG nodes corresponding to a load
14440b57cec5SDimitry Andric // from this parameter.
14450b57cec5SDimitry Andric SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DL));
14460b57cec5SDimitry Andric InVals.push_back(DAG.getLoad(LocVT, dl, Chain, FIN,
1447e8d8bef9SDimitry Andric MachinePointerInfo::getFixedStack(MF, FI)));
14480b57cec5SDimitry Andric }
14490b57cec5SDimitry Andric }
14500b57cec5SDimitry Andric
14510b57cec5SDimitry Andric // If the function takes variable number of arguments, make a frame index for
14520b57cec5SDimitry Andric // the start of the first vararg value... for expansion of llvm.va_start.
14530b57cec5SDimitry Andric if (isVarArg) {
145406c3fb27SDimitry Andric unsigned StackSize = CCInfo.getStackSize();
14550b57cec5SDimitry Andric AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
14560b57cec5SDimitry Andric
14570b57cec5SDimitry Andric AFI->setVarArgsFrameIndex(MFI.CreateFixedObject(2, StackSize, true));
14580b57cec5SDimitry Andric }
14590b57cec5SDimitry Andric
14600b57cec5SDimitry Andric return Chain;
14610b57cec5SDimitry Andric }
14620b57cec5SDimitry Andric
14630b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14640b57cec5SDimitry Andric // Call Calling Convention Implementation
14650b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14660b57cec5SDimitry Andric
LowerCall(TargetLowering::CallLoweringInfo & CLI,SmallVectorImpl<SDValue> & InVals) const14670b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
14680b57cec5SDimitry Andric SmallVectorImpl<SDValue> &InVals) const {
14690b57cec5SDimitry Andric SelectionDAG &DAG = CLI.DAG;
14700b57cec5SDimitry Andric SDLoc &DL = CLI.DL;
14710b57cec5SDimitry Andric SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
14720b57cec5SDimitry Andric SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
14730b57cec5SDimitry Andric SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
14740b57cec5SDimitry Andric SDValue Chain = CLI.Chain;
14750b57cec5SDimitry Andric SDValue Callee = CLI.Callee;
14760b57cec5SDimitry Andric bool &isTailCall = CLI.IsTailCall;
14770b57cec5SDimitry Andric CallingConv::ID CallConv = CLI.CallConv;
14780b57cec5SDimitry Andric bool isVarArg = CLI.IsVarArg;
14790b57cec5SDimitry Andric
14800b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction();
14810b57cec5SDimitry Andric
14820b57cec5SDimitry Andric // AVR does not yet support tail call optimization.
14830b57cec5SDimitry Andric isTailCall = false;
14840b57cec5SDimitry Andric
14850b57cec5SDimitry Andric // Analyze operands of the call, assigning locations to each operand.
14860b57cec5SDimitry Andric SmallVector<CCValAssign, 16> ArgLocs;
14870b57cec5SDimitry Andric CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
14880b57cec5SDimitry Andric *DAG.getContext());
14890b57cec5SDimitry Andric
14900b57cec5SDimitry Andric // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
14910b57cec5SDimitry Andric // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
14920b57cec5SDimitry Andric // node so that legalize doesn't hack it.
14930b57cec5SDimitry Andric const Function *F = nullptr;
14940b57cec5SDimitry Andric if (const GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
14950b57cec5SDimitry Andric const GlobalValue *GV = G->getGlobal();
149681ad6265SDimitry Andric if (isa<Function>(GV))
14970b57cec5SDimitry Andric F = cast<Function>(GV);
14980b57cec5SDimitry Andric Callee =
14990b57cec5SDimitry Andric DAG.getTargetGlobalAddress(GV, DL, getPointerTy(DAG.getDataLayout()));
15000b57cec5SDimitry Andric } else if (const ExternalSymbolSDNode *ES =
15010b57cec5SDimitry Andric dyn_cast<ExternalSymbolSDNode>(Callee)) {
15020b57cec5SDimitry Andric Callee = DAG.getTargetExternalSymbol(ES->getSymbol(),
15030b57cec5SDimitry Andric getPointerTy(DAG.getDataLayout()));
15040b57cec5SDimitry Andric }
15050b57cec5SDimitry Andric
15065ffd83dbSDimitry Andric // Variadic functions do not need all the analysis below.
15075ffd83dbSDimitry Andric if (isVarArg) {
15085ffd83dbSDimitry Andric CCInfo.AnalyzeCallOperands(Outs, ArgCC_AVR_Vararg);
15095ffd83dbSDimitry Andric } else {
151081ad6265SDimitry Andric analyzeArguments(&CLI, F, &DAG.getDataLayout(), Outs, ArgLocs, CCInfo,
151181ad6265SDimitry Andric Subtarget.hasTinyEncoding());
15125ffd83dbSDimitry Andric }
15130b57cec5SDimitry Andric
15140b57cec5SDimitry Andric // Get a count of how many bytes are to be pushed on the stack.
151506c3fb27SDimitry Andric unsigned NumBytes = CCInfo.getStackSize();
15160b57cec5SDimitry Andric
15170b57cec5SDimitry Andric Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, DL);
15180b57cec5SDimitry Andric
15190b57cec5SDimitry Andric SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
15200b57cec5SDimitry Andric
15210b57cec5SDimitry Andric // First, walk the register assignments, inserting copies.
15220b57cec5SDimitry Andric unsigned AI, AE;
15230b57cec5SDimitry Andric bool HasStackArgs = false;
15240b57cec5SDimitry Andric for (AI = 0, AE = ArgLocs.size(); AI != AE; ++AI) {
15250b57cec5SDimitry Andric CCValAssign &VA = ArgLocs[AI];
15260b57cec5SDimitry Andric EVT RegVT = VA.getLocVT();
15270b57cec5SDimitry Andric SDValue Arg = OutVals[AI];
15280b57cec5SDimitry Andric
15290b57cec5SDimitry Andric // Promote the value if needed. With Clang this should not happen.
15300b57cec5SDimitry Andric switch (VA.getLocInfo()) {
15310b57cec5SDimitry Andric default:
15320b57cec5SDimitry Andric llvm_unreachable("Unknown loc info!");
15330b57cec5SDimitry Andric case CCValAssign::Full:
15340b57cec5SDimitry Andric break;
15350b57cec5SDimitry Andric case CCValAssign::SExt:
15360b57cec5SDimitry Andric Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, RegVT, Arg);
15370b57cec5SDimitry Andric break;
15380b57cec5SDimitry Andric case CCValAssign::ZExt:
15390b57cec5SDimitry Andric Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, RegVT, Arg);
15400b57cec5SDimitry Andric break;
15410b57cec5SDimitry Andric case CCValAssign::AExt:
15420b57cec5SDimitry Andric Arg = DAG.getNode(ISD::ANY_EXTEND, DL, RegVT, Arg);
15430b57cec5SDimitry Andric break;
15440b57cec5SDimitry Andric case CCValAssign::BCvt:
15450b57cec5SDimitry Andric Arg = DAG.getNode(ISD::BITCAST, DL, RegVT, Arg);
15460b57cec5SDimitry Andric break;
15470b57cec5SDimitry Andric }
15480b57cec5SDimitry Andric
15490b57cec5SDimitry Andric // Stop when we encounter a stack argument, we need to process them
15500b57cec5SDimitry Andric // in reverse order in the loop below.
15510b57cec5SDimitry Andric if (VA.isMemLoc()) {
15520b57cec5SDimitry Andric HasStackArgs = true;
15530b57cec5SDimitry Andric break;
15540b57cec5SDimitry Andric }
15550b57cec5SDimitry Andric
15560b57cec5SDimitry Andric // Arguments that can be passed on registers must be kept in the RegsToPass
15570b57cec5SDimitry Andric // vector.
15580b57cec5SDimitry Andric RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
15590b57cec5SDimitry Andric }
15600b57cec5SDimitry Andric
1561fe6060f1SDimitry Andric // Second, stack arguments have to walked.
1562fe6060f1SDimitry Andric // Previously this code created chained stores but those chained stores appear
1563fe6060f1SDimitry Andric // to be unchained in the legalization phase. Therefore, do not attempt to
1564fe6060f1SDimitry Andric // chain them here. In fact, chaining them here somehow causes the first and
1565fe6060f1SDimitry Andric // second store to be reversed which is the exact opposite of the intended
1566fe6060f1SDimitry Andric // effect.
15670b57cec5SDimitry Andric if (HasStackArgs) {
1568fe6060f1SDimitry Andric SmallVector<SDValue, 8> MemOpChains;
1569fe6060f1SDimitry Andric for (; AI != AE; AI++) {
1570fe6060f1SDimitry Andric CCValAssign &VA = ArgLocs[AI];
1571fe6060f1SDimitry Andric SDValue Arg = OutVals[AI];
15720b57cec5SDimitry Andric
15730b57cec5SDimitry Andric assert(VA.isMemLoc());
15740b57cec5SDimitry Andric
15750b57cec5SDimitry Andric // SP points to one stack slot further so add one to adjust it.
15760b57cec5SDimitry Andric SDValue PtrOff = DAG.getNode(
15770b57cec5SDimitry Andric ISD::ADD, DL, getPointerTy(DAG.getDataLayout()),
15780b57cec5SDimitry Andric DAG.getRegister(AVR::SP, getPointerTy(DAG.getDataLayout())),
15790b57cec5SDimitry Andric DAG.getIntPtrConstant(VA.getLocMemOffset() + 1, DL));
15800b57cec5SDimitry Andric
1581fe6060f1SDimitry Andric MemOpChains.push_back(
15820b57cec5SDimitry Andric DAG.getStore(Chain, DL, Arg, PtrOff,
1583fe6060f1SDimitry Andric MachinePointerInfo::getStack(MF, VA.getLocMemOffset())));
15840b57cec5SDimitry Andric }
1585fe6060f1SDimitry Andric
1586fe6060f1SDimitry Andric if (!MemOpChains.empty())
1587fe6060f1SDimitry Andric Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
15880b57cec5SDimitry Andric }
15890b57cec5SDimitry Andric
15900b57cec5SDimitry Andric // Build a sequence of copy-to-reg nodes chained together with token chain and
159106c3fb27SDimitry Andric // flag operands which copy the outgoing args into registers. The InGlue in
15920b57cec5SDimitry Andric // necessary since all emited instructions must be stuck together.
159306c3fb27SDimitry Andric SDValue InGlue;
15940b57cec5SDimitry Andric for (auto Reg : RegsToPass) {
159506c3fb27SDimitry Andric Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, InGlue);
159606c3fb27SDimitry Andric InGlue = Chain.getValue(1);
15970b57cec5SDimitry Andric }
15980b57cec5SDimitry Andric
15990b57cec5SDimitry Andric // Returns a chain & a flag for retval copy to use.
16000b57cec5SDimitry Andric SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
16010b57cec5SDimitry Andric SmallVector<SDValue, 8> Ops;
16020b57cec5SDimitry Andric Ops.push_back(Chain);
16030b57cec5SDimitry Andric Ops.push_back(Callee);
16040b57cec5SDimitry Andric
16050b57cec5SDimitry Andric // Add argument registers to the end of the list so that they are known live
16060b57cec5SDimitry Andric // into the call.
16070b57cec5SDimitry Andric for (auto Reg : RegsToPass) {
16080b57cec5SDimitry Andric Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
16090b57cec5SDimitry Andric }
16100b57cec5SDimitry Andric
1611bdd1243dSDimitry Andric // The zero register (usually R1) must be passed as an implicit register so
1612bdd1243dSDimitry Andric // that this register is correctly zeroed in interrupts.
1613bdd1243dSDimitry Andric Ops.push_back(DAG.getRegister(Subtarget.getZeroRegister(), MVT::i8));
1614bdd1243dSDimitry Andric
16150b57cec5SDimitry Andric // Add a register mask operand representing the call-preserved registers.
16160b57cec5SDimitry Andric const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
16170b57cec5SDimitry Andric const uint32_t *Mask =
16180b57cec5SDimitry Andric TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv);
16190b57cec5SDimitry Andric assert(Mask && "Missing call preserved mask for calling convention");
16200b57cec5SDimitry Andric Ops.push_back(DAG.getRegisterMask(Mask));
16210b57cec5SDimitry Andric
162206c3fb27SDimitry Andric if (InGlue.getNode()) {
162306c3fb27SDimitry Andric Ops.push_back(InGlue);
16240b57cec5SDimitry Andric }
16250b57cec5SDimitry Andric
16260b57cec5SDimitry Andric Chain = DAG.getNode(AVRISD::CALL, DL, NodeTys, Ops);
162706c3fb27SDimitry Andric InGlue = Chain.getValue(1);
16280b57cec5SDimitry Andric
16290b57cec5SDimitry Andric // Create the CALLSEQ_END node.
163006c3fb27SDimitry Andric Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, InGlue, DL);
16310b57cec5SDimitry Andric
16320b57cec5SDimitry Andric if (!Ins.empty()) {
163306c3fb27SDimitry Andric InGlue = Chain.getValue(1);
16340b57cec5SDimitry Andric }
16350b57cec5SDimitry Andric
16360b57cec5SDimitry Andric // Handle result values, copying them out of physregs into vregs that we
16370b57cec5SDimitry Andric // return.
163806c3fb27SDimitry Andric return LowerCallResult(Chain, InGlue, CallConv, isVarArg, Ins, DL, DAG,
16390b57cec5SDimitry Andric InVals);
16400b57cec5SDimitry Andric }
16410b57cec5SDimitry Andric
16420b57cec5SDimitry Andric /// Lower the result values of a call into the
16430b57cec5SDimitry Andric /// appropriate copies out of appropriate physical registers.
16440b57cec5SDimitry Andric ///
LowerCallResult(SDValue Chain,SDValue InGlue,CallingConv::ID CallConv,bool isVarArg,const SmallVectorImpl<ISD::InputArg> & Ins,const SDLoc & dl,SelectionDAG & DAG,SmallVectorImpl<SDValue> & InVals) const16450b57cec5SDimitry Andric SDValue AVRTargetLowering::LowerCallResult(
164606c3fb27SDimitry Andric SDValue Chain, SDValue InGlue, CallingConv::ID CallConv, bool isVarArg,
1647349cc55cSDimitry Andric const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
1648349cc55cSDimitry Andric SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
16490b57cec5SDimitry Andric
16500b57cec5SDimitry Andric // Assign locations to each value returned by this call.
16510b57cec5SDimitry Andric SmallVector<CCValAssign, 16> RVLocs;
16520b57cec5SDimitry Andric CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
16530b57cec5SDimitry Andric *DAG.getContext());
16540b57cec5SDimitry Andric
16550b57cec5SDimitry Andric // Handle runtime calling convs.
16565ffd83dbSDimitry Andric if (CallConv == CallingConv::AVR_BUILTIN) {
16575ffd83dbSDimitry Andric CCInfo.AnalyzeCallResult(Ins, RetCC_AVR_BUILTIN);
16585ffd83dbSDimitry Andric } else {
165981ad6265SDimitry Andric analyzeReturnValues(Ins, CCInfo, Subtarget.hasTinyEncoding());
16600b57cec5SDimitry Andric }
16610b57cec5SDimitry Andric
16620b57cec5SDimitry Andric // Copy all of the result registers out of their specified physreg.
16630b57cec5SDimitry Andric for (CCValAssign const &RVLoc : RVLocs) {
16640b57cec5SDimitry Andric Chain = DAG.getCopyFromReg(Chain, dl, RVLoc.getLocReg(), RVLoc.getValVT(),
166506c3fb27SDimitry Andric InGlue)
16660b57cec5SDimitry Andric .getValue(1);
166706c3fb27SDimitry Andric InGlue = Chain.getValue(2);
16680b57cec5SDimitry Andric InVals.push_back(Chain.getValue(0));
16690b57cec5SDimitry Andric }
16700b57cec5SDimitry Andric
16710b57cec5SDimitry Andric return Chain;
16720b57cec5SDimitry Andric }
16730b57cec5SDimitry Andric
16740b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16750b57cec5SDimitry Andric // Return Value Calling Convention Implementation
16760b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16770b57cec5SDimitry Andric
CanLowerReturn(CallingConv::ID CallConv,MachineFunction & MF,bool isVarArg,const SmallVectorImpl<ISD::OutputArg> & Outs,LLVMContext & Context) const16785ffd83dbSDimitry Andric bool AVRTargetLowering::CanLowerReturn(
16795ffd83dbSDimitry Andric CallingConv::ID CallConv, MachineFunction &MF, bool isVarArg,
16805ffd83dbSDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
16815ffd83dbSDimitry Andric if (CallConv == CallingConv::AVR_BUILTIN) {
16820b57cec5SDimitry Andric SmallVector<CCValAssign, 16> RVLocs;
16830b57cec5SDimitry Andric CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context);
16845ffd83dbSDimitry Andric return CCInfo.CheckReturn(Outs, RetCC_AVR_BUILTIN);
16855ffd83dbSDimitry Andric }
16860b57cec5SDimitry Andric
16875ffd83dbSDimitry Andric unsigned TotalBytes = getTotalArgumentsSizeInBytes(Outs);
1688bdd1243dSDimitry Andric return TotalBytes <= (unsigned)(Subtarget.hasTinyEncoding() ? 4 : 8);
16890b57cec5SDimitry Andric }
16900b57cec5SDimitry Andric
16910b57cec5SDimitry Andric SDValue
LowerReturn(SDValue Chain,CallingConv::ID CallConv,bool isVarArg,const SmallVectorImpl<ISD::OutputArg> & Outs,const SmallVectorImpl<SDValue> & OutVals,const SDLoc & dl,SelectionDAG & DAG) const16920b57cec5SDimitry Andric AVRTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
16930b57cec5SDimitry Andric bool isVarArg,
16940b57cec5SDimitry Andric const SmallVectorImpl<ISD::OutputArg> &Outs,
16950b57cec5SDimitry Andric const SmallVectorImpl<SDValue> &OutVals,
16960b57cec5SDimitry Andric const SDLoc &dl, SelectionDAG &DAG) const {
16970b57cec5SDimitry Andric // CCValAssign - represent the assignment of the return value to locations.
16980b57cec5SDimitry Andric SmallVector<CCValAssign, 16> RVLocs;
16990b57cec5SDimitry Andric
17000b57cec5SDimitry Andric // CCState - Info about the registers and stack slot.
17010b57cec5SDimitry Andric CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
17020b57cec5SDimitry Andric *DAG.getContext());
17030b57cec5SDimitry Andric
17040b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction();
17050b57cec5SDimitry Andric
17065ffd83dbSDimitry Andric // Analyze return values.
17075ffd83dbSDimitry Andric if (CallConv == CallingConv::AVR_BUILTIN) {
17085ffd83dbSDimitry Andric CCInfo.AnalyzeReturn(Outs, RetCC_AVR_BUILTIN);
17095ffd83dbSDimitry Andric } else {
171081ad6265SDimitry Andric analyzeReturnValues(Outs, CCInfo, Subtarget.hasTinyEncoding());
17110b57cec5SDimitry Andric }
17120b57cec5SDimitry Andric
171306c3fb27SDimitry Andric SDValue Glue;
17140b57cec5SDimitry Andric SmallVector<SDValue, 4> RetOps(1, Chain);
17150b57cec5SDimitry Andric // Copy the result values into the output registers.
17165ffd83dbSDimitry Andric for (unsigned i = 0, e = RVLocs.size(); i != e; ++i) {
17170b57cec5SDimitry Andric CCValAssign &VA = RVLocs[i];
17180b57cec5SDimitry Andric assert(VA.isRegLoc() && "Can only return in registers!");
17190b57cec5SDimitry Andric
172006c3fb27SDimitry Andric Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Glue);
17210b57cec5SDimitry Andric
17220b57cec5SDimitry Andric // Guarantee that all emitted copies are stuck together with flags.
172306c3fb27SDimitry Andric Glue = Chain.getValue(1);
17240b57cec5SDimitry Andric RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
17250b57cec5SDimitry Andric }
17260b57cec5SDimitry Andric
17270b57cec5SDimitry Andric // Don't emit the ret/reti instruction when the naked attribute is present in
17280b57cec5SDimitry Andric // the function being compiled.
1729349cc55cSDimitry Andric if (MF.getFunction().getAttributes().hasFnAttr(Attribute::Naked)) {
17300b57cec5SDimitry Andric return Chain;
17310b57cec5SDimitry Andric }
17320b57cec5SDimitry Andric
17335ffd83dbSDimitry Andric const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
17345ffd83dbSDimitry Andric
1735bdd1243dSDimitry Andric if (!AFI->isInterruptOrSignalHandler()) {
1736bdd1243dSDimitry Andric // The return instruction has an implicit zero register operand: it must
1737bdd1243dSDimitry Andric // contain zero on return.
1738bdd1243dSDimitry Andric // This is not needed in interrupts however, where the zero register is
1739bdd1243dSDimitry Andric // handled specially (only pushed/popped when needed).
1740bdd1243dSDimitry Andric RetOps.push_back(DAG.getRegister(Subtarget.getZeroRegister(), MVT::i8));
1741bdd1243dSDimitry Andric }
1742bdd1243dSDimitry Andric
17430b57cec5SDimitry Andric unsigned RetOpc =
174406c3fb27SDimitry Andric AFI->isInterruptOrSignalHandler() ? AVRISD::RETI_GLUE : AVRISD::RET_GLUE;
17450b57cec5SDimitry Andric
17460b57cec5SDimitry Andric RetOps[0] = Chain; // Update chain.
17470b57cec5SDimitry Andric
174806c3fb27SDimitry Andric if (Glue.getNode()) {
174906c3fb27SDimitry Andric RetOps.push_back(Glue);
17500b57cec5SDimitry Andric }
17510b57cec5SDimitry Andric
17520b57cec5SDimitry Andric return DAG.getNode(RetOpc, dl, MVT::Other, RetOps);
17530b57cec5SDimitry Andric }
17540b57cec5SDimitry Andric
17550b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17560b57cec5SDimitry Andric // Custom Inserters
17570b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17580b57cec5SDimitry Andric
insertShift(MachineInstr & MI,MachineBasicBlock * BB,bool Tiny) const17590b57cec5SDimitry Andric MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
176006c3fb27SDimitry Andric MachineBasicBlock *BB,
176106c3fb27SDimitry Andric bool Tiny) const {
17620b57cec5SDimitry Andric unsigned Opc;
17630b57cec5SDimitry Andric const TargetRegisterClass *RC;
17640b57cec5SDimitry Andric bool HasRepeatedOperand = false;
17650b57cec5SDimitry Andric MachineFunction *F = BB->getParent();
17660b57cec5SDimitry Andric MachineRegisterInfo &RI = F->getRegInfo();
17670b57cec5SDimitry Andric const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
17680b57cec5SDimitry Andric DebugLoc dl = MI.getDebugLoc();
17690b57cec5SDimitry Andric
17700b57cec5SDimitry Andric switch (MI.getOpcode()) {
17710b57cec5SDimitry Andric default:
17720b57cec5SDimitry Andric llvm_unreachable("Invalid shift opcode!");
17730b57cec5SDimitry Andric case AVR::Lsl8:
17740b57cec5SDimitry Andric Opc = AVR::ADDRdRr; // LSL is an alias of ADD Rd, Rd
17750b57cec5SDimitry Andric RC = &AVR::GPR8RegClass;
17760b57cec5SDimitry Andric HasRepeatedOperand = true;
17770b57cec5SDimitry Andric break;
17780b57cec5SDimitry Andric case AVR::Lsl16:
17790b57cec5SDimitry Andric Opc = AVR::LSLWRd;
17800b57cec5SDimitry Andric RC = &AVR::DREGSRegClass;
17810b57cec5SDimitry Andric break;
17820b57cec5SDimitry Andric case AVR::Asr8:
17830b57cec5SDimitry Andric Opc = AVR::ASRRd;
17840b57cec5SDimitry Andric RC = &AVR::GPR8RegClass;
17850b57cec5SDimitry Andric break;
17860b57cec5SDimitry Andric case AVR::Asr16:
17870b57cec5SDimitry Andric Opc = AVR::ASRWRd;
17880b57cec5SDimitry Andric RC = &AVR::DREGSRegClass;
17890b57cec5SDimitry Andric break;
17900b57cec5SDimitry Andric case AVR::Lsr8:
17910b57cec5SDimitry Andric Opc = AVR::LSRRd;
17920b57cec5SDimitry Andric RC = &AVR::GPR8RegClass;
17930b57cec5SDimitry Andric break;
17940b57cec5SDimitry Andric case AVR::Lsr16:
17950b57cec5SDimitry Andric Opc = AVR::LSRWRd;
17960b57cec5SDimitry Andric RC = &AVR::DREGSRegClass;
17970b57cec5SDimitry Andric break;
17980b57cec5SDimitry Andric case AVR::Rol8:
179906c3fb27SDimitry Andric Opc = Tiny ? AVR::ROLBRdR17 : AVR::ROLBRdR1;
18000b57cec5SDimitry Andric RC = &AVR::GPR8RegClass;
18010b57cec5SDimitry Andric break;
18020b57cec5SDimitry Andric case AVR::Rol16:
18030b57cec5SDimitry Andric Opc = AVR::ROLWRd;
18040b57cec5SDimitry Andric RC = &AVR::DREGSRegClass;
18050b57cec5SDimitry Andric break;
18060b57cec5SDimitry Andric case AVR::Ror8:
1807480093f4SDimitry Andric Opc = AVR::RORBRd;
18080b57cec5SDimitry Andric RC = &AVR::GPR8RegClass;
18090b57cec5SDimitry Andric break;
18100b57cec5SDimitry Andric case AVR::Ror16:
18110b57cec5SDimitry Andric Opc = AVR::RORWRd;
18120b57cec5SDimitry Andric RC = &AVR::DREGSRegClass;
18130b57cec5SDimitry Andric break;
18140b57cec5SDimitry Andric }
18150b57cec5SDimitry Andric
18160b57cec5SDimitry Andric const BasicBlock *LLVM_BB = BB->getBasicBlock();
18170b57cec5SDimitry Andric
18180b57cec5SDimitry Andric MachineFunction::iterator I;
1819349cc55cSDimitry Andric for (I = BB->getIterator(); I != F->end() && &(*I) != BB; ++I)
1820349cc55cSDimitry Andric ;
1821349cc55cSDimitry Andric if (I != F->end())
1822349cc55cSDimitry Andric ++I;
18230b57cec5SDimitry Andric
18240b57cec5SDimitry Andric // Create loop block.
18250b57cec5SDimitry Andric MachineBasicBlock *LoopBB = F->CreateMachineBasicBlock(LLVM_BB);
1826e8d8bef9SDimitry Andric MachineBasicBlock *CheckBB = F->CreateMachineBasicBlock(LLVM_BB);
18270b57cec5SDimitry Andric MachineBasicBlock *RemBB = F->CreateMachineBasicBlock(LLVM_BB);
18280b57cec5SDimitry Andric
18290b57cec5SDimitry Andric F->insert(I, LoopBB);
1830e8d8bef9SDimitry Andric F->insert(I, CheckBB);
18310b57cec5SDimitry Andric F->insert(I, RemBB);
18320b57cec5SDimitry Andric
18330b57cec5SDimitry Andric // Update machine-CFG edges by transferring all successors of the current
18340b57cec5SDimitry Andric // block to the block containing instructions after shift.
18350b57cec5SDimitry Andric RemBB->splice(RemBB->begin(), BB, std::next(MachineBasicBlock::iterator(MI)),
18360b57cec5SDimitry Andric BB->end());
18370b57cec5SDimitry Andric RemBB->transferSuccessorsAndUpdatePHIs(BB);
18380b57cec5SDimitry Andric
1839e8d8bef9SDimitry Andric // Add edges BB => LoopBB => CheckBB => RemBB, CheckBB => LoopBB.
1840e8d8bef9SDimitry Andric BB->addSuccessor(CheckBB);
1841e8d8bef9SDimitry Andric LoopBB->addSuccessor(CheckBB);
1842e8d8bef9SDimitry Andric CheckBB->addSuccessor(LoopBB);
1843e8d8bef9SDimitry Andric CheckBB->addSuccessor(RemBB);
18440b57cec5SDimitry Andric
1845e8d8bef9SDimitry Andric Register ShiftAmtReg = RI.createVirtualRegister(&AVR::GPR8RegClass);
1846e8d8bef9SDimitry Andric Register ShiftAmtReg2 = RI.createVirtualRegister(&AVR::GPR8RegClass);
18478bcb0991SDimitry Andric Register ShiftReg = RI.createVirtualRegister(RC);
18488bcb0991SDimitry Andric Register ShiftReg2 = RI.createVirtualRegister(RC);
18498bcb0991SDimitry Andric Register ShiftAmtSrcReg = MI.getOperand(2).getReg();
18508bcb0991SDimitry Andric Register SrcReg = MI.getOperand(1).getReg();
18518bcb0991SDimitry Andric Register DstReg = MI.getOperand(0).getReg();
18520b57cec5SDimitry Andric
18530b57cec5SDimitry Andric // BB:
1854e8d8bef9SDimitry Andric // rjmp CheckBB
1855e8d8bef9SDimitry Andric BuildMI(BB, dl, TII.get(AVR::RJMPk)).addMBB(CheckBB);
18560b57cec5SDimitry Andric
18570b57cec5SDimitry Andric // LoopBB:
18580b57cec5SDimitry Andric // ShiftReg2 = shift ShiftReg
18590b57cec5SDimitry Andric auto ShiftMI = BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2).addReg(ShiftReg);
18600b57cec5SDimitry Andric if (HasRepeatedOperand)
18610b57cec5SDimitry Andric ShiftMI.addReg(ShiftReg);
18620b57cec5SDimitry Andric
1863e8d8bef9SDimitry Andric // CheckBB:
1864e8d8bef9SDimitry Andric // ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB]
1865e8d8bef9SDimitry Andric // ShiftAmt = phi [%N, BB], [%ShiftAmt2, LoopBB]
18660b57cec5SDimitry Andric // DestReg = phi [%SrcReg, BB], [%ShiftReg, LoopBB]
1867e8d8bef9SDimitry Andric // ShiftAmt2 = ShiftAmt - 1;
1868e8d8bef9SDimitry Andric // if (ShiftAmt2 >= 0) goto LoopBB;
1869e8d8bef9SDimitry Andric BuildMI(CheckBB, dl, TII.get(AVR::PHI), ShiftReg)
18700b57cec5SDimitry Andric .addReg(SrcReg)
18710b57cec5SDimitry Andric .addMBB(BB)
18720b57cec5SDimitry Andric .addReg(ShiftReg2)
18730b57cec5SDimitry Andric .addMBB(LoopBB);
1874e8d8bef9SDimitry Andric BuildMI(CheckBB, dl, TII.get(AVR::PHI), ShiftAmtReg)
1875e8d8bef9SDimitry Andric .addReg(ShiftAmtSrcReg)
1876e8d8bef9SDimitry Andric .addMBB(BB)
1877e8d8bef9SDimitry Andric .addReg(ShiftAmtReg2)
1878e8d8bef9SDimitry Andric .addMBB(LoopBB);
1879e8d8bef9SDimitry Andric BuildMI(CheckBB, dl, TII.get(AVR::PHI), DstReg)
1880e8d8bef9SDimitry Andric .addReg(SrcReg)
1881e8d8bef9SDimitry Andric .addMBB(BB)
1882e8d8bef9SDimitry Andric .addReg(ShiftReg2)
1883e8d8bef9SDimitry Andric .addMBB(LoopBB);
1884e8d8bef9SDimitry Andric
1885349cc55cSDimitry Andric BuildMI(CheckBB, dl, TII.get(AVR::DECRd), ShiftAmtReg2).addReg(ShiftAmtReg);
1886e8d8bef9SDimitry Andric BuildMI(CheckBB, dl, TII.get(AVR::BRPLk)).addMBB(LoopBB);
18870b57cec5SDimitry Andric
18880b57cec5SDimitry Andric MI.eraseFromParent(); // The pseudo instruction is gone now.
18890b57cec5SDimitry Andric return RemBB;
18900b57cec5SDimitry Andric }
18910b57cec5SDimitry Andric
1892bdd1243dSDimitry Andric // Do a multibyte AVR shift. Insert shift instructions and put the output
1893bdd1243dSDimitry Andric // registers in the Regs array.
1894bdd1243dSDimitry Andric // Because AVR does not have a normal shift instruction (only a single bit shift
1895bdd1243dSDimitry Andric // instruction), we have to emulate this behavior with other instructions.
1896bdd1243dSDimitry Andric // It first tries large steps (moving registers around) and then smaller steps
1897bdd1243dSDimitry Andric // like single bit shifts.
1898bdd1243dSDimitry Andric // Large shifts actually reduce the number of shifted registers, so the below
1899bdd1243dSDimitry Andric // algorithms have to work independently of the number of registers that are
1900bdd1243dSDimitry Andric // shifted.
1901bdd1243dSDimitry Andric // For more information and background, see this blogpost:
1902bdd1243dSDimitry Andric // https://aykevl.nl/2021/02/avr-bitshift
insertMultibyteShift(MachineInstr & MI,MachineBasicBlock * BB,MutableArrayRef<std::pair<Register,int>> Regs,ISD::NodeType Opc,int64_t ShiftAmt)1903bdd1243dSDimitry Andric static void insertMultibyteShift(MachineInstr &MI, MachineBasicBlock *BB,
1904bdd1243dSDimitry Andric MutableArrayRef<std::pair<Register, int>> Regs,
1905bdd1243dSDimitry Andric ISD::NodeType Opc, int64_t ShiftAmt) {
1906bdd1243dSDimitry Andric const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo();
1907bdd1243dSDimitry Andric const AVRSubtarget &STI = BB->getParent()->getSubtarget<AVRSubtarget>();
1908bdd1243dSDimitry Andric MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
1909bdd1243dSDimitry Andric const DebugLoc &dl = MI.getDebugLoc();
1910bdd1243dSDimitry Andric
1911bdd1243dSDimitry Andric const bool ShiftLeft = Opc == ISD::SHL;
1912bdd1243dSDimitry Andric const bool ArithmeticShift = Opc == ISD::SRA;
1913bdd1243dSDimitry Andric
1914bdd1243dSDimitry Andric // Zero a register, for use in later operations.
1915bdd1243dSDimitry Andric Register ZeroReg = MRI.createVirtualRegister(&AVR::GPR8RegClass);
1916bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::COPY), ZeroReg)
1917bdd1243dSDimitry Andric .addReg(STI.getZeroRegister());
1918bdd1243dSDimitry Andric
1919bdd1243dSDimitry Andric // Do a shift modulo 6 or 7. This is a bit more complicated than most shifts
1920bdd1243dSDimitry Andric // and is hard to compose with the rest, so these are special cased.
1921bdd1243dSDimitry Andric // The basic idea is to shift one or two bits in the opposite direction and
1922bdd1243dSDimitry Andric // then move registers around to get the correct end result.
1923bdd1243dSDimitry Andric if (ShiftLeft && (ShiftAmt % 8) >= 6) {
1924bdd1243dSDimitry Andric // Left shift modulo 6 or 7.
1925bdd1243dSDimitry Andric
1926bdd1243dSDimitry Andric // Create a slice of the registers we're going to modify, to ease working
1927bdd1243dSDimitry Andric // with them.
1928bdd1243dSDimitry Andric size_t ShiftRegsOffset = ShiftAmt / 8;
1929bdd1243dSDimitry Andric size_t ShiftRegsSize = Regs.size() - ShiftRegsOffset;
1930bdd1243dSDimitry Andric MutableArrayRef<std::pair<Register, int>> ShiftRegs =
1931bdd1243dSDimitry Andric Regs.slice(ShiftRegsOffset, ShiftRegsSize);
1932bdd1243dSDimitry Andric
1933bdd1243dSDimitry Andric // Shift one to the right, keeping the least significant bit as the carry
1934bdd1243dSDimitry Andric // bit.
1935bdd1243dSDimitry Andric insertMultibyteShift(MI, BB, ShiftRegs, ISD::SRL, 1);
1936bdd1243dSDimitry Andric
1937bdd1243dSDimitry Andric // Rotate the least significant bit from the carry bit into a new register
1938bdd1243dSDimitry Andric // (that starts out zero).
1939bdd1243dSDimitry Andric Register LowByte = MRI.createVirtualRegister(&AVR::GPR8RegClass);
1940bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::RORRd), LowByte).addReg(ZeroReg);
1941bdd1243dSDimitry Andric
1942bdd1243dSDimitry Andric // Shift one more to the right if this is a modulo-6 shift.
1943bdd1243dSDimitry Andric if (ShiftAmt % 8 == 6) {
1944bdd1243dSDimitry Andric insertMultibyteShift(MI, BB, ShiftRegs, ISD::SRL, 1);
1945bdd1243dSDimitry Andric Register NewLowByte = MRI.createVirtualRegister(&AVR::GPR8RegClass);
1946bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::RORRd), NewLowByte).addReg(LowByte);
1947bdd1243dSDimitry Andric LowByte = NewLowByte;
1948bdd1243dSDimitry Andric }
1949bdd1243dSDimitry Andric
1950bdd1243dSDimitry Andric // Move all registers to the left, zeroing the bottom registers as needed.
1951bdd1243dSDimitry Andric for (size_t I = 0; I < Regs.size(); I++) {
1952bdd1243dSDimitry Andric int ShiftRegsIdx = I + 1;
1953bdd1243dSDimitry Andric if (ShiftRegsIdx < (int)ShiftRegs.size()) {
1954bdd1243dSDimitry Andric Regs[I] = ShiftRegs[ShiftRegsIdx];
1955bdd1243dSDimitry Andric } else if (ShiftRegsIdx == (int)ShiftRegs.size()) {
1956bdd1243dSDimitry Andric Regs[I] = std::pair(LowByte, 0);
1957bdd1243dSDimitry Andric } else {
1958bdd1243dSDimitry Andric Regs[I] = std::pair(ZeroReg, 0);
1959bdd1243dSDimitry Andric }
1960bdd1243dSDimitry Andric }
1961bdd1243dSDimitry Andric
1962bdd1243dSDimitry Andric return;
1963bdd1243dSDimitry Andric }
1964bdd1243dSDimitry Andric
1965bdd1243dSDimitry Andric // Right shift modulo 6 or 7.
1966bdd1243dSDimitry Andric if (!ShiftLeft && (ShiftAmt % 8) >= 6) {
1967bdd1243dSDimitry Andric // Create a view on the registers we're going to modify, to ease working
1968bdd1243dSDimitry Andric // with them.
1969bdd1243dSDimitry Andric size_t ShiftRegsSize = Regs.size() - (ShiftAmt / 8);
1970bdd1243dSDimitry Andric MutableArrayRef<std::pair<Register, int>> ShiftRegs =
1971bdd1243dSDimitry Andric Regs.slice(0, ShiftRegsSize);
1972bdd1243dSDimitry Andric
1973bdd1243dSDimitry Andric // Shift one to the left.
1974bdd1243dSDimitry Andric insertMultibyteShift(MI, BB, ShiftRegs, ISD::SHL, 1);
1975bdd1243dSDimitry Andric
1976bdd1243dSDimitry Andric // Sign or zero extend the most significant register into a new register.
1977bdd1243dSDimitry Andric // The HighByte is the byte that still has one (or two) bits from the
1978bdd1243dSDimitry Andric // original value. The ExtByte is purely a zero/sign extend byte (all bits
1979bdd1243dSDimitry Andric // are either 0 or 1).
1980bdd1243dSDimitry Andric Register HighByte = MRI.createVirtualRegister(&AVR::GPR8RegClass);
1981bdd1243dSDimitry Andric Register ExtByte = 0;
1982bdd1243dSDimitry Andric if (ArithmeticShift) {
1983bdd1243dSDimitry Andric // Sign-extend bit that was shifted out last.
1984bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::SBCRdRr), HighByte)
1985bdd1243dSDimitry Andric .addReg(HighByte, RegState::Undef)
1986bdd1243dSDimitry Andric .addReg(HighByte, RegState::Undef);
1987bdd1243dSDimitry Andric ExtByte = HighByte;
1988bdd1243dSDimitry Andric // The highest bit of the original value is the same as the zero-extend
1989bdd1243dSDimitry Andric // byte, so HighByte and ExtByte are the same.
1990bdd1243dSDimitry Andric } else {
1991bdd1243dSDimitry Andric // Use the zero register for zero extending.
1992bdd1243dSDimitry Andric ExtByte = ZeroReg;
1993bdd1243dSDimitry Andric // Rotate most significant bit into a new register (that starts out zero).
1994bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::ADCRdRr), HighByte)
1995bdd1243dSDimitry Andric .addReg(ExtByte)
1996bdd1243dSDimitry Andric .addReg(ExtByte);
1997bdd1243dSDimitry Andric }
1998bdd1243dSDimitry Andric
1999bdd1243dSDimitry Andric // Shift one more to the left for modulo 6 shifts.
2000bdd1243dSDimitry Andric if (ShiftAmt % 8 == 6) {
2001bdd1243dSDimitry Andric insertMultibyteShift(MI, BB, ShiftRegs, ISD::SHL, 1);
2002bdd1243dSDimitry Andric // Shift the topmost bit into the HighByte.
2003bdd1243dSDimitry Andric Register NewExt = MRI.createVirtualRegister(&AVR::GPR8RegClass);
2004bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::ADCRdRr), NewExt)
2005bdd1243dSDimitry Andric .addReg(HighByte)
2006bdd1243dSDimitry Andric .addReg(HighByte);
2007bdd1243dSDimitry Andric HighByte = NewExt;
2008bdd1243dSDimitry Andric }
2009bdd1243dSDimitry Andric
2010bdd1243dSDimitry Andric // Move all to the right, while sign or zero extending.
2011bdd1243dSDimitry Andric for (int I = Regs.size() - 1; I >= 0; I--) {
2012bdd1243dSDimitry Andric int ShiftRegsIdx = I - (Regs.size() - ShiftRegs.size()) - 1;
2013bdd1243dSDimitry Andric if (ShiftRegsIdx >= 0) {
2014bdd1243dSDimitry Andric Regs[I] = ShiftRegs[ShiftRegsIdx];
2015bdd1243dSDimitry Andric } else if (ShiftRegsIdx == -1) {
2016bdd1243dSDimitry Andric Regs[I] = std::pair(HighByte, 0);
2017bdd1243dSDimitry Andric } else {
2018bdd1243dSDimitry Andric Regs[I] = std::pair(ExtByte, 0);
2019bdd1243dSDimitry Andric }
2020bdd1243dSDimitry Andric }
2021bdd1243dSDimitry Andric
2022bdd1243dSDimitry Andric return;
2023bdd1243dSDimitry Andric }
2024bdd1243dSDimitry Andric
2025bdd1243dSDimitry Andric // For shift amounts of at least one register, simply rename the registers and
2026bdd1243dSDimitry Andric // zero the bottom registers.
2027bdd1243dSDimitry Andric while (ShiftLeft && ShiftAmt >= 8) {
2028bdd1243dSDimitry Andric // Move all registers one to the left.
2029bdd1243dSDimitry Andric for (size_t I = 0; I < Regs.size() - 1; I++) {
2030bdd1243dSDimitry Andric Regs[I] = Regs[I + 1];
2031bdd1243dSDimitry Andric }
2032bdd1243dSDimitry Andric
2033bdd1243dSDimitry Andric // Zero the least significant register.
2034bdd1243dSDimitry Andric Regs[Regs.size() - 1] = std::pair(ZeroReg, 0);
2035bdd1243dSDimitry Andric
2036bdd1243dSDimitry Andric // Continue shifts with the leftover registers.
2037bdd1243dSDimitry Andric Regs = Regs.drop_back(1);
2038bdd1243dSDimitry Andric
2039bdd1243dSDimitry Andric ShiftAmt -= 8;
2040bdd1243dSDimitry Andric }
2041bdd1243dSDimitry Andric
2042bdd1243dSDimitry Andric // And again, the same for right shifts.
2043bdd1243dSDimitry Andric Register ShrExtendReg = 0;
2044bdd1243dSDimitry Andric if (!ShiftLeft && ShiftAmt >= 8) {
2045bdd1243dSDimitry Andric if (ArithmeticShift) {
2046bdd1243dSDimitry Andric // Sign extend the most significant register into ShrExtendReg.
2047bdd1243dSDimitry Andric ShrExtendReg = MRI.createVirtualRegister(&AVR::GPR8RegClass);
2048bdd1243dSDimitry Andric Register Tmp = MRI.createVirtualRegister(&AVR::GPR8RegClass);
2049bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::ADDRdRr), Tmp)
2050bdd1243dSDimitry Andric .addReg(Regs[0].first, 0, Regs[0].second)
2051bdd1243dSDimitry Andric .addReg(Regs[0].first, 0, Regs[0].second);
2052bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::SBCRdRr), ShrExtendReg)
2053bdd1243dSDimitry Andric .addReg(Tmp)
2054bdd1243dSDimitry Andric .addReg(Tmp);
2055bdd1243dSDimitry Andric } else {
2056bdd1243dSDimitry Andric ShrExtendReg = ZeroReg;
2057bdd1243dSDimitry Andric }
2058bdd1243dSDimitry Andric for (; ShiftAmt >= 8; ShiftAmt -= 8) {
2059bdd1243dSDimitry Andric // Move all registers one to the right.
2060bdd1243dSDimitry Andric for (size_t I = Regs.size() - 1; I != 0; I--) {
2061bdd1243dSDimitry Andric Regs[I] = Regs[I - 1];
2062bdd1243dSDimitry Andric }
2063bdd1243dSDimitry Andric
2064bdd1243dSDimitry Andric // Zero or sign extend the most significant register.
2065bdd1243dSDimitry Andric Regs[0] = std::pair(ShrExtendReg, 0);
2066bdd1243dSDimitry Andric
2067bdd1243dSDimitry Andric // Continue shifts with the leftover registers.
2068bdd1243dSDimitry Andric Regs = Regs.drop_front(1);
2069bdd1243dSDimitry Andric }
2070bdd1243dSDimitry Andric }
2071bdd1243dSDimitry Andric
2072bdd1243dSDimitry Andric // The bigger shifts are already handled above.
2073bdd1243dSDimitry Andric assert((ShiftAmt < 8) && "Unexpect shift amount");
2074bdd1243dSDimitry Andric
2075bdd1243dSDimitry Andric // Shift by four bits, using a complicated swap/eor/andi/eor sequence.
2076bdd1243dSDimitry Andric // It only works for logical shifts because the bits shifted in are all
2077bdd1243dSDimitry Andric // zeroes.
2078bdd1243dSDimitry Andric // To shift a single byte right, it produces code like this:
2079bdd1243dSDimitry Andric // swap r0
2080bdd1243dSDimitry Andric // andi r0, 0x0f
2081bdd1243dSDimitry Andric // For a two-byte (16-bit) shift, it adds the following instructions to shift
2082bdd1243dSDimitry Andric // the upper byte into the lower byte:
2083bdd1243dSDimitry Andric // swap r1
2084bdd1243dSDimitry Andric // eor r0, r1
2085bdd1243dSDimitry Andric // andi r1, 0x0f
2086bdd1243dSDimitry Andric // eor r0, r1
2087bdd1243dSDimitry Andric // For bigger shifts, it repeats the above sequence. For example, for a 3-byte
2088bdd1243dSDimitry Andric // (24-bit) shift it adds:
2089bdd1243dSDimitry Andric // swap r2
2090bdd1243dSDimitry Andric // eor r1, r2
2091bdd1243dSDimitry Andric // andi r2, 0x0f
2092bdd1243dSDimitry Andric // eor r1, r2
2093bdd1243dSDimitry Andric if (!ArithmeticShift && ShiftAmt >= 4) {
2094bdd1243dSDimitry Andric Register Prev = 0;
2095bdd1243dSDimitry Andric for (size_t I = 0; I < Regs.size(); I++) {
2096bdd1243dSDimitry Andric size_t Idx = ShiftLeft ? I : Regs.size() - I - 1;
2097bdd1243dSDimitry Andric Register SwapReg = MRI.createVirtualRegister(&AVR::LD8RegClass);
2098bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::SWAPRd), SwapReg)
2099bdd1243dSDimitry Andric .addReg(Regs[Idx].first, 0, Regs[Idx].second);
2100bdd1243dSDimitry Andric if (I != 0) {
2101bdd1243dSDimitry Andric Register R = MRI.createVirtualRegister(&AVR::GPR8RegClass);
2102bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::EORRdRr), R)
2103bdd1243dSDimitry Andric .addReg(Prev)
2104bdd1243dSDimitry Andric .addReg(SwapReg);
2105bdd1243dSDimitry Andric Prev = R;
2106bdd1243dSDimitry Andric }
2107bdd1243dSDimitry Andric Register AndReg = MRI.createVirtualRegister(&AVR::LD8RegClass);
2108bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::ANDIRdK), AndReg)
2109bdd1243dSDimitry Andric .addReg(SwapReg)
2110bdd1243dSDimitry Andric .addImm(ShiftLeft ? 0xf0 : 0x0f);
2111bdd1243dSDimitry Andric if (I != 0) {
2112bdd1243dSDimitry Andric Register R = MRI.createVirtualRegister(&AVR::GPR8RegClass);
2113bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::EORRdRr), R)
2114bdd1243dSDimitry Andric .addReg(Prev)
2115bdd1243dSDimitry Andric .addReg(AndReg);
2116bdd1243dSDimitry Andric size_t PrevIdx = ShiftLeft ? Idx - 1 : Idx + 1;
2117bdd1243dSDimitry Andric Regs[PrevIdx] = std::pair(R, 0);
2118bdd1243dSDimitry Andric }
2119bdd1243dSDimitry Andric Prev = AndReg;
2120bdd1243dSDimitry Andric Regs[Idx] = std::pair(AndReg, 0);
2121bdd1243dSDimitry Andric }
2122bdd1243dSDimitry Andric ShiftAmt -= 4;
2123bdd1243dSDimitry Andric }
2124bdd1243dSDimitry Andric
2125bdd1243dSDimitry Andric // Shift by one. This is the fallback that always works, and the shift
2126bdd1243dSDimitry Andric // operation that is used for 1, 2, and 3 bit shifts.
2127bdd1243dSDimitry Andric while (ShiftLeft && ShiftAmt) {
2128bdd1243dSDimitry Andric // Shift one to the left.
2129bdd1243dSDimitry Andric for (ssize_t I = Regs.size() - 1; I >= 0; I--) {
2130bdd1243dSDimitry Andric Register Out = MRI.createVirtualRegister(&AVR::GPR8RegClass);
2131bdd1243dSDimitry Andric Register In = Regs[I].first;
2132bdd1243dSDimitry Andric Register InSubreg = Regs[I].second;
2133bdd1243dSDimitry Andric if (I == (ssize_t)Regs.size() - 1) { // first iteration
2134bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::ADDRdRr), Out)
2135bdd1243dSDimitry Andric .addReg(In, 0, InSubreg)
2136bdd1243dSDimitry Andric .addReg(In, 0, InSubreg);
2137bdd1243dSDimitry Andric } else {
2138bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::ADCRdRr), Out)
2139bdd1243dSDimitry Andric .addReg(In, 0, InSubreg)
2140bdd1243dSDimitry Andric .addReg(In, 0, InSubreg);
2141bdd1243dSDimitry Andric }
2142bdd1243dSDimitry Andric Regs[I] = std::pair(Out, 0);
2143bdd1243dSDimitry Andric }
2144bdd1243dSDimitry Andric ShiftAmt--;
2145bdd1243dSDimitry Andric }
2146bdd1243dSDimitry Andric while (!ShiftLeft && ShiftAmt) {
2147bdd1243dSDimitry Andric // Shift one to the right.
2148bdd1243dSDimitry Andric for (size_t I = 0; I < Regs.size(); I++) {
2149bdd1243dSDimitry Andric Register Out = MRI.createVirtualRegister(&AVR::GPR8RegClass);
2150bdd1243dSDimitry Andric Register In = Regs[I].first;
2151bdd1243dSDimitry Andric Register InSubreg = Regs[I].second;
2152bdd1243dSDimitry Andric if (I == 0) {
2153bdd1243dSDimitry Andric unsigned Opc = ArithmeticShift ? AVR::ASRRd : AVR::LSRRd;
2154bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(Opc), Out).addReg(In, 0, InSubreg);
2155bdd1243dSDimitry Andric } else {
2156bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::RORRd), Out).addReg(In, 0, InSubreg);
2157bdd1243dSDimitry Andric }
2158bdd1243dSDimitry Andric Regs[I] = std::pair(Out, 0);
2159bdd1243dSDimitry Andric }
2160bdd1243dSDimitry Andric ShiftAmt--;
2161bdd1243dSDimitry Andric }
2162bdd1243dSDimitry Andric
2163bdd1243dSDimitry Andric if (ShiftAmt != 0) {
2164bdd1243dSDimitry Andric llvm_unreachable("don't know how to shift!"); // sanity check
2165bdd1243dSDimitry Andric }
2166bdd1243dSDimitry Andric }
2167bdd1243dSDimitry Andric
2168bdd1243dSDimitry Andric // Do a wide (32-bit) shift.
2169bdd1243dSDimitry Andric MachineBasicBlock *
insertWideShift(MachineInstr & MI,MachineBasicBlock * BB) const2170bdd1243dSDimitry Andric AVRTargetLowering::insertWideShift(MachineInstr &MI,
2171bdd1243dSDimitry Andric MachineBasicBlock *BB) const {
2172bdd1243dSDimitry Andric const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
2173bdd1243dSDimitry Andric const DebugLoc &dl = MI.getDebugLoc();
2174bdd1243dSDimitry Andric
2175bdd1243dSDimitry Andric // How much to shift to the right (meaning: a negative number indicates a left
2176bdd1243dSDimitry Andric // shift).
2177bdd1243dSDimitry Andric int64_t ShiftAmt = MI.getOperand(4).getImm();
2178bdd1243dSDimitry Andric ISD::NodeType Opc;
2179bdd1243dSDimitry Andric switch (MI.getOpcode()) {
2180bdd1243dSDimitry Andric case AVR::Lsl32:
2181bdd1243dSDimitry Andric Opc = ISD::SHL;
2182bdd1243dSDimitry Andric break;
2183bdd1243dSDimitry Andric case AVR::Lsr32:
2184bdd1243dSDimitry Andric Opc = ISD::SRL;
2185bdd1243dSDimitry Andric break;
2186bdd1243dSDimitry Andric case AVR::Asr32:
2187bdd1243dSDimitry Andric Opc = ISD::SRA;
2188bdd1243dSDimitry Andric break;
2189bdd1243dSDimitry Andric }
2190bdd1243dSDimitry Andric
2191bdd1243dSDimitry Andric // Read the input registers, with the most significant register at index 0.
2192bdd1243dSDimitry Andric std::array<std::pair<Register, int>, 4> Registers = {
2193bdd1243dSDimitry Andric std::pair(MI.getOperand(3).getReg(), AVR::sub_hi),
2194bdd1243dSDimitry Andric std::pair(MI.getOperand(3).getReg(), AVR::sub_lo),
2195bdd1243dSDimitry Andric std::pair(MI.getOperand(2).getReg(), AVR::sub_hi),
2196bdd1243dSDimitry Andric std::pair(MI.getOperand(2).getReg(), AVR::sub_lo),
2197bdd1243dSDimitry Andric };
2198bdd1243dSDimitry Andric
2199bdd1243dSDimitry Andric // Do the shift. The registers are modified in-place.
2200bdd1243dSDimitry Andric insertMultibyteShift(MI, BB, Registers, Opc, ShiftAmt);
2201bdd1243dSDimitry Andric
2202bdd1243dSDimitry Andric // Combine the 8-bit registers into 16-bit register pairs.
2203bdd1243dSDimitry Andric // This done either from LSB to MSB or from MSB to LSB, depending on the
2204bdd1243dSDimitry Andric // shift. It's an optimization so that the register allocator will use the
2205bdd1243dSDimitry Andric // fewest movs possible (which order we use isn't a correctness issue, just an
2206bdd1243dSDimitry Andric // optimization issue).
2207bdd1243dSDimitry Andric // - lsl prefers starting from the most significant byte (2nd case).
2208bdd1243dSDimitry Andric // - lshr prefers starting from the least significant byte (1st case).
2209bdd1243dSDimitry Andric // - for ashr it depends on the number of shifted bytes.
2210bdd1243dSDimitry Andric // Some shift operations still don't get the most optimal mov sequences even
2211bdd1243dSDimitry Andric // with this distinction. TODO: figure out why and try to fix it (but we're
2212bdd1243dSDimitry Andric // already equal to or faster than avr-gcc in all cases except ashr 8).
2213bdd1243dSDimitry Andric if (Opc != ISD::SHL &&
2214bdd1243dSDimitry Andric (Opc != ISD::SRA || (ShiftAmt < 16 || ShiftAmt >= 22))) {
2215bdd1243dSDimitry Andric // Use the resulting registers starting with the least significant byte.
2216bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::REG_SEQUENCE), MI.getOperand(0).getReg())
2217bdd1243dSDimitry Andric .addReg(Registers[3].first, 0, Registers[3].second)
2218bdd1243dSDimitry Andric .addImm(AVR::sub_lo)
2219bdd1243dSDimitry Andric .addReg(Registers[2].first, 0, Registers[2].second)
2220bdd1243dSDimitry Andric .addImm(AVR::sub_hi);
2221bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::REG_SEQUENCE), MI.getOperand(1).getReg())
2222bdd1243dSDimitry Andric .addReg(Registers[1].first, 0, Registers[1].second)
2223bdd1243dSDimitry Andric .addImm(AVR::sub_lo)
2224bdd1243dSDimitry Andric .addReg(Registers[0].first, 0, Registers[0].second)
2225bdd1243dSDimitry Andric .addImm(AVR::sub_hi);
2226bdd1243dSDimitry Andric } else {
2227bdd1243dSDimitry Andric // Use the resulting registers starting with the most significant byte.
2228bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::REG_SEQUENCE), MI.getOperand(1).getReg())
2229bdd1243dSDimitry Andric .addReg(Registers[0].first, 0, Registers[0].second)
2230bdd1243dSDimitry Andric .addImm(AVR::sub_hi)
2231bdd1243dSDimitry Andric .addReg(Registers[1].first, 0, Registers[1].second)
2232bdd1243dSDimitry Andric .addImm(AVR::sub_lo);
2233bdd1243dSDimitry Andric BuildMI(*BB, MI, dl, TII.get(AVR::REG_SEQUENCE), MI.getOperand(0).getReg())
2234bdd1243dSDimitry Andric .addReg(Registers[2].first, 0, Registers[2].second)
2235bdd1243dSDimitry Andric .addImm(AVR::sub_hi)
2236bdd1243dSDimitry Andric .addReg(Registers[3].first, 0, Registers[3].second)
2237bdd1243dSDimitry Andric .addImm(AVR::sub_lo);
2238bdd1243dSDimitry Andric }
2239bdd1243dSDimitry Andric
2240bdd1243dSDimitry Andric // Remove the pseudo instruction.
2241bdd1243dSDimitry Andric MI.eraseFromParent();
2242bdd1243dSDimitry Andric return BB;
2243bdd1243dSDimitry Andric }
2244bdd1243dSDimitry Andric
isCopyMulResult(MachineBasicBlock::iterator const & I)22450b57cec5SDimitry Andric static bool isCopyMulResult(MachineBasicBlock::iterator const &I) {
22460b57cec5SDimitry Andric if (I->getOpcode() == AVR::COPY) {
22478bcb0991SDimitry Andric Register SrcReg = I->getOperand(1).getReg();
22480b57cec5SDimitry Andric return (SrcReg == AVR::R0 || SrcReg == AVR::R1);
22490b57cec5SDimitry Andric }
22500b57cec5SDimitry Andric
22510b57cec5SDimitry Andric return false;
22520b57cec5SDimitry Andric }
22530b57cec5SDimitry Andric
22540b57cec5SDimitry Andric // The mul instructions wreak havock on our zero_reg R1. We need to clear it
22550b57cec5SDimitry Andric // after the result has been evacuated. This is probably not the best way to do
22560b57cec5SDimitry Andric // it, but it works for now.
insertMul(MachineInstr & MI,MachineBasicBlock * BB) const22570b57cec5SDimitry Andric MachineBasicBlock *AVRTargetLowering::insertMul(MachineInstr &MI,
22580b57cec5SDimitry Andric MachineBasicBlock *BB) const {
22590b57cec5SDimitry Andric const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
22600b57cec5SDimitry Andric MachineBasicBlock::iterator I(MI);
22610b57cec5SDimitry Andric ++I; // in any case insert *after* the mul instruction
22620b57cec5SDimitry Andric if (isCopyMulResult(I))
22630b57cec5SDimitry Andric ++I;
22640b57cec5SDimitry Andric if (isCopyMulResult(I))
22650b57cec5SDimitry Andric ++I;
22660b57cec5SDimitry Andric BuildMI(*BB, I, MI.getDebugLoc(), TII.get(AVR::EORRdRr), AVR::R1)
22670b57cec5SDimitry Andric .addReg(AVR::R1)
22680b57cec5SDimitry Andric .addReg(AVR::R1);
22690b57cec5SDimitry Andric return BB;
22700b57cec5SDimitry Andric }
22710b57cec5SDimitry Andric
2272bdd1243dSDimitry Andric // Insert a read from the zero register.
227304eeddc0SDimitry Andric MachineBasicBlock *
insertCopyZero(MachineInstr & MI,MachineBasicBlock * BB) const2274bdd1243dSDimitry Andric AVRTargetLowering::insertCopyZero(MachineInstr &MI,
2275bdd1243dSDimitry Andric MachineBasicBlock *BB) const {
227604eeddc0SDimitry Andric const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
227704eeddc0SDimitry Andric MachineBasicBlock::iterator I(MI);
227804eeddc0SDimitry Andric BuildMI(*BB, I, MI.getDebugLoc(), TII.get(AVR::COPY))
227904eeddc0SDimitry Andric .add(MI.getOperand(0))
2280bdd1243dSDimitry Andric .addReg(Subtarget.getZeroRegister());
228104eeddc0SDimitry Andric MI.eraseFromParent();
228204eeddc0SDimitry Andric return BB;
228304eeddc0SDimitry Andric }
228404eeddc0SDimitry Andric
228581ad6265SDimitry Andric // Lower atomicrmw operation to disable interrupts, do operation, and restore
228681ad6265SDimitry Andric // interrupts. This works because all AVR microcontrollers are single core.
insertAtomicArithmeticOp(MachineInstr & MI,MachineBasicBlock * BB,unsigned Opcode,int Width) const228781ad6265SDimitry Andric MachineBasicBlock *AVRTargetLowering::insertAtomicArithmeticOp(
228881ad6265SDimitry Andric MachineInstr &MI, MachineBasicBlock *BB, unsigned Opcode, int Width) const {
228981ad6265SDimitry Andric MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
229081ad6265SDimitry Andric const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
229181ad6265SDimitry Andric MachineBasicBlock::iterator I(MI);
229281ad6265SDimitry Andric DebugLoc dl = MI.getDebugLoc();
229381ad6265SDimitry Andric
229481ad6265SDimitry Andric // Example instruction sequence, for an atomic 8-bit add:
229581ad6265SDimitry Andric // ldi r25, 5
229681ad6265SDimitry Andric // in r0, SREG
229781ad6265SDimitry Andric // cli
229881ad6265SDimitry Andric // ld r24, X
229981ad6265SDimitry Andric // add r25, r24
230081ad6265SDimitry Andric // st X, r25
230181ad6265SDimitry Andric // out SREG, r0
230281ad6265SDimitry Andric
230381ad6265SDimitry Andric const TargetRegisterClass *RC =
230481ad6265SDimitry Andric (Width == 8) ? &AVR::GPR8RegClass : &AVR::DREGSRegClass;
230581ad6265SDimitry Andric unsigned LoadOpcode = (Width == 8) ? AVR::LDRdPtr : AVR::LDWRdPtr;
230681ad6265SDimitry Andric unsigned StoreOpcode = (Width == 8) ? AVR::STPtrRr : AVR::STWPtrRr;
230781ad6265SDimitry Andric
230881ad6265SDimitry Andric // Disable interrupts.
2309bdd1243dSDimitry Andric BuildMI(*BB, I, dl, TII.get(AVR::INRdA), Subtarget.getTmpRegister())
231081ad6265SDimitry Andric .addImm(Subtarget.getIORegSREG());
231181ad6265SDimitry Andric BuildMI(*BB, I, dl, TII.get(AVR::BCLRs)).addImm(7);
231281ad6265SDimitry Andric
231381ad6265SDimitry Andric // Load the original value.
231481ad6265SDimitry Andric BuildMI(*BB, I, dl, TII.get(LoadOpcode), MI.getOperand(0).getReg())
231581ad6265SDimitry Andric .add(MI.getOperand(1));
231681ad6265SDimitry Andric
231781ad6265SDimitry Andric // Do the arithmetic operation.
231881ad6265SDimitry Andric Register Result = MRI.createVirtualRegister(RC);
231981ad6265SDimitry Andric BuildMI(*BB, I, dl, TII.get(Opcode), Result)
232081ad6265SDimitry Andric .addReg(MI.getOperand(0).getReg())
232181ad6265SDimitry Andric .add(MI.getOperand(2));
232281ad6265SDimitry Andric
232381ad6265SDimitry Andric // Store the result.
232481ad6265SDimitry Andric BuildMI(*BB, I, dl, TII.get(StoreOpcode))
232581ad6265SDimitry Andric .add(MI.getOperand(1))
232681ad6265SDimitry Andric .addReg(Result);
232781ad6265SDimitry Andric
232881ad6265SDimitry Andric // Restore interrupts.
232981ad6265SDimitry Andric BuildMI(*BB, I, dl, TII.get(AVR::OUTARr))
233081ad6265SDimitry Andric .addImm(Subtarget.getIORegSREG())
2331bdd1243dSDimitry Andric .addReg(Subtarget.getTmpRegister());
233281ad6265SDimitry Andric
233381ad6265SDimitry Andric // Remove the pseudo instruction.
233481ad6265SDimitry Andric MI.eraseFromParent();
233581ad6265SDimitry Andric return BB;
233681ad6265SDimitry Andric }
233781ad6265SDimitry Andric
23380b57cec5SDimitry Andric MachineBasicBlock *
EmitInstrWithCustomInserter(MachineInstr & MI,MachineBasicBlock * MBB) const23390b57cec5SDimitry Andric AVRTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
23400b57cec5SDimitry Andric MachineBasicBlock *MBB) const {
23410b57cec5SDimitry Andric int Opc = MI.getOpcode();
234206c3fb27SDimitry Andric const AVRSubtarget &STI = MBB->getParent()->getSubtarget<AVRSubtarget>();
23430b57cec5SDimitry Andric
23440b57cec5SDimitry Andric // Pseudo shift instructions with a non constant shift amount are expanded
23450b57cec5SDimitry Andric // into a loop.
23460b57cec5SDimitry Andric switch (Opc) {
23470b57cec5SDimitry Andric case AVR::Lsl8:
23480b57cec5SDimitry Andric case AVR::Lsl16:
23490b57cec5SDimitry Andric case AVR::Lsr8:
23500b57cec5SDimitry Andric case AVR::Lsr16:
23510b57cec5SDimitry Andric case AVR::Rol8:
23520b57cec5SDimitry Andric case AVR::Rol16:
23530b57cec5SDimitry Andric case AVR::Ror8:
23540b57cec5SDimitry Andric case AVR::Ror16:
23550b57cec5SDimitry Andric case AVR::Asr8:
23560b57cec5SDimitry Andric case AVR::Asr16:
235706c3fb27SDimitry Andric return insertShift(MI, MBB, STI.hasTinyEncoding());
2358bdd1243dSDimitry Andric case AVR::Lsl32:
2359bdd1243dSDimitry Andric case AVR::Lsr32:
2360bdd1243dSDimitry Andric case AVR::Asr32:
2361bdd1243dSDimitry Andric return insertWideShift(MI, MBB);
23620b57cec5SDimitry Andric case AVR::MULRdRr:
23630b57cec5SDimitry Andric case AVR::MULSRdRr:
23640b57cec5SDimitry Andric return insertMul(MI, MBB);
2365bdd1243dSDimitry Andric case AVR::CopyZero:
2366bdd1243dSDimitry Andric return insertCopyZero(MI, MBB);
236781ad6265SDimitry Andric case AVR::AtomicLoadAdd8:
236881ad6265SDimitry Andric return insertAtomicArithmeticOp(MI, MBB, AVR::ADDRdRr, 8);
236981ad6265SDimitry Andric case AVR::AtomicLoadAdd16:
237081ad6265SDimitry Andric return insertAtomicArithmeticOp(MI, MBB, AVR::ADDWRdRr, 16);
237181ad6265SDimitry Andric case AVR::AtomicLoadSub8:
237281ad6265SDimitry Andric return insertAtomicArithmeticOp(MI, MBB, AVR::SUBRdRr, 8);
237381ad6265SDimitry Andric case AVR::AtomicLoadSub16:
237481ad6265SDimitry Andric return insertAtomicArithmeticOp(MI, MBB, AVR::SUBWRdRr, 16);
237581ad6265SDimitry Andric case AVR::AtomicLoadAnd8:
237681ad6265SDimitry Andric return insertAtomicArithmeticOp(MI, MBB, AVR::ANDRdRr, 8);
237781ad6265SDimitry Andric case AVR::AtomicLoadAnd16:
237881ad6265SDimitry Andric return insertAtomicArithmeticOp(MI, MBB, AVR::ANDWRdRr, 16);
237981ad6265SDimitry Andric case AVR::AtomicLoadOr8:
238081ad6265SDimitry Andric return insertAtomicArithmeticOp(MI, MBB, AVR::ORRdRr, 8);
238181ad6265SDimitry Andric case AVR::AtomicLoadOr16:
238281ad6265SDimitry Andric return insertAtomicArithmeticOp(MI, MBB, AVR::ORWRdRr, 16);
238381ad6265SDimitry Andric case AVR::AtomicLoadXor8:
238481ad6265SDimitry Andric return insertAtomicArithmeticOp(MI, MBB, AVR::EORRdRr, 8);
238581ad6265SDimitry Andric case AVR::AtomicLoadXor16:
238681ad6265SDimitry Andric return insertAtomicArithmeticOp(MI, MBB, AVR::EORWRdRr, 16);
23870b57cec5SDimitry Andric }
23880b57cec5SDimitry Andric
23890b57cec5SDimitry Andric assert((Opc == AVR::Select16 || Opc == AVR::Select8) &&
23900b57cec5SDimitry Andric "Unexpected instr type to insert");
23910b57cec5SDimitry Andric
23920b57cec5SDimitry Andric const AVRInstrInfo &TII = (const AVRInstrInfo &)*MI.getParent()
23930b57cec5SDimitry Andric ->getParent()
23940b57cec5SDimitry Andric ->getSubtarget()
23950b57cec5SDimitry Andric .getInstrInfo();
23960b57cec5SDimitry Andric DebugLoc dl = MI.getDebugLoc();
23970b57cec5SDimitry Andric
23980b57cec5SDimitry Andric // To "insert" a SELECT instruction, we insert the diamond
23990b57cec5SDimitry Andric // control-flow pattern. The incoming instruction knows the
24000b57cec5SDimitry Andric // destination vreg to set, the condition code register to branch
24010b57cec5SDimitry Andric // on, the true/false values to select between, and a branch opcode
24020b57cec5SDimitry Andric // to use.
24030b57cec5SDimitry Andric
24040b57cec5SDimitry Andric MachineFunction *MF = MBB->getParent();
24050b57cec5SDimitry Andric const BasicBlock *LLVM_BB = MBB->getBasicBlock();
24060b57cec5SDimitry Andric MachineBasicBlock *FallThrough = MBB->getFallThrough();
24070b57cec5SDimitry Andric
24080b57cec5SDimitry Andric // If the current basic block falls through to another basic block,
24090b57cec5SDimitry Andric // we must insert an unconditional branch to the fallthrough destination
24100b57cec5SDimitry Andric // if we are to insert basic blocks at the prior fallthrough point.
24110b57cec5SDimitry Andric if (FallThrough != nullptr) {
24120b57cec5SDimitry Andric BuildMI(MBB, dl, TII.get(AVR::RJMPk)).addMBB(FallThrough);
24130b57cec5SDimitry Andric }
24140b57cec5SDimitry Andric
24150b57cec5SDimitry Andric MachineBasicBlock *trueMBB = MF->CreateMachineBasicBlock(LLVM_BB);
24160b57cec5SDimitry Andric MachineBasicBlock *falseMBB = MF->CreateMachineBasicBlock(LLVM_BB);
24170b57cec5SDimitry Andric
24180b57cec5SDimitry Andric MachineFunction::iterator I;
2419349cc55cSDimitry Andric for (I = MF->begin(); I != MF->end() && &(*I) != MBB; ++I)
2420349cc55cSDimitry Andric ;
2421349cc55cSDimitry Andric if (I != MF->end())
2422349cc55cSDimitry Andric ++I;
24230b57cec5SDimitry Andric MF->insert(I, trueMBB);
24240b57cec5SDimitry Andric MF->insert(I, falseMBB);
24250b57cec5SDimitry Andric
24265f757f3fSDimitry Andric // Set the call frame size on entry to the new basic blocks.
24275f757f3fSDimitry Andric unsigned CallFrameSize = TII.getCallFrameSizeAt(MI);
24285f757f3fSDimitry Andric trueMBB->setCallFrameSize(CallFrameSize);
24295f757f3fSDimitry Andric falseMBB->setCallFrameSize(CallFrameSize);
24305f757f3fSDimitry Andric
24310b57cec5SDimitry Andric // Transfer remaining instructions and all successors of the current
24320b57cec5SDimitry Andric // block to the block which will contain the Phi node for the
24330b57cec5SDimitry Andric // select.
24340b57cec5SDimitry Andric trueMBB->splice(trueMBB->begin(), MBB,
24350b57cec5SDimitry Andric std::next(MachineBasicBlock::iterator(MI)), MBB->end());
24360b57cec5SDimitry Andric trueMBB->transferSuccessorsAndUpdatePHIs(MBB);
24370b57cec5SDimitry Andric
24380b57cec5SDimitry Andric AVRCC::CondCodes CC = (AVRCC::CondCodes)MI.getOperand(3).getImm();
24390b57cec5SDimitry Andric BuildMI(MBB, dl, TII.getBrCond(CC)).addMBB(trueMBB);
24400b57cec5SDimitry Andric BuildMI(MBB, dl, TII.get(AVR::RJMPk)).addMBB(falseMBB);
24410b57cec5SDimitry Andric MBB->addSuccessor(falseMBB);
24420b57cec5SDimitry Andric MBB->addSuccessor(trueMBB);
24430b57cec5SDimitry Andric
24440b57cec5SDimitry Andric // Unconditionally flow back to the true block
24450b57cec5SDimitry Andric BuildMI(falseMBB, dl, TII.get(AVR::RJMPk)).addMBB(trueMBB);
24460b57cec5SDimitry Andric falseMBB->addSuccessor(trueMBB);
24470b57cec5SDimitry Andric
24480b57cec5SDimitry Andric // Set up the Phi node to determine where we came from
2449349cc55cSDimitry Andric BuildMI(*trueMBB, trueMBB->begin(), dl, TII.get(AVR::PHI),
2450349cc55cSDimitry Andric MI.getOperand(0).getReg())
24510b57cec5SDimitry Andric .addReg(MI.getOperand(1).getReg())
24520b57cec5SDimitry Andric .addMBB(MBB)
24530b57cec5SDimitry Andric .addReg(MI.getOperand(2).getReg())
24540b57cec5SDimitry Andric .addMBB(falseMBB);
24550b57cec5SDimitry Andric
24560b57cec5SDimitry Andric MI.eraseFromParent(); // The pseudo instruction is gone now.
24570b57cec5SDimitry Andric return trueMBB;
24580b57cec5SDimitry Andric }
24590b57cec5SDimitry Andric
24600b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
24610b57cec5SDimitry Andric // Inline Asm Support
24620b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
24630b57cec5SDimitry Andric
24640b57cec5SDimitry Andric AVRTargetLowering::ConstraintType
getConstraintType(StringRef Constraint) const24650b57cec5SDimitry Andric AVRTargetLowering::getConstraintType(StringRef Constraint) const {
24660b57cec5SDimitry Andric if (Constraint.size() == 1) {
24670b57cec5SDimitry Andric // See http://www.nongnu.org/avr-libc/user-manual/inline_asm.html
24680b57cec5SDimitry Andric switch (Constraint[0]) {
24690b57cec5SDimitry Andric default:
24700b57cec5SDimitry Andric break;
24710b57cec5SDimitry Andric case 'a': // Simple upper registers
24720b57cec5SDimitry Andric case 'b': // Base pointer registers pairs
24730b57cec5SDimitry Andric case 'd': // Upper register
24740b57cec5SDimitry Andric case 'l': // Lower registers
24750b57cec5SDimitry Andric case 'e': // Pointer register pairs
24760b57cec5SDimitry Andric case 'q': // Stack pointer register
24770b57cec5SDimitry Andric case 'r': // Any register
24780b57cec5SDimitry Andric case 'w': // Special upper register pairs
24790b57cec5SDimitry Andric return C_RegisterClass;
24800b57cec5SDimitry Andric case 't': // Temporary register
2481349cc55cSDimitry Andric case 'x':
2482349cc55cSDimitry Andric case 'X': // Pointer register pair X
2483349cc55cSDimitry Andric case 'y':
2484349cc55cSDimitry Andric case 'Y': // Pointer register pair Y
2485349cc55cSDimitry Andric case 'z':
2486349cc55cSDimitry Andric case 'Z': // Pointer register pair Z
24870b57cec5SDimitry Andric return C_Register;
24880b57cec5SDimitry Andric case 'Q': // A memory address based on Y or Z pointer with displacement.
24890b57cec5SDimitry Andric return C_Memory;
24900b57cec5SDimitry Andric case 'G': // Floating point constant
24910b57cec5SDimitry Andric case 'I': // 6-bit positive integer constant
24920b57cec5SDimitry Andric case 'J': // 6-bit negative integer constant
24930b57cec5SDimitry Andric case 'K': // Integer constant (Range: 2)
24940b57cec5SDimitry Andric case 'L': // Integer constant (Range: 0)
24950b57cec5SDimitry Andric case 'M': // 8-bit integer constant
24960b57cec5SDimitry Andric case 'N': // Integer constant (Range: -1)
24970b57cec5SDimitry Andric case 'O': // Integer constant (Range: 8, 16, 24)
24980b57cec5SDimitry Andric case 'P': // Integer constant (Range: 1)
24990b57cec5SDimitry Andric case 'R': // Integer constant (Range: -6 to 5)x
25000b57cec5SDimitry Andric return C_Immediate;
25010b57cec5SDimitry Andric }
25020b57cec5SDimitry Andric }
25030b57cec5SDimitry Andric
25040b57cec5SDimitry Andric return TargetLowering::getConstraintType(Constraint);
25050b57cec5SDimitry Andric }
25060b57cec5SDimitry Andric
25075f757f3fSDimitry Andric InlineAsm::ConstraintCode
getInlineAsmMemConstraint(StringRef ConstraintCode) const25080b57cec5SDimitry Andric AVRTargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const {
25090b57cec5SDimitry Andric // Not sure if this is actually the right thing to do, but we got to do
25100b57cec5SDimitry Andric // *something* [agnat]
25110b57cec5SDimitry Andric switch (ConstraintCode[0]) {
25120b57cec5SDimitry Andric case 'Q':
25135f757f3fSDimitry Andric return InlineAsm::ConstraintCode::Q;
25140b57cec5SDimitry Andric }
25150b57cec5SDimitry Andric return TargetLowering::getInlineAsmMemConstraint(ConstraintCode);
25160b57cec5SDimitry Andric }
25170b57cec5SDimitry Andric
25180b57cec5SDimitry Andric AVRTargetLowering::ConstraintWeight
getSingleConstraintMatchWeight(AsmOperandInfo & info,const char * constraint) const25190b57cec5SDimitry Andric AVRTargetLowering::getSingleConstraintMatchWeight(
25200b57cec5SDimitry Andric AsmOperandInfo &info, const char *constraint) const {
25210b57cec5SDimitry Andric ConstraintWeight weight = CW_Invalid;
25220b57cec5SDimitry Andric Value *CallOperandVal = info.CallOperandVal;
25230b57cec5SDimitry Andric
25240b57cec5SDimitry Andric // If we don't have a value, we can't do a match,
25250b57cec5SDimitry Andric // but allow it at the lowest weight.
25260b57cec5SDimitry Andric // (this behaviour has been copied from the ARM backend)
25270b57cec5SDimitry Andric if (!CallOperandVal) {
25280b57cec5SDimitry Andric return CW_Default;
25290b57cec5SDimitry Andric }
25300b57cec5SDimitry Andric
25310b57cec5SDimitry Andric // Look at the constraint type.
25320b57cec5SDimitry Andric switch (*constraint) {
25330b57cec5SDimitry Andric default:
25340b57cec5SDimitry Andric weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint);
25350b57cec5SDimitry Andric break;
25360b57cec5SDimitry Andric case 'd':
25370b57cec5SDimitry Andric case 'r':
25380b57cec5SDimitry Andric case 'l':
25390b57cec5SDimitry Andric weight = CW_Register;
25400b57cec5SDimitry Andric break;
25410b57cec5SDimitry Andric case 'a':
25420b57cec5SDimitry Andric case 'b':
25430b57cec5SDimitry Andric case 'e':
25440b57cec5SDimitry Andric case 'q':
25450b57cec5SDimitry Andric case 't':
25460b57cec5SDimitry Andric case 'w':
2547349cc55cSDimitry Andric case 'x':
2548349cc55cSDimitry Andric case 'X':
2549349cc55cSDimitry Andric case 'y':
2550349cc55cSDimitry Andric case 'Y':
2551349cc55cSDimitry Andric case 'z':
2552349cc55cSDimitry Andric case 'Z':
25530b57cec5SDimitry Andric weight = CW_SpecificReg;
25540b57cec5SDimitry Andric break;
25550b57cec5SDimitry Andric case 'G':
25560b57cec5SDimitry Andric if (const ConstantFP *C = dyn_cast<ConstantFP>(CallOperandVal)) {
25570b57cec5SDimitry Andric if (C->isZero()) {
25580b57cec5SDimitry Andric weight = CW_Constant;
25590b57cec5SDimitry Andric }
25600b57cec5SDimitry Andric }
25610b57cec5SDimitry Andric break;
25620b57cec5SDimitry Andric case 'I':
25630b57cec5SDimitry Andric if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
25640b57cec5SDimitry Andric if (isUInt<6>(C->getZExtValue())) {
25650b57cec5SDimitry Andric weight = CW_Constant;
25660b57cec5SDimitry Andric }
25670b57cec5SDimitry Andric }
25680b57cec5SDimitry Andric break;
25690b57cec5SDimitry Andric case 'J':
25700b57cec5SDimitry Andric if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
25710b57cec5SDimitry Andric if ((C->getSExtValue() >= -63) && (C->getSExtValue() <= 0)) {
25720b57cec5SDimitry Andric weight = CW_Constant;
25730b57cec5SDimitry Andric }
25740b57cec5SDimitry Andric }
25750b57cec5SDimitry Andric break;
25760b57cec5SDimitry Andric case 'K':
25770b57cec5SDimitry Andric if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
25780b57cec5SDimitry Andric if (C->getZExtValue() == 2) {
25790b57cec5SDimitry Andric weight = CW_Constant;
25800b57cec5SDimitry Andric }
25810b57cec5SDimitry Andric }
25820b57cec5SDimitry Andric break;
25830b57cec5SDimitry Andric case 'L':
25840b57cec5SDimitry Andric if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
25850b57cec5SDimitry Andric if (C->getZExtValue() == 0) {
25860b57cec5SDimitry Andric weight = CW_Constant;
25870b57cec5SDimitry Andric }
25880b57cec5SDimitry Andric }
25890b57cec5SDimitry Andric break;
25900b57cec5SDimitry Andric case 'M':
25910b57cec5SDimitry Andric if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
25920b57cec5SDimitry Andric if (isUInt<8>(C->getZExtValue())) {
25930b57cec5SDimitry Andric weight = CW_Constant;
25940b57cec5SDimitry Andric }
25950b57cec5SDimitry Andric }
25960b57cec5SDimitry Andric break;
25970b57cec5SDimitry Andric case 'N':
25980b57cec5SDimitry Andric if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
25990b57cec5SDimitry Andric if (C->getSExtValue() == -1) {
26000b57cec5SDimitry Andric weight = CW_Constant;
26010b57cec5SDimitry Andric }
26020b57cec5SDimitry Andric }
26030b57cec5SDimitry Andric break;
26040b57cec5SDimitry Andric case 'O':
26050b57cec5SDimitry Andric if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
26060b57cec5SDimitry Andric if ((C->getZExtValue() == 8) || (C->getZExtValue() == 16) ||
26070b57cec5SDimitry Andric (C->getZExtValue() == 24)) {
26080b57cec5SDimitry Andric weight = CW_Constant;
26090b57cec5SDimitry Andric }
26100b57cec5SDimitry Andric }
26110b57cec5SDimitry Andric break;
26120b57cec5SDimitry Andric case 'P':
26130b57cec5SDimitry Andric if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
26140b57cec5SDimitry Andric if (C->getZExtValue() == 1) {
26150b57cec5SDimitry Andric weight = CW_Constant;
26160b57cec5SDimitry Andric }
26170b57cec5SDimitry Andric }
26180b57cec5SDimitry Andric break;
26190b57cec5SDimitry Andric case 'R':
26200b57cec5SDimitry Andric if (const ConstantInt *C = dyn_cast<ConstantInt>(CallOperandVal)) {
26210b57cec5SDimitry Andric if ((C->getSExtValue() >= -6) && (C->getSExtValue() <= 5)) {
26220b57cec5SDimitry Andric weight = CW_Constant;
26230b57cec5SDimitry Andric }
26240b57cec5SDimitry Andric }
26250b57cec5SDimitry Andric break;
26260b57cec5SDimitry Andric case 'Q':
26270b57cec5SDimitry Andric weight = CW_Memory;
26280b57cec5SDimitry Andric break;
26290b57cec5SDimitry Andric }
26300b57cec5SDimitry Andric
26310b57cec5SDimitry Andric return weight;
26320b57cec5SDimitry Andric }
26330b57cec5SDimitry Andric
26340b57cec5SDimitry Andric std::pair<unsigned, const TargetRegisterClass *>
getRegForInlineAsmConstraint(const TargetRegisterInfo * TRI,StringRef Constraint,MVT VT) const26350b57cec5SDimitry Andric AVRTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
26360b57cec5SDimitry Andric StringRef Constraint,
26370b57cec5SDimitry Andric MVT VT) const {
26380b57cec5SDimitry Andric if (Constraint.size() == 1) {
26390b57cec5SDimitry Andric switch (Constraint[0]) {
26400b57cec5SDimitry Andric case 'a': // Simple upper registers r16..r23.
2641fe6060f1SDimitry Andric if (VT == MVT::i8)
26420b57cec5SDimitry Andric return std::make_pair(0U, &AVR::LD8loRegClass);
2643fe6060f1SDimitry Andric else if (VT == MVT::i16)
2644fe6060f1SDimitry Andric return std::make_pair(0U, &AVR::DREGSLD8loRegClass);
2645fe6060f1SDimitry Andric break;
26460b57cec5SDimitry Andric case 'b': // Base pointer registers: y, z.
2647fe6060f1SDimitry Andric if (VT == MVT::i8 || VT == MVT::i16)
26480b57cec5SDimitry Andric return std::make_pair(0U, &AVR::PTRDISPREGSRegClass);
2649fe6060f1SDimitry Andric break;
26500b57cec5SDimitry Andric case 'd': // Upper registers r16..r31.
2651fe6060f1SDimitry Andric if (VT == MVT::i8)
26520b57cec5SDimitry Andric return std::make_pair(0U, &AVR::LD8RegClass);
2653fe6060f1SDimitry Andric else if (VT == MVT::i16)
2654fe6060f1SDimitry Andric return std::make_pair(0U, &AVR::DLDREGSRegClass);
2655fe6060f1SDimitry Andric break;
26560b57cec5SDimitry Andric case 'l': // Lower registers r0..r15.
2657fe6060f1SDimitry Andric if (VT == MVT::i8)
26580b57cec5SDimitry Andric return std::make_pair(0U, &AVR::GPR8loRegClass);
2659fe6060f1SDimitry Andric else if (VT == MVT::i16)
2660fe6060f1SDimitry Andric return std::make_pair(0U, &AVR::DREGSloRegClass);
2661fe6060f1SDimitry Andric break;
26620b57cec5SDimitry Andric case 'e': // Pointer register pairs: x, y, z.
2663fe6060f1SDimitry Andric if (VT == MVT::i8 || VT == MVT::i16)
26640b57cec5SDimitry Andric return std::make_pair(0U, &AVR::PTRREGSRegClass);
2665fe6060f1SDimitry Andric break;
26660b57cec5SDimitry Andric case 'q': // Stack pointer register: SPH:SPL.
26670b57cec5SDimitry Andric return std::make_pair(0U, &AVR::GPRSPRegClass);
26680b57cec5SDimitry Andric case 'r': // Any register: r0..r31.
26690b57cec5SDimitry Andric if (VT == MVT::i8)
26700b57cec5SDimitry Andric return std::make_pair(0U, &AVR::GPR8RegClass);
2671fe6060f1SDimitry Andric else if (VT == MVT::i16)
26720b57cec5SDimitry Andric return std::make_pair(0U, &AVR::DREGSRegClass);
2673fe6060f1SDimitry Andric break;
26740b57cec5SDimitry Andric case 't': // Temporary register: r0.
2675fe6060f1SDimitry Andric if (VT == MVT::i8)
2676bdd1243dSDimitry Andric return std::make_pair(unsigned(Subtarget.getTmpRegister()),
2677bdd1243dSDimitry Andric &AVR::GPR8RegClass);
2678fe6060f1SDimitry Andric break;
26790b57cec5SDimitry Andric case 'w': // Special upper register pairs: r24, r26, r28, r30.
2680fe6060f1SDimitry Andric if (VT == MVT::i8 || VT == MVT::i16)
26810b57cec5SDimitry Andric return std::make_pair(0U, &AVR::IWREGSRegClass);
2682fe6060f1SDimitry Andric break;
26830b57cec5SDimitry Andric case 'x': // Pointer register pair X: r27:r26.
26840b57cec5SDimitry Andric case 'X':
2685fe6060f1SDimitry Andric if (VT == MVT::i8 || VT == MVT::i16)
26860b57cec5SDimitry Andric return std::make_pair(unsigned(AVR::R27R26), &AVR::PTRREGSRegClass);
2687fe6060f1SDimitry Andric break;
26880b57cec5SDimitry Andric case 'y': // Pointer register pair Y: r29:r28.
26890b57cec5SDimitry Andric case 'Y':
2690fe6060f1SDimitry Andric if (VT == MVT::i8 || VT == MVT::i16)
26910b57cec5SDimitry Andric return std::make_pair(unsigned(AVR::R29R28), &AVR::PTRREGSRegClass);
2692fe6060f1SDimitry Andric break;
26930b57cec5SDimitry Andric case 'z': // Pointer register pair Z: r31:r30.
26940b57cec5SDimitry Andric case 'Z':
2695fe6060f1SDimitry Andric if (VT == MVT::i8 || VT == MVT::i16)
26960b57cec5SDimitry Andric return std::make_pair(unsigned(AVR::R31R30), &AVR::PTRREGSRegClass);
2697fe6060f1SDimitry Andric break;
26980b57cec5SDimitry Andric default:
26990b57cec5SDimitry Andric break;
27000b57cec5SDimitry Andric }
27010b57cec5SDimitry Andric }
27020b57cec5SDimitry Andric
27030b57cec5SDimitry Andric return TargetLowering::getRegForInlineAsmConstraint(
27040b57cec5SDimitry Andric Subtarget.getRegisterInfo(), Constraint, VT);
27050b57cec5SDimitry Andric }
27060b57cec5SDimitry Andric
LowerAsmOperandForConstraint(SDValue Op,StringRef Constraint,std::vector<SDValue> & Ops,SelectionDAG & DAG) const27070b57cec5SDimitry Andric void AVRTargetLowering::LowerAsmOperandForConstraint(SDValue Op,
27085f757f3fSDimitry Andric StringRef Constraint,
27090b57cec5SDimitry Andric std::vector<SDValue> &Ops,
27100b57cec5SDimitry Andric SelectionDAG &DAG) const {
271104eeddc0SDimitry Andric SDValue Result;
27120b57cec5SDimitry Andric SDLoc DL(Op);
27130b57cec5SDimitry Andric EVT Ty = Op.getValueType();
27140b57cec5SDimitry Andric
27150b57cec5SDimitry Andric // Currently only support length 1 constraints.
27165f757f3fSDimitry Andric if (Constraint.size() != 1) {
27170b57cec5SDimitry Andric return;
27180b57cec5SDimitry Andric }
27190b57cec5SDimitry Andric
27200b57cec5SDimitry Andric char ConstraintLetter = Constraint[0];
27210b57cec5SDimitry Andric switch (ConstraintLetter) {
27220b57cec5SDimitry Andric default:
27230b57cec5SDimitry Andric break;
27240b57cec5SDimitry Andric // Deal with integers first:
27250b57cec5SDimitry Andric case 'I':
27260b57cec5SDimitry Andric case 'J':
27270b57cec5SDimitry Andric case 'K':
27280b57cec5SDimitry Andric case 'L':
27290b57cec5SDimitry Andric case 'M':
27300b57cec5SDimitry Andric case 'N':
27310b57cec5SDimitry Andric case 'O':
27320b57cec5SDimitry Andric case 'P':
27330b57cec5SDimitry Andric case 'R': {
27340b57cec5SDimitry Andric const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op);
27350b57cec5SDimitry Andric if (!C) {
27360b57cec5SDimitry Andric return;
27370b57cec5SDimitry Andric }
27380b57cec5SDimitry Andric
27390b57cec5SDimitry Andric int64_t CVal64 = C->getSExtValue();
27400b57cec5SDimitry Andric uint64_t CUVal64 = C->getZExtValue();
27410b57cec5SDimitry Andric switch (ConstraintLetter) {
27420b57cec5SDimitry Andric case 'I': // 0..63
27430b57cec5SDimitry Andric if (!isUInt<6>(CUVal64))
27440b57cec5SDimitry Andric return;
27450b57cec5SDimitry Andric Result = DAG.getTargetConstant(CUVal64, DL, Ty);
27460b57cec5SDimitry Andric break;
27470b57cec5SDimitry Andric case 'J': // -63..0
27480b57cec5SDimitry Andric if (CVal64 < -63 || CVal64 > 0)
27490b57cec5SDimitry Andric return;
27500b57cec5SDimitry Andric Result = DAG.getTargetConstant(CVal64, DL, Ty);
27510b57cec5SDimitry Andric break;
27520b57cec5SDimitry Andric case 'K': // 2
27530b57cec5SDimitry Andric if (CUVal64 != 2)
27540b57cec5SDimitry Andric return;
27550b57cec5SDimitry Andric Result = DAG.getTargetConstant(CUVal64, DL, Ty);
27560b57cec5SDimitry Andric break;
27570b57cec5SDimitry Andric case 'L': // 0
27580b57cec5SDimitry Andric if (CUVal64 != 0)
27590b57cec5SDimitry Andric return;
27600b57cec5SDimitry Andric Result = DAG.getTargetConstant(CUVal64, DL, Ty);
27610b57cec5SDimitry Andric break;
27620b57cec5SDimitry Andric case 'M': // 0..255
27630b57cec5SDimitry Andric if (!isUInt<8>(CUVal64))
27640b57cec5SDimitry Andric return;
27650b57cec5SDimitry Andric // i8 type may be printed as a negative number,
27660b57cec5SDimitry Andric // e.g. 254 would be printed as -2,
27670b57cec5SDimitry Andric // so we force it to i16 at least.
27680b57cec5SDimitry Andric if (Ty.getSimpleVT() == MVT::i8) {
27690b57cec5SDimitry Andric Ty = MVT::i16;
27700b57cec5SDimitry Andric }
27710b57cec5SDimitry Andric Result = DAG.getTargetConstant(CUVal64, DL, Ty);
27720b57cec5SDimitry Andric break;
27730b57cec5SDimitry Andric case 'N': // -1
27740b57cec5SDimitry Andric if (CVal64 != -1)
27750b57cec5SDimitry Andric return;
27760b57cec5SDimitry Andric Result = DAG.getTargetConstant(CVal64, DL, Ty);
27770b57cec5SDimitry Andric break;
27780b57cec5SDimitry Andric case 'O': // 8, 16, 24
27790b57cec5SDimitry Andric if (CUVal64 != 8 && CUVal64 != 16 && CUVal64 != 24)
27800b57cec5SDimitry Andric return;
27810b57cec5SDimitry Andric Result = DAG.getTargetConstant(CUVal64, DL, Ty);
27820b57cec5SDimitry Andric break;
27830b57cec5SDimitry Andric case 'P': // 1
27840b57cec5SDimitry Andric if (CUVal64 != 1)
27850b57cec5SDimitry Andric return;
27860b57cec5SDimitry Andric Result = DAG.getTargetConstant(CUVal64, DL, Ty);
27870b57cec5SDimitry Andric break;
27880b57cec5SDimitry Andric case 'R': // -6..5
27890b57cec5SDimitry Andric if (CVal64 < -6 || CVal64 > 5)
27900b57cec5SDimitry Andric return;
27910b57cec5SDimitry Andric Result = DAG.getTargetConstant(CVal64, DL, Ty);
27920b57cec5SDimitry Andric break;
27930b57cec5SDimitry Andric }
27940b57cec5SDimitry Andric
27950b57cec5SDimitry Andric break;
27960b57cec5SDimitry Andric }
27970b57cec5SDimitry Andric case 'G':
27980b57cec5SDimitry Andric const ConstantFPSDNode *FC = dyn_cast<ConstantFPSDNode>(Op);
27990b57cec5SDimitry Andric if (!FC || !FC->isZero())
28000b57cec5SDimitry Andric return;
28010b57cec5SDimitry Andric // Soften float to i8 0
28020b57cec5SDimitry Andric Result = DAG.getTargetConstant(0, DL, MVT::i8);
28030b57cec5SDimitry Andric break;
28040b57cec5SDimitry Andric }
28050b57cec5SDimitry Andric
28060b57cec5SDimitry Andric if (Result.getNode()) {
28070b57cec5SDimitry Andric Ops.push_back(Result);
28080b57cec5SDimitry Andric return;
28090b57cec5SDimitry Andric }
28100b57cec5SDimitry Andric
28110b57cec5SDimitry Andric return TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
28120b57cec5SDimitry Andric }
28130b57cec5SDimitry Andric
getRegisterByName(const char * RegName,LLT VT,const MachineFunction & MF) const2814480093f4SDimitry Andric Register AVRTargetLowering::getRegisterByName(const char *RegName, LLT VT,
28158bcb0991SDimitry Andric const MachineFunction &MF) const {
28168bcb0991SDimitry Andric Register Reg;
28170b57cec5SDimitry Andric
2818480093f4SDimitry Andric if (VT == LLT::scalar(8)) {
28190b57cec5SDimitry Andric Reg = StringSwitch<unsigned>(RegName)
2820fe6060f1SDimitry Andric .Case("r0", AVR::R0)
2821fe6060f1SDimitry Andric .Case("r1", AVR::R1)
28220b57cec5SDimitry Andric .Default(0);
28230b57cec5SDimitry Andric } else {
28240b57cec5SDimitry Andric Reg = StringSwitch<unsigned>(RegName)
2825fe6060f1SDimitry Andric .Case("r0", AVR::R1R0)
2826fe6060f1SDimitry Andric .Case("sp", AVR::SP)
28270b57cec5SDimitry Andric .Default(0);
28280b57cec5SDimitry Andric }
28290b57cec5SDimitry Andric
28300b57cec5SDimitry Andric if (Reg)
28310b57cec5SDimitry Andric return Reg;
28320b57cec5SDimitry Andric
2833fe6060f1SDimitry Andric report_fatal_error(
2834fe6060f1SDimitry Andric Twine("Invalid register name \"" + StringRef(RegName) + "\"."));
28350b57cec5SDimitry Andric }
28360b57cec5SDimitry Andric
28370b57cec5SDimitry Andric } // end of namespace llvm
2838