Skip to content

Commit bdd68df

Browse files
Merge pull request #27704 from apple/fix_memory_offset_of_tail_allocated_c_array
IRGen: Fix MemoryLayout::offset(of:) for tail allocated C arrays
2 parents f95a68a + 7a54927 commit bdd68df

File tree

9 files changed

+51
-3
lines changed

9 files changed

+51
-3
lines changed

lib/IRGen/GenHeap.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ HeapNonFixedOffsets::HeapNonFixedOffsets(IRGenFunction &IGF,
317317
elt.getType().getAlignmentMask(IGF, eltTy));
318318
LLVM_FALLTHROUGH;
319319
case ElementLayout::Kind::Empty:
320+
case ElementLayout::Kind::EmptyTailAllocatedCType:
320321
case ElementLayout::Kind::Fixed:
321322
// Don't need to dynamically calculate this offset.
322323
Offsets.push_back(nullptr);

lib/IRGen/GenStruct.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ namespace {
185185
switch (fieldInfo.getKind()) {
186186
case ElementLayout::Kind::Fixed:
187187
case ElementLayout::Kind::Empty:
188+
case ElementLayout::Kind::EmptyTailAllocatedCType:
188189
return MemberAccessStrategy::getDirectFixed(
189190
fieldInfo.getFixedByteOffset());
190191
case ElementLayout::Kind::InitialNonFixedSize:
@@ -278,6 +279,7 @@ namespace {
278279
break;
279280
}
280281
case ElementLayout::Kind::Empty:
282+
case ElementLayout::Kind::EmptyTailAllocatedCType:
281283
case ElementLayout::Kind::InitialNonFixedSize:
282284
case ElementLayout::Kind::NonFixed:
283285
continue;
@@ -789,7 +791,8 @@ class ClangRecordLowering {
789791
ElementLayout layout = ElementLayout::getIncomplete(fieldType);
790792
auto isEmpty = fieldType.isKnownEmpty(ResilienceExpansion::Maximal);
791793
if (isEmpty)
792-
layout.completeEmpty(fieldType.isPOD(ResilienceExpansion::Maximal));
794+
layout.completeEmptyTailAllocatedCType(
795+
fieldType.isPOD(ResilienceExpansion::Maximal), NextOffset);
793796
else
794797
layout.completeFixed(fieldType.isPOD(ResilienceExpansion::Maximal),
795798
NextOffset, LLVMFields.size());

lib/IRGen/GenTuple.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ namespace {
149149
const TupleFieldInfo &field = asImpl().getFields()[fieldNo];
150150
switch (field.getKind()) {
151151
case ElementLayout::Kind::Empty:
152+
case ElementLayout::Kind::EmptyTailAllocatedCType:
152153
case ElementLayout::Kind::Fixed:
153154
return field.getFixedByteOffset();
154155
case ElementLayout::Kind::InitialNonFixedSize:
@@ -194,6 +195,7 @@ namespace {
194195
}
195196

196197
case ElementLayout::Kind::Empty:
198+
case ElementLayout::Kind::EmptyTailAllocatedCType:
197199
case ElementLayout::Kind::InitialNonFixedSize:
198200
case ElementLayout::Kind::NonFixed:
199201
continue;

lib/IRGen/StructLayout.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ Address ElementLayout::project(IRGenFunction &IGF, Address baseAddr,
156156
const llvm::Twine &suffix) const {
157157
switch (getKind()) {
158158
case Kind::Empty:
159+
case Kind::EmptyTailAllocatedCType:
159160
return getType().getUndefAddress();
160161

161162
case Kind::Fixed:

lib/IRGen/StructLayout.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ class ElementLayout {
8484
/// Its offset in the aggregate is always statically zero.
8585
Empty,
8686

87+
/// The element is known to require no storage in the aggregate.
88+
/// But it has an offset in the aggregate. This is to support getting the
89+
/// offset of tail allocated storage using MemoryLayout<>.offset(of:).
90+
EmptyTailAllocatedCType,
91+
8792
/// The element can be positioned at a fixed offset within the
8893
/// aggregate.
8994
Fixed,
@@ -163,6 +168,15 @@ class ElementLayout {
163168
assert(getByteOffset() == byteOffset);
164169
}
165170

171+
void completeEmptyTailAllocatedCType(IsPOD_t isPOD, Size byteOffset) {
172+
TheKind = unsigned(Kind::EmptyTailAllocatedCType);
173+
IsPOD = unsigned(isPOD);
174+
ByteOffset = byteOffset.getValue();
175+
Index = 0;
176+
177+
assert(getByteOffset() == byteOffset);
178+
}
179+
166180
/// Complete this element layout with a non-fixed offset.
167181
///
168182
/// \param nonFixedElementIndex - the index into the elements array
@@ -181,7 +195,8 @@ class ElementLayout {
181195

182196
/// Is this element known to be empty?
183197
bool isEmpty() const {
184-
return getKind() == Kind::Empty;
198+
return getKind() == Kind::Empty ||
199+
getKind() == Kind::EmptyTailAllocatedCType;
185200
}
186201

187202
/// Is this element known to be POD?
@@ -194,6 +209,7 @@ class ElementLayout {
194209
bool hasByteOffset() const {
195210
switch (getKind()) {
196211
case Kind::Empty:
212+
case Kind::EmptyTailAllocatedCType:
197213
case Kind::Fixed:
198214
return true;
199215

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <stdint.h>
2+
3+
typedef struct foo {
4+
uint8_t a;
5+
uint16_t b;
6+
uint8_t tailallocatedarray[0];
7+
} foo;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %target-swift-frontend -import-objc-header %S/Inputs/tail_allocated_c_array.h -primary-file %s -emit-ir -o - | %FileCheck %s
2+
3+
// 25165828 = 0x1800004 The bottom bits designate the offset = 4
4+
// CHECK: @keypath = private global <{{.*}}i32 0, i32 -2147483644, i32 25165828 }>
5+
6+
_ = MemoryLayout<foo>.offset(of: \foo.tailallocatedarray)!
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include <stdint.h>
2+
3+
typedef struct foo {
4+
uint8_t a;
5+
uint16_t b;
6+
uint8_t tailallocatedarray[0];
7+
} foo;

test/stdlib/KeyPath.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-build-swift -swift-version 5 -g %s -o %t/a.out
2+
// RUN: %target-build-swift -import-objc-header %S/Inputs/tail_allocated_c_array.h -swift-version 5 -g %s -o %t/a.out
33
// RUN: %target-codesign %t/a.out
44
// RUN: %target-run %t/a.out
55
// REQUIRES: executable_test
@@ -1019,5 +1019,10 @@ keyPath.test("nested generics") {
10191019
expectTrue(nestedKeyPath is KeyPath<DictType, DictType.Values>)
10201020
}
10211021

1022+
keyPath.test("tail allocated c array") {
1023+
let offset = MemoryLayout<foo>.offset(of: \foo.tailallocatedarray)!
1024+
expectEqual(4, offset)
1025+
}
1026+
10221027
runAllTests()
10231028

0 commit comments

Comments
 (0)