memory: allow aggregate accesses to have bits_byte > 8
MODIFY
ir/memory.cpp
ir/memory.cpp
@@ -1364,7 +1364,6 @@ void Memory::store(const expr &p, const StateValue &v, const Type &type,
assert(!memory_unused());
Pointer ptr(*this, p);
unsigned bytesz = bits_byte / 8;
- assert(align % bytesz == 0);
if (deref_check)
ptr.is_dereferenceable(getStoreByteSize(type), align,
@@ -1377,7 +1376,8 @@ void Memory::store(const expr &p, const StateValue &v, const Type &type,
if (child.bits() == 0)
continue;
auto ptr_i = ptr + byteofs;
- store(ptr_i(), aty->extract(v, i), child, 1, false);
+ auto align_i = gcd(align, byteofs % align);
+ store(ptr_i(), aty->extract(v, i), child, align_i, false);
byteofs += getStoreByteSize(child);
}
assert(byteofs == getStoreByteSize(type));
@@ -1385,6 +1385,7 @@ void Memory::store(const expr &p, const StateValue &v, const Type &type,
} else {
vector<Byte> bytes = valueToBytes(v, type, *this, state);
assert(!v.isValid() || bytes.size() * bytesz == getStoreByteSize(type));
+ assert(align % bytesz == 0);
for (unsigned i = 0, e = bytes.size(); i < e; ++i) {
auto ptr_i = ptr + (little_endian ? i * bytesz :
@@ -1398,7 +1399,6 @@ StateValue Memory::load(const expr &p, const Type &type, unsigned align,
bool deref_check) {
assert(!memory_unused());
unsigned bytesz = bits_byte / 8;
- assert(align % bytesz == 0);
unsigned bytecount = getStoreByteSize(type);
Pointer ptr(*this, p);
@@ -1411,13 +1411,15 @@ StateValue Memory::load(const expr &p, const Type &type, unsigned align,
unsigned byteofs = 0;
for (unsigned i = 0, e = aty->numElementsConst(); i < e; ++i) {
auto ptr_i = ptr + byteofs;
- member_vals.push_back(load(ptr_i(), aty->getChild(i), 1, false));
+ auto align_i = gcd(align, byteofs % align);
+ member_vals.push_back(load(ptr_i(), aty->getChild(i), align_i, false));
byteofs += getStoreByteSize(aty->getChild(i));
}
assert(byteofs == bytecount);
ret = aty->aggregateVals(member_vals);
} else {
+ assert(align % bytesz == 0);
vector<Byte> loadedBytes;
bytecount /= bytesz;
for (unsigned i = 0; i < bytecount; ++i) {

MODIFY
tools/transform.cpp
tools/transform.cpp
@@ -547,35 +547,27 @@ static bool has_sub_byte(const Type &t) {
return false;
}
-static void calculateAndInitConstants(Transform &t) {
- const auto &globals_tgt = t.tgt.getGlobalVars();
- const auto &globals_src = t.src.getGlobalVars();
- unsigned num_globals = globals_src.size();
-
- // TODO: get this from data layout, varies among address spaces
- bits_program_pointer = 64;
-
- for (auto GVT : globals_tgt) {
- auto I = find_if(globals_src.begin(), globals_src.end(),
- [GVT](auto *GV) -> bool { return GVT->getName() == GV->getName(); });
- if (I == globals_src.end())
- ++num_globals;
+static uint64_t get_access_size(const Type &ty) {
+ if (auto agg = ty.getAsAggregateType()) {
+ uint64_t sz = 1;
+ for (unsigned i = 0, e = agg->numElementsConst(); i != e; ++i) {
+ auto n = get_access_size(agg->getChild(i));
+ sz = i == 0 ? n : gcd(sz, n);
}
-
- unsigned num_ptrinputs = 0;
- for (auto &arg : t.src.getInputs()) {
- num_ptrinputs += num_ptrs(arg.getType());
+ return sz;
+ }
+ if (ty.isPtrType())
+ return bits_program_pointer / 8;
+ return divide_up(ty.bits(), 8);
}
- // Returns access size. 0 if no access, -1 if unknown
- const uint64_t UNKNOWN = 1, NO_ACCESS = 0;
- auto get_access_size = [&](const Instr &inst) -> uint64_t {
+static uint64_t get_access_size(const Instr &inst) {
if (dynamic_cast<const Calloc*>(&inst) ||
dynamic_cast<const Memcpy*>(&inst) ||
dynamic_cast<const Memset*>(&inst)) {
// TODO
does_int_mem_access = true;
- return UNKNOWN;
+ return 1;
}
Type *value_ty;
@@ -587,20 +579,35 @@ static void calculateAndInitConstants(Transform &t) {
} else if (auto ld = dynamic_cast<const Load*>(&inst)) {
value_ty = &ld->getType();
align = ld->getAlign();
- } else
- return NO_ACCESS;
+ }
+ else
+ return 0;
does_ptr_mem_access |= hasPtr(*value_ty);
does_int_mem_access |= value_ty->enforcePtrOrVectorType().isFalse();
- if (value_ty->isAggregateType())
- // TODO: AggregateType's elements are splitted and stored, so
- // should they be checked instead
- return UNKNOWN;
- if (value_ty->isPtrType())
- return gcd(align, bits_size_t / 8);
- return gcd(align, util::divide_up(value_ty->bits(), 8));
- };
+ return gcd(align, get_access_size(*value_ty));
+}
+
+static void calculateAndInitConstants(Transform &t) {
+ const auto &globals_tgt = t.tgt.getGlobalVars();
+ const auto &globals_src = t.src.getGlobalVars();
+ unsigned num_globals = globals_src.size();
+
+ // TODO: get this from data layout, varies among address spaces
+ bits_program_pointer = 64;
+
+ for (auto GVT : globals_tgt) {
+ auto I = find_if(globals_src.begin(), globals_src.end(),
+ [GVT](auto *GV) -> bool { return GVT->getName() == GV->getName(); });
+ if (I == globals_src.end())
+ ++num_globals;
+ }
+
+ unsigned num_ptrinputs = 0;
+ for (auto &arg : t.src.getInputs()) {
+ num_ptrinputs += num_ptrs(arg.getType());
+ }
// The number of instructions that can return a pointer to a non-local block.
num_max_nonlocals_inst = 0;
@@ -682,8 +689,7 @@ static void calculateAndInitConstants(Transform &t) {
does_sub_byte_access |= has_sub_byte(I.getType());
- auto accsz = get_access_size(I);
- if (accsz != NO_ACCESS) {
+ if (auto accsz = get_access_size(I)) {
min_access_size = gcd(min_access_size, accsz);
does_mem_access = true;
}

memory: allow aggregate accesses to have bits_byte > 8