Skip to content

IRGen: Fix MemoryLayout::offset(of:) for tail allocated C arrays #27704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/IRGen/GenHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ HeapNonFixedOffsets::HeapNonFixedOffsets(IRGenFunction &IGF,
elt.getType().getAlignmentMask(IGF, eltTy));
LLVM_FALLTHROUGH;
case ElementLayout::Kind::Empty:
case ElementLayout::Kind::EmptyTailAllocatedCType:
case ElementLayout::Kind::Fixed:
// Don't need to dynamically calculate this offset.
Offsets.push_back(nullptr);
Expand Down
5 changes: 4 additions & 1 deletion lib/IRGen/GenStruct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ namespace {
switch (fieldInfo.getKind()) {
case ElementLayout::Kind::Fixed:
case ElementLayout::Kind::Empty:
case ElementLayout::Kind::EmptyTailAllocatedCType:
return MemberAccessStrategy::getDirectFixed(
fieldInfo.getFixedByteOffset());
case ElementLayout::Kind::InitialNonFixedSize:
Expand Down Expand Up @@ -278,6 +279,7 @@ namespace {
break;
}
case ElementLayout::Kind::Empty:
case ElementLayout::Kind::EmptyTailAllocatedCType:
case ElementLayout::Kind::InitialNonFixedSize:
case ElementLayout::Kind::NonFixed:
continue;
Expand Down Expand Up @@ -789,7 +791,8 @@ class ClangRecordLowering {
ElementLayout layout = ElementLayout::getIncomplete(fieldType);
auto isEmpty = fieldType.isKnownEmpty(ResilienceExpansion::Maximal);
if (isEmpty)
layout.completeEmpty(fieldType.isPOD(ResilienceExpansion::Maximal));
layout.completeEmptyTailAllocatedCType(
fieldType.isPOD(ResilienceExpansion::Maximal), NextOffset);
else
layout.completeFixed(fieldType.isPOD(ResilienceExpansion::Maximal),
NextOffset, LLVMFields.size());
Expand Down
2 changes: 2 additions & 0 deletions lib/IRGen/GenTuple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ namespace {
const TupleFieldInfo &field = asImpl().getFields()[fieldNo];
switch (field.getKind()) {
case ElementLayout::Kind::Empty:
case ElementLayout::Kind::EmptyTailAllocatedCType:
case ElementLayout::Kind::Fixed:
return field.getFixedByteOffset();
case ElementLayout::Kind::InitialNonFixedSize:
Expand Down Expand Up @@ -194,6 +195,7 @@ namespace {
}

case ElementLayout::Kind::Empty:
case ElementLayout::Kind::EmptyTailAllocatedCType:
case ElementLayout::Kind::InitialNonFixedSize:
case ElementLayout::Kind::NonFixed:
continue;
Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/StructLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ Address ElementLayout::project(IRGenFunction &IGF, Address baseAddr,
const llvm::Twine &suffix) const {
switch (getKind()) {
case Kind::Empty:
case Kind::EmptyTailAllocatedCType:
return getType().getUndefAddress();

case Kind::Fixed:
Expand Down
18 changes: 17 additions & 1 deletion lib/IRGen/StructLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ class ElementLayout {
/// Its offset in the aggregate is always statically zero.
Empty,

/// The element is known to require no storage in the aggregate.
/// But it has an offset in the aggregate. This is to support getting the
/// offset of tail allocated storage using MemoryLayout<>.offset(of:).
EmptyTailAllocatedCType,

/// The element can be positioned at a fixed offset within the
/// aggregate.
Fixed,
Expand Down Expand Up @@ -163,6 +168,15 @@ class ElementLayout {
assert(getByteOffset() == byteOffset);
}

void completeEmptyTailAllocatedCType(IsPOD_t isPOD, Size byteOffset) {
TheKind = unsigned(Kind::EmptyTailAllocatedCType);
IsPOD = unsigned(isPOD);
ByteOffset = byteOffset.getValue();
Index = 0;

assert(getByteOffset() == byteOffset);
}

/// Complete this element layout with a non-fixed offset.
///
/// \param nonFixedElementIndex - the index into the elements array
Expand All @@ -181,7 +195,8 @@ class ElementLayout {

/// Is this element known to be empty?
bool isEmpty() const {
return getKind() == Kind::Empty;
return getKind() == Kind::Empty ||
getKind() == Kind::EmptyTailAllocatedCType;
}

/// Is this element known to be POD?
Expand All @@ -194,6 +209,7 @@ class ElementLayout {
bool hasByteOffset() const {
switch (getKind()) {
case Kind::Empty:
case Kind::EmptyTailAllocatedCType:
case Kind::Fixed:
return true;

Expand Down
7 changes: 7 additions & 0 deletions test/IRGen/Inputs/tail_allocated_c_array.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <stdint.h>

typedef struct foo {
uint8_t a;
uint16_t b;
uint8_t tailallocatedarray[0];
} foo;
6 changes: 6 additions & 0 deletions test/IRGen/tail_allocated_c_array.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// RUN: %target-swift-frontend -import-objc-header %S/Inputs/tail_allocated_c_array.h -primary-file %s -emit-ir -o - | %FileCheck %s

// 25165828 = 0x1800004 The bottom bits designate the offset = 4
// CHECK: @keypath = private global <{{.*}}i32 0, i32 -2147483644, i32 25165828 }>

_ = MemoryLayout<foo>.offset(of: \foo.tailallocatedarray)!
7 changes: 7 additions & 0 deletions test/stdlib/Inputs/tail_allocated_c_array.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <stdint.h>

typedef struct foo {
uint8_t a;
uint16_t b;
uint8_t tailallocatedarray[0];
} foo;
7 changes: 6 additions & 1 deletion test/stdlib/KeyPath.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -swift-version 5 -g %s -o %t/a.out
// RUN: %target-build-swift -import-objc-header %S/Inputs/tail_allocated_c_array.h -swift-version 5 -g %s -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out
// REQUIRES: executable_test
Expand Down Expand Up @@ -1019,5 +1019,10 @@ keyPath.test("nested generics") {
expectTrue(nestedKeyPath is KeyPath<DictType, DictType.Values>)
}

keyPath.test("tail allocated c array") {
let offset = MemoryLayout<foo>.offset(of: \foo.tailallocatedarray)!
expectEqual(4, offset)
}

runAllTests()