| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 1 | //===-- ARMISelDAGToDAG.cpp - A dag to dag inst selector for ARM ----------===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
| Chris Lattner | f3ebc3f | 2007-12-29 20:36:04 +0000 | [diff] [blame] | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 | // | 
|  | 10 | // This file defines an instruction selector for the ARM target. | 
|  | 11 | // | 
|  | 12 | //===----------------------------------------------------------------------===// | 
|  | 13 |  | 
| Dale Johannesen | d679ff7 | 2010-06-03 21:09:53 +0000 | [diff] [blame] | 14 | #define DEBUG_TYPE "arm-isel" | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 15 | #include "ARM.h" | 
| Evan Cheng | d502173 | 2008-12-10 21:54:21 +0000 | [diff] [blame] | 16 | #include "ARMAddressingModes.h" | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 17 | #include "ARMTargetMachine.h" | 
| Rafael Espindola | 75269be | 2006-07-16 01:02:57 +0000 | [diff] [blame] | 18 | #include "llvm/CallingConv.h" | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 19 | #include "llvm/Constants.h" | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 20 | #include "llvm/DerivedTypes.h" | 
|  | 21 | #include "llvm/Function.h" | 
|  | 22 | #include "llvm/Intrinsics.h" | 
| Owen Anderson | b6b2530 | 2009-07-14 23:09:55 +0000 | [diff] [blame] | 23 | #include "llvm/LLVMContext.h" | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 24 | #include "llvm/CodeGen/MachineFrameInfo.h" | 
|  | 25 | #include "llvm/CodeGen/MachineFunction.h" | 
|  | 26 | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | 27 | #include "llvm/CodeGen/SelectionDAG.h" | 
|  | 28 | #include "llvm/CodeGen/SelectionDAGISel.h" | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 29 | #include "llvm/Target/TargetLowering.h" | 
| Chris Lattner | 1c10821 | 2007-05-03 00:32:00 +0000 | [diff] [blame] | 30 | #include "llvm/Target/TargetOptions.h" | 
| Evan Cheng | 8e6b40a | 2010-05-04 20:39:49 +0000 | [diff] [blame] | 31 | #include "llvm/Support/CommandLine.h" | 
| Chris Lattner | 1770fb8 | 2008-02-03 05:43:57 +0000 | [diff] [blame] | 32 | #include "llvm/Support/Compiler.h" | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 33 | #include "llvm/Support/Debug.h" | 
| Torok Edwin | fb8d6d5 | 2009-07-08 20:53:28 +0000 | [diff] [blame] | 34 | #include "llvm/Support/ErrorHandling.h" | 
|  | 35 | #include "llvm/Support/raw_ostream.h" | 
|  | 36 |  | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 37 | using namespace llvm; | 
|  | 38 |  | 
| Evan Cheng | 59069ec | 2010-07-30 23:33:54 +0000 | [diff] [blame] | 39 | static cl::opt<bool> | 
|  | 40 | DisableShifterOp("disable-shifter-op", cl::Hidden, | 
|  | 41 | cl::desc("Disable isel of shifter-op"), | 
|  | 42 | cl::init(false)); | 
|  | 43 |  | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 44 | //===--------------------------------------------------------------------===// | 
|  | 45 | /// ARMDAGToDAGISel - ARM specific code to select ARM machine | 
|  | 46 | /// instructions for SelectionDAG operations. | 
|  | 47 | /// | 
|  | 48 | namespace { | 
| Jim Grosbach | 0860520 | 2010-09-29 19:03:54 +0000 | [diff] [blame] | 49 |  | 
|  | 50 | enum AddrMode2Type { | 
|  | 51 | AM2_BASE, // Simple AM2 (+-imm12) | 
|  | 52 | AM2_SHOP  // Shifter-op AM2 | 
|  | 53 | }; | 
|  | 54 |  | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 55 | class ARMDAGToDAGISel : public SelectionDAGISel { | 
| Anton Korobeynikov | 99152f3 | 2009-06-26 21:28:53 +0000 | [diff] [blame] | 56 | ARMBaseTargetMachine &TM; | 
| Evan Cheng | bc0d0ec | 2008-09-18 07:24:33 +0000 | [diff] [blame] | 57 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 58 | /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can | 
|  | 59 | /// make the right decision when generating code for different targets. | 
|  | 60 | const ARMSubtarget *Subtarget; | 
|  | 61 |  | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 62 | public: | 
| Bob Wilson | 2dd957f | 2009-09-28 14:30:20 +0000 | [diff] [blame] | 63 | explicit ARMDAGToDAGISel(ARMBaseTargetMachine &tm, | 
|  | 64 | CodeGenOpt::Level OptLevel) | 
|  | 65 | : SelectionDAGISel(tm, OptLevel), TM(tm), | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 66 | Subtarget(&TM.getSubtarget<ARMSubtarget>()) { | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 67 | } | 
|  | 68 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 69 | virtual const char *getPassName() const { | 
|  | 70 | return "ARM Instruction Selection"; | 
| Anton Korobeynikov | 02bb33c | 2009-06-17 18:13:58 +0000 | [diff] [blame] | 71 | } | 
|  | 72 |  | 
| Bob Wilson | 4facd96 | 2009-10-08 18:51:31 +0000 | [diff] [blame] | 73 | /// getI32Imm - Return a target constant of type i32 with the specified | 
|  | 74 | /// value. | 
| Anton Korobeynikov | 02bb33c | 2009-06-17 18:13:58 +0000 | [diff] [blame] | 75 | inline SDValue getI32Imm(unsigned Imm) { | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 76 | return CurDAG->getTargetConstant(Imm, MVT::i32); | 
| Anton Korobeynikov | 02bb33c | 2009-06-17 18:13:58 +0000 | [diff] [blame] | 77 | } | 
|  | 78 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 79 | SDNode *Select(SDNode *N); | 
| Evan Cheng | 5e73ff2 | 2010-02-15 19:41:07 +0000 | [diff] [blame] | 80 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 81 | bool SelectShifterOperandReg(SDValue N, SDValue &A, | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 82 | SDValue &B, SDValue &C); | 
| Jim Grosbach | 0860520 | 2010-09-29 19:03:54 +0000 | [diff] [blame] | 83 | AddrMode2Type SelectAddrMode2Worker(SDValue N, SDValue &Base, | 
|  | 84 | SDValue &Offset, SDValue &Opc); | 
|  | 85 | bool SelectAddrMode2Base(SDValue N, SDValue &Base, SDValue &Offset, | 
|  | 86 | SDValue &Opc) { | 
|  | 87 | return SelectAddrMode2Worker(N, Base, Offset, Opc) == AM2_BASE; | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | bool SelectAddrMode2ShOp(SDValue N, SDValue &Base, SDValue &Offset, | 
|  | 91 | SDValue &Opc) { | 
|  | 92 | return SelectAddrMode2Worker(N, Base, Offset, Opc) == AM2_SHOP; | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | bool SelectAddrMode2(SDValue N, SDValue &Base, SDValue &Offset, | 
|  | 96 | SDValue &Opc) { | 
|  | 97 | SelectAddrMode2Worker(N, Base, Offset, Opc); | 
|  | 98 | // This always matches one way or another. | 
|  | 99 | return true; | 
|  | 100 | } | 
|  | 101 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 102 | bool SelectAddrMode2Offset(SDNode *Op, SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 103 | SDValue &Offset, SDValue &Opc); | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 104 | bool SelectAddrMode3(SDValue N, SDValue &Base, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 105 | SDValue &Offset, SDValue &Opc); | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 106 | bool SelectAddrMode3Offset(SDNode *Op, SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 107 | SDValue &Offset, SDValue &Opc); | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 108 | bool SelectAddrMode4(SDValue N, SDValue &Addr, SDValue &Mode); | 
|  | 109 | bool SelectAddrMode5(SDValue N, SDValue &Base, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 110 | SDValue &Offset); | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 111 | bool SelectAddrMode6(SDValue N, SDValue &Addr, SDValue &Align); | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 112 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 113 | bool SelectAddrModePC(SDValue N, SDValue &Offset, | 
| Bob Wilson | deb35af | 2009-07-01 23:16:05 +0000 | [diff] [blame] | 114 | SDValue &Label); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 115 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 116 | bool SelectThumbAddrModeRR(SDValue N, SDValue &Base, SDValue &Offset); | 
|  | 117 | bool SelectThumbAddrModeRI5(SDValue N, unsigned Scale, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 118 | SDValue &Base, SDValue &OffImm, | 
|  | 119 | SDValue &Offset); | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 120 | bool SelectThumbAddrModeS1(SDValue N, SDValue &Base, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 121 | SDValue &OffImm, SDValue &Offset); | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 122 | bool SelectThumbAddrModeS2(SDValue N, SDValue &Base, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 123 | SDValue &OffImm, SDValue &Offset); | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 124 | bool SelectThumbAddrModeS4(SDValue N, SDValue &Base, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 125 | SDValue &OffImm, SDValue &Offset); | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 126 | bool SelectThumbAddrModeSP(SDValue N, SDValue &Base, SDValue &OffImm); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 127 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 128 | bool SelectT2ShifterOperandReg(SDValue N, | 
| Evan Cheng | eab9ca7 | 2009-06-27 02:26:13 +0000 | [diff] [blame] | 129 | SDValue &BaseReg, SDValue &Opc); | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 130 | bool SelectT2AddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm); | 
|  | 131 | bool SelectT2AddrModeImm8(SDValue N, SDValue &Base, | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 132 | SDValue &OffImm); | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 133 | bool SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N, | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 134 | SDValue &OffImm); | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 135 | bool SelectT2AddrModeSoReg(SDValue N, SDValue &Base, | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 136 | SDValue &OffReg, SDValue &ShImm); | 
|  | 137 |  | 
| Jakob Stoklund Olesen | e2cbaf6 | 2010-08-17 20:39:04 +0000 | [diff] [blame] | 138 | inline bool Pred_so_imm(SDNode *inN) const { | 
|  | 139 | ConstantSDNode *N = cast<ConstantSDNode>(inN); | 
|  | 140 | return ARM_AM::getSOImmVal(N->getZExtValue()) != -1; | 
|  | 141 | } | 
|  | 142 |  | 
|  | 143 | inline bool Pred_t2_so_imm(SDNode *inN) const { | 
|  | 144 | ConstantSDNode *N = cast<ConstantSDNode>(inN); | 
|  | 145 | return ARM_AM::getT2SOImmVal(N->getZExtValue()) != -1; | 
|  | 146 | } | 
|  | 147 |  | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 148 | // Include the pieces autogenerated from the target description. | 
|  | 149 | #include "ARMGenDAGISel.inc" | 
| Bob Wilson | a2c462b | 2009-05-19 05:53:42 +0000 | [diff] [blame] | 150 |  | 
|  | 151 | private: | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 152 | /// SelectARMIndexedLoad - Indexed (pre/post inc/dec) load matching code for | 
|  | 153 | /// ARM. | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 154 | SDNode *SelectARMIndexedLoad(SDNode *N); | 
|  | 155 | SDNode *SelectT2IndexedLoad(SDNode *N); | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 156 |  | 
| Bob Wilson | 340861d | 2010-03-23 05:25:43 +0000 | [diff] [blame] | 157 | /// SelectVLD - Select NEON load intrinsics.  NumVecs should be | 
|  | 158 | /// 1, 2, 3 or 4.  The opcode arrays specify the instructions used for | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 159 | /// loads of D registers and even subregs and odd subregs of Q registers. | 
| Bob Wilson | 340861d | 2010-03-23 05:25:43 +0000 | [diff] [blame] | 160 | /// For NumVecs <= 2, QOpcodes1 is not used. | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 161 | SDNode *SelectVLD(SDNode *N, unsigned NumVecs, unsigned *DOpcodes, | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 162 | unsigned *QOpcodes0, unsigned *QOpcodes1); | 
|  | 163 |  | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 164 | /// SelectVST - Select NEON store intrinsics.  NumVecs should | 
| Bob Wilson | cc0a2a7 | 2010-03-23 06:20:33 +0000 | [diff] [blame] | 165 | /// be 1, 2, 3 or 4.  The opcode arrays specify the instructions used for | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 166 | /// stores of D registers and even subregs and odd subregs of Q registers. | 
| Bob Wilson | cc0a2a7 | 2010-03-23 06:20:33 +0000 | [diff] [blame] | 167 | /// For NumVecs <= 2, QOpcodes1 is not used. | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 168 | SDNode *SelectVST(SDNode *N, unsigned NumVecs, unsigned *DOpcodes, | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 169 | unsigned *QOpcodes0, unsigned *QOpcodes1); | 
|  | 170 |  | 
| Bob Wilson | 93117bc | 2009-10-14 16:46:45 +0000 | [diff] [blame] | 171 | /// SelectVLDSTLane - Select NEON load/store lane intrinsics.  NumVecs should | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 172 | /// be 2, 3 or 4.  The opcode arrays specify the instructions used for | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 173 | /// load/store of D registers and Q registers. | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 174 | SDNode *SelectVLDSTLane(SDNode *N, bool IsLoad, unsigned NumVecs, | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 175 | unsigned *DOpcodes, unsigned *QOpcodes); | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 176 |  | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 177 | /// SelectVTBL - Select NEON VTBL and VTBX intrinsics.  NumVecs should be 2, | 
|  | 178 | /// 3 or 4.  These are custom-selected so that a REG_SEQUENCE can be | 
|  | 179 | /// generated to force the table registers to be consecutive. | 
|  | 180 | SDNode *SelectVTBL(SDNode *N, bool IsExt, unsigned NumVecs, unsigned Opc); | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 181 |  | 
| Sandeep Patel | 7460e08 | 2009-10-13 20:25:58 +0000 | [diff] [blame] | 182 | /// SelectV6T2BitfieldExtractOp - Select SBFX/UBFX instructions for ARM. | 
| Jim Grosbach | 825cb29 | 2010-04-22 23:24:18 +0000 | [diff] [blame] | 183 | SDNode *SelectV6T2BitfieldExtractOp(SDNode *N, bool isSigned); | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 184 |  | 
| Evan Cheng | b6c7704 | 2009-11-19 21:45:22 +0000 | [diff] [blame] | 185 | /// SelectCMOVOp - Select CMOV instructions for ARM. | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 186 | SDNode *SelectCMOVOp(SDNode *N); | 
|  | 187 | SDNode *SelectT2CMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 188 | ARMCC::CondCodes CCVal, SDValue CCR, | 
|  | 189 | SDValue InFlag); | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 190 | SDNode *SelectARMCMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 191 | ARMCC::CondCodes CCVal, SDValue CCR, | 
|  | 192 | SDValue InFlag); | 
| Jim Grosbach | 5b255c2 | 2010-10-07 00:53:56 +0000 | [diff] [blame] | 193 | SDNode *SelectT2CMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 194 | ARMCC::CondCodes CCVal, SDValue CCR, | 
|  | 195 | SDValue InFlag); | 
| Jim Grosbach | 742adc3 | 2010-10-07 00:42:42 +0000 | [diff] [blame] | 196 | SDNode *SelectARMCMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 197 | ARMCC::CondCodes CCVal, SDValue CCR, | 
|  | 198 | SDValue InFlag); | 
| Evan Cheng | b6c7704 | 2009-11-19 21:45:22 +0000 | [diff] [blame] | 199 |  | 
| Evan Cheng | d85631e | 2010-05-05 18:28:36 +0000 | [diff] [blame] | 200 | SDNode *SelectConcatVector(SDNode *N); | 
|  | 201 |  | 
| Evan Cheng | d9c5536 | 2009-07-02 01:23:32 +0000 | [diff] [blame] | 202 | /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for | 
|  | 203 | /// inline asm expressions. | 
|  | 204 | virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, | 
|  | 205 | char ConstraintCode, | 
|  | 206 | std::vector<SDValue> &OutOps); | 
| Bob Wilson | e6b778d | 2009-10-06 22:01:59 +0000 | [diff] [blame] | 207 |  | 
| Bob Wilson | d8a9a04 | 2010-06-04 00:04:02 +0000 | [diff] [blame] | 208 | // Form pairs of consecutive S, D, or Q registers. | 
|  | 209 | SDNode *PairSRegs(EVT VT, SDValue V0, SDValue V1); | 
| Bob Wilson | e6b778d | 2009-10-06 22:01:59 +0000 | [diff] [blame] | 210 | SDNode *PairDRegs(EVT VT, SDValue V0, SDValue V1); | 
| Evan Cheng | c2ae5f5 | 2010-05-10 17:34:18 +0000 | [diff] [blame] | 211 | SDNode *PairQRegs(EVT VT, SDValue V0, SDValue V1); | 
|  | 212 |  | 
| Bob Wilson | d8a9a04 | 2010-06-04 00:04:02 +0000 | [diff] [blame] | 213 | // Form sequences of 4 consecutive S, D, or Q registers. | 
|  | 214 | SDNode *QuadSRegs(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3); | 
| Evan Cheng | c2ae5f5 | 2010-05-10 17:34:18 +0000 | [diff] [blame] | 215 | SDNode *QuadDRegs(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3); | 
| Evan Cheng | 298e6b8 | 2010-05-16 03:27:48 +0000 | [diff] [blame] | 216 | SDNode *QuadQRegs(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3); | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 217 | }; | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 218 | } | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 219 |  | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 220 | /// isInt32Immediate - This method tests to see if the node is a 32-bit constant | 
|  | 221 | /// operand. If so Imm will receive the 32-bit value. | 
|  | 222 | static bool isInt32Immediate(SDNode *N, unsigned &Imm) { | 
|  | 223 | if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i32) { | 
|  | 224 | Imm = cast<ConstantSDNode>(N)->getZExtValue(); | 
|  | 225 | return true; | 
|  | 226 | } | 
|  | 227 | return false; | 
|  | 228 | } | 
|  | 229 |  | 
|  | 230 | // isInt32Immediate - This method tests to see if a constant operand. | 
|  | 231 | // If so Imm will receive the 32 bit value. | 
|  | 232 | static bool isInt32Immediate(SDValue N, unsigned &Imm) { | 
|  | 233 | return isInt32Immediate(N.getNode(), Imm); | 
|  | 234 | } | 
|  | 235 |  | 
|  | 236 | // isOpcWithIntImmediate - This method tests to see if the node is a specific | 
|  | 237 | // opcode and that it has a immediate integer right operand. | 
|  | 238 | // If so Imm will receive the 32 bit value. | 
|  | 239 | static bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) { | 
|  | 240 | return N->getOpcode() == Opc && | 
|  | 241 | isInt32Immediate(N->getOperand(1).getNode(), Imm); | 
|  | 242 | } | 
|  | 243 |  | 
|  | 244 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 245 | bool ARMDAGToDAGISel::SelectShifterOperandReg(SDValue N, | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 246 | SDValue &BaseReg, | 
|  | 247 | SDValue &ShReg, | 
|  | 248 | SDValue &Opc) { | 
| Evan Cheng | 59069ec | 2010-07-30 23:33:54 +0000 | [diff] [blame] | 249 | if (DisableShifterOp) | 
|  | 250 | return false; | 
|  | 251 |  | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 252 | ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N); | 
|  | 253 |  | 
|  | 254 | // Don't match base register only case. That is matched to a separate | 
|  | 255 | // lower complexity pattern with explicit register operand. | 
|  | 256 | if (ShOpcVal == ARM_AM::no_shift) return false; | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 257 |  | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 258 | BaseReg = N.getOperand(0); | 
|  | 259 | unsigned ShImmVal = 0; | 
|  | 260 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 261 | ShReg = CurDAG->getRegister(0, MVT::i32); | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 262 | ShImmVal = RHS->getZExtValue() & 31; | 
|  | 263 | } else { | 
|  | 264 | ShReg = N.getOperand(1); | 
|  | 265 | } | 
|  | 266 | Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 267 | MVT::i32); | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 268 | return true; | 
|  | 269 | } | 
|  | 270 |  | 
| Jim Grosbach | 0860520 | 2010-09-29 19:03:54 +0000 | [diff] [blame] | 271 | AddrMode2Type ARMDAGToDAGISel::SelectAddrMode2Worker(SDValue N, | 
|  | 272 | SDValue &Base, | 
|  | 273 | SDValue &Offset, | 
|  | 274 | SDValue &Opc) { | 
| Evan Cheng | 72a8bcf | 2007-03-13 21:05:54 +0000 | [diff] [blame] | 275 | if (N.getOpcode() == ISD::MUL) { | 
|  | 276 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
|  | 277 | // X * [3,5,9] -> X + X * [2,4,8] etc. | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 278 | int RHSC = (int)RHS->getZExtValue(); | 
| Evan Cheng | 72a8bcf | 2007-03-13 21:05:54 +0000 | [diff] [blame] | 279 | if (RHSC & 1) { | 
|  | 280 | RHSC = RHSC & ~1; | 
|  | 281 | ARM_AM::AddrOpc AddSub = ARM_AM::add; | 
|  | 282 | if (RHSC < 0) { | 
|  | 283 | AddSub = ARM_AM::sub; | 
|  | 284 | RHSC = - RHSC; | 
|  | 285 | } | 
|  | 286 | if (isPowerOf2_32(RHSC)) { | 
|  | 287 | unsigned ShAmt = Log2_32(RHSC); | 
|  | 288 | Base = Offset = N.getOperand(0); | 
|  | 289 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, | 
|  | 290 | ARM_AM::lsl), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 291 | MVT::i32); | 
| Jim Grosbach | 0860520 | 2010-09-29 19:03:54 +0000 | [diff] [blame] | 292 | return AM2_SHOP; | 
| Evan Cheng | 72a8bcf | 2007-03-13 21:05:54 +0000 | [diff] [blame] | 293 | } | 
|  | 294 | } | 
|  | 295 | } | 
|  | 296 | } | 
|  | 297 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 298 | if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB) { | 
|  | 299 | Base = N; | 
|  | 300 | if (N.getOpcode() == ISD::FrameIndex) { | 
|  | 301 | int FI = cast<FrameIndexSDNode>(N)->getIndex(); | 
|  | 302 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
| Anton Korobeynikov | 2522908 | 2009-11-24 00:44:37 +0000 | [diff] [blame] | 303 | } else if (N.getOpcode() == ARMISD::Wrapper && | 
|  | 304 | !(Subtarget->useMovt() && | 
|  | 305 | N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 306 | Base = N.getOperand(0); | 
|  | 307 | } | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 308 | Offset = CurDAG->getRegister(0, MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 309 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::add, 0, | 
|  | 310 | ARM_AM::no_shift), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 311 | MVT::i32); | 
| Jim Grosbach | 0860520 | 2010-09-29 19:03:54 +0000 | [diff] [blame] | 312 | return AM2_BASE; | 
| Rafael Espindola | 708cb60 | 2006-11-08 17:07:32 +0000 | [diff] [blame] | 313 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 314 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 315 | // Match simple R +/- imm12 operands. | 
| Jim Grosbach | c7b10f3 | 2010-09-29 17:32:29 +0000 | [diff] [blame] | 316 | if (N.getOpcode() == ISD::ADD) { | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 317 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 318 | int RHSC = (int)RHS->getZExtValue(); | 
| Evan Cheng | 8942551d | 2007-01-24 02:45:25 +0000 | [diff] [blame] | 319 | if ((RHSC >= 0 && RHSC < 0x1000) || | 
|  | 320 | (RHSC < 0 && RHSC > -0x1000)) { // 12 bits. | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 321 | Base = N.getOperand(0); | 
| Evan Cheng | 8942551d | 2007-01-24 02:45:25 +0000 | [diff] [blame] | 322 | if (Base.getOpcode() == ISD::FrameIndex) { | 
|  | 323 | int FI = cast<FrameIndexSDNode>(Base)->getIndex(); | 
|  | 324 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
|  | 325 | } | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 326 | Offset = CurDAG->getRegister(0, MVT::i32); | 
| Evan Cheng | 8942551d | 2007-01-24 02:45:25 +0000 | [diff] [blame] | 327 |  | 
|  | 328 | ARM_AM::AddrOpc AddSub = ARM_AM::add; | 
|  | 329 | if (RHSC < 0) { | 
|  | 330 | AddSub = ARM_AM::sub; | 
|  | 331 | RHSC = - RHSC; | 
|  | 332 | } | 
|  | 333 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, RHSC, | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 334 | ARM_AM::no_shift), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 335 | MVT::i32); | 
| Jim Grosbach | 0860520 | 2010-09-29 19:03:54 +0000 | [diff] [blame] | 336 | return AM2_BASE; | 
| Rafael Espindola | 708cb60 | 2006-11-08 17:07:32 +0000 | [diff] [blame] | 337 | } | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 338 | } | 
| Jim Grosbach | c7b10f3 | 2010-09-29 17:32:29 +0000 | [diff] [blame] | 339 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 340 |  | 
| Johnny Chen | b678a56 | 2009-10-27 17:25:15 +0000 | [diff] [blame] | 341 | // Otherwise this is R +/- [possibly shifted] R. | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 342 | ARM_AM::AddrOpc AddSub = N.getOpcode() == ISD::ADD ? ARM_AM::add:ARM_AM::sub; | 
|  | 343 | ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(1)); | 
|  | 344 | unsigned ShAmt = 0; | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 345 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 346 | Base   = N.getOperand(0); | 
|  | 347 | Offset = N.getOperand(1); | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 348 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 349 | if (ShOpcVal != ARM_AM::no_shift) { | 
|  | 350 | // Check to see if the RHS of the shift is a constant, if not, we can't fold | 
|  | 351 | // it. | 
|  | 352 | if (ConstantSDNode *Sh = | 
|  | 353 | dyn_cast<ConstantSDNode>(N.getOperand(1).getOperand(1))) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 354 | ShAmt = Sh->getZExtValue(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 355 | Offset = N.getOperand(1).getOperand(0); | 
|  | 356 | } else { | 
|  | 357 | ShOpcVal = ARM_AM::no_shift; | 
| Rafael Espindola | 708cb60 | 2006-11-08 17:07:32 +0000 | [diff] [blame] | 358 | } | 
|  | 359 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 360 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 361 | // Try matching (R shl C) + (R). | 
|  | 362 | if (N.getOpcode() == ISD::ADD && ShOpcVal == ARM_AM::no_shift) { | 
|  | 363 | ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0)); | 
|  | 364 | if (ShOpcVal != ARM_AM::no_shift) { | 
|  | 365 | // Check to see if the RHS of the shift is a constant, if not, we can't | 
|  | 366 | // fold it. | 
|  | 367 | if (ConstantSDNode *Sh = | 
|  | 368 | dyn_cast<ConstantSDNode>(N.getOperand(0).getOperand(1))) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 369 | ShAmt = Sh->getZExtValue(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 370 | Offset = N.getOperand(0).getOperand(0); | 
|  | 371 | Base = N.getOperand(1); | 
|  | 372 | } else { | 
|  | 373 | ShOpcVal = ARM_AM::no_shift; | 
|  | 374 | } | 
|  | 375 | } | 
|  | 376 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 377 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 378 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 379 | MVT::i32); | 
| Jim Grosbach | 0860520 | 2010-09-29 19:03:54 +0000 | [diff] [blame] | 380 | return AM2_SHOP; | 
| Rafael Espindola | 708cb60 | 2006-11-08 17:07:32 +0000 | [diff] [blame] | 381 | } | 
|  | 382 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 383 | bool ARMDAGToDAGISel::SelectAddrMode2Offset(SDNode *Op, SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 384 | SDValue &Offset, SDValue &Opc) { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 385 | unsigned Opcode = Op->getOpcode(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 386 | ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) | 
|  | 387 | ? cast<LoadSDNode>(Op)->getAddressingMode() | 
|  | 388 | : cast<StoreSDNode>(Op)->getAddressingMode(); | 
|  | 389 | ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC) | 
|  | 390 | ? ARM_AM::add : ARM_AM::sub; | 
|  | 391 | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N)) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 392 | int Val = (int)C->getZExtValue(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 393 | if (Val >= 0 && Val < 0x1000) { // 12 bits. | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 394 | Offset = CurDAG->getRegister(0, MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 395 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, Val, | 
|  | 396 | ARM_AM::no_shift), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 397 | MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 398 | return true; | 
|  | 399 | } | 
|  | 400 | } | 
|  | 401 |  | 
|  | 402 | Offset = N; | 
|  | 403 | ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N); | 
|  | 404 | unsigned ShAmt = 0; | 
|  | 405 | if (ShOpcVal != ARM_AM::no_shift) { | 
|  | 406 | // Check to see if the RHS of the shift is a constant, if not, we can't fold | 
|  | 407 | // it. | 
|  | 408 | if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 409 | ShAmt = Sh->getZExtValue(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 410 | Offset = N.getOperand(0); | 
|  | 411 | } else { | 
|  | 412 | ShOpcVal = ARM_AM::no_shift; | 
|  | 413 | } | 
|  | 414 | } | 
|  | 415 |  | 
|  | 416 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 417 | MVT::i32); | 
| Rafael Espindola | 19398ec | 2006-10-17 18:04:53 +0000 | [diff] [blame] | 418 | return true; | 
|  | 419 | } | 
|  | 420 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 421 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 422 | bool ARMDAGToDAGISel::SelectAddrMode3(SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 423 | SDValue &Base, SDValue &Offset, | 
|  | 424 | SDValue &Opc) { | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 425 | if (N.getOpcode() == ISD::SUB) { | 
|  | 426 | // X - C  is canonicalize to X + -C, no need to handle it here. | 
|  | 427 | Base = N.getOperand(0); | 
|  | 428 | Offset = N.getOperand(1); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 429 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::sub, 0),MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 430 | return true; | 
|  | 431 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 432 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 433 | if (N.getOpcode() != ISD::ADD) { | 
|  | 434 | Base = N; | 
|  | 435 | if (N.getOpcode() == ISD::FrameIndex) { | 
|  | 436 | int FI = cast<FrameIndexSDNode>(N)->getIndex(); | 
|  | 437 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
|  | 438 | } | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 439 | Offset = CurDAG->getRegister(0, MVT::i32); | 
|  | 440 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0),MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 441 | return true; | 
|  | 442 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 443 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 444 | // If the RHS is +/- imm8, fold into addr mode. | 
|  | 445 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 446 | int RHSC = (int)RHS->getZExtValue(); | 
| Evan Cheng | 8942551d | 2007-01-24 02:45:25 +0000 | [diff] [blame] | 447 | if ((RHSC >= 0 && RHSC < 256) || | 
|  | 448 | (RHSC < 0 && RHSC > -256)) { // note -256 itself isn't allowed. | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 449 | Base = N.getOperand(0); | 
| Evan Cheng | 8942551d | 2007-01-24 02:45:25 +0000 | [diff] [blame] | 450 | if (Base.getOpcode() == ISD::FrameIndex) { | 
|  | 451 | int FI = cast<FrameIndexSDNode>(Base)->getIndex(); | 
|  | 452 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
|  | 453 | } | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 454 | Offset = CurDAG->getRegister(0, MVT::i32); | 
| Evan Cheng | 8942551d | 2007-01-24 02:45:25 +0000 | [diff] [blame] | 455 |  | 
|  | 456 | ARM_AM::AddrOpc AddSub = ARM_AM::add; | 
|  | 457 | if (RHSC < 0) { | 
|  | 458 | AddSub = ARM_AM::sub; | 
|  | 459 | RHSC = - RHSC; | 
|  | 460 | } | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 461 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, RHSC),MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 462 | return true; | 
|  | 463 | } | 
|  | 464 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 465 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 466 | Base = N.getOperand(0); | 
|  | 467 | Offset = N.getOperand(1); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 468 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0), MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 469 | return true; | 
|  | 470 | } | 
|  | 471 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 472 | bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 473 | SDValue &Offset, SDValue &Opc) { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 474 | unsigned Opcode = Op->getOpcode(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 475 | ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) | 
|  | 476 | ? cast<LoadSDNode>(Op)->getAddressingMode() | 
|  | 477 | : cast<StoreSDNode>(Op)->getAddressingMode(); | 
|  | 478 | ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC) | 
|  | 479 | ? ARM_AM::add : ARM_AM::sub; | 
|  | 480 | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N)) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 481 | int Val = (int)C->getZExtValue(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 482 | if (Val >= 0 && Val < 256) { | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 483 | Offset = CurDAG->getRegister(0, MVT::i32); | 
|  | 484 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, Val), MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 485 | return true; | 
|  | 486 | } | 
|  | 487 | } | 
|  | 488 |  | 
|  | 489 | Offset = N; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 490 | Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, 0), MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 491 | return true; | 
|  | 492 | } | 
|  | 493 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 494 | bool ARMDAGToDAGISel::SelectAddrMode4(SDValue N, SDValue &Addr, SDValue &Mode) { | 
| Anton Korobeynikov | 887d05c | 2009-08-08 13:35:48 +0000 | [diff] [blame] | 495 | Addr = N; | 
| Bob Wilson | 8ee9394 | 2010-08-28 00:20:11 +0000 | [diff] [blame] | 496 | Mode = CurDAG->getTargetConstant(ARM_AM::getAM4ModeImm(ARM_AM::ia), MVT::i32); | 
| Anton Korobeynikov | 887d05c | 2009-08-08 13:35:48 +0000 | [diff] [blame] | 497 | return true; | 
|  | 498 | } | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 499 |  | 
| Jim Grosbach | d37f071 | 2010-10-21 19:38:40 +0000 | [diff] [blame] | 500 | bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 501 | SDValue &Base, SDValue &Offset) { | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 502 | if (N.getOpcode() != ISD::ADD) { | 
|  | 503 | Base = N; | 
|  | 504 | if (N.getOpcode() == ISD::FrameIndex) { | 
|  | 505 | int FI = cast<FrameIndexSDNode>(N)->getIndex(); | 
|  | 506 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
| Anton Korobeynikov | 2522908 | 2009-11-24 00:44:37 +0000 | [diff] [blame] | 507 | } else if (N.getOpcode() == ARMISD::Wrapper && | 
|  | 508 | !(Subtarget->useMovt() && | 
|  | 509 | N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 510 | Base = N.getOperand(0); | 
|  | 511 | } | 
|  | 512 | Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 513 | MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 514 | return true; | 
|  | 515 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 516 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 517 | // If the RHS is +/- imm8, fold into addr mode. | 
|  | 518 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 519 | int RHSC = (int)RHS->getZExtValue(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 520 | if ((RHSC & 3) == 0) {  // The constant is implicitly multiplied by 4. | 
|  | 521 | RHSC >>= 2; | 
| Evan Cheng | 8942551d | 2007-01-24 02:45:25 +0000 | [diff] [blame] | 522 | if ((RHSC >= 0 && RHSC < 256) || | 
|  | 523 | (RHSC < 0 && RHSC > -256)) { // note -256 itself isn't allowed. | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 524 | Base = N.getOperand(0); | 
| Evan Cheng | 8942551d | 2007-01-24 02:45:25 +0000 | [diff] [blame] | 525 | if (Base.getOpcode() == ISD::FrameIndex) { | 
|  | 526 | int FI = cast<FrameIndexSDNode>(Base)->getIndex(); | 
|  | 527 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
|  | 528 | } | 
|  | 529 |  | 
|  | 530 | ARM_AM::AddrOpc AddSub = ARM_AM::add; | 
|  | 531 | if (RHSC < 0) { | 
|  | 532 | AddSub = ARM_AM::sub; | 
|  | 533 | RHSC = - RHSC; | 
|  | 534 | } | 
|  | 535 | Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 536 | MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 537 | return true; | 
|  | 538 | } | 
|  | 539 | } | 
|  | 540 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 541 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 542 | Base = N; | 
|  | 543 | Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 544 | MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 545 | return true; | 
|  | 546 | } | 
|  | 547 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 548 | bool ARMDAGToDAGISel::SelectAddrMode6(SDValue N, SDValue &Addr, SDValue &Align){ | 
| Bob Wilson | deb35af | 2009-07-01 23:16:05 +0000 | [diff] [blame] | 549 | Addr = N; | 
| Jim Grosbach | d1d002a | 2009-11-07 21:25:39 +0000 | [diff] [blame] | 550 | // Default to no alignment. | 
|  | 551 | Align = CurDAG->getTargetConstant(0, MVT::i32); | 
| Bob Wilson | deb35af | 2009-07-01 23:16:05 +0000 | [diff] [blame] | 552 | return true; | 
|  | 553 | } | 
|  | 554 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 555 | bool ARMDAGToDAGISel::SelectAddrModePC(SDValue N, | 
| Evan Cheng | 9a58aff | 2009-08-14 19:01:37 +0000 | [diff] [blame] | 556 | SDValue &Offset, SDValue &Label) { | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 557 | if (N.getOpcode() == ARMISD::PIC_ADD && N.hasOneUse()) { | 
|  | 558 | Offset = N.getOperand(0); | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 559 | SDValue N1 = N.getOperand(1); | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 560 | Label  = CurDAG->getTargetConstant(cast<ConstantSDNode>(N1)->getZExtValue(), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 561 | MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 562 | return true; | 
|  | 563 | } | 
|  | 564 | return false; | 
|  | 565 | } | 
|  | 566 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 567 | bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 568 | SDValue &Base, SDValue &Offset){ | 
| Dale Johannesen | ab8e442 | 2009-02-06 19:16:40 +0000 | [diff] [blame] | 569 | // FIXME dl should come from the parent load or store, not the address | 
| Evan Cheng | c0b7366 | 2007-01-23 22:59:13 +0000 | [diff] [blame] | 570 | if (N.getOpcode() != ISD::ADD) { | 
| Evan Cheng | 0794c6a | 2009-07-11 07:08:13 +0000 | [diff] [blame] | 571 | ConstantSDNode *NC = dyn_cast<ConstantSDNode>(N); | 
| Dan Gohman | f1d8304 | 2010-06-18 14:22:04 +0000 | [diff] [blame] | 572 | if (!NC || !NC->isNullValue()) | 
| Evan Cheng | 0794c6a | 2009-07-11 07:08:13 +0000 | [diff] [blame] | 573 | return false; | 
|  | 574 |  | 
|  | 575 | Base = Offset = N; | 
| Evan Cheng | c0b7366 | 2007-01-23 22:59:13 +0000 | [diff] [blame] | 576 | return true; | 
|  | 577 | } | 
|  | 578 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 579 | Base = N.getOperand(0); | 
|  | 580 | Offset = N.getOperand(1); | 
|  | 581 | return true; | 
|  | 582 | } | 
|  | 583 |  | 
| Evan Cheng | 139edae | 2007-01-24 02:21:22 +0000 | [diff] [blame] | 584 | bool | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 585 | ARMDAGToDAGISel::SelectThumbAddrModeRI5(SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 586 | unsigned Scale, SDValue &Base, | 
|  | 587 | SDValue &OffImm, SDValue &Offset) { | 
| Evan Cheng | 139edae | 2007-01-24 02:21:22 +0000 | [diff] [blame] | 588 | if (Scale == 4) { | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 589 | SDValue TmpBase, TmpOffImm; | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 590 | if (SelectThumbAddrModeSP(N, TmpBase, TmpOffImm)) | 
| Evan Cheng | 139edae | 2007-01-24 02:21:22 +0000 | [diff] [blame] | 591 | return false;  // We want to select tLDRspi / tSTRspi instead. | 
| Evan Cheng | 1526ba5 | 2007-01-24 08:53:17 +0000 | [diff] [blame] | 592 | if (N.getOpcode() == ARMISD::Wrapper && | 
|  | 593 | N.getOperand(0).getOpcode() == ISD::TargetConstantPool) | 
|  | 594 | return false;  // We want to select tLDRpci instead. | 
| Evan Cheng | 139edae | 2007-01-24 02:21:22 +0000 | [diff] [blame] | 595 | } | 
|  | 596 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 597 | if (N.getOpcode() != ISD::ADD) { | 
| Anton Korobeynikov | 2522908 | 2009-11-24 00:44:37 +0000 | [diff] [blame] | 598 | if (N.getOpcode() == ARMISD::Wrapper && | 
|  | 599 | !(Subtarget->useMovt() && | 
|  | 600 | N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { | 
|  | 601 | Base = N.getOperand(0); | 
|  | 602 | } else | 
|  | 603 | Base = N; | 
|  | 604 |  | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 605 | Offset = CurDAG->getRegister(0, MVT::i32); | 
|  | 606 | OffImm = CurDAG->getTargetConstant(0, MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 607 | return true; | 
|  | 608 | } | 
|  | 609 |  | 
| Evan Cheng | 650d067 | 2007-02-06 00:22:06 +0000 | [diff] [blame] | 610 | // Thumb does not have [sp, r] address mode. | 
|  | 611 | RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0)); | 
|  | 612 | RegisterSDNode *RHSR = dyn_cast<RegisterSDNode>(N.getOperand(1)); | 
|  | 613 | if ((LHSR && LHSR->getReg() == ARM::SP) || | 
|  | 614 | (RHSR && RHSR->getReg() == ARM::SP)) { | 
|  | 615 | Base = N; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 616 | Offset = CurDAG->getRegister(0, MVT::i32); | 
|  | 617 | OffImm = CurDAG->getTargetConstant(0, MVT::i32); | 
| Evan Cheng | 650d067 | 2007-02-06 00:22:06 +0000 | [diff] [blame] | 618 | return true; | 
|  | 619 | } | 
|  | 620 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 621 | // If the RHS is + imm5 * scale, fold into addr mode. | 
|  | 622 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 623 | int RHSC = (int)RHS->getZExtValue(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 624 | if ((RHSC & (Scale-1)) == 0) {  // The constant is implicitly multiplied. | 
|  | 625 | RHSC /= Scale; | 
|  | 626 | if (RHSC >= 0 && RHSC < 32) { | 
|  | 627 | Base = N.getOperand(0); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 628 | Offset = CurDAG->getRegister(0, MVT::i32); | 
|  | 629 | OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 630 | return true; | 
|  | 631 | } | 
|  | 632 | } | 
|  | 633 | } | 
|  | 634 |  | 
| Evan Cheng | c0b7366 | 2007-01-23 22:59:13 +0000 | [diff] [blame] | 635 | Base = N.getOperand(0); | 
|  | 636 | Offset = N.getOperand(1); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 637 | OffImm = CurDAG->getTargetConstant(0, MVT::i32); | 
| Evan Cheng | c0b7366 | 2007-01-23 22:59:13 +0000 | [diff] [blame] | 638 | return true; | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 639 | } | 
|  | 640 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 641 | bool ARMDAGToDAGISel::SelectThumbAddrModeS1(SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 642 | SDValue &Base, SDValue &OffImm, | 
|  | 643 | SDValue &Offset) { | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 644 | return SelectThumbAddrModeRI5(N, 1, Base, OffImm, Offset); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 645 | } | 
|  | 646 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 647 | bool ARMDAGToDAGISel::SelectThumbAddrModeS2(SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 648 | SDValue &Base, SDValue &OffImm, | 
|  | 649 | SDValue &Offset) { | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 650 | return SelectThumbAddrModeRI5(N, 2, Base, OffImm, Offset); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 651 | } | 
|  | 652 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 653 | bool ARMDAGToDAGISel::SelectThumbAddrModeS4(SDValue N, | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 654 | SDValue &Base, SDValue &OffImm, | 
|  | 655 | SDValue &Offset) { | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 656 | return SelectThumbAddrModeRI5(N, 4, Base, OffImm, Offset); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 657 | } | 
|  | 658 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 659 | bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue N, | 
|  | 660 | SDValue &Base, SDValue &OffImm) { | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 661 | if (N.getOpcode() == ISD::FrameIndex) { | 
|  | 662 | int FI = cast<FrameIndexSDNode>(N)->getIndex(); | 
|  | 663 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 664 | OffImm = CurDAG->getTargetConstant(0, MVT::i32); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 665 | return true; | 
|  | 666 | } | 
| Evan Cheng | 139edae | 2007-01-24 02:21:22 +0000 | [diff] [blame] | 667 |  | 
| Evan Cheng | 650d067 | 2007-02-06 00:22:06 +0000 | [diff] [blame] | 668 | if (N.getOpcode() != ISD::ADD) | 
|  | 669 | return false; | 
|  | 670 |  | 
|  | 671 | RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0)); | 
| Evan Cheng | a974031 | 2007-02-06 09:11:20 +0000 | [diff] [blame] | 672 | if (N.getOperand(0).getOpcode() == ISD::FrameIndex || | 
|  | 673 | (LHSR && LHSR->getReg() == ARM::SP)) { | 
| Evan Cheng | 139edae | 2007-01-24 02:21:22 +0000 | [diff] [blame] | 674 | // If the RHS is + imm8 * scale, fold into addr mode. | 
|  | 675 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 676 | int RHSC = (int)RHS->getZExtValue(); | 
| Evan Cheng | 139edae | 2007-01-24 02:21:22 +0000 | [diff] [blame] | 677 | if ((RHSC & 3) == 0) {  // The constant is implicitly multiplied. | 
|  | 678 | RHSC >>= 2; | 
|  | 679 | if (RHSC >= 0 && RHSC < 256) { | 
| Evan Cheng | 650d067 | 2007-02-06 00:22:06 +0000 | [diff] [blame] | 680 | Base = N.getOperand(0); | 
| Evan Cheng | a974031 | 2007-02-06 09:11:20 +0000 | [diff] [blame] | 681 | if (Base.getOpcode() == ISD::FrameIndex) { | 
|  | 682 | int FI = cast<FrameIndexSDNode>(Base)->getIndex(); | 
|  | 683 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
|  | 684 | } | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 685 | OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); | 
| Evan Cheng | 139edae | 2007-01-24 02:21:22 +0000 | [diff] [blame] | 686 | return true; | 
|  | 687 | } | 
|  | 688 | } | 
|  | 689 | } | 
|  | 690 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 691 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 692 | return false; | 
|  | 693 | } | 
|  | 694 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 695 | bool ARMDAGToDAGISel::SelectT2ShifterOperandReg(SDValue N, SDValue &BaseReg, | 
| Evan Cheng | eab9ca7 | 2009-06-27 02:26:13 +0000 | [diff] [blame] | 696 | SDValue &Opc) { | 
| Evan Cheng | 59069ec | 2010-07-30 23:33:54 +0000 | [diff] [blame] | 697 | if (DisableShifterOp) | 
|  | 698 | return false; | 
|  | 699 |  | 
| Evan Cheng | eab9ca7 | 2009-06-27 02:26:13 +0000 | [diff] [blame] | 700 | ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N); | 
|  | 701 |  | 
|  | 702 | // Don't match base register only case. That is matched to a separate | 
|  | 703 | // lower complexity pattern with explicit register operand. | 
|  | 704 | if (ShOpcVal == ARM_AM::no_shift) return false; | 
|  | 705 |  | 
|  | 706 | BaseReg = N.getOperand(0); | 
|  | 707 | unsigned ShImmVal = 0; | 
|  | 708 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
|  | 709 | ShImmVal = RHS->getZExtValue() & 31; | 
|  | 710 | Opc = getI32Imm(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal)); | 
|  | 711 | return true; | 
|  | 712 | } | 
|  | 713 |  | 
|  | 714 | return false; | 
|  | 715 | } | 
|  | 716 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 717 | bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDValue N, | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 718 | SDValue &Base, SDValue &OffImm) { | 
|  | 719 | // Match simple R + imm12 operands. | 
| David Goodwin | 802a0b5 | 2009-07-20 15:55:39 +0000 | [diff] [blame] | 720 |  | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 721 | // Base only. | 
|  | 722 | if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB) { | 
| David Goodwin | 802a0b5 | 2009-07-20 15:55:39 +0000 | [diff] [blame] | 723 | if (N.getOpcode() == ISD::FrameIndex) { | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 724 | // Match frame index... | 
| David Goodwin | 802a0b5 | 2009-07-20 15:55:39 +0000 | [diff] [blame] | 725 | int FI = cast<FrameIndexSDNode>(N)->getIndex(); | 
|  | 726 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 727 | OffImm  = CurDAG->getTargetConstant(0, MVT::i32); | 
| David Goodwin | 802a0b5 | 2009-07-20 15:55:39 +0000 | [diff] [blame] | 728 | return true; | 
| Anton Korobeynikov | 2522908 | 2009-11-24 00:44:37 +0000 | [diff] [blame] | 729 | } else if (N.getOpcode() == ARMISD::Wrapper && | 
|  | 730 | !(Subtarget->useMovt() && | 
|  | 731 | N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 732 | Base = N.getOperand(0); | 
|  | 733 | if (Base.getOpcode() == ISD::TargetConstantPool) | 
|  | 734 | return false;  // We want to select t2LDRpci instead. | 
|  | 735 | } else | 
|  | 736 | Base = N; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 737 | OffImm  = CurDAG->getTargetConstant(0, MVT::i32); | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 738 | return true; | 
| David Goodwin | 802a0b5 | 2009-07-20 15:55:39 +0000 | [diff] [blame] | 739 | } | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 740 |  | 
|  | 741 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 742 | if (SelectT2AddrModeImm8(N, Base, OffImm)) | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 743 | // Let t2LDRi8 handle (R - imm8). | 
|  | 744 | return false; | 
|  | 745 |  | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 746 | int RHSC = (int)RHS->getZExtValue(); | 
| David Goodwin | 79c079b | 2009-07-30 18:56:48 +0000 | [diff] [blame] | 747 | if (N.getOpcode() == ISD::SUB) | 
|  | 748 | RHSC = -RHSC; | 
|  | 749 |  | 
|  | 750 | if (RHSC >= 0 && RHSC < 0x1000) { // 12 bits (unsigned) | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 751 | Base   = N.getOperand(0); | 
| David Goodwin | 79c079b | 2009-07-30 18:56:48 +0000 | [diff] [blame] | 752 | if (Base.getOpcode() == ISD::FrameIndex) { | 
|  | 753 | int FI = cast<FrameIndexSDNode>(Base)->getIndex(); | 
|  | 754 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
|  | 755 | } | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 756 | OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 757 | return true; | 
|  | 758 | } | 
|  | 759 | } | 
|  | 760 |  | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 761 | // Base only. | 
|  | 762 | Base = N; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 763 | OffImm  = CurDAG->getTargetConstant(0, MVT::i32); | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 764 | return true; | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 765 | } | 
|  | 766 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 767 | bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue N, | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 768 | SDValue &Base, SDValue &OffImm) { | 
| David Goodwin | 79c079b | 2009-07-30 18:56:48 +0000 | [diff] [blame] | 769 | // Match simple R - imm8 operands. | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 770 | if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::SUB) { | 
| David Goodwin | 5aae45f | 2009-07-30 22:45:52 +0000 | [diff] [blame] | 771 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
|  | 772 | int RHSC = (int)RHS->getSExtValue(); | 
|  | 773 | if (N.getOpcode() == ISD::SUB) | 
|  | 774 | RHSC = -RHSC; | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 775 |  | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 776 | if ((RHSC >= -255) && (RHSC < 0)) { // 8 bits (always negative) | 
|  | 777 | Base = N.getOperand(0); | 
| David Goodwin | 5aae45f | 2009-07-30 22:45:52 +0000 | [diff] [blame] | 778 | if (Base.getOpcode() == ISD::FrameIndex) { | 
|  | 779 | int FI = cast<FrameIndexSDNode>(Base)->getIndex(); | 
|  | 780 | Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
|  | 781 | } | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 782 | OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); | 
| David Goodwin | 5aae45f | 2009-07-30 22:45:52 +0000 | [diff] [blame] | 783 | return true; | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 784 | } | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 785 | } | 
|  | 786 | } | 
|  | 787 |  | 
|  | 788 | return false; | 
|  | 789 | } | 
|  | 790 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 791 | bool ARMDAGToDAGISel::SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N, | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 792 | SDValue &OffImm){ | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 793 | unsigned Opcode = Op->getOpcode(); | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 794 | ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) | 
|  | 795 | ? cast<LoadSDNode>(Op)->getAddressingMode() | 
|  | 796 | : cast<StoreSDNode>(Op)->getAddressingMode(); | 
|  | 797 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N)) { | 
|  | 798 | int RHSC = (int)RHS->getZExtValue(); | 
|  | 799 | if (RHSC >= 0 && RHSC < 0x100) { // 8 bits. | 
| David Goodwin | 95bad85 | 2009-07-14 21:29:29 +0000 | [diff] [blame] | 800 | OffImm = ((AM == ISD::PRE_INC) || (AM == ISD::POST_INC)) | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 801 | ? CurDAG->getTargetConstant(RHSC, MVT::i32) | 
|  | 802 | : CurDAG->getTargetConstant(-RHSC, MVT::i32); | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 803 | return true; | 
|  | 804 | } | 
|  | 805 | } | 
|  | 806 |  | 
|  | 807 | return false; | 
|  | 808 | } | 
|  | 809 |  | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 810 | bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue N, | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 811 | SDValue &Base, | 
|  | 812 | SDValue &OffReg, SDValue &ShImm) { | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 813 | // (R - imm8) should be handled by t2LDRi8. The rest are handled by t2LDRi12. | 
|  | 814 | if (N.getOpcode() != ISD::ADD) | 
|  | 815 | return false; | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 816 |  | 
| Evan Cheng | 3606467 | 2009-08-11 08:52:18 +0000 | [diff] [blame] | 817 | // Leave (R + imm12) for t2LDRi12, (R - imm8) for t2LDRi8. | 
|  | 818 | if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) { | 
|  | 819 | int RHSC = (int)RHS->getZExtValue(); | 
|  | 820 | if (RHSC >= 0 && RHSC < 0x1000) // 12 bits (unsigned) | 
|  | 821 | return false; | 
|  | 822 | else if (RHSC < 0 && RHSC >= -255) // 8 bits | 
| David Goodwin | 79c079b | 2009-07-30 18:56:48 +0000 | [diff] [blame] | 823 | return false; | 
|  | 824 | } | 
|  | 825 |  | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 826 | // Look for (R + R) or (R + (R << [1,2,3])). | 
|  | 827 | unsigned ShAmt = 0; | 
|  | 828 | Base   = N.getOperand(0); | 
|  | 829 | OffReg = N.getOperand(1); | 
|  | 830 |  | 
|  | 831 | // Swap if it is ((R << c) + R). | 
|  | 832 | ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(OffReg); | 
|  | 833 | if (ShOpcVal != ARM_AM::lsl) { | 
|  | 834 | ShOpcVal = ARM_AM::getShiftOpcForNode(Base); | 
|  | 835 | if (ShOpcVal == ARM_AM::lsl) | 
|  | 836 | std::swap(Base, OffReg); | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 837 | } | 
|  | 838 |  | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 839 | if (ShOpcVal == ARM_AM::lsl) { | 
|  | 840 | // Check to see if the RHS of the shift is a constant, if not, we can't fold | 
|  | 841 | // it. | 
|  | 842 | if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(OffReg.getOperand(1))) { | 
|  | 843 | ShAmt = Sh->getZExtValue(); | 
|  | 844 | if (ShAmt >= 4) { | 
|  | 845 | ShAmt = 0; | 
|  | 846 | ShOpcVal = ARM_AM::no_shift; | 
|  | 847 | } else | 
|  | 848 | OffReg = OffReg.getOperand(0); | 
|  | 849 | } else { | 
|  | 850 | ShOpcVal = ARM_AM::no_shift; | 
|  | 851 | } | 
| David Goodwin | f391205 | 2009-07-15 15:50:19 +0000 | [diff] [blame] | 852 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 853 |  | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 854 | ShImm = CurDAG->getTargetConstant(ShAmt, MVT::i32); | 
| Evan Cheng | b23b50d | 2009-06-29 07:51:04 +0000 | [diff] [blame] | 855 |  | 
|  | 856 | return true; | 
|  | 857 | } | 
|  | 858 |  | 
|  | 859 | //===--------------------------------------------------------------------===// | 
|  | 860 |  | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 861 | /// getAL - Returns a ARMCC::AL immediate node. | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 862 | static inline SDValue getAL(SelectionDAG *CurDAG) { | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 863 | return CurDAG->getTargetConstant((uint64_t)ARMCC::AL, MVT::i32); | 
| Evan Cheng | 0f7cbe8 | 2007-05-15 01:29:07 +0000 | [diff] [blame] | 864 | } | 
|  | 865 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 866 | SDNode *ARMDAGToDAGISel::SelectARMIndexedLoad(SDNode *N) { | 
|  | 867 | LoadSDNode *LD = cast<LoadSDNode>(N); | 
| Evan Cheng | d9c5536 | 2009-07-02 01:23:32 +0000 | [diff] [blame] | 868 | ISD::MemIndexedMode AM = LD->getAddressingMode(); | 
|  | 869 | if (AM == ISD::UNINDEXED) | 
|  | 870 | return NULL; | 
|  | 871 |  | 
| Owen Anderson | 53aa7a9 | 2009-08-10 22:56:29 +0000 | [diff] [blame] | 872 | EVT LoadedVT = LD->getMemoryVT(); | 
| Evan Cheng | d9c5536 | 2009-07-02 01:23:32 +0000 | [diff] [blame] | 873 | SDValue Offset, AMOpc; | 
|  | 874 | bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC); | 
|  | 875 | unsigned Opcode = 0; | 
|  | 876 | bool Match = false; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 877 | if (LoadedVT == MVT::i32 && | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 878 | SelectAddrMode2Offset(N, LD->getOffset(), Offset, AMOpc)) { | 
| Evan Cheng | d9c5536 | 2009-07-02 01:23:32 +0000 | [diff] [blame] | 879 | Opcode = isPre ? ARM::LDR_PRE : ARM::LDR_POST; | 
|  | 880 | Match = true; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 881 | } else if (LoadedVT == MVT::i16 && | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 882 | SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) { | 
| Evan Cheng | d9c5536 | 2009-07-02 01:23:32 +0000 | [diff] [blame] | 883 | Match = true; | 
|  | 884 | Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) | 
|  | 885 | ? (isPre ? ARM::LDRSH_PRE : ARM::LDRSH_POST) | 
|  | 886 | : (isPre ? ARM::LDRH_PRE : ARM::LDRH_POST); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 887 | } else if (LoadedVT == MVT::i8 || LoadedVT == MVT::i1) { | 
| Evan Cheng | d9c5536 | 2009-07-02 01:23:32 +0000 | [diff] [blame] | 888 | if (LD->getExtensionType() == ISD::SEXTLOAD) { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 889 | if (SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) { | 
| Evan Cheng | d9c5536 | 2009-07-02 01:23:32 +0000 | [diff] [blame] | 890 | Match = true; | 
|  | 891 | Opcode = isPre ? ARM::LDRSB_PRE : ARM::LDRSB_POST; | 
|  | 892 | } | 
|  | 893 | } else { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 894 | if (SelectAddrMode2Offset(N, LD->getOffset(), Offset, AMOpc)) { | 
| Evan Cheng | d9c5536 | 2009-07-02 01:23:32 +0000 | [diff] [blame] | 895 | Match = true; | 
|  | 896 | Opcode = isPre ? ARM::LDRB_PRE : ARM::LDRB_POST; | 
|  | 897 | } | 
|  | 898 | } | 
|  | 899 | } | 
|  | 900 |  | 
|  | 901 | if (Match) { | 
|  | 902 | SDValue Chain = LD->getChain(); | 
|  | 903 | SDValue Base = LD->getBasePtr(); | 
|  | 904 | SDValue Ops[]= { Base, Offset, AMOpc, getAL(CurDAG), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 905 | CurDAG->getRegister(0, MVT::i32), Chain }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 906 | return CurDAG->getMachineNode(Opcode, N->getDebugLoc(), MVT::i32, MVT::i32, | 
| Dan Gohman | 32f71d7 | 2009-09-25 18:54:59 +0000 | [diff] [blame] | 907 | MVT::Other, Ops, 6); | 
| Evan Cheng | d9c5536 | 2009-07-02 01:23:32 +0000 | [diff] [blame] | 908 | } | 
|  | 909 |  | 
|  | 910 | return NULL; | 
|  | 911 | } | 
|  | 912 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 913 | SDNode *ARMDAGToDAGISel::SelectT2IndexedLoad(SDNode *N) { | 
|  | 914 | LoadSDNode *LD = cast<LoadSDNode>(N); | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 915 | ISD::MemIndexedMode AM = LD->getAddressingMode(); | 
|  | 916 | if (AM == ISD::UNINDEXED) | 
|  | 917 | return NULL; | 
|  | 918 |  | 
| Owen Anderson | 53aa7a9 | 2009-08-10 22:56:29 +0000 | [diff] [blame] | 919 | EVT LoadedVT = LD->getMemoryVT(); | 
| Evan Cheng | 8ecd7eb | 2009-07-02 23:16:11 +0000 | [diff] [blame] | 920 | bool isSExtLd = LD->getExtensionType() == ISD::SEXTLOAD; | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 921 | SDValue Offset; | 
|  | 922 | bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC); | 
|  | 923 | unsigned Opcode = 0; | 
|  | 924 | bool Match = false; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 925 | if (SelectT2AddrModeImm8Offset(N, LD->getOffset(), Offset)) { | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 926 | switch (LoadedVT.getSimpleVT().SimpleTy) { | 
|  | 927 | case MVT::i32: | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 928 | Opcode = isPre ? ARM::t2LDR_PRE : ARM::t2LDR_POST; | 
|  | 929 | break; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 930 | case MVT::i16: | 
| Evan Cheng | 8ecd7eb | 2009-07-02 23:16:11 +0000 | [diff] [blame] | 931 | if (isSExtLd) | 
|  | 932 | Opcode = isPre ? ARM::t2LDRSH_PRE : ARM::t2LDRSH_POST; | 
|  | 933 | else | 
|  | 934 | Opcode = isPre ? ARM::t2LDRH_PRE : ARM::t2LDRH_POST; | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 935 | break; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 936 | case MVT::i8: | 
|  | 937 | case MVT::i1: | 
| Evan Cheng | 8ecd7eb | 2009-07-02 23:16:11 +0000 | [diff] [blame] | 938 | if (isSExtLd) | 
|  | 939 | Opcode = isPre ? ARM::t2LDRSB_PRE : ARM::t2LDRSB_POST; | 
|  | 940 | else | 
|  | 941 | Opcode = isPre ? ARM::t2LDRB_PRE : ARM::t2LDRB_POST; | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 942 | break; | 
|  | 943 | default: | 
|  | 944 | return NULL; | 
|  | 945 | } | 
|  | 946 | Match = true; | 
|  | 947 | } | 
|  | 948 |  | 
|  | 949 | if (Match) { | 
|  | 950 | SDValue Chain = LD->getChain(); | 
|  | 951 | SDValue Base = LD->getBasePtr(); | 
|  | 952 | SDValue Ops[]= { Base, Offset, getAL(CurDAG), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 953 | CurDAG->getRegister(0, MVT::i32), Chain }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 954 | return CurDAG->getMachineNode(Opcode, N->getDebugLoc(), MVT::i32, MVT::i32, | 
| Dan Gohman | 32f71d7 | 2009-09-25 18:54:59 +0000 | [diff] [blame] | 955 | MVT::Other, Ops, 5); | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 956 | } | 
|  | 957 |  | 
|  | 958 | return NULL; | 
|  | 959 | } | 
|  | 960 |  | 
| Bob Wilson | d8a9a04 | 2010-06-04 00:04:02 +0000 | [diff] [blame] | 961 | /// PairSRegs - Form a D register from a pair of S registers. | 
|  | 962 | /// | 
|  | 963 | SDNode *ARMDAGToDAGISel::PairSRegs(EVT VT, SDValue V0, SDValue V1) { | 
|  | 964 | DebugLoc dl = V0.getNode()->getDebugLoc(); | 
|  | 965 | SDValue SubReg0 = CurDAG->getTargetConstant(ARM::ssub_0, MVT::i32); | 
|  | 966 | SDValue SubReg1 = CurDAG->getTargetConstant(ARM::ssub_1, MVT::i32); | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 967 | const SDValue Ops[] = { V0, SubReg0, V1, SubReg1 }; | 
|  | 968 | return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 4); | 
| Bob Wilson | d8a9a04 | 2010-06-04 00:04:02 +0000 | [diff] [blame] | 969 | } | 
|  | 970 |  | 
| Evan Cheng | c2ae5f5 | 2010-05-10 17:34:18 +0000 | [diff] [blame] | 971 | /// PairDRegs - Form a quad register from a pair of D registers. | 
|  | 972 | /// | 
| Bob Wilson | e6b778d | 2009-10-06 22:01:59 +0000 | [diff] [blame] | 973 | SDNode *ARMDAGToDAGISel::PairDRegs(EVT VT, SDValue V0, SDValue V1) { | 
|  | 974 | DebugLoc dl = V0.getNode()->getDebugLoc(); | 
| Jakob Stoklund Olesen | 6c47d64 | 2010-05-24 16:54:32 +0000 | [diff] [blame] | 975 | SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, MVT::i32); | 
|  | 976 | SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, MVT::i32); | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 977 | const SDValue Ops[] = { V0, SubReg0, V1, SubReg1 }; | 
|  | 978 | return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 4); | 
| Bob Wilson | e6b778d | 2009-10-06 22:01:59 +0000 | [diff] [blame] | 979 | } | 
|  | 980 |  | 
| Evan Cheng | ca21cc8 | 2010-05-14 00:21:45 +0000 | [diff] [blame] | 981 | /// PairQRegs - Form 4 consecutive D registers from a pair of Q registers. | 
| Evan Cheng | c2ae5f5 | 2010-05-10 17:34:18 +0000 | [diff] [blame] | 982 | /// | 
|  | 983 | SDNode *ARMDAGToDAGISel::PairQRegs(EVT VT, SDValue V0, SDValue V1) { | 
|  | 984 | DebugLoc dl = V0.getNode()->getDebugLoc(); | 
| Jakob Stoklund Olesen | 6c47d64 | 2010-05-24 16:54:32 +0000 | [diff] [blame] | 985 | SDValue SubReg0 = CurDAG->getTargetConstant(ARM::qsub_0, MVT::i32); | 
|  | 986 | SDValue SubReg1 = CurDAG->getTargetConstant(ARM::qsub_1, MVT::i32); | 
| Evan Cheng | c2ae5f5 | 2010-05-10 17:34:18 +0000 | [diff] [blame] | 987 | const SDValue Ops[] = { V0, SubReg0, V1, SubReg1 }; | 
|  | 988 | return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 4); | 
|  | 989 | } | 
|  | 990 |  | 
| Bob Wilson | d8a9a04 | 2010-06-04 00:04:02 +0000 | [diff] [blame] | 991 | /// QuadSRegs - Form 4 consecutive S registers. | 
|  | 992 | /// | 
|  | 993 | SDNode *ARMDAGToDAGISel::QuadSRegs(EVT VT, SDValue V0, SDValue V1, | 
|  | 994 | SDValue V2, SDValue V3) { | 
|  | 995 | DebugLoc dl = V0.getNode()->getDebugLoc(); | 
|  | 996 | SDValue SubReg0 = CurDAG->getTargetConstant(ARM::ssub_0, MVT::i32); | 
|  | 997 | SDValue SubReg1 = CurDAG->getTargetConstant(ARM::ssub_1, MVT::i32); | 
|  | 998 | SDValue SubReg2 = CurDAG->getTargetConstant(ARM::ssub_2, MVT::i32); | 
|  | 999 | SDValue SubReg3 = CurDAG->getTargetConstant(ARM::ssub_3, MVT::i32); | 
|  | 1000 | const SDValue Ops[] = { V0, SubReg0, V1, SubReg1, V2, SubReg2, V3, SubReg3 }; | 
|  | 1001 | return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 8); | 
|  | 1002 | } | 
|  | 1003 |  | 
| Evan Cheng | ca21cc8 | 2010-05-14 00:21:45 +0000 | [diff] [blame] | 1004 | /// QuadDRegs - Form 4 consecutive D registers. | 
| Evan Cheng | c2ae5f5 | 2010-05-10 17:34:18 +0000 | [diff] [blame] | 1005 | /// | 
|  | 1006 | SDNode *ARMDAGToDAGISel::QuadDRegs(EVT VT, SDValue V0, SDValue V1, | 
|  | 1007 | SDValue V2, SDValue V3) { | 
|  | 1008 | DebugLoc dl = V0.getNode()->getDebugLoc(); | 
| Jakob Stoklund Olesen | 6c47d64 | 2010-05-24 16:54:32 +0000 | [diff] [blame] | 1009 | SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, MVT::i32); | 
|  | 1010 | SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, MVT::i32); | 
|  | 1011 | SDValue SubReg2 = CurDAG->getTargetConstant(ARM::dsub_2, MVT::i32); | 
|  | 1012 | SDValue SubReg3 = CurDAG->getTargetConstant(ARM::dsub_3, MVT::i32); | 
| Evan Cheng | c2ae5f5 | 2010-05-10 17:34:18 +0000 | [diff] [blame] | 1013 | const SDValue Ops[] = { V0, SubReg0, V1, SubReg1, V2, SubReg2, V3, SubReg3 }; | 
|  | 1014 | return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 8); | 
|  | 1015 | } | 
|  | 1016 |  | 
| Evan Cheng | 298e6b8 | 2010-05-16 03:27:48 +0000 | [diff] [blame] | 1017 | /// QuadQRegs - Form 4 consecutive Q registers. | 
|  | 1018 | /// | 
|  | 1019 | SDNode *ARMDAGToDAGISel::QuadQRegs(EVT VT, SDValue V0, SDValue V1, | 
|  | 1020 | SDValue V2, SDValue V3) { | 
|  | 1021 | DebugLoc dl = V0.getNode()->getDebugLoc(); | 
| Jakob Stoklund Olesen | 6c47d64 | 2010-05-24 16:54:32 +0000 | [diff] [blame] | 1022 | SDValue SubReg0 = CurDAG->getTargetConstant(ARM::qsub_0, MVT::i32); | 
|  | 1023 | SDValue SubReg1 = CurDAG->getTargetConstant(ARM::qsub_1, MVT::i32); | 
|  | 1024 | SDValue SubReg2 = CurDAG->getTargetConstant(ARM::qsub_2, MVT::i32); | 
|  | 1025 | SDValue SubReg3 = CurDAG->getTargetConstant(ARM::qsub_3, MVT::i32); | 
| Evan Cheng | 298e6b8 | 2010-05-16 03:27:48 +0000 | [diff] [blame] | 1026 | const SDValue Ops[] = { V0, SubReg0, V1, SubReg1, V2, SubReg2, V3, SubReg3 }; | 
|  | 1027 | return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 8); | 
|  | 1028 | } | 
|  | 1029 |  | 
| Bob Wilson | 7fbbe9a | 2010-09-23 23:42:37 +0000 | [diff] [blame] | 1030 | /// GetVLDSTAlign - Get the alignment (in bytes) for the alignment operand | 
|  | 1031 | /// of a NEON VLD or VST instruction.  The supported values depend on the | 
|  | 1032 | /// number of registers being loaded. | 
|  | 1033 | static unsigned GetVLDSTAlign(SDNode *N, unsigned NumVecs, bool is64BitVector) { | 
|  | 1034 | unsigned NumRegs = NumVecs; | 
|  | 1035 | if (!is64BitVector && NumVecs < 3) | 
|  | 1036 | NumRegs *= 2; | 
|  | 1037 |  | 
|  | 1038 | unsigned Alignment = cast<MemIntrinsicSDNode>(N)->getAlignment(); | 
|  | 1039 | if (Alignment >= 32 && NumRegs == 4) | 
|  | 1040 | return 32; | 
|  | 1041 | if (Alignment >= 16 && (NumRegs == 2 || NumRegs == 4)) | 
|  | 1042 | return 16; | 
|  | 1043 | if (Alignment >= 8) | 
|  | 1044 | return 8; | 
|  | 1045 | return 0; | 
|  | 1046 | } | 
|  | 1047 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1048 | SDNode *ARMDAGToDAGISel::SelectVLD(SDNode *N, unsigned NumVecs, | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1049 | unsigned *DOpcodes, unsigned *QOpcodes0, | 
|  | 1050 | unsigned *QOpcodes1) { | 
| Bob Wilson | 340861d | 2010-03-23 05:25:43 +0000 | [diff] [blame] | 1051 | assert(NumVecs >= 1 && NumVecs <= 4 && "VLD NumVecs out-of-range"); | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1052 | DebugLoc dl = N->getDebugLoc(); | 
|  | 1053 |  | 
| Bob Wilson | ae08a73 | 2010-03-20 22:13:40 +0000 | [diff] [blame] | 1054 | SDValue MemAddr, Align; | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 1055 | if (!SelectAddrMode6(N->getOperand(2), MemAddr, Align)) | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1056 | return NULL; | 
|  | 1057 |  | 
|  | 1058 | SDValue Chain = N->getOperand(0); | 
|  | 1059 | EVT VT = N->getValueType(0); | 
|  | 1060 | bool is64BitVector = VT.is64BitVector(); | 
|  | 1061 |  | 
| Bob Wilson | 7fbbe9a | 2010-09-23 23:42:37 +0000 | [diff] [blame] | 1062 | unsigned Alignment = GetVLDSTAlign(N, NumVecs, is64BitVector); | 
| Bob Wilson | 9eeb890 | 2010-09-23 21:43:54 +0000 | [diff] [blame] | 1063 | Align = CurDAG->getTargetConstant(Alignment, MVT::i32); | 
|  | 1064 |  | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1065 | unsigned OpcodeIndex; | 
|  | 1066 | switch (VT.getSimpleVT().SimpleTy) { | 
|  | 1067 | default: llvm_unreachable("unhandled vld type"); | 
|  | 1068 | // Double-register operations: | 
|  | 1069 | case MVT::v8i8:  OpcodeIndex = 0; break; | 
|  | 1070 | case MVT::v4i16: OpcodeIndex = 1; break; | 
|  | 1071 | case MVT::v2f32: | 
|  | 1072 | case MVT::v2i32: OpcodeIndex = 2; break; | 
|  | 1073 | case MVT::v1i64: OpcodeIndex = 3; break; | 
|  | 1074 | // Quad-register operations: | 
|  | 1075 | case MVT::v16i8: OpcodeIndex = 0; break; | 
|  | 1076 | case MVT::v8i16: OpcodeIndex = 1; break; | 
|  | 1077 | case MVT::v4f32: | 
|  | 1078 | case MVT::v4i32: OpcodeIndex = 2; break; | 
| Bob Wilson | 340861d | 2010-03-23 05:25:43 +0000 | [diff] [blame] | 1079 | case MVT::v2i64: OpcodeIndex = 3; | 
| Bob Wilson | cc0a2a7 | 2010-03-23 06:20:33 +0000 | [diff] [blame] | 1080 | assert(NumVecs == 1 && "v2i64 type only supported for VLD1"); | 
| Bob Wilson | 340861d | 2010-03-23 05:25:43 +0000 | [diff] [blame] | 1081 | break; | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1082 | } | 
|  | 1083 |  | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 1084 | EVT ResTy; | 
|  | 1085 | if (NumVecs == 1) | 
|  | 1086 | ResTy = VT; | 
|  | 1087 | else { | 
|  | 1088 | unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs; | 
|  | 1089 | if (!is64BitVector) | 
|  | 1090 | ResTyElts *= 2; | 
|  | 1091 | ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts); | 
|  | 1092 | } | 
|  | 1093 |  | 
| Evan Cheng | 3da64f76 | 2010-04-16 05:46:06 +0000 | [diff] [blame] | 1094 | SDValue Pred = getAL(CurDAG); | 
| Bob Wilson | ae08a73 | 2010-03-20 22:13:40 +0000 | [diff] [blame] | 1095 | SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 1096 | SDValue SuperReg; | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1097 | if (is64BitVector) { | 
|  | 1098 | unsigned Opc = DOpcodes[OpcodeIndex]; | 
| Bob Wilson | ae08a73 | 2010-03-20 22:13:40 +0000 | [diff] [blame] | 1099 | const SDValue Ops[] = { MemAddr, Align, Pred, Reg0, Chain }; | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 1100 | SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTy, MVT::Other, Ops, 5); | 
| Bob Wilson | 75a6408 | 2010-09-02 16:00:54 +0000 | [diff] [blame] | 1101 | if (NumVecs == 1) | 
| Evan Cheng | 630063a | 2010-05-10 21:26:24 +0000 | [diff] [blame] | 1102 | return VLd; | 
|  | 1103 |  | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 1104 | SuperReg = SDValue(VLd, 0); | 
| Jakob Stoklund Olesen | 8d042c0 | 2010-05-24 17:13:28 +0000 | [diff] [blame] | 1105 | assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); | 
| Evan Cheng | cfa7d02 | 2010-05-14 18:54:59 +0000 | [diff] [blame] | 1106 | for (unsigned Vec = 0; Vec < NumVecs; ++Vec) { | 
| Jakob Stoklund Olesen | 6c47d64 | 2010-05-24 16:54:32 +0000 | [diff] [blame] | 1107 | SDValue D = CurDAG->getTargetExtractSubreg(ARM::dsub_0+Vec, | 
| Bob Wilson | 75a6408 | 2010-09-02 16:00:54 +0000 | [diff] [blame] | 1108 | dl, VT, SuperReg); | 
| Evan Cheng | cfa7d02 | 2010-05-14 18:54:59 +0000 | [diff] [blame] | 1109 | ReplaceUses(SDValue(N, Vec), D); | 
| Evan Cheng | 630063a | 2010-05-10 21:26:24 +0000 | [diff] [blame] | 1110 | } | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 1111 | ReplaceUses(SDValue(N, NumVecs), SDValue(VLd, 1)); | 
| Evan Cheng | 630063a | 2010-05-10 21:26:24 +0000 | [diff] [blame] | 1112 | return NULL; | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1113 | } | 
|  | 1114 |  | 
| Bob Wilson | 340861d | 2010-03-23 05:25:43 +0000 | [diff] [blame] | 1115 | if (NumVecs <= 2) { | 
|  | 1116 | // Quad registers are directly supported for VLD1 and VLD2, | 
|  | 1117 | // loading pairs of D regs. | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1118 | unsigned Opc = QOpcodes0[OpcodeIndex]; | 
| Bob Wilson | ae08a73 | 2010-03-20 22:13:40 +0000 | [diff] [blame] | 1119 | const SDValue Ops[] = { MemAddr, Align, Pred, Reg0, Chain }; | 
| Bob Wilson | 75a6408 | 2010-09-02 16:00:54 +0000 | [diff] [blame] | 1120 | SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTy, MVT::Other, Ops, 5); | 
| Bob Wilson | 75a6408 | 2010-09-02 16:00:54 +0000 | [diff] [blame] | 1121 | if (NumVecs == 1) | 
|  | 1122 | return VLd; | 
|  | 1123 |  | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 1124 | SuperReg = SDValue(VLd, 0); | 
| Bob Wilson | 75a6408 | 2010-09-02 16:00:54 +0000 | [diff] [blame] | 1125 | Chain = SDValue(VLd, 1); | 
|  | 1126 |  | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1127 | } else { | 
|  | 1128 | // Otherwise, quad registers are loaded with two separate instructions, | 
|  | 1129 | // where one loads the even registers and the other loads the odd registers. | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 1130 | EVT AddrTy = MemAddr.getValueType(); | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1131 |  | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1132 | // Load the even subregs. | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1133 | unsigned Opc = QOpcodes0[OpcodeIndex]; | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 1134 | SDValue ImplDef = | 
|  | 1135 | SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, ResTy), 0); | 
|  | 1136 | const SDValue OpsA[] = { MemAddr, Align, Reg0, ImplDef, Pred, Reg0, Chain }; | 
|  | 1137 | SDNode *VLdA = | 
|  | 1138 | CurDAG->getMachineNode(Opc, dl, ResTy, AddrTy, MVT::Other, OpsA, 7); | 
|  | 1139 | Chain = SDValue(VLdA, 2); | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1140 |  | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1141 | // Load the odd subregs. | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1142 | Opc = QOpcodes1[OpcodeIndex]; | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 1143 | const SDValue OpsB[] = { SDValue(VLdA, 1), Align, Reg0, SDValue(VLdA, 0), | 
|  | 1144 | Pred, Reg0, Chain }; | 
|  | 1145 | SDNode *VLdB = | 
|  | 1146 | CurDAG->getMachineNode(Opc, dl, ResTy, AddrTy, MVT::Other, OpsB, 7); | 
|  | 1147 | SuperReg = SDValue(VLdB, 0); | 
|  | 1148 | Chain = SDValue(VLdB, 2); | 
|  | 1149 | } | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1150 |  | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 1151 | // Extract out the Q registers. | 
|  | 1152 | assert(ARM::qsub_3 == ARM::qsub_0+3 && "Unexpected subreg numbering"); | 
|  | 1153 | for (unsigned Vec = 0; Vec < NumVecs; ++Vec) { | 
|  | 1154 | SDValue Q = CurDAG->getTargetExtractSubreg(ARM::qsub_0+Vec, | 
|  | 1155 | dl, VT, SuperReg); | 
|  | 1156 | ReplaceUses(SDValue(N, Vec), Q); | 
| Bob Wilson | 12b4799 | 2009-10-14 17:28:52 +0000 | [diff] [blame] | 1157 | } | 
|  | 1158 | ReplaceUses(SDValue(N, NumVecs), Chain); | 
|  | 1159 | return NULL; | 
|  | 1160 | } | 
|  | 1161 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1162 | SDNode *ARMDAGToDAGISel::SelectVST(SDNode *N, unsigned NumVecs, | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1163 | unsigned *DOpcodes, unsigned *QOpcodes0, | 
|  | 1164 | unsigned *QOpcodes1) { | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 1165 | assert(NumVecs >= 1 && NumVecs <= 4 && "VST NumVecs out-of-range"); | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1166 | DebugLoc dl = N->getDebugLoc(); | 
|  | 1167 |  | 
| Bob Wilson | ae08a73 | 2010-03-20 22:13:40 +0000 | [diff] [blame] | 1168 | SDValue MemAddr, Align; | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 1169 | if (!SelectAddrMode6(N->getOperand(2), MemAddr, Align)) | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1170 | return NULL; | 
|  | 1171 |  | 
|  | 1172 | SDValue Chain = N->getOperand(0); | 
|  | 1173 | EVT VT = N->getOperand(3).getValueType(); | 
|  | 1174 | bool is64BitVector = VT.is64BitVector(); | 
|  | 1175 |  | 
| Bob Wilson | 7fbbe9a | 2010-09-23 23:42:37 +0000 | [diff] [blame] | 1176 | unsigned Alignment = GetVLDSTAlign(N, NumVecs, is64BitVector); | 
|  | 1177 | Align = CurDAG->getTargetConstant(Alignment, MVT::i32); | 
|  | 1178 |  | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1179 | unsigned OpcodeIndex; | 
|  | 1180 | switch (VT.getSimpleVT().SimpleTy) { | 
|  | 1181 | default: llvm_unreachable("unhandled vst type"); | 
|  | 1182 | // Double-register operations: | 
|  | 1183 | case MVT::v8i8:  OpcodeIndex = 0; break; | 
|  | 1184 | case MVT::v4i16: OpcodeIndex = 1; break; | 
|  | 1185 | case MVT::v2f32: | 
|  | 1186 | case MVT::v2i32: OpcodeIndex = 2; break; | 
|  | 1187 | case MVT::v1i64: OpcodeIndex = 3; break; | 
|  | 1188 | // Quad-register operations: | 
|  | 1189 | case MVT::v16i8: OpcodeIndex = 0; break; | 
|  | 1190 | case MVT::v8i16: OpcodeIndex = 1; break; | 
|  | 1191 | case MVT::v4f32: | 
|  | 1192 | case MVT::v4i32: OpcodeIndex = 2; break; | 
| Bob Wilson | cc0a2a7 | 2010-03-23 06:20:33 +0000 | [diff] [blame] | 1193 | case MVT::v2i64: OpcodeIndex = 3; | 
|  | 1194 | assert(NumVecs == 1 && "v2i64 type only supported for VST1"); | 
|  | 1195 | break; | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1196 | } | 
|  | 1197 |  | 
| Evan Cheng | 3da64f76 | 2010-04-16 05:46:06 +0000 | [diff] [blame] | 1198 | SDValue Pred = getAL(CurDAG); | 
| Bob Wilson | ae08a73 | 2010-03-20 22:13:40 +0000 | [diff] [blame] | 1199 | SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); | 
| Evan Cheng | a33fc86 | 2009-11-21 06:21:52 +0000 | [diff] [blame] | 1200 |  | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1201 | SmallVector<SDValue, 7> Ops; | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1202 | Ops.push_back(MemAddr); | 
| Jim Grosbach | d1d002a | 2009-11-07 21:25:39 +0000 | [diff] [blame] | 1203 | Ops.push_back(Align); | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1204 |  | 
|  | 1205 | if (is64BitVector) { | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1206 | if (NumVecs == 1) { | 
|  | 1207 | Ops.push_back(N->getOperand(3)); | 
|  | 1208 | } else { | 
| Evan Cheng | e276c18 | 2010-05-11 01:19:40 +0000 | [diff] [blame] | 1209 | SDValue RegSeq; | 
|  | 1210 | SDValue V0 = N->getOperand(0+3); | 
|  | 1211 | SDValue V1 = N->getOperand(1+3); | 
|  | 1212 |  | 
|  | 1213 | // Form a REG_SEQUENCE to force register allocation. | 
|  | 1214 | if (NumVecs == 2) | 
|  | 1215 | RegSeq = SDValue(PairDRegs(MVT::v2i64, V0, V1), 0); | 
|  | 1216 | else { | 
|  | 1217 | SDValue V2 = N->getOperand(2+3); | 
| Jim Grosbach | d37f071 | 2010-10-21 19:38:40 +0000 | [diff] [blame] | 1218 | // If it's a vld3, form a quad D-register and leave the last part as | 
| Evan Cheng | e276c18 | 2010-05-11 01:19:40 +0000 | [diff] [blame] | 1219 | // an undef. | 
|  | 1220 | SDValue V3 = (NumVecs == 3) | 
|  | 1221 | ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0) | 
|  | 1222 | : N->getOperand(3+3); | 
|  | 1223 | RegSeq = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); | 
|  | 1224 | } | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1225 | Ops.push_back(RegSeq); | 
| Evan Cheng | e276c18 | 2010-05-11 01:19:40 +0000 | [diff] [blame] | 1226 | } | 
| Evan Cheng | a33fc86 | 2009-11-21 06:21:52 +0000 | [diff] [blame] | 1227 | Ops.push_back(Pred); | 
| Bob Wilson | ae08a73 | 2010-03-20 22:13:40 +0000 | [diff] [blame] | 1228 | Ops.push_back(Reg0); // predicate register | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1229 | Ops.push_back(Chain); | 
| Evan Cheng | e276c18 | 2010-05-11 01:19:40 +0000 | [diff] [blame] | 1230 | unsigned Opc = DOpcodes[OpcodeIndex]; | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1231 | return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 6); | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1232 | } | 
|  | 1233 |  | 
| Bob Wilson | cc0a2a7 | 2010-03-23 06:20:33 +0000 | [diff] [blame] | 1234 | if (NumVecs <= 2) { | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1235 | // Quad registers are directly supported for VST1 and VST2. | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1236 | unsigned Opc = QOpcodes0[OpcodeIndex]; | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1237 | if (NumVecs == 1) { | 
|  | 1238 | Ops.push_back(N->getOperand(3)); | 
|  | 1239 | } else { | 
|  | 1240 | // Form a QQ register. | 
| Evan Cheng | c2ae5f5 | 2010-05-10 17:34:18 +0000 | [diff] [blame] | 1241 | SDValue Q0 = N->getOperand(3); | 
|  | 1242 | SDValue Q1 = N->getOperand(4); | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1243 | Ops.push_back(SDValue(PairQRegs(MVT::v4i64, Q0, Q1), 0)); | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1244 | } | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1245 | Ops.push_back(Pred); | 
|  | 1246 | Ops.push_back(Reg0); // predicate register | 
|  | 1247 | Ops.push_back(Chain); | 
|  | 1248 | return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 6); | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1249 | } | 
|  | 1250 |  | 
|  | 1251 | // Otherwise, quad registers are stored with two separate instructions, | 
|  | 1252 | // where one stores the even registers and the other stores the odd registers. | 
| Evan Cheng | 9e688cb | 2010-05-15 07:53:37 +0000 | [diff] [blame] | 1253 |  | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 1254 | // Form the QQQQ REG_SEQUENCE. | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1255 | SDValue V0 = N->getOperand(0+3); | 
|  | 1256 | SDValue V1 = N->getOperand(1+3); | 
|  | 1257 | SDValue V2 = N->getOperand(2+3); | 
|  | 1258 | SDValue V3 = (NumVecs == 3) | 
|  | 1259 | ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0) | 
|  | 1260 | : N->getOperand(3+3); | 
|  | 1261 | SDValue RegSeq = SDValue(QuadQRegs(MVT::v8i64, V0, V1, V2, V3), 0); | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 1262 |  | 
|  | 1263 | // Store the even D registers. | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 1264 | Ops.push_back(Reg0); // post-access address offset | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1265 | Ops.push_back(RegSeq); | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 1266 | Ops.push_back(Pred); | 
|  | 1267 | Ops.push_back(Reg0); // predicate register | 
|  | 1268 | Ops.push_back(Chain); | 
|  | 1269 | unsigned Opc = QOpcodes0[OpcodeIndex]; | 
|  | 1270 | SDNode *VStA = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(), | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1271 | MVT::Other, Ops.data(), 7); | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 1272 | Chain = SDValue(VStA, 1); | 
|  | 1273 |  | 
|  | 1274 | // Store the odd D registers. | 
|  | 1275 | Ops[0] = SDValue(VStA, 0); // MemAddr | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1276 | Ops[6] = Chain; | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 1277 | Opc = QOpcodes1[OpcodeIndex]; | 
|  | 1278 | SDNode *VStB = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(), | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 1279 | MVT::Other, Ops.data(), 7); | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 1280 | Chain = SDValue(VStB, 1); | 
|  | 1281 | ReplaceUses(SDValue(N, 0), Chain); | 
|  | 1282 | return NULL; | 
| Bob Wilson | c350cdf | 2009-10-14 18:32:29 +0000 | [diff] [blame] | 1283 | } | 
|  | 1284 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1285 | SDNode *ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, | 
| Bob Wilson | 93117bc | 2009-10-14 16:46:45 +0000 | [diff] [blame] | 1286 | unsigned NumVecs, unsigned *DOpcodes, | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 1287 | unsigned *QOpcodes) { | 
| Bob Wilson | 93117bc | 2009-10-14 16:46:45 +0000 | [diff] [blame] | 1288 | assert(NumVecs >=2 && NumVecs <= 4 && "VLDSTLane NumVecs out-of-range"); | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1289 | DebugLoc dl = N->getDebugLoc(); | 
|  | 1290 |  | 
| Bob Wilson | ae08a73 | 2010-03-20 22:13:40 +0000 | [diff] [blame] | 1291 | SDValue MemAddr, Align; | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 1292 | if (!SelectAddrMode6(N->getOperand(2), MemAddr, Align)) | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1293 | return NULL; | 
|  | 1294 |  | 
|  | 1295 | SDValue Chain = N->getOperand(0); | 
|  | 1296 | unsigned Lane = | 
|  | 1297 | cast<ConstantSDNode>(N->getOperand(NumVecs+3))->getZExtValue(); | 
| Bob Wilson | 93117bc | 2009-10-14 16:46:45 +0000 | [diff] [blame] | 1298 | EVT VT = IsLoad ? N->getValueType(0) : N->getOperand(3).getValueType(); | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1299 | bool is64BitVector = VT.is64BitVector(); | 
|  | 1300 |  | 
| Bob Wilson | b6d61dc | 2010-10-19 00:16:32 +0000 | [diff] [blame] | 1301 | if (NumVecs != 3) { | 
|  | 1302 | unsigned Alignment = cast<MemIntrinsicSDNode>(N)->getAlignment(); | 
|  | 1303 | unsigned NumBytes = NumVecs * VT.getVectorElementType().getSizeInBits()/8; | 
|  | 1304 | if (Alignment > NumBytes) | 
|  | 1305 | Alignment = NumBytes; | 
|  | 1306 | // Alignment must be a power of two; make sure of that. | 
|  | 1307 | Alignment = (Alignment & -Alignment); | 
|  | 1308 | if (Alignment > 1) | 
|  | 1309 | Align = CurDAG->getTargetConstant(Alignment, MVT::i32); | 
|  | 1310 | } | 
|  | 1311 |  | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1312 | unsigned OpcodeIndex; | 
|  | 1313 | switch (VT.getSimpleVT().SimpleTy) { | 
| Bob Wilson | 93117bc | 2009-10-14 16:46:45 +0000 | [diff] [blame] | 1314 | default: llvm_unreachable("unhandled vld/vst lane type"); | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1315 | // Double-register operations: | 
|  | 1316 | case MVT::v8i8:  OpcodeIndex = 0; break; | 
|  | 1317 | case MVT::v4i16: OpcodeIndex = 1; break; | 
|  | 1318 | case MVT::v2f32: | 
|  | 1319 | case MVT::v2i32: OpcodeIndex = 2; break; | 
|  | 1320 | // Quad-register operations: | 
|  | 1321 | case MVT::v8i16: OpcodeIndex = 0; break; | 
|  | 1322 | case MVT::v4f32: | 
|  | 1323 | case MVT::v4i32: OpcodeIndex = 1; break; | 
|  | 1324 | } | 
|  | 1325 |  | 
| Evan Cheng | 3da64f76 | 2010-04-16 05:46:06 +0000 | [diff] [blame] | 1326 | SDValue Pred = getAL(CurDAG); | 
| Bob Wilson | ae08a73 | 2010-03-20 22:13:40 +0000 | [diff] [blame] | 1327 | SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); | 
| Evan Cheng | a33fc86 | 2009-11-21 06:21:52 +0000 | [diff] [blame] | 1328 |  | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 1329 | SmallVector<SDValue, 7> Ops; | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1330 | Ops.push_back(MemAddr); | 
| Jim Grosbach | d1d002a | 2009-11-07 21:25:39 +0000 | [diff] [blame] | 1331 | Ops.push_back(Align); | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1332 |  | 
| Jim Grosbach | d37f071 | 2010-10-21 19:38:40 +0000 | [diff] [blame] | 1333 | unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] : | 
| Eric Christopher | 726838a | 2010-09-14 08:31:25 +0000 | [diff] [blame] | 1334 | QOpcodes[OpcodeIndex]); | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 1335 |  | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 1336 | SDValue SuperReg; | 
|  | 1337 | SDValue V0 = N->getOperand(0+3); | 
|  | 1338 | SDValue V1 = N->getOperand(1+3); | 
|  | 1339 | if (NumVecs == 2) { | 
|  | 1340 | if (is64BitVector) | 
|  | 1341 | SuperReg = SDValue(PairDRegs(MVT::v2i64, V0, V1), 0); | 
|  | 1342 | else | 
|  | 1343 | SuperReg = SDValue(PairQRegs(MVT::v4i64, V0, V1), 0); | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1344 | } else { | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 1345 | SDValue V2 = N->getOperand(2+3); | 
|  | 1346 | SDValue V3 = (NumVecs == 3) | 
|  | 1347 | ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0) | 
|  | 1348 | : N->getOperand(3+3); | 
|  | 1349 | if (is64BitVector) | 
|  | 1350 | SuperReg = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); | 
|  | 1351 | else | 
|  | 1352 | SuperReg = SDValue(QuadQRegs(MVT::v8i64, V0, V1, V2, V3), 0); | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1353 | } | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 1354 | Ops.push_back(SuperReg); | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1355 | Ops.push_back(getI32Imm(Lane)); | 
| Evan Cheng | a33fc86 | 2009-11-21 06:21:52 +0000 | [diff] [blame] | 1356 | Ops.push_back(Pred); | 
| Bob Wilson | ae08a73 | 2010-03-20 22:13:40 +0000 | [diff] [blame] | 1357 | Ops.push_back(Reg0); | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1358 | Ops.push_back(Chain); | 
|  | 1359 |  | 
| Bob Wilson | 93117bc | 2009-10-14 16:46:45 +0000 | [diff] [blame] | 1360 | if (!IsLoad) | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 1361 | return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 7); | 
| Bob Wilson | 93117bc | 2009-10-14 16:46:45 +0000 | [diff] [blame] | 1362 |  | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 1363 | EVT ResTy; | 
|  | 1364 | unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs; | 
|  | 1365 | if (!is64BitVector) | 
|  | 1366 | ResTyElts *= 2; | 
|  | 1367 | ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts); | 
| Evan Cheng | 0cbd11d | 2010-05-15 01:36:29 +0000 | [diff] [blame] | 1368 |  | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 1369 | SDNode *VLdLn = CurDAG->getMachineNode(Opc, dl, ResTy, MVT::Other, | 
|  | 1370 | Ops.data(), 7); | 
|  | 1371 | SuperReg = SDValue(VLdLn, 0); | 
|  | 1372 | Chain = SDValue(VLdLn, 1); | 
| Evan Cheng | 0cbd11d | 2010-05-15 01:36:29 +0000 | [diff] [blame] | 1373 |  | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 1374 | // Extract the subregisters. | 
| Bob Wilson | 01ac8f9 | 2010-06-16 21:34:01 +0000 | [diff] [blame] | 1375 | assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); | 
|  | 1376 | assert(ARM::qsub_3 == ARM::qsub_0+3 && "Unexpected subreg numbering"); | 
|  | 1377 | unsigned SubIdx = is64BitVector ? ARM::dsub_0 : ARM::qsub_0; | 
|  | 1378 | for (unsigned Vec = 0; Vec < NumVecs; ++Vec) | 
|  | 1379 | ReplaceUses(SDValue(N, Vec), | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 1380 | CurDAG->getTargetExtractSubreg(SubIdx+Vec, dl, VT, SuperReg)); | 
|  | 1381 | ReplaceUses(SDValue(N, NumVecs), Chain); | 
| Bob Wilson | 4145e3a | 2009-10-14 16:19:03 +0000 | [diff] [blame] | 1382 | return NULL; | 
|  | 1383 | } | 
|  | 1384 |  | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 1385 | SDNode *ARMDAGToDAGISel::SelectVTBL(SDNode *N, bool IsExt, unsigned NumVecs, | 
|  | 1386 | unsigned Opc) { | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 1387 | assert(NumVecs >= 2 && NumVecs <= 4 && "VTBL NumVecs out-of-range"); | 
|  | 1388 | DebugLoc dl = N->getDebugLoc(); | 
|  | 1389 | EVT VT = N->getValueType(0); | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 1390 | unsigned FirstTblReg = IsExt ? 2 : 1; | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 1391 |  | 
|  | 1392 | // Form a REG_SEQUENCE to force register allocation. | 
|  | 1393 | SDValue RegSeq; | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 1394 | SDValue V0 = N->getOperand(FirstTblReg + 0); | 
|  | 1395 | SDValue V1 = N->getOperand(FirstTblReg + 1); | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 1396 | if (NumVecs == 2) | 
|  | 1397 | RegSeq = SDValue(PairDRegs(MVT::v16i8, V0, V1), 0); | 
|  | 1398 | else { | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 1399 | SDValue V2 = N->getOperand(FirstTblReg + 2); | 
| Jim Grosbach | d37f071 | 2010-10-21 19:38:40 +0000 | [diff] [blame] | 1400 | // If it's a vtbl3, form a quad D-register and leave the last part as | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 1401 | // an undef. | 
|  | 1402 | SDValue V3 = (NumVecs == 3) | 
|  | 1403 | ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0) | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 1404 | : N->getOperand(FirstTblReg + 3); | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 1405 | RegSeq = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); | 
|  | 1406 | } | 
|  | 1407 |  | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 1408 | SmallVector<SDValue, 6> Ops; | 
|  | 1409 | if (IsExt) | 
|  | 1410 | Ops.push_back(N->getOperand(1)); | 
| Bob Wilson | c597fd3b | 2010-09-13 23:55:10 +0000 | [diff] [blame] | 1411 | Ops.push_back(RegSeq); | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 1412 | Ops.push_back(N->getOperand(FirstTblReg + NumVecs)); | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 1413 | Ops.push_back(getAL(CurDAG)); // predicate | 
|  | 1414 | Ops.push_back(CurDAG->getRegister(0, MVT::i32)); // predicate register | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 1415 | return CurDAG->getMachineNode(Opc, dl, VT, Ops.data(), Ops.size()); | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 1416 | } | 
|  | 1417 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1418 | SDNode *ARMDAGToDAGISel::SelectV6T2BitfieldExtractOp(SDNode *N, | 
| Jim Grosbach | 825cb29 | 2010-04-22 23:24:18 +0000 | [diff] [blame] | 1419 | bool isSigned) { | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 1420 | if (!Subtarget->hasV6T2Ops()) | 
|  | 1421 | return NULL; | 
| Bob Wilson | 93117bc | 2009-10-14 16:46:45 +0000 | [diff] [blame] | 1422 |  | 
| Jim Grosbach | 825cb29 | 2010-04-22 23:24:18 +0000 | [diff] [blame] | 1423 | unsigned Opc = isSigned ? (Subtarget->isThumb() ? ARM::t2SBFX : ARM::SBFX) | 
|  | 1424 | : (Subtarget->isThumb() ? ARM::t2UBFX : ARM::UBFX); | 
|  | 1425 |  | 
|  | 1426 |  | 
|  | 1427 | // For unsigned extracts, check for a shift right and mask | 
|  | 1428 | unsigned And_imm = 0; | 
|  | 1429 | if (N->getOpcode() == ISD::AND) { | 
|  | 1430 | if (isOpcWithIntImmediate(N, ISD::AND, And_imm)) { | 
|  | 1431 |  | 
|  | 1432 | // The immediate is a mask of the low bits iff imm & (imm+1) == 0 | 
|  | 1433 | if (And_imm & (And_imm + 1)) | 
|  | 1434 | return NULL; | 
|  | 1435 |  | 
|  | 1436 | unsigned Srl_imm = 0; | 
|  | 1437 | if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRL, | 
|  | 1438 | Srl_imm)) { | 
|  | 1439 | assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!"); | 
|  | 1440 |  | 
|  | 1441 | unsigned Width = CountTrailingOnes_32(And_imm); | 
|  | 1442 | unsigned LSB = Srl_imm; | 
|  | 1443 | SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); | 
|  | 1444 | SDValue Ops[] = { N->getOperand(0).getOperand(0), | 
|  | 1445 | CurDAG->getTargetConstant(LSB, MVT::i32), | 
|  | 1446 | CurDAG->getTargetConstant(Width, MVT::i32), | 
|  | 1447 | getAL(CurDAG), Reg0 }; | 
|  | 1448 | return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5); | 
|  | 1449 | } | 
|  | 1450 | } | 
|  | 1451 | return NULL; | 
|  | 1452 | } | 
|  | 1453 |  | 
|  | 1454 | // Otherwise, we're looking for a shift of a shift | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 1455 | unsigned Shl_imm = 0; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1456 | if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, Shl_imm)) { | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 1457 | assert(Shl_imm > 0 && Shl_imm < 32 && "bad amount in shift node!"); | 
|  | 1458 | unsigned Srl_imm = 0; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1459 | if (isInt32Immediate(N->getOperand(1), Srl_imm)) { | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 1460 | assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!"); | 
|  | 1461 | unsigned Width = 32 - Srl_imm; | 
|  | 1462 | int LSB = Srl_imm - Shl_imm; | 
| Evan Cheng | 0f55e9c | 2009-10-22 00:40:00 +0000 | [diff] [blame] | 1463 | if (LSB < 0) | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 1464 | return NULL; | 
|  | 1465 | SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1466 | SDValue Ops[] = { N->getOperand(0).getOperand(0), | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 1467 | CurDAG->getTargetConstant(LSB, MVT::i32), | 
|  | 1468 | CurDAG->getTargetConstant(Width, MVT::i32), | 
|  | 1469 | getAL(CurDAG), Reg0 }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1470 | return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5); | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 1471 | } | 
|  | 1472 | } | 
|  | 1473 | return NULL; | 
|  | 1474 | } | 
|  | 1475 |  | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1476 | SDNode *ARMDAGToDAGISel:: | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1477 | SelectT2CMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1478 | ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { | 
|  | 1479 | SDValue CPTmp0; | 
|  | 1480 | SDValue CPTmp1; | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 1481 | if (SelectT2ShifterOperandReg(TrueVal, CPTmp0, CPTmp1)) { | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1482 | unsigned SOVal = cast<ConstantSDNode>(CPTmp1)->getZExtValue(); | 
|  | 1483 | unsigned SOShOp = ARM_AM::getSORegShOp(SOVal); | 
|  | 1484 | unsigned Opc = 0; | 
|  | 1485 | switch (SOShOp) { | 
|  | 1486 | case ARM_AM::lsl: Opc = ARM::t2MOVCClsl; break; | 
|  | 1487 | case ARM_AM::lsr: Opc = ARM::t2MOVCClsr; break; | 
|  | 1488 | case ARM_AM::asr: Opc = ARM::t2MOVCCasr; break; | 
|  | 1489 | case ARM_AM::ror: Opc = ARM::t2MOVCCror; break; | 
|  | 1490 | default: | 
|  | 1491 | llvm_unreachable("Unknown so_reg opcode!"); | 
|  | 1492 | break; | 
|  | 1493 | } | 
|  | 1494 | SDValue SOShImm = | 
|  | 1495 | CurDAG->getTargetConstant(ARM_AM::getSORegOffset(SOVal), MVT::i32); | 
|  | 1496 | SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); | 
|  | 1497 | SDValue Ops[] = { FalseVal, CPTmp0, SOShImm, CC, CCR, InFlag }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1498 | return CurDAG->SelectNodeTo(N, Opc, MVT::i32,Ops, 6); | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1499 | } | 
|  | 1500 | return 0; | 
|  | 1501 | } | 
|  | 1502 |  | 
|  | 1503 | SDNode *ARMDAGToDAGISel:: | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1504 | SelectARMCMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1505 | ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { | 
|  | 1506 | SDValue CPTmp0; | 
|  | 1507 | SDValue CPTmp1; | 
|  | 1508 | SDValue CPTmp2; | 
| Chris Lattner | 0e023ea | 2010-09-21 20:31:19 +0000 | [diff] [blame] | 1509 | if (SelectShifterOperandReg(TrueVal, CPTmp0, CPTmp1, CPTmp2)) { | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1510 | SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); | 
|  | 1511 | SDValue Ops[] = { FalseVal, CPTmp0, CPTmp1, CPTmp2, CC, CCR, InFlag }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1512 | return CurDAG->SelectNodeTo(N, ARM::MOVCCs, MVT::i32, Ops, 7); | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1513 | } | 
|  | 1514 | return 0; | 
|  | 1515 | } | 
|  | 1516 |  | 
|  | 1517 | SDNode *ARMDAGToDAGISel:: | 
| Jim Grosbach | 5b255c2 | 2010-10-07 00:53:56 +0000 | [diff] [blame] | 1518 | SelectT2CMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1519 | ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { | 
|  | 1520 | ConstantSDNode *T = dyn_cast<ConstantSDNode>(TrueVal); | 
|  | 1521 | if (!T) | 
|  | 1522 | return 0; | 
|  | 1523 |  | 
| Jim Grosbach | 5b255c2 | 2010-10-07 00:53:56 +0000 | [diff] [blame] | 1524 | unsigned TrueImm = T->getZExtValue(); | 
|  | 1525 | bool isSoImm = Pred_t2_so_imm(TrueVal.getNode()); | 
|  | 1526 | if (isSoImm || TrueImm <= 0xffff) { | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1527 | SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32); | 
|  | 1528 | SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); | 
|  | 1529 | SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; | 
| Jim Grosbach | 5b255c2 | 2010-10-07 00:53:56 +0000 | [diff] [blame] | 1530 | return CurDAG->SelectNodeTo(N, (isSoImm ? ARM::t2MOVCCi : ARM::t2MOVCCi16), | 
|  | 1531 | MVT::i32, Ops, 5); | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1532 | } | 
|  | 1533 | return 0; | 
|  | 1534 | } | 
|  | 1535 |  | 
|  | 1536 | SDNode *ARMDAGToDAGISel:: | 
| Jim Grosbach | 742adc3 | 2010-10-07 00:42:42 +0000 | [diff] [blame] | 1537 | SelectARMCMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1538 | ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { | 
|  | 1539 | ConstantSDNode *T = dyn_cast<ConstantSDNode>(TrueVal); | 
|  | 1540 | if (!T) | 
|  | 1541 | return 0; | 
|  | 1542 |  | 
| Jim Grosbach | 742adc3 | 2010-10-07 00:42:42 +0000 | [diff] [blame] | 1543 | unsigned TrueImm = T->getZExtValue(); | 
|  | 1544 | bool isSoImm = Pred_so_imm(TrueVal.getNode()); | 
|  | 1545 | if (isSoImm || (Subtarget->hasV6T2Ops() && TrueImm <= 0xffff)) { | 
|  | 1546 | SDValue True = CurDAG->getTargetConstant(TrueImm, MVT::i32); | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1547 | SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); | 
|  | 1548 | SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; | 
| Jim Grosbach | 742adc3 | 2010-10-07 00:42:42 +0000 | [diff] [blame] | 1549 | return CurDAG->SelectNodeTo(N, (isSoImm ? ARM::MOVCCi : ARM::MOVCCi16), | 
|  | 1550 | MVT::i32, Ops, 5); | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1551 | } | 
|  | 1552 | return 0; | 
|  | 1553 | } | 
|  | 1554 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1555 | SDNode *ARMDAGToDAGISel::SelectCMOVOp(SDNode *N) { | 
|  | 1556 | EVT VT = N->getValueType(0); | 
|  | 1557 | SDValue FalseVal = N->getOperand(0); | 
|  | 1558 | SDValue TrueVal  = N->getOperand(1); | 
|  | 1559 | SDValue CC = N->getOperand(2); | 
|  | 1560 | SDValue CCR = N->getOperand(3); | 
|  | 1561 | SDValue InFlag = N->getOperand(4); | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1562 | assert(CC.getOpcode() == ISD::Constant); | 
|  | 1563 | assert(CCR.getOpcode() == ISD::Register); | 
|  | 1564 | ARMCC::CondCodes CCVal = | 
|  | 1565 | (ARMCC::CondCodes)cast<ConstantSDNode>(CC)->getZExtValue(); | 
| Evan Cheng | b6c7704 | 2009-11-19 21:45:22 +0000 | [diff] [blame] | 1566 |  | 
|  | 1567 | if (!Subtarget->isThumb1Only() && VT == MVT::i32) { | 
|  | 1568 | // Pattern: (ARMcmov:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc) | 
|  | 1569 | // Emits: (MOVCCs:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc) | 
|  | 1570 | // Pattern complexity = 18  cost = 1  size = 0 | 
|  | 1571 | SDValue CPTmp0; | 
|  | 1572 | SDValue CPTmp1; | 
|  | 1573 | SDValue CPTmp2; | 
|  | 1574 | if (Subtarget->isThumb()) { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1575 | SDNode *Res = SelectT2CMOVShiftOp(N, FalseVal, TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1576 | CCVal, CCR, InFlag); | 
|  | 1577 | if (!Res) | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1578 | Res = SelectT2CMOVShiftOp(N, TrueVal, FalseVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1579 | ARMCC::getOppositeCondition(CCVal), CCR, InFlag); | 
|  | 1580 | if (Res) | 
|  | 1581 | return Res; | 
| Evan Cheng | b6c7704 | 2009-11-19 21:45:22 +0000 | [diff] [blame] | 1582 | } else { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1583 | SDNode *Res = SelectARMCMOVShiftOp(N, FalseVal, TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1584 | CCVal, CCR, InFlag); | 
|  | 1585 | if (!Res) | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1586 | Res = SelectARMCMOVShiftOp(N, TrueVal, FalseVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1587 | ARMCC::getOppositeCondition(CCVal), CCR, InFlag); | 
|  | 1588 | if (Res) | 
|  | 1589 | return Res; | 
| Evan Cheng | b6c7704 | 2009-11-19 21:45:22 +0000 | [diff] [blame] | 1590 | } | 
|  | 1591 |  | 
|  | 1592 | // Pattern: (ARMcmov:i32 GPR:i32:$false, | 
| Jakob Stoklund Olesen | e2cbaf6 | 2010-08-17 20:39:04 +0000 | [diff] [blame] | 1593 | //             (imm:i32)<<P:Pred_so_imm>>:$true, | 
| Evan Cheng | b6c7704 | 2009-11-19 21:45:22 +0000 | [diff] [blame] | 1594 | //             (imm:i32):$cc) | 
|  | 1595 | // Emits: (MOVCCi:i32 GPR:i32:$false, | 
|  | 1596 | //           (so_imm:i32 (imm:i32):$true), (imm:i32):$cc) | 
|  | 1597 | // Pattern complexity = 10  cost = 1  size = 0 | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1598 | if (Subtarget->isThumb()) { | 
| Jim Grosbach | 5b255c2 | 2010-10-07 00:53:56 +0000 | [diff] [blame] | 1599 | SDNode *Res = SelectT2CMOVImmOp(N, FalseVal, TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1600 | CCVal, CCR, InFlag); | 
|  | 1601 | if (!Res) | 
| Jim Grosbach | 5b255c2 | 2010-10-07 00:53:56 +0000 | [diff] [blame] | 1602 | Res = SelectT2CMOVImmOp(N, TrueVal, FalseVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1603 | ARMCC::getOppositeCondition(CCVal), CCR, InFlag); | 
|  | 1604 | if (Res) | 
|  | 1605 | return Res; | 
|  | 1606 | } else { | 
| Jim Grosbach | 742adc3 | 2010-10-07 00:42:42 +0000 | [diff] [blame] | 1607 | SDNode *Res = SelectARMCMOVImmOp(N, FalseVal, TrueVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1608 | CCVal, CCR, InFlag); | 
|  | 1609 | if (!Res) | 
| Jim Grosbach | 742adc3 | 2010-10-07 00:42:42 +0000 | [diff] [blame] | 1610 | Res = SelectARMCMOVImmOp(N, TrueVal, FalseVal, | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1611 | ARMCC::getOppositeCondition(CCVal), CCR, InFlag); | 
|  | 1612 | if (Res) | 
|  | 1613 | return Res; | 
| Evan Cheng | b6c7704 | 2009-11-19 21:45:22 +0000 | [diff] [blame] | 1614 | } | 
|  | 1615 | } | 
|  | 1616 |  | 
|  | 1617 | // Pattern: (ARMcmov:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) | 
|  | 1618 | // Emits: (MOVCCr:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) | 
|  | 1619 | // Pattern complexity = 6  cost = 1  size = 0 | 
|  | 1620 | // | 
|  | 1621 | // Pattern: (ARMcmov:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) | 
|  | 1622 | // Emits: (tMOVCCr:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc) | 
|  | 1623 | // Pattern complexity = 6  cost = 11  size = 0 | 
|  | 1624 | // | 
|  | 1625 | // Also FCPYScc and FCPYDcc. | 
| Evan Cheng | 81a2851 | 2009-11-20 00:54:03 +0000 | [diff] [blame] | 1626 | SDValue Tmp2 = CurDAG->getTargetConstant(CCVal, MVT::i32); | 
|  | 1627 | SDValue Ops[] = { FalseVal, TrueVal, Tmp2, CCR, InFlag }; | 
| Evan Cheng | b6c7704 | 2009-11-19 21:45:22 +0000 | [diff] [blame] | 1628 | unsigned Opc = 0; | 
|  | 1629 | switch (VT.getSimpleVT().SimpleTy) { | 
|  | 1630 | default: assert(false && "Illegal conditional move type!"); | 
|  | 1631 | break; | 
|  | 1632 | case MVT::i32: | 
|  | 1633 | Opc = Subtarget->isThumb() | 
|  | 1634 | ? (Subtarget->hasThumb2() ? ARM::t2MOVCCr : ARM::tMOVCCr_pseudo) | 
|  | 1635 | : ARM::MOVCCr; | 
|  | 1636 | break; | 
|  | 1637 | case MVT::f32: | 
|  | 1638 | Opc = ARM::VMOVScc; | 
|  | 1639 | break; | 
|  | 1640 | case MVT::f64: | 
|  | 1641 | Opc = ARM::VMOVDcc; | 
|  | 1642 | break; | 
|  | 1643 | } | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1644 | return CurDAG->SelectNodeTo(N, Opc, VT, Ops, 5); | 
| Evan Cheng | b6c7704 | 2009-11-19 21:45:22 +0000 | [diff] [blame] | 1645 | } | 
|  | 1646 |  | 
| Evan Cheng | d85631e | 2010-05-05 18:28:36 +0000 | [diff] [blame] | 1647 | SDNode *ARMDAGToDAGISel::SelectConcatVector(SDNode *N) { | 
|  | 1648 | // The only time a CONCAT_VECTORS operation can have legal types is when | 
|  | 1649 | // two 64-bit vectors are concatenated to a 128-bit vector. | 
|  | 1650 | EVT VT = N->getValueType(0); | 
|  | 1651 | if (!VT.is128BitVector() || N->getNumOperands() != 2) | 
|  | 1652 | llvm_unreachable("unexpected CONCAT_VECTORS"); | 
|  | 1653 | DebugLoc dl = N->getDebugLoc(); | 
|  | 1654 | SDValue V0 = N->getOperand(0); | 
|  | 1655 | SDValue V1 = N->getOperand(1); | 
| Jakob Stoklund Olesen | 6c47d64 | 2010-05-24 16:54:32 +0000 | [diff] [blame] | 1656 | SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, MVT::i32); | 
|  | 1657 | SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, MVT::i32); | 
| Evan Cheng | d85631e | 2010-05-05 18:28:36 +0000 | [diff] [blame] | 1658 | const SDValue Ops[] = { V0, SubReg0, V1, SubReg1 }; | 
|  | 1659 | return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 4); | 
|  | 1660 | } | 
|  | 1661 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1662 | SDNode *ARMDAGToDAGISel::Select(SDNode *N) { | 
| Dale Johannesen | 9f3f72f | 2009-02-06 01:31:28 +0000 | [diff] [blame] | 1663 | DebugLoc dl = N->getDebugLoc(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1664 |  | 
| Dan Gohman | 1705968 | 2008-07-17 19:10:17 +0000 | [diff] [blame] | 1665 | if (N->isMachineOpcode()) | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1666 | return NULL;   // Already selected. | 
| Rafael Espindola | 4e76015 | 2006-06-12 12:28:08 +0000 | [diff] [blame] | 1667 |  | 
|  | 1668 | switch (N->getOpcode()) { | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1669 | default: break; | 
|  | 1670 | case ISD::Constant: { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 1671 | unsigned Val = cast<ConstantSDNode>(N)->getZExtValue(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1672 | bool UseCP = true; | 
| Anton Korobeynikov | 7c2b1e7 | 2009-09-27 23:52:58 +0000 | [diff] [blame] | 1673 | if (Subtarget->hasThumb2()) | 
|  | 1674 | // Thumb2-aware targets have the MOVT instruction, so all immediates can | 
|  | 1675 | // be done with MOV + MOVT, at worst. | 
|  | 1676 | UseCP = 0; | 
|  | 1677 | else { | 
|  | 1678 | if (Subtarget->isThumb()) { | 
| Bob Wilson | 360eef0 | 2009-06-22 17:29:13 +0000 | [diff] [blame] | 1679 | UseCP = (Val > 255 &&                          // MOV | 
|  | 1680 | ~Val > 255 &&                         // MOV + MVN | 
|  | 1681 | !ARM_AM::isThumbImmShiftedVal(Val));  // MOV + LSL | 
| Anton Korobeynikov | 7c2b1e7 | 2009-09-27 23:52:58 +0000 | [diff] [blame] | 1682 | } else | 
|  | 1683 | UseCP = (ARM_AM::getSOImmVal(Val) == -1 &&     // MOV | 
|  | 1684 | ARM_AM::getSOImmVal(~Val) == -1 &&    // MVN | 
|  | 1685 | !ARM_AM::isSOImmTwoPartVal(Val));     // two instrs. | 
|  | 1686 | } | 
|  | 1687 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1688 | if (UseCP) { | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 1689 | SDValue CPIdx = | 
| Owen Anderson | 55f1c09 | 2009-08-13 21:58:54 +0000 | [diff] [blame] | 1690 | CurDAG->getTargetConstantPool(ConstantInt::get( | 
|  | 1691 | Type::getInt32Ty(*CurDAG->getContext()), Val), | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1692 | TLI.getPointerTy()); | 
| Evan Cheng | 1526ba5 | 2007-01-24 08:53:17 +0000 | [diff] [blame] | 1693 |  | 
|  | 1694 | SDNode *ResNode; | 
| Evan Cheng | cd4cdd1 | 2009-07-11 06:43:01 +0000 | [diff] [blame] | 1695 | if (Subtarget->isThumb1Only()) { | 
| Evan Cheng | 3da64f76 | 2010-04-16 05:46:06 +0000 | [diff] [blame] | 1696 | SDValue Pred = getAL(CurDAG); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1697 | SDValue PredReg = CurDAG->getRegister(0, MVT::i32); | 
| Evan Cheng | cd4cdd1 | 2009-07-11 06:43:01 +0000 | [diff] [blame] | 1698 | SDValue Ops[] = { CPIdx, Pred, PredReg, CurDAG->getEntryNode() }; | 
| Dan Gohman | 32f71d7 | 2009-09-25 18:54:59 +0000 | [diff] [blame] | 1699 | ResNode = CurDAG->getMachineNode(ARM::tLDRcp, dl, MVT::i32, MVT::Other, | 
|  | 1700 | Ops, 4); | 
| Evan Cheng | cd4cdd1 | 2009-07-11 06:43:01 +0000 | [diff] [blame] | 1701 | } else { | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 1702 | SDValue Ops[] = { | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 1703 | CPIdx, | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1704 | CurDAG->getRegister(0, MVT::i32), | 
|  | 1705 | CurDAG->getTargetConstant(0, MVT::i32), | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1706 | getAL(CurDAG), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1707 | CurDAG->getRegister(0, MVT::i32), | 
| Evan Cheng | 1526ba5 | 2007-01-24 08:53:17 +0000 | [diff] [blame] | 1708 | CurDAG->getEntryNode() | 
|  | 1709 | }; | 
| Dan Gohman | 32f71d7 | 2009-09-25 18:54:59 +0000 | [diff] [blame] | 1710 | ResNode=CurDAG->getMachineNode(ARM::LDRcp, dl, MVT::i32, MVT::Other, | 
|  | 1711 | Ops, 6); | 
| Evan Cheng | 1526ba5 | 2007-01-24 08:53:17 +0000 | [diff] [blame] | 1712 | } | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1713 | ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1714 | return NULL; | 
|  | 1715 | } | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 1716 |  | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1717 | // Other cases are autogenerated. | 
| Rafael Espindola | 4e76015 | 2006-06-12 12:28:08 +0000 | [diff] [blame] | 1718 | break; | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1719 | } | 
| Rafael Espindola | 5f7ab1b | 2006-11-09 13:58:55 +0000 | [diff] [blame] | 1720 | case ISD::FrameIndex: { | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1721 | // Selects to ADDri FI, 0 which in turn will become ADDri SP, imm. | 
| Rafael Espindola | 5f7ab1b | 2006-11-09 13:58:55 +0000 | [diff] [blame] | 1722 | int FI = cast<FrameIndexSDNode>(N)->getIndex(); | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 1723 | SDValue TFI = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); | 
| David Goodwin | 22c2fba | 2009-07-08 23:10:31 +0000 | [diff] [blame] | 1724 | if (Subtarget->isThumb1Only()) { | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1725 | return CurDAG->SelectNodeTo(N, ARM::tADDrSPi, MVT::i32, TFI, | 
|  | 1726 | CurDAG->getTargetConstant(0, MVT::i32)); | 
| Jim Grosbach | fde2110 | 2009-04-07 20:34:09 +0000 | [diff] [blame] | 1727 | } else { | 
| David Goodwin | 4ad7797 | 2009-07-14 18:48:51 +0000 | [diff] [blame] | 1728 | unsigned Opc = ((Subtarget->isThumb() && Subtarget->hasThumb2()) ? | 
|  | 1729 | ARM::t2ADDri : ARM::ADDri); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1730 | SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, MVT::i32), | 
|  | 1731 | getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), | 
|  | 1732 | CurDAG->getRegister(0, MVT::i32) }; | 
|  | 1733 | return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5); | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1734 | } | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1735 | } | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 1736 | case ISD::SRL: | 
| Jim Grosbach | 825cb29 | 2010-04-22 23:24:18 +0000 | [diff] [blame] | 1737 | if (SDNode *I = SelectV6T2BitfieldExtractOp(N, false)) | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 1738 | return I; | 
|  | 1739 | break; | 
|  | 1740 | case ISD::SRA: | 
| Jim Grosbach | 825cb29 | 2010-04-22 23:24:18 +0000 | [diff] [blame] | 1741 | if (SDNode *I = SelectV6T2BitfieldExtractOp(N, true)) | 
| Sandeep Patel | 423e42b | 2009-10-13 18:59:48 +0000 | [diff] [blame] | 1742 | return I; | 
|  | 1743 | break; | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1744 | case ISD::MUL: | 
| Evan Cheng | b24e51e | 2009-07-07 01:17:28 +0000 | [diff] [blame] | 1745 | if (Subtarget->isThumb1Only()) | 
| Evan Cheng | 139edae | 2007-01-24 02:21:22 +0000 | [diff] [blame] | 1746 | break; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1747 | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) { | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 1748 | unsigned RHSV = C->getZExtValue(); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1749 | if (!RHSV) break; | 
|  | 1750 | if (isPowerOf2_32(RHSV-1)) {  // 2^n+1? | 
| Evan Cheng | 0d8b0cf | 2009-07-21 00:31:12 +0000 | [diff] [blame] | 1751 | unsigned ShImm = Log2_32(RHSV-1); | 
|  | 1752 | if (ShImm >= 32) | 
|  | 1753 | break; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1754 | SDValue V = N->getOperand(0); | 
| Evan Cheng | 0d8b0cf | 2009-07-21 00:31:12 +0000 | [diff] [blame] | 1755 | ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1756 | SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, MVT::i32); | 
|  | 1757 | SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); | 
| Evan Cheng | 1ec4396 | 2009-07-22 18:08:05 +0000 | [diff] [blame] | 1758 | if (Subtarget->isThumb()) { | 
| Evan Cheng | 0d8b0cf | 2009-07-21 00:31:12 +0000 | [diff] [blame] | 1759 | SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG), Reg0, Reg0 }; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1760 | return CurDAG->SelectNodeTo(N, ARM::t2ADDrs, MVT::i32, Ops, 6); | 
| Evan Cheng | 0d8b0cf | 2009-07-21 00:31:12 +0000 | [diff] [blame] | 1761 | } else { | 
|  | 1762 | SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG), Reg0, Reg0 }; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1763 | return CurDAG->SelectNodeTo(N, ARM::ADDrs, MVT::i32, Ops, 7); | 
| Evan Cheng | 0d8b0cf | 2009-07-21 00:31:12 +0000 | [diff] [blame] | 1764 | } | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1765 | } | 
|  | 1766 | if (isPowerOf2_32(RHSV+1)) {  // 2^n-1? | 
| Evan Cheng | 0d8b0cf | 2009-07-21 00:31:12 +0000 | [diff] [blame] | 1767 | unsigned ShImm = Log2_32(RHSV+1); | 
|  | 1768 | if (ShImm >= 32) | 
|  | 1769 | break; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1770 | SDValue V = N->getOperand(0); | 
| Evan Cheng | 0d8b0cf | 2009-07-21 00:31:12 +0000 | [diff] [blame] | 1771 | ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm); | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1772 | SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, MVT::i32); | 
|  | 1773 | SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); | 
| Evan Cheng | 1ec4396 | 2009-07-22 18:08:05 +0000 | [diff] [blame] | 1774 | if (Subtarget->isThumb()) { | 
| Bob Wilson | b6112e8 | 2010-05-28 00:27:15 +0000 | [diff] [blame] | 1775 | SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG), Reg0, Reg0 }; | 
|  | 1776 | return CurDAG->SelectNodeTo(N, ARM::t2RSBrs, MVT::i32, Ops, 6); | 
| Evan Cheng | 0d8b0cf | 2009-07-21 00:31:12 +0000 | [diff] [blame] | 1777 | } else { | 
|  | 1778 | SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG), Reg0, Reg0 }; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1779 | return CurDAG->SelectNodeTo(N, ARM::RSBrs, MVT::i32, Ops, 7); | 
| Evan Cheng | 0d8b0cf | 2009-07-21 00:31:12 +0000 | [diff] [blame] | 1780 | } | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1781 | } | 
|  | 1782 | } | 
|  | 1783 | break; | 
| Evan Cheng | 786b15f | 2009-10-21 08:15:52 +0000 | [diff] [blame] | 1784 | case ISD::AND: { | 
| Jim Grosbach | 825cb29 | 2010-04-22 23:24:18 +0000 | [diff] [blame] | 1785 | // Check for unsigned bitfield extract | 
|  | 1786 | if (SDNode *I = SelectV6T2BitfieldExtractOp(N, false)) | 
|  | 1787 | return I; | 
|  | 1788 |  | 
| Evan Cheng | 786b15f | 2009-10-21 08:15:52 +0000 | [diff] [blame] | 1789 | // (and (or x, c2), c1) and top 16-bits of c1 and c2 match, lower 16-bits | 
|  | 1790 | // of c1 are 0xffff, and lower 16-bit of c2 are 0. That is, the top 16-bits | 
|  | 1791 | // are entirely contributed by c2 and lower 16-bits are entirely contributed | 
|  | 1792 | // by x. That's equal to (or (and x, 0xffff), (and c1, 0xffff0000)). | 
|  | 1793 | // Select it to: "movt x, ((c1 & 0xffff) >> 16) | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1794 | EVT VT = N->getValueType(0); | 
| Evan Cheng | 786b15f | 2009-10-21 08:15:52 +0000 | [diff] [blame] | 1795 | if (VT != MVT::i32) | 
|  | 1796 | break; | 
|  | 1797 | unsigned Opc = (Subtarget->isThumb() && Subtarget->hasThumb2()) | 
|  | 1798 | ? ARM::t2MOVTi16 | 
|  | 1799 | : (Subtarget->hasV6T2Ops() ? ARM::MOVTi16 : 0); | 
|  | 1800 | if (!Opc) | 
|  | 1801 | break; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1802 | SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); | 
| Evan Cheng | 786b15f | 2009-10-21 08:15:52 +0000 | [diff] [blame] | 1803 | ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1); | 
|  | 1804 | if (!N1C) | 
|  | 1805 | break; | 
|  | 1806 | if (N0.getOpcode() == ISD::OR && N0.getNode()->hasOneUse()) { | 
|  | 1807 | SDValue N2 = N0.getOperand(1); | 
|  | 1808 | ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2); | 
|  | 1809 | if (!N2C) | 
|  | 1810 | break; | 
|  | 1811 | unsigned N1CVal = N1C->getZExtValue(); | 
|  | 1812 | unsigned N2CVal = N2C->getZExtValue(); | 
|  | 1813 | if ((N1CVal & 0xffff0000U) == (N2CVal & 0xffff0000U) && | 
|  | 1814 | (N1CVal & 0xffffU) == 0xffffU && | 
|  | 1815 | (N2CVal & 0xffffU) == 0x0U) { | 
|  | 1816 | SDValue Imm16 = CurDAG->getTargetConstant((N2CVal & 0xFFFF0000U) >> 16, | 
|  | 1817 | MVT::i32); | 
|  | 1818 | SDValue Ops[] = { N0.getOperand(0), Imm16, | 
|  | 1819 | getAL(CurDAG), CurDAG->getRegister(0, MVT::i32) }; | 
|  | 1820 | return CurDAG->getMachineNode(Opc, dl, VT, Ops, 4); | 
|  | 1821 | } | 
|  | 1822 | } | 
|  | 1823 | break; | 
|  | 1824 | } | 
| Jim Grosbach | d7cf55c | 2009-11-09 00:11:35 +0000 | [diff] [blame] | 1825 | case ARMISD::VMOVRRD: | 
|  | 1826 | return CurDAG->getMachineNode(ARM::VMOVRRD, dl, MVT::i32, MVT::i32, | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1827 | N->getOperand(0), getAL(CurDAG), | 
| Dan Gohman | 32f71d7 | 2009-09-25 18:54:59 +0000 | [diff] [blame] | 1828 | CurDAG->getRegister(0, MVT::i32)); | 
| Dan Gohman | a160361 | 2007-10-08 18:33:35 +0000 | [diff] [blame] | 1829 | case ISD::UMUL_LOHI: { | 
| Evan Cheng | b24e51e | 2009-07-07 01:17:28 +0000 | [diff] [blame] | 1830 | if (Subtarget->isThumb1Only()) | 
|  | 1831 | break; | 
|  | 1832 | if (Subtarget->isThumb()) { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1833 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1834 | getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), | 
|  | 1835 | CurDAG->getRegister(0, MVT::i32) }; | 
| Jim Grosbach | 84511e1 | 2010-06-02 21:53:11 +0000 | [diff] [blame] | 1836 | return CurDAG->getMachineNode(ARM::t2UMULL, dl, MVT::i32, MVT::i32,Ops,4); | 
| Evan Cheng | b24e51e | 2009-07-07 01:17:28 +0000 | [diff] [blame] | 1837 | } else { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1838 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1839 | getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), | 
|  | 1840 | CurDAG->getRegister(0, MVT::i32) }; | 
| Dan Gohman | 32f71d7 | 2009-09-25 18:54:59 +0000 | [diff] [blame] | 1841 | return CurDAG->getMachineNode(ARM::UMULL, dl, MVT::i32, MVT::i32, Ops, 5); | 
| Evan Cheng | b24e51e | 2009-07-07 01:17:28 +0000 | [diff] [blame] | 1842 | } | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1843 | } | 
| Dan Gohman | a160361 | 2007-10-08 18:33:35 +0000 | [diff] [blame] | 1844 | case ISD::SMUL_LOHI: { | 
| Evan Cheng | b24e51e | 2009-07-07 01:17:28 +0000 | [diff] [blame] | 1845 | if (Subtarget->isThumb1Only()) | 
|  | 1846 | break; | 
|  | 1847 | if (Subtarget->isThumb()) { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1848 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1849 | getAL(CurDAG), CurDAG->getRegister(0, MVT::i32) }; | 
| Jim Grosbach | 84511e1 | 2010-06-02 21:53:11 +0000 | [diff] [blame] | 1850 | return CurDAG->getMachineNode(ARM::t2SMULL, dl, MVT::i32, MVT::i32,Ops,4); | 
| Evan Cheng | b24e51e | 2009-07-07 01:17:28 +0000 | [diff] [blame] | 1851 | } else { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1852 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1853 | getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), | 
|  | 1854 | CurDAG->getRegister(0, MVT::i32) }; | 
| Dan Gohman | 32f71d7 | 2009-09-25 18:54:59 +0000 | [diff] [blame] | 1855 | return CurDAG->getMachineNode(ARM::SMULL, dl, MVT::i32, MVT::i32, Ops, 5); | 
| Evan Cheng | b24e51e | 2009-07-07 01:17:28 +0000 | [diff] [blame] | 1856 | } | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1857 | } | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1858 | case ISD::LOAD: { | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 1859 | SDNode *ResNode = 0; | 
| Evan Cheng | b24e51e | 2009-07-07 01:17:28 +0000 | [diff] [blame] | 1860 | if (Subtarget->isThumb() && Subtarget->hasThumb2()) | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1861 | ResNode = SelectT2IndexedLoad(N); | 
| Evan Cheng | 84c6cda | 2009-07-02 07:28:31 +0000 | [diff] [blame] | 1862 | else | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1863 | ResNode = SelectARMIndexedLoad(N); | 
| Evan Cheng | d9c5536 | 2009-07-02 01:23:32 +0000 | [diff] [blame] | 1864 | if (ResNode) | 
|  | 1865 | return ResNode; | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1866 | // Other cases are autogenerated. | 
| Rafael Espindola | 5f7ab1b | 2006-11-09 13:58:55 +0000 | [diff] [blame] | 1867 | break; | 
| Rafael Espindola | 4e76015 | 2006-06-12 12:28:08 +0000 | [diff] [blame] | 1868 | } | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1869 | case ARMISD::BRCOND: { | 
|  | 1870 | // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc) | 
|  | 1871 | // Emits: (Bcc:void (bb:Other):$dst, (imm:i32):$cc) | 
|  | 1872 | // Pattern complexity = 6  cost = 1  size = 0 | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 1873 |  | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1874 | // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc) | 
|  | 1875 | // Emits: (tBcc:void (bb:Other):$dst, (imm:i32):$cc) | 
|  | 1876 | // Pattern complexity = 6  cost = 1  size = 0 | 
|  | 1877 |  | 
| David Goodwin | 27303cd | 2009-06-30 18:04:13 +0000 | [diff] [blame] | 1878 | // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc) | 
|  | 1879 | // Emits: (t2Bcc:void (bb:Other):$dst, (imm:i32):$cc) | 
|  | 1880 | // Pattern complexity = 6  cost = 1  size = 0 | 
|  | 1881 |  | 
| Jim Grosbach | f24f9d9 | 2009-08-11 15:33:49 +0000 | [diff] [blame] | 1882 | unsigned Opc = Subtarget->isThumb() ? | 
| David Goodwin | 27303cd | 2009-06-30 18:04:13 +0000 | [diff] [blame] | 1883 | ((Subtarget->hasThumb2()) ? ARM::t2Bcc : ARM::tBcc) : ARM::Bcc; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1884 | SDValue Chain = N->getOperand(0); | 
|  | 1885 | SDValue N1 = N->getOperand(1); | 
|  | 1886 | SDValue N2 = N->getOperand(2); | 
|  | 1887 | SDValue N3 = N->getOperand(3); | 
|  | 1888 | SDValue InFlag = N->getOperand(4); | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1889 | assert(N1.getOpcode() == ISD::BasicBlock); | 
|  | 1890 | assert(N2.getOpcode() == ISD::Constant); | 
|  | 1891 | assert(N3.getOpcode() == ISD::Register); | 
|  | 1892 |  | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 1893 | SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 1894 | cast<ConstantSDNode>(N2)->getZExtValue()), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1895 | MVT::i32); | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 1896 | SDValue Ops[] = { N1, Tmp2, N3, Chain, InFlag }; | 
| Dan Gohman | 32f71d7 | 2009-09-25 18:54:59 +0000 | [diff] [blame] | 1897 | SDNode *ResNode = CurDAG->getMachineNode(Opc, dl, MVT::Other, | 
|  | 1898 | MVT::Flag, Ops, 5); | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 1899 | Chain = SDValue(ResNode, 0); | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1900 | if (N->getNumValues() == 2) { | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 1901 | InFlag = SDValue(ResNode, 1); | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1902 | ReplaceUses(SDValue(N, 1), InFlag); | 
| Chris Lattner | e99faac | 2008-02-03 03:20:59 +0000 | [diff] [blame] | 1903 | } | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1904 | ReplaceUses(SDValue(N, 0), | 
| Evan Cheng | 82adca8 | 2009-11-19 08:16:50 +0000 | [diff] [blame] | 1905 | SDValue(Chain.getNode(), Chain.getResNo())); | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1906 | return NULL; | 
|  | 1907 | } | 
| Evan Cheng | b6c7704 | 2009-11-19 21:45:22 +0000 | [diff] [blame] | 1908 | case ARMISD::CMOV: | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1909 | return SelectCMOVOp(N); | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1910 | case ARMISD::CNEG: { | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1911 | EVT VT = N->getValueType(0); | 
|  | 1912 | SDValue N0 = N->getOperand(0); | 
|  | 1913 | SDValue N1 = N->getOperand(1); | 
|  | 1914 | SDValue N2 = N->getOperand(2); | 
|  | 1915 | SDValue N3 = N->getOperand(3); | 
|  | 1916 | SDValue InFlag = N->getOperand(4); | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1917 | assert(N2.getOpcode() == ISD::Constant); | 
|  | 1918 | assert(N3.getOpcode() == ISD::Register); | 
|  | 1919 |  | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 1920 | SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned) | 
| Dan Gohman | effb894 | 2008-09-12 16:56:44 +0000 | [diff] [blame] | 1921 | cast<ConstantSDNode>(N2)->getZExtValue()), | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1922 | MVT::i32); | 
| Dan Gohman | 2ce6f2a | 2008-07-27 21:46:04 +0000 | [diff] [blame] | 1923 | SDValue Ops[] = { N0, N1, Tmp2, N3, InFlag }; | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1924 | unsigned Opc = 0; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1925 | switch (VT.getSimpleVT().SimpleTy) { | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1926 | default: assert(false && "Illegal conditional move type!"); | 
|  | 1927 | break; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1928 | case MVT::f32: | 
| Jim Grosbach | d7cf55c | 2009-11-09 00:11:35 +0000 | [diff] [blame] | 1929 | Opc = ARM::VNEGScc; | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1930 | break; | 
| Owen Anderson | 9f94459 | 2009-08-11 20:47:22 +0000 | [diff] [blame] | 1931 | case MVT::f64: | 
| Jim Grosbach | d7cf55c | 2009-11-09 00:11:35 +0000 | [diff] [blame] | 1932 | Opc = ARM::VNEGDcc; | 
| Evan Cheng | d502173 | 2008-12-10 21:54:21 +0000 | [diff] [blame] | 1933 | break; | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1934 | } | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 1935 | return CurDAG->SelectNodeTo(N, Opc, VT, Ops, 5); | 
| Evan Cheng | 7e90b11 | 2007-07-05 07:15:27 +0000 | [diff] [blame] | 1936 | } | 
| Evan Cheng | d502173 | 2008-12-10 21:54:21 +0000 | [diff] [blame] | 1937 |  | 
| Anton Korobeynikov | 232b19c | 2009-08-21 12:41:42 +0000 | [diff] [blame] | 1938 | case ARMISD::VZIP: { | 
|  | 1939 | unsigned Opc = 0; | 
| Anton Korobeynikov | ce3ff1b | 2009-08-21 12:40:50 +0000 | [diff] [blame] | 1940 | EVT VT = N->getValueType(0); | 
| Anton Korobeynikov | 232b19c | 2009-08-21 12:41:42 +0000 | [diff] [blame] | 1941 | switch (VT.getSimpleVT().SimpleTy) { | 
|  | 1942 | default: return NULL; | 
|  | 1943 | case MVT::v8i8:  Opc = ARM::VZIPd8; break; | 
|  | 1944 | case MVT::v4i16: Opc = ARM::VZIPd16; break; | 
|  | 1945 | case MVT::v2f32: | 
|  | 1946 | case MVT::v2i32: Opc = ARM::VZIPd32; break; | 
|  | 1947 | case MVT::v16i8: Opc = ARM::VZIPq8; break; | 
|  | 1948 | case MVT::v8i16: Opc = ARM::VZIPq16; break; | 
|  | 1949 | case MVT::v4f32: | 
|  | 1950 | case MVT::v4i32: Opc = ARM::VZIPq32; break; | 
|  | 1951 | } | 
| Evan Cheng | 3da64f76 | 2010-04-16 05:46:06 +0000 | [diff] [blame] | 1952 | SDValue Pred = getAL(CurDAG); | 
| Evan Cheng | a33fc86 | 2009-11-21 06:21:52 +0000 | [diff] [blame] | 1953 | SDValue PredReg = CurDAG->getRegister(0, MVT::i32); | 
|  | 1954 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg }; | 
|  | 1955 | return CurDAG->getMachineNode(Opc, dl, VT, VT, Ops, 4); | 
| Anton Korobeynikov | ce3ff1b | 2009-08-21 12:40:50 +0000 | [diff] [blame] | 1956 | } | 
| Anton Korobeynikov | 232b19c | 2009-08-21 12:41:42 +0000 | [diff] [blame] | 1957 | case ARMISD::VUZP: { | 
|  | 1958 | unsigned Opc = 0; | 
| Anton Korobeynikov | ce3ff1b | 2009-08-21 12:40:50 +0000 | [diff] [blame] | 1959 | EVT VT = N->getValueType(0); | 
| Anton Korobeynikov | 232b19c | 2009-08-21 12:41:42 +0000 | [diff] [blame] | 1960 | switch (VT.getSimpleVT().SimpleTy) { | 
|  | 1961 | default: return NULL; | 
|  | 1962 | case MVT::v8i8:  Opc = ARM::VUZPd8; break; | 
|  | 1963 | case MVT::v4i16: Opc = ARM::VUZPd16; break; | 
|  | 1964 | case MVT::v2f32: | 
|  | 1965 | case MVT::v2i32: Opc = ARM::VUZPd32; break; | 
|  | 1966 | case MVT::v16i8: Opc = ARM::VUZPq8; break; | 
|  | 1967 | case MVT::v8i16: Opc = ARM::VUZPq16; break; | 
|  | 1968 | case MVT::v4f32: | 
|  | 1969 | case MVT::v4i32: Opc = ARM::VUZPq32; break; | 
|  | 1970 | } | 
| Evan Cheng | 3da64f76 | 2010-04-16 05:46:06 +0000 | [diff] [blame] | 1971 | SDValue Pred = getAL(CurDAG); | 
| Evan Cheng | a33fc86 | 2009-11-21 06:21:52 +0000 | [diff] [blame] | 1972 | SDValue PredReg = CurDAG->getRegister(0, MVT::i32); | 
|  | 1973 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg }; | 
|  | 1974 | return CurDAG->getMachineNode(Opc, dl, VT, VT, Ops, 4); | 
| Anton Korobeynikov | ce3ff1b | 2009-08-21 12:40:50 +0000 | [diff] [blame] | 1975 | } | 
| Anton Korobeynikov | 232b19c | 2009-08-21 12:41:42 +0000 | [diff] [blame] | 1976 | case ARMISD::VTRN: { | 
|  | 1977 | unsigned Opc = 0; | 
| Anton Korobeynikov | ce3ff1b | 2009-08-21 12:40:50 +0000 | [diff] [blame] | 1978 | EVT VT = N->getValueType(0); | 
| Anton Korobeynikov | 232b19c | 2009-08-21 12:41:42 +0000 | [diff] [blame] | 1979 | switch (VT.getSimpleVT().SimpleTy) { | 
|  | 1980 | default: return NULL; | 
|  | 1981 | case MVT::v8i8:  Opc = ARM::VTRNd8; break; | 
|  | 1982 | case MVT::v4i16: Opc = ARM::VTRNd16; break; | 
|  | 1983 | case MVT::v2f32: | 
|  | 1984 | case MVT::v2i32: Opc = ARM::VTRNd32; break; | 
|  | 1985 | case MVT::v16i8: Opc = ARM::VTRNq8; break; | 
|  | 1986 | case MVT::v8i16: Opc = ARM::VTRNq16; break; | 
|  | 1987 | case MVT::v4f32: | 
|  | 1988 | case MVT::v4i32: Opc = ARM::VTRNq32; break; | 
|  | 1989 | } | 
| Evan Cheng | 3da64f76 | 2010-04-16 05:46:06 +0000 | [diff] [blame] | 1990 | SDValue Pred = getAL(CurDAG); | 
| Evan Cheng | a33fc86 | 2009-11-21 06:21:52 +0000 | [diff] [blame] | 1991 | SDValue PredReg = CurDAG->getRegister(0, MVT::i32); | 
|  | 1992 | SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg }; | 
|  | 1993 | return CurDAG->getMachineNode(Opc, dl, VT, VT, Ops, 4); | 
| Anton Korobeynikov | ce3ff1b | 2009-08-21 12:40:50 +0000 | [diff] [blame] | 1994 | } | 
| Bob Wilson | d8a9a04 | 2010-06-04 00:04:02 +0000 | [diff] [blame] | 1995 | case ARMISD::BUILD_VECTOR: { | 
|  | 1996 | EVT VecVT = N->getValueType(0); | 
|  | 1997 | EVT EltVT = VecVT.getVectorElementType(); | 
|  | 1998 | unsigned NumElts = VecVT.getVectorNumElements(); | 
|  | 1999 | if (EltVT.getSimpleVT() == MVT::f64) { | 
|  | 2000 | assert(NumElts == 2 && "unexpected type for BUILD_VECTOR"); | 
|  | 2001 | return PairDRegs(VecVT, N->getOperand(0), N->getOperand(1)); | 
|  | 2002 | } | 
|  | 2003 | assert(EltVT.getSimpleVT() == MVT::f32 && | 
|  | 2004 | "unexpected type for BUILD_VECTOR"); | 
|  | 2005 | if (NumElts == 2) | 
|  | 2006 | return PairSRegs(VecVT, N->getOperand(0), N->getOperand(1)); | 
|  | 2007 | assert(NumElts == 4 && "unexpected type for BUILD_VECTOR"); | 
|  | 2008 | return QuadSRegs(VecVT, N->getOperand(0), N->getOperand(1), | 
|  | 2009 | N->getOperand(2), N->getOperand(3)); | 
|  | 2010 | } | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2011 |  | 
|  | 2012 | case ISD::INTRINSIC_VOID: | 
|  | 2013 | case ISD::INTRINSIC_W_CHAIN: { | 
|  | 2014 | unsigned IntNo = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue(); | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2015 | switch (IntNo) { | 
|  | 2016 | default: | 
| Bob Wilson | f765e1f | 2010-05-06 16:05:26 +0000 | [diff] [blame] | 2017 | break; | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2018 |  | 
| Bob Wilson | 340861d | 2010-03-23 05:25:43 +0000 | [diff] [blame] | 2019 | case Intrinsic::arm_neon_vld1: { | 
|  | 2020 | unsigned DOpcodes[] = { ARM::VLD1d8, ARM::VLD1d16, | 
|  | 2021 | ARM::VLD1d32, ARM::VLD1d64 }; | 
| Bob Wilson | 75a6408 | 2010-09-02 16:00:54 +0000 | [diff] [blame] | 2022 | unsigned QOpcodes[] = { ARM::VLD1q8Pseudo, ARM::VLD1q16Pseudo, | 
|  | 2023 | ARM::VLD1q32Pseudo, ARM::VLD1q64Pseudo }; | 
| Bob Wilson | 340861d | 2010-03-23 05:25:43 +0000 | [diff] [blame] | 2024 | return SelectVLD(N, 1, DOpcodes, QOpcodes, 0); | 
|  | 2025 | } | 
|  | 2026 |  | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2027 | case Intrinsic::arm_neon_vld2: { | 
| Bob Wilson | 75a6408 | 2010-09-02 16:00:54 +0000 | [diff] [blame] | 2028 | unsigned DOpcodes[] = { ARM::VLD2d8Pseudo, ARM::VLD2d16Pseudo, | 
|  | 2029 | ARM::VLD2d32Pseudo, ARM::VLD1q64Pseudo }; | 
|  | 2030 | unsigned QOpcodes[] = { ARM::VLD2q8Pseudo, ARM::VLD2q16Pseudo, | 
|  | 2031 | ARM::VLD2q32Pseudo }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 2032 | return SelectVLD(N, 2, DOpcodes, QOpcodes, 0); | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2033 | } | 
|  | 2034 |  | 
|  | 2035 | case Intrinsic::arm_neon_vld3: { | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 2036 | unsigned DOpcodes[] = { ARM::VLD3d8Pseudo, ARM::VLD3d16Pseudo, | 
|  | 2037 | ARM::VLD3d32Pseudo, ARM::VLD1d64TPseudo }; | 
|  | 2038 | unsigned QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD, | 
|  | 2039 | ARM::VLD3q16Pseudo_UPD, | 
|  | 2040 | ARM::VLD3q32Pseudo_UPD }; | 
|  | 2041 | unsigned QOpcodes1[] = { ARM::VLD3q8oddPseudo_UPD, | 
|  | 2042 | ARM::VLD3q16oddPseudo_UPD, | 
|  | 2043 | ARM::VLD3q32oddPseudo_UPD }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 2044 | return SelectVLD(N, 3, DOpcodes, QOpcodes0, QOpcodes1); | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2045 | } | 
|  | 2046 |  | 
|  | 2047 | case Intrinsic::arm_neon_vld4: { | 
| Bob Wilson | 35fafca | 2010-09-03 18:16:02 +0000 | [diff] [blame] | 2048 | unsigned DOpcodes[] = { ARM::VLD4d8Pseudo, ARM::VLD4d16Pseudo, | 
|  | 2049 | ARM::VLD4d32Pseudo, ARM::VLD1d64QPseudo }; | 
|  | 2050 | unsigned QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD, | 
|  | 2051 | ARM::VLD4q16Pseudo_UPD, | 
|  | 2052 | ARM::VLD4q32Pseudo_UPD }; | 
|  | 2053 | unsigned QOpcodes1[] = { ARM::VLD4q8oddPseudo_UPD, | 
|  | 2054 | ARM::VLD4q16oddPseudo_UPD, | 
|  | 2055 | ARM::VLD4q32oddPseudo_UPD }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 2056 | return SelectVLD(N, 4, DOpcodes, QOpcodes0, QOpcodes1); | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2057 | } | 
|  | 2058 |  | 
| Bob Wilson | da9817c | 2009-09-01 04:26:28 +0000 | [diff] [blame] | 2059 | case Intrinsic::arm_neon_vld2lane: { | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 2060 | unsigned DOpcodes[] = { ARM::VLD2LNd8Pseudo, ARM::VLD2LNd16Pseudo, | 
|  | 2061 | ARM::VLD2LNd32Pseudo }; | 
|  | 2062 | unsigned QOpcodes[] = { ARM::VLD2LNq16Pseudo, ARM::VLD2LNq32Pseudo }; | 
|  | 2063 | return SelectVLDSTLane(N, true, 2, DOpcodes, QOpcodes); | 
| Bob Wilson | da9817c | 2009-09-01 04:26:28 +0000 | [diff] [blame] | 2064 | } | 
|  | 2065 |  | 
|  | 2066 | case Intrinsic::arm_neon_vld3lane: { | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 2067 | unsigned DOpcodes[] = { ARM::VLD3LNd8Pseudo, ARM::VLD3LNd16Pseudo, | 
|  | 2068 | ARM::VLD3LNd32Pseudo }; | 
|  | 2069 | unsigned QOpcodes[] = { ARM::VLD3LNq16Pseudo, ARM::VLD3LNq32Pseudo }; | 
|  | 2070 | return SelectVLDSTLane(N, true, 3, DOpcodes, QOpcodes); | 
| Bob Wilson | da9817c | 2009-09-01 04:26:28 +0000 | [diff] [blame] | 2071 | } | 
|  | 2072 |  | 
|  | 2073 | case Intrinsic::arm_neon_vld4lane: { | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 2074 | unsigned DOpcodes[] = { ARM::VLD4LNd8Pseudo, ARM::VLD4LNd16Pseudo, | 
|  | 2075 | ARM::VLD4LNd32Pseudo }; | 
|  | 2076 | unsigned QOpcodes[] = { ARM::VLD4LNq16Pseudo, ARM::VLD4LNq32Pseudo }; | 
|  | 2077 | return SelectVLDSTLane(N, true, 4, DOpcodes, QOpcodes); | 
| Bob Wilson | da9817c | 2009-09-01 04:26:28 +0000 | [diff] [blame] | 2078 | } | 
|  | 2079 |  | 
| Bob Wilson | cc0a2a7 | 2010-03-23 06:20:33 +0000 | [diff] [blame] | 2080 | case Intrinsic::arm_neon_vst1: { | 
|  | 2081 | unsigned DOpcodes[] = { ARM::VST1d8, ARM::VST1d16, | 
|  | 2082 | ARM::VST1d32, ARM::VST1d64 }; | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 2083 | unsigned QOpcodes[] = { ARM::VST1q8Pseudo, ARM::VST1q16Pseudo, | 
|  | 2084 | ARM::VST1q32Pseudo, ARM::VST1q64Pseudo }; | 
| Bob Wilson | cc0a2a7 | 2010-03-23 06:20:33 +0000 | [diff] [blame] | 2085 | return SelectVST(N, 1, DOpcodes, QOpcodes, 0); | 
|  | 2086 | } | 
|  | 2087 |  | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2088 | case Intrinsic::arm_neon_vst2: { | 
| Bob Wilson | 950882b | 2010-08-28 05:12:57 +0000 | [diff] [blame] | 2089 | unsigned DOpcodes[] = { ARM::VST2d8Pseudo, ARM::VST2d16Pseudo, | 
|  | 2090 | ARM::VST2d32Pseudo, ARM::VST1q64Pseudo }; | 
|  | 2091 | unsigned QOpcodes[] = { ARM::VST2q8Pseudo, ARM::VST2q16Pseudo, | 
|  | 2092 | ARM::VST2q32Pseudo }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 2093 | return SelectVST(N, 2, DOpcodes, QOpcodes, 0); | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2094 | } | 
|  | 2095 |  | 
|  | 2096 | case Intrinsic::arm_neon_vst3: { | 
| Bob Wilson | 97919e9 | 2010-08-26 18:51:29 +0000 | [diff] [blame] | 2097 | unsigned DOpcodes[] = { ARM::VST3d8Pseudo, ARM::VST3d16Pseudo, | 
|  | 2098 | ARM::VST3d32Pseudo, ARM::VST1d64TPseudo }; | 
|  | 2099 | unsigned QOpcodes0[] = { ARM::VST3q8Pseudo_UPD, | 
|  | 2100 | ARM::VST3q16Pseudo_UPD, | 
|  | 2101 | ARM::VST3q32Pseudo_UPD }; | 
|  | 2102 | unsigned QOpcodes1[] = { ARM::VST3q8oddPseudo_UPD, | 
|  | 2103 | ARM::VST3q16oddPseudo_UPD, | 
|  | 2104 | ARM::VST3q32oddPseudo_UPD }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 2105 | return SelectVST(N, 3, DOpcodes, QOpcodes0, QOpcodes1); | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2106 | } | 
|  | 2107 |  | 
|  | 2108 | case Intrinsic::arm_neon_vst4: { | 
| Bob Wilson | 9392b0e | 2010-08-25 23:27:42 +0000 | [diff] [blame] | 2109 | unsigned DOpcodes[] = { ARM::VST4d8Pseudo, ARM::VST4d16Pseudo, | 
| Bob Wilson | 4cec449 | 2010-08-26 05:33:30 +0000 | [diff] [blame] | 2110 | ARM::VST4d32Pseudo, ARM::VST1d64QPseudo }; | 
| Bob Wilson | 9392b0e | 2010-08-25 23:27:42 +0000 | [diff] [blame] | 2111 | unsigned QOpcodes0[] = { ARM::VST4q8Pseudo_UPD, | 
|  | 2112 | ARM::VST4q16Pseudo_UPD, | 
|  | 2113 | ARM::VST4q32Pseudo_UPD }; | 
|  | 2114 | unsigned QOpcodes1[] = { ARM::VST4q8oddPseudo_UPD, | 
|  | 2115 | ARM::VST4q16oddPseudo_UPD, | 
|  | 2116 | ARM::VST4q32oddPseudo_UPD }; | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 2117 | return SelectVST(N, 4, DOpcodes, QOpcodes0, QOpcodes1); | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2118 | } | 
| Bob Wilson | d779775 | 2009-09-01 18:51:56 +0000 | [diff] [blame] | 2119 |  | 
|  | 2120 | case Intrinsic::arm_neon_vst2lane: { | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 2121 | unsigned DOpcodes[] = { ARM::VST2LNd8Pseudo, ARM::VST2LNd16Pseudo, | 
|  | 2122 | ARM::VST2LNd32Pseudo }; | 
|  | 2123 | unsigned QOpcodes[] = { ARM::VST2LNq16Pseudo, ARM::VST2LNq32Pseudo }; | 
|  | 2124 | return SelectVLDSTLane(N, false, 2, DOpcodes, QOpcodes); | 
| Bob Wilson | d779775 | 2009-09-01 18:51:56 +0000 | [diff] [blame] | 2125 | } | 
|  | 2126 |  | 
|  | 2127 | case Intrinsic::arm_neon_vst3lane: { | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 2128 | unsigned DOpcodes[] = { ARM::VST3LNd8Pseudo, ARM::VST3LNd16Pseudo, | 
|  | 2129 | ARM::VST3LNd32Pseudo }; | 
|  | 2130 | unsigned QOpcodes[] = { ARM::VST3LNq16Pseudo, ARM::VST3LNq32Pseudo }; | 
|  | 2131 | return SelectVLDSTLane(N, false, 3, DOpcodes, QOpcodes); | 
| Bob Wilson | d779775 | 2009-09-01 18:51:56 +0000 | [diff] [blame] | 2132 | } | 
|  | 2133 |  | 
|  | 2134 | case Intrinsic::arm_neon_vst4lane: { | 
| Bob Wilson | d5c57a5 | 2010-09-13 23:01:35 +0000 | [diff] [blame] | 2135 | unsigned DOpcodes[] = { ARM::VST4LNd8Pseudo, ARM::VST4LNd16Pseudo, | 
|  | 2136 | ARM::VST4LNd32Pseudo }; | 
|  | 2137 | unsigned QOpcodes[] = { ARM::VST4LNq16Pseudo, ARM::VST4LNq32Pseudo }; | 
|  | 2138 | return SelectVLDSTLane(N, false, 4, DOpcodes, QOpcodes); | 
| Bob Wilson | d779775 | 2009-09-01 18:51:56 +0000 | [diff] [blame] | 2139 | } | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2140 | } | 
| Bob Wilson | f765e1f | 2010-05-06 16:05:26 +0000 | [diff] [blame] | 2141 | break; | 
| Bob Wilson | e0636a7 | 2009-08-26 17:39:53 +0000 | [diff] [blame] | 2142 | } | 
| Evan Cheng | d85631e | 2010-05-05 18:28:36 +0000 | [diff] [blame] | 2143 |  | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 2144 | case ISD::INTRINSIC_WO_CHAIN: { | 
|  | 2145 | unsigned IntNo = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue(); | 
|  | 2146 | switch (IntNo) { | 
|  | 2147 | default: | 
|  | 2148 | break; | 
|  | 2149 |  | 
|  | 2150 | case Intrinsic::arm_neon_vtbl2: | 
| Bob Wilson | c597fd3b | 2010-09-13 23:55:10 +0000 | [diff] [blame] | 2151 | return SelectVTBL(N, false, 2, ARM::VTBL2Pseudo); | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 2152 | case Intrinsic::arm_neon_vtbl3: | 
| Bob Wilson | c597fd3b | 2010-09-13 23:55:10 +0000 | [diff] [blame] | 2153 | return SelectVTBL(N, false, 3, ARM::VTBL3Pseudo); | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 2154 | case Intrinsic::arm_neon_vtbl4: | 
| Bob Wilson | c597fd3b | 2010-09-13 23:55:10 +0000 | [diff] [blame] | 2155 | return SelectVTBL(N, false, 4, ARM::VTBL4Pseudo); | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 2156 |  | 
|  | 2157 | case Intrinsic::arm_neon_vtbx2: | 
| Bob Wilson | c597fd3b | 2010-09-13 23:55:10 +0000 | [diff] [blame] | 2158 | return SelectVTBL(N, true, 2, ARM::VTBX2Pseudo); | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 2159 | case Intrinsic::arm_neon_vtbx3: | 
| Bob Wilson | c597fd3b | 2010-09-13 23:55:10 +0000 | [diff] [blame] | 2160 | return SelectVTBL(N, true, 3, ARM::VTBX3Pseudo); | 
| Bob Wilson | 5bc8a79 | 2010-07-07 00:08:54 +0000 | [diff] [blame] | 2161 | case Intrinsic::arm_neon_vtbx4: | 
| Bob Wilson | c597fd3b | 2010-09-13 23:55:10 +0000 | [diff] [blame] | 2162 | return SelectVTBL(N, true, 4, ARM::VTBX4Pseudo); | 
| Bob Wilson | 3ed511b | 2010-07-06 23:36:25 +0000 | [diff] [blame] | 2163 | } | 
|  | 2164 | break; | 
|  | 2165 | } | 
|  | 2166 |  | 
| Bob Wilson | f765e1f | 2010-05-06 16:05:26 +0000 | [diff] [blame] | 2167 | case ISD::CONCAT_VECTORS: | 
| Evan Cheng | d85631e | 2010-05-05 18:28:36 +0000 | [diff] [blame] | 2168 | return SelectConcatVector(N); | 
|  | 2169 | } | 
| Evan Cheng | d502173 | 2008-12-10 21:54:21 +0000 | [diff] [blame] | 2170 |  | 
| Dan Gohman | ea6f91f | 2010-01-05 01:24:18 +0000 | [diff] [blame] | 2171 | return SelectCode(N); | 
| Evan Cheng | 10043e2 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 2172 | } | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 2173 |  | 
| Bob Wilson | a2c462b | 2009-05-19 05:53:42 +0000 | [diff] [blame] | 2174 | bool ARMDAGToDAGISel:: | 
|  | 2175 | SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode, | 
|  | 2176 | std::vector<SDValue> &OutOps) { | 
|  | 2177 | assert(ConstraintCode == 'm' && "unexpected asm memory constraint"); | 
| Bob Wilson | 3b51560 | 2009-10-13 20:50:28 +0000 | [diff] [blame] | 2178 | // Require the address to be in a register.  That is safe for all ARM | 
|  | 2179 | // variants and it is hard to do anything much smarter without knowing | 
|  | 2180 | // how the operand is used. | 
|  | 2181 | OutOps.push_back(Op); | 
| Bob Wilson | a2c462b | 2009-05-19 05:53:42 +0000 | [diff] [blame] | 2182 | return false; | 
|  | 2183 | } | 
|  | 2184 |  | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 2185 | /// createARMISelDag - This pass converts a legalized DAG into a | 
|  | 2186 | /// ARM-specific DAG, ready for instruction scheduling. | 
|  | 2187 | /// | 
| Bob Wilson | 2dd957f | 2009-09-28 14:30:20 +0000 | [diff] [blame] | 2188 | FunctionPass *llvm::createARMISelDag(ARMBaseTargetMachine &TM, | 
|  | 2189 | CodeGenOpt::Level OptLevel) { | 
|  | 2190 | return new ARMDAGToDAGISel(TM, OptLevel); | 
| Rafael Espindola | ffdc24b | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 2191 | } |