|
| 1 | +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 |
| 2 | +// RUN: %clang_cc1 -emit-llvm -fextend-variable-liveness -o - %s | FileCheck %s |
| 3 | + |
| 4 | +/// Tests that when we have fake uses in a function ending in a musttail call, |
| 5 | +/// we emit the fake uses and their corresponding loads immediately prior to the |
| 6 | +/// tail call. |
| 7 | + |
| 8 | +struct Class1 { |
| 9 | + Class1(int); |
| 10 | +}; |
| 11 | + |
| 12 | +class Class2 { |
| 13 | + static const char *foo(int *, const char *, int *, Class1, const int *, |
| 14 | + unsigned long); |
| 15 | + template <class> |
| 16 | + static char *bar(int *, const char *, int *, Class1, const int *, unsigned long); |
| 17 | +}; |
| 18 | + |
| 19 | +// CHECK-LABEL: define dso_local noundef ptr @_ZN6Class23fooEPiPKcS0_6Class1PKim( |
| 20 | +// CHECK-SAME: ptr noundef [[E:%.*]], ptr noundef [[F:%.*]], ptr noundef [[G:%.*]], ptr noundef [[H:%.*]], i64 noundef [[I:%.*]]) #[[ATTR0:[0-9]+]] align 2 { |
| 21 | +// CHECK-NEXT: [[ENTRY:.*:]] |
| 22 | +// CHECK-NEXT: [[TMP0:%.*]] = alloca [[STRUCT_CLASS1:%.*]], align 1 |
| 23 | +// CHECK-NEXT: [[E_ADDR:%.*]] = alloca ptr, align 8 |
| 24 | +// CHECK-NEXT: [[F_ADDR:%.*]] = alloca ptr, align 8 |
| 25 | +// CHECK-NEXT: [[G_ADDR:%.*]] = alloca ptr, align 8 |
| 26 | +// CHECK-NEXT: [[H_ADDR:%.*]] = alloca ptr, align 8 |
| 27 | +// CHECK-NEXT: [[I_ADDR:%.*]] = alloca i64, align 8 |
| 28 | +// CHECK-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_CLASS1]], align 1 |
| 29 | +// CHECK-NEXT: store ptr [[E]], ptr [[E_ADDR]], align 8 |
| 30 | +// CHECK-NEXT: store ptr [[F]], ptr [[F_ADDR]], align 8 |
| 31 | +// CHECK-NEXT: store ptr [[G]], ptr [[G_ADDR]], align 8 |
| 32 | +// CHECK-NEXT: store ptr [[H]], ptr [[H_ADDR]], align 8 |
| 33 | +// CHECK-NEXT: store i64 [[I]], ptr [[I_ADDR]], align 8 |
| 34 | +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[E_ADDR]], align 8 |
| 35 | +// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[F_ADDR]], align 8 |
| 36 | +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[G_ADDR]], align 8 |
| 37 | +// CHECK-NEXT: call void @_ZN6Class1C1Ei(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]], i32 noundef 0) |
| 38 | +// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[H_ADDR]], align 8 |
| 39 | +// CHECK-NEXT: [[TMP5:%.*]] = load i64, ptr [[I_ADDR]], align 8 |
| 40 | +// CHECK-NEXT: [[FAKE_USE:%.*]] = load i64, ptr [[I_ADDR]], align 8 |
| 41 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use(i64 [[FAKE_USE]]) #[[ATTR3:[0-9]+]] |
| 42 | +// CHECK-NEXT: [[FAKE_USE1:%.*]] = load ptr, ptr [[H_ADDR]], align 8 |
| 43 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE1]]) #[[ATTR3]] |
| 44 | +// CHECK-NEXT: [[FAKE_USE2:%.*]] = load [[STRUCT_CLASS1]], ptr [[TMP0]], align 1 |
| 45 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use([[STRUCT_CLASS1]] [[FAKE_USE2]]) #[[ATTR3]] |
| 46 | +// CHECK-NEXT: [[FAKE_USE3:%.*]] = load ptr, ptr [[G_ADDR]], align 8 |
| 47 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE3]]) #[[ATTR3]] |
| 48 | +// CHECK-NEXT: [[FAKE_USE4:%.*]] = load ptr, ptr [[F_ADDR]], align 8 |
| 49 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE4]]) #[[ATTR3]] |
| 50 | +// CHECK-NEXT: [[FAKE_USE5:%.*]] = load ptr, ptr [[E_ADDR]], align 8 |
| 51 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE5]]) #[[ATTR3]] |
| 52 | +// CHECK-NEXT: [[CALL:%.*]] = musttail call noundef ptr @_ZN6Class23barIiEEPcPiPKcS2_6Class1PKim(ptr noundef [[TMP1]], ptr noundef [[TMP2]], ptr noundef [[TMP3]], ptr noundef [[TMP4]], i64 noundef [[TMP5]]) |
| 53 | +// CHECK-NEXT: ret ptr [[CALL]] |
| 54 | +// CHECK: [[BB6:.*:]] |
| 55 | +// CHECK-NEXT: [[FAKE_USE6:%.*]] = load i64, ptr [[I_ADDR]], align 8 |
| 56 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use(i64 [[FAKE_USE6]]) #[[ATTR3]] |
| 57 | +// CHECK-NEXT: [[FAKE_USE7:%.*]] = load ptr, ptr [[H_ADDR]], align 8 |
| 58 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE7]]) #[[ATTR3]] |
| 59 | +// CHECK-NEXT: [[FAKE_USE8:%.*]] = load [[STRUCT_CLASS1]], ptr [[TMP0]], align 1 |
| 60 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use([[STRUCT_CLASS1]] [[FAKE_USE8]]) #[[ATTR3]] |
| 61 | +// CHECK-NEXT: [[FAKE_USE9:%.*]] = load ptr, ptr [[G_ADDR]], align 8 |
| 62 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE9]]) #[[ATTR3]] |
| 63 | +// CHECK-NEXT: [[FAKE_USE10:%.*]] = load ptr, ptr [[F_ADDR]], align 8 |
| 64 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE10]]) #[[ATTR3]] |
| 65 | +// CHECK-NEXT: [[FAKE_USE11:%.*]] = load ptr, ptr [[E_ADDR]], align 8 |
| 66 | +// CHECK-NEXT: notail call void (...) @llvm.fake.use(ptr [[FAKE_USE11]]) #[[ATTR3]] |
| 67 | +// CHECK-NEXT: ret ptr undef |
| 68 | +// |
| 69 | +const char *Class2::foo(int *e, const char *f, int *g, Class1, const int *h, |
| 70 | + unsigned long i) { |
| 71 | + [[clang::musttail]] return bar<int>(e, f, g, int(), h, i); |
| 72 | +} |
0 commit comments