Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -45,9 +45,7 @@ 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,94 @@ 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 { + // FIXME: Do we need to subtract 2 from the value we receive to + // account for the PC advancement. + 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; Index: test/MC/RISCV/relaxation.s =================================================================== --- /dev/null +++ test/MC/RISCV/relaxation.s @@ -0,0 +1,41 @@ +# RUN: llvm-mc -triple riscv32 -mattr=+c -filetype=obj %s -o %t1 +# RUN: llvm-objdump -d %t1 | FileCheck -check-prefix=INSTR %s +start: + c.bnez a0, NEAR +#INSTR: 0: {{.*}} c.bnez a0 + c.beqz a0, NEAR +#INSTR-NEXT: 2: {{.*}} c.beqz a0 + c.j NEAR +#INSTR-NEXT: 4: {{.*}} c.j + c.jal NEAR +#INSTR-NEXT: 6: {{.*}} c.jal + + c.bnez a0, FAR_BRANCH +#INSTR-NEXT: 8: {{.*}} bnez a0 + c.beqz a0, FAR_BRANCH +#INSTR-NEXT: c: {{.*}} beqz a0 + c.j FAR_BRANCH +#INSTR-NEXT: 10: {{.*}} c.j + c.jal FAR_BRANCH +#INSTR-NEXT: 12: {{.*}} c.jal + + c.bnez a0, FAR_JUMP +#INSTR-NEXT: 14: {{.*}} bnez a0 + c.beqz a0, FAR_JUMP +#INSTR-NEXT: 18: {{.*}} beqz a0 + c.j FAR_JUMP +#INSTR-NEXT: 1c: {{.*}} j + c.jal FAR_JUMP +#INSTR-NEXT: 20: {{.*}} jal + +.space 20 +NEAR: + nop + +.space 256 +FAR_BRANCH: + nop + +.space 2000 +FAR_JUMP: + nop