Skip to content

Commit

Permalink
[wasm] Add more simd load instructions
Browse files Browse the repository at this point in the history
Note that there are even more simd load instructions (those with
"extract lane") but they have different signatures, so they will need
separate Fuzzilli nodes and therefore are not included in this change.

Bug: chromium:391916477
Change-Id: Iab3f1be0e0c640445ec181240508c2ee0228edab
Reviewed-on: https://chrome-internal-review.googlesource.com/c/v8/fuzzilli/+/7988888
Reviewed-by: Carl Smith <[email protected]>
Reviewed-by: Eva Herencsárová <[email protected]>
Commit-Queue: Matthias Liedtke <[email protected]>
  • Loading branch information
Liedtke authored and V8-internal LUCI CQ committed Jan 30, 2025
1 parent 583b81c commit f31876f
Show file tree
Hide file tree
Showing 15 changed files with 269 additions and 47 deletions.
4 changes: 2 additions & 2 deletions Sources/Fuzzilli/Base/ProgramBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3346,9 +3346,9 @@ public class ProgramBuilder {
}

@discardableResult
public func wasmI64x2LoadSplat(memory: Variable, dynamicOffset: Variable, staticOffset: Int64) -> Variable {
func wasmSimdLoad(kind: WasmSimdLoad.Kind, memory: Variable, dynamicOffset: Variable, staticOffset: Int64) -> Variable {
let isMemory64 = b.type(of: memory).wasmMemoryType!.isMemory64
return b.emit(WasmI64x2LoadSplat(staticOffset: staticOffset, isMemory64: isMemory64), withInputs: [memory, dynamicOffset]).output
return b.emit(WasmSimdLoad(kind: kind, staticOffset: staticOffset, isMemory64: isMemory64), withInputs: [memory, dynamicOffset]).output
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Fuzzilli/CodeGen/CodeGeneratorWeights.swift
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ public let codeGeneratorWeights = [
"WasmSimd128CompareGenerator": 5,
"WasmI64x2SplatGenerator": 5,
"WasmI64x2ExtractLaneGenerator": 5,
"WasmI64x2LoadSplatGenerator": 5,
"WasmSimdLoadGenerator": 5,

"WasmSelectGenerator": 10,
]
6 changes: 3 additions & 3 deletions Sources/Fuzzilli/CodeGen/WasmCodeGenerators.swift
Original file line number Diff line number Diff line change
Expand Up @@ -850,13 +850,13 @@ public let WasmCodeGenerators: [CodeGenerator] = [
function.wasmI64x2ExtractLane(input, 0)
},

CodeGenerator("WasmI64x2LoadSplatGenerator", inContext: .wasmFunction, inputs: .required(.object(ofGroup: "WasmMemory"))) { b, memory in
CodeGenerator("WasmSimdLoadGenerator", inContext: .wasmFunction, inputs: .required(.object(ofGroup: "WasmMemory"))) { b, memory in
if (b.hasZeroPages(memory: memory)) { return }

let function = b.currentWasmModule.currentWasmFunction
let (dynamicOffset, staticOffset) = b.generateMemoryIndexes(forMemory: memory)

function.wasmI64x2LoadSplat(memory: memory, dynamicOffset: dynamicOffset, staticOffset: staticOffset)
let kind = chooseUniform(from: WasmSimdLoad.Kind.allCases)
function.wasmSimdLoad(kind: kind, memory: memory, dynamicOffset: dynamicOffset, staticOffset: staticOffset)
},

// TODO: Add three generators for JSPI
Expand Down
65 changes: 61 additions & 4 deletions Sources/Fuzzilli/FuzzIL/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,33 @@ extension Instruction: ProtobufConvertible {
}
}

func convertWasmSimdLoadKind(_ loadKind: WasmSimdLoad.Kind) -> Fuzzilli_Protobuf_WasmSimdLoadKind {
switch loadKind {
case .LoadS128:
return .loads128
case .Load8x8S:
return .load8X8S
case .Load8x8U:
return .load8X8U
case .Load16x4S:
return .load16X4S
case .Load16x4U:
return .load16X4U
case .Load32x2S:
return .load32X2S
case .Load32x2U:
return .load32X2U
case .Load8Splat:
return .load8Splat
case .Load16Splat:
return .load16Splat
case .Load32Splat:
return .load32Splat
case .Load64Splat:
return .load64Splat
}
}

func convertWasmGlobal(wasmGlobal: WasmGlobal) -> Fuzzilli_Protobuf_WasmGlobal.OneOf_WasmGlobal {
switch wasmGlobal {
case .wasmi32(let val):
Expand Down Expand Up @@ -1303,8 +1330,9 @@ extension Instruction: ProtobufConvertible {
$0.wasmI64X2Splat = Fuzzilli_Protobuf_WasmI64x2Splat()
case .wasmI64x2ExtractLane(_):
$0.wasmI64X2ExtractLane = Fuzzilli_Protobuf_WasmI64x2ExtractLane()
case .wasmI64x2LoadSplat(let op):
$0.wasmI64X2LoadSplat = Fuzzilli_Protobuf_WasmI64x2LoadSplat.with {
case .wasmSimdLoad(let op):
$0.wasmSimdLoad = Fuzzilli_Protobuf_WasmSimdLoad.with {
$0.kind = convertWasmSimdLoadKind(op.kind)
$0.staticOffset = op.staticOffset
$0.isMemory64 = op.isMemory64
}
Expand Down Expand Up @@ -1421,6 +1449,35 @@ extension Instruction: ProtobufConvertible {
}
}

func convertProtoWasmSimdLoadKind(_ loadKind: Fuzzilli_Protobuf_WasmSimdLoadKind) -> WasmSimdLoad.Kind {
switch loadKind {
case .loads128:
return .LoadS128
case .load8X8S:
return .Load8x8S
case .load8X8U:
return .Load8x8U
case .load16X4S:
return .Load16x4S
case .load16X4U:
return .Load16x4U
case .load32X2S:
return .Load32x2S
case .load32X2U:
return .Load32x2U
case .load8Splat:
return .Load8Splat
case .load16Splat:
return .Load16Splat
case .load32Splat:
return .Load32Splat
case .load64Splat:
return .Load64Splat
case .UNRECOGNIZED(let i):
fatalError("Invalid WasmSimdLoadKind \(i)")
}
}

func convertWasmGlobal(_ proto: Fuzzilli_Protobuf_WasmGlobal) -> WasmGlobal {
switch proto.wasmGlobal {
case .nullref(_):
Expand Down Expand Up @@ -2093,8 +2150,8 @@ extension Instruction: ProtobufConvertible {
op = WasmI64x2Splat()
case .wasmI64X2ExtractLane(_):
op = WasmI64x2ExtractLane(lane: 0)
case .wasmI64X2LoadSplat(let p):
op = WasmI64x2LoadSplat(staticOffset: p.staticOffset, isMemory64: p.isMemory64)
case .wasmSimdLoad(let p):
op = WasmSimdLoad(kind: convertProtoWasmSimdLoadKind(p.kind), staticOffset: p.staticOffset, isMemory64: p.isMemory64)
}

guard op.numInputs + op.numOutputs + op.numInnerOutputs == inouts.count else {
Expand Down
2 changes: 1 addition & 1 deletion Sources/Fuzzilli/FuzzIL/Opcodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ enum Opcode {
case wasmSimd128FloatBinOp(WasmSimd128FloatBinOp)
case wasmI64x2Splat(WasmI64x2Splat)
case wasmI64x2ExtractLane(WasmI64x2ExtractLane)
case wasmI64x2LoadSplat(WasmI64x2LoadSplat)
case wasmSimdLoad(WasmSimdLoad)

case wasmUnreachable(WasmUnreachable)
case wasmSelect(WasmSelect)
Expand Down
25 changes: 21 additions & 4 deletions Sources/Fuzzilli/FuzzIL/WasmOperations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1523,13 +1523,30 @@ final class WasmI64x2ExtractLane: WasmOperation {
}
}

final class WasmI64x2LoadSplat: WasmOperation {
override var opcode: Opcode { .wasmI64x2LoadSplat(self) }

final class WasmSimdLoad: WasmOperation {
enum Kind: UInt8, CaseIterable {
// TODO(mliedtke): Test all the other variants!
case LoadS128 = 0x00
case Load8x8S = 0x01
case Load8x8U = 0x02
case Load16x4S = 0x03
case Load16x4U = 0x04
case Load32x2S = 0x05
case Load32x2U = 0x06
case Load8Splat = 0x07
case Load16Splat = 0x08
case Load32Splat = 0x09
case Load64Splat = 0x0A
}

override var opcode: Opcode { .wasmSimdLoad(self) }

let kind: Kind
let staticOffset: Int64
let isMemory64: Bool

init(staticOffset: Int64, isMemory64: Bool) {
init(kind: Kind, staticOffset: Int64, isMemory64: Bool) {
self.kind = kind
self.staticOffset = staticOffset
self.isMemory64 = isMemory64
let dynamicOffsetType = isMemory64 ? ILType.wasmi64 : ILType.wasmi32
Expand Down
4 changes: 2 additions & 2 deletions Sources/Fuzzilli/Lifting/FuzzILLifter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1099,8 +1099,8 @@ public class FuzzILLifter: Lifter {
case .wasmI64x2ExtractLane(let op):
w.emit("\(output()) <- WasmI64x2ExtractLane \(input(0)) \(op.lane)")

case .wasmI64x2LoadSplat(_):
w.emit("\(output()) <- WasmI64x2LoadSplat \(input(0))")
case .wasmSimdLoad(let op):
w.emit("\(output()) <- WasmSimdLoad \(op.kind) \(input(0)) + \(op.staticOffset)")

default:
fatalError("No FuzzIL lifting for this operation!")
Expand Down
2 changes: 1 addition & 1 deletion Sources/Fuzzilli/Lifting/JavaScriptLifter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1607,7 +1607,7 @@ public class JavaScriptLifter: Lifter {
.wasmSimd128Compare(_),
.wasmI64x2Splat(_),
.wasmI64x2ExtractLane(_),
.wasmI64x2LoadSplat(_):
.wasmSimdLoad(_):
fatalError("unreachable")
}

Expand Down
6 changes: 3 additions & 3 deletions Sources/Fuzzilli/Lifting/WasmLifter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ public class WasmLifter {
try memoryOpImportAnalysis(instr: instr, isMemory64: op.isMemory64)
case .wasmMemoryStore(let op):
try memoryOpImportAnalysis(instr: instr, isMemory64: op.isMemory64)
case .wasmI64x2LoadSplat(let op):
case .wasmSimdLoad(let op):
try memoryOpImportAnalysis(instr: instr, isMemory64: op.isMemory64)
case .wasmTableGet(_),
.wasmTableSet(_):
Expand Down Expand Up @@ -1556,9 +1556,9 @@ public class WasmLifter {
return Data([0xFD]) + Leb128.unsignedEncode(0x12)
case .wasmI64x2ExtractLane(let op):
return Data([0xFD]) + Leb128.unsignedEncode(0x1D) + Leb128.unsignedEncode(op.lane)
case .wasmI64x2LoadSplat(let op):
case .wasmSimdLoad(let op):
// The memory immediate is {staticOffset, align} where align is 0 by default. Use signed encoding for potential bad (i.e. negative) offsets.
return Data([0xFD]) + Leb128.unsignedEncode(0x0A) + Leb128.unsignedEncode(0) + Leb128.signedEncode(Int(op.staticOffset))
return Data([0xFD, op.kind.rawValue]) + Leb128.unsignedEncode(0) + Leb128.signedEncode(Int(op.staticOffset))

default:
fatalError("unreachable")
Expand Down
2 changes: 1 addition & 1 deletion Sources/Fuzzilli/Mutators/OperationMutator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ public class OperationMutator: BaseInstructionMutator {
case .wasmI64x2ExtractLane(let op):
// TODO: ?
newOp = op
case .wasmI64x2LoadSplat(let op):
case .wasmSimdLoad(let op):
// TODO: ?
newOp = op
case .createWasmJSTag(let op):
Expand Down
114 changes: 104 additions & 10 deletions Sources/Fuzzilli/Protobuf/operations.pb.swift
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,76 @@ public enum Fuzzilli_Protobuf_WasmMemoryStoreType: SwiftProtobuf.Enum, Swift.Cas

}

public enum Fuzzilli_Protobuf_WasmSimdLoadKind: SwiftProtobuf.Enum, Swift.CaseIterable {
public typealias RawValue = Int
case loads128 // = 0
case load8X8S // = 1
case load8X8U // = 2
case load16X4S // = 3
case load16X4U // = 4
case load32X2S // = 5
case load32X2U // = 6
case load8Splat // = 7
case load16Splat // = 8
case load32Splat // = 9
case load64Splat // = 10
case UNRECOGNIZED(Int)

public init() {
self = .loads128
}

public init?(rawValue: Int) {
switch rawValue {
case 0: self = .loads128
case 1: self = .load8X8S
case 2: self = .load8X8U
case 3: self = .load16X4S
case 4: self = .load16X4U
case 5: self = .load32X2S
case 6: self = .load32X2U
case 7: self = .load8Splat
case 8: self = .load16Splat
case 9: self = .load32Splat
case 10: self = .load64Splat
default: self = .UNRECOGNIZED(rawValue)
}
}

public var rawValue: Int {
switch self {
case .loads128: return 0
case .load8X8S: return 1
case .load8X8U: return 2
case .load16X4S: return 3
case .load16X4U: return 4
case .load32X2S: return 5
case .load32X2U: return 6
case .load8Splat: return 7
case .load16Splat: return 8
case .load32Splat: return 9
case .load64Splat: return 10
case .UNRECOGNIZED(let i): return i
}
}

// The compiler won't synthesize support with the UNRECOGNIZED case.
public static let allCases: [Fuzzilli_Protobuf_WasmSimdLoadKind] = [
.loads128,
.load8X8S,
.load8X8U,
.load16X4S,
.load16X4U,
.load32X2S,
.load32X2U,
.load8Splat,
.load16Splat,
.load32Splat,
.load64Splat,
]

}

/// Parameters used by function definitions, not an operation by itself.
public struct Fuzzilli_Protobuf_Parameters: Sendable {
// SwiftProtobuf.Message conformance is added in an extension below. See the
Expand Down Expand Up @@ -4309,11 +4379,13 @@ public struct Fuzzilli_Protobuf_WasmI64x2ExtractLane: Sendable {
public init() {}
}

public struct Fuzzilli_Protobuf_WasmI64x2LoadSplat: Sendable {
public struct Fuzzilli_Protobuf_WasmSimdLoad: Sendable {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.

public var kind: Fuzzilli_Protobuf_WasmSimdLoadKind = .loads128

public var staticOffset: Int64 = 0

public var isMemory64: Bool = false
Expand Down Expand Up @@ -4488,6 +4560,22 @@ extension Fuzzilli_Protobuf_WasmMemoryStoreType: SwiftProtobuf._ProtoNameProvidi
]
}

extension Fuzzilli_Protobuf_WasmSimdLoadKind: SwiftProtobuf._ProtoNameProviding {
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "LOADS128"),
1: .same(proto: "LOAD8x8S"),
2: .same(proto: "LOAD8x8U"),
3: .same(proto: "LOAD16x4S"),
4: .same(proto: "LOAD16x4U"),
5: .same(proto: "LOAD32x2S"),
6: .same(proto: "LOAD32x2U"),
7: .same(proto: "LOAD8SPLAT"),
8: .same(proto: "LOAD16SPLAT"),
9: .same(proto: "LOAD32SPLAT"),
10: .same(proto: "LOAD64SPLAT"),
]
}

extension Fuzzilli_Protobuf_Parameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".Parameters"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
Expand Down Expand Up @@ -12597,11 +12685,12 @@ extension Fuzzilli_Protobuf_WasmI64x2ExtractLane: SwiftProtobuf.Message, SwiftPr
}
}

extension Fuzzilli_Protobuf_WasmI64x2LoadSplat: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".WasmI64x2LoadSplat"
extension Fuzzilli_Protobuf_WasmSimdLoad: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
public static let protoMessageName: String = _protobuf_package + ".WasmSimdLoad"
public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "staticOffset"),
2: .same(proto: "isMemory64"),
1: .same(proto: "kind"),
2: .same(proto: "staticOffset"),
3: .same(proto: "isMemory64"),
]

public mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
Expand All @@ -12610,24 +12699,29 @@ extension Fuzzilli_Protobuf_WasmI64x2LoadSplat: SwiftProtobuf.Message, SwiftProt
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt64Field(value: &self.staticOffset) }()
case 2: try { try decoder.decodeSingularBoolField(value: &self.isMemory64) }()
case 1: try { try decoder.decodeSingularEnumField(value: &self.kind) }()
case 2: try { try decoder.decodeSingularInt64Field(value: &self.staticOffset) }()
case 3: try { try decoder.decodeSingularBoolField(value: &self.isMemory64) }()
default: break
}
}
}

public func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.kind != .loads128 {
try visitor.visitSingularEnumField(value: self.kind, fieldNumber: 1)
}
if self.staticOffset != 0 {
try visitor.visitSingularInt64Field(value: self.staticOffset, fieldNumber: 1)
try visitor.visitSingularInt64Field(value: self.staticOffset, fieldNumber: 2)
}
if self.isMemory64 != false {
try visitor.visitSingularBoolField(value: self.isMemory64, fieldNumber: 2)
try visitor.visitSingularBoolField(value: self.isMemory64, fieldNumber: 3)
}
try unknownFields.traverse(visitor: &visitor)
}

public static func ==(lhs: Fuzzilli_Protobuf_WasmI64x2LoadSplat, rhs: Fuzzilli_Protobuf_WasmI64x2LoadSplat) -> Bool {
public static func ==(lhs: Fuzzilli_Protobuf_WasmSimdLoad, rhs: Fuzzilli_Protobuf_WasmSimdLoad) -> Bool {
if lhs.kind != rhs.kind {return false}
if lhs.staticOffset != rhs.staticOffset {return false}
if lhs.isMemory64 != rhs.isMemory64 {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
Expand Down
Loading

0 comments on commit f31876f

Please sign in to comment.