Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -234,6 +234,10 @@ return IsConstantImm && isUInt<12>(Imm) && VK == RISCVMCExpr::VK_RISCV_None; } + bool isSImm9Lsb0() const { return isBareSimmNLsb0<9>(); } + + bool isSImm12Lsb0() const { return isBareSimmNLsb0<12>(); } + bool isSImm13Lsb0() const { return isBareSimmNLsb0<13>(); } bool isUImm20() const { @@ -411,6 +415,14 @@ (1 << 11) - 1); case Match_InvalidUImm12: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 12) - 1); + case Match_InvalidSImm9Lsb0: + return generateImmOutOfRangeError( + Operands, ErrorInfo, -(1 << 8), (1 << 8) - 2, + "immediate must be a multiple of 2 bytes in the range"); + case Match_InvalidSImm12Lsb0: + return generateImmOutOfRangeError( + Operands, ErrorInfo, -(1 << 11), (1 << 11) - 2, + "immediate must be a multiple of 2 bytes in the range"); case Match_InvalidSImm13Lsb0: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 12), (1 << 12) - 2, Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -63,7 +63,9 @@ { "fixup_riscv_lo12_s", 0, 32, 0 }, { "fixup_riscv_pcrel_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_jal", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, - { "fixup_riscv_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel } + { "fixup_riscv_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_riscv_rvc_jump", 2, 11, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_riscv_rvc_branch", 2, 11, MCFixupKindInfo::FKF_IsPCRel } }; if (Kind < FirstTargetFixupKind) @@ -152,8 +154,44 @@ Value = (Sbit << 31) | (Mid6 << 25) | (Lo4 << 8) | (Hi1 << 7); return Value; } + case RISCV::fixup_riscv_rvc_jump: { + // Need to produce offset[11|4|9:8|10|6|7|3:1|5] from the 11-bit Value. + unsigned Bit11 = (Value >> 11) & 0x1; + unsigned Bit4 = (Value >> 4) & 0x1; + unsigned Bit9_8 = (Value >> 8) & 0x3; + unsigned Bit10 = (Value >> 10) & 0x1; + unsigned Bit6 = (Value >> 6) & 0x1; + unsigned Bit7 = (Value >> 7) & 0x1; + unsigned Bit3_1 = (Value >> 1) & 0x7; + unsigned Bit5 = (Value >> 5) & 0x1; + Value = (Bit11 << 10) | (Bit4 << 9) | (Bit9_8 << 7) | (Bit10 << 6) | + (Bit6 << 5) | (Bit7 << 4) | (Bit3_1 << 1) | Bit5; + return Value; + } + case RISCV::fixup_riscv_rvc_branch: { + // Need to produce offset[8|4:3], [reg 3 bit], offset[7:6|2:1|5] + unsigned Bit8 = (Value >> 8) & 0x1; + unsigned Bit7_6 = (Value >> 6) & 0x3; + unsigned Bit5 = (Value >> 5) & 0x1; + unsigned Bit4_3 = (Value >> 3) & 0x3; + unsigned Bit2_1 = (Value >> 1) & 0x3; + Value = (Bit8 << 10) | (Bit4_3 << 8) | (Bit7_6 << 3) | + (Bit2_1 << 1) | Bit5; + return Value; + } + + } +} +static unsigned getSize(unsigned Kind) { + switch (Kind) { + default: + return 4; + case RISCV::fixup_riscv_rvc_jump: + case RISCV::fixup_riscv_rvc_branch: + return 2; } + return 4; } void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, @@ -171,6 +209,7 @@ Value <<= Info.TargetOffset; unsigned Offset = Fixup.getOffset(); + unsigned FullSize = getSize(Fixup.getKind()); #ifndef NDEBUG unsigned NumBytes = (Info.TargetSize + 7) / 8; @@ -179,7 +218,7 @@ // For each byte of the fragment that the fixup touches, mask in the // bits from the fixup value. - for (unsigned i = 0; i != 4; ++i) { + for (unsigned i = 0; i != FullSize; ++i) { Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); } } Index: lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -59,6 +59,10 @@ return ELF::R_RISCV_JAL; case RISCV::fixup_riscv_branch: return ELF::R_RISCV_BRANCH; + case RISCV::fixup_riscv_rvc_jump: + return ELF::R_RISCV_RVC_JUMP; + case RISCV::fixup_riscv_rvc_branch: + return ELF::R_RISCV_RVC_BRANCH; } } Index: lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -35,7 +35,13 @@ // fixup_riscv_branch - 12-bit fixup for symbol references in the branch // instructions fixup_riscv_branch, - + // fixup_riscv_rvc_jump - 11-bit fixup for symbol references in the + // compressed instruction + fixup_riscv_rvc_jump, + // fixup_riscv_rvc_branch - 8-bit fixup for symbol references in the + // compressed branch instruction + fixup_riscv_rvc_branch, + // fixup_riscv_invalid - used as a sentinel and a marker, must be last fixup fixup_riscv_invalid, NumTargetFixupKinds = fixup_riscv_invalid - FirstTargetFixupKind Index: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -179,6 +179,10 @@ FixupKind = RISCV::fixup_riscv_jal; } else if (MIFrm == RISCVII::InstFormatB) { FixupKind = RISCV::fixup_riscv_branch; + } else if (MIFrm == RISCVII::InstFormatCJ) { + FixupKind = RISCV::fixup_riscv_rvc_jump; + } else if (MIFrm == RISCVII::InstFormatCB) { + FixupKind = RISCV::fixup_riscv_rvc_branch; } } Index: lib/Target/RISCV/RISCVInstrFormatsC.td =================================================================== --- lib/Target/RISCV/RISCVInstrFormatsC.td +++ lib/Target/RISCV/RISCVInstrFormatsC.td @@ -34,6 +34,18 @@ let TSFlags{3-0} = format.Value; } +class CR funct4, bits<2> opcode, dag outs, dag ins, + string asmstr> + : RV16Inst { + bits<5> rs1; + bits<5> rs2; + + let Inst{15-12} = funct4; + let Inst{11-7} = rs1; + let Inst{6-2} = rs2; + let Inst{1-0} = opcode; +} + class CI funct3, bits<2> opcode, dag outs, dag ins, string asmstr> : RV16Inst { @@ -82,3 +94,31 @@ let Inst{4-2} = rs2; let Inst{1-0} = opcode; } + +class CB funct3, bits<2> opcode, dag outs, dag ins, + string asmstr> + : RV16Inst { + bits<9> imm; + bits<3> rs1; + + let Inst{15-13} = funct3; + let Inst{9-7} = rs1; + let Inst{1-0} = opcode; +} + +class CJ funct3, bits<2> opcode, dag outs, dag ins, + string asmstr> + : RV16Inst { + bits<12> offset; + + let Inst{15-13} = funct3; + let Inst{12} = offset{11}; + let Inst{11} = offset{4}; + let Inst{10-9} = offset{9-8}; + let Inst{8} = offset{10}; + let Inst{7} = offset{6}; + let Inst{6} = offset{7}; + let Inst{5-3} = offset{3-1}; + let Inst{2} = offset{5}; + let Inst{1-0} = opcode; +} Index: lib/Target/RISCV/RISCVInstrInfoC.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfoC.td +++ lib/Target/RISCV/RISCVInstrInfoC.td @@ -29,6 +29,20 @@ let DecoderMethod = "decodeUImmOperand<7>"; } +// A 9-bit signed immediate where the least significant bit is zero. +def simm9_lsb0 : Operand { + let ParserMatchClass = SImmAsmOperand<9, "Lsb0">; + let EncoderMethod = "getImmOpValueAsr1"; + let DecoderMethod = "decodeSImmOperandAndLsl1<9>"; +} + +// A 12-bit signed immediate where the least significant bit is zero. +def simm12_lsb0 : Operand { + let ParserMatchClass = SImmAsmOperand<12, "Lsb0">; + let EncoderMethod = "getImmOpValueAsr1"; + let DecoderMethod = "decodeSImmOperandAndLsl1<12>"; +} + //===----------------------------------------------------------------------===// // Instruction Class Templates //===----------------------------------------------------------------------===// @@ -57,6 +71,49 @@ CS; +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class Jump_Imm : CJ<0b101, 0b01, (outs), (ins simm12_lsb0:$offset), + "c.j\t$offset"> { + let isBranch = 1; + let isTerminator=1; + let isBarrier=1; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCall = 1 in +class Call_Imm : CJ<0b001, 0b01, (outs), (ins simm12_lsb0:$offset), + "c.jal\t$offset">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class Jump_Reg : + CR<0b1000, 0b10, (outs), (ins cls:$rs1), + "c.jr\t$rs1"> { + let isBranch = 1; + let isBarrier = 1; + let isTerminator = 1; + let isIndirectBranch = 1; + let rs2 = 0; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, + isCall=1, Defs=[X1], rs2 = 0 in +class Call_Reg : + CR<0b1001, 0b10, (outs), (ins cls:$rs1), + "c.jalr\t$rs1">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +class Bcz funct3, string OpcodeStr, PatFrag CondOp, + RegisterClass cls> : + CB { + let isBranch = 1; + let isTerminator = 1; + let Inst{12} = imm{8}; + let Inst{11-10} = imm{4-3}; + let Inst{6-5} = imm{7-6}; + let Inst{4-3} = imm{2-1}; + let Inst{2} = imm{5}; +} + //===----------------------------------------------------------------------===// // Stack-Pointer-Based Loads and Stores //===----------------------------------------------------------------------===// @@ -91,3 +148,18 @@ let Inst{6} = imm{2}; let Inst{5} = imm{6}; } + +//===----------------------------------------------------------------------===// +// Control Transfer Instructions +//===----------------------------------------------------------------------===// + +def CJ : Jump_Imm, Requires<[HasStdExtC]>; + +def CJAL : Call_Imm, Requires<[HasStdExtC]>; + +def CJR : Jump_Reg, Requires<[HasStdExtC]>; + +def CJALR : Call_Reg, Requires<[HasStdExtC]>; + +def CBEQZ : Bcz<0b110, "c.beqz", seteq, GPRC>, Requires<[HasStdExtC]>; +def CBNEZ : Bcz<0b111, "c.bnez", setne, GPRC>, Requires<[HasStdExtC]>; Index: test/MC/RISCV/compressed-invalid.s =================================================================== --- test/MC/RISCV/compressed-invalid.s +++ test/MC/RISCV/compressed-invalid.s @@ -1,8 +1,11 @@ # RUN: not llvm-mc -mattr=+c < %s 2>&1 | FileCheck %s +.LBB: ## GPRC c.lw ra, 4(sp) # CHECK: :[[@LINE]]:7: error: invalid operand for instruction c.sw sp, 4(sp) # CHECK: :[[@LINE]]:7: error: invalid operand for instruction +c.beqz t0, .LBB # CHECK: :[[@LINE]]:9: error: invalid operand for instruction +c.bnez s8, .LBB # CHECK: :[[@LINE]]:9: error: invalid operand for instruction # Out of range immediates @@ -12,3 +15,11 @@ ## uimm7_lsb00 c.lw s0, -4(sp) # CHECK: :[[@LINE]]:11: error: immediate must be a multiple of 4 bytes in the range [0, 124] c.sw s0, 130(sp) # CHECK: :[[@LINE]]:11: error: immediate must be a multiple of 4 bytes in the range [0, 124] + +## simm9_lsb0 +c.bnez s1, -1028 # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-256, 254] +c.beqz a0, 280 # CHECK: :[[@LINE]]:13: error: immediate must be a multiple of 2 bytes in the range [-256, 254] + +## simm12_lsb0 +c.j 4096 # CHECK: :[[@LINE]]:5: error: immediate must be a multiple of 2 bytes in the range [-2048, 2046] +c.jal -3000 # CHECK: :[[@LINE]]:7: error: immediate must be a multiple of 2 bytes in the range [-2048, 2046] Index: test/MC/RISCV/compressed-valid.s =================================================================== --- test/MC/RISCV/compressed-valid.s +++ test/MC/RISCV/compressed-valid.s @@ -15,3 +15,19 @@ # CHECK-INST: c.sw a5, 8(a3) # CHECK: encoding: [0x9c,0xc6] c.sw a5, 8(a3) + +# CHECK-INST: c.j -16 +# CHECK: encoding: [0xe5,0xbf] +c.j -16 +# CHECK-INST: c.jr a7 +# CHECK: encoding: [0x82,0x88] +c.jr a7 +# CHECK-INST: c.jalr a1 +# CHECK: encoding: [0x82,0x95] +c.jalr a1 +# CHECK-INST: c.beqz a3, -8 +# CHECK: encoding: [0xf5,0xde] +c.beqz a3, -8 +# CHECK-INST: c.bnez a5, -12 +# CHECK: encoding: [0xed,0xff] +c.bnez a5, -12 Index: test/MC/RISCV/fixups-compressed.s =================================================================== --- /dev/null +++ test/MC/RISCV/fixups-compressed.s @@ -0,0 +1,18 @@ +# RUN: llvm-mc %s -mattr=+c -show-encoding \ +# RUN: | FileCheck -check-prefix=CHECK-FIXUP %s +# RUN: llvm-mc -filetype=obj -mattr=+c < %s \ +# RUN: | llvm-objdump -d -mattr=+c - | FileCheck -check-prefix=CHECK-INSTR %s + +.LBB0_2: +# CHECK-FIXUP: encoding: [0bAAAAAA01,0b101AAAAA] +# 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: encoding: [0bAAAAAA01,0b110AAAAA] +# 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: encoding: [0bAAAAAA01,0b111AAAAA] +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB0_2, kind: fixup_riscv_rvc_branch +# CHECK-INSTR: c.bnez a5, -8 +c.bnez a5, .LBB0_2 Index: test/MC/RISCV/relocations.s =================================================================== --- test/MC/RISCV/relocations.s +++ test/MC/RISCV/relocations.s @@ -1,6 +1,6 @@ -# RUN: llvm-mc -triple riscv32 < %s -show-encoding \ +# RUN: llvm-mc -triple riscv32 -mattr=+c < %s -show-encoding \ # RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s -# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ +# RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+c < %s \ # RUN: | llvm-readobj -r | FileCheck -check-prefix=RELOC %s # Check prefixes: @@ -63,3 +63,13 @@ # RELOC: R_RISCV_BRANCH # INSTR: bgeu a0, a1, foo # FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_branch + +c.jal foo +# RELOC: R_RISCV_RVC_JUMP +# 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 +# INSTR: c.bnez a0, foo +# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_riscv_rvc_branch