Skip to content

Commit 8d5ac75

Browse files
Optimize br_table to skip landing pads when no value is copied
1 parent ab962c7 commit 8d5ac75

File tree

1 file changed

+43
-10
lines changed

1 file changed

+43
-10
lines changed

Sources/WasmKit/Translator.swift

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ struct StackLayout {
243243
func dump<Target: TextOutputStream>(to target: inout Target, iseq: InstructionSequence) {
244244
let frameHeaderSize = FrameHeaderLayout.size(of: frameHeader.type)
245245
let slotMinIndex = VReg(-frameHeaderSize)
246-
let slotMaxIndex = VReg(numberOfLocals - 1)
246+
let slotMaxIndex = VReg(stackRegBase - 1)
247247
let slotIndexWidth = max(String(slotMinIndex).count, String(slotMaxIndex).count)
248248
func writeSlot(_ target: inout Target, _ index: VReg, _ description: String) {
249249
var index = String(index)
@@ -718,6 +718,27 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
718718
self.labels[ref] = .unpinned(users: users)
719719
}
720720
}
721+
722+
/// Schedule to fill a br_table entry with the resolved label position
723+
/// - Parameters:
724+
/// - ref: Label reference to be resolved
725+
/// - table: Building br_table buffer
726+
/// - index: Index of the entry to fill
727+
/// - make: Factory closure to make an br_table entry
728+
mutating func fillBrTableEntry(
729+
_ ref: LabelRef,
730+
table: BuildingBrTable,
731+
index: Int, line: UInt = #line,
732+
make: @escaping BrTableEntryFactory
733+
) {
734+
switch self.labels[ref] {
735+
case .pinned(let pc):
736+
table[index] = make(self, pc)
737+
case .unpinned(var users):
738+
users.append(LabelUser(action: .fillBrTableEntry(buildingTable: table, index: index, make: make), sourceLine: line))
739+
self.labels[ref] = .unpinned(users: users)
740+
}
741+
}
721742
}
722743

723744
struct Locals {
@@ -825,9 +846,11 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
825846
iseqBuilder.emit(instruction, resultRelink: resultRelink)
826847
}
827848

828-
private mutating func emitCopyStack(from source: VReg, to dest: VReg) {
829-
guard source != dest else { return }
849+
@discardableResult
850+
private mutating func emitCopyStack(from source: VReg, to dest: VReg) -> Bool {
851+
guard source != dest else { return false }
830852
emit(.copyStack(Instruction.CopyStackOperand(source: Int32(source), dest: Int32(dest))))
853+
return true
831854
}
832855

833856
private mutating func preserveOnStack(depth: Int) {
@@ -933,11 +956,13 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
933956
}
934957
}
935958

936-
private mutating func copyOnBranch(targetFrame frame: ControlStack.ControlFrame) throws {
959+
@discardableResult
960+
private mutating func copyOnBranch(targetFrame frame: ControlStack.ControlFrame) throws -> Bool {
937961
preserveOnStack(depth: min(Int(frame.copyCount), valueStack.height - frame.stackHeight))
938962
let copyCount = VReg(frame.copyCount)
939963
let sourceBase = valueStack.stackRegBase + VReg(valueStack.height)
940964
let destBase = valueStack.stackRegBase + VReg(frame.stackHeight)
965+
var emittedCopy = false
941966
for i in (0..<copyCount).reversed() {
942967
let source = sourceBase - 1 - VReg(i)
943968
let dest: VReg
@@ -946,8 +971,10 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
946971
} else {
947972
dest = destBase + copyCount - 1 - VReg(i)
948973
}
949-
emitCopyStack(from: source, to: dest)
974+
let copied = emitCopyStack(from: source, to: dest)
975+
emittedCopy = emittedCopy || copied
950976
}
977+
return emittedCopy
951978
}
952979
private mutating func translateReturn() throws {
953980
if intercepting {
@@ -1258,7 +1285,6 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12581285
iseqBuilder.emit(.brTable(operand))
12591286
let brTableAt = iseqBuilder.insertingPC
12601287

1261-
// TODO(optimize): Eliminate landing pads when copyCount of a destination is 0
12621288
//
12631289
// (block $l1 (result i32)
12641290
// (i32.const 63)
@@ -1296,10 +1322,17 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
12961322
offset: Int32(relativeOffset)
12971323
)
12981324
}
1299-
try copyOnBranch(targetFrame: frame)
1300-
iseqBuilder.emitWithLabel(frame.continuation) { _, brAt, continuation in
1301-
let relativeOffset = continuation.offsetFromHead - brAt.offsetFromHead
1302-
return .br(offset: Int32(relativeOffset))
1325+
let emittedCopy = try copyOnBranch(targetFrame: frame)
1326+
if emittedCopy {
1327+
iseqBuilder.emitWithLabel(frame.continuation) { _, brAt, continuation in
1328+
let relativeOffset = continuation.offsetFromHead - brAt.offsetFromHead
1329+
return .br(offset: Int32(relativeOffset))
1330+
}
1331+
} else {
1332+
// Optimization: If no value is copied, we can directly jump to the target
1333+
iseqBuilder.fillBrTableEntry(frame.continuation, table: tableBuffer, index: entryIndex) { _, continuation in
1334+
return Instruction.BrTable.Entry(offset: Int32(continuation.offsetFromHead - brTableAt.offsetFromHead))
1335+
}
13031336
}
13041337
}
13051338
try markUnreachable()

0 commit comments

Comments
 (0)