[libyuv] Fix RISC-V CMake/GN/Bazel builds and C compiler driver linking

- Use -fno-tree-vectorize and -fno-tree-slp-vectorize instead of
  Clang-only -fno-vectorize and -fno-slp-vectorize in CMakeLists.txt,
  riscv-clang.cmake, BUILD.gn, and BUILD.bazel for GCC and Clang
  compatibility.
- Split row_rvv.cc and scale_rvv.cc into a dedicated libyuv_rvv target
  in BUILD.gn and define LIBYUV_RVV so callers in row.h and scale_row.h
  can dispatch to RVV kernels when built without global -march=rv64gcv.
- Guard the x86 AVX512-BF16 vdpphps inline assembly probe in
  util/cpuid.c with __i386__ / __x86_64__.
- Replace new/delete and new[]/delete[] with calloc/malloc/free in
  source/mjpeg_decoder.cc and util/yuvconvert.cc to avoid C++ standard
  library dependencies, and link libm for yuvconstants and
  libyuv_unittest in CMakeLists.txt.

Test: cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ..
Bug: None
Change-Id: I701c0625f2730e864806556213a5e013c931e2d6
Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/8464751
Reviewed-by: richard winterton <rrwinterton@gmail.com>
Commit-Queue: Frank Barchard <fbarchard@google.com>
This commit is contained in:
Frank Barchard 2026-09-25 11:34:33 -07:00 committed by libyuv-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 783ea90384
commit 39445fa162
10 changed files with 113 additions and 57 deletions

View File

@ -46,6 +46,8 @@ SVE_COPTS = select({
SUPPORTS_RVV_COPTS = [
"-DLIBYUV_RVV",
"-fno-tree-vectorize",
"-fno-tree-slp-vectorize",
]
ENABLE_RVV_COPTS = [
@ -62,6 +64,14 @@ RVV_COPTS = select({
"//conditions:default": [],
})
ARCH_SUPPORT_COPTS = select({
"@platforms//cpu:armv7": SUPPORTS_NEON_COPTS,
"@platforms//cpu:aarch64": SUPPORTS_NEON_COPTS + SUPPORTS_SVE_COPTS,
"@platforms//cpu:riscv32": SUPPORTS_RVV_COPTS,
"@platforms//cpu:riscv64": SUPPORTS_RVV_COPTS,
"//conditions:default": [],
})
PLATFORM_COPTS = select({
"@platforms//os:android": ["-DHAVE_JPEG"],
"@platforms//os:linux": ["-DHAVE_JPEG"],
@ -74,7 +84,7 @@ PLATFORM_COPTS = select({
"-DGOOGLE_COMMANDLINEFLAGS_FULL_API",
]
ALL_COPTS = PLATFORM_COPTS
ALL_COPTS = PLATFORM_COPTS + ARCH_SUPPORT_COPTS
ALL_NEON_COPTS = NEON_COPTS + PLATFORM_COPTS

View File

@ -39,6 +39,8 @@ config("libyuv_config") {
}
if (libyuv_disable_rvv) {
defines += [ "LIBYUV_DISABLE_RVV" ]
} else if (libyuv_use_rvv) {
defines += [ "LIBYUV_RVV" ]
}
if (!libyuv_use_lsx) {
defines += [ "LIBYUV_DISABLE_LSX" ]
@ -88,6 +90,10 @@ group("libyuv") {
deps += [ ":libyuv_sme" ]
}
if (libyuv_use_rvv && !libyuv_disable_rvv) {
deps += [ ":libyuv_rvv" ]
}
if (libyuv_use_lsx) {
deps += [ ":libyuv_lsx" ]
}
@ -160,7 +166,6 @@ static_library("libyuv_internal") {
"source/row_any.cc",
"source/row_common.cc",
"source/row_gcc.cc",
"source/row_rvv.cc",
"source/row_win.cc",
"source/scale.cc",
"source/scale_any.cc",
@ -168,7 +173,6 @@ static_library("libyuv_internal") {
"source/scale_common.cc",
"source/scale_gcc.cc",
"source/scale_rgb.cc",
"source/scale_rvv.cc",
"source/scale_uv.cc",
"source/scale_win.cc",
"source/video_common.cc",
@ -274,6 +278,36 @@ if (libyuv_use_sme) {
}
}
if (libyuv_use_rvv && !libyuv_disable_rvv) {
static_library("libyuv_rvv") {
sources = [
"source/row_rvv.cc",
"source/scale_rvv.cc",
]
deps = [ ":libyuv_internal" ]
public_configs = [ ":libyuv_config" ]
# The -march arguments below are incompatible with libc++ modules.
use_libcxx_modules = false
if (current_cpu == "riscv64") {
cflags = [
"-march=rv64gcv",
"-fno-tree-vectorize",
"-fno-tree-slp-vectorize",
]
} else {
cflags = [
"-march=rv32gcv",
"-fno-tree-vectorize",
"-fno-tree-slp-vectorize",
]
}
}
}
if (libyuv_use_lsx) {
static_library("libyuv_lsx") {
sources = [

View File

@ -154,7 +154,7 @@ int main(void) { return 0; }
include(CheckCSourceCompiles)
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
set(OLD_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${RISCV_COMPILER_FLAGS}")
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${RISCV_COMPILER_FLAGS} -fno-tree-vectorize -fno-tree-slp-vectorize")
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
check_c_source_compiles("
int main(void) { return 0; }
@ -164,8 +164,8 @@ int main(void) { return 0; }
if(CAN_COMPILE_RVV)
if(NOT CMAKE_C_FLAGS MATCHES "-march=" AND NOT CMAKE_C_FLAGS MATCHES "-mcpu=")
set(CMAKE_C_FLAGS "${RISCV_COMPILER_FLAGS} -fno-vectorize -fno-slp-vectorize ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${RISCV_COMPILER_FLAGS} -fno-vectorize -fno-slp-vectorize ${CMAKE_CXX_FLAGS}")
set(CMAKE_C_FLAGS "${RISCV_COMPILER_FLAGS} -fno-tree-vectorize -fno-tree-slp-vectorize ${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${RISCV_COMPILER_FLAGS} -fno-tree-vectorize -fno-tree-slp-vectorize ${CMAKE_CXX_FLAGS}")
endif()
else()
add_definitions(-DLIBYUV_DISABLE_RVV)
@ -234,6 +234,9 @@ target_link_libraries ( yuvconvert ${ly_lib_static} )
# this creates the yuvconstants tool
add_executable ( yuvconstants ${ly_base_dir}/util/yuvconstants.c )
target_link_libraries ( yuvconstants ${ly_lib_static} )
if(NOT MSVC)
target_link_libraries ( yuvconstants m )
endif()
if (NOT LIBYUV_DISABLE_JPEG)
find_package ( JPEG )
@ -266,6 +269,9 @@ if(UNIT_TEST)
add_executable(libyuv_unittest ${ly_unittest_sources})
target_link_libraries(libyuv_unittest ${ly_lib_name} ${GTEST_LIBRARY})
if(NOT MSVC)
target_link_libraries(libyuv_unittest m)
endif()
find_library(PTHREAD_LIBRARY pthread)
if(NOT PTHREAD_LIBRARY STREQUAL "PTHREAD_LIBRARY-NOTFOUND")
target_link_libraries(libyuv_unittest pthread)

View File

@ -864,7 +864,8 @@ extern "C" {
#define HAS_YUY2TOYROW_LASX
#endif
#if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector)
#if !defined(LIBYUV_DISABLE_RVV) && \
(defined(__riscv_vector) || defined(LIBYUV_RVV))
#define HAS_AR64TOARGBROW_RVV
#define HAS_ARGBCOPYYTOALPHAROW_RVV
#define HAS_ARGBEXTRACTALPHAROW_RVV

View File

@ -159,8 +159,15 @@ extern "C" {
#define HAS_SCALEROWDOWN34_LSX
#endif
#if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector)
#if !defined(LIBYUV_DISABLE_RVV) && \
((defined(__riscv_vector) && defined(__riscv_zve64x)) || \
(defined(LIBYUV_RVV) && \
(!defined(__riscv_vector) || defined(__riscv_zve64x))))
#define HAS_SCALEUVROWDOWN4_RVV
#endif
#if !defined(LIBYUV_DISABLE_RVV) && \
(defined(__riscv_vector) || defined(LIBYUV_RVV))
#define HAS_SCALEARGBROWDOWN2_RVV
#define HAS_SCALEROWDOWN34_0_BOX_RVV
#define HAS_SCALEROWDOWN34_1_BOX_RVV

View File

@ -30,4 +30,5 @@ declare_args() {
(current_cpu == "mips64el" || current_cpu == "mipsel") && mips_use_mmi
libyuv_use_lsx = current_cpu == "loong64" && loongarch64_use_lsx
libyuv_use_lasx = current_cpu == "loong64" && loongarch64_use_lasx
libyuv_use_rvv = current_cpu == "riscv64" || current_cpu == "riscv32"
}

View File

@ -37,7 +37,7 @@ if(RISCV_COMPILER_FLAGS STREQUAL "")
list(APPEND RISCV_COMPILER_FLAGS "-march=rv64gcv")
if(NOT USE_AUTO_VECTORIZER)
# Disable auto-vectorizer
add_compile_options(-fno-vectorize -fno-slp-vectorize)
add_compile_options(-fno-tree-vectorize -fno-tree-slp-vectorize)
endif()
else()
list(APPEND RISCV_COMPILER_FLAGS "-march=rv64gc")

View File

@ -25,7 +25,8 @@
#endif
#include <stdio.h> // For jpeglib.h.
#include <stdio.h> // For jpeglib.h.
#include <stdlib.h> // For calloc(), malloc(), and free().
// C++ build requires extern C for jpeg internals.
#ifdef __cplusplus
@ -71,10 +72,11 @@ MJpegDecoder::MJpegDecoder()
scanlines_sizes_(NULL),
databuf_(NULL),
databuf_strides_(NULL) {
decompress_struct_ = new jpeg_decompress_struct;
source_mgr_ = new jpeg_source_mgr;
decompress_struct_ = static_cast<jpeg_decompress_struct*>(
malloc(sizeof(jpeg_decompress_struct)));
source_mgr_ = static_cast<jpeg_source_mgr*>(malloc(sizeof(jpeg_source_mgr)));
#ifdef HAVE_SETJMP
error_mgr_ = new SetJmpErrorMgr;
error_mgr_ = static_cast<SetJmpErrorMgr*>(malloc(sizeof(SetJmpErrorMgr)));
decompress_struct_->err = jpeg_std_error(&error_mgr_->base);
// Override standard exit()-based error handler.
error_mgr_->base.error_exit = &ErrorHandler;
@ -94,10 +96,10 @@ MJpegDecoder::MJpegDecoder()
MJpegDecoder::~MJpegDecoder() {
jpeg_destroy_decompress(decompress_struct_);
delete decompress_struct_;
delete source_mgr_;
free(decompress_struct_);
free(source_mgr_);
#ifdef HAVE_SETJMP
delete error_mgr_;
free(error_mgr_);
#endif
DestroyOutputBuffers();
}
@ -126,10 +128,9 @@ bool MJpegDecoder::LoadFrame(const uint8_t* src, size_t src_len) {
for (int i = 0; i < num_outbufs_; ++i) {
int scanlines_size = GetComponentScanlinesPerImcuRow(i);
if (scanlines_sizes_[i] != scanlines_size) {
if (scanlines_[i]) {
delete[] scanlines_[i];
}
scanlines_[i] = new uint8_t*[scanlines_size];
free(scanlines_[i]);
scanlines_[i] =
static_cast<uint8_t**>(malloc(scanlines_size * sizeof(uint8_t*)));
scanlines_sizes_[i] = scanlines_size;
}
@ -147,10 +148,8 @@ bool MJpegDecoder::LoadFrame(const uint8_t* src, size_t src_len) {
// - Sampling factor is stored in 4 bits, so scanlines_size is < 16.
int databuf_size = scanlines_size * databuf_stride;
if (databuf_strides_[i] != databuf_stride) {
if (databuf_[i]) {
delete[] databuf_[i];
}
databuf_[i] = new uint8_t[databuf_size];
free(databuf_[i]);
databuf_[i] = static_cast<uint8_t*>(malloc(databuf_size));
databuf_strides_[i] = databuf_stride;
}
@ -481,17 +480,11 @@ void MJpegDecoder::AllocOutputBuffers(int num_outbufs) {
// it.
DestroyOutputBuffers();
scanlines_ = new uint8_t**[num_outbufs];
scanlines_sizes_ = new int[num_outbufs];
databuf_ = new uint8_t*[num_outbufs];
databuf_strides_ = new int[num_outbufs];
for (int i = 0; i < num_outbufs; ++i) {
scanlines_[i] = NULL;
scanlines_sizes_[i] = 0;
databuf_[i] = NULL;
databuf_strides_[i] = 0;
}
scanlines_ =
static_cast<uint8_t***>(calloc(num_outbufs, sizeof(uint8_t**)));
scanlines_sizes_ = static_cast<int*>(calloc(num_outbufs, sizeof(int)));
databuf_ = static_cast<uint8_t**>(calloc(num_outbufs, sizeof(uint8_t*)));
databuf_strides_ = static_cast<int*>(calloc(num_outbufs, sizeof(int)));
num_outbufs_ = num_outbufs;
}
@ -499,13 +492,13 @@ void MJpegDecoder::AllocOutputBuffers(int num_outbufs) {
void MJpegDecoder::DestroyOutputBuffers() {
for (int i = 0; i < num_outbufs_; ++i) {
delete[] scanlines_[i];
delete[] databuf_[i];
free(scanlines_[i]);
free(databuf_[i]);
}
delete[] scanlines_;
delete[] databuf_;
delete[] scanlines_sizes_;
delete[] databuf_strides_;
free(scanlines_);
free(databuf_);
free(scanlines_sizes_);
free(databuf_strides_);
scanlines_ = NULL;
databuf_ = NULL;
scanlines_sizes_ = NULL;

View File

@ -42,7 +42,7 @@ static void KernelVersion(int* version) {
}
#endif
#ifdef __linux__
#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
static sigjmp_buf vdpphps_jmpbuf;
static void vdpphps_sigill_handler(int sig) {
(void)sig;

View File

@ -201,8 +201,12 @@ int main(int argc, const char* argv[]) {
}
// Open all files to convert to
FILE** file_rec = new FILE*[num_rec];
memset(file_rec, 0, num_rec * sizeof(FILE*)); // NOLINT
FILE** file_rec = static_cast<FILE**>(calloc(num_rec, sizeof(FILE*)));
if (file_rec == NULL) {
fprintf(stderr, "No memory available\n");
fclose(file_org);
exit(1);
}
for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
file_rec[cur_rec] = fopen(argv[fileindex_rec + cur_rec], "wb");
if (file_rec[cur_rec] == NULL) {
@ -211,7 +215,7 @@ int main(int argc, const char* argv[]) {
for (int i = 0; i < cur_rec; ++i) {
fclose(file_rec[i]);
}
delete[] file_rec;
free(file_rec);
exit(1);
}
}
@ -243,19 +247,19 @@ int main(int argc, const char* argv[]) {
fseek(file_org, num_skip_org * total_size, SEEK_SET);
#endif
uint8_t* const ch_org = new uint8_t[org_size];
uint8_t* const ch_dst = new uint8_t[dst_size];
uint8_t* const ch_rec = new uint8_t[total_size];
if (ch_org == NULL || ch_rec == NULL) {
uint8_t* const ch_org = static_cast<uint8_t*>(malloc(org_size));
uint8_t* const ch_dst = static_cast<uint8_t*>(malloc(dst_size));
uint8_t* const ch_rec = static_cast<uint8_t*>(malloc(total_size));
if (ch_org == NULL || ch_dst == NULL || ch_rec == NULL) {
fprintf(stderr, "No memory available\n");
fclose(file_org);
for (int i = 0; i < num_rec; ++i) {
fclose(file_rec[i]);
}
delete[] ch_org;
delete[] ch_dst;
delete[] ch_rec;
delete[] file_rec;
free(ch_org);
free(ch_dst);
free(ch_rec);
free(file_rec);
exit(1);
}
@ -359,9 +363,9 @@ int main(int argc, const char* argv[]) {
for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) {
fclose(file_rec[cur_rec]);
}
delete[] ch_org;
delete[] ch_dst;
delete[] ch_rec;
delete[] file_rec;
free(ch_org);
free(ch_dst);
free(ch_rec);
free(file_rec);
return 0;
}