diff --git a/.github/workflows/build-paddlepaddle.yml b/.github/workflows/build-paddlepaddle.yml new file mode 100644 index 00000000000..48ae76fcce2 --- /dev/null +++ b/.github/workflows/build-paddlepaddle.yml @@ -0,0 +1,282 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# Paddle publishes no wheel workflow on GitHub; ci/run_setup.sh is the script +# its own CI drives, so this mirrors that script's Linux CPU environment and +# its `python setup.py bdist_wheel` invocation, narrowed to riscv64. +name: Build paddlepaddle wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'Version glob to (re)build; empty builds every version of docs/packages/paddlepaddle.yaml not released yet' + required: false + default: '' + pull_request: + branches: [main] + paths: + - '.github/workflows/build-paddlepaddle.yml' + - 'docs/packages/paddlepaddle.yaml' + - 'patches/paddlepaddle/**' + push: + branches: [main] + paths: + - '.github/workflows/build-paddlepaddle.yml' + - 'docs/packages/paddlepaddle.yaml' + - 'patches/paddlepaddle/**' + +run-name: build-paddlepaddle ${{ inputs.version && format('- {0}', inputs.version) || '' }} + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + with: + package: paddlepaddle + version: ${{ inputs.version }} + + build_wheels: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + name: Build paddlepaddle ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 2880 # 48h: 1.3M lines of heavily templated C++ plus the + # third_party world, on the same 4-core runners that + # need this budget for build-vtk.yml. + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + # libpaddle.so links CPython directly, so every interpreter rebuilds the + # whole tree. cp313 is the newest upstream publishes for this release. + python: ["cp312", "cp313"] + + env: + PADDLE_VERSION: ${{ matrix.version }} + + steps: + - name: Checkout Paddle v${{ matrix.version }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: PaddlePaddle/Paddle + ref: v${{ matrix.version }} + path: Paddle + # `git submodule update --init`, as ci/run_setup.sh runs it: cmake + # skips its own submodule step under WITH_SETUP_INSTALL. + submodules: true + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + - name: Patch Paddle source + working-directory: Paddle + run: | + git apply ../python-wheels/patches/paddlepaddle/${{ matrix.version }}/*.patch + + # The recorded submodule commit is a 0.3.7-era tree that knows no riscv64 + # target; openblas.cmake means to move it to CBLAS_TAG itself, but its + # `git checkout v0.3.28` fails silently against a tagless submodule clone. + - name: Move the OpenBLAS submodule to the tag openblas.cmake builds + working-directory: Paddle/third_party/openblas + run: | + git fetch --depth 1 origin tag v0.3.28 + git checkout v0.3.28 + + # gloo.cmake and protobuf.cmake make `git checkout ` an + # ExternalProject patch step, which aborts the build against the tagless + # submodule clone; both tags already name the recorded commit, so only the + # ref is missing and no checkout of our own is needed. + - name: Fetch the submodule tags the third_party patch steps check out + run: | + git -C Paddle/third_party/gloo fetch --depth 1 origin tag v0.0.3 + git -C Paddle/third_party/protobuf fetch --depth 1 origin tag v21.12 + + # Parity with build-vtk.yml's own guard, though swapon fails on these + # runners (/ is overlayfs), so 15GB of RAM is the real link budget. + - name: Set swap space + uses: pierotofy/set-swap-space@fc79b3f67fa8a838184ce84a674ca12238d2c761 # master + with: + swap-size-gb: 10 + + - name: Write container script + run: | + cat > Paddle/riscv64-build-and-test.sh <<'EOF' + #!/bin/bash + set -e -x + + python_exe="/opt/python/${PYTHON_TAG}-${PYTHON_TAG}/bin/python" + py_version="${PYTHON_TAG#cp}" + py_version="${py_version:0:1}.${py_version:1}" + + case "$1" in + build) + # patch 3/5 resolves LAPACK_LIB/BLAS_LIB/GFORTRAN_LIB to these, in + # place of an x86-64-only prebuilt tarball; libgfortran comes with + # them, and riscv64 has no libquadmath to ask for. + dnf install -y --setopt=install_weak_deps=False lapack blas + + "${python_exe}" -m pip install -U pip setuptools wheel + "${python_exe}" -m pip install -r /paddle/python/requirements.txt + "${python_exe}" -m pip install -r /paddle/paddle/scripts/compile_requirements.txt + # The operator generators under paddle/fluid/operators/generator/ + # import yaml, which upstream's own build image preinstalls rather + # than declaring in either requirements file. + "${python_exe}" -m pip install pyyaml + + export PYTHON_EXECUTABLE="${python_exe}" + export PY_VERSION="${py_version}" + export CMAKE_BUILD_TYPE=Release + export WITH_RISCV=ON + export WITH_GPU=OFF + export WITH_ROCM=OFF + export WITH_XPU=OFF + export WITH_IPU=OFF + export WITH_TENSORRT=OFF + export WITH_OPENVINO=OFF + export WITH_ONNXRUNTIME=OFF + export WITH_CUDNN_FRONTEND=OFF + export WITH_CINN=OFF + export WITH_DISTRIBUTE=OFF + export WITH_PYTHON=ON + export WITH_TESTING=OFF + export WITH_CPP_TEST=OFF + export WITH_INFERENCE_API_TEST=OFF + export ON_INFER=OFF + export WITH_STRIP=ON + # The released Linux wheels split phi and pir out of libpaddle.so; + # a single object would not link in this runner's memory. + export WITH_SHARED_PHI=ON + export WITH_SHARED_IR=ON + export MAX_JOBS="$(nproc)" + + cd /paddle + "${python_exe}" setup.py bdist_wheel + + auditwheel show dist/*.whl + auditwheel repair -w /paddle/wheelhouse dist/*.whl + ;; + test) + "${python_exe}" -m venv /tmp/venv + . /tmp/venv/bin/activate + pip install -U pip + pip install /paddle/wheelhouse/*.whl + cd /tmp + # Upstream's documented post-install verification. + python -c "import paddle; paddle.utils.run_check()" + # Exercises the liblapack.so.3 patch 3/5 puts in paddle/libs/. + python -c "import paddle; x = paddle.rand([8, 8]); q, r = paddle.linalg.qr(x); assert paddle.allclose(q @ r, x, atol=1e-5)" + ;; + *) + echo "usage: $0 " >&2 + exit 1 + ;; + esac + EOF + + # numpy and Pillow of python/requirements.txt have riscv64 wheels only on + # our registry; only-binary keeps a newer PyPI release from winning the + # resolution and then compiling from sdist (Pillow's needs libjpeg headers + # the image does not carry). + - name: Build wheel + run: | + podman run -t \ + --log-driver=none \ + --network=host \ + -v "${PWD}/Paddle":/paddle \ + --workdir /paddle \ + -e PYTHON_TAG="${{ matrix.python }}" \ + -e PADDLE_VERSION="${PADDLE_VERSION}" \ + -e PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ \ + -e PIP_ONLY_BINARY=numpy,pillow \ + --pull=newer \ + "${MANYLINUX_RISCV64_IMAGE}" \ + bash /paddle/riscv64-build-and-test.sh build + + # Paddle's EXTERNAL_PROJECT_LOG_ARGS sends every third_party configure and + # install step to a stamp log instead of stdout, so a failure there says + # only "Command failed: 1" in the step above. + - name: Show third_party stamp logs + if: failure() + run: | + tail -n 40 -v Paddle/build/third_party/*/src/*-stamp/*-*-*.log || true + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: paddlepaddle-${{ env.PADDLE_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: Paddle/wheelhouse/*.whl + if-no-files-found: error + + - name: Test wheel + run: | + podman run -t \ + --log-driver=none \ + --network=host \ + -v "${PWD}/Paddle":/paddle \ + --workdir /paddle \ + -e PYTHON_TAG="${{ matrix.python }}" \ + -e PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ \ + -e PIP_ONLY_BINARY=numpy,pillow \ + "${MANYLINUX_RISCV64_IMAGE}" \ + bash /paddle/riscv64-build-and-test.sh test + + gpl_sources: + needs: [setup] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + name: Collect GPL sources (gcc) for paddlepaddle ${{ matrix.version }} + runs-on: ubuntu-24.04-riscv + env: + PADDLE_VERSION: ${{ matrix.version }} + + steps: + # setup.py copies GFORTRAN_LIB and GNU_RT_LIB_1 into paddle/libs/, which + # patch 3/5 resolves to the image's own libgfortran.so.5 and + # libquadmath.so.0. + - name: Collect gcc source RPM from manylinux_riscv64 + uses: riseproject-dev/python-wheels/actions/collect-gpl-sources@main + with: + image: ${{ env.MANYLINUX_RISCV64_IMAGE }} + packages: gcc + output: gpl-sources.tar + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: paddlepaddle-${{ env.PADDLE_VERSION }}-gpl-sources + path: gpl-sources.tar + if-no-files-found: error + + publish: + name: Publish paddlepaddle ${{ matrix.version }} + needs: [setup, build_wheels, gpl_sources] + if: needs.setup.outputs.versions != '[]' + strategy: + fail-fast: false + matrix: + version: ${{ fromJSON(needs.setup.outputs.versions) }} + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + secrets: + app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }} + with: + artifact-pattern: paddlepaddle-${{ matrix.version }}-*-manylinux_riscv64 + gpl-sources-artifact: paddlepaddle-${{ matrix.version }}-gpl-sources + gpl-sources-description: gcc diff --git a/docs/packages/paddlepaddle.yaml b/docs/packages/paddlepaddle.yaml new file mode 100644 index 00000000000..bd00fd88243 --- /dev/null +++ b/docs/packages/paddlepaddle.yaml @@ -0,0 +1,5 @@ +package-name: paddlepaddle +source-code: https://github.com/PaddlePaddle/Paddle +license: Apache-2.0 +versions: +- version: 3.3.1 diff --git a/patches/paddlepaddle/3.3.1/0001-Add-a-WITH_RISCV-build-option.patch b/patches/paddlepaddle/3.3.1/0001-Add-a-WITH_RISCV-build-option.patch new file mode 100644 index 00000000000..dbb70736de3 --- /dev/null +++ b/patches/paddlepaddle/3.3.1/0001-Add-a-WITH_RISCV-build-option.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000001 Mon Sep 17 00:00:00 2001 +From: RISE Project CI +Date: Fri, 19 Sep 2026 00:00:00 +0000 +Subject: [PATCH 1/5] Add a WITH_RISCV build option + +riscv64 is the first architecture Paddle's CMake knows nothing about: +WITH_ARM, WITH_SW, WITH_MIPS and WITH_LOONGARCH each turn off the +x86-only pieces (Xbyak's x86 JIT assembler, MKL, AVX) and define a +PADDLE_WITH_ macro the C++ tree tests, but there is no equivalent +for riscv64, so a riscv64 build takes every x86 branch. + +WITH_RISCV mirrors the WITH_LOONGARCH block, plus three riscv64-specific +additions: + + - WITH_SLEEF=OFF, set through upstream's own WITH_SLEEF_DEFAULT switch + rather than from the WITH_RISCV block, because cmake/third_party.cmake + is included at CMakeLists.txt:591, long before that block: a + set(WITH_SLEEF OFF ... FORCE) there is read too late, after + cmake/sleef.cmake has already run add_definitions(-DPADDLE_WITH_SLEEF), + and only paddle/phi/CMakeLists.txt's `if(WITH_SLEEF) list(APPEND + PHI_DEPS sleef)` still sees the OFF - compiling the SLEEF path without + linking SLEEF. SLEEF 3.6.1 cannot serve Paddle on riscv64 in any case: + src/libm/CMakeLists.txt leaves DSP_SCALAR out of SLEEF_ARCH_RISCV64's + header list, alone among the six architectures, and DSP_SCALAR is the + only entry with no ISA name, i.e. the only one mkrename.c emits the + unsuffixed scalar declarations from. The generated riscv64 sleef.h + therefore declares Sleef_sinf1_u35purec but never Sleef_sinf1_u35, + which is what paddle/phi/kernels/funcs/activation_functor.h calls + under PADDLE_WITH_SLEEF. WIN32 and WITH_ROCM already take this same + SLEEF-less configuration. + + - -latomic on the link lines. riscv64 has no inline instructions for + 1- and 2-byte atomics, so GCC emits libatomic calls; without this + libpaddle.so fails to load with "undefined symbol: + __atomic_exchange_1", as reported for a native riscv64 build in + PaddlePaddle/Paddle#62037. + + - cmake/flags.cmake's unconditional -m64, which riscv64 GCC rejects + ("unrecognized command line option '-m64'"), gated the same way the + other non-x86 architectures already gate it. + +Upstream-Status: To upstream + +Paddle builds linux_aarch64 wheels from WITH_ARM but has no riscv64 CI +to validate a WITH_RISCV option against, so submitting it upstream needs +a riscv64 build running there first. + +Signed-off-by: RISE Project CI +--- + CMakeLists.txt | 20 +++++++++++++++++++- + cmake/flags.cmake | 3 ++- + 2 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index a07b810..884b37d 100755 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -330,6 +330,7 @@ option(WITH_ARM "Compile PaddlePaddle with arm support" OFF) + option(WITH_SW "Compile PaddlePaddle with sw support" OFF) + option(WITH_MIPS "Compile PaddlePaddle with mips support" OFF) + option(WITH_LOONGARCH "Compile PaddlePaddle with loongarch support" OFF) ++option(WITH_RISCV "Compile PaddlePaddle with riscv support" OFF) + option(WITH_MUSL "Compile with musl libc instead of glibc" OFF) + option(WITH_UNITY_BUILD "Compile with UnityBuild mode" OFF) + option(WITH_STRIP "Strip so files of Whl packages" OFF) +@@ -356,5 +357,5 @@ + set(WITH_SLEEF_DEFAULT ON) +-if(WIN32 OR WITH_ROCM) ++if(WIN32 OR WITH_ROCM OR WITH_RISCV) + set(WITH_SLEEF_DEFAULT OFF) + endif() + option( +@@ -684,6 +685,23 @@ if(WITH_LOONGARCH) + add_definitions(-DPADDLE_WITH_LOONGARCH) + endif() + ++if(WITH_RISCV) ++ set(WITH_XBYAK ++ OFF ++ CACHE STRING "Disable XBYAK when compiling WITH_RISCV=ON" FORCE) ++ set(WITH_MKL ++ OFF ++ CACHE STRING "Disable MKL when compiling WITH_RISCV=ON." FORCE) ++ set(WITH_AVX ++ OFF ++ CACHE STRING "Disable AVX when compiling WITH_RISCV=ON." FORCE) ++ # riscv64 has no inline instructions for sub-word atomics, so GCC emits calls ++ # into libatomic that are otherwise left undefined in libpaddle.so. ++ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -latomic") ++ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -latomic") ++ add_definitions(-DPADDLE_WITH_RISCV) ++endif() ++ + if(WITH_ONEMKL) + add_definitions(-DPADDLE_WITH_ONEMKL) + endif() +diff --git a/cmake/flags.cmake b/cmake/flags.cmake +index 67269aa..f86b569 100644 +--- a/cmake/flags.cmake ++++ b/cmake/flags.cmake +@@ -225,7 +225,8 @@ if(NOT WIN32) + AND NOT WITH_ARM + AND NOT WITH_SW + AND NOT WITH_MIPS +- AND NOT WITH_LOONGARCH) ++ AND NOT WITH_LOONGARCH ++ AND NOT WITH_RISCV) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64") + endif() + endif() +-- +2.51.0 diff --git a/patches/paddlepaddle/3.3.1/0002-Guard-the-x86-CPUID-and-SSE-AVX-paths-on-riscv64.patch b/patches/paddlepaddle/3.3.1/0002-Guard-the-x86-CPUID-and-SSE-AVX-paths-on-riscv64.patch new file mode 100644 index 00000000000..d1b242d102a --- /dev/null +++ b/patches/paddlepaddle/3.3.1/0002-Guard-the-x86-CPUID-and-SSE-AVX-paths-on-riscv64.patch @@ -0,0 +1,140 @@ +From 0000000000000000000000000000000000000002 Mon Sep 17 00:00:00 2001 +From: RISE Project CI +Date: Fri, 19 Sep 2026 00:00:00 +0000 +Subject: [PATCH 2/5] Guard the x86 CPUID and SSE/AVX paths on riscv64 + +Four places select x86 intrinsics by listing every non-x86 architecture +Paddle knows about rather than by testing for x86, so any architecture +outside that list -- riscv64 here -- falls into the x86 branch and fails +to compile on / / : + + - paddle/phi/backends/cpu/cpu_info.{h,cc}: the __cpuid_count() helper + and MayIUse()'s CPUID feature probe. + - paddle/phi/core/platform/denormal.cc: DENORM_USE_INTRINSICS, which + pulls in for _MM_SET_FLUSH_ZERO_MODE. + - paddle/phi/kernels/funcs/search_compute.h: the include, + the AVX/SSE helper macros, and axpy()/axpy_noadd()'s architecture + cascade, whose non-x86 branch raises Unimplemented. + +Add PADDLE_WITH_RISCV to each list, in the same form the existing +entries use. The x86 intrinsics files that are *not* touched here are +already correct: paddle/phi/common/float16.h and both spin_lock.h copies +test __x86_64__/__i386__ directly, and the three +kernels/fusion/cpu/*avx* sources are dropped from the build when +AVX512F_FOUND is false. + +Upstream-Status: To upstream + +Same reason as patch 1/2: no riscv64 CI upstream to validate against +yet. + +Signed-off-by: RISE Project CI +--- + paddle/phi/backends/cpu/cpu_info.cc | 6 +++--- + paddle/phi/backends/cpu/cpu_info.h | 6 +++--- + paddle/phi/core/platform/denormal.cc | 3 ++- + paddle/phi/kernels/funcs/search_compute.h | 20 ++++++++++++-------- + 4 files changed, 20 insertions(+), 15 deletions(-) + +diff --git a/paddle/phi/backends/cpu/cpu_info.cc b/paddle/phi/backends/cpu/cpu_info.cc +index 3c492aa..ee93824 100644 +--- a/paddle/phi/backends/cpu/cpu_info.cc ++++ b/paddle/phi/backends/cpu/cpu_info.cc +@@ -149,9 +149,9 @@ bool MayIUse(const cpu_isa_t cpu_isa) { + if (cpu_isa == isa_any) { + return true; + } else { +-#if !defined(WITH_NV_JETSON) && !defined(PADDLE_WITH_ARM) && \ +- !defined(PADDLE_WITH_SW) && !defined(PADDLE_WITH_MIPS) && \ +- !defined(PADDLE_WITH_LOONGARCH) ++#if !defined(WITH_NV_JETSON) && !defined(PADDLE_WITH_ARM) && \ ++ !defined(PADDLE_WITH_SW) && !defined(PADDLE_WITH_MIPS) && \ ++ !defined(PADDLE_WITH_LOONGARCH) && !defined(PADDLE_WITH_RISCV) + std::array reg; + cpuid(reg.data(), 0); + int nIds = reg[0]; +diff --git a/paddle/phi/backends/cpu/cpu_info.h b/paddle/phi/backends/cpu/cpu_info.h +index 2feb294..4c2567e 100644 +--- a/paddle/phi/backends/cpu/cpu_info.h ++++ b/paddle/phi/backends/cpu/cpu_info.h +@@ -40,9 +40,9 @@ + #ifdef _WIN32 + #define cpuid(reg, x) __cpuidex(reg, x, 0) + #else +-#if !defined(WITH_NV_JETSON) && !defined(PADDLE_WITH_ARM) && \ +- !defined(PADDLE_WITH_SW) && !defined(PADDLE_WITH_MIPS) && \ +- !defined(PADDLE_WITH_LOONGARCH) ++#if !defined(WITH_NV_JETSON) && !defined(PADDLE_WITH_ARM) && \ ++ !defined(PADDLE_WITH_SW) && !defined(PADDLE_WITH_MIPS) && \ ++ !defined(PADDLE_WITH_LOONGARCH) && !defined(PADDLE_WITH_RISCV) + #include + inline void cpuid(int reg[4], int x) { + __cpuid_count(x, 0, reg[0], reg[1], reg[2], reg[3]); +diff --git a/paddle/phi/core/platform/denormal.cc b/paddle/phi/core/platform/denormal.cc +index 93c55e8..7b9e79c 100644 +--- a/paddle/phi/core/platform/denormal.cc ++++ b/paddle/phi/core/platform/denormal.cc +@@ -30,7 +30,8 @@ + + #if !defined(GCC_WITHOUT_INTRINSICS) && !defined(PADDLE_WITH_ARM) && \ + !defined(PADDLE_WITH_SW) && !defined(PADDLE_WITH_MIPS) && \ +- !defined(_WIN32) && !defined(PADDLE_WITH_LOONGARCH) ++ !defined(_WIN32) && !defined(PADDLE_WITH_LOONGARCH) && \ ++ !defined(PADDLE_WITH_RISCV) + #define DENORM_USE_INTRINSICS + #endif + +diff --git a/paddle/phi/kernels/funcs/search_compute.h b/paddle/phi/kernels/funcs/search_compute.h +index dbbd42c..3906dc0 100644 +--- a/paddle/phi/kernels/funcs/search_compute.h ++++ b/paddle/phi/kernels/funcs/search_compute.h +@@ -14,8 +14,9 @@ + + #pragma once + +-#if !defined(PADDLE_WITH_ARM) && !defined(PADDLE_WITH_SW) && \ +- !defined(PADDLE_WITH_MIPS) && !defined(PADDLE_WITH_LOONGARCH) ++#if !defined(PADDLE_WITH_ARM) && !defined(PADDLE_WITH_SW) && \ ++ !defined(PADDLE_WITH_MIPS) && !defined(PADDLE_WITH_LOONGARCH) && \ ++ !defined(PADDLE_WITH_RISCV) + #include + #endif + #include +@@ -100,8 +101,9 @@ void call_gemm_batched(const Context& dev_ctx, + } + } + +-#if !defined(PADDLE_WITH_ARM) && !defined(PADDLE_WITH_SW) && \ +- !defined(PADDLE_WITH_MIPS) && !defined(PADDLE_WITH_LOONGARCH) ++#if !defined(PADDLE_WITH_ARM) && !defined(PADDLE_WITH_SW) && \ ++ !defined(PADDLE_WITH_MIPS) && !defined(PADDLE_WITH_LOONGARCH) && \ ++ !defined(PADDLE_WITH_RISCV) + + #define __m256x __m256 + +@@ -141,8 +143,9 @@ inline void axpy(const T* x, T* y, size_t len, const T alpha) { + _mm256_add_px(_mm256_load_px(y + jjj), + _mm256_mul_px(mm_alpha, _mm256_load_px(x + jjj)))); + } +-#elif defined(PADDLE_WITH_ARM) || defined(PADDLE_WITH_SW) || \ +- defined(PADDLE_WITH_MIPS) || defined(PADDLE_WITH_LOONGARCH) ++#elif defined(PADDLE_WITH_ARM) || defined(PADDLE_WITH_SW) || \ ++ defined(PADDLE_WITH_MIPS) || defined(PADDLE_WITH_LOONGARCH) || \ ++ defined(PADDLE_WITH_RISCV) + PADDLE_THROW(common::errors::Unimplemented("axpy is not supported")); + #else + lll = len & ~SSE_CUT_LEN_MASK; +@@ -171,8 +174,9 @@ inline void axpy_noadd(const T* x, T* y, size_t len, const T alpha) { + for (jjj = 0; jjj < lll; jjj += AVX_STEP_SIZE) { + _mm256_store_px(y + jjj, _mm256_mul_px(mm_alpha, _mm256_load_px(x + jjj))); + } +-#elif defined(PADDLE_WITH_ARM) || defined(PADDLE_WITH_SW) || \ +- defined(PADDLE_WITH_MIPS) || defined(PADDLE_WITH_LOONGARCH) ++#elif defined(PADDLE_WITH_ARM) || defined(PADDLE_WITH_SW) || \ ++ defined(PADDLE_WITH_MIPS) || defined(PADDLE_WITH_LOONGARCH) || \ ++ defined(PADDLE_WITH_RISCV) + PADDLE_THROW(common::errors::Unimplemented("axpy_noadd is not supported")); + #else + lll = len & ~SSE_CUT_LEN_MASK; +-- +2.51.0 diff --git a/patches/paddlepaddle/3.3.1/0003-Take-liblapack-and-libblas-from-the-build-environment.patch b/patches/paddlepaddle/3.3.1/0003-Take-liblapack-and-libblas-from-the-build-environment.patch new file mode 100644 index 00000000000..5ceda2cb8d3 --- /dev/null +++ b/patches/paddlepaddle/3.3.1/0003-Take-liblapack-and-libblas-from-the-build-environment.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000003 Mon Sep 17 00:00:00 2001 +From: RISE Project CI +Date: Fri, 19 Sep 2026 00:00:00 +0000 +Subject: [PATCH 3/5] Take liblapack and libblas from the build environment + +cmake/external/lapack.cmake takes one prebuilt tarball for the whole of +Linux, lapack_lnx_v3.10.0.20210628.tar.gz on paddlepaddledeps.bj.bcebos.com, +and that tarball only ever held x86-64 binaries. Nothing links against +them -- paddle/phi/backends/dynload/lapack.cc dlopen()s liblapack.so.3 at +first use -- but setup.py copies LAPACK_LIB, BLAS_LIB, GFORTRAN_LIB and +GNU_RT_LIB_1 into paddle/libs/ unconditionally, so a non-x86 wheel ships +four x86-64 ELFs and every LAPACK-backed paddle.linalg op fails at +runtime. This is already true of the released +paddlepaddle-3.3.1-cp312-cp312-linux_aarch64.whl: its liblapack.so.3, +libblas.so.3 and libgfortran.so.3 all report "ELF 64-bit LSB shared +object, x86-64" next to a genuinely aarch64 libopenblas.so.0. + +Resolve the sonames out of the build environment instead, which is where +GFORTRAN_LIB has to come from on any architecture the tarball does not +cover, and fail at configure time rather than at wheel-packing time when +one is missing. Reference-LAPACK is what distributions package as +liblapack.so.3, so this keeps shipping the same ABI the tarball did. + +GNU_RT_LIB_1 is left unset, because libquadmath exists only where +__float128 is a type distinct from long double: GCC builds none for +riscv64 (nor for aarch64), and Rocky has no libquadmath package there at +all. setup.py copied it unconditionally, so make that copy conditional +the way the neighbouring GNU_RT_LIB_2 one already is -- not gated on any +architecture flag, since an empty GNU_RT_LIB_1 is the bug on every +platform GCC ships no libquadmath for. + +The cmake half is scoped to WITH_RISCV so the x86-64 and macOS builds +keep using the tarball, but the same fix would repair the aarch64 wheel. + +Upstream-Status: To upstream + +The cmake half depends on patch 1/5's WITH_RISCV option, so it can only +go upstream together with it; the setup.py half stands alone. + +Signed-off-by: RISE Project CI +--- + cmake/external/lapack.cmake | 23 +++++++++++++++++++++++ + setup.py | 9 +++++++-- + 2 files changed, 30 insertions(+), 2 deletions(-) + +diff --git a/cmake/external/lapack.cmake b/cmake/external/lapack.cmake +--- a/cmake/external/lapack.cmake ++++ b/cmake/external/lapack.cmake +@@ -19,6 +19,29 @@ + ${PADDLE_SOURCE_DIR}/third_party/lapack/${CMAKE_SYSTEM_NAME}) + set(LAPACK_INSTALL_DIR ${THIRD_PARTY_PATH}/install/lapack) + set(LAPACK_LIB_DIR ${LAPACK_INSTALL_DIR}/lib) ++ ++if(WITH_RISCV) ++ # paddlepaddledeps.bj.bcebos.com publishes lapack_lnx_v3.10.0.20210628.tar.gz ++ # as an x86-64 build only, so on any other Linux architecture the block below ++ # hands setup.py x86-64 ELFs to copy into paddle/libs/, which ++ # phi/backends/dynload/lapack.cc can then never dlopen. ++ macro(lapack_system_lib var soname) ++ execute_process( ++ COMMAND ${CMAKE_C_COMPILER} -print-file-name=${soname} ++ OUTPUT_VARIABLE ${var} ++ OUTPUT_STRIP_TRAILING_WHITESPACE) ++ if(NOT IS_ABSOLUTE "${${var}}") ++ message(FATAL_ERROR "WITH_RISCV needs ${soname} on the library path") ++ endif() ++ message(STATUS "Using ${${var}} for ${var}") ++ endmacro() ++ lapack_system_lib(LAPACK_LIB liblapack.so.3) ++ lapack_system_lib(BLAS_LIB libblas.so.3) ++ lapack_system_lib(GFORTRAN_LIB libgfortran.so.5) ++ # No GNU_RT_LIB_1: riscv64 GCC builds no libquadmath. ++ add_custom_target(extern_lapack) ++ return() ++endif() + + # Note(zhouwei): lapack need fortran compiler which many machines don't have, so use precompiled library. + # use lapack tag v3.10.0 on 06/28/2021 https://github.com/Reference-LAPACK/lapack +diff --git a/setup.py b/setup.py +--- a/setup.py ++++ b/setup.py +@@ -1564,12 +1564,17 @@ + os.path.basename(env_dict.get("LAPACK_LIB")), + os.path.basename(env_dict.get("BLAS_LIB")), + os.path.basename(env_dict.get("GFORTRAN_LIB")), +- os.path.basename(env_dict.get("GNU_RT_LIB_1")), + ] + shutil.copy(env_dict.get("BLAS_LIB"), libs_path) + shutil.copy(env_dict.get("LAPACK_LIB"), libs_path) + shutil.copy(env_dict.get("GFORTRAN_LIB"), libs_path) +- shutil.copy(env_dict.get("GNU_RT_LIB_1"), libs_path) ++ # libquadmath is built only where __float128 differs from long double, so ++ # there is none to ship on riscv64 or aarch64. ++ if env_dict.get("GNU_RT_LIB_1"): ++ package_data['paddle.libs'] += [ ++ os.path.basename(env_dict.get("GNU_RT_LIB_1")) ++ ] ++ shutil.copy(env_dict.get("GNU_RT_LIB_1"), libs_path) + if env_dict.get("WITH_MAGMA") == 'ON': + package_data['paddle.libs'] += [ + os.path.basename('MAGMA_LIB'), +-- +2.51.0 diff --git a/patches/paddlepaddle/3.3.1/0004-Require-only-the-Python-headers-not-a-linkable-libpyt.patch b/patches/paddlepaddle/3.3.1/0004-Require-only-the-Python-headers-not-a-linkable-libpyt.patch new file mode 100644 index 00000000000..9f5cc328e42 --- /dev/null +++ b/patches/paddlepaddle/3.3.1/0004-Require-only-the-Python-headers-not-a-linkable-libpyt.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000004 Mon Sep 17 00:00:00 2001 +From: RISE Project CI +Date: Sun, 20 Sep 2026 00:00:00 +0000 +Subject: [PATCH 4/5] Require only the Python headers, not a linkable libpython + +cmake/external/python.cmake asks for a linkable libpython on every +platform: + + find_package(PythonLibs ${PY_VERSION} REQUIRED) + +but no non-Windows target ever links one. cmake/generic.cmake's +cc_library() removes `python` from the dependency list, keeps it only as +an add_dependencies() ordering edge, and links +"-Wl,-undefined,dynamic_lookup" in its place, citing pybind11's own +"Building manually" notes: libpaddle.so is an extension module, so the +interpreter that loads it is what resolves the CPython symbols. Outside +the cc_test() executables, which do embed an interpreter, nothing on +Linux consumes PYTHON_LIBRARIES at all. + +The REQUIRED therefore fails builds that would otherwise work. A CPython +configured --disable-shared installs no libpythonX.Y.so for +FindPythonLibs to find, and the module does not accept the +libpythonX.Y.a it does install, so configure stops at + + Could NOT find PythonLibs (missing: PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS) + (Required is at least version "3.13") + +before a single file compiles. Every manylinux image builds its +interpreters that way -- pypa/manylinux's build_scripts/build-cpython.sh +passes --disable-shared unconditionally -- and those images are where +release wheels get built. Pointing PYTHON_LIBRARY at the static archive +instead would only move the failure to the end of the build: CPython's +configure adds CFLAGSFORSHARED, i.e. -fPIC, only when LIBRARY differs +from LDLIBRARY, which a --disable-shared build never does, so +libpythonX.Y.a holds no position-independent code and cannot be linked +into libpaddle.so at all. + +Keep the REQUIRED lookup on Windows, where PYTHON_LIBRARIES really is +linked, and elsewhere take the include directory from the interpreter +being built against -- sysconfig's INCLUDEPY, which keeps pointing at the +real installation from inside a virtualenv -- and let the library lookup +fail harmlessly. `python` becomes a link-nothing INTERFACE target when no +library was found, because a SHARED IMPORTED target with an empty +IMPORTED_LOCATION is not valid. + +Taking the headers from PYTHON_EXECUTABLE also stops FindPythonLibs, a +module CMake 4.0 removes (policy CMP0148), from deciding which Python a +build compiles against independently of PYTHON_EXECUTABLE. + +Upstream-Status: To upstream + +Not riscv64-specific, and not specific to any one image either: manylinux +configures CPython with --disable-shared on every architecture it builds, +so the same configure failure stops an x86-64 or aarch64 build of this +release in the same place. + +Signed-off-by: RISE Project CI +--- + cmake/external/python.cmake | 45 +++++++++++++++++++++++++++++++++++--- + 1 file changed, 42 insertions(+), 3 deletions(-) + +diff --git a/cmake/external/python.cmake b/cmake/external/python.cmake +index 488540b..7e80fbb 100644 +--- a/cmake/external/python.cmake ++++ b/cmake/external/python.cmake +@@ -18,7 +18,40 @@ + + # Find Python with minimum PY_VERSION specified or will raise error! + find_package(PythonInterp ${PY_VERSION} REQUIRED) +-find_package(PythonLibs ${PY_VERSION} REQUIRED) ++ ++if(WIN32) ++ find_package(PythonLibs ${PY_VERSION} REQUIRED) ++else() ++ # cc_library() drops `python` from the link line of every non-Windows target ++ # and lets the interpreter resolve the CPython symbols when it loads the ++ # extension module (see cmake/generic.cmake), so a linkable libpython is only ++ # ever needed by the cc_test() executables that embed one -- never to build ++ # libpaddle.so. Requiring one regardless breaks the build against any CPython ++ # configured --disable-shared, as the manylinux wheel-building images are: ++ # those install no libpythonX.Y.so at all, and the libpythonX.Y.a they do ++ # install is compiled without -fPIC (configure adds CFLAGSFORSHARED only when ++ # LIBRARY differs from LDLIBRARY), so no shared object could link it either ++ # way. Take the headers from the interpreter being built against and leave the ++ # library itself optional. ++ if(NOT PYTHON_INCLUDE_DIR OR NOT EXISTS "${PYTHON_INCLUDE_DIR}/Python.h") ++ execute_process( ++ COMMAND "${PYTHON_EXECUTABLE}" "-c" ++ "import sysconfig; print(sysconfig.get_config_var('INCLUDEPY'))" ++ RESULT_VARIABLE _PYTHON_INCLUDEPY_SUCCESS ++ OUTPUT_VARIABLE _PYTHON_INCLUDEPY ++ OUTPUT_STRIP_TRAILING_WHITESPACE) ++ if(NOT _PYTHON_INCLUDEPY_SUCCESS EQUAL 0 OR NOT EXISTS ++ "${_PYTHON_INCLUDEPY}/Python.h") ++ message(FATAL_ERROR "Found no Python.h for ${PYTHON_EXECUTABLE}, looked " ++ "in '${_PYTHON_INCLUDEPY}'") ++ endif() ++ set(PYTHON_INCLUDE_DIR ++ "${_PYTHON_INCLUDEPY}" ++ CACHE PATH "Path to where Python.h is found" FORCE) ++ endif() ++ find_package(PythonLibs ${PY_VERSION}) ++ set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") ++endif() + + if(WIN32) + execute_process( +@@ -64,8 +97,14 @@ + endif(WIN32) + + # Fixme: Maybe find a static library. Get SHARED/STATIC by FIND_PACKAGE. +-add_library(python SHARED IMPORTED GLOBAL) +-set_property(TARGET python PROPERTY IMPORTED_LOCATION ${PYTHON_LIBRARIES}) ++if(PYTHON_LIBRARIES) ++ add_library(python SHARED IMPORTED GLOBAL) ++ set_property(TARGET python PROPERTY IMPORTED_LOCATION ${PYTHON_LIBRARIES}) ++else() ++ # No linkable libpython: keep `python` as the link-nothing placeholder that ++ # cc_library() only ever takes an add_dependencies() ordering edge on. ++ add_library(python INTERFACE IMPORTED GLOBAL) ++endif() + + set(py_env "") + if(PYTHONINTERP_FOUND) diff --git a/patches/paddlepaddle/3.3.1/0005-Give-OpenBLAS-a-riscv64-TARGET.patch b/patches/paddlepaddle/3.3.1/0005-Give-OpenBLAS-a-riscv64-TARGET.patch new file mode 100644 index 00000000000..1364f9b9a78 --- /dev/null +++ b/patches/paddlepaddle/3.3.1/0005-Give-OpenBLAS-a-riscv64-TARGET.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000005 Mon Sep 17 00:00:00 2001 +From: RISE Project CI +Date: Sat, 20 Sep 2026 00:00:00 +0000 +Subject: [PATCH 5/5] Give OpenBLAS a riscv64 TARGET + +OpenBLAS cannot detect a riscv64 host: getarch.c reaches its +riscv64 branch only through -DFORCE_RISCV64_*, which Makefile.system +derives from TARGET=, so a plain `make` stops at + + getarch.c: error: #error "This arch/CPU is not supported by OpenBLAS." + +WITH_ARM already answers this with TARGET=ARMV8. Do the same for +riscv64 with TARGET=RISCV64_GENERIC, whose -march=rv64imafdc -mabi=lp64d +is the rv64gc baseline every riscv64 wheel has to run on; the vector +targets (RISCV64_ZVL128B, RISCV64_ZVL256B) would bake RVV into a +statically linked libopenblas.a. + +Upstream-Status: To upstream + +Depends on patch 1/5's WITH_RISCV option, so it can only go upstream +together with it. + +Signed-off-by: RISE Project CI +--- + cmake/external/openblas.cmake | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/cmake/external/openblas.cmake b/cmake/external/openblas.cmake +--- a/cmake/external/openblas.cmake ++++ b/cmake/external/openblas.cmake +@@ -89,15 +89,19 @@ + if(WITH_ARM) + set(ARM_ARGS TARGET=ARMV8) + endif() ++ if(WITH_RISCV) ++ set(RISCV_ARGS TARGET=RISCV64_GENERIC) ++ endif() + set(COMMON_ARGS CC=${OPENBLAS_CC} NO_SHARED=1 NO_LAPACK=1 libs) + ExternalProject_Add( + extern_openblas + ${EXTERNAL_PROJECT_LOG_ARGS} + SOURCE_DIR ${CBLAS_SOURCE_DIR} + PREFIX ${CBLAS_PREFIX_DIR} + INSTALL_DIR ${CBLAS_INSTALL_DIR} + BUILD_IN_SOURCE 1 +- BUILD_COMMAND make ${ARM_ARGS} -s -j${NPROC} ${COMMON_ARGS} ${OPTIONAL_ARGS} ++ BUILD_COMMAND make ${ARM_ARGS} ${RISCV_ARGS} -s -j${NPROC} ${COMMON_ARGS} ++ ${OPTIONAL_ARGS} + INSTALL_COMMAND make install NO_SHARED=1 NO_LAPACK=1 PREFIX= + UPDATE_COMMAND "" + CONFIGURE_COMMAND "" +-- +2.51.0