Пример #1
0
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
   and 'long long' cases. */
void gen_cvt_itof(int t)
{
    save_reg(TREG_ST0);
    gv(RC_INT);
    if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
        /* signed long long to float/double/long double (unsigned case
           is handled generically) */
        o(0x50 + vtop->r2); /* push r2 */
        o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
        o(0x242cdf); /* fildll (%esp) */
        o(0x08c483); /* add $8, %esp */
    } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == 
               (VT_INT | VT_UNSIGNED)) {
        /* unsigned int to float/double/long double */
        o(0x6a); /* push $0 */
        g(0x00);
        o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
        o(0x242cdf); /* fildll (%esp) */
        o(0x08c483); /* add $8, %esp */
    } else {
        /* int to float/double/long double */
        o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
        o(0x2404db); /* fildl (%esp) */
        o(0x04c483); /* add $4, %esp */
    }
    vtop->r = TREG_ST0;
}
Пример #2
0
// Generate an integer binary operation
void gen_opi(int op) {
  int r, fr, opc, c;

  switch (op) {
    case '+':
    case TOK_ADDC1: // Add with carry generation
      opc = 0;
    gen_op8:
      if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
        // Constant case
        vswap();
        r = gv(RC_INT);
        vswap();
        c = vtop->c.i;
        if (c == (char) c) {
          // Optimize +/- 1 case with inc and dec
          if (op == '+' && c == 1 || op == '-' && c == -1) {
            o(0x40 | r);  // inc r
          } else if (op == '-' && c == 1 || op == '+' && c == -1) {
            o(0x48 | r);  // dec r
          } else {
            o(0x83);
            o(0xc0 | (opc << 3) | r);
            g(c);
          }
        } else {
          o(0x81);
          oad(0xc0 | (opc << 3) | r, c);
        }
      } else {
        gv2(RC_INT, RC_INT);
        r = vtop[-1].r;
        fr = vtop[0].r;
        o((opc << 3) | 0x01);
        o(0xc0 + r + fr * 8); 
      }
      vtop--;
      if (op >= TOK_ULT && op <= TOK_GT) {
        vtop->r = VT_CMP;
        vtop->c.i = op;
      }
      break;
    case '-':
    case TOK_SUBC1: // Subtract with carry generation
      opc = 5;
      goto gen_op8;
    case TOK_ADDC2: // Add with carry use
      opc = 2;
      goto gen_op8;
    case TOK_SUBC2: // Subtract with carry use
      opc = 3;
      goto gen_op8;
    case '&':
      opc = 4;
      goto gen_op8;
    case '^':
      opc = 6;
      goto gen_op8;
    case '|':
      opc = 1;
      goto gen_op8;
    case '*':
      gv2(RC_INT, RC_INT);
      r = vtop[-1].r;
      fr = vtop[0].r;
      vtop--;
      o(0xaf0f); // imul fr, r
      o(0xc0 + fr + r * 8);
      break;
    case TOK_SHL:
      opc = 4;
      goto gen_shift;
    case TOK_SHR:
      opc = 5;
      goto gen_shift;
    case TOK_SAR:
      opc = 7;
    gen_shift:
      opc = 0xc0 | (opc << 3);
      if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
        // Constant case
        vswap();
        r = gv(RC_INT);
        vswap();
        c = vtop->c.i & 0x1f;
        o(0xc1); // shl/shr/sar $xxx, r
        o(opc | r);
        g(c);
      } else {
        // Generate the shift in ecx
        gv2(RC_INT, RC_ECX);
        r = vtop[-1].r;
        o(0xd3); // shl/shr/sar %cl, r
        o(opc | r);
      }
      vtop--;
      break;
    case '/':
    case TOK_UDIV:
    case TOK_PDIV:
    case '%':
    case TOK_UMOD:
    case TOK_UMULL:
      // First operand must be in eax
      // TODO: need better constraint for second operand
      gv2(RC_EAX, RC_ECX);
      r = vtop[-1].r;
      fr = vtop[0].r;
      vtop--;
      save_reg(TREG_EDX);
      if (op == TOK_UMULL) {
        o(0xf7); // mul fr
        o(0xe0 + fr);
        vtop->r2 = TREG_EDX;
        r = TREG_EAX;
      } else {
        if (op == TOK_UDIV || op == TOK_UMOD) {
          o(0xf7d231); // xor %edx, %edx, div fr, %eax
          o(0xf0 + fr);
        } else {
          o(0xf799); // cltd, idiv fr, %eax
          o(0xf8 + fr);
        }
        if (op == '%' || op == TOK_UMOD) {
          r = TREG_EDX;
        } else {
          r = TREG_EAX;
        }
      }
      vtop->r = r;
      break;
    default:
      opc = 7;
      goto gen_op8;
  }
}
Пример #3
0
// Generate a floating point operation 'v = t1 op t2' instruction. The
// two operands are guaranted to have the same floating point type
// TODO: need to use ST1 too
void gen_opf(int op) {
  int a, ft, fc, swapped, r;

  // Convert constants to memory references
  if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
    vswap();
    gv(RC_FLOAT);
    vswap();
  }
  if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) gv(RC_FLOAT);

  // Must put at least one value in the floating point register
  if ((vtop[-1].r & VT_LVAL) && (vtop[0].r & VT_LVAL)) {
    vswap();
    gv(RC_FLOAT);
    vswap();
  }
  swapped = 0;
  // Swap the stack if needed so that t1 is the register and t2 is the memory reference
  if (vtop[-1].r & VT_LVAL) {
    vswap();
    swapped = 1;
  }
  if (op >= TOK_ULT && op <= TOK_GT) {
    // Load on stack second operand
    load(TREG_ST0, vtop);
    save_reg(TREG_EAX); // eax is used by FP comparison code
    if (op == TOK_GE || op == TOK_GT) {
      swapped = !swapped;
    } else if (op == TOK_EQ || op == TOK_NE) {
      swapped = 0;
    }
    if (swapped) o(0xc9d9); // fxch %st(1)
    o(0xe9da); // fucompp
    o(0xe0df); // fnstsw %ax
    if (op == TOK_EQ) {
      o(0x45e480); // and $0x45, %ah
      o(0x40fC80); // cmp $0x40, %ah
    } else if (op == TOK_NE) {
      o(0x45e480); // and $0x45, %ah
      o(0x40f480); // xor $0x40, %ah
      op = TOK_NE;
    } else if (op == TOK_GE || op == TOK_LE) {
      o(0x05c4f6); // test $0x05, %ah
      op = TOK_EQ;
    } else {
      o(0x45c4f6); // test $0x45, %ah
      op = TOK_EQ;
    }
    vtop--;
    vtop->r = VT_CMP;
    vtop->c.i = op;
  } else {
    // No memory reference possible for long double operations
    if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
      load(TREG_ST0, vtop);
      swapped = !swapped;
    }

    switch (op) {
      case '+':
        a = 0;
        break;
      case '-':
        a = 4;
        if (swapped) a++;
        break;
      case '*':
        a = 1;
        break;
      case '/':
        a = 6;
        if (swapped) a++;
        break;
      default:
        a = 0;
    }
    ft = vtop->type.t;
    fc = vtop->c.ul;
    if ((ft & VT_BTYPE) == VT_LDOUBLE) {
      o(0xde); // fxxxp %st, %st(1)
      o(0xc1 + (a << 3));
    } else {
      // If saved lvalue, then we must reload it
      r = vtop->r;
      if ((r & VT_VALMASK) == VT_LLOCAL) {
        SValue v1;
        r = get_reg(RC_INT);
        v1.type.t = VT_INT;
        v1.r = VT_LOCAL | VT_LVAL;
        v1.c.ul = fc;
        load(r, &v1);
        fc = 0;
      }

      if ((ft & VT_BTYPE) == VT_DOUBLE) {
        o(0xdc);
      } else {
        o(0xd8);
      }
      gen_modrm(a, r, vtop->sym, fc);
    }
    vtop--;
  }
}
Пример #4
0
/* generate an integer binary operation */
void gen_opi(int op)
{
    int r, fr, opc, c;

    switch(op) {
    case '+':
    case TOK_ADDC1: /* add with carry generation */
        opc = 0;
    gen_op8:
        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
            /* constant case */
            vswap();
            r = gv(RC_INT);
            vswap();
            c = vtop->c.i;
            if (c == (char)c) {
                /* XXX: generate inc and dec for smaller code ? */
                o(0x83);
                o(0xc0 | (opc << 3) | r);
                g(c);
            } else {
                o(0x81);
                oad(0xc0 | (opc << 3) | r, c);
            }
        } else {
            gv2(RC_INT, RC_INT);
            r = vtop[-1].r;
            fr = vtop[0].r;
            o((opc << 3) | 0x01);
            o(0xc0 + r + fr * 8); 
        }
        vtop--;
        if (op >= TOK_ULT && op <= TOK_GT) {
            vtop->r = VT_CMP;
            vtop->c.i = op;
        }
        break;
    case '-':
    case TOK_SUBC1: /* sub with carry generation */
        opc = 5;
        goto gen_op8;
    case TOK_ADDC2: /* add with carry use */
        opc = 2;
        goto gen_op8;
    case TOK_SUBC2: /* sub with carry use */
        opc = 3;
        goto gen_op8;
    case '&':
        opc = 4;
        goto gen_op8;
    case '^':
        opc = 6;
        goto gen_op8;
    case '|':
        opc = 1;
        goto gen_op8;
    case '*':
        gv2(RC_INT, RC_INT);
        r = vtop[-1].r;
        fr = vtop[0].r;
        vtop--;
        o(0xaf0f); /* imul fr, r */
        o(0xc0 + fr + r * 8);
        break;
    case TOK_SHL:
        opc = 4;
        goto gen_shift;
    case TOK_SHR:
        opc = 5;
        goto gen_shift;
    case TOK_SAR:
        opc = 7;
    gen_shift:
        opc = 0xc0 | (opc << 3);
        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
            /* constant case */
            vswap();
            r = gv(RC_INT);
            vswap();
            c = vtop->c.i & 0x1f;
            o(0xc1); /* shl/shr/sar $xxx, r */
            o(opc | r);
            g(c);
        } else {
            /* we generate the shift in ecx */
            gv2(RC_INT, RC_ECX);
            r = vtop[-1].r;
            o(0xd3); /* shl/shr/sar %cl, r */
            o(opc | r);
        }
        vtop--;
        break;
    case '/':
    case TOK_UDIV:
    case TOK_PDIV:
    case '%':
    case TOK_UMOD:
    case TOK_UMULL:
        /* first operand must be in eax */
        /* XXX: need better constraint for second operand */
        gv2(RC_EAX, RC_ECX);
        r = vtop[-1].r;
        fr = vtop[0].r;
        vtop--;
        save_reg(TREG_EDX);
        if (op == TOK_UMULL) {
            o(0xf7); /* mul fr */
            o(0xe0 + fr);
            vtop->r2 = TREG_EDX;
            r = TREG_EAX;
        } else {
            if (op == TOK_UDIV || op == TOK_UMOD) {
                o(0xf7d231); /* xor %edx, %edx, div fr, %eax */
                o(0xf0 + fr);
            } else {
                o(0xf799); /* cltd, idiv fr, %eax */
                o(0xf8 + fr);
            }
            if (op == '%' || op == TOK_UMOD)
                r = TREG_EDX;
            else
                r = TREG_EAX;
        }
        vtop->r = r;
        break;
    default:
        opc = 7;
        goto gen_op8;
    }
}