[llvm] [RISCV] Support Expressions in .insn Directives (PR #111893)
Sam Elliott via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 10 11:55:18 PDT 2024
https://github.com/lenary created https://github.com/llvm/llvm-project/pull/111893
When assembling raw instructions, often you want to or together several
fields for clarity, or because you're using an assembly macro with
separate arguments.
This brings the use of `.insn` closer into line with what can be done
with the binutils assembler.
The 64-bit instruction test here explicitly sets the top bit to make
sure this works, even though the assembler is really using `int64_t`
in most places internally.
---
This is stacked on #111878, as testing this change is how I found the bug. Please only review the last commit in this PR.
>From 0ae51f116bda27c590fa6197e2e3342b2f0e1f71 Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Thu, 10 Oct 2024 10:39:50 -0700
Subject: [PATCH 1/2] [RISCV][MC] Fix >32bit .insn Directives
The original patch had a reasonably significant bug. You could not use
`.insn` to assemble encodings that had any bits set above the low 32
bits. This is due to the fact that `getMachineOpValue` was truncating
the immediate value, and I did not commit enough tests of useful cases.
This changes the result of `getMachineOpValue` to be able to return the
48-bit and 64-bit immediates needed for the wider `.insn` directives.
I took the opportunity to move some of the test cases around in the file
to make looking at the output of `llvm-objdump` a little clearer.
---
.../RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp | 6 ++--
llvm/test/MC/RISCV/insn.s | 35 +++++++++++++++----
2 files changed, 32 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
index 66970ed37f2724..54f1a3899c4957 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
@@ -77,7 +77,7 @@ class RISCVMCCodeEmitter : public MCCodeEmitter {
/// Return binary encoding of operand. If the machine operand requires
/// relocation, record the relocation and return zero.
- unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
+ uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -375,7 +375,7 @@ void RISCVMCCodeEmitter::encodeInstruction(const MCInst &MI,
++MCNumEmitted; // Keep track of the # of mi's emitted.
}
-unsigned
+uint64_t
RISCVMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
@@ -384,7 +384,7 @@ RISCVMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,
return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
if (MO.isImm())
- return static_cast<unsigned>(MO.getImm());
+ return MO.getImm();
llvm_unreachable("Unhandled expression!");
return 0;
diff --git a/llvm/test/MC/RISCV/insn.s b/llvm/test/MC/RISCV/insn.s
index e32fec25bb16b4..d24f4fe8b36374 100644
--- a/llvm/test/MC/RISCV/insn.s
+++ b/llvm/test/MC/RISCV/insn.s
@@ -170,17 +170,40 @@ target:
# CHECK-OBJ: <unknown>
.insn 6, 0x1f
-# CHECK-ASM: .insn 0x4, 65503
-# CHECK-ASM: encoding: [0xdf,0xff,0x00,0x00]
-# CHECK-OBJ: <unknown>
-.insn 0xffdf
-
# CHECK-ASM: .insn 0x8, 63
# CHECK-ASM: encoding: [0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
# CHECK-OBJ: <unknown>
.insn 8, 0x3f
+# CHECK-ASM: .insn 0x6, 281474976710623
+# CHECK-ASM: encoding: [0xdf,0xff,0xff,0xff,0xff,0xff]
+# CHECK-OBJ: <unknown>
+.insn 0x6, 0xffffffffffdf
+
+# CHECK-ASM: .insn 0x8, -65
+# CHECK-ASM: encoding: [0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff]
+# CHECK-OBJ: <unknown>
+.insn 0x8, 0xffffffffffffffbf
+
+odd_lengths:
+# CHECK-ASM-LABEL: odd_lengths:
+# CHECK-OBJ-LABEL: <odd_lengths>:
+
+## These deliberately disagree with the lengths objdump expects them to have, so
+## keep them at the end so that the disassembled instruction stream is not out
+## of sync with the encoded instruction stream. We don't check for `<unknown>`
+## as we could get any number of those, so instead check for the encoding
+## halfwords. These might be split into odd 16-bit chunks, so each chunk is on
+## one line.
+
+# CHECK-ASM: .insn 0x4, 65503
+# CHECK-ASM: encoding: [0xdf,0xff,0x00,0x00]
+# CHECK-OBJ: ffdf
+# CHECK-OBJ: 0000
+.insn 0xffdf
+
# CHECK-ASM: .insn 0x4, 65471
# CHECK-ASM: encoding: [0xbf,0xff,0x00,0x00]
-# CHECK-OBJ: <unknown>
+# CHECK-OBJ: ffbf
+# CHECK-OBJ: 0000
.insn 0xffbf
>From 74009e29db74b35a3234f43c5f92bf0d8032c302 Mon Sep 17 00:00:00 2001
From: Sam Elliott <quic_aelliott at quicinc.com>
Date: Thu, 10 Oct 2024 11:45:33 -0700
Subject: [PATCH 2/2] [RISCV] Support Expressions in .insn Directives
When assembling raw instructions, often you want to or together several
fields for clarity, or because you're using an assembly macro with
separate arguments.
This brings the use of `.insn` closer into line with what can be done
with the binutils assembler.
The 64-bit instruction test here explicitly sets the top bit to make
sure this works, even though the assembler is really using `int64_t`
in most places internally.
---
llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp | 5 ++---
llvm/test/MC/RISCV/insn-invalid.s | 9 ++++++---
llvm/test/MC/RISCV/insn.s | 10 ++++++++++
3 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index e68674e830436f..d77ad02ec47bf1 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -3172,12 +3172,11 @@ bool RISCVAsmParser::parseDirectiveInsn(SMLoc L) {
// Try parsing .insn [ length , ] value
std::optional<int64_t> Length;
int64_t Value = 0;
- if (Parser.parseIntToken(
- Value, "expected instruction format or an integer constant"))
+ if (Parser.parseAbsoluteExpression(Value))
return true;
if (Parser.parseOptionalToken(AsmToken::Comma)) {
Length = Value;
- if (Parser.parseIntToken(Value, "expected an integer constant"))
+ if (Parser.parseAbsoluteExpression(Value))
return true;
if (*Length == 0 || (*Length % 2) != 0)
diff --git a/llvm/test/MC/RISCV/insn-invalid.s b/llvm/test/MC/RISCV/insn-invalid.s
index ef2f3c382972ab..40d57a2b6fddf1 100644
--- a/llvm/test/MC/RISCV/insn-invalid.s
+++ b/llvm/test/MC/RISCV/insn-invalid.s
@@ -24,8 +24,8 @@
# 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 . # CHECK: :[[@LINE]]:7: error: expected absolute expression
+.insn 0x2, # CHECK: :[[@LINE]]:12: error: unknown token in expression
.insn 0x4, 0x13, 0 # CHECK: :[[@LINE]]:16: error: invalid operand for instruction
@@ -49,7 +49,10 @@
.insn 0x2, 0x10001 # CHECK: :[[@LINE]]:7: error: encoding value does not fit into instruction
.insn 0x4, 0x100000003 # CHECK: :[[@LINE]]:7: error: encoding value does not fit into instruction
.insn 0x6, 0x100000000001f # CHECK: :[[@LINE]]:7: error: encoding value does not fit into instruction
-.insn 0x8, 0x1000000000000003f # CHECK: :[[@LINE]]:12: error: expected an integer constant
+.insn 0x8, 0x1000000000000003f # CHECK: :[[@LINE]]:12: error: literal value out of range for directive
.insn 0x0010 # CHECK: :[[@LINE]]:7: error: compressed instructions are not allowed
.insn 0x2, 0x0001 # CHECK: :[[@LINE]]:7: error: compressed instructions are not allowed
+
+.insn 0x2 + 0x2, 0x3 | (31 # CHECK: :[[@LINE]]:28: error: expected ')'
+.insn 0x4 * , 0xbf | (31 << 59) # CHECK: :[[@LINE]]:13: error: unknown token in expression
diff --git a/llvm/test/MC/RISCV/insn.s b/llvm/test/MC/RISCV/insn.s
index d24f4fe8b36374..829364c6328843 100644
--- a/llvm/test/MC/RISCV/insn.s
+++ b/llvm/test/MC/RISCV/insn.s
@@ -185,6 +185,16 @@ target:
# CHECK-OBJ: <unknown>
.insn 0x8, 0xffffffffffffffbf
+# CHECK-ASM: .insn 0x4, 3971
+# CHECK-ASM: encoding: [0x83,0x0f,0x00,0x00]
+# CHECK-OBJ: lb t6, 0x0(zero)
+.insn 0x2 + 0x2, 0x3 | (31 << 7)
+
+# CHECK-ASM: .insn 0x8, -576460752303423297
+# CHECK-ASM: encoding: [0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0xf8]
+# CHECK-OBJ: <unknown>
+.insn 0x4 * 0x2, 0xbf | (31 << 59)
+
odd_lengths:
# CHECK-ASM-LABEL: odd_lengths:
# CHECK-OBJ-LABEL: <odd_lengths>:
More information about the llvm-commits
mailing list