Merge commit 'f3f6ff7b16861cd0651eccff14689536550762ae^' into HEAD

This commit is contained in:
Thomas Schwinge 2024-03-11 00:26:50 +01:00
commit b2ccc44dfb
1872 changed files with 73051 additions and 12824 deletions

113
ChangeLog
View File

@ -1,3 +1,116 @@
2023-08-29 Tsukasa OI <research_trasio@irq.a4lg.com>
* MAINTAINERS: Add myself.
2023-08-22 Filip Kastl <fkastl@suse.cz>
* MAINTAINERS: Update my email address.
2023-08-11 Eric Feng <ef2648@columbia.edu>
* MAINTAINERS: Add myself.
2023-08-07 Indu Bhagat <indu.bhagat@oracle.com>
* Makefile.def: Reflect that libsframe needs to installed before
libbfd. Reorder a bit to better track libsframe dependencies.
* Makefile.in: Regenerate.
2023-08-07 Indu Bhagat <indu.bhagat@oracle.com>
* Makefile.def: Add install dependency on libsframe for libbfd.
* Makefile.in: Regenerated.
2023-08-07 Nick Alcock <nick.alcock@oracle.com>
* libtool.m4 (lt_cv_sys_global_symbol_pipe): Augment symcode for
Solaris 11.
2023-08-07 Alexander von Gluck IV <kallisti5@unixzen.com>
* configure: Regenerate.
* configure.ac: Add Haiku to list of ELF OSes
* libtool.m4: Update sys_lib_dlsearch_path_spec on Haiku.
2023-08-07 Nick Alcock <nick.alcock@oracle.com>
* libtool.m4 (LT_PATH_NM): Handle user-specified NM with
options, including options containing paths.
2023-08-07 Nick Alcock <nick.alcock@oracle.com>
* libtool.m4 (LT_PATH_NM): Try BSDization flags with a user-provided
NM, if there is one. Run nm on itself, not on /dev/null, to avoid
errors from nms that refuse to work on non-regular files. Remove
other workarounds for this problem. Strip out blank lines from the
nm output.
2023-08-07 Arsen Arsenović <arsen@aarsen.me>
* configure.ac: Reinstate 32b PA-RISC HP-UX targets
* configure: Regenerate.
2023-08-07 Simon Marchi <simon.marchi@efficios.com>
* configure.ac: Add AC_SUBST(PKG_CONFIG_PATH).
* configure: Re-generate.
* Makefile.tpl (HOST_EXPORTS): Pass PKG_CONFIG_PATH.
(PKG_CONFIG_PATH): New.
* Makefile.in: Re-generate.
2023-08-07 Luis Machado <luis.machado@arm.com>
* configure.ac: Disable year2038 by default on 32-bit hosts.
* configure: Regenerate.
2023-08-07 Vladimir Mezentsev <vladimir.mezentsev@oracle.com>
* Makefile.def: Add gprofng module.
* configure.ac: Add --enable-gprofng option.
* Makefile.in: Regenerate.
* configure: Regenerate.
2023-08-07 Martin Liska <mliska@suse.cz>
* configure.ac: Add --enable-default-compressed-debug-sections-algorithm.
* configure: Regenerate.
2023-08-07 Fangrui Song <maskray@google.com>
* configure: Regenerate.
* configure.ac: Add --with-zstd.
2023-08-07 Arsen Arsenović <arsen@aarsen.me>
* configure: Regenerate.
* configure.ac: Recover tilegx/tilepro targets.
2023-08-07 H.J. Lu <hjl.tools@gmail.com>
* configure: Regenerated.
* libtool.m4 (_LT_CMD_OLD_ARCHIVE): Check if AR works with
--plugin and rc before enabling --plugin.
2023-08-07 H.J. Lu <hjl.tools@gmail.com>
* Makefile.tpl (AR): Add @AR_PLUGIN_OPTION@
(RANLIB): Add @RANLIB_PLUGIN_OPTION@.
* configure.ac: Include config/gcc-plugin.m4.
AC_SUBST AR_PLUGIN_OPTION and RANLIB_PLUGIN_OPTION.
* libtool.m4 (_LT_CMD_OLD_ARCHIVE): Pass --plugin to AR and
RANLIB if possible.
* Makefile.in: Regenerated.
* configure: Likewise.
2023-08-07 Arsen Arsenović <arsen@aarsen.me>
* Makefile.tpl: Substitute @GDCFLAGS@ instead of using
$(CFLAGS).
2023-08-07 David Faust <david.faust@oracle.com>
* MAINTAINERS: Add the BPF port to my reviewer listing.
2023-08-02 Jan Beulich <jbeulich@suse.com>
* MAINTAINERS: Correct my email address.

View File

@ -412,6 +412,7 @@ Chris Fairles <cfairles@gcc.gnu.org>
Alessandro Fanfarillo <fanfarillo.gcc@gmail.com>
Changpeng Fang <changpeng.fang@amd.com>
Sam Feifer <sfeifer@redhat.com>
Eric Feng <ef2648@columbia.edu>
Li Feng <nemokingdom@gmail.com>
Thomas Fitzsimmons <fitzsim@redhat.com>
Alexander Fomin <afomin.mailbox@gmail.com>
@ -490,7 +491,7 @@ Kean Johnston <jkj@sco.com>
Phillip Jordan <phillip.m.jordan@gmail.com>
Tim Josling <tej@melbpc.org.au>
Victor Kaplansky <victork@il.ibm.com>
Filip Kastl <filip.kastl@gmail.com>
Filip Kastl <fkastl@suse.cz>
Geoffrey Keating <geoffk@geoffk.org>
Brendan Kehoe <brendan@zen.org>
Andi Kleen <andi@firstfloor.org>
@ -592,6 +593,7 @@ Carlos O'Donell <carlos@redhat.com>
Peter O'Gorman <pogma@thewrittenword.com>
Patrick O'Neill <patrick@rivosinc.com>
Braden Obrzut <admin@maniacsvault.net>
Tsukasa Oi <research_trasio@irq.a4lg.com>
Andrea Ornstein <andrea.ornstein@st.com>
Maxim Ostapenko <m.ostapenko@samsung.com>
Jeevitha Palanisamy <jeevitha@linux.ibm.com>

View File

@ -462,11 +462,14 @@ dependencies = { module=all-gdbsupport; on=all-gnulib; };
dependencies = { module=all-gdbsupport; on=all-intl; };
// Host modules specific to binutils.
// build libsframe before bfd for encoder/decoder support for linking
// SFrame sections
dependencies = { module=configure-bfd; on=configure-libiberty; hard=true; };
dependencies = { module=configure-bfd; on=configure-intl; };
dependencies = { module=all-bfd; on=all-libiberty; };
dependencies = { module=all-bfd; on=all-intl; };
dependencies = { module=all-bfd; on=all-zlib; };
dependencies = { module=all-bfd; on=all-libsframe; };
dependencies = { module=configure-opcodes; on=configure-libiberty; hard=true; };
dependencies = { module=all-opcodes; on=all-libiberty; };
@ -499,6 +502,10 @@ dependencies = { module=install-strip-libctf; on=install-strip-bfd; };
dependencies = { module=install-strip-ld; on=install-strip-bfd; };
dependencies = { module=install-strip-ld; on=install-strip-libctf; };
// libbfd depends on libsframe
dependencies = { module=install-bfd; on=install-libsframe; };
dependencies = { module=install-strip-bfd; on=install-strip-libsframe; };
// libopcodes depends on libbfd
dependencies = { module=configure-opcodes; on=configure-bfd; hard=true; };
dependencies = { module=install-opcodes; on=install-bfd; };

View File

@ -68138,6 +68138,16 @@ all-stagetrain-bfd: maybe-all-stagetrain-zlib
all-stagefeedback-bfd: maybe-all-stagefeedback-zlib
all-stageautoprofile-bfd: maybe-all-stageautoprofile-zlib
all-stageautofeedback-bfd: maybe-all-stageautofeedback-zlib
all-bfd: maybe-all-libsframe
all-stage1-bfd: maybe-all-stage1-libsframe
all-stage2-bfd: maybe-all-stage2-libsframe
all-stage3-bfd: maybe-all-stage3-libsframe
all-stage4-bfd: maybe-all-stage4-libsframe
all-stageprofile-bfd: maybe-all-stageprofile-libsframe
all-stagetrain-bfd: maybe-all-stagetrain-libsframe
all-stagefeedback-bfd: maybe-all-stagefeedback-libsframe
all-stageautoprofile-bfd: maybe-all-stageautoprofile-libsframe
all-stageautofeedback-bfd: maybe-all-stageautofeedback-libsframe
configure-opcodes: configure-libiberty
configure-stage1-opcodes: configure-stage1-libiberty
configure-stage2-opcodes: configure-stage2-libiberty
@ -68276,6 +68286,8 @@ install-ld: maybe-install-libctf
install-strip-libctf: maybe-install-strip-bfd
install-strip-ld: maybe-install-strip-bfd
install-strip-ld: maybe-install-strip-libctf
install-bfd: maybe-install-libsframe
install-strip-bfd: maybe-install-strip-libsframe
configure-opcodes: configure-bfd
configure-stage1-opcodes: configure-stage1-bfd
configure-stage2-opcodes: configure-stage2-bfd

View File

@ -1,3 +1,50 @@
2023-08-11 Joseph Myers <joseph@codesourcery.com>
* gcc-plugin.m4 (GCC_ENABLE_PLUGINS): Use
export_sym_check="$ac_cv_prog_OBJDUMP -T" also when host is not
build or target.
2023-08-07 H.J. Lu <hjl.tools@gmail.com>
* pkg.m4 (PKG_CHECK_MODULES): Use AC_TRY_LINK only if
$pkg_failed = no.
2023-08-07 H.J. Lu <hjl.tools@gmail.com>
* pkg.m4 (PKG_CHECK_MODULES): Add AC_TRY_LINK to check if
$pkg_cv_[]$1[]_LIBS works.
2023-08-07 John Ericson <git@JohnEricson.me>
* picflag.m4: Simplify SHmedia NetBSD match by presuming ELF.
2023-08-07 Alan Modra <amodra@gmail.com>
* override.m4: Correct comment grammar.
2023-08-07 Alan Modra <amodra@gmail.com>
* lib-ld.m4 (AC_LIB_PROG_LD_GNU): Require AC_PROG_EGREP and
invoke $EGREP.
(AC_LIB_PROG_LD): Likewise.
2023-08-07 Christophe Lyon <christophe.lyon@arm.com>
* zstd.m4: Add minimum version requirement of 1.4.0.
2023-08-07 Fangrui Song <maskray@google.com>
* zstd.m4: New file.
2023-08-07 H.J. Lu <hjl.tools@gmail.com>
* gcc-plugin.m4 (GCC_PLUGIN_OPTION): Check if AR works with
--plugin and rc before enabling --plugin.
2023-08-07 H.J. Lu <hjl.tools@gmail.com>
* gcc-plugin.m4 (GCC_PLUGIN_OPTION): New.
2023-07-21 Sergei Trofimovich <siarheit@google.com>
* mh-mingw: Drop assignment of unused BOOT_CXXFLAGS variable.

View File

@ -49,7 +49,7 @@ AC_DEFUN([GCC_ENABLE_PLUGINS],
elif test x$host = x$target; then
export_sym_check="$gcc_cv_objdump -T"
else
export_sym_check=
export_sym_check="$ac_cv_prog_OBJDUMP -T"
fi
;;
esac

View File

@ -1,3 +1,11 @@
2023-08-29 Lehua Ding <lehua.ding@rivai.ai>
* mklog.py: Fix bugs.
2023-08-16 Andrew Pinski <apinski@marvell.com>
* gcc_update: Add libstdc++-v3/include/bits/version.h.
2023-07-13 Lehua Ding <lehua.ding@rivai.ai>
* mklog.py: Add --append option.

View File

@ -182,6 +182,7 @@ libphobos/config.h.in: libphobos/configure.ac libphobos/aclocal.m4
libphobos/configure: libphobos/configure.ac libphobos/aclocal.m4
libphobos/src/Makefile.in: libphobos/src/Makefile.am libphobos/aclocal.m4
libphobos/testsuite/Makefile.in: libphobos/testsuite/Makefile.am libphobos/aclocal.m4
libstdc++-v3/include/bits/version.h: libstdc++-v3/include/bits/version.def libstdc++-v3/include/bits/version.tpl
# Top level
Makefile.in: Makefile.tpl Makefile.def
configure: configure.ac config/acx.m4

View File

@ -398,7 +398,8 @@ if __name__ == '__main__':
args.fill_up_bug_titles, args.pr_numbers)
if args.append:
if (not args.input):
raise Exception("`-a or --append` option not support standard input")
raise Exception("`-a or --append` option not support standard "
"input")
lines = []
with open(args.input, 'r', newline='\n') as f:
# 1 -> not find the possible start of diff log
@ -408,13 +409,14 @@ if __name__ == '__main__':
for line in f:
if maybe_diff_log == 1 and line == "---\n":
maybe_diff_log = 2
elif maybe_diff_log == 2 and \
re.match("\s[^\s]+\s+\|\s\d+\s[+\-]+\n", line):
elif (maybe_diff_log == 2 and
re.match(r"\s[^\s]+\s+\|\s+\d+\s[+\-]+\n", line)):
lines += [output, "---\n", line]
maybe_diff_log = 3
else:
# the possible start is not the true start.
if maybe_diff_log == 2:
lines.append("---\n")
maybe_diff_log = 1
lines.append(line)
with open(args.input, "w") as f:

View File

@ -1,3 +1,14 @@
2023-08-17 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* inclhack.def (darwin_flt_eval_method): Handle macOS 14 guard
variant.
* fixincl.x: Regenerate.
* tests/base/math.h [DARWIN_FLT_EVAL_METHOD_CHECK]: Update test.
2023-08-07 Nick Alcock <nick.alcock@oracle.com>
* configure: Regenerate.
2023-06-15 Marek Polacek <polacek@redhat.com>
* Makefile.in: Set and use PICFLAG and LD_PICFLAG. Use the "pic"

View File

@ -2,11 +2,11 @@
*
* DO NOT EDIT THIS FILE (fixincl.x)
*
* It has been AutoGen-ed January 22, 2023 at 09:03:29 PM by AutoGen 5.18.12
* It has been AutoGen-ed August 17, 2023 at 10:16:38 AM by AutoGen 5.18.12
* From the definitions inclhack.def
* and the template file fixincl
*/
/* DO NOT SVN-MERGE THIS FILE, EITHER Sun Jan 22 21:03:29 CET 2023
/* DO NOT SVN-MERGE THIS FILE, EITHER Thu Aug 17 10:16:38 CEST 2023
*
* You must regenerate it. Use the ./genfixes script.
*
@ -3674,7 +3674,7 @@ tSCC* apzDarwin_Flt_Eval_MethodMachs[] = {
* content selection pattern - do fix if pattern found
*/
tSCC zDarwin_Flt_Eval_MethodSelect0[] =
"^#if __FLT_EVAL_METHOD__ == 0$";
"^#if __FLT_EVAL_METHOD__ == 0( \\|\\| __FLT_EVAL_METHOD__ == -1)?$";
#define DARWIN_FLT_EVAL_METHOD_TEST_CT 1
static tTestDesc aDarwin_Flt_Eval_MethodTests[] = {
@ -3685,7 +3685,7 @@ static tTestDesc aDarwin_Flt_Eval_MethodTests[] = {
*/
static const char* apzDarwin_Flt_Eval_MethodPatch[] = {
"format",
"#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 16",
"%0 || __FLT_EVAL_METHOD__ == 16",
(char*)NULL };
/* * * * * * * * * * * * * * * * * * * * * * * * * *

View File

@ -1819,10 +1819,11 @@ fix = {
hackname = darwin_flt_eval_method;
mach = "*-*-darwin*";
files = math.h;
select = "^#if __FLT_EVAL_METHOD__ == 0$";
select = "^#if __FLT_EVAL_METHOD__ == 0( \\|\\| __FLT_EVAL_METHOD__ == -1)?$";
c_fix = format;
c_fix_arg = "#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 16";
test_text = "#if __FLT_EVAL_METHOD__ == 0";
c_fix_arg = "%0 || __FLT_EVAL_METHOD__ == 16";
test_text = "#if __FLT_EVAL_METHOD__ == 0\n"
"#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == -1";
};
/*

View File

@ -32,6 +32,7 @@
#if defined( DARWIN_FLT_EVAL_METHOD_CHECK )
#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 16
#if __FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == -1 || __FLT_EVAL_METHOD__ == 16
#endif /* DARWIN_FLT_EVAL_METHOD_CHECK */

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
20230807
20230904

View File

@ -55,6 +55,7 @@ MAKEOVERRIDES =
# -------------------------------
build=@build@
build_os=@build_os@
host=@host@
host_noncanonical=@host_noncanonical@
host_os=@host_os@
@ -469,6 +470,7 @@ USER_H = $(srcdir)/ginclude/float.h \
$(srcdir)/ginclude/stdnoreturn.h \
$(srcdir)/ginclude/stdalign.h \
$(srcdir)/ginclude/stdatomic.h \
$(srcdir)/ginclude/stdckdint.h \
$(EXTRA_HEADERS)
USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
@ -895,7 +897,8 @@ OPTIONS_C_EXTRA = $(PRETTY_PRINT_H)
BCONFIG_H = bconfig.h $(build_xm_file_list)
CONFIG_H = config.h $(host_xm_file_list)
TCONFIG_H = tconfig.h $(xm_file_list)
TM_P_H = tm_p.h $(tm_p_file_list)
# Some $(target)-protos.h depends on tree.h
TM_P_H = tm_p.h $(tm_p_file_list) $(TREE_H)
TM_D_H = tm_d.h $(tm_d_file_list)
TM_RUST_H = tm_rust.h $(tm_rust_file_list)
GTM_H = tm.h $(tm_file_list) insn-constants.h
@ -996,7 +999,7 @@ GIMPLE_H = gimple.h gimple.def gsstruct.def $(VEC_H) \
$(GGC_H) $(BASIC_BLOCK_H) $(TREE_H) tree-ssa-operands.h \
tree-ssa-alias.h $(INTERNAL_FN_H) $(HASH_TABLE_H) is-a.h
GCOV_IO_H = gcov-io.h version.h auto-host.h gcov-counter.def
RECOG_H = recog.h
RECOG_H = recog.h $(TREE_H)
EMIT_RTL_H = emit-rtl.h
FLAGS_H = flags.h flag-types.h $(OPTIONS_H)
OPTIONS_H = options.h flag-types.h $(OPTIONS_H_EXTRA)
@ -1318,6 +1321,7 @@ ANALYZER_OBJS = \
analyzer/pending-diagnostic.o \
analyzer/program-point.o \
analyzer/program-state.o \
analyzer/ranges.o \
analyzer/region.o \
analyzer/region-model.o \
analyzer/region-model-asm.o \
@ -3036,8 +3040,8 @@ build/genhooks.o : genhooks.cc $(TARGET_DEF) $(C_TARGET_DEF) \
$(SYSTEM_H) errors.h
build/genmddump.o : genmddump.cc $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) \
$(CORETYPES_H) $(GTM_H) errors.h $(READ_MD_H) $(GENSUPPORT_H)
build/genmatch.o : genmatch.cc $(BCONFIG_H) $(SYSTEM_H) \
$(CORETYPES_H) errors.h $(HASH_TABLE_H) hash-map.h $(GGC_H) is-a.h \
build/genmatch.o : genmatch.cc $(BCONFIG_H) $(SYSTEM_H) $(CORETYPES_H) \
errors.h $(HASH_TABLE_H) hash-map.h $(GGC_H) is-a.h ordered-hash-map.h \
tree.def builtins.def internal-fn.def case-cfn-macros.h $(CPPLIB_H)
build/gencfn-macros.o : gencfn-macros.cc $(BCONFIG_H) $(SYSTEM_H) \
$(CORETYPES_H) errors.h $(HASH_TABLE_H) hash-set.h builtins.def \
@ -3363,8 +3367,13 @@ stmp-fixinc: gsyslimits.h macro_list fixinc_list \
multi_dir=`echo $${ml} | sed -e 's/^[^;]*;//'`; \
fix_dir=include-fixed$${multi_dir}; \
if ! $(inhibit_libc) && test ! -d ${BUILD_SYSTEM_HEADER_DIR}; then \
echo The directory that should contain system headers does not exist: >&2 ; \
echo "The directory (BUILD_SYSTEM_HEADER_DIR) that should contain system headers does not exist:" >&2 ; \
echo " ${BUILD_SYSTEM_HEADER_DIR}" >&2 ; \
case ${build_os} in \
darwin*) \
echo "(on Darwin this usually means you need to pass the --with-sysroot= flag to point to a valid MacOS SDK)" >&2; \
;; \
esac; \
tooldir_sysinc=`echo "${gcc_tooldir}/sys-include" | sed -e :a -e "s,[^/]*/\.\.\/,," -e ta`; \
if test "x${BUILD_SYSTEM_HEADER_DIR}" = "x$${tooldir_sysinc}"; \
then sleep 1; else exit 1; fi; \

View File

@ -1,3 +1,23 @@
2023-08-07 Sheri Bernstein <bernstein@adacore.com>
* libgnat/s-parame__qnx.adb: Refactor multiple returns.
2023-08-07 Piotr Trojanek <trojanek@adacore.com>
* libgnat/i-cstrin.ads (Value): Extend preconditions; adapt comment for
the package.
2023-08-07 Yannick Moy <moy@adacore.com>
* sem_res.adb (Resolve_Call): Always call Cannot_Inline so that
subprogram called is marked as not always inlined.
2023-08-07 Javier Miranda <miranda@adacore.com>
* sem_res.adb (Resolve_Type_Conversion): Do not warn on conversion
to class-wide type on internally build helpers of class-wide
preconditions.
2023-08-03 Sheri Bernstein <bernstein@adacore.com>
* libgnat/s-aridou.adb: Add pragma to exempt Improper_Returns.

View File

@ -1,3 +1,403 @@
2023-09-01 benjamin priour <priour.be@gmail.com>
PR analyzer/105948
PR analyzer/94355
* analyzer.h (is_placement_new_p): New declaration.
* call-details.cc
(call_details::deref_ptr_arg): New function.
Dereference the argument at given index if possible.
* call-details.h: Declaration of the above function.
* kf-lang-cp.cc (is_placement_new_p): Returns true if the gcall
is recognized as a placement new.
(kf_operator_delete::impl_call_post): Unbinding a region and its
descendents now poisons with POISON_KIND_DELETED.
(register_known_functions_lang_cp): Known function "operator
delete" is now registered only once independently of its number of
arguments.
* region-model.cc (region_model::eval_condition): Now
recursively calls itself if any of the operand is wrapped in a
cast.
* sm-malloc.cc (malloc_state_machine::on_stmt):
Add placement new recognition.
* svalue.cc (poison_kind_to_str): Wording for the new PK.
* svalue.h (enum poison_kind): Add value POISON_KIND_DELETED.
2023-08-31 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
* kf.cc: Change spelling to macOS.
2023-08-30 Eric Feng <ef2648@columbia.edu>
PR analyzer/107646
* engine.cc (impl_region_model_context::warn): New optional
parameter.
* exploded-graph.h (class impl_region_model_context): Likewise.
* region-model.cc (region_model::pop_frame): New callback
feature for region_model::pop_frame.
* region-model.h (struct append_regions_cb_data): Likewise.
(class region_model): Likewise.
(class region_model_context): New optional parameter.
(class region_model_context_decorator): Likewise.
2023-08-30 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
* region-model.cc: Define INCLUDE_ALGORITHM.
2023-08-29 David Malcolm <dmalcolm@redhat.com>
PR analyzer/99860
* analyzer-selftests.cc (selftest::run_analyzer_selftests): Call
selftest::analyzer_ranges_cc_tests.
* analyzer-selftests.h (selftest::run_analyzer_selftests): New
decl.
* analyzer.opt (Wanalyzer-overlapping-buffers): New option.
* call-details.cc: Include "analyzer/ranges.h" and "make-unique.h".
(class overlapping_buffers): New.
(call_details::complain_about_overlap): New.
* call-details.h (call_details::complain_about_overlap): New decl.
* kf.cc (kf_memcpy_memmove::impl_call_pre): Call
cd.complain_about_overlap for memcpy and memcpy_chk.
(kf_strcat::impl_call_pre): Call cd.complain_about_overlap.
(kf_strcpy::impl_call_pre): Likewise.
* ranges.cc: New file.
* ranges.h: New file.
2023-08-29 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* kf.cc (kf_strdup::impl_call_pre): Set size of
dynamically-allocated buffer. Simulate copying the string from
the source region to the new buffer.
2023-08-27 benjamin priour <vultkayn@gcc.gnu.org>
PR analyzer/96395
* analyzer.h (class known_function): Add virtual casts
to builtin_known_function.
(class builtin_known_function): New subclass of known_function
for builtins.
* kf.cc (class kf_alloca): Now derived from
builtin_known_function.
(class kf_calloc): Likewise.
(class kf_free): Likewise.
(class kf_malloc): Likewise.
(class kf_memcpy_memmove): Likewise.
(class kf_memset): Likewise.
(class kf_realloc): Likewise.
(class kf_strchr): Likewise.
(class kf_sprintf): Likewise.
(class kf_strcat): Likewise.
(class kf_strcpy): Likewise.
(class kf_strdup): Likewise.
(class kf_strlen): Likewise.
(class kf_strndup): Likewise.
(register_known_functions): Builtins are now registered as
known_functions by name rather than by their BUILTIN_CODE.
* known-function-manager.cc (get_normal_builtin): New overload.
* known-function-manager.h: New overload declaration.
* region-model.cc (region_model::get_builtin_kf): New function.
* region-model.h (class region_model): Add declaration of
get_builtin_kf.
* sm-fd.cc: For called recognized as builtins, use the
attributes of that builtin as defined in gcc/builtins.def
rather than the user's.
* sm-malloc.cc (malloc_state_machine::on_stmt): Likewise.
2023-08-25 David Malcolm <dmalcolm@redhat.com>
* access-diagram.cc (class string_region_spatial_item): Remove
assumption that the string is written to the start of the cluster.
2023-08-24 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* call-details.cc
(call_details::check_for_null_terminated_string_arg): Split into
overloads, one taking just an arg_idx, the other a new
"include_terminator" param.
* call-details.h: Likewise.
* kf.cc (class kf_strcat): New.
(kf_strcpy::impl_call_pre): Update for change to
check_for_null_terminated_string_arg.
(register_known_functions): Register kf_strcat.
* region-model.cc
(region_model::check_for_null_terminated_string_arg): Split into
overloads, one taking just an arg_idx, the other a new
"include_terminator" param. When returning an svalue, handle
"include_terminator" being false by subtracting one.
* region-model.h
(region_model::check_for_null_terminated_string_arg): Split into
overloads, one taking just an arg_idx, the other a new
"include_terminator" param.
2023-08-24 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* region-model.cc (fragment::has_null_terminator): Handle
SK_BITS_WITHIN.
2023-08-24 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* region-model-manager.cc
(region_model_manager::get_or_create_initial_value): Simplify
INIT_VAL(ELEMENT_REG(STRING_REG), CONSTANT_SVAL) to
CONSTANT_SVAL(STRING[N]).
2023-08-24 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* region-model.cc (fragment::has_null_terminator): Move STRING_CST
handling to fragment::string_cst_has_null_terminator; also use it to
handle INIT_VAL(STRING_REG).
(fragment::string_cst_has_null_terminator): New, from above.
2023-08-24 David Malcolm <dmalcolm@redhat.com>
* kf.cc (kf_memcpy_memmove::impl_call_pre): Reimplement using
region_model::copy_bytes.
* region-model.cc (region_model::read_bytes): New.
(region_model::copy_bytes): New.
* region-model.h (region_model::read_bytes): New decl.
(region_model::copy_bytes): New decl.
2023-08-24 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* region-model.cc (region_model::get_string_size): Delete both.
* region-model.h (region_model::get_string_size): Delete both
decls.
2023-08-24 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* kf.cc (kf_strcpy::impl_call_pre): Reimplement using
check_for_null_terminated_string_arg.
* region-model.cc (region_model::get_store_bytes): Shortcut
reading all of a string_region.
(region_model::scan_for_null_terminator): Use get_store_value for
the bytes rather than "unknown" when returning an unknown length.
(region_model::write_bytes): New.
* region-model.h (region_model::write_bytes): New decl.
2023-08-24 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* region-model.cc (iterable_cluster::iterable_cluster): Add
symbolic binding keys to m_symbolic_bindings.
(iterable_cluster::has_symbolic_bindings_p): New.
(iterable_cluster::m_symbolic_bindings): New field.
(region_model::scan_for_null_terminator): Treat clusters with
symbolic bindings as having unknown strlen.
2023-08-24 David Malcolm <dmalcolm@redhat.com>
* engine.cc (impl_path_context::impl_path_context): Add logger
param.
(impl_path_context::bifurcate): Add log message.
(impl_path_context::terminate_path): Likewise.
(impl_path_context::m_logger): New field.
(exploded_graph::process_node): Pass logger to path_ctxt ctor.
2023-08-22 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* kf-analyzer.cc (class kf_analyzer_get_strlen): Move to kf.cc.
(register_known_analyzer_functions): Use make_kf_strlen.
* kf.cc (class kf_strlen::impl_call_pre): Replace with
implementation of kf_analyzer_get_strlen from kf-analyzer.cc.
Handle "UNKNOWN" return from check_for_null_terminated_string_arg
by falling back to a conjured svalue.
(make_kf_strlen): New.
(register_known_functions): Use make_kf_strlen.
* known-function-manager.h (make_kf_strlen): New decl.
2023-08-22 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* call-details.cc (call_details::call_details): New ctor.
* call-details.h (call_details::call_details): New ctor decl.
(struct call_arg_details): Move here from region-model.cc.
* region-model.cc (region_model::check_call_format_attr): New.
(region_model::check_call_args): Call it.
(struct call_arg_details): Move it to call-details.h.
* region-model.h (region_model::check_call_format_attr): New decl.
2023-08-22 David Malcolm <dmalcolm@redhat.com>
* kf.cc (class kf_fopen): New.
(register_known_functions): Register it.
2023-08-22 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* analyzer.opt (Wanalyzer-unterminated-string): Delete.
* call-details.cc
(call_details::check_for_null_terminated_string_arg): Convert
return type from void to const svalue *. Add param "out_sval".
* call-details.h
(call_details::check_for_null_terminated_string_arg): Likewise.
* kf-analyzer.cc (kf_analyzer_get_strlen::impl_call_pre): Wire up
to result of check_for_null_terminated_string_arg.
* region-model.cc (get_strlen): Delete.
(class unterminated_string_arg): Delete.
(struct fragment): New.
(class iterable_cluster): New.
(region_model::get_store_bytes): New.
(get_tree_for_byte_offset): New.
(region_model::scan_for_null_terminator): New.
(region_model::check_for_null_terminated_string_arg): Convert
return type from void to const svalue *. Add param "out_sval".
Reimplement in terms of scan_for_null_terminator, dropping the
special-case for -Wanalyzer-unterminated-string.
* region-model.h (region_model::get_store_bytes): New decl.
(region_model::scan_for_null_terminator): New decl.
(region_model::check_for_null_terminated_string_arg): Convert
return type from void to const svalue *. Add param "out_sval".
* store.cc (concrete_binding::get_byte_range): New.
* store.h (concrete_binding::get_byte_range): New decl.
(store_manager::get_concrete_binding): New overload.
2023-08-22 David Malcolm <dmalcolm@redhat.com>
* region-model.cc (region_model_context_decorator::add_event):
Handle m_inner being NULL.
* region-model.h (class region_model_context_decorator): Likewise.
(annotating_context::warn): Likewise.
2023-08-22 David Malcolm <dmalcolm@redhat.com>
* diagnostic-manager.cc (saved_diagnostic::add_event): New.
(saved_diagnostic::add_any_saved_events): New.
(diagnostic_manager::add_event): New.
(dedupe_winners::emit_best): New.
(diagnostic_manager::emit_saved_diagnostic): Make "sd" param
non-const. Call saved_diagnostic::add_any_saved_events.
* diagnostic-manager.h (saved_diagnostic::add_event): New decl.
(saved_diagnostic::add_any_saved_events): New decl.
(saved_diagnostic::m_saved_events): New field.
(diagnostic_manager::add_event): New decl.
(diagnostic_manager::emit_saved_diagnostic): Make "sd" param
non-const.
* engine.cc (impl_region_model_context::add_event): New.
* exploded-graph.h (impl_region_model_context::add_event): New decl.
* region-model.cc
(noop_region_model_context::add_event): New.
(region_model_context_decorator::add_event): New.
* region-model.h (region_model_context::add_event): New vfunc.
(noop_region_model_context::add_event): New decl.
(region_model_context_decorator::add_event): New decl.
2023-08-22 David Malcolm <dmalcolm@redhat.com>
* region-model.cc
(class check_external_function_for_access_attr::annotating_ctxt):
Convert to an annotating_context.
* region-model.h (class note_adding_context): Rename to...
(class annotating_context): ...this, updating the "warn" method.
(note_adding_context::make_note): Replace with...
(annotating_context::add_annotations): ...this.
2023-08-14 benjamin priour <vultkayn@gcc.gnu.org>
PR analyzer/110543
* analyzer.opt: Add new option.
* diagnostic-manager.cc
(diagnostic_manager::prune_path): Call prune_system_headers.
(prune_frame): New function that deletes all events in a frame.
(diagnostic_manager::prune_system_headers): New function.
* diagnostic-manager.h: Add prune_system_headers declaration.
2023-08-11 David Malcolm <dmalcolm@redhat.com>
PR analyzer/105899
* analyzer.opt (Wanalyzer-unterminated-string): New.
* call-details.cc
(call_details::check_for_null_terminated_string_arg): New.
* call-details.h
(call_details::check_for_null_terminated_string_arg): New decl.
* kf-analyzer.cc (class kf_analyzer_get_strlen): New.
(register_known_analyzer_functions): Register it.
* kf.cc (kf_error::impl_call_pre): Check that format arg is a
valid null-terminated string.
(kf_putenv::impl_call_pre): Likewise for the sole param.
(kf_strchr::impl_call_pre): Likewise for the first param.
(kf_strcpy::impl_call_pre): Likewise for the second param.
(kf_strdup::impl_call_pre): Likewise for the sole param.
* region-model.cc (get_strlen): New.
(struct call_arg_details): New.
(inform_about_expected_null_terminated_string_arg): New.
(class unterminated_string_arg): New.
(region_model::check_for_null_terminated_string_arg): New.
* region-model.h
(region_model::check_for_null_terminated_string_arg): New decl.
2023-08-11 Eric Feng <ef2648@columbia.edu>
PR analyzer/107646
* call-details.h: New function.
* region-model.cc (region_model::get_or_create_region_for_heap_alloc):
New optional parameters.
* region-model.h (class region_model): New optional parameters.
* sm-malloc.cc (on_realloc_with_move): New function.
(region_model::transition_ptr_sval_non_null): New function.
2023-08-09 David Malcolm <dmalcolm@redhat.com>
* analyzer.h (class pure_known_function_with_default_return): New
subclass.
* call-details.cc (const_fn_p): Move here from region-model.cc.
(maybe_get_const_fn_result): Likewise.
(get_result_size_in_bytes): Likewise.
(call_details::set_any_lhs_with_defaults): New function, based on
code in region_model::on_call_pre.
* call-details.h (call_details::set_any_lhs_with_defaults): New
decl.
* diagnostic-manager.cc
(diagnostic_manager::emit_saved_diagnostic): Log the index of the
saved_diagnostic.
* kf.cc (pure_known_function_with_default_return::impl_call_pre):
New.
(kf_memset::impl_call_pre): Set the LHS to the first param.
(kf_putenv::impl_call_pre): Call cd.set_any_lhs_with_defaults.
(kf_sprintf::impl_call_pre): Call cd.set_any_lhs_with_defaults.
(class kf_stack_restore): Derive from
pure_known_function_with_default_return.
(class kf_stack_save): Likewise.
(kf_strlen::impl_call_pre): Call cd.set_any_lhs_with_defaults.
* region-model-reachability.cc (reachable_regions::handle_sval):
Remove logic for symbolic regions for pointers.
* region-model.cc (region_model::canonicalize): Remove purging of
dynamic extents workaround for surplus values from
region_model::on_call_pre's default LHS code.
(const_fn_p): Move to call-details.cc.
(maybe_get_const_fn_result): Likewise.
(get_result_size_in_bytes): Likewise.
(region_model::update_for_nonzero_return): Call
cd.set_any_lhs_with_defaults.
(region_model::on_call_pre): Remove the assignment to the LHS of a
default return value, instead requiring all known_function
implementations to write to any LHS of the call. Use
cd.set_any_lhs_with_defaults on the non-kf paths.
* sm-fd.cc (kf_socket::outcome_of_socket::update_model): Use
cd.set_any_lhs_with_defaults when failing to get at fd state.
(kf_bind::outcome_of_bind::update_model): Likewise.
(kf_listen::outcome_of_listen::update_model): Likewise.
(kf_accept::outcome_of_accept::update_model): Likewise.
(kf_connect::outcome_of_connect::update_model): Likewise.
(kf_read::impl_call_pre): Use cd.set_any_lhs_with_defaults.
* sm-file.cc (class kf_stdio_output_fn): Derive from
pure_known_function_with_default_return.
(class kf_ferror): Likewise.
(class kf_fileno): Likewise.
(kf_fgets::impl_call_pre): Use cd.set_any_lhs_with_defaults.
(kf_read::impl_call_pre): Likewise.
(class kf_getc): Derive from
pure_known_function_with_default_return.
(class kf_getchar): Likewise.
* varargs.cc (kf_va_arg::impl_call_pre): Use
cd.set_any_lhs_with_defaults.
2023-08-04 David Malcolm <dmalcolm@redhat.com>
PR analyzer/110426

View File

@ -1509,10 +1509,16 @@ public:
out.add_all_bytes_in_range (m_actual_bits);
else
{
byte_range head_of_string (0, m_ellipsis_head_len);
byte_range bytes (0, 0);
bool valid = m_actual_bits.as_concrete_byte_range (&bytes);
gcc_assert (valid);
byte_range head_of_string (bytes.get_start_byte_offset (),
m_ellipsis_head_len);
out.add_all_bytes_in_range (head_of_string);
byte_range tail_of_string
(TREE_STRING_LENGTH (string_cst) - m_ellipsis_tail_len,
((bytes.get_start_byte_offset ()
+ TREE_STRING_LENGTH (string_cst)
- m_ellipsis_tail_len),
m_ellipsis_tail_len);
out.add_all_bytes_in_range (tail_of_string);
/* Adding the above pair of ranges will also effectively add
@ -1535,11 +1541,14 @@ public:
tree string_cst = get_string_cst ();
if (m_show_full_string)
{
for (byte_offset_t byte_idx = bytes.get_start_byte_offset ();
byte_idx < bytes.get_next_byte_offset ();
byte_idx = byte_idx + 1)
add_column_for_byte (t, btm, sm, byte_idx,
byte_idx_table_y, byte_val_table_y);
for (byte_offset_t byte_idx_within_cluster
= bytes.get_start_byte_offset ();
byte_idx_within_cluster < bytes.get_next_byte_offset ();
byte_idx_within_cluster = byte_idx_within_cluster + 1)
add_column_for_byte
(t, btm, sm, byte_idx_within_cluster,
byte_idx_within_cluster - bytes.get_start_byte_offset (),
byte_idx_table_y, byte_val_table_y);
if (m_show_utf8)
{
@ -1566,10 +1575,13 @@ public:
= decoded_char.m_start_byte - TREE_STRING_POINTER (string_cst);
byte_size_t size_in_bytes
= decoded_char.m_next_byte - decoded_char.m_start_byte;
byte_range bytes (start_byte_idx, size_in_bytes);
byte_range cluster_bytes_for_codepoint
(start_byte_idx + bytes.get_start_byte_offset (),
size_in_bytes);
const table::rect_t code_point_table_rect
= btm.get_table_rect (&m_string_reg, bytes,
= btm.get_table_rect (&m_string_reg,
cluster_bytes_for_codepoint,
utf8_code_point_table_y, 1);
char buf[100];
sprintf (buf, "U+%04x", decoded_char.m_ch);
@ -1579,7 +1591,8 @@ public:
if (show_unichars)
{
const table::rect_t character_table_rect
= btm.get_table_rect (&m_string_reg, bytes,
= btm.get_table_rect (&m_string_reg,
cluster_bytes_for_codepoint,
utf8_character_table_y, 1);
if (cpp_is_printable_char (decoded_char.m_ch))
t.set_cell_span (character_table_rect,
@ -1598,12 +1611,14 @@ public:
{
/* Head of string. */
for (int byte_idx = 0; byte_idx < m_ellipsis_head_len; byte_idx++)
add_column_for_byte (t, btm, sm, byte_idx,
add_column_for_byte (t, btm, sm,
byte_idx + bytes.get_start_byte_offset (),
byte_idx,
byte_idx_table_y, byte_val_table_y);
/* Ellipsis (two rows high). */
const byte_range ellipsis_bytes
(m_ellipsis_head_len,
(m_ellipsis_head_len + bytes.get_start_byte_offset (),
TREE_STRING_LENGTH (string_cst)
- (m_ellipsis_head_len + m_ellipsis_tail_len));
const table::rect_t table_rect
@ -1616,7 +1631,9 @@ public:
= (TREE_STRING_LENGTH (string_cst) - m_ellipsis_tail_len);
byte_idx < TREE_STRING_LENGTH (string_cst);
byte_idx++)
add_column_for_byte (t, btm, sm, byte_idx,
add_column_for_byte (t, btm, sm,
byte_idx + bytes.get_start_byte_offset (),
byte_idx,
byte_idx_table_y, byte_val_table_y);
}
@ -1660,25 +1677,27 @@ private:
void add_column_for_byte (table &t, const bit_to_table_map &btm,
style_manager &sm,
const byte_offset_t byte_idx,
const byte_offset_t byte_idx_within_cluster,
const byte_offset_t byte_idx_within_string,
const int byte_idx_table_y,
const int byte_val_table_y) const
{
tree string_cst = get_string_cst ();
gcc_assert (byte_idx >= 0);
gcc_assert (byte_idx < TREE_STRING_LENGTH (string_cst));
gcc_assert (byte_idx_within_string >= 0);
gcc_assert (byte_idx_within_string < TREE_STRING_LENGTH (string_cst));
const byte_range bytes (byte_idx, 1);
const byte_range bytes (byte_idx_within_cluster, 1);
if (1) // show_byte_indices
{
const table::rect_t idx_table_rect
= btm.get_table_rect (&m_string_reg, bytes, byte_idx_table_y, 1);
t.set_cell_span (idx_table_rect,
fmt_styled_string (sm, "[%li]",
byte_idx.ulow ()));
byte_idx_within_string.ulow ()));
}
char byte_val = TREE_STRING_POINTER (string_cst)[byte_idx.ulow ()];
char byte_val
= TREE_STRING_POINTER (string_cst)[byte_idx_within_string.ulow ()];
const table::rect_t val_table_rect
= btm.get_table_rect (&m_string_reg, bytes, byte_val_table_y, 1);
table_cell_content content (make_cell_content_for_byte (sm, byte_val));

View File

@ -55,6 +55,7 @@ run_analyzer_selftests ()
analyzer_function_set_cc_tests ();
analyzer_program_point_cc_tests ();
analyzer_program_state_cc_tests ();
analyzer_ranges_cc_tests ();
analyzer_region_model_cc_tests ();
analyzer_sm_file_cc_tests ();
analyzer_sm_signal_cc_tests ();

View File

@ -38,6 +38,7 @@ extern void analyzer_constraint_manager_cc_tests ();
extern void analyzer_function_set_cc_tests ();
extern void analyzer_program_point_cc_tests ();
extern void analyzer_program_state_cc_tests ();
extern void analyzer_ranges_cc_tests ();
extern void analyzer_region_model_cc_tests ();
extern void analyzer_sm_file_cc_tests ();
extern void analyzer_sm_signal_cc_tests ();

View File

@ -128,6 +128,10 @@ struct interesting_t;
class feasible_node;
class known_function;
class builtin_known_function;
class internal_known_function;
/* Forward decls of functions. */
extern void dump_tree (pretty_printer *pp, tree t);
@ -279,6 +283,24 @@ public:
{
return;
}
virtual const builtin_known_function *
dyn_cast_builtin_kf () const { return NULL; }
};
/* Subclass of known_function for builtin functions. */
class builtin_known_function : public known_function
{
public:
virtual enum built_in_function builtin_code () const = 0;
tree builtin_decl () const {
gcc_assert (builtin_code () < END_BUILTINS);
return builtin_info[builtin_code ()].decl;
}
const builtin_known_function *
dyn_cast_builtin_kf () const final override { return this; }
};
/* Subclass of known_function for IFN_* functions. */
@ -293,6 +315,16 @@ public:
}
};
/* Abstract subclass of known_function that merely sets the return
value of the function (based on function attributes), and assumes
it has no side-effects. */
class pure_known_function_with_default_return : public known_function
{
public:
void impl_call_pre (const call_details &cd) const override;
};
extern void register_known_functions (known_function_manager &mgr);
extern void register_known_analyzer_functions (known_function_manager &kfm);
extern void register_known_fd_functions (known_function_manager &kfm);
@ -391,6 +423,7 @@ extern bool is_std_named_call_p (const_tree fndecl, const char *funcname,
const gcall *call, unsigned int num_args);
extern bool is_setjmp_call_p (const gcall *call);
extern bool is_longjmp_call_p (const gcall *call);
extern bool is_placement_new_p (const gcall *call);
extern const char *get_user_facing_name (const gcall *call);

View File

@ -154,6 +154,10 @@ Wanalyzer-out-of-bounds
Common Var(warn_analyzer_out_of_bounds) Init(1) Warning
Warn about code paths in which a write or read to a buffer is out-of-bounds.
Wanalyzer-overlapping-buffers
Common Var(warn_analyzer_overlapping_buffers) Init(1) Warning
Warn about code paths in which undefined behavior would occur due to overlapping buffers.
Wanalyzer-possible-null-argument
Common Var(warn_analyzer_possible_null_argument) Init(1) Warning
Warn about code paths in which a possibly-NULL value is passed to a must-not-be-NULL function argument.
@ -290,6 +294,10 @@ fanalyzer-transitivity
Common Var(flag_analyzer_transitivity) Init(0)
Enable transitivity of constraints during analysis.
fanalyzer-show-events-in-system-headers
Common Var(flag_analyzer_show_events_in_system_headers) Init(0)
Show events within system headers in analyzer execution paths.
fanalyzer-call-summaries
Common Var(flag_analyzer_call_summaries) Init(0)
Approximate the effect of function calls to simplify analysis.

View File

@ -34,8 +34,10 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-pretty-print.h"
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
#include "analyzer/ranges.h"
#include "stringpool.h"
#include "attribs.h"
#include "make-unique.h"
#if ENABLE_ANALYZER
@ -58,6 +60,16 @@ call_details::call_details (const gcall *call, region_model *model,
}
}
/* call_details's ctor: copy CD, but override the context,
using CTXT instead. */
call_details::call_details (const call_details &cd,
region_model_context *ctxt)
{
*this = cd;
m_ctxt = ctxt;
}
/* Get the manager from m_model. */
region_model_manager *
@ -105,6 +117,135 @@ call_details::maybe_set_lhs (const svalue *result) const
return false;
}
/* Return true if CD is known to be a call to a function with
__attribute__((const)). */
static bool
const_fn_p (const call_details &cd)
{
tree fndecl = cd.get_fndecl_for_call ();
if (!fndecl)
return false;
gcc_assert (DECL_P (fndecl));
return TREE_READONLY (fndecl);
}
/* If this CD is known to be a call to a function with
__attribute__((const)), attempt to get a const_fn_result_svalue
based on the arguments, or return NULL otherwise. */
static const svalue *
maybe_get_const_fn_result (const call_details &cd)
{
if (!const_fn_p (cd))
return NULL;
unsigned num_args = cd.num_args ();
if (num_args > const_fn_result_svalue::MAX_INPUTS)
/* Too many arguments. */
return NULL;
auto_vec<const svalue *> inputs (num_args);
for (unsigned arg_idx = 0; arg_idx < num_args; arg_idx++)
{
const svalue *arg_sval = cd.get_arg_svalue (arg_idx);
if (!arg_sval->can_have_associated_state_p ())
return NULL;
inputs.quick_push (arg_sval);
}
region_model_manager *mgr = cd.get_manager ();
const svalue *sval
= mgr->get_or_create_const_fn_result_svalue (cd.get_lhs_type (),
cd.get_fndecl_for_call (),
inputs);
return sval;
}
/* Look for attribute "alloc_size" on the called function and, if found,
return a symbolic value of type size_type_node for the allocation size
based on the call's parameters.
Otherwise, return null. */
static const svalue *
get_result_size_in_bytes (const call_details &cd)
{
const tree attr = cd.lookup_function_attribute ("alloc_size");
if (!attr)
return nullptr;
const tree atval_1 = TREE_VALUE (attr);
if (!atval_1)
return nullptr;
unsigned argidx1 = TREE_INT_CST_LOW (TREE_VALUE (atval_1)) - 1;
if (cd.num_args () <= argidx1)
return nullptr;
const svalue *sval_arg1 = cd.get_arg_svalue (argidx1);
if (const tree atval_2 = TREE_CHAIN (atval_1))
{
/* Two arguments. */
unsigned argidx2 = TREE_INT_CST_LOW (TREE_VALUE (atval_2)) - 1;
if (cd.num_args () <= argidx2)
return nullptr;
const svalue *sval_arg2 = cd.get_arg_svalue (argidx2);
/* TODO: ideally we shouldn't need this cast here;
see PR analyzer/110902. */
return cd.get_manager ()->get_or_create_cast
(size_type_node,
cd.get_manager ()->get_or_create_binop (size_type_node,
MULT_EXPR,
sval_arg1, sval_arg2));
}
else
/* Single argument. */
return cd.get_manager ()->get_or_create_cast (size_type_node, sval_arg1);
}
/* If this call has an LHS, assign a value to it based on attributes
of the function:
- if __attribute__((const)), use a const_fn_result_svalue,
- if __attribute__((malloc)), use a heap-allocated region with
unknown content
- otherwise, use a conjured_svalue.
If __attribute__((alloc_size), set the dynamic extents on the region
pointed to. */
void
call_details::set_any_lhs_with_defaults () const
{
if (!m_lhs_region)
return;
const svalue *sval = maybe_get_const_fn_result (*this);
if (!sval)
{
region_model_manager *mgr = get_manager ();
if (lookup_function_attribute ("malloc"))
{
const region *new_reg
= m_model->get_or_create_region_for_heap_alloc (NULL, m_ctxt);
m_model->mark_region_as_unknown (new_reg, NULL);
sval = mgr->get_ptr_svalue (get_lhs_type (), new_reg);
}
else
/* For the common case of functions without __attribute__((const)),
use a conjured value, and purge any prior state involving that
value (in case this is in a loop). */
sval = get_or_create_conjured_svalue (m_lhs_region);
if (const svalue *size_in_bytes = get_result_size_in_bytes (*this))
{
const region *reg
= m_model->deref_rvalue (sval, NULL_TREE, m_ctxt, false);
m_model->set_dynamic_extents (reg, size_in_bytes, m_ctxt);
}
}
maybe_set_lhs (sval);
}
/* Return the number of arguments used by the call statement. */
unsigned
@ -154,6 +295,17 @@ call_details::get_arg_svalue (unsigned idx) const
return m_model->get_rvalue (arg, m_ctxt);
}
/* If argument IDX's svalue at the callsite is of pointer type,
return the region it points to.
Otherwise return NULL. */
const region *
call_details::deref_ptr_arg (unsigned idx) const
{
const svalue *ptr_sval = get_arg_svalue (idx);
return m_model->deref_rvalue (ptr_sval, get_arg_tree (idx), m_ctxt);
}
/* Attempt to get the string literal for argument IDX, or return NULL
otherwise.
For use when implementing "__analyzer_*" functions that take
@ -247,6 +399,129 @@ call_details::lookup_function_attribute (const char *attr_name) const
return lookup_attribute (attr_name, TYPE_ATTRIBUTES (allocfntype));
}
void
call_details::check_for_null_terminated_string_arg (unsigned arg_idx) const
{
check_for_null_terminated_string_arg (arg_idx, false, nullptr);
}
const svalue *
call_details::
check_for_null_terminated_string_arg (unsigned arg_idx,
bool include_terminator,
const svalue **out_sval) const
{
region_model *model = get_model ();
return model->check_for_null_terminated_string_arg (*this,
arg_idx,
include_terminator,
out_sval);
}
/* A subclass of pending_diagnostic for complaining about overlapping
buffers. */
class overlapping_buffers
: public pending_diagnostic_subclass<overlapping_buffers>
{
public:
overlapping_buffers (tree fndecl)
: m_fndecl (fndecl)
{
}
const char *get_kind () const final override
{
return "overlapping_buffers";
}
bool operator== (const overlapping_buffers &other) const
{
return m_fndecl == other.m_fndecl;
}
int get_controlling_option () const final override
{
return OPT_Wanalyzer_overlapping_buffers;
}
bool emit (rich_location *rich_loc, logger *) final override
{
auto_diagnostic_group d;
bool warned;
warned = warning_at (rich_loc, get_controlling_option (),
"overlapping buffers passed as arguments to %qD",
m_fndecl);
// TODO: draw a picture?
if (warned)
inform (DECL_SOURCE_LOCATION (m_fndecl),
"the behavior of %qD is undefined for overlapping buffers",
m_fndecl);
return warned;
}
label_text describe_final_event (const evdesc::final_event &ev) final override
{
return ev.formatted_print
("overlapping buffers passed as arguments to %qD",
m_fndecl);
}
private:
tree m_fndecl;
};
/* Check if the buffers pointed to by arguments ARG_IDX_A and ARG_IDX_B
(zero-based) overlap, when considering them both to be of size
NUM_BYTES_READ_SVAL.
If they do overlap, complain to the context. */
void
call_details::complain_about_overlap (unsigned arg_idx_a,
unsigned arg_idx_b,
const svalue *num_bytes_read_sval) const
{
region_model_context *ctxt = get_ctxt ();
if (!ctxt)
return;
region_model *model = get_model ();
region_model_manager *mgr = model->get_manager ();
const svalue *arg_a_ptr_sval = get_arg_svalue (arg_idx_a);
if (arg_a_ptr_sval->get_kind () == SK_UNKNOWN)
return;
const region *arg_a_reg = model->deref_rvalue (arg_a_ptr_sval,
get_arg_tree (arg_idx_a),
ctxt);
const svalue *arg_b_ptr_sval = get_arg_svalue (arg_idx_b);
if (arg_b_ptr_sval->get_kind () == SK_UNKNOWN)
return;
const region *arg_b_reg = model->deref_rvalue (arg_b_ptr_sval,
get_arg_tree (arg_idx_b),
ctxt);
if (arg_a_reg->get_base_region () != arg_b_reg->get_base_region ())
return;
/* Are they within NUM_BYTES_READ_SVAL of each other? */
symbolic_byte_range byte_range_a (arg_a_reg->get_offset (mgr),
num_bytes_read_sval,
*mgr);
symbolic_byte_range byte_range_b (arg_b_reg->get_offset (mgr),
num_bytes_read_sval,
*mgr);
if (!byte_range_a.intersection (byte_range_b, *model).is_true ())
return;
ctxt->warn (make_unique<overlapping_buffers> (get_fndecl_for_call ()));
}
} // namespace ana
#endif /* #if ENABLE_ANALYZER */

View File

@ -30,6 +30,7 @@ class call_details
public:
call_details (const gcall *call, region_model *model,
region_model_context *ctxt);
call_details (const call_details &cd, region_model_context *ctxt);
region_model *get_model () const { return m_model; }
region_model_manager *get_manager () const;
@ -41,6 +42,7 @@ public:
const region *get_lhs_region () const { return m_lhs_region; }
bool maybe_set_lhs (const svalue *result) const;
void set_any_lhs_with_defaults () const;
unsigned num_args () const;
bool arg_is_pointer_p (unsigned idx) const
@ -48,6 +50,10 @@ public:
return POINTER_TYPE_P (get_arg_type (idx));
}
bool arg_is_size_p (unsigned idx) const;
bool arg_is_integral_p (unsigned idx) const
{
return INTEGRAL_TYPE_P (get_arg_type (idx));
}
const gcall *get_call_stmt () const { return m_call; }
location_t get_location () const;
@ -55,6 +61,7 @@ public:
tree get_arg_tree (unsigned idx) const;
tree get_arg_type (unsigned idx) const;
const svalue *get_arg_svalue (unsigned idx) const;
const region *deref_ptr_arg (unsigned idx) const;
const char *get_arg_string_literal (unsigned idx) const;
tree get_fndecl_for_call () const;
@ -66,6 +73,18 @@ public:
tree lookup_function_attribute (const char *attr_name) const;
void
check_for_null_terminated_string_arg (unsigned arg_idx) const;
const svalue *
check_for_null_terminated_string_arg (unsigned arg_idx,
bool include_terminator,
const svalue **out_sval) const;
void
complain_about_overlap (unsigned arg_idx_a,
unsigned arg_idx_b,
const svalue *num_bytes_read_sval) const;
private:
const gcall *m_call;
region_model *m_model;
@ -74,6 +93,35 @@ private:
const region *m_lhs_region;
};
/* A bundle of information about a problematic argument at a callsite
for use by pending_diagnostic subclasses for reporting and
for deduplication. */
struct call_arg_details
{
public:
call_arg_details (const call_details &cd, unsigned arg_idx)
: m_call (cd.get_call_stmt ()),
m_called_fndecl (cd.get_fndecl_for_call ()),
m_arg_idx (arg_idx),
m_arg_expr (cd.get_arg_tree (arg_idx))
{
}
bool operator== (const call_arg_details &other) const
{
return (m_call == other.m_call
&& m_called_fndecl == other.m_called_fndecl
&& m_arg_idx == other.m_arg_idx
&& pending_diagnostic::same_tree_p (m_arg_expr, other.m_arg_expr));
}
const gcall *m_call;
tree m_called_fndecl;
unsigned m_arg_idx; // 0-based
tree m_arg_expr;
};
} // namespace ana
#endif /* GCC_ANALYZER_CALL_DETAILS_H */

View File

@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "input.h"
#include "pretty-print.h"
#include "gcc-rich-location.h"
#include "gimple-pretty-print.h"
@ -720,6 +721,15 @@ saved_diagnostic::add_note (std::unique_ptr<pending_note> pn)
m_notes.safe_push (pn.release ());
}
/* Add EVENT to this diagnostic. */
void
saved_diagnostic::add_event (std::unique_ptr<checker_event> event)
{
gcc_assert (event);
m_saved_events.safe_push (event.release ());
}
/* Return a new json::object of the form
{"sm": optional str,
"enode": int,
@ -889,6 +899,19 @@ saved_diagnostic::supercedes_p (const saved_diagnostic &other) const
return m_d->supercedes_p (*other.m_d);
}
/* Move any saved checker_events from this saved_diagnostic to
the end of DST_PATH. */
void
saved_diagnostic::add_any_saved_events (checker_path &dst_path)
{
for (auto &event : m_saved_events)
{
dst_path.add_event (std::unique_ptr<checker_event> (event));
event = nullptr;
}
}
/* Emit any pending notes owned by this diagnostic. */
void
@ -1056,6 +1079,20 @@ diagnostic_manager::add_note (std::unique_ptr<pending_note> pn)
sd->add_note (std::move (pn));
}
/* Add EVENT to the most recent saved_diagnostic. */
void
diagnostic_manager::add_event (std::unique_ptr<checker_event> event)
{
LOG_FUNC (get_logger ());
gcc_assert (event);
/* Get most recent saved_diagnostic. */
gcc_assert (m_saved_diagnostics.length () > 0);
saved_diagnostic *sd = m_saved_diagnostics[m_saved_diagnostics.length () - 1];
sd->add_event (std::move (event));
}
/* Return a new json::object of the form
{"diagnostics" : [obj for saved_diagnostic]}. */
@ -1307,7 +1344,7 @@ public:
{
saved_diagnostic **slot = m_map.get (key);
gcc_assert (*slot);
const saved_diagnostic *sd = *slot;
saved_diagnostic *sd = *slot;
dm->emit_saved_diagnostic (eg, *sd);
}
}
@ -1369,10 +1406,11 @@ diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
void
diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
const saved_diagnostic &sd)
saved_diagnostic &sd)
{
LOG_SCOPE (get_logger ());
log ("sd: %qs at SN: %i", sd.m_d->get_kind (), sd.m_snode->m_index);
log ("sd[%i]: %qs at SN: %i",
sd.get_index (), sd.m_d->get_kind (), sd.m_snode->m_index);
log ("num dupes: %i", sd.get_num_dupes ());
pretty_printer *pp = global_dc->printer->clone ();
@ -1393,6 +1431,11 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
/* Now prune it to just cover the most pertinent events. */
prune_path (&emission_path, sd.m_sm, sd.m_sval, sd.m_state);
/* Add any saved events to the path, giving contextual information
about what the analyzer was simulating as the diagnostic was
generated. These don't get pruned, as they are probably pertinent. */
sd.add_any_saved_events (emission_path);
/* Add a final event to the path, covering the diagnostic itself.
We use the final enode from the epath, which might be different from
the sd.m_enode, as the dedupe code doesn't care about enodes, just
@ -2281,6 +2324,8 @@ diagnostic_manager::prune_path (checker_path *path,
path->maybe_log (get_logger (), "path");
prune_for_sm_diagnostic (path, sm, sval, state);
prune_interproc_events (path);
if (! flag_analyzer_show_events_in_system_headers)
prune_system_headers (path);
consolidate_conditions (path);
finish_pruning (path);
path->maybe_log (get_logger (), "pruned");
@ -2667,6 +2712,99 @@ diagnostic_manager::prune_interproc_events (checker_path *path) const
while (changed);
}
/* Remove everything within [call point, IDX]. For consistency,
IDX should represent the return event of the frame to delete,
or if there is none it should be the last event of the frame.
After this function, IDX designates the event prior to calling
this frame. */
static void
prune_frame (checker_path *path, int &idx)
{
gcc_assert (idx >= 0);
int nesting = 1;
if (path->get_checker_event (idx)->is_return_p ())
nesting = 0;
do
{
if (path->get_checker_event (idx)->is_call_p ())
nesting--;
else if (path->get_checker_event (idx)->is_return_p ())
nesting++;
path->delete_event (idx--);
} while (idx >= 0 && nesting != 0);
}
/* This function is called when fanalyzer-show-events-in-system-headers
is disabled and will prune the diagnostic of all events within a
system header, only keeping the entry and exit events to the header.
This should be called after diagnostic_manager::prune_interproc_events
so that sucessive events [system header call, system header return]
are preserved thereafter.
Given a diagnostics path diving into a system header in the form
[
prefix events...,
system header call,
system header entry,
events within system headers...,
system header return,
suffix events...
]
then transforms it into
[
prefix events...,
system header call,
system header return,
suffix events...
]. */
void
diagnostic_manager::prune_system_headers (checker_path *path) const
{
int idx = (signed)path->num_events () - 1;
while (idx >= 0)
{
const checker_event *event = path->get_checker_event (idx);
/* Prune everything between
[..., system entry, (...), system return, ...]. */
if (event->is_return_p ()
&& in_system_header_at (event->get_location ()))
{
int ret_idx = idx;
prune_frame (path, idx);
if (get_logger ())
{
log ("filtering system headers events %i-%i:",
idx, ret_idx);
}
// Delete function entry within system headers.
if (idx >= 0)
{
event = path->get_checker_event (idx);
if (event->is_function_entry_p ()
&& in_system_header_at (event->get_location ()))
{
if (get_logger ())
{
label_text desc (event->get_desc (false));
log ("filtering event %i:"
"system header entry event: %s",
idx, desc.get ());
}
path->delete_event (idx);
}
}
}
idx--;
}
}
/* Return true iff event IDX within PATH is on the same line as REF_EXP_LOC. */
static bool

View File

@ -42,6 +42,7 @@ public:
bool operator== (const saved_diagnostic &other) const;
void add_note (std::unique_ptr<pending_note> pn);
void add_event (std::unique_ptr<checker_event> event);
json::object *to_json () const;
@ -64,6 +65,8 @@ public:
bool supercedes_p (const saved_diagnostic &other) const;
void add_any_saved_events (checker_path &dst_path);
void emit_any_notes () const;
//private:
@ -87,6 +90,12 @@ private:
auto_vec<const saved_diagnostic *> m_duplicates;
auto_delete_vec <pending_note> m_notes;
/* Optionally: additional context-dependent events to be emitted
immediately before the warning_event, giving more details of what
operation was being simulated when a diagnostic was saved
e.g. "looking for null terminator in param 2 of 'foo'". */
auto_delete_vec <checker_event> m_saved_events;
};
class path_builder;
@ -124,11 +133,12 @@ public:
std::unique_ptr<pending_diagnostic> d);
void add_note (std::unique_ptr<pending_note> pn);
void add_event (std::unique_ptr<checker_event> event);
void emit_saved_diagnostics (const exploded_graph &eg);
void emit_saved_diagnostic (const exploded_graph &eg,
const saved_diagnostic &sd);
saved_diagnostic &sd);
unsigned get_num_diagnostics () const
{
@ -180,6 +190,7 @@ private:
state_machine::state_t state) const;
void update_for_unsuitable_sm_exprs (tree *expr) const;
void prune_interproc_events (checker_path *path) const;
void prune_system_headers (checker_path *path) const;
void consolidate_conditions (checker_path *path) const;
void finish_pruning (checker_path *path) const;

View File

@ -115,10 +115,12 @@ impl_region_model_context (program_state *state,
}
bool
impl_region_model_context::warn (std::unique_ptr<pending_diagnostic> d)
impl_region_model_context::warn (std::unique_ptr<pending_diagnostic> d,
const stmt_finder *custom_finder)
{
LOG_FUNC (get_logger ());
if (m_stmt == NULL && m_stmt_finder == NULL)
auto curr_stmt_finder = custom_finder ? custom_finder : m_stmt_finder;
if (m_stmt == NULL && curr_stmt_finder == NULL)
{
if (get_logger ())
get_logger ()->log ("rejecting diagnostic: no stmt");
@ -129,7 +131,7 @@ impl_region_model_context::warn (std::unique_ptr<pending_diagnostic> d)
bool terminate_path = d->terminate_path_p ();
if (m_eg->get_diagnostic_manager ().add_diagnostic
(m_enode_for_diag, m_enode_for_diag->get_supernode (),
m_stmt, m_stmt_finder, std::move (d)))
m_stmt, curr_stmt_finder, std::move (d)))
{
if (m_path_ctxt
&& terminate_path
@ -149,6 +151,14 @@ impl_region_model_context::add_note (std::unique_ptr<pending_note> pn)
m_eg->get_diagnostic_manager ().add_note (std::move (pn));
}
void
impl_region_model_context::add_event (std::unique_ptr<checker_event> event)
{
LOG_FUNC (get_logger ());
if (m_eg)
m_eg->get_diagnostic_manager ().add_event (std::move (event));
}
void
impl_region_model_context::on_svalue_leak (const svalue *sval)
@ -3840,8 +3850,10 @@ exploded_graph::maybe_create_dynamic_call (const gcall *call,
class impl_path_context : public path_context
{
public:
impl_path_context (const program_state *cur_state)
impl_path_context (const program_state *cur_state,
logger *logger)
: m_cur_state (cur_state),
m_logger (logger),
m_terminate_path (false)
{
}
@ -3860,6 +3872,9 @@ public:
void
bifurcate (std::unique_ptr<custom_edge_info> info) final override
{
if (m_logger)
m_logger->log ("bifurcating path");
if (m_state_at_bifurcation)
/* Verify that the state at bifurcation is consistent when we
split into multiple out-edges. */
@ -3876,6 +3891,8 @@ public:
void terminate_path () final override
{
if (m_logger)
m_logger->log ("terminating path");
m_terminate_path = true;
}
@ -3892,6 +3909,8 @@ public:
private:
const program_state *m_cur_state;
logger *m_logger;
/* Lazily-created copy of the state before the split. */
std::unique_ptr<program_state> m_state_at_bifurcation;
@ -4036,7 +4055,7 @@ exploded_graph::process_node (exploded_node *node)
exactly one stmt, the one that caused the change. */
program_state next_state (state);
impl_path_context path_ctxt (&next_state);
impl_path_context path_ctxt (&next_state, logger);
uncertainty_t uncertainty;
const supernode *snode = point.get_supernode ();

View File

@ -56,8 +56,10 @@ class impl_region_model_context : public region_model_context
uncertainty_t *uncertainty,
logger *logger = NULL);
bool warn (std::unique_ptr<pending_diagnostic> d) final override;
bool warn (std::unique_ptr<pending_diagnostic> d,
const stmt_finder *custom_finder = NULL) final override;
void add_note (std::unique_ptr<pending_note> pn) final override;
void add_event (std::unique_ptr<checker_event> event) final override;
void on_svalue_leak (const svalue *) override;
void on_liveness_change (const svalue_set &live_svalues,
const region_model *model) final override;
@ -106,6 +108,7 @@ class impl_region_model_context : public region_model_context
std::unique_ptr<sm_context> *out_sm_context) override;
const gimple *get_stmt () const override { return m_stmt; }
const exploded_graph *get_eg () const override { return m_eg; }
exploded_graph *m_eg;
log_user m_logger;

View File

@ -379,6 +379,7 @@ register_known_analyzer_functions (known_function_manager &kfm)
kfm.add ("__analyzer_eval", make_unique<kf_analyzer_eval> ());
kfm.add ("__analyzer_get_unknown_ptr",
make_unique<kf_analyzer_get_unknown_ptr> ());
kfm.add ("__analyzer_get_strlen", make_kf_strlen ());
}
} // namespace ana

View File

@ -35,6 +35,38 @@ along with GCC; see the file COPYING3. If not see
#if ENABLE_ANALYZER
/* Return true if CALL is a non-allocating operator new or operator new []
that contains no user-defined args, i.e. having any signature of:
- void* operator new (std::size_t count, void* ptr);
- void* operator new[] (std::size_t count, void* ptr);
See https://en.cppreference.com/w/cpp/memory/new/operator_new. */
bool is_placement_new_p (const gcall *call)
{
gcc_assert (call);
tree fndecl = gimple_call_fndecl (call);
if (!fndecl || TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
/* Give up on overloaded operator new. */
return false;
if (!is_named_call_p (fndecl, "operator new", call, 2)
&& !is_named_call_p (fndecl, "operator new []", call, 2))
return false;
/* We must distinguish between an allocating non-throwing new
and a non-allocating new.
The former might have one of the following signatures :
void* operator new (std::size_t count, const std::nothrow_t& tag);
void* operator new[] (std::size_t count, const std::nothrow_t& tag);
Whereas a placement new would take a pointer. */
tree arg1_type = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
return TREE_CODE (TREE_VALUE (arg1_type)) == POINTER_TYPE;
}
namespace ana {
/* Implementations of specific functions. */
@ -46,7 +78,11 @@ class kf_operator_new : public known_function
public:
bool matches_call_types_p (const call_details &cd) const final override
{
return cd.num_args () == 1;
return (cd.num_args () == 1
&& cd.arg_is_size_p (0))
|| (cd.num_args () == 2
&& cd.arg_is_size_p (0)
&& POINTER_TYPE_P (cd.get_arg_type (1)));
}
void impl_call_pre (const call_details &cd) const final override
@ -54,28 +90,74 @@ public:
region_model *model = cd.get_model ();
region_model_manager *mgr = cd.get_manager ();
const svalue *size_sval = cd.get_arg_svalue (0);
const region *new_reg
= model->get_or_create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
if (cd.get_lhs_type ())
region_model_context *ctxt = cd.get_ctxt ();
const gcall *call = cd.get_call_stmt ();
/* If the call was actually a placement new, check that accessing
the buffer lhs is placed into does not result in out-of-bounds. */
if (is_placement_new_p (call))
{
const svalue *ptr_sval
= mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
cd.maybe_set_lhs (ptr_sval);
const region *ptr_reg = cd.deref_ptr_arg (1);
if (ptr_reg && cd.get_lhs_type ())
{
const svalue *num_bytes_sval = cd.get_arg_svalue (0);
const region *sized_new_reg
= mgr->get_sized_region (ptr_reg,
cd.get_lhs_type (),
num_bytes_sval);
model->check_region_for_write (sized_new_reg,
nullptr,
ctxt);
const svalue *ptr_sval
= mgr->get_ptr_svalue (cd.get_lhs_type (), sized_new_reg);
cd.maybe_set_lhs (ptr_sval);
}
}
/* If the call is an allocating new, then create a heap allocated
region. */
else
{
const region *new_reg
= model->get_or_create_region_for_heap_alloc (size_sval, ctxt);
if (cd.get_lhs_type ())
{
const svalue *ptr_sval
= mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
cd.maybe_set_lhs (ptr_sval);
}
}
}
void impl_call_post (const call_details &cd) const final override
{
region_model *model = cd.get_model ();
region_model_manager *mgr = cd.get_manager ();
tree callee_fndecl = cd.get_fndecl_for_call ();
region_model_context *ctxt = cd.get_ctxt ();
/* If the call is guaranteed to return nonnull
then add a nonnull constraint to the allocated region. */
if (!TREE_NOTHROW (callee_fndecl) && flag_exceptions)
{
const svalue *null_sval
= mgr->get_or_create_null_ptr (cd.get_lhs_type ());
const svalue *result
= model->get_store_value (cd.get_lhs_region (), ctxt);
model->add_constraint (result, NE_EXPR, null_sval, ctxt);
}
}
};
/* Handler for "operator delete", both the sized and unsized variants
(2 arguments and 1 argument respectively), and for "operator delete []" */
/* Handler for "operator delete" and for "operator delete []",
both the sized and unsized variants
(2 arguments and 1 argument respectively). */
class kf_operator_delete : public known_function
{
public:
kf_operator_delete (unsigned num_args) : m_num_args (num_args) {}
bool matches_call_types_p (const call_details &cd) const final override
{
return cd.num_args () == m_num_args;
return cd.num_args () == 1 or cd.num_args () == 2;
}
void impl_call_post (const call_details &cd) const final override
@ -86,12 +168,11 @@ public:
{
/* If the ptr points to an underlying heap region, delete it,
poisoning pointers. */
model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
model->unbind_region_and_descendents (freed_reg,
POISON_KIND_DELETED);
}
}
private:
unsigned m_num_args;
};
/* Populate KFM with instances of known functions relating to C++. */
@ -101,9 +182,8 @@ register_known_functions_lang_cp (known_function_manager &kfm)
{
kfm.add ("operator new", make_unique<kf_operator_new> ());
kfm.add ("operator new []", make_unique<kf_operator_new> ());
kfm.add ("operator delete", make_unique<kf_operator_delete> (1));
kfm.add ("operator delete", make_unique<kf_operator_delete> (2));
kfm.add ("operator delete []", make_unique<kf_operator_delete> (1));
kfm.add ("operator delete", make_unique<kf_operator_delete> ());
kfm.add ("operator delete []", make_unique<kf_operator_delete> ());
}
} // namespace ana

View File

@ -40,17 +40,30 @@ along with GCC; see the file COPYING3. If not see
namespace ana {
/* class pure_known_function_with_default_return : public known_function. */
void
pure_known_function_with_default_return::
impl_call_pre (const call_details &cd) const
{
cd.set_any_lhs_with_defaults ();
}
/* Implementations of specific functions. */
/* Handler for "alloca". */
class kf_alloca : public known_function
class kf_alloca : public builtin_known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
{
return cd.num_args () == 1;
}
enum built_in_function builtin_code () const final override
{
return BUILT_IN_ALLOCA;
}
void impl_call_pre (const call_details &cd) const final override;
};
@ -313,7 +326,7 @@ public:
/* Handler for "calloc". */
class kf_calloc : public known_function
class kf_calloc : public builtin_known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
@ -322,6 +335,11 @@ public:
&& cd.arg_is_size_p (0)
&& cd.arg_is_size_p (1));
}
enum built_in_function builtin_code () const final override
{
return BUILT_IN_CALLOC;
}
void impl_call_pre (const call_details &cd) const final override;
};
@ -405,8 +423,39 @@ kf_error::impl_call_pre (const call_details &cd) const
if (!model->add_constraint (status, EQ_EXPR, integer_zero_node, ctxt))
if (ctxt)
ctxt->terminate_path ();
/* Check "format" arg. */
const int fmt_arg_idx = (m_min_args == 3) ? 2 : 4;
model->check_for_null_terminated_string_arg (cd, fmt_arg_idx);
}
/* Handler for fopen.
FILE *fopen (const char *filename, const char *mode);
See e.g. https://en.cppreference.com/w/c/io/fopen
https://www.man7.org/linux/man-pages/man3/fopen.3.html
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/fopen-wfopen?view=msvc-170 */
class kf_fopen : public known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
{
return (cd.num_args () == 2
&& cd.arg_is_pointer_p (0)
&& cd.arg_is_pointer_p (1));
}
void impl_call_pre (const call_details &cd) const final override
{
cd.check_for_null_terminated_string_arg (0);
cd.check_for_null_terminated_string_arg (1);
cd.set_any_lhs_with_defaults ();
/* fopen's mode param is effectively a mini-DSL, but there are various
non-standard extensions, so we don't bother to check it. */
}
};
/* Handler for "free", after sm-handling.
If the ptr points to an underlying heap region, delete the region,
@ -422,12 +471,16 @@ kf_error::impl_call_pre (const call_details &cd) const
all pointers to the region to the "freed" state together, regardless
of casts. */
class kf_free : public known_function
class kf_free : public builtin_known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
{
return (cd.num_args () == 0 && cd.arg_is_pointer_p (0));
return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
}
enum built_in_function builtin_code () const final override
{
return BUILT_IN_FREE;
}
void impl_call_post (const call_details &cd) const final override;
};
@ -448,7 +501,7 @@ kf_free::impl_call_post (const call_details &cd) const
/* Handle the on_call_pre part of "malloc". */
class kf_malloc : public known_function
class kf_malloc : public builtin_known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
@ -456,6 +509,10 @@ public:
return (cd.num_args () == 1
&& cd.arg_is_size_p (0));
}
enum built_in_function builtin_code () const final override
{
return BUILT_IN_MALLOC;
}
void impl_call_pre (const call_details &cd) const final override;
};
@ -477,12 +534,19 @@ kf_malloc::impl_call_pre (const call_details &cd) const
/* Handler for "memcpy" and "__builtin_memcpy",
"memmove", and "__builtin_memmove". */
/* TODO: complain about overlapping src and dest for the memcpy
variants. */
class kf_memcpy_memmove : public known_function
class kf_memcpy_memmove : public builtin_known_function
{
public:
enum kf_memcpy_memmove_variant
{
KF_MEMCPY,
KF_MEMCPY_CHK,
KF_MEMMOVE,
KF_MEMMOVE_CHK,
};
kf_memcpy_memmove (enum kf_memcpy_memmove_variant variant)
: m_variant (variant) {};
bool matches_call_types_p (const call_details &cd) const final override
{
return (cd.num_args () == 3
@ -490,7 +554,25 @@ public:
&& cd.arg_is_pointer_p (1)
&& cd.arg_is_size_p (2));
}
enum built_in_function builtin_code () const final override
{
switch (m_variant)
{
case KF_MEMCPY:
return BUILT_IN_MEMCPY;
case KF_MEMCPY_CHK:
return BUILT_IN_MEMCPY_CHK;
case KF_MEMMOVE:
return BUILT_IN_MEMMOVE;
case KF_MEMMOVE_CHK:
return BUILT_IN_MEMMOVE_CHK;
default:
gcc_unreachable ();
}
}
void impl_call_pre (const call_details &cd) const final override;
private:
const enum kf_memcpy_memmove_variant m_variant;
};
void
@ -501,7 +583,6 @@ kf_memcpy_memmove::impl_call_pre (const call_details &cd) const
const svalue *num_bytes_sval = cd.get_arg_svalue (2);
region_model *model = cd.get_model ();
region_model_manager *mgr = cd.get_manager ();
const region *dest_reg
= model->deref_rvalue (dest_ptr_sval, cd.get_arg_tree (0), cd.get_ctxt ());
@ -509,29 +590,45 @@ kf_memcpy_memmove::impl_call_pre (const call_details &cd) const
= model->deref_rvalue (src_ptr_sval, cd.get_arg_tree (1), cd.get_ctxt ());
cd.maybe_set_lhs (dest_ptr_sval);
/* Check for overlap. */
switch (m_variant)
{
case KF_MEMCPY:
case KF_MEMCPY_CHK:
cd.complain_about_overlap (0, 1, num_bytes_sval);
break;
const region *sized_src_reg
= mgr->get_sized_region (src_reg, NULL_TREE, num_bytes_sval);
const region *sized_dest_reg
= mgr->get_sized_region (dest_reg, NULL_TREE, num_bytes_sval);
const svalue *src_contents_sval
= model->get_store_value (sized_src_reg, cd.get_ctxt ());
model->check_for_poison (src_contents_sval, cd.get_arg_tree (1),
sized_src_reg, cd.get_ctxt ());
model->set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ());
case KF_MEMMOVE:
case KF_MEMMOVE_CHK:
/* It's OK for memmove's arguments to overlap. */
break;
default:
gcc_unreachable ();
}
model->copy_bytes (dest_reg,
src_reg, cd.get_arg_tree (1),
num_bytes_sval,
cd.get_ctxt ());
}
/* Handler for "memset" and "__builtin_memset". */
class kf_memset : public known_function
class kf_memset : public builtin_known_function
{
public:
kf_memset (bool chk_variant) : m_chk_variant (chk_variant) {}
bool matches_call_types_p (const call_details &cd) const final override
{
return (cd.num_args () == 3 && cd.arg_is_pointer_p (0));
}
enum built_in_function builtin_code () const final override
{
return m_chk_variant ? BUILT_IN_MEMSET_CHK : BUILT_IN_MEMSET;
}
void impl_call_pre (const call_details &cd) const final override;
private:
const bool m_chk_variant;
};
void
@ -557,6 +654,8 @@ kf_memset::impl_call_pre (const call_details &cd) const
nullptr,
cd.get_ctxt ());
model->fill_region (sized_dest_reg, fill_value_u8);
cd.maybe_set_lhs (dest_sval);
}
/* A subclass of pending_diagnostic for complaining about 'putenv'
@ -663,6 +762,7 @@ public:
gcc_assert (fndecl);
region_model_context *ctxt = cd.get_ctxt ();
region_model *model = cd.get_model ();
model->check_for_null_terminated_string_arg (cd, 0);
const svalue *ptr_sval = cd.get_arg_svalue (0);
const region *reg
= model->deref_rvalue (ptr_sval, cd.get_arg_tree (0), ctxt);
@ -683,6 +783,7 @@ public:
ctxt->warn (make_unique<putenv_of_auto_var> (fndecl, reg));
break;
}
cd.set_any_lhs_with_defaults ();
}
};
@ -709,7 +810,7 @@ public:
Each of these has a custom_edge_info subclass, which updates
the region_model and sm-state of the destination state. */
class kf_realloc : public known_function
class kf_realloc : public builtin_known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
@ -718,6 +819,12 @@ public:
&& cd.arg_is_pointer_p (0)
&& cd.arg_is_size_p (1));
}
enum built_in_function builtin_code () const final override
{
return BUILT_IN_REALLOC;
}
void impl_call_post (const call_details &cd) const final override;
};
@ -930,13 +1037,22 @@ kf_realloc::impl_call_post (const call_details &cd) const
/* Handler for "strchr" and "__builtin_strchr". */
class kf_strchr : public known_function
class kf_strchr : public builtin_known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
{
return (cd.num_args () == 2 && cd.arg_is_pointer_p (0));
}
void impl_call_pre (const call_details &cd) const final override
{
cd.check_for_null_terminated_string_arg (0);
}
enum built_in_function builtin_code () const final override
{
return BUILT_IN_STRCHR;
}
void impl_call_post (const call_details &cd) const final override;
};
@ -1013,7 +1129,7 @@ kf_strchr::impl_call_post (const call_details &cd) const
int sprintf(char *str, const char *format, ...);
*/
class kf_sprintf : public known_function
class kf_sprintf : public builtin_known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
@ -1023,6 +1139,11 @@ public:
&& cd.arg_is_pointer_p (1));
}
enum built_in_function builtin_code () const final override
{
return BUILT_IN_SPRINTF;
}
void impl_call_pre (const call_details &cd) const final override
{
/* For now, merely assume that the destination buffer gets set to a
@ -1034,12 +1155,13 @@ public:
= model->deref_rvalue (dst_ptr, cd.get_arg_tree (0), ctxt);
const svalue *content = cd.get_or_create_conjured_svalue (dst_reg);
model->set_value (dst_reg, content, ctxt);
cd.set_any_lhs_with_defaults ();
}
};
/* Handler for "__builtin_stack_restore". */
class kf_stack_restore : public known_function
class kf_stack_restore : public pure_known_function_with_default_return
{
public:
bool matches_call_types_p (const call_details &) const final override
@ -1052,7 +1174,7 @@ public:
/* Handler for "__builtin_stack_save". */
class kf_stack_save : public known_function
class kf_stack_save : public pure_known_function_with_default_return
{
public:
bool matches_call_types_p (const call_details &) const final override
@ -1063,12 +1185,14 @@ public:
/* Currently a no-op. */
};
/* Handler for "strcpy" and "__builtin_strcpy_chk". */
/* Handler for "strcat" and "__builtin_strcat_chk". */
class kf_strcpy : public known_function
class kf_strcat : public builtin_known_function
{
public:
kf_strcpy (unsigned int num_args) : m_num_args (num_args) {}
kf_strcat (unsigned int num_args, bool chk_variant)
: m_num_args (num_args),
m_chk_variant (chk_variant) {}
bool matches_call_types_p (const call_details &cd) const final override
{
return (cd.num_args () == m_num_args
@ -1076,116 +1200,197 @@ public:
&& cd.arg_is_pointer_p (1));
}
enum built_in_function builtin_code () const final override
{
return m_chk_variant ? BUILT_IN_STRCAT_CHK : BUILT_IN_STRCAT;
}
void impl_call_pre (const call_details &cd) const final override
{
region_model *model = cd.get_model ();
region_model_manager *mgr = cd.get_manager ();
const svalue *dest_sval = cd.get_arg_svalue (0);
const region *dest_reg = model->deref_rvalue (dest_sval, cd.get_arg_tree (0),
cd.get_ctxt ());
const svalue *dst_strlen_sval
= cd.check_for_null_terminated_string_arg (0, false, nullptr);
if (!dst_strlen_sval)
{
if (cd.get_ctxt ())
cd.get_ctxt ()->terminate_path ();
return;
}
const svalue *bytes_to_copy;
const svalue *num_src_bytes_read_sval
= cd.check_for_null_terminated_string_arg (1, true, &bytes_to_copy);
if (!num_src_bytes_read_sval)
{
if (cd.get_ctxt ())
cd.get_ctxt ()->terminate_path ();
return;
}
cd.maybe_set_lhs (dest_sval);
cd.complain_about_overlap (0, 1, num_src_bytes_read_sval);
const region *offset_reg
= mgr->get_offset_region (dest_reg, NULL_TREE, dst_strlen_sval);
model->write_bytes (offset_reg,
num_src_bytes_read_sval,
bytes_to_copy,
cd.get_ctxt ());
}
private:
unsigned int m_num_args;
const bool m_chk_variant;
};
/* Handler for "strcpy" and "__builtin_strcpy_chk". */
class kf_strcpy : public builtin_known_function
{
public:
kf_strcpy (unsigned int num_args, bool chk_variant)
: m_num_args (num_args),
m_chk_variant (chk_variant) {}
bool matches_call_types_p (const call_details &cd) const final override
{
return (cd.num_args () == m_num_args
&& cd.arg_is_pointer_p (0)
&& cd.arg_is_pointer_p (1));
}
enum built_in_function builtin_code () const final override
{
return m_chk_variant ? BUILT_IN_STRCPY_CHK : BUILT_IN_STRCPY;
}
void impl_call_pre (const call_details &cd) const final override;
private:
unsigned int m_num_args;
const bool m_chk_variant;
};
void
kf_strcpy::impl_call_pre (const call_details &cd) const
{
region_model *model = cd.get_model ();
region_model_manager *mgr = cd.get_manager ();
region_model_context *ctxt = cd.get_ctxt ();
const svalue *dest_sval = cd.get_arg_svalue (0);
const region *dest_reg = model->deref_rvalue (dest_sval, cd.get_arg_tree (0),
cd.get_ctxt ());
const svalue *src_sval = cd.get_arg_svalue (1);
const region *src_reg = model->deref_rvalue (src_sval, cd.get_arg_tree (1),
cd.get_ctxt ());
const svalue *src_contents_sval = model->get_store_value (src_reg,
cd.get_ctxt ());
ctxt);
/* strcpy returns the initial param. */
cd.maybe_set_lhs (dest_sval);
/* Try to get the string size if SRC_REG is a string_region. */
const svalue *copied_bytes_sval = model->get_string_size (src_reg);
/* Otherwise, check if the contents of SRC_REG is a string. */
if (copied_bytes_sval->get_kind () == SK_UNKNOWN)
copied_bytes_sval = model->get_string_size (src_contents_sval);
const region *sized_dest_reg
= mgr->get_sized_region (dest_reg, NULL_TREE, copied_bytes_sval);
model->set_value (sized_dest_reg, src_contents_sval, cd.get_ctxt ());
const svalue *bytes_to_copy;
if (const svalue *num_bytes_read_sval
= cd.check_for_null_terminated_string_arg (1, true, &bytes_to_copy))
{
cd.complain_about_overlap (0, 1, num_bytes_read_sval);
model->write_bytes (dest_reg, num_bytes_read_sval, bytes_to_copy, ctxt);
}
else
{
if (cd.get_ctxt ())
cd.get_ctxt ()->terminate_path ();
}
}
/* Handler for "strdup" and "__builtin_strdup". */
class kf_strdup : public known_function
class kf_strdup : public builtin_known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
{
return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
}
enum built_in_function builtin_code () const final override
{
return BUILT_IN_STRDUP;
}
void impl_call_pre (const call_details &cd) const final override
{
region_model *model = cd.get_model ();
region_model_context *ctxt = cd.get_ctxt ();
region_model_manager *mgr = cd.get_manager ();
/* Ideally we'd get the size here, and simulate copying the bytes. */
const region *new_reg
= model->get_or_create_region_for_heap_alloc (NULL, cd.get_ctxt ());
model->mark_region_as_unknown (new_reg, NULL);
if (cd.get_lhs_type ())
const svalue *bytes_to_copy;
if (const svalue *num_bytes_read_sval
= cd.check_for_null_terminated_string_arg (0, true, &bytes_to_copy))
{
const svalue *ptr_sval
= mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
cd.maybe_set_lhs (ptr_sval);
const region *new_reg
= model->get_or_create_region_for_heap_alloc (num_bytes_read_sval,
ctxt);
model->write_bytes (new_reg, num_bytes_read_sval, bytes_to_copy, ctxt);
if (cd.get_lhs_type ())
{
const svalue *ptr_sval
= mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
cd.maybe_set_lhs (ptr_sval);
}
}
else
{
if (ctxt)
ctxt->terminate_path ();
}
}
};
/* Handle the on_call_pre part of "strlen". */
/* Handler for "strlen" and for "__analyzer_get_strlen". */
class kf_strlen : public known_function
class kf_strlen : public builtin_known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
{
return (cd.num_args () == 1 && cd.arg_is_pointer_p (0));
}
void impl_call_pre (const call_details &cd) const final override;
};
enum built_in_function builtin_code () const final override
{
return BUILT_IN_STRLEN;
}
void
kf_strlen::impl_call_pre (const call_details &cd) const
{
region_model_context *ctxt = cd.get_ctxt ();
region_model *model = cd.get_model ();
region_model_manager *mgr = cd.get_manager ();
const svalue *arg_sval = cd.get_arg_svalue (0);
const region *buf_reg
= model->deref_rvalue (arg_sval, cd.get_arg_tree (0), ctxt);
if (const string_region *str_reg
= buf_reg->dyn_cast_string_region ())
{
tree str_cst = str_reg->get_string_cst ();
/* TREE_STRING_LENGTH is sizeof, not strlen. */
int sizeof_cst = TREE_STRING_LENGTH (str_cst);
int strlen_cst = sizeof_cst - 1;
if (cd.get_lhs_type ())
void impl_call_pre (const call_details &cd) const final override
{
if (const svalue *strlen_sval
= cd.check_for_null_terminated_string_arg (0, false, nullptr))
if (strlen_sval->get_kind () != SK_UNKNOWN)
{
tree t_cst = build_int_cst (cd.get_lhs_type (), strlen_cst);
const svalue *result_sval
= mgr->get_or_create_constant_svalue (t_cst);
cd.maybe_set_lhs (result_sval);
cd.maybe_set_lhs (strlen_sval);
return;
}
}
/* Otherwise a conjured value. */
/* Use a conjured svalue. */
cd.set_any_lhs_with_defaults ();
}
};
/* Factory function, so that kf-analyzer.cc can use this class. */
std::unique_ptr<known_function>
make_kf_strlen ()
{
return make_unique<kf_strlen> ();
}
/* Handler for "strndup" and "__builtin_strndup". */
class kf_strndup : public known_function
class kf_strndup : public builtin_known_function
{
public:
bool matches_call_types_p (const call_details &cd) const final override
{
return (cd.num_args () == 2 && cd.arg_is_pointer_p (0));
}
enum built_in_function builtin_code () const final override
{
return BUILT_IN_STRNDUP;
}
void impl_call_pre (const call_details &cd) const final override
{
region_model *model = cd.get_model ();
@ -1358,45 +1563,78 @@ register_known_functions (known_function_manager &kfm)
kfm.add (IFN_UBSAN_BOUNDS, make_unique<kf_ubsan_bounds> ());
}
/* Built-ins the analyzer has known_functions for. */
/* GCC built-ins that do not correspond to a function
in the standard library. */
{
kfm.add (BUILT_IN_ALLOCA, make_unique<kf_alloca> ());
kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, make_unique<kf_alloca> ());
kfm.add (BUILT_IN_CALLOC, make_unique<kf_calloc> ());
kfm.add (BUILT_IN_EXPECT, make_unique<kf_expect> ());
kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, make_unique<kf_expect> ());
kfm.add (BUILT_IN_FREE, make_unique<kf_free> ());
kfm.add (BUILT_IN_MALLOC, make_unique<kf_malloc> ());
kfm.add (BUILT_IN_MEMCPY, make_unique<kf_memcpy_memmove> ());
kfm.add (BUILT_IN_MEMCPY_CHK, make_unique<kf_memcpy_memmove> ());
kfm.add (BUILT_IN_MEMMOVE, make_unique<kf_memcpy_memmove> ());
kfm.add (BUILT_IN_MEMMOVE_CHK, make_unique<kf_memcpy_memmove> ());
kfm.add (BUILT_IN_MEMSET, make_unique<kf_memset> ());
kfm.add (BUILT_IN_MEMSET_CHK, make_unique<kf_memset> ());
kfm.add (BUILT_IN_REALLOC, make_unique<kf_realloc> ());
kfm.add (BUILT_IN_SPRINTF, make_unique<kf_sprintf> ());
kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, make_unique<kf_alloca> ());
kfm.add (BUILT_IN_STACK_RESTORE, make_unique<kf_stack_restore> ());
kfm.add (BUILT_IN_STACK_SAVE, make_unique<kf_stack_save> ());
kfm.add (BUILT_IN_STRCHR, make_unique<kf_strchr> ());
kfm.add (BUILT_IN_STRCPY, make_unique<kf_strcpy> (2));
kfm.add (BUILT_IN_STRCPY_CHK, make_unique<kf_strcpy> (3));
kfm.add (BUILT_IN_STRDUP, make_unique<kf_strdup> ());
kfm.add (BUILT_IN_STRNDUP, make_unique<kf_strndup> ());
kfm.add (BUILT_IN_STRLEN, make_unique<kf_strlen> ());
register_atomic_builtins (kfm);
register_varargs_builtins (kfm);
}
/* Known builtins and C standard library functions. */
/* Known builtins and C standard library functions
the analyzer has known functions for. */
{
kfm.add ("memset", make_unique<kf_memset> ());
kfm.add ("alloca", make_unique<kf_alloca> ());
kfm.add ("__builtin_alloca", make_unique<kf_alloca> ());
kfm.add ("calloc", make_unique<kf_calloc> ());
kfm.add ("__builtin_calloc", make_unique<kf_calloc> ());
kfm.add ("free", make_unique<kf_free> ());
kfm.add ("__builtin_free", make_unique<kf_free> ());
kfm.add ("malloc", make_unique<kf_malloc> ());
kfm.add ("__builtin_malloc", make_unique<kf_malloc> ());
kfm.add ("memcpy",
make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
kfm.add ("__builtin_memcpy",
make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
kfm.add ("__memcpy_chk", make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMCPY_CHK));
kfm.add ("__builtin___memcpy_chk", make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMCPY_CHK));
kfm.add ("memmove",
make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
kfm.add ("__builtin_memmove",
make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
kfm.add ("__memmove_chk", make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMMOVE_CHK));
kfm.add ("__builtin___memmove_chk", make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMMOVE_CHK));
kfm.add ("memset", make_unique<kf_memset> (false));
kfm.add ("__builtin_memset", make_unique<kf_memset> (false));
kfm.add ("__memset_chk", make_unique<kf_memset> (true));
kfm.add ("__builtin___memset_chk", make_unique<kf_memset> (true));
kfm.add ("realloc", make_unique<kf_realloc> ());
kfm.add ("__builtin_realloc", make_unique<kf_realloc> ());
kfm.add ("sprintf", make_unique<kf_sprintf> ());
kfm.add ("__builtin_sprintf", make_unique<kf_sprintf> ());
kfm.add ("strchr", make_unique<kf_strchr> ());
kfm.add ("__builtin_strchr", make_unique<kf_strchr> ());
kfm.add ("strcpy", make_unique<kf_strcpy> (2, false));
kfm.add ("__builtin_strcpy", make_unique<kf_strcpy> (2, false));
kfm.add ("__strcpy_chk", make_unique<kf_strcpy> (3, true));
kfm.add ("__builtin___strcpy_chk", make_unique<kf_strcpy> (3, true));
kfm.add ("strcat", make_unique<kf_strcat> (2, false));
kfm.add ("__builtin_strcat", make_unique<kf_strcat> (2, false));
kfm.add ("__strcat_chk", make_unique<kf_strcat> (3, true));
kfm.add ("__builtin___strcat_chk", make_unique<kf_strcat> (3, true));
kfm.add ("strdup", make_unique<kf_strdup> ());
kfm.add ("__builtin_strdup", make_unique<kf_strdup> ());
kfm.add ("strndup", make_unique<kf_strndup> ());
kfm.add ("__builtin_strndup", make_unique<kf_strndup> ());
kfm.add ("strlen", make_unique<kf_strlen> ());
kfm.add ("__builtin_strlen", make_unique<kf_strlen> ());
register_atomic_builtins (kfm);
register_varargs_builtins (kfm);
}
/* Known POSIX functions, and some non-standard extensions. */
{
kfm.add ("fopen", make_unique<kf_fopen> ());
kfm.add ("putenv", make_unique<kf_putenv> ());
register_known_fd_functions (kfm);
@ -1416,7 +1654,7 @@ register_known_functions (known_function_manager &kfm)
like this:
extern int *___errno(void) __attribute__((__const__));
#define errno (*(___errno()))
and OS X like this:
and macOS like this:
extern int * __error(void);
#define errno (*__error())
and similarly __errno for newlib.

View File

@ -137,6 +137,13 @@ known_function_manager::get_normal_builtin (enum built_in_function name) const
return m_combined_fns_arr[name];
}
const known_function *
known_function_manager::
get_normal_builtin (const builtin_known_function *builtin_kf) const
{
return get_normal_builtin (builtin_kf->builtin_code ());
}
/* Get any known_function matching IDENTIFIER, without type-checking.
Return NULL if there isn't one. */

View File

@ -54,6 +54,8 @@ private:
DISABLE_COPY_AND_ASSIGN (known_function_manager);
const known_function *get_normal_builtin (enum built_in_function name) const;
const known_function *
get_normal_builtin (const builtin_known_function *builtin_kf) const;
const known_function *get_by_identifier (tree identifier) const;
/* Map from identifier to known_function instance.
@ -64,6 +66,8 @@ private:
known_function *m_combined_fns_arr[CFN_LAST];
};
extern std::unique_ptr<known_function> make_kf_strlen ();
} // namespace ana
#endif /* GCC_ANALYZER_KNOWN_FUNCTION_MANAGER_H */

324
gcc/analyzer/ranges.cc Normal file
View File

@ -0,0 +1,324 @@
/* Symbolic offsets and ranges.
Copyright (C) 2023 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC 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, or (at your option)
any later version.
GCC 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/>. */
#include "config.h"
#define INCLUDE_MEMORY
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "diagnostic-core.h"
#include "gimple-pretty-print.h"
#include "function.h"
#include "basic-block.h"
#include "gimple.h"
#include "gimple-iterator.h"
#include "diagnostic-core.h"
#include "graphviz.h"
#include "options.h"
#include "cgraph.h"
#include "tree-dfa.h"
#include "stringpool.h"
#include "convert.h"
#include "target.h"
#include "fold-const.h"
#include "tree-pretty-print.h"
#include "bitmap.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
#include "options.h"
#include "analyzer/supergraph.h"
#include "sbitmap.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
#include "analyzer/analyzer-selftests.h"
#include "analyzer/ranges.h"
#if ENABLE_ANALYZER
namespace ana {
/* class symbolic_byte_offset. */
symbolic_byte_offset::symbolic_byte_offset (int i, region_model_manager &mgr)
: m_num_bytes_sval (mgr.get_or_create_int_cst (size_type_node, i))
{
}
symbolic_byte_offset::symbolic_byte_offset (const svalue *num_bytes_sval)
: m_num_bytes_sval (num_bytes_sval)
{
}
symbolic_byte_offset::symbolic_byte_offset (region_offset offset,
region_model_manager &mgr)
{
if (offset.concrete_p ())
{
bit_offset_t num_bits = offset.get_bit_offset ();
gcc_assert (num_bits % BITS_PER_UNIT == 0);
byte_offset_t num_bytes = num_bits / BITS_PER_UNIT;
m_num_bytes_sval = mgr.get_or_create_int_cst (size_type_node, num_bytes);
}
else
m_num_bytes_sval = offset.get_symbolic_byte_offset ();
}
void
symbolic_byte_offset::dump_to_pp (pretty_printer *pp, bool simple) const
{
pp_string (pp, "byte ");
m_num_bytes_sval->dump_to_pp (pp, simple);
}
void
symbolic_byte_offset::dump (bool simple) const
{
pretty_printer pp;
pp_format_decoder (&pp) = default_tree_printer;
pp_show_color (&pp) = pp_show_color (global_dc->printer);
pp.buffer->stream = stderr;
dump_to_pp (&pp, simple);
pp_newline (&pp);
pp_flush (&pp);
}
tree
symbolic_byte_offset::maybe_get_constant () const
{
return m_num_bytes_sval->maybe_get_constant ();
}
/* class symbolic_byte_range. */
symbolic_byte_range::symbolic_byte_range (region_offset start,
const svalue *num_bytes,
region_model_manager &mgr)
: m_start (start, mgr),
m_size (num_bytes)
{
}
void
symbolic_byte_range::dump_to_pp (pretty_printer *pp,
bool simple,
region_model_manager &mgr) const
{
if (empty_p ())
{
pp_string (pp, "empty");
return;
}
if (tree size_cst = m_size.maybe_get_constant ())
if (integer_onep (size_cst))
{
pp_string (pp, "byte ");
m_start.get_svalue ()->dump_to_pp (pp, simple);
return;
}
pp_string (pp, "bytes ");
m_start.get_svalue ()->dump_to_pp (pp, simple);
pp_string (pp, " to ");
get_last_byte_offset (mgr).get_svalue ()->dump_to_pp (pp, simple);
}
void
symbolic_byte_range::dump (bool simple, region_model_manager &mgr) const
{
pretty_printer pp;
pp_format_decoder (&pp) = default_tree_printer;
pp_show_color (&pp) = pp_show_color (global_dc->printer);
pp.buffer->stream = stderr;
dump_to_pp (&pp, simple, mgr);
pp_newline (&pp);
pp_flush (&pp);
}
bool
symbolic_byte_range::empty_p () const
{
tree cst = m_size.maybe_get_constant ();
if (!cst)
return false;
return zerop (cst);
}
symbolic_byte_offset
symbolic_byte_range::get_last_byte_offset (region_model_manager &mgr) const
{
gcc_assert (!empty_p ());
const symbolic_byte_offset one (1, mgr);
return symbolic_byte_offset
(mgr.get_or_create_binop (size_type_node,
MINUS_EXPR,
get_next_byte_offset (mgr).get_svalue (),
one.get_svalue ()));
}
symbolic_byte_offset
symbolic_byte_range::get_next_byte_offset (region_model_manager &mgr) const
{
return symbolic_byte_offset (mgr.get_or_create_binop (size_type_node,
PLUS_EXPR,
m_start.get_svalue (),
m_size.get_svalue ()));
}
/* Attempt to determine if THIS range intersects OTHER,
using constraints from MODEL. */
tristate
symbolic_byte_range::intersection (const symbolic_byte_range &other,
const region_model &model) const
{
/* For brevity, consider THIS to be "range A", and OTHER to be "range B". */
region_model_manager *mgr = model.get_manager ();
const svalue *first_sval_a = m_start.get_svalue ();
const svalue *first_sval_b = other.m_start.get_svalue ();
const svalue *last_sval_a = get_last_byte_offset (*mgr).get_svalue ();
const svalue *last_sval_b = other.get_last_byte_offset (*mgr).get_svalue ();
if (m_size.get_svalue ()->get_kind () == SK_UNKNOWN
|| other.m_size.get_svalue ()->get_kind () == SK_UNKNOWN)
{
if (first_sval_a == first_sval_b)
return tristate::TS_TRUE;
else
return tristate::TS_UNKNOWN;
}
if (first_sval_a == first_sval_b)
return tristate::TS_TRUE;
/* Is B fully before A? */
tristate b_fully_before_a = model.eval_condition (last_sval_b,
LT_EXPR,
first_sval_a);
/* Is B fully after A? */
tristate b_fully_after_a = model.eval_condition (first_sval_b,
GT_EXPR,
last_sval_a);
if (b_fully_before_a.is_true ()
|| b_fully_after_a.is_true ())
return tristate::TS_FALSE;
if (b_fully_before_a.is_unknown ()
|| b_fully_after_a.is_unknown ())
return tristate::TS_UNKNOWN;
return tristate::TS_TRUE;
}
#if CHECKING_P
namespace selftest {
static void test_intersects (void)
{
region_model_manager mgr;
region_model m (&mgr);
/* Test various concrete ranges. */
symbolic_byte_offset zero (0, mgr);
symbolic_byte_offset one (1, mgr);
symbolic_byte_offset five (5, mgr);
symbolic_byte_offset nine (9, mgr);
symbolic_byte_offset ten (10, mgr);
symbolic_byte_range r0_9 (zero, ten);
symbolic_byte_range r0 (zero, one);
symbolic_byte_range r5_9 (five, five);
symbolic_byte_range r9 (nine, one);
symbolic_byte_range r10 (ten, one);
symbolic_byte_range r10_19 (ten, ten);
ASSERT_EQ (r0_9.get_start_byte_offset (), zero);
ASSERT_EQ (r0_9.get_size_in_bytes (), ten);
ASSERT_EQ (r0_9.get_next_byte_offset (mgr), ten);
ASSERT_EQ (r0_9.get_last_byte_offset (mgr), nine);
ASSERT_EQ (r0_9.intersection (r0, m), tristate::TS_TRUE);
ASSERT_EQ (r0.intersection (r0_9, m), tristate::TS_TRUE);
ASSERT_EQ (r0_9.intersection (r9, m), tristate::TS_TRUE);
ASSERT_EQ (r9.intersection (r0_9, m), tristate::TS_TRUE);
ASSERT_EQ (r0_9.intersection (r10, m), tristate::TS_FALSE);
ASSERT_EQ (r10.intersection (r0_9, m), tristate::TS_FALSE);
ASSERT_EQ (r5_9.intersection (r0, m), tristate::TS_FALSE);
ASSERT_EQ (r0.intersection (r5_9, m), tristate::TS_FALSE);
ASSERT_EQ (r9.intersection (r5_9, m), tristate::TS_TRUE);
ASSERT_EQ (r10.intersection (r5_9, m), tristate::TS_FALSE);
/* Test various symbolic ranges. */
tree x = build_global_decl ("x", size_type_node);
const svalue *x_init_sval = m.get_rvalue (x, nullptr);
tree y = build_global_decl ("y", size_type_node);
const svalue *y_init_sval = m.get_rvalue (y, nullptr);
symbolic_byte_range r0_x_minus_1 (zero, x_init_sval);
symbolic_byte_range rx (x_init_sval, one);
symbolic_byte_range r0_y_minus_1 (zero, y_init_sval);
symbolic_byte_range ry (y_init_sval, one);
symbolic_byte_range rx_x_plus_y_minus_1 (x_init_sval, y_init_sval);
ASSERT_EQ (rx_x_plus_y_minus_1.get_start_byte_offset (), x_init_sval);
ASSERT_EQ (rx_x_plus_y_minus_1.get_size_in_bytes (), y_init_sval);
ASSERT_EQ
(rx_x_plus_y_minus_1.get_next_byte_offset (mgr).get_svalue ()->get_kind (),
SK_BINOP);
ASSERT_EQ
(rx_x_plus_y_minus_1.get_last_byte_offset (mgr).get_svalue ()->get_kind (),
SK_BINOP);
ASSERT_EQ (rx.intersection (ry, m), tristate::TS_UNKNOWN);
ASSERT_EQ (r0_x_minus_1.intersection (r0, m), tristate::TS_TRUE);
#if 0
ASSERT_EQ (r0_x_minus_1.intersection (rx, m), tristate::TS_FALSE);
/* Fails (with UNKNOWN): b_fully_after_a is UNKNOWN, when it could
be TRUE: last of A is (x - 1), but it's not necessarily true that
X > (x - 1), for the case where x is (unsigned)0. */
#endif
ASSERT_EQ (r0_x_minus_1.intersection (r0_y_minus_1, m), tristate::TS_TRUE);
// TODO: etc
}
/* Run all of the selftests within this file. */
void
analyzer_ranges_cc_tests ()
{
test_intersects ();
}
} // namespace selftest
#endif /* CHECKING_P */
} // namespace ana
#endif /* #if ENABLE_ANALYZER */

96
gcc/analyzer/ranges.h Normal file
View File

@ -0,0 +1,96 @@
/* Symbolic offsets and ranges.
Copyright (C) 2023 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC 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, or (at your option)
any later version.
GCC 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/>. */
#ifndef GCC_ANALYZER_RANGES_H
#define GCC_ANALYZER_RANGES_H
namespace ana {
/* Wrapper around an svalue for a value measured in bytes. */
class symbolic_byte_offset
{
public:
explicit symbolic_byte_offset (int i, region_model_manager &mgr);
symbolic_byte_offset (const svalue *num_bytes_sval);
explicit symbolic_byte_offset (region_offset offset,
region_model_manager &mgr);
const svalue *get_svalue () const { return m_num_bytes_sval; }
tree maybe_get_constant () const;
void dump_to_pp (pretty_printer *pp, bool) const;
void dump (bool) const;
bool operator== (const symbolic_byte_offset &other) const
{
return m_num_bytes_sval == other.m_num_bytes_sval;
}
private:
const svalue *m_num_bytes_sval;
};
/* A range of byte offsets, where both the start and size of the
range can be symbolic. */
class symbolic_byte_range
{
public:
symbolic_byte_range (symbolic_byte_offset start,
symbolic_byte_offset size)
: m_start (start),
m_size (size)
{
}
symbolic_byte_range (region_offset start,
const svalue *num_bytes,
region_model_manager &mgr);
void dump_to_pp (pretty_printer *pp,
bool simple,
region_model_manager &mgr) const;
void dump (bool, region_model_manager &mgr) const;
bool empty_p () const;
symbolic_byte_offset get_start_byte_offset () const
{
return m_start;
}
symbolic_byte_offset get_last_byte_offset (region_model_manager &mgr) const;
symbolic_byte_offset get_size_in_bytes () const
{
return m_size;
}
symbolic_byte_offset get_next_byte_offset (region_model_manager &mgr) const;
tristate intersection (const symbolic_byte_range &other,
const region_model &model) const;
private:
symbolic_byte_offset m_start;
symbolic_byte_offset m_size;
};
} // namespace ana
#endif /* GCC_ANALYZER_RANGES_H */

View File

@ -310,6 +310,25 @@ region_model_manager::get_or_create_initial_value (const region *reg,
get_or_create_initial_value (original_reg));
}
/* Simplify:
INIT_VAL(ELEMENT_REG(STRING_REG), CONSTANT_SVAL)
to:
CONSTANT_SVAL(STRING[N]). */
if (const element_region *element_reg = reg->dyn_cast_element_region ())
if (tree cst_idx = element_reg->get_index ()->maybe_get_constant ())
if (const string_region *string_reg
= element_reg->get_parent_region ()->dyn_cast_string_region ())
if (tree_fits_shwi_p (cst_idx))
{
HOST_WIDE_INT idx = tree_to_shwi (cst_idx);
tree string_cst = string_reg->get_string_cst ();
if (idx >= 0 && idx <= TREE_STRING_LENGTH (string_cst))
{
int ch = TREE_STRING_POINTER (string_cst)[idx];
return get_or_create_int_cst (reg->get_type (), ch);
}
}
/* INIT_VAL (*UNKNOWN_PTR) -> UNKNOWN_VAL. */
if (reg->symbolic_for_unknown_ptr_p ())
return get_or_create_unknown_svalue (reg->get_type ());

View File

@ -184,27 +184,6 @@ reachable_regions::handle_sval (const svalue *sval)
}
add (pointee, ptr_is_mutable);
}
else if (sval->get_type ()
&& TREE_CODE (sval->get_type ()) == POINTER_TYPE
&& sval->get_kind () == SK_CONJURED)
{
/* Also add symbolic regions for pointers, but only for conjured svalues
for the LHS of a stmt. Doing it for more leads to state explosions
on chains of calls to external functions, due to each conjured svalue
potentially being modified at each successive call, recursively. */
const conjured_svalue *conjured_sval = (const conjured_svalue *)sval;
if (conjured_sval->lhs_value_p ())
{
const region *pointee
= m_model->get_manager ()->get_symbolic_region (sval);
/* Use const-ness of pointer type to affect mutability. */
bool ptr_is_mutable = true;
if (TYPE_READONLY (TREE_TYPE (sval->get_type ())))
ptr_is_mutable = false;
add (pointee, ptr_is_mutable);
}
}
/* Treat all svalues within a compound_svalue as reachable. */
if (const compound_svalue *compound_sval
= sval->dyn_cast_compound_svalue ())

File diff suppressed because it is too large Load Diff

View File

@ -236,6 +236,11 @@ public:
struct append_regions_cb_data;
typedef void (*pop_frame_callback) (const region_model *model,
const region_model *prev_model,
const svalue *retval,
region_model_context *ctxt);
/* A region_model encapsulates a representation of the state of memory, with
a tree of regions, along with their associated values.
The representation is graph-like because values can be pointers to
@ -367,6 +372,19 @@ class region_model
void purge_region (const region *reg);
void fill_region (const region *reg, const svalue *sval);
void zero_fill_region (const region *reg);
void write_bytes (const region *dest_reg,
const svalue *num_bytes_sval,
const svalue *sval,
region_model_context *ctxt);
const svalue *read_bytes (const region *src_reg,
tree src_ptr_expr,
const svalue *num_bytes_sval,
region_model_context *ctxt) const;
void copy_bytes (const region *dest_reg,
const region *src_reg,
tree src_ptr_expr,
const svalue *num_bytes_sval,
region_model_context *ctxt);
void mark_region_as_unknown (const region *reg, uncertainty_t *uncertainty);
tristate eval_condition (const svalue *lhs,
@ -387,9 +405,12 @@ class region_model
region_model_context *ctxt,
rejected_constraint **out);
const region *
get_or_create_region_for_heap_alloc (const svalue *size_in_bytes,
region_model_context *ctxt);
const region *
get_or_create_region_for_heap_alloc (const svalue *size_in_bytes,
region_model_context *ctxt,
bool update_state_machine = false,
const call_details *cd = nullptr);
const region *create_region_for_alloca (const svalue *size_in_bytes,
region_model_context *ctxt);
void get_referenced_base_regions (auto_bitmap &out_ids) const;
@ -448,6 +469,13 @@ class region_model
const svalue *get_store_value (const region *reg,
region_model_context *ctxt) const;
const svalue *get_store_bytes (const region *base_reg,
const byte_range &bytes,
region_model_context *ctxt) const;
const svalue *scan_for_null_terminator (const region *reg,
tree expr,
const svalue **out_sval,
region_model_context *ctxt) const;
bool region_exists_p (const region *reg) const;
@ -455,9 +483,6 @@ class region_model
const svalue *get_capacity (const region *reg) const;
const svalue *get_string_size (const svalue *sval) const;
const svalue *get_string_size (const region *reg) const;
bool replay_call_summary (call_summary_replay &r,
const region_model &summary);
@ -476,6 +501,11 @@ class region_model
const svalue *old_ptr_sval,
const svalue *new_ptr_sval);
/* Implemented in sm-malloc.cc. */
void
transition_ptr_sval_non_null (region_model_context *ctxt,
const svalue *new_ptr_sval);
/* Implemented in sm-taint.cc. */
void mark_as_tainted (const svalue *sval,
region_model_context *ctxt);
@ -494,6 +524,35 @@ class region_model
const svalue *sval_hint,
region_model_context *ctxt) const;
void
check_for_null_terminated_string_arg (const call_details &cd,
unsigned idx);
const svalue *
check_for_null_terminated_string_arg (const call_details &cd,
unsigned idx,
bool include_terminator,
const svalue **out_sval);
const builtin_known_function *
get_builtin_kf (const gcall *call,
region_model_context *ctxt = NULL) const;
static void
register_pop_frame_callback (const pop_frame_callback &callback)
{
pop_frame_callbacks.safe_push (callback);
}
static void
notify_on_pop_frame (const region_model *model,
const region_model *prev_model,
const svalue *retval,
region_model_context *ctxt)
{
for (auto &callback : pop_frame_callbacks)
callback (model, prev_model, retval, ctxt);
}
private:
const region *get_lvalue_1 (path_var pv, region_model_context *ctxt) const;
const svalue *get_rvalue_1 (path_var pv, region_model_context *ctxt) const;
@ -577,10 +636,13 @@ private:
region_model_context *ctxt) const;
void check_call_args (const call_details &cd) const;
void check_call_format_attr (const call_details &cd,
tree format_attr) const;
void check_external_function_for_access_attr (const gcall *call,
tree callee_fndecl,
region_model_context *ctxt) const;
static auto_vec<pop_frame_callback> pop_frame_callbacks;
/* Storing this here to avoid passing it around everywhere. */
region_model_manager *const m_mgr;
@ -609,13 +671,19 @@ class region_model_context
{
public:
/* Hook for clients to store pending diagnostics.
Return true if the diagnostic was stored, or false if it was deleted. */
virtual bool warn (std::unique_ptr<pending_diagnostic> d) = 0;
Return true if the diagnostic was stored, or false if it was deleted.
Optionally provide a custom stmt_finder. */
virtual bool warn (std::unique_ptr<pending_diagnostic> d,
const stmt_finder *custom_finder = NULL) = 0;
/* Hook for clients to add a note to the last previously stored
pending diagnostic. */
virtual void add_note (std::unique_ptr<pending_note> pn) = 0;
/* Hook for clients to add an event to the last previously stored
pending diagnostic. */
virtual void add_event (std::unique_ptr<checker_event> event) = 0;
/* Hook for clients to be notified when an SVAL that was reachable
in a previous state is no longer live, so that clients can emit warnings
about leaks. */
@ -713,6 +781,8 @@ class region_model_context
/* Get the current statement, if any. */
virtual const gimple *get_stmt () const = 0;
virtual const exploded_graph *get_eg () const = 0;
};
/* A "do nothing" subclass of region_model_context. */
@ -720,8 +790,10 @@ class region_model_context
class noop_region_model_context : public region_model_context
{
public:
bool warn (std::unique_ptr<pending_diagnostic>) override { return false; }
bool warn (std::unique_ptr<pending_diagnostic> d,
const stmt_finder *custom_finder) override { return false; }
void add_note (std::unique_ptr<pending_note>) override;
void add_event (std::unique_ptr<checker_event>) override;
void on_svalue_leak (const svalue *) override {}
void on_liveness_change (const svalue_set &,
const region_model *) override {}
@ -767,6 +839,7 @@ public:
}
const gimple *get_stmt () const override { return NULL; }
const exploded_graph *get_eg () const override { return NULL; }
};
/* A subclass of region_model_context for determining if operations fail
@ -795,94 +868,121 @@ private:
class region_model_context_decorator : public region_model_context
{
public:
bool warn (std::unique_ptr<pending_diagnostic> d) override
bool warn (std::unique_ptr<pending_diagnostic> d,
const stmt_finder *custom_finder)
{
return m_inner->warn (std::move (d));
if (m_inner)
return m_inner->warn (std::move (d), custom_finder);
else
return false;
}
void add_note (std::unique_ptr<pending_note> pn) override
{
m_inner->add_note (std::move (pn));
if (m_inner)
m_inner->add_note (std::move (pn));
}
void add_event (std::unique_ptr<checker_event> event) override;
void on_svalue_leak (const svalue *sval) override
{
m_inner->on_svalue_leak (sval);
if (m_inner)
m_inner->on_svalue_leak (sval);
}
void on_liveness_change (const svalue_set &live_svalues,
const region_model *model) override
{
m_inner->on_liveness_change (live_svalues, model);
if (m_inner)
m_inner->on_liveness_change (live_svalues, model);
}
logger *get_logger () override
{
return m_inner->get_logger ();
if (m_inner)
return m_inner->get_logger ();
else
return nullptr;
}
void on_condition (const svalue *lhs,
enum tree_code op,
const svalue *rhs) override
{
m_inner->on_condition (lhs, op, rhs);
if (m_inner)
m_inner->on_condition (lhs, op, rhs);
}
void on_bounded_ranges (const svalue &sval,
const bounded_ranges &ranges) override
{
m_inner->on_bounded_ranges (sval, ranges);
if (m_inner)
m_inner->on_bounded_ranges (sval, ranges);
}
void on_pop_frame (const frame_region *frame_reg) override
{
m_inner->on_pop_frame (frame_reg);
if (m_inner)
m_inner->on_pop_frame (frame_reg);
}
void on_unknown_change (const svalue *sval, bool is_mutable) override
{
m_inner->on_unknown_change (sval, is_mutable);
if (m_inner)
m_inner->on_unknown_change (sval, is_mutable);
}
void on_phi (const gphi *phi, tree rhs) override
{
m_inner->on_phi (phi, rhs);
if (m_inner)
m_inner->on_phi (phi, rhs);
}
void on_unexpected_tree_code (tree t,
const dump_location_t &loc) override
{
m_inner->on_unexpected_tree_code (t, loc);
if (m_inner)
m_inner->on_unexpected_tree_code (t, loc);
}
void on_escaped_function (tree fndecl) override
{
m_inner->on_escaped_function (fndecl);
if (m_inner)
m_inner->on_escaped_function (fndecl);
}
uncertainty_t *get_uncertainty () override
{
return m_inner->get_uncertainty ();
if (m_inner)
return m_inner->get_uncertainty ();
else
return nullptr;
}
void purge_state_involving (const svalue *sval) override
{
m_inner->purge_state_involving (sval);
if (m_inner)
m_inner->purge_state_involving (sval);
}
void bifurcate (std::unique_ptr<custom_edge_info> info) override
{
m_inner->bifurcate (std::move (info));
if (m_inner)
m_inner->bifurcate (std::move (info));
}
void terminate_path () override
{
m_inner->terminate_path ();
if (m_inner)
m_inner->terminate_path ();
}
const extrinsic_state *get_ext_state () const override
{
return m_inner->get_ext_state ();
if (m_inner)
return m_inner->get_ext_state ();
else
return nullptr;
}
bool get_state_map_by_name (const char *name,
@ -892,47 +992,61 @@ class region_model_context_decorator : public region_model_context
std::unique_ptr<sm_context> *out_sm_context)
override
{
return m_inner->get_state_map_by_name (name, out_smap, out_sm, out_sm_idx,
out_sm_context);
if (m_inner)
return m_inner->get_state_map_by_name (name, out_smap, out_sm, out_sm_idx,
out_sm_context);
else
return false;
}
const gimple *get_stmt () const override
{
return m_inner->get_stmt ();
if (m_inner)
return m_inner->get_stmt ();
else
return nullptr;
}
const exploded_graph *get_eg () const override
{
if (m_inner)
return m_inner->get_eg ();
else
return nullptr;
}
protected:
region_model_context_decorator (region_model_context *inner)
: m_inner (inner)
{
gcc_assert (m_inner);
}
region_model_context *m_inner;
};
/* Subclass of region_model_context_decorator that adds a note
when saving diagnostics. */
/* Subclass of region_model_context_decorator with a hook for adding
notes/events when saving diagnostics. */
class note_adding_context : public region_model_context_decorator
class annotating_context : public region_model_context_decorator
{
public:
bool warn (std::unique_ptr<pending_diagnostic> d) override
bool warn (std::unique_ptr<pending_diagnostic> d,
const stmt_finder *custom_finder) override
{
if (m_inner->warn (std::move (d)))
{
add_note (make_note ());
return true;
}
else
return false;
if (m_inner)
if (m_inner->warn (std::move (d), custom_finder))
{
add_annotations ();
return true;
}
return false;
}
/* Hook to make the new note. */
virtual std::unique_ptr<pending_note> make_note () = 0;
/* Hook to add new event(s)/note(s) */
virtual void add_annotations () = 0;
protected:
note_adding_context (region_model_context *inner)
annotating_context (region_model_context *inner)
: region_model_context_decorator (inner)
{
}
@ -1082,7 +1196,8 @@ using namespace ::selftest;
class test_region_model_context : public noop_region_model_context
{
public:
bool warn (std::unique_ptr<pending_diagnostic> d) final override
bool warn (std::unique_ptr<pending_diagnostic> d,
const stmt_finder *custom_finder) final override
{
m_diagnostics.safe_push (d.release ());
return true;

View File

@ -1294,8 +1294,19 @@ fd_state_machine::check_for_fd_attrs (
const gcall *call, const tree callee_fndecl, const char *attr_name,
access_directions fd_attr_access_dir) const
{
/* Handle interesting fd attributes of the callee_fndecl,
or prioritize those of the builtin that callee_fndecl is
expected to be.
Might want this to be controlled by a flag. */
tree fndecl = callee_fndecl;
/* If call is recognized as a builtin known_function,
use that builtin's function_decl. */
if (const region_model *old_model = sm_ctxt->get_old_region_model ())
if (const builtin_known_function *builtin_kf
= old_model->get_builtin_kf (call))
fndecl = builtin_kf->builtin_decl ();
tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (callee_fndecl));
tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (fndecl));
attrs = lookup_attribute (attr_name, attrs);
if (!attrs)
return;
@ -1325,13 +1336,15 @@ fd_state_machine::check_for_fd_attrs (
// attributes
{
/* Do use the fndecl that caused the warning so that the
misused attributes are printed and the user not confused. */
if (is_closed_fd_p (state))
{
sm_ctxt->warn (node, stmt, arg,
make_unique<fd_use_after_close>
(*this, diag_arg,
callee_fndecl, attr_name,
fndecl, attr_name,
arg_idx));
continue;
}
@ -1343,7 +1356,7 @@ fd_state_machine::check_for_fd_attrs (
sm_ctxt->warn (node, stmt, arg,
make_unique<fd_use_without_check>
(*this, diag_arg,
callee_fndecl, attr_name,
fndecl, attr_name,
arg_idx));
continue;
}
@ -1361,7 +1374,7 @@ fd_state_machine::check_for_fd_attrs (
node, stmt, arg,
make_unique<fd_access_mode_mismatch> (*this, diag_arg,
DIRS_WRITE,
callee_fndecl,
fndecl,
attr_name,
arg_idx));
}
@ -1375,7 +1388,7 @@ fd_state_machine::check_for_fd_attrs (
node, stmt, arg,
make_unique<fd_access_mode_mismatch> (*this, diag_arg,
DIRS_READ,
callee_fndecl,
fndecl,
attr_name,
arg_idx));
}
@ -2282,10 +2295,16 @@ public:
const fd_state_machine *fd_sm;
std::unique_ptr<sm_context> sm_ctxt;
if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
return true;
{
cd.set_any_lhs_with_defaults ();
return true;
}
const extrinsic_state *ext_state = ctxt->get_ext_state ();
if (!ext_state)
return true;
{
cd.set_any_lhs_with_defaults ();
return true;
}
return fd_sm->on_socket (cd, m_success, sm_ctxt.get (), *ext_state);
}
@ -2329,10 +2348,16 @@ public:
const fd_state_machine *fd_sm;
std::unique_ptr<sm_context> sm_ctxt;
if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
return true;
{
cd.set_any_lhs_with_defaults ();
return true;
}
const extrinsic_state *ext_state = ctxt->get_ext_state ();
if (!ext_state)
return true;
{
cd.set_any_lhs_with_defaults ();
return true;
}
return fd_sm->on_bind (cd, m_success, sm_ctxt.get (), *ext_state);
}
};
@ -2374,10 +2399,16 @@ class kf_listen : public known_function
const fd_state_machine *fd_sm;
std::unique_ptr<sm_context> sm_ctxt;
if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
return true;
{
cd.set_any_lhs_with_defaults ();
return true;
}
const extrinsic_state *ext_state = ctxt->get_ext_state ();
if (!ext_state)
return true;
{
cd.set_any_lhs_with_defaults ();
return true;
}
return fd_sm->on_listen (cd, m_success, sm_ctxt.get (), *ext_state);
}
@ -2420,10 +2451,16 @@ class kf_accept : public known_function
const fd_state_machine *fd_sm;
std::unique_ptr<sm_context> sm_ctxt;
if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
return true;
{
cd.set_any_lhs_with_defaults ();
return true;
}
const extrinsic_state *ext_state = ctxt->get_ext_state ();
if (!ext_state)
return true;
{
cd.set_any_lhs_with_defaults ();
return true;
}
return fd_sm->on_accept (cd, m_success, sm_ctxt.get (), *ext_state);
}
@ -2469,10 +2506,16 @@ public:
const fd_state_machine *fd_sm;
std::unique_ptr<sm_context> sm_ctxt;
if (!get_fd_state (ctxt, &smap, &fd_sm, NULL, &sm_ctxt))
return true;
{
cd.set_any_lhs_with_defaults ();
return true;
}
const extrinsic_state *ext_state = ctxt->get_ext_state ();
if (!ext_state)
return true;
{
cd.set_any_lhs_with_defaults ();
return true;
}
return fd_sm->on_connect (cd, m_success, sm_ctxt.get (), *ext_state);
}
@ -2687,6 +2730,7 @@ public:
const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
model->set_value (base_reg, new_sval, cd.get_ctxt ());
}
cd.set_any_lhs_with_defaults ();
}
};

View File

@ -494,7 +494,7 @@ make_fileptr_state_machine (logger *logger)
effects that are out of scope for the analyzer: we only want to model
the effects on the return value. */
class kf_stdio_output_fn : public known_function
class kf_stdio_output_fn : public pure_known_function_with_default_return
{
public:
bool matches_call_types_p (const call_details &) const final override
@ -507,7 +507,7 @@ public:
/* Handler for "ferror"". */
class kf_ferror : public known_function
class kf_ferror : public pure_known_function_with_default_return
{
public:
bool matches_call_types_p (const call_details &cd) const final override
@ -521,7 +521,7 @@ public:
/* Handler for "fileno"". */
class kf_fileno : public known_function
class kf_fileno : public pure_known_function_with_default_return
{
public:
bool matches_call_types_p (const call_details &cd) const final override
@ -557,6 +557,7 @@ public:
const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
model->set_value (base_reg, new_sval, cd.get_ctxt ());
}
cd.set_any_lhs_with_defaults ();
}
};
@ -592,12 +593,13 @@ public:
const svalue *new_sval = cd.get_or_create_conjured_svalue (base_reg);
model->set_value (base_reg, new_sval, cd.get_ctxt ());
}
cd.set_any_lhs_with_defaults ();
}
};
/* Handler for "getc"". */
class kf_getc : public known_function
class kf_getc : public pure_known_function_with_default_return
{
public:
bool matches_call_types_p (const call_details &cd) const final override
@ -605,13 +607,11 @@ public:
return (cd.num_args () == 1
&& cd.arg_is_pointer_p (0));
}
/* No side effects. */
};
/* Handler for "getchar"". */
class kf_getchar : public known_function
class kf_getchar : public pure_known_function_with_default_return
{
public:
bool matches_call_types_p (const call_details &cd) const final override

View File

@ -434,6 +434,11 @@ public:
const svalue *new_ptr_sval,
const extrinsic_state &ext_state) const;
void transition_ptr_sval_non_null (region_model *model,
sm_state_map *smap,
const svalue *new_ptr_sval,
const extrinsic_state &ext_state) const;
standard_deallocator_set m_free;
standard_deallocator_set m_scalar_delete;
standard_deallocator_set m_vector_delete;
@ -754,7 +759,7 @@ public:
override
{
if (change.m_old_state == m_sm.get_start_state ()
&& unchecked_p (change.m_new_state))
&& (unchecked_p (change.m_new_state) || nonnull_p (change.m_new_state)))
// TODO: verify that it's the allocation stmt, not a copy
return label_text::borrow ("allocated here");
if (unchecked_p (change.m_old_state)
@ -1174,6 +1179,21 @@ public:
{
return ev.formatted_print ("dereference of NULL %qE", ev.m_expr);
}
/* Implementation of pending_diagnostic::supercedes_p for
null-deref.
We want null-deref to supercede use-of-unitialized-value,
so that if we have these at the same stmt, we don't emit
a use-of-uninitialized, just the null-deref. */
bool supercedes_p (const pending_diagnostic &other) const final override
{
if (other.use_of_uninit_p ())
return true;
return false;
}
};
/* Concrete subclass for describing passing a NULL value to a
@ -1910,12 +1930,20 @@ malloc_state_machine::on_stmt (sm_context *sm_ctxt,
return true;
}
if (is_named_call_p (callee_fndecl, "operator new", call, 1))
on_allocator_call (sm_ctxt, call, &m_scalar_delete);
else if (is_named_call_p (callee_fndecl, "operator new []", call, 1))
on_allocator_call (sm_ctxt, call, &m_vector_delete);
else if (is_named_call_p (callee_fndecl, "operator delete", call, 1)
|| is_named_call_p (callee_fndecl, "operator delete", call, 2))
if (!is_placement_new_p (call))
{
bool returns_nonnull = !TREE_NOTHROW (callee_fndecl)
&& flag_exceptions;
if (is_named_call_p (callee_fndecl, "operator new"))
on_allocator_call (sm_ctxt, call,
&m_scalar_delete, returns_nonnull);
else if (is_named_call_p (callee_fndecl, "operator new []"))
on_allocator_call (sm_ctxt, call,
&m_vector_delete, returns_nonnull);
}
if (is_named_call_p (callee_fndecl, "operator delete", call, 1)
|| is_named_call_p (callee_fndecl, "operator delete", call, 2))
{
on_deallocator_call (sm_ctxt, node, call,
&m_scalar_delete.m_deallocator, 0);
@ -1960,71 +1988,88 @@ malloc_state_machine::on_stmt (sm_context *sm_ctxt,
malloc_state_machine *mutable_this
= const_cast <malloc_state_machine *> (this);
/* Handle "__attribute__((malloc(FOO)))". */
if (const deallocator_set *deallocators
/* Handle interesting attributes of the callee_fndecl,
or prioritize those of the builtin that callee_fndecl is expected
to be.
Might want this to be controlled by a flag. */
{
tree fndecl = callee_fndecl;
/* If call is recognized as a builtin known_function, use that
builtin's function_decl. */
if (const region_model *old_model = sm_ctxt->get_old_region_model ())
if (const builtin_known_function *builtin_kf
= old_model->get_builtin_kf (call))
fndecl = builtin_kf->builtin_decl ();
/* Handle "__attribute__((malloc(FOO)))". */
if (const deallocator_set *deallocators
= mutable_this->get_or_create_custom_deallocator_set
(callee_fndecl))
(fndecl))
{
tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (fndecl));
bool returns_nonnull
= lookup_attribute ("returns_nonnull", attrs);
on_allocator_call (sm_ctxt, call, deallocators, returns_nonnull);
}
{
tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (callee_fndecl));
bool returns_nonnull
= lookup_attribute ("returns_nonnull", attrs);
on_allocator_call (sm_ctxt, call, deallocators, returns_nonnull);
/* Handle "__attribute__((nonnull))". */
tree fntype = TREE_TYPE (fndecl);
bitmap nonnull_args = get_nonnull_args (fntype);
if (nonnull_args)
{
for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
{
tree arg = gimple_call_arg (stmt, i);
if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
continue;
/* If we have a nonnull-args, and either all pointers, or
just the specified pointers. */
if (bitmap_empty_p (nonnull_args)
|| bitmap_bit_p (nonnull_args, i))
{
state_t state = sm_ctxt->get_state (stmt, arg);
/* Can't use a switch as the states are non-const. */
/* Do use the fndecl that caused the warning so that the
misused attributes are printed and the user not
confused. */
if (unchecked_p (state))
{
tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
sm_ctxt->warn (node, stmt, arg,
make_unique<possible_null_arg>
(*this, diag_arg, fndecl, i));
const allocation_state *astate
= as_a_allocation_state (state);
sm_ctxt->set_next_state (stmt, arg,
astate->get_nonnull ());
}
else if (state == m_null)
{
tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
sm_ctxt->warn (node, stmt, arg,
make_unique<null_arg>
(*this, diag_arg, fndecl, i));
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
else if (state == m_start)
maybe_assume_non_null (sm_ctxt, arg, stmt);
}
}
BITMAP_FREE (nonnull_args);
}
}
/* Handle "__attribute__((nonnull))". */
{
tree fntype = TREE_TYPE (callee_fndecl);
bitmap nonnull_args = get_nonnull_args (fntype);
if (nonnull_args)
/* Check for this after nonnull, so that if we have both
then we transition to "freed", rather than "checked". */
unsigned dealloc_argno = fndecl_dealloc_argno (fndecl);
if (dealloc_argno != UINT_MAX)
{
for (unsigned i = 0; i < gimple_call_num_args (stmt); i++)
{
tree arg = gimple_call_arg (stmt, i);
if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
continue;
/* If we have a nonnull-args, and either all pointers, or just
the specified pointers. */
if (bitmap_empty_p (nonnull_args)
|| bitmap_bit_p (nonnull_args, i))
{
state_t state = sm_ctxt->get_state (stmt, arg);
/* Can't use a switch as the states are non-const. */
if (unchecked_p (state))
{
tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
sm_ctxt->warn (node, stmt, arg,
make_unique<possible_null_arg>
(*this, diag_arg, callee_fndecl, i));
const allocation_state *astate
= as_a_allocation_state (state);
sm_ctxt->set_next_state (stmt, arg,
astate->get_nonnull ());
}
else if (state == m_null)
{
tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
sm_ctxt->warn (node, stmt, arg,
make_unique<null_arg>
(*this, diag_arg, callee_fndecl, i));
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
else if (state == m_start)
maybe_assume_non_null (sm_ctxt, arg, stmt);
}
}
BITMAP_FREE (nonnull_args);
const deallocator *d
= mutable_this->get_or_create_deallocator (fndecl);
on_deallocator_call (sm_ctxt, node, call, d, dealloc_argno);
}
}
/* Check for this after nonnull, so that if we have both
then we transition to "freed", rather than "checked". */
unsigned dealloc_argno = fndecl_dealloc_argno (callee_fndecl);
if (dealloc_argno != UINT_MAX)
{
const deallocator *d
= mutable_this->get_or_create_deallocator (callee_fndecl);
on_deallocator_call (sm_ctxt, node, call, d, dealloc_argno);
}
}
/* Look for pointers explicitly being compared against zero
@ -2504,6 +2549,17 @@ on_realloc_with_move (region_model *model,
NULL, ext_state);
}
/* Hook for get_or_create_region_for_heap_alloc for the case when we want
ptr_sval to mark a newly created region as assumed non null on malloc SM. */
void
malloc_state_machine::transition_ptr_sval_non_null (region_model *model,
sm_state_map *smap,
const svalue *new_ptr_sval,
const extrinsic_state &ext_state) const
{
smap->set_state (model, new_ptr_sval, m_free.m_nonnull, NULL, ext_state);
}
} // anonymous namespace
/* Internal interface to this file. */
@ -2548,6 +2604,32 @@ region_model::on_realloc_with_move (const call_details &cd,
*ext_state);
}
/* Moves ptr_sval from start to assumed non-null, for use by
region_model::get_or_create_region_for_heap_alloc. */
void
region_model::transition_ptr_sval_non_null (region_model_context *ctxt,
const svalue *ptr_sval)
{
if (!ctxt)
return;
const extrinsic_state *ext_state = ctxt->get_ext_state ();
if (!ext_state)
return;
sm_state_map *smap;
const state_machine *sm;
unsigned sm_idx;
if (!ctxt->get_malloc_map (&smap, &sm, &sm_idx))
return;
gcc_assert (smap);
gcc_assert (sm);
const malloc_state_machine &malloc_sm = (const malloc_state_machine &)*sm;
malloc_sm.transition_ptr_sval_non_null (this, smap, ptr_sval, *ext_state);
}
} // namespace ana
#endif /* #if ENABLE_ANALYZER */

View File

@ -538,6 +538,15 @@ concrete_binding::overlaps_p (const concrete_binding &other) const
return false;
}
/* If this is expressible as a concrete byte range, return true
and write it to *OUT. Otherwise return false. */
bool
concrete_binding::get_byte_range (byte_range *out) const
{
return m_bit_range.as_byte_range (out);
}
/* Comparator for use by vec<const concrete_binding *>::qsort. */
int

View File

@ -399,6 +399,7 @@ public:
{ return this; }
const bit_range &get_bit_range () const { return m_bit_range; }
bool get_byte_range (byte_range *out) const;
bit_offset_t get_start_bit_offset () const
{
@ -855,6 +856,12 @@ public:
return get_concrete_binding (bits.get_start_bit_offset (),
bits.m_size_in_bits);
}
const concrete_binding *
get_concrete_binding (const byte_range &bytes)
{
bit_range bits = bytes.as_bit_range ();
return get_concrete_binding (bits);
}
const symbolic_binding *
get_symbolic_binding (const region *region);

View File

@ -970,6 +970,8 @@ poison_kind_to_str (enum poison_kind kind)
return "uninit";
case POISON_KIND_FREED:
return "freed";
case POISON_KIND_DELETED:
return "deleted";
case POISON_KIND_POPPED_STACK:
return "popped stack";
}

View File

@ -350,6 +350,9 @@ enum poison_kind
/* For use to describe freed memory. */
POISON_KIND_FREED,
/* For use to describe deleted memory. */
POISON_KIND_DELETED,
/* For use on pointers to regions within popped stack frames. */
POISON_KIND_POPPED_STACK
};

View File

@ -1007,6 +1007,8 @@ kf_va_arg::impl_call_pre (const call_details &cd) const
tree va_list_tree = get_va_list_diag_arg (cd.get_arg_tree (0));
ap_sval = model->check_for_poison (ap_sval, va_list_tree, ap_reg, ctxt);
cd.set_any_lhs_with_defaults ();
if (const region *impl_reg = ap_sval->maybe_get_region ())
{
const svalue *old_impl_sval = model->get_store_value (impl_reg, ctxt);

View File

@ -1578,6 +1578,7 @@ afdo_annotate_cfg (const stmt_set &promoted_stmts)
}
update_max_bb_count ();
profile_status_for_fn (cfun) = PROFILE_READ;
cfun->cfg->full_profile = true;
if (flag_value_profile_transformations)
{
gimple_value_profile_transformations ();

View File

@ -1,3 +1,62 @@
2023-09-01 Jakub Jelinek <jakub@redhat.com>
PR c++/111069
* c-opts.cc (c_common_post_options): Change latest_abi_version to 19.
2023-08-31 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
* c.opt: Change spelling to macOS.
2023-08-31 Richard Biener <rguenther@suse.de>
PR middle-end/111253
* c-pretty-print.cc (c_pretty_printer::primary_expression):
Only dump gimple_assign_single_p SSA def RHS.
2023-08-25 Sandra Loosemore <sandra@codesourcery.com>
* c-common.h (c_omp_check_loop_binding_exprs): Declare.
* c-omp.cc: Include tree-iterator.h.
(find_binding_in_body): New.
(check_loop_binding_expr_r): New.
(LOCATION_OR): New.
(check_looop_binding_expr): New.
(c_omp_check_loop_binding_exprs): New.
2023-08-25 Uros Bizjak <ubizjak@gmail.com>
* c-format.cc (read_any_format_width):
Rename TRUE/FALSE to true/false.
2023-08-20 Martin Uecker <uecker@tugraz.at>
* c-format.cc: Fix identation.
2023-08-20 Tomas Kalibera <tomas.kalibera@gmail.com>
PR c/95130
* c-format.cc: skip default format for printf symbol if
explicitly declared by prototype.
2023-08-17 Jose E. Marchesi <jose.marchesi@oracle.com>
PR c/106537
* c.opt (Wcompare-distinct-pointer-types): New option.
2023-08-14 Jason Merrill <jason@redhat.com>
* c-cppbuiltin.cc (c_cpp_builtins): Adjust __cpp_concepts.
2023-08-11 Jakub Jelinek <jakub@redhat.com>
* c-common.cc (c_common_reswords): Add __typeof_unqual
and __typeof_unqual__ spellings of typeof_unqual.
2023-08-11 Martin Uecker <uecker@tugraz.at>
PR c/84510
* c.opt: Enable warning for C and ObjC.
2023-08-05 Martin Uecker <uecker@tugraz.at>
PR c/98536

View File

@ -420,6 +420,8 @@ const struct c_common_resword c_common_reswords[] =
{ "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 },
{ "__typeof", RID_TYPEOF, 0 },
{ "__typeof__", RID_TYPEOF, 0 },
{ "__typeof_unqual", RID_TYPEOF_UNQUAL, D_CONLY },
{ "__typeof_unqual__", RID_TYPEOF_UNQUAL, D_CONLY },
{ "__volatile", RID_VOLATILE, 0 },
{ "__volatile__", RID_VOLATILE, 0 },
{ "__GIMPLE", RID_GIMPLE, D_CONLY },

View File

@ -1299,6 +1299,7 @@ extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree,
extern bool c_omp_check_loop_iv (tree, tree, walk_tree_lh);
extern bool c_omp_check_loop_iv_exprs (location_t, enum tree_code, tree, int,
tree, tree, tree, walk_tree_lh);
extern bool c_omp_check_loop_binding_exprs (tree, vec<tree> *);
extern tree c_finish_oacc_wait (location_t, tree, tree);
extern tree c_oacc_split_loop_clauses (tree, tree *, bool);
extern void c_omp_split_clauses (location_t, enum tree_code, omp_clause_mask,

View File

@ -1089,7 +1089,7 @@ c_cpp_builtins (cpp_reader *pfile)
}
if (flag_concepts)
{
if (cxx_dialect >= cxx20)
if (cxx_dialect >= cxx20 || !flag_concepts_ts)
cpp_define (pfile, "__cpp_concepts=202002L");
else
cpp_define (pfile, "__cpp_concepts=201507L");

View File

@ -1175,6 +1175,7 @@ check_function_format (const_tree fn, tree attrs, int nargs,
tree a;
tree atname = get_identifier ("format");
bool skipped_default_format = false;
/* See if this function has any format attributes. */
for (a = attrs; a; a = TREE_CHAIN (a))
@ -1185,6 +1186,38 @@ check_function_format (const_tree fn, tree attrs, int nargs,
function_format_info info;
decode_format_attr (fn, atname, TREE_VALUE (a), &info,
/*validated=*/true);
/* Mingw32 targets have traditionally used ms_printf format for the
printf function, and this format is built in GCC. But nowadays,
if mingw-w64 is configured to target UCRT, the printf function
uses the gnu_printf format (specified in the stdio.h header). This
causes GCC to check both formats, which means that GCC would
warn twice about the same issue when both formats are violated,
e.g. for %lu used to print long long unsigned.
Hence, if there is a built-in attribute specifier and at least
one another, we skip the built-in one. See PR 95130 (but note that
GCC ms_printf already supports %llu) and PR 92292. */
if (!skipped_default_format
&& fn
&& TREE_CODE (fn) == FUNCTION_DECL
&& fndecl_built_in_p (fn, BUILT_IN_NORMAL)
&& (tree_to_uhwi (TREE_PURPOSE (TREE_VALUE (a)))
& (int) ATTR_FLAG_BUILT_IN))
{
tree aa;
for (aa = attrs; aa; aa = TREE_CHAIN (aa))
if (a != aa
&& is_attribute_p ("format", get_attribute_name (aa)))
{
skipped_default_format = true;
break;
}
if (skipped_default_format)
continue;
}
if (warn_format)
{
/* FIXME: Rewrite all the internal functions in this file
@ -2292,13 +2325,13 @@ read_any_format_width (tree &params,
{
/* Possibly read a numeric width. If the width is zero,
we complain if appropriate. */
int non_zero_width_char = FALSE;
int found_width = FALSE;
int non_zero_width_char = false;
int found_width = false;
while (ISDIGIT (*format_chars))
{
found_width = TRUE;
found_width = true;
if (*format_chars != '0')
non_zero_width_char = TRUE;
non_zero_width_char = true;
++format_chars;
}
if (found_width && !non_zero_width_char &&
@ -5190,6 +5223,9 @@ handle_format_attribute (tree node[3], tree atname, tree args,
if (TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
TREE_VALUE (args) = canonicalize_attr_name (TREE_VALUE (args));
/* record the flags for check_function_format */
TREE_PURPOSE (args) = build_int_cst (unsigned_type_node, flags);
if (!decode_format_attr (fndecl ? fndecl : type, atname, args, &info,
/* validated_p = */false))
{

View File

@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify.h"
#include "langhooks.h"
#include "bitmap.h"
#include "tree-iterator.h"
/* Complete a #pragma oacc wait construct. LOC is the location of
@ -1728,6 +1729,156 @@ c_omp_check_loop_iv_exprs (location_t stmt_loc, enum tree_code code,
return !data.fail;
}
/* Helper function for c_omp_check_loop_binding_exprs: look for a binding
of DECL in BODY. Only traverse things that might be containers for
intervening code in an OMP loop. Returns the BIND_EXPR or DECL_EXPR
if found, otherwise null. */
static tree
find_binding_in_body (tree decl, tree body)
{
if (!body)
return NULL_TREE;
switch (TREE_CODE (body))
{
case BIND_EXPR:
for (tree b = BIND_EXPR_VARS (body); b; b = DECL_CHAIN (b))
if (b == decl)
return body;
return find_binding_in_body (decl, BIND_EXPR_BODY (body));
case DECL_EXPR:
if (DECL_EXPR_DECL (body) == decl)
return body;
return NULL_TREE;
case STATEMENT_LIST:
for (tree_stmt_iterator si = tsi_start (body); !tsi_end_p (si);
tsi_next (&si))
{
tree b = find_binding_in_body (decl, tsi_stmt (si));
if (b)
return b;
}
return NULL_TREE;
case OMP_STRUCTURED_BLOCK:
return find_binding_in_body (decl, OMP_BODY (body));
default:
return NULL_TREE;
}
}
/* Traversal function for check_loop_binding_expr, to diagnose
errors when a binding made in intervening code is referenced outside
of the loop. Returns non-null if such a reference is found. DATA points
to the tree containing the loop body. */
static tree
check_loop_binding_expr_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
void *data)
{
tree body = *(tree *)data;
if (DECL_P (*tp) && find_binding_in_body (*tp, body))
return *tp;
return NULL_TREE;
}
/* Helper macro used below. */
#define LOCATION_OR(loc1, loc2) \
((loc1) != UNKNOWN_LOCATION ? (loc1) : (loc2))
/* Check a single expression EXPR for references to variables bound in
intervening code in BODY. Return true if ok, otherwise give an error
referencing CONTEXT and return false. Use LOC for the error message
if EXPR doesn't have one. */
static bool
check_loop_binding_expr (tree expr, tree body, const char *context,
location_t loc)
{
tree bad = walk_tree (&expr, check_loop_binding_expr_r, (void *)&body, NULL);
if (bad)
{
location_t eloc = EXPR_LOCATION (expr);
error_at (LOCATION_OR (eloc, loc),
"variable %qD used %s is bound "
"in intervening code", bad, context);
return false;
}
return true;
}
/* STMT is an OMP_FOR construct. Check all of the iteration variable,
initializer, end condition, and increment for bindings inside the
loop body. If ORIG_INITS is provided, check those elements too.
Return true if OK, false otherwise. */
bool
c_omp_check_loop_binding_exprs (tree stmt, vec<tree> *orig_inits)
{
bool ok = true;
location_t loc = EXPR_LOCATION (stmt);
tree body = OMP_FOR_BODY (stmt);
int orig_init_length = orig_inits ? orig_inits->length () : 0;
for (int i = 1; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++)
{
tree init = TREE_VEC_ELT (OMP_FOR_INIT (stmt), i);
tree cond = TREE_VEC_ELT (OMP_FOR_COND (stmt), i);
tree incr = TREE_VEC_ELT (OMP_FOR_INCR (stmt), i);
gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
tree decl = TREE_OPERAND (init, 0);
tree orig_init = i < orig_init_length ? (*orig_inits)[i] : NULL_TREE;
tree e;
location_t eloc;
e = TREE_OPERAND (init, 1);
eloc = LOCATION_OR (EXPR_LOCATION (init), loc);
if (!check_loop_binding_expr (decl, body, "as loop variable", eloc))
ok = false;
if (!check_loop_binding_expr (e, body, "in initializer", eloc))
ok = false;
if (orig_init
&& !check_loop_binding_expr (orig_init, body,
"in initializer", eloc))
ok = false;
/* INCR and/or COND may be null if this is a template with a
class iterator. */
if (cond)
{
eloc = LOCATION_OR (EXPR_LOCATION (cond), loc);
if (COMPARISON_CLASS_P (cond) && TREE_OPERAND (cond, 0) == decl)
e = TREE_OPERAND (cond, 1);
else if (COMPARISON_CLASS_P (cond) && TREE_OPERAND (cond, 1) == decl)
e = TREE_OPERAND (cond, 0);
else
e = cond;
if (!check_loop_binding_expr (e, body, "in end test", eloc))
ok = false;
}
if (incr)
{
eloc = LOCATION_OR (EXPR_LOCATION (incr), loc);
/* INCR should be either a MODIFY_EXPR or pre/post
increment/decrement. We don't have to check the latter
since there are no operands besides the iteration variable. */
if (TREE_CODE (incr) == MODIFY_EXPR
&& !check_loop_binding_expr (TREE_OPERAND (incr, 1), body,
"in increment expression", eloc))
ok = false;
}
}
return ok;
}
/* This function splits clauses for OpenACC combined loop
constructs. OpenACC combined loop constructs are:
#pragma acc kernels loop

View File

@ -974,7 +974,7 @@ c_common_post_options (const char **pfilename)
/* Change flag_abi_version to be the actual current ABI level, for the
benefit of c_cpp_builtins, and to make comparison simpler. */
const int latest_abi_version = 18;
const int latest_abi_version = 19;
/* Generate compatibility aliases for ABI v13 (8.2) by default. */
const int abi_compat_default = 13;

View File

@ -33,6 +33,9 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "options.h"
#include "internal-fn.h"
#include "function.h"
#include "basic-block.h"
#include "gimple.h"
/* The pretty-printer code is primarily designed to closely follow
(GNU) C and C++ grammars. That is to be contrasted with spaghetti
@ -1380,12 +1383,14 @@ c_pretty_printer::primary_expression (tree e)
else
primary_expression (var);
}
else
else if (gimple_assign_single_p (SSA_NAME_DEF_STMT (e)))
{
/* Print only the right side of the GIMPLE assignment. */
gimple *def_stmt = SSA_NAME_DEF_STMT (e);
pp_gimple_stmt_1 (this, def_stmt, 0, TDF_RHS_ONLY);
}
else
expression (e);
break;
default:

View File

@ -1490,7 +1490,7 @@ C++ ObjC++ Var(warn_zero_as_null_pointer_constant) Warning
Warn when a literal '0' is used as null pointer.
Wuseless-cast
C++ ObjC++ Var(warn_useless_cast) Warning
C ObjC C++ ObjC++ Var(warn_useless_cast) Warning
Warn about useless casts.
Wsubobject-linkage
@ -1935,6 +1935,10 @@ Winvalid-imported-macros
C++ ObjC++ Var(warn_imported_macros) Warning
Warn about macros that have conflicting header units definitions.
Wcompare-distinct-pointer-types
C ObjC Var(warn_compare_distinct_pointer_types) Warning Init(1)
Warn if pointers of distinct types are compared without a cast.
flang-info-include-translate
C++ Var(note_include_translate_yes)
Note #include directives translated to import declarations.
@ -1984,7 +1988,7 @@ Implement resolution of DR 150 for matching of template template arguments.
fnext-runtime
ObjC ObjC++ LTO RejectNegative Var(flag_next_runtime)
Generate code for NeXT (Apple Mac OS X) runtime environment.
Generate code for NeXT (Apple macOS) runtime environment.
fnil-receivers
ObjC ObjC++ Var(flag_nil_receivers) Init(1)

View File

@ -1,3 +1,57 @@
2023-08-25 Sandra Loosemore <sandra@codesourcery.com>
* c-parser.cc (struct c_parser): Add omp_for_parse_state field.
(struct omp_for_parse_data): New.
(check_omp_intervening_code): New.
(add_structured_block_stmt): New.
(c_parser_compound_statement_nostart): Recognize intervening code,
nested loops, and other things that need special handling in
OpenMP loop constructs.
(c_parser_while_statement): Error on loop in intervening code.
(c_parser_do_statement): Likewise.
(c_parser_for_statement): Likewise.
(c_parser_postfix_expression_after_primary): Error on calls to
the OpenMP runtime in intervening code.
(c_parser_pragma): Error on OpenMP pragmas in intervening code.
(c_parser_omp_loop_nest): New.
(c_parser_omp_for_loop): Rewrite to use recursive descent, calling
c_parser_omp_loop_nest to do the heavy lifting.
2023-08-24 Richard Sandiford <richard.sandiford@arm.com>
* c-parser.cc (c_parser_std_attribute): Conditionally allow
two colons to be used in place of ::.
(c_parser_std_attribute_list): New function, split out from...
(c_parser_std_attribute_specifier): ...here. Allow the attribute-list
to start with __extension__. When it does, also allow two colons
to be used in place of ::.
2023-08-22 Tobias Burnus <tobias@codesourcery.com>
* c-parser.cc (c_parser_omp_clause_defaultmap): Parse
'all' as category.
2023-08-17 Jose E. Marchesi <jose.marchesi@oracle.com>
PR c/106537
* c-typeck.cc (build_binary_op): Warning on comparing distinct
pointer types only when -Wcompare-distinct-pointer-types.
2023-08-15 Chung-Lin Tang <cltang@codesourcery.com>
Thomas Schwinge <thomas@codesourcery.com>
* c-parser.cc (OACC_DATA_CLAUSE_MASK): Add PRAGMA_OACC_CLAUSE_DEFAULT.
2023-08-11 Jakub Jelinek <jakub@redhat.com>
* c-parser.cc (c_parser_typeof_specifier): Handle
__typeof_unqual and __typeof_unqual__ as !is_std.
2023-08-11 Martin Uecker <uecker@tugraz.at>
PR c/84510
* c-typeck.cc (build_c_cast): Add warning.
2023-08-05 Martin Uecker <uecker@tugraz.at>
* c-parser.cc (c_parser_generic_selection): Inhibit evaluation

File diff suppressed because it is too large Load Diff

View File

@ -6062,9 +6062,13 @@ build_c_cast (location_t loc, tree type, tree expr)
if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value)))
{
if (RECORD_OR_UNION_TYPE_P (type))
pedwarn (loc, OPT_Wpedantic,
"ISO C forbids casting nonscalar to the same type");
if (RECORD_OR_UNION_TYPE_P (type)
&& pedwarn (loc, OPT_Wpedantic,
"ISO C forbids casting nonscalar to the same type"))
;
else if (warn_useless_cast)
warning_at (loc, OPT_Wuseless_cast,
"useless cast to type %qT", type);
/* Convert to remove any qualifiers from VALUE's type. */
value = convert (type, value);
@ -12768,7 +12772,7 @@ build_binary_op (location_t location, enum tree_code code,
else
/* Avoid warning about the volatile ObjC EH puts on decls. */
if (!objc_ok)
pedwarn (location, 0,
pedwarn (location, OPT_Wcompare_distinct_pointer_types,
"comparison of distinct pointer types lacks a cast");
if (result_type == NULL_TREE)
@ -12908,8 +12912,8 @@ build_binary_op (location_t location, enum tree_code code,
int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
result_type = build_pointer_type
(build_qualified_type (void_type_node, qual));
pedwarn (location, 0,
"comparison of distinct pointer types lacks a cast");
pedwarn (location, OPT_Wcompare_distinct_pointer_types,
"comparison of distinct pointer types lacks a cast");
}
}
else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))

View File

@ -342,7 +342,7 @@ new_saved_hard_reg (int regno, int call_freq)
saved_reg->num = saved_regs_num++;
saved_reg->hard_regno = regno;
saved_reg->call_freq = call_freq;
saved_reg->first_p = FALSE;
saved_reg->first_p = false;
saved_reg->next = -1;
}
@ -558,7 +558,7 @@ setup_save_areas (void)
+ saved_reg2->num]
= saved_reg_conflicts[saved_reg2->num * saved_regs_num
+ saved_reg->num]
= TRUE;
= true;
}
}
}
@ -608,7 +608,7 @@ setup_save_areas (void)
}
if (j == i)
{
saved_reg->first_p = TRUE;
saved_reg->first_p = true;
for (best_slot_num = -1, j = 0; j < prev_save_slots_num; j++)
{
slot = prev_save_slots[j];

View File

@ -81,6 +81,7 @@ init_flow (struct function *the_fun)
= ENTRY_BLOCK_PTR_FOR_FN (the_fun);
the_fun->cfg->edge_flags_allocated = EDGE_ALL_FLAGS;
the_fun->cfg->bb_flags_allocated = BB_ALL_FLAGS;
the_fun->cfg->full_profile = false;
}
/* Helper function for remove_edge and free_cffg. Frees edge structure

View File

@ -78,6 +78,9 @@ struct GTY(()) control_flow_graph {
/* Dynamically allocated edge/bb flags. */
int edge_flags_allocated;
int bb_flags_allocated;
/* Set if the profile is computed on every edge and basic block. */
bool full_profile;
};

View File

@ -1296,6 +1296,16 @@ duplicate_loop_body_to_header_edge (class loop *loop, edge e,
}
profile_probability prob_pass_wont_exit =
new_count_le.probability_in (count_in);
/* If profile count is 0, the probability will be uninitialized.
We can set probability to any initialized value to avoid
precision loss. If profile is sane, all counts will be 0 anyway. */
if (!count_in.nonzero_p ())
{
prob_pass_thru
= profile_probability::always ().apply_scale (1, 2);
prob_pass_wont_exit
= profile_probability::always ().apply_scale (1, 2);
}
scale_step = XNEWVEC (profile_probability, ndupl);
@ -1306,7 +1316,9 @@ duplicate_loop_body_to_header_edge (class loop *loop, edge e,
/* Complete peeling is special as the probability of exit in last
copy becomes 1. */
if (flags & DLTHE_FLAG_COMPLETTE_PEEL)
if (!count_in.nonzero_p ())
;
else if (flags & DLTHE_FLAG_COMPLETTE_PEEL)
{
profile_count wanted_count = e->count ();

View File

@ -1010,6 +1010,9 @@ Driver Undocumented
; 18: Corrects errors in mangling of lambdas with additional context.
; Default in G++ 13.
;
; 19: Emits ABI tags if needed in structured binding mangled names.
; Default in G++ 14.
;
; Additional positive integers will be assigned as new versions of
; the ABI become the default version of the ABI.
fabi-version=

View File

@ -533,10 +533,14 @@ get_intel_cpu (struct __processor_model *cpu_model,
cpu_model->__cpu_type = INTEL_COREI7;
cpu_model->__cpu_subtype = INTEL_COREI7_TIGERLAKE;
break;
case 0xbe:
/* Alder Lake N, E-core only. */
case 0x97:
case 0x9a:
/* Alder Lake. */
case 0xb7:
case 0xba:
case 0xbf:
/* Raptor Lake. */
case 0xaa:
@ -762,7 +766,9 @@ get_available_features (struct __processor_model *cpu_model,
/* Get Advanced Features at level 7 (eax = 7, ecx = 0/1). */
if (max_cpuid_level >= 7)
{
__cpuid_count (7, 0, eax, ebx, ecx, edx);
unsigned int max_subleaf_level;
__cpuid_count (7, 0, max_subleaf_level, ebx, ecx, edx);
if (ebx & bit_BMI)
set_feature (FEATURE_BMI);
if (ebx & bit_SGX)
@ -874,45 +880,48 @@ get_available_features (struct __processor_model *cpu_model,
set_feature (FEATURE_AVX512FP16);
}
__cpuid_count (7, 1, eax, ebx, ecx, edx);
if (eax & bit_HRESET)
set_feature (FEATURE_HRESET);
if (eax & bit_CMPCCXADD)
set_feature(FEATURE_CMPCCXADD);
if (edx & bit_PREFETCHI)
set_feature (FEATURE_PREFETCHI);
if (eax & bit_RAOINT)
set_feature (FEATURE_RAOINT);
if (avx_usable)
if (max_subleaf_level >= 1)
{
if (eax & bit_AVXVNNI)
set_feature (FEATURE_AVXVNNI);
if (eax & bit_AVXIFMA)
set_feature (FEATURE_AVXIFMA);
if (edx & bit_AVXVNNIINT8)
set_feature (FEATURE_AVXVNNIINT8);
if (edx & bit_AVXNECONVERT)
set_feature (FEATURE_AVXNECONVERT);
if (edx & bit_AVXVNNIINT16)
set_feature (FEATURE_AVXVNNIINT16);
if (eax & bit_SM3)
set_feature (FEATURE_SM3);
if (eax & bit_SHA512)
set_feature (FEATURE_SHA512);
if (eax & bit_SM4)
set_feature (FEATURE_SM4);
}
if (avx512_usable)
{
if (eax & bit_AVX512BF16)
set_feature (FEATURE_AVX512BF16);
}
if (amx_usable)
{
if (eax & bit_AMX_FP16)
set_feature (FEATURE_AMX_FP16);
if (edx & bit_AMX_COMPLEX)
set_feature (FEATURE_AMX_COMPLEX);
__cpuid_count (7, 1, eax, ebx, ecx, edx);
if (eax & bit_HRESET)
set_feature (FEATURE_HRESET);
if (eax & bit_CMPCCXADD)
set_feature(FEATURE_CMPCCXADD);
if (edx & bit_PREFETCHI)
set_feature (FEATURE_PREFETCHI);
if (eax & bit_RAOINT)
set_feature (FEATURE_RAOINT);
if (avx_usable)
{
if (eax & bit_AVXVNNI)
set_feature (FEATURE_AVXVNNI);
if (eax & bit_AVXIFMA)
set_feature (FEATURE_AVXIFMA);
if (edx & bit_AVXVNNIINT8)
set_feature (FEATURE_AVXVNNIINT8);
if (edx & bit_AVXNECONVERT)
set_feature (FEATURE_AVXNECONVERT);
if (edx & bit_AVXVNNIINT16)
set_feature (FEATURE_AVXVNNIINT16);
if (eax & bit_SM3)
set_feature (FEATURE_SM3);
if (eax & bit_SHA512)
set_feature (FEATURE_SHA512);
if (eax & bit_SM4)
set_feature (FEATURE_SM4);
}
if (avx512_usable)
{
if (eax & bit_AVX512BF16)
set_feature (FEATURE_AVX512BF16);
}
if (amx_usable)
{
if (eax & bit_AMX_FP16)
set_feature (FEATURE_AMX_FP16);
if (edx & bit_AMX_COMPLEX)
set_feature (FEATURE_AMX_COMPLEX);
}
}
}

View File

@ -2044,7 +2044,9 @@ const char *const processor_names[] =
"alderlake",
"rocketlake",
"graniterapids",
"graniterapids-d",
"arrowlake",
"arrowlake-s",
"intel",
"lujiazui",
"geode",
@ -2168,13 +2170,14 @@ const pta processor_alias_table[] =
M_CPU_SUBTYPE (INTEL_COREI7_ALDERLAKE), P_PROC_AVX2},
{"graniterapids", PROCESSOR_GRANITERAPIDS, CPU_HASWELL, PTA_GRANITERAPIDS,
M_CPU_SUBTYPE (INTEL_COREI7_GRANITERAPIDS), P_PROC_AVX512F},
{"graniterapids-d", PROCESSOR_GRANITERAPIDS, CPU_HASWELL, PTA_GRANITERAPIDS_D,
M_CPU_SUBTYPE (INTEL_COREI7_GRANITERAPIDS_D), P_PROC_AVX512F},
{"graniterapids-d", PROCESSOR_GRANITERAPIDS_D, CPU_HASWELL,
PTA_GRANITERAPIDS_D, M_CPU_SUBTYPE (INTEL_COREI7_GRANITERAPIDS_D),
P_PROC_AVX512F},
{"arrowlake", PROCESSOR_ARROWLAKE, CPU_HASWELL, PTA_ARROWLAKE,
M_CPU_SUBTYPE (INTEL_COREI7_ARROWLAKE), P_PROC_AVX2},
{"arrowlake-s", PROCESSOR_ARROWLAKE, CPU_HASWELL, PTA_ARROWLAKE_S,
{"arrowlake-s", PROCESSOR_ARROWLAKE_S, CPU_HASWELL, PTA_ARROWLAKE_S,
M_CPU_SUBTYPE (INTEL_COREI7_ARROWLAKE_S), P_PROC_AVX2},
{"lunarlake", PROCESSOR_ARROWLAKE, CPU_HASWELL, PTA_ARROWLAKE_S,
{"lunarlake", PROCESSOR_ARROWLAKE_S, CPU_HASWELL, PTA_ARROWLAKE_S,
M_CPU_SUBTYPE (INTEL_COREI7_ARROWLAKE_S), P_PROC_AVX2},
{"bonnell", PROCESSOR_BONNELL, CPU_ATOM, PTA_BONNELL,
M_CPU_TYPE (INTEL_BONNELL), P_PROC_SSSE3},
@ -2190,6 +2193,8 @@ const pta processor_alias_table[] =
M_CPU_TYPE (INTEL_GOLDMONT_PLUS), P_PROC_SSE4_2},
{"tremont", PROCESSOR_TREMONT, CPU_HASWELL, PTA_TREMONT,
M_CPU_TYPE (INTEL_TREMONT), P_PROC_SSE4_2},
{"gracemont", PROCESSOR_ALDERLAKE, CPU_HASWELL, PTA_ALDERLAKE,
M_CPU_SUBTYPE (INTEL_COREI7_ALDERLAKE), P_PROC_AVX2},
{"sierraforest", PROCESSOR_SIERRAFOREST, CPU_HASWELL, PTA_SIERRAFOREST,
M_CPU_SUBTYPE (INTEL_SIERRAFOREST), P_PROC_AVX2},
{"grandridge", PROCESSOR_GRANDRIDGE, CPU_HASWELL, PTA_GRANDRIDGE,

View File

@ -35,6 +35,7 @@ static const struct default_options loongarch_option_optimization_table[] =
{
{ OPT_LEVELS_ALL, OPT_fasynchronous_unwind_tables, NULL, 1 },
{ OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 },
{ OPT_LEVELS_2_PLUS, OPT_free, NULL, 1 },
{ OPT_LEVELS_NONE, 0, NULL, 0 }
};

View File

@ -71,6 +71,8 @@ static const riscv_implied_info_t riscv_implied_info[] =
{"zks", "zksed"},
{"zks", "zksh"},
{"ztso", "a"},
{"v", "zvl128b"},
{"v", "zve64d"},
@ -121,6 +123,9 @@ static const riscv_implied_info_t riscv_implied_info[] =
{"zfh", "zfhmin"},
{"zfhmin", "f"},
{"zfa", "f"},
{"zvfhmin", "zve32f"},
{"zvfh", "zve32f"},
{"zvfh", "zfhmin"},
@ -128,6 +133,25 @@ static const riscv_implied_info_t riscv_implied_info[] =
{"zhinx", "zhinxmin"},
{"zhinxmin", "zfinx"},
{"zce", "zca"},
{"zce", "zcb"},
{"zce", "zcmp"},
{"zce", "zcmt"},
{"zcf", "zca"},
{"zcd", "zca"},
{"zcb", "zca"},
{"zcmp", "zca"},
{"zcmt", "zca"},
{"zcmt", "zicsr"},
{"smaia", "ssaia"},
{"smstateen", "ssstateen"},
{"smepmp", "zicsr"},
{"ssaia", "zicsr"},
{"sscofpmf", "zicsr"},
{"ssstateen", "zicsr"},
{"sstc", "zicsr"},
{NULL, NULL}
};
@ -209,6 +233,7 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
{"zkt", ISA_SPEC_CLASS_NONE, 1, 0},
{"zihintntl", ISA_SPEC_CLASS_NONE, 1, 0},
{"zihintpause", ISA_SPEC_CLASS_NONE, 2, 0},
{"zicboz",ISA_SPEC_CLASS_NONE, 1, 0},
{"zicbom",ISA_SPEC_CLASS_NONE, 1, 0},
@ -218,9 +243,10 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
{"zkn", ISA_SPEC_CLASS_NONE, 1, 0},
{"zks", ISA_SPEC_CLASS_NONE, 1, 0},
{"ztso", ISA_SPEC_CLASS_NONE, 1, 0},
{"zve32x", ISA_SPEC_CLASS_NONE, 1, 0},
{"zve32f", ISA_SPEC_CLASS_NONE, 1, 0},
{"zve32d", ISA_SPEC_CLASS_NONE, 1, 0},
{"zve64x", ISA_SPEC_CLASS_NONE, 1, 0},
{"zve64f", ISA_SPEC_CLASS_NONE, 1, 0},
{"zve64d", ISA_SPEC_CLASS_NONE, 1, 0},
@ -259,10 +285,30 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
{"zvfhmin", ISA_SPEC_CLASS_NONE, 1, 0},
{"zvfh", ISA_SPEC_CLASS_NONE, 1, 0},
{"zfa", ISA_SPEC_CLASS_NONE, 0, 1},
{"zmmul", ISA_SPEC_CLASS_NONE, 1, 0},
{"zca", ISA_SPEC_CLASS_NONE, 1, 0},
{"zcb", ISA_SPEC_CLASS_NONE, 1, 0},
{"zce", ISA_SPEC_CLASS_NONE, 1, 0},
{"zcf", ISA_SPEC_CLASS_NONE, 1, 0},
{"zcd", ISA_SPEC_CLASS_NONE, 1, 0},
{"zcmp", ISA_SPEC_CLASS_NONE, 1, 0},
{"zcmt", ISA_SPEC_CLASS_NONE, 1, 0},
{"smaia", ISA_SPEC_CLASS_NONE, 1, 0},
{"smepmp", ISA_SPEC_CLASS_NONE, 1, 0},
{"smstateen", ISA_SPEC_CLASS_NONE, 1, 0},
{"ssaia", ISA_SPEC_CLASS_NONE, 1, 0},
{"sscofpmf", ISA_SPEC_CLASS_NONE, 1, 0},
{"ssstateen", ISA_SPEC_CLASS_NONE, 1, 0},
{"sstc", ISA_SPEC_CLASS_NONE, 1, 0},
{"svinval", ISA_SPEC_CLASS_NONE, 1, 0},
{"svnapot", ISA_SPEC_CLASS_NONE, 1, 0},
{"svpbmt", ISA_SPEC_CLASS_NONE, 1, 0},
{"xtheadba", ISA_SPEC_CLASS_NONE, 1, 0},
{"xtheadbb", ISA_SPEC_CLASS_NONE, 1, 0},
@ -277,6 +323,8 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
{"xtheadmempair", ISA_SPEC_CLASS_NONE, 1, 0},
{"xtheadsync", ISA_SPEC_CLASS_NONE, 1, 0},
{"xventanacondops", ISA_SPEC_CLASS_NONE, 1, 0},
/* Terminate the list. */
{NULL, ISA_SPEC_CLASS_NONE, 0, 0}
};
@ -1266,11 +1314,22 @@ riscv_subset_list::parse (const char *arch, location_t loc)
subset_list->handle_implied_ext (itr->name.c_str ());
}
/* Zce only implies zcf when RV32 and 'f' extension exist. */
if (subset_list->lookup ("zce") != NULL
&& subset_list->m_xlen == 32
&& subset_list->lookup ("f") != NULL
&& subset_list->lookup ("zcf") == NULL)
subset_list->add ("zcf", false);
/* Make sure all implied extensions are included. */
gcc_assert (subset_list->check_implied_ext ());
subset_list->handle_combine_ext ();
if (subset_list->lookup ("zcf") && subset_list->m_xlen == 64)
error_at (loc, "%<-march=%s%>: zcf extension supports in rv32 only"
, arch);
if (subset_list->lookup ("zfinx") && subset_list->lookup ("f"))
error_at (loc, "%<-march=%s%>: z*inx conflicts with floating-point "
"extensions", arch);
@ -1344,6 +1403,7 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
{"zkt", &gcc_options::x_riscv_zk_subext, MASK_ZKT},
{"zihintntl", &gcc_options::x_riscv_zi_subext, MASK_ZIHINTNTL},
{"zihintpause", &gcc_options::x_riscv_zi_subext, MASK_ZIHINTPAUSE},
{"zicboz", &gcc_options::x_riscv_zicmo_subext, MASK_ZICBOZ},
{"zicbom", &gcc_options::x_riscv_zicmo_subext, MASK_ZICBOM},
@ -1402,11 +1462,24 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
{"zvfhmin", &gcc_options::x_riscv_zf_subext, MASK_ZVFHMIN},
{"zvfh", &gcc_options::x_riscv_zf_subext, MASK_ZVFH},
{"zfa", &gcc_options::x_riscv_zfa_subext, MASK_ZFA},
{"zmmul", &gcc_options::x_riscv_zm_subext, MASK_ZMMUL},
/* Code-size reduction extensions. */
{"zca", &gcc_options::x_riscv_zc_subext, MASK_ZCA},
{"zcb", &gcc_options::x_riscv_zc_subext, MASK_ZCB},
{"zce", &gcc_options::x_riscv_zc_subext, MASK_ZCE},
{"zcf", &gcc_options::x_riscv_zc_subext, MASK_ZCF},
{"zcd", &gcc_options::x_riscv_zc_subext, MASK_ZCD},
{"zcmp", &gcc_options::x_riscv_zc_subext, MASK_ZCMP},
{"zcmt", &gcc_options::x_riscv_zc_subext, MASK_ZCMT},
{"svinval", &gcc_options::x_riscv_sv_subext, MASK_SVINVAL},
{"svnapot", &gcc_options::x_riscv_sv_subext, MASK_SVNAPOT},
{"ztso", &gcc_options::x_riscv_ztso_subext, MASK_ZTSO},
{"xtheadba", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBA},
{"xtheadbb", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBB},
{"xtheadbs", &gcc_options::x_riscv_xthead_subext, MASK_XTHEADBS},
@ -1973,6 +2046,8 @@ riscv_get_valid_option_values (int option_code,
static const struct default_options riscv_option_optimization_table[] =
{
{ OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 },
/* Enable -fsched-pressure starting at -O1. */
{ OPT_LEVELS_1_PLUS, OPT_fsched_pressure, NULL, 1 },
{ OPT_LEVELS_2_PLUS, OPT_free, NULL, 1 },
#if TARGET_DEFAULT_ASYNC_UNWIND_TABLES == 1
{ OPT_LEVELS_ALL, OPT_fasynchronous_unwind_tables, NULL, 1 },

View File

@ -541,7 +541,7 @@ pru-*-*)
;;
riscv*)
cpu_type=riscv
extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-v.o riscv-vsetvl.o"
extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-v.o riscv-vsetvl.o riscv-vector-costs.o"
extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o"
extra_objs="${extra_objs} thead.o"
d_target_objs="riscv-d.o"

View File

@ -622,15 +622,13 @@
#endif
/* Define if your Mac OS X assembler supports -mllvm -x86-pad-for-align=false.
*/
/* Define if your macOS assembler supports -mllvm -x86-pad-for-align=false. */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN
#endif
/* Define if your Mac OS X assembler supports the -mmacos-version-min option.
*/
/* Define if your macOS assembler supports the -mmacos-version-min option. */
#ifndef USED_FOR_TARGET
#undef HAVE_AS_MMACOSX_VERSION_MIN_OPTION
#endif

View File

@ -170,10 +170,14 @@ AARCH64_CORE("cortex-r82", cortexr82, cortexa53, V8R, (), cortexa53, 0x41, 0xd15
/* Arm ('A') cores. */
AARCH64_CORE("cortex-a510", cortexa510, cortexa55, V9A, (SVE2_BITPERM, MEMTAG, I8MM, BF16), cortexa53, 0x41, 0xd46, -1)
AARCH64_CORE("cortex-a520", cortexa520, cortexa55, V9_2A, (SVE2_BITPERM, MEMTAG), cortexa53, 0x41, 0xd80, -1)
AARCH64_CORE("cortex-a710", cortexa710, cortexa57, V9A, (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd47, -1)
AARCH64_CORE("cortex-a715", cortexa715, cortexa57, V9A, (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd4d, -1)
AARCH64_CORE("cortex-a720", cortexa720, cortexa57, V9_2A, (SVE2_BITPERM, MEMTAG, PROFILE), neoversen2, 0x41, 0xd81, -1)
AARCH64_CORE("cortex-x2", cortexx2, cortexa57, V9A, (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd48, -1)
AARCH64_CORE("cortex-x3", cortexx3, cortexa57, V9A, (SVE2_BITPERM, MEMTAG, I8MM, BF16), neoversen2, 0x41, 0xd4e, -1)

View File

@ -1,5 +1,5 @@
;; -*- buffer-read-only: t -*-
;; Generated automatically by gentune.sh from aarch64-cores.def
(define_attr "tune"
"cortexa34,cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,thunderx,thunderxt88p1,thunderxt88,octeontx,octeontxt81,octeontxt83,thunderxt81,thunderxt83,ampere1,ampere1a,emag,xgene1,falkor,qdf24xx,exynosm1,phecda,thunderx2t99p1,vulcan,thunderx2t99,cortexa55,cortexa75,cortexa76,cortexa76ae,cortexa77,cortexa78,cortexa78ae,cortexa78c,cortexa65,cortexa65ae,cortexx1,cortexx1c,ares,neoversen1,neoversee1,octeontx2,octeontx2t98,octeontx2t96,octeontx2t93,octeontx2f95,octeontx2f95n,octeontx2f95mm,a64fx,tsv110,thunderx3t110,zeus,neoversev1,neoverse512tvb,saphira,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53,cortexa75cortexa55,cortexa76cortexa55,cortexr82,cortexa510,cortexa710,cortexa715,cortexx2,cortexx3,neoversen2,demeter,neoversev2"
"cortexa34,cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,thunderx,thunderxt88p1,thunderxt88,octeontx,octeontxt81,octeontxt83,thunderxt81,thunderxt83,ampere1,ampere1a,emag,xgene1,falkor,qdf24xx,exynosm1,phecda,thunderx2t99p1,vulcan,thunderx2t99,cortexa55,cortexa75,cortexa76,cortexa76ae,cortexa77,cortexa78,cortexa78ae,cortexa78c,cortexa65,cortexa65ae,cortexx1,cortexx1c,ares,neoversen1,neoversee1,octeontx2,octeontx2t98,octeontx2t96,octeontx2t93,octeontx2f95,octeontx2f95n,octeontx2f95mm,a64fx,tsv110,thunderx3t110,zeus,neoversev1,neoverse512tvb,saphira,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53,cortexa75cortexa55,cortexa76cortexa55,cortexr82,cortexa510,cortexa520,cortexa710,cortexa715,cortexa720,cortexx2,cortexx3,neoversen2,demeter,neoversev2"
(const (symbol_ref "((enum attr_tune) aarch64_tune)")))

View File

@ -84,6 +84,7 @@
#include "aarch64-feature-deps.h"
#include "config/arm/aarch-common.h"
#include "config/arm/aarch-common-protos.h"
#include "ssa.h"
/* This file should be included last. */
#include "target-def.h"
@ -11182,7 +11183,8 @@ aarch64_classify_symbolic_expression (rtx x)
/* Return TRUE if X is a legitimate address for accessing memory in
mode MODE. */
static bool
aarch64_legitimate_address_hook_p (machine_mode mode, rtx x, bool strict_p)
aarch64_legitimate_address_hook_p (machine_mode mode, rtx x, bool strict_p,
code_helper = ERROR_MARK)
{
struct aarch64_address_info addr;
@ -16410,20 +16412,20 @@ aarch64_multiply_add_p (vec_info *vinfo, stmt_vec_info stmt_info,
if (code != PLUS_EXPR && code != MINUS_EXPR)
return false;
for (int i = 1; i < 3; ++i)
auto is_mul_result = [&](int i)
{
tree rhs = gimple_op (assign, i);
/* ??? Should we try to check for a single use as well? */
if (TREE_CODE (rhs) != SSA_NAME)
continue;
return false;
stmt_vec_info def_stmt_info = vinfo->lookup_def (rhs);
if (!def_stmt_info
|| STMT_VINFO_DEF_TYPE (def_stmt_info) != vect_internal_def)
continue;
return false;
gassign *rhs_assign = dyn_cast<gassign *> (def_stmt_info->stmt);
if (!rhs_assign || gimple_assign_rhs_code (rhs_assign) != MULT_EXPR)
continue;
return false;
if (vec_flags & VEC_ADVSIMD)
{
@ -16443,8 +16445,19 @@ aarch64_multiply_add_p (vec_info *vinfo, stmt_vec_info stmt_info,
}
return true;
}
return false;
};
if (code == MINUS_EXPR && (vec_flags & VEC_ADVSIMD))
/* Advanced SIMD doesn't have FNMADD/FNMSUB/FNMLA/FNMLS, so the
multiplication must be on the second operand (to form an FMLS).
But if both operands are multiplications and the second operand
is used more than once, we'll instead negate the second operand
and use it as an accumulator for the first operand. */
return (is_mul_result (2)
&& (has_single_use (gimple_assign_rhs2 (assign))
|| !is_mul_result (1)));
return is_mul_result (1) || is_mul_result (2);
}
/* Return true if STMT_INFO is the second part of a two-statement boolean AND
@ -25665,7 +25678,7 @@ aarch64_asan_shadow_offset (void)
static rtx
aarch64_gen_ccmp_first (rtx_insn **prep_seq, rtx_insn **gen_seq,
int code, tree treeop0, tree treeop1)
rtx_code code, tree treeop0, tree treeop1)
{
machine_mode op_mode, cmp_mode, cc_mode = CCmode;
rtx op0, op1;
@ -25739,7 +25752,8 @@ aarch64_gen_ccmp_first (rtx_insn **prep_seq, rtx_insn **gen_seq,
static rtx
aarch64_gen_ccmp_next (rtx_insn **prep_seq, rtx_insn **gen_seq, rtx prev,
int cmp_code, tree treeop0, tree treeop1, int bit_code)
rtx_code cmp_code, tree treeop0, tree treeop1,
rtx_code bit_code)
{
rtx op0, op1, target;
machine_mode op_mode, cmp_mode, cc_mode = CCmode;

View File

@ -1170,9 +1170,27 @@
{
int i;
/* Generate a PARALLEL that contains all of the register results.
The offsets are somewhat arbitrary, since we don't know the
actual return type. The main thing we need to avoid is having
overlapping byte ranges, since those might give the impression
that two registers are known to have data in common. */
rtvec rets = rtvec_alloc (XVECLEN (operands[2], 0));
poly_int64 offset = 0;
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{
rtx reg = SET_SRC (XVECEXP (operands[2], 0, i));
gcc_assert (REG_P (reg));
rtx offset_rtx = gen_int_mode (offset, Pmode);
rtx piece = gen_rtx_EXPR_LIST (VOIDmode, reg, offset_rtx);
RTVEC_ELT (rets, i) = piece;
offset += GET_MODE_SIZE (GET_MODE (reg));
}
rtx ret = gen_rtx_PARALLEL (VOIDmode, rets);
/* Untyped calls always use the default ABI. It's only possible to use
ABI variants if we know the type of the target function. */
emit_call_insn (gen_call (operands[0], const0_rtx, const0_rtx));
emit_call_insn (gen_call_value (ret, operands[0], const0_rtx, const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
{

View File

@ -740,7 +740,7 @@ dump_insn_list (const rtx &t, const insn_info_list_t &insn_info,
void *unused ATTRIBUTE_UNUSED)
{
gcc_assert (dump_file);
fprintf (dump_file, "Tag 0x%lx ::\n", INTVAL (t));
fprintf (dump_file, "Tag 0x" HOST_WIDE_INT_PRINT_HEX_PURE " ::\n", INTVAL (t));
for (unsigned i = 0; i < insn_info.length (); i++)
dump_insn_slim (dump_file, insn_info[i]->insn);

View File

@ -844,7 +844,8 @@ alpha_linkage_symbol_p (const char *symname)
low-order three bits; this is an "unaligned" access. */
static bool
alpha_legitimate_address_p (machine_mode mode, rtx x, bool strict)
alpha_legitimate_address_p (machine_mode mode, rtx x, bool strict,
code_helper = ERROR_MARK)
{
/* If this is an ldq_u type address, discard the outer AND. */
if (mode == DImode

View File

@ -6715,7 +6715,8 @@ arc_legitimate_constant_p (machine_mode mode, rtx x)
}
static bool
arc_legitimate_address_p (machine_mode mode, rtx x, bool strict)
arc_legitimate_address_p (machine_mode mode, rtx x, bool strict,
code_helper = ERROR_MARK)
{
if (RTX_OK_FOR_BASE_P (x, strict))
return true;
@ -11646,7 +11647,7 @@ arc_split_mov_const (rtx *operands)
}
/* 3. Check if we can just shift by 16 to fit into the u6 of LSL16. */
if (TARGET_BARREL_SHIFTER && TARGET_V2
if (TARGET_SWAP && TARGET_V2
&& ((ival & ~0x3f0000) == 0))
{
shimm = (ival >> 16) & 0x3f;

View File

@ -5991,7 +5991,7 @@ archs4x, archs4xd"
[(set (match_operand:SI 0 "register_operand" "=r")
(ashift:SI (match_operand:SI 1 "nonmemory_operand" "rL")
(const_int 16)))]
"TARGET_BARREL_SHIFTER && TARGET_V2"
"TARGET_SWAP && TARGET_V2"
"lsl16\\t%0,%1"
[(set_attr "type" "shift")
(set_attr "iscompact" "false")

View File

@ -260,8 +260,8 @@ FUNCTION_PRED_P_S_U (vaddvq, VADDVQ)
FUNCTION_PRED_P_S_U (vaddvaq, VADDVAQ)
FUNCTION_WITH_RTX_M (vandq, AND, VANDQ)
FUNCTION_ONLY_N (vbrsrq, VBRSRQ)
FUNCTION (vcaddq_rot90, unspec_mve_function_exact_insn_rot, (UNSPEC_VCADD90, UNSPEC_VCADD90, UNSPEC_VCADD90, VCADDQ_ROT90_M_S, VCADDQ_ROT90_M_U, VCADDQ_ROT90_M_F))
FUNCTION (vcaddq_rot270, unspec_mve_function_exact_insn_rot, (UNSPEC_VCADD270, UNSPEC_VCADD270, UNSPEC_VCADD270, VCADDQ_ROT270_M_S, VCADDQ_ROT270_M_U, VCADDQ_ROT270_M_F))
FUNCTION (vcaddq_rot90, unspec_mve_function_exact_insn_rot, (UNSPEC_VCADD90, UNSPEC_VCADD90, UNSPEC_VCADD90, VCADDQ_ROT90_M, VCADDQ_ROT90_M, VCADDQ_ROT90_M_F))
FUNCTION (vcaddq_rot270, unspec_mve_function_exact_insn_rot, (UNSPEC_VCADD270, UNSPEC_VCADD270, UNSPEC_VCADD270, VCADDQ_ROT270_M, VCADDQ_ROT270_M, VCADDQ_ROT270_M_F))
FUNCTION (vcmlaq, unspec_mve_function_exact_insn_rot, (-1, -1, UNSPEC_VCMLA, -1, -1, VCMLAQ_M_F))
FUNCTION (vcmlaq_rot90, unspec_mve_function_exact_insn_rot, (-1, -1, UNSPEC_VCMLA90, -1, -1, VCMLAQ_ROT90_M_F))
FUNCTION (vcmlaq_rot180, unspec_mve_function_exact_insn_rot, (-1, -1, UNSPEC_VCMLA180, -1, -1, VCMLAQ_ROT180_M_F))
@ -329,6 +329,10 @@ FUNCTION_WITHOUT_N_NO_F (vmovltq, VMOVLTQ)
FUNCTION_WITHOUT_N_NO_F (vmovnbq, VMOVNBQ)
FUNCTION_WITHOUT_N_NO_F (vmovntq, VMOVNTQ)
FUNCTION_WITHOUT_N_NO_F (vmulhq, VMULHQ)
FUNCTION (vmullbq_int, unspec_mve_function_exact_insn_vmull, (VMULLBQ_INT_S, VMULLBQ_INT_U, VMULLBQ_INT_M_S, VMULLBQ_INT_M_U))
FUNCTION (vmulltq_int, unspec_mve_function_exact_insn_vmull, (VMULLTQ_INT_S, VMULLTQ_INT_U, VMULLTQ_INT_M_S, VMULLTQ_INT_M_U))
FUNCTION (vmullbq_poly, unspec_mve_function_exact_insn_vmull_poly, (VMULLBQ_POLY_P, VMULLBQ_POLY_M_P))
FUNCTION (vmulltq_poly, unspec_mve_function_exact_insn_vmull_poly, (VMULLTQ_POLY_P, VMULLTQ_POLY_M_P))
FUNCTION_WITH_RTX_M_N (vmulq, MULT, VMULQ)
FUNCTION_WITH_RTX_M_N_NO_F (vmvnq, NOT, VMVNQ)
FUNCTION (vnegq, unspec_based_mve_function_exact_insn, (NEG, NEG, NEG, -1, -1, -1, VNEGQ_M_S, -1, VNEGQ_M_F, -1, -1, -1))

View File

@ -78,6 +78,10 @@ DEF_MVE_FUNCTION (vmovltq, unary_widen, integer_8_16, mx_or_none)
DEF_MVE_FUNCTION (vmovnbq, binary_move_narrow, integer_16_32, m_or_none)
DEF_MVE_FUNCTION (vmovntq, binary_move_narrow, integer_16_32, m_or_none)
DEF_MVE_FUNCTION (vmulhq, binary, all_integer, mx_or_none)
DEF_MVE_FUNCTION (vmullbq_int, binary_widen, all_integer, mx_or_none)
DEF_MVE_FUNCTION (vmulltq_int, binary_widen, all_integer, mx_or_none)
DEF_MVE_FUNCTION (vmullbq_poly, binary_widen_poly, poly_8_16, mx_or_none)
DEF_MVE_FUNCTION (vmulltq_poly, binary_widen_poly, poly_8_16, mx_or_none)
DEF_MVE_FUNCTION (vmulq, binary_opt_n, all_integer, mx_or_none)
DEF_MVE_FUNCTION (vmvnq, mvn, all_integer, mx_or_none)
DEF_MVE_FUNCTION (vnegq, unary, all_signed, mx_or_none)

View File

@ -102,6 +102,10 @@ extern const function_base *const vmovltq;
extern const function_base *const vmovnbq;
extern const function_base *const vmovntq;
extern const function_base *const vmulhq;
extern const function_base *const vmullbq_int;
extern const function_base *const vmulltq_int;
extern const function_base *const vmullbq_poly;
extern const function_base *const vmulltq_poly;
extern const function_base *const vmulq;
extern const function_base *const vmvnq;
extern const function_base *const vnegq;

View File

@ -838,6 +838,134 @@ public:
}
};
/* Map the vmull-related function directly to CODE (UNSPEC, UNSPEC, M)
where M is the vector mode associated with type suffix 0. We need
this special case because the builtins have _int in their
names. */
class unspec_mve_function_exact_insn_vmull : public function_base
{
public:
CONSTEXPR unspec_mve_function_exact_insn_vmull (int unspec_for_sint,
int unspec_for_uint,
int unspec_for_m_sint,
int unspec_for_m_uint)
: m_unspec_for_sint (unspec_for_sint),
m_unspec_for_uint (unspec_for_uint),
m_unspec_for_m_sint (unspec_for_m_sint),
m_unspec_for_m_uint (unspec_for_m_uint)
{}
/* The unspec code associated with signed-integer and
unsigned-integer operations respectively. It covers the cases
with and without the _m predicate. */
int m_unspec_for_sint;
int m_unspec_for_uint;
int m_unspec_for_m_sint;
int m_unspec_for_m_uint;
rtx
expand (function_expander &e) const override
{
insn_code code;
if (! e.type_suffix (0).integer_p)
gcc_unreachable ();
if (e.mode_suffix_id != MODE_none)
gcc_unreachable ();
switch (e.pred)
{
case PRED_none:
/* No predicate, no suffix. */
if (e.type_suffix (0).unsigned_p)
code = code_for_mve_q_int (m_unspec_for_uint, m_unspec_for_uint, e.vector_mode (0));
else
code = code_for_mve_q_int (m_unspec_for_sint, m_unspec_for_sint, e.vector_mode (0));
return e.use_exact_insn (code);
case PRED_m:
/* No suffix, "m" predicate. */
if (e.type_suffix (0).unsigned_p)
code = code_for_mve_q_int_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
else
code = code_for_mve_q_int_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
return e.use_cond_insn (code, 0);
case PRED_x:
/* No suffix, "x" predicate. */
if (e.type_suffix (0).unsigned_p)
code = code_for_mve_q_int_m (m_unspec_for_m_uint, m_unspec_for_m_uint, e.vector_mode (0));
else
code = code_for_mve_q_int_m (m_unspec_for_m_sint, m_unspec_for_m_sint, e.vector_mode (0));
return e.use_pred_x_insn (code);
default:
gcc_unreachable ();
}
gcc_unreachable ();
}
};
/* Map the vmull_poly-related function directly to CODE (UNSPEC,
UNSPEC, M) where M is the vector mode associated with type suffix
0. We need this special case because the builtins have _poly in
their names, and use the special poly type.. */
class unspec_mve_function_exact_insn_vmull_poly : public function_base
{
public:
CONSTEXPR unspec_mve_function_exact_insn_vmull_poly (int unspec_for_poly,
int unspec_for_m_poly)
: m_unspec_for_poly (unspec_for_poly),
m_unspec_for_m_poly (unspec_for_m_poly)
{}
/* The unspec code associated with signed-integer, unsigned-integer
and poly operations respectively. It covers the cases with and
without the _m predicate. */
int m_unspec_for_poly;
int m_unspec_for_m_poly;
rtx
expand (function_expander &e) const override
{
insn_code code;
if (e.mode_suffix_id != MODE_none)
gcc_unreachable ();
if (! e.type_suffix (0).poly_p)
gcc_unreachable ();
switch (e.pred)
{
case PRED_none:
/* No predicate, no suffix. */
code = code_for_mve_q_poly (m_unspec_for_poly, m_unspec_for_poly, e.vector_mode (0));
return e.use_exact_insn (code);
case PRED_m:
/* No suffix, "m" predicate. */
code = code_for_mve_q_poly_m (m_unspec_for_m_poly, m_unspec_for_m_poly, e.vector_mode (0));
return e.use_cond_insn (code, 0);
case PRED_x:
/* No suffix, "x" predicate. */
code = code_for_mve_q_poly_m (m_unspec_for_m_poly, m_unspec_for_m_poly, e.vector_mode (0));
return e.use_pred_x_insn (code);
default:
gcc_unreachable ();
}
gcc_unreachable ();
}
};
} /* end namespace arm_mve */
/* Declare the global function base NAME, creating it from an instance

View File

@ -61,10 +61,12 @@ apply_predication (const function_instance &instance, tree return_type,
[01] - the element type in type suffix 0 or 1 of INSTANCE.
h<elt> - a half-sized version of <elt>
p<elt> - a poly type with the same width as <elt>
s<bits> - a signed type with the given number of bits
s[01] - a signed type with the same width as type suffix 0 or 1
u<bits> - an unsigned type with the given number of bits
u[01] - an unsigned type with the same width as type suffix 0 or 1
U<elt> - an unsigned type with the double width as <elt>
w<elt> - a double-sized version of <elt>
x<bits> - a type with the given number of bits and same signedness
as the next argument.
@ -78,8 +80,7 @@ parse_element_type (const function_instance &instance, const char *&format)
if (ch == 's' || ch == 'u')
{
type_class_index tclass = (ch == 'f' ? TYPE_float
: ch == 's' ? TYPE_signed
type_class_index tclass = (ch == 's' ? TYPE_signed
: TYPE_unsigned);
char *end;
unsigned int bits = strtol (format, &end, 10);
@ -103,6 +104,20 @@ parse_element_type (const function_instance &instance, const char *&format)
type_suffixes[suffix].element_bits * 2);
}
if (ch == 'U')
{
type_suffix_index suffix = parse_element_type (instance, format);
return find_type_suffix (TYPE_unsigned,
type_suffixes[suffix].element_bits * 2);
}
if (ch == 'p')
{
type_suffix_index suffix = parse_element_type (instance, format);
return find_type_suffix (TYPE_poly,
type_suffixes[suffix].element_bits);
}
if (ch == 'x')
{
const char *next = format;
@ -439,7 +454,7 @@ struct binary_acca_int32_def : public overloaded_base<0>
|| (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES)
return error_mark_node;
unsigned int last_arg = i;
unsigned int last_arg = i + 1;
for (i = 1; i < last_arg; i++)
if (!r.require_matching_vector_type (i, type))
return error_mark_node;
@ -476,7 +491,7 @@ struct binary_acca_int64_def : public overloaded_base<0>
|| (type = r.infer_vector_type (1)) == NUM_TYPE_SUFFIXES)
return error_mark_node;
unsigned int last_arg = i;
unsigned int last_arg = i + 1;
for (i = 1; i < last_arg; i++)
if (!r.require_matching_vector_type (i, type))
return error_mark_node;
@ -1130,6 +1145,97 @@ struct binary_rshift_narrow_unsigned_def : public overloaded_base<0>
};
SHAPE (binary_rshift_narrow_unsigned)
/* <T0:twice>_t vfoo[_t0](<T0>_t, <T0>_t)
Example: vmullbq.
int32x4_t [__arm_]vmullbq_int[_s16](int16x8_t a, int16x8_t b)
int32x4_t [__arm_]vmullbq_int_m[_s16](int32x4_t inactive, int16x8_t a, int16x8_t b, mve_pred16_t p)
int32x4_t [__arm_]vmullbq_int_x[_s16](int16x8_t a, int16x8_t b, mve_pred16_t p) */
struct binary_widen_def : public overloaded_base<0>
{
void
build (function_builder &b, const function_group_info &group,
bool preserve_user_namespace) const override
{
b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
build_all (b, "vw0,v0,v0", group, MODE_none, preserve_user_namespace);
}
tree
resolve (function_resolver &r) const override
{
unsigned int i, nargs;
type_suffix_index type;
if (!r.check_gp_argument (2, i, nargs)
|| (type = r.infer_vector_type (i - 1)) == NUM_TYPE_SUFFIXES)
return error_mark_node;
type_suffix_index wide_suffix
= find_type_suffix (type_suffixes[type].tclass,
type_suffixes[type].element_bits * 2);
if (!r.require_matching_vector_type (i, type))
return error_mark_node;
/* Check the inactive argument has the wide type. */
if ((r.pred == PRED_m)
&& (r.infer_vector_type (0) != wide_suffix))
return r.report_no_such_form (type);
return r.resolve_to (r.mode_suffix_id, type);
}
};
SHAPE (binary_widen)
/* <T0:twice>_t vfoo[_t0](<T0>_t, <T0>_t)
Example: vmullbq_poly.
uint32x4_t [__arm_]vmullbq_poly[_p16](uint16x8_t a, uint16x8_t b)
uint32x4_t [__arm_]vmullbq_poly_m[_p16](uint32x4_t inactive, uint16x8_t a, uint16x8_t b, mve_pred16_t p)
uint32x4_t [__arm_]vmullbq_poly_x[_p16](uint16x8_t a, uint16x8_t b, mve_pred16_t p) */
struct binary_widen_poly_def : public overloaded_base<0>
{
void
build (function_builder &b, const function_group_info &group,
bool preserve_user_namespace) const override
{
b.add_overloaded_functions (group, MODE_none, preserve_user_namespace);
build_all (b, "vU0,vp0,vp0", group, MODE_none, preserve_user_namespace);
}
tree
resolve (function_resolver &r) const override
{
unsigned int i, nargs;
type_suffix_index type;
if (!r.check_gp_argument (2, i, nargs)
|| (type = r.infer_vector_type (i - 1)) == NUM_TYPE_SUFFIXES)
return error_mark_node;
/* infer_vector_type found the 'unsigned' version of the 'poly'
type we are looking for, so find the 'poly' type with the same
width. */
type = find_type_suffix (TYPE_poly, type_suffixes[type].element_bits);
type_suffix_index wide_suffix
= find_type_suffix (TYPE_unsigned,
type_suffixes[type].element_bits * 2);
/* Require the 'poly' type, require_matching_vector_type would try
and fail with the 'unsigned' one. */
if (!r.require_vector_type (i, type_suffixes[type].vector_type))
return error_mark_node;
/* Check the inactive argument has the wide type. */
if ((r.pred == PRED_m)
&& (r.infer_vector_type (0) != wide_suffix))
return r.report_no_such_form (type);
return r.resolve_to (r.mode_suffix_id, type);
}
};
SHAPE (binary_widen_poly)
/* <T0:twice>_t vfoo[_n_t0](<T0>_t, const int)
Check that 'imm' is in the [1..#bits] range.

View File

@ -35,13 +35,13 @@ namespace arm_mve
{
extern const function_shape *const binary;
extern const function_shape *const binary_lshift;
extern const function_shape *const binary_lshift_r;
extern const function_shape *const binary_acc_int32;
extern const function_shape *const binary_acc_int64;
extern const function_shape *const binary_acca_int32;
extern const function_shape *const binary_acca_int64;
extern const function_shape *const binary_imm32;
extern const function_shape *const binary_lshift;
extern const function_shape *const binary_lshift_r;
extern const function_shape *const binary_lshift_unsigned;
extern const function_shape *const binary_maxamina;
extern const function_shape *const binary_maxavminav;
@ -54,8 +54,10 @@ namespace arm_mve
extern const function_shape *const binary_rshift;
extern const function_shape *const binary_rshift_narrow;
extern const function_shape *const binary_rshift_narrow_unsigned;
extern const function_shape *const binary_widen;
extern const function_shape *const binary_widen_n;
extern const function_shape *const binary_widen_opt_n;
extern const function_shape *const binary_widen_poly;
extern const function_shape *const cmp;
extern const function_shape *const create;
extern const function_shape *const inherent;

View File

@ -128,10 +128,11 @@ CONSTEXPR const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = {
TYPE_##CLASS == TYPE_signed || TYPE_##CLASS == TYPE_unsigned, \
TYPE_##CLASS == TYPE_unsigned, \
TYPE_##CLASS == TYPE_float, \
TYPE_##CLASS == TYPE_poly, \
0, \
MODE },
#include "arm-mve-builtins.def"
{ "", NUM_VECTOR_TYPES, TYPE_bool, 0, 0, false, false, false,
{ "", NUM_VECTOR_TYPES, TYPE_bool, 0, 0, false, false, false, false,
0, VOIDmode }
};
@ -177,6 +178,10 @@ CONSTEXPR const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = {
#define TYPES_all_signed(S, D) \
S (s8), S (s16), S (s32)
/* _p8 _p16. */
#define TYPES_poly_8_16(S, D) \
S (p8), S (p16)
/* _u8 _u16 _u32. */
#define TYPES_all_unsigned(S, D) \
S (u8), S (u16), S (u32)
@ -275,6 +280,7 @@ DEF_MVE_TYPES_ARRAY (integer_8);
DEF_MVE_TYPES_ARRAY (integer_8_16);
DEF_MVE_TYPES_ARRAY (integer_16_32);
DEF_MVE_TYPES_ARRAY (integer_32);
DEF_MVE_TYPES_ARRAY (poly_8_16);
DEF_MVE_TYPES_ARRAY (signed_16_32);
DEF_MVE_TYPES_ARRAY (signed_32);
DEF_MVE_TYPES_ARRAY (reinterpret_integer);

View File

@ -63,6 +63,8 @@ DEF_MVE_TYPE_SUFFIX (u8, uint8x16_t, unsigned, 8, V16QImode)
DEF_MVE_TYPE_SUFFIX (u16, uint16x8_t, unsigned, 16, V8HImode)
DEF_MVE_TYPE_SUFFIX (u32, uint32x4_t, unsigned, 32, V4SImode)
DEF_MVE_TYPE_SUFFIX (u64, uint64x2_t, unsigned, 64, V2DImode)
DEF_MVE_TYPE_SUFFIX (p8, uint8x16_t, poly, 8, V16QImode)
DEF_MVE_TYPE_SUFFIX (p16, uint16x8_t, poly, 16, V8HImode)
#undef REQUIRES_FLOAT
#define REQUIRES_FLOAT true

View File

@ -146,6 +146,7 @@ enum type_class_index
TYPE_float,
TYPE_signed,
TYPE_unsigned,
TYPE_poly,
NUM_TYPE_CLASSES
};
@ -221,7 +222,9 @@ struct type_suffix_info
unsigned int unsigned_p : 1;
/* True if the suffix is for a floating-point type. */
unsigned int float_p : 1;
unsigned int spare : 13;
/* True if the suffix is for a polynomial type. */
unsigned int poly_p : 1;
unsigned int spare : 12;
/* The associated vector or predicate mode. */
machine_mode vector_mode : 16;

View File

@ -23,6 +23,7 @@
#define GCC_ARM_PROTOS_H
#include "sbitmap.h"
#include "tree.h" /* For ERROR_MARK. */
rtl_opt_pass *make_pass_insert_bti (gcc::context *ctxt);
@ -83,7 +84,8 @@ extern int arm_split_constant (RTX_CODE, machine_mode, rtx,
extern int legitimate_pic_operand_p (rtx);
extern rtx legitimize_pic_address (rtx, machine_mode, rtx, rtx, bool);
extern rtx legitimize_tls_address (rtx, rtx);
extern bool arm_legitimate_address_p (machine_mode, rtx, bool);
extern bool arm_legitimate_address_p (machine_mode, rtx, bool,
code_helper = ERROR_MARK);
extern int arm_legitimate_address_outer_p (machine_mode, rtx, RTX_CODE, int);
extern int thumb_legitimate_offset_p (machine_mode, HOST_WIDE_INT);
extern int thumb1_legitimate_address_p (machine_mode, rtx, int);

View File

@ -9171,7 +9171,7 @@ thumb_legitimate_offset_p (machine_mode mode, HOST_WIDE_INT val)
}
bool
arm_legitimate_address_p (machine_mode mode, rtx x, bool strict_p)
arm_legitimate_address_p (machine_mode mode, rtx x, bool strict_p, code_helper)
{
if (TARGET_ARM)
return arm_legitimate_address_outer_p (mode, x, SET, strict_p);

File diff suppressed because it is too large Load Diff

View File

@ -523,8 +523,8 @@ VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vhsubq_m_n_u, v16qi, v8hi, v4si)
VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vhaddq_m_u, v16qi, v8hi, v4si)
VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vhaddq_m_n_u, v16qi, v8hi, v4si)
VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, veorq_m_u, v16qi, v8hi, v4si)
VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vcaddq_rot90_m_u, v16qi, v8hi, v4si)
VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vcaddq_rot270_m_u, v16qi, v8hi, v4si)
VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vcaddq_rot90_m_, v16qi, v8hi, v4si)
VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vcaddq_rot270_m_, v16qi, v8hi, v4si)
VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vbicq_m_u, v16qi, v8hi, v4si)
VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vandq_m_u, v16qi, v8hi, v4si)
VAR3 (QUADOP_UNONE_UNONE_UNONE_UNONE_PRED, vaddq_m_u, v16qi, v8hi, v4si)
@ -587,8 +587,6 @@ VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vhcaddq_rot270_m_s, v16qi, v8hi, v4si)
VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vhaddq_m_s, v16qi, v8hi, v4si)
VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vhaddq_m_n_s, v16qi, v8hi, v4si)
VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, veorq_m_s, v16qi, v8hi, v4si)
VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vcaddq_rot90_m_s, v16qi, v8hi, v4si)
VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vcaddq_rot270_m_s, v16qi, v8hi, v4si)
VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vbrsrq_m_n_s, v16qi, v8hi, v4si)
VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vbicq_m_s, v16qi, v8hi, v4si)
VAR3 (QUADOP_NONE_NONE_NONE_NONE_PRED, vandq_m_s, v16qi, v8hi, v4si)

View File

@ -917,6 +917,7 @@
(define_int_attr mve_insn [
(UNSPEC_VCADD90 "vcadd") (UNSPEC_VCADD270 "vcadd")
(UNSPEC_VCMLA "vcmla") (UNSPEC_VCMLA90 "vcmla") (UNSPEC_VCMLA180 "vcmla") (UNSPEC_VCMLA270 "vcmla")
(UNSPEC_VCMUL "vcmul") (UNSPEC_VCMUL90 "vcmul") (UNSPEC_VCMUL180 "vcmul") (UNSPEC_VCMUL270 "vcmul")
(VABAVQ_P_S "vabav") (VABAVQ_P_U "vabav")
(VABAVQ_S "vabav") (VABAVQ_U "vabav")
@ -941,8 +942,8 @@
(VBICQ_N_S "vbic") (VBICQ_N_U "vbic")
(VBRSRQ_M_N_S "vbrsr") (VBRSRQ_M_N_U "vbrsr") (VBRSRQ_M_N_F "vbrsr")
(VBRSRQ_N_S "vbrsr") (VBRSRQ_N_U "vbrsr") (VBRSRQ_N_F "vbrsr")
(VCADDQ_ROT270_M_U "vcadd") (VCADDQ_ROT270_M_S "vcadd") (VCADDQ_ROT270_M_F "vcadd")
(VCADDQ_ROT90_M_U "vcadd") (VCADDQ_ROT90_M_S "vcadd") (VCADDQ_ROT90_M_F "vcadd")
(VCADDQ_ROT270_M "vcadd") (VCADDQ_ROT270_M_F "vcadd")
(VCADDQ_ROT90_M "vcadd") (VCADDQ_ROT90_M_F "vcadd")
(VCLSQ_M_S "vcls")
(VCLSQ_S "vcls")
(VCLZQ_M_S "vclz") (VCLZQ_M_U "vclz")
@ -1044,6 +1045,13 @@
(VMOVNTQ_S "vmovnt") (VMOVNTQ_U "vmovnt")
(VMULHQ_M_S "vmulh") (VMULHQ_M_U "vmulh")
(VMULHQ_S "vmulh") (VMULHQ_U "vmulh")
(VMULLBQ_INT_M_S "vmullb") (VMULLBQ_INT_M_U "vmullb")
(VMULLBQ_INT_S "vmullb") (VMULLBQ_INT_U "vmullb")
(VMULLBQ_POLY_M_P "vmullb") (VMULLTQ_POLY_M_P "vmullt")
(VMULLBQ_POLY_P "vmullb")
(VMULLTQ_INT_M_S "vmullt") (VMULLTQ_INT_M_U "vmullt")
(VMULLTQ_INT_S "vmullt") (VMULLTQ_INT_U "vmullt")
(VMULLTQ_POLY_P "vmullt")
(VMULQ_M_N_S "vmul") (VMULQ_M_N_U "vmul") (VMULQ_M_N_F "vmul")
(VMULQ_M_S "vmul") (VMULQ_M_U "vmul") (VMULQ_M_F "vmul")
(VMULQ_N_S "vmul") (VMULQ_N_U "vmul") (VMULQ_N_F "vmul")
@ -1209,14 +1217,13 @@
(VSUBQ_M_N_S "vsub") (VSUBQ_M_N_U "vsub") (VSUBQ_M_N_F "vsub")
(VSUBQ_M_S "vsub") (VSUBQ_M_U "vsub") (VSUBQ_M_F "vsub")
(VSUBQ_N_S "vsub") (VSUBQ_N_U "vsub") (VSUBQ_N_F "vsub")
(UNSPEC_VCMLA "vcmla") (UNSPEC_VCMLA90 "vcmla") (UNSPEC_VCMLA180 "vcmla") (UNSPEC_VCMLA270 "vcmla")
])
(define_int_attr isu [
(UNSPEC_VCADD90 "i") (UNSPEC_VCADD270 "i")
(VABSQ_M_S "s")
(VCADDQ_ROT270_M_U "i") (VCADDQ_ROT270_M_S "i")
(VCADDQ_ROT90_M_U "i") (VCADDQ_ROT90_M_S "i")
(VCADDQ_ROT270_M "i")
(VCADDQ_ROT90_M "i")
(VCLSQ_M_S "s")
(VCLZQ_M_S "i")
(VCLZQ_M_U "i")
@ -1246,6 +1253,8 @@
(VMOVNBQ_S "i") (VMOVNBQ_U "i")
(VMOVNTQ_M_S "i") (VMOVNTQ_M_U "i")
(VMOVNTQ_S "i") (VMOVNTQ_U "i")
(VMULLBQ_INT_S "s") (VMULLBQ_INT_U "u")
(VMULLTQ_INT_S "s") (VMULLTQ_INT_U "u")
(VNEGQ_M_S "s")
(VQABSQ_M_S "s")
(VQMOVNBQ_M_S "s") (VQMOVNBQ_M_U "u")
@ -2184,11 +2193,9 @@
(define_int_attr rot [(UNSPEC_VCADD90 "90")
(UNSPEC_VCADD270 "270")
(VCADDQ_ROT90_M_F "90")
(VCADDQ_ROT90_M_S "90")
(VCADDQ_ROT90_M_U "90")
(VCADDQ_ROT90_M "90")
(VCADDQ_ROT270_M_F "270")
(VCADDQ_ROT270_M_S "270")
(VCADDQ_ROT270_M_U "270")
(VCADDQ_ROT270_M "270")
(VHCADDQ_ROT90_S "90")
(VHCADDQ_ROT270_S "270")
(VHCADDQ_ROT90_M_S "90")
@ -2241,11 +2248,9 @@
(define_int_attr mve_rot [(UNSPEC_VCADD90 "_rot90")
(UNSPEC_VCADD270 "_rot270")
(VCADDQ_ROT90_M_F "_rot90")
(VCADDQ_ROT90_M_S "_rot90")
(VCADDQ_ROT90_M_U "_rot90")
(VCADDQ_ROT90_M "_rot90")
(VCADDQ_ROT270_M_F "_rot270")
(VCADDQ_ROT270_M_S "_rot270")
(VCADDQ_ROT270_M_U "_rot270")
(VCADDQ_ROT270_M "_rot270")
(VHCADDQ_ROT90_S "_rot90")
(VHCADDQ_ROT270_S "_rot270")
(VHCADDQ_ROT90_M_S "_rot90")
@ -2330,6 +2335,10 @@
(VMLADAVQ_U "u") (VMULHQ_S "s") (VMULHQ_U "u")
(VMULLBQ_INT_S "s") (VMULLBQ_INT_U "u") (VQADDQ_S "s")
(VMULLTQ_INT_S "s") (VMULLTQ_INT_U "u") (VQADDQ_U "u")
(VMULLBQ_POLY_P "p")
(VMULLTQ_POLY_P "p")
(VMULLBQ_POLY_M_P "p")
(VMULLTQ_POLY_M_P "p")
(VMULQ_N_S "s") (VMULQ_N_U "u") (VMULQ_S "s")
(VMULQ_U "u")
(VQADDQ_N_S "s") (VQADDQ_N_U "u")
@ -2403,7 +2412,7 @@
(VCVTQ_M_N_TO_F_U "u") (VADDQ_M_N_U "u")
(VSHLQ_M_N_S "s") (VMAXQ_M_U "u") (VHSUBQ_M_N_U "u")
(VMULQ_M_N_S "s") (VQSHLQ_M_U "u") (VRHADDQ_M_S "s")
(VEORQ_M_U "u") (VSHRQ_M_N_U "u") (VCADDQ_ROT90_M_U "u")
(VEORQ_M_U "u") (VSHRQ_M_N_U "u")
(VMLADAVAQ_P_U "u") (VEORQ_M_S "s") (VBRSRQ_M_N_S "s")
(VMULQ_M_U "u") (VQRDMLAHQ_M_N_S "s") (VHSUBQ_M_N_S "s")
(VQRSHLQ_M_S "s") (VMULQ_M_N_U "u")
@ -2412,17 +2421,17 @@
(VMULLBQ_INT_M_U "u") (VSHLQ_M_N_U "u") (VQSUBQ_M_U "u")
(VQDMLASHQ_M_N_S "s")
(VQRDMLASHQ_M_N_U "u") (VRSHRQ_M_N_S "s")
(VORNQ_M_S "s") (VCADDQ_ROT270_M_S "s") (VRHADDQ_M_U "u")
(VORNQ_M_S "s") (VCADDQ_ROT270_M "") (VRHADDQ_M_U "u")
(VRSHRQ_M_N_U "u") (VMLASQ_M_N_U "u") (VHSUBQ_M_U "u")
(VQSUBQ_M_N_S "s") (VMULLTQ_INT_M_S "s")
(VORRQ_M_S "s") (VQDMLAHQ_M_N_U "u") (VRSHLQ_M_S "s")
(VHADDQ_M_U "u") (VHADDQ_M_N_S "s") (VMULLTQ_INT_M_U "u")
(VORRQ_M_U "u") (VHADDQ_M_S "s") (VHADDQ_M_N_U "u")
(VQDMLAHQ_M_N_S "s") (VMAXQ_M_S "s") (VORNQ_M_U "u")
(VCADDQ_ROT270_M_U "u") (VQADDQ_M_U "u")
(VQADDQ_M_U "u")
(VQRDMLASHQ_M_N_S "s") (VBICQ_M_U "u") (VMINQ_M_U "u")
(VSUBQ_M_N_S "s") (VMULLBQ_INT_M_S "s") (VQSUBQ_M_S "s")
(VCADDQ_ROT90_M_S "s") (VRMULHQ_M_S "s") (VANDQ_M_U "u")
(VCADDQ_ROT90_M "") (VRMULHQ_M_S "s") (VANDQ_M_U "u")
(VMULHQ_M_S "s") (VADDQ_M_S "s") (VQRDMLAHQ_M_N_U "u")
(VMLASQ_M_N_S "s") (VHSUBQ_M_S "s") (VRMULHQ_M_U "u")
(VQADDQ_M_N_S "s") (VSHRQ_M_N_S "s") (VANDQ_M_S "s")
@ -2713,8 +2722,8 @@
(define_int_iterator VMINVQ [VMINVQ_U VMINVQ_S])
(define_int_iterator VMLADAVQ [VMLADAVQ_U VMLADAVQ_S])
(define_int_iterator VMULHQ [VMULHQ_S VMULHQ_U])
(define_int_iterator VMULLBQ_INT [VMULLBQ_INT_U VMULLBQ_INT_S])
(define_int_iterator VMULLTQ_INT [VMULLTQ_INT_U VMULLTQ_INT_S])
(define_int_iterator VMULLxQ_INT [VMULLBQ_INT_U VMULLBQ_INT_S VMULLTQ_INT_U VMULLTQ_INT_S])
(define_int_iterator VMULLxQ_POLY [VMULLBQ_POLY_P VMULLTQ_POLY_P])
(define_int_iterator VMULQ [VMULQ_U VMULQ_S])
(define_int_iterator VMULQ_N [VMULQ_N_U VMULQ_N_S])
(define_int_iterator VQADDQ [VQADDQ_U VQADDQ_S])
@ -2815,7 +2824,8 @@
(define_int_iterator VSLIQ_M_N [VSLIQ_M_N_U VSLIQ_M_N_S])
(define_int_iterator VRSHLQ_M [VRSHLQ_M_S VRSHLQ_M_U])
(define_int_iterator VMINQ_M [VMINQ_M_S VMINQ_M_U])
(define_int_iterator VMULLBQ_INT_M [VMULLBQ_INT_M_U VMULLBQ_INT_M_S])
(define_int_iterator VMULLxQ_INT_M [VMULLBQ_INT_M_U VMULLBQ_INT_M_S VMULLTQ_INT_M_U VMULLTQ_INT_M_S])
(define_int_iterator VMULLxQ_POLY_M [VMULLBQ_POLY_M_P VMULLTQ_POLY_M_P])
(define_int_iterator VMULHQ_M [VMULHQ_M_S VMULHQ_M_U])
(define_int_iterator VMULQ_M [VMULQ_M_S VMULQ_M_U])
(define_int_iterator VHSUBQ_M_N [VHSUBQ_M_N_S VHSUBQ_M_N_U])
@ -2834,7 +2844,7 @@
(define_int_iterator VSHLQ_M_N [VSHLQ_M_N_S VSHLQ_M_N_U])
(define_int_iterator VCADDQ_M_F [VCADDQ_ROT90_M_F VCADDQ_ROT270_M_F])
(define_int_iterator VxCADDQ [UNSPEC_VCADD90 UNSPEC_VCADD270 VHCADDQ_ROT90_S VHCADDQ_ROT270_S])
(define_int_iterator VxCADDQ_M [VHCADDQ_ROT90_M_S VHCADDQ_ROT270_M_S VCADDQ_ROT90_M_U VCADDQ_ROT90_M_S VCADDQ_ROT270_M_U VCADDQ_ROT270_M_S])
(define_int_iterator VxCADDQ_M [VHCADDQ_ROT90_M_S VHCADDQ_ROT270_M_S VCADDQ_ROT90_M VCADDQ_ROT270_M])
(define_int_iterator VQRSHLQ_M [VQRSHLQ_M_U VQRSHLQ_M_S])
(define_int_iterator VQADDQ_M_N [VQADDQ_M_N_U VQADDQ_M_N_S])
(define_int_iterator VADDQ_M_N [VADDQ_M_N_S VADDQ_M_N_U])
@ -2844,7 +2854,6 @@
(define_int_iterator VMLADAVAQ_P [VMLADAVAQ_P_U VMLADAVAQ_P_S])
(define_int_iterator VBRSRQ_M_N [VBRSRQ_M_N_U VBRSRQ_M_N_S])
(define_int_iterator VMULQ_M_N [VMULQ_M_N_U VMULQ_M_N_S])
(define_int_iterator VMULLTQ_INT_M [VMULLTQ_INT_M_S VMULLTQ_INT_M_U])
(define_int_iterator VEORQ_M [VEORQ_M_S VEORQ_M_U])
(define_int_iterator VSHRQ_M_N [VSHRQ_M_N_S VSHRQ_M_N_U])
(define_int_iterator VSUBQ_M_N [VSUBQ_M_N_S VSUBQ_M_N_U])

View File

@ -839,8 +839,8 @@
])
;;
;; [vcaddq_rot90_s, vcadd_rot90_u]
;; [vcaddq_rot270_s, vcadd_rot270_u]
;; [vcaddq_rot90_s, vcaddq_rot90_u]
;; [vcaddq_rot270_s, vcaddq_rot270_u]
;; [vhcaddq_rot90_s]
;; [vhcaddq_rot270_s]
;;
@ -976,32 +976,18 @@
])
;;
;; [vmullbq_int_u, vmullbq_int_s])
;; [vmullbq_int_u, vmullbq_int_s]
;; [vmulltq_int_u, vmulltq_int_s]
;;
(define_insn "mve_vmullbq_int_<supf><mode>"
(define_insn "@mve_<mve_insn>q_int_<supf><mode>"
[
(set (match_operand:<V_double_width> 0 "s_register_operand" "<earlyclobber_32>")
(unspec:<V_double_width> [(match_operand:MVE_2 1 "s_register_operand" "w")
(match_operand:MVE_2 2 "s_register_operand" "w")]
VMULLBQ_INT))
VMULLxQ_INT))
]
"TARGET_HAVE_MVE"
"vmullb.<supf>%#<V_sz_elem>\t%q0, %q1, %q2"
[(set_attr "type" "mve_move")
])
;;
;; [vmulltq_int_u, vmulltq_int_s])
;;
(define_insn "mve_vmulltq_int_<supf><mode>"
[
(set (match_operand:<V_double_width> 0 "s_register_operand" "<earlyclobber_32>")
(unspec:<V_double_width> [(match_operand:MVE_2 1 "s_register_operand" "w")
(match_operand:MVE_2 2 "s_register_operand" "w")]
VMULLTQ_INT))
]
"TARGET_HAVE_MVE"
"vmullt.<supf>%#<V_sz_elem>\t%q0, %q1, %q2"
"<mve_insn>.<isu>%#<V_sz_elem>\t%q0, %q1, %q2"
[(set_attr "type" "mve_move")
])
@ -1528,32 +1514,18 @@
])
;;
;; [vmulltq_poly_p])
;; [vmulltq_poly_p]
;; [vmullbq_poly_p]
;;
(define_insn "mve_vmulltq_poly_p<mode>"
(define_insn "@mve_<mve_insn>q_poly_<supf><mode>"
[
(set (match_operand:<V_double_width> 0 "s_register_operand" "=w")
(unspec:<V_double_width> [(match_operand:MVE_3 1 "s_register_operand" "w")
(match_operand:MVE_3 2 "s_register_operand" "w")]
VMULLTQ_POLY_P))
VMULLxQ_POLY))
]
"TARGET_HAVE_MVE"
"vmullt.p%#<V_sz_elem>\t%q0, %q1, %q2"
[(set_attr "type" "mve_move")
])
;;
;; [vmullbq_poly_p])
;;
(define_insn "mve_vmullbq_poly_p<mode>"
[
(set (match_operand:<V_double_width> 0 "s_register_operand" "=w")
(unspec:<V_double_width> [(match_operand:MVE_3 1 "s_register_operand" "w")
(match_operand:MVE_3 2 "s_register_operand" "w")]
VMULLBQ_POLY_P))
]
"TARGET_HAVE_MVE"
"vmullb.p%#<V_sz_elem>\t%q0, %q1, %q2"
"<mve_insn>.<supf>%#<V_sz_elem>\t%q0, %q1, %q2"
[(set_attr "type" "mve_move")
])
@ -2816,36 +2788,20 @@
(set_attr "length""8")])
;;
;; [vmullbq_int_m_u, vmullbq_int_m_s])
;; [vmullbq_int_m_u, vmullbq_int_m_s]
;; [vmulltq_int_m_s, vmulltq_int_m_u]
;;
(define_insn "mve_vmullbq_int_m_<supf><mode>"
(define_insn "@mve_<mve_insn>q_int_m_<supf><mode>"
[
(set (match_operand:<V_double_width> 0 "s_register_operand" "<earlyclobber_32>")
(unspec:<V_double_width> [(match_operand:<V_double_width> 1 "s_register_operand" "0")
(match_operand:MVE_2 2 "s_register_operand" "w")
(match_operand:MVE_2 3 "s_register_operand" "w")
(match_operand:<MVE_VPRED> 4 "vpr_register_operand" "Up")]
VMULLBQ_INT_M))
VMULLxQ_INT_M))
]
"TARGET_HAVE_MVE"
"vpst\;vmullbt.<supf>%#<V_sz_elem> %q0, %q2, %q3"
[(set_attr "type" "mve_move")
(set_attr "length""8")])
;;
;; [vmulltq_int_m_s, vmulltq_int_m_u])
;;
(define_insn "mve_vmulltq_int_m_<supf><mode>"
[
(set (match_operand:<V_double_width> 0 "s_register_operand" "<earlyclobber_32>")
(unspec:<V_double_width> [(match_operand:<V_double_width> 1 "s_register_operand" "0")
(match_operand:MVE_2 2 "s_register_operand" "w")
(match_operand:MVE_2 3 "s_register_operand" "w")
(match_operand:<MVE_VPRED> 4 "vpr_register_operand" "Up")]
VMULLTQ_INT_M))
]
"TARGET_HAVE_MVE"
"vpst\;vmulltt.<supf>%#<V_sz_elem> %q0, %q2, %q3"
"vpst\;<mve_insn>t.<supf>%#<V_sz_elem>\t%q0, %q2, %q3"
[(set_attr "type" "mve_move")
(set_attr "length""8")])
@ -3006,36 +2962,20 @@
(set_attr "length""8")])
;;
;; [vmullbq_poly_m_p])
;; [vmullbq_poly_m_p]
;; [vmulltq_poly_m_p]
;;
(define_insn "mve_vmullbq_poly_m_p<mode>"
(define_insn "@mve_<mve_insn>q_poly_m_<supf><mode>"
[
(set (match_operand:<V_double_width> 0 "s_register_operand" "=w")
(unspec:<V_double_width> [(match_operand:<V_double_width> 1 "s_register_operand" "0")
(match_operand:MVE_3 2 "s_register_operand" "w")
(match_operand:MVE_3 3 "s_register_operand" "w")
(match_operand:<MVE_VPRED> 4 "vpr_register_operand" "Up")]
VMULLBQ_POLY_M_P))
VMULLxQ_POLY_M))
]
"TARGET_HAVE_MVE"
"vpst\;vmullbt.p%#<V_sz_elem>\t%q0, %q2, %q3"
[(set_attr "type" "mve_move")
(set_attr "length""8")])
;;
;; [vmulltq_poly_m_p])
;;
(define_insn "mve_vmulltq_poly_m_p<mode>"
[
(set (match_operand:<V_double_width> 0 "s_register_operand" "=w")
(unspec:<V_double_width> [(match_operand:<V_double_width> 1 "s_register_operand" "0")
(match_operand:MVE_3 2 "s_register_operand" "w")
(match_operand:MVE_3 3 "s_register_operand" "w")
(match_operand:<MVE_VPRED> 4 "vpr_register_operand" "Up")]
VMULLTQ_POLY_M_P))
]
"TARGET_HAVE_MVE"
"vpst\;vmulltt.p%#<V_sz_elem>\t%q0, %q2, %q3"
"vpst\;<mve_insn>t.<supf>%#<V_sz_elem>\t%q0, %q2, %q3"
[(set_attr "type" "mve_move")
(set_attr "length""8")])

View File

@ -995,8 +995,7 @@
VMAXQ_M_U
VQRDMLAHQ_M_N_U
VCADDQ_ROT270_M_F
VCADDQ_ROT270_M_U
VCADDQ_ROT270_M_S
VCADDQ_ROT270_M
VQRSHLQ_M_S
VMULQ_M_F
VRHADDQ_M_U
@ -1050,8 +1049,7 @@
VSLIQ_M_N_S
VQSHLQ_M_U
VQSHLQ_M_S
VCADDQ_ROT90_M_U
VCADDQ_ROT90_M_S
VCADDQ_ROT90_M
VORNQ_M_U
VORNQ_M_S
VQSHLQ_M_N_S

View File

@ -13433,8 +13433,8 @@ avr_reg_ok_for_pgm_addr (rtx reg, bool strict)
/* Implement `TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P'. */
static bool
avr_addr_space_legitimate_address_p (machine_mode mode, rtx x,
bool strict, addr_space_t as)
avr_addr_space_legitimate_address_p (machine_mode mode, rtx x, bool strict,
addr_space_t as, code_helper = ERROR_MARK)
{
bool ok = false;

View File

@ -2718,7 +2718,8 @@ bfin_valid_reg_p (unsigned int regno, int strict, machine_mode mode,
*/
static bool
bfin_legitimate_address_p (machine_mode mode, rtx x, bool strict)
bfin_legitimate_address_p (machine_mode mode, rtx x, bool strict,
code_helper = ERROR_MARK)
{
switch (GET_CODE (x)) {
case REG:

View File

@ -76,10 +76,6 @@ struct GTY(()) machine_function
{
/* Number of bytes saved on the stack for local variables. */
int local_vars_size;
/* Number of bytes saved on the stack for callee-saved
registers. */
int callee_saved_reg_size;
};
/* Handle an attribute requiring a FUNCTION_DECL;
@ -158,6 +154,10 @@ static const struct attribute_spec bpf_attribute_table[] =
{ "preserve_access_index", 0, -1, false, true, false, true,
bpf_handle_preserve_access_index_attribute, NULL },
/* Support for `naked' function attribute. */
{ "naked", 0, 1, false, false, false, false,
bpf_handle_fndecl_attribute, NULL },
/* The last attribute spec is set to be NULL. */
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
};
@ -339,6 +339,21 @@ bpf_function_value_regno_p (const unsigned int regno)
#undef TARGET_FUNCTION_VALUE_REGNO_P
#define TARGET_FUNCTION_VALUE_REGNO_P bpf_function_value_regno_p
/* Determine whether to warn about lack of return statement in a
function. */
static bool
bpf_warn_func_return (tree decl)
{
/* Naked functions are implemented entirely in assembly, including
the return instructions. */
return lookup_attribute ("naked", DECL_ATTRIBUTES (decl)) == NULL_TREE;
}
#undef TARGET_WARN_FUNC_RETURN
#define TARGET_WARN_FUNC_RETURN bpf_warn_func_return
/* Compute the size of the function's stack frame, including the local
area and the register-save area. */
@ -346,7 +361,7 @@ static void
bpf_compute_frame_layout (void)
{
int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
int padding_locals, regno;
int padding_locals;
/* Set the space used in the stack by local variables. This is
rounded up to respect the minimum stack alignment. */
@ -358,23 +373,9 @@ bpf_compute_frame_layout (void)
cfun->machine->local_vars_size += padding_locals;
if (TARGET_XBPF)
{
/* Set the space used in the stack by callee-saved used
registers in the current function. There is no need to round
up, since the registers are all 8 bytes wide. */
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((df_regs_ever_live_p (regno)
&& !call_used_or_fixed_reg_p (regno))
|| (cfun->calls_alloca
&& regno == STACK_POINTER_REGNUM))
cfun->machine->callee_saved_reg_size += 8;
}
/* Check that the total size of the frame doesn't exceed the limit
imposed by eBPF. */
if ((cfun->machine->local_vars_size
+ cfun->machine->callee_saved_reg_size) > bpf_frame_limit)
if (cfun->machine->local_vars_size > bpf_frame_limit)
{
static int stack_limit_exceeded = 0;
@ -393,69 +394,22 @@ bpf_compute_frame_layout (void)
void
bpf_expand_prologue (void)
{
HOST_WIDE_INT size;
size = (cfun->machine->local_vars_size
+ cfun->machine->callee_saved_reg_size);
/* The BPF "hardware" provides a fresh new set of registers for each
called function, some of which are initialized to the values of
the arguments passed in the first five registers. In doing so,
it saves the values of the registers of the caller, and restored
it saves the values of the registers of the caller, and restores
them upon returning. Therefore, there is no need to save the
callee-saved registers here. What is worse, the kernel
implementation refuses to run programs in which registers are
referred before being initialized. */
if (TARGET_XBPF)
{
int regno;
int fp_offset = -cfun->machine->local_vars_size;
callee-saved registers here. In fact, the kernel implementation
refuses to run programs in which registers are referred before
being initialized. */
/* Save callee-saved hard registes. The register-save-area
starts right after the local variables. */
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
{
if ((df_regs_ever_live_p (regno)
&& !call_used_or_fixed_reg_p (regno))
|| (cfun->calls_alloca
&& regno == STACK_POINTER_REGNUM))
{
rtx mem;
/* BPF does not support functions that allocate stack space
dynamically. This should have been checked already and an error
emitted. */
gcc_assert (!cfun->calls_alloca);
if (!IN_RANGE (fp_offset, -1 - 0x7fff, 0x7fff))
/* This has been already reported as an error in
bpf_compute_frame_layout. */
break;
else
{
mem = gen_frame_mem (DImode,
plus_constant (DImode,
hard_frame_pointer_rtx,
fp_offset - 8));
emit_move_insn (mem, gen_rtx_REG (DImode, regno));
fp_offset -= 8;
}
}
}
}
/* Set the stack pointer, if the function allocates space
dynamically. Note that the value of %sp should be directly
derived from %fp, for the kernel verifier to track it as a stack
accessor. */
if (cfun->calls_alloca)
{
emit_move_insn (stack_pointer_rtx,
hard_frame_pointer_rtx);
if (size > 0)
{
emit_insn (gen_rtx_SET (stack_pointer_rtx,
gen_rtx_PLUS (Pmode,
stack_pointer_rtx,
GEN_INT (-size))));
}
}
/* If we ever need to have a proper prologue here, please mind the
`naked' function attribute. */
}
/* Expand to the instructions in a function epilogue. This function
@ -466,37 +420,9 @@ bpf_expand_epilogue (void)
{
/* See note in bpf_expand_prologue for an explanation on why we are
not restoring callee-saved registers in BPF. */
if (TARGET_XBPF)
{
int regno;
int fp_offset = -cfun->machine->local_vars_size;
/* Restore callee-saved hard registes from the stack. */
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
{
if ((df_regs_ever_live_p (regno)
&& !call_used_or_fixed_reg_p (regno))
|| (cfun->calls_alloca
&& regno == STACK_POINTER_REGNUM))
{
rtx mem;
if (!IN_RANGE (fp_offset, -1 - 0x7fff, 0x7fff))
/* This has been already reported as an error in
bpf_compute_frame_layout. */
break;
else
{
mem = gen_frame_mem (DImode,
plus_constant (DImode,
hard_frame_pointer_rtx,
fp_offset - 8));
emit_move_insn (gen_rtx_REG (DImode, regno), mem);
fp_offset -= 8;
}
}
}
}
/* If we ever need to do anything else than just generating a return
instruction here, please mind the `naked' function attribute. */
emit_jump_insn (gen_exit ());
}
@ -543,11 +469,10 @@ bpf_initial_elimination_offset (int from, int to)
{
HOST_WIDE_INT ret;
if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
ret = (cfun->machine->local_vars_size
+ cfun->machine->callee_saved_reg_size);
else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
ret = 0;
else if (from == STACK_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
ret = -(cfun->machine->local_vars_size);
else
gcc_unreachable ();
@ -625,7 +550,8 @@ bpf_address_base_p (rtx x, bool strict)
static bool
bpf_legitimate_address_p (machine_mode mode,
rtx x,
bool strict)
bool strict,
code_helper = ERROR_MARK)
{
switch (GET_CODE (x))
{
@ -731,7 +657,14 @@ bpf_function_arg_advance (cumulative_args_t ca,
unsigned num_words = CEIL (num_bytes, UNITS_PER_WORD);
if (*cum <= 5 && *cum + num_words > 5)
error ("too many function arguments for eBPF");
{
/* Too many arguments for BPF. However, if the function is
gonna be inline for sure, we let it pass. Otherwise, issue
an error. */
if (!lookup_attribute ("always_inline",
DECL_ATTRIBUTES (cfun->decl)))
error ("too many function arguments for eBPF");
}
*cum += num_words;
}
@ -845,7 +778,7 @@ bpf_print_register (FILE *file, rtx op, int code)
fprintf (file, "%s", reg_names[REGNO (op)]);
else
{
if (code == 'w' && GET_MODE (op) == SImode)
if (code == 'w' && GET_MODE_SIZE (GET_MODE (op)) <= 4)
{
if (REGNO (op) == BPF_FP)
fprintf (file, "w10");

View File

@ -153,24 +153,27 @@
#define BPF_R7 7
#define BPF_R8 8
#define BPF_R9 9
#define BPF_SP BPF_R9
#define BPF_R10 10
#define BPF_FP BPF_R10
#define BPF_R11 11
#define BPF_R12 12
#define BPF_SP BPF_R12
/* 11 is not a real eBPF hard register and is eliminated or not used
in the final assembler. See below. */
#define FIRST_PSEUDO_REGISTER 12
#define FIRST_PSEUDO_REGISTER 13
/* The registers %r0..%r8 are available for general allocation.
%r9 is the pseudo-stack pointer.
%r10 is the stack frame, which is read-only.
%r11 (__arg__) is a fake register that always gets eliminated. */
%r11 (__arg__) is a fake register that always gets eliminated.
%r12 is the pseudo-stack pointer that always gets eliminated. */
#define FIXED_REGISTERS \
{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}
/* %r0..%r5 are clobbered by function calls. */
#define CALL_USED_REGISTERS \
{1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1}
{1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1}
/**** Register Classes. */
@ -206,7 +209,7 @@ enum reg_class
{ \
0x00000000, /* NO_REGS */ \
0x00000001, /* R0 */ \
0x00000fff, /* ALL_REGS */ \
0x00001fff, /* ALL_REGS */ \
}
/* A C expression whose value is a register class containing hard
@ -260,15 +263,15 @@ enum reg_class
/*** Registers That Address the Stack Frame. */
#define FRAME_POINTER_REGNUM 10
#define STACK_POINTER_REGNUM 9
#define ARG_POINTER_REGNUM 11
#define STACK_POINTER_REGNUM 12
#define STATIC_CHAIN_REGNUM 8
/*** Registers elimination. */
#define ELIMINABLE_REGS \
{{ ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM }, \
{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }}
{ STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM }}
/* Define the offset between two registers, one to be eliminated, and
the other its replacement, at the start of a routine. */
@ -444,7 +447,7 @@ enum reg_class
#define REGISTER_NAMES \
{ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", \
"%r8", "%r9", "%fp", "__arg__" }
"%r8", "%r9", "%fp", "__arg__", "__sp__" }
#define ADDITIONAL_REGISTER_NAMES \
{ { "%a", 0 }, { "%ctx", 6 }, { "%r10" , 10 } }

Some files were not shown because too many files have changed in this diff Show More