/* * Copyright (C) 2012-2019 Free Software Foundation, Inc. * * This file is part of GNU lightning. * * GNU lightning is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 3, or (at your option) * any later version. * * GNU lightning is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Authors: * Paulo Cesar Pereira de Andrade */ #if HAVE_CONFIG_H # include "config.h" #endif #if HAVE_GETOPT_H # include #else # include #endif #include #include #include #include #if defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) # include #endif /* The label_t identifier clashes with a system definitions */ #if defined(_AIX) || defined(__sun__) || defined(__osf__) # define label_t l_label_t #endif #if defined(__hpux) # define DL_HANDLE RTLD_NEXT #elif defined(__sgi) static void *DL_HANDLE; #elif defined(__osf__) # define DL_HANDLE NULL #else # define DL_HANDLE RTLD_DEFAULT #endif #if defined(__GNUC__) # define noreturn __attribute__ ((noreturn)) # define printf_format(f, v) __attribute__ ((format (printf, f, v))) # define maybe_unused __attribute__ ((unused)) #else # define noreturn /**/ # define printf_format(f, v) /**/ # define maybe_unused /**/ #endif #define check_data(length) \ do { \ if (data_offset + length > data_length) \ error(".data too small (%ld < %ld)", \ data_length, data_offset + length); \ } while (0) #define get_label_by_name(name) ((label_t *)get_hash(labels, name)) #define PARSING_NONE 0 #define PARSING_DATA 1 #define PARSING_CODE 2 #define MAX_IDENTIFIER 256 /* * Types */ typedef struct instr instr_t; typedef union value value_t; typedef struct parser parser_t; typedef struct label label_t; typedef struct patch patch_t; typedef struct symbol symbol_t; typedef struct hash hash_t; typedef struct entry entry_t; typedef int (*function_t)(int argc, char *argv[]); typedef enum { tok_eof = -1, tok_symbol, tok_char, tok_int, tok_float, tok_pointer, tok_string, tok_register, tok_dot, tok_newline, tok_semicollon, } token_t; typedef enum { skip_none, skip_ws, skip_nl, } skip_t; typedef enum { type_none, type_c, type_s, type_i, type_l, type_f, type_d, type_p, } type_t; #define compose(a, b) (((a) << 8) | b) typedef enum { expr_inc = compose('+', '+'), expr_dec = compose('-', '-'), expr_not = '!', expr_com = '~', expr_mul = '*', expr_div = '/', expr_rem = '%', expr_add = '+', expr_sub = '-', expr_lsh = compose('<', '<'), expr_rsh = compose('>', '>'), expr_and = '&', expr_or = '|', expr_xor = '^', expr_set = '=', expr_mulset = compose('*', '='), expr_divset = compose('/', '='), expr_remset = compose('%', '='), expr_addset = compose('+', '='), expr_subset = compose('-', '='), expr_lshset = compose(expr_lsh, '='), expr_rshset = compose(expr_rsh, '='), expr_andset = compose('&', '='), expr_orset = compose('|', '='), expr_xorset = compose('^', '='), expr_lt = '<', expr_le = compose('<', '='), expr_eq = compose('=', '='), expr_ne = compose('!', '='), expr_gt = '>', expr_ge = compose('>', '='), expr_andand = compose('&', '&'), expr_oror = compose('|', '|'), expr_lparen = '(', expr_rparen = ')', expr_int = '0', expr_float = '.', expr_pointer = '@', expr_symbol = '$', } expr_t; #undef compose struct instr { instr_t *next; const char *name; void (*function)(void); int flag; }; union value { jit_word_t i; jit_uword_t ui; float f; double d; void *p; char *cp; label_t *label; patch_t *patch; }; struct parser { FILE *fp; char name[256]; int line; int regval; type_t regtype; expr_t expr; type_t type; value_t value; /* variable length string buffer */ char *string; int length; int offset; int newline; expr_t putback; int short_circuit; int parsing; struct { unsigned char buffer[4096]; int offset; int length; } data; }; typedef enum { label_kind_data, label_kind_code, label_kind_code_forward, label_kind_dynamic, } label_kind_t; struct hash { entry_t **entries; int size; int count; }; struct entry { entry_t *next; char *name; void *value; int flag; }; struct label { label_t *next; char *name; void *value; label_kind_t kind; }; typedef enum { patch_kind_jmp, patch_kind_mov, patch_kind_call, } patch_kind_t; struct patch { patch_t *next; label_t *label; void *value; patch_kind_t kind; }; /* minor support for expressions */ struct symbol { symbol_t *next; char *name; value_t value; type_t type; }; /* * Prototypes */ static jit_gpr_t get_ireg(void); static jit_fpr_t get_freg(void); static symbol_t *get_symbol(void); static void jmp_forward(void *value, label_t *label); static void mov_forward(void *value, label_t *label); static void call_forward(void *value, label_t *label); static void make_arg(void *value); static jit_pointer_t get_arg(void); static jit_word_t get_imm(void); static void live(void); static void align(void); static void name(void); static void prolog(void); static void frame(void); static void tramp(void); static void ellipsis(void); static void allocai(void); static void allocar(void); static void arg(void); static void getarg_c(void); static void getarg_uc(void); static void getarg_s(void); static void getarg_us(void); static void getarg_i(void); #if __WORDSIZE == 64 static void getarg_ui(void); static void getarg_l(void); #endif static void getarg(void); static void putargr(void); static void putargi(void); static void addr(void); static void addi(void); static void addxr(void); static void addxi(void); static void addcr(void); static void addci(void); static void subr(void); static void subi(void); static void subxr(void); static void subxi(void); static void subcr(void); static void subci(void); static void rsbr(void); static void rsbi(void); static void mulr(void); static void muli(void); static void qmulr(void); static void qmuli(void); static void qmulr_u(void); static void qmuli_u(void); static void divr(void); static void divi(void); static void divr_u(void); static void divi_u(void); static void qdivr(void); static void qdivi(void); static void qdivr_u(void); static void qdivi_u(void); static void remr(void); static void remi(void); static void remr_u(void); static void remi_u(void); static void andr(void); static void andi(void); static void orr(void); static void ori(void); static void xorr(void); static void xori(void); static void lshr(void); static void lshi(void); static void rshr(void); static void rshi(void); static void rshr_u(void); static void rshi_u(void); static void negr(void); static void comr(void); static void ltr(void); static void lti(void); static void ltr_u(void); static void lti_u(void); static void ler(void); static void lei(void); static void ler_u(void); static void lei_u(void); static void eqr(void); static void eqi(void); static void ger(void); static void gei(void); static void ger_u(void); static void gei_u(void); static void gtr(void); static void gti(void); static void gtr_u(void); static void gti_u(void); static void ner(void); static void nei(void); static void movr(void); static void movi(void); static void extr_c(void); static void extr_uc(void); static void extr_s(void); static void extr_us(void); #if __WORDSIZE == 64 static void extr_i(void); static void extr_ui(void); #endif static void htonr_us(void); static void ntohr_us(void); static void htonr_ui(void); static void ntohr_ui(void); #if __WORDSIZE == 64 static void htonr_ul(void); static void ntohr_ul(void); #endif static void htonr(void); static void ntohr(void); static void ldr_c(void); static void ldi_c(void); static void ldr_uc(void); static void ldi_uc(void); static void ldr_s(void); static void ldi_s(void); static void ldr_us(void); static void ldi_us(void); static void ldr_i(void); static void ldi_i(void); #if __WORDSIZE == 64 static void ldr_ui(void); static void ldi_ui(void); static void ldr_l(void); static void ldi_l(void); #endif static void ldr(void); static void ldi(void); static void ldxr_c(void); static void ldxi_c(void); static void ldxr_uc(void); static void ldxi_uc(void); static void ldxr_s(void); static void ldxi_s(void); static void ldxr_us(void); static void ldxi_us(void); static void ldxr_i(void); static void ldxi_i(void); #if __WORDSIZE == 64 static void ldxr_ui(void); static void ldxi_ui(void); static void ldxr_l(void); static void ldxi_l(void); #endif static void ldxr(void); static void ldxi(void); static void str_c(void); static void sti_c(void); static void str_s(void); static void sti_s(void); static void str_i(void); static void sti_i(void); #if __WORDSIZE == 64 static void str_l(void); static void sti_l(void); #endif static void str(void); static void sti(void); static void stxr_c(void); static void stxi_c(void); static void stxr_s(void); static void stxi_s(void); static void stxr_i(void); static void stxi_i(void); #if __WORDSIZE == 64 static void stxr_l(void); static void stxi_l(void); #endif static void stxr(void); static void stxi(void); static void bltr(void); static void blti(void); static void bltr_u(void); static void blti_u(void); static void bler(void); static void blei(void); static void bler_u(void); static void blei_u(void); static void beqr(void); static void beqi(void); static void bger(void); static void bgei(void); static void bger_u(void); static void bgei_u(void); static void bgtr(void); static void bgti(void); static void bgtr_u(void); static void bgti_u(void); static void bner(void); static void bnei(void); static void bmsr(void); static void bmsi(void); static void bmcr(void); static void bmci(void); static void boaddr(void); static void boaddi(void); static void boaddr_u(void); static void boaddi_u(void); static void bxaddr(void); static void bxaddi(void); static void bxaddr_u(void); static void bxaddi_u(void); static void bosubr(void); static void bosubi(void); static void bosubr_u(void); static void bosubi_u(void); static void bxsubr(void); static void bxsubi(void); static void bxsubr_u(void); static void bxsubi_u(void); static void jmpr(void); static void jmpi(void); static void callr(void); static void calli(void); static void prepare(void); static void pushargr(void); static void pushargi(void); static void finishr(void); static void finishi(void); static void ret(void); static void retr(void); static void reti(void); static void retval_c(void); static void retval_uc(void); static void retval_s(void); static void retval_us(void); static void retval_i(void); #if __WORDSIZE == 64 static void retval_ui(void); static void retval_l(void); #endif static void retval(void); static void epilog(void); static void arg_f(void); static void getarg_f(void); static void putargr_f(void); static void putargi_f(void); static void addr_f(void); static void addi_f(void); static void subr_f(void); static void subi_f(void); static void rsbr_f(void); static void rsbi_f(void); static void mulr_f(void); static void muli_f(void); static void divr_f(void); static void divi_f(void); static void negr_f(void); static void absr_f(void); static void sqrtr_f(void); static void ltr_f(void); static void lti_f(void); static void ler_f(void); static void lei_f(void); static void eqr_f(void); static void eqi_f(void); static void ger_f(void); static void gei_f(void); static void gtr_f(void); static void gti_f(void); static void ner_f(void); static void nei_f(void); static void unltr_f(void); static void unlti_f(void); static void unler_f(void); static void unlei_f(void); static void uneqr_f(void); static void uneqi_f(void); static void unger_f(void); static void ungei_f(void); static void ungtr_f(void); static void ungti_f(void); static void ltgtr_f(void); static void ltgti_f(void); static void ordr_f(void); static void ordi_f(void); static void unordr_f(void); static void unordi_f(void); static void truncr_f_i(void); #if __WORDSIZE == 64 static void truncr_f_l(void); #endif static void truncr_f(void); static void extr_f(void); static void extr_d_f(void); static void movr_f(void); static void movi_f(void); static void ldr_f(void); static void ldi_f(void); static void ldxr_f(void); static void ldxi_f(void); static void str_f(void); static void sti_f(void); static void stxr_f(void); static void stxi_f(void); static void bltr_f(void); static void blti_f(void); static void bler_f(void); static void blei_f(void); static void beqr_f(void); static void beqi_f(void); static void bger_f(void); static void bgei_f(void); static void bgtr_f(void); static void bgti_f(void); static void bner_f(void); static void bnei_f(void); static void bunltr_f(void); static void bunlti_f(void); static void bunler_f(void); static void bunlei_f(void); static void buneqr_f(void); static void buneqi_f(void); static void bunger_f(void); static void bungei_f(void); static void bungtr_f(void); static void bungti_f(void); static void bltgtr_f(void); static void bltgti_f(void); static void bordr_f(void); static void bordi_f(void); static void bunordr_f(void); static void bunordi_f(void); static void pushargr_f(void); static void pushargi_f(void); static void retr_f(void); static void reti_f(void); static void retval_f(void); static void arg_d(void); static void getarg_d(void); static void putargr_d(void); static void putargi_d(void); static void addr_d(void); static void addi_d(void); static void subr_d(void); static void subi_d(void); static void rsbr_d(void); static void rsbi_d(void); static void mulr_d(void); static void muli_d(void); static void divr_d(void); static void divi_d(void); static void negr_d(void); static void absr_d(void); static void sqrtr_d(void); static void ltr_d(void); static void lti_d(void); static void ler_d(void); static void lei_d(void); static void eqr_d(void); static void eqi_d(void); static void ger_d(void); static void gei_d(void); static void gtr_d(void); static void gti_d(void); static void ner_d(void); static void nei_d(void); static void unltr_d(void); static void unlti_d(void); static void unler_d(void); static void unlei_d(void); static void uneqr_d(void); static void uneqi_d(void); static void unger_d(void); static void ungei_d(void); static void ungtr_d(void); static void ungti_d(void); static void ltgtr_d(void); static void ltgti_d(void); static void ordr_d(void); static void ordi_d(void); static void unordr_d(void); static void unordi_d(void); static void truncr_d_i(void); #if __WORDSIZE == 64 static void truncr_d_l(void); #endif static void truncr_d(void); static void extr_d(void); static void extr_f_d(void); static void movr_d(void); static void movi_d(void); static void ldr_d(void); static void ldi_d(void); static void ldxr_d(void); static void ldxi_d(void); static void str_d(void); static void sti_d(void); static void stxr_d(void); static void stxi_d(void); static void bltr_d(void); static void blti_d(void); static void bler_d(void); static void blei_d(void); static void beqr_d(void); static void beqi_d(void); static void bger_d(void); static void bgei_d(void); static void bgtr_d(void); static void bgti_d(void); static void bner_d(void); static void bnei_d(void); static void bunltr_d(void); static void bunlti_d(void); static void bunler_d(void); static void bunlei_d(void); static void buneqr_d(void); static void buneqi_d(void); static void bunger_d(void); static void bungei_d(void); static void bungtr_d(void); static void bungti_d(void); static void bltgtr_d(void); static void bltgti_d(void); static void bordr_d(void); static void bordi_d(void); static void bunordr_d(void); static void bunordi_d(void); static void pushargr_d(void); static void pushargi_d(void); static void retr_d(void); static void reti_d(void); static void retval_d(void); static void vastart(void); static void vapush(void); static void vaarg(void); static void vaarg_d(void); static void vaend(void); static void error(const char *format, ...) noreturn printf_format(1, 2); static void warn(const char *format, ...) printf_format(1, 2) maybe_unused; static void message(const char *kind, const char *format, va_list ap); static int getch(void); static int getch_noeof(void); static int ungetch(int ch); static int skipws(void); static int skipnl(void); static int skipct(void); static int skipcp(void); static jit_word_t get_int(skip_t skip); static jit_uword_t get_uint(skip_t skip); static double get_float(skip_t skip); static float make_float(double d); static void *get_pointer(skip_t skip); static label_t *get_label(skip_t skip); static token_t regname(void); static token_t identifier(int ch); static void get_data(type_t type); static void dot(void); static token_t number(int ch); static int escape(int ch); static token_t string(void); static token_t dynamic(void); static token_t character(void); static void expression_prim(void); static void expression_inc(int pre); static void expression_dec(int pre); static void expression_unary(void); static void expression_mul(void); static void expression_add(void); static void expression_shift(void); static void expression_bit(void); static void expression_rel(void); static void expression_cond(void); static token_t expression(void); static token_t primary(skip_t skip); static void parse(void); static int execute(int argc, char *argv[]); static void *xmalloc(size_t size); static void *xrealloc(void *pointer, size_t size); static void *xcalloc(size_t nmemb, size_t size); static label_t *new_label(label_kind_t kind, char *name, void *value); static patch_t *new_patch(patch_kind_t kind, label_t *label, void *value); static int bcmp_symbols(const void *left, const void *right); static int qcmp_symbols(const void *left, const void *right); static symbol_t *new_symbol(char *name); static symbol_t *get_symbol_by_name(char *name); static hash_t *new_hash(void); static int hash_string(char *name); static void put_hash(hash_t *hash, entry_t *entry); static entry_t *get_hash(hash_t *hash, char *name); static void rehash(hash_t *hash); /* * Initialization */ static jit_state_t *_jit; static int flag_verbose; static int flag_data; static int flag_disasm; static char *progname; static parser_t parser; static hash_t *labels; static int label_offset; static patch_t *patches; static symbol_t **symbols; static int symbol_length; static int symbol_offset; static hash_t *instrs; static char *data; static size_t data_offset, data_length; static instr_t instr_vector[] = { #define entry(value) { NULL, #value, value } #define entry2(name, function) { NULL, name, function } entry(live), entry(align), entry(name), entry(prolog), entry(frame), entry(tramp), entry(ellipsis), entry(allocai), entry(allocar), entry(arg), entry(getarg_c), entry(getarg_uc), entry(getarg_s), entry(getarg_us), entry(getarg_i), #if __WORDSIZE == 64 entry(getarg_ui), entry(getarg_l), #endif entry(getarg), entry(putargr), entry(putargi), entry(addr), entry(addi), entry(addxr), entry(addxi), entry(addcr), entry(addci), entry(subr), entry(subi), entry(subxr), entry(subxi), entry(subcr), entry(subci), entry(rsbr), entry(rsbi), entry(mulr), entry(muli), entry(qmulr), entry(qmuli), entry(qmulr_u), entry(qmuli_u), entry(divr), entry(divi), entry(divr_u), entry(divi_u), entry(qdivr), entry(qdivi), entry(qdivr_u), entry(qdivi_u), entry(remr), entry(remi), entry(remr_u), entry(remi_u), entry(andr), entry(andi), entry(orr), entry(ori), entry(xorr), entry(xori), entry(lshr), entry(lshi), entry(rshr), entry(rshi), entry(rshr_u), entry(rshi_u), entry(negr), entry(comr), entry(ltr), entry(lti), entry(ltr_u), entry(lti_u), entry(ler), entry(lei), entry(ler_u), entry(lei_u), entry(eqr), entry(eqi), entry(ger), entry(gei), entry(ger_u), entry(gei_u), entry(gtr), entry(gti), entry(gtr_u), entry(gti_u), entry(ner), entry(nei), entry(movr), entry(movi), entry(extr_c), entry(extr_uc), entry(extr_s), entry(extr_us), #if __WORDSIZE == 64 entry(extr_i), entry(extr_ui), #endif entry(htonr_us), entry(ntohr_us), entry(htonr_ui), entry(ntohr_ui), #if __WORDSIZE == 64 entry(htonr_ul), entry(ntohr_ul), #endif entry(htonr), entry(ntohr), entry(ldr_c), entry(ldi_c), entry(ldr_uc), entry(ldi_uc), entry(ldr_s), entry(ldi_s), entry(ldr_us), entry(ldi_us), entry(ldr_i), entry(ldi_i), #if __WORDSIZE == 64 entry(ldr_ui), entry(ldi_ui), entry(ldr_l), entry(ldi_l), #endif entry(ldr), entry(ldi), entry(ldxr_c), entry(ldxi_c), entry(ldxr_uc), entry(ldxi_uc), entry(ldxr_s), entry(ldxi_s), entry(ldxr_us), entry(ldxi_us), entry(ldxr_i), entry(ldxi_i), #if __WORDSIZE == 64 entry(ldxr_ui), entry(ldxi_ui), entry(ldxr_l), entry(ldxi_l), #endif entry(ldxr), entry(ldxi), entry(str_c), entry(sti_c), entry(str_s), entry(sti_s), entry(str_i), entry(sti_i), #if __WORDSIZE == 64 entry(str_l), entry(sti_l), #endif entry(str), entry(sti), entry(stxr_c), entry(stxi_c), entry(stxr_s), entry(stxi_s), entry(stxr_i), entry(stxi_i), #if __WORDSIZE == 64 entry(stxr_l), entry(stxi_l), #endif entry(stxr), entry(stxi), entry(bltr), entry(blti), entry(bltr_u), entry(blti_u), entry(bler), entry(blei), entry(bler_u), entry(blei_u), entry(beqr), entry(beqi), entry(bger), entry(bgei), entry(bger_u), entry(bgei_u), entry(bgtr), entry(bgti), entry(bgtr_u), entry(bgti_u), entry(bner), entry(bnei), entry(bmsr), entry(bmsi), entry(bmcr), entry(bmci), entry(boaddr), entry(boaddi), entry(boaddr_u), entry(boaddi_u), entry(bxaddr), entry(bxaddi), entry(bxaddr_u), entry(bxaddi_u), entry(bosubr), entry(bosubi), entry(bosubr_u), entry(bosubi_u), entry(bxsubr), entry(bxsubi), entry(bxsubr_u), entry(bxsubi_u), entry(jmpr), entry(jmpi), entry(callr), entry(calli), entry(prepare), entry(pushargr), entry(pushargi), entry(finishr), entry(finishi), entry(ret), entry(retr), entry(reti), entry(retval_c), entry(retval_uc), entry(retval_s), entry(retval_us), entry(retval_i), #if __WORDSIZE == 64 entry(retval_ui), entry(retval_l), #endif entry(retval), entry(epilog), entry(arg_f), entry(getarg_f), entry(putargr_f), entry(putargi_f), entry(addr_f), entry(addi_f), entry(subr_f), entry(subi_f), entry(rsbr_f), entry(rsbi_f), entry(mulr_f), entry(muli_f), entry(divr_f), entry(divi_f), entry(negr_f), entry(absr_f), entry(sqrtr_f), entry(ltr_f), entry(lti_f), entry(ler_f), entry(lei_f), entry(eqr_f), entry(eqi_f), entry(ger_f), entry(gei_f), entry(gtr_f), entry(gti_f), entry(ner_f), entry(nei_f), entry(unltr_f), entry(unlti_f), entry(unler_f), entry(unlei_f), entry(uneqr_f), entry(uneqi_f), entry(unger_f), entry(ungei_f), entry(ungtr_f), entry(ungti_f), entry(ltgtr_f), entry(ltgti_f), entry(ordr_f), entry(ordi_f), entry(unordr_f), entry(unordi_f), entry(truncr_f_i), #if __WORDSIZE == 64 entry(truncr_f_l), #endif entry(truncr_f), entry(extr_f), entry(extr_d_f), entry(movr_f), entry(movi_f), entry(ldr_f), entry(ldi_f), entry(ldxr_f), entry(ldxi_f), entry(str_f), entry(sti_f), entry(stxr_f), entry(stxi_f), entry(bltr_f), entry(blti_f), entry(bler_f), entry(blei_f), entry(beqr_f), entry(beqi_f), entry(bger_f), entry(bgei_f), entry(bgtr_f), entry(bgti_f), entry(bner_f), entry(bnei_f), entry(bunltr_f), entry(bunlti_f), entry(bunler_f), entry(bunlei_f), entry(buneqr_f), entry(buneqi_f), entry(bunger_f), entry(bungei_f), entry(bungtr_f), entry(bungti_f), entry(bltgtr_f), entry(bltgti_f), entry(bordr_f), entry(bordi_f), entry(bunordr_f), entry(bunordi_f), entry(pushargr_f), entry(pushargi_f), entry(retr_f), entry(reti_f), entry(retval_f), entry(arg_d), entry(getarg_d), entry(putargr_d), entry(putargi_d), entry(addr_d), entry(addi_d), entry(subr_d), entry(subi_d), entry(rsbr_d), entry(rsbi_d), entry(mulr_d), entry(muli_d), entry(divr_d), entry(divi_d), entry(negr_d), entry(absr_d), entry(sqrtr_d), entry(ltr_d), entry(lti_d), entry(ler_d), entry(lei_d), entry(eqr_d), entry(eqi_d), entry(ger_d), entry(gei_d), entry(gtr_d), entry(gti_d), entry(ner_d), entry(nei_d), entry(unltr_d), entry(unlti_d), entry(unler_d), entry(unlei_d), entry(uneqr_d), entry(uneqi_d), entry(unger_d), entry(ungei_d), entry(ungtr_d), entry(ungti_d), entry(ltgtr_d), entry(ltgti_d), entry(ordr_d), entry(ordi_d), entry(unordr_d), entry(unordi_d), entry(truncr_d_i), #if __WORDSIZE == 64 entry(truncr_d_l), #endif entry(truncr_d), entry(extr_d), entry(extr_f_d), entry(movr_d), entry(movi_d), entry(ldr_d), entry(ldi_d), entry(ldxr_d), entry(ldxi_d), entry(str_d), entry(sti_d), entry(stxr_d), entry(stxi_d), entry(bltr_d), entry(blti_d), entry(bler_d), entry(blei_d), entry(beqr_d), entry(beqi_d), entry(bger_d), entry(bgei_d), entry(bgtr_d), entry(bgti_d), entry(bner_d), entry(bnei_d), entry(bunltr_d), entry(bunlti_d), entry(bunler_d), entry(bunlei_d), entry(buneqr_d), entry(buneqi_d), entry(bunger_d), entry(bungei_d), entry(bungtr_d), entry(bungti_d), entry(bltgtr_d), entry(bltgti_d), entry(bordr_d), entry(bordi_d), entry(bunordr_d), entry(bunordi_d), entry(pushargr_d), entry(pushargi_d), entry(retr_d), entry(reti_d), entry(retval_d), entry2("va_start", vastart), entry2("va_push", vapush), entry2("va_arg", vaarg), entry2("va_arg_d", vaarg_d), entry2("va_end", vaend), #undef entry }; /* * Implementation */ static jit_gpr_t get_ireg(void) { if (primary(skip_ws) != tok_register) error("bad register"); if (parser.regtype != type_l) error("bad int register"); return ((jit_gpr_t)parser.regval); } static jit_fpr_t get_freg(void) { if (primary(skip_ws) != tok_register) error("bad register"); if (parser.regtype != type_d) error("bad float register"); return ((jit_fpr_t)parser.regval); } static symbol_t * get_symbol(void) { symbol_t *symbol; int ch = skipws(); if (ch != '$') error("expecting variable"); (void)identifier('$'); if (parser.string[1] == '\0') error("expecting variable"); if ((symbol = get_symbol_by_name(parser.string)) == NULL) symbol = new_symbol(parser.string); return (symbol); } static void jmp_forward(void *value, label_t *label) { (void)new_patch(patch_kind_jmp, label, value); } static void mov_forward(void *value, label_t *label) { (void)new_patch(patch_kind_mov, label, value); } static void call_forward(void *value, label_t *label) { (void)new_patch(patch_kind_call, label, value); } static void make_arg(void *value) { symbol_t *symbol = get_symbol(); symbol->type = type_p; symbol->value.p = value; } static jit_pointer_t get_arg(void) { symbol_t *symbol = get_symbol(); if (symbol->type != type_p) error("bad argument %s type", symbol->name); return symbol->value.p; } static jit_word_t get_imm(void) { int ch; label_t *label; jit_word_t value; ch = skipws(); switch (ch) { case '+': case '-': case '0' ... '9': ungetch(ch); value = get_int(skip_none); break; case '\'': character(); value = parser.value.i; break; case '$': switch (expression()) { case tok_int: case tok_pointer: value = parser.value.i; break; default: error("expecting immediate"); } break; case '@': dynamic(); value = (jit_word_t)parser.value.p; break; default: ungetch(ch); label = get_label(skip_none); if (label->kind == label_kind_data) value = (jit_word_t)label->value; else error("expecting immediate"); break; } return (value); } #define entry(name) \ static void \ name(void) \ { \ jit_##name(); \ } #define entry_ca(name) \ static void \ name(void) \ { \ make_arg(jit_##name()); \ } #define entry_ia(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(); \ jit_pointer_t ac = get_arg(); \ jit_##name(r0, ac); \ } #define entry_im(name) \ static void \ name(void) \ { \ jit_word_t im = get_imm(); \ jit_##name(im); \ } #define entry_ir(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(); \ jit_##name(r0); \ } #define entry_ima(name) \ static void \ name(void) \ { \ jit_word_t im = get_imm(); \ jit_pointer_t ac = get_arg(); \ jit_##name(im, ac); \ } #define entry_ir_ir_ir(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(), r1 = get_ireg(), r2 = get_ireg(); \ jit_##name(r0, r1, r2); \ } #define entry_ir_ir_im(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(), r1 = get_ireg(); \ jit_word_t im = get_imm(); \ jit_##name(r0, r1, im); \ } #define entry_ir_ir_ir_ir(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(), r1 = get_ireg(), \ r2 = get_ireg(), r3 = get_ireg(); \ jit_##name(r0, r1, r2, r3); \ } #define entry_ir_ir_ir_im(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(), r1 = get_ireg(), r2 = get_ireg(); \ jit_word_t im = get_imm(); \ jit_##name(r0, r1, r2, im); \ } #define entry_ir_ir(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(), r1 = get_ireg(); \ jit_##name(r0, r1); \ } #define entry_ir_im(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(); \ jit_word_t im = get_imm(); \ jit_##name(r0, im); \ } #define entry_ir_pm(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(); \ void *pm = get_pointer(skip_ws); \ jit_##name(r0, pm); \ } #define entry_pm_ir(name) \ static void \ name(void) \ { \ void *pm = get_pointer(skip_ws); \ jit_gpr_t r0 = get_ireg(); \ jit_##name(pm, r0); \ } #define entry_im_ir_ir(name) \ static void \ name(void) \ { \ jit_word_t im = get_imm(); \ jit_gpr_t r0 = get_ireg(), r1 = get_ireg(); \ (void)jit_##name(im, r0, r1); \ } #define entry_lb_ir_ir(name) \ static void \ name(void) \ { \ jit_node_t *jmp; \ label_t *label = get_label(skip_ws); \ jit_gpr_t r0 = get_ireg(), r1 = get_ireg(); \ if (label->kind == label_kind_code_forward) \ jmp_forward((void *)jit_##name(r0, r1), label); \ else { \ jmp = jit_##name(r0, r1); \ jit_patch_at(jmp, (jit_node_t *)label->value); \ } \ } #define entry_lb_ir_im(name) \ static void \ name(void) \ { \ jit_node_t *jmp; \ label_t *label = get_label(skip_ws); \ jit_gpr_t r0 = get_ireg(); \ jit_word_t im = get_imm(); \ if (label->kind == label_kind_code_forward) \ jmp_forward((void *)jit_##name(r0, im), label); \ else { \ jmp = jit_##name(r0, im); \ jit_patch_at(jmp, (jit_node_t *)label->value); \ } \ } #define entry_lb(name) \ static void \ name(void) \ { \ jit_node_t *jmp; \ label_t *label = get_label(skip_ws); \ if (label->kind == label_kind_code_forward) \ jmp_forward((void *)jit_##name(), label); \ else { \ jmp = jit_##name(); \ jit_patch_at(jmp, (jit_node_t *)label->value); \ } \ } #define entry_pm(name) \ static void \ name(void) \ { \ void *pm = get_pointer(skip_ws); \ jit_##name(pm); \ } #define entry_fa(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(); \ jit_pointer_t ac = get_arg(); \ jit_##name(r0, ac); \ } #define entry_fma(name) \ static void \ name(void) \ { \ jit_float64_t im = get_float(skip_ws); \ jit_pointer_t ac = get_arg(); \ jit_##name(im, ac); \ } #define entry_fr_fr_fr(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(), r1 = get_freg(), r2 = get_freg(); \ jit_##name(r0, r1, r2); \ } #define entry_fr_fr_fm(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(), r1 = get_freg(); \ jit_float64_t im = get_float(skip_ws); \ jit_##name(r0, r1, make_float(im)); \ } #define entry_fr_fr_dm(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(), r1 = get_freg(); \ jit_float64_t im = get_float(skip_ws); \ jit_##name(r0, r1, im); \ } #define entry_fr_fr(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(), r1 = get_freg(); \ jit_##name(r0, r1); \ } #define entry_ir_fr_fr(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(); \ jit_fpr_t r1 = get_freg(), r2 = get_freg(); \ jit_##name(r0, r1, r2); \ } #define entry_ir_fr_fm(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(); \ jit_fpr_t r1 = get_freg(); \ jit_float64_t im = get_float(skip_ws); \ jit_##name(r0, r1, make_float(im)); \ } #define entry_ir_fr_dm(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(); \ jit_fpr_t r1 = get_freg(); \ jit_float64_t im = get_float(skip_ws); \ jit_##name(r0, r1, im); \ } #define entry_ir_fr(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(); \ jit_fpr_t r1 = get_freg(); \ jit_##name(r0, r1); \ } #define entry_fr_ir(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(); \ jit_gpr_t r1 = get_ireg(); \ jit_##name(r0, r1); \ } #define entry_fr_fm(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(); \ jit_float64_t im = get_float(skip_ws); \ jit_##name(r0, make_float(im)); \ } #define entry_fr_dm(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(); \ jit_float64_t im = get_float(skip_ws); \ jit_##name(r0, im); \ } #define entry_fr_pm(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(); \ void *pm = get_pointer(skip_ws); \ jit_##name(r0, pm); \ } #define entry_fr_ir_ir(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(); \ jit_gpr_t r1 = get_ireg(), r2 = get_ireg(); \ jit_##name(r0, r1, r2); \ } #define entry_fr_ir_im(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(); \ jit_gpr_t r1 = get_ireg(); \ jit_word_t im = get_imm(); \ jit_##name(r0, r1, im); \ } #define entry_pm_fr(name) \ static void \ name(void) \ { \ void *pm = get_pointer(skip_ws); \ jit_fpr_t r0 = get_freg(); \ jit_##name(pm, r0); \ } #define entry_ir_ir_fr(name) \ static void \ name(void) \ { \ jit_gpr_t r0 = get_ireg(), r1 = get_ireg(); \ jit_fpr_t r2 = get_freg(); \ jit_##name(r0, r1, r2); \ } #define entry_im_ir_fr(name) \ static void \ name(void) \ { \ jit_word_t im = get_imm(); \ jit_gpr_t r0 = get_ireg(); \ jit_fpr_t r1 = get_freg(); \ jit_##name(im, r0, r1); \ } #define entry_lb_fr_fr(name) \ static void \ name(void) \ { \ jit_node_t *jmp; \ label_t *label = get_label(skip_ws); \ jit_fpr_t r0 = get_freg(), r1 = get_freg(); \ if (label->kind == label_kind_code_forward) \ jmp_forward((void *)jit_##name(r0, r1), label); \ else { \ jmp = jit_##name(r0, r1); \ jit_patch_at(jmp, (jit_node_t *)label->value); \ } \ } #define entry_lb_fr_fm(name) \ static void \ name(void) \ { \ jit_node_t *jmp; \ label_t *label = get_label(skip_ws); \ jit_fpr_t r0 = get_freg(); \ jit_float64_t im = get_float(skip_ws); \ if (label->kind == label_kind_code_forward) \ jmp_forward((void *)jit_##name(r0, make_float(im)), label); \ else { \ jmp = jit_##name(r0, make_float(im)); \ jit_patch_at(jmp, (jit_node_t *)label->value); \ } \ } #define entry_lb_fr_dm(name) \ static void \ name(void) \ { \ jit_node_t *jmp; \ label_t *label = get_label(skip_ws); \ jit_fpr_t r0 = get_freg(); \ jit_float64_t im = get_float(skip_ws); \ if (label->kind == label_kind_code_forward) \ jmp_forward((void *)jit_##name(r0, im), label); \ else { \ jmp = jit_##name(r0, im); \ jit_patch_at(jmp, (jit_node_t *)label->value); \ } \ } #define entry_fr(name) \ static void \ name(void) \ { \ jit_fpr_t r0 = get_freg(); \ jit_##name(r0); \ } #define entry_fm(name) \ static void \ name(void) \ { \ jit_float64_t im = get_float(skip_ws); \ jit_##name(make_float(im)); \ } #define entry_dm(name) \ static void \ name(void) \ { \ jit_float64_t im = get_float(skip_ws); \ jit_##name(im); \ } #define entry_fn(name) \ static void \ name(void) \ { \ int ch; \ label_t *label; \ void *value; \ ch = skipws(); \ switch (ch) { \ case '0' ... '9': \ ungetch(ch); \ value = (void *)(jit_word_t)get_uint(skip_none); \ break; \ case '$': \ switch (expression()) { \ case tok_int: \ value = (void *)parser.value.i; \ break; \ case tok_pointer: \ value = parser.value.p; \ break; \ default: \ error("expecting pointer"); \ } \ break; \ case '@': \ dynamic(); \ value = parser.value.p; \ break; \ default: \ ungetch(ch); \ label = get_label(skip_none); \ if (label->kind == label_kind_code_forward) \ call_forward((void *)jit_##name(NULL), label); \ else \ jit_patch_at(jit_##name(NULL), label->value); \ return; \ } \ jit_##name(value); \ } static void name(void) { int ch = skipws(); (void)identifier(ch); jit_name(parser.string); } static void live(void) { if (primary(skip_ws) != tok_register) error("bad register"); jit_live(parser.regval); } entry_im(align) entry(prolog) entry_im(frame) entry_im(tramp) entry(ellipsis) void allocai(void) { symbol_t *symbol; jit_word_t i, im = get_imm(); i = jit_allocai(im); symbol = get_symbol(); symbol->type = type_l; symbol->value.i = i; } entry_ir_ir(allocar) entry_ca(arg) entry_ia(getarg_c) entry_ia(getarg_uc) entry_ia(getarg_s) entry_ia(getarg_us) entry_ia(getarg_i) #if __WORDSIZE == 64 entry_ia(getarg_ui) entry_ia(getarg_l) #endif entry_ia(getarg) entry_ia(putargr) entry_ima(putargi) entry_ir_ir_ir(addr) entry_ir_ir_im(addi) entry_ir_ir_ir(addxr) entry_ir_ir_im(addxi) entry_ir_ir_ir(addcr) entry_ir_ir_im(addci) entry_ir_ir_ir(subr) entry_ir_ir_im(subi) entry_ir_ir_ir(subxr) entry_ir_ir_im(subxi) entry_ir_ir_ir(subcr) entry_ir_ir_im(subci) entry_ir_ir_ir(rsbr) entry_ir_ir_im(rsbi) entry_ir_ir_ir(mulr) entry_ir_ir_im(muli) entry_ir_ir_ir_ir(qmulr) entry_ir_ir_ir_im(qmuli) entry_ir_ir_ir_ir(qmulr_u) entry_ir_ir_ir_im(qmuli_u) entry_ir_ir_ir(divr) entry_ir_ir_im(divi) entry_ir_ir_ir(divr_u) entry_ir_ir_im(divi_u) entry_ir_ir_ir_ir(qdivr) entry_ir_ir_ir_im(qdivi) entry_ir_ir_ir_ir(qdivr_u) entry_ir_ir_ir_im(qdivi_u) entry_ir_ir_ir(remr) entry_ir_ir_im(remi) entry_ir_ir_ir(remr_u) entry_ir_ir_im(remi_u) entry_ir_ir_ir(andr) entry_ir_ir_im(andi) entry_ir_ir_ir(orr) entry_ir_ir_im(ori) entry_ir_ir_ir(xorr) entry_ir_ir_im(xori) entry_ir_ir_ir(lshr) entry_ir_ir_im(lshi) entry_ir_ir_ir(rshr) entry_ir_ir_im(rshi) entry_ir_ir_ir(rshr_u) entry_ir_ir_im(rshi_u) entry_ir_ir(negr) entry_ir_ir(comr) entry_ir_ir_ir(ltr) entry_ir_ir_im(lti) entry_ir_ir_ir(ltr_u) entry_ir_ir_im(lti_u) entry_ir_ir_ir(ler) entry_ir_ir_im(lei) entry_ir_ir_ir(ler_u) entry_ir_ir_im(lei_u) entry_ir_ir_ir(eqr) entry_ir_ir_im(eqi) entry_ir_ir_ir(ger) entry_ir_ir_im(gei) entry_ir_ir_ir(ger_u) entry_ir_ir_im(gei_u) entry_ir_ir_ir(gtr) entry_ir_ir_im(gti) entry_ir_ir_ir(gtr_u) entry_ir_ir_im(gti_u) entry_ir_ir_ir(ner) entry_ir_ir_im(nei) entry_ir_ir(movr) static void movi(void) { int ch; label_t *label; void *value; jit_gpr_t r0 = get_ireg(); ch = skipws(); switch (ch) { case '+': case '-': case '0' ... '9': ungetch(ch); value = (void *)(jit_word_t)get_uint(skip_none); break; case '\'': character(); value = (void *)parser.value.i; break; case '$': switch (expression()) { case tok_int: value = (void *)parser.value.i; break; case tok_pointer: value = parser.value.p; break; default: error("expecting pointer"); } break; case '@': dynamic(); value = parser.value.p; break; default: ungetch(ch); label = get_label(skip_none); if (label->kind == label_kind_code || label->kind == label_kind_code_forward) { mov_forward((void *)jit_movi(r0, 0), label); return; } value = label->value; break; } jit_movi(r0, (jit_word_t)value); } entry_ir_ir(extr_c) entry_ir_ir(extr_uc) entry_ir_ir(extr_s) entry_ir_ir(extr_us) #if __WORDSIZE == 64 entry_ir_ir(extr_i) entry_ir_ir(extr_ui) #endif entry_ir_ir(htonr_us) entry_ir_ir(ntohr_us) entry_ir_ir(htonr_ui) entry_ir_ir(ntohr_ui) #if __WORDSIZE == 64 entry_ir_ir(htonr_ul) entry_ir_ir(ntohr_ul) #endif entry_ir_ir(htonr) entry_ir_ir(ntohr) entry_ir_ir(ldr_c) entry_ir_pm(ldi_c) entry_ir_ir(ldr_uc) entry_ir_pm(ldi_uc) entry_ir_ir(ldr_s) entry_ir_pm(ldi_s) entry_ir_ir(ldr_us) entry_ir_pm(ldi_us) entry_ir_ir(ldr_i) entry_ir_pm(ldi_i) #if __WORDSIZE == 64 entry_ir_ir(ldr_ui) entry_ir_pm(ldi_ui) entry_ir_ir(ldr_l) entry_ir_pm(ldi_l) #endif entry_ir_ir(ldr) entry_ir_pm(ldi) entry_ir_ir_ir(ldxr_c) entry_ir_ir_im(ldxi_c) entry_ir_ir_ir(ldxr_uc) entry_ir_ir_im(ldxi_uc) entry_ir_ir_ir(ldxr_s) entry_ir_ir_im(ldxi_s) entry_ir_ir_ir(ldxr_us) entry_ir_ir_im(ldxi_us) entry_ir_ir_ir(ldxr_i) entry_ir_ir_im(ldxi_i) #if __WORDSIZE == 64 entry_ir_ir_ir(ldxr_ui) entry_ir_ir_im(ldxi_ui) entry_ir_ir_ir(ldxr_l) entry_ir_ir_im(ldxi_l) #endif entry_ir_ir_ir(ldxr) entry_ir_ir_im(ldxi) entry_ir_ir(str_c) entry_pm_ir(sti_c) entry_ir_ir(str_s) entry_pm_ir(sti_s) entry_ir_ir(str_i) entry_pm_ir(sti_i) #if __WORDSIZE == 64 entry_ir_ir(str_l) entry_pm_ir(sti_l) #endif entry_ir_ir(str) entry_pm_ir(sti) entry_ir_ir_ir(stxr_c) entry_im_ir_ir(stxi_c) entry_ir_ir_ir(stxr_s) entry_im_ir_ir(stxi_s) entry_ir_ir_ir(stxr_i) entry_im_ir_ir(stxi_i) #if __WORDSIZE == 64 entry_ir_ir_ir(stxr_l) entry_im_ir_ir(stxi_l) #endif entry_ir_ir_ir(stxr) entry_im_ir_ir(stxi) entry_lb_ir_ir(bltr) entry_lb_ir_im(blti) entry_lb_ir_ir(bltr_u) entry_lb_ir_im(blti_u) entry_lb_ir_ir(bler) entry_lb_ir_im(blei) entry_lb_ir_ir(bler_u) entry_lb_ir_im(blei_u) entry_lb_ir_ir(beqr) entry_lb_ir_im(beqi) entry_lb_ir_ir(bger) entry_lb_ir_im(bgei) entry_lb_ir_ir(bger_u) entry_lb_ir_im(bgei_u) entry_lb_ir_ir(bgtr) entry_lb_ir_im(bgti) entry_lb_ir_ir(bgtr_u) entry_lb_ir_im(bgti_u) entry_lb_ir_ir(bner) entry_lb_ir_im(bnei) entry_lb_ir_ir(bmsr) entry_lb_ir_im(bmsi) entry_lb_ir_ir(bmcr) entry_lb_ir_im(bmci) entry_lb_ir_ir(boaddr) entry_lb_ir_im(boaddi) entry_lb_ir_ir(boaddr_u) entry_lb_ir_im(boaddi_u) entry_lb_ir_ir(bxaddr) entry_lb_ir_im(bxaddi) entry_lb_ir_ir(bxaddr_u) entry_lb_ir_im(bxaddi_u) entry_lb_ir_ir(bosubr) entry_lb_ir_im(bosubi) entry_lb_ir_ir(bosubr_u) entry_lb_ir_im(bosubi_u) entry_lb_ir_ir(bxsubr) entry_lb_ir_im(bxsubi) entry_lb_ir_ir(bxsubr_u) entry_lb_ir_im(bxsubi_u) entry_ir(jmpr) entry_lb(jmpi) entry_ir(callr) entry_fn(calli) entry(prepare) entry_ir(pushargr) entry_im(pushargi) entry_ir(finishr) entry_fn(finishi) entry(ret) entry_ir(retr) entry_im(reti) entry_ir(retval_c) entry_ir(retval_uc) entry_ir(retval_s) entry_ir(retval_us) entry_ir(retval_i) #if __WORDSIZE == 64 entry_ir(retval_ui) entry_ir(retval_l) #endif entry_ir(retval) entry(epilog) entry_ca(arg_f) entry_fa(getarg_f) entry_fa(putargr_f) entry_fma(putargi_f) entry_fr_fr_fr(addr_f) entry_fr_fr_fm(addi_f) entry_fr_fr_fr(subr_f) entry_fr_fr_fm(subi_f) entry_fr_fr_fr(rsbr_f) entry_fr_fr_fm(rsbi_f) entry_fr_fr_fr(mulr_f) entry_fr_fr_fm(muli_f) entry_fr_fr_fr(divr_f) entry_fr_fr_fm(divi_f) entry_fr_fr(negr_f) entry_fr_fr(absr_f) entry_fr_fr(sqrtr_f) entry_ir_fr_fr(ltr_f) entry_ir_fr_fm(lti_f) entry_ir_fr_fr(ler_f) entry_ir_fr_fm(lei_f) entry_ir_fr_fr(eqr_f) entry_ir_fr_fm(eqi_f) entry_ir_fr_fr(ger_f) entry_ir_fr_fm(gei_f) entry_ir_fr_fr(gtr_f) entry_ir_fr_fm(gti_f) entry_ir_fr_fr(ner_f) entry_ir_fr_fm(nei_f) entry_ir_fr_fr(unltr_f) entry_ir_fr_fm(unlti_f) entry_ir_fr_fr(unler_f) entry_ir_fr_fm(unlei_f) entry_ir_fr_fr(uneqr_f) entry_ir_fr_fm(uneqi_f) entry_ir_fr_fr(unger_f) entry_ir_fr_fm(ungei_f) entry_ir_fr_fr(ungtr_f) entry_ir_fr_fm(ungti_f) entry_ir_fr_fr(ltgtr_f) entry_ir_fr_fm(ltgti_f) entry_ir_fr_fr(ordr_f) entry_ir_fr_fm(ordi_f) entry_ir_fr_fr(unordr_f) entry_ir_fr_fm(unordi_f) entry_ir_fr(truncr_f_i) #if __WORDSIZE == 64 entry_ir_fr(truncr_f_l) #endif entry_ir_fr(truncr_f) entry_fr_ir(extr_f) entry_fr_fr(extr_d_f) entry_fr_fr(movr_f) entry_fr_fm(movi_f) entry_fr_ir(ldr_f) entry_fr_pm(ldi_f) entry_fr_ir_ir(ldxr_f) entry_fr_ir_im(ldxi_f) entry_ir_fr(str_f) entry_pm_fr(sti_f) entry_ir_ir_fr(stxr_f) entry_im_ir_fr(stxi_f) entry_lb_fr_fr(bltr_f) entry_lb_fr_fm(blti_f) entry_lb_fr_fr(bler_f) entry_lb_fr_fm(blei_f) entry_lb_fr_fr(beqr_f) entry_lb_fr_fm(beqi_f) entry_lb_fr_fr(bger_f) entry_lb_fr_fm(bgei_f) entry_lb_fr_fr(bgtr_f) entry_lb_fr_fm(bgti_f) entry_lb_fr_fr(bner_f) entry_lb_fr_fm(bnei_f) entry_lb_fr_fr(bunltr_f) entry_lb_fr_fm(bunlti_f) entry_lb_fr_fr(bunler_f) entry_lb_fr_fm(bunlei_f) entry_lb_fr_fr(buneqr_f) entry_lb_fr_fm(buneqi_f) entry_lb_fr_fr(bunger_f) entry_lb_fr_fm(bungei_f) entry_lb_fr_fr(bungtr_f) entry_lb_fr_fm(bungti_f) entry_lb_fr_fr(bltgtr_f) entry_lb_fr_fm(bltgti_f) entry_lb_fr_fr(bordr_f) entry_lb_fr_fm(bordi_f) entry_lb_fr_fr(bunordr_f) entry_lb_fr_fm(bunordi_f) entry_fr(pushargr_f) entry_fm(pushargi_f) entry_fr(retr_f) entry_fm(reti_f) entry_fr(retval_f) entry_ca(arg_d) entry_fa(getarg_d) entry_fa(putargr_d) entry_fma(putargi_d) entry_fr_fr_fr(addr_d) entry_fr_fr_dm(addi_d) entry_fr_fr_fr(subr_d) entry_fr_fr_dm(subi_d) entry_fr_fr_fr(rsbr_d) entry_fr_fr_dm(rsbi_d) entry_fr_fr_fr(mulr_d) entry_fr_fr_dm(muli_d) entry_fr_fr_fr(divr_d) entry_fr_fr_dm(divi_d) entry_fr_fr(negr_d) entry_fr_fr(absr_d) entry_fr_fr(sqrtr_d) entry_ir_fr_fr(ltr_d) entry_ir_fr_dm(lti_d) entry_ir_fr_fr(ler_d) entry_ir_fr_dm(lei_d) entry_ir_fr_fr(eqr_d) entry_ir_fr_dm(eqi_d) entry_ir_fr_fr(ger_d) entry_ir_fr_dm(gei_d) entry_ir_fr_fr(gtr_d) entry_ir_fr_dm(gti_d) entry_ir_fr_fr(ner_d) entry_ir_fr_dm(nei_d) entry_ir_fr_fr(unltr_d) entry_ir_fr_dm(unlti_d) entry_ir_fr_fr(unler_d) entry_ir_fr_dm(unlei_d) entry_ir_fr_fr(uneqr_d) entry_ir_fr_dm(uneqi_d) entry_ir_fr_fr(unger_d) entry_ir_fr_dm(ungei_d) entry_ir_fr_fr(ungtr_d) entry_ir_fr_dm(ungti_d) entry_ir_fr_fr(ltgtr_d) entry_ir_fr_dm(ltgti_d) entry_ir_fr_fr(ordr_d) entry_ir_fr_dm(ordi_d) entry_ir_fr_fr(unordr_d) entry_ir_fr_dm(unordi_d) entry_ir_fr(truncr_d_i) #if __WORDSIZE == 64 entry_ir_fr(truncr_d_l) #endif entry_ir_fr(truncr_d) entry_fr_ir(extr_d) entry_fr_fr(extr_f_d) entry_fr_fr(movr_d) entry_fr_dm(movi_d) entry_fr_ir(ldr_d) entry_fr_pm(ldi_d) entry_fr_ir_ir(ldxr_d) entry_fr_ir_im(ldxi_d) entry_ir_fr(str_d) entry_pm_fr(sti_d) entry_ir_ir_fr(stxr_d) entry_im_ir_fr(stxi_d) entry_lb_fr_fr(bltr_d) entry_lb_fr_dm(blti_d) entry_lb_fr_fr(bler_d) entry_lb_fr_dm(blei_d) entry_lb_fr_fr(beqr_d) entry_lb_fr_dm(beqi_d) entry_lb_fr_fr(bger_d) entry_lb_fr_dm(bgei_d) entry_lb_fr_fr(bgtr_d) entry_lb_fr_dm(bgti_d) entry_lb_fr_fr(bner_d) entry_lb_fr_dm(bnei_d) entry_lb_fr_fr(bunltr_d) entry_lb_fr_dm(bunlti_d) entry_lb_fr_fr(bunler_d) entry_lb_fr_dm(bunlei_d) entry_lb_fr_fr(buneqr_d) entry_lb_fr_dm(buneqi_d) entry_lb_fr_fr(bunger_d) entry_lb_fr_dm(bungei_d) entry_lb_fr_fr(bungtr_d) entry_lb_fr_dm(bungti_d) entry_lb_fr_fr(bltgtr_d) entry_lb_fr_dm(bltgti_d) entry_lb_fr_fr(bordr_d) entry_lb_fr_dm(bordi_d) entry_lb_fr_fr(bunordr_d) entry_lb_fr_dm(bunordi_d) entry_fr(pushargr_d) entry_dm(pushargi_d) entry_fr(retr_d) entry_dm(reti_d) entry_fr(retval_d) static void vastart(void) { jit_gpr_t r0 = get_ireg(); jit_va_start(r0); } static void vapush(void) { jit_gpr_t r0 = get_ireg(); jit_va_push(r0); } static void vaarg(void) { jit_gpr_t r0 = get_ireg(), r1 = get_ireg(); jit_va_arg(r0, r1); } static void vaarg_d(void) { jit_fpr_t r0 = get_freg(); jit_gpr_t r1 = get_ireg(); jit_va_arg_d(r0, r1); } static void vaend(void) { jit_gpr_t r0 = get_ireg(); jit_va_end(r0); } #undef entry_fn #undef entry_fm #undef entry_dm #undef entry_lb_fr_fm #undef entry_lb_fr_dm #undef entry_lb_fr_fr #undef entry_im_ir_fr #undef entry_ir_ir_fr #undef entry_pm_fr #undef entry_fr_ir_ir #undef entry_fr_ir_im #undef entry_fr_pm #undef entry_fr_fm #undef entry_fr_dm #undef entry_fr_ir #undef entry_ir_fr #undef entry_ir_fr_fm #undef entry_ir_fr_dm #undef entry_ir_fr_fr #undef entry_fr_fr #undef entry_fr_fr_fm #undef entry_fr_fr_dm #undef entry_fr_fr_fr #undef entry_fma #undef entry_fa #undef entry_pm #undef entry_lb #undef entry_lb_ir_im #undef entry_lb_ir_ir #undef entry_im_ir_ir #undef entry_pm_ir #undef entry_ir_pm #undef entry_ir_im #undef entry_ir_ir #undef entry_ir_ir_im #undef entry_ir_ir_ir #undef entry_ima #undef entry_ir #undef entry_im #undef entry_ia #undef entry_ca #undef entry static void error(const char *format, ...) { va_list ap; int length; char *string; va_start(ap, format); message("error", format, ap); va_end(ap); length = parser.data.length - parser.data.offset; string = (char *)(parser.data.buffer + parser.data.offset - 1); if (length > 77) strcpy(string + 74, "..."); else parser.data.buffer[parser.data.length - 1] = '\0'; fprintf(stderr, "(%s)\n", string); exit(-1); } static void warn(const char *format, ...) { va_list ap; va_start(ap, format); message("warning", format, ap); va_end(ap); } static void message(const char *kind, const char *format, va_list ap) { fprintf(stderr, "%s:%d: %s: ", parser.name, parser.line - parser.newline, kind); vfprintf(stderr, format, ap); fputc('\n', stderr); } static int getch(void) { int ch; if (parser.data.offset < parser.data.length) ch = parser.data.buffer[parser.data.offset++]; else { /* keep first offset for ungetch */ if ((parser.data.length = fread(parser.data.buffer + 1, 1, sizeof(parser.data.buffer) - 1, parser.fp) + 1) <= 1) { ch = EOF; parser.data.offset = 1; } else { ch = parser.data.buffer[1]; parser.data.offset = 2; } } if ((parser.newline = ch == '\n')) ++parser.line; return (ch); } static int getch_noeof(void) { int ch = getch(); if (ch == EOF) error("unexpected end of file"); return (ch); } static int ungetch(int ch) { if ((parser.newline = ch == '\n')) --parser.line; if (parser.data.offset) parser.data.buffer[--parser.data.offset] = ch; else /* overwrite */ parser.data.buffer[0] = ch; return (ch); } static int skipws(void) { int ch; for (ch = getch();; ch = getch()) { switch (ch) { case '/': ch = skipct(); break; case '#': ch = skipcp(); break; } switch (ch) { case ' ': case '\f': case '\r': case '\t': break; default: return (ch); } } } static int skipnl(void) { int ch; for (ch = getch();; ch = getch()) { switch (ch) { case '/': ch = skipct(); break; case '#': ch = skipcp(); break; } switch (ch) { case ' ': case '\f': case '\n': case '\r': case '\t': break; /* handle as newline */ case ';': break; default: return (ch); } } } static int skipct(void) { int ch; ch = getch(); switch (ch) { case '/': for (ch = getch(); ch != '\n' && ch != EOF; ch = getch()) ; return (ch); case '*': for (; ch != '/';) { while (getch_noeof() != '*') ; while ((ch = getch_noeof()) == '*') ; } return (getch()); default: ungetch(ch); return ('/'); } } static int skipcp(void) { int ch; for (ch = getch(); ch != '\n' && ch != EOF; ch = getch()) { switch (ch) { case '0' ... '9': if ((number(ch)) == tok_int) parser.line = parser.value.i - 1; break; case '"': string(); if (parser.offset >= (int)sizeof(parser.name)) { strncpy(parser.name, parser.string, sizeof(parser.name)); parser.name[sizeof(parser.name) - 1] = '\0'; } else strcpy(parser.name, parser.string); break; default: break; } } return (ch); } static jit_word_t get_int(skip_t skip) { switch (primary(skip)) { case tok_int: break; case tok_pointer: parser.type = type_l; parser.value.i = (jit_word_t)parser.value.p; break; default: error("expecting integer"); } return (parser.value.i); } static jit_uword_t get_uint(skip_t skip) { switch (primary(skip)) { case tok_char: case tok_int: break; case tok_pointer: parser.type = type_l; parser.value.ui = (jit_uword_t)parser.value.p; break; default: error("expecting integer"); } return (parser.value.ui); } static double get_float(skip_t skip) { switch (primary(skip)) { case tok_char: case tok_int: parser.type = type_d; parser.value.d = parser.value.i; break; case tok_float: break; default: error("expecting float"); } return (parser.value.d); } /* Workaround gcc not converting unordered values from double to * float (as done in other architectures) on s390 */ static float make_float(double d) { /* This is an workaround to a bug in Hercules s390 emulator, * and at least HP-UX ia64 not have these */ #if defined(HAVE_ISNAN) && defined(HAVE_ISINF) if (isnan(d)) return ( 0.0f/0.0f); if (isinf(d)) { if (d > 0.0) return ( 1.0f/0.0f); else return (-1.0f/0.0f); } #endif return ((float)d); } static void * get_pointer(skip_t skip) { label_t *label; token_t token = primary(skip); switch (token) { case tok_symbol: label = get_label_by_name(parser.string); if (label == NULL) error("bad identifier %s", parser.string); switch (label->kind) { case label_kind_data: case label_kind_code: break; case label_kind_code_forward: /* as expression arguments */ error("forward references not implemented"); break; case label_kind_dynamic: break; } parser.type = type_p; return (parser.value.p = label->value); case tok_int: parser.type = type_p; return (parser.value.p = (void *)parser.value.ui); case tok_pointer: return (parser.value.p); default: error("bad pointer"); } } static label_t * get_label(skip_t skip) { label_t *label; int ch = skipws(); switch (ch) { case '@': (void)dynamic(); break; case 'a' ... 'z': case 'A' ... 'Z': case '_': (void)identifier(ch); break; default: error("expecting label/immediate"); } if ((label = get_label_by_name(parser.string)) == NULL) label = new_label(label_kind_code_forward, parser.string, jit_forward()); return (label); } static token_t regname(void) { jit_word_t num; int check = 1, ch = getch(); switch (ch) { case 'r': parser.regtype = type_l; switch (ch = getch()) { case '0': parser.regval = JIT_R0; break; case '1': parser.regval = JIT_R1; break; case '2': parser.regval = JIT_R2; break; case '(': num = get_int(skip_none); if (num < 0 || num >= JIT_R_NUM) goto fail; parser.regval = JIT_R(num); if (getch() != ')') goto fail; check = 0; break; default: goto fail; } break; case 'v': parser.regtype = type_l; switch (ch = getch()) { case '0': parser.regval = JIT_V0; break; case '1': parser.regval = JIT_V1; break; case '2': parser.regval = JIT_V2; break; default: goto fail; case '(': num = get_int(skip_none); if (num < 0 || num >= JIT_V_NUM) goto fail; parser.regval = JIT_V(num); if (getch() != ')') goto fail; check = 0; break; } break; case 'f': parser.regtype = type_d; switch (ch = getch()) { case '0': parser.regval = JIT_F0; break; case '1': parser.regval = JIT_F1; break; case '2': parser.regval = JIT_F2; break; case '3': parser.regval = JIT_F3; break; case '4': parser.regval = JIT_F4; break; case '5': parser.regval = JIT_F5; break; case 'p': parser.regtype = type_l; /* oops */ parser.regval = JIT_FP; break; case '(': num = get_int(skip_none); if (num < 0 || num >= JIT_F_NUM) goto fail; parser.regval = JIT_F(num); if (getch() != ')') goto fail; check = 0; break; default: goto fail; } break; default: fail: error("bad register"); } if (check) { ch = getch(); if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_') goto fail; ungetch(ch); } return (tok_register); } static token_t identifier(int ch) { parser.string[0] = ch; for (parser.offset = 1;;) { switch ((ch = getch())) { case 'a' ... 'z': case 'A' ... 'Z': case '0' ... '9' : case '_': if (parser.offset + 1 >= MAX_IDENTIFIER) { parser.string[parser.offset] = '\0'; error("bad identifier %s", parser.string); } parser.string[parser.offset++] = ch; break; default: parser.string[parser.offset] = '\0'; ungetch(ch); return (tok_symbol); } } } static void get_data(type_t type) { int ch; token_t token; char *test = data; for (;;) { switch (type) { case type_c: switch (token = primary(skip_ws)) { case tok_char: case tok_int: check_data(sizeof(signed char)); *(signed char *)(data + data_offset) = parser.value.i; data_offset += sizeof(char); break; case tok_string: check_data(parser.offset); memcpy(data + data_offset, parser.string, parser.offset); data_offset += parser.offset; break; case tok_newline: case tok_semicollon: if (test == data) error("syntax error"); return; default: error("bad initializer"); } break; case type_s: check_data(sizeof(signed short)); *(signed short *)(data + data_offset) = get_int(skip_ws); data_offset += sizeof(short); break; case type_i: check_data(sizeof(signed int)); *(signed int *)(data + data_offset) = get_int(skip_ws); data_offset += sizeof(int); break; case type_l: check_data(sizeof(jit_word_t)); *(jit_word_t *)(data + data_offset) = get_int(skip_ws); data_offset += sizeof(jit_word_t); break; case type_f: check_data(sizeof(float)); *(float *)(data + data_offset) = get_float(skip_ws); data_offset += sizeof(float); break; case type_d: check_data(sizeof(double)); *(double *)(data + data_offset) = get_float(skip_ws); data_offset += sizeof(double); break; case type_p: /* FIXME **patch if realloc** */ check_data(sizeof(void*)); *(void **)(data + data_offset) = get_pointer(skip_ws); data_offset += sizeof(void*); break; default: abort(); } ch = skipws(); if (ch == '\n' || ch == ';' || ch == EOF) break; ungetch(ch); } } static void dot(void) { int ch; size_t offset, length; switch (ch = getch_noeof()) { case '$': /* use .$(expression) for non side effects expression */ (void)expression(); return; case 'a' ... 'z': case 'A' ... 'Z': case '_': (void)identifier(ch); break; default: ungetch(ch); if (skipws() != '$') error("expecting symbol"); /* allow spaces before an expression */ (void)expression(); return; } if (parser.string[1] == '\0') { switch (parser.string[0]) { case 'c': get_data(type_c); break; case 's': get_data(type_s); break; case 'i': get_data(type_i); break; case 'l': get_data(type_l); break; case 'f': get_data(type_f); break; case 'd': get_data(type_d); break; case 'p': get_data(type_p); break; default: error("bad type .%c", parser.string[0]); } } else if (strcmp(parser.string, "data") == 0) { if (parser.parsing != PARSING_NONE) error(".data must be specified once and be the first section"); parser.parsing = PARSING_DATA; data_length = get_int(skip_ws); data = (char *)xcalloc(1, data_length); } else if (strcmp(parser.string, "code") == 0) { if (parser.parsing != PARSING_NONE && parser.parsing != PARSING_DATA) error(".code must be specified once only"); parser.parsing = PARSING_CODE; } else if (strcmp(parser.string, "align") == 0) { length = get_int(skip_ws); if (parser.parsing != PARSING_DATA) error(".align must be in .data"); if (length > 1 && length <= 4096 && !(length & (length - 1))) { offset = data_offset; offset += length - ((offset + length) % length); check_data(offset - data_offset); data_offset = offset; } else error("bad .align %ld (must be a power of 2, >= 2 && <= 4096)", (jit_word_t)length); } else if (strcmp(parser.string, "size") == 0) { length = get_int(skip_ws); if (parser.parsing != PARSING_DATA) error(".size must be in .data"); check_data(length); data_offset += length; } else if (strcmp(parser.string, "disasm") == 0) flag_disasm = 1; else error("unknown command .%s", parser.string); } static token_t number(int ch) { char buffer[1024], *endptr; int integer = 1, offset = 0, neg = 0, e = 0, d = 0, base = 10; for (;; ch = getch()) { switch (ch) { case '-': if (offset == 0) { neg = 1; continue; } if (offset && buffer[offset - 1] != 'e') { ungetch(ch); goto done; } break; case '+': if (offset == 0) continue; if (offset && buffer[offset - 1] != 'e') { ungetch(ch); goto done; } break; case '.': if (d) goto fail; d = 1; base = 10; integer = 0; break; case '0': if (offset == 0 && base == 10) { base = 8; continue; } break; case 'b': if (offset == 0 && base == 8) { base = 2; continue; } if (base != 16) goto fail; break; case '1': break; case '2' ... '7': if (base < 8) goto fail; break; case '8': case '9': if (base < 10) goto fail; break; case 'x': if (offset == 0 && base == 8) { base = 16; continue; } goto fail; case 'a': case 'c': case 'd': case 'f': if (base < 16) goto fail; break; case 'e': if (e) goto fail; if (base != 16) { e = 1; base = 10; integer = 0; } break; case '_': case 'g' ... 'w': case 'y': case 'z': case 'A' ... 'Z': fail: buffer[offset++] = '\0'; error("bad constant %s", buffer); default: ungetch(ch); goto done; } if (offset + 1 >= (int)sizeof(buffer)) goto fail; buffer[offset++] = ch; } done: /* check for literal 0 */ if (offset == 0 && base == 8) buffer[offset++] = '0'; buffer[offset] = '\0'; if (integer) { #if _WIN32 # define STRTOUL strtoull #else # define STRTOUL strtoul #endif parser.value.ui = STRTOUL(buffer, &endptr, base); parser.type = type_l; if (neg) parser.value.i = -parser.value.i; } else { parser.type = type_d; parser.value.d = strtod(buffer, &endptr); if (neg) parser.value.d = -parser.value.d; } if (*endptr) goto fail; return (integer ? tok_int : tok_float); } static int escape(int ch) { switch (ch) { case 'a': ch = '\a'; break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case 'v': ch = '\v'; break; default: break; } return (ch); } static token_t string(void) { int ch, esc = 0; for (parser.offset = 0;;) { switch (ch = getch_noeof()) { case '\\': if (esc) goto append; esc = 1; break; case '"': if (!esc) { parser.string[parser.offset++] = '\0'; parser.value.p = parser.string; parser.type = type_p; return (tok_string); } /* FALLTHROUGH */ default: append: if (esc) { ch = escape(ch); esc = 0; } if (parser.offset + 1 >= parser.length) { parser.length += 4096; parser.string = (char *)xrealloc(parser.string, parser.length); } parser.string[parser.offset++] = ch; break; } } } static token_t character(void) { int ch, esc = 0; if ((ch = getch_noeof()) == '\\') { esc = 1; ch = getch(); } if (getch_noeof() != '\'') error("bad single byte char"); if (esc) ch = escape(ch); parser.type = type_l; parser.value.i = ch & 0xff; return (tok_char); } static token_t dynamic(void) { label_t *label; void *value; char *string; (void)identifier('@'); if ((label = get_label_by_name(parser.string)) == NULL) { #if __CYGWIN__ ||_WIN32 /* FIXME kludge to pass varargs test case, otherwise, * will not print/scan float values */ if (strcmp(parser.string + 1, "sprintf") == 0) value = sprintf; else if (strcmp(parser.string + 1, "sscanf") == 0) value = sscanf; else #endif { value = dlsym(DL_HANDLE, parser.string + 1); if ((string = dlerror())) error("%s", string); } label = new_label(label_kind_dynamic, parser.string, value); } parser.type = type_p; parser.value.p = label->value; return (tok_pointer); } static void expression_prim(void) { int ch; token_t token; label_t *label; symbol_t *symbol; if (parser.putback) { parser.expr = parser.putback; parser.putback = (expr_t)0; return; } switch (ch = skipws()) { case '!': if ((ch = getch_noeof()) == '=') parser.expr = expr_ne; else { ungetch(ch); parser.expr = expr_not; } break; case '~': parser.expr = expr_com; break; case '*': if ((ch = getch_noeof()) == '=') parser.expr = expr_mulset; else { ungetch(ch); parser.expr = expr_mul; } break; case '/': if ((ch = getch_noeof()) == '=') parser.expr = expr_divset; else { ungetch(ch); parser.expr = expr_div; } break; case '%': if ((ch = getch_noeof()) == '=') parser.expr = expr_remset; else { ungetch(ch); parser.expr = expr_rem; } break; case '+': switch (ch = getch_noeof()) { case '+': parser.expr = expr_inc; break; case '=': parser.expr = expr_addset; break; default: ungetch(ch); parser.expr = expr_add; break; } break; case '-': switch (ch = getch_noeof()) { case '-': parser.expr = expr_dec; break; case '=': parser.expr = expr_subset; break; default: ungetch(ch); parser.expr = expr_sub; break; } break; case '<': switch (ch = getch_noeof()) { case '=': parser.expr = expr_le; break; case '<': ch = getch_noeof(); if (ch == '=') parser.expr = expr_lshset; else { ungetch(ch); parser.expr = expr_lsh; } break; default: ungetch(ch); parser.expr = expr_lt; break; } break; case '>': switch (ch = getch_noeof()) { case '=': parser.expr = expr_ge; break; case '>': ch = getch_noeof(); if (ch == '=') parser.expr = expr_rshset; else { ungetch(ch); parser.expr = expr_rsh; } break; default: ungetch(ch); parser.expr = expr_gt; break; } break; case '&': switch (ch = getch_noeof()) { case '=': parser.expr = expr_andset; break; case '&': parser.expr = expr_andand; break; default: ungetch(ch); parser.expr = expr_and; break; } break; case '|': switch (ch = getch_noeof()) { case '=': parser.expr = expr_orset; break; case '|': parser.expr = expr_oror; break; default: ungetch(ch); parser.expr = expr_or; break; } break; case '^': if ((ch = getch_noeof()) == '=') parser.expr = expr_xorset; else { ungetch(ch); parser.expr = expr_xor; } break; case '=': if ((ch = getch_noeof()) == '=') parser.expr = expr_eq; else { ungetch(ch); parser.expr = expr_set; } break; case '(': parser.expr = expr_lparen; break; case ')': parser.expr = expr_rparen; break; case '0' ... '9': token = number(ch); parser.expr = token == tok_int ? expr_int : expr_float; break; case '@': (void)dynamic(); parser.expr = expr_pointer; break; case '$': identifier('$'); /* no support for nested expressions */ if (parser.string[0] == '\0') error("syntax error"); parser.expr = expr_symbol; if ((symbol = get_symbol_by_name(parser.string)) != NULL) { parser.type = symbol->type; parser.value = symbol->value; } else /* only create symbol on assignment */ parser.type = type_none; break; case 'a' ... 'z': case 'A' ... 'Z': case '_': identifier(ch); if ((label = get_label_by_name(parser.string))) { if (label->kind == label_kind_code_forward) error("forward value for %s not supported", parser.string); parser.expr = expr_pointer; parser.type = type_p; parser.value.p = label->value; } else error("invalid identifier %s", parser.string); break; case '\'': character(); parser.expr = expr_int; break; case '"': /* not smart enough to put it in data and/or relocate it, etc */ error("must declare strings as data"); default: error("syntax error"); } } static void expression_inc(int pre) { symbol_t *symbol; if (pre) { expression_prim(); if (parser.expr != expr_symbol) error("syntax error"); } if ((symbol = get_symbol_by_name(parser.string)) == NULL) { if (!parser.short_circuit) error("undefined symbol %s", symbol->name); } if (!parser.short_circuit) { parser.type = symbol->type; if (!pre) parser.value = symbol->value; switch (symbol->type) { case type_l: ++symbol->value.i; break; case type_d: /* should really be an error */ symbol->value.d += 1.0; break; default: ++parser.value.cp; break; } if (pre) parser.value = symbol->value; } expression_prim(); } static void expression_dec(int pre) { symbol_t *symbol; if (pre) { expression_prim(); if (parser.expr != expr_symbol) error("syntax error"); } if ((symbol = get_symbol_by_name(parser.string)) == NULL) { if (!parser.short_circuit) error("undefined symbol %s", symbol->name); } if (!parser.short_circuit) { parser.type = symbol->type; if (!pre) parser.value = symbol->value; switch (symbol->type) { case type_l: --symbol->value.i; break; case type_d: /* should really be an error */ symbol->value.d -= 1.0; break; default: --parser.value.cp; break; } if (pre) parser.value = symbol->value; } expression_prim(); } static void expression_unary(void) { symbol_t *symbol; char buffer[256]; expression_prim(); switch (parser.expr) { case expr_add: expression_unary(); switch (parser.type) { case type_l: case type_d: break; default: error("syntax error"); } break; case expr_sub: expression_unary(); switch (parser.type) { case type_l: parser.value.i = -parser.value.i; break; case type_d: parser.value.d = -parser.value.d; break; default: error("syntax error"); } break; case expr_inc: expression_inc(1); break; case expr_dec: expression_dec(1); break; case expr_not: expression_unary(); switch (parser.type) { case type_l: parser.value.i = !parser.value.i; break; case type_d: parser.value.i = parser.value.d != 0; break; case type_p: parser.value.i = parser.value.p != NULL; break; default: error("syntax error"); } parser.type = type_l; break; case expr_com: expression_unary(); if (parser.type != type_l) error("syntax error"); parser.value.i = ~parser.value.i; break; case expr_lparen: expression_cond(); if (parser.expr != expr_rparen) error("syntax error"); expression_prim(); break; case expr_symbol: strcpy(buffer, parser.string); expression_prim(); switch (parser.expr) { case expr_set: if ((symbol = get_symbol_by_name(buffer)) == NULL) { if (!parser.short_circuit) symbol = new_symbol(buffer); } expression_cond(); set: if (!parser.short_circuit) { if (symbol == NULL) error("syntax error"); symbol->type = parser.type; symbol->value = parser.value; } break; case expr_mulset: parser.putback = expr_mul; goto check; case expr_divset: parser.putback = expr_div; goto check; case expr_remset: parser.putback = expr_rem; goto check; case expr_addset: parser.putback = expr_add; goto check; case expr_subset: parser.putback = expr_sub; goto check; case expr_lshset: parser.putback = expr_lsh; goto check; case expr_rshset: parser.putback = expr_rsh; goto check; case expr_andset: parser.putback = expr_and; goto check; case expr_orset: parser.putback = expr_or; goto check; case expr_xorset: parser.putback = expr_xor; check: if ((symbol = get_symbol_by_name(buffer)) == NULL) { if (!parser.short_circuit) error("undefined symbol %s", buffer); parser.type = type_l; parser.value.i = 1; } switch (parser.putback) { case expr_mul: case expr_div: case expr_rem: expression_mul(); break; case expr_add: case expr_sub: expression_add(); break; case expr_lsh: case expr_rsh: expression_shift(); break; case expr_and: case expr_or: case expr_xor: expression_bit(); break; default: abort(); } goto set; case expr_inc: expression_inc(0); break; case expr_dec: expression_dec(0); break; default: break; } break; case expr_int: case expr_float: case expr_pointer: /* make next token available */ expression_prim(); default: break; } } static void expression_mul(void) { type_t type; value_t value; expression_unary(); switch (parser.type) { case type_l: case type_d: case type_p: break; default: return; } for (;;) { switch (parser.expr) { case expr_mul: type = parser.type, value = parser.value; expression_unary(); switch (parser.type) { case type_l: if (type == type_l) value.i *= parser.value.i; else value.d *= parser.value.i; break; case type_d: if (type == type_l) { type = type_d; value.d = value.i; } value.d *= parser.value.d; break; default: error("invalid operand"); } parser.type = type, parser.value = value; break; case expr_div: type = parser.type, value = parser.value; expression_unary(); switch (parser.type) { case type_l: if (type == type_l) { if (parser.value.i == 0) error("divide by zero"); value.i /= parser.value.i; } else value.d /= parser.value.i; break; case type_d: if (type == type_l) { type = type_d; value.d = value.i; } value.d /= parser.value.d; break; default: error("invalid operand"); } parser.type = type, parser.value = value; break; case expr_rem: type = parser.type, value = parser.value; expression_unary(); switch (parser.type) { case type_l: if (type == type_l) { if (parser.value.i == 0) error("divide by zero"); value.i %= parser.value.i; } else error("invalid operand"); break; default: error("invalid operand"); } parser.type = type, parser.value = value; break; default: return; } } } static void expression_add(void) { type_t type; value_t value; expression_mul(); switch (parser.type) { case type_l: case type_d: case type_p: break; default: return; } for (;;) { switch (parser.expr) { case expr_add: type = parser.type, value = parser.value; expression_mul(); switch (parser.type) { case type_l: switch (type) { case type_l: value.i += parser.value.i; break; case type_d: value.d += parser.value.i; break; default: value.cp += parser.value.i; break; } break; case type_d: switch (type) { case type_l: type = type_d; value.d = value.i; break; case type_d: break; default: error("invalid operand"); } value.d += parser.value.d; break; case type_p: switch (type) { case type_l: type = type_p; value.cp = value.i + parser.value.cp; break; default: error("invalid operand"); } break; default: error("invalid operand"); } parser.type = type, parser.value = value; break; case expr_sub: type = parser.type, value = parser.value; expression_mul(); switch (parser.type) { case type_l: switch (type) { case type_l: value.i -= parser.value.i; break; case type_d: value.d -= parser.value.i; break; default: value.cp -= parser.value.i; break; } break; case type_d: switch (type) { case type_l: type = type_d; value.d = value.i; break; case type_d: break; default: error("invalid operand"); } value.d -= parser.value.d; break; case type_p: switch (type) { case type_p: type = type_l; value.i = value.cp - parser.value.cp; break; default: error("invalid operand"); } break; default: error("invalid operand"); } parser.type = type, parser.value = value; break; default: return; } } } static void expression_shift(void) { jit_word_t value; expression_add(); switch (parser.type) { case type_l: case type_d: case type_p: break; default: return; } for (;;) { switch (parser.expr) { case expr_lsh: value = parser.value.i; if (parser.type != type_l) error("invalid operand"); expression_add(); if (parser.type != type_l) error("invalid operand"); value <<= parser.value.i; parser.value.i = value; break; case expr_rsh: value = parser.value.i; if (parser.type != type_l) error("invalid operand"); expression_add(); if (parser.type != type_l) error("invalid operand"); value >>= parser.value.i; parser.value.i = value; break; default: return; } } } static void expression_bit(void) { jit_word_t i; expression_shift(); switch (parser.type) { case type_l: case type_d: case type_p: break; default: return; } for (;;) { switch (parser.expr) { case expr_and: if (parser.type != type_l) error("invalid operand"); i = parser.value.i; expression_shift(); if (parser.type != type_l) error("invalid operand"); i &= parser.value.i; parser.value.i = i; break; case expr_or: if (parser.type != type_l) error("invalid operand"); i = parser.value.i; expression_shift(); if (parser.type != type_l) error("invalid operand"); i |= parser.value.i; parser.value.i = i; break; case expr_xor: if (parser.type != type_l) error("invalid operand"); i = parser.value.i; expression_shift(); if (parser.type != type_l) error("invalid operand"); i ^= parser.value.i; parser.value.i = i; break; default: return; } } } static void expression_rel(void) { type_t type; value_t value; expression_bit(); switch (parser.type) { case type_l: case type_d: case type_p: break; default: return; } for (;;) { switch (parser.expr) { case expr_lt: type = parser.type, value = parser.value; expression_bit(); switch (parser.type) { case type_l: switch (type) { case type_l: value.i = value.i < parser.value.i; break; case type_d: value.i = value.d < parser.value.i; break; default: value.i = (jit_word_t)value.p < parser.value.i; break; } break; case type_d: switch (type) { case type_l: value.i = value.i < parser.value.d; break; case type_d: value.i = value.d < parser.value.d; break; default: error("invalid operand"); } break; case type_p: switch (type) { case type_l: value.i = value.i < (jit_word_t)parser.value.p; break; case type_d: error("invalid operand"); default: value.i = (jit_word_t)value.p < (jit_word_t)parser.value.p; break; } break; default: error("invalid operand"); } parser.type = type_l, parser.value = value; break; case expr_le: type = parser.type, value = parser.value; expression_bit(); switch (parser.type) { case type_l: switch (type) { case type_l: value.i = value.i <= parser.value.i; break; case type_d: value.i = value.d <= parser.value.i; break; default: value.i = (jit_word_t)value.p <= parser.value.i; break; } break; case type_d: switch (type) { case type_l: value.i = value.i <= parser.value.d; break; case type_d: value.i = value.d <= parser.value.d; break; default: value.i = (jit_word_t)value.p <= parser.value.d; break; } break; case type_p: switch (type) { case type_l: value.i = value.i <= (jit_word_t)parser.value.p; break; case type_d: error("invalid operand"); default: value.i = (jit_word_t)value.p <= (jit_word_t)parser.value.p; break; } break; default: error("invalid operand"); } parser.type = type_l, parser.value = value; break; case expr_eq: type = parser.type, value = parser.value; expression_bit(); switch (parser.type) { case type_l: switch (type) { case type_l: value.i = value.i == parser.value.i; break; case type_d: value.i = value.d == parser.value.i; break; default: value.i = (jit_word_t)value.p == parser.value.i; break; } break; case type_d: switch (type) { case type_l: value.i = value.i == parser.value.d; break; case type_d: value.i = value.d == parser.value.d; break; default: error("invalid operand"); } break; case type_p: switch (type) { case type_l: value.i = value.i == (jit_word_t)parser.value.p; break; case type_d: error("invalid operand"); default: value.i = value.p == parser.value.p; break; } break; default: error("invalid operand"); } parser.type = type_l, parser.value = value; break; case expr_ge: type = parser.type, value = parser.value; expression_bit(); switch (parser.type) { case type_l: switch (type) { case type_l: value.i = value.i >= parser.value.i; break; case type_d: value.i = value.d >= parser.value.i; break; default: value.i = (jit_word_t)value.p >= parser.value.i; break; } break; case type_d: switch (type) { case type_l: value.i = value.i >= parser.value.d; break; case type_d: value.i = value.d >= parser.value.d; break; default: error("invalid operand"); } break; case type_p: switch (type) { case type_l: value.i = value.i >= (jit_word_t)parser.value.p; break; case type_d: error("invalid operand"); default: value.i = (jit_word_t)value.p >= (jit_word_t)parser.value.p; break; } break; default: error("invalid operand"); } parser.type = type_l, parser.value = value; break; case expr_gt: type = parser.type, value = parser.value; expression_bit(); switch (parser.type) { case type_l: switch (type) { case type_l: value.i = value.i > parser.value.i; break; case type_d: value.i = value.d > parser.value.i; break; default: value.i = (jit_word_t)value.p > parser.value.i; break; } break; case type_d: switch (type) { case type_l: value.i = value.i > parser.value.d; break; case type_d: value.i = value.d > parser.value.d; break; default: error("invalid operand"); } break; case type_p: switch (type) { case type_l: value.i = value.i > (jit_word_t)parser.value.p; break; case type_d: error("invalid operand"); default: value.i = (jit_word_t)value.p > (jit_word_t)parser.value.p; break; } break; default: error("invalid operand"); } parser.type = type_l, parser.value = value; break; case expr_ne: type = parser.type, value = parser.value; expression_bit(); switch (parser.type) { case type_l: switch (type) { case type_l: value.i = value.i != parser.value.i; break; case type_d: value.i = value.d != parser.value.i; break; default: value.i = (jit_word_t)value.p != parser.value.i; break; } break; case type_d: switch (type) { case type_l: value.i = value.i != parser.value.d; break; case type_d: value.i = value.d != parser.value.d; break; default: error("invalid operand"); } break; case type_p: switch (type) { case type_l: value.i = value.i != (jit_word_t)parser.value.p; break; case type_d: error("invalid operand"); default: value.i = value.p != parser.value.p; break; } break; default: error("invalid operand"); } parser.type = type_l, parser.value = value; break; default: return; } } } static void expression_cond(void) { type_t type; value_t value; int short_circuit; expression_rel(); switch (parser.type) { case type_l: case type_d: case type_p: break; default: return; } for (;;) { switch (parser.expr) { case expr_andand: type = parser.type, value = parser.value; switch (type) { case type_l: short_circuit = value.i == 0; break; case type_d: short_circuit = value.d == 0.0; break; default: short_circuit = value.p == NULL; break; } parser.short_circuit += short_circuit; expression_rel(); parser.short_circuit -= short_circuit; switch (parser.type) { case type_l: switch (type) { case type_l: value.i = value.i && parser.value.i; break; case type_d: value.i = value.d && parser.value.i; break; default: value.i = value.p && parser.value.i; break; } break; case type_d: switch (type) { case type_l: value.i = value.i && parser.value.d; break; case type_d: value.i = value.d && parser.value.d; break; default: value.i = value.p && parser.value.d; break; } break; case type_p: switch (type) { case type_l: value.i = value.i && parser.value.p; break; case type_d: value.i = value.d && parser.value.p; break; default: value.i = value.p && parser.value.p; break; } break; default: error("invalid operand"); } parser.type = type_l, parser.value.i = value.i; break; case expr_oror: type = parser.type, value = parser.value; switch (type) { case type_l: short_circuit = value.i != 0; break; case type_d: short_circuit = value.d != 0.0; break; default: short_circuit = value.p != NULL; break; } parser.short_circuit += short_circuit; expression_rel(); parser.short_circuit -= short_circuit; switch (parser.type) { case type_l: switch (type) { case type_l: value.i = value.i || parser.value.i; break; case type_d: value.i = value.d || parser.value.i; break; default: value.i = value.p || parser.value.i; break; } break; case type_d: switch (type) { case type_l: value.i = value.i || parser.value.d; break; case type_d: value.i = value.d || parser.value.d; break; default: value.i = value.p || parser.value.d; break; } break; case type_p: switch (type) { case type_l: value.i = value.i || parser.value.p; break; case type_d: value.i = value.d || parser.value.p; break; default: value.i = value.p || parser.value.p; break; } break; default: error("invalid operand"); } parser.type = type_l, parser.value.i = value.i; break; default: return; } } } static token_t expression(void) { symbol_t *symbol; (void)identifier('$'); if (parser.string[1] == '\0') { if (getch_noeof() != '(') error("bad symbol or expression"); parser.type = type_none; expression_cond(); if (parser.expr != expr_rparen) error("bad expression"); switch (parser.type) { case type_l: return (tok_int); case type_d: return (tok_float); case type_p: return (tok_pointer); default: error("bad expression"); } } else if ((symbol = get_symbol_by_name(parser.string))) { switch (parser.type = symbol->type) { case type_l: parser.value.i = symbol->value.i; return (tok_int); case type_d: parser.value.d = symbol->value.d; return (tok_float); default: parser.value.p = symbol->value.p; return (tok_pointer); } } else error("undefined symbol %s", parser.string); } static token_t primary(skip_t skip) { int ch; switch (skip) { case skip_none: ch = getch(); break; case skip_ws: ch = skipws(); break; case skip_nl: ch = skipnl(); break; default: abort(); } switch (ch) { case '%': return (regname()); case 'a' ... 'z': case 'A' ... 'Z': case '_': return (identifier(ch)); case '0' ... '9': case '+': case '-': return (number(ch)); case '.': return (tok_dot); case '"': return (string()); case '\'': return (character()); case '@': return (dynamic()); case '$': return (expression()); case EOF: return (tok_eof); case '\n': return (tok_newline); case ';': return (tok_semicollon); default: error("syntax error"); } } static void parse(void) { int ch; token_t token; instr_t *instr; label_t *label; void *value; for (;;) { switch (token = primary(skip_nl)) { case tok_symbol: ch = getch_noeof(); if (ch == ':') { if ((label = get_label_by_name(parser.string))) { if (label->kind == label_kind_code_forward) { label->kind = label_kind_code; jit_link(label->value); jit_note(parser.name, parser.line); } else error("label %s: redefined", parser.string); } else { if (parser.parsing == PARSING_DATA) { value = data + data_offset; label = new_label(label_kind_data, parser.string, value); } else if (parser.parsing == PARSING_CODE) { value = jit_label(); jit_note(parser.name, parser.line); label = new_label(label_kind_code, parser.string, value); } else error("label not in .code or .data"); } break; } ungetch(ch); if ((instr = (instr_t *)get_hash(instrs, parser.string)) == NULL) error("unhandled symbol %s", parser.string); if (parser.parsing != PARSING_CODE) error(".code must be specified before instructions"); (*instr->function)(); break; case tok_dot: dot(); break; case tok_eof: return; default: error("syntax error"); } } } static int execute(int argc, char *argv[]) { int result; label_t *label; function_t function; patch_t *patch, *next; for (patch = patches; patch; patch = next) { next = patch->next; label = patch->label; if (label->kind == label_kind_code_forward) error("undefined label %s", label->name); switch (patch->kind) { case patch_kind_jmp: case patch_kind_mov: case patch_kind_call: jit_patch_at(patch->value, label->value); break; default: abort(); } free(patch); patch = next; } if (flag_data == 0) { jit_realize(); jit_set_data(NULL, 0, JIT_DISABLE_DATA | JIT_DISABLE_NOTE); } function = jit_emit(); if (flag_verbose > 1 || flag_disasm) { jit_print(); fprintf(stdout, " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"); } if (flag_verbose > 0 || flag_disasm) { jit_disassemble(); fprintf(stdout, " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"); } jit_clear_state(); if (flag_disasm) result = 0; else result = (*function)(argc, argv); jit_destroy_state(); return (result); } static void * xmalloc(size_t size) { void *pointer = malloc(size); if (pointer == NULL) error("out of memory"); return (pointer); } static void * xrealloc(void *pointer, size_t size) { pointer = realloc(pointer, size); if (pointer == NULL) error("out of memory"); return (pointer); } static void * xcalloc(size_t nmemb, size_t size) { void *pointer = calloc(nmemb, size); if (pointer == NULL) error("out of memory"); return (pointer); } static label_t * new_label(label_kind_t kind, char *name, void *value) { label_t *label; label = (label_t *)xmalloc(sizeof(label_t)); label->kind = kind; label->name = strdup(name); label->value = value; put_hash(labels, (entry_t *)label); label_offset++; return (label); } static patch_t * new_patch(patch_kind_t kind, label_t *label, void *value) { patch_t *patch = (patch_t *)xmalloc(sizeof(patch_t)); patch->kind = kind; patch->label = label; patch->value = value; patch->next = patches; patches = patch; return (patch); } static int bcmp_symbols(const void *left, const void *right) { return (strcmp((char *)left, (*(symbol_t **)right)->name)); } static int qcmp_symbols(const void *left, const void *right) { return (strcmp((*(symbol_t **)left)->name, (*(symbol_t **)right)->name)); } static symbol_t * new_symbol(char *name) { symbol_t *symbol; if ((symbol_offset & 15) == 0) { if ((symbol_length += 16) == 16) symbols = (symbol_t **)xmalloc(sizeof(symbol_t *) * symbol_length); else symbols = (symbol_t **)xrealloc(symbols, sizeof(symbol_t *) * symbol_length); } symbol = (symbol_t *)xmalloc(sizeof(symbol_t)); symbol->name = strdup(name); symbols[symbol_offset++] = symbol; qsort(symbols, symbol_offset, sizeof(symbol_t *), qcmp_symbols); return (symbol); } static symbol_t * get_symbol_by_name(char *name) { symbol_t **symbol_pointer; if (symbols == NULL) return (NULL); symbol_pointer = (symbol_t **)bsearch(name, symbols, symbol_offset, sizeof(symbol_t *), bcmp_symbols); return (symbol_pointer ? *symbol_pointer : NULL); } static hash_t * new_hash(void) { hash_t *hash; hash = (hash_t *)xmalloc(sizeof(hash_t)); hash->count = 0; hash->entries = (entry_t **)xcalloc(hash->size = 32, sizeof(void *)); return (hash); } static int hash_string(char *name) { char *ptr; int key; for (key = 0, ptr = name; *ptr; ptr++) key = (key << (key & 1)) ^ *ptr; return (key); } static void put_hash(hash_t *hash, entry_t *entry) { entry_t *prev, *ptr; int key = hash_string(entry->name) & (hash->size - 1); for (prev = ptr = hash->entries[key]; ptr; prev = ptr, ptr = ptr->next) { if (strcmp(entry->name, ptr->name) == 0) error("duplicated entry %s", entry->name); } if (prev == NULL) hash->entries[key] = entry; else prev->next = entry; entry->next = NULL; ++hash->count; if (hash->count > hash->size * 0.75) rehash(hash); } static entry_t * get_hash(hash_t *hash, char *name) { entry_t *entry; int key = hash_string(name) & (hash->size - 1); for (entry = hash->entries[key]; entry; entry = entry->next) { if (strcmp(entry->name, name) == 0) return (entry); } return (NULL); } static void rehash(hash_t *hash) { int i, size, key; entry_t *entry, *next, **entries; entries = (entry_t **)xcalloc(size = hash->size * 2, sizeof(void *)); for (i = 0; i < hash->size; i++) { for (entry = hash->entries[i]; entry; entry = next) { next = entry->next; key = hash_string(entry->name) & (size - 1); entry->next = entries[key]; entries[key] = entry; } } free(hash->entries); hash->entries = entries; hash->size = size; } static void usage(void) { #if HAVE_GETOPT_LONG_ONLY fprintf(stderr, "\ Usage: %s [jit assembler options] file [jit program options]\n\ Jit assembler options:\n\ -help Display this information\n\ -v[0-3] Verbose output level\n\ -d Do not use a data buffer\n\ -D[=] Preprocessor options\n" # if defined(__i386__) && __WORDSIZE == 32 " -mx87=1 Force using x87 when sse2 available\n" # endif # if defined(__i386__) || defined(__x86_64__) " -msse4_1=0 Do not use sse4_1 instructions when available\n" # endif # if defined(__arm__) " -mcpu= Force cpu version (4, 5, 6 or 7)\n\ -mthumb[=0|1] Enable or disable thumb\n\ -mvfp= Set vpf version (0 to disable)\n\ -mneon[=0|1] Enable or disable neon\n" # endif , progname); #else fprintf(stderr, "\ Usage: %s [jit assembler options] file [jit program options]\n\ Jit assembler options:\n\ -h Display this information\n\ -v Verbose output level\n\ -D[=] Preprocessor options\n", progname); #endif finish_jit(); exit(1); } int main(int argc, char *argv[]) { #if HAVE_GETOPT_LONG_ONLY static const char *short_options = "dv::"; static struct option long_options[] = { { "help", 0, 0, 'h' }, { "data", 2, 0, 'd' }, # if defined(__i386__) && __WORDSIZE == 32 { "mx87", 2, 0, '7' }, # endif # if defined(__i386__) || defined(__x86_64__) { "msse4_1", 2, 0, '4' }, # endif # if defined(__arm__) { "mcpu", 2, 0, 'c' }, { "mthumb", 2, 0, 't' }, { "mvfp", 2, 0, 'f' }, { "mneon", 2, 0, 'n' }, # endif { 0, 0, 0, 0 } }; #else #endif /* HAVE_GETOPT_LONG_ONLY */ int offset; char *endptr; int opt_index; int opt_short; char cmdline[8192]; #if defined(__CYGWIN__) /* Cause a compile warning about redefinition without dllimport * attribute, *but* cause correct linkage if liblightning.a is * linked to binutils (that happens to have an internal * getopt* implementation and an apparently conflicting * optind global variable) */ extern int optind; optind = 1; #endif progname = argv[0]; init_jit(progname); #if defined(__sgi) DL_HANDLE = dlopen(NULL, RTLD_LAZY); #endif flag_data = 1; #if HAVE_GETOPT_LONG_ONLY for (;;) { if ((opt_short = getopt_long_only(argc, argv, short_options, long_options, &opt_index)) < 0) break; switch (opt_short) { case 'h': default: usage(); break; case 'v': if (optarg) { flag_verbose = strtol(optarg, &endptr, 10); if (*endptr || flag_verbose < 0) usage(); } else flag_verbose = 1; break; case 'd': flag_data = 0; break; #if defined(__i386__) && __WORDSIZE == 32 case '7': if (optarg) { if (strcmp(optarg, "") == 0 || strcmp(optarg, "1") == 0) jit_cpu.sse2 = 0; else if (strcmp(optarg, "0")) usage(); } else jit_cpu.sse2 = 0; break; #endif #if defined(__i386__) || defined(__x86_64__) case '4': if (optarg) { if (strcmp(optarg, "0") == 0) jit_cpu.sse4_2 = 0; else if (strcmp(optarg, "1")) usage(); } break; #endif #if defined(__arm__) case 'c': if (optarg) { offset = strtol(optarg, &endptr, 10); if (*endptr || offset < 0) usage(); if (offset < jit_cpu.version) jit_cpu.version = offset; } break; case 't': if (optarg) { if (strcmp(optarg, "0") == 0) jit_cpu.thumb = 0; else if (strcmp(optarg, "1") && strcmp(optarg, "2")) usage(); } break; case 'f': # if !defined(__ARM_PCS_VFP) /* Do not allow overrinding hard float abi */ if (optarg) { offset = strtol(optarg, &endptr, 10); if (*endptr || offset < 0) usage(); if (offset < jit_cpu.vfp) jit_cpu.vfp = offset; } # endif break; case 'n': if (optarg) { if (strcmp(optarg, "0") == 0) jit_cpu.neon = 0; else if (strcmp(optarg, "1")) usage(); } break; #endif } } #else while ((opt_short = getopt(argc, argv, "hvd")) >= 0) { if (opt_short == 'v') ++flag_verbose; else if (opt_short == 'd') flag_data = 0; else usage(); } #endif opt_index = optind; #if defined(__hpux) /* Workaround */ if (opt_index < argc && argv[opt_index][0] == '-') ++opt_index; #endif if (opt_index < 0 || opt_index >= argc) usage(); if (strcmp(argv[opt_index], "-") == 0) strcpy(parser.name, ""); else { if ((endptr = strrchr(argv[opt_index], '/')) == NULL) endptr = argv[opt_index]; else ++endptr; strncpy(parser.name, endptr, sizeof(parser.name)); parser.name[sizeof(parser.name) - 1] = '\0'; } #if __clang__ # define cc "clang" #else # define cc "gcc" #endif opt_short = snprintf(cmdline, sizeof(cmdline), cc " -E -x c %s", argv[opt_index]); for (++opt_index; opt_index < argc; opt_index++) { if (argv[opt_index][0] == '-') opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " %s", argv[opt_index]); else { --opt_index; break; } } opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__WORDSIZE=%d", __WORDSIZE); opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__LITTLE_ENDIAN=%d", __LITTLE_ENDIAN); opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__BIG_ENDIAN=%d", __BIG_ENDIAN); opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__BYTE_ORDER=%d", __BYTE_ORDER); #if defined(__i386__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__i386__=1"); #endif #if defined(__x86_64__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__x86_64__=1"); #endif #if defined(__mips__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__mips__=1"); #endif #if defined(__arm__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__arm__=1"); #endif #if defined(__powerpc__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__ppc__=1"); #endif #if defined(__sparc__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__sparc__=1"); #endif #if defined(__ia64__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__ia64__=1"); #endif #if defined(__hppa__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__hppa__=1"); #endif #if defined(_AIX) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D_AIX=1"); #endif #if defined(__sgi__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__sgi__=1"); #endif #if defined(__aarch64__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__aarch64__=1"); #endif #if defined(__s390__) || defined(__s390x__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__s390__=1"); #endif #if defined(__alpha__) opt_short += snprintf(cmdline + opt_short, sizeof(cmdline) - opt_short, " -D__alpha__=1"); #endif if ((parser.fp = popen(cmdline, "r")) == NULL) error("cannot execute %s", cmdline); parser.line = 1; parser.string = (char *)xmalloc(parser.length = 4096); #if defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) /* double precision 0x200 * round nearest 0x000 * invalid operation mask 0x001 * denormalized operand mask 0x002 * zero divide mask 0x004 * precision (inexact) mask 0x020 */ { fpu_control_t fpu_control = 0x027f; _FPU_SETCW(fpu_control); } #endif _jit = jit_new_state(); instrs = new_hash(); for (offset = 0; offset < (int)(sizeof(instr_vector) / sizeof(instr_vector[0])); offset++) put_hash(instrs, (entry_t *)(instr_vector + offset)); labels = new_hash(); parse(); pclose(parser.fp); parser.fp = NULL; for (opt_short = 0; opt_index < argc; opt_short++, opt_index++) argv[opt_short] = argv[opt_index]; argv[opt_short] = NULL; argc = opt_short; execute(argc, argv); finish_jit(); return (0); }