Skip to content

Commit

Permalink
Merge pull request swiftlang#11671 from eeckstein/fix-static-init
Browse files Browse the repository at this point in the history
IRGen: fix statically initialized globals which contain an empty type.
  • Loading branch information
eeckstein authored Aug 29, 2017
2 parents d51f1b8 + 9050157 commit 1d83366
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 19 deletions.
14 changes: 8 additions & 6 deletions lib/IRGen/GenConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsigned> 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);
Expand All @@ -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,
Expand Down
7 changes: 4 additions & 3 deletions lib/IRGen/GenKeyPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsigned> 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
Expand Down
15 changes: 12 additions & 3 deletions lib/IRGen/GenStruct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ namespace {
return fieldInfo.getStructIndex();
}

Optional<unsigned> 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 {
Expand Down Expand Up @@ -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<unsigned> irgen::getPhysicalStructFieldIndex(IRGenModule &IGM,
SILType baseType,
VarDecl *field) {
FOR_STRUCT_IMPL(IGM, baseType, getFieldIndexIfNotEmpty, field);
}

void IRGenModule::emitStructDecl(StructDecl *st) {
Expand Down
12 changes: 10 additions & 2 deletions lib/IRGen/GenStruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#ifndef SWIFT_IRGEN_GENSTRUCT_H
#define SWIFT_IRGEN_GENSTRUCT_H

#include "llvm/ADT/Optional.h"

namespace llvm {
class Constant;
}
Expand Down Expand Up @@ -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<unsigned> getPhysicalStructFieldIndex(IRGenModule &IGM,
SILType baseType,
VarDecl *field);

} // end namespace irgen
} // end namespace swift
Expand Down
10 changes: 7 additions & 3 deletions lib/IRGen/GenTuple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,11 @@ namespace {
llvm_unreachable("bad element layout kind");
}

unsigned getElementStructIndex(IRGenModule &IGM, unsigned fieldNo) const {
Optional<unsigned> getElementStructIndex(IRGenModule &IGM,
unsigned fieldNo) const {
const TupleFieldInfo &field = asImpl().getFields()[fieldNo];
if (field.isEmpty())
return None;
return field.getStructIndex();
}

Expand Down Expand Up @@ -412,7 +415,8 @@ Optional<Size> irgen::getFixedTupleElementOffset(IRGenModule &IGM,
FOR_TUPLE_IMPL(IGM, tupleType, getFixedElementOffset, fieldNo);
}

unsigned irgen::getTupleElementStructIndex(IRGenModule &IGM, SILType tupleType,
unsigned fieldNo) {
Optional<unsigned> irgen::getPhysicalTupleElementStructIndex(IRGenModule &IGM,
SILType tupleType,
unsigned fieldNo) {
FOR_TUPLE_IMPL(IGM, tupleType, getElementStructIndex, fieldNo);
}
10 changes: 8 additions & 2 deletions lib/IRGen/GenTuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsigned> getPhysicalTupleElementStructIndex(IRGenModule &IGM,
SILType tupleType,
unsigned fieldNo);
} // end namespace irgen
} // end namespace swift

Expand Down
33 changes: 33 additions & 0 deletions test/SILOptimizer/global_init_with_empty.swift
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit 1d83366

Please sign in to comment.