diff --git a/.github/workflows/big_endian.yml b/.github/workflows/big_endian.yml new file mode 100644 index 0000000..6057f5d --- /dev/null +++ b/.github/workflows/big_endian.yml @@ -0,0 +1,142 @@ +name: Big-Endian Architecture Tests + +on: + pull_request: + branches: + - main + paths: + - "quaddtype/**" + - ".github/workflows/**" + workflow_dispatch: + +defaults: + run: + shell: bash + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + big_endian_tests: + runs-on: ubuntu-22.04 + continue-on-error: true + strategy: + fail-fast: false + matrix: + BUILD_PROP: + - [ + "s390x (IBM Z Big Endian)", + "s390x-linux-gnu", + "s390x/ubuntu:22.04", + "s390x", + ] + - [ + "s390x - baseline(Z13)", + "s390x-linux-gnu", + "s390x/ubuntu:22.04", + "s390x", + ] + env: + ARCH_NAME: ${{ matrix.BUILD_PROP[0] }} + TOOLCHAIN_NAME: ${{ matrix.BUILD_PROP[1] }} + DOCKER_CONTAINER: ${{ matrix.BUILD_PROP[2] }} + ARCH: ${{ matrix.BUILD_PROP[3] }} + TERM: xterm-256color + + name: "${{ matrix.BUILD_PROP[0] }}" + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-tags: true + persist-credentials: false + + - name: Initialize binfmt_misc for qemu-user-static + run: | + # Enable QEMU user-mode emulation for cross-architecture execution + docker run --rm --privileged tonistiigi/binfmt:qemu-v9.2.2-52 --install all + + - name: Install cross-compilation toolchain + run: | + sudo apt update + sudo apt install -y ninja-build gcc-${TOOLCHAIN_NAME} g++-${TOOLCHAIN_NAME} gfortran-${TOOLCHAIN_NAME} + + - name: Cache docker container + uses: actions/cache@v4 + id: container-cache + with: + path: ~/docker_${{ matrix.BUILD_PROP[1] }} + key: container-quaddtype-${{ runner.os }}-${{ matrix.BUILD_PROP[1] }}-${{ matrix.BUILD_PROP[2] }}-${{ hashFiles('quaddtype/pyproject.toml') }} + + - name: Create cross-compilation container + if: steps.container-cache.outputs.cache-hit != 'true' + run: | + docker run --platform=linux/${ARCH} --name quaddtype_container --interactive \ + -v /:/host -v $(pwd):/workspace ${DOCKER_CONTAINER} /bin/bash -c " + # Update package manager and install essential tools + apt update && + apt install -y cmake git python3 python-is-python3 python3-dev python3-pip build-essential && + + # Create necessary symlinks for cross-compilation + mkdir -p /lib64 && ln -sf /host/lib64/ld-* /lib64/ || true && + ln -sf /host/lib/x86_64-linux-gnu /lib/x86_64-linux-gnu || true && + + # Link cross-compilation toolchain from host + rm -rf /usr/${TOOLCHAIN_NAME} && ln -sf /host/usr/${TOOLCHAIN_NAME} /usr/${TOOLCHAIN_NAME} && + rm -rf /usr/lib/gcc/${TOOLCHAIN_NAME} && ln -sf /host/usr/lib/gcc-cross/${TOOLCHAIN_NAME} /usr/lib/gcc/${TOOLCHAIN_NAME} && + + # Set up compiler symlinks + rm -f /usr/bin/gcc && ln -sf /host/usr/bin/${TOOLCHAIN_NAME}-gcc /usr/bin/gcc && + rm -f /usr/bin/g++ && ln -sf /host/usr/bin/${TOOLCHAIN_NAME}-g++ /usr/bin/g++ && + rm -f /usr/bin/gfortran && ln -sf /host/usr/bin/${TOOLCHAIN_NAME}-gfortran /usr/bin/gfortran && + + # Set up binutils + rm -f /usr/bin/ar && ln -sf /host/usr/bin/${TOOLCHAIN_NAME}-ar /usr/bin/ar && + rm -f /usr/bin/as && ln -sf /host/usr/bin/${TOOLCHAIN_NAME}-as /usr/bin/as && + rm -f /usr/bin/ld && ln -sf /host/usr/bin/${TOOLCHAIN_NAME}-ld /usr/bin/ld && + rm -f /usr/bin/ld.bfd && ln -sf /host/usr/bin/${TOOLCHAIN_NAME}-ld.bfd /usr/bin/ld.bfd && + + # Link build tools + rm -f /usr/bin/ninja && ln -sf /host/usr/bin/ninja /usr/bin/ninja && + rm -f /usr/local/bin/ninja && mkdir -p /usr/local/bin && ln -sf /host/usr/bin/ninja /usr/local/bin/ninja && + + # Configure git for workspace access + git config --global --add safe.directory /workspace && + + # Install Python build dependencies + python -m pip install --upgrade pip && + python -m pip install meson>=1.3.2 meson-python wheel numpy && + python -m pip install pytest pytest-run-parallel pytest-timeout && + + # Install system dependencies for quaddtype (SLEEF dependencies) + apt install -y libssl-dev libfftw3-dev pkg-config + " + docker commit quaddtype_container quaddtype_container + mkdir -p "~/docker_${TOOLCHAIN_NAME}" + docker save -o "~/docker_${TOOLCHAIN_NAME}/quaddtype_container.tar" quaddtype_container + + - name: Load container from cache + if: steps.container-cache.outputs.cache-hit == 'true' + run: docker load -i "~/docker_${TOOLCHAIN_NAME}/quaddtype_container.tar" + + - name: Build quaddtype with cross-compilation and testing + run: | + docker run --rm --platform=linux/${ARCH} -e "TERM=xterm-256color" \ + -v $(pwd):/workspace -v /:/host quaddtype_container \ + /bin/script -e -q -c "/bin/bash --noprofile --norc -eo pipefail -c ' + cd /workspace/quaddtype && + echo \"Building quaddtype for ${ARCH_NAME}...\" && + + # Set OpenMP linking for cross-compilation + export LDFLAGS=\"-fopenmp\" && + + # Install quaddtype with test dependencies + python -m pip install .[test] -v --no-build-isolation --force-reinstall + + cd .. + python -m pytest -vvv --color=yes --timeout=600 --tb=short quaddtype/tests/ + '" diff --git a/quaddtype/numpy_quaddtype/src/dragon4.c b/quaddtype/numpy_quaddtype/src/dragon4.c index 8e96c0b..5843141 100644 --- a/quaddtype/numpy_quaddtype/src/dragon4.c +++ b/quaddtype/numpy_quaddtype/src/dragon4.c @@ -1885,8 +1885,13 @@ Dragon4_PrintFloat_Sleef_quad(Sleef_quad *value, Dragon4_Options *opt) union { Sleef_quad q; struct { +#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + npy_uint64 hi; + npy_uint64 lo; +#else npy_uint64 lo; npy_uint64 hi; +#endif } i; } u; u.q = *value; diff --git a/quaddtype/numpy_quaddtype/src/quaddtype_main.c b/quaddtype/numpy_quaddtype/src/quaddtype_main.c index 734de21..b8c2bc4 100644 --- a/quaddtype/numpy_quaddtype/src/quaddtype_main.c +++ b/quaddtype/numpy_quaddtype/src/quaddtype_main.c @@ -33,7 +33,6 @@ py_is_longdouble_128(PyObject *self, PyObject *args) #ifdef SLEEF_QUAD_C static const Sleef_quad SMALLEST_SUBNORMAL_VALUE = SLEEF_QUAD_DENORM_MIN; #else -// Use the exact same struct layout as the original buggy code static const union { struct { #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) @@ -94,6 +93,7 @@ get_sleef_constant(PyObject *self, PyObject *args) result->value.sleef_value = SLEEF_QUAD_MIN; } else if (strcmp(constant_name, "smallest_subnormal") == 0) { + // or just use sleef_q(+0x0000000000000LL, 0x0000000000000001ULL, -16383); result->value.sleef_value = SMALLEST_SUBNORMAL_VALUE; } else if (strcmp(constant_name, "bits") == 0) {