Index: llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ llvm/trunk/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -864,6 +864,10 @@ return generateImmOutOfRangeError(Operands, ErrorInfo, std::numeric_limits::min(), std::numeric_limits::max()); + case Match_InvalidImmZero: { + SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "immediate must be zero"); + } case Match_InvalidUImmLog2XLen: if (isRV64()) return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 6) - 1); Index: llvm/trunk/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ llvm/trunk/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -280,8 +280,77 @@ return MCDisassembler::Success; } +static DecodeStatus decodeRVCInstrSImm(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus decodeRVCInstrRdSImm(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus decodeRVCInstrRdRs1UImm(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + +static DecodeStatus decodeRVCInstrRdRs2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); + +static DecodeStatus decodeRVCInstrRdRs1Rs2(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder); + #include "RISCVGenDisassemblerTables.inc" +static DecodeStatus decodeRVCInstrSImm(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + uint64_t SImm6 = + fieldFromInstruction(Insn, 12, 1) << 5 | fieldFromInstruction(Insn, 2, 5); + assert(decodeSImmOperand<6>(Inst, SImm6, Address, Decoder) == + MCDisassembler::Success && "Invalid immediate"); + return MCDisassembler::Success; +} + +static DecodeStatus decodeRVCInstrRdSImm(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder) { + DecodeGPRRegisterClass(Inst, 0, Address, Decoder); + uint64_t SImm6 = + fieldFromInstruction(Insn, 12, 1) << 5 | fieldFromInstruction(Insn, 2, 5); + assert(decodeSImmOperand<6>(Inst, SImm6, Address, Decoder) == + MCDisassembler::Success && "Invalid immediate"); + return MCDisassembler::Success; +} + +static DecodeStatus decodeRVCInstrRdRs1UImm(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder) { + DecodeGPRRegisterClass(Inst, 0, Address, Decoder); + Inst.addOperand(Inst.getOperand(0)); + uint64_t UImm6 = + fieldFromInstruction(Insn, 12, 1) << 5 | fieldFromInstruction(Insn, 2, 5); + assert(decodeUImmOperand<6>(Inst, UImm6, Address, Decoder) == + MCDisassembler::Success && "Invalid immediate"); + return MCDisassembler::Success; +} + +static DecodeStatus decodeRVCInstrRdRs2(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder) { + unsigned Rd = fieldFromInstruction(Insn, 7, 5); + unsigned Rs2 = fieldFromInstruction(Insn, 2, 5); + DecodeGPRRegisterClass(Inst, Rd, Address, Decoder); + DecodeGPRRegisterClass(Inst, Rs2, Address, Decoder); + return MCDisassembler::Success; +} + +static DecodeStatus decodeRVCInstrRdRs1Rs2(MCInst &Inst, unsigned Insn, + uint64_t Address, + const void *Decoder) { + unsigned Rd = fieldFromInstruction(Insn, 7, 5); + unsigned Rs2 = fieldFromInstruction(Insn, 2, 5); + DecodeGPRRegisterClass(Inst, Rd, Address, Decoder); + Inst.addOperand(Inst.getOperand(0)); + DecodeGPRRegisterClass(Inst, Rs2, Address, Decoder); + return MCDisassembler::Success; +} + DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size, ArrayRef Bytes, uint64_t Address, Index: llvm/trunk/lib/Target/RISCV/RISCV.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCV.td +++ llvm/trunk/lib/Target/RISCV/RISCV.td @@ -43,6 +43,11 @@ def HasStdExtC : Predicate<"Subtarget->hasStdExtC()">, AssemblerPredicate<"FeatureStdExtC">; +def FeatureRVCHints + : SubtargetFeature<"rvc-hints", "EnableRVCHintInstrs", "true", + "Enable RVC Hint Instructions.">; +def HasRVCHints : Predicate<"Subtarget->enableRVCHintInstrs()">, + AssemblerPredicate<"FeatureRVCHints">; def Feature64Bit : SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">; @@ -83,9 +88,10 @@ // RISC-V processors supported. //===----------------------------------------------------------------------===// -def : ProcessorModel<"generic-rv32", NoSchedModel, []>; +def : ProcessorModel<"generic-rv32", NoSchedModel, [FeatureRVCHints]>; -def : ProcessorModel<"generic-rv64", NoSchedModel, [Feature64Bit]>; +def : ProcessorModel<"generic-rv64", NoSchedModel, [Feature64Bit, + FeatureRVCHints]>; //===----------------------------------------------------------------------===// // Define the RISC-V target. Index: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td +++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td @@ -69,6 +69,12 @@ let DiagnosticType = !strconcat("Invalid", Name); } +def ImmZeroAsmOperand : AsmOperandClass { + let Name = "ImmZero"; + let RenderMethod = "addImmOperands"; + let DiagnosticType = !strconcat("Invalid", Name); +} + class SImmAsmOperand : ImmAsmOperand<"S", width, suffix> { } Index: llvm/trunk/lib/Target/RISCV/RISCVInstrInfoC.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrInfoC.td +++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfoC.td @@ -61,6 +61,11 @@ }]; } +def immzero : Operand, + ImmLeaf { + let ParserMatchClass = ImmZeroAsmOperand; +} + def CLUIImmAsmOperand : AsmOperandClass { let Name = "CLUIImm"; let RenderMethod = "addImmOperands"; @@ -344,7 +349,10 @@ } let rd = 0, imm = 0, hasSideEffects = 0, mayLoad = 0, mayStore = 0 in -def C_NOP : RVInst16CI<0b000, 0b01, (outs), (ins), "c.nop", "">; +def C_NOP : RVInst16CI<0b000, 0b01, (outs), (ins), "c.nop", ""> +{ + let Inst{6-2} = 0; +} let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in def C_ADDI : RVInst16CI<0b000, 0b01, (outs GPRNoX0:$rd_wb), @@ -354,6 +362,15 @@ let Inst{6-2} = imm{4-0}; } +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def C_ADDI_NOP : RVInst16CI<0b000, 0b01, (outs GPRX0:$rd_wb), + (ins GPRX0:$rd, immzero:$imm), + "c.addi", "$rd, $imm"> { + let Constraints = "$rd = $rd_wb"; + let Inst{6-2} = 0; + let isAsmParserOnly = 1; +} + let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCall = 1, DecoderNamespace = "RISCV32Only_", Defs = [X1], Predicates = [HasStdExtC, IsRV32] in @@ -523,6 +540,105 @@ } // Predicates = [HasStdExtC] //===----------------------------------------------------------------------===// +// HINT Instructions +//===----------------------------------------------------------------------===// + +let Predicates = [HasStdExtC, HasRVCHints], hasSideEffects = 0, mayLoad = 0, + mayStore = 0 in +{ + +let rd = 0 in +def C_NOP_HINT : RVInst16CI<0b000, 0b01, (outs), (ins simm6nonzero:$imm), + "c.nop", "$imm"> { + let Inst{6-2} = imm{4-0}; + let DecoderMethod = "decodeRVCInstrSImm"; +} + +// Just a different syntax for the c.nop hint: c.addi x0, simm6 vs c.nop simm6. +def C_ADDI_HINT_X0 : RVInst16CI<0b000, 0b01, (outs GPRX0:$rd_wb), + (ins GPRX0:$rd, simm6nonzero:$imm), + "c.addi", "$rd, $imm"> { + let Constraints = "$rd = $rd_wb"; + let Inst{6-2} = imm{4-0}; + let isAsmParserOnly = 1; +} + +def C_ADDI_HINT_IMM_ZERO : RVInst16CI<0b000, 0b01, (outs GPRNoX0:$rd_wb), + (ins GPRNoX0:$rd, immzero:$imm), + "c.addi", "$rd, $imm"> { + let Constraints = "$rd = $rd_wb"; + let Inst{6-2} = 0; + let isAsmParserOnly = 1; +} + +def C_LI_HINT : RVInst16CI<0b010, 0b01, (outs GPRX0:$rd), (ins simm6:$imm), + "c.li", "$rd, $imm"> { + let Inst{6-2} = imm{4-0}; + let Inst{11-7} = 0; + let DecoderMethod = "decodeRVCInstrRdSImm"; +} + +def C_LUI_HINT : RVInst16CI<0b011, 0b01, (outs GPRX0:$rd), + (ins c_lui_imm:$imm), + "c.lui", "$rd, $imm"> { + let Inst{6-2} = imm{4-0}; + let Inst{11-7} = 0; + let DecoderMethod = "decodeRVCInstrRdSImm"; +} + +def C_MV_HINT : RVInst16CR<0b1000, 0b10, (outs GPRX0:$rs1), (ins GPRNoX0:$rs2), + "c.mv", "$rs1, $rs2"> +{ + let Inst{11-7} = 0; + let DecoderMethod = "decodeRVCInstrRdRs2"; +} + +def C_ADD_HINT : RVInst16CR<0b1001, 0b10, (outs GPRX0:$rs1_wb), + (ins GPRX0:$rs1, GPRNoX0:$rs2), + "c.add", "$rs1, $rs2"> { + let Constraints = "$rs1 = $rs1_wb"; + let Inst{11-7} = 0; + let DecoderMethod = "decodeRVCInstrRdRs1Rs2"; +} + +def C_SLLI_HINT : RVInst16CI<0b000, 0b10, (outs GPRX0:$rd_wb), + (ins GPRX0:$rd, uimmlog2xlennonzero:$imm), + "c.slli" ,"$rd, $imm"> { + let Constraints = "$rd = $rd_wb"; + let Inst{6-2} = imm{4-0}; + let Inst{11-7} = 0; + let DecoderMethod = "decodeRVCInstrRdRs1UImm"; +} + +def C_SLLI64_HINT : RVInst16CI<0b000, 0b10, (outs GPR:$rd_wb), (ins GPR:$rd), + "c.slli64" ,"$rd"> { + let Constraints = "$rd = $rd_wb"; + let Inst{6-2} = 0; + let Inst{12} = 0; +} + +def C_SRLI64_HINT : RVInst16CI<0b100, 0b01, (outs GPRC:$rd_wb), + (ins GPRC:$rd), + "c.srli64", "$rd"> { + let Constraints = "$rd = $rd_wb"; + let Inst{6-2} = 0; + let Inst{11-10} = 0; + let Inst{12} = 0; +} + +def C_SRAI64_HINT : RVInst16CI<0b100, 0b01, (outs GPRC:$rd_wb), + (ins GPRC:$rd), + "c.srai64", "$rd"> { + let Constraints = "$rd = $rd_wb"; + let Inst{6-2} = 0; + let Inst{11-10} = 1; + let Inst{12} = 0; +} + +} // Predicates = [HasStdExtC, HasRVCHints], hasSideEffects = 0, mayLoad = 0, + // mayStore = 0 + +//===----------------------------------------------------------------------===// // Assembler Pseudo Instructions //===----------------------------------------------------------------------===// Index: llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.td +++ llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.td @@ -101,6 +101,12 @@ [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>; } +def GPRX0 : RegisterClass<"RISCV", [XLenVT], 32, (add X0)> { + let RegInfos = RegInfoByHwMode< + [RV32, RV64, DefaultMode], + [RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>; +} + // The order of registers represents the preferred allocation sequence. // Registers are listed in the order caller-save, callee-save, specials. def GPRNoX0 : RegisterClass<"RISCV", [XLenVT], 32, (add Index: llvm/trunk/lib/Target/RISCV/RISCVSubtarget.h =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVSubtarget.h +++ llvm/trunk/lib/Target/RISCV/RISCVSubtarget.h @@ -42,6 +42,7 @@ bool HasRV64 = false; bool IsRV32E = false; bool EnableLinkerRelax = false; + bool EnableRVCHintInstrs = false; unsigned XLen = 32; MVT XLenVT = MVT::i32; RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown; @@ -87,6 +88,7 @@ bool is64Bit() const { return HasRV64; } bool isRV32E() const { return IsRV32E; } bool enableLinkerRelax() const { return EnableLinkerRelax; } + bool enableRVCHintInstrs() const { return EnableRVCHintInstrs; } MVT getXLenVT() const { return XLenVT; } unsigned getXLen() const { return XLen; } RISCVABI::ABI getTargetABI() const { return TargetABI; } Index: llvm/trunk/test/MC/RISCV/rv32c-invalid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv32c-invalid.s +++ llvm/trunk/test/MC/RISCV/rv32c-invalid.s @@ -1,4 +1,5 @@ -# RUN: not llvm-mc -triple=riscv32 -mattr=+c < %s 2>&1 | FileCheck %s +# RUN: not llvm-mc -triple=riscv32 -mattr=+c -mattr=-rvc-hints < %s 2>&1 \ +# RUN: | FileCheck %s ## GPRC .LBB: @@ -20,16 +21,16 @@ c.lwsp zero, 4(sp) # CHECK: :[[@LINE]]:9: error: invalid operand for instruction c.jr x0 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction c.jalr zero # CHECK: :[[@LINE]]:9: error: invalid operand for instruction -c.addi x0, x0, 1 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction -c.li zero, 2 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction -c.slli zero, zero, 4 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction -c.mv zero, s0 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction +c.addi x0, x0, 1 # CHECK: :[[@LINE]]:13: error: immediate must be zero +c.li zero, 2 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled +c.slli zero, zero, 4 # CHECK: :[[@LINE]]:15: error: invalid operand for instruction +c.mv zero, s0 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled c.mv ra, x0 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction c.add ra, ra, x0 # CHECK: :[[@LINE]]:16: error: invalid operand for instruction -c.add zero, zero, sp # CHECK: :[[@LINE]]:8: error: invalid operand for instruction +c.add zero, zero, sp # CHECK: :[[@LINE]]:14: error: invalid operand for instruction ## GPRNoX0X2 -c.lui x0, 4 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction +c.lui x0, 4 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled c.lui x2, 4 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction ## SP @@ -54,7 +55,7 @@ c.andi a0, %hi(foo) # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [-32, 31] ## simm6nonzero -c.addi t0, 0 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] +c.addi t0, 0 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled c.addi t0, -33 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] c.addi t0, 32 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] c.addi t0, foo # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] Index: llvm/trunk/test/MC/RISCV/rv64c-hints-valid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rv64c-hints-valid.s +++ llvm/trunk/test/MC/RISCV/rv64c-hints-valid.s @@ -0,0 +1,9 @@ +# RUN: llvm-mc %s -triple riscv64 -mattr=+c -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c < %s \ +# RUN: | llvm-objdump -riscv-no-aliases -d -r - \ +# RUN: | FileCheck -check-prefixes=CHECK-OBJ,CHECK-ASM-AND-OBJ %s + +# CHECK-ASM-AND-OBJ: c.slli zero, 63 +# CHECK-ASM: encoding: [0x7e,0x10] +c.slli x0, 63 Index: llvm/trunk/test/MC/RISCV/rvc-hints-invalid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rvc-hints-invalid.s +++ llvm/trunk/test/MC/RISCV/rvc-hints-invalid.s @@ -0,0 +1,25 @@ +# RUN: not llvm-mc -triple=riscv32 -mattr=+c < %s 2>&1 \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-RV32 %s +# RUN: not llvm-mc -triple=riscv64 -mattr=+c < %s 2>&1 \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-RV64 %s + +c.nop 0 # CHECK: :[[@LINE]]:7: error: immediate must be non-zero in the range [-32, 31] + +c.addi x0, 33 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31] + +c.li x0, 42 # CHECK: :[[@LINE]]:10: error: immediate must be an integer in the range [-32, 31] + +c.lui x0, 0 # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31] + +c.mv x0, x0 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction + +c.add x0, x0 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction + +c.slli x0, 0 # CHECK-RV32: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 31] +c.slli x0, 32 # CHECK-RV32: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 31] + +c.slli x0, 0 # CHECK-RV64: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 63] + +c.srli64 x30 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction + +c.srai64 x31 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction Index: llvm/trunk/test/MC/RISCV/rvc-hints-valid.s =================================================================== --- llvm/trunk/test/MC/RISCV/rvc-hints-valid.s +++ llvm/trunk/test/MC/RISCV/rvc-hints-valid.s @@ -0,0 +1,63 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+c -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc %s -triple riscv64 -mattr=+c -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+c < %s \ +# RUN: | llvm-objdump -riscv-no-aliases -d -r - \ +# RUN: | FileCheck -check-prefixes=CHECK-OBJ,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c < %s \ +# RUN: | llvm-objdump -riscv-no-aliases -d -r - \ +# RUN: | FileCheck -check-prefixes=CHECK-OBJ,CHECK-ASM-AND-OBJ %s + +# CHECK-ASM-AND-OBJ: c.nop 8 +# CHECK-ASM: encoding: [0x21,0x00] +c.nop 8 + +# CHECK-ASM: c.addi zero, 7 +# CHECK-ASM: encoding: [0x1d,0x00] +# CHECK-OBJ: c.nop 7 +c.addi x0, 7 + +# CHECK-ASM-AND-OBJ: c.addi a0, 0 +# CHECK-ASM: encoding: [0x01,0x05] +c.addi a0, 0 + +# CHECK-ASM-AND-OBJ: c.li zero, 0 +# CHECK-ASM: encoding: [0x01,0x40] +c.li x0, 0 + +# CHECK-ASM-AND-OBJ: c.li zero, 1 +# CHECK-ASM: encoding: [0x05,0x40] +c.li x0, 1 + +# CHECK-ASM-AND-OBJ: c.lui zero, 1 +# CHECK-ASM: encoding: [0x05,0x60] +c.lui x0, 1 + +# CHECK-ASM-AND-OBJ: c.mv zero, a0 +# CHECK-ASM: encoding: [0x2a,0x80] +c.mv x0, a0 + +# CHECK-ASM-AND-OBJ: c.add zero, a0 +# CHECK-ASM: encoding: [0x2a,0x90] +c.add x0, a0 + +# CHECK-ASM-AND-OBJ: c.slli zero, 1 +# CHECK-ASM: encoding: [0x06,0x00] +c.slli x0, 1 + +# CHECK-ASM-AND-OBJ: c.slli64 zero +# CHECK-ASM: encoding: [0x02,0x00] +c.slli64 x0 + +# CHECK-ASM-AND-OBJ: c.slli64 a0 +# CHECK-ASM: encoding: [0x02,0x05] +c.slli64 a0 + +# CHECK-ASM-AND-OBJ: c.srli64 a1 +# CHECK-ASM: encoding: [0x81,0x81] +c.srli64 a1 + +# CHECK-ASM-AND-OBJ: c.srai64 a0 +# CHECK-ASM: encoding: [0x01,0x85] +c.srai64 a0