forked from OSchip/llvm-project
[RISCV] Implement MC relaxations for compressed instructions.
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
This commit is contained in:
parent
e403c862cc
commit
2646a41e54
|
@ -45,9 +45,7 @@ public:
|
|||
|
||||
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;
|
||||
|
@ -79,17 +77,92 @@ public:
|
|||
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;
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
# 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
|
||||
|
@ -16,3 +18,8 @@ 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue