Esempio n. 1
0
File: matrix.c Progetto: BigEd/wp34s
/* Create either a zero matrix or an identity matrix.
 */
void matrix_create(enum nilop op) {
    decNumber x;
    int r, c, i, j;
    decimal64 *base;
    const decimal64 *diag, *off;

    getX(&x);
    base = matrix_decomp(&x, &r, &c);
    if (base != NULL) {
        off = get_const(OP_ZERO, 0)->s;

        if (op == OP_MAT_IDENT) {
            if (r != c) {
                err(ERR_MATRIX_DIM);
                return;
            }
            diag = get_const(OP_ONE, 0)->s;
        } else
            diag = off;

        for (i=0; i<r; i++)
            for (j=0; j<c; j++)
                *base++ = *((i==j)?diag:off);
    }
}
Esempio n. 2
0
File: matrix.c Progetto: BigEd/wp34s
/* Invert a matrix in situ.
 * Do this by calculating the LU decomposition and solving lots of systems
 * of linear equations.
 */
void matrix_inverse(enum nilop op) {
    decimal128 mat[MAX_SQUARE*MAX_SQUARE];
    decNumber x[MAX_SQUARE];
    unsigned char pivots[MAX_SQUARE];
    int i, j, n;
    decimal64 *base;
    const decimal64 *b[MAX_SQUARE];

    getX(x);
    n = matrix_lu_check(x, mat, &base);
    if (n == 0)
        return;

    i = LU_decomposition(mat, pivots, n);
    if (i == 0) {
        err(ERR_SINGULAR);
        return;
    }

    for (i=0; i<n; i++) {
        for (j=0; j<n; j++)
            b[j] = (i==j) ? (decimal64 *) get_const(OP_ONE, 0) : (decimal64 *) get_const(OP_ZERO, 0);
        matrix_pivoting_solve(mat, b, pivots, x, n);
        for (j=0; j<n; j++)
            packed_from_number(base + matrix_idx(j, i, n), x+j);
    }
}
Esempio n. 3
0
PUBLIC type range_type(tree lower, tree upper)
{ 
     type p;

     check_type("range type", int_type, lower->t_type);
     check_type("range type", int_type, upper->t_type);

     p = alloc_type();
     p->x_kind = RANGE;
     p->x_base = int_type;
     p->x_lo = atol(get_const(lower));
     p->x_hi = atol(get_const(upper));
     return p;
}
Esempio n. 4
0
bool expr_handler::fold(fetch_node& n) {

	unsigned chan = 0;
	for (vvec::iterator I = n.dst.begin(), E = n.dst.end(); I != E; ++I) {
		value* &v = *I;
		if (v) {
			if (n.bc.dst_sel[chan] == SEL_0)
				assign_source(*I, get_const(0.0f));
			else if (n.bc.dst_sel[chan] == SEL_1)
				assign_source(*I, get_const(1.0f));
		}
		++chan;
	}
	return false;
}
Esempio n. 5
0
static void dump_constants(void) {
	char buf[100];
	int i;

	for (i=0; i<NUM_CONSTS; i++) {
		decimal128ToString(&(get_const(i, 1)->d), buf);
		printf("\t%02d\t%s\n", i, buf);
	}
}
Esempio n. 6
0
 virtual std::shared_ptr<TaskData> prepare_data(std::size_t n) override
 {
     auto data = std::make_shared<common::RandomData<item_type>>(n, '0', 'z');
     auto space_idx = common::RandomData<int>(n/10, 0, n);
     auto d = data->get_mutable();
     for (auto i : space_idx.get_const())
         d.at(i) = ' ';
     d.at(d.size()-1) = '0';
     I() << std::string(d.begin(), d.end());
     return data;
 }
Esempio n. 7
0
void set_aryLen(void) /* 配列サイズ設定 */
{
  tmpTb.aryLen = 0;
  if (token.kind != '[') return;                                /* 配列でない */

  token = nextTkn();
  if (token.kind == ']') {                                        /* []である */
    err_s("添字指定がない");
    token = nextTkn(); tmpTb.aryLen = 1; return;         /* 1だったことにする */
  }
  get_const(NULL);                                            /* 定数判定準備 */
  expr_with_chk(0, ']');                                        /* 添字を取得 */
  if (get_const(&(tmpTb.aryLen))) {                             /* 定数式なら */
    if (tmpTb.aryLen <= 0) {
      tmpTb.aryLen = 1; err_s("不正な添字");             /* 1だったことにする */
    }
  } else {
    err_s("配列幅指定が整数定数式でない");
  }

  if (token.kind == '[') {
    err_ss("多次元配列は宣言できない", token.text);
  }
}
Esempio n. 8
0
static void rarg_values(const opcode c, int l) {
	char bf[100];

	if (isRARG(c)) {
		const unsigned int cmd = RARG_CMD(c);
		const unsigned int idx = c & 0x7f;

		if (cmd == RARG_CONV) {
			while (l-- > 0)
				putchar(' ');
			printf("%c %s", (idx & 1)?'*':'/', decimal64ToString(&CONSTANT_CONV(idx/2), bf));
		} else if (cmd == RARG_CONST || cmd == RARG_CONST_CMPLX) {
			while (l-- > 0)
				putchar(' ');
			printf("%s", decimal64ToString((decimal64 *) get_const(c & 0x7f, 0), bf));
		}
	}
}
Esempio n. 9
0
/*
 *	add a string to the constant pool
 *  handle underscore
 *
 */
int add_buffer (char *p, char c, int is_address)
{
	SYMBOL *s = 0;

	/* underscore */
	if (alpha(*p)) {
		if (!is_address) {
			s = findglb(p);
			if (!s) {
				error("undefined global");
				return (0);
			}
			/* Unless preceded by an address operator, we
			   need to get the value, and it better be
			   constant... */
			p = get_const(s);
			if (!p) {
				error("non-constant initializer");
				return (0);
			}
		}
		else if (c != '(') {
			/* If we want the address, we need an underscore
			   prefix. */
			if (const_data_idx < MAX_CONST_DATA)
				const_data[const_data_idx++] = '_';
		}
	}

	/* string */
	while (*p) {
		if (const_data_idx < MAX_CONST_DATA)
			const_data[const_data_idx++] = *p;
		p++;
	}

	/* tell the caller if there were any addresses involved */
	return ((s && s->ident == POINTER) || is_address);
}
Esempio n. 10
0
/* この関数内のラベル処理(飛先処理)の明快さのために以下のマクロを使用する */
#define UPLABEL(pos)  pos=nextCodeCt()              /* 上ジャンプ用ラベル機能 */
#define JMP_UP(pos)   gencode2(JMP,pos)             /* JMPでUPLABELへ         */
#define JPT_UP(pos)   gencode2(JPT,pos)             /* JPTでUPLABELへ         */
#define JMP_DOWN(pos) pos=gencode2(JMP,0)           /* JMPでDWNLABELへ        */
#define JPF_DOWN(pos) pos=gencode2(JPF,0)           /* JPFでDWNLABELへ        */
#define DWNLABEL(pos) backPatch(pos,nextCodeCt())   /* 下ジャンプ用ラベル機能 */
void statement(void) /* 文の処理 */
{
  TknKind kd;
  SymTbl *tp;
  DtType ret_typ = fncPt->dtTyp;
  int i, val;
  int LB_TOP, LB_EXP2, LB_EXP3, LB_BODY, LB_ELSE, LB_END, LB_TBL;

  kd = token.kind;

  if (kd==While || kd==Do || kd==Switch) continue_break_begin(kd);
  switch (kd) {
  case Break:
    if (loopNest_ct == 0) err_s("不正なbreak");
    else {
      gencode2(JMP, NO_FIX_BREAK_ADRS);                     /* 該当末尾位置へ */
      loopNest[loopNest_ct].break_flg = TRUE;              /* breakありを記憶 */
    }
    token = chk_nextTkn(nextTkn(), ';');                          /* ; のはず */
    break;
  case Continue:
    gencode2(JMP, get_loopTop());                   /* ループ開始行へジャンプ */
    token = chk_nextTkn(nextTkn(), ';');                          /* ; のはず */
    break;
  case Case:
    token = nextTkn();
    get_const(NULL);                                          /* 定数判定準備 */
    expr_with_chk(0, ':');                                      /* [式]の処理 */
    if (!get_const(&val))      err_s("case式が定数式でない");
    else if (swchNest_ct == 0) err_s("対応するswitch文がない");
    else {
      for (i=swchNest[swchNest_ct].startCaseList; i<=caseList_ct; i++) {
        if (caseList[i].value == val) {
          err_s("case式の値が重複している"); break;
        }
      }
      incVar(&caseList_ct, CASE_SIZ, "case句が%d個を超えました。");
      caseList[caseList_ct].value = val;                        /* case値設定 */
      caseList[caseList_ct].adrs = nextCodeCt();              /* 対応番地設定 */
    }
    statement();                                                  /* 文の処理 */
    break;
  case Default:
    if (swchNest_ct == 0)
      err_s("対応するswitch文がない");
    else if (swchNest[swchNest_ct].def_adrs != -1)
      err_s("defaultが重複している");
    else
      swchNest[swchNest_ct].def_adrs = nextCodeCt();              /* 番地設定 */
    token = chk_nextTkn(nextTkn(), ':');                          /* : のはず */
    statement();                                                  /* 文の処理 */
    break;
  case For:
    /*[式1]*/
    token = chk_nextTkn(nextTkn(), '(');                          /* ( のはず */
    if (token.kind == ';')
      token = nextTkn();                                           /* 式1なし */
    else {
      expr_with_chk(0, ';');                                   /* [式1]の処理 */
      remove_val();                                               /* 式値不要 */
    }

    /*[式2]*/
    UPLABEL(LB_EXP2);                               /* ←┐                   */
    if (token.kind == ';') {                        /*   │式2なし            */
      gencode2(LDI, 1);                             /*   │真(1)にする        */
      token = nextTkn();                            /*   │                   */
    } else {                                        /*   │                   */
      expr_with_chk(0, ';');                        /*   │[式2]の処理        */
    }                                               /*   │                   */
    JPF_DOWN(LB_END);                               /* ─┼┐  false時        */
    JMP_DOWN(LB_BODY);                              /* ─┼┼┐true時         */
                                                    /*   │││               */
    /*[式3]*/                                       /*   │││               */
    continue_break_begin(kd);                       /*   │││               */
    UPLABEL(LB_EXP3);                               /* ←┼┼┼┐             */
    if (token.kind == ')')                          /*   ││││             */
      token = nextTkn();                            /*   ││││式3なし      */
    else {                                          /*   ││││             */
      expr_with_chk(0, ')');                        /*   ││││[式3]の処理  */
      remove_val();                                 /*   ││││式値不要     */
    }                                               /*   ││││             */
    JMP_UP(LB_EXP2);                                /* ─┘│││             */
                                                    /*     │││             */
    /*[本体]*/                                      /*     │││             */
    DWNLABEL(LB_BODY);                              /* ←─┼┘│             */
    statement();                                    /*     │  │[文]の処理   */
    JMP_UP(LB_EXP3);                                /* ──┼─┘繰り返し     */
                                                    /*     │                 */
    /*[末尾]*/                                      /*     │                 */
    DWNLABEL(LB_END);                               /* ←─┘終端             */
    break;
  case If:
    token = nextTkn();
    expr_with_chk('(', ')');                        /*       [式]の処理       */
    JPF_DOWN(LB_ELSE);                              /* ─┐  false時          */
    statement();                                    /*   │  [文1]の処理      */
    if (token.kind != Else) {                       /*   │                   */
      DWNLABEL(LB_ELSE);                            /* ←┘elseない時の終端   */
      break;                                        /*   │                   */
    }                                               /*   │elseある時         */
    JMP_DOWN(LB_END);                               /* ─┼┐                 */
    DWNLABEL(LB_ELSE);                              /* ←┘│                 */
    token = nextTkn();                              /*     │                 */
    statement();                                    /*     │[文2]の処理      */
    DWNLABEL(LB_END);                               /* ←─┘                 */
    break;
  case While:
    token = nextTkn();
    UPLABEL(LB_TOP);                                /* ←┐                   */
    expr_with_chk('(', ')');                        /*   │  [式]の処理       */
    JPF_DOWN(LB_END);                               /* ─┼┐false時          */
    statement();                                    /*   ││[文]の処理       */
    JMP_UP(LB_TOP);                                 /* ─┘│繰り返し         */
    DWNLABEL(LB_END);                               /* ←─┘                 */
    break;
  case Do:
    token = nextTkn();
    UPLABEL(LB_TOP);                                /* ←┐                   */
    statement();                                    /*   │[文]の処理         */
    if (token.kind == While) {                      /*   │                   */
      token = nextTkn();                            /*   │                   */
      expr_with_chk('(', ')');                      /*   │[式]の処理         */
      token = chk_nextTkn(token, ';');              /*   │; のはず           */
      JPT_UP(LB_TOP);                               /* ─┘true時             */
    } else {
      err_s("do終端のwhileがない");
    }
    break;
  case Switch:
    token = nextTkn();
    expr_with_chk('(', ')');                        /*      [式]の処理        */
    JMP_DOWN(LB_TBL);                               /* ─┐  テーブル処理へ   */
    swch_begin();                                   /*   │                   */
    statement();                                    /* case,default文の処理.  */
    JMP_DOWN(LB_END);                               /* ─┼┐末尾へ           */
    DWNLABEL(LB_TBL);                               /* ←┘│                 */
    swch_end();                                     /*     │テーブル処理     */
    DWNLABEL(LB_END);                               /* ←─┘                 */
    break;
  case Return:
    token = nextTkn();
    if (token.kind == ';') {                                      /* 戻値なし */
      if (ret_typ != VOID_T) err_s("return文に戻り値がない");
    } else {                                                      /* 戻値あり */
      expression();                                               /* 戻値作成 */
      if (ret_typ == VOID_T) err_s("void型関数に値を返すreturn文がある");
    }
    gencode2(JMP, NO_FIX_RET_ADRS);                         /* 関数出口処理へ */
    token = chk_nextTkn(token, ';');                              /* ; のはず */
    break;
  case Printf: case Exit:                                   /* void型組込関数 */
    sys_fncCall(kd);
    token = chk_nextTkn(token, ';');                  /* printf() + b; を防止 */
    break;
  case Input:                                             /* 非void型組込関数 */
    expr_with_chk(0, ';');                                    /* 通常の式解析 */
    remove_val();                                                 /* 式値不要 */
    break;
  case Incre: case Decre:                                      /* ++var --var */
    expr_with_chk(0, ';');
    remove_val();                                                 /* 式値不要 */
    break;
  case Ident:                                           /* 識別子(関数か変数) */
    tp = search(token.text);                                    /* 記号表位置 */
    if ((tp->nmKind==fncId || tp->nmKind==protId) && tp->dtTyp==VOID_T) {
      fncCall(tp);                                  /* void型関数はここで処理 */
      token = chk_nextTkn(token, ';');                            /* ; のはず */
    } else {
      expr_with_chk(0, ';');                                  /* 通常の式解析 */
      remove_val();                                               /* 式値不要 */
    }
    break;
  case Lbrace:                                                    /* 複合文{} */
    block(0);                                             /* 0:非関数ブロック */
    break;
  case Semicolon:                                 /* 空文,forの実行文等で出現 */
    token = nextTkn();
    break;
  case EofTkn:                             /* 最後の } を忘れた場合などに発生 */
    err_s("意図しない終了。'}'不足? "); exit(1);
  default:
    err_ss("不正な記述", token.text);
    token = nextTkn();
  }
  if (kd==For || kd==While || kd==Do || kd==Switch) continue_break_end();
}
Esempio n. 11
0
void comp_fbcc_opp (uae_u32 opcode)
{
    uae_u32 start_68k_offset=m68k_pc_offset;
    uae_u32 off, v1, v2;
    int cc;

    if (!currprefs.compfpu) {
		FAIL(1);
		return;
    }

    if (opcode & 0x20) {  /* only cc from 00 to 1f are defined */
		FAIL(1);
		return;
    }
    if (!(opcode & 0x40)) {
		off = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
    }
    else {
		off = comp_get_ilong((m68k_pc_offset+=4)-4);
    }
    mov_l_ri(S1,(uae_u32)
	     (comp_pc_p+off-(m68k_pc_offset-start_68k_offset)));
    mov_l_ri(PC_P,(uae_u32)comp_pc_p);

    /* Now they are both constant. Might as well fold in m68k_pc_offset */
    add_l_ri(S1,m68k_pc_offset);
    add_l_ri(PC_P,m68k_pc_offset);
    m68k_pc_offset=0;

    /* according to fpp.c, the 0x10 bit is ignored
       (it handles exception handling, which we don't
       do, anyway ;-) */
    cc = opcode & 0x0f;
    v1 = get_const(PC_P);
    v2 = get_const(S1);
    fflags_into_flags(S2);

    // mov_l_mi((uae_u32)&foink3,cc);
    switch(cc) {
	case 0: break;  /* jump never */
	case 1:
		mov_l_rr(S2,PC_P);
		cmov_l_rr(PC_P,S1,4);
	cmov_l_rr(PC_P,S2,10); break;
	case 2: register_branch(v1,v2,7); break;
	case 3: register_branch(v1,v2,3); break;
	case 4:
		mov_l_rr(S2,PC_P);
		cmov_l_rr(PC_P,S1,2);
	cmov_l_rr(PC_P,S2,10); break;
	case 5:
		mov_l_rr(S2,PC_P);
		cmov_l_rr(PC_P,S1,6);
	cmov_l_rr(PC_P,S2,10); break;
     case 6: register_branch(v1,v2,5); break;
     case 7: register_branch(v1,v2,11); break;
     case 8: register_branch(v1,v2,10); break;
     case 9: register_branch(v1,v2,4); break;
	case 10:
		cmov_l_rr(PC_P,S1,10);
	cmov_l_rr(PC_P,S1,7); break;
	case 11:
		cmov_l_rr(PC_P,S1,4);
	cmov_l_rr(PC_P,S1,3); break;
     case 12: register_branch(v1,v2,2); break;
     case 13: register_branch(v1,v2,6); break;
	case 14:
		cmov_l_rr(PC_P,S1,5);
	cmov_l_rr(PC_P,S1,10); break;
     case 15: mov_l_rr(PC_P,S1); break;
    }
}
Esempio n. 12
0
 Object* Module::get_const(STATE, const char* sym) {
   return get_const(state, state->symbol(sym));
 }
Esempio n. 13
0
 Object* Module::get_const(STATE, Symbol* sym) {
   bool found;
   return get_const(state, sym, &found);
 }
Esempio n. 14
0
 Object* Module::get_const(STATE, std::string sym) {
   return get_const(state, state->symbol(sym));
 }
Esempio n. 15
0
bool expr_handler::fold_alu_op1(alu_node& n) {

	assert(!n.src.empty());
	if (n.src.empty())
		return false;

	/* don't fold LDS instructions */
	if (n.bc.op_ptr->flags & AF_LDS)
		return false;

	value* v0 = n.src[0]->gvalue();

	if (v0->is_lds_oq() || v0->is_lds_access())
		return false;
	assert(v0 && n.dst[0]);

	if (!v0->is_const()) {
		// handle (MOV -(MOV -x)) => (MOV x)
		if (n.bc.op == ALU_OP1_MOV && n.bc.src[0].neg && !n.bc.src[1].abs
				&& v0->def && v0->def->is_alu_op(ALU_OP1_MOV)) {
			alu_node *sd = static_cast<alu_node*>(v0->def);
			if (!sd->bc.clamp && !sd->bc.omod && !sd->bc.src[0].abs &&
					sd->bc.src[0].neg) {
				n.src[0] = sd->src[0];
				n.bc.src[0].neg = 0;
				v0 = n.src[0]->gvalue();
			}
		}

		if ((n.bc.op == ALU_OP1_MOV || n.bc.op == ALU_OP1_MOVA_INT ||
				n.bc.op == ALU_OP1_MOVA_GPR_INT)
				&& n.bc.clamp == 0 && n.bc.omod == 0
				&& n.bc.src[0].abs == 0 && n.bc.src[0].neg == 0 &&
				n.src.size() == 1 /* RIM/SIM can be appended as additional values */
				&& n.dst[0]->no_reladdr_conflict_with(v0)) {
			assign_source(n.dst[0], v0);
			return true;
		}
		return false;
	}

	literal dv, cv = v0->get_const_value();
	apply_alu_src_mod(n.bc, 0, cv);

	switch (n.bc.op) {
	case ALU_OP1_CEIL: dv = ceil(cv.f); break;
	case ALU_OP1_COS: dv = cos(cv.f * 2.0f * M_PI); break;
	case ALU_OP1_EXP_IEEE: dv = exp2(cv.f); break;
	case ALU_OP1_FLOOR: dv = floor(cv.f); break;
	case ALU_OP1_FLT_TO_INT: dv = (int)cv.f; break; // FIXME: round modes ????
	case ALU_OP1_FLT_TO_INT_FLOOR: dv = (int32_t)floor(cv.f); break;
	case ALU_OP1_FLT_TO_INT_RPI: dv = (int32_t)floor(cv.f + 0.5f); break;
	case ALU_OP1_FLT_TO_INT_TRUNC: dv = (int32_t)trunc(cv.f); break;
	case ALU_OP1_FLT_TO_UINT: dv = (uint32_t)cv.f; break;
	case ALU_OP1_FRACT: dv = cv.f - floor(cv.f); break;
	case ALU_OP1_INT_TO_FLT: dv = (float)cv.i; break;
	case ALU_OP1_LOG_CLAMPED:
	case ALU_OP1_LOG_IEEE:
		if (cv.f != 0.0f)
			dv = log2(cv.f);
		else
			// don't fold to NAN, let the GPU handle it for now
			// (prevents degenerate LIT tests from failing)
			return false;
		break;
	case ALU_OP1_MOV: dv = cv; break;
	case ALU_OP1_MOVA_INT: dv = cv; break; // FIXME ???
//	case ALU_OP1_MOVA_FLOOR: dv = (int32_t)floor(cv.f); break;
//	case ALU_OP1_MOVA_GPR_INT:
	case ALU_OP1_NOT_INT: dv = ~cv.i; break;
	case ALU_OP1_PRED_SET_INV:
		dv = cv.f == 0.0f ? 1.0f : (cv.f == 1.0f ? 0.0f : cv.f); break;
	case ALU_OP1_PRED_SET_RESTORE: dv = cv; break;
	case ALU_OP1_RECIPSQRT_CLAMPED:
	case ALU_OP1_RECIPSQRT_FF:
	case ALU_OP1_RECIPSQRT_IEEE: dv = 1.0f / sqrt(cv.f); break;
	case ALU_OP1_RECIP_CLAMPED:
	case ALU_OP1_RECIP_FF:
	case ALU_OP1_RECIP_IEEE: dv = 1.0f / cv.f; break;
//	case ALU_OP1_RECIP_INT:
	case ALU_OP1_RECIP_UINT: dv.u = (1ull << 32) / cv.u; break;
//	case ALU_OP1_RNDNE: dv = floor(cv.f + 0.5f); break;
	case ALU_OP1_SIN: dv = sin(cv.f * 2.0f * M_PI); break;
	case ALU_OP1_SQRT_IEEE: dv = sqrt(cv.f); break;
	case ALU_OP1_TRUNC: dv = trunc(cv.f); break;

	default:
		return false;
	}

	apply_alu_dst_mod(n.bc, dv);
	assign_source(n.dst[0], get_const(dv));
	return true;
}
Esempio n. 16
0
 Object* Module::get_const(STATE, Symbol* sym) {
   ConstantMissingReason reason;
   return get_const(state, sym, G(sym_private), &reason);
 }
Esempio n. 17
0
bool expr_handler::fold_alu_op2(alu_node& n) {

	if (n.src.size() < 2)
		return false;

	unsigned flags = n.bc.op_ptr->flags;

	if (flags & AF_SET) {
		return fold_setcc(n);
	}

	if (!sh.safe_math && (flags & AF_M_ASSOC)) {
		if (fold_assoc(&n))
			return true;
	}

	value* v0 = n.src[0]->gvalue();
	value* v1 = n.src[1]->gvalue();

	assert(v0 && v1);

	// handle some operations with equal args, e.g. x + x => x * 2
	if (v0 == v1) {
		if (n.bc.src[0].neg == n.bc.src[1].neg &&
				n.bc.src[0].abs == n.bc.src[1].abs) {
			switch (n.bc.op) {
			case ALU_OP2_MIN: // (MIN x, x) => (MOV x)
			case ALU_OP2_MIN_DX10:
			case ALU_OP2_MAX:
			case ALU_OP2_MAX_DX10:
				convert_to_mov(n, v0, n.bc.src[0].neg, n.bc.src[0].abs);
				return fold_alu_op1(n);
			case ALU_OP2_ADD:  // (ADD x, x) => (MUL x, 2)
				if (!sh.safe_math) {
					n.src[1] = sh.get_const_value(2.0f);
					memset(&n.bc.src[1], 0, sizeof(bc_alu_src));
					n.bc.set_op(ALU_OP2_MUL);
					return fold_alu_op2(n);
				}
				break;
			}
		}
		if (n.bc.src[0].neg != n.bc.src[1].neg &&
				n.bc.src[0].abs == n.bc.src[1].abs) {
			switch (n.bc.op) {
			case ALU_OP2_ADD:  // (ADD x, -x) => (MOV 0)
				if (!sh.safe_math) {
					convert_to_mov(n, sh.get_const_value(literal(0)));
					return fold_alu_op1(n);
				}
				break;
			}
		}
	}

	if (n.bc.op == ALU_OP2_ADD) {
		if (fold_mul_add(&n))
			return true;
	}

	bool isc0 = v0->is_const();
	bool isc1 = v1->is_const();

	if (!isc0 && !isc1)
		return false;

	literal dv, cv0, cv1;

	if (isc0) {
		cv0 = v0->get_const_value();
		apply_alu_src_mod(n.bc, 0, cv0);
	}

	if (isc1) {
		cv1 = v1->get_const_value();
		apply_alu_src_mod(n.bc, 1, cv1);
	}

	if (isc0 && isc1) {

		if (!eval_const_op(n.bc.op, dv, cv0, cv1))
			return false;

	} else { // one source is const

		if (isc0 && cv0 == literal(0)) {
			switch (n.bc.op) {
			case ALU_OP2_ADD:
			case ALU_OP2_ADD_INT:
			case ALU_OP2_MAX_UINT:
			case ALU_OP2_OR_INT:
			case ALU_OP2_XOR_INT:
				convert_to_mov(n, n.src[1], n.bc.src[1].neg,  n.bc.src[1].abs);
				return fold_alu_op1(n);
			case ALU_OP2_AND_INT:
			case ALU_OP2_ASHR_INT:
			case ALU_OP2_LSHL_INT:
			case ALU_OP2_LSHR_INT:
			case ALU_OP2_MIN_UINT:
			case ALU_OP2_MUL:
			case ALU_OP2_MULHI_UINT:
			case ALU_OP2_MULLO_UINT:
				convert_to_mov(n, sh.get_const_value(literal(0)));
				return fold_alu_op1(n);
			}
		} else if (isc1 && cv1 == literal(0)) {
			switch (n.bc.op) {
			case ALU_OP2_ADD:
			case ALU_OP2_ADD_INT:
			case ALU_OP2_ASHR_INT:
			case ALU_OP2_LSHL_INT:
			case ALU_OP2_LSHR_INT:
			case ALU_OP2_MAX_UINT:
			case ALU_OP2_OR_INT:
			case ALU_OP2_SUB_INT:
			case ALU_OP2_XOR_INT:
				convert_to_mov(n, n.src[0], n.bc.src[0].neg,  n.bc.src[0].abs);
				return fold_alu_op1(n);
			case ALU_OP2_AND_INT:
			case ALU_OP2_MIN_UINT:
			case ALU_OP2_MUL:
			case ALU_OP2_MULHI_UINT:
			case ALU_OP2_MULLO_UINT:
				convert_to_mov(n, sh.get_const_value(literal(0)));
				return fold_alu_op1(n);
			}
		} else if (isc0 && cv0 == literal(1.0f)) {
			switch (n.bc.op) {
			case ALU_OP2_MUL:
			case ALU_OP2_MUL_IEEE:
				convert_to_mov(n, n.src[1], n.bc.src[1].neg,  n.bc.src[1].abs);
				return fold_alu_op1(n);
			}
		} else if (isc1 && cv1 == literal(1.0f)) {
			switch (n.bc.op) {
			case ALU_OP2_MUL:
			case ALU_OP2_MUL_IEEE:
				convert_to_mov(n, n.src[0], n.bc.src[0].neg,  n.bc.src[0].abs);
				return fold_alu_op1(n);
			}
		}

		return false;
	}

	apply_alu_dst_mod(n.bc, dv);
	assign_source(n.dst[0], get_const(dv));
	return true;
}
Esempio n. 18
0
bool expr_handler::fold_alu_op3(alu_node& n) {

	if (n.src.size() < 3)
		return false;

	if (!sh.safe_math && (n.bc.op_ptr->flags & AF_M_ASSOC)) {
		if (fold_assoc(&n))
			return true;
		if (n.src.size() < 3)
			return fold_alu_op2(n);
	}

	value* v0 = n.src[0]->gvalue();
	value* v1 = n.src[1]->gvalue();
	value* v2 = n.src[2]->gvalue();

	/* LDS instructions look like op3 with no dst - don't fold. */
	if (!n.dst[0])
		return false;
	assert(v0 && v1 && v2 && n.dst[0]);

	bool isc0 = v0->is_const();
	bool isc1 = v1->is_const();
	bool isc2 = v2->is_const();

	literal dv, cv0, cv1, cv2;

	if (isc0) {
		cv0 = v0->get_const_value();
		apply_alu_src_mod(n.bc, 0, cv0);
	}

	if (isc1) {
		cv1 = v1->get_const_value();
		apply_alu_src_mod(n.bc, 1, cv1);
	}

	if (isc2) {
		cv2 = v2->get_const_value();
		apply_alu_src_mod(n.bc, 2, cv2);
	}

	unsigned flags = n.bc.op_ptr->flags;

	if (flags & AF_CMOV) {
		int src = 0;

		if (v1 == v2 && n.bc.src[1].neg == n.bc.src[2].neg) {
			// result doesn't depend on condition, convert to MOV
			src = 1;
		} else if (isc0) {
			// src0 is const, condition can be evaluated, convert to MOV
			bool cond = evaluate_condition(n.bc.op_ptr->flags & (AF_CC_MASK |
					AF_CMP_TYPE_MASK), cv0, literal(0));
			src = cond ? 1 : 2;
		}

		if (src) {
			// if src is selected, convert to MOV
			convert_to_mov(n, n.src[src], n.bc.src[src].neg);
			return fold_alu_op1(n);
		}
	}

	// handle (MULADD a, x, MUL (x, b)) => (MUL x, ADD (a, b))
	if (!sh.safe_math && (n.bc.op == ALU_OP3_MULADD ||
			n.bc.op == ALU_OP3_MULADD_IEEE)) {

		unsigned op = n.bc.op == ALU_OP3_MULADD_IEEE ?
				ALU_OP2_MUL_IEEE : ALU_OP2_MUL;

		if (!isc2 && v2->def && v2->def->is_alu_op(op)) {

			alu_node *md = static_cast<alu_node*>(v2->def);
			value *mv0 = md->src[0]->gvalue();
			value *mv1 = md->src[1]->gvalue();

			int es0 = -1, es1;

			if (v0 == mv0) {
				es0 = 0;
				es1 = 0;
			} else if (v0 == mv1) {
				es0 = 0;
				es1 = 1;
			} else if (v1 == mv0) {
				es0 = 1;
				es1 = 0;
			} else if (v1 == mv1) {
				es0 = 1;
				es1 = 1;
			}

			value *va0 = es0 == 0 ? v1 : v0;
			value *va1 = es1 == 0 ? mv1 : mv0;

			/* Don't fold if no equal multipliers were found.
			 * Also don#t fold if the operands of the to be created ADD are both
			 * relatively accessed with different AR values because that would
			 * create impossible code.
			 */
			if (es0 != -1 &&
			    (!va0->is_rel() || !va1->is_rel() ||
			     (va0->rel == va1->rel))) {

				alu_node *add = sh.create_alu();
				add->bc.set_op(ALU_OP2_ADD);

				add->dst.resize(1);
				add->src.resize(2);

				value *t = sh.create_temp_value();
				t->def = add;
				add->dst[0] = t;
				add->src[0] = va0;
				add->src[1] = va1;
				add->bc.src[0] = n.bc.src[!es0];
				add->bc.src[1] = md->bc.src[!es1];

				add->bc.src[1].neg ^= n.bc.src[2].neg ^
						(n.bc.src[es0].neg != md->bc.src[es1].neg);

				n.insert_before(add);
				vt.add_value(t);

				t = t->gvalue();

				if (es0 == 1) {
					n.src[0] = n.src[1];
					n.bc.src[0] = n.bc.src[1];
				}

				n.src[1] = t;
				memset(&n.bc.src[1], 0, sizeof(bc_alu_src));

				n.src.resize(2);

				n.bc.set_op(op);
				return fold_alu_op2(n);
			}
		}
	}

	if (!isc0 && !isc1 && !isc2)
		return false;

	if (isc0 && isc1 && isc2) {
		switch (n.bc.op) {
		case ALU_OP3_MULADD_IEEE:
		case ALU_OP3_MULADD: dv = cv0.f * cv1.f + cv2.f; break;

		// TODO

		default:
			return false;
		}
	} else {
		if (isc0 && isc1) {
			switch (n.bc.op) {
			case ALU_OP3_MULADD:
			case ALU_OP3_MULADD_IEEE:
				dv = cv0.f * cv1.f;
				n.bc.set_op(ALU_OP2_ADD);
				n.src[0] = sh.get_const_value(dv);
				memset(&n.bc.src[0], 0, sizeof(bc_alu_src));
				n.src[1] = n.src[2];
				n.bc.src[1] = n.bc.src[2];
				n.src.resize(2);
				return fold_alu_op2(n);
			}
		}

		if (n.bc.op == ALU_OP3_MULADD) {
			if ((isc0 && cv0 == literal(0)) || (isc1 && cv1 == literal(0))) {
				convert_to_mov(n, n.src[2], n.bc.src[2].neg,  n.bc.src[2].abs);
				return fold_alu_op1(n);
			}
		}

		if (n.bc.op == ALU_OP3_MULADD || n.bc.op == ALU_OP3_MULADD_IEEE) {
			unsigned op = n.bc.op == ALU_OP3_MULADD_IEEE ?
					ALU_OP2_MUL_IEEE : ALU_OP2_MUL;

			if (isc1 && v0 == v2) {
				cv1.f += (n.bc.src[2].neg != n.bc.src[0].neg ? -1.0f : 1.0f);
				n.src[1] = sh.get_const_value(cv1);
				n.bc.src[1].neg = 0;
				n.bc.src[1].abs = 0;
				n.bc.set_op(op);
				n.src.resize(2);
				return fold_alu_op2(n);
			} else if (isc0 && v1 == v2) {
				cv0.f += (n.bc.src[2].neg != n.bc.src[1].neg ? -1.0f : 1.0f);
				n.src[0] = sh.get_const_value(cv0);
				n.bc.src[0].neg = 0;
				n.bc.src[0].abs = 0;
				n.bc.set_op(op);
				n.src.resize(2);
				return fold_alu_op2(n);
			}
		}

		return false;
	}

	apply_alu_dst_mod(n.bc, dv);
	assign_source(n.dst[0], get_const(dv));
	return true;
}
 void get_constant_pool(Register reg)                     { get_const(reg); movptr(reg, Address(reg, constMethodOopDesc::constants_offset())); }