diff --git a/lib/IRGen/GenConstant.cpp b/lib/IRGen/GenConstant.cpp index 906ff1abaa6f8..ee2f84ac2e251 100644 --- a/lib/IRGen/GenConstant.cpp +++ b/lib/IRGen/GenConstant.cpp @@ -115,12 +115,13 @@ llvm::Constant *emitConstantStructOrTuple(IRGenModule &IGM, InstTy inst, // appropriate. for (unsigned i = 0, e = inst->getElements().size(); i != e; i++) { auto operand = inst->getOperand(i); - unsigned index = nextIndex(IGM, type, i); + Optional index = nextIndex(IGM, type, i); + if (index.hasValue()) { + assert(elts[index.getValue()] == nullptr && + "Unexpected constant struct field overlap"); - assert(elts[index] == nullptr && - "Unexpected constant struct field overlap"); - - elts[index] = emitConstantValue(IGM, operand); + elts[index.getValue()] = emitConstantValue(IGM, operand); + } } insertPadding(elts, sTy); return llvm::ConstantStruct::get(sTy, elts); @@ -144,7 +145,8 @@ llvm::Constant *irgen::emitConstantStruct(IRGenModule &IGM, StructInst *SI) { } llvm::Constant *irgen::emitConstantTuple(IRGenModule &IGM, TupleInst *TI) { - return emitConstantStructOrTuple(IGM, TI, irgen::getTupleElementStructIndex); + return emitConstantStructOrTuple(IGM, TI, + irgen::getPhysicalTupleElementStructIndex); } llvm::Constant *irgen::emitConstantObject(IRGenModule &IGM, ObjectInst *OI, diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp index ce511701cc5e2..d58f606cb0bc0 100644 --- a/lib/IRGen/GenKeyPath.cpp +++ b/lib/IRGen/GenKeyPath.cpp @@ -541,9 +541,10 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern, idKind = KeyPathComponentHeader::StoredPropertyIndex; if (baseTy->getStructOrBoundGenericStruct()) { idResolved = true; - idValue = llvm::ConstantInt::get(SizeTy, - getPhysicalStructFieldIndex(*this, - SILType::getPrimitiveAddressType(baseTy), property)); + Optional structIdx = getPhysicalStructFieldIndex(*this, + SILType::getPrimitiveAddressType(baseTy), property); + assert(structIdx.hasValue() && "empty property"); + idValue = llvm::ConstantInt::get(SizeTy, structIdx.getValue()); } else if (baseTy->getClassOrBoundGenericClass()) { // TODO: This field index would require runtime resolution with Swift // native class resilience. We never directly access ObjC-imported diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp index 1c7d00c701319..d369aa8d8283d 100644 --- a/lib/IRGen/GenStruct.cpp +++ b/lib/IRGen/GenStruct.cpp @@ -192,6 +192,14 @@ namespace { return fieldInfo.getStructIndex(); } + Optional getFieldIndexIfNotEmpty(IRGenModule &IGM, + VarDecl *field) const { + auto &fieldInfo = getFieldInfo(field); + if (fieldInfo.isEmpty()) + return None; + return fieldInfo.getStructIndex(); + } + // For now, just use extra inhabitants from the first field. // FIXME: generalize bool mayHaveExtraInhabitants(IRGenModule &IGM) const override { @@ -760,9 +768,10 @@ irgen::getPhysicalStructMemberAccessStrategy(IRGenModule &IGM, FOR_STRUCT_IMPL(IGM, baseType, getFieldAccessStrategy, baseType, field); } -unsigned irgen::getPhysicalStructFieldIndex(IRGenModule &IGM, SILType baseType, - VarDecl *field) { - FOR_STRUCT_IMPL(IGM, baseType, getFieldIndex, field); +Optional irgen::getPhysicalStructFieldIndex(IRGenModule &IGM, + SILType baseType, + VarDecl *field) { + FOR_STRUCT_IMPL(IGM, baseType, getFieldIndexIfNotEmpty, field); } void IRGenModule::emitStructDecl(StructDecl *st) { diff --git a/lib/IRGen/GenStruct.h b/lib/IRGen/GenStruct.h index 7d0c1f8ab4296..c3212a32c08fc 100644 --- a/lib/IRGen/GenStruct.h +++ b/lib/IRGen/GenStruct.h @@ -17,6 +17,8 @@ #ifndef SWIFT_IRGEN_GENSTRUCT_H #define SWIFT_IRGEN_GENSTRUCT_H +#include "llvm/ADT/Optional.h" + namespace llvm { class Constant; } @@ -56,8 +58,14 @@ namespace irgen { getPhysicalStructMemberAccessStrategy(IRGenModule &IGM, SILType baseType, VarDecl *field); - unsigned getPhysicalStructFieldIndex(IRGenModule &IGM, SILType baseType, - VarDecl *field); + /// Returns the index of the element in the llvm struct type which represents + /// \p field in \p baseType. + /// + /// Returns None if \p field has an empty type and therefore has no + /// corresponding element in the llvm type. + llvm::Optional getPhysicalStructFieldIndex(IRGenModule &IGM, + SILType baseType, + VarDecl *field); } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/GenTuple.cpp b/lib/IRGen/GenTuple.cpp index 06a38807a9ffd..0d2d73362885d 100644 --- a/lib/IRGen/GenTuple.cpp +++ b/lib/IRGen/GenTuple.cpp @@ -129,8 +129,11 @@ namespace { llvm_unreachable("bad element layout kind"); } - unsigned getElementStructIndex(IRGenModule &IGM, unsigned fieldNo) const { + Optional getElementStructIndex(IRGenModule &IGM, + unsigned fieldNo) const { const TupleFieldInfo &field = asImpl().getFields()[fieldNo]; + if (field.isEmpty()) + return None; return field.getStructIndex(); } @@ -412,7 +415,8 @@ Optional irgen::getFixedTupleElementOffset(IRGenModule &IGM, FOR_TUPLE_IMPL(IGM, tupleType, getFixedElementOffset, fieldNo); } -unsigned irgen::getTupleElementStructIndex(IRGenModule &IGM, SILType tupleType, - unsigned fieldNo) { +Optional irgen::getPhysicalTupleElementStructIndex(IRGenModule &IGM, + SILType tupleType, + unsigned fieldNo) { FOR_TUPLE_IMPL(IGM, tupleType, getElementStructIndex, fieldNo); } diff --git a/lib/IRGen/GenTuple.h b/lib/IRGen/GenTuple.h index 953b0d5f6729c..ee2e1a99f395e 100644 --- a/lib/IRGen/GenTuple.h +++ b/lib/IRGen/GenTuple.h @@ -48,8 +48,14 @@ namespace irgen { SILType tupleType, unsigned fieldNo); - unsigned getTupleElementStructIndex(IRGenModule &IGM, SILType tupleType, - unsigned fieldNo); + /// Returns the index of the element in the llvm struct type which represents + /// \p fieldNo in \p tupleType. + /// + /// Returns None if the tuple element is an empty type and therefore has no + /// corresponding element in the llvm type. + Optional getPhysicalTupleElementStructIndex(IRGenModule &IGM, + SILType tupleType, + unsigned fieldNo); } // end namespace irgen } // end namespace swift diff --git a/test/SILOptimizer/global_init_with_empty.swift b/test/SILOptimizer/global_init_with_empty.swift new file mode 100644 index 0000000000000..be427479dce29 --- /dev/null +++ b/test/SILOptimizer/global_init_with_empty.swift @@ -0,0 +1,33 @@ +// RUN: %target-swift-frontend -primary-file %s -O -module-name=test -emit-ir | %FileCheck %s + +// Also do an end-to-end test. +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -O -module-name=test %s -o %t/a.out +// RUN: %target-run %t/a.out | %FileCheck %s -check-prefix=CHECK-OUTPUT +// REQUIRES: executable_test,optimized_stdlib + +struct Empty { } + +struct Mystruct { + var a: Int + var b: Empty + var c: Int + + // CHECK: @{{[^ ]*structglobal[^ ]*}} = hidden global %{{[^ ]*}} <{ %TSi <{ i{{[0-9]+}} 3 }>, %TSi <{ i{{[0-9]+}} 4 }> }> + static var structglobal = Mystruct(a: 3, b: Empty(), c: 4) + // CHECK: @{{[^ ]*tupleglobal[^ ]*}} = hidden global <{ %TSi, %TSi }> <{ %TSi <{ i{{[0-9]+}} 5 }>, %TSi <{ i{{[0-9]+}} 6 }> }> + static var tupleglobal = (a: 5, b: Empty(), c: 6) +} + +// CHECK-OUTPUT: 3 +print(Mystruct.structglobal.a) +// CHECK-OUTPUT-NEXT: Empty() +print(Mystruct.structglobal.b) +// CHECK-OUTPUT-NEXT: 4 +print(Mystruct.structglobal.c) +// CHECK-OUTPUT-NEXT: 5 +print(Mystruct.tupleglobal.a) +// CHECK-OUTPUT-NEXT: Empty() +print(Mystruct.tupleglobal.b) +// CHECK-OUTPUT-NEXT: 6 +print(Mystruct.tupleglobal.c)