Skip to content

Commit 4aff9cc

Browse files
Eliminate runtime shift operations for register access
1 parent 9c1f0c9 commit 4aff9cc

File tree

5 files changed

+85
-13
lines changed

5 files changed

+85
-13
lines changed

Sources/WasmKit/Execution/Execution.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,50 @@ extension Sp {
130130
return self[Int(index)] = newValue.storage
131131
}
132132
}
133+
134+
subscript<R: ShiftedVReg>(_ index: R) -> UntypedValue {
135+
get {
136+
return UntypedValue(storage: read(shifted: index))
137+
}
138+
nonmutating set {
139+
write(shifted: index, newValue)
140+
}
141+
}
142+
143+
private func read<T: FixedWidthInteger, R: ShiftedVReg>(shifted index: R) -> T {
144+
return UnsafeRawPointer(self).advanced(by: Int(index.value)).withMemoryRebound(to: T.self, capacity: 1) {
145+
$0.pointee
146+
}
147+
}
133148
private func read<T: FixedWidthInteger, R: FixedWidthInteger>(_ index: R) -> T {
134149
return self.advanced(by: Int(index)).withMemoryRebound(to: T.self, capacity: 1) {
135150
$0.pointee
136151
}
137152
}
153+
private func write<R: ShiftedVReg>(shifted index: R, _ value: UntypedValue) {
154+
UnsafeMutableRawPointer(self).advanced(by: Int(index.value)).storeBytes(of: value.storage, as: UInt64.self)
155+
}
138156
private func write<R: FixedWidthInteger>(_ index: R, _ value: UntypedValue) {
139157
self[Int(index)] = value
140158
}
159+
160+
subscript<R: ShiftedVReg>(i32 index: R) -> UInt32 {
161+
get { return read(shifted: index) }
162+
nonmutating set { write(shifted: index, .i32(newValue)) }
163+
}
164+
subscript<R: ShiftedVReg>(i64 index: R) -> UInt64 {
165+
get { return read(shifted: index) }
166+
nonmutating set { write(shifted: index, .i64(newValue)) }
167+
}
168+
subscript<R: ShiftedVReg>(f32 index: R) -> Float32 {
169+
get { return Float32(bitPattern: read(shifted: index)) }
170+
nonmutating set { write(shifted: index, .f32(newValue)) }
171+
}
172+
subscript<R: ShiftedVReg>(f64 index: R) -> Float64 {
173+
get { return Float64(bitPattern: read(shifted: index)) }
174+
nonmutating set { write(shifted: index, .f64(newValue)) }
175+
}
176+
141177
subscript<R: FixedWidthInteger>(i32 index: R) -> UInt32 {
142178
get { return read(index) }
143179
nonmutating set { write(index, .i32(newValue)) }

Sources/WasmKit/Execution/Instructions/Instruction.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ extension Instruction {
431431
return Self(reg: reg, rawGlobal: rawGlobal)
432432
}
433433
@inline(__always) static func emit(to emitSlot: ((Self) -> CodeSlot) -> Void) {
434-
emitSlot { CodeSlot(bitPattern: $0.reg) }
434+
emitSlot { unsafeBitCast(($0.reg) as (LLVReg), to: CodeSlot.self) }
435435
emitSlot { $0.rawGlobal }
436436
}
437437
}
@@ -623,7 +623,7 @@ extension Instruction {
623623
}
624624
@inline(__always) static func emit(to emitSlot: ((Self) -> CodeSlot) -> Void) {
625625
emitSlot { unsafeBitCast(($0.value) as (UntypedValue), to: CodeSlot.self) }
626-
emitSlot { CodeSlot(bitPattern: $0.result) }
626+
emitSlot { unsafeBitCast(($0.result) as (LLVReg), to: CodeSlot.self) }
627627
}
628628
}
629629

Sources/WasmKit/Execution/Instructions/InstructionSupport.swift

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,48 @@
11
import WasmParser
22

3+
/// A register that is used to store a value in the stack.
34
typealias VReg = Int16
4-
typealias LVReg = Int32
5-
typealias LLVReg = Int64
5+
6+
/// A register value that is pre-shifted to avoid runtime shift operation.
7+
protocol ShiftedVReg {
8+
associatedtype Storage: FixedWidthInteger
9+
10+
/// The value of the shifted register.
11+
/// Must be a multiple of `MemoryLayout<StackSlot>.size`.
12+
var value: Storage { get }
13+
}
14+
15+
/// A larger (32-bit) version of `VReg`
16+
/// Used to utilize halfword loads instructions.
17+
struct LVReg: Equatable, ShiftedVReg {
18+
let value: Int32
19+
20+
init(_ value: VReg) {
21+
// Pre-shift to avoid runtime shift operation by using
22+
// unused high bits.
23+
self.value = Int32(value) * Int32(MemoryLayout<StackSlot>.size)
24+
}
25+
26+
init(storage: Int32) {
27+
self.value = storage
28+
}
29+
}
30+
31+
/// A larger (64-bit) version of `VReg`
32+
/// Used to utilize word loads instructions.
33+
struct LLVReg: Equatable, ShiftedVReg {
34+
let value: Int64
35+
36+
init(_ value: VReg) {
37+
// Pre-shift to avoid runtime shift operation by using
38+
// unused high bits.
39+
self.value = Int64(value) * Int64(MemoryLayout<StackSlot>.size)
40+
}
41+
42+
init(storage: Int64) {
43+
self.value = storage
44+
}
45+
}
646

747
extension RawUnsignedInteger {
848
init(_ slot: CodeSlot, shiftWidth: Int) {
@@ -85,10 +125,10 @@ extension VReg: InstructionImmediate {
85125

86126
extension LLVReg: InstructionImmediate {
87127
static func load(from pc: inout Pc) -> Self {
88-
Self(bitPattern: pc.read())
128+
Self(storage: Int64(bitPattern: pc.read()))
89129
}
90130
static func emit(to emitSlot: ((Self) -> CodeSlot) -> Void) {
91-
emitSlot { UInt64(bitPattern: $0) }
131+
emitSlot { UInt64(bitPattern: $0.value) }
92132
}
93133
}
94134

@@ -184,6 +224,8 @@ struct InstructionPrintingContext {
184224
return "reg:\(reg)"
185225
}
186226
}
227+
func reg(_ x: LVReg) -> String { reg(x.value) }
228+
func reg(_ x: LLVReg) -> String { reg(x.value) }
187229

188230
func offset(_ offset: UInt64) -> String {
189231
"offset: \(offset)"

Sources/WasmKit/Translator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ struct InstructionTranslator<Context: TranslatorContext>: InstructionVisitor {
853853
@discardableResult
854854
private mutating func emitCopyStack(from source: VReg, to dest: VReg) -> Bool {
855855
guard source != dest else { return false }
856-
emit(.copyStack(Instruction.CopyStackOperand(source: Int32(source), dest: Int32(dest))))
856+
emit(.copyStack(Instruction.CopyStackOperand(source: LVReg(source), dest: LVReg(dest))))
857857
return true
858858
}
859859

Utilities/Sources/VMSpec/Immediate.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,6 @@ extension VMGen {
125125
output += """
126126
emitSlot { $0.\(slot[0].name) }
127127
128-
"""
129-
continue
130-
case "LLVReg":
131-
output += """
132-
emitSlot { CodeSlot(bitPattern: $0.\(slot[0].name)) }
133-
134128
"""
135129
continue
136130
default: break

0 commit comments

Comments
 (0)