From 714c0c4f6bb7665b4e96a91ec5e5a8185eb36e1c Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 14:36:38 +0000 Subject: [PATCH 01/51] Add basic LLVM backend scaffolding --- CMakeLists.txt | 27 +- Sources/CLI/CMakeLists.txt | 6 +- Sources/CMakeLists.txt | 9 + Sources/LLVMBackend/CMakeLists.txt | 68 ++++ Sources/LLVMBackend/CodegenContext.swift | 135 +++++++ Sources/LLVMBackend/IRContext+codegen.swift | 43 ++ Sources/LLVMBackend/IRFunctionVisitor.swift | 403 +++++++++++++++++++ Sources/LLVMBackend/LLInstance.swift | 36 ++ Sources/LLVMBackend/LLStore.swift | 11 + Sources/LLVMBackend/Linker.swift | 32 ++ Sources/LLVMBackend/Loader.swift | 53 +++ Sources/LLVMBackend/Wasm32Memory.swift | 12 + Sources/LLVMBackendCLI/CMakeLists.txt | 32 ++ Sources/LLVMBackendCLI/Entrypoint.swift | 37 ++ Sources/LLVMInterop/CMakeLists.txt | 43 ++ Sources/LLVMInterop/IR/IRFunction.cpp | 24 ++ Sources/LLVMInterop/IR/IRPHINode.cpp | 7 + Sources/LLVMInterop/IRContext.cpp | 249 ++++++++++++ Sources/LLVMInterop/include/IRBlock.h | 19 + Sources/LLVMInterop/include/IRContext.h | 136 +++++++ Sources/LLVMInterop/include/IRFunction.h | 28 ++ Sources/LLVMInterop/include/IRFunctionType.h | 14 + Sources/LLVMInterop/include/IRPHINode.h | 17 + Sources/LLVMInterop/include/IRPointerType.h | 11 + Sources/LLVMInterop/include/IRType.h | 16 + Sources/LLVMInterop/include/IRValue.h | 16 + Sources/LLVMInterop/include/module.modulemap | 4 + 27 files changed, 1474 insertions(+), 14 deletions(-) create mode 100644 Sources/LLVMBackend/CMakeLists.txt create mode 100644 Sources/LLVMBackend/CodegenContext.swift create mode 100644 Sources/LLVMBackend/IRContext+codegen.swift create mode 100644 Sources/LLVMBackend/IRFunctionVisitor.swift create mode 100644 Sources/LLVMBackend/LLInstance.swift create mode 100644 Sources/LLVMBackend/LLStore.swift create mode 100644 Sources/LLVMBackend/Linker.swift create mode 100644 Sources/LLVMBackend/Loader.swift create mode 100644 Sources/LLVMBackend/Wasm32Memory.swift create mode 100644 Sources/LLVMBackendCLI/CMakeLists.txt create mode 100644 Sources/LLVMBackendCLI/Entrypoint.swift create mode 100644 Sources/LLVMInterop/CMakeLists.txt create mode 100644 Sources/LLVMInterop/IR/IRFunction.cpp create mode 100644 Sources/LLVMInterop/IR/IRPHINode.cpp create mode 100644 Sources/LLVMInterop/IRContext.cpp create mode 100644 Sources/LLVMInterop/include/IRBlock.h create mode 100644 Sources/LLVMInterop/include/IRContext.h create mode 100644 Sources/LLVMInterop/include/IRFunction.h create mode 100644 Sources/LLVMInterop/include/IRFunctionType.h create mode 100644 Sources/LLVMInterop/include/IRPHINode.h create mode 100644 Sources/LLVMInterop/include/IRPointerType.h create mode 100644 Sources/LLVMInterop/include/IRType.h create mode 100644 Sources/LLVMInterop/include/IRValue.h create mode 100644 Sources/LLVMInterop/include/module.modulemap diff --git a/CMakeLists.txt b/CMakeLists.txt index e6289e5e..4374353f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,21 @@ -cmake_minimum_required(VERSION 3.19.6) +cmake_minimum_required(VERSION 3.30) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) -project(WasmKit LANGUAGES C Swift) +project(WasmKit LANGUAGES C CXX Swift) -set(SWIFT_VERSION 5) +set(SWIFT_VERSION 6) set(CMAKE_Swift_LANGUAGE_VERSION ${SWIFT_VERSION}) +set(min_supported_swift_version 6.2) +if(CMAKE_Swift_COMPILER_VERSION VERSION_LESS "${min_supported_swift_version}") + message( + FATAL_ERROR + "Outdated Swift compiler: " + "Swift ${min_supported_swift_version} or newer is required." + ) +endif() + # Enable whole module optimization for Release or RelWithDebInfo builds. if(POLICY CMP0157) set(CMAKE_Swift_COMPILATION_MODE $,wholemodule,incremental>) @@ -14,13 +23,6 @@ else() add_compile_options($<$,$>:-wmo>) endif() -if(CMAKE_VERSION VERSION_LESS 3.21) - get_property(parent_dir DIRECTORY PROPERTY PARENT_DIRECTORY) - if(NOT parent_dir) - set(PROJECT_IS_TOP_LEVEL TRUE) - endif() -endif() - # The subdirectory into which host libraries will be installed. set(SWIFT_HOST_LIBRARIES_SUBDIRECTORY "swift/host") @@ -58,11 +60,13 @@ if(NOT SwiftSystem_FOUND) FetchContent_Declare(SwiftSystem GIT_REPOSITORY https://github.com/apple/swift-system GIT_TAG 1.5.0 + GIT_SHALLOW TRUE ) FetchContent_MakeAvailable(SwiftSystem) endif() -option(WASMKIT_BUILD_CLI "Build wasmkit-cli" ON) +option(WASMKIT_BUILD_CLI "Build WasmKit CLI" ON) +option(WASMKIT_BUILD_LLVM_BACKEND "Build WasmKit LLVM backend (experimental)") if(WASMKIT_BUILD_CLI) set(BUILD_TESTING OFF) # disable ArgumentParser tests @@ -72,6 +76,7 @@ if(WASMKIT_BUILD_CLI) FetchContent_Declare(ArgumentParser GIT_REPOSITORY https://github.com/apple/swift-argument-parser GIT_TAG 1.6.1 + GIT_SHALLOW TRUE ) FetchContent_MakeAvailable(ArgumentParser) endif() diff --git a/Sources/CLI/CMakeLists.txt b/Sources/CLI/CMakeLists.txt index bba5cda1..4a6d8d35 100644 --- a/Sources/CLI/CMakeLists.txt +++ b/Sources/CLI/CMakeLists.txt @@ -1,12 +1,12 @@ -add_executable(wasmkit-cli +add_executable(wasmkit Commands/Explore.swift Commands/Run.swift Commands/Wat2wasm.swift CLI.swift ) -target_link_wasmkit_libraries(wasmkit-cli PUBLIC +target_link_wasmkit_libraries(wasmkit PUBLIC ArgumentParser WAT WasmKitWASI) -install(TARGETS wasmkit-cli +install(TARGETS wasmkit RUNTIME DESTINATION bin) diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index 1f773267..9197f75d 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -10,3 +10,12 @@ add_subdirectory(WAT) if(WASMKIT_BUILD_CLI) add_subdirectory(CLI) endif() + +if(WASMKIT_BUILD_LLVM_BACKEND) + add_subdirectory(LLVMInterop) + add_subdirectory(LLVMBackend) + + if(WASMKIT_BUILD_CLI) + add_subdirectory(LLVMBackendCLI) + endif() +endif() diff --git a/Sources/LLVMBackend/CMakeLists.txt b/Sources/LLVMBackend/CMakeLists.txt new file mode 100644 index 00000000..f2095eca --- /dev/null +++ b/Sources/LLVMBackend/CMakeLists.txt @@ -0,0 +1,68 @@ +add_library( + LLVMBackend + + CodegenContext.swift + IRContext+codegen.swift + IRFunctionVisitor.swift + LLInstance.swift + LLStore.swift + Linker.swift + Loader.swift + Wasm32Memory.swift +) +target_compile_options( + LLVMBackend + PUBLIC + "SHELL:-Xcc -std=c++17" + "SHELL:-Xcc -fapinotes" + "SHELL:-Xcc -fapinotes-modules" + "-cxx-interoperability-mode=default" + -package-name WasmKitPackage +) + +target_include_directories( + LLVMBackend + PUBLIC + "${LLVMINTEROP_INCLUDE_DIR}" + "${LLVM_MAIN_INCLUDE_DIR}" + "${LLVM_INCLUDE_DIR}" +) + +set(WASMKIT_DEPENDENCIES WAT WasmKit WasmTypes WasmParser) +set(BUILD_TESTING OFF) + +include(FetchContent) + +FetchContent_Declare( + SwiftLLVMBindings + GIT_REPOSITORY "https://github.com/swiftlang/swift-llvm-bindings.git" + GIT_TAG c1fffb92d4f9d7cb98800762631cfa354869fb46 + GIT_SHALLOW TRUE + GIT_PROGRESS ON +) + +FetchContent_MakeAvailable(SwiftLLVMBindings) + +find_package(Subprocess CONFIG) + +if(NOT Subprocess_FOUND) + message("-- Vending Subprocess") + FetchContent_Declare( + Subprocess + GIT_REPOSITORY https://github.com/swiftlang/swift-subprocess + GIT_TAG 0.2.1 + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable(Subprocess) +endif() + + +add_dependencies(LLVMInterop LLVM_Utils Subprocess ${WASMKIT_DEPENDENCIES}) + +target_link_libraries( + LLVMBackend + ${WASMKIT_DEPENDENCIES} + LLVMInterop + LLVM_Utils + Subprocess +) diff --git a/Sources/LLVMBackend/CodegenContext.swift b/Sources/LLVMBackend/CodegenContext.swift new file mode 100644 index 00000000..a14aa64e --- /dev/null +++ b/Sources/LLVMBackend/CodegenContext.swift @@ -0,0 +1,135 @@ +import LLVMInterop +import LLVM_Analysis +import LLVM_Utils +import SystemPackage +import WAT +import WasmParser +import WasmTypes + +package struct CodegenContext: ~Copyable { + enum Error: Swift.Error { + case objectFileEmissionFailed + case multiValueResultsNotSupportedYet(functionName: String) + case unsupportedImport(Import) + } + + private(set) var ir: IRContext + + private let isVerbose: Bool + + package init(isVerbose: Bool) { + self.ir = IRContext() + self.isVerbose = isVerbose + } + + mutating func codegen(wasmStream: some ByteStream) throws { + var parser = Parser(stream: wasmStream) + + var types = [FunctionType]() + var functionTypes = [TypeIndex]() + var functionVisitors: UnsafeMutableBufferPointer? + defer { + if let functionVisitors { + functionVisitors.deallocate() + } + } + var importedFunctions = [IRValue]() + var functionNames = [String]() + var memories = [Memory]() + + while let payload = try parser.parseNext() { + switch payload { + case .typeSection(let t): types = t + case .functionSection(let f): functionTypes.append(contentsOf: f) + case .memorySection(let m): + memories = m + + case .importSection(let imports): + for i in imports { + switch i.descriptor { + case .function(let typeIndex): + let type = types[Int(typeIndex)] + + guard type.results.count <= 1 else { + throw Error.multiValueResultsNotSupportedYet(functionName: "\(i.module).\(i.name)") + } + + let irType = self.ir.__pointerTypeUnsafe() + + // Mangle the name with character counts to avoid naming collisions. + // Without this mangling we can't distinguish between a function + // ".print" from module "foo" and function "print" from module "foo.", + // as without character counts they both would be mangled as `foo.print`. + // Another alternative could be to introduce a separator that's not allowed + // in Wasm function and module names (which one?), but character counts + // seem more reliable and predictable at the moment of writing. + let name = "\(i.module.count)_\(i.name.count)_\(i.module).\(i.name)" + name.withStringRef { + importedFunctions.append(self.ir.__createImportedFunctionUnsafe($0, irType)) + } + functionNames.append(name) + functionTypes.append(typeIndex) + + case .global, .table, .memory: + throw Error.unsupportedImport(i) + } + } + + case .codeSection(let functions): + functionVisitors = .allocate(capacity: functions.count) + for (i, f) in functions.enumerated() { + let type = types[Int(functionTypes[importedFunctions.count + i])] + // Create visitors first before actually visiting instructions. + // This will forward-declare all `llvm::Function` instances so that `call` + // LLVM IR instructions have these instances to refer to and are valid. + let name = "\(i)" + try functionVisitors?[i] = .init( + name: name, + type: type, + locals: type.parameters + f.locals, + code: f, + ir: self.ir, + ) + + functionNames.append(name) + } + default: continue + } + } + + if let functionVisitors { + for i in 0.. FilePath { + let fd = try FileDescriptor.open(wasmPath, .readOnly) + try self.codegen(wasmStream: FileHandleStream(fileHandle: fd)) + var objectFilePath = wasmPath + objectFilePath.extension = "o" + guard objectFilePath.string.withStringRef({ self.ir.emitObjectFile($0) }) else { + throw Error.objectFileEmissionFailed + } + + return objectFilePath + } +} + +extension IRContext { + func function(type: IRFunctionType, name: String) -> IRFunction? { + let f = name.withStringRef { + self.__functionUnsafe(type, $0) + } + + return if f._isValid { f } else { nil } + } +} diff --git a/Sources/LLVMBackend/IRContext+codegen.swift b/Sources/LLVMBackend/IRContext+codegen.swift new file mode 100644 index 00000000..b8299478 --- /dev/null +++ b/Sources/LLVMBackend/IRContext+codegen.swift @@ -0,0 +1,43 @@ +import LLVMInterop +import WasmTypes + +extension IRContext { + func codegen(resultType: [ValueType]) -> IRType { + switch resultType.count { + case 0: + return self.__voidTypeUnsafe() + case 1: + return codegen(type: resultType[0]) + default: + var types = IRTypeVector() + for t in resultType { + types.push_back(codegen(type: t)._t) + } + return self.__structTypeUnsafe(types) + } + } + + func codegen(type: ValueType) -> IRType { + switch type { + case .i32: + self.__i32TypeUnsafe() + case .i64: + self.__i64TypeUnsafe() + case .f32: + self.__f32TypeUnsafe() + case .f64: + self.__f64TypeUnsafe() + case .v128, .ref(_): + fatalError() + } + } + + func codegen(functionType: FunctionType) -> IRFunctionType { + var parameterTypes = IRTypeVector() + for parameterType in functionType.parameters { + parameterTypes.push_back(codegen(type: parameterType)._t) + } + + return self.__functionTypeUnsafe(parameterTypes, codegen(resultType: functionType.results)) + } +} diff --git a/Sources/LLVMBackend/IRFunctionVisitor.swift b/Sources/LLVMBackend/IRFunctionVisitor.swift new file mode 100644 index 00000000..7d665c7e --- /dev/null +++ b/Sources/LLVMBackend/IRFunctionVisitor.swift @@ -0,0 +1,403 @@ +import LLVMInterop +import WasmParser +import WasmTypes + +struct IRFunctionVisitor: InstructionVisitor { + enum Error: Swift.Error { + case irFunctionUnknown(Int) + case irFunctionCreationFailed + case irFunctionStackNotEmpty + case irFunctionVerificationFailure(String) + } + + struct Local { + let type: IRType + let address: IRValue + } + private var locals: [Local] + + private var ir: IRContext + let function: IRFunction + + var binaryOffset = 0 + + private(set) var stack = [IRValue]() + private(set) var types = [FunctionType]() + private(set) var functionTypes = [TypeIndex]() + private(set) var functionNames = [String]() + private(set) var importedFunctions = [IRValue]() + private(set) var memories = [Memory]() + + private let name: String + private let code: Code + private var blocks: [IRBlock] + private var currentBlock: IRBlock + + /// Blocks that haven't had their own instructions visited yet, but are needed as targets of `br` instructions + private var pendingBlocks = [IRBlock]() + + /// Trivial counter used for unique block names, incremented when new blocks are created. + private var blockCounter = 0 + + /// Representation of nested Wasm blocks to keep track of when converting to a linear sequence of LLVM IR basic blocks. + struct NestedWasmBlock { + enum Kind { + case `if`(condition: IRValue) + case loop + case plain + } + + let kind: Kind + + let parent: IRBlock + let resultType: IRType? + + var branchBlocks = [IRBlock]() + var phiValues = [IRValue]() + } + + private var nestedBlocks = [NestedWasmBlock]() + + mutating func push(_ value: IRValue) { + stack.append(value) + } + + mutating func pop() -> IRValue { + stack.removeLast() + } + + init(name: String, type: FunctionType, locals: [ValueType], code: Code, ir: IRContext) throws { + let functionType = ir.codegen(functionType: type) + + guard let function = ir.function(type: functionType, name: name) else { + throw Error.irFunctionCreationFailed + } + + self.name = name + self.code = code + self.ir = ir + + self.currentBlock = "entry".withStringRef { ir.__blockUnsafe(function, $0) } + self.blocks = [self.currentBlock] + self.ir.setInsertPoint(self.currentBlock) + + self.locals = locals.enumerated().map { + let type = ir.codegen(type: $1) + let address = ir.__createLocalUnsafe(type) + let result = IRFunctionVisitor.Local( + type: type, + address: address + ) + + ir.setLocal(address, function.getArgument(UInt32($0))) + + return result + } + + self.function = function + } + + mutating func createBlock() { + defer { self.blockCounter += 1 } + "bb\(blockCounter)".withStringRef { + self.currentBlock = self.ir.__blockUnsafe(self.function, $0) + } + self.blocks.append(self.currentBlock) + self.ir.setInsertPoint(self.currentBlock) + } + + mutating func visit( + _ types: [FunctionType], + _ functionTypes: [TypeIndex], + _ memories: [Memory], + importedFunctions: [IRValue], + functionNames: [String] + ) throws { + self.types = types + self.functionTypes = functionTypes + self.memories = memories + self.importedFunctions = importedFunctions + self.functionNames = functionNames + + self.ir.setInsertPoint(self.currentBlock) + + try self.code.parseExpression(visitor: &self) + + // optimization passes don't like empty blocks + if self.currentBlock.isEmpty() && self.blocks.count > 1 { + self.currentBlock.eraseFromParent() + self.blocks.removeLast() + self.currentBlock = self.blocks.last! + self.ir.setInsertPoint(self.currentBlock) + } + + self.ir.createRet(pop()) + + guard self.stack.isEmpty else { + throw Error.irFunctionStackNotEmpty + } + + if let error = self.function.verify().value { + throw Error.irFunctionVerificationFailure(.init(error)) + } + + self.ir.optimize(self.function) + + if let error = self.function.verify().value { + throw Error.irFunctionVerificationFailure(.init(error)) + } + } + + mutating func visitCall(functionIndex: UInt32) throws { + let functionIndex = Int(functionIndex) + + guard + self.functionNames.count > functionIndex, + let f = self.functionNames[functionIndex].withStringRef({ ir.getFunction($0) }).value + else { + throw Error.irFunctionUnknown(functionIndex) + } + + let argTypes = self.types[Int(self.functionTypes[functionIndex])].parameters + var args = IRValueVector() + + for _ in 0.. 1 { + self.ir.__condBrUnsafe( + condition, lastNestedBlock.branchBlocks[0], lastNestedBlock.branchBlocks[1]) + } else { + self.ir.__condBrUnsafe(condition, lastNestedBlock.branchBlocks[0]) + } + } + + self.createBlock() + + if case .if = lastNestedBlock.kind, let resultType = lastNestedBlock.resultType { + // Make sure that `branchBlocks` have terminators. + for block in lastNestedBlock.branchBlocks { + self.ir.setInsertPoint(block) + + // Terminators of `if` blocks should branch to the current block we've just created. + self.ir.br(self.currentBlock) + } + // Set the insertion point back after it was moved for `branchBlocks`. + self.ir.setInsertPoint(self.currentBlock) + + var phi = self.ir.__phiUnsafe( + resultType, .init(lastNestedBlock.phiValues.count) + ) + + for (value, block) in zip(lastNestedBlock.phiValues, lastNestedBlock.branchBlocks) { + phi.addIncoming(value, block) + } + + self.push(IRValue(phi)) + } + + self.nestedBlocks.removeLast() + } + + mutating func visitBlock(blockType: BlockType) throws { fatalError() } + mutating func visitLoop(blockType: BlockType) throws { fatalError() } + + mutating func visitIf(blockType: BlockType) throws { + let condition = self.ir.__bEqUnsafe(self.pop(), self.ir.__i32ValueUnsafe(1)) + + switch blockType { + case .funcType(let index): + fatalError("multi-value blocks are currently not supported") + + case .empty: + self.nestedBlocks.append( + .init(kind: .if(condition: condition), parent: self.currentBlock, resultType: nil)) + + case .type(let type): + self.nestedBlocks.append( + .init( + kind: .if(condition: condition), parent: self.currentBlock, + resultType: self.ir.codegen(type: type)) + ) + } + + createBlock() + } + + mutating func visitElse() throws { + guard let lastBlock = self.nestedBlocks.last, case .if = lastBlock.kind else { + fatalError() + } + + if lastBlock.resultType != nil { + self.nestedBlocks[self.nestedBlocks.count - 1].phiValues.append(pop()) + } + + self.nestedBlocks[self.nestedBlocks.count - 1].branchBlocks.append(self.currentBlock) + + self.createBlock() + } + + mutating func visitBr(relativeDepth: UInt32) throws { fatalError() } + + mutating func visitBrIf(relativeDepth: UInt32) throws { fatalError() } + mutating func visitBrTable(targets: BrTable) throws { fatalError() } + mutating func visitReturn() throws { fatalError() } + mutating func visitCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws { fatalError() } + mutating func visitReturnCall(functionIndex: UInt32) throws { fatalError() } + mutating func visitReturnCallIndirect(typeIndex: UInt32, tableIndex: UInt32) throws { + fatalError() + } + mutating func visitSelect() throws { fatalError() } + mutating func visitTypedSelect(type: ValueType) throws { fatalError() } + mutating func visitLocalSet(localIndex: UInt32) throws { fatalError() } + mutating func visitLocalTee(localIndex: UInt32) throws { fatalError() } + mutating func visitGlobalGet(globalIndex: UInt32) throws { fatalError() } + mutating func visitGlobalSet(globalIndex: UInt32) throws { fatalError() } + mutating func visitLoad(_ load: Instruction.Load, memarg: MemArg) throws { fatalError() } + mutating func visitStore(_ store: Instruction.Store, memarg: MemArg) throws { fatalError() } + mutating func visitMemorySize(memory: UInt32) throws { fatalError() } + mutating func visitMemoryGrow(memory: UInt32) throws { fatalError() } + mutating func visitI64Const(value: Int64) throws { fatalError() } + mutating func visitF32Const(value: IEEE754.Float32) throws { fatalError() } + mutating func visitF64Const(value: IEEE754.Float64) throws { fatalError() } + mutating func visitI32Eqz() throws { fatalError() } + mutating func visitI64Eqz() throws { fatalError() } + mutating func visitUnary(_ unary: Instruction.Unary) throws { fatalError() } + mutating func visitConversion(_ conversion: Instruction.Conversion) throws { fatalError() } + mutating func visitMemoryInit(dataIndex: UInt32) throws { fatalError() } + mutating func visitDataDrop(dataIndex: UInt32) throws { fatalError() } + mutating func visitMemoryCopy(dstMem: UInt32, srcMem: UInt32) throws { fatalError() } + mutating func visitMemoryFill(memory: UInt32) throws { fatalError() } + + mutating func visitRefNull(type: ReferenceType) throws { fatalError() } + mutating func visitRefIsNull() throws { fatalError() } + mutating func visitRefFunc(functionIndex: UInt32) throws { fatalError() } + + mutating func visitTableInit(elemIndex: UInt32, table: UInt32) throws { fatalError() } + mutating func visitElemDrop(elemIndex: UInt32) throws { fatalError() } + mutating func visitTableCopy(dstTable: UInt32, srcTable: UInt32) throws { fatalError() } + mutating func visitTableFill(table: UInt32) throws { fatalError() } + mutating func visitTableGet(table: UInt32) throws { fatalError() } + mutating func visitTableSet(table: UInt32) throws { fatalError() } + mutating func visitTableGrow(table: UInt32) throws { fatalError() } + mutating func visitTableSize(table: UInt32) throws { fatalError() } + + private mutating func codegen(value: Value) { + switch value { + case .f32(let f32): + push(ir.__f32ValueUnsafe(.init(bitPattern: f32))) + case .f64(let f64): + push(ir.__f64ValueUnsafe(.init(bitPattern: f64))) + case .i32(let i32): + push(ir.__i32ValueUnsafe(i32)) + case .i64(let i64): + push(ir.__i64ValueUnsafe(i64)) + case .ref: + fatalError() + } + } + + // mutating func codegen(conversion instruction: NumericInstruction.Conversion) { + // let v = pop() + // + // switch instruction { + // case .wrap: + // push(ir.__wrapUnsafe(v)) + // case .extendUnsigned: + // push(ir.__extendUnsignedUnsafe(v)) + // case .extendSigned: + // push(ir.__extendSignedUnsafe(v)) + // default: + // fatalError() + // } + // } +} + +extension IRFunction: @retroactive CustomStringConvertible { + public var description: String { + .init(self.print().value!) + } +} + +extension IRFunctionType: @retroactive CustomStringConvertible { + public var description: String { + .init(self.print()) + } +} diff --git a/Sources/LLVMBackend/LLInstance.swift b/Sources/LLVMBackend/LLInstance.swift new file mode 100644 index 00000000..414f1545 --- /dev/null +++ b/Sources/LLVMBackend/LLInstance.swift @@ -0,0 +1,36 @@ +import WasmKit + +package final class LLInstance { + package init() {} + + package let exports = LLExports() + + package func export(_ name: String) -> LLExternalValue { + fatalError() + } + + package func exportedFunction(name: String) -> LLFunction? { + fatalError() + } +} + +package struct LLExports: ~Copyable { +} + +package struct LLFunction { + package func invoke(_ args: [Value]) -> [Value] { + fatalError() + } +} +package struct LLGlobal { + package var value: Value { fatalError() } +} +package struct LLMemory {} +package struct LLTable {} + +package enum LLExternalValue { + case function(LLFunction) + case global(LLGlobal) + case memory(LLMemory) + case table(LLTable) +} diff --git a/Sources/LLVMBackend/LLStore.swift b/Sources/LLVMBackend/LLStore.swift new file mode 100644 index 00000000..a0afc108 --- /dev/null +++ b/Sources/LLVMBackend/LLStore.swift @@ -0,0 +1,11 @@ +import WasmKit + +package struct LLStore: ~Copyable { + package init() {} +} + +extension Module { + package func instantiate(llStore: borrowing LLStore, imports: Imports = Imports()) throws -> LLInstance { + LLInstance() + } +} diff --git a/Sources/LLVMBackend/Linker.swift b/Sources/LLVMBackend/Linker.swift new file mode 100644 index 00000000..ada9c719 --- /dev/null +++ b/Sources/LLVMBackend/Linker.swift @@ -0,0 +1,32 @@ +import Subprocess +import SystemPackage + +package enum Linker { + enum Error: Swift.Error { + case unexpectedTerminationStatus(TerminationStatus) + } + + package static func link(objectFilePath: FilePath) async throws -> FilePath { + #if os(macOS) + var dylibPath = objectFilePath + dylibPath.extension = "dylib" + let result = try await run( + .name("ld"), + arguments: [ + "-dylib", objectFilePath.string, + "-lSystem", "-L", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib", + "-o", dylibPath.string, + ], + output: .standardError + ) + + guard result.terminationStatus.isSuccess else { + throw Error.unexpectedTerminationStatus(result.terminationStatus) + } + + return dylibPath + #else + #error("Linking native binaries is currently only supported on macOS") + #endif + } +} diff --git a/Sources/LLVMBackend/Loader.swift b/Sources/LLVMBackend/Loader.swift new file mode 100644 index 00000000..eb284ecf --- /dev/null +++ b/Sources/LLVMBackend/Loader.swift @@ -0,0 +1,53 @@ +import Darwin +import SystemPackage + +package protocol ImportedFunctionArguments { + associatedtype ResultType + + func apply(symbol: UnsafeMutableRawPointer) -> ResultType +} + +package struct U32Args2Result1: ImportedFunctionArguments { + typealias CType = @convention(c) (UInt32, UInt32) -> UInt32 + + private let args: (UInt32, UInt32) + + package init(_ first: UInt32, _ second: UInt32) { + self.args = (first, second) + } + + package func apply(symbol: UnsafeMutableRawPointer) -> UInt32 { + unsafeBitCast(symbol, to: CType.self)(self.args.0, self.args.1) + } +} + +package struct Loader: ~Copyable { + enum Error: Swift.Error { + case symbolNotFound(String) + } + + package enum ClosureType { + case u32Args2Result1(UInt32, UInt32) + } + + let memory: Wasm32Memory? + + package init(memory: consuming Wasm32Memory?) { + self.memory = memory + } + + package func load( + library: FilePath, + entrypointSymbol: String, + arguments: T + ) throws -> T.ResultType { + let handle = dlopen(library.string, RTLD_LAZY) + defer { dlclose(handle) } + + guard let symbol = dlsym(handle, entrypointSymbol) else { + throw Error.symbolNotFound(entrypointSymbol) + } + + return arguments.apply(symbol: symbol) + } +} diff --git a/Sources/LLVMBackend/Wasm32Memory.swift b/Sources/LLVMBackend/Wasm32Memory.swift new file mode 100644 index 00000000..51e5683d --- /dev/null +++ b/Sources/LLVMBackend/Wasm32Memory.swift @@ -0,0 +1,12 @@ +import Darwin + +package struct Wasm32Memory: ~Copyable { + // let memory: UnsafeMutableRawPointer + + init() { + // 1. fd = open(tmpfile) + // 2. unlink(tmpfile) + // 3. memory = mmap(nullptr, 8GB (4GB base + 4GB offset), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0) + // 4. fruncate(fd) to initialize or handle `memory.grow` + } +} diff --git a/Sources/LLVMBackendCLI/CMakeLists.txt b/Sources/LLVMBackendCLI/CMakeLists.txt new file mode 100644 index 00000000..d78069c1 --- /dev/null +++ b/Sources/LLVMBackendCLI/CMakeLists.txt @@ -0,0 +1,32 @@ +add_executable( + LLVMBackendCLI + + Entrypoint.swift +) +target_compile_options( + LLVMBackendCLI + PRIVATE + -parse-as-library + -package-name WasmKitPackage +) +set(BUILD_TESTING OFF) + +find_package(ArgumentParser CONFIG) +if(NOT ArgumentParser_FOUND) + message("-- Vending ArgumentParser") + FetchContent_Declare( + ArgumentParser + GIT_REPOSITORY https://github.com/apple/swift-argument-parser + GIT_TAG 1.6.2 + ) + FetchContent_MakeAvailable(ArgumentParser) +endif() + +add_dependencies(LLVMBackendCLI ArgumentParser LLVMBackend) + +target_link_libraries( + LLVMBackendCLI + + ArgumentParser + LLVMBackend +) diff --git a/Sources/LLVMBackendCLI/Entrypoint.swift b/Sources/LLVMBackendCLI/Entrypoint.swift new file mode 100644 index 00000000..182495ee --- /dev/null +++ b/Sources/LLVMBackendCLI/Entrypoint.swift @@ -0,0 +1,37 @@ +import ArgumentParser +import Foundation +import LLVMBackend +import SystemPackage + +@main +struct Entrypoint: AsyncParsableCommand { + @Argument(help: "Path to a `.wasm` file to operate on.") + var path: String + + @Flag(name: [.long, .short]) + var verbose: Bool = false + + func run() async throws { + let wasmPath = + if FilePath(self.path).isAbsolute { + FilePath(self.path) + } else { + FilePath(FileManager.default.currentDirectoryPath).appending(path) + } + + print("wasmPath is \(wasmPath)") + var context = CodegenContext(isVerbose: verbose) + let objectFilePath = try context.emitObjectFile(wasmPath: wasmPath) + let libraryFilePath = try await Linker.link(objectFilePath: objectFilePath) + + print("Linked library is at \(libraryFilePath.string)") + + let result = try Loader(memory: nil).load( + library: libraryFilePath, + entrypointSymbol: "1", + arguments: U32Args2Result1(42, 24) + ) + + print("invocation result: \(result)") + } +} diff --git a/Sources/LLVMInterop/CMakeLists.txt b/Sources/LLVMInterop/CMakeLists.txt new file mode 100644 index 00000000..b92c77c8 --- /dev/null +++ b/Sources/LLVMInterop/CMakeLists.txt @@ -0,0 +1,43 @@ + + +find_package(LLVM CONFIG REQUIRED) +message(STATUS "Found LLVM headers: ${LLVM_MAIN_INCLUDE_DIR}") +message(STATUS "Found LLVM generated headers: ${LLVM_INCLUDE_DIR}") + +add_library( + LLVMInterop + + IRContext.cpp + IR/IRFunction.cpp + IR/IRPHINode.cpp +) + +target_compile_features(LLVMInterop PRIVATE cxx_std_17) + +set(LLVMINTEROP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") + +target_include_directories( + LLVMInterop + PUBLIC + "${LLVMINTEROP_INCLUDE_DIR}" + "${LLVM_MAIN_INCLUDE_DIR}" + "${LLVM_INCLUDE_DIR}" +) + +llvm_map_components_to_libnames(llvm_libs + support + core irreader mc passes targetparser target + aarch64codegen aarch64asmparser +) + +target_link_libraries(LLVMInterop ${llvm_libs}) + +install( + TARGETS LLVMInterop + # shared libraries + LIBRARY DESTINATION lib + # for static libraries + ARCHIVE DESTINATION lib + # public headers + INCLUDES DESTINATION include +) diff --git a/Sources/LLVMInterop/IR/IRFunction.cpp b/Sources/LLVMInterop/IR/IRFunction.cpp new file mode 100644 index 00000000..6b159978 --- /dev/null +++ b/Sources/LLVMInterop/IR/IRFunction.cpp @@ -0,0 +1,24 @@ +#include "IRFunction.h" + +optional IRFunction::print() const { + string string = ""; + raw_string_ostream stream(string); + + if (this->_isValid) { + this->_f->print(stream); + return string; + } else { + return nullopt; + } +} + +optional IRFunction::verify() const { + string string = ""; + raw_string_ostream stream(string); + + if (verifyFunction(*(this->_f), &stream)) { + return string; + } else { + return nullopt; + } +} diff --git a/Sources/LLVMInterop/IR/IRPHINode.cpp b/Sources/LLVMInterop/IR/IRPHINode.cpp new file mode 100644 index 00000000..1ab32381 --- /dev/null +++ b/Sources/LLVMInterop/IR/IRPHINode.cpp @@ -0,0 +1,7 @@ +#include "IRPHINode.h" +#include "IRBlock.h" +#include "IRValue.h" + +void IRPHINode::addIncoming(IRValue v, IRBlock b) { + this->_n->addIncoming(v._v, b._b); +} diff --git a/Sources/LLVMInterop/IRContext.cpp b/Sources/LLVMInterop/IRContext.cpp new file mode 100644 index 00000000..b34d1ac6 --- /dev/null +++ b/Sources/LLVMInterop/IRContext.cpp @@ -0,0 +1,249 @@ +#include "IRContext.h" + +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +IRContext::IRContext() + : _context(make_shared()), + _module(make_shared("codegen", *_context)), + _builder(make_shared>(*_context)), + _fpm(make_shared()), + _lam(make_shared()), + _fam(make_shared()), + _cgam(make_shared()), + _mam(make_shared()), + _pic(make_shared()), + _si(make_shared(*_context, true)) { + _si->registerCallbacks(*_pic, _mam.get()); + + _fpm->addPass(PromotePass()); + _fpm->addPass(InstCombinePass()); + _fpm->addPass(ReassociatePass()); + _fpm->addPass(GVNPass()); + _fpm->addPass(SimplifyCFGPass()); + + // Register analysis passes used in these transform passes. + PassBuilder pb; + pb.registerModuleAnalyses(*_mam); + pb.registerFunctionAnalyses(*_fam); + pb.crossRegisterProxies(*_lam, *_fam, *_cgam, *_mam); + +#if __aarch64__ + LLVMInitializeAArch64TargetInfo(); + LLVMInitializeAArch64Target(); + LLVMInitializeAArch64TargetMC(); + LLVMInitializeAArch64AsmParser(); + LLVMInitializeAArch64AsmPrinter(); +#elif __x86_64__ + LLVMInitializeX86TargetInfo(); + LLVMInitializeX86Target(); + LLVMInitializeX86TargetMC(); + LLVMInitializeX86AsmParser(); + LLVMInitializeX86AsmPrinter(); +#endif +} + +bool IRContext::emitObjectFile(StringRef path) const { + auto targetTriple = sys::getDefaultTargetTriple(); + Triple triple(targetTriple); + _module->setTargetTriple(triple); + + std::string error; + auto target = TargetRegistry::lookupTarget(targetTriple, error); + + // Print an error and exit if we couldn't find the requested target. + // This generally occurs if we've forgotten to initialise the + // TargetRegistry or we have a bogus target triple. + if (!target) { + errs() << error; + return false; + } + + auto cpu = "generic"; + auto features = ""; + + TargetOptions opt; + auto targetMachine = target->createTargetMachine(triple, cpu, features, + opt, Reloc::PIC_); + + _module->setDataLayout(targetMachine->createDataLayout()); + + std::error_code ec; + raw_fd_ostream dest(path, ec, sys::fs::OpenFlags::OF_None); + + if (ec) { + errs() << "Could not open file: " << ec.message(); + return false; + } + + auto fileType = CodeGenFileType::ObjectFile; + + legacy::PassManager pass; + targetMachine->addPassesToEmitFile(pass, dest, nullptr, fileType); + pass.run(*_module); + dest.flush(); + + outs() << "Wrote " << path << "\n"; + + return true; +} + +std::string IRContext::printModule() const { + std::string string = ""; + raw_string_ostream stream(string); + + this->_module->print(stream, nullptr); + return string; +} + +IRValue IRContext::createImportedFunction(StringRef name, IRPointerType type) { + GlobalVariable *result = + new GlobalVariable(*this->_module, type._pt, false, + llvm::GlobalValue::ExternalLinkage, nullptr, name); + + return result; +} + +std::optional IRContext::getFunction(StringRef name) const { + Function *f = _module->getFunction(name); + if (f) { + return IRFunction(f); + } else { + return std::nullopt; + } +} + +IRValue IRContext::createLocal(IRType type) const { + return _builder->CreateAlloca(type._t); +} + +IRValue IRContext::getLocal(IRType type, IRValue address) const { + return _builder->CreateLoad(type._t, address._v); +} + +void IRContext::setLocal(IRValue address, IRValue value) const { + _builder->CreateStore(value._v, address._v); +} + +void IRContext::br(IRBlock successor) const { + _builder->CreateBr(successor._b); +} + +IRValue IRContext::condBr(IRValue condition, IRBlock trueBlock) const { + + return _builder->CreateCondBr(condition._v, trueBlock._b, nullptr); +} + +IRValue IRContext::condBr(IRValue condition, IRBlock trueBlock, + IRBlock falseBlock) const { + + return _builder->CreateCondBr(condition._v, trueBlock._b, falseBlock._b); +} + +IRValue IRContext::unreachable() const { + return _builder->CreateIntrinsic(Intrinsic::trap, {}); +} + +IRValue IRContext::bEq(IRValue lhs, IRValue rhs) const { + return _builder->CreateICmpEQ(lhs._v, rhs._v); +} + +IRValue IRContext::iAdd(IRValue lhs, IRValue rhs) const { + return _builder->CreateAdd(lhs._v, rhs._v); +} + +IRValue IRContext::fAdd(IRValue lhs, IRValue rhs) const { + return _builder->CreateFAdd(lhs._v, rhs._v); +} + +IRValue IRContext::iSub(IRValue lhs, IRValue rhs) const { + return _builder->CreateSub(lhs._v, rhs._v); +} + +IRValue IRContext::fSub(IRValue lhs, IRValue rhs) const { + return _builder->CreateFSub(lhs._v, rhs._v); +} + +IRValue IRContext::iMul(IRValue lhs, IRValue rhs) const { + return _builder->CreateMul(lhs._v, rhs._v); +} + +IRValue IRContext::fMul(IRValue lhs, IRValue rhs) const { + return _builder->CreateFMul(lhs._v, rhs._v); +} + +IRValue IRContext::iEq(IRValue lhs, IRValue rhs) const { + auto i32 = Type::getInt32Ty(*_context); + auto eqResult = _builder->CreateICmpEQ(lhs._v, rhs._v); + return _builder->CreateZExt(eqResult, i32); +} + +IRValue IRContext::fEq(IRValue lhs, IRValue rhs) const { + auto i32 = Type::getInt32Ty(*_context); + auto eqResult = _builder->CreateFCmpUEQ(lhs._v, rhs._v); + return _builder->CreateZExt(eqResult, i32); +} + +IRValue IRContext::iNe(IRValue lhs, IRValue rhs) const { + auto i32 = Type::getInt32Ty(*_context); + auto eqResult = _builder->CreateICmpEQ(lhs._v, rhs._v); + auto neResult = _builder->CreateNot(eqResult); + return _builder->CreateZExt(neResult, i32); +} + +IRValue IRContext::fNe(IRValue lhs, IRValue rhs) const { + auto i32 = Type::getInt32Ty(*_context); + auto eqResult = _builder->CreateFCmpUEQ(lhs._v, rhs._v); + auto neResult = _builder->CreateNot(eqResult); + return _builder->CreateZExt(neResult, i32); +} + +IRValue IRContext::wrap(IRValue value) const { + auto i32 = Type::getInt32Ty(*_context); + return _builder->CreateTrunc(value._v, i32); +} + +IRValue IRContext::extendUnsigned(IRValue value) const { + auto i64 = Type::getInt64Ty(*_context); + return _builder->CreateZExt(value._v, i64); +} + +IRValue IRContext::extendSigned(IRValue value) const { + auto i64 = Type::getInt64Ty(*_context); + return _builder->CreateSExt(value._v, i64); +} + +IRFunctionType IRContext::functionType(IRTypeVector parameters, + IRType result) const { + return FunctionType::get(result._t, parameters, false); +} + +IRPointerType IRContext::pointerType() const { + return PointerType::getUnqual(*_context); +} + +IRValue IRContext::call(IRFunction callee, IRValueVector args) { + return _builder->CreateCall(callee._f, args); +} + +IRPHINode IRContext::phi(IRType type, unsigned int incomingCount) const { + return _builder->CreatePHI(type._t, incomingCount); +} + +std::string IRFunctionType::print() const { + std::string string = ""; + raw_string_ostream stream(string); + + this->_ft->print(stream); + return string; +} diff --git a/Sources/LLVMInterop/include/IRBlock.h b/Sources/LLVMInterop/include/IRBlock.h new file mode 100644 index 00000000..ce498516 --- /dev/null +++ b/Sources/LLVMInterop/include/IRBlock.h @@ -0,0 +1,19 @@ +#ifndef IRBlock_h +#define IRBlock_h + +#include +#include + +using namespace llvm; + +class IRBlock { +public: + BasicBlock *_b; + + IRBlock(BasicBlock *b) : _b(b) {} + + bool isEmpty() { return _b->empty(); } + void eraseFromParent() { _b->eraseFromParent(); } +}; + +#endif /* IRBlock_h */ diff --git a/Sources/LLVMInterop/include/IRContext.h b/Sources/LLVMInterop/include/IRContext.h new file mode 100644 index 00000000..b0a3d37d --- /dev/null +++ b/Sources/LLVMInterop/include/IRContext.h @@ -0,0 +1,136 @@ +#ifndef IRContext_h +#define IRContext_h + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "IRBlock.h" +#include "IRFunctionType.h" +#include "IRPointerType.h" +#include "IRFunction.h" +#include "IRPHINode.h" +#include "IRType.h" +#include "IRValue.h" + +using namespace llvm; +using namespace std; + +class IRContext { + shared_ptr _context; + shared_ptr _module; + shared_ptr> _builder; + + shared_ptr _fpm; + shared_ptr _lam; + shared_ptr _fam; + shared_ptr _cgam; + shared_ptr _mam; + shared_ptr _pic; + shared_ptr _si; + +public: + IRContext(); + + bool emitObjectFile(StringRef path) const; + + void optimize(IRFunction f) { _fpm->run(*f._f, *_fam); } + + string printModule() const; + + optional getFunction(StringRef name) const; + + IRValue createImportedFunction(StringRef name, IRPointerType type); + + IRValue f32Value(float f32) const { + return ConstantFP::get(*_context, APFloat(f32)); + } + + IRValue f64Value(double f64) const { + return ConstantFP::get(*_context, APFloat(f64)); + } + + IRValue i64Value(uint64_t i64) const { + return ConstantInt::get(*_context, APInt(64, i64)); + } + + IRValue i32Value(uint32_t i32) const { + return ConstantInt::get(*_context, APInt(32, i32)); + } + + IRValue createLocal(IRType type) const; + IRValue getLocal(IRType type, IRValue local) const; + void setLocal(IRValue local, IRValue value) const; + + IRValue call(IRFunction callee, IRValueVector args); + + void br(IRBlock successor) const; + IRValue condBr(IRValue condition, IRBlock trueBlock) const; + IRValue condBr(IRValue condition, IRBlock trueBlock, + IRBlock falseBlock) const; + IRPHINode phi(IRType type, unsigned int incomingCount) const; + + IRValue unreachable() const; + + IRValue bEq(IRValue lhs, IRValue rhs) const; + + IRValue iAdd(IRValue lhs, IRValue rhs) const; + IRValue fAdd(IRValue lhs, IRValue rhs) const; + IRValue iSub(IRValue lhs, IRValue rhs) const; + IRValue fSub(IRValue lhs, IRValue rhs) const; + IRValue iMul(IRValue lhs, IRValue rhs) const; + IRValue fMul(IRValue lhs, IRValue rhs) const; + IRValue iEq(IRValue lhs, IRValue rhs) const; + IRValue fEq(IRValue lhs, IRValue rhs) const; + IRValue iNe(IRValue lhs, IRValue rhs) const; + IRValue fNe(IRValue lhs, IRValue rhs) const; + + IRValue wrap(IRValue value) const; + IRValue extendUnsigned(IRValue value) const; + IRValue extendSigned(IRValue value) const; + + IRFunctionType functionType(IRTypeVector parameters, IRType result) const; + IRPointerType pointerType() const; + + IRType i32Type() const { return Type::getInt32Ty(*_context); } + IRType i64Type() const { return Type::getInt64Ty(*_context); } + IRType f32Type() const { return Type::getFloatTy(*_context); } + IRType f64Type() const { return Type::getDoubleTy(*_context); } + + IRType voidType() const { return Type::getVoidTy(*_context); } + + IRType structType(IRTypeVector types) const { + return StructType::create(types); + } + + IRBlock block(IRFunction function, StringRef name) const { + return BasicBlock::Create(*_context, name, function._f); + } + + void setInsertPoint(IRBlock block) { _builder->SetInsertPoint(block._b); } + + void createRet(IRValue value) { _builder->CreateRet(value._v); } + + IRFunction function(IRFunctionType type, StringRef name) const { + return Function::Create(type._ft, Function::ExternalLinkage, name, + _module.get()); + } +}; + +#endif /* IRContext_h */ diff --git a/Sources/LLVMInterop/include/IRFunction.h b/Sources/LLVMInterop/include/IRFunction.h new file mode 100644 index 00000000..0176d8c8 --- /dev/null +++ b/Sources/LLVMInterop/include/IRFunction.h @@ -0,0 +1,28 @@ +#ifndef IRFunction_h +#define IRFunction_h + + +#include +#include + +#include "IRValue.h" + +using namespace llvm; +using namespace std; + +class IRFunction { +public: + Function *_f; + + bool _isValid; + + IRFunction() : _f(nullptr), _isValid(false) {} + IRFunction(Function *f) : _f(f), _isValid(true) {} + + IRValue getArgument(uint32_t i) const { return _f->getArg(i); } + + optional print() const; + optional verify() const; +}; + +#endif /* IRFunction_h */ diff --git a/Sources/LLVMInterop/include/IRFunctionType.h b/Sources/LLVMInterop/include/IRFunctionType.h new file mode 100644 index 00000000..167204c0 --- /dev/null +++ b/Sources/LLVMInterop/include/IRFunctionType.h @@ -0,0 +1,14 @@ +#include + +using namespace llvm; +using namespace std; + + +class IRFunctionType { +public: + FunctionType *_ft; + + IRFunctionType(FunctionType *ft) : _ft(ft) {} + + string print() const; +}; diff --git a/Sources/LLVMInterop/include/IRPHINode.h b/Sources/LLVMInterop/include/IRPHINode.h new file mode 100644 index 00000000..16cd34b7 --- /dev/null +++ b/Sources/LLVMInterop/include/IRPHINode.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +class IRValue; +class IRBlock; + +using namespace llvm; + +class IRPHINode { +public: + PHINode *_n; + + IRPHINode(PHINode *n) : _n(n) {} + + void addIncoming(IRValue v, IRBlock b); +}; diff --git a/Sources/LLVMInterop/include/IRPointerType.h b/Sources/LLVMInterop/include/IRPointerType.h new file mode 100644 index 00000000..dabc338d --- /dev/null +++ b/Sources/LLVMInterop/include/IRPointerType.h @@ -0,0 +1,11 @@ +#include + +using namespace llvm; +using namespace std; + +class IRPointerType { +public: + PointerType *_pt; + + IRPointerType(PointerType *pt): _pt(pt) {} +}; diff --git a/Sources/LLVMInterop/include/IRType.h b/Sources/LLVMInterop/include/IRType.h new file mode 100644 index 00000000..90a6e259 --- /dev/null +++ b/Sources/LLVMInterop/include/IRType.h @@ -0,0 +1,16 @@ +#ifndef IRType_h +#define IRType_h + +#include + +using namespace llvm; + +class IRType { +public: + Type *_t; + IRType(Type *t) : _t(t) {} +}; + +using IRTypeVector = std::vector; + +#endif /* IRType_h */ diff --git a/Sources/LLVMInterop/include/IRValue.h b/Sources/LLVMInterop/include/IRValue.h new file mode 100644 index 00000000..84039024 --- /dev/null +++ b/Sources/LLVMInterop/include/IRValue.h @@ -0,0 +1,16 @@ +#pragma once + +#include "IRPHINode.h" +#include + +using namespace llvm; + +using IRValueVector = std::vector; + +class IRValue { +public: + Value *_v; + + IRValue(Value *v) : _v(v) {} + IRValue(IRPHINode phi) : _v(phi._n) {} +}; diff --git a/Sources/LLVMInterop/include/module.modulemap b/Sources/LLVMInterop/include/module.modulemap new file mode 100644 index 00000000..4ed80f8c --- /dev/null +++ b/Sources/LLVMInterop/include/module.modulemap @@ -0,0 +1,4 @@ +module LLVMInterop { + header "IRContext.h" + requires cplusplus +} From bdb4dceb2842420bd47e88b4792c60884dc4598a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 14:41:49 +0000 Subject: [PATCH 02/51] Bump CMake to 3.30.2 in CMake GHA workflow --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5970a6d4..5e96334f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -302,7 +302,7 @@ jobs: - name: Install CMake run: | apt-get install -y curl - curl -L https://github.com/Kitware/CMake/releases/download/v3.29.2/cmake-3.29.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ + curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ - run: cmake -G Ninja -B ./build - run: cmake --build ./build - run: ./build/bin/wasmkit-cli --version From e653a99763f6c943db6b1dd4610dd8088b0b4b05 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 14:53:44 +0000 Subject: [PATCH 03/51] Add LLVM build step scaffolding --- .github/workflows/main.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5e96334f..5640456b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -305,7 +305,25 @@ jobs: curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ - run: cmake -G Ninja -B ./build - run: cmake --build ./build - - run: ./build/bin/wasmkit-cli --version + - run: ./build/bin/wasmkit --version + + build-llvm: + runs-on: ubuntu-24.04 + container: + image: swift:6.2-noble + steps: + - uses: actions/checkout@v4 + - name: Install Ninja + run: apt-get update && apt-get install -y ninja-build + - name: Install CMake + run: | + apt-get install -y curl + curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ + - name: Build LLVM + run: | + curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz -C $GITHUB_WORKSPACE/llvm-project + - run: | + ls $GITHUB_WORKSPACE/llvm-project build-wasi: runs-on: ubuntu-24.04 From c8ea1653908bbbeb49ff3f25ff3a1ece30fe21bb Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 14:56:03 +0000 Subject: [PATCH 04/51] Update `.github/workflows/main.yml` --- .github/workflows/main.yml | 583 +++++++++++++++++++------------------ 1 file changed, 292 insertions(+), 291 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5640456b..7656cd93 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,302 +10,302 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: - check-autogen-diff: - runs-on: ubuntu-latest - container: - image: swift:6.2-noble - steps: - - uses: actions/checkout@v4 - - name: Re-generate auto-generated code checks - run: | - swift run -q --package-path Utilities WasmKitDevUtils - - name: Check for changes - run: | - git config --global --add safe.directory "$GITHUB_WORKSPACE" - git diff --exit-code || { - echo "::error::The auto-generated code utilities changed some files. Please see \`Utilities/README.md\`, re-run the tools, and commit the changes." - exit 1 - } - build-macos: - strategy: - matrix: - include: - # Swift 6.0 - - os: macos-14 - xcode: Xcode_16.2 - development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - test-args: "" - # Swift 6.1 - - os: macos-15 - xcode: Xcode_16.4 - development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - test-args: "--sanitize address --traits WasmDebuggingSupport" - # Swift 6.2 - - os: macos-15 - xcode: Xcode_26.1 - development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - test-args: "--sanitize address --traits WasmDebuggingSupport" - # Swift 6.2.3 - - os: macos-26 - xcode: Xcode_26.2 - development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - test-args: "--sanitize address --traits WasmDebuggingSupport" + # check-autogen-diff: + # runs-on: ubuntu-latest + # container: + # image: swift:6.2-noble + # steps: + # - uses: actions/checkout@v4 + # - name: Re-generate auto-generated code checks + # run: | + # swift run -q --package-path Utilities WasmKitDevUtils + # - name: Check for changes + # run: | + # git config --global --add safe.directory "$GITHUB_WORKSPACE" + # git diff --exit-code || { + # echo "::error::The auto-generated code utilities changed some files. Please see \`Utilities/README.md\`, re-run the tools, and commit the changes." + # exit 1 + # } + # build-macos: + # strategy: + # matrix: + # include: + # # Swift 6.0 + # - os: macos-14 + # xcode: Xcode_16.2 + # development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # test-args: "" + # # Swift 6.1 + # - os: macos-15 + # xcode: Xcode_16.4 + # development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # test-args: "--sanitize address --traits WasmDebuggingSupport" + # # Swift 6.2 + # - os: macos-15 + # xcode: Xcode_26.1 + # development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # test-args: "--sanitize address --traits WasmDebuggingSupport" + # # Swift 6.2.3 + # - os: macos-26 + # xcode: Xcode_26.2 + # development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # test-args: "--sanitize address --traits WasmDebuggingSupport" - runs-on: ${{ matrix.os }} - name: "build-macos (${{ matrix.xcode }})" - steps: - - uses: actions/checkout@v4 - - id: setup-development - run: | - toolchain_path="/Library/Developer/Toolchains/${{ matrix.development-toolchain-tag }}.xctoolchain" - pkg="$(mktemp -d)/InstallMe.pkg" - development_toolchain_download="https://download.swift.org/development/xcode/${{ matrix.development-toolchain-tag }}/${{ matrix.development-toolchain-tag }}-osx.pkg" - curl -L "$development_toolchain_download" -o $pkg - sudo installer -pkg $pkg -target / - echo "toolchain-path=$toolchain_path" >> $GITHUB_OUTPUT - "$toolchain_path/usr/bin/swift" sdk install "${{ matrix.wasi-swift-sdk-download }}" --checksum "${{ matrix.wasi-swift-sdk-checksum }}" - wasi_sdk_path=$("$toolchain_path/usr/bin/swift" sdk configure --show-configuration "${{ matrix.wasi-swift-sdk-id }}" wasm32-unknown-wasi | grep sdkRootPath: | cut -d: -f2) - echo "wasi-swift-sdk-path=$(dirname $wasi_sdk_path)" >> $GITHUB_OUTPUT + # runs-on: ${{ matrix.os }} + # name: "build-macos (${{ matrix.xcode }})" + # steps: + # - uses: actions/checkout@v4 + # - id: setup-development + # run: | + # toolchain_path="/Library/Developer/Toolchains/${{ matrix.development-toolchain-tag }}.xctoolchain" + # pkg="$(mktemp -d)/InstallMe.pkg" + # development_toolchain_download="https://download.swift.org/development/xcode/${{ matrix.development-toolchain-tag }}/${{ matrix.development-toolchain-tag }}-osx.pkg" + # curl -L "$development_toolchain_download" -o $pkg + # sudo installer -pkg $pkg -target / + # echo "toolchain-path=$toolchain_path" >> $GITHUB_OUTPUT + # "$toolchain_path/usr/bin/swift" sdk install "${{ matrix.wasi-swift-sdk-download }}" --checksum "${{ matrix.wasi-swift-sdk-checksum }}" + # wasi_sdk_path=$("$toolchain_path/usr/bin/swift" sdk configure --show-configuration "${{ matrix.wasi-swift-sdk-id }}" wasm32-unknown-wasi | grep sdkRootPath: | cut -d: -f2) + # echo "wasi-swift-sdk-path=$(dirname $wasi_sdk_path)" >> $GITHUB_OUTPUT - - name: Select Xcode version - run: sudo xcode-select -switch /Applications/${{ matrix.xcode }}.app - - name: Configure Tests/default.json - run: | - cat < Tests/default.json - { - "swiftExecutablePath": "${{ steps.setup-development.outputs.toolchain-path }}/usr/bin/swift", - "wasiSwiftSDKPath": "${{ steps.setup-development.outputs.wasi-swift-sdk-path }}", - "hostSwiftExecutablePath": "$(xcrun --find swift)", - "hostSdkRootPath": "$(xcrun --show-sdk-path --sdk macosx)" - } - EOS - - run: ./Vendor/checkout-dependency - - run: swift test ${{ matrix.test-args }} + # - name: Select Xcode version + # run: sudo xcode-select -switch /Applications/${{ matrix.xcode }}.app + # - name: Configure Tests/default.json + # run: | + # cat < Tests/default.json + # { + # "swiftExecutablePath": "${{ steps.setup-development.outputs.toolchain-path }}/usr/bin/swift", + # "wasiSwiftSDKPath": "${{ steps.setup-development.outputs.wasi-swift-sdk-path }}", + # "hostSwiftExecutablePath": "$(xcrun --find swift)", + # "hostSdkRootPath": "$(xcrun --show-sdk-path --sdk macosx)" + # } + # EOS + # - run: ./Vendor/checkout-dependency + # - run: swift test ${{ matrix.test-args }} - build-xcode: - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Prepare Xcode platforms - run: | - set -euxo pipefail - sudo xcode-select -s /Applications/Xcode_26.0.app - sudo xcodebuild -runFirstLaunch || true - for PLAT in iOS tvOS watchOS visionOS; do - if ! xcodebuild -showsdks | grep -q "$PLAT"; then - echo "Downloading $PLAT platform..." - sudo xcodebuild -downloadPlatform "$PLAT" - fi - done - xcodebuild -showsdks - xcodebuild -scheme WasmKit-Package -showdestinations || true - - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=macOS - - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=iOS - - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=watchOS - - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=tvOS - - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=visionOS + # build-xcode: + # runs-on: macos-15 + # steps: + # - uses: actions/checkout@v4 + # - name: Prepare Xcode platforms + # run: | + # set -euxo pipefail + # sudo xcode-select -s /Applications/Xcode_26.0.app + # sudo xcodebuild -runFirstLaunch || true + # for PLAT in iOS tvOS watchOS visionOS; do + # if ! xcodebuild -showsdks | grep -q "$PLAT"; then + # echo "Downloading $PLAT platform..." + # sudo xcodebuild -downloadPlatform "$PLAT" + # fi + # done + # xcodebuild -showsdks + # xcodebuild -scheme WasmKit-Package -showdestinations || true + # - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=macOS + # - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=iOS + # - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=watchOS + # - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=tvOS + # - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=visionOS - build-linux: - strategy: - matrix: - include: - - swift: "swift:6.0-jammy" - development-toolchain-download: "https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu22.04.tar.gz" - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - - swift: "swift:6.1-noble" - development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - test-args: "--traits WasmDebuggingSupport" - - swift: "swift:6.2-amazonlinux2" - development-toolchain-download: "https://download.swift.org/development/amazonlinux2/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-amazonlinux2.tar.gz" - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - test-args: "--traits WasmDebuggingSupport" - - swift: "swift:6.2-noble" - development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - test-args: "--traits WasmDebuggingSupport --enable-code-coverage" - build-dev-dashboard: true - - swift: "swiftlang/swift:nightly-6.3-noble" - development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY" - - swift: "swiftlang/swift:nightly-main-noble" - development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY" - - swift: "swiftlang/swift:nightly-main-noble" - development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" - wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY --build-system swiftbuild" - label: " --build-system swiftbuild" + # build-linux: + # strategy: + # matrix: + # include: + # - swift: "swift:6.0-jammy" + # development-toolchain-download: "https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu22.04.tar.gz" + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # - swift: "swift:6.1-noble" + # development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # test-args: "--traits WasmDebuggingSupport" + # - swift: "swift:6.2-amazonlinux2" + # development-toolchain-download: "https://download.swift.org/development/amazonlinux2/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-amazonlinux2.tar.gz" + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # test-args: "--traits WasmDebuggingSupport" + # - swift: "swift:6.2-noble" + # development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # test-args: "--traits WasmDebuggingSupport --enable-code-coverage" + # build-dev-dashboard: true + # - swift: "swiftlang/swift:nightly-6.3-noble" + # development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY" + # - swift: "swiftlang/swift:nightly-main-noble" + # development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY" + # - swift: "swiftlang/swift:nightly-main-noble" + # development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" + # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + # test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY --build-system swiftbuild" + # label: " --build-system swiftbuild" - runs-on: ubuntu-24.04 - name: "build-linux (${{ matrix.swift }}${{ matrix.label }})" + # runs-on: ubuntu-24.04 + # name: "build-linux (${{ matrix.swift }}${{ matrix.label }})" - steps: - - uses: actions/checkout@v4 - - name: Configure container - run: | - docker run -dit --name build-container -v $PWD:/workspace -w /workspace ${{ matrix.swift }} - echo 'docker exec -i build-container "$@"' > ./build-exec - chmod +x ./build-exec + # steps: + # - uses: actions/checkout@v4 + # - name: Configure container + # run: | + # docker run -dit --name build-container -v $PWD:/workspace -w /workspace ${{ matrix.swift }} + # echo 'docker exec -i build-container "$@"' > ./build-exec + # chmod +x ./build-exec - - name: Install Development toolchain - id: setup-development - run: | - toolchain_path="/opt/swiftwasm" - ./build-exec mkdir -p "$toolchain_path" - curl -L ${{ matrix.development-toolchain-download }} | ./build-exec tar xz --strip-component 1 -C "$toolchain_path" - echo "toolchain-path=$toolchain_path" >> $GITHUB_OUTPUT - ./build-exec "$toolchain_path/usr/bin/swift" sdk install "${{ matrix.wasi-swift-sdk-download }}" --checksum "${{ matrix.wasi-swift-sdk-checksum }}" - wasi_sdk_path=$(./build-exec "$toolchain_path/usr/bin/swift" sdk configure --show-configuration "${{ matrix.wasi-swift-sdk-id }}" wasm32-unknown-wasi | grep sdkRootPath: | cut -d: -f2) - echo "wasi-swift-sdk-path=$(dirname $wasi_sdk_path)" >> $GITHUB_OUTPUT + # - name: Install Development toolchain + # id: setup-development + # run: | + # toolchain_path="/opt/swiftwasm" + # ./build-exec mkdir -p "$toolchain_path" + # curl -L ${{ matrix.development-toolchain-download }} | ./build-exec tar xz --strip-component 1 -C "$toolchain_path" + # echo "toolchain-path=$toolchain_path" >> $GITHUB_OUTPUT + # ./build-exec "$toolchain_path/usr/bin/swift" sdk install "${{ matrix.wasi-swift-sdk-download }}" --checksum "${{ matrix.wasi-swift-sdk-checksum }}" + # wasi_sdk_path=$(./build-exec "$toolchain_path/usr/bin/swift" sdk configure --show-configuration "${{ matrix.wasi-swift-sdk-id }}" wasm32-unknown-wasi | grep sdkRootPath: | cut -d: -f2) + # echo "wasi-swift-sdk-path=$(dirname $wasi_sdk_path)" >> $GITHUB_OUTPUT - - name: Configure Tests/default.json - run: | - cat < Tests/default.json - { - "swiftExecutablePath": "${{ steps.setup-development.outputs.toolchain-path }}/usr/bin/swift", - "wasiSwiftSDKPath": "${{ steps.setup-development.outputs.wasi-swift-sdk-path }}", - "hostSwiftExecutablePath": "/usr/bin/swift" - } - EOS - - run: ./build-exec ./CI/install-wabt.sh - - run: ./Vendor/checkout-dependency - - run: ./build-exec swift test ${{ matrix.test-args }} + # - name: Configure Tests/default.json + # run: | + # cat < Tests/default.json + # { + # "swiftExecutablePath": "${{ steps.setup-development.outputs.toolchain-path }}/usr/bin/swift", + # "wasiSwiftSDKPath": "${{ steps.setup-development.outputs.wasi-swift-sdk-path }}", + # "hostSwiftExecutablePath": "/usr/bin/swift" + # } + # EOS + # - run: ./build-exec ./CI/install-wabt.sh + # - run: ./Vendor/checkout-dependency + # - run: ./build-exec swift test ${{ matrix.test-args }} - - if: matrix.build-dev-dashboard - run: ./build-exec ./CI/build-dev-dashboard.sh - - if: matrix.build-dev-dashboard - name: Relax artifact permissions - run: sudo chown -R $USER .build/html - - if: matrix.build-dev-dashboard - id: deployment - uses: actions/upload-pages-artifact@v4 - with: - path: .build/html + # - if: matrix.build-dev-dashboard + # run: ./build-exec ./CI/build-dev-dashboard.sh + # - if: matrix.build-dev-dashboard + # name: Relax artifact permissions + # run: sudo chown -R $USER .build/html + # - if: matrix.build-dev-dashboard + # id: deployment + # uses: actions/upload-pages-artifact@v4 + # with: + # path: .build/html - deploy-dev-dashboard: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - needs: build-linux - permissions: - id-token: write - pages: write - steps: - - id: deployment - uses: actions/deploy-pages@v4 + # deploy-dev-dashboard: + # environment: + # name: github-pages + # url: ${{ steps.deployment.outputs.page_url }} + # runs-on: ubuntu-latest + # if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + # needs: build-linux + # permissions: + # id-token: write + # pages: write + # steps: + # - id: deployment + # uses: actions/deploy-pages@v4 - build-musl: - runs-on: ubuntu-22.04 - strategy: - matrix: - include: - - swift: 6.2-noble - musl-swift-sdk-download: "https://download.swift.org/swift-6.2.3-release/static-sdk/swift-6.2.3-RELEASE/swift-6.2.3-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz" - musl-swift-sdk-checksum: "f30ec724d824ef43b5546e02ca06a8682dafab4b26a99fbb0e858c347e507a2c" - steps: - - uses: actions/checkout@v4 - - name: Configure container - run: | - docker run -dit --name build-container -v $PWD:/workspace -w /workspace swift:${{ matrix.swift }} - echo 'docker exec -i build-container "$@"' > ./build-exec - chmod +x ./build-exec + # build-musl: + # runs-on: ubuntu-22.04 + # strategy: + # matrix: + # include: + # - swift: 6.2-noble + # musl-swift-sdk-download: "https://download.swift.org/swift-6.2.3-release/static-sdk/swift-6.2.3-RELEASE/swift-6.2.3-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz" + # musl-swift-sdk-checksum: "f30ec724d824ef43b5546e02ca06a8682dafab4b26a99fbb0e858c347e507a2c" + # steps: + # - uses: actions/checkout@v4 + # - name: Configure container + # run: | + # docker run -dit --name build-container -v $PWD:/workspace -w /workspace swift:${{ matrix.swift }} + # echo 'docker exec -i build-container "$@"' > ./build-exec + # chmod +x ./build-exec - - name: Install Static Linux SDK - run: ./build-exec swift sdk install "${{ matrix.musl-swift-sdk-download }}" --checksum "${{ matrix.musl-swift-sdk-checksum }}" + # - name: Install Static Linux SDK + # run: ./build-exec swift sdk install "${{ matrix.musl-swift-sdk-download }}" --checksum "${{ matrix.musl-swift-sdk-checksum }}" - - name: Build (x86_64-swift-linux-musl) - run: ./build-exec swift build --swift-sdk x86_64-swift-linux-musl --traits WasmDebuggingSupport - - name: Build (aarch64-swift-linux-musl) - run: ./build-exec swift build --swift-sdk aarch64-swift-linux-musl --traits WasmDebuggingSupport + # - name: Build (x86_64-swift-linux-musl) + # run: ./build-exec swift build --swift-sdk x86_64-swift-linux-musl --traits WasmDebuggingSupport + # - name: Build (aarch64-swift-linux-musl) + # run: ./build-exec swift build --swift-sdk aarch64-swift-linux-musl --traits WasmDebuggingSupport - build-android: - runs-on: ubuntu-24.04 - timeout-minutes: 10 - strategy: - matrix: - include: - - swift-version: "6.2" - - swift-version: "nightly-6.3" - - swift-version: nightly-main + # build-android: + # runs-on: ubuntu-24.04 + # timeout-minutes: 10 + # strategy: + # matrix: + # include: + # - swift-version: "6.2" + # - swift-version: "nightly-6.3" + # - swift-version: nightly-main - steps: - - uses: actions/checkout@v4 - - name: Free up disk space - run: ./CI/gha-free-disk-space.sh - - name: Run Tests on Android emulator - uses: skiptools/swift-android-action@v2 - with: - android-api-level: 30 - swift-version: "${{ matrix.swift-version }}" + # steps: + # - uses: actions/checkout@v4 + # - name: Free up disk space + # run: ./CI/gha-free-disk-space.sh + # - name: Run Tests on Android emulator + # uses: skiptools/swift-android-action@v2 + # with: + # android-api-level: 30 + # swift-version: "${{ matrix.swift-version }}" - build-windows: - runs-on: windows-latest - steps: - - uses: compnerd/gha-setup-swift@main - with: - swift-version: swift-6.2-release - swift-build: 6.2-RELEASE - - uses: actions/checkout@v4 - - run: python3 ./Vendor/checkout-dependency - # FIXME: CMake build is failing on CI due to "link: extra operand '/OUT:lib\\libXXXX.a'" error - # # Check Windows build with CMake - # - uses: Cyberboss/install-winget@v1 - # - run: winget install Ninja-build.Ninja Kitware.CMake --disable-interactivity --accept-source-agreements - # - run: | - # echo "$env:LOCALAPPDATA\Microsoft\WinGet\Links" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - # echo "$env:ProgramFiles\CMake\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - # - run: cmake -G Ninja -B .build/cmake - # - run: cmake --build .build/cmake - # Run tests with SwiftPM - - name: Run tests with SwiftPM - run: swift test + # build-windows: + # runs-on: windows-latest + # steps: + # - uses: compnerd/gha-setup-swift@main + # with: + # swift-version: swift-6.2-release + # swift-build: 6.2-RELEASE + # - uses: actions/checkout@v4 + # - run: python3 ./Vendor/checkout-dependency + # # FIXME: CMake build is failing on CI due to "link: extra operand '/OUT:lib\\libXXXX.a'" error + # # # Check Windows build with CMake + # # - uses: Cyberboss/install-winget@v1 + # # - run: winget install Ninja-build.Ninja Kitware.CMake --disable-interactivity --accept-source-agreements + # # - run: | + # # echo "$env:LOCALAPPDATA\Microsoft\WinGet\Links" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + # # echo "$env:ProgramFiles\CMake\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + # # - run: cmake -G Ninja -B .build/cmake + # # - run: cmake --build .build/cmake + # # Run tests with SwiftPM + # - name: Run tests with SwiftPM + # run: swift test - build-cmake: - runs-on: ubuntu-24.04 - container: - image: swift:6.2-noble - steps: - - uses: actions/checkout@v4 - - name: Install Ninja - run: apt-get update && apt-get install -y ninja-build - - name: Install CMake - run: | - apt-get install -y curl - curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ - - run: cmake -G Ninja -B ./build - - run: cmake --build ./build - - run: ./build/bin/wasmkit --version + # build-cmake: + # runs-on: ubuntu-24.04 + # container: + # image: swift:6.2-noble + # steps: + # - uses: actions/checkout@v4 + # - name: Install Ninja + # run: apt-get update && apt-get install -y ninja-build + # - name: Install CMake + # run: | + # apt-get install -y curl + # curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ + # - run: cmake -G Ninja -B ./build + # - run: cmake --build ./build + # - run: ./build/bin/wasmkit --version build-llvm: runs-on: ubuntu-24.04 @@ -321,20 +321,21 @@ jobs: curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ - name: Build LLVM run: | + mkdir -p $GITHUB_WORKSPACE/llvm-project curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz -C $GITHUB_WORKSPACE/llvm-project - run: | ls $GITHUB_WORKSPACE/llvm-project - build-wasi: - runs-on: ubuntu-24.04 - container: - image: swift:6.2-noble - steps: - - uses: actions/checkout@v4 - - name: Install jq - run: apt-get update && apt-get install -y jq - - name: Install Swift SDK - run: swift sdk install https://download.swift.org/swift-6.2.3-release/wasm-sdk/swift-6.2.3-RELEASE/swift-6.2.3-RELEASE_wasm.artifactbundle.tar.gz --checksum 394040ecd5260e68bb02f6c20aeede733b9b90702c2204e178f3e42413edad2a - - name: Build with the Swift SDK - run: swift build --swift-sdk "$(swiftc -print-target-info | jq -r '.swiftCompilerTag')_wasm" --product wasmkit-cli + # build-wasi: + # runs-on: ubuntu-24.04 + # container: + # image: swift:6.2-noble + # steps: + # - uses: actions/checkout@v4 + # - name: Install jq + # run: apt-get update && apt-get install -y jq + # - name: Install Swift SDK + # run: swift sdk install https://download.swift.org/swift-6.2.3-release/wasm-sdk/swift-6.2.3-RELEASE/swift-6.2.3-RELEASE_wasm.artifactbundle.tar.gz --checksum 394040ecd5260e68bb02f6c20aeede733b9b90702c2204e178f3e42413edad2a + # - name: Build with the Swift SDK + # run: swift build --swift-sdk "$(swiftc -print-target-info | jq -r '.swiftCompilerTag')_wasm" --product wasmkit-cli From 13b5d27cbbd0fb76b2d7d4a507072500a4f8cca5 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 15:02:08 +0000 Subject: [PATCH 05/51] Refine LLVM build steps in CI workflow Updated the LLVM build process to include additional commands for directory navigation and build configuration. --- .github/workflows/main.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7656cd93..4badeb87 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -322,9 +322,11 @@ jobs: - name: Build LLVM run: | mkdir -p $GITHUB_WORKSPACE/llvm-project - curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz -C $GITHUB_WORKSPACE/llvm-project - - run: | - ls $GITHUB_WORKSPACE/llvm-project + curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/llvm-project + cd $GITHUB_WORKSPACE/llvm-project/llvm + cmake -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -B build + cmake --build build + ls $GITHUB_WORKSPACE # build-wasi: # runs-on: ubuntu-24.04 From ce9c98fdda85b21ca255687a40c2ac0d39d3cc2d Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 15:04:27 +0000 Subject: [PATCH 06/51] Install Python 3 when building LLVM --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4badeb87..c0dda7ae 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -313,8 +313,8 @@ jobs: image: swift:6.2-noble steps: - uses: actions/checkout@v4 - - name: Install Ninja - run: apt-get update && apt-get install -y ninja-build + - name: Install dependencies + run: apt-get update && apt-get install -y ninja-build python3 - name: Install CMake run: | apt-get install -y curl From 8b4f17d9f276b8944318dd1dd99f9ffcb7159991 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 15:09:18 +0000 Subject: [PATCH 07/51] Disable LLVM build commands in main.yml Comment out cmake build commands in workflow. --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c0dda7ae..db7e285f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -324,8 +324,8 @@ jobs: mkdir -p $GITHUB_WORKSPACE/llvm-project curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/llvm-project cd $GITHUB_WORKSPACE/llvm-project/llvm - cmake -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -B build - cmake --build build + # cmake -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -B build + # cmake --build build ls $GITHUB_WORKSPACE # build-wasi: From ea4f6a420560ef3466dbc1ad1559ad29b0844e59 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 15:16:00 +0000 Subject: [PATCH 08/51] Refactor LLVM build directory and commands Updated LLVM build process and directory structure. --- .github/workflows/main.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index db7e285f..8d906c0e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -321,12 +321,15 @@ jobs: curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ - name: Build LLVM run: | - mkdir -p $GITHUB_WORKSPACE/llvm-project + mkdir -p $GITHUB_WORKSPACE/Vendor/llvm-project curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/llvm-project - cd $GITHUB_WORKSPACE/llvm-project/llvm - # cmake -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -B build - # cmake --build build - ls $GITHUB_WORKSPACE + cmake -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -S $GITHUB_WORKSPACE/Vendor/llvm-project/llvm -B $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build + cmake --build $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build + - name: Build WasmKit with LLVM + run: | + LLVM_DIR="$GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build/lib/cmake/llvm/" cmake -DWASMKIT_BUILD_LLVM_BACKEND=ON -DWASMKIT_BUILD_CLI=ON -G Ninja -B ./build + cmake --build ./build + - run: ./build/bin/LLVMBackendCLI --help # build-wasi: # runs-on: ubuntu-24.04 From 4261974d74a5d867f76688dac1b5177100a2e38e Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 15:31:10 +0000 Subject: [PATCH 09/51] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8d906c0e..a57b4dc7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -322,7 +322,7 @@ jobs: - name: Build LLVM run: | mkdir -p $GITHUB_WORKSPACE/Vendor/llvm-project - curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/llvm-project + curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/Vendor/llvm-project cmake -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -S $GITHUB_WORKSPACE/Vendor/llvm-project/llvm -B $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build cmake --build $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build - name: Build WasmKit with LLVM From 60f09ef7c4060fe53f145cc70541e1b5d219b330 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 16:25:02 +0000 Subject: [PATCH 10/51] Add X86/AArch64 matrix for LLVM build --- .github/workflows/main.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a57b4dc7..bf66519f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -308,7 +308,15 @@ jobs: # - run: ./build/bin/wasmkit --version build-llvm: - runs-on: ubuntu-24.04 + strategy: + matrix: + include: + - os: ubuntu-24.04 + llvm-target: X86 + - os: ubuntu-24.04-arm + llvm-target: AArch64 + + runs-on: ${{ matrix.os }} container: image: swift:6.2-noble steps: @@ -323,7 +331,7 @@ jobs: run: | mkdir -p $GITHUB_WORKSPACE/Vendor/llvm-project curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/Vendor/llvm-project - cmake -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -S $GITHUB_WORKSPACE/Vendor/llvm-project/llvm -B $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build + cmake -DLLVM_TARGETS_TO_BUILD=${{ matrix.llvm-target }} -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -S $GITHUB_WORKSPACE/Vendor/llvm-project/llvm -B $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build cmake --build $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build - name: Build WasmKit with LLVM run: | From eebd6bc6ae00b96cef6bec32c1cf3d3803e45b15 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 16:26:47 +0000 Subject: [PATCH 11/51] Add `aarch64` to LLVM build matrix for CMake installation --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bf66519f..c02bf6bc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -313,8 +313,10 @@ jobs: include: - os: ubuntu-24.04 llvm-target: X86 + cmake-arch: x86_64 - os: ubuntu-24.04-arm llvm-target: AArch64 + cmake-arch: aarch64 runs-on: ${{ matrix.os }} container: @@ -326,7 +328,7 @@ jobs: - name: Install CMake run: | apt-get install -y curl - curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ + curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-${{ matrix.cmake-arch }}.tar.gz | tar xz --strip-component 1 -C /usr/local/ - name: Build LLVM run: | mkdir -p $GITHUB_WORKSPACE/Vendor/llvm-project From 28fe7ffd0f0fd207911c138fa9d3e68bbd82e476 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 17:25:08 +0000 Subject: [PATCH 12/51] Add caching for LLVM in GitHub Actions workflow --- .github/workflows/main.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c02bf6bc..59318244 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -329,7 +329,14 @@ jobs: run: | apt-get install -y curl curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-${{ matrix.cmake-arch }}.tar.gz | tar xz --strip-component 1 -C /usr/local/ + - name: Cache LLVM + id: cache-llvm + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/Vendor/llvm-project + key: llvm-${{ matrix.os }}-${{ matrix.llvm-target }}-swift-6.2.3 - name: Build LLVM + if: steps.cache-llvm.outputs.cache-hit != 'true' run: | mkdir -p $GITHUB_WORKSPACE/Vendor/llvm-project curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/Vendor/llvm-project From 4cbbca3199234dcfc2f19a453fc8b5228cb526e2 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 17:26:01 +0000 Subject: [PATCH 13/51] Fix libc imports in `LLVMBackend/Loader.swift` --- Sources/LLVMBackend/Loader.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/LLVMBackend/Loader.swift b/Sources/LLVMBackend/Loader.swift index eb284ecf..4c12cc81 100644 --- a/Sources/LLVMBackend/Loader.swift +++ b/Sources/LLVMBackend/Loader.swift @@ -1,4 +1,11 @@ +#if canImport(Darwin) import Darwin +#elseif canImport(Glibc) +import Glibc +#elseif canImport(Musl) +import Musl +#endif + import SystemPackage package protocol ImportedFunctionArguments { From 913626f17a6a0049d1ad76d1785b4ab6e82c663a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 18:07:31 +0000 Subject: [PATCH 14/51] Fix Linux build issues, use fresh LLVM tag from `swiftlang --- .github/workflows/main.yml | 7 ++++--- Sources/LLVMBackend/IRFunctionVisitor.swift | 8 +++++--- Sources/LLVMBackend/Linker.swift | 2 +- Sources/LLVMBackend/Loader.swift | 22 +++++++++++++++------ Sources/LLVMBackend/Wasm32Memory.swift | 2 -- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 59318244..e9923d01 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -317,7 +317,7 @@ jobs: - os: ubuntu-24.04-arm llvm-target: AArch64 cmake-arch: aarch64 - + runs-on: ${{ matrix.os }} container: image: swift:6.2-noble @@ -334,12 +334,13 @@ jobs: uses: actions/cache@v4 with: path: ${{ github.workspace }}/Vendor/llvm-project - key: llvm-${{ matrix.os }}-${{ matrix.llvm-target }}-swift-6.2.3 + # IMPORTANT: Update the key when updating LLVM tag below in the build step. + key: llvm-${{ matrix.os }}-${{ matrix.llvm-target }}-swift-main-2026-01-04 - name: Build LLVM if: steps.cache-llvm.outputs.cache-hit != 'true' run: | mkdir -p $GITHUB_WORKSPACE/Vendor/llvm-project - curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-6.2.3-RELEASE.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/Vendor/llvm-project + curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-DEVELOPMENT-SNAPSHOT-2026-01-04-a.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/Vendor/llvm-project cmake -DLLVM_TARGETS_TO_BUILD=${{ matrix.llvm-target }} -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -S $GITHUB_WORKSPACE/Vendor/llvm-project/llvm -B $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build cmake --build $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build - name: Build WasmKit with LLVM diff --git a/Sources/LLVMBackend/IRFunctionVisitor.swift b/Sources/LLVMBackend/IRFunctionVisitor.swift index 7d665c7e..e9f80454 100644 --- a/Sources/LLVMBackend/IRFunctionVisitor.swift +++ b/Sources/LLVMBackend/IRFunctionVisitor.swift @@ -59,11 +59,11 @@ struct IRFunctionVisitor: InstructionVisitor { private var nestedBlocks = [NestedWasmBlock]() mutating func push(_ value: IRValue) { - stack.append(value) + self.stack.append(value) } mutating func pop() -> IRValue { - stack.removeLast() + self.stack.removeLast() } init(name: String, type: FunctionType, locals: [ValueType], code: Code, ir: IRContext) throws { @@ -279,7 +279,9 @@ struct IRFunctionVisitor: InstructionVisitor { mutating func visitLoop(blockType: BlockType) throws { fatalError() } mutating func visitIf(blockType: BlockType) throws { - let condition = self.ir.__bEqUnsafe(self.pop(), self.ir.__i32ValueUnsafe(1)) + let stackTop = self.pop() + let conditionValue = self.ir.__i32ValueUnsafe(1) + let condition = self.ir.__bEqUnsafe(stackTop, conditionValue) switch blockType { case .funcType(let index): diff --git a/Sources/LLVMBackend/Linker.swift b/Sources/LLVMBackend/Linker.swift index ada9c719..65e35256 100644 --- a/Sources/LLVMBackend/Linker.swift +++ b/Sources/LLVMBackend/Linker.swift @@ -26,7 +26,7 @@ package enum Linker { return dylibPath #else - #error("Linking native binaries is currently only supported on macOS") + fatalError("Linking native binaries is currently only supported on macOS") #endif } } diff --git a/Sources/LLVMBackend/Loader.swift b/Sources/LLVMBackend/Loader.swift index 4c12cc81..6fac0c11 100644 --- a/Sources/LLVMBackend/Loader.swift +++ b/Sources/LLVMBackend/Loader.swift @@ -1,13 +1,13 @@ +import SystemPackage + #if canImport(Darwin) -import Darwin + import Darwin #elseif canImport(Glibc) -import Glibc + import Glibc #elseif canImport(Musl) -import Musl + import Musl #endif -import SystemPackage - package protocol ImportedFunctionArguments { associatedtype ResultType @@ -31,6 +31,7 @@ package struct U32Args2Result1: ImportedFunctionArguments { package struct Loader: ~Copyable { enum Error: Swift.Error { case symbolNotFound(String) + case dlopenFailed } package enum ClosureType { @@ -48,7 +49,16 @@ package struct Loader: ~Copyable { entrypointSymbol: String, arguments: T ) throws -> T.ResultType { - let handle = dlopen(library.string, RTLD_LAZY) + #if canImport(Darwin) + let handle = dlopen(library.string, RTLD_LAZY) + #elseif canImport(Glibc) || canImport(Musl) + guard let handle = dlopen(library.string, RTLD_LAZY) else { + throw Error.dlopenFailed + } + #else + #error("Unsupported platform in dynamic loading code") + #endif + defer { dlclose(handle) } guard let symbol = dlsym(handle, entrypointSymbol) else { diff --git a/Sources/LLVMBackend/Wasm32Memory.swift b/Sources/LLVMBackend/Wasm32Memory.swift index 51e5683d..4dbdd2de 100644 --- a/Sources/LLVMBackend/Wasm32Memory.swift +++ b/Sources/LLVMBackend/Wasm32Memory.swift @@ -1,5 +1,3 @@ -import Darwin - package struct Wasm32Memory: ~Copyable { // let memory: UnsafeMutableRawPointer From 82125acaed19c5b8bdcad3f669c11045c9828bc0 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 20:00:49 +0000 Subject: [PATCH 15/51] Link x86 LLVM components when building on x86 --- .github/workflows/main.yml | 2 +- CMakeLists.txt | 3 ++- Sources/LLVMInterop/CMakeLists.txt | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e9923d01..1e048341 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -345,7 +345,7 @@ jobs: cmake --build $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build - name: Build WasmKit with LLVM run: | - LLVM_DIR="$GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build/lib/cmake/llvm/" cmake -DWASMKIT_BUILD_LLVM_BACKEND=ON -DWASMKIT_BUILD_CLI=ON -G Ninja -B ./build + LLVM_DIR="$GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build/lib/cmake/llvm/" cmake -DWASMKIT_BUILD_LLVM_BACKEND=ON -DWASMKIT_LLVM_BACKEND_TARGET=${{ matrix.llvm-target }} -DWASMKIT_BUILD_CLI=ON -G Ninja -B ./build cmake --build ./build - run: ./build/bin/LLVMBackendCLI --help diff --git a/CMakeLists.txt b/CMakeLists.txt index 4374353f..b2cbab3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,8 @@ if(NOT SwiftSystem_FOUND) endif() option(WASMKIT_BUILD_CLI "Build WasmKit CLI" ON) -option(WASMKIT_BUILD_LLVM_BACKEND "Build WasmKit LLVM backend (experimental)") +option(WASMKIT_BUILD_LLVM_BACKEND "Build WasmKit LLVM backend (experimental)" OFF) +option(WASMKIT_LLVM_BACKEND_TARGET "WasmKit LLVM backend target architecture" "aarch64") if(WASMKIT_BUILD_CLI) set(BUILD_TESTING OFF) # disable ArgumentParser tests diff --git a/Sources/LLVMInterop/CMakeLists.txt b/Sources/LLVMInterop/CMakeLists.txt index b92c77c8..cd2d6786 100644 --- a/Sources/LLVMInterop/CMakeLists.txt +++ b/Sources/LLVMInterop/CMakeLists.txt @@ -27,7 +27,7 @@ target_include_directories( llvm_map_components_to_libnames(llvm_libs support core irreader mc passes targetparser target - aarch64codegen aarch64asmparser + ${WASMKIT_LLVM_BACKEND_TARGET}codegen ${WASMKIT_LLVM_BACKEND_TARGET}asmparser ) target_link_libraries(LLVMInterop ${llvm_libs}) From 01b74143331599e8ba970f87743e5bc382d55354 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 5 Jan 2026 20:53:50 +0000 Subject: [PATCH 16/51] Re-enable existing CI jobs --- .github/workflows/main.yml | 582 ++++++++++++++++++------------------- 1 file changed, 291 insertions(+), 291 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1e048341..423f7b1a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,302 +10,302 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: - # check-autogen-diff: - # runs-on: ubuntu-latest - # container: - # image: swift:6.2-noble - # steps: - # - uses: actions/checkout@v4 - # - name: Re-generate auto-generated code checks - # run: | - # swift run -q --package-path Utilities WasmKitDevUtils - # - name: Check for changes - # run: | - # git config --global --add safe.directory "$GITHUB_WORKSPACE" - # git diff --exit-code || { - # echo "::error::The auto-generated code utilities changed some files. Please see \`Utilities/README.md\`, re-run the tools, and commit the changes." - # exit 1 - # } - # build-macos: - # strategy: - # matrix: - # include: - # # Swift 6.0 - # - os: macos-14 - # xcode: Xcode_16.2 - # development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # test-args: "" - # # Swift 6.1 - # - os: macos-15 - # xcode: Xcode_16.4 - # development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # test-args: "--sanitize address --traits WasmDebuggingSupport" - # # Swift 6.2 - # - os: macos-15 - # xcode: Xcode_26.1 - # development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # test-args: "--sanitize address --traits WasmDebuggingSupport" - # # Swift 6.2.3 - # - os: macos-26 - # xcode: Xcode_26.2 - # development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # test-args: "--sanitize address --traits WasmDebuggingSupport" + check-autogen-diff: + runs-on: ubuntu-latest + container: + image: swift:6.2-noble + steps: + - uses: actions/checkout@v4 + - name: Re-generate auto-generated code checks + run: | + swift run -q --package-path Utilities WasmKitDevUtils + - name: Check for changes + run: | + git config --global --add safe.directory "$GITHUB_WORKSPACE" + git diff --exit-code || { + echo "::error::The auto-generated code utilities changed some files. Please see \`Utilities/README.md\`, re-run the tools, and commit the changes." + exit 1 + } + build-macos: + strategy: + matrix: + include: + # Swift 6.0 + - os: macos-14 + xcode: Xcode_16.2 + development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + test-args: "" + # Swift 6.1 + - os: macos-15 + xcode: Xcode_16.4 + development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + test-args: "--sanitize address --traits WasmDebuggingSupport" + # Swift 6.2 + - os: macos-15 + xcode: Xcode_26.1 + development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + test-args: "--sanitize address --traits WasmDebuggingSupport" + # Swift 6.2.3 + - os: macos-26 + xcode: Xcode_26.2 + development-toolchain-tag: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + test-args: "--sanitize address --traits WasmDebuggingSupport" - # runs-on: ${{ matrix.os }} - # name: "build-macos (${{ matrix.xcode }})" - # steps: - # - uses: actions/checkout@v4 - # - id: setup-development - # run: | - # toolchain_path="/Library/Developer/Toolchains/${{ matrix.development-toolchain-tag }}.xctoolchain" - # pkg="$(mktemp -d)/InstallMe.pkg" - # development_toolchain_download="https://download.swift.org/development/xcode/${{ matrix.development-toolchain-tag }}/${{ matrix.development-toolchain-tag }}-osx.pkg" - # curl -L "$development_toolchain_download" -o $pkg - # sudo installer -pkg $pkg -target / - # echo "toolchain-path=$toolchain_path" >> $GITHUB_OUTPUT - # "$toolchain_path/usr/bin/swift" sdk install "${{ matrix.wasi-swift-sdk-download }}" --checksum "${{ matrix.wasi-swift-sdk-checksum }}" - # wasi_sdk_path=$("$toolchain_path/usr/bin/swift" sdk configure --show-configuration "${{ matrix.wasi-swift-sdk-id }}" wasm32-unknown-wasi | grep sdkRootPath: | cut -d: -f2) - # echo "wasi-swift-sdk-path=$(dirname $wasi_sdk_path)" >> $GITHUB_OUTPUT + runs-on: ${{ matrix.os }} + name: "build-macos (${{ matrix.xcode }})" + steps: + - uses: actions/checkout@v4 + - id: setup-development + run: | + toolchain_path="/Library/Developer/Toolchains/${{ matrix.development-toolchain-tag }}.xctoolchain" + pkg="$(mktemp -d)/InstallMe.pkg" + development_toolchain_download="https://download.swift.org/development/xcode/${{ matrix.development-toolchain-tag }}/${{ matrix.development-toolchain-tag }}-osx.pkg" + curl -L "$development_toolchain_download" -o $pkg + sudo installer -pkg $pkg -target / + echo "toolchain-path=$toolchain_path" >> $GITHUB_OUTPUT + "$toolchain_path/usr/bin/swift" sdk install "${{ matrix.wasi-swift-sdk-download }}" --checksum "${{ matrix.wasi-swift-sdk-checksum }}" + wasi_sdk_path=$("$toolchain_path/usr/bin/swift" sdk configure --show-configuration "${{ matrix.wasi-swift-sdk-id }}" wasm32-unknown-wasi | grep sdkRootPath: | cut -d: -f2) + echo "wasi-swift-sdk-path=$(dirname $wasi_sdk_path)" >> $GITHUB_OUTPUT - # - name: Select Xcode version - # run: sudo xcode-select -switch /Applications/${{ matrix.xcode }}.app - # - name: Configure Tests/default.json - # run: | - # cat < Tests/default.json - # { - # "swiftExecutablePath": "${{ steps.setup-development.outputs.toolchain-path }}/usr/bin/swift", - # "wasiSwiftSDKPath": "${{ steps.setup-development.outputs.wasi-swift-sdk-path }}", - # "hostSwiftExecutablePath": "$(xcrun --find swift)", - # "hostSdkRootPath": "$(xcrun --show-sdk-path --sdk macosx)" - # } - # EOS - # - run: ./Vendor/checkout-dependency - # - run: swift test ${{ matrix.test-args }} + - name: Select Xcode version + run: sudo xcode-select -switch /Applications/${{ matrix.xcode }}.app + - name: Configure Tests/default.json + run: | + cat < Tests/default.json + { + "swiftExecutablePath": "${{ steps.setup-development.outputs.toolchain-path }}/usr/bin/swift", + "wasiSwiftSDKPath": "${{ steps.setup-development.outputs.wasi-swift-sdk-path }}", + "hostSwiftExecutablePath": "$(xcrun --find swift)", + "hostSdkRootPath": "$(xcrun --show-sdk-path --sdk macosx)" + } + EOS + - run: ./Vendor/checkout-dependency + - run: swift test ${{ matrix.test-args }} - # build-xcode: - # runs-on: macos-15 - # steps: - # - uses: actions/checkout@v4 - # - name: Prepare Xcode platforms - # run: | - # set -euxo pipefail - # sudo xcode-select -s /Applications/Xcode_26.0.app - # sudo xcodebuild -runFirstLaunch || true - # for PLAT in iOS tvOS watchOS visionOS; do - # if ! xcodebuild -showsdks | grep -q "$PLAT"; then - # echo "Downloading $PLAT platform..." - # sudo xcodebuild -downloadPlatform "$PLAT" - # fi - # done - # xcodebuild -showsdks - # xcodebuild -scheme WasmKit-Package -showdestinations || true - # - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=macOS - # - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=iOS - # - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=watchOS - # - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=tvOS - # - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=visionOS + build-xcode: + runs-on: macos-15 + steps: + - uses: actions/checkout@v4 + - name: Prepare Xcode platforms + run: | + set -euxo pipefail + sudo xcode-select -s /Applications/Xcode_26.0.app + sudo xcodebuild -runFirstLaunch || true + for PLAT in iOS tvOS watchOS visionOS; do + if ! xcodebuild -showsdks | grep -q "$PLAT"; then + echo "Downloading $PLAT platform..." + sudo xcodebuild -downloadPlatform "$PLAT" + fi + done + xcodebuild -showsdks + xcodebuild -scheme WasmKit-Package -showdestinations || true + - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=macOS + - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=iOS + - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=watchOS + - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=tvOS + - run: xcrun xcodebuild -skipMacroValidation -skipPackagePluginValidation build -scheme WasmKit-Package -destination generic/platform=visionOS - # build-linux: - # strategy: - # matrix: - # include: - # - swift: "swift:6.0-jammy" - # development-toolchain-download: "https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu22.04.tar.gz" - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # - swift: "swift:6.1-noble" - # development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # test-args: "--traits WasmDebuggingSupport" - # - swift: "swift:6.2-amazonlinux2" - # development-toolchain-download: "https://download.swift.org/development/amazonlinux2/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-amazonlinux2.tar.gz" - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # test-args: "--traits WasmDebuggingSupport" - # - swift: "swift:6.2-noble" - # development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # test-args: "--traits WasmDebuggingSupport --enable-code-coverage" - # build-dev-dashboard: true - # - swift: "swiftlang/swift:nightly-6.3-noble" - # development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY" - # - swift: "swiftlang/swift:nightly-main-noble" - # development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY" - # - swift: "swiftlang/swift:nightly-main-noble" - # development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" - # wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" - # wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm - # wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" - # test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY --build-system swiftbuild" - # label: " --build-system swiftbuild" + build-linux: + strategy: + matrix: + include: + - swift: "swift:6.0-jammy" + development-toolchain-download: "https://download.swift.org/development/ubuntu2204/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu22.04.tar.gz" + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + - swift: "swift:6.1-noble" + development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + test-args: "--traits WasmDebuggingSupport" + - swift: "swift:6.2-amazonlinux2" + development-toolchain-download: "https://download.swift.org/development/amazonlinux2/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-amazonlinux2.tar.gz" + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + test-args: "--traits WasmDebuggingSupport" + - swift: "swift:6.2-noble" + development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + test-args: "--traits WasmDebuggingSupport --enable-code-coverage" + build-dev-dashboard: true + - swift: "swiftlang/swift:nightly-6.3-noble" + development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY" + - swift: "swiftlang/swift:nightly-main-noble" + development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY" + - swift: "swiftlang/swift:nightly-main-noble" + development-toolchain-download: "https://download.swift.org/development/ubuntu2404/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a-ubuntu24.04.tar.gz" + wasi-swift-sdk-download: "https://download.swift.org/development/wasm-sdk/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a/swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm.artifactbundle.tar.gz" + wasi-swift-sdk-id: swift-DEVELOPMENT-SNAPSHOT-2025-10-02-a_wasm + wasi-swift-sdk-checksum: "b64dfad9e1c9ccdf06f35cf9b1a00317e000df0c0de0b3eb9f49d6db0fcba4d9" + test-args: "--traits WasmDebuggingSupport -Xswiftc -DWASMKIT_CI_TOOLCHAIN_NIGHTLY --build-system swiftbuild" + label: " --build-system swiftbuild" - # runs-on: ubuntu-24.04 - # name: "build-linux (${{ matrix.swift }}${{ matrix.label }})" + runs-on: ubuntu-24.04 + name: "build-linux (${{ matrix.swift }}${{ matrix.label }})" - # steps: - # - uses: actions/checkout@v4 - # - name: Configure container - # run: | - # docker run -dit --name build-container -v $PWD:/workspace -w /workspace ${{ matrix.swift }} - # echo 'docker exec -i build-container "$@"' > ./build-exec - # chmod +x ./build-exec + steps: + - uses: actions/checkout@v4 + - name: Configure container + run: | + docker run -dit --name build-container -v $PWD:/workspace -w /workspace ${{ matrix.swift }} + echo 'docker exec -i build-container "$@"' > ./build-exec + chmod +x ./build-exec - # - name: Install Development toolchain - # id: setup-development - # run: | - # toolchain_path="/opt/swiftwasm" - # ./build-exec mkdir -p "$toolchain_path" - # curl -L ${{ matrix.development-toolchain-download }} | ./build-exec tar xz --strip-component 1 -C "$toolchain_path" - # echo "toolchain-path=$toolchain_path" >> $GITHUB_OUTPUT - # ./build-exec "$toolchain_path/usr/bin/swift" sdk install "${{ matrix.wasi-swift-sdk-download }}" --checksum "${{ matrix.wasi-swift-sdk-checksum }}" - # wasi_sdk_path=$(./build-exec "$toolchain_path/usr/bin/swift" sdk configure --show-configuration "${{ matrix.wasi-swift-sdk-id }}" wasm32-unknown-wasi | grep sdkRootPath: | cut -d: -f2) - # echo "wasi-swift-sdk-path=$(dirname $wasi_sdk_path)" >> $GITHUB_OUTPUT + - name: Install Development toolchain + id: setup-development + run: | + toolchain_path="/opt/swiftwasm" + ./build-exec mkdir -p "$toolchain_path" + curl -L ${{ matrix.development-toolchain-download }} | ./build-exec tar xz --strip-component 1 -C "$toolchain_path" + echo "toolchain-path=$toolchain_path" >> $GITHUB_OUTPUT + ./build-exec "$toolchain_path/usr/bin/swift" sdk install "${{ matrix.wasi-swift-sdk-download }}" --checksum "${{ matrix.wasi-swift-sdk-checksum }}" + wasi_sdk_path=$(./build-exec "$toolchain_path/usr/bin/swift" sdk configure --show-configuration "${{ matrix.wasi-swift-sdk-id }}" wasm32-unknown-wasi | grep sdkRootPath: | cut -d: -f2) + echo "wasi-swift-sdk-path=$(dirname $wasi_sdk_path)" >> $GITHUB_OUTPUT - # - name: Configure Tests/default.json - # run: | - # cat < Tests/default.json - # { - # "swiftExecutablePath": "${{ steps.setup-development.outputs.toolchain-path }}/usr/bin/swift", - # "wasiSwiftSDKPath": "${{ steps.setup-development.outputs.wasi-swift-sdk-path }}", - # "hostSwiftExecutablePath": "/usr/bin/swift" - # } - # EOS - # - run: ./build-exec ./CI/install-wabt.sh - # - run: ./Vendor/checkout-dependency - # - run: ./build-exec swift test ${{ matrix.test-args }} + - name: Configure Tests/default.json + run: | + cat < Tests/default.json + { + "swiftExecutablePath": "${{ steps.setup-development.outputs.toolchain-path }}/usr/bin/swift", + "wasiSwiftSDKPath": "${{ steps.setup-development.outputs.wasi-swift-sdk-path }}", + "hostSwiftExecutablePath": "/usr/bin/swift" + } + EOS + - run: ./build-exec ./CI/install-wabt.sh + - run: ./Vendor/checkout-dependency + - run: ./build-exec swift test ${{ matrix.test-args }} - # - if: matrix.build-dev-dashboard - # run: ./build-exec ./CI/build-dev-dashboard.sh - # - if: matrix.build-dev-dashboard - # name: Relax artifact permissions - # run: sudo chown -R $USER .build/html - # - if: matrix.build-dev-dashboard - # id: deployment - # uses: actions/upload-pages-artifact@v4 - # with: - # path: .build/html + - if: matrix.build-dev-dashboard + run: ./build-exec ./CI/build-dev-dashboard.sh + - if: matrix.build-dev-dashboard + name: Relax artifact permissions + run: sudo chown -R $USER .build/html + - if: matrix.build-dev-dashboard + id: deployment + uses: actions/upload-pages-artifact@v4 + with: + path: .build/html - # deploy-dev-dashboard: - # environment: - # name: github-pages - # url: ${{ steps.deployment.outputs.page_url }} - # runs-on: ubuntu-latest - # if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} - # needs: build-linux - # permissions: - # id-token: write - # pages: write - # steps: - # - id: deployment - # uses: actions/deploy-pages@v4 + deploy-dev-dashboard: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + needs: build-linux + permissions: + id-token: write + pages: write + steps: + - id: deployment + uses: actions/deploy-pages@v4 - # build-musl: - # runs-on: ubuntu-22.04 - # strategy: - # matrix: - # include: - # - swift: 6.2-noble - # musl-swift-sdk-download: "https://download.swift.org/swift-6.2.3-release/static-sdk/swift-6.2.3-RELEASE/swift-6.2.3-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz" - # musl-swift-sdk-checksum: "f30ec724d824ef43b5546e02ca06a8682dafab4b26a99fbb0e858c347e507a2c" - # steps: - # - uses: actions/checkout@v4 - # - name: Configure container - # run: | - # docker run -dit --name build-container -v $PWD:/workspace -w /workspace swift:${{ matrix.swift }} - # echo 'docker exec -i build-container "$@"' > ./build-exec - # chmod +x ./build-exec + build-musl: + runs-on: ubuntu-22.04 + strategy: + matrix: + include: + - swift: 6.2-noble + musl-swift-sdk-download: "https://download.swift.org/swift-6.2.3-release/static-sdk/swift-6.2.3-RELEASE/swift-6.2.3-RELEASE_static-linux-0.0.1.artifactbundle.tar.gz" + musl-swift-sdk-checksum: "f30ec724d824ef43b5546e02ca06a8682dafab4b26a99fbb0e858c347e507a2c" + steps: + - uses: actions/checkout@v4 + - name: Configure container + run: | + docker run -dit --name build-container -v $PWD:/workspace -w /workspace swift:${{ matrix.swift }} + echo 'docker exec -i build-container "$@"' > ./build-exec + chmod +x ./build-exec - # - name: Install Static Linux SDK - # run: ./build-exec swift sdk install "${{ matrix.musl-swift-sdk-download }}" --checksum "${{ matrix.musl-swift-sdk-checksum }}" + - name: Install Static Linux SDK + run: ./build-exec swift sdk install "${{ matrix.musl-swift-sdk-download }}" --checksum "${{ matrix.musl-swift-sdk-checksum }}" - # - name: Build (x86_64-swift-linux-musl) - # run: ./build-exec swift build --swift-sdk x86_64-swift-linux-musl --traits WasmDebuggingSupport - # - name: Build (aarch64-swift-linux-musl) - # run: ./build-exec swift build --swift-sdk aarch64-swift-linux-musl --traits WasmDebuggingSupport + - name: Build (x86_64-swift-linux-musl) + run: ./build-exec swift build --swift-sdk x86_64-swift-linux-musl --traits WasmDebuggingSupport + - name: Build (aarch64-swift-linux-musl) + run: ./build-exec swift build --swift-sdk aarch64-swift-linux-musl --traits WasmDebuggingSupport - # build-android: - # runs-on: ubuntu-24.04 - # timeout-minutes: 10 - # strategy: - # matrix: - # include: - # - swift-version: "6.2" - # - swift-version: "nightly-6.3" - # - swift-version: nightly-main + build-android: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + strategy: + matrix: + include: + - swift-version: "6.2" + - swift-version: "nightly-6.3" + - swift-version: nightly-main - # steps: - # - uses: actions/checkout@v4 - # - name: Free up disk space - # run: ./CI/gha-free-disk-space.sh - # - name: Run Tests on Android emulator - # uses: skiptools/swift-android-action@v2 - # with: - # android-api-level: 30 - # swift-version: "${{ matrix.swift-version }}" + steps: + - uses: actions/checkout@v4 + - name: Free up disk space + run: ./CI/gha-free-disk-space.sh + - name: Run Tests on Android emulator + uses: skiptools/swift-android-action@v2 + with: + android-api-level: 30 + swift-version: "${{ matrix.swift-version }}" - # build-windows: - # runs-on: windows-latest - # steps: - # - uses: compnerd/gha-setup-swift@main - # with: - # swift-version: swift-6.2-release - # swift-build: 6.2-RELEASE - # - uses: actions/checkout@v4 - # - run: python3 ./Vendor/checkout-dependency - # # FIXME: CMake build is failing on CI due to "link: extra operand '/OUT:lib\\libXXXX.a'" error - # # # Check Windows build with CMake - # # - uses: Cyberboss/install-winget@v1 - # # - run: winget install Ninja-build.Ninja Kitware.CMake --disable-interactivity --accept-source-agreements - # # - run: | - # # echo "$env:LOCALAPPDATA\Microsoft\WinGet\Links" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - # # echo "$env:ProgramFiles\CMake\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - # # - run: cmake -G Ninja -B .build/cmake - # # - run: cmake --build .build/cmake - # # Run tests with SwiftPM - # - name: Run tests with SwiftPM - # run: swift test + build-windows: + runs-on: windows-latest + steps: + - uses: compnerd/gha-setup-swift@main + with: + swift-version: swift-6.2-release + swift-build: 6.2-RELEASE + - uses: actions/checkout@v4 + - run: python3 ./Vendor/checkout-dependency + # FIXME: CMake build is failing on CI due to "link: extra operand '/OUT:lib\\libXXXX.a'" error + # # Check Windows build with CMake + # - uses: Cyberboss/install-winget@v1 + # - run: winget install Ninja-build.Ninja Kitware.CMake --disable-interactivity --accept-source-agreements + # - run: | + # echo "$env:LOCALAPPDATA\Microsoft\WinGet\Links" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + # echo "$env:ProgramFiles\CMake\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + # - run: cmake -G Ninja -B .build/cmake + # - run: cmake --build .build/cmake + # Run tests with SwiftPM + - name: Run tests with SwiftPM + run: swift test - # build-cmake: - # runs-on: ubuntu-24.04 - # container: - # image: swift:6.2-noble - # steps: - # - uses: actions/checkout@v4 - # - name: Install Ninja - # run: apt-get update && apt-get install -y ninja-build - # - name: Install CMake - # run: | - # apt-get install -y curl - # curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ - # - run: cmake -G Ninja -B ./build - # - run: cmake --build ./build - # - run: ./build/bin/wasmkit --version + build-cmake: + runs-on: ubuntu-24.04 + container: + image: swift:6.2-noble + steps: + - uses: actions/checkout@v4 + - name: Install Ninja + run: apt-get update && apt-get install -y ninja-build + - name: Install CMake + run: | + apt-get install -y curl + curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ + - run: cmake -G Ninja -B ./build + - run: cmake --build ./build + - run: ./build/bin/wasmkit --version build-llvm: strategy: @@ -349,16 +349,16 @@ jobs: cmake --build ./build - run: ./build/bin/LLVMBackendCLI --help - # build-wasi: - # runs-on: ubuntu-24.04 - # container: - # image: swift:6.2-noble - # steps: - # - uses: actions/checkout@v4 - # - name: Install jq - # run: apt-get update && apt-get install -y jq - # - name: Install Swift SDK - # run: swift sdk install https://download.swift.org/swift-6.2.3-release/wasm-sdk/swift-6.2.3-RELEASE/swift-6.2.3-RELEASE_wasm.artifactbundle.tar.gz --checksum 394040ecd5260e68bb02f6c20aeede733b9b90702c2204e178f3e42413edad2a - # - name: Build with the Swift SDK - # run: swift build --swift-sdk "$(swiftc -print-target-info | jq -r '.swiftCompilerTag')_wasm" --product wasmkit-cli + build-wasi: + runs-on: ubuntu-24.04 + container: + image: swift:6.2-noble + steps: + - uses: actions/checkout@v4 + - name: Install jq + run: apt-get update && apt-get install -y jq + - name: Install Swift SDK + run: swift sdk install https://download.swift.org/swift-6.2.3-release/wasm-sdk/swift-6.2.3-RELEASE/swift-6.2.3-RELEASE_wasm.artifactbundle.tar.gz --checksum 394040ecd5260e68bb02f6c20aeede733b9b90702c2204e178f3e42413edad2a + - name: Build with the Swift SDK + run: swift build --swift-sdk "$(swiftc -print-target-info | jq -r '.swiftCompilerTag')_wasm" --product wasmkit-cli From 954f9053c1d88e6145f3ea749157260304f28940 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 09:04:08 +0000 Subject: [PATCH 17/51] Rename `LLVMBackendCLI` to `wasmkit-llvm`, add `swift-collections` dep --- Sources/LLVMBackend/CMakeLists.txt | 17 ++++++++++++++++- Sources/LLVMBackend/IRFunctionVisitor.swift | 1 + Sources/LLVMBackendCLI/CMakeLists.txt | 11 +++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/Sources/LLVMBackend/CMakeLists.txt b/Sources/LLVMBackend/CMakeLists.txt index f2095eca..b4782ef1 100644 --- a/Sources/LLVMBackend/CMakeLists.txt +++ b/Sources/LLVMBackend/CMakeLists.txt @@ -56,11 +56,26 @@ if(NOT Subprocess_FOUND) FetchContent_MakeAvailable(Subprocess) endif() +find_package(SwiftCollections CONFIG) +if (NOT SwiftCollections FOUND) + + message("-- Vending SwiftCollections") + FetchContent_Declare( + Subprocess + GIT_REPOSITORY https://github.com/apple/swift-collections + GIT_TAG 1.3.0 + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable(SwiftCollections) +endif() -add_dependencies(LLVMInterop LLVM_Utils Subprocess ${WASMKIT_DEPENDENCIES}) + +add_dependencies(LLVMInterop BasicContainers LLVM_Utils Subprocess ${WASMKIT_DEPENDENCIES}) target_link_libraries( LLVMBackend + + BasicContainers ${WASMKIT_DEPENDENCIES} LLVMInterop LLVM_Utils diff --git a/Sources/LLVMBackend/IRFunctionVisitor.swift b/Sources/LLVMBackend/IRFunctionVisitor.swift index e9f80454..4b71c9d1 100644 --- a/Sources/LLVMBackend/IRFunctionVisitor.swift +++ b/Sources/LLVMBackend/IRFunctionVisitor.swift @@ -1,3 +1,4 @@ +import BasicContainers import LLVMInterop import WasmParser import WasmTypes diff --git a/Sources/LLVMBackendCLI/CMakeLists.txt b/Sources/LLVMBackendCLI/CMakeLists.txt index d78069c1..695f0004 100644 --- a/Sources/LLVMBackendCLI/CMakeLists.txt +++ b/Sources/LLVMBackendCLI/CMakeLists.txt @@ -1,10 +1,10 @@ add_executable( - LLVMBackendCLI + wasmkit-llvm Entrypoint.swift ) target_compile_options( - LLVMBackendCLI + wasmkit-llvm PRIVATE -parse-as-library -package-name WasmKitPackage @@ -22,11 +22,14 @@ if(NOT ArgumentParser_FOUND) FetchContent_MakeAvailable(ArgumentParser) endif() -add_dependencies(LLVMBackendCLI ArgumentParser LLVMBackend) +add_dependencies(wasmkit-llvm ArgumentParser LLVMBackend) target_link_libraries( - LLVMBackendCLI + wasmkit-llvm ArgumentParser LLVMBackend ) + +install(TARGETS wasmkit-llvm + RUNTIME DESTINATION bin) From b0239f48fb4afa284878f316b034b042eb96408b Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 09:07:13 +0000 Subject: [PATCH 18/51] Fix `SwiftCollections` typo in `FetchContent` block --- Sources/LLVMBackend/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Sources/LLVMBackend/CMakeLists.txt b/Sources/LLVMBackend/CMakeLists.txt index b4782ef1..b2e32b54 100644 --- a/Sources/LLVMBackend/CMakeLists.txt +++ b/Sources/LLVMBackend/CMakeLists.txt @@ -57,11 +57,10 @@ if(NOT Subprocess_FOUND) endif() find_package(SwiftCollections CONFIG) -if (NOT SwiftCollections FOUND) - +if(NOT SwiftCollections_FOUND) message("-- Vending SwiftCollections") FetchContent_Declare( - Subprocess + SwiftCollections GIT_REPOSITORY https://github.com/apple/swift-collections GIT_TAG 1.3.0 GIT_SHALLOW TRUE From 216a4aab95dba43bd5a85245af98bfc6e3088e6e Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 09:13:35 +0000 Subject: [PATCH 19/51] CMake: explicitly pass `-module-name` for `wasmkit-llvm` target --- .github/workflows/main.yml | 2 +- Sources/LLVMBackendCLI/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 423f7b1a..a0d532a6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -347,7 +347,7 @@ jobs: run: | LLVM_DIR="$GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build/lib/cmake/llvm/" cmake -DWASMKIT_BUILD_LLVM_BACKEND=ON -DWASMKIT_LLVM_BACKEND_TARGET=${{ matrix.llvm-target }} -DWASMKIT_BUILD_CLI=ON -G Ninja -B ./build cmake --build ./build - - run: ./build/bin/LLVMBackendCLI --help + - run: ./build/bin/wasmkit-llvm --help build-wasi: runs-on: ubuntu-24.04 diff --git a/Sources/LLVMBackendCLI/CMakeLists.txt b/Sources/LLVMBackendCLI/CMakeLists.txt index 695f0004..9777749b 100644 --- a/Sources/LLVMBackendCLI/CMakeLists.txt +++ b/Sources/LLVMBackendCLI/CMakeLists.txt @@ -8,6 +8,7 @@ target_compile_options( PRIVATE -parse-as-library -package-name WasmKitPackage + -module-name LLVMBackendCLI ) set(BUILD_TESTING OFF) From d69db0ac095290139a23e5f48ca1cb25ab824f55 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 09:20:10 +0000 Subject: [PATCH 20/51] Replace `UMBP` with `RigidArray` in `CodegenContext` --- Sources/LLVMBackend/CodegenContext.swift | 24 ++++++++------------- Sources/LLVMBackend/IRFunctionVisitor.swift | 1 - 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/Sources/LLVMBackend/CodegenContext.swift b/Sources/LLVMBackend/CodegenContext.swift index a14aa64e..5c0ff2cd 100644 --- a/Sources/LLVMBackend/CodegenContext.swift +++ b/Sources/LLVMBackend/CodegenContext.swift @@ -1,3 +1,4 @@ +import BasicContainers import LLVMInterop import LLVM_Analysis import LLVM_Utils @@ -27,12 +28,7 @@ package struct CodegenContext: ~Copyable { var types = [FunctionType]() var functionTypes = [TypeIndex]() - var functionVisitors: UnsafeMutableBufferPointer? - defer { - if let functionVisitors { - functionVisitors.deallocate() - } - } + var functionVisitors = RigidArray() var importedFunctions = [IRValue]() var functionNames = [String]() var memories = [Memory]() @@ -76,14 +72,14 @@ package struct CodegenContext: ~Copyable { } case .codeSection(let functions): - functionVisitors = .allocate(capacity: functions.count) + functionVisitors = RigidArray(capacity: functions.count) for (i, f) in functions.enumerated() { let type = types[Int(functionTypes[importedFunctions.count + i])] // Create visitors first before actually visiting instructions. // This will forward-declare all `llvm::Function` instances so that `call` // LLVM IR instructions have these instances to refer to and are valid. let name = "\(i)" - try functionVisitors?[i] = .init( + try functionVisitors[i] = .init( name: name, type: type, locals: type.parameters + f.locals, @@ -97,13 +93,11 @@ package struct CodegenContext: ~Copyable { } } - if let functionVisitors { - for i in 0.. Date: Tue, 6 Jan 2026 09:33:10 +0000 Subject: [PATCH 21/51] Make `IRFunctionVisitor` noncopyable --- Sources/LLVMBackend/IRFunctionVisitor.swift | 2 +- Sources/WasmParser/BinaryInstructionDecoder.swift | 2 +- Sources/WasmParser/InstructionVisitor.swift | 6 +++--- Sources/WasmParser/WasmParser.swift | 4 ++-- Sources/WasmParser/WasmTypes.swift | 12 ++++++------ Utilities/Sources/WasmGen.swift | 8 ++++---- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Sources/LLVMBackend/IRFunctionVisitor.swift b/Sources/LLVMBackend/IRFunctionVisitor.swift index e9f80454..0f5a788a 100644 --- a/Sources/LLVMBackend/IRFunctionVisitor.swift +++ b/Sources/LLVMBackend/IRFunctionVisitor.swift @@ -2,7 +2,7 @@ import LLVMInterop import WasmParser import WasmTypes -struct IRFunctionVisitor: InstructionVisitor { +struct IRFunctionVisitor: InstructionVisitor, ~Copyable { enum Error: Swift.Error { case irFunctionUnknown(Int) case irFunctionCreationFailed diff --git a/Sources/WasmParser/BinaryInstructionDecoder.swift b/Sources/WasmParser/BinaryInstructionDecoder.swift index 68e3c9b6..c9c7a909 100644 --- a/Sources/WasmParser/BinaryInstructionDecoder.swift +++ b/Sources/WasmParser/BinaryInstructionDecoder.swift @@ -101,7 +101,7 @@ protocol BinaryInstructionDecoder { } @inlinable -func parseBinaryInstruction(visitor: inout some InstructionVisitor, decoder: inout some BinaryInstructionDecoder) throws -> Bool { +func parseBinaryInstruction(visitor: inout some InstructionVisitor & ~Copyable, decoder: inout some BinaryInstructionDecoder) throws -> Bool { visitor.binaryOffset = decoder.offset let opcode0 = try decoder.claimNextByte() switch opcode0 { diff --git a/Sources/WasmParser/InstructionVisitor.swift b/Sources/WasmParser/InstructionVisitor.swift index 46b06b41..2dcda5cb 100644 --- a/Sources/WasmParser/InstructionVisitor.swift +++ b/Sources/WasmParser/InstructionVisitor.swift @@ -319,7 +319,7 @@ extension AnyInstructionVisitor { /// /// The visitor pattern is used while parsing WebAssembly expressions to allow for easy extensibility. /// See the expression parsing method ``Code/parseExpression(visitor:)`` -public protocol InstructionVisitor { +public protocol InstructionVisitor: ~Copyable { /// Current offset in visitor's instruction stream. var binaryOffset: Int { get set } @@ -443,7 +443,7 @@ public protocol InstructionVisitor { mutating func visitUnknown(_ opcode: [UInt8]) throws -> Bool } -extension InstructionVisitor { +extension InstructionVisitor where Self: ~Copyable { /// Visits an instruction. public mutating func visit(_ instruction: Instruction) throws { switch instruction { @@ -510,7 +510,7 @@ extension InstructionVisitor { } // MARK: - Placeholder implementations -extension InstructionVisitor { +extension InstructionVisitor where Self: ~Copyable { public mutating func visitUnreachable() throws {} public mutating func visitNop() throws {} public mutating func visitBlock(blockType: BlockType) throws {} diff --git a/Sources/WasmParser/WasmParser.swift b/Sources/WasmParser/WasmParser.swift index 14fb10d7..5e339157 100644 --- a/Sources/WasmParser/WasmParser.swift +++ b/Sources/WasmParser/WasmParser.swift @@ -121,7 +121,7 @@ extension Code { /// } /// ```` @inlinable - public func parseExpression(visitor: inout V) throws { + public func parseExpression(visitor: inout some InstructionVisitor & ~Copyable) throws { var parser = Parser(stream: StaticByteStream(bytes: self.expression), features: self.features) var lastIsEnd: Bool? while try !parser.stream.hasReachedEnd() { @@ -803,7 +803,7 @@ extension Parser: BinaryInstructionDecoder { /// Returns: `true` if the parsed instruction is the block end instruction. @inline(__always) @inlinable - mutating func parseInstruction(visitor v: inout V) throws -> Bool { + mutating func parseInstruction(visitor v: inout some InstructionVisitor & ~Copyable) throws -> Bool { return try parseBinaryInstruction(visitor: &v, decoder: &self) } diff --git a/Sources/WasmParser/WasmTypes.swift b/Sources/WasmParser/WasmTypes.swift index 60870360..6fe6240e 100644 --- a/Sources/WasmParser/WasmTypes.swift +++ b/Sources/WasmParser/WasmTypes.swift @@ -52,7 +52,7 @@ public enum BlockType: Equatable { /// > Note: /// -public struct Limits: Equatable { +public struct Limits: Equatable, Sendable { public var min: UInt64 public var max: UInt64? public var isMemory64: Bool @@ -72,7 +72,7 @@ public typealias MemoryType = Limits /// > Note: /// -public struct TableType: Equatable { +public struct TableType: Equatable, Sendable { public var elementType: ReferenceType public var limits: Limits @@ -84,14 +84,14 @@ public struct TableType: Equatable { /// > Note: /// -public enum Mutability: Equatable { +public enum Mutability: Equatable, Sendable { case constant case variable } /// > Note: /// -public struct GlobalType: Equatable { +public struct GlobalType: Equatable, Sendable { public let mutability: Mutability public let valueType: ValueType @@ -282,7 +282,7 @@ public enum ExportDescriptor: Equatable { /// Import entity in a module /// > Note: /// -public struct Import: Equatable { +public struct Import: Equatable, Sendable { /// Module name imported from public let module: String /// Name of the import @@ -298,7 +298,7 @@ public struct Import: Equatable { } /// Import descriptor -public enum ImportDescriptor: Equatable { +public enum ImportDescriptor: Equatable, Sendable { /// Function import case function(TypeIndex) /// Table import diff --git a/Utilities/Sources/WasmGen.swift b/Utilities/Sources/WasmGen.swift index 1e217bda..a5c64310 100644 --- a/Utilities/Sources/WasmGen.swift +++ b/Utilities/Sources/WasmGen.swift @@ -95,7 +95,7 @@ enum WasmGen { /// /// The visitor pattern is used while parsing WebAssembly expressions to allow for easy extensibility. /// See the expression parsing method ``Code/parseExpression(visitor:)`` - public protocol InstructionVisitor { + public protocol InstructionVisitor: ~Copyable { /// Current offset in visitor's instruction stream. var binaryOffset: Int { get set } @@ -121,7 +121,7 @@ enum WasmGen { code += """ - extension InstructionVisitor { + extension InstructionVisitor where Self: ~Copyable { /// Visits an instruction. public mutating func visit(_ instruction: Instruction) throws { switch instruction { @@ -153,7 +153,7 @@ enum WasmGen { code += """ // MARK: - Placeholder implementations - extension InstructionVisitor { + extension InstructionVisitor where Self: ~Copyable { """ for instruction in instructions.categorized { @@ -567,7 +567,7 @@ enum WasmGen { code += """ @inlinable - func parseBinaryInstruction(visitor: inout some InstructionVisitor, decoder: inout some BinaryInstructionDecoder) throws -> Bool { + func parseBinaryInstruction(visitor: inout some InstructionVisitor & ~Copyable, decoder: inout some BinaryInstructionDecoder) throws -> Bool { visitor.binaryOffset = decoder.offset """ From 626ebd94aa953d2726d0d454e27a34b74fdf3173 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 13:01:59 +0000 Subject: [PATCH 22/51] Move CLI command types into a library for reuse in `LLVMBackendCLI` module --- Sources/CLI/CLI.swift | 1 + Sources/CLI/CMakeLists.txt | 5 +--- Sources/CLI/Commands/Parse.swift | 20 -------------- Sources/CLICommands/CMakeLists.txt | 8 ++++++ .../Commands => CLICommands}/Explore.swift | 8 +++--- Sources/CLICommands/Parse.swift | 3 +++ .../{CLI/Commands => CLICommands}/Run.swift | 26 ++++++++++++++++--- .../Commands => CLICommands}/Wat2wasm.swift | 8 +++--- Sources/CMakeLists.txt | 1 + Sources/LLVMBackendCLI/CMakeLists.txt | 3 ++- 10 files changed, 49 insertions(+), 34 deletions(-) delete mode 100644 Sources/CLI/Commands/Parse.swift create mode 100644 Sources/CLICommands/CMakeLists.txt rename Sources/{CLI/Commands => CLICommands}/Explore.swift (91%) create mode 100644 Sources/CLICommands/Parse.swift rename Sources/{CLI/Commands => CLICommands}/Run.swift (92%) rename Sources/{CLI/Commands => CLICommands}/Wat2wasm.swift (95%) diff --git a/Sources/CLI/CLI.swift b/Sources/CLI/CLI.swift index 14d53166..bf410ea6 100644 --- a/Sources/CLI/CLI.swift +++ b/Sources/CLI/CLI.swift @@ -1,4 +1,5 @@ import ArgumentParser +import CLICommands @main struct CLI: AsyncParsableCommand { diff --git a/Sources/CLI/CMakeLists.txt b/Sources/CLI/CMakeLists.txt index 4a6d8d35..74551c61 100644 --- a/Sources/CLI/CMakeLists.txt +++ b/Sources/CLI/CMakeLists.txt @@ -1,12 +1,9 @@ add_executable(wasmkit - Commands/Explore.swift - Commands/Run.swift - Commands/Wat2wasm.swift CLI.swift ) target_link_wasmkit_libraries(wasmkit PUBLIC - ArgumentParser WAT WasmKitWASI) + CLICommands) install(TARGETS wasmkit RUNTIME DESTINATION bin) diff --git a/Sources/CLI/Commands/Parse.swift b/Sources/CLI/Commands/Parse.swift deleted file mode 100644 index 121edc72..00000000 --- a/Sources/CLI/Commands/Parse.swift +++ /dev/null @@ -1,20 +0,0 @@ -import SystemPackage -import WAT -import WasmKit - -/// Parses a `.wasm` or `.wat` module. -func parseWasm(filePath: FilePath) throws -> Module { - if filePath.extension == "wat", #available(macOS 11.0, iOS 14.0, macCatalyst 14.0, tvOS 14.0, visionOS 1.0, watchOS 7.0, *) { - let fileHandle = try FileDescriptor.open(filePath, .readOnly) - defer { try? fileHandle.close() } - - let size = try fileHandle.seek(offset: 0, from: .end) - - let wat = try String(unsafeUninitializedCapacity: Int(size)) { - try fileHandle.read(fromAbsoluteOffset: 0, into: .init($0)) - } - return try WasmKit.parseWasm(bytes: wat2wasm(wat)) - } else { - return try WasmKit.parseWasm(filePath: filePath) - } -} diff --git a/Sources/CLICommands/CMakeLists.txt b/Sources/CLICommands/CMakeLists.txt new file mode 100644 index 00000000..ada5b5b7 --- /dev/null +++ b/Sources/CLICommands/CMakeLists.txt @@ -0,0 +1,8 @@ +add_wasmkit_library(CLICommands + Explore.swift + Run.swift + Wat2wasm.swift +) + +target_link_wasmkit_libraries(CLICommands PUBLIC + ArgumentParser WAT WasmKitWASI) diff --git a/Sources/CLI/Commands/Explore.swift b/Sources/CLICommands/Explore.swift similarity index 91% rename from Sources/CLI/Commands/Explore.swift rename to Sources/CLICommands/Explore.swift index 9af9d949..df424c94 100644 --- a/Sources/CLI/Commands/Explore.swift +++ b/Sources/CLICommands/Explore.swift @@ -2,9 +2,9 @@ import ArgumentParser import SystemPackage @_spi(OnlyForCLI) import WasmKit -struct Explore: ParsableCommand { +package struct Explore: ParsableCommand { - static let configuration = CommandConfiguration( + package static let configuration = CommandConfiguration( abstract: "Explore the compiled functions of a WebAssembly module", discussion: """ This command will parse a WebAssembly module and dump the compiled functions. @@ -22,7 +22,9 @@ struct Explore: ParsableCommand { } } - func run() throws { + package init() {} + + package func run() throws { let module = try parseWasm(filePath: FilePath(path)) // Instruction dumping requires token threading model for now let configuration = EngineConfiguration(threadingModel: .token) diff --git a/Sources/CLICommands/Parse.swift b/Sources/CLICommands/Parse.swift new file mode 100644 index 00000000..70fdc05d --- /dev/null +++ b/Sources/CLICommands/Parse.swift @@ -0,0 +1,3 @@ +import SystemPackage +import WAT +import WasmKit diff --git a/Sources/CLI/Commands/Run.swift b/Sources/CLICommands/Run.swift similarity index 92% rename from Sources/CLI/Commands/Run.swift rename to Sources/CLICommands/Run.swift index 32769a72..ef5e6499 100644 --- a/Sources/CLI/Commands/Run.swift +++ b/Sources/CLICommands/Run.swift @@ -1,5 +1,6 @@ import ArgumentParser import SystemPackage +import WAT import WasmKit import WasmKitWASI @@ -7,8 +8,8 @@ import WasmKitWASI import os.signpost #endif -struct Run: AsyncParsableCommand { - static let configuration = CommandConfiguration( +package struct Run: AsyncParsableCommand { + package static let configuration = CommandConfiguration( abstract: "Run a WebAssembly module", discussion: """ This command will parse a WebAssembly module and run it. @@ -128,7 +129,9 @@ struct Run: AsyncParsableCommand { ) var arguments: [String] = [] - func run() async throws { + package init() {} + + package func run() async throws { #if WasmDebuggingSupport if let debuggerPort { @@ -311,3 +314,20 @@ struct Run: AsyncParsableCommand { } } } + +/// Parses a `.wasm` or `.wat` module. +func parseWasm(filePath: FilePath) throws -> Module { + if filePath.extension == "wat", #available(macOS 11.0, iOS 14.0, macCatalyst 14.0, tvOS 14.0, visionOS 1.0, watchOS 7.0, *) { + let fileHandle = try FileDescriptor.open(filePath, .readOnly) + defer { try? fileHandle.close() } + + let size = try fileHandle.seek(offset: 0, from: .end) + + let wat = try String(unsafeUninitializedCapacity: Int(size)) { + try fileHandle.read(fromAbsoluteOffset: 0, into: .init($0)) + } + return try WasmKit.parseWasm(bytes: wat2wasm(wat)) + } else { + return try WasmKit.parseWasm(filePath: filePath) + } +} diff --git a/Sources/CLI/Commands/Wat2wasm.swift b/Sources/CLICommands/Wat2wasm.swift similarity index 95% rename from Sources/CLI/Commands/Wat2wasm.swift rename to Sources/CLICommands/Wat2wasm.swift index aa47735f..7f3f61e6 100644 --- a/Sources/CLI/Commands/Wat2wasm.swift +++ b/Sources/CLICommands/Wat2wasm.swift @@ -3,8 +3,8 @@ import SystemPackage import WAT import WasmKit -struct Wat2wasm: ParsableCommand { - static let configuration = CommandConfiguration( +package struct Wat2wasm: ParsableCommand { + package static let configuration = CommandConfiguration( abstract: "Assemble WebAssembly text into a WebAssembly binary", discussion: """ Parse a file in WebAssembly Text Format (`.wat`), \ @@ -58,7 +58,9 @@ struct Wat2wasm: ParsableCommand { ) var output: String? - func run() throws { + package init() {} + + package func run() throws { let filePath = FilePath(path) guard filePath.extension == "wat" else { throw Error.unknownFileExtension(filePath.extension) } let fileHandle = try FileDescriptor.open(filePath, .readOnly) diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index 9197f75d..9c09e136 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(WAT) if(WASMKIT_BUILD_CLI) add_subdirectory(CLI) + add_subdirectory(CLICommands) endif() if(WASMKIT_BUILD_LLVM_BACKEND) diff --git a/Sources/LLVMBackendCLI/CMakeLists.txt b/Sources/LLVMBackendCLI/CMakeLists.txt index 9777749b..4eac1a1f 100644 --- a/Sources/LLVMBackendCLI/CMakeLists.txt +++ b/Sources/LLVMBackendCLI/CMakeLists.txt @@ -23,12 +23,13 @@ if(NOT ArgumentParser_FOUND) FetchContent_MakeAvailable(ArgumentParser) endif() -add_dependencies(wasmkit-llvm ArgumentParser LLVMBackend) +add_dependencies(wasmkit-llvm ArgumentParser CLICommands LLVMBackend) target_link_libraries( wasmkit-llvm ArgumentParser + CLICommands LLVMBackend ) From 5efa2817ded0867fb438814d25c0ed1065bd4181 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 15:10:09 +0000 Subject: [PATCH 23/51] Fix SwiftPM build --- Package.swift | 8 ++++++++ Package@swift-6.1.swift | 13 +++++++++---- Sources/CLI/CMakeLists.txt | 4 ++++ Sources/{CLI => CLICommands}/DebuggerServer.swift | 0 4 files changed, 21 insertions(+), 4 deletions(-) rename Sources/{CLI => CLICommands}/DebuggerServer.swift (100%) diff --git a/Package.swift b/Package.swift index aa82983a..e9a39724 100644 --- a/Package.swift +++ b/Package.swift @@ -22,6 +22,14 @@ let package = Package( targets: [ .executableTarget( name: "CLI", + dependencies: [ + "CLICommands", + ] + exclude: ["CMakeLists.txt"] + ), + + .target( + name: "CLICommands", dependencies: [ "WAT", "WasmKit", diff --git a/Package@swift-6.1.swift b/Package@swift-6.1.swift index 22925888..9f9e556b 100644 --- a/Package@swift-6.1.swift +++ b/Package@swift-6.1.swift @@ -6,8 +6,8 @@ import class Foundation.ProcessInfo let DarwinPlatforms: [Platform] = [.macOS, .iOS, .watchOS, .tvOS, .visionOS] -let cliTarget = Target.executableTarget( - name: "CLI", +let cliCommandsTarget = Target.target( + name: "CLICommands", dependencies: [ "WAT", "WasmKit", @@ -36,7 +36,12 @@ let package = Package( "WasmDebuggingSupport", ], targets: [ - cliTarget, + cliCommandsTarget, + .executableTarget( + name: "CLI", + dependencies: ["CLICommands"], + exclude: ["CMakeLists.txt"] + ), .target( name: "WasmKit", dependencies: [ @@ -193,7 +198,7 @@ if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil { ), ]) - cliTarget.dependencies.append(contentsOf: [ + cliCommandsTarget.dependencies.append(contentsOf: [ .product(name: "Logging", package: "swift-log", condition: .when(traits: ["WasmDebuggingSupport"])), .product(name: "NIOCore", package: "swift-nio", condition: .when(traits: ["WasmDebuggingSupport"])), .product(name: "NIOPosix", package: "swift-nio", condition: .when(traits: ["WasmDebuggingSupport"])), diff --git a/Sources/CLI/CMakeLists.txt b/Sources/CLI/CMakeLists.txt index 74551c61..5b473505 100644 --- a/Sources/CLI/CMakeLists.txt +++ b/Sources/CLI/CMakeLists.txt @@ -2,6 +2,10 @@ add_executable(wasmkit CLI.swift ) +target_compile_options(wasmkit PRIVATE + -package-name WasmKitPackage +) + target_link_wasmkit_libraries(wasmkit PUBLIC CLICommands) diff --git a/Sources/CLI/DebuggerServer.swift b/Sources/CLICommands/DebuggerServer.swift similarity index 100% rename from Sources/CLI/DebuggerServer.swift rename to Sources/CLICommands/DebuggerServer.swift From 13b2df6919dcccb0a00772e248f7e685f5f03ea8 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 15:38:17 +0000 Subject: [PATCH 24/51] Fix `libswiftCompatibilitySpan.dylib` path on macOS --- Sources/LLVMBackendCLI/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/LLVMBackendCLI/CMakeLists.txt b/Sources/LLVMBackendCLI/CMakeLists.txt index 4eac1a1f..8cff0046 100644 --- a/Sources/LLVMBackendCLI/CMakeLists.txt +++ b/Sources/LLVMBackendCLI/CMakeLists.txt @@ -35,3 +35,10 @@ target_link_libraries( install(TARGETS wasmkit-llvm RUNTIME DESTINATION bin) + +if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + add_custom_command(TARGET wasmkit-llvm + POST_BUILD COMMAND + ${CMAKE_INSTALL_NAME_TOOL} -change "@rpath/libswiftCompatibilitySpan.dylib" "/Library/Developer/CommandLineTools/usr/lib/swift-6.2/macosx/libswiftCompatibilitySpan.dylib" + $) +endif() From ce9600c0f45d759e76bf2f4538bbfdcb4da540c1 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 15:38:33 +0000 Subject: [PATCH 25/51] Fix `RigidArray` OOB in `CodegenContext` --- Sources/LLVMBackend/CodegenContext.swift | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Sources/LLVMBackend/CodegenContext.swift b/Sources/LLVMBackend/CodegenContext.swift index 5c0ff2cd..ea813ecf 100644 --- a/Sources/LLVMBackend/CodegenContext.swift +++ b/Sources/LLVMBackend/CodegenContext.swift @@ -79,13 +79,14 @@ package struct CodegenContext: ~Copyable { // This will forward-declare all `llvm::Function` instances so that `call` // LLVM IR instructions have these instances to refer to and are valid. let name = "\(i)" - try functionVisitors[i] = .init( - name: name, - type: type, - locals: type.parameters + f.locals, - code: f, - ir: self.ir, - ) + try functionVisitors.append( + .init( + name: name, + type: type, + locals: type.parameters + f.locals, + code: f, + ir: self.ir, + )) functionNames.append(name) } From 61454ea706e925b6b1705b8cb26c0e18d5a4fe91 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 15:52:33 +0000 Subject: [PATCH 26/51] Fix missing comma in `Package.swift` --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index e9a39724..1ccde2ec 100644 --- a/Package.swift +++ b/Package.swift @@ -24,7 +24,7 @@ let package = Package( name: "CLI", dependencies: [ "CLICommands", - ] + ], exclude: ["CMakeLists.txt"] ), From 9c40c5da0a0e315e126a435d18c94f7400125731 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 15:52:47 +0000 Subject: [PATCH 27/51] Fix formatting --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 1ccde2ec..09b47cb4 100644 --- a/Package.swift +++ b/Package.swift @@ -23,7 +23,7 @@ let package = Package( .executableTarget( name: "CLI", dependencies: [ - "CLICommands", + "CLICommands" ], exclude: ["CMakeLists.txt"] ), From c88f97be11dafef5f3bfc04ccc2b4cf426c74082 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 16:28:28 +0000 Subject: [PATCH 28/51] Enable a simple smoke test setup for `factorial.wat` --- .github/workflows/main.yml | 5 ++- Sources/CLICommands/Run.swift | 24 +++++++++++++++ Sources/LLVMBackend/IRFunctionVisitor.swift | 31 +++++++++++++++++-- Sources/LLVMBackend/Loader.swift | 28 +++++++++++++++++ Sources/LLVMBackendCLI/Entrypoint.swift | 34 ++++++++++++++++++--- Sources/LLVMInterop/IRContext.cpp | 2 -- Sources/LLVMInterop/include/IRType.h | 8 +++++ Sources/LLVMInterop/include/IRValue.h | 8 +++++ 8 files changed, 129 insertions(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a0d532a6..5b65da1a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -347,7 +347,10 @@ jobs: run: | LLVM_DIR="$GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build/lib/cmake/llvm/" cmake -DWASMKIT_BUILD_LLVM_BACKEND=ON -DWASMKIT_LLVM_BACKEND_TARGET=${{ matrix.llvm-target }} -DWASMKIT_BUILD_CLI=ON -G Ninja -B ./build cmake --build ./build - - run: ./build/bin/wasmkit-llvm --help + - name: Run a smoke test + run: | + ./build/bin/wasmkit-llvm wat2wasm Examples/wasm/factorial.wat + ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm 0 i64:5 build-wasi: runs-on: ubuntu-24.04 diff --git a/Sources/CLICommands/Run.swift b/Sources/CLICommands/Run.swift index ef5e6499..579f1fcb 100644 --- a/Sources/CLICommands/Run.swift +++ b/Sources/CLICommands/Run.swift @@ -331,3 +331,27 @@ func parseWasm(filePath: FilePath) throws -> Module { return try WasmKit.parseWasm(filePath: filePath) } } + +extension Run { + package static func parseInvocation(arguments: [String]) -> (functionName: String?, parameters: [Value]) { + let functionName = arguments.first + let arguments = arguments.dropFirst() + + var parameters: [Value] = [] + for argument in arguments { + let parameter: Value + let type = argument.prefix { $0 != ":" } + let value = argument.drop { $0 != ":" }.dropFirst() + switch type { + case "i32": parameter = Value(signed: Int32(value)!) + case "i64": parameter = Value(signed: Int64(value)!) + case "f32": parameter = .f32(Float32(value)!.bitPattern) + case "f64": parameter = .f64(Float64(value)!.bitPattern) + default: fatalError("unknown type") + } + parameters.append(parameter) + } + + return (functionName, parameters) + } +} diff --git a/Sources/LLVMBackend/IRFunctionVisitor.swift b/Sources/LLVMBackend/IRFunctionVisitor.swift index 0f5a788a..847044d4 100644 --- a/Sources/LLVMBackend/IRFunctionVisitor.swift +++ b/Sources/LLVMBackend/IRFunctionVisitor.swift @@ -336,11 +336,24 @@ struct IRFunctionVisitor: InstructionVisitor, ~Copyable { mutating func visitStore(_ store: Instruction.Store, memarg: MemArg) throws { fatalError() } mutating func visitMemorySize(memory: UInt32) throws { fatalError() } mutating func visitMemoryGrow(memory: UInt32) throws { fatalError() } - mutating func visitI64Const(value: Int64) throws { fatalError() } + mutating func visitI64Const(value: Int64) throws { + self.push(self.ir.__i64ValueUnsafe(.init(bitPattern: value))) + } mutating func visitF32Const(value: IEEE754.Float32) throws { fatalError() } mutating func visitF64Const(value: IEEE754.Float64) throws { fatalError() } - mutating func visitI32Eqz() throws { fatalError() } - mutating func visitI64Eqz() throws { fatalError() } + + mutating func visitI32Eqz() throws { + let stackTop = self.pop() + let value = self.ir.__i32ValueUnsafe(0) + self.push(self.ir.__iEqUnsafe(stackTop, value)) + } + + mutating func visitI64Eqz() throws { + let stackTop = self.pop() + let value = self.ir.__i64ValueUnsafe(0) + self.push(self.ir.__iEqUnsafe(stackTop, value)) + } + mutating func visitUnary(_ unary: Instruction.Unary) throws { fatalError() } mutating func visitConversion(_ conversion: Instruction.Conversion) throws { fatalError() } mutating func visitMemoryInit(dataIndex: UInt32) throws { fatalError() } @@ -403,3 +416,15 @@ extension IRFunctionType: @retroactive CustomStringConvertible { .init(self.print()) } } + +extension IRType: @retroactive CustomStringConvertible { + public var description: String { + .init(self.print()) + } +} + +extension IRValue: @retroactive CustomStringConvertible { + public var description: String { + .init(self.print()) + } +} diff --git a/Sources/LLVMBackend/Loader.swift b/Sources/LLVMBackend/Loader.swift index 6fac0c11..fc209be4 100644 --- a/Sources/LLVMBackend/Loader.swift +++ b/Sources/LLVMBackend/Loader.swift @@ -14,6 +14,34 @@ package protocol ImportedFunctionArguments { func apply(symbol: UnsafeMutableRawPointer) -> ResultType } +package struct U64Args1Result1: ImportedFunctionArguments { + typealias CType = @convention(c) (UInt64) -> UInt64 + + private let args: UInt64 + + package init(_ first: UInt64) { + self.args = first + } + + package func apply(symbol: UnsafeMutableRawPointer) -> UInt64 { + unsafeBitCast(symbol, to: CType.self)(self.args) + } +} + +package struct U64Args2Result1: ImportedFunctionArguments { + typealias CType = @convention(c) (UInt64, UInt64) -> UInt64 + + private let args: (UInt64, UInt64) + + package init(_ first: UInt64, _ second: UInt64) { + self.args = (first, second) + } + + package func apply(symbol: UnsafeMutableRawPointer) -> UInt64 { + unsafeBitCast(symbol, to: CType.self)(self.args.0, self.args.1) + } +} + package struct U32Args2Result1: ImportedFunctionArguments { typealias CType = @convention(c) (UInt32, UInt32) -> UInt32 diff --git a/Sources/LLVMBackendCLI/Entrypoint.swift b/Sources/LLVMBackendCLI/Entrypoint.swift index 182495ee..e11b77cb 100644 --- a/Sources/LLVMBackendCLI/Entrypoint.swift +++ b/Sources/LLVMBackendCLI/Entrypoint.swift @@ -1,16 +1,37 @@ import ArgumentParser +import CLICommands import Foundation import LLVMBackend import SystemPackage @main struct Entrypoint: AsyncParsableCommand { + static let configuration = CommandConfiguration( + commandName: "wasmkit", + abstract: "WasmKit LLVM Backend", + subcommands: [ + Run.self, + Wat2wasm.self, + ] + ) +} + +struct Run: AsyncParsableCommand { @Argument(help: "Path to a `.wasm` file to operate on.") var path: String @Flag(name: [.long, .short]) var verbose: Bool = false + @Argument( + parsing: .captureForPassthrough, + help: ArgumentHelp( + "Name of an exported function to call with space-separated function arguments encoded as `:`, e.g. `i32:42`", + valueName: "arguments" + ) + ) + var arguments: [String] = [] + func run() async throws { let wasmPath = if FilePath(self.path).isAbsolute { @@ -19,19 +40,22 @@ struct Entrypoint: AsyncParsableCommand { FilePath(FileManager.default.currentDirectoryPath).appending(path) } - print("wasmPath is \(wasmPath)") var context = CodegenContext(isVerbose: verbose) let objectFilePath = try context.emitObjectFile(wasmPath: wasmPath) let libraryFilePath = try await Linker.link(objectFilePath: objectFilePath) - print("Linked library is at \(libraryFilePath.string)") + let (functionName, functionArguments) = CLICommands.Run.parseInvocation(arguments: self.arguments) + + guard let functionName, functionArguments.count == 1, case .i64(let functionArgument) = functionArguments.first else { + fatalError("Only single-parameter i64 entrypoint functions are currently supported. Arguments passed: \(functionArguments)") + } let result = try Loader(memory: nil).load( library: libraryFilePath, - entrypointSymbol: "1", - arguments: U32Args2Result1(42, 24) + entrypointSymbol: functionName, + arguments: U64Args1Result1(functionArgument) ) - print("invocation result: \(result)") + print(result) } } diff --git a/Sources/LLVMInterop/IRContext.cpp b/Sources/LLVMInterop/IRContext.cpp index b34d1ac6..803d5daf 100644 --- a/Sources/LLVMInterop/IRContext.cpp +++ b/Sources/LLVMInterop/IRContext.cpp @@ -93,8 +93,6 @@ bool IRContext::emitObjectFile(StringRef path) const { pass.run(*_module); dest.flush(); - outs() << "Wrote " << path << "\n"; - return true; } diff --git a/Sources/LLVMInterop/include/IRType.h b/Sources/LLVMInterop/include/IRType.h index 90a6e259..6fc178a5 100644 --- a/Sources/LLVMInterop/include/IRType.h +++ b/Sources/LLVMInterop/include/IRType.h @@ -9,6 +9,14 @@ class IRType { public: Type *_t; IRType(Type *t) : _t(t) {} + + std::string print() const { + string string = ""; + raw_string_ostream stream(string); + + this->_t->print(stream); + return string; + } }; using IRTypeVector = std::vector; diff --git a/Sources/LLVMInterop/include/IRValue.h b/Sources/LLVMInterop/include/IRValue.h index 84039024..4a448d80 100644 --- a/Sources/LLVMInterop/include/IRValue.h +++ b/Sources/LLVMInterop/include/IRValue.h @@ -13,4 +13,12 @@ class IRValue { IRValue(Value *v) : _v(v) {} IRValue(IRPHINode phi) : _v(phi._n) {} + + std::string print() const { + std::string string = ""; + raw_string_ostream stream(string); + + this->_v->print(stream); + return string; + } }; From 539811a6998e1376c91958bc32af384b26d414cb Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 16:29:01 +0000 Subject: [PATCH 29/51] Fix formatting --- Sources/LLVMBackend/IRFunctionVisitor.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/LLVMBackend/IRFunctionVisitor.swift b/Sources/LLVMBackend/IRFunctionVisitor.swift index 847044d4..d01d83e3 100644 --- a/Sources/LLVMBackend/IRFunctionVisitor.swift +++ b/Sources/LLVMBackend/IRFunctionVisitor.swift @@ -343,15 +343,15 @@ struct IRFunctionVisitor: InstructionVisitor, ~Copyable { mutating func visitF64Const(value: IEEE754.Float64) throws { fatalError() } mutating func visitI32Eqz() throws { - let stackTop = self.pop() - let value = self.ir.__i32ValueUnsafe(0) - self.push(self.ir.__iEqUnsafe(stackTop, value)) + let stackTop = self.pop() + let value = self.ir.__i32ValueUnsafe(0) + self.push(self.ir.__iEqUnsafe(stackTop, value)) } mutating func visitI64Eqz() throws { - let stackTop = self.pop() - let value = self.ir.__i64ValueUnsafe(0) - self.push(self.ir.__iEqUnsafe(stackTop, value)) + let stackTop = self.pop() + let value = self.ir.__i64ValueUnsafe(0) + self.push(self.ir.__iEqUnsafe(stackTop, value)) } mutating func visitUnary(_ unary: Instruction.Unary) throws { fatalError() } From 99dd706666b183047ebfdb16e676429c6e48b78a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 16:54:32 +0000 Subject: [PATCH 30/51] Add support for Linux in `LLVMBackend/Linker.swift` --- Sources/LLVMBackend/Linker.swift | 43 +++++++++++++++++++------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/Sources/LLVMBackend/Linker.swift b/Sources/LLVMBackend/Linker.swift index 65e35256..9b7a0240 100644 --- a/Sources/LLVMBackend/Linker.swift +++ b/Sources/LLVMBackend/Linker.swift @@ -7,26 +7,35 @@ package enum Linker { } package static func link(objectFilePath: FilePath) async throws -> FilePath { + var dylibPath = objectFilePath + let arguments: Arguments #if os(macOS) - var dylibPath = objectFilePath dylibPath.extension = "dylib" - let result = try await run( - .name("ld"), - arguments: [ - "-dylib", objectFilePath.string, - "-lSystem", "-L", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib", - "-o", dylibPath.string, - ], - output: .standardError - ) - - guard result.terminationStatus.isSuccess else { - throw Error.unexpectedTerminationStatus(result.terminationStatus) - } - - return dylibPath + arguments = [ + "-dylib", objectFilePath.string, + "-lSystem", "-L", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib", + "-o", dylibPath.string, + ] + #elseif os(Linux) + dylibPath.extension = "so" + arguments = [ + "-shared", objectFilePath.string, + "-o", dylibPath.string, + ] #else - fatalError("Linking native binaries is currently only supported on macOS") + #error("Linking native binaries is currently only supported on macOS and Linux") #endif + + let result = try await run( + .name("ld"), + arguments: arguments, + output: .standardError + ) + + guard result.terminationStatus.isSuccess else { + throw Error.unexpectedTerminationStatus(result.terminationStatus) + } + + return dylibPath } } From 4bbc70638da5404a89dd3caa8735d51cf2b14142 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 17:18:15 +0000 Subject: [PATCH 31/51] Add macOS 15 builds for LLVM configuration --- .github/workflows/main.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5b65da1a..d5a797fc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -313,10 +313,12 @@ jobs: include: - os: ubuntu-24.04 llvm-target: X86 - cmake-arch: x86_64 - os: ubuntu-24.04-arm llvm-target: AArch64 - cmake-arch: aarch64 + - os: macos-15 + llvm-target: X86 + - os: macos-15-arm64 + llvm-target: AArch64 runs-on: ${{ matrix.os }} container: @@ -326,9 +328,18 @@ jobs: - name: Install dependencies run: apt-get update && apt-get install -y ninja-build python3 - name: Install CMake + if: runner.os == 'Linux' run: | apt-get install -y curl - curl -L https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-${{ matrix.cmake-arch }}.tar.gz | tar xz --strip-component 1 -C /usr/local/ + if [ "${{ matrix.llvm-target }}" == "AArch64" ]; then + export CMAKE_ARCH=aarch64 + elif [ "${{ matrix.llvm-target }}" == "X86" ]; then + export CMAKE_ARCH=x86_64 + else + exit 1 + endif + + curl -L "https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-${CMAKE_ARCH}.tar.gz" | tar xz --strip-component 1 -C /usr/local/ - name: Cache LLVM id: cache-llvm uses: actions/cache@v4 From 066478439a0e930e58cb3a95fcb7ea361ebbe70a Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 17:21:36 +0000 Subject: [PATCH 32/51] Separate Ubuntu and macOS build jobs for LLVM --- .github/workflows/main.yml | 43 +++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d5a797fc..d4f925b1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -307,7 +307,7 @@ jobs: - run: cmake --build ./build - run: ./build/bin/wasmkit --version - build-llvm: + build-llvm-ubuntu: strategy: matrix: include: @@ -315,11 +315,6 @@ jobs: llvm-target: X86 - os: ubuntu-24.04-arm llvm-target: AArch64 - - os: macos-15 - llvm-target: X86 - - os: macos-15-arm64 - llvm-target: AArch64 - runs-on: ${{ matrix.os }} container: image: swift:6.2-noble @@ -328,7 +323,6 @@ jobs: - name: Install dependencies run: apt-get update && apt-get install -y ninja-build python3 - name: Install CMake - if: runner.os == 'Linux' run: | apt-get install -y curl if [ "${{ matrix.llvm-target }}" == "AArch64" ]; then @@ -363,6 +357,41 @@ jobs: ./build/bin/wasmkit-llvm wat2wasm Examples/wasm/factorial.wat ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm 0 i64:5 + build-llvm-macos: + strategy: + matrix: + include: + - os: macos-15 + llvm-target: X86 + - os: macos-15-arm64 + llvm-target: AArch64 + + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Cache LLVM + id: cache-llvm + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}/Vendor/llvm-project + # IMPORTANT: Update the key when updating LLVM tag below in the build step. + key: llvm-${{ matrix.os }}-${{ matrix.llvm-target }}-swift-main-2026-01-04 + - name: Build LLVM + if: steps.cache-llvm.outputs.cache-hit != 'true' + run: | + mkdir -p $GITHUB_WORKSPACE/Vendor/llvm-project + curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-DEVELOPMENT-SNAPSHOT-2026-01-04-a.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/Vendor/llvm-project + cmake -DLLVM_TARGETS_TO_BUILD=${{ matrix.llvm-target }} -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -S $GITHUB_WORKSPACE/Vendor/llvm-project/llvm -B $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build + cmake --build $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build + - name: Build WasmKit with LLVM + run: | + LLVM_DIR="$GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build/lib/cmake/llvm/" cmake -DWASMKIT_BUILD_LLVM_BACKEND=ON -DWASMKIT_LLVM_BACKEND_TARGET=${{ matrix.llvm-target }} -DWASMKIT_BUILD_CLI=ON -G Ninja -B ./build + cmake --build ./build + - name: Run a smoke test + run: | + ./build/bin/wasmkit-llvm wat2wasm Examples/wasm/factorial.wat + ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm 0 i64:5 + build-wasi: runs-on: ubuntu-24.04 container: From ae444856ee914074a076f817f40d6350cfe03925 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 17:24:45 +0000 Subject: [PATCH 33/51] Shell uses `fi` instead of `endif` --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d4f925b1..121fa7aa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -331,7 +331,7 @@ jobs: export CMAKE_ARCH=x86_64 else exit 1 - endif + fi curl -L "https://github.com/Kitware/CMake/releases/download/v3.30.2/cmake-3.30.2-linux-${CMAKE_ARCH}.tar.gz" | tar xz --strip-component 1 -C /usr/local/ - name: Cache LLVM From 87a6f389552e0f72507763c56e2435faec9a6f52 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 17:32:19 +0000 Subject: [PATCH 34/51] Try bash-compatible if-else syntax --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 121fa7aa..a1aa40a3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -325,9 +325,9 @@ jobs: - name: Install CMake run: | apt-get install -y curl - if [ "${{ matrix.llvm-target }}" == "AArch64" ]; then + if [[ "${{ matrix.llvm-target }}" == "AArch64" ]]; then export CMAKE_ARCH=aarch64 - elif [ "${{ matrix.llvm-target }}" == "X86" ]; then + elif [[ "${{ matrix.llvm-target }}" == "X86" ]]; then export CMAKE_ARCH=x86_64 else exit 1 @@ -363,7 +363,7 @@ jobs: include: - os: macos-15 llvm-target: X86 - - os: macos-15-arm64 + - os: macos-15-large llvm-target: AArch64 runs-on: ${{ matrix.os }} From 376cb685080047dcf6756afe4ca515539cc6e278 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 17:44:56 +0000 Subject: [PATCH 35/51] Explicitly use bash for Ubuntu LLVM job --- .github/workflows/main.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a1aa40a3..de30b7f4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -318,6 +318,9 @@ jobs: runs-on: ${{ matrix.os }} container: image: swift:6.2-noble + defaults: + run: + shell: bash steps: - uses: actions/checkout@v4 - name: Install dependencies @@ -363,7 +366,7 @@ jobs: include: - os: macos-15 llvm-target: X86 - - os: macos-15-large + - os: macos-14 llvm-target: AArch64 runs-on: ${{ matrix.os }} From 0efa59627387b14f34a7dfedeff525c6daa880da Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 17:49:30 +0000 Subject: [PATCH 36/51] Remove unused files --- Sources/LLVMBackend/CMakeLists.txt | 2 -- Sources/LLVMBackend/LLInstance.swift | 36 ---------------------------- Sources/LLVMBackend/LLStore.swift | 11 --------- 3 files changed, 49 deletions(-) delete mode 100644 Sources/LLVMBackend/LLInstance.swift delete mode 100644 Sources/LLVMBackend/LLStore.swift diff --git a/Sources/LLVMBackend/CMakeLists.txt b/Sources/LLVMBackend/CMakeLists.txt index b2e32b54..9c72c7de 100644 --- a/Sources/LLVMBackend/CMakeLists.txt +++ b/Sources/LLVMBackend/CMakeLists.txt @@ -4,8 +4,6 @@ add_library( CodegenContext.swift IRContext+codegen.swift IRFunctionVisitor.swift - LLInstance.swift - LLStore.swift Linker.swift Loader.swift Wasm32Memory.swift diff --git a/Sources/LLVMBackend/LLInstance.swift b/Sources/LLVMBackend/LLInstance.swift deleted file mode 100644 index 414f1545..00000000 --- a/Sources/LLVMBackend/LLInstance.swift +++ /dev/null @@ -1,36 +0,0 @@ -import WasmKit - -package final class LLInstance { - package init() {} - - package let exports = LLExports() - - package func export(_ name: String) -> LLExternalValue { - fatalError() - } - - package func exportedFunction(name: String) -> LLFunction? { - fatalError() - } -} - -package struct LLExports: ~Copyable { -} - -package struct LLFunction { - package func invoke(_ args: [Value]) -> [Value] { - fatalError() - } -} -package struct LLGlobal { - package var value: Value { fatalError() } -} -package struct LLMemory {} -package struct LLTable {} - -package enum LLExternalValue { - case function(LLFunction) - case global(LLGlobal) - case memory(LLMemory) - case table(LLTable) -} diff --git a/Sources/LLVMBackend/LLStore.swift b/Sources/LLVMBackend/LLStore.swift deleted file mode 100644 index a0afc108..00000000 --- a/Sources/LLVMBackend/LLStore.swift +++ /dev/null @@ -1,11 +0,0 @@ -import WasmKit - -package struct LLStore: ~Copyable { - package init() {} -} - -extension Module { - package func instantiate(llStore: borrowing LLStore, imports: Imports = Imports()) throws -> LLInstance { - LLInstance() - } -} From 8a59391d4c77daa323e16f94ab0d975274ec0879 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 19:05:54 +0000 Subject: [PATCH 37/51] Lower requirement in top-level `CMakeLists.txt` to Swift 6.1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2cbab3c..56643b1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(WasmKit LANGUAGES C CXX Swift) set(SWIFT_VERSION 6) set(CMAKE_Swift_LANGUAGE_VERSION ${SWIFT_VERSION}) -set(min_supported_swift_version 6.2) +set(min_supported_swift_version 6.1) if(CMAKE_Swift_COMPILER_VERSION VERSION_LESS "${min_supported_swift_version}") message( FATAL_ERROR From 229138b81c44c4b1adba0e4206fe8c5bb2e5ec90 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 19:06:39 +0000 Subject: [PATCH 38/51] Remove macOS 14 LLVM target from workflow --- .github/workflows/main.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index de30b7f4..04b9f680 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -365,8 +365,6 @@ jobs: matrix: include: - os: macos-15 - llvm-target: X86 - - os: macos-14 llvm-target: AArch64 runs-on: ${{ matrix.os }} From b4fe009d0825803b1e0e0020e3f6cfe095ff980c Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 19:52:09 +0000 Subject: [PATCH 39/51] `main.yml` workflow: diagnose macOS CMake configuration failure --- .github/workflows/main.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 04b9f680..f0e7cc29 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -386,12 +386,13 @@ jobs: cmake --build $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build - name: Build WasmKit with LLVM run: | - LLVM_DIR="$GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build/lib/cmake/llvm/" cmake -DWASMKIT_BUILD_LLVM_BACKEND=ON -DWASMKIT_LLVM_BACKEND_TARGET=${{ matrix.llvm-target }} -DWASMKIT_BUILD_CLI=ON -G Ninja -B ./build - cmake --build ./build - - name: Run a smoke test - run: | - ./build/bin/wasmkit-llvm wat2wasm Examples/wasm/factorial.wat - ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm 0 i64:5 + cmake --version + # LLVM_DIR="$GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build/lib/cmake/llvm/" cmake -DWASMKIT_BUILD_LLVM_BACKEND=ON -DWASMKIT_LLVM_BACKEND_TARGET=${{ matrix.llvm-target }} -DWASMKIT_BUILD_CLI=ON -G Ninja -B ./build + # cmake --build ./build + # - name: Run a smoke test + # run: | + # ./build/bin/wasmkit-llvm wat2wasm Examples/wasm/factorial.wat + # ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm 0 i64:5 build-wasi: runs-on: ubuntu-24.04 From 884bae996671a3a1aa25739444727e2995a05d94 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 19:56:49 +0000 Subject: [PATCH 40/51] `main.yml` workflow: use Xcode 26.1 to get `-print-target-info` --- .github/workflows/main.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f0e7cc29..36c197b3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -380,19 +380,19 @@ jobs: - name: Build LLVM if: steps.cache-llvm.outputs.cache-hit != 'true' run: | + sudo xcode-select -s /Applications/Xcode_26.1.app mkdir -p $GITHUB_WORKSPACE/Vendor/llvm-project curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-DEVELOPMENT-SNAPSHOT-2026-01-04-a.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/Vendor/llvm-project cmake -DLLVM_TARGETS_TO_BUILD=${{ matrix.llvm-target }} -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -S $GITHUB_WORKSPACE/Vendor/llvm-project/llvm -B $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build cmake --build $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build - name: Build WasmKit with LLVM run: | - cmake --version - # LLVM_DIR="$GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build/lib/cmake/llvm/" cmake -DWASMKIT_BUILD_LLVM_BACKEND=ON -DWASMKIT_LLVM_BACKEND_TARGET=${{ matrix.llvm-target }} -DWASMKIT_BUILD_CLI=ON -G Ninja -B ./build - # cmake --build ./build - # - name: Run a smoke test - # run: | - # ./build/bin/wasmkit-llvm wat2wasm Examples/wasm/factorial.wat - # ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm 0 i64:5 + LLVM_DIR="$GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build/lib/cmake/llvm/" cmake -DWASMKIT_BUILD_LLVM_BACKEND=ON -DWASMKIT_LLVM_BACKEND_TARGET=${{ matrix.llvm-target }} -DWASMKIT_BUILD_CLI=ON -G Ninja -B ./build + cmake --build ./build + - name: Run a smoke test + run: | + ./build/bin/wasmkit-llvm wat2wasm Examples/wasm/factorial.wat + ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm 0 i64:5 build-wasi: runs-on: ubuntu-24.04 From 9f4a9c5d5ce08eccaad88dbe706fd0814ea7cc7e Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 20:59:57 +0000 Subject: [PATCH 41/51] `main.yml` workflow: bump macOS to 26 for LLVM build --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 36c197b3..43bf1085 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -364,7 +364,7 @@ jobs: strategy: matrix: include: - - os: macos-15 + - os: macos-26 llvm-target: AArch64 runs-on: ${{ matrix.os }} @@ -380,7 +380,7 @@ jobs: - name: Build LLVM if: steps.cache-llvm.outputs.cache-hit != 'true' run: | - sudo xcode-select -s /Applications/Xcode_26.1.app + sudo xcode-select -s /Applications/Xcode_26.2.app mkdir -p $GITHUB_WORKSPACE/Vendor/llvm-project curl -L https://github.com/swiftlang/llvm-project/archive/refs/tags/swift-DEVELOPMENT-SNAPSHOT-2026-01-04-a.tar.gz | tar xz --strip-component 1 -C $GITHUB_WORKSPACE/Vendor/llvm-project cmake -DLLVM_TARGETS_TO_BUILD=${{ matrix.llvm-target }} -DLLVM_INCLUDE_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -G Ninja -S $GITHUB_WORKSPACE/Vendor/llvm-project/llvm -B $GITHUB_WORKSPACE/Vendor/llvm-project/llvm/build From f263c7091406e3a33923a1284bb8f211bca88855 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 6 Jan 2026 21:55:07 +0000 Subject: [PATCH 42/51] Raise CMake `min_supported_swift_version` back to 6.2 `swift-subprocess` requires `libswiftCompatibilitySpan.dylib` to be available, and that's only present with Swift 6.2 compilers on macOS. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 56643b1c..b2cbab3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(WasmKit LANGUAGES C CXX Swift) set(SWIFT_VERSION 6) set(CMAKE_Swift_LANGUAGE_VERSION ${SWIFT_VERSION}) -set(min_supported_swift_version 6.1) +set(min_supported_swift_version 6.2) if(CMAKE_Swift_COMPILER_VERSION VERSION_LESS "${min_supported_swift_version}") message( FATAL_ERROR From da4dbea57b3b7caa7d53c6920d9c37ab657586c4 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 7 Jan 2026 10:39:23 +0000 Subject: [PATCH 43/51] Make CLI commands reusable with new `CLICommands` module Prerequisite for https://github.com/swiftwasm/WasmKit/pull/248 to make existing CLI commands reused in both `wasmkit` and `wasmkit-llvm` executables. --- Package.swift | 8 ++ Package@swift-6.1.swift | 13 +- Sources/CLI/CLI.swift | 1 + Sources/CLI/CMakeLists.txt | 15 ++- Sources/CLI/Commands/Parse.swift | 20 --- Sources/CLICommands/CMakeLists.txt | 21 +++ Sources/CLICommands/DebuggerServer.swift | 120 ++++++++++++++++++ .../Commands => CLICommands}/Explore.swift | 8 +- .../{CLI/Commands => CLICommands}/Run.swift | 50 +++++++- .../Commands => CLICommands}/Wat2wasm.swift | 8 +- Sources/CMakeLists.txt | 1 + 11 files changed, 225 insertions(+), 40 deletions(-) delete mode 100644 Sources/CLI/Commands/Parse.swift create mode 100644 Sources/CLICommands/CMakeLists.txt create mode 100644 Sources/CLICommands/DebuggerServer.swift rename Sources/{CLI/Commands => CLICommands}/Explore.swift (91%) rename Sources/{CLI/Commands => CLICommands}/Run.swift (85%) rename Sources/{CLI/Commands => CLICommands}/Wat2wasm.swift (95%) diff --git a/Package.swift b/Package.swift index aa82983a..09b47cb4 100644 --- a/Package.swift +++ b/Package.swift @@ -22,6 +22,14 @@ let package = Package( targets: [ .executableTarget( name: "CLI", + dependencies: [ + "CLICommands" + ], + exclude: ["CMakeLists.txt"] + ), + + .target( + name: "CLICommands", dependencies: [ "WAT", "WasmKit", diff --git a/Package@swift-6.1.swift b/Package@swift-6.1.swift index 22925888..9f9e556b 100644 --- a/Package@swift-6.1.swift +++ b/Package@swift-6.1.swift @@ -6,8 +6,8 @@ import class Foundation.ProcessInfo let DarwinPlatforms: [Platform] = [.macOS, .iOS, .watchOS, .tvOS, .visionOS] -let cliTarget = Target.executableTarget( - name: "CLI", +let cliCommandsTarget = Target.target( + name: "CLICommands", dependencies: [ "WAT", "WasmKit", @@ -36,7 +36,12 @@ let package = Package( "WasmDebuggingSupport", ], targets: [ - cliTarget, + cliCommandsTarget, + .executableTarget( + name: "CLI", + dependencies: ["CLICommands"], + exclude: ["CMakeLists.txt"] + ), .target( name: "WasmKit", dependencies: [ @@ -193,7 +198,7 @@ if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil { ), ]) - cliTarget.dependencies.append(contentsOf: [ + cliCommandsTarget.dependencies.append(contentsOf: [ .product(name: "Logging", package: "swift-log", condition: .when(traits: ["WasmDebuggingSupport"])), .product(name: "NIOCore", package: "swift-nio", condition: .when(traits: ["WasmDebuggingSupport"])), .product(name: "NIOPosix", package: "swift-nio", condition: .when(traits: ["WasmDebuggingSupport"])), diff --git a/Sources/CLI/CLI.swift b/Sources/CLI/CLI.swift index 14d53166..bf410ea6 100644 --- a/Sources/CLI/CLI.swift +++ b/Sources/CLI/CLI.swift @@ -1,4 +1,5 @@ import ArgumentParser +import CLICommands @main struct CLI: AsyncParsableCommand { diff --git a/Sources/CLI/CMakeLists.txt b/Sources/CLI/CMakeLists.txt index bba5cda1..5b473505 100644 --- a/Sources/CLI/CMakeLists.txt +++ b/Sources/CLI/CMakeLists.txt @@ -1,12 +1,13 @@ -add_executable(wasmkit-cli - Commands/Explore.swift - Commands/Run.swift - Commands/Wat2wasm.swift +add_executable(wasmkit CLI.swift ) -target_link_wasmkit_libraries(wasmkit-cli PUBLIC - ArgumentParser WAT WasmKitWASI) +target_compile_options(wasmkit PRIVATE + -package-name WasmKitPackage +) + +target_link_wasmkit_libraries(wasmkit PUBLIC + CLICommands) -install(TARGETS wasmkit-cli +install(TARGETS wasmkit RUNTIME DESTINATION bin) diff --git a/Sources/CLI/Commands/Parse.swift b/Sources/CLI/Commands/Parse.swift deleted file mode 100644 index 121edc72..00000000 --- a/Sources/CLI/Commands/Parse.swift +++ /dev/null @@ -1,20 +0,0 @@ -import SystemPackage -import WAT -import WasmKit - -/// Parses a `.wasm` or `.wat` module. -func parseWasm(filePath: FilePath) throws -> Module { - if filePath.extension == "wat", #available(macOS 11.0, iOS 14.0, macCatalyst 14.0, tvOS 14.0, visionOS 1.0, watchOS 7.0, *) { - let fileHandle = try FileDescriptor.open(filePath, .readOnly) - defer { try? fileHandle.close() } - - let size = try fileHandle.seek(offset: 0, from: .end) - - let wat = try String(unsafeUninitializedCapacity: Int(size)) { - try fileHandle.read(fromAbsoluteOffset: 0, into: .init($0)) - } - return try WasmKit.parseWasm(bytes: wat2wasm(wat)) - } else { - return try WasmKit.parseWasm(filePath: filePath) - } -} diff --git a/Sources/CLICommands/CMakeLists.txt b/Sources/CLICommands/CMakeLists.txt new file mode 100644 index 00000000..ec9324e7 --- /dev/null +++ b/Sources/CLICommands/CMakeLists.txt @@ -0,0 +1,21 @@ +if(WASMKIT_BUILD_CLI) + set(BUILD_TESTING OFF) # disable ArgumentParser tests + find_package(ArgumentParser CONFIG) + if(NOT ArgumentParser_FOUND) + message("-- Vending ArgumentParser") + FetchContent_Declare(ArgumentParser + GIT_REPOSITORY https://github.com/apple/swift-argument-parser + GIT_TAG 1.6.1 + ) + FetchContent_MakeAvailable(ArgumentParser) + endif() +endif() + +add_wasmkit_library(CLICommands + Explore.swift + Run.swift + Wat2wasm.swift +) + +target_link_wasmkit_libraries(CLICommands PUBLIC + ArgumentParser WAT WasmKitWASI) diff --git a/Sources/CLICommands/DebuggerServer.swift b/Sources/CLICommands/DebuggerServer.swift new file mode 100644 index 00000000..3f348bb2 --- /dev/null +++ b/Sources/CLICommands/DebuggerServer.swift @@ -0,0 +1,120 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftNIO open source project +// +// Copyright (c) 2017-2025 Apple Inc. and the SwiftNIO project authors +// Licensed under Apache License v2.0 +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftNIO project authors +// +// SPDX-License-Identifier: Apache-2.0 +// +//===----------------------------------------------------------------------===// + +#if WasmDebuggingSupport + + import GDBRemoteProtocol + import Logging + import NIOCore + import NIOPosix + import SystemPackage + import WasmKit + import WasmKitGDBHandler + + struct DebuggerServer { + var host = "127.0.0.1" + var port: Int + var logLevel = Logger.Level.info + let wasmModulePath: FilePath + let engineConfiguration: EngineConfiguration + + func run() async throws { + let logger = { + var result = Logger(label: "org.swiftwasm.WasmKit") + result.logLevel = self.logLevel + return result + }() + + try await MultiThreadedEventLoopGroup.withEventLoopGroup(numberOfThreads: System.coreCount) { group in + let bootstrap = ServerBootstrap(group: group) + // Specify backlog and enable SO_REUSEADDR for the server itself + .serverChannelOption(.backlog, value: 256) + .serverChannelOption(.socketOption(.so_reuseaddr), value: 1) + + // Set the handlers that are applied to the accepted child `Channel`s. + .childChannelInitializer { channel in + // Ensure we don't read faster then we can write by adding the BackPressureHandler into the pipeline. + channel.eventLoop.makeCompletedFuture { + try channel.pipeline.syncOperations.addHandler(BackPressureHandler()) + // make sure to instantiate your `ChannelHandlers` inside of + // the closure as it will be invoked once per connection. + try channel.pipeline.syncOperations.addHandlers([ + ByteToMessageHandler(GDBHostCommandDecoder(logger: logger)), + MessageToByteHandler(GDBTargetResponseEncoder(logger: logger)), + ]) + } + } + + // Enable SO_REUSEADDR for the accepted Channels + .childChannelOption(.socketOption(.so_reuseaddr), value: 1) + .childChannelOption(.maxMessagesPerRead, value: 16) + .childChannelOption(.recvAllocator, value: AdaptiveRecvByteBufferAllocator()) + + let serverChannel = try await bootstrap.bind(host: self.host, port: self.port) { childChannel in + childChannel.eventLoop.makeCompletedFuture { + try NIOAsyncChannel, GDBTargetResponse>( + wrappingChannelSynchronously: childChannel + ) + } + } + /* the server will now be accepting connections */ + logger.info("Debugger server listening on port \(port)") + + let debuggerHandler = try await WasmKitGDBHandler( + moduleFilePath: self.wasmModulePath, + engineConfiguration: self.engineConfiguration, + logger: logger, + allocator: serverChannel.channel.allocator + ) + + // Discarding task group was designed for persistent server purposes, where a single failing request + // isn't taking down the entire server. In our case we need to be able to shut down the server on + // debugger client's request, so let's wrap the discarding task group with a throwing task group + // for cancellation. + await withThrowingTaskGroup { cancellableGroup in + // Use `AsyncStream` for sending a signal out of the discarding group. + let (shutDownStream, shutDownContinuation) = AsyncStream<()>.makeStream() + + cancellableGroup.addTask { + try await withThrowingDiscardingTaskGroup { discardingGroup in + try await serverChannel.executeThenClose { serverChannelInbound in + for try await connectionChannel in serverChannelInbound { + discardingGroup.addTask { + do { + try await connectionChannel.executeThenClose { connectionChannelInbound, connectionChannelOutbound in + for try await inboundData in connectionChannelInbound { + try await connectionChannelOutbound.write(debuggerHandler.handle(command: inboundData.payload)) + } + } + } catch WasmKitGDBHandler.Error.killRequestReceived { + logger.info("Debugger shut down request received") + shutDownContinuation.yield() + } catch { + logger.error("Error in GDB remote protocol connection channel", metadata: ["error": "\(error)"]) + } + } + } + } + } + } + + // The stream isn't really sending data, just a single empty value, wait for the first one. + await shutDownStream.first { _ in true } + cancellableGroup.cancelAll() + } + } + } + } + +#endif diff --git a/Sources/CLI/Commands/Explore.swift b/Sources/CLICommands/Explore.swift similarity index 91% rename from Sources/CLI/Commands/Explore.swift rename to Sources/CLICommands/Explore.swift index 9af9d949..df424c94 100644 --- a/Sources/CLI/Commands/Explore.swift +++ b/Sources/CLICommands/Explore.swift @@ -2,9 +2,9 @@ import ArgumentParser import SystemPackage @_spi(OnlyForCLI) import WasmKit -struct Explore: ParsableCommand { +package struct Explore: ParsableCommand { - static let configuration = CommandConfiguration( + package static let configuration = CommandConfiguration( abstract: "Explore the compiled functions of a WebAssembly module", discussion: """ This command will parse a WebAssembly module and dump the compiled functions. @@ -22,7 +22,9 @@ struct Explore: ParsableCommand { } } - func run() throws { + package init() {} + + package func run() throws { let module = try parseWasm(filePath: FilePath(path)) // Instruction dumping requires token threading model for now let configuration = EngineConfiguration(threadingModel: .token) diff --git a/Sources/CLI/Commands/Run.swift b/Sources/CLICommands/Run.swift similarity index 85% rename from Sources/CLI/Commands/Run.swift rename to Sources/CLICommands/Run.swift index 32769a72..579f1fcb 100644 --- a/Sources/CLI/Commands/Run.swift +++ b/Sources/CLICommands/Run.swift @@ -1,5 +1,6 @@ import ArgumentParser import SystemPackage +import WAT import WasmKit import WasmKitWASI @@ -7,8 +8,8 @@ import WasmKitWASI import os.signpost #endif -struct Run: AsyncParsableCommand { - static let configuration = CommandConfiguration( +package struct Run: AsyncParsableCommand { + package static let configuration = CommandConfiguration( abstract: "Run a WebAssembly module", discussion: """ This command will parse a WebAssembly module and run it. @@ -128,7 +129,9 @@ struct Run: AsyncParsableCommand { ) var arguments: [String] = [] - func run() async throws { + package init() {} + + package func run() async throws { #if WasmDebuggingSupport if let debuggerPort { @@ -311,3 +314,44 @@ struct Run: AsyncParsableCommand { } } } + +/// Parses a `.wasm` or `.wat` module. +func parseWasm(filePath: FilePath) throws -> Module { + if filePath.extension == "wat", #available(macOS 11.0, iOS 14.0, macCatalyst 14.0, tvOS 14.0, visionOS 1.0, watchOS 7.0, *) { + let fileHandle = try FileDescriptor.open(filePath, .readOnly) + defer { try? fileHandle.close() } + + let size = try fileHandle.seek(offset: 0, from: .end) + + let wat = try String(unsafeUninitializedCapacity: Int(size)) { + try fileHandle.read(fromAbsoluteOffset: 0, into: .init($0)) + } + return try WasmKit.parseWasm(bytes: wat2wasm(wat)) + } else { + return try WasmKit.parseWasm(filePath: filePath) + } +} + +extension Run { + package static func parseInvocation(arguments: [String]) -> (functionName: String?, parameters: [Value]) { + let functionName = arguments.first + let arguments = arguments.dropFirst() + + var parameters: [Value] = [] + for argument in arguments { + let parameter: Value + let type = argument.prefix { $0 != ":" } + let value = argument.drop { $0 != ":" }.dropFirst() + switch type { + case "i32": parameter = Value(signed: Int32(value)!) + case "i64": parameter = Value(signed: Int64(value)!) + case "f32": parameter = .f32(Float32(value)!.bitPattern) + case "f64": parameter = .f64(Float64(value)!.bitPattern) + default: fatalError("unknown type") + } + parameters.append(parameter) + } + + return (functionName, parameters) + } +} diff --git a/Sources/CLI/Commands/Wat2wasm.swift b/Sources/CLICommands/Wat2wasm.swift similarity index 95% rename from Sources/CLI/Commands/Wat2wasm.swift rename to Sources/CLICommands/Wat2wasm.swift index aa47735f..7f3f61e6 100644 --- a/Sources/CLI/Commands/Wat2wasm.swift +++ b/Sources/CLICommands/Wat2wasm.swift @@ -3,8 +3,8 @@ import SystemPackage import WAT import WasmKit -struct Wat2wasm: ParsableCommand { - static let configuration = CommandConfiguration( +package struct Wat2wasm: ParsableCommand { + package static let configuration = CommandConfiguration( abstract: "Assemble WebAssembly text into a WebAssembly binary", discussion: """ Parse a file in WebAssembly Text Format (`.wat`), \ @@ -58,7 +58,9 @@ struct Wat2wasm: ParsableCommand { ) var output: String? - func run() throws { + package init() {} + + package func run() throws { let filePath = FilePath(path) guard filePath.extension == "wat" else { throw Error.unknownFileExtension(filePath.extension) } let fileHandle = try FileDescriptor.open(filePath, .readOnly) diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index 1f773267..5e28ac12 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -9,4 +9,5 @@ add_subdirectory(WAT) if(WASMKIT_BUILD_CLI) add_subdirectory(CLI) + add_subdirectory(CLICommands) endif() From a6aede11310d65ecb48f06b49394fc1bce663622 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 7 Jan 2026 10:41:31 +0000 Subject: [PATCH 44/51] CMake: remove duplicated `FetchContent(ArgumentParser...)` --- CMakeLists.txt | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2cbab3c..31a49026 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,20 +69,6 @@ option(WASMKIT_BUILD_CLI "Build WasmKit CLI" ON) option(WASMKIT_BUILD_LLVM_BACKEND "Build WasmKit LLVM backend (experimental)" OFF) option(WASMKIT_LLVM_BACKEND_TARGET "WasmKit LLVM backend target architecture" "aarch64") -if(WASMKIT_BUILD_CLI) - set(BUILD_TESTING OFF) # disable ArgumentParser tests - find_package(ArgumentParser CONFIG) - if(NOT ArgumentParser_FOUND) - message("-- Vending ArgumentParser") - FetchContent_Declare(ArgumentParser - GIT_REPOSITORY https://github.com/apple/swift-argument-parser - GIT_TAG 1.6.1 - GIT_SHALLOW TRUE - ) - FetchContent_MakeAvailable(ArgumentParser) - endif() -endif() - add_subdirectory(Sources) add_subdirectory(Tests) add_subdirectory(cmake/modules) From 8d845eccd2f63b1cfc3dc4d32808ab6082fe9cd7 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 7 Jan 2026 10:42:54 +0000 Subject: [PATCH 45/51] Fix `wasmkit` executable naming in `main.yml` GHA workflow --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5970a6d4..ba2d1920 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -305,7 +305,7 @@ jobs: curl -L https://github.com/Kitware/CMake/releases/download/v3.29.2/cmake-3.29.2-linux-x86_64.tar.gz | tar xz --strip-component 1 -C /usr/local/ - run: cmake -G Ninja -B ./build - run: cmake --build ./build - - run: ./build/bin/wasmkit-cli --version + - run: ./build/bin/wasmkit --version build-wasi: runs-on: ubuntu-24.04 From 58634fc5a708a8045fcaa79a93d5b0b3d9a12f38 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 7 Jan 2026 10:41:31 +0000 Subject: [PATCH 46/51] CMake: remove duplicated `FetchContent(ArgumentParser...)` # Conflicts: # CMakeLists.txt --- CMakeLists.txt | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6289e5e..cbfc1a04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,19 +64,6 @@ endif() option(WASMKIT_BUILD_CLI "Build wasmkit-cli" ON) -if(WASMKIT_BUILD_CLI) - set(BUILD_TESTING OFF) # disable ArgumentParser tests - find_package(ArgumentParser CONFIG) - if(NOT ArgumentParser_FOUND) - message("-- Vending ArgumentParser") - FetchContent_Declare(ArgumentParser - GIT_REPOSITORY https://github.com/apple/swift-argument-parser - GIT_TAG 1.6.1 - ) - FetchContent_MakeAvailable(ArgumentParser) - endif() -endif() - add_subdirectory(Sources) add_subdirectory(Tests) add_subdirectory(cmake/modules) From 33f8769a45e76344def2c07a60654748293c0949 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 7 Jan 2026 10:47:09 +0000 Subject: [PATCH 47/51] Delete Sources/CLICommands/Parse.swift --- Sources/CLICommands/Parse.swift | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 Sources/CLICommands/Parse.swift diff --git a/Sources/CLICommands/Parse.swift b/Sources/CLICommands/Parse.swift deleted file mode 100644 index 70fdc05d..00000000 --- a/Sources/CLICommands/Parse.swift +++ /dev/null @@ -1,3 +0,0 @@ -import SystemPackage -import WAT -import WasmKit From 8c2b599de56b0b8351658d5a339447f0e4adea8b Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 7 Jan 2026 10:48:00 +0000 Subject: [PATCH 48/51] Delete Sources/CLI/DebuggerServer.swift --- Sources/CLI/DebuggerServer.swift | 120 ------------------------------- 1 file changed, 120 deletions(-) delete mode 100644 Sources/CLI/DebuggerServer.swift diff --git a/Sources/CLI/DebuggerServer.swift b/Sources/CLI/DebuggerServer.swift deleted file mode 100644 index 3f348bb2..00000000 --- a/Sources/CLI/DebuggerServer.swift +++ /dev/null @@ -1,120 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// This source file is part of the SwiftNIO open source project -// -// Copyright (c) 2017-2025 Apple Inc. and the SwiftNIO project authors -// Licensed under Apache License v2.0 -// -// See LICENSE.txt for license information -// See CONTRIBUTORS.txt for the list of SwiftNIO project authors -// -// SPDX-License-Identifier: Apache-2.0 -// -//===----------------------------------------------------------------------===// - -#if WasmDebuggingSupport - - import GDBRemoteProtocol - import Logging - import NIOCore - import NIOPosix - import SystemPackage - import WasmKit - import WasmKitGDBHandler - - struct DebuggerServer { - var host = "127.0.0.1" - var port: Int - var logLevel = Logger.Level.info - let wasmModulePath: FilePath - let engineConfiguration: EngineConfiguration - - func run() async throws { - let logger = { - var result = Logger(label: "org.swiftwasm.WasmKit") - result.logLevel = self.logLevel - return result - }() - - try await MultiThreadedEventLoopGroup.withEventLoopGroup(numberOfThreads: System.coreCount) { group in - let bootstrap = ServerBootstrap(group: group) - // Specify backlog and enable SO_REUSEADDR for the server itself - .serverChannelOption(.backlog, value: 256) - .serverChannelOption(.socketOption(.so_reuseaddr), value: 1) - - // Set the handlers that are applied to the accepted child `Channel`s. - .childChannelInitializer { channel in - // Ensure we don't read faster then we can write by adding the BackPressureHandler into the pipeline. - channel.eventLoop.makeCompletedFuture { - try channel.pipeline.syncOperations.addHandler(BackPressureHandler()) - // make sure to instantiate your `ChannelHandlers` inside of - // the closure as it will be invoked once per connection. - try channel.pipeline.syncOperations.addHandlers([ - ByteToMessageHandler(GDBHostCommandDecoder(logger: logger)), - MessageToByteHandler(GDBTargetResponseEncoder(logger: logger)), - ]) - } - } - - // Enable SO_REUSEADDR for the accepted Channels - .childChannelOption(.socketOption(.so_reuseaddr), value: 1) - .childChannelOption(.maxMessagesPerRead, value: 16) - .childChannelOption(.recvAllocator, value: AdaptiveRecvByteBufferAllocator()) - - let serverChannel = try await bootstrap.bind(host: self.host, port: self.port) { childChannel in - childChannel.eventLoop.makeCompletedFuture { - try NIOAsyncChannel, GDBTargetResponse>( - wrappingChannelSynchronously: childChannel - ) - } - } - /* the server will now be accepting connections */ - logger.info("Debugger server listening on port \(port)") - - let debuggerHandler = try await WasmKitGDBHandler( - moduleFilePath: self.wasmModulePath, - engineConfiguration: self.engineConfiguration, - logger: logger, - allocator: serverChannel.channel.allocator - ) - - // Discarding task group was designed for persistent server purposes, where a single failing request - // isn't taking down the entire server. In our case we need to be able to shut down the server on - // debugger client's request, so let's wrap the discarding task group with a throwing task group - // for cancellation. - await withThrowingTaskGroup { cancellableGroup in - // Use `AsyncStream` for sending a signal out of the discarding group. - let (shutDownStream, shutDownContinuation) = AsyncStream<()>.makeStream() - - cancellableGroup.addTask { - try await withThrowingDiscardingTaskGroup { discardingGroup in - try await serverChannel.executeThenClose { serverChannelInbound in - for try await connectionChannel in serverChannelInbound { - discardingGroup.addTask { - do { - try await connectionChannel.executeThenClose { connectionChannelInbound, connectionChannelOutbound in - for try await inboundData in connectionChannelInbound { - try await connectionChannelOutbound.write(debuggerHandler.handle(command: inboundData.payload)) - } - } - } catch WasmKitGDBHandler.Error.killRequestReceived { - logger.info("Debugger shut down request received") - shutDownContinuation.yield() - } catch { - logger.error("Error in GDB remote protocol connection channel", metadata: ["error": "\(error)"]) - } - } - } - } - } - } - - // The stream isn't really sending data, just a single empty value, wait for the first one. - await shutDownStream.first { _ in true } - cancellableGroup.cancelAll() - } - } - } - } - -#endif From 88a0a39a030b5cb2c6b3fda67ff5415cf3d4caf4 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Sat, 10 Jan 2026 13:43:04 +0000 Subject: [PATCH 49/51] Move dependencies to top-level CMakeLists.txt --- CMakeLists.txt | 37 +++++++++++++++++++++++++++++ Sources/LLVMBackend/CMakeLists.txt | 38 ------------------------------ 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 719306d3..9b0193b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,43 @@ if(WASMKIT_BUILD_CLI) endif() endif() +if(WASMKIT_BUILD_LLVM_BACKEND) + FetchContent_Declare( + SwiftLLVMBindings + GIT_REPOSITORY "https://github.com/swiftlang/swift-llvm-bindings.git" + GIT_TAG c1fffb92d4f9d7cb98800762631cfa354869fb46 + GIT_SHALLOW TRUE + GIT_PROGRESS ON + ) + + FetchContent_MakeAvailable(SwiftLLVMBindings) + + find_package(Subprocess CONFIG) + + if(NOT Subprocess_FOUND) + message("-- Vending Subprocess") + FetchContent_Declare( + Subprocess + GIT_REPOSITORY https://github.com/swiftlang/swift-subprocess + GIT_TAG 0.2.1 + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable(Subprocess) + endif() + + find_package(SwiftCollections CONFIG) + if(NOT SwiftCollections_FOUND) + message("-- Vending SwiftCollections") + FetchContent_Declare( + SwiftCollections + GIT_REPOSITORY https://github.com/apple/swift-collections + GIT_TAG 1.3.0 + GIT_SHALLOW TRUE + ) + FetchContent_MakeAvailable(SwiftCollections) + endif() +endif() + find_package(SwiftSystem CONFIG) if(NOT SwiftSystem_FOUND) message("-- Vending SwiftSystem") diff --git a/Sources/LLVMBackend/CMakeLists.txt b/Sources/LLVMBackend/CMakeLists.txt index 9c72c7de..0c1b51a6 100644 --- a/Sources/LLVMBackend/CMakeLists.txt +++ b/Sources/LLVMBackend/CMakeLists.txt @@ -29,44 +29,6 @@ target_include_directories( set(WASMKIT_DEPENDENCIES WAT WasmKit WasmTypes WasmParser) set(BUILD_TESTING OFF) -include(FetchContent) - -FetchContent_Declare( - SwiftLLVMBindings - GIT_REPOSITORY "https://github.com/swiftlang/swift-llvm-bindings.git" - GIT_TAG c1fffb92d4f9d7cb98800762631cfa354869fb46 - GIT_SHALLOW TRUE - GIT_PROGRESS ON -) - -FetchContent_MakeAvailable(SwiftLLVMBindings) - -find_package(Subprocess CONFIG) - -if(NOT Subprocess_FOUND) - message("-- Vending Subprocess") - FetchContent_Declare( - Subprocess - GIT_REPOSITORY https://github.com/swiftlang/swift-subprocess - GIT_TAG 0.2.1 - GIT_SHALLOW TRUE - ) - FetchContent_MakeAvailable(Subprocess) -endif() - -find_package(SwiftCollections CONFIG) -if(NOT SwiftCollections_FOUND) - message("-- Vending SwiftCollections") - FetchContent_Declare( - SwiftCollections - GIT_REPOSITORY https://github.com/apple/swift-collections - GIT_TAG 1.3.0 - GIT_SHALLOW TRUE - ) - FetchContent_MakeAvailable(SwiftCollections) -endif() - - add_dependencies(LLVMInterop BasicContainers LLVM_Utils Subprocess ${WASMKIT_DEPENDENCIES}) target_link_libraries( From 8bd1bde3144664c426848cea92262b4b1a970b93 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 26 Jan 2026 12:34:12 +0000 Subject: [PATCH 50/51] Fix trailing comma --- Sources/LLVMBackend/CodegenContext.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/LLVMBackend/CodegenContext.swift b/Sources/LLVMBackend/CodegenContext.swift index ea813ecf..3ffcf438 100644 --- a/Sources/LLVMBackend/CodegenContext.swift +++ b/Sources/LLVMBackend/CodegenContext.swift @@ -85,7 +85,7 @@ package struct CodegenContext: ~Copyable { type: type, locals: type.parameters + f.locals, code: f, - ir: self.ir, + ir: self.ir )) functionNames.append(name) From d0bfb95ba8d616f5b6312733f1c844eff31cca8e Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Mon, 26 Jan 2026 17:26:06 +0000 Subject: [PATCH 51/51] LLVM: fix exported functions not callable by name (#250) The exports section was not parsed, so we only assigned names to functions based on their indices. `functionNames` in `CodegenContext.swift` should become a dictionary that maps function indices to their name, so that `IRFunctionVisitor` generates correct symbol names. --- .github/workflows/main.yml | 4 +-- Sources/LLVMBackend/CodegenContext.swift | 27 +++++++++++++++++---- Sources/LLVMBackend/IRFunctionVisitor.swift | 6 ++--- Sources/WasmParser/WasmTypes.swift | 4 +-- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8e12fb0e..1fc9b2f3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -387,7 +387,7 @@ jobs: - name: Run a smoke test run: | ./build/bin/wasmkit-llvm wat2wasm Examples/wasm/factorial.wat - ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm 0 i64:5 + ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm fac i64:5 build-llvm-macos: strategy: @@ -421,7 +421,7 @@ jobs: - name: Run a smoke test run: | ./build/bin/wasmkit-llvm wat2wasm Examples/wasm/factorial.wat - ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm 0 i64:5 + ./build/bin/wasmkit-llvm run Examples/wasm/factorial.wasm fac i64:5 build-wasi: runs-on: ubuntu-24.04 diff --git a/Sources/LLVMBackend/CodegenContext.swift b/Sources/LLVMBackend/CodegenContext.swift index 3ffcf438..33ba8a2b 100644 --- a/Sources/LLVMBackend/CodegenContext.swift +++ b/Sources/LLVMBackend/CodegenContext.swift @@ -12,6 +12,7 @@ package struct CodegenContext: ~Copyable { case objectFileEmissionFailed case multiValueResultsNotSupportedYet(functionName: String) case unsupportedImport(Import) + case unsupportedExport(Export) } private(set) var ir: IRContext @@ -30,7 +31,7 @@ package struct CodegenContext: ~Copyable { var functionTypes = [TypeIndex]() var functionVisitors = RigidArray() var importedFunctions = [IRValue]() - var functionNames = [String]() + var functionNames = [Int: String]() var memories = [Memory]() while let payload = try parser.parseNext() { @@ -41,6 +42,7 @@ package struct CodegenContext: ~Copyable { memories = m case .importSection(let imports): + var currentFunctionIndex = 0 for i in imports { switch i.descriptor { case .function(let typeIndex): @@ -63,7 +65,8 @@ package struct CodegenContext: ~Copyable { name.withStringRef { importedFunctions.append(self.ir.__createImportedFunctionUnsafe($0, irType)) } - functionNames.append(name) + functionNames[currentFunctionIndex] = name + currentFunctionIndex += 1 functionTypes.append(typeIndex) case .global, .table, .memory: @@ -71,14 +74,26 @@ package struct CodegenContext: ~Copyable { } } + case .exportSection(let exports): + for e in exports { + switch e.descriptor { + case .function(let functionIndex): + functionNames[Int(functionIndex)] = e.name + + default: + throw Error.unsupportedExport(e) + } + } + case .codeSection(let functions): functionVisitors = RigidArray(capacity: functions.count) for (i, f) in functions.enumerated() { - let type = types[Int(functionTypes[importedFunctions.count + i])] + let functionIndex = importedFunctions.count + i + let type = types[Int(functionTypes[functionIndex])] // Create visitors first before actually visiting instructions. // This will forward-declare all `llvm::Function` instances so that `call` // LLVM IR instructions have these instances to refer to and are valid. - let name = "\(i)" + let name = functionNames[functionIndex] ?? "\(functionIndex)" try functionVisitors.append( .init( name: name, @@ -88,7 +103,9 @@ package struct CodegenContext: ~Copyable { ir: self.ir )) - functionNames.append(name) + if functionNames[i] == nil { + functionNames[i] = name + } } default: continue } diff --git a/Sources/LLVMBackend/IRFunctionVisitor.swift b/Sources/LLVMBackend/IRFunctionVisitor.swift index d01d83e3..2b508af6 100644 --- a/Sources/LLVMBackend/IRFunctionVisitor.swift +++ b/Sources/LLVMBackend/IRFunctionVisitor.swift @@ -24,7 +24,7 @@ struct IRFunctionVisitor: InstructionVisitor, ~Copyable { private(set) var stack = [IRValue]() private(set) var types = [FunctionType]() private(set) var functionTypes = [TypeIndex]() - private(set) var functionNames = [String]() + private(set) var functionNames = [Int: String]() private(set) var importedFunctions = [IRValue]() private(set) var memories = [Memory]() @@ -111,7 +111,7 @@ struct IRFunctionVisitor: InstructionVisitor, ~Copyable { _ functionTypes: [TypeIndex], _ memories: [Memory], importedFunctions: [IRValue], - functionNames: [String] + functionNames: [Int: String] ) throws { self.types = types self.functionTypes = functionTypes @@ -153,7 +153,7 @@ struct IRFunctionVisitor: InstructionVisitor, ~Copyable { guard self.functionNames.count > functionIndex, - let f = self.functionNames[functionIndex].withStringRef({ ir.getFunction($0) }).value + let f = self.functionNames[functionIndex]?.withStringRef({ ir.getFunction($0) }).value else { throw Error.irFunctionUnknown(functionIndex) } diff --git a/Sources/WasmParser/WasmTypes.swift b/Sources/WasmParser/WasmTypes.swift index cec1aebd..98cd03c3 100644 --- a/Sources/WasmParser/WasmTypes.swift +++ b/Sources/WasmParser/WasmTypes.swift @@ -255,7 +255,7 @@ public enum DataSegment: Equatable { /// Exported entity in a module /// > Note: /// -public struct Export: Equatable { +public struct Export: Equatable, Sendable { /// Name of the export public let name: String /// Descriptor of the export @@ -268,7 +268,7 @@ public struct Export: Equatable { } /// Export descriptor -public enum ExportDescriptor: Equatable { +public enum ExportDescriptor: Equatable, Sendable { /// Function export case function(FunctionIndex) /// Table export