Skip to content

Commit c9ba2bf

Browse files
committed
SILGen: Drop '_unwrapped' intrinsics and use _diagnoseUnexpectedNilOptional.
Being generic, the '_unwrapped' intrinsics force trafficking through memory, and while they're transparent so always get inlined, we don't do memory promotion in -Onone. Emitting the branch inline lets loadable optionals stay values leading to better -Onone codegen. (It also lets us throw away a surprising amount of support code for these optional intrinsics.)
1 parent e72af82 commit c9ba2bf

18 files changed

+51
-236
lines changed

include/swift/AST/ASTContext.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -454,11 +454,6 @@ class ASTContext {
454454
FuncDecl *get##Name(LazyResolver *resolver) const;
455455
#include "swift/AST/KnownDecls.def"
456456

457-
/// Retrieve the declaration of
458-
/// Swift._stdlib_{,ImplicitlyUnwrapped}Optional_unwrapped.
459-
FuncDecl *getOptionalUnwrappedDecl(LazyResolver *resolver,
460-
OptionalTypeKind kind) const;
461-
462457
/// Check whether the standard library provides all the correct
463458
/// intrinsic support for Optional<T>.
464459
///

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,6 @@ struct ASTContext::Implementation {
168168
#define FUNC_DECL(Name, Id) FuncDecl *Get##Name = nullptr;
169169
#include "swift/AST/KnownDecls.def"
170170

171-
/// func _stdlib_Optional_unwrapped<T>(v: Optional<T>) -> T
172-
FuncDecl *OptionalUnwrappedDecls[NumOptionalTypeKinds] = {};
173-
174171
/// The declaration of Swift.ImplicitlyUnwrappedOptional<T>.
175172
EnumDecl *ImplicitlyUnwrappedOptionalDecl = nullptr;
176173

@@ -1055,29 +1052,6 @@ FuncDecl *ASTContext::getIsOSVersionAtLeastDecl(LazyResolver *resolver) const {
10551052
return decl;
10561053
}
10571054

1058-
/// Check whether the given function is generic over a single,
1059-
/// unconstrained archetype.
1060-
static bool isGenericIntrinsic(FuncDecl *fn, CanType &input, CanType &output,
1061-
CanType &param) {
1062-
auto fnType =
1063-
dyn_cast<GenericFunctionType>(fn->getInterfaceType()->getCanonicalType());
1064-
if (!fnType || fnType->getGenericParams().size() != 1)
1065-
return false;
1066-
1067-
bool hasRequirements = std::any_of(fnType->getRequirements().begin(),
1068-
fnType->getRequirements().end(),
1069-
[](const Requirement &req) -> bool {
1070-
return req.getKind() != RequirementKind::WitnessMarker;
1071-
});
1072-
if (hasRequirements)
1073-
return false;
1074-
1075-
param = CanGenericTypeParamType(fnType->getGenericParams().front());
1076-
input = stripImmediateLabels(fnType.getInput());
1077-
output = stripImmediateLabels(fnType.getResult());
1078-
return true;
1079-
}
1080-
10811055
// Find library intrinsic function.
10821056
static FuncDecl *findLibraryFunction(const ASTContext &ctx, FuncDecl *&cache,
10831057
StringRef name, LazyResolver *resolver) {
@@ -1094,67 +1068,11 @@ FuncDecl *ASTContext::get##Name(LazyResolver *resolver) const { \
10941068
}
10951069
#include "swift/AST/KnownDecls.def"
10961070

1097-
/// Check whether the given type is Optional applied to the given
1098-
/// type argument.
1099-
static bool isOptionalType(const ASTContext &ctx,
1100-
OptionalTypeKind optionalKind,
1101-
CanType type, CanType arg) {
1102-
if (auto boundType = dyn_cast<BoundGenericType>(type)) {
1103-
return (boundType->getDecl()->classifyAsOptionalType() == optionalKind &&
1104-
boundType.getGenericArgs().size() == 1 &&
1105-
boundType.getGenericArgs()[0] == arg);
1106-
}
1107-
return false;
1108-
}
1109-
1110-
/// Turn an OptionalTypeKind into an index into one of the caches.
1111-
static unsigned asIndex(OptionalTypeKind optionalKind) {
1112-
assert(optionalKind && "passed a non-optional type kind?");
1113-
return unsigned(optionalKind) - 1;
1114-
}
1115-
1116-
#define getOptionalIntrinsicName(PREFIX, KIND, SUFFIX) \
1117-
((KIND) == OTK_Optional \
1118-
? (PREFIX "Optional" SUFFIX) \
1119-
: (PREFIX "ImplicitlyUnwrappedOptional" SUFFIX))
1120-
1121-
FuncDecl *ASTContext::getOptionalUnwrappedDecl(LazyResolver *resolver,
1122-
OptionalTypeKind optionalKind) const {
1123-
auto &cache = Impl.OptionalUnwrappedDecls[asIndex(optionalKind)];
1124-
if (cache) return cache;
1125-
1126-
auto name = getOptionalIntrinsicName(
1127-
"_stdlib_", optionalKind, "_unwrapped");
1128-
1129-
// Look for the function.
1130-
CanType input, output, param;
1131-
auto decl = findLibraryIntrinsic(*this, name, resolver);
1132-
if (!decl || !isGenericIntrinsic(decl, input, output, param))
1133-
return nullptr;
1134-
1135-
// Input must be Optional<T>.
1136-
if (!isOptionalType(*this, optionalKind, input, param))
1137-
return nullptr;
1138-
1139-
// Output must be T.
1140-
if (output != param)
1141-
return nullptr;
1142-
1143-
cache = decl;
1144-
return decl;
1145-
}
1146-
1147-
static bool hasOptionalIntrinsics(const ASTContext &ctx, LazyResolver *resolver,
1148-
OptionalTypeKind optionalKind) {
1149-
return ctx.getOptionalUnwrappedDecl(resolver, optionalKind);
1150-
}
1151-
11521071
bool ASTContext::hasOptionalIntrinsics(LazyResolver *resolver) const {
11531072
return getOptionalDecl() &&
11541073
getOptionalSomeDecl() &&
11551074
getOptionalNoneDecl() &&
1156-
::hasOptionalIntrinsics(*this, resolver, OTK_Optional) &&
1157-
::hasOptionalIntrinsics(*this, resolver, OTK_ImplicitlyUnwrappedOptional);
1075+
getDiagnoseUnexpectedNilOptional(resolver);
11581076
}
11591077

11601078
bool ASTContext::hasPointerArgumentIntrinsics(LazyResolver *resolver) const {

lib/SILGen/SILGenConvert.cpp

Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -149,20 +149,6 @@ getOptionalSomeValue(SILLocation loc, ManagedValue value,
149149
return emitManagedRValueWithCleanup(result, optTL);
150150
}
151151

152-
static Substitution getSimpleSubstitution(GenericSignature *genericSig,
153-
CanType typeArg) {
154-
assert(genericSig->getGenericParams().size() == 1);
155-
return Substitution{typeArg, {}};
156-
}
157-
158-
/// Create the correct substitution for calling the given function at
159-
/// the given type.
160-
static Substitution getSimpleSubstitution(FuncDecl *fn, CanType typeArg) {
161-
auto genericFnType =
162-
cast<GenericFunctionType>(fn->getInterfaceType()->getCanonicalType());
163-
return getSimpleSubstitution(genericFnType->getGenericSignature(), typeArg);
164-
}
165-
166152
static CanType getOptionalValueType(SILType optType,
167153
OptionalTypeKind &optionalKind) {
168154
auto generic = cast<BoundGenericType>(optType.getSwiftRValueType());
@@ -172,19 +158,24 @@ static CanType getOptionalValueType(SILType optType,
172158
}
173159

174160
void SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc,
175-
SILValue addr) {
161+
SILValue optional) {
176162
OptionalTypeKind OTK;
177-
getOptionalValueType(addr->getType().getObjectType(), OTK);
163+
getOptionalValueType(optional->getType().getObjectType(), OTK);
178164

179-
// Generate code to the optional is present, and if not abort with a message
165+
// Generate code to the optional is present, and if not, abort with a message
180166
// (provided by the stdlib).
181167
SILBasicBlock *contBB = createBasicBlock();
182168
SILBasicBlock *failBB = createBasicBlock();
183169

184170
auto NoneEnumElementDecl = getASTContext().getOptionalNoneDecl(OTK);
185-
B.createSwitchEnumAddr(loc, addr, /*defaultDest*/contBB,
186-
{ { NoneEnumElementDecl, failBB }});
187-
171+
if (optional->getType().isAddress()) {
172+
B.createSwitchEnumAddr(loc, optional, /*defaultDest*/contBB,
173+
{ { NoneEnumElementDecl, failBB }});
174+
} else {
175+
B.createSwitchEnum(loc, optional, /*defaultDest*/contBB,
176+
{ { NoneEnumElementDecl, failBB }});
177+
178+
}
188179
B.emitBlock(failBB);
189180

190181
// Call the standard library implementation of _diagnoseUnexpectedNilOptional.
@@ -221,27 +212,8 @@ ManagedValue SILGenFunction::emitCheckedGetOptionalValueFrom(SILLocation loc,
221212
ManagedValue src,
222213
const TypeLowering &optTL,
223214
SGFContext C) {
224-
SILType optType = src.getType().getObjectType();
225-
OptionalTypeKind optionalKind;
226-
CanType valueType = getOptionalValueType(optType, optionalKind);
227-
228-
FuncDecl *fn = getASTContext().getOptionalUnwrappedDecl(
229-
nullptr, optionalKind);
230-
Substitution sub = getSimpleSubstitution(fn, valueType);
231-
232-
// The intrinsic takes its parameter indirectly.
233-
if (src.getType().isObject()) {
234-
auto buf = emitTemporaryAllocation(loc, src.getType());
235-
B.createStore(loc, src.forward(*this), buf);
236-
src = emitManagedBufferWithCleanup(buf);
237-
}
238-
239-
RValue result = emitApplyOfLibraryIntrinsic(loc, fn, sub, src, C);
240-
if (result) {
241-
return std::move(result).getAsSingleValue(*this, loc);
242-
} else {
243-
return ManagedValue::forInContext();
244-
}
215+
emitPreconditionOptionalHasValue(loc, src.getValue());
216+
return emitUncheckedGetOptionalValueFrom(loc, src, optTL, C);
245217
}
246218

247219
ManagedValue SILGenFunction::emitUncheckedGetOptionalValueFrom(SILLocation loc,

lib/SILGen/SILGenExpr.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3119,14 +3119,11 @@ RValue RValueEmitter::emitForceValue(SILLocation loc, Expr *E,
31193119
return SGF.emitRValue(injection->getSubExpr(), C);
31203120
}
31213121

3122-
// Otherwise, emit the value into memory and use the optional intrinsic.
3122+
// Otherwise, emit the optional and force its value out.
31233123
const TypeLowering &optTL = SGF.getTypeLowering(E->getType());
3124-
auto optTemp = SGF.emitTemporary(E, optTL);
3125-
SGF.emitExprInto(E, optTemp.get());
3126-
3124+
ManagedValue opt = SGF.emitRValueAsSingleValue(E);
31273125
ManagedValue V =
3128-
SGF.emitCheckedGetOptionalValueFrom(loc,
3129-
optTemp->getManagedAddress(), optTL, C);
3126+
SGF.emitCheckedGetOptionalValueFrom(loc, opt, optTL, C);
31303127
return RValue(SGF, loc, valueType->getCanonicalType(), V);
31313128
}
31323129

stdlib/public/core/ImplicitlyUnwrappedOptional.swift

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,6 @@ extension ImplicitlyUnwrappedOptional : CustomDebugStringConvertible {
6363
}
6464
}
6565

66-
@_transparent
67-
public // COMPILER_INTRINSIC
68-
func _stdlib_ImplicitlyUnwrappedOptional_unwrapped<Wrapped>
69-
(_ `self`: Wrapped!) -> Wrapped {
70-
71-
switch `self` {
72-
case .some(let wrapped):
73-
return wrapped
74-
case .none:
75-
_preconditionFailure(
76-
"unexpectedly found nil while unwrapping an Optional value")
77-
}
78-
}
79-
8066
#if _runtime(_ObjC)
8167
extension ImplicitlyUnwrappedOptional : _ObjectiveCBridgeable {
8268
public func _bridgeToObjectiveC() -> AnyObject {

stdlib/public/core/Optional.swift

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -284,18 +284,6 @@ extension Optional : CustomReflectable {
284284
}
285285
}
286286

287-
@_transparent
288-
public // COMPILER_INTRINSIC
289-
func _stdlib_Optional_unwrapped<Wrapped>(_ `self`: Wrapped?) -> Wrapped {
290-
switch `self` {
291-
case let wrapped?:
292-
return wrapped
293-
case .none:
294-
_preconditionFailure(
295-
"unexpectedly found nil while unwrapping an Optional value")
296-
}
297-
}
298-
299287
@_transparent
300288
public // COMPILER_INTRINSIC
301289
func _diagnoseUnexpectedNilOptional() {

test/SILGen/dynamic_lookup.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ func opt_to_property(_ obj: AnyObject) {
132132
// CHECK: store [[OBJ]] to [[PBOBJ]] : $*AnyObject
133133
// CHECK-NEXT: [[INT_BOX:%[0-9]+]] = alloc_box $Int
134134
// CHECK-NEXT: project_box [[INT_BOX]]
135-
// CHECK-NEXT: [[UNKNOWN_USE:%.*]] = alloc_stack $ImplicitlyUnwrappedOptional<Int>
136135
// CHECK-NEXT: [[OBJ:%[0-9]+]] = load [[PBOBJ]] : $*AnyObject
137136
// CHECK-NEXT: strong_retain [[OBJ]] : $AnyObject
138137
// CHECK-NEXT: [[RAWOBJ_SELF:%[0-9]+]] = open_existential_ref [[OBJ]] : $AnyObject
@@ -162,7 +161,6 @@ func direct_to_subscript(_ obj: AnyObject, i: Int) {
162161
// CHECK-NEXT: store [[I]] to [[PBI]] : $*Int
163162
// CHECK-NEXT: alloc_box $Int
164163
// CHECK-NEXT: project_box
165-
// CHECK-NEXT: [[UNKNOWN_USE:%.*]] = alloc_stack $ImplicitlyUnwrappedOptional<Int>
166164
// CHECK-NEXT: [[OBJ:%[0-9]+]] = load [[PBOBJ]] : $*AnyObject
167165
// CHECK-NEXT: strong_retain [[OBJ]] : $AnyObject
168166
// CHECK-NEXT: [[OBJ_REF:%[0-9]+]] = open_existential_ref [[OBJ]] : $AnyObject to $@opened({{.*}}) AnyObject

test/SILGen/expressions.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,10 +541,13 @@ func dontEmitIgnoredLoadExpr(_ a : NonTrivialStruct) -> NonTrivialStruct.Type {
541541
// CHECK: bb0(%0 : $Optional<((Int, Int), Int)>):
542542
func implodeRecursiveTuple(_ expr: ((Int, Int), Int)?) {
543543

544-
// CHECK: [[WHOLE:%[0-9]+]] = load {{.*}} : $*((Int, Int), Int)
544+
// CHECK: [[WHOLE:%[0-9]+]] = unchecked_enum_data {{.*}} : $Optional<((Int, Int), Int)>
545545
// CHECK-NEXT: [[X:%[0-9]+]] = tuple_extract [[WHOLE]] : $((Int, Int), Int), 0
546-
// CHECK-NEXT: debug_value [[X]] : $(Int, Int), let, name "x"
546+
// CHECK-NEXT: [[X0:%[0-9]+]] = tuple_extract [[X]] : $(Int, Int), 0
547+
// CHECK-NEXT: [[X1:%[0-9]+]] = tuple_extract [[X]] : $(Int, Int), 1
547548
// CHECK-NEXT: [[Y:%[0-9]+]] = tuple_extract [[WHOLE]] : $((Int, Int), Int), 1
549+
// CHECK-NEXT: [[X:%[0-9]+]] = tuple ([[X0]] : $Int, [[X1]] : $Int)
550+
// CHECK-NEXT: debug_value [[X]] : $(Int, Int), let, name "x"
548551
// CHECK-NEXT: debug_value [[Y]] : $Int, let, name "y"
549552

550553
let (x, y) = expr!

test/SILGen/force_cast_chained_optional.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ class D: C {}
2121
// CHECK: [[PAYLOAD_ADDR:%.*]] = unchecked_take_enum_data_addr {{%.*}} : $*ImplicitlyUnwrappedOptional<Bar>
2222
// CHECK: [[BAR:%.*]] = load [[PAYLOAD_ADDR]]
2323
// CHECK: class_method {{%.*}} : $Bar, #Bar.bas!getter.1 : (Bar) -> () -> C! , $@convention(method) (@guaranteed Bar) ->
24-
// CHECK: function_ref @_TFs45_stdlib_ImplicitlyUnwrappedOptional_unwrappedurFGSQx_x
2524
// CHECK: unconditional_checked_cast {{%.*}} : $C to $D
2625
// CHECK: [[TRAP]]:
2726
// CHECK: unreachable

test/SILGen/implicitly_unwrapped_optional.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ func wrap<T>(x x: T) -> T! { return x }
3232

3333
// CHECK-LABEL: sil hidden @_TF29implicitly_unwrapped_optional16wrap_then_unwrap
3434
func wrap_then_unwrap<T>(x x: T) -> T {
35-
// CHECK: [[FORCE:%.*]] = function_ref @_TFs45_stdlib_ImplicitlyUnwrappedOptional_unwrappedurFGSQx_x
36-
// CHECK: apply [[FORCE]]<{{.*}}>(%0, {{%.*}})
35+
// CHECK: switch_enum_addr {{%.*}}, case #ImplicitlyUnwrappedOptional.none!enumelt: [[FAIL:.*]], default [[OK:bb[0-9]+]]
36+
// CHECK: [[FAIL]]:
37+
// CHECK: unreachable
38+
// CHECK: [[OK]]:
3739
return wrap(x: x)!
3840
}
3941

test/SILGen/objc_bridging.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ func getDescription(_ o: NSObject) -> String {
2121
// CHECK: [[BRIDGED_BOX:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
2222
// CHECK: [[NATIVE:%.*]] = apply [[NSSTRING_TO_STRING]]([[BRIDGED_BOX]],
2323
// CHECK: [[OPT_NATIVE:%.*]] = enum $ImplicitlyUnwrappedOptional<String>, #ImplicitlyUnwrappedOptional.some!enumelt.1, [[NATIVE]]
24-
// CHECK: [[T0:%.*]] = function_ref @_TFs45_stdlib_ImplicitlyUnwrappedOptional_unwrappedurFGSQx_x
25-
// CHECK: apply [[T0]]<String>([[NATIVE_BUF:%[0-9]*]],
26-
// CHECK: [[NATIVE:%.*]] = load [[NATIVE_BUF]]
24+
// CHECK: [[NATIVE:%.*]] = unchecked_enum_data {{.*}} : $ImplicitlyUnwrappedOptional<String>
2725
// CHECK: return [[NATIVE]]
2826
// CHECK:}
2927

@@ -43,9 +41,7 @@ func getUppercaseString(_ s: NSString) -> String {
4341
// CHECK: [[BRIDGED_BOX:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
4442
// CHECK: [[NATIVE:%.*]] = apply [[NSSTRING_TO_STRING]]([[BRIDGED_BOX]]
4543
// CHECK: [[OPT_NATIVE:%.*]] = enum $ImplicitlyUnwrappedOptional<String>, #ImplicitlyUnwrappedOptional.some!enumelt.1, [[NATIVE]]
46-
// CHECK: [[T0:%.*]] = function_ref @_TFs45_stdlib_ImplicitlyUnwrappedOptional_unwrappedurFGSQx_x
47-
// CHECK: apply [[T0]]<String>([[NATIVE_BUF:%[0-9]*]],
48-
// CHECK: [[NATIVE:%.*]] = load [[NATIVE_BUF]]
44+
// CHECK: [[NATIVE:%.*]] = unchecked_enum_data {{.*}} : $ImplicitlyUnwrappedOptional<String>
4945
// CHECK: return [[NATIVE]]
5046
// CHECK: }
5147

@@ -164,9 +160,7 @@ func callBar() -> String {
164160
// CHECK: [[BRIDGED_BOX:%.*]] = enum $Optional<NSString>, #Optional.some!enumelt.1, [[BRIDGED]]
165161
// CHECK: [[NATIVE:%.*]] = apply [[NSSTRING_TO_STRING]]([[BRIDGED_BOX]]
166162
// CHECK: [[OPT_NATIVE:%.*]] = enum $ImplicitlyUnwrappedOptional<String>, #ImplicitlyUnwrappedOptional.some!enumelt.1, [[NATIVE]]
167-
// CHECK: [[T0:%.*]] = function_ref @_TFs45_stdlib_ImplicitlyUnwrappedOptional_unwrappedurFGSQx_x
168-
// CHECK: apply [[T0]]<String>([[NATIVE_BUF:%[0-9]*]],
169-
// CHECK: [[NATIVE:%.*]] = load [[NATIVE_BUF]]
163+
// CHECK: [[NATIVE:%.*]] = unchecked_enum_data {{.*}} : $ImplicitlyUnwrappedOptional<String>
170164
// CHECK: return [[NATIVE]]
171165
// CHECK: }
172166

test/SILGen/objc_init_ref_delegation.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ extension Gizmo {
1515
// CHECK: [[SELF:%[0-9]+]] = load [[SELFMUI]] : $*Gizmo
1616
// CHECK: [[INIT_DELEG:%[0-9]+]] = class_method [volatile] [[SELF]] : $Gizmo, #Gizmo.init!initializer.1.foreign : Gizmo.Type -> (bellsOn: Int) -> Gizmo! , $@convention(objc_method) (Int, @owned Gizmo) -> @owned ImplicitlyUnwrappedOptional<Gizmo>
1717
// CHECK: [[SELF_RET:%[0-9]+]] = apply [[INIT_DELEG]]([[I]], [[SELF]]) : $@convention(objc_method) (Int, @owned Gizmo) -> @owned ImplicitlyUnwrappedOptional<Gizmo>
18-
// CHECK: store [[SELF_RET]] to [[SELFMUI:%[0-9]+]] : $*ImplicitlyUnwrappedOptional<Gizmo>
1918
// CHECK: strong_retain [[SELF4:%[0-9]+]] : $Gizmo
2019
// CHECK: strong_release [[SELF_BOX:%[0-9]+]] : $@box Gizmo
2120
// CHECK: return [[SELF4]] : $Gizmo

0 commit comments

Comments
 (0)