Issue |
140215
|
Summary |
InstCombine pass wrongly removes va_start/va_end
|
Labels |
new issue
|
Assignees |
|
Reporter |
hongjia
|
Test program:
``` C
typedef __builtin_va_list va_list;
#define va_start(ap, param) __builtin_va_start(ap, param)
#define va_end(ap) __builtin_va_end(ap)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_copy(d, s) __builtin_va_copy(d, s)
int foo(int n, ...)
{
va_list ap, aq;
int x;
va_start(ap, n);
va_copy(aq, ap);
va_end(ap);
x = va_arg(aq, int);
va_end(aq);
return x + n;
}
```
Compile it with -O1:
```
clang -S -emit-llvm -O1 ic-va.c -mllvm --debug-_only_=instcombine
...
IC: Visiting: call void @llvm.va_copy.p0(ptr nonnull %aq, ptr nonnull %ap)
IC: Visiting: call void @llvm.va_end.p0(ptr %ap)
IC: ERASE call void @llvm.va_start.p0(ptr nonnull %ap)
ADD DEFERRED: %ap = alloca ptr, align 2
IC: ERASE call void @llvm.va_end.p0(ptr %ap)
...
```
The resulting IR:
```
...
; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn
define dso_local i32 @foo(i32 noundef %n, ...) local_unnamed_addr #0 {
entry:
%ap = alloca ptr, align 2
%aq = alloca ptr, align 2
call void @llvm.lifetime.start.p0(i64 2, ptr nonnull %ap) #3
call void @llvm.lifetime.start.p0(i64 2, ptr nonnull %aq) #3
call void @llvm.va_copy.p0(ptr nonnull %aq, ptr nonnull %ap)
%0 = va_arg ptr %aq, i32
call void @llvm.va_end.p0(ptr %aq)
%add = add nsw i32 %0, %n
call void @llvm.lifetime.end.p0(i64 2, ptr nonnull %aq) #3
call void @llvm.lifetime.end.p0(i64 2, ptr nonnull %ap) #3
ret i32 %add
}
...
```
%ap is used in va_copy() without being initialized.
For now I use the following ugly patch to fix this:
```
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index c88710214e7e..d83228ae4b7e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -808,7 +808,10 @@ removeTriviallyEmptyRange(IntrinsicInst &EndI, InstCombinerImpl &IC,
IC.eraseInstFromFunction(*I);
IC.eraseInstFromFunction(EndI);
return true;
- }
+ } else if (EndI.getIntrinsicID() == Intrinsic::vaend &&
+ I->getIntrinsicID() == Intrinsic::vacopy &&
+ I->getArgOperand(1) == EndI.getArgOperand(0))
+ break;
// Skip start intrinsics that don't pair with this end intrinsic.
continue;
}
```
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs