//===-- WebAssemblyCallLowering.cpp - Call lowering for GlobalISel -*- C++ -*-//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements the lowering of LLVM calls to machine code calls for
/// GlobalISel.
///
//===----------------------------------------------------------------------===//

#include "WebAssemblyCallLowering.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "Utils/WebAssemblyTypeUtilities.h"
#include "WebAssemblyISelLowering.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblyRegisterInfo.h"
#include "WebAssemblySubtarget.h"
#include "WebAssemblyUtilities.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
#include "llvm/CodeGen/LowLevelTypeUtils.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/RegisterBankInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/ErrorHandling.h"

#define DEBUG_TYPE "wasm-call-lowering"

using namespace llvm;

// Test whether the given calling convention is supported.
static bool callingConvSupported(CallingConv::ID CallConv) {
  // We currently support the language-independent target-independent
  // conventions. We don't yet have a way to annotate calls with properties like
  // "cold", and we don't have any call-clobbered registers, so these are mostly
  // all handled the same.
  return CallConv == CallingConv::C || CallConv == CallingConv::Fast ||
         CallConv == CallingConv::Cold ||
         CallConv == CallingConv::PreserveMost ||
         CallConv == CallingConv::PreserveAll ||
         CallConv == CallingConv::CXX_FAST_TLS ||
         CallConv == CallingConv::WASM_EmscriptenInvoke ||
         CallConv == CallingConv::Swift;
}

static unsigned extendOpFromFlags(ISD::ArgFlagsTy Flags) {
  if (Flags.isSExt())
    return TargetOpcode::G_SEXT;
  if (Flags.isZExt())
    return TargetOpcode::G_ZEXT;
  return TargetOpcode::G_ANYEXT;
}

// GlobalISel doesn't handle reference types. We bail out of GlobalISel for
// functions passing/returning references and fall back to SDAG.
static bool typeContainsReference(const Type *Ty) {
  if (WebAssembly::isWebAssemblyReferenceType(Ty))
    return true;
  if (const auto *ArrTy = dyn_cast<ArrayType>(Ty))
    return typeContainsReference(ArrTy->getElementType());
  if (const auto *StructTy = dyn_cast<StructType>(Ty))
    return any_of(StructTy->elements(), [](const Type *ElemTy) {
      return typeContainsReference(ElemTy);
    });
  return false;
}

WebAssemblyCallLowering::WebAssemblyCallLowering(
    const WebAssemblyTargetLowering &TLI)
    : CallLowering(&TLI) {}

bool WebAssemblyCallLowering::canLowerReturn(MachineFunction &MF,
                                             CallingConv::ID CallConv,
                                             SmallVectorImpl<BaseArgInfo> &Outs,
                                             bool IsVarArg) const {
  return WebAssembly::canLowerReturn(Outs.size(),
                                     &MF.getSubtarget<WebAssemblySubtarget>());
}

bool WebAssemblyCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
                                          const Value *Val,
                                          ArrayRef<Register> VRegs,
                                          FunctionLoweringInfo &FLI,
                                          Register SwiftErrorVReg) const {
  MachineFunction &MF = MIRBuilder.getMF();
  const Function &F = MF.getFunction();
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const WebAssemblyTargetLowering &TLI = *getTLI<WebAssemblyTargetLowering>();
  const DataLayout &DL = F.getDataLayout();

  if (Val && typeContainsReference(Val->getType()))
    return false;

  MachineInstrBuilder MIB = MIRBuilder.buildInstrNoInsert(WebAssembly::RETURN);

  assert(((Val && !VRegs.empty()) || (!Val && VRegs.empty())) &&
         "Return value without a vreg or vice versa");

  if (Val) {
    LLVMContext &Ctx = Val->getType()->getContext();

    if (!FLI.CanLowerReturn) {
      insertSRetStores(MIRBuilder, Val->getType(), VRegs, FLI.DemoteRegister);
    } else {
      SmallVector<EVT, 4> SplitEVTs;
      ComputeValueVTs(TLI, DL, Val->getType(), SplitEVTs);
      assert(VRegs.size() == SplitEVTs.size() &&
             "For each split Type there should be exactly one VReg.");

      SmallVector<ArgInfo, 8> SplitRets;
      CallingConv::ID CallConv = F.getCallingConv();

      unsigned RetIdx = 0;
      for (EVT SplitEVT : SplitEVTs) {
        Register CurVReg = VRegs[RetIdx];
        ArgInfo CurRetInfo = ArgInfo{CurVReg, SplitEVT.getTypeForEVT(Ctx), 0};
        setArgFlags(CurRetInfo, AttributeList::ReturnIndex, DL, F);

        splitToValueTypes(CurRetInfo, SplitRets, DL, CallConv);
        ++RetIdx;
      }

      for (ArgInfo &Ret : SplitRets) {
        const EVT OrigVT = TLI.getValueType(DL, Ret.Ty);
        const MVT NewVT =
            TLI.getRegisterTypeForCallingConv(Ctx, CallConv, OrigVT);
        const LLT OrigLLT =
            getLLTForType(*OrigVT.getTypeForEVT(F.getContext()), DL);
        const LLT NewLLT = getLLTForMVT(NewVT);

        const TargetRegisterClass &NewRegClass = *TLI.getRegClassFor(NewVT);

        // If we need to split the type over multiple regs, check it's a
        // scenario we currently support.
        const unsigned NumParts =
            TLI.getNumRegistersForCallingConv(Ctx, CallConv, OrigVT);

        const ISD::ArgFlagsTy OrigFlags = Ret.Flags[0];
        Ret.Flags.clear();

        for (unsigned Part = 0; Part < NumParts; ++Part) {
          ISD::ArgFlagsTy Flags = OrigFlags;

          if (Part == 0) {
            Flags.setSplit();
          } else {
            Flags.setOrigAlign(Align(1));
            if (Part == NumParts - 1)
              Flags.setSplitEnd();
          }

          Ret.Flags.push_back(Flags);
        }

        Ret.OrigRegs.assign(Ret.Regs.begin(), Ret.Regs.end());
        if (NumParts != 1 || OrigLLT != NewLLT) {
          // If we can't directly assign the register, we need one or more
          // intermediate values.
          Ret.Regs.resize(NumParts);

          // For each split register, create and assign a vreg that will store
          // the incoming component of the larger value. These will later be
          // merged to form the final vreg.
          for (unsigned Part = 0; Part < NumParts; ++Part) {
            Register NewReg = MRI.createVirtualRegister(&NewRegClass);
            MRI.setType(NewReg, NewLLT);
            MIB.addUse(NewReg);
            Ret.Regs[Part] = NewReg;
          }

          buildCopyToRegs(MIRBuilder, Ret.Regs, Ret.OrigRegs[0], OrigLLT,
                          NewLLT, extendOpFromFlags(Ret.Flags[0]));
        } else {
          MIB.addUse(Ret.Regs[0]);
        }
      }
    }
  }

  if (SwiftErrorVReg) {
    reportFatalInternalError(
        "Wasm does not `supportSwiftError`, yet SwiftErrorVReg is "
        "improperly valid.");
  }

  MIRBuilder.insertInstr(MIB);
  return true;
}

static unsigned getWasmArgumentOpcode(MVT ArgType) {
  switch (ArgType.SimpleTy) {
  case MVT::i32:
    return WebAssembly::ARGUMENT_i32;
  case MVT::i64:
    return WebAssembly::ARGUMENT_i64;
  case MVT::f32:
    return WebAssembly::ARGUMENT_f32;
  case MVT::f64:
    return WebAssembly::ARGUMENT_f64;

  case MVT::funcref:
    return WebAssembly::ARGUMENT_funcref;
  case MVT::externref:
    return WebAssembly::ARGUMENT_externref;
  case MVT::exnref:
    return WebAssembly::ARGUMENT_exnref;

  case MVT::v16i8:
    return WebAssembly::ARGUMENT_v16i8;
  case MVT::v8i16:
    return WebAssembly::ARGUMENT_v8i16;
  case MVT::v4i32:
    return WebAssembly::ARGUMENT_v4i32;
  case MVT::v2i64:
    return WebAssembly::ARGUMENT_v2i64;
  case MVT::v8f16:
    return WebAssembly::ARGUMENT_v8f16;
  case MVT::v4f32:
    return WebAssembly::ARGUMENT_v4f32;
  case MVT::v2f64:
    return WebAssembly::ARGUMENT_v2f64;
  default:
    break;
  }
  llvm_unreachable("Found unexpected type for Wasm argument");
}

static Register buildWasmArgument(unsigned Idx, MVT ArgVT, LLT ArgLLT,
                                  MachineIRBuilder &MIRBuilder,
                                  Register Def = Register()) {
  unsigned Op = getWasmArgumentOpcode(ArgVT);

  const TargetInstrInfo &TII = MIRBuilder.getTII();
  MachineFunction &MF = MIRBuilder.getMF();
  MachineRegisterInfo &MRI = MF.getRegInfo();
  const TargetRegisterClass &RegClass = *TII.getRegClass(TII.get(Op), 0);

  Register NewReg;

  if (Def.isValid()) {
    assert(MRI.getRegClassOrRegBank(Def).isNull() &&
           "Def already has reg bank or reg class?");
    MRI.setRegClass(Def, &RegClass);

    NewReg = Def;
  } else {
    NewReg = MRI.createVirtualRegister(&RegClass);
    MRI.setType(NewReg, ArgLLT);
  }

  MIRBuilder.buildInstr(Op).addDef(NewReg).addImm(Idx);

  return NewReg;
}

bool WebAssemblyCallLowering::lowerFormalArguments(
    MachineIRBuilder &MIRBuilder, const Function &F,
    ArrayRef<ArrayRef<Register>> VRegs, FunctionLoweringInfo &FLI) const {
  MachineFunction &MF = MIRBuilder.getMF();
  MachineRegisterInfo &MRI = MF.getRegInfo();
  WebAssemblyFunctionInfo *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
  const DataLayout &DL = F.getDataLayout();
  const WebAssemblyTargetLowering &TLI = *getTLI<WebAssemblyTargetLowering>();

  LLVMContext &Ctx = MIRBuilder.getContext();
  const CallingConv::ID CallConv = F.getCallingConv();

  if (!callingConvSupported(CallConv))
    return false;

  if (typeContainsReference(F.getReturnType()))
    return false;
  for (const Argument &Arg : F.args())
    if (typeContainsReference(Arg.getType()))
      return false;

  MF.getRegInfo().addLiveIn(WebAssembly::ARGUMENTS);
  MF.front().addLiveIn(WebAssembly::ARGUMENTS);

  SmallVector<ArgInfo, 8> SplitArgs;

  if (!FLI.CanLowerReturn)
    insertSRetIncomingArgument(F, SplitArgs, FLI.DemoteRegister, MRI, DL);

  unsigned ArgIdx = 0;
  bool HasSwiftErrorArg = false;
  bool HasSwiftSelfArg = false;
  for (const Argument &Arg : F.args()) {
    ArgInfo OrigArg{VRegs[ArgIdx], Arg.getType(), ArgIdx};
    setArgFlags(OrigArg, ArgIdx + AttributeList::FirstArgIndex, DL, F);

    HasSwiftSelfArg |= Arg.hasSwiftSelfAttr();
    HasSwiftErrorArg |= Arg.hasSwiftErrorAttr();
    if (Arg.hasInAllocaAttr())
      return false;
    if (Arg.hasNestAttr())
      return false;

    splitToValueTypes(OrigArg, SplitArgs, DL, F.getCallingConv());
    ++ArgIdx;
  }

  unsigned FinalArgIdx = 0;
  for (ArgInfo &Arg : SplitArgs) {
    const EVT OrigVT = TLI.getValueType(DL, Arg.Ty);
    const MVT NewVT = TLI.getRegisterTypeForCallingConv(Ctx, CallConv, OrigVT);
    const LLT OrigLLT =
        getLLTForType(*OrigVT.getTypeForEVT(F.getContext()), DL);
    const LLT NewLLT = getLLTForMVT(NewVT);

    // If we need to split the type over multiple regs, check it's a scenario
    // we currently support.
    const unsigned NumParts =
        TLI.getNumRegistersForCallingConv(Ctx, CallConv, OrigVT);

    const ISD::ArgFlagsTy OrigFlags = Arg.Flags[0];
    Arg.Flags.clear();

    for (unsigned Part = 0; Part < NumParts; ++Part) {
      ISD::ArgFlagsTy Flags = OrigFlags;
      if (Part == 0) {
        Flags.setSplit();
      } else {
        Flags.setOrigAlign(Align(1));
        if (Part == NumParts - 1)
          Flags.setSplitEnd();
      }

      Arg.Flags.push_back(Flags);
    }

    Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end());
    if (NumParts != 1 || OrigLLT != NewLLT) {
      // If we can't directly assign the register, we need one or more
      // intermediate values.
      Arg.Regs.resize(NumParts);

      // For each split register, create and assign a vreg that will store
      // the incoming component of the larger value. These will later be
      // merged to form the final vreg.
      for (unsigned Part = 0; Part < NumParts; ++Part) {
        Arg.Regs[Part] =
            buildWasmArgument(FinalArgIdx++, NewVT, NewLLT, MIRBuilder);
        MFI->addParam(NewVT);
      }

      buildCopyFromRegs(MIRBuilder, Arg.OrigRegs, Arg.Regs, OrigLLT, NewLLT,
                        Arg.Flags[0]);
    } else {
      buildWasmArgument(FinalArgIdx++, NewVT, NewLLT, MIRBuilder, Arg.Regs[0]);
      MFI->addParam(NewVT);
    }
  }

  // For swiftcc, emit additional swiftself and swifterror arguments
  // if there aren't. These additional arguments are also added for callee
  // signature They are necessary to match callee and caller signature for
  // indirect call.
  if (CallConv == CallingConv::Swift) {
    const MVT PtrVT = TLI.getPointerTy(DL);

    if (!HasSwiftSelfArg)
      MFI->addParam(PtrVT);
    if (!HasSwiftErrorArg)
      MFI->addParam(PtrVT);
  }

  // Varargs are copied into a buffer allocated by the caller, and a pointer to
  // the buffer is passed as an argument.
  if (F.isVarArg()) {
    const MVT PtrVT = TLI.getPointerTy(DL, 0);
    const LLT PtrLLT = LLT::pointer(0, DL.getPointerSizeInBits(0));

    Register VarargVreg =
        buildWasmArgument(FinalArgIdx++, PtrVT, PtrLLT, MIRBuilder);
    MFI->setVarargBufferVreg(VarargVreg);

    MFI->addParam(PtrVT);
    ++FinalArgIdx;
  }

  // Record the number and types of arguments and results.
  SmallVector<MVT, 4> Params;
  SmallVector<MVT, 4> Results;
  computeSignatureVTs(MF.getFunction().getFunctionType(), &MF.getFunction(),
                      MF.getFunction(), MF.getTarget(), Params, Results);
  for (MVT VT : Results)
    MFI->addResult(VT);

  // TODO: Use signatures in WebAssemblyMachineFunctionInfo too and unify
  // the param logic here with ComputeSignatureVTs
  assert(MFI->getParams().size() == Params.size() &&
         std::equal(MFI->getParams().begin(), MFI->getParams().end(),
                    Params.begin()));
  return true;
}

bool WebAssemblyCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
                                        CallLoweringInfo &Info) const {
  MachineFunction &MF = MIRBuilder.getMF();
  const DataLayout &DL = MIRBuilder.getDataLayout();
  LLVMContext &Ctx = MIRBuilder.getContext();
  const WebAssemblyTargetLowering &TLI = *getTLI<WebAssemblyTargetLowering>();
  MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
  const Function &F = MF.getFunction();

  CallingConv::ID CallConv = Info.CallConv;
  if (!callingConvSupported(CallConv))
    return false;

  if (typeContainsReference(Info.OrigRet.Ty))
    return false;
  for (const ArgInfo &Arg : Info.OrigArgs)
    if (typeContainsReference(Arg.Ty))
      return false;

  // TODO: tail calls
  if (Info.IsMustTailCall)
    return false;

  // TODO: varargs
  if (Info.IsVarArg)
    return false;

  // TODO: swiftcc
  if (CallConv == CallingConv::Swift)
    return false;

  MachineInstrBuilder CallInst;

  // TODO: indirect calls
  if (Info.Callee.isReg())
    return false;

  CallInst = MIRBuilder.buildInstrNoInsert(WebAssembly::CALL);

  SmallVector<ArgInfo, 8> SplitArgs;

  for (const ArgInfo &Arg : Info.OrigArgs) {
    if (Arg.Flags[0].isNest())
      return false;
    if (Arg.Flags[0].isInAlloca())
      return false;
    if (Arg.Flags[0].isInConsecutiveRegs())
      return false;
    if (Arg.Flags[0].isInConsecutiveRegsLast())
      return false;

    // TODO: bulk memory, then byval
    if (Arg.Flags[0].isByVal() && Arg.Flags[0].getByValSize() != 0)
      return false;

    splitToValueTypes(Arg, SplitArgs, DL, CallConv);
  }

  SmallVector<Register> CallUseRegs;

  for (ArgInfo &Arg : SplitArgs) {
    const EVT OrigVT = TLI.getValueType(DL, Arg.Ty);
    const MVT NewVT = TLI.getRegisterTypeForCallingConv(Ctx, CallConv, OrigVT);
    const LLT OrigLLT =
        getLLTForType(*OrigVT.getTypeForEVT(F.getContext()), DL);
    const LLT NewLLT = getLLTForMVT(NewVT);

    const TargetRegisterClass &NewRegClass = *TLI.getRegClassFor(NewVT);

    // If we need to split the type over multiple regs, check it's a scenario
    // we currently support.
    const unsigned NumParts =
        TLI.getNumRegistersForCallingConv(Ctx, CallConv, OrigVT);

    const ISD::ArgFlagsTy OrigFlags = Arg.Flags[0];
    Arg.Flags.clear();

    for (unsigned Part = 0; Part < NumParts; ++Part) {
      ISD::ArgFlagsTy Flags = OrigFlags;
      if (Part == 0) {
        Flags.setSplit();
      } else {
        Flags.setOrigAlign(Align(1));
        if (Part == NumParts - 1)
          Flags.setSplitEnd();
      }

      Arg.Flags.push_back(Flags);
    }

    Arg.OrigRegs.assign(Arg.Regs.begin(), Arg.Regs.end());
    if (NumParts != 1 || OrigLLT != NewLLT) {
      // If we can't directly assign the register, we need one or more
      // intermediate values.
      Arg.Regs.resize(NumParts);

      // For each split register, create and assign a vreg that will store
      // the incoming component of the larger value. These will later be
      // merged to form the final vreg.
      for (unsigned Part = 0; Part < NumParts; ++Part) {
        Register NewReg = MRI.createVirtualRegister(&NewRegClass);
        MRI.setType(NewReg, NewLLT);
        CallUseRegs.push_back(NewReg);
        Arg.Regs[Part] = NewReg;
      }

      buildCopyToRegs(MIRBuilder, Arg.Regs, Arg.OrigRegs[0], OrigLLT, NewLLT,
                      extendOpFromFlags(Arg.Flags[0]));
    } else {
      CallUseRegs.push_back(Arg.Regs[0]);
    }
  }

  // Analyze operands of the call, assigning locations to each operand.
  SmallVector<CCValAssign, 16> ArgLocs;
  CCState CCInfo(CallConv, Info.IsVarArg, MF, ArgLocs, Ctx);

  MIRBuilder.insertInstr(CallInst);

  if (Info.CanLowerReturn && !Info.OrigRet.Ty->isVoidTy()) {
    SmallVector<EVT, 4> SplitEVTs;
    ComputeValueVTs(TLI, DL, Info.OrigRet.Ty, SplitEVTs);
    assert(Info.OrigRet.Regs.size() == SplitEVTs.size() &&
           "For each split Type there should be exactly one VReg.");

    SmallVector<ArgInfo, 8> SplitRets;

    unsigned RetIdx = 0;
    for (EVT SplitEVT : SplitEVTs) {
      Register CurVReg = Info.OrigRet.Regs[RetIdx];
      ArgInfo CurArgInfo = ArgInfo{CurVReg, SplitEVT.getTypeForEVT(Ctx), 0};

      if (Info.CB) {
        setArgFlags(CurArgInfo, AttributeList::ReturnIndex, DL, *Info.CB);
      } else {
        // We don't have a call base, so chances are we're looking at a
        // libcall (external symbol).

        // TODO: figure out how to get ALL the correct attributes
        ISD::ArgFlagsTy &Flags = CurArgInfo.Flags[0];
        PointerType *PtrTy =
            dyn_cast<PointerType>(CurArgInfo.Ty->getScalarType());
        if (PtrTy) {
          Flags.setPointer();
          Flags.setPointerAddrSpace(PtrTy->getPointerAddressSpace());
        }
        Align MemAlign = DL.getABITypeAlign(CurArgInfo.Ty);
        Flags.setMemAlign(MemAlign);
        Flags.setOrigAlign(MemAlign);
      }

      splitToValueTypes(CurArgInfo, SplitRets, DL, CallConv);
      ++RetIdx;
    }

    for (ArgInfo &Ret : SplitRets) {
      const EVT OrigVT = TLI.getValueType(DL, Ret.Ty);
      const MVT NewVT =
          TLI.getRegisterTypeForCallingConv(Ctx, CallConv, OrigVT);
      const LLT OrigLLT =
          getLLTForType(*OrigVT.getTypeForEVT(F.getContext()), DL);
      const LLT NewLLT = getLLTForMVT(NewVT);

      const TargetRegisterClass &NewRegClass = *TLI.getRegClassFor(NewVT);

      // If we need to split the type over multiple regs, check it's a scenario
      // we currently support.
      const unsigned NumParts =
          TLI.getNumRegistersForCallingConv(Ctx, CallConv, OrigVT);

      const ISD::ArgFlagsTy OrigFlags = Ret.Flags[0];
      Ret.Flags.clear();

      for (unsigned Part = 0; Part < NumParts; ++Part) {
        ISD::ArgFlagsTy Flags = OrigFlags;
        if (Part == 0) {
          Flags.setSplit();
        } else {
          Flags.setOrigAlign(Align(1));
          if (Part == NumParts - 1)
            Flags.setSplitEnd();
        }

        Ret.Flags.push_back(Flags);
      }

      Ret.OrigRegs.assign(Ret.Regs.begin(), Ret.Regs.end());

      if (NumParts != 1 || OrigLLT != NewLLT) {
        // If we can't directly assign the register, we need one or more
        // intermediate values.
        Ret.Regs.resize(NumParts);

        // For each split register, create and assign a vreg that will store
        // the incoming component of the larger value. These will later be
        // merged to form the final vreg.
        for (unsigned Part = 0; Part < NumParts; ++Part) {
          Register NewReg = MRI.createVirtualRegister(&NewRegClass);
          MRI.setType(NewReg, NewLLT);
          CallInst.addDef(NewReg);
          Ret.Regs[Part] = NewReg;
        }

        buildCopyFromRegs(MIRBuilder, Ret.OrigRegs, Ret.Regs, OrigLLT, NewLLT,
                          Ret.Flags[0]);
      } else {
        MRI.setRegClass(Ret.Regs[0], &NewRegClass);
        CallInst.addDef(Ret.Regs[0]);
      }
    }
  }

  if (Info.Callee.isGlobal()) {
    CallInst.addGlobalAddress(Info.Callee.getGlobal());
  } else if (Info.Callee.isSymbol()) {
    CallInst.addExternalSymbol(Info.Callee.getSymbolName());
  } else {
    return false;
  }

  for (Register Reg : CallUseRegs) {
    CallInst.addUse(Reg);
  }

  if (!Info.CanLowerReturn)
    insertSRetLoads(MIRBuilder, Info.OrigRet.Ty, Info.OrigRet.Regs,
                    Info.DemoteRegister, Info.DemoteStackIndex);

  return true;
}
