memory: improve handling of alignment so it doesnt deoptimize byte size unnecessarily
MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -1690,14 +1690,13 @@ static void unpack_inputs(State &s, Value &argv, Type &ty,
Pointer p(s.getMemory(), move(value.value));
p.stripAttrs();
if (argflag.has(ParamAttrs::Dereferenceable))
- s.addUB(p.isDereferenceable(argflag.derefBytes, bits_byte / 8, false));
+ s.addUB(p.isDereferenceable(argflag.derefBytes, argflag.align, false));
+ else if (argflag.has(ParamAttrs::Align))
+ s.addUB(p.isAligned(argflag.align));
if (argflag.has(ParamAttrs::NonNull))
s.addUB(!p.isNull());
- if (argflag.has(ParamAttrs::Align))
- s.addUB(p.isAligned(argflag.align));
-
ptr_inputs.emplace_back(StateValue(p.release(), move(value.non_poison)),
argflag.has(ParamAttrs::ByVal),
argflag.has(ParamAttrs::NoCapture));
@@ -1748,11 +1747,11 @@ pack_return(State &s, Type &ty, vector<StateValue> &vals, const FnAttrs &attrs,
Pointer p(s.getMemory(), ret.value);
s.addUB(ret.non_poison);
if (isDeref)
- s.addUB(p.isDereferenceable(attrs.derefBytes));
+ s.addUB(p.isDereferenceable(attrs.derefBytes, attrs.align));
+ else if (isAlign)
+ s.addUB(p.isAligned(attrs.align));
if (isNonNull)
s.addUB(!p.isNull());
- if (isAlign)
- s.addUB(p.isAligned(attrs.align));
}
return ret;
@@ -2412,16 +2411,15 @@ StateValue Return::toSMT(State &s) const {
Pointer p(s.getMemory(), retval.value);
if (isDeref) {
- s.addUB(p.isDereferenceable(attrs.derefBytes));
+ s.addUB(p.isDereferenceable(attrs.derefBytes, attrs.align));
if (has_alloca)
s.addUB(p.getAllocType() != Pointer::STACK);
+ } else if (isAlign) {
+ s.addUB(p.isAligned(attrs.align));
}
if (isNonNull) {
s.addUB(!p.isNull());
}
- if (isAlign) {
- s.addUB(p.isAligned(attrs.align));
- }
}
if (attrs.has(FnAttrs::NoReturn))

MODIFY
ir/memory.cpp
ir/memory.cpp
@@ -641,7 +641,6 @@ expr Pointer::blockAlignment() const {
}
expr Pointer::isBlockAligned(unsigned align, bool exact) const {
- assert(align >= bits_byte / 8);
if (!exact && align == 1)
return true;
@@ -651,7 +650,6 @@ expr Pointer::isBlockAligned(unsigned align, bool exact) const {
}
expr Pointer::isAligned(unsigned align) {
- assert(align >= bits_byte / 8);
if (align == 1)
return true;

MODIFY
ir/memory.h
ir/memory.h
@@ -159,7 +159,7 @@ public:
smt::expr blockAlignment() const; // log(bits)
smt::expr isBlockAligned(unsigned align, bool exact = false) const;
smt::expr isAligned(unsigned align);
- smt::AndExpr isDereferenceable(uint64_t bytes, unsigned align = bits_byte / 8,
+ smt::AndExpr isDereferenceable(uint64_t bytes, unsigned align,
bool iswrite = false);
smt::AndExpr isDereferenceable(const smt::expr &bytes, unsigned align,
bool iswrite);

MODIFY
ir/value.cpp
ir/value.cpp
@@ -221,12 +221,11 @@ StateValue Input::mkInput(State &s, const Type &ty, unsigned child) const {
if (hasAttribute(ParamAttrs::NonNull))
s.addUB(!Pointer(s.getMemory(), val).isNull());
- if (hasAttribute(ParamAttrs::Align))
- s.addUB(Pointer(s.getMemory(), val).isAligned(attrs.align));
-
if (hasAttribute(ParamAttrs::Dereferenceable))
s.addUB(Pointer(s.getMemory(), val)
- .isDereferenceable(attrs.derefBytes, bits_byte/8, false));
+ .isDereferenceable(attrs.derefBytes, attrs.align, false));
+ else if (hasAttribute(ParamAttrs::Align))
+ s.addUB(Pointer(s.getMemory(), val).isAligned(attrs.align));
bool never_poison = config::disable_poison_input || attrs.poisonImpliesUB();
string np_name = "np_" + getSMTName(child);

ADD
tests/alive-tv/memory/align2.srctgt.ll
+; ERROR: Value mismatch
+
+define i32 @src(i32* align(4) %p) {
+ call void @g(i32* align(2) %p)
+ %v = load i32, i32* %p, align 4
+ ret i32 %v
+}
+
+define i32 @tgt(i32* align(4) %p) {
+ call void @g(i32* align(2) %p)
+ %v = load i32, i32* %p, align 4
+ ret i32 0
+}
+
+declare void @g(i32*)

ADD
tests/alive-tv/memory/align3.srctgt.ll
+; ERROR: Value mismatch
+
+define i16 @src(i16* align(4) %p) {
+ %a = load i16, i16* %p, align 1
+ %p2 = getelementptr i16, i16* %p, i32 1
+ %b = load i16, i16* %p2, align 1
+ %x = xor i16 %a, %b
+ ret i16 %x
+}
+
+define i16 @tgt(i16* align(4) %p) {
+ ret i16 0
+}

MODIFY
tests/alive-tv/opt-memory/dereferenceable.srctgt.ll
tests/alive-tv/opt-memory/dereferenceable.srctgt.ll
@@ -10,4 +10,4 @@ define i32 @tgt(i32* dereferenceable(2) align 4 %p) {
ret i32 %v1
}
-; CHECK: min_access_size: 2
+; CHECK: min_access_size: 4

MODIFY
tools/transform.cpp
tools/transform.cpp
@@ -694,11 +694,9 @@ static void calculateAndInitConstants(Transform &t) {
if (!i)
continue;
- uint64_t align = i->getAttributes().align;
if (i->hasAttribute(ParamAttrs::Dereferenceable)) {
does_mem_access = true;
uint64_t deref_bytes = i->getAttributes().derefBytes;
- min_access_size = gcd(min_access_size, gcd(deref_bytes, align));
max_access_size = max(max_access_size, deref_bytes);
}
if (i->hasAttribute(ParamAttrs::ByVal)) {
@@ -708,14 +706,9 @@ static void calculateAndInitConstants(Transform &t) {
min_global_size = min_global_size != UINT64_MAX
? gcd(sz, min_global_size)
: sz;
- min_global_size = gcd(min_global_size, align);
}
}
- if (fn->getFnAttrs().has(FnAttrs::Align)) {
- min_access_size = gcd(min_access_size, fn->getFnAttrs().align);
- }
-
auto update_min_vect_sz = [&](const Type &ty) {
auto elemsz = minVectorElemSize(ty);
if (min_vect_elem_sz && elemsz)
@@ -795,7 +788,6 @@ static void calculateAndInitConstants(Transform &t) {
min_global_size = min_global_size != UINT64_MAX
? gcd(sz, min_global_size)
: sz;
- min_global_size = gcd(min_global_size, glb->getAlignment());
}
}

memory: improve handling of alignment so it doesnt deoptimize byte size unnecessarily