consider fncall param aligns when calculating access size
MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -1565,19 +1565,36 @@ uint64_t FnCall::getMaxAccessSize() const {
}
FnCall::ByteAccessInfo FnCall::getByteAccessInfo() const {
- bool has_deref = getAttributes().has(FnAttrs::Dereferenceable);
- if (!has_deref) {
- for (auto &arg : args)
+ auto &retattr = getAttributes();
+ bool has_deref = retattr.has(FnAttrs::Dereferenceable);
+ uint64_t bytesize = has_deref ? gcd(retattr.derefBytes, retattr.align) : 0;
+
+ for (auto &arg : args) {
+ if (!arg.first->getType().isPtrType())
+ continue;
+
if (arg.second.has(ParamAttrs::Dereferenceable)) {
has_deref = true;
- break;
- }
+ // Without align, nothing is guaranteed about the bytesize
+ uint64_t b = gcd(arg.second.derefBytes, arg.second.align);
+ bytesize = bytesize ? gcd(bytesize, b) : b;
+ }
+ // Pointer arguments without dereferenceable attr don't contribute to the
+ // byte size.
+ // call f(* dereferenceable(n) align m %p, * %q) is equivalent to a dummy
+ // load followed by a function call:
+ // load i<8*n> %p, align m
+ // call f(* %p, * %q)
+ // f(%p, %q) does not contribute to the bytesize. After bytesize is fixed,
+ // function calls update a memory with the granularity.
}
- if (!has_deref)
+ if (!has_deref) {
// No dereferenceable attribute
+ assert(bytesize == 0);
return {};
- // dereferenceable(n) does not guarantee that the pointer is n-byte aligned
- return ByteAccessInfo::anyType(1);
+ }
+
+ return ByteAccessInfo::anyType(bytesize);
}

ADD
tests/alive-tv/opt-memory/deref-align-callee.srctgt.ll
+; TEST-ARGS: -dbg
+
+declare void @f(i32*)
+
+define void @src(i32* dereferenceable(4) align 4 %p) {
+ call void @f(i32* dereferenceable(4) %p)
+ ret void
+}
+
+define void @tgt(i32* dereferenceable(4) align 4 %p) {
+ call void @f(i32* dereferenceable(4) %p)
+ ret void
+}
+
+
+; CHECK: min_access_size: 1

ADD
tests/alive-tv/opt-memory/deref-align-callee2.srctgt.ll
+; TEST-ARGS: -dbg
+
+declare dereferenceable(8) align 4 i32* @f()
+
+define void @src() {
+ %r = call i32* @f()
+ store i32 0, i32* %r, align 4
+ ret void
+}
+
+define void @tgt() {
+ %r = call i32* @f()
+ store i32 0, i32* %r, align 4
+ ret void
+}
+
+; CHECK: min_access_size: 4

consider fncall param aligns when calculating access size (#596)