[llvm] [BPF] Add support for asm gotol_or_nop and nop_or_gotol insns (PR #75110)
Yingchi Long via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 11 20:07:07 PST 2023
https://github.com/inclyc updated https://github.com/llvm/llvm-project/pull/75110
>From b7969b536572828c3ecf2cf348cea9b64b21de8c Mon Sep 17 00:00:00 2001
From: Yonghong Song <yonghong.song at linux.dev>
Date: Mon, 11 Dec 2023 14:01:57 -0800
Subject: [PATCH 1/2] [BPF] Add support for asm gotol_or_nop and nop_or_gotol
insns
Two new insns are added to BPF instruction set:
gotol_or_nop
encoding: gotol encoding with src_reg = 1
nop_or_gotol
encoding: gotol encoding with src_reg = 3
Basically src_reg 'bit_0 == 1' means it is gotol_or_nop/nop_or_gotol
insn. The src_reg 'bit_1' indicates the insn itself will be a
'goto' 'bit_1 == 0' or a 'nop' 'bit_1 == 1'.
Two insns intend to support kernel static key like transformation
where the insn can be a nop or a ja.
The following is an example, where two labels,
static_key_loc_1 and static_key_loc_2, can be used
to identify the location of a particular gotol_or_nop/nop_or_gotol
location.
It is possible that user space could do
static_key_enable("static_key_loc_1")
libbpf can validate that the label "static_key_loc_1" indeed
corresponds to a gotol_or_nop/nop_or_gotol insn and it
can translated the 'static_key_enable("static_key_loc_1")'
to something like bpf syscall command 'static_key_enable prog, insn offset 1'
and kernel will do proper adjustment.
the same for static_key_disable, static_key_enabled, etc.
```
$ cat t.c
int bar(void);
int foo1(int arg1)
{
int a = arg1, b;
asm volatile goto ("r0 = 0; \
static_key_loc_1: \
gotol_or_nop %l[label]; \
r2 = 2; \
r3 = 3; \
"::
: "r0", "r2", "r3"
:label);
a = bar();
label:
b = 20 * a;
return b;
}
int foo2(int arg1)
{
int a = arg1, b;
asm volatile goto ("r0 = 0; \
static_key_loc_2: \
nop_or_gotol %l[label]; \
r2 = 2; \
r3 = 3; \
"::
: "r0", "r2", "r3"
:label);
a = bar();
label:
b = 20 * a;
return b;
}
$ clang --target=bpf -O2 -g -c t.c
$ llvm-objdump -S t.o
t.o: file format elf64-bpf
Disassembly of section .text:
0000000000000000 <foo1>:
; asm volatile goto ("r0 = 0; \
0: b7 00 00 00 00 00 00 00 r0 = 0x0
0000000000000008 <static_key_loc_1>:
1: 06 10 00 00 04 00 00 00 gotol_or_nop +0x4 <LBB0_2>
2: b7 02 00 00 02 00 00 00 r2 = 0x2
3: b7 03 00 00 03 00 00 00 r3 = 0x3
; a = bar();
4: 85 10 00 00 ff ff ff ff call -0x1
5: bf 01 00 00 00 00 00 00 r1 = r0
0000000000000030 <LBB0_2>:
; b = 20 * a;
6: 27 01 00 00 14 00 00 00 r1 *= 0x14
; return b;
7: bf 10 00 00 00 00 00 00 r0 = r1
8: 95 00 00 00 00 00 00 00 exit
0000000000000048 <foo2>:
; asm volatile goto ("r0 = 0; \
9: b7 00 00 00 00 00 00 00 r0 = 0x0
0000000000000050 <static_key_loc_2>:
10: 06 30 00 00 04 00 00 00 nop_or_gotol +0x4 <LBB1_2>
11: b7 02 00 00 02 00 00 00 r2 = 0x2
12: b7 03 00 00 03 00 00 00 r3 = 0x3
; a = bar();
13: 85 10 00 00 ff ff ff ff call -0x1
14: bf 01 00 00 00 00 00 00 r1 = r0
0000000000000078 <LBB1_2>:
; b = 20 * a;
15: 27 01 00 00 14 00 00 00 r1 *= 0x14
; return b;
16: bf 10 00 00 00 00 00 00 r0 = r1
17: 95 00 00 00 00 00 00 00 exit
```
---
.../lib/Target/BPF/AsmParser/BPFAsmParser.cpp | 4 +++
llvm/lib/Target/BPF/BPFInstrInfo.td | 28 +++++++++++++++++++
.../BPF/MCTargetDesc/BPFInstPrinter.cpp | 3 +-
.../BPF/MCTargetDesc/BPFMCCodeEmitter.cpp | 3 +-
4 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
index 90697c6645be2..0422f6b0ee92e 100644
--- a/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
+++ b/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp
@@ -231,6 +231,8 @@ struct BPFOperand : public MCParsedAsmOperand {
.Case("call", true)
.Case("goto", true)
.Case("gotol", true)
+ .Case("gotol_or_nop", true)
+ .Case("nop_or_gotol", true)
.Case("*", true)
.Case("exit", true)
.Case("lock", true)
@@ -259,6 +261,8 @@ struct BPFOperand : public MCParsedAsmOperand {
.Case("bswap64", true)
.Case("goto", true)
.Case("gotol", true)
+ .Case("gotol_or_nop", true)
+ .Case("nop_or_gotol", true)
.Case("ll", true)
.Case("skb", true)
.Case("s", true)
diff --git a/llvm/lib/Target/BPF/BPFInstrInfo.td b/llvm/lib/Target/BPF/BPFInstrInfo.td
index 7d443a3449014..779c8c586371d 100644
--- a/llvm/lib/Target/BPF/BPFInstrInfo.td
+++ b/llvm/lib/Target/BPF/BPFInstrInfo.td
@@ -604,6 +604,32 @@ class BRANCH_LONG<BPFJumpOp Opc, string OpcodeStr, list<dag> Pattern>
let BPFClass = BPF_JMP32;
}
+class BRANCH_OR_NOP<BPFJumpOp Opc, string OpcodeStr, list<dag> Pattern>
+ : TYPE_ALU_JMP<Opc.Value, BPF_K.Value,
+ (outs),
+ (ins brtarget:$BrDst),
+ !strconcat(OpcodeStr, " $BrDst"),
+ Pattern> {
+ bits<32> BrDst;
+
+ let Inst{55-52} = 1;
+ let Inst{31-0} = BrDst;
+ let BPFClass = BPF_JMP32;
+}
+
+class NOP_OR_BRANCH<BPFJumpOp Opc, string OpcodeStr, list<dag> Pattern>
+ : TYPE_ALU_JMP<Opc.Value, BPF_K.Value,
+ (outs),
+ (ins brtarget:$BrDst),
+ !strconcat(OpcodeStr, " $BrDst"),
+ Pattern> {
+ bits<32> BrDst;
+
+ let Inst{55-52} = 3;
+ let Inst{31-0} = BrDst;
+ let BPFClass = BPF_JMP32;
+}
+
class CALL<string OpcodeStr>
: TYPE_ALU_JMP<BPF_CALL.Value, BPF_K.Value,
(outs),
@@ -632,6 +658,8 @@ class CALLX<string OpcodeStr>
let isBranch = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1 in {
def JMP : BRANCH<BPF_JA, "goto", [(br bb:$BrDst)]>;
def JMPL : BRANCH_LONG<BPF_JA, "gotol", []>;
+ def JMPL_OR_NOP : BRANCH_OR_NOP<BPF_JA, "gotol_or_nop", []>;
+ def NOP_OR_JMPL : NOP_OR_BRANCH<BPF_JA, "nop_or_gotol", []>;
}
// Jump and link
diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFInstPrinter.cpp b/llvm/lib/Target/BPF/MCTargetDesc/BPFInstPrinter.cpp
index c266538bec736..fc5eccac96454 100644
--- a/llvm/lib/Target/BPF/MCTargetDesc/BPFInstPrinter.cpp
+++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFInstPrinter.cpp
@@ -103,7 +103,8 @@ void BPFInstPrinter::printBrTargetOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isImm()) {
- if (MI->getOpcode() == BPF::JMPL) {
+ if (MI->getOpcode() == BPF::JMPL || MI->getOpcode() == BPF::JMPL_OR_NOP ||
+ MI->getOpcode() == BPF::NOP_OR_JMPL) {
int32_t Imm = Op.getImm();
O << ((Imm >= 0) ? "+" : "") << formatImm(Imm);
} else {
diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
index b807d6904004d..bdae69960e24a 100644
--- a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
+++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
@@ -96,7 +96,8 @@ unsigned BPFMCCodeEmitter::getMachineOpValue(const MCInst &MI,
Fixups.push_back(MCFixup::create(0, Expr, FK_PCRel_4));
else if (MI.getOpcode() == BPF::LD_imm64)
Fixups.push_back(MCFixup::create(0, Expr, FK_SecRel_8));
- else if (MI.getOpcode() == BPF::JMPL)
+ else if (MI.getOpcode() == BPF::JMPL || MI.getOpcode() == BPF::JMPL_OR_NOP ||
+ MI.getOpcode() == BPF::NOP_OR_JMPL)
Fixups.push_back(MCFixup::create(0, Expr, (MCFixupKind)BPF::FK_BPF_PCRel_4));
else
// bb label
>From bf0b7e650f5272b83c3436596cac56c1b5f35d86 Mon Sep 17 00:00:00 2001
From: Yingchi Long <i at lyc.dev>
Date: Tue, 12 Dec 2023 12:06:12 +0800
Subject: [PATCH 2/2] !fixup: add MC tests for #75110
---
llvm/test/MC/BPF/branch-or-nop.s | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 llvm/test/MC/BPF/branch-or-nop.s
diff --git a/llvm/test/MC/BPF/branch-or-nop.s b/llvm/test/MC/BPF/branch-or-nop.s
new file mode 100644
index 0000000000000..e71803b14a191
--- /dev/null
+++ b/llvm/test/MC/BPF/branch-or-nop.s
@@ -0,0 +1,11 @@
+# RUN: llvm-mc -triple bpfel < %s
+
+dst:
+
+# CHECK: gotol_or_nop dst # encoding: [0x06'A',0x01'A',A,A,0x00,0x00,0x00,0x00]
+# CHECK: # fixup A - offset: 0, value: dst, kind: FK_BPF_PCRel_4
+gotol_or_nop dst
+
+# CHECK: nop_or_gotol dst # encoding: [0x06'A',0x03'A',A,A,0x00,0x00,0x00,0x00]
+# CHECK: # fixup A - offset: 0, value: dst, kind: FK_BPF_PCRel_4
+nop_or_gotol dst
More information about the llvm-commits
mailing list