faucc-20120707/0000750002413100241000000000000011776113700012510 5ustar potyrai3guestfaucc-20120707/faucc.h0000640002413100241000000000135311137625346013752 0ustar potyrai3guest/* $Id: faucc.h,v 1.6 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ enum target { TARGET_NONE, TARGET_I286, TARGET_I386, }; extern const char *progname; extern int opt_S; extern int opt_d; extern enum target opt_t; extern unsigned int opt_f_sizeof_char; extern unsigned int opt_f_sizeof_short_int; extern unsigned int opt_f_sizeof_int; extern unsigned int opt_f_sizeof_long_int; extern unsigned int opt_f_sizeof_long_long_int; extern unsigned int opt_f_sizeof_pointer; faucc-20120707/label.c0000640002413100241000000000344611137625346013750 0ustar potyrai3guest/* $Id: label.c,v 1.4 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include #include "label.h" #include "stmt.h" struct label * label_new(const char *identifier) { struct label *label; label = malloc(sizeof *label); assert(label); memset(label, 0, sizeof *label); label->identifier = identifier; return label; } static void label_free(struct label *label) { if (! label->ref_first && ! label->def_first) { #if 0 free(label); #endif } } void label_ref_add(struct label *label, struct stmt *s) { s->ref_prev = label->ref_last; s->ref_next = NULL; if (s->ref_prev) { s->ref_prev->ref_next = s; } else { label->ref_first = s; } label->ref_last = s; } void label_ref_del(struct label *label, struct stmt *s) { if (s->ref_prev) { s->ref_prev->ref_next = s->ref_next; } else { label->ref_first = s->ref_next; } if (s->ref_next) { s->ref_next->ref_prev = s->ref_prev; } else { label->ref_last = s->ref_prev; } label_free(label); } void label_def_add(struct label *label, struct stmt *s) { s->def_prev = label->def_last; s->def_next = NULL; if (s->def_prev) { s->def_prev->def_next = s; } else { label->def_first = s; } label->def_last = s; } void label_def_del(struct label *label, struct stmt *s) { if (s->def_prev) { s->def_prev->def_next = s->def_next; } else { label->def_first = s->def_next; } if (s->def_next) { s->def_next->def_prev = s->def_prev; } else { label->def_last = s->def_prev; } label_free(label); } faucc-20120707/identifier.h0000640002413100241000000000142511137625346015013 0ustar potyrai3guest/* $Id: identifier.h,v 1.5 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __IDENTIFIER_H_INCLUDED #define __IDENTIFIER_H_INCLUDED #define IDENTIFIER_HASH_SIZE 8192 extern unsigned int identifier_hash(const char *name); extern const char * identifier_new(const char *name); extern const char * identifier_tmp(void); extern int identifier_is_tmp(const char *name); extern const char * identifier_dup(const char *name); extern void identifier_free(const char *name); #endif /* __IDENTIFIER_H_INCLUDED */ faucc-20120707/visitor.c0000640002413100241000000000567111714721521014363 0ustar potyrai3guest/* * $Id: visitor.c,v 1.2 2012-02-09 10:43:29 vrsieh Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include "visitor.h" static int visitor_expr_do( struct stmt *block, struct stmt *stmt, struct expr *expr, int (*ev)(int, struct stmt *, struct stmt *, struct expr *) ) { int retval; struct expr *ce; retval = 0; retval |= (*ev)(0, block, stmt, expr); if (expr->expr0) { retval |= visitor_expr_do(block, stmt, expr->expr0, ev); } if (expr->expr1) { retval |= visitor_expr_do(block, stmt, expr->expr1, ev); } if (expr->expr2) { retval |= visitor_expr_do(block, stmt, expr->expr2, ev); } for (ce = expr->first; ce; ce = ce->next) { retval |= visitor_expr_do(block, stmt, ce, ev); } retval |= (*ev)(1, block, stmt, expr); return retval; } static int visitor_stmt_do( int repeat, struct stmt *block, struct stmt *stmt, int (*sv)(int, struct stmt *, struct stmt *), int (*ev)(int, struct stmt *, struct stmt *, struct expr *) ) { int retval; struct stmt *cs; retval = 0; if (sv) { retval |= (*sv)(0, block, stmt); } if (ev && stmt->expr0) { retval |= visitor_expr_do(block, stmt, stmt->expr0, ev); } if (ev && stmt->expr1) { retval |= visitor_expr_do(block, stmt, stmt->expr1, ev); } if (ev && stmt->expr2) { retval |= visitor_expr_do(block, stmt, stmt->expr2, ev); } if (stmt->stmt0) { retval |= visitor_stmt_do(repeat, block, stmt->stmt0, sv, ev); } if (stmt->stmt1) { retval |= visitor_stmt_do(repeat, block, stmt->stmt1, sv, ev); } again: ; for (cs = stmt->stmt_first; cs; ) { struct stmt *next; next = cs->next; if (visitor_stmt_do(repeat, stmt, cs, sv, ev)) { retval |= 1; if (repeat) { goto again; } } cs = next; } if (sv) { retval |= (*sv)(1, block, stmt); } return retval; } static int visitor_scope( struct scope *scope, int repeat, int (*sv)(int, struct stmt *, struct stmt *), int (*ev)(int, struct stmt *, struct stmt *, struct expr *) ) { struct declaration *dion; int retval; struct stmt *cs; retval = 0; for (dion = scope->declaration_first; dion; dion = dion->next) { if (! dion->stmt) { continue; } again: ; for (cs = dion->stmt->stmt_first; cs; ) { struct stmt *next; next = cs->next; if (visitor_stmt_do(repeat, dion->stmt, cs, sv, ev)) { retval |= 1; if (repeat) { goto again; } } cs = next; } } return retval; } int visitor_stmt( struct scope *scope, int repeat, int (*sv)(int, struct stmt *, struct stmt *) ) { return visitor_scope(scope, repeat, sv, NULL); } int visitor_expr( struct scope *scope, int repeat, int (*ev)(int, struct stmt *, struct stmt *, struct expr *) ) { return visitor_scope(scope, repeat, NULL, ev); } faucc-20120707/type.h0000640002413100241000000001160211717460534013650 0ustar potyrai3guest/* $Id: type.h,v 1.57 2012-02-17 14:17:00 vrsieh Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __TYPE_H_INCLUDED #define __TYPE_H_INCLUDED #include "setup.h" struct type { enum type_type { TYPE_NONE, TYPE_ELIPSIS, TYPE_VOID, TYPE_VA_LIST, TYPE_INT8, TYPE_UINT8, TYPE_INT16, TYPE_UINT16, TYPE_INT32, TYPE_UINT32, TYPE_INT64, TYPE_UINT64, TYPE_FLOAT32, TYPE_FLOAT64, TYPE_FLOAT80, TYPE_STRUCT, TYPE_UNION, TYPE_ENUM, TYPE_POINTER, TYPE_ARRAY, TYPE_FUNCTION, TYPE_MAX, } type; struct type *declarator; /* Pointer */ // struct type *declarator; /* Array */ struct expr *dimension; // struct type *declarator; /* Function */ struct scope *parameter; // struct type *declarator; /* Type Specifier */ const char *identifier; struct scope *scope; /* for struct/union */ unsigned int mod_const; unsigned int mod_volatile; unsigned int attr_aligned; unsigned int attr_packed; struct type *addrof; struct type *constof; struct type *volatileof; struct type *pureof; }; extern const char *type_info[]; extern void type_rename_structunionenum(struct type *t, enum type_type type, const char *old, const char *new); extern void type_rename_type(struct type *t, const char *old, const char *new); extern int type_is_type_spec(struct type *dor); extern int type_is_void(struct type *t); extern int type_is_integer(struct type *t); extern int type_is_struct(struct type *t); extern int type_is_union(struct type *t); extern int type_is_ptrdiff(struct type *t); extern int type_is_pointer(struct type *t); extern int type_is_array(struct type *t); extern int type_is_function(struct type *t); extern int type_equal(struct type *t0, struct type *t1); extern void type_align_size(struct scope *scope, struct type *t, unsigned int *alignp, unsigned int *sizep); extern unsigned int type_sizeof(struct scope *scope, struct type *t); extern unsigned int type_offsetof(struct scope *scope, struct type *t, const char *mem); extern struct expr * type_dimension_get(struct type *abs_decl); extern struct scope * type_parameter_get(struct type *abs_decl); extern struct type * type_new(void); extern struct type * type_type_spec(void); extern struct type * type_gen(enum type_type type); extern struct type * type_void(void); extern struct type * type_int8(void); extern struct type * type_uint8(void); extern struct type * type_int16(void); extern struct type * type_uint16(void); extern struct type * type_int32(void); extern struct type * type_uint32(void); extern struct type * type_int64(void); extern struct type * type_uint64(void); extern struct type * type_float32(void); extern struct type * type_float64(void); extern struct type * type_float80(void); extern struct type * type_signed_char(void); extern struct type * type_unsigned_char(void); extern struct type * type_char(void); extern struct type * type_short_int(void); extern struct type * type_unsigned_short_int(void); extern struct type * type_int(void); extern struct type * type_unsigned_int(void); extern struct type * type_long_int(void); extern struct type * type_unsigned_long_int(void); extern struct type * type_long_long_int(void); extern struct type * type_unsigned_long_long_int(void); extern struct type * type_ptrdiff(void); extern struct type * type_uintptr_t(void); extern struct type * type_float(void); extern struct type * type_double(void); extern struct type * type_long_double(void); extern struct type * type_const_char_pointer(void); extern struct type * type_const_char_array(unsigned int dim); extern struct type * type_add_pointer(struct type *dor, int const_volatile); extern struct type * type_add_array(struct type *dor, struct expr *dimension); extern struct type * type_add_function(struct type *dor, struct scope *parameter); extern struct type * type_add_user(struct type *dor, struct type *dor_user); extern struct type * type_const(struct type *t); extern struct type * type_volatile(struct type *t); extern struct type * type_aligned(struct scope *scope, struct type *t, unsigned int aligned); extern struct type * type_packed(struct scope *scope, struct type *t); extern struct type * type_pure(struct type *t); extern struct type * type_amphersand(struct type *t); extern struct type * type_star(struct type *t); extern struct type * type_array_access(struct type *t); extern struct type * type_call(struct type *t); extern struct type * type_add(struct type *t0, struct type *t1); extern struct type * type_sub(struct type *t0, struct type *t1); extern struct type * type_arithmetic(struct type *t0, struct type *t1); extern struct type * type_pointer_to_ptrdiff(struct type *t); extern void type_free(struct type *ad); #endif /* __TYPE_H_INCLUDED */ faucc-20120707/README0000640002413100241000000000142211135057007013364 0ustar potyrai3guest FAUcc, a C compiler generating Intel code for 16bit/32bit CPUs. Copyright (C) 2007-2009 FAUcc Team, see AUTHORS. Copyright (C) 2007-2009 Department of Computer Science 3, Friedrich Alexander University Erlangen-Nuremberg, Germany This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. faucc-20120707/type.c0000640002413100241000000004302511721453472013645 0ustar potyrai3guest/* $Id: type.c,v 1.77 2012-02-23 15:11:54 vrsieh Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include #include "setup.h" #include "type.h" #include "expr.h" #include "arch_i286_gen.h" #include "arch_i386_gen.h" #include "cc1.h" const char *type_info[TYPE_MAX] = { [TYPE_NONE] = "none", [TYPE_ELIPSIS] = "elipsis", [TYPE_VOID] = "void", [TYPE_VA_LIST] = "va_list", [TYPE_INT8] = "int8", [TYPE_UINT8] = "uint8", [TYPE_INT16] = "int16", [TYPE_UINT16] = "uint16", [TYPE_INT32] = "int32", [TYPE_UINT32] = "uint32", [TYPE_INT64] = "int64", [TYPE_UINT64] = "uint64", [TYPE_FLOAT32] = "float32", [TYPE_FLOAT64] = "float64", [TYPE_FLOAT80] = "float80", [TYPE_STRUCT] = "struct", [TYPE_UNION] = "union", [TYPE_ENUM] = "enum", [TYPE_POINTER] = "pointer", [TYPE_ARRAY] = "array", [TYPE_FUNCTION] = "function", }; void type_rename_structunionenum( struct type *t, enum type_type type, const char *old, const char *new ) { switch (t->type) { case TYPE_POINTER: case TYPE_ARRAY: case TYPE_FUNCTION: type_rename_structunionenum(t->declarator, type, old, new); break; default: if (t->type == type && strcmp(t->identifier, old) == 0) { t->identifier = new; } break; } } void type_rename_type(struct type *t, const char *old, const char *new) { switch (t->type) { case TYPE_POINTER: case TYPE_ARRAY: case TYPE_FUNCTION: type_rename_type(t->declarator, old, new); break; default: break; } } int type_is_type_spec(struct type *t) { return t->type != TYPE_POINTER && t->type != TYPE_ARRAY && t->type != TYPE_FUNCTION; } int type_is_void(struct type *t) { return t->type == TYPE_VOID; } int type_is_integer(struct type *t) { if (TYPE_INT8 <= t->type && t->type <= TYPE_UINT64) { return 1; } else { return 0; } } int type_is_struct(struct type *t) { return t->type == TYPE_STRUCT; } int type_is_union(struct type *t) { return t->type == TYPE_UNION; } int type_is_ptrdiff(struct type *t) { return (t == type_ptrdiff() || t == type_uintptr_t()); } int type_is_pointer(struct type *t) { return t->type == TYPE_POINTER || t->type == TYPE_ARRAY; } int type_is_array(struct type *t) { return t->type == TYPE_ARRAY; } int type_is_function(struct type *t) { return t->type == TYPE_FUNCTION; } int type_equal(struct type *ts0, struct type *ts1) { for (;;) { if (ts0->type != ts1->type) { return 0; } if (ts0->type == TYPE_VOID || ts0->type == TYPE_VA_LIST || (TYPE_INT8 <= ts0->type && ts0->type <= TYPE_FLOAT80)) { return 1; } if (ts0->type == TYPE_STRUCT || ts0->type == TYPE_UNION) { return strcmp(ts0->identifier, ts1->identifier) == 0; } assert(ts0->type == TYPE_POINTER || ts0->type == TYPE_ARRAY || ts0->type == TYPE_FUNCTION); ts0 = ts0->declarator; ts1 = ts1->declarator; } } void type_align_size( struct scope *scope, struct type *t, unsigned int *alignp, unsigned int *sizep ) { struct declaration *dion; unsigned int global_align; unsigned int align; unsigned int size; unsigned int offset; switch (t->type) { case TYPE_NONE: case TYPE_ENUM: case TYPE_MAX: assert(0); case TYPE_ELIPSIS: assert(0); case TYPE_VOID: assert(0); case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: case TYPE_INT64: case TYPE_UINT64: case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: case TYPE_VA_LIST: case TYPE_POINTER: switch (opt_b) { case TARGET_I286: arch_i286_align_size(scope, t, alignp, sizep); break; case TARGET_I386: arch_i386_align_size(scope, t, alignp, sizep); break; default: assert(0); /* FIXME */ } break; case TYPE_STRUCT: if (! t->scope) { int ret; ret = scope_lookup_structunionenum(scope, t->type, t->identifier, &t); assert(0 <= ret); } scope = t->scope; global_align = 1; offset = 0; for (dion = scope->declaration_first; dion; dion = dion->next) { type_align_size(scope, dion->type_name, &align, &size); if (t->attr_packed) { align = 1; } if (global_align < align) { global_align = align; } offset += align - 1; offset &= ~(align - 1); offset += size; } offset += global_align - 1; offset &= ~(global_align - 1); if (t->attr_aligned) { *alignp = t->attr_aligned; } else { *alignp = global_align; } *sizep = offset; break; case TYPE_UNION: if (! t->scope) { int ret; ret = scope_lookup_structunionenum(scope, t->type, t->identifier, &t); assert(0 <= ret); } scope = t->scope; global_align = 1; offset = 0; for (dion = scope->declaration_first; dion; dion = dion->next) { type_align_size(scope, dion->type_name, &align, &size); if (t->attr_packed) { align = 1; } if (global_align < align) { global_align = align; } if (offset < size) { offset = size; } } if (t->attr_aligned) { *alignp = t->attr_aligned; } else { *alignp = global_align; } *sizep = offset; break; case TYPE_ARRAY: assert(t->dimension); assert(t->dimension->type == EXPR_INTEGER); type_align_size(scope, t->declarator, &align, &size); *alignp = align; *sizep = size * t->dimension->integer; break; case TYPE_FUNCTION: assert(0); } } unsigned int type_sizeof(struct scope *scope, struct type *t) { unsigned int align; unsigned int size; type_align_size(scope, t, &align, &size); return size; } unsigned int type_offsetof(struct scope *scope, struct type *t, const char *mem) { struct declaration *dion; unsigned int offset; unsigned int align; unsigned int size; offset = 0; for (dion = t->scope->declaration_first; ; dion = dion->next) { assert(dion); type_align_size(t->scope, dion->type_name, &align, &size); if (t->attr_packed) { align = 1; } offset += align - 1; offset &= ~(align - 1); if (strcmp(dion->identifier, mem) == 0) { break; } offset += size; } return offset; } struct expr * type_dimension_get(struct type *ad) { assert(ad->type == TYPE_ARRAY); return ad->dimension; } struct scope * type_parameter_get(struct type *ad) { assert(ad->type == TYPE_FUNCTION); assert(ad->parameter); return ad->parameter; } struct type * type_new(void) { struct type *d; d = malloc(sizeof(*d)); assert(d); memset(d, 0, sizeof(*d)); return d; } struct type * type_type_spec(void) { return NULL; } struct type * type_gen(enum type_type type) { static struct type *t[TYPE_MAX] = { NULL, NULL /* ... */ }; assert(type < TYPE_MAX); if (t[type] == NULL) { t[type] = type_new(); t[type]->type = type; } return t[type]; } struct type * type_void(void) { return type_gen(TYPE_VOID); } struct type * type_int8(void) { return type_gen(TYPE_INT8); } struct type * type_uint8(void) { return type_gen(TYPE_UINT8); } struct type * type_int16(void) { return type_gen(TYPE_INT16); } struct type * type_uint16(void) { return type_gen(TYPE_UINT16); } struct type * type_int32(void) { return type_gen(TYPE_INT32); } struct type * type_uint32(void) { return type_gen(TYPE_UINT32); } struct type * type_int64(void) { return type_gen(TYPE_INT64); } struct type * type_uint64(void) { return type_gen(TYPE_UINT64); } struct type * type_float32(void) { return type_gen(TYPE_FLOAT32); } struct type * type_float64(void) { return type_gen(TYPE_FLOAT64); } struct type * type_float80(void) { return type_gen(TYPE_FLOAT80); } struct type * type_signed_char(void) { return type_int8(); } struct type * type_unsigned_char(void) { return type_uint8(); } struct type * type_char(void) { if (SIGNED_CHAR) { return type_signed_char(); } else { return type_unsigned_char(); } } struct type * type_short_int(void) { if (opt_f_sizeof_short_int == 2) { return type_gen(TYPE_INT16); } else { assert(0); } } struct type * type_unsigned_short_int(void) { if (opt_f_sizeof_short_int == 2) { return type_gen(TYPE_UINT16); } else { assert(0); } } struct type * type_int(void) { if (opt_f_sizeof_int == 2) { return type_gen(TYPE_INT16); } else if (opt_f_sizeof_int == 4) { return type_gen(TYPE_INT32); } else { assert(0); } } struct type * type_unsigned_int(void) { if (opt_f_sizeof_int == 2) { return type_gen(TYPE_UINT16); } else if (opt_f_sizeof_int == 4) { return type_gen(TYPE_UINT32); } else { assert(0); } } struct type * type_long_int(void) { if (opt_f_sizeof_long_int == 4) { return type_gen(TYPE_INT32); } else if (opt_f_sizeof_long_int == 8) { return type_gen(TYPE_INT64); } else { assert(0); } } struct type * type_unsigned_long_int(void) { if (opt_f_sizeof_long_int == 4) { return type_gen(TYPE_UINT32); } else if (opt_f_sizeof_long_int == 8) { return type_gen(TYPE_UINT64); } else { assert(0); } } struct type * type_long_long_int(void) { if (opt_f_sizeof_long_long_int == 8) { return type_gen(TYPE_INT64); } else { assert(0); } } struct type * type_unsigned_long_long_int(void) { if (opt_f_sizeof_long_long_int == 8) { return type_gen(TYPE_UINT64); } else { assert(0); } } struct type * type_ptrdiff(void) { switch (opt_b) { case TARGET_I286: return arch_i286_type_intptr_t(); case TARGET_I386: return arch_i386_type_intptr_t(); default: assert(0); } } struct type * type_uintptr_t(void) { switch (opt_b) { case TARGET_I286: return arch_i286_type_uintptr_t(); case TARGET_I386: return arch_i386_type_uintptr_t(); default: assert(0); } } struct type * type_float(void) { return type_float32(); } struct type * type_double(void) { return type_float64(); } struct type * type_long_double(void) { return type_float80(); } struct type * type_const_char_pointer(void) { static struct type *t = NULL; if (! t) { t = type_new(); t->type = TYPE_POINTER; t->declarator = type_const(type_char()); } return t; } struct type * type_const_char_array(unsigned int dim) { struct type *t; t = type_new(); t->type = TYPE_ARRAY; t->dimension = expr_integer(dim); t->declarator = type_const(type_char()); return t; } struct type * type_add_pointer(struct type *t, int const_volatile) { struct type *nt; nt = type_new(); nt->type = TYPE_POINTER; nt->declarator = NULL; if (const_volatile & 2) { nt->mod_const = 1; } if (const_volatile & 1) { nt->mod_volatile = 1; } return type_add_user(t, nt); } struct type * type_add_array(struct type *t, struct expr *dimension) { struct type *nt; nt = type_new(); nt->type = TYPE_ARRAY; nt->dimension = dimension; nt->declarator = NULL; return type_add_user(t, nt); } struct type * type_add_function(struct type *t, struct scope *parameter) { struct type *nt; nt = type_new(); nt->type = TYPE_FUNCTION; nt->parameter = parameter; nt->declarator = NULL; return type_add_user(t, nt); } struct type * type_add_user(struct type *t, struct type *t_user) { struct type *last; if (! t) { return t_user; } else { for (last = t; last->declarator; last = last->declarator) { } assert(! last->declarator); last->declarator = t_user; } return t; } struct type * type_const(struct type *t) { if (! t->constof) { struct type *nt; nt = type_new(); assert(nt); memcpy(nt, t, sizeof *nt); nt->mod_const = 1; t->constof = nt; } return t->constof; } struct type * type_volatile(struct type *t) { if (! t->volatileof) { struct type *nt; nt = type_new(); assert(nt); memcpy(nt, t, sizeof *nt); nt->mod_volatile = 1; t->volatileof = nt; } return t->volatileof; } struct type * type_aligned(struct scope *scope, struct type *t, unsigned int aligned) { struct type *nt; int ret; assert(t->type == TYPE_STRUCT); ret = scope_lookup_structunionenum(scope, t->type, t->identifier, &nt); assert(0 <= ret); assert(nt->scope); nt->attr_aligned = aligned; return t; } struct type * type_packed(struct scope *scope, struct type *t) { struct type *nt; int ret; assert(t->type == TYPE_STRUCT); ret = scope_lookup_structunionenum(scope, t->type, t->identifier, &nt); assert(0 <= ret); assert(nt->scope); nt->attr_packed = 1; return t; } struct type * type_pure(struct type *t) { if (! t->pureof) { struct type *tp; tp = type_new(); tp->type = t->type; switch (t->type) { case TYPE_NONE: case TYPE_ENUM: case TYPE_MAX: assert(0); case TYPE_ELIPSIS: case TYPE_VA_LIST: break; case TYPE_VOID: case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: case TYPE_INT64: case TYPE_UINT64: break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: break; case TYPE_STRUCT: case TYPE_UNION: tp->identifier = t->identifier; tp->scope = NULL; break; case TYPE_POINTER: tp->declarator = t->declarator; break; case TYPE_ARRAY: tp->declarator = t->declarator; tp->dimension = t->dimension; break; case TYPE_FUNCTION: tp->declarator = t->declarator; tp->parameter = t->parameter; break; } if (type_is_array(tp)) { tp = type_amphersand(type_array_access(tp)); } else if (type_is_function(tp)) { tp = type_amphersand(tp); } t->pureof = tp; } return t->pureof; } struct type * type_amphersand(struct type *t) { if (! t->addrof) { struct type *ndor; ndor = type_new(); ndor->type = TYPE_POINTER; ndor->declarator = t; t->addrof = ndor; } return t->addrof; } struct type * type_star(struct type *t) { assert(t->type == TYPE_POINTER || t->type == TYPE_ARRAY); return t->declarator; } struct type * type_array_access(struct type *t) { assert(t->type == TYPE_POINTER || t->type == TYPE_ARRAY); return t->declarator; } struct type * type_call(struct type *t) { assert(t->type == TYPE_FUNCTION); return t->declarator; } struct type * type_arithmetic(struct type *t0, struct type *t1) { enum type_type res0; enum type_type res1; enum type_type res; if (t0->type == TYPE_POINTER && t0->declarator->type != TYPE_VOID) { assert(t1->type == TYPE_POINTER || (TYPE_INT8 <= t1->type && t1->type <= TYPE_UINT64)); return t0; } if (t1->type == TYPE_POINTER && t1->declarator->type != TYPE_VOID) { assert(t0->type == TYPE_POINTER || (TYPE_INT8 <= t0->type && t0->type <= TYPE_UINT64)); return t1; } if (t0->type == TYPE_POINTER) { assert(t1->type == TYPE_POINTER || (TYPE_INT8 <= t1->type && t1->type <= TYPE_UINT64)); return t0; } if (t1->type == TYPE_POINTER) { assert(t0->type == TYPE_POINTER || (TYPE_INT8 <= t0->type && t0->type <= TYPE_UINT64)); return t1; } if (t0->type == TYPE_VA_LIST) { return t0; } if (t1->type == TYPE_VA_LIST) { return t1; } res0 = t0->type; res1 = t1->type; assert(TYPE_INT8 <= res0 && res0 <= TYPE_FLOAT80); assert(TYPE_INT8 <= res1 && res1 <= TYPE_FLOAT80); res = (res0 < res1) ? res1 : res0; if (opt_f_sizeof_int == 2) { if (res < TYPE_INT16) { res = TYPE_INT16; } } else if (opt_f_sizeof_int == 4) { if (res < TYPE_INT32) { res = TYPE_INT32; } } else { assert(0); } res = (res == TYPE_FLOAT32) ? TYPE_FLOAT64 : res; return type_gen(res); } struct type * type_add(struct type *t0, struct type *t1) { if (t0->type == TYPE_POINTER || t0->type == TYPE_ARRAY) { assert(t0->declarator->type != TYPE_VOID); assert(TYPE_INT8 <= t1->type && t1->type <= TYPE_UINT64); return t0; } else if (t1->type == TYPE_POINTER || t1->type == TYPE_ARRAY) { assert(t1->declarator->type != TYPE_VOID); assert(TYPE_INT8 <= t0->type && t0->type <= TYPE_UINT64); return t1; } else { return type_arithmetic(t0, t1); } } struct type * type_sub(struct type *t0, struct type *t1) { if ((t0->type == TYPE_POINTER || t0->type == TYPE_ARRAY) && (t1->type == TYPE_POINTER || t1->type == TYPE_ARRAY)) { assert(t0->declarator->type != TYPE_VOID); assert(t1->declarator->type != TYPE_VOID); return type_ptrdiff(); } else if (t0->type == TYPE_POINTER || t0->type == TYPE_ARRAY) { assert(t0->declarator->type != TYPE_VOID); assert(TYPE_INT8 <= t1->type && t1->type <= TYPE_UINT64); return t0; } else { return type_arithmetic(t0, t1); } } struct type * type_pointer_to_ptrdiff(struct type *t) { struct type *t1; struct type *t2; struct declaration *dion; switch (t->type) { case TYPE_NONE: case TYPE_MAX: assert(0); case TYPE_ELIPSIS: case TYPE_VA_LIST: case TYPE_VOID: case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: case TYPE_INT64: case TYPE_UINT64: case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: break; case TYPE_POINTER: t = type_ptrdiff(); break; case TYPE_STRUCT: case TYPE_UNION: if (t->scope) { for (dion = t->scope->declaration_first; dion; dion = dion->next) { dion->type_name = type_pointer_to_ptrdiff( dion->type_name); } } break; case TYPE_ENUM: break; case TYPE_ARRAY: t1 = type_pointer_to_ptrdiff(t->declarator); if (t1 != t->declarator) { t2 = type_new(); t2->type = TYPE_ARRAY; t2->dimension = expr_dup(t->dimension); t2->declarator = t1; t = t2; } break; case TYPE_FUNCTION: t1 = type_pointer_to_ptrdiff(t->declarator); if (t1 != t->declarator) { t2 = type_new(); t2->type = TYPE_FUNCTION; t2->parameter = t->parameter; t2->declarator = t1; t = t2; } for (dion = t->parameter->declaration_first; dion; dion = dion->next) { dion->type_name = type_pointer_to_ptrdiff( dion->type_name); } break; } return t; } void type_free(struct type *t) { /* FIXME */ } faucc-20120707/simplify.h0000640002413100241000000000116411137625346014525 0ustar potyrai3guest/* $Id: simplify.h,v 1.9 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SIMPLIFY_H_INCLUDED #define __SIMPLIFY_H_INCLUDED #include "scope.h" /* FIXME */ extern struct declaration * simplify_declaration_add( struct scope *scope, struct type *ts, const char *name); extern void simplify(struct scope *s); #endif /* __SIMPLIFY_H_INCLUDED */ faucc-20120707/libfaucc/0000750002413100241000000000000011776113700014260 5ustar potyrai3guestfaucc-20120707/libfaucc/Makefile.am0000640002413100241000000000130111133143212016274 0ustar potyrai3guest# # $Id: Makefile.am,v 1.3 2009-01-13 16:51:22 vrsieh Exp $ # # Copyright (C) 2008-2009 FAUcc Team.org>. # This program is free software, GPL-2 (or any later version). See COPYING. # fauccdir = $(libdir)/faucc faucc_LIBRARIES = libfaucc.a libfaucc_a_SOURCES = libfaucc.c libfaucc.a: libfaucc.c rm -f libfaucc.a for src in libfaucc.c ; do \ for arch in i286 i386 ; do \ file=`echo $$src | sed -e 's/\.c$$//'`; \ echo $${file}; \ sed -e "s/ARCH/$${arch}/g" < $${file}.c > $${file}-$${arch}.c; \ ../faucc -B.. -c -b $${arch} -o $${file}-$${arch}.o $${file}-$${arch}.c; \ ar rcs libfaucc.a $${file}-$${arch}.o; \ rm $${file}-$${arch}.o; \ rm $${file}-$${arch}.c; \ done; \ done faucc-20120707/libfaucc/libfaucc.h0000640002413100241000000000152711137626366016217 0ustar potyrai3guest/* $Id: libfaucc.h,v 1.3 2009-01-27 15:49:10 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LIBFAUCC_H_INCLUDED #define __LIBFAUCC_H_INCLUDED unsigned long __div32(unsigned long op1, unsigned long op2); unsigned long __mod32(unsigned long op1, unsigned long op2); unsigned long __mul32(unsigned long op1, unsigned long op2); unsigned long long __div64(unsigned long long op1, unsigned long long op2); unsigned long long __mod64(unsigned long long op1, unsigned long long op2); unsigned long long __mul64(unsigned long long op1, unsigned long long op2); #endif /* __LIBFAUCC_H_INCLUDED */ faucc-20120707/libfaucc/libfaucc.c0000640002413100241000000000623311717460535016207 0ustar potyrai3guest/* * $Id: libfaucc.c,v 1.12 2012-02-17 14:17:01 vrsieh Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include uint32_t __ARCH_div_uint32(uint32_t op1, uint32_t op2) { uint32_t X=0, A=op1; uint32_t res=0; unsigned char N=0; if ((A>>31) == 1) { A = 1 << N; } /* find bit length difference between op1 and op2 */ X=op2; while ((X << 1) <= A) { X = X << 1; if (X == 0) break; N++; } if (N>0) { A = (op1 << (32-N)); X = (op1 >> N); } else X = op1; N++; do { if (X >= op2) { X = X-op2; res = res << 1; res = res | 0x01; } else { res = res << 1; } X = X << 1; if ((A>>31) == 1) { X = X | 0x01; } A = A<<1; N--; } while (N > 0); return res; } uint32_t __ARCH_mod_uint32(uint32_t op1, uint32_t op2) { uint32_t X=0, A=op1; unsigned char N=0; if ((A>>31) == 1) { A = 1 << N; } X=op2; while ((X << 1) <= A) { X = X << 1; if (X == 0) break; N++; } if (N>0) { A = (op1 << (32-N)); X = (op1 >> N); } else X = op1; N++; do { if (X >= op2) { X = X-op2; } X = X << 1; if ((A>>31) == 1) { X = X | 0x01; } A = A<<1; N--; } while (N > 0); X = X >> 1; return X; } uint32_t __ARCH_mul_uint32(uint32_t op1, uint32_t op2) { uint32_t X=0, A=0; uint32_t res=0; unsigned char N=0, I=0; X=op2; while (X != 0) { X = X >> 4; N++; } do { X=0; A=(op2 << (28-4*I)) >> 28; if (((A<<31)>>31) == 1) { X += op1; } if (((A<<30)>>31) == 1) { X += op1 << 1; } if (((A<<29)>>31) == 1) { X += op1 << 2; } if (((A<<28)>>31) == 1) { X += op1 << 3; } X = X << 4*I; res += X; N--; I++; } while (N > 0); return res; } #if 0 uint64_t __ARCH_div_uint64(uint64_t op1, uint64_t op2) { uint64_t X=0, A=0; uint64_t res=0; unsigned char N=0; X=op2; while ((X << 1) < op1) { X = X << 1; N++; } A = (op1 << (64-N)); X = (op1 >> N); N++; do { N--; if (X > op2) { X = X-op2; res = res << 1; res = res | 0x01; } else { res = res << 1; } X = X << 1; if ((A>>63) == 1) { X = X | 0x01; } A = A<<1; } while (N > 0); return res; } uint64_t __ARCH_mod_uint64(uint64_t op1, uint64_t op2) { uint64_t X=0, A=0; unsigned char N=0; X=op2; while ((X << 1) < op1) { X = X << 1; N++; } A = (op1 << (64-N));// >> (32-N); X = (op1 >> N); N++; do { N--; if (X > op2) { X = X-op2; } X = X << 1; if ((A>>63) == 1) { X = X | 0x01; } A = A<<1; } while (N > 0); return X; } uint64_t ARCH_mul_uint64(uint64_t op1, uint64_t op2) { uint64_t X=0, A=0; uint64_t res=0; unsigned char N=0, I=0; X=op2; while (X != 0) { X = X >> 4; N++; } do { X=0; N--; A=(op2 << (60-4*I)) >> 60; if (((A<<63)>>63) == 1) { X += op1; } if (((A<<62)>>63) == 1) { X += op1 << 1; } if (((A<<61)>>63) == 1) { X += op1 << 2; } if (((A<<60)>>63) == 1) { X += op1 << 3; } X = X << 4*I; res += X; I++; } while (N > 0); return res; } #endif faucc-20120707/acinclude.m40000640002413100241000000000145211706306023014677 0ustar potyrai3guest# # $Id: acinclude.m4,v 1.1 2012-01-20 15:45:23 vrsieh Exp $ # # Copyright (C) 2004-2012 FAUmachine Team . # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. # # usage: AC_PROG_CC_OPTION(--compiler-option, if-supported, if-unsupported) # add this option to $(CC) if it is supported by the compiler # if no sc # Martin Waitz AC_DEFUN([AC_PROG_CC_OPTION], [ AC_MSG_CHECKING([whether $CC supports $1]) ac_save_CC="$CC" CC="$CC $1" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],[ AC_MSG_RESULT([yes]) ifelse($2, , [], [ CC="$ac_save_CC" $2]) ], [ AC_MSG_RESULT([no]) CC="$ac_save_CC" $3 ]) ]) faucc-20120707/scripts/0000750002413100241000000000000011776113700014177 5ustar potyrai3guestfaucc-20120707/scripts/syncrep0000750002413100241000000000073611145361463015617 0ustar potyrai3guest#!/bin/sh # # $Id: syncrep,v 1.3 2009-02-13 21:16:35 vrsieh Exp $ # # Copyright (C) 2002-2009 FAUmachine Team . # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. # export RSYNC_RSH=ssh rsync -v -r -t -p --delete faui31f:/proj/FAUcc/. /proj/FAUcc 2>&1 \ | grep -v '/$' \ | tee /tmp/rsync.log faucc-20120707/scripts/genDVD0000750002413100241000000000061610732212757015242 0ustar potyrai3guest#!/bin/sh date=`date +%Y-%m-%d` dir="FAUcc-${date}" iso="FAUcc-${date}.iso" if [ -d ${dir} ] ; then echo "${dir}: exists already" 1>&2 exit 1 fi if [ -f ${iso} ] ; then echo "${iso}: exists already" 1>&2 exit 1 fi mkdir ${dir} cd ${dir} # # copy FAUcc source repository # cp -a /proj/FAUcc FAUcc.repository cd .. # # generate iso image # mkisofs -r -T -v -o ${iso} ${dir} rm -rf ${dir} faucc-20120707/scripts/install_ln.sh0000750002413100241000000000216511265111312016667 0ustar potyrai3guest#!/bin/sh # $Id: install_ln.sh,v 1.3 2009-10-13 14:46:34 potyra Exp $ # # mimic install but use soft links instead # # Copyright (C) 2009 FAUcc Team . # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. if [ $1 = '-c' ]; then # -c -> ignored shift fi if [ $1 = '-m' ]; then # mode -> ignore shift shift fi eval TRG="\${$#}" # more than two arguments? -> target is directory. if [ $# -gt 2 ]; then if [ ! -d "$TRG" ]; then echo "$TRG is not a directory." exit 1 fi fi TARGET_IS_DIR=0 if [ -d "$TRG" ]; then TARGET_IS_DIR=1 fi while [ $# -gt 1 ]; do SRC=$1 shift if [ ! -e "$(pwd)/$SRC" ]; then echo "$SRC no such file or directory." exit 1 fi if [ $TARGET_IS_DIR -eq 1 ]; then DST="$TRG/$(basename $SRC)" else DST="$TRG" fi if [ -e "$DST" -a \( ! \( -h "$DST" \) \) ]; then echo "$DST exists and is not a symbolic link. Skipping." continue fi echo ln -sf "$(pwd)/$SRC" "$TRG" ln -sf "$(pwd)/$SRC" "$TRG" done faucc-20120707/scope.h0000640002413100241000000000477711137625346014017 0ustar potyrai3guest/* $Id: scope.h,v 1.39 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __SCOPE_H_INCLUDED #define __SCOPE_H_INCLUDED #include "declaration.h" #include "label.h" struct scope { struct scope *prev; struct scope *next; enum scope_type { SCOPE_NONE = 0, SCOPE_GLOBAL, SCOPE_FUNCTION, SCOPE_PARAMETER, SCOPE_BLOCK, SCOPE_STRUCT, SCOPE_UNION, SCOPE_ENUM, } type; struct scope *parent; struct scope *child_first; struct scope *child_last; struct declaration *function; struct declaration *declaration_first; struct declaration *declaration_last; struct label *label_first; struct label *label_last; }; extern struct scope *scope_current; extern int scope_lookup_one(struct scope *scope, const char *name, struct declaration **dorp); extern int scope_lookup(struct scope *scope, const char *name, struct declaration **dorp); extern int scope_lookup_current(const char *name, struct declaration **dorp); extern int scope_lookup_structunionenum( struct scope *scope, enum type_type type, const char *name, struct type **tsp ); extern void scope_struct_begin(const char *identifier); extern void scope_struct_end(void); extern void scope_union_begin(const char *identifier); extern void scope_union_end(void); extern void scope_enum_begin(const char *identifier); extern void scope_enum_add(const char *identifier, unsigned int val); extern void scope_enum_end(void); extern void scope_parameter_begin(void); extern void scope_parameter_end(struct declaration *first, struct declaration *last); extern void scope_block_begin(void); extern void scope_block_end(struct stmt *s); extern void scope_function_begin(struct type *ts, struct declaration *dor); extern struct label * scope_function_label_get(const char *identifier); extern void scope_function_end(struct stmt *s); extern void scope_declaration_prepend_first(struct scope *scope, struct declaration *nd); extern void scope_declaration_prepend(struct scope *scope, struct declaration *od, struct declaration *nd); extern void scope_declaration_append(struct scope *scope, struct declaration *dion); extern void scope_asm_add(unsigned int len, const char *code); extern void scope_file_begin(void); extern void scope_file_end(struct scope **scopep); #endif /* __SCOPE_H_INCLUDED */ faucc-20120707/NEWS0000640002413100241000000000000411133124777013205 0ustar potyrai3guest... faucc-20120707/ChangeLog0000640002413100241000000000000411133124777014260 0ustar potyrai3guest... faucc-20120707/arch_i386_gen.h0000640002413100241000000000312711721453472015207 0ustar potyrai3guest/* $Id: arch_i386_gen.h,v 1.19 2012-02-23 15:11:54 vrsieh Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ARCH_I386_GEN_H_INCLUDED #define __ARCH_I386_GEN_H_INCLUDED #include "scope.h" #include "type.h" extern struct type * arch_i386_type_intptr_t(void); extern struct type * arch_i386_type_uintptr_t(void); extern void arch_i386_align_size( struct scope *scope, struct type *type, unsigned int *alignp, unsigned int *sizep); extern void arch_i386_gen_class_and_type_get( const char *name, unsigned int *classp, enum type_type *typep); extern unsigned int arch_i386_gen_class_or(unsigned int a, unsigned int b); extern unsigned int arch_i386_gen_class_and(unsigned int a, unsigned int b); extern void arch_i386_color_init(unsigned int *count); extern void arch_i386_color_add(unsigned int *count, unsigned int set, enum type_type type); extern void arch_i386_color_sub(unsigned int *count, unsigned int set, enum type_type type); extern int arch_i386_color_check(unsigned int *count, unsigned int set, enum type_type type); extern void arch_i386_gen_reg_init(uint32_t *conflicts); extern void arch_i386_gen_reg_add(uint32_t *conflicts, unsigned int reg); extern int arch_i386_gen_reg_get(uint32_t *conflicts, unsigned int class, enum type_type type); extern void arch_i386_gen(const char *out, struct scope *scope); #endif /* __ARCH_I386_GEN_H_INCLUDED */ faucc-20120707/constraint.h0000640002413100241000000000253311137625345015055 0ustar potyrai3guest/* $Id: constraint.h,v 1.7 2009-01-27 15:40:21 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CONSTRAINT_H_INCLUDED #define __CONSTRAINT_H_INCLUDED #include "expr.h" struct constraint { struct constraint *prev; struct constraint *next; const char *string; struct expr *expr; }; struct constraint_list { struct constraint *first; struct constraint *last; }; extern struct constraint * constraint_new(void); extern struct constraint * constraint_dup(struct constraint *oc); extern void constraint_free(struct constraint *c); extern struct constraint_list * constraint_list_new(void); extern struct constraint_list * constraint_list_dup(struct constraint_list *ocl); extern void constraint_list_free(struct constraint_list *cl); extern void constraint_list_append_last(struct constraint_list *cl, struct constraint *c); extern void constraint_output(struct stmt *s, const char *string, struct expr *expr); extern void constraint_input(struct stmt *s, const char *string, struct expr *expr); extern void constraint_change(struct stmt *s, const char *string); #endif /* ! __CONSTRAINT_H_INCLUDED */ faucc-20120707/simplify.c0000640002413100241000000007573011717460534014532 0ustar potyrai3guest/* $Id: simplify.c,v 1.395 2012-02-17 14:17:00 vrsieh Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include #include "cc1.h" #include "identifier.h" #include "declaration.h" #include "stmt.h" #include "expr.h" #include "print.h" #include "visitor.h" #include "simplify.h" static int simplify_change; static void simplify_rename_all_structunionenums_in_stmt(struct stmt *s) { struct stmt *cs; if (s->stmt0) { simplify_rename_all_structunionenums_in_stmt(s->stmt0); } if (s->stmt1) { simplify_rename_all_structunionenums_in_stmt(s->stmt1); } for (cs = s->stmt_first; cs; cs = cs->next) { simplify_rename_all_structunionenums_in_stmt(cs); } if (s->type == STMT_BLOCK) { struct declaration *dion; for (dion = s->scope->declaration_first; dion; dion = dion->next) { if (dion->type_name && (dion->type_name->type == TYPE_STRUCT || dion->type_name->type == TYPE_UNION || dion->type_name->type == TYPE_ENUM) && dion->type_name->scope) { const char *old; const char *new; old = dion->type_name->identifier; new = identifier_tmp(); stmt_rename_structunionenum(s, dion->type_name->type, old, new); } } } } static void simplify_rename_all_structunionenums_in_func(struct stmt *fs) { simplify_rename_all_structunionenums_in_stmt(fs); } static void simplify_rename_all_typevars_in_func(struct stmt *fs) { struct declaration *dion; assert(fs->scope->function); assert(fs->scope->function->type_name->parameter); for (dion = fs->scope->function->type_name->parameter->declaration_first; dion; dion = dion->next) { if (declaration_name_get(dion)) { declaration_name_set(dion, identifier_tmp()); } } for (dion = fs->scope->declaration_first; dion; dion = dion->next) { if (declaration_name_get(dion)) { declaration_name_set(dion, identifier_tmp()); } } } struct declaration * simplify_declaration_add( struct scope *scope, struct type *ts, const char *name ) { struct declaration *dion; dion = declaration_identifier(name); dion->type_name = ts; dion->prev = scope->declaration_last; dion->next = NULL; if (dion->prev) { dion->prev->next = dion; } else { scope->declaration_first = dion; } scope->declaration_last = dion; return dion; } /* ----------------------------------------------------------------- */ /* Scope-related Simplifications */ /* ----------------------------------------------------------------- */ static int simplify_fix_dimensions(struct scope *s) { struct scope *cs; for (cs = s->child_first; cs; cs = cs->next) { simplify_fix_dimensions(cs); } if (s->type == SCOPE_GLOBAL || s->type == SCOPE_FUNCTION || s->type == SCOPE_BLOCK) { struct declaration *dion; for (dion = s->declaration_first; dion; dion = dion->next) { if (dion->type_name && type_is_array(dion->type_name) && ! type_dimension_get(dion->type_name) && declaration_initializer_get(dion)) { struct expr *e; int count; count = 0; for (e = dion->initializer->first; e; e = e->next) { count++; } dion->type_name->dimension = expr_integer(count); simplify_change = 1; } } } return 0; } static int simplify_split_vardecl_init(struct stmt *s) { struct stmt *cs; int retval; retval = 0; if (s->stmt0) { retval |= simplify_split_vardecl_init(s->stmt0); } if (s->stmt1) { retval |= simplify_split_vardecl_init(s->stmt1); } for (cs = s->stmt_first; cs; cs = cs->next) { retval |= simplify_split_vardecl_init(cs); } if (s->type == STMT_BLOCK) { struct declaration *dion; for (dion = s->scope->declaration_last; dion; dion = dion->prev) { if (dion->storage == STORAGE_NONE || dion->storage == STORAGE_AUTO || dion->storage == STORAGE_REGISTER) { struct expr *initializer; initializer = declaration_initializer_get(dion); if (initializer) { struct stmt *s0; declaration_initializer_set(dion, NULL); /* FIXME */ dion->type_name->mod_const = 0; s0 = stmt_expr(expr_assign( expr_identifier(dion), initializer)); stmt_prepend(s, s->stmt_first, s0); retval |= 1; } } } } return retval; } static int simplify_merge_declarations_of_blocks_check(struct stmt *s) { struct declaration *dion; assert(s->type == STMT_BLOCK); for (dion = s->scope->declaration_first; dion; dion = dion->next) { assert(dion->type_name); if (dion->type_name->scope) { assert(! dion->identifier); } if (dion->storage != STORAGE_STATIC && declaration_initializer_get(dion)) { return 0; } } return 1; } static int simplify_merge_declarations_to_func(struct stmt *fb, struct stmt *s) { struct stmt *cs; struct declaration *dion; int retval; retval = 0; if (s->stmt0) { retval |= simplify_merge_declarations_to_func(fb, s->stmt0); } if (s->stmt1) { retval |= simplify_merge_declarations_to_func(fb, s->stmt1); } for (cs = s->stmt_first; cs; cs = cs->next) { retval |= simplify_merge_declarations_to_func(fb, cs); } assert(fb->scope->type == SCOPE_FUNCTION); if (s->type == STMT_BLOCK && simplify_merge_declarations_of_blocks_check(s)) { /* * Move all type and variable definitions from * inner block to outer block. Rename types/variables. */ for (dion = s->scope->declaration_first; dion; ) { struct declaration *next; const char *new_name; const char *old_name; next = dion->next; /* Remove declaration from inner scope. */ if (dion->prev) { dion->prev->next = dion->next; } else { s->scope->declaration_first = dion->next; } if (dion->next) { dion->next->prev = dion->prev; } else { s->scope->declaration_last = dion->prev; } /* Add declaration to outer scope. */ dion->prev = fb->scope->declaration_last; dion->next = NULL; if (dion->prev) { dion->prev->next = dion; } else { fb->scope->declaration_first = dion; } fb->scope->declaration_last = dion; /* Rename declarator. */ old_name = declaration_name_get(dion); if (old_name) { new_name = identifier_tmp(); declaration_name_set(dion, new_name); } dion = next; retval |= 1; } } return retval; } static int simplify_merge_declarations_of_blocks_in_func(struct stmt *fb) { struct stmt *cs; int retval; retval = 0; for (cs = fb->stmt_first; cs; cs = cs->next) { retval |= simplify_merge_declarations_to_func(fb, cs); } return retval; } static int simplify_merge_declarations_of_blocks(struct scope *s) { struct declaration *dion; int retval; retval = 0; for (dion = s->declaration_first; dion; dion = dion->next) { if (dion->stmt) { retval |= simplify_merge_declarations_of_blocks_in_func( dion->stmt); } } return retval; } static void cleanup_func_scope_in_expr( struct scope *gs, struct scope *fs, struct type *tt, struct expr *e ) { struct expr *ce; struct type *ft; if (e->type == EXPR_BRACES || e->type == EXPR_STRING) { ft = NULL; } else { ft = expr_typeof(fs, e); } switch (e->type) { case EXPR_BRACES: if (tt->type == TYPE_STRUCT) { struct declaration *dion; int ret; ret = scope_lookup_structunionenum(fs, tt->type, tt->identifier, &tt); assert(0 <= ret); assert(tt); assert(tt->scope); for (dion = tt->scope->declaration_first, ce = e->first; dion && ce; dion = dion->next, ce = ce->next) { cleanup_func_scope_in_expr(gs, fs, dion->type_name, ce); } } else if (tt->type == TYPE_ARRAY) { for (ce = e->first; ce; ce = ce->next) { cleanup_func_scope_in_expr(gs, fs, type_array_access(tt), ce); } } else { assert(0); } break; case EXPR_STRING: if (tt->type == TYPE_ARRAY) { /* Leave as is. */ } else { struct declaration *dion; dion = declaration_identifier(identifier_tmp()); dion->storage = STORAGE_STATIC; dion->type_name = type_const_char_array(e->string_len + 1); dion->initializer = expr_dup(e); scope_declaration_prepend_first(gs, dion); expr_cp(e, expr_identifier(dion)); simplify_change = 1; } break; case EXPR_INTEGER: case EXPR_REAL: case EXPR_IDENTIFIER: case EXPR_BUILTIN_VA_ARG: case EXPR_STAR: case EXPR_AMPHERSAND: break; case EXPR_TYPE_CONVERSION: case EXPR_NEG: case EXPR_INV: ft = expr_typeof(fs, e->expr0); ft = type_pure(ft); cleanup_func_scope_in_expr(gs, fs, ft, e->expr0); break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: case EXPR_LEFT: case EXPR_RIGHT: case EXPR_ADD: case EXPR_SUB: case EXPR_MUL: case EXPR_DIV: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_XOR: case EXPR_ASSIGN: ft = expr_typeof(fs, e->expr0); ft = type_pure(ft); cleanup_func_scope_in_expr(gs, fs, ft, e->expr0); ft = expr_typeof(fs, e->expr1); ft = type_pure(ft); cleanup_func_scope_in_expr(gs, fs, ft, e->expr1); break; case EXPR_FUNC: for (ce = e->expr1->first; ce; ce = ce->next) { ft = expr_typeof(fs, ce); ft = type_pure(ft); cleanup_func_scope_in_expr(gs, fs, ft, ce); } break; default: assert(0); } } static void cleanup_func_scope_in_func(struct scope *gs, struct declaration *fd) { struct scope *fs; struct declaration *dion; struct stmt *cs; fs = fd->stmt->scope; for (dion = fs->declaration_first; dion; dion = dion->next) { if (dion->initializer) { cleanup_func_scope_in_expr(gs, fs, dion->type_name, dion->initializer); } } for (dion = fs->declaration_first; dion;) { struct declaration *next; next = dion->next; if (dion->storage == STORAGE_STATIC || dion->storage == STORAGE_TYPEDEF || dion->identifier == NULL) { if (dion->identifier) { /* Rename static variable/type definition. */ dion->identifier = identifier_tmp(); } else if (dion->type_name->scope) { /* Rename struct/union/enum definition. */ const char *old; const char *new; assert(dion->type_name->type == TYPE_STRUCT || dion->type_name->type == TYPE_UNION || dion->type_name->type == TYPE_ENUM); old = dion->type_name->identifier; new = identifier_tmp(); stmt_rename_structunionenum(fd->stmt, dion->type_name->type, old, new); dion->type_name->identifier = new; } /* Remove it from functions scope. */ if (dion->prev) { dion->prev->next = dion->next; } else { fs->declaration_first = dion->next; } if (dion->next) { dion->next->prev = dion->prev; } else { fs->declaration_last = dion->prev; } /* Add it to global scope. */ dion->prev = fd->prev; dion->next = fd; if (dion->prev) { dion->prev->next = dion; } else { gs->declaration_first = dion; } dion->next->prev = dion; simplify_change = 1; } dion = next; } for (cs = fd->stmt->stmt_first; cs; cs = cs->next) { struct constraint *c; struct type *t; if (cs->expr0) { t = expr_typeof(fd->stmt->scope, cs->expr0); t = type_pure(t); cleanup_func_scope_in_expr(gs, fs, t, cs->expr0); } if (cs->output) { for (c = cs->output->first; c; c = c->next) { t = expr_typeof(fd->stmt->scope, c->expr); t = type_pure(t); cleanup_func_scope_in_expr(gs, fs, t, c->expr); } } if (cs->input) { for (c = cs->input->first; c; c = c->next) { t = expr_typeof(fd->stmt->scope, c->expr); t = type_pure(t); cleanup_func_scope_in_expr(gs, fs, t, c->expr); } } } } static int cleanup_func_scope(struct scope *scope, struct declaration *dion) { if (dion->initializer) { cleanup_func_scope_in_expr(scope, scope, dion->type_name, dion->initializer); } else if (dion->stmt) { cleanup_func_scope_in_func(scope, dion); } return 0; } /* ----------------------------------------------------------------- */ /* Expression-related Simplifications */ /* ----------------------------------------------------------------- */ static void simplify_inline_in_expr(struct stmt *block, struct stmt *s, struct expr *e) { struct expr *ce; struct declaration *dor0; int retval; if (e->expr0) { simplify_inline_in_expr(block, s, e->expr0); } if (e->expr1) { simplify_inline_in_expr(block, s, e->expr1); } if (e->expr2) { simplify_inline_in_expr(block, s, e->expr2); } for (ce = e->first; ce; ce = ce->next) { simplify_inline_in_expr(block, s, ce); } if (e->type == EXPR_FUNC && e->expr0->type == EXPR_IDENTIFIER) { dor0 = e->expr0->declaration; assert(dor0); if (dor0->mod_inline) { /* * Replace * inline func(p0, ..., pN) { * dion0; * ... * dionM; * * s0; * ...; * return r; * } * ... * func(a0, ..., aN) * by * ... * p0; * ... * pN; * dion0; * ... * dionM; * * p0 = e0; * ... * pN = eN; * s0; * ... * r * * Rename all struct/union/enums, types, vars and labels. */ #if 1 struct type *ts1; struct scope *param; struct declaration *p; struct expr *a; struct stmt *cs; struct stmt *s0; struct expr *e0; assert(dor0->stmt); simplify_rename_all_structunionenums_in_func(dor0->stmt); simplify_rename_all_typevars_in_func(dor0->stmt); assert(dor0->type_name->type == TYPE_FUNCTION); assert(dor0->type_name->parameter); param = dor0->type_name->parameter; /* Clone parameters. */ for (p = param->declaration_first; p; p = p->next) { const char *pn; pn = declaration_name_get(p); if (! pn) { continue; } declaration_type_get(&ts1, p); ts1 = type_pure(ts1); p->clone = simplify_declaration_add( block->scope, ts1, pn); } /* Clone local variables. */ for (p = dor0->stmt->scope->declaration_first; p; p = p->next) { const char *pn; struct expr *pi; pn = declaration_name_get(p); pi = declaration_initializer_get(p); declaration_type_get(&ts1, p); p->clone = simplify_declaration_add( block->scope, ts1, pn); p->clone->storage = p->storage; p->clone->initializer = pi; } /* Clone local labels. */ for (cs = dor0->stmt->stmt_first; cs && cs->type != STMT_RETURN; cs = cs->next) { if (cs->type == STMT_LABEL) { cs->label->clone = label_new(identifier_tmp()); } } /* Copy actual values to formal parameters. */ a = e->expr1->first; for (p = param->declaration_first; p; p = p->next) { const char *pn; assert(p); pn = declaration_name_get(p); if (! pn) { /* void parameter */ continue; } assert(a); e0 = expr_assign( expr_identifier(p->clone), expr_dup(a)); s0 = stmt_expr(e0); stmt_prepend(block, s, s0); a = a->next; } /* Copy statements. */ for (cs = dor0->stmt->stmt_first; cs && cs->type != STMT_RETURN; cs = cs->next) { s0 = stmt_dup(cs); stmt_prepend(block, s, s0); } assert(! cs || (cs->type == STMT_RETURN && ! cs->next)); /* Use return value (if present). */ if (cs && cs->expr0) { e0 = expr_dup(cs->expr0); } else { e0 = expr_integer(0); } expr_cp(e, e0); /* Reset clone info. */ for (cs = dor0->stmt->stmt_first; cs && cs->type != STMT_RETURN; cs = cs->next) { if (cs->type == STMT_LABEL) { cs->label->clone = NULL; } } for (p = param->declaration_first; p; p = p->next) { p->clone = NULL; } for (p = dor0->stmt->scope->declaration_first; p; p = p->next) { p->clone = NULL; } retval = 1; #else retval = 0; #endif } else { retval = 0; } if (retval) { simplify_change = 1; } } } static struct stmt * simplify_inline_in_stmt(struct stmt *fs, struct stmt *s) { struct stmt *next; struct constraint *c; switch (s->type) { case STMT_NONE: assert(0); case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_BREAK: case STMT_CONTINUE: case STMT_CASE: case STMT_DEFAULT: case STMT_BLOCK: /* Should have been done by replace_control. */ assert(0); case STMT_NULL: case STMT_LABEL: case STMT_GOTO: case STMT_VA_START: case STMT_VA_END: /* No function calls. */ next = s->next; break; case STMT_EXPR: case STMT_IF: case STMT_SWITCH: case STMT_RETURN: next = s->next; if (s->expr0) { simplify_inline_in_expr(fs, s, s->expr0); } break; case STMT_ASM: next = s->next; for (c = s->output->first; c; c = c->next) { simplify_inline_in_expr(fs, s, c->expr); } for (c = s->input->first; c; c = c->next) { simplify_inline_in_expr(fs, s, c->expr); } break; default: assert(0); } return next; } static int simplify_inline(struct stmt *fs) { struct stmt *cs; assert(fs->type == STMT_BLOCK); if (fs->scope->function->mod_inline) { /* Don't do inlining in inline functions. */ return 0; } simplify_change = 0; for (cs = fs->stmt_first; cs; ) { cs = simplify_inline_in_stmt(fs, cs); } return simplify_change; } static void simplify_pointer_to_int_in_expr_1( struct scope *scope, struct type *tt, struct expr *e ) { struct expr *ce; struct expr *e0; struct expr *e1; struct expr *e2; struct type *ft; if (e->type != EXPR_BRACES && e->type != EXPR_STRING) { ft = expr_typeof(scope, e); } else { ft = NULL; } switch (e->type) { case EXPR_NONE: assert(0); case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_LIST: assert(0); case EXPR_BRACES: if (tt->type == TYPE_ARRAY) { for (ce = e->first; ce; ce = ce->next) { simplify_pointer_to_int_in_expr_1(scope, type_array_access(tt), ce); } } else if (tt->type == TYPE_STRUCT || tt->type == TYPE_UNION) { struct declaration *dion; if (! tt->scope) { int ret; ret = scope_lookup_structunionenum(scope, tt->type, tt->identifier, &tt); assert(0 <= ret); } assert(tt); assert(tt->scope); for (dion = tt->scope->declaration_first, ce = e->first; ; dion = dion->next, ce = ce->next) { if (! dion || ! ce) { break; } simplify_pointer_to_int_in_expr_1(scope, dion->type_name, ce); } break; } else { assert(0); } break; case EXPR_INTEGER: case EXPR_REAL: break; case EXPR_STRING: if (tt->type == TYPE_POINTER) { /* * Replace * "..." * by * (int) "..." */ e0 = expr_dup(e); e1 = expr_cast(type_ptrdiff(), e0); expr_cp(e, e1); simplify_change = 1; } else if (tt->type == TYPE_ARRAY) { /* Nothing to do... */ } else { assert(0); } break; case EXPR_IDENTIFIER: if (ft->type == TYPE_ARRAY || ft->type == TYPE_FUNCTION) { /* * Replace * array func * by * (int) array (int) func */ e0 = expr_dup(e); e1 = expr_cast(type_ptrdiff(), e0); expr_cp(e, e1); simplify_change = 1; } else if (ft->type == TYPE_POINTER) { /* Will replaced by second step. */ } break; case EXPR_AMPHERSAND: /* * Replace * &x * by * (int) &x */ assert(e->expr0->type == EXPR_IDENTIFIER); e0 = expr_dup(e); e1 = expr_cast(type_ptrdiff(), e0); expr_cp(e, e1); simplify_change = 1; break; case EXPR_BUILTIN_VA_ARG: if (ft->type == TYPE_POINTER) { /* * Replace * va_arg(list, type *) * by * va_arg(list, ptrdiff) */ e0 = expr_dup(e); e0->type_name = type_ptrdiff(); expr_cp(e, e0); simplify_change = 1; } break; case EXPR_STAR: if (expr_typeof(scope, e->expr0)->type == TYPE_ARRAY) { /* * Leave * *array * as is. */ break; } else if (ft->type == TYPE_POINTER) { /* * Replace * *x * by * *(int *) x */ e0 = expr_dup(e->expr0); e1 = expr_cast(type_amphersand(type_ptrdiff()), e0); e2 = expr_star(e1); } else { /* * Replace * *x * by * *(typeof *x) x */ e0 = expr_dup(e->expr0); e1 = expr_cast(type_amphersand(ft), e0); e2 = expr_star(e1); } expr_cp(e, e2); simplify_change = 1; break; case EXPR_TYPE_CONVERSION: if (ft->type == TYPE_POINTER) { /* * Replace * (typeof *x) x * by * (int) x */ e0 = expr_dup(e->expr0); e1 = expr_cast(type_ptrdiff(), e0); expr_cp(e, e1); simplify_change = 1; } break; case EXPR_NEG: case EXPR_INV: simplify_pointer_to_int_in_expr_1(scope, expr_typeof(scope, e->expr0), e->expr0); break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: case EXPR_RIGHT: case EXPR_LEFT: case EXPR_ADD: case EXPR_SUB: case EXPR_MUL: case EXPR_DIV: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_XOR: simplify_pointer_to_int_in_expr_1(scope, expr_typeof(scope, e->expr0), e->expr0); simplify_pointer_to_int_in_expr_1(scope, expr_typeof(scope, e->expr1), e->expr1); break; case EXPR_FUNC: /* * Replace function call. */ if (e->expr0->type == EXPR_STAR) { /* FIXME */ } /* * Replace function parameters. */ for (ce = e->expr1->first; ce; ce = ce->next) { struct type *pt; pt = expr_typeof(scope, ce); pt = type_pure(pt); simplify_pointer_to_int_in_expr_1(scope, pt, ce); } break; default: assert(0); } } static void simplify_pointer_to_int_in_init_1( struct scope *scope, struct type *t, struct expr *e ) { simplify_pointer_to_int_in_expr_1(scope, t, e); } static void simplify_pointer_to_int_in_func_1(struct stmt *fs) { struct declaration *dion; struct stmt *cs; struct constraint *c; struct type *t; for (dion = fs->scope->declaration_first; dion; dion = dion->next) { if (dion->initializer) { simplify_pointer_to_int_in_init_1(fs->scope, dion->type_name, dion->initializer); } } for (cs = fs->stmt_first; cs; cs = cs->next) { switch (cs->type) { case STMT_LABEL: break; case STMT_EXPR: switch (cs->expr0->type) { case EXPR_ASSIGN: t = expr_typeof(fs->scope, cs->expr0->expr0); simplify_pointer_to_int_in_expr_1(fs->scope, t, cs->expr0->expr0); simplify_pointer_to_int_in_expr_1(fs->scope, t, cs->expr0->expr1); break; case EXPR_FUNC: t = expr_typeof(fs->scope, cs->expr0); simplify_pointer_to_int_in_expr_1(fs->scope, t, cs->expr0); break; default: assert(0); } break; case STMT_IF: switch (cs->expr0->type) { case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: t = expr_typeof(fs->scope, cs->expr0); simplify_pointer_to_int_in_expr_1(fs->scope, t, cs->expr0); break; default: assert(0); } break; case STMT_SWITCH: switch (cs->expr0->type) { case EXPR_IDENTIFIER: t = expr_typeof(fs->scope, cs->expr0); simplify_pointer_to_int_in_expr_1(fs->scope, t, cs->expr0); break; default: assert(0); } break; case STMT_GOTO: break; case STMT_RETURN: if (cs->expr0) { switch (cs->expr0->type) { case EXPR_INTEGER: break; case EXPR_IDENTIFIER: t = expr_typeof(fs->scope, cs->expr0); simplify_pointer_to_int_in_expr_1(fs->scope, t, cs->expr0); break; default: assert(0); } } break; case STMT_ASM: if (cs->output) { for (c = cs->output->first; c; c = c->next) { simplify_pointer_to_int_in_expr_1(fs->scope, expr_typeof(fs->scope, c->expr), c->expr); } } if (cs->input) { for (c = cs->input->first; c; c = c->next) { simplify_pointer_to_int_in_expr_1(fs->scope, expr_typeof(fs->scope, c->expr), c->expr); } } break; case STMT_VA_START: break; case STMT_VA_END: break; default: assert(0); } } } static void simplify_pointer_to_int_in_type_2(struct type **tp) { struct type *t0; struct type *t1; t0 = *tp; t1 = type_pointer_to_ptrdiff(t0); if (t1 != t0) { *tp = t1; simplify_change = 1; } } static void simplify_pointer_to_int_in_func_2(struct stmt *fs) { struct declaration *dion; for (dion = fs->scope->function->type_name->parameter->declaration_first; dion; dion = dion->next) { simplify_pointer_to_int_in_type_2(&dion->type_name); } for (dion = fs->scope->declaration_first; dion; dion = dion->next) { simplify_pointer_to_int_in_type_2(&dion->type_name); } } static int simplify_pointer_to_int(struct scope *scope) { struct declaration *dion; /* * First step: * Replace all expressions */ for (dion = scope->declaration_first; dion; dion = dion->next) { if (dion->initializer) { simplify_pointer_to_int_in_init_1(scope, dion->type_name, dion->initializer); } if (dion->stmt) { simplify_pointer_to_int_in_func_1(dion->stmt); } } /* * Second step: * Replace types of variables. */ for (dion = scope->declaration_first; dion; dion = dion->next) { if (dion->type_name) { simplify_pointer_to_int_in_type_2(&dion->type_name); } if (dion->stmt) { simplify_pointer_to_int_in_func_2(dion->stmt); } } return 0; } static int simplify_rename_labels_in_stmt( struct stmt *top, struct stmt *s ) { struct stmt *cs; int retval; retval = 0; if (s->stmt0) { retval |= simplify_rename_labels_in_stmt(top, s->stmt0); } if (s->stmt1) { retval |= simplify_rename_labels_in_stmt(top, s->stmt1); } for (cs = s->stmt_first; cs; cs = cs->next) { retval |= simplify_rename_labels_in_stmt(top, cs); } if (s->type == STMT_LABEL && strncmp(s->label->identifier, "__", 2) != 0) { s->label->identifier = identifier_tmp(); retval |= 1; } return retval; } static int simplify_rename_labels(struct scope *s) { struct declaration *dion; int retval; retval = 0; for (dion = s->declaration_first; dion; dion = dion->next) { if (dion->stmt) { retval |= simplify_rename_labels_in_stmt( dion->stmt, dion->stmt); } } return retval; } static int simplify_inline_remove(struct scope *s) { struct declaration *dion; for (dion = s->declaration_first; dion; ) { struct declaration *next; next = dion->next; if (dion->mod_inline) { /* Remove inline function from declaration list. */ if (dion->prev) { dion->prev->next = dion->next; } else { s->declaration_first = dion->next; } if (dion->next) { dion->next->prev = dion->prev; } else { s->declaration_last = dion->prev; } /* Free inline function. */ /* FIXME */ } dion = next; } return 0; } static void simplify_debug(struct scope *scope, const char *f) { if (opt_d) { static int count = 0; char path[1024]; FILE *fp; int ret; fprintf(stderr, "%s\n", f); sprintf(path, "step%04d", count++); fp = fopen(path, "w"); assert(fp); ret = setvbuf(fp, NULL, _IONBF, 0); assert(ret == 0); fprintf(fp, "%s\n", f); fprintf(fp, "******************************\n"); fprintf(fp, "\n"); print(fp, scope); ret = fclose(fp); assert(0 <= ret); } } static int simplify_once(const char *n, int (*f)(struct scope *), struct scope *s) { int retval; int val; retval = 0; simplify_change = 0; val = (*f)(s); val |= simplify_change; if (val) { retval = 1; simplify_debug(s, n); } return retval; } static int simplify_repeat(const char *n, int (*f)(struct scope *), struct scope *s) { int retval; int val; retval = 0; restart:; simplify_change = 0; val = (*f)(s); val |= simplify_change; if (val) { retval = 1; simplify_debug(s, n); goto restart; } return retval; } static int simplify_once_dion( const char *n, int (*f)(struct scope *, struct declaration *), struct scope *s ) { struct declaration *dion; int retval; int val; retval = 0; for (dion = s->declaration_first; dion; dion = dion->next) { simplify_change = 0; val = (*f)(s, dion); val |= simplify_change; if (val) { retval = 1; simplify_debug(s, n); } } return retval; } static int simplify_repeat_dion( const char *n, int (*f)(struct scope *, struct declaration *), struct scope *s ) { struct declaration *dion; int retval; int val; retval = 0; for (dion = s->declaration_first; dion; dion = dion->next) { restart:; simplify_change = 0; val = (*f)(s, dion); val |= simplify_change; if (val) { retval = 1; simplify_debug(s, n); goto restart; } } return retval; } static int simplify_once_func(const char *n, int (*f)(struct stmt *), struct scope *s) { struct declaration *dion; int retval; int val; retval = 0; for (dion = s->declaration_first; dion; dion = dion->next) { if (dion->stmt) { simplify_change = 0; val = (*f)(dion->stmt); val |= simplify_change; if (val) { retval = 1; simplify_debug(s, n); } } } return retval; } static int simplify_repeat_func(const char *n, int (*f)(struct stmt *), struct scope *s) { struct declaration *dion; int retval; int val; retval = 0; for (dion = s->declaration_first; dion; dion = dion->next) { if (dion->stmt) { restart:; simplify_change = 0; val = (*f)(dion->stmt); val |= simplify_change; if (val) { retval = 1; simplify_debug(s, n); goto restart; } } } return retval; } void simplify(struct scope *scope) { int retval; simplify_debug(scope, "parse"); #define ONCE(x, s) simplify_once(#x, x, s) #define REPEAT(x, s) simplify_repeat(#x, x, s) #define ONCE_DION(x, s) simplify_once_dion(#x, x, s) #define REPEAT_DION(x, s) simplify_repeat_dion(#x, x, s) #define ONCE_FUNC(x, s) simplify_once_func(#x, x, s) #define REPEAT_FUNC(x, s) simplify_repeat_func(#x, x, s) /* * First step: * Clean up parsed code. */ ONCE(simplify_fix_dimensions, scope); ONCE_FUNC(simplify_split_vardecl_init, scope); ONCE(simplify_merge_declarations_of_blocks, scope); /* * Second step: * Translate control structures. * Split some expressions. */ ONCE_FUNC(stmt_simplify, scope); ONCE_FUNC(stmt_simplify_params, scope); ONCE_FUNC(stmt_simplify_returns, scope); REPEAT_DION(expr_simplify, scope); /* * Third step: * Do inlining. */ REPEAT_FUNC(simplify_inline, scope); REPEAT_DION(expr_simplify, scope); /* * Fourth step: * Do optimization. */ do { retval = REPEAT_DION(expr_optimize, scope); retval |= ONCE_FUNC(stmt_optimize, scope); } while (retval); /* * Fifth step: * Replace all pointers by integer vars. */ ONCE(simplify_pointer_to_int, scope); /* * Sixth step: * Do some more optimizations. */ do { retval = REPEAT_DION(expr_optimize, scope); retval |= ONCE_FUNC(stmt_optimize, scope); } while (retval); /* * Seventh step: * Prepare for compiling. */ ONCE(simplify_inline_remove, scope); ONCE(simplify_rename_labels, scope); ONCE_DION(cleanup_func_scope, scope); } faucc-20120707/parse.y0000640002413100241000000011476311717461564014042 0ustar potyrai3guest/* $Id: parse.y,v 1.131 2012-02-17 14:25:56 vrsieh Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ %{ #include #include #include #include #include "scan.h" #include "identifier.h" #include "constraint.h" #include "declaration.h" #include "scope.h" #include "stmt.h" #include "expr.h" %} %union { int nil; unsigned long long integer; long double real; struct { unsigned int len; const char *string; } string; const char *identifier; int const_volatile; struct { enum { TYPE_SPEC_NONE, TYPE_SPEC_VOID, TYPE_SPEC_CHAR, TYPE_SPEC_INT, TYPE_SPEC_FLOAT, TYPE_SPEC_DOUBLE, TYPE_SPEC_STRUCT, TYPE_SPEC_UNION, TYPE_SPEC_ENUM, TYPE_SPEC_USER, TYPE_SPEC_ELIPSIS, TYPE_SPEC_VA_LIST, } type; const char *identifier; unsigned int mod_short; unsigned int mod_long; unsigned int mod_signed; unsigned int mod_unsigned; unsigned int mod_const; unsigned int mod_volatile; unsigned int attr_aligned; unsigned int attr_packed; enum type_storage storage; unsigned int mod_inline; unsigned int mod_noreturn; } type_spec_0; struct { struct type *type; enum type_storage storage; unsigned int mod_inline; unsigned int mod_noreturn; } type_spec_1; struct { int mod_noreturn; int attr_aligned; int attr_packed; } attrs; struct type *type; struct declaration *declarator; struct type *type_name; struct constraint *constraint; struct constraint_list *constraint_list; struct { struct declaration *first; struct declaration *last; } declarator_list; struct declaration *declaration; struct { struct declaration *first; struct declaration *last; } declaration_list; struct stmt *stmt; struct { struct stmt *first; struct stmt *last; } stmt_list; struct expr *expr; } %{ extern int line; extern int column; static struct scope *parse_scope; static unsigned int enum_next; void __attribute__((noreturn)) yyerror(const char *s) { fprintf(stderr, "%d/%d: %s.\n", line, column, s); exit(1); } static void __attribute__((noreturn)) parse_unknown(const char *identifier) { char msg[1024]; sprintf(msg, "%s: unknown", identifier); yyerror(msg); } %} %right '=' MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN %right '?' ':' %left OR_OP %left AND_OP %left '|' %left '^' %left '&' %left EQ_OP NE_OP %left '<' '>' LE_OP GE_OP %left LEFT_OP RIGHT_OP %left '+' '-' %left '*' '/' '%' %right CAST %right SIZEOF BUILTIN_OFFSETOF BUILTIN_VA_ARG BUILTIN_CONSTANT_P %right PTR_OP INC_OP DEC_OP %token TYPEDEF EXTERN STATIC AUTO REGISTER %token CHAR INT FLOAT DOUBLE VOID BUILTIN_VA_LIST %token SHORT LONG SIGNED UNSIGNED CONST VOLATILE %token ATTRIBUTE %token STRUCT UNION ENUM %token ELIPSIS %token INLINE %token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN %token ASM BUILTIN_VA_START BUILTIN_VA_END %token IDENTIFIER %token TYPE_NAME %token INTEGER_LITERAL INTEGER_LITERAL_L INTEGER_LITERAL_LL %token INTEGER_LITERAL_U INTEGER_LITERAL_UL INTEGER_LITERAL_ULL %token REAL_LITERAL %token STRING_LITERAL %type const_volatile_e %type type_spec_mod %type type_spec_type %type type_spec_storage %type type_spec_0 %type type_spec %type enumerator_list_comma %type enumerator_list %type enumerator %type declarator_list_e %type declarator_list %type declarator %type declarator2 %type declarator3 %type declarator4 %type abstract_declarator %type abstract_declarator2 %type asm_constraint_list_e %type asm_constraint_list %type asm_constraint %type asm_change_list_e %type asm_change_list %type asm_change %type parameter_type_list_e %type parameter_type_list %type parameter_list %type parameter_declaration %type type_name %type constant_primary_expr %type primary_expr %type constant_unary_expr %type unary_expr %type offsetof_member_designator %type constant_multiplicative_expr %type multiplicative_expr %type constant_additive_expr %type additive_expr %type constant_shift_expr %type shift_expr %type constant_relational_expr %type relational_expr %type constant_equality_expr %type equality_expr %type constant_and_expr %type and_expr %type constant_exclusive_or_expr %type exclusive_or_expr %type constant_inclusive_or_expr %type inclusive_or_expr %type logical_and_expr %type logical_or_expr %type constant_conditional_expr %type conditional_expr %type assignment_expr %type expr_list_e %type expr_list %type expr %type expr_e %type constant_expr %type initializer_expr %type initializer_expr_list %type attribute_e %type attribute %type attribute_element_list %type attribute_element %type attribute_list %type statement_list %type statement %type compound_statement %type identifier_e %type identifier %type string %start file %% constant_primary_expr : INTEGER_LITERAL { $$ = $1; } | '(' constant_expr ')' { $$ = $2; } ; primary_expr : INTEGER_LITERAL { $$ = expr_new(); $$->type = EXPR_INTEGER; $$->type_name = type_int(); $$->integer = $1; } | INTEGER_LITERAL_L { $$ = expr_new(); $$->type = EXPR_INTEGER; $$->type_name = type_long_int(); $$->integer = $1; } | INTEGER_LITERAL_LL { $$ = expr_new(); $$->type = EXPR_INTEGER; $$->type_name = type_long_long_int(); $$->integer = $1; } | INTEGER_LITERAL_U { $$ = expr_new(); $$->type = EXPR_INTEGER; $$->type_name = type_unsigned_int(); $$->integer = $1; } | INTEGER_LITERAL_UL { $$ = expr_new(); $$->type = EXPR_INTEGER; $$->type_name = type_unsigned_long_int(); $$->integer = $1; } | INTEGER_LITERAL_ULL { $$ = expr_new(); $$->type = EXPR_INTEGER; $$->type_name = type_unsigned_long_long_int(); $$->integer = $1; } /* | REAL_LITERAL_F - FIXME */ | REAL_LITERAL { $$ = expr_new(); $$->type = EXPR_REAL; $$->type_name = type_double(); $$->real = $1; } /* | REAL_LITERAL_L - FIXME */ | string { $$ = expr_new(); $$->type = EXPR_STRING; $$->string_len = $1.len; $$->string = $1.string; } | IDENTIFIER { int ret; $$ = expr_new(); $$->type = EXPR_IDENTIFIER; ret = scope_lookup_current($1, &$$->declaration); if (ret < 0) { parse_unknown($1); } assert(0 <= ret); } | '(' expr ')' { $$ = $2; } | primary_expr '[' expr ']' { $$ = expr_new(); $$->type = EXPR_ARRAY; $$->expr0 = $1; $$->expr1 = $3; } | primary_expr '(' expr_list_e ')' { $$ = expr_new(); $$->type = EXPR_FUNC; $$->expr0 = $1; $$->expr1 = $3; } | primary_expr '.' identifier { $$ = expr_new(); $$->type = EXPR_DOT; $$->expr0 = $1; $$->member = $3; } | primary_expr PTR_OP identifier { $$ = expr_new(); $$->type = EXPR_ARROW; $$->expr0 = $1; $$->member = $3; } ; constant_unary_expr : constant_primary_expr { $$ = $1; } | '-' constant_unary_expr { $$ = -$2; } | '~' constant_unary_expr { $$ = ~$2; } /* | SIZEOF conditional_expr %prec SIZEOF { $$ = 0; } */ /* FIXME */ | SIZEOF '(' type_name ')' %prec SIZEOF { $$ = type_sizeof(scope_current, $3); } ; unary_expr : primary_expr { $$ = $1; } | primary_expr INC_OP { $$ = expr_new(); $$->type = EXPR_POST_INC; $$->expr0 = $1; } | primary_expr DEC_OP { $$ = expr_new(); $$->type = EXPR_POST_DEC; $$->expr0 = $1; } | '*' unary_expr { $$ = expr_new(); $$->type = EXPR_STAR; $$->expr0 = $2; } | '&' unary_expr { $$ = expr_new(); $$->type = EXPR_AMPHERSAND; $$->expr0 = $2; } | '+' unary_expr /* Correct? FIXME */ { $$ = $2; } | '-' unary_expr { $$ = expr_new(); $$->type = EXPR_NEG; $$->expr0 = $2; } | '!' unary_expr { $$ = expr_new(); $$->type = EXPR_NOT; $$->expr0 = $2; } | '~' unary_expr { $$ = expr_new(); $$->type = EXPR_INV; $$->expr0 = $2; } | INC_OP unary_expr { $$ = expr_new(); $$->type = EXPR_PRE_INC; $$->expr0 = $2; } | DEC_OP unary_expr { $$ = expr_new(); $$->type = EXPR_PRE_DEC; $$->expr0 = $2; } | '(' type_name ')' unary_expr %prec CAST { $$ = expr_new(); $$->type = EXPR_TYPE_CONVERSION; $$->type_name = $2; $$->expr0 = $4; } | SIZEOF unary_expr %prec SIZEOF { $$ = expr_new(); $$->type = EXPR_SIZEOF_EXPR; $$->expr0 = $2; } | SIZEOF '(' type_name ')' %prec SIZEOF { $$ = expr_new(); $$->type = EXPR_SIZEOF_TYPE; $$->type_name = $3; } | BUILTIN_OFFSETOF '(' type_name ',' offsetof_member_designator ')' { $$ = expr_new(); $$->type = EXPR_BUILTIN_OFFSETOF; $$->type_name = $3; $$->expr0 = $5; } | BUILTIN_VA_ARG '(' identifier ',' type_name ')' { int ret; $$ = expr_new(); $$->type = EXPR_BUILTIN_VA_ARG; $$->type_name = $5; $$->expr0 = expr_new(); $$->expr0->type = EXPR_IDENTIFIER; ret = scope_lookup_current($3, &$$->expr0->declaration); assert(0 <= ret); } | BUILTIN_CONSTANT_P '(' expr ')' { $$ = expr_new(); $$->type = EXPR_BUILTIN_CONSTANT_P; $$->expr0 = $3; } ; offsetof_member_designator : identifier { $$ = expr_new(); $$->type = EXPR_ARROW; $$->member = $1; } | offsetof_member_designator '.' identifier { $$ = expr_new(); $$->type = EXPR_DOT; $$->member = $3; $$->expr0 = $1; } | offsetof_member_designator '[' expr ']' { $$ = expr_new(); $$->type = EXPR_ARRAY; $$->expr0 = $1; $$->expr1 = $3; } ; constant_multiplicative_expr : constant_unary_expr { $$ = $1; } | constant_multiplicative_expr '*' constant_unary_expr { $$ = $1 * $3; } | constant_multiplicative_expr '/' constant_unary_expr { $$ = $1 / $3; } | constant_multiplicative_expr '%' constant_unary_expr { $$ = $1 % $3; } multiplicative_expr : unary_expr { $$ = $1; } | multiplicative_expr '*' unary_expr { $$ = expr_new(); $$->type = EXPR_MUL; $$->expr0 = $1; $$->expr1 = $3; } | multiplicative_expr '/' unary_expr { $$ = expr_new(); $$->type = EXPR_DIV; $$->expr0 = $1; $$->expr1 = $3; } | multiplicative_expr '%' unary_expr { $$ = expr_new(); $$->type = EXPR_MOD; $$->expr0 = $1; $$->expr1 = $3; } ; constant_additive_expr : constant_multiplicative_expr { $$ = $1; } | constant_additive_expr '+' constant_multiplicative_expr { $$ = $1 + $3; } | constant_additive_expr '-' constant_multiplicative_expr { $$ = $1 - $3; } ; additive_expr : multiplicative_expr { $$ = $1; } | additive_expr '+' multiplicative_expr { $$ = expr_new(); $$->type = EXPR_ADD; $$->expr0 = $1; $$->expr1 = $3; } | additive_expr '-' multiplicative_expr { $$ = expr_new(); $$->type = EXPR_SUB; $$->expr0 = $1; $$->expr1 = $3; } ; constant_shift_expr : constant_additive_expr { $$ = $1; } | constant_shift_expr LEFT_OP constant_additive_expr { $$ = $1 << $3; } | constant_shift_expr RIGHT_OP constant_additive_expr { $$ = $1 >> $3; } ; shift_expr : additive_expr { $$ = $1; } | shift_expr LEFT_OP additive_expr { $$ = expr_new(); $$->type = EXPR_LEFT; $$->expr0 = $1; $$->expr1 = $3; } | shift_expr RIGHT_OP additive_expr { $$ = expr_new(); $$->type = EXPR_RIGHT; $$->expr0 = $1; $$->expr1 = $3; } ; constant_relational_expr : constant_shift_expr { $$ = $1; } | constant_relational_expr '<' constant_shift_expr { $$ = $1 < $3; } | constant_relational_expr '>' constant_shift_expr { $$ = $1 > $3; } | constant_relational_expr LE_OP constant_shift_expr { $$ = $1 <= $3; } | constant_relational_expr GE_OP constant_shift_expr { $$ = $1 >= $3; } ; relational_expr : shift_expr { $$ = $1; } | relational_expr '<' shift_expr { $$ = expr_new(); $$->type = EXPR_LESS; $$->expr0 = $1; $$->expr1 = $3; } | relational_expr '>' shift_expr { $$ = expr_new(); $$->type = EXPR_GREATER; $$->expr0 = $1; $$->expr1 = $3; } | relational_expr LE_OP shift_expr { $$ = expr_new(); $$->type = EXPR_LESS_EQUAL; $$->expr0 = $1; $$->expr1 = $3; } | relational_expr GE_OP shift_expr { $$ = expr_new(); $$->type = EXPR_GREATER_EQUAL; $$->expr0 = $1; $$->expr1 = $3; } ; constant_equality_expr : constant_relational_expr { $$ = $1; } | constant_equality_expr EQ_OP constant_relational_expr { $$ = $1 == $3; } | constant_equality_expr NE_OP constant_relational_expr { $$ = $1 != $3; } ; equality_expr : relational_expr { $$ = $1; } | equality_expr EQ_OP relational_expr { $$ = expr_new(); $$->type = EXPR_EQUAL; $$->expr0 = $1; $$->expr1 = $3; } | equality_expr NE_OP relational_expr { $$ = expr_new(); $$->type = EXPR_NOT_EQUAL; $$->expr0 = $1; $$->expr1 = $3; } ; constant_and_expr : constant_equality_expr { $$ = $1; } | constant_and_expr '&' constant_equality_expr { $$ = $1 & $3; } ; and_expr : equality_expr { $$ = $1; } | and_expr '&' equality_expr { $$ = expr_new(); $$->type = EXPR_AND; $$->expr0 = $1; $$->expr1 = $3; } ; constant_exclusive_or_expr : constant_and_expr { $$ = $1; } | constant_exclusive_or_expr '^' constant_and_expr { $$ = $1 ^ $3; } ; exclusive_or_expr : and_expr { $$ = $1; } | exclusive_or_expr '^' and_expr { $$ = expr_new(); $$->type = EXPR_XOR; $$->expr0 = $1; $$->expr1 = $3; } ; constant_inclusive_or_expr : constant_exclusive_or_expr { $$ = $1; } | constant_inclusive_or_expr '|' constant_exclusive_or_expr { $$ = $1 | $3; } ; inclusive_or_expr : exclusive_or_expr { $$ = $1; } | inclusive_or_expr '|' exclusive_or_expr { $$ = expr_new(); $$->type = EXPR_OR; $$->expr0 = $1; $$->expr1 = $3; } ; logical_and_expr : inclusive_or_expr { $$ = $1; } | logical_and_expr AND_OP inclusive_or_expr { $$ = expr_new(); $$->type = EXPR_SHORT_AND; $$->expr0 = $1; $$->expr1 = $3; } ; logical_or_expr : logical_and_expr { $$ = $1; } | logical_or_expr OR_OP logical_and_expr { $$ = expr_new(); $$->type = EXPR_SHORT_OR; $$->expr0 = $1; $$->expr1 = $3; } ; constant_conditional_expr : constant_inclusive_or_expr { $$ = $1; } | constant_inclusive_or_expr '?' constant_conditional_expr ':' constant_conditional_expr { $$ = $1 ? $3 : $5; } ; conditional_expr : logical_or_expr { $$ = $1; } | logical_or_expr '?' conditional_expr ':' conditional_expr { $$ = expr_new(); $$->type = EXPR_CONDITION; $$->expr0 = $1; $$->expr1 = $3; $$->expr2 = $5; } ; assignment_expr : conditional_expr { $$ = $1; } | unary_expr '=' assignment_expr { $$ = expr_new(); $$->type = EXPR_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } | unary_expr MUL_ASSIGN assignment_expr { $$ = expr_new(); $$->type = EXPR_MUL_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } | unary_expr DIV_ASSIGN assignment_expr { $$ = expr_new(); $$->type = EXPR_DIV_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } | unary_expr MOD_ASSIGN assignment_expr { $$ = expr_new(); $$->type = EXPR_MOD_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } | unary_expr ADD_ASSIGN assignment_expr { $$ = expr_new(); $$->type = EXPR_ADD_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } | unary_expr SUB_ASSIGN assignment_expr { $$ = expr_new(); $$->type = EXPR_SUB_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } | unary_expr LEFT_ASSIGN assignment_expr { $$ = expr_new(); $$->type = EXPR_LEFT_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } | unary_expr RIGHT_ASSIGN assignment_expr { $$ = expr_new(); $$->type = EXPR_RIGHT_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } | unary_expr AND_ASSIGN assignment_expr { $$ = expr_new(); $$->type = EXPR_AND_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } | unary_expr XOR_ASSIGN assignment_expr { $$ = expr_new(); $$->type = EXPR_XOR_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } | unary_expr OR_ASSIGN assignment_expr { $$ = expr_new(); $$->type = EXPR_OR_ASSIGN; $$->expr0 = $1; $$->expr1 = $3; } ; expr_list_e : /* lambda */ { $$ = expr_new(); $$->type = EXPR_LIST; $$->first = NULL; $$->last = NULL; } | expr_list { $$ = $1; } ; expr_list : assignment_expr { $$ = expr_new(); $$->type = EXPR_LIST; $1->prev = NULL; $1->next = NULL; $$->first = $1; $$->last = $1; } | expr_list ',' assignment_expr { $3->prev = $1->last; $3->next = NULL; if ($3->prev) { $3->prev->next = $3; } else { $1->first = $3; } $1->last = $3; $$ = $1; } ; expr : assignment_expr { $$ = $1; } | expr ',' assignment_expr { if ($1->type == EXPR_LIST) { /* Add last to first. */ $3->prev = $1->last; $3->next = NULL; $3->prev->next = $3; $1->last = $3; $$ = $1; } else { /* Create new list. */ $$ = expr_new(); $$->type = EXPR_LIST; $1->prev = NULL; $1->next = $3; $3->prev = $1; $3->next = NULL; $$->first = $1; $$->last = $3; }} ; expr_e : /* lambda */ { $$ = NULL; } | expr { $$ = $1; } ; constant_expr : constant_conditional_expr { $$ = $1; } ; initializer_expr : assignment_expr { $$ = $1; } | '{' initializer_expr_list '}' { $$ = $2; } | '{' initializer_expr_list ',' '}' { $$ = $2; } ; initializer_expr_list : initializer_expr { $$ = expr_new(); $$->type = EXPR_BRACES; $1->prev = NULL; $1->next = NULL; $$->first = $1; $$->last = $1; } | initializer_expr_list ',' initializer_expr { $3->prev = $1->last; $3->next = NULL; $3->prev->next = $3; $1->last = $3; $$ = $1; } ; attribute_e : /* lambda */ { memset(&$$, 0, sizeof($$)); } | attribute_e attribute { memset(&$$, 0, sizeof $$); $$.mod_noreturn = $1.mod_noreturn | $2.mod_noreturn; if ($1.attr_aligned < $2.attr_aligned) { $$.attr_aligned = $2.attr_aligned; } else { $$.attr_aligned = $1.attr_aligned; } $$.attr_packed = $1.attr_packed | $2.attr_packed; } ; attribute : ATTRIBUTE '(' '(' attribute_element_list ')' ')' { memcpy(&$$, &$4, sizeof $$); } ; attribute_element_list : attribute_element { memcpy(&$$, &$1, sizeof $$); } | attribute_element_list ',' attribute_element { $$.mod_noreturn = $1.mod_noreturn | $3.mod_noreturn; if ($1.attr_aligned < $3.attr_aligned) { $$.attr_aligned = $3.attr_aligned; } else { $$.attr_aligned = $1.attr_aligned; } $$.attr_packed = $1.attr_packed | $3.attr_packed; } ; attribute_element : identifier { memset(&$$, 0, sizeof $$); $$.mod_noreturn = (strcmp($1, "noreturn") == 0) | (strcmp($1, "__noreturn__") == 0); $$.attr_packed = (strcmp($1, "packed") == 0) | (strcmp($1, "__packed__") == 0); } | CONST { memset(&$$, 0, sizeof $$); } | identifier '(' attribute_list ')' { memset(&$$, 0, sizeof $$); if (strcmp($1, "aligned") == 0 || strcmp($1, "__aligned__") == 0) { $$.attr_aligned = $3; } } ; attribute_list : INTEGER_LITERAL { $$ = $1; } | string { $$ = 0; } /* FIXME */ | identifier { $$ = 0; } /* FIXME */ | attribute_list ',' INTEGER_LITERAL { $$ = 0; } /* FIXME */ | attribute_list ',' string { $$ = 0; } /* FIXME */ | attribute_list ',' identifier { $$ = 0; } /* FIXME */ ; volatile_e : /* lambda */ | VOLATILE ; const_volatile_e : /* lambda */ { $$ = 0; } | const_volatile_e VOLATILE { $$ = $1 | 1; } | const_volatile_e CONST { $$ = $1 | 2; } ; type_spec_mod : SHORT { memset(&$$, 0, sizeof $$); $$.mod_short = 1; } | LONG { memset(&$$, 0, sizeof $$); $$.mod_long = 1; } | SIGNED { memset(&$$, 0, sizeof $$); $$.mod_signed = 1; } | UNSIGNED { memset(&$$, 0, sizeof $$); $$.mod_unsigned = 1; } | CONST { memset(&$$, 0, sizeof $$); $$.mod_const = 1; } | VOLATILE { memset(&$$, 0, sizeof $$); $$.mod_volatile = 1; } | INLINE { memset(&$$, 0, sizeof $$); $$.mod_inline = 1; } | attribute /* FIXME */ { memset(&$$, 0, sizeof $$); $$.mod_noreturn = $1.mod_noreturn; $$.attr_aligned = $1.attr_aligned; $$.attr_packed = $1.attr_packed; } ; type_spec_storage : EXTERN { memset(&$$, 0, sizeof $$); $$.storage = STORAGE_EXTERN; } | TYPEDEF { memset(&$$, 0, sizeof $$); $$.storage = STORAGE_TYPEDEF; } | AUTO { memset(&$$, 0, sizeof $$); $$.storage = STORAGE_AUTO; } | STATIC { memset(&$$, 0, sizeof $$); $$.storage = STORAGE_STATIC; } | REGISTER { memset(&$$, 0, sizeof $$); $$.storage = STORAGE_REGISTER; } ; type_spec_type : VOID { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_VOID; } | CHAR { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_CHAR; } | INT { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_INT; } | FLOAT { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_FLOAT; } | DOUBLE { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_DOUBLE; } | STRUCT identifier_e '{' { scope_struct_begin($2); } declaration_list '}' { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_STRUCT; $$.identifier = $2; scope_struct_end(); } | STRUCT identifier { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_STRUCT; $$.identifier = $2; } | UNION identifier_e '{' { scope_union_begin($2); } declaration_list '}' { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_UNION; $$.identifier = $2; scope_union_end(); } | UNION identifier { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_UNION; $$.identifier = $2; } | ENUM identifier_e '{' { scope_enum_begin($2); enum_next = 0; } enumerator_list_comma '}' { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_ENUM; $$.identifier = $2; scope_enum_end(); } | ENUM identifier { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_ENUM; $$.identifier = $2; } | BUILTIN_VA_LIST { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_VA_LIST; } | TYPE_NAME { memset(&$$, 0, sizeof $$); $$.type = TYPE_SPEC_USER; $$.identifier = $1; } ; type_spec_0 : type_spec_mod { $$ = $1; } | type_spec_storage { $$ = $1; } | type_spec_type { $$ = $1; } | type_spec_0 type_spec_mod { $$ = $1; $$.mod_short += $2.mod_short; $$.mod_long += $2.mod_long; $$.mod_signed += $2.mod_signed; $$.mod_unsigned += $2.mod_unsigned; $$.mod_const += $2.mod_const; $$.mod_volatile += $2.mod_volatile; if ($$.attr_packed < $2.attr_packed) { $$.attr_packed = $2.attr_packed; } $$.mod_inline += $2.mod_inline; $$.mod_noreturn += $2.mod_noreturn; } | type_spec_0 type_spec_storage { $$ = $1; $$.storage = $2.storage; } | type_spec_0 type_spec_type { $$ = $1; $$.type = $2.type; $$.identifier = $2.identifier; } ; type_spec : type_spec_0 { struct declaration *dion; struct type *type; int ret; switch ($1.type) { case TYPE_SPEC_VOID: if ($1.mod_signed || $1.mod_unsigned || $1.mod_short || $1.mod_long) { yyerror("Bad type modifier"); } type = type_void(); break; case TYPE_SPEC_CHAR: if ($1.mod_short || $1.mod_long || 1 < $1.mod_signed || 1 < $1.mod_unsigned || ($1.mod_signed && $1.mod_unsigned)) { yyerror("Bad type modifier"); } if ($1.mod_signed) { type = type_signed_char(); } else if ($1.mod_unsigned) { type = type_unsigned_char(); } else { type = type_char(); } break; case TYPE_SPEC_NONE: case TYPE_SPEC_INT: if (1 < $1.mod_signed || 1 < $1.mod_unsigned || 1 < $1.mod_short || 2 < $1.mod_long || ($1.mod_signed && $1.mod_unsigned) || ($1.mod_short && $1.mod_long)) { yyerror("Bad type modifier"); } if ($1.mod_unsigned) { if ($1.mod_short) { type = type_unsigned_short_int(); } else if ($1.mod_long == 0) { type = type_unsigned_int(); } else if ($1.mod_long == 1) { type = type_unsigned_long_int(); } else if ($1.mod_long == 2) { type = type_unsigned_long_long_int(); } else { assert(0); } } else { if ($1.mod_short) { type = type_short_int(); } else if ($1.mod_long == 0) { type = type_int(); } else if ($1.mod_long == 1) { type = type_long_int(); } else if ($1.mod_long == 2) { type = type_long_long_int(); } else { assert(0); } } break; case TYPE_SPEC_FLOAT: if ($1.mod_signed || $1.mod_unsigned || $1.mod_short || $1.mod_long) { yyerror("Bad type modifier"); } type = type_float(); break; case TYPE_SPEC_DOUBLE: if ($1.mod_signed || $1.mod_unsigned || $1.mod_short || 1 < $1.mod_long) { yyerror("Bad type modifier"); } if ($1.mod_long == 0) { type = type_double(); } else { type = type_long_double(); } break; case TYPE_SPEC_STRUCT: if ($1.mod_signed || $1.mod_unsigned || $1.mod_short || $1.mod_long) { yyerror("Bad type modifier"); } type = type_new(); type->type = TYPE_STRUCT; type->identifier = $1.identifier; break; case TYPE_SPEC_UNION: if ($1.mod_signed || $1.mod_unsigned || $1.mod_short || $1.mod_long) { yyerror("Bad type modifier"); } type = type_new(); type->type = TYPE_UNION; type->identifier = $1.identifier; break; case TYPE_SPEC_ENUM: if ($1.mod_signed || $1.mod_unsigned || $1.mod_short || $1.mod_long) { yyerror("Bad type modifier"); } type = type_int(); break; case TYPE_SPEC_USER: if ($1.mod_signed || $1.mod_unsigned || $1.mod_short || $1.mod_long) { yyerror("Bad type modifier"); } ret = scope_lookup_current($1.identifier, &dion); assert(0 <= ret); type = dion->type_name; break; case TYPE_SPEC_VA_LIST: if ($1.mod_signed || $1.mod_unsigned || $1.mod_short || $1.mod_long) { yyerror("Bad type modifier"); } type = type_new(); type->type = TYPE_VA_LIST; break; case TYPE_SPEC_ELIPSIS: if ($1.mod_signed || $1.mod_unsigned || $1.mod_short || $1.mod_long) { yyerror("Bad type modifier"); } type = type_new(); type->type = TYPE_ELIPSIS; break; default: assert(0); } if ($1.mod_const) { type = type_const(type); } if ($1.mod_volatile) { type = type_volatile(type); } if ($1.attr_aligned) { type = type_aligned(scope_current, type, $1.attr_aligned); } if ($1.attr_packed) { type = type_packed(scope_current, type); } $$.type = type; $$.storage = $1.storage; $$.mod_inline = $1.mod_inline; $$.mod_noreturn = $1.mod_noreturn; } ; enumerator_list_comma : enumerator_list | enumerator_list ',' ; enumerator_list : enumerator | enumerator_list ',' enumerator ; enumerator : IDENTIFIER { scope_enum_add($1, enum_next++); } | IDENTIFIER '=' constant_expr { enum_next = $3; scope_enum_add($1, enum_next++); } ; declarator_list_e : /* lambda */ { $$.first = NULL; $$.last = NULL; } | declarator_list { $$ = $1; } ; declarator_list : declarator { $1->prev = NULL; $1->next = NULL; $$.first = $1; $$.last = $1; } | declarator_list ',' declarator { $3->prev = $1.last; $3->next = NULL; $3->prev->next = $3; $1.last = $3; $$.first = $1.first; $$.last = $1.last; } ; declarator : declarator2 attribute_e { $$ = $1; $$->attr_aligned = $2.attr_aligned; $$->attr_noreturn = $2.mod_noreturn; } | declarator2 attribute_e '=' initializer_expr attribute_e { $$ = $1; $$->attr_aligned = $2.attr_aligned; $$->attr_noreturn = $2.mod_noreturn; declaration_initializer_set($$, $4); } ; declarator2 : ':' constant_expr { $$ = declaration_identifier(identifier_tmp()); $$->nbits = expr_integer($2); }; | declarator3 { $$ = $1; } | declarator3 ASM '(' string ')' { $$ = $1; $$->regname = $4.string; } | declarator3 ':' constant_expr { $$ = $1; $$->nbits = expr_integer($3); } ; declarator3 : declarator4 { $$ = $1; } | '*' const_volatile_e declarator3 { $$ = $3; $$->type_name = type_add_pointer($$->type_name, $2); } ; declarator4 : IDENTIFIER { $$ = declaration_identifier($1); } | '(' declarator3 ')' { $$ = $2; } | declarator4 '[' ']' { $$ = $1; $$->type_name = type_add_array($$->type_name, NULL); } | declarator4 '[' constant_expr ']' { $$ = $1; $$->type_name = type_add_array( $$->type_name, expr_integer($3)); } | declarator4 '(' { scope_parameter_begin(); } parameter_type_list_e ')' { $$ = $1; $$->type_name = type_add_function( $$->type_name, scope_current); scope_parameter_end($4.first, $4.last); } ; parameter_type_list_e : /* lambda */ { $$.first = NULL; $$.last = NULL; } | parameter_type_list { if ($1.first && $1.first == $1.last && type_is_void($1.first->type_name)) { $$.first = NULL; $$.last = NULL; } else { $$ = $1; }} ; parameter_type_list : parameter_list { $$ = $1; } | parameter_list ',' ELIPSIS { struct declaration *dion; dion = declaration_identifier(NULL); dion->storage = STORAGE_PARAM; dion->mod_inline = 0; dion->attr_aligned = 0; dion->attr_noreturn = 0; dion->type_name = type_new(); dion->type_name->type = TYPE_ELIPSIS; dion->prev = $1.last; dion->next = NULL; dion->prev->next = dion; $1.last = dion; $$.first = $1.first; $$.last = $1.last; } ; parameter_list : parameter_declaration { $1->prev = NULL; $1->next = NULL; $$.first = $1; $$.last = $1; } | parameter_list ',' parameter_declaration { $3->prev = $1.last; $3->next = NULL; $3->prev->next = $3; $1.last = $3; $$.first = $1.first; $$.last = $1.last; } ; parameter_declaration : type_spec declarator { $2->storage = STORAGE_PARAM; $2->mod_inline = 0; $2->attr_aligned = 0; $2->attr_noreturn = 0; $2->type_name = type_add_user($2->type_name, $1.type); if (type_is_array($2->type_name)) { $2->type_name = type_amphersand( type_array_access($2->type_name)); } $$ = $2; } | type_name { $$ = declaration_identifier(NULL); $$->storage = STORAGE_PARAM; $$->mod_inline = 0; $$->attr_aligned = 0; $$->attr_noreturn = 0; $$->type_name = $1; if (type_is_array($$->type_name)) { $$->type_name = type_amphersand( type_array_access($$->type_name)); } } ; type_name : type_spec { $$ = $1.type; } | type_spec abstract_declarator { $$ = type_add_user($2, $1.type); } ; abstract_declarator : '*' const_volatile_e { struct type *dor; dor = type_type_spec(); $$ = type_add_pointer(dor, $2); } | '*' const_volatile_e abstract_declarator { $$ = type_add_pointer($3, $2); } | abstract_declarator2 { $$ = $1; } ; abstract_declarator2 : '(' abstract_declarator ')' { $$ = $2; } | '[' ']' { struct type *dor; dor = type_type_spec(); $$ = type_add_array(dor, NULL); } | '[' constant_expr ']' { struct type *dor; dor = type_type_spec(); $$ = type_add_array(dor, expr_integer($2)); } | '(' { scope_parameter_begin(); } parameter_type_list_e ')' { struct type *dor; dor = type_type_spec(); $$ = type_add_function(dor, scope_current); scope_parameter_end($3.first, $3.last); } | abstract_declarator2 '[' ']' { $$ = type_add_array($1, NULL); } | abstract_declarator2 '[' constant_expr ']' { $$ = type_add_array($1, expr_integer($3)); } | abstract_declarator2 '(' { scope_parameter_begin(); } parameter_type_list_e ')' { $$ = type_add_function($1, scope_current); scope_parameter_end($4.first, $4.last); } ; declaration_list : /* lambda */ | declaration_list declaration ; declaration : type_spec declarator_list_e ';' { struct declaration *dor; for (dor = $2.first; dor; ) { struct declaration *next; next = dor->next; dor->storage = $1.storage; dor->mod_inline += $1.mod_inline; dor->attr_noreturn += $1.mod_noreturn; dor->type_name = type_add_user(dor->type_name, $1.type); scope_declaration_append(scope_current, dor); dor = next; } } ; asm_constraint_list_e : /* lambda */ { $$ = constraint_list_new(); $$->first = NULL; $$->last = NULL; } | asm_constraint_list { $$ = $1; } ; asm_constraint_list : asm_constraint { $$ = constraint_list_new(); $1->prev = NULL; $1->next = NULL; $$->first = $1; $$->last = $1; } | asm_constraint_list ',' asm_constraint { $3->prev = $1->last; $3->next = NULL; $3->prev->next = $3; $1->last = $3; $$ = $1; } ; asm_constraint : string '(' expr ')' { $$ = constraint_new(); $$->string = $1.string; $$->expr = $3; } ; asm_change_list_e : /* lambda */ { $$ = constraint_list_new(); } | asm_change_list { $$ = $1; } ; asm_change_list : asm_change { $$ = constraint_list_new(); $1->prev = NULL; $1->next = NULL; $$->first = $1; $$->last = $1; } | asm_change_list ',' asm_change { $3->prev = $1->last; $3->next = NULL; $3->prev->next = $3; $1->last = $3; $$ = $1; } ; asm_change : string { $$ = constraint_new(); $$->string = $1.string; $$->expr = NULL; } ; statement_list : /* lambda */ { $$.first = NULL; $$.last = NULL; } | statement_list statement { $2->prev = $1.last; $2->next = NULL; if ($2->prev) { $2->prev->next = $2; } else { $1.first = $2; } $1.last = $2; $$.first = $1.first; $$.last = $1.last; } ; statement : ';' { $$ = stmt_null(); } | IDENTIFIER ':' statement { $$ = stmt_label(scope_function_label_get($1), $3); } | CASE constant_expr ':' statement { $$ = stmt_new(); $$->type = STMT_CASE; $$->expr0 = expr_integer($2); $$->stmt0 = $4; } | DEFAULT ':' statement { $$ = stmt_new(); $$->type = STMT_DEFAULT; $$->stmt0 = $3; } | expr ';' { $$ = stmt_expr($1); } | IF '(' expr ')' statement { $$ = stmt_if($3, $5, NULL); } | IF '(' expr ')' statement ELSE statement { $$ = stmt_if($3, $5, $7); } | SWITCH '(' expr ')' '{' { scope_block_begin(); } compound_statement '}' { scope_block_end($7); $$ = stmt_new(); $$->type = STMT_SWITCH; $$->expr0 = $3; $$->stmt0 = $7; } | WHILE '(' expr ')' statement { $$ = stmt_new(); $$->type = STMT_WHILE; $$->expr0 = $3; $$->stmt0 = $5; } | DO statement WHILE '(' expr ')' ';' { $$ = stmt_new(); $$->type = STMT_DO_WHILE; $$->expr0 = $5; $$->stmt0 = $2; } | FOR '(' expr_e ';' expr_e ';' expr_e ')' statement { $$ = stmt_new(); $$->type = STMT_FOR; $$->expr0 = $3; $$->expr1 = $5; $$->expr2 = $7; $$->stmt0 = $9; } | GOTO IDENTIFIER ';' { $$ = stmt_goto(scope_function_label_get($2)); } | CONTINUE ';' { $$ = stmt_new(); $$->type = STMT_CONTINUE; } | BREAK ';' { $$ = stmt_new(); $$->type = STMT_BREAK; } | RETURN ';' { $$ = stmt_new(); $$->type = STMT_RETURN; $$->expr0 = NULL; } | RETURN expr ';' { $$ = stmt_new(); $$->type = STMT_RETURN; $$->expr0 = $2; } | ASM volatile_e '(' string ')' ';' { $$ = stmt_new(); $$->type = STMT_ASM; $$->code_len = $4.len; $$->code = $4.string; $$->output = constraint_list_new(); $$->input = constraint_list_new(); $$->change = constraint_list_new(); } | ASM volatile_e '(' string ':' asm_constraint_list_e ')' ';' { $$ = stmt_new(); $$->type = STMT_ASM; $$->code_len = $4.len; $$->code = $4.string; $$->output = $6; $$->input = constraint_list_new(); $$->change = constraint_list_new(); } | ASM volatile_e '(' string ':' asm_constraint_list_e ':' asm_constraint_list_e ')' ';' { $$ = stmt_new(); $$->type = STMT_ASM; $$->code_len = $4.len; $$->code = $4.string; $$->output = $6; $$->input = $8; $$->change = constraint_list_new(); } | ASM volatile_e '(' string ':' asm_constraint_list_e ':' asm_constraint_list_e ':' asm_change_list_e ')' ';' { $$ = stmt_new(); $$->type = STMT_ASM; $$->code_len = $4.len; $$->code = $4.string; $$->output = $6; $$->input = $8; $$->change = $10; } | BUILTIN_VA_START '(' identifier ',' identifier ')' { int ret; $$ = stmt_new(); $$->type = STMT_VA_START; $$->expr0 = expr_new(); $$->expr0->type = EXPR_IDENTIFIER; ret = scope_lookup_current($3, &$$->expr0->declaration); if (ret < 0) { parse_unknown($3); } assert(0 <= ret); $$->expr1 = expr_new(); $$->expr1->type = EXPR_IDENTIFIER; ret = scope_lookup_current($5, &$$->expr1->declaration); if (ret < 0) { parse_unknown($5); } assert(0 <= ret); } | BUILTIN_VA_END '(' identifier ')' { int ret; $$ = stmt_new(); $$->type = STMT_VA_END; $$->expr0 = expr_new(); $$->expr0->type = EXPR_IDENTIFIER; ret = scope_lookup_current($3, &$$->expr0->declaration); if (ret < 0) { parse_unknown($3); } assert(0 <= ret); } | '{' { scope_block_begin(); } compound_statement '}' { scope_block_end($3); $$ = $3; } ; compound_statement : declaration_list statement_list { $$ = stmt_new(); $$->type = STMT_BLOCK; $$->stmt_first = $2.first; $$->stmt_last = $2.last; } ; external_definition_list : /* lambda */ | external_definition_list external_definition ; external_definition : type_spec declarator '{' { assert(! $2->attr_noreturn); $2->storage = $1.storage; $2->mod_inline += $1.mod_inline; $2->attr_noreturn += $1.mod_noreturn; scope_function_begin($1.type, $2); } compound_statement '}' { scope_function_end($5); } | declaration | ASM '(' string ')' ';' { scope_asm_add($3.len, $3.string); } ; file : /* lambda */ { scope_file_begin(); } external_definition_list { scope_file_end(&parse_scope); } ; identifier_e : /* lambda */ { $$ = identifier_tmp(); } | identifier { $$ = $1; } ; identifier : IDENTIFIER { $$ = $1; } | TYPE_NAME { $$ = $1; } ; string : STRING_LITERAL { $$.len = $1.len; $$.string = $1.string; } | string STRING_LITERAL { char *str; str = malloc($1.len + $2.len + 1); assert(str); memcpy(str, $1.string, $1.len); memcpy(str + $1.len, $2.string, $2.len); str[$1.len + $2.len] = '\0'; free($1.string); free($2.string); $$.len = $1.len + $2.len; $$.string = str; } ; %% struct scope * parse(const char *in) { int ret; yyin = fopen(in, "r"); assert(yyin); yyparse(); ret = fclose(yyin); assert(0 <= ret); return parse_scope; } faucc-20120707/check.sh0000750002413100241000000000316511137630647014136 0ustar potyrai3guest#!/bin/sh # $Id: check.sh,v 1.23 2009-01-27 16:09:11 potyra Exp $ # # Copyright (C) 2007-2009 FAUcc Team. # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. # file=$1 f=`echo ${file} | sed -e 's/\..$//'` ulimit -S -t 10 ulimit -S -m 1000000 # # Generate pre-compile file. # if [ -f ${f}.c ] ; then gcc -m32 -D_GNU_SOURCE -E ${f}.c > ${f}.i fi # # Generate optimized C file. # # ./faucc -b i386 < ${f}.i > ${f}.simple # # if [ ! -s ${f}.simple ] ; then # rm ${f}.simple # else # # # # Try to compile generated file. # # # cp ${f}.simple gcc.c # gcc -fno-builtin -m32 -S gcc.c > ${f}.simple.log 2>&1 # if [ -s ${f}.simple.log ] ; then # head -10 ${f}.simple.log # else # rm ${f}.simple.log # fi # rm -f gcc.c gcc.s # fi # # Generate optimized assembler file. # for t in i286 i386 ; do for sizeof_int in 2 4 ; do echo "target=${t}, sizeof(int)=${sizeof_int}" ./faucc -S -b ${t} -f sizeof_int=${sizeof_int} -o ${f}.${t}.${sizeof_int}.s ${f}.i if [ ! -s ${f}.${t}.${sizeof_int}.s ] ; then rm -f ${f}.${t}.${sizeof_int}.s else # # Try to assemble generated file. # cp ${f}.${t}.${sizeof_int}.s ${t}.${sizeof_int}.s gcc -m32 -c ${t}.${sizeof_int}.s > ${f}.${t}.${sizeof_int}.s.log 2>&1 if [ -s ${f}.${t}.${sizeof_int}.s.log ] ; then head -10 ${f}.${t}.${sizeof_int}.s.log else rm ${f}.${t}.${sizeof_int}.s.log fi rm -f ${t}.${sizeof_int}.s ${t}.${sizeof_int}.o fi done done ulimit -S -m unlimited ulimit -S -t unlimited faucc-20120707/scan.l0000640002413100241000000002210011137625520013604 0ustar potyrai3guest/* $Id: scan.l,v 1.50 2009-01-27 15:42:08 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ D [0-9] L [a-zA-Z_] H [a-fA-F0-9] E [Ee][+-]?{D}+ FS (f|F|l|L) IS (u|U|l|L)* CHAR_BACKSLASH \\\\ CHAR_BELL \\a CHAR_BACKSPACE \\b CHAR_ESCAPE \\e CHAR_FORMFEED \\f CHAR_NEWLINE \\n CHAR_RETURN \\r CHAR_TAB \\t CHAR_VTAB \\v CHAR_TICK \\' CHAR_DTICK \\\" CHAR_OCTAL \\[0-7]{1,3} CHAR_HEX \\x[0-9a-fA-F]{2} CHAR_COMMON ({CHAR_BACKSLASH}|{CHAR_BELL}|{CHAR_BACKSPACE}|{CHAR_ESCAPE}|{CHAR_FORMFEED}|{CHAR_NEWLINE}|{CHAR_RETURN}|{CHAR_TAB}|{CHAR_VTAB}|{CHAR_TICK}|{CHAR_DTICK}|{CHAR_OCTAL}|{CHAR_HEX}) CHAR_STRING ([^\\"]|{CHAR_COMMON}) CHAR_CHAR ([^\\']|{CHAR_COMMON}) %{ #include #include #include #include "scope.h" #include "expr.h" #include "parse.h" #include "cc1.h" extern void __attribute__((noreturn)) yyerror(const char *s); int column = 0; int line = 1; /*forward*/ static void comment(void); /*forward*/ static void count(void); static unsigned char ascii_to_byte(const char *str, const char **endp) { unsigned char c; unsigned int i; if (*str == '\\') { str++; switch (*str) { case 'a': c = '\a'; str++; break; case 'b': c = '\b'; str++; break; case 'e': c = '\033'; str++; break; /* Non-ANSI -- FIXME */ case 'f': c = '\f'; str++; break; case 'n': c = '\n'; str++; break; case 'r': c = '\r'; str++; break; case 't': c = '\t'; str++; break; case 'v': c = '\v'; str++; break; case 'x': case 'X': str++; c = 0; for (i = 0; i < 2; i++) { c *= 16; if ('0' <= *str && *str <= '9') { c += *str - '0'; } else if ('A' <= *str && *str <= 'F') { c += *str - 'A' + 10; } else if ('a' <= *str && *str <= 'f') { c += *str - 'a' + 10; } else { assert(0); } str++; } break; case '\'': c = '\''; str++; break; case '"': c = '"'; str++; break; case '\\': c = '\\'; str++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c = *str++ - '0'; while ('0' <= *str && *str <= '7') { c *= 8; c += *str++ - '0'; } break; default: assert(0); } } else { c = *str++; } *endp = str; return c; } static int integer(char *str) { unsigned long long val; int u; int l; u = 0; l = 0; val = strtoull(str, &str, 0); while (*str) { switch (*str) { case 'L': case 'l': l++; break; case 'U': case 'u': u++; break; default: assert(0); break; } str++; } assert(l < 3); assert(u < 2); yylval.integer = val; if (u == 0 && l < 1 && val < (1ULL << (opt_f_sizeof_int * 8 - 1))) { return INTEGER_LITERAL; } else if (l < 1 && val < (1ULL << (opt_f_sizeof_int * 8))) { return INTEGER_LITERAL_U; } else if (u == 0 && l < 2 && val < (1ULL << (opt_f_sizeof_long_int * 8 - 1))) { return INTEGER_LITERAL_L; } else if (l < 2 && val < (1ULL << (opt_f_sizeof_long_int * 8))) { return INTEGER_LITERAL_UL; } else if (u == 0 && l < 3 && val < (1ULL << (opt_f_sizeof_long_long_int * 8 - 1))) { return INTEGER_LITERAL_LL; } else { return INTEGER_LITERAL_ULL; } } %} %% "/*" { comment(); } "#".* { count(); } "__extension__" { count(); } "__restrict" { count(); } "__builtin_constant_p" { count(); return BUILTIN_CONSTANT_P; } "__builtin_offsetof" { count(); return BUILTIN_OFFSETOF; } "__builtin_va_arg" { count(); return BUILTIN_VA_ARG; } "__builtin_va_start" { count(); return BUILTIN_VA_START; } "__builtin_va_end" { count(); return BUILTIN_VA_END; } "__builtin_va_list" { count(); return BUILTIN_VA_LIST; } "attribute" { count(); return ATTRIBUTE; } "__attribute" { count(); return ATTRIBUTE; } "__attribute__" { count(); return ATTRIBUTE; } "auto" { count(); return AUTO; } "asm" { count(); return ASM; } "__asm__" { count(); return ASM; } "break" { count(); return BREAK; } "case" { count(); return CASE; } "char" { count(); return CHAR; } "const" { count(); return CONST; } "__const" { count(); return CONST; } "continue" { count(); return CONTINUE; } "default" { count(); return DEFAULT; } "do" { count(); return DO; } "double" { count(); return DOUBLE; } "else" { count(); return ELSE; } "enum" { count(); return ENUM; } "extern" { count(); return EXTERN; } "float" { count(); return FLOAT; } "for" { count(); return FOR; } "goto" { count(); return GOTO; } "if" { count(); return IF; } "inline" { count(); return INLINE; } "__inline" { count(); return INLINE; } "int" { count(); return INT; } "long" { count(); return LONG; } "register" { count(); return REGISTER; } "return" { count(); return RETURN; } "short" { count(); return SHORT; } "signed" { count(); return SIGNED; } "sizeof" { count(); return SIZEOF; } "static" { count(); return STATIC; } "struct" { count(); return STRUCT; } "switch" { count(); return SWITCH; } "typedef" { count(); return TYPEDEF; } "union" { count(); return UNION; } "unsigned" { count(); return UNSIGNED; } "void" { count(); return VOID; } "volatile" { count(); return VOLATILE; } "__volatile__" { count(); return VOLATILE; } "while" { count(); return WHILE; } "__PRETTY_FUNCTION__" { struct scope *s; count(); for (s = scope_current; s->type != SCOPE_FUNCTION; s = s->parent) { } yylval.string.len = strlen(s->function->identifier); yylval.string.string = strdup(s->function->identifier); assert(yylval.string.string); return STRING_LITERAL; } {L}({L}|{D})* { struct declaration *dion; int ret; count(); yylval.identifier = strdup(yytext); ret = scope_lookup_current(yytext, &dion); if (ret == STORAGE_TYPEDEF) { return TYPE_NAME; } else if (ret == TYPE_ENUM) { struct expr *initializer; initializer = declaration_initializer_get(dion); assert(initializer); assert(initializer->type == EXPR_INTEGER); yylval.integer = initializer->integer; return INTEGER_LITERAL; } else { return IDENTIFIER; } } 0[xX]{H}+{IS}? { count(); return integer(yytext); } 0{D}+{IS}? { count(); return integer(yytext); } {D}+{IS}? { count(); return integer(yytext); } {D}+{E}{FS}? { count(); yylval.real = strtold(yytext, NULL); return REAL_LITERAL; } {D}*"."{D}+({E})?{FS}? { count(); yylval.real = strtold(yytext, NULL); return REAL_LITERAL; } {D}+"."{D}*({E})?{FS}? { count(); yylval.real = strtold(yytext, NULL); return REAL_LITERAL; } \"{CHAR_STRING}*\" { unsigned int len; char *str; const char *p; unsigned int i; count(); /* Count characters. */ len = 0; for (p = &yytext[1]; p < &yytext[strlen(yytext) - 1]; ) { ascii_to_byte(p, &p); len++; } /* Store characters. */ str = malloc(len + 1); assert(str); i = 0; for (p = &yytext[1]; p < &yytext[strlen(yytext) - 1]; ) { str[i] = ascii_to_byte(p, &p); i++; } str[i] = '\0'; yylval.string.len = len; yylval.string.string = str; return STRING_LITERAL; } '{CHAR_CHAR}' { const char *p; yylval.integer = ascii_to_byte(&yytext[1], &p); return INTEGER_LITERAL; } "\.\.\." { count(); return ELIPSIS; } ">>=" { count(); return RIGHT_ASSIGN; } "<<=" { count(); return LEFT_ASSIGN; } "+=" { count(); return ADD_ASSIGN; } "-=" { count(); return SUB_ASSIGN; } "*=" { count(); return MUL_ASSIGN; } "/=" { count(); return DIV_ASSIGN; } "%=" { count(); return MOD_ASSIGN; } "&=" { count(); return AND_ASSIGN; } "^=" { count(); return XOR_ASSIGN; } "|=" { count(); return OR_ASSIGN; } ">>" { count(); return RIGHT_OP; } "<<" { count(); return LEFT_OP; } "++" { count(); return INC_OP; } "--" { count(); return DEC_OP; } "->" { count(); return PTR_OP; } "&&" { count(); return AND_OP; } "||" { count(); return OR_OP; } "<=" { count(); return LE_OP; } ">=" { count(); return GE_OP; } "==" { count(); return EQ_OP; } "!=" { count(); return NE_OP; } ";" { count(); return ';'; } "{" { count(); return '{'; } "}" { count(); return '}'; } "," { count(); return ','; } ":" { count(); return ':'; } "=" { count(); return '='; } "(" { count(); return '('; } ")" { count(); return ')'; } "[" { count(); return '['; } "]" { count(); return ']'; } "." { count(); return '.'; } "&" { count(); return '&'; } "!" { count(); return '!'; } "~" { count(); return '~'; } "-" { count(); return '-'; } "+" { count(); return '+'; } "*" { count(); return '*'; } "/" { count(); return '/'; } "%" { count(); return '%'; } "<" { count(); return '<'; } ">" { count(); return '>'; } "^" { count(); return '^'; } "|" { count(); return '|'; } "?" { count(); return '?'; } [ \t\v\n\f] { count(); } . { yyerror("syntax error"); } %% int yywrap(void) { return 1; } static void comment(void) { char c, c1; loop: while ((c = input()) != '*' && c != 0) ; if ((c1 = input()) != '/' && c != 0) { unput(c1); goto loop; } } static void count(void) { int i; #if 0 fprintf(stderr, "-- %s --\n", yytext); #endif for (i = 0; yytext[i] != '\0'; i++) { if (yytext[i] == '\n') { column = 0; line++; } else if (yytext[i] == '\t') { column += 8 - (column % 8); } else { column++; } } } faucc-20120707/AUTHORS0000640002413100241000000000003411133124776013560 0ustar potyrai3guestVolkmar Sieh Petr Lambersky faucc-20120707/scope.c0000640002413100241000000002504211717460534013776 0ustar potyrai3guest/* $Id: scope.c,v 1.68 2012-02-17 14:17:00 vrsieh Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include #include "setup.h" #include "declaration.h" #include "stmt.h" #include "scope.h" #include "cc1.h" static struct declaration *dion_current; struct scope *scope_current; static int _scope_lookup_enum( struct scope *scope, const char *name, struct declaration **dorp ) { struct declaration *dion; assert(scope->type == SCOPE_ENUM); for (dion = scope->declaration_first; ; dion = dion->next) { if (! dion) { return -1; } if (declaration_name_get(dion) && strcmp(declaration_name_get(dion), name) == 0) { *dorp = dion; return TYPE_ENUM; } } } static int _scope_lookup( struct scope *scope, const char *name, struct declaration **dorp ) { struct declaration *dion; for (dion = scope->declaration_first; ; dion = dion->next) { if (! dion) { /* Not Found */ return -1; } if (dion->type_name && dion->type_name->type == TYPE_ENUM && dion->type_name->scope) { int ret; ret = _scope_lookup_enum( dion->type_name->scope, name, dorp); if (0 <= ret) { return ret; } } if (declaration_name_get(dion) && strcmp(declaration_name_get(dion), name) == 0) { *dorp = dion; if (scope->type == SCOPE_ENUM) { return TYPE_ENUM; } else { return dion->storage; } } } } int _scope_lookup_structunionenum( struct scope *scope, enum type_type type, const char *name, struct type **tsp ) { struct declaration *dion; assert(type == TYPE_STRUCT || type == TYPE_UNION); for (dion = scope->declaration_first; ; dion = dion->next) { if (! dion) { /* Not Found */ return -1; } if (dion->type_name && dion->type_name->type == type && dion->type_name->identifier && strcmp(dion->type_name->identifier, name) == 0 && dion->type_name->scope) { *tsp = dion->type_name; return 0; } } } static void _scope_add(struct declaration *d) { d->prev = scope_current->declaration_last; d->next = NULL; if (d->prev) { d->prev->next = d; } else { scope_current->declaration_first = d; } scope_current->declaration_last = d; } static void _scope_enter(void) { struct scope *s; s = malloc(sizeof(*s)); assert(s); memset(s, 0, sizeof(*s)); s->prev = scope_current->child_last; s->next = NULL; if (s->prev) { s->prev->next = s; } else { scope_current->child_first = s; } scope_current->child_last = s; s->parent = scope_current; scope_current = s; } static void _scope_leave(void) { scope_current = scope_current->parent; } int scope_lookup_one( struct scope *scope, const char *name, struct declaration **dorp ) { assert(scope); return _scope_lookup(scope, name, dorp); } int scope_lookup( struct scope *scope, const char *name, struct declaration **dorp ) { struct scope *s; int ret; s = scope; again: ; ret = _scope_lookup(s, name, dorp); if (0 <= ret) { return ret; } switch (s->type) { case SCOPE_NONE: assert(0); case SCOPE_GLOBAL: /* * Nothing more to search... */ return -1; case SCOPE_FUNCTION: /* * Next step: look in parameter list. */ assert(s->function); s = type_parameter_get(s->function->type_name); assert(s); goto again; case SCOPE_PARAMETER: /* * Next step: look in parent list. */ s = s->parent; goto again; case SCOPE_BLOCK: /* * Next step: look in upper block / function. */ s = s->parent; assert(s->type == SCOPE_BLOCK || s->type == SCOPE_FUNCTION); goto again; case SCOPE_STRUCT: case SCOPE_UNION: case SCOPE_ENUM: /* * Next step: look in upper block / function / global list. */ s = s->parent; goto again; default: assert(0); } } int scope_lookup_current( const char *name, struct declaration **dorp ) { return scope_lookup(scope_current, name, dorp); } int scope_lookup_structunionenum( struct scope *scope, enum type_type type, const char *name, struct type **tsp ) { struct scope *s; int ret; assert(type == TYPE_STRUCT || type == TYPE_UNION); for (s = scope; ; s = s->parent) { if (! s) { return -1; } ret = _scope_lookup_structunionenum(s, type, name, tsp); if (0 <= ret) { return ret; } } } static void _scope_structunionenum_begin( const char *identifier, enum type_type ttype, enum scope_type stype ) { struct declaration *dion; if (dion_current) { _scope_leave(); } dion = declaration_identifier(NULL); dion->type_name = type_new(); dion->type_name->type = ttype; dion->type_name->identifier = identifier; if (dion_current) { /* Prepend to current struct definition. */ dion->prev = dion_current->prev; dion->next = dion_current; } else { /* Append to declaration list. */ dion->prev = scope_current->declaration_last; dion->next = NULL; } if (dion->prev) { dion->prev->next = dion; } else { scope_current->declaration_first = dion; } if (dion->next) { dion->next->prev = dion; } else { scope_current->declaration_last = dion; } dion_current = dion; _scope_enter(); scope_current->type = stype; dion_current->type_name->scope = scope_current; } static void _scope_structunionenum_end(void) { _scope_leave(); dion_current = dion_current->next; if (dion_current) { scope_current = dion_current->type_name->scope; } } void scope_struct_begin(const char *identifier) { _scope_structunionenum_begin(identifier, TYPE_STRUCT, SCOPE_STRUCT); } void scope_struct_end(void) { _scope_structunionenum_end(); } void scope_union_begin(const char *identifier) { _scope_structunionenum_begin(identifier, TYPE_UNION, SCOPE_UNION); } void scope_union_end(void) { _scope_structunionenum_end(); } void scope_enum_begin(const char *identifier) { _scope_structunionenum_begin(identifier, TYPE_ENUM, SCOPE_ENUM); } void scope_enum_add(const char *identifier, unsigned int val) { struct declaration *dion; dion = declaration_identifier(identifier); dion->type_name = type_int(); declaration_initializer_set(dion, expr_integer(val)); dion->prev = scope_current->declaration_last; dion->next = NULL; if (dion->prev) { dion->prev->next = dion; } else { scope_current->declaration_first = dion; } scope_current->declaration_last = dion; } void scope_enum_end(void) { _scope_structunionenum_end(); } void scope_parameter_begin(void) { _scope_enter(); scope_current->type = SCOPE_PARAMETER; } void scope_parameter_end( struct declaration *first, struct declaration *last ) { scope_current->declaration_first = first; scope_current->declaration_last = last; _scope_leave(); } void scope_block_begin(void) { _scope_enter(); scope_current->type = SCOPE_BLOCK; } void scope_block_end(struct stmt *s) { s->scope = scope_current; _scope_leave(); } void scope_function_begin(struct type *ts, struct declaration *dion) { assert(scope_current->parent == NULL); dion->type_name = type_add_user(dion->type_name, ts); _scope_add(dion); _scope_enter(); scope_current->type = SCOPE_FUNCTION; scope_current->function = dion; } struct label * scope_function_label_get(const char *identifier) { struct scope *s; struct label *l; for (s = scope_current; s->type == SCOPE_BLOCK; s = s->parent) { } for (l = s->label_first; ; l = l->next) { if (! l) { l = label_new(identifier); l->prev = s->label_last; l->next = NULL; if (l->prev) { l->prev->next = l; } else { s->label_first = l; } s->label_last = l; return l; } if (strcmp(l->identifier, identifier) == 0) { return l; } } } void scope_function_end(struct stmt *s) { scope_block_end(s); assert(scope_current->parent == NULL); scope_current->declaration_last->stmt = s; } void scope_declaration_prepend_first( struct scope *scope, struct declaration *nd ) { nd->prev = NULL; nd->next = scope->declaration_first; scope->declaration_first = nd; if (nd->next) { nd->next->prev = nd; } else { scope->declaration_last = nd; } } void scope_declaration_prepend( struct scope *scope, struct declaration *od, struct declaration *nd ) { assert(od); nd->prev = od->prev; nd->next = od; if (nd->prev) { nd->prev->next = nd; } else { scope->declaration_first = nd; } nd->next->prev = nd; } void scope_declaration_append(struct scope *scope, struct declaration *dion) { /* * Fix definitions of int8_t, uint8_t, ..., uint64_t. */ if (dion->storage == STORAGE_TYPEDEF && dion->identifier) { struct { const char *name; struct type *(*func)(void); } table[] = { { "int8_t", type_int8 }, { "uint8_t", type_uint8 }, { "int16_t", type_int16 }, { "uint16_t", type_uint16 }, { "int32_t", type_int32 }, { "uint32_t", type_uint32 }, { "int64_t", type_int64 }, { "uint64_t", type_uint64 }, { "int_least8_t", type_int8 }, { "uint_least8_t", type_uint8 }, { "int_least16_t", type_int16 }, { "uint_least16_t", type_uint16 }, { "int_least32_t", type_int32 }, { "uint_least32_t", type_uint32 }, { "int_least64_t", type_int64 }, { "uint_least64_t", type_uint64 }, { "intmax_t", type_int64 }, { "uintmax_t", type_uint64 }, { "intptr_t", type_ptrdiff }, { "uintptr_t", type_uintptr_t }, }; unsigned int i; for (i = 0; i < sizeof(table) / sizeof(table[0]); i++) { if (strcmp(dion->identifier, table[i].name) == 0 && dion->type_name != (*table[i].func)()) { fprintf(stderr, "%s: Fixing declaration of %s.\n", progname, table[i].name); dion->type_name = (*table[i].func)(); } } } /* * Append to declaration list. */ dion->prev = scope->declaration_last; dion->next = NULL; if (dion->prev) { dion->prev->next = dion; } else { scope->declaration_first = dion; } scope->declaration_last = dion; } void scope_asm_add(unsigned int len, const char *code) { struct declaration *dion; dion = declaration_new(); dion->storage = STORAGE_ASM; dion->code = code; scope_declaration_append(scope_current, dion); } void scope_file_begin(void) { scope_current = malloc(sizeof(*scope_current)); assert(scope_current); memset(scope_current, 0, sizeof(*scope_current)); scope_current->type = SCOPE_GLOBAL; } void scope_file_end(struct scope **sp) { assert(scope_current->parent == NULL); *sp = scope_current; } faucc-20120707/regalloc.h0000640002413100241000000000107511721457410014454 0ustar potyrai3guest/* * $Id: regalloc.h,v 1.1 2012-02-23 15:45:12 vrsieh Exp $ * * Copyright (C) 2007-2012 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __REGALLOC_H_INCLUDED #define __REGALLOC_H_INCLUDED extern void regalloc( struct storage_register *reginfo, unsigned int *classinfo, unsigned int *typeinfo, struct stmt *fs ); #endif /* __REGALLOC_H_INCLUDED */ faucc-20120707/cc1.h0000640002413100241000000000140211721454561013330 0ustar potyrai3guest/* $Id: cc1.h,v 1.7 2012-02-23 15:21:21 vrsieh Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ enum target { TARGET_NONE, TARGET_I286, TARGET_I386, }; extern const char *progname; extern enum target opt_b; extern int opt_d; extern unsigned int opt_f_align_functions; extern unsigned int opt_f_sizeof_char; extern unsigned int opt_f_sizeof_short_int; extern unsigned int opt_f_sizeof_int; extern unsigned int opt_f_sizeof_long_int; extern unsigned int opt_f_sizeof_long_long_int; extern unsigned int opt_f_segment_enable; faucc-20120707/print.h0000640002413100241000000000100411137625346014016 0ustar potyrai3guest/* $Id: print.h,v 1.2 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __PRINT_H_INCLUDED #define __PRINT_H_INCLUDED #include #include "scope.h" extern void print(FILE *fp, struct scope *s); #endif /* __PRINT_H_INCLUDED */ faucc-20120707/stmt.c0000640002413100241000000010702311137625346013654 0ustar potyrai3guest/* $Id: stmt.c,v 1.65 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include #include "identifier.h" #include "expr.h" #include "stmt.h" #include "simplify.h" #define countof(x) (sizeof(x) / sizeof(x[0])) static int stmt_change; static void stmt_check(struct stmt *s) { struct stmt *cs; if (! s) { return; } if (s->stmt0) { stmt_check(s->stmt0); } if (s->stmt1) { stmt_check(s->stmt1); } for (cs = s->stmt_first; cs; cs = cs->next) { stmt_check(cs); } switch (s->type) { case STMT_LABEL: assert(s->label->def_first); assert(s->label->def_first == s->label->def_last); assert(s->label->def_first == s); break; case STMT_GOTO: assert(s->label->ref_first); assert(s->label->ref_last); assert(s->label->def_first); assert(s->label->def_first == s->label->def_last); break; default: break; } } void stmt_rename_structunionenum(struct stmt *s, enum type_type type, const char *old, const char *new) { struct stmt *cs; if (s->expr0) { expr_rename_structunionenum(s->expr0, type, old, new); } if (s->expr1) { expr_rename_structunionenum(s->expr1, type, old, new); } if (s->expr2) { expr_rename_structunionenum(s->expr2, type, old, new); } if (s->stmt0) { stmt_rename_structunionenum(s->stmt0, type, old, new); } if (s->stmt1) { stmt_rename_structunionenum(s->stmt1, type, old, new); } for (cs = s->stmt_first; cs; cs = cs->next) { stmt_rename_structunionenum(cs, type, old, new); } if (s->type == STMT_BLOCK) { struct declaration *dion; for (dion = s->scope->declaration_first; dion; dion = dion->next) { declaration_rename_structunionenum(dion, type, old, new); } } } static void stmt_replace_break(struct stmt *s, struct label *label) { struct stmt *s1; switch (s->type) { case STMT_NONE: assert(0); case STMT_NULL: break; case STMT_LABEL: case STMT_CASE: case STMT_DEFAULT: stmt_replace_break(s->stmt0, label); break; case STMT_EXPR: break; case STMT_IF: stmt_replace_break(s->stmt0, label); if (s->stmt1) { stmt_replace_break(s->stmt1, label); } break; case STMT_SWITCH: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: break; case STMT_GOTO: case STMT_CONTINUE: break; case STMT_BREAK: stmt_cp(s, stmt_goto(label)); stmt_change = 1; break; case STMT_RETURN: case STMT_ASM: break; case STMT_BLOCK: for (s1 = s->stmt_first; s1; s1 = s1->next) { stmt_replace_break(s1, label); } break; default: assert(0); } } void stmt_replace_continue(struct stmt *s, struct label *label) { struct stmt *s1; switch (s->type) { case STMT_NONE: assert(0); case STMT_NULL: break; case STMT_LABEL: case STMT_CASE: case STMT_DEFAULT: stmt_replace_continue(s->stmt0, label); break; case STMT_EXPR: break; case STMT_IF: stmt_replace_continue(s->stmt0, label); if (s->stmt1) { stmt_replace_continue(s->stmt1, label); } break; case STMT_SWITCH: stmt_replace_continue(s->stmt0, label); break; case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: break; case STMT_GOTO: break; case STMT_CONTINUE: stmt_cp(s, stmt_goto(label)); stmt_change = 1; break; case STMT_BREAK: case STMT_RETURN: case STMT_ASM: break; case STMT_BLOCK: for (s1 = s->stmt_first; s1; s1 = s1->next) { stmt_replace_continue(s1, label); } break; default: assert(0); } } void stmt_prepend_first( struct stmt *block, struct stmt *n0 ) { n0->prev = NULL; n0->next = block->stmt_first; block->stmt_first = n0; if (n0->next) { n0->next->prev = n0; } else { block->stmt_last = n0; } } void stmt_prepend( struct stmt *block, struct stmt *o0, struct stmt *n0 ) { if (o0) { n0->prev = o0->prev; n0->next = o0; } else { n0->prev = NULL; n0->next = NULL; } if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n0->next) { n0->next->prev = n0; } else { block->stmt_last = n0; } } void stmt_append( struct stmt *block, struct stmt *o0, struct stmt *n0 ) { if (o0) { n0->prev = o0; n0->next = o0->next; } else { n0->prev = NULL; n0->next = NULL; } if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n0->next) { n0->next->prev = n0; } else { block->stmt_last = n0; } } void stmt_append_last( struct stmt *block, struct stmt *n0 ) { n0->prev = block->stmt_last; n0->next = NULL; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } block->stmt_last = n0; } static void stmt_free_contents(struct stmt *s) { switch (s->type) { case STMT_LABEL: label_def_del(s->label, s); break; case STMT_GOTO: label_ref_del(s->label, s); break; default: /* FIXME */ break; } if (s->stmt0) { stmt_free(s->stmt0); } if (s->stmt1) { stmt_free(s->stmt1); } while (s->stmt_first) { struct stmt *act; act = s->stmt_first; s->stmt_first = act->next; if (act->next) { act->next->prev = act->prev; } else { s->stmt_last = act->prev; } stmt_free(act); } } void stmt_free(struct stmt *s) { /* Free contents. */ stmt_free_contents(s); /* Free struct. */ free(s); } void stmt_cp(struct stmt *o, struct stmt *n) { /* Free old contents. */ stmt_free_contents(o); /* Copy new contents to old struct. */ o->type = n->type; o->label = n->label; if (o->type == STMT_LABEL) { label_def_del(n->label, n); label_def_add(o->label, o); } else if (o->type == STMT_GOTO) { label_ref_del(n->label, n); label_ref_add(o->label, o); } o->expr0 = n->expr0; o->expr1 = n->expr1; o->expr2 = n->expr2; o->stmt0 = n->stmt0; o->stmt1 = n->stmt1; o->code_len = n->code_len; o->code = n->code; o->output = n->output; o->input = n->input; o->change = n->change; o->stmt_first = n->stmt_first; o->stmt_last = n->stmt_last; o->scope = n->scope; o->jit = n->jit; /* Free new struct. */ free(n); } void stmt_replace_1_by_0( struct stmt *block, struct stmt *o0 ) { if (o0->prev) { o0->prev->next = o0->next; } else { block->stmt_first = o0->next; } if (o0->next) { o0->next->prev = o0->prev; } else { block->stmt_last = o0->prev; } stmt_free(o0); } void stmt_replace_1_by_1( struct stmt *block, struct stmt *o0, struct stmt *n0 ) { n0->prev = o0->prev; n0->next = o0->next; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n0->next) { n0->next->prev = n0; } else { block->stmt_last = n0; } stmt_free(o0); } void stmt_replace_1_by_2( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1 ) { n0->prev = o0->prev; n0->next = n1; n1->prev = n0; n1->next = o0->next; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n1->next) { n1->next->prev = n1; } else { block->stmt_last = n1; } stmt_free(o0); } void stmt_replace_1_by_3( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2 ) { n0->prev = o0->prev; n0->next = n1; n1->prev = n0; n1->next = n2; n2->prev = n1; n2->next = o0->next; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n2->next) { n2->next->prev = n2; } else { block->stmt_last = n2; } stmt_free(o0); } void stmt_replace_1_by_4( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3 ) { n0->prev = o0->prev; n0->next = n1; n1->prev = n0; n1->next = n2; n2->prev = n1; n2->next = n3; n3->prev = n2; n3->next = o0->next; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n3->next) { n3->next->prev = n3; } else { block->stmt_last = n3; } stmt_free(o0); } void stmt_replace_1_by_5( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3, struct stmt *n4 ) { n0->prev = o0->prev; n0->next = n1; n1->prev = n0; n1->next = n2; n2->prev = n1; n2->next = n3; n3->prev = n2; n3->next = n4; n4->prev = n3; n4->next = o0->next; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n4->next) { n4->next->prev = n4; } else { block->stmt_last = n4; } stmt_free(o0); } void stmt_replace_1_by_6( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3, struct stmt *n4, struct stmt *n5 ) { n0->prev = o0->prev; n0->next = n1; n1->prev = n0; n1->next = n2; n2->prev = n1; n2->next = n3; n3->prev = n2; n3->next = n4; n4->prev = n3; n4->next = n5; n5->prev = n4; n5->next = o0->next; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n5->next) { n5->next->prev = n5; } else { block->stmt_last = n5; } stmt_free(o0); } void stmt_replace_1_by_7( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3, struct stmt *n4, struct stmt *n5, struct stmt *n6 ) { n0->prev = o0->prev; n0->next = n1; n1->prev = n0; n1->next = n2; n2->prev = n1; n2->next = n3; n3->prev = n2; n3->next = n4; n4->prev = n3; n4->next = n5; n5->prev = n4; n5->next = n6; n6->prev = n5; n6->next = o0->next; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n6->next) { n6->next->prev = n6; } else { block->stmt_last = n6; } stmt_free(o0); } void stmt_replace_1_by_8( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3, struct stmt *n4, struct stmt *n5, struct stmt *n6, struct stmt *n7 ) { n0->prev = o0->prev; n0->next = n1; n1->prev = n0; n1->next = n2; n2->prev = n1; n2->next = n3; n3->prev = n2; n3->next = n4; n4->prev = n3; n4->next = n5; n5->prev = n4; n5->next = n6; n6->prev = n5; n6->next = n7; n7->prev = n6; n7->next = o0->next; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n7->next) { n7->next->prev = n7; } else { block->stmt_last = n7; } stmt_free(o0); } void stmt_replace_1_by_9( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3, struct stmt *n4, struct stmt *n5, struct stmt *n6, struct stmt *n7, struct stmt *n8 ) { n0->prev = o0->prev; n0->next = n1; n1->prev = n0; n1->next = n2; n2->prev = n1; n2->next = n3; n3->prev = n2; n3->next = n4; n4->prev = n3; n4->next = n5; n5->prev = n4; n5->next = n6; n6->prev = n5; n6->next = n7; n7->prev = n6; n7->next = n8; n8->prev = n7; n8->next = o0->next; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n8->next) { n8->next->prev = n8; } else { block->stmt_last = n8; } stmt_free(o0); } struct stmt * stmt_replace_2_by_1( struct stmt *block, struct stmt *o0, struct stmt *n0 ) { struct stmt *next; next = o0->next->next; n0->prev = o0->prev; n0->next = o0->next->next; if (n0->prev) { n0->prev->next = n0; } else { block->stmt_first = n0; } if (n0->next) { n0->next->prev = n0; } else { block->stmt_last = n0; } stmt_free(o0->next); stmt_free(o0); return next; } struct stmt * stmt_new(void) { struct stmt *s; s = malloc(sizeof(*s)); assert(s); memset(s, 0, sizeof(*s)); return s; } struct stmt * stmt_dup(struct stmt *o) { struct stmt *co; struct stmt *n; struct stmt *cn; if (o == NULL) { return NULL; } n = stmt_new(); n->type = o->type; if (o->label && o->label->clone) { n->label = o->label->clone; } else { n->label = o->label; } if (n->type == STMT_LABEL) { label_def_add(n->label, n); } else if (n->type == STMT_GOTO) { label_ref_add(n->label, n); } n->expr0 = expr_dup(o->expr0); n->expr1 = expr_dup(o->expr1); n->expr2 = expr_dup(o->expr2); n->stmt0 = stmt_dup(o->stmt0); n->stmt1 = stmt_dup(o->stmt1); n->code_len = o->code_len; n->code = identifier_dup(o->code); n->output = constraint_list_dup(o->output); n->input = constraint_list_dup(o->input); n->change = constraint_list_dup(o->change); n->stmt_first = NULL; n->stmt_last = NULL; for (co = o->stmt_first; co; co = co->next) { cn = stmt_dup(co); cn->prev = n->stmt_last; cn->next = NULL; if (cn->prev) { cn->prev->next = cn; } else { n->stmt_first = cn; } n->stmt_last = cn; } n->scope = o->scope; n->jit = o->jit; return n; } struct stmt * stmt_null(void) { struct stmt *s; s = stmt_new(); s->type = STMT_NULL; return s; } struct stmt * stmt_label(struct label *label, struct stmt *s0) { struct stmt *s; s = stmt_new(); s->type = STMT_LABEL; s->label = label; s->stmt0 = s0; label_def_add(label, s); return s; } struct stmt * stmt_expr(struct expr *e) { struct stmt *s; assert(e); s = stmt_new(); s->type = STMT_EXPR; s->expr0 = e; return s; } struct stmt * stmt_if(struct expr *e, struct stmt *s0, struct stmt *s1) { struct stmt *s; assert(e); assert(s0); /* s1 might be NULL. */ s = stmt_new(); s->type = STMT_IF; s->expr0 = e; s->stmt0 = s0; s->stmt1 = s1; return s; } struct stmt * stmt_goto(struct label *label) { struct stmt *s; s = stmt_new(); s->type = STMT_GOTO; s->label = label; label_ref_add(label, s); return s; } struct stmt * stmt_return(struct expr *expr) { struct stmt *s; s = stmt_new(); s->type = STMT_RETURN; s->expr0 = expr; return s; } /* ------------------------------------------------------------------------- */ int stmt_simplify_params(struct stmt *fs) { struct declaration *oparam; struct declaration *nparam; struct declaration *prev; struct type *t; struct stmt *s; for (oparam = fs->scope->function->type_name->parameter->declaration_last; oparam; oparam = prev) { prev = oparam->prev; switch (oparam->type_name->type) { case TYPE_NONE: case TYPE_MAX: assert(0); case TYPE_ELIPSIS: continue; case TYPE_VOID: continue; case TYPE_VA_LIST: case TYPE_POINTER: case TYPE_ENUM: /* Copy as is... */ t = oparam->type_name; goto copy; case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: case TYPE_INT64: case TYPE_UINT64: case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: /* Copy as arithmetic type... */ t = type_arithmetic(oparam->type_name, oparam->type_name); copy: ; nparam = declaration_identifier(identifier_tmp()); nparam->storage = STORAGE_PARAM; nparam->type_name = t; nparam->prev = oparam->prev; nparam->next = oparam->next; if (nparam->prev) { nparam->prev->next = nparam; } else { fs->scope->function->type_name->parameter->declaration_first = nparam; } if (nparam->next) { nparam->next->prev = nparam; } else { fs->scope->function->type_name->parameter->declaration_last = nparam; } oparam->storage = STORAGE_AUTO; oparam->prev = NULL; oparam->next = fs->scope->declaration_first; fs->scope->declaration_first = oparam; if (oparam->next) { oparam->next->prev = oparam; } else { fs->scope->declaration_last = oparam; } if (t == oparam->type_name) { s = stmt_expr(expr_assign( expr_identifier(oparam), expr_identifier(nparam))); } else { s = stmt_expr(expr_assign( expr_identifier(oparam), expr_cast(oparam->type_name, expr_identifier(nparam)))); } stmt_prepend_first(fs, s); break; case TYPE_STRUCT: case TYPE_UNION: /* Leave as is... */ break; case TYPE_ARRAY: case TYPE_FUNCTION: assert(0); } } return 1; } int stmt_simplify_returns(struct stmt *fs) { struct stmt *cs; struct type *type; struct declaration *var; struct label *label; struct stmt *s0; struct stmt *s1; assert(fs->type == STMT_BLOCK); if (fs->scope->function->attr_noreturn) { return 0; } type = fs->scope->function->type_name; type = type_call(type); type = type_pure(type); if (type->type == TYPE_VOID) { var = NULL; } else { var = simplify_declaration_add(fs->scope, type, identifier_tmp()); } label = label_new(identifier_tmp()); for (cs = fs->stmt_first; cs; ) { struct stmt *next; next = cs->next; if (cs->type == STMT_RETURN) { if (cs->expr0) { assert(var); s0 = stmt_expr(expr_assign( expr_identifier(var), expr_dup(cs->expr0))); s1 = stmt_goto(label); stmt_replace_1_by_2(fs, cs, s0, s1); } else { assert(! var); s0 = stmt_goto(label); stmt_replace_1_by_1(fs, cs, s0); } } cs = next; } s0 = stmt_label(label, stmt_null()); if (var) { s1 = stmt_return(expr_identifier(var)); } else { s1 = stmt_return(NULL); } stmt_append(fs, fs->stmt_last, s0); stmt_append(fs, fs->stmt_last, s1); return 1; } static struct stmt * simplify_get_case_stmt(struct stmt *s) { struct stmt *cs; struct stmt *res; switch (s->type) { case STMT_NONE: assert(0); case STMT_NULL: return NULL; case STMT_LABEL: return simplify_get_case_stmt(s->stmt0); case STMT_CASE: return s; case STMT_DEFAULT: return simplify_get_case_stmt(s->stmt0); case STMT_EXPR: return NULL; case STMT_IF: res = simplify_get_case_stmt(s->stmt0); if (res) { return res; } if (s->stmt1) { res = simplify_get_case_stmt(s->stmt1); if (res) { return res; } } return NULL; case STMT_SWITCH: return NULL; case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: return simplify_get_case_stmt(s->stmt0); case STMT_GOTO: case STMT_BREAK: case STMT_CONTINUE: case STMT_RETURN: case STMT_ASM: case STMT_VA_START: case STMT_VA_END: return NULL; case STMT_BLOCK: for (cs = s->stmt_first; cs; cs = cs->next) { res = simplify_get_case_stmt(cs); if (res) { return res; } } return NULL; default: assert(0); } assert(0); } static struct stmt * simplify_get_default_stmt(struct stmt *s) { struct stmt *cs; struct stmt *res; switch (s->type) { case STMT_NONE: assert(0); case STMT_NULL: return NULL; case STMT_LABEL: return simplify_get_default_stmt(s->stmt0); case STMT_CASE: return simplify_get_default_stmt(s->stmt0); case STMT_DEFAULT: return s; case STMT_EXPR: return NULL; case STMT_IF: res = simplify_get_default_stmt(s->stmt0); if (res) { return res; } if (s->stmt1) { res = simplify_get_default_stmt(s->stmt1); if (res) { return res; } } return NULL; case STMT_SWITCH: return NULL; case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: return simplify_get_default_stmt(s->stmt0); case STMT_GOTO: case STMT_BREAK: case STMT_CONTINUE: case STMT_RETURN: case STMT_ASM: case STMT_VA_START: case STMT_VA_END: return NULL; case STMT_BLOCK: for (cs = s->stmt_first; cs; cs = cs->next) { res = simplify_get_default_stmt(cs); if (res) { return res; } } return NULL; default: assert(0); } assert(0); } static int simplify_switch_ifgotoswitch_check(struct stmt *s) { struct stmt *s0; int default_seen; if (s->stmt0->scope->declaration_first) { return 0; } default_seen = 0; for (s0 = s->stmt0->stmt_first; s0; s0 = s0->next) { if (s0->type == STMT_CASE) { if (default_seen) { return 0; } } else if (s0->type == STMT_DEFAULT) { default_seen = 1; } else { return 0; } if (! s0->stmt0 || s0->stmt0->type != STMT_GOTO) { return 0; } } return default_seen; } static void stmt_sim_in_stmt(struct stmt *block, struct stmt *s) { struct label *label0; struct label *label1; struct label *label2; struct label *label3; struct stmt *s0; struct stmt *s1; struct stmt *s2; struct stmt *s3; struct stmt *s4; struct stmt *s5; struct stmt *s6; struct stmt *s7; struct stmt *s8; struct stmt *cs; switch (s->type) { case STMT_NONE: assert(0); case STMT_NULL: if (block) { /* * Replace * ; * by * --- */ stmt_replace_1_by_0(block, s); stmt_change = 1; stmt_check(block); } break; case STMT_LABEL: if (block && s->stmt0->type != STMT_NULL) { /* * Replace * l0: s; * by * l0: ; * s; */ s0 = stmt_label(s->label, stmt_null()); s1 = stmt_dup(s->stmt0); stmt_replace_1_by_2(block, s, s0, s1); stmt_change = 1; stmt_check(block); } break; case STMT_CASE: case STMT_DEFAULT: assert(0); case STMT_EXPR: break; case STMT_IF: if (block && s->stmt0->type != STMT_GOTO && s->stmt1) { /* * Replace * if (e) s0; * else s1; * by * 0: if (e) goto label0; * 1: s1; * 2: goto label1; * 3: label0: ; * 4: s0; * 5: label1: ; */ label0 = label_new(identifier_tmp()); label1 = label_new(identifier_tmp()); s0 = stmt_if(expr_dup(s->expr0), stmt_goto(label0), NULL); s1 = stmt_dup(s->stmt1); s2 = stmt_goto(label1); s3 = stmt_label(label0, stmt_null()); s4 = stmt_dup(s->stmt0); s5 = stmt_label(label1, stmt_null()); stmt_replace_1_by_6(block, s, s0, s1, s2, s3, s4, s5); stmt_change = 1; stmt_check(block); break; } if (block && s->stmt0->type != STMT_GOTO && ! s->stmt1) { /* * Replace * if (e) s0; * by * 0: if (! e) goto label; * 1: s0; * 2: label: ; */ label0 = label_new(identifier_tmp()); s0 = stmt_if(expr_not(expr_dup(s->expr0)), stmt_goto(label0), NULL); s1 = stmt_dup(s->stmt0); s2 = stmt_label(label0, stmt_null()); stmt_replace_1_by_3(block, s, s0, s1, s2); stmt_change = 1; stmt_check(block); break; } break; case STMT_SWITCH: if (! block || simplify_switch_ifgotoswitch_check(s)) { goto simplify_switch_done; } /* * Replace * switch (e) { * case A: sA; * case B: sB; * ... * default: sDefault; * ... * case N: sN; * } * by * 0: switch (e) { * 1: case A: * 2: goto LA; * 3: case B: * 4: goto LB; * .. . * 10: case N: * 11: goto LN; * 20: default: * 21: goto LDefault; * } * 30: { * 31: LA: * 32: sA; * 33: LB: * 34: sB; * ... * 40: LDefault: * 41: sDefault; * ... * 50: LN: * 51: sN; * } * 60: end: ; * * Replace all "break;" by "goto end;" */ label0 = label_new(identifier_tmp()); stmt_replace_break(s->stmt0, label0); /* New Switch Statement */ s0 = stmt_new(); s0->type = STMT_SWITCH; s0->expr0 = s->expr0; s0->stmt0 = stmt_new(); s0->stmt0->type = STMT_BLOCK; s0->stmt0->stmt_first = NULL; s0->stmt0->stmt_last = NULL; s0->stmt0->scope = s->stmt0->scope; /* New Block */ s1 = stmt_dup(s->stmt0); /* end: Label */ s2 = stmt_label(label0, stmt_null()); /* * Replace "case" statements. */ while ((s3 = simplify_get_case_stmt(s1)) != NULL) { /* Replace by label. */ label1 = label_new(identifier_tmp()); /* Add new case statement to new switch. */ s4 = stmt_new(); s4->type = STMT_CASE; s4->expr0 = expr_dup(s3->expr0); s4->stmt0 = stmt_goto(label1); stmt_prepend_first(s0->stmt0, s4); /* Replace old case statement by new label. */ s4 = stmt_label(label1, stmt_null()); s5 = stmt_dup(s3->stmt0); stmt_replace_1_by_2(s1, s3, s4, s5); } /* * Replace "default" statement (if present). */ s3 = simplify_get_default_stmt(s1); if (s3) { /* Goto default statement. */ label1 = label_new(identifier_tmp()); } else { /* No default statement => goto end. */ label1 = label0; } s4 = stmt_new(); s4->type = STMT_DEFAULT; s4->stmt0 = stmt_goto(label1); /* Add new default statement to new switch. */ stmt_append_last(s0->stmt0, s4); if (s3) { /* Replace old default statement by new label. */ s4 = stmt_label(label1, stmt_null()); s5 = stmt_dup(s3->stmt0); stmt_replace_1_by_2(s1, s3, s4, s5); } stmt_replace_1_by_3(block, s, s0, s1, s2); stmt_change = 1; stmt_check(block); simplify_switch_done:; break; case STMT_WHILE: if (block) { /* * Replace * while (e) s; * by * 0: goto L1; * 1: L0: ; * 2: s; * 3: L1: ; * 4: if (e) goto L0; * 5: L2: ; * * Substitute "break" and "continue" in "s" by * "goto L2;" and "goto L1;". */ label0 = label_new(identifier_tmp()); label1 = label_new(identifier_tmp()); label2 = label_new(identifier_tmp()); stmt_replace_continue(s->stmt0, label1); stmt_replace_break(s->stmt0, label2); s0 = stmt_goto(label1); s1 = stmt_label(label0, stmt_null()); s2 = stmt_dup(s->stmt0); s3 = stmt_label(label1, stmt_null()); s4 = stmt_if(expr_dup(s->expr0), stmt_goto(label0), NULL); s5 = stmt_label(label2, stmt_null()); stmt_replace_1_by_6(block, s, s0, s1, s2, s3, s4, s5); stmt_change |= 1; stmt_check(block); } break; case STMT_DO_WHILE: if (block) { /* * Replace * do s; while (e); * by * 0: L0: ; * 1: s; * 2: L1: ; * 3: if (e) goto L0; * 4: L2: ; * * Substitute "break" and "continue" in "s" by * "goto L2;" and "goto L1;". */ label0 = label_new(identifier_tmp()); label1 = label_new(identifier_tmp()); label2 = label_new(identifier_tmp()); stmt_replace_continue(s->stmt0, label1); stmt_replace_break(s->stmt0, label2); s0 = stmt_label(label0, stmt_null()); s1 = stmt_dup(s->stmt0); s2 = stmt_label(label1, stmt_null()); s3 = stmt_if(expr_dup(s->expr0), stmt_goto(label0), NULL); s4 = stmt_label(label2, stmt_null()); stmt_replace_1_by_5(block, s, s0, s1, s2, s3, s4); stmt_change = 1; stmt_check(block); } break; case STMT_FOR: if (block) { /* * Replace * for (e0; e1; e2) s * by * 0: e0; * 1: goto L2; * 2: L0: ; * 3: s * 4: L1: ; * 5: e2; * 6: L2: ; * 7: if (e1) goto L0; * 8: L3: ; * * Substitute "break" and "continue" in "s" by * "goto L3" and "goto L1". */ label0 = label_new(identifier_tmp()); label1 = label_new(identifier_tmp()); label2 = label_new(identifier_tmp()); label3 = label_new(identifier_tmp()); stmt_replace_continue(s->stmt0, label1); stmt_replace_break(s->stmt0, label3); if (s->expr0) { s0 = stmt_expr(expr_dup(s->expr0)); } else { s0 = stmt_null(); } s1 = stmt_goto(label2); s2 = stmt_label(label0, stmt_null()); s3 = stmt_dup(s->stmt0); s4 = stmt_label(label1, stmt_null()); if (s->expr2) { s5 = stmt_expr(expr_dup(s->expr2)); } else { s5 = stmt_null(); } s6 = stmt_label(label2, stmt_null()); if (s->expr1) { s7 = stmt_if(expr_dup(s->expr1), stmt_goto(label0), NULL); } else { s7 = stmt_goto(label0); } s8 = stmt_label(label3, stmt_null()); stmt_replace_1_by_9(block, s, s0, s1, s2, s3, s4, s5, s6, s7, s8); stmt_change = 1; stmt_check(block); } break; case STMT_GOTO: case STMT_CONTINUE: case STMT_BREAK: break; case STMT_RETURN: case STMT_ASM: case STMT_VA_START: case STMT_VA_END: break; case STMT_BLOCK: for (cs = s->stmt_first; cs; ) { struct stmt *next; next = cs->next; stmt_sim_in_stmt(s, cs); cs = next; } for (cs = s->stmt_first; cs; ) { struct stmt *next; next = cs->next; if (cs->type == STMT_BLOCK && ! cs->scope->declaration_first) { /* Merge blocks. */ while (cs->stmt_first) { /* Remove statement from inner block.*/ s0 = cs->stmt_last; if (s0->prev) { s0->prev->next = s0->next; } else { cs->stmt_first = s0->next; } cs->stmt_last = s0->prev; /* Add statement to outer block. */ s0->prev = cs; s0->next = cs->next; s0->prev->next = s0; if (s0->next) { s0->next->prev = s0; } else { s->stmt_last = s0; } } /* Remove inner block. */ if (cs->prev) { cs->prev->next = cs->next; } else { s->stmt_first = cs->next; } if (cs->next) { cs->next->prev = cs->prev; } else { s->stmt_last = cs->prev; } /* Don't free block! It's part of a scope! */ stmt_change = 1; } cs = next; } stmt_check(block); break; default: assert(0); } } int stmt_simplify(struct stmt *fs) { int retval; retval = 0; do { stmt_change = 0; stmt_sim_in_stmt(fs, fs); retval |= stmt_change; } while (stmt_change); return retval; } /* ------------------------------------------------------------------------- */ void stmt_opt_label_hashlist(struct stmt *fs) { /* Nothing to do... */ } struct stmt * stmt_opt_label_lookup(struct label *label) { assert(label->def_first); assert(label->def_first == label->def_last); return label->def_first; } static void stmt_opt_control_in_stmt(struct stmt *fs, struct stmt *s) { struct stmt *ss; struct stmt *s0; struct stmt *s1; struct stmt *target; switch (s->type) { case STMT_NONE: assert(0); case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_CONTINUE: case STMT_BREAK: case STMT_BLOCK: /* Should have been removed by simplify_control. */ assert(0); case STMT_NULL: /* * Replace * ; * by * --- */ stmt_replace_1_by_0(fs, s); stmt_change = 1; break; case STMT_LABEL: assert(s->stmt0->type == STMT_NULL); break; case STMT_EXPR: break; case STMT_IF: assert(s->expr0); assert(s->stmt0 && s->stmt0->type == STMT_GOTO); assert(! s->stmt1); if (s->expr0->type == EXPR_INTEGER && s->expr0->integer == 0) { /* * Replace * if (0) goto l0; * by * --- */ stmt_replace_1_by_0(fs, s); stmt_change = 1; } else if (s->expr0->type == EXPR_INTEGER && s->expr0->integer != 0) { /* * Replace * if (1) goto l0; * by * goto l0; */ s0 = stmt_goto(s->stmt0->label); stmt_replace_1_by_1(fs, s, s0); stmt_change = 1; } else if (s->next && s->next->type == STMT_LABEL && strcmp(s->stmt0->label->identifier, s->next->label->identifier) == 0) { /* * Replace * if (e) goto l0; * l0: ; * by * e; * l0: ; */ s0 = stmt_expr(expr_dup(s->expr0)); stmt_replace_1_by_1(fs, s, s0); stmt_change = 1; } else if (s->next && s->next->type == STMT_GOTO && s->next->next && s->next->next->type == STMT_LABEL && strcmp(s->stmt0->label->identifier, s->next->next->label->identifier) == 0) { /* * Replace * if (e) goto l0; * goto l1; * l0: ; * by * if (! e) goto l1; * goto l0; * goto l1; * l0: ; */ /* * NOTE: * We *mustn't* replace * if (e) goto l0; * goto l1; * l0: ; * by * if (! e) goto l1; * l0: ; * * as we cannot replace *2* statements * by 1! */ s0 = stmt_if(expr_not(expr_dup(s->expr0)), stmt_goto(s->next->label), NULL); s1 = stmt_goto(s->stmt0->label); stmt_replace_1_by_2(fs, s, s0, s1); stmt_change = 1; } else { /* Try to optimize goto. */ stmt_opt_control_in_stmt(NULL, s->stmt0); } break; case STMT_SWITCH: if (s->expr0->type == EXPR_INTEGER) { /* * Replace * switch (numX) { * case ...: goto l0; * case ...: goto l1; * ... * case numX: goto lX; * ... * default: goto ldef; * } * by * goto lX; */ struct label *label; label = NULL; for (ss = s->stmt0->stmt_first; ss; ss = ss->next) { assert(ss->type == STMT_CASE || ss->type == STMT_DEFAULT); assert(ss->stmt0 && ss->stmt0->type == STMT_GOTO); if (ss->type == STMT_CASE && s->expr0->integer == ss->expr0->integer) { label = ss->stmt0->label; } else if (ss->type == STMT_DEFAULT && label == NULL) { label = ss->stmt0->label; } } assert(label); s0 = stmt_goto(label); stmt_replace_1_by_1(fs, s, s0); stmt_change = 1; } else { /* Try to optimize gotos. */ for (ss = s->stmt0->stmt_first; ss; ss = ss->next) { assert(ss->type == STMT_CASE || ss->type == STMT_DEFAULT); assert(ss->stmt0 && ss->stmt0->type == STMT_GOTO); stmt_opt_control_in_stmt(NULL, ss->stmt0); } } break; case STMT_GOTO: target = stmt_opt_label_lookup(s->label); assert(target); if (s->next && s->next == target) { /* * Replace * goto l0; * l0: ; * by * l0: ; */ assert(fs); stmt_replace_1_by_0(fs, s); stmt_change = 1; } else if (target->next && target->next->type == STMT_GOTO && s->label != target->next->label) { /* * Replace * goto l0; * ... * l0: ; * goto l1; * ... * l1: ; * by * goto l1; * ... * l0: ; * goto l1; * ... * l1: ; */ label_ref_del(s->label, s); s->label = target->next->label; label_ref_add(s->label, s); stmt_change = 1; } else if (target->next && target->next->type == STMT_LABEL) { /* * Replace * goto l0; * ... * l0: ; * l1: ; * by * goto l1; * ... * l0: ; * l1: ; */ label_ref_del(s->label, s); s->label = target->next->label; label_ref_add(s->label, s); stmt_change = 1; } break; case STMT_RETURN: case STMT_ASM: case STMT_VA_START: case STMT_VA_END: break; default: assert(0); } } static void stmt_opt_control(struct stmt *fs) { struct stmt *cs; assert(fs->type == STMT_BLOCK); for (cs = fs->stmt_first; cs; ) { struct stmt *next; next = cs->next; stmt_opt_control_in_stmt(fs, cs); cs = next; } } static void stmt_opt_mark_unused(struct stmt *s) { struct stmt *cs; if (s->stmt0) { stmt_opt_mark_unused(s->stmt0); } if (s->stmt1) { stmt_opt_mark_unused(s->stmt1); } for (cs = s->stmt_first; cs; cs = cs->next) { stmt_opt_mark_unused(cs); } s->stmt_used = 0; s->label_used = 0; } static void stmt_opt_mark_used_in_stmt(struct stmt *s) { struct stmt *ss; struct stmt *target; if (! s || s->stmt_used) { return; } s->stmt_used = 1; switch (s->type) { case STMT_NONE: assert(0); case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_CONTINUE: case STMT_BREAK: case STMT_BLOCK: /* Should have been removed by simplify_control. */ assert(0); case STMT_NULL: /* Should have been removed above. */ assert(0); case STMT_LABEL: case STMT_EXPR: case STMT_ASM: case STMT_VA_START: case STMT_VA_END: stmt_opt_mark_used_in_stmt(s->next); break; case STMT_IF: stmt_opt_mark_used_in_stmt(s->stmt0); stmt_opt_mark_used_in_stmt(s->next); break; case STMT_SWITCH: for (ss = s->stmt0->stmt_first; ss; ss = ss->next) { stmt_opt_mark_used_in_stmt(ss->stmt0); } break; case STMT_GOTO: target = stmt_opt_label_lookup(s->label); target->label_used = 1; stmt_opt_mark_used_in_stmt(target); break; case STMT_RETURN: break; default: assert(0); } } static void stmt_opt_mark_used(struct stmt *fs) { assert(fs->type == STMT_BLOCK); stmt_opt_mark_used_in_stmt(fs->stmt_first); } static void stmt_opt_remove_unused(struct stmt *fs) { struct stmt *cs; for (cs = fs->stmt_first; cs; ) { struct stmt *next; next = cs->next; if (! cs->stmt_used || (cs->type == STMT_LABEL && ! cs->label_used)) { stmt_replace_1_by_0(fs, cs); stmt_change = 1; } cs = next; } } int stmt_optimize(struct stmt *fs) { stmt_change = 0; stmt_opt_label_hashlist(fs); stmt_opt_control(fs); stmt_opt_mark_unused(fs); stmt_opt_mark_used(fs); stmt_opt_remove_unused(fs); return stmt_change; } faucc-20120707/autogen.sh0000750002413100241000000000117411137625345014520 0ustar potyrai3guest#!/bin/sh # # $Id: autogen.sh,v 1.2 2009-01-27 15:40:21 potyra Exp $ # # Copyright (C) 2008-2009 FAUcc Team . # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. set -e # create scripts directory in case it doesn't exist yet if [ ! -d scripts ]; then mkdir -p scripts fi aclocal #autoheader #libtoolize --force --ltdl -c --automake automake --force --add-missing --copy autoconf echo echo "Now run ./configure to proceed in building FAUcc." faucc-20120707/visitor.h0000640002413100241000000000117311714721521014361 0ustar potyrai3guest/* * $Id: visitor.h,v 1.2 2012-02-09 10:43:29 vrsieh Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "scope.h" #include "stmt.h" #include "expr.h" extern int visitor_stmt( struct scope *scope, int repeat, int (*sv)(int, struct stmt *, struct stmt *) ); extern int visitor_expr( struct scope *scope, int repeat, int (*ev)(int, struct stmt *, struct stmt *, struct expr *) ); faucc-20120707/expr.h0000640002413100241000000001031611137625346013646 0ustar potyrai3guest/* $Id: expr.h,v 1.68 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __EXPR_H_INCLUDED #define __EXPR_H_INCLUDED #include "type.h" #include "scope.h" /* * Types */ struct expr { struct expr *prev; struct expr *next; enum { EXPR_NONE, EXPR_INTEGER, EXPR_REAL, EXPR_STRING, EXPR_IDENTIFIER, EXPR_BRACES, EXPR_SIZEOF_TYPE, EXPR_SIZEOF_EXPR, EXPR_BUILTIN_CONSTANT_P, EXPR_BUILTIN_OFFSETOF, EXPR_BUILTIN_VA_ARG, EXPR_TYPE_CONVERSION, EXPR_STAR, EXPR_AMPHERSAND, EXPR_PRE_INC, EXPR_PRE_DEC, EXPR_POST_INC, EXPR_POST_DEC, EXPR_NEG, EXPR_INV, EXPR_NOT, EXPR_LEFT, EXPR_RIGHT, EXPR_EQUAL, EXPR_NOT_EQUAL, EXPR_LESS, EXPR_GREATER, EXPR_LESS_EQUAL, EXPR_GREATER_EQUAL, EXPR_ADD, EXPR_SUB, EXPR_MUL, EXPR_DIV, EXPR_MOD, EXPR_AND, EXPR_OR, EXPR_XOR, EXPR_SHORT_OR, EXPR_SHORT_AND, EXPR_LIST, EXPR_DOT, EXPR_ARROW, EXPR_ARRAY, EXPR_FUNC, EXPR_CONDITION, EXPR_ASSIGN, EXPR_LEFT_ASSIGN, EXPR_RIGHT_ASSIGN, EXPR_ADD_ASSIGN, EXPR_SUB_ASSIGN, EXPR_MUL_ASSIGN, EXPR_DIV_ASSIGN, EXPR_MOD_ASSIGN, EXPR_AND_ASSIGN, EXPR_OR_ASSIGN, EXPR_XOR_ASSIGN, } type; unsigned long long integer; long double real; unsigned int string_len; const char *string; const char *member; struct declaration *declaration; struct type *type_name; struct expr *expr0; struct expr *expr1; struct expr *expr2; struct expr *first; struct expr *last; }; /* * Functions */ extern void expr_rename_structunionenum( struct expr *e, enum type_type type, const char *old, const char *new); extern struct type * expr_typeof(struct scope *s, struct expr *e); extern int expr_is_constant(struct expr *e); extern struct expr * expr_new(void); extern struct expr * expr_integer(int n); extern struct expr * expr_identifier(struct declaration *dion); extern struct expr * expr_sizeof_expr(struct expr *e0); extern struct expr * expr_sizeof_type(struct type *t); extern struct expr * expr_offsetof(struct type *ts, const char *mem); extern struct expr * expr_amphersand(struct expr *e0); extern struct expr * expr_star(struct expr *e0); extern struct expr * expr_arrow(struct expr *e0, const char *mem); extern struct expr * expr_not(struct expr *e0); extern struct expr * expr_left(struct expr *e0, struct expr *e1); extern struct expr * expr_right(struct expr *e0, struct expr *e1); extern struct expr * expr_add(struct expr *e0, struct expr *e1); extern struct expr * expr_sub(struct expr *e0, struct expr *e1); extern struct expr * expr_mul(struct expr *e0, struct expr *e1); extern struct expr * expr_div(struct expr *e0, struct expr *e1); extern struct expr * expr_mod(struct expr *e0, struct expr *e1); extern struct expr * expr_and(struct expr *e0, struct expr *e1); extern struct expr * expr_or(struct expr *e0, struct expr *e1); extern struct expr * expr_xor(struct expr *e0, struct expr *e1); extern struct expr * expr_short_and(struct expr *e0, struct expr *e1); extern struct expr * expr_short_or(struct expr *e0, struct expr *e1); extern struct expr * expr_equal(struct expr *e0, struct expr *e1); extern struct expr * expr_not_equal(struct expr *e0, struct expr *e1); extern struct expr * expr_less(struct expr *e0, struct expr *e1); extern struct expr * expr_less_equal(struct expr *e0, struct expr *e1); extern struct expr * expr_greater(struct expr *e0, struct expr *e1); extern struct expr * expr_greater_equal(struct expr *e0, struct expr *e1); extern struct expr * expr_assign(struct expr *e0, struct expr *e1); extern struct expr * expr_add_assign(struct expr *e0, struct expr *e1); extern struct expr * expr_cast(struct type *t, struct expr *e0); extern struct expr * expr_cast_ptrdiff(struct expr *e0); extern struct expr * expr_dup(struct expr *e); extern void expr_cp(struct expr *oe, struct expr *ne); extern void expr_free(struct expr *e); extern int expr_simplify(struct scope *s, struct declaration *dion); extern int expr_optimize(struct scope *s, struct declaration *dion); #endif /* __EXPR_H_INCLUDED */ faucc-20120707/COPYING0000640002413100241000000004310311134141647013544 0ustar potyrai3guest GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. faucc-20120707/label.h0000640002413100241000000000171511137625346013752 0ustar potyrai3guest/* $Id: label.h,v 1.4 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __LABEL_H_INCLUDED #define __LABEL_H_INCLUDED #include "stmt.h" struct label { struct label *prev; struct label *next; const char *identifier; struct stmt *ref_first; struct stmt *ref_last; struct stmt *def_first; struct stmt *def_last; struct label *clone; }; extern struct label * label_new(const char *identifier); extern void label_ref_add(struct label *label, struct stmt *s); extern void label_ref_del(struct label *label, struct stmt *s); extern void label_def_add(struct label *label, struct stmt *s); extern void label_def_del(struct label *label, struct stmt *s); #endif /* __LABEL_H_INCLUDED */ faucc-20120707/declaration.h0000640002413100241000000000551411137625346015161 0ustar potyrai3guest/* $Id: declaration.h,v 1.72 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __DECLARATION_H_INCLUDED #define __DECLARATION_H_INCLUDED #include #include "type.h" /* * Constants */ #define DECL_CLASS_NONE 0 #define DECL_CLASS_COUNT 32 #define DECL_REG_COUNT (DECL_CLASS_COUNT * 8) #define DECL_MEMORY DECL_REG_COUNT /* * Types */ struct storage_register { const char *name; unsigned int class; enum type_type type; }; struct decl_live { struct decl_live *prev; struct decl_live *next; struct declaration *decl; }; struct declaration { struct declaration *prev; struct declaration *next; const char *identifier; enum type_storage { STORAGE_NONE = 0, STORAGE_AUTO, STORAGE_STATIC, STORAGE_TYPEDEF, STORAGE_REGISTER, STORAGE_EXTERN, STORAGE_PARAM, STORAGE_ASM, } storage; unsigned int mod_inline; unsigned int attr_aligned; unsigned int attr_noreturn; struct expr *nbits; struct expr *initializer; struct stmt *stmt; struct type *type_name; const char *regname; const char *code; struct declaration *clone; /* SSA Info */ struct expr *assign_expr; unsigned int acount; unsigned int wcount; unsigned int rcount; /* Register Allocation */ unsigned int storage_class; int storage_mem; unsigned int spills; unsigned int reg_count[DECL_CLASS_COUNT]; struct decl_live *move_first; struct decl_live *move_last; struct decl_live *conflict_first; struct decl_live *conflict_last; struct decl_live *conflict_save_first; struct decl_live *conflict_save_last; unsigned int storage_register; unsigned int offset; /* FAUjitcc */ int jit; }; /* * Functions */ extern void declaration_rename_structunionenum( struct declaration *dion, enum type_type type, const char *old, const char *new ); extern void declaration_rename_type( struct declaration *dion, const char *old, const char *new); extern struct declaration * declaration_new(void); extern void declaration_name_set(struct declaration *d, const char *name); extern const char * declaration_name_get(struct declaration *dor); extern void declaration_type_get(struct type **adp, struct declaration *dor); extern void declaration_initializer_set(struct declaration *dor, struct expr *initializer); extern struct expr * declaration_initializer_get(struct declaration *dor); extern struct declaration * declaration_identifier(const char *name); extern void declaration_free(struct declaration *dor); extern void declaration_alive(struct storage_register *reginfo, unsigned int *classinfo, unsigned int *typeinfo, struct stmt *fs); #endif /* __DECLARATION_H_INCLUDED */ faucc-20120707/scan.h0000640002413100241000000000060111717461564013614 0ustar potyrai3guest/* $Id: scan.h,v 1.4 2012-02-17 14:25:56 vrsieh Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ extern FILE *yyin; extern int yylex(void); faucc-20120707/arch_i286_gen.h0000640002413100241000000000313011721453472015200 0ustar potyrai3guest/* $Id: arch_i286_gen.h,v 1.22 2012-02-23 15:11:54 vrsieh Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __ARCH_I286_GEN_H_INCLUDED #define __ARCH_I286_GEN_H_INCLUDED #include "scope.h" #include "type.h" extern struct type * arch_i286_type_intptr_t(void); extern struct type * arch_i286_type_uintptr_t(void); extern void arch_i286_align_size( struct scope *scope, struct type *type, unsigned int *alignp, unsigned int *sizep); extern void arch_i286_gen_class_and_type_get( const char *name, unsigned int *classp, enum type_type *typep); extern unsigned int arch_i286_gen_class_or(unsigned int a, unsigned int b); extern unsigned int arch_i286_gen_class_and(unsigned int a, unsigned int b); extern void arch_i286_color_init(unsigned int *count); extern void arch_i286_color_add(unsigned int *count, unsigned int set, enum type_type type); extern void arch_i286_color_sub(unsigned int *count, unsigned int set, enum type_type type); extern int arch_i286_color_check(unsigned int *count, unsigned int set, enum type_type type); extern void arch_i286_gen_reg_init(uint32_t *conflicts); extern void arch_i286_gen_reg_add(uint32_t *conflicts, unsigned int reg); extern int arch_i286_gen_reg_get(uint32_t *conflicts, unsigned int class, enum type_type type); extern void arch_i286_gen(const char *out, struct scope *scope); #endif /* __ARCH_I286_GEN_H_INCLUDED */ faucc-20120707/setup.h0000640002413100241000000000077211137625346014035 0ustar potyrai3guest/* $Id: setup.h,v 1.10 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #define SIGNED_CHAR (((char) -1) == -1) #define SIZEOF_FLOAT sizeof(float) #define SIZEOF_DOUBLE sizeof(double) #define SIZEOF_LONG_DOUBLE sizeof(long double) faucc-20120707/regalloc.c0000640002413100241000000011046411721457410014452 0ustar potyrai3guest/* $Id: regalloc.c,v 1.1 2012-02-23 15:45:12 vrsieh Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include #include "identifier.h" #include "declaration.h" #include "expr.h" #include "arch_i286_gen.h" #include "arch_i386_gen.h" #include "simplify.h" #include "stmt.h" #include "cc1.h" static void decl_reg_to_type_and_class( const char *name, enum type_type *typep, unsigned int *classp ) { switch (opt_b) { case TARGET_I286: arch_i286_gen_class_and_type_get(name, classp, typep); break; case TARGET_I386: arch_i386_gen_class_and_type_get(name, classp, typep); break; default: assert(0); } } static unsigned int decl_reg_class_or(unsigned int a, unsigned int b) { switch (opt_b) { case TARGET_I286: return arch_i286_gen_class_or(a, b); case TARGET_I386: return arch_i386_gen_class_or(a, b); default: assert(0); } } static unsigned int decl_reg_class_and(unsigned int a, unsigned int b) { switch (opt_b) { case TARGET_I286: return arch_i286_gen_class_and(a, b); case TARGET_I386: return arch_i386_gen_class_and(a, b); default: assert(0); } } static void decl_color_init(unsigned int *count) { switch (opt_b) { case TARGET_I286: arch_i286_color_init(count); break; case TARGET_I386: arch_i386_color_init(count); break; default: assert(0); } } static void decl_color_add(unsigned int *count, unsigned int class, enum type_type type) { switch (opt_b) { case TARGET_I286: arch_i286_color_add(count, class, type); break; case TARGET_I386: arch_i386_color_add(count, class, type); break; default: assert(0); } } static void decl_color_sub(unsigned int *count, unsigned int class, enum type_type type) { switch (opt_b) { case TARGET_I286: arch_i286_color_sub(count, class, type); break; case TARGET_I386: arch_i386_color_sub(count, class, type); break; default: assert(0); } } static int decl_color_check(unsigned int *count, unsigned int class, enum type_type type) { switch (opt_b) { case TARGET_I286: return arch_i286_color_check(count, class, type); case TARGET_I386: return arch_i386_color_check(count, class, type); default: assert(0); } } static void decl_reg_init(uint32_t *conflicts) { switch (opt_b) { case TARGET_I286: arch_i286_gen_reg_init(conflicts); break; case TARGET_I386: arch_i386_gen_reg_init(conflicts); break; default: assert(0); } } static void decl_reg_add(uint32_t *conflicts, unsigned int reg) { switch (opt_b) { case TARGET_I286: arch_i286_gen_reg_add(conflicts, reg); break; case TARGET_I386: arch_i386_gen_reg_add(conflicts, reg); break; default: assert(0); } } static int decl_reg_get(uint32_t *conflicts, unsigned int class, enum type_type type) { switch (opt_b) { case TARGET_I286: return arch_i286_gen_reg_get(conflicts, class, type); case TARGET_I386: return arch_i386_gen_reg_get(conflicts, class, type); default: assert(0); } } static int decl_add(struct decl_live **fp, struct decl_live **lp, struct declaration *d) { struct decl_live *l; for (l = *fp; ; l = l->next) { if (! l) { l = malloc(sizeof *l); assert(l); l->decl = d; l->prev = *lp; l->next = NULL; if (l->prev) { l->prev->next = l; } else { *fp = l; } *lp = l; return 0; } if (l->decl == d) { /* Already in list. */ return 1; } } } static int decl_remove(struct decl_live **fp, struct decl_live **lp, struct declaration *d) { struct decl_live *l; for (l = *fp; ; l = l->next) { if (! l) { return 1; } if (l->decl == d) { if (l->prev) { l->prev->next = l->next; } else { *fp = l->next; } if (l->next) { l->next->prev = l->prev; } else { *lp = l->prev; } free(l); return 0; } } } static int decl_is_element(struct decl_live *first, struct declaration *d) { struct decl_live *l; for (l = first; ; l = l->next) { if (! l) { return 0; } if (l->decl == d) { return 1; } } } static unsigned int decl_count(struct decl_live *first) { struct decl_live *l; unsigned int count; for (l = first, count = 0; l; l = l->next, count++) { } return count; } static int decl_live_add(struct stmt *s, unsigned int tail, struct declaration *d) { return decl_add(&s->decl_live_first[tail], &s->decl_live_last[tail], d); } static void decl_conflict_add(struct declaration *d0, struct declaration *d1) { if (d0 == d1) { /* Don't add conflicts with myself. */ return; } decl_add(&d0->conflict_first, &d0->conflict_last, d1); decl_add(&d1->conflict_first, &d1->conflict_last, d0); } static void decl_move_add(struct declaration *d0, struct declaration *d1) { if (d0 == d1) { /* Don't add moves to myself. */ return; } decl_add(&d0->move_first, &d0->move_last, d1); decl_add(&d1->move_first, &d1->move_last, d0); } static void decl_move_remove(struct declaration *d0, struct declaration *d1) { decl_remove(&d0->move_first, &d0->move_last, d1); decl_remove(&d1->move_first, &d1->move_last, d0); } static int declaration_alive_merge0(struct stmt *s) { struct decl_live *w; struct decl_live *l; int done; done = 1; for (l = s->decl_live_first[1]; l; l = l->next) { for (w = s->decl_write_first; ; w = w->next) { if (! w) { /* Not written in s. */ done &= decl_live_add(s, 0, l->decl); break; } if (l->decl == w->decl) { /* Written in s. */ break; } } } return done; } static int declaration_alive_merge1(struct stmt *s0, struct stmt *s1) { struct decl_live *l; int done; done = 1; for (l = s1->decl_live_first[0]; l; l = l->next) { done &= decl_live_add(s0, 1, l->decl); } return done; } static void declaration_alive_rhs_expr(struct stmt *s, struct expr *e) { struct expr *ce; switch (e->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_LIST: assert(0); case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: break; case EXPR_AMPHERSAND: assert(e->expr0->type == EXPR_IDENTIFIER); if (e->expr0->declaration->storage == STORAGE_AUTO || e->expr0->declaration->storage == STORAGE_REGISTER) { e->expr0->declaration->storage_class = DECL_CLASS_NONE; assert(e->expr0->declaration->storage_mem); decl_add(&s->decl_write_first, &s->decl_write_last, e->expr0->declaration); decl_add(&s->decl_live_first[1], &s->decl_live_last[1], e->expr0->declaration); } break; case EXPR_IDENTIFIER: if ((e->declaration->storage == STORAGE_AUTO || e->declaration->storage == STORAGE_REGISTER) && e->declaration->type_name->type != TYPE_ARRAY) { decl_add(&s->decl_read_first, &s->decl_read_last, e->declaration); decl_add(&s->decl_live_first[0], &s->decl_live_last[0], e->declaration); } break; case EXPR_BUILTIN_VA_ARG: case EXPR_TYPE_CONVERSION: case EXPR_STAR: case EXPR_NEG: case EXPR_INV: case EXPR_NOT: declaration_alive_rhs_expr(s, e->expr0); break; case EXPR_LEFT: case EXPR_RIGHT: case EXPR_ADD: case EXPR_SUB: case EXPR_MUL: case EXPR_DIV: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_XOR: case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: declaration_alive_rhs_expr(s, e->expr0); declaration_alive_rhs_expr(s, e->expr1); break; case EXPR_ASSIGN: assert(0); declaration_alive_rhs_expr(s, e->expr1); break; case EXPR_FUNC: declaration_alive_rhs_expr(s, e->expr0); for (ce = e->expr1->first; ce; ce = ce->next) { declaration_alive_rhs_expr(s, ce); } break; } } static void declaration_alive_lhs_expr(struct stmt *s, struct expr *e) { if (e->type == EXPR_IDENTIFIER) { if ((e->declaration->storage == STORAGE_AUTO || e->declaration->storage == STORAGE_REGISTER) && s) { decl_add(&s->decl_write_first, &s->decl_write_last, e->declaration); decl_add(&s->decl_live_first[1], &s->decl_live_last[1], e->declaration); } } else { assert(e->type == EXPR_STAR); declaration_alive_rhs_expr(s, e->expr0); } } static void declaration_alive_expr(struct stmt *s, struct expr *e) { if (e->type == EXPR_ASSIGN) { declaration_alive_lhs_expr(s, e->expr0); declaration_alive_rhs_expr(s, e->expr1); } else { declaration_alive_rhs_expr(s, e); } } static void decl_expr_constraints(struct expr *e) { struct expr *ce; if (e->expr0) { decl_expr_constraints(e->expr0); } if (e->expr1) { decl_expr_constraints(e->expr1); } for (ce = e->first; ce; ce = ce->next) { decl_expr_constraints(ce); } switch (e->type) { case EXPR_AMPHERSAND: assert(e->expr0->type == EXPR_IDENTIFIER); if (e->expr0->declaration->storage == STORAGE_AUTO || e->expr0->declaration->storage == STORAGE_REGISTER) { e->expr0->declaration->storage_class = DECL_CLASS_NONE; assert(e->expr0->declaration->storage_mem); } break; default: /* No constraints... */ break; } } static void decl_asm_constraints( unsigned int *classinfo, struct scope *scope, const char *s, struct expr *e ) { unsigned int regs; int m; const char *str; unsigned int i; str = s; if ('0' <= *str && *str <= '9') { return; } else { regs = DECL_CLASS_NONE; m = 0; for (str = s; *str; str++) { switch (*str) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': assert(0); case '=': case '&': case '+': break; case 'A': case 'D': case 'S': case 'a': case 'b': case 'c': case 'd': case 'f': case 'q': case 'r': case 'l': case 't': case 'u': i = (unsigned int) *str; assert(classinfo[i] != DECL_CLASS_NONE); regs = decl_reg_class_or(regs, classinfo[i]); break; case 'i': break; case 'm': m = 1; break; default: fprintf(stderr, "Unknown constraint '%c'.\n", *str); assert(0); } } } switch (e->type) { case EXPR_INTEGER: case EXPR_REAL: case EXPR_AMPHERSAND: case EXPR_TYPE_CONVERSION: break; case EXPR_IDENTIFIER: if (e->declaration->storage == STORAGE_AUTO || e->declaration->storage == STORAGE_REGISTER) { e->declaration->storage_class = decl_reg_class_and( e->declaration->storage_class, regs); e->declaration->storage_mem &= m; assert(e->declaration->storage_class != DECL_CLASS_NONE || e->declaration->storage_mem); } break; default: assert(0); } } static void decl_replace( struct expr *e, struct expr *old, struct expr *new ) { if (e->type == EXPR_IDENTIFIER && e->declaration == old->declaration) { expr_cp(e, expr_dup(new)); } } static void decl_lhs_replace( struct expr *e, struct expr *old, struct expr *new ) { if (! e) { return; } switch (e->type) { case EXPR_IDENTIFIER: decl_replace(e, old, new); break; case EXPR_ASSIGN: decl_replace(e->expr0, old, new); break; case EXPR_FUNC: break; default: assert(0); } } static void decl_rhs_replace( struct expr *e, struct expr *old, struct expr *new ) { struct expr *ce; if (! e) { return; } switch (e->type) { case EXPR_INTEGER: break; case EXPR_IDENTIFIER: decl_replace(e, old, new); break; case EXPR_ASSIGN: if (e->expr0->type == EXPR_STAR) { assert(e->expr0->expr0->type == EXPR_TYPE_CONVERSION); decl_replace(e->expr0->expr0->expr0, old, new); } decl_replace(e->expr1, old, new); if (e->expr1->expr0) { decl_replace(e->expr1->expr0, old, new); if (e->expr1->expr0->expr0) { decl_replace(e->expr1->expr0->expr0, old, new); } } if (e->expr1->expr1) { decl_replace(e->expr1->expr1, old, new); for (ce = e->expr1->expr1->first; ce; ce = ce->next) { decl_replace(ce, old, new); } } break; case EXPR_FUNC: decl_replace(e->expr0, old, new); for (ce = e->expr1->first; ce; ce = ce->next) { decl_replace(ce, old, new); } break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: decl_replace(e->expr0, old, new); decl_replace(e->expr1, old, new); break; default: assert(0); } } static void decl_constraint_ease( struct stmt *block, struct stmt *s, struct constraint *c, struct expr **exprlist, unsigned int i ) { struct type *t; struct declaration *dion; struct stmt *s0; struct stmt *s1; const char *constraint; t = expr_typeof(block->scope, c->expr); t = type_pure(t); if (t->type == TYPE_FLOAT32 || t->type == TYPE_FLOAT64 || t->type == TYPE_FLOAT80) { constraint = "=fm"; } else { constraint = "=rm"; } if (*c->string == '=') { /* * Output */ if ((c->expr->type == EXPR_IDENTIFIER && c->expr->declaration->type_name->mod_volatile) || strcmp(c->string, "=m") == 0) { /* Leave as is. */ exprlist[i] = c->expr; return; } if (strchr(c->string, 'm')) { /* Memory allowed. Leave as is. */ exprlist[i] = c->expr; return; } dion = declaration_identifier(identifier_tmp()); dion->storage = STORAGE_AUTO; dion->type_name = t; scope_declaration_append(block->scope, dion); s0 = stmt_expr(expr_assign( expr_dup(c->expr), expr_identifier(dion))); constraint_output(s0, constraint, expr_dup(c->expr)); constraint_input(s0, constraint + 1, expr_identifier(dion)); s0->change = constraint_list_new(); decl_lhs_replace(s->expr0, c->expr, expr_identifier(dion)); expr_cp(c->expr, expr_identifier(dion)); stmt_append(block, s, s0); exprlist[i] = c->expr; } else if (*c->string == '+') { /* * Input/Output */ if ((c->expr->type == EXPR_IDENTIFIER && c->expr->declaration->type_name->mod_volatile) || strcmp(c->string, "+m") == 0) { /* Leave as is. */ exprlist[i] = c->expr; return; } if (strchr(c->string, 'm')) { /* Memory allowed. Leave as is. */ exprlist[i] = c->expr; return; } dion = declaration_identifier(identifier_tmp()); dion->storage = STORAGE_AUTO; dion->type_name = t; scope_declaration_append(block->scope, dion); s0 = stmt_expr(expr_assign( expr_identifier(dion), expr_dup(c->expr))); constraint_output(s0, constraint, expr_identifier(dion)); constraint_input(s0, constraint + 1, expr_dup(c->expr)); s0->change = constraint_list_new(); s1 = stmt_expr(expr_assign( expr_dup(c->expr), expr_identifier(dion))); constraint_output(s1, constraint, expr_dup(c->expr)); constraint_input(s1, constraint + 1, expr_identifier(dion)); s1->change = constraint_list_new(); stmt_prepend(block, s, s0); decl_lhs_replace(s->expr0, c->expr, expr_identifier(dion)); decl_rhs_replace(s->expr0, c->expr, expr_identifier(dion)); expr_cp(c->expr, expr_identifier(dion)); stmt_append(block, s, s1); exprlist[i] = c->expr; } else if ('0' <= *c->string && *c->string <= '9') { /* * Input for Output */ assert(atoi(c->string) < i); assert(atoi(c->string) < 100); if (exprlist[atoi(c->string)]->type == EXPR_IDENTIFIER && exprlist[atoi(c->string)]->declaration->type_name->mod_volatile) { /* Leave as is. */ return; } s0 = stmt_expr(expr_assign( expr_dup(exprlist[atoi(c->string)]), expr_dup(c->expr))); constraint_output(s0, constraint, expr_dup(exprlist[atoi(c->string)])); constraint_input(s0, constraint + 1, expr_dup(c->expr)); s0->change = constraint_list_new(); stmt_prepend(block, s, s0); decl_rhs_replace(s->expr0, c->expr, expr_dup(exprlist[atoi(c->string)])); expr_cp(c->expr, expr_dup(exprlist[atoi(c->string)])); } else if (strchr(c->string, 'i') && expr_is_constant(c->expr)) { /* * Constant Input */ /* Leave as is. */ } else { /* * Input */ if ((c->expr->type == EXPR_IDENTIFIER && c->expr->declaration->type_name->mod_volatile) || strcmp(c->string, "m") == 0) { /* Leave as is. */ return; } if (strchr(c->string, 'm') && (strchr(c->string, 'i') || ! expr_is_constant(c->expr))) { /* Everything allowed. Leave as is. */ return; } dion = declaration_identifier(identifier_tmp()); dion->storage = STORAGE_AUTO; dion->type_name = t; scope_declaration_append(block->scope, dion); s0 = stmt_expr(expr_assign( expr_identifier(dion), expr_dup(c->expr))); constraint_output(s0, constraint, expr_identifier(dion)); constraint_input(s0, constraint + 1, expr_dup(c->expr)); s0->change = constraint_list_new(); stmt_prepend(block, s, s0); decl_rhs_replace(s->expr0, c->expr, expr_identifier(dion)); expr_cp(c->expr, expr_identifier(dion)); } } static int decl_can_coalesce(struct declaration *d0, struct declaration *d1) { unsigned int count0[DECL_CLASS_COUNT]; unsigned int count1[DECL_CLASS_COUNT]; struct decl_live *l0; struct decl_live *l1; struct declaration *n; int first; int check; decl_color_init(count0); for (l0 = d0->conflict_first; l0; l0 = l0->next) { n = l0->decl; first = 1; decl_color_init(count1); for (l1 = n->conflict_first; l1; l1 = l1->next) { if (l1->decl == d0 || l1->decl == d1) { if (first) { decl_color_add(count1, decl_reg_class_and( d0->storage_class, d1->storage_class), d0->type_name->type); first = 0; } } else { decl_color_add(count1, l1->decl->storage_class, l1->decl->type_name->type); } } check = decl_color_check(count1, n->storage_class, n->type_name->type); if (! check) { decl_color_add(count0, n->storage_class, n->type_name->type); } } for (l0 = d1->conflict_first; l0; l0 = l0->next) { n = l0->decl; if (decl_is_element(d0->conflict_first, n)) { continue; } first = 1; decl_color_init(count1); for (l1 = n->conflict_first; l1; l1 = l1->next) { if (l1->decl == d0 || l1->decl == d1) { if (first) { decl_color_add(count1, decl_reg_class_and( d0->storage_class, d1->storage_class), d0->type_name->type); first = 0; } } else { decl_color_add(count1, l1->decl->storage_class, l1->decl->type_name->type); } } check = decl_color_check(count1, n->storage_class, n->type_name->type); if (! check) { decl_color_add(count0, n->storage_class, n->type_name->type); } } return decl_color_check(count0, decl_reg_class_and(d0->storage_class, d1->storage_class), d0->type_name->type); } static void decl_coalesce(struct declaration *d0, struct declaration *d1) { struct declaration *n; while (d0->conflict_first) { n = d0->conflict_first->decl; decl_remove(&n->conflict_first, &n->conflict_last, d0); decl_add(&n->conflict_first, &n->conflict_last, d1); decl_remove(&d0->conflict_first, &d0->conflict_last, n); decl_add(&d1->conflict_first, &d1->conflict_last, n); } while (d0->move_first) { n = d0->move_first->decl; assert(n != d0); decl_move_remove(d0, n); decl_move_add(d1, n); } d0->storage_class = decl_reg_class_and( d0->storage_class, d1->storage_class); d1->storage_class = decl_reg_class_and( d0->storage_class, d1->storage_class); d0->storage_mem &= d1->storage_mem; d1->storage_mem &= d0->storage_mem; d0->clone = d1; } void regalloc( struct storage_register *reginfo, unsigned int *classinfo, unsigned int *typeinfo, struct stmt *fs ) { struct expr *exprlist[100]; struct declaration *dion; struct declaration *stack_first; struct declaration *stack_last; struct stmt *cs; struct stmt *ss; struct constraint *c; struct stmt *target; unsigned int i; int done; #if 0 print_stmt(stderr, 1, 0, fs); fprintf(stderr, "\n"); #endif for (cs = fs->stmt_first; cs; ) { struct stmt *next; next = cs->next; i = 0; if (cs->output) { for (c = cs->output->first; c; c = c->next) { decl_constraint_ease(fs, cs, c, exprlist, i); i++; } } if (cs->input) { for (c = cs->input->last; c; c = c->prev) { decl_constraint_ease(fs, cs, c, exprlist, i); i++; } } cs = next; } #if 0 print_stmt(stderr, 1, 0, fs); fprintf(stderr, "\n"); #endif if (fs->scope->declaration_first != fs->scope->declaration_last) { /* * Sort declarations. Register variables to top of * declaration list. */ for (dion = fs->scope->declaration_first; dion && dion->storage == STORAGE_REGISTER; dion = dion->next) { } if (dion) { struct declaration *dion2; for (dion2 = dion->next; dion2; dion2 = dion2->next) { if (dion2->storage != STORAGE_REGISTER) { continue; } /* Move dion2 before dion. */ dion2->prev->next = dion2->next; if (dion2->next) { dion2->next->prev = dion2->prev; } else { fs->scope->declaration_last = dion2->prev; } dion2->prev = dion->prev; dion2->next = dion; if (dion2->prev) { dion2->prev->next = dion2; } else { fs->scope->declaration_first = dion2; } dion2->next->prev = dion2; } } } #if 0 print_stmt(stderr, 1, 0, fs); fprintf(stderr, "\n"); #endif for (dion = fs->scope->declaration_first; dion; dion = dion->next) { if (dion->storage != STORAGE_AUTO && dion->storage != STORAGE_REGISTER) { continue; } assert(dion->identifier); dion->storage_class = typeinfo[dion->type_name->type]; dion->storage_mem = 1; } for (cs = fs->stmt_first; cs; cs = cs->next) { switch (cs->type) { case STMT_NONE: assert(0); case STMT_NULL: case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_BREAK: case STMT_CONTINUE: case STMT_BLOCK: assert(0); case STMT_LABEL: case STMT_EXPR: case STMT_IF: case STMT_SWITCH: case STMT_GOTO: case STMT_RETURN: case STMT_VA_START: case STMT_VA_END: if (cs->expr0) { decl_expr_constraints(cs->expr0); } if (cs->expr1) { decl_expr_constraints(cs->expr1); } break; case STMT_ASM: break; default: assert(0); } if (cs->output) { for (c = cs->output->first; c; c = c->next) { decl_expr_constraints(c->expr); decl_asm_constraints( classinfo, fs->scope, c->string, c->expr); } } if (cs->input) { for (c = cs->input->first; c; c = c->next) { decl_expr_constraints(c->expr); decl_asm_constraints( classinfo, fs->scope, c->string, c->expr); } } } for (cs = fs->stmt_first; cs; cs = cs->next) { cs->decl_write_first = NULL; cs->decl_write_last = NULL; cs->decl_read_first = NULL; cs->decl_read_last = NULL; cs->decl_live_first[0] = NULL; cs->decl_live_last[0] = NULL; cs->decl_live_first[1] = NULL; cs->decl_live_last[1] = NULL; } for (cs = fs->stmt_first; cs; cs = cs->next) { switch (cs->type) { case STMT_NONE: assert(0); case STMT_NULL: case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_BREAK: case STMT_CONTINUE: case STMT_BLOCK: assert(0); case STMT_LABEL: case STMT_GOTO: break; case STMT_EXPR: case STMT_IF: case STMT_SWITCH: declaration_alive_expr(cs, cs->expr0); break; case STMT_RETURN: if (cs->expr0) { declaration_alive_expr(cs, cs->expr0); } break; case STMT_ASM: break; case STMT_VA_START: declaration_alive_lhs_expr(cs, cs->expr0); declaration_alive_rhs_expr(cs, cs->expr1); break; case STMT_VA_END: break; default: assert(0); } /* All statements might have constraints... */ if (cs->output) { for (c = cs->output->first; c; c = c->next) { assert(c->string[0] == '='); assert(c->expr->type == EXPR_IDENTIFIER); declaration_alive_lhs_expr(cs, c->expr); } } if (cs->input) { for (c = cs->input->first; c; c = c->next) { assert(c->string[0] != '='); declaration_alive_rhs_expr(cs, c->expr); } } } stmt_opt_label_hashlist(fs); do { done = 1; /* Iterate bottom up! */ for (cs = fs->stmt_last; cs; cs = cs->prev) { done &= declaration_alive_merge0(cs); switch (cs->type) { case STMT_NONE: assert(0); case STMT_NULL: case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_BREAK: case STMT_CONTINUE: case STMT_BLOCK: assert(0); case STMT_LABEL: assert(cs->stmt0->type == STMT_NULL); /*FALLTHROUGH*/ case STMT_ASM: case STMT_VA_START: case STMT_VA_END: if (cs->next) { done &= declaration_alive_merge1(cs, cs->next); } break; case STMT_EXPR: if (cs->expr0->type != EXPR_FUNC || cs->expr0->expr0->type != EXPR_IDENTIFIER || ! cs->expr0->expr0->declaration->attr_noreturn) { if (cs->next) { done &= declaration_alive_merge1( cs, cs->next); } } break; case STMT_IF: if (cs->next) { done &= declaration_alive_merge1(cs, cs->next); } target = stmt_opt_label_lookup( cs->stmt0->label); done &= declaration_alive_merge1(cs, target); break; case STMT_SWITCH: for (ss = cs->stmt0->stmt_first; ss; ss = ss->next) { target = stmt_opt_label_lookup( ss->stmt0->label); done &= declaration_alive_merge1(cs, target); } break; case STMT_GOTO: target = stmt_opt_label_lookup(cs->label); done &= declaration_alive_merge1(cs, target); break; case STMT_RETURN: /* No next statement. */ break; default: assert(0); } } } while (! done); #if 0 print_stmt(stderr, 1, 0, fs); fprintf(stderr, "\n"); #endif if (fs->stmt_first && fs->stmt_first->decl_live_first[0]) { struct decl_live *l; fprintf(stderr, "Live variables at start of function:\n"); for (l = fs->stmt_first->decl_live_first[0]; l; l = l->next) { fprintf(stderr, "\t%s\n", l->decl->identifier); } } /* * Build conflict matrix. */ for (cs = fs->stmt_first; cs; cs = cs->next) { if (cs->output) { for (c = cs->output->first; c; c = c->next) { assert(c->string[0] == '='); assert(c->expr->type == EXPR_IDENTIFIER); if (c->string[1] == '&') { struct constraint *c1; assert(cs->input); for (c1 = cs->input->first; c1; c1 = c1->next) { if (c1->expr->type == EXPR_IDENTIFIER && (c1->expr->declaration->storage == STORAGE_NONE || c1->expr->declaration->storage == STORAGE_AUTO || c1->expr->declaration->storage == STORAGE_REGISTER)) { decl_conflict_add(c->expr->declaration, c1->expr->declaration); } } } } } if (cs->change) { for (c = cs->change->first; c; c = c->next) { enum type_type type; unsigned int class; struct declaration *var; if (strcmp(c->string, "cc") == 0 || strcmp(c->string, "memory") == 0) { continue; } decl_reg_to_type_and_class(c->string, &type, &class); var = simplify_declaration_add(fs->scope, type_gen(type), identifier_tmp()); var->storage = STORAGE_AUTO; var->storage_class = class; /* decl_live_add(cs, 0, var); Correct? */ decl_live_add(cs, 1, var); } } } for (cs = fs->stmt_first; cs; cs = cs->next) { struct decl_live *l0; struct decl_live *l1; for (l0 = cs->decl_live_first[0]; l0; l0 = l0->next) { for (l1 = l0->next; l1; l1 = l1->next) { decl_conflict_add(l0->decl, l1->decl); } } for (l0 = cs->decl_live_first[1]; l0; l0 = l0->next) { for (l1 = l0->next; l1; l1 = l1->next) { decl_conflict_add(l0->decl, l1->decl); } } } #if 0 print_stmt(stderr, 1, 0, fs); fprintf(stderr, "\n"); #endif #if 0 /* * Print conflict matrix. */ for (dion = fs->scope->declaration_first; dion; dion = dion->next) { struct decl_live *l; if (dion->storage != STORAGE_AUTO && dion->storage != STORAGE_REGISTER) { continue; } fprintf(stderr, "%s:", dion->identifier); for (l = dion->conflict_first; l; l = l->next) { fprintf(stderr, " %s", l->decl->identifier); } fprintf(stderr, "\n"); } #endif /* * Calculate spill costs. */ for (cs = fs->stmt_first; cs; cs = cs->next) { struct decl_live *l; for (l = cs->decl_write_first; l; l = l->next) { l->decl->spills++; } for (l = cs->decl_read_first; l; l = l->next) { l->decl->spills++; } } /* * Build move matrix. */ for (cs = fs->stmt_first; cs; cs = cs->next) { if (cs->type == STMT_EXPR && cs->expr0->type == EXPR_ASSIGN && cs->expr0->expr0->type == EXPR_IDENTIFIER && (cs->expr0->expr0->declaration->storage == STORAGE_AUTO || cs->expr0->expr0->declaration->storage == STORAGE_REGISTER) && cs->expr0->expr1->type == EXPR_IDENTIFIER && (cs->expr0->expr1->declaration->storage == STORAGE_AUTO || cs->expr0->expr1->declaration->storage == STORAGE_REGISTER)) { decl_move_add(cs->expr0->expr0->declaration, cs->expr0->expr1->declaration); } } /* * Initialize class counts. */ for (dion = fs->scope->declaration_first; dion; dion = dion->next) { struct decl_live *l; decl_color_init(dion->reg_count); for (l = dion->conflict_first; l; l = l->next) { decl_color_add(dion->reg_count, l->decl->storage_class, l->decl->type_name->type); } } /* * Try to assign registers. */ stack_first = NULL; stack_last = NULL; for (;;) { unsigned int count[DECL_CLASS_COUNT]; struct declaration *seldion; unsigned int seldegree; struct decl_live *l0; /* * Select variable to be removed from list. */ again: ; /* Simplify */ for (dion = fs->scope->declaration_first; dion; dion = dion->next) { int check; if (dion->storage != STORAGE_AUTO && dion->storage != STORAGE_REGISTER) { continue; } if (dion->move_first) { /* Ignore move related nodes. */ continue; } decl_color_init(count); for (l0 = dion->conflict_first; l0; l0 = l0->next) { decl_color_add(count, l0->decl->storage_class, l0->decl->type_name->type); } check = decl_color_check(count, dion->storage_class, dion->type_name->type); if (check) { seldion = dion; goto selected; } } /* Coalesce */ seldion = NULL; for (dion = fs->scope->declaration_first; dion; dion = dion->next) { if (dion->storage != STORAGE_AUTO && dion->storage != STORAGE_REGISTER) { continue; } for (l0 = dion->move_first; l0; l0 = l0->next) { if (decl_is_element(dion->conflict_first, l0->decl)) { continue; } if (! decl_can_coalesce(dion, l0->decl)) { continue; } seldion = dion; break; } if (seldion) { decl_coalesce(seldion, l0->decl); break; } } if (seldion) { goto selected; } /* Freeze */ for (dion = fs->scope->declaration_first; dion; dion = dion->next) { int check; if (dion->storage != STORAGE_AUTO && dion->storage != STORAGE_REGISTER) { continue; } if (! dion->move_first) { continue; } decl_color_init(count); for (l0 = dion->conflict_first; l0; l0 = l0->next) { decl_color_add(count, l0->decl->storage_class, l0->decl->type_name->type); } check = decl_color_check(count, dion->storage_class, dion->type_name->type); if (check) { /* Remove "move" info. */ while (dion->move_first) { decl_move_remove(dion, dion->move_first->decl); } goto again; } } /* Spill */ seldion = NULL; seldegree = 0; for (dion = fs->scope->declaration_first; dion; dion = dion->next) { if (dion->storage != STORAGE_AUTO && dion->storage != STORAGE_REGISTER) { continue; } #if 0 if (dion->move_first) { /* Ignore move related nodes. */ continue; } #endif if (dion->storage_mem) { if (! seldion || seldegree < decl_count(dion->conflict_first)) { seldion = dion; seldegree = decl_count(dion->conflict_first); } } } if (seldion) { goto selected; } /* No more variables left. */ break; selected:; /* * Remove variable from list. */ if (seldion->prev) { seldion->prev->next = seldion->next; } else { fs->scope->declaration_first = seldion->next; } if (seldion->next) { seldion->next->prev = seldion->prev; } else { fs->scope->declaration_last = seldion->prev; } /* * Add to operation stack. */ seldion->prev = stack_last; seldion->next = NULL; if (seldion->prev) { seldion->prev->next = seldion; } else { stack_first = seldion; } stack_last = seldion; /* * Remove move info. */ while (seldion->move_first) { decl_move_remove(seldion, seldion->move_first->decl); } /* * Move variable from conflict list of neighbours * to their conflict_save list. */ for (l0 = seldion->conflict_first; l0; l0 = l0->next) { struct declaration *n; n = l0->decl; /* Remove variable from conflict list. */ decl_remove(&n->conflict_first, &n->conflict_last, seldion); /* Add variable to conflict_save list. */ decl_add(&n->conflict_save_first, &n->conflict_save_last, seldion); } } /* All variables must be on stack. */ #if 1 for (dion = fs->scope->declaration_first; dion; dion = dion->next) { struct decl_live *l; if (dion->storage != STORAGE_AUTO && dion->storage != STORAGE_REGISTER) { continue; } for (i = 0; ; i++) { assert(i < 256); if (classinfo[i] == dion->storage_class) { break; } } fprintf(stderr, "%s (class: \"%c\", type: %s, mem: %u):", dion->identifier, i, type_info[dion->type_name->type], dion->storage_mem); for (l = dion->conflict_first; l; l = l->next) { fprintf(stderr, " %s", l->decl->identifier); } fprintf(stderr, "\n"); } #endif for (dion = fs->scope->declaration_first; dion; dion = dion->next) { if (dion->storage != STORAGE_AUTO && dion->storage != STORAGE_REGISTER) { continue; } assert(0); } while (stack_last) { struct decl_live *l0; int reg; dion = stack_last; /* * Remove variable from stack. */ if (dion->prev) { dion->prev->next = dion->next; } else { stack_first = dion->next; } assert(! dion->next); stack_last = dion->prev; /* * Re-add variable to variable list. */ dion->prev = fs->scope->declaration_last; dion->next = NULL; if (dion->prev) { dion->prev->next = dion; } else { fs->scope->declaration_first = dion; } fs->scope->declaration_last = dion; /* * Move variable from conflict_save list of neighbours * to their conflict list. */ for (l0 = dion->conflict_first; l0; l0 = l0->next) { struct declaration *n; n = l0->decl; /* Remove variable from conflict_save list. */ decl_remove(&n->conflict_save_first, &n->conflict_save_last, dion); /* Add variable to conflict list. */ decl_add(&n->conflict_first, &n->conflict_last, dion); } if (dion->clone) { dion->storage_register = dion->clone->storage_register; dion->storage = dion->clone->storage; dion->clone = NULL; } else { /* Assign register. */ decl_reg_init(dion->reg_count); for (l0 = dion->conflict_first; l0; l0 = l0->next) { if (l0->decl->storage_register != DECL_MEMORY) { decl_reg_add(dion->reg_count, l0->decl->storage_register); } } reg = decl_reg_get(dion->reg_count, dion->storage_class, dion->type_name->type); if (0 <= reg) { dion->storage_register = reg; dion->storage = STORAGE_REGISTER; } else if (dion->storage_mem) { dion->storage_register = DECL_MEMORY; dion->storage = STORAGE_AUTO; } else { for (i = 0; ; i++) { assert(i < 256); if (classinfo[i] == dion->storage_class) { break; } } fprintf(stderr, "No register for %s found (class \"%c\", type %s).\n", dion->identifier, i, type_info[dion->type_name->type]); for (l0 = dion->conflict_first; l0; l0 = l0->next) { for (i = 0; ; i++) { assert(i < 256); if (classinfo[i] == l0->decl->storage_class) { break; } } fprintf(stderr, "%s: (class \"%c\", type %s): %s\n", l0->decl->identifier, i, type_info[l0->decl->type_name->type], reginfo[l0->decl->storage_register].name); } assert(0); } } #if 0 if (dion->storage_register != DECL_MEMORY) { fprintf(stderr, "%s: %s\n", dion->identifier, reginfo[dion->storage_register].name); } else { fprintf(stderr, "%s: %s\n", dion->identifier, "memory"); } #endif } } faucc-20120707/set.h0000640002413100241000000000637111137625346013471 0ustar potyrai3guest/* $Id: set.h,v 1.3 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #define set_declare(name, count) \ typedef unsigned char name ## _set[(count + 7) / 8]; \ \ extern int \ name ## _set_is_element(unsigned char *set, unsigned int n); \ extern int \ name ## _set_find_forward(unsigned char *set); \ extern void \ name ## _set_add(unsigned char *set, unsigned int n); \ extern void \ name ## _set_remove(unsigned char *set, unsigned int n); \ extern void \ name ## _set_or(unsigned char *dst, unsigned char *src); \ extern void \ name ## _set_and(unsigned char *dst, unsigned char *src); \ extern void \ name ## _set_and_comp(unsigned char *dst, unsigned char *src); \ extern void \ name ## _set_cp(unsigned char *dst, unsigned char *src); \ extern void \ name ## _set_empty(unsigned char *set); \ extern void \ name ## _set_fill(unsigned char *set); #define set_implement(name, count) \ int \ name ## _set_is_element(unsigned char *set, unsigned int n) \ { \ return (set[n / 8] >> (n % 8)) & 1; \ } \ \ int \ name ## _set_find_forward(unsigned char *set) \ { \ unsigned int n; \ unsigned int m; \ \ for (n = 0; ; n++) { \ if (n == (count + 7) / 8) { \ return -1; \ } \ if (set[n]) { \ for (m = 0; ; m++) { \ if (set[n] & (1 << m)) { \ return n * 8 + m; \ } \ } \ } \ } \ } \ \ void \ name ## _set_add(unsigned char *set, unsigned int n) \ { \ set[n / 8] |= 1 << (n % 8); \ } \ \ void \ name ## _set_remove(unsigned char *set, unsigned int n) \ { \ set[n / 8] &= ~(1 << (n % 8)); \ } \ \ void \ name ## _set_or(unsigned char *dst, unsigned char *src) \ { \ unsigned int n; \ \ for (n = 0; n < (count + 7) / 8; n++) { \ dst[n] |= src[n]; \ } \ } \ \ void \ name ## _set_and(unsigned char *dst, unsigned char *src) \ { \ unsigned int n; \ \ for (n = 0; n < (count + 7) / 8; n++) { \ dst[n] &= src[n]; \ } \ } \ \ void \ name ## _set_and_comp(unsigned char *dst, unsigned char *src) \ { \ unsigned int n; \ \ for (n = 0; n < (count + 7) / 8; n++) { \ dst[n] &= ~src[n]; \ } \ } \ \ void \ name ## _set_cp(unsigned char *dst, unsigned char *src) \ { \ unsigned int n; \ \ for (n = 0; n < (count + 7) / 8; n++) { \ dst[n] = src[n]; \ } \ } \ \ void \ name ## _set_empty(unsigned char *set) \ { \ unsigned int i; \ \ for (i = 0; i < (count + 7) / 8; i++) { \ set[i] = 0; \ } \ } \ \ void \ name ## _set_fill(unsigned char *set) \ { \ unsigned int i; \ \ for (i = 0; i < (count + 7) / 8; i++) { \ set[i] = -1; \ } \ } faucc-20120707/identifier.c0000640002413100241000000000402611137625346015006 0ustar potyrai3guest/* $Id: identifier.c,v 1.12 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include #include #include "identifier.h" struct identifier { struct identifier *prev; struct identifier *next; const char *string; }; static struct identifier *hash_first[IDENTIFIER_HASH_SIZE]; static struct identifier *hash_last[IDENTIFIER_HASH_SIZE]; unsigned int identifier_hash(const char *_n) { const unsigned char *n = (const unsigned char *) _n; unsigned int sum; while (*n == '_') { n++; } sum = 0; while (*n) { if ('0' <= *n && *n <= '9') { sum *= 10; sum += *n - '0'; } else { sum <<= 5; sum += *n & 0x1f; } n++; } sum %= IDENTIFIER_HASH_SIZE; return sum; } const char * identifier_new(const char *n) { struct identifier *id; unsigned int hash; hash = identifier_hash(n); for (id = hash_first[hash]; ; id = id->next) { if (! id) { /* New entry. */ id = malloc(sizeof(*id)); assert(id); id->string = strdup(n); assert(id->string); id->prev = hash_last[hash]; id->next = NULL; if (id->prev) { id->prev->next = id; } else { hash_first[hash] = id; } hash_last[hash] = id; break; } if (strcmp(n, id->string) == 0) { /* Entry found. */ break; } } return id->string; } const char * identifier_tmp(void) { static unsigned int count = 0; char name[20]; sprintf(name, "__%u", count++); return identifier_new(name); } int identifier_is_tmp(const char *name) { unsigned int i; if (name[0] != '_') return 0; if (name[1] != '_') return 0; for (i = 2; name[i]; i++) { if (! isdigit(name[i])) return 0; } return 1; } const char * identifier_dup(const char *n) { return n; } void identifier_free(const char *n) { } faucc-20120707/Makefile.am0000640002413100241000000000257111721457410014551 0ustar potyrai3guest# # $Id: Makefile.am,v 1.16 2012-02-23 15:45:12 vrsieh Exp $ # # Copyright (C) 2008-2009 FAUcc Team. # This program is free software, GPL-2 (or any later version). See COPYING. # SUBDIRS = \ . \ libfaucc \ docs/man fauccdir = $(libdir)/faucc bin_PROGRAMS = faucc faucc_PROGRAMS = cc1 faucc_SOURCES = faucc.c cc1_SOURCES = parse.y \ scan.l \ identifier.c \ label.c \ constraint.c \ declaration.c \ stmt.c \ expr.c \ scope.c \ print.c \ visitor.c \ simplify.c \ type.c \ arch_i386_gen.c \ arch_i286_gen.c \ regalloc.c \ cc1.c # Make sure that parse.[ch] will get built before anything else gets compiled. BUILT_SOURCES = config.h parse.c parse.h CLEANFILES = \ $(BUILT_SOURCES) \ scan.c # remove config.h on make distclean DISTCLEANFILES = config.h config.h: Makefile.am echo '#define FAUCCDIR "'$(fauccdir)'"' > config.h parse.c: parse.y bison -d parse.y mv parse.tab.c parse.c mv parse.tab.h parse.h parse.h: parse.c devel: $(top_srcdir)/scripts/install_ln.sh $(MAKE) install INSTALL=$(CURDIR)/$(top_srcdir)/scripts/install_ln.sh mrproper: distclean find . -name Makefile.in -delete $(RM) -r autom4te.cache/ $(RM) scripts/depcomp $(RM) scripts/install-sh $(RM) scripts/missing $(RM) scripts/ylwrap $(RM) aclocal.m4 $(RM) configure $(RM) INSTALL # run cppcheck cppcheck: $(CPPCHECK) -j 4 -q --enable=style $(top_srcdir) .PHONY: devel mrproper cppcheck faucc-20120707/print.c0000640002413100241000000006040511721157634014022 0ustar potyrai3guest/* $Id: print.c,v 1.125 2012-02-22 12:29:16 vrsieh Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include "declaration.h" #include "scope.h" #include "expr.h" #include "stmt.h" #include "cc1.h" /*forward*/ static void print_expr(FILE *fp, struct expr *e); /*forward*/ static void print_type_spec(FILE *fp, int level, struct type *t); /*forward*/ static void print_type(FILE *fp, int level, struct type *t); /*forward*/ static void print_declarator(FILE *fp, int level, struct declaration *d); /*forward*/ void print_declaration(FILE *fp, int, struct declaration *); static int print_newline(FILE *fp, int sol) { if (! sol) { fprintf(fp, "\n"); sol = 1; } return sol; } static int print_indent(FILE *fp, int sol, int level) { unsigned int i; if (sol) { for (i = 0; i < level; i++) { fprintf(fp, "\t"); } } else { fprintf(fp, " "); } return 0; } static void print_offsetof_member_designator(FILE *fp, struct expr *e) { switch (e->type) { case EXPR_ARROW: fprintf(fp, "%s", e->member); break; case EXPR_DOT: print_offsetof_member_designator(fp, e->expr0); fprintf(fp, "."); fprintf(fp, "%s", e->member); break; case EXPR_ARRAY: print_offsetof_member_designator(fp, e->expr0); fprintf(fp, "["); print_expr(fp, e->expr1); fprintf(fp, "]"); break; default: assert(0); } } static void print_string(FILE *fp, unsigned int len, const char *_str) { const unsigned char *str = (const unsigned char *) _str; unsigned int i; for (i = 0; i < len; i++) { switch (*str) { case '\0': fprintf(fp, "\\0"); break; case '\a': fprintf(fp, "\\a"); break; case '\b': fprintf(fp, "\\b"); break; case '\n': fprintf(fp, "\\n"); break; case '\r': fprintf(fp, "\\r"); break; case '\t': fprintf(fp, "\\t"); break; case '"': fprintf(fp, "\\\""); break; case '\\': fprintf(fp, "\\\\"); break; default: if (32 <= *str && *str <= 127) { fprintf(fp, "%c", *str); } else { fprintf(fp, "\\%03o", *str); } break; } str++; } } static void print_expr(FILE *fp, struct expr *e) { struct expr *e1; switch (e->type) { case EXPR_NONE: assert(0); case EXPR_INTEGER: switch (e->type_name->type) { case TYPE_INT8: fprintf(fp, "0x%x", (char) e->integer); break; case TYPE_UINT8: fprintf(fp, "0x%xU", (unsigned char) e->integer); break; case TYPE_INT16: fprintf(fp, "0x%x", (short) e->integer); break; case TYPE_UINT16: fprintf(fp, "0x%xU", (unsigned short) e->integer); break; case TYPE_INT32: fprintf(fp, "0x%x", (int) e->integer); break; case TYPE_UINT32: fprintf(fp, "0x%xU", (unsigned int) e->integer); break; case TYPE_INT64: fprintf(fp, "0x%llxLL", (long long) e->integer); break; case TYPE_UINT64: fprintf(fp, "0x%llxULL", e->integer); break; default: fprintf(stderr, "type_name->type=%d\n", e->type_name->type); assert(0); } break; case EXPR_REAL: fprintf(fp, "%e", (double) e->real); break; case EXPR_STRING: fprintf(fp, "\""); print_string(fp, e->string_len, e->string); fprintf(fp, "\""); break; case EXPR_IDENTIFIER: fprintf(fp, "%s", e->declaration->identifier); break; case EXPR_BRACES: fprintf(fp, "{"); for (e1 = e->first; e1; e1 = e1->next) { fprintf(fp, " "); print_expr(fp, e1); if (e1->next) { fprintf(fp, ","); } } fprintf(fp, " }"); break; case EXPR_SIZEOF_TYPE: fprintf(fp, "sizeof ("); print_type(fp, -1, e->type_name); fprintf(fp, ")"); break; case EXPR_SIZEOF_EXPR: fprintf(fp, "sizeof "); print_expr(fp, e->expr0); break; case EXPR_BUILTIN_CONSTANT_P: fprintf(fp, "__builtin_constant_p("); print_expr(fp, e->expr0); fprintf(fp, ")"); break; case EXPR_BUILTIN_OFFSETOF: fprintf(fp, "__builtin_offsetof("); print_type(fp, -1, e->type_name); fprintf(fp, ", "); print_offsetof_member_designator(fp, e->expr0); fprintf(fp, ")"); break; case EXPR_BUILTIN_VA_ARG: fprintf(fp, "__builtin_va_arg("); print_expr(fp, e->expr0); fprintf(fp, ", "); print_type(fp, -1, e->type_name); fprintf(fp, ")"); break; case EXPR_TYPE_CONVERSION: fprintf(fp, "("); print_type(fp, -1, e->type_name); fprintf(fp, ") "); print_expr(fp, e->expr0); break; case EXPR_STAR: fprintf(fp, "*"); print_expr(fp, e->expr0); break; case EXPR_AMPHERSAND: fprintf(fp, "&"); print_expr(fp, e->expr0); break; case EXPR_PRE_INC: fprintf(fp, "++"); print_expr(fp, e->expr0); break; case EXPR_PRE_DEC: fprintf(fp, "--"); print_expr(fp, e->expr0); break; case EXPR_POST_INC: print_expr(fp, e->expr0); fprintf(fp, "++"); break; case EXPR_POST_DEC: print_expr(fp, e->expr0); fprintf(fp, "--"); break; case EXPR_NEG: fprintf(fp, "-"); print_expr(fp, e->expr0); break; case EXPR_INV: fprintf(fp, "~"); print_expr(fp, e->expr0); break; case EXPR_NOT: fprintf(fp, "! "); print_expr(fp, e->expr0); break; case EXPR_LEFT: print_expr(fp, e->expr0); fprintf(fp, " << "); print_expr(fp, e->expr1); break; case EXPR_RIGHT: print_expr(fp, e->expr0); fprintf(fp, " >> "); print_expr(fp, e->expr1); break; case EXPR_EQUAL: print_expr(fp, e->expr0); fprintf(fp, " == "); print_expr(fp, e->expr1); break; case EXPR_NOT_EQUAL: print_expr(fp, e->expr0); fprintf(fp, " != "); print_expr(fp, e->expr1); break; case EXPR_LESS: print_expr(fp, e->expr0); fprintf(fp, " < "); print_expr(fp, e->expr1); break; case EXPR_GREATER: print_expr(fp, e->expr0); fprintf(fp, " > "); print_expr(fp, e->expr1); break; case EXPR_LESS_EQUAL: print_expr(fp, e->expr0); fprintf(fp, " <= "); print_expr(fp, e->expr1); break; case EXPR_GREATER_EQUAL: print_expr(fp, e->expr0); fprintf(fp, " >= "); print_expr(fp, e->expr1); break; case EXPR_ADD: print_expr(fp, e->expr0); fprintf(fp, " + "); print_expr(fp, e->expr1); break; case EXPR_SUB: print_expr(fp, e->expr0); fprintf(fp, " - "); print_expr(fp, e->expr1); break; case EXPR_MUL: print_expr(fp, e->expr0); fprintf(fp, " * "); print_expr(fp, e->expr1); break; case EXPR_DIV: print_expr(fp, e->expr0); fprintf(fp, " / "); print_expr(fp, e->expr1); break; case EXPR_MOD: print_expr(fp, e->expr0); fprintf(fp, " %% "); print_expr(fp, e->expr1); break; case EXPR_AND: print_expr(fp, e->expr0); fprintf(fp, " & "); print_expr(fp, e->expr1); break; case EXPR_OR: print_expr(fp, e->expr0); fprintf(fp, " | "); print_expr(fp, e->expr1); break; case EXPR_XOR: print_expr(fp, e->expr0); fprintf(fp, " ^ "); print_expr(fp, e->expr1); break; case EXPR_SHORT_OR: print_expr(fp, e->expr0); fprintf(fp, " || "); print_expr(fp, e->expr1); break; case EXPR_SHORT_AND: print_expr(fp, e->expr0); fprintf(fp, " && "); print_expr(fp, e->expr1); break; case EXPR_LIST: for (e1 = e->first; e1; e1 = e1->next) { print_expr(fp, e1); if (e1->next) { fprintf(fp, ", "); } } break; case EXPR_DOT: print_expr(fp, e->expr0); fprintf(fp, "."); fprintf(fp, "%s", e->member); break; case EXPR_ARROW: print_expr(fp, e->expr0); fprintf(fp, "->"); fprintf(fp, "%s", e->member); break; case EXPR_ARRAY: print_expr(fp, e->expr0); fprintf(fp, "["); print_expr(fp, e->expr1); fprintf(fp, "]"); break; case EXPR_FUNC: print_expr(fp, e->expr0); fprintf(fp, "("); if (e->expr1) { print_expr(fp, e->expr1); } fprintf(fp, ")"); break; case EXPR_CONDITION: print_expr(fp, e->expr0); fprintf(fp, " ? "); print_expr(fp, e->expr1); fprintf(fp, " : "); print_expr(fp, e->expr2); break; case EXPR_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " = "); print_expr(fp, e->expr1); break; case EXPR_LEFT_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " <<= "); print_expr(fp, e->expr1); break; case EXPR_RIGHT_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " >>= "); print_expr(fp, e->expr1); break; case EXPR_ADD_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " += "); print_expr(fp, e->expr1); break; case EXPR_SUB_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " -= "); print_expr(fp, e->expr1); break; case EXPR_MUL_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " *= "); print_expr(fp, e->expr1); break; case EXPR_DIV_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " /= "); print_expr(fp, e->expr1); break; case EXPR_MOD_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " %%= "); print_expr(fp, e->expr1); break; case EXPR_AND_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " &= "); print_expr(fp, e->expr1); break; case EXPR_OR_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " |= "); print_expr(fp, e->expr1); break; case EXPR_XOR_ASSIGN: print_expr(fp, e->expr0); fprintf(fp, " ^= "); print_expr(fp, e->expr1); break; } } int print_stmt(FILE *fp, int sol, int level, struct stmt *s) { struct declaration *d; struct stmt *s1; #if 0 if (s->reachable) { fprintf(fp, "*"); } #endif switch (s->type) { case STMT_NONE: assert(0); case STMT_NULL: sol = print_indent(fp, sol, level); fprintf(fp, ";"); break; case STMT_LABEL: sol = print_newline(fp, sol); sol = print_indent(fp, sol, level - 1); fprintf(fp, "%s:", s->label->identifier); sol = 0; sol = print_newline(fp, sol); sol = print_stmt(fp, sol, level, s->stmt0); break; case STMT_CASE: sol = print_newline(fp, sol); sol = print_indent(fp, sol, level - 1); fprintf(fp, "case "); print_expr(fp, s->expr0); fprintf(fp, ":"); sol = 0; sol = print_newline(fp, sol); sol = print_stmt(fp, sol, level, s->stmt0); break; case STMT_DEFAULT: sol = print_newline(fp, sol); sol = print_indent(fp, sol, level - 1); fprintf(fp, "default:"); sol = 0; sol = print_newline(fp, sol); sol = print_stmt(fp, sol, level, s->stmt0); break; case STMT_EXPR: sol = print_indent(fp, sol, level); print_expr(fp, s->expr0); fprintf(fp, ";"); break; case STMT_IF: sol = print_indent(fp, sol, level); fprintf(fp, "if ("); print_expr(fp, s->expr0); fprintf(fp, ")"); sol = print_stmt(fp, sol, level, s->stmt0); if (s->stmt1) { sol = print_indent(fp, sol, level); fprintf(fp, "else"); sol = 0; sol = print_stmt(fp, sol, level, s->stmt1); } break; case STMT_SWITCH: sol = print_indent(fp, sol, level); fprintf(fp, "switch ("); print_expr(fp, s->expr0); fprintf(fp, ")"); sol = 0; sol = print_stmt(fp, sol, level, s->stmt0); break; case STMT_WHILE: sol = print_indent(fp, sol, level); fprintf(fp, "while ("); print_expr(fp, s->expr0); fprintf(fp, ")"); sol = 0; sol = print_stmt(fp, sol, level, s->stmt0); break; case STMT_DO_WHILE: sol = print_indent(fp, sol, level); fprintf(fp, "do"); sol = print_stmt(fp, sol, level, s->stmt0); sol = print_indent(fp, sol, level); fprintf(fp, "while ("); print_expr(fp, s->expr0); fprintf(fp, ");"); sol = 0; break; case STMT_FOR: sol = print_indent(fp, sol, level); fprintf(fp, "for ("); if (s->expr0) { print_expr(fp, s->expr0); } fprintf(fp, "; "); if (s->expr1) { print_expr(fp, s->expr1); } fprintf(fp, "; "); if (s->expr2) { print_expr(fp, s->expr2); } fprintf(fp, ")"); sol = 0; sol = print_stmt(fp, sol, level, s->stmt0); break; case STMT_GOTO: sol = print_indent(fp, sol, level); fprintf(fp, "goto %s;", s->label->identifier); sol = 0; break; case STMT_CONTINUE: sol = print_indent(fp, sol, level); fprintf(fp, "continue;"); sol = 0; break; case STMT_BREAK: sol = print_indent(fp, sol, level); fprintf(fp, "break;"); sol = 0; break; case STMT_RETURN: sol = print_indent(fp, sol, level); if (s->expr0) { fprintf(fp, "return "); print_expr(fp, s->expr0); fprintf(fp, ";"); } else { fprintf(fp, "return;"); } sol = 0; break; case STMT_ASM: sol = print_indent(fp, sol, level); fprintf(fp, "asm ("); sol = 0; sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, "\""); print_string(fp, s->code_len, s->code); fprintf(fp, "\""); sol = 0; if (s->output->first || s->input->first || s->change->first) { struct constraint *c; sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, ":"); sol = 0; for (c = s->output->first; c; c = c->next) { fprintf(fp, " \"%s\" (", c->string); print_expr(fp, c->expr); fprintf(fp, ")"); if (c->next) { fprintf(fp, ","); } } } if (s->input->first || s->change->first) { struct constraint *c; sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, ":"); sol = 0; for (c = s->input->first; c; c = c->next) { fprintf(fp, " \"%s\" (", c->string); print_expr(fp, c->expr); fprintf(fp, ")"); if (c->next) { fprintf(fp, ","); } } } if (s->change->first) { struct constraint *c; sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, ":"); sol = 0; for (c = s->change->first; c; c = c->next) { fprintf(fp, " \"%s\"", c->string); if (c->next) { fprintf(fp, ","); } } } sol = print_newline(fp, sol); sol = print_indent(fp, sol, level); fprintf(fp, ");"); sol = 0; break; case STMT_VA_START: sol = print_indent(fp, sol, level); fprintf(fp, "__builtin_va_start("); print_expr(fp, s->expr0); fprintf(fp, ", "); print_expr(fp, s->expr1); fprintf(fp, ");"); sol = 0; break; case STMT_VA_END: sol = print_indent(fp, sol, level); fprintf(fp, "__builtin_va_end("); print_expr(fp, s->expr0); fprintf(fp, ");"); sol = 0; break; case STMT_BLOCK: sol = print_indent(fp, sol, level); fprintf(fp, "{"); sol = 0; sol = print_newline(fp, sol); for (d = s->scope->declaration_first; d; d = d->next) { print_declaration(fp, level + 1, d); } if (s->scope->declaration_first && s->stmt_first) { fprintf(fp, "\n"); sol = 1; } for (s1 = s->stmt_first; s1; s1 = s1->next) { sol = print_stmt(fp, sol, level + 1, s1); sol = print_newline(fp, sol); } sol = print_indent(fp, sol, level); fprintf(fp, "}"); sol = 0; break; default: assert(0); } if (s->type != STMT_ASM && s->output) { if (s->output->first || s->input->first || s->change->first) { struct constraint *c; sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, ":"); sol = 0; for (c = s->output->first; c; c = c->next) { fprintf(fp, " \"%s\" (", c->string); print_expr(fp, c->expr); fprintf(fp, ")"); if (c->next) { fprintf(fp, ","); } } } if (s->input->first || s->change->first) { struct constraint *c; sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, ":"); sol = 0; for (c = s->input->first; c; c = c->next) { fprintf(fp, " \"%s\" (", c->string); print_expr(fp, c->expr); fprintf(fp, ")"); if (c->next) { fprintf(fp, ","); } } } if (s->change->first) { struct constraint *c; sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, ":"); sol = 0; for (c = s->change->first; c; c = c->next) { fprintf(fp, " \"%s\"", c->string); if (c->next) { fprintf(fp, ","); } } } } #if 0 { struct decl_live *l; sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, "live:"); sol = 0; for (l = s->decl_live_first[0]; l; l = l->next) { fprintf(fp, " %s", l->decl->identifier); } sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, "read:"); sol = 0; for (l = s->decl_read_first; l; l = l->next) { fprintf(fp, " %s", l->decl->identifier); } sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, "write:"); sol = 0; for (l = s->decl_write_first; l; l = l->next) { fprintf(fp, " %s", l->decl->identifier); } sol = print_newline(fp, sol); sol = print_indent(fp, sol, level + 1); fprintf(fp, "live:"); sol = 0; for (l = s->decl_live_first[1]; l; l = l->next) { fprintf(fp, " %s", l->decl->identifier); } } #endif return sol; } static void print_type_spec(FILE *fp, int level, struct type *t) { int sol; struct declaration *dion; unsigned int n; sol = 1; switch (t->type) { default: for (n = 0; n < t->mod_const; n++) { if (! sol) { fprintf(fp, " "); } fprintf(fp, "const"); sol = 0; } for (n = 0; n < t->mod_volatile; n++) { if (! sol) { fprintf(fp, " "); } fprintf(fp, "volatile"); sol = 0; } for (n = 0; n < t->attr_packed; n++) { if (! sol) { fprintf(fp, " "); } fprintf(fp, "__attribute__((__packed__))"); sol = 0; } break; break; case TYPE_POINTER: case TYPE_ARRAY: case TYPE_FUNCTION: break; } switch (t->type) { case TYPE_NONE: case TYPE_MAX: assert(0); case TYPE_ELIPSIS: if (! sol) { fprintf(fp, " "); } fprintf(fp, "..."); sol = 0; break; case TYPE_VA_LIST: if (! sol) { fprintf(fp, " "); } fprintf(fp, "__builtin_va_list"); sol = 0; break; case TYPE_VOID: if (! sol) { fprintf(fp, " "); } fprintf(fp, "void"); sol = 0; break; case TYPE_INT8: if (! sol) { fprintf(fp, " "); } if (opt_f_sizeof_char == 1) { fprintf(fp, "char"); } else { assert(0); } sol = 0; break; case TYPE_UINT8: if (! sol) { fprintf(fp, " "); } if (opt_f_sizeof_char == 1) { fprintf(fp, "unsigned char"); } else { assert(0); } sol = 0; break; case TYPE_INT16: if (! sol) { fprintf(fp, " "); } if (opt_f_sizeof_int == 2) { fprintf(fp, "int"); } else if (opt_f_sizeof_short_int == 2) { fprintf(fp, "short int"); } else { assert(0); } sol = 0; break; case TYPE_UINT16: if (! sol) { fprintf(fp, " "); } if (opt_f_sizeof_int == 2) { fprintf(fp, "unsigned int"); } else if (opt_f_sizeof_short_int == 2) { fprintf(fp, "unsigned short int"); } else { assert(0); } sol = 0; break; case TYPE_INT32: if (! sol) { fprintf(fp, " "); } if (opt_f_sizeof_int == 4) { fprintf(fp, "int"); } else if (opt_f_sizeof_long_int == 4) { fprintf(fp, "long int"); } else { assert(0); } sol = 0; break; case TYPE_UINT32: if (! sol) { fprintf(fp, " "); } if (opt_f_sizeof_int == 4) { fprintf(fp, "unsigned int"); } else if (opt_f_sizeof_long_int == 4) { fprintf(fp, "long unsigned int"); } else { assert(0); } sol = 0; break; case TYPE_INT64: if (! sol) { fprintf(fp, " "); } if (opt_f_sizeof_long_long_int == 8) { fprintf(fp, "long long int"); } else { assert(0); } sol = 0; break; case TYPE_UINT64: if (! sol) { fprintf(fp, " "); } if (opt_f_sizeof_long_long_int == 8) { fprintf(fp, "unsigned long long int"); } else { assert(0); } sol = 0; break; case TYPE_FLOAT32: if (! sol) { fprintf(fp, " "); } fprintf(fp, "float"); sol = 0; break; case TYPE_FLOAT64: if (! sol) { fprintf(fp, " "); } fprintf(fp, "double"); sol = 0; break; case TYPE_FLOAT80: if (! sol) { fprintf(fp, " "); } fprintf(fp, "long double"); sol = 0; break; case TYPE_STRUCT: if (! sol) { fprintf(fp, " "); } fprintf(fp, "struct"); sol = 0; if (t->identifier) { fprintf(fp, " %s", t->identifier); } if (t->scope && t->scope->declaration_first) { fprintf(fp, " {\n"); sol = 1; for (dion = t->scope->declaration_first; dion; dion = dion->next) { print_declaration(fp, level + 1, dion); sol = 1; } sol = print_indent(fp, sol, level); fprintf(fp, "}"); } break; case TYPE_UNION: if (! sol) { fprintf(fp, " "); } fprintf(fp, "union"); sol = 0; if (t->identifier) { fprintf(fp, " %s", t->identifier); } if (t->scope && t->scope->declaration_first) { fprintf(fp, " {\n"); sol = 1; for (dion = t->scope->declaration_first; dion; dion = dion->next) { print_declaration(fp, level + 1, dion); sol = 1; } sol = print_indent(fp, sol, level); fprintf(fp, "}"); } break; case TYPE_ENUM: if (! sol) { fprintf(fp, " "); } fprintf(fp, "enum"); sol = 0; if (t->identifier) { fprintf(fp, " %s", t->identifier); } if (t->scope) { fprintf(fp, " {\n"); sol = 1; for (dion = t->scope->declaration_first; dion; dion = dion->next) { sol = print_indent(fp, sol, level); print_declarator(fp, level + 1, dion); fprintf(fp, ","); sol = print_newline(fp, sol); } fprintf(fp, "}"); sol = 0; } break; case TYPE_POINTER: case TYPE_ARRAY: case TYPE_FUNCTION: print_type_spec(fp, level, t->declarator); break; } } static void print_abs_decl_prefix(FILE *fp, int level, struct type *d) { if (d->declarator) { print_abs_decl_prefix(fp, level, d->declarator); } switch (d->type) { default: break; case TYPE_POINTER: /* Hack... */ if (type_is_array(d->declarator) || type_is_function(d->declarator)) { fprintf(fp, "("); } fprintf(fp, "*"); if (d->mod_const) { fprintf(fp, " const"); } if (d->mod_volatile) { fprintf(fp, " volatile"); } if (d->mod_const || d->mod_volatile) { fprintf(fp, " "); } break; case TYPE_ARRAY: break; case TYPE_FUNCTION: break; } } static void print_abs_decl_suffix(FILE *fp, int level, struct type *d) { struct declaration *p; switch (d->type) { default: break; case TYPE_POINTER: /* Hack... */ if (type_is_array(d->declarator) || type_is_function(d->declarator)) { fprintf(fp, ")"); } break; case TYPE_ARRAY: fprintf(fp, "["); if (d->dimension) { print_expr(fp, d->dimension); } fprintf(fp, "]"); break; case TYPE_FUNCTION: fprintf(fp, "("); for (p = d->parameter->declaration_first; p; p = p->next) { print_declaration(fp, -1, p); if (p->next) { fprintf(fp, ", "); } } fprintf(fp, ")"); break; } if (d->declarator) { print_abs_decl_suffix(fp, level, d->declarator); } } static void print_declarator(FILE *fp, int level, struct declaration *d) { print_abs_decl_prefix(fp, level, d->type_name); if (d->identifier) { fprintf(fp, "%s", d->identifier); } print_abs_decl_suffix(fp, level, d->type_name); if (d->regname) { fprintf(fp, " asm(\"%s\")", d->regname); } else if (d->storage_register != -1) { fprintf(fp, " asm(\"%d\")", d->storage_register); } if (d->nbits) { fprintf(fp, " : "); print_expr(fp, d->nbits); } if (declaration_initializer_get(d)) { fprintf(fp, " = "); print_expr(fp, declaration_initializer_get(d)); } } static void print_type(FILE *fp, int level, struct type *ad) { print_type_spec(fp, level, ad); fprintf(fp, " "); print_abs_decl_prefix(fp, level, ad); print_abs_decl_suffix(fp, level, ad); } static int isfunc(struct declaration *d) { if (d->stmt) { return 1; } else { return 0; } } static void print_storage(FILE *fp, enum type_storage storage) { switch (storage) { case STORAGE_NONE: case STORAGE_PARAM: break; case STORAGE_AUTO: /* No need to print 'auto' keyword. */ break; case STORAGE_STATIC: fprintf(fp, "static "); break; case STORAGE_TYPEDEF: fprintf(fp, "typedef "); break; case STORAGE_REGISTER: fprintf(fp, "register "); break; case STORAGE_EXTERN: fprintf(fp, "extern "); break; default: assert(0); } } static void print_attr(FILE *fp, unsigned int mod_inline, unsigned int attr_noreturn) { if (mod_inline) { fprintf(fp, "inline "); } if (attr_noreturn) { fprintf(fp, "__attribute__((__noreturn__)) "); } } void print_declaration(FILE *fp, int level, struct declaration *d) { if (d->storage == STORAGE_ASM) { fprintf(fp, "asm (\"%s\");\n", d->code); } else if (isfunc(d)) { print_storage(fp, d->storage); print_attr(fp, d->mod_inline, d->attr_noreturn); print_type_spec(fp, level, d->type_name); fprintf(fp, "\n"); print_declarator(fp, level, d); fprintf(fp, "\n"); print_stmt(fp, 1, 0, d->stmt); fprintf(fp, "\n"); fprintf(fp, "\n"); } else { if (0 <= level) { print_indent(fp, 1, level); } print_storage(fp, d->storage); print_attr(fp, d->mod_inline, d->attr_noreturn); print_type_spec(fp, level, d->type_name); fprintf(fp, " "); print_declarator(fp, level, d); if (0 <= level) { fprintf(fp, ";\n"); } } } void print(FILE *fp, struct scope *s) { struct declaration *d; for (d = s->declaration_first; d; d = d->next) { print_declaration(fp, 0, d); } } faucc-20120707/declaration.c0000640002413100241000000000372011721457410015143 0ustar potyrai3guest/* $Id: declaration.c,v 1.183 2012-02-23 15:45:12 vrsieh Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include #include "setup.h" #include "identifier.h" #include "declaration.h" #include "expr.h" #include "stmt.h" #include "cc1.h" void declaration_rename_structunionenum( struct declaration *dion, enum type_type type, const char *old, const char *new ) { struct expr *initializer; type_rename_structunionenum(dion->type_name, type, old, new); initializer = declaration_initializer_get(dion); if (initializer) { expr_rename_structunionenum(initializer, type, old, new); } } void declaration_rename_type( struct declaration *dion, const char *old, const char *new ) { type_rename_type(dion->type_name, old, new); } struct declaration * declaration_new(void) { struct declaration *d; d = malloc(sizeof(*d)); assert(d); memset(d, 0, sizeof(*d)); return d; } void declaration_name_set(struct declaration *d, const char *name) { d->identifier = name; } const char * declaration_name_get(struct declaration *d) { return d->identifier; } void declaration_type_get(struct type **adp, struct declaration *dor) { *adp = dor->type_name; } void declaration_initializer_set(struct declaration *dor, struct expr *initializer) { dor->initializer = initializer; } struct expr * declaration_initializer_get(struct declaration *dor) { return dor->initializer; } struct declaration * declaration_identifier(const char *name) { struct declaration *dor; dor = malloc(sizeof(*dor)); assert(dor); memset(dor, 0, sizeof(*dor)); dor->identifier = name; dor->type_name = type_type_spec(); return dor; } void declaration_free(struct declaration *dor) { } faucc-20120707/stmt.h0000640002413100241000000002645611137625346013673 0ustar potyrai3guest/* $Id: stmt.h,v 1.46 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __STMT_H_INCLUDED #define __STMT_H_INCLUDED #include "scope.h" #include "expr.h" #include "constraint.h" #include "label.h" /* * Types */ struct stmt { struct stmt *prev; struct stmt *next; struct stmt *hash_prev; struct stmt *hash_next; struct stmt *ref_prev; struct stmt *ref_next; struct stmt *def_prev; struct stmt *def_next; enum { STMT_NONE, STMT_NULL, STMT_LABEL, STMT_CASE, STMT_DEFAULT, STMT_EXPR, STMT_IF, STMT_SWITCH, STMT_WHILE, STMT_DO_WHILE, STMT_FOR, STMT_GOTO, STMT_CONTINUE, STMT_BREAK, STMT_RETURN, STMT_ASM, STMT_VA_START, STMT_VA_END, STMT_BLOCK, STMT_ASM_LABEL, STMT_ASM_GOTO, STMT_ASM_IF, STMT_ASM_SWITCH, STMT_ASM_RETURN, STMT_ASM_ADDRESS_GLOBAL, STMT_ASM_ADDRESS_LOCAL, STMT_ASM_ASSIGN_INT8_INT8, STMT_ASM_ASSIGN_INT8_UINT8, STMT_ASM_ASSIGN_INT8_INT16, STMT_ASM_ASSIGN_INT8_UINT16, STMT_ASM_ASSIGN_INT8_INT32, STMT_ASM_ASSIGN_INT8_UINT32, STMT_ASM_ASSIGN_INT8_INT64, STMT_ASM_ASSIGN_INT8_UINT64, STMT_ASM_ASSIGN_INT8_FLOAT32, STMT_ASM_ASSIGN_INT8_FLOAT64, STMT_ASM_ASSIGN_INT8_FLOAT80, STMT_ASM_ASSIGN_UINT8_INT8, STMT_ASM_ASSIGN_UINT8_UINT8, STMT_ASM_ASSIGN_UINT8_INT16, STMT_ASM_ASSIGN_UINT8_UINT16, STMT_ASM_ASSIGN_UINT8_INT32, STMT_ASM_ASSIGN_UINT8_UINT32, STMT_ASM_ASSIGN_UINT8_INT64, STMT_ASM_ASSIGN_UINT8_UINT64, STMT_ASM_ASSIGN_UINT8_FLOAT32, STMT_ASM_ASSIGN_UINT8_FLOAT64, STMT_ASM_ASSIGN_UINT8_FLOAT80, STMT_ASM_ASSIGN_INT16_INT8, STMT_ASM_ASSIGN_INT16_UINT8, STMT_ASM_ASSIGN_INT16_INT16, STMT_ASM_ASSIGN_INT16_UINT16, STMT_ASM_ASSIGN_INT16_INT32, STMT_ASM_ASSIGN_INT16_UINT32, STMT_ASM_ASSIGN_INT16_INT64, STMT_ASM_ASSIGN_INT16_UINT64, STMT_ASM_ASSIGN_INT16_FLOAT32, STMT_ASM_ASSIGN_INT16_FLOAT64, STMT_ASM_ASSIGN_INT16_FLOAT80, STMT_ASM_ASSIGN_UINT16_INT8, STMT_ASM_ASSIGN_UINT16_UINT8, STMT_ASM_ASSIGN_UINT16_INT16, STMT_ASM_ASSIGN_UINT16_UINT16, STMT_ASM_ASSIGN_UINT16_INT32, STMT_ASM_ASSIGN_UINT16_UINT32, STMT_ASM_ASSIGN_UINT16_INT64, STMT_ASM_ASSIGN_UINT16_UINT64, STMT_ASM_ASSIGN_UINT16_FLOAT32, STMT_ASM_ASSIGN_UINT16_FLOAT64, STMT_ASM_ASSIGN_UINT16_FLOAT80, STMT_ASM_ASSIGN_INT32_INT8, STMT_ASM_ASSIGN_INT32_UINT8, STMT_ASM_ASSIGN_INT32_INT16, STMT_ASM_ASSIGN_INT32_UINT16, STMT_ASM_ASSIGN_INT32_INT32, STMT_ASM_ASSIGN_INT32_UINT32, STMT_ASM_ASSIGN_INT32_INT64, STMT_ASM_ASSIGN_INT32_UINT64, STMT_ASM_ASSIGN_INT32_FLOAT32, STMT_ASM_ASSIGN_INT32_FLOAT64, STMT_ASM_ASSIGN_INT32_FLOAT80, STMT_ASM_ASSIGN_UINT32_INT8, STMT_ASM_ASSIGN_UINT32_UINT8, STMT_ASM_ASSIGN_UINT32_INT16, STMT_ASM_ASSIGN_UINT32_UINT16, STMT_ASM_ASSIGN_UINT32_INT32, STMT_ASM_ASSIGN_UINT32_UINT32, STMT_ASM_ASSIGN_UINT32_INT64, STMT_ASM_ASSIGN_UINT32_UINT64, STMT_ASM_ASSIGN_UINT32_FLOAT32, STMT_ASM_ASSIGN_UINT32_FLOAT64, STMT_ASM_ASSIGN_UINT32_FLOAT80, STMT_ASM_ASSIGN_INT64_INT8, STMT_ASM_ASSIGN_INT64_UINT8, STMT_ASM_ASSIGN_INT64_INT16, STMT_ASM_ASSIGN_INT64_UINT16, STMT_ASM_ASSIGN_INT64_INT32, STMT_ASM_ASSIGN_INT64_UINT32, STMT_ASM_ASSIGN_INT64_INT64, STMT_ASM_ASSIGN_INT64_UINT64, STMT_ASM_ASSIGN_INT64_FLOAT32, STMT_ASM_ASSIGN_INT64_FLOAT64, STMT_ASM_ASSIGN_INT64_FLOAT80, STMT_ASM_ASSIGN_UINT64_INT8, STMT_ASM_ASSIGN_UINT64_UINT8, STMT_ASM_ASSIGN_UINT64_INT16, STMT_ASM_ASSIGN_UINT64_UINT16, STMT_ASM_ASSIGN_UINT64_INT32, STMT_ASM_ASSIGN_UINT64_UINT32, STMT_ASM_ASSIGN_UINT64_INT64, STMT_ASM_ASSIGN_UINT64_UINT64, STMT_ASM_ASSIGN_UINT64_FLOAT32, STMT_ASM_ASSIGN_UINT64_FLOAT64, STMT_ASM_ASSIGN_UINT64_FLOAT80, STMT_ASM_ASSIGN_FLOAT32_INT8, STMT_ASM_ASSIGN_FLOAT32_UINT8, STMT_ASM_ASSIGN_FLOAT32_INT16, STMT_ASM_ASSIGN_FLOAT32_UINT16, STMT_ASM_ASSIGN_FLOAT32_INT32, STMT_ASM_ASSIGN_FLOAT32_UINT32, STMT_ASM_ASSIGN_FLOAT32_INT64, STMT_ASM_ASSIGN_FLOAT32_UINT64, STMT_ASM_ASSIGN_FLOAT32_FLOAT32, STMT_ASM_ASSIGN_FLOAT32_FLOAT64, STMT_ASM_ASSIGN_FLOAT32_FLOAT80, STMT_ASM_ASSIGN_FLOAT64_INT8, STMT_ASM_ASSIGN_FLOAT64_UINT8, STMT_ASM_ASSIGN_FLOAT64_INT16, STMT_ASM_ASSIGN_FLOAT64_UINT16, STMT_ASM_ASSIGN_FLOAT64_INT32, STMT_ASM_ASSIGN_FLOAT64_UINT32, STMT_ASM_ASSIGN_FLOAT64_INT64, STMT_ASM_ASSIGN_FLOAT64_UINT64, STMT_ASM_ASSIGN_FLOAT64_FLOAT32, STMT_ASM_ASSIGN_FLOAT64_FLOAT64, STMT_ASM_ASSIGN_FLOAT64_FLOAT80, STMT_ASM_ASSIGN_FLOAT80_INT8, STMT_ASM_ASSIGN_FLOAT80_UINT8, STMT_ASM_ASSIGN_FLOAT80_INT16, STMT_ASM_ASSIGN_FLOAT80_UINT16, STMT_ASM_ASSIGN_FLOAT80_INT32, STMT_ASM_ASSIGN_FLOAT80_UINT32, STMT_ASM_ASSIGN_FLOAT80_INT64, STMT_ASM_ASSIGN_FLOAT80_FLOAT32, STMT_ASM_ASSIGN_FLOAT80_FLOAT64, STMT_ASM_ASSIGN_FLOAT80_FLOAT80, STMT_ASM_LOAD_INT8, STMT_ASM_LOAD_UINT8, STMT_ASM_LOAD_INT16, STMT_ASM_LOAD_UINT16, STMT_ASM_LOAD_INT32, STMT_ASM_LOAD_UINT32, STMT_ASM_LOAD_INT64, STMT_ASM_LOAD_UINT64, STMT_ASM_LOAD_FLOAT32, STMT_ASM_LOAD_FLOAT64, STMT_ASM_LOAD_FLOAT80, STMT_ASM_STORE_INT8, STMT_ASM_STORE_UINT8, STMT_ASM_STORE_INT16, STMT_ASM_STORE_UINT16, STMT_ASM_STORE_INT32, STMT_ASM_STORE_UINT32, STMT_ASM_STORE_INT64, STMT_ASM_STORE_UINT64, STMT_ASM_STORE_FLOAT32, STMT_ASM_STORE_FLOAT64, STMT_ASM_STORE_FLOAT80, STMT_ASM_NEG_INT32, STMT_ASM_NEG_UINT32, STMT_ASM_NEG_INT64, STMT_ASM_NEG_UINT64, STMT_ASM_NEG_FLOAT64, STMT_ASM_NEG_FLOAT80, STMT_ASM_INV_INT32, STMT_ASM_INV_UINT32, STMT_ASM_INV_INT64, STMT_ASM_INV_UINT64, STMT_ASM_EQUAL_INT32, STMT_ASM_EQUAL_UINT32, STMT_ASM_EQUAL_INT64, STMT_ASM_EQUAL_UINT64, STMT_ASM_EQUAL_FLOAT64, STMT_ASM_EQUAL_FLOAT80, STMT_ASM_NOT_EQUAL_INT32, STMT_ASM_NOT_EQUAL_UINT32, STMT_ASM_NOT_EQUAL_INT64, STMT_ASM_NOT_EQUAL_UINT64, STMT_ASM_NOT_EQUAL_FLOAT64, STMT_ASM_NOT_EQUAL_FLOAT80, STMT_ASM_LESS_INT32, STMT_ASM_LESS_UINT32, STMT_ASM_LESS_INT64, STMT_ASM_LESS_UINT64, STMT_ASM_LESS_FLOAT64, STMT_ASM_LESS_FLOAT80, STMT_ASM_LESS_EQUAL_INT32, STMT_ASM_LESS_EQUAL_UINT32, STMT_ASM_LESS_EQUAL_INT64, STMT_ASM_LESS_EQUAL_UINT64, STMT_ASM_LESS_EQUAL_FLOAT64, STMT_ASM_LESS_EQUAL_FLOAT80, STMT_ASM_GREATER_INT32, STMT_ASM_GREATER_UINT32, STMT_ASM_GREATER_INT64, STMT_ASM_GREATER_UINT64, STMT_ASM_GREATER_FLOAT64, STMT_ASM_GREATER_FLOAT80, STMT_ASM_GREATER_EQUAL_INT32, STMT_ASM_GREATER_EQUAL_UINT32, STMT_ASM_GREATER_EQUAL_INT64, STMT_ASM_GREATER_EQUAL_UINT64, STMT_ASM_GREATER_EQUAL_FLOAT64, STMT_ASM_GREATER_EQUAL_FLOAT80, STMT_ASM_LEFT_INT32, STMT_ASM_LEFT_UINT32, STMT_ASM_LEFT_INT64, STMT_ASM_LEFT_UINT64, STMT_ASM_RIGHT_INT32, STMT_ASM_RIGHT_UINT32, STMT_ASM_RIGHT_INT64, STMT_ASM_RIGHT_UINT64, STMT_ASM_ADD_INT32, STMT_ASM_ADD_UINT32, STMT_ASM_ADD_INT64, STMT_ASM_ADD_UINT64, STMT_ASM_ADD_FLOAT64, STMT_ASM_ADD_FLOAT80, STMT_ASM_SUB_INT32, STMT_ASM_SUB_UINT32, STMT_ASM_SUB_INT64, STMT_ASM_SUB_UINT64, STMT_ASM_SUB_FLOAT64, STMT_ASM_SUB_FLOAT80, STMT_ASM_MUL_INT32, STMT_ASM_MUL_UINT32, STMT_ASM_MUL_INT64, STMT_ASM_MUL_UINT64, STMT_ASM_MUL_FLOAT64, STMT_ASM_MUL_FLOAT80, STMT_ASM_DIV_INT32, STMT_ASM_DIV_UINT32, STMT_ASM_DIV_INT64, STMT_ASM_DIV_UINT64, STMT_ASM_DIV_FLOAT64, STMT_ASM_DIV_FLOAT80, STMT_ASM_MOD_INT32, STMT_ASM_MOD_UINT32, STMT_ASM_MOD_INT64, STMT_ASM_MOD_UINT64, STMT_ASM_MOD_FLOAT64, STMT_ASM_MOD_FLOAT80, STMT_ASM_AND_INT32, STMT_ASM_AND_UINT32, STMT_ASM_AND_INT64, STMT_ASM_AND_UINT64, STMT_ASM_OR_INT32, STMT_ASM_OR_UINT32, STMT_ASM_OR_INT64, STMT_ASM_OR_UINT64, STMT_ASM_XOR_INT32, STMT_ASM_XOR_UINT32, STMT_ASM_XOR_INT64, STMT_ASM_XOR_UINT64, STMT_ASM_FUNC, } type; struct label *label; struct expr *expr0; struct expr *expr1; struct expr *expr2; struct stmt *stmt0; struct stmt *stmt1; unsigned int code_len; const char *code; struct constraint_list *output; struct constraint_list *input; struct constraint_list *change; struct stmt *stmt_first; struct stmt *stmt_last; struct scope *scope; int stmt_used; int label_used; struct decl_live *decl_write_first; struct decl_live *decl_write_last; struct decl_live *decl_read_first; struct decl_live *decl_read_last; struct decl_live *decl_live_first[2]; struct decl_live *decl_live_last[2]; int jit; /* FAUjitcc */ }; /* * Functions */ extern void stmt_rename_structunionenum( struct stmt *s, enum type_type type, const char *old, const char *new); extern void stmt_prepend_first( struct stmt *block, struct stmt *n0 ); extern void stmt_prepend( struct stmt *block, struct stmt *o0, struct stmt *n0 ); extern void stmt_append( struct stmt *block, struct stmt *o0, struct stmt *n0 ); extern void stmt_append_last( struct stmt *block, struct stmt *n0 ); extern void stmt_cp( struct stmt *o, struct stmt *n ); extern void stmt_replace_1_by_0( struct stmt *block, struct stmt *o0 ); extern void stmt_replace_1_by_1( struct stmt *block, struct stmt *o0, struct stmt *n0 ); extern void stmt_replace_1_by_2( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1 ); extern void stmt_replace_1_by_3( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2 ); extern void stmt_replace_1_by_4( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3 ); extern void stmt_replace_1_by_5( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3, struct stmt *n4 ); extern void stmt_replace_1_by_6( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3, struct stmt *n4, struct stmt *n5 ); extern void stmt_replace_1_by_7( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3, struct stmt *n4, struct stmt *n5, struct stmt *n6 ); extern void stmt_replace_1_by_8( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3, struct stmt *n4, struct stmt *n5, struct stmt *n6, struct stmt *n7 ); extern void stmt_replace_1_by_9( struct stmt *block, struct stmt *o0, struct stmt *n0, struct stmt *n1, struct stmt *n2, struct stmt *n3, struct stmt *n4, struct stmt *n5, struct stmt *n6, struct stmt *n7, struct stmt *n8 ); extern struct stmt * stmt_replace_2_by_1( struct stmt *block, struct stmt *o0, struct stmt *n0 ); extern struct stmt * stmt_new(void); extern struct stmt * stmt_dup(struct stmt *o); extern struct stmt * stmt_null(void); extern struct stmt * stmt_label(struct label *label, struct stmt *s0); extern struct stmt * stmt_expr(struct expr *e); extern struct stmt * stmt_if(struct expr *e, struct stmt *s0, struct stmt *s1); extern struct stmt * stmt_goto(struct label *label); extern struct stmt * stmt_return(struct expr *expr); extern void stmt_free(struct stmt *s); extern void stmt_opt_label_hashlist(struct stmt *fs); extern struct stmt * stmt_opt_label_lookup(struct label *label); extern int stmt_simplify_params(struct stmt *fs); extern int stmt_simplify_returns(struct stmt *fs); extern int stmt_simplify(struct stmt *fs); extern int stmt_optimize(struct stmt *fs); #endif /* ! __STMT_H_INCLUDED */ faucc-20120707/cc1.c0000640002413100241000000001473011773060146013332 0ustar potyrai3guest/* $Id: cc1.c,v 1.12 2012-06-28 13:47:18 vrsieh Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #if 1 #include #include #include #include #include #include "declaration.h" #include "print.h" #include "simplify.h" #include "print.h" #include "arch_i286_gen.h" #include "arch_i386_gen.h" #include "cc1.h" const char *progname; int opt_O; const char *opt_O_arg; enum target opt_b = TARGET_NONE; int opt_d; unsigned int opt_f_align_functions = 0; unsigned int opt_f_sizeof_char = 0; unsigned int opt_f_sizeof_short_int = 0; unsigned int opt_f_sizeof_int = 0; unsigned int opt_f_sizeof_long_int = 0; unsigned int opt_f_sizeof_long_long_int = 0; unsigned int opt_f_segment_enable = 0; const char *infile; const char *outfile; extern struct scope * parse(const char *in); static __attribute__((noreturn)) void usage(int retval) { fprintf(stderr, "Usage: %s [-O level] [-d] [-f compile-option] [-m machine-option] -b {i286,i386,...} < infile > outfile\n", progname); exit(retval); } int main(int argc, char **argv) { struct scope *s; int c; #if 0 for (c = 0; c < argc; c++) { fprintf(stderr, "%d: '%s'\n", c, argv[c]); } #endif /* Get Program Name */ progname = *argv; /* Get Options */ while ((c = getopt(argc, argv, "O:b:df:m:")) != -1) { switch (c) { case 'O': opt_O = 1; opt_O_arg = optarg; break; case 'b': if (strcmp(optarg, "i286") == 0) { opt_b = TARGET_I286; if (opt_f_sizeof_int == 0) { opt_f_sizeof_int = 2; } if (opt_f_sizeof_long_int == 0) { opt_f_sizeof_long_int = 4; } } else if (strcmp(optarg, "i386") == 0) { opt_b = TARGET_I386; if (opt_f_sizeof_int == 0) { opt_f_sizeof_int = 4; } if (opt_f_sizeof_long_int == 0) { opt_f_sizeof_long_int = 4; } } else { usage(1); } break; case 'd': opt_d = 1; break; case 'f': if (strncmp(optarg, "align-functions=", 16) == 0) { opt_f_align_functions = atoi(optarg + 16); } else if (strcmp(optarg, "omit-frame-pointer") == 0) { /* Ignore for now... */ } else if (strcmp(optarg, "no-inline-atomics") == 0) { /* Ignore for now... */ } else if (strcmp(optarg, "no-optimize-strlen") == 0) { /* Ignore for now... */ } else if (strcmp(optarg, "no-shrink-wrap") == 0) { /* Ignore for now... */ } else if (strcmp(optarg, "no-tree-tail-merge") == 0) { /* Ignore for now... */ } else if (strncmp(optarg, "sizeof_char=", 12) == 0) { opt_f_sizeof_char = atoi(optarg + 12); } else if (strncmp(optarg, "sizeof_short_int=", 17) == 0) { opt_f_sizeof_short_int = atoi(optarg + 17); } else if (strncmp(optarg, "sizeof_int=", 11) == 0) { opt_f_sizeof_int = atoi(optarg + 11); } else if (strncmp(optarg, "sizeof_long_int=", 16) == 0) { opt_f_sizeof_long_int = atoi(optarg + 16); } else if (strncmp(optarg, "sizeof_long_long_int=", 21) == 0) { opt_f_sizeof_long_long_int = atoi(optarg + 21); } else if (strcmp(optarg, "segment_enable") == 0) { opt_f_segment_enable = 1; } else if (strcmp(optarg, "strict-aliasing") == 0) { /* Ignore for now... */ } else { fprintf(stderr, "%s: WARNING: unknown compile option '-f %s'\n", progname, optarg); } break; case 'm': /* FIXME */ break; default: usage(1); /*NOTREACHED*/ } } argc -= optind; argv += optind; /* Fill defaults. */ if (opt_b == TARGET_NONE) { opt_b = TARGET_I386; if (opt_f_sizeof_int == 0) { opt_f_sizeof_int = 4; } if (opt_f_sizeof_long_int == 0) { opt_f_sizeof_long_int = 4; } } if (opt_f_align_functions == 0) { opt_f_align_functions = 1; } if (opt_f_sizeof_char == 0) { opt_f_sizeof_char = sizeof(char); } if (opt_f_sizeof_short_int == 0) { opt_f_sizeof_short_int = sizeof(short int); } if (opt_f_sizeof_int == 0) { opt_f_sizeof_int = sizeof(int); } if (opt_f_sizeof_long_int == 0) { opt_f_sizeof_long_int = sizeof(long int); } if (opt_f_sizeof_long_long_int == 0) { opt_f_sizeof_long_long_int = sizeof(long long int); } /* Check options. */ /* FIXME */ /* Get Parameter */ if (0 < argc) { infile = *argv; argv++; argc--; } else { usage(1); } if (0 < argc) { outfile = *argv; argv++; argc--; } else { usage(1); } /* Do Work */ s = parse(infile); simplify(s); switch (opt_b) { case TARGET_I286: arch_i286_gen(outfile, s); break; case TARGET_I386: default: arch_i386_gen(outfile, s); break; } return 0; } #else #include #include #include const char *progname; const char *input; int main(int argc, char **argv) { static struct { const char *name; const char *value; } foption[] = { { "-ftarget", NULL }, { "-fsizeof_char", NULL }, { "-fsizeof_short", NULL }, { "-fsizeof_int", NULL }, { "-fsizeof_long", NULL }, { "-fsizeof_long_long", NULL }, { "-fstack-protector", NULL }, { "-mtune", NULL }, { NULL, NULL } }; static struct { const char *name; unsigned int value; } option[] = { { "-quiet", 0 }, { NULL, 0 } }; static struct { const char *name; const char *value; } poption[] = { { "-auxbase", NULL }, { "-dumpbase", NULL }, { "-o", NULL }, { NULL, NULL } }; unsigned int i; unsigned int o; #if 1 fprintf(stderr, "%s", argv[0]); for (i = 1; i < argc; i++) { fprintf(stderr, " %s", argv[i]); } fprintf(stderr, "\n"); #endif progname = *argv; for (i = 1; i < argc; i++) { for (o = 0; foption[o].name; o++) { if (strncmp(argv[i], foption[o].name, strlen(foption[o].name)) == 0 && argv[i][strlen(foption[o].name)] == '\0') { foption[o].value = "1"; goto found; } else if (strncmp(argv[i], foption[o].name, strlen(foption[o].name)) == 0 && argv[i][strlen(foption[o].name)] == '=') { foption[o].value = &argv[i][strlen(foption[o].name) + 1]; goto found; } } for (o = 0; option[o].name; o++) { if (strcmp(argv[i], option[o].name) == 0) { option[o].value = 1; goto found; } } for (o = 0; poption[o].name; o++) { if (strcmp(argv[i], poption[o].name) == 0) { poption[o].value = argv[++i]; goto found; } } if (argv[i][0] == '-') { fprintf(stderr, "Option %s unknown.\n", argv[i]); assert(0); } input = argv[i]; found: ; } fprintf(stderr, "Compiling %s.\n", input); return 0; } #endif faucc-20120707/faucc.c0000640002413100241000000003324411717461564013755 0ustar potyrai3guest/* $Id: faucc.c,v 1.40 2012-02-17 14:25:56 vrsieh Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include "config.h" #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include const char *progname; const char *opt_B = FAUCCDIR; int opt_E; int opt_S; int opt_c; int opt_o; const char *opt_o_arg; const char *input[256]; unsigned int ninputs; const char *output[256]; unsigned int noutputs; const char *cpp_param[256]; unsigned int ncpp_params; const char *cc1_param[256]; unsigned int ncc1_params; const char *as_param[256]; unsigned int nas_params; const char *ld_param[256]; unsigned int nld_params; /* * Possible race condition!!! FIXME */ static void tmpname(char *buf, const char *suffix) { struct stat st; unsigned int i; int ret; for (i = 0; ; i++) { sprintf(buf, "/tmp/faucc.%u.%u.%s", (unsigned int) getpid(), i, suffix); ret = lstat(buf, &st); if (ret < 0 && errno == ENOENT) { break; } } } static void debug(const char *file, const char **param) { #if 0 fprintf(stderr, "%s", file); while (*param) { fprintf(stderr, " %s", *param++); } fprintf(stderr, "\n"); #endif } static void exit_status(const char *prog, int status) { if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { fprintf(stderr, "%s: %s: exit status %u.\n", progname, prog, WEXITSTATUS(status)); } } else if (WIFSIGNALED(status)) { fprintf(stderr, "%s: %s: %s", progname, prog, strsignal(WTERMSIG(status))); if (WCOREDUMP(status)) { fprintf(stderr, " (core dumped)"); } fprintf(stderr, "\n"); } } static int cpp(const char *in, const char *out) { int pid; int status; int ret; cpp_param[ncpp_params++] = in; cpp_param[ncpp_params] = NULL; switch (pid = fork()) { case -1: assert(0); case 0: if (strcmp(out, "") != 0) { ret = close(1); assert(0 <= ret); ret = open(out, O_CREAT | O_TRUNC | O_WRONLY, 0666); assert(0 <= ret); assert(ret == 1); } debug("cpp", cpp_param); execvp("cpp", cpp_param); assert(0); default: ret = wait(&status); assert(0 <= ret); exit_status("cpp", status); break; } return 0; } static int cc1(const char *in, const char *out) { int pid; char path[1024]; int status; int ret; cc1_param[ncc1_params++] = in; cc1_param[ncc1_params++] = out; cc1_param[ncc1_params] = NULL; switch (pid = fork()) { case -1: assert(0); case 0: strcpy(path, opt_B); strcat(path, "/cc1"); debug(path, cc1_param); execvp(path, cc1_param); assert(0); default: ret = wait(&status); assert(0 <= ret); exit_status("cc1", status); break; } return 0; } static int as(const char *in, const char *out) { int pid; int status; int ret; as_param[nas_params++] = "-c"; as_param[nas_params++] = "-o"; as_param[nas_params++] = out; as_param[nas_params++] = in; as_param[nas_params] = NULL; switch (pid = fork()) { case -1: assert(0); case 0: ret = close(0); assert(0 <= ret); ret = open(in, O_RDONLY); assert(0 <= ret); assert(ret == 0); ret = close(1); assert(0 <= ret); ret = open(out, O_CREAT | O_TRUNC | O_WRONLY, 0666); assert(0 <= ret); assert(ret == 1); debug("gcc", as_param); execvp("gcc", as_param); assert(0); default: ret = wait(&status); assert(0 <= ret); exit_status("as", status); break; } return 0; } static int ld(void) { int pid; int status; int ret; ld_param[nld_params] = NULL; switch (pid = fork()) { case -1: assert(0); case 0: debug("ld", ld_param); execvp("gcc", ld_param); assert(0); default: ret = wait(&status); assert(0 <= ret); exit_status("ld", status); break; } return 0; } static int rm(const char *file) { int ret; ret = unlink(file); assert(0 <= ret); return 0; } static __attribute__((__noreturn__)) void usage(int retval) { fprintf(stderr, "Usage: %s [-D macro[=def]] [-E] [-I dir] [-O level] [-U macro] [-S] [-c] -b arch [-o output] [-print-libfaucc-file-name] file...\n", progname); exit(retval); } int main(int argc, char **argv) { unsigned int i; #if 0 for (i = 0; i < argc; i++) { fprintf(stderr, "%u: '%s'\n", i, argv[i]); } #endif progname = *argv; ncpp_params = 0; cpp_param[ncpp_params++] = "cpp"; ncc1_params = 0; cc1_param[ncc1_params++] = "cc1"; nas_params = 0; as_param[nas_params++] = "gcc"; as_param[nas_params++] = "-m32"; nld_params = 0; ld_param[nld_params++] = "gcc"; ld_param[nld_params++] = "-m32"; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-B") == 0) { opt_B = argv[++i]; } else if (strncmp(argv[i], "-B", 2) == 0) { opt_B = &argv[i][2]; } else if (strcmp(argv[i], "-D") == 0) { cpp_param[ncpp_params++] = "-D"; cpp_param[ncpp_params++] = argv[++i]; } else if (strncmp(argv[i], "-D", 2) == 0) { cpp_param[ncpp_params++] = "-D"; cpp_param[ncpp_params++] = &argv[i][2]; } else if (strcmp(argv[i], "-E") == 0) { opt_E = 1; } else if (strcmp(argv[i], "-I") == 0) { cpp_param[ncpp_params++] = "-I"; cpp_param[ncpp_params++] = argv[++i]; } else if (strncmp(argv[i], "-I", 2) == 0) { cpp_param[ncpp_params++] = "-I"; cpp_param[ncpp_params++] = &argv[i][2]; } else if (strcmp(argv[i], "-L") == 0) { ld_param[nld_params++] = "-L"; ld_param[nld_params++] = argv[++i]; } else if (strncmp(argv[i], "-L", 2) == 0) { ld_param[nld_params++] = "-L"; ld_param[nld_params++] = &argv[i][2]; } else if (strcmp(argv[i], "-MD") == 0) { cpp_param[ncpp_params++] = "-MD"; } else if (strcmp(argv[i], "-MF") == 0) { cpp_param[ncpp_params++] = "-MF"; cpp_param[ncpp_params++] = argv[++i]; } else if (strncmp(argv[i], "-MF", 3) == 0) { cpp_param[ncpp_params++] = "-MF"; cpp_param[ncpp_params++] = &argv[i][2]; } else if (strcmp(argv[i], "-MP") == 0) { cpp_param[ncpp_params++] = "-MP"; } else if (strcmp(argv[i], "-MT") == 0) { cpp_param[ncpp_params++] = "-MT"; cpp_param[ncpp_params++] = argv[++i]; } else if (strncmp(argv[i], "-MT", 3) == 0) { cpp_param[ncpp_params++] = "-MT"; cpp_param[ncpp_params++] = &argv[i][2]; } else if (strcmp(argv[i], "-O") == 0) { cc1_param[ncc1_params++] = "-O"; cc1_param[ncc1_params++] = argv[++i]; } else if (strncmp(argv[i], "-O", 2) == 0) { cc1_param[ncc1_params++] = "-O"; cc1_param[ncc1_params++] = &argv[i][2]; } else if (strcmp(argv[i], "-S") == 0) { opt_S = 1; } else if (strcmp(argv[i], "-T") == 0) { ld_param[nld_params++] = "-T"; ld_param[nld_params++] = argv[++i]; } else if (strcmp(argv[i], "-U") == 0) { cpp_param[ncpp_params++] = "-U"; cpp_param[ncpp_params++] = argv[++i]; } else if (strncmp(argv[i], "-U", 2) == 0) { cpp_param[ncpp_params++] = "-U"; cpp_param[ncpp_params++] = &argv[i][2]; } else if (strncmp(argv[i], "-Wl,", 4) == 0) { ld_param[nld_params++] = &argv[i][4]; } else if (strcmp(argv[i], "-Xlinker") == 0) { ld_param[nld_params++] = "-Xlinker"; ld_param[nld_params++] = argv[++i]; } else if (strcmp(argv[i], "-b") == 0) { cc1_param[ncc1_params++] = "-b"; cc1_param[ncc1_params++] = argv[++i]; } else if (strncmp(argv[i], "-b", 2) == 0) { cc1_param[ncc1_params++] = "-b"; cc1_param[ncc1_params++] = &argv[i][2]; } else if (strcmp(argv[i], "-c") == 0) { opt_c = 1; } else if (strcmp(argv[i], "-f") == 0) { cc1_param[ncc1_params++] = "-f"; cc1_param[ncc1_params++] = argv[++i]; } else if (strncmp(argv[i], "-f", 2) == 0) { cc1_param[ncc1_params++] = "-f"; cc1_param[ncc1_params++] = &argv[i][2]; } else if (strcmp(argv[i], "-m") == 0) { cc1_param[ncc1_params++] = "-m"; cc1_param[ncc1_params++] = argv[++i]; } else if (strncmp(argv[i], "-m", 2) == 0) { cc1_param[ncc1_params++] = "-m"; cc1_param[ncc1_params++] = &argv[i][2]; } else if (strcmp(argv[i], "-nostdlib") == 0) { ld_param[nld_params++] = "-nostdlib"; } else if (strcmp(argv[i], "-o") == 0) { opt_o = 1; opt_o_arg = argv[++i]; ld_param[nld_params++] = "-o"; ld_param[nld_params++] = opt_o_arg; } else if (strncmp(argv[i], "-o", 2) == 0) { opt_o = 1; opt_o_arg = &argv[i][2]; ld_param[nld_params++] = "-o"; ld_param[nld_params++] = opt_o_arg; } else if (strcmp(argv[i], "-print-libfaucc-file-name") == 0) { printf("%s/libfaucc.a\n", opt_B); exit(0); } else if (strcmp(argv[i], "-static") == 0) { ld_param[nld_params++] = "-static"; } else if (strcmp(argv[i], "--freestanding") == 0) { /* FIXME */ } else if (strcmp(argv[i], "--no-stack-protector") == 0) { /* FIXME */ } else if (argv[i][0] == '-') { fprintf(stderr, "%s: Unknown option %s.\n", progname, argv[i]); usage(1); } else { char file[256]; char *suffix; char file_o[256]; strcpy(file, argv[i]); if (strrchr(file, '.')) { *strrchr(file, '.') = '\0'; } suffix = strrchr(argv[i], '.'); assert(suffix); input[ninputs++] = argv[i]; if (strcmp(suffix, ".a") == 0 || strcmp(suffix, ".o") == 0) { output[noutputs] = argv[i]; } else { tmpname(file_o, "o"); output[noutputs] = strdup(file_o); } ld_param[nld_params++] = output[noutputs++]; } } /* * Check options. */ if (1 < opt_E + opt_S + opt_c) { fprintf(stderr, "%s: Only one of -E/-S/-c allowed.\n", progname); exit(1); } if (opt_o && 1 < ninputs && (opt_E || opt_S || opt_c)) { fprintf(stderr, "%s: bad usage of -o.\n", progname); exit(1); } /* * Check parameter. */ if (ninputs == 0) { fprintf(stderr, "%s: no input files.\n", progname); exit(1); } if (opt_E + opt_S + opt_c == 0) { opt_o = 0; /* -o part of ld_param. */ } for (i = 0; i < ninputs; i++) { char file[256]; const char *suffix; char file_c[256]; char file_i[256]; char file_S[256]; char file_s[256]; char file_o[256]; strcpy(file, input[i]); if (strrchr(file, '.')) { *strrchr(file, '.') = '\0'; } suffix = strrchr(input[i], '.'); assert(suffix); if (strcmp(suffix, ".c") == 0) { if (opt_E) { sprintf(file_c, "%s.c", file); if (opt_o) { sprintf(file_i, "%s", opt_o_arg); } else { strcpy(file_i, ""); } cpp(file_c, file_i); } else if (opt_S) { sprintf(file_c, "%s.c", file); tmpname(file_i, "i"); if (opt_o) { sprintf(file_s, "%s", opt_o_arg); } else { sprintf(file_s, "%s.s", file); } cpp(file_c, file_i); cc1(file_i, file_s); rm(file_i); } else if (opt_c) { sprintf(file_c, "%s.c", file); tmpname(file_i, "i"); tmpname(file_s, "s"); if (opt_o) { sprintf(file_o, "%s", opt_o_arg); } else { sprintf(file_o, "%s.o", file); } cpp(file_c, file_i); cc1(file_i, file_s); as(file_s, file_o); rm(file_i); rm(file_s); } else { sprintf(file_c, "%s.c", file); tmpname(file_i, "i"); tmpname(file_s, "s"); if (opt_o) { sprintf(file_o, "%s", opt_o_arg); } else { strcpy(file_o, output[i]); } cpp(file_c, file_i); cc1(file_i, file_s); as(file_s, file_o); rm(file_i); rm(file_s); } } else if (strcmp(suffix, ".i") == 0) { if (opt_E) { /* Nothing to do... */ } else if (opt_S) { sprintf(file_i, "%s.i", file); if (opt_o) { sprintf(file_s, "%s", opt_o_arg); } else { sprintf(file_s, "%s.s", file); } cc1(file_i, file_s); } else if (opt_c) { sprintf(file_i, "%s.i", file); tmpname(file_s, "s"); if (opt_o) { sprintf(file_o, "%s", opt_o_arg); } else { sprintf(file_o, "%s.o", file); } cc1(file_i, file_s); as(file_s, file_o); rm(file_s); } else { sprintf(file_i, "%s.i", file); tmpname(file_s, "s"); if (opt_o) { sprintf(file_o, "%s", opt_o_arg); } else { strcpy(file_o, output[i]); } cc1(file_i, file_s); as(file_s, file_o); rm(file_s); } } else if (strcmp(suffix, ".S") == 0) { if (opt_E) { sprintf(file_S, "%s.S", file); if (opt_o) { sprintf(file_i, "%s", opt_o_arg); } else { strcpy(file_i, ""); } cpp(file_S, file_i); } else if (opt_S) { sprintf(file_S, "%s.S", file); sprintf(file_s, "%s.s", file); if (opt_o) { sprintf(file_s, "%s", opt_o_arg); } else { sprintf(file_s, "%s.s", file); } cpp(file_S, file_s); } else if (opt_c) { sprintf(file_S, "%s.S", file); tmpname(file_s, "s"); if (opt_o) { sprintf(file_o, "%s", opt_o_arg); } else { sprintf(file_o, "%s.o", file); } cpp(file_S, file_s); as(file_s, file_o); rm(file_s); } else { sprintf(file_S, "%s.S", file); tmpname(file_s, "s"); if (opt_o) { sprintf(file_o, "%s", opt_o_arg); } else { strcpy(file_o, output[i]); } cpp(file_S, file_s); as(file_s, file_o); rm(file_s); } } else if (strcmp(suffix, ".s") == 0) { if (opt_E) { /* Nothing to do... */ } else if (opt_S) { /* Nothing to do... */ } else if (opt_c) { sprintf(file_s, "%s.s", file); if (opt_o) { sprintf(file_o, "%s", opt_o_arg); } else { sprintf(file_o, "%s.o", file); } as(file_s, file_o); } else { sprintf(file_s, "%s.s", file); if (opt_o) { sprintf(file_o, "%s", opt_o_arg); } else { strcpy(file_o, output[i]); } as(file_s, file_o); } } else if (strcmp(suffix, ".o") == 0 || strcmp(suffix, ".a") == 0) { /* Nothing to do... */ } else { fprintf(stderr, "%s: ERROR: Unknown input %s.\n", progname, input[i]); assert(0); /* FIXME */ } } if (opt_E + opt_S + opt_c == 0) { /* * Do linking. */ ld(); } return 0; } faucc-20120707/docs/0000750002413100241000000000000011776113677013455 5ustar potyrai3guestfaucc-20120707/docs/man/0000750002413100241000000000000011776113700014213 5ustar potyrai3guestfaucc-20120707/docs/man/faucc.1.xml0000640002413100241000000002732711140335762016170 0ustar potyrai3guest ]>
<info@faumachine.org>
FAUcc Team 2009 FAUcc Team. Developed at Friedrich Alexander University Erlangen-Nuremberg. FAUcc comes with ABSOLUTELY NO WARRANTY. FAUcc is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See COPYING for details.
FAUCC 1 &binary; C compiler generating Intel code for 16 bit/32 bit CPUs. &binary; DESCRIPTION &binary; is a C compiler, that can generate Intel 16 bit or 32 bit Code. OPTIONS &binary; tries to mimic the options of gcc. A number of options will be passed to the C preprocessor cpp or to the linker (done via a call to the c-compiler gcc) in unmodified form. path Override the directory prefix where cc1 is looked up with path. MACRO, Define MACRO with the optional initial definition def. If def is omitted, it defaults to 1. Only perform preprocessing, but do not run the compiler. path Add path to the include path in which header files are searched. path Add path to the library search path, in which the linker will look for libraries. Output dependency information while preprocessing. , file Output dependency information while preprocessing to file. , When the preprocessor should output dependency information, it will generate PHONY targets for each dependency. target When the preprocessor should output dependency information, use target as the dependency rule target. level Currently ignored. Output assembly code. script Use script as linker script. macro Undefine a previously defined macro. arg arg Pass arg to the linker. arch Generate code for arch (either i286 or i386) Perform compilation, but do not link. arg Pass code generation argument arg to the compiler. See the cc1 man page for possible arguments. arch Currently ignored. With this option, the linker will only search for libraries that are passed as command line arguments. file Write output to file. Print the full path of the internal compiler library libfaucc.a. Perform static linking. Currently ignored. EXAMPLES &binary; -c hello-world.c -o hello-world.o Compile the program hello-world.c and output the object as hello-wolrd.o. &binary; -S -b i286 -o test.s test.c Compile the program test.c to 16 bit code and output the assembly listing to test.s, but do not assemble or link the result yet. SEE ALSO cc1 1 cpp 1 gcc 1 ld 1 CONTACT Please report all bugs to FAUcc Team info@faumachine.org. FAUcc Homepage .
faucc-20120707/docs/man/Makefile.am0000640002413100241000000000077711144020350016246 0ustar potyrai3guest# $Id: Makefile.am,v 1.3 2009-02-09 12:26:16 vrsieh Exp $ # # Copyright (C) 2009 FAUcc Team . # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. man_MANS = faucc.1 CLEANFILES = $(man_MANS) EXTRA_DIST = $(man_MANS) %.1: %.1.xml $(XMLTO) man $< check-doc: faucc.1.xml xmllint --noout --valid faucc.1.xml .PHONY: check-doc faucc-20120707/docs/optimization.txt0000640002413100241000000001306510751705124016734 0ustar potyrai3guestSimplification steps: Scope/type/declaration related: * simplify_name_structunionenum: All structs/unions/enums get names. * simplify_split_structunion_decl: A declaration using type specifier defining a struct/union might be converted into one typedef declaration of the struct/union and a declaration using the newly defined struct/union. Works only if struct/union has a name. * simplify_split_vardecl_init: "auto" and "register" declarations using an initializer might be splitted into a declaration without an initializer and a new statement assigning the initial value to the variable. Works only in functions and blocks within functions and only if variable is not declared "const". * simplify_split_vardecl_list: Declarations containing two or more declarators might be splitted into separate declarations with only one declarator each. Works only if type specifier is simple type, user type or struct/union without declarations. * simplify_remove_empty_declarations: Declarations containing no declarators might be deleted. Works only if type specifier is simple type or user type. * simplify_enum_expr: Add initializers to all enumerators not having one. * Enum definitions might be converted into constant definitions and int variables. * simplify_merge_declarations_of_blocks: Register and auto variable definitions in sub-scopes of functions might be moved to function scope. Same with type definitions. Rename variable/type in old scope and its sub-scopes. Works only if variables has no initializers and type is visible in outer scope, too. * Static variables from functions and blocks within functions might be moved to top scope if initializer is known constant. Rename variables in old scope and its sub-scopes. * Type definitions from functions and blocks within functions might be moved to top scope. Rename type in old scope and its sub-scopes. * A declaration using a complex declarator might be changed into a typedef declaration defining the type and a variable declaration using the newly defined type. The type specifier must be a simple one. * Register and auto variable definitions with initializers in functions and its sub-scopes might be splitted into variable definitions without initializers and statements containing assignment of initializer to variable. * Type definitions using a simple type specifier and a simple declarator might be removed. Change places where the declared type is used to use the simple type specifier directly. Function related: * For loops might be translated into goto and if-goto statements. Change continue and break statements accordingly using goto statements. * While loops might be translated into goto and if-goto statements. Change continue and break statements accordingly using goto statements. * Do-while loops might be translated into goto and if-goto statements. Change continue and break statements accordingly using goto statements. * Switch statements might be translated into simple switch statements containing only a list of case-goto and default-goto statements. Change break statements accordingly using goto statements. * If-else statements might be translated into goto and if-goto statements. * simplify_rename_labels: Rename user-named labels by labels with unique name. * simplify_remove_labels: Remove labels with no corresponding goto. If consecutive labels exist redirect all gotos to first label to go to second label and remove first label. * simplify_goto: Goto statements with goto-statement as target might be replace by goto statement to second target. Goto or if-then-goto statements with the next statement as target might be removed or converted into null statements. (Keep epression of if-then-goto statements!) An if-goto statement jumping over a following goto statement might be replaced by a single if-goto statement with a negated condition. * simplify_remove_unreachable_stmts: Unreachable code might be removed. * simplify_returns: Return statements not at the end of a function might be replaced by variable assignment and a goto statement to end of function. * simplify_rename_labels: An user-defined label might be replaced by a temporary one to omit "redefined" errors. Change corresponding goto statements accordingly. * simplify_split_exprs: Expressions containing sub-expressions might be translated into several statements with expressions using temporary variables. Comma separated expressions might be translated into several statements containing one expression each. Expressions related: * simplify_constant_folding: sizeof expressions might be replaced by a constant. Operations only using constants as operands might be replaced by only one constant. * simplify_split_exprs: Replace complex expressions by expressions only using one operator. Use temporary variables. Replace pre-dec/inc operator expressions by first decrementing/incrementing the variable before using it in an expression. Replace post-dec/inc operator expressions by first assigning the current value to a temporary variable and then decrementing/incrementing the original variable. Use the temporary variable in the expression instead of the original one. Move up commas in expressions. * Expressions with implicit type conversion should be replaced by expressions using explicit type conversions. faucc-20120707/docs/structure.txt0000640002413100241000000001536210765035300016245 0ustar potyrai3guestAfter simplification the structures are as follows: The top-most scope contains of a double-linked list of declarations. Declarations ------------ Each declaration declares one of the following: * a struct, union, enum The `identifier' field of the declaration struct is NULL in this case. The `type_name' field contains the struct, union, enum definition. The `storage', `mod_inline' fields don't contain any info. * a type The `identifier' field of the declaration struct contains the name of the new type. The `type_name' field contains the type definitions. The `storage' field contains STORAGE_TYPEDEF. * a variable The `identifier' contains the name of the variable. `type_name' is the type of the variable. If `storage' is STORAGE_EXTERN this is only an extern declaration. In case of STORAGE_STATIC it is a local variable. Otherwise (STORAGE_NONE) it is a global variable. STORAGE_AUTO and STORAGE_REGISTER define function local variables. Parameters are marked STORAGE_PARAM. If `initializer' field contains the initializer expressions if it isn't NULL. * a function The `identifier' contains the name of the function. `type_name' is the type of the function. The type contains the parameter list. If `storage' is STORAGE_EXTERN this is only an extern declaration. It also is only a forward declaration if the `stmt' field is NULL. In case of STORAGE_STATIC it is a local function. Otherwise (STORAGE_NONE) it is a global function. `stmt' contains the code. The `mod_inline' marks functions to be inlined. Inlining is done during simplification. After simplification no inline function remain. `attr_noreturn' is true if the function doesn't return (like the exit/abort functions). `nbits' is an expression only valid in struct/union scopes. It is not used, yet. `clone' is used during inlining only. `assign_expr', `acount', `wcount' and `rcount' are used during optimization only. `live_noreg', `move_first', `move_last', `storage_class', `choices', `storage_register', `spills' `degree', `conflict_first', `conflict_last', `conflict_save_first', `conflict_save_last' are used during register allocation only. Code ---- The `stmt' field of a declaration contains the code and the variables of a function. The `stmt' points to a stmt struct of type STMT_BLOCK. STMT_BLOCKs have a `scope' field pointing to a scope (containing a double linked list of declarations; see above) and `stmt_first' and `stmt_last' fields being the head/tail of a double linked list of stmt structs. Each stmt struct is one of the following: * a label In this case the `identifier' field contains a pointer to the name of the label. The `stmt0' field always contains a pointer to a null-statement (type = STMT_NULL). * an expression statement The expression is an assignment or a function-call expression. * an if statement The `expr0' field contains a pointer to an expression of type EXPR_EQUAL, EXPR_NOT_EQUAL, EXPR_LESS, EXPR_LESS_EQUAL, EXPR_GREATER, EXPR_GREATER_EQUAL. The `stmt0' pointer always points to a goto-statement. * a switch statement The `expr0' field contains a pointer to an expression. The expression is always of type EXPR_IDENTIFIER. The `stmt0' pointer points to a block. The block (in a stmt struct) doesn't contain any declarations but only case and default statements. The case statements `expr0' fields always point to an expression of type EXPR_INTEGER. Case and default statements both always have `stmt0' pointers pointing to a goto statement. Switch statements always have a default statement. * a goto statement All goto statements only have a valid `identifier' member containing a pointer to the name of the label to go to. * a return statement Each function have one and only one return statement as the last statement in the statement list. In case the function is no `void' function the `expr0' member points to the return expression. The return expression is of type EXPR_IDENTIFIER or a constant (EXPR_INTEGER, EXPR_REAL, EXPR_AMPHERSAND). * an asm statement The `code' member points to the string containing the asm statements. The `output', `input' and `change' fields (if non-NULL) contain a double linked list of constraints. Each constraint has a `string' field with the register/memory definition and an `expr' field with the expression to pass from/to the code. * a va_start/va_end statement The `expr0' field containts the `args' parameter. The second parameter of the va_start call is stored in `expr1'. No other types of statements are valid after simplification. Optimization will stay with this constraints. Expressions ----------- All expressions are as follows: * assignment expressions The `expr0' pointer points to the lhs of the assignment. The `expr1' field contains the pointer of the rhs. * function/procedure calls The `expr0' is the name of the function to be called or a pointer to such a function. `expr1' is a pointer to an EXPR_LIST element which has the `first' and `last' fields used. `first' and `last' form a double linked list of `expr' objects. Each such expression holds one parameter for the function call. If no parameters are present, `first' and `last' are both NULL. All parameters are simple expressions. Simple expressions are: * an identifier `type' is EXPR_IDENTIFIER. `declaration' points to the declaration of the identifier. The declaration contains the name, type, storage type, etc. of the identifier. * a constant `type' is EXPR_INTEGER, EXPR_REAL. `type_name' contains the type of the constant (int8, uint8, ..., uint64, float32, float64, float80). `integer' or `real' contain the constant. * an address `type' is EXPR_TYPE_CONVERSION, `expr0' is EXPR_AMPHERSAND and `expr0->expr0' is EXPR_IDENTIFIER in this case. `expr0' might be EXPR_IDENTIFIER if the identifier is an array. Examples are expressions like "(int) &var" or "(int) array". Unary expressions are: * a star expression `type' is EXPR_STAR. `expr0' is a type conversion and `expr0->expr0' is an expression containing an address. An example expression is "*(int *) var". * a type conversion `type' is EXPR_TYPE_CONVERSION. `type_name' contains the type be converted to. `expr0' is the expression to be converted. * a NEG or INV expression `type' is EXPR_NEG or EXPR_INV. `expr0' containts the pointer to the expression to be negated/inverted. Binary expressions are: `type' might contain: EXPR_ADD, EXPR_SUB, EXPR_MUL, EXPR_DIV, EXPR_MOD for the standard arithmetic operations, EXPR_LEFT, EXPR_RIGHT for shift operations, EXPR_EQUAL, EXPR_NOT_EQUAL, EXPR_LESS, EXPR_LESS_EQUAL, EXPR_GREATER, EXPR_GREATER_EQUAL for comparisons. `expr0' and `expr1' contain the two operands. No other expressions remain after simplification/optimization steps are performed. faucc-20120707/arch_i386_gen.c0000640002413100241000000035433011721634327015207 0ustar potyrai3guest/* * $Id: arch_i386_gen.c,v 1.320 2012-02-24 07:14:31 vrsieh Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ /* * For gcc inline assembler see e.g. * http://ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */ #include #include #include #include #include #include "identifier.h" #include "declaration.h" #include "scope.h" #include "stmt.h" #include "simplify.h" #include "arch_i386_gen.h" #include "regalloc.h" #include "cc1.h" static struct declaration *arch_mul_int64; static struct declaration *arch_mul_uint64; static struct declaration *arch_div_int64; static struct declaration *arch_div_uint64; static struct declaration *arch_mod_int64; static struct declaration *arch_mod_uint64; enum reg { /*0*/ AL, DL, CL, BL, /*4*/ AH, DH, CH, BH, /*8*/ AX, DX, CX, BX, DI, SI, /*14*/ EAX, EDX, ECX, EBX, EDI, ESI, /*20*/ EAX_EBX, EAX_ECX, EAX_EDX, EAX_EDI, EAX_ESI, /*25*/ EBX_EAX, EBX_ECX, EBX_EDX, EBX_EDI, EBX_ESI, /*30*/ ECX_EAX, ECX_EBX, ECX_EDX, ECX_EDI, ECX_ESI, /*35*/ EDX_EAX, EDX_EBX, EDX_ECX, EDX_EDI, EDX_ESI, /*40*/ EDI_EAX, EDI_EBX, EDI_ECX, EDI_EDX, EDI_ESI, /*45*/ ESI_EAX, ESI_EBX, ESI_ECX, ESI_EDX, ESI_EDI, /*50*/ ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7, /*58*/ REG_COUNT }; enum class { CLASS_NONE, CLASS_A, CLASS_D, CLASS_S, CLASS_a, CLASS_b, CLASS_c, CLASS_d, CLASS_f, CLASS_q, CLASS_r, CLASS_t, CLASS_u, CLASS_st2, CLASS_st3, CLASS_st4, CLASS_st5, CLASS_st6, CLASS_st7, CLASS_COUNT }; enum type_mod { REG_MOD_NONE, REG_MOD_b, REG_MOD_h, REG_MOD_w, REG_MOD_u, }; #define REG_8 \ ((1ULL << AL) \ | (1ULL << BL) \ | (1ULL << CL) \ | (1ULL << DL)) #define REG_16 \ ((1ULL << AX) | (1ULL << BX) \ | (1ULL << CX) | (1ULL << DX) \ | (1ULL << DI) | (1ULL << SI)) #define REG_32 \ ((1ULL << EAX) | (1ULL << EBX) \ | (1ULL << ECX) | (1ULL << EDX) \ | (1ULL << EDI) | (1ULL << ESI)) #define REG_64 \ ((1ULL << EAX_EBX) | (1ULL << EAX_ECX) \ | (1ULL << EAX_EDX) | (1ULL << EAX_EDI) \ | (1ULL << EAX_ESI) \ | (1ULL << EBX_EAX) | (1ULL << EBX_ECX) \ | (1ULL << EBX_EDX) | (1ULL << EBX_EDI) \ | (1ULL << EBX_ESI) \ | (1ULL << ECX_EAX) | (1ULL << ECX_EBX) \ | (1ULL << ECX_EDX) | (1ULL << ECX_EDI) \ | (1ULL << ECX_ESI) \ | (1ULL << EDX_EAX) | (1ULL << EDX_EBX) \ | (1ULL << EDX_ECX) | (1ULL << EDX_EDI) \ | (1ULL << EDX_ESI) \ | (1ULL << EDI_EAX) | (1ULL << EDI_EBX) \ | (1ULL << EDI_ECX) | (1ULL << EDI_EDX) \ | (1ULL << EDI_ESI) \ | (1ULL << ESI_EAX) | (1ULL << ESI_EBX) \ | (1ULL << ESI_ECX) | (1ULL << ESI_EDX) \ | (1ULL << ESI_EDI)) #define REG_A \ ((1ULL << EAX_EDX)) #define REG_D \ ((1ULL << DI) | (1ULL << EDI) \ | (1ULL << EDI_EAX) | (1ULL << EDI_EBX) \ | (1ULL << EDI_ECX) | (1ULL << EDI_EDX) \ | (1ULL << EDI_ESI)) #define REG_S \ ((1ULL << SI) | (1ULL << ESI) \ | (1ULL << ESI_EAX) | (1ULL << ESI_EBX) \ | (1ULL << ESI_ECX) | (1ULL << ESI_EDX) \ | (1ULL << ESI_EDI)) #define REG_a \ ((1ULL << AL) | (1ULL << AX) | (1ULL << EAX) \ | (1ULL << EAX_EBX) | (1ULL << EAX_ECX) \ | (1ULL << EAX_EDX) | (1ULL << EAX_EDI) \ | (1ULL << EAX_ESI)) #define REG_b \ ((1ULL << BL) | (1ULL << BX) | (1ULL << EBX) \ | (1ULL << EBX_EAX) | (1ULL << EBX_ECX) \ | (1ULL << EBX_EDX) | (1ULL << EBX_EDI) \ | (1ULL << EBX_ESI)) #define REG_c \ ((1ULL << CL) | (1ULL << CX) | (1ULL << ECX) \ | (1ULL << ECX_EAX) | (1ULL << ECX_EBX) \ | (1ULL << ECX_EDX) | (1ULL << ECX_EDI) \ | (1ULL << ECX_ESI)) #define REG_d \ ((1ULL << DL) | (1ULL << DX) | (1ULL << EDX) \ | (1ULL << EDX_EAX) | (1ULL << EDX_EBX) \ | (1ULL << EDX_ECX) | (1ULL << EDX_EDI) \ | (1ULL << EDX_ESI)) #define REG_t \ (1ULL << ST0) #define REG_u \ (1ULL << ST1) #define REG_st2 \ (1ULL << ST2) #define REG_st3 \ (1ULL << ST3) #define REG_st4 \ (1ULL << ST4) #define REG_st5 \ (1ULL << ST5) #define REG_st6 \ (1ULL << ST6) #define REG_st7 \ (1ULL << ST7) #define REG_f \ (REG_t | REG_u | REG_st2 | REG_st3 \ | REG_st4 | REG_st5 | REG_st6 | REG_st7) #define REG_q \ (REG_a | REG_b | REG_c | REG_d) #define REG_r \ (REG_a | REG_b | REG_c | REG_d | REG_D | REG_S) #define REG_CALLER \ ((1ULL << EAX) \ | (1ULL << ECX) \ | (1ULL << EDX) \ | (1ULL << ST0) \ | (1ULL << ST1) \ | (1ULL << ST2) \ | (1ULL << ST3) \ | (1ULL << ST4) \ | (1ULL << ST5) \ | (1ULL << ST6) \ | (1ULL << ST7)) #define REG_CALLEE \ ((REG_32 | REG_f) & ~REG_CALLER) static struct storage_register arch_reginfo[] = { /* 8-Bit Registers */ [AL] = { "al", CLASS_a, TYPE_UINT8 }, [BL] = { "bl", CLASS_b, TYPE_UINT8 }, [CL] = { "cl", CLASS_c, TYPE_UINT8 }, [DL] = { "dl", CLASS_d, TYPE_UINT8 }, [AH] = { "ah", CLASS_COUNT, TYPE_UINT8 }, [BH] = { "bh", CLASS_COUNT, TYPE_UINT8 }, [CH] = { "ch", CLASS_COUNT, TYPE_UINT8 }, [DH] = { "dh", CLASS_COUNT, TYPE_UINT8 }, /* 16-Bit Registers */ [AX] = { "ax", CLASS_a, TYPE_UINT16 }, [BX] = { "bx", CLASS_b, TYPE_UINT16 }, [CX] = { "cx", CLASS_c, TYPE_UINT16 }, [DX] = { "dx", CLASS_d, TYPE_UINT16 }, [DI] = { "di", CLASS_D, TYPE_UINT16 }, [SI] = { "si", CLASS_S, TYPE_UINT16 }, /* "bp" Used as frame pointer. */ /* "sp" Used as stack pointer. */ /* 32-Bit Registers */ [EAX] = { "eax", CLASS_a, TYPE_UINT32 }, [EBX] = { "ebx", CLASS_b, TYPE_UINT32 }, [ECX] = { "ecx", CLASS_c, TYPE_UINT32 }, [EDX] = { "edx", CLASS_d, TYPE_UINT32 }, [EDI] = { "edi", CLASS_D, TYPE_UINT32 }, [ESI] = { "esi", CLASS_S, TYPE_UINT32 }, /* "ebp" Used as frame pointer. */ /* "esp" Used as stack pointer. */ /* 64-Bit Registers */ [EAX_EBX] = { "eax_ebx", CLASS_NONE, TYPE_UINT64 }, [EAX_ECX] = { "eax_ecx", CLASS_NONE, TYPE_UINT64 }, [EAX_EDX] = { "eax_edx", CLASS_NONE, TYPE_UINT64 }, [EAX_EDI] = { "eax_edi", CLASS_NONE, TYPE_UINT64 }, [EAX_ESI] = { "eax_esi", CLASS_NONE, TYPE_UINT64 }, [EBX_EAX] = { "ebx_eax", CLASS_NONE, TYPE_UINT64 }, [EBX_ECX] = { "ebx_ecx", CLASS_NONE, TYPE_UINT64 }, [EBX_EDX] = { "ebx_edx", CLASS_NONE, TYPE_UINT64 }, [EBX_EDI] = { "ebx_edi", CLASS_NONE, TYPE_UINT64 }, [EBX_ESI] = { "ebx_esi", CLASS_NONE, TYPE_UINT64 }, [ECX_EAX] = { "ecx_eax", CLASS_NONE, TYPE_UINT64 }, [ECX_EBX] = { "ecx_ebx", CLASS_NONE, TYPE_UINT64 }, [ECX_EDX] = { "ecx_edx", CLASS_NONE, TYPE_UINT64 }, [ECX_EDI] = { "ecx_edi", CLASS_NONE, TYPE_UINT64 }, [ECX_ESI] = { "ecx_esi", CLASS_NONE, TYPE_UINT64 }, [EDX_EAX] = { "edx_eax", CLASS_NONE, TYPE_UINT64 }, [EDX_EBX] = { "edx_ebx", CLASS_NONE, TYPE_UINT64 }, [EDX_ECX] = { "edx_ecx", CLASS_NONE, TYPE_UINT64 }, [EDX_EDI] = { "edx_edi", CLASS_NONE, TYPE_UINT64 }, [EDX_ESI] = { "edx_esi", CLASS_NONE, TYPE_UINT64 }, [EDI_EAX] = { "edi_eax", CLASS_NONE, TYPE_UINT64 }, [EDI_EBX] = { "edi_ebx", CLASS_NONE, TYPE_UINT64 }, [EDI_ECX] = { "edi_ecx", CLASS_NONE, TYPE_UINT64 }, [EDI_EDX] = { "edi_edx", CLASS_NONE, TYPE_UINT64 }, [EDI_ESI] = { "edi_esi", CLASS_NONE, TYPE_UINT64 }, [ESI_EAX] = { "esi_eax", CLASS_NONE, TYPE_UINT64 }, [ESI_EBX] = { "esi_ebx", CLASS_NONE, TYPE_UINT64 }, [ESI_ECX] = { "esi_ecx", CLASS_NONE, TYPE_UINT64 }, [ESI_EDX] = { "esi_edx", CLASS_NONE, TYPE_UINT64 }, [ESI_EDI] = { "esi_edi", CLASS_NONE, TYPE_UINT64 }, /* Floating Point Registers */ [ST0] = { "st(0)", CLASS_t, TYPE_FLOAT64 }, [ST1] = { "st(1)", CLASS_u, TYPE_FLOAT64 }, [ST2] = { "st(2)", CLASS_st2, TYPE_FLOAT64 }, [ST3] = { "st(3)", CLASS_st3, TYPE_FLOAT64 }, [ST4] = { "st(4)", CLASS_st4, TYPE_FLOAT64 }, [ST5] = { "st(5)", CLASS_st5, TYPE_FLOAT64 }, [ST6] = { "st(6)", CLASS_st6, TYPE_FLOAT64 }, [ST7] = { "st(7)", CLASS_st7, TYPE_FLOAT64 }, }; static struct { unsigned int count; enum reg reg[4]; } arch_gen_reg_parts[] = { /* 8-Bit Registers */ [AL] = { 0 }, [BL] = { 0 }, [CL] = { 0 }, [DL] = { 0 }, [AH] = { 0 }, [BH] = { 0 }, [CH] = { 0 }, [DH] = { 0 }, /* 16-Bit Registers */ [AX] = { 2, { AL, AH } }, [BX] = { 2, { BL, BH } }, [CX] = { 2, { CL, CH } }, [DX] = { 2, { DL, DH } }, [DI] = { 0 }, [SI] = { 0 }, /* "bp" Used as frame pointer. */ /* "sp" Used as stack pointer. */ /* 32-Bit Registers */ [EAX] = { 1, { AX } }, [EBX] = { 1, { BX } }, [ECX] = { 1, { CX } }, [EDX] = { 1, { DX } }, [EDI] = { 1, { DI } }, [ESI] = { 1, { SI } }, /* "ebp" Used as frame pointer. */ /* "esp" Used as stack pointer. */ /* 64-Bit Registers */ [EAX_EBX] = { 2, { EAX, EBX } }, [EAX_ECX] = { 2, { EAX, ECX } }, [EAX_EDX] = { 2, { EAX, EDX } }, [EAX_EDI] = { 2, { EAX, EDI } }, [EAX_ESI] = { 2, { EAX, ESI } }, [EBX_EAX] = { 2, { EBX, EAX } }, [EBX_ECX] = { 2, { EBX, ECX } }, [EBX_EDX] = { 2, { EBX, EDX } }, [EBX_EDI] = { 2, { EBX, EDI } }, [EBX_ESI] = { 2, { EBX, ESI } }, [ECX_EAX] = { 2, { ECX, EAX } }, [ECX_EBX] = { 2, { ECX, EBX } }, [ECX_EDX] = { 2, { ECX, EDX } }, [ECX_EDI] = { 2, { ECX, EDI } }, [ECX_ESI] = { 2, { ECX, ESI } }, [EDX_EAX] = { 2, { EDX, EAX } }, [EDX_EBX] = { 2, { EDX, EBX } }, [EDX_ECX] = { 2, { EDX, ECX } }, [EDX_EDI] = { 2, { EDX, EDI } }, [EDX_ESI] = { 2, { EDX, ESI } }, [EDI_EAX] = { 2, { EDI, EAX } }, [EDI_EBX] = { 2, { EDI, EBX } }, [EDI_ECX] = { 2, { EDI, ECX } }, [EDI_EDX] = { 2, { EDI, EDX } }, [EDI_ESI] = { 2, { EDI, ESI } }, [ESI_EAX] = { 2, { ESI, EAX } }, [ESI_EBX] = { 2, { ESI, EBX } }, [ESI_ECX] = { 2, { ESI, ECX } }, [ESI_EDX] = { 2, { ESI, EDX } }, [ESI_EDI] = { 2, { ESI, EDI } }, [ST0] = { 0 }, [ST1] = { 0 }, [ST2] = { 0 }, [ST3] = { 0 }, [ST4] = { 0 }, [ST5] = { 0 }, [ST6] = { 0 }, [ST7] = { 0 }, }; static const char *arch_reg_name_b[] = { [AL] = NULL, [BL] = NULL, [CL] = NULL, [DL] = NULL, [AH] = NULL, [BH] = NULL, [CH] = NULL, [DH] = NULL, [AX] = "al", [BX] = "bl", [CX] = "cl", [DX] = "dl", [DI] = NULL, [SI] = NULL, [EAX] = "al", [EBX] = "bl", [ECX] = "cl", [EDX] = "dl", [EDI] = NULL, [ESI] = NULL, [EAX_EBX] = "al", [EAX_ECX] = "al", [EAX_EDX] = "al", [EAX_EDI] = "al", [EAX_ESI] = "al", [EBX_EAX] = "bl", [EBX_ECX] = "bl", [EBX_EDX] = "bl", [EBX_EDI] = "bl", [EBX_ESI] = "bl", [ECX_EAX] = "cl", [ECX_EBX] = "cl", [ECX_EDX] = "cl", [ECX_EDI] = "cl", [ECX_ESI] = "cl", [EDX_EAX] = "dl", [EDX_EBX] = "dl", [EDX_ECX] = "dl", [EDX_EDI] = "dl", [EDX_ESI] = "dl", [EDI_EAX] = NULL, [EDI_EBX] = NULL, [EDI_ECX] = NULL, [EDI_EDX] = NULL, [EDI_ESI] = NULL, [ESI_EAX] = NULL, [ESI_EBX] = NULL, [ESI_ECX] = NULL, [ESI_EDX] = NULL, [ESI_EDI] = NULL, [ST0] = NULL, [ST1] = NULL, [ST2] = NULL, [ST3] = NULL, [ST4] = NULL, [ST5] = NULL, [ST6] = NULL, [ST7] = NULL, }; static const char *arch_reg_name_h[] = { [AL] = NULL, [BL] = NULL, [CL] = NULL, [DL] = NULL, [AH] = NULL, [BH] = NULL, [CH] = NULL, [DH] = NULL, [AX] = "ah", [BX] = "bh", [CX] = "ch", [DX] = "dh", [DI] = NULL, [SI] = NULL, [EAX] = "ah", [EBX] = "bh", [ECX] = "ch", [EDX] = "dh", [EDI] = NULL, [ESI] = NULL, [EAX_EBX] = "ah", [EAX_ECX] = "ah", [EAX_EDX] = "ah", [EAX_EDI] = "ah", [EAX_ESI] = "ah", [EBX_EAX] = "bh", [EBX_ECX] = "bh", [EBX_EDX] = "bh", [EBX_EDI] = "bh", [EBX_ESI] = "bh", [ECX_EAX] = "ch", [ECX_EBX] = "ch", [ECX_EDX] = "ch", [ECX_EDI] = "ch", [ECX_ESI] = "ch", [EDX_EAX] = "dh", [EDX_EBX] = "dh", [EDX_ECX] = "dh", [EDX_EDI] = "dh", [EDX_ESI] = "dh", [EDI_EAX] = NULL, [EDI_EBX] = NULL, [EDI_ECX] = NULL, [EDI_EDX] = NULL, [EDI_ESI] = NULL, [ESI_EAX] = NULL, [ESI_EBX] = NULL, [ESI_ECX] = NULL, [ESI_EDX] = NULL, [ESI_EDI] = NULL, [ST0] = NULL, [ST1] = NULL, [ST2] = NULL, [ST3] = NULL, [ST4] = NULL, [ST5] = NULL, [ST6] = NULL, [ST7] = NULL, }; static const char *arch_reg_name_w[] = { [AL] = NULL, [BL] = NULL, [CL] = NULL, [DL] = NULL, [AH] = NULL, [BH] = NULL, [CH] = NULL, [DH] = NULL, [AX] = NULL, [BX] = NULL, [CX] = NULL, [DX] = NULL, [DI] = NULL, [SI] = NULL, [EAX] = "ax", [EBX] = "bx", [ECX] = "cx", [EDX] = "dx", [EDI] = "di", [ESI] = "si", [EAX_EBX] = "ax", [EAX_ECX] = "ax", [EAX_EDX] = "ax", [EAX_EDI] = "ax", [EAX_ESI] = "ax", [EBX_EAX] = "bx", [EBX_ECX] = "bx", [EBX_EDX] = "bx", [EBX_EDI] = "bx", [EBX_ESI] = "bx", [ECX_EAX] = "cx", [ECX_EBX] = "cx", [ECX_EDX] = "cx", [ECX_EDI] = "cx", [ECX_ESI] = "cx", [EDX_EAX] = "dx", [EDX_EBX] = "dx", [EDX_ECX] = "dx", [EDX_EDI] = "dx", [EDX_ESI] = "dx", [EDI_EAX] = NULL, [EDI_EBX] = NULL, [EDI_ECX] = NULL, [EDI_EDX] = NULL, [EDI_ESI] = NULL, [ESI_EAX] = NULL, [ESI_EBX] = NULL, [ESI_ECX] = NULL, [ESI_EDX] = NULL, [ESI_EDI] = NULL, [ST0] = NULL, [ST1] = NULL, [ST2] = NULL, [ST3] = NULL, [ST4] = NULL, [ST5] = NULL, [ST6] = NULL, [ST7] = NULL, }; static const char *arch_reg_name_u[] = { [AL] = NULL, [BL] = NULL, [CL] = NULL, [DL] = NULL, [AH] = NULL, [BH] = NULL, [CH] = NULL, [DH] = NULL, [AX] = NULL, [BX] = NULL, [CX] = NULL, [DX] = NULL, [DI] = NULL, [SI] = NULL, [EAX] = NULL, [EBX] = NULL, [ECX] = NULL, [EDX] = NULL, [EDI] = NULL, [ESI] = NULL, [EAX_EBX] = "ebx", [EAX_ECX] = "ecx", [EAX_EDX] = "edx", [EAX_EDI] = "edi", [EAX_ESI] = "esi", [EBX_EAX] = "eax", [EBX_ECX] = "ecx", [EBX_EDX] = "edx", [EBX_EDI] = "edi", [EBX_ESI] = "esi", [ECX_EAX] = "eax", [ECX_EBX] = "ebx", [ECX_EDX] = "edx", [ECX_EDI] = "edi", [ECX_ESI] = "esi", [EDX_EAX] = "eax", [EDX_EBX] = "ebx", [EDX_ECX] = "ecx", [EDX_EDI] = "edi", [EDX_ESI] = "esi", [EDI_EAX] = "eax", [EDI_EBX] = "ebx", [EDI_ECX] = "ecx", [EDI_EDX] = "edx", [EDI_ESI] = "esi", [ESI_EAX] = "eax", [ESI_EBX] = "ebx", [ESI_ECX] = "ecx", [ESI_EDX] = "edx", [ESI_EDI] = "edi", [ST0] = NULL, [ST1] = NULL, [ST2] = NULL, [ST3] = NULL, [ST4] = NULL, [ST5] = NULL, [ST6] = NULL, [ST7] = NULL, }; static const char *arch_reg_name_def[] = { [AL] = "al", [BL] = "bl", [CL] = "cl", [DL] = "dl", [AH] = "ah", [BH] = "bh", [CH] = "ch", [DH] = "dh", [AX] = "ax", [BX] = "bx", [CX] = "cx", [DX] = "dx", [DI] = "di", [SI] = "si", [EAX] = "eax", [EBX] = "ebx", [ECX] = "ecx", [EDX] = "edx", [EDI] = "edi", [ESI] = "esi", [EAX_EBX] = "eax", [EAX_ECX] = "eax", [EAX_EDX] = "eax", [EAX_EDI] = "eax", [EAX_ESI] = "eax", [EBX_EAX] = "ebx", [EBX_ECX] = "ebx", [EBX_EDX] = "ebx", [EBX_EDI] = "ebx", [EBX_ESI] = "ebx", [ECX_EAX] = "ecx", [ECX_EBX] = "ecx", [ECX_EDX] = "ecx", [ECX_EDI] = "ecx", [ECX_ESI] = "ecx", [EDX_EAX] = "edx", [EDX_EBX] = "edx", [EDX_ECX] = "edx", [EDX_EDI] = "edx", [EDX_ESI] = "edx", [EDI_EAX] = "edi", [EDI_EBX] = "edi", [EDI_ECX] = "edi", [EDI_EDX] = "edi", [EDI_ESI] = "edi", [ESI_EAX] = "esi", [ESI_EBX] = "esi", [ESI_ECX] = "esi", [ESI_EDX] = "esi", [ESI_EDI] = "esi", }; static unsigned int arch_classinfo[] = { ['A'] = CLASS_A, ['D'] = CLASS_D, ['Q'] = CLASS_q, ['R'] = CLASS_r, ['S'] = CLASS_S, ['a'] = CLASS_a, ['b'] = CLASS_b, ['c'] = CLASS_c, ['d'] = CLASS_d, ['f'] = CLASS_f, /* FLOAT_REGS */ /* ['l'] = CLASS_l, */ /* INDEX_REG (all but %esp) - FIXME */ ['q'] = CLASS_q, ['r'] = CLASS_r, ['t'] = CLASS_t, /* %st(0) */ ['u'] = CLASS_u, /* %st(1) */ }; static unsigned int arch_typeinfo[TYPE_MAX] = { [TYPE_VA_LIST] = CLASS_r, [TYPE_INT8] = CLASS_q, [TYPE_UINT8] = CLASS_q, [TYPE_INT16] = CLASS_r, [TYPE_UINT16] = CLASS_r, [TYPE_INT32] = CLASS_r, [TYPE_UINT32] = CLASS_r, [TYPE_INT64] = CLASS_r, [TYPE_UINT64] = CLASS_r, [TYPE_FLOAT32] = CLASS_f, [TYPE_FLOAT64] = CLASS_f, [TYPE_FLOAT80] = CLASS_f, [TYPE_STRUCT] = CLASS_NONE, [TYPE_UNION] = CLASS_NONE, [TYPE_POINTER] = CLASS_r, [TYPE_ARRAY] = CLASS_NONE, [TYPE_FUNCTION] = CLASS_NONE, }; static int seg_enabled(void) { return 0; /* FIXME */ } struct type * arch_i386_type_intptr_t(void) { if (seg_enabled()) { assert(0); /* FIXME */ } else { return type_int32(); } } struct type * arch_i386_type_uintptr_t(void) { if (seg_enabled()) { assert(0); /* FIXME */ } else { return type_uint32(); } } void arch_i386_align_size( struct scope *scope, struct type *t, unsigned int *alignp, unsigned int *sizep ) { switch (t->type) { case TYPE_INT8: case TYPE_UINT8: *alignp = 1; *sizep = 1; break; case TYPE_INT16: case TYPE_UINT16: *alignp = 2; *sizep = 2; break; case TYPE_INT32: case TYPE_UINT32: *alignp = 4; *sizep = 4; break; case TYPE_INT64: case TYPE_UINT64: *alignp = 4; *sizep = 8; break; case TYPE_FLOAT32: *alignp = 4; *sizep = 4; break; case TYPE_FLOAT64: *alignp = 4; *sizep = 8; break; case TYPE_FLOAT80: *alignp = 4; *sizep = 16; break; case TYPE_VA_LIST: *alignp = 4; *sizep = 4; break; case TYPE_POINTER: *alignp = 4; *sizep = 4; break; default: assert(0); } } void arch_i386_gen_class_and_type_get( const char *name, unsigned int *classp, enum type_type *typep ) { unsigned int reg; for (reg = 0; ; reg++) { assert(reg < REG_COUNT); if (strcmp(arch_reginfo[reg].name, name) == 0) { *classp = arch_reginfo[reg].class; *typep = arch_reginfo[reg].type; break; } } } unsigned int arch_i386_gen_class_or(unsigned int a, unsigned int b) { unsigned int class; if (a == CLASS_NONE) { class = b; } else if (b == CLASS_NONE) { class = a; } else { /* FIXME */ class = 0; /* Make cppcheck happy. */ assert(0); } return class; } unsigned int arch_i386_gen_class_and(unsigned int a, unsigned int b) { unsigned int class; if (a == CLASS_f && (b == CLASS_t || b == CLASS_u || b == CLASS_st2 || b == CLASS_st3 || b == CLASS_st4 || b == CLASS_st5 || b == CLASS_st6 || b == CLASS_st7 || b == CLASS_f)) { class = b; } else if (b == CLASS_f && (a == CLASS_t || a == CLASS_u || a == CLASS_st2 || a == CLASS_st3 || a == CLASS_st4 || a == CLASS_st5 || a == CLASS_st6 || a == CLASS_st7 || a == CLASS_f)) { class = a; } else if (a == CLASS_r && (b == CLASS_A || b == CLASS_D || b == CLASS_S || b == CLASS_a || b == CLASS_b || b == CLASS_c || b == CLASS_d || b == CLASS_q || b == CLASS_r)) { class = b; } else if (b == CLASS_r && (a == CLASS_A || a == CLASS_D || a == CLASS_S || a == CLASS_a || a == CLASS_b || a == CLASS_c || a == CLASS_d || a == CLASS_q || a == CLASS_r)) { class = a; } else if (a == CLASS_q && (b == CLASS_A || b == CLASS_a || b == CLASS_b || b == CLASS_c || b == CLASS_d || b == CLASS_q || b == CLASS_r)) { class = b; } else if (b == CLASS_q && (a == CLASS_A || a == CLASS_a || a == CLASS_b || a == CLASS_c || a == CLASS_d || a == CLASS_q || a == CLASS_r)) { class = a; } else if (a == b) { class = a; } else { class = CLASS_NONE; } return class; } void arch_i386_color_init(unsigned int *count) { unsigned int class; for (class = 0; class < DECL_CLASS_COUNT; class++) { count[class] = 0; } } void arch_i386_color_add(unsigned int *count, unsigned int class, enum type_type type) { switch (class) { case CLASS_NONE: /* Memory only. */ break; case CLASS_A: assert(type == TYPE_INT64 || type == TYPE_UINT64); count[CLASS_a]++; count[CLASS_d]++; break; case CLASS_D: case CLASS_S: case CLASS_a: case CLASS_b: case CLASS_d: assert(type == TYPE_VA_LIST || type == TYPE_INT8 || type == TYPE_UINT8 || type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_INT32 || type == TYPE_UINT32 || type == TYPE_POINTER); count[class]++; break; case CLASS_c: /* FIXME */ count[CLASS_c]++; if (type == TYPE_INT64 || type == TYPE_UINT64) { count[CLASS_r]++; } break; case CLASS_f: case CLASS_t: case CLASS_u: case CLASS_st2: case CLASS_st3: case CLASS_st4: case CLASS_st5: case CLASS_st6: case CLASS_st7: assert(type == TYPE_FLOAT32 || type == TYPE_FLOAT64 || type == TYPE_FLOAT80); count[class]++; break; case CLASS_q: case CLASS_r: assert(type == TYPE_VA_LIST || type == TYPE_INT8 || type == TYPE_UINT8 || type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_INT32 || type == TYPE_UINT32 || type == TYPE_INT64 || type == TYPE_UINT64 || type == TYPE_POINTER); count[class]++; if (type == TYPE_INT64 || type == TYPE_UINT64) { count[CLASS_r]++; } break; default: fprintf(stderr, "class: %u, type: %u\n", class, type); assert(0); } } void arch_i386_color_sub(unsigned int *count, unsigned int class, enum type_type type) { switch (class) { case CLASS_NONE: /* Memory only. */ break; case CLASS_A: assert(1 <= count[CLASS_a]); assert(1 <= count[CLASS_d]); count[CLASS_a]--; count[CLASS_d]--; break; case CLASS_D: case CLASS_S: case CLASS_a: case CLASS_b: case CLASS_d: assert(1 <= count[class]); count[class]--; break; case CLASS_c: /* FIXME */ assert(1 <= count[CLASS_c]); count[CLASS_c]--; if (type == TYPE_INT64 || type == TYPE_UINT64) { assert(1 <= count[CLASS_r]); count[CLASS_r]--; } break; case CLASS_f: case CLASS_t: case CLASS_u: case CLASS_st2: case CLASS_st3: case CLASS_st4: case CLASS_st5: case CLASS_st6: case CLASS_st7: assert(1 <= count[class]); count[class]--; break; case CLASS_q: case CLASS_r: assert(1 <= count[class]); count[class]--; if (type == TYPE_INT64 || type == TYPE_UINT64) { assert(1 <= count[CLASS_r]); count[CLASS_r]--; } break; default: fprintf(stderr, "class: %u, type: %u\n", class, type); assert(0); } } int arch_i386_color_check(unsigned int *count, unsigned int class, enum type_type type) { unsigned int num; switch (class) { case CLASS_NONE: /* Memory only. */ return 0; case CLASS_A: num = (1 < count[CLASS_a]) ? 1 : count[CLASS_a]; num += (1 < count[CLASS_d]) ? 1 : count[CLASS_d]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (4 < num) num = 4; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (6 < num) num = 6; return num < 1; case CLASS_D: case CLASS_S: num = (1 < count[class]) ? 1 : count[class]; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (1 < num) num = 1; return num < 1; case CLASS_a: case CLASS_b: case CLASS_c: case CLASS_d: num = (1 < count[class]) ? 1 : count[class]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (4 < num) num = 4; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (6 < num) num = 6; return num < 1; case CLASS_f: num = (1 < count[CLASS_t]) ? 1 : count[CLASS_t]; num += (1 < count[CLASS_u]) ? 1 : count[CLASS_u]; num += (1 < count[CLASS_st2]) ? 1 : count[CLASS_st2]; num += (1 < count[CLASS_st3]) ? 1 : count[CLASS_st3]; num += (1 < count[CLASS_st4]) ? 1 : count[CLASS_st4]; num += (1 < count[CLASS_st5]) ? 1 : count[CLASS_st5]; num += (1 < count[CLASS_st6]) ? 1 : count[CLASS_st6]; num += (1 < count[CLASS_st7]) ? 1 : count[CLASS_st7]; num += (8 < count[CLASS_f]) ? 8 : count[CLASS_f]; if (8 < num) num = 8; return num < 8; break; case CLASS_q: num = (1 < count[CLASS_a]) ? 1 : count[CLASS_a]; num += (1 < count[CLASS_b]) ? 1 : count[CLASS_b]; num += (1 < count[CLASS_c]) ? 1 : count[CLASS_c]; num += (1 < count[CLASS_d]) ? 1 : count[CLASS_d]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (4 < num) num = 4; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (6 < num) num = 6; return num < 4; case CLASS_r: num = (1 < count[CLASS_a]) ? 1 : count[CLASS_a]; num += (1 < count[CLASS_b]) ? 1 : count[CLASS_b]; num += (1 < count[CLASS_c]) ? 1 : count[CLASS_c]; num += (1 < count[CLASS_d]) ? 1 : count[CLASS_d]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (4 < num) num = 4; num += (1 < count[CLASS_D]) ? 1 : count[CLASS_D]; num += (1 < count[CLASS_S]) ? 1 : count[CLASS_S]; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (6 < num) num = 6; if (type != TYPE_INT64 && type != TYPE_UINT64) { return num < 6; } else { return num < 5; } case CLASS_t: case CLASS_u: case CLASS_st2: case CLASS_st3: case CLASS_st4: case CLASS_st5: case CLASS_st6: case CLASS_st7: num = (1 < count[class]) ? 1 : count[class]; num += (8 < count[CLASS_f]) ? 8 : count[CLASS_f]; if (1 < num) num = 1; return num < 1; default: fprintf(stderr, "class: %u, type: %u\n", class, type); assert(0); } } void arch_i386_gen_reg_init(uint32_t *conflicts) { memset(conflicts, 0, (REG_COUNT + 7) / 8); } static void arch_gen_reg_add_2(uint32_t *conflicts, unsigned int reg) { unsigned int count; unsigned int reg2; *(uint64_t *) conflicts |= 1ULL << reg; for (reg2 = 0; reg2 < REG_COUNT; reg2++) { for (count = 0; count < arch_gen_reg_parts[reg2].count; count++) { if (arch_gen_reg_parts[reg2].reg[count] == reg) { arch_gen_reg_add_2(conflicts, reg2); } } } } static void arch_gen_reg_add_1(uint32_t *conflicts, unsigned int reg) { if (arch_gen_reg_parts[reg].count == 0) { arch_gen_reg_add_2(conflicts, reg); } else { unsigned int count; unsigned int reg2; for (count = 0; count < arch_gen_reg_parts[reg].count; count++) { reg2 = arch_gen_reg_parts[reg].reg[count]; arch_gen_reg_add_1(conflicts, reg2); } } } void arch_i386_gen_reg_add(uint32_t *conflicts, unsigned int reg) { arch_gen_reg_add_1(conflicts, reg); } int arch_i386_gen_reg_get( uint32_t *conflicts, unsigned int class, enum type_type type ) { uint64_t regs; unsigned int reg; switch (class) { case CLASS_NONE: regs = 0; break; case CLASS_A: regs = REG_A; break; case CLASS_D: regs = REG_D; break; case CLASS_S: regs = REG_S; break; case CLASS_a: regs = REG_a; break; case CLASS_b: regs = REG_b; break; case CLASS_c: regs = REG_c; break; case CLASS_d: regs = REG_d; break; case CLASS_f: regs = REG_f; break; case CLASS_q: regs = REG_q; break; case CLASS_r: regs = REG_r; break; case CLASS_t: regs = REG_t; break; case CLASS_u: regs = REG_u; break; case CLASS_st2: regs = REG_st2; break; case CLASS_st3: regs = REG_st3; break; case CLASS_st4: regs = REG_st4; break; case CLASS_st5: regs = REG_st5; break; case CLASS_st6: regs = REG_st6; break; case CLASS_st7: regs = REG_st7; break; default: assert(0); break; } switch (type) { case TYPE_NONE: regs &= 0; break; case TYPE_INT8: case TYPE_UINT8: regs &= REG_8; break; case TYPE_INT16: case TYPE_UINT16: regs &= REG_16; break; case TYPE_INT32: case TYPE_UINT32: regs &= REG_32; break; case TYPE_INT64: case TYPE_UINT64: regs &= REG_64; break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: regs &= REG_f; break; case TYPE_UNION: regs &= 0; break; case TYPE_STRUCT: regs &= 0; break; case TYPE_ARRAY: regs &= 0; break; case TYPE_FUNCTION: regs &= 0; break; case TYPE_VA_LIST: regs &= REG_32; break; case TYPE_POINTER: regs &= REG_32; break; default: assert(0); break; } regs &= ~ *(uint64_t *) conflicts; for (reg = 0; ; reg++) { if (reg == REG_COUNT) { return -1; } if ((regs >> reg) & 1) { return reg; } } } static const char * arch_gen_name(unsigned int local, const char *prefix, const char *name) { static unsigned int rand = 0; static char buf[10][1024]; static unsigned int cur = 0; char *retval; if (! rand) { struct timeval tv; int ret; ret = gettimeofday(&tv, NULL); assert(0 <= ret); rand = tv.tv_sec ^ tv.tv_usec; } retval = buf[cur]; cur = (cur + 1) % 10; if (prefix) { strcpy(retval, prefix); strcat(retval, "_"); } else { strcpy(retval, ""); } if (local && seg_enabled()) { sprintf(retval + strlen(retval), "L%08x_", rand); } strcat(retval, name); return retval; } static void arch_gen_name_def(int local, const char *name) { } static void arch_gen_local_def(const char *name) { arch_gen_name_def(1, name); } static const char * arch_gen_local(const char *name) { return arch_gen_name(1, NULL, name); } static const char * arch_gen_local_seg(const char *name) { assert(seg_enabled()); return arch_gen_name(1, "SEG", name); } static const char * arch_gen_local_off(const char *name) { if (seg_enabled()) { return arch_gen_name(1, "OFF", name); } else { return arch_gen_name(1, NULL, name); } } static void arch_gen_global_def(const char *name) { arch_gen_name_def(0, name); } static const char * arch_gen_global(const char *name) { return arch_gen_name(0, NULL, name); } static const char * arch_gen_global_seg(const char *name) { assert(seg_enabled()); return arch_gen_name(0, "SEG", name); } static const char * arch_gen_global_off(const char *name) { if (seg_enabled()) { return arch_gen_name(0, "OFF", name); } else { return arch_gen_name(0, NULL, name); } } static void arch_gen_data_init( FILE *fp, struct scope *scope, struct type *t, struct expr *e ) { struct declaration *dion; switch (t->type) { case TYPE_NONE: case TYPE_ELIPSIS: case TYPE_VOID: case TYPE_UNION: case TYPE_ENUM: case TYPE_FUNCTION: case TYPE_MAX: assert(0); case TYPE_INT8: case TYPE_UINT8: if (e) { assert(e->type == EXPR_INTEGER); fprintf(fp, "\t.byte 0x%02x\n", (uint8_t) e->integer); } else { fprintf(fp, "\t.byte 0x00\n"); } break; case TYPE_INT16: case TYPE_UINT16: if (e) { switch (e->type) { case EXPR_INTEGER: fprintf(fp, "\t.word 0x%04x\n", (uint16_t) e->integer); break; case EXPR_TYPE_CONVERSION: assert(0); /* FIXME */ break; default: assert(0); } } else { fprintf(fp, "\t.word 0x0000\n"); } break; case TYPE_INT32: case TYPE_UINT32: if (e) { switch (e->type) { case EXPR_INTEGER: fprintf(fp, "\t.long 0x%08x\n", (uint32_t) e->integer); break; case EXPR_TYPE_CONVERSION: if (e->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ dion = e->expr0->expr0->declaration; } else if (e->expr0->type == EXPR_IDENTIFIER) { /* * Special case: (int) array * Special case: (int) func */ dion = e->expr0->declaration; } else { dion = NULL; } assert(dion); fprintf(fp, "\t.long %s\n", dion->identifier); break; default: assert(0); } } else { fprintf(fp, "\t.long 0x00000000\n"); } break; case TYPE_INT64: case TYPE_UINT64: if (e) { switch (e->type) { case EXPR_INTEGER: fprintf(fp, "\t.long 0x%08x, 0x%08x\n", (uint32_t) (e->integer >> 0), (uint32_t) (e->integer >> 32)); break; default: assert(0); } } else { fprintf(fp, "\t.long 0x00000000, 0x00000000\n"); } break; case TYPE_FLOAT32: if (e) { assert(e->type == EXPR_REAL); fprintf(fp, "\t.float %Le\n", e->real); } else { fprintf(fp, "\t.float 0.0\n"); } break; case TYPE_FLOAT64: if (e) { assert(e->type == EXPR_REAL); fprintf(fp, "\t.dfloat %Le\n", e->real); } else { fprintf(fp, "\t.dfloat 0.0\n"); } break; case TYPE_FLOAT80: /* 10 Bytes Data */ if (e) { assert(e->type == EXPR_REAL); fprintf(fp, "\t.tfloat %Le\n", e->real); } else { fprintf(fp, "\t.tfloat 0.0\n"); } /* 6 Bytes Alignment */ fprintf(fp, "\t.byte 0, 0, 0, 0, 0, 0\n"); break; case TYPE_STRUCT: { struct expr *ce; if (! t->scope) { int ret; ret = scope_lookup_structunionenum(scope, t->type, t->identifier, &t); assert(0 <= ret); } assert(t->scope); for (dion = t->scope->declaration_first, ce = e->first; dion; dion = dion->next, ce = (ce ? ce->next : NULL)) { arch_gen_data_init(fp, scope, dion->type_name, ce); } break; } case TYPE_VA_LIST: case TYPE_POINTER: assert(0); break; case TYPE_ARRAY: { unsigned long long dim; struct expr *ce; unsigned long long i; unsigned char c; assert(t->dimension); assert(t->dimension->type == EXPR_INTEGER); dim = t->dimension->integer; t = type_array_access(t); switch (e->type) { case EXPR_BRACES: for (i = 0, ce = e->first; i < dim; i++, ce = (ce ? ce->next : NULL)) { arch_gen_data_init(fp, scope, t, ce); } break; case EXPR_STRING: assert(t->type == TYPE_INT8 || t->type == TYPE_UINT8); fprintf(fp, "\t.string \""); for (i = 0; i < dim; i++) { if (i < e->string_len) { c = e->string[i]; } else { c = '\0'; } switch (c) { case '\0': fprintf(fp, "\\0"); break; case '\a': fprintf(fp, "\\a"); break; case '\b': fprintf(fp, "\\b"); break; case '\n': fprintf(fp, "\\n"); break; case '\r': fprintf(fp, "\\r"); break; case '\t': fprintf(fp, "\\t"); break; case '"': fprintf(fp, "\\\""); break; case '\\': fprintf(fp, "\\\\"); break; default: if (' ' <= c && c < 127) { fprintf(fp, "%c", c); } else { fprintf(fp, "\\%03o", c); } } } fprintf(fp, "\"\n"); break; default: assert(0); } break; } default: assert(0); } } static void arch_gen_data(FILE *fp, struct scope *scope, struct declaration *dion) { unsigned int align; unsigned int size; type_align_size(scope, dion->type_name, &align, &size); if (dion->attr_aligned) { align = dion->attr_aligned; } if (dion->type_name->mod_const) { fprintf(fp, "\t.section .rodata\n"); } else { fprintf(fp, "\t.data\n"); } if (dion->initializer) { if (dion->storage == STORAGE_STATIC) { /* * NOTE: * Label *must* be global. Otherwise our * linker tool will not generate __SEG_x/__OFF_x * symbols for it. */ fprintf(fp, "\t.globl %s\n", arch_gen_local(dion->identifier)); fprintf(fp, "\t.align %u\n", align); fprintf(fp, "\t.type %s, @object\n", arch_gen_local(dion->identifier)); fprintf(fp, "\t.size %s, %u\n", arch_gen_local(dion->identifier), size); fprintf(fp, "%s:\n", arch_gen_local(dion->identifier)); } else { fprintf(fp, "\t.globl %s\n", arch_gen_global(dion->identifier)); fprintf(fp, "\t.align %u\n", align); fprintf(fp, "\t.type %s, @object\n", arch_gen_global(dion->identifier)); fprintf(fp, "\t.size %s, %u\n", arch_gen_global(dion->identifier), size); fprintf(fp, "%s:\n", arch_gen_global(dion->identifier)); } arch_gen_data_init(fp, scope, dion->type_name, dion->initializer); } else { if (dion->storage == STORAGE_STATIC) { fprintf(fp, "\t.local %s\n", arch_gen_local(dion->identifier)); fprintf(fp, "\t.comm %s, %u, %u\n", arch_gen_local(dion->identifier), size, align); } else { fprintf(fp, "\t.comm %s, %u, %u\n", arch_gen_global(dion->identifier), size, align); } } } static struct declaration * arch_tmp(struct scope *s, struct type *t) { struct declaration *var; var = simplify_declaration_add(s, t, identifier_tmp()); var->storage = STORAGE_AUTO; return var; } static void arch_op_func( struct expr *e, struct declaration *dion ) { struct expr *ce0; struct expr *ce1; ce0 = e->expr0; ce1 = e->expr1; e->type = EXPR_FUNC; e->expr0 = expr_new(); e->expr0->type = EXPR_IDENTIFIER; e->expr0->declaration = dion; e->expr1 = expr_new(); e->expr1->type = EXPR_LIST; ce0->prev = NULL; ce0->next = ce1; ce1->prev = ce0; ce1->next = NULL; e->expr1->first = ce0; e->expr1->last = ce1; } static void arch_gen_expr_1( struct stmt *block, struct stmt *s, struct expr *e, struct expr *lhs ) { struct type *t; struct type *t1; struct expr *ce; struct declaration *var; struct declaration *var0; struct declaration *var1; struct declaration *var2; struct declaration *dion; uint64_t regs_change; unsigned int reg; t = expr_typeof(block->scope, e); t = type_pure(t); assert(lhs || e->type == EXPR_FUNC); if (lhs && lhs->type == EXPR_IDENTIFIER && (lhs->declaration->storage == STORAGE_STATIC || lhs->declaration->storage == STORAGE_NONE || lhs->declaration->storage == STORAGE_EXTERN)) { /* * Store Operation */ assert(e->type == EXPR_INTEGER || e->type == EXPR_REAL || e->type == EXPR_IDENTIFIER); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * movb %1, %0 */ constraint_input(s, "m", expr_dup(lhs)); constraint_input(s, "iq", expr_dup(e)); break; case TYPE_INT16: case TYPE_UINT16: /* * movw %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * movl %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movl %1, %0 * movl %u1, %u0 */ constraint_input(s, "m", expr_dup(lhs)); constraint_input(s, "ir", expr_dup(e)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ case TYPE_VA_LIST: assert(0); /* FIXME */ default: assert(0); /* Mustn't happen. */ } } else if (e->type == EXPR_IDENTIFIER && (e->declaration->storage == STORAGE_STATIC || e->declaration->storage == STORAGE_NONE || e->declaration->storage == STORAGE_EXTERN)) { /* * Load Operation */ assert(lhs && lhs->type == EXPR_IDENTIFIER && lhs->declaration->storage != STORAGE_STATIC && lhs->declaration->storage != STORAGE_NONE && lhs->declaration->storage != STORAGE_EXTERN); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * movb %1, %0 */ /*FALLTHROUGN*/ case TYPE_INT16: case TYPE_UINT16: /* * movw %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * movl %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movl %1, %0 * movl %u1, %u0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "m", expr_dup(e)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ case TYPE_VA_LIST: assert(0); /* FIXME */ default: assert(0); /* Mustn't happen. */ } } else { /* * Non-Load/Non-Store Operation */ switch (e->type) { case EXPR_NONE: case EXPR_BRACES: case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_ASSIGN: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: case EXPR_NOT: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_LIST: case EXPR_STRING: case EXPR_AMPHERSAND: assert(0); break; case EXPR_INTEGER: case EXPR_REAL: case EXPR_IDENTIFIER: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * movb %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * movw %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * movl %1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "imr", expr_dup(e)); break; case TYPE_INT64: case TYPE_UINT64: /* * movl %1, %0 * movl %u1, %u0 */ constraint_output(s, "=&r", expr_dup(lhs)); constraint_input(s, "imr", expr_dup(e)); break; case TYPE_FLOAT32: /* * fsts %0 */ case TYPE_FLOAT64: /* * fstl %0 */ case TYPE_FLOAT80: /* * fstt %0 */ constraint_output(s, "=m", expr_dup(lhs)); constraint_input(s, "it", expr_dup(e)); break; default: assert(0); } break; case EXPR_BUILTIN_VA_ARG: t1 = e->type_name; switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: /* * movb (%1), %0 * addl $4, %1 */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * movw (%1), %0 * addl $4, %1 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * movl (%1), %0 * addl $4, %1 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movl (%1), %0 * movl 4(%1), %u0 * addl $8, %1 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_output(s, "=r", expr_dup(e->expr0)); constraint_input(s, "1", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_TYPE_CONVERSION: if (e->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ dion = e->expr0->expr0->declaration; e = e->expr0->expr0; goto special; } else if (e->expr0->type == EXPR_IDENTIFIER && (e->expr0->declaration->type_name->type == TYPE_ARRAY || e->expr0->declaration->type_name->type == TYPE_FUNCTION)) { /* * Special case: (int) array * Special case: (int) function */ dion = e->expr0->declaration; e = e->expr0; special: if (dion->storage == STORAGE_NONE || dion->storage == STORAGE_EXTERN || dion->storage == STORAGE_STATIC) { /* * movl $%1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "m", expr_dup(e)); } else { /* * leal %1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "m", expr_dup(e)); } break; } t1 = expr_typeof(block->scope, e->expr0); t1 = type_pure(t1); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: /* * No code. */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; case TYPE_INT16: case TYPE_UINT16: /* * movb %b1, %0 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * movb %b1, %0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movb %b1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mq", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT16: case TYPE_UINT16: switch (t1->type) { case TYPE_INT8: /* * movsbw %1, %0 */ /*FALLTHROUGH*/ case TYPE_UINT8: /* * movzbw %1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mq", expr_dup(e->expr0)); break; case TYPE_INT16: case TYPE_UINT16: /* * No code. */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; case TYPE_INT32: case TYPE_UINT32: /* * movw %w1, %0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movw %w1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: /* * fnstcw %0 switch cntrl word * movw %0, %2 * orw $0xc00, %2 * movw %2, %1 * fldcw %1 * * fistps %3 * * fldcw %0 switch back */ goto type_conv_float_to_int; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT32: case TYPE_UINT32: switch (t1->type) { case TYPE_INT8: /* * movsbl %1, %0 */ /*FALLTHROUGH*/ case TYPE_UINT8: /* * movzbl %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT16: /* * movswl %1, %0 */ /*FALLTHROUGH*/ case TYPE_UINT16: /* * movzwl %1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_INT32: case TYPE_UINT32: /* * No code. */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; case TYPE_INT64: case TYPE_UINT64: /* * movl %1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: /* * fnstcw %0 switch cntrl word * movw %0, %2 * orw $0xc00, %2 * movw %2, %1 * fldcw %1 * * fistpl %3 * * fldcw %0 switch back */ goto type_conv_float_to_int; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT64: case TYPE_UINT64: switch (t1->type) { case TYPE_INT8: /* * movsbl %1, %eax * cltd */ constraint_output(s, "=A", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_UINT8: /* * movzbl %1, %0 * xorl %u0, %u0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_INT16: /* * movswl %1, %eax * cltd */ constraint_output(s, "=A", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_UINT16: /* * movzwl %1, %0 * xorl %u0, %u0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_INT32: /* * movl %1, %eax * cltd */ constraint_output(s, "=A", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_UINT32: /* * movl %1, %0 * xorl %u0, %u0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_INT64: case TYPE_UINT64: /* * No code. */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: /* * fnstcw %0 switch cntrl word * movw %0, %2 * orw $0xc00, %2 * movw %2, %1 * fldcw %1 * * fistpll %3 * * fldcw %0 switch back */ type_conv_float_to_int:; var0 = arch_tmp(block->scope, type_uint16()); var1 = arch_tmp(block->scope, type_uint16()); var2 = arch_tmp(block->scope, type_uint16()); constraint_output(s, "=m", expr_identifier(var0)); constraint_output(s, "=m", expr_identifier(var1)); constraint_output(s, "=r", expr_identifier(var2)); constraint_output(s, "=m", expr_dup(lhs)); constraint_input(s, "t", expr_dup(e->expr0)); break; default: assert(0); } break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: case TYPE_POINTER: case TYPE_INT64: case TYPE_UINT64: assert(0); /* FIXME */ break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: /* * No code. Constraint only. */ constraint_output(s, "=t", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; default: assert(0); } break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_STAR: assert(lhs); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * movb (%1), %0 */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * movw (%1), %0 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * movl (%1), %0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movl (%1), %0 * movl 4(%1), %u0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "r", expr_dup(e->expr0->expr0)); break; case TYPE_FLOAT32: /* * movl (%2), %0 * movl %0, %1 * * flds (%2) * * flds (%2) * fstp %1 */ goto star_float; case TYPE_FLOAT64: /* * movl (%2), %0 * movl %0, %1 * movl 4(%2), %0 * movl %0, 4+%1 * * fldl (%2) * * fldl (%2) * fstp %1 */ goto star_float; case TYPE_FLOAT80: /* * movl (%2), %0 * movl %0, %1 * movl 4(%2), %0 * movl %0, 4+%1 * movl 8+(%2), %0 * movl %0, 8+%1 * movl 12+(%2), %0 * movl %0, 12+%1 * * fldt (%2) * * fldt (%2) * fstp %1 */ star_float:; var = arch_tmp(block->scope, type_uint32()); constraint_output(s, "=&r", expr_identifier(var)); constraint_output(s, "=fm", expr_dup(lhs)); constraint_input(s, "r", expr_dup(e->expr0->expr0)); break; default: assert(0); } break; case EXPR_NEG: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: /* * neg{b,w,l} %0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * negl %0 * adcl $0, %u0 * negl %u0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } case EXPR_INV: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * xorb $-1, %0 */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * xorw $-1, %0 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * xorl $-1, %0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * xorl $-1, %0 * xorl $-1, %u0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; default: assert(0); } break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: if (e->expr0->type == EXPR_INTEGER || e->expr0->type == EXPR_REAL) { /* Exchange lhs/rhs. */ struct expr *tmp; tmp = e->expr0; e->expr0 = e->expr1; e->expr1 = tmp; switch (e->type) { case EXPR_EQUAL: break; case EXPR_NOT_EQUAL: break; case EXPR_LESS: e->type = EXPR_GREATER; break; case EXPR_LESS_EQUAL: e->type = EXPR_GREATER_EQUAL; break; case EXPR_GREATER: e->type = EXPR_LESS; break; case EXPR_GREATER_EQUAL: e->type = EXPR_LESS_EQUAL; break; default: assert(0); } } switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * cmp{b,w,l} %3, %2 * setcc %1 * movb %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * cmp{b,w,l} %3, %2 * setcc %1 * movzbw %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * cmp{b,w,l} %3, %2 * setcc %1 * movzb{b,w,l} %1, %0 */ var = arch_tmp(block->scope, type_char()); constraint_output(s, "=r", expr_dup(lhs)); constraint_output(s, "=rm", expr_identifier(var)); constraint_input(s, "ri", expr_dup(e->expr0)); constraint_input(s, "rm", expr_dup(e->expr1)); break; case TYPE_INT64: case TYPE_UINT64: /* * cmpw %w2, %w1 * jcc 2f * ... * 1: * movw $1, %0 * jmp 3f * 2: * xorw %0, %0 * 3: */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "r", expr_dup(e->expr0)); constraint_input(s, "ri", expr_dup(e->expr1)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_LEFT: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: /* * shl{b,w,l} %b2, %0 */ goto shift_int; case TYPE_INT64: case TYPE_UINT64: /* * shldl %0, %u0 * sall %b2, %0 * testb $32, %b2 * je 1f * movl %0, %u0 * xorl %0, %0 * 1: */ goto shift_int; default: assert(0); } break; case EXPR_RIGHT: switch (t->type) { case TYPE_INT8: case TYPE_INT16: case TYPE_INT32: /* * sar{b,w,l} %b2, %0 */ goto shift_int; case TYPE_UINT8: case TYPE_UINT16: case TYPE_UINT32: /* * shr{b,w,l} %b2, %0 */ goto shift_int; case TYPE_INT64: /* * shrdl %u0, %0 * sarl %b2, %u0 * testb $32, %b2 * je 1f * movl %u0, %0 * sarl $31, %u0 * 1: */ goto shift_int; case TYPE_UINT64: /* * shrdl %u0, %0 * shrl %b2, %u0 * testb $32, %b2 * je 1f * movl %u0, %0 * xorl %u0, %u0 * 1: */ shift_int: constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "ci", expr_dup(e->expr1)); break; default: assert(0); } break; case EXPR_ADD: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * addb %2, %0 */ goto sub_int; case TYPE_INT16: case TYPE_UINT16: /* * addw %2, %0 */ goto sub_int; case TYPE_INT32: case TYPE_UINT32: /* * addl %2, %0 */ goto sub_int; case TYPE_INT64: case TYPE_UINT64: /* * addl %2, %0 * adcl %u2, %u0 */ goto sub_int; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: /* * faddp */ goto sub_float; default: assert(0); } break; case EXPR_SUB: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * subb %2, %0 */ goto sub_int; case TYPE_INT16: case TYPE_UINT16: /* * subw %2, %0 */ goto sub_int; case TYPE_INT32: case TYPE_UINT32: /* * subl %2, %0 */ goto sub_int; case TYPE_INT64: case TYPE_UINT64: /* * subl %2, %0 * sbbl %u2, %u0 */ sub_int: constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "imr", expr_dup(e->expr1)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: /* * fsubp */ sub_float:; constraint_output(s, "=t", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "u", expr_dup(e->expr1)); /* constraint_change(s, "st(1)"); FIXME */ break; default: assert(0); } break; case EXPR_MUL: switch (t->type) { case TYPE_INT8: /* * imulb %2 */ /*FALLTHROUGH*/ case TYPE_UINT8: /* * mulb %2 */ /*FALLTHROUGH*/ case TYPE_INT16: /* * imulw %2 */ /*FALLTHROUGH*/ case TYPE_UINT16: /* * mulw %2 */ /*FALLTHROUGH*/ case TYPE_INT32: /* * imull %2 */ /*FALLTHROUGH*/ case TYPE_UINT32: /* * mull %2 */ constraint_output(s, "=a", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); constraint_change(s, "edx"); break; case TYPE_INT64: arch_op_func(e, arch_mul_int64); goto func; case TYPE_UINT64: arch_op_func(e, arch_mul_uint64); goto func; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_DIV: switch (t->type) { case TYPE_INT8: /* * cbw * idivb %2 */ /*FALLTHROUGN*/ case TYPE_UINT8: /* * xorb %%ah, %%ah * divb %2 */ constraint_output(s, "=a", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); constraint_change(s, "ah"); break; case TYPE_INT16: /* * cwd * idivw %2 */ /*FALLTHROUGH*/ case TYPE_UINT16: /* * xorw %%dx, %%dx * divw %2 */ constraint_output(s, "=a", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); constraint_change(s, "dx"); break; case TYPE_INT32: /* * cltd * idivl %2 */ /*FALLTHROUGH*/ case TYPE_UINT32: /* * xorl %%edx, %%edx * divl %2 */ constraint_output(s, "=a", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); constraint_change(s, "edx"); break; case TYPE_INT64: arch_op_func(e, arch_div_int64); goto func; case TYPE_UINT64: arch_op_func(e, arch_div_uint64); goto func; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_MOD: switch (t->type) { case TYPE_INT8: /* * cbw * idiv %2 * movb %%ah, %%al */ /*FALLTHROUGH*/ case TYPE_UINT8: /* * xorb %%ah, %%ah * div %2 * movb %%ah, %%al */ constraint_output(s, "=a", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); constraint_change(s, "ah"); break; case TYPE_INT16: /* * cwd * idivw %2 */ /*FALLTHROUGH*/ case TYPE_UINT16: /* * xorw %%dx, %%dx * divw %3 */ var = arch_tmp(block->scope, type_uint16()); constraint_output(s, "=a", expr_identifier(var)); constraint_output(s, "=&d", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); break; case TYPE_INT32: /* * cltd * idivl %3 */ /*FALLTHROUGH*/ case TYPE_UINT32: /* * xorl %%edx, %%edx * divl %3 */ var = arch_tmp(block->scope, type_uint32()); constraint_output(s, "=a", expr_identifier(var)); constraint_output(s, "=&d", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "rm", expr_dup(e->expr1)); break; case TYPE_INT64: arch_op_func(e, arch_mod_int64); goto func; case TYPE_UINT64: arch_op_func(e, arch_mod_uint64); goto func; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_AND: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * andb %2, %0 */ goto sub_int; case TYPE_INT16: case TYPE_UINT16: /* * andw %2, %0 */ goto sub_int; case TYPE_INT32: case TYPE_UINT32: /* * andl %2, %0 */ goto sub_int; case TYPE_INT64: case TYPE_UINT64: /* * andl %2, %0 * andl %u2, %u0 */ goto sub_int; default: assert(0); } break; case EXPR_OR: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * orb %2, %0 */ goto sub_int; case TYPE_INT16: case TYPE_UINT16: /* * orw %2, %0 */ goto sub_int; case TYPE_INT32: case TYPE_UINT32: /* * orl %2, %0 */ goto sub_int; case TYPE_INT64: case TYPE_UINT64: /* * orl %2, %0 * orl %u2, %u0 */ goto sub_int; default: assert(0); } break; case EXPR_XOR: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * xorb %2, %0 */ goto sub_int; case TYPE_INT16: case TYPE_UINT16: /* * xorw %2, %0 */ goto sub_int; case TYPE_INT32: case TYPE_UINT32: /* * xorl %2, %0 */ goto sub_int; case TYPE_INT64: case TYPE_UINT64: /* * xorl %2, %0 * xorl %u2, %u0 */ goto sub_int; default: assert(0); } break; case EXPR_FUNC: func: ; /* * pushl %N-1 * pushl %N-2 * ... * pushl %1 * call %0 * addl $c, %esp */ regs_change = REG_CALLER; if (lhs) { switch (t->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: constraint_output(s, "=a", expr_dup(lhs)); regs_change &= ~(1ULL << EAX); break; case TYPE_INT64: case TYPE_UINT64: constraint_output(s, "=A", expr_dup(lhs)); regs_change &= ~((1ULL << EAX) | (1ULL << EDX)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: constraint_output(s, "=t", expr_dup(lhs)); regs_change &= ~(1ULL << ST0); break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } } switch (e->expr0->type) { case EXPR_IDENTIFIER: break; case EXPR_STAR: constraint_input(s, "r", expr_dup(e->expr0->expr0->expr0)); break; default: assert(0); } for (ce = e->expr1->first; ce; ce = ce->next) { constraint_input(s, "rmi", expr_dup(ce)); } constraint_change(s, "memory"); for (reg = 0; regs_change; reg++) { if ((regs_change >> reg) & 1) { constraint_change(s, arch_reginfo[reg].name); regs_change &= ~(1ULL << reg); } } break; default: assert(0); } } } static void arch_gen_expr_2( char *buf0, struct stmt *block, struct stmt *s, struct expr *e, struct expr *lhs ) { struct type *t; struct type *t1; struct expr *ce; unsigned int size; struct constraint *c; int reglhs; int reg; int reg0; int reg1; unsigned int n; assert(lhs || e->type == EXPR_FUNC); t = expr_typeof(block->scope, e); t = type_pure(t); if (lhs && lhs->type == EXPR_IDENTIFIER && lhs->declaration->storage == STORAGE_REGISTER) { reglhs = lhs->declaration->storage_register; } else { reglhs = -1; } if (e->type == EXPR_IDENTIFIER && e->declaration->storage == STORAGE_REGISTER) { reg = e->declaration->storage_register; } else { reg = -1; } if (e->expr0 && e->expr0->type == EXPR_IDENTIFIER && e->expr0->declaration->storage == STORAGE_REGISTER) { reg0 = e->expr0->declaration->storage_register; } else { reg0 = -1; } if (e->expr1 && e->expr1->type == EXPR_IDENTIFIER && e->expr1->declaration->storage == STORAGE_REGISTER) { reg1 = e->expr1->declaration->storage_register; } else { reg1 = -1; } if (lhs && lhs->type == EXPR_IDENTIFIER && (lhs->declaration->storage == STORAGE_STATIC || lhs->declaration->storage == STORAGE_NONE || lhs->declaration->storage == STORAGE_EXTERN)) { /* * Store Operation */ assert(e->type == EXPR_INTEGER || e->type == EXPR_REAL || e->type == EXPR_IDENTIFIER); strcpy(buf0, ""); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcat(buf0, "\tmovb %1, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcat(buf0, "\tmovw %1, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcat(buf0, "\tmovl %1, %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcat(buf0, "\tmovl %1, %0\n"); strcat(buf0, "\tmovl %u1, 4+%0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ case TYPE_VA_LIST: assert(0); /* FIXME */ default: assert(0); } } else if (e->type == EXPR_IDENTIFIER && (e->declaration->storage == STORAGE_STATIC || e->declaration->storage == STORAGE_NONE || e->declaration->storage == STORAGE_EXTERN)) { /* * Load Operation */ assert(lhs && lhs->type == EXPR_IDENTIFIER && lhs->declaration->storage != STORAGE_STATIC && lhs->declaration->storage != STORAGE_NONE && lhs->declaration->storage != STORAGE_EXTERN); strcpy(buf0, ""); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcat(buf0, "\tmovb %1, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcat(buf0, "\tmovw %1, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcat(buf0, "\tmovl %1, %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcat(buf0, "\tmovl %1, %0\n"); strcat(buf0, "\tmovl 4+%1, %u0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ case TYPE_VA_LIST: assert(0); /* FIXME */ default: assert(0); /* Mustn't happen. */ } } else { /* * Non-Load/Non-Store Operation */ switch (e->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_ASSIGN: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: case EXPR_NOT: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_LIST: assert(0); case EXPR_STRING: assert(0); case EXPR_AMPHERSAND: assert(0); case EXPR_INTEGER: case EXPR_REAL: simple_copy: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tmovb %1, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tmovw %1, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tmovl %1, %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovl %1, %0\n"); strcat(buf0, "\tmovl %u1, %u0\n"); break; case TYPE_FLOAT32: strcpy(buf0, "\tfstps %0\n"); break; case TYPE_FLOAT64: strcpy(buf0, "\tfstpl %0\n"); break; case TYPE_FLOAT80: strcpy(buf0, "\tfstpt %0\n"); break; case TYPE_VA_LIST: strcpy(buf0, "\tmovl %1, %0\n"); break; default: assert(0); } break; case EXPR_IDENTIFIER: if (reglhs == -1 || reg == -1) { goto simple_copy; } switch (t->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: case TYPE_VA_LIST: /* * Only one register to copy => simple. */ if (reglhs == reg) { /* * Omit instructions "mov %x, %x". */ strcpy(buf0, ""); break; } else { goto simple_copy; } case TYPE_INT64: case TYPE_UINT64: /* * We have *two* registers in * *two* real registers * (e.g. EAX_EBX and EBX_ECX). */ assert(arch_gen_reg_parts[reglhs].count == 2); assert(arch_gen_reg_parts[reg].count == 2); if (arch_gen_reg_parts[reglhs].reg[0] == arch_gen_reg_parts[reg].reg[0] && arch_gen_reg_parts[reglhs].reg[1] == arch_gen_reg_parts[reg].reg[1]) { /* A_B <- A_B. */ strcpy(buf0, ""); } else if (arch_gen_reg_parts[reglhs].reg[0] == arch_gen_reg_parts[reg].reg[1] && arch_gen_reg_parts[reglhs].reg[1] == arch_gen_reg_parts[reg].reg[0]) { /* A_B <- B_A. */ strcpy(buf0, "\txchgl %1, %0\n"); } else if (arch_gen_reg_parts[reglhs].reg[0] == arch_gen_reg_parts[reg].reg[0]) { /* A_B <- A_C. */ strcpy(buf0, "\tmovl %u1, %u0\n"); } else if (arch_gen_reg_parts[reglhs].reg[1] == arch_gen_reg_parts[reg].reg[1]) { /* A_B <- C_B. */ strcpy(buf0, "\tmovl %1, %0\n"); } else if (arch_gen_reg_parts[reglhs].reg[0] == arch_gen_reg_parts[reg].reg[1]) { /* A_B <- C_A. */ strcpy(buf0, "\tmovl %u1, %u0\n"); strcat(buf0, "\tmovl %1, %0\n"); } else if (arch_gen_reg_parts[reglhs].reg[1] == arch_gen_reg_parts[reg].reg[0]) { /* A_B <- B_C. */ strcpy(buf0, "\tmovl %1, %0\n"); strcat(buf0, "\tmovl %u1, %u0\n"); } else { /* A_B <- C_D. */ strcpy(buf0, "\tmovl %1, %0\n"); strcat(buf0, "\tmovl %u1, %u0\n"); } break; default: assert(0); /* Cannot happen. */ } break; case EXPR_BUILTIN_VA_ARG: t1 = e->type_name; switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tmovb (%1), %0\n"); strcat(buf0, "\taddl $1, %1\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tmovw (%1), %0\n"); strcat(buf0, "\taddl $2, %1\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tmovl (%1), %0\n"); strcat(buf0, "\taddl $4, %1\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovl (%1), %0\n"); strcat(buf0, "\tmovl 4(%1), %u0\n"); strcat(buf0, "\taddl $8, %1\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_TYPE_CONVERSION: if (e->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ if (e->expr0->expr0->declaration->storage == STORAGE_NONE || e->expr0->expr0->declaration->storage == STORAGE_EXTERN || e->expr0->expr0->declaration->storage == STORAGE_STATIC) { strcpy(buf0, "\tmovl %1, %0\n"); } else { strcpy(buf0, "\tleal %1, %0\n"); } break; } else if (e->expr0->type == EXPR_IDENTIFIER && (e->expr0->declaration->type_name->type == TYPE_ARRAY || e->expr0->declaration->type_name->type == TYPE_FUNCTION)) { /* * Special case: (int) array * Special case: (int) function */ if (e->expr0->declaration->storage == STORAGE_NONE || e->expr0->declaration->storage == STORAGE_EXTERN || e->expr0->declaration->storage == STORAGE_STATIC) { strcpy(buf0, "\tmovl %1, %0\n"); } else { strcpy(buf0, "\tleal %1, %0\n"); } break; } t1 = expr_typeof(block->scope, e->expr0); t1 = type_pure(t1); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, ""); break; case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovb %b1, %0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT16: case TYPE_UINT16: switch (t1->type) { case TYPE_INT8: strcpy(buf0, "\tmovsbw %1, %0\n"); break; case TYPE_UINT8: strcpy(buf0, "\tmovzbw %1, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, ""); break; case TYPE_INT32: case TYPE_UINT32: case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovw %w1, %0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: /* Unsigned - FIXME */ strcpy(buf0, "\tfnstcw %0\n" "\tmovw %0, %2\n" "\torw $0xc00, %2\n" "\tmovw %2, %1\n" "\tfldcw %1\n" "\tfistps %3\n" "\tfldcw %0\n"); break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT32: case TYPE_UINT32: switch (t1->type) { case TYPE_INT8: strcpy(buf0, "\tmovsbl %1, %0\n"); break; case TYPE_UINT8: strcpy(buf0, "\tmovzbl %1, %0\n"); break; case TYPE_INT16: strcpy(buf0, "\tmovswl %1, %0\n"); break; case TYPE_UINT16: strcpy(buf0, "\tmovzwl %1, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, ""); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovl %1, %0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: /* Unsigned - FIXME */ strcpy(buf0, "\tfnstcw %0\n"); strcat(buf0, "\tmovw %0, %2\n"); strcat(buf0, "\torw $0xc00, %2\n"); strcat(buf0, "\tmovw %2, %1\n"); strcat(buf0, "\tfldcw %1\n"); strcat(buf0, "\tfistpl %3\n"); strcat(buf0, "\tfldcw %0\n"); break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT64: case TYPE_UINT64: switch (t1->type) { case TYPE_INT8: strcpy(buf0, "\tmovsbl %1, %0\n"); strcat(buf0, "\tcltd\n"); break; case TYPE_UINT8: strcpy(buf0, "\tmovzbl %1, %0\n"); strcat(buf0, "\txorl %u0, %u0\n"); break; case TYPE_INT16: strcpy(buf0, "\tmovswl %1, %0\n"); strcat(buf0, "\tcltd\n"); break; case TYPE_UINT16: strcpy(buf0, "\tmovzwl %1, %0\n"); strcat(buf0, "\txorl %u0, %u0\n"); break; case TYPE_INT32: strcpy(buf0, "\tmovl %1, %0\n"); strcat(buf0, "\tcltd\n"); break; case TYPE_UINT32: strcpy(buf0, "\tmovl %1, %0\n"); strcat(buf0, "\txorl %u0, %u0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, ""); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: /* Unsigned - FIXME */ strcpy(buf0, "\tfnstcw %0\n" "\tmovw %0, %2\n" "\torw $0xc00, %2\n" "\tmovw %2, %1\n" "\tfldcw %1\n" "\tfistpll %3\n" "\tfldcw %0\n"); break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: case TYPE_INT64: case TYPE_UINT64: assert(0); /* FIXME */ break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: strcpy(buf0, ""); break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; default: assert(0); } break; case EXPR_STAR: assert(lhs); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tmovb (%1), %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tmovw (%1), %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tmovl (%1), %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovl (%1), %%eax\n" "\tmovl 4(%1), %%edx\n"); break; case TYPE_FLOAT32: switch (s->output->first->next->expr->declaration->storage_register) { case ST0: case ST1: strcpy(buf0, "\tflds (%2)\n"); break; case ST2: case ST3: case ST4: case ST5: case ST6: case ST7: strcpy(buf0, "\tflds (%2)\n" "\tfstp %1\n"); break; default: /* Memory */ strcpy(buf0, "\tmovl (%2), %0\n" "\tmovl %0, %1\n"); break; } break; case TYPE_FLOAT64: switch (s->output->first->next->expr->declaration->storage_register) { case ST0: case ST1: strcpy(buf0, "\tfldl (%2)\n"); break; case ST2: case ST3: case ST4: case ST5: case ST6: case ST7: strcpy(buf0, "\tfldl (%2)\n" "\tfstp %1\n"); break; default: /* Memory */ strcpy(buf0, "\tmovl (%2), %0\n" "\tmovl %0, %1\n" "\tmovl 4(%2), %0\n" "\tmovl %0, 4+%1\n"); break; } break; case TYPE_FLOAT80: switch (s->output->first->next->expr->declaration->storage_register) { case ST0: case ST1: strcpy(buf0, "\tfldt (%2)\n"); break; case ST2: case ST3: case ST4: case ST5: case ST6: case ST7: strcpy(buf0, "\tfldt (%2)\n" "\tfstp %1\n"); break; default: /* Memory */ strcpy(buf0, "\tmovl (%2), %0\n" "\tmovl %0, %1\n" "\tmovl 4(%2), %0\n" "\tmovl %0, 4+%1\n" "\tmovl 8(%2), %0\n" "\tmovl %0, 8+%1\n" "\tmovl 12(%2), %0\n" "\tmovl %0, 12+%1\n"); break; } break; default: assert(0); } break; case EXPR_NEG: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tnegb %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tnegw %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tnegl %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tnegl %0\n"); strcat(buf0, "\tadcl $0, %u0\n"); strcat(buf0, "\tnegl %u0\n"); break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_INV: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\txorb $-1, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\txorw $-1, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\txorl $-1, %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\txorl $-1, %0\n"); strcat(buf0, "\txorl $-1, %u0\n"); break; default: assert(0); } break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: t1 = expr_typeof(block->scope, e->expr0); t1 = type_pure(t1); switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tcmpb %3, %2\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tcmpw %3, %2\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tcmpl %3, %2\n"); break; default: assert(0); } switch (t1->type) { case TYPE_INT8: case TYPE_INT16: case TYPE_INT32: switch (e->type) { case EXPR_EQUAL: strcat(buf0, "\tsete %1\n"); break; case EXPR_NOT_EQUAL: strcat(buf0, "\tsetne %1\n"); break; case EXPR_LESS: strcat(buf0, "\tsetl %1\n"); break; case EXPR_LESS_EQUAL: strcat(buf0, "\tsetle %1\n"); break; case EXPR_GREATER: strcat(buf0, "\tsetg %1\n"); break; case EXPR_GREATER_EQUAL: strcat(buf0, "\tsetge %1\n"); break; default: assert(0); } break; case TYPE_UINT8: case TYPE_UINT16: case TYPE_UINT32: switch (e->type) { case EXPR_EQUAL: strcat(buf0, "\tsete %1\n"); break; case EXPR_NOT_EQUAL: strcat(buf0, "\tsetne %1\n"); break; case EXPR_LESS: strcat(buf0, "\tsetb %1\n"); break; case EXPR_LESS_EQUAL: strcat(buf0, "\tsetbe %1\n"); break; case EXPR_GREATER: strcat(buf0, "\tseta %1\n"); break; case EXPR_GREATER_EQUAL: strcat(buf0, "\tsetae %1\n"); break; default: assert(0); } break; default: assert(0); } break; case TYPE_INT64: case TYPE_UINT64: assert(0); case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } switch (t->type) { case TYPE_INT8: case TYPE_UINT8: break; case TYPE_INT16: case TYPE_UINT16: strcat(buf0, "\tmovzbw %1, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcat(buf0, "\tmovzbl %1, %0\n"); break; default: assert(0); } break; case EXPR_LEFT: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tshlb %b2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tshlw %b2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tshll %b2, %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tshldl %0, %u0\n"); strcat(buf0, "\tsall %b2, %0\n"); strcat(buf0, "\ttestb $32, %b2\n"); strcat(buf0, "\tje 1f\n"); strcat(buf0, "\tmovl %0, %u0\n"); strcat(buf0, "\txorl %0, %0\n"); strcat(buf0, "1:\n"); break; default: assert(0); } break; case EXPR_RIGHT: switch (t->type) { case TYPE_INT8: strcpy(buf0, "\tsarb %b2, %0\n"); break; case TYPE_UINT8: strcpy(buf0, "\tshrb %b2, %0\n"); break; case TYPE_INT16: strcpy(buf0, "\tsarw %b2, %0\n"); break; case TYPE_UINT16: strcpy(buf0, "\tshrw %b2, %0\n"); break; case TYPE_INT32: strcpy(buf0, "\tsarl %b2, %0\n"); break; case TYPE_UINT32: strcpy(buf0, "\tshrl %b2, %0\n"); break; case TYPE_INT64: strcpy(buf0, "\tshrdl %u0, %0\n"); strcat(buf0, "\tsarl %b2, %u0\n"); strcat(buf0, "\ttestb $32, %b2\n"); strcat(buf0, "\tje 1f\n"); strcat(buf0, "\tmovl %u0, %0\n"); strcat(buf0, "\tsarl $31, %u0\n"); strcat(buf0, "1:\n"); break; case TYPE_UINT64: strcpy(buf0, "\tshrdl %u0, %0\n"); strcat(buf0, "\tsarl %b2, %u0\n"); strcat(buf0, "\ttestb $32, %b2\n"); strcat(buf0, "\tje 1f\n"); strcat(buf0, "\tmovl %u0, %0\n"); strcat(buf0, "\txorl %u0, %u0\n"); strcat(buf0, "1:\n"); break; default: assert(0); } break; case EXPR_ADD: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\taddb %2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\taddw %2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\taddl %2, %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\taddl %2, %0\n"); strcat(buf0, "\tadcl %u2, %u0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: strcpy(buf0, "\tfaddp\n"); break; default: assert(0); } break; case EXPR_SUB: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tsubb %2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tsubw %2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tsubl %2, %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tsubl %2, %0\n"); strcat(buf0, "\tsbbl %u2, %u0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: strcpy(buf0, "\tfsubp\n"); break; default: assert(0); } break; case EXPR_MUL: switch (t->type) { case TYPE_INT8: strcpy(buf0, "\timulb %2\n"); break; case TYPE_UINT8: strcpy(buf0, "\tmulb %2\n"); break; case TYPE_INT16: strcpy(buf0, "\timulw %2\n"); break; case TYPE_UINT16: strcpy(buf0, "\tmulw %2\n"); break; case TYPE_INT32: strcpy(buf0, "\timull %2\n"); break; case TYPE_UINT32: strcpy(buf0, "\tmull %2\n"); break; case TYPE_INT64: assert(0); /* Operator replaced by function call. */ case TYPE_UINT64: assert(0); /* Operator replaced by function call. */ case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_DIV: switch (t->type) { case TYPE_INT8: strcpy(buf0, "\tcbw\n"); strcat(buf0, "\tidivb %2\n"); break; case TYPE_UINT8: strcpy(buf0, "\txorb %%ah, %%ah\n"); strcat(buf0, "\tdivb %2\n"); break; case TYPE_INT16: strcpy(buf0, "\tcwd\n"); strcat(buf0, "\tidivw %2\n"); break; case TYPE_UINT16: strcpy(buf0, "\txorw %%dx, %%dx\n"); strcat(buf0, "\tdivw %2\n"); break; case TYPE_INT32: strcpy(buf0, "\tcltd\n"); strcat(buf0, "\tidivl %2\n"); break; case TYPE_UINT32: strcpy(buf0, "\txorl %%edx, %%edx\n"); strcat(buf0, "\tdivl %2\n"); break; case TYPE_INT64: assert(0); /* Operator replaced by function call. */ case TYPE_UINT64: assert(0); /* Operator replaced by function call. */ case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_MOD: switch (t->type) { case TYPE_INT8: strcpy(buf0, "\tcbw\n"); strcat(buf0, "\tidivb %2\n"); strcat(buf0, "\tmovb %%ah, %%al\n"); break; case TYPE_UINT8: strcpy(buf0, "\txorb %%ah, %%ah\n"); strcat(buf0, "\tdivb %2\n"); strcat(buf0, "\tmovb %%ah, %%al\n"); break; case TYPE_INT16: strcpy(buf0, "\tcwd\n"); strcat(buf0, "\tidivw %3\n"); break; case TYPE_UINT16: strcpy(buf0, "\txorw %%dx, %%dx\n"); strcat(buf0, "\tdivw %3\n"); break; case TYPE_INT32: strcpy(buf0, "\tcltd\n"); strcat(buf0, "\tidivl %3\n"); break; case TYPE_UINT32: strcpy(buf0, "\txorl %%edx, %%edx\n"); strcat(buf0, "\tdivl %3\n"); break; case TYPE_INT64: assert(0); /* Operator replaced by function call. */ case TYPE_UINT64: assert(0); /* Operator replaced by function call. */ case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_AND: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tandb %2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tandw %2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tandl %2, %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tandl %2, %0\n"); strcat(buf0, "\tandl %u2, %u0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_OR: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\torb %2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\torw %2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\torl %2, %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\torl %2, %0\n"); strcat(buf0, "\torl %u2, %u0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_XOR: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\txorb %2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\txorw %2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\txorl %2, %0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\txorl %2, %0\n"); strcat(buf0, "\txorl %u2, %u0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_FUNC: /* * pushl %0 * pushl %1 * ... * pushl %N-1 * call label * addl $c, %esp */ strcpy(buf0, ""); size = 0; n = 0; for (c = s->output->first; c; c = c->next) { n++; } for (c = s->input->first; c; c = c->next) { n++; } for (ce = e->expr1->last; ce; ce = ce->prev) { n--; if (ce->type == EXPR_TYPE_CONVERSION) { struct declaration *dion; if (ce->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ dion = ce->expr0->expr0->declaration; } else if (ce->expr0->type == EXPR_IDENTIFIER) { /* * Special case: (int) array * Special case: (int) function */ dion = ce->expr0->declaration; } else { dion = NULL; } assert(dion); if (dion->storage == STORAGE_NONE || dion->storage == STORAGE_EXTERN || dion->storage == STORAGE_STATIC) { sprintf(buf0 + strlen(buf0), "\tpushl %%%u\n", n); } else { sprintf(buf0 + strlen(buf0), "\tleal %%%u, %%%%eax\n", n); /* FIXME */ sprintf(buf0 + strlen(buf0), "\tpushl %%%%eax\n"); /* FIXME */ } size += 4; continue; } t1 = expr_typeof(block->scope, ce); t1 = type_pure(t1); switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: sprintf(buf0 + strlen(buf0), "\tpushb %%%u\n", n); size += 2; break; case TYPE_INT16: case TYPE_UINT16: sprintf(buf0 + strlen(buf0), "\tpushw %%%u\n", n); size += 2; break; case TYPE_INT32: case TYPE_UINT32: sprintf(buf0 + strlen(buf0), "\tpushl %%%u\n", n); size += 4; break; case TYPE_INT64: case TYPE_UINT64: sprintf(buf0 + strlen(buf0), "\tpushl %%u%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushl %%%u\n", n); size += 8; break; case TYPE_FLOAT32: sprintf(buf0 + strlen(buf0), "\tpushl %%%u\n", n); break; case TYPE_FLOAT64: sprintf(buf0 + strlen(buf0), "\tpushl %%u%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushl %%%u\n", n); size += 8; case TYPE_FLOAT80: sprintf(buf0 + strlen(buf0), "\tpushl 12+%%%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushl 8+%%%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushl 4+%%%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushl %%%u\n", n); size += 16; break; case TYPE_VA_LIST: sprintf(buf0 + strlen(buf0), "\tpushl %%%u\n", n); size += 4; break; default: assert(0); } } switch (e->expr0->type) { case EXPR_IDENTIFIER: sprintf(buf0 + strlen(buf0), "\tcall %s\n", e->expr0->declaration->identifier); break; case EXPR_STAR: sprintf(buf0 + strlen(buf0), "\tcall *%%%u\n", n++); break; default: assert(0); } if (0 < size) { sprintf(buf0 + strlen(buf0), "\taddl $%u, %%%%esp\n", size); } break; default: assert(0); } } } static void arch_gen_stmt_simplify_1(struct stmt *block, struct stmt *s) { struct type *t; struct declaration *var; switch (s->type) { case STMT_NONE: assert(0); case STMT_NULL: case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_CONTINUE: case STMT_BREAK: case STMT_BLOCK: assert(0); case STMT_LABEL: /* * label: */ /* No constraints needed. */ break; case STMT_EXPR: switch (s->expr0->type) { case EXPR_ASSIGN: switch (s->expr0->expr0->type) { case EXPR_IDENTIFIER: arch_gen_expr_1(block, s, s->expr0->expr1, s->expr0->expr0); break; case EXPR_STAR: t = expr_typeof(block->scope, s->expr0->expr0); t = type_pure(t); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * movb %1, (%0) */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * movw %1, (%0) */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * movl %1, (%0) */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movl %1, (%0) * movl %u1, 4(%0) */ constraint_input(s, "r", expr_dup(s->expr0->expr0->expr0->expr0)); constraint_input(s, "r", expr_dup(s->expr0->expr1)); break; case TYPE_FLOAT32: /* * movl %2, %0 * movl %0, (%1) * * fstps (%1) * * flds %2 * fstps (%1) */ /*FALLTHROUGH*/ case TYPE_FLOAT64: /* * movl %2, %0 * movl %0, (%1) * movl 4+%2, %0 * movl %0, 4(%1) * * fstpl (%1) * * fldl %2 * fstpl (%1) */ /*FALLTHROUGH*/ case TYPE_FLOAT80: /* * movl %2, %0 * movl %0, (%1) * movl 4+%2, %0 * movl %0, 4(%1) * movl 8+%2, %0 * movl %0, 8(%1) * movl 12+%2, %0 * movl %0, 12(%1) * * fstpt (%1) * * fldt %2 * fstpt (%1) */ var = arch_tmp(block->scope, type_uint32()); constraint_output(s, "=r", expr_identifier(var)); constraint_input(s, "r", expr_dup(s->expr0->expr0->expr0->expr0)); constraint_input(s, "fm", expr_dup(s->expr0->expr1)); break; default: assert(0); } break; default: assert(0); } break; case EXPR_FUNC: arch_gen_expr_1(block, s, s->expr0, NULL); break; default: assert(0); } break; case STMT_IF: t = expr_typeof(block->scope, s->expr0->expr0); t = type_pure(t); if (s->expr0->expr0->type == EXPR_INTEGER || s->expr0->expr0->type == EXPR_REAL) { /* Exchange lhs/rhs. */ struct expr *tmp; tmp = s->expr0->expr0; s->expr0->expr0 = s->expr0->expr1; s->expr0->expr1 = tmp; switch (s->expr0->type) { case EXPR_EQUAL: break; case EXPR_NOT_EQUAL: break; case EXPR_LESS: s->expr0->type = EXPR_GREATER; break; case EXPR_LESS_EQUAL: s->expr0->type = EXPR_GREATER_EQUAL; break; case EXPR_GREATER: s->expr0->type = EXPR_LESS; break; case EXPR_GREATER_EQUAL: s->expr0->type = EXPR_LESS_EQUAL; break; default: assert(0); } } switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * cmpb %1, %0 * jcc label */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * cmpw %1, %0 * jcc label */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * cmpl %1, %0 * jcc label */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * cmpl %u1, %u0 * jcc label * cmpl %1, %0 * jcc label */ constraint_input(s, "mr", expr_dup(s->expr0->expr0)); constraint_input(s, "ir", expr_dup(s->expr0->expr1)); break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case STMT_SWITCH: /* * cmp{b,w,l} $c0, %0 * je l0 * cmp{b,w,l} $c1, %0 * je l1 * cmp{b,w,l} $c2, %0 * je l2 * ... * cmp{b,w,l} $cN, %0 * je lN * jmp ldef */ constraint_input(s, "r", expr_dup(s->expr0)); break; case STMT_GOTO: /* * jmp label */ /* No constraints needed. */ break; case STMT_RETURN: /* * No code. Constraint only. */ if (s->expr0) { t = expr_typeof(block->scope, s->expr0); t = type_pure(t); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: constraint_input(s, "a", expr_dup(s->expr0)); break; case TYPE_INT64: case TYPE_UINT64: constraint_input(s, "A", expr_dup(s->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } } break; case STMT_ASM: /* * Code in asm statement. */ /* Constraints in asm statement. */ break; case STMT_VA_START: /* * leal X(%ebp), %0 */ constraint_output(s, "=r", expr_dup(s->expr0)); break; case STMT_VA_END: /* * No code. No constraints. */ break; default: assert(0); } } static void arch_gen_stmt_simplify_2( struct stmt *block, struct stmt *s, unsigned int paramsize ) { struct type *t; struct constraint *c; struct stmt *cs; struct stmt *s0; char buf0[1024*1024]; char buf1[1024*1024]; const char *from; char *to; struct declaration *dion; switch (s->type) { case STMT_NONE: assert(0); case STMT_NULL: case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_CONTINUE: case STMT_BREAK: case STMT_BLOCK: assert(0); case STMT_LABEL: sprintf(buf0, "%s:\n", s->label->identifier); break; case STMT_EXPR: switch (s->expr0->type) { case EXPR_ASSIGN: switch (s->expr0->expr0->type) { case EXPR_IDENTIFIER: arch_gen_expr_2(buf0, block, s, s->expr0->expr1, s->expr0->expr0); break; case EXPR_STAR: t = expr_typeof(block->scope, s->expr0->expr1); t = type_pure(t); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tmovb %1, (%0)\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tmovw %1, (%0)\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tmovl %1, (%0)\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovl %1, (%0)\n"); strcat(buf0, "\tmovl %u1, 4(%0)\n"); break; case TYPE_FLOAT32: switch (s->input->first->next->expr->declaration->storage_register) { case ST0: case ST1: strcpy(buf0, "\tfstps (%1)\n"); break; case ST2: case ST3: case ST4: case ST5: case ST6: case ST7: strcpy(buf0, "\tfldt %2\n" "\tfstps (%1)\n"); break; default: /* Memory */ strcpy(buf0, "\tmovl %2, %0\n" "\tmovl %0, (%1)\n"); break; } break; case TYPE_FLOAT64: switch (s->input->first->next->expr->declaration->storage_register) { case ST0: case ST1: strcpy(buf0, "\tfstpl (%1)\n"); break; case ST2: case ST3: case ST4: case ST5: case ST6: case ST7: strcpy(buf0, "\tfldt %2\n" "\tfstpl (%1)\n"); break; default: /* Memory */ strcpy(buf0, "\tmovl %2, %0\n" "\tmovl %0, (%1)\n" "\tmovl 4+%2, %0\n" "\tmovl %0, 4(%1)\n"); break; } break; case TYPE_FLOAT80: switch (s->input->first->next->expr->declaration->storage_register) { case ST0: case ST1: strcpy(buf0, "\tfstpt (%1)\n"); break; case ST2: case ST3: case ST4: case ST5: case ST6: case ST7: strcpy(buf0, "\tfldt %2\n" "\tfstpt (%1)\n"); break; default: /* Memory */ strcpy(buf0, "\tmovl %2, %0\n" "\tmovl %0, (%1)\n" "\tmovl 4+%2, %0\n" "\tmovl %0, 4(%1)\n" "\tmovl 8+%2, %0\n" "\tmovl %0, 8(%1)\n" "\tmovl 12+%2, %0\n" "\tmovl %0, 12(%1)\n"); break; } break; default: assert(0); } break; default: assert(0); } break; case EXPR_FUNC: arch_gen_expr_2(buf0, block, s, s->expr0, NULL); break; default: assert(0); } break; case STMT_IF: t = expr_typeof(block->scope, s->expr0->expr0); t = type_pure(t); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tcmpb %1, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tcmpw %1, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tcmpl %1, %0\n"); break; default: assert(0); } switch (t->type) { case TYPE_INT8: case TYPE_INT16: case TYPE_INT32: switch (s->expr0->type) { case EXPR_EQUAL: sprintf(buf0 + strlen(buf0), "\tje %s\n", s->stmt0->label->identifier); break; case EXPR_NOT_EQUAL: sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); break; case EXPR_LESS: sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); break; case EXPR_LESS_EQUAL: sprintf(buf0 + strlen(buf0), "\tjle %s\n", s->stmt0->label->identifier); break; case EXPR_GREATER: sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); break; case EXPR_GREATER_EQUAL: sprintf(buf0 + strlen(buf0), "\tjge %s\n", s->stmt0->label->identifier); break; default: assert(0); } break; case TYPE_UINT8: case TYPE_UINT16: case TYPE_UINT32: switch (s->expr0->type) { case EXPR_EQUAL: sprintf(buf0 + strlen(buf0), "\tje %s\n", s->stmt0->label->identifier); break; case EXPR_NOT_EQUAL: sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); break; case EXPR_LESS: sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); break; case EXPR_LESS_EQUAL: sprintf(buf0 + strlen(buf0), "\tjbe %s\n", s->stmt0->label->identifier); break; case EXPR_GREATER: sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); break; case EXPR_GREATER_EQUAL: sprintf(buf0 + strlen(buf0), "\tjae %s\n", s->stmt0->label->identifier); break; default: assert(0); } break; default: assert(0); } break; case TYPE_INT64: switch (s->expr0->type) { case EXPR_EQUAL: strcpy(buf0, "\tcmpl %u1, %u0\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tje %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_NOT_EQUAL: strcpy(buf0, "\tcmpl %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); break; case EXPR_LESS: strcpy(buf0, "\tcmpl %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_LESS_EQUAL: strcpy(buf0, "\tcmpl %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjle %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER: strcpy(buf0, "\tcmpl %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER_EQUAL: strcpy(buf0, "\tcmpl %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjge %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; default: assert(0); } break; case TYPE_UINT64: switch (s->expr0->type) { case EXPR_EQUAL: strcpy(buf0, "\tcmpl %u1, %u0\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tje %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_NOT_EQUAL: strcpy(buf0, "\tcmpl %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); break; case EXPR_LESS: strcpy(buf0, "\tcmpl %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_LESS_EQUAL: strcpy(buf0, "\tcmpl %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER: strcpy(buf0, "\tcmpl %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER_EQUAL: strcpy(buf0, "\tcmpl %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tcmpl %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjae %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; default: assert(0); } break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case STMT_SWITCH: assert(s->expr0->type == EXPR_IDENTIFIER); t = expr_typeof(block->scope, s->expr0); t = type_pure(t); strcpy(buf0, ""); for (cs = s->stmt0->stmt_first; cs->type != STMT_DEFAULT; cs = cs->next) { switch (t->type) { case TYPE_INT8: case TYPE_UINT8: sprintf(buf0 + strlen(buf0), "\tcmpb $%lld, %%0\n", cs->expr0->integer); sprintf(buf0 + strlen(buf0), "\tje %s\n", cs->stmt0->label->identifier); break; case TYPE_INT16: case TYPE_UINT16: sprintf(buf0 + strlen(buf0), "\tcmpw $%lld, %%0\n", cs->expr0->integer); sprintf(buf0 + strlen(buf0), "\tje %s\n", cs->stmt0->label->identifier); break; case TYPE_INT32: case TYPE_UINT32: sprintf(buf0 + strlen(buf0), "\tcmpl $%lld, %%0\n", cs->expr0->integer); sprintf(buf0 + strlen(buf0), "\tje %s\n", cs->stmt0->label->identifier); break; case TYPE_INT64: case TYPE_UINT64: sprintf(buf0 + strlen(buf0), "\tcmpl $%u, %%0\n", (uint32_t) (cs->expr0->integer >> 0)); strcat(buf0, "\tjne 1f\n"); sprintf(buf0 + strlen(buf0), "\tcmpl $%u, %%u0\n", (uint32_t) (cs->expr0->integer >> 32)); sprintf(buf0 + strlen(buf0), "\tje %s\n", cs->stmt0->label->identifier); strcat(buf0, "1:\n"); break; default: assert(0); } } sprintf(buf0 + strlen(buf0), "\tjmp %s\n", cs->stmt0->label->identifier); break; case STMT_GOTO: sprintf(buf0, "\tjmp %s\n", s->label->identifier); break; case STMT_RETURN: /* * No code. Asm constraints only. */ strcpy(buf0, ""); break; case STMT_ASM: strcpy(buf0, s->code); if (0 < strlen(buf0) && buf0[strlen(buf0) - 1] != '\n') { /* Newline is missing... */ strcat(buf0, "\n"); } break; case STMT_VA_START: sprintf(buf0, "\tleal %u(%%%%ebp), %%0\n", paramsize); break; case STMT_VA_END: strcpy(buf0, ""); break; default: assert(0); } /* * Replace %0, %1, ... in asm statements. */ from = buf0; to = buf1; while (*from) { enum type_mod mod; unsigned int n; unsigned int offset; const char *reg; unsigned long long val; if (*from != '%') { *to++ = *from++; continue; } from++; if (*from == '%') { from++; *to++ = '%'; continue; } /* * Get byte/word/long modifier. */ switch (*from) { case 'b': mod = REG_MOD_b; offset = 0; from++; break; case 'h': mod = REG_MOD_h; offset = 1; from++; break; case 'w': mod = REG_MOD_w; offset = 0; from++; break; case 'u': mod = REG_MOD_u; offset = 4; from++; break; default: mod = REG_MOD_NONE; offset = 0; break; } /* * Get constraint number. */ if (*from < '0' || '9' < *from) { fprintf(stderr, "No constraint number.\n"); goto problem; } assert('0' <= *from && *from <= '9'); n = 0; while ('0' <= *from && *from <= '9') { n *= 10; n += *from++ - '0'; } if (100 <= n) { fprintf(stderr, "Constraint number >= 100.\n"); goto problem; } assert(n < 100); /* * Lookup constraint. */ for (c = s->output->first; c && n; c = c->next) { n--; } if (! c) { for (c = s->input->first; c && n; c = c->next) { n--; } } if (! c) { fprintf(stderr, "Too few constraints.\n"); goto problem; } assert(c); /* * Replace "%num" by real operand. */ switch (c->expr->type) { case EXPR_INTEGER: switch (c->expr->type_name->type) { case TYPE_INT8: case TYPE_UINT8: val = (uint8_t) c->expr->integer; break; case TYPE_INT16: case TYPE_UINT16: val = (uint16_t) c->expr->integer; break; case TYPE_INT32: case TYPE_UINT32: val = (uint32_t) c->expr->integer; break; case TYPE_INT64: case TYPE_UINT64: val = c->expr->integer; break; default: assert(0); } switch (mod) { case REG_MOD_NONE: val &= 0xffffffff; break; case REG_MOD_b: val &= 0xff; break; case REG_MOD_h: val >>= 8; val &= 0xff; break; case REG_MOD_w: val &= 0xffff; break; case REG_MOD_u: val >>= 32; val &= 0xffffffff; break; default: assert(0); } sprintf(to, "$0x%llx", val); to += strlen(to); break; case EXPR_REAL: assert(0); case EXPR_IDENTIFIER: dion = c->expr->declaration; assert(dion); switch (dion->storage) { case STORAGE_AUTO: sprintf(to, "%d(%%ebp)", dion->offset + offset); to += strlen(to); break; case STORAGE_REGISTER: switch (mod) { case REG_MOD_NONE: reg = arch_reg_name_def[dion->storage_register]; break; case REG_MOD_b: reg = arch_reg_name_b[dion->storage_register]; break; case REG_MOD_h: reg = arch_reg_name_h[dion->storage_register]; break; case REG_MOD_w: reg = arch_reg_name_w[dion->storage_register]; break; case REG_MOD_u: reg = arch_reg_name_u[dion->storage_register]; break; default: assert(0); /* Mustn't happen. */ } if (! reg) { fprintf(stderr, "mod=%u, reg=%u\n", mod, dion->storage_register); goto problem; } assert(reg); sprintf(to, "%%%s", reg); to += strlen(to); break; case STORAGE_PARAM: sprintf(to, "%u(%%bp)", dion->offset + offset); to += strlen(to); break; case STORAGE_STATIC: if (offset == 0) { sprintf(to, "%s", arch_gen_local_off(dion->identifier)); to += strlen(to); } else { assert(offset == 2); sprintf(to, "%s", arch_gen_local_seg(dion->identifier)); to += strlen(to); } break; case STORAGE_NONE: case STORAGE_EXTERN: if (offset == 0) { sprintf(to, "%s", arch_gen_global_off(dion->identifier)); to += strlen(to); } else { assert(offset == 2); sprintf(to, "%s", arch_gen_global_seg(dion->identifier)); to += strlen(to); } break; case STORAGE_TYPEDEF: case STORAGE_ASM: assert(0); } break; case EXPR_AMPHERSAND: assert(0); case EXPR_TYPE_CONVERSION: if (c->expr->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ dion = c->expr->expr0->expr0->declaration; } else if (c->expr->expr0->type == EXPR_IDENTIFIER) { /* * Special case: (int) array * Special case: (int) func */ dion = c->expr->expr0->declaration; } else { assert(0); } assert(dion); if (dion->storage == STORAGE_STATIC) { if (offset == 0) { sprintf(to, "$%s", arch_gen_local_off(dion->identifier)); } else { assert(offset == 4); sprintf(to, "$%s", arch_gen_local_seg(dion->identifier)); } } else if (dion->storage == STORAGE_NONE || dion->storage == STORAGE_EXTERN) { if (offset == 0) { sprintf(to, "$%s", arch_gen_global_off(dion->identifier)); } else { assert(offset == 4); sprintf(to, "$%s", arch_gen_global_seg(dion->identifier)); } } else if (dion->storage == STORAGE_AUTO) { sprintf(to, "%d(%%ebp)", dion->offset + offset); } else if (dion->storage == STORAGE_PARAM) { sprintf(to, "%d(%%ebp)", dion->offset + offset); } to += strlen(to); break; default: problem: fprintf(stderr, "Problem with:\n"); fprintf(stderr, "%s", buf0); assert(0); } } *to = '\0'; s0 = stmt_new(); s0->type = STMT_ASM; s0->code = identifier_new(buf1); s0->code_len = strlen(s0->code); s0->output = constraint_list_new(); s0->input = constraint_list_new(); s0->change = constraint_list_new(); stmt_replace_1_by_1(block, s, s0); } static void arch_gen_func(FILE *fp, struct declaration *dion) { struct declaration *save[REG_COUNT]; struct declaration *d; struct stmt *cs; int offset; unsigned int align; unsigned int size; unsigned int autosize; unsigned int paramsize; /* * Check "dion->stmt->stmt_last->type == STMT_RETURN" should * not be neccessary - FIXME. */ if (! dion->attr_noreturn && dion->stmt->stmt_last->type == STMT_RETURN) { unsigned int reg; uint64_t regs_to_save; assert(dion->stmt->stmt_last->type == STMT_RETURN); /* Save Registers */ regs_to_save = REG_CALLEE; assert((regs_to_save & ~REG_32) == 0); cs = stmt_new(); cs->type = STMT_ASM; cs->code = identifier_new(""); cs->code_len = 0; for (reg = 0; reg < REG_COUNT; reg++) { const char *constraint; if (! ((regs_to_save >> reg) & 1)) { save[reg] = NULL; continue; } save[reg] = simplify_declaration_add(dion->stmt->scope, type_uint32(), identifier_tmp()); save[reg]->storage = STORAGE_AUTO; switch (reg) { case EAX: constraint = "=a"; break; case EBX: constraint = "=b"; break; case ECX: constraint = "=c"; break; case EDX: constraint = "=d"; break; case EDI: constraint = "=D"; break; case ESI: constraint = "=S"; break; default: assert(0); /* Mustn't happen. */ } constraint_output(cs, constraint, expr_identifier(save[reg])); } stmt_prepend_first(dion->stmt, cs); /* Restore Registers */ cs = dion->stmt->stmt_last; for (reg = 0; reg < REG_COUNT; reg++) { const char *constraint; if (! ((regs_to_save >> reg) & 1)) { assert(save[reg] == NULL); continue; } switch (reg) { case EAX: constraint = "a"; break; case EBX: constraint = "b"; break; case ECX: constraint = "c"; break; case EDX: constraint = "d"; break; case EDI: constraint = "D"; break; case ESI: constraint = "S"; break; default: assert(0); /* Mustn't happen. */ } constraint_input(cs, constraint, expr_identifier(save[reg])); } } /* * Transform statements into assembler code. * First step. */ for (cs = dion->stmt->stmt_first; cs; ) { struct stmt *next; next = cs->next; arch_gen_stmt_simplify_1(dion->stmt, cs); cs = next; } /* * Add missing constraint info. */ for (cs = dion->stmt->stmt_first; cs; cs = cs->next) { if (! cs->output) { cs->output = constraint_list_new(); } if (! cs->input) { cs->input = constraint_list_new(); } if (! cs->change) { cs->change = constraint_list_new(); } } #if 0 print_declaration(stderr, 0, dion); #endif /* * Register assignment. */ regalloc(arch_reginfo, arch_classinfo, arch_typeinfo, dion->stmt); #if 0 print_declaration(stderr, 0, dion); #endif offset = 0; for (d = dion->stmt->scope->declaration_first; d; d = d->next) { if (d->storage == STORAGE_AUTO) { type_align_size(dion->stmt->scope, d->type_name, &align, &size); offset -= size; offset &= ~(align - 1); d->offset = offset; } } autosize = offset; autosize &= ~(4 - 1); /* 4 Byte Alignment */ autosize = -autosize; offset = 4; /* Base Pointer */ offset += 4; /* Return Address */ for (d = dion->type_name->parameter->declaration_first; d && d->type_name->type != TYPE_ELIPSIS; d = d->next) { type_align_size(dion->stmt->scope, d->type_name, &align, &size); offset += align - 1; offset &= ~(align - 1); d->offset = offset; offset += size; } paramsize = offset; paramsize += 4 - 1; /* 4 Byte Alignment */ paramsize &= ~(4 - 1); /* * Transform remaining statements into assembler code. * Second step. */ for (cs = dion->stmt->stmt_first; cs; ) { struct stmt *next; next = cs->next; arch_gen_stmt_simplify_2(dion->stmt, cs, paramsize); cs = next; } /* * Generate Header */ fprintf(fp, "\t.text\n"); fprintf(fp, "\t.code32\n"); fprintf(fp, "\t.arch i386\n"); if (opt_f_align_functions != 1) { unsigned int p; for (p = 0; (1 << p) < opt_f_align_functions; p++) { } fprintf(fp, "\t.p2align %u\n", p); } if (dion->storage == STORAGE_STATIC) { /* * NOTE: * Label *must* be global. Otherwise our * linker tool will not generate __SEG_x/__OFF_x * symbols for it. */ fprintf(fp, "\t.globl %s\n", arch_gen_local(dion->identifier)); fprintf(fp, "%s:\n", arch_gen_local(dion->identifier)); } else { fprintf(fp, "\t.globl %s\n", arch_gen_global(dion->identifier)); fprintf(fp, "%s:\n", arch_gen_global(dion->identifier)); } fprintf(fp, "\tpushl %%ebp\n"); fprintf(fp, "\tmovl %%esp, %%ebp\n"); if (0 < autosize) { fprintf(fp, "\tsubl $%u, %%esp\n", autosize); } /* * Generate Code */ for (cs = dion->stmt->stmt_first; cs; cs = cs->next) { if (cs->type == STMT_ASM) { fprintf(fp, "%s", cs->code); } else { fprintf(fp, "...\n"); } } /* * Generate Trailer */ fprintf(fp, "\tleave\n"); fprintf(fp, "\tret\n"); } static void arch_gen_dion(FILE *fp, struct scope *scope, struct declaration *dion) { if (dion->storage == STORAGE_TYPEDEF) { /* Type definition only. */ return; } if (dion->storage != STORAGE_ASM && dion->identifier == NULL) { /* struct/union/enum definition only. */ return; } if (dion->storage == STORAGE_EXTERN) { /* Extern declaration only. */ return; } if ((dion->storage == STORAGE_NONE || dion->storage == STORAGE_EXTERN || dion->storage == STORAGE_STATIC) && type_is_function(dion->type_name) && ! dion->stmt) { /* Function prototype only. */ return; } if (dion->storage == STORAGE_ASM) { fprintf(fp, "%s\n", dion->code); } else { if (dion->storage == STORAGE_STATIC) { arch_gen_local_def(dion->identifier); } else { arch_gen_global_def(dion->identifier); } if (! type_is_function(dion->type_name)) { arch_gen_data(fp, scope, dion); } else { arch_gen_func(fp, dion); } } fprintf(fp, "\n"); } void arch_i386_gen(const char *out, struct scope *scope) { FILE *fp; struct declaration *dion; int ret; fp = fopen(out, "w"); assert(fp); assert(REG_COUNT <= DECL_REG_COUNT); assert(CLASS_NONE == DECL_CLASS_NONE); assert(CLASS_COUNT <= DECL_CLASS_COUNT); ret = setvbuf(fp, NULL, _IONBF, 0); assert(0 <= ret); arch_mul_int64 = declaration_identifier("__mul_int64"); arch_mul_int64->type_name = type_new(); arch_mul_int64->type_name->type = TYPE_FUNCTION; arch_mul_int64->type_name->declarator = type_new(); arch_mul_int64->type_name->declarator->type = TYPE_INT64; arch_mul_uint64 = declaration_identifier("__i386_mul_uint64"); arch_mul_uint64->type_name = type_new(); arch_mul_uint64->type_name->type = TYPE_FUNCTION; arch_mul_uint64->type_name->declarator = type_new(); arch_mul_uint64->type_name->declarator->type = TYPE_UINT64; arch_div_int64 = declaration_identifier("__i386_div_int64"); arch_div_int64->type_name = type_new(); arch_div_int64->type_name->type = TYPE_FUNCTION; arch_div_int64->type_name->declarator = type_new(); arch_div_int64->type_name->declarator->type = TYPE_INT64; arch_div_uint64 = declaration_identifier("__i386_div_uint64"); arch_div_uint64->type_name = type_new(); arch_div_uint64->type_name->type = TYPE_FUNCTION; arch_div_uint64->type_name->declarator = type_new(); arch_div_uint64->type_name->declarator->type = TYPE_UINT64; arch_mod_int64 = declaration_identifier("__i386_mod_int64"); arch_mod_int64->type_name = type_new(); arch_mod_int64->type_name->type = TYPE_FUNCTION; arch_mod_int64->type_name->declarator = type_new(); arch_mod_int64->type_name->declarator->type = TYPE_INT64; arch_mod_uint64 = declaration_identifier("__i386_mod_uint64"); arch_mod_uint64->type_name = type_new(); arch_mod_uint64->type_name->type = TYPE_FUNCTION; arch_mod_uint64->type_name->declarator = type_new(); arch_mod_uint64->type_name->declarator->type = TYPE_UINT64; for (dion = scope->declaration_first; dion; dion = dion->next) { #if 0 print_declaration(stderr, 0, dion); #endif arch_gen_dion(fp, scope, dion); #if 0 print_declaration(stderr, 0, dion); #endif } ret = fclose(fp); assert(0 <= ret); } faucc-20120707/arch_i286_gen.c0000640002413100241000000044213711721634327015211 0ustar potyrai3guest/* * $Id: arch_i286_gen.c,v 1.348 2012-02-24 07:14:31 vrsieh Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ /* * For gcc inline assembler see e.g. * http://ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */ #include #include #include #include #include #include "identifier.h" #include "declaration.h" #include "scope.h" #include "stmt.h" #include "simplify.h" #include "arch_i286_gen.h" #include "regalloc.h" #include "cc1.h" static struct declaration *arch_mul_int32; static struct declaration *arch_mul_uint32; static struct declaration *arch_div_int32; static struct declaration *arch_div_uint32; static struct declaration *arch_mod_int32; static struct declaration *arch_mod_uint32; static struct declaration *arch_mul_int64; static struct declaration *arch_mul_uint64; static struct declaration *arch_div_int64; static struct declaration *arch_div_uint64; static struct declaration *arch_mod_int64; static struct declaration *arch_mod_uint64; enum reg { /*0*/ AL, DL, CL, BL, /*4*/ AH, DH, CH, BH, /*8*/ AX, DX, CX, BX, /*12*/ DI, SI, /*14*/ AX_BX, AX_CX, AX_DX, AX_DI, AX_SI, /*19*/ BX_AX, BX_CX, BX_DX, BX_DI, BX_SI, /*24*/ CX_AX, CX_BX, CX_DX, CX_DI, CX_SI, /*29*/ DX_AX, DX_BX, DX_CX, DX_DI, DX_SI, /*34*/ DI_AX, DI_BX, DI_CX, DI_DX, DI_SI, /*39*/ SI_AX, SI_BX, SI_CX, SI_DX, SI_DI, /*44*/ AX_DX_DI_SI, /*45*/ REG_COUNT }; enum class { CLASS_NONE, CLASS_A, CLASS_D, CLASS_S, CLASS_a, CLASS_b, CLASS_c, CLASS_d, CLASS_q, CLASS_r, CLASS_l, CLASS_COUNT }; enum type_mod { REG_MOD_NONE, REG_MOD_b, REG_MOD_h, REG_MOD_w, REG_MOD_u, REG_MOD_v, }; #define REG_8 \ ((1ULL << AL) \ | (1ULL << BL) \ | (1ULL << CL) \ | (1ULL << DL)) #define REG_16 \ ((1ULL << AX) | (1ULL << BX) \ | (1ULL << CX) | (1ULL << DX) \ | (1ULL << DI) | (1ULL << SI)) #define REG_32 \ ((1ULL << AX_BX) | (1ULL << AX_CX) \ | (1ULL << AX_DX) | (1ULL << AX_DI) | (1ULL << AX_SI) \ | (1ULL << BX_AX) | (1ULL << BX_CX) | (1ULL << BX_DX) \ | (1ULL << BX_DI) | (1ULL << BX_SI) \ | (1ULL << CX_AX) | (1ULL << CX_BX) | (1ULL << CX_DX) \ | (1ULL << CX_DI) | (1ULL << CX_SI) \ | (1ULL << DX_AX) | (1ULL << DX_BX) | (1ULL << DX_CX) \ | (1ULL << DX_DI) | (1ULL << DX_SI) \ | (1ULL << DI_AX) | (1ULL << DI_BX) | (1ULL << DI_CX) \ | (1ULL << DI_DX) | (1ULL << DI_SI) \ | (1ULL << SI_AX) | (1ULL << SI_BX) | (1ULL << SI_CX) \ | (1ULL << SI_DX) | (1ULL << SI_DI)) #define REG_64 \ (1ULL << AX_DX_DI_SI) #define REG_A \ (1ULL << AL) \ | (1ULL << AX) \ | (1ULL << AX_DX) \ | (1ULL << AX_DX_DI_SI) #define REG_D \ ((1ULL << DI) \ | (1ULL << DI_AX) | (1ULL << DI_BX) \ | (1ULL << DI_CX) | (1ULL << DI_DX) \ | (1ULL << DI_SI)) #define REG_S \ ((1ULL << SI) \ | (1ULL << SI_AX) | (1ULL << SI_BX) \ | (1ULL << SI_CX) | (1ULL << SI_DX) \ | (1ULL << SI_DI)) #define REG_a \ ((1ULL << AL) | (1ULL << AX) \ | (1ULL << AX_BX) | (1ULL << AX_CX) \ | (1ULL << AX_DX) | (1ULL << AX_DI) \ | (1ULL << AX_SI)) #define REG_b \ ((1ULL << BL) | (1ULL << BX) \ | (1ULL << BX_AX) | (1ULL << BX_CX) \ | (1ULL << BX_DX) | (1ULL << BX_DI) \ | (1ULL << BX_SI)) #define REG_c \ ((1ULL << CL) | (1ULL << CX) \ | (1ULL << CX_AX) | (1ULL << CX_BX) \ | (1ULL << CX_DX) | (1ULL << CX_DI) \ | (1ULL << CX_SI)) #define REG_d \ ((1ULL << DL) | (1ULL << DX) \ | (1ULL << DX_AX) | (1ULL << DX_BX) \ | (1ULL << DX_CX) | (1ULL << DX_DI) \ | (1ULL << DX_SI)) #define REG_q \ (REG_a | REG_b | REG_c | REG_d) #define REG_r \ (REG_8 | REG_16 | REG_32 | REG_64) #define REG_l \ ((1ULL << BX) | (1ULL << DI) | (1ULL << SI) | (1ULL << BX_DI) \ | (1ULL << BX_SI) | (1ULL << BX_AX) | (1ULL << BX_CX) \ | (1ULL << BX_DX)) #define REG_CALLER \ ((1ULL << AX) \ | (1ULL << CX) \ | (1ULL << DX)) #define REG_CALLEE \ (REG_16 & ~REG_CALLER) static struct storage_register arch_reginfo[] = { /* 8-Bit Registers */ [AL] = { "al", CLASS_a, TYPE_UINT8 }, [BL] = { "bl", CLASS_b, TYPE_UINT8 }, [CL] = { "cl", CLASS_c, TYPE_UINT8 }, [DL] = { "dl", CLASS_d, TYPE_UINT8 }, [AH] = { "ah", CLASS_COUNT, TYPE_UINT8 }, [BH] = { "bh", CLASS_COUNT, TYPE_UINT8 }, [CH] = { "ch", CLASS_COUNT, TYPE_UINT8 }, [DH] = { "dh", CLASS_COUNT, TYPE_UINT8 }, /* 16-Bit Registers */ [AX] = { "ax", CLASS_a, TYPE_UINT16 }, [BX] = { "bx", CLASS_b, TYPE_UINT16 }, [CX] = { "cx", CLASS_c, TYPE_UINT16 }, [DX] = { "dx", CLASS_d, TYPE_UINT16 }, [DI] = { "di", CLASS_D, TYPE_UINT16 }, [SI] = { "si", CLASS_S, TYPE_UINT16 }, /* "bp" Used as frame pointer. */ /* "sp" Used as stack pointer. */ /* 32-Bit Registers */ [AX_BX ]= { "ax_bx", CLASS_COUNT, TYPE_UINT32 }, [AX_CX ]= { "ax_cx", CLASS_COUNT, TYPE_UINT32 }, [AX_DX ]= { "ax_dx", CLASS_COUNT, TYPE_UINT32 }, [AX_DI ]= { "ax_di", CLASS_COUNT, TYPE_UINT32 }, [AX_SI ]= { "ax_si", CLASS_COUNT, TYPE_UINT32 }, [BX_AX ]= { "bx_ax", CLASS_COUNT, TYPE_UINT32 }, [BX_CX ]= { "bx_cx", CLASS_COUNT, TYPE_UINT32 }, [BX_DX ]= { "bx_dx", CLASS_COUNT, TYPE_UINT32 }, [BX_DI ]= { "bx_di", CLASS_COUNT, TYPE_UINT32 }, [BX_SI ]= { "bx_si", CLASS_COUNT, TYPE_UINT32 }, [CX_AX ]= { "cx_ax", CLASS_COUNT, TYPE_UINT32 }, [CX_BX ]= { "cx_bx", CLASS_COUNT, TYPE_UINT32 }, [CX_DX ]= { "cx_dx", CLASS_COUNT, TYPE_UINT32 }, [CX_DI ]= { "cx_di", CLASS_COUNT, TYPE_UINT32 }, [CX_SI ]= { "cx_si", CLASS_COUNT, TYPE_UINT32 }, [DX_AX ]= { "dx_ax", CLASS_COUNT, TYPE_UINT32 }, [DX_BX ]= { "dx_bx", CLASS_COUNT, TYPE_UINT32 }, [DX_CX ]= { "dx_cx", CLASS_COUNT, TYPE_UINT32 }, [DX_DI ]= { "dx_di", CLASS_COUNT, TYPE_UINT32 }, [DX_SI ]= { "dx_si", CLASS_COUNT, TYPE_UINT32 }, [DI_AX ]= { "di_ax", CLASS_COUNT, TYPE_UINT32 }, [DI_BX ]= { "di_bx", CLASS_COUNT, TYPE_UINT32 }, [DI_CX ]= { "di_cx", CLASS_COUNT, TYPE_UINT32 }, [DI_DX ]= { "di_dx", CLASS_COUNT, TYPE_UINT32 }, [DI_SI ]= { "di_si", CLASS_COUNT, TYPE_UINT32 }, [SI_AX ]= { "si_ax", CLASS_COUNT, TYPE_UINT32 }, [SI_BX ]= { "si_bx", CLASS_COUNT, TYPE_UINT32 }, [SI_CX ]= { "si_cx", CLASS_COUNT, TYPE_UINT32 }, [SI_DX ]= { "si_dx", CLASS_COUNT, TYPE_UINT32 }, [SI_DI ]= { "si_di", CLASS_COUNT, TYPE_UINT32 }, /* 64-Bit Register */ [AX_DX_DI_SI ]= { "ax_dx_di_si", CLASS_COUNT, TYPE_UINT64 }, }; static struct { unsigned int count; enum reg reg[4]; } arch_gen_reg_parts[] = { /* 8-Bit Registers */ [AL] = { 0 }, [BL] = { 0 }, [CL] = { 0 }, [DL] = { 0 }, [AH] = { 0 }, [BH] = { 0 }, [CH] = { 0 }, [DH] = { 0 }, /* 16-Bit Registers */ [AX] = { 2, { AL, AH } }, [BX] = { 2, { BL, BH } }, [CX] = { 2, { CL, CH } }, [DX] = { 2, { DL, DH } }, [DI] = { 0 }, [SI] = { 0 }, /* "bp" Used as frame pointer. */ /* "sp" Used as stack pointer. */ /* 32-Bit Registers */ [AX_BX] = { 2, { AX, BX } }, [AX_CX] = { 2, { AX, CX } }, [AX_DX] = { 2, { AX, DX } }, [AX_DI] = { 2, { AX, DI } }, [AX_SI] = { 2, { AX, SI } }, [BX_AX] = { 2, { BX, AX } }, [BX_CX] = { 2, { BX, CX } }, [BX_DX] = { 2, { BX, DX } }, [BX_DI] = { 2, { BX, DI } }, [BX_SI] = { 2, { BX, SI } }, [CX_AX] = { 2, { CX, AX } }, [CX_BX] = { 2, { CX, BX } }, [CX_DX] = { 2, { CX, DX } }, [CX_DI] = { 2, { CX, DI } }, [CX_SI] = { 2, { CX, SI } }, [DX_AX] = { 2, { DX, AX } }, [DX_BX] = { 2, { DX, BX } }, [DX_CX] = { 2, { DX, CX } }, [DX_DI] = { 2, { DX, DI } }, [DX_SI] = { 2, { DX, SI } }, [DI_AX] = { 2, { DI, AX } }, [DI_BX] = { 2, { DI, BX } }, [DI_CX] = { 2, { DI, CX } }, [DI_DX] = { 2, { DI, DX } }, [DI_SI] = { 2, { DI, SI } }, [SI_AX] = { 2, { SI, AX } }, [SI_BX] = { 2, { SI, BX } }, [SI_CX] = { 2, { SI, CX } }, [SI_DX] = { 2, { SI, DX } }, [SI_DI] = { 2, { SI, DI } }, /* 64-Bit Register */ [AX_DX_DI_SI] = { 4, { AX, DX, DI, SI } }, }; static const char *arch_reg_name_b[] = { [AL] = NULL, [BL] = NULL, [CL] = NULL, [DL] = NULL, [AH] = NULL, [BH] = NULL, [CH] = NULL, [DH] = NULL, [AX] = "al", [BX] = "bl", [CX] = "cl", [DX] = "dl", [DI] = NULL, [SI] = NULL, [AX_BX] = "al", [AX_CX] = "al", [AX_DX] = "al", [AX_DI] = "al", [AX_SI] = "al", [BX_AX] = "bl", [BX_CX] = "bl", [BX_DX] = "bl", [BX_DI] = "bl", [BX_SI] = "bl", [CX_AX] = "cl", [CX_BX] = "cl", [CX_DX] = "cl", [CX_DI] = "cl", [CX_SI] = "cl", [DX_AX] = "dl", [DX_BX] = "dl", [DX_CX] = "dl", [DX_DI] = "dl", [DX_SI] = "dl", [DI_AX] = NULL, [DI_BX] = NULL, [DI_CX] = NULL, [DI_DX] = NULL, [DI_SI] = NULL, [SI_AX] = NULL, [SI_BX] = NULL, [SI_CX] = NULL, [SI_DX] = NULL, [SI_DI] = NULL, [AX_DX_DI_SI] = "al", }; static const char *arch_reg_name_h[] = { [AL] = NULL, [BL] = NULL, [CL] = NULL, [DL] = NULL, [AH] = NULL, [BH] = NULL, [CH] = NULL, [DH] = NULL, [AX] = "ah", [BX] = "bh", [CX] = "ch", [DX] = "dh", [DI] = NULL, [SI] = NULL, [AX_BX] = "ah", [AX_CX] = "ah", [AX_DX] = "ah", [AX_DI] = "ah", [AX_SI] = "ah", [BX_AX] = "bh", [BX_CX] = "bh", [BX_DX] = "bh", [BX_DI] = "bh", [BX_SI] = "bh", [CX_AX] = "ch", [CX_BX] = "ch", [CX_DX] = "ch", [CX_DI] = "ch", [CX_SI] = "ch", [DX_AX] = "dh", [DX_BX] = "dh", [DX_CX] = "dh", [DX_DI] = "dh", [DX_SI] = "dh", [DI_AX] = NULL, [DI_BX] = NULL, [DI_CX] = NULL, [DI_DX] = NULL, [DI_SI] = NULL, [SI_AX] = NULL, [SI_BX] = NULL, [SI_CX] = NULL, [SI_DX] = NULL, [SI_DI] = NULL, [AX_DX_DI_SI] = "ah", }; static const char *arch_reg_name_w[] = { [AL] = NULL, [BL] = NULL, [CL] = NULL, [DL] = NULL, [AH] = NULL, [BH] = NULL, [CH] = NULL, [DH] = NULL, [AX] = NULL, [BX] = NULL, [CX] = NULL, [DX] = NULL, [DI] = NULL, [SI] = NULL, [AX_BX] = "bx", [AX_CX] = "cx", [AX_DX] = "dx", [AX_DI] = "di", [AX_SI] = "si", [BX_AX] = "ax", [BX_CX] = "cx", [BX_DX] = "dx", [BX_DI] = "di", [BX_SI] = "si", [CX_AX] = "ax", [CX_BX] = "bx", [CX_DX] = "dx", [CX_DI] = "di", [CX_SI] = "si", [DX_AX] = "ax", [DX_BX] = "bx", [DX_CX] = "cx", [DX_DI] = "di", [DX_SI] = "si", [DI_AX] = "ax", [DI_BX] = "bx", [DI_CX] = "cx", [DI_DX] = "dx", [DI_SI] = "si", [SI_AX] = "ax", [SI_BX] = "bx", [SI_CX] = "cx", [SI_DX] = "dx", [SI_DI] = "di", [AX_DX_DI_SI] = "dx", }; static const char *arch_reg_name_u[] = { [AL] = NULL, [BL] = NULL, [CL] = NULL, [DL] = NULL, [AH] = NULL, [BH] = NULL, [CH] = NULL, [DH] = NULL, [AX] = NULL, [BX] = NULL, [CX] = NULL, [DX] = NULL, [DI] = NULL, [SI] = NULL, [AX_BX] = NULL, [AX_CX] = NULL, [AX_DX] = NULL, [AX_DI] = NULL, [AX_SI] = NULL, [BX_AX] = NULL, [BX_CX] = NULL, [BX_DX] = NULL, [BX_DI] = NULL, [BX_SI] = NULL, [CX_AX] = NULL, [CX_BX] = NULL, [CX_DX] = NULL, [CX_DI] = NULL, [CX_SI] = NULL, [DX_AX] = NULL, [DX_BX] = NULL, [DX_CX] = NULL, [DX_DI] = NULL, [DX_SI] = NULL, [DI_AX] = NULL, [DI_BX] = NULL, [DI_CX] = NULL, [DI_DX] = NULL, [DI_SI] = NULL, [SI_AX] = NULL, [SI_BX] = NULL, [SI_CX] = NULL, [SI_DX] = NULL, [SI_DI] = NULL, [AX_DX_DI_SI] = "di", }; static const char *arch_reg_name_v[] = { [AL] = NULL, [BL] = NULL, [CL] = NULL, [DL] = NULL, [AH] = NULL, [BH] = NULL, [CH] = NULL, [DH] = NULL, [AX] = NULL, [BX] = NULL, [CX] = NULL, [DX] = NULL, [DI] = NULL, [SI] = NULL, [AX_BX] = NULL, [AX_CX] = NULL, [AX_DX] = NULL, [AX_DI] = NULL, [AX_SI] = NULL, [BX_AX] = NULL, [BX_CX] = NULL, [BX_DX] = NULL, [BX_DI] = NULL, [BX_SI] = NULL, [CX_AX] = NULL, [CX_BX] = NULL, [CX_DX] = NULL, [CX_DI] = NULL, [CX_SI] = NULL, [DX_AX] = NULL, [DX_BX] = NULL, [DX_CX] = NULL, [DX_DI] = NULL, [DX_SI] = NULL, [DI_AX] = NULL, [DI_BX] = NULL, [DI_CX] = NULL, [DI_DX] = NULL, [DI_SI] = NULL, [SI_AX] = NULL, [SI_BX] = NULL, [SI_CX] = NULL, [SI_DX] = NULL, [SI_DI] = NULL, [AX_DX_DI_SI] = "si", }; static const char *arch_reg_name_def[] = { [AL] = "al", [BL] = "bl", [CL] = "cl", [DL] = "dl", [AH] = "ah", [BH] = "bh", [CH] = "ch", [DH] = "dh", [AX] = "ax", [BX] = "bx", [CX] = "cx", [DX] = "dx", [DI] = "di", [SI] = "si", [AX_BX] = "ax", [AX_CX] = "ax", [AX_DX] = "ax", [AX_DI] = "ax", [AX_SI] = "ax", [BX_AX] = "bx", [BX_CX] = "bx", [BX_DX] = "bx", [BX_DI] = "bx", [BX_SI] = "bx", [CX_AX] = "cx", [CX_BX] = "cx", [CX_DX] = "cx", [CX_DI] = "cx", [CX_SI] = "cx", [DX_AX] = "dx", [DX_BX] = "dx", [DX_CX] = "dx", [DX_DI] = "dx", [DX_SI] = "dx", [DI_AX] = "di", [DI_BX] = "di", [DI_CX] = "di", [DI_DX] = "di", [DI_SI] = "di", [SI_AX] = "si", [SI_BX] = "si", [SI_CX] = "si", [SI_DX] = "si", [SI_DI] = "si", [AX_DX_DI_SI] = "ax", }; static unsigned int arch_classinfo[] = { ['A'] = CLASS_A, ['D'] = CLASS_D, ['Q'] = CLASS_q, ['R'] = CLASS_r, ['S'] = CLASS_S, ['a'] = CLASS_a, ['b'] = CLASS_b, ['c'] = CLASS_c, ['d'] = CLASS_d, ['l'] = CLASS_l, /* indirect addressing */ ['q'] = CLASS_q, ['r'] = CLASS_r, }; static unsigned int arch_typeinfo[TYPE_MAX] = { [TYPE_VA_LIST] = CLASS_r, [TYPE_INT8] = CLASS_q, [TYPE_UINT8] = CLASS_q, [TYPE_INT16] = CLASS_r, [TYPE_UINT16] = CLASS_r, [TYPE_INT32] = CLASS_r, [TYPE_UINT32] = CLASS_r, [TYPE_INT64] = CLASS_r, [TYPE_UINT64] = CLASS_r, [TYPE_FLOAT32] = CLASS_NONE, [TYPE_FLOAT64] = CLASS_NONE, [TYPE_FLOAT80] = CLASS_NONE, [TYPE_STRUCT] = CLASS_NONE, [TYPE_UNION] = CLASS_NONE, [TYPE_POINTER] = CLASS_r, [TYPE_ARRAY] = CLASS_NONE, [TYPE_FUNCTION] = CLASS_NONE, }; static int seg_enabled(void) { return opt_f_segment_enable; } struct type * arch_i286_type_intptr_t(void) { if (seg_enabled()) { return type_int32(); } else { return type_int16(); } } struct type * arch_i286_type_uintptr_t(void) { if (seg_enabled()) { return type_uint32(); } else { return type_uint16(); } } void arch_i286_align_size( struct scope *scope, struct type *t, unsigned int *alignp, unsigned int *sizep ) { switch (t->type) { case TYPE_INT8: case TYPE_UINT8: *alignp = 1; *sizep = 1; break; case TYPE_INT16: case TYPE_UINT16: *alignp = 2; *sizep = 2; break; case TYPE_INT32: case TYPE_UINT32: *alignp = 2; *sizep = 4; break; case TYPE_INT64: case TYPE_UINT64: *alignp = 2; *sizep = 8; break; case TYPE_FLOAT32: *alignp = 2; *sizep = 4; break; case TYPE_FLOAT64: *alignp = 2; *sizep = 8; break; case TYPE_FLOAT80: *alignp = 2; *sizep = 16; break; case TYPE_VA_LIST: *alignp = 2; *sizep = 2; break; case TYPE_POINTER: *alignp = 2; *sizep = 2; break; default: assert(0); } } void arch_i286_gen_class_and_type_get( const char *name, unsigned int *classp, enum type_type *typep ) { unsigned int reg; for (reg = 0; ; reg++) { assert(reg < REG_COUNT); if (strcmp(arch_reginfo[reg].name, name) == 0) { *classp = arch_reginfo[reg].class; *typep = arch_reginfo[reg].type; break; } } } unsigned int arch_i286_gen_class_or(unsigned int a, unsigned int b) { unsigned int class; if (a == CLASS_NONE) { class = b; } else if (b == CLASS_NONE) { class = a; } else { /* FIXME */ class = 0; /* Make cppcheck happy. */ assert(0); } return class; } unsigned int arch_i286_gen_class_and(unsigned int a, unsigned int b) { unsigned int class; if (a == CLASS_r) { class = b; } else if (b == CLASS_r) { class = a; } else if (a == CLASS_q) { class = b; } else if (b == CLASS_q) { class = a; } else if (a == b) { class = a; } else { class = CLASS_NONE; } return class; } void arch_i286_color_init(unsigned int *count) { unsigned int class; for (class = 0; class < DECL_CLASS_COUNT; class++) { count[class] = 0; } } void arch_i286_color_add(unsigned int *count, unsigned int class, enum type_type type) { switch (class) { case CLASS_NONE: break; case CLASS_A: switch (type) { case TYPE_INT8: case TYPE_UINT8: count[CLASS_a]++; break; case TYPE_INT16: case TYPE_UINT16: count[CLASS_a]++; break; case TYPE_INT32: case TYPE_UINT32: count[CLASS_a]++; count[CLASS_d]++; break; case TYPE_INT64: case TYPE_UINT64: count[CLASS_a]++; count[CLASS_d]++; count[CLASS_D]++; count[CLASS_S]++; break; case TYPE_VA_LIST: count[CLASS_a]++; break; default: assert(0); /* Mustn't happen. */ } break; case CLASS_D: case CLASS_S: assert(/*type == TYPE_VA_LIST || */type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_POINTER); count[class]++; break; case CLASS_a: if (type == TYPE_INT8 || type == TYPE_UINT8 || type == TYPE_INT16 || type == TYPE_UINT16) { count[class]++; } else if (type == TYPE_INT32 || type == TYPE_UINT32) { count[class]++; count[CLASS_r]++; } else if (type == TYPE_INT64 || type == TYPE_UINT64) { count[CLASS_D]++; count[CLASS_S]++; count[CLASS_a]++; count[CLASS_d]++; } else { assert(0); } break; case CLASS_b: case CLASS_c: case CLASS_d: if (type == TYPE_INT8 || type == TYPE_UINT8 || type == TYPE_INT16 || type == TYPE_UINT16) { count[class]++; } else if (type == TYPE_INT32 || type == TYPE_UINT32) { count[class]++; count[CLASS_r]++; } else { assert(0); } break; case CLASS_q: if (type == TYPE_INT8 || type == TYPE_UINT8 /* || type == TYPE_VA_LIST*/ || type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_POINTER) { count[class]++; } else if (type == TYPE_INT32 || type == TYPE_UINT32) { count[class]++; count[CLASS_r]++; } else if (type == TYPE_INT64 || type == TYPE_UINT64) { count[CLASS_D]++; count[CLASS_S]++; count[CLASS_a]++; count[CLASS_d]++; } else { assert(0); } break; case CLASS_r: if (/*type == TYPE_VA_LIST || */type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_POINTER) { count[class]++; } else if (type == TYPE_VA_LIST || type == TYPE_INT32 || type == TYPE_UINT32) { count[class]++; count[CLASS_r]++; } else if (type == TYPE_INT64 || type == TYPE_UINT64) { count[CLASS_D]++; count[CLASS_S]++; count[CLASS_a]++; count[CLASS_d]++; } else { assert(0); } break; case CLASS_l: if (/*type == TYPE_VA_LIST || */type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_POINTER) { count[class]++; } else if (type == TYPE_VA_LIST || type == TYPE_INT32 || type == TYPE_UINT32) { count[class]++; count[CLASS_r]++; } else { assert(0); } break; default: fprintf(stderr, "class: %u, type: %u\n", class, type); assert(0); } } void arch_i286_color_sub(unsigned int *count, unsigned int class, enum type_type type) { switch (class) { case CLASS_NONE: break; case CLASS_A: assert(type == TYPE_INT32 || type == TYPE_UINT32); assert(0 < count[CLASS_a]); count[CLASS_a]--; assert(0 < count[CLASS_d]); count[CLASS_d]--; break; case CLASS_D: case CLASS_S: assert(/*type == TYPE_VA_LIST || */type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_POINTER); assert(0 < count[class]); count[class]--; break; case CLASS_a: if (type == TYPE_INT8 || type == TYPE_UINT8 || type == TYPE_INT16 || type == TYPE_UINT16) { assert(0 < count[CLASS_a]); count[CLASS_a]--; } else if (type == TYPE_INT32 || type == TYPE_UINT32) { assert(0 < count[CLASS_a]); count[CLASS_a]--; assert(0 < count[CLASS_r]); count[CLASS_r]--; } else if (type == TYPE_INT64 || type == TYPE_UINT64) { assert(0 < count[CLASS_D]); count[CLASS_D]--; assert(0 < count[CLASS_S]); count[CLASS_S]--; assert(0 < count[CLASS_a]); count[CLASS_a]--; assert(0 < count[CLASS_d]); count[CLASS_d]--; } else { assert(0); } break; case CLASS_b: case CLASS_c: case CLASS_d: if (type == TYPE_INT8 || type == TYPE_UINT8 || type == TYPE_INT16 || type == TYPE_UINT16) { assert(0 < count[class]); count[class]--; } else if (type == TYPE_INT32 /* FIXME */ || type == TYPE_UINT32) { assert(0 < count[class]); count[class]--; assert(0 < count[CLASS_r]); count[CLASS_r]--; } else { assert(0); } break; case CLASS_q: if (type == TYPE_INT8 || type == TYPE_UINT8 /* || type == TYPE_VA_LIST*/ || type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_POINTER) { assert(0 < count[class]); count[class]--; } else if (type == TYPE_INT32 || type == TYPE_UINT32) { assert(0 < count[class]); count[class]--; assert(0 < count[CLASS_r]); count[CLASS_r]--; } else if (type == TYPE_INT64 || type == TYPE_UINT64) { assert(0 < count[CLASS_D]); count[CLASS_D]--; assert(0 < count[CLASS_S]); count[CLASS_S]--; assert(0 < count[CLASS_a]); count[CLASS_a]--; assert(0 < count[CLASS_d]); count[CLASS_d]--; } else { assert(0); } break; case CLASS_r: if (/*type == TYPE_VA_LIST ||*/ type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_POINTER) { assert(0 < count[class]); count[class]--; } else if (type == TYPE_VA_LIST || type == TYPE_INT32 || type == TYPE_UINT32) { assert(0 < count[class]); count[class]--; assert(0 < count[CLASS_r]); count[CLASS_r]--; } else if (type == TYPE_INT64 || type == TYPE_UINT64) { assert(0 < count[CLASS_D]); count[CLASS_D]--; assert(0 < count[CLASS_S]); count[CLASS_S]--; assert(0 < count[CLASS_a]); count[CLASS_a]--; assert(0 < count[CLASS_d]); count[CLASS_d]--; } else { assert(0); } break; case CLASS_l: assert(0 < count[class]); if (/*type == TYPE_VA_LIST || */type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_POINTER) { count[class]--; } else if (type == TYPE_VA_LIST || type == TYPE_INT32 || type == TYPE_UINT32) { count[class]--; count[CLASS_r]--; } else { assert(0); } break; default: fprintf(stderr, "class: %u, type: %u\n", class, type); assert(0); } } int arch_i286_color_check(unsigned int *count, unsigned int class, enum type_type type) { unsigned int num; switch (class) { case CLASS_NONE: /* Memory only. */ return 0; case CLASS_A: num = (1 < count[CLASS_a]) ? 1 : count[CLASS_a]; num += (1 < count[CLASS_d]) ? 1 : count[CLASS_d]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (1 < num) num = 1; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (1 < num) num = 1; return num < 1; case CLASS_D: num = (1 < count[CLASS_D]) ? 1 : count[CLASS_D]; num += (3 < count[CLASS_l]) ? 3 : count[CLASS_l]; if (1 < num) num = 1; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (1 < num) num = 1; return num < 1; case CLASS_S: num = (1 < count[CLASS_S]) ? 1 : count[CLASS_S]; num += (3 < count[CLASS_l]) ? 3 : count[CLASS_l]; if (1 < num) num = 1; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (1 < num) num = 1; return num < 1; case CLASS_a: num = (1 < count[CLASS_a]) ? 1 : count[CLASS_a]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (1 < num) num = 1; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (1 < num) num = 1; return num < 1; case CLASS_b: num = (1 < count[CLASS_b]) ? 1 : count[CLASS_b]; num += (3 < count[CLASS_l]) ? 3 : count[CLASS_l]; if (1 < num) num = 1; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (1 < num) num = 1; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (1 < num) num = 1; return num < 1; case CLASS_c: num = (1 < count[CLASS_c]) ? 1 : count[CLASS_c]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (1 < num) num = 1; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (1 < num) num = 1; return num < 1; case CLASS_d: num = (1 < count[CLASS_d]) ? 1 : count[CLASS_d]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (4 < num) num = 4; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (6 < num) num = 6; return num < 1; case CLASS_q: num = (1 < count[CLASS_b]) ? 1 : count[CLASS_b]; num += (3 < count[CLASS_l]) ? 3 : count[CLASS_l]; if (1 < num) num = 1; num += (1 < count[CLASS_a]) ? 1 : count[CLASS_a]; num += (1 < count[CLASS_c]) ? 1 : count[CLASS_c]; num += (1 < count[CLASS_d]) ? 1 : count[CLASS_d]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (4 < num) num = 4; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (4 < num) num = 4; return num < 4; case CLASS_r: if (type == TYPE_INT8 || type == TYPE_UINT8) { assert(0); /* Don't request 'r' for bytes! */ } else if (/*type == TYPE_VA_LIST ||*/ type == TYPE_INT16 || type == TYPE_UINT16 || type == TYPE_POINTER) { num = (1 < count[CLASS_a]) ? 1 : count[CLASS_a]; num += (1 < count[CLASS_b]) ? 1 : count[CLASS_b]; num += (1 < count[CLASS_c]) ? 1 : count[CLASS_c]; num += (1 < count[CLASS_d]) ? 1 : count[CLASS_d]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (4 < num) num = 4; num += (1 < count[CLASS_D]) ? 1 : count[CLASS_D]; num += (1 < count[CLASS_S]) ? 1 : count[CLASS_S]; num += (3 < count[CLASS_l]) ? 3 : count[CLASS_l]; /* Correct? */ if (6 < num) num = 6; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (6 < num) num = 6; return num < 6; } else if (type == TYPE_VA_LIST || type == TYPE_INT32 || type == TYPE_UINT32) { num = (1 < count[CLASS_a]) ? 1 : count[CLASS_a]; num += (1 < count[CLASS_b]) ? 1 : count[CLASS_b]; num += (1 < count[CLASS_c]) ? 1 : count[CLASS_c]; num += (1 < count[CLASS_d]) ? 1 : count[CLASS_d]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (4 < num) num = 4; num += (1 < count[CLASS_D]) ? 1 : count[CLASS_D]; num += (1 < count[CLASS_S]) ? 1 : count[CLASS_S]; num += (3 < count[CLASS_l]) ? 3 : count[CLASS_l]; /* Correct? */ if (6 < num) num = 6; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (6 < num) num = 6; return num < 5; } else if (type == TYPE_INT64 || type == TYPE_UINT64) { num = (1 < count[CLASS_a]) ? 1 : count[CLASS_a]; num += (1 < count[CLASS_d]) ? 1 : count[CLASS_d]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (4 < num) num = 4; num += (1 < count[CLASS_D]) ? 1 : count[CLASS_D]; num += (1 < count[CLASS_S]) ? 1 : count[CLASS_S]; num += (3 < count[CLASS_l]) ? 3 : count[CLASS_l]; if (6 < num) num = 6; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (6 < num) num = 6; return num < 1; } else { assert(0); return 0; } case CLASS_l: if (/*type == TYPE_VA_LIST ||*/ type == TYPE_INT16 || type == TYPE_UINT16/* || type == TYPE_POINTER*/) { num = (1 < count[CLASS_b]) ? 1 : count[CLASS_b]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (1 < num) num = 1; num += (1 < count[CLASS_D]) ? 1 : count[CLASS_D]; num += (1 < count[CLASS_S]) ? 1 : count[CLASS_S]; num += (3 < count[CLASS_l]) ? 3 : count[CLASS_l]; /* Correct? */ if (3 < num) num = 3; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (3 < num) num = 3; return num < 3; } else if (type == TYPE_VA_LIST || type == TYPE_INT32 || type == TYPE_POINTER || type == TYPE_UINT32) { num = (1 < count[CLASS_b]) ? 1 : count[CLASS_b]; num += (4 < count[CLASS_q]) ? 4 : count[CLASS_q]; if (1 < num) num = 1; num += (1 < count[CLASS_D]) ? 1 : count[CLASS_D]; num += (1 < count[CLASS_S]) ? 1 : count[CLASS_S]; num += (3 < count[CLASS_l]) ? 3 : count[CLASS_l]; if (3 < num) num = 3; num += (6 < count[CLASS_r]) ? 6 : count[CLASS_r]; if (3 < num) num = 3; return num < 1; } else { assert(0); return 0; } default: fprintf(stderr, "class: %u, type: %u\n", class, type); assert(0); } } void arch_i286_gen_reg_init(uint32_t *conflicts) { memset(conflicts, 0, (REG_COUNT + 7) / 8); } static void arch_gen_reg_add_2(uint32_t *conflicts, unsigned int reg) { unsigned int count; unsigned int reg2; *(uint64_t *) conflicts |= 1ULL << reg; for (reg2 = 0; reg2 < REG_COUNT; reg2++) { for (count = 0; count < arch_gen_reg_parts[reg2].count; count++) { if (arch_gen_reg_parts[reg2].reg[count] == reg) { arch_gen_reg_add_2(conflicts, reg2); } } } } static void arch_gen_reg_add_1(uint32_t *conflicts, unsigned int reg) { if (arch_gen_reg_parts[reg].count == 0) { arch_gen_reg_add_2(conflicts, reg); } else { unsigned int count; unsigned int reg2; for (count = 0; count < arch_gen_reg_parts[reg].count; count++) { reg2 = arch_gen_reg_parts[reg].reg[count]; arch_gen_reg_add_1(conflicts, reg2); } } } void arch_i286_gen_reg_add(uint32_t *conflicts, unsigned int reg) { arch_gen_reg_add_1(conflicts, reg); } int arch_i286_gen_reg_get( uint32_t *conflicts, unsigned int class, enum type_type type ) { uint64_t regs; unsigned int reg; switch (class) { case CLASS_NONE: regs = 0; break; case CLASS_A: regs = REG_A; break; case CLASS_D: regs = REG_D; break; case CLASS_S: regs = REG_S; break; case CLASS_a: regs = REG_a; break; case CLASS_b: regs = REG_b; break; case CLASS_c: regs = REG_c; break; case CLASS_d: regs = REG_d; break; case CLASS_q: regs = REG_q; break; case CLASS_r: regs = REG_r; break; case CLASS_l: regs = REG_l; break; default: assert(0); break; } switch (type) { case TYPE_NONE: regs &= 0; break; case TYPE_INT8: case TYPE_UINT8: regs &= REG_8; break; case TYPE_INT16: case TYPE_UINT16: regs &= REG_16; break; case TYPE_INT32: case TYPE_UINT32: regs &= REG_32; break; case TYPE_INT64: case TYPE_UINT64: regs &= REG_64; break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: regs &= 0; break; case TYPE_UNION: regs &= 0; break; case TYPE_STRUCT: regs &= 0; break; case TYPE_ARRAY: regs &= 0; break; case TYPE_FUNCTION: regs &= 0; break; case TYPE_VA_LIST: regs &= REG_16; break; default: assert(0); break; } regs &= ~ *(uint64_t *) conflicts; for (reg = 0; ; reg++) { if (reg == REG_COUNT) { return -1; } if ((regs >> reg) & 1) { return reg; } } } static const char * arch_gen_name(unsigned int local, const char *prefix, const char *name) { static unsigned int rand = 0; static char buf[10][1024]; static unsigned int cur = 0; char *retval; if (! rand) { struct timeval tv; int ret; ret = gettimeofday(&tv, NULL); assert(0 <= ret); rand = tv.tv_sec ^ tv.tv_usec; } retval = buf[cur]; cur = (cur + 1) % 10; if (prefix) { strcpy(retval, prefix); strcat(retval, "_"); } else { strcpy(retval, ""); } if (local && seg_enabled()) { sprintf(retval + strlen(retval), "L%08x_", rand); } strcat(retval, name); return retval; } static void arch_gen_name_def(int local, const char *name) { } static void arch_gen_local_def(const char *name) { arch_gen_name_def(1, name); } static const char * arch_gen_local(const char *name) { return arch_gen_name(1, NULL, name); } static const char * arch_gen_local_seg(const char *name) { assert(seg_enabled()); return arch_gen_name(1, "SEG", name); } static const char * arch_gen_local_off(const char *name) { if (seg_enabled()) { return arch_gen_name(1, "OFF", name); } else { return arch_gen_name(1, NULL, name); } } static void arch_gen_global_def(const char *name) { arch_gen_name_def(0, name); } static const char * arch_gen_global(const char *name) { return arch_gen_name(0, NULL, name); } static const char * arch_gen_global_seg(const char *name) { assert(seg_enabled()); return arch_gen_name(0, "SEG", name); } static const char * arch_gen_global_off(const char *name) { if (seg_enabled()) { return arch_gen_name(0, "OFF", name); } else { return arch_gen_name(0, NULL, name); } } static void arch_gen_data_init( FILE *fp, struct scope *scope, struct type *t, struct expr *e ) { struct declaration *dion; switch (t->type) { case TYPE_NONE: case TYPE_ELIPSIS: case TYPE_VOID: case TYPE_UNION: case TYPE_ENUM: case TYPE_FUNCTION: case TYPE_MAX: assert(0); case TYPE_INT8: case TYPE_UINT8: if (e) { assert(e->type == EXPR_INTEGER); fprintf(fp, "\t.byte 0x%02x\n", (uint8_t) e->integer); } else { fprintf(fp, "\t.byte 0x00\n"); } break; case TYPE_INT16: case TYPE_UINT16: if (e) { switch (e->type) { case EXPR_INTEGER: fprintf(fp, "\t.word 0x%04x\n", (uint16_t) e->integer); break; case EXPR_TYPE_CONVERSION: if (e->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ dion = e->expr0->expr0->declaration; } else if (e->expr0->type == EXPR_IDENTIFIER) { /* * Special case: (int) array * Special case: (int) func */ dion = e->expr0->declaration; } else { dion = NULL; } assert(dion); if (seg_enabled()) { assert(0); /* Mustn't happen. */ } else { if (dion->storage == STORAGE_STATIC) { fprintf(fp, "\t.word %s\n", arch_gen_local_off(dion->identifier)); } else { fprintf(fp, "\t.word %s\n", arch_gen_global_off(dion->identifier)); } } break; default: assert(0); } } else { fprintf(fp, "\t.word 0x0000\n"); } break; case TYPE_INT32: case TYPE_UINT32: if (e) { switch (e->type) { case EXPR_INTEGER: fprintf(fp, "\t.word 0x%04x, 0x%04x\n", (uint16_t) e->integer, (uint16_t) (e->integer >> 16)); break; case EXPR_TYPE_CONVERSION: if (e->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ dion = e->expr0->expr0->declaration; } else if (e->expr0->type == EXPR_IDENTIFIER) { /* * Special case: (int) array * Special case: (int) func */ dion = e->expr0->declaration; } else { dion = NULL; } assert(dion); if (seg_enabled()) { if (dion->storage == STORAGE_STATIC) { fprintf(fp, "\t.word %s, %s\n", arch_gen_local_off(dion->identifier), arch_gen_local_seg(dion->identifier)); } else { fprintf(fp, "\t.word %s, %s\n", arch_gen_global_off(dion->identifier), arch_gen_global_seg(dion->identifier)); } } else { assert(0); /* Mustn't happen. */ } break; default: assert(0); } } else { fprintf(fp, "\t.word 0x0000, 0x0000\n"); } break; case TYPE_INT64: case TYPE_UINT64: if (e) { switch (e->type) { case EXPR_INTEGER: fprintf(fp, "\t.word 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", (uint16_t) e->integer, (uint16_t) (e->integer >> 16), (uint16_t) (e->integer >> 32), (uint16_t) (e->integer >> 48)); break; default: assert(0); } } else { fprintf(fp, "\t.word 0x0000, 0x0000, 0x0000, 0x0000\n"); } break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_STRUCT: { struct expr *ce; if (! t->scope) { int ret; ret = scope_lookup_structunionenum(scope, t->type, t->identifier, &t); assert(0 <= ret); } assert(t->scope); for (dion = t->scope->declaration_first, ce = e->first; dion; dion = dion->next, ce = (ce ? ce->next : NULL)) { arch_gen_data_init(fp, scope, dion->type_name, ce); } break; } case TYPE_VA_LIST: case TYPE_POINTER: assert(0); break; case TYPE_ARRAY: { unsigned long long dim; struct expr *ce; unsigned long long i; unsigned char c; assert(t->dimension); assert(t->dimension->type == EXPR_INTEGER); dim = t->dimension->integer; t = type_array_access(t); switch (e->type) { case EXPR_BRACES: for (i = 0, ce = e->first; i < dim; i++, ce = (ce ? ce->next : NULL)) { arch_gen_data_init(fp, scope, t, ce); } break; case EXPR_STRING: assert(t->type == TYPE_INT8 || t->type == TYPE_UINT8); fprintf(fp, "\t.string \""); for (i = 0; i < dim; i++) { if (i < e->string_len) { c = e->string[i]; } else { c = '\0'; } switch (c) { case '\0': fprintf(fp, "\\0"); break; case '\a': fprintf(fp, "\\a"); break; case '\b': fprintf(fp, "\\b"); break; case '\n': fprintf(fp, "\\n"); break; case '\r': fprintf(fp, "\\r"); break; case '\t': fprintf(fp, "\\t"); break; case '"': fprintf(fp, "\\\""); break; case '\\': fprintf(fp, "\\\\"); break; default: if (' ' <= c && c < 127) { fprintf(fp, "%c", c); } else { fprintf(fp, "\\%03o", c); } } } fprintf(fp, "\"\n"); break; default: assert(0); } break; } default: assert(0); } } static void arch_gen_data(FILE *fp, struct scope *scope, struct declaration *dion) { unsigned int align; unsigned int size; type_align_size(scope, dion->type_name, &align, &size); if (dion->attr_aligned) { align = dion->attr_aligned; } if (dion->type_name->mod_const) { fprintf(fp, "\t.section .rodata\n"); } else { fprintf(fp, "\t.data\n"); } if (dion->initializer) { if (dion->storage == STORAGE_STATIC) { if (seg_enabled()) { /* * NOTE: * Label *must* be global. Otherwise our * linker tool will not generate __SEG_x/__OFF_x * symbols for it. */ fprintf(fp, "\t.globl %s\n", arch_gen_local(dion->identifier)); } fprintf(fp, "\t.align %u\n", align); fprintf(fp, "\t.type %s, @object\n", arch_gen_local(dion->identifier)); fprintf(fp, "\t.size %s, %u\n", arch_gen_local(dion->identifier), size); fprintf(fp, "%s:\n", arch_gen_local(dion->identifier)); } else { fprintf(fp, "\t.globl %s\n", arch_gen_global(dion->identifier)); fprintf(fp, "\t.align %u\n", align); fprintf(fp, "\t.type %s, @object\n", arch_gen_global(dion->identifier)); fprintf(fp, "\t.size %s, %u\n", arch_gen_global(dion->identifier), size); fprintf(fp, "%s:\n", arch_gen_global(dion->identifier)); } arch_gen_data_init(fp, scope, dion->type_name, dion->initializer); } else { if (dion->storage == STORAGE_STATIC) { fprintf(fp, "\t.local %s\n", arch_gen_local(dion->identifier)); fprintf(fp, "\t.comm %s, %u, %u\n", arch_gen_local(dion->identifier), size, align); } else { fprintf(fp, "\t.comm %s, %u, %u\n", arch_gen_global(dion->identifier), size, align); } } } static struct declaration * arch_tmp(struct scope *s, struct type *t) { struct declaration *var; var = simplify_declaration_add(s, t, identifier_tmp()); var->storage = STORAGE_AUTO; return var; } static void arch_op_func( struct expr *e, struct declaration *dion ) { struct expr *ce0; struct expr *ce1; ce0 = e->expr0; ce1 = e->expr1; e->type = EXPR_FUNC; e->expr0 = expr_new(); e->expr0->type = EXPR_IDENTIFIER; e->expr0->declaration = dion; e->expr1 = expr_new(); e->expr1->type = EXPR_LIST; ce0->prev = NULL; ce0->next = ce1; ce1->prev = ce0; ce1->next = NULL; e->expr1->first = ce0; e->expr1->last = ce1; } static void arch_gen_expr_1( struct stmt *block, struct stmt *s, struct expr *e, struct expr *lhs ) { struct type *t; struct type *t1; struct expr *ce; struct declaration *var; struct declaration *dion; uint64_t regs_change; unsigned int reg; t = expr_typeof(block->scope, e); t = type_pure(t); assert(lhs || e->type == EXPR_FUNC); if (lhs && lhs->type == EXPR_IDENTIFIER && (lhs->declaration->storage == STORAGE_STATIC || lhs->declaration->storage == STORAGE_NONE || lhs->declaration->storage == STORAGE_EXTERN)) { /* * Store Operation */ assert(e->type == EXPR_INTEGER || e->type == EXPR_REAL || e->type == EXPR_IDENTIFIER); var = arch_tmp(block->scope, type_uint16()); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: if (seg_enabled()) { /* * movw %w1, %0 * movw %0, %%es * movb %2, %%es:%1 */ constraint_output(s, "=&r", expr_identifier(var)); constraint_output(s, "=m", expr_dup(lhs)); constraint_input(s, "iq", expr_dup(e)); } else { /* * movb %1, %0 */ constraint_output(s, "=m", expr_dup(lhs)); constraint_input(s, "iq", expr_dup(e)); } break; case TYPE_INT16: case TYPE_UINT16: if (seg_enabled()) { /* * movw %w1, %0 * movw %0, %%es * movw %2, %%es:%1 */ } else { /* * movw %1, %0 */ } /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: if (seg_enabled()) { /* * movw %w1, %0 * movw %0, %%es * movw %2, %es:%1 * movw %w2, %es:2+%1 */ } else { /* * movw %1, %0 * movw %w1, 2+%0 */ } /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: if (seg_enabled()) { /* * movw %w1, %0 * movw %0, %%es * movw %2, %%es:%1 * movw %w2, %%es:2+%1 * movw %u2, %%es:4+%1 * movw %v2, %%es:6+%1 */ constraint_output(s, "=&r", expr_identifier(var)); constraint_output(s, "=m", expr_dup(lhs)); constraint_input(s, "ir", expr_dup(e)); } else { /* * movw %1, %0 * movw %w1, 2+%0 * movw %u1, 4+%0 * movw %v1, 6+%0 */ constraint_output(s, "=m", expr_dup(lhs)); constraint_input(s, "ir", expr_dup(e)); } break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ case TYPE_VA_LIST: assert(0); /* FIXME */ default: assert(0); /* Mustn't happen. */ } } else if (e->type == EXPR_IDENTIFIER && (e->declaration->storage == STORAGE_STATIC || e->declaration->storage == STORAGE_NONE || e->declaration->storage == STORAGE_EXTERN)) { /* * Load Operation */ assert(lhs && lhs->type == EXPR_IDENTIFIER && lhs->declaration->storage != STORAGE_STATIC && lhs->declaration->storage != STORAGE_NONE && lhs->declaration->storage != STORAGE_EXTERN); if (seg_enabled()) { var = arch_tmp(block->scope, type_uint16()); } else { var = NULL; } switch (t->type) { case TYPE_INT8: case TYPE_UINT8: if (seg_enabled()) { /* * movw %w2, %1 * movw %1, %%es * movb %%es:%2, %0 */ } else { /* * movb %1, %0 */ } /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: if (seg_enabled()) { /* * movw %w2, %1 * movw %1, %%es * movw %%es:%2, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_output(s, "=&r", expr_identifier(var)); constraint_input(s, "m", expr_dup(e)); } else { /* * movw %1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "m", expr_dup(e)); } break; case TYPE_INT32: case TYPE_UINT32: if (seg_enabled()) { /* * movw %w2, %1 * movw %1, %%es * movw %es:%2, %0 * movw %es:2+%2, %w0 */ } else { /* * movw %1, %0 * movw 2+%1, %w0 */ } /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: if (seg_enabled()) { /* * movw %w2, %1 * movw %1, %%es * movw %es:%2, %0 * movw %es:2+%2, %w0 * movw %es:4+%2, %u0 * movw %es:6+%2, %v0 */ constraint_output(s, "=&r", expr_dup(lhs)); constraint_output(s, "=&r", expr_identifier(var)); constraint_input(s, "m", expr_dup(e)); } else { /* * movw %1, %0 * movw 2+%1, %w0 * movw 4+%1, %u0 * movw 6+%1, %v0 */ constraint_output(s, "=&r", expr_dup(lhs)); constraint_input(s, "m", expr_dup(e)); } break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ case TYPE_VA_LIST: assert(0); /* FIXME */ default: assert(0); /* Mustn't happen. */ } } else { /* * Non-Load/Non-Store Operation */ switch (e->type) { case EXPR_NONE: case EXPR_BRACES: case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_ASSIGN: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: case EXPR_NOT: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_LIST: case EXPR_STRING: case EXPR_AMPHERSAND: assert(0); break; case EXPR_INTEGER: case EXPR_REAL: case EXPR_IDENTIFIER: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * movb %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * movw %1, %0 */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "ir", expr_dup(e)); break; case TYPE_INT32: case TYPE_UINT32: /* * movw %1, %0 * movw %w1, %w0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movw %1, %0 * movw %w1, %w0 * movw %u1, %v0 * movw %v1, %v0 */ constraint_output(s, "=&r", expr_dup(lhs)); constraint_input(s, "imr", expr_dup(e)); break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_BUILTIN_VA_ARG: t1 = e->type_name; switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: /* * movb [%ss:](%1), %0 * addw $2, %1 */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * movw [%ss:](%1), %0 * addw $2, %1 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * movw [%ss:](%1), %0 * movw [%ss:]2(%1), %w0 * addw $4, %1 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movw [%ss:](%1), %0 * movw [%ss:]2(%1), %w0 * movw [%ss:]4(%1), %u0 * movw [%ss:]6(%1), %v0 * addw $8, %1 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_output(s, "=l", expr_dup(e->expr0)); constraint_input(s, "1", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_TYPE_CONVERSION: if (e->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ dion = e->expr0->expr0->declaration; e = e->expr0->expr0; goto special; } else if (e->expr0->type == EXPR_IDENTIFIER && (e->expr0->declaration->type_name->type == TYPE_ARRAY || e->expr0->declaration->type_name->type == TYPE_FUNCTION)) { /* * Special case: (int) array * Special case: (int) function */ dion = e->expr0->declaration; e = e->expr0; special: if (dion->storage == STORAGE_NONE || dion->storage == STORAGE_EXTERN || dion->storage == STORAGE_STATIC) { /* * movw $%1, %0 * [movw $%w1, %w0] */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "m", expr_dup(e)); } else { /* * leaw %1, %0 * [movw %%ss, %w0] */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "m", expr_dup(e)); } break; } t1 = expr_typeof(block->scope, e->expr0); t1 = type_pure(t1); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: /* * No code. */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; case TYPE_INT16: case TYPE_UINT16: /* * movb %b1, %0 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * movb %b1, %0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movb %b1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mq", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT16: case TYPE_UINT16: switch (t1->type) { case TYPE_INT8: /* * cbw */ constraint_output(s, "=a", expr_dup(lhs)); constraint_input(s, "a", expr_dup(e->expr0)); break; case TYPE_UINT8: /* * movb %1, %0 * xorb %h0, %h0 */ constraint_output(s, "=&q", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_INT16: case TYPE_UINT16: /* * No code. */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; case TYPE_INT32: case TYPE_UINT32: /* * movw %1, %0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * movw %1, %0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT32: case TYPE_UINT32: switch (t1->type) { case TYPE_INT8: /* * cbw * cwd */ constraint_output(s, "=A", expr_dup(lhs)); constraint_input(s, "a", expr_dup(e->expr0)); break; case TYPE_UINT8: /* * movb %1, %b0 * xorb %h0, %h0 * xorw %w0, %w0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_INT16: /* * cwd */ constraint_output(s, "=A", expr_dup(lhs)); constraint_input(s, "a", expr_dup(e->expr0)); break; case TYPE_UINT16: /* * movw %1, %0 * xorw %w0, %w0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_INT32: case TYPE_UINT32: /* * No code. */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; case TYPE_INT64: case TYPE_UINT64: /* * movw %1, %0 * movw %w1, %w0 */ constraint_output(s, "=&r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT64: case TYPE_UINT64: switch (t1->type) { case TYPE_INT8: /* * cbw * cwd * movw %%dx, %u0 * movw %%dx, %v0 */ constraint_output(s, "=A", expr_dup(lhs)); constraint_input(s, "a", expr_dup(e->expr0)); break; case TYPE_UINT8: /* * movb %1, %0 * xorb %h0, %h0 * xorw %w0, %w0 * xorw %u0, %u0 * xorw %v0, %v0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_INT16: /* * cwd * movw %%dx, %u0 * movw %%dx, %v0 */ constraint_output(s, "=A", expr_dup(lhs)); constraint_input(s, "a", expr_dup(e->expr0)); break; case TYPE_UINT16: /* * movw %1, %0 * xorw %w0, %w0 * xorw %u0, %u0 * xorw %v0, %v0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_INT32: /* * movw %1, %v0 * movw %w1, %0 * cwd * xchgw %w0, %v0 * xchgw %w0, %0 * movw %v0, %u0 */ constraint_output(s, "=A", expr_dup(lhs)); constraint_input(s, "A", expr_dup(e->expr0)); break; case TYPE_UINT32: /* * movw %1, %0 * movw %w1, %w0 * xorw %u0, %u0 * xorw %v0, %v0 */ constraint_output(s, "=&r", expr_dup(lhs)); constraint_input(s, "mr", expr_dup(e->expr0)); break; case TYPE_INT64: case TYPE_UINT64: /* * No code. */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_STAR: assert(lhs); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * [movw %w1, %%es] * movb [%%es:](%1), %0 */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * [movw %w1, %%es] * movw [%%es:](%1), %0 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * [movw %w1, %%es] * movw [%%es:](%1), %0 * movw [%%es:]2(%1), %w0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * [movw %w1, %%es] * movw [%%es:](%1), %0 * movw [%%es:]2(%1), %w0 * movw [%%es:]4(%1), %u0 * movw [%%es:]6(%1), %v0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "l", expr_dup(e->expr0->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_NEG: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * negb %0 */ /*FALLTRHOUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * negw %0 */ /*FALLTRHOUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * negw %0 * adcw $0, %w0 * negw %w0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * negw %0 * adcw $0, %w0 * adcw $0, %u0 * adcw $0, %v0 * negw %w0 * adcw $0, %u0 * adcw $0, %v0 * negw %u0 * adcw $0, %v0 * negw %v0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } case EXPR_INV: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * xorb $-1, %0 */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * xorw $-1, %0 */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * xorw $-1, %0 * xorw $-1, %w0 */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * xorw $-1, %0 * xorw $-1, %w0 * xorw $-1, %u0 * xorw $-1, %v0 */ constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); break; default: assert(0); } break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: if (e->expr0->type == EXPR_INTEGER || e->expr0->type == EXPR_REAL) { /* Exchange lhs/rhs. */ struct expr *tmp; tmp = e->expr0; e->expr0 = e->expr1; e->expr1 = tmp; switch (e->type) { case EXPR_EQUAL: break; case EXPR_NOT_EQUAL: break; case EXPR_LESS: e->type = EXPR_GREATER; break; case EXPR_LESS_EQUAL: e->type = EXPR_GREATER_EQUAL; break; case EXPR_GREATER: e->type = EXPR_LESS; break; case EXPR_GREATER_EQUAL: e->type = EXPR_LESS_EQUAL; break; default: assert(0); } } switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * cmp{b,w} %2, %1 * jcc 2f * 1: * movw $1, %0 * jmp 3f * 2: * xorw %0, %0 * 3: */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * cmp{b,w} %2, %1 * jcc 2f * 1: * movw $1, %0 * jmp 3f * 2: * xorw %0, %0 * 3: */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * ... */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * cmpw %w2, %w1 * jcc 2f * ... * 1: * movw $1, %0 * jmp 3f * 2: * xorw %0, %0 * 3: */ constraint_output(s, "=mr", expr_dup(lhs)); constraint_input(s, "r", expr_dup(e->expr0)); constraint_input(s, "ri", expr_dup(e->expr1)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_LEFT: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * shlb %b2, %0 */ goto shift_int8_16; case TYPE_INT16: case TYPE_UINT16: /* * shlw %b2, %0 */ goto shift_int8_16; case TYPE_INT32: case TYPE_UINT32: /* * jmp 2f * 1: * shlw $1, %0 * rclw $1, %w0 * decb %b1 * 2: * cmpb $0, %b1 * jne 1b */ goto shift_int32_64; case TYPE_INT64: case TYPE_UINT64: /* * jmp 2f * 1: * shlw $1, %0 * rclw $1, %w0 * rclw $1, %u0 * rclw $1, %v0 * decb %b1 * 2: * cmpb $0, %b1 * jne 1b */ goto shift_int32_64; default: assert(0); } break; case EXPR_RIGHT: switch (t->type) { case TYPE_INT8: /* * sarb %b2, %0 */ goto shift_int8_16; case TYPE_UINT8: /* * shrb %b2, %0 */ goto shift_int8_16; case TYPE_INT16: /* * sarw %b2, %0 */ goto shift_int8_16; case TYPE_UINT16: /* * shrw %b2, %0 */ shift_int8_16: constraint_output(s, "=rm", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "ci", expr_dup(e->expr1)); break; case TYPE_INT32: /* * jmp 2f * 1: * sarw $1, %w0 * rcrw $1, %0 * decb %b1 * 2: * cmpb $0, %b1 * jne 1b */ goto shift_int32_64; case TYPE_UINT32: /* * jmp 2f * 1: * shrw $1, %w0 * rcrw $1, %0 * decb %b1 * 2: * cmpb $0, %b1 * jne 1b */ goto shift_int32_64; case TYPE_INT64: /* * jmp 2f * 1: * sarw $1, %v0 * rcrw $1, %u0 * rcrw $1, %w0 * rcrw $1, %0 * decb %b1 * 2: * cmpb $0, %b1 * jne 1b */ goto shift_int32_64; case TYPE_UINT64: /* * jmp 2f * 1: * sarw $1, %v0 * rcrw $1, %u0 * rcrw $1, %w0 * rcrw $1, %0 * decb %b1 * 2: * cmpb $0, %b1 * jne 1b */ shift_int32_64: var = arch_tmp(block->scope, type_pure(expr_typeof(block->scope, e->expr1))); constraint_output(s, "=rm", expr_dup(lhs)); constraint_output(s, "=q", expr_identifier(var)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "1", expr_dup(e->expr1)); break; default: assert(0); } break; case EXPR_ADD: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * addb %2, %0 */ goto sub_int; case TYPE_INT16: case TYPE_UINT16: /* * addw %2, %0 */ goto sub_int; case TYPE_INT32: case TYPE_UINT32: /* * addw %2, %0 * adcw %w2, %w0 */ goto sub_int; case TYPE_INT64: case TYPE_UINT64: /* * addw %2, %0 * adcw %w2, %w0 * adcw %u2, %u0 * adcw %v2, %v0 */ goto sub_int; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_SUB: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * subb %2, %0 */ goto sub_int; case TYPE_INT16: case TYPE_UINT16: /* * subw %2, %0 */ goto sub_int; case TYPE_INT32: case TYPE_UINT32: /* * subw %2, %0 * sbbw %w2, %w0 */ goto sub_int; case TYPE_INT64: case TYPE_UINT64: /* * subw %2, %0 * sbbw %w2, %w0 * sbbw %u2, %u0 * sbbw %v2, %v0 */ sub_int: constraint_output(s, "=r", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "imr", expr_dup(e->expr1)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_MUL: switch (t->type) { case TYPE_INT8: /* * imulb %2 */ /*FALLTHROUGH*/ case TYPE_UINT8: /* * mulb %2 */ /*FALLTHROUGH*/ case TYPE_INT16: /* * imulw %2 */ /*FALLTHROUGH*/ case TYPE_UINT16: /* * mulw %2 */ constraint_output(s, "=a", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); constraint_change(s, "dx"); break; case TYPE_INT32: arch_op_func(e, arch_mul_int32); goto func; case TYPE_UINT32: arch_op_func(e, arch_mul_uint32); goto func; case TYPE_INT64: arch_op_func(e, arch_mul_int64); goto func; case TYPE_UINT64: arch_op_func(e, arch_mul_uint64); goto func; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_DIV: switch (t->type) { case TYPE_INT8: /* * cbw * idivb %2 */ /*FALLTHROUGN*/ case TYPE_UINT8: /* * xorb %%ah, %%ah * divb %2 */ constraint_output(s, "=a", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); constraint_change(s, "ah"); break; case TYPE_INT16: /* * cwd * idivw %2 */ /*FALLTHROUGH*/ case TYPE_UINT16: /* * xorw %%dx, %%dx * divw %2 */ constraint_output(s, "=a", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); constraint_change(s, "dx"); break; case TYPE_INT32: arch_op_func(e, arch_div_int32); goto func; case TYPE_UINT32: arch_op_func(e, arch_div_uint32); goto func; case TYPE_INT64: arch_op_func(e, arch_div_int64); goto func; case TYPE_UINT64: arch_op_func(e, arch_div_uint64); goto func; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_MOD: switch (t->type) { case TYPE_INT8: /* * cbw * idiv %2 * movb %%ah, %%al */ /*FALLTHROUGH*/ case TYPE_UINT8: /* * xorb %%ah, %%ah * div %2 * movb %%ah, %%al */ constraint_output(s, "=a", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); constraint_change(s, "ah"); break; case TYPE_INT16: /* * cwd * idivw %2 */ /*FALLTHROUGH*/ case TYPE_UINT16: /* * xorw %%dx, %%dx * divw %3 */ var = arch_tmp(block->scope, type_uint16()); constraint_output(s, "=a", expr_identifier(var)); constraint_output(s, "=&d", expr_dup(lhs)); constraint_input(s, "0", expr_dup(e->expr0)); constraint_input(s, "mr", expr_dup(e->expr1)); break; case TYPE_INT32: arch_op_func(e, arch_mod_int32); goto func; case TYPE_UINT32: arch_op_func(e, arch_mod_uint32); goto func; case TYPE_INT64: arch_op_func(e, arch_mod_int64); goto func; case TYPE_UINT64: arch_op_func(e, arch_mod_uint64); goto func; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_AND: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * andb %2, %0 */ goto sub_int; case TYPE_INT16: case TYPE_UINT16: /* * andw %2, %0 */ goto sub_int; case TYPE_INT32: case TYPE_UINT32: /* * andw %2, %0 * andw %w2, %w0 */ goto sub_int; case TYPE_INT64: case TYPE_UINT64: /* * andw %2, %0 * andw %w2, %w0 * andw %u2, %u0 * andw %v2, %v0 */ goto sub_int; default: assert(0); } break; case EXPR_OR: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * orb %2, %0 */ goto sub_int; case TYPE_INT16: case TYPE_UINT16: /* * orw %2, %0 */ goto sub_int; case TYPE_INT32: case TYPE_UINT32: /* * orw %2, %0 * orw %w2, %w0 */ goto sub_int; case TYPE_INT64: case TYPE_UINT64: /* * orw %2, %0 * orw %w2, %w0 * orw %u2, %u0 * orw %v2, %v0 */ goto sub_int; default: assert(0); } break; case EXPR_XOR: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * xorb %2, %0 */ goto sub_int; case TYPE_INT16: case TYPE_UINT16: /* * xorw %2, %0 */ goto sub_int; case TYPE_INT32: case TYPE_UINT32: /* * xorw %2, %0 * xorw %w2, %w0 */ goto sub_int; case TYPE_INT64: case TYPE_UINT64: /* * xorw %2, %0 * xorw %w2, %w0 * xorw %u2, %u0 * xorw %v2, %v0 */ goto sub_int; default: assert(0); } break; case EXPR_FUNC: func: ; /* * pushl %N-1 * pushl %N-2 * ... * pushl %1 * [l]call %0 * addw $c, %esp */ regs_change = REG_CALLER; if (lhs) { switch (t->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: constraint_output(s, "=a", expr_dup(lhs)); regs_change &= ~(1ULL << AX); break; case TYPE_INT32: case TYPE_UINT32: constraint_output(s, "=A", expr_dup(lhs)); regs_change &= ~((1ULL << AX) | (1ULL << DX)); break; case TYPE_INT64: case TYPE_UINT64: constraint_output(s, "=r", expr_dup(lhs)); regs_change &= ~((1ULL << AX) | (1ULL << DX) | (1ULL << DI) | (1ULL << SI)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } } switch (e->expr0->type) { case EXPR_IDENTIFIER: break; case EXPR_STAR: constraint_input(s, "r", expr_dup(e->expr0->expr0->expr0)); break; default: assert(0); } for (ce = e->expr1->first; ce; ce = ce->next) { constraint_input(s, "rmi", expr_dup(ce)); } constraint_change(s, "memory"); for (reg = 0; regs_change; reg++) { if ((regs_change >> reg) & 1) { constraint_change(s, arch_reginfo[reg].name); regs_change &= ~(1ULL << reg); } } break; default: assert(0); } } } static void arch_gen_expr_2( char *buf0, struct stmt *block, struct stmt *s, struct expr *e, struct expr *lhs ) { struct type *t; struct type *t1; struct expr *ce; unsigned int size; struct constraint *c; int reglhs; int reg; int reg0; int reg1; struct declaration *dion; unsigned int n; assert(lhs || e->type == EXPR_FUNC); t = expr_typeof(block->scope, e); t = type_pure(t); if (lhs && lhs->type == EXPR_IDENTIFIER && lhs->declaration->storage == STORAGE_REGISTER) { reglhs = lhs->declaration->storage_register; } else { reglhs = -1; } if (e->type == EXPR_IDENTIFIER && e->declaration->storage == STORAGE_REGISTER) { reg = e->declaration->storage_register; } else { reg = -1; } if (e->expr0 && e->expr0->type == EXPR_IDENTIFIER && e->expr0->declaration->storage == STORAGE_REGISTER) { reg0 = e->expr0->declaration->storage_register; } else { reg0 = -1; } if (e->expr1 && e->expr1->type == EXPR_IDENTIFIER && e->expr1->declaration->storage == STORAGE_REGISTER) { reg1 = e->expr1->declaration->storage_register; } else { reg1 = -1; } if (lhs && lhs->type == EXPR_IDENTIFIER && (lhs->declaration->storage == STORAGE_STATIC || lhs->declaration->storage == STORAGE_NONE || lhs->declaration->storage == STORAGE_EXTERN)) { /* * Store Operation */ assert(e->type == EXPR_INTEGER || e->type == EXPR_REAL || e->type == EXPR_IDENTIFIER); if (seg_enabled()) { strcpy(buf0, "\tmovw %w1, %0\n"); strcat(buf0, "\tmovw %0, %%es\n"); } else { strcpy(buf0, ""); } switch (t->type) { case TYPE_INT8: case TYPE_UINT8: if (seg_enabled()) { strcat(buf0, "\tmovb %2, %%es:%1\n"); } else { strcat(buf0, "\tmovb %1, %0\n"); } break; case TYPE_INT16: case TYPE_UINT16: if (seg_enabled()) { strcat(buf0, "\tmovw %2, %%es:%1\n"); } else { strcat(buf0, "\tmovw %1, %0\n"); } break; case TYPE_INT32: case TYPE_UINT32: if (seg_enabled()) { strcat(buf0, "\tmovw %2, %%es:%1\n"); strcat(buf0, "\tmovw %w2, %%es:2+%1\n"); } else { strcat(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tmovw %w1, 2+%0\n"); } break; case TYPE_INT64: case TYPE_UINT64: if (seg_enabled()) { strcat(buf0, "\tmovw %2, %%es:%1\n"); strcat(buf0, "\tmovw %w2, %%es:2+%1\n"); strcat(buf0, "\tmovw %u2, %%es:4+%1\n"); strcat(buf0, "\tmovw %v2, %%es:6+%1\n"); } else { strcat(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tmovw %w1, 2+%0\n"); strcat(buf0, "\tmovw %u1, 4+%0\n"); strcat(buf0, "\tmovw %v1, 6+%0\n"); } break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ case TYPE_VA_LIST: assert(0); /* FIXME */ default: assert(0); } } else if (e->type == EXPR_IDENTIFIER && (e->declaration->storage == STORAGE_STATIC || e->declaration->storage == STORAGE_NONE || e->declaration->storage == STORAGE_EXTERN)) { /* * Load Operation */ assert(lhs && lhs->type == EXPR_IDENTIFIER && lhs->declaration->storage != STORAGE_STATIC && lhs->declaration->storage != STORAGE_NONE && lhs->declaration->storage != STORAGE_EXTERN); if (seg_enabled()) { strcpy(buf0, "\tmovw %w2, %1\n"); strcat(buf0, "\tmovw %1, %%es\n"); } else { strcpy(buf0, ""); } switch (t->type) { case TYPE_INT8: case TYPE_UINT8: if (seg_enabled()) { strcat(buf0, "\tmovb %%es:%2, %0\n"); } else { strcat(buf0, "\tmovb %1, %0\n"); } break; case TYPE_INT16: case TYPE_UINT16: if (seg_enabled()) { strcat(buf0, "\tmovw %%es:%2, %0\n"); } else { strcat(buf0, "\tmovw %1, %0\n"); } break; case TYPE_INT32: case TYPE_UINT32: if (seg_enabled()) { strcat(buf0, "\tmovw %%es:%2, %0\n"); strcat(buf0, "\tmovw %%es:2+%2, %w0\n"); } else { strcat(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tmovw 2+%1, %w0\n"); } break; case TYPE_INT64: case TYPE_UINT64: if (seg_enabled()) { strcat(buf0, "\tmovw %%es:%2, %0\n"); strcat(buf0, "\tmovw %%es:2+%2, %w0\n"); strcat(buf0, "\tmovw %%es:4+%2, %u0\n"); strcat(buf0, "\tmovw %%es:6+%2, %v0\n"); } else { strcat(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tmovw 2+%1, %w0\n"); strcat(buf0, "\tmovw 4+%1, %u0\n"); strcat(buf0, "\tmovw 6+%1, %v0\n"); } break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ case TYPE_VA_LIST: assert(0); /* FIXME */ default: assert(0); /* Mustn't happen. */ } } else { /* * Non-Load/Non-Store Operation */ switch (e->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_ASSIGN: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: case EXPR_NOT: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_LIST: assert(0); case EXPR_STRING: assert(0); case EXPR_AMPHERSAND: assert(0); case EXPR_INTEGER: case EXPR_REAL: simple_copy: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tmovb %1, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tmovw %1, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tmovw %w1, %w0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tmovw %w1, %w0\n"); strcat(buf0, "\tmovw %u1, %u0\n"); strcat(buf0, "\tmovw %v1, %v0\n"); break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: strcpy(buf0, "\tmovw %1, %0\n"); break; default: assert(0); } break; case EXPR_IDENTIFIER: if (reglhs == -1 || reg == -1) { goto simple_copy; } switch (t->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_VA_LIST: /* * Only one register to copy => simple. */ if (reglhs == reg) { /* * Omit instructions "mov %x, %x". */ strcpy(buf0, ""); break; } else { goto simple_copy; } case TYPE_INT32: case TYPE_UINT32: /* * We have *two* registers in * *two* real registers * (e.g. AX_BX and BX_CX). */ assert(arch_gen_reg_parts[reglhs].count == 2); assert(arch_gen_reg_parts[reg].count == 2); if (arch_gen_reg_parts[reglhs].reg[0] == arch_gen_reg_parts[reg].reg[0] && arch_gen_reg_parts[reglhs].reg[1] == arch_gen_reg_parts[reg].reg[1]) { /* A_B <- A_B. */ strcpy(buf0, ""); } else if (arch_gen_reg_parts[reglhs].reg[0] == arch_gen_reg_parts[reg].reg[1] && arch_gen_reg_parts[reglhs].reg[1] == arch_gen_reg_parts[reg].reg[0]) { /* A_B <- B_A. */ strcpy(buf0, "\txchgw %1, %0\n"); } else if (arch_gen_reg_parts[reglhs].reg[0] == arch_gen_reg_parts[reg].reg[0]) { /* A_B <- A_C. */ strcpy(buf0, "\tmovw %w1, %w0\n"); } else if (arch_gen_reg_parts[reglhs].reg[1] == arch_gen_reg_parts[reg].reg[1]) { /* A_B <- C_B. */ strcpy(buf0, "\tmovw %1, %0\n"); } else if (arch_gen_reg_parts[reglhs].reg[0] == arch_gen_reg_parts[reg].reg[1]) { /* A_B <- C_A. */ strcpy(buf0, "\tmovw %w1, %w0\n"); strcat(buf0, "\tmovw %1, %0\n"); } else if (arch_gen_reg_parts[reglhs].reg[1] == arch_gen_reg_parts[reg].reg[0]) { /* A_B <- B_C. */ strcpy(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tmovw %w1, %w0\n"); } else { /* A_B <- C_D. */ strcpy(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tmovw %w1, %w0\n"); } break; case TYPE_INT64: case TYPE_UINT64: /* * We only have *one* 64-bit register. */ assert(reglhs == reg); strcpy(buf0, ""); break; default: assert(0); /* Cannot happen. */ } break; case EXPR_BUILTIN_VA_ARG: t1 = e->type_name; switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tmovb %%ss:(%1), %0\n"); strcat(buf0, "\taddw $1, %1\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tmovw %%ss:(%1), %0\n"); strcat(buf0, "\taddw $2, %1\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tmovw %%ss:(%1), %0\n"); strcat(buf0, "\tmovw %%ss:2(%1), %w0\n"); strcat(buf0, "\taddw $4, %1\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovw %%ss:(%1), %0\n"); strcat(buf0, "\tmovw %%ss:2(%1), %w0\n"); strcat(buf0, "\tmovw %%ss:4(%1), %u0\n"); strcat(buf0, "\tmovw %%ss:6(%1), %v0\n"); strcat(buf0, "\taddw $8, %1\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_TYPE_CONVERSION: if (e->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ dion = e->expr0->expr0->declaration; goto special; } else if (e->expr0->type == EXPR_IDENTIFIER && (e->expr0->declaration->type_name->type == TYPE_ARRAY || e->expr0->declaration->type_name->type == TYPE_FUNCTION)) { /* * Special case: (int) array * Special case: (int) function */ dion = e->expr0->declaration; special: if (dion->storage == STORAGE_NONE || dion->storage == STORAGE_EXTERN || dion->storage == STORAGE_STATIC) { if (seg_enabled()) { strcpy(buf0, "\tmovw $%1, %0\n"); strcat(buf0, "\tmovw $%w1, %w0\n"); } else { strcpy(buf0, "\tmovw $%1, %0\n"); } } else { if (seg_enabled()) { strcpy(buf0, "\tleaw %1, %0\n"); strcat(buf0, "\tmovw %%ss, %w0\n"); } else { strcpy(buf0, "\tleaw %1, %0\n"); } } break; } t1 = expr_typeof(block->scope, e->expr0); t1 = type_pure(t1); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, ""); break; case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovb %b1, %0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT16: case TYPE_UINT16: switch (t1->type) { case TYPE_INT8: strcpy(buf0, "\tcbw\n"); break; case TYPE_UINT8: strcpy(buf0, "\tmovb %1, %b0\n"); strcat(buf0, "\txorb %h0, %h0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, ""); break; case TYPE_INT32: case TYPE_UINT32: case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovw %1, %0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT32: case TYPE_UINT32: switch (t1->type) { case TYPE_INT8: strcpy(buf0, "\tcbw\n"); strcat(buf0, "\tcwd\n"); break; case TYPE_UINT8: strcpy(buf0, "\tmovb %1, %b0\n"); strcat(buf0, "\txorb %h0, %h0\n"); strcat(buf0, "\txorw %w0, %w0\n"); break; case TYPE_INT16: strcpy(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tcwd\n"); break; case TYPE_UINT16: strcpy(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\txorw %w0, %w0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, ""); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tmovw %w1, %w0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_INT64: case TYPE_UINT64: switch (t1->type) { case TYPE_INT8: strcpy(buf0, "\tcbw\n"); strcat(buf0, "\tcwd\n"); strcat(buf0, "\tmovw %%dx, %u0\n"); strcat(buf0, "\tmovw %%dx, %v0\n"); break; case TYPE_UINT8: strcpy(buf0, "\tmovb %1, %b0\n"); strcat(buf0, "\txorb %h0, %h0\n"); strcat(buf0, "\txorw %w0, %w0\n"); strcat(buf0, "\txorw %u0, %u0\n"); strcat(buf0, "\txorw %v0, %v0\n"); break; case TYPE_INT16: strcpy(buf0, "\tcwd\n"); strcat(buf0, "\tmovw %%dx, %u0\n"); strcat(buf0, "\tmovw %%dx, %v0\n"); break; case TYPE_UINT16: strcpy(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\txorw %w0, %w0\n"); strcat(buf0, "\txorw %u0, %u0\n"); strcat(buf0, "\txorw %v0, %v0\n"); break; case TYPE_INT32: strcpy(buf0, "\tmovw %1, %v0\n"); strcat(buf0, "\tmovw %w1, %0\n"); strcat(buf0, "\tcwd\n"); strcat(buf0, "\txchgw %w0, %v0\n"); strcat(buf0, "\txchgw %w0, %0\n"); strcat(buf0, "\tmovw %v0, %u0\n"); break; case TYPE_UINT32: strcpy(buf0, "\tmovw %1, %0\n"); strcat(buf0, "\tmovw %w1, %w0\n"); strcat(buf0, "\txorw %u0, %u0\n"); strcat(buf0, "\txorw %v0, %v0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, ""); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_STAR: assert(lhs); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: if (seg_enabled()) { strcpy(buf0, "\tmovw %w1, %%es\n"); strcat(buf0, "\tmovb %%es:(%1), %0\n"); } else { strcpy(buf0, "\tmovb (%1), %0\n"); } break; case TYPE_INT16: case TYPE_UINT16: if (seg_enabled()) { strcpy(buf0, "\tmovw %w1, %%es\n"); strcat(buf0, "\tmovw %%es:(%1), %0\n"); } else { strcpy(buf0, "\tmovw (%1), %0\n"); } break; case TYPE_INT32: case TYPE_UINT32: if (seg_enabled()) { strcpy(buf0, "\tmovw %w1, %%es\n"); strcat(buf0, "\tmovw %%es:(%1), %0\n"); strcat(buf0, "\tmovw %%es:2(%1), %w0\n"); } else { strcpy(buf0, "\tmovw (%1), %0\n"); strcat(buf0, "\tmovw 2(%1), %w0\n"); } break; case TYPE_INT64: case TYPE_UINT64: if (seg_enabled()) { strcpy(buf0, "\tmovw %w1, %%es\n"); strcat(buf0, "\tmovw %%es:(%1), %0\n"); strcat(buf0, "\tmovw %%es:2(%1), %w0\n"); strcat(buf0, "\tmovw %%es:4(%1), %u0\n"); strcat(buf0, "\tmovw %%es:6(%1), %v0\n"); } else { strcpy(buf0, "\tmovw (%1), %0\n"); strcat(buf0, "\tmovw 2(%1), %w0\n"); strcat(buf0, "\tmovw 4(%1), %u0\n"); strcat(buf0, "\tmovw 6(%1), %v0\n"); } break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_NEG: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tnegb %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tnegw %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tnegw %0\n"); strcat(buf0, "\tadcw $0, %w0\n"); strcat(buf0, "\tnegw %w0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tnegw %0\n"); strcat(buf0, "\tadcw $0, %w0\n"); strcat(buf0, "\tadcw $0, %u0\n"); strcat(buf0, "\tadcw $0, %v0\n"); strcat(buf0, "\tnegw %w0\n"); strcat(buf0, "\tadcw $0, %u0\n"); strcat(buf0, "\tadcw $0, %v0\n"); strcat(buf0, "\tnegw %u0\n"); strcat(buf0, "\tadcw $0, %v0\n"); strcat(buf0, "\tnegw %v0\n"); break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_INV: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\txorb $-1, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\txorw $-1, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\txorw $-1, %0\n"); strcat(buf0, "\txorw $-1, %w0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\txorw $-1, %0\n"); strcat(buf0, "\txorw $-1, %w0\n"); strcat(buf0, "\txorw $-1, %u0\n"); strcat(buf0, "\txorw $-1, %v0\n"); break; default: assert(0); } break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: t1 = expr_typeof(block->scope, e->expr0); t1 = type_pure(t1); switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tcmpb %2, %1\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tcmpw %2, %1\n"); break; default: assert(0); } switch (t1->type) { case TYPE_INT8: case TYPE_INT16: switch (e->type) { case EXPR_EQUAL: strcat(buf0, "\tjne 2f\n"); break; case EXPR_NOT_EQUAL: strcat(buf0, "\tje 2f\n"); break; case EXPR_LESS: strcat(buf0, "\tjge 2f\n"); break; case EXPR_LESS_EQUAL: strcat(buf0, "\tjg 2f\n"); break; case EXPR_GREATER: strcat(buf0, "\tjle 2f\n"); break; case EXPR_GREATER_EQUAL: strcat(buf0, "\tjl 2f\n"); break; default: assert(0); } break; case TYPE_UINT8: case TYPE_UINT16: switch (e->type) { case EXPR_EQUAL: strcat(buf0, "\tjne 2f\n"); break; case EXPR_NOT_EQUAL: strcat(buf0, "\tje 2f\n"); break; case EXPR_LESS: strcat(buf0, "\tjge 2f\n"); break; case EXPR_LESS_EQUAL: strcat(buf0, "\tjg 2f\n"); break; case EXPR_GREATER: strcat(buf0, "\tjle 2f\n"); break; case EXPR_GREATER_EQUAL: strcat(buf0, "\tjl 2f\n"); break; default: assert(0); } break; default: assert(0); } break; case TYPE_INT32: switch (e->type) { case EXPR_EQUAL: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjne 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjne 2f\n"); break; case EXPR_NOT_EQUAL: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tje 2f\n"); break; case EXPR_LESS: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tjg 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjge 2f\n"); break; case EXPR_LESS_EQUAL: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tjg 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjg 2f\n"); break; case EXPR_GREATER: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tjl 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjle 2f\n"); break; case EXPR_GREATER_EQUAL: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tjl 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjl 2f\n"); break; default: assert(0); } break; case TYPE_UINT32: switch (e->type) { case EXPR_EQUAL: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjne 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjne 2f\n"); break; case EXPR_NOT_EQUAL: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tje 2f\n"); break; case EXPR_LESS: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tjg 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjge 2f\n"); break; case EXPR_LESS_EQUAL: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tjg 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjg 2f\n"); break; case EXPR_GREATER: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tjl 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjle 2f\n"); break; case EXPR_GREATER_EQUAL: strcpy(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tjl 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjl 2f\n"); break; default: assert(0); } break; case TYPE_INT64: switch (e->type) { case EXPR_EQUAL: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tjne 2f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tjne 2f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjne 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjne 2f\n"); break; case EXPR_NOT_EQUAL: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tje 2f\n"); break; case EXPR_LESS: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tjg 2f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tjg 2f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tjg 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjge 2f\n"); break; case EXPR_LESS_EQUAL: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tjg 2f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tjg 2f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tjg 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjg 2f\n"); break; case EXPR_GREATER: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tjl 2f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tjl 2f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tjl 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjle 2f\n"); break; case EXPR_GREATER_EQUAL: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tjl 2f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tjl 2f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tjl 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjl 2f\n"); break; default: assert(0); } break; case TYPE_UINT64: switch (e->type) { case EXPR_EQUAL: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tjne 2f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tjne 2f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjne 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjne 2f\n"); break; case EXPR_NOT_EQUAL: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tje 1f\n"); break; case EXPR_LESS: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tja 2f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tja 2f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tja 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjae 2f\n"); break; case EXPR_LESS_EQUAL: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tja 2f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tja 2f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tja 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tja 2f\n"); break; case EXPR_GREATER: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tjb 2f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tjb 2f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tjb 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjbe 2f\n"); break; case EXPR_GREATER_EQUAL: strcpy(buf0, "\tcmpw %v2, %v1\n"); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tjb 2f\n"); strcat(buf0, "\tcmpw %u2, %u1\n"); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tjb 2f\n"); strcat(buf0, "\tcmpw %w2, %w1\n"); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tjb 2f\n"); strcat(buf0, "\tcmpw %2, %1\n"); strcat(buf0, "\tjb 2f\n"); break; default: assert(0); } break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; case TYPE_POINTER: assert(0); /* FIXME */ break; default: assert(0); } strcat(buf0, "1:\n"); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcat(buf0, "\tmovb $1, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcat(buf0, "\tmovw $1, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcat(buf0, "\tmovw $1, %0\n"); strcat(buf0, "\txorw %w0, %w0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcat(buf0, "\tmovw $1, %0\n"); strcat(buf0, "\txorw %w0, %w0\n"); strcat(buf0, "\txorw %u0, %u0\n"); strcat(buf0, "\txorw %v0, %v0\n"); break; default: assert(0); } strcat(buf0, "\tjmp 3f\n"); strcat(buf0, "2:\n"); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcat(buf0, "\txorb %0, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcat(buf0, "\txorw %0, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcat(buf0, "\txorw %0, %0\n"); strcat(buf0, "\txorw %w0, %w0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcat(buf0, "\txorw %0, %0\n"); strcat(buf0, "\txorw %w0, %w0\n"); strcat(buf0, "\txorw %u0, %u0\n"); strcat(buf0, "\txorw %v0, %v0\n"); break; default: assert(0); } strcat(buf0, "3:\n"); break; case EXPR_LEFT: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tshlb %b2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tshlw %b2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tjmp 2f\n"); strcat(buf0, "1:\n"); strcat(buf0, "\tshlw $1, %0\n"); strcat(buf0, "\trclw $1, %w0\n"); strcat(buf0, "\tdecb %b1\n"); strcat(buf0, "2:\n"); strcat(buf0, "\tcmpb $0, %b1\n"); strcat(buf0, "\tjne 1b\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tjmp 2f\n"); strcat(buf0, "1:\n"); strcat(buf0, "\tshlw $1, %0\n"); strcat(buf0, "\trclw $1, %w0\n"); strcat(buf0, "\trclw $1, %u0\n"); strcat(buf0, "\trclw $1, %v0\n"); strcat(buf0, "\tdecb %b1\n"); strcat(buf0, "2:\n"); strcat(buf0, "\tcmpb $0, %b1\n"); strcat(buf0, "\tjne 1b\n"); break; default: assert(0); } break; case EXPR_RIGHT: switch (t->type) { case TYPE_INT8: strcpy(buf0, "\tsarb %b2, %0\n"); break; case TYPE_UINT8: strcpy(buf0, "\tshrb %b2, %0\n"); break; case TYPE_INT16: strcpy(buf0, "\tsarw %b2, %0\n"); break; case TYPE_UINT16: strcpy(buf0, "\tshrw %b2, %0\n"); break; case TYPE_INT32: strcpy(buf0, "\tjmp 2f\n"); strcat(buf0, "1:\n"); strcat(buf0, "\tsarw $1, %w0\n"); strcat(buf0, "\trcrw $1, %0\n"); strcat(buf0, "\tdecb %b1\n"); strcat(buf0, "2:\n"); strcat(buf0, "\tcmpb $0, %b1\n"); strcat(buf0, "\tjne 1b\n"); break; case TYPE_UINT32: strcpy(buf0, "\tjmp 2f\n"); strcat(buf0, "1:\n"); strcat(buf0, "\tshrw $1, %w0\n"); strcat(buf0, "\trcrw $1, %0\n"); strcat(buf0, "\tdecb %b1\n"); strcat(buf0, "2:\n"); strcat(buf0, "\tcmpb $0, %b1\n"); strcat(buf0, "\tjne 1b\n"); break; case TYPE_INT64: strcpy(buf0, "\tjmp 2f\n"); strcat(buf0, "1:\n"); strcat(buf0, "\tsarw $1, %v0\n"); strcat(buf0, "\trcrw $1, %u0\n"); strcat(buf0, "\trcrw $1, %w0\n"); strcat(buf0, "\trcrw $1, %0\n"); strcat(buf0, "\tdecb %b1\n"); strcat(buf0, "2:\n"); strcat(buf0, "\tcmpb $0, %b1\n"); strcat(buf0, "\tjne 1b\n"); break; case TYPE_UINT64: strcpy(buf0, "\tjmp 2f\n"); strcat(buf0, "1:\n"); strcat(buf0, "\tshrw $1, %v0\n"); strcat(buf0, "\trcrw $1, %u0\n"); strcat(buf0, "\trcrw $1, %w0\n"); strcat(buf0, "\trcrw $1, %0\n"); strcat(buf0, "\tdecb %b1\n"); strcat(buf0, "2:\n"); strcat(buf0, "\tcmpb $0, %b1\n"); strcat(buf0, "\tjne 1b\n"); break; default: assert(0); } break; case EXPR_ADD: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\taddb %2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\taddw %2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\taddw %2, %0\n"); strcat(buf0, "\tadcw %w2, %w0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\taddw %2, %0\n"); strcat(buf0, "\tadcw %w2, %w0\n"); strcat(buf0, "\tadcw %u2, %u0\n"); strcat(buf0, "\tadcw %v2, %v0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_SUB: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tsubb %2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tsubw %2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tsubw %2, %0\n"); strcat(buf0, "\tsbbw %w2, %w0\n"); break; break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tsubw %2, %0\n"); strcat(buf0, "\tsbbw %w2, %w0\n"); strcat(buf0, "\tsbbw %u2, %u0\n"); strcat(buf0, "\tsbbw %v2, %v0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_MUL: switch (t->type) { case TYPE_INT8: strcpy(buf0, "\timulb %2\n"); break; case TYPE_UINT8: strcpy(buf0, "\tmulb %2\n"); break; case TYPE_INT16: strcpy(buf0, "\timulw %2\n"); break; case TYPE_UINT16: strcpy(buf0, "\tmulw %2\n"); break; case TYPE_INT32: assert(0); /* Operator replaced by function call. */ case TYPE_UINT32: assert(0); /* Operator replaced by function call. */ case TYPE_INT64: assert(0); /* Operator replaced by function call. */ case TYPE_UINT64: assert(0); /* Operator replaced by function call. */ case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_DIV: switch (t->type) { case TYPE_INT8: strcpy(buf0, "\tcbw\n"); strcat(buf0, "\tidivb %2\n"); break; case TYPE_UINT8: strcpy(buf0, "\txorb %%ah, %%ah\n"); strcat(buf0, "\tdivb %2\n"); break; case TYPE_INT16: strcpy(buf0, "\tcwd\n"); strcat(buf0, "\tidivw %2\n"); break; case TYPE_UINT16: strcpy(buf0, "\txorw %%dx, %%dx\n"); strcat(buf0, "\tdivw %2\n"); break; case TYPE_INT32: assert(0); /* Operator replaced by function call. */ case TYPE_UINT32: assert(0); /* Operator replaced by function call. */ case TYPE_INT64: assert(0); /* Operator replaced by function call. */ case TYPE_UINT64: assert(0); /* Operator replaced by function call. */ case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_MOD: switch (t->type) { case TYPE_INT8: strcpy(buf0, "\tcbw\n"); strcat(buf0, "\tidivb %2\n"); strcat(buf0, "\tmovb %%ah, %%al\n"); break; case TYPE_UINT8: strcpy(buf0, "\txorb %%ah, %%ah\n"); strcat(buf0, "\tdivb %2\n"); strcat(buf0, "\tmovb %%ah, %%al\n"); break; case TYPE_INT16: strcpy(buf0, "\tcwd\n"); strcat(buf0, "\tidivw %3\n"); break; case TYPE_UINT16: strcpy(buf0, "\txorw %%dx, %%dx\n"); strcat(buf0, "\tdivw %3\n"); break; case TYPE_INT32: assert(0); /* Operator replaced by function call. */ case TYPE_UINT32: assert(0); /* Operator replaced by function call. */ case TYPE_INT64: assert(0); /* Operator replaced by function call. */ case TYPE_UINT64: assert(0); /* Operator replaced by function call. */ case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case EXPR_AND: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tandb %2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tandw %2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\tandw %2, %0\n"); strcat(buf0, "\tandw %w2, %w0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\tandw %2, %0\n"); strcat(buf0, "\tandw %w2, %w0\n"); strcat(buf0, "\tandw %u2, %u0\n"); strcat(buf0, "\tandw %v2, %v0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_OR: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\torb %2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\torw %2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\torw %2, %0\n"); strcat(buf0, "\torw %w2, %w0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\torw %2, %0\n"); strcat(buf0, "\torw %w2, %w0\n"); strcat(buf0, "\torw %u2, %u0\n"); strcat(buf0, "\torw %v2, %v0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_XOR: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\txorb %2, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\txorw %2, %0\n"); break; case TYPE_INT32: case TYPE_UINT32: strcpy(buf0, "\txorw %2, %0\n"); strcat(buf0, "\txorw %w2, %w0\n"); break; case TYPE_INT64: case TYPE_UINT64: strcpy(buf0, "\txorw %2, %0\n"); strcat(buf0, "\txorw %w2, %w0\n"); strcat(buf0, "\txorw %u2, %u0\n"); strcat(buf0, "\txorw %v2, %v0\n"); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } break; case EXPR_FUNC: /* * pushl %0 * pushl %1 * ... * pushl %N-1 * [l]call label * addl $c, %esp */ strcpy(buf0, ""); size = 0; n = 0; for (c = s->output->first; c; c = c->next) { n++; } for (c = s->input->first; c; c = c->next) { n++; } for (ce = e->expr1->last; ce; ce = ce->prev) { n--; if (ce->type == EXPR_TYPE_CONVERSION) { if (ce->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ dion = ce->expr0->expr0->declaration; } else if (ce->expr0->type == EXPR_IDENTIFIER) { /* * Special case: (int) array * Special case: (int) function */ dion = ce->expr0->declaration; } else { dion = NULL; } assert(dion); if (dion->storage == STORAGE_NONE || dion->storage == STORAGE_EXTERN || dion->storage == STORAGE_STATIC) { if (seg_enabled()) { sprintf(buf0 + strlen(buf0), "\tpushw %%w%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushw %%%u\n", n); } else { sprintf(buf0 + strlen(buf0), "\tpushw %%%u\n", n); } } else { if (seg_enabled()) { sprintf(buf0 + strlen(buf0), "\tpushw %%%%ss\n"); sprintf(buf0 + strlen(buf0), "\tleaw %%%u, %%%%ax\n", n); /* FIXME */ sprintf(buf0 + strlen(buf0), "\tpushw %%%%ax\n"); /* FIXME */ } else { sprintf(buf0 + strlen(buf0), "\tleaw %%%u, %%%%ax\n", n); /* FIXME */ sprintf(buf0 + strlen(buf0), "\tpushw %%%%ax\n"); /* FIXME */ } } if (seg_enabled()) { size += 4; } else { size += 2; } continue; } t1 = expr_typeof(block->scope, ce); t1 = type_pure(t1); switch (t1->type) { case TYPE_INT8: case TYPE_UINT8: sprintf(buf0 + strlen(buf0), "\tpushb %%%u\n", n); size += 2; break; case TYPE_INT16: case TYPE_UINT16: sprintf(buf0 + strlen(buf0), "\tpushw %%%u\n", n); size += 2; break; case TYPE_INT32: case TYPE_UINT32: sprintf(buf0 + strlen(buf0), "\tpushw %%w%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushw %%%u\n", n); size += 4; break; case TYPE_INT64: case TYPE_UINT64: sprintf(buf0 + strlen(buf0), "\tpushw %%v%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushw %%u%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushw %%w%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushw %%%u\n", n); size += 8; break; case TYPE_FLOAT32: sprintf(buf0 + strlen(buf0), "\tpushl %%%u\n", n); break; case TYPE_FLOAT64: sprintf(buf0 + strlen(buf0), "\tpushl %%u%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushl %%l%u\n", n); size += 8; case TYPE_FLOAT80: sprintf(buf0 + strlen(buf0), "\tpushl 12+%%%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushl 8+%%%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushl 4+%%%u\n", n); sprintf(buf0 + strlen(buf0), "\tpushl %%%u\n", n); size += 16; break; case TYPE_VA_LIST: sprintf(buf0 + strlen(buf0), "\tpushw %%%u\n", n); size += 2; break; default: assert(0); } } switch (e->expr0->type) { case EXPR_IDENTIFIER: if (seg_enabled()) { /* * gas cannot handle * "lcall $SEG_x, $OFF_x". It reports * * Error: can't handle non absolute segment * in `lcall' * * So use code directly. */ strcat(buf0, "\t.byte 0x9a /* lcall */\n"); if (e->expr0->declaration->storage == STORAGE_STATIC) { sprintf(buf0 + strlen(buf0), "\t.word %s, %s\n", arch_gen_local_off(e->expr0->declaration->identifier), arch_gen_local_seg(e->expr0->declaration->identifier)); } else { sprintf(buf0 + strlen(buf0), "\t.word %s, %s\n", arch_gen_global_off(e->expr0->declaration->identifier), arch_gen_global_seg(e->expr0->declaration->identifier)); } } else { sprintf(buf0 + strlen(buf0), "\tcall %s\n", e->expr0->declaration->identifier); } break; case EXPR_STAR: if (seg_enabled()) { assert(0); /* FIXME */ } else { sprintf(buf0 + strlen(buf0), "\tcall *%%%u\n", n++); } break; default: assert(0); } if (0 < size) { sprintf(buf0 + strlen(buf0), "\taddw $%u, %%%%sp\n", size); } break; default: assert(0); } } } static void arch_gen_stmt_simplify_1(struct stmt *block, struct stmt *s) { struct type *t; /* struct declaration *var; */ switch (s->type) { case STMT_NONE: assert(0); case STMT_NULL: case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_CONTINUE: case STMT_BREAK: case STMT_BLOCK: assert(0); case STMT_LABEL: /* * label: */ /* No constraints needed. */ break; case STMT_EXPR: switch (s->expr0->type) { case EXPR_ASSIGN: switch (s->expr0->expr0->type) { case EXPR_IDENTIFIER: arch_gen_expr_1(block, s, s->expr0->expr1, s->expr0->expr0); break; case EXPR_STAR: t = expr_typeof(block->scope, s->expr0->expr0); t = type_pure(t); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * [movw %w0, %%es] * movb %1, [%%es:](%0) */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * [movw %w0, %%es] * movw %1, [%%es:](%0) */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * [movw %w0, %%es] * movw %1, [%%es:](%0) * movw %w1, [%%es:]2(%0) */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * [movw %w0, %%es] * movw %1, [%%es:](%0) * movw %w1, [%%es:]2(%0) * movw %u1, [%%es:]4(%0) * movw %v1, [%%es:]6(%0) */ constraint_input(s, "l", expr_dup(s->expr0->expr0->expr0->expr0)); constraint_input(s, "r", expr_dup(s->expr0->expr1)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; default: assert(0); } break; case EXPR_FUNC: arch_gen_expr_1(block, s, s->expr0, NULL); break; default: assert(0); } break; case STMT_IF: t = expr_typeof(block->scope, s->expr0->expr0); t = type_pure(t); if (s->expr0->expr0->type == EXPR_INTEGER || s->expr0->expr0->type == EXPR_REAL) { /* Exchange lhs/rhs. */ struct expr *tmp; tmp = s->expr0->expr0; s->expr0->expr0 = s->expr0->expr1; s->expr0->expr1 = tmp; switch (s->expr0->type) { case EXPR_EQUAL: break; case EXPR_NOT_EQUAL: break; case EXPR_LESS: s->expr0->type = EXPR_GREATER; break; case EXPR_LESS_EQUAL: s->expr0->type = EXPR_GREATER_EQUAL; break; case EXPR_GREATER: s->expr0->type = EXPR_LESS; break; case EXPR_GREATER_EQUAL: s->expr0->type = EXPR_LESS_EQUAL; break; default: assert(0); } } switch (t->type) { case TYPE_INT8: case TYPE_UINT8: /* * cmpb %1, %0 * jcc label */ /*FALLTHROUGH*/ case TYPE_INT16: case TYPE_UINT16: /* * cmpw %1, %0 * jcc label */ /*FALLTHROUGH*/ case TYPE_INT32: case TYPE_UINT32: /* * ... */ /*FALLTHROUGH*/ case TYPE_INT64: case TYPE_UINT64: /* * ... */ constraint_input(s, "mr", expr_dup(s->expr0->expr0)); constraint_input(s, "ir", expr_dup(s->expr0->expr1)); break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; case TYPE_VA_LIST: assert(0); /* FIXME */ break; default: assert(0); } break; case STMT_SWITCH: /* * cmp{b,w} $c0, %0 * je l0 * cmp{b,w} $c1, %0 * je l1 * cmp{b,w} $c2, %0 * je l2 * ... * cmp{b,w} $cN, %0 * je lN * jmp ldef */ constraint_input(s, "r", expr_dup(s->expr0)); break; case STMT_GOTO: /* * jmp label */ /* No constraints needed. */ break; case STMT_RETURN: /* * No code. Constraint only. */ if (s->expr0) { t = expr_typeof(block->scope, s->expr0); t = type_pure(t); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: constraint_input(s, "a", expr_dup(s->expr0)); break; case TYPE_INT32: case TYPE_UINT32: constraint_input(s, "A", expr_dup(s->expr0)); break; case TYPE_INT64: case TYPE_UINT64: constraint_input(s, "r", expr_dup(s->expr0)); break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: assert(0); default: assert(0); } } break; case STMT_ASM: /* * Code in asm statement. */ /* Constraints in asm statement. */ break; case STMT_VA_START: /* * lea X(%bp), %0 */ constraint_output(s, "=r", expr_dup(s->expr0)); break; case STMT_VA_END: /* * No code. No constraints. */ break; default: assert(0); } } static void arch_gen_stmt_simplify_2( struct stmt *block, struct stmt *s, unsigned int paramsize ) { struct type *t; struct constraint *c; struct stmt *cs; struct stmt *s0; char buf0[1024*1024]; char buf1[1024*1024]; const char *from; char *to; struct declaration *dion; switch (s->type) { case STMT_NONE: assert(0); case STMT_NULL: case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_CONTINUE: case STMT_BREAK: case STMT_BLOCK: assert(0); case STMT_LABEL: sprintf(buf0, "%s:\n", s->label->identifier); break; case STMT_EXPR: switch (s->expr0->type) { case EXPR_ASSIGN: switch (s->expr0->expr0->type) { case EXPR_IDENTIFIER: arch_gen_expr_2(buf0, block, s, s->expr0->expr1, s->expr0->expr0); break; case EXPR_STAR: t = expr_typeof(block->scope, s->expr0->expr1); t = type_pure(t); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: if (seg_enabled()) { strcpy(buf0, "\tmovw %w0, %%es\n"); strcat(buf0, "\tmovb %1, %%es:(%0)\n"); } else { strcpy(buf0, "\tmovb %1, (%0)\n"); } break; case TYPE_INT16: case TYPE_UINT16: if (seg_enabled()) { strcpy(buf0, "\tmovw %w0, %%es\n"); strcat(buf0, "\tmovw %1, %%es:(%0)\n"); } else { strcpy(buf0, "\tmovw %1, (%0)\n"); } break; case TYPE_INT32: case TYPE_UINT32: if (seg_enabled()) { strcpy(buf0, "\tmovw %w0, %%es\n"); strcat(buf0, "\tmovw %1, %%es:(%0)\n"); strcat(buf0, "\tmovw %w1, %%es:2(%0)\n"); } else { strcpy(buf0, "\tmovw %1, (%0)\n"); strcat(buf0, "\tmovw %w1, 2(%0)\n"); } break; case TYPE_INT64: case TYPE_UINT64: if (seg_enabled()) { strcpy(buf0, "\tmovw %w0, %%es\n"); strcat(buf0, "\tmovw %1, %%es:(%0)\n"); strcat(buf0, "\tmovw %w1, %%es:2(%0)\n"); strcat(buf0, "\tmovw %u1, %%es:4(%0)\n"); strcat(buf0, "\tmovw %v1, %%es:6(%0)\n"); } else { strcpy(buf0, "\tmovw %1, (%0)\n"); strcat(buf0, "\tmovw %w1, 2(%0)\n"); strcat(buf0, "\tmovw %u1, 4(%0)\n"); strcat(buf0, "\tmovw %v1, 6(%0)\n"); } break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; default: assert(0); } break; case EXPR_FUNC: arch_gen_expr_2(buf0, block, s, s->expr0, NULL); break; default: assert(0); } break; case STMT_IF: t = expr_typeof(block->scope, s->expr0->expr0); t = type_pure(t); switch (t->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: switch (t->type) { case TYPE_INT8: case TYPE_UINT8: strcpy(buf0, "\tcmpb %1, %0\n"); break; case TYPE_INT16: case TYPE_UINT16: strcpy(buf0, "\tcmpw %1, %0\n"); break; default: assert(0); } switch (t->type) { case TYPE_INT8: case TYPE_INT16: switch (s->expr0->type) { case EXPR_EQUAL: sprintf(buf0 + strlen(buf0), "\tje %s\n", s->stmt0->label->identifier); break; case EXPR_NOT_EQUAL: sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); break; case EXPR_LESS: sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); break; case EXPR_LESS_EQUAL: sprintf(buf0 + strlen(buf0), "\tjle %s\n", s->stmt0->label->identifier); break; case EXPR_GREATER: sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); break; case EXPR_GREATER_EQUAL: sprintf(buf0 + strlen(buf0), "\tjge %s\n", s->stmt0->label->identifier); break; default: assert(0); } break; case TYPE_UINT8: case TYPE_UINT16: switch (s->expr0->type) { case EXPR_EQUAL: sprintf(buf0 + strlen(buf0), "\tje %s\n", s->stmt0->label->identifier); break; case EXPR_NOT_EQUAL: sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); break; case EXPR_LESS: sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); break; case EXPR_LESS_EQUAL: sprintf(buf0 + strlen(buf0), "\tjbe %s\n", s->stmt0->label->identifier); break; case EXPR_GREATER: sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); break; case EXPR_GREATER_EQUAL: sprintf(buf0 + strlen(buf0), "\tjae %s\n", s->stmt0->label->identifier); break; default: assert(0); } break; default: assert(0); } break; case TYPE_INT32: switch (s->expr0->type) { case EXPR_EQUAL: strcpy(buf0, "\tcmpw %w1, %w0\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tje %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_NOT_EQUAL: strcpy(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); break; case EXPR_LESS: strcpy(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_LESS_EQUAL: strcpy(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjle %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER: strcpy(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER_EQUAL: strcpy(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjge %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; default: assert(0); } break; case TYPE_UINT32: switch (s->expr0->type) { case EXPR_EQUAL: strcpy(buf0, "\tcmpw %w1, %w0\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tje %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_NOT_EQUAL: strcpy(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); break; case EXPR_LESS: strcpy(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_LESS_EQUAL: strcpy(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjbe %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER: strcpy(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER_EQUAL: strcpy(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjge %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; default: assert(0); } break; case TYPE_INT64: switch (s->expr0->type) { case EXPR_EQUAL: strcpy(buf0, "\tcmpw %v1, %v0\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %u1, %u0\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %w1, %w0\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tje %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_NOT_EQUAL: strcpy(buf0, "\tcmpw %v1, %v0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); strcat(buf0, "\tcmpw %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); strcat(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); break; case EXPR_LESS: strcpy(buf0, "\tcmpw %v1, %v0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tcmpw %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_LESS_EQUAL: strcpy(buf0, "\tcmpw %v1, %v0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tcmpw %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjl %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjg 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjle %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER: strcpy(buf0, "\tcmpw %v1, %v0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tcmpw %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER_EQUAL: strcpy(buf0, "\tcmpw %v1, %v0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tcmpw %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjg %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjl 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjge %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; default: assert(0); } break; case TYPE_UINT64: switch (s->expr0->type) { case EXPR_EQUAL: strcpy(buf0, "\tcmpw %v1, %v0\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %u1, %u0\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %w1, %w0\n"); strcat(buf0, "\tjne 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tje %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_NOT_EQUAL: strcpy(buf0, "\tcmpw %v1, %v0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); strcat(buf0, "\tcmpw %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); strcat(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjne %s\n", s->stmt0->label->identifier); break; case EXPR_LESS: strcpy(buf0, "\tcmpw %v1, %v0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpw %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_LESS_EQUAL: strcpy(buf0, "\tcmpw %v1, %v0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpw %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tjb %s\n", s->stmt0->label->identifier); strcat(buf0, "\tja 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjbe %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER: strcpy(buf0, "\tcmpw %v1, %v0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tcmpw %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case EXPR_GREATER_EQUAL: strcpy(buf0, "\tcmpw %v1, %v0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tcmpw %u1, %u0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tcmpw %w1, %w0\n"); sprintf(buf0 + strlen(buf0), "\tja %s\n", s->stmt0->label->identifier); strcat(buf0, "\tjb 1f\n"); strcat(buf0, "\tcmpw %1, %0\n"); sprintf(buf0 + strlen(buf0), "\tjae %s\n", s->stmt0->label->identifier); strcat(buf0, "1:\n"); break; default: assert(0); } break; case TYPE_FLOAT32: assert(0); /* FIXME */ break; case TYPE_FLOAT64: assert(0); /* FIXME */ break; case TYPE_FLOAT80: assert(0); /* FIXME */ break; default: assert(0); } break; case STMT_SWITCH: assert(s->expr0->type == EXPR_IDENTIFIER); t = expr_typeof(block->scope, s->expr0); t = type_pure(t); strcpy(buf0, ""); for (cs = s->stmt0->stmt_first; cs->type != STMT_DEFAULT; cs = cs->next) { switch (t->type) { case TYPE_INT8: case TYPE_UINT8: sprintf(buf0 + strlen(buf0), "\tcmpb $%lld, %%0\n", cs->expr0->integer); sprintf(buf0 + strlen(buf0), "\tje %s\n", cs->stmt0->label->identifier); break; case TYPE_INT16: case TYPE_UINT16: sprintf(buf0 + strlen(buf0), "\tcmpw $%lld, %%0\n", cs->expr0->integer); sprintf(buf0 + strlen(buf0), "\tje %s\n", cs->stmt0->label->identifier); break; case TYPE_INT32: case TYPE_UINT32: sprintf(buf0 + strlen(buf0), "\tcmpw $%u, %%0\n", (uint16_t) (cs->expr0->integer >> 0)); strcat(buf0, "\tjne 1f\n"); sprintf(buf0 + strlen(buf0), "\tcmpw $%u, %%w0\n", (uint16_t) (cs->expr0->integer >> 16)); sprintf(buf0 + strlen(buf0), "\tje %s\n", cs->stmt0->label->identifier); strcat(buf0, "1:\n"); break; case TYPE_INT64: case TYPE_UINT64: sprintf(buf0 + strlen(buf0), "\tcmpw $%u, %%0\n", (uint16_t) (cs->expr0->integer >> 0)); strcat(buf0, "\tjne 1f\n"); sprintf(buf0 + strlen(buf0), "\tcmpw $%u, %%w0\n", (uint16_t) (cs->expr0->integer >> 16)); strcat(buf0, "\tjne 1f\n"); sprintf(buf0 + strlen(buf0), "\tcmpw $%u, %%u0\n", (uint16_t) (cs->expr0->integer >> 32)); strcat(buf0, "\tjne 1f\n"); sprintf(buf0 + strlen(buf0), "\tcmpw $%u, %%v0\n", (uint16_t) (cs->expr0->integer >> 48)); sprintf(buf0 + strlen(buf0), "\tje %s\n", cs->stmt0->label->identifier); strcat(buf0, "1:\n"); break; default: assert(0); } } sprintf(buf0 + strlen(buf0), "\tjmp %s\n", cs->stmt0->label->identifier); break; case STMT_GOTO: sprintf(buf0, "\tjmp %s\n", s->label->identifier); break; case STMT_RETURN: /* * No code. Asm constraints only. */ strcpy(buf0, ""); break; case STMT_ASM: strcpy(buf0, s->code); if (0 < strlen(buf0) && buf0[strlen(buf0) - 1] != '\n') { /* Newline is missing... */ strcat(buf0, "\n"); } break; case STMT_VA_START: sprintf(buf0, "\tleaw %u(%%%%bp), %%0\n", paramsize); break; case STMT_VA_END: strcpy(buf0, ""); break; default: assert(0); } /* * Replace %0, %1, ... in asm statements. */ from = buf0; to = buf1; while (*from) { enum type_mod mod; unsigned int n; unsigned int offset; const char *reg; unsigned long long val; if (*from != '%') { *to++ = *from++; continue; } from++; if (*from == '%') { from++; *to++ = '%'; continue; } /* * Get byte/word/long modifier. */ switch (*from) { case 'b': mod = REG_MOD_b; offset = 0; from++; break; case 'h': mod = REG_MOD_h; offset = 1; from++; break; case 'w': mod = REG_MOD_w; offset = 2; from++; break; case 'u': mod = REG_MOD_u; offset = 4; from++; break; case 'v': mod = REG_MOD_v; offset = 6; from++; break; default: mod = REG_MOD_NONE; offset = 0; break; } /* * Get constraint number. */ if (*from < '0' || '9' < *from) { fprintf(stderr, "No constraint number.\n"); goto problem; } assert('0' <= *from && *from <= '9'); n = 0; while ('0' <= *from && *from <= '9') { n *= 10; n += *from++ - '0'; } if (100 <= n) { fprintf(stderr, "Constraint number >= 100.\n"); goto problem; } assert(n < 100); /* * Lookup constraint. */ for (c = s->output->first; c && n; c = c->next) { n--; } if (! c) { for (c = s->input->first; c && n; c = c->next) { n--; } } if (! c) { fprintf(stderr, "Too few constraints.\n"); goto problem; } assert(c); /* * Replace "%num" by real operand. */ switch (c->expr->type) { case EXPR_INTEGER: switch (c->expr->type_name->type) { case TYPE_INT8: case TYPE_UINT8: val = (uint8_t) c->expr->integer; break; case TYPE_INT16: case TYPE_UINT16: val = (uint16_t) c->expr->integer; break; case TYPE_INT32: case TYPE_UINT32: val = (uint32_t) c->expr->integer; break; case TYPE_INT64: case TYPE_UINT64: val = c->expr->integer; break; default: assert(0); } switch (mod) { case REG_MOD_NONE: val &= 0xffff; break; case REG_MOD_b: val &= 0xff; break; case REG_MOD_h: val >>= 8; val &= 0xff; break; case REG_MOD_u: val >>= 32; val &= 0xff; break; case REG_MOD_v: val >>= 48; val &= 0xff; break; case REG_MOD_w: val >>= 16; val &= 0xffff; break; default: assert(0); } sprintf(to, "$0x%llx", val); to += strlen(to); break; case EXPR_REAL: assert(0); case EXPR_IDENTIFIER: dion = c->expr->declaration; assert(dion); switch (dion->storage) { case STORAGE_AUTO: sprintf(to, "%d(%%bp)", dion->offset + offset); to += strlen(to); break; case STORAGE_REGISTER: switch (mod) { case REG_MOD_NONE: reg = arch_reg_name_def[dion->storage_register]; break; case REG_MOD_b: reg = arch_reg_name_b[dion->storage_register]; break; case REG_MOD_h: reg = arch_reg_name_h[dion->storage_register]; break; case REG_MOD_w: reg = arch_reg_name_w[dion->storage_register]; break; case REG_MOD_u: reg = arch_reg_name_u[dion->storage_register]; break; case REG_MOD_v: reg = arch_reg_name_v[dion->storage_register]; break; default: assert(0); /* Mustn't happen. */ } if (! reg) { fprintf(stderr, "mod=%u, reg=%u\n", mod, dion->storage_register); goto problem; } assert(reg); sprintf(to, "%%%s", reg); to += strlen(to); break; case STORAGE_PARAM: sprintf(to, "%u(%%bp)", dion->offset + offset); to += strlen(to); break; case STORAGE_STATIC: if (offset == 0) { sprintf(to, "%s", arch_gen_local_off(dion->identifier)); to += strlen(to); } else { assert(offset == 2); sprintf(to, "%s", arch_gen_local_seg(dion->identifier)); to += strlen(to); } break; case STORAGE_NONE: case STORAGE_EXTERN: if (offset == 0) { sprintf(to, "%s", arch_gen_global_off(dion->identifier)); to += strlen(to); } else { assert(offset == 2); sprintf(to, "%s", arch_gen_global_seg(dion->identifier)); to += strlen(to); } break; case STORAGE_TYPEDEF: case STORAGE_ASM: assert(0); } break; case EXPR_AMPHERSAND: assert(0); case EXPR_TYPE_CONVERSION: if (c->expr->expr0->type == EXPR_AMPHERSAND) { /* * Special case: (int) &var */ dion = c->expr->expr0->expr0->declaration; } else if (c->expr->expr0->type == EXPR_IDENTIFIER) { /* * Special case: (int) array * Special case: (int) func */ dion = c->expr->expr0->declaration; } else { assert(0); } assert(dion); if (dion->storage == STORAGE_STATIC) { if (seg_enabled()) { if (offset == 0) { sprintf(to, "$%s", arch_gen_local_off(dion->identifier)); } else { assert(offset == 2); sprintf(to, "$%s", arch_gen_local_seg(dion->identifier)); } } else { assert(offset == 0); sprintf(to, "$%s", arch_gen_local_off(dion->identifier)); } } else if (dion->storage == STORAGE_NONE || dion->storage == STORAGE_EXTERN) { if (seg_enabled()) { if (offset == 0) { sprintf(to, "$%s", arch_gen_global_off(dion->identifier)); } else { assert(offset == 2); sprintf(to, "$%s", arch_gen_global_seg(dion->identifier)); } } else { assert(offset == 0); sprintf(to, "$%s", arch_gen_global_off(dion->identifier)); } } else if (dion->storage == STORAGE_AUTO) { sprintf(to, "%d(%%bp)", dion->offset + offset); } else if (dion->storage == STORAGE_PARAM) { sprintf(to, "%d(%%bp)", dion->offset + offset); } to += strlen(to); break; default: problem: fprintf(stderr, "Problem with:\n"); fprintf(stderr, "%s", buf0); assert(0); } } *to = '\0'; s0 = stmt_new(); s0->type = STMT_ASM; s0->code = identifier_new(buf1); s0->code_len = strlen(s0->code); s0->output = constraint_list_new(); s0->input = constraint_list_new(); s0->change = constraint_list_new(); stmt_replace_1_by_1(block, s, s0); } static void arch_gen_func(FILE *fp, struct declaration *dion) { struct declaration *save[REG_COUNT]; struct declaration *d; struct stmt *cs; int offset; unsigned int align; unsigned int size; unsigned int autosize; unsigned int paramsize; /* * Check "dion->stmt->stmt_last->type == STMT_RETURN" should * not be neccessary - FIXME. */ if (! dion->attr_noreturn && dion->stmt->stmt_last->type == STMT_RETURN) { unsigned int reg; uint64_t regs_to_save; assert(dion->stmt->stmt_last->type == STMT_RETURN); /* Save Registers */ regs_to_save = REG_CALLEE; if (dion->stmt->stmt_last->expr0 != NULL) { struct expr *e; struct type *t; e = dion->stmt->stmt_last->expr0; t = e->type_name; t = expr_typeof(dion->stmt->scope, e); t = type_pure(t); switch (t->type) { case TYPE_INT64: case TYPE_UINT64: regs_to_save &= ~((1 << SI) | (1 << DI)); break; default: break; }; } assert((regs_to_save & ~REG_16) == 0); /* Save registers */ cs = stmt_new(); cs->type = STMT_ASM; cs->code = identifier_new(""); cs->code_len = 0; for (reg = 0; reg < REG_COUNT; reg++) { const char *constraint; if (! ((regs_to_save >> reg) & 1)) { save[reg] = NULL; continue; } save[reg] = simplify_declaration_add(dion->stmt->scope, type_uint16(), identifier_tmp()); save[reg]->storage = STORAGE_AUTO; switch (reg) { case AX: constraint = "=a"; break; case BX: constraint = "=b"; break; case CX: constraint = "=c"; break; case DX: constraint = "=d"; break; case DI: constraint = "=D"; break; case SI: constraint = "=S"; break; default: assert(0); /* Mustn't happen. */ } constraint_output(cs, constraint, expr_identifier(save[reg])); } stmt_prepend_first(dion->stmt, cs); /* Restore Registers */ cs = dion->stmt->stmt_last; for (reg = 0; reg < REG_COUNT; reg++) { const char *constraint; if (! ((regs_to_save >> reg) & 1)) { assert(save[reg] == NULL); continue; } switch (reg) { case AX: constraint = "a"; break; case BX: constraint = "b"; break; case CX: constraint = "c"; break; case DX: constraint = "d"; break; case DI: constraint = "D"; break; case SI: constraint = "S"; break; default: assert(0); /* Mustn't happen. */ } constraint_input(cs, constraint, expr_identifier(save[reg])); } } /* * Transform statements into assembler code. * First step. */ for (cs = dion->stmt->stmt_first; cs; ) { struct stmt *next; next = cs->next; arch_gen_stmt_simplify_1(dion->stmt, cs); cs = next; } /* * Add missing constraint info. */ for (cs = dion->stmt->stmt_first; cs; cs = cs->next) { if (! cs->output) { cs->output = constraint_list_new(); } if (! cs->input) { cs->input = constraint_list_new(); } if (! cs->change) { cs->change = constraint_list_new(); } } #if 0 print_declaration(stderr, 0, dion); #endif /* * Register assignment. */ regalloc(arch_reginfo, arch_classinfo, arch_typeinfo, dion->stmt); #if 0 print_declaration(stderr, 0, dion); #endif offset = 0; for (d = dion->stmt->scope->declaration_first; d; d = d->next) { if (d->storage == STORAGE_AUTO) { type_align_size(dion->stmt->scope, d->type_name, &align, &size); offset -= size; offset &= ~(align - 1); d->offset = offset; } } autosize = offset; autosize &= ~(2 - 1); /* 2 Byte Alignment */ autosize = -autosize; offset = 2; /* Base Pointer */ if (seg_enabled()) { offset += 4; /* Return Address */ } else { offset += 2; /* Return Address */ } for (d = dion->type_name->parameter->declaration_first; d && d->type_name->type != TYPE_ELIPSIS; d = d->next) { type_align_size(dion->stmt->scope, d->type_name, &align, &size); offset += align - 1; offset &= ~(align - 1); d->offset = offset; offset += size; } paramsize = offset; paramsize += 2 - 1; /* 2 Byte Alignment */ paramsize &= ~(2 - 1); /* * Transform remaining statements into assembler code. * Second step. */ for (cs = dion->stmt->stmt_first; cs; ) { struct stmt *next; next = cs->next; arch_gen_stmt_simplify_2(dion->stmt, cs, paramsize); cs = next; } /* * Generate Header */ fprintf(fp, "\t.text\n"); fprintf(fp, "\t.code16\n"); fprintf(fp, "\t.arch i286\n"); if (opt_f_align_functions != 1) { unsigned int p; for (p = 0; (1 << p) < opt_f_align_functions; p++) { } fprintf(fp, "\t.p2align %u\n", p); } if (dion->storage == STORAGE_STATIC) { if (seg_enabled()) { /* * NOTE: * Label *must* be global. Otherwise our * linker tool will not generate __SEG_x/__OFF_x * symbols for it. */ fprintf(fp, "\t.globl %s\n", arch_gen_local(dion->identifier)); } fprintf(fp, "%s:\n", arch_gen_local(dion->identifier)); } else { fprintf(fp, "\t.globl %s\n", arch_gen_global(dion->identifier)); fprintf(fp, "%s:\n", arch_gen_global(dion->identifier)); } fprintf(fp, "\tpushw %%bp\n"); fprintf(fp, "\tmovw %%sp, %%bp\n"); if (0 < autosize) { fprintf(fp, "\tsubw $%d, %%sp\n", autosize); } /* * Generate Code */ for (cs = dion->stmt->stmt_first; cs; cs = cs->next) { if (cs->type == STMT_ASM) { fprintf(fp, "%s", cs->code); } else { fprintf(fp, "...\n"); } } /* * Generate Trailer */ if (0 < autosize) { fprintf(fp, "\taddw $%d, %%sp\n", autosize); } fprintf(fp, "\tpopw %%bp\n"); if (seg_enabled()) { fprintf(fp, "\tlret\n"); } else { fprintf(fp, "\tret\n"); } fprintf(fp, "\n"); } static void arch_gen_dion(FILE *fp, struct scope *scope, struct declaration *dion) { if (dion->storage == STORAGE_TYPEDEF) { /* Type definition only. */ return; } if (dion->storage != STORAGE_ASM && dion->identifier == NULL) { /* struct/union/enum definition only. */ return; } if (dion->storage == STORAGE_EXTERN) { /* Extern declaration only. */ return; } if ((dion->storage == STORAGE_NONE || dion->storage == STORAGE_EXTERN || dion->storage == STORAGE_STATIC) && type_is_function(dion->type_name) && ! dion->stmt) { /* Function prototype only. */ return; } if (dion->storage == STORAGE_ASM) { fprintf(fp, "%s\n", dion->code); } else { if (dion->storage == STORAGE_STATIC) { arch_gen_local_def(dion->identifier); } else { arch_gen_global_def(dion->identifier); } if (! type_is_function(dion->type_name)) { arch_gen_data(fp, scope, dion); } else { arch_gen_func(fp, dion); } } fprintf(fp, "\n"); } void arch_i286_gen(const char *out, struct scope *scope) { FILE *fp; struct declaration *dion; int ret; fp = fopen(out, "w"); assert(fp); assert(REG_COUNT <= DECL_REG_COUNT); assert(CLASS_NONE == DECL_CLASS_NONE); assert(CLASS_COUNT <= DECL_CLASS_COUNT); ret = setvbuf(fp, NULL, _IONBF, 0); assert(0 <= ret); arch_mul_int32 = declaration_identifier("__i286_mul_int32"); arch_mul_int32->type_name = type_new(); arch_mul_int32->type_name->type = TYPE_FUNCTION; arch_mul_int32->type_name->declarator = type_new(); arch_mul_int32->type_name->declarator->type = TYPE_INT32; arch_mul_uint32 = declaration_identifier("__i286_mul_uint32"); arch_mul_uint32->type_name = type_new(); arch_mul_uint32->type_name->type = TYPE_FUNCTION; arch_mul_uint32->type_name->declarator = type_new(); arch_mul_uint32->type_name->declarator->type = TYPE_UINT32; arch_div_int32 = declaration_identifier("__i286_div_int32"); arch_div_int32->type_name = type_new(); arch_div_int32->type_name->type = TYPE_FUNCTION; arch_div_int32->type_name->declarator = type_new(); arch_div_int32->type_name->declarator->type = TYPE_INT32; arch_div_uint32 = declaration_identifier("__i286_div_uint32"); arch_div_uint32->type_name = type_new(); arch_div_uint32->type_name->type = TYPE_FUNCTION; arch_div_uint32->type_name->declarator = type_new(); arch_div_uint32->type_name->declarator->type = TYPE_UINT32; arch_mod_int32 = declaration_identifier("__i286_mod_int32"); arch_mod_int32->type_name = type_new(); arch_mod_int32->type_name->type = TYPE_FUNCTION; arch_mod_int32->type_name->declarator = type_new(); arch_mod_int32->type_name->declarator->type = TYPE_INT32; arch_mod_uint32 = declaration_identifier("__i286_mod_uint32"); arch_mod_uint32->type_name = type_new(); arch_mod_uint32->type_name->type = TYPE_FUNCTION; arch_mod_uint32->type_name->declarator = type_new(); arch_mod_uint32->type_name->declarator->type = TYPE_UINT32; arch_mul_int64 = declaration_identifier("__i286_mul_int64"); arch_mul_int64->type_name = type_new(); arch_mul_int64->type_name->type = TYPE_FUNCTION; arch_mul_int64->type_name->declarator = type_new(); arch_mul_int64->type_name->declarator->type = TYPE_INT64; arch_mul_uint64 = declaration_identifier("__i286_mul_uint64"); arch_mul_uint64->type_name = type_new(); arch_mul_uint64->type_name->type = TYPE_FUNCTION; arch_mul_uint64->type_name->declarator = type_new(); arch_mul_uint64->type_name->declarator->type = TYPE_UINT64; arch_div_int64 = declaration_identifier("__i286_div_int64"); arch_div_int64->type_name = type_new(); arch_div_int64->type_name->type = TYPE_FUNCTION; arch_div_int64->type_name->declarator = type_new(); arch_div_int64->type_name->declarator->type = TYPE_INT64; arch_div_uint64 = declaration_identifier("__i286_div_uint64"); arch_div_uint64->type_name = type_new(); arch_div_uint64->type_name->type = TYPE_FUNCTION; arch_div_uint64->type_name->declarator = type_new(); arch_div_uint64->type_name->declarator->type = TYPE_UINT64; arch_mod_int64 = declaration_identifier("__i286_mod_int64"); arch_mod_int64->type_name = type_new(); arch_mod_int64->type_name->type = TYPE_FUNCTION; arch_mod_int64->type_name->declarator = type_new(); arch_mod_int64->type_name->declarator->type = TYPE_INT64; arch_mod_uint64 = declaration_identifier("__i286_mod_uint64"); arch_mod_uint64->type_name = type_new(); arch_mod_uint64->type_name->type = TYPE_FUNCTION; arch_mod_uint64->type_name->declarator = type_new(); arch_mod_uint64->type_name->declarator->type = TYPE_UINT64; for (dion = scope->declaration_first; dion; dion = dion->next) { #if 0 print_declaration(stderr, 0, dion); #endif arch_gen_dion(fp, scope, dion); #if 0 print_declaration(stderr, 0, dion); #endif } ret = fclose(fp); assert(0 <= ret); } faucc-20120707/test/0000750002413100241000000000000011776113700013467 5ustar potyrai3guestfaucc-20120707/test/test21.c0000640002413100241000000000066311703517141014760 0ustar potyrai3guest/* * $Id: test21.c,v 1.1 2012-01-12 08:48:33 vrsieh Exp $ * * Copyright (C) 2008-2012 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ void test0(void) { } void test1(void) { void (*f)(void); f = test0; (*f)(); f(); } faucc-20120707/test/chip_intel_80386_inline.c0000640002413100241000000101522611137627476020102 0ustar potyrai3guest/* $Id: chip_intel_80386_inline.c,v 1.3 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ /* * FUNCTION NAMING CONVENTIONS * * get_VAR() * * returns the value of the variable specified by VAR * * set_VAR(value) * * assigns value to the variable specified by VAR; immediately * * sset_VAR(value) * * scheduled set; like set_VAR(value), but needs a commit * * commit_VAR(value) * * makes a scheduled set persistent * * store_VAR() * * set_VAR(t0) * * load_VAR() * * t1 = get_VAR() * * load_VAR1_VAR2() * * t1 = get_VAR1() * t2 = get_VAR2() * * VAR * * TODO * * ABBREVIATIONS * * TODO * */ #include #include #include #include typedef int bool; /******************************************************************************/ /* forward */ void print_state(FILE *f); /******************************************************************************/ #if 0 static int done; #endif #ifndef DEBUG_CONTROL_FLOW # define DEBUG_CONTROL_FLOW 0 #endif #define DEBUG_EXCEPTIONS 0 #if 0 #define DEBUG(...) \ if (debug_enabled) { \ fprintf(stderr, __VA_ARGS__); \ } bool debug_enabled = 0; #else #define DEBUG(...) #endif #define DEBUG_GET DEBUG #define DEBUG_SET DEBUG /******************************************************************************/ #ifdef INTERPRETER int always_true = 1; /* FIXME */ #define ERROR(...) \ do { \ fprintf(stderr, "\n*** ERROR ***\n" \ "Line: %d\nFunction: %s\nFile: %s\n", \ __LINE__, __FUNCTION__, __FILE__); \ fprintf(stderr, __VA_ARGS__); \ print_state(stderr); \ if (always_true) { \ abort(); \ } \ } while (0) #else /* ! INTERPRETER */ #define ERROR(...) error(__LINE__) #endif /* INTERPRETER */ #define ERROR_NYI() ERROR("Not yet implemented...\n") #define DEBUG_ERROR_SWITCH() ERROR("Unhandled switch case...\n"); /******************************************************************************/ #ifndef INTERPRETER extern uint32_t cpu_phys_mr(uint32_t addr, unsigned int bs); extern void cpu_phys_mw(uint32_t addr, unsigned int bs, uint32_t val); extern uint32_t cpu_ior(uint32_t port, unsigned int bs); extern void cpu_iow(uint32_t port, unsigned int bs, uint32_t val); extern uint8_t cpu_irq(void); extern void __attribute__((__noreturn__)) ret(void); extern void error(int line); #endif /******************************************************************************/ #define SEGMENT_NONE -1 #define SEGMENT_ES 0 #define SEGMENT_CS 1 #define SEGMENT_SS 2 #define SEGMENT_DS 3 #define SEGMENT_FS 4 #define SEGMENT_GS 5 /****************************************************************************** * * Lock and Repeat prefixes * ******************************************************************************/ #define LR_NONE -1 #define LR_LOCK 0 /* 0xf0: LOCK prefix */ #define LR_REPNZ 1 /* 0xf2: REPNE/REPNZ prefix (for string instructions) */ #define LR_REPZ 2 /* 0xf3: REP/REPE/REPZ prefix (for string instructions) */ /******************************************************************************/ #define EFLAG_CF 0 /* Carry Flag */ /* 1 Reserved (set to 1) */ #define EFLAG_PF 2 /* Parity Flag */ /* 3 Reserved (set to 0) */ #define EFLAG_AF 4 /* Auxiliary Carry Flag */ /* 5 Reserved (set to 0) */ #define EFLAG_ZF 6 /* Zero Flag */ #define EFLAG_SF 7 /* Sign Flag */ #define EFLAG_TF 8 /* Trap Flag */ #define EFLAG_IF 9 /* Interrupt Enable Flag */ #define EFLAG_DF 10 /* Direction Flag */ #define EFLAG_OF 11 /* Overflow Flag */ #define EFLAG_IOPL0 12 /* I/O Privilege Level */ #define EFLAG_IOPL1 13 /* I/O Privilege Level */ #define EFLAG_NT 14 /* Nested Task */ /* 15 Reserved (set to 0) */ #define EFLAG_RF 16 /* Resume Flag */ #define EFLAG_VM 17 /* Virtual-8086 Mode */ #define EFLAG_AC 18 /* Alignment Check */ #define EFLAG_VIF 19 /* Virtual Interrupt Flag */ #define EFLAG_VIP 20 /* Virtual Interrupt Pending */ #define EFLAG_ID 21 /* ID Flag */ /* 22 Reserved (set to 0) */ /* ... */ /* 31 Reserved (set to 0) */ /******************************************************************************/ #define CR0_PE 0 /* Protection Enable */ #define CR0_MP 1 /* Monitor Coprocessor */ #define CR0_EM 2 /* Emulation */ #define CR0_TS 3 /* Task Switched */ #define CR0_ET 4 /* Extension Type */ #define CR0_NE 5 /* Numeric Error */ /* Reserved */ #define CR0_WP 16 /* Write Protect */ /* Reserved */ #define CR0_AM 18 /* Alignment Mask */ /* Reserved */ #define CR0_NW 29 /* Not Write-through */ #define CR0_CD 30 /* Cache Disable */ #define CR0_PG 31 /* Paging */ /******************************************************************************/ /* Reserved */ #define CR3_PWT 3 /* Page-level Writes Transparent */ #define CR3_PCD 4 /* Page-level Cache Disable */ /* Reserved */ #define CR3_PDB 12 /* 12-31: Page-Directory Base */ /******************************************************************************/ #define CR4_VME 0 /* Virtual-8086 Mode Extensions */ #define CR4_PVI 1 /* Protected-Mode Virtual Interrupts */ #define CR4_TSD 2 /* Time Stamp Disable */ #define CR4_DE 3 /* Debugging Extensions */ #define CR4_PSE 4 /* Page Size Extension */ #define CR4_PAE 5 /* Physical Address Extension */ #define CR4_MCE 6 /* Machine-Check Enable */ #define CR4_PGE 7 /* Page Global Enable */ #define CR4_PCE 8 /* Performance-Monitoring Counter Enable */ #define CR4_OSFXSR 9 /* Operating System FXSAVE/FXRSTOR Support */ #define CR4_OSXMMEXCPT 10 /* Operating System Unmasked Exception Support */ /* 11 Reserved (set to 0) */ /* ... */ /* 31 Reserved (set to 0) */ /******************************************************************************/ #define EXCEPTION_NONE -1 #define EXCEPTION_DE 0 /* Fault: Divide Error */ #define EXCEPTION_DB 1 /* Fault/Trap: Debug */ #define EXCEPTION_NMI 2 /* Interrupt: NMI Interrupt */ #define EXCEPTION_BP 3 /* Trap: Breakpoint */ #define EXCEPTION_OF 4 /* Trap: Overflow */ #define EXCEPTION_BR 5 /* Fault: BOUND Range Exceeded */ #define EXCEPTION_UD 6 /* Fault: Invalid Opcode (Undefined Opcode) */ #define EXCEPTION_NM 7 /* Fault: Device Not Available (No Math Coprocessor) */ #define EXCEPTION_DF 8 /* Abort: Double Fault */ /* 9 Fault: Coprocessor Segment Overrun (reserved) */ #define EXCEPTION_TS 10 /* Fault: Invalid TSS */ #define EXCEPTION_NP 11 /* Fault: Segment Not Present */ #define EXCEPTION_SS 12 /* Fault: Stack-Segment Fault */ #define EXCEPTION_GP 13 /* Fault: General Protection */ #define EXCEPTION_PF 14 /* Fault: Page Fault */ /* 15 Intel reserved. Do not use. */ #define EXCEPTION_MF 16 /* Fault: Floating-Point Error (Math Fault) */ #define EXCEPTION_AC 17 /* Fault: Alignment Check */ #define EXCEPTION_MC 18 /* Abort: Machine Check */ #define EXCEPTION_XF 19 /* Fault: Streaming SIMD Extensions */ /* 20 Intel reserved. Do not use. */ /* ... */ /* 31 Intel reserved, Do not use. */ /* 32 Interrupt: User Defined (Nonreserved) */ /* ... */ /* 255 Interrupt: User Defined (Nonreserved) */ /****************************************************************************** * * Code- and Data-Segment Types * ******************************************************************************/ #define SEGMENT_DATA_READ_ONLY 0x0 #define SEGMENT_DATA_READ_ONLY_ACCESSED 0x1 #define SEGMENT_DATA_READ_WRITE 0x2 #define SEGMENT_DATA_READ_WRITE_ACCESSED 0x3 #define SEGMENT_DATA_READ_ONLY_EXPAND_DOWN 0x4 #define SEGMENT_DATA_READ_ONLY_EXPAND_DOWN_ACCESSED 0x5 #define SEGMENT_DATA_READ_WRITE_EXPAND_DOWN 0x6 #define SEGMENT_DATA_READ_WRITE_EXPAND_DOWN_ACCESSED 0x7 #define SEGMENT_CODE_EXEC_ONLY 0x8 #define SEGMENT_CODE_EXEC_ONLY_ACCESSED 0x9 #define SEGMENT_CODE_EXEC_READ 0xa #define SEGMENT_CODE_EXEC_READ_ACCESSED 0xb #define SEGMENT_CODE_EXEC_ONLY_CONFORMING 0xc #define SEGMENT_CODE_EXEC_ONLY_CONFORMING_ACCESSED 0xd #define SEGMENT_CODE_EXEC_READ_CONFORMING 0xe #define SEGMENT_CODE_EXEC_READ_CONFORMING_ACCESSED 0xf /****************************************************************************** * * System-Segment and Gate-Descriptor Types * ******************************************************************************/ /* Reserved */ #define SEGMENT_16BIT_AVAIL_TSS 0x1 #define SEGMENT_LDT 0x2 #define SEGMENT_16BIT_BUSY_TSS 0x3 #define SEGMENT_16BIT_CALL_GATE 0x4 #define SEGMENT_TASK_GATE 0x5 #define SEGMENT_16BIT_INTERRUPT_GATE 0x6 #define SEGMENT_16BIT_TRAP_GATE 0x7 /* Reserved */ #define SEGMENT_32BIT_AVAIL_TSS 0x9 /* Reserved */ #define SEGMENT_32BIT_BUSY_TSS 0xb #define SEGMENT_32BIT_CALL_GATE 0xc /* Reserved */ #define SEGMENT_32BIT_INTERRUPT_GATE 0xe #define SEGMENT_32BIT_TRAP_GATE 0xf /****************************************************************************** * * Temporary Registers * ******************************************************************************/ static uint32_t t0; /* Result */ static uint32_t t1; /* Operand1 */ static uint32_t t2; /* Operand2 */ static uint32_t t3; /* Operand3 (for SHRD, SHLD) */ static int32_t tj; /* Jump offset */ /****************************************************************************** * * General-Purpose Data Registers * ******************************************************************************/ static uint32_t eax; static uint32_t ecx; static uint32_t edx; static uint32_t ebx; static uint32_t esp, esp_backup; static uint32_t ebp; static uint32_t esi; static uint32_t edi; /****************************************************************************** * * Status and Control Registers * ******************************************************************************/ static uint32_t eip, eip_new; /* Instruction pointer */ /* EFLAGS Register */ static bool eflag_cf, eflag_cf_new; /* Carry Flag */ static bool eflag_pf, eflag_pf_new; /* Parity flag */ static bool eflag_af, eflag_af_new; /* Auxiliary Carry Flag */ static bool eflag_zf, eflag_zf_new; /* Zero Flag */ static bool eflag_sf, eflag_sf_new; /* Sign Flag */ static bool eflag_tf, eflag_tf_new; /* Trap Flag */ static bool eflag_if, eflag_if_new; /* Interrupt Enable Flag */ static bool eflag_df, eflag_df_new; /* Direction Flag */ static bool eflag_of, eflag_of_new; /* Overflow Flag */ static bool eflag_iopl0, eflag_iopl0_new; /* I/O Privilege Level */ static bool eflag_iopl1, eflag_iopl1_new; /* I/O Privilege Level */ static bool eflag_nt, eflag_nt_new; /* Nested Task Flag */ static bool eflag_rf, eflag_rf_new; /* Resume Flag */ static bool eflag_vm, eflag_vm_new; /* Virtual-8086 Mode */ /* Control Register 0: */ /* Contains system control flags that control */ /* operating mode and states of the processor */ static bool cr0_pe; /* Protection Enable */ static bool cr0_mp; /* Monitor Coprocessor */ static bool cr0_em; /* Emulation */ static bool cr0_ts; /* Task Switch */ static bool cr0_et; /* Extension Type */ static bool cr0_pg; /* Paging */ /* Control Register 1: */ /* Reserved... */ /* Control Register 2: */ /* Contains the page-fault linear address */ /* (the linear address that caused a page fault) */ static uint32_t cr2_pfla; /* Page-Fault Linear Address */ /* Control Register 3: */ /* Contains the physical address of the base of the */ /* page directory and two flags (PCD and PWT) */ static uint32_t cr3_pdb; /* 12-31: Page-Directory Base */ /****************************************************************************** * * Segment Selectors * * 13 index Index in the GDT or LDT * 1 ti Table Indicator (0 = GDT; 1 = LDT) * 2 rpl Requested Privilege Level (RPL) * * Segment Descriptors * * 4 type Segment type * 1 sflag Descriptor type (0 = system; 1 = code or data) * 2 dpl Descriptor privilege level * 1 pflag Segment present * * Data-/Code-Segment Descriptors * * 32 limit Segment limit scaled (20 bit for gflag == 0) * 32 base Segment base address * 1 dflag: Default operation size (0 = 16-bit segment; 1 = 32-bit segment) * 1 avlflag: Available for use by system software * * System-Segment Descriptors * * 32 limit Segment limit scaled (20 bit for gflag == 0) * 32 base Segment base address * * Call-/Trap-/Interrupt-/Task-Gate Descriptors * * 16 selector Segment Selectors * 32 offset Offset in Segment * 5 paramcount * ******************************************************************************/ /* Segment Selector (filled by sset_selector()) */ static uint16_t selector; static uint16_t selector_index; static uint8_t selector_ti; static uint8_t selector_rpl; /* Segment Descriptor (filled by sset_descriptor()) */ static uint8_t descriptor_type; static bool descriptor_sflag; static uint8_t descriptor_dpl; static bool descriptor_pflag; /* Data-/Code-Segment Descriptor (filled by sset_descriptor()) */ static uint32_t descriptor_segment_limit; static uint32_t descriptor_segment_base; static bool descriptor_segment_dflag; static bool descriptor_segment_avlflag; /* System-Segment Descriptor (filled by sset_descriptor()) */ static uint32_t descriptor_system_limit; static uint32_t descriptor_system_base; /* Call-/Trap-/Interrupt-/Task-Gate Descriptor (filled by sset_descriptor()) */ static uint16_t descriptor_gate_selector; static uint32_t descriptor_gate_offset; static uint8_t descriptor_gate_paramcount; /******************************************************************************/ /* Code Segment */ static uint16_t cs_selector; static uint8_t cs_type; static bool cs_sflag; static uint8_t cs_dpl; static bool cs_pflag; static uint32_t cs_segment_limit; static uint32_t cs_segment_base; static bool cs_segment_dflag; static bool cs_segment_avlflag; /* Stack Segment */ static uint16_t ss_selector; static uint8_t ss_type; static bool ss_sflag; static uint8_t ss_dpl; static bool ss_pflag; static uint32_t ss_segment_limit; static uint32_t ss_segment_base; static bool ss_segment_dflag; static bool ss_segment_avlflag; /* Data Segment */ static uint16_t ds_selector; static uint8_t ds_type; static bool ds_sflag; static uint8_t ds_dpl; static bool ds_pflag; static uint32_t ds_segment_limit; static uint32_t ds_segment_base; static bool ds_segment_dflag; static bool ds_segment_avlflag; /* Data Segment */ static uint16_t es_selector; static uint8_t es_type; static bool es_sflag; static uint8_t es_dpl; static bool es_pflag; static uint32_t es_segment_limit; static uint32_t es_segment_base; static bool es_segment_dflag; static bool es_segment_avlflag; /* Data Segment */ static uint16_t fs_selector; static uint8_t fs_type; static bool fs_sflag; static uint8_t fs_dpl; static bool fs_pflag; static uint32_t fs_segment_limit; static uint32_t fs_segment_base; static bool fs_segment_dflag; static bool fs_segment_avlflag; /* Data Segment */ static uint16_t gs_selector; static uint8_t gs_type; static bool gs_sflag; static uint8_t gs_dpl; static bool gs_pflag; static uint32_t gs_segment_limit; static uint32_t gs_segment_base; static bool gs_segment_dflag; static bool gs_segment_avlflag; /****************************************************************************** * * Memory-management Registers * ******************************************************************************/ /* Global Descriptor Table Register */ static uint32_t gdtr_limit; static uint32_t gdtr_base; /* Interrupt Descriptor Table Register */ static uint32_t idtr_limit; static uint32_t idtr_base; /* Local Descriptor Table Register */ static uint16_t ldtr_selector; /* ldtr_type = SEGMENT_LDT */ /* ldtr_sflag = 0 */ /* ldtr_dpl not used */ /* ldtr_pflag = 1 */ static uint32_t ldtr_system_limit; static uint32_t ldtr_system_base; /* Task Register */ static uint16_t tr_selector; static uint8_t tr_type; /* tr_sflag = 0 */ /* tr_dpl not used */ /* tr_pflag = 1 */ static uint32_t tr_system_limit; static uint32_t tr_system_base; /****************************************************************************** * * Instruction / Prefix * * prefix_* persistent * instruction_* cleared for each instruction * ******************************************************************************/ static bool prefix_operand_size_override; static bool prefix_address_size_override; static int prefix_segment_override; static int prefix_lock_repeat; /******************************************************************************/ static uint32_t instruction_opcode; static uint32_t instruction_opcode2; static uint32_t instruction_mod; static uint32_t instruction_reg; static uint32_t instruction_rm; static uint32_t instruction_scale; static uint32_t instruction_index; static uint32_t instruction_base; static uint32_t instruction_displacement; static uint32_t instruction_immediate; /****************************************************************************** * * Exception/Interrupt/Halt State * ******************************************************************************/ static int exception_vector; /* -1 == NONE */ static int exception_error_code; /* -1 == NONE */ static bool exception_is_interrupt; static bool exception_double_page_fault; static bool interrupt_pending; static bool interrupt_delay; static bool halt_state; /****************************************************************************** * * Misc Functions for simple calculations * ******************************************************************************/ static inline uint32_t limit_scaled(uint32_t limit, bool gflag) { if (gflag) { return (limit << 12) | 0xfff; } else { return limit; } } /****************************************************************************** * * Modes of Operation * ******************************************************************************/ static inline bool real_mode(void) { return !cr0_pe; } static inline bool protected_mode(void) { return cr0_pe && !eflag_vm; } static inline bool virtual8086_mode(void) { return cr0_pe && eflag_vm; } /****************************************************************************** * * MISC - TODO * ******************************************************************************/ static inline void prefix_clear(void) { prefix_lock_repeat = LR_NONE; prefix_segment_override = SEGMENT_NONE; prefix_operand_size_override = 0; prefix_address_size_override = 0; } /****************************************************************************** * * Exception * ******************************************************************************/ static void __attribute__((__noreturn__)) exception_debug(uint8_t vector, int error_code, int line) { esp = esp_backup; eip_new = eip; prefix_clear(); DEBUG("\n"); #if DEBUG_EXCEPTIONS fprintf(stderr, "EXCEPTION: vector=%u, error_code=0x%x, line=%d, " "cr2_pfla=0x%08x\n", vector, error_code, line, cr2_pfla); #endif #if 0 if (cr2_pfla != 0xc0000000) { debug_enabled = 1; } #endif if (exception_double_page_fault) { ERROR("Subsequent fault after two page faults..."); } /* PREVIOUS exception was... */ switch (exception_vector) { case EXCEPTION_NONE: exception_vector = vector; exception_error_code = error_code; exception_is_interrupt = 0; break; case EXCEPTION_DF: ERROR("Subsequent fault after double fault..."); break; case EXCEPTION_PF: if (vector == EXCEPTION_PF) { exception_vector = EXCEPTION_PF; exception_error_code = error_code; exception_is_interrupt = 0; exception_double_page_fault = 1; } else { exception_vector = EXCEPTION_DF; exception_error_code = 0; exception_is_interrupt = 0; } break; default: /* Double Fault */ exception_vector = EXCEPTION_DF; exception_error_code = 0; exception_is_interrupt = 0; break; } ret(); } /* FIXME: macros should be upper case */ #define exception(vector, error_code) \ exception_debug(vector, error_code, __LINE__) /****************************************************************************** * * MMU * * cpu_virt_mr -> cpu_phys_mr * cpu_virt_mw -> cpu_phys_mw * ******************************************************************************/ static struct { struct { uint32_t page; uint32_t entry; } cache[4]; uint32_t lru; } tlb[8]; static uint32_t cpu_virt_entry(uint32_t addr, int wflag, int uflag) { uint32_t index; uint32_t paddr; uint32_t entry; bool was_accessed; bool was_dirty; /* Page-Directory Entry */ index = (addr >> 22) & 0x3ff; paddr = (cr3_pdb << 12) | (index << 2); entry = cpu_phys_mr(paddr, 0xf); if (! (entry & 1)) { /* page-table not present */ cr2_pfla = addr; exception(EXCEPTION_PF, (uflag << 2) | (wflag << 1) | 0); } was_accessed = (entry >> 5) & 1; if (!was_accessed) { entry |= 1 << 5; cpu_phys_mw(paddr, 0xf, entry); } if (wflag /* want to write */ && uflag /* in user mode, but */ && ! (entry & 2)) { /* page group is read only */ cr2_pfla = addr; exception(EXCEPTION_PF, (uflag << 2) | (wflag << 1) | 1); } if (uflag /* want to read in user mode, but page group is assigned the */ && ! (entry & 4)) { /* supervisor privilege level */ cr2_pfla = addr; exception(EXCEPTION_PF, (uflag << 2) | (wflag << 1) | 1); } /* Page-Table Entry */ index = (addr >> 12) & 0x3ff; paddr = (entry & 0xfffff000) | (index << 2); entry = cpu_phys_mr(paddr, 0xf); if (! (entry & 1)) { /* page not present */ cr2_pfla = addr; exception(EXCEPTION_PF, (uflag << 2) | (wflag << 1) | 0); } was_accessed = (entry >> 5) & 1; was_dirty = (entry >> 6) & 1; if (!was_accessed || (wflag && !was_dirty)) { entry |= 1 << 5; entry |= wflag << 6; cpu_phys_mw(paddr, 0xf, entry); } if (wflag /* want to write */ && uflag /* in user mode, but */ && ! (entry & 2)) { /* page is read only */ cr2_pfla = addr; exception(EXCEPTION_PF, (uflag << 2) | (wflag << 1) | 1); } if (uflag /* want to read in user mode, but page is assigned the */ && ! (entry & 4)) { /* supervisor privilege level */ cr2_pfla = addr; exception(EXCEPTION_PF, (uflag << 2) | (wflag << 1) | 1); } return entry; } static uint32_t cpu_virt_addr(uint32_t addr, int wflag, int uflag) { uint32_t page; uint32_t offset; unsigned int c0; unsigned int c1; uint32_t entry; page = addr >> 12; offset = addr & 0xfff; c0 = page & 0x7; if (tlb[c0].cache[0].page == page) c1 = 0; else if (tlb[c0].cache[1].page == page) c1 = 1; else if (tlb[c0].cache[2].page == page) c1 = 2; else if (tlb[c0].cache[3].page == page) c1 = 3; else { c1 = tlb[c0].lru; /* Be careful: cpu_virt_entry might fail! */ tlb[c0].cache[c1].entry = cpu_virt_entry(addr, wflag, uflag); tlb[c0].cache[c1].page = page; tlb[c0].lru = (tlb[c0].lru + 1) & 3; } assert(tlb[c0].cache[c1].page == page); entry = tlb[c0].cache[c1].entry; assert(entry & 1); /* Check write access. */ if (wflag && uflag && ! (entry & 2)) { cr2_pfla = addr; exception(EXCEPTION_PF, (uflag << 2) | (wflag << 1) | 0); } /* Check user access. */ if (uflag && ! (entry & 4)) { cr2_pfla = addr; exception(EXCEPTION_PF, (uflag << 2) | (wflag << 1) | 0); } if (wflag && ! ((entry >> 6) & 1)) { /* Set dirty bit. */ tlb[c0].cache[c1].entry = cpu_virt_entry(addr, wflag, uflag); } return (entry & 0xfffff000) | offset; } static void cpu_tlb_flush(void) { unsigned int c0; unsigned int c1; for (c0 = 0; c0 < 8; c0++) { for (c1 = 0; c1 < 4; c1++) { tlb[c0].cache[c1].page = -1; } } } /******************************************************************************/ static uint32_t cpu_virt_mr(uint32_t addr, unsigned int bs, uint8_t pl) { if (cr0_pg) { addr = cpu_virt_addr(addr, 0, pl == 3); } return cpu_phys_mr(addr, bs); } static void cpu_virt_mw(uint32_t addr, unsigned int bs, uint32_t val, uint8_t pl) { if (cr0_pg) { addr = cpu_virt_addr(addr, 1, pl == 3); } cpu_phys_mw(addr, bs, val); } /****************************************************************************** * * Memory Read Byte * ******************************************************************************/ static uint8_t mrb(uint32_t addr, uint8_t pl) { uint32_t val32; uint8_t val8; val32 = cpu_virt_mr(addr & ~3, 1 << (addr & 3), pl); val8 = (val32 >> ((addr & 3) * 8)) & 0xff; if (DEBUG_CONTROL_FLOW) { fprintf(stderr, "Read %02x from %08"PRIx32"\n", val8, addr); } return val8; } /****************************************************************************** * * Memory Read Word * ******************************************************************************/ static uint16_t mrw(uint32_t addr, uint8_t pl) { uint16_t val16; uint32_t val32; if ((addr & 3) == 3) { val16 = mrb(addr, pl) | (mrb(addr + 1, pl) << 8); } else { val32 = cpu_virt_mr(addr & ~3, 3 << (addr & 3), pl); val16 = (val32 >> ((addr & 3) * 8)) & 0xffff; } if (DEBUG_CONTROL_FLOW) { fprintf(stderr, "Read %04x from %08"PRIx32"\n", val16, addr); } return val16; } /****************************************************************************** * * Memory Read Double word * ******************************************************************************/ static uint32_t mrd(uint32_t addr, uint8_t pl) { uint32_t val32; if (addr & 3) { uint32_t val0; uint32_t val1; val0 = cpu_virt_mr(addr & ~3, (0xf << (addr & 3)) & 0xf, pl); val1 = cpu_virt_mr((addr & ~3) + 4, 0xf >> (4 - (addr & 3)),pl); val32 = (val0 >> ((addr & 3) * 8)) | (val1 << ((4 - (addr & 3)) * 8)); } else { val32 = cpu_virt_mr(addr & ~3, 0xf, pl); } if (DEBUG_CONTROL_FLOW) { fprintf(stderr, "Read %08x from %08"PRIx32"\n", val32, addr); } return val32; } /****************************************************************************** * * Memory Write Byte * ******************************************************************************/ static void mwb(uint32_t addr, uint8_t value, uint8_t pl) { uint32_t val32; if (DEBUG_CONTROL_FLOW) { fprintf(stderr, "Write %02x to %08"PRIx32"\n", value, addr); } val32 = value << ((addr & 3) * 8); cpu_virt_mw(addr & ~3, 1 << (addr & 3), val32, pl); } /****************************************************************************** * * Memory Write Word * ******************************************************************************/ static void mww(uint32_t addr, uint16_t value, uint8_t pl) { uint32_t val32; if (DEBUG_CONTROL_FLOW) { fprintf(stderr, "Write %04x to %08"PRIx32"\n", value, addr); } if ((addr & 3) == 3) { uint8_t val0 = (value >> 0) & 0xff; uint8_t val1 = (value >> 8) & 0xff; mwb(addr + 0, val0, pl); mwb(addr + 1, val1, pl); } else { val32 = value << ((addr & 3) * 8); cpu_virt_mw(addr & ~3, 3 << (addr & 3), val32, pl); } } /****************************************************************************** * * Memory Write Double word * ******************************************************************************/ static void mwd(uint32_t addr, uint32_t value, uint8_t pl) { if (DEBUG_CONTROL_FLOW) { fprintf(stderr, "Write %08x to %08"PRIx32"\n", value, addr); } if (addr & 3) { uint32_t val0; uint32_t val1; val0 = value << ((addr & 3) * 8); val1 = value >> ((4 - (addr & 3)) * 8); cpu_virt_mw(addr & ~3, (0xf << (addr & 3)) & 0xf, val0, pl); cpu_virt_mw((addr & ~3) + 4, 0xf >> (4 - (addr & 3)), val1, pl); } else { cpu_virt_mw(addr & ~3, 0xf, value, pl); } } /****************************************************************************** * * Memory Read - Code Segment * ******************************************************************************/ static struct { uint32_t addr; uint32_t val; } ic[4]; static uint32_t instruction_cache(uint32_t addr) { unsigned int c; c = (addr >> 2) & 3; if (ic[c].addr != addr) { /* Be careful: cpu_virt_mr might fail! */ ic[c].val = cpu_virt_mr(addr, 0xf, cs_dpl); ic[c].addr = addr; } return ic[c].val; } static void instruction_cache_flush(void) { ic[0].addr = -1; ic[1].addr = -1; ic[2].addr = -1; ic[3].addr = -1; } static uint8_t mrb_cs(uint32_t addr) { uint8_t value; if (addr > cs_segment_limit) { exception(EXCEPTION_GP, 0); } addr += cs_segment_base; value = instruction_cache(addr & ~3) >> ((addr & 3) * 8); DEBUG("%02x ", value); return value; } static uint16_t mrw_cs(uint32_t addr) { uint16_t value; if (addr > cs_segment_limit - 1) { exception(EXCEPTION_GP, 0); } addr += cs_segment_base; if ((addr & 3) == 3) { uint32_t val0; uint32_t val1; val0 = instruction_cache((addr & ~3) + 0); val1 = instruction_cache((addr & ~3) + 4); value = (val0 >> 24) | (val1 << 8); } else { value = instruction_cache(addr & ~3) >> ((addr & 3) * 8); } DEBUG("%04x ", value); return value; } static uint32_t mrd_cs(uint32_t addr) { uint32_t value; if (addr > cs_segment_limit - 3) { exception(EXCEPTION_GP, 0); } addr += cs_segment_base; if (addr & 3) { uint32_t val0; uint32_t val1; val0 = instruction_cache((addr & ~3) + 0); val1 = instruction_cache((addr & ~3) + 4); value = (val0 >> ((addr & 3) * 8)) | (val1 << ((4 - (addr & 3)) * 8)); } else { value = instruction_cache(addr & ~3); } DEBUG("%08x ", value); return value; } /****************************************************************************** * * Segmented Memory Read / Write * ******************************************************************************/ static uint32_t get_segment_base_and_check_limit(uint32_t addr, int segment, unsigned length) { uint32_t segment_limit; uint32_t segment_base; int vector; switch (segment) { default: DEBUG_ERROR_SWITCH(); case SEGMENT_ES: DEBUG("ES:"); segment_limit = es_segment_limit; segment_base = es_segment_base; vector = EXCEPTION_GP; break; case SEGMENT_CS: DEBUG("CS:"); segment_limit = cs_segment_limit; segment_base = cs_segment_base; vector = EXCEPTION_GP; break; case SEGMENT_SS: DEBUG("SS:"); segment_limit = ss_segment_limit; segment_base = ss_segment_base; vector = EXCEPTION_SS; break; case SEGMENT_DS: DEBUG("DS:"); segment_limit = ds_segment_limit; segment_base = ds_segment_base; vector = EXCEPTION_GP; break; case SEGMENT_FS: DEBUG("FS:"); segment_limit = fs_segment_limit; segment_base = fs_segment_base; vector = EXCEPTION_GP; break; case SEGMENT_GS: DEBUG("GS:"); segment_limit = gs_segment_limit; segment_base = gs_segment_base; vector = EXCEPTION_GP; break; } DEBUG("0x%08x:", addr + segment_base); /* TODO: Add remaining checks */ if (addr > segment_limit - length + 1) { if (!real_mode()) { /* FIXME */ exception(vector, 0); } #if 0 fprintf(stderr, "WARNING: #GP(0) address=0x%08x segment=%d " "length=%u segment_base=0x%08x " "segment_gflag=%d segment_limt=0x%08x\n", addr, segment, length, segment_base, segment_gflag, segment_limit); #endif } return segment_base; } /******************************************************************************/ static uint8_t mrb_seg(uint32_t addr, int segment) { uint32_t base; uint8_t value; DEBUG("["); base = get_segment_base_and_check_limit(addr, segment, 1); value = mrb(addr + base, cs_dpl); DEBUG("0x%02x]", value); return value; } static uint16_t mrw_seg(uint32_t addr, int segment) { uint32_t base; uint16_t value; DEBUG("["); base = get_segment_base_and_check_limit(addr, segment, 2); value = mrw(addr + base, cs_dpl); DEBUG("0x%04x]", value); return value; } static uint32_t mrd_seg(uint32_t addr, int segment) { uint32_t base; uint32_t value; DEBUG("["); base = get_segment_base_and_check_limit(addr, segment, 4); value = mrd(addr + base, cs_dpl); DEBUG("0x%08x]", value); return value; } /******************************************************************************/ static void mwb_seg(uint32_t addr, uint8_t value, int segment) { uint32_t base; DEBUG("{"); base = get_segment_base_and_check_limit(addr, segment, 1); DEBUG("0x%02x}", value); mwb(addr + base, value, cs_dpl); } static void mww_seg(uint32_t addr, uint16_t value, int segment) { uint32_t base; DEBUG("{"); base = get_segment_base_and_check_limit(addr, segment, 2); DEBUG("0x%04x}", value); mww(addr + base, value, cs_dpl); } static void mwd_seg(uint32_t addr, uint32_t value, int segment) { uint32_t base; DEBUG("{"); base = get_segment_base_and_check_limit(addr, segment, 4); DEBUG("0x%08x}", value); mwd(addr + base, value, cs_dpl); } /****************************************************************************** * * LOCK and UNLOCK * ******************************************************************************/ static inline void lock(void) { /* TODO? */ } static inline void unlock(void) { /* TODO? */ } /****************************************************************************** * * EFLAGS Register Accessors * ******************************************************************************/ #define DEFINE_GET_EFLAG(FLAG, flag) \ static inline bool \ get_##FLAG(void) \ { \ return eflag_##flag; \ } DEFINE_GET_EFLAG(CF, cf) DEFINE_GET_EFLAG(PF, pf) DEFINE_GET_EFLAG(AF, af) DEFINE_GET_EFLAG(ZF, zf) DEFINE_GET_EFLAG(SF, sf) DEFINE_GET_EFLAG(TF, tf) DEFINE_GET_EFLAG(IF, if) DEFINE_GET_EFLAG(DF, df) DEFINE_GET_EFLAG(OF, of) DEFINE_GET_EFLAG(IOPL0, iopl0) DEFINE_GET_EFLAG(IOPL1, iopl1) DEFINE_GET_EFLAG(NT, nt) DEFINE_GET_EFLAG(RF, rf) DEFINE_GET_EFLAG(VM, vm) static inline uint8_t get_EFLAGS8(void) { uint8_t eflags; eflags = 0; eflags |= get_CF() << EFLAG_CF; eflags |= 1 << 1; eflags |= get_PF() << EFLAG_PF; /* eflags |= 0 << 3; */ eflags |= get_AF() << EFLAG_AF; /* eflags |= 0 << 5; */ eflags |= get_ZF() << EFLAG_ZF; eflags |= get_SF() << EFLAG_SF; return eflags; } static inline uint16_t get_EFLAGS16(void) { uint16_t eflags; eflags = 0; eflags |= get_EFLAGS8(); eflags |= get_TF() << EFLAG_TF; eflags |= get_IF() << EFLAG_IF; eflags |= get_DF() << EFLAG_DF; eflags |= get_OF() << EFLAG_OF; eflags |= get_IOPL0() << EFLAG_IOPL0; eflags |= get_IOPL1() << EFLAG_IOPL1; eflags |= get_NT() << EFLAG_NT; /* eflags |= 0 << 15; */ return eflags; } static inline uint32_t get_EFLAGS32(void) { uint32_t eflags; eflags = 0; eflags |= get_EFLAGS16(); eflags |= get_RF() << EFLAG_RF; eflags |= get_VM() << EFLAG_VM; return eflags; } static inline uint8_t get_IOPL(void) { return (get_IOPL1() << 1) | get_IOPL0(); } /******************************************************************************/ #define DEFINE_SSET_EFLAG(FLAG, flag) \ static inline void \ sset_##FLAG(bool value) \ { \ eflag_##flag##_new = !!value; \ } DEFINE_SSET_EFLAG(CF, cf) DEFINE_SSET_EFLAG(PF, pf) DEFINE_SSET_EFLAG(AF, af) DEFINE_SSET_EFLAG(ZF, zf) DEFINE_SSET_EFLAG(SF, sf) DEFINE_SSET_EFLAG(TF, tf) DEFINE_SSET_EFLAG(IF, if) DEFINE_SSET_EFLAG(DF, df) DEFINE_SSET_EFLAG(OF, of) DEFINE_SSET_EFLAG(IOPL0, iopl0) DEFINE_SSET_EFLAG(IOPL1, iopl1) DEFINE_SSET_EFLAG(NT, nt) DEFINE_SSET_EFLAG(RF, rf) DEFINE_SSET_EFLAG(VM, vm) static inline void sset_EFLAGS8(uint8_t eflags) { sset_CF((eflags >> EFLAG_CF) & 1); /* Reserved */ sset_PF((eflags >> EFLAG_PF) & 1); /* Reserved */ sset_AF((eflags >> EFLAG_AF) & 1); /* Reserved */ sset_ZF((eflags >> EFLAG_ZF) & 1); sset_SF((eflags >> EFLAG_SF) & 1); } static inline void sset_EFLAGS16(uint16_t eflags) { sset_EFLAGS8(eflags); sset_TF((eflags >> EFLAG_TF) & 1); sset_IF((eflags >> EFLAG_IF) & 1); sset_DF((eflags >> EFLAG_DF) & 1); sset_OF((eflags >> EFLAG_OF) & 1); sset_IOPL0((eflags >> EFLAG_IOPL0) & 1); sset_IOPL1((eflags >> EFLAG_IOPL1) & 1); sset_NT((eflags >> EFLAG_NT) & 1); /* Reserved */ } static inline void sset_EFLAGS32(uint32_t eflags) { sset_EFLAGS16(eflags); sset_RF((eflags >> EFLAG_RF) & 1); sset_VM((eflags >> EFLAG_VM) & 1); } /******************************************************************************/ #define DEFINE_COMMIT_EFLAG(FLAG, flag) \ static inline void \ commit_##FLAG(void) \ { \ eflag_##flag = eflag_##flag##_new; \ } DEFINE_COMMIT_EFLAG(CF, cf) DEFINE_COMMIT_EFLAG(PF, pf) DEFINE_COMMIT_EFLAG(AF, af) DEFINE_COMMIT_EFLAG(ZF, zf) DEFINE_COMMIT_EFLAG(SF, sf) DEFINE_COMMIT_EFLAG(TF, tf) DEFINE_COMMIT_EFLAG(IF, if) DEFINE_COMMIT_EFLAG(DF, df) DEFINE_COMMIT_EFLAG(OF, of) DEFINE_COMMIT_EFLAG(IOPL0, iopl0) DEFINE_COMMIT_EFLAG(IOPL1, iopl1) DEFINE_COMMIT_EFLAG(NT, nt) DEFINE_COMMIT_EFLAG(RF, rf) DEFINE_COMMIT_EFLAG(VM, vm) static inline void commit_EFLAGS8(void) { commit_CF(); commit_PF(); commit_AF(); commit_ZF(); commit_SF(); } static inline void commit_EFLAGS16(void) { commit_EFLAGS8(); commit_TF(); commit_IF(); commit_DF(); commit_OF(); commit_IOPL0(); commit_IOPL1(); commit_NT(); } static inline void commit_EFLAGS32(void) { commit_EFLAGS16(); commit_RF(); commit_VM(); } static inline void commit_OSZAP(void) { commit_OF(); commit_SF(); commit_ZF(); commit_AF(); commit_PF(); } static inline void commit_OSZAPC(void) { commit_OF(); commit_SF(); commit_ZF(); commit_AF(); commit_PF(); commit_CF(); } /****************************************************************************** * * Control Register Accessors * ******************************************************************************/ #define DEFINE_SET_CR(no, FLAG, flag) \ static inline void \ set_##FLAG(bool value) \ { \ cr##no##_##flag = !!value; \ } DEFINE_SET_CR(0, PE, pe) DEFINE_SET_CR(0, MP, mp) DEFINE_SET_CR(0, EM, em) DEFINE_SET_CR(0, TS, ts) DEFINE_SET_CR(0, ET, et) DEFINE_SET_CR(0, PG, pg) static inline void set_PFLA(uint32_t value) { cr2_pfla = value; } static inline void set_PDB(uint32_t value) { cr3_pdb = value & 0xfffff; /* bits 12-31 */ cpu_tlb_flush(); } static inline void set_CR0(uint32_t cr0) { set_PE((cr0 >> CR0_PE) & 1); set_MP((cr0 >> CR0_MP) & 1); set_EM((cr0 >> CR0_EM) & 1); set_TS((cr0 >> CR0_TS) & 1); set_ET((cr0 >> CR0_ET) & 1); set_PG((cr0 >> CR0_PG) & 1); } static inline void set_CR2(uint32_t cr2) { set_PFLA(cr2); } static inline void set_CR3(uint32_t cr3) { set_PDB((cr3 >> CR3_PDB) & 0xfffff); /* bits 12-31 */ } /******************************************************************************/ #define DEFINE_GET_CR(no, FLAG, flag) \ static inline bool \ get_##FLAG(void) \ { \ return cr##no##_##flag; \ } DEFINE_GET_CR(0, PE, pe) DEFINE_GET_CR(0, MP, mp) DEFINE_GET_CR(0, EM, em) DEFINE_GET_CR(0, TS, ts) DEFINE_GET_CR(0, ET, et) DEFINE_GET_CR(0, PG, pg) static inline uint32_t get_PFLA(void) { return cr2_pfla; } static inline uint32_t get_PDB(void) { return cr3_pdb; } static inline uint32_t get_CR0(void) { uint32_t cr0; cr0 = 0; cr0 |= get_PE() << CR0_PE; cr0 |= get_MP() << CR0_MP; cr0 |= get_EM() << CR0_EM; cr0 |= get_TS() << CR0_TS; cr0 |= get_ET() << CR0_ET; /* Reserved... */ cr0 |= get_PG() << CR0_PG; return cr0; } static inline uint32_t get_CR2(void) { return get_PFLA(); } static inline uint32_t get_CR3(void) { uint32_t cr3; cr3 = 0; /* Reserved... */ cr3 |= get_PDB() << CR3_PDB; return cr3; } /****************************************************************************** * * Effective Operand- and Address-Size Attributes * * D Flag in Code Segment Descriptor 0 0 0 0 1 1 1 1 * Operand-Size Prefix 0x66 N N Y Y N N Y Y * Address-Size Prefix 0x67 N Y N Y N Y N Y * Effective Operand Size 16 16 32 32 32 32 16 16 * Effective Address Size 16 32 16 32 32 16 32 16 * ******************************************************************************/ static inline bool operand_size_32(void) { return (cs_segment_dflag ^ prefix_operand_size_override); } static inline bool address_size_32(void) { return (cs_segment_dflag ^ prefix_address_size_override); } static inline bool stack_size_32(void) { return ss_segment_dflag; } /****************************************************************************** * * Fetch Immediate * ******************************************************************************/ static inline void fetch_immb(void) { instruction_immediate = mrb_cs(eip_new); eip_new += 1; } static inline void fetch_immw(void) { instruction_immediate = mrw_cs(eip_new); eip_new += 2; } static inline void fetch_immd(void) { instruction_immediate = mrd_cs(eip_new); eip_new += 4; } static inline void fetch_immv(bool size_32) { if (size_32) { fetch_immd(); } else { fetch_immw(); } } static inline void fetch_ptr(void) { if (operand_size_32()) { instruction_displacement = mrd_cs(eip_new); eip_new += 4; } else { instruction_displacement = mrw_cs(eip_new); eip_new += 2; } instruction_immediate = mrw_cs(eip_new); eip_new += 2; } /****************************************************************************** * * Fetch ModR/M * * Fetch the ModR/M byte and if required: 1 SIB byte and 1, 2 or 4 bytes * displacement. * * Mod/RM: * 7 6 5 4 3 2 1 0 * Mod Reg R/M * * SIB: * 7 6 5 4 3 2 1 0 * Scale Index Base * ******************************************************************************/ static inline void fetch_modrm(void) { uint8_t modrm; modrm = mrb_cs(eip_new); eip_new += 1; instruction_mod = (modrm >> 6) & 3; instruction_reg = (modrm >> 3) & 7; instruction_rm = modrm & 7; if (address_size_32() && instruction_mod != 3 && instruction_rm == 4) { uint8_t sib; sib = mrb_cs(eip_new); eip_new += 1; instruction_scale = (sib >> 6) & 3; instruction_index = (sib >> 3) & 7; instruction_base = sib & 7; } else { instruction_scale = 0; instruction_index = 0; instruction_base = 0; } if (instruction_mod == 1) { instruction_displacement = mrb_cs(eip_new); eip_new += 1; } else { instruction_displacement = 0; if (address_size_32()) { switch (instruction_mod) { case 0: if ((instruction_rm != 5) && (instruction_base != 5)) { break; } case 2: instruction_displacement = mrd_cs(eip_new); eip_new += 4; break; default: break; } } else { switch (instruction_mod) { case 0: if (instruction_rm != 6) { break; } case 2: instruction_displacement = mrw_cs(eip_new); eip_new += 2; break; default: break; } } } } /****************************************************************************** * * Get Instruction * * ******************************************************************************/ static inline uint32_t get_instruction_mod(void) { DEBUG("", instruction_mod); return instruction_mod; } static inline uint32_t get_instruction_reg(void) { DEBUG("", instruction_reg); return instruction_reg; } static inline uint32_t get_instruction_rm(void) { DEBUG("", instruction_rm); return instruction_rm; } static inline uint32_t get_instruction_scale(void) { DEBUG("", instruction_scale); return instruction_scale; } static inline uint32_t get_instruction_index(void) { DEBUG("", instruction_index); return instruction_index; } static inline uint32_t get_instruction_base(void) { DEBUG("", instruction_base); return instruction_base; } static inline uint32_t get_instruction_displacement(void) { DEBUG("", instruction_displacement); return instruction_displacement; } static inline uint32_t get_instruction_immediate(void) { DEBUG("", instruction_immediate); return instruction_immediate; } /****************************************************************************** * * Get * ******************************************************************************/ static inline uint8_t get_CPL(void) { return cs_dpl; } static inline uint32_t get_CS(void) { DEBUG_GET("[CS:0x%04x]", cs_selector); return cs_selector; } static inline uint32_t get_SS(void) { DEBUG_GET("[SS:0x%04x]", ss_selector); return ss_selector; } static inline uint32_t get_DS(void) { DEBUG_GET("[DS:0x%04x]", ds_selector); return ds_selector; } static inline uint32_t get_ES(void) { DEBUG_GET("[ES:0x%04x]", es_selector); return es_selector; } static inline uint32_t get_FS(void) { DEBUG_GET("[FS:0x%04x]", fs_selector); return fs_selector; } static inline uint32_t get_GS(void) { DEBUG_GET("[GS:0x%04x]", gs_selector); return gs_selector; } /******************************************************************************/ static inline uint32_t get_AL(void) { DEBUG_GET("[AL:0x%02x]", eax & 0xff); return eax & 0xff; } static inline uint32_t get_CL(void) { DEBUG_GET("[CL:0x%02x]", ecx & 0xff); return ecx & 0xff; } static inline uint32_t get_DL(void) { DEBUG_GET("[DL:0x%02x]", edx & 0xff); return edx & 0xff; } static inline uint32_t get_BL(void) { DEBUG_GET("[BL:0x%02x]", ebx & 0xff); return ebx & 0xff; } /******************************************************************************/ static inline uint32_t get_AH(void) { DEBUG_GET("[AH:0x%02x]", (eax >> 8) & 0xff); return (eax >> 8) & 0xff; } static inline uint32_t get_CH(void) { DEBUG_GET("[CH:0x%02x]", (ecx >> 8) & 0xff); return (ecx >> 8) & 0xff; } static inline uint32_t get_DH(void) { DEBUG_GET("[DH:0x%02x]", (edx >> 8) & 0xff); return (edx >> 8) & 0xff; } static inline uint32_t get_BH(void) { DEBUG_GET("[BH:0x%02x]", (ebx >> 8) & 0xff); return (ebx >> 8) & 0xff; } /******************************************************************************/ static inline uint32_t get_AX(void) { DEBUG_GET("[AX:0x%04x]", eax & 0xffff); return eax & 0xffff; } static inline uint32_t get_CX(void) { DEBUG_GET("[CX:0x%04x]", ecx & 0xffff); return ecx & 0xffff; } static inline uint32_t get_DX(void) { DEBUG_GET("[DX:0x%04x]", edx & 0xffff); return edx & 0xffff; } static inline uint32_t get_BX(void) { DEBUG_GET("[BX:0x%04x]", ebx & 0xffff); return ebx & 0xffff; } /******************************************************************************/ static inline uint32_t get_SP(void) { DEBUG_GET("[SP:0x%04x]", esp & 0xffff); return esp & 0xffff; } static inline uint32_t get_BP(void) { DEBUG_GET("[BP:0x%04x]", ebp & 0xffff); return ebp & 0xffff; } static inline uint32_t get_SI(void) { DEBUG_GET("[SI:0x%04x]", esi & 0xffff); return esi & 0xffff; } static inline uint32_t get_DI(void) { DEBUG_GET("[DI:0x%04x]", edi & 0xffff); return edi & 0xffff; } /******************************************************************************/ static inline uint32_t get_EAX(void) { DEBUG_GET("[EAX:0x%08x]", eax); return eax; } static inline uint32_t get_ECX(void) { DEBUG_GET("[ECX:0x%08x]", ecx); return ecx; } static inline uint32_t get_EDX(void) { DEBUG_GET("[EDX:0x%08x]", edx); return edx; } static inline uint32_t get_EBX(void) { DEBUG_GET("[EBX:0x%08x]", ebx); return ebx; } /******************************************************************************/ static inline uint32_t get_ESP(void) { DEBUG_GET("[ESP:0x%08x]", esp); return esp; } static inline uint32_t get_EBP(void) { DEBUG_GET("[EBP:0x%08x]", ebp); return ebp; } static inline uint32_t get_ESI(void) { DEBUG_GET("[ESI:0x%08x]", esi); return esi; } static inline uint32_t get_EDI(void) { DEBUG_GET("[EDI:0x%08x]", edi); return edi; } /******************************************************************************/ static inline uint32_t get_eAX(void) { if (operand_size_32()) { return get_EAX(); } else { return get_AX(); } } static inline uint32_t get_eCX(void) { if (operand_size_32()) { return get_ECX(); } else { return get_CX(); } } static inline uint32_t get_eDX(void) { if (operand_size_32()) { return get_EDX(); } else { return get_DX(); } } static inline uint32_t get_eBX(void) { if (operand_size_32()) { return get_EBX(); } else { return get_BX(); } } /******************************************************************************/ static inline uint32_t get_eSP(void) { if (operand_size_32()) { return get_ESP(); } else { return get_SP(); } } static inline uint32_t get_eBP(void) { if (operand_size_32()) { return get_EBP(); } else { return get_BP(); } } static inline uint32_t get_eSI(void) { if (operand_size_32()) { return get_ESI(); } else { return get_SI(); } } static inline uint32_t get_eDI(void) { if (operand_size_32()) { return get_EDI(); } else { return get_DI(); } } /******************************************************************************/ static inline int get_segment_overwritten(int segment) { if (prefix_segment_override == SEGMENT_NONE) { return segment; } else { return prefix_segment_override; } } /******************************************************************************/ static inline uint32_t get_address_sib(void) { uint32_t addr = 0; switch (get_instruction_index()) { default: DEBUG_ERROR_SWITCH(); case 0: addr += get_EAX(); break; case 1: addr += get_ECX(); break; case 2: addr += get_EDX(); break; case 3: addr += get_EBX(); break; case 4: break; case 5: addr += get_EBP(); break; case 6: addr += get_ESI(); break; case 7: addr += get_EDI(); break; } switch (get_instruction_scale()) { default: DEBUG_ERROR_SWITCH(); case 0: break; case 1: addr *= 2; break; case 2: addr *= 4; break; case 3: addr *= 8; break; } switch (get_instruction_base()) { default: DEBUG_ERROR_SWITCH(); case 0: addr += get_EAX(); break; case 1: addr += get_ECX(); break; case 2: addr += get_EDX(); break; case 3: addr += get_EBX(); break; case 4: addr += get_ESP(); break; case 5: if (get_instruction_mod() == 0) { addr += get_instruction_displacement(); } else { addr += get_EBP(); } break; case 6: addr += get_ESI(); break; case 7: addr += get_EDI(); break; } DEBUG("", addr); return addr; } static inline int get_segment_sib(void) { switch (get_instruction_base()) { default: DEBUG_ERROR_SWITCH(); case 0: return SEGMENT_DS; case 1: return SEGMENT_DS; case 2: return SEGMENT_DS; case 3: return SEGMENT_DS; case 4: return SEGMENT_SS; case 5: if (get_instruction_mod() == 0) { return SEGMENT_DS; } else { return SEGMENT_SS; } case 6: return SEGMENT_DS; case 7: return SEGMENT_DS; } } /******************************************************************************/ static inline uint32_t get_address_mod0(void) { uint32_t addr = 0; if (address_size_32()) { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: addr += get_EAX(); break; case 1: addr += get_ECX(); break; case 2: addr += get_EDX(); break; case 3: addr += get_EBX(); break; case 4: addr += get_address_sib(); break; case 5: addr += get_instruction_displacement(); break; case 6: addr += get_ESI(); break; case 7: addr += get_EDI(); break; } } else { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: addr += get_BX() + get_SI(); break; case 1: addr += get_BX() + get_DI(); break; case 2: addr += get_BP() + get_SI(); break; case 3: addr += get_BP() + get_DI(); break; case 4: addr += get_SI(); break; case 5: addr += get_DI(); break; case 6: addr += get_instruction_displacement(); break; case 7: addr += get_BX(); break; } addr &= 0xffff; } DEBUG("", addr); return addr; } static inline int get_segment_mod0(void) { if (address_size_32()) { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: return SEGMENT_DS; case 1: return SEGMENT_DS; case 2: return SEGMENT_DS; case 3: return SEGMENT_DS; case 4: return get_segment_sib(); case 5: return SEGMENT_DS; case 6: return SEGMENT_DS; case 7: return SEGMENT_DS; } } else { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: return SEGMENT_DS; case 1: return SEGMENT_DS; case 2: return SEGMENT_SS; case 3: return SEGMENT_SS; case 4: return SEGMENT_DS; case 5: return SEGMENT_DS; case 6: return SEGMENT_DS; case 7: return SEGMENT_DS; } } } /******************************************************************************/ static inline uint32_t get_address_mod1(void) { uint32_t addr = 0; addr += (int8_t) get_instruction_displacement(); if (address_size_32()) { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: addr += get_EAX(); break; case 1: addr += get_ECX(); break; case 2: addr += get_EDX(); break; case 3: addr += get_EBX(); break; case 4: addr += get_address_sib(); break; case 5: addr += get_EBP(); break; case 6: addr += get_ESI(); break; case 7: addr += get_EDI(); break; } } else { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: addr += get_BX() + get_SI(); break; case 1: addr += get_BX() + get_DI(); break; case 2: addr += get_BP() + get_SI(); break; case 3: addr += get_BP() + get_DI(); break; case 4: addr += get_SI(); break; case 5: addr += get_DI(); break; case 6: addr += get_BP(); break; case 7: addr += get_BX(); break; } addr &= 0xffff; } DEBUG("", addr); return addr; } static inline int get_segment_mod1(void) { if (address_size_32()) { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: return SEGMENT_DS; case 1: return SEGMENT_DS; case 2: return SEGMENT_DS; case 3: return SEGMENT_DS; case 4: return get_segment_sib(); case 5: return SEGMENT_SS; case 6: return SEGMENT_DS; case 7: return SEGMENT_DS; } } else { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: return SEGMENT_DS; case 1: return SEGMENT_DS; case 2: return SEGMENT_SS; case 3: return SEGMENT_SS; case 4: return SEGMENT_DS; case 5: return SEGMENT_DS; case 6: return SEGMENT_SS; case 7: return SEGMENT_DS; } } } /******************************************************************************/ static inline uint32_t get_address_mod2(void) { uint32_t addr = 0; addr += get_instruction_displacement(); if (address_size_32()) { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: addr += get_EAX(); break; case 1: addr += get_ECX(); break; case 2: addr += get_EDX(); break; case 3: addr += get_EBX(); break; case 4: addr += get_address_sib(); break; case 5: addr += get_EBP(); break; case 6: addr += get_ESI(); break; case 7: addr += get_EDI(); break; } } else { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: addr += get_BX() + get_SI(); break; case 1: addr += get_BX() + get_DI(); break; case 2: addr += get_BP() + get_SI(); break; case 3: addr += get_BP() + get_DI(); break; case 4: addr += get_SI(); break; case 5: addr += get_DI(); break; case 6: addr += get_BP(); break; case 7: addr += get_BX(); break; } addr &= 0xffff; } DEBUG("", addr); return addr; } static inline int get_segment_mod2(void) { if (address_size_32()) { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: return SEGMENT_DS; case 1: return SEGMENT_DS; case 2: return SEGMENT_DS; case 3: return SEGMENT_DS; case 4: return get_segment_sib(); case 5: return SEGMENT_SS; case 6: return SEGMENT_DS; case 7: return SEGMENT_DS; } } else { switch (get_instruction_rm()) { default: DEBUG_ERROR_SWITCH(); case 0: return SEGMENT_DS; case 1: return SEGMENT_DS; case 2: return SEGMENT_SS; case 3: return SEGMENT_SS; case 4: return SEGMENT_DS; case 5: return SEGMENT_DS; case 6: return SEGMENT_SS; case 7: return SEGMENT_DS; } } } /******************************************************************************/ static inline uint32_t get_Rb(uint32_t reg) { switch (reg) { default: DEBUG_ERROR_SWITCH(); case 0: return get_AL(); case 1: return get_CL(); case 2: return get_DL(); case 3: return get_BL(); case 4: return get_AH(); case 5: return get_CH(); case 6: return get_DH(); case 7: return get_BH(); } } static inline uint32_t get_Rw(uint32_t reg) { switch (reg) { default: DEBUG_ERROR_SWITCH(); case 0: return get_AX(); case 1: return get_CX(); case 2: return get_DX(); case 3: return get_BX(); case 4: return get_SP(); case 5: return get_BP(); case 6: return get_SI(); case 7: return get_DI(); } } static inline uint32_t get_Rd(uint32_t reg) { switch (reg) { default: DEBUG_ERROR_SWITCH(); case 0: return get_EAX(); case 1: return get_ECX(); case 2: return get_EDX(); case 3: return get_EBX(); case 4: return get_ESP(); case 5: return get_EBP(); case 6: return get_ESI(); case 7: return get_EDI(); } } /******************************************************************************/ static inline uint32_t get_Cd(void) { switch (get_instruction_reg()) { default: DEBUG_ERROR_SWITCH(); case 0: return get_CR0(); case 1: ERROR_NYI(); /* FIXME: Reserved */ case 2: return get_CR2(); case 3: return get_CR3(); case 4: case 5: case 6: case 7: ERROR_NYI(); /* FIXME: Reserved */ return 0; } } /******************************************************************************/ static inline uint32_t get_Gb(void) { return get_Rb(get_instruction_reg()); } static inline uint32_t get_Gw(void) { return get_Rw(get_instruction_reg()); } static inline uint32_t get_Gd(void) { return get_Rd(get_instruction_reg()); } static inline uint32_t get_Gv(void) { if (operand_size_32()) { return get_Gd(); } else { return get_Gw(); } } /******************************************************************************/ static inline uint32_t get_Eb(void) { switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: return mrb_seg(get_address_mod0(), get_segment_overwritten(get_segment_mod0())); case 1: return mrb_seg(get_address_mod1(), get_segment_overwritten(get_segment_mod1())); case 2: return mrb_seg(get_address_mod2(), get_segment_overwritten(get_segment_mod2())); case 3: return get_Rb(get_instruction_rm()); } } static inline uint32_t get_Ew(void) { switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: return mrw_seg(get_address_mod0(), get_segment_overwritten(get_segment_mod0())); case 1: return mrw_seg(get_address_mod1(), get_segment_overwritten(get_segment_mod1())); case 2: return mrw_seg(get_address_mod2(), get_segment_overwritten(get_segment_mod2())); case 3: return get_Rw(get_instruction_rm()); } } static inline uint32_t get_Ed(void) { switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: return mrd_seg(get_address_mod0(), get_segment_overwritten(get_segment_mod0())); case 1: return mrd_seg(get_address_mod1(), get_segment_overwritten(get_segment_mod1())); case 2: return mrd_seg(get_address_mod2(), get_segment_overwritten(get_segment_mod2())); case 3: return get_Rd(get_instruction_rm()); } } static inline uint32_t get_Ev(void) { if (operand_size_32()) { return get_Ed(); } else { return get_Ew(); } } /******************************************************************************/ static inline uint32_t get_EwBIT(void) { int32_t offset; offset = ((int16_t) (get_Rw(get_instruction_reg()) & 0xfff0)) / 16; switch(get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: return mrw_seg(get_address_mod0() + 2 * offset, get_segment_overwritten(get_segment_mod0())); case 1: return mrw_seg(get_address_mod1() + 2 * offset, get_segment_overwritten(get_segment_mod1())); case 2: return mrw_seg(get_address_mod2() + 2 * offset, get_segment_overwritten(get_segment_mod2())); case 3: return get_Rw(get_instruction_rm()); } } static inline uint32_t get_EdBIT(void) { int32_t offset; offset = ((int32_t) (get_Rd(get_instruction_reg()) & 0xffffffe0)) / 32; switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: return mrd_seg(get_address_mod0() + 4 * offset, get_segment_overwritten(get_segment_mod0())); case 1: return mrd_seg(get_address_mod1() + 4 * offset, get_segment_overwritten(get_segment_mod1())); case 2: return mrd_seg(get_address_mod2() + 4 * offset, get_segment_overwritten(get_segment_mod2())); case 3: return get_Rd(get_instruction_rm()); } } static inline uint32_t get_EvBIT(void) { if (operand_size_32()) { return get_EdBIT(); } else { return get_EwBIT(); } } static inline uint32_t get_effective_address(void) { switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: return get_address_mod0(); case 1: return get_address_mod1(); case 2: return get_address_mod2(); case 3: exception(EXCEPTION_UD, -1); } } /******************************************************************************/ static inline uint32_t get_Sw(void) { switch (get_instruction_reg()) { default: DEBUG_ERROR_SWITCH(); case SEGMENT_ES: return get_ES(); case SEGMENT_CS: return get_CS(); case SEGMENT_SS: return get_SS(); case SEGMENT_DS: return get_DS(); case SEGMENT_FS: return get_FS(); case SEGMENT_GS: return get_GS(); case 6: exception(EXCEPTION_UD, -1); case 7: exception(EXCEPTION_UD, -1); } } /****************************************************************************** * * Get Immediates * ******************************************************************************/ static inline uint32_t get_Ib(void) { return get_instruction_immediate() & 0xff; } static inline uint32_t get_IbSE(void) { if (operand_size_32()) { return (uint32_t) (int8_t) (get_instruction_immediate() & 0xff); } else { return (uint16_t) (int8_t) (get_instruction_immediate() & 0xff); } } static inline uint32_t get_Iw(void) { return get_instruction_immediate() & 0xffff; } static inline uint32_t get_Id(void) { return get_instruction_immediate(); } static inline uint32_t get_Iv(void) { if (operand_size_32()) { return get_Id(); } else { return get_Iw(); } } /******************************************************************************/ static inline int32_t get_Jb(void) { return (int8_t) get_instruction_immediate(); } static inline int32_t get_Jw(void) { return (int16_t) get_instruction_immediate(); } static inline int32_t get_Jd(void) { return (int32_t) get_instruction_immediate(); } static inline int32_t get_Jv(void) { if (operand_size_32()) { return get_Jd(); } else { return get_Jw(); } } /******************************************************************************/ static inline uint32_t get_Ob(void) { if (address_size_32()) { return mrb_seg(get_Id(), get_segment_overwritten(SEGMENT_DS)); } else { return mrb_seg(get_Iw(), get_segment_overwritten(SEGMENT_DS)); } } static inline uint32_t get_Ow(void) { if (address_size_32()) { return mrw_seg(get_Id(), get_segment_overwritten(SEGMENT_DS)); } else { return mrw_seg(get_Iw(), get_segment_overwritten(SEGMENT_DS)); } } static inline uint32_t get_Od(void) { if (address_size_32()) { return mrd_seg(get_Id(), get_segment_overwritten(SEGMENT_DS)); } else { return mrd_seg(get_Iw(), get_segment_overwritten(SEGMENT_DS)); } } static inline uint32_t get_Ov(void) { if (operand_size_32()) { return get_Od(); } else { return get_Ow(); } } /****************************************************************************** * * Get Memory addressed by the DS:eSI register pair * ******************************************************************************/ static inline uint32_t get_Xb(void) { if (address_size_32()) { return mrb_seg(get_ESI(), get_segment_overwritten(SEGMENT_DS)); } else { return mrb_seg(get_SI(), get_segment_overwritten(SEGMENT_DS)); } } static inline uint32_t get_Xw(void) { if (address_size_32()) { return mrw_seg(get_ESI(), get_segment_overwritten(SEGMENT_DS)); } else { return mrw_seg(get_SI(), get_segment_overwritten(SEGMENT_DS)); } } static inline uint32_t get_Xd(void) { if (address_size_32()) { return mrd_seg(get_ESI(), get_segment_overwritten(SEGMENT_DS)); } else { return mrd_seg(get_SI(), get_segment_overwritten(SEGMENT_DS)); } } /****************************************************************************** * * Get Memory addressed by the ES:eDI register pair * ******************************************************************************/ static inline uint32_t get_Yb(void) { if (address_size_32()) { return mrb_seg(get_EDI(), SEGMENT_ES); } else { return mrb_seg(get_DI(), SEGMENT_ES); } } static inline uint32_t get_Yw(void) { if (address_size_32()) { return mrw_seg(get_EDI(), SEGMENT_ES); } else { return mrw_seg(get_DI(), SEGMENT_ES); } } static inline uint32_t get_Yd(void) { if (address_size_32()) { return mrd_seg(get_EDI(), SEGMENT_ES); } else { return mrd_seg(get_DI(), SEGMENT_ES); } } /****************************************************************************** * * Load * ******************************************************************************/ #define DEBUG_OPERAND_B(str) \ DEBUG(" %s:0x%02x", str, (uint8_t) t1) #define DEBUG_OPERAND_W(str) \ DEBUG(" %s:0x%04x", str, (uint16_t) t1) #define DEBUG_OPERAND_D(str) \ DEBUG(" %s:0x%08x", str, (uint32_t) t1) #define DEBUG_OPERAND_V(str) \ if (operand_size_32()) { \ DEBUG_OPERAND_D(str); \ } else { \ DEBUG_OPERAND_W(str); \ } #define DEBUG_OPERAND_BB(str) \ DEBUG(" %s:0x%02x,0x%02x", str, (uint8_t) t1, (uint8_t) t2) #define DEBUG_OPERAND_WW(str) \ DEBUG(" %s:0x%04x,0x%04x", str, (uint16_t) t1, (uint16_t) t2) #define DEBUG_OPERAND_DD(str) \ DEBUG(" %s:0x%08x,0x%08x", str, (uint32_t) t1 ,(uint32_t) t2) #define DEBUG_OPERAND_VV(str) \ if (operand_size_32()) { \ DEBUG_OPERAND_DD(str); \ } else { \ DEBUG_OPERAND_WW(str); \ } #define DEBUG_OPERAND_WB(str) \ DEBUG(" %s:0x%04x,0x%02x", str, (uint16_t) t1, (uint8_t) t2) #define DEBUG_OPERAND_WD(str) \ DEBUG(" %s:0x%04x,0x%08x", str, (uint16_t) t1, (uint32_t) t2) #define DEBUG_OPERAND_WV(str) \ if (operand_size_32()) { \ DEBUG_OPERAND_WD(str); \ } else { \ DEBUG_OPERAND_WW(str); \ } #define DEBUG_OPERAND_DB(str) \ DEBUG(" %s:0x%08x,0x%02x", str, (uint32_t) t1, (uint8_t) t2) #define DEBUG_OPERAND_WB(str) \ DEBUG(" %s:0x%04x,0x%02x", str, (uint16_t) t1, (uint8_t) t2) #define DEBUG_OPERAND_VB(str) \ if (operand_size_32()) { \ DEBUG_OPERAND_DB(str); \ } else { \ DEBUG_OPERAND_WB(str); \ } #define DEBUG_OPERAND_BD(str) \ DEBUG(" %s:0x%02x,0x%08x", str, (uint8_t) t1, (uint32_t) t2) #define DEBUG_OPERAND_BW(str) \ DEBUG(" %s:0x%02x,0x%04x", str, (uint16_t) t1, (uint32_t) t2) #define DEBUG_OPERAND_BV(str) \ if (operand_size_32()) { \ DEBUG_OPERAND_BD(str); \ } else { \ DEBUG_OPERAND_BW(str); \ } static inline void load_CS(void) { t1 = get_CS(); DEBUG_OPERAND_W("CS"); } static inline void load_SS(void) { t1 = get_SS(); DEBUG_OPERAND_W("SS"); } static inline void load_DS(void) { t1 = get_DS(); DEBUG_OPERAND_W("DS"); } static inline void load_ES(void) { t1 = get_ES(); DEBUG_OPERAND_W("ES"); } static inline void load_FS(void) { t1 = get_FS(); DEBUG_OPERAND_W("FS"); } static inline void load_GS(void) { t1 = get_GS(); DEBUG_OPERAND_W("GS"); } /******************************************************************************/ static inline void load_AL(void) { t1 = get_AL(); DEBUG_OPERAND_B("AL"); } /******************************************************************************/ static inline void load_eAX(void) { t1 = get_eAX(); DEBUG_OPERAND_V("eAX"); } static inline void load_eCX(void) { t1 = get_eCX(); DEBUG_OPERAND_V("eCX"); } static inline void load_eDX(void) { t1 = get_eDX(); DEBUG_OPERAND_V("eDX"); } static inline void load_eBX(void) { t1 = get_eBX(); DEBUG_OPERAND_V("eBX"); } /******************************************************************************/ static inline void load_eSP(void) { t1 = get_eSP(); DEBUG_OPERAND_V("eSP"); } static inline void load_eBP(void) { t1 = get_eBP(); DEBUG_OPERAND_V("eBP"); } static inline void load_eSI(void) { t1 = get_eSI(); DEBUG_OPERAND_V("eSI"); } static inline void load_eDI(void) { t1 = get_eDI(); DEBUG_OPERAND_V("eDI"); } /******************************************************************************/ static inline void load_Cd(void) { t1 = get_Cd(); DEBUG_OPERAND_V("Cd"); } static inline void load_Rd(void) { t1 = get_Rd(get_instruction_rm()); DEBUG_OPERAND_V("Rd"); } /******************************************************************************/ static inline void load_0(void) { t1 = 0; } static inline void load_Ib(void) { t1 = get_Ib(); DEBUG_OPERAND_B("Ib"); } static inline void load_IbSE(void) { t1 = get_IbSE(); DEBUG_OPERAND_B("IbSE"); } static inline void load_Iw(void) { t1 = get_Iw(); DEBUG_OPERAND_W("Iw"); } static inline void load_Iv(void) { t1 = get_Iv(); DEBUG_OPERAND_V("Iv"); } static inline void load_AL_Ib(void) { t1 = get_AL(); DEBUG_GET(","); t2 = get_Ib(); DEBUG_OPERAND_BB("AL,Ib"); } static inline void load_eAX_Iv(void) { t1 = get_eAX(); DEBUG_GET(","); t2 = get_Iv(); DEBUG_OPERAND_VV("eAX,Iv"); } static inline void load_Ib_AL(void) { t1 = get_Ib(); DEBUG_GET(","); t2 = get_AL(); DEBUG_OPERAND_BB("Ib,AL"); } static inline void load_Ib_eAX(void) { t1 = get_Ib(); DEBUG_GET(","); t2 = get_eAX(); DEBUG_OPERAND_BV("Ib,eAX"); } /******************************************************************************/ static inline void load_eAX_eCX(void) { t1 = get_eAX(); DEBUG_GET(","); t2 = get_eCX(); DEBUG_OPERAND_VV("eAX,eCX"); } static inline void load_eAX_eDX(void) { t1 = get_eAX(); DEBUG_GET(","); t2 = get_eDX(); DEBUG_OPERAND_VV("eAX,eDX"); } static inline void load_eAX_eBX(void) { t1 = get_eAX(); DEBUG_GET(","); t2 = get_eBX(); DEBUG_OPERAND_VV("eAX,eBX"); } static inline void load_eAX_eSP(void) { t1 = get_eAX(); DEBUG_GET(","); t2 = get_eSP(); DEBUG_OPERAND_VV("eAX,eSP"); } static inline void load_eAX_eBP(void) { t1 = get_eAX(); DEBUG_GET(","); t2 = get_eBP(); DEBUG_OPERAND_VV("eAX,eBP"); } static inline void load_eAX_eSI(void) { t1 = get_eAX(); DEBUG_GET(","); t2 = get_eSI(); DEBUG_OPERAND_VV("eAX,eSI"); } static inline void load_eAX_eDI(void) { t1 = get_eAX(); DEBUG_GET(","); t2 = get_eDI(); DEBUG_OPERAND_VV("eAX,eDI"); } /******************************************************************************/ static inline void load_DX(void) { t1 = get_DX(); DEBUG_OPERAND_W("DX"); } static inline void load_DX_AL(void) { t1 = get_DX(); DEBUG_GET(","); t2 = get_AL(); DEBUG_OPERAND_WB("DX,AL"); } static inline void load_DX_eAX(void) { t1 = get_DX(); DEBUG_GET(","); t2 = get_eAX(); DEBUG_OPERAND_WV("DX,eAX"); } /******************************************************************************/ static inline void load_Eb_Gb(void) { t1 = get_Eb(); DEBUG_GET(","); t2 = get_Gb(); DEBUG_OPERAND_BB("Eb,Gb"); } static inline void load_Ev_Gv(void) { t1 = get_Ev(); DEBUG_GET(","); t2 = get_Gv(); DEBUG_OPERAND_VV("Ev,Gv"); } static inline void load_Ev_Gv_Ib(void) { t1 = get_Ev(); DEBUG_GET(","); t2 = get_Gv(); DEBUG_GET(","); t3 = get_Ib(); } static inline void load_Ev_Gv_CL(void) { t1 = get_Ev(); DEBUG_GET(","); t2 = get_Gv(); DEBUG_GET(","); t3 = get_CL(); } static inline void load_EvBIT_Gv(void) { t1 = get_EvBIT(); DEBUG_GET(","); t2 = get_Gv(); DEBUG_OPERAND_VV("EvBIT,Gv"); } static inline void load_Eb_Ib(void) { t1 = get_Eb(); DEBUG_GET(","); t2 = get_Ib(); DEBUG_OPERAND_BB("Eb,Ib"); } static inline void load_Eb_1(void) { t1 = get_Eb(); DEBUG_GET(","); t2 = 1; DEBUG_OPERAND_BB("Eb,1"); } static inline void load_Ev_1(void) { t1 = get_Ev(); DEBUG_GET(","); t2 = 1; DEBUG_OPERAND_VB("Ev,1"); } static inline void load_Eb_CL(void) { t1 = get_Eb(); DEBUG_GET(","); t2 = get_CL(); DEBUG_OPERAND_BB("Eb,CL"); } static inline void load_Ev_CL(void) { t1 = get_Ev(); DEBUG_GET(","); t2 = get_CL(); DEBUG_OPERAND_VB("Ev,CL"); } /******************************************************************************/ static inline void load_Ev_Iv(void) { t1 = get_Ev(); DEBUG_GET(","); t2 = get_Iv(); DEBUG_OPERAND_VV("Ev,Iv"); } static inline void load_Ev_Ib(void) { t1 = get_Ev(); DEBUG_GET(","); t2 = get_Ib(); DEBUG_OPERAND_VB("Ev,Ib"); } static inline void load_Ev_IbSE(void) { t1 = get_Ev(); DEBUG_GET(","); t2 = get_IbSE(); DEBUG_OPERAND_VV("Ev,IbSE"); } static inline void load_Eb(void) { t1 = get_Eb(); DEBUG_OPERAND_B("Eb"); } static inline void load_Ew(void) { t1 = get_Ew(); DEBUG_OPERAND_W("Ew"); } static inline void load_Ev(void) { t1 = get_Ev(); DEBUG_OPERAND_V("Ev"); } static inline void load_Gb(void) { t1 = get_Gb(); DEBUG_OPERAND_B("Gb"); } static inline void load_Gv(void) { t1 = get_Gv(); DEBUG_OPERAND_V("Gv"); } /******************************************************************************/ static inline void load_Gb_Eb(void) { t1 = get_Gb(); DEBUG_GET(","); t2 = get_Eb(); DEBUG_OPERAND_BB("Gb,Eb"); } static inline void load_Gv_Ev(void) { t1 = get_Gv(); DEBUG_GET(","); t2 = get_Ev(); DEBUG_OPERAND_VV("Gv,Ev"); } /******************************************************************************/ static inline void load_Sw(void) { t1 = get_Sw(); DEBUG_OPERAND_W("Sw"); } static inline void load_Ob(void) { t1 = get_Ob(); DEBUG_OPERAND_B("Ob"); } static inline void load_Ov(void) { t1 = get_Ov(); DEBUG_OPERAND_V("Ov"); } static inline void load_Ap(void) { t1 = get_instruction_displacement(); t2 = get_instruction_immediate(); DEBUG_OPERAND_WV("Ap"); } /******************************************************************************/ static inline void load_Jb(void) { tj = get_Jb(); /* TODO: debug */ } static inline void load_Jv(void) { tj = get_Jv(); /* TODO: debug */ } /******************************************************************************/ static inline void load_effective_address(void) { t1 = get_effective_address(); /* TODO: debug */ } static inline void load_Ms(void) { uint32_t addr; int segment; switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: addr = get_address_mod0(); segment = get_segment_mod0(); break; case 1: addr = get_address_mod1(); segment = get_segment_mod1(); break; case 2: addr = get_address_mod2(); segment = get_segment_mod2(); break; case 3: exception(EXCEPTION_UD, -1); } segment = get_segment_overwritten(segment); t1 = mrw_seg(addr + 0, segment); /* limit */ t2 = mrd_seg(addr + 2, segment); /* base */ } static inline void load_Mp(void) { uint32_t addr; int segment; switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: addr = get_address_mod0(); segment = get_segment_mod0(); break; case 1: addr = get_address_mod1(); segment = get_segment_mod1(); break; case 2: addr = get_address_mod2(); segment = get_segment_mod2(); break; case 3: exception(EXCEPTION_UD, -1); } segment = get_segment_overwritten(segment); if (operand_size_32()) { t1 = mrd_seg(addr + 0, segment); /* register */ t2 = mrw_seg(addr + 4, segment); /* segment selector */ } else { t1 = mrw_seg(addr + 0, segment); /* register */ t2 = mrw_seg(addr + 2, segment); /* segment selector */ } } static inline void load_Ep(void) { load_Mp(); } /****************************************************************************** * * Load Memory addressed by the ES:eDI and DS:eSI register pair * ******************************************************************************/ static inline void load_Xb(void) { t1 = get_Xb(); } static inline void load_Xw(void) { t1 = get_Xw(); } static inline void load_Xd(void) { t1 = get_Xd(); } static inline void load_DX_Xb(void) { t1 = get_DX(); t2 = get_Xb(); } static inline void load_DX_Xw(void) { t1 = get_DX(); t2 = get_Xw(); } static inline void load_DX_Xd(void) { t1 = get_DX(); t2 = get_Xd(); } static inline void load_AL_Yb(void) { t1 = get_AL(); t2 = get_Yb(); } static inline void load_AX_Yw(void) { t1 = get_AX(); t2 = get_Yw(); } static inline void load_EAX_Yd(void) { t1 = get_EAX(); t2 = get_Yd(); } static inline void load_Xb_Yb(void) { t1 = get_Xb(); t2 = get_Yb(); } static inline void load_Xw_Yw(void) { t1 = get_Xw(); t2 = get_Yw(); } static inline void load_Xd_Yd(void) { t1 = get_Xd(); t2 = get_Yd(); } /****************************************************************************** * * SET Segment Selector and Descriptor * ******************************************************************************/ static inline uint32_t get_descriptor_address(void) { if (selector_ti == 0) { /* GDT */ if ((selector_index * 8 + 7) > gdtr_limit) { exception(EXCEPTION_GP, selector & 0xfffc); } return gdtr_base + selector_index * 8; } else { /* LDT */ if ((selector_index * 8 + 7) > ldtr_system_limit) { exception(EXCEPTION_GP, selector & 0xfffc); } return ldtr_system_base + selector_index * 8; } } static inline void sset_selector(uint16_t value) { selector = value; selector_index = value >> 3; selector_ti = (value >> 2) & 1; selector_rpl = value & 3; } static inline void sset_descriptor(uint32_t dw1, uint32_t dw2) { bool gflag; descriptor_type = (dw2 >> 8) & 0xf; descriptor_sflag = (dw2 >> 12) & 0x1; descriptor_dpl = (dw2 >> 13) & 0x3; descriptor_pflag = (dw2 >> 15) & 0x1; if (descriptor_sflag) { /* code or data segment descriptor */ gflag = (dw2 & 0x00800000) > 0; descriptor_segment_limit = (dw1 & 0x0000ffff) | (dw2 & 0x000f0000); descriptor_segment_limit = limit_scaled( descriptor_segment_limit, gflag); descriptor_segment_base = (dw1 >> 16) | ((dw2 & 0xff) << 16) | (dw2 & 0xff000000); descriptor_segment_dflag = (dw2 & 0x00400000) > 0; descriptor_segment_avlflag = (dw2 & 0x00100000) > 0; } else { /* system segment descriptor */ switch (descriptor_type) { default: case 0x0: case 0x8: case 0xa: case 0xd: /* Reserved */ break; case SEGMENT_16BIT_CALL_GATE: descriptor_gate_paramcount = dw2 & 0x1f; descriptor_gate_selector = dw1 >> 16; descriptor_gate_offset = dw1 & 0xffff; break; case SEGMENT_16BIT_INTERRUPT_GATE: case SEGMENT_16BIT_TRAP_GATE: descriptor_gate_selector = dw1 >> 16; descriptor_gate_offset = dw1 & 0xffff; break; case SEGMENT_32BIT_CALL_GATE: descriptor_gate_paramcount = dw2 & 0x1f; descriptor_gate_selector = dw1 >> 16; descriptor_gate_offset = (dw2 & 0xffff0000) | (dw1 & 0x0000ffff); break; case SEGMENT_32BIT_INTERRUPT_GATE: case SEGMENT_32BIT_TRAP_GATE: descriptor_gate_selector = dw1 >> 16; descriptor_gate_offset = (dw2 & 0xffff0000) | (dw1 & 0x0000ffff); break; case SEGMENT_TASK_GATE: descriptor_gate_selector = dw1 >> 16; break; case SEGMENT_16BIT_AVAIL_TSS: case SEGMENT_16BIT_BUSY_TSS: descriptor_system_base = (dw1 >> 16) | ((dw2 & 0xff) << 16); descriptor_system_limit = (dw1 & 0xffff); break; case SEGMENT_LDT: case SEGMENT_32BIT_AVAIL_TSS: case SEGMENT_32BIT_BUSY_TSS: gflag = (dw2 & 0x00800000) > 0; descriptor_system_base = (dw1 >> 16) | ((dw2 & 0xff) << 16) | (dw2 & 0xff000000); descriptor_system_limit = (dw1 & 0x0000ffff) | (dw2 & 0x000f0000); descriptor_system_limit = limit_scaled( descriptor_system_limit, gflag); break; } } } static inline void sset_CS(uint16_t value) { DEBUG_SET("{CS:0x%04x}", value); if (protected_mode()) { uint32_t addr; sset_selector(value); if (selector_index == 0) { exception(EXCEPTION_GP, 0); } addr = get_descriptor_address(); sset_descriptor(mrd(addr, get_CPL()), mrd(addr + 4, get_CPL())); if (descriptor_sflag) { /* code or data segment descriptor */ if (!((descriptor_type >> 3) & 1)) { /* data segment */ exception(EXCEPTION_GP, value & 0xfffc); } if ((descriptor_type >> 2) & 1) { /* conforming */ if (descriptor_dpl > get_CPL()) { exception(EXCEPTION_GP, value & 0xfffc); } } else { /* non-conforming */ if (descriptor_dpl != get_CPL()) { exception(EXCEPTION_GP, value & 0xfffc); } if ((selector_rpl) > get_CPL()) { exception(EXCEPTION_GP, value & 0xfffc); } } if (!descriptor_pflag) { exception(EXCEPTION_NP, value & 0xfffc); } } else { /* system segment descriptor */ if ((descriptor_type == 0x0) || (descriptor_type == 0x8) || (descriptor_type == 0xa) || (descriptor_type == 0xd)) { /* Reserved */ exception(EXCEPTION_GP, value & 0xfffc); } if ((descriptor_dpl < get_CPL()) || (descriptor_dpl < selector_rpl)) { exception(EXCEPTION_GP, value & 0xfffc); } if (!descriptor_pflag) { exception(EXCEPTION_NP, value & 0xfffc); } } } else { selector = value; descriptor_type = SEGMENT_CODE_EXEC_READ_ACCESSED; descriptor_sflag = 1; descriptor_pflag = 1; descriptor_segment_base = value << 4; if (real_mode()) { descriptor_dpl = cs_dpl; descriptor_segment_limit = cs_segment_limit; descriptor_segment_dflag = cs_segment_dflag; descriptor_segment_avlflag = cs_segment_avlflag; } else { /* virtual8086_mode */ descriptor_dpl = 3; descriptor_segment_limit = 0xffff; descriptor_segment_dflag = 0; descriptor_segment_avlflag = 0; } } } static inline void sset_SS(uint16_t value) { DEBUG_SET("{SS:0x%04x}", value); if (protected_mode()) { uint32_t addr; sset_selector(value); if (selector_index == 0) { exception(EXCEPTION_GP, 0); } addr = get_descriptor_address(); if (selector_rpl != get_CPL()) { exception(EXCEPTION_GP, value & 0xfffc); } sset_descriptor(mrd(addr, get_CPL()), mrd(addr + 4, get_CPL())); if ((!descriptor_sflag) /* no data/code segment */ || ((descriptor_type >> 3) & 1) /* no data segment */ || (!((descriptor_type >> 1) & 1)) /* not writeable */ || (descriptor_dpl != get_CPL())) { exception(EXCEPTION_GP, value & 0xfffc); } if (!descriptor_pflag) { /* segment not present */ exception(EXCEPTION_SS, value & 0xfffc); } } else { selector = value; descriptor_type = SEGMENT_DATA_READ_WRITE_ACCESSED; descriptor_sflag = 1; descriptor_pflag = 1; descriptor_segment_base = value << 4; if (real_mode()) { descriptor_dpl = ss_dpl; descriptor_segment_limit = ss_segment_limit; descriptor_segment_dflag = ss_segment_dflag; descriptor_segment_avlflag = ss_segment_avlflag; } else { /* virtual8086_mode */ descriptor_dpl = 3; descriptor_segment_limit = 0xffff; descriptor_segment_dflag = 0; descriptor_segment_avlflag = 0; } } } static inline void sset_DS(uint16_t value) { DEBUG_SET("{DS:0x%04x}", value); if (protected_mode()) { uint32_t addr; sset_selector(value); if (selector_index == 0) { sset_selector(0); return; } addr = get_descriptor_address(); sset_descriptor(mrd(addr, get_CPL()), mrd(addr + 4, get_CPL())); if ((!descriptor_sflag) /* no data/code segment */ || (((descriptor_type >> 3) & 1) /* code segment */ && (!((descriptor_type >> 1) & 1)))) { /* not readable */ exception(EXCEPTION_GP, value & 0xfffc); } /* if data or non-conforming code, then rpl and cpl */ /* must be less than or equal to dpl */ if ((!((descriptor_type >> 1) & 1)) /* data segemnt */ || (!((descriptor_type >> 2) & 1))) { /* non-conformaing */ if (((selector_rpl) > descriptor_dpl) || (get_CPL() > descriptor_dpl)) { exception(EXCEPTION_GP, value & 0xfffc); } } if (!descriptor_pflag) { /* segment not present */ exception(EXCEPTION_NP, value & 0xfffc); } } else { selector = value; descriptor_type = SEGMENT_DATA_READ_WRITE_ACCESSED; descriptor_sflag = 1; descriptor_pflag = 1; descriptor_segment_base = value << 4; if (real_mode()) { descriptor_dpl = ds_dpl; descriptor_segment_limit = ds_segment_limit; descriptor_segment_dflag = ds_segment_dflag; descriptor_segment_avlflag = ds_segment_avlflag; } else { /* virtual8086_mode */ descriptor_dpl = 3; descriptor_segment_limit = 0xffff; descriptor_segment_dflag = 0; descriptor_segment_avlflag = 0; } } } static inline void sset_ES(uint16_t value) { DEBUG_SET("{ES:0x%04x}", value); if (protected_mode()) { uint32_t addr; sset_selector(value); if (selector_index == 0) { sset_selector(0); return; } addr = get_descriptor_address(); sset_descriptor(mrd(addr, get_CPL()), mrd(addr + 4, get_CPL())); if ((!descriptor_sflag) /* no data/code segment */ || (((descriptor_type >> 3) & 1) /* code segment */ && (!((descriptor_type >> 1) & 1)))) { /* not readable */ exception(EXCEPTION_GP, value & 0xfffc); } /* if data or non-conforming code, then rpl and cpl */ /* must be less than or equal to dpl */ if ((!((descriptor_type >> 1) & 1)) /* data segemnt */ || (!((descriptor_type >> 2) & 1))) { /* non-conformaing */ if (((selector_rpl) > descriptor_dpl) || (get_CPL() > descriptor_dpl)) { exception(EXCEPTION_GP, value & 0xfffc); } } if (!descriptor_pflag) { /* segment not present */ exception(EXCEPTION_NP, value & 0xfffc); } } else { selector = value; descriptor_type = SEGMENT_DATA_READ_WRITE_ACCESSED; descriptor_sflag = 1; descriptor_pflag = 1; descriptor_segment_base = value << 4; if (real_mode()) { descriptor_dpl = es_dpl; descriptor_segment_limit = es_segment_limit; descriptor_segment_dflag = es_segment_dflag; descriptor_segment_avlflag = es_segment_avlflag; } else { /* virtual8086_mode */ descriptor_dpl = 3; descriptor_segment_limit = 0xffff; descriptor_segment_dflag = 0; descriptor_segment_avlflag = 0; } } } static inline void sset_FS(uint16_t value) { DEBUG_SET("{FS:0x%04x}", value); if (protected_mode()) { uint32_t addr; sset_selector(value); if (selector_index == 0) { sset_selector(0); return; } addr = get_descriptor_address(); sset_descriptor(mrd(addr, get_CPL()), mrd(addr + 4, get_CPL())); if ((!descriptor_sflag) /* no data/code segment */ || (((descriptor_type >> 3) & 1) /* code segment */ && (!((descriptor_type >> 1) & 1)))) { /* not readable */ exception(EXCEPTION_GP, value & 0xfffc); } /* if data or non-conforming code, then rpl and cpl */ /* must be less than or equal to dpl */ if ((!((descriptor_type >> 1) & 1)) /* data segemnt */ || (!((descriptor_type >> 2) & 1))) { /* non-conformaing */ if (((selector_rpl) > descriptor_dpl) || (get_CPL() > descriptor_dpl)) { exception(EXCEPTION_GP, value & 0xfffc); } } if (!descriptor_pflag) { /* segment not present */ exception(EXCEPTION_NP, value & 0xfffc); } } else { selector = value; descriptor_type = SEGMENT_DATA_READ_WRITE_ACCESSED; descriptor_sflag = 1; descriptor_pflag = 1; descriptor_segment_base = value << 4; if (real_mode()) { descriptor_dpl = fs_dpl; descriptor_segment_limit = fs_segment_limit; descriptor_segment_dflag = fs_segment_dflag; descriptor_segment_avlflag = fs_segment_avlflag; } else { /* virtual8086_mode */ descriptor_dpl = 3; descriptor_segment_limit = 0xffff; descriptor_segment_dflag = 0; descriptor_segment_avlflag = 0; } } } static inline void sset_GS(uint16_t value) { DEBUG_SET("{GS:0x%04x}", value); if (protected_mode()) { uint32_t addr; sset_selector(value); if (selector_index == 0) { sset_selector(0); return; } addr = get_descriptor_address(); sset_descriptor(mrd(addr, get_CPL()), mrd(addr + 4, get_CPL())); if ((!descriptor_sflag) /* no data/code segment */ || (((descriptor_type >> 3) & 1) /* code segment */ && (!((descriptor_type >> 1) & 1)))) { /* not readable */ exception(EXCEPTION_GP, value & 0xfffc); } /* if data or non-conforming code, then rpl and cpl */ /* must be less than or equal to dpl */ if ((!((descriptor_type >> 1) & 1)) /* data segemnt */ || (!((descriptor_type >> 2) & 1))) { /* non-conformaing */ if (((selector_rpl) > descriptor_dpl) || (get_CPL() > descriptor_dpl)) { exception(EXCEPTION_GP, value & 0xfffc); } } if (!descriptor_pflag) { /* segment not present */ exception(EXCEPTION_NP, value & 0xfffc); } } else { selector = value; descriptor_type = SEGMENT_DATA_READ_WRITE_ACCESSED; descriptor_sflag = 1; descriptor_pflag = 1; descriptor_segment_base = value << 4; if (real_mode()) { descriptor_dpl = gs_dpl; descriptor_segment_limit = gs_segment_limit; descriptor_segment_dflag = gs_segment_dflag; descriptor_segment_avlflag = gs_segment_avlflag; } else { /* virtual8086_mode */ descriptor_dpl = 3; descriptor_segment_limit = 0xffff; descriptor_segment_dflag = 0; descriptor_segment_avlflag = 0; } } } /******************************************************************************/ static inline void commit_CS(void) { cs_selector = selector; cs_type = descriptor_type; cs_sflag = descriptor_sflag; cs_dpl = descriptor_dpl; cs_pflag = descriptor_pflag; cs_segment_limit = descriptor_segment_limit; cs_segment_base = descriptor_segment_base; cs_segment_dflag = descriptor_segment_dflag; cs_segment_avlflag = descriptor_segment_avlflag; } static inline void commit_SS(void) { ss_selector = selector; ss_type = descriptor_type; ss_sflag = descriptor_sflag; ss_dpl = descriptor_dpl; ss_pflag = descriptor_pflag; ss_segment_limit = descriptor_segment_limit; ss_segment_base = descriptor_segment_base; ss_segment_dflag = descriptor_segment_dflag; ss_segment_avlflag = descriptor_segment_avlflag; } static inline void commit_DS(void) { ds_selector = selector; ds_type = descriptor_type; ds_sflag = descriptor_sflag; ds_dpl = descriptor_dpl; ds_pflag = descriptor_pflag; ds_segment_limit = descriptor_segment_limit; ds_segment_base = descriptor_segment_base; ds_segment_dflag = descriptor_segment_dflag; ds_segment_avlflag = descriptor_segment_avlflag; } static inline void commit_ES(void) { es_selector = selector; es_type = descriptor_type; es_sflag = descriptor_sflag; es_dpl = descriptor_dpl; es_pflag = descriptor_pflag; es_segment_limit = descriptor_segment_limit; es_segment_base = descriptor_segment_base; es_segment_dflag = descriptor_segment_dflag; es_segment_avlflag = descriptor_segment_avlflag; } static inline void commit_FS(void) { fs_selector = selector; fs_type = descriptor_type; fs_sflag = descriptor_sflag; fs_dpl = descriptor_dpl; fs_pflag = descriptor_pflag; fs_segment_limit = descriptor_segment_limit; fs_segment_base = descriptor_segment_base; fs_segment_dflag = descriptor_segment_dflag; fs_segment_avlflag = descriptor_segment_avlflag; } static inline void commit_GS(void) { gs_selector = selector; gs_type = descriptor_type; gs_sflag = descriptor_sflag; gs_dpl = descriptor_dpl; gs_pflag = descriptor_pflag; gs_segment_limit = descriptor_segment_limit; gs_segment_base = descriptor_segment_base; gs_segment_dflag = descriptor_segment_dflag; gs_segment_avlflag = descriptor_segment_avlflag; } static inline void set_SS(uint16_t value) { sset_SS(value); commit_SS(); } static inline void set_DS(uint16_t value) { sset_DS(value); commit_DS(); } static inline void set_ES(uint16_t value) { sset_ES(value); commit_ES(); } static inline void set_FS(uint16_t value) { sset_FS(value); commit_FS(); } static inline void set_GS(uint16_t value) { sset_GS(value); commit_GS(); } /****************************************************************************** * * SET * ******************************************************************************/ static inline void set_AL(uint32_t value) { DEBUG_SET("{AL:0x%02x}", value & 0xff); eax = (eax & ~0xff) | (value & 0xff); } static inline void set_CL(uint32_t value) { DEBUG_SET("{CL:0x%02x}", value & 0xff); ecx = (ecx & ~0xff) | (value & 0xff); } static inline void set_DL(uint32_t value) { DEBUG_SET("{DL:0x%02x}", value & 0xff); edx = (edx & ~0xff) | (value & 0xff); } static inline void set_BL(uint32_t value) { DEBUG_SET("{BL:0x%02x}", value & 0xff); ebx = (ebx & ~0xff) | (value & 0xff); } /******************************************************************************/ static inline void set_AH(uint32_t value) { DEBUG_SET("{AH:0x%02x}", value & 0xff); eax = (eax & 0xffff00ff) | ((value & 0xff) << 8); } static inline void set_CH(uint32_t value) { DEBUG_SET("{CH:0x%02x}", value & 0xff); ecx = (ecx & 0xffff00ff) | ((value & 0xff) << 8); } static inline void set_DH(uint32_t value) { DEBUG_SET("{DH:0x%02x}", value & 0xff); edx = (edx & 0xffff00ff) | ((value & 0xff) << 8); } static inline void set_BH(uint32_t value) { DEBUG_SET("{BH:0x%02x}", value & 0xff); ebx = (ebx & 0xffff00ff) | ((value & 0xff) << 8); } /******************************************************************************/ static inline void set_AX(uint32_t value) { DEBUG_SET("{AX:0x%04x}", value & 0xffff); eax = (eax & ~0xffff) | (value & 0xffff); } static inline void set_CX(uint32_t value) { DEBUG_SET("{CX:0x%04x}", value & 0xffff); ecx = (ecx & ~0xffff) | (value & 0xffff); } static inline void set_DX(uint32_t value) { DEBUG_SET("{DX:0x%04x}", value & 0xffff); edx = (edx & ~0xffff) | (value & 0xffff); } static inline void set_BX(uint32_t value) { DEBUG_SET("{BX:0x%04x}", value & 0xffff); ebx = (ebx & ~0xffff) | (value & 0xffff); } /******************************************************************************/ static inline void set_SP(uint32_t value) { DEBUG_SET("{SP:0x%04x}", value & 0xffff); esp = (esp & ~0xffff) | (value & 0xffff); } static inline void set_BP(uint32_t value) { DEBUG_SET("{BP:0x%04x}", value & 0xffff); ebp = (ebp & ~0xffff) | (value & 0xffff); } static inline void set_SI(uint32_t value) { DEBUG_SET("{SI:0x%04x}", value & 0xffff); esi = (esi & ~0xffff) | (value & 0xffff); } static inline void set_DI(uint32_t value) { DEBUG_SET("{DI:0x%04x}", value & 0xffff); edi = (edi & ~0xffff) | (value & 0xffff); } /******************************************************************************/ static inline void set_EAX(uint32_t value) { DEBUG_SET("{EAX:0x%08x}", value); eax = value; } static inline void set_ECX(uint32_t value) { DEBUG_SET("{ECX:0x%08x}", value); ecx = value; } static inline void set_EDX(uint32_t value) { DEBUG_SET("{EDX:0x%08x}", value); edx = value; } static inline void set_EBX(uint32_t value) { DEBUG_SET("{EBX:0x%08x}", value); ebx = value; } /******************************************************************************/ static inline void set_ESP(uint32_t value) { DEBUG_SET("{ESP:0x%08x}", value); esp = value; } static inline void set_EBP(uint32_t value) { DEBUG_SET("{EBP:0x%08x}", value); ebp = value; } static inline void set_ESI(uint32_t value) { DEBUG_SET("{ESI:0x%08x}", value); esi = value; } static inline void set_EDI(uint32_t value) { DEBUG_SET("{EDI:0x%08x}", value); edi = value; } /******************************************************************************/ static inline void set_eAX(uint32_t value) { if (operand_size_32()) { set_EAX(value); } else { set_AX(value); } } static inline void set_eCX(uint32_t value) { if (operand_size_32()) { set_ECX(value); } else { set_CX(value); } } static inline void set_eDX(uint32_t value) { if (operand_size_32()) { set_EDX(value); } else { set_DX(value); } } static inline void set_eBX(uint32_t value) { if (operand_size_32()) { set_EBX(value); } else { set_BX(value); } } /******************************************************************************/ static inline void set_eSP(uint32_t value) { if (operand_size_32()) { set_ESP(value); } else { set_SP(value); } } static inline void set_eBP(uint32_t value) { if (operand_size_32()) { set_EBP(value); } else { set_BP(value); } } static inline void set_eSI(uint32_t value) { if (operand_size_32()) { set_ESI(value); } else { set_SI(value); } } static inline void set_eDI(uint32_t value) { if (operand_size_32()) { set_EDI(value); } else { set_DI(value); } } /******************************************************************************/ static inline void set_Rb(uint32_t value, uint32_t reg) { switch (reg) { default: DEBUG_ERROR_SWITCH(); case 0: set_AL(value); break; case 1: set_CL(value); break; case 2: set_DL(value); break; case 3: set_BL(value); break; case 4: set_AH(value); break; case 5: set_CH(value); break; case 6: set_DH(value); break; case 7: set_BH(value); break; } } static inline void set_Rw(uint32_t value, uint32_t reg) { switch (reg) { default: DEBUG_ERROR_SWITCH(); case 0: set_AX(value); break; case 1: set_CX(value); break; case 2: set_DX(value); break; case 3: set_BX(value); break; case 4: set_SP(value); break; case 5: set_BP(value); break; case 6: set_SI(value); break; case 7: set_DI(value); break; } } static inline void set_Rd(uint32_t value, uint32_t reg) { switch (reg) { default: DEBUG_ERROR_SWITCH(); case 0: set_EAX(value); break; case 1: set_ECX(value); break; case 2: set_EDX(value); break; case 3: set_EBX(value); break; case 4: set_ESP(value); break; case 5: set_EBP(value); break; case 6: set_ESI(value); break; case 7: set_EDI(value); break; } } /******************************************************************************/ static inline void set_Cd(uint32_t value) { switch(get_instruction_reg()) { default: DEBUG_ERROR_SWITCH(); case 0: set_CR0(value); break; case 1: ERROR_NYI(); /* FIXME: Reserved */ case 2: set_CR2(value); break; case 3: set_CR3(value); break; case 4: case 5: case 6: case 7: ERROR_NYI(); /* FIXME: Reserved */ } } /******************************************************************************/ static inline void set_Eb(uint32_t value) { switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: mwb_seg(get_address_mod0(), value, get_segment_overwritten(get_segment_mod0())); break; case 1: mwb_seg(get_address_mod1(), value, get_segment_overwritten(get_segment_mod1())); break; case 2: mwb_seg(get_address_mod2(), value, get_segment_overwritten(get_segment_mod2())); break; case 3: set_Rb(value, get_instruction_rm()); break; } } static inline void set_Ew(uint32_t value) { switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: mww_seg(get_address_mod0(), value, get_segment_overwritten(get_segment_mod0())); break; case 1: mww_seg(get_address_mod1(), value, get_segment_overwritten(get_segment_mod1())); break; case 2: mww_seg(get_address_mod2(), value, get_segment_overwritten(get_segment_mod2())); break; case 3: set_Rw(value, get_instruction_rm()); break; } } static inline void set_Ed(uint32_t value) { switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: mwd_seg(get_address_mod0(), value, get_segment_overwritten(get_segment_mod0())); break; case 1: mwd_seg(get_address_mod1(), value, get_segment_overwritten(get_segment_mod1())); break; case 2: mwd_seg(get_address_mod2(), value, get_segment_overwritten(get_segment_mod2())); break; case 3: set_Rd(value, get_instruction_rm()); break; } } static inline void set_Ev(uint32_t value) { if (operand_size_32()) { set_Ed(value); } else{ set_Ew(value); } } /******************************************************************************/ static inline void set_EwBIT(uint32_t value) { int32_t offset; offset = ((int16_t) (get_Rw(get_instruction_reg()) & 0xfff0)) / 16; switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: mww_seg(get_address_mod0() + 2 * offset, value, get_segment_overwritten(get_segment_mod0())); break; case 1: mww_seg(get_address_mod1() + 2 * offset, value, get_segment_overwritten(get_segment_mod1())); break; case 2: mww_seg(get_address_mod2() + 2 * offset, value, get_segment_overwritten(get_segment_mod2())); break; case 3: set_Rd(value, get_instruction_rm()); break; } } static inline void set_EdBIT(uint32_t value) { int32_t offset; offset = ((int32_t) (get_Rd(get_instruction_reg()) & 0xffffffe0)) / 32; switch (get_instruction_mod()) { default: DEBUG_ERROR_SWITCH(); case 0: mwd_seg(get_address_mod0() + 4 * offset, value, get_segment_overwritten(get_segment_mod0())); break; case 1: mwd_seg(get_address_mod1() + 4 * offset, value, get_segment_overwritten(get_segment_mod1())); break; case 2: mwd_seg(get_address_mod2() + 4 * offset, value, get_segment_overwritten(get_segment_mod2())); break; case 3: set_Rd(value, get_instruction_rm()); break; } } static inline void set_EvBIT(uint32_t value) { if (operand_size_32()) { set_EdBIT(value); } else { set_EwBIT(value); } } /******************************************************************************/ static inline void set_Ob(uint32_t value) { if (address_size_32()) { mwb_seg(get_Id(), value, get_segment_overwritten(SEGMENT_DS)); } else { mwb_seg(get_Iw(), value, get_segment_overwritten(SEGMENT_DS)); } } static inline void set_Ow(uint32_t value) { if (address_size_32()) { mww_seg(get_Id(), value, get_segment_overwritten(SEGMENT_DS)); } else { mww_seg(get_Iw(), value, get_segment_overwritten(SEGMENT_DS)); } } static inline void set_Od(uint32_t value) { if (address_size_32()) { mwd_seg(get_Id(), value, get_segment_overwritten(SEGMENT_DS)); } else { mwd_seg(get_Iw(), value, get_segment_overwritten(SEGMENT_DS)); } } static inline void set_Ov(uint32_t value) { if (operand_size_32()) { set_Od(value); } else { set_Ow(value); } } /******************************************************************************/ static inline void set_Gb(uint32_t value) { switch (get_instruction_reg()) { default: DEBUG_ERROR_SWITCH(); case 0: set_AL(value); break; case 1: set_CL(value); break; case 2: set_DL(value); break; case 3: set_BL(value); break; case 4: set_AH(value); break; case 5: set_CH(value); break; case 6: set_DH(value); break; case 7: set_BH(value); break; } } static inline void set_Gw(uint32_t value) { switch (get_instruction_reg()) { default: DEBUG_ERROR_SWITCH(); case 0: set_AX(value); break; case 1: set_CX(value); break; case 2: set_DX(value); break; case 3: set_BX(value); break; case 4: set_SP(value); break; case 5: set_BP(value); break; case 6: set_SI(value); break; case 7: set_DI(value); break; } } static inline void set_Gd(uint32_t value) { switch (get_instruction_reg()) { default: DEBUG_ERROR_SWITCH(); case 0: set_EAX(value); break; case 1: set_ECX(value); break; case 2: set_EDX(value); break; case 3: set_EBX(value); break; case 4: set_ESP(value); break; case 5: set_EBP(value); break; case 6: set_ESI(value); break; case 7: set_EDI(value); break; } } static inline void set_Gv(uint32_t value) { if (operand_size_32()) { set_Gd(value); } else { set_Gw(value); } } /******************************************************************************/ static inline void set_Sw(uint32_t value) { switch (get_instruction_reg()) { default: DEBUG_ERROR_SWITCH(); case SEGMENT_ES: set_ES(value); break; case SEGMENT_CS: exception(EXCEPTION_UD, -1); break; case SEGMENT_SS: set_SS(value); break; case SEGMENT_DS: set_DS(value); break; case SEGMENT_FS: set_FS(value); break; case SEGMENT_GS: set_GS(value); break; case 6: exception(EXCEPTION_UD, -1); break; case 7: exception(EXCEPTION_UD, -1); break; } } /****************************************************************************** * * Set Memory addressed by the ES:eDI register pair * ******************************************************************************/ static inline void set_Yb(uint32_t value) { if (address_size_32()) { mwb_seg(get_EDI(), value, SEGMENT_ES); } else { mwb_seg(get_DI(), value, SEGMENT_ES); } } static inline void set_Yw(uint32_t value) { if (address_size_32()) { mww_seg(get_EDI(), value, SEGMENT_ES); } else { mww_seg(get_DI(), value, SEGMENT_ES); } } static inline void set_Yd(uint32_t value) { if (address_size_32()) { mwd_seg(get_EDI(), value, SEGMENT_ES); } else { mwd_seg(get_DI(), value, SEGMENT_ES); } } /****************************************************************************** * * Store * ******************************************************************************/ #define DEBUG_RESULT_B(str) DEBUG(" %s:0x%02x", str, (uint8_t) t0) #define DEBUG_RESULT_W(str) DEBUG(" %s:0x%04x", str, (uint16_t) t0) #define DEBUG_RESULT_D(str) DEBUG(" %s:0x%08x", str, (uint32_t) t0) #define DEBUG_RESULT_V(str) \ if (operand_size_32()) { \ DEBUG_RESULT_D(str); \ } else { \ DEBUG_RESULT_W(str); \ } #define DEBUG_STORE() DEBUG_SET(" -> ") static inline void store_SS(void) { DEBUG_STORE(); set_SS(t0); DEBUG_RESULT_W("SS"); } static inline void store_DS(void) { DEBUG_STORE(); set_DS(t0); DEBUG_RESULT_W("DS"); } static inline void store_ES(void) { DEBUG_STORE(); set_ES(t0); DEBUG_RESULT_W("ES"); } static inline void store_FS(void) { DEBUG_STORE(); set_FS(t0); DEBUG_RESULT_W("FS"); } static inline void store_GS(void) { DEBUG_STORE(); set_GS(t0); DEBUG_RESULT_W("GS"); } /******************************************************************************/ static inline void store_AL(void) { DEBUG_STORE(); set_AL(t0); DEBUG_RESULT_B("AL"); } static inline void store_CL(void) { DEBUG_STORE(); set_CL(t0); DEBUG_RESULT_B("CL"); } static inline void store_DL(void) { DEBUG_STORE(); set_DL(t0); DEBUG_RESULT_B("DL"); } static inline void store_BL(void) { DEBUG_STORE(); set_BL(t0); DEBUG_RESULT_B("BL"); } /******************************************************************************/ static inline void store_AH(void) { DEBUG_STORE(); set_AH(t0); DEBUG_RESULT_B("AH"); } static inline void store_CH(void) { DEBUG_STORE(); set_CH(t0); DEBUG_RESULT_B("CH"); } static inline void store_DH(void) { DEBUG_STORE(); set_DH(t0); DEBUG_RESULT_B("DH"); } static inline void store_BH(void) { DEBUG_STORE(); set_BH(t0); DEBUG_RESULT_B("BH"); } /******************************************************************************/ static inline void store_eAX(void) { DEBUG_STORE(); set_eAX(t0); DEBUG_RESULT_V("eAX"); } static inline void store_eCX(void) { DEBUG_STORE(); set_eCX(t0); DEBUG_RESULT_V("eCX"); } static inline void store_eDX(void) { DEBUG_STORE(); set_eDX(t0); DEBUG_RESULT_V("eDX"); } static inline void store_eBX(void) { DEBUG_STORE(); set_eBX(t0); DEBUG_RESULT_V("eBX"); } /******************************************************************************/ static inline void store_eSP(void) { DEBUG_STORE(); set_eSP(t0); DEBUG_RESULT_V("eSP"); } static inline void store_eBP(void) { DEBUG_STORE(); set_eBP(t0); DEBUG_RESULT_V("eBP"); } static inline void store_eSI(void) { DEBUG_STORE(); set_eSI(t0); DEBUG_RESULT_V("eSI"); } static inline void store_eDI(void) { DEBUG_STORE(); set_eDI(t0); DEBUG_RESULT_V("eDI"); } /******************************************************************************/ static inline void store_Cd(void) { DEBUG_STORE(); set_Cd(t0); DEBUG_RESULT_V("Cd"); } static inline void store_Rd(void) { DEBUG_STORE(); set_Rd(t0, get_instruction_rm()); DEBUG_RESULT_V("Rd"); } /******************************************************************************/ static inline void store_Eb(void) { DEBUG_STORE(); set_Eb(t0); DEBUG_RESULT_B("Eb"); } static inline void store_Ew(void) { DEBUG_STORE(); set_Ew(t0); DEBUG_RESULT_W("Ew"); } #if 0 static inline void store_Ed(void) { DEBUG_STORE(); set_Ed(t0); DEBUG_RESULT_D("Ed"); } #endif static inline void store_Ev(void) { DEBUG_STORE(); set_Ev(t0); DEBUG_RESULT_V("Ev"); } static inline void store_EvBIT(void) { DEBUG_STORE(); set_EvBIT(t0); DEBUG_RESULT_V("EvBIT"); } /******************************************************************************/ static inline void store_Gb(void) { DEBUG_STORE(); set_Gb(t0); DEBUG_RESULT_B("Gb"); } #if 0 static inline void store_Gw(void) { DEBUG_STORE(); set_Gw(t0); DEBUG_RESULT_W("Gw"); } static inline void store_Gd(void) { DEBUG_STORE(); set_Gd(t0); DEBUG_RESULT_D("Gd"); } #endif static inline void store_Gv(void) { DEBUG_STORE(); set_Gv(t0); DEBUG_RESULT_V("Gv"); } static inline void store_Sw(void) { DEBUG_STORE(); set_Sw(t0); DEBUG_RESULT_W("Sw"); } static inline void store_Ob(void) { DEBUG_STORE(); set_Ob(t0); DEBUG_RESULT_B("Ob"); } static inline void store_Ov(void) { DEBUG_STORE(); set_Ov(t0); DEBUG_RESULT_V("Ov"); } /****************************************************************************** * * Store Memory addressed by the ES:eDI register pair * ******************************************************************************/ static inline void store_Yb(void) { DEBUG_STORE(); set_Yb(t0); DEBUG_RESULT_B("Yb"); } static inline void store_Yw(void) { DEBUG_STORE(); set_Yw(t0); DEBUG_RESULT_W("Yw"); } static inline void store_Yd(void) { DEBUG_STORE(); set_Yd(t0); DEBUG_RESULT_D("Yd"); } /****************************************************************************** * * Store t1 and t2 * ******************************************************************************/ static inline void store_eAX_eCX(void) { DEBUG_STORE(); set_eAX(t1); DEBUG_SET(","); set_eCX(t2); /* TODO DEBUG */ } static inline void store_eAX_eDX(void) { DEBUG_STORE(); set_eAX(t1); DEBUG_SET(","); set_eDX(t2); /* TODO DEBUG */ } static inline void store_eAX_eBX(void) { DEBUG_STORE(); set_eAX(t1); DEBUG_SET(","); set_eBX(t2); /* TODO DEBUG */ } static inline void store_eAX_eSP(void) { DEBUG_STORE(); set_eAX(t1); DEBUG_SET(","); set_eSP(t2); /* TODO DEBUG */ } static inline void store_eAX_eBP(void) { DEBUG_STORE(); set_eAX(t1); DEBUG_SET(","); set_eBP(t2); /* TODO DEBUG */ } static inline void store_eAX_eSI(void) { DEBUG_STORE(); set_eAX(t1); DEBUG_SET(","); set_eSI(t2); /* TODO DEBUG */ } static inline void store_eAX_eDI(void) { DEBUG_STORE(); set_eAX(t1); DEBUG_SET(","); set_eDI(t2); /* TODO DEBUG */ } /******************************************************************************/ static inline void store_Eb_Gb(void) { DEBUG_STORE(); set_Eb(t1); DEBUG_SET(","); set_Gb(t2); /* TODO DEBUG_RESULT_BB */ } static inline void store_Ew_Gw(void) { DEBUG_STORE(); set_Ew(t1); DEBUG_SET(","); set_Gw(t2); /* TODO DEBUG_RESULT_WW */ } static inline void store_Ed_Gd(void) { DEBUG_STORE(); set_Ed(t1); DEBUG_SET(","); set_Gd(t2); /* TODO DEBUG_STORE_DD */ } static inline void store_Ev_Gv(void) { if (operand_size_32()) { store_Ed_Gd(); } else { store_Ew_Gw(); } } /****************************************************************************** * * eip * ******************************************************************************/ #if 0 static inline void inc_EIP(int32_t value) { eip_new += value; } #endif static inline void commit_EIP(void) { #if 0 done = 0; #endif if (eip != eip_new) { eip = eip_new; prefix_clear(); interrupt_delay = 0; if (prefix_lock_repeat == LR_LOCK) { unlock(); } } } static inline void commit_EIP_and_delay_interrupts(void) { if (eip != eip_new) { eip = eip_new; prefix_clear(); if (interrupt_delay) { interrupt_delay = 0; } else { interrupt_delay = 1; } if (prefix_lock_repeat == LR_LOCK) { unlock(); } } } static inline void revert_EIP(void) { eip_new = eip; prefix_clear(); } /****************************************************************************** * * Parity * ******************************************************************************/ static inline bool parity(uint8_t value) { static const uint8_t parity_table[256] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 0x00 - 0x0f */ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 0x10 - 0x1f */ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 0x20 - 0x2f */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 0x30 - 0x3f */ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 0x40 - 0x4f */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 0x50 - 0x5f */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 0x60 - 0x6f */ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 0x70 - 0x7f */ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 0x80 - 0x8f */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 0x90 - 0x9f */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 0xa0 - 0xaf */ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 0xb0 - 0xbf */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 0xc0 - 0xcf */ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 0xd0 - 0xdf */ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 0xe0 - 0xef */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 0xf0 - 0xff */ }; return parity_table[value]; } /****************************************************************************** * * OUT - Output to Port * ******************************************************************************/ static inline void iowb(uint8_t value, uint32_t port) { uint32_t val32; if (port == 0xffff) { /* System BIOS / VGA BIOS output port. */ fprintf(stderr, "%c", value); return; } val32 = value << ((port & 3) * 8); cpu_iow(port & ~3, 1 << (port & 3), val32); } static inline void ioww(uint16_t value, uint32_t port) { uint32_t val32; if ((port & 3) == 3) { unsigned char value0 = (value >> 0) & 0xff; unsigned char value8 = (value >> 8) & 0xff; iowb(value0, port + 0); iowb(value8, port + 1); } else { val32 = value << ((port & 3) * 8); cpu_iow(port & ~3, 3 << (port & 3), val32); } } static inline void iowd(uint32_t value, uint32_t port) { if (port & 3) { uint32_t val0; uint32_t val1; val0 = value << ((port & 3) * 8); val1 = value >> ((4 - (port & 3)) * 8); cpu_iow(port & ~3, (0xf << (port & 3)) & 0xf, val0); cpu_iow((port & ~3) + 4, 0xf >> (4 - (port & 3)), val1); } else { cpu_iow(port & ~3, 0xf, value); } } /******************************************************************************/ static inline void outb(void) { /* TODO: check permissions */ iowb(t2 & 0xff, t1 & 0xffff); } static inline void outw(void) { /* TODO: check permissions */ ioww(t2 & 0xffff, t1 & 0xffff); } static inline void outd(void) { /* TODO: check permissions */ iowd(t2, t1 & 0xffff); } static inline void outv(void) { if (operand_size_32()) { outd(); } else { outw(); } } /****************************************************************************** * * IN - Input from Port * ******************************************************************************/ static inline uint8_t iorb(uint32_t port) { uint32_t val32; uint8_t val8; val32 = cpu_ior(port & ~3, 1 << (port & 3)); val8 = (val32 >> ((port & 3) * 8)) & 0xff; return val8; } static inline uint16_t iorw(uint32_t port) { uint16_t val16; uint32_t val32; if ((port & 3) == 3) { val16 = iorb(port) | (iorb(port + 1) << 8); } else { val32 = cpu_ior(port & ~3, 3 << (port & 3)); val16 = (val32 >> ((port & 3) * 8)) & 0xffff; } return val16; } static inline uint32_t iord(uint32_t port) { uint32_t value; if (port & 3) { uint32_t val0; uint32_t val1; val0 = cpu_ior(port & ~3, (0xf << (port & 3)) & 0xf); val1 = cpu_ior((port & ~3) + 4, 0xf >> (4 - (port & 3))); value = (val0 >> ((port & 3) * 8)) | (val1 << ((4 - (port & 3)) * 8)); } else { value = cpu_ior(port & ~3, 0xf); } return value; } /******************************************************************************/ static inline void inb(void) { /* TODO: check permissions */ t0 = iorb(t1 & 0xffff); } static inline void inw(void) { /* TODO: check permissions */ t0 = iorw(t1 & 0xffff); } static inline void ind(void) { /* TODO: check permissions */ t0 = iord(t1 & 0xffff); } static inline void inv(void) { if (operand_size_32()) { ind(); } else { inw(); } } /****************************************************************************** * * INC - Increment by 1 * ******************************************************************************/ static inline void sset_flags_for_inc(void) { /* cf unchanged */ sset_AF((t0 & 0xf) == 0); sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void incb(void) { t0 = (t1 + 1) & 0xff; sset_flags_for_inc(); sset_SF(t0 >= 0x80); sset_OF(t0 == 0x80); } static inline void incw(void) { t0 = (t1 + 1) & 0xffff; sset_flags_for_inc(); sset_SF(t0 >= 0x8000); sset_OF(t0 == 0x8000); } static inline void incd(void) { t0 = t1 + 1; sset_flags_for_inc(); sset_SF(t0 >= 0x80000000); sset_OF(t0 == 0x80000000); } static inline void incv(void) { if (operand_size_32()) { incd(); } else { incw(); } } /****************************************************************************** * * DEC - Decrement by 1 * ******************************************************************************/ static inline void sset_flags_for_dec(void) { /* cf unchanged */ sset_AF((t0 & 0xf) == 0xf); sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void decb(void) { t0 = (t1 - 1) & 0xff; sset_flags_for_dec(); sset_SF(t0 >= 0x80); sset_OF(t0 == 0x7f); } static inline void decw(void) { t0 = (t1 - 1) & 0xffff; sset_flags_for_dec(); sset_SF(t0 >= 0x8000); sset_OF(t0 == 0xf777); } static inline void decd(void) { t0 = t1 - 1; sset_flags_for_dec(); sset_SF(t0 >= 0x80000000); sset_OF(t0 == 0xf7777777); } static inline void decv(void) { if (operand_size_32()) { decd(); } else { decw(); } } /****************************************************************************** * * ADD - Add * ******************************************************************************/ static inline void sset_flags_for_add(void) { sset_CF(t0 < t1); sset_AF((t1 ^ t2 ^ t0) & 0x10); sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void addb(void) { t0 = (t1 + t2) & 0xff; sset_flags_for_add(); sset_SF(t0 >= 0x80); sset_OF(((~(t1 ^ t2) & (t2 ^ t0)) & 0x80) != 0); } static inline void addw(void) { t0 = (t1 + t2) & 0xffff; sset_flags_for_add(); sset_SF(t0 >= 0x8000); sset_OF(((~(t1 ^ t2) & (t2 ^ t0)) & 0x8000) != 0); } static inline void addd(void) { t0 = t1 + t2; sset_flags_for_add(); sset_SF(t0 >= 0x80000000); sset_OF(((~(t1 ^ t2) & (t2 ^ t0)) & 0x80000000) != 0); } static inline void addv(void) { if (operand_size_32()) { addd(); } else { addw(); } } /****************************************************************************** * * OR - Logical Inclusive OR * ******************************************************************************/ static inline void sset_flags_for_or(void) { sset_CF(0); sset_OF(0); sset_AF(0); /* undefined */ sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void orb(void) { t0 = (t1 | t2) & 0xff; sset_flags_for_or(); sset_SF(t0 >= 0x80); } static inline void orw(void) { t0 = (t1 | t2) & 0xffff; sset_flags_for_or(); sset_SF(t0 >= 0x8000); } static inline void ord(void) { t0 = t1 | t2; sset_flags_for_or(); sset_SF(t0 >= 0x80000000); } static inline void orv(void) { if (operand_size_32()) { ord(); } else { orw(); } } /****************************************************************************** * * ADC - Add with Carry * ******************************************************************************/ static inline void sset_flags_for_adc(void) { sset_AF((t1 ^ t2 ^ t0) & 0x10); sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void adcb(void) { t0 = (t1 + t2 + get_CF()) & 0xff; sset_flags_for_adc(); sset_SF(t0 >= 0x80); sset_OF(((~(t1 ^ t2) & (t2 ^ t0)) & 0x80) != 0); if (get_CF()) { sset_CF(t0 <= t1); } else { sset_CF(t0 < t1); } } static inline void adcw(void) { t0 = (t1 + t2 + get_CF()) & 0xffff; sset_flags_for_adc(); sset_SF(t0 >= 0x8000); sset_OF(((~(t1 ^ t2) & (t2 ^ t0)) & 0x8000) != 0); if (get_CF()) { sset_CF(t0 <= t1); } else { sset_CF(t0 < t1); } } static inline void adcd(void) { t0 = t1 + t2 + get_CF(); sset_flags_for_adc(); sset_SF(t0 >= 0x80000000); sset_OF(((~(t1 ^ t2) & (t2 ^ t0)) & 0x80000000) != 0); if (get_CF()) { sset_CF(t0 <= t1); } else { sset_CF(t0 < t1); } } static inline void adcv(void) { if (operand_size_32()) { adcd(); } else { adcw(); } } /****************************************************************************** * * SBB - Integer Subtraction with Borrow * ******************************************************************************/ static inline void sset_flags_for_sbb(void) { sset_AF((t1 ^ t2 ^ t0) & 0x10); sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void sbbb(void) { t0 = (t1 - (t2 + get_CF())) & 0xff; sset_flags_for_sbb(); sset_SF(t0 >= 0x80); sset_CF((t1 < t0) || (t2 == 0xff)); sset_OF((((t1 ^ t2) & (t1 ^ t0)) & 0x80) != 0); } static inline void sbbw(void) { t0 = (t1 - (t2 + get_CF())) & 0xffff; sset_flags_for_sbb(); sset_SF(t0 >= 0x8000); sset_CF((t1 < t0) || (t2 == 0xffff)); sset_OF((((t1 ^ t2) & (t1 ^ t0)) & 0x8000) != 0); } static inline void sbbd(void) { t0 = t1 - (t2 + get_CF()); sset_flags_for_sbb(); sset_SF(t0 >= 0x80000000); sset_CF((t1 < t0) || (t2 == 0xffffffff)); sset_OF((((t1 ^ t2) & (t1 ^ t0)) & 0x80000000) != 0); } static inline void sbbv(void) { if (operand_size_32()) { sbbd(); } else { sbbw(); } } /****************************************************************************** * * AND - Logical AND * ******************************************************************************/ static inline void sset_flags_for_and(void) { sset_CF(0); sset_OF(0); sset_AF(0); /* undefined */ sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void andb(void) { t0 = (t1 & t2) & 0xff; sset_flags_for_and(); sset_SF(t0 >= 0x80); } static inline void andw(void) { t0 = (t1 & t2) & 0xffff; sset_flags_for_and(); sset_SF(t0 >= 0x8000); } static inline void andd(void) { t0 = t1 & t2; sset_flags_for_and(); sset_SF(t0 >= 0x80000000); } static inline void andv(void) { if (operand_size_32()) { andd(); } else { andw(); } } /****************************************************************************** * * SUB - Substract * ******************************************************************************/ static inline void sset_flags_for_sub(void) { sset_AF((t1 ^ t2 ^ t0) & 0x10); sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void subb(void) { t0 = (t1 - t2) & 0xff; sset_flags_for_sub(); sset_SF(t0 >= 0x80); sset_CF((t1 & 0xff) < (t2 & 0xff)); sset_OF((((t1 ^ t2) & (t1 ^ t0)) & 0x80) != 0); } static inline void subw(void) { t0 = (t1 - t2) & 0xffff; sset_flags_for_sub(); sset_SF(t0 >= 0x8000); sset_CF((t1 & 0xffff) < (t2 & 0xffff)); sset_OF((((t1 ^ t2) & (t1 ^ t0)) & 0x8000) != 0); } static inline void subd(void) { t0 = t1 - t2; sset_flags_for_sub(); sset_SF(t0 >= 0x80000000); sset_CF(t1 < t2); sset_OF((((t1 ^ t2) & (t1 ^ t0)) & 0x80000000) != 0); } static inline void subv(void) { if (operand_size_32()) { subd(); } else { subw(); } } /****************************************************************************** * * XOR - Logical Exclusive OR * ******************************************************************************/ static inline void sset_flags_for_xor(void) { sset_CF(0); sset_OF(0); sset_AF(0); /* undefined */ sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void xorb(void) { t0 = (t1 ^ t2) & 0xff; sset_flags_for_xor(); sset_SF(t0 >= 0x80); } static inline void xorw(void) { t0 = (t1 ^ t2) & 0xffff; sset_flags_for_xor(); sset_SF(t0 >= 0x8000); } static inline void xord(void) { t0 = t1 ^ t2; sset_flags_for_xor(); sset_SF(t0 >= 0x80000000); } static inline void xorv(void) { if (operand_size_32()) { xord(); } else { xorw(); } } /****************************************************************************** * * CMP - Compare Two Operands * ******************************************************************************/ static inline void sset_flags_for_cmp(void) { sset_AF((t1 ^ t2 ^ t0) & 0x10); sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void cmpb(void) { t0 = (t1 - t2) & 0xff; sset_flags_for_cmp(); sset_SF(t0 >= 0x80); sset_CF((t1 & 0xff) < (t2 & 0xff)); sset_OF((((t1 ^ t2) & (t1 ^ t0)) & 0x80) != 0); } static inline void cmpw(void) { t0 = (t1 - t2) & 0xffff; sset_flags_for_cmp(); sset_SF(t0 >= 0x8000); sset_CF((t1 & 0xffff) < (t2 & 0xffff)); sset_OF((((t1 ^ t2) & (t1 ^ t0)) & 0x8000) != 0); } static inline void cmpd(void) { t0 = t1 - t2; sset_flags_for_cmp(); sset_SF(t0 >= 0x80000000); sset_CF(t1 < t2); sset_OF((((t1 ^ t2) & (t1 ^ t0)) & 0x80000000) != 0); } static inline void cmpv(void) { if (operand_size_32()) { cmpd(); } else { cmpw(); } } /****************************************************************************** * * TEST - Logical Compare * *****************************************************************************/ /* TODO: merge with AND */ static inline void sset_flags_for_test(void) { sset_CF(0); sset_OF(0); sset_AF(0); /* undefined */ sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void testb(void) { t0 = (t1 & t2) & 0xff; sset_flags_for_test(); sset_SF(t0 >= 0x80); } static inline void testw(void) { t0 = (t1 & t2) & 0xffff; sset_flags_for_test(); sset_SF(t0 >= 0x8000); } static inline void testd(void) { t0 = t1 & t2; sset_flags_for_test(); sset_SF(t0 >= 0x80000000); } static inline void testv(void) { if (operand_size_32()) { testd(); } else { testw(); } } /****************************************************************************** * * NOT - One's Complement Negation * ******************************************************************************/ static inline void notb(void) { t0 = ~t1; } static inline void notv(void) { t0 = ~t1; } /****************************************************************************** * * NEG - Two's Complement Negation * ******************************************************************************/ static inline void sset_flags_for_neg(void) { sset_CF(t1 != 0); sset_AF((t0 & 0xf) != 0); sset_ZF(t0 == 0); sset_PF(parity(t0)); } static inline void negb(void) { t0 = -t1 & 0xff; sset_OF(t0 == 0x80); sset_SF(t0 >= 0x80); sset_flags_for_neg(); } static inline void negw(void) { t0 = -t1 & 0xffff; sset_OF(t0 == 0x8000); sset_SF(t0 >= 0x8000); sset_flags_for_neg(); } static inline void negd(void) { t0 = -t1; sset_OF(t0 == 0x80000000); sset_SF(t0 >= 0x80000000); sset_flags_for_neg(); } static inline void negv(void) { if (operand_size_32()) { negd(); } else { negw(); } } /****************************************************************************** * * MUL - Unsigned Multiply * ******************************************************************************/ static inline void mulb(void) { uint8_t product8l, product8h; uint32_t product16; product16 = get_AL() * (uint8_t) t1; product8l = product16 & 0xff; product8h = product16 >> 8; sset_CF(product8h != 0); sset_ZF(product8l == 0); sset_SF(product8l >= 0x80); sset_OF(product8h != 0); sset_AF(0); sset_PF(parity(product8l)); set_AX(product16); } static inline void mulw(void) { uint16_t product16l, product16h; uint32_t product32; product32 = get_AX() * (uint16_t) t1; product16l = product32 & 0xffff; product16h = product32 >> 16; sset_CF(product16h != 0); sset_ZF(product16l == 0); sset_SF(product16l >= 0x8000); sset_OF(product16h != 0); sset_AF(0); sset_PF(parity(product16l)); set_AX(product16l); set_DX(product16h); } static inline void muld(void) { uint32_t product32l, product32h; uint64_t product64; product64 = (uint64_t) get_EAX() * (uint64_t) t1; product32l = product64 & 0xffffffff; product32h = product64 >> 32; sset_CF(product32h != 0); sset_ZF(product32l == 0); sset_SF(product32l >= 0x80000000); sset_OF(product32h != 0); sset_AF(0); sset_PF(parity(product32l)); set_EAX(product32l); set_EDX(product32h); } static inline void mulv(void) { if (operand_size_32()) { muld(); } else { mulw(); } } /****************************************************************************** * * IMUL - Signed Multiply * ******************************************************************************/ static inline void imul1b(void) { int8_t op2, op1; int16_t product16; uint8_t product8l, product8h; bool cf; op1 = get_AL(); op2 = t1; product16 = op1 * op2; product8l = product16 & 0xff; product8h = product16 >> 8; cf = !(((product8l < 0x80) && (product8h == 0)) || ((product8l & 0x80) && (product8h == 0xff))); sset_CF(cf); sset_OF(cf); sset_AF(0); /* undefined */ sset_ZF(product8l == 0); /* undefined */ sset_SF(product8l >= 0x80); /* undefined */ sset_PF(parity(product8l)); /* undefined */ set_AX(product16); } static inline void imul1w(void) { int16_t op1, op2; int32_t product32; uint16_t product16l, product16h; bool cf; op1 = get_AX(); op2 = t1; product32 = op1 * op2; product16l = product32 & 0xffff; product16h = product32 >> 16; cf = !(((product16l < 0x8000) && (product16h == 0)) || ((product16l & 0x8000) && (product16h == 0xffff))); sset_CF(cf); sset_OF(cf); sset_AF(0); /* undefined */ sset_ZF(product16l == 0); /* undefined */ sset_SF(product16l >= 0x8000); /* undefined */ sset_PF(parity(product16l)); /* undefined */ set_AX(product16l); set_DX(product16h); } static inline void imul1d(void) { int32_t op1, op2; int64_t product64; uint32_t product32l, product32h; bool cf; op1 = get_EAX(); op2 = t1; product64 = ((int64_t) op1) * ((int64_t) op2); product32l = product64 & 0xffffffff; product32h = product64 >> 32; cf = !(((product32l < 0x80000000) && (product32h == 0)) || ((product32l & 0x80000000) && (product32h == 0xffffffff))); sset_CF(cf); sset_OF(cf); sset_AF(0); /* undefined */ sset_ZF(product32l == 0); /* undefined */ sset_SF(product32l >= 0x80000000); /* undefined */ sset_PF(parity(product32l)); /* undefined */ set_EAX(product32l); set_EDX(product32h); } static inline void imul1v(void) { if (operand_size_32()) { imul1d(); } else { imul1w(); } } /******************************************************************************/ static inline void imul3ww(void) { int16_t op1, op2; int32_t product32; uint16_t product16l, product16h; bool cf; op1 = t1; op2 = t2; product32 = op1 * op2; product16l = product32 & 0xffff; product16h = product32 >> 16; t0 = product16l; cf = !(((product16l < 0x8000) && (product16h == 0)) || ((product16l & 0x8000) && (product16h == 0xffff))); sset_CF(cf); sset_OF(cf); sset_AF(0); /* undefined */ sset_SF(product16l >= 0x8000); /* undefined */ sset_ZF(product16l == 0); /* undefined */ sset_PF(parity(product16l)); /* undefined */ } static inline void imul3dd(void) { int32_t op1, op2; int64_t product64; uint32_t product32l, product32h; bool cf; op1 = t1; op2 = t2; product64 = ((int64_t) op1) * ((int64_t) op2); product32l = product64 & 0xffffffff; product32h = product64 >> 32; t0 = product32l; cf = !(((product32l < 0x80000000) && (product32h == 0)) || ((product32l & 0x80000000) && (product32h == 0xffffffff))); sset_CF(cf); sset_OF(cf); sset_AF(0); /* undefined */ sset_SF(product32l >= 0x8000); /* undefined */ sset_ZF(product32l == 0); /* undefined */ sset_PF(parity(product32l)); /* undefined */ } static inline void imul3vv(void) { if (operand_size_32()) { imul3dd(); } else { imul3ww(); } } /******************************************************************************/ static inline void imul3wb(void) { t2 = (int16_t) (int8_t) t2; imul3ww(); } static inline void imul3db(void) { t2 = (int32_t) (int8_t) t2; imul3dd(); } static inline void imul3vb(void) { if (operand_size_32()) { imul3db(); } else { imul3wb(); } } /******************************************************************************/ static inline void imul2v(void) { imul3vv(); } /****************************************************************************** * * DIV - Unsigned Divide * ******************************************************************************/ static inline void sset_flags_for_div(void) { sset_CF(0); /* undefined */ sset_OF(0); /* undefined */ sset_SF(0); /* undefined */ sset_ZF(0); /* undefined */ sset_AF(0); /* undefined */ sset_PF(0); /* undefined */ } static inline void divb(void) { uint8_t remainder8, quotient8; uint16_t operand16, quotient16; operand16 = get_AX(); if (t1 == 0) { exception(EXCEPTION_DE, -1); } quotient16 = operand16 / (uint8_t) t1; remainder8 = operand16 % (uint8_t) t1; quotient8 = quotient16 & 0xff; if (quotient16 != quotient8) { exception(EXCEPTION_DE, -1); } sset_flags_for_div(); set_AL(quotient8); set_AH(remainder8); } static inline void divw(void) { uint16_t remainder16, quotient16; uint32_t operand32, quotient32; operand32 = (get_DX() << 16) | get_AX(); if (t1 == 0) { exception(EXCEPTION_DE, -1); } quotient32 = operand32 / (uint16_t) t1; remainder16 = operand32 % (uint16_t) t1; quotient16 = quotient32 & 0xffff; if (quotient32 != quotient16) { exception(EXCEPTION_DE, -1); } sset_flags_for_div(); set_AX(quotient16); set_DX(remainder16); } static inline void divd(void) { uint32_t remainder32, quotient32; uint64_t operand64, quotient64; operand64 = (((uint64_t) get_EDX()) << 32) + (uint64_t) get_EAX(); if (t1 == 0) { exception(EXCEPTION_DE, -1); } quotient64 = operand64 / t1; remainder32 = (uint32_t) (operand64 % t1); quotient32 = (uint32_t) (quotient64 & 0xffffffff); if (quotient64 != quotient32) { exception(EXCEPTION_DE, -1); } sset_flags_for_div(); set_EAX(quotient32); set_EDX(remainder32); } static inline void divv(void) { if (operand_size_32()) { divd(); } else { divw(); } } /****************************************************************************** * * IDIV - Signed Divide * ******************************************************************************/ static inline void sset_flags_for_idiv(void) { sset_CF(0); /* undefined */ sset_OF(0); /* undefined */ sset_SF(0); /* undefined */ sset_ZF(0); /* undefined */ sset_AF(0); /* undefined */ sset_PF(0); /* undefined */ } static inline void idivb(void) { int8_t op2, quotient8l, remainder8; int16_t op1, quotient16; op1 = get_AX(); op2 = t1; if (op2 == 0) { exception(EXCEPTION_DE, -1); } if ((op1 == ((int16_t) 0x8000)) && (op2 == -1)) { exception(EXCEPTION_DE, -1); } quotient16 = op1 / op2; remainder8 = op1 % op2; quotient8l = quotient16 & 0xff; if (quotient16 != quotient8l) { exception(EXCEPTION_DE, -1); } sset_flags_for_idiv(); set_AL(quotient8l); set_AH(remainder8); } static inline void idivw(void) { int16_t op2, remainder16, quotient16l; int32_t op1, quotient32; op1 = ((get_DX() & 0xffff) << 16) | (get_AX() & 0xffff); op2 = t1; if (op2 == 0) { exception(EXCEPTION_DE, -1); } if ((op1 == ((int32_t) 0x80000000)) && (op2 == -1)) { exception(EXCEPTION_DE, -1); } quotient32 = op1 / op2; remainder16 = op1 / op2; quotient16l = quotient32 & 0xffff; if (quotient32 != quotient16l) { exception(EXCEPTION_DE, -1); } sset_flags_for_idiv(); set_AX(quotient16l); set_DX(remainder16); } static inline void idivd(void) { int32_t op2, remainder32, quotient32l; int64_t op1, quotient64; op1 = ((uint64_t) get_EDX() << 32) | get_EAX(); op2 = t1; if (op2 == 0) { exception(EXCEPTION_DE, -1); } if ((op1 == ((int64_t) 0x8000000000000000ULL)) && (op2 == -1)) { exception(EXCEPTION_DE, -1); } quotient64 = op1 / op2; remainder32 = (int32_t) (op1 % op2); quotient32l = (int32_t) (quotient64 & 0xffffffff); if (quotient64 != quotient32l) { exception(EXCEPTION_DE, -1); } sset_flags_for_idiv(); set_EAX(quotient32l); set_EDX(remainder32); } static inline void idivv(void) { if (operand_size_32()) { idivd(); } else { idivw(); } } /****************************************************************************** * * XCHG - Exchange Register/Memory with Register * ******************************************************************************/ static inline void xchg(void) { uint32_t t; t = t1; t1 = t2; t2 = t; } /****************************************************************************** * * MOV * ******************************************************************************/ static inline void movb(void) { t0 = t1; } static inline void movw(void) { t0 = t1; } static inline void movd(void) { t0 = t1; } static inline void movv(void) { if (operand_size_32()) { movd(); } else { movw(); } } /****************************************************************************** * * MOVS/MOVSB/MOVSW/MOVSD - Move Data from String to String * ******************************************************************************/ #define REP_CHECK() \ if (prefix_lock_repeat == LR_REPZ) { \ if (address_size_32()) { \ if (get_ECX() == 0) { \ return; \ } \ } else { \ if (get_CX() == 0) { \ return; \ } \ } \ } #define REP_DECREMENT() \ if (prefix_lock_repeat == LR_REPZ) { \ revert_EIP(); \ if (address_size_32()) { \ set_ECX(get_ECX() - 1); \ } else { \ set_CX(get_CX() - 1); \ } \ } static inline void movsb(void) { REP_CHECK(); load_Xb(); t0 = t1; store_Yb(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 1); set_EDI(get_EDI() - 1); } else { set_ESI(get_ESI() + 1); set_EDI(get_EDI() + 1); } } else { if (get_DF()) { set_SI(get_SI() - 1); set_DI(get_DI() - 1); } else { set_SI(get_SI() + 1); set_DI(get_DI() + 1); } } REP_DECREMENT(); } static inline void movsw(void) { REP_CHECK(); load_Xw(); t0 = t1; store_Yw(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 2); set_EDI(get_EDI() - 2); } else { set_ESI(get_ESI() + 2); set_EDI(get_EDI() + 2); } } else { if (get_DF()) { set_SI(get_SI() - 2); set_DI(get_DI() - 2); } else { set_SI(get_SI() + 2); set_DI(get_DI() + 2); } } REP_DECREMENT(); } static inline void movsd(void) { REP_CHECK(); load_Xd(); t0 = t1; store_Yd(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 4); set_EDI(get_EDI() - 4); } else { set_ESI(get_ESI() + 4); set_EDI(get_EDI() + 4); } } else { if (get_DF()) { set_SI(get_SI() - 4); set_DI(get_DI() - 4); } else { set_SI(get_SI() + 4); set_DI(get_DI() + 4); } } REP_DECREMENT(); } static inline void movsv(void) { if (operand_size_32()) { movsd(); } else { movsw(); } } /****************************************************************************** * * LODS/LODSB/LODSW/LODSD - Load String * ******************************************************************************/ static inline void lodsb(void) { REP_CHECK(); load_Xb(); t0 = t1; store_AL(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 1); } else { set_ESI(get_ESI() + 1); } } else { if (get_DF()) { set_SI(get_SI() - 1); } else { set_SI(get_SI() + 1); } } REP_DECREMENT(); } static inline void lodsw(void) { REP_CHECK(); load_Xw(); t0 = t1; store_eAX(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 2); } else { set_ESI(get_ESI() + 2); } } else { if (get_DF()) { set_SI(get_SI() - 2); } else { set_SI(get_SI() + 2); } } REP_DECREMENT(); } static inline void lodsd(void) { REP_CHECK(); load_Xd(); t0 = t1; store_eAX(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 4); } else { set_ESI(get_ESI() + 4); } } else { if (get_DF()) { set_SI(get_SI() - 4); } else { set_SI(get_SI() + 4); } } REP_DECREMENT(); } static inline void lodsv(void) { if (operand_size_32()) { lodsd(); } else { lodsw(); } } /****************************************************************************** * * OUTS/OUTSB/OUTSW/OUTSD - Output String to Port * ******************************************************************************/ static inline void outsb(void) { REP_CHECK(); load_DX_Xb(); outb(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 1); } else { set_ESI(get_ESI() + 1); } } else { if (get_DF()) { set_SI(get_SI() - 1); } else { set_SI(get_SI() + 1); } } REP_DECREMENT(); } static inline void outsw(void) { REP_CHECK(); load_DX_Xw(); outw(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 2); } else { set_ESI(get_ESI() + 2); } } else { if (get_DF()) { set_SI(get_SI() - 2); } else { set_SI(get_SI() + 2); } } REP_DECREMENT(); } static inline void outsd(void) { REP_CHECK(); load_DX_Xd(); outd(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 4); } else { set_ESI(get_ESI() + 4); } } else { if (get_DF()) { set_SI(get_SI() - 4); } else { set_SI(get_SI() + 4); } } REP_DECREMENT(); } static inline void outsv(void) { if (operand_size_32()) { outsd(); } else { outsw(); } } /****************************************************************************** * * STOS/STOSB/STOSW/STOSD - Store String * ******************************************************************************/ static inline void stosb(void) { REP_CHECK(); load_AL(); t0 = t1; store_Yb(); if (address_size_32()) { if (get_DF()) { set_EDI(get_EDI() - 1); } else { set_EDI(get_EDI() + 1); } } else { if (get_DF()) { set_DI(get_DI() - 1); } else { set_DI(get_DI() + 1); } } REP_DECREMENT(); } static inline void stosw(void) { REP_CHECK(); load_eAX(); t0 = t1; store_Yw(); if (address_size_32()) { if (get_DF()) { set_EDI(get_EDI() - 2); } else { set_EDI(get_EDI() + 2); } } else { if (get_DF()) { set_DI(get_DI() - 2); } else { set_DI(get_DI() + 2); } } REP_DECREMENT(); } static inline void stosd(void) { REP_CHECK(); load_eAX(); t0 = t1; store_Yd(); if (address_size_32()) { if (get_DF()) { set_EDI(get_EDI() - 4); } else { set_EDI(get_EDI() + 4); } } else { if (get_DF()) { set_DI(get_DI() - 4); } else { set_DI(get_DI() + 4); } } REP_DECREMENT(); } static inline void stosv(void) { if (operand_size_32()) { stosd(); } else { stosw(); } } /****************************************************************************** * * INS/INSB/INSW/INSD - Input from Port to String * ******************************************************************************/ static inline void insb(void) { REP_CHECK(); load_DX(); inb(); store_Yb(); if (address_size_32()) { if (get_DF()) { set_EDI(get_EDI() - 1); } else { set_EDI(get_EDI() + 1); } } else { if (get_DF()) { set_DI(get_DI() - 1); } else { set_DI(get_DI() + 1); } } REP_DECREMENT(); } static inline void insw(void) { REP_CHECK(); load_DX(); inw(); store_Yw(); if (address_size_32()) { if (get_DF()) { set_EDI(get_EDI() - 2); } else { set_EDI(get_EDI() + 2); } } else { if (get_DF()) { set_DI(get_DI() - 2); } else { set_DI(get_DI() + 2); } } REP_DECREMENT(); } static inline void insd(void) { REP_CHECK(); load_DX(); ind(); store_Yd(); if (address_size_32()) { if (get_DF()) { set_EDI(get_EDI() - 4); } else { set_EDI(get_EDI() + 4); } } else { if (get_DF()) { set_DI(get_DI() - 4); } else { set_DI(get_DI() + 4); } } REP_DECREMENT(); } static inline void insv(void) { if (operand_size_32()) { insd(); } else { insw(); } } /****************************************************************************** * * CMPS/CMPSB/CMPSW/CMPSD - Compare String Operands * ******************************************************************************/ #define REPZ_REPNZ_CHECK() \ if ((prefix_lock_repeat == LR_REPZ) \ || (prefix_lock_repeat == LR_REPNZ)) { \ if (address_size_32()) { \ if (get_ECX() == 0) { \ return; \ } \ } else { \ if (get_CX() == 0) { \ return; \ } \ } \ } #define REPZ_REPNZ_DECREMENT() \ commit_OSZAPC(); \ if ((prefix_lock_repeat == LR_REPZ) \ || (prefix_lock_repeat == LR_REPNZ)) { \ bool break_condition = get_ZF(); \ if (prefix_lock_repeat == LR_REPZ) { \ break_condition = !break_condition; \ } \ if (!break_condition) { \ revert_EIP(); \ } \ if (address_size_32()) { \ set_ECX(get_ECX() - 1); \ } else { \ set_CX(get_CX() - 1); \ } \ } static inline void cmpsb(void) { REPZ_REPNZ_CHECK(); load_Xb_Yb(); cmpb(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 1); set_EDI(get_EDI() - 1); } else { set_ESI(get_ESI() + 1); set_EDI(get_EDI() + 1); } } else { if (get_DF()) { set_SI(get_SI() - 1); set_DI(get_DI() - 1); } else { set_SI(get_SI() + 1); set_DI(get_DI() + 1); } } REPZ_REPNZ_DECREMENT(); } static inline void cmpsw(void) { REPZ_REPNZ_CHECK(); load_Xw_Yw(); cmpw(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 2); set_EDI(get_EDI() - 2); } else { set_ESI(get_ESI() + 2); set_EDI(get_EDI() + 2); } } else { if (get_DF()) { set_SI(get_SI() - 2); set_DI(get_DI() - 2); } else { set_SI(get_SI() + 2); set_DI(get_DI() + 2); } } REPZ_REPNZ_DECREMENT(); } static inline void cmpsd(void) { REPZ_REPNZ_CHECK(); load_Xd_Yd(); cmpd(); if (address_size_32()) { if (get_DF()) { set_ESI(get_ESI() - 4); set_EDI(get_EDI() - 4); } else { set_ESI(get_ESI() + 4); set_EDI(get_EDI() + 4); } } else { if (get_DF()) { set_SI(get_SI() - 4); set_DI(get_DI() - 4); } else { set_SI(get_SI() + 4); set_DI(get_DI() + 4); } } REPZ_REPNZ_DECREMENT(); } static inline void cmpsv(void) { if (operand_size_32()) { cmpsd(); } else { cmpsw(); } } /****************************************************************************** * * SCAS/SCASB/SCASW/SCASD - Scan String * ******************************************************************************/ static inline void scasb(void) { REPZ_REPNZ_CHECK(); load_AL_Yb(); cmpb(); if (address_size_32()) { if (get_DF()) { set_EDI(get_EDI() - 1); } else { set_EDI(get_EDI() + 1); } } else { if (get_DF()) { set_DI(get_DI() - 1); } else { set_DI(get_DI() + 1); } } REPZ_REPNZ_DECREMENT(); } static inline void scasw(void) { REPZ_REPNZ_CHECK(); load_AX_Yw(); cmpw(); if (address_size_32()) { if (get_DF()) { set_EDI(get_EDI() - 2); } else { set_EDI(get_EDI() + 2); } } else { if (get_DF()) { set_DI(get_DI() - 2); } else { set_DI(get_DI() + 2); } } REPZ_REPNZ_DECREMENT(); } static inline void scasd(void) { REPZ_REPNZ_CHECK(); load_EAX_Yd(); cmpd(); if (address_size_32()) { if (get_DF()) { set_EDI(get_EDI() - 4); } else { set_EDI(get_EDI() + 4); } } else { if (get_DF()) { set_DI(get_DI() - 4); } else { set_DI(get_DI() + 4); } } REPZ_REPNZ_DECREMENT(); } static inline void scasv(void) { if (operand_size_32()) { scasd(); } else { scasw(); } } /****************************************************************************** * * LEA * ******************************************************************************/ static inline void lea(void) { t0 = t1; } /****************************************************************************** * * MOVZX - Move with Zero-Extend * ******************************************************************************/ static inline void movzxb(void) { t0 = t1 & 0xff; } static inline void movzxw(void) { t0 = t1 & 0xffff; } /****************************************************************************** * * MOVSX - Move with Sign-Extension * ******************************************************************************/ static inline void movsxb(void) { int16_t t; t = (int8_t) t1; t0 = (uint32_t) t; } static inline void movsxw(void) { int32_t t; if (operand_size_32()) { t = (int16_t) t1; } else { t = (int8_t) t1; } t0 = (uint32_t) t; } /****************************************************************************** * * LDS/LES/LFS/LGS/LSS * ******************************************************************************/ static inline void lds(void) { t0 = t1; set_DS(t2); } static inline void les(void) { t0 = t1; set_ES(t2); } static inline void lfs(void) { t0 = t1; set_FS(t2); } static inline void lgs(void) { t0 = t1; set_GS(t2); } static inline void lss(void) { t0 = t1; set_SS(t2); } /****************************************************************************** * * PUSH - Push Word or Doubleword Onto the Stack * ******************************************************************************/ static inline void push32(uint32_t value) { if (stack_size_32()) { set_ESP(get_ESP() - 4); mwd_seg(get_ESP(), value, SEGMENT_SS); } else { set_SP(get_SP() - 4); mwd_seg(get_SP(), value, SEGMENT_SS); } } static inline void push16(uint16_t value) { if (stack_size_32()) { set_ESP(get_ESP() - 2); mww_seg(get_ESP(), value, SEGMENT_SS); } else { set_SP(get_SP() - 2); mww_seg(get_SP(), value, SEGMENT_SS); } } static inline void pushv(void) { if (operand_size_32()) { push32(t1); } else { push16(t1); } } /****************************************************************************** * * PUSHA - Push All General-Purpose Registers * ******************************************************************************/ static inline void pushav(void) { if (operand_size_32()) { uint32_t temp_esp; temp_esp = get_ESP(); push32(get_EAX()); push32(get_ECX()); push32(get_EDX()); push32(get_EBX()); push32(temp_esp); push32(get_EBP()); push32(get_ESI()); push32(get_EDI()); } else { uint16_t temp_sp; temp_sp = get_SP(); push16(get_AX()); push16(get_CX()); push16(get_DX()); push16(get_BX()); push16(temp_sp); push16(get_BP()); push16(get_SI()); push16(get_DI()); } } /****************************************************************************** * * POP - Pop a Value from the Stack * ******************************************************************************/ static inline uint32_t pop32(void) { uint32_t value; if (stack_size_32()) { value = mrd_seg(get_ESP(), SEGMENT_SS); set_ESP(get_ESP() + 4); } else { value = mrd_seg(get_SP(), SEGMENT_SS); set_SP(get_SP() + 4); } return value; } static inline uint16_t pop16(void) { uint16_t value; if (stack_size_32()) { value = mrw_seg(get_ESP(), SEGMENT_SS); set_ESP(get_ESP() + 2); } else { value = mrw_seg(get_SP(), SEGMENT_SS); set_SP(get_SP() + 2); } return value; } static inline void popv(void) { if (operand_size_32()) { t0 = pop32(); } else { t0 = pop16(); } } /****************************************************************************** * * POPA/POPAD - Pop All General-Purpose Registers * ******************************************************************************/ static inline void popa(void) { if (operand_size_32()) { uint32_t temp_edi; uint32_t temp_esi; uint32_t temp_ebp; /* no esp */ uint32_t temp_ebx; uint32_t temp_edx; uint32_t temp_ecx; uint32_t temp_eax; temp_edi = pop32(); temp_esi = pop32(); temp_ebp = pop32(); pop32(); temp_ebx = pop32(); temp_edx = pop32(); temp_ecx = pop32(); temp_eax = pop32(); set_EDI(temp_edi); set_ESI(temp_esi); set_EBP(temp_ebp); /* esp no set */ set_EBX(temp_ebx); set_EDX(temp_edx); set_ECX(temp_ecx); set_EAX(temp_eax); } else { uint16_t temp_di; uint16_t temp_si; uint16_t temp_bp; /* no sp */ uint16_t temp_bx; uint16_t temp_dx; uint16_t temp_cx; uint16_t temp_ax; temp_di = pop16(); temp_si = pop16(); temp_bp = pop16(); pop16(); temp_bx = pop16(); temp_dx = pop16(); temp_cx = pop16(); temp_ax = pop16(); set_DI(temp_di); set_SI(temp_si); set_BP(temp_bp); /* sp not set */ set_BX(temp_bx); set_DX(temp_dx); set_CX(temp_cx); set_AX(temp_ax); } } /****************************************************************************** * * Jcc - Jump if Condition is Met * ******************************************************************************/ static inline void jcc(void) { eip_new += tj; /* TODO: segment limit */ if (!operand_size_32()) { eip_new &= 0xffff; } } static inline void jo(void) { if (get_OF()) { jcc(); } } static inline void jno(void) { if (!get_OF()) { jcc(); } } static inline void jb(void) { if (get_CF()) { jcc(); } } static inline void jnb(void) { if (!get_CF()) { jcc(); } } static inline void jz(void) { if (get_ZF()) { jcc(); } } static inline void jnz(void) { if (!get_ZF()) { jcc(); } } static inline void jbe(void) { if (get_CF() || get_ZF()) { jcc(); } } static inline void jnbe(void) { if (!(get_CF() || get_ZF())) { jcc(); } } static inline void js(void) { if (get_SF()) { jcc(); } } static inline void jns(void) { if (!get_SF()) { jcc(); } } static inline void jp(void) { if (get_PF()) { jcc(); } } static inline void jnp(void) { if (!get_PF()) { jcc(); } } static inline void jl(void) { if (get_SF() != get_OF()) { jcc(); } } static inline void jnl(void) { if (get_SF() == get_OF()) { jcc(); } } static inline void jle(void) { if (get_ZF() || (get_SF() != get_OF())) { jcc(); } } static inline void jnle(void) { if (!(get_ZF() || (get_SF() != get_OF()))) { jcc(); } } static inline void jcxz(void) { if (get_CX() == 0) { jcc(); } } static inline void jecxz(void) { if (get_ECX() == 0) { jcc(); } } /****************************************************************************** * * SETcc - Set Byte on Condition * ******************************************************************************/ static inline void seto(void) { t0 = get_OF(); } static inline void setno(void) { t0 = !get_OF(); } static inline void setb(void) { t0 = get_CF(); } static inline void setnb(void) { t0 = !get_CF(); } static inline void setz(void) { t0 = get_ZF(); } static inline void setnz(void) { t0 = !get_ZF(); } static inline void setbe(void) { t0 = get_CF() || get_ZF(); } static inline void setnbe(void) { t0 = !(get_CF() || get_ZF()); } static inline void sets(void) { t0 = get_SF(); } static inline void setns(void) { t0 = !get_SF(); } static inline void setp(void) { t0 = get_PF(); } static inline void setnp(void) { t0 = !get_PF(); } static inline void setl(void) { t0 = get_SF() != get_OF(); } static inline void setnl(void) { t0 = get_SF() == get_OF(); } static inline void setle(void) { t0 = get_ZF() || (get_SF() != get_OF()); } static inline void setnle(void) { t0 = !(get_ZF() || (get_SF() != get_OF())); } /****************************************************************************** * * LAHF - Load Status Flags into AH Register * ******************************************************************************/ static inline void lahf(void) { set_AH(get_EFLAGS8()); } /****************************************************************************** * * SAHF - Store AH into Flags * ******************************************************************************/ static inline void sahf(void) { sset_EFLAGS8(get_AH()); commit_EFLAGS8(); } /****************************************************************************** * * PUSHF/PUSHFD - Push EFLAGS Register onto the Stack * ******************************************************************************/ static inline void pushf(void) { if (virtual8086_mode()) { if (get_IOPL() < 3) { exception(EXCEPTION_GP, 0); } } if (operand_size_32()) { push32(get_EFLAGS32() & 0x00fcffff); } else { push16(get_EFLAGS16()); } } /****************************************************************************** * * POPF/POPFD - Pop Stack into EFLAGS Register * ******************************************************************************/ static inline void popf(void) { uint32_t mask; mask = 0; mask |= 1 << EFLAG_CF; mask |= 1 << EFLAG_PF; mask |= 1 << EFLAG_AF; mask |= 1 << EFLAG_ZF; mask |= 1 << EFLAG_SF; mask |= 1 << EFLAG_TF; mask |= 1 << EFLAG_DF; mask |= 1 << EFLAG_OF; mask |= 1 << EFLAG_NT; if (real_mode()) { mask |= 1 << EFLAG_IF; mask |= 1 << EFLAG_IOPL0; mask |= 1 << EFLAG_IOPL1; } else if (protected_mode()) { if (get_CPL() == 0) { mask |= 1 << EFLAG_IOPL0; mask |= 1 << EFLAG_IOPL1; } if (get_CPL() <= get_IOPL()) { mask |= 1 << EFLAG_IF; } } else { /* virtual8086_mode */ if (get_IOPL() < 3) { exception(EXCEPTION_GP, 0); } mask |= 1 << EFLAG_IF; } if (operand_size_32()) { mask |= 1 << EFLAG_RF; mask |= 1 << EFLAG_AC; sset_EFLAGS32((pop32() & mask) | (get_EFLAGS32() & ~mask)); commit_EFLAGS32(); } else { sset_EFLAGS16((pop16() & mask) | (get_EFLAGS16() & ~mask)); commit_EFLAGS16(); } } /****************************************************************************** * * CWD/CDQ - Convert Word to Doubleword/Convert Doubleword to Quadword * ******************************************************************************/ static inline void cwd(void) { if (get_AX() & 0x8000) { set_DX(0xffff); } else { set_DX(0x0000); } } static inline void cdq(void) { if (get_EAX() & 0x80000000) { set_EDX(0xffffffff); } else { set_EDX(0x00000000); } } /****************************************************************************** * * CBW/CWDE - Convert Byte to Word/Convert Word to Doubleword * ******************************************************************************/ static inline void cbw(void) { set_AX((int8_t) get_AL()); } static inline void cwde(void) { set_EAX((int16_t) get_AX()); } /****************************************************************************** * * AAA - ASCII Adjust After Addition * ******************************************************************************/ static inline void aaa(void) { /* TODO */ ERROR_NYI(); } /****************************************************************************** * * AAS - ASCII Adjust AL After Substraction * ******************************************************************************/ static inline void aas(void) { /* TODO */ ERROR_NYI(); } /****************************************************************************** * * DAA - Decimal Adjust AL after Addition * * Flags: CF, AF, SF, ZF, PF, OF * Exceptions: None * ******************************************************************************/ static inline void daa(void) { uint8_t al; bool af, cf; al = get_AL(); af = get_AF(); cf = get_CF(); if (((al & 0x0f) > 9) || af) { cf = ((al > 0xf9) || cf); af = 1; al += 6; } else { af = 0; } if (((al & 0xf0) > 0x90) || cf) { al += 0x60; cf = 1; } else { cf = 0; } set_AL(al); sset_AF(af); sset_CF(cf); sset_PF(parity(al)); sset_ZF(al == 0); sset_SF(al >= 0x80); sset_OF(0); /* undefined */ } /****************************************************************************** * * DAS - Decimal Adjust AL after Substraction * ******************************************************************************/ static inline void das(void) { /* TODO */ ERROR_NYI(); } /****************************************************************************** * * AAM - ASCII Adjust AX After Multiply * ******************************************************************************/ static inline void aam(void) { uint8_t al; if (t1 == 0) { exception(EXCEPTION_DE, -1); } al = get_AL(); set_AH(al / (uint8_t) t1); al = al % (uint8_t) t1; set_AL(al); sset_OF(0); /* Undefined */ sset_AF(0); /* Undefined */ sset_CF(0); /* Undefined */ sset_SF(al >= 0x80); sset_ZF(al == 0); sset_PF(parity(al)); } /****************************************************************************** * * AAD - ASCII Adjust AX Before Division * ******************************************************************************/ static inline void aad(void) { uint16_t tmp; tmp = get_AH(); tmp *= (uint8_t) t1; tmp += get_AL(); tmp &= 0xff; set_AL(tmp); set_AH(0); sset_OF(0); /* Undefined */ sset_AF(0); /* Undefined */ sset_CF(0); /* Undefined */ sset_SF(tmp >= 0x80); sset_ZF(tmp == 0); sset_PF(parity(tmp)); } /****************************************************************************** * * CPUID - CPU Identification * ******************************************************************************/ #if 0 #define CONFIG_CPU_FPU_SUPPORT 0 #define CONFIG_CPU_VME_SUPPORT 0 #define CONFIG_CPU_DE_SUPPORT 0 #define CONFIG_CPU_PSE_SUPPORT 0 #define CONFIG_CPU_TSC_SUPPORT 0 #define CONFIG_CPU_MSR_SUPPORT 0 #define CONFIG_CPU_PAE_SUPPORT 0 #define CONFIG_CPU_MCE_SUPPORT 0 #define CONFIG_CPU_CX8_SUPPORT 0 #define CONFIG_CPU_APIC_SUPPORT 0 /* Bit 10 is reserved. */ #define CONFIG_CPU_SEP_SUPPORT 0 #define CONFIG_CPU_MTRR_SUPPORT 0 #define CONFIG_CPU_PGE_SUPPORT 0 #define CONFIG_CPU_MCA_SUPPORT 0 #define CONFIG_CPU_CMOV_SUPPORT 0 #define CONFIG_CPU_PAT_SUPPORT 0 #define CONFIG_CPU_PSE36_SUPPORT 0 #define CONFIG_CPU_PSN_SUPPORT 0 #define CONFIG_CPU_CFLSH_SUPPORT 0 /* Bit 20 is reserved. */ #define CONFIG_CPU_DS_SUPPORT 0 #define CONFIG_CPU_ACPI_SUPPORT 0 #define CONFIG_CPU_MMX_SUPPORT 0 #define CONFIG_CPU_FXSR_SUPPORT 0 #define CONFIG_CPU_SSE_SUPPORT 0 #define CONFIG_CPU_SSE2_SUPPORT 0 #define CONFIG_CPU_SS_SUPPORT 0 #define CONFIG_CPU_HTT_SUPPORT 0 #define CONFIG_CPU_TM_SUPPORT 0 /* Bit 30 is reserved. */ #define CONFIG_CPU_PBE_SUPPORT 0 static inline void cpuid(void) { /* FIXME */ switch (get_EAX()) { default: case 0: eax = 2; ebx = 0x756e6547; /* "GenuineIntel" */ ecx = 0x6c65746e; edx = 0x49656e69; break; case 1: eax = 0x00000634; /* CPU Version */ ebx = 0x00000000; ecx = 0x00000000; edx = CONFIG_CPU_FPU_SUPPORT << 0 | CONFIG_CPU_VME_SUPPORT << 1 | CONFIG_CPU_DE_SUPPORT << 2 | CONFIG_CPU_PSE_SUPPORT << 3 | CONFIG_CPU_TSC_SUPPORT << 4 | CONFIG_CPU_MSR_SUPPORT << 5 | CONFIG_CPU_PAE_SUPPORT << 6 | CONFIG_CPU_MCE_SUPPORT << 7 | CONFIG_CPU_CX8_SUPPORT << 8 | CONFIG_CPU_APIC_SUPPORT << 9 | CONFIG_CPU_SEP_SUPPORT << 11 | CONFIG_CPU_MTRR_SUPPORT << 12 | CONFIG_CPU_PGE_SUPPORT << 13 | CONFIG_CPU_MCA_SUPPORT << 14 | CONFIG_CPU_CMOV_SUPPORT << 15 | CONFIG_CPU_PAT_SUPPORT << 16 | CONFIG_CPU_PSE36_SUPPORT << 17 | CONFIG_CPU_PSN_SUPPORT << 18 | CONFIG_CPU_CFLSH_SUPPORT << 19 | CONFIG_CPU_DS_SUPPORT << 21 | CONFIG_CPU_ACPI_SUPPORT << 22 | CONFIG_CPU_MMX_SUPPORT << 23 | CONFIG_CPU_FXSR_SUPPORT << 24 | CONFIG_CPU_SSE_SUPPORT << 25 | CONFIG_CPU_SSE2_SUPPORT << 26 | CONFIG_CPU_SS_SUPPORT << 27 | CONFIG_CPU_HTT_SUPPORT << 28 | CONFIG_CPU_TM_SUPPORT << 29 | CONFIG_CPU_PBE_SUPPORT << 31; break; case 2: eax = 0x03020101; ebx = 0x00000000; ecx = 0x00000000; edx = 0x0c040843; break; } } #endif /****************************************************************************** * * WAIT/FWAIT - Wait * ******************************************************************************/ static inline void wait(void) { if (get_TS() && get_MP()) { exception(EXCEPTION_NM, -1); } } /****************************************************************************** * * LOOP/LOOPcc - Loop According to ECX Counter * ******************************************************************************/ static inline void loop(void) { uint32_t count; if (address_size_32()) { count = get_ECX() - 1; set_ECX(count); } else { count = get_CX() - 1; set_CX(count); } if (count != 0) { eip_new += tj; } if (!operand_size_32()) { eip_new &= 0xffff; } } static inline void loope(void) { uint32_t count; if (address_size_32()) { count = get_ECX() - 1; set_ECX(count); } else { count = get_CX() - 1; set_CX(count); } if (count != 0 && get_ZF()) { eip_new += tj; } if (!operand_size_32()) { eip_new &= 0xffff; } } static inline void loopne(void) { uint32_t count; if (address_size_32()) { count = get_ECX() - 1; set_ECX(count); } else { count = get_CX() - 1; set_CX(count); } if (count != 0 && !get_ZF()) { eip_new += tj; } if (!operand_size_32()) { eip_new &= 0xffff; } } /****************************************************************************** * * JMP - Jump * ******************************************************************************/ static inline void jmp_far_virtual8086_mode(void) { ERROR_NYI(); } static inline void jmp_far_protected_mode(void) { sset_CS(t2); if (descriptor_sflag) { if (operand_size_32()) { eip_new = t1; } else { eip_new = t1 & 0xffff; } } else { ERROR_NYI(); /* TODO */ } commit_CS(); } static inline void jmp_far_real_mode(void) { sset_CS(t2); if (operand_size_32()) { eip_new = t1; } else { eip_new = t1 & 0xffff; } commit_CS(); } static inline void jmp_far(void) { if (virtual8086_mode()) { jmp_far_virtual8086_mode(); } else if (protected_mode()) { jmp_far_protected_mode(); } else { jmp_far_real_mode(); } instruction_cache_flush(); } static inline void jmp_near(void) { eip_new += tj; if (!operand_size_32()) { eip_new &= 0xffff; } } static inline void jmp_near_absolute(void) { eip_new = t1; if (!operand_size_32()) { eip_new &= 0xffff; } } /****************************************************************************** * * CALL - Call Procedure * ******************************************************************************/ static inline void call_far_virtual8086_mode(void) { ERROR_NYI(); } static inline void call_far_protected_mode(void) { sset_CS(t2); if (descriptor_sflag) { if (operand_size_32()) { push32(get_CS()); push32(eip_new); eip_new = t1; } else { push16(get_CS()); push16(eip_new); eip_new = t1 & 0xffff; } commit_CS(); } else { ERROR_NYI(); /* TODO */ } } static inline void call_far_real_mode(void) { sset_CS(t2); if (operand_size_32()) { push32(get_CS()); push32(eip_new); } else { push16(get_CS()); push16(eip_new); } commit_CS(); eip_new = t1; } static inline void call_far(void) { if (virtual8086_mode()) { call_far_virtual8086_mode(); } else if (protected_mode()) { call_far_protected_mode(); } else { call_far_real_mode(); } } static inline void call_near(void) { if (operand_size_32()) { push32(eip_new); } else { push16(eip_new); } eip_new += tj; if (!operand_size_32()) { eip_new &= 0xffff; } } static inline void call_near_absolute(void) { if (operand_size_32()) { push32(eip_new); } else { push16(eip_new); } eip_new = t1; } /****************************************************************************** * * RET - Return from Procedure * ******************************************************************************/ static inline void ret_far_virtual8086_mode(void) { ERROR_NYI(); } static inline void ret_far_protected_mode(void) { /* TODO: check stack */ if (operand_size_32()) { eip_new = pop32(); sset_CS(pop32()); } else { eip_new = pop16(); sset_CS(pop16()); } if ((selector & 0xfffc) == 0) { exception(EXCEPTION_GP, 0); } if (selector_rpl < get_CPL()) { exception(EXCEPTION_GP, 0); } if (selector_rpl != get_CPL()) { ERROR_NYI(); } if (t1 != 0) { if (stack_size_32()) { set_ESP(get_ESP() + t1); } else { set_SP(get_SP() + t1); } } commit_CS(); } static inline void ret_far_real_mode(void) { if (operand_size_32()) { eip_new = pop32(); sset_CS(pop32()); } else { eip_new = pop16(); sset_CS(pop16()); } if (t1 != 0) { if (stack_size_32()) { set_ESP(get_ESP() + t1); } else { set_SP(get_SP() + t1); } } commit_CS(); } static inline void ret_far(void) { if (virtual8086_mode()) { ret_far_virtual8086_mode(); } else if (protected_mode()) { ret_far_protected_mode(); } else { /* real mode */ ret_far_real_mode(); } } static inline void ret_near(void) { if (operand_size_32()) { eip_new = pop32(); } else { eip_new = pop16(); } if (t1 != 0) { if (stack_size_32()) { set_ESP(get_ESP() + t1); } else { set_SP(get_SP() + t1); } } } /****************************************************************************** * * LEAVE - High Level Procedure Exit * ******************************************************************************/ static inline void leave(void) { if (stack_size_32()) { set_ESP(get_EBP()); } else { set_SP(get_BP()); } if (operand_size_32()) { set_EBP(pop32()); } else { set_BP(pop16()); } } /****************************************************************************** * * INT n/INTO/INT 3 - Call to Interrupt Procedure * ******************************************************************************/ static inline void int3(void) { exception_vector = 3; exception_error_code = -1; exception_is_interrupt = 1; } static inline void intn(void) { if (virtual8086_mode()) { if (get_IOPL() < 3) { exception(EXCEPTION_GP, 0); } } exception_vector = t1 & 0xff; exception_error_code = -1; exception_is_interrupt = 1; } static inline void into(void) { if (get_OF()) { exception_vector = 4; exception_error_code = -1; exception_is_interrupt = 1; } } /****************************************************************************** * * ICEBP - Undocumented Opcode * ******************************************************************************/ static inline void icebp(void) { /* TODO: check IR (DR7) */ exception_vector = t1; exception_error_code = -1; exception_is_interrupt = 1; } /****************************************************************************** * * RCL/RCR/ROL/ROR - Rotate * ******************************************************************************/ static inline void rclb(void) { uint8_t value = t1; uint8_t count = (t2 & 31) % 9; bool cf; if (count == 0) { t0 = value; sset_CF(get_CF()); sset_OF(get_OF()); return; } if (count == 1) { t0 = (value << 1) | get_CF(); } else { t0 = (value << count) | (get_CF() << (count - 1)) | (value >> (9 - count)); } cf = (value >> (8 - count)) & 1; t0 &= 0xff; sset_CF(cf); sset_OF(cf ^ (t0 >> 7)); } static inline void rclw(void) { uint16_t value = t1; uint8_t count = (t2 & 31) % 17; bool cf; if (count == 0) { t0 = value; sset_CF(get_CF()); sset_OF(get_OF()); return; } if (count == 1) { t0 = (value << 1) | get_CF(); } else if (count == 16) { t0 = (get_CF() << 15) | (value >> 1); } else { /* 2..15 */ t0 = (value << count) | (get_CF() << (count - 1)) | (value >> (17 - count)); } cf = (value >> (16 - count)) & 1; t0 &= 0xffff; sset_CF(cf); sset_OF(cf ^ (t0 >> 15)); } static inline void rcld(void) { uint32_t value = t1; uint8_t count = t2 & 31; bool cf; if (count == 0) { t0 = value; sset_CF(get_CF()); sset_OF(get_OF()); return; } if (count == 1) { t0 = (value << 1) | get_CF(); } else { t0 = (value << count) | (get_CF() << (count - 1)) | (value >> (33 - count)); } cf = (value >> (32 - count)) & 1; sset_CF(cf); sset_OF(cf ^ (t0 >> 31)); } static inline void rclv(void) { if (operand_size_32()) { rcld(); } else { rclw(); } } /******************************************************************************/ static inline void rcrb(void) { uint8_t value = t1; uint8_t count = (t2 & 31) % 9; if (count == 0) { t0 = value; sset_CF(get_CF()); sset_OF(get_OF()); return; } t0 = (value >> count) | (get_CF() << (8 - count)) | (value << (9 - count)); t0 &= 0xff; sset_CF((value >> (count - 1)) & 1); sset_OF((((t0 << 1) ^ t0) & 0x80) > 0); } static inline void rcrw(void) { uint16_t value = t1; uint8_t count = (t2 & 31) % 17; if (count == 0) { t0 = value; sset_CF(get_CF()); sset_OF(get_OF()); return; } t0 = (value >> count) | (get_CF() << (16 - count)) | (value << (17 - count)); t0 &= 0xffff; sset_CF((value >> (count - 1)) & 1); sset_OF((((t0 << 1) ^ t0) & 0x8000) > 0); } static inline void rcrd(void) { uint32_t value = t1; uint8_t count = t2 & 31; if (count == 0) { t0 = value; sset_CF(get_CF()); sset_OF(get_OF()); return; } if (count == 1) { t0 = (value >> 1) | (get_CF() << 31); } else { t0 = (value >> count) | (get_CF() << (32 - count)) | (value << (33 - count)); } sset_CF((value >> (count - 1)) & 1); sset_OF((((t0 << 1) ^ t0) & 0x80000000) > 0); } static inline void rcrv(void) { if (operand_size_32()) { rcrd(); } else { rcrw(); } } /******************************************************************************/ static inline void rolb(void) { uint8_t value = t1; uint8_t count = t2 & 7; bool cf; t0 = (value << count) | (value >> (8 - count)); cf = t0 & 1; sset_CF(cf); sset_OF(cf ^ (t0 >> 7)); /* Undefined for multi-bit rotates */ } static inline void rolw(void) { uint16_t value = t1; uint8_t count = t2 & 15; bool cf; t0 = (value << count) | (value >> (16 - count)); cf = t0 & 1; sset_CF(cf); sset_OF(cf ^ (t0 >> 15)); /* Undefined for multi-bit rotates */ } static inline void rold(void) { uint32_t value = t1; uint8_t count = t2 & 31; bool cf; t0 = (value << count) | (value >> (32 - count)); cf = t0 & 1; sset_CF(cf); sset_OF(cf ^ (t0 >> 31)); /* Undefined for multi-bit rotates */ } static inline void rolv(void) { if (operand_size_32()) { rold(); } else { rolw(); } } /******************************************************************************/ static inline void rorb(void) { uint8_t value = t1; uint8_t count = t2 & 7; bool b6, b7; t0 = (value >> count) | (value << (8 - count)); b7 = (t0 & 0x80) != 0; b6 = (t0 & 0x40) != 0; sset_CF(b7); sset_OF(b7 ^ b6); } static inline void rorw(void) { uint16_t value = t1; uint8_t count = t2 & 15; bool b14, b15; t0 = (value >> count) | (value << (16 - count)); b15 = (t0 & 0x8000) != 0; b14 = (t0 & 0x4000) != 0; sset_CF(b15); sset_OF(b15 ^ b14); } static inline void rord(void) { uint32_t value = t1; uint8_t count = t2 * 31; bool b30, b31; t0 = (value >> count) | (value << (32 - count)); b31 = (t0 & 0x80000000) != 0; b30 = (t0 & 0x40000000) != 0; sset_CF(b31); sset_OF(b31 ^ b30); } static inline void rorv(void) { if (operand_size_32()) { rord(); } else { rorw(); } } /****************************************************************************** * * SAL/SAR/SHL/SHR - Shift * ******************************************************************************/ static inline void sarb(void) { uint8_t count = t2 & 31; uint8_t value = t1; uint8_t result; if (count == 0) { t0 = value; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } if (count < 8) { if (value & 0x80) { result = (value >> count) | (0xff << (8 - count)); } else { result = value >> count; } sset_CF((value >> (count - 1)) & 1); } else { if (value & 0x80) { result = 0xff; } else { result = 0; } sset_CF((value & 0x80) > 0); } sset_AF(0); sset_OF(0); t0 = result; sset_SF(result >= 0x80); sset_ZF(result == 0); sset_PF(parity(result)); } static inline void sarw(void) { uint8_t count = t2 & 31; uint16_t value = t1; uint16_t result; if (count == 0) { t0 = value; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } if (count < 16) { if (value & 0x8000) { result = (value >> count) | (0xffff << (16 - count)); } else { result = value >> count; } sset_CF((value >> (count - 1)) & 1); } else { if (value & 0x8000) { result = 0xffff; } else { result = 0; } sset_CF((value & 0x8000) > 0); } sset_AF(0); sset_OF(0); t0 = result; sset_SF(result >= 0x8000); sset_ZF(result == 0); sset_PF(parity(result)); } static inline void sard(void) { uint8_t count = t2 & 31; uint32_t value = t1; uint32_t result; if (count == 0) { t0 = value; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } if (value & 0x80000000) { result = (value >> count) | (0xffffffff << (32 - count)); } else { result = value >> count; } sset_CF((value >> (count - 1)) & 1); sset_AF(0); sset_OF(0); t0 = result; sset_SF(result >= 0x80000000); sset_ZF(result == 0); sset_PF(parity(result)); } static inline void sarv(void) { if (operand_size_32()) { sard(); } else { sarw(); } } /******************************************************************************/ static inline void shlb(void) { uint8_t count = t2 & 31; uint8_t value = t1; uint8_t result; if (count == 0) { t0 = value; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } result = value << count; if (count <= 8) { sset_CF((value >> (8 - count)) & 1); } else { sset_CF(0); } if (count == 1) { sset_OF(((value ^ result) & 0x80) > 0); } else { sset_OF((((value << (count - 1)) ^ result) & 0x80) > 0); } sset_AF(0); /* undefined */ t0 = result; sset_SF(result >= 0x80); sset_ZF(result == 0); sset_PF(parity(result)); } static inline void shlw(void) { uint8_t count = t2 & 31; uint16_t value = t1; uint16_t result; if (count == 0) { t0 = value; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } result = value << count; if (count <= 16) { sset_CF((value >> (16 - count)) & 1); } else { sset_CF(0); } if (count == 1) { sset_OF(((value ^ result) & 0x8000) > 0); } else { sset_OF((((value << (count - 1)) ^ result) & 0x8000) > 0); } sset_AF(0); /* undefined */ t0 = result; sset_SF(result >= 0x8000); sset_ZF(result == 0); sset_PF(parity(result)); } static inline void shld(void) { uint8_t count = t2 & 31; uint32_t value = t1; uint32_t result; if (count == 0) { t0 = value; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } result = value << count; sset_CF((value >> (32 - count)) & 1); if (count == 1) { sset_OF(((value ^ result) & 0x80000000) > 0); } else { sset_OF((((value << (count - 1)) ^ result) & 0x80000000) > 0); } sset_AF(0); /* undefined */ t0 = result; sset_SF(result >= 0x80000000); sset_ZF(result == 0); sset_PF(parity(result)); } static inline void shlv(void) { if (operand_size_32()) { shld(); } else { shlw(); } } /******************************************************************************/ static inline void shrb(void) { uint8_t value = t1; uint8_t count = t2 & 31; if (count == 0) { t0 = value; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } t0 = value >> count; sset_CF((value >> (count - 1)) & 1); if (count == 1) { sset_OF(value >= 0x80); } else { sset_OF(0); /* undocumented, but hardware really does it */ } sset_SF(t0 >= 0x80); sset_ZF(t0 == 0); sset_PF(parity(t0)); sset_AF(0); /* Undefined */ } static inline void shrw(void) { uint16_t value = t1; uint8_t count = t2 & 31; if (count == 0) { t0 = value; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } t0 = value >> count; sset_CF((value >> (count - 1)) & 1); if (count == 1) { sset_OF(value >= 0x8000); } else { sset_OF(0); /* undocumented, but hardware really does it */ } sset_SF(t0 >= 0x8000); sset_ZF(t0 == 0); sset_PF(parity(t0)); sset_AF(0); /* Undefined */ } static inline void shrd(void) { uint32_t value = t1; uint8_t count = t2 & 31; if (count == 0) { t0 = value; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } t0 = value >> count; sset_CF((value >> (count - 1)) & 1); if (count == 1) { sset_OF(value >= 80000000); } else { sset_OF(0); /* undocumented, but hardware really does it */ } sset_SF(t0 >= 0x80000000); sset_ZF(t0 == 0); sset_PF(parity(t0)); sset_AF(0); /* Undefined */ } static inline void shrv(void) { if (operand_size_32()) { shrd(); } else { shrw(); } } /****************************************************************************** * * SHRD - Double Precision Shift Right * ******************************************************************************/ static inline void shrdw(void) { unsigned count = t3 & 31; if (!count) { t0 = t1; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } t0 = ((t2 << 16) | t1) >> count; if (count > 16) { t0 |= t1 << (32 - count); } t0 &= 0xffff; sset_CF((t1 >> (count - 1)) & 1); sset_OF((((t0 << 1) ^ t0) & 0x8000) > 0); sset_SF(t0 >= 0x8000); sset_PF(parity(t0)); sset_AF(0); sset_ZF(t0 == 0); } static inline void shrdd(void) { unsigned count = t3 & 31; if (!count) { t0 = t1; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } t0 = (t2 << (32 - count)) | (t1 >> count); sset_CF((t1 >> (count - 1)) & 1); sset_OF((((t0 << 1) ^ t0) & 0x80000000) > 0); sset_SF(t0 >= 0x80000000); sset_PF(parity(t0)); sset_AF(0); sset_ZF(t0 == 0); } static inline void shrdv(void) { if (operand_size_32()) { shrdd(); } else { shrdw(); } } /****************************************************************************** * * SHLD - Double Precision Shift Left * ******************************************************************************/ static inline void shldw(void) { unsigned count = t3 & 31; if (!count) { t0 = t1; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); } t0 = ((t1 << 16) | t2) << count; if (count > 16) { t0 |= t1 << (count - 16); } t0 >>= 16; if (count <= 16) { sset_CF((t1 >> (16 - count)) & 1); } else { sset_CF(0); } sset_AF(0); sset_ZF(t0 == 0); sset_SF(t0 >= 0x8000); sset_PF(parity(t0)); if (count == 1) { sset_OF(((t1 ^ t0) & 0x8000) > 0); } else { sset_OF((((t1 << (count - 1)) ^ t0) & 0x8000) > 0); } } static inline void shldd(void) { unsigned count = t3 & 31; if (!count) { t0 = t1; sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); sset_CF(get_CF()); return; } t0 = (t1 << count) | (t2 >> (32 - count)); sset_CF((t1 >> (32 - count)) & 1); sset_AF(0); sset_ZF(t0 == 0); sset_SF(t0 >= 0x80000000); sset_PF(parity(t0)); if (count == 1) { sset_OF(((t1 ^ t0) & 0x80000000) > 0); } else { sset_OF((((t1 << (count - 1)) ^ t0) & 0x80000000) > 0); } } static inline void shldv(void) { if (operand_size_32()) { shldd(); } else { shldw(); } } /****************************************************************************** * * XLAT/XLATB - Table Look-up Translation * ******************************************************************************/ static inline void xlat(void) { uint32_t offset; if (address_size_32()) { offset = get_EBX() + get_AL(); } else { offset = get_BX() + get_AL(); } set_AL(mrb_seg(offset, get_segment_overwritten(SEGMENT_DS))); } /****************************************************************************** * * LMSW - Load Machine Status Word * ******************************************************************************/ static inline void lmsw(void) { if (!real_mode() && get_CPL() != 0) { exception(EXCEPTION_GP, 0); } if (!get_PE()) { set_PE((t1 >> CR0_PE) & 1); } set_MP((t1 >> CR0_MP) & 1); set_EM((t1 >> CR0_EM) & 1); set_TS((t1 >> CR0_TS) & 1); } /****************************************************************************** * * SMSW - Store Machine Status Word * ******************************************************************************/ static inline void smsw(void) { t0 = get_CR0() & 0xffff; } /****************************************************************************** * * HLT - Halt * ******************************************************************************/ static inline void hlt(void) { halt_state = 1; } /****************************************************************************** * * STR - Store Task Register * ******************************************************************************/ static inline void str(void) { if (real_mode() || virtual8086_mode()) { exception(EXCEPTION_UD, -1); } t0 = tr_selector; } /****************************************************************************** * * SLDT - Store Local Descriptor Table Register * ******************************************************************************/ static inline void sldt(void) { if (real_mode() || virtual8086_mode()) { exception(EXCEPTION_UD, -1); } t0 = ldtr_selector; } /****************************************************************************** * * LTR - Load Task Register * ******************************************************************************/ static inline void ltr(void) { uint32_t addr, dw1, dw2; if (real_mode() || virtual8086_mode()) { exception(EXCEPTION_UD, -1); } if (get_CPL() != 0) { exception(EXCEPTION_GP, 0); } sset_selector(t1); if (selector_index == 0) { exception(EXCEPTION_GP, 0); } if (selector_ti != 0) { exception(EXCEPTION_GP, selector & 0xfffc); } addr = get_descriptor_address(); dw1 = mrd(addr, get_CPL()); dw2 = mrd(addr + 4, get_CPL()); sset_descriptor(dw1, dw2); if (descriptor_sflag) { exception(EXCEPTION_GP, selector & 0xfffc); } if ((descriptor_type != SEGMENT_32BIT_AVAIL_TSS) && (descriptor_type != SEGMENT_16BIT_AVAIL_TSS)) { exception(EXCEPTION_GP, selector & 0xfffc); } if (!descriptor_pflag) { exception(EXCEPTION_NP, selector & 0xfffc); } tr_selector = selector; tr_type = descriptor_type; tr_system_limit = descriptor_system_limit; tr_system_base = descriptor_system_base; /* set busy bit */ mwd(addr + 4, dw2 | 0x200, get_CPL()); } /****************************************************************************** * * LLDT - Load Local Descriptor Table Register * ******************************************************************************/ static inline void lldt(void) { uint32_t addr; if (real_mode() || virtual8086_mode()) { exception(EXCEPTION_UD, -1); } if (get_CPL() != 0) { exception(EXCEPTION_GP, 0); } sset_selector(t1); if (selector_index == 0) { ldtr_selector = 0; ldtr_system_limit = 0; ldtr_system_base = 0; return; } if (selector_ti != 0) { exception(EXCEPTION_GP, selector & 0xfffc); } addr = get_descriptor_address(); sset_descriptor(mrd(addr, get_CPL()), mrd(addr + 4, get_CPL())); if ((descriptor_sflag) || (descriptor_type != SEGMENT_LDT)) { exception(EXCEPTION_GP, selector & 0xfffc); } if (!descriptor_pflag) { exception(EXCEPTION_NP, selector & 0xfffc); } ldtr_selector = selector; ldtr_system_limit = descriptor_system_limit; ldtr_system_base = descriptor_system_base; } /****************************************************************************** * * LGDT/LIDT - Load Global/Interrupt Descriptor Table Register * ******************************************************************************/ static inline void lgdt(void) { uint16_t limit; uint32_t base; if (virtual8086_mode()) { exception(EXCEPTION_GP, 0); } if (protected_mode() && get_CPL() != 0) { exception(EXCEPTION_GP, 0); } limit = t1; base = t2; if (!operand_size_32()) { base &= 0x00ffffff; } gdtr_limit = limit; gdtr_base = base; } static inline void lidt(void) { uint16_t limit; uint32_t base; if (virtual8086_mode()) { exception(EXCEPTION_GP, 0); } if (protected_mode() && get_CPL() != 0) { exception(EXCEPTION_GP, 0); } limit = t1; base = t2; if (!operand_size_32()) { base &= 0x00ffffff; } idtr_limit = limit; idtr_base = base; } /****************************************************************************** * * BSR - Bit Scan Reverse * ******************************************************************************/ static inline void sset_flags_for_bsr(void) { sset_CF(0); /* Undefined */ sset_OF(0); /* Undefined */ sset_AF(0); /* Undefined */ sset_PF(parity(t0)); /* Undefined */ } static inline void bsrw(void) { sset_ZF(t2 == 0); if (t2 == 0) { t0 = t1; /* Undefined */ } else { t0 = 15; while ((t2 & 0x8000) == 0) { t0--; t2 <<= 1; } } sset_flags_for_bsr(); sset_SF(t0 >= 0x8000); /* Undefined */ } static inline void bsrd(void) { sset_ZF(t2 == 0); if (t2 == 0) { t0 = t1; /* Undefined */ } else { t0 = 31; while ((t2 & 0x80000000) == 0) { t0--; t2 <<= 1; } } sset_flags_for_bsr(); sset_SF(t0 >= 0x80000000); /* Undefined */ } static inline void bsrv(void) { if (operand_size_32()) { bsrd(); } else { bsrw(); } } /****************************************************************************** * * BSF - Bit Scan Forward * ******************************************************************************/ static inline void sset_flags_for_bsf(void) { sset_CF(0); /* Undefined */ sset_OF(0); /* Undefined */ sset_AF(0); /* Undefined */ sset_PF(parity(t0)); /* Undefined */ } static inline void bsfw(void) { sset_ZF(t2 == 0); if (t2 == 0) { t0 = t1; /* Undefined */ } else { t0 = 0; while ((t2 & 1) == 0) { t0++; t2 >>= 1; } } sset_flags_for_bsf(); sset_SF(t0 >= 0x8000); /* Undefined */ } static inline void bsfd(void) { sset_ZF(t2 == 0); if (t2 == 0) { t0 = t1; /* Undefined */ return; } else { t0 = 0; while ((t2 & 1) == 0) { t0++; t2 >>= 1; } } sset_flags_for_bsf(); sset_SF(t0 >= 0x80000000); /* Undefined */ } static inline void bsfv(void) { if (operand_size_32()) { bsfd(); } else { bsfw(); } } /****************************************************************************** * * BT - Bit Test * ******************************************************************************/ static inline void btww(void) { sset_CF((t1 >> (t2 & 15)) & 1); } static inline void btdd(void) { sset_CF((t1 >> (t2 & 31)) & 1); } static inline void btvv(void) { if (operand_size_32()) { btdd(); } else { btww(); } } /****************************************************************************** * * BTS - Bit Test and Set * ******************************************************************************/ static inline void btsww(void) { sset_CF((t1 >> (t2 & 15)) & 1); t0 = t1 | (1 << (t2 & 15)); /* OF, SF, ZF, AF, PF undefined */ sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); } static inline void btsdd(void) { sset_CF((t1 >> (t2 & 31)) & 1); t0 = t1 | (1 << (t2 & 31)); /* OF, SF, ZF, AF, PF undefined */ sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); } static inline void btsvv(void) { if (operand_size_32()) { btsdd(); } else { btsww(); } } static inline void btsvb(void) { if (operand_size_32()) { btsdd(); } else { btsww(); } } /****************************************************************************** * * BTR - Bit Test and Reset * ******************************************************************************/ static inline void btrww(void) { sset_CF((t1 >> (t2 & 15)) & 1); t0 = t1 & ~(1 << (t2 & 15)); /* OF, SF, ZF, AF, PF undefined */ sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); } static inline void btrdd(void) { sset_CF((t1 >> (t2 & 31)) & 1); t0 = t1 & ~(1 << (t2 & 31)); /* OF, SF, ZF, AF, PF undefined */ sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); } static inline void btrvv(void) { if (operand_size_32()) { btrdd(); } else { btrww(); } } static inline void btrvb(void) { if (operand_size_32()) { btrdd(); } else { btrww(); } } /****************************************************************************** * * BTC - Bit Test and Complement * ******************************************************************************/ static inline void btcww(void) { sset_CF((t1 >> (t2 & 15)) & 1); t0 = t1 ^ (1 << (t2 & 15)); /* OF, SF, ZF, AF, PF undefined */ sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); } static inline void btcdd(void) { sset_CF((t1 >> (t2 & 31)) & 1); t0 = t1 ^ (1 << (t2 & 31)); /* OF, SF, ZF, AF, PF undefined */ sset_OF(get_OF()); sset_SF(get_SF()); sset_ZF(get_ZF()); sset_AF(get_AF()); sset_PF(get_PF()); } static inline void btcvv(void) { if (operand_size_32()) { btcdd(); } else { btcww(); } } static inline void btcvb(void) { if (operand_size_32()) { btcdd(); } else { btcww(); } } /****************************************************************************** * * CMC - Complement Carry Flag * ******************************************************************************/ static inline void cmc(void) { sset_CF(!get_CF()); commit_CF(); } /****************************************************************************** * * STD - Set Direction Flag * ******************************************************************************/ static inline void std(void) { sset_DF(1); } /****************************************************************************** * * CLD - Clear Direction Flag * ******************************************************************************/ static inline void cld(void) { sset_DF(0); } /****************************************************************************** * * STC - Set Carry Flag * ******************************************************************************/ static inline void stc(void) { sset_CF(1); } /****************************************************************************** * * CLC - Clear Carry Flag * ******************************************************************************/ static inline void clc(void) { sset_CF(0); } /****************************************************************************** * * CLTS - Clear Task-Switched Flag in CR0 * ******************************************************************************/ static inline void clts(void) { if (!real_mode() && get_CPL() != 0) { exception(EXCEPTION_GP, 0); } set_TS(0); } /****************************************************************************** * * STI - Set Interrupt Flag * ******************************************************************************/ static inline void sti(void) { if (protected_mode()) { if (get_IOPL() < get_CPL()) { exception(EXCEPTION_GP, 0); } } else if (virtual8086_mode()) { if (get_IOPL() != 3) { exception(EXCEPTION_GP, 0); } } sset_IF(1); } /****************************************************************************** * * CLI - Clear Interrupt Flag * ******************************************************************************/ static inline void cli(void) { if (protected_mode()) { if (get_IOPL() < get_CPL()) { exception(EXCEPTION_GP, 0); } } else if (virtual8086_mode()) { if (get_IOPL() != 3) { exception(EXCEPTION_GP, 0); } } sset_IF(0); } /****************************************************************************** * * IRET/IRETD - Interrupt Return * ******************************************************************************/ static inline bool can_pop(uint32_t bytes) { if ((ss_type >> 2) & 1) { /* expand down data segment */ if (stack_size_32()) { if (((0xffffffff - get_ESP()) + 1) >= bytes) { return 1; } else { return 0; } } else { if (((0xffff - get_SP()) + 1) >= bytes ) { return 1; } else { return 0; } } } else { if (stack_size_32()) { if (((ss_segment_limit - get_ESP()) + 1) >= bytes) { return 1; } else { return 0; } } else { if (((ss_segment_limit - get_SP()) + 1) >= bytes) { return 1; } else { return 0; } } } } static inline void iret_virtual8086_mode(void) { ERROR_NYI(); } static inline void iret_to_outer_privilege_level(void) { uint32_t addr; uint16_t temp_cs_selector; uint8_t temp_cs_selector_rpl; uint8_t temp_cs_type; bool temp_cs_sflag; uint8_t temp_cs_dpl; bool temp_cs_pflag; uint32_t temp_cs_segment_limit; uint32_t temp_cs_segment_base; bool temp_cs_segment_dflag; bool temp_cs_segment_avlflag; uint32_t esp_new; temp_cs_selector = selector; temp_cs_selector_rpl = selector_rpl; temp_cs_type = descriptor_type; temp_cs_sflag = descriptor_sflag; temp_cs_dpl = descriptor_dpl; temp_cs_pflag = descriptor_pflag; temp_cs_segment_limit = descriptor_segment_limit; temp_cs_segment_base = descriptor_segment_base; temp_cs_segment_dflag = descriptor_segment_dflag; temp_cs_segment_avlflag = descriptor_segment_avlflag; if (operand_size_32()) { esp_new = pop32(); sset_selector(pop32()); } else { esp_new = pop16(); sset_selector(pop16()); } if (selector_index == 0) { exception(EXCEPTION_GP, 0); } if (selector_rpl != temp_cs_selector_rpl) { exception(EXCEPTION_GP, selector & 0xfffc); } addr = get_descriptor_address(); sset_descriptor(mrd(addr, get_CPL()), mrd(addr + 4, get_CPL())); if ((!descriptor_sflag) /* no data/code segment */ || ((descriptor_type >> 3) & 1) /* code segment */ || (!((descriptor_type >> 1) & 1))) { /* not writeable */ exception(EXCEPTION_GP, selector & 0xfffc); } if (descriptor_dpl != temp_cs_selector_rpl) { exception(EXCEPTION_GP, selector & 0xfffc); } if (!descriptor_pflag) { exception(EXCEPTION_NP, selector & 0xfffc); } if (get_CPL() <= get_IOPL()) { commit_IF(); } if (temp_cs_segment_dflag) { /* new operand size == 32 */ commit_RF(); if (get_CPL() == 0) { commit_IOPL0(); commit_IOPL1(); } } else { if (get_CPL() == 0) { commit_IOPL0(); commit_IOPL1(); } } commit_CF(); commit_PF(); commit_AF(); commit_ZF(); commit_SF(); commit_TF(); commit_OF(); commit_DF(); commit_NT(); cs_selector = temp_cs_selector; cs_type = temp_cs_type; cs_sflag = temp_cs_sflag; cs_dpl = temp_cs_dpl; cs_pflag = temp_cs_pflag; cs_segment_limit = temp_cs_segment_limit; cs_segment_base = temp_cs_segment_base; cs_segment_dflag = temp_cs_segment_dflag; cs_segment_avlflag = temp_cs_segment_avlflag; commit_SS(); if (stack_size_32()) { set_ESP(esp_new); } else { set_SP(esp_new); } } static inline void iret_to_same_privilege_level(void) { if (get_CPL() <= get_IOPL()) { commit_IF(); } if (operand_size_32()) { commit_RF(); if (get_CPL() == 0) { commit_IOPL0(); commit_IOPL1(); } } else { if (get_CPL() == 0) { commit_IOPL0(); commit_IOPL1(); } } commit_CF(); commit_PF(); commit_AF(); commit_ZF(); commit_SF(); commit_TF(); commit_OF(); commit_DF(); commit_NT(); commit_CS(); } static inline void iret_protected_mode(void) { uint32_t addr; if (get_NT()) { ERROR_NYI(); } if (operand_size_32()) { eip_new = pop32(); sset_selector(pop32()); sset_EFLAGS32(pop32()); if (eflag_vm_new) { ERROR_NYI(); /* TODO return to vm86 */ } } else { eip_new = pop16(); sset_selector(pop16()); sset_EFLAGS16(pop16()); } if (selector_index == 0) { exception(EXCEPTION_GP, 0); } addr = get_descriptor_address(); sset_descriptor(mrd(addr, get_CPL()), mrd(addr + 4, get_CPL())); if (selector_rpl < get_CPL()) { exception(EXCEPTION_GP, selector & 0xfffc); } if ((!descriptor_sflag) /* no code or data segment */ || (!((descriptor_type >> 3) & 1))) { /* no code segment */ exception(EXCEPTION_GP, selector & 0xfffc); } if ((descriptor_type >> 2) & 1) { /* conforming */ if (descriptor_dpl > selector_rpl) { exception(EXCEPTION_GP, selector & 0xfffc); } } else { /* non-conforming */ if (descriptor_dpl != selector_rpl) { exception(EXCEPTION_GP, selector & 0xfffc); } } if (!descriptor_pflag) { exception(EXCEPTION_NP, selector & 0xfffc); } if (selector_rpl == get_CPL()) { iret_to_same_privilege_level(); } else { iret_to_outer_privilege_level(); } } static inline void iret_real_mode(void) { if (operand_size_32()) { uint32_t unchanged_mask; uint32_t mask; unchanged_mask = 0; unchanged_mask |= 1 << EFLAG_VIF; unchanged_mask |= 1 << EFLAG_VIP; unchanged_mask |= 1 << EFLAG_VM; mask = ~unchanged_mask; if (!can_pop(12)) { exception(EXCEPTION_SS, 0); } eip_new = pop32(); if (eip_new > 0xffff) { exception(EXCEPTION_GP, 0); } sset_CS(pop32()); sset_EFLAGS32((pop32() & mask) | (get_EFLAGS32() & unchanged_mask)); commit_EFLAGS32(); commit_CS(); } else { if (!can_pop(6)) { exception(EXCEPTION_SS, 0); } eip_new = pop16(); sset_CS(pop16()); sset_EFLAGS16(pop16()); commit_EFLAGS16(); commit_CS(); } } static inline void iret(void) { if (virtual8086_mode()) { iret_virtual8086_mode(); } else if (protected_mode()) { iret_protected_mode(); } else { /* real mode */ iret_real_mode(); } } /****************************************************************************** * * Interrupt * ******************************************************************************/ static inline void interrupt_task_gate(uint8_t vector, bool is_soft_int, int error_code) { ERROR_NYI(); /* TODO */ } static inline void interrupt_gate_to_inner_privilege_level( uint8_t vector, bool is_soft_int, int error_code, uint8_t gate_type, uint32_t gate_offset ) { uint16_t temp_cs_selector; uint8_t temp_cs_selector_rpl; uint8_t temp_cs_type; bool temp_cs_sflag; uint8_t temp_cs_dpl; bool temp_cs_pflag; uint32_t temp_cs_segment_limit; uint32_t temp_cs_segment_base; bool temp_cs_segment_dflag; bool temp_cs_segment_avlflag; uint32_t esp_new; uint32_t offset; uint32_t addr; temp_cs_selector = selector; temp_cs_selector_rpl = selector_rpl; temp_cs_type = descriptor_type; temp_cs_sflag = descriptor_sflag; temp_cs_dpl = descriptor_dpl; temp_cs_pflag = descriptor_pflag; temp_cs_segment_limit = descriptor_segment_limit; temp_cs_segment_base = descriptor_segment_base; temp_cs_segment_dflag = descriptor_segment_dflag; temp_cs_segment_avlflag = descriptor_segment_avlflag; if (virtual8086_mode() && cs_dpl != 0) { exception(EXCEPTION_GP, selector & 0xfffc); } if ((tr_type == SEGMENT_32BIT_AVAIL_TSS) || (tr_type == SEGMENT_32BIT_BUSY_TSS)) { offset = descriptor_dpl * 8 + 4; if ((offset + 6) > tr_system_limit) { exception(EXCEPTION_TS, tr_selector & 0xfffc); } esp_new = mrd(tr_system_base + offset, 0); sset_selector(mrw(tr_system_base + offset + 4, 0)); } else { /* SEGMENT_16BIT_AVAIL_TSS */ /* SEGMENT_16BIT_BUSY_TSS */ offset = descriptor_dpl * 4 + 2; if ((offset + 4) > tr_system_limit) { exception(EXCEPTION_TS, tr_selector & 0xfffc); } esp_new = mrw(tr_system_base + offset, 0); sset_selector(mrw(tr_system_base + offset + 2, 0)); } if (selector_index == 0) { exception(EXCEPTION_TS, 0); } addr = get_descriptor_address(); sset_descriptor(mrd(addr, 0), mrd(addr + 4, 0)); if (selector_rpl != temp_cs_dpl) { exception(EXCEPTION_TS, selector & 0xfffc); } if (descriptor_dpl != temp_cs_dpl) { exception(EXCEPTION_TS, selector & 0xfffc); } if ((!descriptor_sflag) /* no data/code segment */ || ((descriptor_type >> 3) & 1) /* code segment */ || (!((descriptor_type >> 1) & 1))) { /* not writeable */ exception(EXCEPTION_TS, selector & 0xfffc); } if (!descriptor_pflag) { exception(EXCEPTION_SS, selector & 0xfffc); } if (gate_offset > temp_cs_segment_limit) { exception(EXCEPTION_GP, 0); } if (!descriptor_segment_dflag) { esp_new &= 0xffff; } if (virtual8086_mode()) { switch (gate_type) { default: DEBUG_ERROR_SWITCH(); case SEGMENT_32BIT_INTERRUPT_GATE: case SEGMENT_32BIT_TRAP_GATE: ERROR_NYI(); break; case SEGMENT_16BIT_INTERRUPT_GATE: case SEGMENT_16BIT_TRAP_GATE: ERROR_NYI(); break; } } else { switch (gate_type) { default: DEBUG_ERROR_SWITCH(); case SEGMENT_32BIT_INTERRUPT_GATE: case SEGMENT_32BIT_TRAP_GATE: mwd(esp_new + descriptor_segment_base - 4, get_SS(), temp_cs_dpl); mwd(esp_new + descriptor_segment_base - 8, get_ESP(), temp_cs_dpl); mwd(esp_new + descriptor_segment_base - 12, get_EFLAGS32(), temp_cs_dpl); mwd(esp_new + descriptor_segment_base - 16, get_CS(), temp_cs_dpl); mwd(esp_new + descriptor_segment_base - 20, eip_new, temp_cs_dpl); esp_new -= 20; if (error_code >= 0) { mwd(esp_new + descriptor_segment_base - 4, error_code, temp_cs_dpl); esp_new -= 4; } break; case SEGMENT_16BIT_INTERRUPT_GATE: case SEGMENT_16BIT_TRAP_GATE: mww(esp_new + descriptor_segment_base - 2, get_SS(), temp_cs_dpl); mww(esp_new + descriptor_segment_base - 4, get_ESP(), temp_cs_dpl); mww(esp_new + descriptor_segment_base - 6, get_EFLAGS16(), temp_cs_dpl); mww(esp_new + descriptor_segment_base - 8, get_CS(), temp_cs_dpl); mww(esp_new + descriptor_segment_base - 10, eip_new, temp_cs_dpl); esp_new -= 10; if (error_code >= 0) { mww(esp_new + descriptor_segment_base - 4, error_code, temp_cs_dpl); esp_new -= 2; } break; } } eip_new = gate_offset; cs_selector = temp_cs_selector; cs_type = temp_cs_type; cs_sflag = temp_cs_sflag; cs_dpl = temp_cs_dpl; cs_pflag = temp_cs_pflag; cs_segment_limit = temp_cs_segment_limit; cs_segment_base = temp_cs_segment_base; cs_segment_dflag = temp_cs_segment_dflag; cs_segment_avlflag = temp_cs_segment_avlflag; commit_SS(); if (stack_size_32()) { set_ESP(esp_new); } else { set_SP(esp_new); } if (!(gate_type & 1)) { sset_IF(0); commit_IF(); } sset_TF(0); commit_TF(); sset_NT(0); commit_NT(); sset_VM(0); commit_VM(); sset_RF(0); commit_RF(); if (virtual8086_mode()) { /* TODO invalidate ds, es, fs, gs */ ERROR_NYI(); } } static inline void interrupt_gate_to_same_privilege_level( uint8_t vector, bool is_soft_int, int error_code, uint8_t gate_type, uint32_t gate_offset ) { if (gate_offset > descriptor_segment_limit) { exception(EXCEPTION_GP, 0); } switch (gate_type) { default: DEBUG_ERROR_SWITCH(); case SEGMENT_32BIT_INTERRUPT_GATE: case SEGMENT_32BIT_TRAP_GATE: push32(get_EFLAGS32()); push32(get_CS()); push32(eip); if (error_code >= 0) { push32(error_code & 0xffff); } break; case SEGMENT_16BIT_INTERRUPT_GATE: case SEGMENT_16BIT_TRAP_GATE: push16(get_EFLAGS16()); push16(get_CS()); push16(eip); if (error_code >= 0) { push16(error_code & 0xffff); } break; } eip_new = gate_offset; commit_CS(); if (!(gate_type & 1)) { sset_IF(0); commit_IF(); } sset_TF(0); commit_TF(); sset_NT(0); commit_NT(); sset_VM(0); commit_VM(); sset_RF(0); commit_RF(); } static inline void interrupt_gate(uint8_t vector, bool is_soft_int, int error_code) { uint16_t gate_selector; uint32_t gate_offset; uint8_t gate_type; uint32_t addr; gate_selector = descriptor_gate_selector; gate_offset = descriptor_gate_offset; gate_type = descriptor_type; if ((gate_selector & 0xfffc) == 0) { exception(EXCEPTION_GP, 0); } /* overwrite the gate selector with new cs selector */ sset_selector(gate_selector); if (selector_index == 0) { exception(EXCEPTION_GP, 0); } addr = get_descriptor_address(); sset_descriptor(mrd(addr, 0), mrd(addr + 4, 0)); if ((!descriptor_sflag) /* no data/code segment */ || (!((descriptor_type >> 3) & 1)) /* no code segemnt */ || (descriptor_dpl > get_CPL())) { exception(EXCEPTION_GP, selector & 0xfffc); } if (!descriptor_pflag) { exception(EXCEPTION_NP, selector & 0xfffc); } if ((!((descriptor_type >> 2) & 1)) /* non-conforming code segment */ && (descriptor_dpl < get_CPL())) { interrupt_gate_to_inner_privilege_level(vector, is_soft_int, error_code, gate_type, gate_offset); } else if (virtual8086_mode()) { exception(EXCEPTION_GP, selector & 0xfffc); } else if (((descriptor_type >> 2) & 1) /* conforming code segment */ || (descriptor_dpl == get_CPL())) { interrupt_gate_to_same_privilege_level(vector, is_soft_int, error_code, gate_type, gate_offset); } else { exception(EXCEPTION_GP, selector & 0xfffc); } } static inline void interrupt_protected_mode(uint8_t vector, bool is_soft_int, int error_code) { uint32_t addr; if ((vector * 8 + 7) > idtr_limit) { exception(EXCEPTION_GP, vector * 8 + 2); } addr = idtr_base + vector * 8; sset_descriptor(mrd(addr, 0), mrd(addr + 4, 0)); if (descriptor_sflag) { exception(EXCEPTION_GP, vector * 8 + 2); } if ((descriptor_type != SEGMENT_TASK_GATE) && (descriptor_type != SEGMENT_16BIT_INTERRUPT_GATE) && (descriptor_type != SEGMENT_32BIT_INTERRUPT_GATE) && (descriptor_type != SEGMENT_16BIT_TRAP_GATE) && (descriptor_type != SEGMENT_32BIT_TRAP_GATE)) { exception(EXCEPTION_GP, exception_vector * 8 + 2); } if (is_soft_int && descriptor_dpl < get_CPL()) { exception(EXCEPTION_GP, vector * 8 + 2); } if (!descriptor_pflag) { exception(EXCEPTION_NP, vector * 8 + 2); } if (descriptor_type == SEGMENT_TASK_GATE) { interrupt_task_gate(vector, is_soft_int, error_code); } else { /* SEGMENT_16BIT_INTERRUPT_GATE */ /* SEGMENT_32BIT_INTERRUPT_GATE */ /* SEGMENT_16BIT_TRAP_GATE */ /* SEGMENT_32BIT_TRAP_GATE */ interrupt_gate(vector, is_soft_int, error_code); } } static inline void interrupt_real_mode(uint8_t vector) { if ((vector * 4 + 3) > idtr_limit) { exception(EXCEPTION_GP, 0); } eip_new = mrw(idtr_base + 4 * vector, 0); sset_CS(mrw(idtr_base + 4 * vector + 2, 0)); push16(get_EFLAGS16()); push16(get_CS()); push16(eip); commit_CS(); sset_IF(0); commit_IF(); sset_TF(0); commit_TF(); sset_RF(0); commit_RF(); } static inline void interrupt(uint8_t vector, bool is_soft_int, int error_code) { if (real_mode()) { interrupt_real_mode(vector); } else { interrupt_protected_mode(vector, is_soft_int, error_code); } } /****************************************************************************** * * Handler for one instruction including prefixes * ******************************************************************************/ #define DEBUG_OPERATION(operation) \ do { \ uint32_t u = eip_new - eip; \ while (u < 8) { \ DEBUG(" "); \ u++; \ } \ DEBUG("%-6s", operation); \ } while (0) #ifndef DEBUG # define DEBUG_OPERATION_GROUP1(opcode_extension) # define DEBUG_OPERATION_GROUP2(opcode_extension) # define DEBUG_OPERATION_GROUP3(opcode_extension) # define DEBUG_OPERATION_GROUP4(opcode_extension) # define DEBUG_OPERATION_GROUP5(opcode_extension) # define DEBUG_OPERATION_GROUP6(opcode_extension) # define DEBUG_OPERATION_GROUP7(opcode_extension) # define DEBUG_OPERATION_GROUP8(opcode_extension) # define DEBUG_OPERATION_GROUP9(opcode_extension) # define DEBUG_OPERATION_GROUPA(opcode_extension) #else # define DEBUG_OPERATION_GROUP1(opcode_extension) \ switch (opcode_extension) { \ default: DEBUG_ERROR_SWITCH(); \ case 0: DEBUG_OPERATION("ADD"); break; \ case 1: DEBUG_OPERATION("OR"); break; \ case 2: DEBUG_OPERATION("ADC"); break; \ case 3: DEBUG_OPERATION("SBB"); break; \ case 4: DEBUG_OPERATION("AND"); break; \ case 5: DEBUG_OPERATION("SUB"); break; \ case 6: DEBUG_OPERATION("XOR"); break; \ case 7: DEBUG_OPERATION("CMP"); break; \ } # define DEBUG_OPERATION_GROUP2(opcode_extension) \ switch (opcode_extension) { \ default: DEBUG_ERROR_SWITCH(); \ case 0: DEBUG_OPERATION("ROL"); break; \ case 1: DEBUG_OPERATION("ROR"); break; \ case 2: DEBUG_OPERATION("RCL"); break; \ case 3: DEBUG_OPERATION("RCR"); break; \ case 4: DEBUG_OPERATION("SHL"); break; \ case 5: DEBUG_OPERATION("SHR"); break; \ case 6: DEBUG_OPERATION("*RESERVED*"); break; \ case 7: DEBUG_OPERATION("SAR"); break; \ } # define DEBUG_OPERATION_GROUP3(opcode_extension) \ switch (opcode_extension) { \ default: DEBUG_ERROR_SWITCH(); \ case 0: DEBUG_OPERATION("TEST"); break; \ case 1: DEBUG_OPERATION("*RESERVED*"); break; \ case 2: DEBUG_OPERATION("NOT"); break; \ case 3: DEBUG_OPERATION("NEG"); break; \ case 4: DEBUG_OPERATION("MUL"); break; \ case 5: DEBUG_OPERATION("IMUL"); break; \ case 6: DEBUG_OPERATION("DIV"); break; \ case 7: DEBUG_OPERATION("IDIV"); break; \ } # define DEBUG_OPERATION_GROUP4(opcode_extension) \ switch (opcode_extension) { \ default: DEBUG_ERROR_SWITCH(); \ case 0: DEBUG_OPERATION("INC"); break; \ case 1: DEBUG_OPERATION("DEC"); break; \ case 2: DEBUG_OPERATION("*RESERVED*"); break; \ case 3: DEBUG_OPERATION("*RESERVED*"); break; \ case 4: DEBUG_OPERATION("*RESERVED*"); break; \ case 5: DEBUG_OPERATION("*RESERVED*"); break; \ case 6: DEBUG_OPERATION("*RESERVED*"); break; \ case 7: DEBUG_OPERATION("*RESERVED*"); break; \ } #endif #define DEBUG_CPUSTATE DEBUG void handle_instruction(void) { esp_backup = esp; if (exception_vector != EXCEPTION_NONE) { interrupt(exception_vector, exception_is_interrupt, exception_error_code); exception_double_page_fault = 0; exception_vector = EXCEPTION_NONE; commit_EIP(); return; } if (interrupt_pending && get_IF() && !interrupt_delay) { interrupt(cpu_irq(), 0, -1); commit_EIP(); halt_state = 0; return; } if (halt_state) { return; } DEBUG("\n"); DEBUG_CPUSTATE("EAX=0x%08x ", eax); DEBUG_CPUSTATE("ECX=0x%08x ", ecx); DEBUG_CPUSTATE("EDX=0x%08x ", edx); DEBUG_CPUSTATE("EBX=0x%08x ", ebx); DEBUG_CPUSTATE("ESP=0x%08x ", esp); DEBUG_CPUSTATE("EBP=0x%08x ", ebp); DEBUG_CPUSTATE("ESI=0x%08x ", esi); DEBUG_CPUSTATE("EDI=0x%08x ", edi); DEBUG_CPUSTATE("EIP=0x%08x ", eip); DEBUG_CPUSTATE("EFLAGS=%c%c%c%c%c%c0%c0%c1%c ", eflag_of ? 'O' : 'o', eflag_df ? 'D' : 'd', eflag_if ? 'I' : 'i', eflag_tf ? 'T' : 't', eflag_sf ? 'S' : 's', eflag_zf ? 'Z' : 'z', eflag_af ? 'A' : 'a', eflag_pf ? 'P' : 'p', eflag_cf ? 'C' : 'c'); DEBUG_CPUSTATE("\n"); DEBUG("%08x: ", eip_new + cs_segment_base); #if 0 if (0xc0000000 <= cs_segment_base + eip && cs_segment_base + eip <= 0xcfffffff) { debug = 1; } if (debug && ! done) { if (0xc0000000 < cs_segment_base + eip && cs_segment_base + eip <= 0xcfffffff) { fprintf(stderr, "EXECUTING %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", cs_segment_base + eip, eax, ebx, ecx, edx, ebp, esp, edi, esi, get_EFLAGS32()); } done = 1; } #endif instruction_opcode = mrb_cs(eip_new); eip_new += 1; switch (instruction_opcode) { default: ERROR_NYI(); case 0x00: fetch_modrm(); DEBUG_OPERATION("ADD"); load_Eb_Gb(); addb(); store_Eb(); commit_EIP(); commit_OSZAPC(); break; case 0x01: fetch_modrm(); DEBUG_OPERATION("ADD"); load_Ev_Gv(); addv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; case 0x02: fetch_modrm(); DEBUG_OPERATION("ADD"); load_Gb_Eb(); addb(); store_Gb(); commit_EIP(); commit_OSZAPC(); break; case 0x03: fetch_modrm(); DEBUG_OPERATION("ADD"); load_Gv_Ev(); addv(); store_Gv(); commit_EIP(); commit_OSZAPC(); break; case 0x04: fetch_immb(); DEBUG_OPERATION("ADD"); load_AL_Ib(); addb(); store_AL(); commit_EIP(); commit_OSZAPC(); break; case 0x05: fetch_immv(operand_size_32()); DEBUG_OPERATION("ADD"); load_eAX_Iv(); addv(); store_eAX(); commit_EIP(); commit_OSZAPC(); break; case 0x06: DEBUG_OPERATION("PUSH"); load_ES(); pushv(); commit_EIP(); break; case 0x07: DEBUG_OPERATION("POP"); popv(); store_ES(); commit_EIP(); break; case 0x08: fetch_modrm(); DEBUG_OPERATION("OR"); load_Eb_Gb(); orb(); store_Eb(); commit_EIP(); commit_OSZAPC(); break; case 0x09: fetch_modrm(); DEBUG_OPERATION("OR"); load_Ev_Gv(); orv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; case 0x0a: fetch_modrm(); DEBUG_OPERATION("OR"); load_Gb_Eb(); orb(); store_Gb(); commit_EIP(); commit_OSZAPC(); break; case 0x0b: fetch_modrm(); DEBUG_OPERATION("OR"); load_Gv_Ev(); orv(); store_Gv(); commit_EIP(); commit_OSZAPC(); break; case 0x0c: fetch_immb(); DEBUG_OPERATION("OR"); load_AL_Ib(); orb(); store_AL(); commit_EIP(); commit_OSZAPC(); break; case 0x0d: fetch_immv(operand_size_32()); DEBUG_OPERATION("OR"); load_eAX_Iv(); orv(); store_eAX(); commit_EIP(); commit_OSZAPC(); break; case 0x0e: DEBUG_OPERATION("PUSH"); load_CS(); pushv(); commit_EIP(); break; case 0x0f: /* 2-byte opcode */ instruction_opcode2 = mrb_cs(eip_new); eip_new++; switch (instruction_opcode2) { default: ERROR_NYI(); case 0x00: fetch_modrm(); switch (instruction_reg) { default: ERROR_NYI(); /* TODO */ case 0: DEBUG_OPERATION("SLDT"); sldt(); store_Ew(); break; case 1: DEBUG_OPERATION("STR"); str(); store_Ew(); break; case 2: DEBUG_OPERATION("LLDT"); load_Ew(); lldt(); break; case 3: DEBUG_OPERATION("LTR"); load_Ew(); ltr(); break; /* TODO */ } commit_EIP(); break; case 0x01: fetch_modrm(); switch (instruction_reg) { default: ERROR_NYI(); /* TODO */ case 2: DEBUG_OPERATION("LGDT"); load_Ms(); lgdt(); break; case 3: DEBUG_OPERATION("LIDT"); load_Ms(); lidt(); break; case 4: DEBUG_OPERATION("SMSW"); smsw(); store_Ew(); break; /* TODO */ case 6: DEBUG_OPERATION("LMSW"); load_Ew(); lmsw(); break; case 7: DEBUG_OPERATION("INVLPG"); exception(EXCEPTION_UD, -1); /* 486+ */ break; } commit_EIP(); break; /* TODO */ case 0x06: DEBUG_OPERATION("CLTS"); clts(); commit_EIP(); break; /* TODO */ case 0x20: fetch_modrm(); DEBUG_OPERATION("MOV"); load_Cd(); movd(); store_Rd(); commit_EIP(); break; /* TODO */ case 0x22: fetch_modrm(); DEBUG_OPERATION("MOV"); load_Rd(); movd(); store_Cd(); commit_EIP(); break; /* TODO */ case 0x80: fetch_immv(operand_size_32()); DEBUG_OPERATION("JO"); load_Jv(); jo(); commit_EIP(); break; case 0x81: fetch_immv(operand_size_32()); DEBUG_OPERATION("JNO"); load_Jv(); jno(); commit_EIP(); break; case 0x82: fetch_immv(operand_size_32()); DEBUG_OPERATION("JB"); load_Jv(); jb(); commit_EIP(); break; case 0x83: fetch_immv(operand_size_32()); DEBUG_OPERATION("JNB"); load_Jv(); jnb(); commit_EIP(); break; case 0x84: fetch_immv(operand_size_32()); DEBUG_OPERATION("JZ"); load_Jv(); jz(); commit_EIP(); break; case 0x85: fetch_immv(operand_size_32()); DEBUG_OPERATION("JNZ"); load_Jv(); jnz(); commit_EIP(); break; case 0x86: fetch_immv(operand_size_32()); DEBUG_OPERATION("JBE"); load_Jv(); jbe(); commit_EIP(); break; case 0x87: fetch_immv(operand_size_32()); DEBUG_OPERATION("JNBE"); load_Jv(); jnbe(); commit_EIP(); break; case 0x88: fetch_immv(operand_size_32()); DEBUG_OPERATION("JS"); load_Jv(); js(); commit_EIP(); break; case 0x89: fetch_immv(operand_size_32()); DEBUG_OPERATION("JNS"); load_Jv(); jns(); commit_EIP(); break; case 0x8a: fetch_immv(operand_size_32()); DEBUG_OPERATION("JP"); load_Jv(); jp(); commit_EIP(); break; case 0x8b: fetch_immv(operand_size_32()); DEBUG_OPERATION("JNP"); load_Jv(); jnp(); commit_EIP(); break; case 0x8c: fetch_immv(operand_size_32()); DEBUG_OPERATION("JL"); load_Jv(); jl(); commit_EIP(); break; case 0x8d: fetch_immv(operand_size_32()); DEBUG_OPERATION("JNL"); load_Jv(); jnl(); commit_EIP(); break; case 0x8e: fetch_immv(operand_size_32()); DEBUG_OPERATION("JLE"); load_Jv(); jle(); commit_EIP(); break; case 0x8f: fetch_immv(operand_size_32()); DEBUG_OPERATION("JNLE"); load_Jv(); jnle(); commit_EIP(); break; case 0x90: fetch_modrm(); DEBUG_OPERATION("SETO"); seto(); store_Eb(); commit_EIP(); break; case 0x91: fetch_modrm(); DEBUG_OPERATION("SETNO"); setno(); store_Eb(); commit_EIP(); break; case 0x92: fetch_modrm(); DEBUG_OPERATION("SETB"); setb(); store_Eb(); commit_EIP(); break; case 0x93: fetch_modrm(); DEBUG_OPERATION("SETNB"); setnb(); store_Eb(); commit_EIP(); break; case 0x94: fetch_modrm(); DEBUG_OPERATION("SETZ"); setz(); store_Eb(); commit_EIP(); break; case 0x95: fetch_modrm(); DEBUG_OPERATION("SETNZ"); setnz(); store_Eb(); commit_EIP(); break; case 0x96: fetch_modrm(); DEBUG_OPERATION("SETBE"); setbe(); store_Eb(); commit_EIP(); break; case 0x97: fetch_modrm(); DEBUG_OPERATION("SETNBE"); setnbe(); store_Eb(); commit_EIP(); break; case 0x98: fetch_modrm(); DEBUG_OPERATION("SETS"); sets(); store_Eb(); commit_EIP(); break; case 0x99: fetch_modrm(); DEBUG_OPERATION("SETNS"); setns(); store_Eb(); commit_EIP(); break; case 0x9a: fetch_modrm(); DEBUG_OPERATION("SETP"); setp(); store_Eb(); commit_EIP(); break; case 0x9b: fetch_modrm(); DEBUG_OPERATION("SETNP"); setnp(); store_Eb(); commit_EIP(); break; case 0x9c: fetch_modrm(); DEBUG_OPERATION("SETL"); setl(); store_Eb(); commit_EIP(); break; case 0x9d: fetch_modrm(); DEBUG_OPERATION("SETNL"); setnl(); store_Eb(); commit_EIP(); break; case 0x9e: fetch_modrm(); DEBUG_OPERATION("SETLE"); setle(); store_Eb(); commit_EIP(); break; case 0x9f: fetch_modrm(); DEBUG_OPERATION("SETNLE"); setnle(); store_Eb(); commit_EIP(); break; case 0xa0: DEBUG_OPERATION("PUSH"); load_FS(); pushv(); commit_EIP(); break; case 0xa1: DEBUG_OPERATION("POP"); popv(); store_FS(); commit_EIP(); break; case 0xa2: exception(EXCEPTION_UD, -1); break; case 0xa3: fetch_modrm(); DEBUG_OPERATION("BT"); load_EvBIT_Gv(); btvv(); commit_EIP(); commit_CF(); break; case 0xa4: fetch_modrm(); fetch_immb(); DEBUG_OPERATION("SHLD"); load_Ev_Gv_Ib(); shldv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; case 0xa5: fetch_modrm(); DEBUG_OPERATION("SHLD"); load_Ev_Gv_CL(); shldv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; /* TODO */ case 0xa8: DEBUG_OPERATION("PUSH"); load_GS(); pushv(); commit_EIP(); break; case 0xa9: DEBUG_OPERATION("POP"); popv(); store_GS(); commit_EIP(); break; /* TODO */ case 0xab: fetch_modrm(); DEBUG_OPERATION("BTS"); load_EvBIT_Gv(); btsvv(); store_EvBIT(); commit_EIP(); commit_CF(); break; case 0xac: fetch_modrm(); fetch_immb(); DEBUG_OPERATION("SHRD"); load_Ev_Gv_Ib(); shrdv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; case 0xad: fetch_modrm(); DEBUG_OPERATION("SHRD"); load_Ev_Gv_CL(); shrdv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; /* TODO */ case 0xaf: fetch_modrm(); DEBUG_OPERATION("IMUL"); load_Gv_Ev(); imul2v(); store_Gv(); commit_EIP(); commit_OSZAPC(); break; /* TODO */ case 0xb2: fetch_modrm(); DEBUG_OPERATION("LSS"); load_Mp(); lss(); store_Gv(); commit_EIP(); break; case 0xb3: fetch_modrm(); DEBUG_OPERATION("BTR"); load_EvBIT_Gv(); btrvv(); store_EvBIT(); commit_OSZAPC(); commit_EIP(); break; case 0xb4: fetch_modrm(); DEBUG_OPERATION("LFS"); load_Mp(); lfs(); store_Gv(); commit_EIP(); break; case 0xb5: fetch_modrm(); DEBUG_OPERATION("LGS"); load_Mp(); lgs(); store_Gv(); commit_EIP(); break; case 0xb6: fetch_modrm(); DEBUG_OPERATION("MOVZX"); load_Eb(); movzxb(); store_Gv(); commit_EIP(); break; case 0xb7: fetch_modrm(); DEBUG_OPERATION("MOVZX"); load_Ew(); movzxw(); store_Gv(); commit_EIP(); break; /* TODO */ case 0xba: fetch_modrm(); fetch_immb(); switch (instruction_reg) { default: ERROR_NYI(); /* TODO */ case 5: DEBUG_OPERATION("BTS"); load_Ev_Ib(); btsvb(); store_Ev(); commit_OSZAPC(); break; case 6: DEBUG_OPERATION("BTR"); load_Ev_Ib(); btrvb(); store_Ev(); commit_OSZAPC(); break; case 7: DEBUG_OPERATION("BTC"); load_Ev_Ib(); btcvb(); store_Ev(); commit_OSZAPC(); break; } commit_EIP(); break; case 0xbb: fetch_modrm(); DEBUG_OPERATION("BTC"); load_EvBIT_Gv(); btcvv(); store_EvBIT(); commit_OSZAPC(); commit_EIP(); break; case 0xbc: fetch_modrm(); DEBUG_OPERATION("BSF"); load_Gv_Ev(); bsfv(); store_Gv(); commit_OSZAPC(); commit_EIP(); break; case 0xbd: fetch_modrm(); DEBUG_OPERATION("BSR"); load_Gv_Ev(); bsrv(); store_Gv(); commit_OSZAPC(); commit_EIP(); break; case 0xbe: fetch_modrm(); DEBUG_OPERATION("MOVSX"); load_Eb(); movsxb(); store_Gv(); commit_EIP(); break; case 0xbf: fetch_modrm(); DEBUG_OPERATION("MOVSX"); load_Ew(); movsxw(); store_Gv(); commit_EIP(); break; /* TODO */ case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: DEBUG_OPERATION("BSWAP"); exception(EXCEPTION_UD, -1); break; /* TODO */ } break; case 0x10: fetch_modrm(); DEBUG_OPERATION("ADC"); load_Eb_Gb(); adcb(); store_Eb(); commit_EIP(); commit_OSZAPC(); break; case 0x11: fetch_modrm(); DEBUG_OPERATION("ADC"); load_Ev_Gv(); adcv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; case 0x12: fetch_modrm(); DEBUG_OPERATION("ADC"); load_Gb_Eb(); adcb(); store_Gb(); commit_EIP(); commit_OSZAPC(); break; case 0x13: fetch_modrm(); DEBUG_OPERATION("ADC"); load_Gv_Ev(); adcv(); store_Gv(); commit_EIP(); commit_OSZAPC(); break; case 0x14: fetch_immb(); DEBUG_OPERATION("ADC"); load_AL_Ib(); adcb(); store_AL(); commit_EIP(); commit_OSZAPC(); break; case 0x15: fetch_immv(operand_size_32()); DEBUG_OPERATION("ADC"); load_eAX_Iv(); adcv(); store_eAX(); commit_EIP(); commit_OSZAPC(); break; case 0x16: DEBUG_OPERATION("PUSH"); load_SS(); pushv(); commit_EIP(); break; case 0x17: DEBUG_OPERATION("POP"); popv(); store_SS(); commit_EIP_and_delay_interrupts(); break; case 0x18: fetch_modrm(); DEBUG_OPERATION("SBB"); load_Eb_Gb(); sbbb(); store_Eb(); commit_EIP(); commit_OSZAPC(); break; case 0x19: fetch_modrm(); DEBUG_OPERATION("SBB"); load_Ev_Gv(); sbbv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; case 0x1a: fetch_modrm(); DEBUG_OPERATION("SBB"); load_Gb_Eb(); sbbb(); store_Gb(); commit_EIP(); commit_OSZAPC(); break; case 0x1b: fetch_modrm(); DEBUG_OPERATION("SBB"); load_Gv_Ev(); sbbv(); store_Gv(); commit_EIP(); commit_OSZAPC(); break; case 0x1c: fetch_immb(); DEBUG_OPERATION("SBB"); load_AL_Ib(); sbbb(); store_AL(); commit_EIP(); commit_OSZAPC(); break; case 0x1d: fetch_immv(operand_size_32()); DEBUG_OPERATION("SBB"); load_eAX_Iv(); sbbv(); store_eAX(); commit_EIP(); commit_OSZAPC(); break; case 0x1e: DEBUG_OPERATION("PUSH"); load_DS(); pushv(); commit_EIP(); break; case 0x1f: DEBUG_OPERATION("POP"); popv(); store_DS(); commit_EIP(); break; case 0x20: fetch_modrm(); DEBUG_OPERATION("AND"); load_Eb_Gb(); andb(); store_Eb(); commit_EIP(); commit_OSZAPC(); break; case 0x21: fetch_modrm(); DEBUG_OPERATION("AND"); load_Ev_Gv(); andv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; case 0x22: fetch_modrm(); DEBUG_OPERATION("AND"); load_Gb_Eb(); andb(); store_Gb(); commit_EIP(); commit_OSZAPC(); break; case 0x23: fetch_modrm(); DEBUG_OPERATION("AND"); load_Gv_Ev(); andv(); store_Gv(); commit_EIP(); commit_OSZAPC(); break; case 0x24: fetch_immb(); DEBUG_OPERATION("AND"); load_AL_Ib(); andb(); store_AL(); commit_EIP(); commit_OSZAPC(); break; case 0x25: fetch_immv(operand_size_32()); DEBUG_OPERATION("AND"); load_eAX_Iv(); andv(); store_eAX(); commit_EIP(); commit_OSZAPC(); break; case 0x26: DEBUG_OPERATION("ES segment override prefix"); prefix_segment_override = SEGMENT_ES; break; case 0x27: DEBUG_OPERATION("DAA"); daa(); commit_EIP(); commit_OSZAPC(); break; case 0x28: fetch_modrm(); DEBUG_OPERATION("SUB"); load_Eb_Gb(); subb(); store_Eb(); commit_EIP(); commit_OSZAPC(); break; case 0x29: fetch_modrm(); DEBUG_OPERATION("SUB"); load_Ev_Gv(); subv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; case 0x2a: fetch_modrm(); DEBUG_OPERATION("SUB"); load_Gb_Eb(); subb(); store_Gb(); commit_EIP(); commit_OSZAPC(); break; case 0x2b: fetch_modrm(); DEBUG_OPERATION("SUB"); load_Gv_Ev(); subv(); store_Gv(); commit_EIP(); commit_OSZAPC(); break; case 0x2c: fetch_immb(); DEBUG_OPERATION("SUB"); load_AL_Ib(); subb(); store_AL(); commit_EIP(); commit_OSZAPC(); break; case 0x2d: fetch_immv(operand_size_32()); DEBUG_OPERATION("SUB"); load_eAX_Iv(); subv(); store_eAX(); commit_EIP(); commit_OSZAPC(); break; case 0x2e: DEBUG_OPERATION("CS segment override prefix"); prefix_segment_override = SEGMENT_CS; break; case 0x2f: DEBUG_OPERATION("DAS"); das(); commit_EIP(); break; case 0x30: fetch_modrm(); DEBUG_OPERATION("XOR"); load_Eb_Gb(); xorb(); store_Eb(); commit_EIP(); commit_OSZAPC(); break; case 0x31: fetch_modrm(); DEBUG_OPERATION("XOR"); load_Ev_Gv(); xorv(); store_Ev(); commit_EIP(); commit_OSZAPC(); break; case 0x32: fetch_modrm(); DEBUG_OPERATION("XOR"); load_Gb_Eb(); xorb(); store_Gb(); commit_EIP(); commit_OSZAPC(); break; case 0x33: fetch_modrm(); DEBUG_OPERATION("XOR"); load_Gv_Ev(); xorv(); store_Gv(); commit_EIP(); commit_OSZAPC(); break; case 0x34: fetch_immb(); DEBUG_OPERATION("XOR"); load_AL_Ib(); xorb(); store_AL(); commit_EIP(); commit_OSZAPC(); break; case 0x35: fetch_immv(operand_size_32()); DEBUG_OPERATION("XOR"); load_eAX_Iv(); xorv(); store_eAX(); commit_EIP(); commit_OSZAPC(); break; case 0x36: DEBUG_OPERATION("SS segment override prefix"); prefix_segment_override = SEGMENT_SS; break; case 0x37: DEBUG_OPERATION("AAA"); aaa(); commit_EIP(); break; case 0x38: fetch_modrm(); DEBUG_OPERATION("CMP"); load_Eb_Gb(); cmpb(); commit_EIP(); commit_OSZAPC(); break; case 0x39: fetch_modrm(); DEBUG_OPERATION("CMP"); load_Ev_Gv(); cmpv(); commit_EIP(); commit_OSZAPC(); break; case 0x3a: fetch_modrm(); DEBUG_OPERATION("CMP"); load_Gb_Eb(); cmpb(); commit_EIP(); commit_OSZAPC(); break; case 0x3b: fetch_modrm(); DEBUG_OPERATION("CMP"); load_Gv_Ev(); cmpv(); commit_EIP(); commit_OSZAPC(); break; case 0x3c: fetch_immb(); DEBUG_OPERATION("CMP"); load_AL_Ib(); cmpb(); commit_EIP(); commit_OSZAPC(); break; case 0x3d: fetch_immv(operand_size_32()); DEBUG_OPERATION("CMP"); load_eAX_Iv(); cmpv(); commit_EIP(); commit_OSZAPC(); break; case 0x3e: DEBUG_OPERATION("DS segment override prefix"); prefix_segment_override = SEGMENT_DS; break; case 0x3f: DEBUG_OPERATION("AAS"); aas(); commit_EIP(); break; case 0x40: DEBUG_OPERATION("INC"); load_eAX(); incv(); store_eAX(); commit_EIP(); commit_OSZAP(); break; case 0x41: DEBUG_OPERATION("INC"); load_eCX(); incv(); store_eCX(); commit_EIP(); commit_OSZAP(); break; case 0x42: DEBUG_OPERATION("INC"); load_eDX(); incv(); store_eDX(); commit_EIP(); commit_OSZAP(); break; case 0x43: DEBUG_OPERATION("INC"); load_eBX(); incv(); store_eBX(); commit_EIP(); commit_OSZAP(); break; case 0x44: DEBUG_OPERATION("INC"); load_eSP(); incv(); store_eSP(); commit_EIP(); commit_OSZAP(); break; case 0x45: DEBUG_OPERATION("INC"); load_eBP(); incv(); store_eBP(); commit_EIP(); commit_OSZAP(); break; case 0x46: DEBUG_OPERATION("INC"); load_eSI(); incv(); store_eSI(); commit_EIP(); commit_OSZAP(); break; case 0x47: DEBUG_OPERATION("INC"); load_eDI(); incv(); store_eDI(); commit_EIP(); commit_OSZAP(); break; case 0x48: DEBUG_OPERATION("DEC"); load_eAX(); decv(); store_eAX(); commit_EIP(); commit_OSZAP(); break; case 0x49: DEBUG_OPERATION("DEC"); load_eCX(); decv(); store_eCX(); commit_EIP(); commit_OSZAP(); break; case 0x4a: DEBUG_OPERATION("DEC"); load_eDX(); decv(); store_eDX(); commit_EIP(); commit_OSZAP(); break; case 0x4b: DEBUG_OPERATION("DEC"); load_eBX(); decv(); store_eBX(); commit_EIP(); commit_OSZAP(); break; case 0x4c: DEBUG_OPERATION("DEC"); load_eSP(); decv(); store_eSP(); commit_EIP(); commit_OSZAP(); break; case 0x4d: DEBUG_OPERATION("DEC"); load_eBP(); decv(); store_eBP(); commit_EIP(); commit_OSZAP(); break; case 0x4e: DEBUG_OPERATION("DEC"); load_eSI(); decv(); store_eSI(); commit_EIP(); commit_OSZAP(); break; case 0x4f: DEBUG_OPERATION("DEC"); load_eDI(); decv(); store_eDI(); commit_EIP(); commit_OSZAP(); break; case 0x50: DEBUG_OPERATION("PUSH"); load_eAX(); pushv(); commit_EIP(); break; case 0x51: DEBUG_OPERATION("PUSH"); load_eCX(); pushv(); commit_EIP(); break; case 0x52: DEBUG_OPERATION("PUSH"); load_eDX(); pushv(); commit_EIP(); break; case 0x53: DEBUG_OPERATION("PUSH"); load_eBX(); pushv(); commit_EIP(); break; case 0x54: DEBUG_OPERATION("PUSH"); load_eSP(); pushv(); commit_EIP(); break; case 0x55: DEBUG_OPERATION("PUSH"); load_eBP(); pushv(); commit_EIP(); break; case 0x56: DEBUG_OPERATION("PUSH"); load_eSI(); pushv(); commit_EIP(); break; case 0x57: DEBUG_OPERATION("PUSH"); load_eDI(); pushv(); commit_EIP(); break; case 0x58: DEBUG_OPERATION("POP"); popv(); store_eAX(); commit_EIP(); break; case 0x59: DEBUG_OPERATION("POP"); popv(); store_eCX(); commit_EIP(); break; case 0x5a: DEBUG_OPERATION("POP"); popv(); store_eDX(); commit_EIP(); break; case 0x5b: DEBUG_OPERATION("POP"); popv(); store_eBX(); commit_EIP(); break; case 0x5c: DEBUG_OPERATION("POP"); popv(); store_eSP(); commit_EIP(); break; case 0x5d: DEBUG_OPERATION("POP"); popv(); store_eBP(); commit_EIP(); break; case 0x5e: DEBUG_OPERATION("POP"); popv(); store_eSI(); commit_EIP(); break; case 0x5f: DEBUG_OPERATION("POP"); popv(); store_eDI(); commit_EIP(); break; case 0x60: DEBUG_OPERATION("PUSHA"); pushav(); commit_EIP(); break; case 0x61: DEBUG_OPERATION("POPA"); popa(); commit_EIP(); break; /* TODO */ case 0x64: DEBUG_OPERATION("FS segment override prefix"); prefix_segment_override = SEGMENT_FS; break; case 0x65: DEBUG_OPERATION("GS segment override prefix"); prefix_segment_override = SEGMENT_GS; break; case 0x66: DEBUG_OPERATION("Operand-size override prefix"); prefix_operand_size_override = 1; break; case 0x67: DEBUG_OPERATION("Address-size override prefix"); prefix_address_size_override = 1; break; case 0x68: fetch_immv(operand_size_32()); DEBUG_OPERATION("PUSH"); load_Iv(); pushv(); commit_EIP(); break; case 0x69: fetch_modrm(); fetch_immv(operand_size_32()); DEBUG_OPERATION("IMUL"); load_Ev_Iv(); imul3vv(); store_Gv(); commit_EIP(); commit_OSZAPC(); break; case 0x6a: fetch_immb(); DEBUG_OPERATION("PUSH"); load_IbSE(); pushv(); commit_EIP(); break; case 0x6b: fetch_modrm(); fetch_immb(); DEBUG_OPERATION("IMUL"); load_Ev_IbSE(); imul3vb(); store_Gv(); commit_EIP(); commit_OSZAPC(); break; case 0x6c: DEBUG_OPERATION("INS"); insb(); commit_EIP(); break; case 0x6d: DEBUG_OPERATION("INS"); insv(); commit_EIP(); break; case 0x6e: DEBUG_OPERATION("OUTS"); outsb(); commit_EIP(); break; case 0x6f: DEBUG_OPERATION("OUTS"); outsv(); commit_EIP(); break; case 0x70: fetch_immb(); DEBUG_OPERATION("JO"); load_Jb(); jo(); commit_EIP(); break; case 0x71: fetch_immb(); DEBUG_OPERATION("JNO"); load_Jb(); jno(); commit_EIP(); break; case 0x72: fetch_immb(); DEBUG_OPERATION("JB"); load_Jb(); jb(); commit_EIP(); break; case 0x73: fetch_immb(); DEBUG_OPERATION("JNB"); load_Jb(); jnb(); commit_EIP(); break; case 0x74: fetch_immb(); DEBUG_OPERATION("JZ"); load_Jb(); jz(); commit_EIP(); break; case 0x75: fetch_immb(); DEBUG_OPERATION("JNZ"); load_Jb(); jnz(); commit_EIP(); break; case 0x76: fetch_immb(); DEBUG_OPERATION("JBE"); load_Jb(); jbe(); commit_EIP(); break; case 0x77: fetch_immb(); DEBUG_OPERATION("JNBE"); load_Jb(); jnbe(); commit_EIP(); break; case 0x78: fetch_immb(); DEBUG_OPERATION("JS"); load_Jb(); js(); commit_EIP(); break; case 0x79: fetch_immb(); DEBUG_OPERATION("JNS"); load_Jb(); jns(); commit_EIP(); break; case 0x7a: fetch_immb(); DEBUG_OPERATION("JP"); load_Jb(); jp(); commit_EIP(); break; case 0x7b: fetch_immb(); DEBUG_OPERATION("JNP"); load_Jb(); jnp(); commit_EIP(); break; case 0x7c: fetch_immb(); DEBUG_OPERATION("JL"); load_Jb(); jl(); commit_EIP(); break; case 0x7d: fetch_immb(); DEBUG_OPERATION("JNL"); load_Jb(); jnl(); commit_EIP(); break; case 0x7e: fetch_immb(); DEBUG_OPERATION("JLE"); load_Jb(); jle(); commit_EIP(); break; case 0x7f: fetch_immb(); DEBUG_OPERATION("JNLE"); load_Jb(); jnle(); commit_EIP(); break; case 0x80: fetch_modrm(); fetch_immb(); DEBUG_OPERATION_GROUP1(instruction_reg); load_Eb_Ib(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: addb(); store_Eb(); commit_OSZAPC(); break; case 1: orb(); store_Eb(); commit_OSZAPC(); break; case 2: adcb(); store_Eb(); commit_OSZAPC(); break; case 3: sbbb(); store_Eb(); commit_OSZAPC(); break; case 4: andb(); store_Eb(); commit_OSZAPC(); break; case 5: subb(); store_Eb(); commit_OSZAPC(); break; case 6: xorb(); store_Eb(); commit_OSZAPC(); break; case 7: cmpb(); commit_OSZAPC(); break; } commit_EIP(); break; case 0x81: fetch_modrm(); fetch_immv(operand_size_32()); DEBUG_OPERATION_GROUP1(instruction_reg); load_Ev_Iv(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: addv(); store_Ev(); commit_OSZAPC(); break; case 1: orv(); store_Ev(); commit_OSZAPC(); break; case 2: adcv(); store_Ev(); commit_OSZAPC(); break; case 3: sbbv(); store_Ev(); commit_OSZAPC(); break; case 4: andv(); store_Ev(); commit_OSZAPC(); break; case 5: subv(); store_Ev(); commit_OSZAPC(); break; case 6: xorv(); store_Ev(); commit_OSZAPC(); break; case 7: cmpv(); commit_OSZAPC(); break; } commit_EIP(); break; case 0x82: /* FIXME: undocumented */ fetch_modrm(); fetch_immb(); DEBUG_OPERATION_GROUP1(instruction_reg); load_Eb_Ib(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: addb(); store_Eb(); commit_OSZAPC(); break; case 1: orb(); store_Eb(); commit_OSZAPC(); break; case 2: adcb(); store_Eb(); commit_OSZAPC(); break; case 3: sbbb(); store_Eb(); commit_OSZAPC(); break; case 4: andb(); store_Eb(); commit_OSZAPC(); break; case 5: subb(); store_Eb(); commit_OSZAPC(); break; case 6: xorb(); store_Eb(); commit_OSZAPC(); break; case 7: cmpb(); commit_OSZAPC(); break; } commit_EIP(); break; case 0x83: fetch_modrm(); fetch_immb(); DEBUG_OPERATION_GROUP1(instruction_reg); load_Ev_IbSE(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: addv(); store_Ev(); commit_OSZAPC(); break; case 1: orv(); store_Ev(); commit_OSZAPC(); break; case 2: adcv(); store_Ev(); commit_OSZAPC(); break; case 3: sbbv(); store_Ev(); commit_OSZAPC(); break; case 4: andv(); store_Ev(); commit_OSZAPC(); break; case 5: subv(); store_Ev(); commit_OSZAPC(); break; case 6: xorv(); store_Ev(); commit_OSZAPC(); break; case 7: cmpv(); commit_OSZAPC(); break; } commit_EIP(); break; case 0x84: fetch_modrm(); DEBUG_OPERATION("TEST"); load_Eb_Gb(); testb(); commit_EIP(); commit_OSZAPC(); break; case 0x85: fetch_modrm(); DEBUG_OPERATION("TEST"); load_Ev_Gv(); testv(); commit_EIP(); commit_OSZAPC(); break; case 0x86: fetch_modrm(); DEBUG_OPERATION("XCHG"); load_Eb_Gb(); xchg(); store_Eb_Gb(); commit_EIP(); break; case 0x87: fetch_modrm(); DEBUG_OPERATION("XCHG"); load_Ev_Gv(); xchg(); store_Ev_Gv(); commit_EIP(); break; case 0x88: fetch_modrm(); DEBUG_OPERATION("MOV"); load_Gb(); movb(); store_Eb(); commit_EIP(); break; case 0x89: fetch_modrm(); DEBUG_OPERATION("MOV"); load_Gv(); movv(); store_Ev(); commit_EIP(); break; case 0x8a: fetch_modrm(); DEBUG_OPERATION("MOV"); load_Eb(); movb(); store_Gb(); commit_EIP(); break; case 0x8b: fetch_modrm(); DEBUG_OPERATION("MOV"); load_Ev(); movv(); store_Gv(); commit_EIP(); break; case 0x8c: fetch_modrm(); DEBUG_OPERATION("MOV"); load_Sw(); movw(); store_Ev(); commit_EIP(); break; case 0x8d: fetch_modrm(); DEBUG_OPERATION("LEA"); load_effective_address(); lea(); store_Gv(); commit_EIP(); break; case 0x8e: fetch_modrm(); DEBUG_OPERATION("MOV"); load_Ew(); movw(); store_Sw(); if (instruction_reg == SEGMENT_SS) { commit_EIP_and_delay_interrupts(); } else { commit_EIP(); } break; case 0x8f: fetch_modrm(); DEBUG_OPERATION("POP"); popv(); store_Ev(); commit_EIP(); break; case 0x90: DEBUG_OPERATION("NOP"); /* TODO: hmm... */ commit_EIP(); break; case 0x91: DEBUG_OPERATION("XCHG"); load_eAX_eCX(); xchg(); store_eAX_eCX(); commit_EIP(); break; case 0x92: DEBUG_OPERATION("XCHG"); load_eAX_eDX(); xchg(); store_eAX_eDX(); commit_EIP(); break; case 0x93: DEBUG_OPERATION("XCHG"); load_eAX_eBX(); xchg(); store_eAX_eBX(); commit_EIP(); break; case 0x94: DEBUG_OPERATION("XCHG"); load_eAX_eSP(); xchg(); store_eAX_eSP(); commit_EIP(); break; case 0x95: DEBUG_OPERATION("XCHG"); load_eAX_eBP(); xchg(); store_eAX_eBP(); commit_EIP(); break; case 0x96: DEBUG_OPERATION("XCHG"); load_eAX_eSI(); xchg(); store_eAX_eSI(); commit_EIP(); break; case 0x97: DEBUG_OPERATION("XCHG"); load_eAX_eDI(); xchg(); store_eAX_eDI(); commit_EIP(); break; case 0x98: if (operand_size_32()) { DEBUG_OPERATION("CWDE"); cwde(); } else { DEBUG_OPERATION("CBW"); cbw(); } commit_EIP(); break; case 0x99: if (operand_size_32()) { DEBUG_OPERATION("CDQ"); cdq(); } else { DEBUG_OPERATION("CWD"); cwd(); } commit_EIP(); break; case 0x9a: fetch_ptr(); DEBUG_OPERATION("CALL"); load_Ap(); call_far(); commit_EIP(); break; case 0x9b: DEBUG_OPERATION("WAIT"); wait(); commit_EIP(); break; case 0x9c: DEBUG_OPERATION("PUSHF"); pushf(); commit_EIP(); break; case 0x9d: DEBUG_OPERATION("POPF"); popf(); commit_EIP(); break; case 0x9e: DEBUG_OPERATION("SAHF"); sahf(); commit_EIP(); break; case 0x9f: DEBUG_OPERATION("LAHF"); lahf(); commit_EIP(); break; case 0xa0: fetch_immv(address_size_32()); DEBUG_OPERATION("MOV"); load_Ob(); movb(); store_AL(); commit_EIP(); break; case 0xa1: fetch_immv(address_size_32()); DEBUG_OPERATION("MOV"); load_Ov(); movv(); store_eAX(); commit_EIP(); break; case 0xa2: fetch_immv(address_size_32()); DEBUG_OPERATION("MOV"); load_AL(); movb(); store_Ob(); commit_EIP(); break; case 0xa3: fetch_immv(address_size_32()); DEBUG_OPERATION("MOV"); load_eAX(); movv(); store_Ov(); commit_EIP(); break; case 0xa4: DEBUG_OPERATION("MOVS"); movsb(); commit_EIP(); break; case 0xa5: DEBUG_OPERATION("MOVS"); movsv(); commit_EIP(); break; case 0xa6: DEBUG_OPERATION("CMPS"); cmpsb(); commit_EIP(); break; case 0xa7: DEBUG_OPERATION("CMPS"); cmpsv(); commit_EIP(); break; case 0xa8: fetch_immb(); DEBUG_OPERATION("TEST"); load_AL_Ib(); testb(); commit_EIP(); commit_OSZAPC(); break; case 0xa9: fetch_immv(operand_size_32()); DEBUG_OPERATION("TEST"); load_eAX_Iv(); testv(); commit_EIP(); commit_OSZAPC(); break; case 0xaa: DEBUG_OPERATION("STOS"); stosb(); commit_EIP(); break;; case 0xab: DEBUG_OPERATION("STOS"); stosv(); commit_EIP(); break;; case 0xac: DEBUG_OPERATION("LODS"); lodsb(); commit_EIP(); break;; case 0xad: DEBUG_OPERATION("LODS"); lodsv(); commit_EIP(); break; case 0xae: DEBUG_OPERATION("SCAS"); scasb(); commit_EIP(); break; case 0xaf: DEBUG_OPERATION("SCAS"); scasv(); commit_EIP(); break; case 0xb0: fetch_immb(); DEBUG_OPERATION("MOV"); load_Ib(); movb(); store_AL(); commit_EIP(); break; case 0xb1: fetch_immb(); DEBUG_OPERATION("MOV"); load_Ib(); movb(); store_CL(); commit_EIP(); break; case 0xb2: fetch_immb(); DEBUG_OPERATION("MOV"); load_Ib(); movb(); store_DL(); commit_EIP(); break; case 0xb3: fetch_immb(); DEBUG_OPERATION("MOV"); load_Ib(); movb(); store_BL(); commit_EIP(); break; case 0xb4: fetch_immb(); DEBUG_OPERATION("MOV"); load_Ib(); movb(); store_AH(); commit_EIP(); break; case 0xb5: fetch_immb(); DEBUG_OPERATION("MOV"); load_Ib(); movb(); store_CH(); commit_EIP(); break; case 0xb6: fetch_immb(); DEBUG_OPERATION("MOV"); load_Ib(); movb(); store_DH(); commit_EIP(); break; case 0xb7: fetch_immb(); DEBUG_OPERATION("MOV"); load_Ib(); movb(); store_BH(); commit_EIP(); break; case 0xb8: fetch_immv(operand_size_32()); DEBUG_OPERATION("MOV"); load_Iv(); movv(); store_eAX(); commit_EIP(); break; case 0xb9: fetch_immv(operand_size_32()); DEBUG_OPERATION("MOV"); load_Iv(); movv(); store_eCX(); commit_EIP(); break; case 0xba: fetch_immv(operand_size_32()); DEBUG_OPERATION("MOV"); load_Iv(); movv(); store_eDX(); commit_EIP(); break; case 0xbb: fetch_immv(operand_size_32()); DEBUG_OPERATION("MOV"); load_Iv(); movv(); store_eBX(); commit_EIP(); break; case 0xbc: fetch_immv(operand_size_32()); DEBUG_OPERATION("MOV"); load_Iv(); movv(); store_eSP(); commit_EIP(); break; case 0xbd: fetch_immv(operand_size_32()); DEBUG_OPERATION("MOV"); load_Iv(); movv(); store_eBP(); commit_EIP(); break; case 0xbe: fetch_immv(operand_size_32()); DEBUG_OPERATION("MOV"); load_Iv(); movv(); store_eSI(); commit_EIP(); break; case 0xbf: fetch_immv(operand_size_32()); DEBUG_OPERATION("MOV"); load_Iv(); movv(); store_eDI(); commit_EIP(); break; case 0xc0: fetch_modrm(); fetch_immb(); DEBUG_OPERATION_GROUP2(instruction_reg); load_Eb_Ib(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: rolb(); store_Eb(); commit_OF(); commit_CF(); break; case 1: rorb(); store_Eb(); commit_OF(); commit_CF(); break; case 2: rclb(); store_Eb(); commit_OF(); commit_CF(); break; case 3: rcrb(); store_Eb(); commit_OF(); commit_CF(); break; case 4: shlb(); store_Eb(); commit_OSZAPC(); break; case 5: shrb(); store_Eb(); commit_OSZAPC(); break; case 6: ERROR_NYI(); /* salb()/shlb() or error? */ break; case 7: sarb(); store_Eb(); commit_OSZAPC(); break; } commit_EIP(); break; case 0xc1: fetch_modrm(); fetch_immb(); DEBUG_OPERATION_GROUP2(instruction_reg); load_Ev_Ib(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: rolv(); store_Ev(); commit_OF(); commit_CF(); break; case 1: rorv(); store_Ev(); commit_OF(); commit_CF(); break; case 2: rclv(); store_Ev(); commit_OF(); commit_CF(); break; case 3: rcrv(); store_Ev(); commit_OF(); commit_CF(); break; case 4: shlv(); store_Ev(); commit_OSZAPC(); break; case 5: shrv(); store_Ev(); commit_OSZAPC(); break; case 6: ERROR_NYI(); /* salv()/shlv() or error? */ break; case 7: sarv(); store_Ev(); commit_OSZAPC(); break; } commit_EIP(); break; case 0xc2: fetch_immv(0); DEBUG_OPERATION("RET"); load_Iw(); ret_near(); commit_EIP(); break; case 0xc3: DEBUG_OPERATION("RET"); load_0(); ret_near(); commit_EIP(); break; case 0xc4: fetch_modrm(); DEBUG_OPERATION("LES"); load_Mp(); les(); store_Gv(); commit_EIP(); break; case 0xc5: fetch_modrm(); DEBUG_OPERATION("LDS"); load_Mp(); lds(); store_Gv(); commit_EIP(); break; case 0xc6: fetch_modrm(); fetch_immb(); DEBUG_OPERATION("MOV"); load_Ib(); movb(); store_Eb(); commit_EIP(); break; case 0xc7: fetch_modrm(); fetch_immv(operand_size_32()); DEBUG_OPERATION("MOV"); load_Iv(); movv(); store_Ev(); commit_EIP(); break; /* TODO */ case 0xc9: DEBUG_OPERATION("LEAVE"); leave(); commit_EIP(); break; case 0xca: fetch_immv(0); DEBUG_OPERATION("RET"); load_Iw(); ret_far(); commit_EIP(); break; case 0xcb: DEBUG_OPERATION("RET"); load_0(); ret_far(); commit_EIP(); break; case 0xcc: DEBUG_OPERATION("INT3"); int3(); commit_EIP(); break; case 0xcd: fetch_immb(); DEBUG_OPERATION("INTn"); load_Ib(); intn(); commit_EIP(); break; case 0xce: DEBUG_OPERATION("INTO"); into(); commit_EIP(); break; case 0xcf: DEBUG_OPERATION("IRET"); iret(); commit_EIP(); break; case 0xd0: fetch_modrm(); DEBUG_OPERATION_GROUP2(instruction_reg); load_Eb_1(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: rolb(); store_Eb(); commit_OF(); commit_CF(); break; case 1: rorb(); store_Eb(); commit_OF(); commit_CF(); break; case 2: rclb(); store_Eb(); commit_OF(); commit_CF(); break; case 3: rcrb(); store_Eb(); commit_OF(); commit_CF(); break; case 4: shlb(); store_Eb(); commit_OSZAPC(); break; case 5: shrb(); store_Eb(); commit_OSZAPC(); break; case 6: ERROR_NYI(); /* salb()/shlb() or error? */ break; case 7: sarb(); store_Eb(); commit_OSZAPC(); break; } commit_EIP(); break; case 0xd1: fetch_modrm(); DEBUG_OPERATION_GROUP2(instruction_reg); load_Ev_1(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: rolv(); store_Ev(); commit_OF(); commit_CF(); break; case 1: rorv(); store_Ev(); commit_OF(); commit_CF(); break; case 2: rclv(); store_Ev(); commit_OF(); commit_CF(); break; case 3: rcrv(); store_Ev(); commit_OF(); commit_CF(); break; case 4: shlv(); store_Ev(); commit_OSZAPC(); break; case 5: shrv(); store_Ev(); commit_OSZAPC(); break; case 6: ERROR_NYI(); /* salv()/shlv() or error? */ break; case 7: sarv(); store_Ev(); commit_OSZAPC(); break; } commit_EIP(); break; case 0xd2: fetch_modrm(); DEBUG_OPERATION_GROUP2(instruction_reg); load_Eb_CL(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: rolb(); store_Eb(); commit_OF(); commit_CF(); break; case 1: rorb(); store_Eb(); commit_OF(); commit_CF(); break; case 2: rclb(); store_Eb(); commit_OF(); commit_CF(); break; case 3: rcrb(); store_Eb(); commit_OF(); commit_CF(); break; case 4: shlb(); store_Eb(); commit_OSZAPC(); break; case 5: shrb(); store_Eb(); commit_OSZAPC(); break; case 6: ERROR_NYI(); /* salb()/shlb() or error? */ break; case 7: sarb(); store_Eb(); commit_OSZAPC(); break; } commit_EIP(); break; case 0xd3: fetch_modrm(); DEBUG_OPERATION_GROUP2(instruction_reg); load_Ev_CL(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: rolv(); store_Ev(); commit_OF(); commit_CF(); break; case 1: rorv(); store_Ev(); commit_OF(); commit_CF(); break; case 2: rclv(); store_Ev(); commit_OF(); commit_CF(); break; case 3: rcrv(); store_Ev(); commit_OF(); commit_CF(); break; case 4: shlv(); store_Ev(); commit_OSZAPC(); break; case 5: shrv(); store_Ev(); commit_OSZAPC(); break; case 6: ERROR_NYI(); /* salv()/shlv() or error? */ break; case 7: sarv(); store_Ev(); commit_OSZAPC(); break; } commit_EIP(); break; case 0xd4: fetch_immb(); DEBUG_OPERATION("AAM"); load_Ib(); aam(); commit_EIP(); commit_OSZAPC(); break; case 0xd5: fetch_immb(); DEBUG_OPERATION("AAD"); load_Ib(); aad(); commit_EIP(); commit_OSZAPC(); break; /* TODO */ case 0xd7: DEBUG_OPERATION("XLAT"); xlat(); commit_EIP(); break; case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf: fetch_modrm(); DEBUG_OPERATION("ESC"); if (get_EM()) { exception(EXCEPTION_NM, -1); } commit_EIP(); break; case 0xe0: fetch_immb(); DEBUG_OPERATION("LOOPNE"); load_Jb(); loopne(); commit_EIP(); break; case 0xe1: fetch_immb(); DEBUG_OPERATION("LOOPE"); load_Jb(); loope(); commit_EIP(); break; case 0xe2: fetch_immb(); DEBUG_OPERATION("LOOP"); load_Jb(); loop(); commit_EIP(); break; case 0xe3: fetch_immb(); if (address_size_32()) { DEBUG_OPERATION("JECXZ"); load_Jb(); jecxz(); } else { DEBUG_OPERATION("JCXZ"); load_Jb(); jcxz(); } commit_EIP(); break; case 0xe4: fetch_immb(); DEBUG_OPERATION("IN"); load_Ib(); inb(); store_AL(); commit_EIP(); break; case 0xe5: fetch_immb(); DEBUG_OPERATION("IN"); load_Ib(); inv(); store_eAX(); commit_EIP(); break; case 0xe6: fetch_immb(); DEBUG_OPERATION("OUT"); load_Ib_AL(); outb(); commit_EIP(); break; case 0xe7: fetch_immb(); DEBUG_OPERATION("OUT"); load_Ib_eAX(); outv(); commit_EIP(); break; case 0xe8: fetch_immv(operand_size_32()); DEBUG_OPERATION("CALL"); load_Jv(); call_near(); commit_EIP(); break; case 0xe9: fetch_immv(operand_size_32()); DEBUG_OPERATION("JMP"); load_Jv(); jmp_near(); commit_EIP(); break; case 0xea: fetch_ptr(); DEBUG_OPERATION("JMP"); load_Ap(); jmp_far(); commit_EIP(); break; case 0xeb: fetch_immb(); DEBUG_OPERATION("JMP"); load_Jb(); jmp_near(); commit_EIP(); break; case 0xec: DEBUG_OPERATION("IN"); load_DX(); inb(); store_AL(); commit_EIP(); break; case 0xed: DEBUG_OPERATION("IN"); load_DX(); inv(); store_eAX(); commit_EIP(); break; case 0xee: DEBUG_OPERATION("OUT"); load_DX_AL(); outb(); commit_EIP(); break; case 0xef: DEBUG_OPERATION("OUT"); load_DX_eAX(); outv(); commit_EIP(); break; case 0xf0: DEBUG_OPERATION("LOCK prefix"); lock(); prefix_lock_repeat = LR_LOCK; break; case 0xf1: DEBUG_OPERATION("ICEBP"); icebp(); commit_EIP(); break; case 0xf2: DEBUG_OPERATION("REPNE/REPNZ prefix"); if (prefix_lock_repeat == LR_LOCK) { unlock(); } prefix_lock_repeat = LR_REPNZ; break; case 0xf3: DEBUG_OPERATION("REP/REPE/REPZ prefix"); if (prefix_lock_repeat == LR_LOCK) { unlock(); } prefix_lock_repeat = LR_REPZ; break; case 0xf4: DEBUG_OPERATION("HLT"); hlt(); commit_EIP(); break; case 0xf5: DEBUG_OPERATION("CMC"); cmc(); commit_EIP(); break; case 0xf6: fetch_modrm(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: fetch_immb(); DEBUG_OPERATION("TEST"); load_Eb_Ib(); testb(); commit_OSZAPC(); break; case 1: /* FIXME: RESERVED */ ERROR_NYI(); break; case 2: DEBUG_OPERATION("NOT"); load_Eb(); notb(); store_Eb(); break; case 3: DEBUG_OPERATION("NEG"); load_Eb(); negb(); store_Eb(); commit_OSZAPC(); break; case 4: DEBUG_OPERATION("MUL"); load_Eb(); mulb(); commit_OSZAPC(); break; case 5: DEBUG_OPERATION("IMUL"); load_Eb(); imul1b(); commit_OSZAPC(); break; case 6: DEBUG_OPERATION("DIV"); load_Eb(); divb(); commit_OSZAPC(); break; case 7: DEBUG_OPERATION("IDIV"); load_Eb(); idivb(); commit_OSZAPC(); break; } commit_EIP(); break; case 0xf7: fetch_modrm(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: fetch_immv(operand_size_32()); DEBUG_OPERATION("TEST"); load_Ev_Iv(); testv(); commit_OSZAPC(); break; case 1: /* FIXME: RESERVED */ ERROR_NYI(); break; case 2: DEBUG_OPERATION("NOT"); load_Ev(); notv(); store_Ev(); break; case 3: DEBUG_OPERATION("NEG"); load_Ev(); negv(); store_Ev(); commit_OSZAPC(); break; case 4: DEBUG_OPERATION("MUL"); load_Ev(); mulv(); commit_OSZAPC(); break; case 5: DEBUG_OPERATION("IMUL"); load_Ev(); imul1v(); commit_OSZAPC(); break; case 6: DEBUG_OPERATION("DIV"); load_Ev(); divv(); commit_OSZAPC(); break; case 7: DEBUG_OPERATION("IDIV"); load_Ev(); idivv(); commit_OSZAPC(); break; } commit_EIP(); break; case 0xf8: DEBUG_OPERATION("CLC"); clc(); commit_CF(); commit_EIP(); break; case 0xf9: DEBUG_OPERATION("STC"); stc(); commit_CF(); commit_EIP(); break; case 0xfa: DEBUG_OPERATION("CLI"); cli(); commit_IF(); commit_EIP(); break; case 0xfb: DEBUG_OPERATION("STI"); sti(); commit_IF(); commit_EIP_and_delay_interrupts(); break; case 0xfc: DEBUG_OPERATION("CLD"); cld(); commit_DF(); commit_EIP(); break; case 0xfd: DEBUG_OPERATION("STD"); std(); commit_DF(); commit_EIP(); break; case 0xfe: fetch_modrm(); DEBUG_OPERATION_GROUP4(instruction_reg); load_Eb(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: incb(); commit_OSZAP(); break; case 1: decb(); commit_OSZAP(); break; case 2: case 3: case 4: case 5: case 6: case 7: /* TODO reserved */ ERROR_NYI(); } store_Eb(); commit_EIP(); break; case 0xff: fetch_modrm(); switch (instruction_reg) { default: DEBUG_ERROR_SWITCH(); case 0: DEBUG_OPERATION("INC"); load_Ev(); incv(); store_Ev(); commit_OSZAP(); break; case 1: DEBUG_OPERATION("DEC"); load_Ev(); decv(); store_Ev(); commit_OSZAP(); break; case 2: DEBUG_OPERATION("CALL"); load_Ev(); call_near_absolute(); break; case 3: DEBUG_OPERATION("CALL"); load_Ep(); call_far(); break; case 4: DEBUG_OPERATION("JMP"); load_Ev(); jmp_near_absolute(); break; case 5: DEBUG_OPERATION("JMP"); load_Ep(); jmp_far(); break; case 6: DEBUG_OPERATION("PUSH"); load_Ev(); pushv(); break; case 7: /* TODO reserved */ ERROR_NYI(); } commit_EIP(); break; } } /******************************************************************************/ void reset(void) { exception_vector = EXCEPTION_NONE; exception_error_code = -1; exception_is_interrupt = 0; exception_double_page_fault = 0; prefix_clear(); eax = 0x00000000; ebx = 0x00000000; ecx = 0x00000000; edx = 0; /* FIXME: cpu version information */ ebp = 0x00000000; esi = 0x00000000; edi = 0x00000000; esp = 0x00000000; eflag_cf = 0; eflag_pf = 0; eflag_af = 0; eflag_zf = 0; eflag_sf = 0; eflag_tf = 0; eflag_if = 0; eflag_df = 0; eflag_of = 0; eflag_iopl0 = 0; eflag_iopl1 = 0; eflag_nt = 0; eflag_rf = 0; eflag_vm = 0; eip = eip_new = 0x0000fff0; /* NW(29) and CD(30) enabled; ET(4) disabled (no math coprocessor) */ set_CR0(0x60000000); set_CR2(0); set_CR3(0); cs_selector = 0xf000; cs_type = SEGMENT_CODE_EXEC_READ_ACCESSED; cs_sflag = 1; cs_dpl = 0; cs_pflag = 1; cs_segment_limit = 0xffff; cs_segment_base = 0xffff0000; cs_segment_dflag = 0; cs_segment_avlflag = 0; ss_selector = 0x0000; ss_type = SEGMENT_DATA_READ_WRITE_ACCESSED; ss_sflag = 1; ss_dpl = 0; ss_pflag = 1; ss_segment_limit = 0xffff; ss_segment_base = 0x00000000; ss_segment_dflag = 0; ss_segment_avlflag = 0; ds_selector = 0x0000; ds_type = SEGMENT_DATA_READ_WRITE_ACCESSED; ds_sflag = 1; ds_dpl = 0; ds_pflag = 1; ds_segment_limit = 0xffff; ds_segment_base = 0x00000000; ds_segment_dflag = 0; ds_segment_avlflag = 0; es_segment_base = ds_selector; es_type = ds_type; es_sflag = ds_sflag; es_dpl = ds_dpl; es_pflag = ds_pflag; es_segment_limit = ds_segment_limit; es_segment_base = ds_segment_base; es_segment_dflag = ds_segment_dflag; es_segment_avlflag = ds_segment_avlflag; fs_selector = ds_selector; fs_type = ds_type; fs_sflag = ds_sflag; fs_dpl = ds_dpl; fs_pflag = ds_pflag; fs_segment_limit = ds_segment_limit; fs_segment_base = ds_segment_base; fs_segment_dflag = ds_segment_dflag; fs_segment_avlflag = ds_segment_avlflag; gs_selector = ds_selector; gs_type = ds_type; gs_sflag = ds_sflag; gs_dpl = ds_dpl; gs_pflag = ds_pflag; gs_segment_limit = ds_segment_limit; gs_segment_base = ds_segment_base; gs_segment_dflag = ds_segment_dflag; gs_segment_avlflag = ds_segment_avlflag; gdtr_base = 0x00000000; gdtr_limit = 0xffff; idtr_base = 0x00000000; idtr_limit = 0xffff; ldtr_selector = 0x0000; ldtr_system_limit = 0xffff; ldtr_system_base = 0x00000000; tr_selector = 0x0000; tr_type = SEGMENT_32BIT_BUSY_TSS; tr_system_limit = 0xffff; tr_system_base = 0x00000000; interrupt_pending = 0; interrupt_delay = 0; halt_state = 0; } void irq_set(unsigned int value) { DEBUG("\n *** IRQ %u ***\n", value); interrupt_pending = !!value; } void nmi_set(unsigned int value) { DEBUG("\n *** NMI %u ***\n", value); ERROR_NYI(); /* FIXME */ } /****************************************************************************** * * Print State * ******************************************************************************/ void print_state(FILE *f) { int i; fprintf(f, "\n"); fprintf(f, "**************** CPU STATE ****************\n\n"); fprintf(f, "EAX=0x%08x ECX=0x%08x EDX=0x%08x EBX=0x%08x\n", eax, ecx, edx, ebx); fprintf(f, "ESP=0x%08x EBP=0x%08x ESI=0x%08x EDI=0x%08x\n\n", esp, ebp, esi, edi); fprintf(f, "EIP=0x%08x (0x%08x:0x%08x) EFLAGS=0x%08x\n\n", eip + cs_segment_base, cs_segment_base, eip, get_EFLAGS32()); fprintf(f, "CF=%d PF=%d AF=%d ZF=%d\n", eflag_cf, eflag_pf, eflag_af, eflag_zf); fprintf(f, "SF=%d TF=%d IF=%d DF=%d\n", eflag_sf, eflag_tf, eflag_if, eflag_df); fprintf(f, "OF=%d IOPL=%d NT=%d RF=%d\n", eflag_of, get_IOPL(), eflag_nt, eflag_rf); fprintf(f, "VM=%d", eflag_vm); fprintf(f, "CR0=0x%08x CR2=0x%08x CR3=0x%08x\n\n", get_CR0(), get_CR2(), get_CR3()); fprintf(f, "PE=%d MP=%d EM=%d TS=%d\n", cr0_pe, cr0_mp, cr0_em, cr0_ts); fprintf(f, "ET=%d PG=%d\n", cr0_et, cr0_pg); fprintf(f, " CS=0x%04x SS=0x%04x DS=0x%04x " "ES=0x%04x FS=0x%04x GS=0x%04x\n", cs_selector, ss_selector, ds_selector, es_selector, fs_selector, gs_selector); fprintf(f, "limit: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", cs_segment_limit, ss_segment_limit, ds_segment_limit, es_segment_limit, fs_segment_limit, gs_segment_limit); fprintf(f, "scaled: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", cs_segment_limit, ss_segment_limit, ds_segment_limit, es_segment_limit, fs_segment_limit, gs_segment_limit); fprintf(f, "base: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", cs_segment_base, ss_segment_base, ds_segment_base, es_segment_base, fs_segment_base, gs_segment_base); fprintf(f, "type: %8x %8x %8x %8x %8x %8x\n", cs_type, ss_type, ds_type, es_type, fs_type, gs_type); fprintf(f, "dpl: %8x %8x %8x %8x %8x %8x\n", cs_dpl, ss_dpl, ds_dpl, es_dpl, fs_dpl, gs_dpl); fprintf(f, "sflag: %8x %8x %8x %8x %8x %8x\n", cs_sflag, ss_sflag, ds_sflag, es_sflag, fs_sflag, gs_sflag); fprintf(f, "pflag: %8x %8x %8x %8x %8x %8x\n", cs_pflag, ss_pflag, ds_pflag, es_pflag, fs_pflag, gs_pflag); fprintf(f, "dflag: %8x %8x %8x %8x %8x %8x\n", cs_segment_dflag, ss_segment_dflag, ds_segment_dflag, es_segment_dflag, fs_segment_dflag, gs_segment_dflag); fprintf(f, "avlflag: %8x %8x %8x %8x %8x %8x\n\n", cs_segment_avlflag, ss_segment_avlflag, ds_segment_avlflag, es_segment_avlflag, fs_segment_avlflag, gs_segment_avlflag); fprintf(f, "gdtr_limit=0x%08x gdtr_base=0x%08x\n", gdtr_limit, gdtr_base); fprintf(f, "idtr_limit=0x%08x idtr_base=0x%08x\n\n", idtr_limit, idtr_base); fprintf(f, "ldtr_selector=0x%04x ldtr_system_limit=0x%08x\n", ldtr_selector, ldtr_system_limit); fprintf(f, "ldtr_system_base=0x%08x\n\n", ldtr_system_base); fprintf(f, "tr_selector=0x%04x tr_type=%d\n", tr_selector, tr_type); fprintf(f, "tr_system_limit=0x%08x tr_system_base=0x%08x\n\n", tr_system_limit, tr_system_base); fprintf(f, "t0=0x%08x t1=0x%08x t2=0x%08x t3=0x%08x tj=%d\n\n", t0, t1, t2, t3, tj); fprintf(f, "Prefix operand size override: %d\n", prefix_operand_size_override); fprintf(f, "Prefix address size override: %d\n", prefix_address_size_override); fprintf(f, "Prefix segment override: %d\n", prefix_segment_override); fprintf(f, "Prefix lock repeat: %d\n\n", prefix_lock_repeat); fprintf(f, "Instruction opcode: 0x%02x\n", instruction_opcode); fprintf(f, "Instruction opcode2: 0x%02x\n", instruction_opcode2); fprintf(f, "Instruction mod: 0x%x\n", instruction_mod); fprintf(f, "Instruction reg: 0x%x\n", instruction_reg); fprintf(f, "Instruction rm: 0x%x\n", instruction_rm); fprintf(f, "Instruction scale: 0x%x\n", instruction_scale); fprintf(f, "Instruction index: 0x%x\n", instruction_index); fprintf(f, "Instruction base: 0x%x\n", instruction_base); fprintf(f, "Instruction displacement: 0x%x\n", instruction_displacement); fprintf(f, "Instruction immediate: 0x%x\n\n", instruction_immediate); fprintf(f, "**************** MEMORY DUMP ****************\n\n"); for (i = -16; i < 16; i++) { uint32_t esp_addr, eip_addr; esp_addr = (esp & ~3) + 4 * i; eip_addr = (eip & ~3) + 4 * i; fprintf(f, "0x%08x: 0x%08x 0x%08x: 0x%08x\n", esp_addr, mrd(esp_addr, 0), eip_addr, mrd(eip_addr, 0)); } fprintf(f, "\n"); } faucc-20120707/test/test13.c0000640002413100241000000000061111137627476014770 0ustar potyrai3guest/* $Id: test13.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ struct x { int x; struct y { int y; } y; } x; faucc-20120707/test/test.c0000640002413100241000000000064311137627476014631 0ustar potyrai3guest/* $Id: test.c,v 1.3 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ struct x { char arr[10]; }; struct x y; int main(void) { return y.arr[0]; } faucc-20120707/test/test7.c0000640002413100241000000000061011137627476014712 0ustar potyrai3guest/* $Id: test7.c,v 1.3 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ void (*func(int x))(void) { return (void *) 0; } faucc-20120707/test/mb_ibm_at_bios/0000750002413100241000000000000011776113700016414 5ustar potyrai3guestfaucc-20120707/test/mb_ibm_at_bios/00get.sh0000750002413100241000000000130511137630652017672 0ustar potyrai3guest#!/bin/sh # $Id: 00get.sh,v 1.3 2009-01-27 16:09:14 potyra Exp $ # # Copyright (C) 2008-2009 FAUcc Team. # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. # BIOS=$HOME/Work/FAUmachine/node-pc/simulator/bios CONFIG='-DCONFIG_80286_SUPPORT' for section in INIT_RM INIT_EARLY RUNTIME_PM RUNTIME_RM ; do ( cd ${BIOS} ls *.c ) \ | while read file ; do file=`echo ${file} | sed -e 's/\.c//'` gcc -m32 -E ${CONFIG} -I${BIOS} -I${BIOS}/.. -I${BIOS}/../.. -D${section} -I${BIOS}/../../.. ${BIOS}/${file}.c > ${file}.${section}.i done done faucc-20120707/test/dotests.sh0000750002413100241000000000274611721455120015517 0ustar potyrai3guest#!/bin/sh TEST="test-bda test-conv test-expr test-if test-switch test-hello-world test-ext" TEST2="test.c \ test3.c \ test4.c \ test5.c \ test6.c \ test7.c \ test8.c \ test9.c \ test10.c \ test11.c \ test12.c \ test13.c \ test14.c \ test15.c \ test16.c \ test17.c \ test18.c \ test19.c \ test20.c \ test21.c \ \ chip_intel_80386_inline.c \ test-hello-world.c \ test-i386-add.c \ test-i386.c \ test-i386-noinline.c" for test in ${TEST} ; do echo "${test}" # Check for warnings. gcc -Wall -c ${test}.c rm -f ${test}.o # Generate assembler code using gcc. gcc -S -m32 -falign-functions=15 ${test}.c mv ${test}.s ${test}.s.gcc # Generate assembler code using faucc with different args. ( echo "-b i386 -falign-functions=15" echo "-b i286 -falign-functions=15" echo "-b i286 -falign-functions=15 -fsegment_enable" ) \ | while read args ; do echo "${test} (${args})..." # Generate assembler code using faucc. ../faucc -S ${args} ${test}.c 2>&1 \ | grep -v 'Fixing declaration of ' # Call assembler to check syntax. gcc -c ${test}.s rm -f ${test}.o # Save generated file for later inspection. mv ${test}.s ${test}.s."${args}" done echo "" done cd bios for file in *.i ; do file=`basename ${file} .i` echo "${file}..." # Generate assembler code using faucc. ../../faucc -S -b i286 -fsegment_enable ${file}.i 2>&1 \ | grep -v 'Fixing declaration of ' # Call assembler to check syntax. ../../faucc -c -b i286 ${file}.s done cd .. faucc-20120707/test/test-i386-noinline.c0000640002413100241000000017210711137627476017136 0ustar potyrai3guest/* $Id: test-i386-noinline.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CHIP_H__ #define __CHIP_H__ #include /******************************************************************************/ typedef enum { false, true } bool; /******************************************************************************/ /* QEMU: arch_gen_cpu_x86_sim_fast.c */ #define lock() #define unlock() /******************************************************************************/ extern bool bit_get(uint32_t *bitset, int index); extern void bit_set(uint32_t *bitset, int index, bool value); extern void bit_set_undef(uint32_t *bitset, int index); /******************************************************************************/ extern void __attribute__((__noreturn__)) globalreturn(void); /* only use at points never reached! */ #define ERROR() error(__FILE__, __LINE__) extern __attribute__((__noreturn__)) void error(const char *file, int line); /******************************************************************************/ #endif /* __CHIP_H__ */ /******************************************************************************/ extern uint8_t fetch_uint8(uint32_t); extern uint16_t fetch_uint16(uint32_t); extern uint32_t fetch_uint32(uint32_t); extern uint8_t load_uint8(uint32_t addr); extern uint16_t load_uint16(uint32_t addr); extern uint32_t load_uint32(uint32_t addr); extern void store_uint8(uint8_t value, uint32_t addr); extern void store_uint16(uint16_t value, uint32_t addr); extern void store_uint32(uint32_t value, uint32_t addr); /******************************************************************************/ enum operand_t { OPERAND_EAX = 0, OPERAND_ECX = 1, OPERAND_EDX = 2, OPERAND_EBX = 3, OPERAND_ESP = 4, OPERAND_EBP = 5, OPERAND_ESI = 6, OPERAND_EDI = 7, OPERAND_IMMEDIATE, OPERAND_ADDRESS, OPERAND_CS, OPERAND_SS, OPERAND_DS, OPERAND_ES, OPERAND_FS, OPERAND_GS }; enum size_t { SIZE_8, SIZE_16, SIZE_32 }; enum segment_t { SEGMENT_NONE = -1, SEGMENT_ES = 0, SEGMENT_CS = 1, SEGMENT_SS = 2, SEGMENT_DS = 3, SEGMENT_FS = 4, SEGMENT_GS = 5, SEGMENT_INVALID = 6 }; enum lock_repeat_t { LR_NONE, LR_LOCK, LR_REPNZ, LR_REPZ }; enum eflag_t { EFLAG_CF = 0, // Carry Flag // 1: Reserved (set to 1) EFLAG_PF = 2, // Parity Flag // 3: Reserved (set to 0) EFLAG_AF = 4, // Auxiliary Carry Flag // 5: Reserved (set to 0) EFLAG_ZF = 6, // Zero Flag EFLAG_SF = 7, // Sign Flag EFLAG_TF = 8, // Trap Flag EFLAG_IF = 9, // Interrupt Enable Flag EFLAG_DF = 10, // Direction Flag EFLAG_OF = 11, // Overflow Flag EFLAG_IOPL0 = 12, // I/O Privilege Level EFLAG_IOPL1 = 13, // I/O Privilege Level EFLAG_NT = 14, // Nested Task // 15: Reserved (set to 0) EFLAG_RF = 16, // Resume Flag EFLAG_VM = 17, // Virtual-8086 Mode EFLAG_AC = 18, // Alignment Check EFLAG_VIF = 19, // Virtual Interrupt Flag EFLAG_VIP = 20, // Virtual Interrupt Pending EFLAG_ID = 21 // ID Flag // 22: Reserved (set to 0) // ... // 31: Reserved (set to 0) }; enum cr0_t { CR0_PE = 0, // Protection Enable CR0_MP = 1, // Monitor Coprocessor CR0_EM = 2, // Emulation CR0_TS = 3, // Task Switched CR0_ET = 4, // Extension Type CR0_NE = 5, // Numeric Error // Reserved CR0_WP = 16, // Write Protect // Reserved CR0_AM = 18, // Alignment Mask // Reserved CR0_NW = 29, // Not Write-through CR0_CD = 30, // Cache Disbale CR0_PG = 31 // Paging }; enum cr3_t { // Reserved CR3_PWT = 3, // Page-level Writes Transparent CR3_PCD = 4, // Page-level Cache Disable // Reserved // 12-31: Page-Directory Base }; enum cr4_t { CR4_VME = 0, // Virtual-8086 Mode Extensions CR4_PVI = 1, // Protected-Mode Virtual Interrupts CR4_TSD = 2, // Time Stamp Disable CR4_DE = 3, // Debugging Extensions CR4_PSE = 4, // Page Size Extensiion CR4_PAE = 5, // Physical Address Extension CR4_MCE = 6, // Machine-Check Enable CR4_PGE = 7, // Page Global Enable CR4_PCE = 8, // Performance-Monitoring Counter Enable CR4_OSFXSR = 9, // Operating System FXSAVE/FXRSTOR Support CR4_OSXMMEXCPT = 10, // Operating System Unmasked Exception Support // 11: Reserved (set to 0) // ... // 31: Reserved (set to 0) }; enum exception_t { EXCEPTION_NONE = -1, EXCEPTION_DE = 0, // Fault: Divide Error EXCEPTION_DB = 1, // Fault/Trap: Debug EXCEPTION_NMI = 2, // Interrupt: NMI Interrupt EXCEPTION_BP = 3, // Trap: Breakpoint EXCEPTION_OF = 4, // Trap: Overflow EXCEPTION_BR = 5, // Fault: BOUND Range Exceeded EXCEPTION_UD = 6, // Fault: Invalid Opcode (Undefined Opcode) EXCEPTION_NM = 7, // Fault: Device Not Available (No Math Coprocessor) EXCEPTION_DF = 8, // Abort: Double Fault EXCEPTION_009 = 9, // Fault: Coprocessor Segment Overrun (reserved) EXCEPTION_TS = 10, // Fault: Invalid TSS EXCEPTION_NP = 11, // Fault: Segment Not Present EXCEPTION_SS = 12, // Fault: Stack-Segment Fault EXCEPTIOB_GP = 13, // Fault: General Protection EXCEPTION_PF = 14, // Fault: Page Fault EXCEPTION_015 = 15, // Intel reserved. Do not use. EXCEPTION_MF = 16, // Fault: Floating-Point Error (Math Fault) EXCEPTION_AC = 17, // Fault: Alignment Check EXCEPTION_MC = 18, // Abort: Machine Check EXCEPTION_XF = 19, // Fault: Streaming SIMD Extensions EXCEPTION_020 = 20, // Intel reserved. Do not use. /* ... */ EXCEPTION_031 = 31, // Intel reserved, Do not use. EXCEPTION_032 = 32, // Interrupt: User Defined (Nonreserved) Interrupts /* ... */ EXCEPTION_255 = 255 // Interrupt: User Defined (Nonreserved) Interrupts }; enum jcc_t { JCC_O = 0, // overflow (OF=1) JCC_B = 1, // below (CF=1) JCC_Z = 2, // zero (ZF=1) JCC_BE = 3, // below or equal (CF=1 or ZF=1) JCC_S = 4, // sign (SF=1) JCC_P = 5, // parity (PF=1) JCC_L = 6, // less (SF<>OF) JCC_LE = 7, // less or equal (ZF=1 or SF<>OF) }; /****************************************************************************** * * General-purpose data registers * ******************************************************************************/ static uint32_t eax; // Accumulator for operands and results data static uint32_t ecx; // Counter for string and loop operations static uint32_t edx; // I/O pointer static uint32_t ebx; // Pointer to data in the DS segment static uint32_t esp; // Stack pointer (in the SS segment) static uint32_t ebp; // Pointer to data on the stack (in the SS segment) static uint32_t esi; // Pointer to data in the segment pointed to by the DS register; source pointer for string operations static uint32_t edi; // Pointer to data (or destination) in the segment pointed to by the ES register; destination pointer for string operations /****************************************************************************** * * Segment Registers * ******************************************************************************/ static uint16_t cs; // Code Segment static uint16_t ss; // Stack Segment static uint16_t ds; // Data Segment static uint16_t es; // Data Segment static uint16_t fs; // Data Segment static uint16_t gs; // Data Segment /****************************************************************************** * * Status and Control Registers * ******************************************************************************/ static uint32_t eip; // Instruction pointer static uint32_t eflags; // EFLAGS Register //static uint32_t cr0; // Control Register 0: Contains system control flags that control operating mode and states of the processor //static uint32_t cr1; // Control Register 1: Reserved //static uint32_t cr2; // Control Register 2: Contains the page-fault linear address (the linear address that caused a page fault) //static uint32_t cr3; // Control Register 3: Contains the physical address of the base of the page directory and two flags (PCD and PWT) //static uint32_t cr4; // Control Register 4: Contains a group of flags that enable several architecture extensions, as well as indicating the level of OS support for the Streaming SIMD Extension /****************************************************************************** * * Memory-management Registers * ******************************************************************************/ //static uint32_t gdtr_base_address; //static uint16_t gdtr_table_limit; //static uint32_t idtr_base_address; //static uint16_t idtr_table_limit; //static uint16_t tr_segment_selector; //static uint32_t tr_base_address; //static uint16_t tr_segment_limit; //static uint16_t ldtr_segment_selector; //static uint32_t ldtr_base_address; //static uint16_t ldtr_segment_limit; /******************************************************************************/ static bool cs_size32; // D Flag in Code Segment Descriptor static bool ss_size32; // address size attribute of the stack segment (QEMU: ss32) static bool prefix_operand_size_override; static bool prefix_address_size_override; static enum segment_t prefix_segment_override; static enum lock_repeat_t prefix_lock_repeat; static enum exception_t exception_vector; static uint16_t exception_error_code; /****************************************************************************** * * Mask * ******************************************************************************/ static uint32_t mask(uint32_t t, enum size_t size) { uint32_t value; switch (size) { case SIZE_8: value = t & 0xff; break; case SIZE_16: value = t & 0xffff; break; case SIZE_32: value = t & 0xffffffff; break; default: ERROR(); } return value; } /****************************************************************************** * * Exception * ******************************************************************************/ static void exception(enum exception_t vector, uint16_t error_code) { exception_vector = vector; exception_error_code = error_code; globalreturn(); } /****************************************************************************** * * EFLAGS Register Accessors * ******************************************************************************/ static bool eflag_get(enum eflag_t eflag) { return bit_get(&eflags, eflag); } static void eflag_set(enum eflag_t eflag, bool value) { bit_set(&eflags, eflag, value); } static void eflag_set_undef(enum eflag_t eflag) { bit_set_undef(&eflags, eflag); } /****************************************************************************** * * Effective Operand- and Address-Size Attributes * * D Flag in Code Segment Descriptor 0 0 0 0 1 1 1 1 * Operand-Size Prefix 0x66 N N Y Y N N Y Y * Address-Size Prefix 0x67 N Y N Y N Y N Y * Effective Operand Size 16 16 32 32 32 32 16 16 * Effective Address Size 16 32 16 32 32 16 32 16 * ******************************************************************************/ static enum size_t effective_operand_size(void) { if (cs_size32 ^ prefix_operand_size_override) return SIZE_32; else return SIZE_16; } static enum size_t effective_address_size(void) { if (cs_size32 ^ prefix_address_size_override) return SIZE_32; else return SIZE_16; } /****************************************************************************** * * Instruction Fetch * ******************************************************************************/ static uint32_t fetch(uint32_t *counter, enum size_t size) { uint32_t value; if (!counter) ERROR(); switch (size) { case SIZE_8: value = fetch_uint8(eip + cs); *counter += 1; break; case SIZE_16: value = fetch_uint16(eip + cs); *counter += 2; break; case SIZE_32: value = fetch_uint32(eip + cs); *counter += 4; break; default: ERROR(); } return value; } /****************************************************************************** * * Store (Register and Memeory) * * SIZE_8 SIZE_16 SIZE_32 * OPERAND_EAX AL AX EAX * OPERAND_ECX CL CX ECX * OPERAND_EDX DL DX EDX * OPERAND_EBX BL BX EBX * OPERAND_ESP AH SP ESP * OPERAND_EBP CH BP EBP * OPERAND_ESI DH SI ESI * OPERAND_EDI BH DI EDI * ******************************************************************************/ static void store(uint32_t t, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { switch (operand) { case OPERAND_EAX: eax = mask(t, size); break; case OPERAND_ECX: ecx = mask(t, size); break; case OPERAND_EDX: edx = mask(t, size); break; case OPERAND_EBX: ebx = mask(t, size); break; case OPERAND_ESP: if (size == SIZE_8) // AH !!! eax = (t & 0xff) << 8; else esp = mask(t, size); break; case OPERAND_EBP: if (size == SIZE_8) // CH !!! ecx = (t & 0xff) << 8; else ebp = mask(t, size); break; case OPERAND_ESI: if (size == SIZE_8) // DH !!! edx = (t & 0xff) << 8; else esi = mask(t, size); break; case OPERAND_EDI: if (size == SIZE_8) // BH !!! ebx = (t & 0xff) << 8; else edi = mask(t, size); break; case OPERAND_IMMEDIATE: ERROR(); break; case OPERAND_ADDRESS: switch (segment) { case SEGMENT_NONE: break; case SEGMENT_CS: addr += cs; break; case SEGMENT_SS: addr += ss; break; case SEGMENT_DS: addr += ds; break; case SEGMENT_ES: addr += es; break; case SEGMENT_FS: addr += fs; break; case SEGMENT_GS: addr += gs; break; default: ERROR(); } switch (size) { case SIZE_8: store_uint8(t, addr); break; case SIZE_16: store_uint16(t, addr); break; case SIZE_32: store_uint32(t, addr); break; default: ERROR(); } break; case OPERAND_CS: cs = mask(t, size); break; case OPERAND_SS: ss = mask(t, size); break; case OPERAND_DS: ds = mask(t, size); break; case OPERAND_ES: es = mask(t, size); break; case OPERAND_FS: fs = mask(t, size); break; case OPERAND_GS: gs = mask(t, size); break; default: ERROR(); } } /****************************************************************************** * * Load (Register and Memory) * * SIZE_8 SIZE_16 SIZE_32 * OPERAND_EAX AL AX EAX * OPERAND_ECX CL CX ECX * OPERAND_EDX DL DX EDX * OPERAND_EBX BL BX EBX * OPERAND_ESP AH SP ESP * OPERAND_EBP CH BP EBP * OPERAND_ESI DH SI ESI * OPERAND_EDI BH DI EDI * ******************************************************************************/ static uint32_t load(uint32_t *counter, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { uint32_t value; switch (operand) { case OPERAND_EAX: value = eax; break; case OPERAND_ECX: value = ecx; break; case OPERAND_EDX: value = edx; break; case OPERAND_EBX: value = ebx; break; case OPERAND_ESP: if (size == SIZE_8) // AH !!! value = eax >> 8; else value = esp; break; case OPERAND_EBP: if (size == SIZE_8) // CH !!! value = ecx >> 8; else value = ebp; break; case OPERAND_ESI: if (size == SIZE_8) // DH !!! value = edx >> 8; else value = esi; break; case OPERAND_EDI: if (size == SIZE_8) // BH !!! value = ebx >> 8; else value = edi; break; case OPERAND_IMMEDIATE: value = fetch(counter, size); break; case OPERAND_ADDRESS: switch (segment) { case SEGMENT_NONE: break; case SEGMENT_CS: addr += cs; break; case SEGMENT_SS: addr += ss; break; case SEGMENT_DS: addr += ds; break; case SEGMENT_ES: addr += es; break; case SEGMENT_FS: addr += fs; break; case SEGMENT_GS: addr += gs; break; default: ERROR(); } switch (size) { case SIZE_8: value = load_uint8(addr); break; case SIZE_16: value = load_uint16(addr); break; case SIZE_32: value = load_uint32(addr); break; default: ERROR(); } break; case OPERAND_CS: value = cs; break; case OPERAND_SS: value = ss; break; case OPERAND_DS: value = ds; break; case OPERAND_ES: value = es; break; case OPERAND_FS: value = fs; break; case OPERAND_GS: value = gs; break; default: ERROR(); } return value; } /****************************************************************************** * * Update SF - Sign flag * * Set equal to the most-significant bit of the result, which is the sign bit * of a signed integer. (0 indicates a positive value and 1 indicates a negative * value.) * ******************************************************************************/ static void update_sf(uint32_t t, enum size_t size) { switch (size) { case SIZE_8: eflag_set(EFLAG_SF, t >> 7); break; case SIZE_16: eflag_set(EFLAG_SF, t >> 15); break; case SIZE_32: eflag_set(EFLAG_SF, t >> 31); break; default: ERROR(); } } /****************************************************************************** * * Update ZF - Zero flag * * Set if the result is zero; cleared otherwise. * ******************************************************************************/ static void update_zf(uint32_t t) { eflag_set(EFLAG_ZF, t == 0); } /****************************************************************************** * * Update PF - Parity flag * * Set if the least-significant byte of the result contains an even number * of 1 bits; cleared otherwise. * ******************************************************************************/ static void update_pf(uint32_t t) { static const uint8_t parity_table[256] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x00 - 0x0f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x10 - 0x1f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x20 - 0x2f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x30 - 0x3f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x40 - 0x4f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x50 - 0x5f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x60 - 0x6f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x70 - 0x7f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x80 - 0x8f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x90 - 0x9f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0xa0 - 0xaf 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0xb0 - 0xbf 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0xc0 - 0xcf 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0xd0 - 0xdf 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0xe0 - 0xef 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0xf0 - 0xff }; eflag_set(EFLAG_PF, parity_table[t & 0xff]); } /****************************************************************************** * * Update 'Result' - Flags * * Update SF, ZF and PF. * ******************************************************************************/ static void update_sf_zf_pf(uint32_t t, enum size_t size) { update_sf(t, size); update_zf(t); update_pf(t); } /****************************************************************************** * * Arithmetic and Logic Generator Functions * ******************************************************************************/ /* Increment by 1 */ static void inc(uint32_t counter, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand, size, addr, segment); t2 = 1; t0 = mask(t1 + t2, size); store(t0, operand, size, addr, segment); update_sf_zf_pf(t0, size); /* cf unchanged */ eflag_set(EFLAG_OF, t0 == 0); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Decrement by 1 */ static void dec(uint32_t counter, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand, size, addr, segment); t2 = 1; t0 = mask(t1 - t2, size); store(t0, operand, size, addr, segment); update_sf_zf_pf(t0, size); /* cf unchanged */ eflag_set(EFLAG_OF, t0 == mask(-1, size)); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Add */ static void add(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 + t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, t0 < t1); eflag_set(EFLAG_OF, (t1 ^ t2 ^ -1) & (t1 ^ t0)); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Logical Inclusive OR */ static void or(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 | t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, false); eflag_set(EFLAG_OF, false); eflag_set_undef(EFLAG_AF); eip += counter; } /* Add with Carry */ static void adc(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 + t2 + eflag_get(EFLAG_CF), size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, t0 <= t1); eflag_set(EFLAG_OF, (t1 ^ t2 ^ -1) & (t1 ^ t0)); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Integer Subtraction with Borrow */ static void sbb(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 - (t2 + eflag_get(EFLAG_CF)), size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, t1 <= t2); eflag_set(EFLAG_OF, (t1 ^ t2) & (t1 ^ t0)); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Logical AND */ static void and(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 & t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, false); eflag_set(EFLAG_OF, false); eflag_set_undef(EFLAG_AF); eip += counter; } /* Substract */ static void sub(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 - t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, t1 < t2); eflag_set(EFLAG_OF, (t1 ^ t2) & (t1 ^ t0)); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Logical Exclusive OR */ static void xor(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 ^ t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, false); eflag_set(EFLAG_OF, false); eflag_set_undef(EFLAG_AF); eip += counter; } /* Compare Two Operands */ static void cmp(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 - t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set_undef(EFLAG_CF); // FIXME eflag_set_undef(EFLAG_OF); // FIXME eflag_set_undef(EFLAG_AF); // FIXME eip += counter; } /******************************************************************************/ static void test(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static void not(uint32_t counter, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static void neg(uint32_t counter, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static void mul(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static void imul(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static void div(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static void idiv(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } /****************************************************************************** * * MOV * ******************************************************************************/ static void mov(uint32_t counter, enum operand_t operand_dst, enum size_t size_dst, enum operand_t operand_src, enum size_t size_src, uint32_t addr, enum segment_t segment) { uint32_t t; t = load(&counter, operand_src, size_src, addr, segment); store(t, operand_dst, size_dst, addr, segment); eip += counter; } /****************************************************************************** * * Push and Pop Generator Functions * ******************************************************************************/ static void push(uint32_t counter, enum operand_t operand, enum size_t operand_size, uint32_t addr, enum segment_t segment, enum size_t stack_size) { uint32_t a, t; switch (operand_size) { case SIZE_8: ERROR(); case SIZE_16: esp -= 2; break; case SIZE_32: esp -= 4; break; default: ERROR(); } esp = mask(esp, stack_size); a = mask(esp + ss, stack_size); t = load(&counter, operand, operand_size, addr, segment); switch (operand_size) { case SIZE_8: ERROR(); case SIZE_16: store_uint16(t, a); break; case SIZE_32: store_uint32(t, a); break; default: ERROR(); } eip += counter; } static void pop(uint32_t counter, enum operand_t operand, enum size_t operand_size, uint32_t addr, enum segment_t segment, enum size_t stack_size) { uint32_t a, t; a = mask(esp + ss, stack_size); switch (operand_size) { case SIZE_8: ERROR(); case SIZE_16: t = load_uint16(a); break; case SIZE_32: t = load_uint32(a); break; default: ERROR(); } store(t, operand, operand_size, addr, segment); switch (operand_size) { case SIZE_8: ERROR(); case SIZE_16: esp += 2; break; case SIZE_32: esp += 4; break; default: ERROR(); } esp = mask(esp, stack_size); eip += counter; } static void jecxz(uint32_t counter, enum size_t size) { int8_t offset; bool condition; offset = fetch(&counter, SIZE_8); condition = mask(ecx, size) == 0; eip += counter; // FIXME: check segment limits if (condition) { eip += offset; eip = mask(eip, size); } } static void jcc(uint32_t counter, enum jcc_t cc, bool negate, enum size_t size) { int32_t offset; bool condition; offset = fetch(&counter, size); switch (cc) { case JCC_O: condition = eflag_get(EFLAG_OF); break; case JCC_B: condition = eflag_get(EFLAG_CF); break; case JCC_Z: condition = eflag_get(EFLAG_ZF); break; case JCC_BE: condition = eflag_get(EFLAG_CF) || eflag_get(EFLAG_ZF); break; case JCC_S: condition = eflag_get(EFLAG_SF); break; case JCC_P: condition = eflag_get(EFLAG_PF); break; case JCC_L: condition = eflag_get(EFLAG_SF) != eflag_get(EFLAG_OF); break; case JCC_LE: condition = eflag_get(EFLAG_ZF) || (eflag_get(EFLAG_SF) != eflag_get(EFLAG_OF)); break; default: ERROR(); } condition ^= negate; eip += counter; // FIXME: check segment limits if (condition) { eip += offset; if (size == SIZE_16) eip &= 0xffff; } } /****************************************************************************** * * LAHF - Load Status Flags into AH Register * * AH = SF:ZF:0:AF:0:PF:1:CF * * Flags: None * Exceptions: None * ******************************************************************************/ static void lahf(uint32_t counter) { uint8_t ah; ah = 0; ah &= eflag_get(EFLAG_CF) << EFLAG_CF; ah &= 1 << 1; ah &= eflag_get(EFLAG_PF) << EFLAG_PF; ah &= 0 << 3; ah &= eflag_get(EFLAG_AF) << EFLAG_AF; ah &= 0 << 5; ah &= eflag_get(EFLAG_ZF) << EFLAG_ZF; ah &= eflag_get(EFLAG_SF) << EFLAG_SF; eax = ah << 8; eip += counter; } /****************************************************************************** * * DAA - Decimal Adjust AL after Addition * * Flags: CF, AF, SF, ZF, PF, OF * Exceptions: None * ******************************************************************************/ static void daa(uint32_t counter) { uint8_t al; bool af, cf; al = eax & 0xff; af = eflag_get(EFLAG_AF); cf = eflag_get(EFLAG_CF); if (((al & 0x0f) > 9) || af) { cf = ((al > 0xf9) || cf); af = true; al += 6; } else { af = false; } if (((al & 0xf0) > 0x90) || cf) { al += 0x60; cf = true; } else { cf = false; } eax = al; eflag_set(EFLAG_AF, af); eflag_set(EFLAG_CF, cf); update_sf_zf_pf(al, SIZE_8); eip += counter; } /****************************************************************************** * * Handler for the operand-identifier byte (ModR/M byte) and the * addressing-mode specifier byte (SIB byte). * * Reads the ModR/M byte and if required: 1 SIB byte and 1, 2 or 4 bytes * displacement. * * Possible return values for operand_reg: * OPERAND_EAX, OPERAND_ECX, OPERAND_EDX, OPERAND_EBX, * OPERAND_ESP, OPERAND_EBP, OPERAND_ESI, OPERAND_EDI * * Possible return values for operand_rm: * OPERAND_EAX, OPERAND_ECX, OPERAND_EDX, OPERAND_EBX, * OPERAND_ESP, OPERAND_EBP, OPERAND_ESI, OPERAND_EDI, * OPERAND_ADDRESS (the address value is stored in addr) * * Mod/RM: * * 7 6 5 4 3 2 1 0 * Mod Reg R/M * * SIB: * 7 6 5 4 3 2 1 0 * Scale Index Base * ******************************************************************************/ static void fetch_mod_rm(uint32_t *counter, enum operand_t *operand_reg, enum operand_t *operand_rm, uint32_t *addr, enum segment_t *segment) { int mod_rm, mod, reg, rm; mod_rm = fetch(counter, SIZE_8); mod = (mod_rm >> 6) & 3; reg = (mod_rm >> 3) & 7; rm = mod_rm & 7; if (operand_reg) *operand_reg = reg; if (!operand_rm) return; if (mod == 3) { *operand_rm = rm; return; } *operand_rm = OPERAND_ADDRESS; if (!addr) ERROR(); if (!segment) ERROR(); // now calculate the address if (cs_size32 ^ prefix_address_size_override) { int scale, index, base; uint32_t disp; if (rm == 4) { int sib = fetch(counter, SIZE_8); scale = (sib >> 6) & 3; index = (sib >> 3) & 7; base = sib & 7; } else { scale = 0; index = 0; base = rm; } switch (mod & 3) { case 0: // no disp, exception: rm == 5 if (base == 5) { disp = fetch(counter, SIZE_32); base = -1; } else { disp = 0; } break; case 1: // disp8 disp = fetch(counter, SIZE_8); break; case 2: // disp32 disp = fetch(counter, SIZE_32); break; case 3: // register only: already handled default: ERROR(); } if (disp != 0) *addr = disp; // IMMEDIATE else *addr = 0; if (base >= 0) { // TODO? popl handling with esp switch (base & 7) { case OPERAND_EAX: *addr += eax; break; case OPERAND_ECX: *addr += ecx; break; case OPERAND_EDX: *addr += edx; break; case OPERAND_EBX: *addr += ebx; break; case OPERAND_ESP: *addr += esp; break; case OPERAND_EBP: *addr += ebp; break; case OPERAND_ESI: *addr += esi; break; case OPERAND_EDI: *addr += edi; break; default: ERROR(); } } switch (index & 7) { case OPERAND_EAX: *addr += eax * (1 << scale); break; case OPERAND_ECX: *addr += ecx * (1 << scale); break; case OPERAND_EDX: *addr += edx * (1 << scale); break; case OPERAND_EBX: *addr += ebx * (1 << scale); break; case OPERAND_ESP: ERROR(); case OPERAND_EBP: *addr += ebp * (1 << scale); break; case OPERAND_ESI: *addr += esi * (1 << scale); break; case OPERAND_EDI: *addr += edi * (1 << scale); break; default: ERROR(); } if (prefix_segment_override != SEGMENT_NONE) *segment = prefix_segment_override; else if (base == OPERAND_EBP || base == OPERAND_ESP) *segment = SEGMENT_SS; else *segment = SEGMENT_DS; } else { uint32_t disp; switch (mod) { case 0: // no disp, exception: rm == 6 if (rm == 6) { disp = fetch(counter, SIZE_16); rm = -1; } else { disp = 0; } break; case 1: // disp8 disp = fetch(counter, SIZE_8); break; case 2: // disp16 disp = fetch(counter, SIZE_16); break; case 3: // register only (already checked) default: ERROR(); } if (disp != 0) *addr = disp; // IMMEDIATE else *addr = 0; switch (rm) { case -1: break; case 0: *addr += ebx + esi; break; case 1: *addr += ebx + edi; break; case 2: *addr += ebp + esi; break; case 3: *addr += ebp + edi; break; case 4: *addr += esi; break; case 5: *addr += edi; break; case 6: *addr += ebp; break; case 7: *addr += ebx; break; default: ERROR(); } *addr = *addr & 0xffff; if (prefix_segment_override != SEGMENT_NONE) *segment = prefix_segment_override; else if (rm == 2 || rm == 3 || rm == 6) *segment = SEGMENT_SS; else *segment = SEGMENT_DS; } } /****************************************************************************** * * Handler for arithmetic and logic instructions * * Opcode: * * 7 6 5 4 3 2 1 0 * 0 0 Operation Direction Immediate Operandsize * ******************************************************************************/ static void handle_arithmetic_and_logic(uint32_t counter, uint32_t opcode) { int operation, direction, immediate; enum operand_t operand_a, operand_b; enum segment_t segment; enum size_t size; uint32_t addr; operation = (opcode >> 3) & 7; direction = (opcode >> 1) & 1; immediate = (opcode >> 2) & 1; if ((opcode & 1) == 0) size = SIZE_8; else size = effective_operand_size(); if (immediate == 1) { operand_a = OPERAND_EAX; operand_b = OPERAND_IMMEDIATE; } else { enum operand_t operand_reg, operand_rm; fetch_mod_rm(&counter, &operand_reg, &operand_rm, &addr, &segment); if (direction == 0) { operand_a = operand_rm; operand_b = operand_reg; } else { operand_a = operand_reg; operand_b = operand_rm; } } switch (operation & 7) { case 0x0: add(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x1: or(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x2: adc(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x3: sbb(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x4: and(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x5: sub(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x6: xor(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x7: cmp(counter, operand_a, size, operand_b, size, addr, segment); break; default: ERROR(); } } /****************************************************************************** * * Handler for Immediate Group 1 * * Bits 5, 4 and 3 of ModR/M byte used as an opcode extension. * ******************************************************************************/ static void handle_group_1(uint32_t counter, uint32_t opcode) { enum operand_t operand_a, operand_b; enum size_t size_a, size_b; enum segment_t segment; int operation; uint32_t addr; if ((opcode & 1) == 0) size_a = SIZE_8; else size_a = effective_operand_size(); if (opcode == 0x83) size_b = SIZE_8; else size_b = size_a; operand_b = OPERAND_IMMEDIATE; fetch_mod_rm(&counter, (enum operand_t *) &operation, &operand_a, &addr, &segment); switch (operation & 7) { case 0x0: add(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x1: or(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x2: adc(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x3: sbb(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x4: and(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x5: sub(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x6: xor(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x7: cmp(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; default: ERROR(); } } /****************************************************************************** * * Handler for Unary Group 3 * * Bits 5, 4 and 3 of ModR/M byte used as an opcode extension. * ******************************************************************************/ static void handle_group_3(uint32_t counter, uint32_t opcode) { enum operand_t operand_a, operand_b; enum segment_t segment; enum size_t size; int operation; uint32_t addr; if ((opcode & 1) == 0) size = SIZE_8; else size = effective_operand_size(); fetch_mod_rm(&counter, (enum operand_t *) &operation, &operand_b, &addr, &segment); if (operation != 0x2 && operation != 0x3) operand_b = OPERAND_IMMEDIATE; switch (operation & 7) { case 0x0: test(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x1: ERROR(); break; case 0x2: not(counter, operand_a, size, addr, segment); break; case 0x3: neg(counter, operand_a, size, addr, segment); break; case 0x4: mul(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x5: imul(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x6: div(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x7: idiv(counter, operand_a, size, operand_b, size, addr, segment); break; default: ERROR(); } } /****************************************************************************** * * Handler for Group 4 and Group 5 * * Bits 5, 4 and 3 of ModR/M byte used as an opcode extension. * ******************************************************************************/ /* static void handle_group_4_and_5(uint32_t counter, uint32_t opcode) { int operand_size, opcode_extension, mod, rm; if ((opcode & 1) == 0) operand_size = 1; else operand_size = prefix_operand_size_override ? 4 : 2; decode_mod_rm(GET(1), &mod, &opcode_extension, &rm); if (opcode_extension >= 2 && opcode == 0xfe) { // TODO // gen_exception(c, CPU_FAULT_UD, pc_start - s->cs_base); // return; } if (mod != 3) { // TODO load: gen_lea_modrm // set ADDR } else { gen_load_reg_t1(rm, op_size); } switch (opcode_extension) { case 0x0: // INC gen_inc((mod == 0x3) ? rm : OPERAND_ADDR, operand_size); break; case 0x1: // DEC gen_dec((mod == 0x3) ? rm : OPERAND_ADDR, operand_size); break; case 0x2: // CALL break; } } */ /****************************************************************************** * * Handler for INC general-purpose register * * Opcode: 0x40 ... 0x47 * ******************************************************************************/ static void handle_inc_general_register(uint32_t counter, uint32_t opcode) { enum operand_t operand; enum size_t size; operand = opcode & 7; size = effective_operand_size(); inc(counter, operand, size, 0, SEGMENT_NONE); } /****************************************************************************** * * Handler for DEC general-purpose register * * Opcode: 0x48 ... 0x4f * ******************************************************************************/ static void handle_dec_general_register(uint32_t counter, uint32_t opcode) { enum operand_t operand; enum size_t size; operand = opcode & 7; size = effective_operand_size(); dec(counter, operand, size, 0, SEGMENT_NONE); } /****************************************************************************** * * Handler for PUSH general-purpose register * * Opcode: 0x50 ... 0x57 * ******************************************************************************/ static void handle_push_general_register(uint32_t counter, uint32_t opcode) { enum size_t operand_size, stack_size; enum operand_t operand; operand = opcode & 7; operand_size = effective_operand_size(); if (ss_size32) stack_size = SIZE_32; else stack_size = SIZE_16; push(counter, operand, operand_size, 0, SEGMENT_NONE, stack_size); } /****************************************************************************** * * Handler for POP general-purpose register * * Opcode: 0x58 ... 0x5f * ******************************************************************************/ static void handle_pop_general_register(uint32_t counter, uint32_t opcode) { enum size_t operand_size, stack_size; enum operand_t operand; operand = opcode & 7; operand_size = effective_operand_size(); if (ss_size32) stack_size = SIZE_32; else stack_size = SIZE_16; pop(counter, operand, operand_size, 0, SEGMENT_NONE, stack_size); } /****************************************************************************** * * Handler for PUSH segment register * ******************************************************************************/ static void handle_push_segment_register(uint32_t counter, uint32_t opcode) { enum size_t operand_size, stack_size; enum operand_t operand; switch (opcode) { case 0x06: operand = OPERAND_ES; break; case 0x0e: operand = OPERAND_CS; break; case 0x16: operand = OPERAND_SS; break; case 0x1e: operand = OPERAND_DS; break; case 0x0fa0: operand = OPERAND_FS; break; case 0x0fa8: operand = OPERAND_GS; break; default: ERROR(); } operand_size = effective_operand_size(); if (ss_size32) stack_size = SIZE_32; else stack_size = SIZE_16; push(counter, operand, operand_size, 0, SEGMENT_NONE, stack_size); } /****************************************************************************** * * Handler for POP segment register * ******************************************************************************/ static void handle_pop_segment_register(uint32_t counter, uint32_t opcode) { enum size_t operand_size, stack_size; enum operand_t operand; switch (opcode) { case 0x07: operand = OPERAND_ES; break; case 0x17: operand = OPERAND_SS; break; case 0x1f: operand = OPERAND_DS; break; case 0x0fa1: operand = OPERAND_FS; break; case 0x0fa8: operand = OPERAND_GS; break; default: ERROR(); } operand_size = effective_operand_size(); if (ss_size32) stack_size = SIZE_32; else stack_size = SIZE_16; pop(counter, operand, operand_size, 0, SEGMENT_NONE, stack_size); } /****************************************************************************** * * Handler for MOV * ******************************************************************************/ static enum operand_t segment2operand(enum segment_t segment) { switch (segment) { case SEGMENT_NONE: ERROR(); case SEGMENT_ES: return OPERAND_ES; case SEGMENT_CS: return OPERAND_CS; case SEGMENT_SS: return OPERAND_SS; case SEGMENT_DS: return OPERAND_DS; case SEGMENT_FS: return OPERAND_FS; case SEGMENT_GS: return OPERAND_GS; default: ERROR(); } } static void handle_mov(uint32_t counter, uint32_t opcode) { enum operand_t operand_src, operand_dst; enum segment_t segment; enum segment_t sreg; enum size_t size; uint32_t addr; if (opcode == 0x8c || opcode == 0x8e) size = SIZE_16; else if (opcode == 0xb8 || (opcode & 1) == 1) size = effective_operand_size(); else size = SIZE_8; switch (opcode) { case 0x88: case 0x89: fetch_mod_rm(&counter, &operand_src, &operand_dst, &addr, &segment); break; case 0x8a: case 0x8b: fetch_mod_rm(&counter, &operand_dst, &operand_src, &addr, &segment); break; case 0x8c: fetch_mod_rm(&counter, (enum operand_t *) &sreg, &operand_dst, &addr, &segment); if (sreg >= SEGMENT_INVALID) exception(EXCEPTION_UD, 0); operand_src = segment2operand(sreg); break; case 0x8e: fetch_mod_rm(&counter, (enum operand_t *) &sreg, &operand_src, &addr, &segment); if (sreg >= SEGMENT_INVALID || sreg == SEGMENT_CS) exception(EXCEPTION_UD, 0); operand_dst = segment2operand(sreg); break; case 0xa0: case 0xa1: case 0xa2: case 0xa3: addr = fetch(&counter, effective_address_size()); if ((opcode & 2) == 0) { operand_src = OPERAND_ADDRESS; operand_dst = OPERAND_EAX; } else { operand_src = OPERAND_EAX; operand_dst = OPERAND_ADDRESS; } segment = SEGMENT_DS; break; case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: operand_dst = opcode & 7; operand_src = OPERAND_IMMEDIATE; break; case 0xc6: case 0xc7: fetch_mod_rm(&counter, &operand_dst, &operand_src, &addr, &segment); if (operand_src != 0) exception(EXCEPTION_UD, 0); operand_src = OPERAND_IMMEDIATE; break; default: ERROR(); } mov(counter, operand_dst, size, operand_src, size, addr, segment); } /****************************************************************************** * * Handler for Jcc - Jump if Condition Is Met * ******************************************************************************/ static void handle_jecxz(uint32_t counter, uint32_t opcode) { enum size_t size; size = effective_operand_size(); jecxz(counter, size); } static void handle_jcc(uint32_t counter, uint32_t opcode) { enum size_t size; bool negate; enum jcc_t cc; negate = opcode & 1; cc = (enum jcc_t) ((opcode >> 1) & 7); switch (opcode >> 4) { case 0x7: size = SIZE_8; break; case 0x0f8: size = effective_operand_size(); break; default: ERROR(); } jcc(counter, cc, negate, size); } /****************************************************************************** * * Exception handler * ******************************************************************************/ static void handle_exception(void) { // TODO exception_vector = EXCEPTION_NONE; ERROR(); } /****************************************************************************** * * Prefix Handler * ******************************************************************************/ static void handle_prefix(uint32_t counter, uint32_t opcode) { switch (opcode) { case 0x26: // ES segment override prefix prefix_segment_override = SEGMENT_ES; eip += counter; break; case 0x2e: // CS segment override prefix prefix_segment_override = SEGMENT_CS; eip += counter; break; case 0x36: // SS segment override prefix prefix_segment_override = SEGMENT_SS; eip += counter; break; case 0x3e: // DS segment override prefix prefix_segment_override = SEGMENT_DS; eip += counter; break; case 0x64: // FS segment override prefix prefix_segment_override = SEGMENT_FS; eip += counter; break; case 0x65: // GS segment override prefix prefix_segment_override = SEGMENT_GS; eip += counter; break; case 0x66: // Operand-size override prefix prefix_operand_size_override = true; eip += counter; break; case 0x67: // Address-size override prefix prefix_address_size_override = true; eip += counter; break; case 0xf0: // LOCK prefix lock(); prefix_lock_repeat = LR_LOCK; eip += counter; break; case 0xf2: // REPNE/REPNZ prefix (used only with string instructions) if (prefix_lock_repeat == LR_LOCK) unlock(); prefix_lock_repeat = LR_REPNZ; eip += counter; break; case 0xf3: // REP/REPE/REPZ prefix (used only with string instructions) if (prefix_lock_repeat == LR_LOCK) unlock(); prefix_lock_repeat = LR_REPZ; eip += counter; break; default: ERROR(); } } /****************************************************************************** * * Handler for one instruction including prefixes * ******************************************************************************/ void handle_instruction(void) { uint32_t counter; uint32_t opcode; if (exception_vector != EXCEPTION_NONE) { handle_exception(); return; } counter = 0; opcode = fetch(&counter, SIZE_8); switch (opcode) { case 0x00: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x01: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x02: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x03: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x04: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x05: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x06: handle_push_segment_register(counter, opcode); break; // PUSH ES case 0x07: handle_pop_segment_register(counter, opcode); break; // POP ES case 0x08: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x09: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x0a: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x0b: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x0c: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x0d: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x0e: handle_push_segment_register(counter, opcode); break; // PUSH CS case 0x0f: // two-byte opcode opcode = 0xf00 | fetch(&counter, SIZE_8); switch (opcode) { /* TODO */ case 0x0f80: handle_jcc(counter, opcode); break; // JO case 0x0f81: handle_jcc(counter, opcode); break; // JNO case 0x0f82: handle_jcc(counter, opcode); break; // JB case 0x0f83: handle_jcc(counter, opcode); break; // JNB case 0x0f84: handle_jcc(counter, opcode); break; // JZ case 0x0f85: handle_jcc(counter, opcode); break; // JNZ case 0x0f86: handle_jcc(counter, opcode); break; // JBE case 0x0f87: handle_jcc(counter, opcode); break; // JNBE case 0x0f88: handle_jcc(counter, opcode); break; // JS case 0x0f89: handle_jcc(counter, opcode); break; // JNS case 0x0f8a: handle_jcc(counter, opcode); break; // JP case 0x0f8b: handle_jcc(counter, opcode); break; // JNP case 0x0f8c: handle_jcc(counter, opcode); break; // JL case 0x0f8d: handle_jcc(counter, opcode); break; // JNL case 0x0f8e: handle_jcc(counter, opcode); break; // JLE case 0x0f8f: handle_jcc(counter, opcode); break; // JNLE /* TODO */ case 0x0fa0: handle_push_segment_register(counter, opcode); break; // PUSH FS case 0x0fa1: handle_pop_segment_register(counter, opcode); break; // POP FS /* TODO */ case 0x0fa8: handle_push_segment_register(counter, opcode); break; // PUSH GS case 0x0fa9: handle_pop_segment_register(counter, opcode); break; // POP GS /* TODO */ default: ERROR(); } break; case 0x10: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x11: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x12: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x13: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x14: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x15: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x16: handle_push_segment_register(counter, opcode); break; // PUSH SS case 0x17: handle_pop_segment_register(counter, opcode); break; // POP SS case 0x18: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x19: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x1a: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x1b: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x1c: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x1d: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x1e: handle_push_segment_register(counter, opcode); break; // PUSH DS case 0x1f: handle_pop_segment_register(counter, opcode); break; // POP DS case 0x20: handle_arithmetic_and_logic(counter, opcode); break; // AND case 0x21: handle_arithmetic_and_logic(counter, opcode); break; // AND case 0x22: handle_arithmetic_and_logic(counter, opcode); break; // AND case 0x23: handle_arithmetic_and_logic(counter, opcode); break; // AND case 0x24: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x25: handle_arithmetic_and_logic(counter, opcode); break; // AND case 0x26: handle_prefix(counter, opcode); return; // ES segment override prefix case 0x27: daa(counter); break; // DAA case 0x28: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x29: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x2a: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x2b: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x2c: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x2d: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x2e: handle_prefix(counter, opcode); return; // CS segment override prefix /* TODO: DAS */ case 0x30: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x31: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x32: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x33: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x34: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x35: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x36: handle_prefix(counter, opcode); return; // SS segment override prefix /* TODO: AAA */ case 0x38: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x39: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x3a: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x3b: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x3c: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x3d: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x3e: handle_prefix(counter, opcode); return; // DS segment override prefix /* TODO: AAS */ case 0x40: handle_inc_general_register(counter, opcode); break; // INC case 0x41: handle_inc_general_register(counter, opcode); break; // INC case 0x42: handle_inc_general_register(counter, opcode); break; // INC case 0x43: handle_inc_general_register(counter, opcode); break; // INC case 0x44: handle_inc_general_register(counter, opcode); break; // INC case 0x45: handle_inc_general_register(counter, opcode); break; // INC case 0x46: handle_inc_general_register(counter, opcode); break; // INC case 0x47: handle_inc_general_register(counter, opcode); break; // INC case 0x48: handle_dec_general_register(counter, opcode); break; // DEC case 0x49: handle_dec_general_register(counter, opcode); break; // DEC case 0x4a: handle_dec_general_register(counter, opcode); break; // DEC case 0x4b: handle_dec_general_register(counter, opcode); break; // DEC case 0x4c: handle_dec_general_register(counter, opcode); break; // DEC case 0x4d: handle_dec_general_register(counter, opcode); break; // DEC case 0x4e: handle_dec_general_register(counter, opcode); break; // DEC case 0x4f: handle_dec_general_register(counter, opcode); break; // DEC case 0x50: handle_push_general_register(counter, opcode); break; // PUSH case 0x51: handle_push_general_register(counter, opcode); break; // PUSH case 0x52: handle_push_general_register(counter, opcode); break; // PUSH case 0x53: handle_push_general_register(counter, opcode); break; // PUSH case 0x54: handle_push_general_register(counter, opcode); break; // PUSH case 0x55: handle_push_general_register(counter, opcode); break; // PUSH case 0x56: handle_push_general_register(counter, opcode); break; // PUSH case 0x57: handle_push_general_register(counter, opcode); break; // PUSH case 0x58: handle_pop_general_register(counter, opcode); break; // POP case 0x59: handle_pop_general_register(counter, opcode); break; // POP case 0x5a: handle_pop_general_register(counter, opcode); break; // POP case 0x5b: handle_pop_general_register(counter, opcode); break; // POP case 0x5c: handle_pop_general_register(counter, opcode); break; // POP case 0x5d: handle_pop_general_register(counter, opcode); break; // POP case 0x5e: handle_pop_general_register(counter, opcode); break; case 0x5f: handle_pop_general_register(counter, opcode); break; // POP /* TODO */ case 0x64: handle_prefix(counter, opcode); return; // FS segment override prefix case 0x65: handle_prefix(counter, opcode); return; // GS segment override prefix case 0x66: handle_prefix(counter, opcode); return; // Operand-size override prefix case 0x67: handle_prefix(counter, opcode); return; // Address-size override prefix /* TODO */ case 0x70: handle_jcc(counter, opcode); break; // JO case 0x71: handle_jcc(counter, opcode); break; // JNO case 0x72: handle_jcc(counter, opcode); break; // JB case 0x73: handle_jcc(counter, opcode); break; // JNB case 0x74: handle_jcc(counter, opcode); break; // JZ case 0x75: handle_jcc(counter, opcode); break; // JNZ case 0x76: handle_jcc(counter, opcode); break; // JBE case 0x77: handle_jcc(counter, opcode); break; // JNBE case 0x78: handle_jcc(counter, opcode); break; // JS case 0x79: handle_jcc(counter, opcode); break; // JNS case 0x7a: handle_jcc(counter, opcode); break; // JP case 0x7b: handle_jcc(counter, opcode); break; // JNP case 0x7c: handle_jcc(counter, opcode); break; // JL case 0x7d: handle_jcc(counter, opcode); break; // JNL case 0x7e: handle_jcc(counter, opcode); break; // JLE case 0x7f: handle_jcc(counter, opcode); break; // JNLE case 0x80: handle_group_1(counter, opcode); break; // ADD,OR,ADC,SBB,AND,SUB,XOR,CMP case 0x81: handle_group_1(counter, opcode); break; // ADD,OR,ADC,SBB,AND,SUB,XOR,CMP case 0x82: handle_group_1(counter, opcode); break; // ADD,OR,ADC,SBB,AND,SUB,XOR,CMP case 0x83: handle_group_1(counter, opcode); break; // ADD,OR,ADC,SBB,AND,SUB,XOR,CMP /* TODO */ case 0x88: handle_mov(counter, opcode); break; // MOV case 0x89: handle_mov(counter, opcode); break; // MOV case 0x8a: handle_mov(counter, opcode); break; // MOV case 0x8b: handle_mov(counter, opcode); break; // MOV case 0x8c: handle_mov(counter, opcode); break; // MOV case 0x8e: handle_mov(counter, opcode); break; // MOV /* TODO */ case 0x9f: lahf(counter); break; // LAHF /* TODO */ case 0xa0: handle_mov(counter, opcode); break; // MOV case 0xa1: handle_mov(counter, opcode); break; // MOV case 0xa2: handle_mov(counter, opcode); break; // MOV case 0xa3: handle_mov(counter, opcode); break; // MOV /* TODO */ case 0xb0: handle_mov(counter, opcode); break; // MOV case 0xb1: handle_mov(counter, opcode); break; // MOV case 0xb2: handle_mov(counter, opcode); break; // MOV case 0xb3: handle_mov(counter, opcode); break; // MOV case 0xb4: handle_mov(counter, opcode); break; // MOV case 0xb5: handle_mov(counter, opcode); break; // MOV case 0xb6: handle_mov(counter, opcode); break; // MOV case 0xb7: handle_mov(counter, opcode); break; // MOV case 0xb8: handle_mov(counter, opcode); break; // MOV case 0xb9: handle_mov(counter, opcode); break; // MOV case 0xba: handle_mov(counter, opcode); break; // MOV case 0xbb: handle_mov(counter, opcode); break; // MOV case 0xbc: handle_mov(counter, opcode); break; // MOV case 0xbd: handle_mov(counter, opcode); break; // MOV case 0xbe: handle_mov(counter, opcode); break; // MOV case 0xbf: handle_mov(counter, opcode); break; // MOV /* TODO */ case 0xc6: handle_mov(counter, opcode); break; // MOV case 0xc7: handle_mov(counter, opcode); break; // MOV /* TODO */ case 0xe3: handle_jecxz(counter, opcode); break; // JECXZ JCXZ /* TODO */ case 0xf0: handle_prefix(counter, opcode); return; // LOCK prefix case 0xf1: exception(EXCEPTION_UD, 0); break; // Reserved and should not be used case 0xf2: handle_prefix(counter, opcode); return; // REPNE/REPNZ prefix (used only with string instructions) case 0xf3: handle_prefix(counter, opcode); return; // REP/REPE/REPZ prefix (used only with string instructions) /* TODO */ case 0xf6: handle_group_3(counter, opcode); break; // TEST,NOT,NEG,MUL,IMUL,DIV,IDIV case 0xf7: handle_group_3(counter, opcode); break; // TEST,NOT,NEG,MUL,IMUL,DIV,IDIV /* TODO */ default: ERROR(); } if (prefix_lock_repeat == LR_LOCK) unlock(); prefix_lock_repeat = LR_NONE; prefix_segment_override = SEGMENT_NONE; prefix_operand_size_override = false; prefix_address_size_override = false; } faucc-20120707/test/bios/0000750002413100241000000000000011776113700014423 5ustar potyrai3guestfaucc-20120707/test/bios/00get.sh0000750002413100241000000000173711717460536015720 0ustar potyrai3guest#!/bin/sh # $Id: 00get.sh,v 1.9 2012-02-17 14:17:02 vrsieh Exp $ # # Copyright (C) 2007-2009 FAUcc Team. # This program is free software. You can redistribute it and/or modify it # under the terms of the GNU General Public License, either version 2 of # the License, or (at your option) any later version. See COPYING. # BIOS=$HOME/Work/FAUmachine/src/node-pc/simulator/bios # CONFIG='-DCONFIG_APIC_SUPPORT -DCONFIG_APM_SUPPORT -DCONFIG_MOUSE_SUPPORT -DCONFIG_PCI_SUPPORT -DCONFIG_SMI_SUPPORT -DCONFIG_SMP_SUPPORT -DCONFIG_ACPI_SUPPORT' CONFIG='-DCONFIG_80286_SUPPORT' for section in INIT_RM INIT_EARLY RUNTIME_PM RUNTIME_RM ; do ( cd ${BIOS} ls *.c ) \ | grep -v 'mouse.c' \ | grep -v 'pci.c' \ | grep -v 'smi.c' \ | while read file ; do file=`echo ${file} | sed -e 's/\.c//'` gcc -m32 -E ${CONFIG} -I${BIOS} -I${BIOS}/.. -I${BIOS}/../.. -I${BIOS}/../../.. -I${BIOS}/../mb_ibm_at_bios -I${BIOS}/../../../lib -D${section} ${BIOS}/${file}.c > ${file}.${section}.i done done faucc-20120707/test/test11.c0000640002413100241000000000065711137627476015000 0ustar potyrai3guest/* $Id: test11.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ inline int test(int x) { return x * 2; } int main(void) { return test(2) + test(3); } faucc-20120707/test/test-i386-add.c0000640002413100241000000002524211137627476016050 0ustar potyrai3guest/* $Id: test-i386-add.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #define addr_t uint32_t #ifndef __CHIP_H__ #define __CHIP_H__ #include /******************************************************************************/ #define true (!false) #define false (0) typedef int bool; /******************************************************************************/ extern uint8_t get_uint8(void); extern uint16_t get_uint16(void); extern uint32_t get_uint32(void); extern uint64_t get_uint64(void); /******************************************************************************/ extern uint8_t load_uint8(addr_t addr); extern uint16_t load_uint16(addr_t addr); extern uint32_t load_uint32(addr_t addr); extern uint64_t load_uint64(addr_t addr); /******************************************************************************/ extern void store_uint8(uint8_t value, addr_t addr); extern void store_uint16(uint16_t value, addr_t addr); extern void store_uint32(uint32_t value, addr_t addr); extern void store_uint64(uint64_t value, addr_t addr); /******************************************************************************/ typedef struct _bit_t *bit_t; extern bool bit_get(bit_t); extern void bit_set(bit_t, bool value); extern void bit_unset(bit_t); /******************************************************************************/ /* only use at points never reached! */ extern __attribute__((__noreturn__)) void error(const char *file, int line); #define ERROR() error(__FILE__, __LINE__) /******************************************************************************/ #endif /* __CHIP_H__ */ /******************************************************************************/ enum operand_t { OPERAND_EAX = 0x0, OPERAND_ECX = 0x1, OPERAND_EDX = 0x2, OPERAND_EBX = 0x3, OPERAND_ESP = 0x4, OPERAND_EBP = 0x5, OPERAND_ESI = 0x6, OPERAND_EDI = 0x7, OPERAND_IMMEDIATE, OPERAND_ADDRESS, OPERAND_CS, OPERAND_SS, OPERAND_DS, OPERAND_ES, OPERAND_FS, OPERAND_GS }; enum operand_size_t { OPERAND_SIZE_1 = 1, OPERAND_SIZE_2 = 2, OPERAND_SIZE_4 = 4 }; enum prefix_lock_repeat_t { PREFIX_LR_NONE, PREFIX_LR_LOCK, PREFIX_LR_REPNZ, PREFIX_LR_REPZ }; enum prefix_segment_override_t { PREFIX_SO_NONE, PREFIX_SO_CS, PREFIX_SO_SS, PREFIX_SO_DS, PREFIX_SO_ES, PREFIX_SO_FS, PREFIX_SO_GS }; /****************************************************************************** * * Global variables (CPU State) * ******************************************************************************/ // General-purpose data registers uint32_t eax; uint32_t ecx; uint32_t edx; uint32_t ebx; uint32_t esp; uint32_t ebp; uint32_t esi; uint32_t edi; // Segment Registers uint16_t cs; // Code Segment uint16_t ss; // Stack Segment uint16_t ds; // Data Segment uint16_t es; // Data Segment uint16_t fs; // Data Segment uint16_t gs; // Data Segment // Status and Control Registers //uint32_t EFLAGS; //uint32_t EIP; // EFLAGS (Status Flags) bit_t cf; // Carry Flag bit_t pf; // Parity Flag bit_t af; // Auxiliary Carry Flag bit_t zf; // Zero Flag bit_t sf; // Sign Flag bit_t of; // Overflow Flag /******************************************************************************/ static inline uint32_t get_uint(enum operand_size_t size) { uint32_t value; switch (size) { case OPERAND_SIZE_1: value = get_uint8(); break; case OPERAND_SIZE_2: value = get_uint16(); break; case OPERAND_SIZE_4: value = get_uint32(); break; // no default! } return value; } /******************************************************************************/ static inline uint32_t mask(uint32_t t, enum operand_size_t size) { uint32_t value; switch (size) { case OPERAND_SIZE_1: value = t & 0xff; break; case OPERAND_SIZE_2: value = t & 0xffff; break; case OPERAND_SIZE_4: value = t & 0xffffffff; break; // no default! } return value; } /******************************************************************************/ static inline void store(uint32_t t, enum operand_t operand, enum operand_size_t size, uint32_t addr) { switch (operand) { case OPERAND_EAX: eax = mask(t, size); break; case OPERAND_ECX: ecx = mask(t, size); break; case OPERAND_EDX: edx = mask(t, size); break; case OPERAND_EBX: ebx = mask(t, size); break; case OPERAND_ESP: esp = mask(t, size); break; case OPERAND_EBP: ebp = mask(t, size); break; case OPERAND_ESI: esi = mask(t, size); break; case OPERAND_EDI: edi = mask(t, size); break; case OPERAND_IMMEDIATE: ERROR(); break; case OPERAND_ADDRESS: switch (size) { case OPERAND_SIZE_1: store_uint8(t, addr); break; case OPERAND_SIZE_2: store_uint16(t, addr); break; case OPERAND_SIZE_4: store_uint32(t, addr); break; // no default! } break; case OPERAND_CS: cs = mask(t, size); break; case OPERAND_SS: ss = mask(t, size); break; case OPERAND_DS: ds = mask(t, size); break; case OPERAND_ES: es = mask(t, size); break; case OPERAND_FS: fs = mask(t, size); break; case OPERAND_GS: gs = mask(t, size); break; // no default! } } static inline uint32_t load(enum operand_t operand, enum operand_size_t size, uint32_t addr) { uint32_t value; switch (operand) { case OPERAND_EAX: value = mask(eax, size); break; case OPERAND_ECX: value = mask(ecx, size); break; case OPERAND_EDX: value = mask(edx, size); break; case OPERAND_EBX: value = mask(ebx, size); break; case OPERAND_ESP: value = mask(esp, size); break; case OPERAND_EBP: value = mask(ebp, size); break; case OPERAND_ESI: value = mask(esi, size); break; case OPERAND_EDI: value = mask(edi, size); break; case OPERAND_IMMEDIATE: value = get_uint(size); break; case OPERAND_ADDRESS: switch (size) { case OPERAND_SIZE_1: value = load_uint8(addr); break; case OPERAND_SIZE_2: value = load_uint16(addr); break; case OPERAND_SIZE_4: value = load_uint32(addr); break; // no default! } break; case OPERAND_CS: value = mask(cs, size); break; case OPERAND_SS: value = mask(ss, size); break; case OPERAND_DS: value = mask(ds, size); break; case OPERAND_ES: value = mask(es, size); break; case OPERAND_FS: value = mask(fs, size); break; case OPERAND_GS: value = mask(gs, size); break; // no default! } return value; } /****************************************************************************** * * SF - Sign flag * * Set equal to the most-significant bit of the result, which is the sign bit * of a signed integer. (0 indicates a positive value and 1 indicates a negative * value.) * ******************************************************************************/ static inline void update_sf(uint32_t t, enum operand_size_t size) { switch (size) { case OPERAND_SIZE_1: bit_set(sf, t >> 7); break; case OPERAND_SIZE_2: bit_set(sf, t >> 15); break; case OPERAND_SIZE_4: bit_set(sf, t >> 31); break; // no default! } } /****************************************************************************** * * ZF - Zero flag * * Set if the result is zero; cleared otherwise. * ******************************************************************************/ static inline void update_zf(uint32_t t) { bit_set(zf, t == 0); } /****************************************************************************** * * PF - Parity flag * * Set if the least-significant byte of the result contains an even number * of 1 bits; cleared otherwise. * ******************************************************************************/ static inline void update_pf(uint32_t t) { static const uint8_t parity_table[256] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x00 - 0x0f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x10 - 0x1f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x20 - 0x2f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x30 - 0x3f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x40 - 0x4f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x50 - 0x5f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x60 - 0x6f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x70 - 0x7f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x80 - 0x8f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x90 - 0x9f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0xa0 - 0xaf 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0xb0 - 0xbf 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0xc0 - 0xcf 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0xd0 - 0xdf 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0xe0 - 0xef 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0xf0 - 0xff }; bit_set(pf, parity_table[(uint8_t) t]); } /****************************************************************************** * * 'Result' - Flags * * Update SF, ZF and PF. * ******************************************************************************/ static inline void update_sf_zf_pf(uint32_t t, enum operand_size_t size) { update_sf(t, size); update_zf(t); update_pf(t); } /****************************************************************************** * * Arithmetic and Logic Generator Functions * ******************************************************************************/ /* Add */ static inline void add(enum operand_t operand_a, enum operand_size_t size_a, enum operand_t operand_b, enum operand_size_t size_b, uint32_t addr) { uint32_t t0, t1, t2; t1 = load(operand_a, size_a, addr); t2 = load(operand_b, size_b, addr); t0 = mask(t1 + t2, size_a); store(t0, operand_a, size_a, addr); update_sf_zf_pf(t0, size_a); bit_set(cf, t0 < t1); bit_set(of, (t1 ^ t2 ^ -1) & (t1 ^ t0)); bit_set(af, (t1 ^ t2 ^ t0) & 0x10); } /******************************************************************************/ void add_eax_4_eax_4(uint32_t addr) { add(OPERAND_EAX, OPERAND_SIZE_4, OPERAND_EAX, OPERAND_SIZE_4, addr); } void add_edx_2_ebx_2(uint32_t addr) { add(OPERAND_EDX, OPERAND_SIZE_2, OPERAND_EBX, OPERAND_SIZE_2, addr); } void add_ebx_4_addr_4(uint32_t addr) { add(OPERAND_EBX, OPERAND_SIZE_4, OPERAND_ADDRESS, OPERAND_SIZE_4, addr); } void add_ecx_4_imm_4(uint32_t addr) { add(OPERAND_ECX, OPERAND_SIZE_4, OPERAND_IMMEDIATE, OPERAND_SIZE_4, addr); } void add_eax_4_imm_1(uint32_t addr) { add(OPERAND_EAX, OPERAND_SIZE_4, OPERAND_IMMEDIATE, OPERAND_SIZE_1, addr); } faucc-20120707/test/test16.c0000640002413100241000000000123511137627476014776 0ustar potyrai3guest/* $Id: test16.c,v 1.5 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ enum bool { false = 0, true }; int f(char c, int i) { return (c > i) || i; } int f1(double l) { int i = l + 1; return i; } int f2(double l) { int i = l; return i + 1; } enum bool f3(char c) { enum bool b = c; return b; } inline int f4(int i) { return i; } int f5(char c) { return f4(c); } faucc-20120707/test/test14.c0000640002413100241000000000123411137627476014773 0ustar potyrai3guest/* $Id: test14.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ extern unsigned char get(void); int reg; inline void func(int opcode) { switch (opcode) { case 0: reg += 7; break; case 1: reg -= 7; break; case 2: reg %= 7; break; } } void disas(void) { int opcode = get(); switch (opcode) { case 0: func(0); break; case 1: func(1); break; case 2: func(2); break; } } faucc-20120707/test/test4.c0000640002413100241000000000076211137627476014717 0ustar potyrai3guest/* $Id: test4.c,v 1.4 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ void test1(void) {} void test2(void) {} int main(void) { int y; y = 1; if (0) { test1(); l1: test2(); y--; } if (y) { goto l1; } return 0; } faucc-20120707/test/test17.c0000640002413100241000000000101311137627476014771 0ustar potyrai3guest/* $Id: test17.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include int main(int argc, char **argv) { unsigned int i; printf("%s", *argv); for (i = 1; i < argc; i++) { printf(" %s", argv[i]); } printf("\n"); return 0; } faucc-20120707/test/test8.c0000640002413100241000000000071311137627476014717 0ustar potyrai3guest/* $Id: test8.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ int main(void) { int i; int precision; i = 0; precision = 0; if (i < precision--) goto l0; l0: ; return 0; } faucc-20120707/test/test5.c0000640002413100241000000000114611137627476014715 0ustar potyrai3guest/* $Id: test5.c,v 1.3 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ int func0(void) { return 0; } int func1(void) { return 0; } int func2(void) { return 0; } int func3(void) { return 0; } int main(void) { int a; int b; int c; a = 0; b = 1; c = a + 2 * b; b || func2(); a && func3(); a ? func0() : func1(); return a + b + c; } faucc-20120707/test/test-ext.c0000640002413100241000000000124611720403471015410 0ustar potyrai3guest/* * $Id: test-ext.c,v 1.3 2012-02-20 08:41:29 vrsieh Exp $ */ #include char globalvar; char globalstr[1] = { '0' }; static char localvar; static char localstr[1] = { '0' }; void func(void) { char tmp; printf("%c\n", globalvar); printf("%c\n", globalstr[0]); printf("%p\n", &globalvar); printf("%p\n", globalstr); printf("%c\n", localvar); printf("%c\n", localstr[0]); printf("%p\n", &localvar); printf("%p\n", localstr); printf("%p\n", func); tmp = globalstr[0] + 1; globalstr[0] = tmp + 1; globalvar = globalstr[0]; globalstr[0] = globalvar; tmp = localstr[0] + 1; localstr[0] = tmp + 1; localvar = localstr[0]; localstr[0] = localvar; } faucc-20120707/test/test-expr.c0000640002413100241000000000043511721364167015576 0ustar potyrai3guest/* * $Id: test-expr.c,v 1.2 2012-02-23 07:19:19 vrsieh Exp $ */ #include #define expr(t) \ t \ expr_ ## t(t x, t y) \ { \ return x + y - x * y / x; \ } expr(int8_t) expr(uint8_t) expr(int16_t) expr(uint16_t) expr(int32_t) expr(uint32_t) expr(int64_t) expr(uint64_t) faucc-20120707/test/test18.c0000640002413100241000000000076011137627476015002 0ustar potyrai3guest/* $Id: test18.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ void outsw(unsigned short port, unsigned short *addr, unsigned long len) { } void main(void) { unsigned short x; outsw(1, &x, 2 / 1); } faucc-20120707/test/test12.c0000640002413100241000000000066111137627476014774 0ustar potyrai3guest/* $Id: test12.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ inline int f(void) { static int i = 4711; return i; } int func(void) { return f(); } faucc-20120707/test/test19.c0000640002413100241000000000071511137627476015003 0ustar potyrai3guest/* $Id: test19.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ void f1(int i) { if (i == 0) { ; } else { ; } } void f2(void) { int i; for (i = 0; i < 10; i++) { ; } } faucc-20120707/test/test15.c0000640002413100241000000000072711137627476015002 0ustar potyrai3guest/* $Id: test15.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ extern int test(void); register int x asm("eax"); int main(void) { register int y asm("ebx"); y = test() + x; return y; } faucc-20120707/test/test6.c0000640002413100241000000000130511137627476014713 0ustar potyrai3guest/* $Id: test6.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ /* * Testing simplification of LHS of expressions. */ int main(void) { struct complex { double r; double i; }; struct complex a, b; struct complex array[10]; struct complex *pointer; pointer = &a; a.r = b.i; a.r = array[2].i; a.r = pointer->i; b.i = a.r; array[2].i = a.r; pointer->i = a.r; a.i = (b.i = 0, 0.0); a.i = b.i++; return 0; } faucc-20120707/test/test3.c0000640002413100241000000005275611137627476014730 0ustar potyrai3guest/* $Id: test3.c,v 1.3 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ # 1 "i386.c" # 1 "" # 1 "" # 1 "i386.c" # 1 "/usr/include/inttypes.h" 1 3 4 # 26 "/usr/include/inttypes.h" 3 4 # 1 "/usr/include/features.h" 1 3 4 # 308 "/usr/include/features.h" 3 4 # 1 "/usr/include/sys/cdefs.h" 1 3 4 # 309 "/usr/include/features.h" 2 3 4 # 331 "/usr/include/features.h" 3 4 # 1 "/usr/include/gnu/stubs.h" 1 3 4 # 332 "/usr/include/features.h" 2 3 4 # 27 "/usr/include/inttypes.h" 2 3 4 # 1 "/usr/include/stdint.h" 1 3 4 # 27 "/usr/include/stdint.h" 3 4 # 1 "/usr/include/bits/wchar.h" 1 3 4 # 28 "/usr/include/stdint.h" 2 3 4 # 1 "/usr/include/bits/wordsize.h" 1 3 4 # 29 "/usr/include/stdint.h" 2 3 4 # 37 "/usr/include/stdint.h" 3 4 typedef signed char int8_t; typedef short int int16_t; typedef int int32_t; typedef long int int64_t; typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned int uint32_t; typedef unsigned long int uint64_t; # 66 "/usr/include/stdint.h" 3 4 typedef signed char int_least8_t; typedef short int int_least16_t; typedef int int_least32_t; typedef long int int_least64_t; typedef unsigned char uint_least8_t; typedef unsigned short int uint_least16_t; typedef unsigned int uint_least32_t; typedef unsigned long int uint_least64_t; # 91 "/usr/include/stdint.h" 3 4 typedef signed char int_fast8_t; typedef long int int_fast16_t; typedef long int int_fast32_t; typedef long int int_fast64_t; # 104 "/usr/include/stdint.h" 3 4 typedef unsigned char uint_fast8_t; typedef unsigned long int uint_fast16_t; typedef unsigned long int uint_fast32_t; typedef unsigned long int uint_fast64_t; # 120 "/usr/include/stdint.h" 3 4 typedef long int intptr_t; typedef unsigned long int uintptr_t; # 135 "/usr/include/stdint.h" 3 4 typedef long int intmax_t; typedef unsigned long int uintmax_t; # 29 "/usr/include/inttypes.h" 2 3 4 typedef int __gwchar_t; # 274 "/usr/include/inttypes.h" 3 4 typedef struct { long int quot; long int rem; } imaxdiv_t; # 298 "/usr/include/inttypes.h" 3 4 extern intmax_t imaxabs (intmax_t __n) __attribute__ ((__nothrow__)) __attribute__ ((__const__)); extern imaxdiv_t imaxdiv (intmax_t __numer, intmax_t __denom) __attribute__ ((__nothrow__)) __attribute__ ((__const__)); extern intmax_t strtoimax (__const char *__restrict __nptr, char **__restrict __endptr, int __base) __attribute__ ((__nothrow__)); extern uintmax_t strtoumax (__const char *__restrict __nptr, char ** __restrict __endptr, int __base) __attribute__ ((__nothrow__)); extern intmax_t wcstoimax (__const __gwchar_t *__restrict __nptr, __gwchar_t **__restrict __endptr, int __base) __attribute__ ((__nothrow__)); extern uintmax_t wcstoumax (__const __gwchar_t *__restrict __nptr, __gwchar_t ** __restrict __endptr, int __base) __attribute__ ((__nothrow__)); # 459 "/usr/include/inttypes.h" 3 4 # 3 "i386.c" 2 typedef int bool; # 14 "i386.c" int get(void); int load(uint32_t addr); void store(uint32_t value, uint32_t addr); enum operand_t { OPERAND_EAX = 0x0, OPERAND_ECX = 0x1, OPERAND_EDX = 0x2, OPERAND_EBX = 0x3, OPERAND_ESP = 0x4, OPERAND_EBP = 0x5, OPERAND_ESI = 0x6, OPERAND_EDI = 0x7, OPERAND_T0, OPERAND_T1, OPERAND_T2, OPERAND_ADDR }; uint32_t T0; uint32_t T1; uint32_t T2; uint32_t ADDR; uint32_t EAX; uint32_t ECX; uint32_t EDX; uint32_t EBX; uint32_t ESP; uint32_t EBP; uint32_t ESI; uint32_t EDI; uint16_t CS; uint16_t SS; uint16_t DS; uint16_t ES; uint16_t FS; uint16_t GS; uint32_t EIP; uint32_t pc; bool CF; bool PF; bool AF; bool ZF; bool SF; bool OF; enum { PREFIX_LR_NONE, PREFIX_LR_LOCK, PREFIX_LR_REPNZ, PREFIX_LR_REPZ } prefix_lock_repeat; enum { PREFIX_SO_NONE, PREFIX_SO_CS, PREFIX_SO_SS, PREFIX_SO_DS, PREFIX_SO_ES, PREFIX_SO_FS, PREFIX_SO_GS } prefix_segment_override; bool prefix_operand_size_override; bool prefix_address_size_override; bool code32; bool addseg; uint8_t get8(void) { pc += 1; return get(); } uint16_t get16(void) { pc += 2; return get8() << 8 | get8(); } uint32_t get32(void) { pc += 4; return get16() << 16 || get16(); } uint32_t getn(int bits) { switch (bits) { case 1: return get8(); case 2: return get16(); case 4: return get32(); default: ; } } void gen_mask_t0(int operand_size) { switch (operand_size) { case 1: T0 = T0 & 0xff; break; case 2: T0 = T0 & 0xffff; break; case 4: T0 = T0 & 0xffffffff; break; default: ; } } void gen_mask_t1(int operand_size) { switch (operand_size) { case 1: T1 = T1 & 0xff; break; case 2: T1 = T1 & 0xffff; break; case 4: T1 = T1 & 0xffffffff; break; default: ; } } void gen_mask_t2(int operand_size) { switch (operand_size) { case 1: T2 = T2 & 0xff; break; case 2: T2 = T2 & 0xffff; break; case 4: T2 = T2 & 0xffffffff; break; default: ; } } void gen_store_t0(enum operand_t operand, int operand_size) { gen_mask_t0(operand_size); switch (operand) { case OPERAND_EAX: EAX = T0; break; case OPERAND_ECX: ECX = T0; break; case OPERAND_EDX: EDX = T0; break; case OPERAND_EBX: EBX = T0; break; case OPERAND_ESP: ESP = T0; break; case OPERAND_EBP: EBP = T0; break; case OPERAND_ESI: ESI = T0; break; case OPERAND_EDI: EDI = T0; break; case OPERAND_T0: break; case OPERAND_ADDR: store(T0, ADDR); break; default: ; } } void gen_load_t1(enum operand_t operand, int operand_size) { switch (operand) { case OPERAND_EAX: T1 = EAX; break; case OPERAND_ECX: T1 = ECX; break; case OPERAND_EDX: T1 = EDX; break; case OPERAND_EBX: T1 = EBX; break; case OPERAND_ESP: T1 = ESP; break; case OPERAND_EBP: T1 = EBP; break; case OPERAND_ESI: T1 = ESI; break; case OPERAND_EDI: T1 = EDI; break; case OPERAND_T1: break; case OPERAND_ADDR: T1 = load(ADDR); break; default: ; } gen_mask_t1(operand_size); } void gen_load_t2(enum operand_t operand, int operand_size) { switch (operand) { case OPERAND_EAX: T2 = EAX; break; case OPERAND_ECX: T2 = ECX; break; case OPERAND_EDX: T2 = EDX; break; case OPERAND_EBX: T2 = EBX; break; case OPERAND_ESP: T2 = ESP; break; case OPERAND_EBP: T2 = EBP; break; case OPERAND_ESI: T2 = ESI; break; case OPERAND_EDI: T2 = EDI; break; case OPERAND_T2: break; case OPERAND_ADDR: T2 = load(ADDR); break; default: ; } gen_mask_t2(operand_size); } # 226 "i386.c" void gen_update_sf(int operand_size) { switch (operand_size) { case 1: SF = T0 >> 7; break; case 2: SF = T0 >> 15; break; case 4: SF = T0 >> 31; break; default: ; } } # 243 "i386.c" void gen_update_zf(void) { ZF = (T0 == 0) ? 1 : 0; } # 256 "i386.c" void gen_update_pf(void) { static const uint8_t parity_table[256] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, }; PF = parity_table[(uint8_t) T0]; } # 286 "i386.c" void gen_update_sf_zf_pf(int operand_size) { gen_update_sf(operand_size); gen_update_zf(); gen_update_pf(); } # 299 "i386.c" void gen_inc(enum operand_t operand, int operand_size) { gen_load_t1(operand, operand_size); T0 = T1 + 1; gen_store_t0(operand, operand_size); gen_update_sf_zf_pf(operand_size); OF = 0; AF = 0; } void gen_dec(enum operand_t operand, int operand_size) { gen_load_t1(operand, operand_size); T0 = T1 - 1; gen_store_t0(operand, operand_size); gen_update_sf_zf_pf(operand_size); OF = 0; AF = 0; } void gen_add(enum operand_t operand_a, enum operand_t operand_b, int operand_size) { gen_load_t1(operand_a, operand_size); gen_load_t2(operand_b, operand_size); T0 = T1 + T2; gen_store_t0(operand_a, operand_size); gen_update_sf_zf_pf(operand_size); CF = 0; OF = 0; AF = 0; } void gen_or(enum operand_t operand_a, enum operand_t operand_b, int operand_size) { gen_load_t1(operand_a, operand_size); gen_load_t2(operand_b, operand_size); T0 = T1 | T2; gen_store_t0(operand_a, operand_size); gen_update_sf_zf_pf(operand_size); OF = 0; CF = 0; AF = 0; } void gen_adc(enum operand_t operand_a, enum operand_t operand_b, int operand_size) { gen_load_t1(operand_a, operand_size); gen_load_t2(operand_b, operand_size); T0 = T1 + T2 + CF; gen_store_t0(operand_a, operand_size); gen_update_sf_zf_pf(operand_size); CF = 0; OF = 0; AF = 0; } void gen_sbb(enum operand_t operand_a, enum operand_t operand_b, int operand_size) { gen_load_t1(operand_a, operand_size); gen_load_t2(operand_b, operand_size); T0 = T1 - (T2 + CF); gen_store_t0(operand_a, operand_size); gen_update_sf_zf_pf(operand_size); CF = 0; OF = 0; AF = 0; } void gen_and(enum operand_t operand_a, enum operand_t operand_b, int operand_size) { gen_load_t1(operand_a, operand_size); gen_load_t2(operand_b, operand_size); T0 = T1 & T2; gen_store_t0(operand_a, operand_size); gen_update_sf_zf_pf(operand_size); OF = 0; CF = 0; AF = 0; } void gen_sub(enum operand_t operand_a, enum operand_t operand_b, int operand_size) { gen_load_t1(operand_a, operand_size); gen_load_t2(operand_b, operand_size); T0 = T1 - T2; gen_store_t0(operand_a, operand_size); gen_update_sf_zf_pf(operand_size); CF = 0; OF = 0; AF = 0; } void gen_xor(enum operand_t operand_a, enum operand_t operand_b, int operand_size) { gen_load_t1(operand_a, operand_size); gen_load_t2(operand_b, operand_size); T0 = T1 ^ T2; gen_store_t0(operand_a, operand_size); gen_update_sf_zf_pf(operand_size); OF = 0; CF = 0; AF = 0; } void gen_cmp(enum operand_t operand_a, enum operand_t operand_b, int operand_size) { gen_load_t1(operand_a, operand_size); gen_load_t2(operand_b, operand_size); T0 = T1 - T2; gen_store_t0(operand_a, operand_size); gen_update_sf_zf_pf(operand_size); OF = 0; CF = 0; AF = 0; } # 444 "i386.c" void disas_mod_rm(enum operand_t *operand_reg, enum operand_t *operand_rm) { int mod_rm, mod, reg, rm; mod_rm = get8(); mod = (mod_rm >> 6) & 3; reg = (mod_rm >> 3) & 7; rm = mod_rm & 7; if (operand_reg) *operand_reg = reg; if (!operand_rm) return; if (mod == 3) { *operand_rm = rm; return; } *operand_rm = OPERAND_ADDR; if (code32 ^ prefix_address_size_override) { int scale, index, base; uint32_t disp; if (rm == 4) { int sib = get8(); scale = (sib >> 6) & 3; index = (sib >> 3) & 7; base = sib & 7; } else { scale = 0; index = 0; base = rm; } switch (mod) { case 0: if (base == 5) { disp = get32(); base = -1; } else { disp = 0; } break; case 1: disp = get8(); break; case 2: disp = get32(); break; case 3: default: ; } if (disp != 0) ADDR = disp; else ADDR = 0; if (base >= 0) { switch (base) { case OPERAND_EAX: ADDR += EAX; break; case OPERAND_ECX: ADDR += ECX; break; case OPERAND_EDX: ADDR += EDX; break; case OPERAND_EBX: ADDR += EBX; break; case OPERAND_ESP: ADDR += ESP; break; case OPERAND_EBP: ADDR += EBP; break; case OPERAND_ESI: ADDR += ESI; break; case OPERAND_EDI: ADDR += EDI; break; default: ; } } if (scale == 0) { switch (index) { case OPERAND_EAX: ADDR += EAX; break; case OPERAND_ECX: ADDR += ECX; break; case OPERAND_EDX: ADDR += EDX; break; case OPERAND_EBX: ADDR += EBX; break; case OPERAND_ESP: break; case OPERAND_EBP: ADDR += EBP; break; case OPERAND_ESI: ADDR += ESI; break; case OPERAND_EDI: ADDR += EDI; break; default: ; } } else if (scale == 1) { switch (index) { case OPERAND_EAX: ADDR += EAX * 2; break; case OPERAND_ECX: ADDR += ECX * 2; break; case OPERAND_EDX: ADDR += EDX * 2; break; case OPERAND_EBX: ADDR += EBX * 2; break; case OPERAND_ESP: break; case OPERAND_EBP: ADDR += EBP * 2; break; case OPERAND_ESI: ADDR += ESI * 2; break; case OPERAND_EDI: ADDR += EDI * 2; break; default: ; } } else if (scale == 2) { switch (index) { case OPERAND_EAX: ADDR += EAX * 4; break; case OPERAND_ECX: ADDR += ECX * 4; break; case OPERAND_EDX: ADDR += EDX * 4; break; case OPERAND_EBX: ADDR += EBX * 4; break; case OPERAND_ESP: break; case OPERAND_EBP: ADDR += EBP * 4; break; case OPERAND_ESI: ADDR += ESI * 4; break; case OPERAND_EDI: ADDR += EDI * 4; break; default: ; } } else if (scale == 3) { switch (index) { case OPERAND_EAX: ADDR += EAX * 8; break; case OPERAND_ECX: ADDR += ECX * 8; break; case OPERAND_EDX: ADDR += EDX * 8; break; case OPERAND_EBX: ADDR += EBX * 8; break; case OPERAND_ESP: break; case OPERAND_EBP: ADDR += EBP * 8; break; case OPERAND_ESI: ADDR += ESI * 8; break; case OPERAND_EDI: ADDR += EDI * 8; break; default: ; } } if (prefix_segment_override != PREFIX_SO_NONE || addseg) { if (base == OPERAND_EBP || base == OPERAND_ESP) ADDR += SS; else ADDR += DS; } } else { uint32_t disp; switch (mod) { case 0: if (rm == 6) { disp = get16(); rm = -1; } else { disp = 0; } break; case 1: disp = get8(); break; case 2: disp = get16(); break; case 3: default: break; } if (disp != 0) ADDR = disp; else ADDR = 0; switch (rm) { case -1: break; case 0: ADDR += EBX + ESI; break; case 1: ADDR += EBX + EDI; break; case 2: ADDR += EBP + ESI; break; case 3: ADDR += EBP + EDI; break; case 4: ADDR += ESI; break; case 5: ADDR += EDI; break; case 6: ADDR += EBP; break; case 7: ADDR += EBX; break; default: ; } ADDR = ADDR & 0xffff; if (prefix_segment_override != PREFIX_SO_NONE || addseg) { if (rm == 2 || rm == 3 || rm == 6) ADDR += SS; else ADDR += DS; } } } # 642 "i386.c" void disas_arithmetic_and_logic(int opcode) { int operation, direction, immediate, operand_size; enum operand_t operand_a, operand_b; operation = (opcode >> 3) & 7; direction = (opcode >> 1) & 1; immediate = (opcode >> 2) & 1; if ((opcode & 1) == 0) operand_size = 1; else operand_size = (code32 ^ prefix_operand_size_override) ? 4 : 2; if (immediate == 1) { uint32_t immediate; immediate = getn(operand_size); T2 = immediate; operand_a = OPERAND_EAX; operand_b = OPERAND_T2; } else { enum operand_t operand_reg, operand_rm; disas_mod_rm(&operand_reg, &operand_rm); if (direction == 0) { operand_a = operand_rm; operand_b = operand_reg; } else { operand_a = operand_reg; operand_b = operand_rm; } } switch (operation) { case 0x0: gen_add(operand_a, operand_b, operand_size); break; case 0x1: gen_or(operand_a, operand_b, operand_size); break; case 0x2: gen_adc(operand_a, operand_b, operand_size); break; case 0x3: gen_sbb(operand_a, operand_b, operand_size); break; case 0x4: gen_and(operand_a, operand_b, operand_size); break; case 0x5: gen_sub(operand_a, operand_b, operand_size); break; case 0x6: gen_xor(operand_a, operand_b, operand_size); break; case 0x7: gen_cmp(operand_a, operand_b, operand_size); break; default: ; } } # 698 "i386.c" void disas_group_1(int opcode) { int operation, operand_size; enum operand_t operand_a, operand_b; uint32_t immediate; if ((opcode & 1) == 0) operand_size = 1; else operand_size = (code32 ^ prefix_operand_size_override) ? 4 : 2; if (opcode == 0x83) immediate = get8(); else immediate = getn(operand_size); T2 = immediate; operand_b = OPERAND_T2; disas_mod_rm((enum operand_t *) &operation, &operand_a); switch (operation) { case 0x0: gen_add(operand_a, operand_b, operand_size); break; case 0x1: gen_or(operand_a, operand_b, operand_size); break; case 0x2: gen_adc(operand_a, operand_b, operand_size); break; case 0x3: gen_sbb(operand_a, operand_b, operand_size); break; case 0x4: gen_and(operand_a, operand_b, operand_size); break; case 0x5: gen_sub(operand_a, operand_b, operand_size); break; case 0x6: gen_xor(operand_a, operand_b, operand_size); break; case 0x7: gen_cmp(operand_a, operand_b, operand_size); break; default: ; } } void disas_inc_register(int opcode) { gen_inc(opcode & 0x7, (code32 ^ prefix_operand_size_override) ? 4 : 2); } void disas_dec_register(int opcode) { gen_dec(opcode & 0x7, (code32 ^ prefix_operand_size_override) ? 4 : 2); } # 759 "i386.c" void disas_group_3(int opcode) { int operation, operand_size; enum operand_t operand_a, operand_b; if ((opcode & 1) == 0) operand_size = 1; else operand_size = (code32 ^ prefix_operand_size_override) ? 4 : 2; disas_mod_rm((enum operand_t *) &operation, &operand_b); if (operation != 0x2 && operation != 0x3) { uint32_t immediate = getn(operand_size); T2 = immediate; operand_b = OPERAND_T2; } switch (operation) { case 0x0: gen_test(operand_a, operand_b, operand_size); break; case 0x1: ; case 0x2: gen_not(operand_a, operand_size); break; case 0x3: gen_neg(operand_a, operand_size); break; case 0x4: gen_mul(operand_a, operand_b, operand_size); break; case 0x5: gen_imul(operand_a, operand_b, operand_size); break; case 0x6: gen_div(operand_a, operand_b, operand_size); break; case 0x7: gen_idiv(operand_a, operand_b, operand_size); break; default: ; } } # 840 "i386.c" void disas_opcode_two(int opcode) { int opcode2; if (opcode != 0x0f) ; opcode2 = get8(); opcode = 0x0f00 | opcode2; switch (opcode) { case 0x00: break; default: ; } } void disas_opcode_one(bool lock) { int opcode; opcode = get8(); switch (opcode) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: disas_arithmetic_and_logic(opcode); break; case 0x06: break; case 0x07: break; case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: disas_arithmetic_and_logic(opcode); break; case 0x0e: break; case 0x0f: disas_opcode_two(opcode); break; case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: disas_arithmetic_and_logic(opcode); break; case 0x16: break; case 0x17: break; case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: disas_arithmetic_and_logic(opcode); break; case 0x1e: break; case 0x1f: break; case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: disas_arithmetic_and_logic(opcode); break; case 0x26: prefix_segment_override = PREFIX_SO_ES; disas_opcode_one(lock); break; case 0x27: break; case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: disas_arithmetic_and_logic(opcode); break; case 0x2e: prefix_segment_override = PREFIX_SO_CS; disas_opcode_one(lock); break; case 0x2f: break; case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: disas_arithmetic_and_logic(opcode); break; case 0x36: prefix_segment_override = PREFIX_SO_SS; disas_opcode_one(lock); break; case 0x37: break; case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: disas_arithmetic_and_logic(opcode); break; case 0x3e: prefix_segment_override = PREFIX_SO_DS; disas_opcode_one(lock); break; case 0x3f: break; case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: disas_inc_register(opcode); break; case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: disas_dec_register(opcode); break; case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: disas_push_register(opcode); break; case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: disas_pop_register(opcode); break; case 0x60: break; case 0x61: break; case 0x62: break; case 0x63: break; case 0x64: prefix_segment_override = PREFIX_SO_FS; disas_opcode_one(lock); break; case 0x65: prefix_segment_override = PREFIX_SO_GS; disas_opcode_one(lock); break; case 0x66: prefix_operand_size_override = (!(0)); disas_opcode_one(lock); break; case 0x67: prefix_address_size_override = (!(0)); disas_opcode_one(lock); break; case 0x80: case 0x81: case 0x82: case 0x83: disas_group_1(opcode); break; case 0xf0: prefix_lock_repeat = PREFIX_LR_LOCK; if (!lock) { gen_lock(); disas_opcode_one((!(0))); gen_unlock(); } else { disas_opcode_one((!(0))); } break; case 0xf1: break; case 0xf2: prefix_lock_repeat = PREFIX_LR_REPNZ; disas_opcode_one(lock); break; case 0xf3: prefix_lock_repeat = PREFIX_LR_REPZ; disas_opcode_one(lock); break; case 0xf4: break; case 0xf5: break; case 0xf6: case 0xf7: disas_group_3(opcode); break; default: ; } } int main(void) { prefix_lock_repeat = PREFIX_LR_NONE; prefix_segment_override = PREFIX_SO_NONE; prefix_operand_size_override = (0); prefix_address_size_override = (0); disas_opcode_one((0)); return 0; } faucc-20120707/test/test20.c0000640002413100241000000000102211137627476014763 0ustar potyrai3guest/* $Id: test20.c,v 1.4 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ extern void test2(long long a, long long b, long long c, long long d, long long e); void test(long long a, long long b, long long c, long long d, long long e) { test2(a, b, c, d, e); } faucc-20120707/test/test-bda.c0000640002413100241000000000042511716711504015340 0ustar potyrai3guest/* * $Id: test-bda.c,v 1.2 2012-02-15 11:13:08 vrsieh Exp $ */ struct bda { short x; char y; int z; } __attribute__((__packed__)); int test(void) { struct bda *BDA = (struct bda *) 0x00000400; BDA->x = 0; BDA->y = 1; BDA->z = 2; return BDA->x + BDA->y + BDA->z; } faucc-20120707/test/test-i386.c0000640002413100241000000017267111137627476015333 0ustar potyrai3guest/* $Id: test-i386.c,v 1.10 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #ifndef __CHIP_H__ #define __CHIP_H__ #include /******************************************************************************/ typedef enum { false, true } bool; /******************************************************************************/ /* QEMU: arch_gen_cpu_x86_sim_fast.c */ #define lock() #define unlock() /******************************************************************************/ extern bool bit_get(uint32_t *bitset, int index); extern void bit_set(uint32_t *bitset, int index, bool value); extern void bit_set_undef(uint32_t *bitset, int index); /******************************************************************************/ extern void __attribute__((__noreturn__)) globalreturn(void); /* only use at points never reached! */ #define ERROR() error(__FILE__, __LINE__) extern __attribute__((__noreturn__)) void error(const char *file, int line); /******************************************************************************/ #endif /* __CHIP_H__ */ /******************************************************************************/ extern uint8_t fetch_uint8(uint32_t); extern uint16_t fetch_uint16(uint32_t); extern uint32_t fetch_uint32(uint32_t); extern uint8_t load_uint8(uint32_t addr); extern uint16_t load_uint16(uint32_t addr); extern uint32_t load_uint32(uint32_t addr); extern void store_uint8(uint8_t value, uint32_t addr); extern void store_uint16(uint16_t value, uint32_t addr); extern void store_uint32(uint32_t value, uint32_t addr); /******************************************************************************/ enum operand_t { OPERAND_EAX = 0, OPERAND_ECX = 1, OPERAND_EDX = 2, OPERAND_EBX = 3, OPERAND_ESP = 4, OPERAND_EBP = 5, OPERAND_ESI = 6, OPERAND_EDI = 7, OPERAND_IMMEDIATE, OPERAND_ADDRESS, OPERAND_CS, OPERAND_SS, OPERAND_DS, OPERAND_ES, OPERAND_FS, OPERAND_GS }; enum size_t { SIZE_8, SIZE_16, SIZE_32 }; enum segment_t { SEGMENT_NONE = -1, SEGMENT_ES = 0, SEGMENT_CS = 1, SEGMENT_SS = 2, SEGMENT_DS = 3, SEGMENT_FS = 4, SEGMENT_GS = 5, SEGMENT_INVALID = 6 }; enum lock_repeat_t { LR_NONE, LR_LOCK, LR_REPNZ, LR_REPZ }; enum eflag_t { EFLAG_CF = 0, // Carry Flag // 1: Reserved (set to 1) EFLAG_PF = 2, // Parity Flag // 3: Reserved (set to 0) EFLAG_AF = 4, // Auxiliary Carry Flag // 5: Reserved (set to 0) EFLAG_ZF = 6, // Zero Flag EFLAG_SF = 7, // Sign Flag EFLAG_TF = 8, // Trap Flag EFLAG_IF = 9, // Interrupt Enable Flag EFLAG_DF = 10, // Direction Flag EFLAG_OF = 11, // Overflow Flag EFLAG_IOPL0 = 12, // I/O Privilege Level EFLAG_IOPL1 = 13, // I/O Privilege Level EFLAG_NT = 14, // Nested Task // 15: Reserved (set to 0) EFLAG_RF = 16, // Resume Flag EFLAG_VM = 17, // Virtual-8086 Mode EFLAG_AC = 18, // Alignment Check EFLAG_VIF = 19, // Virtual Interrupt Flag EFLAG_VIP = 20, // Virtual Interrupt Pending EFLAG_ID = 21 // ID Flag // 22: Reserved (set to 0) // ... // 31: Reserved (set to 0) }; enum cr0_t { CR0_PE = 0, // Protection Enable CR0_MP = 1, // Monitor Coprocessor CR0_EM = 2, // Emulation CR0_TS = 3, // Task Switched CR0_ET = 4, // Extension Type CR0_NE = 5, // Numeric Error // Reserved CR0_WP = 16, // Write Protect // Reserved CR0_AM = 18, // Alignment Mask // Reserved CR0_NW = 29, // Not Write-through CR0_CD = 30, // Cache Disbale CR0_PG = 31 // Paging }; enum cr3_t { // Reserved CR3_PWT = 3, // Page-level Writes Transparent CR3_PCD = 4, // Page-level Cache Disable // Reserved // 12-31: Page-Directory Base }; enum cr4_t { CR4_VME = 0, // Virtual-8086 Mode Extensions CR4_PVI = 1, // Protected-Mode Virtual Interrupts CR4_TSD = 2, // Time Stamp Disable CR4_DE = 3, // Debugging Extensions CR4_PSE = 4, // Page Size Extensiion CR4_PAE = 5, // Physical Address Extension CR4_MCE = 6, // Machine-Check Enable CR4_PGE = 7, // Page Global Enable CR4_PCE = 8, // Performance-Monitoring Counter Enable CR4_OSFXSR = 9, // Operating System FXSAVE/FXRSTOR Support CR4_OSXMMEXCPT = 10, // Operating System Unmasked Exception Support // 11: Reserved (set to 0) // ... // 31: Reserved (set to 0) }; enum exception_t { EXCEPTION_NONE = -1, EXCEPTION_DE = 0, // Fault: Divide Error EXCEPTION_DB = 1, // Fault/Trap: Debug EXCEPTION_NMI = 2, // Interrupt: NMI Interrupt EXCEPTION_BP = 3, // Trap: Breakpoint EXCEPTION_OF = 4, // Trap: Overflow EXCEPTION_BR = 5, // Fault: BOUND Range Exceeded EXCEPTION_UD = 6, // Fault: Invalid Opcode (Undefined Opcode) EXCEPTION_NM = 7, // Fault: Device Not Available (No Math Coprocessor) EXCEPTION_DF = 8, // Abort: Double Fault EXCEPTION_009 = 9, // Fault: Coprocessor Segment Overrun (reserved) EXCEPTION_TS = 10, // Fault: Invalid TSS EXCEPTION_NP = 11, // Fault: Segment Not Present EXCEPTION_SS = 12, // Fault: Stack-Segment Fault EXCEPTIOB_GP = 13, // Fault: General Protection EXCEPTION_PF = 14, // Fault: Page Fault EXCEPTION_015 = 15, // Intel reserved. Do not use. EXCEPTION_MF = 16, // Fault: Floating-Point Error (Math Fault) EXCEPTION_AC = 17, // Fault: Alignment Check EXCEPTION_MC = 18, // Abort: Machine Check EXCEPTION_XF = 19, // Fault: Streaming SIMD Extensions EXCEPTION_020 = 20, // Intel reserved. Do not use. /* ... */ EXCEPTION_031 = 31, // Intel reserved, Do not use. EXCEPTION_032 = 32, // Interrupt: User Defined (Nonreserved) Interrupts /* ... */ EXCEPTION_255 = 255 // Interrupt: User Defined (Nonreserved) Interrupts }; enum jcc_t { JCC_O = 0, // overflow (OF=1) JCC_B = 1, // below (CF=1) JCC_Z = 2, // zero (ZF=1) JCC_BE = 3, // below or equal (CF=1 or ZF=1) JCC_S = 4, // sign (SF=1) JCC_P = 5, // parity (PF=1) JCC_L = 6, // less (SF<>OF) JCC_LE = 7, // less or equal (ZF=1 or SF<>OF) }; /****************************************************************************** * * General-purpose data registers * ******************************************************************************/ static uint32_t eax; // Accumulator for operands and results data static uint32_t ecx; // Counter for string and loop operations static uint32_t edx; // I/O pointer static uint32_t ebx; // Pointer to data in the DS segment static uint32_t esp; // Stack pointer (in the SS segment) static uint32_t ebp; // Pointer to data on the stack (in the SS segment) static uint32_t esi; // Pointer to data in the segment pointed to by the DS register; source pointer for string operations static uint32_t edi; // Pointer to data (or destination) in the segment pointed to by the ES register; destination pointer for string operations /****************************************************************************** * * Segment Registers * ******************************************************************************/ static uint16_t cs; // Code Segment static uint16_t ss; // Stack Segment static uint16_t ds; // Data Segment static uint16_t es; // Data Segment static uint16_t fs; // Data Segment static uint16_t gs; // Data Segment /****************************************************************************** * * Status and Control Registers * ******************************************************************************/ static uint32_t eip; // Instruction pointer static uint32_t eflags; // EFLAGS Register //static uint32_t cr0; // Control Register 0: Contains system control flags that control operating mode and states of the processor //static uint32_t cr1; // Control Register 1: Reserved //static uint32_t cr2; // Control Register 2: Contains the page-fault linear address (the linear address that caused a page fault) //static uint32_t cr3; // Control Register 3: Contains the physical address of the base of the page directory and two flags (PCD and PWT) //static uint32_t cr4; // Control Register 4: Contains a group of flags that enable several architecture extensions, as well as indicating the level of OS support for the Streaming SIMD Extension /****************************************************************************** * * Memory-management Registers * ******************************************************************************/ //static uint32_t gdtr_base_address; //static uint16_t gdtr_table_limit; //static uint32_t idtr_base_address; //static uint16_t idtr_table_limit; //static uint16_t tr_segment_selector; //static uint32_t tr_base_address; //static uint16_t tr_segment_limit; //static uint16_t ldtr_segment_selector; //static uint32_t ldtr_base_address; //static uint16_t ldtr_segment_limit; /******************************************************************************/ static bool cs_size32; // D Flag in Code Segment Descriptor static bool ss_size32; // address size attribute of the stack segment (QEMU: ss32) static bool prefix_operand_size_override; static bool prefix_address_size_override; static enum segment_t prefix_segment_override; static enum lock_repeat_t prefix_lock_repeat; static enum exception_t exception_vector; static uint16_t exception_error_code; /****************************************************************************** * * Mask * ******************************************************************************/ static inline uint32_t mask(uint32_t t, enum size_t size) { uint32_t value; switch (size) { case SIZE_8: value = t & 0xff; break; case SIZE_16: value = t & 0xffff; break; case SIZE_32: value = t & 0xffffffff; break; default: ERROR(); } return value; } /****************************************************************************** * * Exception * ******************************************************************************/ static inline void exception(enum exception_t vector, uint16_t error_code) { exception_vector = vector; exception_error_code = error_code; globalreturn(); } /****************************************************************************** * * EFLAGS Register Accessors * ******************************************************************************/ static inline bool eflag_get(enum eflag_t eflag) { return bit_get(&eflags, eflag); } static inline void eflag_set(enum eflag_t eflag, bool value) { bit_set(&eflags, eflag, value); } static inline void eflag_set_undef(enum eflag_t eflag) { bit_set_undef(&eflags, eflag); } /****************************************************************************** * * Effective Operand- and Address-Size Attributes * * D Flag in Code Segment Descriptor 0 0 0 0 1 1 1 1 * Operand-Size Prefix 0x66 N N Y Y N N Y Y * Address-Size Prefix 0x67 N Y N Y N Y N Y * Effective Operand Size 16 16 32 32 32 32 16 16 * Effective Address Size 16 32 16 32 32 16 32 16 * ******************************************************************************/ static inline enum size_t effective_operand_size(void) { if (cs_size32 ^ prefix_operand_size_override) return SIZE_32; else return SIZE_16; } static inline enum size_t effective_address_size(void) { if (cs_size32 ^ prefix_address_size_override) return SIZE_32; else return SIZE_16; } /****************************************************************************** * * Instruction Fetch * ******************************************************************************/ static inline uint32_t fetch(uint32_t *counter, enum size_t size) { uint32_t value; if (!counter) ERROR(); switch (size) { case SIZE_8: value = fetch_uint8(eip + cs); *counter += 1; break; case SIZE_16: value = fetch_uint16(eip + cs); *counter += 2; break; case SIZE_32: value = fetch_uint32(eip + cs); *counter += 4; break; default: ERROR(); } return value; } /****************************************************************************** * * Store (Register and Memeory) * * SIZE_8 SIZE_16 SIZE_32 * OPERAND_EAX AL AX EAX * OPERAND_ECX CL CX ECX * OPERAND_EDX DL DX EDX * OPERAND_EBX BL BX EBX * OPERAND_ESP AH SP ESP * OPERAND_EBP CH BP EBP * OPERAND_ESI DH SI ESI * OPERAND_EDI BH DI EDI * ******************************************************************************/ static inline void store(uint32_t t, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { switch (operand) { case OPERAND_EAX: eax = mask(t, size); break; case OPERAND_ECX: ecx = mask(t, size); break; case OPERAND_EDX: edx = mask(t, size); break; case OPERAND_EBX: ebx = mask(t, size); break; case OPERAND_ESP: if (size == SIZE_8) // AH !!! eax = (t & 0xff) << 8; else esp = mask(t, size); break; case OPERAND_EBP: if (size == SIZE_8) // CH !!! ecx = (t & 0xff) << 8; else ebp = mask(t, size); break; case OPERAND_ESI: if (size == SIZE_8) // DH !!! edx = (t & 0xff) << 8; else esi = mask(t, size); break; case OPERAND_EDI: if (size == SIZE_8) // BH !!! ebx = (t & 0xff) << 8; else edi = mask(t, size); break; case OPERAND_IMMEDIATE: ERROR(); break; case OPERAND_ADDRESS: switch (segment) { case SEGMENT_NONE: break; case SEGMENT_CS: addr += cs; break; case SEGMENT_SS: addr += ss; break; case SEGMENT_DS: addr += ds; break; case SEGMENT_ES: addr += es; break; case SEGMENT_FS: addr += fs; break; case SEGMENT_GS: addr += gs; break; default: ERROR(); } switch (size) { case SIZE_8: store_uint8(t, addr); break; case SIZE_16: store_uint16(t, addr); break; case SIZE_32: store_uint32(t, addr); break; default: ERROR(); } break; case OPERAND_CS: cs = mask(t, size); break; case OPERAND_SS: ss = mask(t, size); break; case OPERAND_DS: ds = mask(t, size); break; case OPERAND_ES: es = mask(t, size); break; case OPERAND_FS: fs = mask(t, size); break; case OPERAND_GS: gs = mask(t, size); break; default: ERROR(); } } /****************************************************************************** * * Load (Register and Memory) * * SIZE_8 SIZE_16 SIZE_32 * OPERAND_EAX AL AX EAX * OPERAND_ECX CL CX ECX * OPERAND_EDX DL DX EDX * OPERAND_EBX BL BX EBX * OPERAND_ESP AH SP ESP * OPERAND_EBP CH BP EBP * OPERAND_ESI DH SI ESI * OPERAND_EDI BH DI EDI * ******************************************************************************/ static inline uint32_t load(uint32_t *counter, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { uint32_t value; switch (operand) { case OPERAND_EAX: value = eax; break; case OPERAND_ECX: value = ecx; break; case OPERAND_EDX: value = edx; break; case OPERAND_EBX: value = ebx; break; case OPERAND_ESP: if (size == SIZE_8) // AH !!! value = eax >> 8; else value = esp; break; case OPERAND_EBP: if (size == SIZE_8) // CH !!! value = ecx >> 8; else value = ebp; break; case OPERAND_ESI: if (size == SIZE_8) // DH !!! value = edx >> 8; else value = esi; break; case OPERAND_EDI: if (size == SIZE_8) // BH !!! value = ebx >> 8; else value = edi; break; case OPERAND_IMMEDIATE: value = fetch(counter, size); break; case OPERAND_ADDRESS: switch (segment) { case SEGMENT_NONE: break; case SEGMENT_CS: addr += cs; break; case SEGMENT_SS: addr += ss; break; case SEGMENT_DS: addr += ds; break; case SEGMENT_ES: addr += es; break; case SEGMENT_FS: addr += fs; break; case SEGMENT_GS: addr += gs; break; default: ERROR(); } switch (size) { case SIZE_8: value = load_uint8(addr); break; case SIZE_16: value = load_uint16(addr); break; case SIZE_32: value = load_uint32(addr); break; default: ERROR(); } break; case OPERAND_CS: value = cs; break; case OPERAND_SS: value = ss; break; case OPERAND_DS: value = ds; break; case OPERAND_ES: value = es; break; case OPERAND_FS: value = fs; break; case OPERAND_GS: value = gs; break; default: ERROR(); } return value; } /****************************************************************************** * * Update SF - Sign flag * * Set equal to the most-significant bit of the result, which is the sign bit * of a signed integer. (0 indicates a positive value and 1 indicates a negative * value.) * ******************************************************************************/ static inline void update_sf(uint32_t t, enum size_t size) { switch (size) { case SIZE_8: eflag_set(EFLAG_SF, t >> 7); break; case SIZE_16: eflag_set(EFLAG_SF, t >> 15); break; case SIZE_32: eflag_set(EFLAG_SF, t >> 31); break; default: ERROR(); } } /****************************************************************************** * * Update ZF - Zero flag * * Set if the result is zero; cleared otherwise. * ******************************************************************************/ static inline void update_zf(uint32_t t) { eflag_set(EFLAG_ZF, t == 0); } /****************************************************************************** * * Update PF - Parity flag * * Set if the least-significant byte of the result contains an even number * of 1 bits; cleared otherwise. * ******************************************************************************/ static inline void update_pf(uint32_t t) { static const uint8_t parity_table[256] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x00 - 0x0f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x10 - 0x1f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x20 - 0x2f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x30 - 0x3f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x40 - 0x4f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x50 - 0x5f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x60 - 0x6f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x70 - 0x7f 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0x80 - 0x8f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0x90 - 0x9f 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0xa0 - 0xaf 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0xb0 - 0xbf 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0xc0 - 0xcf 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0xd0 - 0xdf 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, // 0xe0 - 0xef 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, // 0xf0 - 0xff }; eflag_set(EFLAG_PF, parity_table[t & 0xff]); } /****************************************************************************** * * Update 'Result' - Flags * * Update SF, ZF and PF. * ******************************************************************************/ static inline void update_sf_zf_pf(uint32_t t, enum size_t size) { update_sf(t, size); update_zf(t); update_pf(t); } /****************************************************************************** * * Arithmetic and Logic Generator Functions * ******************************************************************************/ /* Increment by 1 */ static inline void inc(uint32_t counter, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand, size, addr, segment); t2 = 1; t0 = mask(t1 + t2, size); store(t0, operand, size, addr, segment); update_sf_zf_pf(t0, size); /* cf unchanged */ eflag_set(EFLAG_OF, t0 == 0); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Decrement by 1 */ static inline void dec(uint32_t counter, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand, size, addr, segment); t2 = 1; t0 = mask(t1 - t2, size); store(t0, operand, size, addr, segment); update_sf_zf_pf(t0, size); /* cf unchanged */ eflag_set(EFLAG_OF, t0 == mask(-1, size)); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Add */ static inline void add(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 + t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, t0 < t1); eflag_set(EFLAG_OF, (t1 ^ t2 ^ -1) & (t1 ^ t0)); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Logical Inclusive OR */ static inline void or(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 | t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, false); eflag_set(EFLAG_OF, false); eflag_set_undef(EFLAG_AF); eip += counter; } /* Add with Carry */ static inline void adc(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 + t2 + eflag_get(EFLAG_CF), size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, t0 <= t1); eflag_set(EFLAG_OF, (t1 ^ t2 ^ -1) & (t1 ^ t0)); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Integer Subtraction with Borrow */ static inline void sbb(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 - (t2 + eflag_get(EFLAG_CF)), size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, t1 <= t2); eflag_set(EFLAG_OF, (t1 ^ t2) & (t1 ^ t0)); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Logical AND */ static inline void and(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 & t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, false); eflag_set(EFLAG_OF, false); eflag_set_undef(EFLAG_AF); eip += counter; } /* Substract */ static inline void sub(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 - t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, t1 < t2); eflag_set(EFLAG_OF, (t1 ^ t2) & (t1 ^ t0)); eflag_set(EFLAG_AF, (t1 ^ t2 ^ t0) & 0x10); eip += counter; } /* Logical Exclusive OR */ static inline void xor(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 ^ t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set(EFLAG_CF, false); eflag_set(EFLAG_OF, false); eflag_set_undef(EFLAG_AF); eip += counter; } /* Compare Two Operands */ static inline void cmp(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { uint32_t t0, t1, t2; t1 = load(&counter, operand_a, size_a, addr, segment); t2 = load(&counter, operand_b, size_b, addr, segment); t0 = mask(t1 - t2, size_a); store(t0, operand_a, size_a, addr, segment); update_sf_zf_pf(t0, size_a); eflag_set_undef(EFLAG_CF); // FIXME eflag_set_undef(EFLAG_OF); // FIXME eflag_set_undef(EFLAG_AF); // FIXME eip += counter; } /******************************************************************************/ static inline void test(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static inline void not(uint32_t counter, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static inline void neg(uint32_t counter, enum operand_t operand, enum size_t size, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static inline void mul(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static inline void imul(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static inline void div(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } static inline void idiv(uint32_t counter, enum operand_t operand_a, enum size_t size_a, enum operand_t operand_b, enum size_t size_b, uint32_t addr, enum segment_t segment) { // TODO eip += counter; } /****************************************************************************** * * MOV * ******************************************************************************/ static inline void mov(uint32_t counter, enum operand_t operand_dst, enum size_t size_dst, enum operand_t operand_src, enum size_t size_src, uint32_t addr, enum segment_t segment) { uint32_t t; t = load(&counter, operand_src, size_src, addr, segment); store(t, operand_dst, size_dst, addr, segment); eip += counter; } /****************************************************************************** * * Push and Pop Generator Functions * ******************************************************************************/ static inline void push(uint32_t counter, enum operand_t operand, enum size_t operand_size, uint32_t addr, enum segment_t segment, enum size_t stack_size) { uint32_t a, t; switch (operand_size) { case SIZE_8: ERROR(); case SIZE_16: esp -= 2; break; case SIZE_32: esp -= 4; break; default: ERROR(); } esp = mask(esp, stack_size); a = mask(esp + ss, stack_size); t = load(&counter, operand, operand_size, addr, segment); switch (operand_size) { case SIZE_8: ERROR(); case SIZE_16: store_uint16(t, a); break; case SIZE_32: store_uint32(t, a); break; default: ERROR(); } eip += counter; } static inline void pop(uint32_t counter, enum operand_t operand, enum size_t operand_size, uint32_t addr, enum segment_t segment, enum size_t stack_size) { uint32_t a, t; a = mask(esp + ss, stack_size); switch (operand_size) { case SIZE_8: ERROR(); case SIZE_16: t = load_uint16(a); break; case SIZE_32: t = load_uint32(a); break; default: ERROR(); } store(t, operand, operand_size, addr, segment); switch (operand_size) { case SIZE_8: ERROR(); case SIZE_16: esp += 2; break; case SIZE_32: esp += 4; break; default: ERROR(); } esp = mask(esp, stack_size); eip += counter; } static void inline jecxz(uint32_t counter, enum size_t size) { int8_t offset; bool condition; offset = fetch(&counter, SIZE_8); condition = mask(ecx, size) == 0; eip += counter; // FIXME: check segment limits if (condition) { eip += offset; eip = mask(eip, size); } } static void inline jcc(uint32_t counter, enum jcc_t cc, bool negate, enum size_t size) { int32_t offset; bool condition; offset = fetch(&counter, size); switch (cc) { case JCC_O: condition = eflag_get(EFLAG_OF); break; case JCC_B: condition = eflag_get(EFLAG_CF); break; case JCC_Z: condition = eflag_get(EFLAG_ZF); break; case JCC_BE: condition = eflag_get(EFLAG_CF) || eflag_get(EFLAG_ZF); break; case JCC_S: condition = eflag_get(EFLAG_SF); break; case JCC_P: condition = eflag_get(EFLAG_PF); break; case JCC_L: condition = eflag_get(EFLAG_SF) != eflag_get(EFLAG_OF); break; case JCC_LE: condition = eflag_get(EFLAG_ZF) || (eflag_get(EFLAG_SF) != eflag_get(EFLAG_OF)); break; default: ERROR(); } condition ^= negate; eip += counter; // FIXME: check segment limits if (condition) { eip += offset; if (size == SIZE_16) eip &= 0xffff; } } /****************************************************************************** * * LAHF - Load Status Flags into AH Register * * AH = SF:ZF:0:AF:0:PF:1:CF * * Flags: None * Exceptions: None * ******************************************************************************/ static inline void lahf(uint32_t counter) { uint8_t ah; ah = 0; ah &= eflag_get(EFLAG_CF) << EFLAG_CF; ah &= 1 << 1; ah &= eflag_get(EFLAG_PF) << EFLAG_PF; ah &= 0 << 3; ah &= eflag_get(EFLAG_AF) << EFLAG_AF; ah &= 0 << 5; ah &= eflag_get(EFLAG_ZF) << EFLAG_ZF; ah &= eflag_get(EFLAG_SF) << EFLAG_SF; eax = ah << 8; eip += counter; } /****************************************************************************** * * DAA - Decimal Adjust AL after Addition * * Flags: CF, AF, SF, ZF, PF, OF * Exceptions: None * ******************************************************************************/ static inline void daa(uint32_t counter) { uint8_t al; bool af, cf; al = eax & 0xff; af = eflag_get(EFLAG_AF); cf = eflag_get(EFLAG_CF); if (((al & 0x0f) > 9) || af) { cf = ((al > 0xf9) || cf); af = true; al += 6; } else { af = false; } if (((al & 0xf0) > 0x90) || cf) { al += 0x60; cf = true; } else { cf = false; } eax = al; eflag_set(EFLAG_AF, af); eflag_set(EFLAG_CF, cf); update_sf_zf_pf(al, SIZE_8); eip += counter; } /****************************************************************************** * * Handler for the operand-identifier byte (ModR/M byte) and the * addressing-mode specifier byte (SIB byte). * * Reads the ModR/M byte and if required: 1 SIB byte and 1, 2 or 4 bytes * displacement. * * Possible return values for operand_reg: * OPERAND_EAX, OPERAND_ECX, OPERAND_EDX, OPERAND_EBX, * OPERAND_ESP, OPERAND_EBP, OPERAND_ESI, OPERAND_EDI * * Possible return values for operand_rm: * OPERAND_EAX, OPERAND_ECX, OPERAND_EDX, OPERAND_EBX, * OPERAND_ESP, OPERAND_EBP, OPERAND_ESI, OPERAND_EDI, * OPERAND_ADDRESS (the address value is stored in addr) * * Mod/RM: * * 7 6 5 4 3 2 1 0 * Mod Reg R/M * * SIB: * 7 6 5 4 3 2 1 0 * Scale Index Base * ******************************************************************************/ static inline void fetch_mod_rm(uint32_t *counter, enum operand_t *operand_reg, enum operand_t *operand_rm, uint32_t *addr, enum segment_t *segment) { int mod_rm, mod, reg, rm; mod_rm = fetch(counter, SIZE_8); mod = (mod_rm >> 6) & 3; reg = (mod_rm >> 3) & 7; rm = mod_rm & 7; if (operand_reg) *operand_reg = reg; if (!operand_rm) return; if (mod == 3) { *operand_rm = rm; return; } *operand_rm = OPERAND_ADDRESS; if (!addr) ERROR(); if (!segment) ERROR(); // now calculate the address if (cs_size32 ^ prefix_address_size_override) { int scale, index, base; uint32_t disp; if (rm == 4) { int sib = fetch(counter, SIZE_8); scale = (sib >> 6) & 3; index = (sib >> 3) & 7; base = sib & 7; } else { scale = 0; index = 0; base = rm; } switch (mod & 3) { case 0: // no disp, exception: rm == 5 if (base == 5) { disp = fetch(counter, SIZE_32); base = -1; } else { disp = 0; } break; case 1: // disp8 disp = fetch(counter, SIZE_8); break; case 2: // disp32 disp = fetch(counter, SIZE_32); break; case 3: // register only: already handled default: ERROR(); } if (disp != 0) *addr = disp; // IMMEDIATE else *addr = 0; if (base >= 0) { // TODO? popl handling with esp switch (base & 7) { case OPERAND_EAX: *addr += eax; break; case OPERAND_ECX: *addr += ecx; break; case OPERAND_EDX: *addr += edx; break; case OPERAND_EBX: *addr += ebx; break; case OPERAND_ESP: *addr += esp; break; case OPERAND_EBP: *addr += ebp; break; case OPERAND_ESI: *addr += esi; break; case OPERAND_EDI: *addr += edi; break; default: ERROR(); } } switch (index & 7) { case OPERAND_EAX: *addr += eax * (1 << scale); break; case OPERAND_ECX: *addr += ecx * (1 << scale); break; case OPERAND_EDX: *addr += edx * (1 << scale); break; case OPERAND_EBX: *addr += ebx * (1 << scale); break; case OPERAND_ESP: ERROR(); case OPERAND_EBP: *addr += ebp * (1 << scale); break; case OPERAND_ESI: *addr += esi * (1 << scale); break; case OPERAND_EDI: *addr += edi * (1 << scale); break; default: ERROR(); } if (prefix_segment_override != SEGMENT_NONE) *segment = prefix_segment_override; else if (base == OPERAND_EBP || base == OPERAND_ESP) *segment = SEGMENT_SS; else *segment = SEGMENT_DS; } else { uint32_t disp; switch (mod) { case 0: // no disp, exception: rm == 6 if (rm == 6) { disp = fetch(counter, SIZE_16); rm = -1; } else { disp = 0; } break; case 1: // disp8 disp = fetch(counter, SIZE_8); break; case 2: // disp16 disp = fetch(counter, SIZE_16); break; case 3: // register only (already checked) default: ERROR(); } if (disp != 0) *addr = disp; // IMMEDIATE else *addr = 0; switch (rm) { case -1: break; case 0: *addr += ebx + esi; break; case 1: *addr += ebx + edi; break; case 2: *addr += ebp + esi; break; case 3: *addr += ebp + edi; break; case 4: *addr += esi; break; case 5: *addr += edi; break; case 6: *addr += ebp; break; case 7: *addr += ebx; break; default: ERROR(); } *addr = *addr & 0xffff; if (prefix_segment_override != SEGMENT_NONE) *segment = prefix_segment_override; else if (rm == 2 || rm == 3 || rm == 6) *segment = SEGMENT_SS; else *segment = SEGMENT_DS; } } /****************************************************************************** * * Handler for arithmetic and logic instructions * * Opcode: * * 7 6 5 4 3 2 1 0 * 0 0 Operation Direction Immediate Operandsize * ******************************************************************************/ static inline void handle_arithmetic_and_logic(uint32_t counter, uint32_t opcode) { int operation, direction, immediate; enum operand_t operand_a, operand_b; enum segment_t segment; enum size_t size; uint32_t addr; operation = (opcode >> 3) & 7; direction = (opcode >> 1) & 1; immediate = (opcode >> 2) & 1; if ((opcode & 1) == 0) size = SIZE_8; else size = effective_operand_size(); if (immediate == 1) { operand_a = OPERAND_EAX; operand_b = OPERAND_IMMEDIATE; } else { enum operand_t operand_reg, operand_rm; fetch_mod_rm(&counter, &operand_reg, &operand_rm, &addr, &segment); if (direction == 0) { operand_a = operand_rm; operand_b = operand_reg; } else { operand_a = operand_reg; operand_b = operand_rm; } } switch (operation & 7) { case 0x0: add(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x1: or(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x2: adc(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x3: sbb(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x4: and(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x5: sub(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x6: xor(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x7: cmp(counter, operand_a, size, operand_b, size, addr, segment); break; default: ERROR(); } } /****************************************************************************** * * Handler for Immediate Group 1 * * Bits 5, 4 and 3 of ModR/M byte used as an opcode extension. * ******************************************************************************/ static inline void handle_group_1(uint32_t counter, uint32_t opcode) { enum operand_t operand_a, operand_b; enum size_t size_a, size_b; enum segment_t segment; int operation; uint32_t addr; if ((opcode & 1) == 0) size_a = SIZE_8; else size_a = effective_operand_size(); if (opcode == 0x83) size_b = SIZE_8; else size_b = size_a; operand_b = OPERAND_IMMEDIATE; fetch_mod_rm(&counter, (enum operand_t *) &operation, &operand_a, &addr, &segment); switch (operation & 7) { case 0x0: add(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x1: or(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x2: adc(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x3: sbb(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x4: and(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x5: sub(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x6: xor(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; case 0x7: cmp(counter, operand_a, size_a, operand_b, size_b, addr, segment); break; default: ERROR(); } } /****************************************************************************** * * Handler for Unary Group 3 * * Bits 5, 4 and 3 of ModR/M byte used as an opcode extension. * ******************************************************************************/ static inline void handle_group_3(uint32_t counter, uint32_t opcode) { enum operand_t operand_a, operand_b; enum segment_t segment; enum size_t size; int operation; uint32_t addr; if ((opcode & 1) == 0) size = SIZE_8; else size = effective_operand_size(); fetch_mod_rm(&counter, (enum operand_t *) &operation, &operand_b, &addr, &segment); if (operation != 0x2 && operation != 0x3) operand_b = OPERAND_IMMEDIATE; switch (operation & 7) { case 0x0: test(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x1: ERROR(); break; case 0x2: not(counter, operand_a, size, addr, segment); break; case 0x3: neg(counter, operand_a, size, addr, segment); break; case 0x4: mul(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x5: imul(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x6: div(counter, operand_a, size, operand_b, size, addr, segment); break; case 0x7: idiv(counter, operand_a, size, operand_b, size, addr, segment); break; default: ERROR(); } } /****************************************************************************** * * Handler for Group 4 and Group 5 * * Bits 5, 4 and 3 of ModR/M byte used as an opcode extension. * ******************************************************************************/ /* static void handle_group_4_and_5(uint32_t counter, uint32_t opcode) { int operand_size, opcode_extension, mod, rm; if ((opcode & 1) == 0) operand_size = 1; else operand_size = prefix_operand_size_override ? 4 : 2; decode_mod_rm(GET(1), &mod, &opcode_extension, &rm); if (opcode_extension >= 2 && opcode == 0xfe) { // TODO // gen_exception(c, CPU_FAULT_UD, pc_start - s->cs_base); // return; } if (mod != 3) { // TODO load: gen_lea_modrm // set ADDR } else { gen_load_reg_t1(rm, op_size); } switch (opcode_extension) { case 0x0: // INC gen_inc((mod == 0x3) ? rm : OPERAND_ADDR, operand_size); break; case 0x1: // DEC gen_dec((mod == 0x3) ? rm : OPERAND_ADDR, operand_size); break; case 0x2: // CALL break; } } */ /****************************************************************************** * * Handler for INC general-purpose register * * Opcode: 0x40 ... 0x47 * ******************************************************************************/ static inline void handle_inc_general_register(uint32_t counter, uint32_t opcode) { enum operand_t operand; enum size_t size; operand = opcode & 7; size = effective_operand_size(); inc(counter, operand, size, 0, SEGMENT_NONE); } /****************************************************************************** * * Handler for DEC general-purpose register * * Opcode: 0x48 ... 0x4f * ******************************************************************************/ static inline void handle_dec_general_register(uint32_t counter, uint32_t opcode) { enum operand_t operand; enum size_t size; operand = opcode & 7; size = effective_operand_size(); dec(counter, operand, size, 0, SEGMENT_NONE); } /****************************************************************************** * * Handler for PUSH general-purpose register * * Opcode: 0x50 ... 0x57 * ******************************************************************************/ static inline void handle_push_general_register(uint32_t counter, uint32_t opcode) { enum size_t operand_size, stack_size; enum operand_t operand; operand = opcode & 7; operand_size = effective_operand_size(); if (ss_size32) stack_size = SIZE_32; else stack_size = SIZE_16; push(counter, operand, operand_size, 0, SEGMENT_NONE, stack_size); } /****************************************************************************** * * Handler for POP general-purpose register * * Opcode: 0x58 ... 0x5f * ******************************************************************************/ static inline void handle_pop_general_register(uint32_t counter, uint32_t opcode) { enum size_t operand_size, stack_size; enum operand_t operand; operand = opcode & 7; operand_size = effective_operand_size(); if (ss_size32) stack_size = SIZE_32; else stack_size = SIZE_16; pop(counter, operand, operand_size, 0, SEGMENT_NONE, stack_size); } /****************************************************************************** * * Handler for PUSH segment register * ******************************************************************************/ static inline void handle_push_segment_register(uint32_t counter, uint32_t opcode) { enum size_t operand_size, stack_size; enum operand_t operand; switch (opcode) { case 0x06: operand = OPERAND_ES; break; case 0x0e: operand = OPERAND_CS; break; case 0x16: operand = OPERAND_SS; break; case 0x1e: operand = OPERAND_DS; break; case 0x0fa0: operand = OPERAND_FS; break; case 0x0fa8: operand = OPERAND_GS; break; default: ERROR(); } operand_size = effective_operand_size(); if (ss_size32) stack_size = SIZE_32; else stack_size = SIZE_16; push(counter, operand, operand_size, 0, SEGMENT_NONE, stack_size); } /****************************************************************************** * * Handler for POP segment register * ******************************************************************************/ static inline void handle_pop_segment_register(uint32_t counter, uint32_t opcode) { enum size_t operand_size, stack_size; enum operand_t operand; switch (opcode) { case 0x07: operand = OPERAND_ES; break; case 0x17: operand = OPERAND_SS; break; case 0x1f: operand = OPERAND_DS; break; case 0x0fa1: operand = OPERAND_FS; break; case 0x0fa8: operand = OPERAND_GS; break; default: ERROR(); } operand_size = effective_operand_size(); if (ss_size32) stack_size = SIZE_32; else stack_size = SIZE_16; pop(counter, operand, operand_size, 0, SEGMENT_NONE, stack_size); } /****************************************************************************** * * Handler for MOV * ******************************************************************************/ static inline enum operand_t segment2operand(enum segment_t segment) { switch (segment) { case SEGMENT_NONE: ERROR(); case SEGMENT_ES: return OPERAND_ES; case SEGMENT_CS: return OPERAND_CS; case SEGMENT_SS: return OPERAND_SS; case SEGMENT_DS: return OPERAND_DS; case SEGMENT_FS: return OPERAND_FS; case SEGMENT_GS: return OPERAND_GS; default: ERROR(); } } static inline void handle_mov(uint32_t counter, uint32_t opcode) { enum operand_t operand_src, operand_dst; enum segment_t segment; enum segment_t sreg; enum size_t size; uint32_t addr; if (opcode == 0x8c || opcode == 0x8e) size = SIZE_16; else if (opcode == 0xb8 || (opcode & 1) == 1) size = effective_operand_size(); else size = SIZE_8; switch (opcode) { case 0x88: case 0x89: fetch_mod_rm(&counter, &operand_src, &operand_dst, &addr, &segment); break; case 0x8a: case 0x8b: fetch_mod_rm(&counter, &operand_dst, &operand_src, &addr, &segment); break; case 0x8c: fetch_mod_rm(&counter, (enum operand_t *) &sreg, &operand_dst, &addr, &segment); if (sreg >= SEGMENT_INVALID) exception(EXCEPTION_UD, 0); operand_src = segment2operand(sreg); break; case 0x8e: fetch_mod_rm(&counter, (enum operand_t *) &sreg, &operand_src, &addr, &segment); if (sreg >= SEGMENT_INVALID || sreg == SEGMENT_CS) exception(EXCEPTION_UD, 0); operand_dst = segment2operand(sreg); break; case 0xa0: case 0xa1: case 0xa2: case 0xa3: addr = fetch(&counter, effective_address_size()); if ((opcode & 2) == 0) { operand_src = OPERAND_ADDRESS; operand_dst = OPERAND_EAX; } else { operand_src = OPERAND_EAX; operand_dst = OPERAND_ADDRESS; } segment = SEGMENT_DS; break; case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: operand_dst = opcode & 7; operand_src = OPERAND_IMMEDIATE; break; case 0xc6: case 0xc7: fetch_mod_rm(&counter, &operand_dst, &operand_src, &addr, &segment); if (operand_src != 0) exception(EXCEPTION_UD, 0); operand_src = OPERAND_IMMEDIATE; break; default: ERROR(); } mov(counter, operand_dst, size, operand_src, size, addr, segment); } /****************************************************************************** * * Handler for Jcc - Jump if Condition Is Met * ******************************************************************************/ static inline void handle_jecxz(uint32_t counter, uint32_t opcode) { enum size_t size; size = effective_operand_size(); jecxz(counter, size); } static inline void handle_jcc(uint32_t counter, uint32_t opcode) { enum size_t size; bool negate; enum jcc_t cc; negate = opcode & 1; cc = (enum jcc_t) ((opcode >> 1) & 7); switch (opcode >> 4) { case 0x7: size = SIZE_8; break; case 0x0f8: size = effective_operand_size(); break; default: ERROR(); } jcc(counter, cc, negate, size); } /****************************************************************************** * * Exception handler * ******************************************************************************/ static inline void handle_exception(void) { // TODO exception_vector = EXCEPTION_NONE; ERROR(); } /****************************************************************************** * * Prefix Handler * ******************************************************************************/ static inline void handle_prefix(uint32_t counter, uint32_t opcode) { switch (opcode) { case 0x26: // ES segment override prefix prefix_segment_override = SEGMENT_ES; eip += counter; break; case 0x2e: // CS segment override prefix prefix_segment_override = SEGMENT_CS; eip += counter; break; case 0x36: // SS segment override prefix prefix_segment_override = SEGMENT_SS; eip += counter; break; case 0x3e: // DS segment override prefix prefix_segment_override = SEGMENT_DS; eip += counter; break; case 0x64: // FS segment override prefix prefix_segment_override = SEGMENT_FS; eip += counter; break; case 0x65: // GS segment override prefix prefix_segment_override = SEGMENT_GS; eip += counter; break; case 0x66: // Operand-size override prefix prefix_operand_size_override = true; eip += counter; break; case 0x67: // Address-size override prefix prefix_address_size_override = true; eip += counter; break; case 0xf0: // LOCK prefix lock(); prefix_lock_repeat = LR_LOCK; eip += counter; break; case 0xf2: // REPNE/REPNZ prefix (used only with string instructions) if (prefix_lock_repeat == LR_LOCK) unlock(); prefix_lock_repeat = LR_REPNZ; eip += counter; break; case 0xf3: // REP/REPE/REPZ prefix (used only with string instructions) if (prefix_lock_repeat == LR_LOCK) unlock(); prefix_lock_repeat = LR_REPZ; eip += counter; break; default: ERROR(); } } /****************************************************************************** * * Handler for one instruction including prefixes * ******************************************************************************/ void handle_instruction(void) { uint32_t counter; uint32_t opcode; if (exception_vector != EXCEPTION_NONE) { handle_exception(); return; } counter = 0; opcode = fetch(&counter, SIZE_8); switch (opcode) { case 0x00: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x01: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x02: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x03: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x04: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x05: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x06: handle_push_segment_register(counter, opcode); break; // PUSH ES case 0x07: handle_pop_segment_register(counter, opcode); break; // POP ES case 0x08: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x09: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x0a: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x0b: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x0c: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x0d: handle_arithmetic_and_logic(counter, opcode); break; // OR case 0x0e: handle_push_segment_register(counter, opcode); break; // PUSH CS case 0x0f: // two-byte opcode opcode = 0xf00 | fetch(&counter, SIZE_8); switch (opcode) { /* TODO */ case 0x0f80: handle_jcc(counter, opcode); break; // JO case 0x0f81: handle_jcc(counter, opcode); break; // JNO case 0x0f82: handle_jcc(counter, opcode); break; // JB case 0x0f83: handle_jcc(counter, opcode); break; // JNB case 0x0f84: handle_jcc(counter, opcode); break; // JZ case 0x0f85: handle_jcc(counter, opcode); break; // JNZ case 0x0f86: handle_jcc(counter, opcode); break; // JBE case 0x0f87: handle_jcc(counter, opcode); break; // JNBE case 0x0f88: handle_jcc(counter, opcode); break; // JS case 0x0f89: handle_jcc(counter, opcode); break; // JNS case 0x0f8a: handle_jcc(counter, opcode); break; // JP case 0x0f8b: handle_jcc(counter, opcode); break; // JNP case 0x0f8c: handle_jcc(counter, opcode); break; // JL case 0x0f8d: handle_jcc(counter, opcode); break; // JNL case 0x0f8e: handle_jcc(counter, opcode); break; // JLE case 0x0f8f: handle_jcc(counter, opcode); break; // JNLE /* TODO */ case 0x0fa0: handle_push_segment_register(counter, opcode); break; // PUSH FS case 0x0fa1: handle_pop_segment_register(counter, opcode); break; // POP FS /* TODO */ case 0x0fa8: handle_push_segment_register(counter, opcode); break; // PUSH GS case 0x0fa9: handle_pop_segment_register(counter, opcode); break; // POP GS /* TODO */ default: ERROR(); } break; case 0x10: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x11: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x12: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x13: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x14: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x15: handle_arithmetic_and_logic(counter, opcode); break; // ADC case 0x16: handle_push_segment_register(counter, opcode); break; // PUSH SS case 0x17: handle_pop_segment_register(counter, opcode); break; // POP SS case 0x18: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x19: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x1a: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x1b: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x1c: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x1d: handle_arithmetic_and_logic(counter, opcode); break; // SBB case 0x1e: handle_push_segment_register(counter, opcode); break; // PUSH DS case 0x1f: handle_pop_segment_register(counter, opcode); break; // POP DS case 0x20: handle_arithmetic_and_logic(counter, opcode); break; // AND case 0x21: handle_arithmetic_and_logic(counter, opcode); break; // AND case 0x22: handle_arithmetic_and_logic(counter, opcode); break; // AND case 0x23: handle_arithmetic_and_logic(counter, opcode); break; // AND case 0x24: handle_arithmetic_and_logic(counter, opcode); break; // ADD case 0x25: handle_arithmetic_and_logic(counter, opcode); break; // AND case 0x26: handle_prefix(counter, opcode); return; // ES segment override prefix case 0x27: daa(counter); break; // DAA case 0x28: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x29: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x2a: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x2b: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x2c: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x2d: handle_arithmetic_and_logic(counter, opcode); break; // SUB case 0x2e: handle_prefix(counter, opcode); return; // CS segment override prefix /* TODO: DAS */ case 0x30: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x31: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x32: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x33: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x34: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x35: handle_arithmetic_and_logic(counter, opcode); break; // XOR case 0x36: handle_prefix(counter, opcode); return; // SS segment override prefix /* TODO: AAA */ case 0x38: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x39: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x3a: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x3b: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x3c: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x3d: handle_arithmetic_and_logic(counter, opcode); break; // CMP case 0x3e: handle_prefix(counter, opcode); return; // DS segment override prefix /* TODO: AAS */ case 0x40: handle_inc_general_register(counter, opcode); break; // INC case 0x41: handle_inc_general_register(counter, opcode); break; // INC case 0x42: handle_inc_general_register(counter, opcode); break; // INC case 0x43: handle_inc_general_register(counter, opcode); break; // INC case 0x44: handle_inc_general_register(counter, opcode); break; // INC case 0x45: handle_inc_general_register(counter, opcode); break; // INC case 0x46: handle_inc_general_register(counter, opcode); break; // INC case 0x47: handle_inc_general_register(counter, opcode); break; // INC case 0x48: handle_dec_general_register(counter, opcode); break; // DEC case 0x49: handle_dec_general_register(counter, opcode); break; // DEC case 0x4a: handle_dec_general_register(counter, opcode); break; // DEC case 0x4b: handle_dec_general_register(counter, opcode); break; // DEC case 0x4c: handle_dec_general_register(counter, opcode); break; // DEC case 0x4d: handle_dec_general_register(counter, opcode); break; // DEC case 0x4e: handle_dec_general_register(counter, opcode); break; // DEC case 0x4f: handle_dec_general_register(counter, opcode); break; // DEC case 0x50: handle_push_general_register(counter, opcode); break; // PUSH case 0x51: handle_push_general_register(counter, opcode); break; // PUSH case 0x52: handle_push_general_register(counter, opcode); break; // PUSH case 0x53: handle_push_general_register(counter, opcode); break; // PUSH case 0x54: handle_push_general_register(counter, opcode); break; // PUSH case 0x55: handle_push_general_register(counter, opcode); break; // PUSH case 0x56: handle_push_general_register(counter, opcode); break; // PUSH case 0x57: handle_push_general_register(counter, opcode); break; // PUSH case 0x58: handle_pop_general_register(counter, opcode); break; // POP case 0x59: handle_pop_general_register(counter, opcode); break; // POP case 0x5a: handle_pop_general_register(counter, opcode); break; // POP case 0x5b: handle_pop_general_register(counter, opcode); break; // POP case 0x5c: handle_pop_general_register(counter, opcode); break; // POP case 0x5d: handle_pop_general_register(counter, opcode); break; // POP case 0x5e: handle_pop_general_register(counter, opcode); break; case 0x5f: handle_pop_general_register(counter, opcode); break; // POP /* TODO */ case 0x64: handle_prefix(counter, opcode); return; // FS segment override prefix case 0x65: handle_prefix(counter, opcode); return; // GS segment override prefix case 0x66: handle_prefix(counter, opcode); return; // Operand-size override prefix case 0x67: handle_prefix(counter, opcode); return; // Address-size override prefix /* TODO */ case 0x70: handle_jcc(counter, opcode); break; // JO case 0x71: handle_jcc(counter, opcode); break; // JNO case 0x72: handle_jcc(counter, opcode); break; // JB case 0x73: handle_jcc(counter, opcode); break; // JNB case 0x74: handle_jcc(counter, opcode); break; // JZ case 0x75: handle_jcc(counter, opcode); break; // JNZ case 0x76: handle_jcc(counter, opcode); break; // JBE case 0x77: handle_jcc(counter, opcode); break; // JNBE case 0x78: handle_jcc(counter, opcode); break; // JS case 0x79: handle_jcc(counter, opcode); break; // JNS case 0x7a: handle_jcc(counter, opcode); break; // JP case 0x7b: handle_jcc(counter, opcode); break; // JNP case 0x7c: handle_jcc(counter, opcode); break; // JL case 0x7d: handle_jcc(counter, opcode); break; // JNL case 0x7e: handle_jcc(counter, opcode); break; // JLE case 0x7f: handle_jcc(counter, opcode); break; // JNLE case 0x80: handle_group_1(counter, opcode); break; // ADD,OR,ADC,SBB,AND,SUB,XOR,CMP case 0x81: handle_group_1(counter, opcode); break; // ADD,OR,ADC,SBB,AND,SUB,XOR,CMP case 0x82: handle_group_1(counter, opcode); break; // ADD,OR,ADC,SBB,AND,SUB,XOR,CMP case 0x83: handle_group_1(counter, opcode); break; // ADD,OR,ADC,SBB,AND,SUB,XOR,CMP /* TODO */ case 0x88: handle_mov(counter, opcode); break; // MOV case 0x89: handle_mov(counter, opcode); break; // MOV case 0x8a: handle_mov(counter, opcode); break; // MOV case 0x8b: handle_mov(counter, opcode); break; // MOV case 0x8c: handle_mov(counter, opcode); break; // MOV case 0x8e: handle_mov(counter, opcode); break; // MOV /* TODO */ case 0x9f: lahf(counter); break; // LAHF /* TODO */ case 0xa0: handle_mov(counter, opcode); break; // MOV case 0xa1: handle_mov(counter, opcode); break; // MOV case 0xa2: handle_mov(counter, opcode); break; // MOV case 0xa3: handle_mov(counter, opcode); break; // MOV /* TODO */ case 0xb0: handle_mov(counter, opcode); break; // MOV case 0xb1: handle_mov(counter, opcode); break; // MOV case 0xb2: handle_mov(counter, opcode); break; // MOV case 0xb3: handle_mov(counter, opcode); break; // MOV case 0xb4: handle_mov(counter, opcode); break; // MOV case 0xb5: handle_mov(counter, opcode); break; // MOV case 0xb6: handle_mov(counter, opcode); break; // MOV case 0xb7: handle_mov(counter, opcode); break; // MOV case 0xb8: handle_mov(counter, opcode); break; // MOV case 0xb9: handle_mov(counter, opcode); break; // MOV case 0xba: handle_mov(counter, opcode); break; // MOV case 0xbb: handle_mov(counter, opcode); break; // MOV case 0xbc: handle_mov(counter, opcode); break; // MOV case 0xbd: handle_mov(counter, opcode); break; // MOV case 0xbe: handle_mov(counter, opcode); break; // MOV case 0xbf: handle_mov(counter, opcode); break; // MOV /* TODO */ case 0xc6: handle_mov(counter, opcode); break; // MOV case 0xc7: handle_mov(counter, opcode); break; // MOV /* TODO */ case 0xe3: handle_jecxz(counter, opcode); break; // JECXZ JCXZ /* TODO */ case 0xf0: handle_prefix(counter, opcode); return; // LOCK prefix case 0xf1: exception(EXCEPTION_UD, 0); break; // Reserved and should not be used case 0xf2: handle_prefix(counter, opcode); return; // REPNE/REPNZ prefix (used only with string instructions) case 0xf3: handle_prefix(counter, opcode); return; // REP/REPE/REPZ prefix (used only with string instructions) /* TODO */ case 0xf6: handle_group_3(counter, opcode); break; // TEST,NOT,NEG,MUL,IMUL,DIV,IDIV case 0xf7: handle_group_3(counter, opcode); break; // TEST,NOT,NEG,MUL,IMUL,DIV,IDIV /* TODO */ default: ERROR(); } if (prefix_lock_repeat == LR_LOCK) unlock(); prefix_lock_repeat = LR_NONE; prefix_segment_override = SEGMENT_NONE; prefix_operand_size_override = false; prefix_address_size_override = false; } faucc-20120707/test/test10.c0000640002413100241000000000064511137627476014774 0ustar potyrai3guest/* $Id: test10.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2008-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ inline int test(int x) { return 2 * x; } int main(void) { return test(1); } faucc-20120707/test/test-conv.c0000640002413100241000000000322011710270011015536 0ustar potyrai3guest/* * $Id: test-conv.c,v 1.1 2012-01-26 15:23:53 vrsieh Exp $ */ #include #define conv(t0, t1) \ t0 \ conv_ ## t0 ## _ ## t1(t1 x) \ { \ return x; \ } conv(int8_t, int8_t) conv(int8_t, uint8_t) conv(int8_t, int16_t) conv(int8_t, uint16_t) conv(int8_t, int32_t) conv(int8_t, uint32_t) conv(int8_t, int64_t) conv(int8_t, uint64_t) conv(uint8_t, int8_t) conv(uint8_t, uint8_t) conv(uint8_t, int16_t) conv(uint8_t, uint16_t) conv(uint8_t, int32_t) conv(uint8_t, uint32_t) conv(uint8_t, int64_t) conv(uint8_t, uint64_t) conv(int16_t, int8_t) conv(int16_t, uint8_t) conv(int16_t, int16_t) conv(int16_t, uint16_t) conv(int16_t, int32_t) conv(int16_t, uint32_t) conv(int16_t, int64_t) conv(int16_t, uint64_t) conv(uint16_t, int8_t) conv(uint16_t, uint8_t) conv(uint16_t, int16_t) conv(uint16_t, uint16_t) conv(uint16_t, int32_t) conv(uint16_t, uint32_t) conv(uint16_t, int64_t) conv(uint16_t, uint64_t) conv(int32_t, int8_t) conv(int32_t, uint8_t) conv(int32_t, int16_t) conv(int32_t, uint16_t) conv(int32_t, int32_t) conv(int32_t, uint32_t) conv(int32_t, int64_t) conv(int32_t, uint64_t) conv(uint32_t, int8_t) conv(uint32_t, uint8_t) conv(uint32_t, int16_t) conv(uint32_t, uint16_t) conv(uint32_t, int32_t) conv(uint32_t, uint32_t) conv(uint32_t, int64_t) conv(uint32_t, uint64_t) conv(int64_t, int8_t) conv(int64_t, uint8_t) conv(int64_t, int16_t) conv(int64_t, uint16_t) conv(int64_t, int32_t) conv(int64_t, uint32_t) conv(int64_t, int64_t) conv(int64_t, uint64_t) conv(uint64_t, int8_t) conv(uint64_t, uint8_t) conv(uint64_t, int16_t) conv(uint64_t, uint16_t) conv(uint64_t, int32_t) conv(uint64_t, uint32_t) conv(uint64_t, int64_t) conv(uint64_t, uint64_t) faucc-20120707/test/test9.c0000640002413100241000000000077011137627476014723 0ustar potyrai3guest/* $Id: test9.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ extern void printf(const char *, ...); int x = 10; int main(void) { int y = x; int x; for (x = 0; x < 5; x++) { printf("%d %d\n", x, y); } return 0; } faucc-20120707/test/test-switch.c0000640002413100241000000000231511706307555016121 0ustar potyrai3guest/* * $Id: test-switch.c,v 1.1 2012-01-20 15:59:41 vrsieh Exp $ */ #include extern void a(void); void uint8_switch_test(uint8_t x) { switch (x) { case 0: a(); break; case 1: a(); case 2: a(); break; default: a(); } } void int8_switch_test(int8_t x) { switch (x) { case 0: a(); break; case 1: a(); case 2: a(); break; default: a(); } } void uint16_switch_test(uint16_t x) { switch (x) { case 0: a(); break; case 1: a(); case 2: a(); break; default: a(); } } void int16_switch_test(int16_t x) { switch (x) { case 0: a(); break; case 1: a(); case 2: a(); break; default: a(); } } void uint32_switch_test(uint32_t x) { switch (x) { case 0: a(); break; case 1: a(); case 2: a(); break; default: a(); } } void int32_switch_test(int32_t x) { switch (x) { case 0: a(); break; case 1: a(); case 2: a(); break; default: a(); } } void uint64_switch_test(uint64_t x) { switch (x) { case 0: a(); break; case 1: a(); case 2: a(); break; default: a(); } } void int64_switch_test(int64_t x) { switch (x) { case 0: a(); break; case 1: a(); case 2: a(); break; default: a(); } } faucc-20120707/test/test-hello-world.c0000640002413100241000000000066111137627476017057 0ustar potyrai3guest/* * $Id: test-hello-world.c,v 1.2 2009-01-27 15:58:54 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include int main(void) { printf("hello world!\n"); return 0; } faucc-20120707/test/test-if.c0000640002413100241000000000320311706307266015212 0ustar potyrai3guest/* * $Id: test-if.c,v 1.1 2012-01-20 15:56:38 vrsieh Exp $ */ #include extern void a(void); void uint8_if_test(uint8_t x, uint8_t y) { if (x == y) { a(); } if (x != y) { a(); } if (x < y) { a(); } if (x <= y) { a(); } if (x > y) { a(); } if (x >= y) { a(); } } void int8_if_test(int8_t x, int8_t y) { if (x == y) { a(); } if (x != y) { a(); } if (x < y) { a(); } if (x <= y) { a(); } if (x > y) { a(); } if (x >= y) { a(); } } void uint16_if_test(uint16_t x, uint16_t y) { if (x == y) { a(); } if (x != y) { a(); } if (x < y) { a(); } if (x <= y) { a(); } if (x > y) { a(); } if (x >= y) { a(); } } void int16_if_test(int16_t x, int16_t y) { if (x == y) { a(); } if (x != y) { a(); } if (x < y) { a(); } if (x <= y) { a(); } if (x > y) { a(); } if (x >= y) { a(); } } void uint32_if_test(uint32_t x, uint32_t y) { if (x == y) { a(); } if (x != y) { a(); } if (x < y) { a(); } if (x <= y) { a(); } if (x > y) { a(); } if (x >= y) { a(); } } void int32_if_test(int32_t x, int32_t y) { if (x == y) { a(); } if (x != y) { a(); } if (x < y) { a(); } if (x <= y) { a(); } if (x > y) { a(); } if (x >= y) { a(); } } void uint64_if_test(uint64_t x, uint64_t y) { if (x == y) { a(); } if (x != y) { a(); } if (x < y) { a(); } if (x <= y) { a(); } if (x > y) { a(); } if (x >= y) { a(); } } void int64_if_test(int64_t x, int64_t y) { if (x == y) { a(); } if (x != y) { a(); } if (x < y) { a(); } if (x <= y) { a(); } if (x > y) { a(); } if (x >= y) { a(); } } faucc-20120707/expr.c0000640002413100241000000027327411137625346013657 0ustar potyrai3guest/* $Id: expr.c,v 1.171 2009-01-27 15:40:22 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include #include #include "identifier.h" #include "type.h" #include "declaration.h" #include "scope.h" #include "expr.h" #include "stmt.h" #include "simplify.h" static int expr_change; void expr_rename_structunionenum( struct expr *e, enum type_type type, const char *old, const char *new ) { if (e->type_name) { type_rename_structunionenum(e->type_name, type, old, new); } } struct type * expr_typeof(struct scope *s, struct expr *e) { struct declaration *dion; struct type *ts0; struct type *ts1; struct type *t; int ret; switch (e->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_INTEGER: case EXPR_REAL: return e->type_name; case EXPR_STRING: return type_const_char_pointer(); case EXPR_IDENTIFIER: return e->declaration->type_name; case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: return type_int(); case EXPR_BUILTIN_VA_ARG: case EXPR_TYPE_CONVERSION: return e->type_name; case EXPR_STAR: return type_star(expr_typeof(s, e->expr0)); case EXPR_ARRAY: return type_array_access(expr_typeof(s, e->expr0)); case EXPR_AMPHERSAND: return type_amphersand(expr_typeof(s, e->expr0)); case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: return expr_typeof(s, e->expr0); case EXPR_NEG: case EXPR_INV: return expr_typeof(s, e->expr0); case EXPR_NOT: return type_int(); case EXPR_LEFT: case EXPR_RIGHT: t = expr_typeof(s, e->expr0); return type_arithmetic(t, t); case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_GREATER: case EXPR_LESS_EQUAL: case EXPR_GREATER_EQUAL: return type_int(); case EXPR_ADD: case EXPR_SUB: case EXPR_MUL: case EXPR_DIV: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_XOR: ts0 = expr_typeof(s, e->expr0); ts1 = expr_typeof(s, e->expr1); if (e->type == EXPR_ADD) { return type_add(ts0, ts1); } else if (e->type == EXPR_SUB) { return type_sub(ts0, ts1); } else { return type_arithmetic(ts0, ts1); } case EXPR_SHORT_OR: case EXPR_SHORT_AND: return type_int(); case EXPR_LIST: return expr_typeof(s, e->last); case EXPR_DOT: case EXPR_ARROW: ts0 = expr_typeof(s, e->expr0); if (e->type == EXPR_ARROW) { ts0 = type_star(ts0); } assert(type_is_struct(ts0) || type_is_union(ts0)); if (! ts0->scope) { ret = scope_lookup_structunionenum(s, ts0->type, ts0->identifier, &ts1); assert(0 <= ret); ts0 = ts1; } assert(ts0->scope); ret = scope_lookup_one(ts0->scope, e->member, &dion); assert(0 <= ret); return dion->type_name; case EXPR_FUNC: t = expr_typeof(s, e->expr0); if (type_is_pointer(t)) { t = type_star(t); } return type_call(t); case EXPR_CONDITION: ts0 = expr_typeof(s, e->expr1); ts1 = expr_typeof(s, e->expr2); return type_arithmetic(ts0, ts1); case EXPR_ASSIGN: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: return expr_typeof(s, e->expr0); } /*NOTREACHED*/ assert(0); return NULL; } int expr_is_constant(struct expr *e) { switch (e->type) { case EXPR_INTEGER: return 1; case EXPR_REAL: return 1; case EXPR_TYPE_CONVERSION: if (e->expr0->type == EXPR_AMPHERSAND && (e->expr0->expr0->declaration->storage == STORAGE_NONE || e->expr0->expr0->declaration->storage == STORAGE_EXTERN || e->expr0->expr0->declaration->storage == STORAGE_STATIC)) { /* * (int) & global_var */ return 1; } if (e->expr0->type == EXPR_IDENTIFIER && (e->expr0->declaration->storage == STORAGE_NONE || e->expr0->declaration->storage == STORAGE_EXTERN || e->expr0->declaration->storage == STORAGE_STATIC)) { /* * (int) global_array * (int) function */ return 1; } return 0; default: return 0; } } struct expr * expr_new(void) { struct expr *e; e = malloc(sizeof(*e)); assert(e); memset(e, 0, sizeof(*e)); return e; } struct expr * expr_integer(int n) { struct expr *e; e = expr_new(); e->type = EXPR_INTEGER; e->type_name = type_int(); e->integer = n; return e; } struct expr * expr_identifier(struct declaration *dion) { struct expr *e; e = expr_new(); e->type = EXPR_IDENTIFIER; e->declaration = dion; return e; } struct expr * expr_sizeof_expr(struct expr *e0) { struct expr *e; e = expr_new(); e->type = EXPR_SIZEOF_EXPR; e->expr0 = e0; return e; } struct expr * expr_sizeof_type(struct type *t) { struct expr *e; e = expr_new(); e->type = EXPR_SIZEOF_TYPE; e->type_name = t; return e; } struct expr * expr_offsetof(struct type *t, const char *name) { struct expr *e; e = expr_new(); e->type = EXPR_BUILTIN_OFFSETOF; e->type_name = t; e->expr0 = expr_new(); e->expr0->type = EXPR_ARROW; e->expr0->member = identifier_dup(name); return e; } struct expr * expr_amphersand(struct expr *e0) { struct expr *e; e = expr_new(); e->type = EXPR_AMPHERSAND; e->expr0 = e0; return e; } struct expr * expr_star(struct expr *e0) { struct expr *e; e = expr_new(); e->type = EXPR_STAR; e->expr0 = e0; return e; } struct expr * expr_arrow(struct expr *e0, const char *mem) { struct expr *e; assert(mem); e = expr_new(); e->type = EXPR_ARROW; e->expr0 = e0; e->member = mem; return e; } struct expr * expr_not(struct expr *e0) { struct expr *e; e = expr_new(); e->type = EXPR_NOT; e->expr0 = e0; return e; } struct expr * expr_left(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_LEFT; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_right(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_RIGHT; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_add(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_ADD; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_sub(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_SUB; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_mul(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_MUL; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_div(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_DIV; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_mod(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_MOD; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_and(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_AND; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_or(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_OR; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_xor(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_XOR; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_short_and(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_SHORT_AND; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_short_or(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_SHORT_OR; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_equal(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_EQUAL; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_not_equal(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_NOT_EQUAL; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_less(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_LESS; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_less_equal(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_LESS_EQUAL; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_greater(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_GREATER; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_greater_equal(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_GREATER_EQUAL; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_assign(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_ASSIGN; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_add_assign(struct expr *e0, struct expr *e1) { struct expr *e; e = expr_new(); e->type = EXPR_ADD_ASSIGN; e->expr0 = e0; e->expr1 = e1; return e; } struct expr * expr_cast(struct type *t, struct expr *e0) { struct expr *e; e = expr_new(); e->type = EXPR_TYPE_CONVERSION; e->type_name = t; e->expr0 = e0; return e; } struct expr * expr_cast_ptrdiff(struct expr *e0) { struct type *t; t = type_ptrdiff(); return expr_cast(t, e0); } struct expr * expr_dup(struct expr *e) { struct expr *ce; struct expr *ne; struct expr *nce; if (e == NULL) { return NULL; } ne = expr_new(); ne->type = e->type; ne->integer = e->integer; ne->real = e->real; ne->string_len = e->string_len; ne->string = identifier_dup(e->string); ne->member = identifier_dup(e->member); if (e->declaration && e->declaration->clone) { ne->declaration = e->declaration->clone; } else { ne->declaration = e->declaration; } ne->type_name = e->type_name; ne->expr0 = expr_dup(e->expr0); ne->expr1 = expr_dup(e->expr1); ne->expr2 = expr_dup(e->expr2); ne->first = NULL; ne->last = NULL; for (ce = e->first; ce; ce = ce->next) { nce = expr_dup(ce); nce->prev = ne->last; nce->next = NULL; if (nce->prev) { nce->prev->next = nce; } else { ne->first = nce; } ne->last = nce; } return ne; } void expr_cp(struct expr *oe, struct expr *ne) { struct expr *prev; struct expr *next; prev = oe->prev; next = oe->next; memcpy(oe, ne, sizeof *oe); oe->prev = prev; oe->next = next; } void expr_free(struct expr *e) { if (! e) { return; } /* ... */ } /* ------------------------------------------------------------------------- */ static void expr_simplify_sizeof(struct scope *scope, struct expr *e) { struct type *t0; struct expr *e0; switch (e->type) { case EXPR_SIZEOF_TYPE: /* * Replace * sizeof(type) * by * constant */ t0 = e->type_name; sizeof_type:; e0 = expr_integer(type_sizeof(scope, t0)); expr_cp(e, e0); expr_change = 1; break; case EXPR_SIZEOF_EXPR: /* * Replace * sizeof expr * by * constant */ t0 = expr_typeof(scope, e->expr0); goto sizeof_type; default: assert(0); } } static void _expr_simplify_offsetof( struct scope *scope, struct type *t, struct expr *e, struct type **rt, struct expr **re ) { struct declaration *dion; struct expr *e0; struct expr *e1; struct expr *e2; int ret; switch (e->type) { case EXPR_ARROW: assert(type_is_struct(t) || type_is_union(t)); ret = scope_lookup_structunionenum(scope, t->type, t->identifier, &t); assert(0 <= ret); ret = scope_lookup_one(t->scope, e->member, &dion); assert(0 <= ret); /* Return type. */ *rt = dion->type_name; /* Return expression. */ if (t->type == TYPE_STRUCT) { e0 = expr_integer(type_offsetof(scope, t, e->member)); } else { e0 = expr_integer(0); } *re = e0; break; case EXPR_DOT: _expr_simplify_offsetof(scope, t, e->expr0, &t, &e0); assert(type_is_struct(t) || type_is_union(t)); ret = scope_lookup_structunionenum(scope, t->type, t->identifier, &t); assert(0 <= ret); ret = scope_lookup_one(t->scope, e->member, &dion); assert(0 <= ret); /* Return type. */ *rt = dion->type_name; /* Return expression. */ if (t->type == TYPE_STRUCT) { e1 = expr_integer(type_offsetof(scope, t, e->member)); } else { e1 = expr_integer(0); } *re = expr_add(e0, e1); break; case EXPR_ARRAY: _expr_simplify_offsetof(scope, t, e->expr0, &t, &e0); assert(type_is_array(t)); t = type_array_access(t); /* Return type. */ *rt = t; /* Return expression. */ e1 = expr_integer(type_sizeof(scope, t)); e2 = expr_dup(e->expr1); *re = expr_add(e0, expr_mul(e1, e2)); break; default: assert(0); } } static void expr_simplify_offsetof(struct scope *scope, struct expr *e) { struct type *t0; struct expr *e0; _expr_simplify_offsetof(scope, e->type_name, e->expr0, &t0, &e0); expr_cp(e, e0); expr_change = 1; } static void expr_simplify_in_init(struct scope *scope, struct expr *e) { struct expr *ce; switch (e->type) { case EXPR_NONE: assert(0); case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: case EXPR_IDENTIFIER: /* Already simple. */ break; case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: expr_simplify_sizeof(scope, e); break; case EXPR_BUILTIN_OFFSETOF: expr_simplify_offsetof(scope, e); break; case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_VA_ARG: case EXPR_STAR: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_ASSIGN: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: case EXPR_FUNC: case EXPR_LIST: /* Mustn't be part of constant initializer. */ assert(0); case EXPR_TYPE_CONVERSION: case EXPR_AMPHERSAND: case EXPR_NEG: case EXPR_INV: case EXPR_NOT: expr_simplify_in_init(scope, e->expr0); break; case EXPR_LEFT: case EXPR_RIGHT: case EXPR_ADD: case EXPR_SUB: case EXPR_MUL: case EXPR_DIV: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_XOR: case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: expr_simplify_in_init(scope, e->expr0); expr_simplify_in_init(scope, e->expr1); break; case EXPR_BRACES: for (ce = e->first; ce; ce = ce->next) { expr_simplify_in_init(scope, ce); } break; } } static void expr_localize(struct stmt *block, struct stmt *s, struct expr *e) { struct declaration *var; struct type *t0; struct expr *e0; struct stmt *s0; switch (e->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: break; case EXPR_IDENTIFIER: if (! identifier_is_tmp(e->declaration->identifier)) { goto localize; } break; case EXPR_AMPHERSAND: if (e->expr0->type != EXPR_IDENTIFIER) { goto localize; } break; default: localize:; t0 = expr_typeof(block->scope, e); t0 = type_pure(t0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); e0 = expr_assign(expr_identifier(var), expr_dup(e)); s0 = stmt_expr(e0); e0 = expr_identifier(var); stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; } } static void expr_simplify_in_expr(struct stmt *block, struct stmt *s, struct expr *e) { struct declaration *var; struct label *label0; struct label *label1; struct type *t0; struct type *t1; int is_array; struct expr *e0; struct expr *e1; struct expr *e2; struct expr *e3; struct expr *e4; struct expr *e5; struct expr *e6; struct stmt *s0; struct stmt *s1; struct stmt *s2; struct stmt *s3; struct stmt *s4; struct stmt *s5; struct stmt *s6; again: ; switch (e->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: /* Already simple. */ break; case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: expr_simplify_sizeof(block->scope, e); break; case EXPR_BUILTIN_CONSTANT_P: /* * Replace * __builtin_constant_p(e) * by * 1 (if e is an integer/real/...) * 0 (else) */ switch (e->expr0->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: e0 = expr_integer(1); break; default: e0 = expr_integer(0); break; } expr_cp(e, e0); expr_change = 1; break; case EXPR_BUILTIN_OFFSETOF: expr_simplify_offsetof(block->scope, e); goto again; /* Split expression. */ case EXPR_BUILTIN_VA_ARG: case EXPR_IDENTIFIER: /* Already simple. */ break; case EXPR_STAR: if (e->expr0->type != EXPR_IDENTIFIER) { /* * Replace * *e0 * by * var = e0; * *var */ t0 = expr_typeof(block->scope, e->expr0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); e0 = expr_identifier(var); e1 = expr_dup(e->expr0); e2 = expr_assign(e0, e1); s0 = stmt_expr(e2); e0 = expr_identifier(var); stmt_prepend(block, s, s0); expr_cp(e->expr0, e0); expr_change = 1; } break; case EXPR_DOT: /* * Replace * struct.mem * * by (if struct.mem is *not* an array): * var = (typeof e0.mem *) * ((int) &struct + offsetof(typeof struct, mem)) * *var * * by (if struct.mem is an array): * var = (typeof struct.mem[0] *) * ((int) &struct + offsetof(typeof(struct, mem)) * var */ t0 = expr_typeof(block->scope, e); is_array = type_is_array(t0); t1 = expr_typeof(block->scope, e->expr0); assert(type_is_struct(t1) || type_is_union(t1)); e0 = expr_amphersand(expr_dup(e->expr0)); e1 = expr_cast(type_ptrdiff(), e0); e2 = expr_offsetof(t1, e->member); e3 = expr_add(e1, e2); if (is_array) { t0 = type_array_access(t0); } t0 = type_amphersand(t0); t0 = type_pure(t0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); e4 = expr_cast(t0, e3); s0 = stmt_expr(expr_assign(expr_identifier(var), e4)); if (is_array) { e0 = expr_identifier(var); } else { e0 = expr_star(expr_identifier(var)); } stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; case EXPR_ARROW: /* * Replace * struct->mem * * by (if struct->mem is *not* an array): * var = *(typeof struct->mem *) * ((int) struct + offsetof(typeof(struct, mem)) * *var * * by (if struct->mem is an array): * var = (typeof struct->mem[0] *) * ((int) struct + offsetof(typeof(struct, mem)) * var */ t0 = expr_typeof(block->scope, e); is_array = type_is_array(t0); t1 = expr_typeof(block->scope, e->expr0); t1 = type_star(t1); assert(type_is_struct(t1) || type_is_union(t1)); e0 = expr_dup(e->expr0); e1 = expr_cast(type_ptrdiff(), e0); e2 = expr_offsetof(t1, e->member); e3 = expr_add(e1, e2); if (is_array) { t0 = type_array_access(t0); } t0 = type_amphersand(t0); t0 = type_pure(t0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); e4 = expr_cast(t0, e3); s0 = stmt_expr(expr_assign(expr_identifier(var), e4)); if (is_array) { e0 = expr_identifier(var); } else { e0 = expr_star(expr_identifier(var)); } stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; case EXPR_ARRAY: /* * Replace * array[index] * * by (if array[index] is *not* an array): * var = (typeof array[index] *) * ((int) array + index * sizeof typeof array[index]) * *var * * by (if array[index] is an array): * var = (typeof array[index][0] *) * ((int) array + index * sizeof typeof array[index]) * var */ t0 = expr_typeof(block->scope, e); is_array = type_is_array(t0); t1 = expr_typeof(block->scope, e->expr0); assert(type_is_pointer(t1) || type_is_array(t1)); e0 = expr_dup(e->expr0); e1 = expr_cast(type_ptrdiff(), e0); e2 = expr_dup(e->expr1); e3 = expr_sizeof_type(t0); e4 = expr_mul(e2, e3); e5 = expr_add(e1, e4); if (is_array) { t0 = type_array_access(t0); } t0 = type_amphersand(t0); t0 = type_pure(t0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); e6 = expr_cast(t0, e5); s0 = stmt_expr(expr_assign(expr_identifier(var), e6)); if (is_array) { e0 = expr_identifier(var); } else { e0 = expr_star(expr_identifier(var)); } stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; case EXPR_AMPHERSAND: switch (e->expr0->type) { case EXPR_IDENTIFIER: /* Already simple. */ break; case EXPR_STAR: /* * Replace * &*e * by * var = e; * var */ t0 = expr_typeof(block->scope, e->expr0->expr0); t0 = type_pure(t0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); s0 = stmt_expr(expr_assign(expr_identifier(var), expr_dup(e->expr0->expr0))); e0 = expr_identifier(var); stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; case EXPR_DOT: /* * Replace * &struct.mem * by * var = (typeof struct.mem *) * ((int) &struct + offsetof(typeof struct, mem)) * var */ t0 = expr_typeof(block->scope, e->expr0); t1 = expr_typeof(block->scope, e->expr0->expr0); assert(type_is_struct(t1) || type_is_union(t1)); e0 = expr_amphersand(expr_dup(e->expr0->expr0)); e1 = expr_cast(type_ptrdiff(), e0); e2 = expr_offsetof(t1, e->expr0->member); e3 = expr_add(e1, e2); t0 = type_amphersand(t0); t0 = type_pure(t0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); e4 = expr_cast(t0, e3); s0 = stmt_expr(expr_assign(expr_identifier(var), e4)); e0 = expr_identifier(var); stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; case EXPR_ARROW: /* * Replace * &struct->mem * by * var = (typeof struct.mem *) * ((int) struct + offsetof(typeof struct, mem)) * var */ t0 = expr_typeof(block->scope, e->expr0); t1 = expr_typeof(block->scope, e->expr0->expr0); t1 = type_star(t1); assert(type_is_struct(t1) || type_is_union(t1)); e0 = expr_dup(e->expr0->expr0); e1 = expr_cast(type_ptrdiff(), e0); e2 = expr_offsetof(t1, e->expr0->member); e3 = expr_add(e1, e2); t0 = type_amphersand(t0); t0 = type_pure(t0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); e4 = expr_cast(t0, e3); s0 = stmt_expr(expr_assign(expr_identifier(var), e4)); e0 = expr_identifier(var); stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; case EXPR_ARRAY: /* * Replace * &array[index] * by * var = (typeof array[index] *) * ((ptrdiff_t) array + index * sizeof(typeof array[index])) * var */ t0 = expr_typeof(block->scope, e->expr0); t1 = expr_typeof(block->scope, e->expr0->expr0); assert(type_is_pointer(t1) || type_is_array(t1)); e0 = expr_dup(e->expr0->expr0); e1 = expr_cast(type_ptrdiff(), e0); e2 = expr_dup(e->expr0->expr1); e3 = expr_sizeof_type(t0); e4 = expr_mul(e2, e3); e5 = expr_add(e1, e4); t0 = type_amphersand(t0); t0 = type_pure(t0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); e6 = expr_cast(t0, e5); s0 = stmt_expr(expr_assign(expr_identifier(var), e6)); e0 = expr_identifier(var); stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; default: assert(0); } break; case EXPR_TYPE_CONVERSION: case EXPR_INV: case EXPR_NEG: case EXPR_NOT: case EXPR_LEFT: case EXPR_RIGHT: case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: case EXPR_ADD: case EXPR_SUB: case EXPR_MUL: case EXPR_DIV: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_XOR: case EXPR_FUNC: /* * Replace * complex-expression * by * var = complex-expression * var */ t0 = expr_typeof(block->scope, e); t0 = type_pure(t0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); s0 = stmt_expr(expr_assign(expr_identifier(var), expr_dup(e))); e0 = expr_identifier(var); stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; case EXPR_SHORT_AND: /* * Replace * e0 && e1 * by * 0: if (! e0) goto l0; * 1: if (! e1) goto l0; * 2: tmp = 1; * 3: goto l1; * 4: l0: ; * 5: tmp = 0; * 6: l1: ; * tmp */ label0 = label_new(identifier_tmp()); label1 = label_new(identifier_tmp()); var = simplify_declaration_add(block->scope, type_int(), identifier_tmp()); e0 = expr_not(expr_dup(e->expr0)); s0 = stmt_if(e0, stmt_goto(label0), NULL); e0 = expr_not(expr_dup(e->expr1)); s1 = stmt_if(e0, stmt_goto(label0), NULL); e0 = expr_assign(expr_identifier(var), expr_integer(1)); s2 = stmt_expr(e0); s3 = stmt_goto(label1); s4 = stmt_label(label0, stmt_null()); e0 = expr_assign(expr_identifier(var), expr_integer(0)); s5 = stmt_expr(e0); s6 = stmt_label(label1, stmt_null()); stmt_prepend(block, s, s0); stmt_prepend(block, s, s1); stmt_prepend(block, s, s2); stmt_prepend(block, s, s3); stmt_prepend(block, s, s4); stmt_prepend(block, s, s5); stmt_prepend(block, s, s6); expr_cp(e, expr_identifier(var)); expr_change = 1; break; case EXPR_SHORT_OR: /* * Replace * e0 || e1 * by * 0: if (e0) goto l0; * 1: if (e1) goto l0; * 2: tmp = 0; * 3: goto l1; * 4: l0: ; * 5: tmp = 1; * 6: l1: ; * tmp */ label0 = label_new(identifier_tmp()); label1 = label_new(identifier_tmp()); var = simplify_declaration_add(block->scope, type_int(), identifier_tmp()); e0 = expr_dup(e->expr0); s0 = stmt_if(e0, stmt_goto(label0), NULL); e0 = expr_dup(e->expr1); s1 = stmt_if(e0, stmt_goto(label0), NULL); e0 = expr_assign(expr_identifier(var), expr_integer(0)); s2 = stmt_expr(e0); s3 = stmt_goto(label1); s4 = stmt_label(label0, stmt_null()); e0 = expr_assign(expr_identifier(var), expr_integer(1)); s5 = stmt_expr(e0); s6 = stmt_label(label1, stmt_null()); stmt_prepend(block, s, s0); stmt_prepend(block, s, s1); stmt_prepend(block, s, s2); stmt_prepend(block, s, s3); stmt_prepend(block, s, s4); stmt_prepend(block, s, s5); stmt_prepend(block, s, s6); expr_cp(e, expr_identifier(var)); expr_change = 1; break; case EXPR_CONDITION: /* * Replace * e0 ? e1 : e2 * by * 0: if (e0) goto l0; * 1: tmp = e2; * 2: goto l1; * 3: l0: ; * 4: tmp = e1; * 5: l1: ; * tmp */ label0 = label_new(identifier_tmp()); label1 = label_new(identifier_tmp()); t0 = expr_typeof(block->scope, e); t0 = type_pure(t0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); e0 = expr_dup(e->expr0); s0 = stmt_if(e0, stmt_goto(label0), NULL); e0 = expr_assign(expr_identifier(var), expr_dup(e->expr2)); s1 = stmt_expr(e0); s2 = stmt_goto(label1); s3 = stmt_label(label0, stmt_null()); e0 = expr_assign(expr_identifier(var), expr_dup(e->expr1)); s4 = stmt_expr(e0); s5 = stmt_label(label1, stmt_null()); stmt_prepend(block, s, s0); stmt_prepend(block, s, s1); stmt_prepend(block, s, s2); stmt_prepend(block, s, s3); stmt_prepend(block, s, s4); stmt_prepend(block, s, s5); expr_cp(e, expr_identifier(var)); expr_change = 1; break; case EXPR_LIST: /* * Replace * e0, e1, ..., eNm1, eN * by * e0; * e1; * ... * eNm1; * eN */ assert(e->first); while (e->first != e->last) { e0 = e->first; /* Remove first entry from list. */ e->first = e0->next; e0->next->prev = NULL; /* Add as separate statement. */ s0 = stmt_expr(e0); stmt_prepend(block, s, s0); } assert(e->first == e->last); e0 = expr_dup(e->first); expr_cp(e, e0); expr_change = 1; break; case EXPR_PRE_INC: case EXPR_PRE_DEC: /* * Replace * ++e0 --e0 * by * e0 = e0 + 1; e0 = e0 - 1; * e0 e0 */ expr_simplify_in_expr(block, s, e->expr0); e0 = expr_dup(e->expr0); e1 = expr_dup(e->expr0); e2 = expr_integer(1); if (e->type == EXPR_PRE_INC) { e3 = expr_add(e1, e2); } else { e3 = expr_sub(e1, e2); } e4 = expr_assign(e0, e3); s0 = stmt_expr(e4); e0 = expr_dup(e->expr0); stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; case EXPR_POST_INC: case EXPR_POST_DEC: /* * Replace * e0++ e0-- * by * var = e0; var = e0; * e0 = e0 + 1; e0 = e0 - 1; * var var */ expr_simplify_in_expr(block, s, e->expr0); t0 = expr_typeof(block->scope, e->expr0); var = simplify_declaration_add(block->scope, t0, identifier_tmp()); e0 = expr_identifier(var); e1 = expr_dup(e->expr0); e2 = expr_assign(e0, e1); s0 = stmt_expr(e2); e0 = expr_dup(e->expr0); e1 = expr_dup(e->expr0); e2 = expr_integer(1); if (e->type == EXPR_POST_INC) { e3 = expr_add(e1, e2); } else { e3 = expr_sub(e1, e2); } e4 = expr_assign(e0, e3); s1 = stmt_expr(e4); e0 = expr_identifier(var); stmt_prepend(block, s, s0); stmt_prepend(block, s, s1); expr_cp(e, e0); expr_change = 1; break; case EXPR_ASSIGN: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: expr_simplify_in_expr(block, s, e->expr0); s0 = stmt_expr(expr_dup(e)); e0 = expr_dup(e->expr0); stmt_prepend(block, s, s0); expr_cp(e, e0); expr_change = 1; break; } } static void expr_simplify_in_stmt(struct stmt *block, struct stmt *s) { struct label *label0; struct label *label1; struct label *label2; struct type *t0; struct type *t1; struct type *t2; struct declaration *f; struct expr *ce; struct expr *e0; struct expr *e1; struct expr *e2; struct expr *e3; struct expr *e4; struct expr *e5; struct expr *e6; struct stmt *s0; struct stmt *s1; struct stmt *s2; struct stmt *s3; struct stmt *s4; struct stmt *s5; struct constraint *c; switch (s->type) { case STMT_NONE: assert(0); case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_BLOCK: case STMT_CASE: case STMT_DEFAULT: case STMT_CONTINUE: case STMT_BREAK: assert(0); case STMT_LABEL: case STMT_NULL: case STMT_GOTO: case STMT_VA_START: case STMT_VA_END: /* Nothing to do... */ break; case STMT_EXPR: switch (s->expr0->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: case EXPR_IDENTIFIER: case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: /* * Remove expression with no effect. */ stmt_replace_1_by_0(block, s); expr_change = 1; break; case EXPR_BUILTIN_VA_ARG: /* Already simple. */ break; case EXPR_TYPE_CONVERSION: case EXPR_STAR: case EXPR_AMPHERSAND: case EXPR_NEG: case EXPR_INV: case EXPR_NOT: case EXPR_DOT: case EXPR_ARROW: /* * Unary expressions. */ e0 = expr_dup(s->expr0->expr0); expr_cp(s->expr0, e0); expr_change = 1; break; case EXPR_LEFT: case EXPR_RIGHT: case EXPR_ADD: case EXPR_SUB: case EXPR_MUL: case EXPR_DIV: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_XOR: case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: case EXPR_ARRAY: /* * Binary expressions. */ e0 = expr_dup(s->expr0->expr0); s0 = stmt_expr(e0); e0 = expr_dup(s->expr0->expr1); stmt_prepend(block, s, s0); expr_cp(s->expr0, e0); expr_change = 1; break; case EXPR_SHORT_AND: /* * Replace * e0 && e1; * by * 0: if (! e0) goto l0; * 1: e1; * 2: l0: ; */ label0 = label_new(identifier_tmp()); e0 = expr_not(expr_dup(s->expr0->expr0)); s0 = stmt_if(e0, stmt_goto(label0), NULL); e0 = expr_dup(s->expr0->expr1); s1 = stmt_expr(e0); s2 = stmt_label(label0, stmt_null()); stmt_replace_1_by_3(block, s, s0, s1, s2); expr_change = 1; break; case EXPR_SHORT_OR: /* * Replace * e0 || e1; * by * 0: if (e0) goto l0; * 1: e1; * 2: l0: ; */ label0 = label_new(identifier_tmp()); e0 = expr_dup(s->expr0->expr0); s0 = stmt_if(e0, stmt_goto(label0), NULL); e0 = expr_dup(s->expr0->expr1); s1 = stmt_expr(e0); s2 = stmt_label(label0, stmt_null()); stmt_replace_1_by_3(block, s, s0, s1, s2); expr_change = 1; break; case EXPR_CONDITION: /* * Replace * e0 ? e1 : e2; * by * 0: if (e0) goto l0; * 1: e2; * 2: goto l1; * 3: l0: ; * 4: e1; * 5: l1: ; */ label0 = label_new(identifier_tmp()); label1 = label_new(identifier_tmp()); e0 = expr_dup(s->expr0->expr0); s0 = stmt_if(e0, stmt_goto(label0), NULL); e0 = expr_dup(s->expr0->expr2); s1 = stmt_expr(e0); s2 = stmt_goto(label1); s3 = stmt_label(label0, stmt_null()); e0 = expr_dup(s->expr0->expr1); s4 = stmt_expr(e0); s5 = stmt_label(label1, stmt_null()); stmt_replace_1_by_6(block, s, s0, s1, s2, s3, s4, s5); expr_change = 1; break; case EXPR_LIST: /* * Replace * e0, e1, ..., eN; * by * e0; * e1; * ... * eN; */ assert(s->expr0->first); while (s->expr0->first != s->expr0->last) { e0 = s->expr0->first; /* Remove first entry from list. */ s->expr0->first = e0->next; e0->next->prev = NULL; s0 = stmt_expr(e0); stmt_prepend(block, s, s0); } assert(s->expr0->first); assert(s->expr0->first == s->expr0->last); e0 = expr_dup(s->expr0->first); s0 = stmt_expr(e0); stmt_replace_1_by_1(block, s, s0); expr_change = 1; break; case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: expr_simplify_in_expr(block, s, s->expr0->expr0); e0 = expr_dup(s->expr0->expr0); e1 = expr_dup(s->expr0->expr0); e2 = expr_integer(1); if (s->expr0->type == EXPR_PRE_INC || s->expr0->type == EXPR_POST_INC) { e3 = expr_add(e1, e2); } else { e3 = expr_sub(e1, e2); } e4 = expr_assign(e0, e3); expr_cp(s->expr0, e4); expr_change = 1; break; case EXPR_ASSIGN: expr_simplify_in_expr(block, s, s->expr0->expr0); t0 = expr_typeof(block->scope, s->expr0->expr0); t1 = expr_typeof(block->scope, s->expr0->expr1); t1 = type_pure(t1); if (! type_equal(t0, t1)) { e0 = expr_dup(s->expr0->expr1); e1 = expr_cast(t0, e0); expr_cp(s->expr0->expr1, e1); expr_change = 1; } if (s->expr0->expr0->type != EXPR_IDENTIFIER || ! identifier_is_tmp(s->expr0->expr0->declaration->identifier)) { /* * Store operation. * RHS must be simple. */ expr_localize(block, s, s->expr0->expr1); break; } switch (s->expr0->expr1->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: case EXPR_BUILTIN_VA_ARG: case EXPR_IDENTIFIER: /* Already simple. */ break; case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_AMPHERSAND: case EXPR_SHORT_OR: case EXPR_SHORT_AND: case EXPR_CONDITION: case EXPR_LIST: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_ASSIGN: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: /* Special case. */ expr_simplify_in_expr(block, s, s->expr0->expr1); expr_localize(block, s, s->expr0->expr1); break; case EXPR_STAR: case EXPR_TYPE_CONVERSION: case EXPR_NOT: expr_simplify_in_expr(block, s, s->expr0->expr1->expr0); expr_localize(block, s, s->expr0->expr1->expr0); break; case EXPR_NEG: case EXPR_INV: /* Unary expression. */ t0 = expr_typeof(block->scope, s->expr0->expr1->expr0); t2 = type_arithmetic(t0, t0); if (! type_equal(t0, t2)) { e0 = expr_dup(s->expr0->expr1->expr0); e1 = expr_cast(t2, e0); expr_cp(s->expr0->expr1->expr0, e1); expr_change = 1; } expr_simplify_in_expr(block, s, s->expr0->expr1->expr0); expr_localize(block, s, s->expr0->expr1->expr0); break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: case EXPR_LEFT: case EXPR_RIGHT: case EXPR_ADD: case EXPR_SUB: case EXPR_MUL: case EXPR_DIV: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_XOR: t0 = expr_typeof(block->scope, s->expr0->expr1->expr0); t1 = expr_typeof(block->scope, s->expr0->expr1->expr1); if (s->expr0->expr1->type == EXPR_ADD && type_is_pointer(t0) && type_is_integer(t1)) { /* * Replace * x + y * by * (typeof x) ((int) x + y * sizeof(typeof *x)) */ if (type_is_array(t0)) { t0 = type_array_access(t0); t0 = type_amphersand(t0); } e0 = expr_dup(s->expr0->expr1->expr0); e1 = expr_cast(type_ptrdiff(), e0); e2 = expr_dup(s->expr0->expr1->expr1); e3 = expr_sizeof_type(type_star(t0)); e4 = expr_mul(e2, e3); e5 = expr_add(e1, e4); e6 = expr_cast(t0, e5); expr_cp(s->expr0->expr1, e6); expr_change = 1; } else if (s->expr0->expr1->type == EXPR_ADD && type_is_integer(t0) && type_is_pointer(t1)) { /* * Replace * x + y * by * (typeof y) ((int) y + x * sizeof(typeof *y)) */ if (type_is_array(t1)) { t1 = type_array_access(t1); t1 = type_amphersand(t1); } e0 = expr_dup(s->expr0->expr1->expr1); e1 = expr_cast(type_ptrdiff(), e0); e2 = expr_dup(s->expr0->expr1->expr0); e3 = expr_sizeof_type(type_star(t1)); e4 = expr_mul(e2, e3); e5 = expr_add(e1, e4); e6 = expr_cast(t1, e5); expr_cp(s->expr0->expr1, e6); expr_change = 1; } else if (s->expr0->expr1->type == EXPR_SUB && type_is_pointer(t0) && type_is_integer(t1)) { /* * Replace * x - y * by * (typeof x) ((int) x - y * sizeof(typeof *x)) */ if (type_is_array(t0)) { t0 = type_array_access(t0); t0 = type_amphersand(t0); } e0 = expr_dup(s->expr0->expr1->expr0); e1 = expr_cast(type_ptrdiff(), e0); e2 = expr_dup(s->expr0->expr1->expr1); e3 = expr_sizeof_type(type_star(t0)); e4 = expr_mul(e2, e3); e5 = expr_sub(e1, e4); e6 = expr_cast(t0, e5); expr_cp(s->expr0->expr1, e6); expr_change = 1; } else if (s->expr0->expr1->type == EXPR_SUB && type_is_pointer(t0) && type_is_pointer(t1)) { /* * Replace * x - y * by * ((int) x - (int) y) / sizeof(typeof *x)) */ if (type_is_array(t0)) { t0 = type_array_access(t0); t0 = type_amphersand(t0); } if (type_is_array(t1)) { t1 = type_array_access(t1); t1 = type_amphersand(t1); } e0 = expr_dup(s->expr0->expr1->expr0); e1 = expr_cast(type_ptrdiff(), e0); e2 = expr_dup(s->expr0->expr1->expr1); e3 = expr_cast(type_ptrdiff(), e2); e4 = expr_sub(e1, e3); e5 = expr_sizeof_type(type_star(t0)); e6 = expr_div(e4, e5); expr_cp(s->expr0->expr1, e6); expr_change = 1; } else { /* * Standard binary operation. */ t2 = type_arithmetic(t0, t1); if (! type_equal(t0, t2)) { e0 = expr_dup(s->expr0->expr1->expr0); e1 = expr_cast(t2, e0); expr_cp(s->expr0->expr1->expr0, e1); expr_change = 1; } if (! type_equal(t1, t2)) { e0 = expr_dup(s->expr0->expr1->expr1); e1 = expr_cast(t2, e0); expr_cp(s->expr0->expr1->expr1, e1); expr_change = 1; } /* Binary expression. */ expr_simplify_in_expr(block, s, s->expr0->expr1->expr0); expr_localize(block, s, s->expr0->expr1->expr0); expr_simplify_in_expr(block, s, s->expr0->expr1->expr1); expr_localize(block, s, s->expr0->expr1->expr1); } break; case EXPR_FUNC: t0 = expr_typeof(block->scope, s->expr0->expr1->expr0); assert(t0->type == TYPE_FUNCTION); expr_simplify_in_expr(block, s, s->expr0->expr1->expr0); /* expr_localize? FIXME */ ce = s->expr0->expr1->expr1->first; f = t0->parameter->declaration_first; for (;;) { if (ce && ! f) { assert(0); /* FIXME */ } if (! ce && f && f->type_name->type != TYPE_ELIPSIS) { assert(0); /* FIXME */ } if (! ce && ! f) { break; } if (! ce && f->type_name->type == TYPE_ELIPSIS) { break; } /* Formal Type */ if (f->type_name->type == TYPE_ELIPSIS) { t0 = expr_typeof(block->scope, ce); t0 = type_pure(t0); } else { t0 = f->type_name; t0 = type_pure(t0); } t0 = type_arithmetic(t0, t0); /* Actual Type */ t2 = expr_typeof(block->scope, ce); t2 = type_pure(t2); if (! type_equal(t0, t2)) { e0 = expr_dup(ce); e1 = expr_cast(t0, e0); expr_cp(ce, e1); expr_change = 1; } expr_simplify_in_expr(block, s, ce); expr_localize(block, s, ce); ce = ce->next; if (f->type_name->type != TYPE_ELIPSIS) { f = f->next; } } break; } break; case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: expr_simplify_in_expr(block, s, s->expr0->expr0); e0 = expr_dup(s->expr0->expr0); e1 = expr_dup(s->expr0->expr0); e2 = expr_dup(s->expr0->expr1); switch (s->expr0->type) { case EXPR_LEFT_ASSIGN: e3 = expr_left(e1, e2); break; case EXPR_RIGHT_ASSIGN: e3 = expr_right(e1, e2); break; case EXPR_ADD_ASSIGN: e3 = expr_add(e1, e2); break; case EXPR_SUB_ASSIGN: e3 = expr_sub(e1, e2); break; case EXPR_MUL_ASSIGN: e3 = expr_mul(e1, e2); break; case EXPR_DIV_ASSIGN: e3 = expr_div(e1, e2); break; case EXPR_MOD_ASSIGN: e3 = expr_mod(e1, e2); break; case EXPR_AND_ASSIGN: e3 = expr_and(e1, e2); break; case EXPR_OR_ASSIGN: e3 = expr_or(e1, e2); break; case EXPR_XOR_ASSIGN: e3 = expr_xor(e1, e2); break; default: assert(0); } e4 = expr_assign(e0, e3); expr_cp(s->expr0, e4); expr_change = 1; break; case EXPR_FUNC: t0 = expr_typeof(block->scope, s->expr0->expr0); assert(t0->type == TYPE_FUNCTION); expr_simplify_in_expr(block, s, s->expr0->expr0); /* expr_localize? FIXME */ ce = s->expr0->expr1->first; f = t0->parameter->declaration_first; for (;;) { if (ce && ! f) { assert(0); /* FIXME */ } if (! ce && f && f->type_name->type != TYPE_ELIPSIS) { assert(0); /* FIXME */ } if (! ce && ! f) { break; } if (! ce && f->type_name->type == TYPE_ELIPSIS) { break; } /* Formal Type */ if (f->type_name->type == TYPE_ELIPSIS) { t0 = expr_typeof(block->scope, ce); t0 = type_pure(t0); } else { t0 = f->type_name; t0 = type_pure(t0); } t0 = type_arithmetic(t0, t0); /* Actual Type */ t2 = expr_typeof(block->scope, ce); t2 = type_pure(t2); if (! type_equal(t0, t2)) { e0 = expr_dup(ce); e1 = expr_cast(t0, e0); expr_cp(ce, e1); expr_change = 1; } expr_simplify_in_expr(block, s, ce); expr_localize(block, s, ce); ce = ce->next; if (f->type_name->type != TYPE_ELIPSIS) { f = f->next; } } break; } break; case STMT_IF: switch (s->expr0->type) { case EXPR_NOT: switch (s->expr0->expr0->type) { case EXPR_NOT: /* * Replace * if (! ! e0) goto l0; * by * if (e0) goto l0; */ e0 = expr_dup(s->expr0->expr0->expr0); expr_cp(s->expr0, e0); expr_change = 1; break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: /* * Replace * if (! (e0 op e1)) goto l0; * by * if (e0 !op e1) goto l0; */ /* Correct only for integer/pointer! */ /* FIXME */ e0 = expr_dup(s->expr0->expr0->expr0); e1 = expr_dup(s->expr0->expr0->expr1); switch (s->expr0->expr0->type) { case EXPR_EQUAL: e2 = expr_not_equal(e0, e1); break; case EXPR_NOT_EQUAL: e2 = expr_equal(e0, e1); break; case EXPR_LESS: e2 = expr_greater_equal(e0, e1); break; case EXPR_LESS_EQUAL: e2 = expr_greater(e0, e1); break; case EXPR_GREATER: e2 = expr_less_equal(e0, e1); break; case EXPR_GREATER_EQUAL: e2 = expr_less(e0, e1); break; default: assert(0); } expr_cp(s->expr0, e2); expr_change = 1; break; case EXPR_SHORT_AND: /* * Replace * if (! (e0 && e1)) goto l0; * by * 0: if (! e0) goto l0; * 1: if (! e1) goto l0; */ e0 = expr_not(expr_dup(s->expr0->expr0->expr0)); s0 = stmt_if(e0, stmt_goto(s->stmt0->label), NULL); e0 = expr_not(expr_dup(s->expr0->expr0->expr1)); s1 = stmt_if(e0, stmt_goto(s->stmt0->label), NULL); stmt_replace_1_by_2(block, s, s0, s1); expr_change = 1; break; case EXPR_SHORT_OR: /* * Replace * if (! (e0 || e1)) goto l0; * by * 0: if (e0) goto l1; * 1: if (! e1) goto l0; * 2: l1: ; */ label1 = label_new(identifier_tmp()); e0 = expr_dup(s->expr0->expr0->expr0); s0 = stmt_if(e0, stmt_goto(label1), NULL); e0 = expr_not(expr_dup(s->expr0->expr0->expr1)); s1 = stmt_if(e0, stmt_goto(s->stmt0->label), NULL); s2 = stmt_label(label1, stmt_null()); stmt_replace_1_by_3(block, s, s0, s1, s2); expr_change = 1; break; case EXPR_CONDITION: /* * Replace * if (! (e0 ? e1 : e2)) goto l0; * by * 0: if (e0) goto l1; * 1: if (! e2) goto l0; * 2: goto l2; * 3: l1: ; * 4: if (! e1) goto l0; * 5: l2: ; */ label1 = label_new(identifier_tmp()); label2 = label_new(identifier_tmp()); e0 = expr_dup(s->expr0->expr0->expr0); s0 = stmt_if(e0, stmt_goto(label1), NULL); e0 = expr_not(expr_dup(s->expr0->expr0->expr2)); s1 = stmt_if(e0, stmt_goto(s->stmt0->label), NULL); s2 = stmt_goto(label2); s3 = stmt_label(label1, stmt_null()); e0 = expr_not(expr_dup(s->expr0->expr0->expr1)); s4 = stmt_if(e0, stmt_goto(s->stmt0->label), NULL); s5 = stmt_label(label2, stmt_null()); stmt_replace_1_by_6(block, s, s0, s1, s2, s3, s4, s5); expr_change = 1; break; default: /* * Replace * if (! e) goto l0; * by * if (e == 0) goto l0; */ e0 = expr_equal(expr_dup(s->expr0->expr0), expr_integer(0)); expr_cp(s->expr0, e0); expr_change = 1; break; } break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: t0 = expr_typeof(block->scope, s->expr0->expr0); t0 = type_pure(t0); t1 = expr_typeof(block->scope, s->expr0->expr1); t1 = type_pure(t1); t2 = type_arithmetic(t0, t1); if (! type_equal(t0, t2)) { e0 = expr_dup(s->expr0->expr0); e1 = expr_cast(t2, e0); expr_cp(s->expr0->expr0, e1); expr_change = 1; } if (! type_equal(t1, t2)) { e0 = expr_dup(s->expr0->expr1); e1 = expr_cast(t2, e0); expr_cp(s->expr0->expr1, e1); expr_change = 1; } expr_simplify_in_expr(block, s, s->expr0->expr0); expr_localize(block, s, s->expr0->expr0); expr_simplify_in_expr(block, s, s->expr0->expr1); expr_localize(block, s, s->expr0->expr1); break; case EXPR_SHORT_AND: /* * Replace * if (e0 && e1) goto l0; * by * 0: if (! e0) goto l1; * 1: if (e1) goto l0; * 2: l1: ; */ label1 = label_new(identifier_tmp()); e0 = expr_not(expr_dup(s->expr0->expr0)); s0 = stmt_if(e0, stmt_goto(label1), NULL); e0 = expr_dup(s->expr0->expr1); s1 = stmt_if(e0, stmt_goto(s->stmt0->label), NULL); s2 = stmt_label(label1, stmt_null()); stmt_replace_1_by_3(block, s, s0, s1, s2); expr_change = 1; break; case EXPR_SHORT_OR: /* * Replace * if (e0 || e1) goto l0; * by * 0: if (e0) goto l0; * 1: if (e1) goto l0; */ e0 = expr_dup(s->expr0->expr0); s0 = stmt_if(e0, stmt_goto(s->stmt0->label), NULL); e0 = expr_dup(s->expr0->expr1); s1 = stmt_if(e0, stmt_goto(s->stmt0->label), NULL); stmt_replace_1_by_2(block, s, s0, s1); expr_change = 1; break; case EXPR_CONDITION: /* * Replace * if (e0 ? e1 : e2) goto l0; * by * 0: if (e0) goto l1; * 1: if (e2) goto l0; * 2: goto l2; * 3: l1: ; * 4: if (e1) goto l0; * 5: l2: ; */ label1 = label_new(identifier_tmp()); label2 = label_new(identifier_tmp()); e0 = expr_dup(s->expr0->expr0); s0 = stmt_if(e0, stmt_goto(label1), NULL); e0 = expr_dup(s->expr0->expr2); s1 = stmt_if(e0, stmt_goto(s->stmt0->label), NULL); s2 = stmt_goto(label2); s3 = stmt_label(label1, stmt_null()); e0 = expr_dup(s->expr0->expr1); s4 = stmt_if(e0, stmt_goto(s->stmt0->label), NULL); s5 = stmt_label(label2, stmt_null()); stmt_replace_1_by_6(block, s, s0, s1, s2, s3, s4, s5); expr_change = 1; break; default: /* * Replace * if (e) goto l0; * by * if (e != 0) goto l0; */ e0 = expr_not_equal(expr_dup(s->expr0), expr_integer(0)); expr_cp(s->expr0, e0); expr_change = 1; break; } break; case STMT_SWITCH: t0 = expr_typeof(block->scope, s->expr0); if (! type_equal(t0, type_int()) && ! type_equal(t0, type_unsigned_int())) { e0 = expr_dup(s->expr0); e1 = expr_cast(type_int(), e0); expr_cp(s->expr0, e1); expr_change = 1; } expr_simplify_in_expr(block, s, s->expr0); expr_localize(block, s, s->expr0); break; case STMT_RETURN: if (s->expr0) { expr_simplify_in_expr(block, s, s->expr0); expr_localize(block, s, s->expr0); } break; case STMT_ASM: if (s->output) { for (c = s->output->first; c; c = c->next) { expr_simplify_in_expr(block, s, c->expr); assert(c->expr->type == EXPR_IDENTIFIER || c->expr->type == EXPR_STAR); } } if (s->input) { for (c = s->input->first; c; c = c->next) { expr_simplify_in_expr(block, s, c->expr); expr_localize(block, s, c->expr); assert(c->expr->type == EXPR_INTEGER || c->expr->type == EXPR_REAL || c->expr->type == EXPR_STRING || c->expr->type == EXPR_AMPHERSAND || c->expr->type == EXPR_IDENTIFIER); } } break; default: assert(0); } } int expr_simplify(struct scope *s, struct declaration *dion) { struct stmt *cs; struct declaration *cd; expr_change = 0; if (dion->initializer) { expr_simplify_in_init(s, dion->initializer); } else if (dion->stmt) { assert(dion->stmt->type == STMT_BLOCK); for (cd = dion->stmt->scope->declaration_first; cd; cd = cd->next) { if (cd->initializer) { expr_simplify_in_init(dion->stmt->scope, cd->initializer); } } for (cs = dion->stmt->stmt_first; cs; ) { struct stmt *next; next = cs->next; expr_simplify_in_stmt(dion->stmt, cs); cs = next; } } return expr_change; } /* ------------------------------------------------------------------------- */ static void expr_stat_in_expr(struct expr *e) { struct expr *ce; switch (e->type) { case EXPR_IDENTIFIER: e->declaration->rcount++; break; case EXPR_AMPHERSAND: switch (e->expr0->type) { case EXPR_IDENTIFIER: e->expr0->declaration->acount++; break; case EXPR_STAR: expr_stat_in_expr(e->expr0); break; default: assert(0); } break; case EXPR_FUNC: expr_stat_in_expr(e->expr0); for (ce = e->expr1->first; ce; ce = ce->next) { expr_stat_in_expr(ce); } break; default: if (e->expr0) { expr_stat_in_expr(e->expr0); } if (e->expr1) { expr_stat_in_expr(e->expr1); } assert(! e->expr2); } } static void expr_stat_in_func(struct stmt *fs) { struct stmt *cs; struct expr *ce; struct constraint *c; for (cs = fs->stmt_first; cs; cs = cs->next) { switch (cs->type) { case STMT_NONE: assert(0); case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_CONTINUE: case STMT_BREAK: case STMT_BLOCK: /* Should have been replaced by stmt_simplify. */ assert(0); case STMT_NULL: case STMT_LABEL: case STMT_GOTO: break; case STMT_EXPR: switch (cs->expr0->type) { case EXPR_ASSIGN: if (cs->expr0->expr0->type == EXPR_IDENTIFIER) { cs->expr0->expr0->declaration->assign_expr = cs->expr0->expr1; cs->expr0->expr0->declaration->wcount++; } else if (cs->expr0->expr0->type == EXPR_STAR) { expr_stat_in_expr(cs->expr0->expr0); } expr_stat_in_expr(cs->expr0->expr1); break; case EXPR_FUNC: expr_stat_in_expr(cs->expr0->expr0); for (ce = cs->expr0->expr1->first; ce; ce = ce->next) { expr_stat_in_expr(ce); } break; default: /* Expression not used. */ expr_stat_in_expr(cs->expr0); break; } break; case STMT_IF: case STMT_SWITCH: expr_stat_in_expr(cs->expr0); break; case STMT_RETURN: if (cs->expr0) { expr_stat_in_expr(cs->expr0); } break; case STMT_VA_START: case STMT_VA_END: /* FIXME */ break; case STMT_ASM: if (cs->output) { for (c = cs->output->first; c; c = c->next) { if (c->expr->type == EXPR_IDENTIFIER) { c->expr->declaration->wcount++; c->expr->declaration->rcount++; } } } if (cs->input) { for (c = cs->input->first; c; c = c->next) { expr_stat_in_expr(c->expr); } } break; default: assert(0); } } } static int expr_ssa_check(struct scope *scope, struct expr *e) { switch (e->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_LIST: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_ASSIGN: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: assert(0); case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: return 1; case EXPR_AMPHERSAND: assert(e->expr0->type == EXPR_IDENTIFIER); return 1; case EXPR_IDENTIFIER: if (e->declaration->storage != STORAGE_PARAM && e->declaration->storage != STORAGE_AUTO && e->declaration->storage != STORAGE_REGISTER) { /* Not local. */ return 0; } if (2 <= e->declaration->wcount) { /* Many writes exists. */ return 0; } if (1 <= e->declaration->acount) { /* Alias exists. */ return 0; } return 1; case EXPR_STAR: case EXPR_TYPE_CONVERSION: case EXPR_NEG: case EXPR_INV: case EXPR_NOT: return expr_ssa_check(scope, e->expr0); case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_LESS_EQUAL: case EXPR_GREATER: case EXPR_GREATER_EQUAL: case EXPR_LEFT: case EXPR_RIGHT: case EXPR_ADD: case EXPR_SUB: case EXPR_MUL: case EXPR_DIV: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_XOR: return expr_ssa_check(scope, e->expr0) && expr_ssa_check(scope, e->expr0); case EXPR_BUILTIN_VA_ARG: case EXPR_FUNC: return 0; } assert(0); return 0; } static void expr_ssa(struct stmt *fs) { struct declaration *dion; struct declaration *next; /* * Initialize counters. */ for (dion = fs->scope->function->type_name->parameter->declaration_first; dion; dion = dion->next) { assert(dion->storage == STORAGE_PARAM); dion->assign_expr = NULL; dion->acount = 0; dion->wcount = 1; /* Set by caller. */ dion->rcount = 0; } for (dion = fs->scope->declaration_first; dion; dion = dion->next) { if (dion->storage == STORAGE_TYPEDEF || ! dion->identifier) { continue; } if (dion->storage == STORAGE_NONE) { dion->storage = STORAGE_AUTO; } dion->assign_expr = NULL; dion->acount = 0; dion->wcount = 0; dion->rcount = 0; } /* * Do counting. */ expr_stat_in_func(fs); for (dion = fs->scope->function->type_name->parameter->declaration_first; dion; dion = dion->next) { dion->assign_expr = NULL; } for (dion = fs->scope->declaration_first; dion; dion = dion->next) { if (dion->storage == STORAGE_TYPEDEF || ! dion->identifier) { continue; } #if 0 fprintf(stderr, "ssa: %s: %d %d %d\n", dion->identifier, dion->acount, dion->wcount, dion->rcount); #endif if (1 <= dion->acount || 2 <= dion->wcount || ! dion->assign_expr || ! expr_ssa_check(fs->scope, dion->assign_expr)) { dion->assign_expr = NULL; } } /* * Remove variables not used. */ for (dion = fs->scope->declaration_first; dion; dion = next) { next = dion->next; if (dion->storage == STORAGE_TYPEDEF || ! dion->identifier) { continue; } if (dion->acount == 0 && dion->wcount == 0 && dion->rcount == 0) { /* Variable not used. */ if (dion->prev) { dion->prev->next = dion->next; } else { fs->scope->declaration_first = dion->next; } if (dion->next) { dion->next->prev = dion->prev; } else { fs->scope->declaration_last = dion->prev; } /* Free declaration. */ /* FIXME */ } } } static struct expr * simplify_expr_lookup(struct scope *scope, struct expr *e) { assert(e->type == EXPR_IDENTIFIER); if (e->declaration->storage != STORAGE_PARAM && e->declaration->storage != STORAGE_AUTO && e->declaration->storage != STORAGE_REGISTER) { return NULL; } else { return e->declaration->assign_expr; } } static void expr_optimize_in_expr(struct scope *scope, struct expr *e) { struct expr *ce; struct expr *ce0; struct expr *ce1; struct expr *e0; struct expr *e1; struct expr *e2; struct type *ts0; struct type *ts1; struct type *ts2; unsigned long long val; long double fval; if (e->expr0) { expr_optimize_in_expr(scope, e->expr0); } if (e->expr1) { if (e->type == EXPR_FUNC) { for (ce = e->first; ce; ce = ce->next) { expr_optimize_in_expr(scope, ce); } } else { expr_optimize_in_expr(scope, e->expr1); } } assert(! e->expr2); if (e->type == EXPR_BRACES) { for (ce = e->first; ce; ce = ce->next) { expr_optimize_in_expr(scope, ce); } } switch (e->type) { case EXPR_NONE: assert(0); case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_LIST: /* Should have been replaced by expr_simplify. */ assert(0); case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: case EXPR_BUILTIN_VA_ARG: /* Already simple. */ break; case EXPR_IDENTIFIER: ce0 = simplify_expr_lookup(scope, e); if (ce0) { switch (ce0->type) { case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: case EXPR_IDENTIFIER: /* Use constant/var instead of var. */ expr_cp(e, expr_dup(ce0)); expr_change = 1; break; default: break; } } break; case EXPR_TYPE_CONVERSION: switch (e->expr0->type) { case EXPR_INTEGER: switch (e->type_name->type) { case TYPE_NONE: case TYPE_ENUM: case TYPE_MAX: assert(0); case TYPE_VOID: assert(0); case TYPE_INT8: case TYPE_INT16: case TYPE_INT32: case TYPE_INT64: switch (e->expr0->type_name->type) { case TYPE_INT8: val = (int64_t) (int8_t) e->expr0->integer; break; case TYPE_INT16: val = (int64_t) (int16_t) e->expr0->integer; break; case TYPE_INT32: val = (int64_t) (int32_t) e->expr0->integer; break; case TYPE_INT64: val = (int64_t) (int64_t) e->expr0->integer; break; case TYPE_UINT8: val = (int64_t) (uint8_t) e->expr0->integer; break; case TYPE_UINT16: val = (int64_t) (uint16_t) e->expr0->integer; break; case TYPE_UINT32: val = (int64_t) (uint32_t) e->expr0->integer; break; case TYPE_UINT64: val = (int64_t) (uint64_t) e->expr0->integer; break; default: assert(0); } e0 = expr_new(); e0->type = EXPR_INTEGER; e0->integer = val; e0->type_name = e->type_name; expr_cp(e, e0); expr_change = 1; break; case TYPE_UINT8: case TYPE_UINT16: case TYPE_UINT32: case TYPE_UINT64: switch (e->expr0->type_name->type) { case TYPE_INT8: val = (uint64_t) (int8_t) e->expr0->integer; break; case TYPE_INT16: val = (uint64_t) (int16_t) e->expr0->integer; break; case TYPE_INT32: val = (uint64_t) (int32_t) e->expr0->integer; break; case TYPE_INT64: val = (uint64_t) (int64_t) e->expr0->integer; break; case TYPE_UINT8: val = (uint64_t) (uint8_t) e->expr0->integer; break; case TYPE_UINT16: val = (uint64_t) (uint16_t) e->expr0->integer; break; case TYPE_UINT32: val = (uint64_t) (uint32_t) e->expr0->integer; break; case TYPE_UINT64: val = (uint64_t) (uint64_t) e->expr0->integer; break; default: assert(0); } e0 = expr_new(); e0->type = EXPR_INTEGER; e0->integer = val; e0->type_name = e->type_name; expr_cp(e, e0); expr_change = 1; break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: switch (e->expr0->type_name->type) { case TYPE_INT8: fval = (long double) (int8_t) e->expr0->integer; break; case TYPE_INT16: fval = (long double) (int16_t) e->expr0->integer; break; case TYPE_INT32: fval = (long double) (int32_t) e->expr0->integer; break; case TYPE_INT64: fval = (long double) (int64_t) e->expr0->integer; break; case TYPE_UINT8: fval = (long double) (uint8_t) e->expr0->integer; break; case TYPE_UINT16: fval = (long double) (uint16_t) e->expr0->integer; break; case TYPE_UINT32: fval = (long double) (uint32_t) e->expr0->integer; break; case TYPE_UINT64: fval = (long double) (long double) e->expr0->integer; break; default: assert(0); } e0 = expr_new(); e0->type = EXPR_REAL; e0->real = fval; e0->type_name = e->type_name; expr_cp(e, e0); expr_change = 1; break; case TYPE_VA_LIST: case TYPE_POINTER: break; default: assert(0); } break; case EXPR_REAL: switch (e->type_name->type) { case TYPE_INT8: case TYPE_UINT8: case TYPE_INT16: case TYPE_UINT16: case TYPE_INT32: case TYPE_UINT32: case TYPE_INT64: case TYPE_UINT64: e0 = expr_new(); e0->type = EXPR_INTEGER; e0->integer = (int64_t) e->real; e0->type_name = e->type_name; expr_cp(e, e0); expr_change = 1; break; case TYPE_FLOAT32: case TYPE_FLOAT64: case TYPE_FLOAT80: switch (e->expr0->type_name->type) { case TYPE_FLOAT32: fval = (long double) (float) e->expr0->real; break; case TYPE_FLOAT64: fval = (long double) (double) e->expr0->real; break; case TYPE_FLOAT80: fval = (long double) (long double) e->expr0->real; break; default: assert(0); } e0 = expr_new(); e0->type = EXPR_REAL; e0->real = fval; e0->type_name = e->type_name; expr_cp(e, e0); expr_change = 1; break; default: assert(0); } break; case EXPR_STRING: /* FIXME */ break; case EXPR_TYPE_CONVERSION: ts0 = e->type_name; ts1 = e->expr0->type_name; ts2 = expr_typeof(scope, e->expr0->expr0); if (type_is_pointer(ts0) && type_is_ptrdiff(ts1) && type_is_pointer(ts2)) { /* * Replace * (type *) (ptrdiff_t) &e0 * by * (type *) &e0 */ goto type_conversion_replace; } else if (type_equal(ts0, ts1)) { /* * Replace * (type) (type) e0 * by * (type) e0 */ goto type_conversion_replace; } else if (type_is_pointer(ts0) && type_is_pointer(ts1)) { /* * Replace * (type0 *) (type1 *) e0 * by * (type0 *) e0 */ goto type_conversion_replace; } else if (type_is_ptrdiff(ts0) && type_is_pointer(ts1)) { /* * Replace * (ptrdiff_t) (type1 *) e0 * by * (ptrdiff_t) e0 */ type_conversion_replace:; e0 = expr_dup(e->expr0->expr0); expr_cp(e->expr0, e0); expr_change = 1; } break; default: ts0 = e->type_name; ts1 = expr_typeof(scope, e->expr0); if (type_equal(ts0, ts1)) { /* * Replace * (type) e0 * by * e0 */ e0 = expr_dup(e->expr0); expr_cp(e, e0); expr_change = 1; } break; } break; case EXPR_STAR: assert(e->expr0->type == EXPR_IDENTIFIER || (e->expr0->type == EXPR_TYPE_CONVERSION && e->expr0->expr0->type == EXPR_IDENTIFIER) || (e->expr0->type == EXPR_TYPE_CONVERSION && e->expr0->expr0->type == EXPR_INTEGER)); /* Nothing to optimize. */ break; case EXPR_AMPHERSAND: switch (e->expr0->type) { case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: /* Should have been replaced by expr_simplify. */ assert(0); case EXPR_IDENTIFIER: /* Is already simple. */ break; case EXPR_STAR: /* * Replace * &*e0 * by * e0 */ e0 = expr_dup(e->expr0->expr0); expr_cp(e, e0); expr_change = 1; break; default: assert(0); } break; case EXPR_NEG: switch (e->expr0->type) { case EXPR_INTEGER: /* * Replace * -num * by * num */ e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = e->expr0->type_name; e0->integer = -e->expr0->integer; expr_cp(e, e0); expr_change = 1; break; case EXPR_REAL: /* * Replace * -num * by * num */ e0 = expr_new(); e0->type = EXPR_REAL; e0->type_name = e->expr0->type_name; e0->real = -e->expr0->real; expr_cp(e, e0); expr_change = 1; break; case EXPR_SUB: /* * Replace * -(e0 - e1) * by * e1 - e0 */ e0 = expr_dup(e->expr0->expr0); e1 = expr_dup(e->expr0->expr1); e2 = expr_sub(e1, e0); expr_cp(e, e2); expr_change = 1; break; default: /* Cannot simplify. */ break; } break; case EXPR_INV: if (e->expr0->type == EXPR_INTEGER) { /* * Replace * ~num * by * num */ e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = e->expr0->type_name; e0->integer = ~ e->expr0->integer; expr_cp(e, e0); expr_change = 1; } break; case EXPR_NOT: switch (e->expr0->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_ASSIGN: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_LIST: /* Should have been simplified by op_assigns. */ assert(0); case EXPR_INTEGER: /* * Replace * ! num * by * num */ e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = type_int(); e0->integer = ! e->expr0->integer; expr_cp(e, e0); expr_change = 1; break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_GREATER: case EXPR_LESS_EQUAL: case EXPR_GREATER_EQUAL: ts0 = expr_typeof(scope, e->expr0->expr0); ts1 = expr_typeof(scope, e->expr0->expr1); if (((TYPE_INT8 <= ts0->type && ts0->type <= TYPE_UINT64) || type_is_pointer(ts0)) && ((TYPE_INT8 <= ts1->type && ts1->type <= TYPE_UINT64) || type_is_pointer(ts1))) { /* * Replace * ! (e0 == e1) ! (e0 < e1) ... * by * e0 != e1 e0 >= e1 ... */ e0 = expr_dup(e->expr0->expr0); e1 = expr_dup(e->expr0->expr1); e2 = expr_new(); switch (e->expr0->type) { case EXPR_EQUAL: e2->type = EXPR_NOT_EQUAL; break; case EXPR_NOT_EQUAL: e2->type = EXPR_EQUAL; break; case EXPR_LESS: e2->type = EXPR_GREATER_EQUAL; break; case EXPR_GREATER: e2->type = EXPR_LESS_EQUAL; break; case EXPR_LESS_EQUAL: e2->type = EXPR_GREATER; break; case EXPR_GREATER_EQUAL: e2->type = EXPR_LESS; break; default: assert(0); } e2->expr0 = e0; e2->expr1 = e1; expr_cp(e, e2); expr_change = 1; } break; default: /* * Replace * ! e0 * by * e0 == 0 */ e0 = expr_dup(e->expr0); e1 = expr_integer(0); e2 = expr_new(); e2->type = EXPR_EQUAL; e2->expr0 = e0; e2->expr1 = e1; expr_cp(e, e2); expr_change = 1; break; } break; case EXPR_LEFT: case EXPR_RIGHT: if (e->expr0->type == EXPR_INTEGER && e->expr1->type == EXPR_INTEGER) { e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = e->expr0->type_name; switch (e->type) { case EXPR_LEFT: val = e->expr0->integer << e->expr1->integer; break; case EXPR_RIGHT: val = e->expr0->integer >> e->expr1->integer; break; default: assert(0); } e0->integer = val; expr_cp(e, e0); expr_change = 1; } break; case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_GREATER: case EXPR_LESS_EQUAL: case EXPR_GREATER_EQUAL: if (e->expr0->type == EXPR_INTEGER && e->expr1->type == EXPR_INTEGER) { e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = type_int(); switch (e->type) { case EXPR_EQUAL: val = e->expr0->integer == e->expr1->integer; break; case EXPR_NOT_EQUAL: val = e->expr0->integer != e->expr1->integer; break; case EXPR_LESS: val = e->expr0->integer < e->expr1->integer; break; case EXPR_GREATER: val = e->expr0->integer > e->expr1->integer; break; case EXPR_LESS_EQUAL: val = e->expr0->integer <= e->expr1->integer; break; case EXPR_GREATER_EQUAL: val = e->expr0->integer >= e->expr1->integer; break; default: assert(0); } e0->integer = val; expr_cp(e, e0); expr_change = 1; } break; case EXPR_ADD: if (e->expr0->type == EXPR_INTEGER && e->expr1->type == EXPR_INTEGER) { /* * Replace * num + num * by * num */ e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = type_arithmetic(e->expr0->type_name, e->expr1->type_name); e0->integer = e->expr0->integer + e->expr1->integer; expr_cp(e, e0); expr_change = 1; } else if (e->expr0->type == EXPR_REAL && e->expr1->type == EXPR_REAL) { /* * Replace * num + num * by * num */ e0 = expr_new(); e0->type = EXPR_REAL; e0->type_name = type_arithmetic(e->expr0->type_name, e->expr1->type_name); e0->real = e->expr0->real + e->expr1->real; expr_cp(e, e0); expr_change = 1; } else if ((e->expr0->type == EXPR_INTEGER && e->expr0->integer == 0) || (e->expr0->type == EXPR_REAL && e->expr0->real == 0.0)) { /* * Replace * 0 + e0 * by * e0 */ expr_cp(e, expr_dup(e->expr1)); expr_change = 1; } else if ((e->expr1->type == EXPR_INTEGER && e->expr1->integer == 0) || (e->expr1->type == EXPR_REAL && e->expr1->real == 0.0)) { /* * Replace * e0 + 0 * by * e0 */ expr_cp(e, expr_dup(e->expr0)); expr_change = 1; } else if (e->expr0->type == EXPR_ADD && (e->expr0->expr1->type == EXPR_INTEGER || e->expr0->expr1->type == EXPR_REAL) && (e->expr1->type == EXPR_INTEGER || e->expr1->type == EXPR_REAL)) { /* * Replace * (e0 + c0) + c1 * by * e0 + (c0 + c1) */ expr_cp(e, expr_add( expr_dup(e->expr0->expr0), expr_add( expr_dup(e->expr0->expr1), expr_dup(e->expr1)))); expr_change = 1; } break; case EXPR_SUB: if (e->expr0->type == EXPR_INTEGER && e->expr1->type == EXPR_INTEGER) { /* * Replace * num - num * by * num */ e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = type_arithmetic(e->expr0->type_name, e->expr1->type_name); e0->integer = e->expr0->integer - e->expr1->integer; expr_cp(e, e0); expr_change = 1; } else if (e->expr0->type == EXPR_REAL && e->expr1->type == EXPR_REAL) { /* * Replace * num - num * by * num */ e0 = expr_new(); e0->type = EXPR_REAL; e0->type_name = type_arithmetic(e->expr0->type_name, e->expr1->type_name); e0->real = e->expr0->real - e->expr1->real; expr_cp(e, e0); expr_change = 1; } else if ((e->expr0->type == EXPR_INTEGER && e->expr0->integer == 0) || (e->expr0->type == EXPR_REAL && e->expr0->real == 0.0)) { /* * Replace * 0 - e0 * by * -e0 */ e0 = expr_dup(e->expr1); e1 = expr_new(); e1->type = EXPR_NEG; e1->expr0 = e0; expr_cp(e, e1); expr_change = 1; } else if ((e->expr1->type == EXPR_INTEGER && e->expr1->integer == 0) || (e->expr1->type == EXPR_REAL && e->expr1->real == 0.0)) { /* * Replace * e0 - 0 * by * e0 */ expr_cp(e, expr_dup(e->expr0)); expr_change = 1; } break; case EXPR_MUL: if (e->expr0->type == EXPR_INTEGER && e->expr1->type == EXPR_INTEGER) { /* * Replace * num * num * by * num */ e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = type_arithmetic(e->expr0->type_name, e->expr1->type_name); e0->integer = e->expr0->integer * e->expr1->integer; expr_cp(e, e0); expr_change = 1; } else if ((e->expr0->type == EXPR_INTEGER && e->expr0->integer == 1) || (e->expr0->type == EXPR_REAL && e->expr0->real == 1.0)) { /* * Replace * 1 * e1 * by * e1 */ expr_cp(e, expr_dup(e->expr1)); expr_change = 1; } else if (e->expr0->type == EXPR_INTEGER && (e->expr0->integer == (1ULL << 1) || e->expr0->integer == (1ULL << 2) || e->expr0->integer == (1ULL << 3) || e->expr0->integer == (1ULL << 4) || e->expr0->integer == (1ULL << 5) || e->expr0->integer == (1ULL << 6) || e->expr0->integer == (1ULL << 7) || e->expr0->integer == (1ULL << 8) || e->expr0->integer == (1ULL << 9) || e->expr0->integer == (1ULL << 10) || e->expr0->integer == (1ULL << 11) || e->expr0->integer == (1ULL << 12) || e->expr0->integer == (1ULL << 13) || e->expr0->integer == (1ULL << 14) || e->expr0->integer == (1ULL << 15) || e->expr0->integer == (1ULL << 16) || e->expr0->integer == (1ULL << 17) || e->expr0->integer == (1ULL << 18) || e->expr0->integer == (1ULL << 19) || e->expr0->integer == (1ULL << 20) || e->expr0->integer == (1ULL << 21) || e->expr0->integer == (1ULL << 22) || e->expr0->integer == (1ULL << 23) || e->expr0->integer == (1ULL << 24) || e->expr0->integer == (1ULL << 25) || e->expr0->integer == (1ULL << 26) || e->expr0->integer == (1ULL << 27) || e->expr0->integer == (1ULL << 28) || e->expr0->integer == (1ULL << 29) || e->expr0->integer == (1ULL << 30) || e->expr0->integer == (1ULL << 31) || e->expr0->integer == (1ULL << 32) || e->expr0->integer == (1ULL << 33) || e->expr0->integer == (1ULL << 34) || e->expr0->integer == (1ULL << 35) || e->expr0->integer == (1ULL << 36) || e->expr0->integer == (1ULL << 37) || e->expr0->integer == (1ULL << 38) || e->expr0->integer == (1ULL << 39) || e->expr0->integer == (1ULL << 40) || e->expr0->integer == (1ULL << 41) || e->expr0->integer == (1ULL << 42) || e->expr0->integer == (1ULL << 43) || e->expr0->integer == (1ULL << 44) || e->expr0->integer == (1ULL << 45) || e->expr0->integer == (1ULL << 46) || e->expr0->integer == (1ULL << 47) || e->expr0->integer == (1ULL << 48) || e->expr0->integer == (1ULL << 49) || e->expr0->integer == (1ULL << 50) || e->expr0->integer == (1ULL << 51) || e->expr0->integer == (1ULL << 52) || e->expr0->integer == (1ULL << 53) || e->expr0->integer == (1ULL << 54) || e->expr0->integer == (1ULL << 55) || e->expr0->integer == (1ULL << 56) || e->expr0->integer == (1ULL << 57) || e->expr0->integer == (1ULL << 58) || e->expr0->integer == (1ULL << 59) || e->expr0->integer == (1ULL << 60) || e->expr0->integer == (1ULL << 61) || e->expr0->integer == (1ULL << 62) || e->expr0->integer == (1ULL << 63))) { /* * Replace * (1 << val) * e0 * by * e0 << val */ for (val = 0; ; val++) { assert(val < 64); if (e->expr0->integer == (1ULL << val)) { break; } } ce = e->expr0; e->expr0 = e->expr1; e->expr1 = ce; e->type = EXPR_LEFT; e->expr1->integer = val; } else if ((e->expr1->type == EXPR_INTEGER && e->expr1->integer == 1) || (e->expr1->type == EXPR_REAL && e->expr1->real == 1.0)) { /* * Replace * e0 * 1 * by * e0 */ expr_cp(e, expr_dup(e->expr0)); expr_change = 1; } else if (e->expr1->type == EXPR_INTEGER && (e->expr1->integer == (1ULL << 1) || e->expr1->integer == (1ULL << 2) || e->expr1->integer == (1ULL << 3) || e->expr1->integer == (1ULL << 4) || e->expr1->integer == (1ULL << 5) || e->expr1->integer == (1ULL << 6) || e->expr1->integer == (1ULL << 7) || e->expr1->integer == (1ULL << 8) || e->expr1->integer == (1ULL << 9) || e->expr1->integer == (1ULL << 10) || e->expr1->integer == (1ULL << 11) || e->expr1->integer == (1ULL << 12) || e->expr1->integer == (1ULL << 13) || e->expr1->integer == (1ULL << 14) || e->expr1->integer == (1ULL << 15) || e->expr1->integer == (1ULL << 16) || e->expr1->integer == (1ULL << 17) || e->expr1->integer == (1ULL << 18) || e->expr1->integer == (1ULL << 19) || e->expr1->integer == (1ULL << 20) || e->expr1->integer == (1ULL << 21) || e->expr1->integer == (1ULL << 22) || e->expr1->integer == (1ULL << 23) || e->expr1->integer == (1ULL << 24) || e->expr1->integer == (1ULL << 25) || e->expr1->integer == (1ULL << 26) || e->expr1->integer == (1ULL << 27) || e->expr1->integer == (1ULL << 28) || e->expr1->integer == (1ULL << 29) || e->expr1->integer == (1ULL << 30) || e->expr1->integer == (1ULL << 31) || e->expr1->integer == (1ULL << 32) || e->expr1->integer == (1ULL << 33) || e->expr1->integer == (1ULL << 34) || e->expr1->integer == (1ULL << 35) || e->expr1->integer == (1ULL << 36) || e->expr1->integer == (1ULL << 37) || e->expr1->integer == (1ULL << 38) || e->expr1->integer == (1ULL << 39) || e->expr1->integer == (1ULL << 40) || e->expr1->integer == (1ULL << 41) || e->expr1->integer == (1ULL << 42) || e->expr1->integer == (1ULL << 43) || e->expr1->integer == (1ULL << 44) || e->expr1->integer == (1ULL << 45) || e->expr1->integer == (1ULL << 46) || e->expr1->integer == (1ULL << 47) || e->expr1->integer == (1ULL << 48) || e->expr1->integer == (1ULL << 49) || e->expr1->integer == (1ULL << 50) || e->expr1->integer == (1ULL << 51) || e->expr1->integer == (1ULL << 52) || e->expr1->integer == (1ULL << 53) || e->expr1->integer == (1ULL << 54) || e->expr1->integer == (1ULL << 55) || e->expr1->integer == (1ULL << 56) || e->expr1->integer == (1ULL << 57) || e->expr1->integer == (1ULL << 58) || e->expr1->integer == (1ULL << 59) || e->expr1->integer == (1ULL << 60) || e->expr1->integer == (1ULL << 61) || e->expr1->integer == (1ULL << 62) || e->expr1->integer == (1ULL << 63))) { /* * Replace * e1 * (1 << val) * by * e1 << val */ for (val = 0; ; val++) { assert(val < 64); if (e->expr1->integer == (1ULL << val)) { break; } } e->type = EXPR_LEFT; e->expr1->integer = val; } break; case EXPR_DIV: if (e->expr0->type == EXPR_INTEGER && e->expr1->type == EXPR_INTEGER) { /* * Replace * num / num * by * num */ assert(e->expr1->integer != 0); e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = type_arithmetic(e->expr0->type_name, e->expr1->type_name); e0->integer = e->expr0->integer / e->expr1->integer; expr_cp(e, e0); expr_change = 1; } else if ((e->expr1->type == EXPR_INTEGER && e->expr1->integer == 1) || (e->expr1->type == EXPR_REAL && e->expr1->real == 1.0)) { /* * Replace * e1 / 1 * by * e1 */ expr_cp(e, expr_dup(e->expr0)); expr_change = 1; } else if (e->expr1->type == EXPR_INTEGER && (e->expr1->integer == (1ULL << 1) || e->expr1->integer == (1ULL << 2) || e->expr1->integer == (1ULL << 3) || e->expr1->integer == (1ULL << 4) || e->expr1->integer == (1ULL << 5) || e->expr1->integer == (1ULL << 6) || e->expr1->integer == (1ULL << 7) || e->expr1->integer == (1ULL << 8) || e->expr1->integer == (1ULL << 9) || e->expr1->integer == (1ULL << 10) || e->expr1->integer == (1ULL << 11) || e->expr1->integer == (1ULL << 12) || e->expr1->integer == (1ULL << 13) || e->expr1->integer == (1ULL << 14) || e->expr1->integer == (1ULL << 15) || e->expr1->integer == (1ULL << 16) || e->expr1->integer == (1ULL << 17) || e->expr1->integer == (1ULL << 18) || e->expr1->integer == (1ULL << 19) || e->expr1->integer == (1ULL << 20) || e->expr1->integer == (1ULL << 21) || e->expr1->integer == (1ULL << 22) || e->expr1->integer == (1ULL << 23) || e->expr1->integer == (1ULL << 24) || e->expr1->integer == (1ULL << 25) || e->expr1->integer == (1ULL << 26) || e->expr1->integer == (1ULL << 27) || e->expr1->integer == (1ULL << 28) || e->expr1->integer == (1ULL << 29) || e->expr1->integer == (1ULL << 30) || e->expr1->integer == (1ULL << 31) || e->expr1->integer == (1ULL << 32) || e->expr1->integer == (1ULL << 33) || e->expr1->integer == (1ULL << 34) || e->expr1->integer == (1ULL << 35) || e->expr1->integer == (1ULL << 36) || e->expr1->integer == (1ULL << 37) || e->expr1->integer == (1ULL << 38) || e->expr1->integer == (1ULL << 39) || e->expr1->integer == (1ULL << 40) || e->expr1->integer == (1ULL << 41) || e->expr1->integer == (1ULL << 42) || e->expr1->integer == (1ULL << 43) || e->expr1->integer == (1ULL << 44) || e->expr1->integer == (1ULL << 45) || e->expr1->integer == (1ULL << 46) || e->expr1->integer == (1ULL << 47) || e->expr1->integer == (1ULL << 48) || e->expr1->integer == (1ULL << 49) || e->expr1->integer == (1ULL << 50) || e->expr1->integer == (1ULL << 51) || e->expr1->integer == (1ULL << 52) || e->expr1->integer == (1ULL << 53) || e->expr1->integer == (1ULL << 54) || e->expr1->integer == (1ULL << 55) || e->expr1->integer == (1ULL << 56) || e->expr1->integer == (1ULL << 57) || e->expr1->integer == (1ULL << 58) || e->expr1->integer == (1ULL << 59) || e->expr1->integer == (1ULL << 60) || e->expr1->integer == (1ULL << 61) || e->expr1->integer == (1ULL << 62) || e->expr1->integer == (1ULL << 63))) { /* * Replace * e1 / (1 << val) * by * e1 >> val */ for (val = 0; ; val++) { assert(val < 64); if (e->expr1->integer == (1ULL << val)) { break; } } e->type = EXPR_RIGHT; e->expr1->integer = val; expr_change = 1; } break; case EXPR_MOD: if (e->expr0->type == EXPR_INTEGER && e->expr1->type == EXPR_INTEGER) { /* * Replace * num % num * by * num */ assert(e->expr1->integer != 0); e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = type_arithmetic(e->expr0->type_name, e->expr1->type_name); e0->integer = e->expr0->integer % e->expr1->integer; expr_cp(e, e0); expr_change = 1; } else if ((e->expr1->type == EXPR_INTEGER && e->expr1->integer == 1) || (e->expr1->type == EXPR_REAL && e->expr1->real == 1.0)) { /* * Replace * e1 % 1 * by * 0 */ e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = type_arithmetic(e->expr0->type_name, e->expr1->type_name); e0->integer = 0; expr_change = 1; } else if (e->expr1->type == EXPR_INTEGER && (e->expr1->integer == (1ULL << 1) || e->expr1->integer == (1ULL << 2) || e->expr1->integer == (1ULL << 3) || e->expr1->integer == (1ULL << 4) || e->expr1->integer == (1ULL << 5) || e->expr1->integer == (1ULL << 6) || e->expr1->integer == (1ULL << 7) || e->expr1->integer == (1ULL << 8) || e->expr1->integer == (1ULL << 9) || e->expr1->integer == (1ULL << 10) || e->expr1->integer == (1ULL << 11) || e->expr1->integer == (1ULL << 12) || e->expr1->integer == (1ULL << 13) || e->expr1->integer == (1ULL << 14) || e->expr1->integer == (1ULL << 15) || e->expr1->integer == (1ULL << 16) || e->expr1->integer == (1ULL << 17) || e->expr1->integer == (1ULL << 18) || e->expr1->integer == (1ULL << 19) || e->expr1->integer == (1ULL << 20) || e->expr1->integer == (1ULL << 21) || e->expr1->integer == (1ULL << 22) || e->expr1->integer == (1ULL << 23) || e->expr1->integer == (1ULL << 24) || e->expr1->integer == (1ULL << 25) || e->expr1->integer == (1ULL << 26) || e->expr1->integer == (1ULL << 27) || e->expr1->integer == (1ULL << 28) || e->expr1->integer == (1ULL << 29) || e->expr1->integer == (1ULL << 30) || e->expr1->integer == (1ULL << 31) || e->expr1->integer == (1ULL << 32) || e->expr1->integer == (1ULL << 33) || e->expr1->integer == (1ULL << 34) || e->expr1->integer == (1ULL << 35) || e->expr1->integer == (1ULL << 36) || e->expr1->integer == (1ULL << 37) || e->expr1->integer == (1ULL << 38) || e->expr1->integer == (1ULL << 39) || e->expr1->integer == (1ULL << 40) || e->expr1->integer == (1ULL << 41) || e->expr1->integer == (1ULL << 42) || e->expr1->integer == (1ULL << 43) || e->expr1->integer == (1ULL << 44) || e->expr1->integer == (1ULL << 45) || e->expr1->integer == (1ULL << 46) || e->expr1->integer == (1ULL << 47) || e->expr1->integer == (1ULL << 48) || e->expr1->integer == (1ULL << 49) || e->expr1->integer == (1ULL << 50) || e->expr1->integer == (1ULL << 51) || e->expr1->integer == (1ULL << 52) || e->expr1->integer == (1ULL << 53) || e->expr1->integer == (1ULL << 54) || e->expr1->integer == (1ULL << 55) || e->expr1->integer == (1ULL << 56) || e->expr1->integer == (1ULL << 57) || e->expr1->integer == (1ULL << 58) || e->expr1->integer == (1ULL << 59) || e->expr1->integer == (1ULL << 60) || e->expr1->integer == (1ULL << 61) || e->expr1->integer == (1ULL << 62) || e->expr1->integer == (1ULL << 63))) { /* * Replace * e0 % (1 << val) * by * e0 & (val - 1) */ for (val = 0; ; val++) { assert(val < 64); if (e->expr1->integer == (1ULL << val)) { break; } } e->type = EXPR_AND; e->expr1->integer = (1ULL << val) - 1; expr_change = 1; } break; case EXPR_AND: if (e->expr0->type == EXPR_INTEGER && e->expr1->type == EXPR_INTEGER) { /* * Replace * num & num * by * num */ e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = type_arithmetic(e->expr0->type_name, e->expr1->type_name); e0->integer = e->expr0->integer & e->expr1->integer; expr_cp(e, e0); expr_change = 1; } else if (e->expr0->type == EXPR_INTEGER && e->expr0->integer == 0xffffffff) { /* * Replace * -1 & e1 * by * e1 */ expr_cp(e, expr_dup(e->expr1)); expr_change = 1; } else if (e->expr1->type == EXPR_INTEGER && e->expr1->integer == 0xffffffff) { /* * Replace * e0 & -1 * by * e0 */ expr_cp(e, expr_dup(e->expr0)); expr_change = 1; } break; case EXPR_OR: case EXPR_XOR: if (e->expr0->type == EXPR_INTEGER && e->expr1->type == EXPR_INTEGER) { e0 = expr_new(); e0->type = EXPR_INTEGER; e0->type_name = type_arithmetic(e->expr0->type_name, e->expr1->type_name); switch (e->type) { case EXPR_OR: val = e->expr0->integer | e->expr1->integer; break; case EXPR_XOR: val = e->expr0->integer ^ e->expr1->integer; break; default: assert(0); } e0->integer = val; expr_cp(e, e0); expr_change = 1; } break; case EXPR_FUNC: /* expr_optimize_in_expr(scope, ce); Done above. */ for (ce = e->expr1->first; ce; ce = ce->next) { expr_optimize_in_expr(scope, ce); } break; case EXPR_ASSIGN: /* No simplification possible. */ break; case EXPR_BRACES: /* Simplification of elements done by loop above. */ break; } } static void expr_optimize_in_stmt(struct stmt *block, struct stmt *s) { struct expr *ce; struct constraint *c; struct declaration *dion; struct stmt *s0; struct stmt *s1; switch (s->type) { case STMT_NONE: assert(0); case STMT_CASE: case STMT_DEFAULT: case STMT_WHILE: case STMT_DO_WHILE: case STMT_FOR: case STMT_BREAK: case STMT_CONTINUE: case STMT_BLOCK: assert(0); case STMT_NULL: case STMT_LABEL: case STMT_GOTO: case STMT_VA_START: case STMT_VA_END: /* No expressions; nothing to optimize. */ break; case STMT_EXPR: switch (s->expr0->type) { case EXPR_NONE: assert(0); case EXPR_BRACES: assert(0); case EXPR_SIZEOF_TYPE: case EXPR_SIZEOF_EXPR: case EXPR_BUILTIN_CONSTANT_P: case EXPR_BUILTIN_OFFSETOF: case EXPR_DOT: case EXPR_ARROW: case EXPR_ARRAY: case EXPR_PRE_INC: case EXPR_PRE_DEC: case EXPR_POST_INC: case EXPR_POST_DEC: case EXPR_LEFT_ASSIGN: case EXPR_RIGHT_ASSIGN: case EXPR_ADD_ASSIGN: case EXPR_SUB_ASSIGN: case EXPR_MUL_ASSIGN: case EXPR_DIV_ASSIGN: case EXPR_MOD_ASSIGN: case EXPR_AND_ASSIGN: case EXPR_OR_ASSIGN: case EXPR_XOR_ASSIGN: case EXPR_SHORT_AND: case EXPR_SHORT_OR: case EXPR_CONDITION: case EXPR_LIST: /* Should have been removed by expr_simplify. */ assert(0); case EXPR_INTEGER: case EXPR_REAL: case EXPR_STRING: case EXPR_IDENTIFIER: case EXPR_AMPHERSAND: stmt_replace_1_by_0(block, s); expr_change = 1; break; case EXPR_TYPE_CONVERSION: case EXPR_STAR: case EXPR_NEG: case EXPR_INV: case EXPR_NOT: /* Unary expressions. */ s0 = stmt_expr(expr_dup(s->expr0->expr0)); stmt_replace_1_by_1(block, s, s0); expr_change = 1; break; case EXPR_LEFT: case EXPR_RIGHT: case EXPR_EQUAL: case EXPR_NOT_EQUAL: case EXPR_LESS: case EXPR_GREATER: case EXPR_LESS_EQUAL: case EXPR_GREATER_EQUAL: case EXPR_ADD: case EXPR_SUB: case EXPR_MUL: case EXPR_DIV: case EXPR_MOD: case EXPR_AND: case EXPR_OR: case EXPR_XOR: /* Binary expressions. */ s0 = stmt_expr(expr_dup(s->expr0->expr0)); s1 = stmt_expr(expr_dup(s->expr0->expr1)); stmt_replace_1_by_2(block, s, s0, s1); expr_change = 1; break; case EXPR_ASSIGN: switch (s->expr0->expr0->type) { case EXPR_IDENTIFIER: dion = s->expr0->expr0->declaration; if ((dion->storage == STORAGE_PARAM || dion->storage == STORAGE_AUTO || dion->storage == STORAGE_REGISTER) && dion->rcount == 0 && dion->acount == 0) { /* * Variable not used. * Remove LHS. */ expr_cp(s->expr0, expr_dup(s->expr0->expr1)); expr_change = 1; } else { /* * Optimize RHS. */ expr_optimize_in_expr(block->scope, s->expr0->expr1); } break; case EXPR_STAR: expr_optimize_in_expr(block->scope, s->expr0->expr0); expr_optimize_in_expr(block->scope, s->expr0->expr1); break; default: assert(0); } break; case EXPR_BUILTIN_VA_ARG: /* Must leave as is. */ break; case EXPR_FUNC: expr_optimize_in_expr(block->scope, s->expr0); for (ce = s->expr0->expr1->first; ce; ce = ce->next) { expr_optimize_in_expr(block->scope, ce); } break; } break; case STMT_IF: case STMT_SWITCH: expr_optimize_in_expr(block->scope, s->expr0); break; case STMT_RETURN: if (s->expr0) { expr_optimize_in_expr(block->scope, s->expr0); } break; case STMT_ASM: if (s->output) { for (c = s->output->first; c; c = c->next) { expr_optimize_in_expr(block->scope, c->expr); } } if (s->input) { for (c = s->input->first; c; c = c->next) { expr_optimize_in_expr(block->scope, c->expr); } } break; default: assert(0); } } int expr_optimize(struct scope *s, struct declaration *dion) { struct stmt *cs; struct declaration *cd; expr_change = 0; if (dion->initializer) { expr_optimize_in_expr(s, dion->initializer); } else if (dion->stmt) { assert(dion->stmt->type == STMT_BLOCK); for (cd = dion->stmt->scope->declaration_first; cd; cd = cd->next) { if (cd->initializer) { expr_optimize_in_expr(dion->stmt->scope, cd->initializer); } } expr_ssa(dion->stmt); for (cs = dion->stmt->stmt_first; cs; ) { struct stmt *next; next = cs->next; expr_optimize_in_stmt(dion->stmt, cs); cs = next; } } return expr_change; } faucc-20120707/configure.ac0000640002413100241000000000342611776113700015004 0ustar potyrai3guest# # $Id: configure.ac,v 1.7 2012-02-17 14:16:59 vrsieh Exp $ # # Copyright (C) 2008-2009 FAUcc Team. # This program is free software, GPL-2 (or any later version). See COPYING. # # Initialize automake. AC_INIT(faucc, 20120707) # don't spam / AC_CONFIG_AUX_DIR(scripts) AM_INIT_AUTOMAKE # Check for progs needed. AC_PROG_CC AC_PROG_RANLIB AC_PROG_LEX AC_PROG_YACC AC_CHECK_PROGS(XMLTO, xmlto) AC_CHECK_PROGS(CPPCHECK, cppcheck, false --) if test -z "$XMLTO"; then AC_MSG_ERROR([xmlto not found.]) fi # Compiler warnings (not needed but nice to have). # Compiler warnings go into $CC! AC_PROG_CC_OPTION(-Wchar-subscripts) AC_PROG_CC_OPTION(-Wcomment) AC_PROG_CC_OPTION(-Wformat) AC_PROG_CC_OPTION(-Wnonnull) AC_PROG_CC_OPTION(-Wimplicit-int) AC_PROG_CC_OPTION(-Wimplicit-function-declaration) AC_PROG_CC_OPTION(-Wimplicit) AC_PROG_CC_OPTION(-Wmain) AC_PROG_CC_OPTION(-Wmissing-braces) AC_PROG_CC_OPTION(-Wparentheses) AC_PROG_CC_OPTION(-Wsequence-point) AC_PROG_CC_OPTION(-Wreturn-type) AC_PROG_CC_OPTION(-Wswitch) AC_PROG_CC_OPTION(-Wtrigraphs) AC_PROG_CC_OPTION(-Wunused-function) AC_PROG_CC_OPTION(-Wunused-label) AC_PROG_CC_OPTION(-Wunused-variable) AC_PROG_CC_OPTION(-Wunused-value) AC_PROG_CC_OPTION(-Wuninitialized) AC_PROG_CC_OPTION(-Wunknown-pragmas) AC_PROG_CC_OPTION(-Wstrict-aliasing) AC_PROG_CC_OPTION(-Wundef) AC_PROG_CC_OPTION(-Wendif-labels) AC_PROG_CC_OPTION(-Wshadow) AC_PROG_CC_OPTION(-Wpointer-arith) AC_PROG_CC_OPTION(-Wcast-qual) AC_PROG_CC_OPTION(-Wcast-align) AC_PROG_CC_OPTION(-Wwrite-strings) AC_PROG_CC_OPTION(-Waggregate-return) AC_PROG_CC_OPTION(-Wstrict-prototypes) AC_PROG_CC_OPTION(-Wmissing-noreturn) AC_PROG_CC_OPTION(-Wnested-externs) # We want these Makefiles AC_CONFIG_FILES([\ Makefile libfaucc/Makefile docs/man/Makefile ]) # Finally create the Makefiles. AC_OUTPUT() faucc-20120707/constraint.c0000640002413100241000000000515711137625345015055 0ustar potyrai3guest/* $Id: constraint.c,v 1.8 2009-01-27 15:40:21 potyra Exp $ * * Copyright (C) 2007-2009 FAUcc Team . * This program is free software. You can redistribute it and/or modify it * under the terms of the GNU General Public License, either version 2 of * the License, or (at your option) any later version. See COPYING. */ #include #include #include #include #include "identifier.h" #include "constraint.h" #include "stmt.h" struct constraint * constraint_new(void) { struct constraint *c; c = malloc(sizeof *c); assert(c); memset(c, 0, sizeof *c); return c; } struct constraint * constraint_dup(struct constraint *oc) { struct constraint *nc; nc = constraint_new(); nc->string = identifier_dup(oc->string); nc->expr = expr_dup(oc->expr); return nc; } void constraint_free(struct constraint *c) { } struct constraint_list * constraint_list_new(void) { struct constraint_list *cl; cl = malloc(sizeof *cl); assert(cl); memset(cl, 0, sizeof *cl); return cl; } struct constraint_list * constraint_list_dup(struct constraint_list *ocl) { struct constraint_list *ncl; struct constraint *oc; struct constraint *nc; if (ocl == NULL) { return ocl; } ncl = constraint_list_new(); for (oc = ocl->first; oc; oc = oc->next) { nc = constraint_dup(oc); nc->prev = ncl->last; nc->next = NULL; if (nc->prev) { nc->prev->next = nc; } else { ncl->first = nc; } ncl->last = nc; } return ncl; } void constraint_list_free(struct constraint_list *cl) { } void constraint_list_append_last(struct constraint_list *cl, struct constraint *c) { c->prev = cl->last; c->next = NULL; if (c->prev) { c->prev->next = c; } else { cl->first = c; } cl->last = c; } void constraint_output(struct stmt *s, const char *string, struct expr *expr) { struct constraint *c; assert(*string == '=' || *string == '+'); if (! s->output) { s->output = constraint_list_new(); } c = constraint_new(); c->string = string; c->expr = expr; constraint_list_append_last(s->output, c); } void constraint_input(struct stmt *s, const char *string, struct expr *expr) { struct constraint *c; assert(*string != '=' && *string != '+'); if (! s->input) { s->input = constraint_list_new(); } c = constraint_new(); c->string = string; c->expr = expr; constraint_list_append_last(s->input, c); } void constraint_change(struct stmt *s, const char *string) { struct constraint *c; if (! s->change) { s->change = constraint_list_new(); } c = constraint_new(); c->string = string; c->expr = NULL; constraint_list_append_last(s->change, c); }