/* Helper to fill in the range (src_min, src_max, dest_min, dest_max) * based on message parameters and known connection and signal * properties; return flags to indicate which parts of the range were * found. */ static int set_range(mapper_connection c, mapper_message_t *msg) { lo_arg **args = NULL; const char *types = NULL; int i, length = 0, updated = 0, result; if (!c) return 0; /* The logic here is to first try to use information from the * message, starting with @srcMax, @srcMin, @destMax, @destMin, * and then @min and @max. * Next priority is already-known properties of the connection. * Lastly, we fill in source range from the signal. */ /* @srcMax */ args = mapper_msg_get_param(msg, AT_SRC_MAX); types = mapper_msg_get_type(msg, AT_SRC_MAX); length = mapper_msg_get_length(msg, AT_SRC_MAX); if (args && types && is_number_type(types[0])) { if (length == c->props.src_length) { if (!c->props.src_max) c->props.src_max = calloc(1, length * c->props.src_type); c->props.range_known |= CONNECTION_RANGE_SRC_MAX; for (i=0; i<length; i++) { result = propval_set_from_lo_arg(c->props.src_max, c->props.src_type, args[i], types[i], i); if (result == -1) { c->props.range_known &= ~CONNECTION_RANGE_SRC_MAX; break; } else updated += result; } } else c->props.range_known &= ~CONNECTION_RANGE_SRC_MAX; } /* @srcMin */ args = mapper_msg_get_param(msg, AT_SRC_MIN); types = mapper_msg_get_type(msg, AT_SRC_MIN); length = mapper_msg_get_length(msg, AT_SRC_MIN); if (args && types && is_number_type(types[0])) { if (length == c->props.src_length) { if (!c->props.src_min) c->props.src_min = calloc(1, length * c->props.src_type); c->props.range_known |= CONNECTION_RANGE_SRC_MIN; for (i=0; i<length; i++) { result = propval_set_from_lo_arg(c->props.src_min, c->props.src_type, args[i], types[i], i); if (result == -1) { c->props.range_known &= ~CONNECTION_RANGE_SRC_MIN; break; } else updated += result; } } else c->props.range_known &= ~CONNECTION_RANGE_SRC_MIN; } /* @destMax */ args = mapper_msg_get_param(msg, AT_DEST_MAX); types = mapper_msg_get_type(msg, AT_DEST_MAX); length = mapper_msg_get_length(msg, AT_DEST_MAX); if (args && types && is_number_type(types[0])) { if (length == c->props.dest_length) { if (!c->props.dest_max) c->props.dest_max = calloc(1, length * c->props.dest_type); c->props.range_known |= CONNECTION_RANGE_DEST_MAX; for (i=0; i<length; i++) { result = propval_set_from_lo_arg(c->props.dest_max, c->props.dest_type, args[i], types[i], i); if (result == -1) { c->props.range_known &= ~CONNECTION_RANGE_DEST_MAX; break; } else updated += result; } } else c->props.range_known &= ~CONNECTION_RANGE_DEST_MAX; } /* @destMin */ args = mapper_msg_get_param(msg, AT_DEST_MIN); types = mapper_msg_get_type(msg, AT_DEST_MIN); length = mapper_msg_get_length(msg, AT_DEST_MIN); if (args && types && is_number_type(types[0])) { if (length == c->props.dest_length) { if (!c->props.dest_min) c->props.dest_min = calloc(1, length * c->props.dest_type); c->props.range_known |= CONNECTION_RANGE_DEST_MIN; for (i=0; i<length; i++) { result = propval_set_from_lo_arg(c->props.dest_min, c->props.dest_type, args[i], types[i], i); if (result == -1) { c->props.range_known &= ~CONNECTION_RANGE_DEST_MIN; break; } else updated += result; } } else c->props.range_known &= ~CONNECTION_RANGE_DEST_MIN; } /* @min, @max */ if (!(c->props.range_known & CONNECTION_RANGE_DEST_MIN)) { args = mapper_msg_get_param(msg, AT_MIN); types = mapper_msg_get_type(msg, AT_MIN); length = mapper_msg_get_length(msg, AT_MIN); if (args && types && is_number_type(types[0])) { if (length == c->props.dest_length) { if (!c->props.dest_min) c->props.dest_min = calloc(1, length * c->props.dest_type); c->props.range_known |= CONNECTION_RANGE_DEST_MIN; for (i=0; i<length; i++) { result = propval_set_from_lo_arg(c->props.dest_min, c->props.dest_type, args[i], types[i], i); if (result == -1) { c->props.range_known &= ~CONNECTION_RANGE_DEST_MIN; break; } else updated += result; } } else c->props.range_known &= ~CONNECTION_RANGE_DEST_MIN; } } if (!(c->props.range_known & CONNECTION_RANGE_DEST_MAX)) { args = mapper_msg_get_param(msg, AT_MAX); types = mapper_msg_get_type(msg, AT_MAX); length = mapper_msg_get_length(msg, AT_MAX); if (args && types && is_number_type(types[0])) { if (length == c->props.dest_length) { if (!c->props.dest_max) c->props.dest_max = calloc(1, length * c->props.dest_type); c->props.range_known |= CONNECTION_RANGE_DEST_MAX; for (i=0; i<length; i++) { result = propval_set_from_lo_arg(c->props.dest_max, c->props.dest_type, args[i], types[i], i); if (result == -1) { c->props.range_known &= ~CONNECTION_RANGE_DEST_MAX; break; } else updated += result; } } else c->props.range_known &= ~CONNECTION_RANGE_DEST_MAX; } } /* Signal */ mapper_signal sig = c->parent->signal; /* If parent signal is an output it must be the "source" of this connection, * if it is an input it must be the "destination". According to the protocol * for negotiating new connections, we will only fill-in ranges for the * "source" signal.*/ if (!sig || !sig->props.is_output) return updated; if (!c->props.src_min && sig->props.minimum) { c->props.src_min = malloc(msig_vector_bytes(sig)); memcpy(c->props.src_min, sig->props.minimum, msig_vector_bytes(sig)); c->props.range_known |= CONNECTION_RANGE_SRC_MIN; updated++; } if (!c->props.src_max && sig->props.maximum) { c->props.src_max = malloc(msig_vector_bytes(sig)); memcpy(c->props.src_max, sig->props.maximum, msig_vector_bytes(sig)); c->props.range_known |= CONNECTION_RANGE_SRC_MAX; updated++; } return updated; }
smt_astt smt_convt::convert_byte_update(const expr2tc &expr) { const byte_update2t &data = to_byte_update2t(expr); assert(is_scalar_type(data.source_value) && "Byte update only works on " "scalar variables now"); if (!is_constant_int2t(data.source_offset)) { expr2tc source = data.source_value; unsigned int src_width = source->type->get_width(); if (!is_bv_type(source)) source = typecast2tc(get_uint_type(src_width), source); expr2tc offs = data.source_offset; // Endian-ness: if we're in non-"native" endian-ness mode, then flip the // offset distance. The rest of these calculations will still apply. if (data.big_endian) { auto data_size = type_byte_size(*source->type); constant_int2tc data_size_expr(source->type, data_size - 1); sub2tc sub(source->type, data_size_expr, offs); offs = sub; } if (offs->type->get_width() != src_width) offs = typecast2tc(get_uint_type(src_width), offs); expr2tc update = data.update_value; if (update->type->get_width() != src_width) update = typecast2tc(get_uint_type(src_width), update); // The approach: mask, shift and or. XXX, byte order? // Massively inefficient. expr2tc eight = constant_int2tc(get_uint_type(src_width), BigInt(8)); expr2tc effs = constant_int2tc(eight->type, BigInt(255)); offs = mul2tc(eight->type, offs, eight); expr2tc shl = shl2tc(offs->type, effs, offs); expr2tc noteffs = bitnot2tc(effs->type, shl); source = bitand2tc(source->type, source, noteffs); expr2tc shl2 = shl2tc(offs->type, update, offs); return convert_ast(bitor2tc(offs->type, shl2, source)); } // We are merging two values: an 8 bit update value, and a larger source // value that we will have to merge it into. Start off by collecting // information about the source values and their widths. assert(is_number_type(data.source_value->type) && "Byte update of unsupported data type"); smt_astt value, src_value; unsigned int width_op0, width_op2, src_offset; value = convert_ast(data.update_value); src_value = convert_ast(data.source_value); width_op2 = data.update_value->type->get_width(); width_op0 = data.source_value->type->get_width(); src_offset = to_constant_int2t(data.source_offset).constant_value.to_ulong(); // Flip location if we're in big-endian mode if (data.big_endian) { unsigned int data_size = type_byte_size(*data.source_value->type).to_ulong() - 1; src_offset = data_size - src_offset; } if (int_encoding) { std::cerr << "Can't byte update in integer mode; rerun in bitvector mode" << std::endl; abort(); } // Assertion some of our assumptions, which broadly mean that we'll only work // on bytes that are going into non-byte words assert(width_op2 == 8 && "Can't byte update non-byte operations"); assert(width_op2 != width_op0 && "Can't byte update bytes, sorry"); smt_astt top, middle, bottom; // Build in three parts: the most significant bits, any in the middle, and // the bottom, of the reconstructed / merged output. There might not be a // middle if the update byte is at the top or the bottom. unsigned int top_of_update = (8 * src_offset) + 8; unsigned int bottom_of_update = (8 * src_offset); if (top_of_update == width_op0) { top = value; } else { smt_sortt s = mk_sort(SMT_SORT_BV, width_op0 - top_of_update, false); top = mk_extract(src_value, width_op0 - 1, top_of_update, s); } if (top == value) { middle = NULL; } else { middle = value; } if (src_offset == 0) { middle = NULL; bottom = value; } else { smt_sortt s = mk_sort(SMT_SORT_BV, bottom_of_update, false); bottom = mk_extract(src_value, bottom_of_update - 1, 0, s); } // Concatenate the top and bottom, and possible middle, together. smt_astt concat; if (middle != NULL) { smt_sortt s = mk_sort(SMT_SORT_BV, width_op0 - bottom_of_update, false); concat = mk_func_app(s, SMT_FUNC_CONCAT, top, middle); } else { concat = top; } return mk_func_app(src_value->sort, SMT_FUNC_CONCAT, concat, bottom); }