+ ir_node *cur_block = get_cur_block();
+
+ ir_node *one_block = new_immBlock();
+ ir_node *one = new_Const(mode, get_mode_one(mode));
+ ir_node *jmp_one = new_d_Jmp(dbgi);
+
+ ir_node *zero_block = new_immBlock();
+ ir_node *zero = new_Const(mode, get_mode_null(mode));
+ ir_node *jmp_zero = new_d_Jmp(dbgi);
+
+ set_cur_block(cur_block);
+ create_condition_evaluation((const expression_t*) expression,
+ one_block, zero_block);
+ mature_immBlock(one_block);
+ mature_immBlock(zero_block);
+
+ ir_node *common_block = new_immBlock();
+ add_immBlock_pred(common_block, jmp_one);
+ add_immBlock_pred(common_block, jmp_zero);
+ mature_immBlock(common_block);
+
+ ir_node *in[2] = { one, zero };
+ ir_node *val = new_d_Phi(dbgi, 2, in, mode);
+
+ 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 *pointer_arithmetic(ir_node *const pointer,
+ ir_node * integer,
+ type_t *const type,
+ dbg_info *const dbgi,
+ const create_arithmetic_func func)
+{
+ pointer_type_t *const pointer_type = (pointer_type_t*)type;
+ type_t *const points_to = pointer_type->points_to;
+ const 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 *const cnst = new_Const_long(mode_Is, (long)elem_size);
+ ir_node *const mul = new_d_Mul(dbgi, integer, cnst, mode_Is);
+ integer = mul;
+ }
+
+ ir_mode *const mode = get_ir_mode(type);
+ return func(dbgi, pointer, integer, mode);
+}
+
+static ir_node *create_arithmetic_assign_binop(
+ const binary_expression_t *expression, create_arithmetic_func func)
+{
+ dbg_info *const dbgi = get_dbg_info(&expression->expression.source_position);
+ type_t *const type = expression->expression.datatype;
+ ir_node *value;
+
+ if (type->type == TYPE_POINTER) {
+ ir_node *const pointer = expression_to_firm(expression->left);
+ ir_node * integer = expression_to_firm(expression->right);
+ value = pointer_arithmetic(pointer, integer, type, dbgi, func);
+ } else {
+ value = create_arithmetic_binop(expression, func);
+ }
+
+ ir_mode *const mode = get_ir_mode(type);
+ 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;
+
+ 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)) {
+ ir_mode *const mode = get_ir_mode(type);
+ return new_d_Add(dbgi, left, right, mode);
+ }
+
+ if (type_left->type == TYPE_POINTER || type_left->type == TYPE_ARRAY) {
+ return pointer_arithmetic(left, right, type, dbgi, new_d_Add);
+ } else {
+ assert(type_right->type == TYPE_POINTER || type_right->type == TYPE_ARRAY);
+ return pointer_arithmetic(right, left, type, dbgi, new_d_Add);
+ }
+}
+
+static ir_node *create_sub(const binary_expression_t *expression)
+{
+ dbg_info *const dbgi = get_dbg_info(&expression->expression.source_position);
+ expression_t *const expr_left = expression->left;
+ expression_t *const expr_right = expression->right;
+ ir_node *const left = expression_to_firm(expr_left);
+ ir_node *const right = expression_to_firm(expr_right);
+ type_t *const type = expression->expression.datatype;
+ type_t *const type_left = skip_typeref(expr_left->datatype);
+ type_t *const 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)) {
+ ir_mode *const mode = get_ir_mode(type);
+ return new_d_Sub(dbgi, left, right, mode);
+ }
+
+ assert(type_left->type == TYPE_POINTER);
+ return pointer_arithmetic(left, right, type_left, dbgi, new_d_Sub);
+}
+
+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;
+
+ switch (expression->type) {
+ case BINEXPR_DIV:
+ case BINEXPR_DIV_ASSIGN:
+ 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);
+ }
+ break;
+
+ case BINEXPR_MOD:
+ case BINEXPR_MOD_ASSIGN:
+ 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);
+ break;
+
+ default: panic("unexpected binary expression type in create_divmod()");
+ }
+
+ return res;
+}
+
+static ir_node *create_arithmetic_assign_divmod(
+ const binary_expression_t *expression)
+{
+ ir_node * value = create_divmod(expression);
+ dbg_info *const dbgi = get_dbg_info(&expression->expression.source_position);
+ type_t *const type = expression->expression.datatype;
+ ir_mode *const 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 *binary_expression_to_firm(const binary_expression_t *expression)
+{