Logo Search packages:      
Sourcecode: faucc version File versions

arch_i286_gen.c

/* $Id: arch_i286_gen.c,v 1.225 2009-01-27 15:40:21 potyra Exp $ 
 *
 * Copyright (C) 2008-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.
 */

#include "identifier.h"
#include "declaration.h"
#include "simplify.h"
#include "arch_i286_gen.h"
#include "cc1.h"

void
arch_i286_gen_variable(FILE *fp, struct scope * s, struct declaration *d);
void
arch_i286_gen_function_variables(FILE *fp, struct declaration *d, int *iVarsLen);
void
arch_i286_gen_function(FILE *fp, struct declaration *d);

struct declaration *fdion_div,*fdion_mod,*fdion_mul;
struct declaration *fdion_div64,*fdion_mod64,*fdion_mul64;

typedef enum {
      B,
      H,
      W,
      U,
      V,
      N,
      NONE
} type_mod;

typedef enum {
      IND_S,
      IND_D,
      VAR_S,
      VAR_D,
      OP_NONE
} type_op;

enum {
      AL, DL, CL, BL,
      AX, DX, CX, BX,
      DI, SI,
      AX_BX, AX_CX, AX_DX, AX_DI, AX_SI,
      BX_AX, BX_CX, BX_DX, BX_DI, BX_SI,
      CX_AX, CX_BX, CX_DX, CX_DI, CX_SI,
      DX_AX, DX_BX, DX_CX, DX_DI, DX_SI,
      DI_AX, DI_BX, DI_CX, DI_DX, DI_SI,
      SI_AX, SI_BX, SI_CX, SI_DX, SI_DI,
      AX_DX_DI_SI,

      REG_COUNT
};

enum {
      CLASS_NONE,

      CLASS_A,
      CLASS_D,
      CLASS_S,
      CLASS_a,
      CLASS_b,
      CLASS_c,
      CLASS_d,
      CLASS_q,
      CLASS_r,
      CLASS_l,

      CLASS_COUNT
};

#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 << AX_DX))
#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))

/* end with certain register */
#define REG_e_a ((1ULL << BX_AX) | (1ULL << CX_AX) \
                  | (1ULL << DX_AX) | (1ULL << DI_AX) \
                  | (1ULL << SI_AX))
#define REG_e_b ((1ULL << AX_BX) | (1ULL << CX_BX) \
                  | (1ULL << DX_BX) | (1ULL << DI_BX) \
                  | (1ULL << SI_BX))
#define REG_e_c ((1ULL << AX_CX) | (1ULL << BX_CX) \
                  | (1ULL << DX_CX) | (1ULL << DI_CX) \
                  | (1ULL << SI_CX))
#define REG_e_d ((1ULL << AX_DX) | (1ULL << BX_DX) \
                  | (1ULL << CX_DX) | (1ULL << DI_DX) \
                  | (1ULL << SI_DX))
#define REG_e_D ((1ULL << AX_DI) | (1ULL << BX_DI) \
                  | (1ULL << CX_DI) | (1ULL << DX_DI) \
                  | (1ULL << SI_DI))
#define REG_e_S ((1ULL << AX_SI) | (1ULL << BX_SI) \
                  | (1ULL << CX_SI) | (1ULL << DX_SI) \
                  | (1ULL << DI_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))

#define REG_CALLEE      ((1ULL << BX) | REG_D | REG_S)
#define REG_CALLER      ((1ULL << AX) | (1ULL << CX) | (1ULL << DX))

static struct storage_register arch_i286_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 },

      /* 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 uint64_t arch_i286_conflicts[] = {
      /* 8-Bit Registers */
      [AL] = (1ULL << AX) | (1ULL << AX_DX_DI_SI) | REG_e_a
                  | (1ULL << AX_BX) | (1ULL << AX_CX)
                  | (1ULL << AX_DX) | (1ULL << AX_DI)
                  | (1ULL << AX_SI),
      [BL] = (1ULL << BX) | REG_e_b
                  | (1ULL << BX_AX) | (1ULL << BX_CX)
                  | (1ULL << BX_DX) | (1ULL << BX_DI)
                  | (1ULL << BX_SI),
      [CL] = (1ULL << CX) | REG_e_c
                  | (1ULL << CX_AX) | (1ULL << CX_BX)
                  | (1ULL << CX_DX) | (1ULL << CX_DI)
                  | (1ULL << CX_SI),
      [DL] = (1ULL << DX) | (1ULL << AX_DX_DI_SI) | REG_e_d
                  | (1ULL << DX_AX) | (1ULL << DX_BX)
                  | (1ULL << DX_CX) | (1ULL << DX_DI)
                  | (1ULL << DX_SI),

      /* 16-Bit Registers */
      [AX] = REG_a | (1ULL << AX_DX_DI_SI)
                  | (1ULL << BX_AX) | (1ULL << CX_AX)
                  | (1ULL << DX_AX) | (1ULL << DI_AX)
                  | (1ULL << SI_AX),
      [BX] = REG_b
                  | (1ULL << AX_BX) | (1ULL << CX_BX)
                  | (1ULL << DX_BX) | (1ULL << DI_BX)
                  | (1ULL << SI_BX),
      [CX] = REG_c 
                  | (1ULL << AX_CX) | (1ULL << BX_CX)
                  | (1ULL << DX_CX) | (1ULL << DI_CX)
                  | (1ULL << SI_CX),
      [DX] = REG_d | (1ULL << AX_DX_DI_SI)
                  | (1ULL << AX_DX) | (1ULL << BX_DX)
                  | (1ULL << CX_DX) | (1ULL << DI_DX)
                  | (1ULL << SI_DX),
      [DI] = REG_D | (1ULL << AX_DX_DI_SI)
                  | (1ULL << AX_DI) | (1ULL << BX_DI)
                  | (1ULL << CX_DI) | (1ULL << DX_DI)
                  | (1ULL << SI_DI),
      [SI] = REG_S | (1ULL << AX_DX_DI_SI)
                  | (1ULL << AX_SI) | (1ULL << BX_SI)
                  | (1ULL << CX_SI) | (1ULL << DX_SI)
                  | (1ULL << DI_SI),
      /* "bp" Used as frame pointer. */
      /* "sp" Used as stack pointer. */

      /* 32-Bit Registers */
      [AX_BX] = REG_a | REG_b | (1ULL << AX_DX_DI_SI) | REG_e_a | REG_e_b,
      [AX_CX] = REG_a | REG_c | (1ULL << AX_DX_DI_SI) | REG_e_a | REG_e_c,
      [AX_DX] = REG_a | REG_d | (1ULL << AX_DX_DI_SI) | REG_e_a | REG_e_d,
      [AX_DI] = REG_a | REG_D | (1ULL << AX_DX_DI_SI) | REG_e_a | REG_e_D,
      [AX_SI] = REG_a | REG_S | (1ULL << AX_DX_DI_SI) | REG_e_a | REG_e_S,

      [BX_AX] = REG_b | REG_a | (1ULL << AX_DX_DI_SI) | REG_e_b | REG_e_a,
      [BX_CX] = REG_b | REG_c | REG_e_b | REG_e_c,
      [BX_DX] = REG_b | REG_d | (1ULL << AX_DX_DI_SI) | REG_e_b | REG_e_d,
      [BX_DI] = REG_b | REG_D | (1ULL << AX_DX_DI_SI) | REG_e_b | REG_e_D,
      [BX_SI] = REG_b | REG_S | (1ULL << AX_DX_DI_SI) | REG_e_b | REG_e_S,

      [CX_AX] = REG_c | REG_a | (1ULL << AX_DX_DI_SI) | REG_e_c | REG_e_a,
      [CX_BX] = REG_c | REG_b | REG_e_c | REG_e_b,
      [CX_DX] = REG_c | REG_d | (1ULL << AX_DX_DI_SI) | REG_e_c | REG_e_d,
      [CX_DI] = REG_c | REG_D | (1ULL << AX_DX_DI_SI) | REG_e_c | REG_e_D,
      [CX_SI] = REG_c | REG_S | (1ULL << AX_DX_DI_SI) | REG_e_c | REG_e_S,

      [DX_AX] = REG_d | REG_a | (1ULL << AX_DX_DI_SI) | REG_e_d | REG_e_a,
      [DX_BX] = REG_d | REG_b | (1ULL << AX_DX_DI_SI) | REG_e_d | REG_e_b,
      [DX_CX] = REG_d | REG_c | (1ULL << AX_DX_DI_SI) | REG_e_d | REG_e_c,
      [DX_DI] = REG_d | REG_D | (1ULL << AX_DX_DI_SI) | REG_e_d | REG_e_D,
      [DX_SI] = REG_d | REG_S | (1ULL << AX_DX_DI_SI) | REG_e_d | REG_e_S,

      [DI_AX] = REG_D | REG_a | (1ULL << AX_DX_DI_SI) | REG_e_D | REG_e_a,
      [DI_BX] = REG_D | REG_b | (1ULL << AX_DX_DI_SI) | REG_e_D | REG_e_b,
      [DI_CX] = REG_D | REG_c | (1ULL << AX_DX_DI_SI) | REG_e_D | REG_e_c,
      [DI_DX] = REG_D | REG_d | (1ULL << AX_DX_DI_SI) | REG_e_D | REG_e_d,
      [DI_SI] = REG_D | REG_S | (1ULL << AX_DX_DI_SI) | REG_e_D | REG_e_S,

      [SI_AX] = REG_S | REG_a | (1ULL << AX_DX_DI_SI) | REG_e_S | REG_e_a,
      [SI_BX] = REG_S | REG_b | (1ULL << AX_DX_DI_SI) | REG_e_S | REG_e_b,
      [SI_CX] = REG_S | REG_c | (1ULL << AX_DX_DI_SI) | REG_e_S | REG_e_c,
      [SI_DX] = REG_S | REG_d | (1ULL << AX_DX_DI_SI) | REG_e_S | REG_e_d,
      [SI_DI] = REG_S | REG_D | (1ULL << AX_DX_DI_SI) | REG_e_S | REG_e_D,

      /* 64-Bit Register */
      [AX_DX_DI_SI ]= (1ULL << AL) | (1ULL << AX) | (1ULL << DL) | (1ULL << DX) 
                  | REG_a | REG_d | REG_D | REG_S
                  | REG_e_a | REG_e_d | REG_e_D | REG_e_S
                  | (1ULL << SI) | (1ULL << DI),
};

static unsigned int arch_i286_classinfo[256] = {
      ['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_i286_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,
};

const char *arch_i286_reg_name_b[] = {
      [AL] = NULL,
      [BL] = NULL,
      [CL] = NULL,
      [DL] = 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",
};

const char *arch_i286_reg_name_h[] = {
      [AL] = NULL,
      [BL] = NULL,
      [CL] = NULL,
      [DL] = 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",
};

const char *arch_i286_reg_name_w[] = {
      [AL] = "ax",
      [BL] = "bx",
      [CL] = "cx",
      [DL] = "dx",

      [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",
};

const char *arch_i286_reg_name_u[] = {
      [AL] = NULL,
      [BL] = NULL,
      [CL] = NULL,
      [DL] = 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",
};

const char *arch_i286_reg_name_v[] = {
      [AL] = NULL,
      [BL] = NULL,
      [CL] = NULL,
      [DL] = 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",
};

const char *arch_i286_reg_name_def[] = {
      [AL] = "al",
      [BL] = "bl",
      [CL] = "cl",
      [DL] = "dl",

      [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",
};

struct declaration *
arch_i286_tmp(struct scope *s, struct type *t)
{
      struct declaration *var;

      var = simplify_declaration_add(s, t, identifier_tmp());
      var->storage = STORAGE_AUTO;

      return var;
}

int
IsPointer32b(void)
{
      if (opt_f_sizeof_pointer == 2) {
            return 0;
      } else {
            // 32bit = segment:offset
            return 1;
      }

      return 0;
}

void
arch_i286_gen_expr_1(
      struct stmt *block,
      struct stmt *s,
      struct expr *e,
      struct expr *lhs
)
{
      struct type *t = NULL;
      struct type *t1 = NULL;
      struct expr *ce = NULL;
      struct expr *ce2 = NULL;
      struct declaration *var = NULL;
      struct declaration *dion = NULL;
      struct scope *sc = NULL;
      uint64_t reg;
      uint64_t regs_to_save;
      const char *c;

      t = expr_typeof(block->scope, e);
      t = type_pure(t);

      switch (e->type) {
      case EXPR_NONE:
            assert(0);

      case EXPR_INTEGER:
      case EXPR_REAL:
      case EXPR_AMPHERSAND:
            /*
             * No code. Constraint only.
             */
            constraint_output(s, "=rm", expr_dup(lhs));
            constraint_input(s, "i", expr_dup(e));
            break;

      case EXPR_IDENTIFIER:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /*
                   * movb %1, %0
                   */
                  constraint_output(s, "=qm", expr_dup(lhs));
                  constraint_input(s, "q", expr_dup(e));
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /*
                   * movw %1, %0
                   */
                  constraint_output(s, "=rm", expr_dup(lhs));
                  constraint_input(s, "r", expr_dup(e));
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  constraint_output(s, "=rm", expr_dup(lhs));
                  constraint_input(s, "r", expr_dup(e));
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  constraint_output(s, "=rm", expr_dup(lhs));
                  constraint_input(s, "r", expr_dup(e));
                  break;
            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;

      case EXPR_BUILTIN_VA_ARG:
            t1 = e->type_name;

            switch (t1->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
                  /*
                   * mov{b,w} (%1), %0
                   * addw $2, %1
                   */
            case TYPE_INT32:
            case TYPE_UINT32:
                  /*
                   * movw (%1), %0
                   * movw 2(%1), %w0
                   * addw $4, %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_INT64:
            case TYPE_UINT64:
                  assert(0);
            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;

      case EXPR_TYPE_CONVERSION:
            if (_DEBUG > 2)
                  fprintf(stderr, "EXPR_TYPE_CONVERSION\n");

            /*
             * MOVZB
             */
            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:
                  case TYPE_INT16:
                  case TYPE_UINT16:
                        constraint_output(s, "=qm", expr_dup(lhs));
                        constraint_input(s, "q", expr_dup(e->expr0));
                        break;
                  case TYPE_INT32:
                  case TYPE_UINT32:
                        constraint_output(s, "=qm", expr_dup(lhs));
                        constraint_input(s, "A", expr_dup(e->expr0));
                        break;
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        constraint_output(s, "=qm", expr_dup(lhs));
                        constraint_input(s, "r", expr_dup(e->expr0));
                        break;

                  case TYPE_FLOAT32:
                  case TYPE_FLOAT64:
                  case TYPE_FLOAT80:
                        assert(0);
                  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:
                        /*
                         * xorb %h0, %h0
                         * movb %1, %0
                         */
                        constraint_output(s, "=q", expr_dup(lhs));
                        constraint_input(s, "q", expr_dup(e->expr0));
                        break;
                  case TYPE_INT16:
                  case TYPE_UINT16:
                        constraint_output(s, "=r", expr_dup(lhs));
                        constraint_input(s, "rm", expr_dup(e->expr0));
                        break;
                  case TYPE_INT32:
                  case TYPE_UINT32:
                        /*
                         * movw %1, %0
                         */
                        constraint_output(s, "=rm", expr_dup(lhs));
                        constraint_input(s, "A", expr_dup(e->expr0));
                        break;
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        constraint_output(s, "=r", expr_dup(lhs));
                        constraint_input(s, "rm", expr_dup(e->expr0));
                        break;

                  case TYPE_FLOAT32:
                  case TYPE_FLOAT64:
                  case TYPE_FLOAT80:
                        assert(0);

                  case TYPE_POINTER:
                        /*
                         * movw %1, %0
                         */
                        constraint_output(s, "=r", expr_dup(lhs));
                        constraint_input(s, "rmi", expr_dup(e));
                        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:
                        /*
                         * xorb %h0, %h0
                         * xorw %w0, %w0
                         * movb %1, %0
                         */
                        constraint_output(s, "=A", expr_dup(lhs));
                        constraint_input(s, "qm", expr_dup(e->expr0));
                        break;
                  case TYPE_INT16:
                        /*
                         * movw %1, %0
                         * cwd
                         */
                        constraint_output(s, "=A", expr_dup(lhs));
                        constraint_input(s, "rm", expr_dup(e->expr0));
                        break;
                  case TYPE_UINT16:
                        /*
                         * xorw %w0, %w0
                         * movw %1, %0
                         */
                        constraint_output(s, "=r", expr_dup(lhs));
                        constraint_input(s, "rm", expr_dup(e->expr0));
                        break;
                  case TYPE_INT32:
                  case TYPE_UINT32:
                        /*
                         * mov{b,w} %{b,w}1, %{b,w}0
                         */
                        if (t->type <= TYPE_UINT8
                         || t1->type <= TYPE_UINT8) {
                              constraint_output(s, "=q", expr_dup(lhs));
                              constraint_input(s, "qm", expr_dup(e->expr0));
                        } else {
                              constraint_output(s, "=r", expr_dup(lhs));
                              constraint_input(s, "rm", expr_dup(e->expr0));
                        }
                        break;
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        constraint_output(s, "=r", expr_dup(lhs));
                        constraint_input(s, "rm", expr_dup(e->expr0));
                        break;

                  case TYPE_FLOAT32:
                  case TYPE_FLOAT64:
                  case TYPE_FLOAT80:
                        assert(0);
                  case TYPE_POINTER:
                        /*
                         * movw %1, %0
                         */
                        constraint_output(s, "=r", expr_dup(lhs));
                        constraint_input(s, "rmi", expr_dup(e));
                        break;
                  default:
                        assert(0);
                  }
                  break;

            case TYPE_INT64:
            case TYPE_UINT64:
                  switch (t1->type) {
                  case TYPE_INT8:
                  case TYPE_INT16:
                        /*
                         * [cbw]
                         * cwd
                         * movw %%dx, %u0
                         * movw %%dx, %v0
                         */
                        constraint_output(s, "=r", expr_dup(lhs));
                        constraint_input(s, "rm", expr_dup(e->expr0));
                        break;
                  case TYPE_UINT8:
                        /*
                         * xorb %h0, %h0
                         * xorw %w0, %w0
                         * xorw %u0, %u0
                         * xorw %v0, %v0
                         * movb %1, %0
                         */
                        constraint_output(s, "=r", expr_dup(lhs));
                        constraint_input(s, "qm", expr_dup(e->expr0));
                        break;
                  case TYPE_UINT16:
                  case TYPE_UINT32:
                        constraint_output(s, "=rm", expr_dup(lhs));
                        constraint_input(s, "r", expr_dup(e->expr0));
                        break;
                  case TYPE_INT32:
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        constraint_output(s, "=r", expr_dup(lhs));
                        constraint_input(s, "rm", expr_dup(e->expr0));
                        break;

                  case TYPE_FLOAT32:
                  case TYPE_FLOAT64:
                  case TYPE_FLOAT80:
                        assert(0); /* FIXME */

                  case TYPE_POINTER:
                        constraint_output(s, "=r", expr_dup(lhs));
                        constraint_input(s, "rmi", expr_dup(e));
                        break;
                  default:
                        assert(0);
                  }
                  break;

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);

            default:
                  assert(0);
            }
            break;

      case EXPR_STAR:
            assert(lhs);

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
                  /*
                   * mov{b,w} (%1), %0
                   */
                  constraint_output(s, "=r", expr_dup(lhs));
                  constraint_input(s, "l", expr_dup(e->expr0->expr0));
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
            case TYPE_INT64:
            case TYPE_UINT64:
                  /*
                   * 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, "l", expr_dup(e->expr0->expr0));
                  break;

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
                  break;

            default:
                  assert(0);
            }
            break;

      case EXPR_NEG:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
                  /*
                   * neg{b,w} %0
                   */
                  goto inv_int16;
            case TYPE_INT32:
            case TYPE_UINT32:
                  goto inv_int32;
            case TYPE_INT64:
            case TYPE_UINT64:
                  goto inv_int16;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }

      case EXPR_INV:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
                  /*
                   * xor{b,w} $-1, %0
                   */
            inv_int16:
                  constraint_output(s, "=r", expr_dup(lhs));
                  constraint_input(s, "0", expr_dup(e->expr0));
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
            inv_int32:
                  constraint_output(s, "=A", expr_dup(lhs));
                  constraint_input(s, "0", expr_dup(e->expr0));
                  break;

            case TYPE_INT64:
            case TYPE_UINT64:
                  goto inv_int16;

            default:
                  assert(0);
            }
            break;

      case EXPR_ADD:
                  /*
                   * add{b,w} %2, %0
                   */
      case EXPR_SUB:
                  /*
                   * sub{b,w} %2, %0
                   */
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
            sub_int16:
                  constraint_output(s, "=r", expr_dup(lhs));
                  constraint_input(s, "0", expr_dup(e->expr0));
                  constraint_input(s, "rmi", expr_dup(e->expr1));
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  /* FIXME */
            sub_int32:
                  constraint_output(s, "=r", expr_dup(lhs));
                  constraint_input(s, "0", expr_dup(e->expr0));
                  constraint_input(s, "rmi", expr_dup(e->expr1));
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
            sub_int64:
                  constraint_output(s, "=r", expr_dup(lhs));
                  constraint_input(s, "0", expr_dup(e->expr0));
                  constraint_input(s, "mi", expr_dup(e->expr1));
                  break;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;

      case EXPR_MUL:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_INT16:
                  /*
                   * imul{b,w} %2
                   */
            case TYPE_UINT8:
            case TYPE_UINT16:
                  /*
                   * mul{b,w} %2
                   */
                  constraint_output(s, "=a", expr_dup(lhs));
                  constraint_input(s, "0", expr_dup(e->expr0));
                  constraint_input(s, "rm", expr_dup(e->expr1));
                  constraint_change(s, "dx");
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  if (_DEBUG > 1)
                        fprintf(stderr, "MUL32\n");
                  if (fdion_mul==NULL) {
                        fdion_mul = declaration_identifier("__i286_mul32\0");
                        assert(fdion_mul);
                        dion = fdion_mul;
                        dion->type_name = type_new();
                        dion->type_name->type = TYPE_FUNCTION;
                        dion->type_name->declarator = type_new();
                        /* return type */
                        dion->type_name->declarator->type = t->type;
                  }
                  dion = fdion_mul;
                  goto div_32;
            case TYPE_INT64:
            case TYPE_UINT64:
                  if (_DEBUG > 1)
                        fprintf(stderr, "MUL64\n");
                  if (fdion_mul64==NULL) {
                        fdion_mul64 = declaration_identifier("__i286_mul64\0");
                        assert(fdion_mul64);
                        dion = fdion_mul64;
                        dion->type_name = type_new();
                        dion->type_name->type = TYPE_FUNCTION;
                        dion->type_name->declarator = type_new();
                        /* return type */
                        dion->type_name->declarator->type = t->type;
                  }
                  dion = fdion_mul64;
                  goto div_64_reg;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);

            default:
                  assert(0);
            }
            break;

      case EXPR_DIV:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /*
                   * idivwb %2
                   */
                  constraint_output(s, "=a", expr_dup(lhs));
                  constraint_input(s, "0", expr_dup(e->expr0));
                  constraint_input(s, "rm", expr_dup(e->expr1));
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /*
                   * xorw %dx, %dx
                   * divw %3
                   */
                  constraint_output(s, "=a", expr_dup(lhs));
                  constraint_output(s, "=&d", expr_dup(lhs));
                  constraint_input(s, "0", expr_dup(e->expr0));
                  constraint_input(s, "rm", expr_dup(e->expr1));
#if 0
                  constraint_change(s, "dx");
#endif
                  break;

            case TYPE_INT32:
            case TYPE_UINT32:
                  if (_DEBUG > 1)
                        fprintf(stderr, "DIV32\n");
                  if (fdion_div==NULL) {
                        fdion_div = declaration_identifier("__i286_div32\0");
                        assert(fdion_div);
                        dion = fdion_div;
                        dion->type_name = type_new();
                        dion->type_name->type = TYPE_FUNCTION;
                        dion->type_name->declarator = type_new();
                        /* return type */
                        dion->type_name->declarator->type = t->type;
                  }
                  dion = fdion_div;

                  div_32:
                  regs_to_save = REG_CALLER;
                  regs_to_save &= ~((1ULL << AX) | (1ULL << DX));
                  div_64:

                  assert(lhs);
                  switch (t->type) {
                  case TYPE_INT8:
                  case TYPE_UINT8:
                  case TYPE_INT16:
                  case TYPE_UINT16:
                        assert(0);
                  case TYPE_INT32:
                  case TYPE_UINT32:
                        constraint_output(s, "=A", expr_dup(lhs));
                        break;
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        constraint_output(s, "=r", expr_dup(lhs));
                        break;
                  case TYPE_FLOAT32:
                  case TYPE_FLOAT64:
                  case TYPE_FLOAT80:
                        assert(0);
                  default:
                        assert(0);
                  }
                  /* 
                   * change of:
                   * e->expr0: operand1 -> ce
                   * e->expr1: operand2 -> ce2
                   * into:
                   * e->expr0 - name of function
                   * e->expr1 - list of func. parameters
                   */
                  e->type = EXPR_FUNC;
                  ce = e->expr0;
                  ce2 = e->expr1;
                  e->expr1 = NULL;
                  e->expr1 = expr_new();
                  e->expr1->first = ce;
                  ce->next = ce2;
                  ce2->prev = ce;
                  e->expr1->last = ce2;

                  e->expr1->type = EXPR_LIST;
                  e->expr0 = expr_new();
                  e->expr0->type = EXPR_IDENTIFIER;
                  e->expr0->declaration = dion;

                  /* parameters */
                  sc = malloc(sizeof(*sc));
                  assert(sc);
                  memset(sc, 0, sizeof(*sc));
                  e->expr0->type_name = type_new();
                  e->expr0->type_name->parameter = sc;
                  
                  regs_to_save = REG_CALLER;
                  regs_to_save &= ~((1ULL << AX) | (1ULL << DX));

                  for (reg = 0; regs_to_save; reg++) {
                        if ((regs_to_save >> reg) & 1) {
                              switch (reg) {
                              case AX: c = "=a"; break;
                              case BX: c = "=b"; break;
                              case CX: c = "=c"; break;
                              case DX: c = "=d"; break;
                              case DI: c = "=D"; break;
                              case SI: c = "=S"; break;
                              default: assert(0);
                              }
                              constraint_change(s, arch_i286_reginfo[reg].name);
                              regs_to_save &= ~(1 << reg);
                        }
                  }

                  for (ce = e->expr1->last; ce; ce = ce->prev) {
                        constraint_input(s, "rmi", expr_dup(ce));
                  }
                  constraint_change(s, "memory");

                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  if (_DEBUG > 1)
                        fprintf(stderr, "DIV64\n");
                  if (fdion_div64==NULL) {
                        fdion_div64 = declaration_identifier("__i286_div64\0");
                        assert(fdion_div64);
                        dion = fdion_div64;
                        dion->type_name = type_new();
                        dion->type_name->type = TYPE_FUNCTION;
                        dion->type_name->declarator = type_new();
                        /* return type */
                        dion->type_name->declarator->type = t->type;
                  }
                  dion = fdion_div64;
                  div_64_reg:
                  regs_to_save = REG_CALLER;
                  regs_to_save &= ~((1ULL << AX) | (1ULL << DX) 
                                          | (1ULL << DI) | (1ULL << SI));
                  goto div_64;

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);

            default:
                  assert(0);
            }
            break;

      case EXPR_MOD:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_INT16:
                  /*
                   * idivw %2
                   */
            case TYPE_UINT8:
            case TYPE_UINT16:
                  /*
                   * xorw %dx, %dx
                   * divw %2
                   */
                  constraint_output(s, "=d", expr_dup(lhs));
                  constraint_input(s, "a", expr_dup(e->expr0));
                  constraint_input(s, "rm", expr_dup(e->expr1));
                  constraint_change(s, "ax");
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  if (_DEBUG > 1)
                        fprintf(stderr, "MOD32\n");
                  if (fdion_mod==NULL) {
                        fdion_mod = declaration_identifier("__i286_mod32\0");
                        assert(fdion_mod);
                        dion = fdion_mod;
                        dion->type_name = type_new();
                        dion->type_name->type = TYPE_FUNCTION;
                        dion->type_name->declarator = type_new();
                        /* return type */
                        dion->type_name->declarator->type = t->type;
                  }
                  dion = fdion_mod;
                  goto div_32;
            case TYPE_INT64:
            case TYPE_UINT64:
                  if (_DEBUG > 1)
                        fprintf(stderr, "MOD64\n");
                  if (fdion_mod64==NULL) {
                        fdion_mod64 = declaration_identifier("__i286_mod64\0");
                        assert(fdion_mod64);
                        dion = fdion_mod64;
                        dion->type_name = type_new();
                        dion->type_name->type = TYPE_FUNCTION;
                        dion->type_name->declarator = type_new();
                        /* return type */
                        dion->type_name->declarator->type = t->type;
                  }
                  dion = fdion_mod64;
                  goto div_64_reg;

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);

            default:
                  assert(0);
            }
            break;

      case EXPR_LEFT:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
                  /*
                   * shl{b,w} %b2, %0
                   */
                  goto shift_int16;
            case TYPE_INT32:
            case TYPE_UINT32:
                  goto shift_int32;
            case TYPE_INT64:
            case TYPE_UINT64:
                  goto shift_int64;

            default:
                  assert(0);
            }
            break;

      case EXPR_RIGHT:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_INT16:
                  /*
                   * sar{b,w} %b2, %0
                   */
                  goto shift_int16;
            case TYPE_UINT8:
            case TYPE_UINT16:
                  /*
                   * shr{b,w} %b2, %0
                   */
            shift_int16:
                  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:
            case TYPE_UINT32:
            shift_int32:
                  /* FIXME */
                  /* TODO: detect shift 0x10 and optimize it! */
                  constraint_output(s, "=rm", expr_dup(lhs));
                  constraint_input(s, "0", expr_dup(e->expr0));
                  constraint_input(s, "ci", expr_dup(e->expr1));
                  constraint_change(s, "cx");
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
            shift_int64:
                  constraint_output(s, "=r", expr_dup(lhs));
                  constraint_input(s, "0", expr_dup(e->expr0));
                  constraint_input(s, "mi", expr_dup(e->expr1));
                  constraint_change(s, "cx");
                  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:

            var = simplify_declaration_add(block->scope,
                        type_uint16(), identifier_tmp());
            var->storage = STORAGE_AUTO;

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
            case TYPE_INT32:
            case TYPE_UINT32:
                  /*
                   * cmp{b,w} %3, %2
                   * emu-setcc %1
                   * emu-movzb{b,w} %1, %0
                   */

                  constraint_output(s, "=rm", expr_dup(lhs));
                  constraint_output(s, "=c", expr_identifier(var));
                  constraint_input(s, "rm", expr_dup(e->expr0));
                  constraint_input(s, "rmi", expr_dup(e->expr1));
                  break;

            case TYPE_INT64:
            case TYPE_UINT64:
                  constraint_output(s, "=rm", expr_dup(lhs));
                  constraint_output(s, "=c", expr_identifier(var));
                  constraint_input(s, "m", expr_dup(e->expr0));
                  constraint_input(s, "mi", expr_dup(e->expr1));
                  break;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);

            default:
                  assert(0);
            }
            break;

      case EXPR_AND:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
                  /*
                   * and{b,w} %2, %0
                   */
                  goto sub_int16;
            case TYPE_INT32:
            case TYPE_UINT32:
                  goto sub_int32;
            case TYPE_INT64:
            case TYPE_UINT64:
                  goto sub_int64;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;
      case EXPR_OR:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
                  /*
                   * or{b,w} %2, %0
                   */
                  goto sub_int16;
            case TYPE_INT32:
            case TYPE_UINT32:
                  goto sub_int32;
            case TYPE_INT64:
            case TYPE_UINT64:
                  goto sub_int64;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;
      case EXPR_XOR:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
                  /*
                   * xor{b,w} %2, %0
                   */
                  goto sub_int16;
            case TYPE_INT32:
            case TYPE_UINT32:
                  goto sub_int32;
            case TYPE_INT64:
            case TYPE_UINT64:
                  goto sub_int64;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;

      case EXPR_FUNC:
            regs_to_save = 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_to_save &= ~(1ULL << AX);
                        break;
                  case TYPE_INT32:
                  case TYPE_UINT32:
                        constraint_output(s, "=A", expr_dup(lhs));
                        regs_to_save &= ~((1ULL << AX) | (1ULL << DX));
                        break;
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        assert(0);
                  case TYPE_FLOAT32:
                  case TYPE_FLOAT64:
                  case TYPE_FLOAT80:
                        assert(0);
                  default:
                        assert(0);
                  }
            }

            for (reg = 0; regs_to_save; reg++) {
                  if ((regs_to_save >> reg) & 1) {
                        switch (reg) {
                        case AX: c = "=a"; break;
                        case BX: c = "=b"; break;
                        case CX: c = "=c"; break;
                        case DX: c = "=d"; break;
                        case DI: c = "=D"; break;
                        case SI: c = "=S"; break;
                        default: assert(0);
                        }
                        constraint_change(s, arch_i286_reginfo[reg].name);
                        regs_to_save &= ~(1 << reg);
                  }
            }

            for (ce = e->expr1->last; ce; ce = ce->prev) {
                  constraint_input(s, "rmi", expr_dup(ce));
            }

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

            constraint_change(s, "memory");

            break;

      default:
            assert(0);
      }
}

void
arch_i286_gen_stmt_reg_alloc(FILE *fp, struct stmt *block, struct stmt *s)
{
      struct type *t = NULL;

      switch (s->type) {
      case STMT_NONE:
            assert(0);
            break;

      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);
            break;

      case STMT_LABEL:
            break;

      case STMT_EXPR:
            switch (s->expr0->type) {
            case EXPR_ASSIGN:
                  switch (s->expr0->expr0->type) {
                  case EXPR_IDENTIFIER:
                        if (_DEBUG > 2)
                              fprintf(stderr, "EXPR_IDENTIFIER\n");
                        arch_i286_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)
                               */
                              constraint_input(s, "l",
                                    expr_dup(s->expr0->expr0->expr0->expr0));
                              constraint_input(s, "q",
                                    expr_dup(s->expr0->expr1));
                              break;

                        case TYPE_INT16:
                        case TYPE_UINT16:
                        case TYPE_INT32:
                        case TYPE_UINT32:
                        case TYPE_INT64:
                        case TYPE_UINT64:
                              /*
                               * movw %1, (%0)
                               * [movw %1, 2(%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);
                              break;

                        default:
                              assert(0);
                        }
                        if (_DEBUG > 2)
                              fprintf(stderr, "EXPR_STAR\n");
                        break;
                  default:
                        assert(0);
                        break;
                  }
                  break;
            case EXPR_FUNC:
                  if (_DEBUG > 2)
                        fprintf(stderr, "EXPR_FUNC\n");
                  arch_i286_gen_expr_1(block, s, s->expr0, NULL);
                  break;
            default:
                  assert(0);
            }
            break;

      case STMT_IF:
            if (_DEBUG > 2)
                  fprintf(stderr, "STMT_IF \n");

            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:
                  /*
                   * cmp{b,w} %1, %0
                   * jcc label
                   */
                  constraint_input(s, "r", expr_dup(s->expr0->expr1));
                  constraint_input(s, "rmi", expr_dup(s->expr0->expr0));
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  constraint_input(s, "r", expr_dup(s->expr0->expr1));
                  constraint_input(s, "rmi", expr_dup(s->expr0->expr0));
                  break;

            case TYPE_INT64:
            case TYPE_UINT64:
                  constraint_input(s, "r", expr_dup(s->expr0->expr1));
                  constraint_input(s, "mi", expr_dup(s->expr0->expr0));
                  break;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);

            default:
                  assert(0);
            }
            break;

      case STMT_SWITCH:
            /*
             * cmp{b,w} $c0, %ax
             * je l0
             * cmp{b,w} $c1, %ax
             * je l1
             * cmp{b,w} $c2, %ax
             * je l2
             * ...
             * cmp{b,w} $cN, %ax
             * je lN
             * jmp ldef
             */
            if (_DEBUG > 2)
                  fprintf(stderr, "STMT_SWITCH \n");
            constraint_input(s, "r", expr_dup(s->expr0));
            break;

      case STMT_GOTO:
            break;

      case STMT_RETURN:
            if (_DEBUG > 1)
                  fprintf(stderr, "Expr1:STMT_RETURN \n");
            /*
             * 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:
            break;

      case STMT_VA_START:
            /*
             * lea X(%bp), %0
             */
            if (_DEBUG > 2)
                  fprintf(stderr, "STMT_VA_START \n");
            constraint_output(s, "=r", expr_dup(s->expr0));
            break;

      case STMT_VA_END:
            break;

      default:
            assert(0);
            break;
      }
}

void
arch_i286_declaration_alive(
      struct storage_register *reginfo,
      unsigned int *coninfo,
      unsigned int *typeinfo,
      struct stmt *fs,
      FILE *fp
)
{
#if 0
      struct expr *exprlist[100];
#endif
      struct stmt *cs = NULL;
      struct constraint *c = NULL;
      unsigned int i;

#if 0
      if (_DEBUG == 1)
      {
            fprintf(fp, "\n");
            print_stmt(fp, 1, 0, fs);
            fprintf(fp, "\n");
      } else {
            fprintf(stderr, "\n");
            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) {
#if 0
                        decl_constraint_ease(fs, cs, c, exprlist, i);
#endif
                        i++;
                  }
            }
            if (cs->input) {
                  for (c = cs->input->first; c; c = c->next) {
#if 0
                        decl_constraint_ease(fs, cs, c, exprlist, i);
#endif
                        i++;
                  }
            }

            cs = next;
      }

}

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:
//    case TYPE_VA_LIST:
      case TYPE_POINTER:
            *alignp = 2;
            *sizep = 2;
            break;

      case TYPE_VA_LIST:
      case TYPE_INT32:
      case TYPE_UINT32:
      case TYPE_FLOAT32:
            *alignp = 2;
            *sizep = 4;
            break;

      case TYPE_INT64:
      case TYPE_UINT64:
      case TYPE_FLOAT64:
            *alignp = 2;
            *sizep = 8;
            break;

      case TYPE_FLOAT80:
            *alignp = 2;
            *sizep = 16;
            break;

      default:
            assert(0);
      }
}

void
arch_i286_calculate_local_size(
      FILE *fp,
      struct declaration *d,
      unsigned int *autosize
)
{
      struct scope *s = NULL;
      struct declaration *dion = NULL;
      struct stmt *stmt = NULL;
      int offset = 0;
      unsigned int align = 0;
      unsigned int size = 0;

      for (stmt=d->stmt; stmt;stmt=stmt->next) {
            dion = stmt->scope->declaration_first;
            s = stmt->scope;

            for (dion = s->declaration_first; dion; dion = dion->next) {
                  if (dion->storage == STORAGE_AUTO) {
                        type_align_size(s,dion->type_name,
                                    &align, &size);
                        size += align - 1;
                        size &= ~(align - 1);
                        offset -= size;
                        dion->offset = offset;
                  }
            }
      }

      /* 2 Byte align */
      offset &= ~(2 - 1);
      offset *= -1;
      *autosize = offset;
      #if _DEBUG > 2
      fprintf(stderr, "autosize:%d\n", *autosize);
      #endif
}

void
arch_i286_calculate_param_size(
      FILE *fp,
      struct declaration *d,
      unsigned int *paramsize
)
{
      struct declaration *dion = NULL;
      int offset = 0;
      unsigned int align = 0;
      unsigned int size = 0;

      for (dion = d->type_name->parameter->declaration_first;
          dion && dion->type_name->type != TYPE_ELIPSIS;
          dion = dion->next) {
            type_align_size(d->stmt->scope, dion->type_name,
                        &align, &size);

            dion->offset = offset;
            dion->offset += align - 1;
            dion->offset &= ~(align - 1);
            offset += size;
      }

      /* 2 Byte align */
      offset = offset + 1;
      offset &= ~(2 - 1);
      *paramsize = offset;
      #if _DEBUG > 2
      fprintf(stderr, "paramsize:%d\n\n", *paramsize);
      #endif
}

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_i286_reginfo[reg].name, name) == 0) {
                  *classp = arch_i286_reginfo[reg].class;
                  *typep = arch_i286_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 */
            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:
            assert(type == TYPE_INT32
                || type == TYPE_UINT32);
            count[CLASS_a]++;
            count[CLASS_d]++; 
            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_D]++;
            } 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_D]--;
            } 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_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);
}

void
arch_i286_gen_reg_add(uint32_t *conflicts, unsigned int reg)
{
      *(uint64_t *) conflicts |= 1ULL << reg;
      *(uint64_t *) conflicts |= arch_i286_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_VA_LIST:*/
      case TYPE_INT16:
      case TYPE_UINT16:
      case TYPE_POINTER: regs &= REG_16; break;
      case TYPE_VA_LIST:
      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;
      default: assert(0); break;
      }

      regs &= ~*(uint64_t *) conflicts;

      for (reg = 0; ; reg++) {
            if (reg == REG_COUNT) {
                  return -1;
            }
            if ((regs >> reg) & 1) {
                  return reg;
            }
      }
}

void
arch_i286_gen_variable_init(
      FILE *fp,
      struct scope *s,
      struct type *t,
      struct expr *e
)
{
      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(e->type_name->type == TYPE_INT16
                            || e->type_name->type == TYPE_UINT16);

                        switch (e->expr0->type) {
                        case EXPR_IDENTIFIER:
                              assert(e->expr0->declaration->type_name->type
                                          == TYPE_ARRAY
                                  || e->expr0->declaration->type_name->type
                                          == TYPE_FUNCTION);
                              fprintf(fp, "\t.word %s\n",
                                          e->expr0->declaration->identifier);
                              break;
                        case EXPR_AMPHERSAND:
                              assert(e->expr0->expr0->type == EXPR_IDENTIFIER);
                              fprintf(fp, "\t.word %s\n",
                                          e->expr0->expr0->declaration->identifier);
                              break;
                        default:
                              assert(0);
                        }
                        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:
                        assert(e->type_name->type == TYPE_INT32
                            || e->type_name->type == TYPE_UINT32);
                        /* FIXME */
                        switch (e->expr0->type) {
                        case EXPR_IDENTIFIER:
                              assert(e->expr0->declaration->type_name->type
                                          == TYPE_ARRAY
                                  || e->expr0->declaration->type_name->type
                                          == TYPE_FUNCTION);
                              fprintf(fp, "\t.size %s, 4\n",
                                          e->expr0->declaration->identifier);
                              break;
                        case EXPR_AMPHERSAND:
                              assert(e->expr0->expr0->type == EXPR_IDENTIFIER);
                              fprintf(fp, "\t.size %s, 4\n",
                                          e->expr0->expr0->declaration->identifier);
                              break;
                        default:
                              assert(0);
                        }
                        break;
                  default:
                        assert(0);
                  }
            } else {
                  fprintf(fp, "\t.word 0x0000, 0x0000\n");
            }
            break;
      case TYPE_INT64:
      case TYPE_UINT64:
            if (e) {
                  assert(e->type == 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));
            } else {
                  fprintf(fp, "\t.word 0x0000, 0x0000, 0x0000, 0x0000\n");
            }
            break;

      case TYPE_FLOAT32:
      case TYPE_FLOAT64:
      case TYPE_FLOAT80:
            assert(0);

      case TYPE_STRUCT: {
            struct declaration *d = NULL;
            struct expr *ce = NULL;
            int ret;

            if (! t->scope) {
                  ret = scope_lookup_structunionenum(s,
                              t->type, t->identifier, &t);
                  assert(0 <= ret);
            }
            assert(t->scope);

            for (d = t->scope->declaration_first, ce = e->first;
                d;
                d = d->next, ce = (ce ? ce->next : NULL)) {
                  arch_i286_gen_variable_init(fp, s, d->type_name, ce);
            }
            break;
            }

      case TYPE_VA_LIST:
      case TYPE_POINTER:
            assert(0);
            break;

      case TYPE_ARRAY: {
            unsigned int dim = 0;
            struct expr *ce = NULL;
            unsigned int i = 0;
            char c;

            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_i286_gen_variable_init(fp, s, 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':
                              if (i < dim - 1) {
                                    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:
            break;
      }
}

void
arch_i286_gen_variable(FILE *fp, struct scope * s, struct declaration *d)
{
      unsigned int size = 0;
      unsigned int align = 0;

      size = type_sizeof(s, d->type_name);

      align = 2;
      if (d->type_name->mod_const) {
            fprintf(fp, "\t.section .rodata\n");
      } else {
            fprintf(fp, "\t.data\n");
      }
      if (d->initializer) {
            if (d->storage != STORAGE_STATIC) {
                  fprintf(fp, "\t.globl %s\n", d->identifier);
            }
      } else {
            if (d->storage == STORAGE_STATIC) {
                  fprintf(fp, "\t.local %s\n", d->identifier);
            }
      }
      if (d->initializer) {
            fprintf(fp, "\t.align %u\n", align);
            fprintf(fp, "\t.type %s, @object\n", d->identifier);
            fprintf(fp, "\t.size %s, %u\n", d->identifier, size);
            fprintf(fp, "%s:\n", d->identifier);
            arch_i286_gen_variable_init(fp, s, d->type_name,
                        d->initializer);
      } else {
            fprintf(fp, "\t.comm %s, %u, %u\n", d->identifier,
                        size, align);
      }
}

const char *
arch_i286_get_reg2(struct declaration *d, type_mod mod)
{
      const char *nreg = NULL;

      switch (mod) {
      case B:
            nreg = arch_i286_reg_name_b[d->storage_register];
            break;
      case H:
            nreg = arch_i286_reg_name_h[d->storage_register];
            break;
      case W:
            nreg = arch_i286_reg_name_w[d->storage_register];
            break;
      case U:
            nreg = arch_i286_reg_name_u[d->storage_register];
            break;
      case V:
            nreg = arch_i286_reg_name_v[d->storage_register];
            break;
      default:
            /* modifier N */
            nreg = arch_i286_reg_name_def[d->storage_register];
            break;
      }

      return nreg;
}

void
arch_i286_set_identifier(
      struct constraint *c,
      struct declaration *d,
      char *buf1,
      type_mod mod
)
{
      if(d->storage == STORAGE_AUTO) {
            if (mod == W) {
                  sprintf(buf1+strlen(buf1), "%%ss");
            } else {
                  sprintf(buf1+strlen(buf1), "%d(%%bp)", d->offset);
            }
      } else {
            if (  c->expr->type_name->type == TYPE_INT32 ||
                  c->expr->type_name->type == TYPE_UINT32) {
                  if (mod == W) {
                        sprintf(buf1, "$SEG_%s", d->identifier);
                  } else {
                        sprintf(buf1, "$OFF_%s", d->identifier);
                  }     
            } else {
                  sprintf(buf1, "$%s", d->identifier);
            }
      }
}

void
arch_i286_get_operand(
      struct stmt *s,
      struct constraint *c,
      char *buf,
      type_mod mod
)
{
      struct declaration * d = NULL;
      const char *reg = NULL;
      char *buf1;

      buf1 = buf + strlen(buf);

      switch (c->expr->type) {
      case EXPR_INTEGER:
            switch (c->expr->type_name->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  sprintf(buf1, "$0x%x", (uint8_t) c->expr->integer);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  sprintf(buf1, "$0x%x", (uint16_t) c->expr->integer);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  if (mod == W) {
                        sprintf(buf1, "$0x%x", 
                        (uint16_t) (c->expr->integer >> 16));
                  } else {
                        sprintf(buf1, "$0x%x", (uint16_t)
c->expr->integer);
                  }
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  if (mod == V) {
                        sprintf(buf1, "$0x%x", 
                  (uint16_t) (c->expr->integer >> 48));
                  } else if (mod == U) {
                        sprintf(buf1, "$0x%x", 
                        (uint16_t) (c->expr->integer >> 32));
                  } else if (mod == W) {
                        sprintf(buf1, "$0x%x", 
                        (uint16_t) (c->expr->integer >> 16));
                  } else {
                        sprintf(buf1, "$0x%x", 
                        (uint16_t) c->expr->integer);
                  }
                  break;
            default:
                  assert(0);
            }
            buf1 += strlen(buf1);
            break;

      case EXPR_REAL:
            assert(0);

      case EXPR_IDENTIFIER:
            d = c->expr->declaration;
            assert(d);
            #if _DEBUG > 1
                  fprintf(stderr, "%s", d->identifier);
            #endif
            switch (d->storage) {
            case STORAGE_AUTO:
                  #if _DEBUG > 1
                        fprintf(stderr, "STORAGE_AUTO");
                  #endif
                  if (mod == V) {
                        sprintf(buf1, "%d(%%bp)", d->offset+6);
                  } else if (mod == U) {
                        sprintf(buf1, "%d(%%bp)", d->offset+4);
                  } else if (mod == W) {
                        sprintf(buf1, "%d(%%bp)", d->offset+2);
                  } else {
                        sprintf(buf1, "%d(%%bp)", d->offset);
                  }
                  buf1 += strlen(buf1);
                  break;

            case STORAGE_REGISTER:

                  #if _DEBUG > 1
                        fprintf(stderr, "STORAGE_REGISTER(%s|%u)",
arch_i286_reginfo[d->storage_register].name, d->storage_register);
                  #endif
                  *buf1++ = '%';
                  reg = arch_i286_get_reg2(d, mod);

                  if (reg==NULL) {
                        fprintf(stderr, "buf1:%s", buf1);
                        fprintf(stderr, "reg=%s, strg_reg=%u, mod=%c\n",
arch_i286_reginfo[d->storage_register].name, d->storage_register, mod);
                  }
                  assert(reg);

                  sprintf(buf1, "%s", reg);/*
                  strcpy(buf1, reg);
                  buf1 += strlen(reg);*/
                  break;

            case STORAGE_PARAM:
                  #if _DEBUG > 1
                        fprintf(stderr, "STORAGE_PARAM");
                  #endif
                  if (mod == V) {
                        sprintf(buf1, "%u(%%bp)", 12 + d->offset);
                  } else if (mod == U) {
                        sprintf(buf1, "%u(%%bp)", 10 + d->offset);
                  } else if (mod == W) {
                        sprintf(buf1, "%u(%%bp)", 8 + d->offset);
                  } else {
                        sprintf(buf1, "%u(%%bp)", 6 + d->offset);
                  }
                  buf1 += strlen(buf1);
                  break;

            case STORAGE_NONE:
                  #if _DEBUG > 1
                        fprintf(stderr, "STORAGE_NONE");
                        goto dbg_print_storage;
                  #endif
            case STORAGE_STATIC:
                  #if _DEBUG > 1
                        fprintf(stderr, "STORAGE_STATIC");
                        goto dbg_print_storage;
                  #endif
            case STORAGE_EXTERN:
                  #if _DEBUG > 1
                        fprintf(stderr, "STORAGE_EXTERN");
                        dbg_print_storage:
                  #endif
                  strcpy(buf1, d->identifier);
                  buf1 += strlen(buf1);
                  break;

            case STORAGE_TYPEDEF:
            case STORAGE_ASM:
                  assert(0);
            }
            break;

      case EXPR_AMPHERSAND:
            assert(0);

      case EXPR_TYPE_CONVERSION:
            if (_DEBUG > 1)
                  fprintf(stderr, "\ncode_gen:EXPR_TYPE_CONVERSION\n");
            /* TYPE_(U)INT32 in case sizeof_int=4 */
            assert(c->expr->type_name->type == TYPE_INT16
                  || c->expr->type_name->type == TYPE_UINT16
                  || c->expr->type_name->type == TYPE_INT32
                  || c->expr->type_name->type == TYPE_UINT32);
            d = c->expr->expr0->declaration;
            if (c->expr->expr0->type == EXPR_IDENTIFIER) {
                  /* FIXME */
                  if (d->type_name->type == TYPE_ARRAY
                        && s->expr0->type != EXPR_FUNC
                        && d->storage == STORAGE_AUTO) {
                        if (mod == W) {
                              sprintf(buf1+strlen(buf1), "%%ss");
                        } else {
                              sprintf(buf1, "%d(%%bp)", d->offset);
                        }
                  } else {
                        arch_i286_set_identifier(c, d, buf1, mod);
                  }
            } else if (c->expr->expr0->type == EXPR_AMPHERSAND) {
                  assert(c->expr->expr0->expr0->type
                              == EXPR_IDENTIFIER);
                  d = c->expr->expr0->expr0->declaration;
                  arch_i286_set_identifier(c, d, buf1, mod);
            }
            buf1 += strlen(buf1);
            break;

      default:
            assert(0);
      }
}

int
arch_i286_is_local(struct expr * e)
{
      if ((e->expr0->type == EXPR_IDENTIFIER
            &&
      e->expr0->declaration->type_name->type 
            == TYPE_ARRAY
            && e->expr0->declaration->storage ==
            STORAGE_AUTO)) {
            return 1;
      } else {
            return 0;
      }
}

int
arch_i286_is_local2(struct constraint * c)
{
      struct declaration * d = NULL;

      if (c->expr->type == EXPR_TYPE_CONVERSION) {
            if (c->expr->expr0->type == EXPR_IDENTIFIER/* 
                ||
                c->expr->expr0->type == EXPR_AMPHERSAND*/) {
                  d = c->expr->expr0->declaration;
                  assert(d);
                  if (d->type_name->type == TYPE_ARRAY
                        && d->storage == STORAGE_AUTO) {
                        return 1;
                  }
            } else if (c->expr->expr0->type == EXPR_AMPHERSAND) {
                  assert(c->expr->expr0->expr0->type == EXPR_IDENTIFIER);
                  d = c->expr->expr0->expr0->declaration;
                  assert(d);
                  return 1;
            }
      }
      return 0;
}

void
arch_i286_set_register(
      struct stmt *s,
      struct constraint * c0,
      char *buf1,
      type_mod mod0,
      int eof
)
{
      arch_i286_get_operand(s, c0, buf1, mod0);
      if (eof > 0) {
            strcat(buf1, "\n");
      }
}

void
arch_i286_set_registers(
      struct stmt *s,
      struct constraint * c0,
      struct constraint * c1,
      char *buf1,
      type_mod mod1,
      type_mod mod0
)
{
      arch_i286_get_operand(s, c1, buf1, mod1);
      strcat(buf1, ", ");
      arch_i286_get_operand(s, c0, buf1, mod0);
      strcat(buf1, "\n");
}

void
arch_i286_set_ind_mem(
      struct stmt *s,
      struct constraint * c0,
      struct constraint * c1,
      char *buf1,
      type_mod mod,
      int offset,
      type_op type
)
{
      switch (type) {
      case IND_S:
            if (offset != 0) {
                  sprintf(buf1 + strlen(buf1), "%d", offset);
            }
            if (IsPointer32b()) {
                  strcat(buf1, "%es:");
            }
            strcat(buf1, "(");
            arch_i286_get_operand(s, c1, buf1, N);
            strcat(buf1, "), ");
            arch_i286_get_operand(s, c0, buf1, mod);
            strcat(buf1, "\n");
            break;
      case IND_D:
            arch_i286_get_operand(s, c1, buf1, mod);
            strcat(buf1, ", ");
            if (offset != 0) {
                  sprintf(buf1 + strlen(buf1), "%d", offset);
            }
            if (IsPointer32b()) {
                  strcat(buf1, "%es:");
            }
            strcat(buf1, "(");
            arch_i286_get_operand(s, c0, buf1, N);
            strcat(buf1, ")\n");
            break;
      case VAR_S:
            arch_i286_get_operand(s, c1, buf1, mod);
            if (offset != 0) {
                  sprintf(buf1 + strlen(buf1), "+%d", offset);
            }
            strcat(buf1, ", ");
            arch_i286_get_operand(s, c0, buf1, mod);
            strcat(buf1, "\n");
            break;
      case VAR_D:
            arch_i286_get_operand(s, c1, buf1, mod);
            strcat(buf1, ", ");
            arch_i286_get_operand(s, c0, buf1, mod);
            if (offset != 0) {
                  sprintf(buf1 + strlen(buf1), "+%d", offset);
            }
            strcat(buf1, "\n");
            break;
      default:
            assert(0);
      }
}

int
i286_omit_simple_mov(
      char *buf1,
      struct constraint * c0,
      struct constraint * c1,
      type_mod mod1,
      type_mod mod0
)
{
      /* for mov8/16 */
      struct declaration * d0 = NULL;
      struct declaration * d1 = NULL;
      const char *sreg = NULL;
      const char *dreg = NULL;

      d0 = c0->expr->declaration;
      d1 = c1->expr->declaration;
      assert(d0);

      if (d1 == NULL) {
            /* c1 is constant expr */
            return 0;
      }

      if (d0->storage == STORAGE_REGISTER 
            && d1->storage == STORAGE_REGISTER) {
            dreg = arch_i286_get_reg2(d0, mod0);
            sreg = arch_i286_get_reg2(d1, mod1);
            if (strncmp(sreg, dreg, 2) != 0) {
                  /* FIXME */
                  if (d0->type_name->type == TYPE_UINT8
                        || d0->type_name->type == TYPE_INT8
                        || (mod0 == B)) {
                        sprintf(buf1 + strlen(buf1),
                              "\tmovb %%%s, %%%s\n",
                              sreg, dreg);
                  } else {
                        sprintf(buf1 + strlen(buf1),
                              "\tmovw %%%s, %%%s\n",
                              sreg, dreg);
                  }
            }
            return 1;
      } else {
            return 0;
      }
}

int
arch_i286_omit_mov(
      char *buf1,
      struct constraint * c0,
      struct constraint * c1,
      type_mod mod,
      type_mod mod2
)
{
      /* mov16/32 only */
      struct declaration * d0 = NULL;
      struct declaration * d1 = NULL;
      const char *sreg = NULL;
      const char *dreg = NULL;
      const char *sreg2 = NULL;
      const char *dreg2 = NULL;

      d0 = c0->expr->declaration;
      d1 = c1->expr->declaration;
      assert(d0);

      if (d1 == NULL) {
            /* c1 is constant expr */
            return 0;
      }

      if (d0->storage == STORAGE_REGISTER 
            && d1->storage == STORAGE_REGISTER) {
            if (mod2 != NONE) {
                  dreg = arch_i286_get_reg2(d0, mod);
                  sreg = arch_i286_get_reg2(d1, mod);
                  dreg2 = arch_i286_get_reg2(d0, mod2);
                  sreg2 = arch_i286_get_reg2(d1, mod2);
                  if (strncmp(sreg2, dreg, 2) == 0 && 
                      strncmp(sreg, dreg2, 2) == 0) {
                        /* Register pairs ax_bx, bx_ax */
                        sprintf(buf1 + strlen(buf1),
                              "\txchgw %%%s, %%%s\n",
                              sreg, dreg);
                        return 1;
                  } else if (strncmp(sreg2, dreg, 2) == 0) {
                        /* Register pairs ax_BX, BX_cx */
                        sprintf(buf1 + strlen(buf1),
                              "\tmovw %%%s, %%%s\n"
                              "\tmovw %%%s, %%%s\n",
                              sreg2, dreg2,
                              sreg, dreg);
                        return 1;
                  }
            } else {
                  dreg = arch_i286_get_reg2(d0, mod);
                  sreg = arch_i286_get_reg2(d1, mod);
            }

            if (strncmp(sreg, dreg, 2) != 0) {
                  sprintf(buf1 + strlen(buf1),
                        "\tmovw %%%s, %%%s\n",
                        sreg, dreg);
            }
            if (mod2 != NONE) {
#if 0
                  dreg = arch_i286_get_reg2(d0, mod2);
                  sreg = arch_i286_get_reg2(d1, mod2);
#endif
                  if (strncmp(sreg2, dreg2, 2) != 0) {
                        sprintf(buf1 + strlen(buf1),
                              "\tmovw %%%s, %%%s\n",
                              sreg2, dreg2);
                  }
            }
            return 1;
      } else {
            return 0;
      }
}

struct constraint *
arch_i286_get_expr_constraint(
      struct stmt *s,
      unsigned int n
)
{
      struct constraint * c = NULL;

      for (c = s->output->first; c && n; c = c->next) {
            n--;
      }
      if (! c) {
            for (c = s->input->first; c && n; c = c->next) {
                  n--;
            }
      }
      assert(c);
      return c;
}

void
arch_i286_expr2_compare(
      char *buf1,
      struct stmt *s,
      struct expr *e,
      struct expr *lhs,
      struct type *t1
)
{
      struct constraint * c0 = NULL;
      struct constraint * c1 = NULL;
      struct constraint * c2 = NULL;
      struct constraint * c3 = NULL;

      c0 = arch_i286_get_expr_constraint(s, 0);
      c1 = arch_i286_get_expr_constraint(s, 1);
      c2 = arch_i286_get_expr_constraint(s, 2);
      c3 = arch_i286_get_expr_constraint(s, 3);

      switch (t1->type) {
      case TYPE_INT8:
      case TYPE_UINT8:
      case TYPE_INT16:
      case TYPE_UINT16:
            /* FIXME 
             * cx should be %1,
             * cl %b1, ch %h1
             */
            switch (t1->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  strcpy(buf1, "\txorw %cx, %cx\n");
                  strcat(buf1, "\tcmpb ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  strcpy(buf1, "\txorw %cx, %cx\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  break;
            default:
                  assert(0);
            }
            switch (t1->type) {
            case TYPE_INT8:
            case TYPE_INT16:
                  switch (e->type) {
                  case EXPR_EQUAL:
                        /* ZF == 1 */
                        strcat(buf1, "\tpushf\n");
                        strcat(buf1, "\tpop %cx\n");
                        strcat(buf1, "\tandw $0x40, %cx\n");
                        strcat(buf1, "\tcmpb $0x40, %cl\n");
                        strcat(buf1, "\tcmc\n");
                        strcat(buf1, "\trclb $0x1, %cl\n");
                        break;
                  case EXPR_NOT_EQUAL:
                        /* ZF == 0 */
                        strcat(buf1, "\tpushf\n");
                        strcat(buf1, "\tpop %cx\n");
                        strcat(buf1, "\tandw $0x40, %cx\n");
                        strcat(buf1, "\tcmpb $0x40, %cl\n");
                        strcat(buf1, "\trclb $0x1, %cl\n");
                        break;
                  case EXPR_LESS:
                        /* SF != OF */
                        strcat(buf1, "\tpushf\n");
                        strcat(buf1, "\tpop %cx\n");
                        strcat(buf1, "\tandw $0x0480, %cx\n");
                        strcat(buf1, "\tcmpw $0x01, %cx\n");
                        strcat(buf1, "\tcmc\n");
                        strcat(buf1, "\trclw $0x1, %cx\n");
                        strcat(buf1, "\tcmpb $0x11, %ch\n");
                        strcat(buf1, "\trclb $0x1, %ch\n");
                        strcat(buf1, "\tandb $0x1, %ch\n");
                        strcat(buf1, "\tandb %ch, %cl\n");
                        break;
                  case EXPR_LESS_EQUAL:
                        /* (ZF == 1) v (SF != OF) */
                        strcat(buf1, "\tpushf\n");
                        strcat(buf1, "\tpop %cx\n");
                        strcat(buf1, "\tandw $0x0440, %cx\n");
                        strcat(buf1, "\tcmpw $0x0440, %cx\n");
                        strcat(buf1, "\tcmc\n");
                        strcat(buf1, "\trclw $0x1, %cx\n");
                        strcat(buf1, "\tcmpw $0x0182, %cx\n");
                        strcat(buf1, "\trclb $0x1, %ch\n");
                        strcat(buf1, "\tandb $0x1, %ch\n");
                        strcat(buf1, "\torb %ch, %cl\n");
                        break;
                  case EXPR_GREATER:
                        /* (ZF == 0) ^ (SF == OF) */
                        strcat(buf1, "\tpushf\n");
                        strcat(buf1, "\tpop %cx\n");
                        strcat(buf1, "\tandw $0x0480, %cx\n");
                        strcat(buf1, "\tcmpw $0x01, %cx\n");
                        strcat(buf1, "\tcmc\n");
                        strcat(buf1, "\trclw $0x1, %cx\n");
                        strcat(buf1, "\tcmpb $0x1, %ch\n");
                        strcat(buf1, "\trclb $0x1, %ch\n");
                        strcat(buf1, "\tandb $0x1, %ch\n");
                        strcat(buf1, "\torb %ch, %cl\n");
                        break;
                  case EXPR_GREATER_EQUAL:
                        /* SF == OF */
                        strcat(buf1, "\tpushf\n");
                        strcat(buf1, "\tpop %cx\n");
                        strcat(buf1, "\tandw $0x0480, %cx\n");
                        strcat(buf1, "\tcmpw $0x01, %cx\n");
                        strcat(buf1, "\tcmc\n");
                        strcat(buf1, "\trclw $0x1, %cx\n");
                        strcat(buf1, "\tcmpb $0x11, %ch\n");
                        strcat(buf1, "\trclb $0x1, %ch\n");
                        strcat(buf1, "\tandb $0x1, %ch\n");
                        strcat(buf1, "\tandb %ch, %cl\n");
                        strcat(buf1, "\trcrw $0x1, %cx\n");
                        strcat(buf1, "\tcmc\n");
                        strcat(buf1, "\trclw $0x1, %cx\n");
                        break;
                  default:
                        assert(0);
                  }
                  break;
            case TYPE_UINT8:
            case TYPE_UINT16:
                  switch (e->type) {
                  case EXPR_EQUAL:
                        /* ZF == 1 */
                        strcat(buf1, "\tpushf\n");
                        strcat(buf1, "\tpop %cx\n");
                        strcat(buf1, "\tandw $0x40, %cx\n");
                        strcat(buf1, "\tcmpb $0x40, %cl\n");
                        strcat(buf1, "\trclb $0x1, %cl\n");
                        break;
                  case EXPR_NOT_EQUAL:
                        /* ZF == 0 */
                        strcat(buf1, "\tpushf\n");
                        strcat(buf1, "\tpop %cx\n");
                        strcat(buf1, "\tandw $0x40, %cx\n");
                        strcat(buf1, "\tcmpb $0x40, %cl\n");
                        strcat(buf1, "\tcmc\n");
                        strcat(buf1, "\trclb $0x1, %cl\n");
                        break;
                  case EXPR_GREATER_EQUAL:
                        /* CF == 0  */
                        strcat(buf1, "\tcmc\n");
                        strcat(buf1, "\trclb $0x1, %cl\n");
                        break;
                  case EXPR_LESS:
                        /* CF == 1  */
                        strcat(buf1, "\trclb $0x1, %cl\n");
                        break;
                  case EXPR_LESS_EQUAL:
                        /* CF == 1 v ZF == 1 */
                        strcat(buf1, "\tpushf\n");
                        strcat(buf1, "\tpop %cx\n");
                        strcat(buf1, "\tandw $0x41, %cx\n");
                        strcat(buf1, "\tcmpb $0x01, %cl\n");
                        strcat(buf1, "\tcmc\n");
                        strcat(buf1, "\trclb $0x1, %cl\n");
                        break;
                  case EXPR_GREATER:
                        /* CF == 0 ^ ZF == 0 */
                        strcat(buf1, "\tpushf\n");
                        strcat(buf1, "\tpop %cx\n");
                        strcat(buf1, "\tandw $0x41, %cx\n");
                        strcat(buf1, "\tcmpb $0x01, %cl\n");
                        strcat(buf1, "\trclb $0x1, %cl\n");
                        break;
                  default:
                        assert(0);
                  }
                  break;
            default:
                  assert(0);
            }
            strcat(buf1, "\tmovw ");
            arch_i286_set_registers(s, c0, c1, buf1, N, N);
            break;

      case TYPE_INT32:
            strcpy(buf1, "\tcmpw ");
            arch_i286_set_registers(s, c2, c3, buf1, W, W);

            switch (e->type) {
            case EXPR_EQUAL: 
                  /* ZF == 1 */
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x40, %cx\n");
                  strcat(buf1, "\tcmpb $0x40, %cl\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  break;
            case EXPR_NOT_EQUAL:
                  /* ZF == 0 */
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x40, %cx\n");
                  strcat(buf1, "\tcmpb $0x40, %cl\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  break;
            case EXPR_LESS:
                  /* SF != OF */
                  strcat(buf1, "\tjl 1f\n");
                  strcat(buf1, "\tjg 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x0480, %cx\n");
                  strcat(buf1, "\tcmpw $0x01, %cx\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclw $0x1, %cx\n");
                  strcat(buf1, "\tcmpb $0x11, %ch\n");
                  strcat(buf1, "\trclb $0x1, %ch\n");
                  strcat(buf1, "\tandb $0x1, %ch\n");
                  strcat(buf1, "\tandb %ch, %cl\n");
                  break;
            case EXPR_LESS_EQUAL:
                  /* (ZF == 1) v (SF != OF) */
                  strcat(buf1, "\tjl 1f\n");
                  strcat(buf1, "\tjg 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x0440, %cx\n");
                  strcat(buf1, "\tcmpw $0x0440, %cx\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclw $0x1, %cx\n");
                  strcat(buf1, "\tcmpw $0x0182, %cx\n");
                  strcat(buf1, "\trclb $0x1, %ch\n");
                  strcat(buf1, "\tandb $0x1, %ch\n");
                  strcat(buf1, "\torb %ch, %cl\n");
                  break;
            case EXPR_GREATER:
                  /* (ZF == 0) ^ (SF == OF) */
                  strcat(buf1, "\tjl 1f\n");
                  strcat(buf1, "\tjg 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x0480, %cx\n");
                  strcat(buf1, "\tcmpw $0x01, %cx\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclw $0x1, %cx\n");
                  strcat(buf1, "\tcmpb $0x1, %ch\n");
                  strcat(buf1, "\trclb $0x1, %ch\n");
                  strcat(buf1, "\tandb $0x1, %ch\n");
                  strcat(buf1, "\torb %ch, %cl\n");
                  break;
            case EXPR_GREATER_EQUAL:
                  /* SF == OF */
                  strcat(buf1, "\tjl 1f\n");
                  strcat(buf1, "\tjg 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x0480, %cx\n");
                  strcat(buf1, "\tcmpw $0x01, %cx\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclw $0x1, %cx\n");
                  strcat(buf1, "\tcmpb $0x11, %ch\n");
                  strcat(buf1, "\trclb $0x1, %ch\n");
                  strcat(buf1, "\tandb $0x1, %ch\n");
                  strcat(buf1, "\tandb %ch, %cl\n");
                  strcat(buf1, "\trcrw $0x1, %cx\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclw $0x1, %cx\n");
                  break;
            default:
                  assert(0);
            }
            strcat(buf1, "\tmovw ");
            arch_i286_set_registers(s, c0, c1, buf1, N, N);
            break;

      case TYPE_UINT32:
            strcpy(buf1, "\tcmpw ");
            arch_i286_set_registers(s, c2, c3, buf1, W, W);

            switch (e->type) {
            case EXPR_EQUAL:
                  /* ZF == 1 */
                  strcat(buf1, "\tje 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x40, %cx\n");
                  strcat(buf1, "\tcmpb $0x40, %cl\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  break;
            case EXPR_NOT_EQUAL:
                  /* ZF == 0 */
                  strcat(buf1, "\tje 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x40, %cx\n");
                  strcat(buf1, "\tcmpb $0x40, %cl\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  break;
            case EXPR_LESS:
                  /* CF == 1  */
                  strcat(buf1, "\tjb 1f\n");
                  strcat(buf1, "\tja 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x1, %cx\n");
                  break;
            case EXPR_LESS_EQUAL:
                  /* CF == 1 v ZF == 1 */
                  strcat(buf1, "\tjb 1f\n");
                  strcat(buf1, "\tja 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x41, %cx\n");
                  strcat(buf1, "\tcmpb $0x01, %cl\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  break;
            case EXPR_GREATER:
                  /* CF == 0 ^ ZF == 0 */
                  strcat(buf1, "\tjb 1f\n");
                  strcat(buf1, "\tja 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x41, %cx\n");
                  strcat(buf1, "\tcmpb $0x01, %cl\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  break;
            case EXPR_GREATER_EQUAL:
                  /* CF == 0  */
                  strcat(buf1, "\tja 1f\n");
                  strcat(buf1, "\tjb 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x1, %cx\n");
                  break;
            default:
                  assert(0);
            }
            strcat(buf1, "\tmovw ");
            arch_i286_set_registers(s, c0, c1, buf1, N, N);
            break;

      case TYPE_INT64:
            strcpy(buf1, "\tcmpw ");
            arch_i286_set_registers(s, c2, c3, buf1, V, V);

            switch (e->type) {
            case EXPR_EQUAL: 
                  /* ZF == 1 */
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");

                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x40, %cx\n");
                  strcat(buf1, "\tcmpb $0x40, %cl\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  strcat(buf1, "\tandw $0x1, %cx\n");
                  break;
            case EXPR_NOT_EQUAL:
                  /* ZF == 0 */
                  strcat(buf1, "\tje 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tje 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tje 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");

                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x40, %cx\n");
                  strcat(buf1, "\tcmpb $0x40, %cl\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  strcat(buf1, "\tandw $0x1, %cx\n");
                  break;
            case EXPR_LESS:
                  /* SF != OF */
                  strcat(buf1, "\tjg 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tjg 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tjg 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");

                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x0480, %cx\n");
                  strcat(buf1, "\tcmpw $0x01, %cx\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclw $0x1, %cx\n");
                  strcat(buf1, "\tcmpb $0x11, %ch\n");
                  strcat(buf1, "\trclb $0x1, %ch\n");
                  strcat(buf1, "\tandb $0x1, %ch\n");
                  strcat(buf1, "\tandb %ch, %cl\n");
                  break;
            case EXPR_LESS_EQUAL:
                  /* (ZF == 1) v (SF != OF) */
                  strcat(buf1, "\tjg 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tjg 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tjg 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");

                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x0440, %cx\n");
                  strcat(buf1, "\tcmpw $0x0440, %cx\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclw $0x1, %cx\n");
                  strcat(buf1, "\tcmpw $0x0182, %cx\n");
                  strcat(buf1, "\trclb $0x1, %ch\n");
                  strcat(buf1, "\tandb $0x1, %ch\n");
                  strcat(buf1, "\torb %ch, %cl\n");
                  break;
            case EXPR_GREATER:
                  /* (ZF == 0) ^ (SF == OF) */
                  strcat(buf1, "\tjl 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tjl 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tjl 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");

                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x0480, %cx\n");
                  strcat(buf1, "\tcmpw $0x01, %cx\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclw $0x1, %cx\n");
                  strcat(buf1, "\tcmpb $0x1, %ch\n");
                  strcat(buf1, "\trclb $0x1, %ch\n");
                  strcat(buf1, "\tandb $0x1, %ch\n");
                  strcat(buf1, "\torb %ch, %cl\n");
                  break;
            case EXPR_GREATER_EQUAL:
                  /* SF == OF */
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");

                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x0480, %cx\n");
                  strcat(buf1, "\tcmpw $0x01, %cx\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclw $0x1, %cx\n");
                  strcat(buf1, "\tcmpb $0x11, %ch\n");
                  strcat(buf1, "\trclb $0x1, %ch\n");
                  strcat(buf1, "\tandb $0x1, %ch\n");
                  strcat(buf1, "\tandb %ch, %cl\n");
                  strcat(buf1, "\trcrw $0x1, %cx\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclw $0x1, %cx\n");
                  break;
            default:
                  assert(0);
            }
            strcat(buf1, "\tmovw ");
            arch_i286_set_registers(s, c0, c1, buf1, N, N);
            break;

      case TYPE_UINT64:
            strcpy(buf1, "\tcmpw ");
            arch_i286_set_registers(s, c2, c3, buf1, V, V);

            switch (e->type) {
            case EXPR_EQUAL:
                  /* ZF == 1 */
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x40, %cx\n");
                  strcat(buf1, "\tcmpb $0x40, %cl\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  strcat(buf1, "\tandw $0x1, %cx\n");
                  break;
            case EXPR_NOT_EQUAL:
                  /* ZF == 0 */
                  strcat(buf1, "\tje 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tje 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tje 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x40, %cx\n");
                  strcat(buf1, "\tcmpb $0x40, %cl\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  strcat(buf1, "\tandw $0x1, %cx\n");
                  break;
            case EXPR_LESS:
                  /* CF == 1  */
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x1, %cx\n");
                  break;
            case EXPR_LESS_EQUAL:
                  /* CF == 1 v ZF == 1 */
                  strcat(buf1, "\tja 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tja 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tja 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x41, %cx\n");
                  strcat(buf1, "\tcpb $0x01, %cl\n");
                  strcat(buf1, "\tcmc\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  break;
            case EXPR_GREATER:
                  /* CF == 0 ^ ZF == 0 */
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x41, %cx\n");
                  strcat(buf1, "\tcmpb $0x01, %cl\n");
                  strcat(buf1, "\trclb $0x1, %cl\n");
                  break;
            case EXPR_GREATER_EQUAL:
                  /* CF == 0  */
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, U, U);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, W, W);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c2, c3, buf1, N, N);
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tpushf\n");
                  strcat(buf1, "\tpop %cx\n");
                  strcat(buf1, "\tandw $0x1, %cx\n");
                  break;
            default:
                  assert(0);
            }
            strcat(buf1, "\tmovw ");
            arch_i286_set_registers(s, c0, c1, buf1, N, N);
            break;

      case TYPE_FLOAT64:
      case TYPE_FLOAT80:
            assert(0);

      default:
            assert(0);
      }
}

void
arch_i286_expr2_mov64(
      char *buf1,
      struct stmt *s,
      struct expr *e,
      struct expr *lhs,
      struct type *t,
      unsigned int iconst
)
{
      struct constraint * c0 = NULL;
      struct constraint * c1 = NULL;
      int iRet;

      c0 = arch_i286_get_expr_constraint(s, 0);
      c1 = arch_i286_get_expr_constraint(s, 1);

      if (e->type == EXPR_IDENTIFIER
            && e->declaration->storage == STORAGE_NONE) {
            /* variable -> regs */
            /* movw %1, %0
               movw %1+2, %w0
               movw %1+4, %u0
               movw %1+6, %v0 */
            strcpy(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, VAR_S);
            strcat(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, W, 2, VAR_S);
            strcat(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, U, 4, VAR_S);
            strcat(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, V, 6, VAR_S);
      } else if (e->type == EXPR_IDENTIFIER
            && lhs->declaration->storage == STORAGE_NONE) {
            /* regs -> variable */
            /* movw %1, %0
               movw %w1, %0+2
               movw %u1, %0+4
               movw %v1, %0+6 */
            strcpy(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, VAR_D);
            strcat(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, W, 2, VAR_D);
            strcat(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, U, 4, VAR_D);
            strcat(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, V, 6, VAR_D);
      } else if (iconst == 1) {
            switch (e->type_name->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* movw %1, %0 */
                  strcpy(buf1, "\tmovw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  if (lhs->declaration->storage == STORAGE_NONE) {
                        /* const -> variable */
                        /* movw %1, %0
                           movw %w1, %0+2 */
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_ind_mem(s, c0, c1,buf1,N,0,VAR_D);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_ind_mem(s, c0, c1,buf1,W,2,VAR_D);
                  } else {
                        /* movw %1, %0
                           movw %w1, %w0 */
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  }
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  if (lhs->declaration->storage == STORAGE_NONE) {
                        /* const -> variable */
                        /* movw %1, %0
                           movw %w1, %0+2
                           movw %u1, %0+4
                           movw %v1, %0+6 */
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_ind_mem(s, c0, c1,buf1,N,0,VAR_D);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_ind_mem(s, c0, c1,buf1,W,2,VAR_D);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_ind_mem(s, c0, c1,buf1,U,4,VAR_D);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_ind_mem(s, c0, c1,buf1,V,6,VAR_D);
                  } else {
                        /* movw %1, %0
                           movw %w1, %w0
                           movw %u1, %u0
                           movw %v1, %v0 */
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, W, W);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, U, U);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  }
                  break;
            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
      } else {
            /* movw %1, %0
               movw %w1, %w0
               movw %u1, %u0
               movw %v1, %v0 */
            iRet = arch_i286_omit_mov(buf1, c0, c1, N, W);
            if (iRet == 0) {
                  strcpy(buf1, "\tmovw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  strcat(buf1, "\tmovw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
            }
            iRet = arch_i286_omit_mov(buf1, c0, c1, U, V);
            if (iRet == 0) {
                  sprintf(buf1 + strlen(buf1),"\tmovw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),"\tmovw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
            }
      }
}


void
arch_i286_expr2_mov32(
      char *buf1,
      struct stmt *s,
      struct expr *e,
      struct expr *lhs,
      struct type *t,
      unsigned int iconst
)
{
      struct constraint * c0 = NULL;
      struct constraint * c1 = NULL;

      c0 = arch_i286_get_expr_constraint(s, 0);
      c1 = arch_i286_get_expr_constraint(s, 1);

      if (e->type == EXPR_IDENTIFIER
            && e->declaration->storage == STORAGE_NONE) {
            /* variable -> regs */
            /* movw %1, %0
               movw %1+2, %w0 */
            strcpy(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, VAR_S);
            strcat(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, W, 2, VAR_S);
      } else if (e->type == EXPR_IDENTIFIER
            && lhs->declaration->storage == STORAGE_NONE) {
            /* regs -> variable */
            /* movw %1, %0
               movw %w1, %0+2 */
            strcpy(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, VAR_D);
            strcat(buf1, "\tmovw ");
            arch_i286_set_ind_mem(s, c0, c1, buf1, W, 2, VAR_D);
      } else if (iconst == 1) {
            switch (e->type_name->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* movw %1, %0 */
                  strcpy(buf1, "\tmovw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  if (lhs->declaration->storage == STORAGE_NONE) {
                        /* const -> variable */
                        /* movw %1, %0
                           movw %w1, %0+2 */
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_ind_mem(s, c0, c1,buf1,N,0,VAR_D);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_ind_mem(s, c0, c1,buf1,W,2,VAR_D);
                  } else {
                        /* movw %1, %0
                           movw %w1, %w0 */
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  }
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  assert(0);
            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
      } else {
            /* movw %1, %0
               movw %w1, %w0 */
            if (arch_i286_omit_mov(buf1, c0, c1, N, W)) {
                  return;
            }

            strcpy(buf1, "\tmovw ");
            arch_i286_set_registers(s, c0, c1, buf1, N, N);
            strcat(buf1, "\tmovw ");
            arch_i286_set_registers(s, c0, c1, buf1, W, W);
      }
}

void
arch_i286_gen_expr_2(
      char *buf1,
      struct stmt *block,
      struct stmt *s,
      struct expr *e,
      struct expr *lhs
)
{
      struct expr *ce = NULL;
      struct type *t = NULL;
      struct type *t1 = NULL;
      struct constraint *c = NULL;
      struct constraint * c0 = NULL;
      struct constraint * c1 = NULL;
      struct constraint * c2 = NULL;
      struct constraint * c3 = NULL;

      unsigned int size = 0;
      unsigned int n = 0;
      unsigned int iconst = 0;


      t = expr_typeof(block->scope, e);
      t = type_pure(t);

      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:
            assert(0);
      case EXPR_ASSIGN:
            assert(0);
      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_NOT:
      case EXPR_SHORT_AND:
      case EXPR_SHORT_OR:
      case EXPR_CONDITION:
      case EXPR_LIST:
            assert(0);

      case EXPR_STRING:
            assert(0);


      case EXPR_INTEGER:
      case EXPR_REAL:
            iconst = 1;
      case EXPR_IDENTIFIER:
      case EXPR_AMPHERSAND:
#if 0
            if (e->type == EXPR_IDENTIFIER
             && e->declaration->storage == STORAGE_REGISTER
             && lhs->type == EXPR_IDENTIFIER
             && lhs->declaration->storage == STORAGE_REGISTER
             && e->declaration->storage_register
                        == lhs->declaration->storage_register) {
                  /* Omit instructions "mov %x, %x". */
                  strcpy(buf1, "");
                  break;
            }
#endif
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* movb %1, %0 */
                  c0 = arch_i286_get_expr_constraint(s, 0);
                  c1 = arch_i286_get_expr_constraint(s, 1);
      
                  if (i286_omit_simple_mov(buf1, c0, c1, N, N)) {
                        break;
                  }
      
                  strcpy(buf1, "\tmovb ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  break;
            case TYPE_VA_LIST:
                  /* FIXME - do not generate 'movw %xx, %es' */
                  c0 = arch_i286_get_expr_constraint(s, 0);
                  c1 = arch_i286_get_expr_constraint(s, 1);

                  strcpy(buf1, "\tMovw ");
                  arch_i286_set_register(s, c1, buf1, W, 0);
                  strcat(buf1, ", %es\n");

                  if (i286_omit_simple_mov(buf1, c0, c1, N, N)) {
                        break;
                  }

                  strcat(buf1, "\tmovw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  #if _DEBUG_MOV > 3
                        fprintf(stderr, "MOV16\n");
                  #endif
                  /* movw %1, %0 */
                  c0 = arch_i286_get_expr_constraint(s, 0);
                  c1 = arch_i286_get_expr_constraint(s, 1);
      
                  if (i286_omit_simple_mov(buf1, c0, c1, N, N)) {
                        break;
                  }

                  strcpy(buf1, "\tmovw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  #if _DEBUG_MOV > 2
                        fprintf(stderr, "MOV32\n");
                  #endif
                  arch_i286_expr2_mov32(buf1, s, e, lhs, t, iconst);
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  #if _DEBUG_MOV > 1
                        fprintf(stderr, "MOV64\n");
                  #endif
                  arch_i286_expr2_mov64(buf1, s, e, lhs, t, iconst);
                  break;

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;

      case EXPR_BUILTIN_VA_ARG:
            #if _DEBUG > 1
                  fprintf(stderr, "EXPR_BUILTIN_VA_ARG\n");
            #endif
            t1 = e->type_name;

            switch (t1->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* movb es:(%1), %0
                     addw $1, %1 */
                  c0 = arch_i286_get_expr_constraint(s, 0);
                  c1 = arch_i286_get_expr_constraint(s, 1);
      
                  strcpy(buf1, "\tmovw ");
                  arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, IND_S);
                  strcat(buf1, "\taddw $1, ");
                  arch_i286_set_register(s, c1, buf1, N, 1);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* movw es:(%1), %0
                     addw $2, %1 */
                  c0 = arch_i286_get_expr_constraint(s, 0);
                  c1 = arch_i286_get_expr_constraint(s, 1);
      
                  strcpy(buf1, "\tmovw ");
                  arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, IND_S);
                  strcat(buf1, "\tAddw $2, ");
                  arch_i286_set_register(s, c1, buf1, N, 1);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  /* movw es:(%1), %0
                     addw $2, %1
                     movw es:(%1), %w0
                     addw $2, %1 */
                  /* FIXME: pointer is only 16bit here...??? */
                  c0 = arch_i286_get_expr_constraint(s, 0);
                  c1 = arch_i286_get_expr_constraint(s, 1);

                  strcpy(buf1, "\tmovw ");
                  arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, IND_S);
                  strcat(buf1, "\taddw $0x2, ");
                  arch_i286_set_register(s, c1, buf1, N, 1);
                  strcat(buf1, "\tmovw ");
#if 0
                  arch_i286_set_ind_mem(s, c0, c1, buf1, W, 2, IND_S);
#else
                  // no offset
                  arch_i286_set_ind_mem(s, c0, c1, buf1, W, 0, IND_S);
#endif
                  strcat(buf1, "\taddw $2, ");
                  arch_i286_set_register(s, c1, buf1, N, 1);
                  break;

            case TYPE_INT64:
            case TYPE_UINT64:
                  assert(0);

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;

      case EXPR_TYPE_CONVERSION:
            #if _DEBUG > 1
                  fprintf(stderr, "EXPR_TYPE_CONVERSION\n");
            #endif
            /*
             * MOVZB - FIXME
             */
            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:
                        /* movb %1, %0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);
            
                        if (i286_omit_simple_mov(buf1, c0, c1, N, N)) {
                              break;
                        }
      
                        strcpy(buf1, "\tmovb ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
                        break;
                  case TYPE_INT16:
                  case TYPE_UINT16:
                  case TYPE_INT32:
                  case TYPE_UINT32:
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        /* movb %b1, %0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);
            
                        if (i286_omit_simple_mov(buf1, c0, c1, B, N)) {
                              break;
                        }

                        strcpy(buf1, "\tmovb ");
                        arch_i286_set_registers(s, c0, c1, buf1, B, N);
                        break;

                  case TYPE_FLOAT32:
                  case TYPE_FLOAT64:
                  case TYPE_FLOAT80:
                        assert(0);
                  default:
                        assert(0);
                  }
                  break;

            case TYPE_INT16:
            case TYPE_UINT16:
                  switch (t1->type) {
                  case TYPE_INT8:
                        strcpy(buf1, "\tcbw\n");
                        break;      
                  case TYPE_UINT8:
                        /* xorb %b1, %b0
                           movb %1, %b0*/
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        strcpy(buf1, "\txorb ");
                        arch_i286_set_registers(s, c0, c0, buf1, H, H);

                        if (i286_omit_simple_mov(buf1, c0, c1, N, B)) {
                              break;
                        }
                        strcat(buf1, "\tmovb ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, B);
                        break;

                  case TYPE_INT16:
                  case TYPE_UINT16:
                  case TYPE_INT32:
                  case TYPE_UINT32:
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        /* movw %1, %0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        if (i286_omit_simple_mov(buf1, c0, c1, N, N)) {
                              break;
                        }
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
                        break;

                  case TYPE_FLOAT32:
                  case TYPE_FLOAT64:
                  case TYPE_FLOAT80:
                        assert(0);

                  case TYPE_POINTER:
                        /* FIXME */
#if 0
                        c = s->input->first;
                        assert(c);
                        if (c->expr->type == EXPR_IDENTIFIER) {
                              d = c->expr->declaration;
                              assert(d);
                              if (d->storage == STORAGE_REGISTER) {
                              /* dont generate lea !reg!, xxx */
                                    strcpy(buf1, "");
                                    break;
                              }
                        }
#endif
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        if (arch_i286_is_local(e)) {
                              /* use lea for function local variables
*/
                              /* leaw %1, %0 */
                              strcpy(buf1, "\tleaw ");
                        } else {
                              /* movw %1, %0 */
                              strcpy(buf1, "\tmovw ");
                        }
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
                        break;

                  default:
                        assert(0);
                  }
                  break;

            case TYPE_INT32:
            case TYPE_UINT32:
                  switch (t1->type) {
                  case TYPE_INT8:
                        strcpy(buf1, "\tcbw\n");
                        strcat(buf1, "\tcwd\n");
                        break;
                  case TYPE_UINT8:
                        /* movb %1, %b0
                           xorb %h0, %h0
                           xorw %w1, %w0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        i286_omit_simple_mov(buf1, c0, c1, N, B);

                        sprintf(buf1 + strlen(buf1),"\txorb ");
                        arch_i286_set_registers(s, c0, c0, buf1, H, H);
                        strcat(buf1, "\txorw ");
                        arch_i286_set_registers(s, c0, c0, buf1, W, W);
                        break;
                  case TYPE_INT16:
                        /* movw %1, %0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        if (i286_omit_simple_mov(buf1, c0, c1, N, N)) {
                              sprintf(buf1 + strlen(buf1),"\tcwd\n");
                              break;;
                        }
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
                        strcat(buf1, "\tcwd\n");
                        break;
                  case TYPE_UINT16:
                        /* movw %1, %0 
                           xorw %w0, %w0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        if (i286_omit_simple_mov(buf1, c0, c1, N, N)) {
                              sprintf(buf1 + strlen(buf1),"\txorw ");
                              arch_i286_set_registers(s, c0, c0,
                                                buf1, W, W);
                              break;
                        }
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
                        strcat(buf1, "\txorw ");
                        arch_i286_set_registers(s, c0, c0, buf1, W, W);
                        break;
                  case TYPE_INT32:
                  case TYPE_UINT32:
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        /* movw %1, %0
                           movw %w1, %w0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        if (arch_i286_omit_mov(buf1, c0, c1, N, W)) {
                              break;
                        }
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, W, W);
                        break;

                  case TYPE_POINTER:
                        /* FIXME */
                        /* movw %1, %0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        if (arch_i286_is_local(e)) {
                              strcpy(buf1, "\tleaw ");
                        } else {
                              strcpy(buf1, "\tmovw ");
                        }
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
#if 1
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, W, W);
#endif
                        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 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        strcpy(buf1, "\tcbw\n");
                        strcat(buf1, "\tcwd\n");
                        strcat(buf1, "\tmovw %dx, ");
                        arch_i286_set_register(s, c0, buf1, U, 1);
                        strcat(buf1, "\tmovw %dx, ");
                        arch_i286_set_register(s, c0, buf1, V, 1);
                        break;
                  case TYPE_UINT8:
                        /* movb %1, %b0
                           xorb %h0, %h0
                           xorw %w0, %w0
                           xorw %u0, %u0
                           xorw %v0, %v0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        i286_omit_simple_mov(buf1, c0, c1, N, B);

                        sprintf(buf1 + strlen(buf1),"\txorb ");
                        arch_i286_set_registers(s, c0, c0, buf1, H, H);
                        strcat(buf1, "\txorw ");
                        arch_i286_set_registers(s, c0, c0, buf1, W, W);
                        strcat(buf1, "\txorw ");
                        arch_i286_set_registers(s, c0, c0, buf1, U, U);
                        strcat(buf1, "\txorw ");
                        arch_i286_set_registers(s, c0, c0, buf1, V, V);
                        break;
                  case TYPE_INT16:
                        /* cwd
                           movw %%dx, %u0
                           movw %%dx, %v0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);

                        strcpy(buf1, "\tcwd\n");
                        strcat(buf1, "\tmovw %dx, ");
                        arch_i286_set_register(s, c0, buf1, U, 1);
                        strcat(buf1, "\tmovw %dx, ");
                        arch_i286_set_register(s, c0, buf1, V, 1);
                        break;
                  case TYPE_UINT16:
                        /* movw %1, %0
                           xorw %w0, %w0
                           xorw %u0, %u0
                           xorw %v0, %v0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        i286_omit_simple_mov(buf1, c0, c1, N, N);

                        sprintf(buf1 + strlen(buf1),"\txorw ");
                        arch_i286_set_registers(s, c0, c0, buf1, W, W);
                        strcat(buf1, "\txorw ");
                        arch_i286_set_registers(s, c0, c0, buf1, U, U);
                        strcat(buf1, "\txorw ");
                        arch_i286_set_registers(s, c0, c0, buf1, V, V);
                        break;
                  case TYPE_INT32:
                        /* movw %1, %v0
                           movw %w1, %0
                           cwd
                           xchgw %w0, %v0
                           xchgw %w0, %0
                           movw %v0, %u0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, V);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, W, N);
                        strcat(buf1, "\tcwd\n");
                        strcat(buf1, "\txchgw ");
                        arch_i286_set_registers(s, c0, c0, buf1, W, V);
                        strcat(buf1, "\txchgw ");
                        arch_i286_set_registers(s, c0, c0, buf1, W, N);
                        strcat(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c0, buf1, V, U);
                        break;
                  case TYPE_UINT32:
                        /* movw %1, %0
                           xorw %u0, %u0
                           xorw %v0, %v0
                           movw %w1, %w0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        i286_omit_simple_mov(buf1, c0, c1, N, N);

                        sprintf(buf1 + strlen(buf1),"\txorw ");
                        arch_i286_set_registers(s, c0, c0, buf1, U, U);
                        strcat(buf1, "\txorw ");
                        arch_i286_set_registers(s, c0, c0, buf1, V, V);

                        i286_omit_simple_mov(buf1, c0, c1, W, W);
                        break;
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        strcpy(buf1, "");
                        break;
                  case TYPE_POINTER:
                        /* FIXME */
                        /* movw %1, %0 */
                        c0 = arch_i286_get_expr_constraint(s, 0);
                        c1 = arch_i286_get_expr_constraint(s, 1);

                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_registers(s, c0, c1, buf1, N, N);
                        break;

                  default:
                        assert(0);
                  }
                  break;

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);

            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  */
                  c0 = arch_i286_get_expr_constraint(s, 0);
                  c1 = arch_i286_get_expr_constraint(s, 1);

                  if (IsPointer32b()) {
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_register(s, c1, buf1, W, 0);      
                        strcat(buf1, ", %es\n");
                        strcat(buf1, "\tmovb ");
                  } else {
                        strcpy(buf1, "\tmovb ");
                  }
                  arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, IND_S);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* [movw %w1, %es]      */
                  /* movw [%es:](%1), %0  */
                  c0 = arch_i286_get_expr_constraint(s, 0);
                  c1 = arch_i286_get_expr_constraint(s, 1);

                  if (IsPointer32b()) {
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_register(s, c1, buf1, W, 0);      
                        strcat(buf1, ", %es\n");
                        strcat(buf1, "\tmovw ");
                  } else {
                        strcpy(buf1, "\tmovw ");
                  }
                  arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, IND_S);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  #if _DEBUG_MOV > 1
                        fprintf(stderr, "(MOV32)\n");
                  #endif
                  /* [movw %w1, %es]      */
                  /* movw [%es:](%1), %0  */
                  /* addw $0x2, %1 FIXME  */
                  /* movw es:(%1), %w0    */
                  c0 = arch_i286_get_expr_constraint(s, 0);
                  c1 = arch_i286_get_expr_constraint(s, 1);
      
                  if (IsPointer32b()) {
                        strcpy(buf1, "\tmovw ");
                        arch_i286_set_register(s, c1, buf1, W, 0);      
                        strcat(buf1, ", %es\n");
                        strcat(buf1, "\tmovw ");
                  } else {
                        strcpy(buf1, "\tmovw ");
                  }
                  arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, IND_S);
                  strcat(buf1, "\taddw $0x2, ");
                  arch_i286_set_register(s, c1, buf1, N, 1);
                  strcat(buf1, "\tmovw ");
#if 0
                  arch_i286_set_ind_mem(s, c0, c1, buf1, W, 2, IND_S);
#else
                  // no offset
                  arch_i286_set_ind_mem(s, c0, c1, buf1, W, 0, IND_S);
#endif
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  /* movw (%1), %0
                     movw 2(%1), %w0
                     movw 4(%1), %u0
                     movw 6(%1), %v0 */
                  c0 = arch_i286_get_expr_constraint(s, 0);
                  c1 = arch_i286_get_expr_constraint(s, 1);
      
                  strcpy(buf1, "\tmovw ");
                  arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, IND_S);
                  strcat(buf1, "\tmovw ");
                  arch_i286_set_ind_mem(s, c0, c1, buf1, W, 2, IND_S);
                  strcat(buf1, "\tmovw ");
                  arch_i286_set_ind_mem(s, c0, c1, buf1, U, 4, IND_S);
                  strcat(buf1, "\tmovw ");
                  arch_i286_set_ind_mem(s, c0, c1, buf1, V, 6, IND_S);
                  break;

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
                  break;

            default:
                  assert(0);
            }
            break;

      case EXPR_NEG:
            c0 = arch_i286_get_expr_constraint(s, 0);

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* negb %0 */
                  strcpy(buf1, "\tnegb ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* negw %0 */
                  strcpy(buf1, "\tnegw ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  /* negw %0
                     negw %w0 */
                  strcpy(buf1, "\tnegw ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  strcat(buf1, "\tnegw ");
                  arch_i286_set_register(s, c0, buf1, W, 1);
                  break;

            case TYPE_INT64:
            case TYPE_UINT64:
                  /* negw %0
                     negw %w0
                     negw %u0
                     negw %v0 */
                  strcpy(buf1, "\tnegw ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  strcat(buf1, "\tnegw ");
                  arch_i286_set_register(s, c0, buf1, W, 1);
                  strcat(buf1, "\tnegw ");
                  arch_i286_set_register(s, c0, buf1, U, 1);
                  strcat(buf1, "\tnegw ");
                  arch_i286_set_register(s, c0, buf1, V, 1);
                  break;

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }

      case EXPR_INV:
            c0 = arch_i286_get_expr_constraint(s, 0);

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* xorb $-1, %0 */
                  strcpy(buf1, "\txorb $-1, ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* xorw $-1, %0 */
                  strcpy(buf1, "\txorw $-1, ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  break;

            case TYPE_INT32:
            case TYPE_UINT32:
                  /* xorw $-1, %0
                     xorw $-1, %w0 */
                  strcpy(buf1, "\txorw $-1, ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  strcat(buf1, "\txorw $-1, ");
                  arch_i286_set_register(s, c0, buf1, W, 1);
                  break;

            case TYPE_INT64:
            case TYPE_UINT64:
                  /* xorw $-1, %0
                     xorw $-1, %w0
                     xorw $-1, %u0
                     xorw $-1, %v0 */
                  strcpy(buf1, "\txorw $-1, ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  strcat(buf1, "\txorw $-1, ");
                  arch_i286_set_register(s, c0, buf1, W, 1);
                  strcat(buf1, "\txorw $-1, ");
                  arch_i286_set_register(s, c0, buf1, U, 1);
                  strcat(buf1, "\txorw $-1, ");
                  arch_i286_set_register(s, c0, buf1, V, 1);
                  break;

            default:
                  assert(0);
            }
            break;

      case EXPR_ADD:
            c0 = arch_i286_get_expr_constraint(s, 0);
            c2 = arch_i286_get_expr_constraint(s, 2);

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* addb %2, %0 */
                  strcpy(buf1, "\taddb ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* addw %2, %0 */
                  strcpy(buf1, "\taddw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  /* addw %2, %0
                     adcw %w2, %w0 */
                  strcpy(buf1, "\taddw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  strcat(buf1, "\tadcw ");
                  arch_i286_set_registers(s, c0, c2, buf1, W, W);
                  break;

            case TYPE_INT64:
            case TYPE_UINT64:
                  /* addw %2, %0
                     adcw %w2, %w0
                     adcw %u2, %u0
                     adcw %v2, %v0 */
                  strcpy(buf1, "\taddw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  strcat(buf1, "\tadcw ");
                  arch_i286_set_registers(s, c0, c2, buf1, W, W);
                  strcat(buf1, "\tadcw ");
                  arch_i286_set_registers(s, c0, c2, buf1, U, U);
                  strcat(buf1, "\tadcw ");
                  arch_i286_set_registers(s, c0, c2, buf1, V, V);
                  break;

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;
      case EXPR_SUB:
            c0 = arch_i286_get_expr_constraint(s, 0);
            c2 = arch_i286_get_expr_constraint(s, 2);

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* subb %2, %0 */
                  strcpy(buf1, "\tsubb ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* subw %2, %0 */
                  strcpy(buf1, "\tsubw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  /* subw %2, %0
                     sbbw %w2, %w0 */
                  strcpy(buf1, "\tsubw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  strcat(buf1, "\tsbbw ");
                  arch_i286_set_registers(s, c0, c2, buf1, W, W);
                  break;
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  /* subw %2, %0
                     sbbw %w2, %w0
                     sbbw %u2, %u0
                     sbbw %v2, %v0 */
                  strcpy(buf1, "\tsubw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  strcat(buf1, "\tsbbw ");
                  arch_i286_set_registers(s, c0, c2, buf1, W, W);
                  strcat(buf1, "\tsbbw ");
                  arch_i286_set_registers(s, c0, c2, buf1, U, U);
                  strcat(buf1, "\tsbbw ");
                  arch_i286_set_registers(s, c0, c2, buf1, V, V);
                  break;      

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;

      case EXPR_MUL:
            c2 = arch_i286_get_expr_constraint(s, 2);

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* mulb %2 */
                  strcpy(buf1, "\tmulb ");
                  arch_i286_set_register(s, c2, buf1, N, 1);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* mulw %2 */
                  strcpy(buf1, "\tmulw ");
                  arch_i286_set_register(s, c2, buf1, N, 1);
                  break;

            case TYPE_INT32:
            case TYPE_UINT32:
                  assert(0);

            case TYPE_INT64:
            case TYPE_UINT64:
                  assert(0);

            case TYPE_FLOAT32:
            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);

            default:
                  assert(0);
            }
            break;

      case EXPR_DIV:
            c2 = arch_i286_get_expr_constraint(s, 2);
            c3 = arch_i286_get_expr_constraint(s, 3);

            switch (t->type) {
            case TYPE_INT8:
                  /* cbw
                     divb %2 */
                  strcpy(buf1, "\tcbw\n");
                  strcat(buf1, "\tdivb ");
                  arch_i286_set_register(s, c2, buf1, N, 1);
                  break;
            case TYPE_INT16:
                  /* cwd
                     idivw %2 */
                  strcpy(buf1, "\tcwd\n");
                  strcat(buf1, "\tidivw ");
                  arch_i286_set_register(s, c3, buf1, N, 1);
                  break;
            case TYPE_UINT8:
                  /* xorb %%ah, %%ah
                     divb %2 */
                  strcpy(buf1, "\txorb %ah, %ah\n");
                  strcat(buf1, "\tdivb ");
                  arch_i286_set_register(s, c2, buf1, N, 1);
                  break;
            case TYPE_UINT16:
                  /* xorw %dx, %dx
                     divw %2 */
                  strcpy(buf1, "\txorw %dx, %dx\n");
                  strcat(buf1, "\tdivw ");
                  arch_i286_set_register(s, c3, buf1, N, 1);
                  break;

            case TYPE_INT32:
            case TYPE_UINT32:
                  assert(0);
            case TYPE_INT64:
            case TYPE_UINT64:
                  assert(0);

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);

            default:
                  assert(0);
            }
            break;

      case EXPR_MOD:
            c2 = arch_i286_get_expr_constraint(s, 2);

            switch (t->type) {
            case TYPE_INT8:
                  /* cbw
                     divb %2 */
                  strcpy(buf1, "\tcbw\n");
                  strcat(buf1, "\tdivb ");
                  arch_i286_set_register(s, c2, buf1, N, 1);
                  break;
            case TYPE_INT16:
                  /* cwd
                     idivw %2 */
                  strcpy(buf1, "\tcwd\n");
                  strcat(buf1, "\tidivw ");
                  arch_i286_set_register(s, c2, buf1, N, 1);
                  break;
            case TYPE_UINT8:
                  /* xorb %%ah, %%ah
                     divb %2 */
                  strcpy(buf1, "\txorb %ah, %ah\n");
                  strcat(buf1, "\tdivb ");
                  arch_i286_set_register(s, c2, buf1, N, 1);
                  break;
            case TYPE_UINT16:
                  /* xorw %dx, %dx
                     divw %2 */
                  strcpy(buf1, "\txorw %dx, %dx\n");
                  strcat(buf1, "\tdivw ");
                  arch_i286_set_register(s, c2, buf1, N, 1);
                  break;

            case TYPE_INT32:
            case TYPE_UINT32:
                  assert(0);
            case TYPE_INT64:
            case TYPE_UINT64:
                  assert(0);

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);

            default:
                  assert(0);
            }
            break;

      case EXPR_LEFT:
            /* FIXME optimize */
            c0 = arch_i286_get_expr_constraint(s, 0);
            c2 = arch_i286_get_expr_constraint(s, 2);

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* shlb %b2, %0 */
                  strcpy(buf1, "\tshlb ");
                  arch_i286_set_registers(s, c0, c2, buf1, B, N);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* shlw %b2, %0 */
                  strcpy(buf1, "\tshlw ");
                  arch_i286_set_registers(s, c0, c2, buf1, B, N);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  /* movb %b2, %ch
                     movb $1, %cl
                     1:
                     shlw %cl, %0
                     rclw %cl, %w0
                     dec %ch
                     cmpb $0, %ch
                     jnz 1b */
                  strcpy(buf1, "\tmovb ");
                  arch_i286_set_register(s, c2, buf1, B, 0);
                  strcat(buf1, ", %ch\n");
                  strcat(buf1, "\tmovb $1, %cl\n");
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tshlw %cl, ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  strcat(buf1, "\trclw %cl, ");
                  arch_i286_set_register(s, c0, buf1, W, 1);
                  strcat(buf1, "\tdec %ch\n");
                  strcat(buf1, "\tcmpb $0, %ch\n");
                  strcat(buf1, "\tjnz 1b\n");
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  /* movb %b2, %ch
                     movb $1, %cl
                     1:
                     shlw %cl, %0
                     rclw %cl, %w0
                     rclw %cl, %u0
                     rclw %cl, %v0
                     dec %ch
                     cmpb $0, %ch
                     jnz 1b */
                  strcpy(buf1, "\tmovb ");
                  arch_i286_set_register(s, c2, buf1, B, 0);
                  strcat(buf1, ", %ch\n");
                  strcat(buf1, "\tmovb $1, %cl\n");
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tshlw %cl, ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  strcat(buf1, "\trclw %cl, ");
                  arch_i286_set_register(s, c0, buf1, W, 1);
                  strcat(buf1, "\trclw %cl, ");
                  arch_i286_set_register(s, c0, buf1, U, 1);
                  strcat(buf1, "\trclw %cl, ");
                  arch_i286_set_register(s, c0, buf1, V, 1);
                  strcat(buf1, "\tdec %ch\n");
                  strcat(buf1, "\tcmpb $0, %ch\n");
                  strcat(buf1, "\tjnz 1b\n");
                  break;

            default:
                  assert(0);
            }
            break;

      case EXPR_RIGHT:
            /* FIXME optimize shr 0x10 ... */
            c0 = arch_i286_get_expr_constraint(s, 0);
            c2 = arch_i286_get_expr_constraint(s, 2);

            switch (t->type) {
            case TYPE_INT8:
                  /* sarb %b2, %0 */
                  strcpy(buf1, "\tsarb ");
                  arch_i286_set_registers(s, c0, c2, buf1, B, N);
                  break;
            case TYPE_INT16:
                  /* sarw %b2, %0 */
                  strcpy(buf1, "\tsarw ");
                  arch_i286_set_registers(s, c0, c2, buf1, B, N);
                  break;
            case TYPE_INT32:
                  /* movb %b2, %ch
                     movb $1, %cl
                     1:
                     sarw %cl, %w0
                     rcrw %cl, %0
                     dec %ch
                     cmpb $0, %ch
                     jnz 1b */
                  strcpy(buf1, "\tmovb ");
                  arch_i286_set_register(s, c2, buf1, B, 0);
                  strcat(buf1, ", %ch\n");
                  strcat(buf1, "\tmovb $1, %cl\n");
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tsarw %cl, ");
                  arch_i286_set_register(s, c0, buf1, W, 1);
                  strcat(buf1, "\trcrw %cl, ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  strcat(buf1, "\tdec %ch\n");
                  strcat(buf1, "\tcmpb $0, %ch\n");
                  strcat(buf1, "\tjnz 1b\n");
                  break;
            case TYPE_INT64:
                  /* movb %b2, %ch
                     movb $1, %cl
                     1:
                     sarw %cl, %v0
                     rcrw %cl, %u0
                     rcrw %cl, %w0
                     rcrw %cl, %0
                     dec %ch
                     cmpb $0, %ch
                     jnz 1b */
                  strcpy(buf1, "\tmovb ");
                  arch_i286_set_register(s, c2, buf1, B, 0);
                  strcat(buf1, ", %ch\n");
                  strcat(buf1, "\tmovb $1, %cl\n");
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tsarw %cl, ");
                  arch_i286_set_register(s, c0, buf1, V, 1);
                  strcat(buf1, "\trcrw %cl, ");
                  arch_i286_set_register(s, c0, buf1, U, 1);
                  strcat(buf1, "\trcrw %cl, ");
                  arch_i286_set_register(s, c0, buf1, W, 1);
                  strcat(buf1, "\trcrw %cl, ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  strcat(buf1, "\tdec %ch\n");
                  strcat(buf1, "\tcmpb $0, %ch\n");
                  strcat(buf1, "\tjnz 1b\n");
                  break;
            case TYPE_UINT8:
                  /* shrb %b2, %0 */
                  strcpy(buf1, "\tshrb ");
                  arch_i286_set_registers(s, c0, c2, buf1, B, N);
                  break;
            case TYPE_UINT16:
                  /* shrw %b2, %0 */
                  strcpy(buf1, "\tshrw ");
                  arch_i286_set_registers(s, c0, c2, buf1, B, N);
                  break;
            case TYPE_UINT32:
                  /* movb %b2, %ch
                     movb $1, %cl
                     1:
                     shrw %cl, %w0
                     rcrw %cl, %0
                     dec %ch
                     cmpb $0, %ch
                     jnz 1b */
                  strcpy(buf1, "\tmovb ");
                  arch_i286_set_register(s, c2, buf1, B, 0);
                  strcat(buf1, ", %ch\n");
                  strcat(buf1, "\tmovb $1, %cl\n");
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tshrw %cl, ");
                  arch_i286_set_register(s, c0, buf1, W, 1);
                  strcat(buf1, "\trcrw %cl, ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  strcat(buf1, "\tdec %ch\n");
                  strcat(buf1, "\tcmpb $0, %ch\n");
                  strcat(buf1, "\tjnz 1b\n");
                  break;
            case TYPE_UINT64:
                  /* movb %b2, %ch
                     movb $1, %cl
                     1:
                     shrw %cl, %v0
                     rcrw %cl, %u0
                     rcrw %cl, %w0
                     rcrw %cl, %0
                     dec %ch
                     cmpb $0, %ch
                     jnz 1b */
                  strcpy(buf1, "\tmovb ");
                  arch_i286_set_register(s, c2, buf1, B, 0);
                  strcat(buf1, ", %ch\n");
                  strcat(buf1, "\tmovb $1, %cl\n");
                  strcat(buf1, "\t1:\n");
                  strcat(buf1, "\tshrw %cl, ");
                  arch_i286_set_register(s, c0, buf1, V, 1);
                  strcat(buf1, "\trcrw %cl, ");
                  arch_i286_set_register(s, c0, buf1, U, 1);
                  strcat(buf1, "\trcrw %cl, ");
                  arch_i286_set_register(s, c0, buf1, W, 1);
                  strcat(buf1, "\trcrw %cl, ");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  strcat(buf1, "\tdec %ch\n");
                  strcat(buf1, "\tcmpb $0, %ch\n");
                  strcat(buf1, "\tjnz 1b\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);

            arch_i286_expr2_compare(buf1, s, e, lhs, t1);
            break;

      case EXPR_AND:
            c0 = arch_i286_get_expr_constraint(s, 0);
            c2 = arch_i286_get_expr_constraint(s, 2);

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* andb %2, %0 */
                  strcpy(buf1, "\tandb ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* andw %2, %0 */
                  strcpy(buf1, "\tandw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  if (_DEBUG > 1)
                        fprintf(stderr, "\tEXPR_AND->TYPE_INT32\n");
                  /* andw %2, %0
                     andw %w2, %w0 */
                  strcpy(buf1, "\tandw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  strcat(buf1, "\tandw ");
                  arch_i286_set_registers(s, c0, c2, buf1, W, W);
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  /* andw %2, %0
                     andw %w2, %w0
                     andw %u2, %u0
                     andw %v2, %v0 */
                  strcpy(buf1, "\tandw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  strcat(buf1, "\tandw ");
                  arch_i286_set_registers(s, c0, c2, buf1, W, W);
                  strcat(buf1, "\tandw ");
                  arch_i286_set_registers(s, c0, c2, buf1, U, U);
                  strcat(buf1, "\tandw ");
                  arch_i286_set_registers(s, c0, c2, buf1, V, V);
                  break;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;

      case EXPR_OR:
            c0 = arch_i286_get_expr_constraint(s, 0);
            c2 = arch_i286_get_expr_constraint(s, 2);

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* orb %2, %0 */
                  strcpy(buf1, "\torb ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* orw %2, %0 */
                  strcpy(buf1, "\torw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  /* orw %2, %0
                     orw %w2, %w0 */
                  strcpy(buf1, "\torw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  strcat(buf1, "\torw ");
                  arch_i286_set_registers(s, c0, c2, buf1, W, W);
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  /* orw %2, %0
                     orw %w2, %w0
                     orw %u2, %u0
                     orw %v2, %v0 */
                  strcpy(buf1, "\torw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  strcat(buf1, "\torw ");
                  arch_i286_set_registers(s, c0, c2, buf1, W, W);
                  strcat(buf1, "\torw ");
                  arch_i286_set_registers(s, c0, c2, buf1, U, U);
                  strcat(buf1, "\torw ");
                  arch_i286_set_registers(s, c0, c2, buf1, V, V);
                  break;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;

      case EXPR_XOR:
            c0 = arch_i286_get_expr_constraint(s, 0);
            c2 = arch_i286_get_expr_constraint(s, 2);

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* xorb %2, %0 */
                  strcpy(buf1, "\txorb ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* xorw %2, %0 */
                  strcpy(buf1, "\txorw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  /* xorw %2, %0
                     xorw %w2, %w0 */
                  strcpy(buf1, "\txorw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  strcat(buf1, "\txorw ");
                  arch_i286_set_registers(s, c0, c2, buf1, W, W);
                  break;
            case TYPE_INT64:
            case TYPE_UINT64:
                  /* xorw %2, %0
                     xorw %w2, %w0
                     xorw %u2, %u0
                     xorw %v2, %v0 */
                  strcpy(buf1, "\txorw ");
                  arch_i286_set_registers(s, c0, c2, buf1, N, N);
                  strcat(buf1, "\txorw ");
                  arch_i286_set_registers(s, c0, c2, buf1, W, W);
                  strcat(buf1, "\txorw ");
                  arch_i286_set_registers(s, c0, c2, buf1, U, U);
                  strcat(buf1, "\txorw ");
                  arch_i286_set_registers(s, c0, c2, buf1, V, V);
                  break;

            case TYPE_FLOAT64:
            case TYPE_FLOAT80:
                  assert(0);
            default:
                  assert(0);
            }
            break;

      case EXPR_FUNC:
            n=0;
            for (c = s->output->first; c; c = c->next) {
                  n++;
            }
            for (ce = e->expr1->last; ce; ce = ce->prev) {
                  t1 = expr_typeof(block->scope, ce);
                  t1 = type_pure(t1);
                  c0 = arch_i286_get_expr_constraint(s, n);

                  switch (t1->type) {
                  case TYPE_INT8:
                  case TYPE_UINT8:
                        sprintf(buf1 + strlen(buf1), "\tpushb ");
                        arch_i286_set_register(s, c0, buf1, N, 1);
                        n++;
                        size += 1;
                        break;
                  case TYPE_VA_LIST:
                        sprintf(buf1 + strlen(buf1), "\tpushw ");
                        arch_i286_set_register(s, c0, buf1, W, 1);
                        size += 2;
                  case TYPE_INT16:
                  case TYPE_UINT16:
                        sprintf(buf1 + strlen(buf1), "\tpushw ");
                        arch_i286_set_register(s, c0, buf1, N, 1);
                        n++;
                        size += 2;
                        break;
                  case TYPE_INT32:
                  case TYPE_UINT32:
                        sprintf(buf1 + strlen(buf1), "\tpushw ");
                        arch_i286_set_register(s, c0, buf1, W, 1);
                        if (arch_i286_is_local2(c0)) {
                              sprintf(buf1 + strlen(buf1), "\tpushw %%ss\n");
                              sprintf(buf1 + strlen(buf1), "\tpopw %%es\n");
                              sprintf(buf1 + strlen(buf1), "\tpushw %%ax\n");
                              sprintf(buf1 + strlen(buf1), "\tpushw %%bx\n");
                              sprintf(buf1 + strlen(buf1), "\tleaw ");
                              arch_i286_set_register(s, c0, buf1, N, 0);
                              sprintf(buf1 + strlen(buf1), ", %%ax\n");
                              sprintf(buf1 + strlen(buf1), "\tmovw %%sp, %%bx\n");
                              sprintf(buf1 + strlen(buf1), "\txchg %%es:2(%%bx),%%ax\n");
                              sprintf(buf1 + strlen(buf1), "\tpopw %%bx\n");
                        } else {
                              sprintf(buf1 + strlen(buf1), "\tpushw ");
                              arch_i286_set_register(s, c0, buf1, N, 1);
                        }
                        n++;
                        size += 4;
                        break;
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        sprintf(buf1 + strlen(buf1), "\tpushw ");
                        arch_i286_set_register(s, c0, buf1, V, 1);
                        sprintf(buf1 + strlen(buf1), "\tpushw ");
                        arch_i286_set_register(s, c0, buf1, U, 1);
                        sprintf(buf1 + strlen(buf1), "\tpushw ");
                        arch_i286_set_register(s, c0, buf1, W, 1);
                        sprintf(buf1 + strlen(buf1), "\tpushw ");
                        arch_i286_set_register(s, c0, buf1, N, 1);
                        n++;
                        size += 8;
                        break;

                  case TYPE_FLOAT32:
                  case TYPE_FLOAT64:
                  case TYPE_FLOAT80:
                        assert(0);
                  default:
                        assert(0);
                  }
            }

            if (e->expr0->declaration->storage != STORAGE_NONE) {
                  sprintf(buf1 + strlen(buf1), "\tcall");
            } else {
                  /* lcall */
                  sprintf(buf1 + strlen(buf1), "\tcall");
            }
            switch (e->expr0->type) {
            case EXPR_IDENTIFIER:
                  if (e->expr0->declaration->storage != STORAGE_NONE) {
                        sprintf(buf1 + strlen(buf1), " %s\n",
                              e->expr0->declaration->identifier);
                  } else {
                        /* *(%s) */
                        sprintf(buf1 + strlen(buf1), " %s\n",
                              e->expr0->declaration->identifier);
                  }
                  break;
            case EXPR_STAR:
                  sprintf(buf1 + strlen(buf1), " *");
                  arch_i286_set_register(s, c0, buf1, N, 1);
                  n++;
                  break;
            default:
                  assert(0);
            }
            if (0 < size) {
                  sprintf(buf1 + strlen(buf1), "\taddw $%u, %%sp\n",
                        size);
            }
            break;

      default:
            assert(0);
      }
}

void
arch_i286_gen_asm_stmt_if(
      struct stmt *s,
      struct type * t,
      char * buf1
)
{
      struct constraint * c0 = NULL;
      struct constraint * c1 = NULL;

      c0 = arch_i286_get_expr_constraint(s, 0);
      c1 = arch_i286_get_expr_constraint(s, 1);

      switch (t->type) {
      case TYPE_INT8:
      case TYPE_UINT8:
      case TYPE_INT16:
      case TYPE_UINT16:
            switch (t->type) {
            case TYPE_INT8:
            case TYPE_UINT8:
                  /* cmpb %1, %0 */
                  strcpy(buf1, "\tcmpb ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  break;
            case TYPE_INT16:
            case TYPE_UINT16:
                  /* cmpw %1, %0 */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  break;
            case TYPE_INT32:
            case TYPE_UINT32:
                  assert(0);
            default:
                  assert(0);
            }

            switch (t->type) {
            case TYPE_INT8:
            case TYPE_INT16:
                  switch (s->expr0->type) {
                  case EXPR_EQUAL:
                        sprintf(buf1 + strlen(buf1), "\tjne 1f\n");
                        sprintf(buf1 + strlen(buf1), "\tjmp %s\n",
                              s->stmt0->label->identifier);
                        sprintf(buf1 + strlen(buf1), "\t1:\n");
                        break;
                  case EXPR_NOT_EQUAL:
                        sprintf(buf1 + strlen(buf1), "\tje 1f\n");
                        sprintf(buf1 + strlen(buf1), "\tjmp %s\n",
                              s->stmt0->label->identifier);
                        sprintf(buf1 + strlen(buf1), "\t1:\n");
                        break;
                  case EXPR_LESS:
                        sprintf(buf1 + strlen(buf1), "\tjle 1f\n");
                        sprintf(buf1 + strlen(buf1), "\tjmp %s\n",
                              s->stmt0->label->identifier);
                        sprintf(buf1 + strlen(buf1), "\t1:\n");
                        break;
                  case EXPR_LESS_EQUAL:
                        sprintf(buf1 + strlen(buf1), "\tjl 1f\n");
                        sprintf(buf1 + strlen(buf1), "\tjmp %s\n",
                              s->stmt0->label->identifier);
                        sprintf(buf1 + strlen(buf1), "\t1:\n");
                        break;
                  case EXPR_GREATER:
                        sprintf(buf1 + strlen(buf1), "\tjge 1f\n");
                        sprintf(buf1 + strlen(buf1), "\tjmp %s\n",
                              s->stmt0->label->identifier);
                        sprintf(buf1 + strlen(buf1), "\t1:\n");
                        break;
                  case EXPR_GREATER_EQUAL:
                        sprintf(buf1 + strlen(buf1), "\tjg 1f\n");
                        sprintf(buf1 + strlen(buf1), "\tjmp %s\n",
                              s->stmt0->label->identifier);
                        sprintf(buf1 + strlen(buf1), "\t1:\n");
                        break;
                  default:
                        assert(0);
                  }
                  break;

            case TYPE_UINT8:
            case TYPE_UINT16:
                  switch (s->expr0->type) {
                  case EXPR_EQUAL:
                        /* "\tje %s\n" */
                        sprintf(buf1 + strlen(buf1), "\tjne 1f\n");
                        sprintf(buf1 + strlen(buf1), "\tjmp %s\n",
                              s->stmt0->label->identifier);
                        sprintf(buf1 + strlen(buf1), "\t1:\n");
                        break;
                  case EXPR_NOT_EQUAL:
                        sprintf(buf1 + strlen(buf1), "\tjne %s\n",
                              s->stmt0->label->identifier);
                        break;
                  case EXPR_LESS:
                        /* jb */
                        sprintf(buf1 + strlen(buf1), "\tja %s\n",
                              s->stmt0->label->identifier); /* jae */
                        break;
                  case EXPR_LESS_EQUAL:
                        /* jbe */
                        sprintf(buf1 + strlen(buf1), "\tjae %s\n",
                              s->stmt0->label->identifier); /* ja */
                        break;
                  case EXPR_GREATER:
                        /* ja */
                        sprintf(buf1 + strlen(buf1), "\tjb %s\n",
                              s->stmt0->label->identifier);
                        break;
                  case EXPR_GREATER_EQUAL:
                        /* jae */
                        sprintf(buf1 + strlen(buf1), "\tjbe %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:
                  /* cmpw %%w1, %%w0
                     jne 1f
                     cmpw %%1, %%0
                     je %s
                     1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  strcat(buf1, "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tje %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_NOT_EQUAL:
                  /* cmpw %%w1, %%w0
                     jne %s
                     cmpw %%1, %%0
                     jne %s */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  break;
            case EXPR_LESS:
                  /* cmpw %%w1, %%w0
                     jl %s
                     jg 1f
                     cmpw %%1, %%0
                     jl %s
                     1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjl 2f\n"
                        "\tje 1f\n"
                        "\tjmp %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\t1: cmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjg %s\n"
                        "2:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_LESS_EQUAL:
                  /* cmpw %%w1, %%w0
                     jl %s
                     jg 1f
                     cmpw %%1, %%0
                     jle %s
                     1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tje 1f\n"
                        "\tjl 2f\n"
                        "\tjmp %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\t1: cmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjge %s\n"
                        "2:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_GREATER:
                  /* cmpw %%w1, %%w0
                     jg %s
                     jl 1f
                     cmpw %%1, %%0
                     jg %s
                     1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tje 1f\n"
                        "\tjg 2f\n"
                        "\tjmp %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\t1: cmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjl %s\n"
                        "2:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_GREATER_EQUAL:
                  /* cmpw %%w1, %%w0
                     jg %s
                     jl 1f
                     cmpw %%1, %%0
                     jge %s
                     1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tje 1f\n"
                        "\tjg 2f\n"
                        "\tjmp %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\t1: cmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjle %s\n"
                        "2:\n", s->stmt0->label->identifier);
                  break;
            default:
                  assert(0);
            }
            break;

      case TYPE_UINT32:
            switch (s->expr0->type) {
            case EXPR_EQUAL:
                  /* cmpw %%w1, %%w0
                     jne 1f
                     cmpw %%1, %%0
                     je %s
                     1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tje %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_NOT_EQUAL:
                  /* cmpw %%w1, %%w0
                        jne %s
                        cmpw %%1, %%0
                        jne %s */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  break;
            case EXPR_LESS:
                  /* cmpw %%w1, %%w0
                        ja %s
                        jb 1f
                        cmpw %%1, %%0
                        jae %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjb 2f\n"
                        "\tje 1f\n"
                        "\tjmp %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\t1:cmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tja %s\n"
                        "2:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_LESS_EQUAL:
                  /* cmpw %%w1, %%w0
                        ja %s
                        jbe 1f
                        cmpw %%1, %%0
                        ja %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tje 1f\n"
                        "\tjb 2f\n"
                        "\tjmp %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\t1: cmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjae %s\n"
                        "2:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_GREATER:
                  /* cmpw %%w1, %%w0
                        jbe %s
                        ja 1f
                        cmpw %%1, %%0
                        jbe %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tje 1f\n"
                        "\tja 2f\n"
                        "\tjmp %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\t1: cmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjb %s\n"
                        "2:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_GREATER_EQUAL:
                  /* cmpw %%w1, %%w0
                        jb %s
                        jae 1f
                        cmpw %%1, %%0
                        jb %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tje 1f\n"
                        "\tjnc 2f\n"
                        "\tjmp %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\t1: cmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjbe %s\n"
                        "2:\n", s->stmt0->label->identifier);
                  break;
            default:
                  assert(0);
            }
            break;

      case TYPE_INT64:
            switch (s->expr0->type) {
            case EXPR_EQUAL:
                  /* cmpw %%v1, %%v0
                        jne 1f
                        cmpw %%u1, %%u0
                        jne 1f
                        cmpw %%w1, %%w0
                        jne 1f
                        cmpw %%1, %%0
                        je %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tje %s\n"
                        "1:\n",s->stmt0->label->identifier);
                  break;
            case EXPR_NOT_EQUAL:
                  /* cmpw %%v1, %%v0
                        jne %s
                        cmpw %%u1, %%u0
                        jne %s
                        cmpw %%w1, %%w0
                        jne %s
                        cmpw %%1, %%0
                        jne %s */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  break;
            case EXPR_LESS:
                  /* cmpw %%v1, %%v0
                        jl %s
                        jg 1f
                        cmpw %%u1, %%u0
                        jl %s
                        jg 1f
                        cmpw %%w1, %%w0
                        jl %s
                        jg 1f
                        cmpw %%1, %%0
                        jl %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tjg %s\n"
                        "\tjl 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tjg %s\n"
                        "\tjl 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjg %s\n"
                        "\tjl 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjg %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_LESS_EQUAL:
                  /* cmpw %%v1, %%v0
                        jl %s
                        jg 1f
                        cmpw %%u1, %%u0
                        jl %s
                        jg 1f
                        cmpw %%w1, %%w0
                        jl %s
                        jg 1f
                        cmpw %%1, %%0
                        jle %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tjg %s\n"
                        "\tjl 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tjg %s\n"
                        "\tjl 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjg %s\n"
                        "\tjl 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjge %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_GREATER:
                  /* cmpw %%v1, %%v0
                        jg %s
                        jl 1f
                        cmpw %%u1, %%u0
                        jg %s
                        jl 1f
                        cmpw %%w1, %%w0
                        jg %s
                        jl 1f
                        cmpw %%1, %%0
                        jg %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tjl %s\n"
                        "\tjg 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tjl %s\n"
                        "\tjg 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjl %s\n"
                        "\tjg 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjl %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_GREATER_EQUAL:
                  /* cmpw %%v1, %%v0
                        jg %s
                        jl 1f
                        cmpw %%u1, %%u0
                        jg %s
                        jl 1f
                        cmpw %%w1, %%w0
                        jg %s
                        jl 1f
                        cmpw %%1, %%0
                        jge %s
                        1: */ 
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tjl %s\n"
                        "\tjg 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tjl %s\n"
                        "\tjg 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjl %s\n"
                        "\tjg 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjle %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            default:
                  assert(0);
            }
            break;

      case TYPE_UINT64:
            switch (s->expr0->type) {
            case EXPR_EQUAL:
                  /* cmpw %%v1, %%v0
                        jne 1f
                        cmpw %%u1, %%u0
                        jne 1f
                        cmpw %%w1, %%w0
                        jne 1f
                        cmpw %%1, %%0
                        je %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne 1f\n");
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tje %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_NOT_EQUAL:
                  /* cmpw %%v1, %%v0
                        jne %s
                        cmpw %%u1, %%u0
                        jne %s
                        cmpw %%w1, %%w0
                        jne %s
                        cmpw %%1, %%0
                        jne %s */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjne %s\n",
                        s->stmt0->label->identifier);
                  break;
            case EXPR_LESS:
                  /* cmpw %%v1, %%v0
                        jb %s
                        ja 1f
                        cmpw %%u1, %%u0
                        jb %s
                        ja 1f
                        cmpw %%w1, %%w0
                        jb %s
                        ja 1f
                        cmpw %%1, %%0
                        jb %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tja %s\n"
                        "\tjb 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tja %s\n"
                        "\tjb 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tja %s\n"
                        "\tjb 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tja %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_LESS_EQUAL:
                  /* cmpw %%v1, %%v0
                        jb %s
                        ja 1f
                        cmpw %%u1, %%u0
                        jb %s
                        ja 1f
                        cmpw %%w1, %%w0
                        jb %s
                        ja 1f
                        cmpw %%1, %%0
                        jbe %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tja %s\n"
                        "\tjb 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tja %s\n"
                        "\tjb 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tja %s\n"
                        "\tjb 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjae %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_GREATER:
                  /* cmpw %%v1, %%v0
                        ja %s
                        jb 1f
                        cmpw %%u1, %%u0
                        ja %s
                        jb 1f
                        cmpw %%w1, %%w0
                        ja %s
                        jb 1f
                        cmpw %%1, %%0
                        ja %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tjb %s\n"
                        "\tja 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tjb %s\n"
                        "\tja 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjb %s\n"
                        "\tja 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjb %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            case EXPR_GREATER_EQUAL:
                  /* cmpw %%v1, %%v0
                        ja %s
                        jb 1f
                        cmpw %%u1, %%u0
                        ja %s
                        jb 1f
                        cmpw %%w1, %%w0
                        ja %s
                        jb 1f
                        cmpw %%1, %%0
                        jae %s
                        1: */
                  strcpy(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, V, V);
                  sprintf(buf1 + strlen(buf1),
                        "\tjb %s\n"
                        "\tja 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, U, U);
                  sprintf(buf1 + strlen(buf1),
                        "\tjb %s\n"
                        "\tja 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, W, W);
                  sprintf(buf1 + strlen(buf1),
                        "\tjb %s\n"
                        "\tja 1f\n",
                        s->stmt0->label->identifier);
                  strcat(buf1, "\tcmpw ");
                  arch_i286_set_registers(s, c0, c1, buf1, N, N);
                  sprintf(buf1 + strlen(buf1),
                        "\tjle %s\n"
                        "1:\n", s->stmt0->label->identifier);
                  break;
            default:
                  assert(0);
            }
            break;

      case TYPE_FLOAT32:
      case TYPE_FLOAT64:
      case TYPE_FLOAT80:
            assert(0);
      default:
            assert(0);
      }
}

void
arch_i286_stmt_gen_asm(
      struct stmt *block,
      struct stmt *s,
      const char *buf0,
      char *buf1)
{
      struct constraint *c = NULL;
      type_mod mod;
      unsigned int n;
      const char *from = buf0;
      char *to = buf1;

      while(*from) {
            if (_DEBUG > 1)
                  fprintf(stderr, "%c", *from);
            if (*from != '%') {
                  *to++ = *from++;
                  *to = 0;
                  continue;
            }
            from++;
            if (*from == '%') {
                  from++;
                  *to++ = '%';
                  *to = 0;
                  continue;
            }

            switch(*from) {
            case 'b':
                  mod = B;
                  from++;
                  break;
            case 'h':
                  mod = H;
                  from++;
                  break;
            case 'w':
                  mod = W;
                  from++;
                  break;
            case 'u':
                  mod = U;
                  from++;
                  break;
            case 'v':
                  mod = V;
                  from++;
                  break;
            default:
                  mod = N;
                  break;
            };

            assert('0' <= *from && *from <= '9');

            n = *from++ - '0';
            for (c = s->output->first; c && n; c = c->next) {
                  n--;
            }
            if (! c) {
                  for (c = s->input->first; c && n; c = c->next) {
                        n--;
                  }
            }

            assert(c);

            arch_i286_get_operand(s, c, to, mod);
            to = buf1 + strlen(buf1);
      }
}

void
arch_i286_gen_asm_stmt(
      struct stmt *block,
      struct stmt *s,
      unsigned int paramsize
)
{
      struct stmt * s0 = NULL;
      struct constraint * c0 = NULL;
      struct constraint * c1 = NULL;
      struct type * t = NULL;
      char buf1[1024*64];
      const char *buf;
      char *to;

      strcpy(buf1, "");

      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);
            break;

      case STMT_LABEL:
            sprintf(buf1, "%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_i286_gen_expr_2(buf1,
                                    block, s, s->expr0->expr1,
                                    s->expr0->expr0);
                        break;
                  case EXPR_STAR:
                        t = expr_typeof(block->scope, s->expr0->expr1);
                        t = type_pure(t);

                        c0 = arch_i286_get_expr_constraint(s,0);
                        c1 = arch_i286_get_expr_constraint(s,1);

                        switch (t->type) {
                        case TYPE_INT8:
                        case TYPE_UINT8:
                              /* [movw %w1, %es]      */
                              /* movb %0, [%es:](%1)  */
                              if (IsPointer32b()) {
                                    strcpy(buf1, "\tmovw ");
                                    arch_i286_set_register(s, c0, buf1, W, 0);      
                                    strcat(buf1, ", %es\n");
                                    strcat(buf1, "\tmovb ");
                              } else {
                                    strcpy(buf1, "\tmovb ");
                              }
                              arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, IND_D);
                              break;
                        case TYPE_INT16:
                        case TYPE_UINT16:
                              /* [movw %w1, %es]      */
                              /* movw %0, [%es:](%1)  */

                              if (IsPointer32b()) {
                                    strcpy(buf1, "\tmovw ");
                                    arch_i286_set_register(s, c0, buf1, W, 0);
                                    strcat(buf1, ", %es\n");
                                    strcat(buf1, "\tmovw ");
                              } else {
                                    strcpy(buf1, "\tmovw ");
                              }
                              arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, IND_D);

                              break;
                        case TYPE_INT32:
                        case TYPE_UINT32:
                              /* [movw %w1, %es]      */
                              /* movw %0, [%es:](%1)  */
                              /* addw $0x2, %1  */ 
                              /* movw %w0, [es:](%1)  */
                              
                              c0 = arch_i286_get_expr_constraint(s, 0);
                              c1 = arch_i286_get_expr_constraint(s, 1);
                  
                              if (IsPointer32b()) {
                                    strcpy(buf1, "\tmovw ");
                                    arch_i286_set_register(s, c0, buf1, W, 0);      
                                    strcat(buf1, ", %es\n");
                                    strcat(buf1, "\tmovw ");
                              } else {
                                    strcpy(buf1, "\tmovw ");
                              }
                              arch_i286_set_ind_mem(s, c0, c1, buf1, N, 0, IND_D);
                              strcat(buf1, "\taddw $0x2, ");
                              arch_i286_set_register(s, c0, buf1, N, 1);
                              strcat(buf1, "\tmovw ");
                              // no offset
                              arch_i286_set_ind_mem(s, c0, c1, buf1, W, 0, IND_D);
                              break;
                        case TYPE_INT64:
                        case TYPE_UINT64:
                              /* movw %0, (%1)
                                 movw %w0, 2(%1)
                                 movw %u0, 4(%1)
                                 movw %v0, 6(%1) */
                              strcpy(buf1, "\tmovw ");
                              arch_i286_set_ind_mem(s, c0, c1, buf1,
                                                N, 0, IND_D);
                              strcat(buf1, "\tmovw ");
                              arch_i286_set_ind_mem(s, c0, c1, buf1,
                                                W, 2, IND_D);
                              strcat(buf1, "\tmovw ");
                              arch_i286_set_ind_mem(s, c0, c1, buf1,
                                                U, 4, IND_D);
                              strcat(buf1, "\tmovw ");
                              arch_i286_set_ind_mem(s, c0, c1, buf1,
                                                V, 6, IND_D);
                              break;

                        case TYPE_FLOAT32:
                        case TYPE_FLOAT64:
                        case TYPE_FLOAT80:
                              assert(0);
                              break;
            
                        default:
                              assert(0);
                        }
                        break;

                  default:
                        assert(0);
                  }
                  break;
            case EXPR_FUNC:
                  arch_i286_gen_expr_2(buf1, 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);

            arch_i286_gen_asm_stmt_if(s, t, buf1);

            break;

      case STMT_SWITCH:
            assert(s->expr0->type == EXPR_IDENTIFIER);

            t = expr_typeof(block->scope, s->expr0);
            t = type_pure(t);

            c0 = arch_i286_get_expr_constraint(s,0);

            strcpy(buf1, "");
            for (s0 = s->stmt0->stmt_first;
                s0->type != STMT_DEFAULT;
                s0 = s0->next) {

                  assert(s0);
                  assert(strlen(buf1) < (1023*64));

                  switch (t->type) {
                  case TYPE_INT8:
                  case TYPE_UINT8:
                        /* cmpb $%u, %0 */
                        sprintf(buf1 + strlen(buf1),
                              "\tcmpb $%u, ",
                              (uint16_t)s0->expr0->integer);
                        arch_i286_set_register(s, c0, buf1, N, 1);
                        break;
                  case TYPE_INT16:
                  case TYPE_UINT16:
                        /* cmpw $%u, %0 */
                        sprintf(buf1 + strlen(buf1),
                              "\tcmpw $%u, ",
                              (uint16_t)s0->expr0->integer);
                        arch_i286_set_register(s, c0, buf1, N, 1);
                        break;
                  case TYPE_INT32:
                  case TYPE_UINT32:
                        /* cmpw $%u, %w0
                           jne 1f
                           cmpw $%u, %0 */
                        sprintf(buf1 + strlen(buf1),
                              "\tcmpw $%u, ",
                              (uint16_t)(s0->expr0->integer >> 16));
                        arch_i286_set_register(s, c0, buf1, W, 1);
                        sprintf(buf1 + strlen(buf1),
                              "\tjne 1f\n"
                              "\tcmpw $%u, ",
                              (uint16_t)s0->expr0->integer);
                        arch_i286_set_register(s, c0, buf1, N, 1);
                        break;
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        /* cmpw $%u, %v0
                           jne 1f
                           cmpw $%u, %u0
                           jne 1f
                           cmpw $%u, %w0
                           jne 1f
                           cmpw $%u, %0 */
                        sprintf(buf1 + strlen(buf1),
                              "\tcmpw $%u, ",
                              (uint16_t)(s0->expr0->integer >> 48));
                        arch_i286_set_register(s, c0, buf1, U, 1);
                        sprintf(buf1 + strlen(buf1),
                              "\tjne 1f\n"
                              "\tcmpw $%u, ",
                              (uint16_t)(s0->expr0->integer >> 32));
                        arch_i286_set_register(s, c0, buf1, V, 1);
                        sprintf(buf1 + strlen(buf1),
                              "\tjne 1f\n"
                              "\tcmpw $%u, ",
                              (uint16_t)(s0->expr0->integer >> 16));
                        arch_i286_set_register(s, c0, buf1, W, 1);
                        sprintf(buf1 + strlen(buf1),
                              "\tjne 1f\n"
                              "\tcmpw $%u, ",
                              (uint16_t)s0->expr0->integer);
                        arch_i286_set_register(s, c0, buf1, N, 1);
                        break;

                  default:
                        assert(0);
                  }
                  sprintf(buf1 + strlen(buf1),
                        "\tje %s\n"
                        "\t1:\n",
                        s0->stmt0->label->identifier);
            }
            sprintf(buf1 + strlen(buf1), "\tjmp %s\n",
                        s0->stmt0->label->identifier);
            break;

      case STMT_GOTO:
            sprintf(buf1, "\tjmp %s\n", s->label->identifier);
            break;

      case STMT_RETURN:
            strcpy(buf1, "");
            break;

      case STMT_ASM:
            buf = s->code;
            arch_i286_stmt_gen_asm(block, s, buf, buf1);
            if (0 < strlen(buf1) && buf1[strlen(buf1) - 1] != '\n') {
                  strcat(buf1, "\n");
            }
            #if _DEBUG > 1
                  fprintf(stderr, "STMT_ASM:\t%s.\n", buf1);
            #endif
            break;

      case STMT_VA_START:
            /*
             * [mov %ss, %w0]
             * lea X(%bp), %0
             */
            #if _DEBUG > 1
                  fprintf(stderr, "STMT_VA_START\n");
            #endif
            c0 = arch_i286_get_expr_constraint(s, 0);
            sprintf(buf1, "\tmovw %%ss, ");
            arch_i286_set_register(s, c0, buf1, W, 1);
            sprintf(buf1 + strlen(buf1), "\tleaw %u(%%bp), ", paramsize+6);
            arch_i286_set_register(s, c0, buf1, N, 1);
            break;

      case STMT_VA_END:
            #if _DEBUG > 1
                  fprintf(stderr, "STMT_VA_END\n");
            #endif
            break;

      default:
            assert(0);
      }

      #if _DEBUG > 2
            fprintf(stderr, "buf1:\n%s", buf1);
      #endif

      to = buf1 + strlen(buf1);
      *to = '\0';
#if _DEBUG > 2
      fprintf(stderr, "buf1:%s\n", buf1);
#endif

      s0 = stmt_new();
      s0->type = STMT_ASM;
      s0->code = identifier_new(buf1);
      s0->code_len = strlen(s0->code);
      if (_DEBUG > 1) {
            fprintf(stderr, "%s\n", buf1);
      }

      s0->output = constraint_list_new();
      s0->input = constraint_list_new();
      s0->change = constraint_list_new();

      stmt_replace_1_by_1(block, s, s0);
}

void
arch_i286_gen_function(FILE *fp, struct declaration *d)
{
      struct declaration *sreg[3];
      struct stmt * stmt = NULL;
      struct expr * e = NULL;
      struct type * t = NULL;

      unsigned int localmemsize;
      unsigned int paramsize;
      uint32_t reg;
      uint32_t regs_to_save;

      if (_DEBUG)
            fprintf(stderr, "\nFunction %s\n", d->identifier);

      /* Save/Restore registers  */
      /* FIXME */
      if (! d->attr_noreturn
       && d->stmt->stmt_last->type == STMT_RETURN) {
            const char *c;
            assert(d->stmt->stmt_last->type == STMT_RETURN);

            /* BX and/or SI and/or DI */
            regs_to_save = (uint32_t)REG_CALLEE;

            if (d->stmt->stmt_last->expr0 != NULL) {
                  e = d->stmt->stmt_last->expr0;
                  t = e->type_name;

                  t = expr_typeof(d->stmt->scope, e);
                  t = type_pure(t);
      
                  switch (t->type) {
                  case TYPE_INT64:
                  case TYPE_UINT64:
                        #if _DEBUG > 1
                              fprintf(stderr, "\nRET->(U)INT64\n");
                        #endif
                        regs_to_save &= ~((1 << SI) | (1 << DI));
                        break;
                  default:
                        break;
                  };
            }

            /* Save registers */
            stmt = stmt_new();
            stmt->type = STMT_ASM;
            stmt->code = identifier_new("");
            stmt->code_len = 0;
            for (reg = BX; reg<=SI; reg++) {
                  if ((regs_to_save >> reg) & 1) {
                        switch (reg) {
                        case AX: c = "=a"; break;
                        case BX: c = "=b"; break;
                        case CX: c = "=c"; break;
                        case DX: c = "=d"; break;
                        case DI: c = "=D"; break;
                        case SI: c = "=S"; break;
                        default:
                              fprintf(stderr, "\nregs_to_save=%x\n",
                                    regs_to_save);
                              fprintf(stderr, "reg=%x\n", reg);
                              assert(0);
                        }
                        sreg[reg-BX] = simplify_declaration_add(d->stmt->scope,
                              type_uint16(), identifier_tmp());
                        sreg[reg-BX]->storage = STORAGE_AUTO;
                        constraint_output(stmt, c, expr_identifier(sreg[reg-BX]));
                  } else {
                        sreg[reg-BX] = NULL;
                  }
            }
            stmt_prepend_first(d->stmt, stmt);

            /* Restore registers */
            stmt = stmt_new();
            stmt->type = STMT_ASM;
            stmt->code = identifier_new("");
            stmt->code_len = 0;
            for (reg = BX; reg<=SI; reg++) {
                  if ((regs_to_save >> reg) & 1) {
                        switch (reg) {
                        case AX: c = "a"; break;
                        case BX: c = "b"; break;
                        case CX: c = "c"; break;
                        case DX: c = "d"; break;
                        case DI: c = "D"; break;
                        case SI: c = "S"; break;
                        default:
                              fprintf(stderr, "\nregs_to_save=%x\n",
                                    regs_to_save);
                              fprintf(stderr, "reg=%x\n", reg);
                              assert(0);
                        }
                        assert(sreg[reg-BX]);
                        constraint_input(stmt, c, expr_identifier(sreg[reg-BX]));
                  }
            }
            stmt_prepend(d->stmt, d->stmt->stmt_last, stmt);
      }
      #if _DEBUG
            fprintf(stderr, "Allocating registers ...\n");
      #endif
      /*
       * Register allocation
       */
      for (stmt = d->stmt->stmt_first; stmt; ) {
            struct stmt *next;

            next = stmt->next;
            arch_i286_gen_stmt_reg_alloc(fp, d->stmt, stmt);
            stmt = next;
      }

      /*
       * Add missing constraint info.
       */
      for (stmt = d->stmt->stmt_first; stmt; stmt = stmt->next) {
            if (! stmt->output) {
                  stmt->output = constraint_list_new();
            }
            if (! stmt->input) {
                  stmt->input = constraint_list_new();
            }
            if (! stmt->change) {
                  stmt->change = constraint_list_new();
            }
      }

      #if _DEBUG
            fprintf(stderr, "Assigning registers ...\n");
      #endif
      /*
       * Register assignment.
       */
      declaration_alive(arch_i286_reginfo, arch_i286_classinfo,
                  arch_i286_typeinfo, d->stmt);

      /* Calculation of params size and local vars size */
      localmemsize = 0;
      arch_i286_calculate_local_size(fp, d, &localmemsize);
      arch_i286_calculate_param_size(fp, d, &paramsize);

      #if _DEBUG
            fprintf(stderr, "Generating code ...\n");
      #endif
      /*
       * Transform remaining statements into assembler code.
       * Second step.
       */
      for (stmt = d->stmt->stmt_first; stmt; ) {
            struct stmt *next;

            next = stmt->next;
            arch_i286_gen_asm_stmt(d->stmt, stmt, paramsize);
            stmt = next;
      }
      #if _DEBUG
            fprintf(stderr, "Printing code ...\n");
      #endif
      /*
       *    Generate Code
       */
      fprintf(fp, "\n.text\n");
      if (d->storage != STORAGE_STATIC) {
            fprintf(fp, "\t.globl %s\n", d->identifier);
      }
      fprintf(fp, "%s:\n", d->identifier);
      /* FIXME: when paramsize=localmemsize=0 then do not generate following? */
      fprintf(fp, "\tpushw %%bp\n");
      fprintf(fp, "\tmovw %%sp, %%bp\n");
      if (0 < localmemsize) {
            fprintf(fp, "\tsubw $%d, %%sp\n", localmemsize);
      }

      for (stmt=d->stmt->stmt_first; stmt; stmt=stmt->next) {
            if (stmt->type == STMT_ASM) {
                  fprintf(fp, "%s", stmt->code);
            } else {
                  fprintf(fp, "...\n");
            }
      }

      if (0 < localmemsize) {
            fprintf(fp, "\taddw $%d, %%sp\n", localmemsize);      
      }
      fprintf(fp, "\tpopw %%bp\n");
      if (d->storage == STORAGE_STATIC) {
            fprintf(fp, "\tret\n");
      } else {
            /* FIXME lret */
            fprintf(fp, "\tlret\n");
      }
      fprintf(fp, "\n");
}

void
arch_i286_gen_declaration(
      FILE *fp, 
      struct scope *scope, 
      struct declaration *d)
{
      if (d->storage == STORAGE_TYPEDEF
       || d->identifier == NULL) {
            /* Type definition only. */
            return;
      }
      if (d->storage == STORAGE_EXTERN) {
            /* Extern declaration only. */
            return;
      }

      if (d->identifier == NULL)
      {
#if 0
            if (d->type_name->type == TYPE_STRUCT) {
                  fprintf(stderr, "Struct-Definition \n");
            } else if (d->type_name->type == TYPE_UNION) {
                  fprintf(stderr, "Union-Definition \n");
            } else if (d->type_name->type == TYPE_ENUM) {
                  fprintf(stderr, "Enum-Definition \n");
            }
            fprintf(stderr, "id: %s\n", d->type_name->identifier);
#endif
            return;
      } else {
            /* Type, variable, function */
            if ((d->type_name->type == TYPE_FUNCTION) && !(d->stmt)) {
                  if ((d->storage == STORAGE_EXTERN)) {
                        fprintf(fp, ".globl ");
                        fprintf(fp, "%s\n", d->identifier);
                  } else {
                        fprintf(fp, ".globl ");
                        fprintf(fp, "%s\n", d->identifier);
                  }
            } else if ((d->stmt)) {
                  arch_i286_gen_function(fp, d);
            } else {
                  arch_i286_gen_variable(fp, scope, d);
                  }
      }
}

void
arch_i286_gen(FILE *fp, struct scope *scope)
{
      struct declaration *dion;
      int ret;

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

      fprintf(fp, ".code16\n");
      fprintf(fp, ".arch i286\n");

      fdion_div=fdion_mod=fdion_mul=NULL;
      fdion_div64=fdion_mod64=fdion_mul64=NULL;

      for (dion = scope->declaration_first; dion; dion = dion->next) {
            arch_i286_gen_declaration(fp, scope, dion);
      }
}

Generated by  Doxygen 1.6.0   Back to index