| # 1 "tccgen.c" | |
| # 1 "<built-in>" | |
| # 1 "<command-line>" | |
| # 1 "tccgen.c" | |
| # 21 "tccgen.c" | |
| # 1 "tcc.h" 1 | |
| # 25 "tcc.h" | |
| # 1 "config.h" 1 | |
| # 26 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 | |
| typedef int size_t; | |
| typedef int __builtin_va_list; | |
| typedef int __gnuc_va_list; | |
| typedef int va_list; | |
| typedef int __int8_t; | |
| typedef int __uint8_t; | |
| typedef int __int16_t; | |
| typedef int __uint16_t; | |
| typedef int __int_least16_t; | |
| typedef int __uint_least16_t; | |
| typedef int __int32_t; | |
| typedef int __uint32_t; | |
| typedef int __int64_t; | |
| typedef int __uint64_t; | |
| typedef int __int_least32_t; | |
| typedef int __uint_least32_t; | |
| typedef int __s8; | |
| typedef int __u8; | |
| typedef int __s16; | |
| typedef int __u16; | |
| typedef int __s32; | |
| typedef int __u32; | |
| typedef int __s64; | |
| typedef int __u64; | |
| typedef int _LOCK_T; | |
| typedef int _LOCK_RECURSIVE_T; | |
| typedef int _off_t; | |
| typedef int __dev_t; | |
| typedef int __uid_t; | |
| typedef int __gid_t; | |
| typedef int _off64_t; | |
| typedef int _fpos_t; | |
| typedef int _ssize_t; | |
| typedef int wint_t; | |
| typedef int _mbstate_t; | |
| typedef int _flock_t; | |
| typedef int _iconv_t; | |
| typedef int __ULong; | |
| typedef int __FILE; | |
| typedef int ptrdiff_t; | |
| typedef int wchar_t; | |
| typedef int __off_t; | |
| typedef int __pid_t; | |
| typedef int __loff_t; | |
| typedef int u_char; | |
| typedef int u_short; | |
| typedef int u_int; | |
| typedef int u_long; | |
| typedef int ushort; | |
| typedef int uint; | |
| typedef int clock_t; | |
| typedef int time_t; | |
| typedef int daddr_t; | |
| typedef int caddr_t; | |
| typedef int ino_t; | |
| typedef int off_t; | |
| typedef int dev_t; | |
| typedef int uid_t; | |
| typedef int gid_t; | |
| typedef int pid_t; | |
| typedef int key_t; | |
| typedef int ssize_t; | |
| typedef int mode_t; | |
| typedef int nlink_t; | |
| typedef int fd_mask; | |
| typedef int _types_fd_set; | |
| typedef int clockid_t; | |
| typedef int timer_t; | |
| typedef int useconds_t; | |
| typedef int suseconds_t; | |
| typedef int FILE; | |
| typedef int fpos_t; | |
| typedef int cookie_read_function_t; | |
| typedef int cookie_write_function_t; | |
| typedef int cookie_seek_function_t; | |
| typedef int cookie_close_function_t; | |
| typedef int cookie_io_functions_t; | |
| typedef int div_t; | |
| typedef int ldiv_t; | |
| typedef int lldiv_t; | |
| typedef int sigset_t; | |
| typedef int __sigset_t; | |
| typedef int _sig_func_ptr; | |
| typedef int sig_atomic_t; | |
| typedef int __tzrule_type; | |
| typedef int __tzinfo_type; | |
| typedef int mbstate_t; | |
| typedef int sem_t; | |
| typedef int pthread_t; | |
| typedef int pthread_attr_t; | |
| typedef int pthread_mutex_t; | |
| typedef int pthread_mutexattr_t; | |
| typedef int pthread_cond_t; | |
| typedef int pthread_condattr_t; | |
| typedef int pthread_key_t; | |
| typedef int pthread_once_t; | |
| typedef int pthread_rwlock_t; | |
| typedef int pthread_rwlockattr_t; | |
| typedef int pthread_spinlock_t; | |
| typedef int pthread_barrier_t; | |
| typedef int pthread_barrierattr_t; | |
| typedef int jmp_buf; | |
| typedef int rlim_t; | |
| typedef int sa_family_t; | |
| typedef int sigjmp_buf; | |
| typedef int stack_t; | |
| typedef int siginfo_t; | |
| typedef int z_stream; | |
| typedef int int8_t; | |
| typedef int uint8_t; | |
| typedef int int16_t; | |
| typedef int uint16_t; | |
| typedef int int32_t; | |
| typedef int uint32_t; | |
| typedef int int64_t; | |
| typedef int uint64_t; | |
| typedef int int_least8_t; | |
| typedef int uint_least8_t; | |
| typedef int int_least16_t; | |
| typedef int uint_least16_t; | |
| typedef int int_least32_t; | |
| typedef int uint_least32_t; | |
| typedef int int_least64_t; | |
| typedef int uint_least64_t; | |
| typedef int int_fast8_t; | |
| typedef int uint_fast8_t; | |
| typedef int int_fast16_t; | |
| typedef int uint_fast16_t; | |
| typedef int int_fast32_t; | |
| typedef int uint_fast32_t; | |
| typedef int int_fast64_t; | |
| typedef int uint_fast64_t; | |
| typedef int intptr_t; | |
| typedef int uintptr_t; | |
| typedef int intmax_t; | |
| typedef int uintmax_t; | |
| typedef _Bool bool; | |
| typedef void* MirEGLNativeWindowType; | |
| typedef void* MirEGLNativeDisplayType; | |
| typedef struct MirConnection MirConnection; | |
| typedef struct MirSurface MirSurface; | |
| typedef struct MirSurfaceSpec MirSurfaceSpec; | |
| typedef struct MirScreencast MirScreencast; | |
| typedef struct MirPromptSession MirPromptSession; | |
| typedef struct MirBufferStream MirBufferStream; | |
| typedef struct MirPersistentId MirPersistentId; | |
| typedef struct MirBlob MirBlob; | |
| typedef struct MirDisplayConfig MirDisplayConfig; | |
| typedef struct xcb_connection_t xcb_connection_t; | |
| typedef uint32_t xcb_window_t; | |
| typedef uint32_t xcb_visualid_t; | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdlib.h" 2 | |
| # 28 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdio.h" 2 | |
| # 29 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/stdarg.h" 2 | |
| # 30 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/string.h" 2 | |
| # 31 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/errno.h" 2 | |
| # 32 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/math.h" 2 | |
| # 33 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/fcntl.h" 2 | |
| # 34 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/setjmp.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/setjmp.h" 2 | |
| # 35 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/time.h" 2 | |
| # 36 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/unistd.h" 2 | |
| # 39 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_typedefs.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/sys/time.h" 2 | |
| # 40 "tcc.h" 2 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/dlfcn.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/dlfcn.h" 2 | |
| # 42 "tcc.h" 2 | |
| extern float strtof (const char *__nptr, char **__endptr); | |
| extern long double strtold (const char *__nptr, char **__endptr); | |
| # 283 "tcc.h" | |
| # 1 "libtcc.h" 1 | |
| # 12 "libtcc.h" | |
| struct TCCState; | |
| typedef struct TCCState TCCState; | |
| TCCState *tcc_new(void); | |
| void tcc_delete(TCCState *s); | |
| void tcc_set_lib_path(TCCState *s, const char *path); | |
| void tcc_set_error_func(TCCState *s, void *error_opaque, | |
| void (*error_func)(void *opaque, const char *msg)); | |
| void tcc_set_options(TCCState *s, const char *str); | |
| int tcc_add_include_path(TCCState *s, const char *pathname); | |
| int tcc_add_sysinclude_path(TCCState *s, const char *pathname); | |
| void tcc_define_symbol(TCCState *s, const char *sym, const char *value); | |
| void tcc_undefine_symbol(TCCState *s, const char *sym); | |
| int tcc_add_file(TCCState *s, const char *filename); | |
| int tcc_compile_string(TCCState *s, const char *buf); | |
| int tcc_set_output_type(TCCState *s, int output_type); | |
| int tcc_add_library_path(TCCState *s, const char *pathname); | |
| int tcc_add_library(TCCState *s, const char *libraryname); | |
| int tcc_add_symbol(TCCState *s, const char *name, const void *val); | |
| int tcc_output_file(TCCState *s, const char *filename); | |
| int tcc_run(TCCState *s, int argc, char **argv); | |
| int tcc_relocate(TCCState *s1, void *ptr); | |
| # 94 "libtcc.h" | |
| void *tcc_get_symbol(TCCState *s, const char *name); | |
| # 284 "tcc.h" 2 | |
| # 1 "elf.h" 1 | |
| # 23 "elf.h" | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/inttypes.h" 1 | |
| # 1 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/_fake_defines.h" 1 | |
| # 2 "/usr/local/google/home/eliben/eli/pycparser/utils/fake_libc_include/inttypes.h" 2 | |
| # 24 "elf.h" 2 | |
| # 41 "elf.h" | |
| typedef uint16_t Elf32_Half; | |
| typedef uint16_t Elf64_Half; | |
| typedef uint32_t Elf32_Word; | |
| typedef int32_t Elf32_Sword; | |
| typedef uint32_t Elf64_Word; | |
| typedef int32_t Elf64_Sword; | |
| typedef uint64_t Elf32_Xword; | |
| typedef int64_t Elf32_Sxword; | |
| typedef uint64_t Elf64_Xword; | |
| typedef int64_t Elf64_Sxword; | |
| typedef uint32_t Elf32_Addr; | |
| typedef uint64_t Elf64_Addr; | |
| typedef uint32_t Elf32_Off; | |
| typedef uint64_t Elf64_Off; | |
| typedef uint16_t Elf32_Section; | |
| typedef uint16_t Elf64_Section; | |
| typedef Elf32_Half Elf32_Versym; | |
| typedef Elf64_Half Elf64_Versym; | |
| typedef struct | |
| { | |
| unsigned char e_ident[(16)]; | |
| Elf32_Half e_type; | |
| Elf32_Half e_machine; | |
| Elf32_Word e_version; | |
| Elf32_Addr e_entry; | |
| Elf32_Off e_phoff; | |
| Elf32_Off e_shoff; | |
| Elf32_Word e_flags; | |
| Elf32_Half e_ehsize; | |
| Elf32_Half e_phentsize; | |
| Elf32_Half e_phnum; | |
| Elf32_Half e_shentsize; | |
| Elf32_Half e_shnum; | |
| Elf32_Half e_shstrndx; | |
| } Elf32_Ehdr; | |
| typedef struct | |
| { | |
| unsigned char e_ident[(16)]; | |
| Elf64_Half e_type; | |
| Elf64_Half e_machine; | |
| Elf64_Word e_version; | |
| Elf64_Addr e_entry; | |
| Elf64_Off e_phoff; | |
| Elf64_Off e_shoff; | |
| Elf64_Word e_flags; | |
| Elf64_Half e_ehsize; | |
| Elf64_Half e_phentsize; | |
| Elf64_Half e_phnum; | |
| Elf64_Half e_shentsize; | |
| Elf64_Half e_shnum; | |
| Elf64_Half e_shstrndx; | |
| } Elf64_Ehdr; | |
| # 282 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Word sh_name; | |
| Elf32_Word sh_type; | |
| Elf32_Word sh_flags; | |
| Elf32_Addr sh_addr; | |
| Elf32_Off sh_offset; | |
| Elf32_Word sh_size; | |
| Elf32_Word sh_link; | |
| Elf32_Word sh_info; | |
| Elf32_Word sh_addralign; | |
| Elf32_Word sh_entsize; | |
| } Elf32_Shdr; | |
| typedef struct | |
| { | |
| Elf64_Word sh_name; | |
| Elf64_Word sh_type; | |
| Elf64_Xword sh_flags; | |
| Elf64_Addr sh_addr; | |
| Elf64_Off sh_offset; | |
| Elf64_Xword sh_size; | |
| Elf64_Word sh_link; | |
| Elf64_Word sh_info; | |
| Elf64_Xword sh_addralign; | |
| Elf64_Xword sh_entsize; | |
| } Elf64_Shdr; | |
| # 392 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Word st_name; | |
| Elf32_Addr st_value; | |
| Elf32_Word st_size; | |
| unsigned char st_info; | |
| unsigned char st_other; | |
| Elf32_Section st_shndx; | |
| } Elf32_Sym; | |
| typedef struct | |
| { | |
| Elf64_Word st_name; | |
| unsigned char st_info; | |
| unsigned char st_other; | |
| Elf64_Section st_shndx; | |
| Elf64_Addr st_value; | |
| Elf64_Xword st_size; | |
| } Elf64_Sym; | |
| typedef struct | |
| { | |
| Elf32_Half si_boundto; | |
| Elf32_Half si_flags; | |
| } Elf32_Syminfo; | |
| typedef struct | |
| { | |
| Elf64_Half si_boundto; | |
| Elf64_Half si_flags; | |
| } Elf64_Syminfo; | |
| # 507 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Addr r_offset; | |
| Elf32_Word r_info; | |
| } Elf32_Rel; | |
| typedef struct | |
| { | |
| Elf64_Addr r_offset; | |
| Elf64_Xword r_info; | |
| } Elf64_Rel; | |
| typedef struct | |
| { | |
| Elf32_Addr r_offset; | |
| Elf32_Word r_info; | |
| Elf32_Sword r_addend; | |
| } Elf32_Rela; | |
| typedef struct | |
| { | |
| Elf64_Addr r_offset; | |
| Elf64_Xword r_info; | |
| Elf64_Sxword r_addend; | |
| } Elf64_Rela; | |
| # 552 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Word p_type; | |
| Elf32_Off p_offset; | |
| Elf32_Addr p_vaddr; | |
| Elf32_Addr p_paddr; | |
| Elf32_Word p_filesz; | |
| Elf32_Word p_memsz; | |
| Elf32_Word p_flags; | |
| Elf32_Word p_align; | |
| } Elf32_Phdr; | |
| typedef struct | |
| { | |
| Elf64_Word p_type; | |
| Elf64_Word p_flags; | |
| Elf64_Off p_offset; | |
| Elf64_Addr p_vaddr; | |
| Elf64_Addr p_paddr; | |
| Elf64_Xword p_filesz; | |
| Elf64_Xword p_memsz; | |
| Elf64_Xword p_align; | |
| } Elf64_Phdr; | |
| # 658 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Sword d_tag; | |
| union | |
| { | |
| Elf32_Word d_val; | |
| Elf32_Addr d_ptr; | |
| } d_un; | |
| } Elf32_Dyn; | |
| typedef struct | |
| { | |
| Elf64_Sxword d_tag; | |
| union | |
| { | |
| Elf64_Xword d_val; | |
| Elf64_Addr d_ptr; | |
| } d_un; | |
| } Elf64_Dyn; | |
| # 834 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Half vd_version; | |
| Elf32_Half vd_flags; | |
| Elf32_Half vd_ndx; | |
| Elf32_Half vd_cnt; | |
| Elf32_Word vd_hash; | |
| Elf32_Word vd_aux; | |
| Elf32_Word vd_next; | |
| } Elf32_Verdef; | |
| typedef struct | |
| { | |
| Elf64_Half vd_version; | |
| Elf64_Half vd_flags; | |
| Elf64_Half vd_ndx; | |
| Elf64_Half vd_cnt; | |
| Elf64_Word vd_hash; | |
| Elf64_Word vd_aux; | |
| Elf64_Word vd_next; | |
| } Elf64_Verdef; | |
| # 876 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Word vda_name; | |
| Elf32_Word vda_next; | |
| } Elf32_Verdaux; | |
| typedef struct | |
| { | |
| Elf64_Word vda_name; | |
| Elf64_Word vda_next; | |
| } Elf64_Verdaux; | |
| typedef struct | |
| { | |
| Elf32_Half vn_version; | |
| Elf32_Half vn_cnt; | |
| Elf32_Word vn_file; | |
| Elf32_Word vn_aux; | |
| Elf32_Word vn_next; | |
| } Elf32_Verneed; | |
| typedef struct | |
| { | |
| Elf64_Half vn_version; | |
| Elf64_Half vn_cnt; | |
| Elf64_Word vn_file; | |
| Elf64_Word vn_aux; | |
| Elf64_Word vn_next; | |
| } Elf64_Verneed; | |
| # 923 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Word vna_hash; | |
| Elf32_Half vna_flags; | |
| Elf32_Half vna_other; | |
| Elf32_Word vna_name; | |
| Elf32_Word vna_next; | |
| } Elf32_Vernaux; | |
| typedef struct | |
| { | |
| Elf64_Word vna_hash; | |
| Elf64_Half vna_flags; | |
| Elf64_Half vna_other; | |
| Elf64_Word vna_name; | |
| Elf64_Word vna_next; | |
| } Elf64_Vernaux; | |
| # 957 "elf.h" | |
| typedef struct | |
| { | |
| uint32_t a_type; | |
| union | |
| { | |
| uint32_t a_val; | |
| } a_un; | |
| } Elf32_auxv_t; | |
| typedef struct | |
| { | |
| uint64_t a_type; | |
| union | |
| { | |
| uint64_t a_val; | |
| } a_un; | |
| } Elf64_auxv_t; | |
| # 1041 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Word n_namesz; | |
| Elf32_Word n_descsz; | |
| Elf32_Word n_type; | |
| } Elf32_Nhdr; | |
| typedef struct | |
| { | |
| Elf64_Word n_namesz; | |
| Elf64_Word n_descsz; | |
| Elf64_Word n_type; | |
| } Elf64_Nhdr; | |
| # 1105 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Xword m_value; | |
| Elf32_Word m_info; | |
| Elf32_Word m_poffset; | |
| Elf32_Half m_repeat; | |
| Elf32_Half m_stride; | |
| } Elf32_Move; | |
| typedef struct | |
| { | |
| Elf64_Xword m_value; | |
| Elf64_Xword m_info; | |
| Elf64_Xword m_poffset; | |
| Elf64_Half m_repeat; | |
| Elf64_Half m_stride; | |
| } Elf64_Move; | |
| # 1489 "elf.h" | |
| typedef union | |
| { | |
| struct | |
| { | |
| Elf32_Word gt_current_g_value; | |
| Elf32_Word gt_unused; | |
| } gt_header; | |
| struct | |
| { | |
| Elf32_Word gt_g_value; | |
| Elf32_Word gt_bytes; | |
| } gt_entry; | |
| } Elf32_gptab; | |
| typedef struct | |
| { | |
| Elf32_Word ri_gprmask; | |
| Elf32_Word ri_cprmask[4]; | |
| Elf32_Sword ri_gp_value; | |
| } Elf32_RegInfo; | |
| typedef struct | |
| { | |
| unsigned char kind; | |
| unsigned char size; | |
| Elf32_Section section; | |
| Elf32_Word info; | |
| } Elf_Options; | |
| # 1565 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Word hwp_flags1; | |
| Elf32_Word hwp_flags2; | |
| } Elf_Options_Hw; | |
| # 1726 "elf.h" | |
| typedef struct | |
| { | |
| Elf32_Word l_name; | |
| Elf32_Word l_time_stamp; | |
| Elf32_Word l_checksum; | |
| Elf32_Word l_version; | |
| Elf32_Word l_flags; | |
| } Elf32_Lib; | |
| typedef struct | |
| { | |
| Elf64_Word l_name; | |
| Elf64_Word l_time_stamp; | |
| Elf64_Word l_checksum; | |
| Elf64_Word l_version; | |
| Elf64_Word l_flags; | |
| } Elf64_Lib; | |
| # 1757 "elf.h" | |
| typedef Elf32_Addr Elf32_Conflict; | |
| # 285 "tcc.h" 2 | |
| # 1 "stab.h" 1 | |
| # 9 "stab.h" | |
| enum __stab_debug_code | |
| { | |
| # 1 "stab.def" 1 | |
| # 24 "stab.def" | |
| N_GSYM=0x20, | |
| N_FNAME=0x22, | |
| N_FUN=0x24, | |
| N_STSYM=0x26, | |
| N_LCSYM=0x28, | |
| N_MAIN=0x2a, | |
| N_PC=0x30, | |
| N_NSYMS=0x32, | |
| N_NOMAP=0x34, | |
| N_OBJ=0x38, | |
| N_OPT=0x3c, | |
| N_RSYM=0x40, | |
| N_M2C=0x42, | |
| N_SLINE=0x44, | |
| N_DSLINE=0x46, | |
| N_BSLINE=0x48, | |
| N_BROWS=0x48, | |
| N_DEFD=0x4a, | |
| N_EHDECL=0x50, | |
| N_MOD2=0x50, | |
| N_CATCH=0x54, | |
| N_SSYM=0x60, | |
| N_SO=0x64, | |
| N_LSYM=0x80, | |
| N_BINCL=0x82, | |
| N_SOL=0x84, | |
| N_PSYM=0xa0, | |
| N_EINCL=0xa2, | |
| N_ENTRY=0xa4, | |
| N_LBRAC=0xc0, | |
| N_EXCL=0xc2, | |
| N_SCOPE=0xc4, | |
| N_RBRAC=0xe0, | |
| N_BCOMM=0xe2, | |
| N_ECOMM=0xe4, | |
| N_ECOML=0xe8, | |
| N_NBTEXT=0xF0, | |
| N_NBDATA=0xF2, | |
| N_NBBSS=0xF4, | |
| N_NBSTS=0xF6, | |
| N_NBLCS=0xF8, | |
| N_LENG=0xfe, | |
| # 12 "stab.h" 2 | |
| LAST_UNUSED_STAB_CODE | |
| }; | |
| # 286 "tcc.h" 2 | |
| # 320 "tcc.h" | |
| # 1 "x86_64-gen.c" 1 | |
| # 57 "x86_64-gen.c" | |
| enum { | |
| TREG_RAX = 0, | |
| TREG_RCX = 1, | |
| TREG_RDX = 2, | |
| TREG_RSP = 4, | |
| TREG_RSI = 6, | |
| TREG_RDI = 7, | |
| TREG_R8 = 8, | |
| TREG_R9 = 9, | |
| TREG_R10 = 10, | |
| TREG_R11 = 11, | |
| TREG_XMM0 = 16, | |
| TREG_XMM1 = 17, | |
| TREG_XMM2 = 18, | |
| TREG_XMM3 = 19, | |
| TREG_XMM4 = 20, | |
| TREG_XMM5 = 21, | |
| TREG_XMM6 = 22, | |
| TREG_XMM7 = 23, | |
| TREG_ST0 = 24, | |
| TREG_MEM = 0x20 | |
| }; | |
| # 321 "tcc.h" 2 | |
| # 1 "x86_64-link.c" 1 | |
| # 322 "tcc.h" 2 | |
| # 381 "tcc.h" | |
| typedef struct TokenSym { | |
| struct TokenSym *hash_next; | |
| struct Sym *sym_define; | |
| struct Sym *sym_label; | |
| struct Sym *sym_struct; | |
| struct Sym *sym_identifier; | |
| int tok; | |
| int len; | |
| char str[1]; | |
| } TokenSym; | |
| typedef int nwchar_t; | |
| typedef struct CString { | |
| int size; | |
| void *data; | |
| int size_allocated; | |
| } CString; | |
| typedef struct CType { | |
| int t; | |
| struct Sym *ref; | |
| } CType; | |
| typedef union CValue { | |
| long double ld; | |
| double d; | |
| float f; | |
| uint64_t i; | |
| struct { | |
| int size; | |
| const void *data; | |
| } str; | |
| int tab[16/4]; | |
| } CValue; | |
| typedef struct SValue { | |
| CType type; | |
| unsigned short r; | |
| unsigned short r2; | |
| CValue c; | |
| struct Sym *sym; | |
| } SValue; | |
| struct SymAttr { | |
| unsigned short | |
| aligned : 5, | |
| packed : 1, | |
| weak : 1, | |
| visibility : 2, | |
| dllexport : 1, | |
| dllimport : 1, | |
| unused : 5; | |
| }; | |
| struct FuncAttr { | |
| unsigned | |
| func_call : 3, | |
| func_type : 2, | |
| func_args : 8; | |
| }; | |
| typedef struct AttributeDef { | |
| struct SymAttr a; | |
| struct FuncAttr f; | |
| struct Section *section; | |
| int alias_target; | |
| int asm_label; | |
| char attr_mode; | |
| } AttributeDef; | |
| typedef struct Sym { | |
| int v; | |
| unsigned short r; | |
| struct SymAttr a; | |
| union { | |
| struct { | |
| int c; | |
| union { | |
| int sym_scope; | |
| int jnext; | |
| struct FuncAttr f; | |
| int auxtype; | |
| }; | |
| }; | |
| long long enum_val; | |
| int *d; | |
| }; | |
| CType type; | |
| union { | |
| struct Sym *next; | |
| int asm_label; | |
| }; | |
| struct Sym *prev; | |
| struct Sym *prev_tok; | |
| } Sym; | |
| typedef struct Section { | |
| unsigned long data_offset; | |
| unsigned char *data; | |
| unsigned long data_allocated; | |
| int sh_name; | |
| int sh_num; | |
| int sh_type; | |
| int sh_flags; | |
| int sh_info; | |
| int sh_addralign; | |
| int sh_entsize; | |
| unsigned long sh_size; | |
| Elf64_Addr sh_addr; | |
| unsigned long sh_offset; | |
| int nb_hashed_syms; | |
| struct Section *link; | |
| struct Section *reloc; | |
| struct Section *hash; | |
| struct Section *prev; | |
| char name[1]; | |
| } Section; | |
| typedef struct DLLReference { | |
| int level; | |
| void *handle; | |
| char name[1]; | |
| } DLLReference; | |
| # 554 "tcc.h" | |
| typedef struct BufferedFile { | |
| uint8_t *buf_ptr; | |
| uint8_t *buf_end; | |
| int fd; | |
| struct BufferedFile *prev; | |
| int line_num; | |
| int line_ref; | |
| int ifndef_macro; | |
| int ifndef_macro_saved; | |
| int *ifdef_stack_ptr; | |
| int include_next_index; | |
| char filename[1024]; | |
| char *true_filename; | |
| unsigned char unget[4]; | |
| unsigned char buffer[1]; | |
| } BufferedFile; | |
| typedef struct TokenString { | |
| int *str; | |
| int len; | |
| int lastlen; | |
| int allocated_len; | |
| int last_line_num; | |
| int save_line_num; | |
| struct TokenString *prev; | |
| const int *prev_ptr; | |
| char alloc; | |
| } TokenString; | |
| typedef struct InlineFunc { | |
| TokenString *func_str; | |
| Sym *sym; | |
| char filename[1]; | |
| } InlineFunc; | |
| typedef struct CachedInclude { | |
| int ifndef_macro; | |
| int once; | |
| int hash_next; | |
| char filename[1]; | |
| } CachedInclude; | |
| typedef struct ExprValue { | |
| uint64_t v; | |
| Sym *sym; | |
| int pcrel; | |
| } ExprValue; | |
| typedef struct ASMOperand { | |
| int id; | |
| char *constraint; | |
| char asm_str[16]; | |
| SValue *vt; | |
| int ref_index; | |
| int input_index; | |
| int priority; | |
| int reg; | |
| int is_llong; | |
| int is_memory; | |
| int is_rw; | |
| } ASMOperand; | |
| struct sym_attr { | |
| unsigned got_offset; | |
| unsigned plt_offset; | |
| int plt_sym; | |
| int dyn_index; | |
| }; | |
| struct TCCState { | |
| int verbose; | |
| int nostdinc; | |
| int nostdlib; | |
| int nocommon; | |
| int static_link; | |
| int rdynamic; | |
| int symbolic; | |
| int alacarte_link; | |
| char *tcc_lib_path; | |
| char *soname; | |
| char *rpath; | |
| int enable_new_dtags; | |
| int output_type; | |
| int output_format; | |
| int char_is_unsigned; | |
| int leading_underscore; | |
| int ms_extensions; | |
| int dollars_in_identifiers; | |
| int ms_bitfields; | |
| int warn_write_strings; | |
| int warn_unsupported; | |
| int warn_error; | |
| int warn_none; | |
| int warn_implicit_function_declaration; | |
| int warn_gcc_compat; | |
| int do_debug; | |
| int do_bounds_check; | |
| int run_test; | |
| Elf64_Addr text_addr; | |
| int has_text_addr; | |
| unsigned section_align; | |
| char *init_symbol; | |
| char *fini_symbol; | |
| int nosse; | |
| DLLReference **loaded_dlls; | |
| int nb_loaded_dlls; | |
| char **include_paths; | |
| int nb_include_paths; | |
| char **sysinclude_paths; | |
| int nb_sysinclude_paths; | |
| char **library_paths; | |
| int nb_library_paths; | |
| char **crt_paths; | |
| int nb_crt_paths; | |
| char **cmd_include_files; | |
| int nb_cmd_include_files; | |
| void *error_opaque; | |
| void (*error_func)(void *opaque, const char *msg); | |
| int error_set_jmp_enabled; | |
| jmp_buf error_jmp_buf; | |
| int nb_errors; | |
| FILE *ppfp; | |
| enum { | |
| LINE_MACRO_OUTPUT_FORMAT_GCC, | |
| LINE_MACRO_OUTPUT_FORMAT_NONE, | |
| LINE_MACRO_OUTPUT_FORMAT_STD, | |
| LINE_MACRO_OUTPUT_FORMAT_P10 = 11 | |
| } Pflag; | |
| char dflag; | |
| char **target_deps; | |
| int nb_target_deps; | |
| BufferedFile *include_stack[32]; | |
| BufferedFile **include_stack_ptr; | |
| int ifdef_stack[64]; | |
| int *ifdef_stack_ptr; | |
| int cached_includes_hash[32]; | |
| CachedInclude **cached_includes; | |
| int nb_cached_includes; | |
| int pack_stack[8]; | |
| int *pack_stack_ptr; | |
| char **pragma_libs; | |
| int nb_pragma_libs; | |
| struct InlineFunc **inline_fns; | |
| int nb_inline_fns; | |
| Section **sections; | |
| int nb_sections; | |
| Section **priv_sections; | |
| int nb_priv_sections; | |
| Section *got; | |
| Section *plt; | |
| Section *dynsymtab_section; | |
| Section *dynsym; | |
| Section *symtab; | |
| struct sym_attr *sym_attrs; | |
| int nb_sym_attrs; | |
| # 805 "tcc.h" | |
| const char *runtime_main; | |
| void **runtime_mem; | |
| int nb_runtime_mem; | |
| struct filespec **files; | |
| int nb_files; | |
| int nb_libraries; | |
| int filetype; | |
| char *outfile; | |
| int option_r; | |
| int do_bench; | |
| int gen_deps; | |
| char *deps_outfile; | |
| int option_pthread; | |
| int argc; | |
| char **argv; | |
| }; | |
| struct filespec { | |
| char type; | |
| char alacarte; | |
| char name[1]; | |
| }; | |
| # 1070 "tcc.h" | |
| enum tcc_token { | |
| TOK_LAST = 256 - 1 | |
| # 1 "tcctok.h" 1 | |
| ,TOK_INT | |
| ,TOK_VOID | |
| ,TOK_CHAR | |
| ,TOK_IF | |
| ,TOK_ELSE | |
| ,TOK_WHILE | |
| ,TOK_BREAK | |
| ,TOK_RETURN | |
| ,TOK_FOR | |
| ,TOK_EXTERN | |
| ,TOK_STATIC | |
| ,TOK_UNSIGNED | |
| ,TOK_GOTO | |
| ,TOK_DO | |
| ,TOK_CONTINUE | |
| ,TOK_SWITCH | |
| ,TOK_CASE | |
| ,TOK_CONST1 | |
| ,TOK_CONST2 | |
| ,TOK_CONST3 | |
| ,TOK_VOLATILE1 | |
| ,TOK_VOLATILE2 | |
| ,TOK_VOLATILE3 | |
| ,TOK_LONG | |
| ,TOK_REGISTER | |
| ,TOK_SIGNED1 | |
| ,TOK_SIGNED2 | |
| ,TOK_SIGNED3 | |
| ,TOK_AUTO | |
| ,TOK_INLINE1 | |
| ,TOK_INLINE2 | |
| ,TOK_INLINE3 | |
| ,TOK_RESTRICT1 | |
| ,TOK_RESTRICT2 | |
| ,TOK_RESTRICT3 | |
| ,TOK_EXTENSION | |
| ,TOK_GENERIC | |
| ,TOK_FLOAT | |
| ,TOK_DOUBLE | |
| ,TOK_BOOL | |
| ,TOK_SHORT | |
| ,TOK_STRUCT | |
| ,TOK_UNION | |
| ,TOK_TYPEDEF | |
| ,TOK_DEFAULT | |
| ,TOK_ENUM | |
| ,TOK_SIZEOF | |
| ,TOK_ATTRIBUTE1 | |
| ,TOK_ATTRIBUTE2 | |
| ,TOK_ALIGNOF1 | |
| ,TOK_ALIGNOF2 | |
| ,TOK_TYPEOF1 | |
| ,TOK_TYPEOF2 | |
| ,TOK_TYPEOF3 | |
| ,TOK_LABEL | |
| ,TOK_ASM1 | |
| ,TOK_ASM2 | |
| ,TOK_ASM3 | |
| # 71 "tcctok.h" | |
| ,TOK_DEFINE | |
| ,TOK_INCLUDE | |
| ,TOK_INCLUDE_NEXT | |
| ,TOK_IFDEF | |
| ,TOK_IFNDEF | |
| ,TOK_ELIF | |
| ,TOK_ENDIF | |
| ,TOK_DEFINED | |
| ,TOK_UNDEF | |
| ,TOK_ERROR | |
| ,TOK_WARNING | |
| ,TOK_LINE | |
| ,TOK_PRAGMA | |
| ,TOK___LINE__ | |
| ,TOK___FILE__ | |
| ,TOK___DATE__ | |
| ,TOK___TIME__ | |
| ,TOK___FUNCTION__ | |
| ,TOK___VA_ARGS__ | |
| ,TOK___COUNTER__ | |
| ,TOK___FUNC__ | |
| ,TOK___NAN__ | |
| ,TOK___SNAN__ | |
| ,TOK___INF__ | |
| ,TOK_SECTION1 | |
| ,TOK_SECTION2 | |
| ,TOK_ALIGNED1 | |
| ,TOK_ALIGNED2 | |
| ,TOK_PACKED1 | |
| ,TOK_PACKED2 | |
| ,TOK_WEAK1 | |
| ,TOK_WEAK2 | |
| ,TOK_ALIAS1 | |
| ,TOK_ALIAS2 | |
| ,TOK_UNUSED1 | |
| ,TOK_UNUSED2 | |
| ,TOK_CDECL1 | |
| ,TOK_CDECL2 | |
| ,TOK_CDECL3 | |
| ,TOK_STDCALL1 | |
| ,TOK_STDCALL2 | |
| ,TOK_STDCALL3 | |
| ,TOK_FASTCALL1 | |
| ,TOK_FASTCALL2 | |
| ,TOK_FASTCALL3 | |
| ,TOK_REGPARM1 | |
| ,TOK_REGPARM2 | |
| ,TOK_MODE | |
| ,TOK_MODE_QI | |
| ,TOK_MODE_DI | |
| ,TOK_MODE_HI | |
| ,TOK_MODE_SI | |
| ,TOK_MODE_word | |
| ,TOK_DLLEXPORT | |
| ,TOK_DLLIMPORT | |
| ,TOK_NORETURN1 | |
| ,TOK_NORETURN2 | |
| ,TOK_VISIBILITY1 | |
| ,TOK_VISIBILITY2 | |
| ,TOK_builtin_types_compatible_p | |
| ,TOK_builtin_choose_expr | |
| ,TOK_builtin_constant_p | |
| ,TOK_builtin_frame_address | |
| ,TOK_builtin_return_address | |
| ,TOK_builtin_expect | |
| ,TOK_builtin_va_arg_types | |
| ,TOK_pack | |
| ,TOK_comment | |
| ,TOK_lib | |
| ,TOK_push_macro | |
| ,TOK_pop_macro | |
| ,TOK_once | |
| ,TOK_option | |
| ,TOK_memcpy | |
| ,TOK_memmove | |
| ,TOK_memset | |
| ,TOK___divdi3 | |
| ,TOK___moddi3 | |
| ,TOK___udivdi3 | |
| ,TOK___umoddi3 | |
| ,TOK___ashrdi3 | |
| ,TOK___lshrdi3 | |
| ,TOK___ashldi3 | |
| ,TOK___floatundisf | |
| ,TOK___floatundidf | |
| ,TOK___floatundixf | |
| ,TOK___fixunsxfdi | |
| ,TOK___fixunssfdi | |
| ,TOK___fixunsdfdi | |
| # 251 "tcctok.h" | |
| ,TOK_alloca | |
| # 285 "tcctok.h" | |
| ,TOK___bound_ptr_add | |
| ,TOK___bound_ptr_indir1 | |
| ,TOK___bound_ptr_indir2 | |
| ,TOK___bound_ptr_indir4 | |
| ,TOK___bound_ptr_indir8 | |
| ,TOK___bound_ptr_indir12 | |
| ,TOK___bound_ptr_indir16 | |
| ,TOK___bound_main_arg | |
| ,TOK___bound_local_new | |
| ,TOK___bound_local_delete | |
| ,TOK_strlen | |
| ,TOK_strcpy | |
| ,TOK_ASMDIR_byte | |
| ,TOK_ASMDIR_word | |
| ,TOK_ASMDIR_align | |
| ,TOK_ASMDIR_balign | |
| ,TOK_ASMDIR_p2align | |
| ,TOK_ASMDIR_set | |
| ,TOK_ASMDIR_skip | |
| ,TOK_ASMDIR_space | |
| ,TOK_ASMDIR_string | |
| ,TOK_ASMDIR_asciz | |
| ,TOK_ASMDIR_ascii | |
| ,TOK_ASMDIR_file | |
| ,TOK_ASMDIR_globl | |
| ,TOK_ASMDIR_global | |
| ,TOK_ASMDIR_weak | |
| ,TOK_ASMDIR_hidden | |
| ,TOK_ASMDIR_ident | |
| ,TOK_ASMDIR_size | |
| ,TOK_ASMDIR_type | |
| ,TOK_ASMDIR_text | |
| ,TOK_ASMDIR_data | |
| ,TOK_ASMDIR_bss | |
| ,TOK_ASMDIR_previous | |
| ,TOK_ASMDIR_pushsection | |
| ,TOK_ASMDIR_popsection | |
| ,TOK_ASMDIR_fill | |
| ,TOK_ASMDIR_rept | |
| ,TOK_ASMDIR_endr | |
| ,TOK_ASMDIR_org | |
| ,TOK_ASMDIR_quad | |
| ,TOK_ASMDIR_code64 | |
| ,TOK_ASMDIR_short | |
| ,TOK_ASMDIR_long | |
| ,TOK_ASMDIR_int | |
| ,TOK_ASMDIR_section | |
| # 1 "i386-tok.h" 1 | |
| ,TOK_ASM_al | |
| ,TOK_ASM_cl | |
| ,TOK_ASM_dl | |
| ,TOK_ASM_bl | |
| ,TOK_ASM_ah | |
| ,TOK_ASM_ch | |
| ,TOK_ASM_dh | |
| ,TOK_ASM_bh | |
| ,TOK_ASM_ax | |
| ,TOK_ASM_cx | |
| ,TOK_ASM_dx | |
| ,TOK_ASM_bx | |
| ,TOK_ASM_sp | |
| ,TOK_ASM_bp | |
| ,TOK_ASM_si | |
| ,TOK_ASM_di | |
| ,TOK_ASM_eax | |
| ,TOK_ASM_ecx | |
| ,TOK_ASM_edx | |
| ,TOK_ASM_ebx | |
| ,TOK_ASM_esp | |
| ,TOK_ASM_ebp | |
| ,TOK_ASM_esi | |
| ,TOK_ASM_edi | |
| ,TOK_ASM_rax | |
| ,TOK_ASM_rcx | |
| ,TOK_ASM_rdx | |
| ,TOK_ASM_rbx | |
| ,TOK_ASM_rsp | |
| ,TOK_ASM_rbp | |
| ,TOK_ASM_rsi | |
| ,TOK_ASM_rdi | |
| ,TOK_ASM_mm0 | |
| ,TOK_ASM_mm1 | |
| ,TOK_ASM_mm2 | |
| ,TOK_ASM_mm3 | |
| ,TOK_ASM_mm4 | |
| ,TOK_ASM_mm5 | |
| ,TOK_ASM_mm6 | |
| ,TOK_ASM_mm7 | |
| ,TOK_ASM_xmm0 | |
| ,TOK_ASM_xmm1 | |
| ,TOK_ASM_xmm2 | |
| ,TOK_ASM_xmm3 | |
| ,TOK_ASM_xmm4 | |
| ,TOK_ASM_xmm5 | |
| ,TOK_ASM_xmm6 | |
| ,TOK_ASM_xmm7 | |
| ,TOK_ASM_cr0 | |
| ,TOK_ASM_cr1 | |
| ,TOK_ASM_cr2 | |
| ,TOK_ASM_cr3 | |
| ,TOK_ASM_cr4 | |
| ,TOK_ASM_cr5 | |
| ,TOK_ASM_cr6 | |
| ,TOK_ASM_cr7 | |
| ,TOK_ASM_tr0 | |
| ,TOK_ASM_tr1 | |
| ,TOK_ASM_tr2 | |
| ,TOK_ASM_tr3 | |
| ,TOK_ASM_tr4 | |
| ,TOK_ASM_tr5 | |
| ,TOK_ASM_tr6 | |
| ,TOK_ASM_tr7 | |
| ,TOK_ASM_db0 | |
| ,TOK_ASM_db1 | |
| ,TOK_ASM_db2 | |
| ,TOK_ASM_db3 | |
| ,TOK_ASM_db4 | |
| ,TOK_ASM_db5 | |
| ,TOK_ASM_db6 | |
| ,TOK_ASM_db7 | |
| ,TOK_ASM_dr0 | |
| ,TOK_ASM_dr1 | |
| ,TOK_ASM_dr2 | |
| ,TOK_ASM_dr3 | |
| ,TOK_ASM_dr4 | |
| ,TOK_ASM_dr5 | |
| ,TOK_ASM_dr6 | |
| ,TOK_ASM_dr7 | |
| ,TOK_ASM_es | |
| ,TOK_ASM_cs | |
| ,TOK_ASM_ss | |
| ,TOK_ASM_ds | |
| ,TOK_ASM_fs | |
| ,TOK_ASM_gs | |
| ,TOK_ASM_st | |
| ,TOK_ASM_rip | |
| ,TOK_ASM_spl | |
| ,TOK_ASM_bpl | |
| ,TOK_ASM_sil | |
| ,TOK_ASM_dil | |
| ,TOK_ASM_movb ,TOK_ASM_movw ,TOK_ASM_movl ,TOK_ASM_movq ,TOK_ASM_mov | |
| ,TOK_ASM_addb ,TOK_ASM_addw ,TOK_ASM_addl ,TOK_ASM_addq ,TOK_ASM_add | |
| ,TOK_ASM_orb ,TOK_ASM_orw ,TOK_ASM_orl ,TOK_ASM_orq ,TOK_ASM_or | |
| ,TOK_ASM_adcb ,TOK_ASM_adcw ,TOK_ASM_adcl ,TOK_ASM_adcq ,TOK_ASM_adc | |
| ,TOK_ASM_sbbb ,TOK_ASM_sbbw ,TOK_ASM_sbbl ,TOK_ASM_sbbq ,TOK_ASM_sbb | |
| ,TOK_ASM_andb ,TOK_ASM_andw ,TOK_ASM_andl ,TOK_ASM_andq ,TOK_ASM_and | |
| ,TOK_ASM_subb ,TOK_ASM_subw ,TOK_ASM_subl ,TOK_ASM_subq ,TOK_ASM_sub | |
| ,TOK_ASM_xorb ,TOK_ASM_xorw ,TOK_ASM_xorl ,TOK_ASM_xorq ,TOK_ASM_xor | |
| ,TOK_ASM_cmpb ,TOK_ASM_cmpw ,TOK_ASM_cmpl ,TOK_ASM_cmpq ,TOK_ASM_cmp | |
| ,TOK_ASM_incb ,TOK_ASM_incw ,TOK_ASM_incl ,TOK_ASM_incq ,TOK_ASM_inc | |
| ,TOK_ASM_decb ,TOK_ASM_decw ,TOK_ASM_decl ,TOK_ASM_decq ,TOK_ASM_dec | |
| ,TOK_ASM_notb ,TOK_ASM_notw ,TOK_ASM_notl ,TOK_ASM_notq ,TOK_ASM_not | |
| ,TOK_ASM_negb ,TOK_ASM_negw ,TOK_ASM_negl ,TOK_ASM_negq ,TOK_ASM_neg | |
| ,TOK_ASM_mulb ,TOK_ASM_mulw ,TOK_ASM_mull ,TOK_ASM_mulq ,TOK_ASM_mul | |
| ,TOK_ASM_imulb ,TOK_ASM_imulw ,TOK_ASM_imull ,TOK_ASM_imulq ,TOK_ASM_imul | |
| ,TOK_ASM_divb ,TOK_ASM_divw ,TOK_ASM_divl ,TOK_ASM_divq ,TOK_ASM_div | |
| ,TOK_ASM_idivb ,TOK_ASM_idivw ,TOK_ASM_idivl ,TOK_ASM_idivq ,TOK_ASM_idiv | |
| ,TOK_ASM_xchgb ,TOK_ASM_xchgw ,TOK_ASM_xchgl ,TOK_ASM_xchgq ,TOK_ASM_xchg | |
| ,TOK_ASM_testb ,TOK_ASM_testw ,TOK_ASM_testl ,TOK_ASM_testq ,TOK_ASM_test | |
| ,TOK_ASM_rolb ,TOK_ASM_rolw ,TOK_ASM_roll ,TOK_ASM_rolq ,TOK_ASM_rol | |
| ,TOK_ASM_rorb ,TOK_ASM_rorw ,TOK_ASM_rorl ,TOK_ASM_rorq ,TOK_ASM_ror | |
| ,TOK_ASM_rclb ,TOK_ASM_rclw ,TOK_ASM_rcll ,TOK_ASM_rclq ,TOK_ASM_rcl | |
| ,TOK_ASM_rcrb ,TOK_ASM_rcrw ,TOK_ASM_rcrl ,TOK_ASM_rcrq ,TOK_ASM_rcr | |
| ,TOK_ASM_shlb ,TOK_ASM_shlw ,TOK_ASM_shll ,TOK_ASM_shlq ,TOK_ASM_shl | |
| ,TOK_ASM_shrb ,TOK_ASM_shrw ,TOK_ASM_shrl ,TOK_ASM_shrq ,TOK_ASM_shr | |
| ,TOK_ASM_sarb ,TOK_ASM_sarw ,TOK_ASM_sarl ,TOK_ASM_sarq ,TOK_ASM_sar | |
| ,TOK_ASM_shldw ,TOK_ASM_shldl ,TOK_ASM_shldq ,TOK_ASM_shld | |
| ,TOK_ASM_shrdw ,TOK_ASM_shrdl ,TOK_ASM_shrdq ,TOK_ASM_shrd | |
| ,TOK_ASM_pushw | |
| ,TOK_ASM_pushl | |
| ,TOK_ASM_pushq | |
| ,TOK_ASM_push | |
| ,TOK_ASM_popw | |
| ,TOK_ASM_popl | |
| ,TOK_ASM_popq | |
| ,TOK_ASM_pop | |
| ,TOK_ASM_inb ,TOK_ASM_inw ,TOK_ASM_inl ,TOK_ASM_in | |
| ,TOK_ASM_outb ,TOK_ASM_outw ,TOK_ASM_outl ,TOK_ASM_out | |
| ,TOK_ASM_movzbw ,TOK_ASM_movzbl ,TOK_ASM_movzbq ,TOK_ASM_movzb | |
| ,TOK_ASM_movzwl | |
| ,TOK_ASM_movsbw | |
| ,TOK_ASM_movsbl | |
| ,TOK_ASM_movswl | |
| ,TOK_ASM_movsbq | |
| ,TOK_ASM_movswq | |
| ,TOK_ASM_movzwq | |
| ,TOK_ASM_movslq | |
| ,TOK_ASM_leaw ,TOK_ASM_leal ,TOK_ASM_leaq ,TOK_ASM_lea | |
| ,TOK_ASM_les | |
| ,TOK_ASM_lds | |
| ,TOK_ASM_lss | |
| ,TOK_ASM_lfs | |
| ,TOK_ASM_lgs | |
| ,TOK_ASM_call | |
| ,TOK_ASM_jmp | |
| ,TOK_ASM_lcall | |
| ,TOK_ASM_ljmp | |
| ,TOK_ASM_jo ,TOK_ASM_jno ,TOK_ASM_jb ,TOK_ASM_jc ,TOK_ASM_jnae ,TOK_ASM_jnb ,TOK_ASM_jnc ,TOK_ASM_jae ,TOK_ASM_je ,TOK_ASM_jz ,TOK_ASM_jne ,TOK_ASM_jnz ,TOK_ASM_jbe ,TOK_ASM_jna ,TOK_ASM_jnbe ,TOK_ASM_ja ,TOK_ASM_js ,TOK_ASM_jns ,TOK_ASM_jp ,TOK_ASM_jpe ,TOK_ASM_jnp ,TOK_ASM_jpo ,TOK_ASM_jl ,TOK_ASM_jnge ,TOK_ASM_jnl ,TOK_ASM_jge ,TOK_ASM_jle ,TOK_ASM_jng ,TOK_ASM_jnle ,TOK_ASM_jg | |
| ,TOK_ASM_seto ,TOK_ASM_setno ,TOK_ASM_setb ,TOK_ASM_setc ,TOK_ASM_setnae ,TOK_ASM_setnb ,TOK_ASM_setnc ,TOK_ASM_setae ,TOK_ASM_sete ,TOK_ASM_setz ,TOK_ASM_setne ,TOK_ASM_setnz ,TOK_ASM_setbe ,TOK_ASM_setna ,TOK_ASM_setnbe ,TOK_ASM_seta ,TOK_ASM_sets ,TOK_ASM_setns ,TOK_ASM_setp ,TOK_ASM_setpe ,TOK_ASM_setnp ,TOK_ASM_setpo ,TOK_ASM_setl ,TOK_ASM_setnge ,TOK_ASM_setnl ,TOK_ASM_setge ,TOK_ASM_setle ,TOK_ASM_setng ,TOK_ASM_setnle ,TOK_ASM_setg | |
| ,TOK_ASM_setob ,TOK_ASM_setnob ,TOK_ASM_setbb ,TOK_ASM_setcb ,TOK_ASM_setnaeb ,TOK_ASM_setnbb ,TOK_ASM_setncb ,TOK_ASM_setaeb ,TOK_ASM_seteb ,TOK_ASM_setzb ,TOK_ASM_setneb ,TOK_ASM_setnzb ,TOK_ASM_setbeb ,TOK_ASM_setnab ,TOK_ASM_setnbeb ,TOK_ASM_setab ,TOK_ASM_setsb ,TOK_ASM_setnsb ,TOK_ASM_setpb ,TOK_ASM_setpeb ,TOK_ASM_setnpb ,TOK_ASM_setpob ,TOK_ASM_setlb ,TOK_ASM_setngeb ,TOK_ASM_setnlb ,TOK_ASM_setgeb ,TOK_ASM_setleb ,TOK_ASM_setngb ,TOK_ASM_setnleb ,TOK_ASM_setgb | |
| ,TOK_ASM_cmovo ,TOK_ASM_cmovno ,TOK_ASM_cmovb ,TOK_ASM_cmovc ,TOK_ASM_cmovnae ,TOK_ASM_cmovnb ,TOK_ASM_cmovnc ,TOK_ASM_cmovae ,TOK_ASM_cmove ,TOK_ASM_cmovz ,TOK_ASM_cmovne ,TOK_ASM_cmovnz ,TOK_ASM_cmovbe ,TOK_ASM_cmovna ,TOK_ASM_cmovnbe ,TOK_ASM_cmova ,TOK_ASM_cmovs ,TOK_ASM_cmovns ,TOK_ASM_cmovp ,TOK_ASM_cmovpe ,TOK_ASM_cmovnp ,TOK_ASM_cmovpo ,TOK_ASM_cmovl ,TOK_ASM_cmovnge ,TOK_ASM_cmovnl ,TOK_ASM_cmovge ,TOK_ASM_cmovle ,TOK_ASM_cmovng ,TOK_ASM_cmovnle ,TOK_ASM_cmovg | |
| ,TOK_ASM_bsfw ,TOK_ASM_bsfl ,TOK_ASM_bsfq ,TOK_ASM_bsf | |
| ,TOK_ASM_bsrw ,TOK_ASM_bsrl ,TOK_ASM_bsrq ,TOK_ASM_bsr | |
| ,TOK_ASM_btw ,TOK_ASM_btl ,TOK_ASM_btq ,TOK_ASM_bt | |
| ,TOK_ASM_btsw ,TOK_ASM_btsl ,TOK_ASM_btsq ,TOK_ASM_bts | |
| ,TOK_ASM_btrw ,TOK_ASM_btrl ,TOK_ASM_btrq ,TOK_ASM_btr | |
| ,TOK_ASM_btcw ,TOK_ASM_btcl ,TOK_ASM_btcq ,TOK_ASM_btc | |
| ,TOK_ASM_larw ,TOK_ASM_larl ,TOK_ASM_larq ,TOK_ASM_lar | |
| ,TOK_ASM_lslw ,TOK_ASM_lsll ,TOK_ASM_lslq ,TOK_ASM_lsl | |
| ,TOK_ASM_fadd ,TOK_ASM_faddp ,TOK_ASM_fadds ,TOK_ASM_fiaddl ,TOK_ASM_faddl ,TOK_ASM_fiadds | |
| ,TOK_ASM_fmul ,TOK_ASM_fmulp ,TOK_ASM_fmuls ,TOK_ASM_fimull ,TOK_ASM_fmull ,TOK_ASM_fimuls | |
| ,TOK_ASM_fcom | |
| ,TOK_ASM_fcom_1 | |
| ,TOK_ASM_fcoms ,TOK_ASM_ficoml ,TOK_ASM_fcoml ,TOK_ASM_ficoms | |
| ,TOK_ASM_fcomp ,TOK_ASM_fcompp ,TOK_ASM_fcomps ,TOK_ASM_ficompl ,TOK_ASM_fcompl ,TOK_ASM_ficomps | |
| ,TOK_ASM_fsub ,TOK_ASM_fsubp ,TOK_ASM_fsubs ,TOK_ASM_fisubl ,TOK_ASM_fsubl ,TOK_ASM_fisubs | |
| ,TOK_ASM_fsubr ,TOK_ASM_fsubrp ,TOK_ASM_fsubrs ,TOK_ASM_fisubrl ,TOK_ASM_fsubrl ,TOK_ASM_fisubrs | |
| ,TOK_ASM_fdiv ,TOK_ASM_fdivp ,TOK_ASM_fdivs ,TOK_ASM_fidivl ,TOK_ASM_fdivl ,TOK_ASM_fidivs | |
| ,TOK_ASM_fdivr ,TOK_ASM_fdivrp ,TOK_ASM_fdivrs ,TOK_ASM_fidivrl ,TOK_ASM_fdivrl ,TOK_ASM_fidivrs | |
| ,TOK_ASM_xaddb ,TOK_ASM_xaddw ,TOK_ASM_xaddl ,TOK_ASM_xaddq ,TOK_ASM_xadd | |
| ,TOK_ASM_cmpxchgb ,TOK_ASM_cmpxchgw ,TOK_ASM_cmpxchgl ,TOK_ASM_cmpxchgq ,TOK_ASM_cmpxchg | |
| ,TOK_ASM_cmpsb ,TOK_ASM_cmpsw ,TOK_ASM_cmpsl ,TOK_ASM_cmpsq ,TOK_ASM_cmps | |
| ,TOK_ASM_scmpb ,TOK_ASM_scmpw ,TOK_ASM_scmpl ,TOK_ASM_scmpq ,TOK_ASM_scmp | |
| ,TOK_ASM_insb ,TOK_ASM_insw ,TOK_ASM_insl ,TOK_ASM_ins | |
| ,TOK_ASM_outsb ,TOK_ASM_outsw ,TOK_ASM_outsl ,TOK_ASM_outs | |
| ,TOK_ASM_lodsb ,TOK_ASM_lodsw ,TOK_ASM_lodsl ,TOK_ASM_lodsq ,TOK_ASM_lods | |
| ,TOK_ASM_slodb ,TOK_ASM_slodw ,TOK_ASM_slodl ,TOK_ASM_slodq ,TOK_ASM_slod | |
| ,TOK_ASM_movsb ,TOK_ASM_movsw ,TOK_ASM_movsl ,TOK_ASM_movsq ,TOK_ASM_movs | |
| ,TOK_ASM_smovb ,TOK_ASM_smovw ,TOK_ASM_smovl ,TOK_ASM_smovq ,TOK_ASM_smov | |
| ,TOK_ASM_scasb ,TOK_ASM_scasw ,TOK_ASM_scasl ,TOK_ASM_scasq ,TOK_ASM_scas | |
| ,TOK_ASM_sscab ,TOK_ASM_sscaw ,TOK_ASM_sscal ,TOK_ASM_sscaq ,TOK_ASM_ssca | |
| ,TOK_ASM_stosb ,TOK_ASM_stosw ,TOK_ASM_stosl ,TOK_ASM_stosq ,TOK_ASM_stos | |
| ,TOK_ASM_sstob ,TOK_ASM_sstow ,TOK_ASM_sstol ,TOK_ASM_sstoq ,TOK_ASM_ssto | |
| # 238 "i386-tok.h" | |
| # 1 "x86_64-asm.h" 1 | |
| ,TOK_ASM_clc | |
| ,TOK_ASM_cld | |
| ,TOK_ASM_cli | |
| ,TOK_ASM_clts | |
| ,TOK_ASM_cmc | |
| ,TOK_ASM_lahf | |
| ,TOK_ASM_sahf | |
| ,TOK_ASM_pushfq | |
| ,TOK_ASM_popfq | |
| ,TOK_ASM_pushf | |
| ,TOK_ASM_popf | |
| ,TOK_ASM_stc | |
| ,TOK_ASM_std | |
| ,TOK_ASM_sti | |
| ,TOK_ASM_aaa | |
| ,TOK_ASM_aas | |
| ,TOK_ASM_daa | |
| ,TOK_ASM_das | |
| ,TOK_ASM_aad | |
| ,TOK_ASM_aam | |
| ,TOK_ASM_cbw | |
| ,TOK_ASM_cwd | |
| ,TOK_ASM_cwde | |
| ,TOK_ASM_cdq | |
| ,TOK_ASM_cbtw | |
| ,TOK_ASM_cwtl | |
| ,TOK_ASM_cwtd | |
| ,TOK_ASM_cltd | |
| ,TOK_ASM_cqto | |
| ,TOK_ASM_int3 | |
| ,TOK_ASM_into | |
| ,TOK_ASM_iret | |
| ,TOK_ASM_rsm | |
| ,TOK_ASM_hlt | |
| ,TOK_ASM_wait | |
| ,TOK_ASM_nop | |
| ,TOK_ASM_pause | |
| ,TOK_ASM_xlat | |
| ,TOK_ASM_lock | |
| ,TOK_ASM_rep | |
| ,TOK_ASM_repe | |
| ,TOK_ASM_repz | |
| ,TOK_ASM_repne | |
| ,TOK_ASM_repnz | |
| ,TOK_ASM_invd | |
| ,TOK_ASM_wbinvd | |
| ,TOK_ASM_cpuid | |
| ,TOK_ASM_wrmsr | |
| ,TOK_ASM_rdtsc | |
| ,TOK_ASM_rdmsr | |
| ,TOK_ASM_rdpmc | |
| ,TOK_ASM_syscall | |
| ,TOK_ASM_sysret | |
| ,TOK_ASM_ud2 | |
| ,TOK_ASM_leave | |
| ,TOK_ASM_ret | |
| ,TOK_ASM_retq | |
| ,TOK_ASM_lret | |
| ,TOK_ASM_fucompp | |
| ,TOK_ASM_ftst | |
| ,TOK_ASM_fxam | |
| ,TOK_ASM_fld1 | |
| ,TOK_ASM_fldl2t | |
| ,TOK_ASM_fldl2e | |
| ,TOK_ASM_fldpi | |
| ,TOK_ASM_fldlg2 | |
| ,TOK_ASM_fldln2 | |
| ,TOK_ASM_fldz | |
| ,TOK_ASM_f2xm1 | |
| ,TOK_ASM_fyl2x | |
| ,TOK_ASM_fptan | |
| ,TOK_ASM_fpatan | |
| ,TOK_ASM_fxtract | |
| ,TOK_ASM_fprem1 | |
| ,TOK_ASM_fdecstp | |
| ,TOK_ASM_fincstp | |
| ,TOK_ASM_fprem | |
| ,TOK_ASM_fyl2xp1 | |
| ,TOK_ASM_fsqrt | |
| ,TOK_ASM_fsincos | |
| ,TOK_ASM_frndint | |
| ,TOK_ASM_fscale | |
| ,TOK_ASM_fsin | |
| ,TOK_ASM_fcos | |
| ,TOK_ASM_fchs | |
| ,TOK_ASM_fabs | |
| ,TOK_ASM_fninit | |
| ,TOK_ASM_fnclex | |
| ,TOK_ASM_fnop | |
| ,TOK_ASM_fwait | |
| ,TOK_ASM_fxch | |
| ,TOK_ASM_fnstsw | |
| ,TOK_ASM_emms | |
| # 239 "i386-tok.h" 2 | |
| # 250 "i386-tok.h" | |
| # 1 "x86_64-asm.h" 1 | |
| ,TOK_ASM_sysretq | |
| ,TOK_ASM_ljmpw | |
| ,TOK_ASM_ljmpl | |
| ,TOK_ASM_enter | |
| ,TOK_ASM_loopne | |
| ,TOK_ASM_loopnz | |
| ,TOK_ASM_loope | |
| ,TOK_ASM_loopz | |
| ,TOK_ASM_loop | |
| ,TOK_ASM_jecxz | |
| ,TOK_ASM_fld | |
| ,TOK_ASM_fldl | |
| ,TOK_ASM_flds | |
| ,TOK_ASM_fildl | |
| ,TOK_ASM_fildq | |
| ,TOK_ASM_fildll | |
| ,TOK_ASM_fldt | |
| ,TOK_ASM_fbld | |
| ,TOK_ASM_fst | |
| ,TOK_ASM_fstl | |
| ,TOK_ASM_fsts | |
| ,TOK_ASM_fstps | |
| ,TOK_ASM_fstpl | |
| ,TOK_ASM_fist | |
| ,TOK_ASM_fistp | |
| ,TOK_ASM_fistl | |
| ,TOK_ASM_fistpl | |
| ,TOK_ASM_fstp | |
| ,TOK_ASM_fistpq | |
| ,TOK_ASM_fistpll | |
| ,TOK_ASM_fstpt | |
| ,TOK_ASM_fbstp | |
| ,TOK_ASM_fucom | |
| ,TOK_ASM_fucomp | |
| ,TOK_ASM_finit | |
| ,TOK_ASM_fldcw | |
| ,TOK_ASM_fnstcw | |
| ,TOK_ASM_fstcw | |
| ,TOK_ASM_fstsw | |
| ,TOK_ASM_fclex | |
| ,TOK_ASM_fnstenv | |
| ,TOK_ASM_fstenv | |
| ,TOK_ASM_fldenv | |
| ,TOK_ASM_fnsave | |
| ,TOK_ASM_fsave | |
| ,TOK_ASM_frstor | |
| ,TOK_ASM_ffree | |
| ,TOK_ASM_ffreep | |
| ,TOK_ASM_fxsave | |
| ,TOK_ASM_fxrstor | |
| ,TOK_ASM_fxsaveq | |
| ,TOK_ASM_fxrstorq | |
| ,TOK_ASM_arpl | |
| ,TOK_ASM_lgdt | |
| ,TOK_ASM_lgdtq | |
| ,TOK_ASM_lidt | |
| ,TOK_ASM_lidtq | |
| ,TOK_ASM_lldt | |
| ,TOK_ASM_lmsw | |
| ,TOK_ASM_ltr | |
| ,TOK_ASM_sgdt | |
| ,TOK_ASM_sgdtq | |
| ,TOK_ASM_sidt | |
| ,TOK_ASM_sidtq | |
| ,TOK_ASM_sldt | |
| ,TOK_ASM_smsw | |
| ,TOK_ASM_str | |
| ,TOK_ASM_verr | |
| ,TOK_ASM_verw | |
| ,TOK_ASM_swapgs | |
| ,TOK_ASM_bswap | |
| ,TOK_ASM_bswapl | |
| ,TOK_ASM_bswapq | |
| ,TOK_ASM_invlpg | |
| ,TOK_ASM_cmpxchg8b | |
| ,TOK_ASM_cmpxchg16b | |
| ,TOK_ASM_fcmovb | |
| ,TOK_ASM_fcmove | |
| ,TOK_ASM_fcmovbe | |
| ,TOK_ASM_fcmovu | |
| ,TOK_ASM_fcmovnb | |
| ,TOK_ASM_fcmovne | |
| ,TOK_ASM_fcmovnbe | |
| ,TOK_ASM_fcmovnu | |
| ,TOK_ASM_fucomi | |
| ,TOK_ASM_fcomi | |
| ,TOK_ASM_fucomip | |
| ,TOK_ASM_fcomip | |
| ,TOK_ASM_movd | |
| ,TOK_ASM_packssdw | |
| ,TOK_ASM_packsswb | |
| ,TOK_ASM_packuswb | |
| ,TOK_ASM_paddb | |
| ,TOK_ASM_paddw | |
| ,TOK_ASM_paddd | |
| ,TOK_ASM_paddsb | |
| ,TOK_ASM_paddsw | |
| ,TOK_ASM_paddusb | |
| ,TOK_ASM_paddusw | |
| ,TOK_ASM_pand | |
| ,TOK_ASM_pandn | |
| ,TOK_ASM_pcmpeqb | |
| ,TOK_ASM_pcmpeqw | |
| ,TOK_ASM_pcmpeqd | |
| ,TOK_ASM_pcmpgtb | |
| ,TOK_ASM_pcmpgtw | |
| ,TOK_ASM_pcmpgtd | |
| ,TOK_ASM_pmaddwd | |
| ,TOK_ASM_pmulhw | |
| ,TOK_ASM_pmullw | |
| ,TOK_ASM_por | |
| ,TOK_ASM_psllw | |
| ,TOK_ASM_pslld | |
| ,TOK_ASM_psllq | |
| ,TOK_ASM_psraw | |
| ,TOK_ASM_psrad | |
| ,TOK_ASM_psrlw | |
| ,TOK_ASM_psrld | |
| ,TOK_ASM_psrlq | |
| ,TOK_ASM_psubb | |
| ,TOK_ASM_psubw | |
| ,TOK_ASM_psubd | |
| ,TOK_ASM_psubsb | |
| ,TOK_ASM_psubsw | |
| ,TOK_ASM_psubusb | |
| ,TOK_ASM_psubusw | |
| ,TOK_ASM_punpckhbw | |
| ,TOK_ASM_punpckhwd | |
| ,TOK_ASM_punpckhdq | |
| ,TOK_ASM_punpcklbw | |
| ,TOK_ASM_punpcklwd | |
| ,TOK_ASM_punpckldq | |
| ,TOK_ASM_pxor | |
| ,TOK_ASM_movups | |
| ,TOK_ASM_movaps | |
| ,TOK_ASM_movhps | |
| ,TOK_ASM_addps | |
| ,TOK_ASM_cvtpi2ps | |
| ,TOK_ASM_cvtps2pi | |
| ,TOK_ASM_cvttps2pi | |
| ,TOK_ASM_divps | |
| ,TOK_ASM_maxps | |
| ,TOK_ASM_minps | |
| ,TOK_ASM_mulps | |
| ,TOK_ASM_pavgb | |
| ,TOK_ASM_pavgw | |
| ,TOK_ASM_pmaxsw | |
| ,TOK_ASM_pmaxub | |
| ,TOK_ASM_pminsw | |
| ,TOK_ASM_pminub | |
| ,TOK_ASM_rcpss | |
| ,TOK_ASM_rsqrtps | |
| ,TOK_ASM_sqrtps | |
| ,TOK_ASM_subps | |
| ,TOK_ASM_prefetchnta | |
| ,TOK_ASM_prefetcht0 | |
| ,TOK_ASM_prefetcht1 | |
| ,TOK_ASM_prefetcht2 | |
| ,TOK_ASM_prefetchw | |
| ,TOK_ASM_lfence | |
| ,TOK_ASM_mfence | |
| ,TOK_ASM_sfence | |
| ,TOK_ASM_clflush | |
| # 251 "i386-tok.h" 2 | |
| # 350 "tcctok.h" 2 | |
| # 1074 "tcc.h" 2 | |
| }; | |
| static int gnu_ext; | |
| static int tcc_ext; | |
| static struct TCCState *tcc_state; | |
| static char *pstrcpy(char *buf, int buf_size, const char *s); | |
| static char *pstrcat(char *buf, int buf_size, const char *s); | |
| static char *pstrncpy(char *out, const char *in, size_t num); | |
| char *tcc_basename(const char *name); | |
| char *tcc_fileextension (const char *name); | |
| void tcc_free(void *ptr); | |
| void *tcc_malloc(unsigned long size); | |
| void *tcc_mallocz(unsigned long size); | |
| void *tcc_realloc(void *ptr, unsigned long size); | |
| char *tcc_strdup(const char *str); | |
| # 1120 "tcc.h" | |
| void tcc_memcheck(void); | |
| void tcc_error_noabort(const char *fmt, ...); | |
| void tcc_error(const char *fmt, ...); | |
| void tcc_warning(const char *fmt, ...); | |
| static void dynarray_add(void *ptab, int *nb_ptr, void *data); | |
| static void dynarray_reset(void *pp, int *n); | |
| static inline void cstr_ccat(CString *cstr, int ch); | |
| static void cstr_cat(CString *cstr, const char *str, int len); | |
| static void cstr_wccat(CString *cstr, int ch); | |
| static void cstr_new(CString *cstr); | |
| static void cstr_free(CString *cstr); | |
| static void cstr_reset(CString *cstr); | |
| static inline void sym_free(Sym *sym); | |
| static Sym *sym_push2(Sym **ps, int v, int t, int c); | |
| static Sym *sym_find2(Sym *s, int v); | |
| static Sym *sym_push(int v, CType *type, int r, int c); | |
| static void sym_pop(Sym **ptop, Sym *b, int keep); | |
| static inline Sym *struct_find(int v); | |
| static inline Sym *sym_find(int v); | |
| static Sym *global_identifier_push(int v, int t, int c); | |
| static void tcc_open_bf(TCCState *s1, const char *filename, int initlen); | |
| static int tcc_open(TCCState *s1, const char *filename); | |
| static void tcc_close(void); | |
| static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags); | |
| # 1166 "tcc.h" | |
| static int tcc_add_crt(TCCState *s, const char *filename); | |
| static int tcc_add_dll(TCCState *s, const char *filename, int flags); | |
| static void tcc_add_pragma_libs(TCCState *s1); | |
| int tcc_add_library_err(TCCState *s, const char *f); | |
| void tcc_print_stats(TCCState *s, unsigned total_time); | |
| int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind); | |
| # 1188 "tcc.h" | |
| static struct BufferedFile *file; | |
| static int ch, tok; | |
| static CValue tokc; | |
| static const int *macro_ptr; | |
| static int parse_flags; | |
| static int tok_flags; | |
| static CString tokcstr; | |
| static int total_lines; | |
| static int total_bytes; | |
| static int tok_ident; | |
| static TokenSym **table_ident; | |
| # 1222 "tcc.h" | |
| static TokenSym *tok_alloc(const char *str, int len); | |
| static const char *get_tok_str(int v, CValue *cv); | |
| static void begin_macro(TokenString *str, int alloc); | |
| static void end_macro(void); | |
| static int set_idnum(int c, int val); | |
| static inline void tok_str_new(TokenString *s); | |
| static TokenString *tok_str_alloc(void); | |
| static void tok_str_free(TokenString *s); | |
| static void tok_str_free_str(int *str); | |
| static void tok_str_add(TokenString *s, int t); | |
| static void tok_str_add_tok(TokenString *s); | |
| static inline void define_push(int v, int macro_type, int *str, Sym *first_arg); | |
| static void define_undef(Sym *s); | |
| static inline Sym *define_find(int v); | |
| static void free_defines(Sym *b); | |
| static Sym *label_find(int v); | |
| static Sym *label_push(Sym **ptop, int v, int flags); | |
| static void label_pop(Sym **ptop, Sym *slast, int keep); | |
| static void parse_define(void); | |
| static void preprocess(int is_bof); | |
| static void next_nomacro(void); | |
| static void next(void); | |
| static inline void unget_tok(int last_tok); | |
| static void preprocess_start(TCCState *s1, int is_asm); | |
| static void preprocess_end(TCCState *s1); | |
| static void tccpp_new(TCCState *s); | |
| static void tccpp_delete(TCCState *s); | |
| static int tcc_preprocess(TCCState *s1); | |
| static void skip(int c); | |
| static void expect(const char *msg); | |
| static inline int is_space(int ch) { | |
| return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r'; | |
| } | |
| static inline int isid(int c) { | |
| return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; | |
| } | |
| static inline int isnum(int c) { | |
| return c >= '0' && c <= '9'; | |
| } | |
| static inline int isoct(int c) { | |
| return c >= '0' && c <= '7'; | |
| } | |
| static inline int toup(int c) { | |
| return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; | |
| } | |
| static Sym *sym_free_first; | |
| static void **sym_pools; | |
| static int nb_sym_pools; | |
| static Sym *global_stack; | |
| static Sym *local_stack; | |
| static Sym *local_label_stack; | |
| static Sym *global_label_stack; | |
| static Sym *define_stack; | |
| static CType char_pointer_type, func_old_type, int_type, size_type; | |
| static SValue __vstack[1+ 256], *vtop, *pvtop; | |
| static int rsym, anon_sym, ind, loc; | |
| static int const_wanted; | |
| static int nocode_wanted; | |
| static int global_expr; | |
| static CType func_vt; | |
| static int func_var; | |
| static int func_vc; | |
| static int last_line_num, last_ind, func_ind; | |
| static const char *funcname; | |
| static int g_debug; | |
| static void tcc_debug_start(TCCState *s1); | |
| static void tcc_debug_end(TCCState *s1); | |
| static void tcc_debug_funcstart(TCCState *s1, Sym *sym); | |
| static void tcc_debug_funcend(TCCState *s1, int size); | |
| static void tcc_debug_line(TCCState *s1); | |
| static int tccgen_compile(TCCState *s1); | |
| static void free_inline_functions(TCCState *s); | |
| static void check_vstack(void); | |
| static inline int is_float(int t); | |
| static int ieee_finite(double d); | |
| static void test_lvalue(void); | |
| static void vpushi(int v); | |
| static Elf64_Sym *elfsym(Sym *); | |
| static void update_storage(Sym *sym); | |
| static Sym *external_global_sym(int v, CType *type, int r); | |
| static void vset(CType *type, int r, int v); | |
| static void vswap(void); | |
| static void vpush_global_sym(CType *type, int v); | |
| static void vrote(SValue *e, int n); | |
| static void vrott(int n); | |
| static void vrotb(int n); | |
| static void vpushv(SValue *v); | |
| static void save_reg(int r); | |
| static void save_reg_upstack(int r, int n); | |
| static int get_reg(int rc); | |
| static void save_regs(int n); | |
| static void gaddrof(void); | |
| static int gv(int rc); | |
| static void gv2(int rc1, int rc2); | |
| static void vpop(void); | |
| static void gen_op(int op); | |
| static int type_size(CType *type, int *a); | |
| static void mk_pointer(CType *type); | |
| static void vstore(void); | |
| static void inc(int post, int c); | |
| static void parse_mult_str (CString *astr, const char *msg); | |
| static void parse_asm_str(CString *astr); | |
| static int lvalue_type(int t); | |
| static void indir(void); | |
| static void unary(void); | |
| static void expr_prod(void); | |
| static void expr_sum(void); | |
| static void gexpr(void); | |
| static int expr_const(void); | |
| static Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size); | |
| static int classify_x86_64_va_arg(CType *ty); | |
| # 1362 "tcc.h" | |
| typedef struct { | |
| unsigned int n_strx; | |
| unsigned char n_type; | |
| unsigned char n_other; | |
| unsigned short n_desc; | |
| unsigned int n_value; | |
| } Stab_Sym; | |
| static Section *text_section, *data_section, *bss_section; | |
| static Section *common_section; | |
| static Section *cur_text_section; | |
| static Section *last_text_section; | |
| static Section *bounds_section; | |
| static Section *lbounds_section; | |
| static void tccelf_bounds_new(TCCState *s); | |
| static Section *symtab_section; | |
| static Section *stab_section, *stabstr_section; | |
| static void tccelf_new(TCCState *s); | |
| static void tccelf_delete(TCCState *s); | |
| static void tccelf_stab_new(TCCState *s); | |
| static void tccelf_begin_file(TCCState *s1); | |
| static void tccelf_end_file(TCCState *s1); | |
| static Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags); | |
| static void section_realloc(Section *sec, unsigned long new_size); | |
| static size_t section_add(Section *sec, Elf64_Addr size, int align); | |
| static void *section_ptr_add(Section *sec, Elf64_Addr size); | |
| static void section_reserve(Section *sec, unsigned long size); | |
| static Section *find_section(TCCState *s1, const char *name); | |
| static Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags); | |
| static void put_extern_sym2(Sym *sym, int sh_num, Elf64_Addr value, unsigned long size, int can_add_underscore); | |
| static void put_extern_sym(Sym *sym, Section *section, Elf64_Addr value, unsigned long size); | |
| static void greloca(Section *s, Sym *sym, unsigned long offset, int type, Elf64_Addr addend); | |
| static int put_elf_str(Section *s, const char *sym); | |
| static int put_elf_sym(Section *s, Elf64_Addr value, unsigned long size, int info, int other, int shndx, const char *name); | |
| static int set_elf_sym(Section *s, Elf64_Addr value, unsigned long size, int info, int other, int shndx, const char *name); | |
| static int find_elf_sym(Section *s, const char *name); | |
| static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol); | |
| static void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, int type, int symbol, Elf64_Addr addend); | |
| static void put_stabs(const char *str, int type, int other, int desc, unsigned long value); | |
| static void put_stabs_r(const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index); | |
| static void put_stabn(int type, int other, int desc, int value); | |
| static void put_stabd(int type, int other, int desc); | |
| static void resolve_common_syms(TCCState *s1); | |
| static void relocate_syms(TCCState *s1, Section *symtab, int do_resolve); | |
| static void relocate_section(TCCState *s1, Section *s); | |
| static int tcc_object_type(int fd, Elf64_Ehdr *h); | |
| static int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset); | |
| static int tcc_load_archive(TCCState *s1, int fd); | |
| static void tcc_add_bcheck(TCCState *s1); | |
| static void tcc_add_runtime(TCCState *s1); | |
| static void build_got_entries(TCCState *s1); | |
| static struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc); | |
| static void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset); | |
| static Elf64_Addr get_elf_sym_addr(TCCState *s, const char *name, int err); | |
| static void *tcc_get_symbol_err(TCCState *s, const char *name); | |
| static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level); | |
| static int tcc_load_ldscript(TCCState *s1); | |
| static uint8_t *parse_comment(uint8_t *p); | |
| static void minp(void); | |
| static inline void inp(void); | |
| static int handle_eob(void); | |
| enum gotplt_entry { | |
| NO_GOTPLT_ENTRY, | |
| BUILD_GOT_ONLY, | |
| AUTO_GOTPLT_ENTRY, | |
| ALWAYS_GOTPLT_ENTRY | |
| }; | |
| static int code_reloc (int reloc_type); | |
| static int gotplt_entry_type (int reloc_type); | |
| static unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr); | |
| static void relocate_init(Section *sr); | |
| static void relocate(TCCState *s1, Elf64_Rela *rel, int type, unsigned char *ptr, Elf64_Addr addr, Elf64_Addr val); | |
| static void relocate_plt(TCCState *s1); | |
| static const int reg_classes[25]; | |
| static void gsym_addr(int t, int a); | |
| static void gsym(int t); | |
| static void load(int r, SValue *sv); | |
| static void store(int r, SValue *v); | |
| static int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize); | |
| static void gfunc_call(int nb_args); | |
| static void gfunc_prolog(CType *func_type); | |
| static void gfunc_epilog(void); | |
| static int gjmp(int t); | |
| static void gjmp_addr(int a); | |
| static int gtst(int inv, int t); | |
| static void gtst_addr(int inv, int a); | |
| static void gen_opi(int op); | |
| static void gen_opf(int op); | |
| static void gen_cvt_ftoi(int t); | |
| static void gen_cvt_ftof(int t); | |
| static void ggoto(void); | |
| static void o(unsigned int c); | |
| static void gen_cvt_itof(int t); | |
| static void gen_vla_sp_save(int addr); | |
| static void gen_vla_sp_restore(int addr); | |
| static void gen_vla_alloc(CType *type, int align); | |
| static inline uint16_t read16le(unsigned char *p) { | |
| return p[0] | (uint16_t)p[1] << 8; | |
| } | |
| static inline void write16le(unsigned char *p, uint16_t x) { | |
| p[0] = x & 255; p[1] = x >> 8 & 255; | |
| } | |
| static inline uint32_t read32le(unsigned char *p) { | |
| return read16le(p) | (uint32_t)read16le(p + 2) << 16; | |
| } | |
| static inline void write32le(unsigned char *p, uint32_t x) { | |
| write16le(p, x); write16le(p + 2, x >> 16); | |
| } | |
| static inline void add32le(unsigned char *p, int32_t x) { | |
| write32le(p, read32le(p) + x); | |
| } | |
| static inline uint64_t read64le(unsigned char *p) { | |
| return read32le(p) | (uint64_t)read32le(p + 4) << 32; | |
| } | |
| static inline void write64le(unsigned char *p, uint64_t x) { | |
| write32le(p, x); write32le(p + 4, x >> 32); | |
| } | |
| static inline void add64le(unsigned char *p, int64_t x) { | |
| write64le(p, read64le(p) + x); | |
| } | |
| static void g(int c); | |
| static void gen_le16(int c); | |
| static void gen_le32(int c); | |
| static void gen_addr32(int r, Sym *sym, int c); | |
| static void gen_addrpc32(int r, Sym *sym, int c); | |
| static void gen_bounded_ptr_add(void); | |
| static void gen_bounded_ptr_deref(void); | |
| static void gen_addr64(int r, Sym *sym, int64_t c); | |
| static void gen_opl(int op); | |
| # 1580 "tcc.h" | |
| static void asm_instr(void); | |
| static void asm_global_instr(void); | |
| static int find_constraint(ASMOperand *operands, int nb_operands, const char *name, const char **pp); | |
| static Sym* get_asm_sym(int name, Sym *csym); | |
| static void asm_expr(TCCState *s1, ExprValue *pe); | |
| static int asm_int_expr(TCCState *s1); | |
| static int tcc_assemble(TCCState *s1, int do_preprocess); | |
| static void gen_expr32(ExprValue *pe); | |
| static void gen_expr64(ExprValue *pe); | |
| static void asm_opcode(TCCState *s1, int opcode); | |
| static int asm_parse_regvar(int t); | |
| static void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg); | |
| static void subst_asm_operand(CString *add_str, SValue *sv, int modifier); | |
| static void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg); | |
| static void asm_clobber(uint8_t *clobber_regs, const char *str); | |
| # 1634 "tcc.h" | |
| static int rt_num_callers; | |
| static const char **rt_bound_error_msg; | |
| static void *rt_prog_main; | |
| static void tcc_set_num_callers(int n); | |
| static void tcc_run_free(TCCState *s1); | |
| # 22 "tccgen.c" 2 | |
| # 31 "tccgen.c" | |
| static int rsym, anon_sym, ind, loc; | |
| static Sym *sym_free_first; | |
| static void **sym_pools; | |
| static int nb_sym_pools; | |
| static Sym *global_stack; | |
| static Sym *local_stack; | |
| static Sym *define_stack; | |
| static Sym *global_label_stack; | |
| static Sym *local_label_stack; | |
| static int local_scope; | |
| static int in_sizeof; | |
| static int section_sym; | |
| static int vlas_in_scope; | |
| static int vla_sp_root_loc; | |
| static int vla_sp_loc; | |
| static SValue __vstack[1+256], *vtop, *pvtop; | |
| static int const_wanted; | |
| static int nocode_wanted; | |
| static int global_expr; | |
| static CType func_vt; | |
| static int func_var; | |
| static int func_vc; | |
| static int last_line_num, last_ind, func_ind; | |
| static const char *funcname; | |
| static int g_debug; | |
| static CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type; | |
| static struct switch_t { | |
| struct case_t { | |
| int64_t v1, v2; | |
| int sym; | |
| } **p; int n; | |
| int def_sym; | |
| } *cur_switch; | |
| static void gen_cast(CType *type); | |
| static void gen_cast_s(int t); | |
| static inline CType *pointed_type(CType *type); | |
| static int is_compatible_types(CType *type1, CType *type2); | |
| static int parse_btype(CType *type, AttributeDef *ad); | |
| static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); | |
| static void parse_expr_type(CType *type); | |
| static void init_putv(CType *type, Section *sec, unsigned long c); | |
| static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only); | |
| static void block(int *bsym, int *csym, int is_expr); | |
| static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); | |
| static void decl(int l); | |
| static int decl0(int l, int is_for_loop_init, Sym *); | |
| static void expr_eq(void); | |
| static void vla_runtime_type_size(CType *type, int *a); | |
| static void vla_sp_restore(void); | |
| static void vla_sp_restore_root(void); | |
| static int is_compatible_unqualified_types(CType *type1, CType *type2); | |
| static inline int64_t expr_const64(void); | |
| static void vpush64(int ty, unsigned long long v); | |
| static void vpush(CType *type); | |
| static int gvtst(int inv, int t); | |
| static void gen_inline_functions(TCCState *s); | |
| static void skip_or_save_block(TokenString **str); | |
| static void gv_dup(void); | |
| static inline int is_float(int t) | |
| { | |
| int bt; | |
| bt = t & 0x000f; | |
| return bt == 10 || bt == 9 || bt == 8 || bt == 14; | |
| } | |
| static int ieee_finite(double d) | |
| { | |
| int p[4]; | |
| memcpy(p, &d, sizeof(double)); | |
| return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; | |
| } | |
| static void test_lvalue(void) | |
| { | |
| if (!(vtop->r & 0x0100)) | |
| expect("lvalue"); | |
| } | |
| static void check_vstack(void) | |
| { | |
| if (pvtop != vtop) | |
| tcc_error("internal compiler error: vstack leak (%d)", vtop - pvtop); | |
| } | |
| # 154 "tccgen.c" | |
| static void tcc_debug_start(TCCState *s1) | |
| { | |
| if (s1->do_debug) { | |
| char buf[512]; | |
| section_sym = put_elf_sym(symtab_section, 0, 0, | |
| ((((0)) << 4) + (((3)) & 0xf)), 0, | |
| text_section->sh_num, 0); | |
| getcwd(buf, sizeof(buf)); | |
| pstrcat(buf, sizeof(buf), "/"); | |
| put_stabs_r(buf, N_SO, 0, 0, | |
| text_section->data_offset, text_section, section_sym); | |
| put_stabs_r(file->filename, N_SO, 0, 0, | |
| text_section->data_offset, text_section, section_sym); | |
| last_ind = 0; | |
| last_line_num = 0; | |
| } | |
| put_elf_sym(symtab_section, 0, 0, | |
| ((((0)) << 4) + (((4)) & 0xf)), 0, | |
| 0xfff1, file->filename); | |
| } | |
| static void tcc_debug_end(TCCState *s1) | |
| { | |
| if (!s1->do_debug) | |
| return; | |
| put_stabs_r(0, N_SO, 0, 0, | |
| text_section->data_offset, text_section, section_sym); | |
| } | |
| static void tcc_debug_line(TCCState *s1) | |
| { | |
| if (!s1->do_debug) | |
| return; | |
| if ((last_line_num != file->line_num || last_ind != ind)) { | |
| put_stabn(N_SLINE, 0, file->line_num, ind - func_ind); | |
| last_ind = ind; | |
| last_line_num = file->line_num; | |
| } | |
| } | |
| static void tcc_debug_funcstart(TCCState *s1, Sym *sym) | |
| { | |
| char buf[512]; | |
| if (!s1->do_debug) | |
| return; | |
| snprintf(buf, sizeof(buf), "%s:%c1", | |
| funcname, sym->type.t & 0x00002000 ? 'f' : 'F'); | |
| put_stabs_r(buf, N_FUN, 0, file->line_num, 0, | |
| cur_text_section, sym->c); | |
| put_stabn(N_SLINE, 0, file->line_num, 0); | |
| last_ind = 0; | |
| last_line_num = 0; | |
| } | |
| static void tcc_debug_funcend(TCCState *s1, int size) | |
| { | |
| if (!s1->do_debug) | |
| return; | |
| put_stabn(N_FUN, 0, 0, size); | |
| } | |
| static int tccgen_compile(TCCState *s1) | |
| { | |
| cur_text_section = 0; | |
| funcname = ""; | |
| anon_sym = 0x10000000; | |
| section_sym = 0; | |
| const_wanted = 0; | |
| nocode_wanted = 0x80000000; | |
| int_type.t = 3; | |
| char_pointer_type.t = 1; | |
| mk_pointer(&char_pointer_type); | |
| size_type.t = 0x0800 | 4 | 0x0010; | |
| ptrdiff_type.t = 0x0800 | 4; | |
| func_old_type.t = 6; | |
| func_old_type.ref = sym_push(0x20000000, &int_type, 0, 0); | |
| func_old_type.ref->f.func_call = 0; | |
| func_old_type.ref->f.func_type = 2; | |
| tcc_debug_start(s1); | |
| # 273 "tccgen.c" | |
| parse_flags = 0x0001 | 0x0002 | 0x0040; | |
| next(); | |
| decl(0x0030); | |
| gen_inline_functions(s1); | |
| check_vstack(); | |
| tcc_debug_end(s1); | |
| return 0; | |
| } | |
| static Elf64_Sym *elfsym(Sym *s) | |
| { | |
| if (!s || !s->c) | |
| return 0; | |
| return &((Elf64_Sym *)symtab_section->data)[s->c]; | |
| } | |
| static void update_storage(Sym *sym) | |
| { | |
| Elf64_Sym *esym; | |
| int sym_bind, old_sym_bind; | |
| esym = elfsym(sym); | |
| if (!esym) | |
| return; | |
| if (sym->a.visibility) | |
| esym->st_other = (esym->st_other & ~((-1) & 0x03)) | |
| | sym->a.visibility; | |
| if (sym->type.t & 0x00002000) | |
| sym_bind = 0; | |
| else if (sym->a.weak) | |
| sym_bind = 2; | |
| else | |
| sym_bind = 1; | |
| old_sym_bind = (((unsigned char) (esym->st_info)) >> 4); | |
| if (sym_bind != old_sym_bind) { | |
| esym->st_info = ((((sym_bind)) << 4) + (((((esym->st_info) & 0xf))) & 0xf)); | |
| } | |
| # 332 "tccgen.c" | |
| } | |
| static void put_extern_sym2(Sym *sym, int sh_num, | |
| Elf64_Addr value, unsigned long size, | |
| int can_add_underscore) | |
| { | |
| int sym_type, sym_bind, info, other, t; | |
| Elf64_Sym *esym; | |
| const char *name; | |
| char buf1[256]; | |
| char buf[32]; | |
| if (!sym->c) { | |
| name = get_tok_str(sym->v, 0); | |
| if (tcc_state->do_bounds_check) { | |
| switch(sym->v) { | |
| # 366 "tccgen.c" | |
| case TOK_memcpy: | |
| case TOK_memmove: | |
| case TOK_memset: | |
| case TOK_strlen: | |
| case TOK_strcpy: | |
| case TOK_alloca: | |
| strcpy(buf, "__bound_"); | |
| strcat(buf, name); | |
| name = buf; | |
| break; | |
| } | |
| } | |
| t = sym->type.t; | |
| if ((t & 0x000f) == 6) { | |
| sym_type = 2; | |
| } else if ((t & 0x000f) == 0) { | |
| sym_type = 0; | |
| } else { | |
| sym_type = 1; | |
| } | |
| if (t & 0x00002000) | |
| sym_bind = 0; | |
| else | |
| sym_bind = 1; | |
| other = 0; | |
| # 403 "tccgen.c" | |
| if (tcc_state->leading_underscore && can_add_underscore) { | |
| buf1[0] = '_'; | |
| pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); | |
| name = buf1; | |
| } | |
| if (sym->asm_label) | |
| name = get_tok_str(sym->asm_label, 0); | |
| info = ((((sym_bind)) << 4) + (((sym_type)) & 0xf)); | |
| sym->c = put_elf_sym(symtab_section, value, size, info, other, sh_num, name); | |
| } else { | |
| esym = elfsym(sym); | |
| esym->st_value = value; | |
| esym->st_size = size; | |
| esym->st_shndx = sh_num; | |
| } | |
| update_storage(sym); | |
| } | |
| static void put_extern_sym(Sym *sym, Section *section, | |
| Elf64_Addr value, unsigned long size) | |
| { | |
| int sh_num = section ? section->sh_num : 0; | |
| put_extern_sym2(sym, sh_num, value, size, 1); | |
| } | |
| static void greloca(Section *s, Sym *sym, unsigned long offset, int type, | |
| Elf64_Addr addend) | |
| { | |
| int c = 0; | |
| if (nocode_wanted && s == cur_text_section) | |
| return; | |
| if (sym) { | |
| if (0 == sym->c) | |
| put_extern_sym(sym, 0, 0, 0); | |
| c = sym->c; | |
| } | |
| put_elf_reloca(symtab_section, s, offset, type, c, addend); | |
| } | |
| # 456 "tccgen.c" | |
| static Sym *__sym_malloc(void) | |
| { | |
| Sym *sym_pool, *sym, *last_sym; | |
| int i; | |
| sym_pool = tcc_malloc((8192 / sizeof(Sym)) * sizeof(Sym)); | |
| dynarray_add(&sym_pools, &nb_sym_pools, sym_pool); | |
| last_sym = sym_free_first; | |
| sym = sym_pool; | |
| for(i = 0; i < (8192 / sizeof(Sym)); i++) { | |
| sym->next = last_sym; | |
| last_sym = sym; | |
| sym++; | |
| } | |
| sym_free_first = last_sym; | |
| return last_sym; | |
| } | |
| static inline Sym *sym_malloc(void) | |
| { | |
| Sym *sym; | |
| sym = sym_free_first; | |
| if (!sym) | |
| sym = __sym_malloc(); | |
| sym_free_first = sym->next; | |
| return sym; | |
| } | |
| static inline void sym_free(Sym *sym) | |
| { | |
| sym->next = sym_free_first; | |
| sym_free_first = sym; | |
| } | |
| static Sym *sym_push2(Sym **ps, int v, int t, int c) | |
| { | |
| Sym *s; | |
| s = sym_malloc(); | |
| memset(s, 0, sizeof *s); | |
| s->v = v; | |
| s->type.t = t; | |
| s->c = c; | |
| s->prev = *ps; | |
| *ps = s; | |
| return s; | |
| } | |
| static Sym *sym_find2(Sym *s, int v) | |
| { | |
| while (s) { | |
| if (s->v == v) | |
| return s; | |
| else if (s->v == -1) | |
| return 0; | |
| s = s->prev; | |
| } | |
| return 0; | |
| } | |
| static inline Sym *struct_find(int v) | |
| { | |
| v -= 256; | |
| if ((unsigned)v >= (unsigned)(tok_ident - 256)) | |
| return 0; | |
| return table_ident[v]->sym_struct; | |
| } | |
| static inline Sym *sym_find(int v) | |
| { | |
| v -= 256; | |
| if ((unsigned)v >= (unsigned)(tok_ident - 256)) | |
| return 0; | |
| return table_ident[v]->sym_identifier; | |
| } | |
| static Sym *sym_push(int v, CType *type, int r, int c) | |
| { | |
| Sym *s, **ps; | |
| TokenSym *ts; | |
| if (local_stack) | |
| ps = &local_stack; | |
| else | |
| ps = &global_stack; | |
| s = sym_push2(ps, v, type->t, c); | |
| s->type.ref = type->ref; | |
| s->r = r; | |
| if (!(v & 0x20000000) && (v & ~0x40000000) < 0x10000000) { | |
| ts = table_ident[(v & ~0x40000000) - 256]; | |
| if (v & 0x40000000) | |
| ps = &ts->sym_struct; | |
| else | |
| ps = &ts->sym_identifier; | |
| s->prev_tok = *ps; | |
| *ps = s; | |
| s->sym_scope = local_scope; | |
| if (s->prev_tok && s->prev_tok->sym_scope == s->sym_scope) | |
| tcc_error("redeclaration of '%s'", | |
| get_tok_str(v & ~0x40000000, 0)); | |
| } | |
| return s; | |
| } | |
| static Sym *global_identifier_push(int v, int t, int c) | |
| { | |
| Sym *s, **ps; | |
| s = sym_push2(&global_stack, v, t, c); | |
| if (v < 0x10000000) { | |
| ps = &table_ident[v - 256]->sym_identifier; | |
| while (*ps != 0 && (*ps)->sym_scope) | |
| ps = &(*ps)->prev_tok; | |
| s->prev_tok = *ps; | |
| *ps = s; | |
| } | |
| return s; | |
| } | |
| static void sym_pop(Sym **ptop, Sym *b, int keep) | |
| { | |
| Sym *s, *ss, **ps; | |
| TokenSym *ts; | |
| int v; | |
| s = *ptop; | |
| while(s != b) { | |
| ss = s->prev; | |
| v = s->v; | |
| if (!(v & 0x20000000) && (v & ~0x40000000) < 0x10000000) { | |
| ts = table_ident[(v & ~0x40000000) - 256]; | |
| if (v & 0x40000000) | |
| ps = &ts->sym_struct; | |
| else | |
| ps = &ts->sym_identifier; | |
| *ps = s->prev_tok; | |
| } | |
| if (!keep) | |
| sym_free(s); | |
| s = ss; | |
| } | |
| if (!keep) | |
| *ptop = b; | |
| } | |
| static void vsetc(CType *type, int r, CValue *vc) | |
| { | |
| int v; | |
| if (vtop >= (__vstack + 1) + (256 - 1)) | |
| tcc_error("memory full (vstack)"); | |
| # 649 "tccgen.c" | |
| if (vtop >= (__vstack + 1) && !nocode_wanted) { | |
| v = vtop->r & 0x003f; | |
| if (v == 0x0033 || (v & ~1) == 0x0034) | |
| gv(0x0001); | |
| } | |
| vtop++; | |
| vtop->type = *type; | |
| vtop->r = r; | |
| vtop->r2 = 0x0030; | |
| vtop->c = *vc; | |
| vtop->sym = 0; | |
| } | |
| static void vswap(void) | |
| { | |
| SValue tmp; | |
| if (vtop >= (__vstack + 1) && !nocode_wanted) { | |
| int v = vtop->r & 0x003f; | |
| if (v == 0x0033 || (v & ~1) == 0x0034) | |
| gv(0x0001); | |
| } | |
| tmp = vtop[0]; | |
| vtop[0] = vtop[-1]; | |
| vtop[-1] = tmp; | |
| } | |
| static void vpop(void) | |
| { | |
| int v; | |
| v = vtop->r & 0x003f; | |
| if (v == TREG_ST0) { | |
| o(0xd8dd); | |
| } else | |
| if (v == 0x0034 || v == 0x0035) { | |
| gsym(vtop->c.i); | |
| } | |
| vtop--; | |
| } | |
| static void vpush(CType *type) | |
| { | |
| vset(type, 0x0030, 0); | |
| } | |
| static void vpushi(int v) | |
| { | |
| CValue cval; | |
| cval.i = v; | |
| vsetc(&int_type, 0x0030, &cval); | |
| } | |
| static void vpushs(Elf64_Addr v) | |
| { | |
| CValue cval; | |
| cval.i = v; | |
| vsetc(&size_type, 0x0030, &cval); | |
| } | |
| static void vpush64(int ty, unsigned long long v) | |
| { | |
| CValue cval; | |
| CType ctype; | |
| ctype.t = ty; | |
| ctype.ref = 0; | |
| cval.i = v; | |
| vsetc(&ctype, 0x0030, &cval); | |
| } | |
| static inline void vpushll(long long v) | |
| { | |
| vpush64(4, v); | |
| } | |
| static void vset(CType *type, int r, int v) | |
| { | |
| CValue cval; | |
| cval.i = v; | |
| vsetc(type, r, &cval); | |
| } | |
| static void vseti(int r, int v) | |
| { | |
| CType type; | |
| type.t = 3; | |
| type.ref = 0; | |
| vset(&type, r, v); | |
| } | |
| static void vpushv(SValue *v) | |
| { | |
| if (vtop >= (__vstack + 1) + (256 - 1)) | |
| tcc_error("memory full (vstack)"); | |
| vtop++; | |
| *vtop = *v; | |
| } | |
| static void vdup(void) | |
| { | |
| vpushv(vtop); | |
| } | |
| static void vrotb(int n) | |
| { | |
| int i; | |
| SValue tmp; | |
| tmp = vtop[-n + 1]; | |
| for(i=-n+1;i!=0;i++) | |
| vtop[i] = vtop[i+1]; | |
| vtop[0] = tmp; | |
| } | |
| static void vrote(SValue *e, int n) | |
| { | |
| int i; | |
| SValue tmp; | |
| tmp = *e; | |
| for(i = 0;i < n - 1; i++) | |
| e[-i] = e[-i - 1]; | |
| e[-n + 1] = tmp; | |
| } | |
| static void vrott(int n) | |
| { | |
| vrote(vtop, n); | |
| } | |
| static inline void vpushsym(CType *type, Sym *sym) | |
| { | |
| CValue cval; | |
| cval.i = 0; | |
| vsetc(type, 0x0030 | 0x0200, &cval); | |
| vtop->sym = sym; | |
| } | |
| static Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) | |
| { | |
| int v; | |
| Sym *sym; | |
| v = anon_sym++; | |
| sym = global_identifier_push(v, type->t | 0x00002000, 0); | |
| sym->type.ref = type->ref; | |
| sym->r = 0x0030 | 0x0200; | |
| put_extern_sym(sym, sec, offset, size); | |
| return sym; | |
| } | |
| static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) | |
| { | |
| vpushsym(type, get_sym_ref(type, sec, offset, size)); | |
| } | |
| static Sym *external_global_sym(int v, CType *type, int r) | |
| { | |
| Sym *s; | |
| s = sym_find(v); | |
| if (!s) { | |
| s = global_identifier_push(v, type->t | 0x00001000, 0); | |
| s->type.ref = type->ref; | |
| s->r = r | 0x0030 | 0x0200; | |
| } else if ((((s)->type.t & (0x000f | (0 | 0x0010))) == (0 | 0x0010))) { | |
| s->type.t = type->t | (s->type.t & 0x00001000); | |
| s->type.ref = type->ref; | |
| update_storage(s); | |
| } | |
| return s; | |
| } | |
| static void patch_type(Sym *sym, CType *type) | |
| { | |
| if (!(type->t & 0x00001000)) { | |
| if (!(sym->type.t & 0x00001000)) | |
| tcc_error("redefinition of '%s'", get_tok_str(sym->v, 0)); | |
| sym->type.t &= ~0x00001000; | |
| } | |
| if ((((sym)->type.t & (0x000f | (0 | 0x0010))) == (0 | 0x0010))) { | |
| sym->type.t = type->t & (sym->type.t | ~0x00002000); | |
| sym->type.ref = type->ref; | |
| } | |
| if (!is_compatible_types(&sym->type, type)) { | |
| tcc_error("incompatible types for redefinition of '%s'", | |
| get_tok_str(sym->v, 0)); | |
| } else if ((sym->type.t & 0x000f) == 6) { | |
| int static_proto = sym->type.t & 0x00002000; | |
| if ((type->t & 0x00002000) && !static_proto && !(type->t & 0x00008000)) | |
| tcc_warning("static storage ignored for redefinition of '%s'", | |
| get_tok_str(sym->v, 0)); | |
| if (0 == (type->t & 0x00001000)) { | |
| sym->type.t = (type->t & ~0x00002000) | static_proto; | |
| if (type->t & 0x00008000) | |
| sym->type.t = type->t; | |
| sym->type.ref = type->ref; | |
| } | |
| } else { | |
| if ((sym->type.t & 0x0040) && type->ref->c >= 0) { | |
| if (sym->type.ref->c < 0) | |
| sym->type.ref->c = type->ref->c; | |
| else if (sym->type.ref->c != type->ref->c) | |
| tcc_error("conflicting type for '%s'", get_tok_str(sym->v, 0)); | |
| } | |
| if ((type->t ^ sym->type.t) & 0x00002000) | |
| tcc_warning("storage mismatch for redefinition of '%s'", | |
| get_tok_str(sym->v, 0)); | |
| } | |
| } | |
| static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) | |
| { | |
| if (type) | |
| patch_type(sym, type); | |
| sym->a.weak |= ad->a.weak; | |
| if (ad->a.visibility) { | |
| int vis = sym->a.visibility; | |
| int vis2 = ad->a.visibility; | |
| if (vis == 0) | |
| vis = vis2; | |
| else if (vis2 != 0) | |
| vis = (vis < vis2) ? vis : vis2; | |
| sym->a.visibility = vis; | |
| } | |
| if (ad->a.aligned) | |
| sym->a.aligned = ad->a.aligned; | |
| if (ad->asm_label) | |
| sym->asm_label = ad->asm_label; | |
| update_storage(sym); | |
| } | |
| static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad) | |
| { | |
| Sym *s; | |
| s = sym_find(v); | |
| if (!s) { | |
| s = sym_push(v, type, r | 0x0030 | 0x0200, 0); | |
| s->type.t |= 0x00001000; | |
| s->a = ad->a; | |
| s->sym_scope = 0; | |
| } else { | |
| if (s->type.ref == func_old_type.ref) { | |
| s->type.ref = type->ref; | |
| s->r = r | 0x0030 | 0x0200; | |
| s->type.t |= 0x00001000; | |
| } | |
| patch_storage(s, ad, type); | |
| } | |
| return s; | |
| } | |
| static void vpush_global_sym(CType *type, int v) | |
| { | |
| vpushsym(type, external_global_sym(v, type, 0)); | |
| } | |
| static void save_regs(int n) | |
| { | |
| SValue *p, *p1; | |
| for(p = (__vstack + 1), p1 = vtop - n; p <= p1; p++) | |
| save_reg(p->r); | |
| } | |
| static void save_reg(int r) | |
| { | |
| save_reg_upstack(r, 0); | |
| } | |
| static void save_reg_upstack(int r, int n) | |
| { | |
| int l, saved, size, align; | |
| SValue *p, *p1, sv; | |
| CType *type; | |
| if ((r &= 0x003f) >= 0x0030) | |
| return; | |
| if (nocode_wanted) | |
| return; | |
| saved = 0; | |
| l = 0; | |
| for(p = (__vstack + 1), p1 = vtop - n; p <= p1; p++) { | |
| if ((p->r & 0x003f) == r || | |
| ((p->type.t & 0x000f) == 4 && (p->r2 & 0x003f) == r)) { | |
| if (!saved) { | |
| r = p->r & 0x003f; | |
| type = &p->type; | |
| if ((p->r & 0x0100) || | |
| (!is_float(type->t) && (type->t & 0x000f) != 4)) | |
| type = &char_pointer_type; | |
| size = type_size(type, &align); | |
| loc = (loc - size) & -align; | |
| sv.type.t = type->t; | |
| sv.r = 0x0032 | 0x0100; | |
| sv.c.i = loc; | |
| store(r, &sv); | |
| if (r == TREG_ST0) { | |
| o(0xd8dd); | |
| } | |
| # 1018 "tccgen.c" | |
| l = loc; | |
| saved = 1; | |
| } | |
| if (p->r & 0x0100) { | |
| p->r = (p->r & ~(0x003f | 0x8000)) | 0x0031; | |
| } else { | |
| p->r = lvalue_type(p->type.t) | 0x0032; | |
| } | |
| p->r2 = 0x0030; | |
| p->c.i = l; | |
| } | |
| } | |
| } | |
| # 1062 "tccgen.c" | |
| static int get_reg(int rc) | |
| { | |
| int r; | |
| SValue *p; | |
| for(r=0;r<25;r++) { | |
| if (reg_classes[r] & rc) { | |
| if (nocode_wanted) | |
| return r; | |
| for(p=(__vstack + 1);p<=vtop;p++) { | |
| if ((p->r & 0x003f) == r || | |
| (p->r2 & 0x003f) == r) | |
| goto notfound; | |
| } | |
| return r; | |
| } | |
| notfound: ; | |
| } | |
| for(p=(__vstack + 1);p<=vtop;p++) { | |
| r = p->r2 & 0x003f; | |
| if (r < 0x0030 && (reg_classes[r] & rc)) | |
| goto save_found; | |
| r = p->r & 0x003f; | |
| if (r < 0x0030 && (reg_classes[r] & rc)) { | |
| save_found: | |
| save_reg(r); | |
| return r; | |
| } | |
| } | |
| return -1; | |
| } | |
| static void move_reg(int r, int s, int t) | |
| { | |
| SValue sv; | |
| if (r != s) { | |
| save_reg(r); | |
| sv.type.t = t; | |
| sv.type.ref = 0; | |
| sv.r = s; | |
| sv.c.i = 0; | |
| load(r, &sv); | |
| } | |
| } | |
| static void gaddrof(void) | |
| { | |
| vtop->r &= ~0x0100; | |
| if ((vtop->r & 0x003f) == 0x0031) | |
| vtop->r = (vtop->r & ~(0x003f | (0x1000 | 0x2000 | 0x4000))) | 0x0032 | 0x0100; | |
| } | |
| static void gbound(void) | |
| { | |
| int lval_type; | |
| CType type1; | |
| vtop->r &= ~0x0800; | |
| if (vtop->r & 0x0100) { | |
| if (!(vtop->r & 0x8000)) { | |
| lval_type = vtop->r & ((0x1000 | 0x2000 | 0x4000) | 0x0100); | |
| type1 = vtop->type; | |
| vtop->type.t = 5; | |
| gaddrof(); | |
| vpushi(0); | |
| gen_bounded_ptr_add(); | |
| vtop->r |= lval_type; | |
| vtop->type = type1; | |
| } | |
| gen_bounded_ptr_deref(); | |
| } | |
| } | |
| static void incr_bf_adr(int o) | |
| { | |
| vtop->type = char_pointer_type; | |
| gaddrof(); | |
| vpushi(o); | |
| gen_op('+'); | |
| vtop->type.t = (vtop->type.t & ~(0x000f|0x0020)) | |
| | (1|0x0010); | |
| vtop->r = (vtop->r & ~(0x1000 | 0x2000 | 0x4000)) | |
| | (0x1000|0x4000|0x0100); | |
| } | |
| static void load_packed_bf(CType *type, int bit_pos, int bit_size) | |
| { | |
| int n, o, bits; | |
| save_reg_upstack(vtop->r, 1); | |
| vpush64(type->t & 0x000f, 0); | |
| bits = 0, o = bit_pos >> 3, bit_pos &= 7; | |
| do { | |
| vswap(); | |
| incr_bf_adr(o); | |
| vdup(); | |
| n = 8 - bit_pos; | |
| if (n > bit_size) | |
| n = bit_size; | |
| if (bit_pos) | |
| vpushi(bit_pos), gen_op(0xc9), bit_pos = 0; | |
| if (n < 8) | |
| vpushi((1 << n) - 1), gen_op('&'); | |
| gen_cast(type); | |
| if (bits) | |
| vpushi(bits), gen_op(0x01); | |
| vrotb(3); | |
| gen_op('|'); | |
| bits += n, bit_size -= n, o = 1; | |
| } while (bit_size); | |
| vswap(), vpop(); | |
| if (!(type->t & 0x0010)) { | |
| n = ((type->t & 0x000f) == 4 ? 64 : 32) - bits; | |
| vpushi(n), gen_op(0x01); | |
| vpushi(n), gen_op(0x02); | |
| } | |
| } | |
| static void store_packed_bf(int bit_pos, int bit_size) | |
| { | |
| int bits, n, o, m, c; | |
| c = (vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; | |
| vswap(); | |
| save_reg_upstack(vtop->r, 1); | |
| bits = 0, o = bit_pos >> 3, bit_pos &= 7; | |
| do { | |
| incr_bf_adr(o); | |
| vswap(); | |
| c ? vdup() : gv_dup(); | |
| vrott(3); | |
| if (bits) | |
| vpushi(bits), gen_op(0xc9); | |
| if (bit_pos) | |
| vpushi(bit_pos), gen_op(0x01); | |
| n = 8 - bit_pos; | |
| if (n > bit_size) | |
| n = bit_size; | |
| if (n < 8) { | |
| m = ((1 << n) - 1) << bit_pos; | |
| vpushi(m), gen_op('&'); | |
| vpushv(vtop-1); | |
| vpushi(m & 0x80 ? ~m & 0x7f : ~m); | |
| gen_op('&'); | |
| gen_op('|'); | |
| } | |
| vdup(), vtop[-1] = vtop[-2]; | |
| vstore(), vpop(); | |
| bits += n, bit_size -= n, bit_pos = 0, o = 1; | |
| } while (bit_size); | |
| vpop(), vpop(); | |
| } | |
| static int adjust_bf(SValue *sv, int bit_pos, int bit_size) | |
| { | |
| int t; | |
| if (0 == sv->type.ref) | |
| return 0; | |
| t = sv->type.ref->auxtype; | |
| if (t != -1 && t != 7) { | |
| sv->type.t = (sv->type.t & ~0x000f) | t; | |
| sv->r = (sv->r & ~(0x1000 | 0x2000 | 0x4000)) | lvalue_type(sv->type.t); | |
| } | |
| return t; | |
| } | |
| static int gv(int rc) | |
| { | |
| int r, bit_pos, bit_size, size, align, rc2; | |
| if (vtop->type.t & 0x0080) { | |
| CType type; | |
| bit_pos = (((vtop->type.t) >> 20) & 0x3f); | |
| bit_size = (((vtop->type.t) >> (20 + 6)) & 0x3f); | |
| vtop->type.t &= ~(((1 << (6+6)) - 1) << 20 | 0x0080); | |
| type.ref = 0; | |
| type.t = vtop->type.t & 0x0010; | |
| if ((vtop->type.t & 0x000f) == 11) | |
| type.t |= 0x0010; | |
| r = adjust_bf(vtop, bit_pos, bit_size); | |
| if ((vtop->type.t & 0x000f) == 4) | |
| type.t |= 4; | |
| else | |
| type.t |= 3; | |
| if (r == 7) { | |
| load_packed_bf(&type, bit_pos, bit_size); | |
| } else { | |
| int bits = (type.t & 0x000f) == 4 ? 64 : 32; | |
| gen_cast(&type); | |
| vpushi(bits - (bit_pos + bit_size)); | |
| gen_op(0x01); | |
| vpushi(bits - bit_size); | |
| gen_op(0x02); | |
| } | |
| r = gv(rc); | |
| } else { | |
| if (is_float(vtop->type.t) && | |
| (vtop->r & (0x003f | 0x0100)) == 0x0030) { | |
| unsigned long offset; | |
| size = type_size(&vtop->type, &align); | |
| if ((nocode_wanted > 0)) | |
| size = 0, align = 1; | |
| offset = section_add(data_section, size, align); | |
| vpush_ref(&vtop->type, data_section, offset, size); | |
| vswap(); | |
| init_putv(&vtop->type, data_section, offset); | |
| vtop->r |= 0x0100; | |
| } | |
| if (vtop->r & 0x0800) | |
| gbound(); | |
| r = vtop->r & 0x003f; | |
| rc2 = (rc & 0x0002) ? 0x0002 : 0x0001; | |
| if (rc == 0x0004) | |
| rc2 = 0x0010; | |
| else if (rc == 0x1000) | |
| rc2 = 0x2000; | |
| if (r >= 0x0030 | |
| || (vtop->r & 0x0100) | |
| || !(reg_classes[r] & rc) | |
| || ((vtop->type.t & 0x000f) == 13 && !(reg_classes[vtop->r2] & rc2)) | |
| || ((vtop->type.t & 0x000f) == 14 && !(reg_classes[vtop->r2] & rc2)) | |
| ) | |
| { | |
| r = get_reg(rc); | |
| if (((vtop->type.t & 0x000f) == 13) || ((vtop->type.t & 0x000f) == 14)) { | |
| int addr_type = 4, load_size = 8, load_type = ((vtop->type.t & 0x000f) == 13) ? 4 : 9; | |
| int r2, original_type; | |
| original_type = vtop->type.t; | |
| # 1360 "tccgen.c" | |
| if (vtop->r & 0x0100) { | |
| # 1369 "tccgen.c" | |
| save_reg_upstack(vtop->r, 1); | |
| vtop->type.t = load_type; | |
| load(r, vtop); | |
| vdup(); | |
| vtop[-1].r = r; | |
| vtop->type.t = addr_type; | |
| gaddrof(); | |
| vpushi(load_size); | |
| gen_op('+'); | |
| vtop->r |= 0x0100; | |
| vtop->type.t = load_type; | |
| } else { | |
| load(r, vtop); | |
| vdup(); | |
| vtop[-1].r = r; | |
| vtop->r = vtop[-1].r2; | |
| } | |
| r2 = get_reg(rc2); | |
| load(r2, vtop); | |
| vpop(); | |
| vtop->r2 = r2; | |
| vtop->type.t = original_type; | |
| } else if ((vtop->r & 0x0100) && !is_float(vtop->type.t)) { | |
| int t1, t; | |
| t = vtop->type.t; | |
| t1 = t; | |
| if (vtop->r & 0x1000) | |
| t = 1; | |
| else if (vtop->r & 0x2000) | |
| t = 2; | |
| if (vtop->r & 0x4000) | |
| t |= 0x0010; | |
| vtop->type.t = t; | |
| load(r, vtop); | |
| vtop->type.t = t1; | |
| } else { | |
| load(r, vtop); | |
| } | |
| } | |
| vtop->r = r; | |
| } | |
| return r; | |
| } | |
| static void gv2(int rc1, int rc2) | |
| { | |
| int v; | |
| v = vtop[0].r & 0x003f; | |
| if (v != 0x0033 && (v & ~1) != 0x0034 && rc1 <= rc2) { | |
| vswap(); | |
| gv(rc1); | |
| vswap(); | |
| gv(rc2); | |
| if ((vtop[-1].r & 0x003f) >= 0x0030) { | |
| vswap(); | |
| gv(rc1); | |
| vswap(); | |
| } | |
| } else { | |
| gv(rc2); | |
| vswap(); | |
| gv(rc1); | |
| vswap(); | |
| if ((vtop[0].r & 0x003f) >= 0x0030) { | |
| gv(rc2); | |
| } | |
| } | |
| } | |
| static int rc_fret(int t) | |
| { | |
| if (t == 10) { | |
| return 0x0080; | |
| } | |
| return 0x1000; | |
| } | |
| static int reg_fret(int t) | |
| { | |
| if (t == 10) { | |
| return TREG_ST0; | |
| } | |
| return TREG_XMM0; | |
| } | |
| # 1550 "tccgen.c" | |
| static void gv_dup(void) | |
| { | |
| int rc, t, r, r1; | |
| SValue sv; | |
| t = vtop->type.t; | |
| # 1577 "tccgen.c" | |
| { | |
| rc = 0x0001; | |
| sv.type.t = 3; | |
| if (is_float(t)) { | |
| rc = 0x0002; | |
| if ((t & 0x000f) == 10) { | |
| rc = 0x0080; | |
| } | |
| sv.type.t = t; | |
| } | |
| r = gv(rc); | |
| r1 = get_reg(rc); | |
| sv.r = r; | |
| sv.c.i = 0; | |
| load(r1, &sv); | |
| vdup(); | |
| if (r != r1) | |
| vtop->r = r1; | |
| } | |
| } | |
| static int gvtst(int inv, int t) | |
| { | |
| int v = vtop->r & 0x003f; | |
| if (v != 0x0033 && v != 0x0034 && v != 0x0035) { | |
| vpushi(0); | |
| gen_op(0x95); | |
| } | |
| if ((vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030) { | |
| if ((vtop->c.i != 0) != inv) | |
| t = gjmp(t); | |
| vtop--; | |
| return t; | |
| } | |
| return gtst(inv, t); | |
| } | |
| # 1851 "tccgen.c" | |
| static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b) | |
| { | |
| uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b); | |
| return (a ^ b) >> 63 ? -x : x; | |
| } | |
| static int gen_opic_lt(uint64_t a, uint64_t b) | |
| { | |
| return (a ^ (uint64_t)1 << 63) < (b ^ (uint64_t)1 << 63); | |
| } | |
| static void gen_opic(int op) | |
| { | |
| SValue *v1 = vtop - 1; | |
| SValue *v2 = vtop; | |
| int t1 = v1->type.t & 0x000f; | |
| int t2 = v2->type.t & 0x000f; | |
| int c1 = (v1->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; | |
| int c2 = (v2->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; | |
| uint64_t l1 = c1 ? v1->c.i : 0; | |
| uint64_t l2 = c2 ? v2->c.i : 0; | |
| int shm = (t1 == 4) ? 63 : 31; | |
| if (t1 != 4 && (8 != 8 || t1 != 5)) | |
| l1 = ((uint32_t)l1 | | |
| (v1->type.t & 0x0010 ? 0 : -(l1 & 0x80000000))); | |
| if (t2 != 4 && (8 != 8 || t2 != 5)) | |
| l2 = ((uint32_t)l2 | | |
| (v2->type.t & 0x0010 ? 0 : -(l2 & 0x80000000))); | |
| if (c1 && c2) { | |
| switch(op) { | |
| case '+': l1 += l2; break; | |
| case '-': l1 -= l2; break; | |
| case '&': l1 &= l2; break; | |
| case '^': l1 ^= l2; break; | |
| case '|': l1 |= l2; break; | |
| case '*': l1 *= l2; break; | |
| case 0xb2: | |
| case '/': | |
| case '%': | |
| case 0xb0: | |
| case 0xb1: | |
| if (l2 == 0) { | |
| if (const_wanted) | |
| tcc_error("division by zero in constant"); | |
| goto general_case; | |
| } | |
| switch(op) { | |
| default: l1 = gen_opic_sdiv(l1, l2); break; | |
| case '%': l1 = l1 - l2 * gen_opic_sdiv(l1, l2); break; | |
| case 0xb0: l1 = l1 / l2; break; | |
| case 0xb1: l1 = l1 % l2; break; | |
| } | |
| break; | |
| case 0x01: l1 <<= (l2 & shm); break; | |
| case 0xc9: l1 >>= (l2 & shm); break; | |
| case 0x02: | |
| l1 = (l1 >> 63) ? ~(~l1 >> (l2 & shm)) : l1 >> (l2 & shm); | |
| break; | |
| case 0x92: l1 = l1 < l2; break; | |
| case 0x93: l1 = l1 >= l2; break; | |
| case 0x94: l1 = l1 == l2; break; | |
| case 0x95: l1 = l1 != l2; break; | |
| case 0x96: l1 = l1 <= l2; break; | |
| case 0x97: l1 = l1 > l2; break; | |
| case 0x9c: l1 = gen_opic_lt(l1, l2); break; | |
| case 0x9d: l1 = !gen_opic_lt(l1, l2); break; | |
| case 0x9e: l1 = !gen_opic_lt(l2, l1); break; | |
| case 0x9f: l1 = gen_opic_lt(l2, l1); break; | |
| case 0xa0: l1 = l1 && l2; break; | |
| case 0xa1: l1 = l1 || l2; break; | |
| default: | |
| goto general_case; | |
| } | |
| if (t1 != 4 && (8 != 8 || t1 != 5)) | |
| l1 = ((uint32_t)l1 | | |
| (v1->type.t & 0x0010 ? 0 : -(l1 & 0x80000000))); | |
| v1->c.i = l1; | |
| vtop--; | |
| } else { | |
| if (c1 && (op == '+' || op == '&' || op == '^' || | |
| op == '|' || op == '*')) { | |
| vswap(); | |
| c2 = c1; | |
| l2 = l1; | |
| } | |
| if (!const_wanted && | |
| c1 && ((l1 == 0 && | |
| (op == 0x01 || op == 0xc9 || op == 0x02)) || | |
| (l1 == -1 && op == 0x02))) { | |
| vtop--; | |
| } else if (!const_wanted && | |
| c2 && ((l2 == 0 && (op == '&' || op == '*')) || | |
| (op == '|' && | |
| (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != 4))) || | |
| (l2 == 1 && (op == '%' || op == 0xb1)))) { | |
| if (l2 == 1) | |
| vtop->c.i = 0; | |
| vswap(); | |
| vtop--; | |
| } else if (c2 && (((op == '*' || op == '/' || op == 0xb0 || | |
| op == 0xb2) && | |
| l2 == 1) || | |
| ((op == '+' || op == '-' || op == '|' || op == '^' || | |
| op == 0x01 || op == 0xc9 || op == 0x02) && | |
| l2 == 0) || | |
| (op == '&' && | |
| (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != 4))))) { | |
| vtop--; | |
| } else if (c2 && (op == '*' || op == 0xb2 || op == 0xb0)) { | |
| if (l2 > 0 && (l2 & (l2 - 1)) == 0) { | |
| int n = -1; | |
| while (l2) { | |
| l2 >>= 1; | |
| n++; | |
| } | |
| vtop->c.i = n; | |
| if (op == '*') | |
| op = 0x01; | |
| else if (op == 0xb2) | |
| op = 0x02; | |
| else | |
| op = 0xc9; | |
| } | |
| goto general_case; | |
| } else if (c2 && (op == '+' || op == '-') && | |
| (((vtop[-1].r & (0x003f | 0x0100 | 0x0200)) == (0x0030 | 0x0200)) | |
| || (vtop[-1].r & (0x003f | 0x0100)) == 0x0032)) { | |
| if (op == '-') | |
| l2 = -l2; | |
| l2 += vtop[-1].c.i; | |
| if ((int)l2 != l2) | |
| goto general_case; | |
| vtop--; | |
| vtop->c.i = l2; | |
| } else { | |
| general_case: | |
| if (t1 == 4 || t2 == 4 || | |
| (8 == 8 && (t1 == 5 || t2 == 5))) | |
| gen_opl(op); | |
| else | |
| gen_opi(op); | |
| } | |
| } | |
| } | |
| static void gen_opif(int op) | |
| { | |
| int c1, c2; | |
| SValue *v1, *v2; | |
| long double f1, f2; | |
| v1 = vtop - 1; | |
| v2 = vtop; | |
| c1 = (v1->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; | |
| c2 = (v2->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; | |
| if (c1 && c2) { | |
| if (v1->type.t == 8) { | |
| f1 = v1->c.f; | |
| f2 = v2->c.f; | |
| } else if (v1->type.t == 9) { | |
| f1 = v1->c.d; | |
| f2 = v2->c.d; | |
| } else { | |
| f1 = v1->c.ld; | |
| f2 = v2->c.ld; | |
| } | |
| if (!ieee_finite(f1) || !ieee_finite(f2)) | |
| goto general_case; | |
| switch(op) { | |
| case '+': f1 += f2; break; | |
| case '-': f1 -= f2; break; | |
| case '*': f1 *= f2; break; | |
| case '/': | |
| if (f2 == 0.0) { | |
| if (const_wanted) | |
| tcc_error("division by zero in constant"); | |
| goto general_case; | |
| } | |
| f1 /= f2; | |
| break; | |
| default: | |
| goto general_case; | |
| } | |
| if (v1->type.t == 8) { | |
| v1->c.f = f1; | |
| } else if (v1->type.t == 9) { | |
| v1->c.d = f1; | |
| } else { | |
| v1->c.ld = f1; | |
| } | |
| vtop--; | |
| } else { | |
| general_case: | |
| gen_opf(op); | |
| } | |
| } | |
| static int pointed_size(CType *type) | |
| { | |
| int align; | |
| return type_size(pointed_type(type), &align); | |
| } | |
| static void vla_runtime_pointed_size(CType *type) | |
| { | |
| int align; | |
| vla_runtime_type_size(pointed_type(type), &align); | |
| } | |
| static inline int is_null_pointer(SValue *p) | |
| { | |
| if ((p->r & (0x003f | 0x0100 | 0x0200)) != 0x0030) | |
| return 0; | |
| return ((p->type.t & 0x000f) == 3 && (uint32_t)p->c.i == 0) || | |
| ((p->type.t & 0x000f) == 4 && p->c.i == 0) || | |
| ((p->type.t & 0x000f) == 5 && | |
| (8 == 4 ? (uint32_t)p->c.i == 0 : p->c.i == 0)); | |
| } | |
| static inline int is_integer_btype(int bt) | |
| { | |
| return (bt == 1 || bt == 2 || | |
| bt == 3 || bt == 4); | |
| } | |
| static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) | |
| { | |
| CType *type1, *type2, tmp_type1, tmp_type2; | |
| int bt1, bt2; | |
| if (is_null_pointer(p1) || is_null_pointer(p2)) | |
| return; | |
| type1 = &p1->type; | |
| type2 = &p2->type; | |
| bt1 = type1->t & 0x000f; | |
| bt2 = type2->t & 0x000f; | |
| if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { | |
| if (op != 0xa1 && op != 0xa0 ) | |
| tcc_warning("comparison between pointer and integer"); | |
| return; | |
| } | |
| if (bt1 == 5) { | |
| type1 = pointed_type(type1); | |
| } else if (bt1 != 6) | |
| goto invalid_operands; | |
| if (bt2 == 5) { | |
| type2 = pointed_type(type2); | |
| } else if (bt2 != 6) { | |
| invalid_operands: | |
| tcc_error("invalid operands to binary %s", get_tok_str(op, 0)); | |
| } | |
| if ((type1->t & 0x000f) == 0 || | |
| (type2->t & 0x000f) == 0) | |
| return; | |
| tmp_type1 = *type1; | |
| tmp_type2 = *type2; | |
| tmp_type1.t &= ~(0x0020 | 0x0010 | 0x0100 | 0x0200); | |
| tmp_type2.t &= ~(0x0020 | 0x0010 | 0x0100 | 0x0200); | |
| if (!is_compatible_types(&tmp_type1, &tmp_type2)) { | |
| if (op == '-') | |
| goto invalid_operands; | |
| else | |
| tcc_warning("comparison of distinct pointer types lacks a cast"); | |
| } | |
| } | |
| static void gen_op(int op) | |
| { | |
| int u, t1, t2, bt1, bt2, t; | |
| CType type1; | |
| redo: | |
| t1 = vtop[-1].type.t; | |
| t2 = vtop[0].type.t; | |
| bt1 = t1 & 0x000f; | |
| bt2 = t2 & 0x000f; | |
| if (bt1 == 7 || bt2 == 7) { | |
| tcc_error("operation on a struct"); | |
| } else if (bt1 == 6 || bt2 == 6) { | |
| if (bt2 == 6) { | |
| mk_pointer(&vtop->type); | |
| gaddrof(); | |
| } | |
| if (bt1 == 6) { | |
| vswap(); | |
| mk_pointer(&vtop->type); | |
| gaddrof(); | |
| vswap(); | |
| } | |
| goto redo; | |
| } else if (bt1 == 5 || bt2 == 5) { | |
| if (op >= 0x92 && op <= 0xa1) { | |
| check_comparison_pointer_types(vtop - 1, vtop, op); | |
| t = 4 | 0x0010; | |
| goto std_op; | |
| } | |
| if (bt1 == 5 && bt2 == 5) { | |
| if (op != '-') | |
| tcc_error("cannot use pointers here"); | |
| check_comparison_pointer_types(vtop - 1, vtop, op); | |
| if (vtop[-1].type.t & 0x0400) { | |
| vla_runtime_pointed_size(&vtop[-1].type); | |
| } else { | |
| vpushi(pointed_size(&vtop[-1].type)); | |
| } | |
| vrott(3); | |
| gen_opic(op); | |
| vtop->type.t = ptrdiff_type.t; | |
| vswap(); | |
| gen_op(0xb2); | |
| } else { | |
| if (op != '-' && op != '+') | |
| tcc_error("cannot use pointers here"); | |
| if (bt2 == 5) { | |
| vswap(); | |
| t = t1, t1 = t2, t2 = t; | |
| } | |
| type1 = vtop[-1].type; | |
| type1.t &= ~0x0040; | |
| if (vtop[-1].type.t & 0x0400) | |
| vla_runtime_pointed_size(&vtop[-1].type); | |
| else { | |
| u = pointed_size(&vtop[-1].type); | |
| if (u < 0) | |
| tcc_error("unknown array element size"); | |
| vpushll(u); | |
| } | |
| gen_op('*'); | |
| # 2267 "tccgen.c" | |
| { | |
| gen_opic(op); | |
| } | |
| vtop->type = type1; | |
| } | |
| } else if (is_float(bt1) || is_float(bt2)) { | |
| if (bt1 == 10 || bt2 == 10) { | |
| t = 10; | |
| } else if (bt1 == 9 || bt2 == 9) { | |
| t = 9; | |
| } else { | |
| t = 8; | |
| } | |
| if (op != '+' && op != '-' && op != '*' && op != '/' && | |
| (op < 0x92 || op > 0x9f)) | |
| tcc_error("invalid operands for binary operation"); | |
| goto std_op; | |
| } else if (op == 0xc9 || op == 0x02 || op == 0x01) { | |
| t = bt1 == 4 ? 4 : 3; | |
| if ((t1 & (0x000f | 0x0010 | 0x0080)) == (t | 0x0010)) | |
| t |= 0x0010; | |
| t |= (0x0800 & t1); | |
| goto std_op; | |
| } else if (bt1 == 4 || bt2 == 4) { | |
| t = 4 | 0x0800; | |
| if (bt1 == 4) | |
| t &= t1; | |
| if (bt2 == 4) | |
| t &= t2; | |
| if ((t1 & (0x000f | 0x0010 | 0x0080)) == (4 | 0x0010) || | |
| (t2 & (0x000f | 0x0010 | 0x0080)) == (4 | 0x0010)) | |
| t |= 0x0010; | |
| goto std_op; | |
| } else { | |
| t = 3 | (0x0800 & (t1 | t2)); | |
| if ((t1 & (0x000f | 0x0010 | 0x0080)) == (3 | 0x0010) || | |
| (t2 & (0x000f | 0x0010 | 0x0080)) == (3 | 0x0010)) | |
| t |= 0x0010; | |
| std_op: | |
| if (t & 0x0010) { | |
| if (op == 0x02) | |
| op = 0xc9; | |
| else if (op == '/') | |
| op = 0xb0; | |
| else if (op == '%') | |
| op = 0xb1; | |
| else if (op == 0x9c) | |
| op = 0x92; | |
| else if (op == 0x9f) | |
| op = 0x97; | |
| else if (op == 0x9e) | |
| op = 0x96; | |
| else if (op == 0x9d) | |
| op = 0x93; | |
| } | |
| vswap(); | |
| type1.t = t; | |
| type1.ref = 0; | |
| gen_cast(&type1); | |
| vswap(); | |
| if (op == 0xc9 || op == 0x02 || op == 0x01) | |
| type1.t = 3; | |
| gen_cast(&type1); | |
| if (is_float(t)) | |
| gen_opif(op); | |
| else | |
| gen_opic(op); | |
| if (op >= 0x92 && op <= 0x9f) { | |
| vtop->type.t = 3; | |
| } else { | |
| vtop->type.t = t; | |
| } | |
| } | |
| if (vtop->r & 0x0100) | |
| gv(is_float(vtop->type.t & 0x000f) ? 0x0002 : 0x0001); | |
| } | |
| static void gen_cvt_itof1(int t) | |
| { | |
| if ((vtop->type.t & (0x000f | 0x0010)) == | |
| (4 | 0x0010)) { | |
| if (t == 8) | |
| vpush_global_sym(&func_old_type, TOK___floatundisf); | |
| else if (t == 10) | |
| vpush_global_sym(&func_old_type, TOK___floatundixf); | |
| else | |
| vpush_global_sym(&func_old_type, TOK___floatundidf); | |
| vrott(2); | |
| gfunc_call(1); | |
| vpushi(0); | |
| vtop->r = reg_fret(t); | |
| } else { | |
| gen_cvt_itof(t); | |
| } | |
| } | |
| static void gen_cvt_ftoi1(int t) | |
| { | |
| int st; | |
| if (t == (4 | 0x0010)) { | |
| st = vtop->type.t & 0x000f; | |
| if (st == 8) | |
| vpush_global_sym(&func_old_type, TOK___fixunssfdi); | |
| else if (st == 10) | |
| vpush_global_sym(&func_old_type, TOK___fixunsxfdi); | |
| else | |
| vpush_global_sym(&func_old_type, TOK___fixunsdfdi); | |
| vrott(2); | |
| gfunc_call(1); | |
| vpushi(0); | |
| vtop->r = TREG_RAX; | |
| vtop->r2 = TREG_RDX; | |
| } else { | |
| gen_cvt_ftoi(t); | |
| } | |
| } | |
| static void force_charshort_cast(int t) | |
| { | |
| int bits, dbt; | |
| if ((nocode_wanted & 0xC0000000)) | |
| return; | |
| dbt = t & 0x000f; | |
| if (dbt == 1) | |
| bits = 8; | |
| else | |
| bits = 16; | |
| if (t & 0x0010) { | |
| vpushi((1 << bits) - 1); | |
| gen_op('&'); | |
| } else { | |
| if ((vtop->type.t & 0x000f) == 4) | |
| bits = 64 - bits; | |
| else | |
| bits = 32 - bits; | |
| vpushi(bits); | |
| gen_op(0x01); | |
| vtop->type.t &= ~0x0010; | |
| vpushi(bits); | |
| gen_op(0x02); | |
| } | |
| } | |
| static void gen_cast_s(int t) | |
| { | |
| CType type; | |
| type.t = t; | |
| type.ref = 0; | |
| gen_cast(&type); | |
| } | |
| static void gen_cast(CType *type) | |
| { | |
| int sbt, dbt, sf, df, c, p; | |
| if (vtop->r & 0x0400) { | |
| vtop->r &= ~0x0400; | |
| force_charshort_cast(vtop->type.t); | |
| } | |
| if (vtop->type.t & 0x0080) { | |
| gv(0x0001); | |
| } | |
| dbt = type->t & (0x000f | 0x0010); | |
| sbt = vtop->type.t & (0x000f | 0x0010); | |
| if (sbt != dbt) { | |
| sf = is_float(sbt); | |
| df = is_float(dbt); | |
| c = (vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; | |
| p = (vtop->r & (0x003f | 0x0100 | 0x0200)) == (0x0030 | 0x0200); | |
| if (c) { | |
| if (sbt == 8) | |
| vtop->c.ld = vtop->c.f; | |
| else if (sbt == 9) | |
| vtop->c.ld = vtop->c.d; | |
| if (df) { | |
| if ((sbt & 0x000f) == 4) { | |
| if ((sbt & 0x0010) || !(vtop->c.i >> 63)) | |
| vtop->c.ld = vtop->c.i; | |
| else | |
| vtop->c.ld = -(long double)-vtop->c.i; | |
| } else if(!sf) { | |
| if ((sbt & 0x0010) || !(vtop->c.i >> 31)) | |
| vtop->c.ld = (uint32_t)vtop->c.i; | |
| else | |
| vtop->c.ld = -(long double)-(uint32_t)vtop->c.i; | |
| } | |
| if (dbt == 8) | |
| vtop->c.f = (float)vtop->c.ld; | |
| else if (dbt == 9) | |
| vtop->c.d = (double)vtop->c.ld; | |
| } else if (sf && dbt == (4|0x0010)) { | |
| vtop->c.i = vtop->c.ld; | |
| } else if (sf && dbt == 11) { | |
| vtop->c.i = (vtop->c.ld != 0); | |
| } else { | |
| if(sf) | |
| vtop->c.i = vtop->c.ld; | |
| else if (sbt == (4|0x0010)) | |
| ; | |
| else if (sbt & 0x0010) | |
| vtop->c.i = (uint32_t)vtop->c.i; | |
| else if (sbt == 5) | |
| ; | |
| else if (sbt != 4) | |
| vtop->c.i = ((uint32_t)vtop->c.i | | |
| -(vtop->c.i & 0x80000000)); | |
| if (dbt == (4|0x0010)) | |
| ; | |
| else if (dbt == 11) | |
| vtop->c.i = (vtop->c.i != 0); | |
| else if (dbt == 5) | |
| ; | |
| else if (dbt != 4) { | |
| uint32_t m = ((dbt & 0x000f) == 1 ? 0xff : | |
| (dbt & 0x000f) == 2 ? 0xffff : | |
| 0xffffffff); | |
| vtop->c.i &= m; | |
| if (!(dbt & 0x0010)) | |
| vtop->c.i |= -(vtop->c.i & ((m >> 1) + 1)); | |
| } | |
| } | |
| } else if (p && dbt == 11) { | |
| vtop->r = 0x0030; | |
| vtop->c.i = 1; | |
| } else { | |
| if (sf && df) { | |
| gen_cvt_ftof(dbt); | |
| } else if (df) { | |
| gen_cvt_itof1(dbt); | |
| } else if (sf) { | |
| if (dbt == 11) { | |
| vpushi(0); | |
| gen_op(0x95); | |
| } else { | |
| if (dbt != (3 | 0x0010) && | |
| dbt != (4 | 0x0010) && | |
| dbt != 4) | |
| dbt = 3; | |
| gen_cvt_ftoi1(dbt); | |
| if (dbt == 3 && (type->t & (0x000f | 0x0010)) != dbt) { | |
| vtop->type.t = dbt; | |
| gen_cast(type); | |
| } | |
| } | |
| # 2602 "tccgen.c" | |
| } else if ((dbt & 0x000f) == 4 || | |
| (dbt & 0x000f) == 5 || | |
| (dbt & 0x000f) == 6) { | |
| if ((sbt & 0x000f) != 4 && | |
| (sbt & 0x000f) != 5 && | |
| (sbt & 0x000f) != 6) { | |
| gv(0x0001); | |
| if (sbt != (3 | 0x0010)) { | |
| int r = gv(0x0001); | |
| o(0x6348); | |
| o(0xc0 + (((r) & 7) << 3) + ((r) & 7)); | |
| } | |
| } | |
| } else if (dbt == 11) { | |
| vpushi(0); | |
| gen_op(0x95); | |
| } else if ((dbt & 0x000f) == 1 || | |
| (dbt & 0x000f) == 2) { | |
| if (sbt == 5) { | |
| vtop->type.t = 3; | |
| tcc_warning("nonportable conversion from pointer to char/short"); | |
| } | |
| force_charshort_cast(dbt); | |
| # 2647 "tccgen.c" | |
| } | |
| } | |
| } else if ((dbt & 0x000f) == 5 && !(vtop->r & 0x0100)) { | |
| vtop->r = (vtop->r & ~(0x1000 | 0x2000 | 0x4000)) | |
| | (lvalue_type(type->ref->type.t) & (0x1000 | 0x2000 | 0x4000)); | |
| } | |
| vtop->type = *type; | |
| } | |
| static int type_size(CType *type, int *a) | |
| { | |
| Sym *s; | |
| int bt; | |
| bt = type->t & 0x000f; | |
| if (bt == 7) { | |
| s = type->ref; | |
| *a = s->r; | |
| return s->c; | |
| } else if (bt == 5) { | |
| if (type->t & 0x0040) { | |
| int ts; | |
| s = type->ref; | |
| ts = type_size(&s->type, a); | |
| if (ts < 0 && s->c < 0) | |
| ts = -ts; | |
| return ts * s->c; | |
| } else { | |
| *a = 8; | |
| return 8; | |
| } | |
| } else if (((type->t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20)) && type->ref->c == -1) { | |
| return -1; | |
| } else if (bt == 10) { | |
| *a = 16; | |
| return 16; | |
| } else if (bt == 9 || bt == 4) { | |
| # 2704 "tccgen.c" | |
| *a = 8; | |
| return 8; | |
| } else if (bt == 3 || bt == 8) { | |
| *a = 4; | |
| return 4; | |
| } else if (bt == 2) { | |
| *a = 2; | |
| return 2; | |
| } else if (bt == 13 || bt == 14) { | |
| *a = 8; | |
| return 16; | |
| } else { | |
| *a = 1; | |
| return 1; | |
| } | |
| } | |
| static void vla_runtime_type_size(CType *type, int *a) | |
| { | |
| if (type->t & 0x0400) { | |
| type_size(&type->ref->type, a); | |
| vset(&int_type, 0x0032|0x0100, type->ref->c); | |
| } else { | |
| vpushi(type_size(type, a)); | |
| } | |
| } | |
| static void vla_sp_restore(void) { | |
| if (vlas_in_scope) { | |
| gen_vla_sp_restore(vla_sp_loc); | |
| } | |
| } | |
| static void vla_sp_restore_root(void) { | |
| if (vlas_in_scope) { | |
| gen_vla_sp_restore(vla_sp_root_loc); | |
| } | |
| } | |
| static inline CType *pointed_type(CType *type) | |
| { | |
| return &type->ref->type; | |
| } | |
| static void mk_pointer(CType *type) | |
| { | |
| Sym *s; | |
| s = sym_push(0x20000000, type, 0, -1); | |
| type->t = 5 | (type->t & (0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)); | |
| type->ref = s; | |
| } | |
| static int is_compatible_func(CType *type1, CType *type2) | |
| { | |
| Sym *s1, *s2; | |
| s1 = type1->ref; | |
| s2 = type2->ref; | |
| if (!is_compatible_types(&s1->type, &s2->type)) | |
| return 0; | |
| if (s1->f.func_call != s2->f.func_call) | |
| return 0; | |
| if (s1->f.func_type == 2 || s2->f.func_type == 2) | |
| return 1; | |
| if (s1->f.func_type != s2->f.func_type) | |
| return 0; | |
| while (s1 != 0) { | |
| if (s2 == 0) | |
| return 0; | |
| if (!is_compatible_unqualified_types(&s1->type, &s2->type)) | |
| return 0; | |
| s1 = s1->next; | |
| s2 = s2->next; | |
| } | |
| if (s2) | |
| return 0; | |
| return 1; | |
| } | |
| static int compare_types(CType *type1, CType *type2, int unqualified) | |
| { | |
| int bt1, t1, t2; | |
| t1 = type1->t & (~((0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)|(((1 << (6+6)) - 1) << 20 | 0x0080))); | |
| t2 = type2->t & (~((0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)|(((1 << (6+6)) - 1) << 20 | 0x0080))); | |
| if (unqualified) { | |
| t1 &= ~(0x0100 | 0x0200); | |
| t2 &= ~(0x0100 | 0x0200); | |
| } | |
| if ((t1 & 0x000f) != 1) { | |
| t1 &= ~0x0020; | |
| t2 &= ~0x0020; | |
| } | |
| if (t1 != t2) | |
| return 0; | |
| bt1 = t1 & 0x000f; | |
| if (bt1 == 5) { | |
| type1 = pointed_type(type1); | |
| type2 = pointed_type(type2); | |
| return is_compatible_types(type1, type2); | |
| } else if (bt1 == 7) { | |
| return (type1->ref == type2->ref); | |
| } else if (bt1 == 6) { | |
| return is_compatible_func(type1, type2); | |
| } else { | |
| return 1; | |
| } | |
| } | |
| static int is_compatible_types(CType *type1, CType *type2) | |
| { | |
| return compare_types(type1,type2,0); | |
| } | |
| static int is_compatible_unqualified_types(CType *type1, CType *type2) | |
| { | |
| return compare_types(type1,type2,1); | |
| } | |
| static void type_to_str(char *buf, int buf_size, | |
| CType *type, const char *varstr) | |
| { | |
| int bt, v, t; | |
| Sym *s, *sa; | |
| char buf1[256]; | |
| const char *tstr; | |
| t = type->t; | |
| bt = t & 0x000f; | |
| buf[0] = '\0'; | |
| if (t & 0x00001000) | |
| pstrcat(buf, buf_size, "extern "); | |
| if (t & 0x00002000) | |
| pstrcat(buf, buf_size, "static "); | |
| if (t & 0x00004000) | |
| pstrcat(buf, buf_size, "typedef "); | |
| if (t & 0x00008000) | |
| pstrcat(buf, buf_size, "inline "); | |
| if (t & 0x0200) | |
| pstrcat(buf, buf_size, "volatile "); | |
| if (t & 0x0100) | |
| pstrcat(buf, buf_size, "const "); | |
| if (((t & 0x0020) && bt == 1) | |
| || ((t & 0x0010) | |
| && (bt == 2 || bt == 3 || bt == 4) | |
| && !((t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20)) | |
| )) | |
| pstrcat(buf, buf_size, (t & 0x0010) ? "unsigned " : "signed "); | |
| buf_size -= strlen(buf); | |
| buf += strlen(buf); | |
| switch(bt) { | |
| case 0: | |
| tstr = "void"; | |
| goto add_tstr; | |
| case 11: | |
| tstr = "_Bool"; | |
| goto add_tstr; | |
| case 1: | |
| tstr = "char"; | |
| goto add_tstr; | |
| case 2: | |
| tstr = "short"; | |
| goto add_tstr; | |
| case 3: | |
| tstr = "int"; | |
| goto maybe_long; | |
| case 4: | |
| tstr = "long long"; | |
| maybe_long: | |
| if (t & 0x0800) | |
| tstr = "long"; | |
| if (!((t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20))) | |
| goto add_tstr; | |
| tstr = "enum "; | |
| goto tstruct; | |
| case 8: | |
| tstr = "float"; | |
| goto add_tstr; | |
| case 9: | |
| tstr = "double"; | |
| goto add_tstr; | |
| case 10: | |
| tstr = "long double"; | |
| add_tstr: | |
| pstrcat(buf, buf_size, tstr); | |
| break; | |
| case 7: | |
| tstr = "struct "; | |
| if (((t & ((((1 << (6+6)) - 1) << 20 | 0x0080)|0x000f)) == (1 << 20 | 7))) | |
| tstr = "union "; | |
| tstruct: | |
| pstrcat(buf, buf_size, tstr); | |
| v = type->ref->v & ~0x40000000; | |
| if (v >= 0x10000000) | |
| pstrcat(buf, buf_size, "<anonymous>"); | |
| else | |
| pstrcat(buf, buf_size, get_tok_str(v, 0)); | |
| break; | |
| case 6: | |
| s = type->ref; | |
| type_to_str(buf, buf_size, &s->type, varstr); | |
| pstrcat(buf, buf_size, "("); | |
| sa = s->next; | |
| while (sa != 0) { | |
| type_to_str(buf1, sizeof(buf1), &sa->type, 0); | |
| pstrcat(buf, buf_size, buf1); | |
| sa = sa->next; | |
| if (sa) | |
| pstrcat(buf, buf_size, ", "); | |
| } | |
| pstrcat(buf, buf_size, ")"); | |
| goto no_var; | |
| case 5: | |
| s = type->ref; | |
| if (t & 0x0040) { | |
| snprintf(buf1, sizeof(buf1), "%s[%d]", varstr ? varstr : "", s->c); | |
| type_to_str(buf, buf_size, &s->type, buf1); | |
| goto no_var; | |
| } | |
| pstrcpy(buf1, sizeof(buf1), "*"); | |
| if (t & 0x0100) | |
| pstrcat(buf1, buf_size, "const "); | |
| if (t & 0x0200) | |
| pstrcat(buf1, buf_size, "volatile "); | |
| if (varstr) | |
| pstrcat(buf1, sizeof(buf1), varstr); | |
| type_to_str(buf, buf_size, &s->type, buf1); | |
| goto no_var; | |
| } | |
| if (varstr) { | |
| pstrcat(buf, buf_size, " "); | |
| pstrcat(buf, buf_size, varstr); | |
| } | |
| no_var: ; | |
| } | |
| static void gen_assign_cast(CType *dt) | |
| { | |
| CType *st, *type1, *type2; | |
| char buf1[256], buf2[256]; | |
| int dbt, sbt; | |
| st = &vtop->type; | |
| dbt = dt->t & 0x000f; | |
| sbt = st->t & 0x000f; | |
| if (sbt == 0 || dbt == 0) { | |
| if (sbt == 0 && dbt == 0) | |
| ; | |
| # 2994 "tccgen.c" | |
| else | |
| tcc_error("cannot cast from/to void"); | |
| } | |
| if (dt->t & 0x0100) | |
| tcc_warning("assignment of read-only location"); | |
| switch(dbt) { | |
| case 5: | |
| if (is_null_pointer(vtop)) | |
| goto type_ok; | |
| if (is_integer_btype(sbt)) { | |
| tcc_warning("assignment makes pointer from integer without a cast"); | |
| goto type_ok; | |
| } | |
| type1 = pointed_type(dt); | |
| if (sbt == 6) { | |
| if ((type1->t & 0x000f) != 0 && | |
| !is_compatible_types(pointed_type(dt), st)) | |
| tcc_warning("assignment from incompatible pointer type"); | |
| goto type_ok; | |
| } | |
| if (sbt != 5) | |
| goto error; | |
| type2 = pointed_type(st); | |
| if ((type1->t & 0x000f) == 0 || | |
| (type2->t & 0x000f) == 0) { | |
| } else { | |
| if (!is_compatible_unqualified_types(type1, type2)) { | |
| if ((type1->t & (0x000f|0x0800)) != (type2->t & (0x000f|0x0800)) | |
| || ((type1->t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20)) || ((type2->t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20)) | |
| ) | |
| tcc_warning("assignment from incompatible pointer type"); | |
| } | |
| } | |
| if ((!(type1->t & 0x0100) && (type2->t & 0x0100)) || | |
| (!(type1->t & 0x0200) && (type2->t & 0x0200))) | |
| tcc_warning("assignment discards qualifiers from pointer target type"); | |
| break; | |
| case 1: | |
| case 2: | |
| case 3: | |
| case 4: | |
| if (sbt == 5 || sbt == 6) { | |
| tcc_warning("assignment makes integer from pointer without a cast"); | |
| } else if (sbt == 7) { | |
| goto case_VT_STRUCT; | |
| } | |
| break; | |
| case 7: | |
| case_VT_STRUCT: | |
| if (!is_compatible_unqualified_types(dt, st)) { | |
| error: | |
| type_to_str(buf1, sizeof(buf1), st, 0); | |
| type_to_str(buf2, sizeof(buf2), dt, 0); | |
| tcc_error("cannot cast '%s' to '%s'", buf1, buf2); | |
| } | |
| break; | |
| } | |
| type_ok: | |
| gen_cast(dt); | |
| } | |
| static void vstore(void) | |
| { | |
| int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; | |
| ft = vtop[-1].type.t; | |
| sbt = vtop->type.t & 0x000f; | |
| dbt = ft & 0x000f; | |
| if ((((sbt == 3 || sbt == 2) && dbt == 1) || | |
| (sbt == 3 && dbt == 2)) | |
| && !(vtop->type.t & 0x0080)) { | |
| delayed_cast = 0x0400; | |
| vtop->type.t = ft & (~((0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)|(((1 << (6+6)) - 1) << 20 | 0x0080))); | |
| if (ft & 0x0100) | |
| tcc_warning("assignment of read-only location"); | |
| } else { | |
| delayed_cast = 0; | |
| if (!(ft & 0x0080)) | |
| gen_assign_cast(&vtop[-1].type); | |
| } | |
| if (sbt == 7) { | |
| size = type_size(&vtop->type, &align); | |
| vswap(); | |
| vtop->type.t = 5; | |
| gaddrof(); | |
| # 3111 "tccgen.c" | |
| vpush_global_sym(&func_old_type, TOK_memmove); | |
| vswap(); | |
| vpushv(vtop - 2); | |
| vtop->type.t = 5; | |
| gaddrof(); | |
| vpushi(size); | |
| gfunc_call(3); | |
| } else if (ft & 0x0080) { | |
| vdup(), vtop[-1] = vtop[-2]; | |
| bit_pos = (((ft) >> 20) & 0x3f); | |
| bit_size = (((ft) >> (20 + 6)) & 0x3f); | |
| vtop[-1].type.t = ft & ~(((1 << (6+6)) - 1) << 20 | 0x0080); | |
| if ((ft & 0x000f) == 11) { | |
| gen_cast(&vtop[-1].type); | |
| vtop[-1].type.t = (vtop[-1].type.t & ~0x000f) | (1 | 0x0010); | |
| } | |
| r = adjust_bf(vtop - 1, bit_pos, bit_size); | |
| if (r == 7) { | |
| gen_cast_s((ft & 0x000f) == 4 ? 4 : 3); | |
| store_packed_bf(bit_pos, bit_size); | |
| } else { | |
| unsigned long long mask = (1ULL << bit_size) - 1; | |
| if ((ft & 0x000f) != 11) { | |
| if ((vtop[-1].type.t & 0x000f) == 4) | |
| vpushll(mask); | |
| else | |
| vpushi((unsigned)mask); | |
| gen_op('&'); | |
| } | |
| vpushi(bit_pos); | |
| gen_op(0x01); | |
| vswap(); | |
| vdup(); | |
| vrott(3); | |
| if ((vtop->type.t & 0x000f) == 4) | |
| vpushll(~(mask << bit_pos)); | |
| else | |
| vpushi(~((unsigned)mask << bit_pos)); | |
| gen_op('&'); | |
| gen_op('|'); | |
| vstore(); | |
| vpop(); | |
| } | |
| } else if (dbt == 0) { | |
| --vtop; | |
| } else { | |
| if (vtop[-1].r & 0x0800) { | |
| vswap(); | |
| gbound(); | |
| vswap(); | |
| } | |
| rc = 0x0001; | |
| if (is_float(ft)) { | |
| rc = 0x0002; | |
| if ((ft & 0x000f) == 10) { | |
| rc = 0x0080; | |
| } else if ((ft & 0x000f) == 14) { | |
| rc = 0x1000; | |
| } | |
| } | |
| r = gv(rc); | |
| if ((vtop[-1].r & 0x003f) == 0x0031) { | |
| SValue sv; | |
| t = get_reg(0x0001); | |
| sv.type.t = 5; | |
| sv.r = 0x0032 | 0x0100; | |
| sv.c.i = vtop[-1].c.i; | |
| load(t, &sv); | |
| vtop[-1].r = t | 0x0100; | |
| } | |
| if (((ft & 0x000f) == 13) || ((ft & 0x000f) == 14)) { | |
| int addr_type = 4, load_size = 8, load_type = ((vtop->type.t & 0x000f) == 13) ? 4 : 9; | |
| vtop[-1].type.t = load_type; | |
| store(r, vtop - 1); | |
| vswap(); | |
| vtop->type.t = addr_type; | |
| gaddrof(); | |
| vpushi(load_size); | |
| gen_op('+'); | |
| vtop->r |= 0x0100; | |
| vswap(); | |
| vtop[-1].type.t = load_type; | |
| store(vtop->r2, vtop - 1); | |
| } else { | |
| store(r, vtop - 1); | |
| } | |
| vswap(); | |
| vtop--; | |
| vtop->r |= delayed_cast; | |
| } | |
| } | |
| static void inc(int post, int c) | |
| { | |
| test_lvalue(); | |
| vdup(); | |
| if (post) { | |
| gv_dup(); | |
| vrotb(3); | |
| vrotb(3); | |
| } | |
| vpushi(c - 0xa3); | |
| gen_op('+'); | |
| vstore(); | |
| if (post) | |
| vpop(); | |
| } | |
| static void parse_mult_str (CString *astr, const char *msg) | |
| { | |
| if (tok != 0xb9) | |
| expect(msg); | |
| cstr_new(astr); | |
| while (tok == 0xb9) { | |
| cstr_cat(astr, tokc.str.data, -1); | |
| next(); | |
| } | |
| cstr_ccat(astr, '\0'); | |
| } | |
| static int exact_log2p1(int i) | |
| { | |
| int ret; | |
| if (!i) | |
| return 0; | |
| for (ret = 1; i >= 1 << 8; ret += 8) | |
| i >>= 8; | |
| if (i >= 1 << 4) | |
| ret += 4, i >>= 4; | |
| if (i >= 1 << 2) | |
| ret += 2, i >>= 2; | |
| if (i >= 1 << 1) | |
| ret++; | |
| return ret; | |
| } | |
| static void parse_attribute(AttributeDef *ad) | |
| { | |
| int t, n; | |
| CString astr; | |
| redo: | |
| if (tok != TOK_ATTRIBUTE1 && tok != TOK_ATTRIBUTE2) | |
| return; | |
| next(); | |
| skip('('); | |
| skip('('); | |
| while (tok != ')') { | |
| if (tok < 256) | |
| expect("attribute name"); | |
| t = tok; | |
| next(); | |
| switch(t) { | |
| case TOK_SECTION1: | |
| case TOK_SECTION2: | |
| skip('('); | |
| parse_mult_str(&astr, "section name"); | |
| ad->section = find_section(tcc_state, (char *)astr.data); | |
| skip(')'); | |
| cstr_free(&astr); | |
| break; | |
| case TOK_ALIAS1: | |
| case TOK_ALIAS2: | |
| skip('('); | |
| parse_mult_str(&astr, "alias(\"target\")"); | |
| ad->alias_target = | |
| tok_alloc((char*)astr.data, astr.size-1)->tok; | |
| skip(')'); | |
| cstr_free(&astr); | |
| break; | |
| case TOK_VISIBILITY1: | |
| case TOK_VISIBILITY2: | |
| skip('('); | |
| parse_mult_str(&astr, | |
| "visibility(\"default|hidden|internal|protected\")"); | |
| if (!strcmp (astr.data, "default")) | |
| ad->a.visibility = 0; | |
| else if (!strcmp (astr.data, "hidden")) | |
| ad->a.visibility = 2; | |
| else if (!strcmp (astr.data, "internal")) | |
| ad->a.visibility = 1; | |
| else if (!strcmp (astr.data, "protected")) | |
| ad->a.visibility = 3; | |
| else | |
| expect("visibility(\"default|hidden|internal|protected\")"); | |
| skip(')'); | |
| cstr_free(&astr); | |
| break; | |
| case TOK_ALIGNED1: | |
| case TOK_ALIGNED2: | |
| if (tok == '(') { | |
| next(); | |
| n = expr_const(); | |
| if (n <= 0 || (n & (n - 1)) != 0) | |
| tcc_error("alignment must be a positive power of two"); | |
| skip(')'); | |
| } else { | |
| n = 16; | |
| } | |
| ad->a.aligned = exact_log2p1(n); | |
| if (n != 1 << (ad->a.aligned - 1)) | |
| tcc_error("alignment of %d is larger than implemented", n); | |
| break; | |
| case TOK_PACKED1: | |
| case TOK_PACKED2: | |
| ad->a.packed = 1; | |
| break; | |
| case TOK_WEAK1: | |
| case TOK_WEAK2: | |
| ad->a.weak = 1; | |
| break; | |
| case TOK_UNUSED1: | |
| case TOK_UNUSED2: | |
| break; | |
| case TOK_NORETURN1: | |
| case TOK_NORETURN2: | |
| break; | |
| case TOK_CDECL1: | |
| case TOK_CDECL2: | |
| case TOK_CDECL3: | |
| ad->f.func_call = 0; | |
| break; | |
| case TOK_STDCALL1: | |
| case TOK_STDCALL2: | |
| case TOK_STDCALL3: | |
| ad->f.func_call = 1; | |
| break; | |
| # 3405 "tccgen.c" | |
| case TOK_MODE: | |
| skip('('); | |
| switch(tok) { | |
| case TOK_MODE_DI: | |
| ad->attr_mode = 4 + 1; | |
| break; | |
| case TOK_MODE_QI: | |
| ad->attr_mode = 1 + 1; | |
| break; | |
| case TOK_MODE_HI: | |
| ad->attr_mode = 2 + 1; | |
| break; | |
| case TOK_MODE_SI: | |
| case TOK_MODE_word: | |
| ad->attr_mode = 3 + 1; | |
| break; | |
| default: | |
| tcc_warning("__mode__(%s) not supported\n", get_tok_str(tok, 0)); | |
| break; | |
| } | |
| next(); | |
| skip(')'); | |
| break; | |
| case TOK_DLLEXPORT: | |
| ad->a.dllexport = 1; | |
| break; | |
| case TOK_DLLIMPORT: | |
| ad->a.dllimport = 1; | |
| break; | |
| default: | |
| if (tcc_state->warn_unsupported) | |
| tcc_warning("'%s' attribute ignored", get_tok_str(t, 0)); | |
| if (tok == '(') { | |
| int parenthesis = 0; | |
| do { | |
| if (tok == '(') | |
| parenthesis++; | |
| else if (tok == ')') | |
| parenthesis--; | |
| next(); | |
| } while (parenthesis && tok != -1); | |
| } | |
| break; | |
| } | |
| if (tok != ',') | |
| break; | |
| next(); | |
| } | |
| skip(')'); | |
| skip(')'); | |
| goto redo; | |
| } | |
| static Sym * find_field (CType *type, int v) | |
| { | |
| Sym *s = type->ref; | |
| v |= 0x20000000; | |
| while ((s = s->next) != 0) { | |
| if ((s->v & 0x20000000) && | |
| (s->type.t & 0x000f) == 7 && | |
| (s->v & ~0x20000000) >= 0x10000000) { | |
| Sym *ret = find_field (&s->type, v); | |
| if (ret) | |
| return ret; | |
| } | |
| if (s->v == v) | |
| break; | |
| } | |
| return s; | |
| } | |
| static void struct_add_offset (Sym *s, int offset) | |
| { | |
| while ((s = s->next) != 0) { | |
| if ((s->v & 0x20000000) && | |
| (s->type.t & 0x000f) == 7 && | |
| (s->v & ~0x20000000) >= 0x10000000) { | |
| struct_add_offset(s->type.ref, offset); | |
| } else | |
| s->c += offset; | |
| } | |
| } | |
| static void struct_layout(CType *type, AttributeDef *ad) | |
| { | |
| int size, align, maxalign, offset, c, bit_pos, bit_size; | |
| int packed, a, bt, prevbt, prev_bit_size; | |
| int pcc = !tcc_state->ms_bitfields; | |
| int pragma_pack = *tcc_state->pack_stack_ptr; | |
| Sym *f; | |
| maxalign = 1; | |
| offset = 0; | |
| c = 0; | |
| bit_pos = 0; | |
| prevbt = 7; | |
| prev_bit_size = 0; | |
| for (f = type->ref->next; f; f = f->next) { | |
| if (f->type.t & 0x0080) | |
| bit_size = (((f->type.t) >> (20 + 6)) & 0x3f); | |
| else | |
| bit_size = -1; | |
| size = type_size(&f->type, &align); | |
| a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0; | |
| packed = 0; | |
| if (pcc && bit_size == 0) { | |
| } else { | |
| if (pcc && (f->a.packed || ad->a.packed)) | |
| align = packed = 1; | |
| if (pragma_pack) { | |
| packed = 1; | |
| if (pragma_pack < align) | |
| align = pragma_pack; | |
| if (pcc && pragma_pack < a) | |
| a = 0; | |
| } | |
| } | |
| if (a) | |
| align = a; | |
| if (type->ref->type.t == (1 << 20 | 7)) { | |
| if (pcc && bit_size >= 0) | |
| size = (bit_size + 7) >> 3; | |
| offset = 0; | |
| if (size > c) | |
| c = size; | |
| } else if (bit_size < 0) { | |
| if (pcc) | |
| c += (bit_pos + 7) >> 3; | |
| c = (c + align - 1) & -align; | |
| offset = c; | |
| if (size > 0) | |
| c += size; | |
| bit_pos = 0; | |
| prevbt = 7; | |
| prev_bit_size = 0; | |
| } else { | |
| if (pcc) { | |
| if (bit_size == 0) { | |
| new_field: | |
| c = (c + ((bit_pos + 7) >> 3) + align - 1) & -align; | |
| bit_pos = 0; | |
| } else if (f->a.aligned) { | |
| goto new_field; | |
| } else if (!packed) { | |
| int a8 = align * 8; | |
| int ofs = ((c * 8 + bit_pos) % a8 + bit_size + a8 - 1) / a8; | |
| if (ofs > size / align) | |
| goto new_field; | |
| } | |
| if (size == 8 && bit_size <= 32) | |
| f->type.t = (f->type.t & ~0x000f) | 3, size = 4; | |
| while (bit_pos >= align * 8) | |
| c += align, bit_pos -= align * 8; | |
| offset = c; | |
| if (f->v & 0x10000000 | |
| ) | |
| align = 1; | |
| } else { | |
| bt = f->type.t & 0x000f; | |
| if ((bit_pos + bit_size > size * 8) | |
| || (bit_size > 0) == (bt != prevbt) | |
| ) { | |
| c = (c + align - 1) & -align; | |
| offset = c; | |
| bit_pos = 0; | |
| if (bit_size || prev_bit_size) | |
| c += size; | |
| } | |
| if (bit_size == 0 && prevbt != bt) | |
| align = 1; | |
| prevbt = bt; | |
| prev_bit_size = bit_size; | |
| } | |
| f->type.t = (f->type.t & ~(0x3f << 20)) | |
| | (bit_pos << 20); | |
| bit_pos += bit_size; | |
| } | |
| if (align > maxalign) | |
| maxalign = align; | |
| # 3638 "tccgen.c" | |
| if (f->v & 0x10000000 && (f->type.t & 0x000f) == 7) { | |
| Sym *ass; | |
| int v2 = f->type.ref->v; | |
| if (!(v2 & 0x20000000) && | |
| (v2 & ~0x40000000) < 0x10000000) { | |
| Sym **pps; | |
| ass = f->type.ref; | |
| f->type.ref = sym_push(anon_sym++ | 0x20000000, | |
| &f->type.ref->type, 0, | |
| f->type.ref->c); | |
| pps = &f->type.ref->next; | |
| while ((ass = ass->next) != 0) { | |
| *pps = sym_push(ass->v, &ass->type, 0, ass->c); | |
| pps = &((*pps)->next); | |
| } | |
| *pps = 0; | |
| } | |
| struct_add_offset(f->type.ref, offset); | |
| f->c = 0; | |
| } else { | |
| f->c = offset; | |
| } | |
| f->r = 0; | |
| } | |
| if (pcc) | |
| c += (bit_pos + 7) >> 3; | |
| a = bt = ad->a.aligned ? 1 << (ad->a.aligned - 1) : 1; | |
| if (a < maxalign) | |
| a = maxalign; | |
| type->ref->r = a; | |
| if (pragma_pack && pragma_pack < maxalign && 0 == pcc) { | |
| a = pragma_pack; | |
| if (a < bt) | |
| a = bt; | |
| } | |
| c = (c + a - 1) & -a; | |
| type->ref->c = c; | |
| for (f = type->ref->next; f; f = f->next) { | |
| int s, px, cx, c0; | |
| CType t; | |
| if (0 == (f->type.t & 0x0080)) | |
| continue; | |
| f->type.ref = f; | |
| f->auxtype = -1; | |
| bit_size = (((f->type.t) >> (20 + 6)) & 0x3f); | |
| if (bit_size == 0) | |
| continue; | |
| bit_pos = (((f->type.t) >> 20) & 0x3f); | |
| size = type_size(&f->type, &align); | |
| if (bit_pos + bit_size <= size * 8 && f->c + size <= c) | |
| continue; | |
| c0 = -1, s = align = 1; | |
| for (;;) { | |
| px = f->c * 8 + bit_pos; | |
| cx = (px >> 3) & -align; | |
| px = px - (cx << 3); | |
| if (c0 == cx) | |
| break; | |
| s = (px + bit_size + 7) >> 3; | |
| if (s > 4) { | |
| t.t = 4; | |
| } else if (s > 2) { | |
| t.t = 3; | |
| } else if (s > 1) { | |
| t.t = 2; | |
| } else { | |
| t.t = 1; | |
| } | |
| s = type_size(&t, &align); | |
| c0 = cx; | |
| } | |
| if (px + bit_size <= s * 8 && cx + s <= c) { | |
| f->c = cx; | |
| bit_pos = px; | |
| f->type.t = (f->type.t & ~(0x3f << 20)) | |
| | (bit_pos << 20); | |
| if (s != size) | |
| f->auxtype = t.t; | |
| } else { | |
| f->auxtype = 7; | |
| } | |
| } | |
| } | |
| static void struct_decl(CType *type, int u) | |
| { | |
| int v, c, size, align, flexible; | |
| int bit_size, bsize, bt; | |
| Sym *s, *ss, **ps; | |
| AttributeDef ad, ad1; | |
| CType type1, btype; | |
| memset(&ad, 0, sizeof ad); | |
| next(); | |
| parse_attribute(&ad); | |
| if (tok != '{') { | |
| v = tok; | |
| next(); | |
| if (v < 256) | |
| expect("struct/union/enum name"); | |
| s = struct_find(v); | |
| if (s && (s->sym_scope == local_scope || tok != '{')) { | |
| if (u == s->type.t) | |
| goto do_decl; | |
| if (u == (2 << 20) && ((s->type.t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20))) | |
| goto do_decl; | |
| tcc_error("redefinition of '%s'", get_tok_str(v, 0)); | |
| } | |
| } else { | |
| v = anon_sym++; | |
| } | |
| type1.t = u == (2 << 20) ? u | 3 | 0x0010 : u; | |
| type1.ref = 0; | |
| s = sym_push(v | 0x40000000, &type1, 0, -1); | |
| s->r = 0; | |
| do_decl: | |
| type->t = s->type.t; | |
| type->ref = s; | |
| if (tok == '{') { | |
| next(); | |
| if (s->c != -1) | |
| tcc_error("struct/union/enum already defined"); | |
| ps = &s->next; | |
| if (u == (2 << 20)) { | |
| long long ll = 0, pl = 0, nl = 0; | |
| CType t; | |
| t.ref = s; | |
| t.t = 3|0x00002000|(3 << 20); | |
| for(;;) { | |
| v = tok; | |
| if (v < TOK_DEFINE) | |
| expect("identifier"); | |
| ss = sym_find(v); | |
| if (ss && !local_stack) | |
| tcc_error("redefinition of enumerator '%s'", | |
| get_tok_str(v, 0)); | |
| next(); | |
| if (tok == '=') { | |
| next(); | |
| ll = expr_const64(); | |
| } | |
| ss = sym_push(v, &t, 0x0030, 0); | |
| ss->enum_val = ll; | |
| *ps = ss, ps = &ss->next; | |
| if (ll < nl) | |
| nl = ll; | |
| if (ll > pl) | |
| pl = ll; | |
| if (tok != ',') | |
| break; | |
| next(); | |
| ll++; | |
| if (tok == '}') | |
| break; | |
| } | |
| skip('}'); | |
| t.t = 3; | |
| if (nl >= 0) { | |
| if (pl != (unsigned)pl) | |
| t.t = (8==8 ? 4|0x0800 : 4); | |
| t.t |= 0x0010; | |
| } else if (pl != (int)pl || nl != (int)nl) | |
| t.t = (8==8 ? 4|0x0800 : 4); | |
| s->type.t = type->t = t.t | (2 << 20); | |
| s->c = 0; | |
| for (ss = s->next; ss; ss = ss->next) { | |
| ll = ss->enum_val; | |
| if (ll == (int)ll) | |
| continue; | |
| if (t.t & 0x0010) { | |
| ss->type.t |= 0x0010; | |
| if (ll == (unsigned)ll) | |
| continue; | |
| } | |
| ss->type.t = (ss->type.t & ~0x000f) | |
| | (8==8 ? 4|0x0800 : 4); | |
| } | |
| } else { | |
| c = 0; | |
| flexible = 0; | |
| while (tok != '}') { | |
| if (!parse_btype(&btype, &ad1)) { | |
| skip(';'); | |
| continue; | |
| } | |
| while (1) { | |
| if (flexible) | |
| tcc_error("flexible array member '%s' not at the end of struct", | |
| get_tok_str(v, 0)); | |
| bit_size = -1; | |
| v = 0; | |
| type1 = btype; | |
| if (tok != ':') { | |
| if (tok != ';') | |
| type_decl(&type1, &ad1, &v, 2); | |
| if (v == 0) { | |
| if ((type1.t & 0x000f) != 7) | |
| expect("identifier"); | |
| else { | |
| int v = btype.ref->v; | |
| if (!(v & 0x20000000) && (v & ~0x40000000) < 0x10000000) { | |
| if (tcc_state->ms_extensions == 0) | |
| expect("identifier"); | |
| } | |
| } | |
| } | |
| if (type_size(&type1, &align) < 0) { | |
| if ((u == 7) && (type1.t & 0x0040) && c) | |
| flexible = 1; | |
| else | |
| tcc_error("field '%s' has incomplete type", | |
| get_tok_str(v, 0)); | |
| } | |
| if ((type1.t & 0x000f) == 6 || | |
| (type1.t & (0x00001000 | 0x00002000 | 0x00004000 | 0x00008000))) | |
| tcc_error("invalid type for '%s'", | |
| get_tok_str(v, 0)); | |
| } | |
| if (tok == ':') { | |
| next(); | |
| bit_size = expr_const(); | |
| if (bit_size < 0) | |
| tcc_error("negative width in bit-field '%s'", | |
| get_tok_str(v, 0)); | |
| if (v && bit_size == 0) | |
| tcc_error("zero width for bit-field '%s'", | |
| get_tok_str(v, 0)); | |
| parse_attribute(&ad1); | |
| } | |
| size = type_size(&type1, &align); | |
| if (bit_size >= 0) { | |
| bt = type1.t & 0x000f; | |
| if (bt != 3 && | |
| bt != 1 && | |
| bt != 2 && | |
| bt != 11 && | |
| bt != 4) | |
| tcc_error("bitfields must have scalar type"); | |
| bsize = size * 8; | |
| if (bit_size > bsize) { | |
| tcc_error("width of '%s' exceeds its type", | |
| get_tok_str(v, 0)); | |
| } else if (bit_size == bsize | |
| && !ad.a.packed && !ad1.a.packed) { | |
| ; | |
| } else if (bit_size == 64) { | |
| tcc_error("field width 64 not implemented"); | |
| } else { | |
| type1.t = (type1.t & ~(((1 << (6+6)) - 1) << 20 | 0x0080)) | |
| | 0x0080 | |
| | (bit_size << (20 + 6)); | |
| } | |
| } | |
| if (v != 0 || (type1.t & 0x000f) == 7) { | |
| c = 1; | |
| } | |
| if (v == 0 && | |
| ((type1.t & 0x000f) == 7 || | |
| bit_size >= 0)) { | |
| v = anon_sym++; | |
| } | |
| if (v) { | |
| ss = sym_push(v | 0x20000000, &type1, 0, 0); | |
| ss->a = ad1.a; | |
| *ps = ss; | |
| ps = &ss->next; | |
| } | |
| if (tok == ';' || tok == (-1)) | |
| break; | |
| skip(','); | |
| } | |
| skip(';'); | |
| } | |
| skip('}'); | |
| parse_attribute(&ad); | |
| struct_layout(type, &ad); | |
| } | |
| } | |
| } | |
| static void sym_to_attr(AttributeDef *ad, Sym *s) | |
| { | |
| if (s->a.aligned && 0 == ad->a.aligned) | |
| ad->a.aligned = s->a.aligned; | |
| if (s->f.func_call && 0 == ad->f.func_call) | |
| ad->f.func_call = s->f.func_call; | |
| if (s->f.func_type && 0 == ad->f.func_type) | |
| ad->f.func_type = s->f.func_type; | |
| if (s->a.packed) | |
| ad->a.packed = 1; | |
| } | |
| static void parse_btype_qualify(CType *type, int qualifiers) | |
| { | |
| while (type->t & 0x0040) { | |
| type->ref = sym_push(0x20000000, &type->ref->type, 0, type->ref->c); | |
| type = &type->ref->type; | |
| } | |
| type->t |= qualifiers; | |
| } | |
| static int parse_btype(CType *type, AttributeDef *ad) | |
| { | |
| int t, u, bt, st, type_found, typespec_found, g; | |
| Sym *s; | |
| CType type1; | |
| memset(ad, 0, sizeof(AttributeDef)); | |
| type_found = 0; | |
| typespec_found = 0; | |
| t = 3; | |
| bt = st = -1; | |
| type->ref = 0; | |
| while(1) { | |
| switch(tok) { | |
| case TOK_EXTENSION: | |
| next(); | |
| continue; | |
| case TOK_CHAR: | |
| u = 1; | |
| basic_type: | |
| next(); | |
| basic_type1: | |
| if (u == 2 || u == 0x0800) { | |
| if (st != -1 || (bt != -1 && bt != 3)) | |
| tmbt: tcc_error("too many basic types"); | |
| st = u; | |
| } else { | |
| if (bt != -1 || (st != -1 && u != 3)) | |
| goto tmbt; | |
| bt = u; | |
| } | |
| if (u != 3) | |
| t = (t & ~(0x000f|0x0800)) | u; | |
| typespec_found = 1; | |
| break; | |
| case TOK_VOID: | |
| u = 0; | |
| goto basic_type; | |
| case TOK_SHORT: | |
| u = 2; | |
| goto basic_type; | |
| case TOK_INT: | |
| u = 3; | |
| goto basic_type; | |
| case TOK_LONG: | |
| if ((t & 0x000f) == 9) { | |
| t = (t & ~(0x000f|0x0800)) | 10; | |
| } else if ((t & (0x000f|0x0800)) == 0x0800) { | |
| t = (t & ~(0x000f|0x0800)) | 4; | |
| } else { | |
| u = 0x0800; | |
| goto basic_type; | |
| } | |
| next(); | |
| break; | |
| case TOK_BOOL: | |
| u = 11; | |
| goto basic_type; | |
| case TOK_FLOAT: | |
| u = 8; | |
| goto basic_type; | |
| case TOK_DOUBLE: | |
| if ((t & (0x000f|0x0800)) == 0x0800) { | |
| t = (t & ~(0x000f|0x0800)) | 10; | |
| } else { | |
| u = 9; | |
| goto basic_type; | |
| } | |
| next(); | |
| break; | |
| case TOK_ENUM: | |
| struct_decl(&type1, (2 << 20)); | |
| basic_type2: | |
| u = type1.t; | |
| type->ref = type1.ref; | |
| goto basic_type1; | |
| case TOK_STRUCT: | |
| struct_decl(&type1, 7); | |
| goto basic_type2; | |
| case TOK_UNION: | |
| struct_decl(&type1, (1 << 20 | 7)); | |
| goto basic_type2; | |
| case TOK_CONST1: | |
| case TOK_CONST2: | |
| case TOK_CONST3: | |
| type->t = t; | |
| parse_btype_qualify(type, 0x0100); | |
| t = type->t; | |
| next(); | |
| break; | |
| case TOK_VOLATILE1: | |
| case TOK_VOLATILE2: | |
| case TOK_VOLATILE3: | |
| type->t = t; | |
| parse_btype_qualify(type, 0x0200); | |
| t = type->t; | |
| next(); | |
| break; | |
| case TOK_SIGNED1: | |
| case TOK_SIGNED2: | |
| case TOK_SIGNED3: | |
| if ((t & (0x0020|0x0010)) == (0x0020|0x0010)) | |
| tcc_error("signed and unsigned modifier"); | |
| t |= 0x0020; | |
| next(); | |
| typespec_found = 1; | |
| break; | |
| case TOK_REGISTER: | |
| case TOK_AUTO: | |
| case TOK_RESTRICT1: | |
| case TOK_RESTRICT2: | |
| case TOK_RESTRICT3: | |
| next(); | |
| break; | |
| case TOK_UNSIGNED: | |
| if ((t & (0x0020|0x0010)) == 0x0020) | |
| tcc_error("signed and unsigned modifier"); | |
| t |= 0x0020 | 0x0010; | |
| next(); | |
| typespec_found = 1; | |
| break; | |
| case TOK_EXTERN: | |
| g = 0x00001000; | |
| goto storage; | |
| case TOK_STATIC: | |
| g = 0x00002000; | |
| goto storage; | |
| case TOK_TYPEDEF: | |
| g = 0x00004000; | |
| goto storage; | |
| storage: | |
| if (t & (0x00001000|0x00002000|0x00004000) & ~g) | |
| tcc_error("multiple storage classes"); | |
| t |= g; | |
| next(); | |
| break; | |
| case TOK_INLINE1: | |
| case TOK_INLINE2: | |
| case TOK_INLINE3: | |
| t |= 0x00008000; | |
| next(); | |
| break; | |
| case TOK_ATTRIBUTE1: | |
| case TOK_ATTRIBUTE2: | |
| parse_attribute(ad); | |
| if (ad->attr_mode) { | |
| u = ad->attr_mode -1; | |
| t = (t & ~(0x000f|0x0800)) | u; | |
| } | |
| break; | |
| case TOK_TYPEOF1: | |
| case TOK_TYPEOF2: | |
| case TOK_TYPEOF3: | |
| next(); | |
| parse_expr_type(&type1); | |
| type1.t &= ~((0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)&~0x00004000); | |
| if (type1.ref) | |
| sym_to_attr(ad, type1.ref); | |
| goto basic_type2; | |
| default: | |
| if (typespec_found) | |
| goto the_end; | |
| s = sym_find(tok); | |
| if (!s || !(s->type.t & 0x00004000)) | |
| goto the_end; | |
| t &= ~(0x000f|0x0800); | |
| u = t & ~(0x0100 | 0x0200), t ^= u; | |
| type->t = (s->type.t & ~0x00004000) | u; | |
| type->ref = s->type.ref; | |
| if (t) | |
| parse_btype_qualify(type, t); | |
| t = type->t; | |
| sym_to_attr(ad, s); | |
| next(); | |
| typespec_found = 1; | |
| st = bt = -2; | |
| break; | |
| } | |
| type_found = 1; | |
| } | |
| the_end: | |
| if (tcc_state->char_is_unsigned) { | |
| if ((t & (0x0020|0x000f)) == 1) | |
| t |= 0x0010; | |
| } | |
| bt = t & (0x000f|0x0800); | |
| if (bt == 0x0800) | |
| t |= 8 == 8 ? 4 : 3; | |
| type->t = t; | |
| return type_found; | |
| } | |
| static inline void convert_parameter_type(CType *pt) | |
| { | |
| pt->t &= ~(0x0100 | 0x0200); | |
| pt->t &= ~0x0040; | |
| if ((pt->t & 0x000f) == 6) { | |
| mk_pointer(pt); | |
| } | |
| } | |
| static void parse_asm_str(CString *astr) | |
| { | |
| skip('('); | |
| parse_mult_str(astr, "string constant"); | |
| } | |
| static int asm_label_instr(void) | |
| { | |
| int v; | |
| CString astr; | |
| next(); | |
| parse_asm_str(&astr); | |
| skip(')'); | |
| v = tok_alloc(astr.data, astr.size - 1)->tok; | |
| cstr_free(&astr); | |
| return v; | |
| } | |
| static int post_type(CType *type, AttributeDef *ad, int storage, int td) | |
| { | |
| int n, l, t1, arg_size, align; | |
| Sym **plast, *s, *first; | |
| AttributeDef ad1; | |
| CType pt; | |
| if (tok == '(') { | |
| next(); | |
| if (td && !(td & 1)) | |
| return 0; | |
| if (tok == ')') | |
| l = 0; | |
| else if (parse_btype(&pt, &ad1)) | |
| l = 1; | |
| else if (td) | |
| return 0; | |
| else | |
| l = 2; | |
| first = 0; | |
| plast = &first; | |
| arg_size = 0; | |
| if (l) { | |
| for(;;) { | |
| if (l != 2) { | |
| if ((pt.t & 0x000f) == 0 && tok == ')') | |
| break; | |
| type_decl(&pt, &ad1, &n, 2 | 1); | |
| if ((pt.t & 0x000f) == 0) | |
| tcc_error("parameter declared as void"); | |
| arg_size += (type_size(&pt, &align) + 8 - 1) / 8; | |
| } else { | |
| n = tok; | |
| if (n < TOK_DEFINE) | |
| expect("identifier"); | |
| pt.t = 0; | |
| next(); | |
| } | |
| convert_parameter_type(&pt); | |
| s = sym_push(n | 0x20000000, &pt, 0, 0); | |
| *plast = s; | |
| plast = &s->next; | |
| if (tok == ')') | |
| break; | |
| skip(','); | |
| if (l == 1 && tok == 0xc8) { | |
| l = 3; | |
| next(); | |
| break; | |
| } | |
| if (l == 1 && !parse_btype(&pt, &ad1)) | |
| tcc_error("invalid type"); | |
| } | |
| } else | |
| l = 2; | |
| skip(')'); | |
| type->t &= ~0x0100; | |
| if (tok == '[') { | |
| next(); | |
| skip(']'); | |
| mk_pointer(type); | |
| } | |
| ad->f.func_args = arg_size; | |
| ad->f.func_type = l; | |
| s = sym_push(0x20000000, type, 0, 0); | |
| s->a = ad->a; | |
| s->f = ad->f; | |
| s->next = first; | |
| type->t = 6; | |
| type->ref = s; | |
| } else if (tok == '[') { | |
| int saved_nocode_wanted = nocode_wanted; | |
| next(); | |
| if (tok == TOK_RESTRICT1) | |
| next(); | |
| n = -1; | |
| t1 = 0; | |
| if (tok != ']') { | |
| if (!local_stack || (storage & 0x00002000)) | |
| vpushi(expr_const()); | |
| else { | |
| nocode_wanted = 0; | |
| gexpr(); | |
| } | |
| if ((vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030) { | |
| n = vtop->c.i; | |
| if (n < 0) | |
| tcc_error("invalid array size"); | |
| } else { | |
| if (!is_integer_btype(vtop->type.t & 0x000f)) | |
| tcc_error("size of variable length array should be an integer"); | |
| t1 = 0x0400; | |
| } | |
| } | |
| skip(']'); | |
| post_type(type, ad, storage, 0); | |
| if (type->t == 6) | |
| tcc_error("declaration of an array of functions"); | |
| t1 |= type->t & 0x0400; | |
| if (t1 & 0x0400) { | |
| loc -= type_size(&int_type, &align); | |
| loc &= -align; | |
| n = loc; | |
| vla_runtime_type_size(type, &align); | |
| gen_op('*'); | |
| vset(&int_type, 0x0032|0x0100, n); | |
| vswap(); | |
| vstore(); | |
| } | |
| if (n != -1) | |
| vpop(); | |
| nocode_wanted = saved_nocode_wanted; | |
| s = sym_push(0x20000000, type, 0, n); | |
| type->t = (t1 ? 0x0400 : 0x0040) | 5; | |
| type->ref = s; | |
| } | |
| return 1; | |
| } | |
| # 4401 "tccgen.c" | |
| static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) | |
| { | |
| CType *post, *ret; | |
| int qualifiers, storage; | |
| storage = type->t & (0x00001000 | 0x00002000 | 0x00004000 | 0x00008000); | |
| type->t &= ~(0x00001000 | 0x00002000 | 0x00004000 | 0x00008000); | |
| post = ret = type; | |
| while (tok == '*') { | |
| qualifiers = 0; | |
| redo: | |
| next(); | |
| switch(tok) { | |
| case TOK_CONST1: | |
| case TOK_CONST2: | |
| case TOK_CONST3: | |
| qualifiers |= 0x0100; | |
| goto redo; | |
| case TOK_VOLATILE1: | |
| case TOK_VOLATILE2: | |
| case TOK_VOLATILE3: | |
| qualifiers |= 0x0200; | |
| goto redo; | |
| case TOK_RESTRICT1: | |
| case TOK_RESTRICT2: | |
| case TOK_RESTRICT3: | |
| goto redo; | |
| case TOK_ATTRIBUTE1: | |
| case TOK_ATTRIBUTE2: | |
| parse_attribute(ad); | |
| break; | |
| } | |
| mk_pointer(type); | |
| type->t |= qualifiers; | |
| if (ret == type) | |
| ret = pointed_type(type); | |
| } | |
| if (tok == '(') { | |
| if (!post_type(type, ad, 0, td)) { | |
| parse_attribute(ad); | |
| post = type_decl(type, ad, v, td); | |
| skip(')'); | |
| } | |
| } else if (tok >= 256 && (td & 2)) { | |
| *v = tok; | |
| next(); | |
| } else { | |
| if (!(td & 1)) | |
| expect("identifier"); | |
| *v = 0; | |
| } | |
| post_type(post, ad, storage, 0); | |
| parse_attribute(ad); | |
| type->t |= storage; | |
| return ret; | |
| } | |
| static int lvalue_type(int t) | |
| { | |
| int bt, r; | |
| r = 0x0100; | |
| bt = t & 0x000f; | |
| if (bt == 1 || bt == 11) | |
| r |= 0x1000; | |
| else if (bt == 2) | |
| r |= 0x2000; | |
| else | |
| return r; | |
| if (t & 0x0010) | |
| r |= 0x4000; | |
| return r; | |
| } | |
| static void indir(void) | |
| { | |
| if ((vtop->type.t & 0x000f) != 5) { | |
| if ((vtop->type.t & 0x000f) == 6) | |
| return; | |
| expect("pointer"); | |
| } | |
| if (vtop->r & 0x0100) | |
| gv(0x0001); | |
| vtop->type = *pointed_type(&vtop->type); | |
| if (!(vtop->type.t & 0x0040) && !(vtop->type.t & 0x0400) | |
| && (vtop->type.t & 0x000f) != 6) { | |
| vtop->r |= lvalue_type(vtop->type.t); | |
| if (tcc_state->do_bounds_check) | |
| vtop->r |= 0x0800; | |
| } | |
| } | |
| static void gfunc_param_typed(Sym *func, Sym *arg) | |
| { | |
| int func_type; | |
| CType type; | |
| func_type = func->f.func_type; | |
| if (func_type == 2 || | |
| (func_type == 3 && arg == 0)) { | |
| if ((vtop->type.t & 0x000f) == 8) { | |
| gen_cast_s(9); | |
| } else if (vtop->type.t & 0x0080) { | |
| type.t = vtop->type.t & (0x000f | 0x0010); | |
| type.ref = vtop->type.ref; | |
| gen_cast(&type); | |
| } | |
| } else if (arg == 0) { | |
| tcc_error("too many arguments to function"); | |
| } else { | |
| type = arg->type; | |
| type.t &= ~0x0100; | |
| gen_assign_cast(&type); | |
| } | |
| } | |
| static void expr_type(CType *type, void (*expr_fn)(void)) | |
| { | |
| nocode_wanted++; | |
| expr_fn(); | |
| *type = vtop->type; | |
| vpop(); | |
| nocode_wanted--; | |
| } | |
| static void parse_expr_type(CType *type) | |
| { | |
| int n; | |
| AttributeDef ad; | |
| skip('('); | |
| if (parse_btype(type, &ad)) { | |
| type_decl(type, &ad, &n, 1); | |
| } else { | |
| expr_type(type, gexpr); | |
| } | |
| skip(')'); | |
| } | |
| static void parse_type(CType *type) | |
| { | |
| AttributeDef ad; | |
| int n; | |
| if (!parse_btype(type, &ad)) { | |
| expect("type"); | |
| } | |
| type_decl(type, &ad, &n, 1); | |
| } | |
| static void parse_builtin_params(int nc, const char *args) | |
| { | |
| char c, sep = '('; | |
| CType t; | |
| if (nc) | |
| nocode_wanted++; | |
| next(); | |
| while ((c = *args++)) { | |
| skip(sep); | |
| sep = ','; | |
| switch (c) { | |
| case 'e': expr_eq(); continue; | |
| case 't': parse_type(&t); vpush(&t); continue; | |
| default: tcc_error("internal error"); break; | |
| } | |
| } | |
| skip(')'); | |
| if (nc) | |
| nocode_wanted--; | |
| } | |
| static void unary(void) | |
| { | |
| int n, t, align, size, r, sizeof_caller; | |
| CType type; | |
| Sym *s; | |
| AttributeDef ad; | |
| sizeof_caller = in_sizeof; | |
| in_sizeof = 0; | |
| type.ref = 0; | |
| tok_next: | |
| switch(tok) { | |
| case TOK_EXTENSION: | |
| next(); | |
| goto tok_next; | |
| case 0xb4: | |
| case 0xb5: | |
| case 0xb3: | |
| t = 3; | |
| push_tokc: | |
| type.t = t; | |
| vsetc(&type, 0x0030, &tokc); | |
| next(); | |
| break; | |
| case 0xb6: | |
| t = 3 | 0x0010; | |
| goto push_tokc; | |
| case 0xb7: | |
| t = 4; | |
| goto push_tokc; | |
| case 0xb8: | |
| t = 4 | 0x0010; | |
| goto push_tokc; | |
| case 0xbb: | |
| t = 8; | |
| goto push_tokc; | |
| case 0xbc: | |
| t = 9; | |
| goto push_tokc; | |
| case 0xbd: | |
| t = 10; | |
| goto push_tokc; | |
| case 0xce: | |
| t = (8 == 8 ? 4 : 3) | 0x0800; | |
| goto push_tokc; | |
| case 0xcf: | |
| t = (8 == 8 ? 4 : 3) | 0x0800 | 0x0010; | |
| goto push_tokc; | |
| case TOK___FUNCTION__: | |
| if (!gnu_ext) | |
| goto tok_identifier; | |
| case TOK___FUNC__: | |
| { | |
| void *ptr; | |
| int len; | |
| len = strlen(funcname) + 1; | |
| type.t = 1; | |
| mk_pointer(&type); | |
| type.t |= 0x0040; | |
| type.ref->c = len; | |
| vpush_ref(&type, data_section, data_section->data_offset, len); | |
| if (!(nocode_wanted > 0)) { | |
| ptr = section_ptr_add(data_section, len); | |
| memcpy(ptr, funcname, len); | |
| } | |
| next(); | |
| } | |
| break; | |
| case 0xba: | |
| t = 3; | |
| goto str_init; | |
| case 0xb9: | |
| t = 1; | |
| if (tcc_state->char_is_unsigned) | |
| t = 1 | 0x0010; | |
| str_init: | |
| if (tcc_state->warn_write_strings) | |
| t |= 0x0100; | |
| type.t = t; | |
| mk_pointer(&type); | |
| type.t |= 0x0040; | |
| memset(&ad, 0, sizeof(AttributeDef)); | |
| decl_initializer_alloc(&type, &ad, 0x0030, 2, 0, 0); | |
| break; | |
| case '(': | |
| next(); | |
| if (parse_btype(&type, &ad)) { | |
| type_decl(&type, &ad, &n, 1); | |
| skip(')'); | |
| if (tok == '{') { | |
| if (global_expr) | |
| r = 0x0030; | |
| else | |
| r = 0x0032; | |
| if (!(type.t & 0x0040)) | |
| r |= lvalue_type(type.t); | |
| memset(&ad, 0, sizeof(AttributeDef)); | |
| decl_initializer_alloc(&type, &ad, r, 1, 0, 0); | |
| } else { | |
| if (sizeof_caller) { | |
| vpush(&type); | |
| return; | |
| } | |
| unary(); | |
| gen_cast(&type); | |
| } | |
| } else if (tok == '{') { | |
| int saved_nocode_wanted = nocode_wanted; | |
| if (const_wanted) | |
| tcc_error("expected constant"); | |
| save_regs(0); | |
| block(0, 0, 1); | |
| nocode_wanted = saved_nocode_wanted; | |
| skip(')'); | |
| } else { | |
| gexpr(); | |
| skip(')'); | |
| } | |
| break; | |
| case '*': | |
| next(); | |
| unary(); | |
| indir(); | |
| break; | |
| case '&': | |
| next(); | |
| unary(); | |
| if ((vtop->type.t & 0x000f) != 6 && | |
| !(vtop->type.t & 0x0040)) | |
| test_lvalue(); | |
| mk_pointer(&vtop->type); | |
| gaddrof(); | |
| break; | |
| case '!': | |
| next(); | |
| unary(); | |
| if ((vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030) { | |
| gen_cast_s(11); | |
| vtop->c.i = !vtop->c.i; | |
| } else if ((vtop->r & 0x003f) == 0x0033) | |
| vtop->c.i ^= 1; | |
| else { | |
| save_regs(1); | |
| vseti(0x0034, gvtst(1, 0)); | |
| } | |
| break; | |
| case '~': | |
| next(); | |
| unary(); | |
| vpushi(-1); | |
| gen_op('^'); | |
| break; | |
| case '+': | |
| next(); | |
| unary(); | |
| if ((vtop->type.t & 0x000f) == 5) | |
| tcc_error("pointer not accepted for unary plus"); | |
| if (!is_float(vtop->type.t)) { | |
| vpushi(0); | |
| gen_op('+'); | |
| } | |
| break; | |
| case TOK_SIZEOF: | |
| case TOK_ALIGNOF1: | |
| case TOK_ALIGNOF2: | |
| t = tok; | |
| next(); | |
| in_sizeof++; | |
| expr_type(&type, unary); | |
| s = vtop[1].sym; | |
| size = type_size(&type, &align); | |
| if (s && s->a.aligned) | |
| align = 1 << (s->a.aligned - 1); | |
| if (t == TOK_SIZEOF) { | |
| if (!(type.t & 0x0400)) { | |
| if (size < 0) | |
| tcc_error("sizeof applied to an incomplete type"); | |
| vpushs(size); | |
| } else { | |
| vla_runtime_type_size(&type, &align); | |
| } | |
| } else { | |
| vpushs(align); | |
| } | |
| vtop->type.t |= 0x0010; | |
| break; | |
| case TOK_builtin_expect: | |
| parse_builtin_params(0, "ee"); | |
| vpop(); | |
| break; | |
| case TOK_builtin_types_compatible_p: | |
| parse_builtin_params(0, "tt"); | |
| vtop[-1].type.t &= ~(0x0100 | 0x0200); | |
| vtop[0].type.t &= ~(0x0100 | 0x0200); | |
| n = is_compatible_types(&vtop[-1].type, &vtop[0].type); | |
| vtop -= 2; | |
| vpushi(n); | |
| break; | |
| case TOK_builtin_choose_expr: | |
| { | |
| int64_t c; | |
| next(); | |
| skip('('); | |
| c = expr_const64(); | |
| skip(','); | |
| if (!c) { | |
| nocode_wanted++; | |
| } | |
| expr_eq(); | |
| if (!c) { | |
| vpop(); | |
| nocode_wanted--; | |
| } | |
| skip(','); | |
| if (c) { | |
| nocode_wanted++; | |
| } | |
| expr_eq(); | |
| if (c) { | |
| vpop(); | |
| nocode_wanted--; | |
| } | |
| skip(')'); | |
| } | |
| break; | |
| case TOK_builtin_constant_p: | |
| parse_builtin_params(1, "e"); | |
| n = (vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030; | |
| vtop--; | |
| vpushi(n); | |
| break; | |
| case TOK_builtin_frame_address: | |
| case TOK_builtin_return_address: | |
| { | |
| int tok1 = tok; | |
| int level; | |
| next(); | |
| skip('('); | |
| if (tok != 0xb5) { | |
| tcc_error("%s only takes positive integers", | |
| tok1 == TOK_builtin_return_address ? | |
| "__builtin_return_address" : | |
| "__builtin_frame_address"); | |
| } | |
| level = (uint32_t)tokc.i; | |
| next(); | |
| skip(')'); | |
| type.t = 0; | |
| mk_pointer(&type); | |
| vset(&type, 0x0032, 0); | |
| while (level--) { | |
| mk_pointer(&vtop->type); | |
| indir(); | |
| } | |
| if (tok1 == TOK_builtin_return_address) { | |
| vpushi(8); | |
| gen_op('+'); | |
| mk_pointer(&vtop->type); | |
| indir(); | |
| } | |
| } | |
| break; | |
| # 4906 "tccgen.c" | |
| case TOK_builtin_va_arg_types: | |
| parse_builtin_params(0, "t"); | |
| vpushi(classify_x86_64_va_arg(&vtop->type)); | |
| vswap(); | |
| vpop(); | |
| break; | |
| # 4942 "tccgen.c" | |
| case 0xa4: | |
| case 0xa2: | |
| t = tok; | |
| next(); | |
| unary(); | |
| inc(0, t); | |
| break; | |
| case '-': | |
| next(); | |
| unary(); | |
| t = vtop->type.t & 0x000f; | |
| if (is_float(t)) { | |
| vpush(&vtop->type); | |
| if (t == 8) | |
| vtop->c.f = -1.0 * 0.0; | |
| else if (t == 9) | |
| vtop->c.d = -1.0 * 0.0; | |
| else | |
| vtop->c.ld = -1.0 * 0.0; | |
| } else | |
| vpushi(0); | |
| vswap(); | |
| gen_op('-'); | |
| break; | |
| case 0xa0: | |
| if (!gnu_ext) | |
| goto tok_identifier; | |
| next(); | |
| if (tok < TOK_DEFINE) | |
| expect("label identifier"); | |
| s = label_find(tok); | |
| if (!s) { | |
| s = label_push(&global_label_stack, tok, 1); | |
| } else { | |
| if (s->r == 2) | |
| s->r = 1; | |
| } | |
| if (!s->type.t) { | |
| s->type.t = 0; | |
| mk_pointer(&s->type); | |
| s->type.t |= 0x00002000; | |
| } | |
| vpushsym(&s->type, s); | |
| next(); | |
| break; | |
| case TOK_GENERIC: | |
| { | |
| CType controlling_type; | |
| int has_default = 0; | |
| int has_match = 0; | |
| int learn = 0; | |
| TokenString *str = 0; | |
| next(); | |
| skip('('); | |
| expr_type(&controlling_type, expr_eq); | |
| controlling_type.t &= ~(0x0100 | 0x0200 | 0x0040); | |
| for (;;) { | |
| learn = 0; | |
| skip(','); | |
| if (tok == TOK_DEFAULT) { | |
| if (has_default) | |
| tcc_error("too many 'default'"); | |
| has_default = 1; | |
| if (!has_match) | |
| learn = 1; | |
| next(); | |
| } else { | |
| AttributeDef ad_tmp; | |
| int itmp; | |
| CType cur_type; | |
| parse_btype(&cur_type, &ad_tmp); | |
| type_decl(&cur_type, &ad_tmp, &itmp, 1); | |
| if (compare_types(&controlling_type, &cur_type, 0)) { | |
| if (has_match) { | |
| tcc_error("type match twice"); | |
| } | |
| has_match = 1; | |
| learn = 1; | |
| } | |
| } | |
| skip(':'); | |
| if (learn) { | |
| if (str) | |
| tok_str_free(str); | |
| skip_or_save_block(&str); | |
| } else { | |
| skip_or_save_block(0); | |
| } | |
| if (tok == ')') | |
| break; | |
| } | |
| if (!str) { | |
| char buf[60]; | |
| type_to_str(buf, sizeof buf, &controlling_type, 0); | |
| tcc_error("type '%s' does not match any association", buf); | |
| } | |
| begin_macro(str, 1); | |
| next(); | |
| expr_eq(); | |
| if (tok != (-1)) | |
| expect(","); | |
| end_macro(); | |
| next(); | |
| break; | |
| } | |
| case TOK___NAN__: | |
| vpush64(9, 0x7ff8000000000000ULL); | |
| next(); | |
| break; | |
| case TOK___SNAN__: | |
| vpush64(9, 0x7ff0000000000001ULL); | |
| next(); | |
| break; | |
| case TOK___INF__: | |
| vpush64(9, 0x7ff0000000000000ULL); | |
| next(); | |
| break; | |
| default: | |
| tok_identifier: | |
| t = tok; | |
| next(); | |
| if (t < TOK_DEFINE) | |
| expect("identifier"); | |
| s = sym_find(t); | |
| if (!s || (((s)->type.t & (0x000f | (0 | 0x0010))) == (0 | 0x0010))) { | |
| const char *name = get_tok_str(t, 0); | |
| if (tok != '(') | |
| tcc_error("'%s' undeclared", name); | |
| if (tcc_state->warn_implicit_function_declaration | |
| ) | |
| tcc_warning("implicit declaration of function '%s'", name); | |
| s = external_global_sym(t, &func_old_type, 0); | |
| } | |
| r = s->r; | |
| if ((r & 0x003f) < 0x0030) | |
| r = (r & ~0x003f) | 0x0032; | |
| vset(&s->type, r, s->c); | |
| vtop->sym = s; | |
| if (r & 0x0200) { | |
| vtop->c.i = 0; | |
| } else if (r == 0x0030 && ((s->type.t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (3 << 20))) { | |
| vtop->c.i = s->enum_val; | |
| } | |
| break; | |
| } | |
| while (1) { | |
| if (tok == 0xa4 || tok == 0xa2) { | |
| inc(1, tok); | |
| next(); | |
| } else if (tok == '.' || tok == 0xc7 || tok == 0xbc) { | |
| int qualifiers; | |
| if (tok == 0xc7) | |
| indir(); | |
| qualifiers = vtop->type.t & (0x0100 | 0x0200); | |
| test_lvalue(); | |
| gaddrof(); | |
| if ((vtop->type.t & 0x000f) != 7) | |
| expect("struct or union"); | |
| if (tok == 0xbc) | |
| expect("field name"); | |
| next(); | |
| if (tok == 0xb5 || tok == 0xb6) | |
| expect("field name"); | |
| s = find_field(&vtop->type, tok); | |
| if (!s) | |
| tcc_error("field not found: %s", get_tok_str(tok & ~0x20000000, &tokc)); | |
| vtop->type = char_pointer_type; | |
| vpushi(s->c); | |
| gen_op('+'); | |
| vtop->type = s->type; | |
| vtop->type.t |= qualifiers; | |
| if (!(vtop->type.t & 0x0040)) { | |
| vtop->r |= lvalue_type(vtop->type.t); | |
| if (tcc_state->do_bounds_check && (vtop->r & 0x003f) != 0x0032) | |
| vtop->r |= 0x0800; | |
| } | |
| next(); | |
| } else if (tok == '[') { | |
| next(); | |
| gexpr(); | |
| gen_op('+'); | |
| indir(); | |
| skip(']'); | |
| } else if (tok == '(') { | |
| SValue ret; | |
| Sym *sa; | |
| int nb_args, ret_nregs, ret_align, regsize, variadic; | |
| if ((vtop->type.t & 0x000f) != 6) { | |
| if ((vtop->type.t & (0x000f | 0x0040)) == 5) { | |
| vtop->type = *pointed_type(&vtop->type); | |
| if ((vtop->type.t & 0x000f) != 6) | |
| goto error_func; | |
| } else { | |
| error_func: | |
| expect("function pointer"); | |
| } | |
| } else { | |
| vtop->r &= ~0x0100; | |
| } | |
| s = vtop->type.ref; | |
| next(); | |
| sa = s->next; | |
| nb_args = regsize = 0; | |
| ret.r2 = 0x0030; | |
| if ((s->type.t & 0x000f) == 7) { | |
| variadic = (s->f.func_type == 3); | |
| ret_nregs = gfunc_sret(&s->type, variadic, &ret.type, | |
| &ret_align, ®size); | |
| if (!ret_nregs) { | |
| size = type_size(&s->type, &align); | |
| # 5199 "tccgen.c" | |
| loc = (loc - size) & -align; | |
| ret.type = s->type; | |
| ret.r = 0x0032 | 0x0100; | |
| vseti(0x0032, loc); | |
| ret.c = vtop->c; | |
| nb_args++; | |
| } | |
| } else { | |
| ret_nregs = 1; | |
| ret.type = s->type; | |
| } | |
| if (ret_nregs) { | |
| if (is_float(ret.type.t)) { | |
| ret.r = reg_fret(ret.type.t); | |
| if ((ret.type.t & 0x000f) == 14) | |
| ret.r2 = TREG_XMM1; | |
| } else { | |
| if ((ret.type.t & 0x000f) == 13) | |
| ret.r2 = TREG_RDX; | |
| ret.r = TREG_RAX; | |
| } | |
| ret.c.i = 0; | |
| } | |
| if (tok != ')') { | |
| for(;;) { | |
| expr_eq(); | |
| gfunc_param_typed(s, sa); | |
| nb_args++; | |
| if (sa) | |
| sa = sa->next; | |
| if (tok == ')') | |
| break; | |
| skip(','); | |
| } | |
| } | |
| if (sa) | |
| tcc_error("too few arguments to function"); | |
| skip(')'); | |
| gfunc_call(nb_args); | |
| for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) { | |
| vsetc(&ret.type, r, &ret.c); | |
| vtop->r2 = ret.r2; | |
| } | |
| if (((s->type.t & 0x000f) == 7) && ret_nregs) { | |
| int addr, offset; | |
| size = type_size(&s->type, &align); | |
| if (regsize > align) | |
| align = regsize; | |
| loc = (loc - size) & -align; | |
| addr = loc; | |
| offset = 0; | |
| for (;;) { | |
| vset(&ret.type, 0x0032 | 0x0100, addr + offset); | |
| vswap(); | |
| vstore(); | |
| vtop--; | |
| if (--ret_nregs == 0) | |
| break; | |
| offset += regsize; | |
| } | |
| vset(&s->type, 0x0032 | 0x0100, addr); | |
| } | |
| } else { | |
| break; | |
| } | |
| } | |
| } | |
| static void expr_prod(void) | |
| { | |
| int t; | |
| unary(); | |
| while (tok == '*' || tok == '/' || tok == '%') { | |
| t = tok; | |
| next(); | |
| unary(); | |
| gen_op(t); | |
| } | |
| } | |
| static void expr_sum(void) | |
| { | |
| int t; | |
| expr_prod(); | |
| while (tok == '+' || tok == '-') { | |
| t = tok; | |
| next(); | |
| expr_prod(); | |
| gen_op(t); | |
| } | |
| } | |
| static void expr_shift(void) | |
| { | |
| int t; | |
| expr_sum(); | |
| while (tok == 0x01 || tok == 0x02) { | |
| t = tok; | |
| next(); | |
| expr_sum(); | |
| gen_op(t); | |
| } | |
| } | |
| static void expr_cmp(void) | |
| { | |
| int t; | |
| expr_shift(); | |
| while ((tok >= 0x96 && tok <= 0x9f) || | |
| tok == 0x92 || tok == 0x93) { | |
| t = tok; | |
| next(); | |
| expr_shift(); | |
| gen_op(t); | |
| } | |
| } | |
| static void expr_cmpeq(void) | |
| { | |
| int t; | |
| expr_cmp(); | |
| while (tok == 0x94 || tok == 0x95) { | |
| t = tok; | |
| next(); | |
| expr_cmp(); | |
| gen_op(t); | |
| } | |
| } | |
| static void expr_and(void) | |
| { | |
| expr_cmpeq(); | |
| while (tok == '&') { | |
| next(); | |
| expr_cmpeq(); | |
| gen_op('&'); | |
| } | |
| } | |
| static void expr_xor(void) | |
| { | |
| expr_and(); | |
| while (tok == '^') { | |
| next(); | |
| expr_and(); | |
| gen_op('^'); | |
| } | |
| } | |
| static void expr_or(void) | |
| { | |
| expr_xor(); | |
| while (tok == '|') { | |
| next(); | |
| expr_xor(); | |
| gen_op('|'); | |
| } | |
| } | |
| static void expr_land(void) | |
| { | |
| expr_or(); | |
| if (tok == 0xa0) { | |
| int t = 0; | |
| for(;;) { | |
| if ((vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030) { | |
| gen_cast_s(11); | |
| if (vtop->c.i) { | |
| vpop(); | |
| } else { | |
| nocode_wanted++; | |
| while (tok == 0xa0) { | |
| next(); | |
| expr_or(); | |
| vpop(); | |
| } | |
| nocode_wanted--; | |
| if (t) | |
| gsym(t); | |
| gen_cast_s(3); | |
| break; | |
| } | |
| } else { | |
| if (!t) | |
| save_regs(1); | |
| t = gvtst(1, t); | |
| } | |
| if (tok != 0xa0) { | |
| if (t) | |
| vseti(0x0035, t); | |
| else | |
| vpushi(1); | |
| break; | |
| } | |
| next(); | |
| expr_or(); | |
| } | |
| } | |
| } | |
| static void expr_lor(void) | |
| { | |
| expr_land(); | |
| if (tok == 0xa1) { | |
| int t = 0; | |
| for(;;) { | |
| if ((vtop->r & (0x003f | 0x0100 | 0x0200)) == 0x0030) { | |
| gen_cast_s(11); | |
| if (!vtop->c.i) { | |
| vpop(); | |
| } else { | |
| nocode_wanted++; | |
| while (tok == 0xa1) { | |
| next(); | |
| expr_land(); | |
| vpop(); | |
| } | |
| nocode_wanted--; | |
| if (t) | |
| gsym(t); | |
| gen_cast_s(3); | |
| break; | |
| } | |
| } else { | |
| if (!t) | |
| save_regs(1); | |
| t = gvtst(0, t); | |
| } | |
| if (tok != 0xa1) { | |
| if (t) | |
| vseti(0x0034, t); | |
| else | |
| vpushi(0); | |
| break; | |
| } | |
| next(); | |
| expr_land(); | |
| } | |
| } | |
| } | |
| static int condition_3way(void) | |
| { | |
| int c = -1; | |
| if ((vtop->r & (0x003f | 0x0100)) == 0x0030 && | |
| (!(vtop->r & 0x0200) || !vtop->sym->a.weak)) { | |
| vdup(); | |
| gen_cast_s(11); | |
| c = vtop->c.i; | |
| vpop(); | |
| } | |
| return c; | |
| } | |
| static void expr_cond(void) | |
| { | |
| int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv, c, g; | |
| SValue sv; | |
| CType type, type1, type2; | |
| expr_lor(); | |
| if (tok == '?') { | |
| next(); | |
| c = condition_3way(); | |
| g = (tok == ':' && gnu_ext); | |
| if (c < 0) { | |
| if (is_float(vtop->type.t)) { | |
| rc = 0x0002; | |
| if ((vtop->type.t & 0x000f) == 10) { | |
| rc = 0x0080; | |
| } | |
| } else | |
| rc = 0x0001; | |
| gv(rc); | |
| save_regs(1); | |
| if (g) | |
| gv_dup(); | |
| tt = gvtst(1, 0); | |
| } else { | |
| if (!g) | |
| vpop(); | |
| tt = 0; | |
| } | |
| if (1) { | |
| if (c == 0) | |
| nocode_wanted++; | |
| if (!g) | |
| gexpr(); | |
| type1 = vtop->type; | |
| sv = *vtop; | |
| vtop--; | |
| skip(':'); | |
| u = 0; | |
| if (c < 0) | |
| u = gjmp(0); | |
| gsym(tt); | |
| if (c == 0) | |
| nocode_wanted--; | |
| if (c == 1) | |
| nocode_wanted++; | |
| expr_cond(); | |
| if (c == 1) | |
| nocode_wanted--; | |
| type2 = vtop->type; | |
| t1 = type1.t; | |
| bt1 = t1 & 0x000f; | |
| t2 = type2.t; | |
| bt2 = t2 & 0x000f; | |
| type.ref = 0; | |
| if (is_float(bt1) || is_float(bt2)) { | |
| if (bt1 == 10 || bt2 == 10) { | |
| type.t = 10; | |
| } else if (bt1 == 9 || bt2 == 9) { | |
| type.t = 9; | |
| } else { | |
| type.t = 8; | |
| } | |
| } else if (bt1 == 4 || bt2 == 4) { | |
| type.t = 4 | 0x0800; | |
| if (bt1 == 4) | |
| type.t &= t1; | |
| if (bt2 == 4) | |
| type.t &= t2; | |
| if ((t1 & (0x000f | 0x0010 | 0x0080)) == (4 | 0x0010) || | |
| (t2 & (0x000f | 0x0010 | 0x0080)) == (4 | 0x0010)) | |
| type.t |= 0x0010; | |
| } else if (bt1 == 5 || bt2 == 5) { | |
| if (is_null_pointer (vtop)) | |
| type = type1; | |
| else if (is_null_pointer (&sv)) | |
| type = type2; | |
| else | |
| type = type1; | |
| } else if (bt1 == 6 || bt2 == 6) { | |
| type = bt1 == 6 ? type1 : type2; | |
| } else if (bt1 == 7 || bt2 == 7) { | |
| type = bt1 == 7 ? type1 : type2; | |
| } else if (bt1 == 0 || bt2 == 0) { | |
| type.t = 0; | |
| } else { | |
| type.t = 3 | (0x0800 & (t1 | t2)); | |
| if ((t1 & (0x000f | 0x0010 | 0x0080)) == (3 | 0x0010) || | |
| (t2 & (0x000f | 0x0010 | 0x0080)) == (3 | 0x0010)) | |
| type.t |= 0x0010; | |
| } | |
| islv = (vtop->r & 0x0100) && (sv.r & 0x0100) && 7 == (type.t & 0x000f); | |
| islv &= c < 0; | |
| if (c != 1) { | |
| gen_cast(&type); | |
| if (islv) { | |
| mk_pointer(&vtop->type); | |
| gaddrof(); | |
| } else if (7 == (vtop->type.t & 0x000f)) | |
| gaddrof(); | |
| } | |
| rc = 0x0001; | |
| if (is_float(type.t)) { | |
| rc = 0x0002; | |
| if ((type.t & 0x000f) == 10) { | |
| rc = 0x0080; | |
| } | |
| } else if ((type.t & 0x000f) == 4) { | |
| rc = 0x0004; | |
| } | |
| tt = r2 = 0; | |
| if (c < 0) { | |
| r2 = gv(rc); | |
| tt = gjmp(0); | |
| } | |
| gsym(u); | |
| if (c != 0) { | |
| *vtop = sv; | |
| gen_cast(&type); | |
| if (islv) { | |
| mk_pointer(&vtop->type); | |
| gaddrof(); | |
| } else if (7 == (vtop->type.t & 0x000f)) | |
| gaddrof(); | |
| } | |
| if (c < 0) { | |
| r1 = gv(rc); | |
| move_reg(r2, r1, type.t); | |
| vtop->r = r2; | |
| gsym(tt); | |
| if (islv) | |
| indir(); | |
| } | |
| } | |
| } | |
| } | |
| static void expr_eq(void) | |
| { | |
| int t; | |
| expr_cond(); | |
| if (tok == '=' || | |
| (tok >= 0xa5 && tok <= 0xaf) || | |
| tok == 0xde || tok == 0xfc || | |
| tok == 0x81 || tok == 0x82) { | |
| test_lvalue(); | |
| t = tok; | |
| next(); | |
| if (t == '=') { | |
| expr_eq(); | |
| } else { | |
| vdup(); | |
| expr_eq(); | |
| gen_op(t & 0x7f); | |
| } | |
| vstore(); | |
| } | |
| } | |
| static void gexpr(void) | |
| { | |
| while (1) { | |
| expr_eq(); | |
| if (tok != ',') | |
| break; | |
| vpop(); | |
| next(); | |
| } | |
| } | |
| static void expr_const1(void) | |
| { | |
| const_wanted++; | |
| nocode_wanted++; | |
| expr_cond(); | |
| nocode_wanted--; | |
| const_wanted--; | |
| } | |
| static inline int64_t expr_const64(void) | |
| { | |
| int64_t c; | |
| expr_const1(); | |
| if ((vtop->r & (0x003f | 0x0100 | 0x0200)) != 0x0030) | |
| expect("constant expression"); | |
| c = vtop->c.i; | |
| vpop(); | |
| return c; | |
| } | |
| static int expr_const(void) | |
| { | |
| int c; | |
| int64_t wc = expr_const64(); | |
| c = wc; | |
| if (c != wc && (unsigned)c != wc) | |
| tcc_error("constant exceeds 32 bit"); | |
| return c; | |
| } | |
| static int is_label(void) | |
| { | |
| int last_tok; | |
| if (tok < TOK_DEFINE) | |
| return 0; | |
| last_tok = tok; | |
| next(); | |
| if (tok == ':') { | |
| return last_tok; | |
| } else { | |
| unget_tok(last_tok); | |
| return 0; | |
| } | |
| } | |
| static void gfunc_return(CType *func_type) | |
| { | |
| if ((func_type->t & 0x000f) == 7) { | |
| CType type, ret_type; | |
| int ret_align, ret_nregs, regsize; | |
| ret_nregs = gfunc_sret(func_type, func_var, &ret_type, | |
| &ret_align, ®size); | |
| if (0 == ret_nregs) { | |
| type = *func_type; | |
| mk_pointer(&type); | |
| vset(&type, 0x0032 | 0x0100, func_vc); | |
| indir(); | |
| vswap(); | |
| vstore(); | |
| } else { | |
| int r, size, addr, align; | |
| size = type_size(func_type,&align); | |
| if ((vtop->r != (0x0032 | 0x0100) || | |
| (vtop->c.i & (ret_align-1))) | |
| && (align & (ret_align-1))) { | |
| loc = (loc - size) & -ret_align; | |
| addr = loc; | |
| type = *func_type; | |
| vset(&type, 0x0032 | 0x0100, addr); | |
| vswap(); | |
| vstore(); | |
| vpop(); | |
| vset(&ret_type, 0x0032 | 0x0100, addr); | |
| } | |
| vtop->type = ret_type; | |
| if (is_float(ret_type.t)) | |
| r = rc_fret(ret_type.t); | |
| else | |
| r = 0x0004; | |
| if (ret_nregs == 1) | |
| gv(r); | |
| else { | |
| for (;;) { | |
| vdup(); | |
| gv(r); | |
| vpop(); | |
| if (--ret_nregs == 0) | |
| break; | |
| r <<= 1; | |
| vtop->c.i += regsize; | |
| } | |
| } | |
| } | |
| } else if (is_float(func_type->t)) { | |
| gv(rc_fret(func_type->t)); | |
| } else { | |
| gv(0x0004); | |
| } | |
| vtop--; | |
| } | |
| static int case_cmp(const void *pa, const void *pb) | |
| { | |
| int64_t a = (*(struct case_t**) pa)->v1; | |
| int64_t b = (*(struct case_t**) pb)->v1; | |
| return a < b ? -1 : a > b; | |
| } | |
| static void gcase(struct case_t **base, int len, int *bsym) | |
| { | |
| struct case_t *p; | |
| int e; | |
| int ll = (vtop->type.t & 0x000f) == 4; | |
| gv(0x0001); | |
| while (len > 4) { | |
| p = base[len/2]; | |
| vdup(); | |
| if (ll) | |
| vpushll(p->v2); | |
| else | |
| vpushi(p->v2); | |
| gen_op(0x9e); | |
| e = gtst(1, 0); | |
| vdup(); | |
| if (ll) | |
| vpushll(p->v1); | |
| else | |
| vpushi(p->v1); | |
| gen_op(0x9d); | |
| gtst_addr(0, p->sym); | |
| gcase(base, len/2, bsym); | |
| if (cur_switch->def_sym) | |
| gjmp_addr(cur_switch->def_sym); | |
| else | |
| *bsym = gjmp(*bsym); | |
| gsym(e); | |
| e = len/2 + 1; | |
| base += e; len -= e; | |
| } | |
| while (len--) { | |
| p = *base++; | |
| vdup(); | |
| if (ll) | |
| vpushll(p->v2); | |
| else | |
| vpushi(p->v2); | |
| if (p->v1 == p->v2) { | |
| gen_op(0x94); | |
| gtst_addr(0, p->sym); | |
| } else { | |
| gen_op(0x9e); | |
| e = gtst(1, 0); | |
| vdup(); | |
| if (ll) | |
| vpushll(p->v1); | |
| else | |
| vpushi(p->v1); | |
| gen_op(0x9d); | |
| gtst_addr(0, p->sym); | |
| gsym(e); | |
| } | |
| } | |
| } | |
| static void block(int *bsym, int *csym, int is_expr) | |
| { | |
| int a, b, c, d, cond; | |
| Sym *s; | |
| if (tcc_state->do_debug) | |
| tcc_debug_line(tcc_state); | |
| if (is_expr) { | |
| vpushi(0); | |
| vtop->type.t = 0; | |
| } | |
| if (tok == TOK_IF) { | |
| int saved_nocode_wanted = nocode_wanted; | |
| next(); | |
| skip('('); | |
| gexpr(); | |
| skip(')'); | |
| cond = condition_3way(); | |
| if (cond == 1) | |
| a = 0, vpop(); | |
| else | |
| a = gvtst(1, 0); | |
| if (cond == 0) | |
| nocode_wanted |= 0x20000000; | |
| block(bsym, csym, 0); | |
| if (cond != 1) | |
| nocode_wanted = saved_nocode_wanted; | |
| c = tok; | |
| if (c == TOK_ELSE) { | |
| next(); | |
| d = gjmp(0); | |
| gsym(a); | |
| if (cond == 1) | |
| nocode_wanted |= 0x20000000; | |
| block(bsym, csym, 0); | |
| gsym(d); | |
| if (cond != 0) | |
| nocode_wanted = saved_nocode_wanted; | |
| } else | |
| gsym(a); | |
| } else if (tok == TOK_WHILE) { | |
| int saved_nocode_wanted; | |
| nocode_wanted &= ~0x20000000; | |
| next(); | |
| d = ind; | |
| vla_sp_restore(); | |
| skip('('); | |
| gexpr(); | |
| skip(')'); | |
| a = gvtst(1, 0); | |
| b = 0; | |
| ++local_scope; | |
| saved_nocode_wanted = nocode_wanted; | |
| block(&a, &b, 0); | |
| nocode_wanted = saved_nocode_wanted; | |
| --local_scope; | |
| gjmp_addr(d); | |
| gsym(a); | |
| gsym_addr(b, d); | |
| } else if (tok == '{') { | |
| Sym *llabel; | |
| int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope; | |
| next(); | |
| s = local_stack; | |
| llabel = local_label_stack; | |
| ++local_scope; | |
| if (tok == TOK_LABEL) { | |
| next(); | |
| for(;;) { | |
| if (tok < TOK_DEFINE) | |
| expect("label identifier"); | |
| label_push(&local_label_stack, tok, 2); | |
| next(); | |
| if (tok == ',') { | |
| next(); | |
| } else { | |
| skip(';'); | |
| break; | |
| } | |
| } | |
| } | |
| while (tok != '}') { | |
| if ((a = is_label())) | |
| unget_tok(a); | |
| else | |
| decl(0x0032); | |
| if (tok != '}') { | |
| if (is_expr) | |
| vpop(); | |
| block(bsym, csym, is_expr); | |
| } | |
| } | |
| label_pop(&local_label_stack, llabel, is_expr); | |
| --local_scope; | |
| sym_pop(&local_stack, s, is_expr); | |
| if (vlas_in_scope > saved_vlas_in_scope) { | |
| vla_sp_loc = saved_vlas_in_scope ? block_vla_sp_loc : vla_sp_root_loc; | |
| vla_sp_restore(); | |
| } | |
| vlas_in_scope = saved_vlas_in_scope; | |
| next(); | |
| } else if (tok == TOK_RETURN) { | |
| next(); | |
| if (tok != ';') { | |
| gexpr(); | |
| gen_assign_cast(&func_vt); | |
| if ((func_vt.t & 0x000f) == 0) | |
| vtop--; | |
| else | |
| gfunc_return(&func_vt); | |
| } | |
| skip(';'); | |
| if (tok != '}' || local_scope != 1) | |
| rsym = gjmp(rsym); | |
| nocode_wanted |= 0x20000000; | |
| } else if (tok == TOK_BREAK) { | |
| if (!bsym) | |
| tcc_error("cannot break"); | |
| *bsym = gjmp(*bsym); | |
| next(); | |
| skip(';'); | |
| nocode_wanted |= 0x20000000; | |
| } else if (tok == TOK_CONTINUE) { | |
| if (!csym) | |
| tcc_error("cannot continue"); | |
| vla_sp_restore_root(); | |
| *csym = gjmp(*csym); | |
| next(); | |
| skip(';'); | |
| } else if (tok == TOK_FOR) { | |
| int e; | |
| int saved_nocode_wanted; | |
| nocode_wanted &= ~0x20000000; | |
| next(); | |
| skip('('); | |
| s = local_stack; | |
| ++local_scope; | |
| if (tok != ';') { | |
| if (!decl0(0x0032, 1, 0)) { | |
| gexpr(); | |
| vpop(); | |
| } | |
| } | |
| skip(';'); | |
| d = ind; | |
| c = ind; | |
| vla_sp_restore(); | |
| a = 0; | |
| b = 0; | |
| if (tok != ';') { | |
| gexpr(); | |
| a = gvtst(1, 0); | |
| } | |
| skip(';'); | |
| if (tok != ')') { | |
| e = gjmp(0); | |
| c = ind; | |
| vla_sp_restore(); | |
| gexpr(); | |
| vpop(); | |
| gjmp_addr(d); | |
| gsym(e); | |
| } | |
| skip(')'); | |
| saved_nocode_wanted = nocode_wanted; | |
| block(&a, &b, 0); | |
| nocode_wanted = saved_nocode_wanted; | |
| gjmp_addr(c); | |
| gsym(a); | |
| gsym_addr(b, c); | |
| --local_scope; | |
| sym_pop(&local_stack, s, 0); | |
| } else | |
| if (tok == TOK_DO) { | |
| int saved_nocode_wanted; | |
| nocode_wanted &= ~0x20000000; | |
| next(); | |
| a = 0; | |
| b = 0; | |
| d = ind; | |
| vla_sp_restore(); | |
| saved_nocode_wanted = nocode_wanted; | |
| block(&a, &b, 0); | |
| skip(TOK_WHILE); | |
| skip('('); | |
| gsym(b); | |
| gexpr(); | |
| c = gvtst(0, 0); | |
| gsym_addr(c, d); | |
| nocode_wanted = saved_nocode_wanted; | |
| skip(')'); | |
| gsym(a); | |
| skip(';'); | |
| } else | |
| if (tok == TOK_SWITCH) { | |
| struct switch_t *saved, sw; | |
| int saved_nocode_wanted = nocode_wanted; | |
| SValue switchval; | |
| next(); | |
| skip('('); | |
| gexpr(); | |
| skip(')'); | |
| switchval = *vtop--; | |
| a = 0; | |
| b = gjmp(0); | |
| sw.p = 0; sw.n = 0; sw.def_sym = 0; | |
| saved = cur_switch; | |
| cur_switch = &sw; | |
| block(&a, csym, 0); | |
| nocode_wanted = saved_nocode_wanted; | |
| a = gjmp(a); | |
| gsym(b); | |
| qsort(sw.p, sw.n, sizeof(void*), case_cmp); | |
| for (b = 1; b < sw.n; b++) | |
| if (sw.p[b - 1]->v2 >= sw.p[b]->v1) | |
| tcc_error("duplicate case value"); | |
| if ((switchval.type.t & 0x000f) == 4) | |
| switchval.type.t &= ~0x0010; | |
| vpushv(&switchval); | |
| gcase(sw.p, sw.n, &a); | |
| vpop(); | |
| if (sw.def_sym) | |
| gjmp_addr(sw.def_sym); | |
| dynarray_reset(&sw.p, &sw.n); | |
| cur_switch = saved; | |
| gsym(a); | |
| } else | |
| if (tok == TOK_CASE) { | |
| struct case_t *cr = tcc_malloc(sizeof(struct case_t)); | |
| if (!cur_switch) | |
| expect("switch"); | |
| nocode_wanted &= ~0x20000000; | |
| next(); | |
| cr->v1 = cr->v2 = expr_const64(); | |
| if (gnu_ext && tok == 0xc8) { | |
| next(); | |
| cr->v2 = expr_const64(); | |
| if (cr->v2 < cr->v1) | |
| tcc_warning("empty case range"); | |
| } | |
| cr->sym = ind; | |
| dynarray_add(&cur_switch->p, &cur_switch->n, cr); | |
| skip(':'); | |
| is_expr = 0; | |
| goto block_after_label; | |
| } else | |
| if (tok == TOK_DEFAULT) { | |
| next(); | |
| skip(':'); | |
| if (!cur_switch) | |
| expect("switch"); | |
| if (cur_switch->def_sym) | |
| tcc_error("too many 'default'"); | |
| cur_switch->def_sym = ind; | |
| is_expr = 0; | |
| goto block_after_label; | |
| } else | |
| if (tok == TOK_GOTO) { | |
| next(); | |
| if (tok == '*' && gnu_ext) { | |
| next(); | |
| gexpr(); | |
| if ((vtop->type.t & 0x000f) != 5) | |
| expect("pointer"); | |
| ggoto(); | |
| } else if (tok >= TOK_DEFINE) { | |
| s = label_find(tok); | |
| if (!s) { | |
| s = label_push(&global_label_stack, tok, 1); | |
| } else { | |
| if (s->r == 2) | |
| s->r = 1; | |
| } | |
| vla_sp_restore_root(); | |
| if (s->r & 1) | |
| s->jnext = gjmp(s->jnext); | |
| else | |
| gjmp_addr(s->jnext); | |
| next(); | |
| } else { | |
| expect("label identifier"); | |
| } | |
| skip(';'); | |
| } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { | |
| asm_instr(); | |
| } else { | |
| b = is_label(); | |
| if (b) { | |
| next(); | |
| s = label_find(b); | |
| if (s) { | |
| if (s->r == 0) | |
| tcc_error("duplicate label '%s'", get_tok_str(s->v, 0)); | |
| gsym(s->jnext); | |
| s->r = 0; | |
| } else { | |
| s = label_push(&global_label_stack, b, 0); | |
| } | |
| s->jnext = ind; | |
| vla_sp_restore(); | |
| block_after_label: | |
| nocode_wanted &= ~0x20000000; | |
| if (tok == '}') { | |
| tcc_warning("deprecated use of label at end of compound statement"); | |
| } else { | |
| if (is_expr) | |
| vpop(); | |
| block(bsym, csym, is_expr); | |
| } | |
| } else { | |
| if (tok != ';') { | |
| if (is_expr) { | |
| vpop(); | |
| gexpr(); | |
| } else { | |
| gexpr(); | |
| vpop(); | |
| } | |
| } | |
| skip(';'); | |
| } | |
| } | |
| } | |
| static void skip_or_save_block(TokenString **str) | |
| { | |
| int braces = tok == '{'; | |
| int level = 0; | |
| if (str) | |
| *str = tok_str_alloc(); | |
| while ((level > 0 || (tok != '}' && tok != ',' && tok != ';' && tok != ')'))) { | |
| int t; | |
| if (tok == (-1)) { | |
| if (str || level > 0) | |
| tcc_error("unexpected end of file"); | |
| else | |
| break; | |
| } | |
| if (str) | |
| tok_str_add_tok(*str); | |
| t = tok; | |
| next(); | |
| if (t == '{' || t == '(') { | |
| level++; | |
| } else if (t == '}' || t == ')') { | |
| level--; | |
| if (level == 0 && braces && t == '}') | |
| break; | |
| } | |
| } | |
| if (str) { | |
| tok_str_add(*str, -1); | |
| tok_str_add(*str, 0); | |
| } | |
| } | |
| static void parse_init_elem(int expr_type) | |
| { | |
| int saved_global_expr; | |
| switch(expr_type) { | |
| case 1: | |
| saved_global_expr = global_expr; | |
| global_expr = 1; | |
| expr_const1(); | |
| global_expr = saved_global_expr; | |
| if (((vtop->r & (0x003f | 0x0100)) != 0x0030 | |
| && ((vtop->r & (0x0200|0x0100)) != (0x0200|0x0100) | |
| || vtop->sym->v < 0x10000000)) | |
| ) | |
| tcc_error("initializer element is not constant"); | |
| break; | |
| case 2: | |
| expr_eq(); | |
| break; | |
| } | |
| } | |
| static void init_putz(Section *sec, unsigned long c, int size) | |
| { | |
| if (sec) { | |
| } else { | |
| vpush_global_sym(&func_old_type, TOK_memset); | |
| vseti(0x0032, c); | |
| vpushi(0); | |
| vpushs(size); | |
| gfunc_call(3); | |
| } | |
| } | |
| static int decl_designator(CType *type, Section *sec, unsigned long c, | |
| Sym **cur_field, int size_only, int al) | |
| { | |
| Sym *s, *f; | |
| int index, index_last, align, l, nb_elems, elem_size; | |
| unsigned long corig = c; | |
| elem_size = 0; | |
| nb_elems = 1; | |
| if (gnu_ext && (l = is_label()) != 0) | |
| goto struct_field; | |
| while (nb_elems == 1 && (tok == '[' || tok == '.')) { | |
| if (tok == '[') { | |
| if (!(type->t & 0x0040)) | |
| expect("array type"); | |
| next(); | |
| index = index_last = expr_const(); | |
| if (tok == 0xc8 && gnu_ext) { | |
| next(); | |
| index_last = expr_const(); | |
| } | |
| skip(']'); | |
| s = type->ref; | |
| if (index < 0 || (s->c >= 0 && index_last >= s->c) || | |
| index_last < index) | |
| tcc_error("invalid index"); | |
| if (cur_field) | |
| (*cur_field)->c = index_last; | |
| type = pointed_type(type); | |
| elem_size = type_size(type, &align); | |
| c += index * elem_size; | |
| nb_elems = index_last - index + 1; | |
| } else { | |
| next(); | |
| l = tok; | |
| struct_field: | |
| next(); | |
| if ((type->t & 0x000f) != 7) | |
| expect("struct/union type"); | |
| f = find_field(type, l); | |
| if (!f) | |
| expect("field"); | |
| if (cur_field) | |
| *cur_field = f; | |
| type = &f->type; | |
| c += f->c; | |
| } | |
| cur_field = 0; | |
| } | |
| if (!cur_field) { | |
| if (tok == '=') { | |
| next(); | |
| } else if (!gnu_ext) { | |
| expect("="); | |
| } | |
| } else { | |
| if (type->t & 0x0040) { | |
| index = (*cur_field)->c; | |
| if (type->ref->c >= 0 && index >= type->ref->c) | |
| tcc_error("index too large"); | |
| type = pointed_type(type); | |
| c += index * type_size(type, &align); | |
| } else { | |
| f = *cur_field; | |
| while (f && (f->v & 0x10000000) && (f->type.t & 0x0080)) | |
| *cur_field = f = f->next; | |
| if (!f) | |
| tcc_error("too many field init"); | |
| type = &f->type; | |
| c += f->c; | |
| } | |
| } | |
| if (!size_only && c - corig > al) | |
| init_putz(sec, corig + al, c - corig - al); | |
| decl_initializer(type, sec, c, 0, size_only); | |
| if (!size_only && nb_elems > 1) { | |
| unsigned long c_end; | |
| uint8_t *src, *dst; | |
| int i; | |
| if (!sec) { | |
| vset(type, 0x0032|0x0100, c); | |
| for (i = 1; i < nb_elems; i++) { | |
| vset(type, 0x0032|0x0100, c + elem_size * i); | |
| vswap(); | |
| vstore(); | |
| } | |
| vpop(); | |
| } else if (!(nocode_wanted > 0)) { | |
| c_end = c + nb_elems * elem_size; | |
| if (c_end > sec->data_allocated) | |
| section_realloc(sec, c_end); | |
| src = sec->data + c; | |
| dst = src; | |
| for(i = 1; i < nb_elems; i++) { | |
| dst += elem_size; | |
| memcpy(dst, src, elem_size); | |
| } | |
| } | |
| } | |
| c += nb_elems * type_size(type, &align); | |
| if (c - corig > al) | |
| al = c - corig; | |
| return al; | |
| } | |
| static void init_putv(CType *type, Section *sec, unsigned long c) | |
| { | |
| int bt; | |
| void *ptr; | |
| CType dtype; | |
| dtype = *type; | |
| dtype.t &= ~0x0100; | |
| if (sec) { | |
| int size, align; | |
| gen_assign_cast(&dtype); | |
| bt = type->t & 0x000f; | |
| if ((vtop->r & 0x0200) | |
| && bt != 5 | |
| && bt != 6 | |
| && (bt != (8 == 8 ? 4 : 3) | |
| || (type->t & 0x0080)) | |
| && !((vtop->r & 0x0030) && vtop->sym->v >= 0x10000000) | |
| ) | |
| tcc_error("initializer element is not computable at load time"); | |
| if ((nocode_wanted > 0)) { | |
| vtop--; | |
| return; | |
| } | |
| size = type_size(type, &align); | |
| section_reserve(sec, c + size); | |
| ptr = sec->data + c; | |
| if ((vtop->r & (0x0200|0x0030)) == (0x0200|0x0030) && | |
| vtop->sym->v >= 0x10000000 && | |
| # 6488 "tccgen.c" | |
| (vtop->type.t & 0x000f) != 5) { | |
| Section *ssec; | |
| Elf64_Sym *esym; | |
| Elf64_Rela *rel; | |
| esym = elfsym(vtop->sym); | |
| ssec = tcc_state->sections[esym->st_shndx]; | |
| memmove (ptr, ssec->data + esym->st_value, size); | |
| if (ssec->reloc) { | |
| int num_relocs = ssec->reloc->data_offset / sizeof(*rel); | |
| rel = (Elf64_Rela*)(ssec->reloc->data + ssec->reloc->data_offset); | |
| while (num_relocs--) { | |
| rel--; | |
| if (rel->r_offset >= esym->st_value + size) | |
| continue; | |
| if (rel->r_offset < esym->st_value) | |
| break; | |
| put_elf_reloca(symtab_section, sec, | |
| c + rel->r_offset - esym->st_value, | |
| ((rel->r_info) & 0xffffffff), | |
| ((rel->r_info) >> 32), | |
| rel->r_addend | |
| ); | |
| } | |
| } | |
| } else { | |
| if (type->t & 0x0080) { | |
| int bit_pos, bit_size, bits, n; | |
| unsigned char *p, v, m; | |
| bit_pos = (((vtop->type.t) >> 20) & 0x3f); | |
| bit_size = (((vtop->type.t) >> (20 + 6)) & 0x3f); | |
| p = (unsigned char*)ptr + (bit_pos >> 3); | |
| bit_pos &= 7, bits = 0; | |
| while (bit_size) { | |
| n = 8 - bit_pos; | |
| if (n > bit_size) | |
| n = bit_size; | |
| v = vtop->c.i >> bits << bit_pos; | |
| m = ((1 << n) - 1) << bit_pos; | |
| *p = (*p & ~m) | (v & m); | |
| bits += n, bit_size -= n, bit_pos = 0, ++p; | |
| } | |
| } else | |
| switch(bt) { | |
| case 11: | |
| vtop->c.i = vtop->c.i != 0; | |
| case 1: | |
| *(char *)ptr |= vtop->c.i; | |
| break; | |
| case 2: | |
| *(short *)ptr |= vtop->c.i; | |
| break; | |
| case 8: | |
| *(float*)ptr = vtop->c.f; | |
| break; | |
| case 9: | |
| *(double *)ptr = vtop->c.d; | |
| break; | |
| case 10: | |
| if (sizeof (long double) >= 10) | |
| memcpy(ptr, &vtop->c.ld, 10); | |
| else if (vtop->c.ld == 0.0) | |
| ; | |
| else | |
| if (sizeof(long double) == 16) | |
| *(long double*)ptr = vtop->c.ld; | |
| else if (sizeof(double) == 16) | |
| *(double *)ptr = (double)vtop->c.ld; | |
| else | |
| tcc_error("can't cross compile long double constants"); | |
| break; | |
| case 4: | |
| case 5: | |
| { | |
| Elf64_Addr val = vtop->c.i; | |
| if (vtop->r & 0x0200) | |
| greloca(sec, vtop->sym, c, 1, val); | |
| else | |
| *(Elf64_Addr *)ptr |= val; | |
| break; | |
| } | |
| default: | |
| { | |
| int val = vtop->c.i; | |
| if (vtop->r & 0x0200) | |
| greloca(sec, vtop->sym, c, 1, val); | |
| else | |
| *(int *)ptr |= val; | |
| break; | |
| } | |
| } | |
| } | |
| vtop--; | |
| } else { | |
| vset(&dtype, 0x0032|0x0100, c); | |
| vswap(); | |
| vstore(); | |
| vpop(); | |
| } | |
| } | |
| static void decl_initializer(CType *type, Section *sec, unsigned long c, | |
| int first, int size_only) | |
| { | |
| int len, n, no_oblock, nb, i; | |
| int size1, align1; | |
| int have_elem; | |
| Sym *s, *f; | |
| Sym indexsym; | |
| CType *t1; | |
| have_elem = tok == '}' || tok == ','; | |
| if (!have_elem && tok != '{' && | |
| tok != 0xba && tok != 0xb9 && | |
| !size_only) { | |
| parse_init_elem(!sec ? 2 : 1); | |
| have_elem = 1; | |
| } | |
| if (have_elem && | |
| !(type->t & 0x0040) && | |
| is_compatible_unqualified_types(type, &vtop->type)) { | |
| init_putv(type, sec, c); | |
| } else if (type->t & 0x0040) { | |
| s = type->ref; | |
| n = s->c; | |
| t1 = pointed_type(type); | |
| size1 = type_size(t1, &align1); | |
| no_oblock = 1; | |
| if ((first && tok != 0xba && tok != 0xb9) || | |
| tok == '{') { | |
| if (tok != '{') | |
| tcc_error("character array initializer must be a literal," | |
| " optionally enclosed in braces"); | |
| skip('{'); | |
| no_oblock = 0; | |
| } | |
| if ((tok == 0xba && | |
| (t1->t & 0x000f) == 3 | |
| ) || (tok == 0xb9 && (t1->t & 0x000f) == 1)) { | |
| len = 0; | |
| while (tok == 0xb9 || tok == 0xba) { | |
| int cstr_len, ch; | |
| if (tok == 0xb9) | |
| cstr_len = tokc.str.size; | |
| else | |
| cstr_len = tokc.str.size / sizeof(nwchar_t); | |
| cstr_len--; | |
| nb = cstr_len; | |
| if (n >= 0 && nb > (n - len)) | |
| nb = n - len; | |
| if (!size_only) { | |
| if (cstr_len > nb) | |
| tcc_warning("initializer-string for array is too long"); | |
| if (sec && tok == 0xb9 && size1 == 1) { | |
| if (!(nocode_wanted > 0)) | |
| memcpy(sec->data + c + len, tokc.str.data, nb); | |
| } else { | |
| for(i=0;i<nb;i++) { | |
| if (tok == 0xb9) | |
| ch = ((unsigned char *)tokc.str.data)[i]; | |
| else | |
| ch = ((nwchar_t *)tokc.str.data)[i]; | |
| vpushi(ch); | |
| init_putv(t1, sec, c + (len + i) * size1); | |
| } | |
| } | |
| } | |
| len += nb; | |
| next(); | |
| } | |
| if (n < 0 || len < n) { | |
| if (!size_only) { | |
| vpushi(0); | |
| init_putv(t1, sec, c + (len * size1)); | |
| } | |
| len++; | |
| } | |
| len *= size1; | |
| } else { | |
| indexsym.c = 0; | |
| f = &indexsym; | |
| do_init_list: | |
| len = 0; | |
| while (tok != '}' || have_elem) { | |
| len = decl_designator(type, sec, c, &f, size_only, len); | |
| have_elem = 0; | |
| if (type->t & 0x0040) { | |
| ++indexsym.c; | |
| if (no_oblock && len >= n*size1) | |
| break; | |
| } else { | |
| if (s->type.t == (1 << 20 | 7)) | |
| f = 0; | |
| else | |
| f = f->next; | |
| if (no_oblock && f == 0) | |
| break; | |
| } | |
| if (tok == '}') | |
| break; | |
| skip(','); | |
| } | |
| } | |
| if (!size_only && len < n*size1) | |
| init_putz(sec, c + len, n*size1 - len); | |
| if (!no_oblock) | |
| skip('}'); | |
| if (n < 0) | |
| s->c = size1 == 1 ? len : ((len + size1 - 1)/size1); | |
| } else if ((type->t & 0x000f) == 7) { | |
| size1 = 1; | |
| no_oblock = 1; | |
| if (first || tok == '{') { | |
| skip('{'); | |
| no_oblock = 0; | |
| } | |
| s = type->ref; | |
| f = s->next; | |
| n = s->c; | |
| goto do_init_list; | |
| } else if (tok == '{') { | |
| next(); | |
| decl_initializer(type, sec, c, first, size_only); | |
| skip('}'); | |
| } else if (size_only) { | |
| skip_or_save_block(0); | |
| } else { | |
| if (!have_elem) { | |
| if (tok != 0xb9 && tok != 0xba) | |
| expect("string constant"); | |
| parse_init_elem(!sec ? 2 : 1); | |
| } | |
| init_putv(type, sec, c); | |
| } | |
| } | |
| # 6818 "tccgen.c" | |
| static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, | |
| int has_init, int v, int scope) | |
| { | |
| int size, align, addr; | |
| TokenString *init_str = 0; | |
| Section *sec; | |
| Sym *flexible_array; | |
| Sym *sym = 0; | |
| int saved_nocode_wanted = nocode_wanted; | |
| int bcheck = tcc_state->do_bounds_check && !(nocode_wanted > 0); | |
| if (type->t & 0x00002000) | |
| nocode_wanted |= (nocode_wanted > 0) ? 0x40000000 : 0x80000000; | |
| flexible_array = 0; | |
| if ((type->t & 0x000f) == 7) { | |
| Sym *field = type->ref->next; | |
| if (field) { | |
| while (field->next) | |
| field = field->next; | |
| if (field->type.t & 0x0040 && field->type.ref->c < 0) | |
| flexible_array = field; | |
| } | |
| } | |
| size = type_size(type, &align); | |
| if (size < 0 || (flexible_array && has_init)) { | |
| if (!has_init) | |
| tcc_error("unknown type size"); | |
| if (has_init == 2) { | |
| init_str = tok_str_alloc(); | |
| while (tok == 0xb9 || tok == 0xba) { | |
| tok_str_add_tok(init_str); | |
| next(); | |
| } | |
| tok_str_add(init_str, -1); | |
| tok_str_add(init_str, 0); | |
| } else { | |
| skip_or_save_block(&init_str); | |
| } | |
| unget_tok(0); | |
| begin_macro(init_str, 1); | |
| next(); | |
| decl_initializer(type, 0, 0, 1, 1); | |
| macro_ptr = init_str->str; | |
| next(); | |
| size = type_size(type, &align); | |
| if (size < 0) | |
| tcc_error("unknown type size"); | |
| } | |
| if (flexible_array && | |
| flexible_array->type.ref->c > 0) | |
| size += flexible_array->type.ref->c | |
| * pointed_size(&flexible_array->type); | |
| if (ad->a.aligned) { | |
| int speca = 1 << (ad->a.aligned - 1); | |
| if (speca > align) | |
| align = speca; | |
| } else if (ad->a.packed) { | |
| align = 1; | |
| } | |
| if ((nocode_wanted > 0)) | |
| size = 0, align = 1; | |
| if ((r & 0x003f) == 0x0032) { | |
| sec = 0; | |
| if (bcheck && (type->t & 0x0040)) { | |
| loc--; | |
| } | |
| loc = (loc - size) & -align; | |
| addr = loc; | |
| if (bcheck && (type->t & 0x0040)) { | |
| Elf64_Addr *bounds_ptr; | |
| loc--; | |
| bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(Elf64_Addr)); | |
| bounds_ptr[0] = addr; | |
| bounds_ptr[1] = size; | |
| } | |
| if (v) { | |
| if (ad->asm_label) { | |
| int reg = asm_parse_regvar(ad->asm_label); | |
| if (reg >= 0) | |
| r = (r & ~0x003f) | reg; | |
| } | |
| sym = sym_push(v, type, r, addr); | |
| sym->a = ad->a; | |
| } else { | |
| vset(type, r, addr); | |
| } | |
| } else { | |
| if (v && scope == 0x0030) { | |
| sym = sym_find(v); | |
| if (sym) { | |
| patch_storage(sym, ad, type); | |
| if (!has_init && sym->c && elfsym(sym)->st_shndx != 0) | |
| goto no_alloc; | |
| } | |
| } | |
| sec = ad->section; | |
| if (!sec) { | |
| if (has_init) | |
| sec = data_section; | |
| else if (tcc_state->nocommon) | |
| sec = bss_section; | |
| } | |
| if (sec) { | |
| addr = section_add(sec, size, align); | |
| if (bcheck) | |
| section_add(sec, 1, 1); | |
| } else { | |
| addr = align; | |
| sec = common_section; | |
| } | |
| if (v) { | |
| if (!sym) { | |
| sym = sym_push(v, type, r | 0x0200, 0); | |
| patch_storage(sym, ad, 0); | |
| } | |
| sym->sym_scope = 0; | |
| put_extern_sym(sym, sec, addr, size); | |
| } else { | |
| sym = get_sym_ref(type, sec, addr, size); | |
| vpushsym(type, sym); | |
| vtop->r |= r; | |
| } | |
| if (bcheck) { | |
| Elf64_Addr *bounds_ptr; | |
| greloca(bounds_section, sym, bounds_section->data_offset, 1, 0); | |
| bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(Elf64_Addr)); | |
| bounds_ptr[0] = 0; | |
| bounds_ptr[1] = size; | |
| } | |
| } | |
| if (type->t & 0x0400) { | |
| int a; | |
| if ((nocode_wanted > 0)) | |
| goto no_alloc; | |
| if (vlas_in_scope == 0) { | |
| if (vla_sp_root_loc == -1) | |
| vla_sp_root_loc = (loc -= 8); | |
| gen_vla_sp_save(vla_sp_root_loc); | |
| } | |
| vla_runtime_type_size(type, &a); | |
| gen_vla_alloc(type, a); | |
| gen_vla_sp_save(addr); | |
| vla_sp_loc = addr; | |
| vlas_in_scope++; | |
| } else if (has_init) { | |
| size_t oldreloc_offset = 0; | |
| if (sec && sec->reloc) | |
| oldreloc_offset = sec->reloc->data_offset; | |
| decl_initializer(type, sec, addr, 1, 0); | |
| if (sec && sec->reloc) | |
| squeeze_multi_relocs(sec, oldreloc_offset); | |
| if (flexible_array) | |
| flexible_array->type.ref->c = -1; | |
| } | |
| no_alloc: | |
| if (init_str) { | |
| end_macro(); | |
| next(); | |
| } | |
| nocode_wanted = saved_nocode_wanted; | |
| } | |
| static void gen_function(Sym *sym) | |
| { | |
| nocode_wanted = 0; | |
| ind = cur_text_section->data_offset; | |
| put_extern_sym(sym, cur_text_section, ind, 0); | |
| funcname = get_tok_str(sym->v, 0); | |
| func_ind = ind; | |
| vla_sp_loc = -1; | |
| vla_sp_root_loc = -1; | |
| tcc_debug_funcstart(tcc_state, sym); | |
| sym_push2(&local_stack, 0x20000000, 0, 0); | |
| local_scope = 1; | |
| gfunc_prolog(&sym->type); | |
| local_scope = 0; | |
| rsym = 0; | |
| block(0, 0, 0); | |
| nocode_wanted = 0; | |
| gsym(rsym); | |
| gfunc_epilog(); | |
| cur_text_section->data_offset = ind; | |
| label_pop(&global_label_stack, 0, 0); | |
| local_scope = 0; | |
| sym_pop(&local_stack, 0, 0); | |
| elfsym(sym)->st_size = ind - func_ind; | |
| tcc_debug_funcend(tcc_state, ind - func_ind); | |
| cur_text_section = 0; | |
| funcname = ""; | |
| func_vt.t = 0; | |
| func_var = 0; | |
| ind = 0; | |
| nocode_wanted = 0x80000000; | |
| check_vstack(); | |
| } | |
| static void gen_inline_functions(TCCState *s) | |
| { | |
| Sym *sym; | |
| int inline_generated, i, ln; | |
| struct InlineFunc *fn; | |
| ln = file->line_num; | |
| do { | |
| inline_generated = 0; | |
| for (i = 0; i < s->nb_inline_fns; ++i) { | |
| fn = s->inline_fns[i]; | |
| sym = fn->sym; | |
| if (sym && sym->c) { | |
| fn->sym = 0; | |
| if (file) | |
| pstrcpy(file->filename, sizeof file->filename, fn->filename); | |
| sym->type.t &= ~0x00008000; | |
| begin_macro(fn->func_str, 1); | |
| next(); | |
| cur_text_section = text_section; | |
| gen_function(sym); | |
| end_macro(); | |
| inline_generated = 1; | |
| } | |
| } | |
| } while (inline_generated); | |
| file->line_num = ln; | |
| } | |
| static void free_inline_functions(TCCState *s) | |
| { | |
| int i; | |
| for (i = 0; i < s->nb_inline_fns; ++i) { | |
| struct InlineFunc *fn = s->inline_fns[i]; | |
| if (fn->sym) | |
| tok_str_free(fn->func_str); | |
| } | |
| dynarray_reset(&s->inline_fns, &s->nb_inline_fns); | |
| } | |
| static int decl0(int l, int is_for_loop_init, Sym *func_sym) | |
| { | |
| int v, has_init, r; | |
| CType type, btype; | |
| Sym *sym; | |
| AttributeDef ad; | |
| while (1) { | |
| if (!parse_btype(&btype, &ad)) { | |
| if (is_for_loop_init) | |
| return 0; | |
| if (tok == ';' && l != 0x0033) { | |
| next(); | |
| continue; | |
| } | |
| if (l != 0x0030) | |
| break; | |
| if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { | |
| asm_global_instr(); | |
| continue; | |
| } | |
| if (tok >= TOK_DEFINE) { | |
| btype.t = 3; | |
| } else { | |
| if (tok != (-1)) | |
| expect("declaration"); | |
| break; | |
| } | |
| } | |
| if (tok == ';') { | |
| if ((btype.t & 0x000f) == 7) { | |
| int v = btype.ref->v; | |
| if (!(v & 0x20000000) && (v & ~0x40000000) >= 0x10000000) | |
| tcc_warning("unnamed struct/union that defines no instances"); | |
| next(); | |
| continue; | |
| } | |
| if (((btype.t & (((1 << (6+6)) - 1) << 20 | 0x0080)) == (2 << 20))) { | |
| next(); | |
| continue; | |
| } | |
| } | |
| while (1) { | |
| type = btype; | |
| if ((type.t & 0x0040) && type.ref->c < 0) { | |
| type.ref = sym_push(0x20000000, &type.ref->type, 0, type.ref->c); | |
| } | |
| type_decl(&type, &ad, &v, 2); | |
| if ((type.t & 0x000f) == 6) { | |
| if ((type.t & 0x00002000) && (l == 0x0032)) { | |
| tcc_error("function without file scope cannot be static"); | |
| } | |
| sym = type.ref; | |
| if (sym->f.func_type == 2 && l == 0x0030) | |
| decl0(0x0033, 0, sym); | |
| } | |
| if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { | |
| ad.asm_label = asm_label_instr(); | |
| parse_attribute(&ad); | |
| if (tok == '{') | |
| expect(";"); | |
| } | |
| # 7239 "tccgen.c" | |
| if (tok == '{') { | |
| if (l != 0x0030) | |
| tcc_error("cannot use local functions"); | |
| if ((type.t & 0x000f) != 6) | |
| expect("function definition"); | |
| sym = type.ref; | |
| while ((sym = sym->next) != 0) { | |
| if (!(sym->v & ~0x20000000)) | |
| expect("identifier"); | |
| if (sym->type.t == 0) | |
| sym->type = int_type; | |
| } | |
| if ((type.t & (0x00001000 | 0x00008000)) == (0x00001000 | 0x00008000)) | |
| type.t = (type.t & ~0x00001000) | 0x00002000; | |
| sym = external_global_sym(v, &type, 0); | |
| type.t &= ~0x00001000; | |
| patch_storage(sym, &ad, &type); | |
| if ((type.t & (0x00008000 | 0x00002000)) == | |
| (0x00008000 | 0x00002000)) { | |
| struct InlineFunc *fn; | |
| const char *filename; | |
| filename = file ? file->filename : ""; | |
| fn = tcc_malloc(sizeof *fn + strlen(filename)); | |
| strcpy(fn->filename, filename); | |
| fn->sym = sym; | |
| skip_or_save_block(&fn->func_str); | |
| dynarray_add(&tcc_state->inline_fns, | |
| &tcc_state->nb_inline_fns, fn); | |
| } else { | |
| cur_text_section = ad.section; | |
| if (!cur_text_section) | |
| cur_text_section = text_section; | |
| gen_function(sym); | |
| } | |
| break; | |
| } else { | |
| if (l == 0x0033) { | |
| for (sym = func_sym->next; sym; sym = sym->next) | |
| if ((sym->v & ~0x20000000) == v) | |
| goto found; | |
| tcc_error("declaration for parameter '%s' but no such parameter", | |
| get_tok_str(v, 0)); | |
| found: | |
| if (type.t & (0x00001000 | 0x00002000 | 0x00004000 | 0x00008000)) | |
| tcc_error("storage class specified for '%s'", | |
| get_tok_str(v, 0)); | |
| if (sym->type.t != 0) | |
| tcc_error("redefinition of parameter '%s'", | |
| get_tok_str(v, 0)); | |
| convert_parameter_type(&type); | |
| sym->type = type; | |
| } else if (type.t & 0x00004000) { | |
| sym = sym_find(v); | |
| if (sym && sym->sym_scope == local_scope) { | |
| if (!is_compatible_types(&sym->type, &type) | |
| || !(sym->type.t & 0x00004000)) | |
| tcc_error("incompatible redefinition of '%s'", | |
| get_tok_str(v, 0)); | |
| sym->type = type; | |
| } else { | |
| sym = sym_push(v, &type, 0, 0); | |
| } | |
| sym->a = ad.a; | |
| sym->f = ad.f; | |
| } else { | |
| r = 0; | |
| if ((type.t & 0x000f) == 6) { | |
| type.ref->f = ad.f; | |
| } else if (!(type.t & 0x0040)) { | |
| r |= lvalue_type(type.t); | |
| } | |
| has_init = (tok == '='); | |
| if (has_init && (type.t & 0x0400)) | |
| tcc_error("variable length array cannot be initialized"); | |
| if (((type.t & 0x00001000) && (!has_init || l != 0x0030)) || | |
| ((type.t & 0x000f) == 6) || | |
| ((type.t & 0x0040) && (type.t & 0x00002000) && | |
| !has_init && l == 0x0030 && type.ref->c < 0)) { | |
| type.t |= 0x00001000; | |
| sym = external_sym(v, &type, r, &ad); | |
| if (ad.alias_target) { | |
| Elf64_Sym *esym; | |
| Sym *alias_target; | |
| alias_target = sym_find(ad.alias_target); | |
| esym = elfsym(alias_target); | |
| if (!esym) | |
| tcc_error("unsupported forward __alias__ attribute"); | |
| sym->sym_scope = 0; | |
| put_extern_sym2(sym, esym->st_shndx, esym->st_value, esym->st_size, 0); | |
| } | |
| } else { | |
| if (type.t & 0x00002000) | |
| r |= 0x0030; | |
| else | |
| r |= l; | |
| if (has_init) | |
| next(); | |
| else if (l == 0x0030) | |
| type.t |= 0x00001000; | |
| decl_initializer_alloc(&type, &ad, r, has_init, v, l); | |
| } | |
| } | |
| if (tok != ',') { | |
| if (is_for_loop_init) | |
| return 1; | |
| skip(';'); | |
| break; | |
| } | |
| next(); | |
| } | |
| ad.a.aligned = 0; | |
| } | |
| } | |
| return 0; | |
| } | |
| static void decl(int l) | |
| { | |
| decl0(l, 0, 0); | |
| } |