Skip to content

Commit 3fca8cd

Browse files
committed
Swift SIL: speed up Operand.value
Instead of doing the type casts and/or conformance lookup on the swift side, do it on the C++ side. It makes a significant performance difference because `Operand.value` is a time critical function
1 parent 210d115 commit 3fca8cd

File tree

3 files changed

+43
-14
lines changed

3 files changed

+43
-14
lines changed

SwiftCompilerSources/Sources/SIL/Value.swift

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,18 +157,21 @@ extension Value {
157157
extension BridgedValue {
158158
public func getAs<T: AnyObject>(_ valueType: T.Type) -> T { obj.getAs(T.self) }
159159

160+
public var value: Value { getAs(AnyObject.self) as! Value }
161+
}
162+
163+
extension BridgedClassifiedValue {
160164
public var value: Value {
161-
// This is much faster than a conformance lookup with `as! Value`.
162-
let v = getAs(AnyObject.self)
163-
switch v {
164-
case let inst as SingleValueInstruction:
165-
return inst
166-
case let arg as Argument:
167-
return arg
168-
case let mvr as MultipleValueInstructionResult:
169-
return mvr
170-
case let undef as Undef:
171-
return undef
165+
// Doing the type check in C++ is much faster than a conformance lookup with `as! Value`.
166+
switch kind {
167+
case .SingleValueInstruction:
168+
return obj.getAs(SingleValueInstruction.self)
169+
case .Argument:
170+
return obj.getAs(Argument.self)
171+
case .MultipleValueInstructionResult:
172+
return obj.getAs(MultipleValueInstructionResult.self)
173+
case .Undef:
174+
return obj.getAs(Undef.self)
172175
default:
173176
fatalError("unknown Value type")
174177
}

include/swift/SIL/SILBridging.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,19 @@ typedef struct {
133133
SwiftObject obj;
134134
} BridgedValue;
135135

136+
// For fast SILValue -> Value briding.
137+
// This is doing the type checks in C++ rather than in Swift.
138+
// It's used for getting the value of an Operand, which is a time critical function.
139+
typedef struct {
140+
SwiftObject obj;
141+
enum class Kind {
142+
SingleValueInstruction,
143+
Argument,
144+
MultipleValueInstructionResult,
145+
Undef
146+
} kind;
147+
} BridgedClassifiedValue;
148+
136149
typedef struct {
137150
OptionalSwiftObject obj;
138151
} OptionalBridgedValue;
@@ -305,7 +318,7 @@ OptionalBridgedSuccessor SILSuccessor_getNext(BridgedSuccessor succ);
305318
BridgedBasicBlock SILSuccessor_getTargetBlock(BridgedSuccessor succ);
306319
BridgedInstruction SILSuccessor_getContainingInst(BridgedSuccessor succ);
307320

308-
BridgedValue Operand_getValue(BridgedOperand);
321+
BridgedClassifiedValue Operand_getValue(BridgedOperand);
309322
OptionalBridgedOperand Operand_nextUse(BridgedOperand);
310323
BridgedInstruction Operand_getUser(BridgedOperand);
311324
SwiftInt Operand_isTypeDependent(BridgedOperand);

lib/SIL/Utils/SILBridging.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,8 +447,21 @@ static Operand *castToOperand(BridgedOperand operand) {
447447
return const_cast<Operand *>(static_cast<const Operand *>(operand.op));
448448
}
449449

450-
BridgedValue Operand_getValue(BridgedOperand operand) {
451-
return {castToOperand(operand)->get()};
450+
BridgedClassifiedValue Operand_getValue(BridgedOperand operand) {
451+
SILValue v = castToOperand(operand)->get();
452+
BridgedClassifiedValue::Kind k;
453+
if (isa<SingleValueInstruction>(v)) {
454+
k = BridgedClassifiedValue::Kind::SingleValueInstruction;
455+
} else if (isa<SILArgument>(v)) {
456+
k = BridgedClassifiedValue::Kind::Argument;
457+
} else if (isa<MultipleValueInstructionResult>(v)) {
458+
k = BridgedClassifiedValue::Kind::MultipleValueInstructionResult;
459+
} else if (isa<SILUndef>(v)) {
460+
k = BridgedClassifiedValue::Kind::Undef;
461+
} else {
462+
llvm_unreachable("unknown SILValue");
463+
}
464+
return {castToOperand(operand)->get(), k};
452465
}
453466

454467
OptionalBridgedOperand Operand_nextUse(BridgedOperand operand) {

0 commit comments

Comments
 (0)