Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -148,6 +148,9 @@ bool expandLoadAddressReg(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); + void expandLoadAddressSym(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions); + void expandMemInst(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions, bool isLoad, bool isImmOpnd); @@ -1103,8 +1106,8 @@ } namespace { -template -void createShiftOr(int64_t Value, unsigned RegNo, SMLoc IDLoc, +template +void createShiftOr(MCOperand Operand, unsigned RegNo, SMLoc IDLoc, SmallVectorImpl &Instructions) { MCInst tmpInst; if (PerformShift) { @@ -1119,11 +1122,18 @@ tmpInst.setOpcode(Mips::ORi); tmpInst.addOperand(MCOperand::CreateReg(RegNo)); tmpInst.addOperand(MCOperand::CreateReg(RegNo)); - tmpInst.addOperand( - MCOperand::CreateImm(((Value & (0xffffLL << Shift)) >> Shift))); + tmpInst.addOperand(Operand); tmpInst.setLoc(IDLoc); Instructions.push_back(tmpInst); } + +template +void createShiftOr(int64_t Value, unsigned RegNo, SMLoc IDLoc, + SmallVectorImpl &Instructions) { + createShiftOr( + MCOperand::CreateImm(((Value & (0xffffLL << Shift)) >> Shift)), RegNo, + IDLoc, Instructions); +} } bool MipsAsmParser::expandLoadImm(MCInst &Inst, SMLoc IDLoc, @@ -1228,7 +1238,12 @@ SmallVectorImpl &Instructions) { MCInst tmpInst; const MCOperand &ImmOp = Inst.getOperand(2); - assert(ImmOp.isImm() && "expected immediate operand kind"); + assert((ImmOp.isImm() || ImmOp.isExpr()) && + "expected immediate operand kind"); + if (!ImmOp.isImm()) { + expandLoadAddressSym(Inst, IDLoc, Instructions); + return false; + } const MCOperand &SrcRegOp = Inst.getOperand(1); assert(SrcRegOp.isReg() && "expected register operand kind"); const MCOperand &DstRegOp = Inst.getOperand(0); @@ -1272,7 +1287,12 @@ SmallVectorImpl &Instructions) { MCInst tmpInst; const MCOperand &ImmOp = Inst.getOperand(1); - assert(ImmOp.isImm() && "expected immediate operand kind"); + assert((ImmOp.isImm() || ImmOp.isExpr()) && + "expected immediate operand kind"); + if (!ImmOp.isImm()) { + expandLoadAddressSym(Inst, IDLoc, Instructions); + return false; + } const MCOperand &RegOp = Inst.getOperand(0); assert(RegOp.isReg() && "expected register operand kind"); int ImmValue = ImmOp.getImm(); @@ -1302,6 +1322,71 @@ return false; } +void +MipsAsmParser::expandLoadAddressSym(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions) { + // FIXME: If we do have a valid at register to use, we should generate a + // slightly shorter sequence here. + MCInst tmpInst; + int ExprOperandNo = 1; + // Sometimes the assembly parser will get the immediate expression as + // a $zero + an immediate. + if (Inst.getNumOperands() == 3) { + assert(Inst.getOperand(1).getReg() == + (isGP64bit() ? Mips::ZERO_64 : Mips::ZERO)); + ExprOperandNo = 2; + } + const MCOperand &SymOp = Inst.getOperand(ExprOperandNo); + assert(SymOp.isExpr() && "expected symbol operand kind"); + const MCOperand &RegOp = Inst.getOperand(0); + unsigned RegNo = RegOp.getReg(); + const MCSymbolRefExpr *Symbol = cast(SymOp.getExpr()); + const MCSymbolRefExpr *HiExpr = + MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::VK_Mips_ABS_HI, getContext()); + const MCSymbolRefExpr *LoExpr = + MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::VK_Mips_ABS_LO, getContext()); + if (isGP64bit()) { + // If it's a 64-bit architecture, expand to: + // la d,sym => lui d,highest(sym) + // ori d,d,higher(sym) + // dsll d,d,16 + // ori d,d,hi16(sym) + // dsll d,d,16 + // ori d,d,lo16(sym) + const MCSymbolRefExpr *HighestExpr = + MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::VK_Mips_HIGHEST, getContext()); + const MCSymbolRefExpr *HigherExpr = + MCSymbolRefExpr::Create(Symbol->getSymbol().getName(), + MCSymbolRefExpr::VK_Mips_HIGHER, getContext()); + + tmpInst.setOpcode(Mips::LUi); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateExpr(HighestExpr)); + Instructions.push_back(tmpInst); + + createShiftOr(MCOperand::CreateExpr(HigherExpr), RegNo, SMLoc(), + Instructions); + createShiftOr(MCOperand::CreateExpr(HiExpr), RegNo, SMLoc(), + Instructions); + createShiftOr(MCOperand::CreateExpr(LoExpr), RegNo, SMLoc(), + Instructions); + } else { + // Otherwise, expand to: + // la d,sym => lui d,hi16(sym) + // ori d,d,lo16(sym) + tmpInst.setOpcode(Mips::LUi); + tmpInst.addOperand(MCOperand::CreateReg(RegNo)); + tmpInst.addOperand(MCOperand::CreateExpr(HiExpr)); + Instructions.push_back(tmpInst); + + createShiftOr(MCOperand::CreateExpr(LoExpr), RegNo, SMLoc(), + Instructions); + } +} + void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions, bool isLoad, bool isImmOpnd) { Index: test/MC/Mips/mips-expansions.s =================================================================== --- test/MC/Mips/mips-expansions.s +++ test/MC/Mips/mips-expansions.s @@ -17,6 +17,22 @@ # CHECK: lui $7, 1 # encoding: [0x01,0x00,0x07,0x3c] # CHECK: ori $7, $7, 2 # encoding: [0x02,0x00,0xe7,0x34] # CHECK: addu $7, $7, $8 # encoding: [0x21,0x38,0xe8,0x00] +# CHECK: lui $8, %hi(symbol) # encoding: [A,A,0x08,0x3c] + # fixup A - offset: 0, value: symbol@ABS_HI, kind: fixup_Mips_HI16 +# CHECK: ori $8, $8, %lo(symbol) # encoding: [A,A,0x08,0x35] + # fixup A - offset: 0, value: symbol@ABS_LO, kind: fixup_Mips_LO16 +# CHECK: .set mips64 +# CHECK: lui $8, %highest(symbol) # encoding: [A,A,0x08,0x3c] + # fixup A - offset: 0, value: symbol@HIGHEST, kind: fixup_Mips_HIGHEST +# CHECK: ori $8, $8, %higher(symbol) # encoding: [A,A,0x08,0x35] + # fixup A - offset: 0, value: symbol@HIGHER, kind: fixup_Mips_HIGHER +# CHECK: dsll $8, $8, 16 # encoding: [0x38,0x44,0x08,0x00] +# CHECK: ori $8, $8, %hi(symbol) # encoding: [A,A,0x08,0x35] + # fixup A - offset: 0, value: symbol@ABS_HI, kind: fixup_Mips_HI16 +# CHECK: dsll $8, $8, 16 # encoding: [0x38,0x44,0x08,0x00] +# CHECK: ori $8, $8, %lo(symbol) # encoding: [A,A,0x08,0x35] + # fixup A - offset: 0, value: symbol@ABS_LO, kind: fixup_Mips_LO16 +# CHECK: .set mips32r2 # CHECK: lui $10, %hi(symbol) # encoding: [A,A,0x0a,0x3c] # CHECK: # fixup A - offset: 0, value: symbol@ABS_HI, kind: fixup_Mips_HI16 # CHECK: addu $10, $10, $4 # encoding: [0x21,0x50,0x44,0x01] @@ -48,6 +64,10 @@ la $7,65538 la $a0, 20($a1) la $7,65538($8) + la $t0, symbol + .set mips64 + la $t0, symbol + .set mips32r2 .set noat lw $t2, symbol($a0)