unsafe fn gen_terminator(
        &mut self,
        context: &mut FunctionContext<'_>,
        bb: &BasicBlock,
        loop_terminator: Option<(LLVMBasicBlockRef, LLVMValueRef)>,
    ) -> WeldResult<()> {
        if self.conf.trace_run {
            self.gen_print(
                context.builder,
                context.get_run(),
                CString::new(format!("{}", bb.terminator)).unwrap(),
            )?;
        }

        use crate::sir::Terminator::*;
        match bb.terminator {
            ProgramReturn(ref sym) => {
                let value = self.load(context.builder, context.get_value(sym)?)?;
                let run = context.get_run();
                let ty = LLVMTypeOf(value);
                let size = self.size_of(ty);
                let bytes = self
                    .intrinsics
                    .call_weld_run_malloc(context.builder, run, size, None);
                let pointer =
                    LLVMBuildBitCast(context.builder, bytes, LLVMPointerType(ty, 0), c_str!(""));
                LLVMBuildStore(context.builder, value, pointer);
                let _ = self
                    .intrinsics
                    .call_weld_run_set_result(context.builder, run, bytes, None);
                LLVMBuildRet(context.builder, value);
            }
            Branch {
                ref cond,
                ref on_true,
                ref on_false,
            } => {
                let cond = self.load(context.builder, context.get_value(cond)?)?;
                let cond = self.bool_to_i1(context.builder, cond);
                let _ = LLVMBuildCondBr(
                    context.builder,
                    cond,
                    context.get_block(*on_true)?,
                    context.get_block(*on_false)?,
                );
            }
            JumpBlock(ref id) => {
                LLVMBuildBr(context.builder, context.get_block(*id)?);
            }
            EndFunction(ref sym) => {
                if let Some((jumpto, loop_builder)) = loop_terminator {
                    let pointer = context.get_value(sym)?;
                    let updated_builder = self.load(context.builder, pointer)?;
                    LLVMBuildStore(context.builder, updated_builder, loop_builder);
                    LLVMBuildBr(context.builder, jumpto);
                } else {
                    let pointer = context.get_value(sym)?;
                    let return_value = self.load(context.builder, pointer)?;
                    LLVMBuildRet(context.builder, return_value);
                }
            }
            Crash => {
                let errno = self.i64(WeldRuntimeErrno::Unknown as i64);
                self.intrinsics.call_weld_run_set_errno(
                    context.builder,
                    context.get_run(),
                    errno,
                    None,
                );
                LLVMBuildUnreachable(context.builder);
            }
        };
        Ok(())
    }
Generate code for a terminator within an SIR basic block.

`loop_terminator` is an optional tuple that is present only when generating loop body
functions. The first argument is a basic block to jump to to continue looping instead of
returning from a function. The second argument is a value representing the loop's builder
argument pointer. In cases where the loop body function returns, this function stores the
resulting builder into this pointer. The function is guaranteed to return a builder (since
For loop functions must return builders derived from their input builder).

This function does not make any assumptions about which *LLVM basic block* the
builder is positioned in, as long as the builder is logically within the passed SIR basic
block.
weld/src/codegen/llvm2/mod.rs