Skip to content

Commit

Permalink
[RISCV] Implement MC relaxations for compressed instructions.
Browse files Browse the repository at this point in the history
Summary:
     This patch implements relaxation for RISCV in the MC layer.
      The following relaxations are currently handled:
      1) Relax C_BEQZ to BEQ and C_BNEZ to BNEZ in RISCV.
      2) Relax and C_J $imm  to JAL x0, $imm  and CJAL to JAL ra, $imm.

Reviewers: asb, llvm-commits, efriedma

Reviewed By: asb

Subscribers: shiva0217

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

llvm-svn: 326626
  • Loading branch information
Sameer AbuAsal committed Mar 2, 2018
1 parent e403c86 commit 2646a41
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 10 deletions.
87 changes: 80 additions & 7 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
Expand Up @@ -45,9 +45,7 @@ class RISCVAsmBackend : public MCAsmBackend {

bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const override {
return false;
}
const MCAsmLayout &Layout) const override;

unsigned getNumFixupKinds() const override {
return RISCV::NumTargetFixupKinds;
Expand Down Expand Up @@ -79,17 +77,92 @@ class RISCVAsmBackend : public MCAsmBackend {
return Infos[Kind - FirstTargetFixupKind];
}

bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
bool mayNeedRelaxation(const MCInst &Inst) const override;
unsigned getRelaxedOpcode(unsigned Op) const;

void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
MCInst &Res) const override {
MCInst &Res) const override;

report_fatal_error("RISCVAsmBackend::relaxInstruction() unimplemented");
}

bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
};


bool RISCVAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup,
uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const {
int64_t Offset = int64_t(Value);
switch ((unsigned)Fixup.getKind()) {
default:
return false;
case RISCV::fixup_riscv_rvc_branch:
// For compressed branch instructions the immediate must be
// in the range [-256, 254].
return Offset > 254 || Offset < -256;
case RISCV::fixup_riscv_rvc_jump:
// For compressed jump instructions the immediate must be
// in the range [-2048, 2046].
return Offset > 2046 || Offset < -2048;
}
}

void RISCVAsmBackend::relaxInstruction(const MCInst &Inst,
const MCSubtargetInfo &STI,
MCInst &Res) const {
// TODO: replace this with call to auto generated uncompressinstr() function.
switch (Inst.getOpcode()) {
default:
llvm_unreachable("Opcode not expected!");
case RISCV::C_BEQZ:
// c.beqz $rs1, $imm -> beq $rs1, X0, $imm.
Res.setOpcode(RISCV::BEQ);
Res.addOperand(Inst.getOperand(0));
Res.addOperand(MCOperand::createReg(RISCV::X0));
Res.addOperand(Inst.getOperand(1));
break;
case RISCV::C_BNEZ:
// c.bnez $rs1, $imm -> bne $rs1, X0, $imm.
Res.setOpcode(RISCV::BNE);
Res.addOperand(Inst.getOperand(0));
Res.addOperand(MCOperand::createReg(RISCV::X0));
Res.addOperand(Inst.getOperand(1));
break;
case RISCV::C_J:
// c.j $imm -> jal X0, $imm.
Res.setOpcode(RISCV::JAL);
Res.addOperand(MCOperand::createReg(RISCV::X0));
Res.addOperand(Inst.getOperand(0));
break;
case RISCV::C_JAL:
// c.jal $imm -> jal X1, $imm.
Res.setOpcode(RISCV::JAL);
Res.addOperand(MCOperand::createReg(RISCV::X1));
Res.addOperand(Inst.getOperand(0));
break;
}
}

// Given a compressed control flow instruction this function returns
// the expanded instruction.
unsigned RISCVAsmBackend::getRelaxedOpcode(unsigned Op) const {
switch (Op) {
default:
return Op;
case RISCV::C_BEQZ:
return RISCV::BEQ;
case RISCV::C_BNEZ:
return RISCV::BNE;
case RISCV::C_J:
case RISCV::C_JAL: // fall through.
return RISCV::JAL;
}
}

bool RISCVAsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
return getRelaxedOpcode(Inst.getOpcode()) != Inst.getOpcode();
}

bool RISCVAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
bool HasStdExtC = STI.getFeatureBits()[RISCV::FeatureStdExtC];
unsigned MinNopLen = HasStdExtC ? 2 : 4;
Expand Down
9 changes: 8 additions & 1 deletion llvm/test/MC/RISCV/fixups-compressed.s
Expand Up @@ -2,17 +2,24 @@
# RUN: | FileCheck -check-prefix=CHECK-FIXUP %s
# RUN: llvm-mc -triple riscv32 -filetype=obj -mattr=+c < %s \
# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INSTR %s
# RUN: llvm-mc -filetype=obj -mattr=+c -triple=riscv32 %s \
# RUN: | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-REL

.LBB0_2:
# CHECK-FIXUP: fixup A - offset: 0, value: .LBB0_2, kind: fixup_riscv_rvc_jump
# CHECK-INSTR: c.j 0
c.j .LBB0_2
# CHECK: fixup A - offset: 0, value: func1, kind: fixup_riscv_rvc_jump
# CHECK-INSTR: c.jal 0
# CHECK-INSTR: c.jal 6
c.jal func1
# CHECK-FIXUP: fixup A - offset: 0, value: .LBB0_2, kind: fixup_riscv_rvc_branch
# CHECK-INSTR: c.beqz a3, -4
c.beqz a3, .LBB0_2
# CHECK-FIXUP: fixup A - offset: 0, value: .LBB0_2, kind: fixup_riscv_rvc_branch
# CHECK-INSTR: c.bnez a5, -6
c.bnez a5, .LBB0_2

func1:
nop

# CHECK-REL-NOT: R_RISCV
6 changes: 4 additions & 2 deletions llvm/test/MC/RISCV/relocations.s
Expand Up @@ -85,11 +85,13 @@ bgeu a0, a1, foo
# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_branch

c.jal foo
# RELOC: R_RISCV_RVC_JUMP
# A compressed jump (c.j) to an unresolved symbol will be relaxed to a (jal).
# RELOC: R_RISCV_JAL
# INSTR: c.jal foo
# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_jump

c.bnez a0, foo
# RELOC: R_RISCV_RVC_BRANCH
# A compressed branch (c.bnez) to an unresolved symbol will be relaxed to a (bnez).
# RELOC: R_RISCV_BRANCH
# INSTR: c.bnez a0, foo
# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_branch
75 changes: 75 additions & 0 deletions llvm/test/MC/RISCV/rv32-relaxation.s
@@ -0,0 +1,75 @@
# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \
# RUN: | llvm-objdump -d - | FileCheck -check-prefix=INSTR %s

FAR_JUMP_NEGATIVE:
c.nop
.space 2000

FAR_BRANCH_NEGATIVE:
c.nop
.space 256

NEAR_NEGATIVE:
c.nop

start:
c.bnez a0, NEAR
#INSTR: c.bnez a0, 72
c.bnez a0, NEAR_NEGATIVE
#INSTR: c.bnez a0, -4
c.bnez a0, FAR_BRANCH
#INSTR-NEXT: bnez a0, 326
c.bnez a0, FAR_BRANCH_NEGATIVE
#INSTR-NEXT: bnez a0, -268
c.bnez a0, FAR_JUMP
#INSTR-NEXT: bnez a0, 2320
c.bnez a0, FAR_JUMP_NEGATIVE
#INSTR-NEXT: bnez a0, -2278

c.beqz a0, NEAR
#INSTR-NEXT: c.beqz a0, 52
c.beqz a0, NEAR_NEGATIVE
#INSTR-NEXT: c.beqz a0, -24
c.beqz a0, FAR_BRANCH
#INSTR-NEXT: beqz a0, 306
c.beqz a0, FAR_BRANCH_NEGATIVE
#INSTR-NEXT: beqz a0, -288
c.beqz a0, FAR_JUMP
#INSTR-NEXT: beqz a0, 2300
c.beqz a0, FAR_JUMP_NEGATIVE
#INSTR-NEXT: beqz a0, -2298

c.j NEAR
#INSTR-NEXT: c.j 32
c.j NEAR_NEGATIVE
#INSTR-NEXT: c.j -44
c.j FAR_BRANCH
#INSTR-NEXT: c.j 286
c.j FAR_BRANCH_NEGATIVE
#INSTR-NEXT: c.j -306
c.j FAR_JUMP
#INSTR-NEXT: j 2284
c.j FAR_JUMP_NEGATIVE
#INSTR-NEXT: j -2314

c.jal NEAR
#INSTR: c.jal 16
c.jal NEAR_NEGATIVE
#INSTR: c.jal -60
c.jal FAR_BRANCH
#INSTR-NEXT: c.jal 270
c.jal FAR_BRANCH_NEGATIVE
#INSTR-NEXT: c.jal -322
c.jal FAR_JUMP
#INSTR-NEXT: jal 2268
c.jal FAR_JUMP_NEGATIVE
#INSTR-NEXT: jal -2330

NEAR:
c.nop
.space 256
FAR_BRANCH:
c.nop
.space 2000
FAR_JUMP:
c.nop
64 changes: 64 additions & 0 deletions llvm/test/MC/RISCV/rv64-relaxation.s
@@ -0,0 +1,64 @@
# RUN: llvm-mc -filetype=obj -triple riscv64 -mattr=+c < %s \
# RUN: | llvm-objdump -d - | FileCheck -check-prefix=INSTR %s

FAR_JUMP_NEGATIVE:
c.nop
.space 2000

FAR_BRANCH_NEGATIVE:
c.nop
.space 256

NEAR_NEGATIVE:
c.nop

start:
c.bnez a0, NEAR
#INSTR: c.bnez a0, 56
c.bnez a0, NEAR_NEGATIVE
#INSTR: c.bnez a0, -4
c.bnez a0, FAR_BRANCH
#INSTR-NEXT: bnez a0, 310
c.bnez a0, FAR_BRANCH_NEGATIVE
#INSTR-NEXT: bnez a0, -268
c.bnez a0, FAR_JUMP
#INSTR-NEXT: bnez a0, 2304
c.bnez a0, FAR_JUMP_NEGATIVE
#INSTR-NEXT: bnez a0, -2278

c.beqz a0, NEAR
#INSTR-NEXT: c.beqz a0, 36
c.beqz a0, NEAR_NEGATIVE
#INSTR-NEXT: c.beqz a0, -24
c.beqz a0, FAR_BRANCH
#INSTR-NEXT: beqz a0, 290
c.beqz a0, FAR_BRANCH_NEGATIVE
#INSTR-NEXT: beqz a0, -288
c.beqz a0, FAR_JUMP
#INSTR-NEXT: beqz a0, 2284
c.beqz a0, FAR_JUMP_NEGATIVE
#INSTR-NEXT: beqz a0, -2298

c.j NEAR
#INSTR-NEXT: c.j 16
c.j NEAR_NEGATIVE
#INSTR-NEXT: c.j -44
c.j FAR_BRANCH
#INSTR-NEXT: c.j 270
c.j FAR_BRANCH_NEGATIVE
#INSTR-NEXT: c.j -306
c.j FAR_JUMP
#INSTR-NEXT: j 2268
c.j FAR_JUMP_NEGATIVE
#INSTR-NEXT: j -2314

NEAR:
c.nop

.space 256
FAR_BRANCH:
c.nop

.space 2000
FAR_JUMP:
c.nop

0 comments on commit 2646a41

Please sign in to comment.