text: //===--- IRGenFunction.cpp - Swift Per-Function IR Generation -------------===//
  //
  // This source file is part of the Swift.org open source project
  //
  // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
  // Licensed under Apache License v2.0 with Runtime Library Exception
  //
  // See https://swift.org/LICENSE.txt for license information
  // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  //
  //===----------------------------------------------------------------------===//
  //
  //  This file implements basic setup and teardown for the class which
  //  performs IR generation for function bodies.
  //
  //===----------------------------------------------------------------------===//
  
  #include "swift/AST/IRGenOptions.h"
  #include "swift/Basic/SourceLoc.h"
  #include "swift/IRGen/Linking.h"
  #include "llvm/IR/Instructions.h"
  #include "llvm/IR/Function.h"
  #include "llvm/Support/raw_ostream.h"
  
  #include "Explosion.h"
  #include "IRGenDebugInfo.h"
  #include "IRGenFunction.h"
  #include "IRGenModule.h"
  #include "LoadableTypeInfo.h"
  
  using namespace swift;
  using namespace irgen;
  
  IRGenFunction::IRGenFunction(IRGenModule &IGM, llvm::Function *Fn,
                               OptimizationMode OptMode,
                               const SILDebugScope *DbgScope,
                               Optional<SILLocation> DbgLoc)
      : IGM(IGM), Builder(IGM.getLLVMContext(),
                          IGM.DebugInfo && !IGM.Context.LangOpts.DebuggerSupport),
        OptMode(OptMode), CurFn(Fn), DbgScope(DbgScope) {
  
    // Make sure the instructions in this function are attached its debug scope.
    if (IGM.DebugInfo) {
      // Functions, especially artificial thunks and closures, are often
      // generated on-the-fly while we are in the middle of another
      // function. Be nice and preserve the current debug location until
      // after we're done with this function.
      IGM.DebugInfo->pushLoc();
    }
  
    emitPrologue();
  }
  
  IRGenFunction::~IRGenFunction() {
    emitEpilogue();
  
    // Restore the debug location.
    if (IGM.DebugInfo) IGM.DebugInfo->popLoc();
  
    // Tear down any side-table data structures.
    if (LocalTypeData) destroyLocalTypeData();
  }
  
  OptimizationMode IRGenFunction::getEffectiveOptimizationMode() const {
    if (OptMode != OptimizationMode::NotSet)
      return OptMode;
  
    return IGM.getOptions().OptMode;
  }
  
  ModuleDecl *IRGenFunction::getSwiftModule() const {
    return IGM.getSwiftModule();
  }
  
  SILModule &IRGenFunction::getSILModule() const {
    return IGM.getSILModule();
  }
  
  Lowering::TypeConverter &IRGenFunction::getSILTypes() const {
    return IGM.getSILTypes();
  }
  
  const IRGenOptions &IRGenFunction::getOptions() const {
    return IGM.getOptions();
  }
  
  // Returns the default atomicity of the module.
  Atomicity IRGenFunction::getDefaultAtomicity() {
    return getSILModule().isDefaultAtomic() ? Atomicity::Atomic : Atomicity::NonAtomic;
  }
  
  /// Call the llvm.memcpy intrinsic.  The arguments need not already
  /// be of i8* type.
  void IRGenFunction::emitMemCpy(llvm::Value *dest, llvm::Value *src,
                                 Size size, Alignment align) {
    emitMemCpy(dest, src, IGM.getSize(size), align);
  }
  
  void IRGenFunction::emitMemCpy(llvm::Value *dest, llvm::Value *src,
                                 llvm::Value *size, Alignment align) {
    Builder.CreateMemCpy(dest, align.getValue(), src, align.getValue(), size);
  }
  
  void IRGenFunction::emitMemCpy(Address dest, Address src, Size size) {
    emitMemCpy(dest, src, IGM.getSize(size));
  }
  
  void IRGenFunction::emitMemCpy(Address dest, Address src, llvm::Value *size) {
    // Map over to the inferior design of the LLVM intrinsic.
    emitMemCpy(dest.getAddress(), src.getAddress(), size,
               std::min(dest.getAlignment(), src.getAlignment()));
  }
  
  static llvm::Value *emitAllocatingCall(IRGenFunction &IGF,
                                         llvm::Constant *fn,
                                         ArrayRef<llvm::Value*> args,
                                         const llvm::Twine &name) {
    auto allocAttrs = IGF.IGM.getAllocAttrs();
    llvm::CallInst *call =
      IGF.Builder.CreateCall(fn, makeArrayRef(args.begin(), args.size()));
    call->setAttributes(allocAttrs);
    return call;
  }
  
  /// Emit a 'raw' allocation, which has no heap pointer and is
  /// not guaranteed to be zero-initialized.
  llvm::Value *IRGenFunction::emitAllocRawCall(llvm::Value *size,
                                               llvm::Value *alignMask,
                                               const llvm::Twine &name) {
    // For now, all we have is swift_slowAlloc.
    return emitAllocatingCall(*this, IGM.getSlowAllocFn(),
                              {size, alignMask},
                              name);
  }
  
  /// Emit a heap allocation.
  llvm::Value *IRGenFunction::emitAllocObjectCall(llvm::Value *metadata,
                                                  llvm::Value *size,
                                                  llvm::Value *alignMask,
                                                  const llvm::Twine &name) {
    // For now, all we have is swift_allocObject.
    return emitAllocatingCall(*this, IGM.getAllocObjectFn(),
                              { metadata, size, alignMask }, name);
  }
  
  llvm::Value *IRGenFunction::emitInitStackObjectCall(llvm::Value *metadata,
                                                      llvm::Value *object,
                                                      const llvm::Twine &name) {
    llvm::CallInst *call =
      Builder.CreateCall(IGM.getInitStackObjectFn(), { metadata, object }, name);
    call->setDoesNotThrow();
    return call;
  }
  
  llvm::Value *IRGenFunction::emitInitStaticObjectCall(llvm::Value *metadata,
                                                       llvm::Value *object,
                                                       const llvm::Twine &name) {
    llvm::CallInst *call =
      Builder.CreateCall(IGM.getInitStaticObjectFn(), { metadata, object }, name);
    call->setDoesNotThrow();
    return call;
  }
  
  llvm::Value *IRGenFunction::emitVerifyEndOfLifetimeCall(llvm::Value *object,
                                                        const llvm::Twine &name) {
    llvm::CallInst *call =
      Builder.CreateCall(IGM.getVerifyEndOfLifetimeFn(), { object }, name);
    call->setDoesNotThrow();
    return call;
  }
  
  void IRGenFunction::emitAllocBoxCall(llvm::Value *typeMetadata,
                                        llvm::Value *&box,
                                        llvm::Value *&valueAddress) {
    auto attrs = llvm::AttributeList::get(IGM.LLVMContext,
                                          llvm::AttributeList::FunctionIndex,
                                          llvm::Attribute::NoUnwind);
  
    llvm::CallInst *call =
      Builder.CreateCall(IGM.getAllocBoxFn(), typeMetadata);
    call->setAttributes(attrs);
  
    box = Builder.CreateExtractValue(call, 0);
    valueAddress = Builder.CreateExtractValue(call, 1);
  }
  
  void IRGenFunction::emitMakeBoxUniqueCall(llvm::Value *box,
                                            llvm::Value *typeMetadata,
                                            llvm::Value *alignMask,
                                            llvm::Value *&outBox,
                                            llvm::Value *&outValueAddress) {
    auto attrs = llvm::AttributeList::get(IGM.LLVMContext,
                                          llvm::AttributeList::FunctionIndex,
                                          llvm::Attribute::NoUnwind);
  
    llvm::CallInst *call = Builder.CreateCall(IGM.getMakeBoxUniqueFn(),
                                              {box, typeMetadata, alignMask});
    call->setAttributes(attrs);
  
    outBox = Builder.CreateExtractValue(call, 0);
    outValueAddress = Builder.CreateExtractValue(call, 1);
  }
  
  
  void IRGenFunction::emitDeallocBoxCall(llvm::Value *box,
                                          llvm::Value *typeMetadata) {
    auto attrs = llvm::AttributeList::get(IGM.LLVMContext,
                                          llvm::AttributeList::FunctionIndex,
                                          llvm::Attribute::NoUnwind);
  
    llvm::CallInst *call =
      Builder.CreateCall(IGM.getDeallocBoxFn(), box);
    call->setCallingConv(IGM.DefaultCC);
    call->setAttributes(attrs);
  }
  
  llvm::Value *IRGenFunction::emitProjectBoxCall(llvm::Value *box,
                                                  llvm::Value *typeMetadata) {
    llvm::Attribute::AttrKind attrKinds[] = {
      llvm::Attribute::NoUnwind,
      llvm::Attribute::ReadNone,
    };
    auto attrs = llvm::AttributeList::get(
        IGM.LLVMContext, llvm::AttributeList::FunctionIndex, attrKinds);
    llvm::CallInst *call =
      Builder.CreateCall(IGM.getProjectBoxFn(), box);
    call->setCallingConv(IGM.DefaultCC);
    call->setAttributes(attrs);
    return call;
  }
  
  llvm::Value *IRGenFunction::emitAllocEmptyBoxCall() {
    auto attrs = llvm::AttributeList::get(IGM.LLVMContext,
                                          llvm::AttributeList::FunctionIndex,
                                          llvm::Attribute::NoUnwind);
    llvm::CallInst *call =
      Builder.CreateCall(IGM.getAllocEmptyBoxFn(), {});
    call->setCallingConv(IGM.DefaultCC);
    call->setAttributes(attrs);
    return call;
  }
  
  static void emitDeallocatingCall(IRGenFunction &IGF, llvm::Constant *fn,
                                   std::initializer_list<llvm::Value *> args) {
    auto cc = IGF.IGM.DefaultCC;
    if (auto fun = dyn_cast<llvm::Function>(fn))
      cc = fun->getCallingConv();
  
  
    llvm::CallInst *call =
      IGF.Builder.CreateCall(fn, makeArrayRef(args.begin(), args.size()));
    call->setCallingConv(cc);
    call->setDoesNotThrow();
  }
  
  /// Emit a 'raw' deallocation, which has no heap pointer and is not
  /// guaranteed to be zero-initialized.
  void IRGenFunction::emitDeallocRawCall(llvm::Value *pointer,
                                         llvm::Value *size,
                                         llvm::Value *alignMask) {
    // For now, all we have is swift_slowDealloc.
    return emitDeallocatingCall(*this, IGM.getSlowDeallocFn(),
                                {pointer, size, alignMask});
  }
  
  void IRGenFunction::emitTSanInoutAccessCall(llvm::Value *address) {
    llvm::Function *fn = cast<llvm::Function>(IGM.getTSanInoutAccessFn());
  
    llvm::Value *castAddress = Builder.CreateBitCast(address, IGM.Int8PtrTy);
  
    // Passing 0 as the caller PC causes compiler-rt to get our PC.
    llvm::Value *callerPC = llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
  
    // A magic number agreed upon with compiler-rt to indicate a modifying
    // access.
    const unsigned kExternalTagSwiftModifyingAccess = 0x1;
    llvm::Value *tagValue =
        llvm::ConstantInt::get(IGM.SizeTy, kExternalTagSwiftModifyingAccess);
    llvm::Value *castTag = Builder.CreateIntToPtr(tagValue, IGM.Int8PtrTy);
  
    Builder.CreateCall(fn, {castAddress, callerPC, castTag});
  }
  
  
  /// Initialize a relative indirectable pointer to the given value.
  /// This always leaves the value in the direct state; if it's not a
  /// far reference, it's the caller's responsibility to ensure that the
  /// pointer ranges are sufficient.
  void IRGenFunction::emitStoreOfRelativeIndirectablePointer(llvm::Value *value,
                                                             Address addr,
                                                             bool isFar) {
    value = Builder.CreatePtrToInt(value, IGM.IntPtrTy);
    auto addrAsInt =
      Builder.CreatePtrToInt(addr.getAddress(), IGM.IntPtrTy);
  
    auto difference = Builder.CreateSub(value, addrAsInt);
    if (!isFar) {
      difference = Builder.CreateTrunc(difference, IGM.RelativeAddressTy);
    }
  
    Builder.CreateStore(difference, addr);
  }
  
  llvm::Value *
  IRGenFunction::emitLoadOfRelativeIndirectablePointer(Address addr,
                                                  bool isFar,
                                                  llvm::PointerType *expectedType,
                                                  const llvm::Twine &name) {
    // Load the pointer and turn it back into a pointer.
    llvm::Value *value = Builder.CreateLoad(addr);
    assert(value->getType() == (isFar ? IGM.FarRelativeAddressTy
                                      : IGM.RelativeAddressTy));
    if (!isFar) {
      value = Builder.CreateSExt(value, IGM.IntPtrTy);
    }
    assert(value->getType() == IGM.IntPtrTy);
  
    llvm::BasicBlock *origBB = Builder.GetInsertBlock();
    llvm::Value *directResult = Builder.CreateIntToPtr(value, expectedType);
  
    // Check whether the low bit is set.
    llvm::Constant *one = llvm::ConstantInt::get(IGM.IntPtrTy, 1);
    llvm::BasicBlock *indirectBB = createBasicBlock("relptr.indirect");
    llvm::BasicBlock *contBB = createBasicBlock("relptr.cont");
    llvm::Value *isIndirect = Builder.CreateAnd(value, one);
    isIndirect = Builder.CreateIsNotNull(isIndirect);
    Builder.CreateCondBr(isIndirect, indirectBB, contBB);
  
    // In the indirect block, clear the low bit and perform an additional load.
    llvm::Value *indirectResult; {
      Builder.emitBlock(indirectBB);
  
      // Clear the low bit.
      llvm::Value *ptr = Builder.CreateSub(value, one);
      ptr = Builder.CreateIntToPtr(ptr, expectedType->getPointerTo());
  
      // Load.
      Address indirectAddr(ptr, IGM.getPointerAlignment());
      indirectResult = Builder.CreateLoad(indirectAddr);
  
      Builder.CreateBr(contBB);
    }
  
    Builder.emitBlock(contBB);
    auto phi = Builder.CreatePHI(expectedType, 2, name);
    phi->addIncoming(directResult, origBB);
    phi->addIncoming(indirectResult, indirectBB);
  
    return phi;
  }
  
  void IRGenFunction::emitFakeExplosion(const TypeInfo &type,
                                        Explosion &explosion) {
    if (!isa<LoadableTypeInfo>(type)) {
      explosion.add(llvm::UndefValue::get(type.getStorageType()->getPointerTo()));
      return;
    }
  
    ExplosionSchema schema = cast<LoadableTypeInfo>(type).getSchema();
    for (auto &element : schema) {
      llvm::Type *elementType;
      if (element.isAggregate()) {
        elementType = element.getAggregateType()->getPointerTo();
      } else {
        elementType = element.getScalarType();
      }
      
      explosion.add(llvm::UndefValue::get(elementType));
    }
  }
  
  void IRGenFunction::unimplemented(SourceLoc Loc, StringRef Message) {
    return IGM.unimplemented(Loc, Message);
  }
  
  // Debug output for Explosions.
  
  void Explosion::print(llvm::raw_ostream &OS) {
    for (auto value : makeArrayRef(Values).slice(NextValue)) {
      value->print(OS);
      OS << '\n';
    }
  }
  
  void Explosion::dump() {
    print(llvm::errs());
  }
  
  llvm::Value *Offset::getAsValue(IRGenFunction &IGF) const {
    if (isStatic()) {
      return IGF.IGM.getSize(getStatic());
    } else {
      return getDynamic();
    }
  }
  
  Offset Offset::offsetBy(IRGenFunction &IGF, Size other) const {
    if (isStatic()) {
      return Offset(getStatic() + other);
    }
    auto otherVal = llvm::ConstantInt::get(IGF.IGM.SizeTy, other.getValue());
    return Offset(IGF.Builder.CreateAdd(getDynamic(), otherVal));
  }
  
  Address IRGenFunction::emitAddressAtOffset(llvm::Value *base, Offset offset,
                                             llvm::Type *objectTy,
                                             Alignment objectAlignment,
                                             const llvm::Twine &name) {
    // Use a slightly more obvious IR pattern if it's a multiple of the type
    // size.  I'll confess that this is partly just to avoid updating tests.
    if (offset.isStatic()) {
      auto byteOffset = offset.getStatic();
      Size objectSize(IGM.DataLayout.getTypeAllocSize(objectTy));
      if (byteOffset.isMultipleOf(objectSize)) {
        // Cast to T*.
        auto objectPtrTy = objectTy->getPointerTo();
        base = Builder.CreateBitCast(base, objectPtrTy);
  
        // GEP to the slot, computing the index as a signed number.
        auto scaledIndex =
          int64_t(byteOffset.getValue()) / int64_t(objectSize.getValue());
        auto indexValue = IGM.getSize(Size(scaledIndex));
        auto slotPtr = Builder.CreateInBoundsGEP(base, indexValue);
  
        return Address(slotPtr, objectAlignment);
      }
    }
  
    // GEP to the slot.
    auto offsetValue = offset.getAsValue(*this);
    auto slotPtr = emitByteOffsetGEP(base, offsetValue, objectTy);
    return Address(slotPtr, objectAlignment);
  }
  
  llvm::CallInst *IRBuilder::CreateNonMergeableTrap(IRGenModule &IGM) {
    if (IGM.IRGen.Opts.shouldOptimize()) {
      // Emit unique side-effecting inline asm calls in order to eliminate
      // the possibility that an LLVM optimization or code generation pass
      // will merge these blocks back together again. We emit an empty asm
      // string with the side-effect flag set, and with a unique integer
      // argument for each cond_fail we see in the function.
      llvm::IntegerType *asmArgTy = IGM.Int32Ty;
      llvm::Type *argTys = {asmArgTy};
      llvm::FunctionType *asmFnTy =
          llvm::FunctionType::get(IGM.VoidTy, argTys, false /* = isVarArg */);
      llvm::InlineAsm *inlineAsm =
          llvm::InlineAsm::get(asmFnTy, "", "n", true /* = SideEffects */);
      CreateAsmCall(inlineAsm,
                    llvm::ConstantInt::get(asmArgTy, NumTrapBarriers++));
    }
  
    // Emit the trap instruction.
    llvm::Function *trapIntrinsic =
        llvm::Intrinsic::getDeclaration(&IGM.Module, llvm::Intrinsic::ID::trap);
    auto Call = IRBuilderBase::CreateCall(trapIntrinsic, {});
    setCallingConvUsingCallee(Call);
    return Call;
  }
  
  void IRGenFunction::emitTrap(bool EmitUnreachable) {
    Builder.CreateNonMergeableTrap(IGM);
    if (EmitUnreachable)
      Builder.CreateUnreachable();
  }
  