Index: llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ llvm/trunk/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -361,6 +361,8 @@ /// This should be used in pseudo-instruction expansions which need AT. unsigned getATReg(SMLoc Loc); + bool canUseATReg(); + bool processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); @@ -2706,20 +2708,24 @@ // This is the 64-bit symbol address expansion. if (ABI.ArePtrs64bit() && isGP64bit()) { - // We always need AT for the 64-bit expansion. - // If it is not available we exit. - unsigned ATReg = getATReg(IDLoc); - if (!ATReg) - return true; + // We need AT for the 64-bit expansion in the cases where the optional + // source register is the destination register and for the superscalar + // scheduled form. + // + // If it is not available we exit if the destination is the same as the + // source register. const MipsMCExpr *HighestExpr = MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, SymExpr, getContext()); const MipsMCExpr *HigherExpr = MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, SymExpr, getContext()); - if (UseSrcReg && - getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, - SrcReg)) { + bool RdRegIsRsReg = + getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, SrcReg); + + if (canUseATReg() && UseSrcReg && RdRegIsRsReg) { + unsigned ATReg = getATReg(IDLoc); + // If $rs is the same as $rd: // (d)la $rd, sym($rd) => lui $at, %highest(sym) // daddiu $at, $at, %higher(sym) @@ -2741,29 +2747,65 @@ TOut.emitRRR(Mips::DADDu, DstReg, ATReg, SrcReg, IDLoc, STI); return false; - } + } else if (canUseATReg() && !RdRegIsRsReg) { + unsigned ATReg = getATReg(IDLoc); - // Otherwise, if the $rs is different from $rd or if $rs isn't specified: - // (d)la $rd, sym/sym($rs) => lui $rd, %highest(sym) - // lui $at, %hi(sym) - // daddiu $rd, $rd, %higher(sym) - // daddiu $at, $at, %lo(sym) - // dsll32 $rd, $rd, 0 - // daddu $rd, $rd, $at - // (daddu $rd, $rd, $rs) - TOut.emitRX(Mips::LUi, DstReg, MCOperand::createExpr(HighestExpr), IDLoc, - STI); - TOut.emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HiExpr), IDLoc, STI); - TOut.emitRRX(Mips::DADDiu, DstReg, DstReg, - MCOperand::createExpr(HigherExpr), IDLoc, STI); - TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(LoExpr), - IDLoc, STI); - TOut.emitRRI(Mips::DSLL32, DstReg, DstReg, 0, IDLoc, STI); - TOut.emitRRR(Mips::DADDu, DstReg, DstReg, ATReg, IDLoc, STI); - if (UseSrcReg) - TOut.emitRRR(Mips::DADDu, DstReg, DstReg, SrcReg, IDLoc, STI); + // If the $rs is different from $rd or if $rs isn't specified and we + // have $at available: + // (d)la $rd, sym/sym($rs) => lui $rd, %highest(sym) + // lui $at, %hi(sym) + // daddiu $rd, $rd, %higher(sym) + // daddiu $at, $at, %lo(sym) + // dsll32 $rd, $rd, 0 + // daddu $rd, $rd, $at + // (daddu $rd, $rd, $rs) + // + // Which is preferred for superscalar issue. + TOut.emitRX(Mips::LUi, DstReg, MCOperand::createExpr(HighestExpr), IDLoc, + STI); + TOut.emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HiExpr), IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, DstReg, DstReg, + MCOperand::createExpr(HigherExpr), IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(LoExpr), + IDLoc, STI); + TOut.emitRRI(Mips::DSLL32, DstReg, DstReg, 0, IDLoc, STI); + TOut.emitRRR(Mips::DADDu, DstReg, DstReg, ATReg, IDLoc, STI); + if (UseSrcReg) + TOut.emitRRR(Mips::DADDu, DstReg, DstReg, SrcReg, IDLoc, STI); - return false; + return false; + } else if (!canUseATReg() && !RdRegIsRsReg) { + // Otherwise, synthesize the address in the destination register + // serially: + // (d)la $rd, sym/sym($rs) => lui $rd, %highest(sym) + // daddiu $rd, $rd, %higher(sym) + // dsll $rd, $rd, 16 + // daddiu $rd, $rd, %hi(sym) + // dsll $rd, $rd, 16 + // daddiu $rd, $rd, %lo(sym) + TOut.emitRX(Mips::LUi, DstReg, MCOperand::createExpr(HighestExpr), IDLoc, + STI); + TOut.emitRRX(Mips::DADDiu, DstReg, DstReg, + MCOperand::createExpr(HigherExpr), IDLoc, STI); + TOut.emitRRI(Mips::DSLL, DstReg, DstReg, 16, IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, DstReg, DstReg, + MCOperand::createExpr(HiExpr), IDLoc, STI); + TOut.emitRRI(Mips::DSLL, DstReg, DstReg, 16, IDLoc, STI); + TOut.emitRRX(Mips::DADDiu, DstReg, DstReg, + MCOperand::createExpr(LoExpr), IDLoc, STI); + if (UseSrcReg) + TOut.emitRRR(Mips::DADDu, DstReg, DstReg, SrcReg, IDLoc, STI); + + return false; + } else { + // We have a case where SrcReg == DstReg and we don't have $at + // available. We can't expand this case, so error out appropriately. + assert(SrcReg == DstReg && !canUseATReg() && + "Could have expanded dla but didn't?"); + reportParseError(IDLoc, + "pseudo-instruction requires $at, which is not available"); + return true; + } } // And now, the 32-bit symbol address expansion: @@ -4650,6 +4692,10 @@ return CC; } +bool MipsAsmParser::canUseATReg() { + return AssemblerOptions.back()->getATRegIndex() != 0; +} + unsigned MipsAsmParser::getATReg(SMLoc Loc) { unsigned ATIndex = AssemblerOptions.back()->getATRegIndex(); if (ATIndex == 0) { Index: llvm/trunk/test/MC/Mips/macro-dla.s =================================================================== --- llvm/trunk/test/MC/Mips/macro-dla.s +++ llvm/trunk/test/MC/Mips/macro-dla.s @@ -702,6 +702,54 @@ # CHECK: daddiu $1, $1, %lo(extern_sym+8) # encoding: [0x64,0x21,A,A] # CHECK: # fixup A - offset: 0, value: %lo(extern_sym+8), kind: fixup_Mips_LO16 # CHECK: daddu $5, $1, $5 # encoding: [0x00,0x25,0x28,0x2d] +.set noat +dla $5, extern_sym # CHECK: lui $5, %highest(extern_sym) # encoding: [0x3c,0x05,A,A] + # CHECK: # fixup A - offset: 0, value: %highest(extern_sym), kind: fixup_Mips_HIGHEST + # CHECK: daddiu $5, $5, %higher(extern_sym) # encoding: [0x64,0xa5,A,A] + # CHECK: # fixup A - offset: 0, value: %higher(extern_sym), kind: fixup_Mips_HIGHER + # CHECK: dsll $5, $5, 16 # encoding: [0x00,0x05,0x2c,0x38] + # CHECK: daddiu $5, $5, %hi(extern_sym) # encoding: [0x64,0xa5,A,A] + # CHECK: # fixup A - offset: 0, value: %hi(extern_sym), kind: fixup_Mips_HI16 + # CHECK: dsll $5, $5, 16 # encoding: [0x00,0x05,0x2c,0x38] + # CHECK: daddiu $5, $5, %lo(extern_sym) # encoding: [0x64,0xa5,A,A] + # CHECK: # fixup A - offset: 0, value: %lo(extern_sym), kind: fixup_Mips_LO16 + +dla $5, extern_sym+8 # CHECK: lui $5, %highest(extern_sym+8) # encoding: [0x3c,0x05,A,A] + # CHECK: # fixup A - offset: 0, value: %highest(extern_sym+8), kind: fixup_Mips_HIGHEST + # CHECK: daddiu $5, $5, %higher(extern_sym+8) # encoding: [0x64,0xa5,A,A] + # CHECK: # fixup A - offset: 0, value: %higher(extern_sym+8), kind: fixup_Mips_HIGHER + # CHECK: dsll $5, $5, 16 # encoding: [0x00,0x05,0x2c,0x38] + # CHECK: daddiu $5, $5, %hi(extern_sym+8) # encoding: [0x64,0xa5,A,A] + # CHECK: # fixup A - offset: 0, value: %hi(extern_sym+8), kind: fixup_Mips_HI16 + # CHECK: dsll $5, $5, 16 # encoding: [0x00,0x05,0x2c,0x38] + # CHECK: daddiu $5, $5, %lo(extern_sym+8) # encoding: [0x64,0xa5,A,A] + # CHECK: # fixup A - offset: 0, value: %lo(extern_sym+8), kind: fixup_Mips_LO16 + +dla $5, extern_sym($6) # CHECK: lui $5, %highest(extern_sym) # encoding: [0x3c,0x05,A,A] + # CHECK: # fixup A - offset: 0, value: %highest(extern_sym), kind: fixup_Mips_HIGHEST + # CHECK: daddiu $5, $5, %higher(extern_sym) # encoding: [0x64,0xa5,A,A] + # CHECK: # fixup A - offset: 0, value: %higher(extern_sym), kind: fixup_Mips_HIGHER + # CHECK: dsll $5, $5, 16 # encoding: [0x00,0x05,0x2c,0x38] + # CHECK: daddiu $5, $5, %hi(extern_sym) # encoding: [0x64,0xa5,A,A] + # CHECK: # fixup A - offset: 0, value: %hi(extern_sym), kind: fixup_Mips_HI16 + # CHECK: dsll $5, $5, 16 # encoding: [0x00,0x05,0x2c,0x38] + # CHECK: daddiu $5, $5, %lo(extern_sym) # encoding: [0x64,0xa5,A,A] + # CHECK: # fixup A - offset: 0, value: %lo(extern_sym), kind: fixup_Mips_LO16 + # CHECK: daddu $5, $5, $6 # encoding: [0x00,0xa6,0x28,0x2d] + +dla $4, extern_sym+8($6) # CHECK: lui $4, %highest(extern_sym+8) # encoding: [0x3c,0x04,A,A] + # CHECK: # fixup A - offset: 0, value: %highest(extern_sym+8), kind: fixup_Mips_HIGHEST + # CHECK: daddiu $4, $4, %higher(extern_sym+8) # encoding: [0x64,0x84,A,A] + # CHECK: # fixup A - offset: 0, value: %higher(extern_sym+8), kind: fixup_Mips_HIGHER + # CHECK: dsll $4, $4, 16 # encoding: [0x00,0x04,0x24,0x38] + # CHECK: daddiu $4, $4, %hi(extern_sym+8) # encoding: [0x64,0x84,A,A] + # CHECK: # fixup A - offset: 0, value: %hi(extern_sym+8), kind: fixup_Mips_HI16 + # CHECK: dsll $4, $4, 16 # encoding: [0x00,0x04,0x24,0x38] + # CHECK: daddiu $4, $4, %lo(extern_sym+8) # encoding: [0x64,0x84,A,A] + # CHECK: # fixup A - offset: 0, value: %lo(extern_sym+8), kind: fixup_Mips_LO16 + # CHECK: daddu $4, $4, $6 # encoding: [0x00,0x86,0x20,0x2d] + +.set at .option pic2 #dla $5, symbol