/* $Id: stmt.h,v 1.46 2009/01/27 15:40:22 potyra Exp $ 
 *
 * Copyright (C) 2007-2009 FAUcc Team <info@faumachine.org>.
 * 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 */
