Skip to content

Commit e75b35f

Browse files
Merge pull request #63863 from aschwaighofer/witness_table_elim_relative_pwt
Support witness table elimination in relative protocol witness tables mode
2 parents 5ab60e6 + d3e3651 commit e75b35f

File tree

5 files changed

+102
-9
lines changed

5 files changed

+102
-9
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2319,7 +2319,9 @@ static void addWTableTypeMetadata(IRGenModule &IGM,
23192319
auto &fnProtoInfo =
23202320
IGM.getProtocolInfo(conf->getProtocol(), ProtocolInfoKind::Full);
23212321
auto index = fnProtoInfo.getFunctionIndex(member).forProtocolWitnessTable();
2322-
auto offset = index.getValue() * IGM.getPointerSize().getValue();
2322+
auto entrySize = IGM.IRGen.Opts.UseRelativeProtocolWitnessTables ?
2323+
4 : IGM.getPointerSize().getValue();
2324+
auto offset = index.getValue() * entrySize;
23232325
global->addTypeMetadata(offset, typeIdForMethod(IGM, member));
23242326

23252327
minOffset = std::min(minOffset, offset);
@@ -3810,9 +3812,11 @@ static llvm::Value *emitWTableSlotLoad(IRGenFunction &IGF, llvm::Value *wtable,
38103812

38113813
// TODO/FIXME: Using @llvm.type.checked.load loses the "invariant" marker
38123814
// which could mean redundant loads don't get removed.
3813-
llvm::Value *checkedLoad = IGF.Builder.CreateIntrinsicCall(
3814-
llvm::Intrinsic::type_checked_load, args);
3815-
assert(!isRelativeTable && "Not yet implemented");
3815+
llvm::Value *checkedLoad =
3816+
isRelativeTable ? IGF.Builder.CreateIntrinsicCall(
3817+
llvm::Intrinsic::type_checked_load_relative, args)
3818+
: IGF.Builder.CreateIntrinsicCall(
3819+
llvm::Intrinsic::type_checked_load, args);
38163820
return IGF.Builder.CreateExtractValue(checkedLoad, 0);
38173821
}
38183822

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Tests that under -enable-llvm-wme, LLVM GlobalDCE is able to remove unused
2+
// witness methods, and that used witness methods are not removed (by running
3+
// the program).
4+
5+
// RUN: %empty-directory(%t)
6+
// RUN: %target-build-swift -Xfrontend -enable-llvm-wme %s -Onone -emit-ir -o %t/main.ll -Xfrontend -enable-relative-protocol-witness-tables
7+
// RUN: %target-clang %t/main.ll -isysroot %sdk -L%swift_obj_root/lib/swift/%target-sdk-name -flto -o %t/main
8+
// RUN: %target-codesign %t/main
9+
// RUN: %target-run %t/main | %FileCheck %s
10+
11+
// RUN: %llvm-nm --defined-only %t/main | %FileCheck %s --check-prefix=NM
12+
13+
// REQUIRES: executable_test
14+
15+
// FIXME(mracek): More work needed to get this to work on non-Apple platforms.
16+
// REQUIRES: VENDOR=apple
17+
18+
// For LTO, the linker dlopen()'s the libLTO library, which is a scenario that
19+
// ASan cannot work in ("Interceptors are not working, AddressSanitizer is
20+
// loaded too late").
21+
// REQUIRES: no_asan
22+
23+
protocol TheProtocol {
24+
func func1_live()
25+
func func2_dead()
26+
}
27+
28+
struct MyStruct : TheProtocol {
29+
func func1_live() { print("MyStruct.func1_live") }
30+
func func2_dead() { print("MyStruct.func2_dead") }
31+
}
32+
33+
let x: TheProtocol = MyStruct()
34+
x.func1_live()
35+
// CHECK: MyStruct.func1_live
36+
37+
// NM: $s4main8MyStructV10func1_liveyyF
38+
// NM-NOT: $s4main8MyStructV10func2_deadyyF
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Tests that under -enable-llvm-wme, IRGen marks wtables and wcall sites with
2+
// the right attributes and intrinsics.
3+
4+
// RUN: %target-build-swift -Xfrontend -disable-objc-interop -Xfrontend -enable-llvm-wme \
5+
// RUN: -Xfrontend -enable-relative-protocol-witness-tables \
6+
// RUN: %s -emit-ir -o - | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
7+
8+
// REQUIRES: PTRSIZE=64
9+
10+
protocol TheProtocol {
11+
func func1_live()
12+
func func2_dead()
13+
}
14+
15+
struct MyStruct : TheProtocol {
16+
func func1_live() { print("MyStruct.func1_live") }
17+
func func2_dead() { print("MyStruct.func2_dead") }
18+
}
19+
20+
21+
// CHECK: @"$s4main8MyStructVAA11TheProtocolAAWP" =
22+
// CHECK-SAME: hidden constant [3 x i32]
23+
// CHECK-SAME: i32 trunc {{.*}} @"$s4main8MyStructVAA11TheProtocolAAMc"
24+
// CHECK-SAME: i32 trunc {{.*}} @"$s4main8MyStructVAA11TheProtocolA2aDP10func1_liveyyFTW"
25+
// CHECK-SAME: i32 trunc {{.*}} @"$s4main8MyStructVAA11TheProtocolA2aDP10func2_deadyyFTW"
26+
// CHECK-SAME: ], align 8, !type !0, !type !1, !vcall_visibility !2, !typed_global_not_for_cfi !3
27+
28+
func test1() {
29+
// CHECK: define hidden swiftcc void @"$s4main5test1yyF"()
30+
let x: MyStruct = MyStruct()
31+
x.func1_live()
32+
// CHECK: call swiftcc void @"$s4main8MyStructVACycfC"()
33+
// CHECK-NEXT: call swiftcc void @"$s4main8MyStructV10func1_liveyyF"()
34+
// CHECK-NEXT: ret void
35+
}
36+
37+
func test2() {
38+
// CHECK: define hidden swiftcc void @"$s4main5test2yyF"()
39+
let x: TheProtocol = MyStruct()
40+
x.func1_live()
41+
// CHECK: [[TBL:%.*]] = phi i8**
42+
// CHECK: [[TBL2:%.*]] = bitcast i8** [[TBL]] to i32*
43+
// CHECK: [[ENTRY:%.*]] = getelementptr inbounds i32, i32* [[TBL2]], i32 1
44+
// CHECK: [[ENTRY2:%.*]] = bitcast i32* [[ENTRY]] to i8*
45+
// CHECK: call { i8*, i1 } @llvm.type.checked.load.relative(i8* [[ENTRY2]], i32 0, metadata !"$s4main11TheProtocolP10func1_liveyyFTq")
46+
}
47+
48+
// CHECK: !0 = !{i64 4, !"$s4main11TheProtocolP10func1_liveyyFTq"}
49+
// CHECK: !1 = !{i64 8, !"$s4main11TheProtocolP10func2_deadyyFTq"}
50+
// CHECK: !2 = !{i64 1, i64 4, i64 12}
51+
// CHECK: !3 = !{}

test/lit.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1003,7 +1003,7 @@ if run_vendor == 'apple':
10031003

10041004
# TODO: consider making the addition of these flags dependent on the CMake
10051005
# setting for hermetic seal at link
1006-
if not config.swift_freestanding_is_darwin and not config.swift_stdlib_use_relative_protocol_witness_tables:
1006+
if not config.swift_freestanding_is_darwin:
10071007
swift_execution_tests_extra_flags += ' -experimental-hermetic-seal-at-link -lto=llvm-full'
10081008

10091009
if not config.swift_freestanding_is_darwin:

utils/build-presets.ini

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2624,8 +2624,8 @@ mixin-preset=
26242624
mixin_stdlib_minimal
26252625

26262626
build-subdir=stdlib_S_standalone
2627-
debug
2628-
assertions
2627+
min-size-release
2628+
no-assertions
26292629

26302630
verbose-build
26312631

@@ -2643,8 +2643,8 @@ swift-freestanding-archs=arm64
26432643
# For lit tests, we are producing dynamic executables with statically linked stdlib into the executable.
26442644
swift-runtime-static-image-inspection=0
26452645

2646-
swift-stdlib-experimental-hermetic-seal-at-link=0
2647-
swift-stdlib-lto=
2646+
swift-stdlib-experimental-hermetic-seal-at-link=1
2647+
swift-stdlib-lto=full
26482648
swift-enable-runtime-function-counters=0
26492649
swift-stdlib-use-relative-protocol-witness-tables=1
26502650

0 commit comments

Comments
 (0)