aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKito Cheng <kito.cheng@sifive.com>2025-07-10 15:28:30 +0800
committerKito Cheng <kito.cheng@sifive.com>2025-09-04 17:05:57 +0800
commita7fe8f83bf89704e278c1db30f51d6bb26bf0e69 (patch)
treed58df084e494def081369e2f4f3f1a66963e8713
parent9df4edf0af74e867df8ae6422143dc5ed4eb1c10 (diff)
downloadgcc-a7fe8f83bf89704e278c1db30f51d6bb26bf0e69.zip
gcc-a7fe8f83bf89704e278c1db30f51d6bb26bf0e69.tar.gz
gcc-a7fe8f83bf89704e278c1db30f51d6bb26bf0e69.tar.bz2
RISC-V: Always register vector built-in functions during LTO [PR110812]
Previously, vector built-in functions were not properly registered during the LTO pipeline, causing link failures when vector intrinsics were used in LTO builds with mixed architecture options. This patch ensures all vector built-in functions are always registered during LTO compilation. The key changes include: - Moving pragma intrinsic flag manipulation from riscv-c.cc to riscv-vector-builtins.cc for better encapsulation - Registering all vector built-in functions regardless of current ISA extensions, deferring the actual extension checking to expansion time - Adding proper support for built-in type registration during LTO This approach is safe because we already perform extension requirement checking at expansion time. The trade-off is a slight increase in bootstrap time for LTO builds due to registering more built-in functions. PR target/110812 gcc/ChangeLog: * config/riscv/riscv-c.cc (pragma_intrinsic_flags): Remove struct. (riscv_pragma_intrinsic_flags_pollute): Remove function. (riscv_pragma_intrinsic_flags_restore): Remove function. (riscv_pragma_intrinsic): Simplify to only call handle_pragma_vector. * config/riscv/riscv-vector-builtins.cc (pragma_intrinsic_flags): Move struct definition here from riscv-c.cc. (riscv_pragma_intrinsic_flags_pollute): Move and adapt from riscv-c.cc, add zvfbfmin, zvfhmin and vector_elen_bf_16 support. (riscv_pragma_intrinsic_flags_restore): Move from riscv-c.cc. (rvv_switcher::rvv_switcher): Add pollute_flags parameter to control flag manipulation. (rvv_switcher::~rvv_switcher): Restore flags conditionally. (register_builtin_types): Use rvv_switcher without polluting flags. (get_required_extensions): Remove function. (check_required_extensions): Simplify to only check type validity. (function_instance::function_returns_void_p): Move implementation from header. (function_builder::add_function): Register placeholder for LTO. (init_builtins): Simplify and handle LTO case. (reinit_builtins): Remove function. (handle_pragma_vector): Remove extension checking. * config/riscv/riscv-vector-builtins.h (function_instance::function_returns_void_p): Add declaration. (function_call_info::function_returns_void_p): Remove inline implementation. gcc/testsuite/ChangeLog: * gcc.target/riscv/lto/pr110812_0.c: New test. * gcc.target/riscv/lto/pr110812_1.c: New test. * gcc.target/riscv/lto/riscv-lto.exp: New test driver. * gcc.target/riscv/lto/riscv_vector.h: New header wrapper.
-rw-r--r--gcc/config/riscv/riscv-c.cc84
-rw-r--r--gcc/config/riscv/riscv-vector-builtins.cc211
-rw-r--r--gcc/config/riscv/riscv-vector-builtins.h10
-rw-r--r--gcc/testsuite/gcc.target/riscv/lto/pr110812_0.c9
-rw-r--r--gcc/testsuite/gcc.target/riscv/lto/pr110812_1.c9
-rw-r--r--gcc/testsuite/gcc.target/riscv/lto/riscv-lto.exp61
-rw-r--r--gcc/testsuite/gcc.target/riscv/lto/riscv_vector.h11
7 files changed, 211 insertions, 184 deletions
diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index d2c0af3..4fc0528 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -34,77 +34,6 @@ along with GCC; see the file COPYING3. If not see
#define builtin_define(TXT) cpp_define (pfile, TXT)
-struct pragma_intrinsic_flags
-{
- int intrinsic_riscv_isa_flags;
-
- int intrinsic_riscv_vector_elen_flags;
- int intrinsic_riscv_zvl_subext;
- int intrinsic_riscv_zvb_subext;
- int intrinsic_riscv_zvk_subext;
-};
-
-static void
-riscv_pragma_intrinsic_flags_pollute (struct pragma_intrinsic_flags *flags)
-{
- flags->intrinsic_riscv_isa_flags = riscv_isa_flags;
- flags->intrinsic_riscv_vector_elen_flags = riscv_vector_elen_flags;
- flags->intrinsic_riscv_zvl_subext = riscv_zvl_subext;
- flags->intrinsic_riscv_zvb_subext = riscv_zvb_subext;
- flags->intrinsic_riscv_zvk_subext = riscv_zvk_subext;
-
- riscv_isa_flags = riscv_isa_flags
- | MASK_VECTOR;
-
- riscv_zvl_subext = riscv_zvl_subext
- | MASK_ZVL32B
- | MASK_ZVL64B
- | MASK_ZVL128B
- | MASK_ZVL256B
- | MASK_ZVL512B
- | MASK_ZVL1024B
- | MASK_ZVL2048B
- | MASK_ZVL4096B;
-
- riscv_vector_elen_flags = riscv_vector_elen_flags
- | MASK_VECTOR_ELEN_32
- | MASK_VECTOR_ELEN_64
- | MASK_VECTOR_ELEN_FP_16
- | MASK_VECTOR_ELEN_FP_32
- | MASK_VECTOR_ELEN_FP_64;
-
- riscv_zvb_subext = riscv_zvb_subext
- | MASK_ZVBB
- | MASK_ZVBC
- | MASK_ZVKB;
-
- riscv_zvk_subext = riscv_zvk_subext
- | MASK_ZVKG
- | MASK_ZVKNED
- | MASK_ZVKNHA
- | MASK_ZVKNHB
- | MASK_ZVKSED
- | MASK_ZVKSH
- | MASK_ZVKN
- | MASK_ZVKNC
- | MASK_ZVKNG
- | MASK_ZVKS
- | MASK_ZVKSC
- | MASK_ZVKSG
- | MASK_ZVKT;
-}
-
-static void
-riscv_pragma_intrinsic_flags_restore (struct pragma_intrinsic_flags *flags)
-{
- riscv_isa_flags = flags->intrinsic_riscv_isa_flags;
-
- riscv_vector_elen_flags = flags->intrinsic_riscv_vector_elen_flags;
- riscv_zvl_subext = flags->intrinsic_riscv_zvl_subext;
- riscv_zvb_subext = flags->intrinsic_riscv_zvb_subext;
- riscv_zvk_subext = flags->intrinsic_riscv_zvk_subext;
-}
-
static int
riscv_ext_version_value (unsigned major, unsigned minor)
{
@@ -278,20 +207,7 @@ riscv_pragma_intrinsic (cpp_reader *)
|| strcmp (name, "xtheadvector") == 0
|| strcmp (name, "xsfvcp") == 0)
{
- struct pragma_intrinsic_flags backup_flags;
-
- riscv_pragma_intrinsic_flags_pollute (&backup_flags);
-
- riscv_option_override ();
- init_adjust_machine_modes ();
- riscv_vector::reinit_builtins ();
riscv_vector::handle_pragma_vector ();
-
- riscv_pragma_intrinsic_flags_restore (&backup_flags);
-
- /* Re-initialize after the flags are restored. */
- riscv_option_override ();
- init_adjust_machine_modes ();
}
else
error ("unknown %<#pragma riscv intrinsic%> option %qs", name);
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 0db7549..00a8157 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -3474,6 +3474,71 @@ static hash_table<registered_function_hasher> *function_table;
static hash_table<non_overloaded_registered_function_hasher>
*non_overloaded_function_table;
+struct pragma_intrinsic_flags
+{
+ int intrinsic_riscv_isa_flags;
+ int intrinsic_riscv_base_subext;
+
+ int intrinsic_riscv_vector_elen_flags;
+ int intrinsic_riscv_zvl_subext;
+ int intrinsic_riscv_zvf_subext;
+};
+
+static void
+riscv_pragma_intrinsic_flags_pollute (struct pragma_intrinsic_flags *flags)
+{
+ /* We already defer the required extension checking to expantion time, so we
+ only need to pollute those flags that might affect the type registration.
+
+ e.g. zvfbmin and zvfhmin are required to define the vector bf16 and f16,
+ and VECTOR_ELEN* also required for vector interger and floating
+ type. */
+ flags->intrinsic_riscv_isa_flags = riscv_isa_flags;
+ flags->intrinsic_riscv_base_subext = riscv_base_subext;
+ flags->intrinsic_riscv_vector_elen_flags = riscv_vector_elen_flags;
+ flags->intrinsic_riscv_zvl_subext = riscv_zvl_subext;
+ flags->intrinsic_riscv_zvf_subext = riscv_zvf_subext;
+
+ riscv_zvf_subext = riscv_zvf_subext
+ | MASK_ZVFBFMIN
+ | MASK_ZVFHMIN;
+
+ riscv_isa_flags = riscv_isa_flags
+ | MASK_VECTOR;
+
+ riscv_base_subext = riscv_base_subext
+ | MASK_MUL;
+
+ riscv_zvl_subext = riscv_zvl_subext
+ | MASK_ZVL32B
+ | MASK_ZVL64B
+ | MASK_ZVL128B
+ | MASK_ZVL256B
+ | MASK_ZVL512B
+ | MASK_ZVL1024B
+ | MASK_ZVL2048B
+ | MASK_ZVL4096B;
+
+ riscv_vector_elen_flags = riscv_vector_elen_flags
+ | MASK_VECTOR_ELEN_32
+ | MASK_VECTOR_ELEN_64
+ | MASK_VECTOR_ELEN_FP_16
+ | MASK_VECTOR_ELEN_FP_32
+ | MASK_VECTOR_ELEN_FP_64
+ | MASK_VECTOR_ELEN_BF_16;
+}
+
+static void
+riscv_pragma_intrinsic_flags_restore (struct pragma_intrinsic_flags *flags)
+{
+ riscv_isa_flags = flags->intrinsic_riscv_isa_flags;
+ riscv_base_subext = flags->intrinsic_riscv_base_subext;
+
+ riscv_vector_elen_flags = flags->intrinsic_riscv_vector_elen_flags;
+ riscv_zvl_subext = flags->intrinsic_riscv_zvl_subext;
+ riscv_zvf_subext = flags->intrinsic_riscv_zvf_subext;
+}
+
/* RAII class for enabling enough RVV features to define the built-in
types and implement the riscv_vector.h pragma.
@@ -3486,21 +3551,42 @@ static hash_table<non_overloaded_registered_function_hasher>
class rvv_switcher
{
public:
- rvv_switcher ();
+ rvv_switcher (bool pollute_flags = true);
~rvv_switcher ();
private:
bool m_old_have_regs_of_mode[MAX_MACHINE_MODE];
+ struct pragma_intrinsic_flags backup_flags;
+ bool m_pollute_flags;
};
-rvv_switcher::rvv_switcher ()
+static void
+register_builtin_types_on_null ();
+
+rvv_switcher::rvv_switcher (bool pollute_flags)
+ : m_pollute_flags (pollute_flags)
{
+ if (m_pollute_flags)
+ {
+ riscv_pragma_intrinsic_flags_pollute (&backup_flags);
+ riscv_option_override ();
+ }
+
/* Set have_regs_of_mode before targetm.init_builtins (). */
memcpy (m_old_have_regs_of_mode, have_regs_of_mode,
sizeof (have_regs_of_mode));
for (int i = 0; i < NUM_MACHINE_MODES; ++i)
if (riscv_v_ext_vector_mode_p ((machine_mode) i))
have_regs_of_mode[i] = true;
+
+ /* Not necessary to adjust mode and register type if we don't pollute
+ flags. */
+ if (m_pollute_flags)
+ {
+ init_adjust_machine_modes ();
+
+ register_builtin_types_on_null ();
+ }
}
rvv_switcher::~rvv_switcher ()
@@ -3508,6 +3594,15 @@ rvv_switcher::~rvv_switcher ()
/* Recover back have_regs_of_mode. */
memcpy (have_regs_of_mode, m_old_have_regs_of_mode,
sizeof (have_regs_of_mode));
+
+ if (m_pollute_flags)
+ {
+ riscv_pragma_intrinsic_flags_restore (&backup_flags);
+
+ /* Re-initialize after the flags are restored. */
+ riscv_option_override ();
+ init_adjust_machine_modes ();
+ }
}
/* Add attribute NAME to ATTRS. */
@@ -3664,26 +3759,10 @@ register_tuple_type (vector_type_index type, vector_type_index subpart_type,
static void
register_builtin_types ()
{
- /* Get type node from get_typenode_from_name to prevent we have different type
- node define in different target libraries, e.g. int32_t defined as
- `long` in RV32/newlib-stdint, but `int` for RV32/glibc-stdint.h.
- NOTE: uint[16|32|64]_type_node already defined in tree.h. */
- tree int8_type_node = get_typenode_from_name (INT8_TYPE);
- tree uint8_type_node = get_typenode_from_name (UINT8_TYPE);
- tree int16_type_node = get_typenode_from_name (INT16_TYPE);
- tree int32_type_node = get_typenode_from_name (INT32_TYPE);
- tree int64_type_node = get_typenode_from_name (INT64_TYPE);
-
- machine_mode mode;
-#define DEF_RVV_TYPE(NAME, NCHARS, ABI_NAME, SCALAR_TYPE, VECTOR_MODE, \
- ARGS...) \
- mode = VECTOR_MODE##mode; \
- register_builtin_type (VECTOR_TYPE_##NAME, SCALAR_TYPE##_type_node, mode);
-#define DEF_RVV_TUPLE_TYPE(NAME, NCHARS, ABI_NAME, SUBPART_TYPE, SCALAR_TYPE, \
- NF, VECTOR_SUFFIX) \
- register_tuple_type (VECTOR_TYPE_##NAME, VECTOR_TYPE_##SUBPART_TYPE, \
- SCALAR_TYPE##_type_node, NF);
-#include "riscv-vector-builtins.def"
+ /* Don't pollute flags at this stage to make sure we only register type with
+ what we want so far, we will register all type if necessary later. */
+ rvv_switcher rvv (/* pollute_flags */ false);
+ register_builtin_types_on_null ();
}
/* Similar as register_builtin_types but perform the registration if and
@@ -3795,25 +3874,15 @@ required_extensions_p (enum rvv_base_type type)
gcc_unreachable ();
}
-static uint64_t
-get_required_extensions (vector_type_index type_idx)
-{
- for (unsigned int i = 0; all_ops[i].index != NUM_VECTOR_TYPES; i++)
- if (type_idx == all_ops[i].index)
- return all_ops[i].required_extensions;
- for (unsigned int i = 0; b_ops[i].index != NUM_VECTOR_TYPES; i++)
- if (type_idx == b_ops[i].index)
- return b_ops[i].required_extensions;
- gcc_unreachable ();
-}
-
/* Check whether all the RVV_REQUIRE_* values in REQUIRED_EXTENSIONS are
- enabled. */
+ enabled.
+ TODO: We defer the required extensions to expantion time, this function is
+ only doing the legality now, and we may rename this function and moving
+ to another layer. */
static bool
check_required_extensions (const function_instance &instance)
{
rvv_type_info type_info = instance.type;
- uint64_t required_extensions = type_info.required_extensions;
const rvv_op_info *op_info = instance.op_info;
if (required_extensions_p (op_info->ret.base_type))
@@ -3822,48 +3891,18 @@ check_required_extensions (const function_instance &instance)
= op_info->ret.get_function_type_index (type_info.index);
if (ret_type_idx == NUM_VECTOR_TYPES)
return false;
- required_extensions |= get_required_extensions (ret_type_idx);
}
for (unsigned i = 0; op_info->args[i].base_type != NUM_BASE_TYPES; ++i)
{
if (!required_extensions_p (op_info->args[i].base_type))
continue;
-
enum vector_type_index vector_type
= op_info->args[i].get_function_type_index (type_info.index);
if (vector_type == NUM_VECTOR_TYPES)
return false;
- required_extensions |= get_required_extensions (vector_type);
-
- /* According to RVV ISA, EEW=64 index of indexed loads/stores require
- XLEN = 64. */
- if (op_info->args[i].base_type == RVV_BASE_eew64_index)
- required_extensions |= RVV_REQUIRE_RV64BIT;
}
- uint64_t isa_flags = 0;
-
- if (TARGET_VECTOR_ELEN_BF_16)
- isa_flags |= RVV_REQUIRE_ELEN_BF_16;
- if (TARGET_VECTOR_ELEN_FP_16)
- isa_flags |= RVV_REQUIRE_ELEN_FP_16;
- if (TARGET_VECTOR_ELEN_FP_32)
- isa_flags |= RVV_REQUIRE_ELEN_FP_32;
- if (TARGET_VECTOR_ELEN_FP_64)
- isa_flags |= RVV_REQUIRE_ELEN_FP_64;
- if (TARGET_VECTOR_ELEN_64)
- isa_flags |= RVV_REQUIRE_ELEN_64;
- if (TARGET_64BIT)
- isa_flags |= RVV_REQUIRE_RV64BIT;
- if (TARGET_FULL_V)
- isa_flags |= RVV_REQUIRE_FULL_V;
- if (TARGET_MIN_VLEN > 32)
- isa_flags |= RVV_REQUIRE_MIN_VLEN_64;
-
- uint64_t missing_extensions = required_extensions & ~isa_flags;
- if (missing_extensions != 0)
- return false;
return true;
}
@@ -4044,6 +4083,12 @@ function_instance::get_return_type () const
return op_info->ret.get_tree_type (type.index);
}
+bool
+function_instance::function_returns_void_p () const
+{
+ return get_return_type () == void_type_node;
+}
+
tree
function_instance::get_arg_type (unsigned opno) const
{
@@ -4316,7 +4361,7 @@ function_builder::add_function (const function_instance &instance,
nodes and remove the target hook. For now, however, we need to appease the
validation and return a non-NULL, non-error_mark_node node, so we
arbitrarily choose integer_zero_node. */
- tree decl = placeholder_p
+ tree decl = placeholder_p || in_lto_p
? integer_zero_node
: simulate_builtin_function_decl (input_location, name, fntype,
code, NULL, attrs);
@@ -5094,28 +5139,15 @@ builtin_type_p (const_tree type)
void
init_builtins ()
{
- rvv_switcher rvv;
- if (!TARGET_VECTOR)
- return;
- register_builtin_types ();
- if (in_lto_p)
- handle_pragma_vector ();
-}
-
-/* Reinitialize builtins similar to init_builtins, but only the null
- builtin types will be registered. */
-void
-reinit_builtins ()
-{
- rvv_switcher rvv;
-
- if (!TARGET_VECTOR)
- return;
-
- register_builtin_types_on_null ();
-
if (in_lto_p)
+ /* "pragma vector" will register type during the process. */
handle_pragma_vector ();
+ else
+ {
+ if (!TARGET_VECTOR)
+ return;
+ register_builtin_types ();
+ }
}
/* Implement TARGET_VERIFY_TYPE_CONTEXT for RVV types. */
@@ -5281,10 +5313,7 @@ handle_pragma_vector ()
function_table = new hash_table<registered_function_hasher> (1023);
function_builder builder;
for (unsigned int i = 0; i < ARRAY_SIZE (function_groups); ++i)
- {
- if (function_groups[i].match (function_groups[i].required_extensions))
- builder.register_function_group (function_groups[i]);
- }
+ builder.register_function_group (function_groups[i]);
}
/* Return the function decl with RVV function subcode CODE, or error_mark_node
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index 86d8115..12a07a1 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -377,6 +377,7 @@ public:
bool any_type_float_p () const;
tree get_return_type () const;
+ bool function_returns_void_p () const;
tree get_arg_type (unsigned opno) const;
/* The properties of the function. (The explicit "enum"s are required
@@ -432,8 +433,6 @@ class function_call_info : public function_instance
public:
function_call_info (location_t, const function_instance &, tree);
- bool function_returns_void_p ();
-
/* The location of the call. */
location_t location;
@@ -441,13 +440,6 @@ public:
tree fndecl;
};
-/* Return true if the function has no return value. */
-inline bool
-function_call_info::function_returns_void_p ()
-{
- return TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node;
-}
-
/* A class for folding a gimple function call. */
class gimple_folder : public function_call_info
{
diff --git a/gcc/testsuite/gcc.target/riscv/lto/pr110812_0.c b/gcc/testsuite/gcc.target/riscv/lto/pr110812_0.c
new file mode 100644
index 0000000..a2f7092
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/lto/pr110812_0.c
@@ -0,0 +1,9 @@
+/* { dg-lto-do link } */
+/* { dg-lto-options { { -flto -march=rv64gc -mabi=lp64d } } } */
+/* { dg-extra-ld-options "-nostdlib" } */
+
+void foo();
+
+int _start(){
+ foo();
+}
diff --git a/gcc/testsuite/gcc.target/riscv/lto/pr110812_1.c b/gcc/testsuite/gcc.target/riscv/lto/pr110812_1.c
new file mode 100644
index 0000000..34d7cbb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/lto/pr110812_1.c
@@ -0,0 +1,9 @@
+/* { dg-options { -flto -march=rv64gcv -mabi=lp64d } } */
+
+#include "riscv_vector.h"
+uint8_t *x, *y;
+void foo () {
+ int vl = __riscv_vsetvl_e8m8 (100);
+ vint8m8_t a = __riscv_vle8_v_i8m8 (x, 100);
+ __riscv_vse8_v_i8m8 (y, a, 100);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/lto/riscv-lto.exp b/gcc/testsuite/gcc.target/riscv/lto/riscv-lto.exp
new file mode 100644
index 0000000..459cb76
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/lto/riscv-lto.exp
@@ -0,0 +1,61 @@
+# Copyright (C) 2025 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Exit immediately if this isn't an RISC-V target.
+if ![istarget riscv*-*-*] then {
+ return
+}
+
+# Test link-time optimization across multiple files.
+#
+# Programs are broken into multiple files. Each one is compiled
+# separately with LTO information. The final executable is generated
+# by collecting all the generated object files using regular LTO or WHOPR.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+# Load procedures from common libraries.
+load_lib standard.exp
+load_lib gcc.exp
+
+# Load the language-independent compabibility support procedures.
+load_lib lto.exp
+
+# If LTO has not been enabled, bail.
+if { ![check_effective_target_lto] } {
+ return
+}
+
+gcc_init
+lto_init no-mathlib
+
+# Define an identifier for use with this suite to avoid name conflicts
+# with other lto tests running at the same time.
+set sid "c_lto"
+
+# Main loop.
+foreach src [lsort [find $srcdir/$subdir *_0.c]] {
+ # If we're only testing specific files and this isn't one of them, skip it.
+ if ![runtest_file_p $runtests $src] then {
+ continue
+ }
+
+ lto-execute $src $sid
+}
+
+lto_finish
diff --git a/gcc/testsuite/gcc.target/riscv/lto/riscv_vector.h b/gcc/testsuite/gcc.target/riscv/lto/riscv_vector.h
new file mode 100644
index 0000000..fbb4858f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/lto/riscv_vector.h
@@ -0,0 +1,11 @@
+/* Wrapper of riscv_vector.h, prevent riscv_vector.h including stdint.h from
+ C library, that might cause problem on testing RV32 related testcase when
+ we disable multilib. */
+#ifndef _RISCV_VECTOR_WRAP_H
+
+#define _GCC_WRAP_STDINT_H
+#include "stdint-gcc.h"
+#include_next <riscv_vector.h>
+#define _RISCV_VECTOR_WRAP_H
+
+#endif