//===--- GenRecord.h - IR generation for record types -----------*- C++ -*-===//
//
// 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 provides some common code for emitting record types.
//  A record type is something like a tuple or a struct.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_IRGEN_GENRECORD_H
#define SWIFT_IRGEN_GENRECORD_H

#include "IRGenFunction.h"
#include "IRGenModule.h"
#include "Explosion.h"
#include "GenEnum.h"
#include "GenOpaque.h"
#include "LoadableTypeInfo.h"
#include "Outlining.h"
#include "TypeInfo.h"
#include "StructLayout.h"
#include "llvm/Support/TrailingObjects.h"

namespace swift {
namespace irgen {

template <class, class, class> class RecordTypeBuilder;

/// A field of a record type.
template <class FieldImpl> class RecordField {
  ElementLayout Layout;

  template <class, class, class> friend class RecordTypeBuilder;

  /// Begin/End - the range of explosion indexes for this element
  unsigned Begin : 16;
  unsigned End : 16;

protected:
  explicit RecordField(const TypeInfo &elementTI)
    : Layout(ElementLayout::getIncomplete(elementTI, elementTI)) {}

  explicit RecordField(const ElementLayout &layout,
                       unsigned begin, unsigned end)
    : Layout(layout), Begin(begin), End(end) {}

  const FieldImpl *asImpl() const {
    return static_cast<const FieldImpl*>(this);
  }
public:
  const TypeInfo &getTypeInfo() const { return Layout.getTypeForLayout(); }

  void completeFrom(const ElementLayout &layout) {
    Layout.completeFrom(layout);
  }

  bool isEmpty() const {
    return Layout.isEmpty();
  }

  IsPOD_t isPOD() const {
    return Layout.isPOD();
  }

  IsABIAccessible_t isABIAccessible() const {
    return Layout.getTypeForLayout().isABIAccessible();
  }

  Address projectAddress(IRGenFunction &IGF, Address seq,
                         NonFixedOffsets offsets) const {
    return Layout.project(IGF, seq, offsets, "." + asImpl()->getFieldName());
  }
  
  ElementLayout::Kind getKind() const {
    return Layout.getKind();
  }
  
  Size getFixedByteOffset() const {
    return Layout.getByteOffset();
  }

  unsigned getStructIndex() const { return Layout.getStructIndex(); }

  unsigned getNonFixedElementIndex() const {
    return Layout.getNonFixedElementIndex();
  }

  std::pair<unsigned, unsigned> getProjectionRange() const {
    return {Begin, End};
  }
};

enum FieldsAreABIAccessible_t : bool {
  FieldsAreNotABIAccessible = false,
  FieldsAreABIAccessible = true,
};

/// A metaprogrammed TypeInfo implementation for record types.
template <class Impl, class Base, class FieldImpl_,
          bool IsLoadable = std::is_base_of<LoadableTypeInfo, Base>::value>
class RecordTypeInfoImpl : public Base,
    private llvm::TrailingObjects<Impl, FieldImpl_> {
  friend class llvm::TrailingObjects<Impl, FieldImpl_>;

public:
  using FieldImpl = FieldImpl_;

private:
  const unsigned NumFields;
  const unsigned AreFieldsABIAccessible : 1;

protected:
  const Impl &asImpl() const { return *static_cast<const Impl*>(this); }

  template <class... As> 
  RecordTypeInfoImpl(ArrayRef<FieldImpl> fields,
                     FieldsAreABIAccessible_t fieldsABIAccessible,
                     As&&...args)
      : Base(std::forward<As>(args)...),
        NumFields(fields.size()),
        AreFieldsABIAccessible(fieldsABIAccessible) {
    std::uninitialized_copy(fields.begin(), fields.end(),
                            this->template getTrailingObjects<FieldImpl>());
  }

public:
  /// Allocate and initialize a type info of this type.
  template <class... As>
  static Impl *create(ArrayRef<FieldImpl> fields, As &&...args) {
    size_t size = Impl::template totalSizeToAlloc<FieldImpl>(fields.size());
    void *buffer = ::operator new(size);
    return new(buffer) Impl(fields, std::forward<As>(args)...);
  }

  ArrayRef<FieldImpl> getFields() const {
    return {this->template getTrailingObjects<FieldImpl>(), NumFields};
  }

  /// The standard schema is just all the fields jumbled together.
  void getSchema(ExplosionSchema &schema) const override {
    for (auto &field : getFields()) {
      field.getTypeInfo().getSchema(schema);
    }
  }

  void assignWithCopy(IRGenFunction &IGF, Address dest, Address src, SILType T,
                      bool isOutlined) const override {
    // If the fields are not ABI-accessible, use the value witness table.
    if (!AreFieldsABIAccessible) {
      return emitAssignWithCopyCall(IGF, T, dest, src);
    }

    if (isOutlined || T.hasOpenedExistential()) {
      auto offsets = asImpl().getNonFixedOffsets(IGF, T);
      for (auto &field : getFields()) {
        if (field.isEmpty())
          continue;

        Address destField = field.projectAddress(IGF, dest, offsets);
        Address srcField = field.projectAddress(IGF, src, offsets);
        field.getTypeInfo().assignWithCopy(
            IGF, destField, srcField, field.getType(IGF.IGM, T), isOutlined);
      }
    } else {
      this->callOutlinedCopy(IGF, dest, src, T, IsNotInitialization, IsNotTake);
    }
  }

  void assignWithTake(IRGenFunction &IGF, Address dest, Address src, SILType T,
                      bool isOutlined) const override {
    // If the fields are not ABI-accessible, use the value witness table.
    if (!AreFieldsABIAccessible) {
      return emitAssignWithTakeCall(IGF, T, dest, src);
    }

    if (isOutlined || T.hasOpenedExistential()) {
      auto offsets = asImpl().getNonFixedOffsets(IGF, T);
      for (auto &field : getFields()) {
        if (field.isEmpty())
          continue;

        Address destField = field.projectAddress(IGF, dest, offsets);
        Address srcField = field.projectAddress(IGF, src, offsets);
        field.getTypeInfo().assignWithTake(
            IGF, destField, srcField, field.getType(IGF.IGM, T), isOutlined);
      }
    } else {
      this->callOutlinedCopy(IGF, dest, src, T, IsNotInitialization, IsTake);
    }
  }

  void initializeWithCopy(IRGenFunction &IGF, Address dest, Address src,
                          SILType T, bool isOutlined) const override {
    // If we're POD, use the generic routine.
    if (this->isPOD(ResilienceExpansion::Maximal) &&
        isa<LoadableTypeInfo>(this)) {
      return cast<LoadableTypeInfo>(this)->LoadableTypeInfo::initializeWithCopy(
          IGF, dest, src, T, isOutlined);
    }

    // If the fields are not ABI-accessible, use the value witness table.
    if (!AreFieldsABIAccessible) {
      return emitInitializeWithCopyCall(IGF, T, dest, src);
    }

    if (isOutlined || T.hasOpenedExistential()) {
      auto offsets = asImpl().getNonFixedOffsets(IGF, T);
      for (auto &field : getFields()) {
        if (field.isEmpty())
          continue;

        Address destField = field.projectAddress(IGF, dest, offsets);
        Address srcField = field.projectAddress(IGF, src, offsets);
        field.getTypeInfo().initializeWithCopy(
            IGF, destField, srcField, field.getType(IGF.IGM, T), isOutlined);
      }
    } else {
      this->callOutlinedCopy(IGF, dest, src, T, IsInitialization, IsNotTake);
    }
  }

  void initializeWithTake(IRGenFunction &IGF, Address dest, Address src,
                          SILType T, bool isOutlined) const override {
    // If we're bitwise-takable, use memcpy.
    if (this->isBitwiseTakable(ResilienceExpansion::Maximal)) {
      IGF.Builder.CreateMemCpy(dest.getAddress(), src.getAddress(),
                 asImpl().Impl::getSize(IGF, T),
                 std::min(dest.getAlignment(), src.getAlignment()).getValue());
      return;
    }

    // If the fields are not ABI-accessible, use the value witness table.
    if (!AreFieldsABIAccessible) {
      return emitInitializeWithTakeCall(IGF, T, dest, src);
    }

    if (isOutlined || T.hasOpenedExistential()) {
      auto offsets = asImpl().getNonFixedOffsets(IGF, T);
      for (auto &field : getFields()) {
        if (field.isEmpty())
          continue;

        Address destField = field.projectAddress(IGF, dest, offsets);
        Address srcField = field.projectAddress(IGF, src, offsets);
        field.getTypeInfo().initializeWithTake(
            IGF, destField, srcField, field.getType(IGF.IGM, T), isOutlined);
      }
    } else {
      this->callOutlinedCopy(IGF, dest, src, T, IsInitialization, IsTake);
    }
  }

  void destroy(IRGenFunction &IGF, Address addr, SILType T,
               bool isOutlined) const override {
    // If the fields are not ABI-accessible, use the value witness table.
    if (!AreFieldsABIAccessible) {
      return emitDestroyCall(IGF, T, addr);
    }

    if (isOutlined || T.hasOpenedExistential()) {
      auto offsets = asImpl().getNonFixedOffsets(IGF, T);
      for (auto &field : getFields()) {
        if (field.isPOD())
          continue;

        field.getTypeInfo().destroy(IGF,
                                    field.projectAddress(IGF, addr, offsets),
                                    field.getType(IGF.IGM, T), isOutlined);
      }
    } else {
      this->callOutlinedDestroy(IGF, addr, T);
    }
  }

  void collectMetadataForOutlining(OutliningMetadataCollector &collector,
                                   SILType T) const override {
    for (auto &field : getFields()) {
      if (field.isEmpty())
        continue;
      auto fType = field.getType(collector.IGF.IGM, T);
      field.getTypeInfo().collectMetadataForOutlining(collector, fType);
    }
    collector.collectTypeMetadataForLayout(T);
  }
};

template <class Impl, class Base, class FieldImpl_,
          bool IsFixedSize = std::is_base_of<FixedTypeInfo, Base>::value,
          bool IsLoadable = std::is_base_of<LoadableTypeInfo, Base>::value>
class RecordTypeInfo;

/// An implementation of RecordTypeInfo for non-fixed-size types
/// (but not resilient ones where we don't know the complete set of
/// stored properties).
///
/// Override the buffer operations to just delegate to the unique
/// non-empty field, if there is one.
template <class Impl, class Base, class FieldImpl>
class RecordTypeInfo<Impl, Base, FieldImpl,
                     /*IsFixedSize*/ false, /*IsLoadable*/ false>
    : public RecordTypeInfoImpl<Impl, Base, FieldImpl> {
  using super = RecordTypeInfoImpl<Impl, Base, FieldImpl>;

  /// The index+1 of the unique non-empty field, or zero if there is none.
  unsigned UniqueNonEmptyFieldIndexPlusOne;
protected:
  template <class... As>
  RecordTypeInfo(ArrayRef<FieldImpl> fields, As&&...args)
      : super(fields, std::forward<As>(args)...) {

    // Look for a unique non-empty field.
    UniqueNonEmptyFieldIndexPlusOne = findUniqueNonEmptyField(fields);
  }

public:
  using super::getStorageType;

  Address initializeBufferWithTakeOfBuffer(IRGenFunction &IGF,
                                           Address destBuffer,
                                           Address srcBuffer,
                                           SILType type) const override {
    if (auto field = getUniqueNonEmptyField()) {
      auto &fieldTI = field->getTypeInfo();
      Address fieldResult =
        fieldTI.initializeBufferWithTakeOfBuffer(IGF, destBuffer, srcBuffer,
                                                 field->getType(IGF.IGM, type));
      return IGF.Builder.CreateElementBitCast(fieldResult, getStorageType());
    } else {
      return super::initializeBufferWithTakeOfBuffer(IGF, destBuffer,
                                                     srcBuffer, type);
    }
  }

  Address initializeBufferWithCopyOfBuffer(IRGenFunction &IGF,
                                           Address destBuffer,
                                           Address srcBuffer,
                                           SILType type) const override {
    if (auto field = getUniqueNonEmptyField()) {
      auto &fieldTI = field->getTypeInfo();
      Address fieldResult =
        fieldTI.initializeBufferWithCopyOfBuffer(IGF, destBuffer, srcBuffer,
                                                 field->getType(IGF.IGM, type));
      return IGF.Builder.CreateElementBitCast(fieldResult, getStorageType());
    } else {
      return super::initializeBufferWithCopyOfBuffer(IGF, destBuffer,
                                                     srcBuffer, type);
    }
  }

private:
  /// Scan the given field info
  static unsigned findUniqueNonEmptyField(ArrayRef<FieldImpl> fields) {
    unsigned result = 0;
    for (auto &field : fields) {
      // Ignore empty fields.
      if (field.isEmpty()) continue;

      // If the field is not ABI-accessible, suppress this.
      if (!field.isABIAccessible()) continue;

      // If we've already found an index, then there isn't a
      // unique non-empty field.
      if (result) return 0;

      result = (&field - fields.data()) + 1;
    }

    return result;
  }

  const FieldImpl *getUniqueNonEmptyField() const {
    if (UniqueNonEmptyFieldIndexPlusOne) {
      return &this->getFields()[UniqueNonEmptyFieldIndexPlusOne - 1];
    } else {
      return nullptr;
    }
  }
};

/// An implementation of RecordTypeInfo for non-loadable types. 
template <class Impl, class Base, class FieldImpl>
class RecordTypeInfo<Impl, Base, FieldImpl,
                     /*IsFixedSize*/ true, /*IsLoadable*/ false>
    : public RecordTypeInfoImpl<Impl, Base, FieldImpl> {
  using super = RecordTypeInfoImpl<Impl, Base, FieldImpl>;

protected:
  template <class... As> 
  RecordTypeInfo(ArrayRef<FieldImpl> fields, As &&...args)
    : super(fields, FieldsAreABIAccessible, std::forward<As>(args)...) {}
};

/// An implementation of RecordTypeInfo for loadable types. 
template <class Impl, class Base, class FieldImpl>
class RecordTypeInfo<Impl, Base, FieldImpl,
                     /*IsFixedSize*/ true, /*IsLoadable*/ true>
    : public RecordTypeInfoImpl<Impl, Base, FieldImpl> {
  using super = RecordTypeInfoImpl<Impl, Base, FieldImpl>;

  unsigned ExplosionSize : 16;

protected:
  using super::asImpl;

  template <class... As> 
  RecordTypeInfo(ArrayRef<FieldImpl> fields,
                 unsigned explosionSize,
                 As &&...args)
    : super(fields, FieldsAreABIAccessible, std::forward<As>(args)...),
      ExplosionSize(explosionSize) {}

private:
  template <void (LoadableTypeInfo::*Op)(IRGenFunction &IGF,
                                         Address addr,
                                         Explosion &out) const>
  void forAllFields(IRGenFunction &IGF, Address addr, Explosion &out) const {
    auto offsets = asImpl().getNonFixedOffsets(IGF);
    for (auto &field : getFields()) {
      if (field.isEmpty()) continue;

      Address fieldAddr = field.projectAddress(IGF, addr, offsets);
      (cast<LoadableTypeInfo>(field.getTypeInfo()).*Op)(IGF, fieldAddr, out);
    }
  }

  template <void (LoadableTypeInfo::*Op)(IRGenFunction &IGF, Address addr,
                                         Explosion &out, Atomicity atomicity) const>
  void forAllFields(IRGenFunction &IGF, Address addr, Explosion &out,
                    Atomicity atomicity) const {
    auto offsets = asImpl().getNonFixedOffsets(IGF);
    for (auto &field : getFields()) {
      if (field.isEmpty()) continue;

      Address fieldAddr = field.projectAddress(IGF, addr, offsets);
      (cast<LoadableTypeInfo>(field.getTypeInfo()).*Op)(IGF, fieldAddr, out,
                                                        atomicity);
    }
  }

  template <void (LoadableTypeInfo::*Op)(IRGenFunction &IGF, Explosion &in,
                                         Address addr, bool isOutlined) const>
  void forAllFields(IRGenFunction &IGF, Explosion &in, Address addr,
                    bool isOutlined) const {
    auto offsets = asImpl().getNonFixedOffsets(IGF);
    for (auto &field : getFields()) {
      if (field.isEmpty()) continue;

      Address fieldAddr = field.projectAddress(IGF, addr, offsets);
      (cast<LoadableTypeInfo>(field.getTypeInfo()).*Op)(IGF, in, fieldAddr,
                                                        isOutlined);
    }
  }

public:
  using super::getFields;

  void loadAsCopy(IRGenFunction &IGF, Address addr,
                  Explosion &out) const override {
    forAllFields<&LoadableTypeInfo::loadAsCopy>(IGF, addr, out);
  }

  void loadAsTake(IRGenFunction &IGF, Address addr,
                  Explosion &out) const override {
    forAllFields<&LoadableTypeInfo::loadAsTake>(IGF, addr, out);
  }

  void assign(IRGenFunction &IGF, Explosion &e, Address addr,
              bool isOutlined) const override {
    forAllFields<&LoadableTypeInfo::assign>(IGF, e, addr, isOutlined);
  }

  void initialize(IRGenFunction &IGF, Explosion &e, Address addr,
                  bool isOutlined) const override {
    forAllFields<&LoadableTypeInfo::initialize>(IGF, e, addr, isOutlined);
  }

  unsigned getExplosionSize() const override {
    return ExplosionSize;
  }

  void reexplode(IRGenFunction &IGF, Explosion &src,
                 Explosion &dest) const override {
    for (auto &field : getFields())
      cast<LoadableTypeInfo>(field.getTypeInfo()).reexplode(IGF, src, dest);
  }

  void copy(IRGenFunction &IGF, Explosion &src,
            Explosion &dest, Atomicity atomicity) const override {
    for (auto &field : getFields())
      cast<LoadableTypeInfo>(field.getTypeInfo())
          .copy(IGF, src, dest, atomicity);
  }

  void consume(IRGenFunction &IGF, Explosion &src,
               Atomicity atomicity) const override {
    for (auto &field : getFields())
      cast<LoadableTypeInfo>(field.getTypeInfo())
          .consume(IGF, src, atomicity);
  }

  void fixLifetime(IRGenFunction &IGF, Explosion &src) const override {
    for (auto &field : getFields())
      cast<LoadableTypeInfo>(field.getTypeInfo()).fixLifetime(IGF, src);
  }
  
  void packIntoEnumPayload(IRGenFunction &IGF,
                           EnumPayload &payload,
                           Explosion &src,
                           unsigned startOffset) const override {
    for (auto &field : getFields()) {
      if (field.getKind() != ElementLayout::Kind::Empty) {
        unsigned offset = field.getFixedByteOffset().getValueInBits()
          + startOffset;
        cast<LoadableTypeInfo>(field.getTypeInfo())
          .packIntoEnumPayload(IGF, payload, src, offset);
      }
    }
  }
  
  void unpackFromEnumPayload(IRGenFunction &IGF, const EnumPayload &payload,
                             Explosion &dest, unsigned startOffset)
                            const override {
    for (auto &field : getFields()) {
      if (field.getKind() != ElementLayout::Kind::Empty) {
        unsigned offset = field.getFixedByteOffset().getValueInBits()
          + startOffset;
        cast<LoadableTypeInfo>(field.getTypeInfo())
          .unpackFromEnumPayload(IGF, payload, dest, offset);
      }
    }
  }
};

/// A builder of record types.
///
/// Required for a full implementation:
///   TypeInfoImpl *construct(void *buffer, ArrayRef<ASTField> fields);
///   FieldImpl getFieldInfo(const ASTField &field, const TypeInfo &fieldTI);
///   Type getType(const ASTField &field);
///   void performLayout(ArrayRef<const TypeInfo *> fieldTypes);
///     - should call recordLayout with the layout
template <class BuilderImpl, class FieldImpl, class ASTField>
class RecordTypeBuilder {
protected:
  IRGenModule &IGM;
  RecordTypeBuilder(IRGenModule &IGM) : IGM(IGM) {}

  BuilderImpl *asImpl() { return static_cast<BuilderImpl*>(this); }

public:
  TypeInfo *layout(ArrayRef<ASTField> astFields) {
    SmallVector<FieldImpl, 8> fields;
    SmallVector<const TypeInfo *, 8> fieldTypesForLayout;
    fields.reserve(astFields.size());
    fieldTypesForLayout.reserve(astFields.size());

    bool loadable = true;
    auto fieldsABIAccessible = FieldsAreABIAccessible;

    unsigned explosionSize = 0;
    for (unsigned i : indices(astFields)) {
      auto &astField = astFields[i];
      // Compute the field's type info.
      auto &fieldTI = IGM.getTypeInfo(asImpl()->getType(astField));
      fieldTypesForLayout.push_back(&fieldTI);

      if (!fieldTI.isABIAccessible())
        fieldsABIAccessible = FieldsAreNotABIAccessible;

      fields.push_back(FieldImpl(asImpl()->getFieldInfo(i, astField, fieldTI)));

      auto loadableFieldTI = dyn_cast<LoadableTypeInfo>(&fieldTI);
      if (!loadableFieldTI) {
        loadable = false;
        continue;
      }

      auto &fieldInfo = fields.back();
      fieldInfo.Begin = explosionSize;
      explosionSize += loadableFieldTI->getExplosionSize();
      fieldInfo.End = explosionSize;
    }

    // Perform layout and fill in the fields.
    StructLayout layout = asImpl()->performLayout(fieldTypesForLayout);
    for (unsigned i = 0, e = fields.size(); i != e; ++i) {
      fields[i].completeFrom(layout.getElements()[i]);
    }

    // Create the type info.
    if (loadable) {
      assert(layout.isFixedLayout());
      assert(fieldsABIAccessible);
      return asImpl()->createLoadable(fields, std::move(layout), explosionSize);
    } else if (layout.isFixedLayout()) {
      assert(fieldsABIAccessible);
      return asImpl()->createFixed(fields, std::move(layout));
    } else {
      return asImpl()->createNonFixed(fields, fieldsABIAccessible,
                                      std::move(layout));
    }
  }  
};

} // end namespace irgen
} // end namespace swift

#endif
