Преглед изворни кода

cranelift: Implement Cranelift jumps

Signed-off-by: Afonso Bordado <afonsobordado@az8.co>
Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Afonso Bordado пре 2 година
родитељ
комит
073b5a161a
2 измењених фајлова са 976 додато и 10 уклоњено
  1. 154 4
      src/cranelift.rs
  2. 822 6
      tests/cranelift.rs

+ 154 - 4
src/cranelift.rs

@@ -1,6 +1,10 @@
 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
 
-use std::{collections::HashMap, convert::TryInto, io::ErrorKind};
+use std::{
+    collections::{BTreeMap, HashMap, HashSet},
+    convert::TryInto,
+    io::ErrorKind
+};
 
 use cranelift_codegen::{
     entity::EntityRef,
@@ -18,7 +22,10 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
 use cranelift_jit::{JITBuilder, JITModule};
 use cranelift_module::{FuncId, Linkage, Module};
 
-use crate::ebpf::{self, Insn, STACK_SIZE};
+use crate::ebpf::{
+    self, Insn, BPF_ALU_OP_MASK, BPF_JEQ, BPF_JGE, BPF_JGT, BPF_JLE, BPF_JLT, BPF_JMP32, BPF_JNE,
+    BPF_JSET, BPF_JSGE, BPF_JSGT, BPF_JSLE, BPF_JSLT, BPF_X, STACK_SIZE,
+};
 
 use super::Error;
 
@@ -44,6 +51,11 @@ pub(crate) struct CraneliftCompiler {
     helpers: HashMap<u32, ebpf::Helper>,
     helper_func_refs: HashMap<u32, FuncRef>,
 
+    /// List of blocks corresponding to each instruction.
+    /// We only store the first instruction that observes a new block
+    insn_blocks: BTreeMap<u32, Block>,
+    filled_blocks: HashSet<Block>,
+
     /// Map of register numbers to Cranelift variables.
     registers: [Variable; 11],
     /// Other usefull variables used throughout the program.
@@ -88,6 +100,8 @@ impl CraneliftCompiler {
             module,
             helpers,
             helper_func_refs: HashMap::new(),
+            insn_blocks: BTreeMap::new(),
+            filled_blocks: HashSet::new(),
             registers,
             mem_start: Variable::new(11),
             mem_end: Variable::new(12),
@@ -147,6 +161,7 @@ impl CraneliftCompiler {
 
         self.module.define_function(func_id, &mut ctx).unwrap();
         self.module.finalize_definitions().unwrap();
+        ctx.clear();
 
         Ok(func_id)
     }
@@ -228,6 +243,12 @@ impl CraneliftCompiler {
         bcx.def_var(self.mbuf_start, mbuf_start);
         bcx.def_var(self.mbuf_end, mbuf_end);
 
+        // Insert the *actual* initial block
+        let program_entry = bcx.create_block();
+        bcx.ins().jump(program_entry, &[]);
+        self.filled_blocks.insert(bcx.current_block().unwrap());
+        self.insn_blocks.insert(0, program_entry);
+
         Ok(())
     }
 
@@ -236,6 +257,17 @@ impl CraneliftCompiler {
         while insn_ptr * ebpf::INSN_SIZE < prog.len() {
             let insn = ebpf::get_insn(prog, insn_ptr);
 
+            // If this instruction is on a new block switch to it.
+            if let Some(block) = self.insn_blocks.get(&(insn_ptr as u32)) {
+                // Blocks must have a terminator instruction at the end before we switch away from them
+                let current_block = bcx.current_block().unwrap();
+                if !self.filled_blocks.contains(&current_block) {
+                    bcx.ins().jump(*block, &[]);
+                }
+
+                bcx.switch_to_block(*block);
+            }
+
             // Set the source location for the instruction
             bcx.set_srcloc(SourceLoc::new(insn_ptr as u32));
 
@@ -739,6 +771,98 @@ impl CraneliftCompiler {
                     self.set_dst(bcx, &insn, res);
                 }
 
+                // BPF_JMP & BPF_JMP32 class
+                ebpf::JA => {
+                    let (_, target_block) = self.prepare_jump_blocks(bcx, insn_ptr, &insn);
+
+                    bcx.ins().jump(target_block, &[]);
+                    self.filled_blocks.insert(bcx.current_block().unwrap());
+                }
+                ebpf::JEQ_IMM
+                | ebpf::JEQ_REG
+                | ebpf::JGT_IMM
+                | ebpf::JGT_REG
+                | ebpf::JGE_IMM
+                | ebpf::JGE_REG
+                | ebpf::JLT_IMM
+                | ebpf::JLT_REG
+                | ebpf::JLE_IMM
+                | ebpf::JLE_REG
+                | ebpf::JNE_IMM
+                | ebpf::JNE_REG
+                | ebpf::JSGT_IMM
+                | ebpf::JSGT_REG
+                | ebpf::JSGE_IMM
+                | ebpf::JSGE_REG
+                | ebpf::JSLT_IMM
+                | ebpf::JSLT_REG
+                | ebpf::JSLE_IMM
+                | ebpf::JSLE_REG
+                | ebpf::JSET_IMM
+                | ebpf::JSET_REG
+                | ebpf::JEQ_IMM32
+                | ebpf::JEQ_REG32
+                | ebpf::JGT_IMM32
+                | ebpf::JGT_REG32
+                | ebpf::JGE_IMM32
+                | ebpf::JGE_REG32
+                | ebpf::JLT_IMM32
+                | ebpf::JLT_REG32
+                | ebpf::JLE_IMM32
+                | ebpf::JLE_REG32
+                | ebpf::JNE_IMM32
+                | ebpf::JNE_REG32
+                | ebpf::JSGT_IMM32
+                | ebpf::JSGT_REG32
+                | ebpf::JSGE_IMM32
+                | ebpf::JSGE_REG32
+                | ebpf::JSLT_IMM32
+                | ebpf::JSLT_REG32
+                | ebpf::JSLE_IMM32
+                | ebpf::JSLE_REG32
+                | ebpf::JSET_IMM32
+                | ebpf::JSET_REG32 => {
+                    let (fallthrough, target) = self.prepare_jump_blocks(bcx, insn_ptr, &insn);
+
+                    let is_reg = (insn.opc & BPF_X) != 0;
+                    let is_32 = (insn.opc & BPF_JMP32) != 0;
+                    let intcc = match insn.opc {
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JEQ => IntCC::Equal,
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JNE => IntCC::NotEqual,
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JGT => IntCC::UnsignedGreaterThan,
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JGE => IntCC::UnsignedGreaterThanOrEqual,
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JLT => IntCC::UnsignedLessThan,
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JLE => IntCC::UnsignedLessThanOrEqual,
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JSGT => IntCC::SignedGreaterThan,
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JSGE => IntCC::SignedGreaterThanOrEqual,
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JSLT => IntCC::SignedLessThan,
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JSLE => IntCC::SignedLessThanOrEqual,
+                        // JSET is handled specially below
+                        c if (c & BPF_ALU_OP_MASK) == BPF_JSET => IntCC::NotEqual,
+                        _ => unreachable!(),
+                    };
+
+                    let lhs = if is_32 {
+                        self.insn_dst32(bcx, &insn)
+                    } else {
+                        self.insn_dst(bcx, &insn)
+                    };
+                    let rhs = match (is_reg, is_32) {
+                        (true, false) => self.insn_src(bcx, &insn),
+                        (true, true) => self.insn_src32(bcx, &insn),
+                        (false, false) => self.insn_imm64(bcx, &insn),
+                        (false, true) => self.insn_imm32(bcx, &insn),
+                    };
+
+                    let cmp_res = if (insn.opc & BPF_ALU_OP_MASK) == BPF_JSET {
+                        bcx.ins().band(lhs, rhs)
+                    } else {
+                        bcx.ins().icmp(intcc, lhs, rhs)
+                    };
+                    bcx.ins().brif(cmp_res, target, &[], fallthrough, &[]);
+                    self.filled_blocks.insert(bcx.current_block().unwrap());
+                }
+
                 // Do not delegate the check to the verifier, since registered functions can be
                 // changed after the program has been verified.
                 ebpf::CALL => {
@@ -765,6 +889,7 @@ impl CraneliftCompiler {
                 ebpf::EXIT => {
                     let ret = bcx.use_var(self.registers[0]);
                     bcx.ins().return_(&[ret]);
+                    self.filled_blocks.insert(bcx.current_block().unwrap());
                 }
                 _ => unimplemented!("inst: {:?}", insn),
             }
@@ -807,7 +932,7 @@ impl CraneliftCompiler {
     }
 
     fn reg_load(&mut self, bcx: &mut FunctionBuilder, ty: Type, base: Value, offset: i16) -> Value {
-        self.insert_bounds_check(bcx, ty, base, offset);
+        // self.insert_bounds_check(bcx, ty, base, offset);
 
         let mut flags = MemFlags::new();
         flags.set_endianness(Endianness::Little);
@@ -822,7 +947,7 @@ impl CraneliftCompiler {
         offset: i16,
         val: Value,
     ) {
-        self.insert_bounds_check(bcx, ty, base, offset);
+        // self.insert_bounds_check(bcx, ty, base, offset);
 
         let mut flags = MemFlags::new();
         flags.set_endianness(Endianness::Little);
@@ -830,6 +955,31 @@ impl CraneliftCompiler {
         bcx.ins().store(flags, val, base, offset as i32);
     }
 
+    fn prepare_jump_blocks(
+        &mut self,
+        bcx: &mut FunctionBuilder,
+        insn_ptr: usize,
+        insn: &Insn,
+    ) -> (Block, Block) {
+        let target_pc: u32 = (insn_ptr as isize + insn.off as isize + 1)
+            .try_into()
+            .unwrap();
+
+        // This is the fallthrough block
+        let fallthrough_block = *self
+            .insn_blocks
+            .entry((insn_ptr + 1) as u32)
+            .or_insert_with(|| bcx.create_block());
+
+        // Jump Target
+        let target_block = *self
+            .insn_blocks
+            .entry(target_pc)
+            .or_insert_with(|| bcx.create_block());
+
+        (fallthrough_block, target_block)
+    }
+
     /// Inserts a bounds check for a memory access
     ///
     /// This emits a conditional trap if the access is out of bounds for any of the known

+ 822 - 6
tests/cranelift.rs

@@ -469,6 +469,777 @@ test_cranelift!(
     0x0
 );
 
+test_cranelift!(
+    test_cranelift_ja,
+    "
+    mov r0, 1
+    ja +1
+    mov r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jeq_imm,
+    "
+    mov32 r0, 0
+    mov32 r1, 0xa
+    jeq r1, 0xb, +4
+    mov32 r0, 1
+    mov32 r1, 0xb
+    jeq r1, 0xb, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jeq_reg,
+    "
+    mov32 r0, 0
+    mov32 r1, 0xa
+    mov32 r2, 0xb
+    jeq r1, r2, +4
+    mov32 r0, 1
+    mov32 r1, 0xb
+    jeq r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jge_imm,
+    "
+    mov32 r0, 0
+    mov32 r1, 0xa
+    jge r1, 0xb, +4
+    mov32 r0, 1
+    mov32 r1, 0xc
+    jge r1, 0xb, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jle_imm,
+    "
+    mov32 r0, 0
+    mov32 r1, 5
+    jle r1, 4, +1
+    jle r1, 6, +1
+    exit
+    jle r1, 5, +1
+    exit
+    mov32 r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jle_reg,
+    "
+    mov r0, 0
+    mov r1, 5
+    mov r2, 4
+    mov r3, 6
+    jle r1, r2, +2
+    jle r1, r1, +1
+    exit
+    jle r1, r3, +1
+    exit
+    mov r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jgt_imm,
+    "
+    mov32 r0, 0
+    mov32 r1, 5
+    jgt r1, 6, +2
+    jgt r1, 5, +1
+    jgt r1, 4, +1
+    exit
+    mov32 r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jgt_reg,
+    "
+    mov r0, 0
+    mov r1, 5
+    mov r2, 6
+    mov r3, 4
+    jgt r1, r2, +2
+    jgt r1, r1, +1
+    jgt r1, r3, +1
+    exit
+    mov r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jlt_imm,
+    "
+    mov32 r0, 0
+    mov32 r1, 5
+    jlt r1, 4, +2
+    jlt r1, 5, +1
+    jlt r1, 6, +1
+    exit
+    mov32 r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jlt_reg,
+    "
+    mov r0, 0
+    mov r1, 5
+    mov r2, 4
+    mov r3, 6
+    jlt r1, r2, +2
+    jlt r1, r1, +1
+    jlt r1, r3, +1
+    exit
+    mov r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jit_bounce,
+    "
+    mov r0, 1
+    mov r6, r0
+    mov r7, r6
+    mov r8, r7
+    mov r9, r8
+    mov r0, r9
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jne_reg,
+    "
+    mov32 r0, 0
+    mov32 r1, 0xb
+    mov32 r2, 0xb
+    jne r1, r2, +4
+    mov32 r0, 1
+    mov32 r1, 0xa
+    jne r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jset_imm,
+    "
+    mov32 r0, 0
+    mov32 r1, 0x7
+    jset r1, 0x8, +4
+    mov32 r0, 1
+    mov32 r1, 0x9
+    jset r1, 0x8, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jset_reg,
+    "
+    mov32 r0, 0
+    mov32 r1, 0x7
+    mov32 r2, 0x8
+    jset r1, r2, +4
+    mov32 r0, 1
+    mov32 r1, 0x9
+    jset r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsge_imm,
+    "
+    mov32 r0, 0
+    mov r1, -2
+    jsge r1, -1, +5
+    jsge r1, 0, +4
+    mov32 r0, 1
+    mov r1, -1
+    jsge r1, -1, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsge_reg,
+    "
+    mov32 r0, 0
+    mov r1, -2
+    mov r2, -1
+    mov32 r3, 0
+    jsge r1, r2, +5
+    jsge r1, r3, +4
+    mov32 r0, 1
+    mov r1, r2
+    jsge r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsle_imm,
+    "
+    mov32 r0, 0
+    mov r1, -2
+    jsle r1, -3, +1
+    jsle r1, -1, +1
+    exit
+    mov32 r0, 1
+    jsle r1, -2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsle_reg,
+    "
+    mov32 r0, 0
+    mov r1, -1
+    mov r2, -2
+    mov32 r3, 0
+    jsle r1, r2, +1
+    jsle r1, r3, +1
+    exit
+    mov32 r0, 1
+    mov r1, r2
+    jsle r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsgt_imm,
+    "
+    mov32 r0, 0
+    mov r1, -2
+    jsgt r1, -1, +4
+    mov32 r0, 1
+    mov32 r1, 0
+    jsgt r1, -1, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsgt_reg,
+    "
+    mov32 r0, 0
+    mov r1, -2
+    mov r2, -1
+    jsgt r1, r2, +4
+    mov32 r0, 1
+    mov32 r1, 0
+    jsgt r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jslt_imm,
+    "
+    mov32 r0, 0
+    mov r1, -2
+    jslt r1, -3, +2
+    jslt r1, -2, +1
+    jslt r1, -1, +1
+    exit
+    mov32 r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jslt_reg,
+    "
+    mov32 r0, 0
+    mov r1, -2
+    mov r2, -3
+    mov r3, -1
+    jslt r1, r1, +2
+    jslt r1, r2, +1
+    jslt r1, r3, +1
+    exit
+    mov32 r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jeq32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0x0
+    mov32 r1, 0xa
+    jeq32 r1, 0xb, +5
+    mov32 r0, 1
+    mov r1, 0xb
+    or r1, r9
+    jeq32 r1, 0xb, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jeq32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, 0xa
+    mov32 r2, 0xb
+    jeq32 r1, r2, +5
+    mov32 r0, 1
+    mov32 r1, 0xb
+    or r1, r9
+    jeq32 r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jge32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, 0xa
+    jge32 r1, 0xb, +5
+    mov32 r0, 1
+    or r1, r9
+    mov32 r1, 0xc
+    jge32 r1, 0xb, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jge32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, 0xa
+    mov32 r2, 0xb
+    jge32 r1, r2, +5
+    mov32 r0, 1
+    or r1, r9
+    mov32 r1, 0xc
+    jge32 r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jgt32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, 5
+    or r1, r9
+    jgt32 r1, 6, +4
+    jgt32 r1, 5, +3
+    jgt32 r1, 4, +1
+    exit
+    mov32 r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jgt32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov r0, 0
+    mov r1, 5
+    mov32 r1, 5
+    or r1, r9
+    mov r2, 6
+    mov r3, 4
+    jgt32 r1, r2, +4
+    jgt32 r1, r1, +3
+    jgt32 r1, r3, +1
+    exit
+    mov r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jle32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, 5
+    or r1, r9
+    jle32 r1, 4, +5
+    jle32 r1, 6, +1
+    exit
+    jle32 r1, 5, +1
+    exit
+    mov32 r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jle32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov r0, 0
+    mov r1, 5
+    mov r2, 4
+    mov r3, 6
+    or r1, r9
+    jle32 r1, r2, +5
+    jle32 r1, r1, +1
+    exit
+    jle32 r1, r3, +1
+    exit
+    mov r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jlt32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, 5
+    or r1, r9
+    jlt32 r1, 4, +4
+    jlt32 r1, 5, +3
+    jlt32 r1, 6, +1
+    exit
+    mov32 r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jlt32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov r0, 0
+    mov r1, 5
+    mov r2, 4
+    mov r3, 6
+    or r1, r9
+    jlt32 r1, r2, +4
+    jlt32 r1, r1, +3
+    jlt32 r1, r3, +1
+    exit
+    mov r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jne32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, 0xb
+    or r1, r9
+    jne32 r1, 0xb, +4
+    mov32 r0, 1
+    mov32 r1, 0xa
+    or r1, r9
+    jne32 r1, 0xb, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jne32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, 0xb
+    or r1, r9
+    mov32 r2, 0xb
+    jne32 r1, r2, +4
+    mov32 r0, 1
+    mov32 r1, 0xa
+    or r1, r9
+    jne32 r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jset32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, 0x7
+    or r1, r9
+    jset32 r1, 0x8, +4
+    mov32 r0, 1
+    mov32 r1, 0x9
+    jset32 r1, 0x8, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jset32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, 0x7
+    or r1, r9
+    mov32 r2, 0x8
+    jset32 r1, r2, +4
+    mov32 r0, 1
+    mov32 r1, 0x9
+    jset32 r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsge32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, -2
+    or r1, r9
+    jsge32 r1, -1, +5
+    jsge32 r1, 0, +4
+    mov32 r0, 1
+    mov r1, -1
+    jsge32 r1, -1, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsge32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, -2
+    or r1, r9
+    mov r2, -1
+    mov32 r3, 0
+    jsge32 r1, r2, +5
+    jsge32 r1, r3, +4
+    mov32 r0, 1
+    mov r1, r2
+    jsge32 r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsgt32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, -2
+    or r1, r9
+    jsgt32 r1, -1, +4
+    mov32 r0, 1
+    mov32 r1, 0
+    jsgt32 r1, -1, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsgt32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, -2
+    or r1, r9
+    mov r2, -1
+    jsgt32 r1, r2, +4
+    mov32 r0, 1
+    mov32 r1, 0
+    jsgt32 r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsle32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, -2
+    or r1, r9
+    jsle32 r1, -3, +5
+    jsle32 r1, -1, +1
+    exit
+    mov32 r0, 1
+    jsle32 r1, -2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jsle32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, -2
+    or r1, r9
+    mov r2, -3
+    mov32 r3, 0
+    jsle32 r1, r2, +6
+    jsle32 r1, r3, +1
+    exit
+    mov32 r0, 1
+    mov r1, r2
+    jsle32 r1, r2, +1
+    mov32 r0, 2
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jslt32_imm,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, -2
+    or r1, r9
+    jslt32 r1, -3, +4
+    jslt32 r1, -2, +3
+    jslt32 r1, -1, +1
+    exit
+    mov32 r0, 1
+    exit
+    ",
+    0x1
+);
+
+test_cranelift!(
+    test_cranelift_jslt32_reg,
+    "
+    mov r9, 1
+    lsh r9, 32
+    mov32 r0, 0
+    mov32 r1, -2
+    or r1, r9
+    mov r2, -3
+    mov r3, -1
+    jslt32 r1, r1, +4
+    jslt32 r1, r2, +3
+    jslt32 r1, r3, +1
+    exit
+    mov32 r0, 1
+    exit
+    ",
+    0x1
+);
+
 test_cranelift!(
     test_cranelift_lddw,
     "
@@ -880,6 +1651,29 @@ test_cranelift!(
     0xfffffffe
 );
 
+test_cranelift!(
+    test_cranelift_prime,
+    "
+    mov r1, 67
+    mov r0, 0x1
+    mov r2, 0x2
+    jgt r1, 0x2, +4
+    ja +10
+    add r2, 0x1
+    mov r0, 0x1
+    jge r2, r1, +7
+    mov r3, r1
+    div r3, r2
+    mul r3, r2
+    mov r4, r1
+    sub r4, r3
+    mov r0, 0x0
+    jne r4, 0x0, -10
+    exit
+    ",
+    1
+);
+
 test_cranelift!(
     test_cranelift_rhs32,
     "
@@ -1154,6 +1948,34 @@ test_cranelift!(
     0x44332211
 );
 
+test_cranelift!(
+    test_cranelift_subnet,
+    "
+    mov r2, 0xe
+    ldxh r3, [r1+12]
+    jne r3, 0x81, +2
+    mov r2, 0x12
+    ldxh r3, [r1+16]
+    and r3, 0xffff
+    jne r3, 0x8, +5
+    add r1, r2
+    mov r0, 0x1
+    ldxw r1, [r1+16]
+    and r1, 0xffffff
+    jeq r1, 0x1a8c0, +1
+    mov r0, 0x0
+    exit
+    ",
+    [
+        0x00, 0x00, 0xc0, 0x9f, 0xa0, 0x97, 0x00, 0xa0, 0xcc, 0x3b, 0xbf, 0xfa, 0x08, 0x00, 0x45,
+        0x10, 0x00, 0x3c, 0x46, 0x3c, 0x40, 0x00, 0x40, 0x06, 0x73, 0x1c, 0xc0, 0xa8, 0x01, 0x02,
+        0xc0, 0xa8, 0x01, 0x01, 0x06, 0x0e, 0x00, 0x17, 0x99, 0xc5, 0xa0, 0xec, 0x00, 0x00, 0x00,
+        0x00, 0xa0, 0x02, 0x7d, 0x78, 0xe0, 0xa3, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02,
+        0x08, 0x0a, 0x00, 0x9c, 0x27, 0x24, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x00,
+    ],
+    0x1
+);
+
 const PROG_TCP_PORT_80: [u8; 152] = [
     0x71, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x13, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x67, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1168,7 +1990,6 @@ const PROG_TCP_PORT_80: [u8; 152] = [
 ];
 
 #[test]
-#[ignore]
 fn test_cranelift_tcp_port80_match() {
     let mem = &mut [
         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
@@ -1185,7 +2006,6 @@ fn test_cranelift_tcp_port80_match() {
 }
 
 #[test]
-#[ignore]
 fn test_cranelift_tcp_port80_nomatch() {
     let mem = &mut [
         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
@@ -1202,7 +2022,6 @@ fn test_cranelift_tcp_port80_nomatch() {
 }
 
 #[test]
-#[ignore]
 fn test_cranelift_tcp_port80_nomatch_ethertype() {
     let mem = &mut [
         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x01, 0x45,
@@ -1219,7 +2038,6 @@ fn test_cranelift_tcp_port80_nomatch_ethertype() {
 }
 
 #[test]
-#[ignore]
 fn test_cranelift_tcp_port80_nomatch_proto() {
     let mem = &mut [
         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x08, 0x00, 0x45,
@@ -1236,7 +2054,6 @@ fn test_cranelift_tcp_port80_nomatch_proto() {
 }
 
 #[test]
-#[ignore]
 fn test_cranelift_tcp_sack_match() {
     let mut mem = TCP_SACK_MATCH.to_vec();
     let prog = assemble(TCP_SACK_ASM).unwrap();
@@ -1245,7 +2062,6 @@ fn test_cranelift_tcp_sack_match() {
 }
 
 #[test]
-#[ignore]
 fn test_cranelift_tcp_sack_nomatch() {
     let mut mem = TCP_SACK_NOMATCH.to_vec();
     let prog = assemble(TCP_SACK_ASM).unwrap();