Bläddra i källkod

cranelift: Implement loads and byteswaps

Signed-off-by: Afonso Bordado <afonsobordado@az8.co>
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Afonso Bordado 2 år sedan
förälder
incheckning
9fcdb85cb2
2 ändrade filer med 122 tillägg och 2 borttagningar
  1. 67 2
      src/cranelift.rs
  2. 55 0
      tests/cranelift.rs

+ 67 - 2
src/cranelift.rs

@@ -6,8 +6,9 @@ use cranelift_codegen::{
     entity::EntityRef,
     ir::{
         condcodes::IntCC,
-        types::{I32, I64},
-        AbiParam, Block, Function, InstBuilder, LibCall, Signature, UserFuncName, Value,
+        types::{I16, I32, I64, I8},
+        AbiParam, Block, Endianness, Function, InstBuilder, LibCall, MemFlags, Signature, Type,
+        UserFuncName, Value,
     },
     isa::{CallConv, OwnedTargetIsa},
     settings::{self, Configurable},
@@ -161,6 +162,28 @@ impl CraneliftCompiler {
                     self.set_dst(bcx, &insn, iconst);
                 }
 
+                // BPF_LDX class
+                ebpf::LD_B_REG | ebpf::LD_H_REG | ebpf::LD_W_REG | ebpf::LD_DW_REG => {
+                    let ty = match insn.opc {
+                        ebpf::LD_B_REG => I8,
+                        ebpf::LD_H_REG => I16,
+                        ebpf::LD_W_REG => I32,
+                        ebpf::LD_DW_REG => I64,
+                        _ => unreachable!(),
+                    };
+
+                    let base = self.insn_src(bcx, &insn);
+                    let loaded = self.reg_load(bcx, ty, base, insn.off);
+
+                    let ext = if ty != I64 {
+                        bcx.ins().uextend(I64, loaded)
+                    } else {
+                        loaded
+                    };
+
+                    self.set_dst(bcx, &insn, ext);
+                }
+
                 // BPF_ALU class
                 // TODO Check how overflow works in kernel. Should we &= U32MAX all src register value
                 // before we do the operation?
@@ -358,6 +381,39 @@ impl CraneliftCompiler {
                     self.set_dst32(bcx, &insn, res);
                 }
 
+                ebpf::BE | ebpf::LE => {
+                    let should_swap = match insn.opc {
+                        ebpf::BE => self.isa.endianness() == Endianness::Little,
+                        ebpf::LE => self.isa.endianness() == Endianness::Big,
+                        _ => unreachable!(),
+                    };
+
+                    let ty: Type = match insn.imm {
+                        16 => I16,
+                        32 => I32,
+                        64 => I64,
+                        _ => unreachable!(),
+                    };
+
+                    if should_swap {
+                        let src = self.insn_dst(bcx, &insn);
+                        let src_narrow = if ty != I64 {
+                            bcx.ins().ireduce(ty, src)
+                        } else {
+                            src
+                        };
+
+                        let res = bcx.ins().bswap(src_narrow);
+                        let res_wide = if ty != I64 {
+                            bcx.ins().uextend(I64, res)
+                        } else {
+                            res
+                        };
+
+                        self.set_dst(bcx, &insn, res_wide);
+                    }
+                }
+
                 // BPF_ALU64 class
                 ebpf::ADD64_IMM => {
                     // reg[_dst] = reg[_dst].wrapping_add(insn.imm as u64),
@@ -602,4 +658,13 @@ impl CraneliftCompiler {
         let val32 = bcx.ins().uextend(I64, val);
         self.set_dst(bcx, insn, val32);
     }
+
+    fn reg_load(&mut self, bcx: &mut FunctionBuilder, ty: Type, base: Value, offset: i16) -> Value {
+        // TODO: Emit bounds checks
+
+        let mut flags = MemFlags::new();
+        flags.set_endianness(Endianness::Little);
+
+        bcx.ins().load(ty, flags, base, offset as i32)
+    }
 }

+ 55 - 0
tests/cranelift.rs

@@ -196,3 +196,58 @@ test_cranelift!(
     ",
     0xffff8000
 );
+
+test_cranelift!(
+    test_cranelift_be16,
+    "
+    ldxh r0, [r1]
+    be16 r0
+    exit
+    ",
+    [0x11, 0x22],
+    0x1122
+);
+
+test_cranelift!(
+    test_cranelift_be16_high,
+    "
+    ldxdw r0, [r1]
+    be16 r0
+    exit
+    ",
+    [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
+    0x1122
+);
+
+test_cranelift!(
+    test_cranelift_be32,
+    "
+    ldxw r0, [r1]
+    be32 r0
+    exit
+    ",
+    [0x11, 0x22, 0x33, 0x44],
+    0x11223344
+);
+
+test_cranelift!(
+    test_cranelift_be32_high,
+    "
+    ldxdw r0, [r1]
+    be32 r0
+    exit
+    ",
+    [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
+    0x11223344
+);
+
+test_cranelift!(
+    test_cranelift_be64,
+    "
+    ldxdw r0, [r1]
+    be64 r0
+    exit
+    ",
+    [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88],
+    0x1122334455667788
+);