Initial commit
This commit is contained in:
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+14
@@ -0,0 +1,14 @@
|
||||
This README file is copied into the directory for GCC-only header files
|
||||
when fixincludes is run by the makefile for GCC.
|
||||
|
||||
Many of the files in this directory were automatically edited from the
|
||||
standard system header files by the fixincludes process. They are
|
||||
system-specific, and will not work on any other kind of system. They
|
||||
are also not part of GCC. The reason we have to do this is because
|
||||
GCC requires ANSI C headers and many vendors supply ANSI-incompatible
|
||||
headers.
|
||||
|
||||
Because this is an automated process, sometimes headers get "fixed"
|
||||
that do not, strictly speaking, need a fix. As long as nothing is broken
|
||||
by the process, it is just an unfortunate collateral inconvenience.
|
||||
We would like to rectify it, if it is not "too inconvenient".
|
||||
+279
@@ -0,0 +1,279 @@
|
||||
/* DO NOT EDIT THIS FILE.
|
||||
|
||||
It has been auto-edited by fixincludes from:
|
||||
|
||||
"/github/home/x-tools/arm-kobo-linux-gnueabihf/arm-kobo-linux-gnueabihf/sysroot/usr/include/linux/a.out.h"
|
||||
|
||||
This had to be done to correct non-standard usages in the
|
||||
original, manufacturer supplied header file. */
|
||||
|
||||
#ifndef __A_OUT_GNU_H__
|
||||
#define __A_OUT_GNU_H__
|
||||
|
||||
#define __GNU_EXEC_MACROS__
|
||||
|
||||
#ifndef __STRUCT_EXEC_OVERRIDE__
|
||||
|
||||
#include <asm/a.out.h>
|
||||
|
||||
#endif /* __STRUCT_EXEC_OVERRIDE__ */
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
/* these go in the N_MACHTYPE field */
|
||||
enum machine_type {
|
||||
#if defined (M_OLDSUN2)
|
||||
M__OLDSUN2 = M_OLDSUN2,
|
||||
#else
|
||||
M_OLDSUN2 = 0,
|
||||
#endif
|
||||
#if defined (M_68010)
|
||||
M__68010 = M_68010,
|
||||
#else
|
||||
M_68010 = 1,
|
||||
#endif
|
||||
#if defined (M_68020)
|
||||
M__68020 = M_68020,
|
||||
#else
|
||||
M_68020 = 2,
|
||||
#endif
|
||||
#if defined (M_SPARC)
|
||||
M__SPARC = M_SPARC,
|
||||
#else
|
||||
M_SPARC = 3,
|
||||
#endif
|
||||
/* skip a bunch so we don't run into any of sun's numbers */
|
||||
M_386 = 100,
|
||||
M_MIPS1 = 151, /* MIPS R3000/R3000 binary */
|
||||
M_MIPS2 = 152 /* MIPS R6000/R4000 binary */
|
||||
};
|
||||
|
||||
#if !defined (N_MAGIC)
|
||||
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
|
||||
#endif
|
||||
#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
|
||||
#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
|
||||
#define N_SET_INFO(exec, magic, type, flags) \
|
||||
((exec).a_info = ((magic) & 0xffff) \
|
||||
| (((int)(type) & 0xff) << 16) \
|
||||
| (((flags) & 0xff) << 24))
|
||||
#define N_SET_MAGIC(exec, magic) \
|
||||
((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff)))
|
||||
|
||||
#define N_SET_MACHTYPE(exec, machtype) \
|
||||
((exec).a_info = \
|
||||
((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16))
|
||||
|
||||
#define N_SET_FLAGS(exec, flags) \
|
||||
((exec).a_info = \
|
||||
((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24))
|
||||
|
||||
/* Code indicating object file or impure executable. */
|
||||
#define OMAGIC 0407
|
||||
/* Code indicating pure executable. */
|
||||
#define NMAGIC 0410
|
||||
/* Code indicating demand-paged executable. */
|
||||
#define ZMAGIC 0413
|
||||
/* This indicates a demand-paged executable with the header in the text.
|
||||
The first page is unmapped to help trap NULL pointer references */
|
||||
#define QMAGIC 0314
|
||||
|
||||
/* Code indicating core file. */
|
||||
#define CMAGIC 0421
|
||||
|
||||
#if !defined (N_BADMAG)
|
||||
#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
|
||||
&& N_MAGIC(x) != NMAGIC \
|
||||
&& N_MAGIC(x) != ZMAGIC \
|
||||
&& N_MAGIC(x) != QMAGIC)
|
||||
#endif
|
||||
|
||||
#define _N_HDROFF(x) (1024 - sizeof (struct exec))
|
||||
|
||||
#if !defined (N_TXTOFF)
|
||||
#define N_TXTOFF(x) \
|
||||
(N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
|
||||
(N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
|
||||
#endif
|
||||
|
||||
#if !defined (N_DATOFF)
|
||||
#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
|
||||
#endif
|
||||
|
||||
#if !defined (N_TRELOFF)
|
||||
#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
|
||||
#endif
|
||||
|
||||
#if !defined (N_DRELOFF)
|
||||
#define N_DRELOFF(x) (N_TRELOFF(x) + N_TRSIZE(x))
|
||||
#endif
|
||||
|
||||
#if !defined (N_SYMOFF)
|
||||
#define N_SYMOFF(x) (N_DRELOFF(x) + N_DRSIZE(x))
|
||||
#endif
|
||||
|
||||
#if !defined (N_STROFF)
|
||||
#define N_STROFF(x) (N_SYMOFF(x) + N_SYMSIZE(x))
|
||||
#endif
|
||||
|
||||
/* Address of text segment in memory after it is loaded. */
|
||||
#if !defined (N_TXTADDR)
|
||||
#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? PAGE_SIZE : 0)
|
||||
#endif
|
||||
|
||||
/* Address of data segment in memory after it is loaded.
|
||||
Note that it is up to you to define SEGMENT_SIZE
|
||||
on machines not listed here. */
|
||||
#if defined(vax) || defined(hp300) || defined(pyr)
|
||||
#define SEGMENT_SIZE page_size
|
||||
#endif
|
||||
#ifdef sony
|
||||
#define SEGMENT_SIZE 0x2000
|
||||
#endif /* Sony. */
|
||||
#ifdef is68k
|
||||
#define SEGMENT_SIZE 0x20000
|
||||
#endif
|
||||
#if defined(m68k) && defined(PORTAR)
|
||||
#define PAGE_SIZE 0x400
|
||||
#define SEGMENT_SIZE PAGE_SIZE
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#if defined(__i386__) || defined(__mc68000__)
|
||||
#define SEGMENT_SIZE 1024
|
||||
#else
|
||||
#ifndef SEGMENT_SIZE
|
||||
#define SEGMENT_SIZE getpagesize()
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define _N_SEGMENT_ROUND(x) ALIGN(x, SEGMENT_SIZE)
|
||||
|
||||
#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
|
||||
|
||||
#ifndef N_DATADDR
|
||||
#define N_DATADDR(x) \
|
||||
(N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
|
||||
: (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
|
||||
#endif
|
||||
|
||||
/* Address of bss segment in memory after it is loaded. */
|
||||
#if !defined (N_BSSADDR)
|
||||
#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
|
||||
#endif
|
||||
|
||||
#if !defined (N_NLIST_DECLARED)
|
||||
struct nlist {
|
||||
union {
|
||||
char *n_name;
|
||||
struct nlist *n_next;
|
||||
long n_strx;
|
||||
} n_un;
|
||||
unsigned char n_type;
|
||||
char n_other;
|
||||
short n_desc;
|
||||
unsigned long n_value;
|
||||
};
|
||||
#endif /* no N_NLIST_DECLARED. */
|
||||
|
||||
#if !defined (N_UNDF)
|
||||
#define N_UNDF 0
|
||||
#endif
|
||||
#if !defined (N_ABS)
|
||||
#define N_ABS 2
|
||||
#endif
|
||||
#if !defined (N_TEXT)
|
||||
#define N_TEXT 4
|
||||
#endif
|
||||
#if !defined (N_DATA)
|
||||
#define N_DATA 6
|
||||
#endif
|
||||
#if !defined (N_BSS)
|
||||
#define N_BSS 8
|
||||
#endif
|
||||
#if !defined (N_FN)
|
||||
#define N_FN 15
|
||||
#endif
|
||||
|
||||
#if !defined (N_EXT)
|
||||
#define N_EXT 1
|
||||
#endif
|
||||
#if !defined (N_TYPE)
|
||||
#define N_TYPE 036
|
||||
#endif
|
||||
#if !defined (N_STAB)
|
||||
#define N_STAB 0340
|
||||
#endif
|
||||
|
||||
/* The following type indicates the definition of a symbol as being
|
||||
an indirect reference to another symbol. The other symbol
|
||||
appears as an undefined reference, immediately following this symbol.
|
||||
|
||||
Indirection is asymmetrical. The other symbol's value will be used
|
||||
to satisfy requests for the indirect symbol, but not vice versa.
|
||||
If the other symbol does not have a definition, libraries will
|
||||
be searched to find a definition. */
|
||||
#define N_INDR 0xa
|
||||
|
||||
/* The following symbols refer to set elements.
|
||||
All the N_SET[ATDB] symbols with the same name form one set.
|
||||
Space is allocated for the set in the text section, and each set
|
||||
element's value is stored into one word of the space.
|
||||
The first word of the space is the length of the set (number of elements).
|
||||
|
||||
The address of the set is made into an N_SETV symbol
|
||||
whose name is the same as the name of the set.
|
||||
This symbol acts like a N_DATA global symbol
|
||||
in that it can satisfy undefined external references. */
|
||||
|
||||
/* These appear as input to LD, in a .o file. */
|
||||
#define N_SETA 0x14 /* Absolute set element symbol */
|
||||
#define N_SETT 0x16 /* Text set element symbol */
|
||||
#define N_SETD 0x18 /* Data set element symbol */
|
||||
#define N_SETB 0x1A /* Bss set element symbol */
|
||||
|
||||
/* This is output from LD. */
|
||||
#define N_SETV 0x1C /* Pointer to set vector in data area. */
|
||||
|
||||
#if !defined (N_RELOCATION_INFO_DECLARED)
|
||||
/* This structure describes a single relocation to be performed.
|
||||
The text-relocation section of the file is a vector of these structures,
|
||||
all of which apply to the text section.
|
||||
Likewise, the data-relocation section applies to the data section. */
|
||||
|
||||
struct relocation_info
|
||||
{
|
||||
/* Address (within segment) to be relocated. */
|
||||
int r_address;
|
||||
/* The meaning of r_symbolnum depends on r_extern. */
|
||||
unsigned int r_symbolnum:24;
|
||||
/* Nonzero means value is a pc-relative offset
|
||||
and it should be relocated for changes in its own address
|
||||
as well as for changes in the symbol or section specified. */
|
||||
unsigned int r_pcrel:1;
|
||||
/* Length (as exponent of 2) of the field to be relocated.
|
||||
Thus, a value of 2 indicates 1<<2 bytes. */
|
||||
unsigned int r_length:2;
|
||||
/* 1 => relocate with value of symbol.
|
||||
r_symbolnum is the index of the symbol
|
||||
in file's the symbol table.
|
||||
0 => relocate with the address of a segment.
|
||||
r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
|
||||
(the N_EXT bit may be set also, but signifies nothing). */
|
||||
unsigned int r_extern:1;
|
||||
/* Four bits that aren't used, but when writing an object file
|
||||
it is desirable to clear them. */
|
||||
#ifdef NS32K
|
||||
unsigned r_bsr:1;
|
||||
unsigned r_disp:1;
|
||||
unsigned r_pad:2;
|
||||
#else
|
||||
unsigned int r_pad:4;
|
||||
#endif
|
||||
};
|
||||
#endif /* no N_RELOCATION_INFO_DECLARED. */
|
||||
|
||||
#endif /*__ASSEMBLY__ */
|
||||
#endif /* __A_OUT_GNU_H__ */
|
||||
+836
@@ -0,0 +1,836 @@
|
||||
/* ARM Non-NEON ACLE intrinsics include file.
|
||||
|
||||
Copyright (C) 2013-2024 Free Software Foundation, Inc.
|
||||
Contributed by ARM Ltd.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _GCC_ARM_ACLE_H
|
||||
#define _GCC_ARM_ACLE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _GCC_ARM_ACLE_ROR_FN(NAME, TYPE) \
|
||||
__extension__ extern __inline TYPE \
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \
|
||||
NAME (TYPE __value, uint32_t __rotate) \
|
||||
{ \
|
||||
int __size = (int) sizeof (TYPE) * __CHAR_BIT__; \
|
||||
__rotate = __rotate % __size; \
|
||||
return __value >> __rotate | __value << ((__size - __rotate) % __size); \
|
||||
}
|
||||
|
||||
_GCC_ARM_ACLE_ROR_FN (__ror, uint32_t)
|
||||
_GCC_ARM_ACLE_ROR_FN (__rorl, unsigned long)
|
||||
_GCC_ARM_ACLE_ROR_FN (__rorll, uint64_t)
|
||||
|
||||
#undef _GCC_ARM_ACLE_ROR_FN
|
||||
|
||||
#define _GCC_ARM_ACLE_DATA_FN(NAME, ITYPE, RTYPE) \
|
||||
__extension__ extern __inline RTYPE \
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) \
|
||||
__##NAME (ITYPE __value)
|
||||
|
||||
#define _GCC_ARM_ACLE_DATA_ALIAS(NAME, BUILTIN, ITYPE, RTYPE) \
|
||||
_GCC_ARM_ACLE_DATA_FN(NAME, ITYPE, RTYPE) \
|
||||
{ \
|
||||
return __builtin_##BUILTIN (__value); \
|
||||
}
|
||||
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (clz, clz, uint32_t, unsigned int)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (clzl, clzl, unsigned long, unsigned int)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (clzll, clzll, uint64_t, unsigned int)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (cls, clrsb, uint32_t, unsigned int)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (clsl, clrsbl, unsigned long, unsigned int)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (clsll, clrsbll, uint64_t, unsigned int)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (revsh, bswap16, int16_t, int16_t)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (rev, bswap32, uint32_t, uint32_t)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (revl, bswap32, unsigned long, unsigned long)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (revll, bswap64, uint64_t, uint64_t)
|
||||
#if __ARM_ARCH >= 6
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (rev16, arm_rev16si2, uint32_t, uint32_t)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (rev16l, arm_rev16si2, unsigned long, unsigned long)
|
||||
#else
|
||||
_GCC_ARM_ACLE_DATA_FN(rev16, uint32_t, uint32_t) {
|
||||
return ((__value & 0xff00ff) << 8 | (__value & 0xff00ff00) >> 8);
|
||||
}
|
||||
_GCC_ARM_ACLE_DATA_FN(rev16l, unsigned long, unsigned long) {
|
||||
return ((__value & 0xff00ff) << 8 | (__value & 0xff00ff00) >> 8);
|
||||
}
|
||||
#endif
|
||||
_GCC_ARM_ACLE_DATA_FN(rev16ll, uint64_t, uint64_t) {
|
||||
return __rev16l(__value) | (uint64_t)__rev16l(__value >> 32) << 32;
|
||||
}
|
||||
|
||||
#if __ARM_ARCH_6T2__ || __ARM_ARCH >= 7
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (rbit, arm_rbit, uint32_t, uint32_t)
|
||||
_GCC_ARM_ACLE_DATA_ALIAS (rbitl, arm_rbit, unsigned long, unsigned int)
|
||||
_GCC_ARM_ACLE_DATA_FN(rbitll, uint64_t, uint64_t) {
|
||||
return ((uint64_t)__rbit(__value) << 32) | __rbit(__value >> 32);
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef _GCC_ARM_ACLE_DATA_ALIAS
|
||||
#undef _GCC_ARM_ACLE_DATA_FN
|
||||
|
||||
#if (!__thumb__ || __thumb2__) && __ARM_ARCH >= 4
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_cdp (const unsigned int __coproc, const unsigned int __opc1,
|
||||
const unsigned int __CRd, const unsigned int __CRn,
|
||||
const unsigned int __CRm, const unsigned int __opc2)
|
||||
{
|
||||
__builtin_arm_cdp (__coproc, __opc1, __CRd, __CRn, __CRm, __opc2);
|
||||
}
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_ldc (const unsigned int __coproc, const unsigned int __CRd,
|
||||
const void * __p)
|
||||
{
|
||||
__builtin_arm_ldc (__coproc, __CRd, __p);
|
||||
}
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_ldcl (const unsigned int __coproc, const unsigned int __CRd,
|
||||
const void * __p)
|
||||
{
|
||||
__builtin_arm_ldcl (__coproc, __CRd, __p);
|
||||
}
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_stc (const unsigned int __coproc, const unsigned int __CRd,
|
||||
void * __p)
|
||||
{
|
||||
__builtin_arm_stc (__coproc, __CRd, __p);
|
||||
}
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_stcl (const unsigned int __coproc, const unsigned int __CRd,
|
||||
void * __p)
|
||||
{
|
||||
__builtin_arm_stcl (__coproc, __CRd, __p);
|
||||
}
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_mcr (const unsigned int __coproc, const unsigned int __opc1,
|
||||
uint32_t __value, const unsigned int __CRn, const unsigned int __CRm,
|
||||
const unsigned int __opc2)
|
||||
{
|
||||
__builtin_arm_mcr (__coproc, __opc1, __value, __CRn, __CRm, __opc2);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
__arm_mrc (const unsigned int __coproc, const unsigned int __opc1,
|
||||
const unsigned int __CRn, const unsigned int __CRm,
|
||||
const unsigned int __opc2)
|
||||
{
|
||||
return __builtin_arm_mrc (__coproc, __opc1, __CRn, __CRm, __opc2);
|
||||
}
|
||||
#if __ARM_ARCH >= 5
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_cdp2 (const unsigned int __coproc, const unsigned int __opc1,
|
||||
const unsigned int __CRd, const unsigned int __CRn,
|
||||
const unsigned int __CRm, const unsigned int __opc2)
|
||||
{
|
||||
__builtin_arm_cdp2 (__coproc, __opc1, __CRd, __CRn, __CRm, __opc2);
|
||||
}
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_ldc2 (const unsigned int __coproc, const unsigned int __CRd,
|
||||
const void * __p)
|
||||
{
|
||||
__builtin_arm_ldc2 (__coproc, __CRd, __p);
|
||||
}
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_ldc2l (const unsigned int __coproc, const unsigned int __CRd,
|
||||
const void * __p)
|
||||
{
|
||||
__builtin_arm_ldc2l (__coproc, __CRd, __p);
|
||||
}
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_stc2 (const unsigned int __coproc, const unsigned int __CRd,
|
||||
void * __p)
|
||||
{
|
||||
__builtin_arm_stc2 (__coproc, __CRd, __p);
|
||||
}
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_stc2l (const unsigned int __coproc, const unsigned int __CRd,
|
||||
void * __p)
|
||||
{
|
||||
__builtin_arm_stc2l (__coproc, __CRd, __p);
|
||||
}
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_mcr2 (const unsigned int __coproc, const unsigned int __opc1,
|
||||
uint32_t __value, const unsigned int __CRn,
|
||||
const unsigned int __CRm, const unsigned int __opc2)
|
||||
{
|
||||
__builtin_arm_mcr2 (__coproc, __opc1, __value, __CRn, __CRm, __opc2);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
__arm_mrc2 (const unsigned int __coproc, const unsigned int __opc1,
|
||||
const unsigned int __CRn, const unsigned int __CRm,
|
||||
const unsigned int __opc2)
|
||||
{
|
||||
return __builtin_arm_mrc2 (__coproc, __opc1, __CRn, __CRm, __opc2);
|
||||
}
|
||||
|
||||
#if __ARM_ARCH >= 6 || defined (__ARM_ARCH_5TE__)
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_mcrr (const unsigned int __coproc, const unsigned int __opc1,
|
||||
uint64_t __value, const unsigned int __CRm)
|
||||
{
|
||||
__builtin_arm_mcrr (__coproc, __opc1, __value, __CRm);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint64_t __attribute__ ((__always_inline__))
|
||||
__arm_mrrc (const unsigned int __coproc, const unsigned int __opc1,
|
||||
const unsigned int __CRm)
|
||||
{
|
||||
return __builtin_arm_mrrc (__coproc, __opc1, __CRm);
|
||||
}
|
||||
|
||||
#if __ARM_ARCH >= 6
|
||||
|
||||
__extension__ static __inline void __attribute__ ((__always_inline__))
|
||||
__arm_mcrr2 (const unsigned int __coproc, const unsigned int __opc1,
|
||||
uint64_t __value, const unsigned int __CRm)
|
||||
{
|
||||
__builtin_arm_mcrr2 (__coproc, __opc1, __value, __CRm);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint64_t __attribute__ ((__always_inline__))
|
||||
__arm_mrrc2 (const unsigned int __coproc, const unsigned int __opc1,
|
||||
const unsigned int __CRm)
|
||||
{
|
||||
return __builtin_arm_mrrc2 (__coproc, __opc1, __CRm);
|
||||
}
|
||||
#endif /* __ARM_ARCH >= 6. */
|
||||
#endif /* __ARM_ARCH >= 6 || defined (__ARM_ARCH_5TE__). */
|
||||
#endif /* __ARM_ARCH >= 5. */
|
||||
#endif /* (!__thumb__ || __thumb2__) && __ARM_ARCH >= 4. */
|
||||
|
||||
#ifdef __ARM_FEATURE_SIMD32
|
||||
typedef int32_t int16x2_t;
|
||||
typedef uint32_t uint16x2_t;
|
||||
typedef int32_t int8x4_t;
|
||||
typedef uint32_t uint8x4_t;
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__sxtab16 (int16x2_t __a, int8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_sxtab16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__sxtb16 (int8x4_t __a)
|
||||
{
|
||||
return __builtin_arm_sxtb16 (__a);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uxtab16 (uint16x2_t __a, uint8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_uxtab16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uxtb16 (uint8x4_t __a)
|
||||
{
|
||||
return __builtin_arm_uxtb16 (__a);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__qadd8 (int8x4_t __a, int8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_qadd8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__qsub8 (int8x4_t __a, int8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_qsub8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__shadd8 (int8x4_t __a, int8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_shadd8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__shsub8 (int8x4_t __a, int8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_shsub8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uhadd8 (uint8x4_t __a, uint8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_uhadd8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uhsub8 (uint8x4_t __a, uint8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_uhsub8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uqadd8 (uint8x4_t __a, uint8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_uqadd8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uqsub8 (uint8x4_t __a, uint8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_uqsub8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__qadd16 (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_qadd16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__qasx (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_qasx (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__qsax (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_qsax (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__qsub16 (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_qsub16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__shadd16 (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_shadd16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__shasx (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_shasx (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__shsax (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_shsax (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__shsub16 (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_shsub16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uhadd16 (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_uhadd16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uhasx (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_uhasx (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uhsax (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_uhsax (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uhsub16 (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_uhsub16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uqadd16 (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_uqadd16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uqasx (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_uqasx (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uqsax (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_uqsax (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uqsub16 (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_uqsub16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smusd (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_smusd (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smusdx (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_smusdx (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__usad8 (uint8x4_t __a, uint8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_usad8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__usada8 (uint8x4_t __a, uint8x4_t __b, uint32_t __c)
|
||||
{
|
||||
return __builtin_arm_usada8 (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int64_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlald (int16x2_t __a, int16x2_t __b, int64_t __c)
|
||||
{
|
||||
return __builtin_arm_smlald (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int64_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlaldx (int16x2_t __a, int16x2_t __b, int64_t __c)
|
||||
{
|
||||
return __builtin_arm_smlaldx (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int64_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlsld (int16x2_t __a, int16x2_t __b, int64_t __c)
|
||||
{
|
||||
return __builtin_arm_smlsld (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int64_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlsldx (int16x2_t __a, int16x2_t __b, int64_t __c)
|
||||
{
|
||||
return __builtin_arm_smlsldx (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__sel (uint8x4_t __a, uint8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_sel (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__sadd8 (int8x4_t __a, int8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_sadd8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__ssub8 (int8x4_t __a, int8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_ssub8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uadd8 (uint8x4_t __a, uint8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_uadd8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint8x4_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__usub8 (uint8x4_t __a, uint8x4_t __b)
|
||||
{
|
||||
return __builtin_arm_usub8 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__sadd16 (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_sadd16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__sasx (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_sasx (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__ssax (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_ssax (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__ssub16 (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_ssub16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uadd16 (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_uadd16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__uasx (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_uasx (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__usax (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_usax (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline uint16x2_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__usub16 (uint16x2_t __a, uint16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_usub16 (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlad (int16x2_t __a, int16x2_t __b, int32_t __c)
|
||||
{
|
||||
return __builtin_arm_smlad (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smladx (int16x2_t __a, int16x2_t __b, int32_t __c)
|
||||
{
|
||||
return __builtin_arm_smladx (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlsd (int16x2_t __a, int16x2_t __b, int32_t __c)
|
||||
{
|
||||
return __builtin_arm_smlsd (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlsdx (int16x2_t __a, int16x2_t __b, int32_t __c)
|
||||
{
|
||||
return __builtin_arm_smlsdx (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smuad (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_smuad (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smuadx (int16x2_t __a, int16x2_t __b)
|
||||
{
|
||||
return __builtin_arm_smuadx (__a, __b);
|
||||
}
|
||||
|
||||
#define __ssat16(__a, __sat) \
|
||||
__extension__ \
|
||||
({ \
|
||||
int16x2_t __arg = (__a); \
|
||||
__builtin_sat_imm_check (__sat, 1, 16); \
|
||||
int16x2_t __res = __builtin_arm_ssat16 (__arg, __sat); \
|
||||
__res; \
|
||||
})
|
||||
|
||||
#define __usat16(__a, __sat) \
|
||||
__extension__ \
|
||||
({ \
|
||||
int16x2_t __arg = (__a); \
|
||||
__builtin_sat_imm_check (__sat, 0, 15); \
|
||||
int16x2_t __res = __builtin_arm_usat16 (__arg, __sat); \
|
||||
__res; \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __ARM_FEATURE_SAT
|
||||
|
||||
#define __ssat(__a, __sat) \
|
||||
__extension__ \
|
||||
({ \
|
||||
int32_t __arg = (__a); \
|
||||
__builtin_sat_imm_check (__sat, 1, 32); \
|
||||
int32_t __res = __builtin_arm_ssat (__arg, __sat); \
|
||||
__res; \
|
||||
})
|
||||
|
||||
#define __usat(__a, __sat) \
|
||||
__extension__ \
|
||||
({ \
|
||||
int32_t __arg = (__a); \
|
||||
__builtin_sat_imm_check (__sat, 0, 31); \
|
||||
uint32_t __res = __builtin_arm_usat (__arg, __sat); \
|
||||
__res; \
|
||||
})
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __ARM_FEATURE_QBIT
|
||||
__extension__ extern __inline void
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__ignore_saturation (void)
|
||||
{
|
||||
/* ACLE designates this intrinsic as a hint.
|
||||
Implement as a nop for now. */
|
||||
}
|
||||
|
||||
/* These are defined as macros because the implementation of the builtins
|
||||
requires easy access to the current function so wrapping it in an
|
||||
always_inline function complicates things. */
|
||||
|
||||
#define __saturation_occurred __builtin_arm_saturation_occurred
|
||||
|
||||
#define __set_saturation_occurred(__a) \
|
||||
__extension__ \
|
||||
({ \
|
||||
int __arg = (__a); \
|
||||
__builtin_arm_set_saturation (__arg); \
|
||||
})
|
||||
#endif
|
||||
|
||||
#ifdef __ARM_FEATURE_DSP
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__qadd (int32_t __a, int32_t __b)
|
||||
{
|
||||
return __builtin_arm_qadd (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__qsub (int32_t __a, int32_t __b)
|
||||
{
|
||||
return __builtin_arm_qsub (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__qdbl (int32_t __x)
|
||||
{
|
||||
return __qadd (__x, __x);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlabb (int32_t __a, int32_t __b, int32_t __c)
|
||||
{
|
||||
return __builtin_arm_smlabb (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlatb (int32_t __a, int32_t __b, int32_t __c)
|
||||
{
|
||||
return __builtin_arm_smlatb (__a, __b, __c);
|
||||
}
|
||||
|
||||
/* smlatb is equivalent to smlabt with the two multiplication operands
|
||||
swapped around. */
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlabt (int32_t __a, int32_t __b, int32_t __c)
|
||||
{
|
||||
return __smlatb (__b, __a, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlatt (int32_t __a, int32_t __b, int32_t __c)
|
||||
{
|
||||
return __builtin_arm_smlatt (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlawb (int32_t __a, int32_t __b, int32_t __c)
|
||||
{
|
||||
return __builtin_arm_smlawb (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ extern __inline int32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
__smlawt (int32_t __a, int32_t __b, int32_t __c)
|
||||
{
|
||||
return __builtin_arm_smlawt (__a, __b, __c);
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma GCC push_options
|
||||
#ifdef __ARM_FEATURE_CRC32
|
||||
#ifdef __ARM_FP
|
||||
#pragma GCC target ("arch=armv8-a+crc+simd")
|
||||
#else
|
||||
#pragma GCC target ("arch=armv8-a+crc")
|
||||
#endif
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
__crc32b (uint32_t __a, uint8_t __b)
|
||||
{
|
||||
return __builtin_arm_crc32b (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
__crc32h (uint32_t __a, uint16_t __b)
|
||||
{
|
||||
return __builtin_arm_crc32h (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
__crc32w (uint32_t __a, uint32_t __b)
|
||||
{
|
||||
return __builtin_arm_crc32w (__a, __b);
|
||||
}
|
||||
|
||||
#ifdef __ARM_32BIT_STATE
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
__crc32d (uint32_t __a, uint64_t __b)
|
||||
{
|
||||
uint32_t __d;
|
||||
|
||||
__d = __crc32w (__crc32w (__a, __b & 0xffffffffULL), __b >> 32);
|
||||
return __d;
|
||||
}
|
||||
#endif
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
__crc32cb (uint32_t __a, uint8_t __b)
|
||||
{
|
||||
return __builtin_arm_crc32cb (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
__crc32ch (uint32_t __a, uint16_t __b)
|
||||
{
|
||||
return __builtin_arm_crc32ch (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
__crc32cw (uint32_t __a, uint32_t __b)
|
||||
{
|
||||
return __builtin_arm_crc32cw (__a, __b);
|
||||
}
|
||||
|
||||
#ifdef __ARM_32BIT_STATE
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
__crc32cd (uint32_t __a, uint64_t __b)
|
||||
{
|
||||
uint32_t __d;
|
||||
|
||||
__d = __crc32cw (__crc32cw (__a, __b & 0xffffffffULL), __b >> 32);
|
||||
return __d;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ARM_FEATURE_CRC32 */
|
||||
#pragma GCC pop_options
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/* Arm BF16 intrinsics include file.
|
||||
|
||||
Copyright (C) 2019-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#ifndef _GCC_ARM_BF16_H
|
||||
#define _GCC_ARM_BF16_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef __bf16 bfloat16_t;
|
||||
typedef float float32_t;
|
||||
|
||||
__extension__ extern __inline float32_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
vcvtah_f32_bf16 (bfloat16_t __a)
|
||||
{
|
||||
return __builtin_neon_vbfcvtbf (__a);
|
||||
}
|
||||
|
||||
__extension__ extern __inline bfloat16_t
|
||||
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
|
||||
vcvth_bf16_f32 (float32_t __a)
|
||||
{
|
||||
return __builtin_neon_vbfcvtsf (__a);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
/* Arm Custom Datapath Extension (CDE) intrinsics include file.
|
||||
|
||||
Copyright (C) 2020-2024 Free Software Foundation, Inc.
|
||||
Contributed by Arm Ltd.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _GCC_ARM_CDE_H
|
||||
#define _GCC_ARM_CDE_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined (__ARM_FEATURE_CDE)
|
||||
|
||||
#define __arm_cx1(coproc, imm) \
|
||||
__builtin_arm_cx1si(coproc, imm)
|
||||
|
||||
#define __arm_cx1a(coproc, acc, imm) \
|
||||
__builtin_arm_cx1asi(coproc, acc, imm)
|
||||
|
||||
#define __arm_cx2(coproc, n, imm) \
|
||||
__builtin_arm_cx2si(coproc, n, imm)
|
||||
|
||||
#define __arm_cx2a(coproc, acc, n, imm) \
|
||||
__builtin_arm_cx2asi(coproc, acc, n, imm)
|
||||
|
||||
#define __arm_cx3(coproc, n, m, imm) \
|
||||
__builtin_arm_cx3si(coproc, n, m, imm)
|
||||
|
||||
#define __arm_cx3a(coproc, acc, n, m, imm) \
|
||||
__builtin_arm_cx3asi(coproc, acc, n, m, imm)
|
||||
|
||||
#define __arm_cx1d(coproc, imm) \
|
||||
__builtin_arm_cx1di(coproc, imm)
|
||||
|
||||
#define __arm_cx1da(coproc, acc, imm) \
|
||||
__builtin_arm_cx1adi(coproc, acc, imm)
|
||||
|
||||
#define __arm_cx2d(coproc, n, imm) \
|
||||
__builtin_arm_cx2di(coproc, n, imm)
|
||||
|
||||
#define __arm_cx2da(coproc, acc, n, imm) \
|
||||
__builtin_arm_cx2adi(coproc, acc, n, imm)
|
||||
|
||||
#define __arm_cx3d(coproc, n, m, imm) \
|
||||
__builtin_arm_cx3di(coproc, n, m, imm)
|
||||
|
||||
#define __arm_cx3da(coproc, acc, n, m, imm) \
|
||||
__builtin_arm_cx3adi(coproc, acc, n, m, imm)
|
||||
|
||||
#if defined (__ARM_FP) || defined (__ARM_FEATURE_MVE)
|
||||
|
||||
/* CDE builtins using FPU/MVE registers. */
|
||||
|
||||
/* uint32_t
|
||||
__arm_vcx1_u32(int coproc, uint32_t imm); */
|
||||
#define __arm_vcx1_u32(coproc, imm) \
|
||||
__builtin_arm_vcx1si(coproc, imm)
|
||||
|
||||
/* uint32_t
|
||||
__arm_vcx1a_u32(int coproc, uint32_t acc, uint32_t imm); */
|
||||
#define __arm_vcx1a_u32(coproc, acc, imm) \
|
||||
__builtin_arm_vcx1asi(coproc, acc, imm)
|
||||
|
||||
/* uint32_t
|
||||
__arm_vcx2_u32(int coproc, uint32_t n, uint32_t imm); */
|
||||
#define __arm_vcx2_u32(coproc, n, imm) \
|
||||
__builtin_arm_vcx2si(coproc, n, imm)
|
||||
|
||||
/* uint32_t
|
||||
__arm_vcx2a_u32(int coproc, uint32_t acc, uint32_t n, uint32_t imm); */
|
||||
#define __arm_vcx2a_u32(coproc, acc, n, imm) \
|
||||
__builtin_arm_vcx2asi(coproc, acc, n, imm)
|
||||
|
||||
/* uint32_t
|
||||
__arm_vcx3_u32(int coproc, uint32_t n, uint32_t m, uint32_t imm); */
|
||||
#define __arm_vcx3_u32(coproc, n, m, imm) \
|
||||
__builtin_arm_vcx3si(coproc, n, m, imm)
|
||||
|
||||
/* uint32_t
|
||||
__arm_vcx3a_u32(int coproc, uint32_t acc, uint32_t n, uint32_t m,
|
||||
uint32_t imm); */
|
||||
#define __arm_vcx3a_u32(coproc, acc, n, m, imm) \
|
||||
__builtin_arm_vcx3asi(coproc, acc, n, m, imm)
|
||||
|
||||
/* uint64_t
|
||||
__arm_vcx1d_u64(int coproc, uint32_t imm); */
|
||||
#define __arm_vcx1d_u64(coproc, imm) \
|
||||
__builtin_arm_vcx1di(coproc, imm)
|
||||
|
||||
/* uint64_t
|
||||
__arm_vcx1da_u64(int coproc, uint64_t acc, uint32_t imm); */
|
||||
#define __arm_vcx1da_u64(coproc, acc, imm) \
|
||||
__builtin_arm_vcx1adi(coproc, acc, imm)
|
||||
|
||||
/* uint64_t
|
||||
__arm_vcx2d_u64(int coproc, uint64_t m, uint32_t imm); */
|
||||
#define __arm_vcx2d_u64(coproc, m, imm) \
|
||||
__builtin_arm_vcx2di(coproc, m, imm)
|
||||
|
||||
/* uint64_t
|
||||
__arm_vcx2da_u64(int coproc, uint64_t acc, uint64_t m, uint32_t imm); */
|
||||
#define __arm_vcx2da_u64(coproc, acc, m, imm) \
|
||||
__builtin_arm_vcx2adi(coproc, acc, m, imm)
|
||||
|
||||
/* uint64_t
|
||||
__arm_vcx3d_u64(int coproc, uint64_t n, uint64_t m, uint32_t imm); */
|
||||
#define __arm_vcx3d_u64(coproc, n, m, imm) \
|
||||
__builtin_arm_vcx3di(coproc, n, m, imm)
|
||||
|
||||
/* uint64_t
|
||||
__arm_vcx3da_u64(int coproc, uint64_t acc, uint64_t n, uint64_t m,
|
||||
uint32_t imm); */
|
||||
#define __arm_vcx3da_u64(coproc, acc, n, m, imm) \
|
||||
__builtin_arm_vcx3adi(coproc, acc, n, m, imm)
|
||||
|
||||
#endif /* __ARM_FP || __ARM_FEATURE_MVE. */
|
||||
#endif /* __ARM_FEATURE_CDE. */
|
||||
|
||||
#if __ARM_FEATURE_MVE
|
||||
#include "arm_mve_types.h"
|
||||
|
||||
#define __arm_vcx1q_u8(coproc, imm) \
|
||||
(uint8x16_t)__builtin_arm_vcx1qv16qi(coproc, imm)
|
||||
#define __arm_vcx1qa(coproc, acc, imm) \
|
||||
__builtin_arm_vcx1qav16qi(coproc, acc, imm)
|
||||
#define __arm_vcx2q(coproc, n, imm) \
|
||||
__builtin_arm_vcx2qv16qi(coproc, n, imm)
|
||||
#define __arm_vcx2q_u8(coproc, n, imm) \
|
||||
(uint8x16_t)__builtin_arm_vcx2qv16qi(coproc, n, imm)
|
||||
#define __arm_vcx2qa(coproc, acc, n, imm) \
|
||||
__builtin_arm_vcx2qav16qi(coproc, acc, n, imm)
|
||||
#define __arm_vcx3q(coproc, n, m, imm) \
|
||||
__builtin_arm_vcx3qv16qi(coproc, n, m, imm)
|
||||
#define __arm_vcx3q_u8(coproc, n, m, imm) \
|
||||
(uint8x16_t)__builtin_arm_vcx3qv16qi(coproc, n, m, imm)
|
||||
#define __arm_vcx3qa(coproc, acc, n, m, imm) \
|
||||
__builtin_arm_vcx3qav16qi(coproc, acc, n, m, imm)
|
||||
|
||||
#define __arm_vcx1q_m(coproc, inactive, imm, pred) \
|
||||
__builtin_arm_vcx1q_p_v16qi(coproc, inactive, imm, pred)
|
||||
#define __arm_vcx1qa_m(coproc, acc, imm, pred) \
|
||||
__builtin_arm_vcx1qa_p_v16qi(coproc, acc, imm, pred)
|
||||
|
||||
#define __arm_vcx2q_m(coproc, inactive, n, imm, pred) \
|
||||
__builtin_arm_vcx2q_p_v16qi(coproc, inactive, n, imm, pred)
|
||||
#define __arm_vcx2qa_m(coproc, acc, n, imm, pred) \
|
||||
__builtin_arm_vcx2qa_p_v16qi(coproc, acc, n, imm, pred)
|
||||
|
||||
#define __arm_vcx3q_m(coproc, inactive, n, m, imm, pred) \
|
||||
__builtin_arm_vcx3q_p_v16qi(coproc, inactive, n, m, imm, pred)
|
||||
#define __arm_vcx3qa_m(coproc, acc, n, m, imm, pred) \
|
||||
__builtin_arm_vcx3qa_p_v16qi(coproc, acc, n, m, imm, pred)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
/* ARMv8-M Secure Extensions intrinsics include file.
|
||||
|
||||
Copyright (C) 2015-2024 Free Software Foundation, Inc.
|
||||
Contributed by ARM Ltd.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#ifndef _GCC_ARM_CMSE_H
|
||||
#define _GCC_ARM_CMSE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if __ARM_FEATURE_CMSE & 1
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __ARM_BIG_ENDIAN
|
||||
|
||||
typedef union {
|
||||
struct cmse_address_info {
|
||||
#if __ARM_FEATURE_CMSE & 2
|
||||
unsigned idau_region:8;
|
||||
unsigned idau_region_valid:1;
|
||||
unsigned secure:1;
|
||||
unsigned nonsecure_readwrite_ok:1;
|
||||
unsigned nonsecure_read_ok:1;
|
||||
#else
|
||||
unsigned :12;
|
||||
#endif
|
||||
unsigned readwrite_ok:1;
|
||||
unsigned read_ok:1;
|
||||
#if __ARM_FEATURE_CMSE & 2
|
||||
unsigned sau_region_valid:1;
|
||||
#else
|
||||
unsigned :1;
|
||||
#endif
|
||||
unsigned mpu_region_valid:1;
|
||||
#if __ARM_FEATURE_CMSE & 2
|
||||
unsigned sau_region:8;
|
||||
#else
|
||||
unsigned :8;
|
||||
#endif
|
||||
unsigned mpu_region:8;
|
||||
} flags;
|
||||
unsigned value;
|
||||
} cmse_address_info_t;
|
||||
|
||||
#else
|
||||
|
||||
typedef union {
|
||||
struct cmse_address_info {
|
||||
unsigned mpu_region:8;
|
||||
#if __ARM_FEATURE_CMSE & 2
|
||||
unsigned sau_region:8;
|
||||
#else
|
||||
unsigned :8;
|
||||
#endif
|
||||
unsigned mpu_region_valid:1;
|
||||
#if __ARM_FEATURE_CMSE & 2
|
||||
unsigned sau_region_valid:1;
|
||||
#else
|
||||
unsigned :1;
|
||||
#endif
|
||||
unsigned read_ok:1;
|
||||
unsigned readwrite_ok:1;
|
||||
#if __ARM_FEATURE_CMSE & 2
|
||||
unsigned nonsecure_read_ok:1;
|
||||
unsigned nonsecure_readwrite_ok:1;
|
||||
unsigned secure:1;
|
||||
unsigned idau_region_valid:1;
|
||||
unsigned idau_region:8;
|
||||
#else
|
||||
unsigned :12;
|
||||
#endif
|
||||
} flags;
|
||||
unsigned value;
|
||||
} cmse_address_info_t;
|
||||
|
||||
#endif /* __ARM_BIG_ENDIAN */
|
||||
|
||||
#define cmse_TT_fptr(p) (__cmse_TT_fptr ((__cmse_fptr)(p)))
|
||||
|
||||
typedef void (*__cmse_fptr)(void);
|
||||
|
||||
#define __CMSE_TT_ASM(flags) \
|
||||
{ \
|
||||
cmse_address_info_t __result; \
|
||||
__asm__ ("tt" # flags " %0,%1" \
|
||||
: "=r"(__result) \
|
||||
: "r"(__p) \
|
||||
: "memory"); \
|
||||
return __result; \
|
||||
}
|
||||
|
||||
__extension__ static __inline __attribute__ ((__always_inline__))
|
||||
cmse_address_info_t
|
||||
__cmse_TT_fptr (__cmse_fptr __p)
|
||||
__CMSE_TT_ASM ()
|
||||
|
||||
__extension__ static __inline __attribute__ ((__always_inline__))
|
||||
cmse_address_info_t
|
||||
cmse_TT (void *__p)
|
||||
__CMSE_TT_ASM ()
|
||||
|
||||
#define cmse_TTT_fptr(p) (__cmse_TTT_fptr ((__cmse_fptr)(p)))
|
||||
|
||||
__extension__ static __inline __attribute__ ((__always_inline__))
|
||||
cmse_address_info_t
|
||||
__cmse_TTT_fptr (__cmse_fptr __p)
|
||||
__CMSE_TT_ASM (t)
|
||||
|
||||
__extension__ static __inline __attribute__ ((__always_inline__))
|
||||
cmse_address_info_t
|
||||
cmse_TTT (void *__p)
|
||||
__CMSE_TT_ASM (t)
|
||||
|
||||
#if __ARM_FEATURE_CMSE & 2
|
||||
|
||||
#define cmse_TTA_fptr(p) (__cmse_TTA_fptr ((__cmse_fptr)(p)))
|
||||
|
||||
__extension__ static __inline __attribute__ ((__always_inline__))
|
||||
cmse_address_info_t
|
||||
__cmse_TTA_fptr (__cmse_fptr __p)
|
||||
__CMSE_TT_ASM (a)
|
||||
|
||||
__extension__ static __inline __attribute__ ((__always_inline__))
|
||||
cmse_address_info_t
|
||||
cmse_TTA (void *__p)
|
||||
__CMSE_TT_ASM (a)
|
||||
|
||||
#define cmse_TTAT_fptr(p) (__cmse_TTAT_fptr ((__cmse_fptr)(p)))
|
||||
|
||||
__extension__ static __inline cmse_address_info_t
|
||||
__attribute__ ((__always_inline__))
|
||||
__cmse_TTAT_fptr (__cmse_fptr __p)
|
||||
__CMSE_TT_ASM (at)
|
||||
|
||||
__extension__ static __inline cmse_address_info_t
|
||||
__attribute__ ((__always_inline__))
|
||||
cmse_TTAT (void *__p)
|
||||
__CMSE_TT_ASM (at)
|
||||
|
||||
/* FIXME: diagnose use outside cmse_nonsecure_entry functions. */
|
||||
__extension__ static __inline int __attribute__ ((__always_inline__))
|
||||
__attribute__ ((warn_unused_result))
|
||||
cmse_nonsecure_caller (void)
|
||||
{
|
||||
return __builtin_arm_cmse_nonsecure_caller ();
|
||||
}
|
||||
|
||||
#define CMSE_AU_NONSECURE 2
|
||||
#define CMSE_MPU_NONSECURE 16
|
||||
#define CMSE_NONSECURE 18
|
||||
|
||||
#define cmse_nsfptr_create(p) ((__typeof__ ((p))) ((__INTPTR_TYPE__) (p) & ~1))
|
||||
|
||||
#define cmse_is_nsfptr(p) (!((__INTPTR_TYPE__) (p) & 1))
|
||||
|
||||
#endif /* __ARM_FEATURE_CMSE & 2 */
|
||||
|
||||
#define CMSE_MPU_UNPRIV 4
|
||||
#define CMSE_MPU_READWRITE 1
|
||||
#define CMSE_MPU_READ 8
|
||||
|
||||
__extension__ void *
|
||||
__attribute__ ((warn_unused_result))
|
||||
cmse_check_address_range (void *, size_t, int);
|
||||
|
||||
#define cmse_check_pointed_object(p, f) \
|
||||
((__typeof__ ((p))) cmse_check_address_range ((p), sizeof (*(p)), (f)))
|
||||
|
||||
#endif /* __ARM_FEATURE_CMSE & 1 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _GCC_ARM_CMSE_H */
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
/* ARM FP16 intrinsics include file.
|
||||
|
||||
Copyright (C) 2016-2024 Free Software Foundation, Inc.
|
||||
Contributed by ARM Ltd.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _GCC_ARM_FP16_H
|
||||
#define _GCC_ARM_FP16_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Intrinsics for FP16 instructions. */
|
||||
#pragma GCC push_options
|
||||
#pragma GCC target ("fpu=fp-armv8")
|
||||
|
||||
#if defined (__ARM_FEATURE_FP16_SCALAR_ARITHMETIC)
|
||||
|
||||
typedef __fp16 float16_t;
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vabsh_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vabshf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vaddh_f16 (float16_t __a, float16_t __b)
|
||||
{
|
||||
return __a + __b;
|
||||
}
|
||||
|
||||
__extension__ static __inline int32_t __attribute__ ((__always_inline__))
|
||||
vcvtah_s32_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvtahssi (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
vcvtah_u32_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvtahusi (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vcvth_f16_s32 (int32_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvthshf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vcvth_f16_u32 (uint32_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvthuhf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vcvth_n_f16_s32 (int32_t __a, const int __b)
|
||||
{
|
||||
return __builtin_neon_vcvths_nhf (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vcvth_n_f16_u32 (uint32_t __a, const int __b)
|
||||
{
|
||||
return __builtin_neon_vcvthu_nhf ((int32_t)__a, __b);
|
||||
}
|
||||
|
||||
__extension__ static __inline int32_t __attribute__ ((__always_inline__))
|
||||
vcvth_n_s32_f16 (float16_t __a, const int __b)
|
||||
{
|
||||
return __builtin_neon_vcvths_nsi (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
vcvth_n_u32_f16 (float16_t __a, const int __b)
|
||||
{
|
||||
return (uint32_t)__builtin_neon_vcvthu_nsi (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ static __inline int32_t __attribute__ ((__always_inline__))
|
||||
vcvth_s32_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvthssi (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
vcvth_u32_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvthusi (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline int32_t __attribute__ ((__always_inline__))
|
||||
vcvtmh_s32_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvtmhssi (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
vcvtmh_u32_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvtmhusi (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline int32_t __attribute__ ((__always_inline__))
|
||||
vcvtnh_s32_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvtnhssi (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
vcvtnh_u32_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvtnhusi (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline int32_t __attribute__ ((__always_inline__))
|
||||
vcvtph_s32_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvtphssi (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline uint32_t __attribute__ ((__always_inline__))
|
||||
vcvtph_u32_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vcvtphusi (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vdivh_f16 (float16_t __a, float16_t __b)
|
||||
{
|
||||
return __a / __b;
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vfmah_f16 (float16_t __a, float16_t __b, float16_t __c)
|
||||
{
|
||||
return __builtin_neon_vfmahf (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vfmsh_f16 (float16_t __a, float16_t __b, float16_t __c)
|
||||
{
|
||||
return __builtin_neon_vfmshf (__a, __b, __c);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vmaxnmh_f16 (float16_t __a, float16_t __b)
|
||||
{
|
||||
return __builtin_neon_vmaxnmhf (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vminnmh_f16 (float16_t __a, float16_t __b)
|
||||
{
|
||||
return __builtin_neon_vminnmhf (__a, __b);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vmulh_f16 (float16_t __a, float16_t __b)
|
||||
{
|
||||
return __a * __b;
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vnegh_f16 (float16_t __a)
|
||||
{
|
||||
return - __a;
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vrndah_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vrndahf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vrndh_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vrndhf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vrndih_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vrndihf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vrndmh_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vrndmhf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vrndnh_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vrndnhf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vrndph_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vrndphf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vrndxh_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vrndxhf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vsqrth_f16 (float16_t __a)
|
||||
{
|
||||
return __builtin_neon_vsqrthf (__a);
|
||||
}
|
||||
|
||||
__extension__ static __inline float16_t __attribute__ ((__always_inline__))
|
||||
vsubh_f16 (float16_t __a, float16_t __b)
|
||||
{
|
||||
return __a - __b;
|
||||
}
|
||||
|
||||
#endif /* __ARM_FEATURE_FP16_SCALAR_ARITHMETIC */
|
||||
#pragma GCC pop_options
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+9508
File diff suppressed because it is too large
Load Diff
+32
@@ -0,0 +1,32 @@
|
||||
/* Arm MVE intrinsics include file.
|
||||
|
||||
Copyright (C) 2020-2024 Free Software Foundation, Inc.
|
||||
Contributed by Arm.
|
||||
|
||||
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_ARM_MVE_TYPES_H
|
||||
#define _GCC_ARM_MVE_TYPES_H
|
||||
|
||||
#if (__ARM_FEATURE_MVE & 2) /* MVE Floating point. */
|
||||
typedef __fp16 float16_t;
|
||||
typedef float float32_t;
|
||||
#endif
|
||||
|
||||
#pragma GCC arm "arm_mve_types.h"
|
||||
|
||||
#endif /* _GCC_ARM_MVE_H. */
|
||||
+21492
File diff suppressed because it is too large
Load Diff
+631
@@ -0,0 +1,631 @@
|
||||
/* Copyright (C) 2002-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/*
|
||||
* ISO C Standard: 5.2.4.2.2 Characteristics of floating types <float.h>
|
||||
*/
|
||||
|
||||
#ifndef _FLOAT_H___
|
||||
#define _FLOAT_H___
|
||||
|
||||
/* Radix of exponent representation, b. */
|
||||
#undef FLT_RADIX
|
||||
#define FLT_RADIX __FLT_RADIX__
|
||||
|
||||
/* Number of base-FLT_RADIX digits in the significand, p. */
|
||||
#undef FLT_MANT_DIG
|
||||
#undef DBL_MANT_DIG
|
||||
#undef LDBL_MANT_DIG
|
||||
#define FLT_MANT_DIG __FLT_MANT_DIG__
|
||||
#define DBL_MANT_DIG __DBL_MANT_DIG__
|
||||
#define LDBL_MANT_DIG __LDBL_MANT_DIG__
|
||||
|
||||
/* Number of decimal digits, q, such that any floating-point number with q
|
||||
decimal digits can be rounded into a floating-point number with p radix b
|
||||
digits and back again without change to the q decimal digits,
|
||||
|
||||
p * log10(b) if b is a power of 10
|
||||
floor((p - 1) * log10(b)) otherwise
|
||||
*/
|
||||
#undef FLT_DIG
|
||||
#undef DBL_DIG
|
||||
#undef LDBL_DIG
|
||||
#define FLT_DIG __FLT_DIG__
|
||||
#define DBL_DIG __DBL_DIG__
|
||||
#define LDBL_DIG __LDBL_DIG__
|
||||
|
||||
/* Minimum int x such that FLT_RADIX**(x-1) is a normalized float, emin */
|
||||
#undef FLT_MIN_EXP
|
||||
#undef DBL_MIN_EXP
|
||||
#undef LDBL_MIN_EXP
|
||||
#define FLT_MIN_EXP __FLT_MIN_EXP__
|
||||
#define DBL_MIN_EXP __DBL_MIN_EXP__
|
||||
#define LDBL_MIN_EXP __LDBL_MIN_EXP__
|
||||
|
||||
/* Minimum negative integer such that 10 raised to that power is in the
|
||||
range of normalized floating-point numbers,
|
||||
|
||||
ceil(log10(b) * (emin - 1))
|
||||
*/
|
||||
#undef FLT_MIN_10_EXP
|
||||
#undef DBL_MIN_10_EXP
|
||||
#undef LDBL_MIN_10_EXP
|
||||
#define FLT_MIN_10_EXP __FLT_MIN_10_EXP__
|
||||
#define DBL_MIN_10_EXP __DBL_MIN_10_EXP__
|
||||
#define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__
|
||||
|
||||
/* Maximum int x such that FLT_RADIX**(x-1) is a representable float, emax. */
|
||||
#undef FLT_MAX_EXP
|
||||
#undef DBL_MAX_EXP
|
||||
#undef LDBL_MAX_EXP
|
||||
#define FLT_MAX_EXP __FLT_MAX_EXP__
|
||||
#define DBL_MAX_EXP __DBL_MAX_EXP__
|
||||
#define LDBL_MAX_EXP __LDBL_MAX_EXP__
|
||||
|
||||
/* Maximum integer such that 10 raised to that power is in the range of
|
||||
representable finite floating-point numbers,
|
||||
|
||||
floor(log10((1 - b**-p) * b**emax))
|
||||
*/
|
||||
#undef FLT_MAX_10_EXP
|
||||
#undef DBL_MAX_10_EXP
|
||||
#undef LDBL_MAX_10_EXP
|
||||
#define FLT_MAX_10_EXP __FLT_MAX_10_EXP__
|
||||
#define DBL_MAX_10_EXP __DBL_MAX_10_EXP__
|
||||
#define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__
|
||||
|
||||
/* Maximum representable finite floating-point number,
|
||||
|
||||
(1 - b**-p) * b**emax
|
||||
*/
|
||||
#undef FLT_MAX
|
||||
#undef DBL_MAX
|
||||
#undef LDBL_MAX
|
||||
#define FLT_MAX __FLT_MAX__
|
||||
#define DBL_MAX __DBL_MAX__
|
||||
#define LDBL_MAX __LDBL_MAX__
|
||||
|
||||
/* The difference between 1 and the least value greater than 1 that is
|
||||
representable in the given floating point type, b**1-p. */
|
||||
#undef FLT_EPSILON
|
||||
#undef DBL_EPSILON
|
||||
#undef LDBL_EPSILON
|
||||
#define FLT_EPSILON __FLT_EPSILON__
|
||||
#define DBL_EPSILON __DBL_EPSILON__
|
||||
#define LDBL_EPSILON __LDBL_EPSILON__
|
||||
|
||||
/* Minimum normalized positive floating-point number, b**(emin - 1). */
|
||||
#undef FLT_MIN
|
||||
#undef DBL_MIN
|
||||
#undef LDBL_MIN
|
||||
#define FLT_MIN __FLT_MIN__
|
||||
#define DBL_MIN __DBL_MIN__
|
||||
#define LDBL_MIN __LDBL_MIN__
|
||||
|
||||
/* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown. */
|
||||
/* ??? This is supposed to change with calls to fesetround in <fenv.h>. */
|
||||
#undef FLT_ROUNDS
|
||||
#define FLT_ROUNDS 1
|
||||
|
||||
#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \
|
||||
|| (defined (__cplusplus) && __cplusplus >= 201103L)
|
||||
/* The floating-point expression evaluation method. The precise
|
||||
definitions of these values are generalised to include support for
|
||||
the interchange and extended types defined in ISO/IEC TS 18661-3.
|
||||
Prior to this (for C99/C11) the definitions were:
|
||||
|
||||
-1 indeterminate
|
||||
0 evaluate all operations and constants just to the range and
|
||||
precision of the type
|
||||
1 evaluate operations and constants of type float and double
|
||||
to the range and precision of the double type, evaluate
|
||||
long double operations and constants to the range and
|
||||
precision of the long double type
|
||||
2 evaluate all operations and constants to the range and
|
||||
precision of the long double type
|
||||
|
||||
The TS 18661-3 definitions are:
|
||||
|
||||
-1 indeterminate
|
||||
0 evaluate all operations and constants, whose semantic type has
|
||||
at most the range and precision of float, to the range and
|
||||
precision of float; evaluate all other operations and constants
|
||||
to the range and precision of the semantic type.
|
||||
1 evaluate all operations and constants, whose semantic type has
|
||||
at most the range and precision of double, to the range and
|
||||
precision of double; evaluate all other operations and constants
|
||||
to the range and precision of the semantic type.
|
||||
2 evaluate all operations and constants, whose semantic type has
|
||||
at most the range and precision of long double, to the range and
|
||||
precision of long double; evaluate all other operations and
|
||||
constants to the range and precision of the semantic type.
|
||||
N where _FloatN is a supported interchange floating type
|
||||
evaluate all operations and constants, whose semantic type has
|
||||
at most the range and precision of the _FloatN type, to the
|
||||
range and precision of the _FloatN type; evaluate all other
|
||||
operations and constants to the range and precision of the
|
||||
semantic type.
|
||||
N + 1, where _FloatNx is a supported extended floating type
|
||||
evaluate operations and constants, whose semantic type has at
|
||||
most the range and precision of the _FloatNx type, to the range
|
||||
and precision of the _FloatNx type; evaluate all other
|
||||
operations and constants to the range and precision of the
|
||||
semantic type.
|
||||
|
||||
The compiler predefines two macros:
|
||||
|
||||
__FLT_EVAL_METHOD__
|
||||
Which, depending on the value given for
|
||||
-fpermitted-flt-eval-methods, may be limited to only those values
|
||||
for FLT_EVAL_METHOD defined in C99/C11.
|
||||
|
||||
__FLT_EVAL_METHOD_TS_18661_3__
|
||||
Which always permits the values for FLT_EVAL_METHOD defined in
|
||||
ISO/IEC TS 18661-3.
|
||||
|
||||
Here we want to use __FLT_EVAL_METHOD__, unless
|
||||
__STDC_WANT_IEC_60559_TYPES_EXT__ is defined, in which case the user
|
||||
is specifically asking for the ISO/IEC TS 18661-3 types, so we use
|
||||
__FLT_EVAL_METHOD_TS_18661_3__.
|
||||
|
||||
??? This ought to change with the setting of the fp control word;
|
||||
the value provided by the compiler assumes the widest setting. */
|
||||
#undef FLT_EVAL_METHOD
|
||||
#ifdef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
#define FLT_EVAL_METHOD __FLT_EVAL_METHOD_TS_18661_3__
|
||||
#else
|
||||
#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
|
||||
#endif
|
||||
|
||||
/* Number of decimal digits, n, such that any floating-point number in the
|
||||
widest supported floating type with pmax radix b digits can be rounded
|
||||
to a floating-point number with n decimal digits and back again without
|
||||
change to the value,
|
||||
|
||||
pmax * log10(b) if b is a power of 10
|
||||
ceil(1 + pmax * log10(b)) otherwise
|
||||
*/
|
||||
#undef DECIMAL_DIG
|
||||
#define DECIMAL_DIG __DECIMAL_DIG__
|
||||
|
||||
#endif /* C99 */
|
||||
|
||||
#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|
||||
|| (defined (__cplusplus) && __cplusplus >= 201703L)
|
||||
/* Versions of DECIMAL_DIG for each floating-point type. */
|
||||
#undef FLT_DECIMAL_DIG
|
||||
#undef DBL_DECIMAL_DIG
|
||||
#undef LDBL_DECIMAL_DIG
|
||||
#define FLT_DECIMAL_DIG __FLT_DECIMAL_DIG__
|
||||
#define DBL_DECIMAL_DIG __DBL_DECIMAL_DIG__
|
||||
#define LDBL_DECIMAL_DIG __LDBL_DECIMAL_DIG__
|
||||
|
||||
/* Whether types support subnormal numbers. */
|
||||
#undef FLT_HAS_SUBNORM
|
||||
#undef DBL_HAS_SUBNORM
|
||||
#undef LDBL_HAS_SUBNORM
|
||||
#define FLT_HAS_SUBNORM __FLT_HAS_DENORM__
|
||||
#define DBL_HAS_SUBNORM __DBL_HAS_DENORM__
|
||||
#define LDBL_HAS_SUBNORM __LDBL_HAS_DENORM__
|
||||
|
||||
/* Minimum positive values, including subnormals. */
|
||||
#undef FLT_TRUE_MIN
|
||||
#undef DBL_TRUE_MIN
|
||||
#undef LDBL_TRUE_MIN
|
||||
#define FLT_TRUE_MIN __FLT_DENORM_MIN__
|
||||
#define DBL_TRUE_MIN __DBL_DENORM_MIN__
|
||||
#define LDBL_TRUE_MIN __LDBL_DENORM_MIN__
|
||||
|
||||
#endif /* C11 */
|
||||
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
/* Maximum finite positive value with MANT_DIG digits in the
|
||||
significand taking their maximum value. */
|
||||
#undef FLT_NORM_MAX
|
||||
#undef DBL_NORM_MAX
|
||||
#undef LDBL_NORM_MAX
|
||||
#define FLT_NORM_MAX __FLT_NORM_MAX__
|
||||
#define DBL_NORM_MAX __DBL_NORM_MAX__
|
||||
#define LDBL_NORM_MAX __LDBL_NORM_MAX__
|
||||
|
||||
/* Whether each type matches an IEC 60559 format. */
|
||||
#undef FLT_IS_IEC_60559
|
||||
#undef DBL_IS_IEC_60559
|
||||
#undef LDBL_IS_IEC_60559
|
||||
#define FLT_IS_IEC_60559 __FLT_IS_IEC_60559__
|
||||
#define DBL_IS_IEC_60559 __DBL_IS_IEC_60559__
|
||||
#define LDBL_IS_IEC_60559 __LDBL_IS_IEC_60559__
|
||||
|
||||
/* Infinity in type float; not defined if infinity not supported. */
|
||||
#if __FLT_HAS_INFINITY__
|
||||
#undef INFINITY
|
||||
#define INFINITY (__builtin_inff ())
|
||||
#endif
|
||||
|
||||
/* Quiet NaN, if supported for float. */
|
||||
#if __FLT_HAS_QUIET_NAN__
|
||||
#undef NAN
|
||||
#define NAN (__builtin_nanf (""))
|
||||
#endif
|
||||
|
||||
/* Signaling NaN, if supported for each type. All formats supported
|
||||
by GCC support either both quiet and signaling NaNs, or neither
|
||||
kind of NaN. */
|
||||
#if __FLT_HAS_QUIET_NAN__
|
||||
#undef FLT_SNAN
|
||||
#define FLT_SNAN (__builtin_nansf (""))
|
||||
#endif
|
||||
#if __DBL_HAS_QUIET_NAN__
|
||||
#undef DBL_SNAN
|
||||
#define DBL_SNAN (__builtin_nans (""))
|
||||
#endif
|
||||
#if __LDBL_HAS_QUIET_NAN__
|
||||
#undef LDBL_SNAN
|
||||
#define LDBL_SNAN (__builtin_nansl (""))
|
||||
#endif
|
||||
|
||||
#endif /* C23 */
|
||||
|
||||
#if (defined __STDC_WANT_IEC_60559_BFP_EXT__ \
|
||||
|| defined __STDC_WANT_IEC_60559_EXT__)
|
||||
/* Number of decimal digits for which conversions between decimal
|
||||
character strings and binary formats, in both directions, are
|
||||
correctly rounded. */
|
||||
#define CR_DECIMAL_DIG __UINTMAX_MAX__
|
||||
#endif
|
||||
|
||||
#ifdef __STDC_WANT_IEC_60559_TYPES_EXT__
|
||||
/* Constants for _FloatN and _FloatNx types from TS 18661-3. See
|
||||
comments above for their semantics. */
|
||||
|
||||
#ifdef __FLT16_MANT_DIG__
|
||||
#undef FLT16_MANT_DIG
|
||||
#define FLT16_MANT_DIG __FLT16_MANT_DIG__
|
||||
#undef FLT16_DIG
|
||||
#define FLT16_DIG __FLT16_DIG__
|
||||
#undef FLT16_MIN_EXP
|
||||
#define FLT16_MIN_EXP __FLT16_MIN_EXP__
|
||||
#undef FLT16_MIN_10_EXP
|
||||
#define FLT16_MIN_10_EXP __FLT16_MIN_10_EXP__
|
||||
#undef FLT16_MAX_EXP
|
||||
#define FLT16_MAX_EXP __FLT16_MAX_EXP__
|
||||
#undef FLT16_MAX_10_EXP
|
||||
#define FLT16_MAX_10_EXP __FLT16_MAX_10_EXP__
|
||||
#undef FLT16_MAX
|
||||
#define FLT16_MAX __FLT16_MAX__
|
||||
#undef FLT16_EPSILON
|
||||
#define FLT16_EPSILON __FLT16_EPSILON__
|
||||
#undef FLT16_MIN
|
||||
#define FLT16_MIN __FLT16_MIN__
|
||||
#undef FLT16_DECIMAL_DIG
|
||||
#define FLT16_DECIMAL_DIG __FLT16_DECIMAL_DIG__
|
||||
#undef FLT16_TRUE_MIN
|
||||
#define FLT16_TRUE_MIN __FLT16_DENORM_MIN__
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#undef FLT16_SNAN
|
||||
#define FLT16_SNAN (__builtin_nansf16 (""))
|
||||
#endif /* C23 */
|
||||
#endif /* __FLT16_MANT_DIG__. */
|
||||
|
||||
#ifdef __FLT32_MANT_DIG__
|
||||
#undef FLT32_MANT_DIG
|
||||
#define FLT32_MANT_DIG __FLT32_MANT_DIG__
|
||||
#undef FLT32_DIG
|
||||
#define FLT32_DIG __FLT32_DIG__
|
||||
#undef FLT32_MIN_EXP
|
||||
#define FLT32_MIN_EXP __FLT32_MIN_EXP__
|
||||
#undef FLT32_MIN_10_EXP
|
||||
#define FLT32_MIN_10_EXP __FLT32_MIN_10_EXP__
|
||||
#undef FLT32_MAX_EXP
|
||||
#define FLT32_MAX_EXP __FLT32_MAX_EXP__
|
||||
#undef FLT32_MAX_10_EXP
|
||||
#define FLT32_MAX_10_EXP __FLT32_MAX_10_EXP__
|
||||
#undef FLT32_MAX
|
||||
#define FLT32_MAX __FLT32_MAX__
|
||||
#undef FLT32_EPSILON
|
||||
#define FLT32_EPSILON __FLT32_EPSILON__
|
||||
#undef FLT32_MIN
|
||||
#define FLT32_MIN __FLT32_MIN__
|
||||
#undef FLT32_DECIMAL_DIG
|
||||
#define FLT32_DECIMAL_DIG __FLT32_DECIMAL_DIG__
|
||||
#undef FLT32_TRUE_MIN
|
||||
#define FLT32_TRUE_MIN __FLT32_DENORM_MIN__
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#undef FLT32_SNAN
|
||||
#define FLT32_SNAN (__builtin_nansf32 (""))
|
||||
#endif /* C23 */
|
||||
#endif /* __FLT32_MANT_DIG__. */
|
||||
|
||||
#ifdef __FLT64_MANT_DIG__
|
||||
#undef FLT64_MANT_DIG
|
||||
#define FLT64_MANT_DIG __FLT64_MANT_DIG__
|
||||
#undef FLT64_DIG
|
||||
#define FLT64_DIG __FLT64_DIG__
|
||||
#undef FLT64_MIN_EXP
|
||||
#define FLT64_MIN_EXP __FLT64_MIN_EXP__
|
||||
#undef FLT64_MIN_10_EXP
|
||||
#define FLT64_MIN_10_EXP __FLT64_MIN_10_EXP__
|
||||
#undef FLT64_MAX_EXP
|
||||
#define FLT64_MAX_EXP __FLT64_MAX_EXP__
|
||||
#undef FLT64_MAX_10_EXP
|
||||
#define FLT64_MAX_10_EXP __FLT64_MAX_10_EXP__
|
||||
#undef FLT64_MAX
|
||||
#define FLT64_MAX __FLT64_MAX__
|
||||
#undef FLT64_EPSILON
|
||||
#define FLT64_EPSILON __FLT64_EPSILON__
|
||||
#undef FLT64_MIN
|
||||
#define FLT64_MIN __FLT64_MIN__
|
||||
#undef FLT64_DECIMAL_DIG
|
||||
#define FLT64_DECIMAL_DIG __FLT64_DECIMAL_DIG__
|
||||
#undef FLT64_TRUE_MIN
|
||||
#define FLT64_TRUE_MIN __FLT64_DENORM_MIN__
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#undef FLT64_SNAN
|
||||
#define FLT64_SNAN (__builtin_nansf64 (""))
|
||||
#endif /* C23 */
|
||||
#endif /* __FLT64_MANT_DIG__. */
|
||||
|
||||
#ifdef __FLT128_MANT_DIG__
|
||||
#undef FLT128_MANT_DIG
|
||||
#define FLT128_MANT_DIG __FLT128_MANT_DIG__
|
||||
#undef FLT128_DIG
|
||||
#define FLT128_DIG __FLT128_DIG__
|
||||
#undef FLT128_MIN_EXP
|
||||
#define FLT128_MIN_EXP __FLT128_MIN_EXP__
|
||||
#undef FLT128_MIN_10_EXP
|
||||
#define FLT128_MIN_10_EXP __FLT128_MIN_10_EXP__
|
||||
#undef FLT128_MAX_EXP
|
||||
#define FLT128_MAX_EXP __FLT128_MAX_EXP__
|
||||
#undef FLT128_MAX_10_EXP
|
||||
#define FLT128_MAX_10_EXP __FLT128_MAX_10_EXP__
|
||||
#undef FLT128_MAX
|
||||
#define FLT128_MAX __FLT128_MAX__
|
||||
#undef FLT128_EPSILON
|
||||
#define FLT128_EPSILON __FLT128_EPSILON__
|
||||
#undef FLT128_MIN
|
||||
#define FLT128_MIN __FLT128_MIN__
|
||||
#undef FLT128_DECIMAL_DIG
|
||||
#define FLT128_DECIMAL_DIG __FLT128_DECIMAL_DIG__
|
||||
#undef FLT128_TRUE_MIN
|
||||
#define FLT128_TRUE_MIN __FLT128_DENORM_MIN__
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#undef FLT128_SNAN
|
||||
#define FLT128_SNAN (__builtin_nansf128 (""))
|
||||
#endif /* C23 */
|
||||
#endif /* __FLT128_MANT_DIG__. */
|
||||
|
||||
#ifdef __FLT32X_MANT_DIG__
|
||||
#undef FLT32X_MANT_DIG
|
||||
#define FLT32X_MANT_DIG __FLT32X_MANT_DIG__
|
||||
#undef FLT32X_DIG
|
||||
#define FLT32X_DIG __FLT32X_DIG__
|
||||
#undef FLT32X_MIN_EXP
|
||||
#define FLT32X_MIN_EXP __FLT32X_MIN_EXP__
|
||||
#undef FLT32X_MIN_10_EXP
|
||||
#define FLT32X_MIN_10_EXP __FLT32X_MIN_10_EXP__
|
||||
#undef FLT32X_MAX_EXP
|
||||
#define FLT32X_MAX_EXP __FLT32X_MAX_EXP__
|
||||
#undef FLT32X_MAX_10_EXP
|
||||
#define FLT32X_MAX_10_EXP __FLT32X_MAX_10_EXP__
|
||||
#undef FLT32X_MAX
|
||||
#define FLT32X_MAX __FLT32X_MAX__
|
||||
#undef FLT32X_EPSILON
|
||||
#define FLT32X_EPSILON __FLT32X_EPSILON__
|
||||
#undef FLT32X_MIN
|
||||
#define FLT32X_MIN __FLT32X_MIN__
|
||||
#undef FLT32X_DECIMAL_DIG
|
||||
#define FLT32X_DECIMAL_DIG __FLT32X_DECIMAL_DIG__
|
||||
#undef FLT32X_TRUE_MIN
|
||||
#define FLT32X_TRUE_MIN __FLT32X_DENORM_MIN__
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#undef FLT32X_SNAN
|
||||
#define FLT32X_SNAN (__builtin_nansf32x (""))
|
||||
#endif /* C23 */
|
||||
#endif /* __FLT32X_MANT_DIG__. */
|
||||
|
||||
#ifdef __FLT64X_MANT_DIG__
|
||||
#undef FLT64X_MANT_DIG
|
||||
#define FLT64X_MANT_DIG __FLT64X_MANT_DIG__
|
||||
#undef FLT64X_DIG
|
||||
#define FLT64X_DIG __FLT64X_DIG__
|
||||
#undef FLT64X_MIN_EXP
|
||||
#define FLT64X_MIN_EXP __FLT64X_MIN_EXP__
|
||||
#undef FLT64X_MIN_10_EXP
|
||||
#define FLT64X_MIN_10_EXP __FLT64X_MIN_10_EXP__
|
||||
#undef FLT64X_MAX_EXP
|
||||
#define FLT64X_MAX_EXP __FLT64X_MAX_EXP__
|
||||
#undef FLT64X_MAX_10_EXP
|
||||
#define FLT64X_MAX_10_EXP __FLT64X_MAX_10_EXP__
|
||||
#undef FLT64X_MAX
|
||||
#define FLT64X_MAX __FLT64X_MAX__
|
||||
#undef FLT64X_EPSILON
|
||||
#define FLT64X_EPSILON __FLT64X_EPSILON__
|
||||
#undef FLT64X_MIN
|
||||
#define FLT64X_MIN __FLT64X_MIN__
|
||||
#undef FLT64X_DECIMAL_DIG
|
||||
#define FLT64X_DECIMAL_DIG __FLT64X_DECIMAL_DIG__
|
||||
#undef FLT64X_TRUE_MIN
|
||||
#define FLT64X_TRUE_MIN __FLT64X_DENORM_MIN__
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#undef FLT64X_SNAN
|
||||
#define FLT64X_SNAN (__builtin_nansf64x (""))
|
||||
#endif /* C23 */
|
||||
#endif /* __FLT64X_MANT_DIG__. */
|
||||
|
||||
#ifdef __FLT128X_MANT_DIG__
|
||||
#undef FLT128X_MANT_DIG
|
||||
#define FLT128X_MANT_DIG __FLT128X_MANT_DIG__
|
||||
#undef FLT128X_DIG
|
||||
#define FLT128X_DIG __FLT128X_DIG__
|
||||
#undef FLT128X_MIN_EXP
|
||||
#define FLT128X_MIN_EXP __FLT128X_MIN_EXP__
|
||||
#undef FLT128X_MIN_10_EXP
|
||||
#define FLT128X_MIN_10_EXP __FLT128X_MIN_10_EXP__
|
||||
#undef FLT128X_MAX_EXP
|
||||
#define FLT128X_MAX_EXP __FLT128X_MAX_EXP__
|
||||
#undef FLT128X_MAX_10_EXP
|
||||
#define FLT128X_MAX_10_EXP __FLT128X_MAX_10_EXP__
|
||||
#undef FLT128X_MAX
|
||||
#define FLT128X_MAX __FLT128X_MAX__
|
||||
#undef FLT128X_EPSILON
|
||||
#define FLT128X_EPSILON __FLT128X_EPSILON__
|
||||
#undef FLT128X_MIN
|
||||
#define FLT128X_MIN __FLT128X_MIN__
|
||||
#undef FLT128X_DECIMAL_DIG
|
||||
#define FLT128X_DECIMAL_DIG __FLT128X_DECIMAL_DIG__
|
||||
#undef FLT128X_TRUE_MIN
|
||||
#define FLT128X_TRUE_MIN __FLT128X_DENORM_MIN__
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#undef FLT128X_SNAN
|
||||
#define FLT128X_SNAN (__builtin_nansf128x (""))
|
||||
#endif /* C23 */
|
||||
#endif /* __FLT128X_MANT_DIG__. */
|
||||
|
||||
#endif /* __STDC_WANT_IEC_60559_TYPES_EXT__. */
|
||||
|
||||
#ifdef __DEC32_MANT_DIG__
|
||||
#if (defined __STDC_WANT_DEC_FP__ \
|
||||
|| defined __STDC_WANT_IEC_60559_DFP_EXT__ \
|
||||
|| (defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L))
|
||||
/* C23; formerly Technical Report 24732, extension for decimal
|
||||
floating-point arithmetic: Characteristic of decimal floating types
|
||||
<float.h>, and TS 18661-2. */
|
||||
|
||||
/* Number of base-FLT_RADIX digits in the significand, p. */
|
||||
#undef DEC32_MANT_DIG
|
||||
#undef DEC64_MANT_DIG
|
||||
#undef DEC128_MANT_DIG
|
||||
#define DEC32_MANT_DIG __DEC32_MANT_DIG__
|
||||
#define DEC64_MANT_DIG __DEC64_MANT_DIG__
|
||||
#define DEC128_MANT_DIG __DEC128_MANT_DIG__
|
||||
|
||||
/* Minimum exponent. */
|
||||
#undef DEC32_MIN_EXP
|
||||
#undef DEC64_MIN_EXP
|
||||
#undef DEC128_MIN_EXP
|
||||
#define DEC32_MIN_EXP __DEC32_MIN_EXP__
|
||||
#define DEC64_MIN_EXP __DEC64_MIN_EXP__
|
||||
#define DEC128_MIN_EXP __DEC128_MIN_EXP__
|
||||
|
||||
/* Maximum exponent. */
|
||||
#undef DEC32_MAX_EXP
|
||||
#undef DEC64_MAX_EXP
|
||||
#undef DEC128_MAX_EXP
|
||||
#define DEC32_MAX_EXP __DEC32_MAX_EXP__
|
||||
#define DEC64_MAX_EXP __DEC64_MAX_EXP__
|
||||
#define DEC128_MAX_EXP __DEC128_MAX_EXP__
|
||||
|
||||
/* Maximum representable finite decimal floating-point number
|
||||
(there are 6, 15, and 33 9s after the decimal points respectively). */
|
||||
#undef DEC32_MAX
|
||||
#undef DEC64_MAX
|
||||
#undef DEC128_MAX
|
||||
#define DEC32_MAX __DEC32_MAX__
|
||||
#define DEC64_MAX __DEC64_MAX__
|
||||
#define DEC128_MAX __DEC128_MAX__
|
||||
|
||||
/* The difference between 1 and the least value greater than 1 that is
|
||||
representable in the given floating point type. */
|
||||
#undef DEC32_EPSILON
|
||||
#undef DEC64_EPSILON
|
||||
#undef DEC128_EPSILON
|
||||
#define DEC32_EPSILON __DEC32_EPSILON__
|
||||
#define DEC64_EPSILON __DEC64_EPSILON__
|
||||
#define DEC128_EPSILON __DEC128_EPSILON__
|
||||
|
||||
/* Minimum normalized positive floating-point number. */
|
||||
#undef DEC32_MIN
|
||||
#undef DEC64_MIN
|
||||
#undef DEC128_MIN
|
||||
#define DEC32_MIN __DEC32_MIN__
|
||||
#define DEC64_MIN __DEC64_MIN__
|
||||
#define DEC128_MIN __DEC128_MIN__
|
||||
|
||||
/* The floating-point expression evaluation method.
|
||||
-1 indeterminate
|
||||
0 evaluate all operations and constants just to the range and
|
||||
precision of the type
|
||||
1 evaluate operations and constants of type _Decimal32
|
||||
and _Decimal64 to the range and precision of the _Decimal64
|
||||
type, evaluate _Decimal128 operations and constants to the
|
||||
range and precision of the _Decimal128 type;
|
||||
2 evaluate all operations and constants to the range and
|
||||
precision of the _Decimal128 type. */
|
||||
|
||||
#undef DEC_EVAL_METHOD
|
||||
#define DEC_EVAL_METHOD __DEC_EVAL_METHOD__
|
||||
|
||||
#endif /* __STDC_WANT_DEC_FP__ || __STDC_WANT_IEC_60559_DFP_EXT__ || C23. */
|
||||
|
||||
#ifdef __STDC_WANT_DEC_FP__
|
||||
|
||||
/* Minimum subnormal positive floating-point number. */
|
||||
#undef DEC32_SUBNORMAL_MIN
|
||||
#undef DEC64_SUBNORMAL_MIN
|
||||
#undef DEC128_SUBNORMAL_MIN
|
||||
#define DEC32_SUBNORMAL_MIN __DEC32_SUBNORMAL_MIN__
|
||||
#define DEC64_SUBNORMAL_MIN __DEC64_SUBNORMAL_MIN__
|
||||
#define DEC128_SUBNORMAL_MIN __DEC128_SUBNORMAL_MIN__
|
||||
|
||||
#endif /* __STDC_WANT_DEC_FP__. */
|
||||
|
||||
#if (defined __STDC_WANT_IEC_60559_DFP_EXT__ \
|
||||
|| (defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L))
|
||||
|
||||
/* Minimum subnormal positive floating-point number. */
|
||||
#undef DEC32_TRUE_MIN
|
||||
#undef DEC64_TRUE_MIN
|
||||
#undef DEC128_TRUE_MIN
|
||||
#define DEC32_TRUE_MIN __DEC32_SUBNORMAL_MIN__
|
||||
#define DEC64_TRUE_MIN __DEC64_SUBNORMAL_MIN__
|
||||
#define DEC128_TRUE_MIN __DEC128_SUBNORMAL_MIN__
|
||||
|
||||
#endif /* __STDC_WANT_IEC_60559_DFP_EXT__ || C23. */
|
||||
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
|
||||
/* Infinity in type _Decimal32. */
|
||||
#undef DEC_INFINITY
|
||||
#define DEC_INFINITY (__builtin_infd32 ())
|
||||
|
||||
/* Quiet NaN in type _Decimal32. */
|
||||
#undef DEC_NAN
|
||||
#define DEC_NAN (__builtin_nand32 (""))
|
||||
|
||||
/* Signaling NaN in each decimal floating-point type. */
|
||||
#undef DEC32_SNAN
|
||||
#define DEC32_SNAN (__builtin_nansd32 (""))
|
||||
#undef DEC64_SNAN
|
||||
#define DEC64_SNAN (__builtin_nansd64 (""))
|
||||
#undef DEC128_SNAN
|
||||
#define DEC128_SNAN (__builtin_nansd128 (""))
|
||||
|
||||
#endif /* C23 */
|
||||
|
||||
#endif /* __DEC32_MANT_DIG__ */
|
||||
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#define __STDC_VERSION_FLOAT_H__ 202311L
|
||||
#endif
|
||||
|
||||
#endif /* _FLOAT_H___ */
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/* GCOV interface routines.
|
||||
Copyright (C) 2017-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GCC_GCOV_H
|
||||
#define GCC_GCOV_H
|
||||
|
||||
struct gcov_info;
|
||||
|
||||
/* Set all counters to zero. */
|
||||
|
||||
extern void __gcov_reset (void);
|
||||
|
||||
/* Write profile information to a file. */
|
||||
|
||||
extern void __gcov_dump (void);
|
||||
|
||||
/* Convert the gcov information referenced by INFO to a gcda data stream.
|
||||
The FILENAME_FN callback is called exactly once with the filename associated
|
||||
with the gcov information. The filename may be NULL. Afterwards, the
|
||||
DUMP_FN callback is subsequently called with chunks (the begin and length of
|
||||
the chunk are passed as the first two callback parameters) of the gcda data
|
||||
stream. The ALLOCATE_FN callback shall allocate memory with a size in
|
||||
characters specified by the first callback parameter. The ARG parameter is
|
||||
a user-provided argument passed as the last argument to the callback
|
||||
functions. It is recommended to use the __gcov_filename_to_gcfn()
|
||||
in the filename callback function. */
|
||||
|
||||
extern void
|
||||
__gcov_info_to_gcda (const struct gcov_info *__info,
|
||||
void (*__filename_fn) (const char *, void *),
|
||||
void (*__dump_fn) (const void *, unsigned, void *),
|
||||
void *(*__allocate_fn) (unsigned, void *),
|
||||
void *__arg);
|
||||
|
||||
/* Convert the FILENAME to a gcfn data stream. The DUMP_FN callback is
|
||||
subsequently called with chunks (the begin and length of the chunk are
|
||||
passed as the first two callback parameters) of the gcfn data stream.
|
||||
The ARG parameter is a user-provided argument passed as the last
|
||||
argument to the DUMP_FN callback function. This function is intended
|
||||
to be used by the filename callback of __gcov_info_to_gcda(). The gcfn
|
||||
data stream is used by the merge-stream subcommand of the gcov-tool to
|
||||
get the filename associated with a gcda data stream. */
|
||||
|
||||
extern void
|
||||
__gcov_filename_to_gcfn (const char *__filename,
|
||||
void (*__dump_fn) (const void *, unsigned, void *),
|
||||
void *__arg);
|
||||
|
||||
#endif /* GCC_GCOV_H */
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/* Copyright (C) 1997-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/*
|
||||
* ISO C Standard: 7.9 Alternative spellings <iso646.h>
|
||||
*/
|
||||
|
||||
#ifndef _ISO646_H
|
||||
#define _ISO646_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#define and &&
|
||||
#define and_eq &=
|
||||
#define bitand &
|
||||
#define bitor |
|
||||
#define compl ~
|
||||
#define not !
|
||||
#define not_eq !=
|
||||
#define or ||
|
||||
#define or_eq |=
|
||||
#define xor ^
|
||||
#define xor_eq ^=
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
/* Copyright (C) 1992-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This administrivia gets added to the beginning of limits.h
|
||||
if the system has its own version of limits.h. */
|
||||
|
||||
/* We use _GCC_LIMITS_H_ because we want this not to match
|
||||
any macros that the system's limits.h uses for its own purposes. */
|
||||
#ifndef _GCC_LIMITS_H_ /* Terminated in limity.h. */
|
||||
#define _GCC_LIMITS_H_
|
||||
|
||||
#ifndef _LIBC_LIMITS_H_
|
||||
/* Use "..." so that we find syslimits.h only in this same directory. */
|
||||
#include "syslimits.h"
|
||||
#endif
|
||||
/* Copyright (C) 1991-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _LIMITS_H___
|
||||
#define _LIMITS_H___
|
||||
|
||||
/* Number of bits in a `char'. */
|
||||
#undef CHAR_BIT
|
||||
#define CHAR_BIT __CHAR_BIT__
|
||||
|
||||
/* Maximum length of a multibyte character. */
|
||||
#ifndef MB_LEN_MAX
|
||||
#define MB_LEN_MAX 1
|
||||
#endif
|
||||
|
||||
/* Minimum and maximum values a `signed char' can hold. */
|
||||
#undef SCHAR_MIN
|
||||
#define SCHAR_MIN (-SCHAR_MAX - 1)
|
||||
#undef SCHAR_MAX
|
||||
#define SCHAR_MAX __SCHAR_MAX__
|
||||
|
||||
/* Maximum value an `unsigned char' can hold. (Minimum is 0). */
|
||||
#undef UCHAR_MAX
|
||||
#if __SCHAR_MAX__ == __INT_MAX__
|
||||
# define UCHAR_MAX (SCHAR_MAX * 2U + 1U)
|
||||
#else
|
||||
# define UCHAR_MAX (SCHAR_MAX * 2 + 1)
|
||||
#endif
|
||||
|
||||
/* Minimum and maximum values a `char' can hold. */
|
||||
#ifdef __CHAR_UNSIGNED__
|
||||
# undef CHAR_MIN
|
||||
# if __SCHAR_MAX__ == __INT_MAX__
|
||||
# define CHAR_MIN 0U
|
||||
# else
|
||||
# define CHAR_MIN 0
|
||||
# endif
|
||||
# undef CHAR_MAX
|
||||
# define CHAR_MAX UCHAR_MAX
|
||||
#else
|
||||
# undef CHAR_MIN
|
||||
# define CHAR_MIN SCHAR_MIN
|
||||
# undef CHAR_MAX
|
||||
# define CHAR_MAX SCHAR_MAX
|
||||
#endif
|
||||
|
||||
/* Minimum and maximum values a `signed short int' can hold. */
|
||||
#undef SHRT_MIN
|
||||
#define SHRT_MIN (-SHRT_MAX - 1)
|
||||
#undef SHRT_MAX
|
||||
#define SHRT_MAX __SHRT_MAX__
|
||||
|
||||
/* Maximum value an `unsigned short int' can hold. (Minimum is 0). */
|
||||
#undef USHRT_MAX
|
||||
#if __SHRT_MAX__ == __INT_MAX__
|
||||
# define USHRT_MAX (SHRT_MAX * 2U + 1U)
|
||||
#else
|
||||
# define USHRT_MAX (SHRT_MAX * 2 + 1)
|
||||
#endif
|
||||
|
||||
/* Minimum and maximum values a `signed int' can hold. */
|
||||
#undef INT_MIN
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
#undef INT_MAX
|
||||
#define INT_MAX __INT_MAX__
|
||||
|
||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0). */
|
||||
#undef UINT_MAX
|
||||
#define UINT_MAX (INT_MAX * 2U + 1U)
|
||||
|
||||
/* Minimum and maximum values a `signed long int' can hold.
|
||||
(Same as `int'). */
|
||||
#undef LONG_MIN
|
||||
#define LONG_MIN (-LONG_MAX - 1L)
|
||||
#undef LONG_MAX
|
||||
#define LONG_MAX __LONG_MAX__
|
||||
|
||||
/* Maximum value an `unsigned long int' can hold. (Minimum is 0). */
|
||||
#undef ULONG_MAX
|
||||
#define ULONG_MAX (LONG_MAX * 2UL + 1UL)
|
||||
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
/* Minimum and maximum values a `signed long long int' can hold. */
|
||||
# undef LLONG_MIN
|
||||
# define LLONG_MIN (-LLONG_MAX - 1LL)
|
||||
# undef LLONG_MAX
|
||||
# define LLONG_MAX __LONG_LONG_MAX__
|
||||
|
||||
/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */
|
||||
# undef ULLONG_MAX
|
||||
# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
|
||||
#endif
|
||||
|
||||
#if defined (__GNU_LIBRARY__) ? defined (__USE_GNU) : !defined (__STRICT_ANSI__)
|
||||
/* Minimum and maximum values a `signed long long int' can hold. */
|
||||
# undef LONG_LONG_MIN
|
||||
# define LONG_LONG_MIN (-LONG_LONG_MAX - 1LL)
|
||||
# undef LONG_LONG_MAX
|
||||
# define LONG_LONG_MAX __LONG_LONG_MAX__
|
||||
|
||||
/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */
|
||||
# undef ULONG_LONG_MAX
|
||||
# define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1ULL)
|
||||
#endif
|
||||
|
||||
#if (defined __STDC_WANT_IEC_60559_BFP_EXT__ \
|
||||
|| (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L))
|
||||
/* TS 18661-1 / C23 widths of integer types. */
|
||||
# undef CHAR_WIDTH
|
||||
# define CHAR_WIDTH __SCHAR_WIDTH__
|
||||
# undef SCHAR_WIDTH
|
||||
# define SCHAR_WIDTH __SCHAR_WIDTH__
|
||||
# undef UCHAR_WIDTH
|
||||
# define UCHAR_WIDTH __SCHAR_WIDTH__
|
||||
# undef SHRT_WIDTH
|
||||
# define SHRT_WIDTH __SHRT_WIDTH__
|
||||
# undef USHRT_WIDTH
|
||||
# define USHRT_WIDTH __SHRT_WIDTH__
|
||||
# undef INT_WIDTH
|
||||
# define INT_WIDTH __INT_WIDTH__
|
||||
# undef UINT_WIDTH
|
||||
# define UINT_WIDTH __INT_WIDTH__
|
||||
# undef LONG_WIDTH
|
||||
# define LONG_WIDTH __LONG_WIDTH__
|
||||
# undef ULONG_WIDTH
|
||||
# define ULONG_WIDTH __LONG_WIDTH__
|
||||
# undef LLONG_WIDTH
|
||||
# define LLONG_WIDTH __LONG_LONG_WIDTH__
|
||||
# undef ULLONG_WIDTH
|
||||
# define ULLONG_WIDTH __LONG_LONG_WIDTH__
|
||||
#endif
|
||||
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L
|
||||
/* C23 width and limit of _Bool. */
|
||||
# undef BOOL_MAX
|
||||
# define BOOL_MAX 1
|
||||
# undef BOOL_WIDTH
|
||||
# define BOOL_WIDTH 1
|
||||
|
||||
# ifdef __BITINT_MAXWIDTH__
|
||||
# undef BITINT_MAXWIDTH
|
||||
# define BITINT_MAXWIDTH __BITINT_MAXWIDTH__
|
||||
# endif
|
||||
|
||||
# define __STDC_VERSION_LIMITS_H__ 202311L
|
||||
#endif
|
||||
|
||||
#endif /* _LIMITS_H___ */
|
||||
/* This administrivia gets added to the end of limits.h
|
||||
if the system has its own version of limits.h. */
|
||||
|
||||
#else /* not _GCC_LIMITS_H_ */
|
||||
|
||||
#ifdef _GCC_NEXT_LIMITS_H
|
||||
#include_next <limits.h> /* recurse down to the real one */
|
||||
#endif
|
||||
|
||||
#endif /* not _GCC_LIMITS_H_ */
|
||||
+1839
File diff suppressed because it is too large
Load Diff
+40
@@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2011-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* ISO C1X: 7.15 Alignment <stdalign.h>. */
|
||||
|
||||
#ifndef _STDALIGN_H
|
||||
#define _STDALIGN_H
|
||||
|
||||
#if (!defined __cplusplus \
|
||||
&& !(defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L))
|
||||
|
||||
#define alignas _Alignas
|
||||
#define alignof _Alignof
|
||||
|
||||
#define __alignas_is_defined 1
|
||||
#define __alignof_is_defined 1
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* stdalign.h */
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/* Copyright (C) 1989-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/*
|
||||
* ISO C Standard: 7.15 Variable arguments <stdarg.h>
|
||||
*/
|
||||
|
||||
#ifndef _STDARG_H
|
||||
#ifndef _ANSI_STDARG_H_
|
||||
#ifndef __need___va_list
|
||||
#define _STDARG_H
|
||||
#define _ANSI_STDARG_H_
|
||||
#endif /* not __need___va_list */
|
||||
#undef __need___va_list
|
||||
|
||||
/* Define __gnuc_va_list. */
|
||||
|
||||
#ifndef __GNUC_VA_LIST
|
||||
#define __GNUC_VA_LIST
|
||||
typedef __builtin_va_list __gnuc_va_list;
|
||||
#endif
|
||||
|
||||
/* Define the standard macros for the user,
|
||||
if this invocation was from the user program. */
|
||||
#ifdef _STDARG_H
|
||||
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#define va_start(v, ...) __builtin_va_start(v, 0)
|
||||
#else
|
||||
#define va_start(v,l) __builtin_va_start(v,l)
|
||||
#endif
|
||||
#define va_end(v) __builtin_va_end(v)
|
||||
#define va_arg(v,l) __builtin_va_arg(v,l)
|
||||
#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L \
|
||||
|| __cplusplus + 0 >= 201103L
|
||||
#define va_copy(d,s) __builtin_va_copy(d,s)
|
||||
#endif
|
||||
#define __va_copy(d,s) __builtin_va_copy(d,s)
|
||||
|
||||
/* Define va_list, if desired, from __gnuc_va_list. */
|
||||
/* We deliberately do not define va_list when called from
|
||||
stdio.h, because ANSI C says that stdio.h is not supposed to define
|
||||
va_list. stdio.h needs to have access to that data type,
|
||||
but must not use that name. It should use the name __gnuc_va_list,
|
||||
which is safe because it is reserved for the implementation. */
|
||||
|
||||
#ifdef _BSD_VA_LIST
|
||||
#undef _BSD_VA_LIST
|
||||
#endif
|
||||
|
||||
#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST))
|
||||
/* SVR4.2 uses _VA_LIST for an internal alias for va_list,
|
||||
so we must avoid testing it and setting it here.
|
||||
SVR4 uses _VA_LIST as a flag in stdarg.h, but we should
|
||||
have no conflict with that. */
|
||||
#ifndef _VA_LIST_
|
||||
#define _VA_LIST_
|
||||
#ifdef __i860__
|
||||
#ifndef _VA_LIST
|
||||
#define _VA_LIST va_list
|
||||
#endif
|
||||
#endif /* __i860__ */
|
||||
typedef __gnuc_va_list va_list;
|
||||
#ifdef _SCO_DS
|
||||
#define __VA_LIST
|
||||
#endif
|
||||
#endif /* _VA_LIST_ */
|
||||
#else /* not __svr4__ || _SCO_DS */
|
||||
|
||||
/* The macro _VA_LIST_ is the same thing used by this file in Ultrix.
|
||||
But on BSD NET2 we must not test or define or undef it.
|
||||
(Note that the comments in NET 2's ansi.h
|
||||
are incorrect for _VA_LIST_--see stdio.h!) */
|
||||
#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT)
|
||||
/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */
|
||||
#ifndef _VA_LIST_DEFINED
|
||||
/* The macro _VA_LIST is used in SCO Unix 3.2. */
|
||||
#ifndef _VA_LIST
|
||||
/* The macro _VA_LIST_T_H is used in the Bull dpx2 */
|
||||
#ifndef _VA_LIST_T_H
|
||||
/* The macro __va_list__ is used by BeOS. */
|
||||
#ifndef __va_list__
|
||||
typedef __gnuc_va_list va_list;
|
||||
#endif /* not __va_list__ */
|
||||
#endif /* not _VA_LIST_T_H */
|
||||
#endif /* not _VA_LIST */
|
||||
#endif /* not _VA_LIST_DEFINED */
|
||||
#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__))
|
||||
#define _VA_LIST_
|
||||
#endif
|
||||
#ifndef _VA_LIST
|
||||
#define _VA_LIST
|
||||
#endif
|
||||
#ifndef _VA_LIST_DEFINED
|
||||
#define _VA_LIST_DEFINED
|
||||
#endif
|
||||
#ifndef _VA_LIST_T_H
|
||||
#define _VA_LIST_T_H
|
||||
#endif
|
||||
#ifndef __va_list__
|
||||
#define __va_list__
|
||||
#endif
|
||||
|
||||
#endif /* not _VA_LIST_, except on certain systems */
|
||||
|
||||
#endif /* not __svr4__ */
|
||||
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#define __STDC_VERSION_STDARG_H__ 202311L
|
||||
#endif
|
||||
|
||||
#endif /* _STDARG_H */
|
||||
|
||||
#endif /* not _ANSI_STDARG_H_ */
|
||||
#endif /* not _STDARG_H */
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
/* Copyright (C) 2013-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* ISO C11 Standard: 7.17 Atomics <stdatomic.h>. */
|
||||
|
||||
#ifndef _STDATOMIC_H
|
||||
#define _STDATOMIC_H
|
||||
|
||||
typedef enum
|
||||
{
|
||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
||||
memory_order_consume = __ATOMIC_CONSUME,
|
||||
memory_order_acquire = __ATOMIC_ACQUIRE,
|
||||
memory_order_release = __ATOMIC_RELEASE,
|
||||
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
||||
memory_order_seq_cst = __ATOMIC_SEQ_CST
|
||||
} memory_order;
|
||||
|
||||
|
||||
typedef _Atomic _Bool atomic_bool;
|
||||
typedef _Atomic char atomic_char;
|
||||
typedef _Atomic signed char atomic_schar;
|
||||
typedef _Atomic unsigned char atomic_uchar;
|
||||
typedef _Atomic short atomic_short;
|
||||
typedef _Atomic unsigned short atomic_ushort;
|
||||
typedef _Atomic int atomic_int;
|
||||
typedef _Atomic unsigned int atomic_uint;
|
||||
typedef _Atomic long atomic_long;
|
||||
typedef _Atomic unsigned long atomic_ulong;
|
||||
typedef _Atomic long long atomic_llong;
|
||||
typedef _Atomic unsigned long long atomic_ullong;
|
||||
#ifdef __CHAR8_TYPE__
|
||||
typedef _Atomic __CHAR8_TYPE__ atomic_char8_t;
|
||||
#endif
|
||||
typedef _Atomic __CHAR16_TYPE__ atomic_char16_t;
|
||||
typedef _Atomic __CHAR32_TYPE__ atomic_char32_t;
|
||||
typedef _Atomic __WCHAR_TYPE__ atomic_wchar_t;
|
||||
typedef _Atomic __INT_LEAST8_TYPE__ atomic_int_least8_t;
|
||||
typedef _Atomic __UINT_LEAST8_TYPE__ atomic_uint_least8_t;
|
||||
typedef _Atomic __INT_LEAST16_TYPE__ atomic_int_least16_t;
|
||||
typedef _Atomic __UINT_LEAST16_TYPE__ atomic_uint_least16_t;
|
||||
typedef _Atomic __INT_LEAST32_TYPE__ atomic_int_least32_t;
|
||||
typedef _Atomic __UINT_LEAST32_TYPE__ atomic_uint_least32_t;
|
||||
typedef _Atomic __INT_LEAST64_TYPE__ atomic_int_least64_t;
|
||||
typedef _Atomic __UINT_LEAST64_TYPE__ atomic_uint_least64_t;
|
||||
typedef _Atomic __INT_FAST8_TYPE__ atomic_int_fast8_t;
|
||||
typedef _Atomic __UINT_FAST8_TYPE__ atomic_uint_fast8_t;
|
||||
typedef _Atomic __INT_FAST16_TYPE__ atomic_int_fast16_t;
|
||||
typedef _Atomic __UINT_FAST16_TYPE__ atomic_uint_fast16_t;
|
||||
typedef _Atomic __INT_FAST32_TYPE__ atomic_int_fast32_t;
|
||||
typedef _Atomic __UINT_FAST32_TYPE__ atomic_uint_fast32_t;
|
||||
typedef _Atomic __INT_FAST64_TYPE__ atomic_int_fast64_t;
|
||||
typedef _Atomic __UINT_FAST64_TYPE__ atomic_uint_fast64_t;
|
||||
typedef _Atomic __INTPTR_TYPE__ atomic_intptr_t;
|
||||
typedef _Atomic __UINTPTR_TYPE__ atomic_uintptr_t;
|
||||
typedef _Atomic __SIZE_TYPE__ atomic_size_t;
|
||||
typedef _Atomic __PTRDIFF_TYPE__ atomic_ptrdiff_t;
|
||||
typedef _Atomic __INTMAX_TYPE__ atomic_intmax_t;
|
||||
typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
|
||||
|
||||
|
||||
#if !(defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L)
|
||||
#define ATOMIC_VAR_INIT(VALUE) (VALUE)
|
||||
#endif
|
||||
|
||||
/* Initialize an atomic object pointed to by PTR with VAL. */
|
||||
#define atomic_init(PTR, VAL) \
|
||||
atomic_store_explicit (PTR, VAL, __ATOMIC_RELAXED)
|
||||
|
||||
#define kill_dependency(Y) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __kill_dependency_tmp = (Y); \
|
||||
__kill_dependency_tmp; \
|
||||
})
|
||||
|
||||
extern void atomic_thread_fence (memory_order);
|
||||
#define atomic_thread_fence(MO) __atomic_thread_fence (MO)
|
||||
extern void atomic_signal_fence (memory_order);
|
||||
#define atomic_signal_fence(MO) __atomic_signal_fence (MO)
|
||||
#define atomic_is_lock_free(OBJ) __atomic_is_lock_free (sizeof (*(OBJ)), (OBJ))
|
||||
|
||||
#define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE
|
||||
#define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE
|
||||
#ifdef __GCC_ATOMIC_CHAR8_T_LOCK_FREE
|
||||
#define ATOMIC_CHAR8_T_LOCK_FREE __GCC_ATOMIC_CHAR8_T_LOCK_FREE
|
||||
#endif
|
||||
#define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE
|
||||
#define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE
|
||||
#define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE
|
||||
#define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE
|
||||
#define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE
|
||||
#define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE
|
||||
#define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE
|
||||
#define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE
|
||||
|
||||
|
||||
/* Note that these macros require __auto_type to remove
|
||||
_Atomic qualifiers (and const qualifiers, if those are valid on
|
||||
macro operands).
|
||||
|
||||
Also note that the header file uses the generic form of __atomic
|
||||
builtins, which requires the address to be taken of the value
|
||||
parameter, and then we pass that value on. This allows the macros
|
||||
to work for any type, and the compiler is smart enough to convert
|
||||
these to lock-free _N variants if possible, and throw away the
|
||||
temps. */
|
||||
|
||||
#define atomic_store_explicit(PTR, VAL, MO) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __atomic_store_ptr = (PTR); \
|
||||
__typeof__ ((void)0, *__atomic_store_ptr) __atomic_store_tmp = (VAL); \
|
||||
__atomic_store (__atomic_store_ptr, &__atomic_store_tmp, (MO)); \
|
||||
})
|
||||
|
||||
#define atomic_store(PTR, VAL) \
|
||||
atomic_store_explicit (PTR, VAL, __ATOMIC_SEQ_CST)
|
||||
|
||||
|
||||
#define atomic_load_explicit(PTR, MO) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __atomic_load_ptr = (PTR); \
|
||||
__typeof__ ((void)0, *__atomic_load_ptr) __atomic_load_tmp; \
|
||||
__atomic_load (__atomic_load_ptr, &__atomic_load_tmp, (MO)); \
|
||||
__atomic_load_tmp; \
|
||||
})
|
||||
|
||||
#define atomic_load(PTR) atomic_load_explicit (PTR, __ATOMIC_SEQ_CST)
|
||||
|
||||
|
||||
#define atomic_exchange_explicit(PTR, VAL, MO) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __atomic_exchange_ptr = (PTR); \
|
||||
__typeof__ ((void)0, *__atomic_exchange_ptr) __atomic_exchange_val = (VAL); \
|
||||
__typeof__ ((void)0, *__atomic_exchange_ptr) __atomic_exchange_tmp; \
|
||||
__atomic_exchange (__atomic_exchange_ptr, &__atomic_exchange_val, \
|
||||
&__atomic_exchange_tmp, (MO)); \
|
||||
__atomic_exchange_tmp; \
|
||||
})
|
||||
|
||||
#define atomic_exchange(PTR, VAL) \
|
||||
atomic_exchange_explicit (PTR, VAL, __ATOMIC_SEQ_CST)
|
||||
|
||||
|
||||
#define atomic_compare_exchange_strong_explicit(PTR, VAL, DES, SUC, FAIL) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __atomic_compare_exchange_ptr = (PTR); \
|
||||
__typeof__ ((void)0, *__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \
|
||||
= (DES); \
|
||||
__atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \
|
||||
&__atomic_compare_exchange_tmp, 0, \
|
||||
(SUC), (FAIL)); \
|
||||
})
|
||||
|
||||
#define atomic_compare_exchange_strong(PTR, VAL, DES) \
|
||||
atomic_compare_exchange_strong_explicit (PTR, VAL, DES, __ATOMIC_SEQ_CST, \
|
||||
__ATOMIC_SEQ_CST)
|
||||
|
||||
#define atomic_compare_exchange_weak_explicit(PTR, VAL, DES, SUC, FAIL) \
|
||||
__extension__ \
|
||||
({ \
|
||||
__auto_type __atomic_compare_exchange_ptr = (PTR); \
|
||||
__typeof__ ((void)0, *__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \
|
||||
= (DES); \
|
||||
__atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \
|
||||
&__atomic_compare_exchange_tmp, 1, \
|
||||
(SUC), (FAIL)); \
|
||||
})
|
||||
|
||||
#define atomic_compare_exchange_weak(PTR, VAL, DES) \
|
||||
atomic_compare_exchange_weak_explicit (PTR, VAL, DES, __ATOMIC_SEQ_CST, \
|
||||
__ATOMIC_SEQ_CST)
|
||||
|
||||
|
||||
|
||||
#define atomic_fetch_add(PTR, VAL) __atomic_fetch_add ((PTR), (VAL), \
|
||||
__ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_add_explicit(PTR, VAL, MO) \
|
||||
__atomic_fetch_add ((PTR), (VAL), (MO))
|
||||
|
||||
#define atomic_fetch_sub(PTR, VAL) __atomic_fetch_sub ((PTR), (VAL), \
|
||||
__ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_sub_explicit(PTR, VAL, MO) \
|
||||
__atomic_fetch_sub ((PTR), (VAL), (MO))
|
||||
|
||||
#define atomic_fetch_or(PTR, VAL) __atomic_fetch_or ((PTR), (VAL), \
|
||||
__ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_or_explicit(PTR, VAL, MO) \
|
||||
__atomic_fetch_or ((PTR), (VAL), (MO))
|
||||
|
||||
#define atomic_fetch_xor(PTR, VAL) __atomic_fetch_xor ((PTR), (VAL), \
|
||||
__ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_xor_explicit(PTR, VAL, MO) \
|
||||
__atomic_fetch_xor ((PTR), (VAL), (MO))
|
||||
|
||||
#define atomic_fetch_and(PTR, VAL) __atomic_fetch_and ((PTR), (VAL), \
|
||||
__ATOMIC_SEQ_CST)
|
||||
#define atomic_fetch_and_explicit(PTR, VAL, MO) \
|
||||
__atomic_fetch_and ((PTR), (VAL), (MO))
|
||||
|
||||
|
||||
typedef _Atomic struct
|
||||
{
|
||||
#if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1
|
||||
_Bool __val;
|
||||
#else
|
||||
unsigned char __val;
|
||||
#endif
|
||||
} atomic_flag;
|
||||
|
||||
#define ATOMIC_FLAG_INIT { 0 }
|
||||
|
||||
|
||||
extern _Bool atomic_flag_test_and_set (volatile atomic_flag *);
|
||||
#define atomic_flag_test_and_set(PTR) \
|
||||
__atomic_test_and_set ((PTR), __ATOMIC_SEQ_CST)
|
||||
extern _Bool atomic_flag_test_and_set_explicit (volatile atomic_flag *,
|
||||
memory_order);
|
||||
#define atomic_flag_test_and_set_explicit(PTR, MO) \
|
||||
__atomic_test_and_set ((PTR), (MO))
|
||||
|
||||
extern void atomic_flag_clear (volatile atomic_flag *);
|
||||
#define atomic_flag_clear(PTR) __atomic_clear ((PTR), __ATOMIC_SEQ_CST)
|
||||
extern void atomic_flag_clear_explicit (volatile atomic_flag *, memory_order);
|
||||
#define atomic_flag_clear_explicit(PTR, MO) __atomic_clear ((PTR), (MO))
|
||||
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#define __STDC_VERSION_STDATOMIC_H__ 202311L
|
||||
#endif
|
||||
|
||||
#endif /* _STDATOMIC_H */
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/* Copyright (C) 1998-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/*
|
||||
* ISO C Standard: 7.16 Boolean type and values <stdbool.h>
|
||||
*/
|
||||
|
||||
#ifndef _STDBOOL_H
|
||||
#define _STDBOOL_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
/* bool, true and false are keywords. */
|
||||
#else
|
||||
#define bool _Bool
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#else /* __cplusplus */
|
||||
|
||||
/* Supporting _Bool in C++ is a GCC extension. */
|
||||
#define _Bool bool
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Signal that all the definitions are present. */
|
||||
#define __bool_true_false_are_defined 1
|
||||
|
||||
#endif /* stdbool.h */
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/* Copyright (C) 2023-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* ISO C23: 7.20 Checked Integer Arithmetic <stdckdint.h>. */
|
||||
|
||||
#ifndef _STDCKDINT_H
|
||||
#define _STDCKDINT_H
|
||||
|
||||
#define __STDC_VERSION_STDCKDINT_H__ 202311L
|
||||
|
||||
#define ckd_add(r, a, b) ((_Bool) __builtin_add_overflow (a, b, r))
|
||||
#define ckd_sub(r, a, b) ((_Bool) __builtin_sub_overflow (a, b, r))
|
||||
#define ckd_mul(r, a, b) ((_Bool) __builtin_mul_overflow (a, b, r))
|
||||
|
||||
/* Allow for the C library to add its part to the header. */
|
||||
#if !defined (_LIBC_STDCKDINT_H) && __has_include_next (<stdckdint.h>)
|
||||
# include_next <stdckdint.h>
|
||||
#endif
|
||||
|
||||
#endif /* stdckdint.h */
|
||||
+463
@@ -0,0 +1,463 @@
|
||||
/* Copyright (C) 1989-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/*
|
||||
* ISO C Standard: 7.17 Common definitions <stddef.h>
|
||||
*/
|
||||
#if (!defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \
|
||||
&& !defined(__STDDEF_H__)) \
|
||||
|| defined(__need_wchar_t) || defined(__need_size_t) \
|
||||
|| defined(__need_ptrdiff_t) || defined(__need_NULL) \
|
||||
|| defined(__need_wint_t)
|
||||
|
||||
/* Any one of these symbols __need_* means that GNU libc
|
||||
wants us just to define one data type. So don't define
|
||||
the symbols that indicate this file's entire job has been done. */
|
||||
#if (!defined(__need_wchar_t) && !defined(__need_size_t) \
|
||||
&& !defined(__need_ptrdiff_t) && !defined(__need_NULL) \
|
||||
&& !defined(__need_wint_t))
|
||||
#define _STDDEF_H
|
||||
#define _STDDEF_H_
|
||||
/* snaroff@next.com says the NeXT needs this. */
|
||||
#define _ANSI_STDDEF_H
|
||||
#endif
|
||||
|
||||
#ifndef __sys_stdtypes_h
|
||||
/* This avoids lossage on SunOS but only if stdtypes.h comes first.
|
||||
There's no way to win with the other order! Sun lossage. */
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <machine/ansi.h>
|
||||
#endif
|
||||
|
||||
#if defined (__FreeBSD__)
|
||||
#include <sys/_types.h>
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#if !defined(_SIZE_T_) && !defined(_BSD_SIZE_T_)
|
||||
#define _SIZE_T
|
||||
#endif
|
||||
#if !defined(_PTRDIFF_T_) && !defined(_BSD_PTRDIFF_T_)
|
||||
#define _PTRDIFF_T
|
||||
#endif
|
||||
/* On BSD/386 1.1, at least, machine/ansi.h defines _BSD_WCHAR_T_
|
||||
instead of _WCHAR_T_. */
|
||||
#if !defined(_WCHAR_T_) && !defined(_BSD_WCHAR_T_)
|
||||
#ifndef _BSD_WCHAR_T_
|
||||
#define _WCHAR_T
|
||||
#endif
|
||||
#endif
|
||||
/* Undef _FOO_T_ if we are supposed to define foo_t. */
|
||||
#if defined (__need_ptrdiff_t) || defined (_STDDEF_H_)
|
||||
#undef _PTRDIFF_T_
|
||||
#undef _BSD_PTRDIFF_T_
|
||||
#endif
|
||||
#if defined (__need_size_t) || defined (_STDDEF_H_)
|
||||
#undef _SIZE_T_
|
||||
#undef _BSD_SIZE_T_
|
||||
#endif
|
||||
#if defined (__need_wchar_t) || defined (_STDDEF_H_)
|
||||
#undef _WCHAR_T_
|
||||
#undef _BSD_WCHAR_T_
|
||||
#endif
|
||||
#endif /* defined(__NetBSD__) */
|
||||
|
||||
/* Sequent's header files use _PTRDIFF_T_ in some conflicting way.
|
||||
Just ignore it. */
|
||||
#if defined (__sequent__) && defined (_PTRDIFF_T_)
|
||||
#undef _PTRDIFF_T_
|
||||
#endif
|
||||
|
||||
/* On VxWorks, <type/vxTypesBase.h> may have defined macros like
|
||||
_TYPE_size_t which will typedef size_t. fixincludes patched the
|
||||
vxTypesBase.h so that this macro is only defined if _GCC_SIZE_T is
|
||||
not defined, and so that defining this macro defines _GCC_SIZE_T.
|
||||
If we find that the macros are still defined at this point, we must
|
||||
invoke them so that the type is defined as expected. */
|
||||
#if defined (_TYPE_ptrdiff_t) && (defined (__need_ptrdiff_t) || defined (_STDDEF_H_))
|
||||
_TYPE_ptrdiff_t;
|
||||
#undef _TYPE_ptrdiff_t
|
||||
#endif
|
||||
#if defined (_TYPE_size_t) && (defined (__need_size_t) || defined (_STDDEF_H_))
|
||||
_TYPE_size_t;
|
||||
#undef _TYPE_size_t
|
||||
#endif
|
||||
#if defined (_TYPE_wchar_t) && (defined (__need_wchar_t) || defined (_STDDEF_H_))
|
||||
_TYPE_wchar_t;
|
||||
#undef _TYPE_wchar_t
|
||||
#endif
|
||||
|
||||
/* In case nobody has defined these types, but we aren't running under
|
||||
GCC 2.00, make sure that __PTRDIFF_TYPE__, __SIZE_TYPE__, and
|
||||
__WCHAR_TYPE__ have reasonable values. This can happen if the
|
||||
parts of GCC is compiled by an older compiler, that actually
|
||||
include gstddef.h, such as collect2. */
|
||||
|
||||
/* Signed type of difference of two pointers. */
|
||||
|
||||
/* Define this type if we are doing the whole job,
|
||||
or if we want this type in particular. */
|
||||
#if defined (_STDDEF_H) || defined (__need_ptrdiff_t)
|
||||
#ifndef _PTRDIFF_T /* in case <sys/types.h> has defined it. */
|
||||
#ifndef _T_PTRDIFF_
|
||||
#ifndef _T_PTRDIFF
|
||||
#ifndef __PTRDIFF_T
|
||||
#ifndef _PTRDIFF_T_
|
||||
#ifndef _BSD_PTRDIFF_T_
|
||||
#ifndef ___int_ptrdiff_t_h
|
||||
#ifndef _GCC_PTRDIFF_T
|
||||
#ifndef _PTRDIFF_T_DECLARED /* DragonFly */
|
||||
#ifndef __DEFINED_ptrdiff_t /* musl libc */
|
||||
#define _PTRDIFF_T
|
||||
#define _T_PTRDIFF_
|
||||
#define _T_PTRDIFF
|
||||
#define __PTRDIFF_T
|
||||
#define _PTRDIFF_T_
|
||||
#define _BSD_PTRDIFF_T_
|
||||
#define ___int_ptrdiff_t_h
|
||||
#define _GCC_PTRDIFF_T
|
||||
#define _PTRDIFF_T_DECLARED
|
||||
#define __DEFINED_ptrdiff_t
|
||||
#ifndef __PTRDIFF_TYPE__
|
||||
#define __PTRDIFF_TYPE__ long int
|
||||
#endif
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
#endif /* __DEFINED_ptrdiff_t */
|
||||
#endif /* _PTRDIFF_T_DECLARED */
|
||||
#endif /* _GCC_PTRDIFF_T */
|
||||
#endif /* ___int_ptrdiff_t_h */
|
||||
#endif /* _BSD_PTRDIFF_T_ */
|
||||
#endif /* _PTRDIFF_T_ */
|
||||
#endif /* __PTRDIFF_T */
|
||||
#endif /* _T_PTRDIFF */
|
||||
#endif /* _T_PTRDIFF_ */
|
||||
#endif /* _PTRDIFF_T */
|
||||
|
||||
/* If this symbol has done its job, get rid of it. */
|
||||
#undef __need_ptrdiff_t
|
||||
|
||||
#endif /* _STDDEF_H or __need_ptrdiff_t. */
|
||||
|
||||
/* Unsigned type of `sizeof' something. */
|
||||
|
||||
/* Define this type if we are doing the whole job,
|
||||
or if we want this type in particular. */
|
||||
#if defined (_STDDEF_H) || defined (__need_size_t)
|
||||
#ifndef __size_t__ /* BeOS */
|
||||
#ifndef __SIZE_T__ /* Cray Unicos/Mk */
|
||||
#ifndef _SIZE_T /* in case <sys/types.h> has defined it. */
|
||||
#ifndef _SYS_SIZE_T_H
|
||||
#ifndef _T_SIZE_
|
||||
#ifndef _T_SIZE
|
||||
#ifndef __SIZE_T
|
||||
#ifndef _SIZE_T_
|
||||
#ifndef _BSD_SIZE_T_
|
||||
#ifndef _SIZE_T_DEFINED_
|
||||
#ifndef _SIZE_T_DEFINED
|
||||
#ifndef _BSD_SIZE_T_DEFINED_ /* Darwin */
|
||||
#ifndef _SIZE_T_DECLARED /* FreeBSD 5 */
|
||||
#ifndef __DEFINED_size_t /* musl libc */
|
||||
#ifndef ___int_size_t_h
|
||||
#ifndef _GCC_SIZE_T
|
||||
#ifndef _SIZET_
|
||||
#ifndef __size_t
|
||||
#define __size_t__ /* BeOS */
|
||||
#define __SIZE_T__ /* Cray Unicos/Mk */
|
||||
#define _SIZE_T
|
||||
#define _SYS_SIZE_T_H
|
||||
#define _T_SIZE_
|
||||
#define _T_SIZE
|
||||
#define __SIZE_T
|
||||
#define _SIZE_T_
|
||||
#define _BSD_SIZE_T_
|
||||
#define _SIZE_T_DEFINED_
|
||||
#define _SIZE_T_DEFINED
|
||||
#define _BSD_SIZE_T_DEFINED_ /* Darwin */
|
||||
#define _SIZE_T_DECLARED /* FreeBSD 5 */
|
||||
#define __DEFINED_size_t /* musl libc */
|
||||
#define ___int_size_t_h
|
||||
#define _GCC_SIZE_T
|
||||
#define _SIZET_
|
||||
#if defined (__FreeBSD__) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD_kernel__) \
|
||||
|| defined(__VMS__)
|
||||
/* __size_t is a typedef, must not trash it. */
|
||||
#else
|
||||
#define __size_t
|
||||
#endif
|
||||
#ifndef __SIZE_TYPE__
|
||||
#define __SIZE_TYPE__ long unsigned int
|
||||
#endif
|
||||
#if !(defined (__GNUG__) && defined (size_t))
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
#ifdef __BEOS__
|
||||
typedef long ssize_t;
|
||||
#endif /* __BEOS__ */
|
||||
#endif /* !(defined (__GNUG__) && defined (size_t)) */
|
||||
#endif /* __size_t */
|
||||
#endif /* _SIZET_ */
|
||||
#endif /* _GCC_SIZE_T */
|
||||
#endif /* ___int_size_t_h */
|
||||
#endif /* __DEFINED_size_t */
|
||||
#endif /* _SIZE_T_DECLARED */
|
||||
#endif /* _BSD_SIZE_T_DEFINED_ */
|
||||
#endif /* _SIZE_T_DEFINED */
|
||||
#endif /* _SIZE_T_DEFINED_ */
|
||||
#endif /* _BSD_SIZE_T_ */
|
||||
#endif /* _SIZE_T_ */
|
||||
#endif /* __SIZE_T */
|
||||
#endif /* _T_SIZE */
|
||||
#endif /* _T_SIZE_ */
|
||||
#endif /* _SYS_SIZE_T_H */
|
||||
#endif /* _SIZE_T */
|
||||
#endif /* __SIZE_T__ */
|
||||
#endif /* __size_t__ */
|
||||
#undef __need_size_t
|
||||
#endif /* _STDDEF_H or __need_size_t. */
|
||||
|
||||
|
||||
/* Wide character type.
|
||||
Locale-writers should change this as necessary to
|
||||
be big enough to hold unique values not between 0 and 127,
|
||||
and not (wchar_t) -1, for each defined multibyte character. */
|
||||
|
||||
/* Define this type if we are doing the whole job,
|
||||
or if we want this type in particular. */
|
||||
#if defined (_STDDEF_H) || defined (__need_wchar_t)
|
||||
#ifndef __wchar_t__ /* BeOS */
|
||||
#ifndef __WCHAR_T__ /* Cray Unicos/Mk */
|
||||
#ifndef _WCHAR_T
|
||||
#ifndef _T_WCHAR_
|
||||
#ifndef _T_WCHAR
|
||||
#ifndef __WCHAR_T
|
||||
#ifndef _WCHAR_T_
|
||||
#ifndef _BSD_WCHAR_T_
|
||||
#ifndef _BSD_WCHAR_T_DEFINED_ /* Darwin */
|
||||
#ifndef _BSD_RUNE_T_DEFINED_ /* Darwin */
|
||||
#ifndef _WCHAR_T_DECLARED /* FreeBSD 5 */
|
||||
#ifndef __DEFINED_wchar_t /* musl libc */
|
||||
#ifndef _WCHAR_T_DEFINED_
|
||||
#ifndef _WCHAR_T_DEFINED
|
||||
#ifndef _WCHAR_T_H
|
||||
#ifndef ___int_wchar_t_h
|
||||
#ifndef __INT_WCHAR_T_H
|
||||
#ifndef _GCC_WCHAR_T
|
||||
#define __wchar_t__ /* BeOS */
|
||||
#define __WCHAR_T__ /* Cray Unicos/Mk */
|
||||
#define _WCHAR_T
|
||||
#define _T_WCHAR_
|
||||
#define _T_WCHAR
|
||||
#define __WCHAR_T
|
||||
#define _WCHAR_T_
|
||||
#define _BSD_WCHAR_T_
|
||||
#define _WCHAR_T_DEFINED_
|
||||
#define _WCHAR_T_DEFINED
|
||||
#define _WCHAR_T_H
|
||||
#define ___int_wchar_t_h
|
||||
#define __INT_WCHAR_T_H
|
||||
#define _GCC_WCHAR_T
|
||||
#define _WCHAR_T_DECLARED
|
||||
#define __DEFINED_wchar_t
|
||||
|
||||
/* On BSD/386 1.1, at least, machine/ansi.h defines _BSD_WCHAR_T_
|
||||
instead of _WCHAR_T_, and _BSD_RUNE_T_ (which, unlike the other
|
||||
symbols in the _FOO_T_ family, stays defined even after its
|
||||
corresponding type is defined). If we define wchar_t, then we
|
||||
must undef _WCHAR_T_; for BSD/386 1.1 (and perhaps others), if
|
||||
we undef _WCHAR_T_, then we must also define rune_t, since
|
||||
headers like runetype.h assume that if machine/ansi.h is included,
|
||||
and _BSD_WCHAR_T_ is not defined, then rune_t is available.
|
||||
machine/ansi.h says, "Note that _WCHAR_T_ and _RUNE_T_ must be of
|
||||
the same type." */
|
||||
#ifdef _BSD_WCHAR_T_
|
||||
#undef _BSD_WCHAR_T_
|
||||
#ifdef _BSD_RUNE_T_
|
||||
#if !defined (_ANSI_SOURCE) && !defined (_POSIX_SOURCE)
|
||||
typedef _BSD_RUNE_T_ rune_t;
|
||||
#define _BSD_WCHAR_T_DEFINED_
|
||||
#define _BSD_RUNE_T_DEFINED_ /* Darwin */
|
||||
#if defined (__FreeBSD__) && (__FreeBSD__ < 5)
|
||||
/* Why is this file so hard to maintain properly? In contrast to
|
||||
the comment above regarding BSD/386 1.1, on FreeBSD for as long
|
||||
as the symbol has existed, _BSD_RUNE_T_ must not stay defined or
|
||||
redundant typedefs will occur when stdlib.h is included after this file. */
|
||||
#undef _BSD_RUNE_T_
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
/* FreeBSD 5 can't be handled well using "traditional" logic above
|
||||
since it no longer defines _BSD_RUNE_T_ yet still desires to export
|
||||
rune_t in some cases... */
|
||||
#if defined (__FreeBSD__) && (__FreeBSD__ >= 5)
|
||||
#if !defined (_ANSI_SOURCE) && !defined (_POSIX_SOURCE)
|
||||
#if __BSD_VISIBLE
|
||||
#ifndef _RUNE_T_DECLARED
|
||||
typedef __rune_t rune_t;
|
||||
#define _RUNE_T_DECLARED
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef __WCHAR_TYPE__
|
||||
#define __WCHAR_TYPE__ int
|
||||
#endif
|
||||
#ifndef __cplusplus
|
||||
typedef __WCHAR_TYPE__ wchar_t;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif /* __DEFINED_wchar_t */
|
||||
#endif /* _WCHAR_T_DECLARED */
|
||||
#endif /* _BSD_RUNE_T_DEFINED_ */
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif /* __WCHAR_T__ */
|
||||
#endif /* __wchar_t__ */
|
||||
#undef __need_wchar_t
|
||||
#endif /* _STDDEF_H or __need_wchar_t. */
|
||||
|
||||
#if defined (__need_wint_t)
|
||||
#ifndef _WINT_T
|
||||
#define _WINT_T
|
||||
|
||||
#ifndef __WINT_TYPE__
|
||||
#define __WINT_TYPE__ unsigned int
|
||||
#endif
|
||||
typedef __WINT_TYPE__ wint_t;
|
||||
#endif
|
||||
#undef __need_wint_t
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
/* The references to _GCC_PTRDIFF_T_, _GCC_SIZE_T_, and _GCC_WCHAR_T_
|
||||
are probably typos and should be removed before 2.8 is released. */
|
||||
#ifdef _GCC_PTRDIFF_T_
|
||||
#undef _PTRDIFF_T_
|
||||
#undef _BSD_PTRDIFF_T_
|
||||
#endif
|
||||
#ifdef _GCC_SIZE_T_
|
||||
#undef _SIZE_T_
|
||||
#undef _BSD_SIZE_T_
|
||||
#endif
|
||||
#ifdef _GCC_WCHAR_T_
|
||||
#undef _WCHAR_T_
|
||||
#undef _BSD_WCHAR_T_
|
||||
#endif
|
||||
/* The following ones are the real ones. */
|
||||
#ifdef _GCC_PTRDIFF_T
|
||||
#undef _PTRDIFF_T_
|
||||
#undef _BSD_PTRDIFF_T_
|
||||
#endif
|
||||
#ifdef _GCC_SIZE_T
|
||||
#undef _SIZE_T_
|
||||
#undef _BSD_SIZE_T_
|
||||
#endif
|
||||
#ifdef _GCC_WCHAR_T
|
||||
#undef _WCHAR_T_
|
||||
#undef _BSD_WCHAR_T_
|
||||
#endif
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
#endif /* __sys_stdtypes_h */
|
||||
|
||||
/* A null pointer constant. */
|
||||
|
||||
#if defined (_STDDEF_H) || defined (__need_NULL)
|
||||
#undef NULL /* in case <stdio.h> has defined it. */
|
||||
#ifdef __GNUG__
|
||||
#define NULL __null
|
||||
#else /* G++ */
|
||||
#ifndef __cplusplus
|
||||
#define NULL ((void *)0)
|
||||
#else /* C++ */
|
||||
#define NULL 0
|
||||
#endif /* C++ */
|
||||
#endif /* G++ */
|
||||
#endif /* NULL not defined and <stddef.h> or need NULL. */
|
||||
#undef __need_NULL
|
||||
|
||||
#ifdef _STDDEF_H
|
||||
|
||||
/* Offset of member MEMBER in a struct of type TYPE. */
|
||||
#undef offsetof /* in case a system header has defined it. */
|
||||
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
|
||||
|
||||
#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \
|
||||
|| (defined(__cplusplus) && __cplusplus >= 201103L)
|
||||
#ifndef _GCC_MAX_ALIGN_T
|
||||
#define _GCC_MAX_ALIGN_T
|
||||
/* Type whose alignment is supported in every context and is at least
|
||||
as great as that of any standard type not using alignment
|
||||
specifiers. */
|
||||
typedef struct {
|
||||
long long __max_align_ll __attribute__((__aligned__(__alignof__(long long))));
|
||||
long double __max_align_ld __attribute__((__aligned__(__alignof__(long double))));
|
||||
/* _Float128 is defined as a basic type, so max_align_t must be
|
||||
sufficiently aligned for it. This code must work in C++, so we
|
||||
use __float128 here; that is only available on some
|
||||
architectures, but only on i386 is extra alignment needed for
|
||||
__float128. */
|
||||
#ifdef __i386__
|
||||
__float128 __max_align_f128 __attribute__((__aligned__(__alignof(__float128))));
|
||||
#endif
|
||||
} max_align_t;
|
||||
#endif
|
||||
#endif /* C11 or C++11. */
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L
|
||||
#ifndef _GXX_NULLPTR_T
|
||||
#define _GXX_NULLPTR_T
|
||||
typedef decltype(nullptr) nullptr_t;
|
||||
#endif
|
||||
#endif /* C++11. */
|
||||
|
||||
#if (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L)
|
||||
#ifndef _GCC_NULLPTR_T
|
||||
#define _GCC_NULLPTR_T
|
||||
typedef __typeof__(nullptr) nullptr_t;
|
||||
/* ??? This doesn't define __STDC_VERSION_STDDEF_H__ yet. */
|
||||
#endif
|
||||
#endif /* C23. */
|
||||
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#define unreachable() (__builtin_unreachable ())
|
||||
#define __STDC_VERSION_STDDEF_H__ 202311L
|
||||
#endif
|
||||
|
||||
#endif /* _STDDEF_H was defined this time */
|
||||
|
||||
#endif /* !_STDDEF_H && !_STDDEF_H_ && !_ANSI_STDDEF_H && !__STDDEF_H__
|
||||
|| __need_XXX was not defined before */
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
/* Copyright (C) 2007-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* ISO/IEC JTC1 SC22 WG14 N1169
|
||||
* Date: 2006-04-04
|
||||
* ISO/IEC TR 18037
|
||||
* Programming languages - C - Extensions to support embedded processors
|
||||
*/
|
||||
|
||||
#ifndef _STDFIX_H
|
||||
#define _STDFIX_H
|
||||
|
||||
/* 7.18a.1 Introduction. */
|
||||
|
||||
#undef fract
|
||||
#undef accum
|
||||
#undef sat
|
||||
#define fract _Fract
|
||||
#define accum _Accum
|
||||
#define sat _Sat
|
||||
|
||||
/* 7.18a.3 Precision macros. */
|
||||
|
||||
#undef SFRACT_FBIT
|
||||
#undef SFRACT_MIN
|
||||
#undef SFRACT_MAX
|
||||
#undef SFRACT_EPSILON
|
||||
#define SFRACT_FBIT __SFRACT_FBIT__
|
||||
#define SFRACT_MIN __SFRACT_MIN__
|
||||
#define SFRACT_MAX __SFRACT_MAX__
|
||||
#define SFRACT_EPSILON __SFRACT_EPSILON__
|
||||
|
||||
#undef USFRACT_FBIT
|
||||
#undef USFRACT_MIN
|
||||
#undef USFRACT_MAX
|
||||
#undef USFRACT_EPSILON
|
||||
#define USFRACT_FBIT __USFRACT_FBIT__
|
||||
#define USFRACT_MIN __USFRACT_MIN__ /* GCC extension. */
|
||||
#define USFRACT_MAX __USFRACT_MAX__
|
||||
#define USFRACT_EPSILON __USFRACT_EPSILON__
|
||||
|
||||
#undef FRACT_FBIT
|
||||
#undef FRACT_MIN
|
||||
#undef FRACT_MAX
|
||||
#undef FRACT_EPSILON
|
||||
#define FRACT_FBIT __FRACT_FBIT__
|
||||
#define FRACT_MIN __FRACT_MIN__
|
||||
#define FRACT_MAX __FRACT_MAX__
|
||||
#define FRACT_EPSILON __FRACT_EPSILON__
|
||||
|
||||
#undef UFRACT_FBIT
|
||||
#undef UFRACT_MIN
|
||||
#undef UFRACT_MAX
|
||||
#undef UFRACT_EPSILON
|
||||
#define UFRACT_FBIT __UFRACT_FBIT__
|
||||
#define UFRACT_MIN __UFRACT_MIN__ /* GCC extension. */
|
||||
#define UFRACT_MAX __UFRACT_MAX__
|
||||
#define UFRACT_EPSILON __UFRACT_EPSILON__
|
||||
|
||||
#undef LFRACT_FBIT
|
||||
#undef LFRACT_MIN
|
||||
#undef LFRACT_MAX
|
||||
#undef LFRACT_EPSILON
|
||||
#define LFRACT_FBIT __LFRACT_FBIT__
|
||||
#define LFRACT_MIN __LFRACT_MIN__
|
||||
#define LFRACT_MAX __LFRACT_MAX__
|
||||
#define LFRACT_EPSILON __LFRACT_EPSILON__
|
||||
|
||||
#undef ULFRACT_FBIT
|
||||
#undef ULFRACT_MIN
|
||||
#undef ULFRACT_MAX
|
||||
#undef ULFRACT_EPSILON
|
||||
#define ULFRACT_FBIT __ULFRACT_FBIT__
|
||||
#define ULFRACT_MIN __ULFRACT_MIN__ /* GCC extension. */
|
||||
#define ULFRACT_MAX __ULFRACT_MAX__
|
||||
#define ULFRACT_EPSILON __ULFRACT_EPSILON__
|
||||
|
||||
#undef LLFRACT_FBIT
|
||||
#undef LLFRACT_MIN
|
||||
#undef LLFRACT_MAX
|
||||
#undef LLFRACT_EPSILON
|
||||
#define LLFRACT_FBIT __LLFRACT_FBIT__ /* GCC extension. */
|
||||
#define LLFRACT_MIN __LLFRACT_MIN__ /* GCC extension. */
|
||||
#define LLFRACT_MAX __LLFRACT_MAX__ /* GCC extension. */
|
||||
#define LLFRACT_EPSILON __LLFRACT_EPSILON__ /* GCC extension. */
|
||||
|
||||
#undef ULLFRACT_FBIT
|
||||
#undef ULLFRACT_MIN
|
||||
#undef ULLFRACT_MAX
|
||||
#undef ULLFRACT_EPSILON
|
||||
#define ULLFRACT_FBIT __ULLFRACT_FBIT__ /* GCC extension. */
|
||||
#define ULLFRACT_MIN __ULLFRACT_MIN__ /* GCC extension. */
|
||||
#define ULLFRACT_MAX __ULLFRACT_MAX__ /* GCC extension. */
|
||||
#define ULLFRACT_EPSILON __ULLFRACT_EPSILON__ /* GCC extension. */
|
||||
|
||||
#undef SACCUM_FBIT
|
||||
#undef SACCUM_IBIT
|
||||
#undef SACCUM_MIN
|
||||
#undef SACCUM_MAX
|
||||
#undef SACCUM_EPSILON
|
||||
#define SACCUM_FBIT __SACCUM_FBIT__
|
||||
#define SACCUM_IBIT __SACCUM_IBIT__
|
||||
#define SACCUM_MIN __SACCUM_MIN__
|
||||
#define SACCUM_MAX __SACCUM_MAX__
|
||||
#define SACCUM_EPSILON __SACCUM_EPSILON__
|
||||
|
||||
#undef USACCUM_FBIT
|
||||
#undef USACCUM_IBIT
|
||||
#undef USACCUM_MIN
|
||||
#undef USACCUM_MAX
|
||||
#undef USACCUM_EPSILON
|
||||
#define USACCUM_FBIT __USACCUM_FBIT__
|
||||
#define USACCUM_IBIT __USACCUM_IBIT__
|
||||
#define USACCUM_MIN __USACCUM_MIN__ /* GCC extension. */
|
||||
#define USACCUM_MAX __USACCUM_MAX__
|
||||
#define USACCUM_EPSILON __USACCUM_EPSILON__
|
||||
|
||||
#undef ACCUM_FBIT
|
||||
#undef ACCUM_IBIT
|
||||
#undef ACCUM_MIN
|
||||
#undef ACCUM_MAX
|
||||
#undef ACCUM_EPSILON
|
||||
#define ACCUM_FBIT __ACCUM_FBIT__
|
||||
#define ACCUM_IBIT __ACCUM_IBIT__
|
||||
#define ACCUM_MIN __ACCUM_MIN__
|
||||
#define ACCUM_MAX __ACCUM_MAX__
|
||||
#define ACCUM_EPSILON __ACCUM_EPSILON__
|
||||
|
||||
#undef UACCUM_FBIT
|
||||
#undef UACCUM_IBIT
|
||||
#undef UACCUM_MIN
|
||||
#undef UACCUM_MAX
|
||||
#undef UACCUM_EPSILON
|
||||
#define UACCUM_FBIT __UACCUM_FBIT__
|
||||
#define UACCUM_IBIT __UACCUM_IBIT__
|
||||
#define UACCUM_MIN __UACCUM_MIN__ /* GCC extension. */
|
||||
#define UACCUM_MAX __UACCUM_MAX__
|
||||
#define UACCUM_EPSILON __UACCUM_EPSILON__
|
||||
|
||||
#undef LACCUM_FBIT
|
||||
#undef LACCUM_IBIT
|
||||
#undef LACCUM_MIN
|
||||
#undef LACCUM_MAX
|
||||
#undef LACCUM_EPSILON
|
||||
#define LACCUM_FBIT __LACCUM_FBIT__
|
||||
#define LACCUM_IBIT __LACCUM_IBIT__
|
||||
#define LACCUM_MIN __LACCUM_MIN__
|
||||
#define LACCUM_MAX __LACCUM_MAX__
|
||||
#define LACCUM_EPSILON __LACCUM_EPSILON__
|
||||
|
||||
#undef ULACCUM_FBIT
|
||||
#undef ULACCUM_IBIT
|
||||
#undef ULACCUM_MIN
|
||||
#undef ULACCUM_MAX
|
||||
#undef ULACCUM_EPSILON
|
||||
#define ULACCUM_FBIT __ULACCUM_FBIT__
|
||||
#define ULACCUM_IBIT __ULACCUM_IBIT__
|
||||
#define ULACCUM_MIN __ULACCUM_MIN__ /* GCC extension. */
|
||||
#define ULACCUM_MAX __ULACCUM_MAX__
|
||||
#define ULACCUM_EPSILON __ULACCUM_EPSILON__
|
||||
|
||||
#undef LLACCUM_FBIT
|
||||
#undef LLACCUM_IBIT
|
||||
#undef LLACCUM_MIN
|
||||
#undef LLACCUM_MAX
|
||||
#undef LLACCUM_EPSILON
|
||||
#define LLACCUM_FBIT __LLACCUM_FBIT__ /* GCC extension. */
|
||||
#define LLACCUM_IBIT __LLACCUM_IBIT__ /* GCC extension. */
|
||||
#define LLACCUM_MIN __LLACCUM_MIN__ /* GCC extension. */
|
||||
#define LLACCUM_MAX __LLACCUM_MAX__ /* GCC extension. */
|
||||
#define LLACCUM_EPSILON __LLACCUM_EPSILON__ /* GCC extension. */
|
||||
|
||||
#undef ULLACCUM_FBIT
|
||||
#undef ULLACCUM_IBIT
|
||||
#undef ULLACCUM_MIN
|
||||
#undef ULLACCUM_MAX
|
||||
#undef ULLACCUM_EPSILON
|
||||
#define ULLACCUM_FBIT __ULLACCUM_FBIT__ /* GCC extension. */
|
||||
#define ULLACCUM_IBIT __ULLACCUM_IBIT__ /* GCC extension. */
|
||||
#define ULLACCUM_MIN __ULLACCUM_MIN__ /* GCC extension. */
|
||||
#define ULLACCUM_MAX __ULLACCUM_MAX__ /* GCC extension. */
|
||||
#define ULLACCUM_EPSILON __ULLACCUM_EPSILON__ /* GCC extension. */
|
||||
|
||||
#endif /* _STDFIX_H */
|
||||
+369
@@ -0,0 +1,369 @@
|
||||
/* Copyright (C) 2008-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/*
|
||||
* ISO C Standard: 7.18 Integer types <stdint.h>
|
||||
*/
|
||||
|
||||
#ifndef _GCC_STDINT_H
|
||||
#define _GCC_STDINT_H
|
||||
|
||||
/* 7.8.1.1 Exact-width integer types */
|
||||
|
||||
#ifdef __INT8_TYPE__
|
||||
typedef __INT8_TYPE__ int8_t;
|
||||
#endif
|
||||
#ifdef __INT16_TYPE__
|
||||
typedef __INT16_TYPE__ int16_t;
|
||||
#endif
|
||||
#ifdef __INT32_TYPE__
|
||||
typedef __INT32_TYPE__ int32_t;
|
||||
#endif
|
||||
#ifdef __INT64_TYPE__
|
||||
typedef __INT64_TYPE__ int64_t;
|
||||
#endif
|
||||
#ifdef __UINT8_TYPE__
|
||||
typedef __UINT8_TYPE__ uint8_t;
|
||||
#endif
|
||||
#ifdef __UINT16_TYPE__
|
||||
typedef __UINT16_TYPE__ uint16_t;
|
||||
#endif
|
||||
#ifdef __UINT32_TYPE__
|
||||
typedef __UINT32_TYPE__ uint32_t;
|
||||
#endif
|
||||
#ifdef __UINT64_TYPE__
|
||||
typedef __UINT64_TYPE__ uint64_t;
|
||||
#endif
|
||||
|
||||
/* 7.8.1.2 Minimum-width integer types */
|
||||
|
||||
typedef __INT_LEAST8_TYPE__ int_least8_t;
|
||||
typedef __INT_LEAST16_TYPE__ int_least16_t;
|
||||
typedef __INT_LEAST32_TYPE__ int_least32_t;
|
||||
typedef __INT_LEAST64_TYPE__ int_least64_t;
|
||||
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
|
||||
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
|
||||
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
|
||||
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
|
||||
|
||||
/* 7.8.1.3 Fastest minimum-width integer types */
|
||||
|
||||
typedef __INT_FAST8_TYPE__ int_fast8_t;
|
||||
typedef __INT_FAST16_TYPE__ int_fast16_t;
|
||||
typedef __INT_FAST32_TYPE__ int_fast32_t;
|
||||
typedef __INT_FAST64_TYPE__ int_fast64_t;
|
||||
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
|
||||
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
|
||||
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
|
||||
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
|
||||
|
||||
/* 7.8.1.4 Integer types capable of holding object pointers */
|
||||
|
||||
#ifdef __INTPTR_TYPE__
|
||||
typedef __INTPTR_TYPE__ intptr_t;
|
||||
#endif
|
||||
#ifdef __UINTPTR_TYPE__
|
||||
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||
#endif
|
||||
|
||||
/* 7.8.1.5 Greatest-width integer types */
|
||||
|
||||
typedef __INTMAX_TYPE__ intmax_t;
|
||||
typedef __UINTMAX_TYPE__ uintmax_t;
|
||||
|
||||
#if (!defined __cplusplus || __cplusplus >= 201103L \
|
||||
|| defined __STDC_LIMIT_MACROS)
|
||||
|
||||
/* 7.18.2 Limits of specified-width integer types */
|
||||
|
||||
#ifdef __INT8_MAX__
|
||||
# undef INT8_MAX
|
||||
# define INT8_MAX __INT8_MAX__
|
||||
# undef INT8_MIN
|
||||
# define INT8_MIN (-INT8_MAX - 1)
|
||||
#endif
|
||||
#ifdef __UINT8_MAX__
|
||||
# undef UINT8_MAX
|
||||
# define UINT8_MAX __UINT8_MAX__
|
||||
#endif
|
||||
#ifdef __INT16_MAX__
|
||||
# undef INT16_MAX
|
||||
# define INT16_MAX __INT16_MAX__
|
||||
# undef INT16_MIN
|
||||
# define INT16_MIN (-INT16_MAX - 1)
|
||||
#endif
|
||||
#ifdef __UINT16_MAX__
|
||||
# undef UINT16_MAX
|
||||
# define UINT16_MAX __UINT16_MAX__
|
||||
#endif
|
||||
#ifdef __INT32_MAX__
|
||||
# undef INT32_MAX
|
||||
# define INT32_MAX __INT32_MAX__
|
||||
# undef INT32_MIN
|
||||
# define INT32_MIN (-INT32_MAX - 1)
|
||||
#endif
|
||||
#ifdef __UINT32_MAX__
|
||||
# undef UINT32_MAX
|
||||
# define UINT32_MAX __UINT32_MAX__
|
||||
#endif
|
||||
#ifdef __INT64_MAX__
|
||||
# undef INT64_MAX
|
||||
# define INT64_MAX __INT64_MAX__
|
||||
# undef INT64_MIN
|
||||
# define INT64_MIN (-INT64_MAX - 1)
|
||||
#endif
|
||||
#ifdef __UINT64_MAX__
|
||||
# undef UINT64_MAX
|
||||
# define UINT64_MAX __UINT64_MAX__
|
||||
#endif
|
||||
|
||||
#undef INT_LEAST8_MAX
|
||||
#define INT_LEAST8_MAX __INT_LEAST8_MAX__
|
||||
#undef INT_LEAST8_MIN
|
||||
#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1)
|
||||
#undef UINT_LEAST8_MAX
|
||||
#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__
|
||||
#undef INT_LEAST16_MAX
|
||||
#define INT_LEAST16_MAX __INT_LEAST16_MAX__
|
||||
#undef INT_LEAST16_MIN
|
||||
#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1)
|
||||
#undef UINT_LEAST16_MAX
|
||||
#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__
|
||||
#undef INT_LEAST32_MAX
|
||||
#define INT_LEAST32_MAX __INT_LEAST32_MAX__
|
||||
#undef INT_LEAST32_MIN
|
||||
#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1)
|
||||
#undef UINT_LEAST32_MAX
|
||||
#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
|
||||
#undef INT_LEAST64_MAX
|
||||
#define INT_LEAST64_MAX __INT_LEAST64_MAX__
|
||||
#undef INT_LEAST64_MIN
|
||||
#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1)
|
||||
#undef UINT_LEAST64_MAX
|
||||
#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__
|
||||
|
||||
#undef INT_FAST8_MAX
|
||||
#define INT_FAST8_MAX __INT_FAST8_MAX__
|
||||
#undef INT_FAST8_MIN
|
||||
#define INT_FAST8_MIN (-INT_FAST8_MAX - 1)
|
||||
#undef UINT_FAST8_MAX
|
||||
#define UINT_FAST8_MAX __UINT_FAST8_MAX__
|
||||
#undef INT_FAST16_MAX
|
||||
#define INT_FAST16_MAX __INT_FAST16_MAX__
|
||||
#undef INT_FAST16_MIN
|
||||
#define INT_FAST16_MIN (-INT_FAST16_MAX - 1)
|
||||
#undef UINT_FAST16_MAX
|
||||
#define UINT_FAST16_MAX __UINT_FAST16_MAX__
|
||||
#undef INT_FAST32_MAX
|
||||
#define INT_FAST32_MAX __INT_FAST32_MAX__
|
||||
#undef INT_FAST32_MIN
|
||||
#define INT_FAST32_MIN (-INT_FAST32_MAX - 1)
|
||||
#undef UINT_FAST32_MAX
|
||||
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
|
||||
#undef INT_FAST64_MAX
|
||||
#define INT_FAST64_MAX __INT_FAST64_MAX__
|
||||
#undef INT_FAST64_MIN
|
||||
#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
|
||||
#undef UINT_FAST64_MAX
|
||||
#define UINT_FAST64_MAX __UINT_FAST64_MAX__
|
||||
|
||||
#ifdef __INTPTR_MAX__
|
||||
# undef INTPTR_MAX
|
||||
# define INTPTR_MAX __INTPTR_MAX__
|
||||
# undef INTPTR_MIN
|
||||
# define INTPTR_MIN (-INTPTR_MAX - 1)
|
||||
#endif
|
||||
#ifdef __UINTPTR_MAX__
|
||||
# undef UINTPTR_MAX
|
||||
# define UINTPTR_MAX __UINTPTR_MAX__
|
||||
#endif
|
||||
|
||||
#undef INTMAX_MAX
|
||||
#define INTMAX_MAX __INTMAX_MAX__
|
||||
#undef INTMAX_MIN
|
||||
#define INTMAX_MIN (-INTMAX_MAX - 1)
|
||||
#undef UINTMAX_MAX
|
||||
#define UINTMAX_MAX __UINTMAX_MAX__
|
||||
|
||||
/* 7.18.3 Limits of other integer types */
|
||||
|
||||
#undef PTRDIFF_MAX
|
||||
#define PTRDIFF_MAX __PTRDIFF_MAX__
|
||||
#undef PTRDIFF_MIN
|
||||
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
|
||||
|
||||
#undef SIG_ATOMIC_MAX
|
||||
#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
|
||||
#undef SIG_ATOMIC_MIN
|
||||
#define SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__
|
||||
|
||||
#undef SIZE_MAX
|
||||
#define SIZE_MAX __SIZE_MAX__
|
||||
|
||||
#undef WCHAR_MAX
|
||||
#define WCHAR_MAX __WCHAR_MAX__
|
||||
#undef WCHAR_MIN
|
||||
#define WCHAR_MIN __WCHAR_MIN__
|
||||
|
||||
#undef WINT_MAX
|
||||
#define WINT_MAX __WINT_MAX__
|
||||
#undef WINT_MIN
|
||||
#define WINT_MIN __WINT_MIN__
|
||||
|
||||
#endif /* (!defined __cplusplus || __cplusplus >= 201103L
|
||||
|| defined __STDC_LIMIT_MACROS) */
|
||||
|
||||
#if (!defined __cplusplus || __cplusplus >= 201103L \
|
||||
|| defined __STDC_CONSTANT_MACROS)
|
||||
|
||||
#undef INT8_C
|
||||
#define INT8_C(c) __INT8_C(c)
|
||||
#undef INT16_C
|
||||
#define INT16_C(c) __INT16_C(c)
|
||||
#undef INT32_C
|
||||
#define INT32_C(c) __INT32_C(c)
|
||||
#undef INT64_C
|
||||
#define INT64_C(c) __INT64_C(c)
|
||||
#undef UINT8_C
|
||||
#define UINT8_C(c) __UINT8_C(c)
|
||||
#undef UINT16_C
|
||||
#define UINT16_C(c) __UINT16_C(c)
|
||||
#undef UINT32_C
|
||||
#define UINT32_C(c) __UINT32_C(c)
|
||||
#undef UINT64_C
|
||||
#define UINT64_C(c) __UINT64_C(c)
|
||||
#undef INTMAX_C
|
||||
#define INTMAX_C(c) __INTMAX_C(c)
|
||||
#undef UINTMAX_C
|
||||
#define UINTMAX_C(c) __UINTMAX_C(c)
|
||||
|
||||
#endif /* (!defined __cplusplus || __cplusplus >= 201103L
|
||||
|| defined __STDC_CONSTANT_MACROS) */
|
||||
|
||||
#if (defined __STDC_WANT_IEC_60559_BFP_EXT__ \
|
||||
|| (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L))
|
||||
/* TS 18661-1 / C23 widths of integer types. */
|
||||
|
||||
#ifdef __INT8_TYPE__
|
||||
# undef INT8_WIDTH
|
||||
# define INT8_WIDTH 8
|
||||
#endif
|
||||
#ifdef __UINT8_TYPE__
|
||||
# undef UINT8_WIDTH
|
||||
# define UINT8_WIDTH 8
|
||||
#endif
|
||||
#ifdef __INT16_TYPE__
|
||||
# undef INT16_WIDTH
|
||||
# define INT16_WIDTH 16
|
||||
#endif
|
||||
#ifdef __UINT16_TYPE__
|
||||
# undef UINT16_WIDTH
|
||||
# define UINT16_WIDTH 16
|
||||
#endif
|
||||
#ifdef __INT32_TYPE__
|
||||
# undef INT32_WIDTH
|
||||
# define INT32_WIDTH 32
|
||||
#endif
|
||||
#ifdef __UINT32_TYPE__
|
||||
# undef UINT32_WIDTH
|
||||
# define UINT32_WIDTH 32
|
||||
#endif
|
||||
#ifdef __INT64_TYPE__
|
||||
# undef INT64_WIDTH
|
||||
# define INT64_WIDTH 64
|
||||
#endif
|
||||
#ifdef __UINT64_TYPE__
|
||||
# undef UINT64_WIDTH
|
||||
# define UINT64_WIDTH 64
|
||||
#endif
|
||||
|
||||
#undef INT_LEAST8_WIDTH
|
||||
#define INT_LEAST8_WIDTH __INT_LEAST8_WIDTH__
|
||||
#undef UINT_LEAST8_WIDTH
|
||||
#define UINT_LEAST8_WIDTH __INT_LEAST8_WIDTH__
|
||||
#undef INT_LEAST16_WIDTH
|
||||
#define INT_LEAST16_WIDTH __INT_LEAST16_WIDTH__
|
||||
#undef UINT_LEAST16_WIDTH
|
||||
#define UINT_LEAST16_WIDTH __INT_LEAST16_WIDTH__
|
||||
#undef INT_LEAST32_WIDTH
|
||||
#define INT_LEAST32_WIDTH __INT_LEAST32_WIDTH__
|
||||
#undef UINT_LEAST32_WIDTH
|
||||
#define UINT_LEAST32_WIDTH __INT_LEAST32_WIDTH__
|
||||
#undef INT_LEAST64_WIDTH
|
||||
#define INT_LEAST64_WIDTH __INT_LEAST64_WIDTH__
|
||||
#undef UINT_LEAST64_WIDTH
|
||||
#define UINT_LEAST64_WIDTH __INT_LEAST64_WIDTH__
|
||||
|
||||
#undef INT_FAST8_WIDTH
|
||||
#define INT_FAST8_WIDTH __INT_FAST8_WIDTH__
|
||||
#undef UINT_FAST8_WIDTH
|
||||
#define UINT_FAST8_WIDTH __INT_FAST8_WIDTH__
|
||||
#undef INT_FAST16_WIDTH
|
||||
#define INT_FAST16_WIDTH __INT_FAST16_WIDTH__
|
||||
#undef UINT_FAST16_WIDTH
|
||||
#define UINT_FAST16_WIDTH __INT_FAST16_WIDTH__
|
||||
#undef INT_FAST32_WIDTH
|
||||
#define INT_FAST32_WIDTH __INT_FAST32_WIDTH__
|
||||
#undef UINT_FAST32_WIDTH
|
||||
#define UINT_FAST32_WIDTH __INT_FAST32_WIDTH__
|
||||
#undef INT_FAST64_WIDTH
|
||||
#define INT_FAST64_WIDTH __INT_FAST64_WIDTH__
|
||||
#undef UINT_FAST64_WIDTH
|
||||
#define UINT_FAST64_WIDTH __INT_FAST64_WIDTH__
|
||||
|
||||
#ifdef __INTPTR_TYPE__
|
||||
# undef INTPTR_WIDTH
|
||||
# define INTPTR_WIDTH __INTPTR_WIDTH__
|
||||
#endif
|
||||
#ifdef __UINTPTR_TYPE__
|
||||
# undef UINTPTR_WIDTH
|
||||
# define UINTPTR_WIDTH __INTPTR_WIDTH__
|
||||
#endif
|
||||
|
||||
#undef INTMAX_WIDTH
|
||||
#define INTMAX_WIDTH __INTMAX_WIDTH__
|
||||
#undef UINTMAX_WIDTH
|
||||
#define UINTMAX_WIDTH __INTMAX_WIDTH__
|
||||
|
||||
#undef PTRDIFF_WIDTH
|
||||
#define PTRDIFF_WIDTH __PTRDIFF_WIDTH__
|
||||
|
||||
#undef SIG_ATOMIC_WIDTH
|
||||
#define SIG_ATOMIC_WIDTH __SIG_ATOMIC_WIDTH__
|
||||
|
||||
#undef SIZE_WIDTH
|
||||
#define SIZE_WIDTH __SIZE_WIDTH__
|
||||
|
||||
#undef WCHAR_WIDTH
|
||||
#define WCHAR_WIDTH __WCHAR_WIDTH__
|
||||
|
||||
#undef WINT_WIDTH
|
||||
#define WINT_WIDTH __WINT_WIDTH__
|
||||
|
||||
#endif
|
||||
|
||||
#if defined __STDC_VERSION__ && __STDC_VERSION__ > 201710L
|
||||
#define __STDC_VERSION_STDINT_H__ 202311L
|
||||
#endif
|
||||
|
||||
#endif /* _GCC_STDINT_H */
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#ifndef _GCC_WRAP_STDINT_H
|
||||
#if __STDC_HOSTED__
|
||||
# if defined __cplusplus && __cplusplus >= 201103L
|
||||
# undef __STDC_LIMIT_MACROS
|
||||
# define __STDC_LIMIT_MACROS
|
||||
# undef __STDC_CONSTANT_MACROS
|
||||
# define __STDC_CONSTANT_MACROS
|
||||
# endif
|
||||
# include_next <stdint.h>
|
||||
#else
|
||||
# include "stdint-gcc.h"
|
||||
#endif
|
||||
#define _GCC_WRAP_STDINT_H
|
||||
#endif
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/* Copyright (C) 2011-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* ISO C1X: 7.23 _Noreturn <stdnoreturn.h>. */
|
||||
|
||||
#ifndef _STDNORETURN_H
|
||||
#define _STDNORETURN_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#define noreturn _Noreturn
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* stdnoreturn.h */
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/* syslimits.h stands for the system's own limits.h file.
|
||||
If we can use it ok unmodified, then we install this text.
|
||||
If fixincludes fixes it, then the fixed version is installed
|
||||
instead of this text. */
|
||||
|
||||
#define _GCC_NEXT_LIMITS_H /* tell gcc's limits.h to recurse */
|
||||
#include_next <limits.h>
|
||||
#undef _GCC_NEXT_LIMITS_H
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
/* Header file for the ARM EABI and C6X unwinders
|
||||
Copyright (C) 2003-2024 Free Software Foundation, Inc.
|
||||
Contributed by Paul Brook
|
||||
|
||||
This file 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.
|
||||
|
||||
This file 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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Language-independent unwinder header public defines. This contains both
|
||||
ABI defined objects, and GNU support routines. */
|
||||
|
||||
#ifndef UNWIND_ARM_COMMON_H
|
||||
#define UNWIND_ARM_COMMON_H
|
||||
|
||||
#define __ARM_EABI_UNWINDER__ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
|
||||
typedef signed _Unwind_Sword __attribute__((__mode__(__word__)));
|
||||
typedef unsigned _Unwind_Ptr __attribute__((__mode__(__pointer__)));
|
||||
typedef unsigned _Unwind_Internal_Ptr __attribute__((__mode__(__pointer__)));
|
||||
typedef _Unwind_Word _uw;
|
||||
typedef unsigned _uw64 __attribute__((mode(__DI__)));
|
||||
typedef unsigned _uw16 __attribute__((mode(__HI__)));
|
||||
typedef unsigned _uw8 __attribute__((mode(__QI__)));
|
||||
|
||||
typedef enum
|
||||
{
|
||||
_URC_OK = 0, /* operation completed successfully */
|
||||
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||
_URC_END_OF_STACK = 5,
|
||||
_URC_HANDLER_FOUND = 6,
|
||||
_URC_INSTALL_CONTEXT = 7,
|
||||
_URC_CONTINUE_UNWIND = 8,
|
||||
_URC_FAILURE = 9 /* unspecified failure of some kind */
|
||||
}
|
||||
_Unwind_Reason_Code;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
_US_VIRTUAL_UNWIND_FRAME = 0,
|
||||
_US_UNWIND_FRAME_STARTING = 1,
|
||||
_US_UNWIND_FRAME_RESUME = 2,
|
||||
_US_ACTION_MASK = 3,
|
||||
_US_FORCE_UNWIND = 8,
|
||||
_US_END_OF_STACK = 16
|
||||
}
|
||||
_Unwind_State;
|
||||
|
||||
/* Provided only for compatibility with existing code. */
|
||||
typedef int _Unwind_Action;
|
||||
#define _UA_SEARCH_PHASE 1
|
||||
#define _UA_CLEANUP_PHASE 2
|
||||
#define _UA_HANDLER_FRAME 4
|
||||
#define _UA_FORCE_UNWIND 8
|
||||
#define _UA_END_OF_STACK 16
|
||||
#define _URC_NO_REASON _URC_OK
|
||||
|
||||
typedef struct _Unwind_Control_Block _Unwind_Control_Block;
|
||||
typedef struct _Unwind_Context _Unwind_Context;
|
||||
typedef _uw _Unwind_EHT_Header;
|
||||
|
||||
|
||||
/* UCB: */
|
||||
|
||||
struct _Unwind_Control_Block
|
||||
{
|
||||
char exception_class[8];
|
||||
void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *);
|
||||
/* Unwinder cache, private fields for the unwinder's use */
|
||||
struct
|
||||
{
|
||||
_uw reserved1; /* Forced unwind stop fn, 0 if not forced */
|
||||
_uw reserved2; /* Personality routine address */
|
||||
_uw reserved3; /* Saved callsite address */
|
||||
_uw reserved4; /* Forced unwind stop arg */
|
||||
_uw reserved5; /* Personality routine GOT value in FDPIC mode. */
|
||||
}
|
||||
unwinder_cache;
|
||||
/* Propagation barrier cache (valid after phase 1): */
|
||||
struct
|
||||
{
|
||||
_uw sp;
|
||||
_uw bitpattern[5];
|
||||
}
|
||||
barrier_cache;
|
||||
/* Cleanup cache (preserved over cleanup): */
|
||||
struct
|
||||
{
|
||||
_uw bitpattern[4];
|
||||
}
|
||||
cleanup_cache;
|
||||
/* Pr cache (for pr's benefit): */
|
||||
struct
|
||||
{
|
||||
_uw fnstart; /* function start address */
|
||||
_Unwind_EHT_Header *ehtp; /* pointer to EHT entry header word */
|
||||
_uw additional; /* additional data */
|
||||
_uw reserved1;
|
||||
}
|
||||
pr_cache;
|
||||
long long int :0; /* Force alignment to 8-byte boundary */
|
||||
};
|
||||
|
||||
/* Virtual Register Set*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
_UVRSC_CORE = 0, /* integer register */
|
||||
_UVRSC_VFP = 1, /* vfp */
|
||||
_UVRSC_FPA = 2, /* fpa */
|
||||
_UVRSC_WMMXD = 3, /* Intel WMMX data register */
|
||||
_UVRSC_WMMXC = 4, /* Intel WMMX control register */
|
||||
_UVRSC_PAC = 5 /* Armv8.1-M Mainline PAC/AUTH pseudo-register */
|
||||
}
|
||||
_Unwind_VRS_RegClass;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
_UVRSD_UINT32 = 0,
|
||||
_UVRSD_VFPX = 1,
|
||||
_UVRSD_FPAX = 2,
|
||||
_UVRSD_UINT64 = 3,
|
||||
_UVRSD_FLOAT = 4,
|
||||
_UVRSD_DOUBLE = 5
|
||||
}
|
||||
_Unwind_VRS_DataRepresentation;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
_UVRSR_OK = 0,
|
||||
_UVRSR_NOT_IMPLEMENTED = 1,
|
||||
_UVRSR_FAILED = 2
|
||||
}
|
||||
_Unwind_VRS_Result;
|
||||
|
||||
/* Frame unwinding state. */
|
||||
typedef struct
|
||||
{
|
||||
/* The current word (bytes packed msb first). */
|
||||
_uw data;
|
||||
/* Pointer to the next word of data. */
|
||||
_uw *next;
|
||||
/* The number of bytes left in this word. */
|
||||
_uw8 bytes_left;
|
||||
/* The number of words pointed to by ptr. */
|
||||
_uw8 words_left;
|
||||
}
|
||||
__gnu_unwind_state;
|
||||
|
||||
typedef _Unwind_Reason_Code (*personality_routine) (_Unwind_State,
|
||||
_Unwind_Control_Block *, _Unwind_Context *);
|
||||
|
||||
_Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *, _Unwind_VRS_RegClass,
|
||||
_uw, _Unwind_VRS_DataRepresentation,
|
||||
void *);
|
||||
|
||||
_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *, _Unwind_VRS_RegClass,
|
||||
_uw, _Unwind_VRS_DataRepresentation,
|
||||
void *);
|
||||
|
||||
_Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context *, _Unwind_VRS_RegClass,
|
||||
_uw, _Unwind_VRS_DataRepresentation);
|
||||
|
||||
|
||||
/* Support functions for the PR. */
|
||||
#define _Unwind_Exception _Unwind_Control_Block
|
||||
typedef char _Unwind_Exception_Class[8];
|
||||
|
||||
void * _Unwind_GetLanguageSpecificData (_Unwind_Context *);
|
||||
_Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
|
||||
|
||||
_Unwind_Ptr _Unwind_GetDataRelBase (_Unwind_Context *);
|
||||
/* This should never be used. */
|
||||
_Unwind_Ptr _Unwind_GetTextRelBase (_Unwind_Context *);
|
||||
|
||||
/* Interface functions: */
|
||||
_Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block *ucbp);
|
||||
void __attribute__((noreturn)) _Unwind_Resume(_Unwind_Control_Block *ucbp);
|
||||
_Unwind_Reason_Code _Unwind_Resume_or_Rethrow (_Unwind_Control_Block *ucbp);
|
||||
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
|
||||
(int, _Unwind_Action, _Unwind_Exception_Class,
|
||||
_Unwind_Control_Block *, struct _Unwind_Context *, void *);
|
||||
_Unwind_Reason_Code _Unwind_ForcedUnwind (_Unwind_Control_Block *,
|
||||
_Unwind_Stop_Fn, void *);
|
||||
/* @@@ Use unwind data to perform a stack backtrace. The trace callback
|
||||
is called for every stack frame in the call chain, but no cleanup
|
||||
actions are performed. */
|
||||
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (_Unwind_Context *, void *);
|
||||
_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn,
|
||||
void*);
|
||||
|
||||
_Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *);
|
||||
void _Unwind_Complete(_Unwind_Control_Block *ucbp);
|
||||
void _Unwind_DeleteException (_Unwind_Exception *);
|
||||
|
||||
_Unwind_Reason_Code __gnu_unwind_frame (_Unwind_Control_Block *,
|
||||
_Unwind_Context *);
|
||||
_Unwind_Reason_Code __gnu_unwind_execute (_Unwind_Context *,
|
||||
__gnu_unwind_state *);
|
||||
|
||||
static inline _Unwind_Word
|
||||
_Unwind_GetGR (_Unwind_Context *context, int regno)
|
||||
{
|
||||
_uw val;
|
||||
_Unwind_VRS_Get (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
#define _Unwind_GetIPInfo(context, ip_before_insn) \
|
||||
(*ip_before_insn = 0, _Unwind_GetIP (context))
|
||||
|
||||
static inline void
|
||||
_Unwind_SetGR (_Unwind_Context *context, int regno, _Unwind_Word val)
|
||||
{
|
||||
_Unwind_VRS_Set (context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val);
|
||||
}
|
||||
|
||||
_Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
|
||||
void * _Unwind_GetLanguageSpecificData (_Unwind_Context *);
|
||||
|
||||
/* leb128 type numbers have a potentially unlimited size.
|
||||
The target of the following definitions of _sleb128_t and _uleb128_t
|
||||
is to have efficient data types large enough to hold the leb128 type
|
||||
numbers used in the unwind code. */
|
||||
typedef long _sleb128_t;
|
||||
typedef unsigned long _uleb128_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* defined UNWIND_ARM_COMMON_H */
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/* Header file for the ARM EABI unwinder
|
||||
Copyright (C) 2003-2024 Free Software Foundation, Inc.
|
||||
Contributed by Paul Brook
|
||||
|
||||
This file 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.
|
||||
|
||||
This file 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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Language-independent unwinder header public defines. This contains both
|
||||
ABI defined objects, and GNU support routines. */
|
||||
|
||||
#ifndef UNWIND_ARM_H
|
||||
#define UNWIND_ARM_H
|
||||
|
||||
#include "unwind-arm-common.h"
|
||||
|
||||
#define UNWIND_STACK_REG 13
|
||||
/* Use IP as a scratch register within the personality routine. */
|
||||
#define UNWIND_POINTER_REG 12
|
||||
|
||||
#define FDPIC_REGNUM 9
|
||||
|
||||
#define STR(x) #x
|
||||
#define XSTR(x) STR(x)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
_Unwind_Ptr __attribute__((weak)) __gnu_Unwind_Find_got (_Unwind_Ptr);
|
||||
|
||||
static inline _Unwind_Ptr _Unwind_gnu_Find_got (_Unwind_Ptr ptr)
|
||||
{
|
||||
_Unwind_Ptr res;
|
||||
|
||||
if (__gnu_Unwind_Find_got)
|
||||
res = __gnu_Unwind_Find_got (ptr);
|
||||
else
|
||||
__asm volatile ("mov %[result], r" XSTR(FDPIC_REGNUM)
|
||||
: [result] "=r" (res));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Decode an R_ARM_TARGET2 relocation. */
|
||||
static inline _Unwind_Word
|
||||
_Unwind_decode_typeinfo_ptr (_Unwind_Word base __attribute__ ((unused)),
|
||||
_Unwind_Word ptr)
|
||||
{
|
||||
_Unwind_Word tmp;
|
||||
|
||||
tmp = *(_Unwind_Word *) ptr;
|
||||
/* Zero values are always NULL. */
|
||||
if (!tmp)
|
||||
return 0;
|
||||
|
||||
#if __FDPIC__
|
||||
/* For FDPIC, we store the offset of the GOT entry. */
|
||||
/* So, first get GOT from dynamic linker and then use indirect access. */
|
||||
tmp += _Unwind_gnu_Find_got (ptr);
|
||||
tmp = *(_Unwind_Word *) tmp;
|
||||
#elif (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__) \
|
||||
|| defined(__FreeBSD__) || defined(__fuchsia__)
|
||||
/* Pc-relative indirect. */
|
||||
#define _GLIBCXX_OVERRIDE_TTYPE_ENCODING (DW_EH_PE_pcrel | DW_EH_PE_indirect)
|
||||
tmp += ptr;
|
||||
tmp = *(_Unwind_Word *) tmp;
|
||||
#elif defined(__symbian__) || defined(__uClinux__)
|
||||
#define _GLIBCXX_OVERRIDE_TTYPE_ENCODING (DW_EH_PE_absptr)
|
||||
/* Absolute pointer. Nothing more to do. */
|
||||
#else
|
||||
#define _GLIBCXX_OVERRIDE_TTYPE_ENCODING (DW_EH_PE_pcrel)
|
||||
/* Pc-relative pointer. */
|
||||
tmp += ptr;
|
||||
#endif
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static inline _Unwind_Reason_Code
|
||||
__gnu_unwind_24bit (_Unwind_Context * context __attribute__ ((unused)),
|
||||
_uw data __attribute__ ((unused)),
|
||||
int compact __attribute__ ((unused)))
|
||||
{
|
||||
return _URC_FAILURE;
|
||||
}
|
||||
#ifndef __FreeBSD__
|
||||
/* Return the address of the instruction, not the actual IP value. */
|
||||
#define _Unwind_GetIP(context) \
|
||||
(_Unwind_GetGR (context, 15) & ~(_Unwind_Word)1)
|
||||
|
||||
#define _Unwind_SetIP(context, val) \
|
||||
_Unwind_SetGR (context, 15, val | (_Unwind_GetGR (context, 15) & 1))
|
||||
#else
|
||||
#undef _Unwind_GetIPInfo
|
||||
_Unwind_Ptr _Unwind_GetIP (struct _Unwind_Context *);
|
||||
_Unwind_Ptr _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
|
||||
void _Unwind_SetIP (struct _Unwind_Context *, _Unwind_Ptr);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* defined UNWIND_ARM_H */
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
#ifndef _VARARGS_H
|
||||
#define _VARARGS_H
|
||||
|
||||
#error "GCC no longer implements <varargs.h>."
|
||||
#error "Revise your code to use <stdarg.h>."
|
||||
|
||||
#endif
|
||||
+1
@@ -0,0 +1 @@
|
||||
;
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/* syslimits.h stands for the system's own limits.h file.
|
||||
If we can use it ok unmodified, then we install this text.
|
||||
If fixincludes fixes it, then the fixed version is installed
|
||||
instead of this text. */
|
||||
|
||||
#define _GCC_NEXT_LIMITS_H /* tell gcc's limits.h to recurse */
|
||||
#include_next <limits.h>
|
||||
#undef _GCC_NEXT_LIMITS_H
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
This README file is copied into the directory for GCC-only header files
|
||||
when fixincludes is run by the makefile for GCC.
|
||||
|
||||
Many of the files in this directory were automatically edited from the
|
||||
standard system header files by the fixincludes process. They are
|
||||
system-specific, and will not work on any other kind of system. They
|
||||
are also not part of GCC. The reason we have to do this is because
|
||||
GCC requires ANSI C headers and many vendors supply ANSI-incompatible
|
||||
headers.
|
||||
|
||||
Because this is an automated process, sometimes headers get "fixed"
|
||||
that do not, strictly speaking, need a fix. As long as nothing is broken
|
||||
by the process, it is just an unfortunate collateral inconvenience.
|
||||
We would like to rectify it, if it is not "too inconvenient".
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
/* Copyright (C) 1992-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This administrivia gets added to the beginning of limits.h
|
||||
if the system has its own version of limits.h. */
|
||||
|
||||
/* We use _GCC_LIMITS_H_ because we want this not to match
|
||||
any macros that the system's limits.h uses for its own purposes. */
|
||||
#ifndef _GCC_LIMITS_H_ /* Terminated in limity.h. */
|
||||
#define _GCC_LIMITS_H_
|
||||
|
||||
#ifndef _LIBC_LIMITS_H_
|
||||
/* Use "..." so that we find syslimits.h only in this same directory. */
|
||||
#include "syslimits.h"
|
||||
#endif
|
||||
/* Copyright (C) 1991-2024 Free Software Foundation, Inc.
|
||||
|
||||
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.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _LIMITS_H___
|
||||
#define _LIMITS_H___
|
||||
|
||||
/* Number of bits in a `char'. */
|
||||
#undef CHAR_BIT
|
||||
#define CHAR_BIT __CHAR_BIT__
|
||||
|
||||
/* Maximum length of a multibyte character. */
|
||||
#ifndef MB_LEN_MAX
|
||||
#define MB_LEN_MAX 1
|
||||
#endif
|
||||
|
||||
/* Minimum and maximum values a `signed char' can hold. */
|
||||
#undef SCHAR_MIN
|
||||
#define SCHAR_MIN (-SCHAR_MAX - 1)
|
||||
#undef SCHAR_MAX
|
||||
#define SCHAR_MAX __SCHAR_MAX__
|
||||
|
||||
/* Maximum value an `unsigned char' can hold. (Minimum is 0). */
|
||||
#undef UCHAR_MAX
|
||||
#if __SCHAR_MAX__ == __INT_MAX__
|
||||
# define UCHAR_MAX (SCHAR_MAX * 2U + 1U)
|
||||
#else
|
||||
# define UCHAR_MAX (SCHAR_MAX * 2 + 1)
|
||||
#endif
|
||||
|
||||
/* Minimum and maximum values a `char' can hold. */
|
||||
#ifdef __CHAR_UNSIGNED__
|
||||
# undef CHAR_MIN
|
||||
# if __SCHAR_MAX__ == __INT_MAX__
|
||||
# define CHAR_MIN 0U
|
||||
# else
|
||||
# define CHAR_MIN 0
|
||||
# endif
|
||||
# undef CHAR_MAX
|
||||
# define CHAR_MAX UCHAR_MAX
|
||||
#else
|
||||
# undef CHAR_MIN
|
||||
# define CHAR_MIN SCHAR_MIN
|
||||
# undef CHAR_MAX
|
||||
# define CHAR_MAX SCHAR_MAX
|
||||
#endif
|
||||
|
||||
/* Minimum and maximum values a `signed short int' can hold. */
|
||||
#undef SHRT_MIN
|
||||
#define SHRT_MIN (-SHRT_MAX - 1)
|
||||
#undef SHRT_MAX
|
||||
#define SHRT_MAX __SHRT_MAX__
|
||||
|
||||
/* Maximum value an `unsigned short int' can hold. (Minimum is 0). */
|
||||
#undef USHRT_MAX
|
||||
#if __SHRT_MAX__ == __INT_MAX__
|
||||
# define USHRT_MAX (SHRT_MAX * 2U + 1U)
|
||||
#else
|
||||
# define USHRT_MAX (SHRT_MAX * 2 + 1)
|
||||
#endif
|
||||
|
||||
/* Minimum and maximum values a `signed int' can hold. */
|
||||
#undef INT_MIN
|
||||
#define INT_MIN (-INT_MAX - 1)
|
||||
#undef INT_MAX
|
||||
#define INT_MAX __INT_MAX__
|
||||
|
||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0). */
|
||||
#undef UINT_MAX
|
||||
#define UINT_MAX (INT_MAX * 2U + 1U)
|
||||
|
||||
/* Minimum and maximum values a `signed long int' can hold.
|
||||
(Same as `int'). */
|
||||
#undef LONG_MIN
|
||||
#define LONG_MIN (-LONG_MAX - 1L)
|
||||
#undef LONG_MAX
|
||||
#define LONG_MAX __LONG_MAX__
|
||||
|
||||
/* Maximum value an `unsigned long int' can hold. (Minimum is 0). */
|
||||
#undef ULONG_MAX
|
||||
#define ULONG_MAX (LONG_MAX * 2UL + 1UL)
|
||||
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
/* Minimum and maximum values a `signed long long int' can hold. */
|
||||
# undef LLONG_MIN
|
||||
# define LLONG_MIN (-LLONG_MAX - 1LL)
|
||||
# undef LLONG_MAX
|
||||
# define LLONG_MAX __LONG_LONG_MAX__
|
||||
|
||||
/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */
|
||||
# undef ULLONG_MAX
|
||||
# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
|
||||
#endif
|
||||
|
||||
#if defined (__GNU_LIBRARY__) ? defined (__USE_GNU) : !defined (__STRICT_ANSI__)
|
||||
/* Minimum and maximum values a `signed long long int' can hold. */
|
||||
# undef LONG_LONG_MIN
|
||||
# define LONG_LONG_MIN (-LONG_LONG_MAX - 1LL)
|
||||
# undef LONG_LONG_MAX
|
||||
# define LONG_LONG_MAX __LONG_LONG_MAX__
|
||||
|
||||
/* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */
|
||||
# undef ULONG_LONG_MAX
|
||||
# define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1ULL)
|
||||
#endif
|
||||
|
||||
#if (defined __STDC_WANT_IEC_60559_BFP_EXT__ \
|
||||
|| (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L))
|
||||
/* TS 18661-1 / C23 widths of integer types. */
|
||||
# undef CHAR_WIDTH
|
||||
# define CHAR_WIDTH __SCHAR_WIDTH__
|
||||
# undef SCHAR_WIDTH
|
||||
# define SCHAR_WIDTH __SCHAR_WIDTH__
|
||||
# undef UCHAR_WIDTH
|
||||
# define UCHAR_WIDTH __SCHAR_WIDTH__
|
||||
# undef SHRT_WIDTH
|
||||
# define SHRT_WIDTH __SHRT_WIDTH__
|
||||
# undef USHRT_WIDTH
|
||||
# define USHRT_WIDTH __SHRT_WIDTH__
|
||||
# undef INT_WIDTH
|
||||
# define INT_WIDTH __INT_WIDTH__
|
||||
# undef UINT_WIDTH
|
||||
# define UINT_WIDTH __INT_WIDTH__
|
||||
# undef LONG_WIDTH
|
||||
# define LONG_WIDTH __LONG_WIDTH__
|
||||
# undef ULONG_WIDTH
|
||||
# define ULONG_WIDTH __LONG_WIDTH__
|
||||
# undef LLONG_WIDTH
|
||||
# define LLONG_WIDTH __LONG_LONG_WIDTH__
|
||||
# undef ULLONG_WIDTH
|
||||
# define ULLONG_WIDTH __LONG_LONG_WIDTH__
|
||||
#endif
|
||||
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L
|
||||
/* C23 width and limit of _Bool. */
|
||||
# undef BOOL_MAX
|
||||
# define BOOL_MAX 1
|
||||
# undef BOOL_WIDTH
|
||||
# define BOOL_WIDTH 1
|
||||
|
||||
# ifdef __BITINT_MAXWIDTH__
|
||||
# undef BITINT_MAXWIDTH
|
||||
# define BITINT_MAXWIDTH __BITINT_MAXWIDTH__
|
||||
# endif
|
||||
|
||||
# define __STDC_VERSION_LIMITS_H__ 202311L
|
||||
#endif
|
||||
|
||||
#endif /* _LIMITS_H___ */
|
||||
/* This administrivia gets added to the end of limits.h
|
||||
if the system has its own version of limits.h. */
|
||||
|
||||
#else /* not _GCC_LIMITS_H_ */
|
||||
|
||||
#ifdef _GCC_NEXT_LIMITS_H
|
||||
#include_next <limits.h> /* recurse down to the real one */
|
||||
#endif
|
||||
|
||||
#endif /* not _GCC_LIMITS_H_ */
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
linux
|
||||
unix
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
SYSTEM_HEADER_DIR="/github/home/x-tools/arm-kobo-linux-gnueabihf/arm-kobo-linux-gnueabihf/sysroot${sysroot_headers_suffix}/usr/include"
|
||||
OTHER_FIXINCLUDES_DIRS=""
|
||||
STMP_FIXINC="stmp-fixinc"
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+41693
File diff suppressed because it is too large
Load Diff
+83
@@ -0,0 +1,83 @@
|
||||
/****************************************************************************
|
||||
* *
|
||||
* GNAT COMPILER COMPONENTS *
|
||||
* *
|
||||
* GNAT-SPECIFIC GCC TREE CODES *
|
||||
* *
|
||||
* Specification *
|
||||
* *
|
||||
* Copyright (C) 1992-2024, Free Software Foundation, Inc. *
|
||||
* *
|
||||
* GNAT is free software; you can redistribute it and/or modify it under *
|
||||
* terms of the GNU General Public License as published by the Free Soft- *
|
||||
* ware Foundation; either version 3, or (at your option) any later ver- *
|
||||
* sion. GNAT is distributed in the hope that it will be useful, but WITH- *
|
||||
* OUT 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/>. *
|
||||
* *
|
||||
* GNAT was originally developed by the GNAT team at New York University. *
|
||||
* Extensive contributions were provided by Ada Core Technologies Inc. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
/* A type that is an unconstrained array. This node is never passed to GCC.
|
||||
TREE_TYPE is the type of the fat pointer and TYPE_OBJECT_RECORD_TYPE is
|
||||
the type of a record containing the template and data. */
|
||||
DEFTREECODE (UNCONSTRAINED_ARRAY_TYPE, "unconstrained_array_type", tcc_type, 0)
|
||||
|
||||
/* A reference to an unconstrained array. This node only exists as an
|
||||
intermediate node during the translation of a GNAT tree to a GCC tree;
|
||||
it is never passed to GCC. The only field used is operand 0, which
|
||||
is the fat pointer object. */
|
||||
DEFTREECODE (UNCONSTRAINED_ARRAY_REF, "unconstrained_array_ref",
|
||||
tcc_reference, 1)
|
||||
|
||||
/* Same as SAVE_EXPR, but operand 1 contains the statement used to initialize
|
||||
the temporary instead of using the value of operand 0 directly. */
|
||||
DEFTREECODE (LOAD_EXPR, "load_expr", tcc_expression, 2)
|
||||
|
||||
/* An expression that returns an RTL suitable for its type. Operand 0
|
||||
is an expression to be evaluated for side effects only. */
|
||||
DEFTREECODE (NULL_EXPR, "null_expr", tcc_expression, 1)
|
||||
|
||||
/* Same as PLUS_EXPR, except that no modulo reduction is applied.
|
||||
This is used for loops and never shows up in the tree. */
|
||||
DEFTREECODE (PLUS_NOMOD_EXPR, "plus_nomod_expr", tcc_binary, 2)
|
||||
|
||||
/* Same as MINUS_EXPR, except that no modulo reduction is applied.
|
||||
This is used for loops and never shows up in the tree. */
|
||||
DEFTREECODE (MINUS_NOMOD_EXPR, "minus_nomod_expr", tcc_binary, 2)
|
||||
|
||||
/* An expression that computes an exponentiation. Operand 0 is the base and
|
||||
Operand 1 is the exponent. This node is never passed to GCC: it is only
|
||||
used internally to describe fixed point types scale factors. */
|
||||
DEFTREECODE (POWER_EXPR, "power_expr", tcc_binary, 2)
|
||||
|
||||
/* Same as ADDR_EXPR, except that if the operand represents a bit field,
|
||||
return the address of the byte containing the bit. This is used
|
||||
for the Address attribute and never shows up in the tree. */
|
||||
DEFTREECODE (ATTR_ADDR_EXPR, "attr_addr_expr", tcc_reference, 1)
|
||||
|
||||
/* Here are the tree codes for the statement types known to Ada. These
|
||||
must be at the end of this file to allow IS_ADA_STMT to work. */
|
||||
|
||||
/* This is how record_code_position and insert_code_for work. The former
|
||||
makes this tree node, whose operand is a statement. The latter inserts
|
||||
the actual statements into this node. Gimplification consists of
|
||||
just returning the inner statement. */
|
||||
DEFTREECODE (STMT_STMT, "stmt_stmt", tcc_statement, 1)
|
||||
|
||||
/* A loop. LOOP_STMT_COND is the test to exit the loop. LOOP_STMT_UPDATE
|
||||
is the statement to update the loop iteration variable at the continue
|
||||
point. LOOP_STMT_BODY are the statements in the body of the loop. And
|
||||
LOOP_STMT_LABEL points to the LABEL_DECL of the end label of the loop. */
|
||||
DEFTREECODE (LOOP_STMT, "loop_stmt", tcc_statement, 4)
|
||||
|
||||
/* Conditionally exit a loop. EXIT_STMT_COND is the condition, which, if
|
||||
true, will cause the loop to be exited. If no condition is specified,
|
||||
the loop is unconditionally exited. EXIT_STMT_LABEL is the end label
|
||||
corresponding to the loop to exit. */
|
||||
DEFTREECODE (EXIT_STMT, "exit_stmt", tcc_statement, 2)
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/* Inline functions to test validity of reg classes for addressing modes.
|
||||
Copyright (C) 2006-2024 Free Software Foundation, Inc.
|
||||
|
||||
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/>. */
|
||||
|
||||
/* Wrapper function to unify target macros MODE_CODE_BASE_REG_CLASS,
|
||||
MODE_BASE_REG_REG_CLASS, MODE_BASE_REG_CLASS and BASE_REG_CLASS.
|
||||
Arguments as for the MODE_CODE_BASE_REG_CLASS macro. */
|
||||
|
||||
#ifndef GCC_ADDRESSES_H
|
||||
#define GCC_ADDRESSES_H
|
||||
|
||||
inline enum reg_class
|
||||
base_reg_class (machine_mode mode ATTRIBUTE_UNUSED,
|
||||
addr_space_t as ATTRIBUTE_UNUSED,
|
||||
enum rtx_code outer_code ATTRIBUTE_UNUSED,
|
||||
enum rtx_code index_code ATTRIBUTE_UNUSED,
|
||||
rtx_insn *insn ATTRIBUTE_UNUSED = NULL)
|
||||
{
|
||||
#ifdef INSN_BASE_REG_CLASS
|
||||
return INSN_BASE_REG_CLASS (insn);
|
||||
#else
|
||||
#ifdef MODE_CODE_BASE_REG_CLASS
|
||||
return MODE_CODE_BASE_REG_CLASS (MACRO_MODE (mode), as, outer_code,
|
||||
index_code);
|
||||
#else
|
||||
#ifdef MODE_BASE_REG_REG_CLASS
|
||||
if (index_code == REG)
|
||||
return MODE_BASE_REG_REG_CLASS (MACRO_MODE (mode));
|
||||
#endif
|
||||
#ifdef MODE_BASE_REG_CLASS
|
||||
return MODE_BASE_REG_CLASS (MACRO_MODE (mode));
|
||||
#else
|
||||
return BASE_REG_CLASS;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
inline enum reg_class
|
||||
index_reg_class (rtx_insn *insn ATTRIBUTE_UNUSED = NULL)
|
||||
{
|
||||
#ifdef INSN_INDEX_REG_CLASS
|
||||
return INSN_INDEX_REG_CLASS (insn);
|
||||
#else
|
||||
return INDEX_REG_CLASS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Wrapper function to unify target macros REGNO_MODE_CODE_OK_FOR_BASE_P,
|
||||
REGNO_MODE_OK_FOR_REG_BASE_P, REGNO_MODE_OK_FOR_BASE_P and
|
||||
REGNO_OK_FOR_BASE_P.
|
||||
Arguments as for the REGNO_MODE_CODE_OK_FOR_BASE_P macro. */
|
||||
|
||||
inline bool
|
||||
ok_for_base_p_1 (unsigned regno ATTRIBUTE_UNUSED,
|
||||
machine_mode mode ATTRIBUTE_UNUSED,
|
||||
addr_space_t as ATTRIBUTE_UNUSED,
|
||||
enum rtx_code outer_code ATTRIBUTE_UNUSED,
|
||||
enum rtx_code index_code ATTRIBUTE_UNUSED,
|
||||
rtx_insn* insn ATTRIBUTE_UNUSED = NULL)
|
||||
{
|
||||
#ifdef REGNO_OK_FOR_INSN_BASE_P
|
||||
return REGNO_OK_FOR_INSN_BASE_P (regno, insn);
|
||||
#else
|
||||
#ifdef REGNO_MODE_CODE_OK_FOR_BASE_P
|
||||
return REGNO_MODE_CODE_OK_FOR_BASE_P (regno, MACRO_MODE (mode), as,
|
||||
outer_code, index_code);
|
||||
#else
|
||||
#ifdef REGNO_MODE_OK_FOR_REG_BASE_P
|
||||
if (index_code == REG)
|
||||
return REGNO_MODE_OK_FOR_REG_BASE_P (regno, MACRO_MODE (mode));
|
||||
#endif
|
||||
#ifdef REGNO_MODE_OK_FOR_BASE_P
|
||||
return REGNO_MODE_OK_FOR_BASE_P (regno, MACRO_MODE (mode));
|
||||
#else
|
||||
return REGNO_OK_FOR_BASE_P (regno);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Wrapper around ok_for_base_p_1, for use after register allocation is
|
||||
complete. Arguments as for the called function. */
|
||||
|
||||
inline bool
|
||||
regno_ok_for_base_p (unsigned regno, machine_mode mode, addr_space_t as,
|
||||
enum rtx_code outer_code, enum rtx_code index_code,
|
||||
rtx_insn *insn = NULL)
|
||||
{
|
||||
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] >= 0)
|
||||
regno = reg_renumber[regno];
|
||||
|
||||
return ok_for_base_p_1 (regno, mode, as, outer_code, index_code, insn);
|
||||
}
|
||||
|
||||
#endif /* GCC_ADDRESSES_H */
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/* Exported functions from alias.cc
|
||||
Copyright (C) 2004-2024 Free Software Foundation, Inc.
|
||||
|
||||
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_ALIAS_H
|
||||
#define GCC_ALIAS_H
|
||||
|
||||
extern alias_set_type new_alias_set (void);
|
||||
extern alias_set_type get_alias_set (tree);
|
||||
extern alias_set_type get_deref_alias_set (tree);
|
||||
extern alias_set_type get_varargs_alias_set (void);
|
||||
extern alias_set_type get_frame_alias_set (void);
|
||||
extern tree component_uses_parent_alias_set_from (const_tree);
|
||||
extern bool ends_tbaa_access_path_p (const_tree);
|
||||
extern bool alias_set_subset_of (alias_set_type, alias_set_type);
|
||||
extern void record_alias_subset (alias_set_type, alias_set_type);
|
||||
extern void record_component_aliases (tree);
|
||||
extern bool alias_sets_conflict_p (alias_set_type, alias_set_type);
|
||||
extern bool alias_sets_must_conflict_p (alias_set_type, alias_set_type);
|
||||
extern bool objects_must_conflict_p (tree, tree);
|
||||
extern bool nonoverlapping_memrefs_p (const_rtx, const_rtx, bool);
|
||||
extern void dump_alias_stats_in_alias_c (FILE *s);
|
||||
tree reference_alias_ptr_type (tree);
|
||||
tree reference_alias_ptr_type_1 (tree *);
|
||||
bool alias_ptr_types_compatible_p (tree, tree);
|
||||
int compare_base_decls (tree, tree);
|
||||
bool refs_same_for_tbaa_p (tree, tree);
|
||||
bool mems_same_for_tbaa_p (rtx, rtx);
|
||||
|
||||
/* This alias set can be used to force a memory to conflict with all
|
||||
other memories, creating a barrier across which no memory reference
|
||||
can move. Note that there are other legacy ways to create such
|
||||
memory barriers, including an address of SCRATCH. */
|
||||
#define ALIAS_SET_MEMORY_BARRIER ((alias_set_type) -1)
|
||||
|
||||
#endif /* GCC_ALIAS_H */
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/* Alignment-related classes.
|
||||
Copyright (C) 2018-2024 Free Software Foundation, Inc.
|
||||
|
||||
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/>. */
|
||||
|
||||
/* Align flags tuple with alignment in log form and with a maximum skip. */
|
||||
|
||||
struct align_flags_tuple
|
||||
{
|
||||
/* Values of the -falign-* flags: how much to align labels in code.
|
||||
log is "align to 2^log" (so 0 means no alignment).
|
||||
maxskip is the maximum allowed amount of padding to insert. */
|
||||
int log;
|
||||
int maxskip;
|
||||
|
||||
/* Normalize filled values so that maxskip is not bigger than 1 << log. */
|
||||
void normalize ()
|
||||
{
|
||||
int n = (1 << log);
|
||||
if (maxskip > n)
|
||||
maxskip = n - 1;
|
||||
}
|
||||
|
||||
/* Return original value of an alignment flag. */
|
||||
int get_value ()
|
||||
{
|
||||
return maxskip + 1;
|
||||
}
|
||||
};
|
||||
|
||||
/* Alignment flags is structure used as value of -align-* options.
|
||||
It's used in target-dependant code. */
|
||||
|
||||
class align_flags
|
||||
{
|
||||
public:
|
||||
/* Default constructor. */
|
||||
align_flags (int log0 = 0, int maxskip0 = 0, int log1 = 0, int maxskip1 = 0)
|
||||
{
|
||||
levels[0].log = log0;
|
||||
levels[0].maxskip = maxskip0;
|
||||
levels[1].log = log1;
|
||||
levels[1].maxskip = maxskip1;
|
||||
normalize ();
|
||||
}
|
||||
|
||||
/* Normalize both components of align_flags. */
|
||||
void normalize ()
|
||||
{
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
levels[i].normalize ();
|
||||
}
|
||||
|
||||
/* Get alignment that is common bigger alignment of alignments F0 and F1. */
|
||||
static align_flags max (const align_flags f0, const align_flags f1)
|
||||
{
|
||||
int log0 = MAX (f0.levels[0].log, f1.levels[0].log);
|
||||
int maxskip0 = MAX (f0.levels[0].maxskip, f1.levels[0].maxskip);
|
||||
int log1 = MAX (f0.levels[1].log, f1.levels[1].log);
|
||||
int maxskip1 = MAX (f0.levels[1].maxskip, f1.levels[1].maxskip);
|
||||
return align_flags (log0, maxskip0, log1, maxskip1);
|
||||
}
|
||||
|
||||
align_flags_tuple levels[2];
|
||||
};
|
||||
|
||||
/* Define maximum supported code alignment. */
|
||||
#define MAX_CODE_ALIGN 16
|
||||
#define MAX_CODE_ALIGN_VALUE (1 << MAX_CODE_ALIGN)
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
#include "tree.def"
|
||||
END_OF_BASE_TREE_CODES
|
||||
#include "c-family/c-common.def"
|
||||
#include "ada/gcc-interface/ada-tree.def"
|
||||
#include "c/c-tree.def"
|
||||
#include "cp/cp-tree.def"
|
||||
#include "d/d-tree.def"
|
||||
#include "m2/m2-tree.def"
|
||||
#include "objc/objc-tree.def"
|
||||
+576
@@ -0,0 +1,576 @@
|
||||
/* Functions to support a pool of allocatable objects
|
||||
Copyright (C) 1997-2024 Free Software Foundation, Inc.
|
||||
Contributed by Daniel Berlin <dan@cgsoftware.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 ALLOC_POOL_H
|
||||
#define ALLOC_POOL_H
|
||||
|
||||
#include "memory-block.h"
|
||||
#include "options.h" // for flag_checking
|
||||
|
||||
extern void dump_alloc_pool_statistics (void);
|
||||
|
||||
/* Flag indicates whether memory statistics are gathered any longer. */
|
||||
extern bool after_memory_report;
|
||||
|
||||
typedef unsigned long ALLOC_POOL_ID_TYPE;
|
||||
|
||||
/* Last used ID. */
|
||||
extern ALLOC_POOL_ID_TYPE last_id;
|
||||
|
||||
/* Pool allocator memory usage. */
|
||||
class pool_usage: public mem_usage
|
||||
{
|
||||
public:
|
||||
/* Default contructor. */
|
||||
pool_usage (): m_element_size (0), m_pool_name ("") {}
|
||||
/* Constructor. */
|
||||
pool_usage (size_t allocated, size_t times, size_t peak,
|
||||
size_t instances, size_t element_size,
|
||||
const char *pool_name)
|
||||
: mem_usage (allocated, times, peak, instances),
|
||||
m_element_size (element_size),
|
||||
m_pool_name (pool_name) {}
|
||||
|
||||
/* Sum the usage with SECOND usage. */
|
||||
pool_usage
|
||||
operator+ (const pool_usage &second)
|
||||
{
|
||||
return pool_usage (m_allocated + second.m_allocated,
|
||||
m_times + second.m_times,
|
||||
m_peak + second.m_peak,
|
||||
m_instances + second.m_instances,
|
||||
m_element_size, m_pool_name);
|
||||
}
|
||||
|
||||
/* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
|
||||
inline void
|
||||
dump (mem_location *loc, const mem_usage &total) const
|
||||
{
|
||||
char *location_string = loc->to_string ();
|
||||
|
||||
fprintf (stderr, "%-32s%-48s " PRsa(5) PRsa(9) ":%5.1f%%"
|
||||
PRsa(9) PRsa(9) ":%5.1f%%%12" PRIu64 "\n",
|
||||
m_pool_name, location_string,
|
||||
SIZE_AMOUNT (m_instances),
|
||||
SIZE_AMOUNT (m_allocated),
|
||||
get_percent (m_allocated, total.m_allocated),
|
||||
SIZE_AMOUNT (m_peak),
|
||||
SIZE_AMOUNT (m_times),
|
||||
get_percent (m_times, total.m_times),
|
||||
(uint64_t)m_element_size);
|
||||
|
||||
free (location_string);
|
||||
}
|
||||
|
||||
/* Dump header with NAME. */
|
||||
static inline void
|
||||
dump_header (const char *name)
|
||||
{
|
||||
fprintf (stderr, "%-32s%-48s %6s%11s%16s%17s%12s\n", "Pool name", name,
|
||||
"Pools", "Leak", "Peak", "Times", "Elt size");
|
||||
}
|
||||
|
||||
/* Dump footer. */
|
||||
inline void
|
||||
dump_footer ()
|
||||
{
|
||||
fprintf (stderr, "%s" PRsa(82) PRsa(10) "\n", "Total",
|
||||
SIZE_AMOUNT (m_instances), SIZE_AMOUNT (m_allocated));
|
||||
}
|
||||
|
||||
/* Element size. */
|
||||
size_t m_element_size;
|
||||
/* Pool name. */
|
||||
const char *m_pool_name;
|
||||
};
|
||||
|
||||
extern mem_alloc_description<pool_usage> pool_allocator_usage;
|
||||
|
||||
#if 0
|
||||
/* If a pool with custom block size is needed, one might use the following
|
||||
template. An instance of this template can be used as a parameter for
|
||||
instantiating base_pool_allocator template:
|
||||
|
||||
typedef custom_block_allocator <128*1024> huge_block_allocator;
|
||||
...
|
||||
static base_pool_allocator <huge_block_allocator>
|
||||
value_pool ("value", 16384);
|
||||
|
||||
Right now it's not used anywhere in the code, and is given here as an
|
||||
example). */
|
||||
|
||||
template <size_t BlockSize>
|
||||
class custom_block_allocator
|
||||
{
|
||||
public:
|
||||
static const size_t block_size = BlockSize;
|
||||
|
||||
static inline void *
|
||||
allocate () ATTRIBUTE_MALLOC
|
||||
{
|
||||
return XNEWVEC (char, BlockSize);
|
||||
}
|
||||
|
||||
static inline void
|
||||
release (void *block)
|
||||
{
|
||||
XDELETEVEC (block);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Generic pool allocator. */
|
||||
|
||||
template <typename TBlockAllocator>
|
||||
class base_pool_allocator
|
||||
{
|
||||
public:
|
||||
/* Default constructor for pool allocator called NAME. */
|
||||
base_pool_allocator (const char *name, size_t size CXX_MEM_STAT_INFO);
|
||||
~base_pool_allocator ();
|
||||
void release ();
|
||||
void release_if_empty ();
|
||||
void *allocate () ATTRIBUTE_MALLOC;
|
||||
void remove (void *object);
|
||||
size_t num_elts_current ();
|
||||
|
||||
private:
|
||||
struct allocation_pool_list
|
||||
{
|
||||
allocation_pool_list *next;
|
||||
};
|
||||
|
||||
/* Initialize a pool allocator. */
|
||||
void initialize ();
|
||||
|
||||
struct allocation_object
|
||||
{
|
||||
#if CHECKING_P
|
||||
/* The ID of alloc pool which the object was allocated from. */
|
||||
ALLOC_POOL_ID_TYPE id;
|
||||
#endif
|
||||
|
||||
union
|
||||
{
|
||||
/* The data of the object. */
|
||||
char data[1];
|
||||
|
||||
/* Because we want any type of data to be well aligned after the ID,
|
||||
the following elements are here. They are never accessed so
|
||||
the allocated object may be even smaller than this structure.
|
||||
We do not care about alignment for floating-point types. */
|
||||
char *align_p;
|
||||
int64_t align_i;
|
||||
} u;
|
||||
|
||||
#if CHECKING_P
|
||||
static inline allocation_object*
|
||||
get_instance (void *data_ptr)
|
||||
{
|
||||
return (allocation_object *)(((char *)(data_ptr))
|
||||
- offsetof (allocation_object,
|
||||
u.data));
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void*
|
||||
get_data (void *instance_ptr)
|
||||
{
|
||||
return (void*)(((allocation_object *) instance_ptr)->u.data);
|
||||
}
|
||||
};
|
||||
|
||||
/* Align X to 8. */
|
||||
static inline size_t
|
||||
align_eight (size_t x)
|
||||
{
|
||||
return (((x+7) >> 3) << 3);
|
||||
}
|
||||
|
||||
const char *m_name;
|
||||
ALLOC_POOL_ID_TYPE m_id;
|
||||
size_t m_elts_per_block;
|
||||
|
||||
/* These are the elements that have been allocated at least once
|
||||
and freed. */
|
||||
allocation_pool_list *m_returned_free_list;
|
||||
|
||||
/* These are the elements that have not yet been allocated out of
|
||||
the last block obtained from XNEWVEC. */
|
||||
char* m_virgin_free_list;
|
||||
|
||||
/* The number of elements in the virgin_free_list that can be
|
||||
allocated before needing another block. */
|
||||
size_t m_virgin_elts_remaining;
|
||||
/* The number of elements that are allocated. */
|
||||
size_t m_elts_allocated;
|
||||
/* The number of elements that are released. */
|
||||
size_t m_elts_free;
|
||||
/* The number of allocated blocks. */
|
||||
size_t m_blocks_allocated;
|
||||
/* List of blocks that are used to allocate new objects. */
|
||||
allocation_pool_list *m_block_list;
|
||||
/* Size of a pool elements in bytes. */
|
||||
size_t m_elt_size;
|
||||
/* Size in bytes that should be allocated for each element. */
|
||||
size_t m_size;
|
||||
/* Flag if a pool allocator is initialized. */
|
||||
bool m_initialized;
|
||||
/* Memory allocation location. */
|
||||
mem_location m_location;
|
||||
};
|
||||
|
||||
template <typename TBlockAllocator>
|
||||
inline
|
||||
base_pool_allocator <TBlockAllocator>::base_pool_allocator (
|
||||
const char *name, size_t size MEM_STAT_DECL):
|
||||
m_name (name), m_id (0), m_elts_per_block (0), m_returned_free_list (NULL),
|
||||
m_virgin_free_list (NULL), m_virgin_elts_remaining (0), m_elts_allocated (0),
|
||||
m_elts_free (0), m_blocks_allocated (0), m_block_list (NULL), m_elt_size (0),
|
||||
m_size (size), m_initialized (false),
|
||||
m_location (ALLOC_POOL_ORIGIN, false PASS_MEM_STAT) {}
|
||||
|
||||
/* Initialize a pool allocator. */
|
||||
|
||||
template <typename TBlockAllocator>
|
||||
inline void
|
||||
base_pool_allocator <TBlockAllocator>::initialize ()
|
||||
{
|
||||
gcc_checking_assert (!m_initialized);
|
||||
m_initialized = true;
|
||||
|
||||
size_t size = m_size;
|
||||
|
||||
gcc_checking_assert (m_name);
|
||||
gcc_checking_assert (m_size);
|
||||
|
||||
/* Make size large enough to store the list header. */
|
||||
if (size < sizeof (allocation_pool_list*))
|
||||
size = sizeof (allocation_pool_list*);
|
||||
|
||||
/* Now align the size to a multiple of 8. */
|
||||
size = align_eight (size);
|
||||
|
||||
/* Add the aligned size of ID. */
|
||||
size += offsetof (allocation_object, u.data);
|
||||
|
||||
m_elt_size = size;
|
||||
|
||||
if (GATHER_STATISTICS)
|
||||
{
|
||||
pool_usage *u = pool_allocator_usage.register_descriptor
|
||||
(this, new mem_location (m_location));
|
||||
|
||||
u->m_element_size = m_elt_size;
|
||||
u->m_pool_name = m_name;
|
||||
}
|
||||
|
||||
/* List header size should be a multiple of 8. */
|
||||
size_t header_size = align_eight (sizeof (allocation_pool_list));
|
||||
|
||||
m_elts_per_block = (TBlockAllocator::block_size - header_size) / size;
|
||||
gcc_checking_assert (m_elts_per_block != 0);
|
||||
|
||||
/* Increase the last used ID and use it for this pool.
|
||||
ID == 0 is used for free elements of pool so skip it. */
|
||||
last_id++;
|
||||
if (last_id == 0)
|
||||
last_id++;
|
||||
|
||||
m_id = last_id;
|
||||
}
|
||||
|
||||
/* Free all memory allocated for the given memory pool. */
|
||||
template <typename TBlockAllocator>
|
||||
inline void
|
||||
base_pool_allocator <TBlockAllocator>::release ()
|
||||
{
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
allocation_pool_list *block, *next_block;
|
||||
|
||||
/* Free each block allocated to the pool. */
|
||||
for (block = m_block_list; block != NULL; block = next_block)
|
||||
{
|
||||
next_block = block->next;
|
||||
TBlockAllocator::release (block);
|
||||
}
|
||||
|
||||
if (GATHER_STATISTICS && !after_memory_report)
|
||||
{
|
||||
pool_allocator_usage.release_instance_overhead
|
||||
(this, (m_elts_allocated - m_elts_free) * m_elt_size);
|
||||
}
|
||||
|
||||
m_returned_free_list = NULL;
|
||||
m_virgin_free_list = NULL;
|
||||
m_virgin_elts_remaining = 0;
|
||||
m_elts_allocated = 0;
|
||||
m_elts_free = 0;
|
||||
m_blocks_allocated = 0;
|
||||
m_block_list = NULL;
|
||||
}
|
||||
|
||||
template <typename TBlockAllocator>
|
||||
inline void
|
||||
base_pool_allocator <TBlockAllocator>::release_if_empty ()
|
||||
{
|
||||
if (m_elts_free == m_elts_allocated)
|
||||
release ();
|
||||
}
|
||||
|
||||
template <typename TBlockAllocator>
|
||||
inline base_pool_allocator <TBlockAllocator>::~base_pool_allocator ()
|
||||
{
|
||||
release ();
|
||||
}
|
||||
|
||||
/* Allocates one element from the pool specified. */
|
||||
template <typename TBlockAllocator>
|
||||
inline void*
|
||||
base_pool_allocator <TBlockAllocator>::allocate ()
|
||||
{
|
||||
if (!m_initialized)
|
||||
initialize ();
|
||||
|
||||
allocation_pool_list *header;
|
||||
#ifdef ENABLE_VALGRIND_ANNOTATIONS
|
||||
int size;
|
||||
#endif
|
||||
|
||||
if (GATHER_STATISTICS)
|
||||
{
|
||||
pool_allocator_usage.register_instance_overhead (m_elt_size, this);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_VALGRIND_ANNOTATIONS
|
||||
size = m_elt_size - offsetof (allocation_object, u.data);
|
||||
#endif
|
||||
|
||||
/* If there are no more free elements, make some more!. */
|
||||
if (!m_returned_free_list)
|
||||
{
|
||||
char *block;
|
||||
if (!m_virgin_elts_remaining)
|
||||
{
|
||||
allocation_pool_list *block_header;
|
||||
|
||||
/* Make the block. */
|
||||
block = reinterpret_cast<char *> (TBlockAllocator::allocate ());
|
||||
block_header = new (block) allocation_pool_list;
|
||||
block += align_eight (sizeof (allocation_pool_list));
|
||||
|
||||
/* Throw it on the block list. */
|
||||
block_header->next = m_block_list;
|
||||
m_block_list = block_header;
|
||||
|
||||
/* Make the block available for allocation. */
|
||||
m_virgin_free_list = block;
|
||||
m_virgin_elts_remaining = m_elts_per_block;
|
||||
|
||||
/* Also update the number of elements we have free/allocated, and
|
||||
increment the allocated block count. */
|
||||
m_elts_allocated += m_elts_per_block;
|
||||
m_elts_free += m_elts_per_block;
|
||||
m_blocks_allocated += 1;
|
||||
}
|
||||
|
||||
/* We now know that we can take the first elt off the virgin list and
|
||||
put it on the returned list. */
|
||||
block = m_virgin_free_list;
|
||||
header = (allocation_pool_list*) allocation_object::get_data (block);
|
||||
header->next = NULL;
|
||||
|
||||
/* Mark the element to be free. */
|
||||
#if CHECKING_P
|
||||
((allocation_object*) block)->id = 0;
|
||||
#endif
|
||||
VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS (header,size));
|
||||
m_returned_free_list = header;
|
||||
m_virgin_free_list += m_elt_size;
|
||||
m_virgin_elts_remaining--;
|
||||
|
||||
}
|
||||
|
||||
/* Pull the first free element from the free list, and return it. */
|
||||
header = m_returned_free_list;
|
||||
VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (header, sizeof (*header)));
|
||||
m_returned_free_list = header->next;
|
||||
m_elts_free--;
|
||||
|
||||
/* Set the ID for element. */
|
||||
#if CHECKING_P
|
||||
allocation_object::get_instance (header)->id = m_id;
|
||||
#endif
|
||||
VALGRIND_DISCARD (VALGRIND_MAKE_MEM_UNDEFINED (header, size));
|
||||
|
||||
return (void *)(header);
|
||||
}
|
||||
|
||||
/* Puts PTR back on POOL's free list. */
|
||||
template <typename TBlockAllocator>
|
||||
inline void
|
||||
base_pool_allocator <TBlockAllocator>::remove (void *object)
|
||||
{
|
||||
int size = m_elt_size - offsetof (allocation_object, u.data);
|
||||
|
||||
if (flag_checking)
|
||||
{
|
||||
gcc_assert (m_initialized);
|
||||
gcc_assert (object
|
||||
/* Check if we free more than we allocated. */
|
||||
&& m_elts_free < m_elts_allocated);
|
||||
#if CHECKING_P
|
||||
/* Check whether the PTR was allocated from POOL. */
|
||||
gcc_assert (m_id == allocation_object::get_instance (object)->id);
|
||||
#endif
|
||||
|
||||
memset (object, 0xaf, size);
|
||||
}
|
||||
|
||||
#if CHECKING_P
|
||||
/* Mark the element to be free. */
|
||||
allocation_object::get_instance (object)->id = 0;
|
||||
#endif
|
||||
|
||||
allocation_pool_list *header = new (object) allocation_pool_list;
|
||||
header->next = m_returned_free_list;
|
||||
m_returned_free_list = header;
|
||||
VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS (object, size));
|
||||
m_elts_free++;
|
||||
|
||||
if (GATHER_STATISTICS)
|
||||
{
|
||||
pool_allocator_usage.release_instance_overhead (this, m_elt_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Number of elements currently active (not returned to pool). Used for cheap
|
||||
consistency checks. */
|
||||
template <typename TBlockAllocator>
|
||||
inline size_t
|
||||
base_pool_allocator <TBlockAllocator>::num_elts_current ()
|
||||
{
|
||||
return m_elts_allocated - m_elts_free;
|
||||
}
|
||||
|
||||
/* Specialization of base_pool_allocator which should be used in most cases.
|
||||
Another specialization may be needed, if object size is greater than
|
||||
memory_block_pool::block_size (64 KB). */
|
||||
typedef base_pool_allocator <memory_block_pool> pool_allocator;
|
||||
|
||||
/* Type based memory pool allocator. */
|
||||
template <typename T>
|
||||
class object_allocator
|
||||
{
|
||||
public:
|
||||
/* Default constructor for pool allocator called NAME. */
|
||||
object_allocator (const char *name CXX_MEM_STAT_INFO):
|
||||
m_allocator (name, sizeof (T) PASS_MEM_STAT) {}
|
||||
|
||||
inline void
|
||||
release ()
|
||||
{
|
||||
m_allocator.release ();
|
||||
}
|
||||
|
||||
inline void release_if_empty ()
|
||||
{
|
||||
m_allocator.release_if_empty ();
|
||||
}
|
||||
|
||||
|
||||
/* Allocate memory for instance of type T and call a default constructor. */
|
||||
|
||||
inline T *
|
||||
allocate () ATTRIBUTE_MALLOC
|
||||
{
|
||||
return ::new (m_allocator.allocate ()) T;
|
||||
}
|
||||
|
||||
/* Allocate memory for instance of type T and return void * that
|
||||
could be used in situations where a default constructor is not provided
|
||||
by the class T. */
|
||||
|
||||
inline void *
|
||||
allocate_raw () ATTRIBUTE_MALLOC
|
||||
{
|
||||
return m_allocator.allocate ();
|
||||
}
|
||||
|
||||
inline void
|
||||
remove (T *object)
|
||||
{
|
||||
/* Call destructor. */
|
||||
object->~T ();
|
||||
|
||||
m_allocator.remove (object);
|
||||
}
|
||||
|
||||
inline void
|
||||
remove_raw (void *object)
|
||||
{
|
||||
m_allocator.remove (object);
|
||||
}
|
||||
|
||||
inline size_t
|
||||
num_elts_current ()
|
||||
{
|
||||
return m_allocator.num_elts_current ();
|
||||
}
|
||||
|
||||
private:
|
||||
pool_allocator m_allocator;
|
||||
};
|
||||
|
||||
/* Store information about each particular alloc_pool. Note that this
|
||||
will underestimate the amount the amount of storage used by a small amount:
|
||||
1) The overhead in a pool is not accounted for.
|
||||
2) The unallocated elements in a block are not accounted for. Note
|
||||
that this can at worst case be one element smaller that the block
|
||||
size for that pool. */
|
||||
struct alloc_pool_descriptor
|
||||
{
|
||||
/* Number of pools allocated. */
|
||||
unsigned long created;
|
||||
/* Gross allocated storage. */
|
||||
unsigned long allocated;
|
||||
/* Amount of currently active storage. */
|
||||
unsigned long current;
|
||||
/* Peak amount of storage used. */
|
||||
unsigned long peak;
|
||||
/* Size of element in the pool. */
|
||||
int elt_size;
|
||||
};
|
||||
|
||||
/* Helper for classes that do not provide default ctor. */
|
||||
|
||||
template <typename T>
|
||||
inline void *
|
||||
operator new (size_t, object_allocator<T> &a)
|
||||
{
|
||||
return a.allocate_raw ();
|
||||
}
|
||||
|
||||
/* Hashtable mapping alloc_pool names to descriptors. */
|
||||
extern hash_map<const char *, alloc_pool_descriptor> *alloc_pool_hash;
|
||||
|
||||
|
||||
#endif
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
/* Text art visualizations within -fanalyzer.
|
||||
Copyright (C) 2023-2024 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_ACCESS_DIAGRAM_H
|
||||
#define GCC_ANALYZER_ACCESS_DIAGRAM_H
|
||||
|
||||
#include "text-art/canvas.h"
|
||||
#include "text-art/theme.h"
|
||||
#include "text-art/widget.h"
|
||||
#include "analyzer/analyzer.h"
|
||||
#include "analyzer/store.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
class bit_size_expr
|
||||
{
|
||||
public:
|
||||
bit_size_expr (const svalue &num_bits) : m_num_bits (num_bits) {}
|
||||
|
||||
std::unique_ptr<text_art::styled_string>
|
||||
maybe_get_formatted_str (text_art::style_manager &sm,
|
||||
const region_model &model,
|
||||
const char *concrete_single_bit_fmt,
|
||||
const char *concrete_plural_bits_fmt,
|
||||
const char *concrete_single_byte_fmt,
|
||||
const char *concrete_plural_bytes_fmt,
|
||||
const char *symbolic_bits_fmt,
|
||||
const char *symbolic_bytes_fmt) const;
|
||||
bool maybe_print_for_user (pretty_printer *pp,
|
||||
const region_model &model) const;
|
||||
|
||||
const svalue *maybe_get_as_bytes (region_model_manager &mgr) const;
|
||||
|
||||
private:
|
||||
const svalue &m_num_bits;
|
||||
};
|
||||
|
||||
/* A range of bits within a base region, where each endpoint
|
||||
could be concrete or symbolic (not necessarily the same). */
|
||||
|
||||
struct access_range
|
||||
{
|
||||
access_range ()
|
||||
: m_start (), m_next ()
|
||||
{
|
||||
}
|
||||
access_range (region_offset start, region_offset next,
|
||||
region_model_manager &mgr)
|
||||
: m_start (strip_types (start, mgr)), m_next (strip_types (next, mgr))
|
||||
{}
|
||||
access_range (const region *base_region, const bit_range &bits);
|
||||
access_range (const region *base_region, const byte_range &bytes);
|
||||
access_range (const region ®, region_model_manager *);
|
||||
|
||||
bool concrete_p () const
|
||||
{
|
||||
return m_start.concrete_p () && m_next.concrete_p ();
|
||||
}
|
||||
|
||||
bool empty_p () const;
|
||||
|
||||
bit_size_expr get_size (region_model_manager *mgr) const;
|
||||
|
||||
bool get_size_in_bits (bit_size_t *out) const
|
||||
{
|
||||
if (concrete_p ())
|
||||
{
|
||||
*out = m_next.get_bit_offset () - m_start.get_bit_offset ();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool as_concrete_bit_range (bit_range *out) const
|
||||
{
|
||||
if (!concrete_p ())
|
||||
return false;
|
||||
bit_size_t size = m_next.get_bit_offset () - m_start.get_bit_offset ();
|
||||
*out = bit_range (m_start.get_bit_offset (), size);
|
||||
return true;
|
||||
}
|
||||
bool as_concrete_byte_range (byte_range *out) const
|
||||
{
|
||||
bit_range bits (0, 0);
|
||||
if (!as_concrete_bit_range (&bits))
|
||||
return false;
|
||||
return bits.as_byte_range (out);
|
||||
}
|
||||
|
||||
bool contains_p (const access_range &other) const;
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool) const;
|
||||
void dump (bool) const;
|
||||
void log (const char *title, logger &) const;
|
||||
|
||||
region_offset m_start;
|
||||
region_offset m_next;
|
||||
};
|
||||
|
||||
struct access_operation
|
||||
{
|
||||
access_operation (const region_model &model,
|
||||
enum access_direction dir,
|
||||
const region ®,
|
||||
const svalue *sval_hint)
|
||||
: m_model (model),
|
||||
m_dir (dir),
|
||||
m_reg (reg),
|
||||
m_sval_hint (sval_hint),
|
||||
m_base_region (reg.get_base_region ())
|
||||
{}
|
||||
|
||||
region_model_manager *get_manager () const
|
||||
{
|
||||
return m_model.get_manager ();
|
||||
}
|
||||
|
||||
/* Get the valid bits to access within the base region. */
|
||||
access_range get_valid_bits () const;
|
||||
|
||||
/* Get the actual bits accessed within the base region. */
|
||||
access_range get_actual_bits () const;
|
||||
|
||||
bool maybe_get_invalid_before_bits (access_range *out) const;
|
||||
bool maybe_get_invalid_after_bits (access_range *out) const;
|
||||
|
||||
const region_model &m_model;
|
||||
enum access_direction m_dir;
|
||||
const region &m_reg;
|
||||
const svalue *m_sval_hint;
|
||||
const region *m_base_region;
|
||||
};
|
||||
|
||||
class access_diagram : public text_art::wrapper_widget
|
||||
{
|
||||
public:
|
||||
access_diagram (const access_operation &op,
|
||||
diagnostic_event_id_t region_creation_event_id,
|
||||
text_art::style_manager &sm,
|
||||
const text_art::theme &theme,
|
||||
logger *logger);
|
||||
const char *get_desc () const override
|
||||
{
|
||||
return "access_diagram";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_ACCESS_DIAGRAM_H */
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/* A class to encapsulate decisions about how the analysis should happen.
|
||||
Copyright (C) 2019-2024 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_ANALYSIS_PLAN_H
|
||||
#define GCC_ANALYZER_ANALYSIS_PLAN_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A class to encapsulate decisions about how the analysis should happen.
|
||||
Examples:
|
||||
- the order in which functions should be analyzed, so that function
|
||||
summaries are created before analysis of call sites that might use
|
||||
them
|
||||
- which callgraph edges should use call summaries
|
||||
TODO: the above is a work-in-progress. */
|
||||
|
||||
class analysis_plan : public log_user
|
||||
{
|
||||
public:
|
||||
analysis_plan (const supergraph &sg, logger *logger);
|
||||
~analysis_plan ();
|
||||
|
||||
int cmp_function (function *fun_a, function *fun_b) const;
|
||||
|
||||
bool use_summary_p (const cgraph_edge *edge) const;
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN (analysis_plan);
|
||||
|
||||
const supergraph &m_sg;
|
||||
|
||||
/* Result of ipa_reverse_postorder. */
|
||||
cgraph_node **m_cgraph_node_postorder;
|
||||
int m_num_cgraph_nodes;
|
||||
|
||||
/* Index of each node within the postorder ordering,
|
||||
accessed via the "m_uid" field. */
|
||||
auto_vec<int> m_index_by_uid;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_ANALYSIS_PLAN_H */
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/* Interface between analyzer and frontends.
|
||||
Copyright (C) 2022-2024 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_LANGUAGE_H
|
||||
#define GCC_ANALYZER_LANGUAGE_H
|
||||
|
||||
#include "analyzer/analyzer-logging.h"
|
||||
|
||||
#if ENABLE_ANALYZER
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Abstract base class for representing a specific TU
|
||||
to the analyzer. */
|
||||
|
||||
class translation_unit
|
||||
{
|
||||
public:
|
||||
/* Attempt to look up an value for identifier ID (e.g. in the headers that
|
||||
have been seen). If it is defined and an integer (e.g. either as a
|
||||
macro or enum), return the INTEGER_CST value, otherwise return NULL. */
|
||||
virtual tree lookup_constant_by_id (tree id) const = 0;
|
||||
virtual tree lookup_type_by_id (tree id) const = 0;
|
||||
virtual tree lookup_global_var_by_id (tree id) const = 0;
|
||||
};
|
||||
|
||||
typedef void (*finish_translation_unit_callback)
|
||||
(logger *, const translation_unit &);
|
||||
void register_finish_translation_unit_callback (
|
||||
finish_translation_unit_callback callback);
|
||||
|
||||
/* Analyzer hook for frontends to call at the end of the TU. */
|
||||
|
||||
void on_finish_translation_unit (const translation_unit &tu);
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* #if ENABLE_ANALYZER */
|
||||
|
||||
#endif /* GCC_ANALYZER_LANGUAGE_H */
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
/* Hierarchical log messages for the analyzer.
|
||||
Copyright (C) 2014-2024 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/>. */
|
||||
|
||||
/* Adapted from jit-logging.h. */
|
||||
|
||||
#ifndef ANALYZER_LOGGING_H
|
||||
#define ANALYZER_LOGGING_H
|
||||
|
||||
#include "diagnostic-core.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A logger encapsulates a logging stream: a way to send
|
||||
lines of pertinent information to a FILE *. */
|
||||
|
||||
class logger
|
||||
{
|
||||
public:
|
||||
logger (FILE *f_out, int flags, int verbosity, const pretty_printer &reference_pp);
|
||||
~logger ();
|
||||
|
||||
void incref (const char *reason);
|
||||
void decref (const char *reason);
|
||||
|
||||
void log (const char *fmt, ...)
|
||||
ATTRIBUTE_GCC_DIAG(2, 3);
|
||||
void log_va (const char *fmt, va_list *ap)
|
||||
ATTRIBUTE_GCC_DIAG(2, 0);
|
||||
void start_log_line ();
|
||||
void log_partial (const char *fmt, ...)
|
||||
ATTRIBUTE_GCC_DIAG(2, 3);
|
||||
void log_va_partial (const char *fmt, va_list *ap)
|
||||
ATTRIBUTE_GCC_DIAG(2, 0);
|
||||
void end_log_line ();
|
||||
|
||||
void enter_scope (const char *scope_name);
|
||||
void enter_scope (const char *scope_name, const char *fmt, va_list *ap)
|
||||
ATTRIBUTE_GCC_DIAG(3, 0);
|
||||
void exit_scope (const char *scope_name);
|
||||
void inc_indent () { m_indent_level++; }
|
||||
void dec_indent () { m_indent_level--; }
|
||||
|
||||
pretty_printer *get_printer () const { return m_pp; }
|
||||
FILE *get_file () const { return m_f_out; }
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN (logger);
|
||||
|
||||
int m_refcount;
|
||||
FILE *m_f_out;
|
||||
int m_indent_level;
|
||||
bool m_log_refcount_changes;
|
||||
pretty_printer *m_pp;
|
||||
};
|
||||
|
||||
/* The class log_scope is an RAII-style class intended to make
|
||||
it easy to notify a logger about entering and exiting the body of a
|
||||
given function. */
|
||||
|
||||
class log_scope
|
||||
{
|
||||
public:
|
||||
log_scope (logger *logger, const char *name);
|
||||
log_scope (logger *logger, const char *name, const char *fmt, ...)
|
||||
ATTRIBUTE_GCC_DIAG(4, 5);
|
||||
~log_scope ();
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN (log_scope);
|
||||
|
||||
logger *m_logger;
|
||||
const char *m_name;
|
||||
};
|
||||
|
||||
/* The constructor for log_scope.
|
||||
|
||||
The normal case is that the logger is NULL, in which case this should
|
||||
be largely a no-op.
|
||||
|
||||
If we do have a logger, notify it that we're entering the given scope.
|
||||
We also need to hold a reference on it, to avoid a use-after-free
|
||||
when logging the cleanup of the owner of the logger. */
|
||||
|
||||
inline
|
||||
log_scope::log_scope (logger *logger, const char *name) :
|
||||
m_logger (logger),
|
||||
m_name (name)
|
||||
{
|
||||
if (m_logger)
|
||||
{
|
||||
m_logger->incref ("log_scope ctor");
|
||||
m_logger->enter_scope (m_name);
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
log_scope::log_scope (logger *logger, const char *name, const char *fmt, ...):
|
||||
m_logger (logger),
|
||||
m_name (name)
|
||||
{
|
||||
if (m_logger)
|
||||
{
|
||||
m_logger->incref ("log_scope ctor");
|
||||
va_list ap;
|
||||
va_start (ap, fmt);
|
||||
m_logger->enter_scope (m_name, fmt, &ap);
|
||||
va_end (ap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The destructor for log_scope; essentially the opposite of
|
||||
the constructor. */
|
||||
|
||||
inline
|
||||
log_scope::~log_scope ()
|
||||
{
|
||||
if (m_logger)
|
||||
{
|
||||
m_logger->exit_scope (m_name);
|
||||
m_logger->decref ("log_scope dtor");
|
||||
}
|
||||
}
|
||||
|
||||
/* A log_user is something that potentially uses a logger (which could be NULL).
|
||||
|
||||
The log_user class keeps the reference-count of a logger up-to-date. */
|
||||
|
||||
class log_user
|
||||
{
|
||||
public:
|
||||
log_user (logger *logger);
|
||||
~log_user ();
|
||||
|
||||
logger * get_logger () const { return m_logger; }
|
||||
void set_logger (logger * logger);
|
||||
|
||||
void log (const char *fmt, ...) const
|
||||
ATTRIBUTE_GCC_DIAG(2, 3);
|
||||
|
||||
void start_log_line () const;
|
||||
void end_log_line () const;
|
||||
|
||||
void enter_scope (const char *scope_name);
|
||||
void exit_scope (const char *scope_name);
|
||||
|
||||
pretty_printer *get_logger_pp () const
|
||||
{
|
||||
gcc_assert (m_logger);
|
||||
return m_logger->get_printer ();
|
||||
}
|
||||
|
||||
FILE *get_logger_file () const
|
||||
{
|
||||
if (m_logger == NULL)
|
||||
return NULL;
|
||||
return m_logger->get_file ();
|
||||
}
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN (log_user);
|
||||
|
||||
logger *m_logger;
|
||||
};
|
||||
|
||||
/* A shortcut for calling log from a log_user, handling the common
|
||||
case where the underlying logger is NULL via a no-op. */
|
||||
|
||||
inline void
|
||||
log_user::log (const char *fmt, ...) const
|
||||
{
|
||||
if (m_logger)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, fmt);
|
||||
m_logger->log_va (fmt, &ap);
|
||||
va_end (ap);
|
||||
}
|
||||
}
|
||||
|
||||
/* A shortcut for starting a log line from a log_user,
|
||||
handling the common case where the underlying logger is NULL via
|
||||
a no-op. */
|
||||
|
||||
inline void
|
||||
log_user::start_log_line () const
|
||||
{
|
||||
if (m_logger)
|
||||
m_logger->start_log_line ();
|
||||
}
|
||||
|
||||
/* A shortcut for ending a log line from a log_user,
|
||||
handling the common case where the underlying logger is NULL via
|
||||
a no-op. */
|
||||
|
||||
inline void
|
||||
log_user::end_log_line () const
|
||||
{
|
||||
if (m_logger)
|
||||
m_logger->end_log_line ();
|
||||
}
|
||||
|
||||
/* A shortcut for recording entry into a scope from a log_user,
|
||||
handling the common case where the underlying logger is NULL via
|
||||
a no-op. */
|
||||
|
||||
inline void
|
||||
log_user::enter_scope (const char *scope_name)
|
||||
{
|
||||
if (m_logger)
|
||||
m_logger->enter_scope (scope_name);
|
||||
}
|
||||
|
||||
/* A shortcut for recording exit from a scope from a log_user,
|
||||
handling the common case where the underlying logger is NULL via
|
||||
a no-op. */
|
||||
|
||||
inline void
|
||||
log_user::exit_scope (const char *scope_name)
|
||||
{
|
||||
if (m_logger)
|
||||
m_logger->exit_scope (scope_name);
|
||||
}
|
||||
|
||||
/* If the given logger is non-NULL, log entry/exit of this scope to
|
||||
it, identifying it using __PRETTY_FUNCTION__. */
|
||||
|
||||
#define LOG_SCOPE(LOGGER) \
|
||||
log_scope s (LOGGER, __PRETTY_FUNCTION__)
|
||||
|
||||
/* If the given logger is non-NULL, log entry/exit of this scope to
|
||||
it, identifying it using __func__. */
|
||||
|
||||
#define LOG_FUNC(LOGGER) \
|
||||
log_scope s (LOGGER, __func__)
|
||||
|
||||
#define LOG_FUNC_1(LOGGER, FMT, A0) \
|
||||
log_scope s (LOGGER, __func__, FMT, A0)
|
||||
|
||||
#define LOG_FUNC_2(LOGGER, FMT, A0, A1) \
|
||||
log_scope s (LOGGER, __func__, FMT, A0, A1)
|
||||
|
||||
#define LOG_FUNC_3(LOGGER, FMT, A0, A1, A2) \
|
||||
log_scope s (LOGGER, __func__, FMT, A0, A1, A2)
|
||||
|
||||
#define LOG_FUNC_4(LOGGER, FMT, A0, A1, A2, A3) \
|
||||
log_scope s (LOGGER, __func__, FMT, A0, A1, A2, A3)
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* ANALYZER_LOGGING_H */
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/* Selftests for the analyzer.
|
||||
Copyright (C) 2019-2024 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_SELFTESTS_H
|
||||
#define GCC_ANALYZER_SELFTESTS_H
|
||||
|
||||
#if CHECKING_P
|
||||
|
||||
namespace ana {
|
||||
|
||||
namespace selftest {
|
||||
|
||||
extern tree build_global_decl (const char *name, tree type);
|
||||
|
||||
extern void run_analyzer_selftests ();
|
||||
|
||||
/* Declarations for specific families of tests (by source file), in
|
||||
alphabetical order. */
|
||||
extern void analyzer_access_diagram_cc_tests ();
|
||||
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 ();
|
||||
extern void analyzer_store_cc_tests ();
|
||||
|
||||
} /* end of namespace ana::selftest. */
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* #if CHECKING_P */
|
||||
|
||||
#endif /* GCC_ANALYZER_SELFTESTS_H */
|
||||
+578
@@ -0,0 +1,578 @@
|
||||
/* Utility functions for the analyzer.
|
||||
Copyright (C) 2019-2024 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_ANALYZER_H
|
||||
#define GCC_ANALYZER_ANALYZER_H
|
||||
|
||||
#include "rich-location.h"
|
||||
#include "function.h"
|
||||
#include "json.h"
|
||||
#include "tristate.h"
|
||||
|
||||
class graphviz_out;
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Forward decls of common types, with indentation to show inheritance. */
|
||||
|
||||
class supergraph;
|
||||
class supernode;
|
||||
class superedge;
|
||||
class cfg_superedge;
|
||||
class switch_cfg_superedge;
|
||||
class callgraph_superedge;
|
||||
class call_superedge;
|
||||
class return_superedge;
|
||||
|
||||
class svalue;
|
||||
class region_svalue;
|
||||
class constant_svalue;
|
||||
class unknown_svalue;
|
||||
class poisoned_svalue;
|
||||
class setjmp_svalue;
|
||||
class initial_svalue;
|
||||
class unaryop_svalue;
|
||||
class binop_svalue;
|
||||
class sub_svalue;
|
||||
class repeated_svalue;
|
||||
class bits_within_svalue;
|
||||
class unmergeable_svalue;
|
||||
class placeholder_svalue;
|
||||
class widening_svalue;
|
||||
class compound_svalue;
|
||||
class conjured_svalue;
|
||||
class asm_output_svalue;
|
||||
class const_fn_result_svalue;
|
||||
typedef hash_set<const svalue *> svalue_set;
|
||||
class region;
|
||||
class frame_region;
|
||||
class function_region;
|
||||
class label_region;
|
||||
class decl_region;
|
||||
class symbolic_region;
|
||||
class element_region;
|
||||
class offset_region;
|
||||
class sized_region;
|
||||
class cast_region;
|
||||
class field_region;
|
||||
class string_region;
|
||||
class bit_range_region;
|
||||
class var_arg_region;
|
||||
class region_model_manager;
|
||||
class conjured_purge;
|
||||
struct model_merger;
|
||||
class store_manager;
|
||||
class store;
|
||||
class region_model;
|
||||
class region_model_context;
|
||||
class impl_region_model_context;
|
||||
class call_details;
|
||||
class rejected_constraint;
|
||||
class constraint_manager;
|
||||
class equiv_class;
|
||||
class reachable_regions;
|
||||
class bounded_ranges;
|
||||
class bounded_ranges_manager;
|
||||
|
||||
struct pending_location;
|
||||
class pending_diagnostic;
|
||||
class pending_note;
|
||||
class saved_diagnostic;
|
||||
struct event_loc_info;
|
||||
class checker_event;
|
||||
class state_change_event;
|
||||
class warning_event;
|
||||
class checker_path;
|
||||
class extrinsic_state;
|
||||
class sm_state_map;
|
||||
class stmt_finder;
|
||||
class program_point;
|
||||
class function_point;
|
||||
class program_state;
|
||||
class exploded_graph;
|
||||
class exploded_node;
|
||||
class exploded_edge;
|
||||
class feasibility_problem;
|
||||
class exploded_cluster;
|
||||
class exploded_path;
|
||||
class analysis_plan;
|
||||
class state_purge_map;
|
||||
class state_purge_per_ssa_name;
|
||||
class state_purge_per_decl;
|
||||
class state_change;
|
||||
class rewind_info_t;
|
||||
|
||||
class engine;
|
||||
class state_machine;
|
||||
class logger;
|
||||
class visitor;
|
||||
class known_function_manager;
|
||||
class call_summary;
|
||||
class call_summary_replay;
|
||||
struct per_function_data;
|
||||
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);
|
||||
extern void dump_quoted_tree (pretty_printer *pp, tree t);
|
||||
extern void print_quoted_type (pretty_printer *pp, tree t);
|
||||
extern void print_expr_for_user (pretty_printer *pp, tree t);
|
||||
extern int readability_comparator (const void *p1, const void *p2);
|
||||
extern int tree_cmp (const void *p1, const void *p2);
|
||||
extern tree fixup_tree_for_diagnostic (tree);
|
||||
extern tree get_diagnostic_tree_for_gassign (const gassign *);
|
||||
|
||||
/* A tree, extended with stack frame information for locals, so that
|
||||
we can distinguish between different values of locals within a potentially
|
||||
recursive callstack. */
|
||||
|
||||
class path_var
|
||||
{
|
||||
public:
|
||||
path_var (tree t, int stack_depth)
|
||||
: m_tree (t), m_stack_depth (stack_depth)
|
||||
{
|
||||
// TODO: ignore stack depth for globals and constants
|
||||
}
|
||||
|
||||
bool operator== (const path_var &other) const
|
||||
{
|
||||
return (m_tree == other.m_tree
|
||||
&& m_stack_depth == other.m_stack_depth);
|
||||
}
|
||||
|
||||
operator bool () const
|
||||
{
|
||||
return m_tree != NULL_TREE;
|
||||
}
|
||||
|
||||
void dump (pretty_printer *pp) const;
|
||||
|
||||
tree m_tree;
|
||||
int m_stack_depth; // or -1 for globals?
|
||||
};
|
||||
|
||||
typedef offset_int bit_offset_t;
|
||||
typedef offset_int bit_size_t;
|
||||
typedef offset_int byte_offset_t;
|
||||
typedef offset_int byte_size_t;
|
||||
|
||||
extern bool int_size_in_bits (const_tree type, bit_size_t *out);
|
||||
|
||||
extern tree get_field_at_bit_offset (tree record_type, bit_offset_t bit_offset);
|
||||
|
||||
/* The location of a region expressesd as an offset relative to a
|
||||
base region. */
|
||||
|
||||
class region_offset
|
||||
{
|
||||
public:
|
||||
region_offset ()
|
||||
: m_base_region (NULL), m_offset (0), m_sym_offset (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
static region_offset make_concrete (const region *base_region,
|
||||
bit_offset_t offset)
|
||||
{
|
||||
return region_offset (base_region, offset, NULL);
|
||||
}
|
||||
static region_offset make_symbolic (const region *base_region,
|
||||
const svalue *sym_offset)
|
||||
{
|
||||
return region_offset (base_region, 0, sym_offset);
|
||||
}
|
||||
static region_offset make_byte_offset (const region *base_region,
|
||||
const svalue *num_bytes_sval);
|
||||
|
||||
const region *get_base_region () const { return m_base_region; }
|
||||
|
||||
bool concrete_p () const { return m_sym_offset == NULL; }
|
||||
bool symbolic_p () const { return m_sym_offset != NULL; }
|
||||
|
||||
bit_offset_t get_bit_offset () const
|
||||
{
|
||||
gcc_assert (!symbolic_p ());
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
bool get_concrete_byte_offset (byte_offset_t *out) const
|
||||
{
|
||||
gcc_assert (!symbolic_p ());
|
||||
if (m_offset % BITS_PER_UNIT == 0)
|
||||
{
|
||||
*out = m_offset / BITS_PER_UNIT;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const svalue *get_symbolic_byte_offset () const
|
||||
{
|
||||
gcc_assert (symbolic_p ());
|
||||
return m_sym_offset;
|
||||
}
|
||||
|
||||
const svalue &calc_symbolic_bit_offset (region_model_manager *mgr) const;
|
||||
const svalue *calc_symbolic_byte_offset (region_model_manager *mgr) const;
|
||||
|
||||
bool operator== (const region_offset &other) const
|
||||
{
|
||||
return (m_base_region == other.m_base_region
|
||||
&& m_offset == other.m_offset
|
||||
&& m_sym_offset == other.m_sym_offset);
|
||||
}
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool) const;
|
||||
void dump (bool) const;
|
||||
|
||||
private:
|
||||
region_offset (const region *base_region, bit_offset_t offset,
|
||||
const svalue *sym_offset)
|
||||
: m_base_region (base_region), m_offset (offset), m_sym_offset (sym_offset)
|
||||
{}
|
||||
|
||||
const region *m_base_region;
|
||||
bit_offset_t m_offset;
|
||||
const svalue *m_sym_offset;
|
||||
};
|
||||
|
||||
extern bool operator< (const region_offset &, const region_offset &);
|
||||
extern bool operator<= (const region_offset &, const region_offset &);
|
||||
extern bool operator> (const region_offset &, const region_offset &);
|
||||
extern bool operator>= (const region_offset &, const region_offset &);
|
||||
|
||||
extern location_t get_stmt_location (const gimple *stmt, function *fun);
|
||||
|
||||
extern bool compat_types_p (tree src_type, tree dst_type);
|
||||
|
||||
/* Abstract base class for simulating the behavior of known functions,
|
||||
supplied by the core of the analyzer, or by plugins.
|
||||
The former are typically implemented in the various kf*.cc */
|
||||
|
||||
class known_function
|
||||
{
|
||||
public:
|
||||
virtual ~known_function () {}
|
||||
virtual bool matches_call_types_p (const call_details &cd) const = 0;
|
||||
virtual void impl_call_pre (const call_details &) const
|
||||
{
|
||||
return;
|
||||
}
|
||||
virtual void impl_call_post (const call_details &) const
|
||||
{
|
||||
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. */
|
||||
|
||||
class internal_known_function : public known_function
|
||||
{
|
||||
public:
|
||||
bool matches_call_types_p (const call_details &) const final override
|
||||
{
|
||||
/* Types are assumed to be correct. */
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/* 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 &kfm,
|
||||
region_model_manager &rmm);
|
||||
extern void register_known_analyzer_functions (known_function_manager &kfm);
|
||||
extern void register_known_fd_functions (known_function_manager &kfm);
|
||||
extern void register_known_file_functions (known_function_manager &kfm);
|
||||
extern void register_known_functions_lang_cp (known_function_manager &kfm);
|
||||
extern void register_varargs_builtins (known_function_manager &kfm);
|
||||
|
||||
/* Passed by pointer to PLUGIN_ANALYZER_INIT callbacks. */
|
||||
|
||||
class plugin_analyzer_init_iface
|
||||
{
|
||||
public:
|
||||
virtual void register_state_machine (std::unique_ptr<state_machine>) = 0;
|
||||
virtual void register_known_function (const char *name,
|
||||
std::unique_ptr<known_function>) = 0;
|
||||
virtual logger *get_logger () const = 0;
|
||||
};
|
||||
|
||||
/* An enum for describing the direction of an access to memory. */
|
||||
|
||||
enum access_direction
|
||||
{
|
||||
DIR_READ,
|
||||
DIR_WRITE
|
||||
};
|
||||
|
||||
/* Abstract base class for associating custom data with an
|
||||
exploded_edge, for handling non-standard edges such as
|
||||
rewinding from a longjmp, signal handlers, etc.
|
||||
Also used when "bifurcating" state: splitting the execution
|
||||
path in non-standard ways (e.g. for simulating the various
|
||||
outcomes of "realloc"). */
|
||||
|
||||
class custom_edge_info
|
||||
{
|
||||
public:
|
||||
virtual ~custom_edge_info () {}
|
||||
|
||||
/* Hook for making .dot label more readable. */
|
||||
virtual void print (pretty_printer *pp) const = 0;
|
||||
|
||||
/* Hook for updating STATE when handling bifurcation. */
|
||||
virtual bool update_state (program_state *state,
|
||||
const exploded_edge *eedge,
|
||||
region_model_context *ctxt) const;
|
||||
|
||||
/* Hook for updating MODEL within exploded_path::feasible_p
|
||||
and when handling bifurcation. */
|
||||
virtual bool update_model (region_model *model,
|
||||
const exploded_edge *eedge,
|
||||
region_model_context *ctxt) const = 0;
|
||||
|
||||
virtual void add_events_to_path (checker_path *emission_path,
|
||||
const exploded_edge &eedge) const = 0;
|
||||
};
|
||||
|
||||
/* Abstract base class for splitting state.
|
||||
|
||||
Most of the state-management code in the analyzer involves
|
||||
modifying state objects in-place, which assumes a single outcome.
|
||||
|
||||
This class provides an escape hatch to allow for multiple outcomes
|
||||
for such updates e.g. for modelling multiple outcomes from function
|
||||
calls, such as the various outcomes of "realloc". */
|
||||
|
||||
class path_context
|
||||
{
|
||||
public:
|
||||
virtual ~path_context () {}
|
||||
|
||||
/* Hook for clients to split state with a non-standard path. */
|
||||
virtual void bifurcate (std::unique_ptr<custom_edge_info> info) = 0;
|
||||
|
||||
/* Hook for clients to terminate the standard path. */
|
||||
virtual void terminate_path () = 0;
|
||||
|
||||
/* Hook for clients to determine if the standard path has been
|
||||
terminated. */
|
||||
virtual bool terminate_path_p () const = 0;
|
||||
};
|
||||
|
||||
extern tree get_stashed_constant_by_name (const char *name);
|
||||
extern void log_stashed_constants (logger *logger);
|
||||
|
||||
extern FILE *get_or_create_any_logfile ();
|
||||
|
||||
extern json::value *
|
||||
tree_to_json (tree node);
|
||||
|
||||
extern json::value *
|
||||
diagnostic_event_id_to_json (const diagnostic_event_id_t &);
|
||||
|
||||
extern json::value *
|
||||
bit_offset_to_json (const bit_offset_t &offset);
|
||||
|
||||
extern json::value *
|
||||
byte_offset_to_json (const byte_offset_t &offset);
|
||||
|
||||
extern tristate
|
||||
compare_constants (tree lhs_const, enum tree_code op, tree rhs_const);
|
||||
|
||||
extern tree
|
||||
get_string_cst_size (const_tree string_cst);
|
||||
|
||||
extern tree
|
||||
get_ssa_default_def (const function &fun, tree var);
|
||||
|
||||
extern const svalue *
|
||||
strip_types (const svalue *sval, region_model_manager &mgr);
|
||||
|
||||
extern region_offset
|
||||
strip_types (const region_offset &offset, region_model_manager &mgr);
|
||||
|
||||
extern tree remove_ssa_names (tree expr);
|
||||
|
||||
} // namespace ana
|
||||
|
||||
extern bool is_special_named_call_p (const gcall *call, const char *funcname,
|
||||
unsigned int num_args);
|
||||
extern bool is_named_call_p (const_tree fndecl, const char *funcname);
|
||||
extern bool is_named_call_p (const_tree fndecl, const char *funcname,
|
||||
const gcall *call, unsigned int num_args);
|
||||
extern bool is_std_named_call_p (const_tree fndecl, const char *funcname);
|
||||
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);
|
||||
|
||||
extern void register_analyzer_pass ();
|
||||
|
||||
extern label_text make_label_text (bool can_colorize, const char *fmt, ...);
|
||||
extern label_text make_label_text_n (bool can_colorize,
|
||||
unsigned HOST_WIDE_INT n,
|
||||
const char *singular_fmt,
|
||||
const char *plural_fmt, ...);
|
||||
|
||||
extern bool fndecl_has_gimple_body_p (tree fndecl);
|
||||
|
||||
/* An RAII-style class for pushing/popping cfun within a scope.
|
||||
Doing so ensures we get "In function " announcements
|
||||
from the diagnostics subsystem. */
|
||||
|
||||
class auto_cfun
|
||||
{
|
||||
public:
|
||||
auto_cfun (function *fun) { push_cfun (fun); }
|
||||
~auto_cfun () { pop_cfun (); }
|
||||
};
|
||||
|
||||
/* A template for creating hash traits for a POD type. */
|
||||
|
||||
template <typename Type>
|
||||
struct pod_hash_traits : typed_noop_remove<Type>
|
||||
{
|
||||
typedef Type value_type;
|
||||
typedef Type compare_type;
|
||||
static inline hashval_t hash (value_type);
|
||||
static inline bool equal (const value_type &existing,
|
||||
const value_type &candidate);
|
||||
static inline void mark_deleted (Type &);
|
||||
static inline void mark_empty (Type &);
|
||||
static inline bool is_deleted (Type);
|
||||
static inline bool is_empty (Type);
|
||||
};
|
||||
|
||||
/* A hash traits class that uses member functions to implement
|
||||
the various required ops. */
|
||||
|
||||
template <typename Type>
|
||||
struct member_function_hash_traits : public typed_noop_remove<Type>
|
||||
{
|
||||
typedef Type value_type;
|
||||
typedef Type compare_type;
|
||||
static inline hashval_t hash (value_type v) { return v.hash (); }
|
||||
static inline bool equal (const value_type &existing,
|
||||
const value_type &candidate)
|
||||
{
|
||||
return existing == candidate;
|
||||
}
|
||||
static inline void mark_deleted (Type &t) { t.mark_deleted (); }
|
||||
static inline void mark_empty (Type &t) { t.mark_empty (); }
|
||||
static inline bool is_deleted (Type t) { return t.is_deleted (); }
|
||||
static inline bool is_empty (Type t) { return t.is_empty (); }
|
||||
};
|
||||
|
||||
/* A map from T::key_t to T* for use in consolidating instances of T.
|
||||
Owns all instances of T.
|
||||
T::key_t should have operator== and be hashable. */
|
||||
|
||||
template <typename T>
|
||||
class consolidation_map
|
||||
{
|
||||
public:
|
||||
typedef typename T::key_t key_t;
|
||||
typedef T instance_t;
|
||||
typedef hash_map<key_t, instance_t *> inner_map_t;
|
||||
typedef typename inner_map_t::iterator iterator;
|
||||
|
||||
/* Delete all instances of T. */
|
||||
|
||||
~consolidation_map ()
|
||||
{
|
||||
for (typename inner_map_t::iterator iter = m_inner_map.begin ();
|
||||
iter != m_inner_map.end (); ++iter)
|
||||
delete (*iter).second;
|
||||
}
|
||||
|
||||
/* Get the instance of T for K if one exists, or NULL. */
|
||||
|
||||
T *get (const key_t &k) const
|
||||
{
|
||||
if (instance_t **slot = const_cast<inner_map_t &> (m_inner_map).get (k))
|
||||
return *slot;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Take ownership of INSTANCE. */
|
||||
|
||||
void put (const key_t &k, T *instance)
|
||||
{
|
||||
m_inner_map.put (k, instance);
|
||||
}
|
||||
|
||||
size_t elements () const { return m_inner_map.elements (); }
|
||||
|
||||
iterator begin () const { return m_inner_map.begin (); }
|
||||
iterator end () const { return m_inner_map.end (); }
|
||||
|
||||
private:
|
||||
inner_map_t m_inner_map;
|
||||
};
|
||||
|
||||
/* Disable -Wformat-diag; we want to be able to use pp_printf
|
||||
for logging/dumping without complying with the rules for diagnostics. */
|
||||
#if __GNUC__ >= 10
|
||||
#pragma GCC diagnostic ignored "-Wformat-diag"
|
||||
#endif
|
||||
|
||||
#if !ENABLE_ANALYZER
|
||||
extern void sorry_no_analyzer ();
|
||||
#endif /* #if !ENABLE_ANALYZER */
|
||||
|
||||
#endif /* GCC_ANALYZER_ANALYZER_H */
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/* Support for plotting bar charts in dumps.
|
||||
Copyright (C) 2020-2024 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_BAR_CHART_H
|
||||
#define GCC_ANALYZER_BAR_CHART_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A class for printing bar charts to a pretty_printer.
|
||||
|
||||
TODO(stage1): move to gcc subdir? */
|
||||
|
||||
class bar_chart
|
||||
{
|
||||
public:
|
||||
typedef unsigned long value_t;
|
||||
|
||||
/* Add an item, taking a copy of NAME. */
|
||||
void add_item (const char *name, value_t value);
|
||||
|
||||
/* Print the data to PP. */
|
||||
void print (pretty_printer *pp) const;
|
||||
|
||||
private:
|
||||
struct item
|
||||
{
|
||||
item (const char *name, value_t value)
|
||||
: m_name (xstrdup (name)), m_strlen (strlen (name)) , m_value (value) {}
|
||||
~item () { free (m_name); }
|
||||
|
||||
char *m_name;
|
||||
size_t m_strlen;
|
||||
value_t m_value;
|
||||
};
|
||||
|
||||
static void print_padding (pretty_printer *pp, size_t count);
|
||||
|
||||
auto_delete_vec<item> m_items;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_BAR_CHART_H */
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/* Helper class for handling a call with specific arguments.
|
||||
Copyright (C) 2019-2024 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_CALL_DETAILS_H
|
||||
#define GCC_ANALYZER_CALL_DETAILS_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Helper class for handling calls to functions with known behavior. */
|
||||
|
||||
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;
|
||||
region_model_context *get_ctxt () const { return m_ctxt; }
|
||||
logger *get_logger () const;
|
||||
|
||||
uncertainty_t *get_uncertainty () const;
|
||||
tree get_lhs_type () const { return m_lhs_type; }
|
||||
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
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool simple) const;
|
||||
void dump (bool simple) const;
|
||||
|
||||
const svalue *get_or_create_conjured_svalue (const region *) const;
|
||||
|
||||
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;
|
||||
region_model_context *m_ctxt;
|
||||
tree m_lhs_type;
|
||||
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 */
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/* Subclasses of custom_edge_info for describing outcomes of function calls.
|
||||
Copyright (C) 2021-2024 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_CALL_INFO_H
|
||||
#define GCC_ANALYZER_CALL_INFO_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Subclass of custom_edge_info for an outcome of a call.
|
||||
This is still abstract; the update_model and get_desc vfuncs must be
|
||||
implemented. */
|
||||
|
||||
class call_info : public custom_edge_info
|
||||
{
|
||||
public:
|
||||
void print (pretty_printer *pp) const final override;
|
||||
void add_events_to_path (checker_path *emission_path,
|
||||
const exploded_edge &eedge) const final override;
|
||||
|
||||
const gcall *get_call_stmt () const { return m_call_stmt; }
|
||||
tree get_fndecl () const { return m_fndecl; }
|
||||
|
||||
virtual label_text get_desc (bool can_colorize) const = 0;
|
||||
|
||||
call_details get_call_details (region_model *model,
|
||||
region_model_context *ctxt) const;
|
||||
|
||||
protected:
|
||||
call_info (const call_details &cd);
|
||||
call_info (const call_details &cd, const function &called_fn);
|
||||
|
||||
private:
|
||||
const gcall *m_call_stmt;
|
||||
tree m_fndecl;
|
||||
};
|
||||
|
||||
/* Subclass of call_info for a "success" outcome of a call,
|
||||
adding either a
|
||||
"when `FNDECL' succeeds" message (when 'success' is true)
|
||||
or a
|
||||
"when `FNDECL' fails" message (when 'success' is false).
|
||||
This is still abstract: the custom_edge_info::update_model vfunc
|
||||
must be implemented. */
|
||||
|
||||
class succeed_or_fail_call_info : public call_info
|
||||
{
|
||||
public:
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
protected:
|
||||
succeed_or_fail_call_info (const call_details &cd, bool success)
|
||||
: call_info (cd), m_success (success) {}
|
||||
|
||||
bool m_success;
|
||||
};
|
||||
|
||||
/* Subclass of call_info for a "success" outcome of a call,
|
||||
adding a "when `FNDECL' succeeds" message.
|
||||
This is still abstract: the custom_edge_info::update_model vfunc
|
||||
must be implemented. */
|
||||
|
||||
class success_call_info : public succeed_or_fail_call_info
|
||||
{
|
||||
protected:
|
||||
success_call_info (const call_details &cd)
|
||||
: succeed_or_fail_call_info (cd, true)
|
||||
{}
|
||||
};
|
||||
|
||||
/* Subclass of call_info for a "failure" outcome of a call,
|
||||
adding a "when `FNDECL' fails" message.
|
||||
This is still abstract: the custom_edge_info::update_model vfunc
|
||||
must be implemented. */
|
||||
|
||||
class failed_call_info : public succeed_or_fail_call_info
|
||||
{
|
||||
protected:
|
||||
failed_call_info (const call_details &cd)
|
||||
: succeed_or_fail_call_info (cd, false)
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_CALL_INFO_H */
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
/* Call stacks at program points.
|
||||
Copyright (C) 2019-2024 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_CALL_STRING_H
|
||||
#define GCC_ANALYZER_CALL_STRING_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
class supergraph;
|
||||
class supernode;
|
||||
class call_superedge;
|
||||
class return_superedge;
|
||||
|
||||
|
||||
/* A string of return_superedge pointers, representing a call stack
|
||||
at a program point.
|
||||
|
||||
This is used to ensure that we generate interprocedurally valid paths
|
||||
i.e. that we return to the same callsite that called us.
|
||||
|
||||
The class stores returning calls ( which may be represented by a
|
||||
returning superedge ). We do so because this is what we need to compare
|
||||
against.
|
||||
|
||||
Instances of call_string are consolidated by the region_model_manager,
|
||||
which effectively owns them: it owns the root/empty call_string, and each
|
||||
call_string instance tracks its children, lazily creating them on demand,
|
||||
so that the call_string instances form a tree-like hierarchy in memory. */
|
||||
|
||||
class call_string
|
||||
{
|
||||
public:
|
||||
/* A struct representing an element in the call_string.
|
||||
|
||||
Each element represents a path from m_callee to m_caller which represents
|
||||
returning from function. */
|
||||
|
||||
struct element_t
|
||||
{
|
||||
element_t (const supernode *caller, const supernode *callee)
|
||||
: m_caller (caller), m_callee (callee)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator== (const element_t &other) const;
|
||||
bool operator!= (const element_t &other) const;
|
||||
|
||||
/* Accessors */
|
||||
function *get_caller_function () const;
|
||||
function *get_callee_function () const;
|
||||
|
||||
const supernode *m_caller;
|
||||
const supernode *m_callee;
|
||||
};
|
||||
|
||||
void print (pretty_printer *pp) const;
|
||||
|
||||
json::value *to_json () const;
|
||||
|
||||
bool empty_p () const { return m_elements.is_empty (); }
|
||||
|
||||
const call_string *push_call (const supergraph &sg,
|
||||
const call_superedge *sedge) const;
|
||||
|
||||
const call_string *push_call (const supernode *src,
|
||||
const supernode *dest) const;
|
||||
const call_string *get_parent () const { return m_parent; }
|
||||
|
||||
int calc_recursion_depth () const;
|
||||
|
||||
static int cmp (const call_string &a,
|
||||
const call_string &b);
|
||||
|
||||
static int cmp_ptr_ptr (const void *, const void *);
|
||||
|
||||
/* Accessors */
|
||||
|
||||
const supernode *get_callee_node () const;
|
||||
const supernode *get_caller_node () const;
|
||||
unsigned length () const { return m_elements.length (); }
|
||||
element_t operator[] (unsigned idx) const
|
||||
{
|
||||
return m_elements[idx];
|
||||
}
|
||||
const element_t &get_top_of_stack () const
|
||||
{
|
||||
gcc_assert (m_elements.length () > 0);
|
||||
return m_elements[m_elements.length () - 1];
|
||||
}
|
||||
|
||||
int count_occurrences_of_function (function *) const;
|
||||
|
||||
void validate () const;
|
||||
|
||||
private:
|
||||
struct hashmap_traits_t
|
||||
{
|
||||
typedef element_t key_type;
|
||||
typedef const call_string *value_type;
|
||||
|
||||
static const bool maybe_mx = false;
|
||||
static inline hashval_t hash (const key_type &k)
|
||||
{
|
||||
inchash::hash hstate;
|
||||
hstate.add_ptr (k.m_caller);
|
||||
hstate.add_ptr (k.m_callee);
|
||||
return hstate.end ();
|
||||
}
|
||||
static inline bool equal_keys (const key_type &k1, const key_type &k2)
|
||||
{
|
||||
return k1 == k2;
|
||||
}
|
||||
template <typename T> static inline void remove (T &entry)
|
||||
{
|
||||
entry.m_key = element_t (NULL, NULL);
|
||||
}
|
||||
static const bool empty_zero_p = true;
|
||||
template <typename T> static inline bool is_empty (const T &entry)
|
||||
{
|
||||
return entry.m_key.m_caller == NULL;
|
||||
}
|
||||
template <typename T> static inline bool is_deleted (const T &entry)
|
||||
{
|
||||
return entry.m_key.m_caller == reinterpret_cast<const supernode *> (1);
|
||||
}
|
||||
template <typename T> static inline void mark_empty (T &entry)
|
||||
{
|
||||
entry.m_key = element_t (NULL, NULL);
|
||||
entry.m_value = NULL;
|
||||
}
|
||||
template <typename T> static inline void mark_deleted (T &entry)
|
||||
{
|
||||
entry.m_key.m_caller = reinterpret_cast<const supernode *> (1);
|
||||
}
|
||||
};
|
||||
|
||||
friend class region_model_manager;
|
||||
|
||||
DISABLE_COPY_AND_ASSIGN (call_string);
|
||||
|
||||
call_string ();
|
||||
call_string (const call_string &parent, const element_t &to_push);
|
||||
~call_string ();
|
||||
|
||||
void recursive_log (logger *logger) const;
|
||||
|
||||
const call_string *m_parent;
|
||||
auto_vec<element_t> m_elements;
|
||||
mutable hash_map<element_t, const call_string *, hashmap_traits_t> m_children;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_CALL_STRING_H */
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/* Classes for working with summaries of function calls.
|
||||
Copyright (C) 2022 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_CALL_SUMMARY_H
|
||||
#define GCC_ANALYZER_CALL_SUMMARY_H
|
||||
|
||||
#include "call-details.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A class summarizing one particular outcome of a function that
|
||||
we've already analyzed.
|
||||
This lets us efficiently replay the analysis when we see calls
|
||||
to the function, providing an approximation of the behavior of
|
||||
the function without having to execute within the function itself. */
|
||||
|
||||
class call_summary
|
||||
{
|
||||
public:
|
||||
call_summary (per_function_data *per_fn_data,
|
||||
const exploded_node *enode)
|
||||
: m_per_fn_data (per_fn_data),
|
||||
m_enode (enode)
|
||||
{}
|
||||
const program_state &get_state () const;
|
||||
tree get_fndecl () const;
|
||||
|
||||
label_text get_desc () const;
|
||||
|
||||
void dump_to_pp (const extrinsic_state &ext_state,
|
||||
pretty_printer *pp,
|
||||
bool simple) const;
|
||||
void dump (const extrinsic_state &ext_state, FILE *fp, bool simple) const;
|
||||
void dump (const extrinsic_state &ext_state, bool simple) const;
|
||||
|
||||
private:
|
||||
void get_user_facing_desc (pretty_printer *pp) const;
|
||||
|
||||
per_function_data *const m_per_fn_data;
|
||||
const exploded_node *const m_enode;
|
||||
};
|
||||
|
||||
/* A class for handling replaying a specific call summary at
|
||||
a specific call site.
|
||||
|
||||
Supports remapping svalues and regions, e.g. remapping
|
||||
INIT_VAL(param of callee)
|
||||
to:
|
||||
whatever that argument is at the call site. */
|
||||
|
||||
class call_summary_replay
|
||||
{
|
||||
public:
|
||||
call_summary_replay (const call_details &cd,
|
||||
const function &called_fn,
|
||||
call_summary *m_summary,
|
||||
const extrinsic_state &ext_state);
|
||||
|
||||
const call_details &get_call_details () const { return m_cd; }
|
||||
const gcall *get_call_stmt () const { return m_cd.get_call_stmt (); }
|
||||
region_model_manager *get_manager () const { return m_cd.get_manager (); }
|
||||
store_manager *get_store_manager () const
|
||||
{
|
||||
return get_manager ()->get_store_manager ();
|
||||
}
|
||||
region_model_context *get_ctxt () const { return m_cd.get_ctxt (); }
|
||||
region_model *get_caller_model () const { return m_cd.get_model (); }
|
||||
|
||||
const svalue *convert_svalue_from_summary (const svalue *);
|
||||
const region *convert_region_from_summary (const region *);
|
||||
const binding_key *convert_key_from_summary (const binding_key *);
|
||||
|
||||
void add_svalue_mapping (const svalue *summary_sval,
|
||||
const svalue *caller_sval);
|
||||
void add_region_mapping (const region *summary_sval,
|
||||
const region *caller_sval);
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool simple) const;
|
||||
void dump (FILE *fp, bool simple) const;
|
||||
void dump (bool simple) const;
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN (call_summary_replay);
|
||||
|
||||
const svalue *convert_svalue_from_summary_1 (const svalue *);
|
||||
const region *convert_region_from_summary_1 (const region *);
|
||||
|
||||
const call_details &m_cd;
|
||||
call_summary *m_summary;
|
||||
const extrinsic_state &m_ext_state;
|
||||
|
||||
// Mapping from svalues in summary to svalues for callsite:
|
||||
typedef hash_map <const svalue *, const svalue *> svalue_map_t;
|
||||
svalue_map_t m_map_svalue_from_summary_to_caller;
|
||||
|
||||
// Mapping from regions in summary to regions for callsite:
|
||||
typedef hash_map <const region *, const region *> region_map_t;
|
||||
region_map_t m_map_region_from_summary_to_caller;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_CALL_SUMMARY_H */
|
||||
+709
@@ -0,0 +1,709 @@
|
||||
/* Subclasses of diagnostic_event for analyzer diagnostics.
|
||||
Copyright (C) 2019-2024 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_CHECKER_EVENT_H
|
||||
#define GCC_ANALYZER_CHECKER_EVENT_H
|
||||
|
||||
#include "tree-logical-location.h"
|
||||
#include "analyzer/program-state.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A bundle of location information for a checker_event. */
|
||||
|
||||
struct event_loc_info
|
||||
{
|
||||
event_loc_info (location_t loc, tree fndecl, int depth)
|
||||
: m_loc (loc), m_fndecl (fndecl), m_depth (depth)
|
||||
{}
|
||||
|
||||
location_t m_loc;
|
||||
tree m_fndecl;
|
||||
int m_depth;
|
||||
};
|
||||
|
||||
/* An enum for discriminating between the concrete subclasses of
|
||||
checker_event. */
|
||||
|
||||
enum event_kind
|
||||
{
|
||||
EK_DEBUG,
|
||||
EK_CUSTOM,
|
||||
EK_STMT,
|
||||
EK_REGION_CREATION,
|
||||
EK_FUNCTION_ENTRY,
|
||||
EK_STATE_CHANGE,
|
||||
EK_START_CFG_EDGE,
|
||||
EK_END_CFG_EDGE,
|
||||
EK_CALL_EDGE,
|
||||
EK_RETURN_EDGE,
|
||||
EK_START_CONSOLIDATED_CFG_EDGES,
|
||||
EK_END_CONSOLIDATED_CFG_EDGES,
|
||||
EK_INLINED_CALL,
|
||||
EK_SETJMP,
|
||||
EK_REWIND_FROM_LONGJMP,
|
||||
EK_REWIND_TO_SETJMP,
|
||||
EK_WARNING
|
||||
};
|
||||
|
||||
extern const char *event_kind_to_string (enum event_kind ek);
|
||||
|
||||
/* Event subclasses.
|
||||
|
||||
The class hierarchy looks like this (using indentation to show
|
||||
inheritance, and with event_kinds shown for the concrete subclasses):
|
||||
|
||||
diagnostic_event
|
||||
checker_event
|
||||
debug_event (EK_DEBUG)
|
||||
custom_event (EK_CUSTOM)
|
||||
precanned_custom_event
|
||||
statement_event (EK_STMT)
|
||||
region_creation_event (EK_REGION_CREATION)
|
||||
function_entry_event (EK_FUNCTION_ENTRY)
|
||||
state_change_event (EK_STATE_CHANGE)
|
||||
superedge_event
|
||||
cfg_edge_event
|
||||
start_cfg_edge_event (EK_START_CFG_EDGE)
|
||||
end_cfg_edge_event (EK_END_CFG_EDGE)
|
||||
call_event (EK_CALL_EDGE)
|
||||
return_edge (EK_RETURN_EDGE)
|
||||
start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
|
||||
end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
|
||||
inlined_call_event (EK_INLINED_CALL)
|
||||
setjmp_event (EK_SETJMP)
|
||||
rewind_event
|
||||
rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
|
||||
rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
|
||||
warning_event (EK_WARNING). */
|
||||
|
||||
/* Abstract subclass of diagnostic_event; the base class for use in
|
||||
checker_path (the analyzer's diagnostic_path subclass). */
|
||||
|
||||
class checker_event : public diagnostic_event
|
||||
{
|
||||
public:
|
||||
/* Implementation of diagnostic_event. */
|
||||
|
||||
location_t get_location () const final override { return m_loc; }
|
||||
tree get_fndecl () const final override { return m_effective_fndecl; }
|
||||
int get_stack_depth () const final override { return m_effective_depth; }
|
||||
const logical_location *get_logical_location () const final override
|
||||
{
|
||||
if (m_effective_fndecl)
|
||||
return &m_logical_loc;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
meaning get_meaning () const override;
|
||||
diagnostic_thread_id_t get_thread_id () const final override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj) const override;
|
||||
|
||||
/* Additional functionality. */
|
||||
|
||||
int get_original_stack_depth () const { return m_original_depth; }
|
||||
|
||||
virtual void prepare_for_emission (checker_path *,
|
||||
pending_diagnostic *pd,
|
||||
diagnostic_event_id_t emission_id);
|
||||
virtual bool is_call_p () const { return false; }
|
||||
virtual bool is_function_entry_p () const { return false; }
|
||||
virtual bool is_return_p () const { return false; }
|
||||
|
||||
/* For use with %@. */
|
||||
const diagnostic_event_id_t *get_id_ptr () const
|
||||
{
|
||||
return &m_emission_id;
|
||||
}
|
||||
|
||||
void dump (pretty_printer *pp) const;
|
||||
void debug () const;
|
||||
|
||||
void set_location (location_t loc) { m_loc = loc; }
|
||||
|
||||
protected:
|
||||
checker_event (enum event_kind kind,
|
||||
const event_loc_info &loc_info);
|
||||
|
||||
public:
|
||||
const enum event_kind m_kind;
|
||||
protected:
|
||||
location_t m_loc;
|
||||
tree m_original_fndecl;
|
||||
tree m_effective_fndecl;
|
||||
int m_original_depth;
|
||||
int m_effective_depth;
|
||||
pending_diagnostic *m_pending_diagnostic;
|
||||
diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
|
||||
tree_logical_location m_logical_loc;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for a purely textual event, for use in
|
||||
debugging path creation and filtering. */
|
||||
|
||||
class debug_event : public checker_event
|
||||
{
|
||||
public:
|
||||
|
||||
debug_event (const event_loc_info &loc_info,
|
||||
const char *desc)
|
||||
: checker_event (EK_DEBUG, loc_info),
|
||||
m_desc (xstrdup (desc))
|
||||
{
|
||||
}
|
||||
~debug_event ()
|
||||
{
|
||||
free (m_desc);
|
||||
}
|
||||
|
||||
label_text get_desc (bool) const final override;
|
||||
|
||||
private:
|
||||
char *m_desc;
|
||||
};
|
||||
|
||||
/* An abstract event subclass for custom events. These are not filtered,
|
||||
as they are likely to be pertinent to the diagnostic. */
|
||||
|
||||
class custom_event : public checker_event
|
||||
{
|
||||
protected:
|
||||
custom_event (const event_loc_info &loc_info)
|
||||
: checker_event (EK_CUSTOM, loc_info)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/* A concrete custom_event subclass with a precanned message. */
|
||||
|
||||
class precanned_custom_event : public custom_event
|
||||
{
|
||||
public:
|
||||
precanned_custom_event (const event_loc_info &loc_info,
|
||||
const char *desc)
|
||||
: custom_event (loc_info),
|
||||
m_desc (xstrdup (desc))
|
||||
{
|
||||
}
|
||||
~precanned_custom_event ()
|
||||
{
|
||||
free (m_desc);
|
||||
}
|
||||
|
||||
label_text get_desc (bool) const final override;
|
||||
|
||||
private:
|
||||
char *m_desc;
|
||||
};
|
||||
|
||||
/* A concrete event subclass describing the execution of a gimple statement,
|
||||
for use at high verbosity levels when debugging paths. */
|
||||
|
||||
class statement_event : public checker_event
|
||||
{
|
||||
public:
|
||||
statement_event (const gimple *stmt, tree fndecl, int depth,
|
||||
const program_state &dst_state);
|
||||
|
||||
label_text get_desc (bool) const final override;
|
||||
|
||||
const gimple * const m_stmt;
|
||||
const program_state m_dst_state;
|
||||
};
|
||||
|
||||
/* An abstract event subclass describing the creation of a region that
|
||||
is significant for a diagnostic.
|
||||
|
||||
There are too many combinations to express region creation in one message,
|
||||
so we emit multiple region_creation_event instances when each pertinent
|
||||
region is created.
|
||||
|
||||
The events are created by pending_diagnostic's add_region_creation_events
|
||||
vfunc, which by default creates a region_creation_event_memory_space, and
|
||||
if a capacity is known, a region_creation_event_capacity, giving e.g.:
|
||||
(1) region created on stack here
|
||||
(2) capacity: 100 bytes
|
||||
but this vfunc can be overridden to create other events if other wordings
|
||||
are more appropriate foa a given pending_diagnostic. */
|
||||
|
||||
class region_creation_event : public checker_event
|
||||
{
|
||||
protected:
|
||||
region_creation_event (const event_loc_info &loc_info);
|
||||
};
|
||||
|
||||
/* Concrete subclass of region_creation_event.
|
||||
Generates a message based on the memory space of the region
|
||||
e.g. "region created on stack here". */
|
||||
|
||||
class region_creation_event_memory_space : public region_creation_event
|
||||
{
|
||||
public:
|
||||
region_creation_event_memory_space (enum memory_space mem_space,
|
||||
const event_loc_info &loc_info)
|
||||
: region_creation_event (loc_info),
|
||||
m_mem_space (mem_space)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
private:
|
||||
enum memory_space m_mem_space;
|
||||
};
|
||||
|
||||
/* Concrete subclass of region_creation_event.
|
||||
Generates a message based on the capacity of the region
|
||||
e.g. "capacity: 100 bytes". */
|
||||
|
||||
class region_creation_event_capacity : public region_creation_event
|
||||
{
|
||||
public:
|
||||
region_creation_event_capacity (tree capacity,
|
||||
const event_loc_info &loc_info)
|
||||
: region_creation_event (loc_info),
|
||||
m_capacity (capacity)
|
||||
{
|
||||
gcc_assert (m_capacity);
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
private:
|
||||
tree m_capacity;
|
||||
};
|
||||
|
||||
/* Concrete subclass of region_creation_event.
|
||||
Generates a message based on the capacity of the region
|
||||
e.g. "allocated 100 bytes here". */
|
||||
|
||||
class region_creation_event_allocation_size : public region_creation_event
|
||||
{
|
||||
public:
|
||||
region_creation_event_allocation_size (tree capacity,
|
||||
const event_loc_info &loc_info)
|
||||
: region_creation_event (loc_info),
|
||||
m_capacity (capacity)
|
||||
{}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
private:
|
||||
tree m_capacity;
|
||||
};
|
||||
|
||||
/* Concrete subclass of region_creation_event.
|
||||
Generates a debug message intended for analyzer developers. */
|
||||
|
||||
class region_creation_event_debug : public region_creation_event
|
||||
{
|
||||
public:
|
||||
region_creation_event_debug (const region *reg, tree capacity,
|
||||
const event_loc_info &loc_info)
|
||||
: region_creation_event (loc_info),
|
||||
m_reg (reg), m_capacity (capacity)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
private:
|
||||
const region *m_reg;
|
||||
tree m_capacity;
|
||||
};
|
||||
|
||||
/* An event subclass describing the entry to a function. */
|
||||
|
||||
class function_entry_event : public checker_event
|
||||
{
|
||||
public:
|
||||
function_entry_event (const event_loc_info &loc_info)
|
||||
: checker_event (EK_FUNCTION_ENTRY, loc_info)
|
||||
{
|
||||
}
|
||||
|
||||
function_entry_event (const program_point &dst_point);
|
||||
|
||||
label_text get_desc (bool can_colorize) const override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
bool is_function_entry_p () const final override { return true; }
|
||||
};
|
||||
|
||||
/* Subclass of checker_event describing a state change. */
|
||||
|
||||
class state_change_event : public checker_event
|
||||
{
|
||||
public:
|
||||
state_change_event (const supernode *node, const gimple *stmt,
|
||||
int stack_depth,
|
||||
const state_machine &sm,
|
||||
const svalue *sval,
|
||||
state_machine::state_t from,
|
||||
state_machine::state_t to,
|
||||
const svalue *origin,
|
||||
const program_state &dst_state,
|
||||
const exploded_node *enode);
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
const function *get_dest_function () const
|
||||
{
|
||||
return m_dst_state.get_current_function ();
|
||||
}
|
||||
|
||||
const exploded_node *get_exploded_node () const { return m_enode; }
|
||||
|
||||
const supernode *m_node;
|
||||
const gimple *m_stmt;
|
||||
const state_machine &m_sm;
|
||||
const svalue *m_sval;
|
||||
state_machine::state_t m_from;
|
||||
state_machine::state_t m_to;
|
||||
const svalue *m_origin;
|
||||
program_state m_dst_state;
|
||||
const exploded_node *m_enode;
|
||||
};
|
||||
|
||||
/* Subclass of checker_event; parent class for subclasses that relate to
|
||||
a superedge. */
|
||||
|
||||
class superedge_event : public checker_event
|
||||
{
|
||||
public:
|
||||
void maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj)
|
||||
const override;
|
||||
|
||||
/* Mark this edge event as being either an interprocedural call or
|
||||
return in which VAR is in STATE, and that this is critical to the
|
||||
diagnostic (so that get_desc can attempt to get a better description
|
||||
from any pending_diagnostic). */
|
||||
void record_critical_state (tree var, state_machine::state_t state)
|
||||
{
|
||||
m_var = var;
|
||||
m_critical_state = state;
|
||||
}
|
||||
|
||||
const callgraph_superedge& get_callgraph_superedge () const;
|
||||
|
||||
bool should_filter_p (int verbosity) const;
|
||||
|
||||
protected:
|
||||
superedge_event (enum event_kind kind, const exploded_edge &eedge,
|
||||
const event_loc_info &loc_info);
|
||||
|
||||
public:
|
||||
const exploded_edge &m_eedge;
|
||||
const superedge *m_sedge;
|
||||
tree m_var;
|
||||
state_machine::state_t m_critical_state;
|
||||
};
|
||||
|
||||
/* An abstract event subclass for when a CFG edge is followed; it has two
|
||||
subclasses, representing the start of the edge and the end of the
|
||||
edge, which come in pairs. */
|
||||
|
||||
class cfg_edge_event : public superedge_event
|
||||
{
|
||||
public:
|
||||
meaning get_meaning () const override;
|
||||
|
||||
const cfg_superedge& get_cfg_superedge () const;
|
||||
|
||||
protected:
|
||||
cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
|
||||
const event_loc_info &loc_info);
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the start of a CFG edge
|
||||
e.g. "following 'false' branch...'. */
|
||||
|
||||
class start_cfg_edge_event : public cfg_edge_event
|
||||
{
|
||||
public:
|
||||
start_cfg_edge_event (const exploded_edge &eedge,
|
||||
const event_loc_info &loc_info)
|
||||
: cfg_edge_event (EK_START_CFG_EDGE, eedge, loc_info)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const override;
|
||||
|
||||
protected:
|
||||
label_text maybe_describe_condition (bool can_colorize) const;
|
||||
|
||||
private:
|
||||
static label_text maybe_describe_condition (bool can_colorize,
|
||||
tree lhs,
|
||||
enum tree_code op,
|
||||
tree rhs);
|
||||
static bool should_print_expr_p (tree);
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the end of a CFG edge
|
||||
e.g. "...to here'. */
|
||||
|
||||
class end_cfg_edge_event : public cfg_edge_event
|
||||
{
|
||||
public:
|
||||
end_cfg_edge_event (const exploded_edge &eedge,
|
||||
const event_loc_info &loc_info)
|
||||
: cfg_edge_event (EK_END_CFG_EDGE, eedge, loc_info)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool /*can_colorize*/) const final override
|
||||
{
|
||||
return label_text::borrow ("...to here");
|
||||
}
|
||||
};
|
||||
|
||||
/* A concrete event subclass for an interprocedural call. */
|
||||
|
||||
class call_event : public superedge_event
|
||||
{
|
||||
public:
|
||||
call_event (const exploded_edge &eedge,
|
||||
const event_loc_info &loc_info);
|
||||
|
||||
label_text get_desc (bool can_colorize) const override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
bool is_call_p () const final override;
|
||||
|
||||
protected:
|
||||
tree get_caller_fndecl () const;
|
||||
tree get_callee_fndecl () const;
|
||||
|
||||
const supernode *m_src_snode;
|
||||
const supernode *m_dest_snode;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for an interprocedural return. */
|
||||
|
||||
class return_event : public superedge_event
|
||||
{
|
||||
public:
|
||||
return_event (const exploded_edge &eedge,
|
||||
const event_loc_info &loc_info);
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
bool is_return_p () const final override;
|
||||
|
||||
const supernode *m_src_snode;
|
||||
const supernode *m_dest_snode;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the start of a consolidated run of CFG
|
||||
edges all either TRUE or FALSE e.g. "following 'false' branch...'. */
|
||||
|
||||
class start_consolidated_cfg_edges_event : public checker_event
|
||||
{
|
||||
public:
|
||||
start_consolidated_cfg_edges_event (const event_loc_info &loc_info,
|
||||
bool edge_sense)
|
||||
: checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc_info),
|
||||
m_edge_sense (edge_sense)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
private:
|
||||
bool m_edge_sense;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for the end of a consolidated run of
|
||||
CFG edges e.g. "...to here'. */
|
||||
|
||||
class end_consolidated_cfg_edges_event : public checker_event
|
||||
{
|
||||
public:
|
||||
end_consolidated_cfg_edges_event (const event_loc_info &loc_info)
|
||||
: checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc_info)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool /*can_colorize*/) const final override
|
||||
{
|
||||
return label_text::borrow ("...to here");
|
||||
}
|
||||
};
|
||||
|
||||
/* A concrete event subclass for describing an inlined call event
|
||||
e.g. "inlined call to 'callee' from 'caller'". */
|
||||
|
||||
class inlined_call_event : public checker_event
|
||||
{
|
||||
public:
|
||||
inlined_call_event (location_t loc,
|
||||
tree apparent_callee_fndecl,
|
||||
tree apparent_caller_fndecl,
|
||||
int actual_depth,
|
||||
int stack_depth_adjustment)
|
||||
: checker_event (EK_INLINED_CALL,
|
||||
event_loc_info (loc,
|
||||
apparent_caller_fndecl,
|
||||
actual_depth + stack_depth_adjustment)),
|
||||
m_apparent_callee_fndecl (apparent_callee_fndecl),
|
||||
m_apparent_caller_fndecl (apparent_caller_fndecl)
|
||||
{
|
||||
gcc_assert (LOCATION_BLOCK (loc) == NULL);
|
||||
}
|
||||
|
||||
label_text get_desc (bool /*can_colorize*/) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
private:
|
||||
tree m_apparent_callee_fndecl;
|
||||
tree m_apparent_caller_fndecl;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for a setjmp or sigsetjmp call. */
|
||||
|
||||
class setjmp_event : public checker_event
|
||||
{
|
||||
public:
|
||||
setjmp_event (const event_loc_info &loc_info,
|
||||
const exploded_node *enode,
|
||||
const gcall *setjmp_call)
|
||||
: checker_event (EK_SETJMP, loc_info),
|
||||
m_enode (enode), m_setjmp_call (setjmp_call)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
void prepare_for_emission (checker_path *path,
|
||||
pending_diagnostic *pd,
|
||||
diagnostic_event_id_t emission_id) final override;
|
||||
|
||||
private:
|
||||
const exploded_node *m_enode;
|
||||
const gcall *m_setjmp_call;
|
||||
};
|
||||
|
||||
/* An abstract event subclass for rewinding from a longjmp to a setjmp
|
||||
(or siglongjmp to sigsetjmp).
|
||||
|
||||
Base class for two from/to subclasses, showing the two halves of the
|
||||
rewind. */
|
||||
|
||||
class rewind_event : public checker_event
|
||||
{
|
||||
public:
|
||||
tree get_longjmp_caller () const;
|
||||
tree get_setjmp_caller () const;
|
||||
const exploded_edge *get_eedge () const { return m_eedge; }
|
||||
|
||||
protected:
|
||||
rewind_event (const exploded_edge *eedge,
|
||||
enum event_kind kind,
|
||||
const event_loc_info &loc_info,
|
||||
const rewind_info_t *rewind_info);
|
||||
const rewind_info_t *m_rewind_info;
|
||||
|
||||
private:
|
||||
const exploded_edge *m_eedge;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for rewinding from a longjmp to a setjmp,
|
||||
showing the longjmp (or siglongjmp). */
|
||||
|
||||
class rewind_from_longjmp_event : public rewind_event
|
||||
{
|
||||
public:
|
||||
rewind_from_longjmp_event (const exploded_edge *eedge,
|
||||
const event_loc_info &loc_info,
|
||||
const rewind_info_t *rewind_info)
|
||||
: rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc_info,
|
||||
rewind_info)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
};
|
||||
|
||||
/* A concrete event subclass for rewinding from a longjmp to a setjmp,
|
||||
showing the setjmp (or sigsetjmp). */
|
||||
|
||||
class rewind_to_setjmp_event : public rewind_event
|
||||
{
|
||||
public:
|
||||
rewind_to_setjmp_event (const exploded_edge *eedge,
|
||||
const event_loc_info &loc_info,
|
||||
const rewind_info_t *rewind_info)
|
||||
: rewind_event (eedge, EK_REWIND_TO_SETJMP, loc_info,
|
||||
rewind_info)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
|
||||
void prepare_for_emission (checker_path *path,
|
||||
pending_diagnostic *pd,
|
||||
diagnostic_event_id_t emission_id) final override;
|
||||
|
||||
private:
|
||||
diagnostic_event_id_t m_original_setjmp_event_id;
|
||||
};
|
||||
|
||||
/* Concrete subclass of checker_event for use at the end of a path:
|
||||
a repeat of the warning message at the end of the path (perhaps with
|
||||
references to pertinent events that occurred on the way), at the point
|
||||
where the problem occurs. */
|
||||
|
||||
class warning_event : public checker_event
|
||||
{
|
||||
public:
|
||||
warning_event (const event_loc_info &loc_info,
|
||||
const exploded_node *enode,
|
||||
const state_machine *sm,
|
||||
tree var, state_machine::state_t state)
|
||||
: checker_event (EK_WARNING, loc_info),
|
||||
m_enode (enode),
|
||||
m_sm (sm), m_var (var), m_state (state)
|
||||
{
|
||||
}
|
||||
|
||||
label_text get_desc (bool can_colorize) const final override;
|
||||
meaning get_meaning () const override;
|
||||
|
||||
const exploded_node *get_exploded_node () const { return m_enode; }
|
||||
|
||||
private:
|
||||
const exploded_node *m_enode;
|
||||
const state_machine *m_sm;
|
||||
tree m_var;
|
||||
state_machine::state_t m_state;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_CHECKER_EVENT_H */
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/* Subclass of diagnostic_path for analyzer diagnostics.
|
||||
Copyright (C) 2019-2024 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_CHECKER_PATH_H
|
||||
#define GCC_ANALYZER_CHECKER_PATH_H
|
||||
|
||||
#include "analyzer/checker-event.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Subclass of diagnostic_path for analyzer diagnostics. */
|
||||
|
||||
class checker_path : public diagnostic_path
|
||||
{
|
||||
public:
|
||||
checker_path (logger *logger)
|
||||
: diagnostic_path (),
|
||||
m_thread ("main"),
|
||||
m_logger (logger)
|
||||
{}
|
||||
|
||||
/* Implementation of diagnostic_path vfuncs. */
|
||||
|
||||
unsigned num_events () const final override
|
||||
{
|
||||
return m_events.length ();
|
||||
}
|
||||
|
||||
const diagnostic_event & get_event (int idx) const final override
|
||||
{
|
||||
return *m_events[idx];
|
||||
}
|
||||
unsigned num_threads () const final override
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
const diagnostic_thread &
|
||||
get_thread (diagnostic_thread_id_t) const final override
|
||||
{
|
||||
return m_thread;
|
||||
}
|
||||
|
||||
checker_event *get_checker_event (int idx)
|
||||
{
|
||||
return m_events[idx];
|
||||
}
|
||||
|
||||
void dump (pretty_printer *pp) const;
|
||||
void debug () const;
|
||||
|
||||
logger *get_logger () const { return m_logger; }
|
||||
void maybe_log (logger *logger, const char *desc) const;
|
||||
|
||||
void add_event (std::unique_ptr<checker_event> event);
|
||||
|
||||
void delete_event (int idx)
|
||||
{
|
||||
checker_event *event = m_events[idx];
|
||||
m_events.ordered_remove (idx);
|
||||
delete event;
|
||||
}
|
||||
|
||||
void delete_events (unsigned start_idx, unsigned len)
|
||||
{
|
||||
for (unsigned i = start_idx; i < start_idx + len; i++)
|
||||
delete m_events[i];
|
||||
m_events.block_remove (start_idx, len);
|
||||
}
|
||||
|
||||
void replace_event (unsigned idx, checker_event *new_event)
|
||||
{
|
||||
delete m_events[idx];
|
||||
m_events[idx] = new_event;
|
||||
}
|
||||
|
||||
void add_region_creation_events (pending_diagnostic *pd,
|
||||
const region *reg,
|
||||
const region_model *model,
|
||||
const event_loc_info &loc_info,
|
||||
bool debug);
|
||||
|
||||
/* After all event-pruning, a hook for notifying each event what
|
||||
its ID will be. The events are notified in order, allowing
|
||||
for later events to refer to the IDs of earlier events in
|
||||
their descriptions. */
|
||||
void prepare_for_emission (pending_diagnostic *pd)
|
||||
{
|
||||
checker_event *e;
|
||||
int i;
|
||||
FOR_EACH_VEC_ELT (m_events, i, e)
|
||||
e->prepare_for_emission (this, pd, diagnostic_event_id_t (i));
|
||||
}
|
||||
|
||||
void fixup_locations (pending_diagnostic *pd);
|
||||
|
||||
void record_setjmp_event (const exploded_node *enode,
|
||||
diagnostic_event_id_t setjmp_emission_id)
|
||||
{
|
||||
m_setjmp_event_ids.put (enode, setjmp_emission_id);
|
||||
}
|
||||
|
||||
bool get_setjmp_event (const exploded_node *enode,
|
||||
diagnostic_event_id_t *out_emission_id)
|
||||
{
|
||||
if (diagnostic_event_id_t *emission_id = m_setjmp_event_ids.get (enode))
|
||||
{
|
||||
*out_emission_id = *emission_id;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cfg_edge_pair_at_p (unsigned idx) const;
|
||||
|
||||
void inject_any_inlined_call_events (logger *logger);
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN(checker_path);
|
||||
|
||||
simple_diagnostic_thread m_thread;
|
||||
|
||||
/* The events that have occurred along this path. */
|
||||
auto_delete_vec<checker_event> m_events;
|
||||
|
||||
/* During prepare_for_emission (and after), the setjmp_event for each
|
||||
exploded_node *, so that rewind events can refer to them in their
|
||||
descriptions. */
|
||||
hash_map <const exploded_node *, diagnostic_event_id_t> m_setjmp_event_ids;
|
||||
|
||||
logger *m_logger;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_CHECKER_PATH_H */
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/* Measuring the complexity of svalues/regions.
|
||||
Copyright (C) 2020-2024 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_COMPLEXITY_H
|
||||
#define GCC_ANALYZER_COMPLEXITY_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A measurement of the complexity of an svalue or region, so that
|
||||
we can impose bounds on the growth of these tree-like structures
|
||||
and thus avoid infinite chains of analysis. */
|
||||
|
||||
struct complexity
|
||||
{
|
||||
complexity (unsigned num_nodes, unsigned max_depth)
|
||||
: m_num_nodes (num_nodes), m_max_depth (max_depth)
|
||||
{}
|
||||
|
||||
complexity (const region *reg);
|
||||
complexity (const svalue *sval);
|
||||
static complexity from_pair (const complexity &c1, const complexity &c);
|
||||
static complexity from_vec_svalue (const vec<const svalue *> &vec);
|
||||
|
||||
/* The total number of svalues and regions in the tree of this
|
||||
entity, including the entity itself. */
|
||||
unsigned m_num_nodes;
|
||||
|
||||
/* The maximum depth of the tree of this entity, including the
|
||||
entity itself. */
|
||||
unsigned m_max_depth;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_COMPLEXITY_H */
|
||||
+515
@@ -0,0 +1,515 @@
|
||||
/* Tracking equivalence classes and constraints at a point on an execution path.
|
||||
Copyright (C) 2019-2024 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_CONSTRAINT_MANAGER_H
|
||||
#define GCC_ANALYZER_CONSTRAINT_MANAGER_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
class constraint_manager;
|
||||
|
||||
enum bound_kind
|
||||
{
|
||||
BK_LOWER,
|
||||
BK_UPPER
|
||||
};
|
||||
|
||||
/* One of the end-points of a range. */
|
||||
|
||||
struct bound
|
||||
{
|
||||
bound () : m_constant (NULL_TREE), m_closed (false) {}
|
||||
bound (tree constant, bool closed)
|
||||
: m_constant (constant), m_closed (closed) {}
|
||||
|
||||
void ensure_closed (enum bound_kind bound_kind);
|
||||
|
||||
const char * get_relation_as_str () const;
|
||||
|
||||
tree m_constant;
|
||||
bool m_closed;
|
||||
};
|
||||
|
||||
/* A range of values, used for determining if a value has been
|
||||
constrained to just one possible constant value. */
|
||||
|
||||
class range
|
||||
{
|
||||
public:
|
||||
range () : m_lower_bound (), m_upper_bound () {}
|
||||
range (const bound &lower, const bound &upper)
|
||||
: m_lower_bound (lower), m_upper_bound (upper) {}
|
||||
|
||||
void dump_to_pp (pretty_printer *pp) const;
|
||||
void dump () const;
|
||||
|
||||
tree constrained_to_single_element ();
|
||||
|
||||
tristate eval_condition (enum tree_code op,
|
||||
tree rhs_const) const;
|
||||
bool below_lower_bound (tree rhs_const) const;
|
||||
bool above_upper_bound (tree rhs_const) const;
|
||||
|
||||
bool add_bound (bound b, enum bound_kind bound_kind);
|
||||
bool add_bound (enum tree_code op, tree rhs_const);
|
||||
|
||||
private:
|
||||
bound m_lower_bound;
|
||||
bound m_upper_bound;
|
||||
};
|
||||
|
||||
/* A closed range of values with constant integer bounds
|
||||
e.g. [3, 5] for the set {3, 4, 5}. */
|
||||
|
||||
struct bounded_range
|
||||
{
|
||||
bounded_range (const_tree lower, const_tree upper);
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool show_types) const;
|
||||
void dump (bool show_types) const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool contains_p (tree cst) const;
|
||||
|
||||
bool intersects_p (const bounded_range &other,
|
||||
bounded_range *out) const;
|
||||
|
||||
bool operator== (const bounded_range &other) const;
|
||||
bool operator!= (const bounded_range &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
static int cmp (const bounded_range &a, const bounded_range &b);
|
||||
|
||||
bool singleton_p () const
|
||||
{
|
||||
return tree_int_cst_equal (m_lower, m_upper);
|
||||
}
|
||||
|
||||
tree m_lower;
|
||||
tree m_upper;
|
||||
|
||||
private:
|
||||
static void set_json_attr (json::object *obj, const char *name, tree value);
|
||||
};
|
||||
|
||||
/* A collection of bounded_range instances, suitable
|
||||
for representing the ranges on a case label within a switch
|
||||
statement. */
|
||||
|
||||
struct bounded_ranges
|
||||
{
|
||||
public:
|
||||
typedef bounded_ranges key_t;
|
||||
|
||||
bounded_ranges (const bounded_range &range);
|
||||
bounded_ranges (const vec<bounded_range> &ranges);
|
||||
bounded_ranges (enum tree_code op, tree rhs_const);
|
||||
|
||||
bool operator== (const bounded_ranges &other) const;
|
||||
|
||||
hashval_t get_hash () const { return m_hash; }
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool show_types) const;
|
||||
void dump (bool show_types) const;
|
||||
|
||||
json::value *to_json () const;
|
||||
|
||||
tristate eval_condition (enum tree_code op,
|
||||
tree rhs_const,
|
||||
bounded_ranges_manager *mgr) const;
|
||||
|
||||
bool contain_p (tree cst) const;
|
||||
bool empty_p () const { return m_ranges.length () == 0; }
|
||||
|
||||
static int cmp (const bounded_ranges *a, const bounded_ranges *b);
|
||||
|
||||
unsigned get_count () const { return m_ranges.length (); }
|
||||
const bounded_range &get_range (unsigned idx) const { return m_ranges[idx]; }
|
||||
|
||||
private:
|
||||
void canonicalize ();
|
||||
void validate () const;
|
||||
|
||||
friend class bounded_ranges_manager;
|
||||
|
||||
auto_vec<bounded_range> m_ranges;
|
||||
hashval_t m_hash;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
template <> struct default_hash_traits<bounded_ranges::key_t>
|
||||
: public member_function_hash_traits<bounded_ranges::key_t>
|
||||
{
|
||||
static const bool empty_zero_p = true;
|
||||
};
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* An object to own and consolidate bounded_ranges instances.
|
||||
This also caches the mapping from switch_cfg_superedge
|
||||
bounded_ranges instances, so that get_or_create_ranges_for_switch is
|
||||
memoized. */
|
||||
|
||||
class bounded_ranges_manager
|
||||
{
|
||||
public:
|
||||
~bounded_ranges_manager ();
|
||||
|
||||
const bounded_ranges *
|
||||
get_or_create_ranges_for_switch (const switch_cfg_superedge *edge,
|
||||
const gswitch *switch_stmt);
|
||||
|
||||
const bounded_ranges *get_or_create_empty ();
|
||||
const bounded_ranges *get_or_create_point (const_tree value);
|
||||
const bounded_ranges *get_or_create_range (const_tree lower_bound,
|
||||
const_tree upper_bound);
|
||||
const bounded_ranges *
|
||||
get_or_create_union (const vec <const bounded_ranges *> &others);
|
||||
const bounded_ranges *
|
||||
get_or_create_intersection (const bounded_ranges *a,
|
||||
const bounded_ranges *b);
|
||||
const bounded_ranges *
|
||||
get_or_create_inverse (const bounded_ranges *other, tree type);
|
||||
|
||||
void log_stats (logger *logger, bool show_objs) const;
|
||||
|
||||
private:
|
||||
const bounded_ranges *
|
||||
create_ranges_for_switch (const switch_cfg_superedge &edge,
|
||||
const gswitch *switch_stmt);
|
||||
|
||||
const bounded_ranges *
|
||||
make_case_label_ranges (const gswitch *switch_stmt,
|
||||
tree case_label);
|
||||
|
||||
const bounded_ranges *consolidate (bounded_ranges *);
|
||||
|
||||
struct hash_traits_t : public typed_noop_remove<bounded_ranges *>
|
||||
{
|
||||
typedef bounded_ranges *key_type;
|
||||
typedef bounded_ranges *value_type;
|
||||
|
||||
static inline bool
|
||||
equal (const key_type &k1, const key_type &k2)
|
||||
{
|
||||
return *k1 == *k2;
|
||||
}
|
||||
static inline hashval_t
|
||||
hash (const key_type &k)
|
||||
{
|
||||
return k->get_hash ();
|
||||
}
|
||||
static inline bool is_empty (key_type k) { return k == NULL; }
|
||||
static inline void mark_empty (key_type &k) { k = NULL; }
|
||||
static inline bool is_deleted (key_type k)
|
||||
{
|
||||
return k == reinterpret_cast<key_type> (1);
|
||||
}
|
||||
|
||||
static const bool empty_zero_p = true;
|
||||
};
|
||||
struct traits_t : public simple_hashmap_traits<hash_traits_t,
|
||||
bounded_ranges *>
|
||||
{
|
||||
};
|
||||
typedef hash_map<bounded_ranges *, bounded_ranges *, traits_t> map_t;
|
||||
map_t m_map;
|
||||
|
||||
typedef hash_map<const switch_cfg_superedge *,
|
||||
const bounded_ranges *> edge_cache_t;
|
||||
edge_cache_t m_edge_cache;
|
||||
};
|
||||
|
||||
/* An equivalence class within a constraint manager: a set of
|
||||
svalues that are known to all be equal to each other,
|
||||
together with an optional tree constant that they are equal to. */
|
||||
|
||||
class equiv_class
|
||||
{
|
||||
public:
|
||||
equiv_class ();
|
||||
equiv_class (const equiv_class &other);
|
||||
|
||||
hashval_t hash () const;
|
||||
bool operator== (const equiv_class &other);
|
||||
|
||||
void add (const svalue *sval);
|
||||
bool del (const svalue *sval);
|
||||
|
||||
tree get_any_constant () const { return m_constant; }
|
||||
|
||||
const svalue *get_representative () const;
|
||||
|
||||
void canonicalize ();
|
||||
|
||||
void print (pretty_printer *pp) const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool contains_non_constant_p () const;
|
||||
|
||||
/* An equivalence class can contain multiple constants (e.g. multiple
|
||||
different zeroes, for different types); these are just for the last
|
||||
constant added. */
|
||||
tree m_constant;
|
||||
const svalue *m_cst_sval;
|
||||
|
||||
// TODO: should this be a set rather than a vec?
|
||||
auto_vec<const svalue *> m_vars;
|
||||
};
|
||||
|
||||
/* The various kinds of constraint. */
|
||||
|
||||
enum constraint_op
|
||||
{
|
||||
CONSTRAINT_NE,
|
||||
CONSTRAINT_LT,
|
||||
CONSTRAINT_LE
|
||||
};
|
||||
|
||||
const char *constraint_op_code (enum constraint_op c_op);
|
||||
|
||||
/* An ID for an equiv_class within a constraint_manager. Internally, this
|
||||
is an index into a vector of equiv_class * within the constraint_manager. */
|
||||
|
||||
class equiv_class_id
|
||||
{
|
||||
public:
|
||||
static equiv_class_id null () { return equiv_class_id (-1); }
|
||||
|
||||
equiv_class_id (unsigned idx) : m_idx (idx) {}
|
||||
const equiv_class &get_obj (const constraint_manager &cm) const;
|
||||
equiv_class &get_obj (constraint_manager &cm) const;
|
||||
|
||||
bool operator== (const equiv_class_id &other) const
|
||||
{
|
||||
return m_idx == other.m_idx;
|
||||
}
|
||||
bool operator!= (const equiv_class_id &other) const
|
||||
{
|
||||
return m_idx != other.m_idx;
|
||||
}
|
||||
|
||||
bool null_p () const { return m_idx == -1; }
|
||||
|
||||
static equiv_class_id from_int (int idx) { return equiv_class_id (idx); }
|
||||
int as_int () const { return m_idx; }
|
||||
|
||||
void print (pretty_printer *pp) const;
|
||||
|
||||
void update_for_removal (equiv_class_id other)
|
||||
{
|
||||
if (m_idx > other.m_idx)
|
||||
m_idx--;
|
||||
}
|
||||
|
||||
int m_idx;
|
||||
};
|
||||
|
||||
/* A relationship between two equivalence classes in a constraint_manager. */
|
||||
|
||||
class constraint
|
||||
{
|
||||
public:
|
||||
constraint (equiv_class_id lhs, enum constraint_op c_op, equiv_class_id rhs)
|
||||
: m_lhs (lhs), m_op (c_op), m_rhs (rhs)
|
||||
{
|
||||
gcc_assert (!lhs.null_p ());
|
||||
gcc_assert (!rhs.null_p ());
|
||||
}
|
||||
|
||||
void print (pretty_printer *pp, const constraint_manager &cm) const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
hashval_t hash () const;
|
||||
bool operator== (const constraint &other) const;
|
||||
|
||||
/* Is this an ordering, rather than a "!=". */
|
||||
bool is_ordering_p () const
|
||||
{
|
||||
return m_op != CONSTRAINT_NE;
|
||||
}
|
||||
|
||||
bool implied_by (const constraint &other,
|
||||
const constraint_manager &cm) const;
|
||||
|
||||
equiv_class_id m_lhs;
|
||||
enum constraint_op m_op;
|
||||
equiv_class_id m_rhs;
|
||||
};
|
||||
|
||||
/* An abstract base class for use with constraint_manager::for_each_fact. */
|
||||
|
||||
class fact_visitor
|
||||
{
|
||||
public:
|
||||
virtual ~fact_visitor () {}
|
||||
virtual void on_fact (const svalue *lhs,
|
||||
enum tree_code,
|
||||
const svalue *rhs) = 0;
|
||||
virtual void on_ranges (const svalue *lhs,
|
||||
const bounded_ranges *ranges) = 0;
|
||||
};
|
||||
|
||||
class bounded_ranges_constraint
|
||||
{
|
||||
public:
|
||||
bounded_ranges_constraint (equiv_class_id ec_id,
|
||||
const bounded_ranges *ranges)
|
||||
: m_ec_id (ec_id), m_ranges (ranges)
|
||||
{
|
||||
}
|
||||
|
||||
void print (pretty_printer *pp, const constraint_manager &cm) const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool operator== (const bounded_ranges_constraint &other) const;
|
||||
bool operator!= (const bounded_ranges_constraint &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void add_to_hash (inchash::hash *hstate) const;
|
||||
|
||||
equiv_class_id m_ec_id;
|
||||
const bounded_ranges *m_ranges;
|
||||
};
|
||||
|
||||
/* A collection of equivalence classes and constraints on them.
|
||||
|
||||
Given N svalues, this can be thought of as representing a subset of
|
||||
N-dimensional space. When we call add_constraint,
|
||||
we are effectively taking an intersection with that constraint. */
|
||||
|
||||
class constraint_manager
|
||||
{
|
||||
public:
|
||||
constraint_manager (region_model_manager *mgr) : m_mgr (mgr) {}
|
||||
constraint_manager (const constraint_manager &other);
|
||||
virtual ~constraint_manager () {}
|
||||
|
||||
constraint_manager& operator= (const constraint_manager &other);
|
||||
|
||||
hashval_t hash () const;
|
||||
bool operator== (const constraint_manager &other) const;
|
||||
bool operator!= (const constraint_manager &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void print (pretty_printer *pp) const;
|
||||
void dump_to_pp (pretty_printer *pp, bool multiline) const;
|
||||
void dump (FILE *fp) const;
|
||||
void dump () const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
const equiv_class &get_equiv_class_by_index (unsigned idx) const
|
||||
{
|
||||
return *m_equiv_classes[idx];
|
||||
}
|
||||
equiv_class &get_equiv_class_by_index (unsigned idx)
|
||||
{
|
||||
return *m_equiv_classes[idx];
|
||||
}
|
||||
|
||||
equiv_class &get_equiv_class (const svalue *sval)
|
||||
{
|
||||
equiv_class_id ec_id = get_or_add_equiv_class (sval);
|
||||
return ec_id.get_obj (*this);
|
||||
}
|
||||
|
||||
bool add_constraint (const svalue *lhs,
|
||||
enum tree_code op,
|
||||
const svalue *rhs);
|
||||
|
||||
bool add_constraint (equiv_class_id lhs_ec_id,
|
||||
enum tree_code op,
|
||||
equiv_class_id rhs_ec_id);
|
||||
|
||||
void add_unknown_constraint (equiv_class_id lhs_ec_id,
|
||||
enum tree_code op,
|
||||
equiv_class_id rhs_ec_id);
|
||||
|
||||
bool add_bounded_ranges (const svalue *sval,
|
||||
const bounded_ranges *ranges);
|
||||
|
||||
bool get_equiv_class_by_svalue (const svalue *sval,
|
||||
equiv_class_id *out) const;
|
||||
bool sval_constrained_p (const svalue *sval) const;
|
||||
equiv_class_id get_or_add_equiv_class (const svalue *sval);
|
||||
tristate eval_condition (equiv_class_id lhs,
|
||||
enum tree_code op,
|
||||
equiv_class_id rhs) const;
|
||||
tristate eval_condition (equiv_class_id lhs_ec,
|
||||
enum tree_code op,
|
||||
tree rhs_const) const;
|
||||
tristate eval_condition (const svalue *lhs,
|
||||
enum tree_code op,
|
||||
const svalue *rhs) const;
|
||||
range get_ec_bounds (equiv_class_id ec_id) const;
|
||||
|
||||
/* PurgeCriteria should have:
|
||||
bool should_purge_p (const svalue *sval) const. */
|
||||
template <typename PurgeCriteria>
|
||||
void purge (const PurgeCriteria &p, purge_stats *stats);
|
||||
|
||||
void on_liveness_change (const svalue_set &live_svalues,
|
||||
const region_model *model);
|
||||
void purge_state_involving (const svalue *sval);
|
||||
|
||||
void canonicalize ();
|
||||
|
||||
static void merge (const constraint_manager &cm_a,
|
||||
const constraint_manager &cm_b,
|
||||
constraint_manager *out);
|
||||
|
||||
void for_each_fact (fact_visitor *) const;
|
||||
|
||||
void validate () const;
|
||||
|
||||
bounded_ranges_manager *get_range_manager () const;
|
||||
|
||||
bool replay_call_summary (call_summary_replay &r,
|
||||
const constraint_manager &summary);
|
||||
|
||||
auto_delete_vec<equiv_class> m_equiv_classes;
|
||||
auto_vec<constraint> m_constraints;
|
||||
auto_vec<bounded_ranges_constraint> m_bounded_ranges_constraints;
|
||||
|
||||
private:
|
||||
void add_constraint_internal (equiv_class_id lhs_id,
|
||||
enum constraint_op c_op,
|
||||
equiv_class_id rhs_id);
|
||||
bool impossible_derived_conditions_p (const svalue *lhs,
|
||||
const svalue *rhs) const;
|
||||
|
||||
region_model_manager *m_mgr;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_CONSTRAINT_MANAGER_H */
|
||||
+242
@@ -0,0 +1,242 @@
|
||||
/* Classes for saving, deduplicating, and emitting analyzer diagnostics.
|
||||
Copyright (C) 2019-2024 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_DIAGNOSTIC_MANAGER_H
|
||||
#define GCC_ANALYZER_DIAGNOSTIC_MANAGER_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
class epath_finder;
|
||||
|
||||
/* A to-be-emitted diagnostic stored within diagnostic_manager. */
|
||||
|
||||
class saved_diagnostic
|
||||
{
|
||||
public:
|
||||
saved_diagnostic (const state_machine *sm,
|
||||
const pending_location &ploc,
|
||||
tree var, const svalue *sval,
|
||||
state_machine::state_t state,
|
||||
std::unique_ptr<pending_diagnostic> d,
|
||||
unsigned idx);
|
||||
|
||||
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;
|
||||
|
||||
void dump_dot_id (pretty_printer *pp) const;
|
||||
void dump_as_dot_node (pretty_printer *pp) const;
|
||||
|
||||
const feasibility_problem *get_feasibility_problem () const
|
||||
{
|
||||
return m_problem.get ();
|
||||
}
|
||||
|
||||
bool calc_best_epath (epath_finder *pf);
|
||||
const exploded_path *get_best_epath () const { return m_best_epath.get (); }
|
||||
unsigned get_epath_length () const;
|
||||
|
||||
void add_duplicate (saved_diagnostic *other);
|
||||
unsigned get_num_dupes () const { return m_duplicates.length (); }
|
||||
|
||||
unsigned get_index () const { return m_idx; }
|
||||
|
||||
bool supercedes_p (const saved_diagnostic &other) const;
|
||||
|
||||
void add_any_saved_events (checker_path &dst_path);
|
||||
|
||||
void emit_any_notes () const;
|
||||
|
||||
void maybe_add_sarif_properties (sarif_object &result_obj) const;
|
||||
|
||||
//private:
|
||||
const state_machine *m_sm;
|
||||
const exploded_node *m_enode;
|
||||
const supernode *m_snode;
|
||||
const gimple *m_stmt;
|
||||
std::unique_ptr<stmt_finder> m_stmt_finder;
|
||||
location_t m_loc;
|
||||
tree m_var;
|
||||
const svalue *m_sval;
|
||||
state_machine::state_t m_state;
|
||||
std::unique_ptr<pending_diagnostic> m_d;
|
||||
const exploded_edge *m_trailing_eedge;
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN (saved_diagnostic);
|
||||
|
||||
unsigned m_idx;
|
||||
std::unique_ptr<exploded_path> m_best_epath;
|
||||
std::unique_ptr<feasibility_problem> m_problem;
|
||||
|
||||
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;
|
||||
|
||||
/* A bundle of information capturing where a pending_diagnostic should
|
||||
be emitted. */
|
||||
|
||||
struct pending_location
|
||||
{
|
||||
public:
|
||||
pending_location (exploded_node *enode,
|
||||
const supernode *snode,
|
||||
const gimple *stmt,
|
||||
const stmt_finder *finder)
|
||||
: m_enode (enode),
|
||||
m_snode (snode),
|
||||
m_stmt (stmt),
|
||||
m_finder (finder),
|
||||
m_loc (UNKNOWN_LOCATION)
|
||||
{
|
||||
gcc_assert (m_stmt || m_finder);
|
||||
}
|
||||
|
||||
/* ctor for cases where we have a location_t but there isn't any
|
||||
gimple stmt associated with the diagnostic. */
|
||||
|
||||
pending_location (exploded_node *enode,
|
||||
const supernode *snode,
|
||||
location_t loc)
|
||||
: m_enode (enode),
|
||||
m_snode (snode),
|
||||
m_stmt (nullptr),
|
||||
m_finder (nullptr),
|
||||
m_loc (loc)
|
||||
{
|
||||
}
|
||||
|
||||
exploded_node *m_enode;
|
||||
const supernode *m_snode;
|
||||
const gimple *m_stmt;
|
||||
const stmt_finder *m_finder;
|
||||
location_t m_loc;
|
||||
};
|
||||
|
||||
/* A class with responsibility for saving pending diagnostics, so that
|
||||
they can be emitted after the exploded_graph is complete.
|
||||
This lets us de-duplicate diagnostics, and find the shortest path
|
||||
for each similar diagnostic, potentially using edges that might
|
||||
not have been found when each diagnostic was first saved.
|
||||
|
||||
This also lets us compute shortest_paths once, rather than
|
||||
per-diagnostic. */
|
||||
|
||||
class diagnostic_manager : public log_user
|
||||
{
|
||||
public:
|
||||
diagnostic_manager (logger *logger, engine *eng, int verbosity);
|
||||
|
||||
engine *get_engine () const { return m_eng; }
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool add_diagnostic (const state_machine *sm,
|
||||
const pending_location &ploc,
|
||||
tree var,
|
||||
const svalue *sval,
|
||||
state_machine::state_t state,
|
||||
std::unique_ptr<pending_diagnostic> d);
|
||||
|
||||
bool add_diagnostic (const pending_location &ploc,
|
||||
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,
|
||||
saved_diagnostic &sd);
|
||||
|
||||
unsigned get_num_diagnostics () const
|
||||
{
|
||||
return m_saved_diagnostics.length ();
|
||||
}
|
||||
saved_diagnostic *get_saved_diagnostic (unsigned idx)
|
||||
{
|
||||
return m_saved_diagnostics[idx];
|
||||
}
|
||||
const saved_diagnostic *get_saved_diagnostic (unsigned idx) const
|
||||
{
|
||||
return m_saved_diagnostics[idx];
|
||||
}
|
||||
|
||||
private:
|
||||
void build_emission_path (const path_builder &pb,
|
||||
const exploded_path &epath,
|
||||
checker_path *emission_path) const;
|
||||
|
||||
void add_event_on_final_node (const path_builder &pb,
|
||||
const exploded_node *final_enode,
|
||||
checker_path *emission_path,
|
||||
interesting_t *interest) const;
|
||||
|
||||
void add_events_for_eedge (const path_builder &pb,
|
||||
const exploded_edge &eedge,
|
||||
checker_path *emission_path,
|
||||
interesting_t *interest) const;
|
||||
|
||||
bool significant_edge_p (const path_builder &pb,
|
||||
const exploded_edge &eedge) const;
|
||||
|
||||
void add_events_for_superedge (const path_builder &pb,
|
||||
const exploded_edge &eedge,
|
||||
checker_path *emission_path) const;
|
||||
|
||||
void prune_path (checker_path *path,
|
||||
const state_machine *sm,
|
||||
const svalue *sval,
|
||||
state_machine::state_t state) const;
|
||||
|
||||
void prune_for_sm_diagnostic (checker_path *path,
|
||||
const state_machine *sm,
|
||||
tree var,
|
||||
state_machine::state_t state) const;
|
||||
void prune_for_sm_diagnostic (checker_path *path,
|
||||
const state_machine *sm,
|
||||
const svalue *sval,
|
||||
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;
|
||||
|
||||
engine *m_eng;
|
||||
auto_delete_vec<saved_diagnostic> m_saved_diagnostics;
|
||||
const int m_verbosity;
|
||||
int m_num_disabled_diagnostics;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_DIAGNOSTIC_MANAGER_H */
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/* The analysis "engine".
|
||||
Copyright (C) 2019-2024 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_ENGINE_H
|
||||
#define GCC_ANALYZER_ENGINE_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
extern void run_checkers ();
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_ENGINE_H */
|
||||
+1044
File diff suppressed because it is too large
Load Diff
+224
@@ -0,0 +1,224 @@
|
||||
/* A graph for exploring trees of feasible paths through the egraph.
|
||||
Copyright (C) 2021-2024 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_FEASIBLE_GRAPH_H
|
||||
#define GCC_ANALYZER_FEASIBLE_GRAPH_H
|
||||
|
||||
#include "analyzer/exploded-graph.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Forward decls. */
|
||||
|
||||
class base_feasible_node;
|
||||
class feasible_node;
|
||||
class infeasible_node;
|
||||
class base_feasible_edge;
|
||||
class feasible_edge;
|
||||
class infeasible_edge;
|
||||
class feasible_graph;
|
||||
class feasible_cluster;
|
||||
|
||||
/* A traits class for feasible_graph. */
|
||||
|
||||
struct fg_traits
|
||||
{
|
||||
typedef base_feasible_node node_t;
|
||||
typedef base_feasible_edge edge_t;
|
||||
typedef feasible_graph graph_t;
|
||||
struct dump_args_t
|
||||
{
|
||||
typedef typename eg_traits::dump_args_t inner_args_t;
|
||||
|
||||
dump_args_t (const inner_args_t &inner_args)
|
||||
: m_inner_args (inner_args)
|
||||
{
|
||||
}
|
||||
|
||||
const inner_args_t &m_inner_args;
|
||||
};
|
||||
typedef feasible_cluster cluster_t;
|
||||
};
|
||||
|
||||
/* Base class of node within a feasible_graph.
|
||||
There can be 0 or more base_feasible_nodes per exploded_node. */
|
||||
|
||||
class base_feasible_node : public dnode<fg_traits>
|
||||
{
|
||||
public:
|
||||
void dump_dot_id (pretty_printer *pp) const;
|
||||
|
||||
const exploded_node *get_inner_node () const { return m_inner_node; }
|
||||
unsigned get_index () const { return m_index; }
|
||||
|
||||
protected:
|
||||
base_feasible_node (const exploded_node *inner_node, unsigned index)
|
||||
: m_inner_node (inner_node), m_index (index)
|
||||
{}
|
||||
|
||||
const exploded_node *m_inner_node;
|
||||
unsigned m_index;
|
||||
};
|
||||
|
||||
/* Subclass of base_feasible_node for a node that is reachable via a
|
||||
feasible path, with a particular state. */
|
||||
|
||||
class feasible_node : public base_feasible_node
|
||||
{
|
||||
public:
|
||||
feasible_node (const exploded_node *inner_node, unsigned index,
|
||||
const feasibility_state &state,
|
||||
unsigned path_length)
|
||||
: base_feasible_node (inner_node, index),
|
||||
m_state (state),
|
||||
m_path_length (path_length)
|
||||
{
|
||||
}
|
||||
|
||||
void dump_dot (graphviz_out *gv,
|
||||
const dump_args_t &args) const final override;
|
||||
|
||||
const feasibility_state &get_state () const { return m_state; }
|
||||
const region_model &get_model () const { return m_state.get_model (); }
|
||||
const auto_sbitmap &get_snodes_visited () const
|
||||
{
|
||||
return m_state.get_snodes_visited ();
|
||||
}
|
||||
|
||||
unsigned get_path_length () const { return m_path_length; }
|
||||
|
||||
bool get_state_at_stmt (const gimple *target_stmt,
|
||||
region_model *out) const;
|
||||
|
||||
private:
|
||||
feasibility_state m_state;
|
||||
unsigned m_path_length;
|
||||
};
|
||||
|
||||
/* Subclass of base_feasible_node for a node that requires following
|
||||
an infeasible edge to reach (and thus terminating this part of the
|
||||
exploration). */
|
||||
|
||||
class infeasible_node : public base_feasible_node
|
||||
{
|
||||
public:
|
||||
infeasible_node (const exploded_node *inner_node, unsigned index,
|
||||
std::unique_ptr<rejected_constraint> rc)
|
||||
: base_feasible_node (inner_node, index),
|
||||
m_rc (std::move (rc))
|
||||
{
|
||||
}
|
||||
|
||||
void dump_dot (graphviz_out *gv,
|
||||
const dump_args_t &args) const final override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<rejected_constraint> m_rc;
|
||||
};
|
||||
|
||||
/* Base class of edge within a feasible_graph. */
|
||||
|
||||
class base_feasible_edge : public dedge<fg_traits>
|
||||
{
|
||||
public:
|
||||
void dump_dot (graphviz_out *gv,
|
||||
const dump_args_t &args) const final override;
|
||||
|
||||
const exploded_edge *get_inner_edge () const { return m_inner_edge; }
|
||||
|
||||
protected:
|
||||
base_feasible_edge (base_feasible_node *src, base_feasible_node *dest,
|
||||
const exploded_edge *inner_edge)
|
||||
: dedge<fg_traits> (src, dest), m_inner_edge (inner_edge)
|
||||
{
|
||||
}
|
||||
|
||||
const exploded_edge *m_inner_edge;
|
||||
};
|
||||
|
||||
/* Subclass of base_feasible_edge for connecting two feasible_nodes. */
|
||||
|
||||
class feasible_edge : public base_feasible_edge
|
||||
{
|
||||
public:
|
||||
feasible_edge (feasible_node *src, feasible_node *dest,
|
||||
const exploded_edge *inner_edge)
|
||||
: base_feasible_edge (src, dest, inner_edge)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/* Subclass of base_feasible_edge for connecting a feasible_node
|
||||
to an infeasible_node (and thus terminating this part of the
|
||||
exploration). */
|
||||
|
||||
class infeasible_edge : public base_feasible_edge
|
||||
{
|
||||
public:
|
||||
infeasible_edge (feasible_node *src, infeasible_node *dest,
|
||||
const exploded_edge *inner_edge)
|
||||
: base_feasible_edge (src, dest, inner_edge)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/* A digraph subclass for exploring trees of feasible paths through
|
||||
the egraph. This is actually a tree.
|
||||
|
||||
The paths within the graph of feasible_nodes express feasible paths
|
||||
through the graph, and it also captures known infeasible edges,
|
||||
which is invaluable for debugging. */
|
||||
|
||||
class feasible_graph : public digraph <fg_traits>
|
||||
{
|
||||
public:
|
||||
feasible_graph ();
|
||||
|
||||
feasible_node *add_node (const exploded_node *enode,
|
||||
const feasibility_state &state,
|
||||
unsigned path_length);
|
||||
|
||||
void add_feasibility_problem (feasible_node *src_fnode,
|
||||
const exploded_edge *eedge,
|
||||
std::unique_ptr<rejected_constraint> rc);
|
||||
|
||||
std::unique_ptr<exploded_path> make_epath (feasible_node *fnode) const;
|
||||
|
||||
void dump_feasible_path (const feasible_node &dst_fnode,
|
||||
const char *filename) const;
|
||||
|
||||
unsigned get_num_infeasible () const { return m_num_infeasible; }
|
||||
|
||||
void log_stats (logger *logger) const;
|
||||
|
||||
private:
|
||||
void dump_feasible_path (const feasible_node &dst_fnode,
|
||||
pretty_printer *pp) const;
|
||||
|
||||
unsigned m_num_infeasible;
|
||||
};
|
||||
|
||||
class feasible_cluster : public cluster <fg_traits>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_FEASIBLE_GRAPH_H */
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/* Sets of function names.
|
||||
Copyright (C) 2019-2024 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_FUNCTION_SET_H
|
||||
#define GCC_ANALYZER_FUNCTION_SET_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A set of names. */
|
||||
|
||||
class function_set
|
||||
{
|
||||
public:
|
||||
/* Construct from a sorted array NAMES of size COUNT. */
|
||||
function_set (const char * const *names, size_t count)
|
||||
: m_names (names), m_count (count)
|
||||
{
|
||||
}
|
||||
|
||||
bool contains_name_p (const char *name) const;
|
||||
bool contains_decl_p (tree fndecl) const;
|
||||
|
||||
void assert_sorted () const;
|
||||
void assert_sane () const;
|
||||
|
||||
private:
|
||||
const char * const *m_names; // must be sorted
|
||||
size_t m_count;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_FUNCTION_SET_H */
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/* Iterator for walking a chain of inlining locations.
|
||||
Copyright (C) 2022-2024 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_INLINING_ITERATOR_H
|
||||
#define GCC_ANALYZER_INLINING_ITERATOR_H
|
||||
|
||||
/* Iterator for walking a chain of inlining locations.
|
||||
|
||||
The fndecls and locations will be traversed from innermost to outermost.
|
||||
For example, given:
|
||||
|
||||
inline void inner (void)
|
||||
{
|
||||
...LOCATION HERE...
|
||||
}
|
||||
void outer (void)
|
||||
{
|
||||
inner (); <-- CALLSITE
|
||||
}
|
||||
|
||||
then the fndecl will be "inner" on the initial iteration, and "outer" on
|
||||
the second (final) iteration.
|
||||
|
||||
Compare with lhd_print_error_function, cp_print_error_function,
|
||||
and optrecord_json_writer::inlining_chain_to_json. */
|
||||
|
||||
class inlining_iterator
|
||||
{
|
||||
public:
|
||||
inlining_iterator (location_t loc)
|
||||
: m_abstract_origin (LOCATION_BLOCK (loc)),
|
||||
m_callsite (UNKNOWN_LOCATION), m_fndecl (NULL),
|
||||
m_next_abstract_origin (NULL)
|
||||
{
|
||||
prepare_iteration ();
|
||||
}
|
||||
|
||||
bool done_p () const { return m_abstract_origin == NULL; }
|
||||
|
||||
void next ()
|
||||
{
|
||||
m_abstract_origin = m_next_abstract_origin;
|
||||
prepare_iteration ();
|
||||
}
|
||||
|
||||
tree get_fndecl () const { return m_fndecl; }
|
||||
location_t get_callsite () const { return m_callsite; }
|
||||
tree get_block () const { return m_abstract_origin; }
|
||||
|
||||
private:
|
||||
void prepare_iteration ()
|
||||
{
|
||||
if (done_p ())
|
||||
return;
|
||||
tree block = m_abstract_origin;
|
||||
m_callsite = BLOCK_SOURCE_LOCATION (block);
|
||||
m_fndecl = NULL;
|
||||
block = BLOCK_SUPERCONTEXT (block);
|
||||
while (block && TREE_CODE (block) == BLOCK
|
||||
&& BLOCK_ABSTRACT_ORIGIN (block))
|
||||
{
|
||||
tree ao = BLOCK_ABSTRACT_ORIGIN (block);
|
||||
if (TREE_CODE (ao) == FUNCTION_DECL)
|
||||
{
|
||||
m_fndecl = ao;
|
||||
break;
|
||||
}
|
||||
else if (TREE_CODE (ao) != BLOCK)
|
||||
break;
|
||||
|
||||
block = BLOCK_SUPERCONTEXT (block);
|
||||
}
|
||||
if (m_fndecl)
|
||||
m_next_abstract_origin = block;
|
||||
else
|
||||
{
|
||||
while (block && TREE_CODE (block) == BLOCK)
|
||||
block = BLOCK_SUPERCONTEXT (block);
|
||||
|
||||
if (block && TREE_CODE (block) == FUNCTION_DECL)
|
||||
m_fndecl = block;
|
||||
m_next_abstract_origin = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
tree m_abstract_origin;
|
||||
location_t m_callsite;
|
||||
tree m_fndecl;
|
||||
tree m_next_abstract_origin;
|
||||
};
|
||||
|
||||
/* A class for fixing up fndecls and stack depths in checker_event, based
|
||||
on inlining records.
|
||||
|
||||
The early inliner runs before the analyzer, which can lead to confusing
|
||||
output.
|
||||
|
||||
Tne base fndecl and depth within a checker_event are from call strings
|
||||
in program_points, which reflect the call strings after inlining.
|
||||
This class lets us offset the depth and fix up the reported fndecl and
|
||||
stack depth to better reflect the user's original code. */
|
||||
|
||||
class inlining_info
|
||||
{
|
||||
public:
|
||||
inlining_info (location_t loc)
|
||||
{
|
||||
inlining_iterator iter (loc);
|
||||
m_inner_fndecl = iter.get_fndecl ();
|
||||
int num_frames = 0;
|
||||
while (!iter.done_p ())
|
||||
{
|
||||
m_outer_fndecl = iter.get_fndecl ();
|
||||
num_frames++;
|
||||
iter.next ();
|
||||
}
|
||||
if (num_frames > 1)
|
||||
m_extra_frames = num_frames - 1;
|
||||
else
|
||||
m_extra_frames = 0;
|
||||
}
|
||||
|
||||
tree get_inner_fndecl () const { return m_inner_fndecl; }
|
||||
int get_extra_frames () const { return m_extra_frames; }
|
||||
|
||||
private:
|
||||
tree m_outer_fndecl;
|
||||
tree m_inner_fndecl;
|
||||
int m_extra_frames;
|
||||
};
|
||||
|
||||
#endif /* GCC_ANALYZER_INLINING_ITERATOR_H */
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/* Support for plugin-supplied behaviors of known functions.
|
||||
Copyright (C) 2022-2024 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_KNOWN_FUNCTION_MANAGER_H
|
||||
#define GCC_ANALYZER_KNOWN_FUNCTION_MANAGER_H
|
||||
|
||||
#include "analyzer/analyzer-logging.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Instances of known_function are registered with the known_function_manager
|
||||
when the analyzer starts.
|
||||
|
||||
The known_function_manager has responsibility for determining which
|
||||
known_function instance (if any) is relevant at a call site, by checking
|
||||
name or id, and by calling known_function::matches_call_types_p to ensure
|
||||
that the known_function's preconditions hold (typically assumptions about
|
||||
types e.g. that "has 3 args, and that arg 0 is of pointer type").
|
||||
|
||||
The known_function subclasses themselves have responsibility for
|
||||
determining the outcome(s) of the call. */
|
||||
|
||||
class known_function_manager : public log_user
|
||||
{
|
||||
public:
|
||||
known_function_manager (logger *logger);
|
||||
~known_function_manager ();
|
||||
|
||||
void add (const char *name, std::unique_ptr<known_function> kf);
|
||||
void add (enum built_in_function name, std::unique_ptr<known_function> kf);
|
||||
void add (enum internal_fn ifn, std::unique_ptr<known_function> kf);
|
||||
|
||||
const known_function *get_match (tree fndecl, const call_details &cd) const;
|
||||
const known_function *get_internal_fn (enum internal_fn) const;
|
||||
|
||||
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.
|
||||
Has ownership of the latter. */
|
||||
hash_map<tree, known_function *> m_map_id_to_kf;
|
||||
|
||||
/* Array of known builtins. */
|
||||
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 */
|
||||
+482
@@ -0,0 +1,482 @@
|
||||
/* Classes for analyzer diagnostics.
|
||||
Copyright (C) 2019-2024 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_PENDING_DIAGNOSTIC_H
|
||||
#define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
|
||||
|
||||
#include "diagnostic-metadata.h"
|
||||
#include "diagnostic-path.h"
|
||||
#include "analyzer/sm.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A bundle of information about things that are of interest to a
|
||||
pending_diagnostic.
|
||||
|
||||
For now, merely the set of regions that are pertinent to the
|
||||
diagnostic, so that we can notify the user about when they
|
||||
were created. */
|
||||
|
||||
struct interesting_t
|
||||
{
|
||||
void add_region_creation (const region *reg);
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool simple) const;
|
||||
|
||||
auto_vec<const region *> m_region_creation;
|
||||
};
|
||||
|
||||
/* Various bundles of information used for generating more precise
|
||||
messages for events within a diagnostic_path, for passing to the
|
||||
various "describe_*" vfuncs of pending_diagnostic. See those
|
||||
for more information. */
|
||||
|
||||
namespace evdesc {
|
||||
|
||||
struct event_desc
|
||||
{
|
||||
event_desc (bool colorize) : m_colorize (colorize) {}
|
||||
|
||||
label_text formatted_print (const char *fmt, ...) const
|
||||
ATTRIBUTE_GCC_DIAG(2,3);
|
||||
|
||||
bool m_colorize;
|
||||
};
|
||||
|
||||
/* For use by pending_diagnostic::describe_state_change. */
|
||||
|
||||
struct state_change : public event_desc
|
||||
{
|
||||
state_change (bool colorize,
|
||||
tree expr,
|
||||
tree origin,
|
||||
state_machine::state_t old_state,
|
||||
state_machine::state_t new_state,
|
||||
diagnostic_event_id_t event_id,
|
||||
const state_change_event &event)
|
||||
: event_desc (colorize),
|
||||
m_expr (expr), m_origin (origin),
|
||||
m_old_state (old_state), m_new_state (new_state),
|
||||
m_event_id (event_id), m_event (event)
|
||||
{}
|
||||
|
||||
bool is_global_p () const { return m_expr == NULL_TREE; }
|
||||
|
||||
tree m_expr;
|
||||
tree m_origin;
|
||||
state_machine::state_t m_old_state;
|
||||
state_machine::state_t m_new_state;
|
||||
diagnostic_event_id_t m_event_id;
|
||||
const state_change_event &m_event;
|
||||
};
|
||||
|
||||
/* For use by pending_diagnostic::describe_call_with_state. */
|
||||
|
||||
struct call_with_state : public event_desc
|
||||
{
|
||||
call_with_state (bool colorize,
|
||||
tree caller_fndecl, tree callee_fndecl,
|
||||
tree expr, state_machine::state_t state)
|
||||
: event_desc (colorize),
|
||||
m_caller_fndecl (caller_fndecl),
|
||||
m_callee_fndecl (callee_fndecl),
|
||||
m_expr (expr),
|
||||
m_state (state)
|
||||
{
|
||||
}
|
||||
|
||||
tree m_caller_fndecl;
|
||||
tree m_callee_fndecl;
|
||||
tree m_expr;
|
||||
state_machine::state_t m_state;
|
||||
};
|
||||
|
||||
/* For use by pending_diagnostic::describe_return_of_state. */
|
||||
|
||||
struct return_of_state : public event_desc
|
||||
{
|
||||
return_of_state (bool colorize,
|
||||
tree caller_fndecl, tree callee_fndecl,
|
||||
state_machine::state_t state)
|
||||
: event_desc (colorize),
|
||||
m_caller_fndecl (caller_fndecl),
|
||||
m_callee_fndecl (callee_fndecl),
|
||||
m_state (state)
|
||||
{
|
||||
}
|
||||
|
||||
tree m_caller_fndecl;
|
||||
tree m_callee_fndecl;
|
||||
state_machine::state_t m_state;
|
||||
};
|
||||
|
||||
/* For use by pending_diagnostic::describe_final_event. */
|
||||
|
||||
struct final_event : public event_desc
|
||||
{
|
||||
final_event (bool colorize,
|
||||
tree expr, state_machine::state_t state,
|
||||
const warning_event &event)
|
||||
: event_desc (colorize),
|
||||
m_expr (expr), m_state (state), m_event (event)
|
||||
{}
|
||||
|
||||
tree m_expr;
|
||||
state_machine::state_t m_state;
|
||||
const warning_event &m_event;
|
||||
};
|
||||
|
||||
} /* end of namespace evdesc */
|
||||
|
||||
/* A bundle of information for use by implementations of the
|
||||
pending_diagnostic::emit vfunc.
|
||||
|
||||
The rich_location will have already been populated with a
|
||||
diagnostic_path. */
|
||||
|
||||
class diagnostic_emission_context
|
||||
{
|
||||
public:
|
||||
diagnostic_emission_context (const saved_diagnostic &sd,
|
||||
rich_location &rich_loc,
|
||||
diagnostic_metadata &metadata,
|
||||
logger *logger)
|
||||
: m_sd (sd),
|
||||
m_rich_loc (rich_loc),
|
||||
m_metadata (metadata),
|
||||
m_logger (logger)
|
||||
{
|
||||
}
|
||||
|
||||
const pending_diagnostic &get_pending_diagnostic () const;
|
||||
|
||||
bool warn (const char *, ...) ATTRIBUTE_GCC_DIAG (2,3);
|
||||
void inform (const char *, ...) ATTRIBUTE_GCC_DIAG (2,3);
|
||||
|
||||
location_t get_location () const { return m_rich_loc.get_loc (); }
|
||||
logger *get_logger () const { return m_logger; }
|
||||
|
||||
void add_cwe (int cwe) { m_metadata.add_cwe (cwe); }
|
||||
void add_rule (const diagnostic_metadata::rule &r)
|
||||
{
|
||||
m_metadata.add_rule (r);
|
||||
}
|
||||
|
||||
private:
|
||||
const saved_diagnostic &m_sd;
|
||||
rich_location &m_rich_loc;
|
||||
diagnostic_metadata &m_metadata;
|
||||
logger *m_logger;
|
||||
};
|
||||
|
||||
/* An abstract base class for capturing information about a diagnostic in
|
||||
a form that is ready to emit at a later point (or be rejected).
|
||||
Each kind of diagnostic will have a concrete subclass of
|
||||
pending_diagnostic.
|
||||
|
||||
Normally, gcc diagnostics are emitted using va_list, which can't be
|
||||
portably stored for later use, so we have to use an "emit" virtual
|
||||
function.
|
||||
|
||||
This class also supports comparison, so that multiple pending_diagnostic
|
||||
instances can be de-duplicated.
|
||||
|
||||
As well as emitting a diagnostic, the class has various "precision of
|
||||
wording" virtual functions, for generating descriptions for events
|
||||
within a diagnostic_path. These are optional, but implementing these
|
||||
allows for more precise wordings than the more generic
|
||||
implementation. */
|
||||
|
||||
class pending_diagnostic
|
||||
{
|
||||
public:
|
||||
virtual ~pending_diagnostic () {}
|
||||
|
||||
/* Vfunc to get the command-line option used when emitting the diagnostic,
|
||||
or zero if there is none.
|
||||
Used by diagnostic_manager for early rejection of diagnostics (to avoid
|
||||
having to generate feasible execution paths for them). */
|
||||
virtual int get_controlling_option () const = 0;
|
||||
|
||||
/* Vfunc to give the diagnostic the chance to terminate the execution
|
||||
path being explored. By default, don't terminate the path. */
|
||||
virtual bool terminate_path_p () const { return false; }
|
||||
|
||||
/* Vfunc for emitting the diagnostic.
|
||||
Return true if a diagnostic is actually emitted. */
|
||||
virtual bool emit (diagnostic_emission_context &) = 0;
|
||||
|
||||
/* Hand-coded RTTI: get an ID for the subclass. */
|
||||
virtual const char *get_kind () const = 0;
|
||||
|
||||
/* A vfunc for identifying "use of uninitialized value". */
|
||||
virtual bool use_of_uninit_p () const { return false; }
|
||||
|
||||
/* Compare for equality with OTHER, which might be of a different
|
||||
subclass. */
|
||||
|
||||
bool equal_p (const pending_diagnostic &other) const
|
||||
{
|
||||
/* Check for pointer equality on the IDs from get_kind. */
|
||||
if (get_kind () != other.get_kind ())
|
||||
return false;
|
||||
/* Call vfunc now we know they have the same ID: */
|
||||
return subclass_equal_p (other);
|
||||
}
|
||||
|
||||
/* A vfunc for testing for equality, where we've already
|
||||
checked they have the same ID. See pending_diagnostic_subclass
|
||||
below for a convenience subclass for implementing this. */
|
||||
virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
|
||||
|
||||
/* Return true if T1 and T2 are "the same" for the purposes of
|
||||
diagnostic deduplication. */
|
||||
static bool same_tree_p (tree t1, tree t2);
|
||||
|
||||
/* Vfunc for fixing up locations, e.g. to avoid unwinding
|
||||
inside specific macros. PRIMARY is true for the primary location
|
||||
for the diagnostic, and FALSE for events in their paths. */
|
||||
virtual location_t fixup_location (location_t loc, bool primary) const;
|
||||
|
||||
/* Precision-of-wording vfunc for describing a critical state change
|
||||
within the diagnostic_path.
|
||||
|
||||
For example, a double-free diagnostic might use the descriptions:
|
||||
- "first 'free' happens here"
|
||||
- "second 'free' happens here"
|
||||
for the pertinent events, whereas a use-after-free might use the
|
||||
descriptions:
|
||||
- "freed here"
|
||||
- "use after free here"
|
||||
Note how in both cases the first event is a "free": the best
|
||||
description to use depends on the diagnostic. */
|
||||
|
||||
virtual label_text describe_state_change (const evdesc::state_change &)
|
||||
{
|
||||
/* Default no-op implementation. */
|
||||
return label_text ();
|
||||
}
|
||||
|
||||
/* Vfunc for implementing diagnostic_event::get_meaning for
|
||||
state_change_event. */
|
||||
virtual diagnostic_event::meaning
|
||||
get_meaning_for_state_change (const evdesc::state_change &) const
|
||||
{
|
||||
/* Default no-op implementation. */
|
||||
return diagnostic_event::meaning ();
|
||||
}
|
||||
|
||||
/* Precision-of-wording vfunc for describing an interprocedural call
|
||||
carrying critial state for the diagnostic, from caller to callee.
|
||||
|
||||
For example a double-free diagnostic might use:
|
||||
- "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
|
||||
to make it clearer how the freed value moves from caller to
|
||||
callee. */
|
||||
|
||||
virtual label_text describe_call_with_state (const evdesc::call_with_state &)
|
||||
{
|
||||
/* Default no-op implementation. */
|
||||
return label_text ();
|
||||
}
|
||||
|
||||
/* Precision-of-wording vfunc for describing an interprocedural return
|
||||
within the diagnostic_path that carries critial state for the
|
||||
diagnostic, from callee back to caller.
|
||||
|
||||
For example, a deref-of-unchecked-malloc diagnostic might use:
|
||||
- "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
|
||||
to make it clearer how the unchecked value moves from callee
|
||||
back to caller. */
|
||||
|
||||
virtual label_text describe_return_of_state (const evdesc::return_of_state &)
|
||||
{
|
||||
/* Default no-op implementation. */
|
||||
return label_text ();
|
||||
}
|
||||
|
||||
/* Precision-of-wording vfunc for describing the final event within a
|
||||
diagnostic_path.
|
||||
|
||||
For example a double-free diagnostic might use:
|
||||
- "second 'free' here; first 'free' was at (3)"
|
||||
and a use-after-free might use
|
||||
- "use after 'free' here; memory was freed at (2)". */
|
||||
|
||||
virtual label_text describe_final_event (const evdesc::final_event &)
|
||||
{
|
||||
/* Default no-op implementation. */
|
||||
return label_text ();
|
||||
}
|
||||
|
||||
/* End of precision-of-wording vfuncs. */
|
||||
|
||||
/* Vfunc for adding a function_entry_event to a checker_path, so that e.g.
|
||||
the infinite recursion diagnostic can add a custom event subclass
|
||||
that annotates recursively entering a function. */
|
||||
|
||||
virtual void
|
||||
add_function_entry_event (const exploded_edge &eedge,
|
||||
checker_path *emission_path);
|
||||
|
||||
/* Vfunc for extending/overriding creation of the events for an
|
||||
exploded_edge that corresponds to a superedge, allowing for custom
|
||||
events to be created that are pertinent to a particular
|
||||
pending_diagnostic subclass.
|
||||
|
||||
For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
|
||||
custom event showing when the pertinent stack frame is popped
|
||||
(and thus the point at which the jmp_buf becomes invalid). */
|
||||
|
||||
virtual bool maybe_add_custom_events_for_superedge (const exploded_edge &,
|
||||
checker_path *)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Vfunc for adding a call_event to a checker_path, so that e.g.
|
||||
the varargs diagnostics can add a custom event subclass that annotates
|
||||
the variadic arguments. */
|
||||
virtual void add_call_event (const exploded_edge &,
|
||||
checker_path *);
|
||||
|
||||
/* Vfunc for adding any events for the creation of regions identified
|
||||
by the mark_interesting_stuff vfunc.
|
||||
See the comment for class region_creation_event. */
|
||||
virtual void add_region_creation_events (const region *reg,
|
||||
tree capacity,
|
||||
const event_loc_info &loc_info,
|
||||
checker_path &emission_path);
|
||||
|
||||
/* Vfunc for adding the final warning_event to a checker_path, so that e.g.
|
||||
the infinite recursion diagnostic can have its diagnostic appear at
|
||||
the callsite, but the final event in the path be at the entrypoint
|
||||
of the called function. */
|
||||
virtual void add_final_event (const state_machine *sm,
|
||||
const exploded_node *enode,
|
||||
const gimple *stmt,
|
||||
tree var, state_machine::state_t state,
|
||||
checker_path *emission_path);
|
||||
|
||||
/* Vfunc for determining that this pending_diagnostic supercedes OTHER,
|
||||
and that OTHER should therefore not be emitted.
|
||||
They have already been tested for being at the same stmt. */
|
||||
|
||||
virtual bool
|
||||
supercedes_p (const pending_diagnostic &other ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Vfunc for registering additional information of interest to this
|
||||
diagnostic. */
|
||||
|
||||
virtual void mark_interesting_stuff (interesting_t *)
|
||||
{
|
||||
/* Default no-op implementation. */
|
||||
}
|
||||
|
||||
/* Vfunc to give diagnostic subclasses the opportunity to reject diagnostics
|
||||
by imposing their own additional feasibility checks on the path to a
|
||||
given feasible_node. */
|
||||
virtual bool check_valid_fpath_p (const feasible_node &,
|
||||
const gimple *) const
|
||||
{
|
||||
/* Default implementation: accept this path. */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Vfunc for use in SARIF output to give pending_diagnostic subclasses
|
||||
the opportunity to add diagnostic-specific properties to the SARIF
|
||||
"result" object for the diagnostic.
|
||||
This is intended for use when debugging a diagnostic. */
|
||||
virtual void maybe_add_sarif_properties (sarif_object &/*result_obj*/) const
|
||||
{
|
||||
/* Default no-op implementation. */
|
||||
}
|
||||
};
|
||||
|
||||
/* A template to make it easier to make subclasses of pending_diagnostic.
|
||||
|
||||
This uses the curiously-recurring template pattern, to implement
|
||||
pending_diagnostic::subclass_equal_p by casting and calling
|
||||
the operator==
|
||||
|
||||
This assumes that BASE_OTHER has already been checked to have
|
||||
been of the same subclass (which pending_diagnostic::equal_p does). */
|
||||
|
||||
template <class Subclass>
|
||||
class pending_diagnostic_subclass : public pending_diagnostic
|
||||
{
|
||||
public:
|
||||
bool subclass_equal_p (const pending_diagnostic &base_other) const
|
||||
final override
|
||||
{
|
||||
const Subclass &other = (const Subclass &)base_other;
|
||||
return *(const Subclass*)this == other;
|
||||
}
|
||||
};
|
||||
|
||||
/* An abstract base class for capturing additional notes that are to be
|
||||
emitted with a diagnostic. */
|
||||
|
||||
class pending_note
|
||||
{
|
||||
public:
|
||||
virtual ~pending_note () {}
|
||||
|
||||
/* Hand-coded RTTI: get an ID for the subclass. */
|
||||
virtual const char *get_kind () const = 0;
|
||||
|
||||
/* Vfunc for emitting the note. */
|
||||
virtual void emit () const = 0;
|
||||
|
||||
bool equal_p (const pending_note &other) const
|
||||
{
|
||||
/* Check for pointer equality on the IDs from get_kind. */
|
||||
if (get_kind () != other.get_kind ())
|
||||
return false;
|
||||
/* Call vfunc now we know they have the same ID: */
|
||||
return subclass_equal_p (other);
|
||||
}
|
||||
|
||||
/* A vfunc for testing for equality, where we've already
|
||||
checked they have the same ID. See pending_note_subclass
|
||||
below for a convenience subclass for implementing this. */
|
||||
virtual bool subclass_equal_p (const pending_note &other) const = 0;
|
||||
};
|
||||
|
||||
/* Analogous to pending_diagnostic_subclass, but for pending_note. */
|
||||
|
||||
template <class Subclass>
|
||||
class pending_note_subclass : public pending_note
|
||||
{
|
||||
public:
|
||||
bool subclass_equal_p (const pending_note &base_other) const
|
||||
final override
|
||||
{
|
||||
const Subclass &other = (const Subclass &)base_other;
|
||||
return *(const Subclass*)this == other;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
/* Classes for representing locations within the program.
|
||||
Copyright (C) 2019-2024 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_PROGRAM_POINT_H
|
||||
#define GCC_ANALYZER_PROGRAM_POINT_H
|
||||
|
||||
#include "pretty-print.h"
|
||||
#include "analyzer/call-string.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
class exploded_graph;
|
||||
|
||||
/* An enum for distinguishing the various kinds of program_point. */
|
||||
|
||||
enum point_kind {
|
||||
/* A "fake" node which has edges to all entrypoints. */
|
||||
PK_ORIGIN,
|
||||
|
||||
PK_BEFORE_SUPERNODE,
|
||||
PK_BEFORE_STMT,
|
||||
PK_AFTER_SUPERNODE,
|
||||
|
||||
/* Special values used for hash_map: */
|
||||
PK_EMPTY,
|
||||
PK_DELETED,
|
||||
|
||||
NUM_POINT_KINDS
|
||||
};
|
||||
|
||||
extern const char *point_kind_to_string (enum point_kind pk);
|
||||
|
||||
class format
|
||||
{
|
||||
public:
|
||||
format (bool newlines) : m_newlines (newlines) {}
|
||||
|
||||
void spacer (pretty_printer *pp) const
|
||||
{
|
||||
if (m_newlines)
|
||||
pp_newline (pp);
|
||||
else
|
||||
pp_space (pp);
|
||||
}
|
||||
|
||||
bool m_newlines;
|
||||
};
|
||||
|
||||
/* A class for representing a location within the program, without
|
||||
interprocedural information.
|
||||
|
||||
This represents a fine-grained location within the supergraph (or
|
||||
within one of its nodes). */
|
||||
|
||||
class function_point
|
||||
{
|
||||
public:
|
||||
function_point (const supernode *supernode,
|
||||
const superedge *from_edge,
|
||||
unsigned stmt_idx,
|
||||
enum point_kind kind);
|
||||
|
||||
void print (pretty_printer *pp, const format &f) const;
|
||||
void print_source_line (pretty_printer *pp) const;
|
||||
void dump () const;
|
||||
|
||||
hashval_t hash () const;
|
||||
bool operator== (const function_point &other) const
|
||||
{
|
||||
return (m_supernode == other.m_supernode
|
||||
&& m_from_edge == other.m_from_edge
|
||||
&& m_stmt_idx == other.m_stmt_idx
|
||||
&& m_kind == other.m_kind);
|
||||
}
|
||||
|
||||
/* Accessors. */
|
||||
|
||||
const supernode *get_supernode () const { return m_supernode; }
|
||||
function *get_function () const;
|
||||
const gimple *get_stmt () const;
|
||||
location_t get_location () const;
|
||||
enum point_kind get_kind () const { return m_kind; }
|
||||
const superedge *get_from_edge () const
|
||||
{
|
||||
return m_from_edge;
|
||||
}
|
||||
unsigned get_stmt_idx () const
|
||||
{
|
||||
gcc_assert (m_kind == PK_BEFORE_STMT);
|
||||
return m_stmt_idx;
|
||||
}
|
||||
|
||||
bool final_stmt_p () const;
|
||||
|
||||
/* Factory functions for making various kinds of program_point. */
|
||||
|
||||
static function_point from_function_entry (const supergraph &sg,
|
||||
const function &fun);
|
||||
|
||||
static function_point before_supernode (const supernode *supernode,
|
||||
const superedge *from_edge);
|
||||
|
||||
static function_point before_stmt (const supernode *supernode,
|
||||
unsigned stmt_idx)
|
||||
{
|
||||
return function_point (supernode, NULL, stmt_idx, PK_BEFORE_STMT);
|
||||
}
|
||||
|
||||
static function_point after_supernode (const supernode *supernode)
|
||||
{
|
||||
return function_point (supernode, NULL, 0, PK_AFTER_SUPERNODE);
|
||||
}
|
||||
|
||||
/* Support for hash_map. */
|
||||
|
||||
static function_point empty ()
|
||||
{
|
||||
return function_point (NULL, NULL, 0, PK_EMPTY);
|
||||
}
|
||||
static function_point deleted ()
|
||||
{
|
||||
return function_point (NULL, NULL, 0, PK_DELETED);
|
||||
}
|
||||
|
||||
static int cmp_within_supernode_1 (const function_point &point_a,
|
||||
const function_point &point_b);
|
||||
static int cmp_within_supernode (const function_point &point_a,
|
||||
const function_point &point_b);
|
||||
static int cmp (const function_point &point_a,
|
||||
const function_point &point_b);
|
||||
static int cmp_ptr (const void *p1, const void *p2);
|
||||
|
||||
/* For before_stmt, go to next stmt. */
|
||||
void next_stmt ();
|
||||
|
||||
function_point get_next () const;
|
||||
|
||||
private:
|
||||
const supernode *m_supernode;
|
||||
|
||||
/* For PK_BEFORE_SUPERNODE, and only for CFG edges. */
|
||||
const superedge *m_from_edge;
|
||||
|
||||
/* Only for PK_BEFORE_STMT. */
|
||||
unsigned m_stmt_idx;
|
||||
|
||||
enum point_kind m_kind;
|
||||
};
|
||||
|
||||
/* A class for representing a location within the program, including
|
||||
interprocedural information.
|
||||
|
||||
This represents a fine-grained location within the supergraph (or
|
||||
within one of its nodes), along with a call string giving the
|
||||
interprocedural context. */
|
||||
|
||||
class program_point
|
||||
{
|
||||
public:
|
||||
program_point (const function_point &fn_point,
|
||||
const call_string &call_string)
|
||||
: m_function_point (fn_point),
|
||||
m_call_string (&call_string)
|
||||
{
|
||||
}
|
||||
|
||||
void print (pretty_printer *pp, const format &f) const;
|
||||
void dump () const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
hashval_t hash () const;
|
||||
bool operator== (const program_point &other) const
|
||||
{
|
||||
return (m_function_point == other.m_function_point
|
||||
&& m_call_string == other.m_call_string);
|
||||
}
|
||||
bool operator!= (const program_point &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/* Accessors. */
|
||||
|
||||
const function_point &get_function_point () const { return m_function_point; }
|
||||
const call_string &get_call_string () const { return *m_call_string; }
|
||||
|
||||
const supernode *get_supernode () const
|
||||
{
|
||||
return m_function_point.get_supernode ();
|
||||
}
|
||||
function *get_function () const
|
||||
{
|
||||
return m_function_point.get_function ();
|
||||
}
|
||||
function *get_function_at_depth (unsigned depth) const;
|
||||
tree get_fndecl () const
|
||||
{
|
||||
gcc_assert (get_kind () != PK_ORIGIN);
|
||||
return get_function ()->decl;
|
||||
}
|
||||
const gimple *get_stmt () const
|
||||
{
|
||||
return m_function_point.get_stmt ();
|
||||
}
|
||||
location_t get_location () const
|
||||
{
|
||||
return m_function_point.get_location ();
|
||||
}
|
||||
enum point_kind get_kind () const
|
||||
{
|
||||
return m_function_point.get_kind ();
|
||||
}
|
||||
const superedge *get_from_edge () const
|
||||
{
|
||||
return m_function_point.get_from_edge ();
|
||||
}
|
||||
unsigned get_stmt_idx () const
|
||||
{
|
||||
return m_function_point.get_stmt_idx ();
|
||||
}
|
||||
|
||||
/* Get the number of frames we expect at this program point.
|
||||
This will be one more than the length of the call_string
|
||||
(which stores the parent callsites), apart from the origin
|
||||
node, which doesn't have any frames. */
|
||||
int get_stack_depth () const
|
||||
{
|
||||
if (get_kind () == PK_ORIGIN)
|
||||
return 0;
|
||||
return get_call_string ().length () + 1;
|
||||
}
|
||||
|
||||
/* Factory functions for making various kinds of program_point. */
|
||||
static program_point origin (const region_model_manager &mgr);
|
||||
static program_point from_function_entry (const region_model_manager &mgr,
|
||||
const supergraph &sg,
|
||||
const function &fun);
|
||||
|
||||
static program_point before_supernode (const supernode *supernode,
|
||||
const superedge *from_edge,
|
||||
const call_string &call_string)
|
||||
{
|
||||
return program_point (function_point::before_supernode (supernode,
|
||||
from_edge),
|
||||
call_string);
|
||||
}
|
||||
|
||||
static program_point before_stmt (const supernode *supernode,
|
||||
unsigned stmt_idx,
|
||||
const call_string &call_string)
|
||||
{
|
||||
return program_point (function_point::before_stmt (supernode, stmt_idx),
|
||||
call_string);
|
||||
}
|
||||
|
||||
static program_point after_supernode (const supernode *supernode,
|
||||
const call_string &call_string)
|
||||
{
|
||||
return program_point (function_point::after_supernode (supernode),
|
||||
call_string);
|
||||
}
|
||||
|
||||
/* Support for hash_map. */
|
||||
|
||||
static program_point empty ()
|
||||
{
|
||||
return program_point (function_point::empty ());
|
||||
}
|
||||
static program_point deleted ()
|
||||
{
|
||||
return program_point (function_point::deleted ());
|
||||
}
|
||||
|
||||
bool on_edge (exploded_graph &eg, const superedge *succ);
|
||||
void push_to_call_stack (const supernode *caller, const supernode *callee);
|
||||
void pop_from_call_stack ();
|
||||
void validate () const;
|
||||
|
||||
/* For before_stmt, go to next stmt. */
|
||||
void next_stmt () { m_function_point.next_stmt (); }
|
||||
|
||||
program_point get_next () const;
|
||||
|
||||
static bool effectively_intraprocedural_p (const program_point &point_a,
|
||||
const program_point &point_b);
|
||||
|
||||
private:
|
||||
program_point (const function_point &fn_point)
|
||||
: m_function_point (fn_point),
|
||||
m_call_string (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
function_point m_function_point;
|
||||
const call_string *m_call_string;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_PROGRAM_POINT_H */
|
||||
+331
@@ -0,0 +1,331 @@
|
||||
/* Classes for representing the state of interest at a given path of analysis.
|
||||
Copyright (C) 2019-2024 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_PROGRAM_STATE_H
|
||||
#define GCC_ANALYZER_PROGRAM_STATE_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Data shared by all program_state instances. */
|
||||
|
||||
class extrinsic_state
|
||||
{
|
||||
public:
|
||||
extrinsic_state (auto_delete_vec <state_machine> &checkers,
|
||||
engine *eng,
|
||||
logger *logger = NULL)
|
||||
: m_checkers (checkers), m_logger (logger), m_engine (eng)
|
||||
{
|
||||
}
|
||||
|
||||
const state_machine &get_sm (int idx) const
|
||||
{
|
||||
return *m_checkers[idx];
|
||||
}
|
||||
|
||||
const char *get_name (int idx) const
|
||||
{
|
||||
return m_checkers[idx]->get_name ();
|
||||
}
|
||||
|
||||
unsigned get_num_checkers () const { return m_checkers.length (); }
|
||||
|
||||
logger *get_logger () const { return m_logger; }
|
||||
|
||||
void dump_to_pp (pretty_printer *pp) const;
|
||||
void dump_to_file (FILE *outf) const;
|
||||
void dump () const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
engine *get_engine () const { return m_engine; }
|
||||
region_model_manager *get_model_manager () const;
|
||||
|
||||
bool get_sm_idx_by_name (const char *name, unsigned *out) const;
|
||||
|
||||
private:
|
||||
/* The state machines. */
|
||||
auto_delete_vec <state_machine> &m_checkers;
|
||||
|
||||
logger *m_logger;
|
||||
engine *m_engine;
|
||||
};
|
||||
|
||||
/* Map from svalue * to state machine state, also capturing the origin of
|
||||
each state. */
|
||||
|
||||
class sm_state_map
|
||||
{
|
||||
public:
|
||||
/* An entry in the hash_map. */
|
||||
struct entry_t
|
||||
{
|
||||
/* Default ctor needed by hash_map::empty. */
|
||||
entry_t ()
|
||||
: m_state (0), m_origin (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
entry_t (state_machine::state_t state,
|
||||
const svalue *origin)
|
||||
: m_state (state), m_origin (origin)
|
||||
{}
|
||||
|
||||
bool operator== (const entry_t &other) const
|
||||
{
|
||||
return (m_state == other.m_state
|
||||
&& m_origin == other.m_origin);
|
||||
}
|
||||
bool operator!= (const entry_t &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
static int cmp (const entry_t &entry_a, const entry_t &entry_b);
|
||||
|
||||
state_machine::state_t m_state;
|
||||
const svalue *m_origin;
|
||||
};
|
||||
typedef hash_map <const svalue *, entry_t> map_t;
|
||||
typedef map_t::iterator iterator_t;
|
||||
|
||||
sm_state_map (const state_machine &sm);
|
||||
|
||||
sm_state_map *clone () const;
|
||||
|
||||
void print (const region_model *model,
|
||||
bool simple, bool multiline,
|
||||
pretty_printer *pp) const;
|
||||
void dump (bool simple) const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool is_empty_p () const;
|
||||
|
||||
hashval_t hash () const;
|
||||
|
||||
bool operator== (const sm_state_map &other) const;
|
||||
bool operator!= (const sm_state_map &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
state_machine::state_t get_state (const svalue *sval,
|
||||
const extrinsic_state &ext_state) const;
|
||||
const svalue *get_origin (const svalue *sval,
|
||||
const extrinsic_state &ext_state) const;
|
||||
|
||||
void set_state (region_model *model,
|
||||
const svalue *sval,
|
||||
state_machine::state_t state,
|
||||
const svalue *origin,
|
||||
const extrinsic_state &ext_state);
|
||||
bool set_state (const equiv_class &ec,
|
||||
state_machine::state_t state,
|
||||
const svalue *origin,
|
||||
const extrinsic_state &ext_state);
|
||||
bool impl_set_state (const svalue *sval,
|
||||
state_machine::state_t state,
|
||||
const svalue *origin,
|
||||
const extrinsic_state &ext_state);
|
||||
void clear_any_state (const svalue *sval);
|
||||
void clear_all_per_svalue_state ();
|
||||
|
||||
void set_global_state (state_machine::state_t state);
|
||||
state_machine::state_t get_global_state () const;
|
||||
|
||||
void on_svalue_leak (const svalue *sval,
|
||||
impl_region_model_context *ctxt);
|
||||
void on_liveness_change (const svalue_set &live_svalues,
|
||||
const region_model *model,
|
||||
const extrinsic_state &ext_state,
|
||||
impl_region_model_context *ctxt);
|
||||
|
||||
void on_unknown_change (const svalue *sval,
|
||||
bool is_mutable,
|
||||
const extrinsic_state &ext_state);
|
||||
|
||||
void purge_state_involving (const svalue *sval,
|
||||
const extrinsic_state &ext_state);
|
||||
|
||||
iterator_t begin () const { return m_map.begin (); }
|
||||
iterator_t end () const { return m_map.end (); }
|
||||
size_t elements () const { return m_map.elements (); }
|
||||
|
||||
static int cmp (const sm_state_map &smap_a, const sm_state_map &smap_b);
|
||||
|
||||
static const svalue *
|
||||
canonicalize_svalue (const svalue *sval, const extrinsic_state &ext_state);
|
||||
|
||||
bool replay_call_summary (call_summary_replay &r,
|
||||
const sm_state_map &summary);
|
||||
|
||||
bool can_merge_with_p (const sm_state_map &other,
|
||||
const state_machine &sm,
|
||||
const extrinsic_state &ext_state,
|
||||
sm_state_map **out) const;
|
||||
|
||||
private:
|
||||
const state_machine &m_sm;
|
||||
map_t m_map;
|
||||
state_machine::state_t m_global_state;
|
||||
};
|
||||
|
||||
/* A class for representing the state of interest at a given path of
|
||||
analysis.
|
||||
|
||||
Currently this is a combination of:
|
||||
(a) a region_model, giving:
|
||||
(a.1) a hierarchy of memory regions
|
||||
(a.2) values for the regions
|
||||
(a.3) inequalities between values
|
||||
(b) sm_state_maps per state machine, giving a sparse mapping of
|
||||
values to states. */
|
||||
|
||||
class program_state
|
||||
{
|
||||
public:
|
||||
program_state (const extrinsic_state &ext_state);
|
||||
program_state (const program_state &other);
|
||||
program_state& operator= (const program_state &other);
|
||||
program_state (program_state &&other);
|
||||
~program_state ();
|
||||
|
||||
hashval_t hash () const;
|
||||
bool operator== (const program_state &other) const;
|
||||
bool operator!= (const program_state &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void print (const extrinsic_state &ext_state,
|
||||
pretty_printer *pp) const;
|
||||
|
||||
void dump_to_pp (const extrinsic_state &ext_state, bool simple,
|
||||
bool multiline, pretty_printer *pp) const;
|
||||
void dump_to_file (const extrinsic_state &ext_state, bool simple,
|
||||
bool multiline, FILE *outf) const;
|
||||
void dump (const extrinsic_state &ext_state, bool simple) const;
|
||||
|
||||
json::object *to_json (const extrinsic_state &ext_state) const;
|
||||
|
||||
void push_frame (const extrinsic_state &ext_state, const function &fun);
|
||||
const function * get_current_function () const;
|
||||
|
||||
void push_call (exploded_graph &eg,
|
||||
exploded_node *enode,
|
||||
const gcall *call_stmt,
|
||||
uncertainty_t *uncertainty);
|
||||
|
||||
void returning_call (exploded_graph &eg,
|
||||
exploded_node *enode,
|
||||
const gcall *call_stmt,
|
||||
uncertainty_t *uncertainty);
|
||||
|
||||
|
||||
bool on_edge (exploded_graph &eg,
|
||||
exploded_node *enode,
|
||||
const superedge *succ,
|
||||
uncertainty_t *uncertainty);
|
||||
|
||||
program_state prune_for_point (exploded_graph &eg,
|
||||
const program_point &point,
|
||||
exploded_node *enode_for_diag,
|
||||
uncertainty_t *uncertainty) const;
|
||||
|
||||
tree get_representative_tree (const svalue *sval) const;
|
||||
|
||||
bool can_purge_p (const extrinsic_state &ext_state,
|
||||
const svalue *sval) const
|
||||
{
|
||||
/* Don't purge vars that have non-purgeable sm state, to avoid
|
||||
generating false "leak" complaints. */
|
||||
int i;
|
||||
sm_state_map *smap;
|
||||
FOR_EACH_VEC_ELT (m_checker_states, i, smap)
|
||||
{
|
||||
const state_machine &sm = ext_state.get_sm (i);
|
||||
if (!sm.can_purge_p (smap->get_state (sval, ext_state)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool can_purge_base_region_p (const extrinsic_state &ext_state,
|
||||
const region *base_reg) const;
|
||||
|
||||
bool can_merge_with_p (const program_state &other,
|
||||
const extrinsic_state &ext_state,
|
||||
const program_point &point,
|
||||
program_state *out) const;
|
||||
|
||||
void validate (const extrinsic_state &ext_state) const;
|
||||
|
||||
static void detect_leaks (const program_state &src_state,
|
||||
const program_state &dest_state,
|
||||
const svalue *extra_sval,
|
||||
const extrinsic_state &ext_state,
|
||||
region_model_context *ctxt);
|
||||
|
||||
bool replay_call_summary (call_summary_replay &r,
|
||||
const program_state &summary);
|
||||
|
||||
void impl_call_analyzer_dump_state (const gcall *call,
|
||||
const extrinsic_state &ext_state,
|
||||
region_model_context *ctxt);
|
||||
|
||||
/* TODO: lose the pointer here (const-correctness issues?). */
|
||||
region_model *m_region_model;
|
||||
auto_delete_vec<sm_state_map> m_checker_states;
|
||||
|
||||
/* If false, then don't attempt to explore further states along this path.
|
||||
For use in "handling" lvalues for tree codes we haven't yet
|
||||
implemented. */
|
||||
bool m_valid;
|
||||
};
|
||||
|
||||
/* An abstract base class for use with for_each_state_change. */
|
||||
|
||||
class state_change_visitor
|
||||
{
|
||||
public:
|
||||
virtual ~state_change_visitor () {}
|
||||
|
||||
/* Return true for early exit, false to keep iterating. */
|
||||
virtual bool on_global_state_change (const state_machine &sm,
|
||||
state_machine::state_t src_sm_val,
|
||||
state_machine::state_t dst_sm_val) = 0;
|
||||
|
||||
/* Return true for early exit, false to keep iterating. */
|
||||
virtual bool on_state_change (const state_machine &sm,
|
||||
state_machine::state_t src_sm_val,
|
||||
state_machine::state_t dst_sm_val,
|
||||
const svalue *dst_sval,
|
||||
const svalue *dst_origin_sval) = 0;
|
||||
};
|
||||
|
||||
extern bool for_each_state_change (const program_state &src_state,
|
||||
const program_state &dst_state,
|
||||
const extrinsic_state &ext_state,
|
||||
state_change_visitor *visitor);
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_PROGRAM_STATE_H */
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/* Symbolic offsets and ranges.
|
||||
Copyright (C) 2023-2024 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;
|
||||
|
||||
json::value *to_json () 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;
|
||||
|
||||
json::value *to_json () 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 */
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/* Digraph reachability.
|
||||
Copyright (C) 2020-2024 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_REACHABILITY_H
|
||||
#define GCC_ANALYZER_REACHABILITY_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* The set of nodes from which a target node in a digraph can be reached. */
|
||||
// TODO(stage1): move to gcc
|
||||
|
||||
template <typename GraphTraits>
|
||||
class reachability
|
||||
{
|
||||
public:
|
||||
typedef typename GraphTraits::graph_t graph_t;
|
||||
typedef typename GraphTraits::node_t node_t;
|
||||
typedef typename GraphTraits::edge_t edge_t;
|
||||
|
||||
reachability (const graph_t &graph,
|
||||
const node_t *target_node)
|
||||
: m_indices (graph.m_nodes.length ())
|
||||
{
|
||||
bitmap_clear (m_indices);
|
||||
auto_vec<const node_t *> worklist;
|
||||
worklist.safe_push (target_node);
|
||||
bitmap_set_bit (m_indices, target_node->m_index);
|
||||
|
||||
while (worklist.length () > 0)
|
||||
{
|
||||
const node_t *next = worklist.pop ();
|
||||
unsigned i;
|
||||
edge_t *pred;
|
||||
FOR_EACH_VEC_ELT (next->m_preds, i, pred)
|
||||
{
|
||||
if (!reachable_from_p (pred->m_src))
|
||||
{
|
||||
worklist.safe_push (pred->m_src);
|
||||
bitmap_set_bit (m_indices, pred->m_src->m_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool reachable_from_p (const node_t *src_node) const
|
||||
{
|
||||
return bitmap_bit_p (m_indices, src_node->m_index);
|
||||
}
|
||||
|
||||
private:
|
||||
/* The nodes that can reach the target. */
|
||||
auto_sbitmap m_indices;
|
||||
};
|
||||
|
||||
//TODO: selftests for reachability
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_REACHABILITY_H */
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/* Declaration of class record_layout.
|
||||
Copyright (C) 2022-2024 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_RECORD_LAYOUT_H
|
||||
#define GCC_ANALYZER_RECORD_LAYOUT_H
|
||||
|
||||
#include "analyzer/store.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Information of the layout of a RECORD_TYPE, capturing it as a vector
|
||||
of items, where each item is either a field or padding. */
|
||||
|
||||
class record_layout
|
||||
{
|
||||
public:
|
||||
/* An item within a record; either a field, or padding after a field. */
|
||||
struct item
|
||||
{
|
||||
public:
|
||||
item (const bit_range &br,
|
||||
tree field,
|
||||
bool is_padding)
|
||||
: m_bit_range (br),
|
||||
m_field (field),
|
||||
m_is_padding (is_padding)
|
||||
{
|
||||
}
|
||||
|
||||
bit_offset_t get_start_bit_offset () const
|
||||
{
|
||||
return m_bit_range.get_start_bit_offset ();
|
||||
}
|
||||
bit_offset_t get_next_bit_offset () const
|
||||
{
|
||||
return m_bit_range.get_next_bit_offset ();
|
||||
}
|
||||
|
||||
bool contains_p (bit_offset_t offset) const
|
||||
{
|
||||
return m_bit_range.contains_p (offset);
|
||||
}
|
||||
|
||||
void dump_to_pp (pretty_printer *pp) const
|
||||
{
|
||||
if (m_is_padding)
|
||||
pp_printf (pp, "padding after %qD", m_field);
|
||||
else
|
||||
pp_printf (pp, "%qD", m_field);
|
||||
pp_string (pp, ", ");
|
||||
m_bit_range.dump_to_pp (pp);
|
||||
}
|
||||
|
||||
bit_range m_bit_range;
|
||||
tree m_field;
|
||||
bool m_is_padding;
|
||||
};
|
||||
|
||||
record_layout (tree record_type);
|
||||
|
||||
void dump_to_pp (pretty_printer *pp) const;
|
||||
DEBUG_FUNCTION void dump () const;
|
||||
|
||||
const record_layout::item *get_item_at (bit_offset_t offset) const;
|
||||
|
||||
private:
|
||||
void maybe_pad_to (bit_offset_t next_offset);
|
||||
|
||||
auto_vec<item> m_items;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_RECORD_LAYOUT_H */
|
||||
+330
@@ -0,0 +1,330 @@
|
||||
/* Consolidation of svalues and regions.
|
||||
Copyright (C) 2020-2024 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_REGION_MODEL_MANAGER_H
|
||||
#define GCC_ANALYZER_REGION_MODEL_MANAGER_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A class responsible for owning and consolidating region and svalue
|
||||
instances.
|
||||
region and svalue instances are immutable as far as clients are
|
||||
concerned, so they are provided as "const" ptrs. */
|
||||
|
||||
class region_model_manager
|
||||
{
|
||||
public:
|
||||
region_model_manager (logger *logger = NULL);
|
||||
~region_model_manager ();
|
||||
|
||||
unsigned get_num_symbols () const { return m_next_symbol_id; }
|
||||
unsigned alloc_symbol_id () { return m_next_symbol_id++; }
|
||||
|
||||
/* call_string consolidation. */
|
||||
const call_string &get_empty_call_string () const
|
||||
{
|
||||
return m_empty_call_string;
|
||||
}
|
||||
|
||||
/* svalue consolidation. */
|
||||
const svalue *get_or_create_constant_svalue (tree type, tree cst_expr);
|
||||
const svalue *get_or_create_constant_svalue (tree cst_expr);
|
||||
const svalue *get_or_create_int_cst (tree type, const poly_wide_int_ref &cst);
|
||||
const svalue *get_or_create_null_ptr (tree pointer_type);
|
||||
const svalue *get_or_create_unknown_svalue (tree type);
|
||||
const svalue *get_or_create_setjmp_svalue (const setjmp_record &r,
|
||||
tree type);
|
||||
const svalue *get_or_create_poisoned_svalue (enum poison_kind kind,
|
||||
tree type);
|
||||
const svalue *get_or_create_initial_value (const region *reg,
|
||||
bool check_poisoned = true);
|
||||
const svalue *get_ptr_svalue (tree ptr_type, const region *pointee);
|
||||
const svalue *get_or_create_unaryop (tree type, enum tree_code op,
|
||||
const svalue *arg);
|
||||
const svalue *get_or_create_cast (tree type, const svalue *arg);
|
||||
const svalue *get_or_create_binop (tree type,
|
||||
enum tree_code op,
|
||||
const svalue *arg0, const svalue *arg1);
|
||||
const svalue *get_or_create_sub_svalue (tree type,
|
||||
const svalue *parent_svalue,
|
||||
const region *subregion);
|
||||
const svalue *get_or_create_repeated_svalue (tree type,
|
||||
const svalue *outer_size,
|
||||
const svalue *inner_svalue);
|
||||
const svalue *get_or_create_bits_within (tree type,
|
||||
const bit_range &bits,
|
||||
const svalue *inner_svalue);
|
||||
const svalue *get_or_create_unmergeable (const svalue *arg);
|
||||
const svalue *get_or_create_widening_svalue (tree type,
|
||||
const function_point &point,
|
||||
const svalue *base_svalue,
|
||||
const svalue *iter_svalue);
|
||||
const svalue *get_or_create_compound_svalue (tree type,
|
||||
const binding_map &map);
|
||||
const svalue *get_or_create_conjured_svalue (tree type, const gimple *stmt,
|
||||
const region *id_reg,
|
||||
const conjured_purge &p,
|
||||
unsigned idx = 0);
|
||||
const svalue *
|
||||
get_or_create_asm_output_svalue (tree type,
|
||||
const gasm *asm_stmt,
|
||||
unsigned output_idx,
|
||||
const vec<const svalue *> &inputs);
|
||||
const svalue *
|
||||
get_or_create_asm_output_svalue (tree type,
|
||||
const char *asm_string,
|
||||
unsigned output_idx,
|
||||
unsigned num_outputs,
|
||||
const vec<const svalue *> &inputs);
|
||||
const svalue *
|
||||
get_or_create_const_fn_result_svalue (tree type,
|
||||
tree fndecl,
|
||||
const vec<const svalue *> &inputs);
|
||||
|
||||
const svalue *maybe_get_char_from_string_cst (tree string_cst,
|
||||
tree byte_offset_cst);
|
||||
|
||||
/* Dynamically-allocated svalue instances.
|
||||
The number of these within the analysis can grow arbitrarily.
|
||||
They are still owned by the manager. */
|
||||
const svalue *create_unique_svalue (tree type);
|
||||
|
||||
/* region consolidation. */
|
||||
const root_region *get_root_region () const { return &m_root_region; }
|
||||
const stack_region * get_stack_region () const { return &m_stack_region; }
|
||||
const heap_region *get_heap_region () const { return &m_heap_region; }
|
||||
const code_region *get_code_region () const { return &m_code_region; }
|
||||
const globals_region *get_globals_region () const
|
||||
{
|
||||
return &m_globals_region;
|
||||
}
|
||||
const errno_region *get_errno_region () const { return &m_errno_region; }
|
||||
const function_region *get_region_for_fndecl (tree fndecl);
|
||||
const label_region *get_region_for_label (tree label);
|
||||
const decl_region *get_region_for_global (tree expr);
|
||||
const region *get_field_region (const region *parent, tree field);
|
||||
const region *get_element_region (const region *parent,
|
||||
tree element_type,
|
||||
const svalue *index);
|
||||
const region *get_offset_region (const region *parent,
|
||||
tree type,
|
||||
const svalue *byte_offset);
|
||||
const region *get_sized_region (const region *parent,
|
||||
tree type,
|
||||
const svalue *byte_size_sval);
|
||||
const region *get_cast_region (const region *original_region,
|
||||
tree type);
|
||||
const frame_region *get_frame_region (const frame_region *calling_frame,
|
||||
const function &fun);
|
||||
const region *get_symbolic_region (const svalue *sval);
|
||||
const string_region *get_region_for_string (tree string_cst);
|
||||
const region *get_bit_range (const region *parent, tree type,
|
||||
const bit_range &bits);
|
||||
const var_arg_region *get_var_arg_region (const frame_region *parent,
|
||||
unsigned idx);
|
||||
|
||||
const region *get_unknown_symbolic_region (tree region_type);
|
||||
|
||||
const region *
|
||||
get_region_for_unexpected_tree_code (region_model_context *ctxt,
|
||||
tree t,
|
||||
const dump_location_t &loc);
|
||||
|
||||
store_manager *get_store_manager () { return &m_store_mgr; }
|
||||
bounded_ranges_manager *get_range_manager () const { return m_range_mgr; }
|
||||
|
||||
known_function_manager *get_known_function_manager ()
|
||||
{
|
||||
return &m_known_fn_mgr;
|
||||
}
|
||||
|
||||
/* Dynamically-allocated region instances.
|
||||
The number of these within the analysis can grow arbitrarily.
|
||||
They are still owned by the manager. */
|
||||
const region *
|
||||
get_or_create_region_for_heap_alloc (const bitmap &base_regs_in_use);
|
||||
const region *create_region_for_alloca (const frame_region *frame);
|
||||
|
||||
void log_stats (logger *logger, bool show_objs) const;
|
||||
|
||||
void begin_checking_feasibility (void) { m_checking_feasibility = true; }
|
||||
void end_checking_feasibility (void) { m_checking_feasibility = false; }
|
||||
|
||||
logger *get_logger () const { return m_logger; }
|
||||
|
||||
void dump_untracked_regions () const;
|
||||
|
||||
const svalue *maybe_fold_binop (tree type, enum tree_code op,
|
||||
const svalue *arg0, const svalue *arg1);
|
||||
private:
|
||||
bool too_complex_p (const complexity &c) const;
|
||||
bool reject_if_too_complex (svalue *sval);
|
||||
|
||||
const svalue *maybe_fold_unaryop (tree type, enum tree_code op,
|
||||
const svalue *arg);
|
||||
const svalue *maybe_fold_sub_svalue (tree type,
|
||||
const svalue *parent_svalue,
|
||||
const region *subregion);
|
||||
const svalue *maybe_fold_repeated_svalue (tree type,
|
||||
const svalue *outer_size,
|
||||
const svalue *inner_svalue);
|
||||
const svalue *maybe_fold_bits_within_svalue (tree type,
|
||||
const bit_range &bits,
|
||||
const svalue *inner_svalue);
|
||||
const svalue *maybe_undo_optimize_bit_field_compare (tree type,
|
||||
const compound_svalue *compound_sval,
|
||||
tree cst, const svalue *arg1);
|
||||
const svalue *maybe_fold_asm_output_svalue (tree type,
|
||||
const vec<const svalue *> &inputs);
|
||||
|
||||
logger *m_logger;
|
||||
|
||||
unsigned m_next_symbol_id;
|
||||
|
||||
const call_string m_empty_call_string;
|
||||
|
||||
root_region m_root_region;
|
||||
stack_region m_stack_region;
|
||||
heap_region m_heap_region;
|
||||
|
||||
/* svalue consolidation. */
|
||||
typedef hash_map<constant_svalue::key_t, constant_svalue *> constants_map_t;
|
||||
constants_map_t m_constants_map;
|
||||
|
||||
typedef hash_map<tree, unknown_svalue *> unknowns_map_t;
|
||||
unknowns_map_t m_unknowns_map;
|
||||
const unknown_svalue *m_unknown_NULL;
|
||||
|
||||
typedef hash_map<poisoned_svalue::key_t,
|
||||
poisoned_svalue *> poisoned_values_map_t;
|
||||
poisoned_values_map_t m_poisoned_values_map;
|
||||
|
||||
typedef hash_map<setjmp_svalue::key_t,
|
||||
setjmp_svalue *> setjmp_values_map_t;
|
||||
setjmp_values_map_t m_setjmp_values_map;
|
||||
|
||||
typedef hash_map<const region *, initial_svalue *> initial_values_map_t;
|
||||
initial_values_map_t m_initial_values_map;
|
||||
|
||||
typedef hash_map<region_svalue::key_t, region_svalue *> pointer_values_map_t;
|
||||
pointer_values_map_t m_pointer_values_map;
|
||||
|
||||
typedef hash_map<unaryop_svalue::key_t,
|
||||
unaryop_svalue *> unaryop_values_map_t;
|
||||
unaryop_values_map_t m_unaryop_values_map;
|
||||
|
||||
typedef hash_map<binop_svalue::key_t, binop_svalue *> binop_values_map_t;
|
||||
binop_values_map_t m_binop_values_map;
|
||||
|
||||
typedef hash_map<sub_svalue::key_t, sub_svalue *> sub_values_map_t;
|
||||
sub_values_map_t m_sub_values_map;
|
||||
|
||||
typedef hash_map<repeated_svalue::key_t,
|
||||
repeated_svalue *> repeated_values_map_t;
|
||||
repeated_values_map_t m_repeated_values_map;
|
||||
|
||||
typedef hash_map<bits_within_svalue::key_t,
|
||||
bits_within_svalue *> bits_within_values_map_t;
|
||||
bits_within_values_map_t m_bits_within_values_map;
|
||||
|
||||
typedef hash_map<const svalue *,
|
||||
unmergeable_svalue *> unmergeable_values_map_t;
|
||||
unmergeable_values_map_t m_unmergeable_values_map;
|
||||
|
||||
typedef hash_map<widening_svalue::key_t,
|
||||
widening_svalue */*,
|
||||
widening_svalue::key_t::hash_map_traits*/>
|
||||
widening_values_map_t;
|
||||
widening_values_map_t m_widening_values_map;
|
||||
|
||||
typedef hash_map<compound_svalue::key_t,
|
||||
compound_svalue *> compound_values_map_t;
|
||||
compound_values_map_t m_compound_values_map;
|
||||
|
||||
typedef hash_map<conjured_svalue::key_t,
|
||||
conjured_svalue *> conjured_values_map_t;
|
||||
conjured_values_map_t m_conjured_values_map;
|
||||
|
||||
typedef hash_map<asm_output_svalue::key_t,
|
||||
asm_output_svalue *> asm_output_values_map_t;
|
||||
asm_output_values_map_t m_asm_output_values_map;
|
||||
|
||||
typedef hash_map<const_fn_result_svalue::key_t,
|
||||
const_fn_result_svalue *> const_fn_result_values_map_t;
|
||||
const_fn_result_values_map_t m_const_fn_result_values_map;
|
||||
|
||||
bool m_checking_feasibility;
|
||||
|
||||
/* "Dynamically-allocated" svalue instances.
|
||||
The number of these within the analysis can grow arbitrarily.
|
||||
They are still owned by the manager. */
|
||||
auto_delete_vec<svalue> m_managed_dynamic_svalues;
|
||||
|
||||
/* Maximum complexity of svalues that weren't rejected. */
|
||||
complexity m_max_complexity;
|
||||
|
||||
/* region consolidation. */
|
||||
|
||||
code_region m_code_region;
|
||||
typedef hash_map<tree, function_region *> fndecls_map_t;
|
||||
typedef fndecls_map_t::iterator fndecls_iterator_t;
|
||||
fndecls_map_t m_fndecls_map;
|
||||
|
||||
typedef hash_map<tree, label_region *> labels_map_t;
|
||||
typedef labels_map_t::iterator labels_iterator_t;
|
||||
labels_map_t m_labels_map;
|
||||
|
||||
globals_region m_globals_region;
|
||||
typedef hash_map<tree, decl_region *> globals_map_t;
|
||||
typedef globals_map_t::iterator globals_iterator_t;
|
||||
globals_map_t m_globals_map;
|
||||
|
||||
thread_local_region m_thread_local_region;
|
||||
errno_region m_errno_region;
|
||||
|
||||
consolidation_map<field_region> m_field_regions;
|
||||
consolidation_map<element_region> m_element_regions;
|
||||
consolidation_map<offset_region> m_offset_regions;
|
||||
consolidation_map<sized_region> m_sized_regions;
|
||||
consolidation_map<cast_region> m_cast_regions;
|
||||
consolidation_map<frame_region> m_frame_regions;
|
||||
consolidation_map<symbolic_region> m_symbolic_regions;
|
||||
|
||||
typedef hash_map<tree, string_region *> string_map_t;
|
||||
string_map_t m_string_map;
|
||||
|
||||
consolidation_map<bit_range_region> m_bit_range_regions;
|
||||
consolidation_map<var_arg_region> m_var_arg_regions;
|
||||
|
||||
store_manager m_store_mgr;
|
||||
|
||||
bounded_ranges_manager *m_range_mgr;
|
||||
|
||||
known_function_manager m_known_fn_mgr;
|
||||
|
||||
/* "Dynamically-allocated" region instances.
|
||||
The number of these within the analysis can grow arbitrarily.
|
||||
They are still owned by the manager. */
|
||||
auto_delete_vec<region> m_managed_dynamic_regions;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_REGION_MODEL_MANAGER_H */
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/* Finding reachable regions and values.
|
||||
Copyright (C) 2020-2024 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_REGION_MODEL_REACHABILITY_H
|
||||
#define GCC_ANALYZER_REGION_MODEL_REACHABILITY_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A class for determining which regions and svalues are reachable.
|
||||
|
||||
Used by region_model::handle_unrecognized_call for keeping
|
||||
track of all regions that are reachable, and, of those, which are
|
||||
mutable.
|
||||
|
||||
Used by program_state::detect_leaks
|
||||
(via region_model::get_reachable_svalues) for detecting leaks. */
|
||||
|
||||
class reachable_regions
|
||||
{
|
||||
public:
|
||||
reachable_regions (region_model *model);
|
||||
|
||||
/* Callback called for each cluster when initializing this object. */
|
||||
static void init_cluster_cb (const region *base_reg,
|
||||
reachable_regions *this_ptr);
|
||||
|
||||
/* Called for each cluster when initializing this object. */
|
||||
void init_cluster (const region *base_reg);
|
||||
|
||||
/* Lazily mark the cluster containing REG as being reachable, recursively
|
||||
adding clusters reachable from REG's cluster. */
|
||||
void add (const region *reg, bool is_mutable);
|
||||
|
||||
static void handle_sval_cb (const svalue *sval,
|
||||
reachable_regions *this_ptr);
|
||||
|
||||
/* Add SVAL. If it is a pointer, add the pointed-to region. */
|
||||
void handle_sval (const svalue *sval);
|
||||
|
||||
/* Add SVAL. If it is a pointer, add the pointed-to region.
|
||||
Use PARAM_TYPE for determining mutability. */
|
||||
void handle_parm (const svalue *sval, tree param_type);
|
||||
|
||||
/* Update the store to mark the clusters that were found to be mutable
|
||||
as having escaped.
|
||||
Notify CTXT about escaping function_decls. */
|
||||
void mark_escaped_clusters (region_model_context *ctxt);
|
||||
|
||||
/* Iteration over reachable base regions. */
|
||||
hash_set<const region *>::iterator begin ()
|
||||
{
|
||||
return m_reachable_base_regs.begin ();
|
||||
}
|
||||
hash_set<const region *>::iterator end ()
|
||||
{
|
||||
return m_reachable_base_regs.end ();
|
||||
}
|
||||
|
||||
svalue_set::iterator begin_reachable_svals ()
|
||||
{
|
||||
return m_reachable_svals.begin ();
|
||||
}
|
||||
svalue_set::iterator end_reachable_svals ()
|
||||
{
|
||||
return m_reachable_svals.end ();
|
||||
}
|
||||
svalue_set::iterator begin_mutable_svals ()
|
||||
{
|
||||
return m_mutable_svals.begin ();
|
||||
}
|
||||
svalue_set::iterator end_mutable_svals ()
|
||||
{
|
||||
return m_mutable_svals.end ();
|
||||
}
|
||||
hash_set<const region *>::iterator begin_mutable_base_regs ()
|
||||
{
|
||||
return m_mutable_base_regs.begin ();
|
||||
}
|
||||
hash_set<const region *>::iterator end_mutable_base_regs ()
|
||||
{
|
||||
return m_mutable_base_regs.end ();
|
||||
}
|
||||
|
||||
void dump_to_pp (pretty_printer *pp) const;
|
||||
|
||||
DEBUG_FUNCTION void dump () const;
|
||||
|
||||
private:
|
||||
region_model *m_model;
|
||||
store *m_store;
|
||||
|
||||
/* The base regions already seen. */
|
||||
hash_set<const region *> m_reachable_base_regs;
|
||||
|
||||
/* The base regions that can be changed (accessed via non-const pointers). */
|
||||
hash_set<const region *> m_mutable_base_regs;
|
||||
|
||||
/* svalues that were passed as const pointers, so e.g. couldn't have
|
||||
been freed (but could have e.g. had "close" called on them if an
|
||||
int file-descriptor). */
|
||||
svalue_set m_reachable_svals;
|
||||
/* svalues that were passed as non-const pointers, so e.g. could have
|
||||
been freed. */
|
||||
svalue_set m_mutable_svals;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_REGION_MODEL_REACHABILITY_H */
|
||||
+1344
File diff suppressed because it is too large
Load Diff
+1509
File diff suppressed because it is too large
Load Diff
+358
@@ -0,0 +1,358 @@
|
||||
/* Modeling API uses and misuses via state machines.
|
||||
Copyright (C) 2019-2024 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_SM_H
|
||||
#define GCC_ANALYZER_SM_H
|
||||
|
||||
/* Utility functions for use by state machines. */
|
||||
|
||||
namespace ana {
|
||||
|
||||
class state_machine;
|
||||
class sm_context;
|
||||
class pending_diagnostic;
|
||||
|
||||
extern bool any_pointer_p (tree expr);
|
||||
extern bool any_pointer_p (const svalue *sval);
|
||||
|
||||
/* An abstract base class for a state machine describing an API.
|
||||
Manages a set of state objects, and has various virtual functions
|
||||
for pattern-matching on statements. */
|
||||
|
||||
class state_machine : public log_user
|
||||
{
|
||||
public:
|
||||
/* States are represented by immutable objects, owned by the state
|
||||
machine. */
|
||||
class state
|
||||
{
|
||||
public:
|
||||
state (const char *name, unsigned id) : m_name (name), m_id (id) {}
|
||||
virtual ~state () {}
|
||||
|
||||
const char *get_name () const { return m_name; }
|
||||
virtual void dump_to_pp (pretty_printer *pp) const;
|
||||
virtual json::value *to_json () const;
|
||||
|
||||
unsigned get_id () const { return m_id; }
|
||||
|
||||
private:
|
||||
const char *m_name;
|
||||
unsigned m_id;
|
||||
};
|
||||
typedef const state_machine::state *state_t;
|
||||
|
||||
state_machine (const char *name, logger *logger);
|
||||
virtual ~state_machine () {}
|
||||
|
||||
/* Should states be inherited from a parent region to a child region,
|
||||
when first accessing a child region?
|
||||
For example we should inherit the taintedness of a subregion,
|
||||
but we should not inherit the "malloc:non-null" state of a field
|
||||
within a heap-allocated struct. */
|
||||
virtual bool inherited_state_p () const = 0;
|
||||
|
||||
/* A vfunc for more general handling of inheritance. */
|
||||
virtual state_t
|
||||
alt_get_inherited_state (const sm_state_map &,
|
||||
const svalue *,
|
||||
const extrinsic_state &) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
has_alt_get_inherited_state_p () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual state_machine::state_t get_default_state (const svalue *) const
|
||||
{
|
||||
return m_start;
|
||||
}
|
||||
|
||||
const char *get_name () const { return m_name; }
|
||||
|
||||
state_t get_state_by_name (const char *name) const;
|
||||
|
||||
/* Return true if STMT is a function call recognized by this sm. */
|
||||
virtual bool on_stmt (sm_context *sm_ctxt,
|
||||
const supernode *node,
|
||||
const gimple *stmt) const = 0;
|
||||
|
||||
virtual void on_phi (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
|
||||
const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gphi *phi ATTRIBUTE_UNUSED,
|
||||
tree rhs ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
}
|
||||
|
||||
virtual void on_condition (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
|
||||
const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt ATTRIBUTE_UNUSED,
|
||||
const svalue *lhs ATTRIBUTE_UNUSED,
|
||||
enum tree_code op ATTRIBUTE_UNUSED,
|
||||
const svalue *rhs ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
}
|
||||
|
||||
virtual void
|
||||
on_bounded_ranges (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
|
||||
const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt ATTRIBUTE_UNUSED,
|
||||
const svalue &sval ATTRIBUTE_UNUSED,
|
||||
const bounded_ranges &ranges ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
}
|
||||
|
||||
virtual void
|
||||
on_pop_frame (sm_state_map *smap ATTRIBUTE_UNUSED,
|
||||
const frame_region *frame_reg ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
}
|
||||
|
||||
/* Return true if it safe to discard the given state (to help
|
||||
when simplifying state objects).
|
||||
States that need leak detection should return false. */
|
||||
virtual bool can_purge_p (state_t s) const = 0;
|
||||
|
||||
/* Called when VAR leaks (and !can_purge_p). */
|
||||
virtual std::unique_ptr<pending_diagnostic>
|
||||
on_leak (tree var ATTRIBUTE_UNUSED) const;
|
||||
|
||||
/* Return true if S should be reset to "start" for values passed (or reachable
|
||||
from) calls to unknown functions. IS_MUTABLE is true for pointers as
|
||||
non-const, false if only passed as const-pointers.
|
||||
|
||||
For example, in sm-malloc.cc, an on-stack ptr doesn't stop being
|
||||
stack-allocated when passed to an unknown fn, but a malloc-ed pointer
|
||||
could be freed when passed to an unknown fn (unless passed as "const"). */
|
||||
virtual bool reset_when_passed_to_unknown_fn_p (state_t s ATTRIBUTE_UNUSED,
|
||||
bool is_mutable) const
|
||||
{
|
||||
return is_mutable;
|
||||
}
|
||||
|
||||
/* Attempt to get a state for the merger of STATE_A and STATE_B,
|
||||
or return NULL if merging shouldn't occur, so that differences
|
||||
between sm-state will lead to separate exploded nodes.
|
||||
|
||||
Most state machines will only merge equal states, but can
|
||||
override maybe_get_merged_states_nonequal to support mergers
|
||||
of certain non-equal states. */
|
||||
state_t maybe_get_merged_state (state_t state_a,
|
||||
state_t state_b) const
|
||||
{
|
||||
if (state_a == state_b)
|
||||
return state_a;
|
||||
return maybe_get_merged_states_nonequal (state_a, state_b);
|
||||
}
|
||||
|
||||
/* Base implementation of hook for maybe_get_merged_state on non-equal
|
||||
states. */
|
||||
virtual state_t
|
||||
maybe_get_merged_states_nonequal (state_t state_a ATTRIBUTE_UNUSED,
|
||||
state_t state_b ATTRIBUTE_UNUSED) const
|
||||
{
|
||||
/* By default, non-equal sm states should inhibit merger of enodes. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void validate (state_t s) const;
|
||||
|
||||
void dump_to_pp (pretty_printer *pp) const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
state_t get_start_state () const { return m_start; }
|
||||
|
||||
protected:
|
||||
state_t add_state (const char *name);
|
||||
state_t add_custom_state (state *s)
|
||||
{
|
||||
m_states.safe_push (s);
|
||||
return s;
|
||||
}
|
||||
|
||||
unsigned alloc_state_id () { return m_next_state_id++; }
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN (state_machine);
|
||||
|
||||
const char *m_name;
|
||||
|
||||
/* States are owned by the state_machine. */
|
||||
auto_delete_vec<state> m_states;
|
||||
|
||||
unsigned m_next_state_id;
|
||||
|
||||
protected:
|
||||
/* Must be inited after m_next_state_id. */
|
||||
state_t m_start;
|
||||
};
|
||||
|
||||
/* Abstract base class for state machines to pass to
|
||||
sm_context::on_custom_transition for handling non-standard transitions
|
||||
(e.g. adding a node and edge to simulate registering a callback and having
|
||||
the callback be called later). */
|
||||
|
||||
class custom_transition
|
||||
{
|
||||
public:
|
||||
virtual ~custom_transition () {}
|
||||
virtual void impl_transition (exploded_graph *eg,
|
||||
exploded_node *src_enode,
|
||||
int sm_idx) = 0;
|
||||
};
|
||||
|
||||
/* Abstract base class giving an interface for the state machine to call
|
||||
the checker engine, at a particular stmt. */
|
||||
|
||||
class sm_context
|
||||
{
|
||||
public:
|
||||
virtual ~sm_context () {}
|
||||
|
||||
/* Get the fndecl used at call, or NULL_TREE.
|
||||
Use in preference to gimple_call_fndecl (and gimple_call_addr_fndecl),
|
||||
since it can look through function pointer assignments and
|
||||
other callback handling. */
|
||||
virtual tree get_fndecl_for_call (const gcall *call) = 0;
|
||||
|
||||
/* Get the old state of VAR at STMT. */
|
||||
virtual state_machine::state_t get_state (const gimple *stmt,
|
||||
tree var) = 0;
|
||||
virtual state_machine::state_t get_state (const gimple *stmt,
|
||||
const svalue *) = 0;
|
||||
/* Set the next state of VAR to be TO, recording the "origin" of the
|
||||
state as ORIGIN.
|
||||
Use STMT for location information. */
|
||||
virtual void set_next_state (const gimple *stmt,
|
||||
tree var,
|
||||
state_machine::state_t to,
|
||||
tree origin = NULL_TREE) = 0;
|
||||
virtual void set_next_state (const gimple *stmt,
|
||||
const svalue *var,
|
||||
state_machine::state_t to,
|
||||
tree origin = NULL_TREE) = 0;
|
||||
|
||||
/* Called by state_machine in response to pattern matches:
|
||||
if VAR is in state FROM, transition it to state TO, potentially
|
||||
recording the "origin" of the state as ORIGIN.
|
||||
Use NODE and STMT for location information. */
|
||||
void on_transition (const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt,
|
||||
tree var,
|
||||
state_machine::state_t from,
|
||||
state_machine::state_t to,
|
||||
tree origin = NULL_TREE)
|
||||
{
|
||||
state_machine::state_t current = get_state (stmt, var);
|
||||
if (current == from)
|
||||
set_next_state (stmt, var, to, origin);
|
||||
}
|
||||
|
||||
void on_transition (const supernode *node ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt,
|
||||
const svalue *var,
|
||||
state_machine::state_t from,
|
||||
state_machine::state_t to,
|
||||
tree origin = NULL_TREE)
|
||||
{
|
||||
state_machine::state_t current = get_state (stmt, var);
|
||||
if (current == from)
|
||||
set_next_state (stmt, var, to, origin);
|
||||
}
|
||||
|
||||
/* Called by state_machine in response to pattern matches:
|
||||
issue a diagnostic D using NODE and STMT for location information. */
|
||||
virtual void warn (const supernode *node, const gimple *stmt,
|
||||
tree var,
|
||||
std::unique_ptr<pending_diagnostic> d) = 0;
|
||||
virtual void warn (const supernode *node, const gimple *stmt,
|
||||
const svalue *var,
|
||||
std::unique_ptr<pending_diagnostic> d) = 0;
|
||||
|
||||
/* For use when generating trees when creating pending_diagnostics, so that
|
||||
rather than e.g.
|
||||
"double-free of '<unknown>'"
|
||||
we can print:
|
||||
"double-free of 'inbuf.data'". */
|
||||
virtual tree get_diagnostic_tree (tree expr)
|
||||
{
|
||||
return expr;
|
||||
}
|
||||
virtual tree get_diagnostic_tree (const svalue *) = 0;
|
||||
|
||||
virtual state_machine::state_t get_global_state () const = 0;
|
||||
virtual void set_global_state (state_machine::state_t) = 0;
|
||||
|
||||
virtual void clear_all_per_svalue_state () = 0;
|
||||
|
||||
/* A vfunc for handling custom transitions, such as when registering
|
||||
a signal handler. */
|
||||
virtual void on_custom_transition (custom_transition *transition) = 0;
|
||||
|
||||
/* If STMT is an assignment known to assign zero to its LHS, return
|
||||
the LHS.
|
||||
Otherwise return NULL_TREE. */
|
||||
virtual tree is_zero_assignment (const gimple *stmt) = 0;
|
||||
|
||||
virtual path_context *get_path_context () const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Are we handling an external function with unknown side effects? */
|
||||
virtual bool unknown_side_effects_p () const { return false; }
|
||||
|
||||
virtual const program_state *get_old_program_state () const = 0;
|
||||
virtual const program_state *get_new_program_state () const = 0;
|
||||
|
||||
const region_model *get_old_region_model () const;
|
||||
|
||||
protected:
|
||||
sm_context (int sm_idx, const state_machine &sm)
|
||||
: m_sm_idx (sm_idx), m_sm (sm) {}
|
||||
|
||||
int m_sm_idx;
|
||||
const state_machine &m_sm;
|
||||
};
|
||||
|
||||
|
||||
/* The various state_machine subclasses are hidden in their respective
|
||||
implementation files. */
|
||||
|
||||
extern void make_checkers (auto_delete_vec <state_machine> &out,
|
||||
logger *logger);
|
||||
|
||||
extern state_machine *make_malloc_state_machine (logger *logger);
|
||||
extern state_machine *make_fileptr_state_machine (logger *logger);
|
||||
extern state_machine *make_taint_state_machine (logger *logger);
|
||||
extern state_machine *make_sensitive_state_machine (logger *logger);
|
||||
extern state_machine *make_signal_state_machine (logger *logger);
|
||||
extern state_machine *make_pattern_test_state_machine (logger *logger);
|
||||
extern state_machine *make_va_list_state_machine (logger *logger);
|
||||
extern state_machine *make_fd_state_machine (logger *logger);
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_SM_H */
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
/* Classes for purging state at function_points.
|
||||
Copyright (C) 2019-2024 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_STATE_PURGE_H
|
||||
#define GCC_ANALYZER_STATE_PURGE_H
|
||||
|
||||
/* Hash traits for function_point. */
|
||||
|
||||
template <> struct default_hash_traits<function_point>
|
||||
: public pod_hash_traits<function_point>
|
||||
{
|
||||
static const bool empty_zero_p = false;
|
||||
};
|
||||
|
||||
template <>
|
||||
inline hashval_t
|
||||
pod_hash_traits<function_point>::hash (value_type v)
|
||||
{
|
||||
return v.hash ();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool
|
||||
pod_hash_traits<function_point>::equal (const value_type &existing,
|
||||
const value_type &candidate)
|
||||
{
|
||||
return existing == candidate;
|
||||
}
|
||||
template <>
|
||||
inline void
|
||||
pod_hash_traits<function_point>::mark_deleted (value_type &v)
|
||||
{
|
||||
v = function_point::deleted ();
|
||||
}
|
||||
template <>
|
||||
inline void
|
||||
pod_hash_traits<function_point>::mark_empty (value_type &v)
|
||||
{
|
||||
v = function_point::empty ();
|
||||
}
|
||||
template <>
|
||||
inline bool
|
||||
pod_hash_traits<function_point>::is_deleted (value_type v)
|
||||
{
|
||||
return v.get_kind () == PK_DELETED;
|
||||
}
|
||||
template <>
|
||||
inline bool
|
||||
pod_hash_traits<function_point>::is_empty (value_type v)
|
||||
{
|
||||
return v.get_kind () == PK_EMPTY;
|
||||
}
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* The result of analyzing which decls and SSA names can be purged from state at
|
||||
different points in the program, so that we can simplify program_state
|
||||
objects, in the hope of reducing state-blowup. */
|
||||
|
||||
class state_purge_map : public log_user
|
||||
{
|
||||
public:
|
||||
typedef ordered_hash_map<tree, state_purge_per_ssa_name *> ssa_map_t;
|
||||
typedef ssa_map_t::iterator ssa_iterator;
|
||||
|
||||
typedef ordered_hash_map<tree, state_purge_per_decl *> decl_map_t;
|
||||
typedef decl_map_t::iterator decl_iterator;
|
||||
|
||||
state_purge_map (const supergraph &sg,
|
||||
region_model_manager *mgr,
|
||||
logger *logger);
|
||||
~state_purge_map ();
|
||||
|
||||
const state_purge_per_ssa_name &get_data_for_ssa_name (tree name) const
|
||||
{
|
||||
gcc_assert (TREE_CODE (name) == SSA_NAME);
|
||||
if (tree var = SSA_NAME_VAR (name))
|
||||
if (TREE_CODE (var) == VAR_DECL)
|
||||
gcc_assert (!VAR_DECL_IS_VIRTUAL_OPERAND (var));
|
||||
|
||||
state_purge_per_ssa_name **slot
|
||||
= const_cast <ssa_map_t&> (m_ssa_map).get (name);
|
||||
return **slot;
|
||||
}
|
||||
|
||||
const state_purge_per_decl *get_any_data_for_decl (tree decl) const
|
||||
{
|
||||
gcc_assert (TREE_CODE (decl) == VAR_DECL
|
||||
|| TREE_CODE (decl) == PARM_DECL
|
||||
|| TREE_CODE (decl) == RESULT_DECL);
|
||||
if (state_purge_per_decl **slot
|
||||
= const_cast <decl_map_t&> (m_decl_map).get (decl))
|
||||
return *slot;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state_purge_per_decl &
|
||||
get_or_create_data_for_decl (const function &fun, tree decl);
|
||||
|
||||
const supergraph &get_sg () const { return m_sg; }
|
||||
|
||||
ssa_iterator begin_ssas () const { return m_ssa_map.begin (); }
|
||||
ssa_iterator end_ssas () const { return m_ssa_map.end (); }
|
||||
|
||||
decl_iterator begin_decls () const { return m_decl_map.begin (); }
|
||||
decl_iterator end_decls () const { return m_decl_map.end (); }
|
||||
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN (state_purge_map);
|
||||
|
||||
const supergraph &m_sg;
|
||||
ssa_map_t m_ssa_map;
|
||||
decl_map_t m_decl_map;
|
||||
};
|
||||
|
||||
/* Base class for state_purge_per_ssa_name and state_purge_per_decl. */
|
||||
|
||||
class state_purge_per_tree
|
||||
{
|
||||
public:
|
||||
const function &get_function () const { return m_fun; }
|
||||
tree get_fndecl () const { return m_fun.decl; }
|
||||
|
||||
protected:
|
||||
typedef hash_set<function_point> point_set_t;
|
||||
|
||||
state_purge_per_tree (const function &fun)
|
||||
: m_fun (fun)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
const function &m_fun;
|
||||
};
|
||||
|
||||
/* The part of a state_purge_map relating to a specific SSA name.
|
||||
|
||||
The result of analyzing a given SSA name, recording which
|
||||
function_points need to retain state information about it to handle
|
||||
their successor states, so that we can simplify program_state objects,
|
||||
in the hope of reducing state-blowup. */
|
||||
|
||||
class state_purge_per_ssa_name : public state_purge_per_tree
|
||||
{
|
||||
public:
|
||||
state_purge_per_ssa_name (const state_purge_map &map,
|
||||
tree name,
|
||||
const function &fun);
|
||||
|
||||
bool needed_at_point_p (const function_point &point) const;
|
||||
|
||||
private:
|
||||
static function_point before_use_stmt (const state_purge_map &map,
|
||||
const gimple *use_stmt);
|
||||
|
||||
void add_to_worklist (const function_point &point,
|
||||
auto_vec<function_point> *worklist,
|
||||
logger *logger);
|
||||
|
||||
void process_point (const function_point &point,
|
||||
auto_vec<function_point> *worklist,
|
||||
const state_purge_map &map);
|
||||
|
||||
point_set_t m_points_needing_name;
|
||||
tree m_name;
|
||||
};
|
||||
|
||||
/* The part of a state_purge_map relating to a specific decl.
|
||||
|
||||
Analogous to state_purge_per_ssa_name, but for local decls.
|
||||
|
||||
This is more involved than the SSA name case, because we also need
|
||||
to handle pointers and components. */
|
||||
|
||||
class state_purge_per_decl : public state_purge_per_tree
|
||||
{
|
||||
public:
|
||||
state_purge_per_decl (const state_purge_map &map,
|
||||
tree decl,
|
||||
const function &fun);
|
||||
|
||||
bool needed_at_point_p (const function_point &point) const;
|
||||
|
||||
void add_needed_at (const function_point &point);
|
||||
void add_pointed_to_at (const function_point &point);
|
||||
void process_worklists (const state_purge_map &map,
|
||||
region_model_manager *mgr);
|
||||
|
||||
private:
|
||||
static function_point before_use_stmt (const state_purge_map &map,
|
||||
const gimple *use_stmt);
|
||||
|
||||
void add_to_worklist (const function_point &point,
|
||||
auto_vec<function_point> *worklist,
|
||||
point_set_t *seen,
|
||||
logger *logger);
|
||||
|
||||
void process_point_backwards (const function_point &point,
|
||||
auto_vec<function_point> *worklist,
|
||||
point_set_t *seen,
|
||||
const state_purge_map &map,
|
||||
const region_model &model);
|
||||
void process_point_forwards (const function_point &point,
|
||||
auto_vec<function_point> *worklist,
|
||||
point_set_t *seen,
|
||||
const state_purge_map &map);
|
||||
|
||||
point_set_t m_points_needing_decl;
|
||||
point_set_t m_points_taking_address;
|
||||
tree m_decl;
|
||||
};
|
||||
|
||||
/* Subclass of dot_annotator for use by -fdump-analyzer-state-purge.
|
||||
Annotate the .dot output with state-purge information. */
|
||||
|
||||
class state_purge_annotator : public dot_annotator
|
||||
{
|
||||
public:
|
||||
state_purge_annotator (const state_purge_map *map) : m_map (map) {}
|
||||
|
||||
bool add_node_annotations (graphviz_out *gv, const supernode &n, bool)
|
||||
const final override;
|
||||
|
||||
void add_stmt_annotations (graphviz_out *gv, const gimple *stmt,
|
||||
bool within_row)
|
||||
const final override;
|
||||
|
||||
private:
|
||||
void print_needed (graphviz_out *gv,
|
||||
const function_point &point,
|
||||
bool within_table) const;
|
||||
|
||||
const state_purge_map *m_map;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_STATE_PURGE_H */
|
||||
+886
@@ -0,0 +1,886 @@
|
||||
/* Classes for modeling the state of memory.
|
||||
Copyright (C) 2020-2024 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_STORE_H
|
||||
#define GCC_ANALYZER_STORE_H
|
||||
|
||||
/* Implementation of the region-based ternary model described in:
|
||||
"A Memory Model for Static Analysis of C Programs"
|
||||
(Zhongxing Xu, Ted Kremenek, and Jian Zhang)
|
||||
http://lcs.ios.ac.cn/~xuzb/canalyze/memmodel.pdf */
|
||||
|
||||
/* The store models memory as a collection of "clusters", where regions
|
||||
are partitioned into clusters via their base region.
|
||||
|
||||
For example, given:
|
||||
int a, b, c;
|
||||
struct coord { double x; double y; } verts[3];
|
||||
then "verts[0].y" and "verts[1].x" both have "verts" as their base region.
|
||||
Each of a, b, c, and verts will have their own clusters, so that we
|
||||
know that writes to e.g. "verts[1].x".don't affect e.g. "a".
|
||||
|
||||
Within each cluster we store a map of bindings to values, where the
|
||||
binding keys can be either concrete or symbolic.
|
||||
|
||||
Concrete bindings affect a specific range of bits relative to the start
|
||||
of the base region of the cluster, whereas symbolic bindings affect
|
||||
a specific subregion within the cluster.
|
||||
|
||||
Consider (from the symbolic-1.c testcase):
|
||||
|
||||
char arr[1024];
|
||||
arr[2] = a; (1)
|
||||
arr[3] = b; (2)
|
||||
After (1) and (2), the cluster for "arr" has concrete bindings
|
||||
for bits 16-23 and for bits 24-31, with svalues "INIT_VAL(a)"
|
||||
and "INIT_VAL(b)" respectively:
|
||||
cluster: {bits 16-23: "INIT_VAL(a)",
|
||||
bits 24-31: "INIT_VAL(b)";
|
||||
flags: {}}
|
||||
Attempting to query unbound subregions e.g. arr[4] will
|
||||
return "UNINITIALIZED".
|
||||
"a" and "b" are each in their own clusters, with no explicit
|
||||
bindings, and thus implicitly have value INIT_VAL(a) and INIT_VAL(b).
|
||||
|
||||
arr[3] = c; (3)
|
||||
After (3), the concrete binding for bits 24-31 is replaced with the
|
||||
svalue "INIT_VAL(c)":
|
||||
cluster: {bits 16-23: "INIT_VAL(a)", (from before)
|
||||
bits 24-31: "INIT_VAL(c)"; (updated)
|
||||
flags: {}}
|
||||
|
||||
arr[i] = d; (4)
|
||||
After (4), we lose the concrete bindings and replace them with a
|
||||
symbolic binding for "arr[i]", with svalue "INIT_VAL(d)". We also
|
||||
mark the cluster as having been "symbolically touched": future
|
||||
attempts to query the values of subregions other than "arr[i]",
|
||||
such as "arr[3]" are "UNKNOWN", since we don't know if the write
|
||||
to arr[i] affected them.
|
||||
cluster: {symbolic_key(arr[i]): "INIT_VAL(d)";
|
||||
flags: {TOUCHED}}
|
||||
|
||||
arr[j] = e; (5)
|
||||
After (5), we lose the symbolic binding for "arr[i]" since we could
|
||||
have overwritten it, and add a symbolic binding for "arr[j]".
|
||||
cluster: {symbolic_key(arr[j]): "INIT_VAL(d)"; (different symbolic
|
||||
flags: {TOUCHED}} binding)
|
||||
|
||||
arr[3] = f; (6)
|
||||
After (6), we lose the symbolic binding for "arr[j]" since we could
|
||||
have overwritten it, and gain a concrete binding for bits 24-31
|
||||
again, this time with svalue "INIT_VAL(e)":
|
||||
cluster: {bits 24-31: "INIT_VAL(d)";
|
||||
flags: {TOUCHED}}
|
||||
The cluster is still flagged as touched, so that we know that
|
||||
accesses to other elements are "UNKNOWN" rather than
|
||||
"UNINITIALIZED".
|
||||
|
||||
Handling symbolic regions requires us to handle aliasing.
|
||||
|
||||
In the first example above, each of a, b, c and verts are non-symbolic
|
||||
base regions and so their clusters are "concrete clusters", whereas given:
|
||||
struct coord *p, *q;
|
||||
then "*p" and "*q" are symbolic base regions, and thus "*p" and "*q"
|
||||
have "symbolic clusters".
|
||||
|
||||
In the above, "verts[i].x" will have a symbolic *binding* within a
|
||||
concrete cluster for "verts", whereas "*p" is a symbolic *cluster*.
|
||||
|
||||
Writes to concrete clusters can't affect other concrete clusters,
|
||||
but can affect symbolic clusters; e.g. after:
|
||||
verts[0].x = 42;
|
||||
we bind 42 in the cluster for "verts", but the clusters for "b" and "c"
|
||||
can't be affected. Any symbolic clusters for *p and for *q can be
|
||||
affected, *p and *q could alias verts.
|
||||
|
||||
Writes to a symbolic cluster can affect other clusters, both
|
||||
concrete and symbolic; e.g. after:
|
||||
p->x = 17;
|
||||
we bind 17 within the cluster for "*p". The concrete clusters for a, b,
|
||||
c, and verts could be affected, depending on whether *p aliases them.
|
||||
Similarly, the symbolic cluster to *q could be affected. */
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A class for keeping track of aspects of a program_state that we don't
|
||||
know about, to avoid false positives about leaks.
|
||||
|
||||
Consider:
|
||||
|
||||
p->field = malloc (1024);
|
||||
q->field = NULL;
|
||||
|
||||
where we don't know whether or not p and q point to the same memory,
|
||||
and:
|
||||
|
||||
p->field = malloc (1024);
|
||||
unknown_fn (p);
|
||||
|
||||
In both cases, the svalue for the address of the allocated buffer
|
||||
goes from being bound to p->field to not having anything explicitly bound
|
||||
to it.
|
||||
|
||||
Given that we conservatively discard bindings due to possible aliasing or
|
||||
calls to unknown function, the store loses references to svalues,
|
||||
but these svalues could still be live. We don't want to warn about
|
||||
them leaking - they're effectively in a "maybe live" state.
|
||||
|
||||
This "maybe live" information is somewhat transient.
|
||||
|
||||
We don't want to store this "maybe live" information in the program_state,
|
||||
region_model, or store, since we don't want to bloat these objects (and
|
||||
potentially bloat the exploded_graph with more nodes).
|
||||
However, we can't store it in the region_model_context, as these context
|
||||
objects sometimes don't last long enough to be around when comparing the
|
||||
old vs the new state.
|
||||
|
||||
This class is a way to track a set of such svalues, so that we can
|
||||
temporarily capture that they are in a "maybe live" state whilst
|
||||
comparing old and new states. */
|
||||
|
||||
class uncertainty_t
|
||||
{
|
||||
public:
|
||||
typedef hash_set<const svalue *>::iterator iterator;
|
||||
|
||||
void on_maybe_bound_sval (const svalue *sval)
|
||||
{
|
||||
m_maybe_bound_svals.add (sval);
|
||||
}
|
||||
void on_mutable_sval_at_unknown_call (const svalue *sval)
|
||||
{
|
||||
m_mutable_at_unknown_call_svals.add (sval);
|
||||
}
|
||||
|
||||
bool unknown_sm_state_p (const svalue *sval)
|
||||
{
|
||||
return (m_maybe_bound_svals.contains (sval)
|
||||
|| m_mutable_at_unknown_call_svals.contains (sval));
|
||||
}
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool simple) const;
|
||||
void dump (bool simple) const;
|
||||
|
||||
iterator begin_maybe_bound_svals () const
|
||||
{
|
||||
return m_maybe_bound_svals.begin ();
|
||||
}
|
||||
iterator end_maybe_bound_svals () const
|
||||
{
|
||||
return m_maybe_bound_svals.end ();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/* svalues that might or might not still be bound. */
|
||||
hash_set<const svalue *> m_maybe_bound_svals;
|
||||
|
||||
/* svalues that have mutable sm-state at unknown calls. */
|
||||
hash_set<const svalue *> m_mutable_at_unknown_call_svals;
|
||||
};
|
||||
|
||||
class byte_range;
|
||||
class concrete_binding;
|
||||
class symbolic_binding;
|
||||
|
||||
/* Abstract base class for describing ranges of bits within a binding_map
|
||||
that can have svalues bound to them. */
|
||||
|
||||
class binding_key
|
||||
{
|
||||
public:
|
||||
virtual ~binding_key () {}
|
||||
virtual bool concrete_p () const = 0;
|
||||
bool symbolic_p () const { return !concrete_p (); }
|
||||
|
||||
static const binding_key *make (store_manager *mgr, const region *r);
|
||||
|
||||
virtual void dump_to_pp (pretty_printer *pp, bool simple) const = 0;
|
||||
void dump (bool simple) const;
|
||||
label_text get_desc (bool simple=true) const;
|
||||
|
||||
static int cmp_ptrs (const void *, const void *);
|
||||
static int cmp (const binding_key *, const binding_key *);
|
||||
|
||||
virtual const concrete_binding *dyn_cast_concrete_binding () const
|
||||
{ return NULL; }
|
||||
virtual const symbolic_binding *dyn_cast_symbolic_binding () const
|
||||
{ return NULL; }
|
||||
};
|
||||
|
||||
/* A concrete range of bits. */
|
||||
|
||||
struct bit_range
|
||||
{
|
||||
bit_range (bit_offset_t start_bit_offset, bit_size_t size_in_bits)
|
||||
: m_start_bit_offset (start_bit_offset),
|
||||
m_size_in_bits (size_in_bits)
|
||||
{}
|
||||
|
||||
void dump_to_pp (pretty_printer *pp) const;
|
||||
void dump () const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool empty_p () const
|
||||
{
|
||||
return m_size_in_bits == 0;
|
||||
}
|
||||
|
||||
bit_offset_t get_start_bit_offset () const
|
||||
{
|
||||
return m_start_bit_offset;
|
||||
}
|
||||
bit_offset_t get_next_bit_offset () const
|
||||
{
|
||||
return m_start_bit_offset + m_size_in_bits;
|
||||
}
|
||||
bit_offset_t get_last_bit_offset () const
|
||||
{
|
||||
gcc_assert (!empty_p ());
|
||||
return get_next_bit_offset () - 1;
|
||||
}
|
||||
|
||||
bool contains_p (bit_offset_t offset) const
|
||||
{
|
||||
return (offset >= get_start_bit_offset ()
|
||||
&& offset < get_next_bit_offset ());
|
||||
}
|
||||
|
||||
bool contains_p (const bit_range &other, bit_range *out) const;
|
||||
|
||||
bool operator== (const bit_range &other) const
|
||||
{
|
||||
return (m_start_bit_offset == other.m_start_bit_offset
|
||||
&& m_size_in_bits == other.m_size_in_bits);
|
||||
}
|
||||
|
||||
bool intersects_p (const bit_range &other) const
|
||||
{
|
||||
return (get_start_bit_offset () < other.get_next_bit_offset ()
|
||||
&& other.get_start_bit_offset () < get_next_bit_offset ());
|
||||
}
|
||||
bool intersects_p (const bit_range &other,
|
||||
bit_size_t *out_num_overlap_bits) const;
|
||||
bool intersects_p (const bit_range &other,
|
||||
bit_range *out_this,
|
||||
bit_range *out_other) const;
|
||||
|
||||
bool exceeds_p (const bit_range &other,
|
||||
bit_range *out_overhanging_bit_range) const;
|
||||
|
||||
bool falls_short_of_p (bit_offset_t offset,
|
||||
bit_range *out_fall_short_bits) const;
|
||||
|
||||
static int cmp (const bit_range &br1, const bit_range &br2);
|
||||
|
||||
bit_range operator- (bit_offset_t offset) const;
|
||||
|
||||
static bool from_mask (unsigned HOST_WIDE_INT mask, bit_range *out);
|
||||
|
||||
bool as_byte_range (byte_range *out) const;
|
||||
|
||||
bit_offset_t m_start_bit_offset;
|
||||
bit_size_t m_size_in_bits;
|
||||
};
|
||||
|
||||
/* A concrete range of bytes. */
|
||||
|
||||
struct byte_range
|
||||
{
|
||||
byte_range (byte_offset_t start_byte_offset, byte_size_t size_in_bytes)
|
||||
: m_start_byte_offset (start_byte_offset),
|
||||
m_size_in_bytes (size_in_bytes)
|
||||
{}
|
||||
|
||||
void dump_to_pp (pretty_printer *pp) const;
|
||||
void dump () const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool empty_p () const
|
||||
{
|
||||
return m_size_in_bytes == 0;
|
||||
}
|
||||
|
||||
bool contains_p (byte_offset_t offset) const
|
||||
{
|
||||
return (offset >= get_start_byte_offset ()
|
||||
&& offset < get_next_byte_offset ());
|
||||
}
|
||||
bool contains_p (const byte_range &other, byte_range *out) const;
|
||||
|
||||
bool operator== (const byte_range &other) const
|
||||
{
|
||||
return (m_start_byte_offset == other.m_start_byte_offset
|
||||
&& m_size_in_bytes == other.m_size_in_bytes);
|
||||
}
|
||||
|
||||
byte_offset_t get_start_byte_offset () const
|
||||
{
|
||||
return m_start_byte_offset;
|
||||
}
|
||||
byte_offset_t get_next_byte_offset () const
|
||||
{
|
||||
return m_start_byte_offset + m_size_in_bytes;
|
||||
}
|
||||
byte_offset_t get_last_byte_offset () const
|
||||
{
|
||||
gcc_assert (!empty_p ());
|
||||
return m_start_byte_offset + m_size_in_bytes - 1;
|
||||
}
|
||||
|
||||
bit_range as_bit_range () const
|
||||
{
|
||||
return bit_range (m_start_byte_offset * BITS_PER_UNIT,
|
||||
m_size_in_bytes * BITS_PER_UNIT);
|
||||
}
|
||||
|
||||
bit_offset_t get_start_bit_offset () const
|
||||
{
|
||||
return m_start_byte_offset * BITS_PER_UNIT;
|
||||
}
|
||||
bit_offset_t get_next_bit_offset () const
|
||||
{
|
||||
return get_next_byte_offset () * BITS_PER_UNIT;
|
||||
}
|
||||
|
||||
static int cmp (const byte_range &br1, const byte_range &br2);
|
||||
|
||||
byte_offset_t m_start_byte_offset;
|
||||
byte_size_t m_size_in_bytes;
|
||||
};
|
||||
|
||||
/* Concrete subclass of binding_key, for describing a non-empty
|
||||
concrete range of bits within the binding_map (e.g. "bits 8-15"). */
|
||||
|
||||
class concrete_binding : public binding_key
|
||||
{
|
||||
public:
|
||||
/* This class is its own key for the purposes of consolidation. */
|
||||
typedef concrete_binding key_t;
|
||||
|
||||
concrete_binding (bit_offset_t start_bit_offset, bit_size_t size_in_bits)
|
||||
: m_bit_range (start_bit_offset, size_in_bits)
|
||||
{
|
||||
gcc_assert (m_bit_range.m_size_in_bits > 0);
|
||||
}
|
||||
bool concrete_p () const final override { return true; }
|
||||
|
||||
hashval_t hash () const
|
||||
{
|
||||
inchash::hash hstate;
|
||||
hstate.add_wide_int (m_bit_range.m_start_bit_offset);
|
||||
hstate.add_wide_int (m_bit_range.m_size_in_bits);
|
||||
return hstate.end ();
|
||||
}
|
||||
bool operator== (const concrete_binding &other) const
|
||||
{
|
||||
return m_bit_range == other.m_bit_range;
|
||||
}
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
|
||||
|
||||
const concrete_binding *dyn_cast_concrete_binding () const final override
|
||||
{ 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
|
||||
{
|
||||
return m_bit_range.m_start_bit_offset;
|
||||
}
|
||||
bit_size_t get_size_in_bits () const
|
||||
{
|
||||
return m_bit_range.m_size_in_bits;
|
||||
}
|
||||
/* Return the next bit offset after the end of this binding. */
|
||||
bit_offset_t get_next_bit_offset () const
|
||||
{
|
||||
return m_bit_range.get_next_bit_offset ();
|
||||
}
|
||||
|
||||
bool overlaps_p (const concrete_binding &other) const;
|
||||
|
||||
static int cmp_ptr_ptr (const void *, const void *);
|
||||
|
||||
void mark_deleted () { m_bit_range.m_size_in_bits = -1; }
|
||||
void mark_empty () { m_bit_range.m_size_in_bits = -2; }
|
||||
bool is_deleted () const { return m_bit_range.m_size_in_bits == -1; }
|
||||
bool is_empty () const { return m_bit_range.m_size_in_bits == -2; }
|
||||
|
||||
private:
|
||||
bit_range m_bit_range;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
template <>
|
||||
template <>
|
||||
inline bool
|
||||
is_a_helper <const ana::concrete_binding *>::test (const ana::binding_key *key)
|
||||
{
|
||||
return key->concrete_p ();
|
||||
}
|
||||
|
||||
template <> struct default_hash_traits<ana::concrete_binding>
|
||||
: public member_function_hash_traits<ana::concrete_binding>
|
||||
{
|
||||
static const bool empty_zero_p = false;
|
||||
};
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Concrete subclass of binding_key, for describing a symbolic set of
|
||||
bits within the binding_map in terms of a region (e.g. "arr[i]"). */
|
||||
|
||||
class symbolic_binding : public binding_key
|
||||
{
|
||||
public:
|
||||
/* This class is its own key for the purposes of consolidation. */
|
||||
typedef symbolic_binding key_t;
|
||||
|
||||
symbolic_binding (const region *region) : m_region (region) {}
|
||||
bool concrete_p () const final override { return false; }
|
||||
|
||||
hashval_t hash () const
|
||||
{
|
||||
return (intptr_t)m_region;
|
||||
}
|
||||
bool operator== (const symbolic_binding &other) const
|
||||
{
|
||||
return m_region == other.m_region;
|
||||
}
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
|
||||
|
||||
const symbolic_binding *dyn_cast_symbolic_binding () const final override
|
||||
{ return this; }
|
||||
|
||||
const region *get_region () const { return m_region; }
|
||||
|
||||
static int cmp_ptr_ptr (const void *, const void *);
|
||||
|
||||
void mark_deleted () { m_region = reinterpret_cast<const region *> (1); }
|
||||
void mark_empty () { m_region = NULL; }
|
||||
bool is_deleted () const
|
||||
{ return m_region == reinterpret_cast<const region *> (1); }
|
||||
bool is_empty () const { return m_region == NULL; }
|
||||
|
||||
private:
|
||||
const region *m_region;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
template <> struct default_hash_traits<ana::symbolic_binding>
|
||||
: public member_function_hash_traits<ana::symbolic_binding>
|
||||
{
|
||||
static const bool empty_zero_p = true;
|
||||
};
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A mapping from binding_keys to svalues, for use by binding_cluster
|
||||
and compound_svalue. */
|
||||
|
||||
class binding_map
|
||||
{
|
||||
public:
|
||||
typedef hash_map <const binding_key *, const svalue *> map_t;
|
||||
typedef map_t::iterator iterator_t;
|
||||
|
||||
binding_map () : m_map () {}
|
||||
binding_map (const binding_map &other);
|
||||
binding_map& operator=(const binding_map &other);
|
||||
|
||||
bool operator== (const binding_map &other) const;
|
||||
bool operator!= (const binding_map &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
hashval_t hash () const;
|
||||
|
||||
const svalue *get (const binding_key *key) const
|
||||
{
|
||||
const svalue **slot = const_cast<map_t &> (m_map).get (key);
|
||||
if (slot)
|
||||
return *slot;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
bool put (const binding_key *k, const svalue *v)
|
||||
{
|
||||
gcc_assert (v);
|
||||
return m_map.put (k, v);
|
||||
}
|
||||
|
||||
void remove (const binding_key *k) { m_map.remove (k); }
|
||||
void empty () { m_map.empty (); }
|
||||
|
||||
iterator_t begin () const { return m_map.begin (); }
|
||||
iterator_t end () const { return m_map.end (); }
|
||||
size_t elements () const { return m_map.elements (); }
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
|
||||
void dump (bool simple) const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
bool apply_ctor_to_region (const region *parent_reg, tree ctor,
|
||||
region_model_manager *mgr);
|
||||
|
||||
static int cmp (const binding_map &map1, const binding_map &map2);
|
||||
|
||||
void remove_overlapping_bindings (store_manager *mgr,
|
||||
const binding_key *drop_key,
|
||||
uncertainty_t *uncertainty,
|
||||
svalue_set *maybe_live_values,
|
||||
bool always_overlap);
|
||||
|
||||
private:
|
||||
void get_overlapping_bindings (const binding_key *key,
|
||||
auto_vec<const binding_key *> *out);
|
||||
bool apply_ctor_val_to_range (const region *parent_reg,
|
||||
region_model_manager *mgr,
|
||||
tree min_index, tree max_index,
|
||||
tree val);
|
||||
bool apply_ctor_pair_to_child_region (const region *parent_reg,
|
||||
region_model_manager *mgr,
|
||||
tree index, tree val);
|
||||
|
||||
map_t m_map;
|
||||
};
|
||||
|
||||
/* Concept: BindingVisitor, for use by binding_cluster::for_each_binding
|
||||
and store::for_each_binding.
|
||||
|
||||
Should implement:
|
||||
void on_binding (const binding_key *key, const svalue *&sval);
|
||||
*/
|
||||
|
||||
/* All of the bindings within a store for regions that share the same
|
||||
base region. */
|
||||
|
||||
class binding_cluster
|
||||
{
|
||||
public:
|
||||
friend class store;
|
||||
|
||||
typedef hash_map <const binding_key *, const svalue *> map_t;
|
||||
typedef map_t::iterator iterator_t;
|
||||
|
||||
binding_cluster (const region *base_region);
|
||||
binding_cluster (const binding_cluster &other);
|
||||
binding_cluster& operator=(const binding_cluster &other);
|
||||
|
||||
bool operator== (const binding_cluster &other) const;
|
||||
bool operator!= (const binding_cluster &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
hashval_t hash () const;
|
||||
|
||||
bool symbolic_p () const;
|
||||
|
||||
const region *get_base_region () const { return m_base_region; }
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
|
||||
void dump (bool simple) const;
|
||||
|
||||
void validate () const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
void bind (store_manager *mgr, const region *, const svalue *);
|
||||
|
||||
void clobber_region (store_manager *mgr, const region *reg);
|
||||
void purge_region (store_manager *mgr, const region *reg);
|
||||
void fill_region (store_manager *mgr, const region *reg, const svalue *sval);
|
||||
void zero_fill_region (store_manager *mgr, const region *reg);
|
||||
void mark_region_as_unknown (store_manager *mgr,
|
||||
const region *reg_to_bind,
|
||||
const region *reg_for_overlap,
|
||||
uncertainty_t *uncertainty,
|
||||
svalue_set *maybe_live_values);
|
||||
void purge_state_involving (const svalue *sval,
|
||||
region_model_manager *sval_mgr);
|
||||
|
||||
const svalue *get_binding (store_manager *mgr, const region *reg) const;
|
||||
const svalue *get_binding_recursive (store_manager *mgr,
|
||||
const region *reg) const;
|
||||
const svalue *get_any_binding (store_manager *mgr,
|
||||
const region *reg) const;
|
||||
const svalue *maybe_get_compound_binding (store_manager *mgr,
|
||||
const region *reg) const;
|
||||
|
||||
void remove_overlapping_bindings (store_manager *mgr, const region *reg,
|
||||
uncertainty_t *uncertainty,
|
||||
svalue_set *maybe_live_values);
|
||||
|
||||
template <typename T>
|
||||
void for_each_value (void (*cb) (const svalue *sval, T user_data),
|
||||
T user_data) const
|
||||
{
|
||||
for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
|
||||
cb ((*iter).second, user_data);
|
||||
}
|
||||
|
||||
static bool can_merge_p (const binding_cluster *cluster_a,
|
||||
const binding_cluster *cluster_b,
|
||||
binding_cluster *out_cluster,
|
||||
store *out_store,
|
||||
store_manager *mgr,
|
||||
model_merger *merger);
|
||||
void make_unknown_relative_to (const binding_cluster *other_cluster,
|
||||
store *out_store,
|
||||
store_manager *mgr);
|
||||
|
||||
void mark_as_escaped ();
|
||||
void on_unknown_fncall (const gcall *call, store_manager *mgr,
|
||||
const conjured_purge &p);
|
||||
void on_asm (const gasm *stmt, store_manager *mgr,
|
||||
const conjured_purge &p);
|
||||
|
||||
bool escaped_p () const;
|
||||
bool touched_p () const { return m_touched; }
|
||||
|
||||
bool redundant_p () const;
|
||||
bool empty_p () const { return m_map.elements () == 0; }
|
||||
|
||||
void get_representative_path_vars (const region_model *model,
|
||||
svalue_set *visited,
|
||||
const region *base_reg,
|
||||
const svalue *sval,
|
||||
auto_vec<path_var> *out_pvs) const;
|
||||
|
||||
const svalue *maybe_get_simple_value (store_manager *mgr) const;
|
||||
|
||||
template <typename BindingVisitor>
|
||||
void for_each_binding (BindingVisitor &v) const
|
||||
{
|
||||
for (map_t::iterator iter = m_map.begin (); iter != m_map.end (); ++iter)
|
||||
{
|
||||
const binding_key *key = (*iter).first;
|
||||
const svalue *&sval = (*iter).second;
|
||||
v.on_binding (key, sval);
|
||||
}
|
||||
}
|
||||
|
||||
iterator_t begin () const { return m_map.begin (); }
|
||||
iterator_t end () const { return m_map.end (); }
|
||||
|
||||
const binding_map &get_map () const { return m_map; }
|
||||
|
||||
private:
|
||||
const svalue *get_any_value (const binding_key *key) const;
|
||||
void bind_compound_sval (store_manager *mgr,
|
||||
const region *reg,
|
||||
const compound_svalue *compound_sval);
|
||||
void bind_key (const binding_key *key, const svalue *sval);
|
||||
|
||||
const region *m_base_region;
|
||||
|
||||
binding_map m_map;
|
||||
|
||||
/* Has a pointer to this cluster "escaped" into a part of the program
|
||||
we don't know about (via a call to a function with an unknown body,
|
||||
or by being passed in as a pointer param of a "top-level" function call).
|
||||
Such regions could be overwritten when other such functions are called,
|
||||
even if the region is no longer reachable by pointers that we are
|
||||
tracking. */
|
||||
bool m_escaped;
|
||||
|
||||
/* Has this cluster been written to via a symbolic binding?
|
||||
If so, then we don't know anything about unbound subregions,
|
||||
so we can't use initial_svalue, treat them as uninitialized, or
|
||||
inherit values from a parent region. */
|
||||
bool m_touched;
|
||||
};
|
||||
|
||||
/* The mapping from regions to svalues.
|
||||
This is actually expressed by subdividing into clusters, to better
|
||||
handle aliasing. */
|
||||
|
||||
class store
|
||||
{
|
||||
public:
|
||||
typedef hash_map <const region *, binding_cluster *> cluster_map_t;
|
||||
|
||||
store ();
|
||||
store (const store &other);
|
||||
~store ();
|
||||
|
||||
store &operator= (const store &other);
|
||||
|
||||
bool operator== (const store &other) const;
|
||||
bool operator!= (const store &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
hashval_t hash () const;
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool summarize, bool multiline,
|
||||
store_manager *mgr) const;
|
||||
void dump (bool simple) const;
|
||||
void summarize_to_pp (pretty_printer *pp, bool simple) const;
|
||||
|
||||
void validate () const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
const svalue *get_any_binding (store_manager *mgr, const region *reg) const;
|
||||
|
||||
bool called_unknown_fn_p () const { return m_called_unknown_fn; }
|
||||
|
||||
void set_value (store_manager *mgr, const region *lhs_reg,
|
||||
const svalue *rhs_sval,
|
||||
uncertainty_t *uncertainty);
|
||||
void clobber_region (store_manager *mgr, const region *reg);
|
||||
void purge_region (store_manager *mgr, const region *reg);
|
||||
void fill_region (store_manager *mgr, const region *reg, const svalue *sval);
|
||||
void zero_fill_region (store_manager *mgr, const region *reg);
|
||||
void mark_region_as_unknown (store_manager *mgr, const region *reg,
|
||||
uncertainty_t *uncertainty,
|
||||
svalue_set *maybe_live_values);
|
||||
void purge_state_involving (const svalue *sval,
|
||||
region_model_manager *sval_mgr);
|
||||
|
||||
const binding_cluster *get_cluster (const region *base_reg) const;
|
||||
binding_cluster *get_cluster (const region *base_reg);
|
||||
binding_cluster *get_or_create_cluster (const region *base_reg);
|
||||
void purge_cluster (const region *base_reg);
|
||||
|
||||
template <typename T>
|
||||
void for_each_cluster (void (*cb) (const region *base_reg, T user_data),
|
||||
T user_data) const
|
||||
{
|
||||
for (cluster_map_t::iterator iter = m_cluster_map.begin ();
|
||||
iter != m_cluster_map.end (); ++iter)
|
||||
cb ((*iter).first, user_data);
|
||||
}
|
||||
|
||||
static bool can_merge_p (const store *store_a, const store *store_b,
|
||||
store *out_store, store_manager *mgr,
|
||||
model_merger *merger);
|
||||
|
||||
void mark_as_escaped (const region *base_reg);
|
||||
void on_unknown_fncall (const gcall *call, store_manager *mgr,
|
||||
const conjured_purge &p);
|
||||
bool escaped_p (const region *reg) const;
|
||||
|
||||
void get_representative_path_vars (const region_model *model,
|
||||
svalue_set *visited,
|
||||
const svalue *sval,
|
||||
auto_vec<path_var> *out_pvs) const;
|
||||
|
||||
cluster_map_t::iterator begin () const { return m_cluster_map.begin (); }
|
||||
cluster_map_t::iterator end () const { return m_cluster_map.end (); }
|
||||
|
||||
tristate eval_alias (const region *base_reg_a,
|
||||
const region *base_reg_b) const;
|
||||
|
||||
template <typename BindingVisitor>
|
||||
void for_each_binding (BindingVisitor &v)
|
||||
{
|
||||
for (cluster_map_t::iterator iter = m_cluster_map.begin ();
|
||||
iter != m_cluster_map.end (); ++iter)
|
||||
(*iter).second->for_each_binding (v);
|
||||
}
|
||||
|
||||
void canonicalize (store_manager *mgr);
|
||||
void loop_replay_fixup (const store *other_store,
|
||||
region_model_manager *mgr);
|
||||
|
||||
void replay_call_summary (call_summary_replay &r,
|
||||
const store &summary);
|
||||
void replay_call_summary_cluster (call_summary_replay &r,
|
||||
const store &summary,
|
||||
const region *base_reg);
|
||||
void on_maybe_live_values (const svalue_set &maybe_live_values);
|
||||
|
||||
private:
|
||||
void remove_overlapping_bindings (store_manager *mgr, const region *reg,
|
||||
uncertainty_t *uncertainty);
|
||||
tristate eval_alias_1 (const region *base_reg_a,
|
||||
const region *base_reg_b) const;
|
||||
|
||||
cluster_map_t m_cluster_map;
|
||||
|
||||
/* If this is true, then unknown code has been called, and so
|
||||
any global variable that isn't currently modelled by the store
|
||||
has unknown state, rather than being in an "initial state".
|
||||
This is to avoid having to mark (and thus explicitly track)
|
||||
every global when an unknown function is called; instead, they
|
||||
can be tracked implicitly. */
|
||||
bool m_called_unknown_fn;
|
||||
};
|
||||
|
||||
/* A class responsible for owning and consolidating binding keys
|
||||
(both concrete and symbolic).
|
||||
Key instances are immutable as far as clients are concerned, so they
|
||||
are provided as "const" ptrs. */
|
||||
|
||||
class store_manager
|
||||
{
|
||||
public:
|
||||
store_manager (region_model_manager *mgr) : m_mgr (mgr) {}
|
||||
|
||||
logger *get_logger () const;
|
||||
|
||||
/* binding consolidation. */
|
||||
const concrete_binding *
|
||||
get_concrete_binding (bit_offset_t start_bit_offset,
|
||||
bit_offset_t size_in_bits);
|
||||
const concrete_binding *
|
||||
get_concrete_binding (const bit_range &bits)
|
||||
{
|
||||
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);
|
||||
|
||||
region_model_manager *get_svalue_manager () const
|
||||
{
|
||||
return m_mgr;
|
||||
}
|
||||
|
||||
void log_stats (logger *logger, bool show_objs) const;
|
||||
|
||||
private:
|
||||
region_model_manager *m_mgr;
|
||||
consolidation_map<concrete_binding> m_concrete_binding_key_mgr;
|
||||
consolidation_map<symbolic_binding> m_symbolic_binding_key_mgr;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_STORE_H */
|
||||
+626
@@ -0,0 +1,626 @@
|
||||
/* "Supergraph" classes that combine CFGs and callgraph into one digraph.
|
||||
Copyright (C) 2019-2024 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_SUPERGRAPH_H
|
||||
#define GCC_ANALYZER_SUPERGRAPH_H
|
||||
|
||||
#include "ordered-hash-map.h"
|
||||
#include "cfg.h"
|
||||
#include "basic-block.h"
|
||||
#include "gimple.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "digraph.h"
|
||||
|
||||
using namespace ana;
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Forward decls, using indentation to show inheritance. */
|
||||
|
||||
class supergraph;
|
||||
class supernode;
|
||||
class superedge;
|
||||
class callgraph_superedge;
|
||||
class call_superedge;
|
||||
class return_superedge;
|
||||
class cfg_superedge;
|
||||
class switch_cfg_superedge;
|
||||
class supercluster;
|
||||
class dot_annotator;
|
||||
|
||||
class logger;
|
||||
|
||||
/* An enum for discriminating between superedge subclasses. */
|
||||
|
||||
enum edge_kind
|
||||
{
|
||||
SUPEREDGE_CFG_EDGE,
|
||||
SUPEREDGE_CALL,
|
||||
SUPEREDGE_RETURN,
|
||||
SUPEREDGE_INTRAPROCEDURAL_CALL
|
||||
};
|
||||
|
||||
/* Flags for controlling the appearance of .dot dumps. */
|
||||
|
||||
enum supergraph_dot_flags
|
||||
{
|
||||
SUPERGRAPH_DOT_SHOW_BBS = (1 << 0)
|
||||
};
|
||||
|
||||
/* A traits struct describing the family of node, edge and digraph
|
||||
classes for supergraphs. */
|
||||
|
||||
struct supergraph_traits
|
||||
{
|
||||
typedef supernode node_t;
|
||||
typedef superedge edge_t;
|
||||
typedef supergraph graph_t;
|
||||
struct dump_args_t
|
||||
{
|
||||
dump_args_t (enum supergraph_dot_flags flags,
|
||||
const dot_annotator *node_annotator)
|
||||
: m_flags (flags),
|
||||
m_node_annotator (node_annotator)
|
||||
{}
|
||||
|
||||
enum supergraph_dot_flags m_flags;
|
||||
const dot_annotator *m_node_annotator;
|
||||
};
|
||||
typedef supercluster cluster_t;
|
||||
};
|
||||
|
||||
/* A class to manage the setting and restoring of statement uids. */
|
||||
|
||||
class saved_uids
|
||||
{
|
||||
public:
|
||||
void make_uid_unique (gimple *stmt);
|
||||
void restore_uids () const;
|
||||
|
||||
private:
|
||||
auto_vec<std::pair<gimple *, unsigned> > m_old_stmt_uids;
|
||||
};
|
||||
|
||||
/* A "supergraph" is a directed graph formed by joining together all CFGs,
|
||||
linking them via interprocedural call and return edges.
|
||||
|
||||
Basic blocks are split at callsites, so that a call statement occurs
|
||||
twice: once at the end of a supernode, and a second instance at the
|
||||
start of the next supernode (to handle the return). */
|
||||
|
||||
class supergraph : public digraph<supergraph_traits>
|
||||
{
|
||||
public:
|
||||
supergraph (logger *logger);
|
||||
~supergraph ();
|
||||
|
||||
supernode *get_node_for_function_entry (const function &fun) const
|
||||
{
|
||||
return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (&fun));
|
||||
}
|
||||
|
||||
supernode *get_node_for_function_exit (const function &fun) const
|
||||
{
|
||||
return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (&fun));
|
||||
}
|
||||
|
||||
supernode *get_node_for_block (basic_block bb) const
|
||||
{
|
||||
return *const_cast <bb_to_node_t &> (m_bb_to_initial_node).get (bb);
|
||||
}
|
||||
|
||||
/* Get the supernode containing the second half of the gcall *
|
||||
at an interprocedural call, within the caller. */
|
||||
supernode *get_caller_next_node (cgraph_edge *edge) const
|
||||
{
|
||||
return (*const_cast <cgraph_edge_to_node_t &>
|
||||
(m_cgraph_edge_to_caller_next_node).get (edge));
|
||||
}
|
||||
|
||||
call_superedge *get_edge_for_call (cgraph_edge *edge) const
|
||||
{
|
||||
return (*const_cast <cgraph_edge_to_call_superedge_t &>
|
||||
(m_cgraph_edge_to_call_superedge).get (edge));
|
||||
}
|
||||
|
||||
return_superedge *get_edge_for_return (cgraph_edge *edge) const
|
||||
{
|
||||
return (*const_cast <cgraph_edge_to_return_superedge_t &>
|
||||
(m_cgraph_edge_to_return_superedge).get (edge));
|
||||
}
|
||||
|
||||
superedge *get_intraprocedural_edge_for_call (cgraph_edge *edge) const
|
||||
{
|
||||
return (*const_cast <cgraph_edge_to_intraproc_superedge_t &>
|
||||
(m_cgraph_edge_to_intraproc_superedge).get (edge));
|
||||
}
|
||||
|
||||
cfg_superedge *get_edge_for_cfg_edge (edge e) const
|
||||
{
|
||||
return (*const_cast <cfg_edge_to_cfg_superedge_t &>
|
||||
(m_cfg_edge_to_cfg_superedge).get (e));
|
||||
}
|
||||
|
||||
supernode *get_supernode_for_stmt (const gimple *stmt) const
|
||||
{
|
||||
return (*const_cast <stmt_to_node_t &>(m_stmt_to_node_t).get
|
||||
(const_cast <gimple *> (stmt)));
|
||||
}
|
||||
|
||||
void dump_dot_to_pp (pretty_printer *pp, const dump_args_t &) const;
|
||||
void dump_dot_to_file (FILE *fp, const dump_args_t &) const;
|
||||
void dump_dot (const char *path, const dump_args_t &) const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
int num_nodes () const { return m_nodes.length (); }
|
||||
int num_edges () const { return m_edges.length (); }
|
||||
|
||||
supernode *get_node_by_index (int idx) const
|
||||
{
|
||||
return m_nodes[idx];
|
||||
}
|
||||
|
||||
unsigned get_num_snodes (const function *fun) const
|
||||
{
|
||||
function_to_num_snodes_t &map
|
||||
= const_cast <function_to_num_snodes_t &>(m_function_to_num_snodes);
|
||||
return *map.get (fun);
|
||||
}
|
||||
|
||||
private:
|
||||
supernode *add_node (function *fun, basic_block bb, gcall *returning_call,
|
||||
gimple_seq phi_nodes);
|
||||
cfg_superedge *add_cfg_edge (supernode *src, supernode *dest, ::edge e);
|
||||
call_superedge *add_call_superedge (supernode *src, supernode *dest,
|
||||
cgraph_edge *cedge);
|
||||
return_superedge *add_return_superedge (supernode *src, supernode *dest,
|
||||
cgraph_edge *cedge);
|
||||
|
||||
/* Data. */
|
||||
|
||||
typedef ordered_hash_map<basic_block, supernode *> bb_to_node_t;
|
||||
bb_to_node_t m_bb_to_initial_node;
|
||||
bb_to_node_t m_bb_to_final_node;
|
||||
|
||||
typedef ordered_hash_map<cgraph_edge *, supernode *> cgraph_edge_to_node_t;
|
||||
cgraph_edge_to_node_t m_cgraph_edge_to_caller_prev_node;
|
||||
cgraph_edge_to_node_t m_cgraph_edge_to_caller_next_node;
|
||||
|
||||
typedef ordered_hash_map< ::edge, cfg_superedge *>
|
||||
cfg_edge_to_cfg_superedge_t;
|
||||
cfg_edge_to_cfg_superedge_t m_cfg_edge_to_cfg_superedge;
|
||||
|
||||
typedef ordered_hash_map<cgraph_edge *, call_superedge *>
|
||||
cgraph_edge_to_call_superedge_t;
|
||||
cgraph_edge_to_call_superedge_t m_cgraph_edge_to_call_superedge;
|
||||
|
||||
typedef ordered_hash_map<cgraph_edge *, return_superedge *>
|
||||
cgraph_edge_to_return_superedge_t;
|
||||
cgraph_edge_to_return_superedge_t m_cgraph_edge_to_return_superedge;
|
||||
|
||||
typedef ordered_hash_map<cgraph_edge *, superedge *>
|
||||
cgraph_edge_to_intraproc_superedge_t;
|
||||
cgraph_edge_to_intraproc_superedge_t m_cgraph_edge_to_intraproc_superedge;
|
||||
|
||||
typedef ordered_hash_map<gimple *, supernode *> stmt_to_node_t;
|
||||
stmt_to_node_t m_stmt_to_node_t;
|
||||
|
||||
typedef hash_map<const function *, unsigned> function_to_num_snodes_t;
|
||||
function_to_num_snodes_t m_function_to_num_snodes;
|
||||
|
||||
saved_uids m_stmt_uids;
|
||||
};
|
||||
|
||||
/* A node within a supergraph. */
|
||||
|
||||
class supernode : public dnode<supergraph_traits>
|
||||
{
|
||||
public:
|
||||
supernode (function *fun, basic_block bb, gcall *returning_call,
|
||||
gimple_seq phi_nodes, int index)
|
||||
: m_fun (fun), m_bb (bb), m_returning_call (returning_call),
|
||||
m_phi_nodes (phi_nodes), m_index (index)
|
||||
{}
|
||||
|
||||
function *get_function () const { return m_fun; }
|
||||
|
||||
bool entry_p () const
|
||||
{
|
||||
return m_bb == ENTRY_BLOCK_PTR_FOR_FN (m_fun);
|
||||
}
|
||||
|
||||
bool return_p () const
|
||||
{
|
||||
return m_bb == EXIT_BLOCK_PTR_FOR_FN (m_fun);
|
||||
}
|
||||
|
||||
void dump_dot (graphviz_out *gv, const dump_args_t &args) const override;
|
||||
void dump_dot_id (pretty_printer *pp) const;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
location_t get_start_location () const;
|
||||
location_t get_end_location () const;
|
||||
|
||||
/* Returns iterator at the start of the list of phi nodes, if any. */
|
||||
gphi_iterator start_phis ()
|
||||
{
|
||||
gimple_seq *pseq = &m_phi_nodes;
|
||||
|
||||
/* Adapted from gsi_start_1. */
|
||||
gphi_iterator i;
|
||||
|
||||
i.ptr = gimple_seq_first (*pseq);
|
||||
i.seq = pseq;
|
||||
i.bb = i.ptr ? gimple_bb (i.ptr) : NULL;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
gcall *get_returning_call () const
|
||||
{
|
||||
return m_returning_call;
|
||||
}
|
||||
|
||||
gimple *get_last_stmt () const
|
||||
{
|
||||
if (m_stmts.length () == 0)
|
||||
return NULL;
|
||||
return m_stmts[m_stmts.length () - 1];
|
||||
}
|
||||
|
||||
gcall *get_final_call () const
|
||||
{
|
||||
gimple *stmt = get_last_stmt ();
|
||||
if (stmt == NULL)
|
||||
return NULL;
|
||||
return dyn_cast<gcall *> (stmt);
|
||||
}
|
||||
|
||||
unsigned int get_stmt_index (const gimple *stmt) const;
|
||||
|
||||
tree get_label () const;
|
||||
|
||||
function * const m_fun; // alternatively could be stored as runs of indices within the supergraph
|
||||
const basic_block m_bb;
|
||||
gcall * const m_returning_call; // for handling the result of a returned call
|
||||
gimple_seq m_phi_nodes; // ptr to that of the underlying BB, for the first supernode for the BB
|
||||
auto_vec<gimple *> m_stmts;
|
||||
const int m_index; /* unique within the supergraph as a whole. */
|
||||
};
|
||||
|
||||
/* An abstract base class encapsulating an edge within a supergraph.
|
||||
Edges can be CFG edges, or calls/returns for callgraph edges. */
|
||||
|
||||
class superedge : public dedge<supergraph_traits>
|
||||
{
|
||||
public:
|
||||
virtual ~superedge () {}
|
||||
|
||||
void dump (pretty_printer *pp) const;
|
||||
void dump () const;
|
||||
void dump_dot (graphviz_out *gv, const dump_args_t &args)
|
||||
const final override;
|
||||
|
||||
virtual void dump_label_to_pp (pretty_printer *pp,
|
||||
bool user_facing) const = 0;
|
||||
|
||||
json::object *to_json () const;
|
||||
|
||||
enum edge_kind get_kind () const { return m_kind; }
|
||||
|
||||
virtual cfg_superedge *dyn_cast_cfg_superedge () { return NULL; }
|
||||
virtual const cfg_superedge *dyn_cast_cfg_superedge () const { return NULL; }
|
||||
virtual const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const { return NULL; }
|
||||
virtual callgraph_superedge *dyn_cast_callgraph_superedge () { return NULL; }
|
||||
virtual const callgraph_superedge *dyn_cast_callgraph_superedge () const { return NULL; }
|
||||
virtual call_superedge *dyn_cast_call_superedge () { return NULL; }
|
||||
virtual const call_superedge *dyn_cast_call_superedge () const { return NULL; }
|
||||
virtual return_superedge *dyn_cast_return_superedge () { return NULL; }
|
||||
virtual const return_superedge *dyn_cast_return_superedge () const { return NULL; }
|
||||
|
||||
::edge get_any_cfg_edge () const;
|
||||
cgraph_edge *get_any_callgraph_edge () const;
|
||||
|
||||
label_text get_description (bool user_facing) const;
|
||||
|
||||
protected:
|
||||
superedge (supernode *src, supernode *dest, enum edge_kind kind)
|
||||
: dedge<supergraph_traits> (src, dest),
|
||||
m_kind (kind)
|
||||
{}
|
||||
|
||||
public:
|
||||
const enum edge_kind m_kind;
|
||||
};
|
||||
|
||||
/* An ID representing an expression at a callsite:
|
||||
either a parameter index, or the return value (or unknown). */
|
||||
|
||||
class callsite_expr
|
||||
{
|
||||
public:
|
||||
callsite_expr () : m_val (-1) {}
|
||||
|
||||
static callsite_expr from_zero_based_param (int idx)
|
||||
{
|
||||
return callsite_expr (idx + 1);
|
||||
}
|
||||
|
||||
static callsite_expr from_return_value ()
|
||||
{
|
||||
return callsite_expr (0);
|
||||
}
|
||||
|
||||
bool param_p () const
|
||||
{
|
||||
return m_val > 0;
|
||||
}
|
||||
|
||||
bool return_value_p () const
|
||||
{
|
||||
return m_val == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
callsite_expr (int val) : m_val (val) {}
|
||||
|
||||
int m_val; /* 1-based parm, 0 for return value, or -1 for "unknown". */
|
||||
};
|
||||
|
||||
/* A subclass of superedge with an associated callgraph edge (either a
|
||||
call or a return). */
|
||||
|
||||
class callgraph_superedge : public superedge
|
||||
{
|
||||
public:
|
||||
callgraph_superedge (supernode *src, supernode *dst, enum edge_kind kind,
|
||||
cgraph_edge *cedge)
|
||||
: superedge (src, dst, kind),
|
||||
m_cedge (cedge)
|
||||
{}
|
||||
|
||||
void dump_label_to_pp (pretty_printer *pp, bool user_facing) const
|
||||
final override;
|
||||
|
||||
callgraph_superedge *dyn_cast_callgraph_superedge () final override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
const callgraph_superedge *dyn_cast_callgraph_superedge () const
|
||||
final override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
function *get_callee_function () const;
|
||||
function *get_caller_function () const;
|
||||
tree get_callee_decl () const;
|
||||
tree get_caller_decl () const;
|
||||
gcall *get_call_stmt () const;
|
||||
tree get_arg_for_parm (tree parm, callsite_expr *out) const;
|
||||
tree get_parm_for_arg (tree arg, callsite_expr *out) const;
|
||||
tree map_expr_from_caller_to_callee (tree caller_expr,
|
||||
callsite_expr *out) const;
|
||||
tree map_expr_from_callee_to_caller (tree callee_expr,
|
||||
callsite_expr *out) const;
|
||||
|
||||
cgraph_edge *const m_cedge;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
template <>
|
||||
template <>
|
||||
inline bool
|
||||
is_a_helper <const callgraph_superedge *>::test (const superedge *sedge)
|
||||
{
|
||||
return (sedge->get_kind () == SUPEREDGE_INTRAPROCEDURAL_CALL
|
||||
|| sedge->get_kind () == SUPEREDGE_CALL
|
||||
|| sedge->get_kind () == SUPEREDGE_RETURN);
|
||||
}
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A subclass of superedge representing an interprocedural call. */
|
||||
|
||||
class call_superedge : public callgraph_superedge
|
||||
{
|
||||
public:
|
||||
call_superedge (supernode *src, supernode *dst, cgraph_edge *cedge)
|
||||
: callgraph_superedge (src, dst, SUPEREDGE_CALL, cedge)
|
||||
{}
|
||||
|
||||
call_superedge *dyn_cast_call_superedge () final override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
const call_superedge *dyn_cast_call_superedge () const final override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
return_superedge *get_edge_for_return (const supergraph &sg) const
|
||||
{
|
||||
return sg.get_edge_for_return (m_cedge);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
template <>
|
||||
template <>
|
||||
inline bool
|
||||
is_a_helper <const call_superedge *>::test (const superedge *sedge)
|
||||
{
|
||||
return sedge->get_kind () == SUPEREDGE_CALL;
|
||||
}
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A subclass of superedge represesnting an interprocedural return. */
|
||||
|
||||
class return_superedge : public callgraph_superedge
|
||||
{
|
||||
public:
|
||||
return_superedge (supernode *src, supernode *dst, cgraph_edge *cedge)
|
||||
: callgraph_superedge (src, dst, SUPEREDGE_RETURN, cedge)
|
||||
{}
|
||||
|
||||
return_superedge *dyn_cast_return_superedge () final override { return this; }
|
||||
const return_superedge *dyn_cast_return_superedge () const final override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
call_superedge *get_edge_for_call (const supergraph &sg) const
|
||||
{
|
||||
return sg.get_edge_for_call (m_cedge);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
template <>
|
||||
template <>
|
||||
inline bool
|
||||
is_a_helper <const return_superedge *>::test (const superedge *sedge)
|
||||
{
|
||||
return sedge->get_kind () == SUPEREDGE_RETURN;
|
||||
}
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A subclass of superedge that corresponds to a CFG edge. */
|
||||
|
||||
class cfg_superedge : public superedge
|
||||
{
|
||||
public:
|
||||
cfg_superedge (supernode *src, supernode *dst, ::edge e)
|
||||
: superedge (src, dst, SUPEREDGE_CFG_EDGE),
|
||||
m_cfg_edge (e)
|
||||
{}
|
||||
|
||||
void dump_label_to_pp (pretty_printer *pp, bool user_facing) const override;
|
||||
cfg_superedge *dyn_cast_cfg_superedge () final override { return this; }
|
||||
const cfg_superedge *dyn_cast_cfg_superedge () const final override { return this; }
|
||||
|
||||
::edge get_cfg_edge () const { return m_cfg_edge; }
|
||||
int get_flags () const { return m_cfg_edge->flags; }
|
||||
int true_value_p () const { return get_flags () & EDGE_TRUE_VALUE; }
|
||||
int false_value_p () const { return get_flags () & EDGE_FALSE_VALUE; }
|
||||
int back_edge_p () const { return get_flags () & EDGE_DFS_BACK; }
|
||||
|
||||
size_t get_phi_arg_idx () const;
|
||||
tree get_phi_arg (const gphi *phi) const;
|
||||
|
||||
location_t get_goto_locus () const { return m_cfg_edge->goto_locus; }
|
||||
|
||||
private:
|
||||
const ::edge m_cfg_edge;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
template <>
|
||||
template <>
|
||||
inline bool
|
||||
is_a_helper <const cfg_superedge *>::test (const superedge *sedge)
|
||||
{
|
||||
return sedge->get_kind () == SUPEREDGE_CFG_EDGE;
|
||||
}
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* A subclass for edges from switch statements, retaining enough
|
||||
information to identify the pertinent cases, and for adding labels
|
||||
when rendering via graphviz. */
|
||||
|
||||
class switch_cfg_superedge : public cfg_superedge {
|
||||
public:
|
||||
switch_cfg_superedge (supernode *src, supernode *dst, ::edge e);
|
||||
|
||||
const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const
|
||||
final override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void dump_label_to_pp (pretty_printer *pp, bool user_facing) const
|
||||
final override;
|
||||
|
||||
gswitch *get_switch_stmt () const
|
||||
{
|
||||
return as_a <gswitch *> (m_src->get_last_stmt ());
|
||||
}
|
||||
|
||||
const vec<tree> &get_case_labels () const { return m_case_labels; }
|
||||
|
||||
bool implicitly_created_default_p () const;
|
||||
|
||||
private:
|
||||
auto_vec<tree> m_case_labels;
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
template <>
|
||||
template <>
|
||||
inline bool
|
||||
is_a_helper <const switch_cfg_superedge *>::test (const superedge *sedge)
|
||||
{
|
||||
return sedge->dyn_cast_switch_cfg_superedge () != NULL;
|
||||
}
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Base class for adding additional content to the .dot output
|
||||
for a supergraph. */
|
||||
|
||||
class dot_annotator
|
||||
{
|
||||
public:
|
||||
virtual ~dot_annotator () {}
|
||||
virtual bool add_node_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
|
||||
const supernode &n ATTRIBUTE_UNUSED,
|
||||
bool within_table ATTRIBUTE_UNUSED)
|
||||
const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual void add_stmt_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
|
||||
const gimple *stmt ATTRIBUTE_UNUSED,
|
||||
bool within_row ATTRIBUTE_UNUSED)
|
||||
const {}
|
||||
virtual bool add_after_node_annotations (graphviz_out *gv ATTRIBUTE_UNUSED,
|
||||
const supernode &n ATTRIBUTE_UNUSED)
|
||||
const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
extern cgraph_edge *supergraph_call_edge (function *fun, const gimple *stmt);
|
||||
extern function *get_ultimate_function_for_cgraph_edge (cgraph_edge *edge);
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_SUPERGRAPH_H */
|
||||
+1749
File diff suppressed because it is too large
Load Diff
+53
@@ -0,0 +1,53 @@
|
||||
/* Base class for svalues and regions.
|
||||
Copyright (C) 2023-2024 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_SYMBOL_H
|
||||
#define GCC_ANALYZER_SYMBOL_H
|
||||
|
||||
#include "analyzer/complexity.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Base class for svalues and regions: has a complexity and a numeric ID. */
|
||||
|
||||
class symbol
|
||||
{
|
||||
public:
|
||||
typedef unsigned id_t;
|
||||
|
||||
const complexity &get_complexity () const { return m_complexity; }
|
||||
|
||||
id_t get_id () const { return m_id; }
|
||||
static int cmp_ids (const symbol *s1, const symbol *s2);
|
||||
|
||||
protected:
|
||||
symbol (complexity c, unsigned id)
|
||||
: m_complexity (c),
|
||||
m_id (id)
|
||||
{}
|
||||
|
||||
private:
|
||||
complexity m_complexity;
|
||||
id_t m_id; // for deterministic sorting at this stage, for dumps
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_SYMBOL_H */
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/* Trimming an exploded graph to a subset of nodes and edges.
|
||||
Copyright (C) 2021-2024 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_TRIMMED_GRAPH_H
|
||||
#define GCC_ANALYZER_TRIMMED_GRAPH_H
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Forward decls. */
|
||||
|
||||
class trimmed_node;
|
||||
class trimmed_edge;
|
||||
class trimmed_graph;
|
||||
class trimmed_cluster;
|
||||
|
||||
/* A traits class for trimming a digraph to a subset of nodes and edges. */
|
||||
|
||||
struct tg_traits
|
||||
{
|
||||
typedef trimmed_node node_t;
|
||||
typedef trimmed_edge edge_t;
|
||||
typedef trimmed_graph graph_t;
|
||||
struct dump_args_t
|
||||
{
|
||||
typedef typename eg_traits::dump_args_t inner_args_t;
|
||||
|
||||
dump_args_t (const inner_args_t &inner_args)
|
||||
: m_inner_args (inner_args)
|
||||
{
|
||||
}
|
||||
|
||||
const inner_args_t &m_inner_args;
|
||||
};
|
||||
typedef trimmed_cluster cluster_t;
|
||||
};
|
||||
|
||||
/* A node within the trimmed_graph, corresponding to an "inner node"
|
||||
within the original exploded_graph. */
|
||||
|
||||
class trimmed_node : public dnode<tg_traits>
|
||||
{
|
||||
public:
|
||||
trimmed_node (const exploded_node *inner_node)
|
||||
: m_inner_node (inner_node) {}
|
||||
|
||||
void dump_dot (graphviz_out *gv,
|
||||
const dump_args_t &args) const final override;
|
||||
|
||||
private:
|
||||
const exploded_node *m_inner_node;
|
||||
};
|
||||
|
||||
/* An edge within the trimmed_graph, corresponding to an "inner edge"
|
||||
within the original exploded_graph. */
|
||||
|
||||
class trimmed_edge : public dedge<tg_traits>
|
||||
{
|
||||
public:
|
||||
trimmed_edge (trimmed_node *src, trimmed_node *dest,
|
||||
const exploded_edge *inner_edge);
|
||||
|
||||
void dump_dot (graphviz_out *gv,
|
||||
const dump_args_t &args) const final override;
|
||||
|
||||
private:
|
||||
const exploded_edge *m_inner_edge;
|
||||
};
|
||||
|
||||
/* A digraph for trimming an exploded_graph to the subset of nodes and edges
|
||||
from which paths reach INNER_DST_NODE (along with a precanned way to print
|
||||
these in .dot form). */
|
||||
|
||||
class trimmed_graph : public digraph <tg_traits>
|
||||
{
|
||||
public:
|
||||
trimmed_graph (const exploded_graph &inner_graph,
|
||||
const exploded_node *inner_dst_node);
|
||||
|
||||
bool contains_p (const exploded_edge *eedge) const
|
||||
{
|
||||
hash_set <const exploded_edge *> & mut
|
||||
= const_cast <hash_set <const exploded_edge *> &> (m_eedges);
|
||||
return mut.contains (eedge);
|
||||
}
|
||||
|
||||
void log_stats (logger *logger) const;
|
||||
|
||||
private:
|
||||
/* The subset of nodes in the inner graph that are in the
|
||||
trimmed graph. */
|
||||
hash_set <const exploded_node *> m_enodes;
|
||||
/* Likewise for edges. */
|
||||
hash_set <const exploded_edge *> m_eedges;
|
||||
|
||||
typedef hash_map<const exploded_node *, trimmed_node *> map_t;
|
||||
map_t m_map_from_enode_to_tnode;
|
||||
};
|
||||
|
||||
class trimmed_cluster : public cluster <tg_traits>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* GCC_ANALYZER_TRIMMED_GRAPH_H */
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
/* Compiler compatibility macros
|
||||
Copyright (C) 1991-2024 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
/* For ease of writing code which uses GCC extensions but needs to be
|
||||
portable to other compilers, we provide the GCC_VERSION macro that
|
||||
simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
|
||||
wrappers around __attribute__. Also, __extension__ will be #defined
|
||||
to nothing if it doesn't work. See below. */
|
||||
|
||||
#ifndef _ANSIDECL_H
|
||||
#define _ANSIDECL_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Every source file includes this file,
|
||||
so they will all get the switch for lint. */
|
||||
/* LINTLIBRARY */
|
||||
|
||||
/* Using MACRO(x,y) in cpp #if conditionals does not work with some
|
||||
older preprocessors. Thus we can't define something like this:
|
||||
|
||||
#define HAVE_GCC_VERSION(MAJOR, MINOR) \
|
||||
(__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
|
||||
|
||||
and then test "#if HAVE_GCC_VERSION(2,7)".
|
||||
|
||||
So instead we use the macro below and test it against specific values. */
|
||||
|
||||
/* This macro simplifies testing whether we are using gcc, and if it
|
||||
is of a particular minimum version. (Both major & minor numbers are
|
||||
significant.) This macro will evaluate to 0 if we are not using
|
||||
gcc at all. */
|
||||
#ifndef GCC_VERSION
|
||||
#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
|
||||
#endif /* GCC_VERSION */
|
||||
|
||||
/* inline requires special treatment; it's in C99, and GCC >=2.7 supports
|
||||
it too, but it's not in C89. */
|
||||
#undef inline
|
||||
#if (!defined(__cplusplus) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__))
|
||||
/* it's a keyword */
|
||||
#else
|
||||
# if GCC_VERSION >= 2007
|
||||
# define inline __inline__ /* __inline__ prevents -pedantic warnings */
|
||||
# else
|
||||
# define inline /* nothing */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define macros for some gcc attributes. This permits us to use the
|
||||
macros freely, and know that they will come into play for the
|
||||
version of gcc in which they are supported. */
|
||||
|
||||
#if (GCC_VERSION < 2007)
|
||||
# define __attribute__(x)
|
||||
#endif
|
||||
|
||||
/* Attribute __malloc__ on functions was valid as of gcc 2.96. */
|
||||
#ifndef ATTRIBUTE_MALLOC
|
||||
# if (GCC_VERSION >= 2096)
|
||||
# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
|
||||
# else
|
||||
# define ATTRIBUTE_MALLOC
|
||||
# endif /* GNUC >= 2.96 */
|
||||
#endif /* ATTRIBUTE_MALLOC */
|
||||
|
||||
/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5. For
|
||||
g++ an attribute on a label must be followed by a semicolon. */
|
||||
#ifndef ATTRIBUTE_UNUSED_LABEL
|
||||
# ifndef __cplusplus
|
||||
# if GCC_VERSION >= 2093
|
||||
# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
|
||||
# else
|
||||
# define ATTRIBUTE_UNUSED_LABEL
|
||||
# endif
|
||||
# else
|
||||
# if GCC_VERSION >= 4005
|
||||
# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ;
|
||||
# else
|
||||
# define ATTRIBUTE_UNUSED_LABEL
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Similarly to ARG_UNUSED below. Prior to GCC 3.4, the C++ frontend
|
||||
couldn't parse attributes placed after the identifier name, and now
|
||||
the entire compiler is built with C++. */
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
#if GCC_VERSION >= 3004
|
||||
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
|
||||
#else
|
||||
#define ATTRIBUTE_UNUSED
|
||||
#endif
|
||||
#endif /* ATTRIBUTE_UNUSED */
|
||||
|
||||
/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the
|
||||
identifier name. */
|
||||
#if ! defined(__cplusplus) || (GCC_VERSION >= 3004)
|
||||
# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED
|
||||
#else /* !__cplusplus || GNUC >= 3.4 */
|
||||
# define ARG_UNUSED(NAME) NAME
|
||||
#endif /* !__cplusplus || GNUC >= 3.4 */
|
||||
|
||||
#ifndef ATTRIBUTE_NORETURN
|
||||
#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
|
||||
#endif /* ATTRIBUTE_NORETURN */
|
||||
|
||||
/* Attribute `nonnull' was valid as of gcc 3.3. */
|
||||
#ifndef ATTRIBUTE_NONNULL
|
||||
# if (GCC_VERSION >= 3003)
|
||||
# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m)))
|
||||
# else
|
||||
# define ATTRIBUTE_NONNULL(m)
|
||||
# endif /* GNUC >= 3.3 */
|
||||
#endif /* ATTRIBUTE_NONNULL */
|
||||
|
||||
/* Attribute `returns_nonnull' was valid as of gcc 4.9. */
|
||||
#ifndef ATTRIBUTE_RETURNS_NONNULL
|
||||
# if (GCC_VERSION >= 4009)
|
||||
# define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__))
|
||||
# else
|
||||
# define ATTRIBUTE_RETURNS_NONNULL
|
||||
# endif /* GNUC >= 4.9 */
|
||||
#endif /* ATTRIBUTE_RETURNS_NONNULL */
|
||||
|
||||
/* Attribute `pure' was valid as of gcc 3.0. */
|
||||
#ifndef ATTRIBUTE_PURE
|
||||
# if (GCC_VERSION >= 3000)
|
||||
# define ATTRIBUTE_PURE __attribute__ ((__pure__))
|
||||
# else
|
||||
# define ATTRIBUTE_PURE
|
||||
# endif /* GNUC >= 3.0 */
|
||||
#endif /* ATTRIBUTE_PURE */
|
||||
|
||||
/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL.
|
||||
This was the case for the `printf' format attribute by itself
|
||||
before GCC 3.3, but as of 3.3 we need to add the `nonnull'
|
||||
attribute to retain this behavior. */
|
||||
#ifndef ATTRIBUTE_PRINTF
|
||||
#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m)
|
||||
#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
|
||||
#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
|
||||
#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
|
||||
#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
|
||||
#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
|
||||
#endif /* ATTRIBUTE_PRINTF */
|
||||
|
||||
/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on
|
||||
a function pointer. Format attributes were allowed on function
|
||||
pointers as of gcc 3.1. */
|
||||
#ifndef ATTRIBUTE_FPTR_PRINTF
|
||||
# if (GCC_VERSION >= 3001)
|
||||
# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n)
|
||||
# else
|
||||
# define ATTRIBUTE_FPTR_PRINTF(m, n)
|
||||
# endif /* GNUC >= 3.1 */
|
||||
# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2)
|
||||
# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3)
|
||||
# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4)
|
||||
# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5)
|
||||
# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6)
|
||||
#endif /* ATTRIBUTE_FPTR_PRINTF */
|
||||
|
||||
/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A
|
||||
NULL format specifier was allowed as of gcc 3.3. */
|
||||
#ifndef ATTRIBUTE_NULL_PRINTF
|
||||
# if (GCC_VERSION >= 3003)
|
||||
# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
|
||||
# else
|
||||
# define ATTRIBUTE_NULL_PRINTF(m, n)
|
||||
# endif /* GNUC >= 3.3 */
|
||||
# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2)
|
||||
# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3)
|
||||
# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4)
|
||||
# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5)
|
||||
# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
|
||||
#endif /* ATTRIBUTE_NULL_PRINTF */
|
||||
|
||||
/* Attribute `sentinel' was valid as of gcc 3.5. */
|
||||
#ifndef ATTRIBUTE_SENTINEL
|
||||
# if (GCC_VERSION >= 3005)
|
||||
# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__))
|
||||
# else
|
||||
# define ATTRIBUTE_SENTINEL
|
||||
# endif /* GNUC >= 3.5 */
|
||||
#endif /* ATTRIBUTE_SENTINEL */
|
||||
|
||||
|
||||
#ifndef ATTRIBUTE_ALIGNED_ALIGNOF
|
||||
# if (GCC_VERSION >= 3000)
|
||||
# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m))))
|
||||
# else
|
||||
# define ATTRIBUTE_ALIGNED_ALIGNOF(m)
|
||||
# endif /* GNUC >= 3.0 */
|
||||
#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */
|
||||
|
||||
/* Useful for structures whose layout must match some binary specification
|
||||
regardless of the alignment and padding qualities of the compiler. */
|
||||
#ifndef ATTRIBUTE_PACKED
|
||||
# define ATTRIBUTE_PACKED __attribute__ ((packed))
|
||||
#endif
|
||||
|
||||
/* Attribute `hot' and `cold' was valid as of gcc 4.3. */
|
||||
#ifndef ATTRIBUTE_COLD
|
||||
# if (GCC_VERSION >= 4003)
|
||||
# define ATTRIBUTE_COLD __attribute__ ((__cold__))
|
||||
# else
|
||||
# define ATTRIBUTE_COLD
|
||||
# endif /* GNUC >= 4.3 */
|
||||
#endif /* ATTRIBUTE_COLD */
|
||||
#ifndef ATTRIBUTE_HOT
|
||||
# if (GCC_VERSION >= 4003)
|
||||
# define ATTRIBUTE_HOT __attribute__ ((__hot__))
|
||||
# else
|
||||
# define ATTRIBUTE_HOT
|
||||
# endif /* GNUC >= 4.3 */
|
||||
#endif /* ATTRIBUTE_HOT */
|
||||
|
||||
/* Attribute 'no_sanitize_undefined' was valid as of gcc 4.9. */
|
||||
#ifndef ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
||||
# if (GCC_VERSION >= 4009)
|
||||
# define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize_undefined))
|
||||
# else
|
||||
# define ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
||||
# endif /* GNUC >= 4.9 */
|
||||
#endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */
|
||||
|
||||
/* Attribute 'nonstring' was valid as of gcc 8. */
|
||||
#ifndef ATTRIBUTE_NONSTRING
|
||||
# if GCC_VERSION >= 8000
|
||||
# define ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__))
|
||||
# else
|
||||
# define ATTRIBUTE_NONSTRING
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Attribute `alloc_size' was valid as of gcc 4.3. */
|
||||
#ifndef ATTRIBUTE_RESULT_SIZE_1
|
||||
# if (GCC_VERSION >= 4003)
|
||||
# define ATTRIBUTE_RESULT_SIZE_1 __attribute__ ((alloc_size (1)))
|
||||
# else
|
||||
# define ATTRIBUTE_RESULT_SIZE_1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_RESULT_SIZE_2
|
||||
# if (GCC_VERSION >= 4003)
|
||||
# define ATTRIBUTE_RESULT_SIZE_2 __attribute__ ((alloc_size (2)))
|
||||
# else
|
||||
# define ATTRIBUTE_RESULT_SIZE_2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ATTRIBUTE_RESULT_SIZE_1_2
|
||||
# if (GCC_VERSION >= 4003)
|
||||
# define ATTRIBUTE_RESULT_SIZE_1_2 __attribute__ ((alloc_size (1, 2)))
|
||||
# else
|
||||
# define ATTRIBUTE_RESULT_SIZE_1_2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Attribute `warn_unused_result' was valid as of gcc 3.3. */
|
||||
#ifndef ATTRIBUTE_WARN_UNUSED_RESULT
|
||||
# if GCC_VERSION >= 3003
|
||||
# define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
|
||||
# else
|
||||
# define ATTRIBUTE_WARN_UNUSED_RESULT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* We use __extension__ in some places to suppress -pedantic warnings
|
||||
about GCC extensions. This feature didn't work properly before
|
||||
gcc 2.8. */
|
||||
#if GCC_VERSION < 2008
|
||||
#define __extension__
|
||||
#endif
|
||||
|
||||
/* This is used to declare a const variable which should be visible
|
||||
outside of the current compilation unit. Use it as
|
||||
EXPORTED_CONST int i = 1;
|
||||
This is because the semantics of const are different in C and C++.
|
||||
"extern const" is permitted in C but it looks strange, and gcc
|
||||
warns about it when -Wc++-compat is not used. */
|
||||
#ifdef __cplusplus
|
||||
#define EXPORTED_CONST extern const
|
||||
#else
|
||||
#define EXPORTED_CONST const
|
||||
#endif
|
||||
|
||||
/* Be conservative and only use enum bitfields with C++ or GCC.
|
||||
FIXME: provide a complete autoconf test for buggy enum bitfields. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define ENUM_BITFIELD(TYPE) enum TYPE
|
||||
#elif (GCC_VERSION > 2000)
|
||||
#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
|
||||
#else
|
||||
#define ENUM_BITFIELD(TYPE) unsigned int
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && __cpp_constexpr >= 200704
|
||||
#define CONSTEXPR constexpr
|
||||
#else
|
||||
#define CONSTEXPR
|
||||
#endif
|
||||
|
||||
/* A macro to disable the copy constructor and assignment operator.
|
||||
When building with C++11 and above, the methods are explicitly
|
||||
deleted, causing a compile-time error if something tries to copy.
|
||||
For C++03, this just declares the methods, causing a link-time
|
||||
error if the methods end up called (assuming you don't
|
||||
define them). For C++03, for best results, place the macro
|
||||
under the private: access specifier, like this,
|
||||
|
||||
class name_lookup
|
||||
{
|
||||
private:
|
||||
DISABLE_COPY_AND_ASSIGN (name_lookup);
|
||||
};
|
||||
|
||||
so that most attempts at copy are caught at compile-time. */
|
||||
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103
|
||||
#define DISABLE_COPY_AND_ASSIGN(TYPE) \
|
||||
TYPE (const TYPE&) = delete; \
|
||||
void operator= (const TYPE &) = delete
|
||||
#else
|
||||
#define DISABLE_COPY_AND_ASSIGN(TYPE) \
|
||||
TYPE (const TYPE&); \
|
||||
void operator= (const TYPE &)
|
||||
#endif /* __cplusplus >= 201103 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ansidecl.h */
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
/* -*- buffer-read-only: t -*-
|
||||
Generated automatically by parsecpu.awk from arm-cpus.in.
|
||||
Do not edit.
|
||||
|
||||
Copyright (C) 2011-2024 Free Software Foundation, Inc.
|
||||
|
||||
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/>. */
|
||||
|
||||
enum processor_type
|
||||
{
|
||||
TARGET_CPU_arm8,
|
||||
TARGET_CPU_arm810,
|
||||
TARGET_CPU_strongarm,
|
||||
TARGET_CPU_fa526,
|
||||
TARGET_CPU_fa626,
|
||||
TARGET_CPU_arm7tdmi,
|
||||
TARGET_CPU_arm710t,
|
||||
TARGET_CPU_arm9,
|
||||
TARGET_CPU_arm9tdmi,
|
||||
TARGET_CPU_arm920t,
|
||||
TARGET_CPU_arm10tdmi,
|
||||
TARGET_CPU_arm9e,
|
||||
TARGET_CPU_arm10e,
|
||||
TARGET_CPU_xscale,
|
||||
TARGET_CPU_iwmmxt,
|
||||
TARGET_CPU_iwmmxt2,
|
||||
TARGET_CPU_fa606te,
|
||||
TARGET_CPU_fa626te,
|
||||
TARGET_CPU_fmp626,
|
||||
TARGET_CPU_fa726te,
|
||||
TARGET_CPU_arm926ejs,
|
||||
TARGET_CPU_arm1026ejs,
|
||||
TARGET_CPU_arm1136js,
|
||||
TARGET_CPU_arm1136jfs,
|
||||
TARGET_CPU_arm1176jzs,
|
||||
TARGET_CPU_arm1176jzfs,
|
||||
TARGET_CPU_mpcorenovfp,
|
||||
TARGET_CPU_mpcore,
|
||||
TARGET_CPU_arm1156t2s,
|
||||
TARGET_CPU_arm1156t2fs,
|
||||
TARGET_CPU_cortexm1,
|
||||
TARGET_CPU_cortexm0,
|
||||
TARGET_CPU_cortexm0plus,
|
||||
TARGET_CPU_cortexm1smallmultiply,
|
||||
TARGET_CPU_cortexm0smallmultiply,
|
||||
TARGET_CPU_cortexm0plussmallmultiply,
|
||||
TARGET_CPU_genericv7a,
|
||||
TARGET_CPU_cortexa5,
|
||||
TARGET_CPU_cortexa7,
|
||||
TARGET_CPU_cortexa8,
|
||||
TARGET_CPU_cortexa9,
|
||||
TARGET_CPU_cortexa12,
|
||||
TARGET_CPU_cortexa15,
|
||||
TARGET_CPU_cortexa17,
|
||||
TARGET_CPU_cortexr4,
|
||||
TARGET_CPU_cortexr4f,
|
||||
TARGET_CPU_cortexr5,
|
||||
TARGET_CPU_cortexr7,
|
||||
TARGET_CPU_cortexr8,
|
||||
TARGET_CPU_cortexm7,
|
||||
TARGET_CPU_cortexm4,
|
||||
TARGET_CPU_cortexm3,
|
||||
TARGET_CPU_marvell_pj4,
|
||||
TARGET_CPU_cortexa15cortexa7,
|
||||
TARGET_CPU_cortexa17cortexa7,
|
||||
TARGET_CPU_cortexa32,
|
||||
TARGET_CPU_cortexa35,
|
||||
TARGET_CPU_cortexa53,
|
||||
TARGET_CPU_cortexa57,
|
||||
TARGET_CPU_cortexa72,
|
||||
TARGET_CPU_cortexa73,
|
||||
TARGET_CPU_exynosm1,
|
||||
TARGET_CPU_xgene1,
|
||||
TARGET_CPU_cortexa57cortexa53,
|
||||
TARGET_CPU_cortexa72cortexa53,
|
||||
TARGET_CPU_cortexa73cortexa35,
|
||||
TARGET_CPU_cortexa73cortexa53,
|
||||
TARGET_CPU_cortexa55,
|
||||
TARGET_CPU_cortexa75,
|
||||
TARGET_CPU_cortexa76,
|
||||
TARGET_CPU_cortexa76ae,
|
||||
TARGET_CPU_cortexa77,
|
||||
TARGET_CPU_cortexa78,
|
||||
TARGET_CPU_cortexa78ae,
|
||||
TARGET_CPU_cortexa78c,
|
||||
TARGET_CPU_cortexa710,
|
||||
TARGET_CPU_cortexx1,
|
||||
TARGET_CPU_cortexx1c,
|
||||
TARGET_CPU_neoversen1,
|
||||
TARGET_CPU_cortexa75cortexa55,
|
||||
TARGET_CPU_cortexa76cortexa55,
|
||||
TARGET_CPU_neoversev1,
|
||||
TARGET_CPU_neoversen2,
|
||||
TARGET_CPU_cortexm23,
|
||||
TARGET_CPU_cortexm33,
|
||||
TARGET_CPU_cortexm35p,
|
||||
TARGET_CPU_cortexm52,
|
||||
TARGET_CPU_cortexm55,
|
||||
TARGET_CPU_starmc1,
|
||||
TARGET_CPU_cortexm85,
|
||||
TARGET_CPU_cortexr52,
|
||||
TARGET_CPU_cortexr52plus,
|
||||
TARGET_CPU_arm_none
|
||||
};
|
||||
|
||||
enum arch_type
|
||||
{
|
||||
TARGET_ARCH_armv4,
|
||||
TARGET_ARCH_armv4t,
|
||||
TARGET_ARCH_armv5t,
|
||||
TARGET_ARCH_armv5te,
|
||||
TARGET_ARCH_armv5tej,
|
||||
TARGET_ARCH_armv6,
|
||||
TARGET_ARCH_armv6j,
|
||||
TARGET_ARCH_armv6k,
|
||||
TARGET_ARCH_armv6z,
|
||||
TARGET_ARCH_armv6kz,
|
||||
TARGET_ARCH_armv6zk,
|
||||
TARGET_ARCH_armv6t2,
|
||||
TARGET_ARCH_armv6_m,
|
||||
TARGET_ARCH_armv6s_m,
|
||||
TARGET_ARCH_armv7,
|
||||
TARGET_ARCH_armv7_a,
|
||||
TARGET_ARCH_armv7ve,
|
||||
TARGET_ARCH_armv7_r,
|
||||
TARGET_ARCH_armv7_m,
|
||||
TARGET_ARCH_armv7e_m,
|
||||
TARGET_ARCH_armv8_a,
|
||||
TARGET_ARCH_armv8_1_a,
|
||||
TARGET_ARCH_armv8_2_a,
|
||||
TARGET_ARCH_armv8_3_a,
|
||||
TARGET_ARCH_armv8_4_a,
|
||||
TARGET_ARCH_armv8_5_a,
|
||||
TARGET_ARCH_armv8_6_a,
|
||||
TARGET_ARCH_armv8_m_base,
|
||||
TARGET_ARCH_armv8_m_main,
|
||||
TARGET_ARCH_armv8_r,
|
||||
TARGET_ARCH_armv8_1_m_main,
|
||||
TARGET_ARCH_armv9_a,
|
||||
TARGET_ARCH_iwmmxt,
|
||||
TARGET_ARCH_iwmmxt2,
|
||||
TARGET_ARCH_arm_none
|
||||
};
|
||||
|
||||
enum fpu_type
|
||||
{
|
||||
TARGET_FPU_vfp,
|
||||
TARGET_FPU_vfpv2,
|
||||
TARGET_FPU_vfpv3,
|
||||
TARGET_FPU_vfpv3_fp16,
|
||||
TARGET_FPU_vfpv3_d16,
|
||||
TARGET_FPU_vfpv3_d16_fp16,
|
||||
TARGET_FPU_vfpv3xd,
|
||||
TARGET_FPU_vfpv3xd_fp16,
|
||||
TARGET_FPU_neon,
|
||||
TARGET_FPU_neon_vfpv3,
|
||||
TARGET_FPU_neon_fp16,
|
||||
TARGET_FPU_vfpv4,
|
||||
TARGET_FPU_neon_vfpv4,
|
||||
TARGET_FPU_vfpv4_d16,
|
||||
TARGET_FPU_fpv4_sp_d16,
|
||||
TARGET_FPU_fpv5_sp_d16,
|
||||
TARGET_FPU_fpv5_d16,
|
||||
TARGET_FPU_fp_armv8,
|
||||
TARGET_FPU_neon_fp_armv8,
|
||||
TARGET_FPU_crypto_neon_fp_armv8,
|
||||
TARGET_FPU_vfp3,
|
||||
TARGET_FPU_auto
|
||||
};
|
||||
+682
@@ -0,0 +1,682 @@
|
||||
/* -*- buffer-read-only: t -*-
|
||||
Generated automatically by parsecpu.awk from arm-cpus.in.
|
||||
Do not edit.
|
||||
|
||||
Copyright (C) 2011-2024 Free Software Foundation, Inc.
|
||||
|
||||
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/>. */
|
||||
|
||||
enum isa_feature {
|
||||
isa_nobit = 0,
|
||||
isa_bit_quirk_vlldm,
|
||||
isa_bit_fp16fml,
|
||||
isa_bit_mve,
|
||||
isa_bit_cmse,
|
||||
isa_bit_quirk_armv6kz,
|
||||
isa_bit_dotprod,
|
||||
isa_bit_crc32,
|
||||
isa_bit_xscale,
|
||||
isa_bit_pacbti,
|
||||
isa_bit_vfpv2,
|
||||
isa_bit_vfpv3,
|
||||
isa_bit_vfpv4,
|
||||
isa_bit_lpae,
|
||||
isa_bit_armv7em,
|
||||
isa_bit_fp16,
|
||||
isa_bit_adiv,
|
||||
isa_bit_fp_d32,
|
||||
isa_bit_be8,
|
||||
isa_bit_fp16conv,
|
||||
isa_bit_thumb2,
|
||||
isa_bit_crypto,
|
||||
isa_bit_mp,
|
||||
isa_bit_sec,
|
||||
isa_bit_sb,
|
||||
isa_bit_bf16,
|
||||
isa_bit_predres,
|
||||
isa_bit_armv4,
|
||||
isa_bit_quirk_cm3_ldrd,
|
||||
isa_bit_smallmul,
|
||||
isa_bit_armv5t,
|
||||
isa_bit_armv8_1m_main,
|
||||
isa_bit_armv6,
|
||||
isa_bit_thumb,
|
||||
isa_bit_quirk_no_asmcpu,
|
||||
isa_bit_armv7,
|
||||
isa_bit_armv8,
|
||||
isa_bit_armv9,
|
||||
isa_bit_i8mm,
|
||||
isa_bit_fp_dbl,
|
||||
isa_bit_armv5te,
|
||||
isa_bit_fpv5,
|
||||
isa_bit_iwmmxt2,
|
||||
isa_bit_quirk_aes_1742098,
|
||||
isa_bit_notm,
|
||||
isa_bit_cdecp0,
|
||||
isa_bit_cdecp1,
|
||||
isa_bit_cdecp2,
|
||||
isa_bit_cdecp3,
|
||||
isa_bit_iwmmxt,
|
||||
isa_bit_cdecp4,
|
||||
isa_bit_cdecp5,
|
||||
isa_bit_cdecp6,
|
||||
isa_bit_cdecp7,
|
||||
isa_bit_mve_float,
|
||||
isa_bit_armv8_1,
|
||||
isa_bit_armv8_2,
|
||||
isa_bit_armv8_3,
|
||||
isa_bit_tdiv,
|
||||
isa_bit_armv8_4,
|
||||
isa_bit_armv8_5,
|
||||
isa_bit_armv8_6,
|
||||
isa_bit_neon,
|
||||
isa_bit_quirk_no_volatile_ce,
|
||||
isa_bit_armv6k,
|
||||
isa_bit_vfp_base,
|
||||
isa_num_bits
|
||||
};
|
||||
|
||||
#define ISA_ARMv8_6a \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_mp, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_crc32, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_sec, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_sb, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8, \
|
||||
isa_bit_adiv, \
|
||||
isa_bit_armv8_1, \
|
||||
isa_bit_armv8_2, \
|
||||
isa_bit_armv8_3, \
|
||||
isa_bit_armv8_4, \
|
||||
isa_bit_armv8_5, \
|
||||
isa_bit_armv8_6, \
|
||||
isa_bit_lpae, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_predres
|
||||
|
||||
#define ISA_ARMv8r \
|
||||
isa_bit_adiv, \
|
||||
isa_bit_mp, \
|
||||
isa_bit_lpae, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_sec, \
|
||||
isa_bit_be8
|
||||
|
||||
#define ISA_ARMv6z \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_notm
|
||||
|
||||
#define ISA_DOTPROD \
|
||||
isa_bit_dotprod, \
|
||||
isa_bit_neon, \
|
||||
isa_bit_fp_dbl, \
|
||||
isa_bit_fp_d32
|
||||
|
||||
#define ISA_ALL_CRYPTO \
|
||||
isa_bit_crypto
|
||||
|
||||
#define ISA_ALL_FPU_EXTERNAL \
|
||||
isa_bit_fp16, \
|
||||
isa_bit_bf16
|
||||
|
||||
#define ISA_ALL_SIMD \
|
||||
isa_bit_fp_d32, \
|
||||
isa_bit_fp16fml, \
|
||||
isa_bit_dotprod, \
|
||||
isa_bit_neon, \
|
||||
isa_bit_crypto, \
|
||||
isa_bit_i8mm
|
||||
|
||||
#define ISA_ALL_QUIRKS \
|
||||
isa_bit_quirk_no_asmcpu, \
|
||||
isa_bit_quirk_vlldm, \
|
||||
isa_bit_xscale, \
|
||||
isa_bit_quirk_cm3_ldrd, \
|
||||
isa_bit_quirk_no_volatile_ce, \
|
||||
isa_bit_quirk_armv6kz, \
|
||||
isa_bit_quirk_aes_1742098
|
||||
|
||||
#define ISA_CRYPTO \
|
||||
isa_bit_neon, \
|
||||
isa_bit_fp_dbl, \
|
||||
isa_bit_fp_d32, \
|
||||
isa_bit_crypto
|
||||
|
||||
#define ISA_ARMv8m_base \
|
||||
isa_bit_be8, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_cmse, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv8
|
||||
|
||||
#define ISA_ARMv6zk \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_be8
|
||||
|
||||
#define ISA_VFPv2 \
|
||||
isa_bit_vfpv2
|
||||
|
||||
#define ISA_VFPv3 \
|
||||
isa_bit_vfpv2, \
|
||||
isa_bit_vfpv3
|
||||
|
||||
#define ISA_VFPv4 \
|
||||
isa_bit_fp16conv, \
|
||||
isa_bit_vfpv2, \
|
||||
isa_bit_vfpv3, \
|
||||
isa_bit_vfpv4
|
||||
|
||||
#define ISA_FP_D32 \
|
||||
isa_bit_fp_dbl, \
|
||||
isa_bit_fp_d32
|
||||
|
||||
#define ISA_ARMv7ve \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_adiv, \
|
||||
isa_bit_lpae, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_mp, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_sec
|
||||
|
||||
#define ISA_ARMv7a \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv6k
|
||||
|
||||
#define ISA_ALL_SIMD_INTERNAL \
|
||||
isa_bit_fp_d32, \
|
||||
isa_bit_crypto, \
|
||||
isa_bit_neon
|
||||
|
||||
#define ISA_ARMv8_1a \
|
||||
isa_bit_crc32, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_armv8_1, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_sec, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_adiv, \
|
||||
isa_bit_lpae, \
|
||||
isa_bit_mp
|
||||
|
||||
#define ISA_ARMv7em \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_armv7em, \
|
||||
isa_bit_tdiv
|
||||
|
||||
#define ISA_FP_DBL \
|
||||
isa_bit_fp_dbl
|
||||
|
||||
#define ISA_ARMv9a \
|
||||
isa_bit_be8, \
|
||||
isa_bit_sb, \
|
||||
isa_bit_adiv, \
|
||||
isa_bit_lpae, \
|
||||
isa_bit_armv8_1, \
|
||||
isa_bit_armv8_2, \
|
||||
isa_bit_armv8_3, \
|
||||
isa_bit_armv8_4, \
|
||||
isa_bit_armv8_5, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_predres, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_crc32, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8, \
|
||||
isa_bit_armv9, \
|
||||
isa_bit_mp, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_sec
|
||||
|
||||
#define ISA_ARMv8_3a \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_sec, \
|
||||
isa_bit_mp, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_crc32, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_adiv, \
|
||||
isa_bit_lpae, \
|
||||
isa_bit_armv8_1, \
|
||||
isa_bit_armv8_2, \
|
||||
isa_bit_armv8_3, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8, \
|
||||
isa_bit_thumb
|
||||
|
||||
#define ISA_ARMv5t \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_armv4
|
||||
|
||||
#define ISA_ARMv7m \
|
||||
isa_bit_be8, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_thumb
|
||||
|
||||
#define ISA_ARMv4 \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv4
|
||||
|
||||
#define ISA_ARMv6kz \
|
||||
isa_bit_be8, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_quirk_armv6kz, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_armv6k
|
||||
|
||||
#define ISA_ARMv6 \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_be8
|
||||
|
||||
#define ISA_ALL_FP \
|
||||
isa_bit_fp_dbl, \
|
||||
isa_bit_fp16conv, \
|
||||
isa_bit_fp16, \
|
||||
isa_bit_fp_d32, \
|
||||
isa_bit_bf16, \
|
||||
isa_bit_fpv5, \
|
||||
isa_bit_neon, \
|
||||
isa_bit_fp16fml, \
|
||||
isa_bit_crypto, \
|
||||
isa_bit_i8mm, \
|
||||
isa_bit_dotprod, \
|
||||
isa_bit_vfpv2, \
|
||||
isa_bit_vfpv3, \
|
||||
isa_bit_vfpv4
|
||||
|
||||
#define ISA_ARMv7 \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t
|
||||
|
||||
#define ISA_ARMv8_5a \
|
||||
isa_bit_adiv, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8, \
|
||||
isa_bit_lpae, \
|
||||
isa_bit_armv8_1, \
|
||||
isa_bit_armv8_2, \
|
||||
isa_bit_armv8_3, \
|
||||
isa_bit_armv8_4, \
|
||||
isa_bit_armv8_5, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_predres, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_mp, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_crc32, \
|
||||
isa_bit_sec, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_sb
|
||||
|
||||
#define ISA_ARMv7r \
|
||||
isa_bit_be8, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_thumb
|
||||
|
||||
#define ISA_ALL_FPU_INTERNAL \
|
||||
isa_bit_fp16conv, \
|
||||
isa_bit_crypto, \
|
||||
isa_bit_vfpv2, \
|
||||
isa_bit_vfpv3, \
|
||||
isa_bit_vfpv4, \
|
||||
isa_bit_fpv5, \
|
||||
isa_bit_neon, \
|
||||
isa_bit_fp_dbl, \
|
||||
isa_bit_fp_d32
|
||||
|
||||
#define ISA_FPv5 \
|
||||
isa_bit_fpv5, \
|
||||
isa_bit_fp16conv, \
|
||||
isa_bit_vfpv2, \
|
||||
isa_bit_vfpv3, \
|
||||
isa_bit_vfpv4
|
||||
|
||||
#define ISA_ARMv6t2 \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_be8
|
||||
|
||||
#define ISA_ARMv8m_main \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_cmse, \
|
||||
isa_bit_armv5te
|
||||
|
||||
#define ISA_ARMv8_1m_main \
|
||||
isa_bit_be8, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_cmse, \
|
||||
isa_bit_armv8_1m_main, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_tdiv
|
||||
|
||||
#define ISA_NEON \
|
||||
isa_bit_fp_d32, \
|
||||
isa_bit_neon, \
|
||||
isa_bit_fp_dbl
|
||||
|
||||
#define ISA_ARMv5te \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_armv5t
|
||||
|
||||
#define ISA_FP_ARMv8 \
|
||||
isa_bit_fp_dbl, \
|
||||
isa_bit_fp_d32, \
|
||||
isa_bit_vfpv2, \
|
||||
isa_bit_vfpv3, \
|
||||
isa_bit_vfpv4, \
|
||||
isa_bit_fp16conv, \
|
||||
isa_bit_fpv5
|
||||
|
||||
#define ISA_ARMv8a \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_sec, \
|
||||
isa_bit_adiv, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_lpae, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8, \
|
||||
isa_bit_mp, \
|
||||
isa_bit_armv6k
|
||||
|
||||
#define ISA_MVE \
|
||||
isa_bit_armv7em, \
|
||||
isa_bit_mve
|
||||
|
||||
#define ISA_ALL_SIMD_EXTERNAL \
|
||||
isa_bit_fp16fml, \
|
||||
isa_bit_dotprod, \
|
||||
isa_bit_i8mm
|
||||
|
||||
#define ISA_ARMv8_2a \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_sec, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_mp, \
|
||||
isa_bit_crc32, \
|
||||
isa_bit_adiv, \
|
||||
isa_bit_lpae, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_armv8_1, \
|
||||
isa_bit_armv8_2, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8
|
||||
|
||||
#define ISA_ARMv6j \
|
||||
isa_bit_be8, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_armv5t
|
||||
|
||||
#define ISA_ARMv6k \
|
||||
isa_bit_be8, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_armv6k
|
||||
|
||||
#define ISA_ARMv4t \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_notm
|
||||
|
||||
#define ISA_ARMv6m \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_armv5t
|
||||
|
||||
#define ISA_IGNORE_FOR_MULTILIB \
|
||||
isa_bit_cdecp0, \
|
||||
isa_bit_cdecp1, \
|
||||
isa_bit_cdecp2, \
|
||||
isa_bit_cdecp3, \
|
||||
isa_bit_cdecp4, \
|
||||
isa_bit_cdecp5, \
|
||||
isa_bit_cdecp6, \
|
||||
isa_bit_cdecp7
|
||||
|
||||
#define ISA_MVE_FP \
|
||||
isa_bit_fp16, \
|
||||
isa_bit_armv7em, \
|
||||
isa_bit_mve, \
|
||||
isa_bit_fpv5, \
|
||||
isa_bit_vfpv2, \
|
||||
isa_bit_vfpv3, \
|
||||
isa_bit_vfpv4, \
|
||||
isa_bit_fp16conv, \
|
||||
isa_bit_mve_float
|
||||
|
||||
#define ISA_ARMv5tej \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv5te, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_armv5t
|
||||
|
||||
#define ISA_ARMv8_4a \
|
||||
isa_bit_sec, \
|
||||
isa_bit_crc32, \
|
||||
isa_bit_be8, \
|
||||
isa_bit_thumb2, \
|
||||
isa_bit_armv5t, \
|
||||
isa_bit_adiv, \
|
||||
isa_bit_lpae, \
|
||||
isa_bit_armv4, \
|
||||
isa_bit_armv6, \
|
||||
isa_bit_armv7, \
|
||||
isa_bit_armv8, \
|
||||
isa_bit_tdiv, \
|
||||
isa_bit_armv8_1, \
|
||||
isa_bit_armv8_2, \
|
||||
isa_bit_armv8_3, \
|
||||
isa_bit_armv8_4, \
|
||||
isa_bit_armv6k, \
|
||||
isa_bit_notm, \
|
||||
isa_bit_thumb, \
|
||||
isa_bit_mp, \
|
||||
isa_bit_armv5te
|
||||
|
||||
struct fbit_implication {
|
||||
/* Represents a feature implication, where:
|
||||
ante IMPLIES cons
|
||||
meaning that if ante is enabled then we should
|
||||
also implicitly enable cons. */
|
||||
enum isa_feature ante;
|
||||
enum isa_feature cons;
|
||||
};
|
||||
|
||||
static const struct fbit_implication all_implied_fbits[] =
|
||||
{
|
||||
{ isa_bit_neon, isa_bit_vfp_base },
|
||||
{ isa_bit_vfpv4, isa_bit_vfp_base },
|
||||
{ isa_bit_fp_d32, isa_bit_vfp_base },
|
||||
{ isa_bit_fp_dbl, isa_bit_vfp_base },
|
||||
{ isa_bit_mve_float, isa_bit_vfp_base },
|
||||
{ isa_bit_mve, isa_bit_vfp_base },
|
||||
{ isa_bit_dotprod, isa_bit_vfp_base },
|
||||
{ isa_bit_crypto, isa_bit_vfp_base },
|
||||
{ isa_bit_fp16, isa_bit_vfp_base },
|
||||
{ isa_bit_armv7em, isa_bit_vfp_base },
|
||||
{ isa_bit_i8mm, isa_bit_vfp_base },
|
||||
{ isa_bit_fp16conv, isa_bit_vfp_base },
|
||||
{ isa_bit_fpv5, isa_bit_vfp_base },
|
||||
{ isa_bit_fp16fml, isa_bit_vfp_base },
|
||||
{ isa_bit_bf16, isa_bit_vfp_base },
|
||||
{ isa_bit_vfpv2, isa_bit_vfp_base },
|
||||
{ isa_bit_vfpv3, isa_bit_vfp_base },
|
||||
{ isa_nobit, isa_nobit }
|
||||
};
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/* Descriptions of array-like objects.
|
||||
Copyright (C) 2019-2024 Free Software Foundation, Inc.
|
||||
|
||||
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_ARRAY_TRAITS_H
|
||||
#define GCC_ARRAY_TRAITS_H
|
||||
|
||||
/* Implementation for single integers (and similar types). */
|
||||
template<typename T, T zero = T (0)>
|
||||
struct scalar_array_traits
|
||||
{
|
||||
typedef T element_type;
|
||||
static const bool has_constant_size = true;
|
||||
static const size_t constant_size = 1;
|
||||
static const T *base (const T &x) { return &x; }
|
||||
static size_t size (const T &) { return 1; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct array_traits : scalar_array_traits<T> {};
|
||||
|
||||
/* Implementation for arrays with a static size. */
|
||||
template<typename T, size_t N>
|
||||
struct array_traits<T[N]>
|
||||
{
|
||||
typedef T element_type;
|
||||
static const bool has_constant_size = true;
|
||||
static const size_t constant_size = N;
|
||||
static const T *base (const T (&x)[N]) { return x; }
|
||||
static size_t size (const T (&)[N]) { return N; }
|
||||
};
|
||||
|
||||
#endif
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
/* AddressSanitizer, a fast memory error detector.
|
||||
Copyright (C) 2011-2024 Free Software Foundation, Inc.
|
||||
Contributed by Kostya Serebryany <kcc@google.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 TREE_ASAN
|
||||
#define TREE_ASAN
|
||||
|
||||
extern void asan_function_start (void);
|
||||
extern void asan_finish_file (void);
|
||||
extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
|
||||
HOST_WIDE_INT *, tree *, int);
|
||||
extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
|
||||
extern bool asan_protect_global (tree, bool ignore_decl_rtl_set_p = false);
|
||||
extern void initialize_sanitizer_builtins (void);
|
||||
extern tree asan_dynamic_init_call (bool);
|
||||
extern bool asan_expand_check_ifn (gimple_stmt_iterator *, bool);
|
||||
extern bool asan_expand_mark_ifn (gimple_stmt_iterator *);
|
||||
extern bool asan_expand_poison_ifn (gimple_stmt_iterator *, bool *,
|
||||
hash_map<tree, tree> &);
|
||||
extern rtx asan_memfn_rtl (tree);
|
||||
|
||||
extern void hwasan_record_frame_init ();
|
||||
extern void hwasan_record_stack_var (rtx, rtx, poly_int64, poly_int64);
|
||||
extern void hwasan_emit_prologue ();
|
||||
extern rtx_insn *hwasan_emit_untag_frame (rtx, rtx);
|
||||
extern rtx hwasan_get_frame_extent ();
|
||||
extern rtx hwasan_frame_base ();
|
||||
extern void hwasan_maybe_emit_frame_base_init (void);
|
||||
extern bool stack_vars_base_reg_p (rtx);
|
||||
extern uint8_t hwasan_current_frame_tag ();
|
||||
extern void hwasan_increment_frame_tag ();
|
||||
extern rtx hwasan_truncate_to_tag_size (rtx, rtx);
|
||||
extern void hwasan_finish_file (void);
|
||||
extern bool hwasan_sanitize_p (void);
|
||||
extern bool hwasan_sanitize_stack_p (void);
|
||||
extern bool hwasan_sanitize_allocas_p (void);
|
||||
extern bool hwasan_expand_check_ifn (gimple_stmt_iterator *, bool);
|
||||
extern bool hwasan_expand_mark_ifn (gimple_stmt_iterator *);
|
||||
extern bool gate_hwasan (void);
|
||||
|
||||
extern gimple_stmt_iterator create_cond_insert_point
|
||||
(gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *);
|
||||
|
||||
/* Alias set for accessing the shadow memory. */
|
||||
extern alias_set_type asan_shadow_set;
|
||||
|
||||
/* Hash set of labels that are either used in a goto, or their address
|
||||
has been taken. */
|
||||
extern hash_set <tree> *asan_used_labels;
|
||||
|
||||
/* Shadow memory is found at
|
||||
(address >> ASAN_SHADOW_SHIFT) + asan_shadow_offset (). */
|
||||
#define ASAN_SHADOW_SHIFT 3
|
||||
#define ASAN_SHADOW_GRANULARITY (1UL << ASAN_SHADOW_SHIFT)
|
||||
|
||||
/* Red zone size, stack and global variables are padded by ASAN_RED_ZONE_SIZE
|
||||
up to 2 * ASAN_RED_ZONE_SIZE - 1 bytes. */
|
||||
#define ASAN_RED_ZONE_SIZE 32
|
||||
|
||||
/* Stack variable use more compact red zones. The size includes also
|
||||
size of variable itself. */
|
||||
|
||||
#define ASAN_MIN_RED_ZONE_SIZE 16
|
||||
|
||||
/* Shadow memory values for stack protection. Left is below protected vars,
|
||||
the first pointer in stack corresponding to that offset contains
|
||||
ASAN_STACK_FRAME_MAGIC word, the second pointer to a string describing
|
||||
the frame. Middle is for padding in between variables, right is
|
||||
above the last protected variable and partial immediately after variables
|
||||
up to ASAN_RED_ZONE_SIZE alignment. */
|
||||
#define ASAN_STACK_MAGIC_LEFT 0xf1
|
||||
#define ASAN_STACK_MAGIC_MIDDLE 0xf2
|
||||
#define ASAN_STACK_MAGIC_RIGHT 0xf3
|
||||
#define ASAN_STACK_MAGIC_USE_AFTER_RET 0xf5
|
||||
#define ASAN_STACK_MAGIC_USE_AFTER_SCOPE 0xf8
|
||||
|
||||
#define ASAN_STACK_FRAME_MAGIC 0x41b58ab3
|
||||
#define ASAN_STACK_RETIRED_MAGIC 0x45e0360e
|
||||
|
||||
#define ASAN_USE_AFTER_SCOPE_ATTRIBUTE "use after scope memory"
|
||||
|
||||
/* NOTE: The values below and the hooks under targetm.memtag define an ABI and
|
||||
are hard-coded to these values in libhwasan, hence they can't be changed
|
||||
independently here. */
|
||||
/* How many bits are used to store a tag in a pointer.
|
||||
The default version uses the entire top byte of a pointer (i.e. 8 bits). */
|
||||
#define HWASAN_TAG_SIZE targetm.memtag.tag_size ()
|
||||
/* Tag Granule of HWASAN shadow stack.
|
||||
This is the size in real memory that each byte in the shadow memory refers
|
||||
to. I.e. if a variable is X bytes long in memory then its tag in shadow
|
||||
memory will span X / HWASAN_TAG_GRANULE_SIZE bytes.
|
||||
Most variables will need to be aligned to this amount since two variables
|
||||
that are neighbors in memory and share a tag granule would need to share the
|
||||
same tag (the shared tag granule can only store one tag). */
|
||||
#define HWASAN_TAG_GRANULE_SIZE targetm.memtag.granule_size ()
|
||||
/* Define the tag for the stack background.
|
||||
This defines what tag the stack pointer will be and hence what tag all
|
||||
variables that are not given special tags are (e.g. spilled registers,
|
||||
and parameters passed on the stack). */
|
||||
#define HWASAN_STACK_BACKGROUND gen_int_mode (0, QImode)
|
||||
|
||||
/* Various flags for Asan builtins. */
|
||||
enum asan_check_flags
|
||||
{
|
||||
ASAN_CHECK_STORE = 1 << 0,
|
||||
ASAN_CHECK_SCALAR_ACCESS = 1 << 1,
|
||||
ASAN_CHECK_NON_ZERO_LEN = 1 << 2,
|
||||
ASAN_CHECK_LAST = 1 << 3
|
||||
};
|
||||
|
||||
/* Flags for Asan check builtins. */
|
||||
#define IFN_ASAN_MARK_FLAGS DEF(POISON), DEF(UNPOISON)
|
||||
|
||||
enum asan_mark_flags
|
||||
{
|
||||
#define DEF(X) ASAN_MARK_##X
|
||||
IFN_ASAN_MARK_FLAGS
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
/* Return true if STMT is ASAN_MARK with FLAG as first argument. */
|
||||
extern bool asan_mark_p (gimple *stmt, enum asan_mark_flags flag);
|
||||
|
||||
/* Return the size of padding needed to insert after a protected
|
||||
decl of SIZE. */
|
||||
|
||||
inline unsigned int
|
||||
asan_red_zone_size (unsigned int size)
|
||||
{
|
||||
unsigned int c = size & (ASAN_RED_ZONE_SIZE - 1);
|
||||
return c ? 2 * ASAN_RED_ZONE_SIZE - c : ASAN_RED_ZONE_SIZE;
|
||||
}
|
||||
|
||||
/* Return how much a stack variable occupis on a stack
|
||||
including a space for red zone. */
|
||||
|
||||
inline unsigned HOST_WIDE_INT
|
||||
asan_var_and_redzone_size (unsigned HOST_WIDE_INT size)
|
||||
{
|
||||
if (size <= 4)
|
||||
return 16;
|
||||
else if (size <= 16)
|
||||
return 32;
|
||||
else if (size <= 128)
|
||||
return size + 32;
|
||||
else if (size <= 512)
|
||||
return size + 64;
|
||||
else if (size <= 4096)
|
||||
return size + 128;
|
||||
else
|
||||
return size + 256;
|
||||
}
|
||||
|
||||
extern bool set_asan_shadow_offset (const char *);
|
||||
|
||||
extern bool asan_shadow_offset_set_p ();
|
||||
|
||||
extern void set_sanitized_sections (const char *);
|
||||
|
||||
extern bool asan_sanitize_stack_p (void);
|
||||
|
||||
extern bool asan_sanitize_allocas_p (void);
|
||||
|
||||
extern hash_set<tree> *asan_handled_variables;
|
||||
|
||||
/* Return TRUE if builtin with given FCODE will be intercepted by
|
||||
libasan. */
|
||||
|
||||
inline bool
|
||||
asan_intercepted_p (enum built_in_function fcode)
|
||||
{
|
||||
/* This list should be kept up-to-date with upstream's version at
|
||||
compiler-rt/lib/hwasan/hwasan_platform_interceptors.h. */
|
||||
if (hwasan_sanitize_p ())
|
||||
return fcode == BUILT_IN_MEMCMP
|
||||
|| fcode == BUILT_IN_MEMCPY
|
||||
|| fcode == BUILT_IN_MEMMOVE
|
||||
|| fcode == BUILT_IN_MEMSET;
|
||||
|
||||
return fcode == BUILT_IN_INDEX
|
||||
|| fcode == BUILT_IN_MEMCHR
|
||||
|| fcode == BUILT_IN_MEMCMP
|
||||
|| fcode == BUILT_IN_MEMCPY
|
||||
|| fcode == BUILT_IN_MEMMOVE
|
||||
|| fcode == BUILT_IN_MEMSET
|
||||
|| fcode == BUILT_IN_STRCASECMP
|
||||
|| fcode == BUILT_IN_STRCAT
|
||||
|| fcode == BUILT_IN_STRCHR
|
||||
|| fcode == BUILT_IN_STRCMP
|
||||
|| fcode == BUILT_IN_STRCPY
|
||||
|| fcode == BUILT_IN_STRDUP
|
||||
|| fcode == BUILT_IN_STRLEN
|
||||
|| fcode == BUILT_IN_STRNCASECMP
|
||||
|| fcode == BUILT_IN_STRNCAT
|
||||
|| fcode == BUILT_IN_STRNCMP
|
||||
|| fcode == BUILT_IN_STRCSPN
|
||||
|| fcode == BUILT_IN_STRPBRK
|
||||
|| fcode == BUILT_IN_STRSPN
|
||||
|| fcode == BUILT_IN_STRSTR
|
||||
|| fcode == BUILT_IN_STRNCPY;
|
||||
}
|
||||
|
||||
/* Return TRUE if we should instrument for use-after-scope sanity checking. */
|
||||
|
||||
inline bool
|
||||
asan_sanitize_use_after_scope (void)
|
||||
{
|
||||
return (flag_sanitize_address_use_after_scope
|
||||
&& (asan_sanitize_stack_p () || hwasan_sanitize_stack_p ()));
|
||||
}
|
||||
|
||||
/* Return true if DECL should be guarded on the stack. */
|
||||
|
||||
inline bool
|
||||
asan_protect_stack_decl (tree decl)
|
||||
{
|
||||
return DECL_P (decl)
|
||||
&& (!DECL_ARTIFICIAL (decl)
|
||||
|| (asan_sanitize_use_after_scope () && TREE_ADDRESSABLE (decl)));
|
||||
}
|
||||
|
||||
/* Return true when flag_sanitize & FLAG is non-zero. If FN is non-null,
|
||||
remove all flags mentioned in "no_sanitize" of DECL_ATTRIBUTES. */
|
||||
|
||||
inline bool
|
||||
sanitize_flags_p (unsigned int flag, const_tree fn = current_function_decl)
|
||||
{
|
||||
unsigned int result_flags = flag_sanitize & flag;
|
||||
if (result_flags == 0)
|
||||
return false;
|
||||
|
||||
if (fn != NULL_TREE)
|
||||
{
|
||||
tree value = lookup_attribute ("no_sanitize", DECL_ATTRIBUTES (fn));
|
||||
if (value)
|
||||
result_flags &= ~tree_to_uhwi (TREE_VALUE (value));
|
||||
}
|
||||
|
||||
return result_flags;
|
||||
}
|
||||
|
||||
/* Return true when coverage sanitization should happend for FN function. */
|
||||
|
||||
inline bool
|
||||
sanitize_coverage_p (const_tree fn = current_function_decl)
|
||||
{
|
||||
return (flag_sanitize_coverage
|
||||
&& (fn == NULL_TREE
|
||||
|| lookup_attribute ("no_sanitize_coverage",
|
||||
DECL_ATTRIBUTES (fn)) == NULL_TREE));
|
||||
}
|
||||
|
||||
#endif /* TREE_ASAN */
|
||||
+304
@@ -0,0 +1,304 @@
|
||||
/* Handling of fnspec attribute specifiers
|
||||
Copyright (C) 2008-2024 Free Software Foundation, Inc.
|
||||
Contributed by Richard Guenther <rguenther@suse.de>
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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/>. */
|
||||
|
||||
/* Parse string of attribute "fn spec". This is an internal attribute
|
||||
describing side effects of a function as follows:
|
||||
|
||||
character 0 specifies properties of return values as follows:
|
||||
'1'...'4' specifies number of argument function returns (as in memset)
|
||||
'm' specifies that returned value is noalias (as in malloc)
|
||||
'.' specifies that nothing is known.
|
||||
character 1 specifies additional function properties
|
||||
' ' specifies that nothing is known
|
||||
'p' or 'P' specifies that function is pure except for described side
|
||||
effects.
|
||||
'c' or 'C' specifies that function is const except for described side
|
||||
effects.
|
||||
The uppercase letter in addition specifies that function clobbers errno.
|
||||
|
||||
character 2+2i specifies properties of argument number i as follows:
|
||||
'x' or 'X' specifies that parameter is unused.
|
||||
'r' or 'R' specifies that the memory pointed to by the parameter is only
|
||||
read and does not escape
|
||||
'o' or 'O' specifies that the memory pointed to by the parameter is only
|
||||
written and does not escape
|
||||
'w' or 'W' specifies that the memory pointed to by the parameter does not
|
||||
escape
|
||||
'1'....'9' specifies that the memory pointed to by the parameter is
|
||||
copied to memory pointed to by different parameter
|
||||
(as in memcpy).
|
||||
'.' specifies that nothing is known.
|
||||
The uppercase letter in addition specifies that the memory pointed to
|
||||
by the parameter is not dereferenced. For 'r' only read applies
|
||||
transitively to pointers read from the pointed-to memory.
|
||||
|
||||
character 3+2i specifies additional properties of argument number i
|
||||
as follows:
|
||||
' ' nothing is known
|
||||
't' the size of value written/read corresponds to the size of
|
||||
of the pointed-to type of the argument type
|
||||
'1'...'9' specifies the size of value written/read is bound by the
|
||||
specified argument
|
||||
*/
|
||||
|
||||
#ifndef ATTR_FNSPEC_H
|
||||
#define ATTR_FNSPEC_H
|
||||
|
||||
class attr_fnspec
|
||||
{
|
||||
private:
|
||||
/* fn spec attribute string. */
|
||||
const char *str;
|
||||
/* length of the fn spec string. */
|
||||
const unsigned len;
|
||||
/* Number of characters specifying return value. */
|
||||
const unsigned int return_desc_size = 2;
|
||||
/* Number of characters specifying size. */
|
||||
const unsigned int arg_desc_size = 2;
|
||||
|
||||
/* Return start of specifier of arg i. */
|
||||
unsigned int arg_idx (int i)
|
||||
{
|
||||
return return_desc_size + arg_desc_size * i;
|
||||
}
|
||||
|
||||
public:
|
||||
attr_fnspec (const char *str, unsigned len)
|
||||
: str (str), len (len)
|
||||
{
|
||||
if (flag_checking)
|
||||
verify ();
|
||||
}
|
||||
attr_fnspec (const char *str)
|
||||
: str (str), len (strlen (str))
|
||||
{
|
||||
if (flag_checking)
|
||||
verify ();
|
||||
}
|
||||
attr_fnspec (const_tree identifier)
|
||||
: str (TREE_STRING_POINTER (identifier)),
|
||||
len (TREE_STRING_LENGTH (identifier))
|
||||
{
|
||||
if (flag_checking)
|
||||
verify ();
|
||||
}
|
||||
attr_fnspec ()
|
||||
: str (NULL), len (0)
|
||||
{
|
||||
}
|
||||
|
||||
/* Return true if fn spec is known. */
|
||||
bool
|
||||
known_p ()
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Return true if arg I is specified. */
|
||||
bool
|
||||
arg_specified_p (unsigned int i)
|
||||
{
|
||||
return len >= arg_idx (i + 1);
|
||||
}
|
||||
|
||||
/* True if the argument is not dereferenced recursively, thus only
|
||||
directly reachable memory is read or written. */
|
||||
bool
|
||||
arg_direct_p (unsigned int i)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx] == 'R' || str[idx] == 'O'
|
||||
|| str[idx] == 'W' || (str[idx] >= '1' && str[idx] <= '9');
|
||||
}
|
||||
|
||||
/* True if argument is used. */
|
||||
bool
|
||||
arg_used_p (unsigned int i)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx] != 'x' && str[idx] != 'X';
|
||||
}
|
||||
|
||||
/* True if memory reached by the argument is readonly (not clobbered). */
|
||||
bool
|
||||
arg_readonly_p (unsigned int i)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx] == 'r' || str[idx] == 'R' || (str[idx] >= '1' && str[idx] <= '9');
|
||||
}
|
||||
|
||||
/* True if memory reached by the argument is read (directly or indirectly) */
|
||||
bool
|
||||
arg_maybe_read_p (unsigned int i)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx] != 'o' && str[idx] != 'O'
|
||||
&& str[idx] != 'x' && str[idx] != 'X';
|
||||
}
|
||||
|
||||
/* True if memory reached by the argument is written.
|
||||
(directly or indirectly) */
|
||||
bool
|
||||
arg_maybe_written_p (unsigned int i)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx] != 'r' && str[idx] != 'R'
|
||||
&& (str[idx] < '1' || str[idx] > '9')
|
||||
&& str[idx] != 'x' && str[idx] != 'X';
|
||||
}
|
||||
|
||||
/* Return true if load of memory pointed to by argument I is bound
|
||||
by another argument. In this case set ARG. */
|
||||
bool
|
||||
arg_max_access_size_given_by_arg_p (unsigned int i, unsigned int *arg)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
if (str[idx + 1] >= '1' && str[idx + 1] <= '9')
|
||||
{
|
||||
*arg = str[idx + 1] - '1';
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return true if the pointed-to type of the argument correspond to the
|
||||
size of the memory acccess. */
|
||||
bool
|
||||
arg_access_size_given_by_type_p (unsigned int i)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx + 1] == 't';
|
||||
}
|
||||
|
||||
/* Return true if memory pointer to by argument is copied to a memory
|
||||
pointed to by a different argument (as in memcpy).
|
||||
In this case set ARG. */
|
||||
bool
|
||||
arg_copied_to_arg_p (unsigned int i, unsigned int *arg)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
if (str[idx] < '1' || str[idx] > '9')
|
||||
return false;
|
||||
*arg = str[idx] - '1';
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* True if the argument does not escape. */
|
||||
bool
|
||||
arg_noescape_p (unsigned int i)
|
||||
{
|
||||
unsigned int idx = arg_idx (i);
|
||||
gcc_checking_assert (arg_specified_p (i));
|
||||
return str[idx] == 'w' || str[idx] == 'W'
|
||||
|| str[idx] == 'r' || str[idx] == 'R'
|
||||
|| str[idx] == 'o' || str[idx] == 'O';
|
||||
}
|
||||
|
||||
/* Return true if function returns value of its parameter. If ARG_NO is
|
||||
non-NULL return initialize it to the argument returned. */
|
||||
bool
|
||||
returns_arg (unsigned int *arg_no)
|
||||
{
|
||||
if (str[0] >= '1' && str[0] <= '4')
|
||||
{
|
||||
if (arg_no)
|
||||
*arg_no = str[0] - '1';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Nonzero if the return value does not alias with anything. Functions
|
||||
with the malloc attribute have this set on their return value. */
|
||||
bool
|
||||
returns_noalias_p ()
|
||||
{
|
||||
return str[0] == 'm';
|
||||
}
|
||||
|
||||
/* Return true if all memory read by the function is specified by fnspec. */
|
||||
bool
|
||||
global_memory_read_p ()
|
||||
{
|
||||
return str[1] != 'c' && str[1] != 'C';
|
||||
}
|
||||
|
||||
/* Return true if all memory written by the function
|
||||
is specified by fnspec. */
|
||||
bool
|
||||
global_memory_written_p ()
|
||||
{
|
||||
return str[1] != 'c' && str[1] != 'C' && str[1] != 'p' && str[1] != 'P';
|
||||
}
|
||||
|
||||
bool
|
||||
errno_maybe_written_p ()
|
||||
{
|
||||
return str[1] == 'C' || str[1] == 'P';
|
||||
}
|
||||
|
||||
/* Return EAF flags for arg I. */
|
||||
int
|
||||
arg_eaf_flags (unsigned int i)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (!arg_specified_p (i))
|
||||
;
|
||||
else if (!arg_used_p (i))
|
||||
flags = EAF_UNUSED;
|
||||
else
|
||||
{
|
||||
if (arg_direct_p (i))
|
||||
flags |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_ESCAPE
|
||||
| EAF_NOT_RETURNED_INDIRECTLY | EAF_NO_INDIRECT_CLOBBER;
|
||||
if (arg_noescape_p (i))
|
||||
flags |= EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE;
|
||||
if (arg_readonly_p (i))
|
||||
flags |= EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* Check validity of the string. */
|
||||
void verify ();
|
||||
|
||||
/* Return the fnspec string. */
|
||||
const char *
|
||||
get_str ()
|
||||
{
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
extern attr_fnspec gimple_call_fnspec (const gcall *stmt);
|
||||
extern attr_fnspec builtin_fnspec (tree);
|
||||
|
||||
#endif /* ATTR_FNSPEC_H */
|
||||
+408
@@ -0,0 +1,408 @@
|
||||
/* Declarations and definitions dealing with attribute handling.
|
||||
Copyright (C) 2013-2024 Free Software Foundation, Inc.
|
||||
|
||||
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_ATTRIBS_H
|
||||
#define GCC_ATTRIBS_H
|
||||
|
||||
/* A set of attributes that belong to the same namespace, given by NS. */
|
||||
struct scoped_attribute_specs
|
||||
{
|
||||
const char *ns;
|
||||
array_slice<const attribute_spec> attributes;
|
||||
};
|
||||
|
||||
extern const struct attribute_spec *lookup_attribute_spec (const_tree);
|
||||
extern void free_attr_data ();
|
||||
extern void init_attributes (void);
|
||||
|
||||
/* Process the attributes listed in ATTRIBUTES and install them in *NODE,
|
||||
which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
|
||||
it should be modified in place; if a TYPE, a copy should be created
|
||||
unless ATTR_FLAG_TYPE_IN_PLACE is set in FLAGS. FLAGS gives further
|
||||
information, in the form of a bitwise OR of flags in enum attribute_flags
|
||||
from tree.h. Depending on these flags, some attributes may be
|
||||
returned to be applied at a later stage (for example, to apply
|
||||
a decl attribute to the declaration rather than to its type). */
|
||||
extern tree decl_attributes (tree *, tree, int, tree = NULL_TREE);
|
||||
|
||||
extern bool cxx11_attribute_p (const_tree);
|
||||
extern tree get_attribute_name (const_tree);
|
||||
extern tree get_attribute_namespace (const_tree);
|
||||
extern void apply_tm_attr (tree, tree);
|
||||
extern tree make_attribute (const char *, const char *, tree);
|
||||
extern bool attribute_ignored_p (tree);
|
||||
extern bool attribute_ignored_p (const attribute_spec *const);
|
||||
extern bool any_nonignored_attribute_p (tree);
|
||||
|
||||
extern struct scoped_attributes *
|
||||
register_scoped_attributes (const scoped_attribute_specs &, bool = false);
|
||||
|
||||
extern char *sorted_attr_string (tree);
|
||||
extern bool common_function_versions (tree, tree);
|
||||
extern tree make_dispatcher_decl (const tree);
|
||||
extern bool is_function_default_version (const tree);
|
||||
extern void handle_ignored_attributes_option (vec<char *> *);
|
||||
|
||||
/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
|
||||
is ATTRIBUTE.
|
||||
|
||||
Such modified types already made are recorded so that duplicates
|
||||
are not made. */
|
||||
|
||||
extern tree build_type_attribute_variant (tree, tree);
|
||||
extern tree build_decl_attribute_variant (tree, tree);
|
||||
extern tree build_type_attribute_qual_variant (tree, tree, int);
|
||||
|
||||
extern bool simple_cst_list_equal (const_tree, const_tree);
|
||||
extern bool attribute_value_equal (const_tree, const_tree);
|
||||
|
||||
/* Return 0 if the attributes for two types are incompatible, 1 if they
|
||||
are compatible, and 2 if they are nearly compatible (which causes a
|
||||
warning to be generated). */
|
||||
extern int comp_type_attributes (const_tree, const_tree);
|
||||
|
||||
extern tree affects_type_identity_attributes (tree, bool = true);
|
||||
extern tree restrict_type_identity_attributes_to (tree, tree);
|
||||
|
||||
/* Default versions of target-overridable functions. */
|
||||
extern tree merge_decl_attributes (tree, tree);
|
||||
extern tree merge_type_attributes (tree, tree);
|
||||
|
||||
/* Remove any instances of attribute ATTR_NAME in LIST and return the
|
||||
modified list. */
|
||||
|
||||
extern tree remove_attribute (const char *, tree);
|
||||
|
||||
/* Similarly but also with specific attribute namespace. */
|
||||
|
||||
extern tree remove_attribute (const char *, const char *, tree);
|
||||
|
||||
/* Given two attributes lists, return a list of their union. */
|
||||
|
||||
extern tree merge_attributes (tree, tree);
|
||||
|
||||
/* Duplicate all attributes with name NAME in ATTR list to *ATTRS if
|
||||
they are missing there. */
|
||||
|
||||
extern void duplicate_one_attribute (tree *, tree, const char *);
|
||||
|
||||
/* Duplicate all attributes from user DECL to the corresponding
|
||||
builtin that should be propagated. */
|
||||
|
||||
extern void copy_attributes_to_builtin (tree);
|
||||
|
||||
/* Given two Windows decl attributes lists, possibly including
|
||||
dllimport, return a list of their union . */
|
||||
extern tree merge_dllimport_decl_attributes (tree, tree);
|
||||
|
||||
/* Handle a "dllimport" or "dllexport" attribute. */
|
||||
extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
|
||||
|
||||
extern int attribute_list_equal (const_tree, const_tree);
|
||||
extern int attribute_list_contained (const_tree, const_tree);
|
||||
|
||||
/* The backbone of lookup_attribute(). ATTR_LEN is the string length
|
||||
of ATTR_NAME, and LIST is not NULL_TREE.
|
||||
|
||||
The function is called from lookup_attribute in order to optimize
|
||||
for size. */
|
||||
extern tree private_lookup_attribute (const char *attr_name, size_t attr_len,
|
||||
tree list);
|
||||
extern tree private_lookup_attribute (const char *attr_ns,
|
||||
const char *attr_name,
|
||||
size_t attr_ns_len, size_t attr_len,
|
||||
tree list);
|
||||
|
||||
extern unsigned decls_mismatched_attributes (tree, tree, tree,
|
||||
const char* const[],
|
||||
pretty_printer*);
|
||||
|
||||
extern void maybe_diag_alias_attributes (tree, tree);
|
||||
|
||||
/* For a given string S of length L, strip leading and trailing '_' characters
|
||||
so that we have a canonical form of attribute names. NB: This function may
|
||||
change S and L. */
|
||||
|
||||
template <typename T>
|
||||
inline bool
|
||||
canonicalize_attr_name (const char *&s, T &l)
|
||||
{
|
||||
if (l > 4 && s[0] == '_' && s[1] == '_' && s[l - 1] == '_' && s[l - 2] == '_')
|
||||
{
|
||||
s += 2;
|
||||
l -= 4;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
|
||||
so that we have a canonical form of attribute names. */
|
||||
|
||||
inline tree
|
||||
canonicalize_attr_name (tree attr_name)
|
||||
{
|
||||
size_t l = IDENTIFIER_LENGTH (attr_name);
|
||||
const char *s = IDENTIFIER_POINTER (attr_name);
|
||||
|
||||
if (canonicalize_attr_name (s, l))
|
||||
return get_identifier_with_length (s, l);
|
||||
|
||||
return attr_name;
|
||||
}
|
||||
|
||||
/* Compare attribute identifiers ATTR1 and ATTR2 with length ATTR1_LEN and
|
||||
ATTR2_LEN. */
|
||||
|
||||
inline bool
|
||||
cmp_attribs (const char *attr1, size_t attr1_len,
|
||||
const char *attr2, size_t attr2_len)
|
||||
{
|
||||
return attr1_len == attr2_len && strncmp (attr1, attr2, attr1_len) == 0;
|
||||
}
|
||||
|
||||
/* Compare attribute identifiers ATTR1 and ATTR2. */
|
||||
|
||||
inline bool
|
||||
cmp_attribs (const char *attr1, const char *attr2)
|
||||
{
|
||||
return cmp_attribs (attr1, strlen (attr1), attr2, strlen (attr2));
|
||||
}
|
||||
|
||||
/* Given an identifier node IDENT and a string ATTR_NAME, return true
|
||||
if the identifier node is a valid attribute name for the string. */
|
||||
|
||||
inline bool
|
||||
is_attribute_p (const char *attr_name, const_tree ident)
|
||||
{
|
||||
return cmp_attribs (attr_name, strlen (attr_name),
|
||||
IDENTIFIER_POINTER (ident), IDENTIFIER_LENGTH (ident));
|
||||
}
|
||||
|
||||
/* Given an attribute ATTR and a string ATTR_NS, return true
|
||||
if the attribute namespace is valid for the string. ATTR_NS "" stands
|
||||
for standard attribute (NULL get_attribute_namespace) or "gnu"
|
||||
namespace. */
|
||||
|
||||
inline bool
|
||||
is_attribute_namespace_p (const char *attr_ns, const_tree attr)
|
||||
{
|
||||
tree ident = get_attribute_namespace (attr);
|
||||
if (attr_ns == NULL)
|
||||
return ident == NULL_TREE;
|
||||
if (attr_ns[0])
|
||||
return ident && is_attribute_p (attr_ns, ident);
|
||||
return ident == NULL_TREE || is_attribute_p ("gnu", ident);
|
||||
}
|
||||
|
||||
/* Given an attribute name ATTR_NAME and a list of attributes LIST,
|
||||
return a pointer to the attribute's list element if the attribute
|
||||
is part of the list, or NULL_TREE if not found. If the attribute
|
||||
appears more than once, this only returns the first occurrence; the
|
||||
TREE_CHAIN of the return value should be passed back in if further
|
||||
occurrences are wanted. ATTR_NAME must be in the form 'text' (not
|
||||
'__text__'). */
|
||||
|
||||
inline tree
|
||||
lookup_attribute (const char *attr_name, tree list)
|
||||
{
|
||||
if (CHECKING_P && attr_name[0] != '_')
|
||||
{
|
||||
size_t attr_len = strlen (attr_name);
|
||||
gcc_checking_assert (!canonicalize_attr_name (attr_name, attr_len));
|
||||
}
|
||||
/* In most cases, list is NULL_TREE. */
|
||||
if (list == NULL_TREE)
|
||||
return NULL_TREE;
|
||||
else
|
||||
{
|
||||
size_t attr_len = strlen (attr_name);
|
||||
/* Do the strlen() before calling the out-of-line implementation.
|
||||
In most cases attr_name is a string constant, and the compiler
|
||||
will optimize the strlen() away. */
|
||||
return private_lookup_attribute (attr_name, attr_len, list);
|
||||
}
|
||||
}
|
||||
|
||||
/* Similar to lookup_attribute, but also match the attribute namespace.
|
||||
ATTR_NS "" stands for either standard attribute or "gnu" namespace. */
|
||||
|
||||
inline tree
|
||||
lookup_attribute (const char *attr_ns, const char *attr_name, tree list)
|
||||
{
|
||||
if (CHECKING_P && attr_name[0] != '_')
|
||||
{
|
||||
size_t attr_len = strlen (attr_name);
|
||||
gcc_checking_assert (!canonicalize_attr_name (attr_name, attr_len));
|
||||
}
|
||||
if (CHECKING_P && attr_ns && attr_ns[0] != '_')
|
||||
{
|
||||
size_t attr_ns_len = strlen (attr_ns);
|
||||
gcc_checking_assert (!canonicalize_attr_name (attr_ns, attr_ns_len));
|
||||
}
|
||||
/* In most cases, list is NULL_TREE. */
|
||||
if (list == NULL_TREE)
|
||||
return NULL_TREE;
|
||||
else
|
||||
{
|
||||
size_t attr_ns_len = attr_ns ? strlen (attr_ns) : 0;
|
||||
size_t attr_len = strlen (attr_name);
|
||||
/* Do the strlen() before calling the out-of-line implementation.
|
||||
In most cases attr_name is a string constant, and the compiler
|
||||
will optimize the strlen() away. */
|
||||
return private_lookup_attribute (attr_ns, attr_name,
|
||||
attr_ns_len, attr_len, list);
|
||||
}
|
||||
}
|
||||
|
||||
/* Given an attribute name ATTR_NAME and a list of attributes LIST,
|
||||
return a pointer to the attribute's list first element if the attribute
|
||||
starts with ATTR_NAME. ATTR_NAME must be in the form 'text' (not
|
||||
'__text__'). */
|
||||
|
||||
inline tree
|
||||
lookup_attribute_by_prefix (const char *attr_name, tree list)
|
||||
{
|
||||
gcc_checking_assert (attr_name[0] != '_');
|
||||
/* In most cases, list is NULL_TREE. */
|
||||
if (list == NULL_TREE)
|
||||
return NULL_TREE;
|
||||
else
|
||||
{
|
||||
size_t attr_len = strlen (attr_name);
|
||||
while (list)
|
||||
{
|
||||
tree name = get_attribute_name (list);
|
||||
size_t ident_len = IDENTIFIER_LENGTH (name);
|
||||
|
||||
if (attr_len > ident_len)
|
||||
{
|
||||
list = TREE_CHAIN (list);
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *p = IDENTIFIER_POINTER (name);
|
||||
gcc_checking_assert (attr_len == 0 || p[0] != '_'
|
||||
|| (ident_len > 1 && p[1] != '_'));
|
||||
if (strncmp (attr_name, p, attr_len) == 0)
|
||||
break;
|
||||
|
||||
list = TREE_CHAIN (list);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
/* Description of a function argument declared with attribute access.
|
||||
Used as an "iterator" over all such arguments in a function declaration
|
||||
or call. */
|
||||
|
||||
struct attr_access
|
||||
{
|
||||
/* The beginning and end of the internal string representation. */
|
||||
const char *str, *end;
|
||||
/* The attribute pointer argument. */
|
||||
tree ptr;
|
||||
/* For a declaration, a TREE_CHAIN of VLA bound expressions stored
|
||||
in TREE_VALUE and their positions in the argument list (stored
|
||||
in TREE_PURPOSE). Each expression may be a PARM_DECL or some
|
||||
other DECL (for ordinary variables), or an EXPR for other
|
||||
expressions (e.g., function calls). */
|
||||
tree size;
|
||||
|
||||
/* The zero-based position of each of the formal function arguments.
|
||||
For the optional SIZARG, UINT_MAX when not specified. For VLAs
|
||||
with multiple variable bounds, SIZARG is the position corresponding
|
||||
to the most significant bound in the argument list. Positions of
|
||||
subsequent bounds are in the TREE_PURPOSE field of the SIZE chain. */
|
||||
unsigned ptrarg;
|
||||
unsigned sizarg;
|
||||
/* For internal specifications only, the constant minimum size of
|
||||
the array, zero if not specified, and HWI_M1U for the unspecified
|
||||
VLA [*] notation. Meaningless for external (explicit) access
|
||||
specifications. */
|
||||
unsigned HOST_WIDE_INT minsize;
|
||||
|
||||
/* The access mode. */
|
||||
access_mode mode;
|
||||
|
||||
/* Set for an attribute added internally rather than by an explicit
|
||||
declaration. */
|
||||
bool internal_p;
|
||||
/* Set for the T[static MINSIZE] array notation for nonzero MINSIZE
|
||||
less than HWI_M1U. */
|
||||
bool static_p;
|
||||
|
||||
/* Return the number of specified VLA bounds. */
|
||||
unsigned vla_bounds (unsigned *) const;
|
||||
|
||||
/* Return internal representation as STRING_CST. */
|
||||
tree to_internal_string () const;
|
||||
|
||||
/* Return the human-readable representation of the external attribute
|
||||
specification (as it might appear in the source code) as STRING_CST. */
|
||||
tree to_external_string () const;
|
||||
|
||||
/* Return argument of array type formatted as a readable string. */
|
||||
std::string array_as_string (tree) const;
|
||||
|
||||
/* Return the access mode corresponding to the character code. */
|
||||
static access_mode from_mode_char (char);
|
||||
|
||||
/* Reset front end-specific attribute access data from attributes. */
|
||||
static void free_lang_data (tree);
|
||||
|
||||
/* The character codes corresponding to all the access modes. */
|
||||
static constexpr char mode_chars[5] = { '-', 'r', 'w', 'x', '^' };
|
||||
|
||||
/* The strings corresponding to just the external access modes. */
|
||||
static constexpr char mode_names[4][11] =
|
||||
{
|
||||
"none", "read_only", "write_only", "read_write"
|
||||
};
|
||||
};
|
||||
|
||||
inline access_mode
|
||||
attr_access::from_mode_char (char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case mode_chars[access_none]: return access_none;
|
||||
case mode_chars[access_read_only]: return access_read_only;
|
||||
case mode_chars[access_write_only]: return access_write_only;
|
||||
case mode_chars[access_read_write]: return access_read_write;
|
||||
case mode_chars[access_deferred]: return access_deferred;
|
||||
}
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Used to define rdwr_map below. */
|
||||
struct rdwr_access_hash: int_hash<int, -1> { };
|
||||
|
||||
/* A mapping between argument number corresponding to attribute access
|
||||
mode (read_only, write_only, or read_write) and operands. */
|
||||
struct attr_access;
|
||||
typedef hash_map<rdwr_access_hash, attr_access> rdwr_map;
|
||||
|
||||
extern void init_attr_rdwr_indices (rdwr_map *, tree);
|
||||
extern attr_access *get_parm_access (rdwr_map &, tree,
|
||||
tree = current_function_decl);
|
||||
|
||||
#endif // GCC_ATTRIBS_H
|
||||
+2804
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user