From dc867ab11df8bad1b08d20607c4ea03526392561 Mon Sep 17 00:00:00 2001 From: dcandler Date: Tue, 13 Jan 2026 13:09:41 +0000 Subject: [PATCH 1/3] [ATfE] Remove PICOLIBC_TEST hack (#666) The minimum version of meson required by picolibc has been increased to 0.61, and so the PICOLIBC_TEST hack to enable builds on older versions has been removed from upstream test scripts. The scripts used by ATfE still expected this variable to be set, and so this has now also been removed to match. In order to continue to set stdin to /dev/null, this is now done in the run_qemu script. (cherry picked from commit 779e73e74ff8c9c15fe5dd95e046c9665655d580) --- This is a cherry-pick from ATfE [1]. Our "main" picolibc doesn't need this, but this will be needed by our soon-to-be-added picolibc v1.8.12 overlay as [2] is present in that version (which removes the support for `PICOLIBC_TEST`). This is safe for us to do in cpullvm with picolibc versions before the meson minimum requirement bump in picolibc [3] as cpullvm needs meson >= 1.9.0 anyway (for eld support in meson). [1] https://github.com/arm/arm-toolchain/commit/779e73e74ff8c9c15fe5dd95e046c9665655d580 [2] https://github.com/picolibc/picolibc/commit/45dde9042ad91c54e360d2866904e7ec9f74128b [3] https://github.com/picolibc/picolibc/commit/33065fe2705b5e9211177df09df21ee7aebe2dc2 Signed-off-by: Jonathon Penix --- .../embedded-runtimes/meson-cross-build.txt.in | 7 ++----- .../test-support/picolibc-test-wrapper.py | 6 ++++++ .../embedded-runtimes/test-support/run_qemu.py | 2 ++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/qualcomm-software/embedded-runtimes/meson-cross-build.txt.in b/qualcomm-software/embedded-runtimes/meson-cross-build.txt.in index bd7397f23b43..a93a5c1b691a 100644 --- a/qualcomm-software/embedded-runtimes/meson-cross-build.txt.in +++ b/qualcomm-software/embedded-runtimes/meson-cross-build.txt.in @@ -6,12 +6,9 @@ cpp_ld = 'eld' ar = '@LLVM_BINARY_DIR@/bin/llvm-ar@CMAKE_EXECUTABLE_SUFFIX@' strip = '@LLVM_BINARY_DIR@/bin/llvm-strip@CMAKE_EXECUTABLE_SUFFIX@' # only needed to run tests -# setting stdin to /dev/null prevents qemu from fiddling with the echo bit of -# the parent terminal exe_wrapper = [ - 'sh', - '-c', - 'test -z "$PICOLIBC_TEST" || @Python3_EXECUTABLE@ @picolibc_test_executor_bin@ "$@" < /dev/null', + 'env', + '@Python3_EXECUTABLE@', '@picolibc_test_executor_bin@', @meson_test_executor_params@] diff --git a/qualcomm-software/embedded-runtimes/test-support/picolibc-test-wrapper.py b/qualcomm-software/embedded-runtimes/test-support/picolibc-test-wrapper.py index 532f1b6542e6..a3743357635a 100755 --- a/qualcomm-software/embedded-runtimes/test-support/picolibc-test-wrapper.py +++ b/qualcomm-software/embedded-runtimes/test-support/picolibc-test-wrapper.py @@ -11,6 +11,7 @@ from run_qemu import run_qemu import argparse import pathlib +import subprocess import sys @@ -30,6 +31,11 @@ def run(args): pathlib.Path.cwd(), args.verbose, args.trace, + # Setting stdin to /dev/null prevents qemu from fiddling with + # the echo bit of the parent terminal when meson runs multiple + # tests in parallel. stdin is only tested by picolibc when + # test-stdin=true, which is not the default. + stdin=subprocess.DEVNULL, ) diff --git a/qualcomm-software/embedded-runtimes/test-support/run_qemu.py b/qualcomm-software/embedded-runtimes/test-support/run_qemu.py index 2d96a3fb2574..93fe6e7e75a9 100755 --- a/qualcomm-software/embedded-runtimes/test-support/run_qemu.py +++ b/qualcomm-software/embedded-runtimes/test-support/run_qemu.py @@ -27,6 +27,7 @@ def run_qemu( working_directory, verbose, trace, + stdin=None, ): """Execute the program using QEMU and return the subprocess return code.""" qemu_params = ["-M", qemu_machine] @@ -73,6 +74,7 @@ def run_qemu( result = subprocess.run( command, + stdin=stdin, stdout=subprocess.PIPE, stderr=sys.stderr, timeout=timeout, From 72da29d8c282e21f039b7c88a601a594f50c547c Mon Sep 17 00:00:00 2001 From: Jonathon Penix Date: Thu, 6 Aug 2026 20:17:06 -0700 Subject: [PATCH 2/3] [cpullvm] Support picolibc versions with and without `--args` support Note that this is derived from a commit in ATfE [1]. [2] in picolibc introduced a new `--args ` option to pass arguments into tests rather than just passing them through as extra individual arguments. [2] isn't present in our "main" picolibc, but will be in our soon-to-be-added picolibc v1.8.12 overlay. Which, causes a bit of a wrinkle--we need to support both picolibc's old and new way of handling these arguments. To do so, I think we can just leave both bits in--older picolibcs don't use `--args`, newer picolibc versions seem to only use `--args` (and not pass in extra arguments). That said, `argparse.REMAINDER` needs to change as otherwise it will eat what is passed in after the last positional argument (which is how picolibc passes in `--args`). Instead, use `parse_known_args()` and feed whatever is unknown into the program. There's a small risk of possible conflicts (picolibc using an argument that matches one in our wrapper, a prefix matching, etc.) but I think the risk of that should be fairly small. [1] https://github.com/arm/arm-toolchain/commit/3e28dfdd0405710a67bf652eb0c7d0180d6f0c6c [2] https://github.com/picolibc/picolibc/commit/295b45098fb189185c973376b53d48b86b65e4ae Signed-off-by: Jonathon Penix --- .../test-support/picolibc-test-wrapper.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/qualcomm-software/embedded-runtimes/test-support/picolibc-test-wrapper.py b/qualcomm-software/embedded-runtimes/test-support/picolibc-test-wrapper.py index a3743357635a..739a796714c2 100755 --- a/qualcomm-software/embedded-runtimes/test-support/picolibc-test-wrapper.py +++ b/qualcomm-software/embedded-runtimes/test-support/picolibc-test-wrapper.py @@ -15,10 +15,15 @@ import sys -def run(args): +def run(args, extra_args): # Some picolibc tests expect argv[0] to be literally "program-name", not # the actual program name. - argv = ["program-name"] + args.arguments + argv = ["program-name"] + extra_args + if args.args: + # In picolibc v1.8.11 and later, arguments from the picolibc tests + # will come as a string rather than a list, so append to the first + # element and let the semihosting library handle the splitting. + argv[0] += " " + args.args if args.qemu_command: return run_qemu( args.qemu_command, @@ -68,18 +73,21 @@ def main(): help="Print verbose output. This may affect test result, as the output " "will be added to the output of the test.", ) - parser.add_argument("image", help="image file to execute") parser.add_argument( - "arguments", - nargs=argparse.REMAINDER, - default=[], - help="optional arguments for the image", + "--args", + help="String containing optional arguments for the image", ) - args = parser.parse_args() + parser.add_argument("image", help="image file to execute") + # FIXME: We need to support picolibc versions both with and without + # https://github.com/picolibc/picolibc/commit/295b45098fb189185c973376b53d48b86b65e4ae. + # Once all supported picolibc versions have this commit (picolibc v1.8.11 + # or later), `extra_args` should be removed and this can go back to just + # `parse_args()`. + args, extra_args = parser.parse_known_args() # --qemu-cpu is encoded with colons instead of commas to survive CMake list # separator substitution (LIST_SEPARATOR ,). Decode it back here. args.qemu_cpu = args.qemu_cpu.replace(":", ",") if args.qemu_cpu else None - ret_code = run(args) + ret_code = run(args, extra_args) sys.exit(ret_code) From 3388bae09dca028e36c76633b2881e0269808fea Mon Sep 17 00:00:00 2001 From: Jonathon Penix Date: Thu, 6 Aug 2026 13:28:41 -0700 Subject: [PATCH 3/3] [cpullvm] WIP: Add picolibc v1.8.12 overlay Two primary issues to sort out: * The xqci memcpy patches need to be rebased and added * There's a few picolibc tests that are xpassing that need to be investigated/fixed. Signed-off-by: Jonathon Penix --- .github/workflows/linux-premerge.yml | 8 + qualcomm-software/CMakeLists.txt | 16 +- .../embedded-multilib/CMakeLists.txt | 4 +- .../embedded-runtimes/CMakeLists.txt | 2 +- .../embedded-runtimes/test-support/xfails.py | 36 +- .../0001-Enable-libcxx-builds.patch | 52 ++ ...memset-memcpy-strcpy-strcmp-for-Xqci.patch | 814 ++++++++++++++++++ .../scripts/build_picolibc-v1812_overlay.sh | 38 + .../scripts/test_picolibc-v1812_overlay.sh | 29 + qualcomm-software/versions.json | 5 + 10 files changed, 996 insertions(+), 8 deletions(-) create mode 100644 qualcomm-software/patches/picolibc-v1812/0001-Enable-libcxx-builds.patch create mode 100644 qualcomm-software/patches/picolibc-v1812/0002-Add-optimized-memset-memcpy-strcpy-strcmp-for-Xqci.patch create mode 100755 qualcomm-software/scripts/build_picolibc-v1812_overlay.sh create mode 100755 qualcomm-software/scripts/test_picolibc-v1812_overlay.sh diff --git a/.github/workflows/linux-premerge.yml b/.github/workflows/linux-premerge.yml index b661af17267a..fce77578e4ec 100644 --- a/.github/workflows/linux-premerge.yml +++ b/.github/workflows/linux-premerge.yml @@ -39,6 +39,14 @@ jobs: target_os: Linux-x86_64 runner: cpullvm-ubuntu24-x86_64 + # FIXME: this should maybe go into the nightly instead, + # but I don't want to keep triggering those until we're + # closer to being ready to merge. + - build_script: build_picolibc-v1812_overlay.sh + test_script: test_picolibc-v1812_overlay.sh + target_os: Linux-x86_64 + runner: cpullvm-ubuntu24-x86_64 + steps: - name: Checkout source uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 diff --git a/qualcomm-software/CMakeLists.txt b/qualcomm-software/CMakeLists.txt index f4a1519abd1c..534d67123230 100644 --- a/qualcomm-software/CMakeLists.txt +++ b/qualcomm-software/CMakeLists.txt @@ -120,7 +120,7 @@ set(LLVM_TOOLCHAIN_C_LIBRARY "Which C library to use." ) set_property(CACHE LLVM_TOOLCHAIN_C_LIBRARY - PROPERTY STRINGS picolibc musl-embedded) + PROPERTY STRINGS picolibc picolibc-v1812 musl-embedded) option( SHORT_BUILD_PATHS @@ -819,9 +819,12 @@ install( COMPONENT llvm-toolchain-docs ) -if(LLVM_TOOLCHAIN_C_LIBRARY MATCHES "^picolibc") +if(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL picolibc) string(APPEND LIBC_LICENSE_FILES " - Picolibc: third-party-licenses/COPYING.NEWLIB, third-party-licenses/COPYING.picolibc\n") endif() +if(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL picolibc-v1812) + string(APPEND LIBC_LICENSE_FILES " - Picolibc: third-party-licenses/COPYING.picolibc\n") +endif() if(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL musl-embedded OR ENABLE_LINUX_LIBRARIES) string(APPEND LIBC_LICENSE_FILES " - musl-embedded: third-party-licenses/musl-embedded-COPYRIGHT.txt\n") if(ENABLE_LINUX_LIBRARIES) @@ -867,9 +870,14 @@ list(APPEND third_party_license_files if(LLVM_TOOLCHAIN_C_LIBRARY MATCHES "^picolibc") list(APPEND third_party_license_files - ${${LLVM_TOOLCHAIN_C_LIBRARY}_SOURCE_DIR}/COPYING.NEWLIB COPYING.NEWLIB - ${${LLVM_TOOLCHAIN_C_LIBRARY}_SOURCE_DIR}/COPYING.picolibc COPYING.picolibc + ${${LLVM_TOOLCHAIN_C_LIBRARY}_SOURCE_DIR}/COPYING.picolibc COPYING.picolibc ) + # COPYING.NEWLIB has been removed in picolibc 1.8.11 and later. + if(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL "picolibc") + list(APPEND third_party_license_files + ${${LLVM_TOOLCHAIN_C_LIBRARY}_SOURCE_DIR}/COPYING.NEWLIB COPYING.NEWLIB + ) + endif() elseif(LLVM_TOOLCHAIN_C_LIBRARY STREQUAL musl-embedded) list(APPEND third_party_license_files ${musl-embedded_SOURCE_DIR}/COPYRIGHT musl-embedded-COPYRIGHT.txt diff --git a/qualcomm-software/embedded-multilib/CMakeLists.txt b/qualcomm-software/embedded-multilib/CMakeLists.txt index 4e611264511b..38dcbf8d330d 100644 --- a/qualcomm-software/embedded-multilib/CMakeLists.txt +++ b/qualcomm-software/embedded-multilib/CMakeLists.txt @@ -27,11 +27,11 @@ set(llvmproject_src_dir ${TOOLCHAIN_SOURCE_DIR}/..) set(MULTILIB_JSON "" CACHE STRING "JSON file to load library definitions from.") set(ENABLE_VARIANTS "all" CACHE STRING "Semicolon separated list of variants to build, or \"all\". Must match entries in the json.") set(C_LIBRARY "picolibc" CACHE STRING "Which C library to use.") -set_property(CACHE C_LIBRARY PROPERTY STRINGS picolibc musl-embedded) +set_property(CACHE C_LIBRARY PROPERTY STRINGS picolibc picolibc-v1812 musl-embedded) # multilib.json and the per-variant JSON files only know about one # "picolibc" entry, shared by every fetched picolibc version (e.g. -# picolibc-main), not a separate entry per version. So map C_LIBRARY to +# picolibc-v1812), not a separate entry per version. So map C_LIBRARY to # its base library name before looking anything up there. if(C_LIBRARY MATCHES "^picolibc") set(json_library_key picolibc) diff --git a/qualcomm-software/embedded-runtimes/CMakeLists.txt b/qualcomm-software/embedded-runtimes/CMakeLists.txt index 76d9d34de1ef..983afc49782d 100644 --- a/qualcomm-software/embedded-runtimes/CMakeLists.txt +++ b/qualcomm-software/embedded-runtimes/CMakeLists.txt @@ -25,7 +25,7 @@ set(llvmproject_src_dir ${TOOLCHAIN_SOURCE_DIR}/..) # CMake arguments are loaded from the JSON file depending on which C # library is used, so this must be set before the JSON is processed. set(C_LIBRARY "picolibc" CACHE STRING "Which C library to use.") -set_property(CACHE C_LIBRARY PROPERTY STRINGS picolibc musl-embedded) +set_property(CACHE C_LIBRARY PROPERTY STRINGS picolibc picolibc-v1812 musl-embedded) set(VARIANT_JSON "" CACHE STRING "JSON file to load args from.") if(VARIANT_JSON) diff --git a/qualcomm-software/embedded-runtimes/test-support/xfails.py b/qualcomm-software/embedded-runtimes/test-support/xfails.py index 3f5acd1fa48d..53fa047b1bd0 100644 --- a/qualcomm-software/embedded-runtimes/test-support/xfails.py +++ b/qualcomm-software/embedded-runtimes/test-support/xfails.py @@ -96,6 +96,20 @@ def check_r52_warning(): p = subprocess.run(test_args, capture_output=True, check=False) return p.returncode != 0 + # FIXME: Eventualy it might make more sense to add a `libc` member into + # `XFail` for more direct use depending on how many libc-specific xfails + # are needed. But, while supporting multiple picolibc versions is new, + # using the existing conditionals seems an unobtrusive and flexible way + # forward. + # Test whether picolibc is cpullvm's v1.8.12 version. + def check_picolibc_is_v1812(): + return args.libc == 'picolibc-v1812' + + # Test whether picolibc is cpullvm's "primary" version (currently between + # v1.8.10 and v1.8.11). + def check_picolibc_is_primary(): + return args.libc == 'picolibc' + xfails = [ XFail( name="no frwpi", @@ -175,6 +189,24 @@ def check_r52_warning(): ], description="Disable the tests for now while the issue is being fixed upstream (https://github.com/picolibc/picolibc/pull/1072).", ), + XFail( + name="picolibc v1.8.12 hello-raw", + testnames=[ + "test-hello-raw.test", + "test-hello-raw-no-flash.test", + ], + result=NewResult.EXCLUDE, + conditional=check_picolibc_is_v1812, + project="picolibc", + variants=[ + "aarch64a_tlsie", + "aarch64a_soft_nofp_tlsie", + ], + description="picolibc's `*-raw-*` tests rely on serial port usage " + "to exit correctly which our existing wrappers are not " + "setup to handle. Exclude them for now as we aren't losing " + "any significant test coverage by doing so.", + ), XFail( name="Insufficient RAM", testnames=[ @@ -290,8 +322,10 @@ def check_r52_warning(): "std/language.support/support.start.term/quick_exit.pass.cpp", ], result=NewResult.XFAILED, + conditional=check_picolibc_is_primary, project="libcxx", - description="at_quick_exit symbol is not found in the picolibc semihosting runtime.", + description="quick_exit, at_quick_exit, and __cxa_at_quick_exit were first added " + "in picolibc v1.8.12. Older versions fail with undefined symbols.", ), XFail( name="uchar-cuchar-xpass-picolibc", diff --git a/qualcomm-software/patches/picolibc-v1812/0001-Enable-libcxx-builds.patch b/qualcomm-software/patches/picolibc-v1812/0001-Enable-libcxx-builds.patch new file mode 100644 index 000000000000..28aecd46cb8b --- /dev/null +++ b/qualcomm-software/patches/picolibc-v1812/0001-Enable-libcxx-builds.patch @@ -0,0 +1,52 @@ +From a59afdaf3697da7a1cfc62e0f957be780d6ae11a Mon Sep 17 00:00:00 2001 +From: Simi Pallipurath +Date: Thu, 14 Nov 2024 10:07:08 +0000 +Subject: Enable libcxx builds + +Modifications to build config and linker script required to enable +libc++ builds. +--- + meson.build | 12 ++++++++++++ + picolibc.ld.in | 3 +++ + 2 files changed, 15 insertions(+) + +diff --git a/meson.build b/meson.build +index f33d011b2..2c653de02 100644 +--- a/meson.build ++++ b/meson.build +@@ -1340,6 +1340,18 @@ NEWLIB_MAJOR_VERSION=4 + NEWLIB_MINOR_VERSION=3 + NEWLIB_PATCHLEVEL_VERSION=0 + ++conf_data.set('_GNU_SOURCE', '', ++ description: '''Enable GNU functions like strtof_l. ++It's necessary to set this globally because inline functions in ++libc++ headers call the GNU functions.''' ++) ++ ++conf_data.set('_PICOLIBC_CTYPE_SMALL', '0', ++ description: '''Disable picolibc's small ctype implementation. ++libc++ expects newlib-style ctype tables, and also expects support for locales ++and extended character sets, so picolibc's small ctype is not compatible with it''' ++) ++ + conf_data.set('__HAVE_CC_INHIBIT_LOOP_TO_LIBCALL', + cc.has_argument('-fno-tree-loop-distribute-patterns'), + description: 'Compiler flag to prevent detecting memcpy/memset patterns') +diff --git a/picolibc.ld.in b/picolibc.ld.in +index 0bcfe4ca8..c3055c49e 100644 +--- a/picolibc.ld.in ++++ b/picolibc.ld.in +@@ -69,6 +69,9 @@ SECTIONS + *(.literal.startup .text.startup .literal.startup.* .text.startup.*) + *(SORT(.text.sorted.*)) + *(.literal .text .literal.* .text.* .opd .opd.* .branch_lt .branch_lt.* @EXTRA_TEXT_SECTIONS@) ++ PROVIDE (__start___lcxx_override = .); ++ *(__lcxx_override) ++ PROVIDE (__stop___lcxx_override = .); + *(.gnu.linkonce.t.*) + KEEP (*(.fini .fini.*)) + @PREFIX@__text_end = .; +-- +2.43.0 + diff --git a/qualcomm-software/patches/picolibc-v1812/0002-Add-optimized-memset-memcpy-strcpy-strcmp-for-Xqci.patch b/qualcomm-software/patches/picolibc-v1812/0002-Add-optimized-memset-memcpy-strcpy-strcmp-for-Xqci.patch new file mode 100644 index 000000000000..03db4b71c045 --- /dev/null +++ b/qualcomm-software/patches/picolibc-v1812/0002-Add-optimized-memset-memcpy-strcpy-strcmp-for-Xqci.patch @@ -0,0 +1,814 @@ +From 88e28394e35aa782d2a371742e8502bdf4757c0e Mon Sep 17 00:00:00 2001 +From: Venkata Ramanaiah Nalamothu +Date: Thu, 6 Aug 2026 15:09:04 -0700 +Subject: [PATCH] Add optimized memset/memcpy/strcpy/strcmp for Xqci + +The optimized implementations for Xqci will override the other +existing corresponding varients when Xqci extenions are enabled. + +The orverriding happens using the interface implemented in the +upstream Picolibc pull requests 1090, 1092 and 1098. +--- + libc/machine/riscv/CMakeLists.txt | 4 + + libc/machine/riscv/memcpy-xqci.S | 283 ++++++++++++++++++++++++++++++ + libc/machine/riscv/memset-xqci.S | 161 +++++++++++++++++ + libc/machine/riscv/memset.S | 7 +- + libc/machine/riscv/meson.build | 4 + + libc/machine/riscv/rv_string.h | 22 ++- + libc/machine/riscv/strcmp-xqci.S | 83 +++++++++ + libc/machine/riscv/strcmp.S | 6 +- + libc/machine/riscv/strcpy-xqci.S | 87 +++++++++ + libc/machine/riscv/strcpy.c | 5 + + 10 files changed, 659 insertions(+), 3 deletions(-) + create mode 100644 libc/machine/riscv/memcpy-xqci.S + create mode 100644 libc/machine/riscv/memset-xqci.S + create mode 100644 libc/machine/riscv/strcmp-xqci.S + create mode 100644 libc/machine/riscv/strcpy-xqci.S + +diff --git a/libc/machine/riscv/CMakeLists.txt b/libc/machine/riscv/CMakeLists.txt +index 05b2f0084..35ff47fc0 100644 +--- a/libc/machine/riscv/CMakeLists.txt ++++ b/libc/machine/riscv/CMakeLists.txt +@@ -38,14 +38,18 @@ add_subdirectory(machine) + picolibc_sources_flags("-fno-builtin" + ieeefp.c + memcpy-asm.S ++ memcpy-xqci.S + memcpy.c + memmove.S + memmove.c + memset.S ++ memset-xqci.S + setjmp.S + stpcpy.c + strcmp.S ++ strcmp-xqci.S + strcpy.c ++ strcpy-xqci.S + strlen.c + tls.c + ) +diff --git a/libc/machine/riscv/memcpy-xqci.S b/libc/machine/riscv/memcpy-xqci.S +new file mode 100644 +index 000000000..c3bb96743 +--- /dev/null ++++ b/libc/machine/riscv/memcpy-xqci.S +@@ -0,0 +1,283 @@ ++/***************************************************************** ++Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. ++SPDX-License-Identifier: BSD-3-Clause-Clear ++*****************************************************************/ ++ ++#include "rv_string.h" ++ ++#ifdef _MACHINE_RISCV_MEMCPY_ASM_XQCI_ ++ ++.text ++ ++/*=========================================================================== ++ ++ void *memcpy(void *dest, const void *src, size_t n) ++ ++ void __xqci_memcpy(void *dest, const void *src, size_t n) ++ ++ void __xqci_memcpy_aligned(void *dest, void *src, size_t n) ++ ++ void __xqci_memcpy_words(void *dest, void *src, size_t nwords) ++ ++===========================================================================*/ ++/*! ++ @brief ++ memcpy() is standard libc memcpy(). ++ It returns the "dest" argument. ++ ++ __xqci_memcpy is called by the compiler memcpy() builtin if it can't ++ inline. It is identical to standard memcpy(), except it does not ++ return a value. ++ ++ __xqci_memcpy_aligned assumes that dest/src are 32-bit word aligned, ++ and n is a multiple of words (n==0 is allowed). ++ Alignment is not checked, behavior is undefined if not satisfied. ++ ++ __xqci_memcpy_words is like __xqci_memcpy_aligned, except that length ++ is in units of 32-bit words instead of bytes. ++ ++ For word-aligned src/dest/size, these functions are guaranteed to ++ do only word accesses, in sequential order, so they are safe to use ++ for HW peripherals. ++ For byte alignment on src/dest/size, access order may be non-sequential, ++ and some locations may be read/written multiple times. ++ In all cases, only bytes strictly within the src/dest regions will be ++ accessed, with no over-read. ++*/ ++/*=========================================================================*/ ++ ++// Inputs: ++#define dest a0 ++#define src a1 ++#define n a2 ++#define nwords n ++ ++#define BUFSZ 4 ++ ++// Locals: ++#define dst a3 ++#define buf00 a4 ++#define buf01 a5 ++#define buf02 a6 ++#define buf03 a7 ++#define buf10 t3 ++#define buf11 t4 ++#define buf12 t5 ++#define buf13 t6 ++#define buf_size t0 ++#define len0 t1 ++#define len1 t2 ++#define tmp buf00 ++#define src_end len0 ++#define dst_end len1 ++ ++#ifndef MEMSET_TEST ++.global memcpy ++.type memcpy, @function ++memcpy: ++#endif ++ ++.global __xqci_memcpy ++.type __xqci_memcpy, @function ++__xqci_memcpy: ++ // Check for src/dest/size alignment ++ or tmp, dest, src ++ or tmp, tmp, n ++ andi tmp, tmp, 0x3 # LSB of dest, src, and n are 0 ++ bnez tmp,.Lunaligned # Unaligned, take slow path ++ ++.size memcpy, . - memcpy ++ ++.global __xqci_memcpy_aligned ++.type __xqci_memcpy_aligned, @function ++__xqci_memcpy_aligned: ++ ++ srli nwords, n, 2 # Number of words ++ ++.global __xqci_memcpy_words ++.type __xqci_memcpy_words, @function ++__xqci_memcpy_words: ++ mv dst, dest ++ ++.Lmemcpy_words_cont: ++ qc.bgeui nwords, (BUFSZ*2+1), .Lmemcpy_words_long ++ ++.Lmemcpy_words_short: ++ li buf_size, BUFSZ ++ minu len0, nwords, buf_size # Limit to nwords or bufsize (can be 0) ++ qc.lwm buf00, len0, 0(src) # Load first buffer (can be 0 size) ++ sub nwords, nwords, len0 # adjust remind words number ++ minu len1, nwords, buf_size # Second buffer size (can be 0) ++ qc.lwm buf10, len1, (BUFSZ*4)(src) # Load second buffer (can be 0 size) ++ qc.swm buf00, len0, 0(dst) # Store first buffer (can be 0 size) ++ qc.swm buf10, len1, (BUFSZ*4)(dst) # Store second buffer (can be 0 size) ++ ret ++ ++.Lmemcpy_words_long: ++ addi dst, dst, -(BUFSZ*4*2) # pre-decrement destination pointer ++ ++.Lmemcpy_words_loop: ++ qc.lwmi buf00, BUFSZ, 0(src) # Load first buffer (can be 0 size) ++ qc.lwmi buf10, BUFSZ, (BUFSZ*4)(src) # Load second buffer (can be 0 size) ++ addi src, src, (BUFSZ*4*2) # Increment source pointer ++ addi dst, dst, (BUFSZ*4*2) # increment destination pointer ++ qc.swmi buf00, BUFSZ, 0(dst) # Store first buffer (can be 0 size) ++ qc.swmi buf10, BUFSZ, (BUFSZ*4)(dst) # Store second buffer (can be 0 size) ++ addi nwords, nwords, -(BUFSZ*2) # adjust remind words number ++ qc.bgeui nwords, (BUFSZ*2), .Lmemcpy_words_loop ++ ++ addi dst, dst, (BUFSZ*4*2) # increment destination pointer ++ bnez nwords, .Lmemcpy_words_short ++ ret ++ ++// src and/or dest and/or size are not word aligned. ++.Lunaligned: ++ mv dst, dest ++ qc.bltui n, 16, .Lbytecopy # Buffer is <= 15 bytes, copy directly ++ ++ // Copy 3 bytes from the beginning and end of the buffer to handle ++ // realignment and over-read prevention. These will never overlap. ++ // Some of these may be re-copied after realignment. ++ ++ lbu buf00, 0(src) # Start of buffer ++ lbu buf01, 1(src) ++ lbu buf02, 2(src) ++ add src_end, src, n # doing this add here to avoid bubble ++ sb buf00, 0(dst) ++ sb buf01, 1(dst) ++ sb buf02, 2(dst) ++ ++ lbu buf00, -3(src_end) ++ lbu buf01, -2(src_end) ++ lbu buf02, -1(src_end) ++ add dst_end, dst, n # doing this add here to avoid bubble ++ sb buf00, -3(dst_end) ++ sb buf01, -2(dst_end) ++ sb buf02, -1(dst_end) ++ ++ // Add 4 to avoid over-read in src, and +3 to round up dest to word boundary. ++ // Subtract 4 to avoid over-read in src_end, and round down to word boundary. ++ addi dst, dst, 3 ++ andi dst, dst, -4 # dest+7, rounded down ++ sub tmp, dst, dest # Offset from original dest ++ add src, src, tmp # Offset src by same amount (may not align) ++ andi dst_end, dst_end, -4 # -4 and round down on end of dest ++ sub n, dst_end, dst # Updated n. Word multiple, >= 4 ++ ++ // dest and n are now word aligned. ++ // If src is also aligned, do remainder, as word aligned copy. ++ srli nwords, n, 2 # Number of words ++ andi tmp, src, 0x3 ++ beqz tmp, .Lmemcpy_words_cont # we are ready to branch to aligned word loop ++ ++#define buf04 s2 ++#define buf05 s3 ++#define buf06 s4 ++#define buf07 s5 ++#define desc s0 ++#define len s1 ++#define limit buf_size ++#define LIMIT_WORDS (BUFSZ*2-1) ++#define LIMIT_BYTES (LIMIT_WORDS*4) ++ ++ // src is not aligned to dest. Realign src data. ++ qc.cm.push {ra,s0-s5}, -32 ++ li desc, 0x200000 # Width=32 in upper halfword ++ qc.insb desc, src, 2, 3 # Byte offset*8 in lower halfword ++ andi src, src, -4 # Word align src ++ lw buf07, 0(src) # Load first word ++ addi dst, dst, -LIMIT_BYTES # Pre-subtract dest ++ ++ // We don't expect to be doing unaligned access to cache. ++ // Pipeline less aggressively to save code, do bookkeeping ++ // between load and access which should hide memory latency. ++ // This loop copies <= 7 words per iteration. ++ ++ li limit, LIMIT_WORDS ++.Lunaligned_word_loop: ++ mv buf00, buf07 # Copy last word from previous buf ++ minu len, nwords, limit # Maximum 7 words per iteration ++ qc.lwm buf01, len, 4(src) # Load next buffer, offset by 1 word ++ addi src, src, LIMIT_BYTES # Inc src for next iteration ++ addi dst, dst, LIMIT_BYTES # Pre-inc dest ++ qc.extdur buf00, buf00, desc # Realign each word ++ qc.extdur buf01, buf01, desc ++ qc.extdur buf02, buf02, desc ++ qc.extdur buf03, buf03, desc ++ qc.extdur buf04, buf04, desc ++ qc.extdur buf05, buf05, desc ++ qc.extdur buf06, buf06, desc ++ qc.swm buf00, len, 0(dst) # Store realigned data ++ sub nwords, nwords, len ++ bnez nwords, .Lunaligned_word_loop ++ qc.cm.popret {ra,s0-s5}, 32 ++ ++#undef buf04 ++#undef buf05 ++#undef buf06 ++#undef buf07 ++#undef limit ++#undef desc ++#undef LIMIT_WORDS ++#undef LIMIT_BYTES ++ ++// Copy buffer directly, size is <= 15 bytes ++// Try to hide load latency, within reason. ++.Lbytecopy: ++ qc.bltui n, 4, .Lbytecopy_2 ++ ++.Lbytecopy_4: ++ // Copy 4 bytes per iteration ++ lbu buf00, 0(src) ++ lbu buf01, 1(src) ++ lbu buf02, 2(src) ++ lbu buf03, 3(src) ++ addi src, src, 4 ++ sb buf00, 0(dst) ++ sb buf01, 1(dst) ++ sb buf02, 2(dst) ++ sb buf03, 3(dst) ++ addi dst, dst, 4 ++ addi n, n, -4 ++ qc.bgeui n, 4, .Lbytecopy_4 # Repeat until < 4 bytes remaining ++ ++.Lbytecopy_2: ++ qc.bltui n, 2, .Lbytecopy_1_check ++ // Copy 2 bytes. ++ lbu buf00, 0(src) ++ lbu buf01, 1(src) ++ addi src, src, 2 ++ addi n, n, -2 ++ sb buf00, 0(dst) ++ sb buf01, 1(dst) ++ addi dst, dst, 2 ++ ++.Lbytecopy_1_check: ++ bnez n, .Lbytecopy_1 ++ ret ++ ++.Lbytecopy_1: ++ lbu buf00, 0(src) ++ sb buf00, 0(dst) ++ ret ++ ++#undef BUFSZ ++#undef src_end ++#undef dst_end ++#undef tmp ++#undef dst ++#undef len0 ++#undef len1 ++#undef buf_size ++#undef buf00 ++#undef buf01 ++#undef buf02 ++#undef buf03 ++#undef buf10 ++#undef buf11 ++#undef buf12 ++#undef buf13 ++ ++.size __xqci_memcpy, . - __xqci_memcpy ++ ++#endif /*_MACHINE_RISCV_MEMCPY_ASM_XQCI_ */ +diff --git a/libc/machine/riscv/memset-xqci.S b/libc/machine/riscv/memset-xqci.S +new file mode 100644 +index 000000000..361fdb7b3 +--- /dev/null ++++ b/libc/machine/riscv/memset-xqci.S +@@ -0,0 +1,161 @@ ++/***************************************************************** ++Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. ++SPDX-License-Identifier: BSD-3-Clause-Clear ++*****************************************************************/ ++ ++#include "rv_string.h" ++ ++#ifdef _MACHINE_RISCV_MEMSET_ASM_XQCI_ ++ ++.text ++ ++/*=========================================================================== ++ ++ void *memset(void *s, int c, size_t n) ++ ++ void __xqci_memset(void *s, int c, size_t n) ++ ++ void __xqci_memset_aligned(unsigned *s, int c, size_t n) ++ ++ void __xqci_memset_words(unsigned *s, unsigned w, size_t nwords) ++ ++===========================================================================*/ ++/*! ++ @brief ++ memset() is the standard libc implementation. ++ It returns the "s" argument. ++ ++ __xqci_memset() is called by the compiler memset() builtin if it can't ++ inline. It is identical to standard memset(), except it does not ++ return a value. ++ ++ __xqci_memset_aligned() works similarly to __xqci_memset(), except it assumes ++ s is 32-bit aligned, and n is a multiple of 32 bits (n==0 is allowed). ++ Alignment is not checked, behavior is undefined if not satisfied. ++ ++ __xqci_memset_words() also requires s to be 32-bit aligned. ++ w has the value replicated in each byte, and nwords is the length ++ in units of 32-bit words. ++ ++ For word aligned address/length, these functions are guaranteed to do ++ only word access, in sequential order, so they are safe to use for ++ HW peripherals. ++ If address or length have byte alignment, then sequential access ++ is not guaranteed, and some locations may be written multiple times. ++*/ ++/*=========================================================================*/ ++ ++#ifndef MEMSET_TEST ++.global memset ++.type memset, @function ++memset: ++#endif ++ ++.global __xqci_memset ++.type __xqci_memset, @function ++__xqci_memset: ++// Inputs: ++#define s a0 ++#define c a1 ++#define w c ++#define n a2 ++#define nwords n ++// Locals: ++#define len a3 ++#define end a5 ++ ++#define BLOCK_WORDS (28) ++#define BLOCK_BYTES (BLOCK_WORDS*4) ++ ++ // Common case: if s and n are word aligned, use aligned function. ++#define a a4 ++ or a, s, n ++ andi a, a, 0x3 ++ bnez a, .Lunaligned # Skip if unaligned ++#undef a ++ // Fallthrough to aligned memset ++ ++#define p a4 ++// External entry for __xqci_memset_aligned ++.global __xqci_memset_aligned ++.type __xqci_memset_aligned, @function ++__xqci_memset_aligned: ++ mv p, s # keep s value since it is return value ++.L__xqci_memset_aligned: ++ ++ srli nwords, n, 2 # Convert to nwords ++ qc.insb w, c, 8, 8 # Splat c over all 4 bytes ++ qc.insb w, w, 16, 16 ++ qc.e.bgeui nwords, 32, .Llong # Long memset if >= 32 words ++ qc.setwm w, nwords, 0(p) # Short memset (1..31 words) is fast path ++ ret ++ ++.Llong: ++ // Long memset, 32 or more words. ++ // Align the address to a 128-bit PDMEM boundary so block stores ++ // are more efficient. ++ qc.extu len, p, 2, 2 # Word address mod 4 ++ not len, len ++ addi len, len, 5 # Residual to next 4-word multiple ++ qc.setwm w, len, 0(p) # Store 1..4 words for alignment ++ sh2add p, len, p # p += alignment words*4 ++ sub nwords, nwords, len # nwords -= alignment words ++ qc.e.bltui nwords, 32, .Ltail ++ ++ // Store in blocks of 28 words, except for last block. ++.Lblocks: ++ qc.setwmi w, BLOCK_WORDS, 0(p) # Store block size words ++ addi p, p, BLOCK_BYTES # Increment ptr, may overflow but not used in ++ addi nwords, nwords, -BLOCK_WORDS # nwords -= length ++ qc.bgeui nwords, BLOCK_WORDS, .Lblocks ++ ++.Ltail: ++ qc.setwm w, nwords, 0(p) # Store reminder of words, if any ++ ret ++ ++ // Unaligned start address and/or length. ++.Lunaligned: ++ // Do byte stores at start/end of buffer. ++ // Some locations may be written multiple times for small buffers. ++ mv p, s # keep s value since it is return value ++ add end, p, n # End of buffer ++ beqz n, .Lroundup ++ sb c, 0(p) ++ sb c, -1(end) ++ addi n, n, -1 ++ beqz n, .Lroundup ++ sb c, 1(p) ++ sb c, -2(end) ++ addi n, n, -1 ++ beqz n, .Lroundup ++ sb c, 2(p) ++ sb c, -3(end) ++ ++ // Any residual bytes at start/end of buffer have been set. ++ // Round up starting address and round down size to word boundaries and ++ // continue with alignment memset. ++ // Some bytes may be written again by word writes. ++.Lroundup: ++ addi p, p, 3 ++ andi p, p, -4 # Round up p ++ sub n, end, p # n = end - p (may be negative) ++ # __xqci_memset_aligned will round down n ++ qc.bgei n, 4, .L__xqci_memset_aligned # Set middle of buffer as words ++ ++ // Short buffer, return immediately ++ ret ++ ++// External entry for __xqci_memset_words ++.global __xqci_memset_words ++.type __xqci_memset_words, @function ++__xqci_memset_words: ++ mv p, s # keep s value since it is return value ++ qc.e.bgeui nwords, 32, .Llong # Long memset if >= 32 words ++ qc.setwm w, nwords, 0(s) # Short memset (1..31 words) is fast path ++ ret ++ ++#undef p ++ ++.size __xqci_memset, . - __xqci_memset ++ ++#endif /* _MACHINE_RISCV_MEMSET_ASM_XQCI_ */ +diff --git a/libc/machine/riscv/memset.S b/libc/machine/riscv/memset.S +index eaae02a5b..c1ea0a589 100644 +--- a/libc/machine/riscv/memset.S ++++ b/libc/machine/riscv/memset.S +@@ -9,7 +9,10 @@ + http://www.opensource.org/licenses. + */ + +-#include ++#include "rv_string.h" ++ ++#ifdef _MACHINE_RISCV_MEMSET_ASM_ ++ + #include "asm.h" + + +@@ -375,3 +378,5 @@ memset: + ret + #endif + .size memset, .-memset ++ ++#endif /* _MACHINE_RISCV_MEMSET_ASM_ */ +diff --git a/libc/machine/riscv/meson.build b/libc/machine/riscv/meson.build +index b95b78846..4a1d05e7a 100644 +--- a/libc/machine/riscv/meson.build ++++ b/libc/machine/riscv/meson.build +@@ -35,13 +35,17 @@ + srcs_machine = [ + 'ieeefp.c', + 'memcpy-asm.S', ++ 'memcpy-xqci.S', + 'memcpy.c', + 'memmove.S', + 'memmove.c', + 'memset.S', ++ 'memset-xqci.S', + 'setjmp.S', + 'stpcpy.c', ++ 'strcmp-xqci.S', + 'strcmp.S', ++ 'strcpy-xqci.S', + 'strcpy.c', + 'strlen.c', + 'tls.c', +diff --git a/libc/machine/riscv/rv_string.h b/libc/machine/riscv/rv_string.h +index 7fd95da09..872b33d9a 100644 +--- a/libc/machine/riscv/rv_string.h ++++ b/libc/machine/riscv/rv_string.h +@@ -23,7 +23,9 @@ + + #include + +-#if defined(__PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) ++#ifdef __riscv_xqci ++# define _MACHINE_RISCV_MEMCPY_ASM_XQCI_ ++#elif defined(__PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__) + #define _MACHINE_RISCV_MEMCPY_ASM_ + #elif defined(__riscv_vector) + #define _MACHINE_RISCV_MEMCPY_VECTOR_ +@@ -39,4 +41,22 @@ + #define _MACHINE_RISCV_MEMMOVE_GENERIC_ + #endif + ++#if defined(__riscv_xqci) ++# define _MACHINE_RISCV_MEMSET_ASM_XQCI_ ++#else ++# define _MACHINE_RISCV_MEMSET_ASM_ ++#endif ++ ++#if defined(__riscv_xqci) ++# define _MACHINE_RISCV_STRCMP_ASM_XQCI_ ++#else ++# define _MACHINE_RISCV_STRCMP_ASM_ ++#endif ++ ++#if defined(__riscv_xqci) ++# define _MACHINE_RISCV_STRCPY_ASM_XQCI_ ++#else ++# define _MACHINE_RISCV_STRCPY_ASM_ ++#endif ++ + #endif /* _RV_STRING_H_ */ +diff --git a/libc/machine/riscv/strcmp-xqci.S b/libc/machine/riscv/strcmp-xqci.S +new file mode 100644 +index 000000000..1a7fdda89 +--- /dev/null ++++ b/libc/machine/riscv/strcmp-xqci.S +@@ -0,0 +1,83 @@ ++/***************************************************************** ++Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. ++SPDX-License-Identifier: BSD-3-Clause-Clear ++*****************************************************************/ ++ ++#include "rv_string.h" ++ ++#ifdef _MACHINE_RISCV_STRCMP_ASM_XQCI_ ++ ++.text ++ ++/*=========================================================================== ++ ++ int strcmp(const char *s1, const char *s2) ++ ++===========================================================================*/ ++ ++ /* ++ * Returns ++ * a0 - comparison result, value like strcmp ++ * ++ * Parameters ++ * a0 - string1 ++ * a1 - string2 ++ * ++ * Clobbers ++ * a2, a3, a4, a5, a6 ++ */ ++.global strcmp ++.type strcmp, @function ++strcmp: ++ mv a6, a0 ++ or a5, a6, a1 ++ and a5, a5, 3 ++ li a4, 0 ++ bnez a5, 3f ++ ++ /* Main loop for aligned string. */ ++1: ++ qc.lrw a2, a6, a4, 0 ++ qc.lrw a3, a1, a4, 0 ++ orc.b a5, a2 ++ qc.bnei a5, -1, 2f ++ addi a4, a4, 4 ++ beq a2, a3, 1b ++ ++ /* ++ * Words don't match, and no null byte in the first word. ++ * Compute the first differing byte and return unsigned difference. ++ */ ++ xor a5, a2, a3 ++ ctz a5, a5 # bit offset to first differing bit ++ andi a5, a5, -0x8 # bit offset to first differing byte ++ srl a0, a2, a5 ++ andi a0, a0, 0xFF ++ srl a3, a3, a5 ++ andi a3, a3, 0xFF ++ sub a0, a0, a3 ++ ret ++ ++2: ++ /* ++ * Found a null byte. ++ * If words don't match, fall back to simple loop. ++ */ ++ xor a0, a2, a3 ++ bnez a0, 3f ++ /* Otherwise, strings are equal. */ ++ ret ++ ++ /* Simple loop for misaligned strings. */ ++3: ++ qc.lrbu a2, a6, a4, 0 ++ qc.lrbu a3, a1, a4, 0 ++ addi a4, a4, 1 ++ bne a2, a3, 4f ++ bnez a2, 3b ++ ++4: ++ sub a0, a2, a3 ++ ret ++ ++#endif /* _MACHINE_RISCV_STRCMP_ASM_XQCI_ */ +diff --git a/libc/machine/riscv/strcmp.S b/libc/machine/riscv/strcmp.S +index 52305db3d..0af12436c 100644 +--- a/libc/machine/riscv/strcmp.S ++++ b/libc/machine/riscv/strcmp.S +@@ -9,7 +9,9 @@ + http://www.opensource.org/licenses. + */ + +-#include ++#include "rv_string.h" ++ ++#ifdef _MACHINE_RISCV_STRCMP_ASM_ + + #include "asm.h" + +@@ -309,3 +311,5 @@ mask: + .size strcmp, .-strcmp + + #endif ++ ++#endif /* _MACHINE_RISCV_STRCMP_ASM_ */ +diff --git a/libc/machine/riscv/strcpy-xqci.S b/libc/machine/riscv/strcpy-xqci.S +new file mode 100644 +index 000000000..56d82fe85 +--- /dev/null ++++ b/libc/machine/riscv/strcpy-xqci.S +@@ -0,0 +1,87 @@ ++/***************************************************************** ++Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. ++SPDX-License-Identifier: BSD-3-Clause-Clear ++*****************************************************************/ ++ ++#include "rv_string.h" ++ ++#ifdef _MACHINE_RISCV_STRCPY_ASM_XQCI_ ++ ++.text ++ ++/*=========================================================================== ++ ++ char * strcpy(char *dst, const char *src) ++ ++===========================================================================*/ ++ ++ /* ++ * Returns ++ * a0 - destination string ++ * ++ * Parameters ++ * a0 - destination ++ * a1 - source ++ * ++ * Clobbers ++ * a2, a3, a4, a5, a6, a7, t3, t4, t5, t6 ++ */ ++.global strcpy ++.type strcpy, @function ++strcpy: ++ mv a7, a0 ++ or a2, a0, a1 ++ and a2, a1, 3 ++ bnez a2, 4f ++1: ++ qc.lwmi t3, 4, 0(a1) ++ add a1, a1, 16 ++ li a2, -1 ++ orc.b a3, t3 ++ and a2, a2, a3 ++ orc.b a4, t4 ++ and a2, a2, a4 ++ orc.b a5, t5 ++ and a2, a2, a5 ++ orc.b a6, t6 ++ and a2, a2, a6 ++ qc.bnei a2, -1, 2f ++ qc.swmi t3, 4, 0(a7) ++ add a7, a7, 16 ++ j 1b ++ ++2: ++ add a1, a1, -16 ++ li a2, 0 ++ qc.bnei a3, -1, 3f ++ qc.srw t3, a7, a2, 0 ++ add a2, a2, 4 ++ qc.bnei a4, -1, 3f ++ qc.srw t4, a7, a2, 0 ++ add a2, a2, 4 ++ qc.bnei a5, -1, 3f ++ qc.srw t5, a7, a2, 0 ++ add a2, a2, 4 ++ ++3: ++ add a7, a7, a2 ++ add a1, a1, a2 ++4: ++ lbu a2, 0(a1) ++ lbu a3, 1(a1) ++ lbu a4, 2(a1) ++ lbu a5, 3(a1) ++ sb a2, 0(a7) ++ beqz a2, 5f ++ sb a3, 1(a7) ++ beqz a3, 5f ++ sb a4, 2(a7) ++ beqz a4, 5f ++ sb a5, 3(a7) ++ beqz a5, 5f ++ li a2, 4 ++ j 3b ++5: ++ ret ++ ++#endif /* _MACHINE_RISCV_STRCPY_ASM_XQCI_ */ +diff --git a/libc/machine/riscv/strcpy.c b/libc/machine/riscv/strcpy.c +index 8ead748bd..b77efb2a5 100644 +--- a/libc/machine/riscv/strcpy.c ++++ b/libc/machine/riscv/strcpy.c +@@ -11,6 +11,9 @@ + + #include + #include "rv_strcpy.h" ++#include "rv_string.h" ++ ++#ifdef _MACHINE_RISCV_STRCPY_ASM_ + + #undef strcpy + +@@ -19,3 +22,5 @@ strcpy(char *dst, const char *src) + { + return __libc_strcpy(dst, src, true); + } ++ ++#endif /* _MACHINE_RISCV_STRCPY_ASM_ */ +-- +2.43.0 + diff --git a/qualcomm-software/scripts/build_picolibc-v1812_overlay.sh b/qualcomm-software/scripts/build_picolibc-v1812_overlay.sh new file mode 100755 index 000000000000..9cdfdad165a6 --- /dev/null +++ b/qualcomm-software/scripts/build_picolibc-v1812_overlay.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Copyright (c) 2025, Arm Limited and affiliates. +# Part of the Arm Toolchain project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Changes from Qualcomm Technologies, Inc. are provided under the following license: +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# A bash script to build the picolibc-v1812 overlay. + +# The script creates a build of the toolchain in the 'build_picolibc-v1812_overlay' +# directory, inside the repository tree. + +set -ex + +export CC=clang +export CXX=clang++ + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +REPO_ROOT=$( git -C "${SCRIPT_DIR}" rev-parse --show-toplevel ) +BUILD_DIR=${REPO_ROOT}/build_picolibc-v1812_overlay + +mkdir -p "${BUILD_DIR}" +cd "${BUILD_DIR}" + +cmake ../qualcomm-software \ + -GNinja -DFETCHCONTENT_QUIET=OFF \ + -DLLVM_TOOLCHAIN_C_LIBRARY=picolibc-v1812 \ + -DLLVM_TOOLCHAIN_LIBRARY_OVERLAY_INSTALL=ON \ + ${EXTRA_CMAKE_ARGS} +ninja package-llvm-toolchain + +# The package-llvm-toolchain target will produce a .tar.xz package, but we also +# want a zip version for Windows users +cpack -G ZIP diff --git a/qualcomm-software/scripts/test_picolibc-v1812_overlay.sh b/qualcomm-software/scripts/test_picolibc-v1812_overlay.sh new file mode 100755 index 000000000000..2d00ed61897d --- /dev/null +++ b/qualcomm-software/scripts/test_picolibc-v1812_overlay.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# Copyright (c) 2025, Arm Limited and affiliates. +# Part of the Arm Toolchain project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# Changes from Qualcomm Technologies, Inc. are provided under the following license: +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# The script assumes a successful build of the toolchain exists in the +# 'build_picolibc-v1812_overlay' directory inside the repository tree. + +set -ex + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +REPO_ROOT=$( git -C "${SCRIPT_DIR}" rev-parse --show-toplevel ) + +# Run only the library and multilib lit tests. Run libc++ tests for only a few +# variants to keep the runtime acceptable. +cd "${REPO_ROOT}"/build_picolibc-v1812_overlay +ninja check-llvm-toolchain +ninja check-cxxabi +ninja check-unwind +ninja check-cxx-aarch64a_tlsie +ninja check-cxx-armv7a_soft_nofp +ninja check-cxx-riscv32imac_ilp32 +ninja check-cxx-riscv64gc_lp64_nopic diff --git a/qualcomm-software/versions.json b/qualcomm-software/versions.json index e37e69fa4f46..5a2a4157ddc7 100644 --- a/qualcomm-software/versions.json +++ b/qualcomm-software/versions.json @@ -10,6 +10,11 @@ "tagType": "commithash", "tag": "01254932e8e81085817ed61fd858648584ffe37c" }, + "picolibc-v1812": { + "url": "https://github.com/picolibc/picolibc.git", + "tagType": "tag", + "tag": "1.8.12" + }, "musl": { "url": "https://git.musl-libc.org/git/musl", "tagType": "tag",