| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 1 | //===-- SystemZISelLowering.cpp - SystemZ DAG Lowering Implementation  -----==// | 
 | 2 | // | 
 | 3 | //                     The LLVM Compiler Infrastructure | 
 | 4 | // | 
 | 5 | // This file is distributed under the University of Illinois Open Source | 
 | 6 | // License. See LICENSE.TXT for details. | 
 | 7 | // | 
 | 8 | //===----------------------------------------------------------------------===// | 
 | 9 | // | 
 | 10 | // This file implements the SystemZTargetLowering class. | 
 | 11 | // | 
 | 12 | //===----------------------------------------------------------------------===// | 
 | 13 |  | 
 | 14 | #define DEBUG_TYPE "systemz-lower" | 
 | 15 |  | 
 | 16 | #include "SystemZISelLowering.h" | 
 | 17 | #include "SystemZ.h" | 
 | 18 | #include "SystemZTargetMachine.h" | 
 | 19 | #include "SystemZSubtarget.h" | 
 | 20 | #include "llvm/DerivedTypes.h" | 
 | 21 | #include "llvm/Function.h" | 
 | 22 | #include "llvm/Intrinsics.h" | 
 | 23 | #include "llvm/CallingConv.h" | 
 | 24 | #include "llvm/GlobalVariable.h" | 
 | 25 | #include "llvm/GlobalAlias.h" | 
 | 26 | #include "llvm/CodeGen/CallingConvLower.h" | 
 | 27 | #include "llvm/CodeGen/MachineFrameInfo.h" | 
 | 28 | #include "llvm/CodeGen/MachineFunction.h" | 
 | 29 | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
 | 30 | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
 | 31 | #include "llvm/CodeGen/PseudoSourceValue.h" | 
 | 32 | #include "llvm/CodeGen/SelectionDAGISel.h" | 
 | 33 | #include "llvm/CodeGen/ValueTypes.h" | 
 | 34 | #include "llvm/Support/Debug.h" | 
| Anton Korobeynikov | 2c97ae8 | 2009-07-16 14:19:02 +0000 | [diff] [blame] | 35 | #include "llvm/Target/TargetOptions.h" | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 36 | #include "llvm/ADT/VectorExtras.h" | 
 | 37 | using namespace llvm; | 
 | 38 |  | 
 | 39 | SystemZTargetLowering::SystemZTargetLowering(SystemZTargetMachine &tm) : | 
 | 40 |   TargetLowering(tm), Subtarget(*tm.getSubtargetImpl()), TM(tm) { | 
 | 41 |  | 
| Anton Korobeynikov | 656ac6f | 2009-07-16 13:51:53 +0000 | [diff] [blame] | 42 |   RegInfo = TM.getRegisterInfo(); | 
 | 43 |  | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 44 |   // Set up the register classes. | 
| Anton Korobeynikov | 8d1837d | 2009-07-16 13:56:42 +0000 | [diff] [blame] | 45 |   addRegisterClass(MVT::i32,  SystemZ::GR32RegisterClass); | 
 | 46 |   addRegisterClass(MVT::i64,  SystemZ::GR64RegisterClass); | 
| Anton Korobeynikov | 0a42d2b | 2009-07-16 14:14:33 +0000 | [diff] [blame] | 47 |   addRegisterClass(MVT::v2i32,SystemZ::GR64PRegisterClass); | 
| Anton Korobeynikov | 8d1837d | 2009-07-16 13:56:42 +0000 | [diff] [blame] | 48 |   addRegisterClass(MVT::i128, SystemZ::GR128RegisterClass); | 
| Anton Korobeynikov | 0a42d2b | 2009-07-16 14:14:33 +0000 | [diff] [blame] | 49 |   addRegisterClass(MVT::v2i64,SystemZ::GR128RegisterClass); | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 50 |  | 
| Anton Korobeynikov | 2c97ae8 | 2009-07-16 14:19:02 +0000 | [diff] [blame] | 51 |   if (!UseSoftFloat) { | 
 | 52 |     addRegisterClass(MVT::f32, SystemZ::FP32RegisterClass); | 
 | 53 |     addRegisterClass(MVT::f64, SystemZ::FP64RegisterClass); | 
 | 54 |   } | 
 | 55 |  | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 56 |   // Compute derived properties from the register classes | 
 | 57 |   computeRegisterProperties(); | 
 | 58 |  | 
| Anton Korobeynikov | 9e4816e | 2009-07-16 13:43:18 +0000 | [diff] [blame] | 59 |   // Set shifts properties | 
 | 60 |   setShiftAmountFlavor(Extend); | 
| Anton Korobeynikov | 48e8b3c | 2009-07-16 14:15:24 +0000 | [diff] [blame] | 61 |   setShiftAmountType(MVT::i64); | 
| Anton Korobeynikov | 9e4816e | 2009-07-16 13:43:18 +0000 | [diff] [blame] | 62 |  | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 63 |   // Provide all sorts of operation actions | 
| Anton Korobeynikov | bf02217 | 2009-07-16 13:53:35 +0000 | [diff] [blame] | 64 |   setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote); | 
 | 65 |   setLoadExtAction(ISD::ZEXTLOAD, MVT::i1, Promote); | 
 | 66 |   setLoadExtAction(ISD::EXTLOAD,  MVT::i1, Promote); | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 67 |  | 
| Anton Korobeynikov | 23eff5c | 2009-07-16 14:20:08 +0000 | [diff] [blame] | 68 |   setLoadExtAction(ISD::SEXTLOAD, MVT::f32, Promote); | 
 | 69 |   setLoadExtAction(ISD::ZEXTLOAD, MVT::f32, Promote); | 
 | 70 |   setLoadExtAction(ISD::EXTLOAD,  MVT::f32, Promote); | 
 | 71 |   setLoadExtAction(ISD::SEXTLOAD, MVT::f64, Promote); | 
 | 72 |   setLoadExtAction(ISD::ZEXTLOAD, MVT::f64, Promote); | 
 | 73 |   setLoadExtAction(ISD::EXTLOAD,  MVT::f64, Promote); | 
 | 74 |  | 
| Anton Korobeynikov | e0167c1 | 2009-07-16 13:35:30 +0000 | [diff] [blame] | 75 |   setStackPointerRegisterToSaveRestore(SystemZ::R15D); | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 76 |   setSchedulingPreference(SchedulingForLatency); | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 77 |  | 
 | 78 |   setOperationAction(ISD::RET,              MVT::Other, Custom); | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 79 |  | 
| Anton Korobeynikov | 983d3a1 | 2009-07-16 14:07:24 +0000 | [diff] [blame] | 80 |   setOperationAction(ISD::BR_JT,            MVT::Other, Expand); | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 81 |   setOperationAction(ISD::BRCOND,           MVT::Other, Expand); | 
 | 82 |   setOperationAction(ISD::BR_CC,            MVT::i32, Custom); | 
 | 83 |   setOperationAction(ISD::BR_CC,            MVT::i64, Custom); | 
| Anton Korobeynikov | ae53567 | 2009-07-16 14:19:35 +0000 | [diff] [blame] | 84 |   setOperationAction(ISD::BR_CC,            MVT::f32, Custom); | 
 | 85 |   setOperationAction(ISD::BR_CC,            MVT::f64, Custom); | 
 | 86 |   setOperationAction(ISD::ConstantPool,     MVT::i32, Custom); | 
 | 87 |   setOperationAction(ISD::ConstantPool,     MVT::i64, Custom); | 
| Anton Korobeynikov | bad769f | 2009-07-16 13:57:27 +0000 | [diff] [blame] | 88 |   setOperationAction(ISD::GlobalAddress,    MVT::i64, Custom); | 
| Anton Korobeynikov | c16cdc5 | 2009-07-16 14:07:50 +0000 | [diff] [blame] | 89 |   setOperationAction(ISD::JumpTable,        MVT::i64, Custom); | 
| Anton Korobeynikov | c772c44 | 2009-07-16 14:08:15 +0000 | [diff] [blame] | 90 |   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand); | 
| Anton Korobeynikov | 7d1e39b | 2009-07-16 13:52:51 +0000 | [diff] [blame] | 91 |  | 
| Anton Korobeynikov | 0a42d2b | 2009-07-16 14:14:33 +0000 | [diff] [blame] | 92 |   setOperationAction(ISD::SDIV,             MVT::i32, Expand); | 
 | 93 |   setOperationAction(ISD::UDIV,             MVT::i32, Expand); | 
 | 94 |   setOperationAction(ISD::SDIV,             MVT::i64, Expand); | 
 | 95 |   setOperationAction(ISD::UDIV,             MVT::i64, Expand); | 
 | 96 |   setOperationAction(ISD::SREM,             MVT::i32, Expand); | 
 | 97 |   setOperationAction(ISD::UREM,             MVT::i32, Expand); | 
 | 98 |   setOperationAction(ISD::SREM,             MVT::i64, Expand); | 
 | 99 |   setOperationAction(ISD::UREM,             MVT::i64, Expand); | 
 | 100 |  | 
| Anton Korobeynikov | 7d1e39b | 2009-07-16 13:52:51 +0000 | [diff] [blame] | 101 |   // FIXME: Can we lower these 2 efficiently? | 
 | 102 |   setOperationAction(ISD::SETCC,            MVT::i32, Expand); | 
 | 103 |   setOperationAction(ISD::SETCC,            MVT::i64, Expand); | 
| Anton Korobeynikov | da723d7 | 2009-07-16 14:22:15 +0000 | [diff] [blame^] | 104 |   setOperationAction(ISD::SETCC,            MVT::f32, Expand); | 
 | 105 |   setOperationAction(ISD::SETCC,            MVT::f64, Expand); | 
| Anton Korobeynikov | 7d1e39b | 2009-07-16 13:52:51 +0000 | [diff] [blame] | 106 |   setOperationAction(ISD::SELECT,           MVT::i32, Expand); | 
 | 107 |   setOperationAction(ISD::SELECT,           MVT::i64, Expand); | 
| Anton Korobeynikov | da723d7 | 2009-07-16 14:22:15 +0000 | [diff] [blame^] | 108 |   setOperationAction(ISD::SELECT,           MVT::f32, Expand); | 
 | 109 |   setOperationAction(ISD::SELECT,           MVT::f64, Expand); | 
| Anton Korobeynikov | 7d1e39b | 2009-07-16 13:52:51 +0000 | [diff] [blame] | 110 |   setOperationAction(ISD::SELECT_CC,        MVT::i32, Custom); | 
 | 111 |   setOperationAction(ISD::SELECT_CC,        MVT::i64, Custom); | 
| Anton Korobeynikov | ae53567 | 2009-07-16 14:19:35 +0000 | [diff] [blame] | 112 |   setOperationAction(ISD::SELECT_CC,        MVT::f32, Custom); | 
 | 113 |   setOperationAction(ISD::SELECT_CC,        MVT::f64, Custom); | 
| Anton Korobeynikov | dd0239b | 2009-07-16 13:53:55 +0000 | [diff] [blame] | 114 |  | 
| Anton Korobeynikov | 8d1837d | 2009-07-16 13:56:42 +0000 | [diff] [blame] | 115 |   // Funny enough: we don't have 64-bit signed versions of these stuff, but have | 
 | 116 |   // unsigned. | 
| Anton Korobeynikov | dd0239b | 2009-07-16 13:53:55 +0000 | [diff] [blame] | 117 |   setOperationAction(ISD::MULHS,            MVT::i64, Expand); | 
| Anton Korobeynikov | dd0239b | 2009-07-16 13:53:55 +0000 | [diff] [blame] | 118 |   setOperationAction(ISD::SMUL_LOHI,        MVT::i64, Expand); | 
| Anton Korobeynikov | 9b4ae57 | 2009-07-16 14:20:56 +0000 | [diff] [blame] | 119 |  | 
 | 120 |   setOperationAction(ISD::FSIN,             MVT::f32, Expand); | 
 | 121 |   setOperationAction(ISD::FSIN,             MVT::f64, Expand); | 
 | 122 |   setOperationAction(ISD::FCOS,             MVT::f32, Expand); | 
 | 123 |   setOperationAction(ISD::FCOS,             MVT::f64, Expand); | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 124 | } | 
 | 125 |  | 
 | 126 | SDValue SystemZTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { | 
 | 127 |   switch (Op.getOpcode()) { | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 128 |   case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG); | 
 | 129 |   case ISD::RET:              return LowerRET(Op, DAG); | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 130 |   case ISD::CALL:             return LowerCALL(Op, DAG); | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 131 |   case ISD::BR_CC:            return LowerBR_CC(Op, DAG); | 
| Anton Korobeynikov | 7d1e39b | 2009-07-16 13:52:51 +0000 | [diff] [blame] | 132 |   case ISD::SELECT_CC:        return LowerSELECT_CC(Op, DAG); | 
| Anton Korobeynikov | bad769f | 2009-07-16 13:57:27 +0000 | [diff] [blame] | 133 |   case ISD::GlobalAddress:    return LowerGlobalAddress(Op, DAG); | 
| Anton Korobeynikov | c16cdc5 | 2009-07-16 14:07:50 +0000 | [diff] [blame] | 134 |   case ISD::JumpTable:        return LowerJumpTable(Op, DAG); | 
| Anton Korobeynikov | ae53567 | 2009-07-16 14:19:35 +0000 | [diff] [blame] | 135 |   case ISD::ConstantPool:     return LowerConstantPool(Op, DAG); | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 136 |   default: | 
 | 137 |     assert(0 && "unimplemented operand"); | 
 | 138 |     return SDValue(); | 
 | 139 |   } | 
 | 140 | } | 
 | 141 |  | 
 | 142 | //===----------------------------------------------------------------------===// | 
 | 143 | //                      Calling Convention Implementation | 
 | 144 | //===----------------------------------------------------------------------===// | 
 | 145 |  | 
 | 146 | #include "SystemZGenCallingConv.inc" | 
 | 147 |  | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 148 | SDValue SystemZTargetLowering::LowerFORMAL_ARGUMENTS(SDValue Op, | 
 | 149 |                                                      SelectionDAG &DAG) { | 
 | 150 |   unsigned CC = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue(); | 
 | 151 |   switch (CC) { | 
 | 152 |   default: | 
 | 153 |     assert(0 && "Unsupported calling convention"); | 
 | 154 |   case CallingConv::C: | 
 | 155 |   case CallingConv::Fast: | 
 | 156 |     return LowerCCCArguments(Op, DAG); | 
 | 157 |   } | 
 | 158 | } | 
 | 159 |  | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 160 | SDValue SystemZTargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) { | 
 | 161 |   CallSDNode *TheCall = cast<CallSDNode>(Op.getNode()); | 
 | 162 |   unsigned CallingConv = TheCall->getCallingConv(); | 
 | 163 |   switch (CallingConv) { | 
 | 164 |   default: | 
 | 165 |     assert(0 && "Unsupported calling convention"); | 
 | 166 |   case CallingConv::Fast: | 
 | 167 |   case CallingConv::C: | 
 | 168 |     return LowerCCCCallTo(Op, DAG, CallingConv); | 
 | 169 |   } | 
 | 170 | } | 
 | 171 |  | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 172 | /// LowerCCCArguments - transform physical registers into virtual registers and | 
 | 173 | /// generate load operations for arguments places on the stack. | 
 | 174 | // FIXME: struct return stuff | 
 | 175 | // FIXME: varargs | 
 | 176 | SDValue SystemZTargetLowering::LowerCCCArguments(SDValue Op, | 
 | 177 |                                                  SelectionDAG &DAG) { | 
 | 178 |   MachineFunction &MF = DAG.getMachineFunction(); | 
 | 179 |   MachineFrameInfo *MFI = MF.getFrameInfo(); | 
 | 180 |   MachineRegisterInfo &RegInfo = MF.getRegInfo(); | 
 | 181 |   SDValue Root = Op.getOperand(0); | 
 | 182 |   bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue() != 0; | 
 | 183 |   unsigned CC = MF.getFunction()->getCallingConv(); | 
 | 184 |   DebugLoc dl = Op.getDebugLoc(); | 
 | 185 |  | 
 | 186 |   // Assign locations to all of the incoming arguments. | 
 | 187 |   SmallVector<CCValAssign, 16> ArgLocs; | 
 | 188 |   CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs); | 
 | 189 |   CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_SystemZ); | 
 | 190 |  | 
 | 191 |   assert(!isVarArg && "Varargs not supported yet"); | 
 | 192 |  | 
 | 193 |   SmallVector<SDValue, 16> ArgValues; | 
 | 194 |   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { | 
 | 195 |     CCValAssign &VA = ArgLocs[i]; | 
 | 196 |     if (VA.isRegLoc()) { | 
 | 197 |       // Arguments passed in registers | 
 | 198 |       MVT RegVT = VA.getLocVT(); | 
| Anton Korobeynikov | 0e31d5c | 2009-07-16 14:19:16 +0000 | [diff] [blame] | 199 |       TargetRegisterClass *RC; | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 200 |       switch (RegVT.getSimpleVT()) { | 
 | 201 |       default: | 
 | 202 |         cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: " | 
 | 203 |              << RegVT.getSimpleVT() | 
 | 204 |              << "\n"; | 
 | 205 |         abort(); | 
| Anton Korobeynikov | 0e31d5c | 2009-07-16 14:19:16 +0000 | [diff] [blame] | 206 |        case MVT::i64: | 
 | 207 |         RC = SystemZ::GR64RegisterClass; | 
 | 208 |         break; | 
 | 209 |        case MVT::f32: | 
 | 210 |         RC = SystemZ::FP32RegisterClass; | 
 | 211 |         break; | 
 | 212 |        case MVT::f64: | 
 | 213 |         RC = SystemZ::FP64RegisterClass; | 
 | 214 |         break; | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 215 |       } | 
| Anton Korobeynikov | 0e31d5c | 2009-07-16 14:19:16 +0000 | [diff] [blame] | 216 |  | 
 | 217 |       unsigned VReg = RegInfo.createVirtualRegister(RC); | 
 | 218 |       RegInfo.addLiveIn(VA.getLocReg(), VReg); | 
 | 219 |       SDValue ArgValue = DAG.getCopyFromReg(Root, dl, VReg, RegVT); | 
 | 220 |  | 
 | 221 |       // If this is an 8/16/32-bit value, it is really passed promoted to 64 | 
 | 222 |       // bits. Insert an assert[sz]ext to capture this, then truncate to the | 
 | 223 |       // right size. | 
 | 224 |       if (VA.getLocInfo() == CCValAssign::SExt) | 
 | 225 |         ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue, | 
 | 226 |                                DAG.getValueType(VA.getValVT())); | 
 | 227 |       else if (VA.getLocInfo() == CCValAssign::ZExt) | 
 | 228 |         ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue, | 
 | 229 |                                DAG.getValueType(VA.getValVT())); | 
 | 230 |  | 
 | 231 |       if (VA.getLocInfo() != CCValAssign::Full) | 
 | 232 |         ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); | 
 | 233 |  | 
 | 234 |       ArgValues.push_back(ArgValue); | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 235 |     } else { | 
 | 236 |       // Sanity check | 
 | 237 |       assert(VA.isMemLoc()); | 
| Anton Korobeynikov | 980d550 | 2009-07-16 14:08:42 +0000 | [diff] [blame] | 238 |  | 
 | 239 |       // Create the nodes corresponding to a load from this parameter slot. | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 240 |       // Create the frame index object for this incoming parameter... | 
| Anton Korobeynikov | 980d550 | 2009-07-16 14:08:42 +0000 | [diff] [blame] | 241 |       int FI = MFI->CreateFixedObject(VA.getValVT().getSizeInBits()/8, | 
 | 242 |                                       VA.getLocMemOffset()); | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 243 |  | 
 | 244 |       // Create the SelectionDAG nodes corresponding to a load | 
 | 245 |       //from this parameter | 
| Anton Korobeynikov | 980d550 | 2009-07-16 14:08:42 +0000 | [diff] [blame] | 246 |       SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); | 
 | 247 |       ArgValues.push_back(DAG.getLoad(VA.getValVT(), dl, Root, FIN, | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 248 |                                       PseudoSourceValue::getFixedStack(FI), 0)); | 
 | 249 |     } | 
 | 250 |   } | 
 | 251 |  | 
 | 252 |   ArgValues.push_back(Root); | 
 | 253 |  | 
 | 254 |   // Return the new list of results. | 
 | 255 |   return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(), | 
 | 256 |                      &ArgValues[0], ArgValues.size()).getValue(Op.getResNo()); | 
 | 257 | } | 
 | 258 |  | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 259 | /// LowerCCCCallTo - functions arguments are copied from virtual regs to | 
 | 260 | /// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. | 
 | 261 | /// TODO: sret. | 
 | 262 | SDValue SystemZTargetLowering::LowerCCCCallTo(SDValue Op, SelectionDAG &DAG, | 
 | 263 |                                               unsigned CC) { | 
 | 264 |   CallSDNode *TheCall = cast<CallSDNode>(Op.getNode()); | 
 | 265 |   SDValue Chain  = TheCall->getChain(); | 
 | 266 |   SDValue Callee = TheCall->getCallee(); | 
 | 267 |   bool isVarArg  = TheCall->isVarArg(); | 
 | 268 |   DebugLoc dl = Op.getDebugLoc(); | 
| Anton Korobeynikov | 656ac6f | 2009-07-16 13:51:53 +0000 | [diff] [blame] | 269 |   MachineFunction &MF = DAG.getMachineFunction(); | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 270 |  | 
| Anton Korobeynikov | c7b71be | 2009-07-16 13:52:10 +0000 | [diff] [blame] | 271 |   // Offset to first argument stack slot. | 
 | 272 |   const unsigned FirstArgOffset = 160; | 
 | 273 |  | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 274 |   // Analyze operands of the call, assigning locations to each operand. | 
 | 275 |   SmallVector<CCValAssign, 16> ArgLocs; | 
 | 276 |   CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs); | 
 | 277 |  | 
 | 278 |   CCInfo.AnalyzeCallOperands(TheCall, CC_SystemZ); | 
 | 279 |  | 
 | 280 |   // Get a count of how many bytes are to be pushed on the stack. | 
 | 281 |   unsigned NumBytes = CCInfo.getNextStackOffset(); | 
 | 282 |  | 
 | 283 |   Chain = DAG.getCALLSEQ_START(Chain ,DAG.getConstant(NumBytes, | 
 | 284 |                                                       getPointerTy(), true)); | 
 | 285 |  | 
 | 286 |   SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass; | 
 | 287 |   SmallVector<SDValue, 12> MemOpChains; | 
 | 288 |   SDValue StackPtr; | 
 | 289 |  | 
 | 290 |   // Walk the register/memloc assignments, inserting copies/loads. | 
 | 291 |   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { | 
 | 292 |     CCValAssign &VA = ArgLocs[i]; | 
 | 293 |  | 
 | 294 |     // Arguments start after the 5 first operands of ISD::CALL | 
 | 295 |     SDValue Arg = TheCall->getArg(i); | 
 | 296 |  | 
 | 297 |     // Promote the value if needed. | 
 | 298 |     switch (VA.getLocInfo()) { | 
 | 299 |       default: assert(0 && "Unknown loc info!"); | 
 | 300 |       case CCValAssign::Full: break; | 
 | 301 |       case CCValAssign::SExt: | 
 | 302 |         Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); | 
 | 303 |         break; | 
 | 304 |       case CCValAssign::ZExt: | 
 | 305 |         Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); | 
 | 306 |         break; | 
 | 307 |       case CCValAssign::AExt: | 
 | 308 |         Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); | 
 | 309 |         break; | 
 | 310 |     } | 
 | 311 |  | 
 | 312 |     // Arguments that can be passed on register must be kept at RegsToPass | 
 | 313 |     // vector | 
 | 314 |     if (VA.isRegLoc()) { | 
 | 315 |       RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); | 
 | 316 |     } else { | 
 | 317 |       assert(VA.isMemLoc()); | 
 | 318 |  | 
 | 319 |       if (StackPtr.getNode() == 0) | 
| Anton Korobeynikov | 656ac6f | 2009-07-16 13:51:53 +0000 | [diff] [blame] | 320 |         StackPtr = | 
 | 321 |           DAG.getCopyFromReg(Chain, dl, | 
 | 322 |                              (RegInfo->hasFP(MF) ? | 
 | 323 |                               SystemZ::R11D : SystemZ::R15D), | 
 | 324 |                              getPointerTy()); | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 325 |  | 
| Anton Korobeynikov | c7b71be | 2009-07-16 13:52:10 +0000 | [diff] [blame] | 326 |       unsigned Offset = FirstArgOffset + VA.getLocMemOffset(); | 
 | 327 |       SDValue PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(), | 
 | 328 |                                    StackPtr, | 
 | 329 |                                    DAG.getIntPtrConstant(Offset)); | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 330 |  | 
 | 331 |       MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, | 
| Anton Korobeynikov | c7b71be | 2009-07-16 13:52:10 +0000 | [diff] [blame] | 332 |                                          PseudoSourceValue::getStack(), Offset)); | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 333 |     } | 
 | 334 |   } | 
 | 335 |  | 
 | 336 |   // Transform all store nodes into one single node because all store nodes are | 
 | 337 |   // independent of each other. | 
 | 338 |   if (!MemOpChains.empty()) | 
 | 339 |     Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, | 
 | 340 |                         &MemOpChains[0], MemOpChains.size()); | 
 | 341 |  | 
 | 342 |   // Build a sequence of copy-to-reg nodes chained together with token chain and | 
 | 343 |   // flag operands which copy the outgoing args into registers.  The InFlag in | 
 | 344 |   // necessary since all emited instructions must be stuck together. | 
 | 345 |   SDValue InFlag; | 
 | 346 |   for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { | 
 | 347 |     Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, | 
 | 348 |                              RegsToPass[i].second, InFlag); | 
 | 349 |     InFlag = Chain.getValue(1); | 
 | 350 |   } | 
 | 351 |  | 
 | 352 |   // If the callee is a GlobalAddress node (quite common, every direct call is) | 
 | 353 |   // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. | 
 | 354 |   // Likewise ExternalSymbol -> TargetExternalSymbol. | 
 | 355 |   if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) | 
 | 356 |     Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy()); | 
 | 357 |   else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) | 
 | 358 |     Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy()); | 
 | 359 |  | 
 | 360 |   // Returns a chain & a flag for retval copy to use. | 
 | 361 |   SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Flag); | 
 | 362 |   SmallVector<SDValue, 8> Ops; | 
 | 363 |   Ops.push_back(Chain); | 
 | 364 |   Ops.push_back(Callee); | 
 | 365 |  | 
 | 366 |   // Add argument registers to the end of the list so that they are | 
 | 367 |   // known live into the call. | 
 | 368 |   for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) | 
 | 369 |     Ops.push_back(DAG.getRegister(RegsToPass[i].first, | 
 | 370 |                                   RegsToPass[i].second.getValueType())); | 
 | 371 |  | 
 | 372 |   if (InFlag.getNode()) | 
 | 373 |     Ops.push_back(InFlag); | 
 | 374 |  | 
 | 375 |   Chain = DAG.getNode(SystemZISD::CALL, dl, NodeTys, &Ops[0], Ops.size()); | 
 | 376 |   InFlag = Chain.getValue(1); | 
 | 377 |  | 
 | 378 |   // Create the CALLSEQ_END node. | 
 | 379 |   Chain = DAG.getCALLSEQ_END(Chain, | 
 | 380 |                              DAG.getConstant(NumBytes, getPointerTy(), true), | 
 | 381 |                              DAG.getConstant(0, getPointerTy(), true), | 
 | 382 |                              InFlag); | 
 | 383 |   InFlag = Chain.getValue(1); | 
 | 384 |  | 
 | 385 |   // Handle result values, copying them out of physregs into vregs that we | 
 | 386 |   // return. | 
 | 387 |   return SDValue(LowerCallResult(Chain, InFlag, TheCall, CC, DAG), | 
 | 388 |                  Op.getResNo()); | 
 | 389 | } | 
 | 390 |  | 
 | 391 | /// LowerCallResult - Lower the result values of an ISD::CALL into the | 
 | 392 | /// appropriate copies out of appropriate physical registers.  This assumes that | 
 | 393 | /// Chain/InFlag are the input chain/flag to use, and that TheCall is the call | 
 | 394 | /// being lowered. Returns a SDNode with the same number of values as the | 
 | 395 | /// ISD::CALL. | 
 | 396 | SDNode* | 
 | 397 | SystemZTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, | 
 | 398 |                                        CallSDNode *TheCall, | 
 | 399 |                                        unsigned CallingConv, | 
 | 400 |                                        SelectionDAG &DAG) { | 
 | 401 |   bool isVarArg = TheCall->isVarArg(); | 
 | 402 |   DebugLoc dl = TheCall->getDebugLoc(); | 
 | 403 |  | 
 | 404 |   // Assign locations to each value returned by this call. | 
 | 405 |   SmallVector<CCValAssign, 16> RVLocs; | 
 | 406 |   CCState CCInfo(CallingConv, isVarArg, getTargetMachine(), RVLocs); | 
 | 407 |  | 
 | 408 |   CCInfo.AnalyzeCallResult(TheCall, RetCC_SystemZ); | 
 | 409 |   SmallVector<SDValue, 8> ResultVals; | 
 | 410 |  | 
 | 411 |   // Copy all of the result registers out of their specified physreg. | 
 | 412 |   for (unsigned i = 0; i != RVLocs.size(); ++i) { | 
| Anton Korobeynikov | 22836d1 | 2009-07-16 13:58:24 +0000 | [diff] [blame] | 413 |     CCValAssign &VA = RVLocs[i]; | 
 | 414 |  | 
 | 415 |     Chain = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), | 
 | 416 |                                VA.getLocVT(), InFlag).getValue(1); | 
 | 417 |     SDValue RetValue = Chain.getValue(0); | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 418 |     InFlag = Chain.getValue(2); | 
| Anton Korobeynikov | 22836d1 | 2009-07-16 13:58:24 +0000 | [diff] [blame] | 419 |  | 
 | 420 |     // If this is an 8/16/32-bit value, it is really passed promoted to 64 | 
 | 421 |     // bits. Insert an assert[sz]ext to capture this, then truncate to the | 
 | 422 |     // right size. | 
 | 423 |     if (VA.getLocInfo() == CCValAssign::SExt) | 
 | 424 |       RetValue = DAG.getNode(ISD::AssertSext, dl, VA.getLocVT(), RetValue, | 
 | 425 |                              DAG.getValueType(VA.getValVT())); | 
 | 426 |     else if (VA.getLocInfo() == CCValAssign::ZExt) | 
 | 427 |       RetValue = DAG.getNode(ISD::AssertZext, dl, VA.getLocVT(), RetValue, | 
 | 428 |                              DAG.getValueType(VA.getValVT())); | 
 | 429 |  | 
 | 430 |     if (VA.getLocInfo() != CCValAssign::Full) | 
 | 431 |       RetValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), RetValue); | 
 | 432 |  | 
 | 433 |     ResultVals.push_back(RetValue); | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 434 |   } | 
 | 435 |  | 
 | 436 |   ResultVals.push_back(Chain); | 
 | 437 |  | 
 | 438 |   // Merge everything together with a MERGE_VALUES node. | 
 | 439 |   return DAG.getNode(ISD::MERGE_VALUES, dl, TheCall->getVTList(), | 
 | 440 |                      &ResultVals[0], ResultVals.size()).getNode(); | 
 | 441 | } | 
 | 442 |  | 
 | 443 |  | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 444 | SDValue SystemZTargetLowering::LowerRET(SDValue Op, SelectionDAG &DAG) { | 
 | 445 |   // CCValAssign - represent the assignment of the return value to a location | 
 | 446 |   SmallVector<CCValAssign, 16> RVLocs; | 
 | 447 |   unsigned CC   = DAG.getMachineFunction().getFunction()->getCallingConv(); | 
 | 448 |   bool isVarArg = DAG.getMachineFunction().getFunction()->isVarArg(); | 
 | 449 |   DebugLoc dl = Op.getDebugLoc(); | 
 | 450 |  | 
 | 451 |   // CCState - Info about the registers and stack slot. | 
 | 452 |   CCState CCInfo(CC, isVarArg, getTargetMachine(), RVLocs); | 
 | 453 |  | 
 | 454 |   // Analize return values of ISD::RET | 
 | 455 |   CCInfo.AnalyzeReturn(Op.getNode(), RetCC_SystemZ); | 
 | 456 |  | 
 | 457 |   // If this is the first return lowered for this function, add the regs to the | 
 | 458 |   // liveout set for the function. | 
 | 459 |   if (DAG.getMachineFunction().getRegInfo().liveout_empty()) { | 
 | 460 |     for (unsigned i = 0; i != RVLocs.size(); ++i) | 
 | 461 |       if (RVLocs[i].isRegLoc()) | 
 | 462 |         DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); | 
 | 463 |   } | 
 | 464 |  | 
 | 465 |   // The chain is always operand #0 | 
 | 466 |   SDValue Chain = Op.getOperand(0); | 
 | 467 |   SDValue Flag; | 
 | 468 |  | 
 | 469 |   // Copy the result values into the output registers. | 
 | 470 |   for (unsigned i = 0; i != RVLocs.size(); ++i) { | 
 | 471 |     CCValAssign &VA = RVLocs[i]; | 
| Anton Korobeynikov | a51752c | 2009-07-16 13:42:31 +0000 | [diff] [blame] | 472 |     SDValue ResValue = Op.getOperand(i*2+1); | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 473 |     assert(VA.isRegLoc() && "Can only return in registers!"); | 
 | 474 |  | 
| Anton Korobeynikov | a51752c | 2009-07-16 13:42:31 +0000 | [diff] [blame] | 475 |     // If this is an 8/16/32-bit value, it is really should be passed promoted | 
 | 476 |     // to 64 bits. | 
 | 477 |     if (VA.getLocInfo() == CCValAssign::SExt) | 
 | 478 |       ResValue = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), ResValue); | 
 | 479 |     else if (VA.getLocInfo() == CCValAssign::ZExt) | 
 | 480 |       ResValue = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), ResValue); | 
 | 481 |     else if (VA.getLocInfo() == CCValAssign::AExt) | 
 | 482 |       ResValue = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), ResValue); | 
 | 483 |  | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 484 |     // ISD::RET => ret chain, (regnum1,val1), ... | 
 | 485 |     // So i*2+1 index only the regnums | 
| Anton Korobeynikov | a51752c | 2009-07-16 13:42:31 +0000 | [diff] [blame] | 486 |     Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), ResValue, Flag); | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 487 |  | 
 | 488 |     // Guarantee that all emitted copies are stuck together, | 
 | 489 |     // avoiding something bad. | 
 | 490 |     Flag = Chain.getValue(1); | 
 | 491 |   } | 
 | 492 |  | 
 | 493 |   if (Flag.getNode()) | 
 | 494 |     return DAG.getNode(SystemZISD::RET_FLAG, dl, MVT::Other, Chain, Flag); | 
 | 495 |  | 
 | 496 |   // Return Void | 
 | 497 |   return DAG.getNode(SystemZISD::RET_FLAG, dl, MVT::Other, Chain); | 
 | 498 | } | 
 | 499 |  | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 500 | SDValue SystemZTargetLowering::EmitCmp(SDValue LHS, SDValue RHS, | 
 | 501 |                                        ISD::CondCode CC, SDValue &SystemZCC, | 
 | 502 |                                        SelectionDAG &DAG) { | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 503 |   // FIXME: Emit a test if RHS is zero | 
 | 504 |  | 
 | 505 |   bool isUnsigned = false; | 
 | 506 |   SystemZCC::CondCodes TCC; | 
 | 507 |   switch (CC) { | 
 | 508 |   default: assert(0 && "Invalid integer condition!"); | 
 | 509 |   case ISD::SETEQ: | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 510 |   case ISD::SETOEQ: | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 511 |     TCC = SystemZCC::E; | 
 | 512 |     break; | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 513 |   case ISD::SETUEQ: | 
 | 514 |     TCC = SystemZCC::NLH; | 
 | 515 |     break; | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 516 |   case ISD::SETNE: | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 517 |   case ISD::SETONE: | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 518 |     TCC = SystemZCC::NE; | 
 | 519 |     break; | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 520 |   case ISD::SETUNE: | 
 | 521 |     TCC = SystemZCC::LH; | 
 | 522 |     break; | 
 | 523 |   case ISD::SETO: | 
 | 524 |     TCC = SystemZCC::O; | 
 | 525 |     break; | 
 | 526 |   case ISD::SETUO: | 
 | 527 |     TCC = SystemZCC::NO; | 
 | 528 |     break; | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 529 |   case ISD::SETULE: | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 530 |     if (LHS.getValueType().isFloatingPoint()) { | 
 | 531 |       TCC = SystemZCC::NH; | 
 | 532 |       break; | 
 | 533 |     } | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 534 |     isUnsigned = true;   // FALLTHROUGH | 
 | 535 |   case ISD::SETLE: | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 536 |   case ISD::SETOLE: | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 537 |     TCC = SystemZCC::LE; | 
 | 538 |     break; | 
 | 539 |   case ISD::SETUGE: | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 540 |     if (LHS.getValueType().isFloatingPoint()) { | 
 | 541 |       TCC = SystemZCC::NL; | 
 | 542 |       break; | 
 | 543 |     } | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 544 |     isUnsigned = true;   // FALLTHROUGH | 
 | 545 |   case ISD::SETGE: | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 546 |   case ISD::SETOGE: | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 547 |     TCC = SystemZCC::HE; | 
 | 548 |     break; | 
 | 549 |   case ISD::SETUGT: | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 550 |     if (LHS.getValueType().isFloatingPoint()) { | 
 | 551 |       TCC = SystemZCC::NLE; | 
 | 552 |       break; | 
 | 553 |     } | 
 | 554 |     isUnsigned = true;  // FALLTHROUGH | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 555 |   case ISD::SETGT: | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 556 |   case ISD::SETOGT: | 
 | 557 |     TCC = SystemZCC::H; | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 558 |     break; | 
 | 559 |   case ISD::SETULT: | 
| Anton Korobeynikov | 10c086c | 2009-07-16 14:19:54 +0000 | [diff] [blame] | 560 |     if (LHS.getValueType().isFloatingPoint()) { | 
 | 561 |       TCC = SystemZCC::NHE; | 
 | 562 |       break; | 
 | 563 |     } | 
 | 564 |     isUnsigned = true;  // FALLTHROUGH | 
 | 565 |   case ISD::SETLT: | 
 | 566 |   case ISD::SETOLT: | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 567 |     TCC = SystemZCC::L; | 
 | 568 |     break; | 
 | 569 |   } | 
 | 570 |  | 
 | 571 |   SystemZCC = DAG.getConstant(TCC, MVT::i32); | 
 | 572 |  | 
 | 573 |   DebugLoc dl = LHS.getDebugLoc(); | 
 | 574 |   return DAG.getNode((isUnsigned ? SystemZISD::UCMP : SystemZISD::CMP), | 
 | 575 |                      dl, MVT::Flag, LHS, RHS); | 
 | 576 | } | 
 | 577 |  | 
 | 578 |  | 
 | 579 | SDValue SystemZTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) { | 
 | 580 |   SDValue Chain = Op.getOperand(0); | 
 | 581 |   ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); | 
 | 582 |   SDValue LHS   = Op.getOperand(2); | 
 | 583 |   SDValue RHS   = Op.getOperand(3); | 
 | 584 |   SDValue Dest  = Op.getOperand(4); | 
 | 585 |   DebugLoc dl   = Op.getDebugLoc(); | 
 | 586 |  | 
 | 587 |   SDValue SystemZCC; | 
 | 588 |   SDValue Flag = EmitCmp(LHS, RHS, CC, SystemZCC, DAG); | 
 | 589 |   return DAG.getNode(SystemZISD::BRCOND, dl, Op.getValueType(), | 
 | 590 |                      Chain, Dest, SystemZCC, Flag); | 
 | 591 | } | 
 | 592 |  | 
| Anton Korobeynikov | 7d1e39b | 2009-07-16 13:52:51 +0000 | [diff] [blame] | 593 | SDValue SystemZTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { | 
 | 594 |   SDValue LHS    = Op.getOperand(0); | 
 | 595 |   SDValue RHS    = Op.getOperand(1); | 
 | 596 |   SDValue TrueV  = Op.getOperand(2); | 
 | 597 |   SDValue FalseV = Op.getOperand(3); | 
 | 598 |   ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get(); | 
 | 599 |   DebugLoc dl   = Op.getDebugLoc(); | 
 | 600 |  | 
 | 601 |   SDValue SystemZCC; | 
 | 602 |   SDValue Flag = EmitCmp(LHS, RHS, CC, SystemZCC, DAG); | 
 | 603 |  | 
 | 604 |   SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Flag); | 
 | 605 |   SmallVector<SDValue, 4> Ops; | 
 | 606 |   Ops.push_back(TrueV); | 
 | 607 |   Ops.push_back(FalseV); | 
 | 608 |   Ops.push_back(SystemZCC); | 
 | 609 |   Ops.push_back(Flag); | 
 | 610 |  | 
 | 611 |   return DAG.getNode(SystemZISD::SELECT, dl, VTs, &Ops[0], Ops.size()); | 
 | 612 | } | 
 | 613 |  | 
| Anton Korobeynikov | bad769f | 2009-07-16 13:57:27 +0000 | [diff] [blame] | 614 | SDValue SystemZTargetLowering::LowerGlobalAddress(SDValue Op, | 
 | 615 |                                                   SelectionDAG &DAG) { | 
 | 616 |   DebugLoc dl = Op.getDebugLoc(); | 
 | 617 |   GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); | 
| Anton Korobeynikov | 6fe326c | 2009-07-16 14:16:05 +0000 | [diff] [blame] | 618 |   int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset(); | 
| Anton Korobeynikov | bad769f | 2009-07-16 13:57:27 +0000 | [diff] [blame] | 619 |  | 
| Anton Korobeynikov | 6fe326c | 2009-07-16 14:16:05 +0000 | [diff] [blame] | 620 |   bool IsPic = getTargetMachine().getRelocationModel() == Reloc::PIC_; | 
 | 621 |   bool ExtraLoadRequired = | 
 | 622 |     Subtarget.GVRequiresExtraLoad(GV, getTargetMachine(), false); | 
 | 623 |  | 
 | 624 |   SDValue Result; | 
 | 625 |   if (!IsPic && !ExtraLoadRequired) { | 
 | 626 |     Result = DAG.getTargetGlobalAddress(GV, getPointerTy(), Offset); | 
 | 627 |     Offset = 0; | 
 | 628 |   } else { | 
 | 629 |     unsigned char OpFlags = 0; | 
 | 630 |     if (ExtraLoadRequired) | 
 | 631 |       OpFlags = SystemZII::MO_GOTENT; | 
 | 632 |  | 
 | 633 |     Result = DAG.getTargetGlobalAddress(GV, getPointerTy(), 0, OpFlags); | 
 | 634 |   } | 
 | 635 |  | 
 | 636 |   Result = DAG.getNode(SystemZISD::PCRelativeWrapper, dl, | 
 | 637 |                        getPointerTy(), Result); | 
 | 638 |  | 
 | 639 |   if (ExtraLoadRequired) | 
 | 640 |     Result = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), Result, | 
 | 641 |                          PseudoSourceValue::getGOT(), 0); | 
 | 642 |  | 
 | 643 |   // If there was a non-zero offset that we didn't fold, create an explicit | 
 | 644 |   // addition for it. | 
 | 645 |   if (Offset != 0) | 
 | 646 |     Result = DAG.getNode(ISD::ADD, dl, getPointerTy(), Result, | 
 | 647 |                          DAG.getConstant(Offset, getPointerTy())); | 
 | 648 |  | 
 | 649 |   return Result; | 
| Anton Korobeynikov | bad769f | 2009-07-16 13:57:27 +0000 | [diff] [blame] | 650 | } | 
 | 651 |  | 
| Anton Korobeynikov | ae53567 | 2009-07-16 14:19:35 +0000 | [diff] [blame] | 652 | // FIXME: PIC here | 
| Anton Korobeynikov | c16cdc5 | 2009-07-16 14:07:50 +0000 | [diff] [blame] | 653 | SDValue SystemZTargetLowering::LowerJumpTable(SDValue Op, | 
 | 654 |                                               SelectionDAG &DAG) { | 
 | 655 |   DebugLoc dl = Op.getDebugLoc(); | 
 | 656 |   JumpTableSDNode *JT = cast<JumpTableSDNode>(Op); | 
 | 657 |   SDValue Result = DAG.getTargetJumpTable(JT->getIndex(), getPointerTy()); | 
 | 658 |  | 
 | 659 |   return DAG.getNode(SystemZISD::PCRelativeWrapper, dl, getPointerTy(), Result); | 
 | 660 | } | 
 | 661 |  | 
| Anton Korobeynikov | ae53567 | 2009-07-16 14:19:35 +0000 | [diff] [blame] | 662 |  | 
 | 663 | // FIXME: PIC here | 
 | 664 | // FIXME: This is just dirty hack. We need to lower cpool properly | 
 | 665 | SDValue SystemZTargetLowering::LowerConstantPool(SDValue Op, | 
 | 666 |                                                  SelectionDAG &DAG) { | 
 | 667 |   DebugLoc dl = Op.getDebugLoc(); | 
 | 668 |   ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op); | 
 | 669 |  | 
 | 670 |   SDValue Result = DAG.getTargetConstantPool(CP->getConstVal(), getPointerTy(), | 
 | 671 |                                              CP->getAlignment(), | 
 | 672 |                                              CP->getOffset()); | 
 | 673 |  | 
 | 674 |   return DAG.getNode(SystemZISD::PCRelativeWrapper, dl, getPointerTy(), Result); | 
 | 675 | } | 
 | 676 |  | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 677 | const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const { | 
 | 678 |   switch (Opcode) { | 
| Anton Korobeynikov | 87a24e3 | 2009-07-16 13:28:59 +0000 | [diff] [blame] | 679 |   case SystemZISD::RET_FLAG:           return "SystemZISD::RET_FLAG"; | 
| Anton Korobeynikov | ba249e4 | 2009-07-16 13:50:21 +0000 | [diff] [blame] | 680 |   case SystemZISD::CALL:               return "SystemZISD::CALL"; | 
| Anton Korobeynikov | 4ec3e5f | 2009-07-16 13:52:31 +0000 | [diff] [blame] | 681 |   case SystemZISD::BRCOND:             return "SystemZISD::BRCOND"; | 
 | 682 |   case SystemZISD::CMP:                return "SystemZISD::CMP"; | 
 | 683 |   case SystemZISD::UCMP:               return "SystemZISD::UCMP"; | 
| Anton Korobeynikov | 7d1e39b | 2009-07-16 13:52:51 +0000 | [diff] [blame] | 684 |   case SystemZISD::SELECT:             return "SystemZISD::SELECT"; | 
| Anton Korobeynikov | bad769f | 2009-07-16 13:57:27 +0000 | [diff] [blame] | 685 |   case SystemZISD::PCRelativeWrapper:  return "SystemZISD::PCRelativeWrapper"; | 
| Anton Korobeynikov | 4403b93 | 2009-07-16 13:27:25 +0000 | [diff] [blame] | 686 |   default: return NULL; | 
 | 687 |   } | 
 | 688 | } | 
 | 689 |  | 
| Anton Korobeynikov | 7d1e39b | 2009-07-16 13:52:51 +0000 | [diff] [blame] | 690 | //===----------------------------------------------------------------------===// | 
 | 691 | //  Other Lowering Code | 
 | 692 | //===----------------------------------------------------------------------===// | 
 | 693 |  | 
 | 694 | MachineBasicBlock* | 
 | 695 | SystemZTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, | 
 | 696 |                                                    MachineBasicBlock *BB) const { | 
 | 697 |   const SystemZInstrInfo &TII = *TM.getInstrInfo(); | 
 | 698 |   DebugLoc dl = MI->getDebugLoc(); | 
| Anton Korobeynikov | da723d7 | 2009-07-16 14:22:15 +0000 | [diff] [blame^] | 699 |   assert((MI->getOpcode() == SystemZ::Select32  || | 
 | 700 |           MI->getOpcode() == SystemZ::SelectF32 || | 
 | 701 |           MI->getOpcode() == SystemZ::Select64  || | 
 | 702 |           MI->getOpcode() == SystemZ::SelectF64) && | 
| Anton Korobeynikov | 7d1e39b | 2009-07-16 13:52:51 +0000 | [diff] [blame] | 703 |          "Unexpected instr type to insert"); | 
 | 704 |  | 
 | 705 |   // To "insert" a SELECT instruction, we actually have to insert the diamond | 
 | 706 |   // control-flow pattern.  The incoming instruction knows the destination vreg | 
 | 707 |   // to set, the condition code register to branch on, the true/false values to | 
 | 708 |   // select between, and a branch opcode to use. | 
 | 709 |   const BasicBlock *LLVM_BB = BB->getBasicBlock(); | 
 | 710 |   MachineFunction::iterator I = BB; | 
 | 711 |   ++I; | 
 | 712 |  | 
 | 713 |   //  thisMBB: | 
 | 714 |   //  ... | 
 | 715 |   //   TrueVal = ... | 
 | 716 |   //   cmpTY ccX, r1, r2 | 
 | 717 |   //   jCC copy1MBB | 
 | 718 |   //   fallthrough --> copy0MBB | 
 | 719 |   MachineBasicBlock *thisMBB = BB; | 
 | 720 |   MachineFunction *F = BB->getParent(); | 
 | 721 |   MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); | 
 | 722 |   MachineBasicBlock *copy1MBB = F->CreateMachineBasicBlock(LLVM_BB); | 
 | 723 |   SystemZCC::CondCodes CC = (SystemZCC::CondCodes)MI->getOperand(3).getImm(); | 
 | 724 |   BuildMI(BB, dl, TII.getBrCond(CC)).addMBB(copy1MBB); | 
 | 725 |   F->insert(I, copy0MBB); | 
 | 726 |   F->insert(I, copy1MBB); | 
 | 727 |   // Update machine-CFG edges by transferring all successors of the current | 
 | 728 |   // block to the new block which will contain the Phi node for the select. | 
 | 729 |   copy1MBB->transferSuccessors(BB); | 
 | 730 |   // Next, add the true and fallthrough blocks as its successors. | 
 | 731 |   BB->addSuccessor(copy0MBB); | 
 | 732 |   BB->addSuccessor(copy1MBB); | 
 | 733 |  | 
 | 734 |   //  copy0MBB: | 
 | 735 |   //   %FalseValue = ... | 
 | 736 |   //   # fallthrough to copy1MBB | 
 | 737 |   BB = copy0MBB; | 
 | 738 |  | 
 | 739 |   // Update machine-CFG edges | 
 | 740 |   BB->addSuccessor(copy1MBB); | 
 | 741 |  | 
 | 742 |   //  copy1MBB: | 
 | 743 |   //   %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] | 
 | 744 |   //  ... | 
 | 745 |   BB = copy1MBB; | 
 | 746 |   BuildMI(BB, dl, TII.get(SystemZ::PHI), | 
 | 747 |           MI->getOperand(0).getReg()) | 
 | 748 |     .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) | 
 | 749 |     .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); | 
 | 750 |  | 
 | 751 |   F->DeleteMachineInstr(MI);   // The pseudo instruction is gone now. | 
 | 752 |   return BB; | 
 | 753 | } |