Skip to content

Commit 12d78cf

Browse files
Gwen Mittertreinergmittert
authored andcommitted
Use TypeLayout Structs instead of TypeInfo
When generating TypeLayouts, rather than using a Scalar Layout, use an aligned struct so that we use the typelayout path rather than the typeinfo path when doing irgen.
1 parent e94a871 commit 12d78cf

File tree

4 files changed

+190
-9
lines changed

4 files changed

+190
-9
lines changed

lib/IRGen/GenDiffFunc.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//===----------------------------------------------------------------------===//
1717

1818
#include "swift/AST/Decl.h"
19+
#include "swift/AST/IRGenOptions.h"
1920
#include "swift/AST/Pattern.h"
2021
#include "swift/AST/Types.h"
2122
#include "swift/SIL/SILModule.h"
@@ -118,7 +119,25 @@ class DifferentiableFuncTypeInfo final
118119

119120
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
120121
SILType T) const override {
121-
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
122+
if (!IGM.getOptions().ForceStructTypeLayouts || !areFieldsABIAccessible()) {
123+
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
124+
}
125+
126+
if (getFields().empty()) {
127+
return IGM.typeLayoutCache.getEmptyEntry();
128+
}
129+
130+
std::vector<TypeLayoutEntry *> fields;
131+
for (auto &field : getFields()) {
132+
auto fieldTy = field.getType(IGM, T);
133+
fields.push_back(field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy));
134+
}
135+
136+
if (fields.size() == 1) {
137+
return fields[0];
138+
}
139+
140+
return IGM.typeLayoutCache.getOrCreateAlignedGroupEntry(fields, 1);
122141
}
123142

124143
llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF) const { return None; }
@@ -272,7 +291,25 @@ class LinearFuncTypeInfo final
272291

273292
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
274293
SILType T) const override {
275-
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
294+
if (!IGM.getOptions().ForceStructTypeLayouts || !areFieldsABIAccessible()) {
295+
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
296+
}
297+
298+
if (getFields().empty()) {
299+
return IGM.typeLayoutCache.getEmptyEntry();
300+
}
301+
302+
std::vector<TypeLayoutEntry *> fields;
303+
for (auto &field : getFields()) {
304+
auto fieldTy = field.getType(IGM, T);
305+
fields.push_back(field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy));
306+
}
307+
308+
if (fields.size() == 1) {
309+
return fields[0];
310+
}
311+
312+
return IGM.typeLayoutCache.getOrCreateAlignedGroupEntry(fields, 1);
276313
}
277314

278315
llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF) const { return None; }

lib/IRGen/GenStruct.cpp

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,27 @@ namespace {
354354

355355
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
356356
SILType T) const override {
357-
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
357+
if (!IGM.getOptions().ForceStructTypeLayouts) {
358+
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
359+
}
360+
if (!areFieldsABIAccessible()) {
361+
return IGM.typeLayoutCache.getOrCreateResilientEntry(T);
362+
}
363+
364+
std::vector<TypeLayoutEntry *> fields;
365+
for (auto &field : getFields()) {
366+
auto fieldTy = field.getType(IGM, T);
367+
fields.push_back(
368+
field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy));
369+
}
370+
assert(!fields.empty() &&
371+
"Empty structs should not be LoadableClangRecordTypeInfo");
372+
373+
if (fields.size() == 1) {
374+
return fields[0];
375+
}
376+
377+
return IGM.typeLayoutCache.getOrCreateAlignedGroupEntry(fields, 1);
358378
}
359379

360380
void initializeFromParams(IRGenFunction &IGF, Explosion &params,
@@ -520,7 +540,25 @@ namespace {
520540

521541
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
522542
SILType T) const override {
523-
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
543+
if (!IGM.getOptions().ForceStructTypeLayouts || getCXXDestructor(T) ||
544+
!areFieldsABIAccessible()) {
545+
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
546+
}
547+
548+
std::vector<TypeLayoutEntry *> fields;
549+
for (auto &field : getFields()) {
550+
auto fieldTy = field.getType(IGM, T);
551+
fields.push_back(
552+
field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy));
553+
}
554+
assert(!fields.empty() &&
555+
"Empty structs should not be AddressOnlyRecordTypeInfo");
556+
557+
if (fields.size() == 1) {
558+
return fields[0];
559+
}
560+
561+
return IGM.typeLayoutCache.getOrCreateAlignedGroupEntry(fields, 1);
524562
}
525563

526564
void initializeFromParams(IRGenFunction &IGF, Explosion &params,
@@ -583,7 +621,30 @@ namespace {
583621

584622
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
585623
SILType T) const override {
586-
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
624+
if (!IGM.getOptions().ForceStructTypeLayouts) {
625+
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
626+
}
627+
628+
if (!areFieldsABIAccessible()) {
629+
return IGM.typeLayoutCache.getOrCreateResilientEntry(T);
630+
}
631+
632+
if (getFields().empty()) {
633+
return IGM.typeLayoutCache.getEmptyEntry();
634+
}
635+
636+
std::vector<TypeLayoutEntry *> fields;
637+
for (auto &field : getFields()) {
638+
auto fieldTy = field.getType(IGM, T);
639+
fields.push_back(
640+
field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy));
641+
}
642+
643+
if (fields.size() == 1) {
644+
return fields[0];
645+
}
646+
647+
return IGM.typeLayoutCache.getOrCreateAlignedGroupEntry(fields, 1);
587648
}
588649

589650
void initializeFromParams(IRGenFunction &IGF, Explosion &params,
@@ -622,7 +683,28 @@ namespace {
622683

623684
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
624685
SILType T) const override {
625-
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
686+
if (!IGM.getOptions().ForceStructTypeLayouts) {
687+
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
688+
}
689+
690+
if (!areFieldsABIAccessible()) {
691+
return IGM.typeLayoutCache.getOrCreateResilientEntry(T);
692+
}
693+
694+
std::vector<TypeLayoutEntry *> fields;
695+
for (auto &field : getFields()) {
696+
auto fieldTy = field.getType(IGM, T);
697+
fields.push_back(
698+
field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy));
699+
}
700+
assert(!fields.empty() &&
701+
"Empty structs should not be FixedStructTypeInfo");
702+
703+
if (fields.size() == 1) {
704+
return fields[0];
705+
}
706+
707+
return IGM.typeLayoutCache.getOrCreateAlignedGroupEntry(fields, 1);
626708
}
627709

628710
llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF) const {

lib/IRGen/GenTuple.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
//
2121
//===----------------------------------------------------------------------===//
2222

23-
#include "swift/AST/Types.h"
2423
#include "swift/AST/Decl.h"
24+
#include "swift/AST/IRGenOptions.h"
2525
#include "swift/AST/Pattern.h"
26+
#include "swift/AST/Types.h"
2627
#include "swift/SIL/SILModule.h"
2728
#include "swift/SIL/SILType.h"
2829
#include "llvm/IR/DerivedTypes.h"
@@ -231,7 +232,23 @@ namespace {
231232

232233
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
233234
SILType T) const override {
234-
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
235+
if (!IGM.getOptions().ForceStructTypeLayouts) {
236+
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
237+
}
238+
if (getFields().empty()) {
239+
return IGM.typeLayoutCache.getEmptyEntry();
240+
}
241+
242+
std::vector<TypeLayoutEntry *> fields;
243+
for (auto &field : getFields()) {
244+
auto fieldTy = field.getType(IGM, T);
245+
fields.push_back(
246+
field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy));
247+
}
248+
if (fields.size() == 1) {
249+
return fields[0];
250+
}
251+
return IGM.typeLayoutCache.getOrCreateAlignedGroupEntry(fields, 1);
235252
}
236253

237254
llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF) const {
@@ -260,7 +277,24 @@ namespace {
260277

261278
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
262279
SILType T) const override {
263-
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
280+
if (!IGM.getOptions().ForceStructTypeLayouts) {
281+
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
282+
}
283+
if (getFields().empty()) {
284+
return IGM.typeLayoutCache.getEmptyEntry();
285+
}
286+
287+
std::vector<TypeLayoutEntry *> fields;
288+
for (auto &field : getFields()) {
289+
auto fieldTy = field.getType(IGM, T);
290+
fields.push_back(
291+
field.getTypeInfo().buildTypeLayoutEntry(IGM, fieldTy));
292+
}
293+
if (fields.size() == 1) {
294+
return fields[0];
295+
}
296+
297+
return IGM.typeLayoutCache.getOrCreateAlignedGroupEntry(fields, 1);
264298
}
265299

266300
llvm::NoneType getNonFixedOffsets(IRGenFunction &IGF) const {

test/IRGen/typelayout_based_value_witness.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %target-swift-frontend -enable-type-layout -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK
22
// RUN: %target-swift-frontend -enable-type-layout -primary-file %s -O -emit-ir | %FileCheck %s --check-prefix=OPT --check-prefix=OPT-%target-ptrsize
3+
// RUN: %target-swift-frontend -enable-type-layout -force-struct-type-layouts -primary-file %s -O -emit-ir | %FileCheck %s --check-prefix=FORCE-OPT --check-prefix=FORCE-OPT-%target-ptrsize
34
// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s --check-prefix=NOTL
45

56
public struct B<T> {
@@ -12,6 +13,21 @@ public struct A<T> {
1213
var b: B<T>
1314
}
1415

16+
public class C<T> {
17+
init(a: B<T>, b: B<T>) {
18+
self.a = a
19+
self.b = b
20+
}
21+
var a : B<T>
22+
var b: B<T>
23+
}
24+
25+
public struct Fixed<T> {
26+
var a : Int8
27+
var b : Int16
28+
var c : C<T>
29+
}
30+
1531
// NOTL-LABEL: define{{.*}} %swift.opaque* @"$s30typelayout_based_value_witness1AVwCP"(
1632
// NOTL: @"$s30typelayout_based_value_witness1BVMa"(
1733
// NOTL: }
@@ -88,6 +104,18 @@ public struct A<T> {
88104
// OPT: ret void
89105
// CHECK: }
90106

107+
// FORCE-OPT: define{{.*}} void @"$s30typelayout_based_value_witness5FixedVwxx"(%swift.opaque* noalias nocapture readonly %object, %swift.type* nocapture readnone %"Fixed<T>")
108+
// For fixed types, we should expect a direct gep to the address instead of a
109+
// manual alignment computation only if we force creating aligned groups for structs
110+
// FORCE-OPT: [[T_PARAM:%.*]] = bitcast %swift.opaque* %object to i8*
111+
// FORCE-OPT: [[OFFSET:%.*]] = getelementptr inbounds i8, i8* [[T_PARAM]], i64 8
112+
// FORCE-OPT: [[CASTED:%.*]] = bitcast i8* [[OFFSET]] to %T30typelayout_based_value_witness1CC**
113+
// FORCE-OPT: %toDestroy = load %T30typelayout_based_value_witness1CC*, %T30typelayout_based_value_witness1CC** [[CASTED]], align 8
114+
// FORCE-OPT: [[FIELD:%.*]] = getelementptr %T30typelayout_based_value_witness1CC, %T30typelayout_based_value_witness1CC* %toDestroy, i64 0, i32 0
115+
// FORCE-OPT: tail call void @swift_release(%swift.refcounted* [[FIELD]]) #6
116+
// FORCE-OPT: ret void
117+
// FORCE-OPT:}
118+
91119
// Let's not crash on the following example.
92120
public protocol P {}
93121

0 commit comments

Comments
 (0)