+static ir_node *create_cast(dbg_info *dbgi, ir_node *value_node,
+ type_t *from_type, type_t *type)
+{
+ type = skip_typeref(type);
+ if (!is_type_scalar(type)) {
+ /* make sure firm type is constructed */
+ (void) get_ir_type(type);
+ return value_node;
+ }
+
+ from_type = skip_typeref(from_type);
+ ir_mode *mode = get_ir_mode_storage(type);
+ /* check for conversion from / to __based types */
+ if (is_type_pointer(type) && is_type_pointer(from_type)) {
+ const variable_t *from_var = from_type->pointer.base_variable;
+ const variable_t *to_var = type->pointer.base_variable;
+ if (from_var != to_var) {
+ if (from_var != NULL) {
+ ir_node *const addr = get_global_var_address(dbgi, from_var);
+ ir_node *const base = deref_address(dbgi, from_var->base.type, addr);
+ value_node = new_d_Add(dbgi, value_node, base, get_ir_mode_storage(from_type));
+ }
+ if (to_var != NULL) {
+ ir_node *const addr = get_global_var_address(dbgi, to_var);
+ ir_node *const base = deref_address(dbgi, to_var->base.type, addr);
+ value_node = new_d_Sub(dbgi, value_node, base, mode);
+ }
+ }
+ }
+
+ if (is_type_atomic(type, ATOMIC_TYPE_BOOL)) {
+ /* bool adjustments (we save a mode_Bu, but have to temporarily
+ * convert to mode_b so we only get a 0/1 value */
+ value_node = create_conv(dbgi, value_node, mode_b);
+ }
+
+ ir_mode *mode_arith = get_ir_mode_arithmetic(type);
+ ir_node *node = create_conv(dbgi, value_node, mode);
+ node = do_strict_conv(dbgi, node);
+ node = create_conv(dbgi, node, mode_arith);
+
+ return node;
+}
+