//===--- GenTuple.cpp - Swift IR Generation For Tuple Types ---------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements IR generation for tuple types in Swift. This // includes creating the IR type as well as emitting the primitive access // operations. // // It is assumed in several places in IR-generation that the // explosion schema of a tuple type is always equal to the appended // explosion schemas of the component types. // //===----------------------------------------------------------------------===// #include "swift/AST/Types.h" #include "swift/AST/Decl.h" #include "swift/AST/Pattern.h" #include "swift/SIL/SILType.h" #include "swift/Basic/Optional.h" #include "llvm/IR/DerivedTypes.h" #include "ASTVisitor.h" #include "GenHeap.h" #include "GenSequential.h" #include "GenType.h" #include "IRGenFunction.h" #include "IRGenModule.h" #include "Explosion.h" #include "NonFixedTypeInfo.h" #include "GenTuple.h" using namespace swift; using namespace irgen; namespace { class TupleFieldInfo : public SequentialField { public: TupleFieldInfo(const TupleTypeElt &field, const TypeInfo &type) : SequentialField(type), Field(field) {} /// The field. const TupleTypeElt &Field; StringRef getFieldName() const { if (Field.hasName()) return Field.getName().str(); return "elt"; } }; /// Adapter for tuple types. template class TupleTypeInfoBase : public SequentialTypeInfo { typedef SequentialTypeInfo super; protected: template TupleTypeInfoBase(As &&...args) : super(std::forward(args)...) {} using super::asImpl; public: /// Given a full tuple explosion, project out a single element. void projectElementFromExplosion(IRGenFunction &IGF, Explosion &tuple, unsigned fieldNo, Explosion &out) const { assert(tuple.getKind() == out.getKind()); const TupleFieldInfo &field = asImpl().getFields()[fieldNo]; // If the field requires no storage, there's nothing to do. if (field.isEmpty()) return IGF.emitFakeExplosion(field.getTypeInfo(), out); // Otherwise, project from the base. auto fieldRange = field.getProjectionRange(out.getKind()); ArrayRef element = tuple.getRange(fieldRange.first, fieldRange.second); out.add(element); } /// Given the address of a tuple, project out the address of a /// single element. OwnedAddress projectElementAddress(IRGenFunction &IGF, OwnedAddress tuple, unsigned fieldNo) const { const TupleFieldInfo &field = asImpl().getFields()[fieldNo]; if (field.isEmpty()) return {field.getTypeInfo().getUndefAddress(), nullptr}; auto offsets = asImpl().getNonFixedOffsets(IGF); Address fieldAddr = field.projectAddress(IGF, tuple.getAddress(), offsets); return {fieldAddr, tuple.getOwner()}; } }; /// Type implementation for fixed-size tuples. class FixedTupleTypeInfo : public TupleTypeInfoBase { public: FixedTupleTypeInfo(unsigned numFields, llvm::Type *ty, Size size, Alignment align, IsPOD_t isPOD) : TupleTypeInfoBase(numFields, ty, size, align, isPOD) {} Nothing_t getNonFixedOffsets(IRGenFunction &IGF) const { return Nothing; } }; /// An accessor for the non-fixed offsets for a tuple type. class TupleNonFixedOffsets : public NonFixedOffsetsImpl { CanType TheType; public: TupleNonFixedOffsets(CanType type) : TheType(type) { assert(isa(TheType)); } llvm::Value *getOffsetForIndex(IRGenFunction &IGF, unsigned index) { // Fetch the metadata as a tuple type. We cache this because // we might repeatedly need the bitcast. auto metadata = IGF.emitTypeMetadataRef(TheType); auto asTuple = IGF.Builder.CreateBitCast(metadata, IGF.IGM.TupleTypeMetadataPtrTy); llvm::Value *indices[] = { IGF.IGM.getSize(Size(0)), // (*tupleType) llvm::ConstantInt::get(IGF.IGM.Int32Ty, 3), // .Elements IGF.IGM.getSize(Size(index)), // [index] llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1) // .Offset }; auto slot = IGF.Builder.CreateInBoundsGEP(asTuple, indices); return IGF.Builder.CreateLoad(slot, IGF.IGM.getPointerAlignment(), metadata->getName() + "." + Twine(index) + ".offset"); } }; /// Type implementation for non-fixed-size tuples. class NonFixedTupleTypeInfo : public TupleTypeInfoBase > { CanType TheType; public: NonFixedTupleTypeInfo(unsigned numFields, llvm::Type *T, CanType type, Alignment minAlign, IsPOD_t isPOD) : TupleTypeInfoBase(numFields, T, minAlign, isPOD), TheType(type) {} TupleNonFixedOffsets getNonFixedOffsets(IRGenFunction &IGF) const { return TupleNonFixedOffsets(TheType); } llvm::Value *getMetadataRef(IRGenFunction &IGF) const { return IGF.emitTypeMetadataRef(TheType); } llvm::Value *getValueWitnessTable(IRGenFunction &IGF) const { auto metadata = getMetadataRef(IGF); return IGF.emitValueWitnessTableRefForMetadata(metadata); } }; class TupleTypeBuilder : public SequentialTypeBuilder { CanType TheTuple; public: TupleTypeBuilder(IRGenModule &IGM, CanType theTuple) : SequentialTypeBuilder(IGM), TheTuple(theTuple) {} FixedTupleTypeInfo *createFixed(ArrayRef fields, const StructLayout &layout) { return create(fields, layout.getType(), layout.getSize(), layout.getAlignment(), layout.isKnownPOD()); } NonFixedTupleTypeInfo *createNonFixed(ArrayRef fields, const StructLayout &layout) { return create(fields, layout.getType(), TheTuple, layout.getAlignment(), layout.isKnownPOD()); } TupleFieldInfo getFieldInfo(const TupleTypeElt &field, const TypeInfo &fieldTI) { return TupleFieldInfo(field, fieldTI); } Type getType(const TupleTypeElt &field) { return field.getType(); } StructLayout performLayout(ArrayRef fieldTypes) { return StructLayout(IGM, LayoutKind::NonHeapObject, LayoutStrategy::Universal, fieldTypes); } }; } const TypeInfo *TypeConverter::convertTupleType(TupleType *tuple) { TupleTypeBuilder builder(IGM, CanType(tuple)); return builder.layout(tuple->getFields()); } /// A convenient macro for delegating an operation to all of the /// various tuple implementations. #define FOR_TUPLE_IMPL(IGF, type, op, ...) do { \ auto &tupleTI = IGF.getFragileTypeInfo(type); \ if (isa(tupleTI)) { \ return tupleTI.as().op(IGF, __VA_ARGS__); \ } else { \ return tupleTI.as().op(IGF, __VA_ARGS__); \ } \ } while(0) void irgen::projectTupleElementFromExplosion(IRGenFunction &IGF, SILType tupleType, Explosion &tuple, unsigned fieldNo, Explosion &out) { FOR_TUPLE_IMPL(IGF, tupleType.getSwiftRValueType(), projectElementFromExplosion, tuple, fieldNo, out); } OwnedAddress irgen::projectTupleElementAddress(IRGenFunction &IGF, OwnedAddress tuple, SILType tupleType, unsigned fieldNo) { FOR_TUPLE_IMPL(IGF, tupleType.getSwiftRValueType(), projectElementAddress, tuple, fieldNo); } /// Emit a string literal, either as a C string pointer or as a (pointer, size) /// tuple. // FIXME: Why is this here? void swift::irgen::emitStringLiteral(IRGenFunction &IGF, StringRef string, bool includeSize, Explosion &out) { auto ptr = IGF.IGM.getAddrOfGlobalString(string); out.add(ptr); if (includeSize) out.add(IGF.Builder.getInt64(string.size())); }