| 1 | // RUN: %clangxx %s -O1 -o %t -fexperimental-sanitize-metadata=covered,uar && %t | FileCheck %s |
| 2 | // RUN: %clangxx %s -O1 -o %t -fexperimental-sanitize-metadata=covered,uar -fsanitize=address,signed-integer-overflow,alignment && %t | FileCheck %s |
| 3 | // RUN: %clangxx %s -O1 -o %t -mcmodel=large -fexperimental-sanitize-metadata=covered,uar -fsanitize=address,signed-integer-overflow,alignment && %t | FileCheck %s |
| 4 | |
| 5 | // CHECK-DAG: metadata add version 2 |
| 6 | |
| 7 | __attribute__((noinline, not_tail_called)) void escape(const volatile void *p) { |
| 8 | [[maybe_unused]] static const volatile void *sink; |
| 9 | sink = p; |
| 10 | } |
| 11 | |
| 12 | __attribute__((noinline, not_tail_called)) void use(int x) { |
| 13 | static volatile int sink; |
| 14 | sink += x; |
| 15 | } |
| 16 | |
| 17 | // CHECK-DAG: empty: features=0 stack_args=0 |
| 18 | void empty() {} |
| 19 | |
| 20 | // CHECK-DAG: simple: features=0 stack_args=0 |
| 21 | int simple(int *data, int index) { return data[index + 1]; } |
| 22 | |
| 23 | // CHECK-DAG: builtins: features=0 stack_args=0 |
| 24 | int builtins() { |
| 25 | int x = 0; |
| 26 | __builtin_prefetch(&x); |
| 27 | return x; |
| 28 | } |
| 29 | |
| 30 | // CHECK-DAG: ellipsis: features=0 stack_args=0 |
| 31 | void ellipsis(const char *fmt, ...) { |
| 32 | int x; |
| 33 | escape(p: &x); |
| 34 | } |
| 35 | |
| 36 | // CHECK-DAG: non_empty_function: features=2 stack_args=0 |
| 37 | void non_empty_function() { |
| 38 | int x; |
| 39 | escape(p: &x); |
| 40 | } |
| 41 | |
| 42 | // CHECK-DAG: no_stack_args: features=2 stack_args=0 |
| 43 | void no_stack_args(long a0, long a1, long a2, long a3, long a4, long a5) { |
| 44 | int x; |
| 45 | escape(p: &x); |
| 46 | } |
| 47 | |
| 48 | // CHECK-DAG: stack_args: features=6 stack_args=16 |
| 49 | void stack_args(long a0, long a1, long a2, long a3, long a4, long a5, long a6) { |
| 50 | int x; |
| 51 | escape(p: &x); |
| 52 | } |
| 53 | |
| 54 | // CHECK-DAG: more_stack_args: features=6 stack_args=32 |
| 55 | void more_stack_args(long a0, long a1, long a2, long a3, long a4, long a5, |
| 56 | long a6, long a7, long a8) { |
| 57 | int x; |
| 58 | escape(p: &x); |
| 59 | } |
| 60 | |
| 61 | // CHECK-DAG: struct_stack_args: features=6 stack_args=144 |
| 62 | struct large { |
| 63 | char x[131]; |
| 64 | }; |
| 65 | void struct_stack_args(large a) { |
| 66 | int x; |
| 67 | escape(p: &x); |
| 68 | } |
| 69 | |
| 70 | __attribute__((noinline)) int tail_called(int x) { return x; } |
| 71 | |
| 72 | // CHECK-DAG: with_tail_call: features=2 |
| 73 | int with_tail_call(int x) { [[clang::musttail]] return tail_called(x); } |
| 74 | |
| 75 | __attribute__((noinline, noreturn)) int noreturn(int x) { __builtin_trap(); } |
| 76 | |
| 77 | // CHECK-DAG: with_noreturn_tail_call: features=0 |
| 78 | int with_noreturn_tail_call(int x) { return noreturn(x); } |
| 79 | |
| 80 | // CHECK-DAG: local_array: features=0 |
| 81 | void local_array(int x) { |
| 82 | int data[10]; |
| 83 | use(x: data[x]); |
| 84 | } |
| 85 | |
| 86 | // CHECK-DAG: local_alloca: features=0 |
| 87 | void local_alloca(int size, int i, int j) { |
| 88 | volatile int *p = static_cast<int *>(__builtin_alloca(size)); |
| 89 | p[i] = 0; |
| 90 | use(x: p[j]); |
| 91 | } |
| 92 | |
| 93 | // CHECK-DAG: escaping_alloca: features=2 |
| 94 | void escaping_alloca(int size, int i) { |
| 95 | volatile int *p = static_cast<int *>(__builtin_alloca(size)); |
| 96 | escape(p: &p[i]); |
| 97 | } |
| 98 | |
| 99 | #define FUNCTIONS \ |
| 100 | FN(empty); \ |
| 101 | FN(simple); \ |
| 102 | FN(builtins); \ |
| 103 | FN(ellipsis); \ |
| 104 | FN(non_empty_function); \ |
| 105 | FN(no_stack_args); \ |
| 106 | FN(stack_args); \ |
| 107 | FN(more_stack_args); \ |
| 108 | FN(struct_stack_args); \ |
| 109 | FN(with_tail_call); \ |
| 110 | FN(with_noreturn_tail_call); \ |
| 111 | FN(local_array); \ |
| 112 | FN(local_alloca); \ |
| 113 | FN(escaping_alloca); \ |
| 114 | /**/ |
| 115 | |
| 116 | #include "common.h" |
| 117 | |