* Map an Add (a_l, a_h, b_l, b_h)
*/
static int map_Add(ir_node *call, void *ctx) {
- ir_graph *irg = current_ir_graph;
- dbg_info *dbg = get_irn_dbg_info(call);
- ir_node *block = get_nodes_block(call);
- ir_node **params = get_Call_param_arr(call);
- ir_type *method = get_Call_type(call);
- ir_node *a_l = params[BINOP_Left_Low];
- ir_node *a_h = params[BINOP_Left_High];
- ir_node *b_l = params[BINOP_Right_Low];
- ir_node *b_h = params[BINOP_Right_High];
- ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
- ir_node *l_res, *h_res, *add;
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbg = get_irn_dbg_info(call);
+ ir_node *block = get_nodes_block(call);
+ ir_node **params = get_Call_param_arr(call);
+ ir_type *method = get_Call_type(call);
+ ir_node *a_l = params[BINOP_Left_Low];
+ ir_node *a_h = params[BINOP_Left_High];
+ ir_node *b_l = params[BINOP_Right_Low];
+ ir_node *b_h = params[BINOP_Right_High];
+ ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
+ ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
+ ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
+ ir_node *add_low, *add_high, *flags;
+ ir_node *l_res, *h_res;
(void) ctx;
assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
/* l_res = a_l + b_l */
/* h_res = a_h + b_h + carry */
- add = new_rd_ia32_Add64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
- l_res = new_r_Proj(irg, block, add, l_mode, pn_ia32_Add64Bit_low_res);
- h_res = new_r_Proj(irg, block, add, l_mode, pn_ia32_Add64Bit_high_res);
+ add_low = new_rd_ia32_l_Add(dbg, irg, block, a_l, b_l, mode_T);
+ flags = new_r_Proj(irg, block, add_low, mode_flags, pn_ia32_flags);
+ add_high = new_rd_ia32_l_Adc(dbg, irg, block, a_h, b_h, flags, h_mode);
+
+ l_res = new_r_Proj(irg, block, add_low, l_mode, pn_ia32_res);
+ h_res = add_high;
resolve_call(call, l_res, h_res, irg, block);
return 1;
h_res = t2 + t3
*/
- if (is_Shrs(a_h) && get_Shrs_left(a_h) == a_l &&
- is_Shrs(b_h) && get_Shrs_left(b_h) == b_l) {
+ /* handle the often used case of 32x32=64 mul */
+ if (is_Shrs(a_h) && get_Shrs_left(a_h) == a_l) {
ir_node *c1 = get_Shrs_right(a_h);
- if (c1 == get_Shrs_right(b_h) && is_Const(c1)) {
+ if (is_Const(c1)) {
tarval *tv = get_Const_tarval(c1);
if (tarval_is_long(tv) && get_tarval_long(tv) == 31) {
- /* it's a 32 * 32 = 64 signed multiplication */
-
- mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
- h_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
- l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
-
- goto end;
+ /* a is a sign extend */
+
+ if (is_Shrs(b_h) && get_Shrs_left(b_h) == b_l && c1 == get_Shrs_right(b_h)) {
+ /* b is a sign extend: it's a 32 * 32 = 64 signed multiplication */
+ mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
+ h_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
+ l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
+
+ goto end;
+ }
+ /* we rely here on Consts being on the right site */
+ if (is_Const(b_h) && is_Const(b_l)) {
+ tarval *th = get_Const_tarval(b_h);
+ tarval *tl = get_Const_tarval(b_l);
+
+ if (tarval_is_long(th) && tarval_is_long(tl)) {
+ long h = get_tarval_long(th);
+ long l = get_tarval_long(tl);
+
+ if ((h == 0 && l >= 0) || (h == -1 && l < 0)) {
+ /* b is a sign extended const */
+ mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
+ h_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
+ l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
+
+ goto end;
+ }
+ }
+ }
}
}
+
}
mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
*/
- sign = new_rd_ia32_l_Sar(dbg, irg, block, a_h, new_Const_long(l_mode, 31), l_mode);
- sub_l = new_rd_ia32_l_Xor(dbg, irg, block, a_l, sign, l_mode);
- sub_h = new_rd_ia32_l_Xor(dbg, irg, block, a_h, sign, l_mode);
+ /* TODO: give a hint to the backend somehow to not create a cltd here... */
+ sign = new_rd_Shrs(dbg, irg, block, a_h, new_Const_long(l_mode, 31), l_mode);
+ sub_l = new_rd_Eor(dbg, irg, block, a_l, sign, l_mode);
+ sub_h = new_rd_Eor(dbg, irg, block, a_h, sign, l_mode);
res = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign);
l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);