309 lines
12 KiB
C
309 lines
12 KiB
C
|
// Check that backend stack layout diagnostics are working correctly with and
|
||
|
// without debug information, and when optimizations are enabled
|
||
|
//
|
||
|
// REQUIRES: x86-registered-target
|
||
|
//
|
||
|
// RUN: rm -rf %t
|
||
|
// RUN: mkdir -p %t
|
||
|
// RUN: %clang_cc1 %s -emit-codegen-only -triple x86_64-unknown-linux-gnu -target-cpu corei7 -Rpass-analysis=stack-frame-layout -o /dev/null -O0 2>&1 | FileCheck %s --check-prefix=O0-NODEBUG
|
||
|
// RUN: %clang_cc1 %s -emit-codegen-only -triple x86_64-unknown-linux-gnu -target-cpu corei7 -Rpass-analysis=stack-frame-layout -o /dev/null -O0 -debug-info-kind=constructor -dwarf-version=5 -debugger-tuning=gdb 2>&1 | FileCheck %s --check-prefix=O0-DEBUG
|
||
|
// RUN: %clang_cc1 %s -emit-codegen-only -triple x86_64-unknown-linux-gnu -target-cpu corei7 -funwind-tables=2 -O3 -Rpass-analysis=stack-frame-layout -debug-info-kind=constructor -dwarf-version=5 -debugger-tuning=gdb -opt-record-file %t/stack-layout-remark.c.yml -opt-record-passes stack-frame-layout 2>&1 | FileCheck %s --check-prefix=O3-DEBUG
|
||
|
// RUN: cat %t/stack-layout-remark.c.yml | FileCheck %s --check-prefix=YAML
|
||
|
|
||
|
#define NULL (void*)0
|
||
|
|
||
|
extern void* allocate(unsigned size);
|
||
|
extern void deallocate(void* ptr);
|
||
|
extern int work(char *ary, int size);
|
||
|
extern int rand(void);
|
||
|
|
||
|
// Test YAML Ouput
|
||
|
// YAML: --- !Analysis
|
||
|
// YAML: Pass: stack-frame-layout
|
||
|
// YAML: Name: StackLayout
|
||
|
// YAML: DebugLoc: { File: '{{.*}}stack-layout-remark.c',{{[[:space:]]*}}Line: [[# @LINE + 24]],
|
||
|
// YAML: Function: foo
|
||
|
// YAML: Args:
|
||
|
// YAML: - Offset: '-40'
|
||
|
// YAML: - Type: Variable
|
||
|
// YAML: - Align: '16'
|
||
|
// YAML: - Size: '32'
|
||
|
// YAML: - DataLoc: 'a @ {{.*}}stack-layout-remark.c:[[# @LINE + 19]]'
|
||
|
// YAML: - DataLoc: 'f @ {{.*}}stack-layout-remark.c:[[# @LINE + 21]]'
|
||
|
|
||
|
// O0-NODEBUG: Function: foo
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32
|
||
|
//
|
||
|
// O0-DEBUG: Function: foo
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
|
||
|
// O0-DEBUG-NEXT: a @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32
|
||
|
// O0-DEBUG-NEXT: f @ {{.*}}stack-layout-remark.c:[[# @LINE + 11]]
|
||
|
|
||
|
// O3-DEBUG: Function: foo
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
|
||
|
// O3-DEBUG-NEXT: a @ {{.*}}stack-layout-remark.c:[[# @LINE + 4]]
|
||
|
// O3-DEBUG-NEXT: f @ {{.*}}stack-layout-remark.c:[[# @LINE + 6]]
|
||
|
void foo() {
|
||
|
{
|
||
|
char a[32] = {0};
|
||
|
work(a, sizeof(a));
|
||
|
}
|
||
|
char f[32] = {0};
|
||
|
work(f, sizeof(f));
|
||
|
}
|
||
|
// O0-NODEBUG: Function: bar
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32
|
||
|
|
||
|
// O0-DEBUG: Function: bar
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
|
||
|
// O0-DEBUG-NEXT: f @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32
|
||
|
// O0-DEBUG-NEXT: a @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]]
|
||
|
|
||
|
// O3-DEBUG: Function: bar
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
|
||
|
// O3-DEBUG-NEXT: f @ {{.*}}stack-layout-remark.c:[[# @LINE + 4]]
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32
|
||
|
// O3-DEBUG-NEXT: a @ {{.*}}stack-layout-remark.c:[[# @LINE + 4]]
|
||
|
void bar() {
|
||
|
char f[32] = {0};
|
||
|
{
|
||
|
char a[32] = {0};
|
||
|
work(a, sizeof(a));
|
||
|
}
|
||
|
work(f, sizeof(f));
|
||
|
}
|
||
|
|
||
|
struct Array {
|
||
|
int *data;
|
||
|
int size;
|
||
|
};
|
||
|
|
||
|
struct Result {
|
||
|
struct Array *data;
|
||
|
int sum;
|
||
|
};
|
||
|
|
||
|
// O0-NODEBUG: Function: cleanup_array
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
|
||
|
|
||
|
// O0-DEBUG: Function: cleanup_array
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: a @ {{.*}}stack-layout-remark.c:[[# @LINE + 5]]
|
||
|
|
||
|
// O3-DEBUG: Function: cleanup_array
|
||
|
// O3-DEBUG: Function: cleanup_result
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8
|
||
|
void cleanup_array(struct Array *a) {
|
||
|
if (!a)
|
||
|
return;
|
||
|
if (!a->data)
|
||
|
return;
|
||
|
deallocate(a->data);
|
||
|
}
|
||
|
|
||
|
// O0-NODEBUG: Function: cleanup_result
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
|
||
|
|
||
|
// O0-DEBUG: Function: cleanup_result
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: res @ {{.*}}stack-layout-remark.c:[[# @LINE + 1]]
|
||
|
void cleanup_result(struct Result *res) {
|
||
|
if (!res)
|
||
|
return;
|
||
|
if (!res->data)
|
||
|
return;
|
||
|
cleanup_array(res->data);
|
||
|
deallocate(res->data);
|
||
|
}
|
||
|
|
||
|
extern void use_dot_vector(struct Array *data);
|
||
|
|
||
|
// O0-NODEBUG: Function: do_work
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-48], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-52], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-56], Type: Variable, Align: 4, Size: 4
|
||
|
|
||
|
// O0-DEBUG: Function: do_work
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: A @ {{.*}}stack-layout-remark.c:[[# @LINE + 20]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: B @ {{.*}}stack-layout-remark.c:[[# @LINE + 18]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: out @ {{.*}}stack-layout-remark.c:[[# @LINE + 16]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-DEBUG-NEXT: len @ {{.*}}stack-layout-remark.c:[[# @LINE + 19]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-48], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: AB @ {{.*}}stack-layout-remark.c:[[# @LINE + 18]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-52], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-DEBUG-NEXT: sum @ {{.*}}stack-layout-remark.c:[[# @LINE + 32]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-56], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-DEBUG-NEXT: i @ {{.*}}stack-layout-remark.c:[[# @LINE + 31]]
|
||
|
|
||
|
// O3-DEBUG: Function: do_work
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-24], Type: Spill, Align: 16, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-32], Type: Spill, Align: 8, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-40], Type: Spill, Align: 16, Size: 8
|
||
|
int do_work(struct Array *A, struct Array *B, struct Result *out) {
|
||
|
if (!A || !B)
|
||
|
return -1;
|
||
|
if (A->size != B->size)
|
||
|
return -1;
|
||
|
const int len = A->size;
|
||
|
struct Array *AB;
|
||
|
if (out->data == NULL) {
|
||
|
AB = (struct Array *)allocate(sizeof(struct Array));
|
||
|
AB->data = NULL;
|
||
|
AB->size = 0;
|
||
|
out->data = AB;
|
||
|
} else {
|
||
|
AB = out->data;
|
||
|
}
|
||
|
|
||
|
if (AB->data)
|
||
|
deallocate(AB->data);
|
||
|
|
||
|
AB->data = (int *)allocate(len * sizeof(int));
|
||
|
AB->size = len;
|
||
|
|
||
|
int sum = 0;
|
||
|
for (int i = 0; i < len; ++i) {
|
||
|
AB->data[i] = A->data[i] * B->data[i];
|
||
|
sum += AB->data[i];
|
||
|
}
|
||
|
return sum;
|
||
|
}
|
||
|
|
||
|
// O0-NODEBUG: Function: gen_array
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-12], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-28], Type: Variable, Align: 4, Size: 4
|
||
|
|
||
|
// O0-DEBUG: Function: gen_array
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-12], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-DEBUG-NEXT: size @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: res @ {{.*}}stack-layout-remark.c:[[# @LINE + 11]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-28], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-DEBUG-NEXT: i @ {{.*}}stack-layout-remark.c:[[# @LINE + 13]]
|
||
|
|
||
|
// O3-DEBUG: Function: gen_array
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-24], Type: Spill, Align: 16, Size: 8
|
||
|
struct Array *gen_array(int size) {
|
||
|
if (size < 0)
|
||
|
return NULL;
|
||
|
struct Array *res = (struct Array *)allocate(sizeof(struct Array));
|
||
|
res->size = size;
|
||
|
res->data = (int *)allocate(size * sizeof(int));
|
||
|
|
||
|
for (int i = 0; i < size; ++i) {
|
||
|
res->data[i] = rand();
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
// YAML: --- !Analysis
|
||
|
// YAML: Pass: stack-frame-layout
|
||
|
// YAML: Name: StackLayout
|
||
|
// YAML: DebugLoc: { File: '{{.*}}stack-layout-remark.c',{{[[:space:]]*}}Line: [[# @LINE + 59]],
|
||
|
// YAML: Function: caller
|
||
|
// YAML: Args:
|
||
|
// YAML: - Offset: '-8'
|
||
|
// YAML: - Type: Spill
|
||
|
// YAML: - Align: '16'
|
||
|
// YAML: - Size: '8'
|
||
|
// YAML: - Offset: '-16'
|
||
|
// YAML: - Type: Spill
|
||
|
// YAML: - Align: '8'
|
||
|
// YAML: - Size: '8'
|
||
|
// YAML: - Offset: '-24'
|
||
|
// YAML: - Type: Spill
|
||
|
// YAML: - Align: '16'
|
||
|
// YAML: - Size: '8'
|
||
|
// YAML: - Offset: '-32'
|
||
|
// YAML: - Type: Spill
|
||
|
// YAML: - Align: '8'
|
||
|
// YAML: - Size: '8'
|
||
|
// YAML: - Offset: '-40'
|
||
|
// YAML: - Type: Spill
|
||
|
// YAML: - Align: '16'
|
||
|
// YAML: - Size: '8'
|
||
|
// YAML: - Offset: '-48'
|
||
|
// YAML: - Type: Spill
|
||
|
// YAML: - Align: '8'
|
||
|
// YAML: - Size: '8'
|
||
|
|
||
|
// O0-NODEBUG: Function: caller
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-NODEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 4, Size: 4
|
||
|
|
||
|
// O0-DEBUG: Function: caller
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-DEBUG-NEXT: size @ {{.*}}stack-layout-remark.c:[[# @LINE + 20]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: A @ {{.*}}stack-layout-remark.c:[[# @LINE + 19]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: B @ {{.*}}stack-layout-remark.c:[[# @LINE + 18]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8
|
||
|
// O0-DEBUG-NEXT: res @ {{.*}}stack-layout-remark.c:[[# @LINE + 17]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-DEBUG-NEXT: ret @ {{.*}}stack-layout-remark.c:[[# @LINE + 16]]
|
||
|
// O0-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 4, Size: 4
|
||
|
// O0-DEBUG-NEXT: err @ {{.*}}stack-layout-remark.c:[[# @LINE + 16]]
|
||
|
|
||
|
// O3-DEBUG: Function: caller
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-24], Type: Spill, Align: 16, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-32], Type: Spill, Align: 8, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-40], Type: Spill, Align: 16, Size: 8
|
||
|
// O3-DEBUG-NEXT: Offset: [SP-48], Type: Spill, Align: 8, Size: 8
|
||
|
int caller() {
|
||
|
const int size = 100;
|
||
|
struct Array *A = gen_array(size);
|
||
|
struct Array *B = gen_array(size);
|
||
|
struct Result *res = (struct Result *)allocate(sizeof(struct Result));
|
||
|
int ret = -1;
|
||
|
|
||
|
int err = do_work(A, B, res);
|
||
|
if (err == -1) {
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
ret = res->sum;
|
||
|
if (ret == -1)
|
||
|
return caller();
|
||
|
|
||
|
use_dot_vector(res->data);
|
||
|
|
||
|
cleanup:
|
||
|
cleanup_array(A);
|
||
|
cleanup_array(B);
|
||
|
cleanup_result(res);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|