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_GOT16: Kind = MCSymbolRefExpr::VK_Mips_GOT16; break; 45 case MipsII::MO_GOT: Kind = MCSymbolRefExpr::VK_Mips_GOT; break; 46 case MipsII::MO_ABS_HI: Kind = MCSymbolRefExpr::VK_Mips_ABS_HI; break; 47 case MipsII::MO_ABS_LO: Kind = MCSymbolRefExpr::VK_Mips_ABS_LO; break; 48 case MipsII::MO_TLSGD: Kind = MCSymbolRefExpr::VK_Mips_TLSGD; break; 49 case MipsII::MO_TLSLDM: Kind = MCSymbolRefExpr::VK_Mips_TLSLDM; break; 50 case MipsII::MO_DTPREL_HI: Kind = MCSymbolRefExpr::VK_Mips_DTPREL_HI; break; 51 case MipsII::MO_DTPREL_LO: Kind = MCSymbolRefExpr::VK_Mips_DTPREL_LO; break; 52 case MipsII::MO_GOTTPREL: Kind = MCSymbolRefExpr::VK_Mips_GOTTPREL; break; 53 case MipsII::MO_TPREL_HI: Kind = MCSymbolRefExpr::VK_Mips_TPREL_HI; break; 54 case MipsII::MO_TPREL_LO: Kind = MCSymbolRefExpr::VK_Mips_TPREL_LO; break; 55 case MipsII::MO_GPOFF_HI: Kind = MCSymbolRefExpr::VK_Mips_GPOFF_HI; break; 56 case MipsII::MO_GPOFF_LO: Kind = MCSymbolRefExpr::VK_Mips_GPOFF_LO; break; 57 case MipsII::MO_GOT_DISP: Kind = MCSymbolRefExpr::VK_Mips_GOT_DISP; break; 58 case MipsII::MO_GOT_PAGE: Kind = MCSymbolRefExpr::VK_Mips_GOT_PAGE; break; 59 case MipsII::MO_GOT_OFST: Kind = MCSymbolRefExpr::VK_Mips_GOT_OFST; break; 60 } 61 62 switch (MOTy) { 63 case MachineOperand::MO_MachineBasicBlock: 64 Symbol = MO.getMBB()->getSymbol(); 65 break; 66 67 case MachineOperand::MO_GlobalAddress: 68 Symbol = Mang->getSymbol(MO.getGlobal()); 69 break; 70 71 case MachineOperand::MO_BlockAddress: 72 Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress()); 73 break; 74 75 case MachineOperand::MO_ExternalSymbol: 76 Symbol = AsmPrinter.GetExternalSymbolSymbol(MO.getSymbolName()); 77 break; 78 79 case MachineOperand::MO_JumpTableIndex: 80 Symbol = AsmPrinter.GetJTISymbol(MO.getIndex()); 81 break; 82 83 case MachineOperand::MO_ConstantPoolIndex: 84 Symbol = AsmPrinter.GetCPISymbol(MO.getIndex()); 85 if (MO.getOffset()) 86 Offset += MO.getOffset(); 87 break; 88 89 default: 90 llvm_unreachable("<unknown operand type>"); 91 } 92 93 const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Symbol, Kind, Ctx); 94 95 if (!Offset) 96 return MCOperand::CreateExpr(MCSym); 97 98 // Assume offset is never negative. 99 assert(Offset > 0); 100 101 const MCConstantExpr *OffsetExpr = MCConstantExpr::Create(Offset, Ctx); 102 const MCBinaryExpr *AddExpr = MCBinaryExpr::CreateAdd(MCSym, OffsetExpr, Ctx); 103 return MCOperand::CreateExpr(AddExpr); 104 } 105 106 // Lower ".cpload $reg" to 107 // "lui $gp, %hi(_gp_disp)" 108 // "addiu $gp, $gp, %lo(_gp_disp)" 109 // "addu $gp. $gp, $reg" 110 void MipsMCInstLower::LowerCPLOAD(const MachineInstr *MI, 111 SmallVector<MCInst, 4>& MCInsts) { 112 MCInst Lui, Addiu, Addu; 113 StringRef SymName("_gp_disp"); 114 const MCSymbol *Symbol = Ctx.GetOrCreateSymbol(SymName); 115 const MCSymbolRefExpr *MCSym; 116 117 // lui $gp, %hi(_gp_disp) 118 Lui.setOpcode(Mips::LUi); 119 Lui.addOperand(MCOperand::CreateReg(Mips::GP)); 120 MCSym = MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_Mips_ABS_HI, Ctx); 121 Lui.addOperand(MCOperand::CreateExpr(MCSym)); 122 MCInsts.push_back(Lui); 123 124 // addiu $gp, $gp, %lo(_gp_disp) 125 Addiu.setOpcode(Mips::ADDiu); 126 Addiu.addOperand(MCOperand::CreateReg(Mips::GP)); 127 Addiu.addOperand(MCOperand::CreateReg(Mips::GP)); 128 MCSym = MCSymbolRefExpr::Create(Symbol, MCSymbolRefExpr::VK_Mips_ABS_LO, Ctx); 129 Addiu.addOperand(MCOperand::CreateExpr(MCSym)); 130 MCInsts.push_back(Addiu); 131 132 // addu $gp. $gp, $reg 133 Addu.setOpcode(Mips::ADDu); 134 Addu.addOperand(MCOperand::CreateReg(Mips::GP)); 135 Addu.addOperand(MCOperand::CreateReg(Mips::GP)); 136 const MachineOperand &MO = MI->getOperand(0); 137 assert(MO.isReg() && "CPLOAD's operand must be a register."); 138 Addu.addOperand(MCOperand::CreateReg(MO.getReg())); 139 MCInsts.push_back(Addu); 140 } 141 142 // Lower ".cprestore offset" to "sw $gp, offset($sp)". 143 void MipsMCInstLower::LowerCPRESTORE(const MachineInstr *MI, 144 SmallVector<MCInst, 4>& MCInsts) { 145 const MachineOperand &MO = MI->getOperand(0); 146 assert(MO.isImm() && "CPRESTORE's operand must be an immediate."); 147 unsigned Offset = MO.getImm(), Reg = Mips::SP; 148 MCInst Sw; 149 150 if (Offset >= 0x8000) { 151 unsigned Hi = (Offset >> 16) + ((Offset & 0x8000) != 0); 152 Offset &= 0xffff; 153 Reg = Mips::AT; 154 155 // lui at,hi 156 // addu at,at,sp 157 MCInsts.resize(2); 158 MCInsts[0].setOpcode(Mips::LUi); 159 MCInsts[0].addOperand(MCOperand::CreateReg(Mips::AT)); 160 MCInsts[0].addOperand(MCOperand::CreateImm(Hi)); 161 MCInsts[1].setOpcode(Mips::ADDu); 162 MCInsts[1].addOperand(MCOperand::CreateReg(Mips::AT)); 163 MCInsts[1].addOperand(MCOperand::CreateReg(Mips::AT)); 164 MCInsts[1].addOperand(MCOperand::CreateReg(Mips::SP)); 165 } 166 167 Sw.setOpcode(Mips::SW); 168 Sw.addOperand(MCOperand::CreateReg(Mips::GP)); 169 Sw.addOperand(MCOperand::CreateReg(Reg)); 170 Sw.addOperand(MCOperand::CreateImm(Offset)); 171 MCInsts.push_back(Sw); 172 } 173 174 MCOperand MipsMCInstLower::LowerOperand(const MachineOperand& MO, 175 unsigned offset) const { 176 MachineOperandType MOTy = MO.getType(); 177 178 switch (MOTy) { 179 default: 180 assert(0 && "unknown operand type"); 181 break; 182 case MachineOperand::MO_Register: 183 // Ignore all implicit register operands. 184 if (MO.isImplicit()) break; 185 return MCOperand::CreateReg(MO.getReg()); 186 case MachineOperand::MO_Immediate: 187 return MCOperand::CreateImm(MO.getImm() + offset); 188 case MachineOperand::MO_MachineBasicBlock: 189 case MachineOperand::MO_GlobalAddress: 190 case MachineOperand::MO_ExternalSymbol: 191 case MachineOperand::MO_JumpTableIndex: 192 case MachineOperand::MO_ConstantPoolIndex: 193 case MachineOperand::MO_BlockAddress: 194 return LowerSymbolOperand(MO, MOTy, offset); 195 case MachineOperand::MO_RegisterMask: 196 break; 197 } 198 199 return MCOperand(); 200 } 201 202 void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { 203 OutMI.setOpcode(MI->getOpcode()); 204 205 for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { 206 const MachineOperand &MO = MI->getOperand(i); 207 MCOperand MCOp = LowerOperand(MO); 208 209 if (MCOp.isValid()) 210 OutMI.addOperand(MCOp); 211 } 212 } 213 214 void MipsMCInstLower::LowerUnalignedLoadStore(const MachineInstr *MI, 215 SmallVector<MCInst, 216 4>& MCInsts) { 217 unsigned Opc = MI->getOpcode(); 218 MCInst Instr1, Instr2, Instr3, Move; 219 220 bool TwoInstructions = false; 221 222 assert(MI->getNumOperands() == 3); 223 assert(MI->getOperand(0).isReg()); 224 assert(MI->getOperand(1).isReg()); 225 226 MCOperand Target = LowerOperand(MI->getOperand(0)); 227 MCOperand Base = LowerOperand(MI->getOperand(1)); 228 MCOperand ATReg = MCOperand::CreateReg(Mips::AT); 229 MCOperand ZeroReg = MCOperand::CreateReg(Mips::ZERO); 230 231 MachineOperand UnLoweredName = MI->getOperand(2); 232 MCOperand Name = LowerOperand(UnLoweredName); 233 234 Move.setOpcode(Mips::ADDu); 235 Move.addOperand(Target); 236 Move.addOperand(ATReg); 237 Move.addOperand(ZeroReg); 238 239 switch (Opc) { 240 case Mips::ULW: { 241 // FIXME: only works for little endian right now 242 MCOperand AdjName = LowerOperand(UnLoweredName, 3); 243 if (Base.getReg() == (Target.getReg())) { 244 Instr1.setOpcode(Mips::LWL); 245 Instr1.addOperand(ATReg); 246 Instr1.addOperand(Base); 247 Instr1.addOperand(AdjName); 248 Instr2.setOpcode(Mips::LWR); 249 Instr2.addOperand(ATReg); 250 Instr2.addOperand(Base); 251 Instr2.addOperand(Name); 252 Instr3 = Move; 253 } else { 254 TwoInstructions = true; 255 Instr1.setOpcode(Mips::LWL); 256 Instr1.addOperand(Target); 257 Instr1.addOperand(Base); 258 Instr1.addOperand(AdjName); 259 Instr2.setOpcode(Mips::LWR); 260 Instr2.addOperand(Target); 261 Instr2.addOperand(Base); 262 Instr2.addOperand(Name); 263 } 264 break; 265 } 266 case Mips::ULHu: { 267 // FIXME: only works for little endian right now 268 MCOperand AdjName = LowerOperand(UnLoweredName, 1); 269 Instr1.setOpcode(Mips::LBu); 270 Instr1.addOperand(ATReg); 271 Instr1.addOperand(Base); 272 Instr1.addOperand(AdjName); 273 Instr2.setOpcode(Mips::LBu); 274 Instr2.addOperand(Target); 275 Instr2.addOperand(Base); 276 Instr2.addOperand(Name); 277 Instr3.setOpcode(Mips::INS); 278 Instr3.addOperand(Target); 279 Instr3.addOperand(ATReg); 280 Instr3.addOperand(MCOperand::CreateImm(0x8)); 281 Instr3.addOperand(MCOperand::CreateImm(0x18)); 282 break; 283 } 284 285 case Mips::USW: { 286 // FIXME: only works for little endian right now 287 assert (Base.getReg() != Target.getReg()); 288 TwoInstructions = true; 289 MCOperand AdjName = LowerOperand(UnLoweredName, 3); 290 Instr1.setOpcode(Mips::SWL); 291 Instr1.addOperand(Target); 292 Instr1.addOperand(Base); 293 Instr1.addOperand(AdjName); 294 Instr2.setOpcode(Mips::SWR); 295 Instr2.addOperand(Target); 296 Instr2.addOperand(Base); 297 Instr2.addOperand(Name); 298 break; 299 } 300 case Mips::USH: { 301 MCOperand AdjName = LowerOperand(UnLoweredName, 1); 302 Instr1.setOpcode(Mips::SB); 303 Instr1.addOperand(Target); 304 Instr1.addOperand(Base); 305 Instr1.addOperand(Name); 306 Instr2.setOpcode(Mips::SRL); 307 Instr2.addOperand(ATReg); 308 Instr2.addOperand(Target); 309 Instr2.addOperand(MCOperand::CreateImm(8)); 310 Instr3.setOpcode(Mips::SB); 311 Instr3.addOperand(ATReg); 312 Instr3.addOperand(Base); 313 Instr3.addOperand(AdjName); 314 break; 315 } 316 default: 317 // FIXME: need to add others 318 assert(0 && "unaligned instruction not processed"); 319 } 320 321 MCInsts.push_back(Instr1); 322 MCInsts.push_back(Instr2); 323 if (!TwoInstructions) MCInsts.push_back(Instr3); 324 } 325 326