| # 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); |
| } |