This is an archive of the discontinued LLVM Phabricator instance.

[BPF] Consolidate 32-bit and 64-bit LDX/STX operations
DraftPublic

Authored by eddyz87 on Jul 28 2023, 9:50 AM.
This is a draft revision that has not yet been submitted for review.

Details

Reviewers
None
Summary

In BPF instruction set [1] load and store instructions are the same
for both ALU and ALU64 modes. Current STW/STW32, STH/STH32, STB/STB32,
LDW/LDW32, LDH/LDH32, LDB/LDB32 instructions have identical byte-code
representations pairwise.

However, at assembly level current BPF backend has different
syntactical representations for these instructions, e.g.:

in -mcpu=v2 mode: r0 = *(u32 *)(r1 + 42)
  vs
in -mcpu=v3 mode: w0 = *(u32 *)(r1 + 42)

This discrepancy is discussed in recent LKML mail thread [2].
This commit removes ST*32/LD*32 instructions replacing those with
64-bit versions combined with EXTRACT_SUBREG when appropriate,
thus removing the notational difference.

E.g. for the code snippet below:

void bar(unsigned int *a, unsigned int *b) { *a = *b; }

Results of clang -O2 -mcpu=v3 --target=bpf -S -o - t.c change as
follows:

before                   after
------                   -----
w2 = *(u32 *)(r2 + 0)    r2 = *(u32 *)(r2 + 0)
*(u32 *)(r1 + 0) = w2    *(u32 *)(r1 + 0) = r2

[1] https://www.kernel.org/doc/html/latest/bpf/instruction-set.html#load-and-store-instructions
[2] https://lore.kernel.org/bpf/87ila7dhmp.fsf@oracle.com/

Diff Detail

Event Timeline

eddyz87 created this revision.Jul 28 2023, 9:50 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 28 2023, 9:50 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
yonghong-song added inline comments.
llvm/test/MC/BPF/load-store-32.s
8

If I understand correctly, the asm syntax w5 = *(u8 *)(r0 + 0) is not supported any more with this patch. That means, if users write inline asm in their code like

...
w5 = *(u8 *)(r0 + 0)
...

The inline asm can be successfully compiled with llvm17/llvm16 etc. but will
fail compilation with llvm18 (with this patch). Is this what we want?

eddyz87 added inline comments.Jul 30 2023, 5:14 AM
llvm/test/MC/BPF/load-store-32.s
8

You are correct. I'm trying to fix this using InstAlias. So far I have the incantation below that works but is kind-of ugly:

foreach I = 0-11 in {
  def : InstAlias<!strconcat("w"#I, " = *(u8 *)($src $offset)"),
                  (LDB !cast<Ri>("R"#I), GPR:$src, i16imm:$offset)>;
  def : InstAlias<!strconcat("w"#I, " = *(u16 *)($src $offset)"),
                  (LDH !cast<Ri>("R"#I), GPR:$src, i16imm:$offset)>;
  def : InstAlias<!strconcat("w"#I, " = *(u32 *)($src $offset)"),
                  (LDW !cast<Ri>("R"#I), GPR:$src, i16imm:$offset)>;
  def : InstAlias<!strconcat("*(u8 *)($dst $offset) = ", "w"#I),
                  (STB !cast<Ri>("R"#I), GPR:$dst, i16imm:$offset)>;
  def : InstAlias<!strconcat("*(u16 *)($dst $offset) = ", "w"#I),
                  (STH !cast<Ri>("R"#I), GPR:$dst, i16imm:$offset)>;
  def : InstAlias<!strconcat("*(u32 *)($dst $offset) = ", "w"#I),
                  (STW !cast<Ri>("R"#I), GPR:$dst, i16imm:$offset)>;
}

I'd prefer to have something like below instead:

def : InstAlias<"$dst = *(u8 *)($src $offset)",
  (LDB (Reg32To64 GPR32:$dst).Reg64, GPR:$src, i16imm:$offset)>;

But can't figure out how to define Reg32To64 at the moment. Still trying to figure it out but if you have a suggestion, please share.

eddyz87 updated this revision to Diff 545492.Jul 30 2023, 5:29 PM

Use InstAlias to preserve w0 = *(u8*)(r1 + 2) syntax.

eddyz87 updated this revision to Diff 547618.Aug 6 2023, 5:36 PM

Mark zero-extension as free for LOAD instructions, see is_zext_free2.ll.
Use INSERT_SUBREG instead of SUBREG_TO_REG for ST{B,H,W} GPR32 patterns.

eddyz87 updated this revision to Diff 549952.Aug 14 2023, 8:10 AM

Added isSmallLoad() check for BPFMIPeephole::eliminateZExtSeq() to eliminate unnecessary ZEXT after CORE instructions.