From 387e5fe8889fb54be7739f70a82494cb59f1f7ce Mon Sep 17 00:00:00 2001 From: Georgii Plotnikov Date: Tue, 9 Dec 2025 09:05:54 +0900 Subject: [PATCH 1/3] Add WebAssembly inference block intrinsics with CI/CD workflow - Add inference block intrinsics: forall, exists, assume, unique (with start/end markers) - Add uzumaki.i32 and uzumaki.i64 intrinsics for WebAssembly - Implement instruction definitions and lowering in WebAssembly backend - Add ISD node types for inference blocks in WebAssemblyISD.def - Implement bytecode emission in WebAssemblyAsmPrinter - Add GitHub Actions workflow for building LLVM static artifacts (Linux/Windows) - Configure static linking with WebAssembly and X86 targets - Package artifacts with flat directory structure for easier extraction - Update workflow to reference inference-intrinsics branch --- .../build-inference-llvm-artifacts.yml | 451 ++++++++++++++++++ llvm/include/llvm/IR/IntrinsicsWebAssembly.td | 40 ++ .../SelectionDAG/SelectionDAGBuilder.cpp | 20 + .../WebAssembly/WebAssemblyAsmPrinter.cpp | 36 ++ .../lib/Target/WebAssembly/WebAssemblyISD.def | 12 + .../WebAssembly/WebAssemblyISelDAGToDAG.cpp | 148 ++++++ .../WebAssembly/WebAssemblyISelLowering.cpp | 34 +- .../WebAssembly/WebAssemblyInstrControl.td | 51 ++ .../WebAssembly/WebAssemblyInstrInfo.td | 28 ++ .../WebAssembly/WebAssemblyInstrInteger.td | 10 + 10 files changed, 827 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/build-inference-llvm-artifacts.yml diff --git a/.github/workflows/build-inference-llvm-artifacts.yml b/.github/workflows/build-inference-llvm-artifacts.yml new file mode 100644 index 0000000000000..520aa9860bfbf --- /dev/null +++ b/.github/workflows/build-inference-llvm-artifacts.yml @@ -0,0 +1,451 @@ +name: Build Inference LLVM Static Artifacts + +on: + pull_request: + branches: [main, inference-intrinsics] + push: + branches: [main, inference-intrinsics] + workflow_dispatch: + +env: + LLVM_VERSION: "21.1.0" + ARTIFACT_NAME: "llvm-inference-static" + +jobs: + build-llvm: + name: Build LLVM Static Libraries (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + platform: Linux + arch: x64 + - os: windows-latest + platform: Windows + arch: x64 + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Setup Build Environment + run: | + if [ "$RUNNER_OS" == "Linux" ]; then + sudo apt-get update + sudo apt-get install -y \ + ninja-build \ + cmake \ + build-essential \ + libzstd-dev \ + zlib1g-dev + elif [ "$RUNNER_OS" == "Windows" ]; then + choco install ninja cmake + fi + shell: bash + + - name: Configure LLVM for Static Linking + run: | + mkdir -p build-static + cd build-static + + # Platform-specific flags + EXTRA_FLAGS="" + if [ "$RUNNER_OS" != "Windows" ]; then + EXTRA_FLAGS="-DLLVM_ENABLE_PIC=OFF" + fi + + cmake -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_TARGETS_TO_BUILD="WebAssembly;X86" \ + -DLLVM_BUILD_LLVM_DYLIB=OFF \ + -DLLVM_LINK_LLVM_DYLIB=OFF \ + -DLLVM_BUILD_STATIC=ON \ + -DLLVM_ENABLE_TERMINFO=OFF \ + -DLLVM_ENABLE_ZLIB=OFF \ + -DLLVM_ENABLE_ZSTD=OFF \ + -DLLVM_INCLUDE_TESTS=OFF \ + -DLLVM_INCLUDE_BENCHMARKS=OFF \ + -DLLVM_INCLUDE_EXAMPLES=OFF \ + -DLLVM_BUILD_TOOLS=ON \ + -DLLVM_TOOL_LLVM_CONFIG_BUILD=ON \ + -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/llvm-install" \ + $EXTRA_FLAGS \ + ../llvm + shell: bash + + - name: Build LLVM + run: | + cd build-static + if [ "$RUNNER_OS" == "Windows" ]; then + ninja -j4 # Limit parallelism on Windows to avoid memory issues + else + ninja -j$(nproc) + fi + shell: bash + + - name: Install LLVM + run: | + cd build-static + ninja install + + # Verify installation + ls -la "${{ github.workspace }}/llvm-install/bin/" || echo "Install directory not found" + ls -la "${{ github.workspace }}/llvm-install/lib/" || echo "Lib directory not found" + shell: bash + + - name: Prepare Artifact Package + run: | + mkdir -p llvm-package/{lib,include,bin} + + INSTALL_DIR="${{ github.workspace }}/llvm-install" + BUILD_DIR="${{ github.workspace }}/build-static" + + echo "📦 Packaging LLVM artifacts" + + # Determine source directory (install if available, otherwise build) + if [ -d "$INSTALL_DIR/lib" ]; then + SRC_DIR="$INSTALL_DIR" + echo "Using install directory: $SRC_DIR" + elif [ -d "$BUILD_DIR/lib" ]; then + SRC_DIR="$BUILD_DIR" + echo "Using build directory: $SRC_DIR" + else + echo "❌ No valid source directory found" + exit 1 + fi + + # Copy all static libraries + if [ -d "$SRC_DIR/lib" ]; then + echo "Copying static libraries..." + if [ "$RUNNER_OS" == "Windows" ]; then + find "$SRC_DIR/lib" -name "*.lib" -exec cp -v {} llvm-package/lib/ \; + find "$SRC_DIR/lib" -name "*.a" -exec cp -v {} llvm-package/lib/ \; + else + find "$SRC_DIR/lib" -name "*.a" -exec cp -v {} llvm-package/lib/ \; + fi + echo "✓ Libraries copied: $(ls llvm-package/lib/*.a llvm-package/lib/*.lib 2>/dev/null | wc -l) files" + fi + + # Copy headers from both install and source + if [ -d "$SRC_DIR/include" ]; then + echo "Copying headers from $SRC_DIR..." + cp -r "$SRC_DIR/include"/* llvm-package/include/ + fi + if [ -d "llvm/include" ]; then + echo "Copying headers from source..." + cp -r llvm/include/* llvm-package/include/ + fi + + # Copy essential LLVM tools + echo "Copying LLVM tools..." + for tool in llvm-config llc llvm-as llvm-dis llvm-link opt llvm-ar llvm-nm; do + TOOL_PATH="$SRC_DIR/bin/$tool" + # Add .exe extension on Windows + if [ "$RUNNER_OS" == "Windows" ] && [ -f "$TOOL_PATH.exe" ]; then + cp -v "$TOOL_PATH.exe" llvm-package/bin/ + chmod +x llvm-package/bin/$tool.exe + echo "✓ Copied $tool.exe" + elif [ -f "$TOOL_PATH" ]; then + cp -v "$TOOL_PATH" llvm-package/bin/ + chmod +x llvm-package/bin/$tool + echo "✓ Copied $tool" + else + echo "⚠️ $tool not found in $SRC_DIR/bin/" + fi + done + + # Verify binaries are present + echo "" + echo "📋 Final artifact contents:" + ls -lh llvm-package/bin/ || echo "No binaries found" + echo "" + echo "Library count: $(ls llvm-package/lib/*.a llvm-package/lib/*.lib 2>/dev/null | wc -l)" + shell: bash + + - name: Create Setup Scripts + run: | + # Create a config script for Rust builds + cat > llvm-package/setup-env.sh << 'EOF' + #!/bin/bash + # LLVM Static Build Environment Configuration + export LLVM_SYS_211_PREFIX="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + export LLVM_CONFIG_PATH="$LLVM_SYS_211_PREFIX/bin/llvm-config" + export RUSTFLAGS="-C target-cpu=native -C link-arg=-static-libgcc" + echo "✅ LLVM environment configured" + echo " LLVM_SYS_211_PREFIX: $LLVM_SYS_211_PREFIX" + EOF + chmod +x llvm-package/setup-env.sh + shell: bash + + - name: Create Documentation + run: | + # Create a README + cat > llvm-package/README.md << 'EOF' + # LLVM Inference Static Build + + This package contains statically-linked LLVM libraries with custom Inference intrinsics. + + ## Usage with Rust + + 1. Extract this archive + 2. Set environment variable: + ```bash + export LLVM_SYS_211_PREFIX=/path/to/extracted/artifact + ``` + 3. Build your Rust project: + ```bash + cargo build --release + ``` + + ## Files Included + + - `lib/*.a` - Static LLVM libraries + - `include/` - LLVM headers + - `bin/llvm-config` - LLVM configuration tool + - `bin/llc` - LLVM static compiler + - `bin/llvm-as` - LLVM assembler + - `bin/llvm-dis` - LLVM disassembler + - `bin/llvm-link` - LLVM linker + - `bin/opt` - LLVM optimizer + - `bin/wasm-ld` - WebAssembly linker + - `setup-env.sh` - Environment setup script + + ## Custom Features + + This build includes: + - Uzumaki intrinsics (i32/i64) + - Inference block types (forall, exists, assume, unique) + - WebAssembly target support + + Built from: ${{ github.repository }}@${{ github.sha }} + EOF + shell: bash + + - name: Create Build Info + run: | + cd llvm-package + cat > BUILD_INFO.json << EOF + { + "version": "${{ env.LLVM_VERSION }}", + "commit": "${{ github.sha }}", + "branch": "${{ github.ref_name }}", + "build_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)", + "targets": ["WebAssembly", "X86"], + "features": ["uzumaki-intrinsics", "inference-blocks"], + "os": "${{ runner.os }}", + "static": true + } + EOF + shell: bash + + - name: Package Artifact + run: | + if [ "$RUNNER_OS" == "Windows" ]; then + # Use zip for Windows - package contents directly without parent directory + cd llvm-package + 7z a -tzip ../${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip * + cd .. + + # Create checksum + certutil -hashfile ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip SHA256 > ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip.sha256 + else + # Use tar.gz for Linux - package contents directly without parent directory + tar -czf ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz -C llvm-package . + + # Create checksum + sha256sum ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz > ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz.sha256 + fi + shell: bash + + - name: Upload Build Artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64 + path: | + ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.* + retention-days: 90 + compression-level: 0 # Already compressed + + - name: Display Package Info + run: | + echo "📦 Artifact Package Created" + echo "==========================" + if [ "$RUNNER_OS" == "Windows" ]; then + ls -lh ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip + echo "" + echo "📋 Checksum:" + cat ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip.sha256 + echo "" + echo "📊 Package Contents (first 20 entries):" + # Ignore broken pipe so 7z listing doesn't fail the step + set +e + 7z l ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip | head -20 + set -e + else + ls -lh ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz + echo "" + echo "📋 Checksum:" + cat ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz.sha256 + echo "" + echo "📊 Package Contents (first 20 entries):" + # Ignore broken pipe so tar listing doesn't fail the step + set +e + tar -tzf ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz | head -20 + set -e + fi + shell: bash + + create-release: + name: Create Release (on merge to main) + needs: build-llvm + runs-on: ubuntu-latest + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download Artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Create Release Tag + id: create_tag + run: | + TAG="${{ env.ARTIFACT_NAME }}-$(date +%Y%m%d-%H%M%S)" + echo "tag=$TAG" >> $GITHUB_OUTPUT + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "$TAG" -m "LLVM Inference Static Build - $(date)" + git push origin "$TAG" || true + + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.create_tag.outputs.tag }} + name: "LLVM Inference Static Build - $(date +%Y-%m-%d)" + body: | + ## LLVM Static Build with Inference Extensions + + ### Features + - ✅ Inference intrinsics (i32/i64) + - ✅ Inference blocks (forall, exists, assume, unique) + - ✅ WebAssembly target support + - ✅ Statically linked for easy distribution + + ### Usage + + Download the artifact for your platform and extract: + + **Linux:** + ```bash + mkdir llvm-inference && cd llvm-inference + tar -xzf ../${{ env.ARTIFACT_NAME }}-Linux-x64.tar.gz + source setup-env.sh + ``` + + **Windows:** + ```powershell + mkdir llvm-inference + cd llvm-inference + 7z x ..\${{ env.ARTIFACT_NAME }}-Windows-x64.zip + # Set environment variables manually or use setup-env.sh in Git Bash + ``` + + Then build your Rust project: + ```bash + cargo build --release + ``` + + ### Verification + + Verify the download with SHA256: + + **Linux:** + ```bash + sha256sum -c ${{ env.ARTIFACT_NAME }}-Linux-x64.tar.gz.sha256 + ``` + + **Windows:** + ```powershell + certutil -hashfile ${{ env.ARTIFACT_NAME }}-Windows-x64.zip SHA256 + ``` + + **Commit:** ${{ github.sha }} + **Branch:** ${{ github.ref_name }} + files: | + artifacts/**/*.tar.gz + artifacts/**/*.sha256 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + test-artifact: + name: Test Artifact with Sample Rust Project (${{ matrix.platform }}) + needs: build-llvm + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-latest + platform: Linux + - os: windows-latest + platform: Windows + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + + - name: Download LLVM Artifact + uses: actions/download-artifact@v4 + with: + name: ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64 + path: llvm-artifact + + - name: Extract and Setup LLVM + run: | + mkdir -p llvm-extract + cd llvm-extract + if [ "$RUNNER_OS" == "Windows" ]; then + 7z x ../llvm-artifact/${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip + else + tar -xzf ../llvm-artifact/${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz + fi + source setup-env.sh + + # Verify llvm-config works + $LLVM_CONFIG_PATH --version + + echo "LLVM_SYS_211_PREFIX=$LLVM_SYS_211_PREFIX" >> $GITHUB_ENV + echo "LLVM_CONFIG_PATH=$LLVM_CONFIG_PATH" >> $GITHUB_ENV + shell: bash + + - name: Create Test Rust Project + run: | + # Create a minimal test if it doesn't exist + if [ ! -f "Cargo.toml" ]; then + cat > test-llvm.rs << 'EOF' + fn main() { + println!("LLVM artifact test successful!"); + } + EOF + rustc test-llvm.rs -o test-llvm + ./test-llvm + fi + shell: bash + + - name: Build Test (if Cargo.toml exists) + if: hashFiles('Cargo.toml') != '' + run: | + cargo build --release + echo "✅ Test build completed successfully!" diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td index f592ff287a0e3..f020b6bcdecf9 100644 --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -118,6 +118,46 @@ def int_wasm_trunc_saturate_unsigned : DefaultAttrsIntrinsic<[llvm_anyint_ty], [llvm_anyfloat_ty], [IntrNoMem, IntrSpeculatable]>; +// Uzumaki intrinsics + +def int_wasm_uzumaki_i32 : + DefaultAttrsIntrinsic<[llvm_i32_ty], [], [IntrNoMem, IntrHasSideEffects]>; + +def int_wasm_uzumaki_i64 : + DefaultAttrsIntrinsic<[llvm_i64_ty], [], [IntrNoMem, IntrHasSideEffects]>; + +//===----------------------------------------------------------------------===// +// Inference block intrinsics +//===----------------------------------------------------------------------===// + +// These are block-like intrinsics that take a function pointer or code block +// For simplicity in LLVM IR, we model them as markers that the backend +// transforms into proper blocks + +def int_wasm_forall_start : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + +def int_wasm_forall_end : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + +def int_wasm_exists_start : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + +def int_wasm_exists_end : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + +def int_wasm_assume_start : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + +def int_wasm_assume_end : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + +def int_wasm_unique_start : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + +def int_wasm_unique_end : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + //===----------------------------------------------------------------------===// // Exception handling intrinsics //===----------------------------------------------------------------------===// diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 4954e23f9846f..6c8222df0edb2 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -3428,6 +3428,26 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) { DAG.setRoot(DAG.getNode(ISD::INTRINSIC_VOID, getCurSDLoc(), VTs, Ops)); break; } + // Inference block intrinsics: handle them like wasm_throw/wasm_rethrow + // to prevent crashes in visitTargetIntrinsic + case Intrinsic::wasm_forall_start: + case Intrinsic::wasm_forall_end: + case Intrinsic::wasm_exists_start: + case Intrinsic::wasm_exists_end: + case Intrinsic::wasm_assume_start: + case Intrinsic::wasm_assume_end: + case Intrinsic::wasm_unique_start: + case Intrinsic::wasm_unique_end: { + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + unsigned IntrID = cast(I).getIntrinsicID(); + std::array Ops = { + getControlRoot(), // inchain for the terminator node + DAG.getTargetConstant(IntrID, getCurSDLoc(), + TLI.getPointerTy(DAG.getDataLayout()))}; + SDVTList VTs = DAG.getVTList(ArrayRef({MVT::Other})); // outchain + DAG.setRoot(DAG.getNode(ISD::INTRINSIC_VOID, getCurSDLoc(), VTs, Ops)); + break; + } } } else if (I.hasDeoptState()) { // Currently we do not lower any intrinsic calls with deopt operand bundles. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 1bf070e9ec9c8..20c664596cfbc 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -645,6 +645,42 @@ void WebAssemblyAsmPrinter::emitInstruction(const MachineInstr *MI) { Subtarget->getFeatureBits()); switch (MI->getOpcode()) { + case WebAssembly::UZUMAKI_I32: { + OutStreamer->emitIntValue(0xFC, 1); + OutStreamer->emitIntValue(0x31, 1); + break; + } + case WebAssembly::UZUMAKI_I64: { + OutStreamer->emitIntValue(0xFC, 1); + OutStreamer->emitIntValue(0x32, 1); + break; + } + // Inference block instructions + case WebAssembly::INFERENCE_FORALL: { + OutStreamer->emitIntValue(0xFC, 1); + OutStreamer->emitIntValue(0x3A, 1); + // Emit block type (0x40 for void) + OutStreamer->emitIntValue(0x40, 1); + break; + } + case WebAssembly::INFERENCE_EXISTS: { + OutStreamer->emitIntValue(0xFC, 1); + OutStreamer->emitIntValue(0x3B, 1); + OutStreamer->emitIntValue(0x40, 1); + break; + } + case WebAssembly::INFERENCE_ASSUME: { + OutStreamer->emitIntValue(0xFC, 1); + OutStreamer->emitIntValue(0x3C, 1); + OutStreamer->emitIntValue(0x40, 1); + break; + } + case WebAssembly::INFERENCE_UNIQUE: { + OutStreamer->emitIntValue(0xFC, 1); + OutStreamer->emitIntValue(0x3D, 1); + OutStreamer->emitIntValue(0x40, 1); + break; + } case WebAssembly::ARGUMENT_i32: case WebAssembly::ARGUMENT_i32_S: case WebAssembly::ARGUMENT_i64: diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def index 378ef2c8f250e..bdfe00ea79f14 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISD.def +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISD.def @@ -47,6 +47,18 @@ HANDLE_NODETYPE(I64_ADD128) HANDLE_NODETYPE(I64_SUB128) HANDLE_NODETYPE(I64_MUL_WIDE_S) HANDLE_NODETYPE(I64_MUL_WIDE_U) +HANDLE_NODETYPE(UZUMAKI_I32) +HANDLE_NODETYPE(UZUMAKI_I64) + +// Inference block markers +HANDLE_NODETYPE(BLOCK_FORALL) +HANDLE_NODETYPE(BLOCK_EXISTS) +HANDLE_NODETYPE(BLOCK_ASSUME) +HANDLE_NODETYPE(BLOCK_UNIQUE) +HANDLE_NODETYPE(BLOCK_FORALL_END) +HANDLE_NODETYPE(BLOCK_EXISTS_END) +HANDLE_NODETYPE(BLOCK_ASSUME_END) +HANDLE_NODETYPE(BLOCK_UNIQUE_END) // Memory intrinsics HANDLE_NODETYPE(GLOBAL_GET) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp index ac819cf5c1801..9ab175551d96c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -260,10 +260,158 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) { ReplaceNode(Node, Rethrow); return; } + + // Inference block intrinsics + case Intrinsic::wasm_forall_start: { + MachineSDNode *ForallStart = CurDAG->getMachineNode( + WebAssembly::INFERENCE_FORALL, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, ForallStart); + return; + } + case Intrinsic::wasm_exists_start: { + MachineSDNode *ExistsStart = CurDAG->getMachineNode( + WebAssembly::INFERENCE_EXISTS, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, ExistsStart); + return; + } + case Intrinsic::wasm_assume_start: { + MachineSDNode *AssumeStart = CurDAG->getMachineNode( + WebAssembly::INFERENCE_ASSUME, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, AssumeStart); + return; + } + case Intrinsic::wasm_unique_start: { + MachineSDNode *UniqueStart = CurDAG->getMachineNode( + WebAssembly::INFERENCE_UNIQUE, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, UniqueStart); + return; + } + case Intrinsic::wasm_forall_end: { + MachineSDNode *ForallEnd = CurDAG->getMachineNode( + WebAssembly::INFERENCE_FORALL_END, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, ForallEnd); + return; + } + case Intrinsic::wasm_exists_end: { + MachineSDNode *ExistsEnd = CurDAG->getMachineNode( + WebAssembly::INFERENCE_EXISTS_END, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, ExistsEnd); + return; + } + case Intrinsic::wasm_assume_end: { + MachineSDNode *AssumeEnd = CurDAG->getMachineNode( + WebAssembly::INFERENCE_ASSUME_END, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, AssumeEnd); + return; + } + case Intrinsic::wasm_unique_end: { + MachineSDNode *UniqueEnd = CurDAG->getMachineNode( + WebAssembly::INFERENCE_UNIQUE_END, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, UniqueEnd); + return; + } } break; } + + // Inference block instructions + case WebAssemblyISD::BLOCK_FORALL: { + MachineSDNode *ForallStart = CurDAG->getMachineNode( + WebAssembly::INFERENCE_FORALL, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, ForallStart); + return; + } + case WebAssemblyISD::BLOCK_EXISTS: { + MachineSDNode *ExistsStart = CurDAG->getMachineNode( + WebAssembly::INFERENCE_EXISTS, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, ExistsStart); + return; + } + case WebAssemblyISD::BLOCK_ASSUME: { + MachineSDNode *AssumeStart = CurDAG->getMachineNode( + WebAssembly::INFERENCE_ASSUME, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, AssumeStart); + return; + } + case WebAssemblyISD::BLOCK_UNIQUE: { + MachineSDNode *UniqueStart = CurDAG->getMachineNode( + WebAssembly::INFERENCE_UNIQUE, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, UniqueStart); + return; + } + case WebAssemblyISD::BLOCK_FORALL_END: { + MachineSDNode *ForallEnd = CurDAG->getMachineNode( + WebAssembly::INFERENCE_FORALL_END, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, ForallEnd); + return; + } + case WebAssemblyISD::BLOCK_EXISTS_END: { + MachineSDNode *ExistsEnd = CurDAG->getMachineNode( + WebAssembly::INFERENCE_EXISTS_END, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, ExistsEnd); + return; + } + case WebAssemblyISD::BLOCK_ASSUME_END: { + MachineSDNode *AssumeEnd = CurDAG->getMachineNode( + WebAssembly::INFERENCE_ASSUME_END, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, AssumeEnd); + return; + } + case WebAssemblyISD::BLOCK_UNIQUE_END: { + MachineSDNode *UniqueEnd = CurDAG->getMachineNode( + WebAssembly::INFERENCE_UNIQUE_END, DL, + MVT::Other, // outchain type + Node->getOperand(0) // inchain + ); + ReplaceNode(Node, UniqueEnd); + return; + } case WebAssemblyISD::CALL: case WebAssemblyISD::RET_CALL: { // CALL has both variable operands and variable results, but ISel only diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index bf2e04caa0a61..3ea52c937ecf1 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -1654,9 +1654,13 @@ SDValue WebAssemblyTargetLowering::LowerOperation(SDValue Op, case ISD::INSERT_VECTOR_ELT: return LowerAccessVectorElement(Op, DAG); case ISD::INTRINSIC_VOID: - case ISD::INTRINSIC_WO_CHAIN: case ISD::INTRINSIC_W_CHAIN: - return LowerIntrinsic(Op, DAG); + case ISD::INTRINSIC_WO_CHAIN: { + SDValue Res = LowerIntrinsic(Op, DAG); + if (Res.getNode()) + return Res; + return SDValue(); + } case ISD::SIGN_EXTEND_INREG: return LowerSIGN_EXTEND_INREG(Op, DAG); case ISD::ZERO_EXTEND_VECTOR_INREG: @@ -2204,7 +2208,31 @@ SDValue WebAssemblyTargetLowering::LowerIntrinsic(SDValue Op, switch (IntNo) { default: - return SDValue(); // Don't custom lower most intrinsics. + // Don't custom lower most intrinsics. + return SDValue(); + + case Intrinsic::wasm_uzumaki_i32: + return DAG.getNode(WebAssemblyISD::UZUMAKI_I32, DL, MVT::i32); + case Intrinsic::wasm_uzumaki_i64: + return DAG.getNode(WebAssemblyISD::UZUMAKI_I64, DL, MVT::i64); + + // Inference block intrinsics - lower to WebAssemblyISD nodes + case Intrinsic::wasm_forall_start: + return DAG.getNode(WebAssemblyISD::BLOCK_FORALL, DL, MVT::Other, Op.getOperand(0)); + case Intrinsic::wasm_forall_end: + return DAG.getNode(WebAssemblyISD::BLOCK_FORALL_END, DL, MVT::Other, Op.getOperand(0)); + case Intrinsic::wasm_exists_start: + return DAG.getNode(WebAssemblyISD::BLOCK_EXISTS, DL, MVT::Other, Op.getOperand(0)); + case Intrinsic::wasm_exists_end: + return DAG.getNode(WebAssemblyISD::BLOCK_EXISTS_END, DL, MVT::Other, Op.getOperand(0)); + case Intrinsic::wasm_assume_start: + return DAG.getNode(WebAssemblyISD::BLOCK_ASSUME, DL, MVT::Other, Op.getOperand(0)); + case Intrinsic::wasm_assume_end: + return DAG.getNode(WebAssemblyISD::BLOCK_ASSUME_END, DL, MVT::Other, Op.getOperand(0)); + case Intrinsic::wasm_unique_start: + return DAG.getNode(WebAssemblyISD::BLOCK_UNIQUE, DL, MVT::Other, Op.getOperand(0)); + case Intrinsic::wasm_unique_end: + return DAG.getNode(WebAssemblyISD::BLOCK_UNIQUE_END, DL, MVT::Other, Op.getOperand(0)); case Intrinsic::wasm_lsda: { auto PtrVT = getPointerTy(MF.getDataLayout()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td index ed6aec1ab33e3..a390427fb0e6e 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -205,3 +205,54 @@ let isTerminator = 1, hasCtrlDep = 1, hasSideEffects = 1 in defm DELEGATE : NRI<(outs), (ins bb_op:$dst), [], "delegate \t $dst", 0x18>; } // Predicates = [HasExceptionHandling] + +//===----------------------------------------------------------------------===// +// Inference block instructions +//===----------------------------------------------------------------------===// + +// FORALL block - considers all execution paths +let isTerminator = 0, isBarrier = 0, hasCtrlDep = 1, Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { +defm BLOCK_FORALL : NRI<(outs), (ins Signature:$sig), + [], + "block.forall\t$sig", 0x00>; +} + +// EXISTS block - considers existence of execution path +let isTerminator = 0, isBarrier = 0, hasCtrlDep = 1, Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { +defm BLOCK_EXISTS : NRI<(outs), (ins Signature:$sig), + [], + "block.exists\t$sig", 0x00>; +} + +// ASSUME block - defines assumptions about program state +let isTerminator = 0, isBarrier = 0, hasCtrlDep = 1, Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { +defm BLOCK_ASSUME : NRI<(outs), (ins Signature:$sig), + [], + "block.assume\t$sig", 0x00>; +} + +// UNIQUE block - assumes unique execution path +let isTerminator = 0, isBarrier = 0, hasCtrlDep = 1, Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { +defm BLOCK_UNIQUE : NRI<(outs), (ins Signature:$sig), + [], + "block.unique\t$sig", 0x00>; +} + +// Inference block instructions: side-effect operations like exception handling +let hasCtrlDep = 1, hasSideEffects = 1, Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { +defm INFERENCE_FORALL : NRI<(outs), (ins), [], "forall", 0x00>; +defm INFERENCE_EXISTS : NRI<(outs), (ins), [], "exists", 0x00>; +defm INFERENCE_ASSUME : NRI<(outs), (ins), [], "assume", 0x00>; +defm INFERENCE_UNIQUE : NRI<(outs), (ins), [], "unique", 0x00>; + +// End markers for inference blocks (generate regular 'end' instruction) +defm INFERENCE_FORALL_END : NRI<(outs), (ins), [], "end", 0x0b>; +defm INFERENCE_EXISTS_END : NRI<(outs), (ins), [], "end", 0x0b>; +defm INFERENCE_ASSUME_END : NRI<(outs), (ins), [], "end", 0x0b>; +defm INFERENCE_UNIQUE_END : NRI<(outs), (ins), [], "end", 0x0b>; +} + +// Patterns to connect chain-based SDNodes to inference block instructions +// Note: These patterns expect chain inputs but our instructions have no operands +// This approach may need a different strategy + diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index b5e723e2a48d3..5244820703c36 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -113,6 +113,9 @@ def SDT_WebAssemblyWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; def SDT_WebAssemblyGlobalGet : SDTypeProfile<1, 1, [SDTCisPtrTy<1>]>; def SDT_WebAssemblyGlobalSet : SDTypeProfile<0, 2, [SDTCisPtrTy<1>]>; +def SDT_WebAssemblyUzumakiI32 : SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>; +def SDT_WebAssemblyUzumakiI64 : SDTypeProfile<1, 0, [SDTCisVT<0, i64>]>; +def SDT_WebAssemblyChainVoid : SDTypeProfile<1, 1, []>; //===----------------------------------------------------------------------===// // WebAssembly-specific DAG Nodes. @@ -142,6 +145,31 @@ def WebAssemblyglobal_get : def WebAssemblyglobal_set : SDNode<"WebAssemblyISD::GLOBAL_SET", SDT_WebAssemblyGlobalSet, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; +def WebAssemblyuzumaki_i32 : SDNode<"WebAssemblyISD::UZUMAKI_I32", + SDT_WebAssemblyUzumakiI32>; +def WebAssemblyuzumaki_i64 : SDNode<"WebAssemblyISD::UZUMAKI_I64", + SDT_WebAssemblyUzumakiI64>; + +// Inference block SDNodes +def WebAssemblyforall_start : SDNode<"WebAssemblyISD::BLOCK_FORALL", + SDT_WebAssemblyChainVoid, [SDNPHasChain]>; +def WebAssemblyexists_start : SDNode<"WebAssemblyISD::BLOCK_EXISTS", + SDT_WebAssemblyChainVoid, [SDNPHasChain]>; +def WebAssemblyassume_start : SDNode<"WebAssemblyISD::BLOCK_ASSUME", + SDT_WebAssemblyChainVoid, [SDNPHasChain]>; +def WebAssemblyunique_start : SDNode<"WebAssemblyISD::BLOCK_UNIQUE", + SDT_WebAssemblyChainVoid, [SDNPHasChain]>; + +// Inference block end markers (use regular 'end' instruction) +def WebAssemblyforall_end : SDNode<"WebAssemblyISD::BLOCK_FORALL_END", + SDT_WebAssemblyChainVoid, [SDNPHasChain]>; +def WebAssemblyexists_end : SDNode<"WebAssemblyISD::BLOCK_EXISTS_END", + SDT_WebAssemblyChainVoid, [SDNPHasChain]>; +def WebAssemblyassume_end : SDNode<"WebAssemblyISD::BLOCK_ASSUME_END", + SDT_WebAssemblyChainVoid, [SDNPHasChain]>; +def WebAssemblyunique_end : SDNode<"WebAssemblyISD::BLOCK_UNIQUE_END", + SDT_WebAssemblyChainVoid, [SDNPHasChain]>; + def WebAssemblylocal_get : SDNode<"WebAssemblyISD::LOCAL_GET", SDT_WebAssemblyLocalGet, [SDNPHasChain, SDNPMayLoad]>; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td index d4c8f92c883e7..c8870feeb4649 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td @@ -86,6 +86,16 @@ defm CLZ : UnaryInt; defm CTZ : UnaryInt; defm POPCNT : UnaryInt; +// Uzumaki custom value operations: nullary nodes producing a value. +// These are matched directly from the custom SDNodes with no operands; +// the actual opcode bytes are emitted in WebAssemblyAsmPrinter. +defm UZUMAKI_I32 : I<(outs I32:$dst), (ins), (outs), (ins), + [(set I32:$dst, (WebAssemblyuzumaki_i32))], + "i32.uzumaki\t$dst", "i32.uzumaki", 0x00>; +defm UZUMAKI_I64 : I<(outs I64:$dst), (ins), (outs), (ins), + [(set I64:$dst, (WebAssemblyuzumaki_i64))], + "i64.uzumaki\t$dst", "i64.uzumaki", 0x00>; + defm EQZ_I32 : I<(outs I32:$dst), (ins I32:$src), (outs), (ins), [(set I32:$dst, (setcc I32:$src, 0, SETEQ))], "i32.eqz \t$dst, $src", "i32.eqz", 0x45>; From bae8e514e46e95ae1b665f4d43c481b410a7d678 Mon Sep 17 00:00:00 2001 From: Georgii Plotnikov Date: Tue, 9 Dec 2025 15:25:06 +0900 Subject: [PATCH 2/3] Optimizing td --- llvm/include/llvm/IR/IntrinsicsWebAssembly.td | 20 ++++----- .../WebAssembly/WebAssemblyInstrControl.td | 43 +++---------------- .../WebAssembly/WebAssemblyInstrInteger.td | 4 +- 3 files changed, 17 insertions(+), 50 deletions(-) diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td index f020b6bcdecf9..0273b69de8602 100644 --- a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td +++ b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td @@ -121,10 +121,10 @@ def int_wasm_trunc_saturate_unsigned : // Uzumaki intrinsics def int_wasm_uzumaki_i32 : - DefaultAttrsIntrinsic<[llvm_i32_ty], [], [IntrNoMem, IntrHasSideEffects]>; + DefaultAttrsIntrinsic<[llvm_i32_ty], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; def int_wasm_uzumaki_i64 : - DefaultAttrsIntrinsic<[llvm_i64_ty], [], [IntrNoMem, IntrHasSideEffects]>; + DefaultAttrsIntrinsic<[llvm_i64_ty], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; //===----------------------------------------------------------------------===// // Inference block intrinsics @@ -135,28 +135,28 @@ def int_wasm_uzumaki_i64 : // transforms into proper blocks def int_wasm_forall_start : - DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; def int_wasm_forall_end : - DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; def int_wasm_exists_start : - DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; def int_wasm_exists_end : - DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; def int_wasm_assume_start : - DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; def int_wasm_assume_end : - DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; def int_wasm_unique_start : - DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; def int_wasm_unique_end : - DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects]>; + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; //===----------------------------------------------------------------------===// // Exception handling intrinsics diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td index a390427fb0e6e..d2359e3be26f8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -210,49 +210,16 @@ defm DELEGATE : NRI<(outs), (ins bb_op:$dst), [], "delegate \t $dst", 0x18>; // Inference block instructions //===----------------------------------------------------------------------===// -// FORALL block - considers all execution paths -let isTerminator = 0, isBarrier = 0, hasCtrlDep = 1, Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { -defm BLOCK_FORALL : NRI<(outs), (ins Signature:$sig), - [], - "block.forall\t$sig", 0x00>; -} - -// EXISTS block - considers existence of execution path -let isTerminator = 0, isBarrier = 0, hasCtrlDep = 1, Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { -defm BLOCK_EXISTS : NRI<(outs), (ins Signature:$sig), - [], - "block.exists\t$sig", 0x00>; -} - -// ASSUME block - defines assumptions about program state -let isTerminator = 0, isBarrier = 0, hasCtrlDep = 1, Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { -defm BLOCK_ASSUME : NRI<(outs), (ins Signature:$sig), - [], - "block.assume\t$sig", 0x00>; -} - -// UNIQUE block - assumes unique execution path -let isTerminator = 0, isBarrier = 0, hasCtrlDep = 1, Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { -defm BLOCK_UNIQUE : NRI<(outs), (ins Signature:$sig), - [], - "block.unique\t$sig", 0x00>; -} - // Inference block instructions: side-effect operations like exception handling let hasCtrlDep = 1, hasSideEffects = 1, Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { -defm INFERENCE_FORALL : NRI<(outs), (ins), [], "forall", 0x00>; -defm INFERENCE_EXISTS : NRI<(outs), (ins), [], "exists", 0x00>; -defm INFERENCE_ASSUME : NRI<(outs), (ins), [], "assume", 0x00>; -defm INFERENCE_UNIQUE : NRI<(outs), (ins), [], "unique", 0x00>; +defm INFERENCE_FORALL : NRI<(outs), (ins), [], "forall", 0xfc3a>; +defm INFERENCE_EXISTS : NRI<(outs), (ins), [], "exists", 0xfc3b>; +defm INFERENCE_ASSUME : NRI<(outs), (ins), [], "assume", 0xfc3c>; +defm INFERENCE_UNIQUE : NRI<(outs), (ins), [], "unique", 0xfc3d>; // End markers for inference blocks (generate regular 'end' instruction) defm INFERENCE_FORALL_END : NRI<(outs), (ins), [], "end", 0x0b>; defm INFERENCE_EXISTS_END : NRI<(outs), (ins), [], "end", 0x0b>; defm INFERENCE_ASSUME_END : NRI<(outs), (ins), [], "end", 0x0b>; defm INFERENCE_UNIQUE_END : NRI<(outs), (ins), [], "end", 0x0b>; -} - -// Patterns to connect chain-based SDNodes to inference block instructions -// Note: These patterns expect chain inputs but our instructions have no operands -// This approach may need a different strategy - +} \ No newline at end of file diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td index c8870feeb4649..76824ac16f402 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInteger.td @@ -91,10 +91,10 @@ defm POPCNT : UnaryInt; // the actual opcode bytes are emitted in WebAssemblyAsmPrinter. defm UZUMAKI_I32 : I<(outs I32:$dst), (ins), (outs), (ins), [(set I32:$dst, (WebAssemblyuzumaki_i32))], - "i32.uzumaki\t$dst", "i32.uzumaki", 0x00>; + "i32.uzumaki\t$dst", "i32.uzumaki", 0xfc31>; defm UZUMAKI_I64 : I<(outs I64:$dst), (ins), (outs), (ins), [(set I64:$dst, (WebAssemblyuzumaki_i64))], - "i64.uzumaki\t$dst", "i64.uzumaki", 0x00>; + "i64.uzumaki\t$dst", "i64.uzumaki", 0xfc32>; defm EQZ_I32 : I<(outs I32:$dst), (ins I32:$src), (outs), (ins), [(set I32:$dst, (setcc I32:$src, 0, SETEQ))], From 2348e47b040113fdff88446f9dce19488db6f8d2 Mon Sep 17 00:00:00 2001 From: Georgii Plotnikov Date: Wed, 31 Dec 2025 17:38:32 +0900 Subject: [PATCH 3/3] Add macos build --- .../build-inference-llvm-artifacts.yml | 172 +++++------------- 1 file changed, 48 insertions(+), 124 deletions(-) diff --git a/.github/workflows/build-inference-llvm-artifacts.yml b/.github/workflows/build-inference-llvm-artifacts.yml index 520aa9860bfbf..ecd28bc814e09 100644 --- a/.github/workflows/build-inference-llvm-artifacts.yml +++ b/.github/workflows/build-inference-llvm-artifacts.yml @@ -16,6 +16,7 @@ jobs: name: Build LLVM Static Libraries (${{ matrix.os }}) runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: include: - os: ubuntu-latest @@ -24,6 +25,9 @@ jobs: - os: windows-latest platform: Windows arch: x64 + - os: macos-14 + platform: macOS + arch: arm64 steps: - name: Checkout Repository @@ -43,6 +47,8 @@ jobs: zlib1g-dev elif [ "$RUNNER_OS" == "Windows" ]; then choco install ninja cmake + elif [ "$RUNNER_OS" == "macOS" ]; then + brew install ninja fi shell: bash @@ -53,8 +59,14 @@ jobs: # Platform-specific flags EXTRA_FLAGS="" - if [ "$RUNNER_OS" != "Windows" ]; then + + # Disable PIC only on Linux for smaller static libraries + # macOS and Windows keep PIC enabled (required by their toolchains) + if [ "$RUNNER_OS" == "Linux" ]; then EXTRA_FLAGS="-DLLVM_ENABLE_PIC=OFF" + elif [ "$RUNNER_OS" == "macOS" ]; then + # Use default system configuration for macOS + EXTRA_FLAGS="-DCMAKE_POSITION_INDEPENDENT_CODE=ON" fi cmake -G Ninja \ @@ -62,7 +74,7 @@ jobs: -DLLVM_TARGETS_TO_BUILD="WebAssembly;X86" \ -DLLVM_BUILD_LLVM_DYLIB=OFF \ -DLLVM_LINK_LLVM_DYLIB=OFF \ - -DLLVM_BUILD_STATIC=ON \ + -DBUILD_SHARED_LIBS=OFF \ -DLLVM_ENABLE_TERMINFO=OFF \ -DLLVM_ENABLE_ZLIB=OFF \ -DLLVM_ENABLE_ZSTD=OFF \ @@ -81,6 +93,8 @@ jobs: cd build-static if [ "$RUNNER_OS" == "Windows" ]; then ninja -j4 # Limit parallelism on Windows to avoid memory issues + elif [ "$RUNNER_OS" == "macOS" ]; then + ninja -j$(sysctl -n hw.ncpu) else ninja -j$(nproc) fi @@ -179,50 +193,6 @@ jobs: EOF chmod +x llvm-package/setup-env.sh shell: bash - - - name: Create Documentation - run: | - # Create a README - cat > llvm-package/README.md << 'EOF' - # LLVM Inference Static Build - - This package contains statically-linked LLVM libraries with custom Inference intrinsics. - - ## Usage with Rust - - 1. Extract this archive - 2. Set environment variable: - ```bash - export LLVM_SYS_211_PREFIX=/path/to/extracted/artifact - ``` - 3. Build your Rust project: - ```bash - cargo build --release - ``` - - ## Files Included - - - `lib/*.a` - Static LLVM libraries - - `include/` - LLVM headers - - `bin/llvm-config` - LLVM configuration tool - - `bin/llc` - LLVM static compiler - - `bin/llvm-as` - LLVM assembler - - `bin/llvm-dis` - LLVM disassembler - - `bin/llvm-link` - LLVM linker - - `bin/opt` - LLVM optimizer - - `bin/wasm-ld` - WebAssembly linker - - `setup-env.sh` - Environment setup script - - ## Custom Features - - This build includes: - - Uzumaki intrinsics (i32/i64) - - Inference block types (forall, exists, assume, unique) - - WebAssembly target support - - Built from: ${{ github.repository }}@${{ github.sha }} - EOF - shell: bash - name: Create Build Info run: | @@ -246,26 +216,32 @@ jobs: if [ "$RUNNER_OS" == "Windows" ]; then # Use zip for Windows - package contents directly without parent directory cd llvm-package - 7z a -tzip ../${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip * + 7z a -tzip ../${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.zip * cd .. # Create checksum - certutil -hashfile ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip SHA256 > ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip.sha256 + certutil -hashfile ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.zip SHA256 > ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.zip.sha256 + elif [ "$RUNNER_OS" == "macOS" ]; then + # Use tar.gz for macOS - package contents directly without parent directory + tar -czf ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz -C llvm-package . + + # Create checksum using shasum + shasum -a 256 ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz > ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz.sha256 else # Use tar.gz for Linux - package contents directly without parent directory - tar -czf ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz -C llvm-package . + tar -czf ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz -C llvm-package . - # Create checksum - sha256sum ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz > ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz.sha256 + # Create checksum using sha256sum + sha256sum ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz > ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz.sha256 fi shell: bash - name: Upload Build Artifacts uses: actions/upload-artifact@v4 with: - name: ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64 + name: ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }} path: | - ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.* + ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.* retention-days: 90 compression-level: 0 # Already compressed @@ -274,26 +250,26 @@ jobs: echo "📦 Artifact Package Created" echo "==========================" if [ "$RUNNER_OS" == "Windows" ]; then - ls -lh ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip + ls -lh ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.zip echo "" echo "📋 Checksum:" - cat ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip.sha256 + cat ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.zip.sha256 echo "" echo "📊 Package Contents (first 20 entries):" # Ignore broken pipe so 7z listing doesn't fail the step set +e - 7z l ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip | head -20 + 7z l ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.zip | head -20 set -e else - ls -lh ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz + ls -lh ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz echo "" echo "📋 Checksum:" - cat ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz.sha256 + cat ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz.sha256 echo "" echo "📊 Package Contents (first 20 entries):" # Ignore broken pipe so tar listing doesn't fail the step set +e - tar -tzf ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz | head -20 + tar -tzf ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz | head -20 set -e fi shell: bash @@ -358,6 +334,13 @@ jobs: # Set environment variables manually or use setup-env.sh in Git Bash ``` + **macOS:** + ```bash + mkdir llvm-inference && cd llvm-inference + tar -xzf ../${{ env.ARTIFACT_NAME }}-macOS-x64.tar.gz + source setup-env.sh + ``` + Then build your Rust project: ```bash cargo build --release @@ -377,75 +360,16 @@ jobs: certutil -hashfile ${{ env.ARTIFACT_NAME }}-Windows-x64.zip SHA256 ``` + **macOS:** + ```bash + shasum -a 256 -c ${{ env.ARTIFACT_NAME }}-macOS-x64.tar.gz.sha256 + ``` + **Commit:** ${{ github.sha }} **Branch:** ${{ github.ref_name }} files: | artifacts/**/*.tar.gz + artifacts/**/*.zip artifacts/**/*.sha256 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - test-artifact: - name: Test Artifact with Sample Rust Project (${{ matrix.platform }}) - needs: build-llvm - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - - os: ubuntu-latest - platform: Linux - - os: windows-latest - platform: Windows - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Rust - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - toolchain: stable - - - name: Download LLVM Artifact - uses: actions/download-artifact@v4 - with: - name: ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64 - path: llvm-artifact - - - name: Extract and Setup LLVM - run: | - mkdir -p llvm-extract - cd llvm-extract - if [ "$RUNNER_OS" == "Windows" ]; then - 7z x ../llvm-artifact/${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.zip - else - tar -xzf ../llvm-artifact/${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-x64.tar.gz - fi - source setup-env.sh - - # Verify llvm-config works - $LLVM_CONFIG_PATH --version - - echo "LLVM_SYS_211_PREFIX=$LLVM_SYS_211_PREFIX" >> $GITHUB_ENV - echo "LLVM_CONFIG_PATH=$LLVM_CONFIG_PATH" >> $GITHUB_ENV - shell: bash - - - name: Create Test Rust Project - run: | - # Create a minimal test if it doesn't exist - if [ ! -f "Cargo.toml" ]; then - cat > test-llvm.rs << 'EOF' - fn main() { - println!("LLVM artifact test successful!"); - } - EOF - rustc test-llvm.rs -o test-llvm - ./test-llvm - fi - shell: bash - - - name: Build Test (if Cargo.toml exists) - if: hashFiles('Cargo.toml') != '' - run: | - cargo build --release - echo "✅ Test build completed successfully!"