Skip to content

Commit cf87b9d

Browse files
committed
IRGen: Generate swift_fixLifetime marker as a private stub.
This lets us remove `swift_fixLifetime` as a real runtime entry point. Also, avoid generating the marker at all if the LLVM ARC optimizer won't be run, as in -Onone or -disable-llvm-arc-optimizer mode.
1 parent a5ba9e0 commit cf87b9d

File tree

7 files changed

+71
-35
lines changed

7 files changed

+71
-35
lines changed

lib/IRGen/GenHeap.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/Basic/Fallthrough.h"
2525
#include "swift/Basic/SourceLoc.h"
2626
#include "swift/ABI/MetadataValues.h"
27+
#include "swift/AST/IRGenOptions.h"
2728

2829
#include "Explosion.h"
2930
#include "GenProto.h"
@@ -1169,9 +1170,39 @@ void IRGenFunction::emitNativeUnownedTakeAssign(Address dest, Address src) {
11691170
emitNativeUnownedRelease(oldValue);
11701171
}
11711172

1173+
llvm::Constant *IRGenModule::getFixLifetimeFn() {
1174+
if (FixLifetimeFn)
1175+
return FixLifetimeFn;
1176+
1177+
// Generate a private stub function for the LLVM ARC optimizer to recognize.
1178+
auto fixLifetimeTy = llvm::FunctionType::get(VoidTy, RefCountedPtrTy,
1179+
/*isVarArg*/ false);
1180+
auto fixLifetime = llvm::Function::Create(fixLifetimeTy,
1181+
llvm::GlobalValue::PrivateLinkage,
1182+
"__swift_fixLifetime",
1183+
&Module);
1184+
assert(fixLifetime->getName().equals("__swift_fixLifetime")
1185+
&& "fixLifetime symbol name got mangled?!");
1186+
// Don't inline the function, so it stays as a signal to the ARC passes.
1187+
// The ARC passes will remove references to the function when they're
1188+
// no longer needed.
1189+
fixLifetime->addAttribute(llvm::AttributeSet::FunctionIndex,
1190+
llvm::Attribute::NoInline);
1191+
1192+
// Give the function an empty body.
1193+
auto entry = llvm::BasicBlock::Create(LLVMContext, "", fixLifetime);
1194+
llvm::ReturnInst::Create(LLVMContext, entry);
1195+
1196+
FixLifetimeFn = fixLifetime;
1197+
return fixLifetime;
1198+
}
1199+
11721200
/// Fix the lifetime of a live value. This communicates to the LLVM level ARC
11731201
/// optimizer not to touch this value.
11741202
void IRGenFunction::emitFixLifetime(llvm::Value *value) {
1203+
// If we aren't running the LLVM ARC optimizer, we don't need to emit this.
1204+
if (!IGM.Opts.Optimize || IGM.Opts.DisableLLVMARCOpts)
1205+
return;
11751206
if (doesNotRequireRefCounting(value)) return;
11761207
emitUnaryRefCountCall(*this, IGM.getFixLifetimeFn(), value);
11771208
}

lib/IRGen/IRGenModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,11 +640,14 @@ public: \
640640
private: \
641641
llvm::Constant *Id##Fn = nullptr;
642642
#include "RuntimeFunctions.def"
643+
644+
llvm::Constant *FixLifetimeFn = nullptr;
643645

644646
mutable Optional<SpareBitVector> HeapPointerSpareBits;
645647

646648
//--- Generic ---------------------------------------------------------------
647649
public:
650+
llvm::Constant *getFixLifetimeFn();
648651

649652
/// The constructor.
650653
///

lib/IRGen/RuntimeFunctions.def

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,6 @@ FUNCTION(NativeUnpin, swift_unpin, RuntimeCC,
150150
ARGS(RefCountedPtrTy),
151151
ATTRS(NoUnwind))
152152

153-
// void swift_fixLifetime(void *ptr);
154-
FUNCTION(FixLifetime, swift_fixLifetime, RuntimeCC,
155-
RETURNS(VoidTy),
156-
ARGS(RefCountedPtrTy),
157-
ATTRS(NoUnwind))
158-
159153
// void swift_unknownRetain(void *ptr);
160154
FUNCTION(UnknownRetain, swift_unknownRetain, RuntimeCC,
161155
RETURNS(VoidTy),

lib/LLVMPasses/LLVMARCOpts.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ enum RT_Kind {
6262
/// void swift_unknownRelease_n(%swift.refcounted* %P)
6363
RT_UnknownReleaseN,
6464

65-
/// void swift_fixLifetime(%swift.refcounted* %P)
65+
/// void __swift_fixLifetime(%swift.refcounted* %P)
6666
RT_FixLifetime,
6767

6868
/// void swift_bridgeRetain(%swift.refcounted* %P)
@@ -112,7 +112,7 @@ inline RT_Kind classifyInstruction(const llvm::Instruction &I) {
112112
.Case("swift_unknownRetain_n", RT_UnknownRetainN)
113113
.Case("swift_unknownRelease", RT_UnknownRelease)
114114
.Case("swift_unknownRelease_n", RT_UnknownReleaseN)
115-
.Case("swift_fixLifetime", RT_FixLifetime)
115+
.Case("__swift_fixLifetime", RT_FixLifetime)
116116
.Default(RT_Unknown);
117117
}
118118

stdlib/public/runtime/HeapObject.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -581,11 +581,6 @@ void swift::swift_deallocObject(HeapObject *object, size_t allocatedSize,
581581
}
582582
}
583583

584-
/// This is a function that is opaque to the optimizer. It is called to ensure
585-
/// that an object is alive at least until that time.
586-
extern "C" void swift_fixLifetime(OpaqueValue *value) {
587-
}
588-
589584
void swift::swift_weakInit(WeakReference *ref, HeapObject *value) {
590585
ref->Value = value;
591586
swift_unownedRetain(value);

test/IRGen/fixlifetime.sil

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
1-
// RUN: %target-swift-frontend -parse-sil -emit-ir %s | FileCheck --check-prefix=CHECK-%target-runtime %s
1+
// RUN: %target-swift-frontend -parse-sil -emit-ir -disable-llvm-optzns -O %s | FileCheck --check-prefix=CHECK-%target-runtime %s
2+
// RUN: %target-swift-frontend -parse-sil -emit-ir -disable-llvm-optzns -Ounchecked %s | FileCheck --check-prefix=CHECK-%target-runtime %s
3+
// RUN: %target-swift-frontend -parse-sil -emit-ir -disable-llvm-optzns -Onone %s | FileCheck --check-prefix=ONONE %s
24

35
// REQUIRES: CPU=i386_or_x86_64
46

7+
// At -Onone we don't run the LLVM ARC optimizer, so the fixLifetime call is
8+
// unnecessary.
9+
// ONONE-NOT: @__swift_fixLifetime
10+
511
// CHECK-objc-LABEL: define void @test(%C11fixlifetime1C*, %objc_object*, i8**, i8*, %swift.refcounted*, %V11fixlifetime3Agg* noalias nocapture dereferenceable({{.*}})) {{.*}} {
612
// CHECK-objc: entry:
7-
// CHECK-objc: call void bitcast (void (%swift.refcounted*)* @swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
8-
// CHECK-objc: call void bitcast (void (%swift.refcounted*)* @swift_fixLifetime to void (%objc_object*)*)(%objc_object*
9-
// CHECK-objc: call void @swift_fixLifetime(%swift.refcounted*
10-
// CHECK-objc: call void bitcast (void (%swift.refcounted*)* @swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
11-
// CHECK-objc: call void bitcast (void (%swift.refcounted*)* @swift_fixLifetime to void (%objc_object*)*)(%objc_object*
12-
// CHECK-objc: call void @swift_fixLifetime(%swift.refcounted*
13-
// CHECK-objc: call void bitcast (void (%swift.refcounted*)* @swift_fixLifetime to void (%C11fixlifetime1C**)*)(%C11fixlifetime1C**
13+
// CHECK-objc: call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
14+
// CHECK-objc: call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%objc_object*)*)(%objc_object*
15+
// CHECK-objc: call void @__swift_fixLifetime(%swift.refcounted*
16+
// CHECK-objc: call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
17+
// CHECK-objc: call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%objc_object*)*)(%objc_object*
18+
// CHECK-objc: call void @__swift_fixLifetime(%swift.refcounted*
19+
// CHECK-objc: call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C**)*)(%C11fixlifetime1C**
1420

1521
// CHECK-native-LABEL: define void @test(%C11fixlifetime1C*, %swift.refcounted*, i8**, i8*, %swift.refcounted*, %V11fixlifetime3Agg* noalias nocapture dereferenceable({{.*}})) {{.*}} {
1622
// CHECK-native: entry:
17-
// CHECK-native: call void bitcast (void (%swift.refcounted*)* @swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
18-
// CHECK-native: call void @swift_fixLifetime(%swift.refcounted*
19-
// CHECK-native: call void @swift_fixLifetime(%swift.refcounted*
20-
// CHECK-native: call void bitcast (void (%swift.refcounted*)* @swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
21-
// CHECK-native: call void @swift_fixLifetime(%swift.refcounted*
22-
// CHECK-native: call void @swift_fixLifetime(%swift.refcounted*
23-
// CHECK-native: call void bitcast (void (%swift.refcounted*)* @swift_fixLifetime to void (%C11fixlifetime1C**)*)(%C11fixlifetime1C**
23+
// CHECK-native: call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
24+
// CHECK-native: call void @__swift_fixLifetime(%swift.refcounted*
25+
// CHECK-native: call void @__swift_fixLifetime(%swift.refcounted*
26+
// CHECK-native: call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C*)*)(%C11fixlifetime1C*
27+
// CHECK-native: call void @__swift_fixLifetime(%swift.refcounted*
28+
// CHECK-native: call void @__swift_fixLifetime(%swift.refcounted*
29+
// CHECK-native: call void bitcast (void (%swift.refcounted*)* @__swift_fixLifetime to void (%C11fixlifetime1C**)*)(%C11fixlifetime1C**
30+
31+
sil_stage canonical
2432

2533
class C {}
2634
sil_vtable C {}
@@ -32,7 +40,8 @@ struct Agg {
3240
var f : F
3341
}
3442

35-
sil @test : $@convention(thin) (C, P, @callee_owned () -> (), Agg) -> () {
43+
sil [_semantics "optimize.sil.never"] @test
44+
: $@convention(thin) (C, P, @callee_owned () -> (), Agg) -> () {
3645
bb0(%0 : $C, %1 : $P, %2 : $@callee_owned () -> (), %3 : $Agg):
3746
fix_lifetime %0 : $C
3847
fix_lifetime %1 : $P

test/LLVMPasses/basic.ll

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ declare void @objc_release(%objc_object*)
1515
declare %swift.refcounted* @swift_allocObject(%swift.heapmetadata* , i64, i64) nounwind
1616
declare void @swift_release(%swift.refcounted* nocapture)
1717
declare void @swift_retain(%swift.refcounted* ) nounwind
18-
declare void @swift_fixLifetime(%swift.refcounted* ) nounwind
1918
declare %swift.bridge* @swift_bridgeObjectRetain(%swift.bridge*)
2019
declare void @swift_bridgeObjectRelease(%swift.bridge*)
2120
declare void @swift_retainUnowned(%swift.refcounted*)
@@ -24,6 +23,11 @@ declare void @user(%swift.refcounted *) nounwind
2423
declare void @user_objc(%objc_object*) nounwind
2524
declare void @unknown_func()
2625

26+
define private void @__swift_fixLifetime(%swift.refcounted*) noinline nounwind {
27+
entry:
28+
ret void
29+
}
30+
2731
; CHECK-LABEL: @trivial_objc_canonicalization(
2832
; CHECK-NEXT: entry:
2933
; CHECK-NEXT: [[RET0:%.+]] = bitcast i8* %O to %objc_object*
@@ -142,7 +146,7 @@ define void @objc_retain_release_opt(%objc_object* %P, i32* %IP) {
142146
define void @swift_fixLifetimeTest(%swift.refcounted* %A) {
143147
tail call void @swift_retain(%swift.refcounted* %A)
144148
call void @user(%swift.refcounted* %A) nounwind
145-
call void @swift_fixLifetime(%swift.refcounted* %A)
149+
call void @__swift_fixLifetime(%swift.refcounted* %A)
146150
tail call void @swift_release(%swift.refcounted* %A) nounwind
147151
ret void
148152
}
@@ -183,17 +187,17 @@ define i32 @move_retain_across_load(%swift.refcounted* %A, i32* %ptr) {
183187
}
184188

185189
; CHECK-LABEL: @move_retain_but_not_release_across_objc_fix_lifetime
186-
; CHECK: call void @swift_fixLifetime
190+
; CHECK: call void @__swift_fixLifetime
187191
; CHECK-NEXT: tail call void @swift_retain
188192
; CHECK-NEXT: call void @user
189-
; CHECK-NEXT: call void @swift_fixLifetime
193+
; CHECK-NEXT: call void @__swift_fixLifetime
190194
; CHECK-NEXT: call void @swift_release
191195
; CHECK-NEXT: ret
192196
define void @move_retain_but_not_release_across_objc_fix_lifetime(%swift.refcounted* %A) {
193197
tail call void @swift_retain(%swift.refcounted* %A)
194-
call void @swift_fixLifetime(%swift.refcounted* %A) nounwind
198+
call void @__swift_fixLifetime(%swift.refcounted* %A) nounwind
195199
call void @user(%swift.refcounted* %A) nounwind
196-
call void @swift_fixLifetime(%swift.refcounted* %A) nounwind
200+
call void @__swift_fixLifetime(%swift.refcounted* %A) nounwind
197201
tail call void @swift_release(%swift.refcounted* %A) nounwind
198202
ret void
199203
}

0 commit comments

Comments
 (0)