Skip to content

Commit

Permalink
tests for passing struct parameters by value
Browse files Browse the repository at this point in the history
  • Loading branch information
nlsandler committed Oct 31, 2023
1 parent 6b474d4 commit afe2b2a
Show file tree
Hide file tree
Showing 67 changed files with 1,558 additions and 548 deletions.
2 changes: 1 addition & 1 deletion expected_results.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions test_framework/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,13 @@ def needs_mathlib(prog: Path) -> bool:
key = get_props_key(prog)
return key in REQUIRES_MATHLIB and not IS_OSX


def print_stderr(proc: subprocess.CompletedProcess[str]) -> None:
"""Print out stderr of CompletedProcess if it's not empty. Intended to print assembler/linker warnings"""
if proc.stderr:
print(proc.stderr)


def gcc_build_obj(prog: Path) -> None:
"""Use the 'gcc' command to compile source file to an object file.
This is used to test ABI compatibility between our compiler and the system compiler
Expand Down Expand Up @@ -119,7 +121,6 @@ def gcc_compile_and_run(
# TODO better handling of internal problems with test suite
raise RuntimeError(err.stderr) from err


# run it
return subprocess.run([exe], check=False, text=True, capture_output=True)

Expand Down Expand Up @@ -178,7 +179,7 @@ def tearDown(self) -> None:
f
for f in self.test_dir.rglob("*")
if not f.is_dir()
and f.suffix not in [".c", ".h"]
and f.suffix not in [".c", ".h", ".md"]
and f.name not in ASSEMBLY_LIBS
)

Expand Down
2 changes: 1 addition & 1 deletion test_framework/tacky/dead_store_elim.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class TestDeadStoreElimination(common.TackyOptimizationTest):
Each dynamically generated test calls one of the following main test methods:
* compile_and_run, defined in TestChapter: validate behavior but don't inspect assembly
* store_eliminated_test: make sure a particular mov instrucion was eliminated
* store_eliminated_test: make sure a particular mov instruction was eliminated
* return_const_test: make sure entire funcion is reduce to a return instruction
"""

Expand Down
2 changes: 1 addition & 1 deletion test_framework/test_tests/test_programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def tearDown(self) -> None:
garbage_files = (
f
for f in basic.TEST_DIR.rglob("*")
if not f.is_dir() and f.suffix not in [".c", ".h", ".s"]
if not f.is_dir() and f.suffix not in [".c", ".h", ".s", ".md"]
)

for junk in garbage_files:
Expand Down
8 changes: 8 additions & 0 deletions test_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,14 @@
"chapter_18/valid/params_and_returns/return_struct_on_page_boundary.c": {
"linux": "data_on_page_boundary_linux.s",
"os_x": "data_on_page_boundary_osx.s"
},
"chapter_18/valid/params_and_returns/return_big_struct_on_page_boundary.c": {
"linux": "big_data_on_page_boundary_linux.s",
"os_x": "big_data_on_page_boundary_osx.s"
},
"chapter_18/valid/params_and_returns/return_space_overlap.c": {
"linux": "return_space_address_overlap_linux.s",
"os_x": "return_space_address_overlap_osx.s"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
/* Test that we can pass a pointer to an array of structures as a parameter */

#include "array_of_structs.h"

int validate_struct_array(struct outer *struct_array) {
for (int i = 0; i < 3; i = i + 1) {
if (struct_array[i].a != i * 2)
return i;
return 0;
if (struct_array[i].b.l != i * 3)
return i * 10;
return 0;
if (struct_array[i].b.arr[0] != i * 4)
return i * 25;
return 0;
if (struct_array[i].b.arr[1] != i * 5)
return i * 11;
return 0;
}
return 0;
return 1; // success
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* Test that we can pass a pointer to an array of structures as a parameter */

struct inner {
long l;
char arr[2];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* Test that we can pass a pointer to an array of structures as a parameter */

#include "array_of_structs.h"

static struct outer static_array[3] = {
{0, {0, {0, 0}}}, {2, {3, {4, 5}}}, {4, {6, {8, 10}}}};

int main(void) {
struct outer auto_array[3] = {
{0, {0, {0, 0}}}, {2, {3, {4, 5}}}, {4, {6, {8, 10}}}};

// pass pointers to struct arrays with both static and automatic storage
// both have same contents so we can validate them with the same function

if (!validate_struct_array(static_array)) {
return 1;
}

if (!validate_struct_array(auto_array)) {
return 2;
}

return 0; // success
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#endif
#endif

// library functoins
// library functions
int strcmp(char *s1, char *s2);

void *malloc(unsigned long size);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#endif
#endif

// library functoins
// library functions
int strcmp(char *s1, char *s2);
int puts(char *s);
void *malloc(unsigned long size);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,9 @@ int main(void) {
return 3;
}

if (!test_update_nested_struct_thru_retval()) {
return 4;
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ int strcmp(char *s1, char *s2);
// test 1: you can declare a function that accepts/returns incomplete struct
// types we don't define or use this function, we just need to validate that
// this declaration doesn't cause a compiler error
// TODO include test in appropriate folder where we define/call this after
// completing the type
struct never_used;
struct never_used incomplete_fun(struct never_used x);

Expand Down Expand Up @@ -162,6 +160,7 @@ int test_use_incomplete_struct_pointers(void) {
return 0;
}

// can pass them as parameters
if (use_struct_pointers(ptr3)) {
return 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ int test_copy_array_element_with_padding(void) {
struct with_end_padding arr[3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
struct with_end_padding elem = {9, 9, 9};
arr[1] = elem;
if (arr[0].a == 0 && arr[0].b == 1 && arr[0].c == 2 && arr[1].a == 9 &&
arr[1].b == 9 && arr[1].c == 9 && arr[2].a == 6 && arr[2].b == 7 &&
arr[2].c == 8) {
if (arr[0].a != 0 || arr[0].b != 1 || arr[0].c != 2 || arr[1].a != 9 ||
arr[1].b != 9 || arr[1].c != 9 || arr[2].a != 6 || arr[2].b != 7 ||
arr[2].c != 8) {
return 0;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.bss
.align 4096
.zero 4085
.bss # .bss is the last segment in the program image - the page after it will be unampped
.align 4096 # force page alignment
.zero 4085 # write a bunch of zeros so on_page_boundary is at the end of the page
.globl on_page_boundary
on_page_boundary:
.zero 9
.zero 11
.section ".note.GNU-stack","",@progbits
8 changes: 4 additions & 4 deletions tests/chapter_18/valid/parameters/data_on_page_boundary_osx.s
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.bss
.align 12
.zero 4085
.bss # .bss is the last segment in the program image - the page after it will be unampped
.align 12 # force page alignment (2^12 == 4096)
.zero 4085 # write a bunch of zeros so on_page_boundary is at the end of the page
.globl _on_page_boundary
_on_page_boundary:
.zero 9
.zero 11
7 changes: 6 additions & 1 deletion tests/chapter_18/valid/parameters/incomplete_param_type.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
/* Test that we can declare a function with an incomplete parameter type,
* then call/define it after the type is completed */
struct s;

// struct s is incomplete here, so we can declare this function
// but not define it
int foo(struct s blah);

// complete the type
struct s {
int a;
int b;
};

int main(void) {
struct s arg = {1, 2};
return foo(arg);
return foo(arg); // we can call foo b/c 'struct s' type is completed
}

int foo(struct s blah) {
Expand Down

This file was deleted.

62 changes: 62 additions & 0 deletions tests/chapter_18/valid/parameters/libraries/classify_params.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* Test that we classify structure parameters correctly,
* by passing a variety of structures as arguments.
* Each test function takes only one argument.
* */

#include "classify_params.h"

int test_twelve_bytes(struct twelve_bytes s) {
if (s.i != 0 || strcmp(s.arr, "lmnopqr")) {
return 0;
}
return 1; // success
}
int test_nested_ints(struct nested_ints s) {
if (s.ch1 != 127 || s.nested.i != 2147483647 || s.nested.ch2 != -128) {
return 0;
}
return 1; // success
}
int test_flattened_ints(struct flattened_ints s) {
if (s.c != 127 || s.i != 2147483647 || s.a != -128) {
return 0;
}

return 1; // success
}
int test_large(struct large s) {
if (s.i != 200000 || s.d != 23.25 || strcmp(s.arr, "abcdefghi")) {
return 0;
}

return 1; // success
}
int test_two_ints(struct two_ints s) {
if (s.i != 999 || s.i2 != 888) {
return 0;
}

return 1; // success
}
int test_nested_double(struct nested_double s) {
if (s.array[0] != 25.125e3) {
return 0;
}

return 1; // success
}
int test_two_eightbytes(struct two_eightbytes s) {
if (s.d != 1000. || s.c != 'x') {
return 0;
}

return 1; // success
}
int test_pass_in_memory(struct pass_in_memory s) {
if (s.w != 1.7e308 || s.x != -1.7e308 || s.y != -2147483647 ||
s.z != -9223372036854775807l) {
return 0;
}

return 1; // success
}
78 changes: 78 additions & 0 deletions tests/chapter_18/valid/parameters/libraries/classify_params.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* Test that we classify structure parameters correctly,
* by passing a variety of structures as arguments.
* Each test function takes only one argument.
* */

#ifdef SUPPRESS_WARNINGS
#ifdef __clang__
#pragma clang diagnostic ignored "-Wincompatible-library-redeclaration"
#else
#pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch"
#endif
#endif

int strcmp(char *s1, char *s2);

// from Listing 18-39
struct twelve_bytes {
int i;
char arr[8];
}; // two INTEGER eightbytes

// from Listing 18-40
struct inner {
int i;
char ch2;
};

struct nested_ints {
char ch1;
struct inner nested;
}; // two INTEGER eightbytes

// from Listing 18-41
struct flattened_ints {
char c;
int i;
char a;
}; // two INTEGER eightbytes

// From uncaptioned listing in "Classifying Eightbytes" section
struct large {
int i;
double d;
char arr[10];
}; // four MEMORY eightbytes

// Three structure declarations from Listing 18-42
struct two_ints {
int i;
int i2;
}; // one INTEGER eightbyte

struct nested_double {
double array[1];
}; // one SSE eightbyte

struct two_eightbytes {
double d;
char c;
}; // one SSE eightbyte, one INTEGER eightbyte

// From Listing 18-47
struct pass_in_memory {
double w;
double x;
int y;
long z;
}; // four MEMORY eightbytes

// validation functions defined in library
int test_twelve_bytes(struct twelve_bytes s);
int test_nested_ints(struct nested_ints s);
int test_flattened_ints(struct flattened_ints s);
int test_large(struct large s);
int test_two_ints(struct two_ints s);
int test_nested_double(struct nested_double s);
int test_two_eightbytes(struct two_eightbytes s);
int test_pass_in_memory(struct pass_in_memory s);
Loading

0 comments on commit afe2b2a

Please sign in to comment.