Skip to content

Commit

Permalink
[Mips] Instruction sc now accepts symbol as an argument
Browse files Browse the repository at this point in the history
Function MipsAsmParser::expandMemInst() did not properly handle
instruction `sc` with a symbol as an argument because first argument
would be counted twice. We add additional checks and handle this case
separately.

Patch by Mirko Brkusanin.

Differential Revision: https://reviews.llvm.org/D64252

llvm-svn: 368160
  • Loading branch information
atanasyan committed Aug 7, 2019
1 parent 8280730 commit 9f2e076
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 29 deletions.
81 changes: 52 additions & 29 deletions llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
Expand Up @@ -3581,7 +3581,6 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
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();
Expand All @@ -3603,6 +3602,26 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
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;
Expand All @@ -3628,35 +3647,39 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out,
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,
Expand Down
52 changes: 52 additions & 0 deletions llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
Expand Up @@ -216,6 +216,19 @@ void MipsTargetStreamer::emitRRR(unsigned Opcode, unsigned Reg0, unsigned Reg1,
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) {
Expand Down Expand Up @@ -328,6 +341,36 @@ void MipsTargetStreamer::emitStoreWithSymOffset(
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
Expand Down Expand Up @@ -388,6 +431,15 @@ void MipsTargetStreamer::emitLoadWithSymOffset(unsigned Opcode, unsigned DstReg,
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) {}
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/Target/Mips/MipsTargetStreamer.h
Expand Up @@ -130,6 +130,8 @@ class MipsTargetStreamer : public MCTargetStreamer {
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,
Expand Down Expand Up @@ -158,6 +160,10 @@ class MipsTargetStreamer : public MCTargetStreamer {
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);
Expand Down Expand Up @@ -185,6 +191,9 @@ class MipsTargetStreamer : public MCTargetStreamer {
return *ABI;
}

bool isMipsR6(const MCSubtargetInfo *STI) const;
bool isMicroMips(const MCSubtargetInfo *STI) const;

protected:
llvm::Optional<MipsABIInfo> ABI;
MipsABIFlagsSection ABIFlagsSection;
Expand Down
74 changes: 74 additions & 0 deletions llvm/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

0 comments on commit 9f2e076

Please sign in to comment.