Skip to content

Commit c3bf3d1

Browse files
committed
[RISCV] Add support for RVC HINT instructions
The hint instructions are enabled by default (if the standard C extension is enabled). To disable them pass -mattr=-rvc-hints. Differential Revision: https://reviews.llvm.org/D62592 llvm-svn: 369528
1 parent a451156 commit c3bf3d1

File tree

11 files changed

+318
-11
lines changed

11 files changed

+318
-11
lines changed

llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,10 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
864864
return generateImmOutOfRangeError(Operands, ErrorInfo,
865865
std::numeric_limits<int32_t>::min(),
866866
std::numeric_limits<uint32_t>::max());
867+
case Match_InvalidImmZero: {
868+
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
869+
return Error(ErrorLoc, "immediate must be zero");
870+
}
867871
case Match_InvalidUImmLog2XLen:
868872
if (isRV64())
869873
return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 6) - 1);

llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,77 @@ static DecodeStatus decodeFRMArg(MCInst &Inst, uint64_t Imm,
280280
return MCDisassembler::Success;
281281
}
282282

283+
static DecodeStatus decodeRVCInstrSImm(MCInst &Inst, unsigned Insn,
284+
uint64_t Address, const void *Decoder);
285+
286+
static DecodeStatus decodeRVCInstrRdSImm(MCInst &Inst, unsigned Insn,
287+
uint64_t Address, const void *Decoder);
288+
289+
static DecodeStatus decodeRVCInstrRdRs1UImm(MCInst &Inst, unsigned Insn,
290+
uint64_t Address,
291+
const void *Decoder);
292+
293+
static DecodeStatus decodeRVCInstrRdRs2(MCInst &Inst, unsigned Insn,
294+
uint64_t Address, const void *Decoder);
295+
296+
static DecodeStatus decodeRVCInstrRdRs1Rs2(MCInst &Inst, unsigned Insn,
297+
uint64_t Address,
298+
const void *Decoder);
299+
283300
#include "RISCVGenDisassemblerTables.inc"
284301

302+
static DecodeStatus decodeRVCInstrSImm(MCInst &Inst, unsigned Insn,
303+
uint64_t Address, const void *Decoder) {
304+
uint64_t SImm6 =
305+
fieldFromInstruction(Insn, 12, 1) << 5 | fieldFromInstruction(Insn, 2, 5);
306+
assert(decodeSImmOperand<6>(Inst, SImm6, Address, Decoder) ==
307+
MCDisassembler::Success && "Invalid immediate");
308+
return MCDisassembler::Success;
309+
}
310+
311+
static DecodeStatus decodeRVCInstrRdSImm(MCInst &Inst, unsigned Insn,
312+
uint64_t Address,
313+
const void *Decoder) {
314+
DecodeGPRRegisterClass(Inst, 0, Address, Decoder);
315+
uint64_t SImm6 =
316+
fieldFromInstruction(Insn, 12, 1) << 5 | fieldFromInstruction(Insn, 2, 5);
317+
assert(decodeSImmOperand<6>(Inst, SImm6, Address, Decoder) ==
318+
MCDisassembler::Success && "Invalid immediate");
319+
return MCDisassembler::Success;
320+
}
321+
322+
static DecodeStatus decodeRVCInstrRdRs1UImm(MCInst &Inst, unsigned Insn,
323+
uint64_t Address,
324+
const void *Decoder) {
325+
DecodeGPRRegisterClass(Inst, 0, Address, Decoder);
326+
Inst.addOperand(Inst.getOperand(0));
327+
uint64_t UImm6 =
328+
fieldFromInstruction(Insn, 12, 1) << 5 | fieldFromInstruction(Insn, 2, 5);
329+
assert(decodeUImmOperand<6>(Inst, UImm6, Address, Decoder) ==
330+
MCDisassembler::Success && "Invalid immediate");
331+
return MCDisassembler::Success;
332+
}
333+
334+
static DecodeStatus decodeRVCInstrRdRs2(MCInst &Inst, unsigned Insn,
335+
uint64_t Address, const void *Decoder) {
336+
unsigned Rd = fieldFromInstruction(Insn, 7, 5);
337+
unsigned Rs2 = fieldFromInstruction(Insn, 2, 5);
338+
DecodeGPRRegisterClass(Inst, Rd, Address, Decoder);
339+
DecodeGPRRegisterClass(Inst, Rs2, Address, Decoder);
340+
return MCDisassembler::Success;
341+
}
342+
343+
static DecodeStatus decodeRVCInstrRdRs1Rs2(MCInst &Inst, unsigned Insn,
344+
uint64_t Address,
345+
const void *Decoder) {
346+
unsigned Rd = fieldFromInstruction(Insn, 7, 5);
347+
unsigned Rs2 = fieldFromInstruction(Insn, 2, 5);
348+
DecodeGPRRegisterClass(Inst, Rd, Address, Decoder);
349+
Inst.addOperand(Inst.getOperand(0));
350+
DecodeGPRRegisterClass(Inst, Rs2, Address, Decoder);
351+
return MCDisassembler::Success;
352+
}
353+
285354
DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
286355
ArrayRef<uint8_t> Bytes,
287356
uint64_t Address,

llvm/lib/Target/RISCV/RISCV.td

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ def FeatureStdExtC
4343
def HasStdExtC : Predicate<"Subtarget->hasStdExtC()">,
4444
AssemblerPredicate<"FeatureStdExtC">;
4545

46+
def FeatureRVCHints
47+
: SubtargetFeature<"rvc-hints", "EnableRVCHintInstrs", "true",
48+
"Enable RVC Hint Instructions.">;
49+
def HasRVCHints : Predicate<"Subtarget->enableRVCHintInstrs()">,
50+
AssemblerPredicate<"FeatureRVCHints">;
4651

4752
def Feature64Bit
4853
: SubtargetFeature<"64bit", "HasRV64", "true", "Implements RV64">;
@@ -83,9 +88,10 @@ include "RISCVRegisterBanks.td"
8388
// RISC-V processors supported.
8489
//===----------------------------------------------------------------------===//
8590

86-
def : ProcessorModel<"generic-rv32", NoSchedModel, []>;
91+
def : ProcessorModel<"generic-rv32", NoSchedModel, [FeatureRVCHints]>;
8792

88-
def : ProcessorModel<"generic-rv64", NoSchedModel, [Feature64Bit]>;
93+
def : ProcessorModel<"generic-rv64", NoSchedModel, [Feature64Bit,
94+
FeatureRVCHints]>;
8995

9096
//===----------------------------------------------------------------------===//
9197
// Define the RISC-V target.

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ class ImmAsmOperand<string prefix, int width, string suffix> : AsmOperandClass {
6969
let DiagnosticType = !strconcat("Invalid", Name);
7070
}
7171

72+
def ImmZeroAsmOperand : AsmOperandClass {
73+
let Name = "ImmZero";
74+
let RenderMethod = "addImmOperands";
75+
let DiagnosticType = !strconcat("Invalid", Name);
76+
}
77+
7278
class SImmAsmOperand<int width, string suffix = "">
7379
: ImmAsmOperand<"S", width, suffix> {
7480
}

llvm/lib/Target/RISCV/RISCVInstrInfoC.td

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ def simm6nonzero : Operand<XLenVT>,
6161
}];
6262
}
6363

64+
def immzero : Operand<XLenVT>,
65+
ImmLeaf<XLenVT, [{return (Imm == 0);}]> {
66+
let ParserMatchClass = ImmZeroAsmOperand;
67+
}
68+
6469
def CLUIImmAsmOperand : AsmOperandClass {
6570
let Name = "CLUIImm";
6671
let RenderMethod = "addImmOperands";
@@ -344,7 +349,10 @@ def C_SD : CStore_rri<0b111, "c.sd", GPRC, uimm8_lsb000> {
344349
}
345350

346351
let rd = 0, imm = 0, hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
347-
def C_NOP : RVInst16CI<0b000, 0b01, (outs), (ins), "c.nop", "">;
352+
def C_NOP : RVInst16CI<0b000, 0b01, (outs), (ins), "c.nop", "">
353+
{
354+
let Inst{6-2} = 0;
355+
}
348356

349357
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
350358
def C_ADDI : RVInst16CI<0b000, 0b01, (outs GPRNoX0:$rd_wb),
@@ -354,6 +362,15 @@ def C_ADDI : RVInst16CI<0b000, 0b01, (outs GPRNoX0:$rd_wb),
354362
let Inst{6-2} = imm{4-0};
355363
}
356364

365+
let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
366+
def C_ADDI_NOP : RVInst16CI<0b000, 0b01, (outs GPRX0:$rd_wb),
367+
(ins GPRX0:$rd, immzero:$imm),
368+
"c.addi", "$rd, $imm"> {
369+
let Constraints = "$rd = $rd_wb";
370+
let Inst{6-2} = 0;
371+
let isAsmParserOnly = 1;
372+
}
373+
357374
let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCall = 1,
358375
DecoderNamespace = "RISCV32Only_", Defs = [X1],
359376
Predicates = [HasStdExtC, IsRV32] in
@@ -522,6 +539,105 @@ def C_UNIMP : RVInst16<(outs), (ins), "c.unimp", "", [], InstFormatOther> {
522539

523540
} // Predicates = [HasStdExtC]
524541

542+
//===----------------------------------------------------------------------===//
543+
// HINT Instructions
544+
//===----------------------------------------------------------------------===//
545+
546+
let Predicates = [HasStdExtC, HasRVCHints], hasSideEffects = 0, mayLoad = 0,
547+
mayStore = 0 in
548+
{
549+
550+
let rd = 0 in
551+
def C_NOP_HINT : RVInst16CI<0b000, 0b01, (outs), (ins simm6nonzero:$imm),
552+
"c.nop", "$imm"> {
553+
let Inst{6-2} = imm{4-0};
554+
let DecoderMethod = "decodeRVCInstrSImm";
555+
}
556+
557+
// Just a different syntax for the c.nop hint: c.addi x0, simm6 vs c.nop simm6.
558+
def C_ADDI_HINT_X0 : RVInst16CI<0b000, 0b01, (outs GPRX0:$rd_wb),
559+
(ins GPRX0:$rd, simm6nonzero:$imm),
560+
"c.addi", "$rd, $imm"> {
561+
let Constraints = "$rd = $rd_wb";
562+
let Inst{6-2} = imm{4-0};
563+
let isAsmParserOnly = 1;
564+
}
565+
566+
def C_ADDI_HINT_IMM_ZERO : RVInst16CI<0b000, 0b01, (outs GPRNoX0:$rd_wb),
567+
(ins GPRNoX0:$rd, immzero:$imm),
568+
"c.addi", "$rd, $imm"> {
569+
let Constraints = "$rd = $rd_wb";
570+
let Inst{6-2} = 0;
571+
let isAsmParserOnly = 1;
572+
}
573+
574+
def C_LI_HINT : RVInst16CI<0b010, 0b01, (outs GPRX0:$rd), (ins simm6:$imm),
575+
"c.li", "$rd, $imm"> {
576+
let Inst{6-2} = imm{4-0};
577+
let Inst{11-7} = 0;
578+
let DecoderMethod = "decodeRVCInstrRdSImm";
579+
}
580+
581+
def C_LUI_HINT : RVInst16CI<0b011, 0b01, (outs GPRX0:$rd),
582+
(ins c_lui_imm:$imm),
583+
"c.lui", "$rd, $imm"> {
584+
let Inst{6-2} = imm{4-0};
585+
let Inst{11-7} = 0;
586+
let DecoderMethod = "decodeRVCInstrRdSImm";
587+
}
588+
589+
def C_MV_HINT : RVInst16CR<0b1000, 0b10, (outs GPRX0:$rs1), (ins GPRNoX0:$rs2),
590+
"c.mv", "$rs1, $rs2">
591+
{
592+
let Inst{11-7} = 0;
593+
let DecoderMethod = "decodeRVCInstrRdRs2";
594+
}
595+
596+
def C_ADD_HINT : RVInst16CR<0b1001, 0b10, (outs GPRX0:$rs1_wb),
597+
(ins GPRX0:$rs1, GPRNoX0:$rs2),
598+
"c.add", "$rs1, $rs2"> {
599+
let Constraints = "$rs1 = $rs1_wb";
600+
let Inst{11-7} = 0;
601+
let DecoderMethod = "decodeRVCInstrRdRs1Rs2";
602+
}
603+
604+
def C_SLLI_HINT : RVInst16CI<0b000, 0b10, (outs GPRX0:$rd_wb),
605+
(ins GPRX0:$rd, uimmlog2xlennonzero:$imm),
606+
"c.slli" ,"$rd, $imm"> {
607+
let Constraints = "$rd = $rd_wb";
608+
let Inst{6-2} = imm{4-0};
609+
let Inst{11-7} = 0;
610+
let DecoderMethod = "decodeRVCInstrRdRs1UImm";
611+
}
612+
613+
def C_SLLI64_HINT : RVInst16CI<0b000, 0b10, (outs GPR:$rd_wb), (ins GPR:$rd),
614+
"c.slli64" ,"$rd"> {
615+
let Constraints = "$rd = $rd_wb";
616+
let Inst{6-2} = 0;
617+
let Inst{12} = 0;
618+
}
619+
620+
def C_SRLI64_HINT : RVInst16CI<0b100, 0b01, (outs GPRC:$rd_wb),
621+
(ins GPRC:$rd),
622+
"c.srli64", "$rd"> {
623+
let Constraints = "$rd = $rd_wb";
624+
let Inst{6-2} = 0;
625+
let Inst{11-10} = 0;
626+
let Inst{12} = 0;
627+
}
628+
629+
def C_SRAI64_HINT : RVInst16CI<0b100, 0b01, (outs GPRC:$rd_wb),
630+
(ins GPRC:$rd),
631+
"c.srai64", "$rd"> {
632+
let Constraints = "$rd = $rd_wb";
633+
let Inst{6-2} = 0;
634+
let Inst{11-10} = 1;
635+
let Inst{12} = 0;
636+
}
637+
638+
} // Predicates = [HasStdExtC, HasRVCHints], hasSideEffects = 0, mayLoad = 0,
639+
// mayStore = 0
640+
525641
//===----------------------------------------------------------------------===//
526642
// Assembler Pseudo Instructions
527643
//===----------------------------------------------------------------------===//

llvm/lib/Target/RISCV/RISCVRegisterInfo.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ def GPR : RegisterClass<"RISCV", [XLenVT], 32, (add
101101
[RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>;
102102
}
103103

104+
def GPRX0 : RegisterClass<"RISCV", [XLenVT], 32, (add X0)> {
105+
let RegInfos = RegInfoByHwMode<
106+
[RV32, RV64, DefaultMode],
107+
[RegInfo<32,32,32>, RegInfo<64,64,64>, RegInfo<32,32,32>]>;
108+
}
109+
104110
// The order of registers represents the preferred allocation sequence.
105111
// Registers are listed in the order caller-save, callee-save, specials.
106112
def GPRNoX0 : RegisterClass<"RISCV", [XLenVT], 32, (add

llvm/lib/Target/RISCV/RISCVSubtarget.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
4242
bool HasRV64 = false;
4343
bool IsRV32E = false;
4444
bool EnableLinkerRelax = false;
45+
bool EnableRVCHintInstrs = false;
4546
unsigned XLen = 32;
4647
MVT XLenVT = MVT::i32;
4748
RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown;
@@ -87,6 +88,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
8788
bool is64Bit() const { return HasRV64; }
8889
bool isRV32E() const { return IsRV32E; }
8990
bool enableLinkerRelax() const { return EnableLinkerRelax; }
91+
bool enableRVCHintInstrs() const { return EnableRVCHintInstrs; }
9092
MVT getXLenVT() const { return XLenVT; }
9193
unsigned getXLen() const { return XLen; }
9294
RISCVABI::ABI getTargetABI() const { return TargetABI; }

llvm/test/MC/RISCV/rv32c-invalid.s

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# RUN: not llvm-mc -triple=riscv32 -mattr=+c < %s 2>&1 | FileCheck %s
1+
# RUN: not llvm-mc -triple=riscv32 -mattr=+c -mattr=-rvc-hints < %s 2>&1 \
2+
# RUN: | FileCheck %s
23

34
## GPRC
45
.LBB:
@@ -20,16 +21,16 @@ c.lwsp x0, 4(sp) # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
2021
c.lwsp zero, 4(sp) # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
2122
c.jr x0 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
2223
c.jalr zero # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
23-
c.addi x0, x0, 1 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
24-
c.li zero, 2 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
25-
c.slli zero, zero, 4 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction
26-
c.mv zero, s0 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
24+
c.addi x0, x0, 1 # CHECK: :[[@LINE]]:13: error: immediate must be zero
25+
c.li zero, 2 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled
26+
c.slli zero, zero, 4 # CHECK: :[[@LINE]]:15: error: invalid operand for instruction
27+
c.mv zero, s0 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled
2728
c.mv ra, x0 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
2829
c.add ra, ra, x0 # CHECK: :[[@LINE]]:16: error: invalid operand for instruction
29-
c.add zero, zero, sp # CHECK: :[[@LINE]]:8: error: invalid operand for instruction
30+
c.add zero, zero, sp # CHECK: :[[@LINE]]:14: error: invalid operand for instruction
3031

3132
## GPRNoX0X2
32-
c.lui x0, 4 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
33+
c.lui x0, 4 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled
3334
c.lui x2, 4 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
3435

3536
## SP
@@ -54,7 +55,7 @@ c.andi a0, %lo(foo) # CHECK: :[[@LINE]]:12: error: immediate must be an integer
5455
c.andi a0, %hi(foo) # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [-32, 31]
5556

5657
## simm6nonzero
57-
c.addi t0, 0 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31]
58+
c.addi t0, 0 # CHECK: :[[@LINE]]:1: error: instruction use requires an option to be enabled
5859
c.addi t0, -33 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31]
5960
c.addi t0, 32 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31]
6061
c.addi t0, foo # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# RUN: llvm-mc %s -triple riscv64 -mattr=+c -riscv-no-aliases -show-encoding \
2+
# RUN: | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
3+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c < %s \
4+
# RUN: | llvm-objdump -riscv-no-aliases -d -r - \
5+
# RUN: | FileCheck -check-prefixes=CHECK-OBJ,CHECK-ASM-AND-OBJ %s
6+
7+
# CHECK-ASM-AND-OBJ: c.slli zero, 63
8+
# CHECK-ASM: encoding: [0x7e,0x10]
9+
c.slli x0, 63
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# RUN: not llvm-mc -triple=riscv32 -mattr=+c < %s 2>&1 \
2+
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-RV32 %s
3+
# RUN: not llvm-mc -triple=riscv64 -mattr=+c < %s 2>&1 \
4+
# RUN: | FileCheck -check-prefixes=CHECK,CHECK-RV64 %s
5+
6+
c.nop 0 # CHECK: :[[@LINE]]:7: error: immediate must be non-zero in the range [-32, 31]
7+
8+
c.addi x0, 33 # CHECK: :[[@LINE]]:12: error: immediate must be non-zero in the range [-32, 31]
9+
10+
c.li x0, 42 # CHECK: :[[@LINE]]:10: error: immediate must be an integer in the range [-32, 31]
11+
12+
c.lui x0, 0 # CHECK: :[[@LINE]]:11: error: immediate must be in [0xfffe0, 0xfffff] or [1, 31]
13+
14+
c.mv x0, x0 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
15+
16+
c.add x0, x0 # CHECK: :[[@LINE]]:11: error: invalid operand for instruction
17+
18+
c.slli x0, 0 # CHECK-RV32: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 31]
19+
c.slli x0, 32 # CHECK-RV32: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 31]
20+
21+
c.slli x0, 0 # CHECK-RV64: :[[@LINE]]:12: error: immediate must be an integer in the range [1, 63]
22+
23+
c.srli64 x30 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction
24+
25+
c.srai64 x31 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction

0 commit comments

Comments
 (0)