unsafe fn gen_entry(&mut self, program: &SirProgram) -> WeldResult<()> {
        use crate::ast::Type::Struct;

        let input_type = WeldInputArgs::llvm_type(self.context);
        let output_type = WeldOutputArgs::llvm_type(self.context);

        let name = CString::new(self.conf.llvm.run_func_name.as_bytes()).unwrap();
        let func_ty = LLVMFunctionType(self.i64_type(), [self.i64_type()].as_mut_ptr(), 1, 0);
        let function = LLVMAddFunction(self.module, name.as_ptr(), func_ty);

        // Add the default attributes to all functions.
        llvm_exts::LLVMExtAddDefaultAttrs(self.context(), function);

        // This function is the global entry point into the program, so we must give it externally
        // visible linkage.
        LLVMSetLinkage(function, LLVMLinkage::LLVMExternalLinkage);

        let builder = LLVMCreateBuilderInContext(self.context);
        let entry_block = LLVMAppendBasicBlockInContext(self.context, function, c_str!(""));
        let init_run_block = LLVMAppendBasicBlockInContext(self.context, function, c_str!(""));
        let get_arg_block = LLVMAppendBasicBlockInContext(self.context, function, c_str!(""));

        LLVMPositionBuilderAtEnd(builder, entry_block);
        let argument = LLVMGetParam(function, 0);
        let pointer = LLVMBuildIntToPtr(
            builder,
            argument,
            LLVMPointerType(input_type, 0),
            c_str!(""),
        );

        // Check whether we already have an existing run.
        let run_pointer =
            LLVMBuildStructGEP(builder, pointer, WeldInputArgs::run_index(), c_str!(""));
        let run_pointer = self.load(builder, run_pointer)?;
        let run_arg = LLVMBuildIntToPtr(builder, run_pointer, self.run_handle_type(), c_str!(""));
        let null = LLVMConstNull(self.run_handle_type());
        let null_check = LLVMBuildICmp(
            builder,
            llvm_sys::LLVMIntPredicate::LLVMIntEQ,
            run_arg,
            null,
            c_str!(""),
        );
        LLVMBuildCondBr(builder, null_check, init_run_block, get_arg_block);

        LLVMPositionBuilderAtEnd(builder, init_run_block);
        let nworkers_pointer = LLVMBuildStructGEP(
            builder,
            pointer,
            WeldInputArgs::nworkers_index(),
            c_str!("nworkers"),
        );
        let nworkers = self.load(builder, nworkers_pointer)?;
        let memlimit_pointer = LLVMBuildStructGEP(
            builder,
            pointer,
            WeldInputArgs::memlimit_index(),
            c_str!("memlimit"),
        );
        let memlimit = self.load(builder, memlimit_pointer)?;
        let run_new = self
            .intrinsics
            .call_weld_run_init(builder, nworkers, memlimit, None);
        LLVMBuildBr(builder, get_arg_block);

        LLVMPositionBuilderAtEnd(builder, get_arg_block);
        let run = LLVMBuildPhi(builder, self.run_handle_type(), c_str!(""));
        let mut blocks = [entry_block, init_run_block];
        let mut values = [run_arg, run_new];
        LLVMAddIncoming(
            run,
            values.as_mut_ptr(),
            blocks.as_mut_ptr(),
            blocks.len() as u32,
        );

        let arg_pointer = LLVMBuildStructGEP(
            builder,
            pointer,
            WeldInputArgs::input_index(),
            c_str!("argptr"),
        );
        // Still a pointer, but now as an integer.
        let arg_pointer = self.load(builder, arg_pointer)?;
        // The first SIR function is the entry point.
        let arg_ty = &Struct(program.top_params.iter().map(|p| p.ty.clone()).collect());
        let llvm_arg_ty = self.llvm_type(arg_ty)?;
        let arg_struct_pointer = LLVMBuildIntToPtr(
            builder,
            arg_pointer,
            LLVMPointerType(llvm_arg_ty, 0),
            c_str!("arg"),
        );

        // Function arguments are sorted by symbol name - arrange the inputs in the proper order.
        let mut params: Vec<(&Symbol, u32)> = program
            .top_params
            .iter()
            .enumerate()
            .map(|(i, p)| (&p.name, i as u32))
            .collect();

        params.sort();

        let mut func_args = vec![];
        for (_, i) in params.iter() {
            let pointer = LLVMBuildStructGEP(builder, arg_struct_pointer, *i, c_str!("param"));
            let value = self.load(builder, pointer)?;
            func_args.push(value);
        }
        // Push the run handle.
        func_args.push(run);

        // Run the Weld program.
        let entry_function = self.functions[&program.funcs[0].id];
        let inst = LLVMBuildCall(
            builder,
            entry_function,
            func_args.as_mut_ptr(),
            func_args.len() as u32,
            c_str!(""),
        );
        LLVMSetInstructionCallConv(inst, SIR_FUNC_CALL_CONV);

        let result = self.intrinsics.call_weld_run_get_result(builder, run, None);
        let result = LLVMBuildPtrToInt(builder, result, self.i64_type(), c_str!("result"));
        let errno = self
            .intrinsics
            .call_weld_run_get_errno(builder, run, Some(c_str!("errno")));
        let run_int = LLVMBuildPtrToInt(builder, run, self.i64_type(), c_str!("run"));

        let mut output = LLVMGetUndef(output_type);
        output = LLVMBuildInsertValue(
            builder,
            output,
            result,
            WeldOutputArgs::output_index(),
            c_str!(""),
        );
        output = LLVMBuildInsertValue(
            builder,
            output,
            run_int,
            WeldOutputArgs::run_index(),
            c_str!(""),
        );
        output = LLVMBuildInsertValue(
            builder,
            output,
            errno,
            WeldOutputArgs::errno_index(),
            c_str!(""),
        );

        let return_size = self.size_of(output_type);
        let return_pointer = self
            .intrinsics
            .call_weld_run_malloc(builder, run, return_size, None);
        let return_pointer = LLVMBuildBitCast(
            builder,
            return_pointer,
            LLVMPointerType(output_type, 0),
            c_str!(""),
        );

        LLVMBuildStore(builder, output, return_pointer);
        let return_value = LLVMBuildPtrToInt(builder, return_pointer, self.i64_type(), c_str!(""));
        LLVMBuildRet(builder, return_value);

        LLVMDisposeBuilder(builder);
        Ok(())
    }
Generates the entry point to the Weld program.

The entry function takes an `i64` and returns an `i64`. Both represent pointers that
point to a `WeldInputArgs` and `WeldOutputArgs` respectively.
weld/src/codegen/llvm2/mod.rs