-- | A helper function for genCallWithOverflow that handles generating the call
-- to the LLVM intrinsic and extracting the result from the struct to LlvmVars.
genCallExtract
    :: ForeignTarget           -- ^ PrimOp
    -> Width                   -- ^ Width of the operands.
    -> (CmmActual, CmmActual)  -- ^ Actual arguments.
    -> (LlvmType, LlvmType)    -- ^ LLVM types of the returned struct.
    -> LlvmM (LlvmVar, LlvmVar, StmtData)
genCallExtract target@(PrimTarget op) w (argA, argB) (llvmTypeA, llvmTypeB) = do
    let width = widthToLlvmInt w
        argTy = [width, width]
        retTy = LMStructU [llvmTypeA, llvmTypeB]

    -- Process the arguments.
    let args_hints = zip [argA, argB] (snd $ foreignTargetHints target)
    (argsV1, args1, top1) <- arg_vars args_hints ([], nilOL, [])
    (argsV2, args2) <- castVars $ zip argsV1 argTy

    -- Get the function and make the call.
    fname <- cmmPrimOpFunctions op
    (fptr, _, top2) <- getInstrinct fname retTy argTy
    -- We use StdCall for primops. See also the last case of genCall.
    (retV, call) <- doExpr retTy $ Call StdCall fptr argsV2 []

    -- This will result in a two element struct, we need to use "extractvalue"
    -- to get them out of it.
    (res1, ext1) <- doExpr llvmTypeA (ExtractV retV 0)
    (res2, ext2) <- doExpr llvmTypeB (ExtractV retV 1)

    let stmts = args1 `appOL` args2 `snocOL` call `snocOL` ext1 `snocOL` ext2
        tops = top1 ++ top2
    return (res1, res2, (stmts, tops))
genCallExtract
    :: ForeignTarget           -- ^ PrimOp
    -> Width                   -- ^ Width of the operands.
    -> (CmmActual, CmmActual)  -- ^ Actual arguments.
    -> (LlvmType, LlvmType)    -- ^ LLVM types of the returned struct.
    -> LlvmM (LlvmVar, LlvmVar, StmtData)
genCallExtract target@(PrimTarget op) w (argA, argB) (llvmTypeA, llvmTypeB) = do
    let width = widthToLlvmInt w
        argTy = [width, width]
        retTy = LMStructU [llvmTypeA, llvmTypeB]

    -- Process the arguments.
    let args_hints = zip [argA, argB] (snd $ foreignTargetHints target)
    (argsV1, args1, top1) <- arg_vars args_hints ([], nilOL, [])
    (argsV2, args2) <- castVars $ zip argsV1 argTy

    -- Get the function and make the call.
    fname <- cmmPrimOpFunctions op
    (fptr, _, top2) <- getInstrinct fname retTy argTy
    -- We use StdCall for primops. See also the last case of genCall.
    (retV, call) <- doExpr retTy $ Call StdCall fptr argsV2 []

    -- This will result in a two element struct, we need to use "extractvalue"
    -- to get them out of it.
    (res1, ext1) <- doExpr llvmTypeA (ExtractV retV 0)
    (res2, ext2) <- doExpr llvmTypeB (ExtractV retV 1)

    let stmts = args1 `appOL` args2 `snocOL` call `snocOL` ext1 `snocOL` ext2
        tops = top1 ++ top2
    return (res1, res2, (stmts, tops))
genCallExtract target@(PrimTarget op) w (argA, argB) (llvmTypeA, llvmTypeB) = do
    let width = widthToLlvmInt w
        argTy = [width, width]
        retTy = LMStructU [llvmTypeA, llvmTypeB]

    -- Process the arguments.
    let args_hints = zip [argA, argB] (snd $ foreignTargetHints target)
    (argsV1, args1, top1) <- arg_vars args_hints ([], nilOL, [])
    (argsV2, args2) <- castVars $ zip argsV1 argTy

    -- Get the function and make the call.
    fname <- cmmPrimOpFunctions op
    (fptr, _, top2) <- getInstrinct fname retTy argTy
    -- We use StdCall for primops. See also the last case of genCall.
    (retV, call) <- doExpr retTy $ Call StdCall fptr argsV2 []

    -- This will result in a two element struct, we need to use "extractvalue"
    -- to get them out of it.
    (res1, ext1) <- doExpr llvmTypeA (ExtractV retV 0)
    (res2, ext2) <- doExpr llvmTypeB (ExtractV retV 1)

    let stmts = args1 `appOL` args2 `snocOL` call `snocOL` ext1 `snocOL` ext2
        tops = top1 ++ top2
    return (res1, res2, (stmts, tops))