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 @@ -3581,7 +3581,6 @@ assert(DstRegOp.isReg() && "expected register operand kind"); const MCOperand &BaseRegOp = Inst.getOperand(1); assert(BaseRegOp.isReg() && "expected register operand kind"); - const MCOperand &OffsetOp = Inst.getOperand(2); MipsTargetStreamer &TOut = getTargetStreamer(); unsigned DstReg = DstRegOp.getReg(); @@ -3603,6 +3602,26 @@ return; } + if (Inst.getNumOperands() > 3) { + const MCOperand &BaseRegOp = Inst.getOperand(2); + assert(BaseRegOp.isReg() && "expected register operand kind"); + const MCOperand &ExprOp = Inst.getOperand(3); + assert(ExprOp.isExpr() && "expected expression oprand kind"); + + unsigned BaseReg = BaseRegOp.getReg(); + const MCExpr *ExprOffset = ExprOp.getExpr(); + + MCOperand LoOperand = MCOperand::createExpr( + MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); + MCOperand HiOperand = MCOperand::createExpr( + MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext())); + TOut.emitSCWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, + LoOperand, TmpReg, IDLoc, STI); + return; + } + + const MCOperand &OffsetOp = Inst.getOperand(2); + if (OffsetOp.isImm()) { int64_t LoOffset = OffsetOp.getImm() & 0xffff; int64_t HiOffset = OffsetOp.getImm() & ~0xffff; @@ -3628,35 +3647,39 @@ return; } - assert(OffsetOp.isExpr() && "expected expression operand kind"); - if (inPicMode()) { - // FIXME: - // a) Fix lw/sw $reg, symbol($reg) instruction expanding. - // b) If expression includes offset (sym + number), do not - // encode the offset into a relocation. Take it in account - // in the last load/store instruction. - // c) Check that immediates of R_MIPS_GOT16/R_MIPS_LO16 relocations - // do not exceed 16-bit. - // d) Use R_MIPS_GOT_PAGE/R_MIPS_GOT_OFST relocations instead - // of R_MIPS_GOT_DISP in appropriate cases to reduce number - // of GOT entries. - expandLoadAddress(TmpReg, Mips::NoRegister, OffsetOp, !ABI.ArePtrs64bit(), - IDLoc, Out, STI); - TOut.emitRRI(Inst.getOpcode(), DstReg, TmpReg, 0, IDLoc, STI); - } else { - const MCExpr *ExprOffset = OffsetOp.getExpr(); - MCOperand LoOperand = MCOperand::createExpr( - MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); - MCOperand HiOperand = MCOperand::createExpr( - MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext())); - - if (IsLoad) - TOut.emitLoadWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, - LoOperand, TmpReg, IDLoc, STI); - else - TOut.emitStoreWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, - LoOperand, TmpReg, IDLoc, STI); + if (OffsetOp.isExpr()) { + if (inPicMode()) { + // FIXME: + // a) Fix lw/sw $reg, symbol($reg) instruction expanding. + // b) If expression includes offset (sym + number), do not + // encode the offset into a relocation. Take it in account + // in the last load/store instruction. + // c) Check that immediates of R_MIPS_GOT16/R_MIPS_LO16 relocations + // do not exceed 16-bit. + // d) Use R_MIPS_GOT_PAGE/R_MIPS_GOT_OFST relocations instead + // of R_MIPS_GOT_DISP in appropriate cases to reduce number + // of GOT entries. + expandLoadAddress(TmpReg, Mips::NoRegister, OffsetOp, !ABI.ArePtrs64bit(), + IDLoc, Out, STI); + TOut.emitRRI(Inst.getOpcode(), DstReg, TmpReg, 0, IDLoc, STI); + } else { + const MCExpr *ExprOffset = OffsetOp.getExpr(); + MCOperand LoOperand = MCOperand::createExpr( + MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); + MCOperand HiOperand = MCOperand::createExpr( + MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext())); + + if (IsLoad) + TOut.emitLoadWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, + LoOperand, TmpReg, IDLoc, STI); + else + TOut.emitStoreWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, + HiOperand, LoOperand, TmpReg, IDLoc, STI); + } + return; } + + llvm_unreachable("unexpected operand type"); } bool MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, Index: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -216,6 +216,19 @@ emitRRX(Opcode, Reg0, Reg1, MCOperand::createReg(Reg2), IDLoc, STI); } +void MipsTargetStreamer::emitRRRX(unsigned Opcode, unsigned Reg0, unsigned Reg1, + unsigned Reg2, MCOperand Op3, SMLoc IDLoc, + const MCSubtargetInfo *STI) { + MCInst TmpInst; + TmpInst.setOpcode(Opcode); + TmpInst.addOperand(MCOperand::createReg(Reg0)); + TmpInst.addOperand(MCOperand::createReg(Reg1)); + TmpInst.addOperand(MCOperand::createReg(Reg2)); + TmpInst.addOperand(Op3); + TmpInst.setLoc(IDLoc); + getStreamer().EmitInstruction(TmpInst, *STI); +} + void MipsTargetStreamer::emitRRI(unsigned Opcode, unsigned Reg0, unsigned Reg1, int16_t Imm, SMLoc IDLoc, const MCSubtargetInfo *STI) { @@ -328,6 +341,36 @@ emitRRX(Opcode, SrcReg, ATReg, LoOperand, IDLoc, STI); } +/// Emit a store instruction with an symbol offset. +void MipsTargetStreamer::emitSCWithSymOffset(unsigned Opcode, unsigned SrcReg, + unsigned BaseReg, + MCOperand &HiOperand, + MCOperand &LoOperand, + unsigned ATReg, SMLoc IDLoc, + const MCSubtargetInfo *STI) { + // sc $8, sym => lui $at, %hi(sym) + // sc $8, %lo(sym)($at) + + // Generate the base address in ATReg. + emitRX(Mips::LUi, ATReg, HiOperand, IDLoc, STI); + if (!isMicroMips(STI) && isMipsR6(STI)) { + // For non-micromips r6 offset for 'sc' is not in the lower 16 bits so we + // put it in 'at'. + // sc $8, sym => lui $at, %hi(sym) + // addiu $at, $at, %lo(sym) + // sc $8, 0($at) + emitRRX(Mips::ADDiu, ATReg, ATReg, LoOperand, IDLoc, STI); + MCOperand Offset = MCOperand::createImm(0); + // Emit the store with the adjusted base and offset. + emitRRRX(Opcode, SrcReg, SrcReg, ATReg, Offset, IDLoc, STI); + } else { + if (BaseReg != Mips::ZERO) + emitRRR(Mips::ADDu, ATReg, ATReg, BaseReg, IDLoc, STI); + // Emit the store with the adjusted base and offset. + emitRRRX(Opcode, SrcReg, SrcReg, ATReg, LoOperand, IDLoc, STI); + } +} + /// Emit a load instruction with an immediate offset. DstReg and TmpReg are /// permitted to be the same register iff DstReg is distinct from BaseReg and /// DstReg is a GPR. It is the callers responsibility to identify such cases @@ -388,6 +431,15 @@ emitRRX(Opcode, DstReg, TmpReg, LoOperand, IDLoc, STI); } +bool MipsTargetStreamer::isMipsR6(const MCSubtargetInfo *STI) const { + return STI->getFeatureBits()[Mips::FeatureMips32r6] || + STI->getFeatureBits()[Mips::FeatureMips64r6]; +} + +bool MipsTargetStreamer::isMicroMips(const MCSubtargetInfo *STI) const { + return STI->getFeatureBits()[Mips::FeatureMicroMips]; +} + MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS) : MipsTargetStreamer(S), OS(OS) {} Index: llvm/trunk/lib/Target/Mips/MipsTargetStreamer.h =================================================================== --- llvm/trunk/lib/Target/Mips/MipsTargetStreamer.h +++ llvm/trunk/lib/Target/Mips/MipsTargetStreamer.h @@ -130,6 +130,8 @@ SMLoc IDLoc, const MCSubtargetInfo *STI); void emitRRR(unsigned Opcode, unsigned Reg0, unsigned Reg1, unsigned Reg2, SMLoc IDLoc, const MCSubtargetInfo *STI); + void emitRRRX(unsigned Opcode, unsigned Reg0, unsigned Reg1, unsigned Reg2, + MCOperand Op3, SMLoc IDLoc, const MCSubtargetInfo *STI); void emitRRI(unsigned Opcode, unsigned Reg0, unsigned Reg1, int16_t Imm, SMLoc IDLoc, const MCSubtargetInfo *STI); void emitRRIII(unsigned Opcode, unsigned Reg0, unsigned Reg1, int16_t Imm0, @@ -158,6 +160,10 @@ unsigned BaseReg, MCOperand &HiOperand, MCOperand &LoOperand, unsigned ATReg, SMLoc IDLoc, const MCSubtargetInfo *STI); + void emitSCWithSymOffset(unsigned Opcode, unsigned SrcReg, unsigned BaseReg, + MCOperand &HiOperand, MCOperand &LoOperand, + unsigned ATReg, SMLoc IDLoc, + const MCSubtargetInfo *STI); void emitLoadWithImmOffset(unsigned Opcode, unsigned DstReg, unsigned BaseReg, int64_t Offset, unsigned TmpReg, SMLoc IDLoc, const MCSubtargetInfo *STI); @@ -185,6 +191,9 @@ return *ABI; } + bool isMipsR6(const MCSubtargetInfo *STI) const; + bool isMicroMips(const MCSubtargetInfo *STI) const; + protected: llvm::Optional ABI; MipsABIFlagsSection ABIFlagsSection; Index: llvm/trunk/test/MC/Mips/sym-sc.s =================================================================== --- llvm/trunk/test/MC/Mips/sym-sc.s +++ llvm/trunk/test/MC/Mips/sym-sc.s @@ -0,0 +1,74 @@ +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips2 %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefix=MIPS +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips32 %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefix=MIPS +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips32r2 %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefix=MIPS +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips3 %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefix=MIPS +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips64 %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefix=MIPS +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips64r2 %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefix=MIPS +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips32r6 %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefix=MIPSR6 +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips64r6 %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefix=MIPSR6 +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips32r2 -mattr=+micromips %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefixes=MICROMIPS,MICROMIPSR2 +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips32r6 -mattr=+micromips %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefixes=MICROMIPS,MICROMIPSR6 + +# MIPS: 0: e0 6c 00 00 sc $12, 0($3) +# MIPSR6: 0: 7c 6c 00 26 sc $12, 0($3) +# MICROMIPS: 0: 61 83 b0 00 sc $12, 0($3) +sc $12, 0($3) + +# MIPS: 4: e0 6c 00 04 sc $12, 4($3) +# MIPSR6: 4: 7c 6c 02 26 sc $12, 4($3) +# MICROMIPS: 4: 61 83 b0 04 sc $12, 4($3) +sc $12, 4($3) + +# MIPS: 8: 3c 01 00 00 lui $1, 0 +# MIPS: 00000008: R_MIPS_HI16 symbol +# MIPS: c: e0 2c 00 00 sc $12, 0($1) +# MIPS: 0000000c: R_MIPS_LO16 symbol + +# MIPSR6: 8: 3c 01 00 00 aui $1, $zero, 0 +# MIPSR6: 00000008: R_MIPS_HI16 symbol +# MIPSR6: c: 24 21 00 00 addiu $1, $1, 0 +# MIPSR6: 0000000c: R_MIPS_LO16 symbol +# MIPSR6: 10: 7c 2c 00 26 sc $12, 0($1) + +# MICROMIPSR2: 8: 41 a1 00 00 lui $1, 0 +# MICROMIPSR2: 00000008: R_MICROMIPS_HI16 symbol +# MICROMIPSR2: c: 61 81 b0 00 sc $12, 0($1) +# MICROMIPSR2: 0000000c: R_MICROMIPS_LO16 symbol + +# MICROMIPSR6: 8: 3c 01 00 00 lh $zero, 0($1) +# MICROMIPSR6: 00000008: R_MICROMIPS_HI16 symbol +# MICROMIPSR6: c: 61 81 b0 00 sc $12, 0($1) +# MICROMIPSR6: 0000000c: R_MICROMIPS_LO16 symbol +sc $12, symbol + +# MIPS: 10: 3c 01 00 00 lui $1, 0 +# MIPS: 00000010: R_MIPS_HI16 symbol +# MIPS: 14: e0 2c 00 08 sc $12, 8($1) +# MIPS: 00000014: R_MIPS_LO16 symbol + +# MIPSR6: 14: 3c 01 00 00 aui $1, $zero, 0 +# MIPSR6: 00000014: R_MIPS_HI16 symbol +# MIPSR6: 18: 24 21 00 08 addiu $1, $1, 8 +# MIPSR6: 00000018: R_MIPS_LO16 symbol +# MIPSR6: 1c: 7c 2c 00 26 sc $12, 0($1) + +# MICROMIPSR2: 10: 41 a1 00 00 lui $1, 0 +# MICROMIPSR2: 00000010: R_MICROMIPS_HI16 symbol +# MICROMIPSR2: 14: 61 81 b0 08 sc $12, 8($1) +# MICROMIPSR2: 00000014: R_MICROMIPS_LO16 symbol + +# MICROMIPSR6: 10: 3c 01 00 00 lh $zero, 0($1) +# MICROMIPSR6: 00000010: R_MICROMIPS_HI16 symbol +# MICROMIPSR6: 14: 61 81 b0 08 sc $12, 8($1) +# MICROMIPSR6: 00000014: R_MICROMIPS_LO16 symbol +sc $12, symbol + 8