From 712093728f1990bebd0a0c58a04734da41128039 Mon Sep 17 00:00:00 2001 From: Frank Barchard Date: Thu, 8 Oct 2026 13:18:09 -0700 Subject: [PATCH] Fix missing inline asm register clobbers Change-Id: Ic573c8d7d8921a1dd00e4481b854a8168d0c94f7 --- GEMINI.md | 13 +++++++++++++ source/compare_gcc.cc | 7 +++++++ source/compare_neon.cc | 7 +++++++ source/compare_neon64.cc | 7 +++++++ source/rotate_gcc.cc | 7 +++++++ source/rotate_neon.cc | 7 +++++++ source/rotate_neon64.cc | 7 +++++++ source/rotate_sme.cc | 7 +++++++ source/row_gcc.cc | 7 +++++++ source/row_lasx.cc | 15 +++++++++++++-- source/row_lsx.cc | 14 ++++++++++++-- source/row_neon.cc | 15 +++++++++++---- source/row_neon64.cc | 12 ++++++++++-- source/row_rvv.cc | 12 ++++++++++++ source/row_sme.cc | 7 +++++++ source/row_sve.cc | 7 +++++++ source/scale_gcc.cc | 9 ++++++++- source/scale_neon.cc | 17 ++++++++++++----- source/scale_neon64.cc | 13 ++++++++++--- source/scale_rvv.cc | 12 ++++++++++++ source/scale_sme.cc | 12 ++++++++++-- 21 files changed, 193 insertions(+), 21 deletions(-) diff --git a/GEMINI.md b/GEMINI.md index 95eefc2a5..79423847a 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -55,6 +55,15 @@ and compiler compatibility. 1. **Feature Macros**: Use the `HAS_` macros in `include/libyuv/row.h` to enable or disable specific instruction set extensions. +2. **Inline asm clobbers (all architectures)**: Every register written by an + inline asm block must be listed in its clobber list: vector registers, + general purpose registers, mask/predicate registers, `"cc"` when flags + are set (`subs`, `cmp`, `whilelt`, ...) and `"memory"` when the block + stores. Declare them even if the ABI treats them as caller-saved: with + LTO/LTCG the compiler may keep values live in any register across the + asm, and other OS ABIs (e.g. Windows) differ in which registers are + callee-saved. Never remove a clobber because it "is not needed by the + ABI". Use real register names, not numbers (`"v22"`, not `"22"`). ### x86 Architectures (32-bit and 64-bit) @@ -63,6 +72,10 @@ and compiler compatibility. 2. **MSVC Intrinsics (`row_win.cc`)**: When converting `row_gcc.cc` to `row_win.cc`, use `_mm512_permutex2var_epi8`, not `_mm512_permi2var_epi8` intrinsic. +3. **Clobber names**: Always declare vector clobbers as `"xmmN"`, never + `"ymmN"` or `"zmmN"`, including for AVX2 and AVX512 code. Clang for + Windows must preserve xmm6-xmm15 and does not save them when they are + declared as ymm or zmm. ### AArch64 diff --git a/source/compare_gcc.cc b/source/compare_gcc.cc index 3124d7de0..f0a5096a5 100644 --- a/source/compare_gcc.cc +++ b/source/compare_gcc.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for GCC x86 and x64. #if !defined(LIBYUV_DISABLE_X86) && \ (defined(__x86_64__) || defined(__i386__)) && \ diff --git a/source/compare_neon.cc b/source/compare_neon.cc index 67b44a1e3..0c2f163d6 100644 --- a/source/compare_neon.cc +++ b/source/compare_neon.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + #if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__) && \ !defined(__aarch64__) diff --git a/source/compare_neon64.cc b/source/compare_neon64.cc index 91d4c8d10..fb24f61df 100644 --- a/source/compare_neon64.cc +++ b/source/compare_neon64.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) // 256 bits at a time diff --git a/source/rotate_gcc.cc b/source/rotate_gcc.cc index 64181160a..5a6261ba0 100644 --- a/source/rotate_gcc.cc +++ b/source/rotate_gcc.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for GCC and clang x64. 32 bit x86 uses rotate_win.cc. #if !defined(LIBYUV_DISABLE_X86) && defined(__x86_64__) && \ !defined(LIBYUV_ENABLE_ROWWIN) diff --git a/source/rotate_neon.cc b/source/rotate_neon.cc index 3394a10f7..7a7f360ce 100644 --- a/source/rotate_neon.cc +++ b/source/rotate_neon.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + #if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__) && \ !defined(__aarch64__) diff --git a/source/rotate_neon64.cc b/source/rotate_neon64.cc index f81a419c5..cca995074 100644 --- a/source/rotate_neon64.cc +++ b/source/rotate_neon64.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for GCC Neon armv8 64 bit. #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) diff --git a/source/rotate_sme.cc b/source/rotate_sme.cc index 6cf0a1528..c071a68b1 100644 --- a/source/rotate_sme.cc +++ b/source/rotate_sme.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + #if !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) && \ defined(__aarch64__) diff --git a/source/row_gcc.cc b/source/row_gcc.cc index 5d0d46060..92dab2336 100644 --- a/source/row_gcc.cc +++ b/source/row_gcc.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for GCC x86 and x64. #if !defined(LIBYUV_DISABLE_X86) && \ (defined(__x86_64__) || defined(__i386__)) && \ diff --git a/source/row_lasx.cc b/source/row_lasx.cc index 0ae67b12a..38fc886b6 100644 --- a/source/row_lasx.cc +++ b/source/row_lasx.cc @@ -12,6 +12,13 @@ #include "libyuv/row.h" +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + #if !defined(LIBYUV_DISABLE_LASX) && defined(__loongarch_asx) #include "libyuv/loongson_intrinsics.h" @@ -1960,7 +1967,9 @@ void ARGBToYMatrixRow_LASX(const uint8_t* src_argb, "+&r"(dst_y), // %1 "+&r"(width) // %2 : "r"(c), "r"(shuff) - : "memory"); + : "memory", "$xr0", "$xr1", "$xr2", "$xr3", "$xr4", "$xr5", "$xr6", + "$xr7", "$xr8", "$xr9", "$xr10", "$xr11", "$xr12", "$xr13", "$xr20", + "$xr21"); } void RGBToYMatrixRow_LASX(const uint8_t* src_rgba, @@ -2018,7 +2027,9 @@ void RGBToYMatrixRow_LASX(const uint8_t* src_rgba, "+&r"(width) // %2 : "r"(c), // %3 "r"(shuff) // %4 - : "memory"); + : "memory", "$xr0", "$xr1", "$xr2", "$xr3", "$xr4", "$xr5", "$xr6", + "$xr7", "$xr8", "$xr9", "$xr10", "$xr11", "$xr12", "$xr13", "$xr14", + "$xr15", "$xr16", "$xr17"); } // undef for unified sources build #undef ALPHA_VAL diff --git a/source/row_lsx.cc b/source/row_lsx.cc index c54196100..a52a23f81 100644 --- a/source/row_lsx.cc +++ b/source/row_lsx.cc @@ -12,6 +12,13 @@ #include "libyuv/row.h" +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + #if !defined(LIBYUV_DISABLE_LSX) && defined(__loongarch_sx) #include "libyuv/loongson_intrinsics.h" @@ -2637,7 +2644,8 @@ void ARGBToYMatrixRow_LSX(const uint8_t* src_argb, "+&r"(dst_y), // %1 "+&r"(width) // %2 : "r"(c) - : "memory"); + : "memory", "$vr0", "$vr1", "$vr2", "$vr3", "$vr4", "$vr5", "$vr6", + "$vr7", "$vr8", "$vr9", "$vr10", "$vr11", "$vr12", "$vr13", "$vr20"); } void RGBToYMatrixRow_LSX(const uint8_t* src_rgba, @@ -2688,7 +2696,9 @@ void RGBToYMatrixRow_LSX(const uint8_t* src_rgba, "+&r"(width) // %2 : "r"(c), // %3 "r"(shuff) // %4 - : "memory"); + : "memory", "$vr0", "$vr1", "$vr2", "$vr3", "$vr4", "$vr5", "$vr6", + "$vr7", "$vr8", "$vr9", "$vr10", "$vr12", "$vr13", "$vr14", "$vr15", + "$vr16", "$vr17"); } // undef for unified sources build diff --git a/source/row_neon.cc b/source/row_neon.cc index 3dba9d423..90a1f7d1c 100644 --- a/source/row_neon.cc +++ b/source/row_neon.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for GCC Neon #if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__) && \ !defined(__aarch64__) @@ -1670,8 +1677,8 @@ void YUY2ToNVUVRow_NEON(const uint8_t* src_yuy2, "+r"(dst_uv), // %2 "+r"(width) // %3 : - : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", - "d7" // Clobber List + : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", + "d9" // Clobber List ); } @@ -2981,8 +2988,8 @@ void ARGBSepiaRow_NEON(uint8_t* dst_argb, int width) { : "+r"(dst_argb), // %0 "+r"(width) // %1 : - : "cc", "memory", "q0", "q1", "q2", "q3", "q10", "q11", "q12", "q13", - "q14", "q15"); + : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q10", "q11", "q12", + "q13", "q14", "q15"); } // Tranform 8 ARGB pixels (32 bytes) with color matrix. diff --git a/source/row_neon64.cc b/source/row_neon64.cc index 8fea6df10..5b9321725 100644 --- a/source/row_neon64.cc +++ b/source/row_neon64.cc @@ -20,6 +20,13 @@ extern "C" { // STn over ZIP1+ST1 // Exynos M1, M2, M3 are slow with ST2, ST3 and ST4 instructions. +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for GCC Neon armv8 64 bit. #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) @@ -2148,7 +2155,7 @@ void ARGB1555ToARGBRow_NEON(const uint8_t* src_argb1555, "+r"(dst_argb), // %1 "+r"(width) // %2 : - : "cc", "memory", "v0", "v1", "v2", "v3", "v29" // Clobber List + : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v29" // Clobber List ); } @@ -3489,7 +3496,8 @@ void ARGB4444ToYRow_NEON(const uint8_t* src_argb4444, "+r"(dst_y), // %1 "+r"(width) // %2 : - : "cc", "memory", "v0", "v1", "v2", "v3", "v24", "v25", "v26", "v27"); + : "cc", "memory", "v0", "v1", "v2", "v3", "v16", "v17", "v24", "v25", + "v26", "v27"); } // ARGB expects first 3 values to contain RGB and 4th value is ignored. diff --git a/source/row_rvv.cc b/source/row_rvv.cc index 2206c53e9..708dcd0dc 100644 --- a/source/row_rvv.cc +++ b/source/row_rvv.cc @@ -17,10 +17,22 @@ #include "libyuv/row.h" +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for RVV (RISC-V Vector extension) #if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector) #include +// vsetvli/vsetivli write the vl and vtype CSRs. Only "vl" is declared, and +// only for GCC; clang historically rejected it. The "vtype" register is +// intentionally not declared, and whether it should be is unresolved. +// TODO(fbarchard): consider adding "vtype" (and "vl" for clang) to the +// clobber list once confirmed with compiler maintainers. #ifndef RVV_VL_CLOBBER #ifdef __clang__ #define RVV_VL_CLOBBER diff --git a/source/row_sme.cc b/source/row_sme.cc index a78a2c02b..5b00e8840 100644 --- a/source/row_sme.cc +++ b/source/row_sme.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + #if !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) && \ defined(__aarch64__) diff --git a/source/row_sve.cc b/source/row_sve.cc index 2d32c7048..5ad817073 100644 --- a/source/row_sve.cc +++ b/source/row_sve.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + #if !defined(LIBYUV_DISABLE_SVE) && defined(__aarch64__) #define RGBTOARGB8_SVE_2X \ diff --git a/source/scale_gcc.cc b/source/scale_gcc.cc index ed5684748..f0b98b8da 100644 --- a/source/scale_gcc.cc +++ b/source/scale_gcc.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for GCC x86 and x64. #if !defined(LIBYUV_DISABLE_X86) && \ (defined(__x86_64__) || defined(__i386__)) && \ @@ -2763,7 +2770,7 @@ void ScaleARGBRowDown2Linear_SSE2(const uint8_t* src_argb, "+r"(dst_argb), // %1 "+r"(dst_width) // %2 : - : "memory", "cc", "xmm0", "xmm1"); + : "memory", "cc", "xmm0", "xmm1", "xmm2"); } void ScaleARGBRowDown2Box_SSE2(const uint8_t* src_argb, diff --git a/source/scale_neon.cc b/source/scale_neon.cc index 0ed3287a6..a180f7785 100644 --- a/source/scale_neon.cc +++ b/source/scale_neon.cc @@ -16,6 +16,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for GCC Neon. #if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__) && \ !defined(__aarch64__) @@ -40,7 +47,7 @@ void ScaleRowDown2_NEON(const uint8_t* src_ptr, "+r"(dst), // %1 "+r"(dst_width) // %2 : - : "q0", "q1" // Clobber List + : "memory", "cc", "q0", "q1" // Clobber List ); } @@ -61,7 +68,7 @@ void ScaleRowDown2Linear_NEON(const uint8_t* src_ptr, "+r"(dst), // %1 "+r"(dst_width) // %2 : - : "q0", "q1" // Clobber List + : "memory", "cc", "q0", "q1" // Clobber List ); } @@ -92,7 +99,7 @@ void ScaleRowDown2Box_NEON(const uint8_t* src_ptr, "+r"(dst), // %2 "+r"(dst_width) // %3 : - : "q0", "q1", "q2", "q3" // Clobber List + : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List ); } @@ -296,7 +303,7 @@ void ScaleRowDown38_NEON(const uint8_t* src_ptr, "+r"(dst_ptr), // %1 "+r"(dst_width) // %2 : "r"(&kShuf38) // %3 - : "d0", "d1", "d2", "d3", "d4", "d5", "memory", "cc"); + : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "memory", "cc"); } // 32x3 -> 12x1 @@ -725,7 +732,7 @@ void ScaleRowUp2_Linear_16_NEON(const uint16_t* src_ptr, "+r"(dst_width), // %2 "+r"(src_temp) // %3 : - : "memory", "cc", "q0", "q1", "q2", "q15" // Clobber List + : "memory", "cc", "q0", "q1", "q2", "q3", "q4", "q5", "q15" // Clobber List ); } diff --git a/source/scale_neon64.cc b/source/scale_neon64.cc index e7f9f6c03..7e438494b 100644 --- a/source/scale_neon64.cc +++ b/source/scale_neon64.cc @@ -17,6 +17,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for GCC Neon armv8 64 bit. #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) @@ -431,8 +438,8 @@ void ScaleRowDown38_3_Box_NEON(const uint8_t* src_ptr, [tblArray2] "r"(kScaleRowDown38_3_BoxIndices2), // %[tblArray2] [tblArray3] "r"(kScaleRowDown38_3_BoxIndices3), // %[tblArray3] [tblArray4] "r"(kScaleRowDown38_NarrowIndices) // %[tblArray4] - : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v20", "v21", "22", "23", - "24", "v27", "v28", "v29", "v30", "v31"); + : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v20", "v21", "v22", + "v23", "v24", "v25", "v27", "v28", "v29", "v30", "v31"); } static const uvec8 kScaleRowDown38_2_BoxIndices1[] = { @@ -721,7 +728,7 @@ void ScaleRowUp2_Linear_16_NEON(const uint16_t* src_ptr, "+r"(dst_ptr), // %2 "+r"(dst_width) // %3 : - : "memory", "cc", "v0", "v1", "v2", "v31" // Clobber List + : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v31" // Clobber List ); } diff --git a/source/scale_rvv.cc b/source/scale_rvv.cc index 26cd79cbe..723aeb7a0 100644 --- a/source/scale_rvv.cc +++ b/source/scale_rvv.cc @@ -18,6 +18,13 @@ #include "libyuv/row.h" #include "libyuv/scale_row.h" +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + // This module is for RVV (RISC-V Vector extension) #if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector) #include @@ -26,6 +33,11 @@ namespace libyuv { extern "C" { #endif +// vsetvli/vsetivli write the vl and vtype CSRs. Only "vl" is declared, and +// only for GCC; clang historically rejected it. The "vtype" register is +// intentionally not declared, and whether it should be is unresolved. +// TODO(fbarchard): consider adding "vtype" (and "vl" for clang) to the +// clobber list once confirmed with compiler maintainers. #ifndef RVV_VL_CLOBBER #ifdef __clang__ #define RVV_VL_CLOBBER diff --git a/source/scale_sme.cc b/source/scale_sme.cc index fa74569d1..73368973c 100644 --- a/source/scale_sme.cc +++ b/source/scale_sme.cc @@ -15,6 +15,13 @@ namespace libyuv { extern "C" { #endif +// Note: every register written by an inline asm block (vector, general +// purpose, mask/predicate, "cc" for flags and "memory" for stores) must be +// listed in its clobber list, even when the ABI treats it as caller-saved. +// With LTO/LTCG the compiler may keep values live in any register across the +// asm statement, and other OS ABIs (e.g. Windows) differ in which registers +// are callee-saved. + #if !defined(LIBYUV_DISABLE_SME) && defined(CLANG_HAS_SME) && \ defined(__aarch64__) @@ -356,7 +363,7 @@ __arm_locally_streaming void ScaleUVRowDown2Linear_SME(const uint8_t* src_uv, [dst_width] "+r"(dst_width), // %[dst_width] [vl] "=r"(vl) // %[vl] : - : "z0", "z1", "p0", "p1"); + : "memory", "cc", "z0", "z1", "p0", "p1"); } #define SCALEUVROWDOWN2BOX_SVE \ @@ -408,7 +415,8 @@ __arm_locally_streaming void ScaleUVRowDown2Box_SME(const uint8_t* src_uv, [dst_width] "+r"(dst_width), // %[dst_width] [vl] "=r"(vl) // %[vl] : - : "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "p0", "p1"); + : "memory", "cc", "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "p0", + "p1"); } #undef SCALEUVROWDOWN2BOX_SVE