Skip to content

Commit

Permalink
[RISCV][MC] Add support for hardcode encoding of .insn directive (#98030
Browse files Browse the repository at this point in the history
)

This patch adds support for the following two hardcode encodings of
.insn directive:
```
.insn <insn-length>, <value>
.insn <value>
```

See also gas's patch
bminor/binutils-gdb@a262b82
NOTE: This patch doesn't support long instructions. 

Closes #97498.
  • Loading branch information
dtcxzyw authored Jul 9, 2024
1 parent 5e56d74 commit 2a086dc
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 4 deletions.
43 changes: 39 additions & 4 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,9 @@ struct RISCVOperand final : public MCParsedAsmOperand {
bool isUImm6() const { return IsUImm<6>(); }
bool isUImm7() const { return IsUImm<7>(); }
bool isUImm8() const { return IsUImm<8>(); }
bool isUImm16() const { return IsUImm<16>(); }
bool isUImm20() const { return IsUImm<20>(); }
bool isUImm32() const { return IsUImm<32>(); }

bool isUImm8GE32() const {
int64_t Imm;
Expand Down Expand Up @@ -3055,17 +3057,50 @@ bool isValidInsnFormat(StringRef Format, bool AllowC) {

/// parseDirectiveInsn
/// ::= .insn [ format encoding, (operands (, operands)*) ]
/// ::= .insn [ length, value ]
/// ::= .insn [ value ]
bool RISCVAsmParser::parseDirectiveInsn(SMLoc L) {
MCAsmParser &Parser = getParser();

bool AllowC = getSTI().hasFeature(RISCV::FeatureStdExtC) ||
getSTI().hasFeature(RISCV::FeatureStdExtZca);

// Expect instruction format as identifier.
StringRef Format;
SMLoc ErrorLoc = Parser.getTok().getLoc();
if (Parser.parseIdentifier(Format))
return Error(ErrorLoc, "expected instruction format");
if (Parser.parseIdentifier(Format)) {
// Try parsing .insn [length], value
int64_t Length = 0;
int64_t Value = 0;
if (Parser.parseIntToken(
Value, "expected instruction format or an integer constant"))
return true;
if (Parser.parseOptionalToken(AsmToken::Comma)) {
Length = Value;
if (Parser.parseIntToken(Value, "expected an integer constant"))
return true;
}

// TODO: Add support for long instructions
int64_t RealLength = (Value & 3) == 3 ? 4 : 2;
if (!isUIntN(RealLength * 8, Value))
return Error(ErrorLoc, "invalid operand for instruction");
if (RealLength == 2 && !AllowC)
return Error(ErrorLoc, "compressed instructions are not allowed");
if (Length != 0 && Length != RealLength)
return Error(ErrorLoc, "instruction length mismatch");

if (getParser().parseEOL("invalid operand for instruction")) {
getParser().eatToEndOfStatement();
return true;
}

emitToStreamer(getStreamer(), MCInstBuilder(RealLength == 2 ? RISCV::Insn16
: RISCV::Insn32)
.addImm(Value));
return false;
}

bool AllowC = getSTI().hasFeature(RISCV::FeatureStdExtC) ||
getSTI().hasFeature(RISCV::FeatureStdExtZca);
if (!isValidInsnFormat(Format, AllowC))
return Error(ErrorLoc, "invalid instruction format");

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ enum OperandType : unsigned {
OPERAND_UIMM9_LSB000,
OPERAND_UIMM10_LSB00_NONZERO,
OPERAND_UIMM12,
OPERAND_UIMM16,
OPERAND_UIMM32,
OPERAND_ZERO,
OPERAND_SIMM5,
OPERAND_SIMM5_PLUS1,
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ def uimm7_opcode : RISCVUImmOp<7> {
}
def uimm7 : RISCVUImmOp<7>;
def uimm8 : RISCVUImmOp<8>;
def uimm16 : RISCVUImmOp<16>;
def uimm32 : RISCVUImmOp<32>;
def simm12 : RISCVSImmLeafOp<12> {
let MCOperandPredicate = [{
int64_t Imm;
Expand Down Expand Up @@ -1120,6 +1122,12 @@ def InsnS : DirectiveInsnS<(outs), (ins uimm7_opcode:$opcode, uimm3:$funct3,
AnyReg:$rs2, AnyReg:$rs1,
simm12:$imm12),
"$opcode, $funct3, $rs2, ${imm12}(${rs1})">;
def Insn32 : RVInst<(outs), (ins uimm32:$value), "", "", [], InstFormatOther> {
bits<32> value;

let Inst{31-0} = value;
let AsmString = ".insn 0x4, $value";
}
}

// Use InstAliases to match these so that we can combine the insn and format
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfoC.td
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,12 @@ def InsnCJ : DirectiveInsnCJ<(outs), (ins uimm2_opcode:$opcode,
uimm3:$funct3,
simm12_lsb0:$imm11),
"$opcode, $funct3, $imm11">;
def Insn16 : RVInst16<(outs), (ins uimm16:$value), "", "", [], InstFormatOther> {
bits<16> value;

let Inst{15-0} = value;
let AsmString = ".insn 0x2, $value";
}
}

// Use InstAliases to match these so that we can combine the insn and format
Expand Down
8 changes: 8 additions & 0 deletions llvm/test/MC/RISCV/insn-invalid.s
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,11 @@

# Make fake mnemonics we use to match these in the tablegened asm match table isn't exposed.
.insn_i 0x13, 0, a0, a1, 13, 14 # CHECK: :[[@LINE]]:1: error: unknown directive

.insn . # CHECK: :[[@LINE]]:7: error: expected instruction format or an integer constant
.insn 0x2, # CHECK: :[[@LINE]]:12: error: expected an integer constant
.insn 0x2, 0xffff # CHECK: :[[@LINE]]:7: error: instruction length mismatch
.insn 0x2, 0xffffffff # CHECK: :[[@LINE]]:7: error: instruction length mismatch
.insn 0xffffffffff # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
.insn 0x0010 # CHECK: :[[@LINE]]:7: error: compressed instructions are not allowed
.insn 0x4, 0x13, 0 # CHECK: :[[@LINE]]:16: error: invalid operand for instruction
10 changes: 10 additions & 0 deletions llvm/test/MC/RISCV/insn.s
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,13 @@ target:
# CHECK-ASM: encoding: [0x03,0xd3,0x03,0x80]
# CHECK-OBJ: lhu t1, -0x800(t2)
.insn i LOAD, 0x5, x6, %lo(2048)(x7)

# CHECK-ASM: .insn 0x4, 19
# CHECK-ASM: encoding: [0x13,0x00,0x00,0x00]
# CHECK-OBJ: addi zero, zero, 0x0
.insn 0x13

# CHECK-ASM: .insn 0x4, 19
# CHECK-ASM: encoding: [0x13,0x00,0x00,0x00]
# CHECK-OBJ: addi zero, zero, 0x0
.insn 0x4, 0x13
1 change: 1 addition & 0 deletions llvm/test/MC/RISCV/insn_c-invalid.s
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
## Make fake mnemonics we use to match these in the tablegened asm match table isn't exposed.
.insn_cr 2, 9, a0, a1 # CHECK: :[[#@LINE]]:1: error: unknown directive

.insn 0xfffffff0 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction
10 changes: 10 additions & 0 deletions llvm/test/MC/RISCV/insn_c.s
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,13 @@ target:
# CHECK-ASM: encoding: [0bAAAAAA01,0b101AAAAA]
# CHECK-OBJ: c.j 0x0 <target>
.insn cj 1, 5, target

# CHECK-ASM: .insn 0x2, 1
# CHECK-ASM: encoding: [0x01,0x00]
# CHECK-OBJ: c.nop
.insn 0x0001

# CHECK-ASM: .insn 0x2, 1
# CHECK-ASM: encoding: [0x01,0x00]
# CHECK-OBJ: c.nop
.insn 0x2, 0x0001

0 comments on commit 2a086dc

Please sign in to comment.