1 //===-- MipsMCInstLower.cpp - Convert Mips MachineInstr to MCInst ---------===// 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 contains code to lower Mips MachineInstrs to their corresponding 11 // MCInst records. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "MipsAsmPrinter.h" 16 #include "MipsInstrInfo.h" 17 #include "MipsMCInstLower.h" 18 #include "MCTargetDesc/MipsBaseInfo.h" 19 #include "llvm/CodeGen/MachineFunction.h" 20 #include "llvm/CodeGen/MachineInstr.h" 21 #include "llvm/CodeGen/MachineOperand.h" 22 #include "llvm/MC/MCContext.h" 23 #include "llvm/MC/MCExpr.h" 24 #include "llvm/MC/MCInst.h" 25 #include "llvm/Target/Mangler.h" 26 27 using namespace llvm; 28 29 MipsMCInstLower::MipsMCInstLower(Mangler *mang, const MachineFunction &mf, 30 MipsAsmPrinter &asmprinter) 31 : Ctx(mf.getContext()), Mang(mang), AsmPrinter(asmprinter) {} 32 33 MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO, 34 MachineOperandType MOTy, 35 unsigned Offset) const { 36 MCSymbolRefExpr::VariantKind Kind; 37 const MCSymbol *Symbol; 38 39 switch(MO.getTargetFlags()) { 40 default: assert(0 && "Invalid target flag!"); 41 case MipsII::MO_NO_FLAG: Kind = MCSymbolRefExpr::VK_None; break; 42 case MipsII::MO_GPREL: Kind = MCSymbolRefExpr::VK_Mips_GPREL; break; 43 case MipsII::MO_GOT_CALL: Kind = MCSymbolRefExpr::VK_Mips_GOT_CALL; break; 44 case MipsII::MO_GOT: Kind = MCSymbolRefExpr::VK_Mips_GOT; break; 45 case MipsII::MO_ABS_HI: Kind = MCSymbolRefExpr::VK_Mips_ABS_HI; break; 46 case MipsII::MO_ABS_LO: Kind = MCSymbolRefExpr::VK_Mips_ABS_LO; break; 47 case MipsII::MO_TLSGD: Kind = MCSymbolRefExpr::VK_Mips_TLSGD; break; 48 case MipsII::MO_GOTTPREL: Kind = MCSymbolRefExpr::VK_Mips_GOTTPREL; break; 49 case MipsII::MO_TPREL_HI: Kind = MCSymbolRefExpr::VK_Mips_TPREL_HI; break; 50 case MipsII::MO_TPREL_LO: Kind = MCSymbolRefExpr::VK_Mips_TPREL_LO; break; 51 case MipsII::MO_GPOFF_HI: Kind = MCSymbolRefExpr::VK_Mips_GPOFF_HI; break; 52 case MipsII::MO_GPOFF_LO: Kind = MCSymbolRefExpr::VK_Mips_GPOFF_LO; break; 53 case MipsII::MO_GOT_DISP: Kind = MCSymbolRefExpr::VK_Mips_GOT_DISP; break; 54 case MipsII::MO_GOT_PAGE: Kind = MCSymbolRefExpr::VK_Mips_GOT_PAGE; break; 55 case MipsII::MO_GOT_OFST: Kind = MCSymbolRefExpr::VK_Mips_GOT_OFST; break; 56 } 57 58 switch (MOTy) { 59 case MachineOperand::MO_MachineBasicBlock: 60 Symbol = MO.getMBB()->getSymbol(); 61 break; 62 63 case MachineOperand::MO_GlobalAddress: 64 Symbol = Mang->getSymbol(MO.getGlobal()); 65 break; 66 67 case MachineOperand::MO_BlockAddress: 68 Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress()); 69 break; 70 71 case MachineOperand::MO_ExternalSymbol: 72 Symbol = AsmPrinter.GetExternalSymbolSymbol(MO.getSymbolName()); 73 break; 74 75 case MachineOperand::MO_JumpTableIndex: 76 Symbol = AsmPrinter.GetJTISymbol(MO.getIndex()); 77 break; 78 79 case MachineOperand::MO_ConstantPoolIndex: 80 Symbol = AsmPrinter.GetCPISymbol(MO.getIndex()); 81 if (MO.getOffset()) 82 Offset += MO.getOffset(); 83 break; 84 85 default: 86 llvm_unreachable("<unknown operand type>"); 87 } 88 89 const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Symbol, Kind, Ctx); 90 91 if (!Offset) 92 return MCOperand::CreateExpr(MCSym); 93 94 // Assume offset is never negative. 95 assert(Offset > 0); 96 97 const MCConstantExpr *OffsetExpr = MCConstantExpr::Create(Offset, Ctx); 98 const MCBinaryExpr *AddExpr = MCBinaryExpr::CreateAdd(MCSym, OffsetExpr, Ctx); 99 return MCOperand::CreateExpr(AddExpr); 100 } 101 102 // Lower ".cpload $reg" to 103 // "lui $gp, %hi(_gp_disp)" 104 // "addiu $gp, $gp, %lo(_gp_disp)" 105 // "addu $gp. $gp, $reg" 106 void MipsMCInstLower::LowerCPLOAD(const MachineInstr *MI, 107 SmallVector<MCInst, 4>& MCInsts) { 108 MCInst Lui, Addiu, Addu; 109 StringRef SymName("_gp_disp"); 110 const MCSymbol *Symbol = Ctx.GetOrCreateSymbol(SymName); 111 const MCSymbolRefExpr *MCSym; 112 113 // lui $gp, %hi(_gp_disp) 114 Lui.setOpcode(Mips::LUi); 115 Lui.addOperand(MCOperand::CreateReg(Mips::GP)); 116 MCSym = MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_Mips_ABS_HI, Ctx); 117 Lui.addOperand(MCOperand::CreateExpr(MCSym)); 118 MCInsts.push_back(Lui); 119 120 // addiu $gp, $gp, %lo(_gp_disp) 121 Addiu.setOpcode(Mips::ADDiu); 122 Addiu.addOperand(MCOperand::CreateReg(Mips::GP)); 123 Addiu.addOperand(MCOperand::CreateReg(Mips::GP)); 124 MCSym = MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_Mips_ABS_LO, Ctx); 125 Addiu.addOperand(MCOperand::CreateExpr(MCSym)); 126 MCInsts.push_back(Addiu); 127 128 // addu $gp. $gp, $reg 129 Addu.setOpcode(Mips::ADDu); 130 Addu.addOperand(MCOperand::CreateReg(Mips::GP)); 131 Addu.addOperand(MCOperand::CreateReg(Mips::GP)); 132 const MachineOperand &MO = MI->getOperand(0); 133 assert(MO.isReg() && "CPLOAD's operand must be a register."); 134 Addu.addOperand(MCOperand::CreateReg(MO.getReg())); 135 MCInsts.push_back(Addu); 136 } 137 138 // Lower ".cprestore offset" to "sw $gp, offset($sp)". 139 void MipsMCInstLower::LowerCPRESTORE(const MachineInstr *MI, MCInst &OutMI) { 140 OutMI.clear(); 141 OutMI.setOpcode(Mips::SW); 142 OutMI.addOperand(MCOperand::CreateReg(Mips::GP)); 143 OutMI.addOperand(MCOperand::CreateReg(Mips::SP)); 144 const MachineOperand &MO = MI->getOperand(0); 145 assert(MO.isImm() && "CPRESTORE's operand must be an immediate."); 146 OutMI.addOperand(MCOperand::CreateImm(MO.getImm())); 147 } 148 149 MCOperand MipsMCInstLower::LowerOperand(const MachineOperand& MO, 150 unsigned offset) const { 151 MachineOperandType MOTy = MO.getType(); 152 153 switch (MOTy) { 154 default: 155 assert(0 && "unknown operand type"); 156 break; 157 case MachineOperand::MO_Register: 158 // Ignore all implicit register operands. 159 if (MO.isImplicit()) break; 160 return MCOperand::CreateReg(MO.getReg()); 161 case MachineOperand::MO_Immediate: 162 return MCOperand::CreateImm(MO.getImm() + offset); 163 case MachineOperand::MO_MachineBasicBlock: 164 case MachineOperand::MO_GlobalAddress: 165 case MachineOperand::MO_ExternalSymbol: 166 case MachineOperand::MO_JumpTableIndex: 167 case MachineOperand::MO_ConstantPoolIndex: 168 case MachineOperand::MO_BlockAddress: 169 return LowerSymbolOperand(MO, MOTy, offset); 170 } 171 172 return MCOperand(); 173 } 174 175 void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { 176 OutMI.setOpcode(MI->getOpcode()); 177 178 for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { 179 const MachineOperand &MO = MI->getOperand(i); 180 MCOperand MCOp = LowerOperand(MO); 181 182 if (MCOp.isValid()) 183 OutMI.addOperand(MCOp); 184 } 185 } 186 187 void MipsMCInstLower::LowerUnalignedLoadStore(const MachineInstr *MI, 188 SmallVector<MCInst, 189 4>& MCInsts) { 190 unsigned Opc = MI->getOpcode(); 191 MCInst instr1, instr2, instr3, move; 192 193 bool two_instructions = false; 194 195 assert(MI->getNumOperands() == 3); 196 assert(MI->getOperand(0).isReg()); 197 assert(MI->getOperand(1).isReg()); 198 199 MCOperand target = LowerOperand(MI->getOperand(0)); 200 MCOperand base = LowerOperand(MI->getOperand(1)); 201 MCOperand atReg = MCOperand::CreateReg(Mips::AT); 202 MCOperand zeroReg = MCOperand::CreateReg(Mips::ZERO); 203 204 MachineOperand unloweredName = MI->getOperand(2); 205 MCOperand name = LowerOperand(unloweredName); 206 207 move.setOpcode(Mips::ADDu); 208 move.addOperand(target); 209 move.addOperand(atReg); 210 move.addOperand(zeroReg); 211 212 switch (Opc) { 213 case Mips::ULW: { 214 // FIXME: only works for little endian right now 215 MCOperand adj_name = LowerOperand(unloweredName, 3); 216 if (base.getReg() == (target.getReg())) { 217 instr1.setOpcode(Mips::LWL); 218 instr1.addOperand(atReg); 219 instr1.addOperand(base); 220 instr1.addOperand(adj_name); 221 instr2.setOpcode(Mips::LWR); 222 instr2.addOperand(atReg); 223 instr2.addOperand(base); 224 instr2.addOperand(name); 225 instr3 = move; 226 } else { 227 two_instructions = true; 228 instr1.setOpcode(Mips::LWL); 229 instr1.addOperand(target); 230 instr1.addOperand(base); 231 instr1.addOperand(adj_name); 232 instr2.setOpcode(Mips::LWR); 233 instr2.addOperand(target); 234 instr2.addOperand(base); 235 instr2.addOperand(name); 236 } 237 break; 238 } 239 case Mips::ULHu: { 240 // FIXME: only works for little endian right now 241 MCOperand adj_name = LowerOperand(unloweredName, 1); 242 instr1.setOpcode(Mips::LBu); 243 instr1.addOperand(atReg); 244 instr1.addOperand(base); 245 instr1.addOperand(adj_name); 246 instr2.setOpcode(Mips::LBu); 247 instr2.addOperand(target); 248 instr2.addOperand(base); 249 instr2.addOperand(name); 250 instr3.setOpcode(Mips::INS); 251 instr3.addOperand(target); 252 instr3.addOperand(atReg); 253 instr3.addOperand(MCOperand::CreateImm(0x8)); 254 instr3.addOperand(MCOperand::CreateImm(0x18)); 255 break; 256 } 257 258 case Mips::USW: { 259 // FIXME: only works for little endian right now 260 assert (base.getReg() != target.getReg()); 261 two_instructions = true; 262 MCOperand adj_name = LowerOperand(unloweredName, 3); 263 instr1.setOpcode(Mips::SWL); 264 instr1.addOperand(target); 265 instr1.addOperand(base); 266 instr1.addOperand(adj_name); 267 instr2.setOpcode(Mips::SWR); 268 instr2.addOperand(target); 269 instr2.addOperand(base); 270 instr2.addOperand(name); 271 break; 272 } 273 case Mips::USH: { 274 MCOperand adj_name = LowerOperand(unloweredName, 1); 275 instr1.setOpcode(Mips::SB); 276 instr1.addOperand(target); 277 instr1.addOperand(base); 278 instr1.addOperand(name); 279 instr2.setOpcode(Mips::SRL); 280 instr2.addOperand(atReg); 281 instr2.addOperand(target); 282 instr2.addOperand(MCOperand::CreateImm(8)); 283 instr3.setOpcode(Mips::SB); 284 instr3.addOperand(atReg); 285 instr3.addOperand(base); 286 instr3.addOperand(adj_name); 287 break; 288 } 289 default: 290 // FIXME: need to add others 291 assert(0 && "unaligned instruction not processed"); 292 } 293 294 MCInsts.push_back(instr1); 295 MCInsts.push_back(instr2); 296 if (!two_instructions) MCInsts.push_back(instr3); 297 } 298 299