Theoretically, a phi node occurs when a variable assignment can not be determined statically. But the following code does not generate the phi node as expected:
clang++ -c -emit-llvm -fno-discard-value-names -S -o test.ll test.cpp
struct someClass
{
int a;
char* b;
bool c;
someClass *next;
};
someClass* m(bool r, bool y, someClass* c){
bool l = y || r ;
if(l)
return c;
else
return nullptr;
}
someClass* phiFunc(int a, int b, someClass *c) {
if (a > b) {
c = m(false, true, c);
} else {
c = m(true, false, c);
}
someClass* ret = m(true, true, c); // <<--- phi node expected here.
return ret;
}
Changing c
to int
or adding -O0
does not make any difference either.
By looking at the IR generated below, we can see c.addr
is stored with register call
and call1
respectively in if.then
and if.else
branches.
But adding --print-memoryssa
, I think the problem is why the compiler does not generate phi node even though memory phi occurs.
opt-10 --print-memoryssa -S test.ll
; Function Attrs: noinline nounwind optnone uwtable
define dso_local %struct.someClass* @_Z7phiFunciiP9someClass(i32 %a, i32 %b, %struct.someClass* %c) #0 {
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%c.addr = alloca %struct.someClass*, align 8
%ret = alloca %struct.someClass*, align 8
; 1 = MemoryDef(liveOnEntry)
store i32 %a, i32* %a.addr, align 4
; 2 = MemoryDef(1)
store i32 %b, i32* %b.addr, align 4
; 3 = MemoryDef(2)
store %struct.someClass* %c, %struct.someClass** %c.addr, align 8
; MemoryUse(1) MustAlias
%0 = load i32, i32* %a.addr, align 4
; MemoryUse(2) MustAlias
%1 = load i32, i32* %b.addr, align 4
%cmp = icmp sgt i32 %0, %1
br i1 %cmp, label %if.then, label %if.else
if.then: ; preds = %entry
; MemoryUse(3) MustAlias
%2 = load %struct.someClass*, %struct.someClass** %c.addr, align 8
; 4 = MemoryDef(3)
%call = call %struct.someClass* @_Z1mbbP9someClass(i1 zeroext false, i1 zeroext true, %struct.someClass* %2)
; 5 = MemoryDef(4)
store %struct.someClass* %call, %struct.someClass** %c.addr, align 8
br label %if.end
if.else: ; preds = %entry
; MemoryUse(3) MustAlias
%3 = load %struct.someClass*, %struct.someClass** %c.addr, align 8
; 6 = MemoryDef(3)
%call1 = call %struct.someClass* @_Z1mbbP9someClass(i1 zeroext true, i1 zeroext false, %struct.someClass* %3)
; 7 = MemoryDef(6)
store %struct.someClass* %call1, %struct.someClass** %c.addr, align 8
br label %if.end
if.end: ; preds = %if.else, %if.then
; 10 = MemoryPhi({if.then,5},{if.else,7})
; MemoryUse(10) MayAlias
%4 = load %struct.someClass*, %struct.someClass** %c.addr, align 8
; 8 = MemoryDef(10)
%call2 = call %struct.someClass* @_Z1mbbP9someClass(i1 zeroext true, i1 zeroext true, %struct.someClass* %4)
; 9 = MemoryDef(8)
store %struct.someClass* %call2, %struct.someClass** %ret, align 8
; MemoryUse(9) MustAlias
%5 = load %struct.someClass*, %struct.someClass** %ret, align 8
ret %struct.someClass* %5
}
Using mem2reg
optimization does not help either:
➜ ~ opt -mem2reg -S test.ll -o test-opt.ll
➜ ~ diff test.ll test-opt.ll
1c1
< ; ModuleID = 'test.cpp'
---
> ; ModuleID = 'test.ll'
How can I make the compiler generate phi node as expected?
Thanks!