To represent branch probabilities we use branch_weight metadata which can be attached to branch, select or switch instruction. It can also be attached to call instruction, but in this case it would mean the invocation counter. Currently we don't have a way to express the branch probability information for invoke instructions, i.e. probabilty of the normal return edge vs unwind edge.
It looks like we only use a hard-coded heuristic that invokes unwind rarely (1024 * 1024 - 1 vs 1). In managed environment we can have a profile for normal and unwind returns and might benefit from this information being expressed in the IR.
However, I'm uncertaion what would be the best way to go about it. Allowing branch_weights on invoke instructions seems natural, but then it clashes with the existing branch_weights on calls which have a different meaning.
The existing branch_weights on calls is somewhat confusing, maybe we should introduce a separate metadata type for counters and use branch_weights only for relative weights as the name suggestes.
Artur and I discussed this offline, but I want to share my thoughts with the mailing list as well.
The current use of “branch_weights” on calls to indicate the invocation count has always felt ugly to me. It’s seemingly inconsistent with our other uses of branch_weight, and we also have an alternate way of spelling* the same thing with VP prof data.
My suggestion was to do one of the following:
Introduce a new “invocation_count” profile metadata type. Upgrade old single argument “branch_weight” on call to the new form. Support the new form on both calls and invokes. Introduce a new two argument “branch_weights” with the desired semantics.
Simply upgrade all one argument branch_weight metadata on calls to two argument forms and count the invoke count as normal return. This is the simplest, but possibly problematic since we have no idea what the throw frequency of such a call was and it might have been non-trivial.
Keep the single argument form of branch_weights, and treat it as if the second argument was 0. (i.e. the call never threw)
I’d prefer (1) as I see an interesting semantic difference between a call which is known to execute N times, and a call which is known to return normally with a given frequency. (2) and (3) gives us no way to represent that difference.
- That spelling is a type-0 profile for an indirect call with the two predictions having random hashes with count 0. As an aside, the fact that our value profiling support can only support profiles of width 2 (according to the docs) is restrictive and weird.