-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Description
While working on improving the norecurse attribute inference in #139943, we came across a couple of cases of incorrect inference in PO and RPO FunctionAttr pass.
As per my understanding, both of these cases are not possible to reach through compiler analysis/transformations unless forced using
-mllvm -force-attribute=<fname>:norecurse
define dso_local void @norecurse_fn() norecurse {
entry:
tail call fastcc void @a(i32 0)
ret void
}
define internal fastcc void @a(i32 range(i32 0, 2) %c) {
entry:
%tobool.not = icmp eq i32 %c, 0
br i1 %tobool.not, label %if.end, label %if.then
if.then: ; preds = %entry
tail call void @calls_norecurse()
br label %if.end
if.end: ; preds = %if.then, %entry
ret void
}
define dso_local noundef i32 @main() norecurse {
entry:
tail call fastcc void @foo()
ret i32 1
}
define internal fastcc void @foo() {
entry:
tail call void @norecurse_fn()
tail call fastcc void @a(i32 1)
ret void
}
declare void @calls_norecurse()
ReversePostOrderPass
adds the norecurse attribute to function a, even when there is a possible recursion as a -> calls_norecurse (external function without definition) -> norecurse_fn -> a
This issue occurs because RPO norecurse
attribute inference solely work based on the fact that all callers of function being examined are marked norecurse
, which happens to be true when walking in top-down manner.
In this case, the norecurse
attribute on norecurse_fn is not correct as it is not an internal function and can be called from external function which may introduce some indirect recursion.
define void @a(i32 %c) {
%tobool.not = icmp ne i32 %c, 0
br i1 %tobool.not, label %if.then, label %if.end
if.then:
call void @calls_b()
br label %if.end
if.end:
ret void
}
declare void @calls_b() norecurse
;define void @b() norecurse {
; call void @a(i32 0)
; ret void
;}
In this case, PostOrderFunctionAttrsPass
infers norecurse
on a which is incorrect. It relies on the fact that if all callees are norecurse
, the caller is also norecurse
.
Here as well, the norecurse attribute on calls_b is incorrect as its definition is not known.
CC: @nikic @david-arm