unsafe fn gen_probe_loop(
        &mut self,
        builder: LLVMBuilderRef,
        slot_array: LLVMValueRef,
        capacity: LLVMValueRef,
        hash: LLVMValueRef,
        blocks: (
            LLVMBasicBlockRef,
            LLVMBasicBlockRef,
            LLVMBasicBlockRef,
            LLVMBasicBlockRef,
        ),
        key: Option<LLVMValueRef>,
    ) -> LLVMValueRef {
        // Generated Code:
        //
        //   start = probe_index(hash, cap);
        //   jump top
        // top:
        //   i = phi [ start, top ] [ i2, check_key ]
        //   s = getslot(i)
        //   br s.filled ? check_key : return
        // check_key:
        //   tmp = i + 1
        //   i2 = probe_index(tmp)
        //   br s.key == key ? return : top | br top, depending on `check_key`
        // return:
        //   return s
        // }

        let (start_block, top_block, check_block, end_block) = blocks;

        let hash = LLVMBuildZExt(builder, hash, self.i64_type(), c_str!(""));
        let start_index = self.probe_index(builder, hash, capacity);
        LLVMBuildBr(builder, top_block);

        LLVMPositionBuilderAtEnd(builder, top_block);
        let index = LLVMBuildPhi(builder, self.i64_type(), c_str!(""));
        let slot = self.slot_at_index(builder, slot_array, index);

        let filled = self.slot_ty.filled(builder, slot);
        LLVMBuildCondBr(builder, filled, check_block, end_block);

        LLVMPositionBuilderAtEnd(builder, check_block);
        let update_index = LLVMBuildNSWAdd(builder, index, self.i64(1), c_str!(""));
        let update_index = self.probe_index(builder, update_index, capacity);
        if let Some(key) = key {
            let slot_key = self.slot_ty.key(builder, slot);
            let keys_eq = self.compare_keys(builder, slot_key, key);
            LLVMBuildCondBr(builder, keys_eq, end_block, top_block);
        } else {
            LLVMBuildBr(builder, top_block);
        }

        let mut blocks = [start_block, check_block];
        let mut values = [start_index, update_index];
        LLVMAddIncoming(
            index,
            values.as_mut_ptr(),
            blocks.as_mut_ptr(),
            values.len() as u32,
        );

        LLVMPositionBuilderAtEnd(builder, end_block);
        slot
    }
Generate a probe loop. The probe loop uses the provided hash to search the hash table using
linear probing. If a key is provided, either the matching slot or an empty slot is
returned. If a key is not provided, the first empty slot starting at the hash's index is
returned.

This method takes four basic blocks for loop control flow: the basic block the builder is
currently positioned in, a top block, a check block to check for the key, and an exit
block.

When the function returns, the builder is guaranteed to be positioned at the beginning of the
exit block. The function returns the LLVMValue representing the slot found with the probe.
weld/src/codegen/llvm2/dict.rs