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();
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;
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,
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) {
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
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) {}
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,
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);
return *ABI;
}
+ bool isMipsR6(const MCSubtargetInfo *STI) const;
+ bool isMicroMips(const MCSubtargetInfo *STI) const;
+
protected:
llvm::Optional<MipsABIInfo> ABI;
MipsABIFlagsSection ABIFlagsSection;
--- /dev/null
+# 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