[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:11:21 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 90697c6645be2f..0422f6b0ee92e6 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 7d443a34490146..779c8c586371d5 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 c266538bec7361..fc5eccac96454f 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 b807d6904004d0..bdae69960e24aa 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 fb247ebee109294e3590941a8b3bbe41d15d43d4 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 00000000000000..49e40195f6a827
--- /dev/null
+++ b/llvm/test/MC/BPF/branch-or-nop.s
@@ -0,0 +1,11 @@
+# RUN: llvm-mc -triple bpfel -show-encoding < %s | FileCheck %s
+
+dst:
+
+# CHECK: gotol_or_nop dst                        # encoding: [0x06'A',0x10'A',A,A,0x00,0x00,0x00,0x00]
+# CHECK-NEXT:                                    #   fixup A - offset: 0, value: dst, kind: FK_BPF_PCRel_4
+gotol_or_nop dst
+
+# CHECK: nop_or_gotol dst                        # encoding: [0x06'A',0x30'A',A,A,0x00,0x00,0x00,0x00]
+# CHECK-NEXT:                                    #   fixup A - offset: 0, value: dst, kind: FK_BPF_PCRel_4
+nop_or_gotol dst



More information about the llvm-commits mailing list