Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -3625,8 +3625,8 @@ TOut.emitRRR(isGP64bit() ? Mips::DADDu : Mips::ADDu, TmpReg, TmpReg, BaseReg, IDLoc, STI); TOut.emitRRI(Inst.getOpcode(), DstReg, TmpReg, LoOffset, IDLoc, STI); - } else { - assert(OffsetOp.isExpr() && "expected expression operand kind"); + } else if (OffsetOp.isExpr()) { + const MCExpr *ExprOffset = OffsetOp.getExpr(); MCOperand LoOperand = MCOperand::createExpr( MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); @@ -3639,6 +3639,19 @@ else TOut.emitStoreWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, LoOperand, TmpReg, IDLoc, STI); + } else if (Inst.getNumOperands() > 3) { + const MCOperand &BaseRegOp = Inst.getOperand(2); + const MCOperand &ExprOp = Inst.getOperand(3); + unsigned BaseReg = BaseRegOp.getReg(); + + assert(ExprOp.isExpr() && "expected expression oprand kind"); + 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); } } Index: lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ 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,20 @@ 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, 0 + // sc $8, 0($at) + + // Generate the base address in ATReg. + emitRX(Mips::LUi, ATReg, HiOperand, 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 Index: lib/Target/Mips/MipsTargetStreamer.h =================================================================== --- lib/Target/Mips/MipsTargetStreamer.h +++ 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); Index: test/MC/Mips/sym-sc.s =================================================================== --- /dev/null +++ test/MC/Mips/sym-sc.s @@ -0,0 +1,51 @@ +# 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-prefix=MICROMIPSR2 +# RUN: llvm-mc -filetype=obj -triple mips -mcpu=mips32r6 -mattr=+micromips %s -o - \ +# RUN: | llvm-objdump -d -r - | FileCheck %s --check-prefix=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 some_random_symbol_name +# MIPS: c: e0 2c 00 00 sc $12, 0($1) +# MIPS: 0000000c: R_MIPS_LO16 some_random_symbol_name + +# MIPSR6: 8: 3c 01 00 00 aui $1, $zero, 0 +# MIPSR6: 00000008: R_MIPS_HI16 some_random_symbol_name +# MIPSR6: c: 7c 2c 00 26 sc $12, 0($1) +# MIPSR6: 0000000c: R_MIPS_LO16 some_random_symbol_name + +# MICROMIPSR2: 8: 41 a1 00 00 lui $1, 0 +# MICROMIPSR2: 00000008: R_MICROMIPS_HI16 some_random_symbol_name +# MICROMIPSR2: c: 61 81 b0 00 sc $12, 0($1) +# MICROMIPSR2: 0000000c: R_MICROMIPS_LO16 some_random_symbol_name + +# MICROMIPSR6: 8: 3c 01 00 00 lh $zero, 0($1) +# MICROMIPSR6: 00000008: R_MICROMIPS_HI16 some_random_symbol_name +# MICROMIPSR6: c: 61 81 b0 00 sc $12, 0($1) +# MICROMIPSR6: 0000000c: R_MICROMIPS_LO16 some_random_symbol_name +sc $12, some_random_symbol_name