diff --git a/.github/workflows/build-inference-llvm-artifacts.yml b/.github/workflows/build-inference-llvm-artifacts.yml new file mode 100644 index 0000000000000..ecd28bc814e09 --- /dev/null +++ b/.github/workflows/build-inference-llvm-artifacts.yml @@ -0,0 +1,375 @@ +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: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + platform: Linux + arch: x64 + - os: windows-latest + platform: Windows + arch: x64 + - os: macos-14 + platform: macOS + arch: arm64 + + 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 + elif [ "$RUNNER_OS" == "macOS" ]; then + brew install ninja + fi + shell: bash + + - name: Configure LLVM for Static Linking + run: | + mkdir -p build-static + cd build-static + + # Platform-specific flags + EXTRA_FLAGS="" + + # 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 \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_TARGETS_TO_BUILD="WebAssembly;X86" \ + -DLLVM_BUILD_LLVM_DYLIB=OFF \ + -DLLVM_LINK_LLVM_DYLIB=OFF \ + -DBUILD_SHARED_LIBS=OFF \ + -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 + elif [ "$RUNNER_OS" == "macOS" ]; then + ninja -j$(sysctl -n hw.ncpu) + 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 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 }}-${{ matrix.arch }}.zip * + cd .. + + # Create checksum + 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 }}-${{ matrix.arch }}.tar.gz -C llvm-package . + + # 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 }}-${{ matrix.arch }} + path: | + ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.* + 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 }}-${{ matrix.arch }}.zip + echo "" + echo "📋 Checksum:" + 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 }}-${{ matrix.arch }}.zip | head -20 + set -e + else + ls -lh ${{ env.ARTIFACT_NAME }}-${{ matrix.platform }}-${{ matrix.arch }}.tar.gz + echo "" + echo "📋 Checksum:" + 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 }}-${{ matrix.arch }}.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 + ``` + + **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 + ``` + + ### 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 + ``` + + **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 }} diff --git a/llvm/include/llvm/IR/IntrinsicsWebAssembly.td b/llvm/include/llvm/IR/IntrinsicsWebAssembly.td index f592ff287a0e3..0273b69de8602 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, IntrConvergent]>; + +def int_wasm_uzumaki_i64 : + DefaultAttrsIntrinsic<[llvm_i64_ty], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; + +//===----------------------------------------------------------------------===// +// 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, IntrConvergent]>; + +def int_wasm_forall_end : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; + +def int_wasm_exists_start : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; + +def int_wasm_exists_end : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; + +def int_wasm_assume_start : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; + +def int_wasm_assume_end : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; + +def int_wasm_unique_start : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; + +def int_wasm_unique_end : + DefaultAttrsIntrinsic<[], [], [IntrNoMem, IntrHasSideEffects, IntrConvergent]>; + //===----------------------------------------------------------------------===// // 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..d2359e3be26f8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -205,3 +205,21 @@ 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 +//===----------------------------------------------------------------------===// + +// 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", 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>; +} \ No newline at end of file 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..76824ac16f402 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", 0xfc31>; +defm UZUMAKI_I64 : I<(outs I64:$dst), (ins), (outs), (ins), + [(set I64:$dst, (WebAssemblyuzumaki_i64))], + "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))], "i32.eqz \t$dst, $src", "i32.eqz", 0x45>;