phi instruction semantics in llvm-IR - llvm

Trying to understand phi instruction semantics in llvm-IR
(https://llvm.org/docs/LangRef.html#phi-instruction)
Let's consider the following example:
; Function Attrs: norecurse nounwind
define i32 #main( i32 %argc, i8** %argv) {
entry:
switch i32 %argc, label %L1 [ i32 0, label %L0
i32 1, label %L1 ]
L0:
%x = add i32 %argc, 1
br label %L1
L1:
%y = phi i32 [ %argc, %entry ], [ %x, %L0 ]
%z = sub i32 %y, 1
%w = udiv i32 100, %z
ret i32 %w
}
Compilation with clang-7.0.1
$ clang-7.0.1 -O0 test.ll -o a.out
PHINode should have one entry for each predecessor of its parent basic
block!
%y = phi i32 [ %argc, %entry ], [ %x, %L0 ]
fatal error: error in backend: Broken function found, compilation
aborted!
When I replaced "%y = phi ..." by "%y = add i32 2, 1" the test was compiled successfully.
The question here is about error message:
why not all predecessors are listed in phi in the test? From description of phi instruction in LangRef.html#phi-instruction I can't
understand it.

When there are multiple edges from block A to block B, then the PHI nodes in B must list A as many times as there are edges, each time with the same value. In your case there are two edges from entry to L1 (one for the default case of the switch and one for the 1 case), so entry needs to be listed twice in the PHI node.
But perhaps the cleaner solution in this case would be to just remove the [i32 1, label %L1] case from your switch as that's redundant anyway. Then there'd only be one edge and you'd only need one entry for entry.

Related

LLVM IR position of predecessor block labels in phi node instruction

When using a phi node in a basic block is there a suggested order in which I should place the labels if there is a higher probability that the predecessor is a certain block. For example take the simple factorial function listed below.
define private i64 #fact(i64 %start) {
entry:
%0 = icmp sle i64 1, %start
br i1 %0, label %loop, label %endcond
loop: ; preds = %loop, %entry
%1 = phi i64 [ %res, %loop ], [ 1, %entry ] ; if %start > 2 predecessor
%2 = phi i64 [ %3, %loop ], [ %start, %entry ] ; is likely %loop
%res = mul i64 %1, %2
%3 = sub i64 %2, 1
%cond = icmp sle i64 1, %3
br i1 %cond, label %loop, label %endcond
endcond: ; preds = %loop, %entry
%fin = phi i64 [ %res, %loop ], [ 1, %entry ] ; highly unlikely
ret i64 %fin ; predecessor is %entry
}
While it is possible that the user will input #fact(1) it is unlikely, so I expect in most cases the predecessor block for the phi node in endcond to be post.loop. So is my assumption that in this case
%fin = phi i64 [ %res, %post.loop ], [ 1, %entry ]
is better than
%fin = phi i64 [ 1, %entry ], [ %res, %post.loop ]
correct? And if so, why or why not?
Doesn't make a difference. LLVM will do an analysis on your code to estimate the branch probabilities, and it uses that to order the resulting block.
You can influence this by using branch weight metadata: http://llvm.org/docs/BlockFrequencyTerminology.html

What exactly is the LLVM C++ API

I found it hard to understand the LLVM C++ API.
Is there any relationship between LLVM C++ API and LLVM IR? Also, how could one use the LLVM C++ API?
To (greatly) simplify, LLVM is a C++ library for writing compilers. Its C++ API is the external interface users of the library employ to implement their compiler.
There's a degree of symmetry between LLVM IR and part of the LLVM C++ API - the part used to build IR. A very good resource for getting a feel for this symmetry is http://llvm.org/demo/. For example, you can compile this C code:
int factorial(int X) {
if (X == 0) return 1;
return X*factorial(X-1);
}
Into LLVM IR:
define i32 #factorial(i32 %X) nounwind uwtable readnone {
%1 = icmp eq i32 %X, 0
br i1 %1, label %tailrecurse._crit_edge, label %tailrecurse
tailrecurse: ; preds = %tailrecurse, %0
%X.tr2 = phi i32 [ %2, %tailrecurse ], [ %X, %0 ]
%accumulator.tr1 = phi i32 [ %3, %tailrecurse ], [ 1, %0 ]
%2 = add nsw i32 %X.tr2, -1
%3 = mul nsw i32 %X.tr2, %accumulator.tr1
%4 = icmp eq i32 %2, 0
br i1 %4, label %tailrecurse._crit_edge, label %tailrecurse
tailrecurse._crit_edge: ; preds = %tailrecurse, %0
%accumulator.tr.lcssa = phi i32 [ 1, %0 ], [ %3, %tailrecurse ]
ret i32 %accumulator.tr.lcssa
}
As well as to C++ API calls (I won't paste it here because the output is long, but you can try it yourself). Doing this, you'll see, for example the icmp instruction from the IR code above done as:
ICmpInst* int1_5 = new ICmpInst(*label_4, ICmpInst::ICMP_EQ, int32_X, const_int32_1, "");
ICmpInst is a class that's part of the C++ API used to create icmp instructions. A good reference for the C++ API is the Programmer's manual.
You can use the CPP backend (llc -march=cpp) to find out the mapping from any given IR to the C++ API.
UPDATE: the cpp backend is no longer available.

Find values in a basicblock,which are computed in previous basicblocks

In a basicblock I wants to find all the values used in instructions, That are not computed in the same basicblock.
Example,
for.body5:
%i.015 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.body ]
%add1 = add nsw i32 %2, %i.015
%arrayidx = getelementptr inbounds [100 x i32]* %b, i32 0, i32 %i.015
store i32 %add1, i32* %arrayidx, align 4, !tbaa !0
%arrayidx2 = getelementptr inbounds [100 x i32]* %a, i32 0, i32 %i.015
store i32 %add1, i32* %arrayidx2, align 4, !tbaa !0
%inc = add nsw i32 %i.015, 1
%cmp = icmp slt i32 %inc, %3
br i1 %cmp, label %for.body, label %for.cond3.preheader
In above example i should get,
%2
%b
%a
%3
Which are declared and/or assigned in other basicblocks.
Please Suggest me a method.
Thanks in advance.
Hi I havent tested this out, but I would do something like this:
vector<Value*> values;
BasicBlock::iterator it;
User::op_iterator it;
// Iterate over all of the instructions in the Block
for (it=block->begin(); it++; it != block->end()){
// Iterate over the operands used by an instruction. 'op_begin' Defined in llvm::User class.
for (operand_it=it->op_begin(); operand_it++; operand_it != it->op_end() ){
// Could this if else statement be reduced?
// If this operand is an argument it was not defined in the block.
if (isa<Argument>(operand_it)){
values.push_back(operand_it);
}
// Otherwize, it could be a constant value or ...
else if (!isa<Instruction>(operand_it)){
continue;
}
// Check if the parent of the instruction is not the block in question.
else if (((Instruction*)operand_it)->getParent() != block){
values.push_back(operand_it);
}
}
}

Do modern C++ compilers inline functions which are called exactly once?

As in, say my header file is:
class A
{
void Complicated();
}
And my source file
void A::Complicated()
{
...really long function...
}
Can I split the source file into
void DoInitialStuff(pass necessary vars by ref or value)
{
...
}
void HandleCaseA(pass necessary vars by ref or value)
{
...
}
void HandleCaseB(pass necessary vars by ref or value)
{
...
}
void FinishUp(pass necessary vars by ref or value)
{
...
}
void A::Complicated()
{
...
DoInitialStuff(...);
switch ...
HandleCaseA(...)
HandleCaseB(...)
...
FinishUp(...)
}
Entirely for readability and without any fear of impact in terms of performance?
You should mark the functions static so that the compiler know they are local to that translation unit.
Without static the compiler cannot assume (barring LTO / WPA) that the function is only called once, so is less likely to inline it.
Demonstration using the LLVM Try Out page.
That said, code for readability first, micro-optimizations (and such tweaking is a micro-optimization) should only come after performance measures.
Example:
#include <cstdio>
static void foo(int i) {
int m = i % 3;
printf("%d %d", i, m);
}
int main(int argc, char* argv[]) {
for (int i = 0; i != argc; ++i) {
foo(i);
}
}
Produces with static:
; ModuleID = '/tmp/webcompile/_27689_0.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"
#.str = private constant [6 x i8] c"%d %d\00" ; <[6 x i8]*> [#uses=1]
define i32 #main(i32 %argc, i8** nocapture %argv) nounwind {
entry:
%cmp4 = icmp eq i32 %argc, 0 ; <i1> [#uses=1]
br i1 %cmp4, label %for.end, label %for.body
for.body: ; preds = %for.body, %entry
%0 = phi i32 [ %inc, %for.body ], [ 0, %entry ] ; <i32> [#uses=3]
%rem.i = srem i32 %0, 3 ; <i32> [#uses=1]
%call.i = tail call i32 (i8*, ...)* #printf(i8* getelementptr inbounds ([6 x i8]* #.str, i64 0, i64 0), i32 %0, i32 %rem.i) nounwind ; <i32> [#uses=0]
%inc = add nsw i32 %0, 1 ; <i32> [#uses=2]
%exitcond = icmp eq i32 %inc, %argc ; <i1> [#uses=1]
br i1 %exitcond, label %for.end, label %for.body
for.end: ; preds = %for.body, %entry
ret i32 0
}
declare i32 #printf(i8* nocapture, ...) nounwind
Without static:
; ModuleID = '/tmp/webcompile/_27859_0.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"
#.str = private constant [6 x i8] c"%d %d\00" ; <[6 x i8]*> [#uses=1]
define void #foo(int)(i32 %i) nounwind {
entry:
%rem = srem i32 %i, 3 ; <i32> [#uses=1]
%call = tail call i32 (i8*, ...)* #printf(i8* getelementptr inbounds ([6 x i8]* #.str, i64 0, i64 0), i32 %i, i32 %rem) ; <i32> [#uses=0]
ret void
}
declare i32 #printf(i8* nocapture, ...) nounwind
define i32 #main(i32 %argc, i8** nocapture %argv) nounwind {
entry:
%cmp4 = icmp eq i32 %argc, 0 ; <i1> [#uses=1]
br i1 %cmp4, label %for.end, label %for.body
for.body: ; preds = %for.body, %entry
%0 = phi i32 [ %inc, %for.body ], [ 0, %entry ] ; <i32> [#uses=3]
%rem.i = srem i32 %0, 3 ; <i32> [#uses=1]
%call.i = tail call i32 (i8*, ...)* #printf(i8* getelementptr inbounds ([6 x i8]* #.str, i64 0, i64 0), i32 %0, i32 %rem.i) nounwind ; <i32> [#uses=0]
%inc = add nsw i32 %0, 1 ; <i32> [#uses=2]
%exitcond = icmp eq i32 %inc, %argc ; <i1> [#uses=1]
br i1 %exitcond, label %for.end, label %for.body
for.end: ; preds = %for.body, %entry
ret i32 0
}
Depends on aliasing (pointers to that function) and function length (a large function inlined in a branch could throw the other branch out of cache, thus hurting performance).
Let the compiler worry about that, you worry about your code :)
A complicated function is likely to have its speed dominated by the operations within the function; the overhead of a function call won't be noticeable even if it isn't inlined.
You don't have much control over the inlining of a function, the best way to know is to try it and find out.
A compiler's optimizer might be more effective with shorter pieces of code, so you might find it getting faster even if it's not inlined.
If you split up your code into logical groupings the compiler will do what it deems best: If it's short and easy, the compiler should inline it and the result is the same. If however the code is complicated, making an extra function call might actually be faster than doing all the work inlined, so you leave the compiler the option to do that too. On top of all that, the logically split code can be far easier for a maintainer to grok and avoid future bugs.
I suggest you create a helper class to break your complicated function into method calls, much like you were proposing, but without the long, boring and unreadable task of passing arguments to each and every one of these smaller functions. Pass these arguments only once by making them member variables of the helper class.
Don't focus on optimization at this point, make sure your code is readable and you'll be fine 99% of the time.

Speed difference between If-Else and Ternary operator in C...?

So at the suggestion of a colleague, I just tested the speed difference between the ternary operator and the equivalent If-Else block... and it seems that the ternary operator yields code that is between 1x and 2x faster than If-Else. My code is:
gettimeofday(&tv3, 0);
for(i = 0; i < N; i++)
{
a = i & 1;
if(a) a = b; else a = c;
}
gettimeofday(&tv4, 0);
gettimeofday(&tv1, 0);
for(i = 0; i < N; i++)
{
a = i & 1;
a = a ? b : c;
}
gettimeofday(&tv2, 0);
(Sorry for using gettimeofday and not clock_gettime... I will endeavor to better myself.)
I tried changing the order in which I timed the blocks, but the results seem to persist. What gives? Also, the If-Else shows much more variability in terms of execution speed. Should I be examining the assembly that gcc generates?
By the way, this is all at optimization level zero (-O0).
Am I imagining this, or is there something I'm not taking into account, or is this a machine-dependent thing, or what? Any help is appreciated.
There's a good chance that the ternary operator gets compiled into a cmov while the if/else results in a cmp+jmp. Just take a look at the assembly (using -S) to be sure. With optimizations enabled, it won't matter any more anyway, as any good compiler should produce the same code in both cases.
You could also go completely branchless and measure if it makes any difference:
int m = -(i & 1);
a = (b & m) | (c & ~m);
On today's architectures, this style of programming has grown a bit out of fashion.
This is a nice explanation: http://www.nynaeve.net/?p=178
Basically, there are "conditional set" processor instructions, which is faster than branching and setting in separate instructions.
If there is any, change your compiler!
For this kind of questions I use the Try Out LLVM page. It's an old release of LLVM (still using the gcc front-end), but those are old tricks.
Here is my little sample program (simplified version of yours):
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
int main (int argc, char* argv[]) {
int N = atoi(argv[0]);
int a = 0, d = 0, b = atoi(argv[1]), c = atoi(argv[2]);
int i;
for(i = 0; i < N; i++)
{
a = i & 1;
if(a) a = b+i; else a = c+i;
}
for(i = 0; i < N; i++)
{
d = i & 1;
d = d ? b+i : c+i;
}
printf("%d %d", a, d);
return 0;
}
And there is the corresponding LLVM IR generated:
define i32 #main(i32 %argc, i8** nocapture %argv) nounwind {
entry:
%0 = load i8** %argv, align 8 ; <i8*> [#uses=1]
%N = tail call i32 #atoi(i8* %0) nounwind readonly ; <i32> [#uses=5]
%2 = getelementptr inbounds i8** %argv, i64 1 ; <i8**> [#uses=1]
%3 = load i8** %2, align 8 ; <i8*> [#uses=1]
%b = tail call i32 #atoi(i8* %3) nounwind readonly ; <i32> [#uses=2]
%5 = getelementptr inbounds i8** %argv, i64 2 ; <i8**> [#uses=1]
%6 = load i8** %5, align 8 ; <i8*> [#uses=1]
%c = tail call i32 #atoi(i8* %6) nounwind readonly ; <i32> [#uses=2]
%8 = icmp sgt i32 %N, 0 ; <i1> [#uses=2]
br i1 %8, label %bb, label %bb11
bb: ; preds = %bb, %entry
%9 = phi i32 [ %10, %bb ], [ 0, %entry ] ; <i32> [#uses=2]
%10 = add nsw i32 %9, 1 ; <i32> [#uses=2]
%exitcond22 = icmp eq i32 %10, %N ; <i1> [#uses=1]
br i1 %exitcond22, label %bb10.preheader, label %bb
bb10.preheader: ; preds = %bb
%11 = and i32 %9, 1 ; <i32> [#uses=1]
%12 = icmp eq i32 %11, 0 ; <i1> [#uses=1]
%.pn13 = select i1 %12, i32 %c, i32 %b ; <i32> [#uses=1]
%tmp21 = add i32 %N, -1 ; <i32> [#uses=1]
%a.1 = add i32 %.pn13, %tmp21 ; <i32> [#uses=2]
br i1 %8, label %bb6, label %bb11
bb6: ; preds = %bb6, %bb10.preheader
%13 = phi i32 [ %14, %bb6 ], [ 0, %bb10.preheader ] ; <i32> [#uses=2]
%14 = add nsw i32 %13, 1 ; <i32> [#uses=2]
%exitcond = icmp eq i32 %14, %N ; <i1> [#uses=1]
br i1 %exitcond, label %bb10.bb11_crit_edge, label %bb6
bb10.bb11_crit_edge: ; preds = %bb6
%15 = and i32 %13, 1 ; <i32> [#uses=1]
%16 = icmp eq i32 %15, 0 ; <i1> [#uses=1]
%.pn = select i1 %16, i32 %c, i32 %b ; <i32> [#uses=1]
%tmp = add i32 %N, -1 ; <i32> [#uses=1]
%d.1 = add i32 %.pn, %tmp ; <i32> [#uses=1]
br label %bb11
bb11: ; preds = %bb10.bb11_crit_edge, %bb10.preheader, %entry
%a.0 = phi i32 [ %a.1, %bb10.bb11_crit_edge ], [ %a.1, %bb10.preheader ], [ 0, %entry ] ; <i32> [#uses=1]
%d.0 = phi i32 [ %d.1, %bb10.bb11_crit_edge ], [ 0, %bb10.preheader ], [ 0, %entry ] ; <i32> [#uses=1]
%17 = tail call i32 (i8*, ...)* #printf(i8* noalias getelementptr inbounds ([6 x i8]* #.str, i64 0, i64 0), i32 %a.0, i32 %d.0) nounwind ; <i32> [#uses=0]
ret i32 0
}
Okay, so it's likely to be chinese, even though I went ahead and renamed some variables to make it a bit easier to read.
The important bits are these two blocks:
%.pn13 = select i1 %12, i32 %c, i32 %b ; <i32> [#uses=1]
%tmp21 = add i32 %N, -1 ; <i32> [#uses=1]
%a.1 = add i32 %.pn13, %tmp21 ; <i32> [#uses=2]
%.pn = select i1 %16, i32 %c, i32 %b ; <i32> [#uses=1]
%tmp = add i32 %N, -1 ; <i32> [#uses=1]
%d.1 = add i32 %.pn, %tmp ; <i32> [#uses=1]
Which respectively set a and d.
And the conclusion is: No difference
Note: in a simpler example the two variables actually got merged, it seems here that the optimizer did not detect the similarity...
Any decent compiler should generate the same code for these if optimisation is turned on.
Understand that it's entirely up to the compiler how it interprets ternary expression (unless you actually force it not to with (inline) asm). It could just as easily understand ternary expression as 'if..else' in its Internal Representation language, and depending on the target backend, it may choose to generate conditional move instruction (on x86, CMOVcc is such one. There should also be ones for min/max, abs, etc). The main motivation of using conditional move is to transfer the risk of branch mispredict to a memory/register move operation. The caveat to this instruction is that nearly all the time, the operand register that will be conditionally loaded will have to be evaluated down to register form to take advantage of the cmov instruction.
This means that the unconditional evaluation process now has to be unconditional, and this will appear to increase the length of the unconditional path of the program. But understand that branch mispredict is most often resolved as 'flushing' the pipeline, which means that the instructions that would have finished executing are ignored (turned to No Operation instructions). This means that the actual number of instructions executed is higher because of the stalls or NOPs, and the effect scales with the depth of the processor pipeline and the misprediction rate.
This brings an interesting dilemma in determining the right heuristics. First, we know for sure that if the pipeline is too shallow or the branch prediction is fully able to learn pattern from branch history, then cmov is not worth doing. It's also not worth doing if the cost of evaluation of conditional argument is greater on than the cost from misprediction on average.
These are perhaps the core reasons why compilers have difficulty exploiting cmov instruction, since the heuristics determination is largely dependent on the runtime profiling information. It makes more sense to use this on JIT compiler since it can provide runtime instrumentation feedback and build a stronger heuristics for using this ("Is the branch truly unpredictable?"). On static compiler side without training data or profiler, it's most difficult to assume when this will be useful. However, a simple negative heuristic is, as aforementioned, if the compiler knows that the dataset is completely random or forcing cond. to uncond. evaluation is costly (perhaps due to irreducible, costly operations like fp divides), it would make good heuristics not to do this.
Any compiler worth its salt will do all that. Question is, what will it do after all dependable heuristics have been used up...