unsafe fn gen_resize(
        &mut self,
        builder: LLVMBuilderRef,
        intrinsics: &mut Intrinsics,
        dict: LLVMValueRef,
        run: LLVMValueRef,
    ) -> LLVMValueRef {
        if self.resize.is_none() {
            let mut arg_tys = [self.dict_ty, self.run_handle_type()];
            let ret_ty = self.i1_type();
            let name = format!("{}.resize", self.name);

            let (function, builder, _) = self.define_function(ret_ty, &mut arg_tys, name);

            LLVMExtAddAttrsOnParameter(self.context, function, &[NoAlias], 0);
            LLVMExtAddAttrsOnParameter(self.context, function, &[NoAlias, NoCapture, NonNull], 1);

            let dict = LLVMGetParam(function, 0);
            let run = LLVMGetParam(function, 1);

            // Type of the alloca is same as `self.dict_ty`
            let new_dictionary = LLVMBuildAlloca(builder, self.dict_inner_ty, c_str!(""));

            let old_size = self.size(builder, dict);
            let old_capacity = self.capacity(builder, dict);
            let old_slot_array = self.slot_array(builder, dict);

            // Resize
            let resize_block = LLVMAppendBasicBlockInContext(self.context(), function, c_str!(""));

            // Copy loop.
            let copy_top_block =
                LLVMAppendBasicBlockInContext(self.context(), function, c_str!(""));
            let copy_cpy_block =
                LLVMAppendBasicBlockInContext(self.context(), function, c_str!(""));

            // Probe for empty slot.
            let probe_top_block =
                LLVMAppendBasicBlockInContext(self.context(), function, c_str!(""));
            let probe_chk_block =
                LLVMAppendBasicBlockInContext(self.context(), function, c_str!(""));
            let probe_bot_block =
                LLVMAppendBasicBlockInContext(self.context(), function, c_str!(""));

            // End of copy loop.
            let copy_bot_block =
                LLVMAppendBasicBlockInContext(self.context(), function, c_str!(""));
            let copy_fin_block =
                LLVMAppendBasicBlockInContext(self.context(), function, c_str!(""));

            // Exit
            let exit_block = LLVMAppendBasicBlockInContext(self.context(), function, c_str!(""));

            let should_resize = self.should_resize(builder, old_size, old_capacity);
            LLVMBuildCondBr(builder, should_resize, resize_block, exit_block);

            LLVMPositionBuilderAtEnd(builder, resize_block);

            // Resize the dictionary -- double it capacity.
            let new_capacity = LLVMBuildNSWMul(builder, old_capacity, self.i64(2), c_str!(""));
            let new_dictionary_inner =
                self.gen_new_dict_with_capacity(builder, intrinsics, new_capacity, run);
            LLVMBuildStore(builder, new_dictionary_inner, new_dictionary);

            let new_slot_array = self.slot_array(builder, new_dictionary);
            LLVMBuildBr(builder, copy_top_block);

            // Loop to copy slots:
            //
            // top:
            //  i = phi [ resizeblock, 0 ], [ bottom, i2 ]
            //  slot = slotatindex(i)
            //  br slot.filled ? copyblock : bottom
            // cpy:
            //  newslot = getempty(new_dictionary, slot.hash) XXX geherated with gen_probe_loop
            //  memcpy(slot, newslot, sizeof(slot))
            //  br bot
            // bot:
            //  i2 = i + 1
            //  br i2 == capacity : fin ? top
            // fin:
            //  free(dict.slot_array)
            //  memcpy(dict, new_dictionary, sizeof(dict))
            //  br exit
            // exit:
            //  ...

            // Top Block.
            LLVMPositionBuilderAtEnd(builder, copy_top_block);
            let index = LLVMBuildPhi(builder, self.i64_type(), c_str!(""));
            let old_slot = self.slot_at_index(builder, old_slot_array, index);
            let filled = self.slot_ty.filled(builder, old_slot);
            LLVMBuildCondBr(builder, filled, copy_cpy_block, copy_bot_block);

            // Copy Block.
            LLVMPositionBuilderAtEnd(builder, copy_cpy_block);
            let hash_pointer = self.slot_ty.hash(builder, old_slot);
            let old_slot_hash = self.load(builder, hash_pointer).unwrap();
            let new_slot = self.gen_probe_loop(
                builder,
                new_slot_array,
                new_capacity,
                old_slot_hash,
                (
                    copy_cpy_block,
                    probe_top_block,
                    probe_chk_block,
                    probe_bot_block,
                ),
                None,
            );

            let new_slot_bytes =
                LLVMBuildBitCast(builder, new_slot, self.void_pointer_type(), c_str!(""));
            let old_slot_bytes =
                LLVMBuildBitCast(builder, old_slot, self.void_pointer_type(), c_str!(""));
            let _ = intrinsics.call_memcpy(
                builder,
                new_slot_bytes,
                old_slot_bytes,
                self.size_of(self.slot_ty.slot_ty),
            );

            // Update the size.
            let size_pointer = LLVMBuildStructGEP(builder, new_dictionary, SIZE_INDEX, c_str!(""));
            let size = self.load(builder, size_pointer).unwrap();
            let new_size = LLVMBuildNSWAdd(builder, size, self.i64(1), c_str!(""));
            LLVMBuildStore(builder, new_size, size_pointer);
            LLVMBuildBr(builder, copy_bot_block);

            // Bottom Block.
            LLVMPositionBuilderAtEnd(builder, copy_bot_block);
            let update_index = LLVMBuildNSWAdd(builder, index, self.i64(1), c_str!(""));
            let finished =
                LLVMBuildICmp(builder, LLVMIntEQ, update_index, old_capacity, c_str!(""));
            LLVMBuildCondBr(builder, finished, copy_fin_block, copy_top_block);

            // Set the PHI value for the index.
            let mut blocks = [resize_block, copy_bot_block];
            let mut values = [self.i64(0), update_index];
            LLVMAddIncoming(
                index,
                values.as_mut_ptr(),
                blocks.as_mut_ptr(),
                values.len() as u32,
            );

            // Finish Block.
            LLVMPositionBuilderAtEnd(builder, copy_fin_block);
            // 1. Free Old Dictionary buffer.
            let old_slotarray_bytes = LLVMBuildBitCast(
                builder,
                old_slot_array,
                self.void_pointer_type(),
                c_str!(""),
            );
            let _ = intrinsics.call_weld_run_free(builder, run, old_slotarray_bytes);

            // 2. Move the new dictionary state to the old dictionary pointer.
            let new_dict_bytes = LLVMBuildBitCast(
                builder,
                new_dictionary,
                self.void_pointer_type(),
                c_str!(""),
            );
            let old_dict_bytes =
                LLVMBuildBitCast(builder, dict, self.void_pointer_type(), c_str!(""));
            let _ = intrinsics.call_memcpy(
                builder,
                old_dict_bytes,
                new_dict_bytes,
                self.size_of(self.dict_inner_ty),
            );
            LLVMBuildBr(builder, exit_block);

            // Finished at last! Hallelujah. Who would've thought resizing a dictionary is so hard.
            LLVMPositionBuilderAtEnd(builder, exit_block);
            LLVMBuildRet(builder, should_resize);

            self.resize = Some(function);
            LLVMDisposeBuilder(builder);
        }

        let mut args = [dict, run];
        LLVMBuildCall(
            builder,
            self.resize.unwrap(),
            args.as_mut_ptr(),
            args.len() as u32,
            c_str!(""),
        )
    }
Resize the dictionary if necessary.

Returns an `i1` indicating whether a resize occurred. If the dictionary was resized, slots
acquired from the dictionary should be re-acquired.
weld/src/codegen/llvm2/dict.rs