+ bool is_or = (expression->type == BINEXPR_LOGICAL_OR);
+ assert(is_or || expression->type == BINEXPR_LOGICAL_AND);
+
+ ir_node *val1 = expression_to_modeb(expression->left);
+ ir_node *cond = new_d_Cond(dbgi, val1);
+ ir_node *true_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_true);
+ ir_node *false_proj = new_d_Proj(dbgi, cond, mode_X, pn_Cond_false);
+
+ ir_node *fallthrough_block = new_immBlock();
+
+ /* the true case */
+ ir_node *calc_val2_block = new_immBlock();
+ if(is_or) {
+ add_immBlock_pred(calc_val2_block, false_proj);
+ } else {
+ add_immBlock_pred(calc_val2_block, true_proj);
+ }
+
+ mature_immBlock(calc_val2_block);
+
+ ir_node *val2 = expression_to_modeb(expression->right);
+ if(get_cur_block() != NULL) {
+ ir_node *jmp = new_d_Jmp(dbgi);
+ add_immBlock_pred(fallthrough_block, jmp);
+ }
+
+ /* fallthrough */
+ ir_node *constb;
+ if(is_or) {
+ constb = new_d_Const(dbgi, mode_b, get_tarval_b_true());
+ add_immBlock_pred(fallthrough_block, true_proj);
+ } else {
+ constb = new_d_Const(dbgi, mode_b, get_tarval_b_false());
+ add_immBlock_pred(fallthrough_block, false_proj);
+ }
+ mature_immBlock(fallthrough_block);
+
+ set_cur_block(fallthrough_block);
+
+ ir_node *in[2] = { val2, constb };
+ ir_node *val = new_d_Phi(dbgi, 2, in, mode_b);
+
+ return val;
+}
+
+typedef ir_node * (*create_arithmetic_func)(dbg_info *dbgi, ir_node *left,
+ ir_node *right, ir_mode *mode);
+
+static ir_node *create_arithmetic_binop(const binary_expression_t *expression,
+ create_arithmetic_func func)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
+ ir_node *left = expression_to_firm(expression->left);
+ ir_node *right = expression_to_firm(expression->right);
+ type_t *type = expression->right->datatype;
+ /* be careful with the modes, because in asithmetic assign nodes only
+ * the right operand has the mode of the arithmetic alread */
+ ir_mode *mode = get_ir_mode(type);
+ left = create_conv(dbgi, left, mode);
+ ir_node *res = func(dbgi, left, right, mode);
+
+ return res;
+}
+
+static ir_node *create_arithmetic_assign_binop(
+ const binary_expression_t *expression, create_arithmetic_func func)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
+ ir_node *value = create_arithmetic_binop(expression, func);
+ type_t *type = expression->expression.datatype;
+ ir_mode *mode = get_ir_mode(type);
+
+ assert(type->type != TYPE_POINTER);
+
+ value = create_conv(dbgi, value, mode);
+ set_value_for_expression(expression->left, value);
+
+ return value;
+}
+
+static ir_node *create_add(const binary_expression_t *expression)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
+ ir_node *left = expression_to_firm(expression->left);
+ ir_node *right = expression_to_firm(expression->right);
+ type_t *type = expression->expression.datatype;
+ ir_mode *mode = get_ir_mode(type);
+
+ expression_t *expr_left = expression->left;
+ expression_t *expr_right = expression->right;
+ type_t *type_left = skip_typeref(expr_left->datatype);
+ type_t *type_right = skip_typeref(expr_right->datatype);
+
+ if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
+ return new_d_Add(dbgi, left, right, mode);
+ }
+
+ ir_node *pointer;
+ ir_node *integer;
+ pointer_type_t *pointer_type;
+ if(type_left->type == TYPE_POINTER) {
+ pointer = left;
+ integer = right;
+ pointer_type = (pointer_type_t*) type_left;
+ } else {
+ assert(type_right->type == TYPE_POINTER);
+ pointer = right;
+ integer = left;
+ pointer_type = (pointer_type_t*) type_right;
+ }
+
+ type_t *points_to = pointer_type->points_to;
+ unsigned elem_size = get_type_size(points_to);
+
+ assert(elem_size >= 1);
+ if(elem_size > 1) {
+ integer = create_conv(dbgi, integer, mode_Is);
+ ir_node *cnst = new_Const_long(mode_Is, (int) elem_size);
+ ir_node *mul = new_d_Mul(dbgi, integer, cnst, mode_Is);
+ integer = mul;
+ }
+
+ ir_node *res = new_d_Add(dbgi, pointer, integer, mode);
+
+ return res;
+}
+
+static ir_node *create_sub(const binary_expression_t *expression)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
+ ir_node *left = expression_to_firm(expression->left);
+ ir_node *right = expression_to_firm(expression->right);
+ type_t *type = expression->expression.datatype;
+ ir_mode *mode = get_ir_mode(type);
+
+ expression_t *expr_left = expression->left;
+ expression_t *expr_right = expression->right;
+ type_t *type_left = skip_typeref(expr_left->datatype);
+ type_t *type_right = skip_typeref(expr_right->datatype);
+
+ if((is_type_arithmetic(type_left) && is_type_arithmetic(type_right))
+ || (type_left->type == TYPE_POINTER
+ && type_right->type == TYPE_POINTER)) {
+ return new_d_Sub(dbgi, left, right, mode);
+ }
+
+ assert(type_right->type == TYPE_POINTER);
+ ir_node *pointer = left;
+ ir_node *integer = right;
+ pointer_type_t *pointer_type = (pointer_type_t*) type_right;
+
+ type_t *points_to = pointer_type->points_to;
+ unsigned elem_size = get_type_size(points_to);
+
+ assert(elem_size >= 1);
+ if(elem_size > 1) {
+ ir_node *cnst = new_Const_long(mode_Iu, elem_size);
+ ir_node *mul = new_d_Mul(dbgi, integer, cnst, mode_Iu);
+ integer = mul;
+ }
+
+ ir_node *res = new_d_Sub(dbgi, pointer, integer, mode);
+
+ return res;
+}
+
+static ir_node *create_shift(const binary_expression_t *expression)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
+ ir_node *left = expression_to_firm(expression->left);
+ ir_node *right = expression_to_firm(expression->right);
+ type_t *type = expression->expression.datatype;
+ ir_mode *mode = get_ir_mode(type);
+
+ /* firm always wants the shift count to be unsigned */
+ right = create_conv(dbgi, right, mode_Iu);
+
+ ir_node *res;
+
+ switch(expression->type) {
+ case BINEXPR_SHIFTLEFT:
+ res = new_d_Shl(dbgi, left, right, mode);
+ break;
+ case BINEXPR_SHIFTRIGHT: {
+ expression_t *expr_left = expression->left;
+ type_t *type_left = skip_typeref(expr_left->datatype);
+
+ if(is_type_signed(type_left)) {
+ res = new_d_Shrs(dbgi, left, right, mode);
+ } else {
+ res = new_d_Shr(dbgi, left, right, mode);
+ }
+ break;
+ }
+ default:
+ panic("create shift op called for non-shift op");
+ }
+
+ return res;
+}
+
+
+static ir_node *create_divmod(const binary_expression_t *expression)
+{
+ dbg_info *dbgi = get_dbg_info(&expression->expression.source_position);
+ ir_node *left = expression_to_firm(expression->left);
+ ir_node *right = expression_to_firm(expression->right);
+ ir_node *pin = new_Pin(new_NoMem());
+ type_t *type = expression->expression.datatype;
+ ir_mode *mode = get_ir_mode(type);
+ ir_node *op;
+ ir_node *res;
+
+ if(expression->type == BINEXPR_DIV) {
+ if(mode_is_float(mode)) {
+ op = new_d_Quot(dbgi, pin, left, right, mode, op_pin_state_floats);
+ res = new_d_Proj(dbgi, op, mode, pn_Quot_res);
+ } else {
+ op = new_d_Div(dbgi, pin, left, right, mode, op_pin_state_floats);
+ res = new_d_Proj(dbgi, op, mode, pn_Div_res);
+ }
+ } else {
+ assert(expression->type == BINEXPR_MOD);
+ assert(!mode_is_float(mode));
+ op = new_d_Mod(dbgi, pin, left, right, mode, op_pin_state_floats);
+ res = new_d_Proj(dbgi, op, mode, pn_Mod_res);
+ }
+
+ return res;
+}
+
+
+
+static ir_node *binary_expression_to_firm(const binary_expression_t *expression)
+{