From 986acfcab76a0e058ff501df5871e06ff8d6075f Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Fri, 1 Sep 2023 01:15:56 +0000 Subject: [PATCH 001/167] add license and README --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..63b4b681 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From df3b418b7b40a528d4bf16cd29e3fc985c32bb31 Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Mon, 6 Mar 2023 10:49:35 -0800 Subject: [PATCH 002/167] tests for chapter 12, extra credit tests for chapter 11, move a few tests to the correct spot --- .../goto_cross_function.c | 0 .../goto_function.c | 0 .../goto_file_scope_label.c | 7 ++++ .../goto_global_var.c | 7 ++++ .../extern_param.c | 0 chapter11/invalid_parse/static_and_extern.c | 6 +++ .../static_param.c | 0 .../goto_skip_static_initializer.c | 9 ++++ .../switch_duplicate_cases.c | 16 +++++++ chapter12/invalid_lex/invalid_suffix2.c | 8 ++++ chapter12/invalid_parse/bad_specifiers.c | 5 +++ chapter12/invalid_parse/empty_cast.c | 4 ++ chapter12/invalid_parse/fun_name_long.c | 8 ++++ chapter12/invalid_parse/invalid_cast.c | 6 +++ chapter12/invalid_parse/invalid_suffix.c | 4 ++ .../invalid_parse/long_constant_as_var.c | 5 +++ .../invalid_parse/missing_cast_parentheses.c | 4 ++ chapter12/invalid_parse/var_name_long.c | 5 +++ .../conflicting_function_types.c | 9 ++++ .../invalid_types/conflicting_global_types.c | 10 +++++ .../conflicting_variable_types.c | 9 ++++ chapter12/valid/explicit_casts/sign_extend.c | 16 +++++++ .../explicit_casts/sign_extend_constant.c | 5 +++ chapter12/valid/explicit_casts/truncate.c | 41 ++++++++++++++++++ .../implicit_casts/addition_common_type.c | 13 ++++++ .../implicit_casts/comparison_common_type.c | 13 ++++++ .../implicit_casts/conditional_common_type.c | 12 ++++++ .../convert_function_arguments.c | 42 +++++++++++++++++++ .../convert_static_initializer.c | 8 ++++ .../implicit_casts/division_common_type.c | 18 ++++++++ .../implicit_casts/extend_return_value.c | 12 ++++++ .../valid/implicit_casts/long_constants.c | 7 ++++ .../valid/implicit_casts/truncate_constant.c | 5 +++ .../implicit_casts/truncate_on_assignment.c | 6 +++ .../implicit_casts/truncate_return_value.c | 16 +++++++ chapter12/valid/libraries/long_args.c | 10 +++++ chapter12/valid/libraries/long_args_client.c | 9 ++++ chapter12/valid/libraries/long_global_var.c | 9 ++++ .../valid/libraries/long_global_var_client.c | 30 +++++++++++++ .../libraries/maintain_stack_alignment.c | 3 ++ .../maintain_stack_alignment_client.c | 12 ++++++ chapter12/valid/libraries/return_long.c | 3 ++ .../valid/libraries/return_long_client.c | 14 +++++++ chapter12/valid/long_expressions/add.c | 11 +++++ chapter12/valid/long_expressions/assign.c | 10 +++++ chapter12/valid/long_expressions/compare.c | 10 +++++ chapter12/valid/long_expressions/div.c | 12 ++++++ .../valid/long_expressions/large_constants.c | 25 +++++++++++ .../long_expressions/long_and_int_locals.c | 26 ++++++++++++ chapter12/valid/long_expressions/long_args.c | 14 +++++++ chapter12/valid/long_expressions/mod.c | 11 +++++ chapter12/valid/long_expressions/mult.c | 10 +++++ chapter12/valid/long_expressions/multi_op.c | 15 +++++++ .../valid/long_expressions/return_long.c | 12 ++++++ .../valid/long_expressions/static_long.c | 14 +++++++ chapter12/valid/long_expressions/sub.c | 9 ++++ .../valid/long_expressions/type_specifiers.c | 32 ++++++++++++++ .../valid_extra_credit/bitwise_long_op.c | 34 +++++++++++++++ .../compound_assign_to_int.c | 11 +++++ .../compound_assign_to_long.c | 7 ++++ chapter12/valid_extra_credit/switch_int.c | 37 ++++++++++++++++ chapter12/valid_extra_credit/switch_long.c | 22 ++++++++++ 62 files changed, 748 insertions(+) rename chapter10/{invalid_declarations_extra_credit => invalid_labels_extra_credit}/goto_cross_function.c (100%) rename chapter10/{invalid_declarations_extra_credit => invalid_labels_extra_credit}/goto_function.c (100%) create mode 100644 chapter11/invalid_labels_extra_credit/goto_file_scope_label.c create mode 100644 chapter11/invalid_labels_extra_credit/goto_global_var.c rename chapter11/{invalid_types => invalid_parse}/extern_param.c (100%) create mode 100644 chapter11/invalid_parse/static_and_extern.c rename chapter11/{invalid_types => invalid_parse}/static_param.c (100%) create mode 100644 chapter11/valid_extra_credit/goto_skip_static_initializer.c create mode 100644 chapter12/invalid_labels_extra_credit/switch_duplicate_cases.c create mode 100644 chapter12/invalid_lex/invalid_suffix2.c create mode 100644 chapter12/invalid_parse/bad_specifiers.c create mode 100644 chapter12/invalid_parse/empty_cast.c create mode 100644 chapter12/invalid_parse/fun_name_long.c create mode 100644 chapter12/invalid_parse/invalid_cast.c create mode 100644 chapter12/invalid_parse/invalid_suffix.c create mode 100644 chapter12/invalid_parse/long_constant_as_var.c create mode 100644 chapter12/invalid_parse/missing_cast_parentheses.c create mode 100644 chapter12/invalid_parse/var_name_long.c create mode 100644 chapter12/invalid_types/conflicting_function_types.c create mode 100644 chapter12/invalid_types/conflicting_global_types.c create mode 100644 chapter12/invalid_types/conflicting_variable_types.c create mode 100644 chapter12/valid/explicit_casts/sign_extend.c create mode 100644 chapter12/valid/explicit_casts/sign_extend_constant.c create mode 100644 chapter12/valid/explicit_casts/truncate.c create mode 100644 chapter12/valid/implicit_casts/addition_common_type.c create mode 100644 chapter12/valid/implicit_casts/comparison_common_type.c create mode 100644 chapter12/valid/implicit_casts/conditional_common_type.c create mode 100644 chapter12/valid/implicit_casts/convert_function_arguments.c create mode 100644 chapter12/valid/implicit_casts/convert_static_initializer.c create mode 100644 chapter12/valid/implicit_casts/division_common_type.c create mode 100644 chapter12/valid/implicit_casts/extend_return_value.c create mode 100644 chapter12/valid/implicit_casts/long_constants.c create mode 100644 chapter12/valid/implicit_casts/truncate_constant.c create mode 100644 chapter12/valid/implicit_casts/truncate_on_assignment.c create mode 100644 chapter12/valid/implicit_casts/truncate_return_value.c create mode 100644 chapter12/valid/libraries/long_args.c create mode 100644 chapter12/valid/libraries/long_args_client.c create mode 100644 chapter12/valid/libraries/long_global_var.c create mode 100644 chapter12/valid/libraries/long_global_var_client.c create mode 100644 chapter12/valid/libraries/maintain_stack_alignment.c create mode 100644 chapter12/valid/libraries/maintain_stack_alignment_client.c create mode 100644 chapter12/valid/libraries/return_long.c create mode 100644 chapter12/valid/libraries/return_long_client.c create mode 100644 chapter12/valid/long_expressions/add.c create mode 100644 chapter12/valid/long_expressions/assign.c create mode 100644 chapter12/valid/long_expressions/compare.c create mode 100644 chapter12/valid/long_expressions/div.c create mode 100644 chapter12/valid/long_expressions/large_constants.c create mode 100644 chapter12/valid/long_expressions/long_and_int_locals.c create mode 100644 chapter12/valid/long_expressions/long_args.c create mode 100644 chapter12/valid/long_expressions/mod.c create mode 100644 chapter12/valid/long_expressions/mult.c create mode 100644 chapter12/valid/long_expressions/multi_op.c create mode 100644 chapter12/valid/long_expressions/return_long.c create mode 100644 chapter12/valid/long_expressions/static_long.c create mode 100644 chapter12/valid/long_expressions/sub.c create mode 100644 chapter12/valid/long_expressions/type_specifiers.c create mode 100644 chapter12/valid_extra_credit/bitwise_long_op.c create mode 100644 chapter12/valid_extra_credit/compound_assign_to_int.c create mode 100644 chapter12/valid_extra_credit/compound_assign_to_long.c create mode 100644 chapter12/valid_extra_credit/switch_int.c create mode 100644 chapter12/valid_extra_credit/switch_long.c diff --git a/chapter10/invalid_declarations_extra_credit/goto_cross_function.c b/chapter10/invalid_labels_extra_credit/goto_cross_function.c similarity index 100% rename from chapter10/invalid_declarations_extra_credit/goto_cross_function.c rename to chapter10/invalid_labels_extra_credit/goto_cross_function.c diff --git a/chapter10/invalid_declarations_extra_credit/goto_function.c b/chapter10/invalid_labels_extra_credit/goto_function.c similarity index 100% rename from chapter10/invalid_declarations_extra_credit/goto_function.c rename to chapter10/invalid_labels_extra_credit/goto_function.c diff --git a/chapter11/invalid_labels_extra_credit/goto_file_scope_label.c b/chapter11/invalid_labels_extra_credit/goto_file_scope_label.c new file mode 100644 index 00000000..27848683 --- /dev/null +++ b/chapter11/invalid_labels_extra_credit/goto_file_scope_label.c @@ -0,0 +1,7 @@ +/* Labels cannot appear at file scope. */ +x: +int foo = 0; + +int main() { + return 0; +} \ No newline at end of file diff --git a/chapter11/invalid_labels_extra_credit/goto_global_var.c b/chapter11/invalid_labels_extra_credit/goto_global_var.c new file mode 100644 index 00000000..6c8b507d --- /dev/null +++ b/chapter11/invalid_labels_extra_credit/goto_global_var.c @@ -0,0 +1,7 @@ +int x = 10; + +int main() { + /* goto statements can only target labels, not variables. */ + goto x; + return 0; +} \ No newline at end of file diff --git a/chapter11/invalid_types/extern_param.c b/chapter11/invalid_parse/extern_param.c similarity index 100% rename from chapter11/invalid_types/extern_param.c rename to chapter11/invalid_parse/extern_param.c diff --git a/chapter11/invalid_parse/static_and_extern.c b/chapter11/invalid_parse/static_and_extern.c new file mode 100644 index 00000000..0a8eccb0 --- /dev/null +++ b/chapter11/invalid_parse/static_and_extern.c @@ -0,0 +1,6 @@ +/* A declaration cannot include both static and extern specifiers */ +static extern int a; + +int main() { + return 0; +} \ No newline at end of file diff --git a/chapter11/invalid_types/static_param.c b/chapter11/invalid_parse/static_param.c similarity index 100% rename from chapter11/invalid_types/static_param.c rename to chapter11/invalid_parse/static_param.c diff --git a/chapter11/valid_extra_credit/goto_skip_static_initializer.c b/chapter11/valid_extra_credit/goto_skip_static_initializer.c new file mode 100644 index 00000000..339c0426 --- /dev/null +++ b/chapter11/valid_extra_credit/goto_skip_static_initializer.c @@ -0,0 +1,9 @@ +int main() { + goto end; + /* Since x is static, it's initialized at program startup, + * so its value will be 10 even though we jump over this declaration + */ + static int x = 10; + end: + return x; +} \ No newline at end of file diff --git a/chapter12/invalid_labels_extra_credit/switch_duplicate_cases.c b/chapter12/invalid_labels_extra_credit/switch_duplicate_cases.c new file mode 100644 index 00000000..8e92d69b --- /dev/null +++ b/chapter12/invalid_labels_extra_credit/switch_duplicate_cases.c @@ -0,0 +1,16 @@ +int switch_statement(int i) { + switch(i) { + case 0: return 0; + /* because i is an int, the constant for + * each case will be converted to an int. + * 17179869184 (equal to 2^34) will be converted + * to 0, which conflicts with the previous case. + */ + case 17179869184: return 0; + default: return 1; + } +} + +int main() { + return switch_statement(0); +} \ No newline at end of file diff --git a/chapter12/invalid_lex/invalid_suffix2.c b/chapter12/invalid_lex/invalid_suffix2.c new file mode 100644 index 00000000..63d3beec --- /dev/null +++ b/chapter12/invalid_lex/invalid_suffix2.c @@ -0,0 +1,8 @@ +int main() { + /* only one "L" suffix is permitted on a long + * Note: an "LL" suffix is standard-compliant and indicates + * a long long constant, but isn't supported by our implementation. + * Instead, we use an LLL suffix, which is always invalid. + */ + return 0LLL; +} \ No newline at end of file diff --git a/chapter12/invalid_parse/bad_specifiers.c b/chapter12/invalid_parse/bad_specifiers.c new file mode 100644 index 00000000..755b57d5 --- /dev/null +++ b/chapter12/invalid_parse/bad_specifiers.c @@ -0,0 +1,5 @@ +int main() { + /* Cannot declare a variable with two "int" specifiers */ + int long int i = 0; + return i; +} \ No newline at end of file diff --git a/chapter12/invalid_parse/empty_cast.c b/chapter12/invalid_parse/empty_cast.c new file mode 100644 index 00000000..3b04b839 --- /dev/null +++ b/chapter12/invalid_parse/empty_cast.c @@ -0,0 +1,4 @@ +int main() { + /* A cast expression must include at least one type specifier */ + return () 0; +} \ No newline at end of file diff --git a/chapter12/invalid_parse/fun_name_long.c b/chapter12/invalid_parse/fun_name_long.c new file mode 100644 index 00000000..b494accb --- /dev/null +++ b/chapter12/invalid_parse/fun_name_long.c @@ -0,0 +1,8 @@ +/* Because long is a keyword, you can't use it as a function name */ +int long() { + return 4; +} + +int main(){ + return long(); +} \ No newline at end of file diff --git a/chapter12/invalid_parse/invalid_cast.c b/chapter12/invalid_parse/invalid_cast.c new file mode 100644 index 00000000..d97cb21e --- /dev/null +++ b/chapter12/invalid_parse/invalid_cast.c @@ -0,0 +1,6 @@ +int main() { + /* A cast expression can only contain type specifiers, + * not storage class specifiers + */ + return (static int) 10; +} \ No newline at end of file diff --git a/chapter12/invalid_parse/invalid_suffix.c b/chapter12/invalid_parse/invalid_suffix.c new file mode 100644 index 00000000..27db37e3 --- /dev/null +++ b/chapter12/invalid_parse/invalid_suffix.c @@ -0,0 +1,4 @@ +int main() { + /* There shouldn't be a space before the 'l' suffix in a long constant */ + return 0 l; +} \ No newline at end of file diff --git a/chapter12/invalid_parse/long_constant_as_var.c b/chapter12/invalid_parse/long_constant_as_var.c new file mode 100644 index 00000000..3c5d7944 --- /dev/null +++ b/chapter12/invalid_parse/long_constant_as_var.c @@ -0,0 +1,5 @@ +int main() { + /* You can't use a long constant where a variable is required */ + int 10l; + return 0; +} \ No newline at end of file diff --git a/chapter12/invalid_parse/missing_cast_parentheses.c b/chapter12/invalid_parse/missing_cast_parentheses.c new file mode 100644 index 00000000..490ce798 --- /dev/null +++ b/chapter12/invalid_parse/missing_cast_parentheses.c @@ -0,0 +1,4 @@ +int main() { + /* The type specifier in a cast expression must be in parentheses */ + return long 0; +} \ No newline at end of file diff --git a/chapter12/invalid_parse/var_name_long.c b/chapter12/invalid_parse/var_name_long.c new file mode 100644 index 00000000..ca032734 --- /dev/null +++ b/chapter12/invalid_parse/var_name_long.c @@ -0,0 +1,5 @@ +int main() { + /* Because long is a keyword, you can't use it as a variable name */ + int long = 5; + return long; +} \ No newline at end of file diff --git a/chapter12/invalid_types/conflicting_function_types.c b/chapter12/invalid_types/conflicting_function_types.c new file mode 100644 index 00000000..03e7b6c7 --- /dev/null +++ b/chapter12/invalid_types/conflicting_function_types.c @@ -0,0 +1,9 @@ +/* It's illegal to declare a function multiple times with different parameter types */ + +int foo(int a); + +int main() { + return 0; +} + +int foo(long a); \ No newline at end of file diff --git a/chapter12/invalid_types/conflicting_global_types.c b/chapter12/invalid_types/conflicting_global_types.c new file mode 100644 index 00000000..ec3d81cf --- /dev/null +++ b/chapter12/invalid_types/conflicting_global_types.c @@ -0,0 +1,10 @@ +int foo = 3; + +/* It's illegal to declare the same variable + * with different types + */ +long foo; + +int main() { + return foo; +} \ No newline at end of file diff --git a/chapter12/invalid_types/conflicting_variable_types.c b/chapter12/invalid_types/conflicting_variable_types.c new file mode 100644 index 00000000..025535ae --- /dev/null +++ b/chapter12/invalid_types/conflicting_variable_types.c @@ -0,0 +1,9 @@ +long a; + +int main() { + /* This declaration refers to the global 'a' variable, + * but has a conflicting type. + */ + extern int a; + return 0; +} \ No newline at end of file diff --git a/chapter12/valid/explicit_casts/sign_extend.c b/chapter12/valid/explicit_casts/sign_extend.c new file mode 100644 index 00000000..c681df3a --- /dev/null +++ b/chapter12/valid/explicit_casts/sign_extend.c @@ -0,0 +1,16 @@ +int main() { + /* Converting a positive or negative int to a long preserves its value */ + + int pos = 10; + long pos_long = (long) pos; + int neg = -10; + long neg_long = (long) neg; + + if (pos_long != 10l) + return 0; + + if (pos_long + neg_long != 0l) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter12/valid/explicit_casts/sign_extend_constant.c b/chapter12/valid/explicit_casts/sign_extend_constant.c new file mode 100644 index 00000000..65496b33 --- /dev/null +++ b/chapter12/valid/explicit_casts/sign_extend_constant.c @@ -0,0 +1,5 @@ +int main() { + /* Make sure we've implemented rewrite rule for movsx correctly */ + long l = (long) 100; + return (l == 100l); +} \ No newline at end of file diff --git a/chapter12/valid/explicit_casts/truncate.c b/chapter12/valid/explicit_casts/truncate.c new file mode 100644 index 00000000..ff66b1e7 --- /dev/null +++ b/chapter12/valid/explicit_casts/truncate.c @@ -0,0 +1,41 @@ +int main() +{ + /* If a long is already in the range of 'int', + * truncation doesn't change its value. + */ + long l = 10l; + int i = (int)l; + if (i != 10) + return 0; + + /* Truncating a negative int also preserves its value */ + l = -10l; + i = (int)l; + if (i != -10) + return 0; + + /* If a long is outside the range of int, + * subtract 2^32 until it's in range + */ + l = 17179869189l; // 2^34 + 5 + i = (int)l; + if (i != 5) + return 0; + + /* If a negative long is outside the range of int, + * add 2^32 until it's in range + */ + l = -17179869179l; // (-2^34) + 5 + i = (int)l; + if (i != 5) + return 0; + + /* truncate negative long constant that can't + * be expressed in 32 bits, to test rewrite rule + */ + i = (int)-17179869179l; + if (i != 5) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/addition_common_type.c b/chapter12/valid/implicit_casts/addition_common_type.c new file mode 100644 index 00000000..64157636 --- /dev/null +++ b/chapter12/valid/implicit_casts/addition_common_type.c @@ -0,0 +1,13 @@ +/* Test that we perform the correct implicit conversions during addition */ + +int main() { + long l = 2147483653; + int i = 10; + /* The common type of i and l is long, so we should + * promote i to a long, then perform addition. + * If we instead converted l to an int, its value would be + * -2147483643, and the result of i + l would be -2147483633 + */ + long l2 = i + l; + return (l2 == 2147483663l); +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/comparison_common_type.c b/chapter12/valid/implicit_casts/comparison_common_type.c new file mode 100644 index 00000000..5c3bd751 --- /dev/null +++ b/chapter12/valid/implicit_casts/comparison_common_type.c @@ -0,0 +1,13 @@ +int main() { + int i = -100; + long l = 4294967296; // 2^32 + + /* Make sure we convert i to a long instead of converting l to an int. + * If we convert l to an int its value will be -2147483648, + * which is smaller than -100. + */ + if (i >= l) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/conditional_common_type.c b/chapter12/valid/implicit_casts/conditional_common_type.c new file mode 100644 index 00000000..5cb7652d --- /dev/null +++ b/chapter12/valid/implicit_casts/conditional_common_type.c @@ -0,0 +1,12 @@ +int main() { + long l = 8589934592l; // 2^33 + int i = 10; + + /* When a conditional expression includes both int and long branches, + * make sure the int type is promoted to a long, rather than the long being + * converted to an int + */ + long result = 1 ? l : i; + + return (result == 8589934592l); +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/convert_function_arguments.c b/chapter12/valid/implicit_casts/convert_function_arguments.c new file mode 100644 index 00000000..cc69456c --- /dev/null +++ b/chapter12/valid/implicit_casts/convert_function_arguments.c @@ -0,0 +1,42 @@ +/* Test that function arguments, including arguments put on the stack, + * are converted to the corresponding parameter type */ + +int foo(long a, int b, long c, int d, long e, int f, long g, int h) { + if (a != -1l) + return 0; + + if (b != 2) + return 0; + + if (c != -4294967296) + return 0; + + if (d != -5) + return 0; + + if (e != -101) + return 0; + + if (f != -123) + return 0; + + if (g != -10) + return 0; + + if (h != 1234) + return 0; + + return 1; +} + +int main() { + int a = -1; + long int b = 4294967298; // 2^32 + 2, becomes 2 when converted to an int + long c = -4294967296; + long d = 21474836475; // 2^34 + 2^32 - 5, becomes -5 when converted to an int + int e = -101; + long f = -123; + int g = -10; + long h = -9223372036854774574; // -2^63 + 1234, becomes 1234 when converted to an int + return foo(a, b, c, d, e, f, g, h); +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/convert_static_initializer.c b/chapter12/valid/implicit_casts/convert_static_initializer.c new file mode 100644 index 00000000..65a7eb91 --- /dev/null +++ b/chapter12/valid/implicit_casts/convert_static_initializer.c @@ -0,0 +1,8 @@ +/* Test that a long static initializer for an int variable + * is truncted to an int + */ +int i = 8589934592l; // 2^33, truncated to 0 + +int main() { + return (i == 0); +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/division_common_type.c b/chapter12/valid/implicit_casts/division_common_type.c new file mode 100644 index 00000000..62b1dc5d --- /dev/null +++ b/chapter12/valid/implicit_casts/division_common_type.c @@ -0,0 +1,18 @@ +/* Test that we perform the correct implicit conversions during division */ + +int main() { + long l = 2147483649l; + int i = 10; + /* The common type of i and l is long. + * Therefore, we should promote i to a long, + * then divide (resulting in 214748364), + * then convert back to an int (which can be done without + * changing the result's value, since 214748364 is within + * the range of int.) + + * If instead we truncated l to an int before performing division, + * the result would be 1 / 10, or 0. + */ + int result = l / i; + return (result == 214748364); +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/extend_return_value.c b/chapter12/valid/implicit_casts/extend_return_value.c new file mode 100644 index 00000000..acc401b7 --- /dev/null +++ b/chapter12/valid/implicit_casts/extend_return_value.c @@ -0,0 +1,12 @@ +/* Test that the value in a 'return' statement is converted to the function's return type. */ + +long return_extended_int() { + int i = -10; + return i; // this sign-extends i to a long, preserving its value +} + +int main() { + long result = return_extended_int(); + + return (result == -10); +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/long_constants.c b/chapter12/valid/implicit_casts/long_constants.c new file mode 100644 index 00000000..a2c79813 --- /dev/null +++ b/chapter12/valid/implicit_casts/long_constants.c @@ -0,0 +1,7 @@ +int main() { + /* if a constant is too large to store as an int, + * it's automatically converted to a long, even if it + * doesn't have an 'l' suffix + */ + return (17179869184 > 100l); // 17179869184 == 2^34 +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/truncate_constant.c b/chapter12/valid/implicit_casts/truncate_constant.c new file mode 100644 index 00000000..5b139a7e --- /dev/null +++ b/chapter12/valid/implicit_casts/truncate_constant.c @@ -0,0 +1,5 @@ +int main() +{ + int i = 4294967298l; + return i; +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/truncate_on_assignment.c b/chapter12/valid/implicit_casts/truncate_on_assignment.c new file mode 100644 index 00000000..818c9704 --- /dev/null +++ b/chapter12/valid/implicit_casts/truncate_on_assignment.c @@ -0,0 +1,6 @@ +int main() { + long l = 17179869184l; // 2**34 + // This long is implicitly converted to an int on assignment + int i = l; + return (i == 0); +} \ No newline at end of file diff --git a/chapter12/valid/implicit_casts/truncate_return_value.c b/chapter12/valid/implicit_casts/truncate_return_value.c new file mode 100644 index 00000000..b3c993be --- /dev/null +++ b/chapter12/valid/implicit_casts/truncate_return_value.c @@ -0,0 +1,16 @@ +/* Test that the value in a 'return' statement is converted to the function's return type. */ + +int return_truncated_long() { + long l = 4294967298; // 2^32 + 2 + return l; // this truncates l to an int with value 2 +} + +int main() { + /* return_truncated_long() returns 2, + * the assignment statement converts this to a long + * but preserves its value. + */ + long result = return_truncated_long(); + + return (result == 2l); +} \ No newline at end of file diff --git a/chapter12/valid/libraries/long_args.c b/chapter12/valid/libraries/long_args.c new file mode 100644 index 00000000..5e8fe8dd --- /dev/null +++ b/chapter12/valid/libraries/long_args.c @@ -0,0 +1,10 @@ +int test_sum(long a, long b, int c, int d, int e, int f, int g, int h, long i) { + /* Make sure the arguments passed in main weren't converted to ints */ + if (a + b < 100l) { + return 0; + } + /* Check an argument that was passed on the stack too */ + if (i < 100l) + return 0; + return 1; +} \ No newline at end of file diff --git a/chapter12/valid/libraries/long_args_client.c b/chapter12/valid/libraries/long_args_client.c new file mode 100644 index 00000000..cdd9ac5a --- /dev/null +++ b/chapter12/valid/libraries/long_args_client.c @@ -0,0 +1,9 @@ +/* This is identical to the test case in tests/chapter12/valid/long_expressions/long_args.c, + * but split across multiple files. + */ + +int test_sum(long a, long b, int c, int d, int e, int f, int g, int h, long i); + +int main() { + return test_sum(34359738368l, 34359738368l, 0, 0, 0, 0, 0, 0, 34359738368l); +} \ No newline at end of file diff --git a/chapter12/valid/libraries/long_global_var.c b/chapter12/valid/libraries/long_global_var.c new file mode 100644 index 00000000..0a363e2a --- /dev/null +++ b/chapter12/valid/libraries/long_global_var.c @@ -0,0 +1,9 @@ +long int l = 8589934592l; // 2^33 + +long return_l() { + return l; +} + +int return_l_as_int() { + return l; +} \ No newline at end of file diff --git a/chapter12/valid/libraries/long_global_var_client.c b/chapter12/valid/libraries/long_global_var_client.c new file mode 100644 index 00000000..0b0fa26b --- /dev/null +++ b/chapter12/valid/libraries/long_global_var_client.c @@ -0,0 +1,30 @@ +/* Make sure we can read and write long integers in other translation units */ + +// the following are defined in long_global_var.c +extern long int l; +long return_l(); +int return_l_as_int(); + + + +int main() { + + /* Make sure l has the right value before we update it */ + if (return_l() != 8589934592l) + return 0; + + if (return_l_as_int() != 0) + return 0; + + /* Update l */ + l = l - 10l; + + /* Read back the value we just assigned to l */ + if (return_l() != 8589934582l) + return 0; + + if (return_l_as_int() != -10) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter12/valid/libraries/maintain_stack_alignment.c b/chapter12/valid/libraries/maintain_stack_alignment.c new file mode 100644 index 00000000..bb22f886 --- /dev/null +++ b/chapter12/valid/libraries/maintain_stack_alignment.c @@ -0,0 +1,3 @@ +long add_variables(long x, long y, int z){ + return x + y + z; +} \ No newline at end of file diff --git a/chapter12/valid/libraries/maintain_stack_alignment_client.c b/chapter12/valid/libraries/maintain_stack_alignment_client.c new file mode 100644 index 00000000..d26233cf --- /dev/null +++ b/chapter12/valid/libraries/maintain_stack_alignment_client.c @@ -0,0 +1,12 @@ +long add_variables(long x, long y, int z); + +int main() { + /* Allocate several stack variables of different sizes; + * in our implementation, this will allocate 20 bytes on the stack */ + long x = 3; + long y = 4; + int z = 5; + + /* Test that we can make function calls (i.e. that stack is aligned correctly) */ + return add_variables(x, y, z); +} \ No newline at end of file diff --git a/chapter12/valid/libraries/return_long.c b/chapter12/valid/libraries/return_long.c new file mode 100644 index 00000000..a5433838 --- /dev/null +++ b/chapter12/valid/libraries/return_long.c @@ -0,0 +1,3 @@ +long add(int a, int b) { + return (long) a + (long) b; +} \ No newline at end of file diff --git a/chapter12/valid/libraries/return_long_client.c b/chapter12/valid/libraries/return_long_client.c new file mode 100644 index 00000000..869d40ce --- /dev/null +++ b/chapter12/valid/libraries/return_long_client.c @@ -0,0 +1,14 @@ +/* This is identical to the test case in tests/chapter12/valid/long_expressions/return_long.c, + * but split across multiple files. + */ + +long add(int a, int b); + +int main() { + long a = add(2147483645, 2147483645); + /* Test returning a long from a function call */ + if (a == 4294967290l) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/add.c b/chapter12/valid/long_expressions/add.c new file mode 100644 index 00000000..eb990637 --- /dev/null +++ b/chapter12/valid/long_expressions/add.c @@ -0,0 +1,11 @@ +int main() { + long a = 4294967290l; + long b = 5l; + /* Adding two longs should produce the correct result, + * even when that result is too large for an int to represent + */ + if (a + b == 4294967295l) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/assign.c b/chapter12/valid/long_expressions/assign.c new file mode 100644 index 00000000..67946348 --- /dev/null +++ b/chapter12/valid/long_expressions/assign.c @@ -0,0 +1,10 @@ +int main() { + long a = 4294967290l; + long b = 0l; + /* Assign the value of one long variable + * (which is too large for an int to represent) + * to another long variable + */ + b = a; + return (b == 4294967290l); +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/compare.c b/chapter12/valid/long_expressions/compare.c new file mode 100644 index 00000000..7a34744c --- /dev/null +++ b/chapter12/valid/long_expressions/compare.c @@ -0,0 +1,10 @@ +int main() { + /* Comparing two longs should produce the correct result. + * Note that if we considered only the lower 32 bits of + * each number (or cast them to ints), 255 would be larger + */ + if (8589934593l < 255l) { + return 0; + } + return 1; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/div.c b/chapter12/valid/long_expressions/div.c new file mode 100644 index 00000000..b7b4ccc5 --- /dev/null +++ b/chapter12/valid/long_expressions/div.c @@ -0,0 +1,12 @@ +int main() { + long a = 4294967290l; + long b = a / 128l; + /* Make sure division works correctly even when the first operand + * can't fit in an int; this requires us to store the operand in RDX:RAX + * using the 'cqo' instruction, instead of in EDX:EAX using 'cdq' + */ + if (b == 33554431l) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/large_constants.c b/chapter12/valid/long_expressions/large_constants.c new file mode 100644 index 00000000..228ddee5 --- /dev/null +++ b/chapter12/valid/long_expressions/large_constants.c @@ -0,0 +1,25 @@ +/* Make sure we can handle adding, subtracting, + * and multiplying by constants that are outside + * the range of int; this tests our assembly rewrite rules. + */ + +int main() { + long x = 5l; + + /* Add a large constant to a variable */ + x = x + 4294967290l; + if (x != 4294967295l) + return 0; + + /* Subtract a large constant from a variable */ + x = x - 4294967290l; + if (x != 5l) + return 0; + + /* Multiply a variable by a large constant */ + x = x * 4294967290l; + if (x != 21474836450l) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/long_and_int_locals.c b/chapter12/valid/long_expressions/long_and_int_locals.c new file mode 100644 index 00000000..7f515a66 --- /dev/null +++ b/chapter12/valid/long_expressions/long_and_int_locals.c @@ -0,0 +1,26 @@ +int main() { + /* Initialize and then update a mix of long and int variables, + * to check that we allocate enough stack space for each of them, + * and writing to one doesn't clobber another */ + + long a = 8589934592l; // this number is outside the range of int + int b = -1; + long c = -8589934592l; // also outside the range of int + int d = 10; + + /* Make sure every variable has the right value */ + if (a != 8589934592l || b != -1 || c != -8589934592l || d != 10) + return 0; + + /* update every variable */ + a = -a; + b = b - 1; + c = c + 8589934594l; + d = d + 10; + + /* Make sure the updated values are correct */ + if (a != -8589934592l || b != -2 || c != 2 || d != 20) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/long_args.c b/chapter12/valid/long_expressions/long_args.c new file mode 100644 index 00000000..864963f6 --- /dev/null +++ b/chapter12/valid/long_expressions/long_args.c @@ -0,0 +1,14 @@ +int test_sum(long a, long b, int c, int d, int e, int f, int g, int h, long i) { + /* Make sure the arguments passed in main weren't converted to ints */ + if (a + b < 100l) { + return 0; + } + /* Check an argument that was passed on the stack too */ + if (i < 100l) + return 0; + return 1; +} + +int main() { + return test_sum(34359738368l, 34359738368l, 0, 0, 0, 0, 0, 0, 34359738368l); +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/mod.c b/chapter12/valid/long_expressions/mod.c new file mode 100644 index 00000000..ee96ad2a --- /dev/null +++ b/chapter12/valid/long_expressions/mod.c @@ -0,0 +1,11 @@ +int main() { + long a = 8589934585l; + long b = -a % 4294967290l; + /* Make sure mod operator works correctly when both operators + * are too large to represent as ints + */ + if (b == -5l) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/mult.c b/chapter12/valid/long_expressions/mult.c new file mode 100644 index 00000000..03a4cc45 --- /dev/null +++ b/chapter12/valid/long_expressions/mult.c @@ -0,0 +1,10 @@ +int main() { + long int a = 4294967290l; + /* Multiplying two longs should produce the correct result, + * even when that result is too large for an int to represent + */ + if (a * 4l == 17179869160l) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/multi_op.c b/chapter12/valid/long_expressions/multi_op.c new file mode 100644 index 00000000..5a773189 --- /dev/null +++ b/chapter12/valid/long_expressions/multi_op.c @@ -0,0 +1,15 @@ +int main() { + + long a = 4294967290l; + + /* This expression produces an intermediate result that cannot + * fit in an int, in order to test that we track the sizes + * of intermediate results and allocate enough stack + * space for them. + */ + long b = a * 5l - 10l; + if (b == 21474836440l) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/return_long.c b/chapter12/valid/long_expressions/return_long.c new file mode 100644 index 00000000..537e0560 --- /dev/null +++ b/chapter12/valid/long_expressions/return_long.c @@ -0,0 +1,12 @@ +long add(int a, int b) { + return (long) a + (long) b; +} + +int main() { + long a = add(2147483645, 2147483645); + /* Test returning a long from a function call */ + if (a == 4294967290l) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/static_long.c b/chapter12/valid/long_expressions/static_long.c new file mode 100644 index 00000000..15b05b86 --- /dev/null +++ b/chapter12/valid/long_expressions/static_long.c @@ -0,0 +1,14 @@ +/* Test initializing and updating a long global variable */ +static long foo = 4294967290l; + +int main() +{ + if (foo + 5l == 4294967295l) + { + // assign a constant that can't fit in 32 bits; tests assembly rewrite rule + foo = 1152921504606846988l; + if (foo == 1152921504606846988l) + return 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/sub.c b/chapter12/valid/long_expressions/sub.c new file mode 100644 index 00000000..d6ac8c2f --- /dev/null +++ b/chapter12/valid/long_expressions/sub.c @@ -0,0 +1,9 @@ +int main() { + long a = -4294967290l; + long b = 90l; + /* Subtracting two longs should produce the correct result */ + if (a - b == -4294967380l) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter12/valid/long_expressions/type_specifiers.c b/chapter12/valid/long_expressions/type_specifiers.c new file mode 100644 index 00000000..95b4a17c --- /dev/null +++ b/chapter12/valid/long_expressions/type_specifiers.c @@ -0,0 +1,32 @@ +/* These declarations all look slightly different, + * but they all declare 'a' as a static long, so they don't conflict. + */ +static int long a; +int static long a; +long static a; + +/* These declarations all look slightly different, + * but they all declare 'my_function' as a function + * with three long parameters and an int return value, + * so they don't conflict. + */ +int my_function(long a, long int b, int long c); +int my_function(long int x, int long y, long z) { + return x + y + z; +} + +int main() { + /* Several different ways to declare local long variables */ + long x = 1l; + long int y = 2l; + int long z = 3l; + + /* This links to the file-scope declarations of 'a' above */ + extern long a; + a = 4; + + /* Make sure everything has the expected value */ + return (x == 1 && y == 2 && z == 3 + && a == 4 + && my_function(x, y, z) == 6); +} \ No newline at end of file diff --git a/chapter12/valid_extra_credit/bitwise_long_op.c b/chapter12/valid_extra_credit/bitwise_long_op.c new file mode 100644 index 00000000..ff2d4bf2 --- /dev/null +++ b/chapter12/valid_extra_credit/bitwise_long_op.c @@ -0,0 +1,34 @@ +int main() { + /* A long integer where the upper 32 bits are 0 and lower 32 bits are 1 */ + long lower_32_bits_set = 4294967295; // 2^32 - 1 + + /* A long integer where upper 32 bits are 1 and lower 32 bits are 0 */ + long upper_32_bits_set = -1 - lower_32_bits_set; + + /* Casting a long to an int and back is equivalent to either: + * - setting all upper bits to 1, if bit 32 is 1 (meaning the truncated int is negative) + * or, + * - setting all uppers bits to 0, if bit 32 is 0 (meaning the truncated int is positive) + * Additionally, i & -1 == i for any signed integer i, whether i is a long or an int. + * The loop below validates that these properties holds for a sample of + * roughly 100,000,000 longs. + */ + for (long l = 17179869184; l > 2147483648; l = l - 150) { + + int i = (int) l; + if (i >= 0) { + /* use bitwise "and" to zero out upper bits */ + if ((l & lower_32_bits_set) != i) + return 0; + } else { + /* use bitwise "or" to set upper bits */ + if ((l | upper_32_bits_set) != i) + return 0; + } + + /* every bit is set in -1, so l & -1 == l */ + if ((l & -1) != l) + return 0; + } + return 1; +} \ No newline at end of file diff --git a/chapter12/valid_extra_credit/compound_assign_to_int.c b/chapter12/valid_extra_credit/compound_assign_to_int.c new file mode 100644 index 00000000..884afb2a --- /dev/null +++ b/chapter12/valid_extra_credit/compound_assign_to_int.c @@ -0,0 +1,11 @@ +int main() { + int i = -20; + /* This statement is evaluated as follows: + * 1. sign-extend i to a long with value -20 + * 2. add this long to 2147483648, resulting in the long 2147483628, + * 3. convert this to an int with value 2147483628 (this value + * can be represented as an int) + */ + i += 2147483648l; + return (i == 2147483628); +} \ No newline at end of file diff --git a/chapter12/valid_extra_credit/compound_assign_to_long.c b/chapter12/valid_extra_credit/compound_assign_to_long.c new file mode 100644 index 00000000..419cd954 --- /dev/null +++ b/chapter12/valid_extra_credit/compound_assign_to_long.c @@ -0,0 +1,7 @@ +int main() { + long l = -1; + int i = -10; + /* We should convert i to a long, then add it to l */ + l += i; + return (l == -11); +} \ No newline at end of file diff --git a/chapter12/valid_extra_credit/switch_int.c b/chapter12/valid_extra_credit/switch_int.c new file mode 100644 index 00000000..f9ebeb32 --- /dev/null +++ b/chapter12/valid_extra_credit/switch_int.c @@ -0,0 +1,37 @@ +/* When an int is used the controlling expression of a switch statement, + * the constant in each case statement should be converted to an int. + */ + +int switch_on_int(int i) { + switch(i) { + case 5: + return 0; + // this is 2^33; it will be truncated to int 0 + case 8589934592l: // case 0: + return 1; + // this is 2^35 - 1; it will be truncated to -1 + case 34359738367: // case -1: + return 2; + default: + return 3; + } +} + +int main() { + /* Call switch_on_int once for each case, validate + * that we get the expected result + */ + if (switch_on_int(5) != 0) + return 0; + if (switch_on_int(0) != 1) + return 0; + if (switch_on_int(-1) != 2) + return 0; + /* 17179869184 is 2^34; it will be truncated to 0 + * when passed as a parameter to switch_on_int + */ + if (switch_on_int(17179869184) != 1) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter12/valid_extra_credit/switch_long.c b/chapter12/valid_extra_credit/switch_long.c new file mode 100644 index 00000000..c38ea29c --- /dev/null +++ b/chapter12/valid_extra_credit/switch_long.c @@ -0,0 +1,22 @@ +/* When a long is used in the controlling condition of a switch statement, + * the constant in each case statement should be converted to a long + */ + +int switch_on_long(long l) { + switch (l) { + case 0: return 0; + case 100: return 1; + case 8589934592l: // 2^33 + return 2; + default: + return -1; + } +} + +int main() { + if (switch_on_long(8589934592) != 2) + return 0; + if (switch_on_long(100) != 1) + return 0; + return 1; +} \ No newline at end of file From 2e5b66329eb4343c5dc9f50b5b5c6fabf9f6ea1c Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Mon, 6 Mar 2023 10:52:01 -0800 Subject: [PATCH 003/167] chapter 13 tests --- .../switch_duplicate_cases.c | 11 ++++ chapter13/invalid_lex/invalid_suffix.c | 4 ++ chapter13/invalid_lex/invalid_suffix_2.c | 4 ++ chapter13/invalid_parse/bad_specifiers.c | 5 ++ chapter13/invalid_parse/bad_specifiers_2.c | 5 ++ .../conflicting_signed_unsigned.c | 9 +++ .../invalid_types/conflicting_uint_ulong.c | 9 +++ .../valid/explicit_casts/chained_casts.c | 25 +++++++++ .../valid/explicit_casts/round_trip_casts.c | 23 ++++++++ .../explicit_casts/same_size_conversion.c | 32 +++++++++++ .../explicit_casts/truncate_long_to_uints.c | 21 +++++++ .../valid/explicit_casts/truncate_ulong.c | 35 ++++++++++++ .../valid/explicit_casts/widen_signed_int.c | 25 +++++++++ chapter13/valid/explicit_casts/widen_uint.c | 15 +++++ .../explicit_casts/zero_extend_literal.c | 8 +++ chapter13/valid/implicit_casts/int_and_uint.c | 13 +++++ .../valid/implicit_casts/int_and_ulong.c | 17 ++++++ .../valid/implicit_casts/promote_constants.c | 20 +++++++ .../implicit_casts/static_initializers.c | 56 +++++++++++++++++++ chapter13/valid/implicit_casts/ternary.c | 22 ++++++++ .../valid/implicit_casts/uint_and_long.c | 15 +++++ .../valid/implicit_casts/uint_and_ulong.c | 14 +++++ chapter13/valid/libraries/unsigned_args.c | 7 +++ .../valid/libraries/unsigned_args_client.c | 7 +++ .../valid/libraries/unsigned_global_var.c | 13 +++++ .../libraries/unsigned_global_var_client.c | 32 +++++++++++ .../signed_int_type_specifiers.c | 10 ++++ .../signed_long_type_specifiers.c | 11 ++++ .../unsigned_int_type_specifiers.c | 10 ++++ .../unsigned_long_type_specifiers.c | 15 +++++ .../valid/unsigned_expressions/add_literal.c | 10 ++++ .../addition_wraparound.c | 10 ++++ .../comparison_set_upper_bit.c | 30 ++++++++++ .../comparison_unset_upper_bit.c | 30 ++++++++++ .../unsigned_expressions/divide_by_literal.c | 5 ++ .../divide_large_dividend.c | 11 ++++ .../valid/unsigned_expressions/division.c | 14 +++++ chapter13/valid/unsigned_expressions/mod.c | 5 ++ chapter13/valid/unsigned_expressions/neg.c | 10 ++++ .../unsigned_expressions/static_variables.c | 18 ++++++ .../subtraction_wraparound.c | 11 ++++ .../valid_extra_credit/bitwise_unsigned_ops.c | 42 ++++++++++++++ .../bitwise_unsigned_shift.c | 10 ++++ .../valid_extra_credit/compound_assign_uint.c | 10 ++++ chapter13/valid_extra_credit/switch_uint.c | 27 +++++++++ 45 files changed, 736 insertions(+) create mode 100644 chapter13/invalid_labels_extra_credit/switch_duplicate_cases.c create mode 100644 chapter13/invalid_lex/invalid_suffix.c create mode 100644 chapter13/invalid_lex/invalid_suffix_2.c create mode 100644 chapter13/invalid_parse/bad_specifiers.c create mode 100644 chapter13/invalid_parse/bad_specifiers_2.c create mode 100644 chapter13/invalid_types/conflicting_signed_unsigned.c create mode 100644 chapter13/invalid_types/conflicting_uint_ulong.c create mode 100644 chapter13/valid/explicit_casts/chained_casts.c create mode 100644 chapter13/valid/explicit_casts/round_trip_casts.c create mode 100644 chapter13/valid/explicit_casts/same_size_conversion.c create mode 100644 chapter13/valid/explicit_casts/truncate_long_to_uints.c create mode 100644 chapter13/valid/explicit_casts/truncate_ulong.c create mode 100644 chapter13/valid/explicit_casts/widen_signed_int.c create mode 100644 chapter13/valid/explicit_casts/widen_uint.c create mode 100644 chapter13/valid/explicit_casts/zero_extend_literal.c create mode 100644 chapter13/valid/implicit_casts/int_and_uint.c create mode 100644 chapter13/valid/implicit_casts/int_and_ulong.c create mode 100644 chapter13/valid/implicit_casts/promote_constants.c create mode 100644 chapter13/valid/implicit_casts/static_initializers.c create mode 100644 chapter13/valid/implicit_casts/ternary.c create mode 100644 chapter13/valid/implicit_casts/uint_and_long.c create mode 100644 chapter13/valid/implicit_casts/uint_and_ulong.c create mode 100644 chapter13/valid/libraries/unsigned_args.c create mode 100644 chapter13/valid/libraries/unsigned_args_client.c create mode 100644 chapter13/valid/libraries/unsigned_global_var.c create mode 100644 chapter13/valid/libraries/unsigned_global_var_client.c create mode 100644 chapter13/valid/type_specifiers/signed_int_type_specifiers.c create mode 100644 chapter13/valid/type_specifiers/signed_long_type_specifiers.c create mode 100644 chapter13/valid/type_specifiers/unsigned_int_type_specifiers.c create mode 100644 chapter13/valid/type_specifiers/unsigned_long_type_specifiers.c create mode 100644 chapter13/valid/unsigned_expressions/add_literal.c create mode 100644 chapter13/valid/unsigned_expressions/addition_wraparound.c create mode 100644 chapter13/valid/unsigned_expressions/comparison_set_upper_bit.c create mode 100644 chapter13/valid/unsigned_expressions/comparison_unset_upper_bit.c create mode 100644 chapter13/valid/unsigned_expressions/divide_by_literal.c create mode 100644 chapter13/valid/unsigned_expressions/divide_large_dividend.c create mode 100644 chapter13/valid/unsigned_expressions/division.c create mode 100644 chapter13/valid/unsigned_expressions/mod.c create mode 100644 chapter13/valid/unsigned_expressions/neg.c create mode 100644 chapter13/valid/unsigned_expressions/static_variables.c create mode 100644 chapter13/valid/unsigned_expressions/subtraction_wraparound.c create mode 100644 chapter13/valid_extra_credit/bitwise_unsigned_ops.c create mode 100644 chapter13/valid_extra_credit/bitwise_unsigned_shift.c create mode 100644 chapter13/valid_extra_credit/compound_assign_uint.c create mode 100644 chapter13/valid_extra_credit/switch_uint.c diff --git a/chapter13/invalid_labels_extra_credit/switch_duplicate_cases.c b/chapter13/invalid_labels_extra_credit/switch_duplicate_cases.c new file mode 100644 index 00000000..c634a540 --- /dev/null +++ b/chapter13/invalid_labels_extra_credit/switch_duplicate_cases.c @@ -0,0 +1,11 @@ +int main() { + unsigned int ui = 10u; + + switch(ui) { + case 4294967295u: // 2^32 - 1 + return 0; + case -1l: // this will be converted to 2^32 - 1 + return 1; + default: return 2; + } +} \ No newline at end of file diff --git a/chapter13/invalid_lex/invalid_suffix.c b/chapter13/invalid_lex/invalid_suffix.c new file mode 100644 index 00000000..89e60505 --- /dev/null +++ b/chapter13/invalid_lex/invalid_suffix.c @@ -0,0 +1,4 @@ +int main() { + /* An unsigned constant suffix should only have one 'u' */ + return 0uu; +} \ No newline at end of file diff --git a/chapter13/invalid_lex/invalid_suffix_2.c b/chapter13/invalid_lex/invalid_suffix_2.c new file mode 100644 index 00000000..78d9c161 --- /dev/null +++ b/chapter13/invalid_lex/invalid_suffix_2.c @@ -0,0 +1,4 @@ +int main() { + /* lul is not a valid suffix for integer constants */ + return 0lul; +} \ No newline at end of file diff --git a/chapter13/invalid_parse/bad_specifiers.c b/chapter13/invalid_parse/bad_specifiers.c new file mode 100644 index 00000000..e3541f73 --- /dev/null +++ b/chapter13/invalid_parse/bad_specifiers.c @@ -0,0 +1,5 @@ +int main() { + /* Can't combine signed and unsigned specifiers */ + int i = 0; + return (signed unsigned) i; +} \ No newline at end of file diff --git a/chapter13/invalid_parse/bad_specifiers_2.c b/chapter13/invalid_parse/bad_specifiers_2.c new file mode 100644 index 00000000..c084efde --- /dev/null +++ b/chapter13/invalid_parse/bad_specifiers_2.c @@ -0,0 +1,5 @@ +int main() { + /* Can't include the same specifier twice */ + unsigned long unsigned i = 0; + return 0; +} \ No newline at end of file diff --git a/chapter13/invalid_types/conflicting_signed_unsigned.c b/chapter13/invalid_types/conflicting_signed_unsigned.c new file mode 100644 index 00000000..754a699a --- /dev/null +++ b/chapter13/invalid_types/conflicting_signed_unsigned.c @@ -0,0 +1,9 @@ +/* Cannot declare x as both signed int and unsigned int */ + +unsigned x; + +int x; + +int main() { + return 0; +} \ No newline at end of file diff --git a/chapter13/invalid_types/conflicting_uint_ulong.c b/chapter13/invalid_types/conflicting_uint_ulong.c new file mode 100644 index 00000000..e1221a89 --- /dev/null +++ b/chapter13/invalid_types/conflicting_uint_ulong.c @@ -0,0 +1,9 @@ +unsigned int foo(); + +unsigned long foo() { + return 0; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/chapter13/valid/explicit_casts/chained_casts.c b/chapter13/valid/explicit_casts/chained_casts.c new file mode 100644 index 00000000..52fc11dd --- /dev/null +++ b/chapter13/valid/explicit_casts/chained_casts.c @@ -0,0 +1,25 @@ +/* The order in which multiple casts are applied matters */ + +int main() { + + unsigned int ui = 4294967200u; + + /* In this case we + * 1. convert ui to a signed int by computing 2^32 - ui, producing -96 + * 2. signed-extend the result, which preserves the value of -96 + * Note that if we cast ui directly to a signed long, its value wouldn't change + */ + if ((long) (signed) ui != -96l) + return 0; + + /* In this case we + * 1. convert ui to a signed int by computing 2^32 - ui, producing -96 + * 2. convert this signed int to an unsigned long by computing -96 + 2^64 + * Note that if we converted ui directly to an unsigned long, its value + * wouldn't change + */ + if ((unsigned long) (signed) ui != 18446744073709551520ul) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter13/valid/explicit_casts/round_trip_casts.c b/chapter13/valid/explicit_casts/round_trip_casts.c new file mode 100644 index 00000000..f0199984 --- /dev/null +++ b/chapter13/valid/explicit_casts/round_trip_casts.c @@ -0,0 +1,23 @@ +/* Converting a value to a different type, then back to the original type, + * does not always recover its original value + */ +int main() { + unsigned long a = 8589934580ul; // 2^33 - 12 + + /* casting to unsigned int and back reduces is equivalent to subtracting + * 2^32, resulting in 4294967284 + */ + a = (unsigned long) (unsigned int) a; + + if (a != 4294967284ul) + return 0; + + /* Casting to a signed int and back results in 2^64 - 12, + * or 18446744073709551604 + */ + a = (unsigned long) (signed int) a; + if (a != 18446744073709551604ul) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter13/valid/explicit_casts/same_size_conversion.c b/chapter13/valid/explicit_casts/same_size_conversion.c new file mode 100644 index 00000000..6708b3eb --- /dev/null +++ b/chapter13/valid/explicit_casts/same_size_conversion.c @@ -0,0 +1,32 @@ +/* Test conversions between signed and unsigned types of the same size */ + +int main() { + int x = 10; + unsigned int y = (unsigned) x; + + /* Converting a positive signed int to an unsigned int preserves its value */ + if (y != 10u) + return 0; + + /* If an unsigned int is within the range of signed int, + * converting it to a signed int preserves its value + */ + if ((signed) y != 10) + return 0; + + /* Converting a negative signed long -x to an unsigned long + * results in 2^64 - x + */ + long a = -1000; + unsigned long b = (unsigned long) a; + if (b != 18446744073709550616ul) + return 0; + + /* If an unsigned long is too large for a long to represent, + * reduce it modulo 2^64 until it's in range. + */ + if ((long) b != -1000) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter13/valid/explicit_casts/truncate_long_to_uints.c b/chapter13/valid/explicit_casts/truncate_long_to_uints.c new file mode 100644 index 00000000..aaf4e2da --- /dev/null +++ b/chapter13/valid/explicit_casts/truncate_long_to_uints.c @@ -0,0 +1,21 @@ +/* Truncate from signed long to unsigned int */ + +int main() { + + /* 100 is in the range of unsigned int, + * so truncating it to an unsigned int + * will preserve its value + */ + long l = 100l; + if ((unsigned) l != 100u) + return 0; + + /* -9223372036854774574 is outside the range of unsigned int, + * so add 2^32 to bring it within range */ + l = -9223372036854774574l; // -2^63 + 1234 + if ((unsigned) l != 1234) + return 0; + + + return 1; +} \ No newline at end of file diff --git a/chapter13/valid/explicit_casts/truncate_ulong.c b/chapter13/valid/explicit_casts/truncate_ulong.c new file mode 100644 index 00000000..8c6bb948 --- /dev/null +++ b/chapter13/valid/explicit_casts/truncate_ulong.c @@ -0,0 +1,35 @@ +/* Truncate unsigned long to int or unsigned int */ + +int main() { + /* 100 can be cast to an int or unsigned int without changing its value */ + unsigned long ul = 100ul; + + if ((int) ul != 100) + return 0; + + if (100u != (unsigned) ul) + return 0; + + /* 4294967200 can be cast to an unsigned int without changing its value, + * but must be reduced modulo 2^32 to cast to a signed int + */ + + ul = 4294967200ul; + if ((unsigned) ul != 4294967200u) + return 0; + + if (-96 != (signed) ul) + return 0; + + /* 1152921506754330624 (2^60 + 2^31) must be reduced modulo 2^32 + * to represent as a signed or unsigned int + */ + ul = 1152921506754330624ul; + if (2147483648u != (unsigned) ul) // reduce to 2^31 + return 0; + + if ((signed) ul != -2147483648) // reduce to -2^31 + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter13/valid/explicit_casts/widen_signed_int.c b/chapter13/valid/explicit_casts/widen_signed_int.c new file mode 100644 index 00000000..ccfcddce --- /dev/null +++ b/chapter13/valid/explicit_casts/widen_signed_int.c @@ -0,0 +1,25 @@ +/* Test sign-extending a signed int to a long or unsigned long */ + +int main() { + int i = 10; + /* Converting a positive int to a signed long preserves its value */ + if ((signed long) i != 10l) + return 0; + + /* Converting a positive int to an unsigned long preserves its value */ + if ((unsigned long) i != 10ul) + return 0; + + /* Converting a negative int to a signed long preserves its value */ + i = -10; + if ((signed long) i != -10l) + return 0; + + /* When you convert a negative int to an unsigned long, + * add 2^64 until it's positive + */ + if ((unsigned long) i != 18446744073709551606ul) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter13/valid/explicit_casts/widen_uint.c b/chapter13/valid/explicit_casts/widen_uint.c new file mode 100644 index 00000000..4c772f21 --- /dev/null +++ b/chapter13/valid/explicit_casts/widen_uint.c @@ -0,0 +1,15 @@ +/* Test zero-extending a uint to a long or ulong */ + +int main() { + unsigned int ui = 4294967200u; + + /* Extending an unsigned int to a signed long preserves its value */ + if ((signed long) ui != 4294967200l) + return 0; + + /* Extending an unsigned int to an unsigned long preserves its value */ + if ((unsigned long) ui != 4294967200ul) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter13/valid/explicit_casts/zero_extend_literal.c b/chapter13/valid/explicit_casts/zero_extend_literal.c new file mode 100644 index 00000000..1e83bee1 --- /dev/null +++ b/chapter13/valid/explicit_casts/zero_extend_literal.c @@ -0,0 +1,8 @@ +int main() { + /* Zero-extend 4294967200 + * from an unsigned int to an unsigned long + * to test the assembly rewrite rule for MovZeroExtend + */ + unsigned long x = (unsigned long) 4294967200u; + return (x == 4294967200ul); +} \ No newline at end of file diff --git a/chapter13/valid/implicit_casts/int_and_uint.c b/chapter13/valid/implicit_casts/int_and_uint.c new file mode 100644 index 00000000..836a2240 --- /dev/null +++ b/chapter13/valid/implicit_casts/int_and_uint.c @@ -0,0 +1,13 @@ +/* When performing an operation on two types + * of the same rank, convert the signed value + * to the type of the unsigned value + */ + +int main() { + unsigned int ui = 100u; + + // this will be converted to 2^32 - 100 + signed int i = -100; + + return (i > ui); +} \ No newline at end of file diff --git a/chapter13/valid/implicit_casts/int_and_ulong.c b/chapter13/valid/implicit_casts/int_and_ulong.c new file mode 100644 index 00000000..a8446eff --- /dev/null +++ b/chapter13/valid/implicit_casts/int_and_ulong.c @@ -0,0 +1,17 @@ +/* When performing an operation on two different types, + * where the unsigned type is an equal or higher rank, + * convert the signed value to the unsigned type + */ + +int main() { + /* This value is 2^64 - 10, + * which is too large to represent as an unsigned int + * or signed long + */ + unsigned long ul = 18446744073709551606ul; + + // this will be converted to 2^64 - 1 + int i = -1; + + return (i > ul); +} \ No newline at end of file diff --git a/chapter13/valid/implicit_casts/promote_constants.c b/chapter13/valid/implicit_casts/promote_constants.c new file mode 100644 index 00000000..cc56a3d7 --- /dev/null +++ b/chapter13/valid/implicit_casts/promote_constants.c @@ -0,0 +1,20 @@ +int main() { + /* -1u evaluates to UINT_MAX; -1ul evaluates to ULONG_MAX */ + if (-1u >= -1ul) + return 0; + + + /* 2^36 can't be represented as an unsigned int, + * so it will be promoted to an unsigned long; + * when we compare this to -1l, we'll convert -1l to + * an usigned long with value ULONG_MAX + */ + if (68719476736u >= -1l) + return 0; + + /* The same constant without the u suffix + * is promoted to a signed long, which is greater + * than the signed long -1 + */ + return (68719476736 > -1l); +} \ No newline at end of file diff --git a/chapter13/valid/implicit_casts/static_initializers.c b/chapter13/valid/implicit_casts/static_initializers.c new file mode 100644 index 00000000..280bd40c --- /dev/null +++ b/chapter13/valid/implicit_casts/static_initializers.c @@ -0,0 +1,56 @@ +/* Make sure static initializers are set to the correct + * implicitly-converted value at program startup + */ + +// this is 2^60 + 2^31 + 12 +// should be truncated to 2^31 + 12 (which is 2147483660) +unsigned int u = 1152921506754330636l; + +/* This should be initialized to -2147483646, + * or 2147483650 - 2^32 + */ +int i = 2147483650u; + +/* This should be initialized to -9223372036854775716, + * or 9223372036854775900 - 2^64 + */ +long l = 9223372036854775900u; // note: this has type unsigned long + +// this can be converted to a long with no change in value +long l2 = 2147483650u; + +// any unsigned int can be converted to an unsigned long w/ no change in value +unsigned long ul = 4294967294u; + +/* any signed long _literal_ can be converted to an unsigned long w/ no change in value + * (we don't support negation expressions in constant initializers) */ +unsigned long ul2 = 9223372036854775798l; + +// truncate ulong 2**63 + 2**31 + 150 +// to int -2**31 + 150 (which is -2147483498) +int i2 = 9223372039002259606ul; + +// truncate ulong 2**63 + 2**31 + 150 +// to uint 2**31 + 150 (which is 2147483798) +unsigned ui2 = 9223372039002259606ul; + +int main() +{ + if (u != 2147483660u) + return 0; + if (i != -2147483646) + return 0; + if (l != -9223372036854775716l) + return 0; + if (l2 != 2147483650l) + return 0; + if (ul != 4294967294ul) + return 0; + if (i2 != -2147483498) + return 0; + if (ul2 != 9223372036854775798ul) + return 0; + if (ui2 != 2147483798u) + return 0; + return 1; +} \ No newline at end of file diff --git a/chapter13/valid/implicit_casts/ternary.c b/chapter13/valid/implicit_casts/ternary.c new file mode 100644 index 00000000..f0146996 --- /dev/null +++ b/chapter13/valid/implicit_casts/ternary.c @@ -0,0 +1,22 @@ +/* When we evaluate a ternary operation, + * convert the result to the common type of both branches + */ + +int main() { + unsigned long cond = 100u; + + int i = -1; + unsigned int ui = 10u; + + /* The common type of i and ui is unsigned int + * (we don't consider the type of cond when we + * determine the common type). + * We therefore convert i to an unsigned int, 2^32 - 1, + * which we then convert o a signed long. + * Therefore, result will be positive. If we didn't + * convert i to an unsigned int, result would be negative. + */ + long result = cond ? i : ui; + + return (result > 0); +} \ No newline at end of file diff --git a/chapter13/valid/implicit_casts/uint_and_long.c b/chapter13/valid/implicit_casts/uint_and_long.c new file mode 100644 index 00000000..f6166ee3 --- /dev/null +++ b/chapter13/valid/implicit_casts/uint_and_long.c @@ -0,0 +1,15 @@ +/* When performing an operation on an unsigned type, + * and a signed type that can represent every value of the + * unsigned type, convert the unsigned value to the signed type + */ + +int main() { + /* This will be converted to a long + * with value 100 + */ + unsigned int ui = 100u; + + signed long l = -100; + + return (ui > l); +} \ No newline at end of file diff --git a/chapter13/valid/implicit_casts/uint_and_ulong.c b/chapter13/valid/implicit_casts/uint_and_ulong.c new file mode 100644 index 00000000..395375d6 --- /dev/null +++ b/chapter13/valid/implicit_casts/uint_and_ulong.c @@ -0,0 +1,14 @@ +int main() { + /* when performing an arithmetic operation or comparison + * on an unsigned int and an unsigned long, promote + * the unsigned int to an unsigned long first + */ + + // 2^35 - if you converted this to an unsigned long + // its value would be 0 + unsigned long ul = 34359738368u; + + unsigned int ui = 1073741824u; // 2^30 + + return (ul > ui); +} \ No newline at end of file diff --git a/chapter13/valid/libraries/unsigned_args.c b/chapter13/valid/libraries/unsigned_args.c new file mode 100644 index 00000000..4441ec64 --- /dev/null +++ b/chapter13/valid/libraries/unsigned_args.c @@ -0,0 +1,7 @@ +int add_unsigned(unsigned int a, unsigned int b, unsigned long c, unsigned long d, + unsigned int e, unsigned int f, unsigned long g, unsigned int h, + unsigned long i) { + /* Make sure unsigned arguments are passed correctly */ + return (a == 1 && b == -1 && c == 2 && d == -2 && e == 3 && f == -3 && + g == 4 && h == -4 && i == 5); +} \ No newline at end of file diff --git a/chapter13/valid/libraries/unsigned_args_client.c b/chapter13/valid/libraries/unsigned_args_client.c new file mode 100644 index 00000000..07422c81 --- /dev/null +++ b/chapter13/valid/libraries/unsigned_args_client.c @@ -0,0 +1,7 @@ +int add_unsigned(unsigned int a, unsigned int b, unsigned long c, unsigned long d, + unsigned int e, unsigned int f, unsigned long g, unsigned int h, + unsigned long i); + +int main() { + return add_unsigned(1, -1, 2, -2, 3, -3, 4, -4, 5); +} \ No newline at end of file diff --git a/chapter13/valid/libraries/unsigned_global_var.c b/chapter13/valid/libraries/unsigned_global_var.c new file mode 100644 index 00000000..36649254 --- /dev/null +++ b/chapter13/valid/libraries/unsigned_global_var.c @@ -0,0 +1,13 @@ +unsigned int ui = 4294967200u; + +unsigned int return_uint() { + return ui; +} + +int return_uint_as_signed() { + return ui; //implicitly convert to signed int +} + +long return_uint_as_long() { + return ui; // implicitly convert to signed long +} \ No newline at end of file diff --git a/chapter13/valid/libraries/unsigned_global_var_client.c b/chapter13/valid/libraries/unsigned_global_var_client.c new file mode 100644 index 00000000..641f8474 --- /dev/null +++ b/chapter13/valid/libraries/unsigned_global_var_client.c @@ -0,0 +1,32 @@ +/* Make sure we can interact with unsigned variables in other translation units*/ + +/* Declarations of variable/functions defined in library */ +extern unsigned int ui; +unsigned int return_uint(); +int return_uint_as_signed(); +long return_uint_as_long(); + +int main() { + if (ui != 4294967200u) + return 0; + + // should be converted to 2^32 - 1 on assignment + ui = -1; + + /* Make sure that our update to ui is visible in the other translation unit, + * and that we correctly track function return types + */ + long result = (long) return_uint(); + if (result != 4294967295l) + return 0; + + result = (long) return_uint_as_signed(); + if (result != -1l) + return 0; + + result = return_uint_as_long(); + if (result != 4294967295l) + return 0; + + return 1; +} diff --git a/chapter13/valid/type_specifiers/signed_int_type_specifiers.c b/chapter13/valid/type_specifiers/signed_int_type_specifiers.c new file mode 100644 index 00000000..1bd31042 --- /dev/null +++ b/chapter13/valid/type_specifiers/signed_int_type_specifiers.c @@ -0,0 +1,10 @@ +/* Test out different ways to declare a signed int */ +static int x; +signed extern x; +int static signed x = 5; +signed int static x; + +int main() { + int signed extern x; + return x; +} \ No newline at end of file diff --git a/chapter13/valid/type_specifiers/signed_long_type_specifiers.c b/chapter13/valid/type_specifiers/signed_long_type_specifiers.c new file mode 100644 index 00000000..827b511e --- /dev/null +++ b/chapter13/valid/type_specifiers/signed_long_type_specifiers.c @@ -0,0 +1,11 @@ +/* Test out different ways to declare a signed long */ + +long signed x; +long x = 7; +int long x; +signed long int x; + +int main() { + extern signed long x; + return x; +} \ No newline at end of file diff --git a/chapter13/valid/type_specifiers/unsigned_int_type_specifiers.c b/chapter13/valid/type_specifiers/unsigned_int_type_specifiers.c new file mode 100644 index 00000000..a76a44cf --- /dev/null +++ b/chapter13/valid/type_specifiers/unsigned_int_type_specifiers.c @@ -0,0 +1,10 @@ +/* Test out different ways to declare an unsigned int */ + +unsigned x; +int unsigned x; +unsigned int x = 6; + +int main() { + return x; +} + diff --git a/chapter13/valid/type_specifiers/unsigned_long_type_specifiers.c b/chapter13/valid/type_specifiers/unsigned_long_type_specifiers.c new file mode 100644 index 00000000..145a368e --- /dev/null +++ b/chapter13/valid/type_specifiers/unsigned_long_type_specifiers.c @@ -0,0 +1,15 @@ +/* Exercise different ways to specify the type "unsigned long" */ + +/* Declare the global variable x in several different ways */ +unsigned long x; +long unsigned x; +long int unsigned x; +unsigned int long x = 4; + +int main() { + /* Declare the same variable again with a storage-class specifier */ + long extern unsigned x; + unsigned long extern x; + int extern unsigned long x; + return x; +} diff --git a/chapter13/valid/unsigned_expressions/add_literal.c b/chapter13/valid/unsigned_expressions/add_literal.c new file mode 100644 index 00000000..a84a7692 --- /dev/null +++ b/chapter13/valid/unsigned_expressions/add_literal.c @@ -0,0 +1,10 @@ +int main() { + unsigned int x = 10; + /* Test out rewrite rule for addition; + * even when adding numbers we interpret as unsigned, + * the 'add' instruction can only handle immediate values + * that fit into a signed int + */ + unsigned long y = x + 4294967295; // 2^32 - 1 is UINT_MAX + return (y == 4294967305); +} \ No newline at end of file diff --git a/chapter13/valid/unsigned_expressions/addition_wraparound.c b/chapter13/valid/unsigned_expressions/addition_wraparound.c new file mode 100644 index 00000000..bfa9004c --- /dev/null +++ b/chapter13/valid/unsigned_expressions/addition_wraparound.c @@ -0,0 +1,10 @@ +int main() { + unsigned int a = 4294967294u; + unsigned int b = 2u; + /* a + b = 4294967296, or 2^32. + * This is one more than the maximum value + * an unsigned int can represent, so it should + * wrap around to 0 + */ + return !(a + b); // Test that a + b == 0 +} \ No newline at end of file diff --git a/chapter13/valid/unsigned_expressions/comparison_set_upper_bit.c b/chapter13/valid/unsigned_expressions/comparison_set_upper_bit.c new file mode 100644 index 00000000..24131d3b --- /dev/null +++ b/chapter13/valid/unsigned_expressions/comparison_set_upper_bit.c @@ -0,0 +1,30 @@ +int main() { + unsigned x = 100u; + /* if you interpret y's binary + * representation as a signed int, + * its value is -2 + */ + unsigned y = 4294967294u; + + /* Test out every comparison code. + * False comparisons: + */ + if (y < x) + return 0; + if (y <= x) + return 0; + if (x >= y) + return 0; + if (x > y) + return 0; + /* True comparisons */ + if (!(x <= y)) + return 0; + if (!(x < y)) + return 0; + if (!(y > x)) + return 0; + if (!(y >= x)) + return 0; + return (y > x); +} \ No newline at end of file diff --git a/chapter13/valid/unsigned_expressions/comparison_unset_upper_bit.c b/chapter13/valid/unsigned_expressions/comparison_unset_upper_bit.c new file mode 100644 index 00000000..136ab60d --- /dev/null +++ b/chapter13/valid/unsigned_expressions/comparison_unset_upper_bit.c @@ -0,0 +1,30 @@ +int main() { + unsigned long x = 100ul; + /* This test case is identical to comparison_set_upper_bit.c, + * except both numbers have the same value whether they're interpreted + * as signed or unsigned values + */ + unsigned long y = 429496729400ul; + + /* Test out every comparison code. + * False comparisons: + */ + if (y < x) + return 0; + if (y <= x) + return 0; + if (x >= y) + return 0; + if (x > y) + return 0; + /* True comparisons */ + if (!(x <= y)) + return 0; + if (!(x < y)) + return 0; + if (!(y > x)) + return 0; + if (!(y >= x)) + return 0; + return (y > x); +} \ No newline at end of file diff --git a/chapter13/valid/unsigned_expressions/divide_by_literal.c b/chapter13/valid/unsigned_expressions/divide_by_literal.c new file mode 100644 index 00000000..5ecf7325 --- /dev/null +++ b/chapter13/valid/unsigned_expressions/divide_by_literal.c @@ -0,0 +1,5 @@ +int main() { + unsigned long x = 1099511627775; // 2^40 - 1 + /* Test out the assembly rewrite rule for 'div' */ + return (x / 5ul == 219902325555ul); +} \ No newline at end of file diff --git a/chapter13/valid/unsigned_expressions/divide_large_dividend.c b/chapter13/valid/unsigned_expressions/divide_large_dividend.c new file mode 100644 index 00000000..a82d7b6d --- /dev/null +++ b/chapter13/valid/unsigned_expressions/divide_large_dividend.c @@ -0,0 +1,11 @@ +int main() { + // The upper bit of x is set + unsigned int x = 4294967294u; + // y = x / 2 + unsigned int y = 2147483647u; + + /* This tests that we zero-extend x into EDX + * instead of sign-extending it + */ + return (x / y == 2); +} \ No newline at end of file diff --git a/chapter13/valid/unsigned_expressions/division.c b/chapter13/valid/unsigned_expressions/division.c new file mode 100644 index 00000000..f86b1819 --- /dev/null +++ b/chapter13/valid/unsigned_expressions/division.c @@ -0,0 +1,14 @@ +int main() { + unsigned x = 100u; + /* if you interpret y's binary + * representation as a signed int, + * its value is -2 + */ + unsigned y = 4294967294u; + + /* If we're performing unsigned division, + * this result is 0. If we performed signed + * division it would be -50. + */ + return (x / y == 0u); +} \ No newline at end of file diff --git a/chapter13/valid/unsigned_expressions/mod.c b/chapter13/valid/unsigned_expressions/mod.c new file mode 100644 index 00000000..42519554 --- /dev/null +++ b/chapter13/valid/unsigned_expressions/mod.c @@ -0,0 +1,5 @@ +int main() { + unsigned long x = 100ul; + unsigned long y = 18446744073709551605ul; + return (y % x == 5ul); +} \ No newline at end of file diff --git a/chapter13/valid/unsigned_expressions/neg.c b/chapter13/valid/unsigned_expressions/neg.c new file mode 100644 index 00000000..6a38c3f9 --- /dev/null +++ b/chapter13/valid/unsigned_expressions/neg.c @@ -0,0 +1,10 @@ +int main() { + /* Negating -1 is equivalent to computing 0 - 1. + * According to the rules for unsigned wraparound, + * this results in ULONG_MAX + */ + unsigned long x = -1ul; + // This is ULONG_MAX - 1 + unsigned long y = 18446744073709551615u; + return x == y; +} \ No newline at end of file diff --git a/chapter13/valid/unsigned_expressions/static_variables.c b/chapter13/valid/unsigned_expressions/static_variables.c new file mode 100644 index 00000000..01c8c090 --- /dev/null +++ b/chapter13/valid/unsigned_expressions/static_variables.c @@ -0,0 +1,18 @@ +/* Test initializing and updating unsigned global variables */ +static unsigned long x = 9223372036854775803ul; // 2^63 - 5 + +// make sure these are initialized to zero +unsigned long zero_long; +unsigned zero_int; + +int main() +{ + if (x != 9223372036854775803ul) + return 0; + x = x + 10; + if (x != 9223372036854775813ul) + return 0; + if (zero_long || zero_int) + return 0; + return 1; +} \ No newline at end of file diff --git a/chapter13/valid/unsigned_expressions/subtraction_wraparound.c b/chapter13/valid/unsigned_expressions/subtraction_wraparound.c new file mode 100644 index 00000000..46d2f96e --- /dev/null +++ b/chapter13/valid/unsigned_expressions/subtraction_wraparound.c @@ -0,0 +1,11 @@ +int main() { + unsigned long a = 10ul; + unsigned long b = 20ul; + /* a - b = -10 + * Since this number is negative, it wraps around + * to 2^64 - 10, or 18446744073709551606 + */ + unsigned long result = a - b; + return (result > a && result > b && + result == 18446744073709551606ul); +} \ No newline at end of file diff --git a/chapter13/valid_extra_credit/bitwise_unsigned_ops.c b/chapter13/valid_extra_credit/bitwise_unsigned_ops.c new file mode 100644 index 00000000..24c3e8ec --- /dev/null +++ b/chapter13/valid_extra_credit/bitwise_unsigned_ops.c @@ -0,0 +1,42 @@ +int main() { + unsigned int ui = -1u; // lower 32 bits set + unsigned long ul = 9223372036854775808ul; // 2^63, only uppermost bit set + + /* this expression will: + * 1. zero-extend ui. the result will have all 32 lower bits set to 1 + * and all upper bits set to 0 + * 2. calculate the bitwise and of this zero-extended value and ul. the result is 0 + */ + if ((ui & ul) != 0) + return 0; + + /* this expression will: + * 1. zero-extend ui. the result will have all 32 lower bits set to 1 + * and all upper bits set to 0 + * 2. calculate the bitwise or of this zero-extended value and ul. + * the result is 2^63 + 2^32 - 1 + */ + if ((ui | ul) != 9223372041149743103ul) + return 0; + + signed int i = -1; + /* this expression will: + * 1. sign-extend i. the result will have every bit set to 1. + * 2. calculate the bitwise and of this zero-extended value and ul. + * the result is equal to ul. + */ + if ((i & ul) != ul) + return 0; + + + /* this expression will: + * 1. sign-extend i. the result will have every bit set to 1. + * 2. calculate the bitwise or of this zero-extended value and ul. + * the result will have every bit set + */ + if ((i | ul) != i) + return 0; + + return 1; + +} \ No newline at end of file diff --git a/chapter13/valid_extra_credit/bitwise_unsigned_shift.c b/chapter13/valid_extra_credit/bitwise_unsigned_shift.c new file mode 100644 index 00000000..32cff4c2 --- /dev/null +++ b/chapter13/valid_extra_credit/bitwise_unsigned_shift.c @@ -0,0 +1,10 @@ +/* Bit-shift operations do not perform the usual arithmetic conversions. */ + +int main() { + unsigned int ui = -1u; // 2^32 - 1, or 4294967295 + + /* shifting right by 2 is like subtracting 3. + * note that we don't cast ui to a long first + */ + return ((ui << 2l) == 4294967292); +} \ No newline at end of file diff --git a/chapter13/valid_extra_credit/compound_assign_uint.c b/chapter13/valid_extra_credit/compound_assign_uint.c new file mode 100644 index 00000000..a8e718a6 --- /dev/null +++ b/chapter13/valid_extra_credit/compound_assign_uint.c @@ -0,0 +1,10 @@ +int main() { + unsigned int x = -1u; // 2^32 - 1 + /* 1. convert x to a signed long, which preserves its value + * 2. divide by -10, resulting in -429496729 + * 3. convert -429496729 to an unsigned int by adding 2^32 + */ + x /= -10l; + + return (x == 3865470567u); +} \ No newline at end of file diff --git a/chapter13/valid_extra_credit/switch_uint.c b/chapter13/valid_extra_credit/switch_uint.c new file mode 100644 index 00000000..ba2ff476 --- /dev/null +++ b/chapter13/valid_extra_credit/switch_uint.c @@ -0,0 +1,27 @@ +int switch_on_uint(unsigned int ui) +{ + switch (ui) + { + case 5u: + return 0; + // this will be converted to 2^32 - 10, or 4294967286 + // case -10l: + // return 1; + // 2^35 + 10, will be converted to 10 + case 34359738378ul: + return 2; + default: + return 3; + } +} + +int main() +{ + if (switch_on_uint(5) != 0) + return 0; + if (switch_on_uint(4294967286) != 1) + return 0; + if (switch_on_uint(10) != 2) + return 0; + return 1; +} \ No newline at end of file From e0902dd32e67479e64794f4512ee3a1f971be0b7 Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Mon, 6 Mar 2023 10:53:02 -0800 Subject: [PATCH 004/167] add chapter 14 tests, fix folder name in chapter 10 --- .../expression_args.c | 0 .../fibonacci.c | 0 .../forward_decl_multi_arg.c | 0 .../hello_world.c | 0 .../parameter_shadows_function.c | 0 .../parameters_are_preserved.c | 0 .../single_arg.c | 0 chapter14/invalid_lex/another_bad_constant.c | 8 +++ chapter14/invalid_lex/bad_exponent_suffix.c | 4 ++ chapter14/invalid_lex/malformed_const.c | 7 ++ chapter14/invalid_lex/malformed_exponent.c | 10 +++ chapter14/invalid_lex/missing_exponent.c | 7 ++ .../invalid_lex/missing_negative_exponent.c | 7 ++ .../invalid_lex/yet_another_bad_constant.c | 4 ++ .../invalid_parse/invalid_type_specifier.c | 5 ++ .../invalid_parse/invalid_type_specifier_2.c | 5 ++ chapter14/invalid_types/complement_double.c | 5 ++ chapter14/invalid_types/mod_double.c | 6 ++ chapter14/invalid_types/mod_double_2.c | 6 ++ .../invalid_types_extra_credit/bitwise_and.c | 5 ++ .../invalid_types_extra_credit/bitwise_or.c | 5 ++ .../bitwise_shift_double.c | 5 ++ .../invalid_types_extra_credit/bitwise_xor.c | 4 ++ .../switch_double_case.c | 9 +++ .../switch_on_double.c | 10 +++ chapter14/valid/constants/constant_doubles.c | 34 +++++++++ .../valid/constants/double_rounded_constant.c | 24 +++++++ chapter14/valid/constants/round_constants.c | 8 +++ .../valid/explicit_casts/cvtsi2sd_rewrite.c | 72 +++++++++++++++++++ .../valid/explicit_casts/double_to_int.c | 15 ++++ .../valid/explicit_casts/double_to_signed.c | 14 ++++ .../valid/explicit_casts/double_to_uint.c | 14 ++++ .../valid/explicit_casts/double_to_ulong.c | 18 +++++ chapter14/valid/explicit_casts/round_to_odd.c | 20 ++++++ .../valid/explicit_casts/signed_to_double.c | 15 ++++ .../valid/explicit_casts/uint_to_double.c | 13 ++++ .../valid/explicit_casts/ulong_to_double.c | 14 ++++ chapter14/valid/floating_expressions/and.c | 20 ++++++ .../floating_expressions/basic_arithmetic.c | 43 +++++++++++ .../valid/floating_expressions/comparisons.c | 37 ++++++++++ .../loop_controlling_expression.c | 14 ++++ chapter14/valid/floating_expressions/not.c | 8 +++ chapter14/valid/floating_expressions/or.c | 21 ++++++ .../double_and_int_parameters.c | 11 +++ .../double_and_int_params_recursive.c | 20 ++++++ .../valid/function_calls/double_parameters.c | 11 +++ .../valid/function_calls/return_double.c | 9 +++ .../function_calls/standard_library_call.c | 16 +++++ .../function_calls/use_arg_after_fun_call.c | 18 +++++ .../implicit_casts/comparison_common_type.c | 15 ++++ .../complex_arithmetic_common_type.c | 18 +++++ .../implicit_casts/convert_for_assignment.c | 9 +++ .../convert_function_argument.c | 8 +++ .../implicit_casts/convert_return_value.c | 10 +++ .../multiplication_common_type.c | 14 ++++ .../implicit_casts/ternary_common_type.c | 19 +++++ .../double_and_int_params_recursive.c | 13 ++++ .../double_and_int_params_recursive_client.c | 10 +++ chapter14/valid/libraries/double_parameters.c | 4 ++ .../libraries/double_parameters_client.c | 7 ++ chapter14/valid/libraries/extern_double.c | 1 + .../valid/libraries/extern_double_client.c | 6 ++ .../valid/libraries/use_arg_after_fun_call.c | 8 +++ .../libraries/use_arg_after_fun_call_client.c | 7 ++ .../valid/special_values/const_infinity.c | 20 ++++++ chapter14/valid/special_values/copysign.c | 11 +++ .../negative_and_positive_zero.c | 19 +++++ .../valid/special_values/negative_infinity.c | 10 +++ .../valid/special_values/negative_zero.c | 24 +++++++ .../valid/special_values/positive_infinity.c | 10 +++ .../valid/special_values/subnormal_not_zero.c | 8 +++ .../valid/static_variables/static_double.c | 6 ++ .../static_double_initialized_from_int.c | 27 +++++++ .../static_initialized_double.c | 16 +++++ .../static_int_initialized_from_double.c | 17 +++++ .../valid_extra_credit/compound_assign.c | 6 ++ .../compound_assign_implicit_cast.c | 23 ++++++ chapter14/valid_extra_credit/nan.c | 13 ++++ 78 files changed, 960 insertions(+) rename chapter10/valid/{arguments_in_parameters => arguments_in_registers}/expression_args.c (100%) rename chapter10/valid/{arguments_in_parameters => arguments_in_registers}/fibonacci.c (100%) rename chapter10/valid/{arguments_in_parameters => arguments_in_registers}/forward_decl_multi_arg.c (100%) rename chapter10/valid/{arguments_in_parameters => arguments_in_registers}/hello_world.c (100%) rename chapter10/valid/{arguments_in_parameters => arguments_in_registers}/parameter_shadows_function.c (100%) rename chapter10/valid/{arguments_in_parameters => arguments_in_registers}/parameters_are_preserved.c (100%) rename chapter10/valid/{arguments_in_parameters => arguments_in_registers}/single_arg.c (100%) create mode 100644 chapter14/invalid_lex/another_bad_constant.c create mode 100644 chapter14/invalid_lex/bad_exponent_suffix.c create mode 100644 chapter14/invalid_lex/malformed_const.c create mode 100644 chapter14/invalid_lex/malformed_exponent.c create mode 100644 chapter14/invalid_lex/missing_exponent.c create mode 100644 chapter14/invalid_lex/missing_negative_exponent.c create mode 100644 chapter14/invalid_lex/yet_another_bad_constant.c create mode 100644 chapter14/invalid_parse/invalid_type_specifier.c create mode 100644 chapter14/invalid_parse/invalid_type_specifier_2.c create mode 100644 chapter14/invalid_types/complement_double.c create mode 100644 chapter14/invalid_types/mod_double.c create mode 100644 chapter14/invalid_types/mod_double_2.c create mode 100644 chapter14/invalid_types_extra_credit/bitwise_and.c create mode 100644 chapter14/invalid_types_extra_credit/bitwise_or.c create mode 100644 chapter14/invalid_types_extra_credit/bitwise_shift_double.c create mode 100644 chapter14/invalid_types_extra_credit/bitwise_xor.c create mode 100644 chapter14/invalid_types_extra_credit/switch_double_case.c create mode 100644 chapter14/invalid_types_extra_credit/switch_on_double.c create mode 100644 chapter14/valid/constants/constant_doubles.c create mode 100644 chapter14/valid/constants/double_rounded_constant.c create mode 100644 chapter14/valid/constants/round_constants.c create mode 100644 chapter14/valid/explicit_casts/cvtsi2sd_rewrite.c create mode 100644 chapter14/valid/explicit_casts/double_to_int.c create mode 100644 chapter14/valid/explicit_casts/double_to_signed.c create mode 100644 chapter14/valid/explicit_casts/double_to_uint.c create mode 100644 chapter14/valid/explicit_casts/double_to_ulong.c create mode 100644 chapter14/valid/explicit_casts/round_to_odd.c create mode 100644 chapter14/valid/explicit_casts/signed_to_double.c create mode 100644 chapter14/valid/explicit_casts/uint_to_double.c create mode 100644 chapter14/valid/explicit_casts/ulong_to_double.c create mode 100644 chapter14/valid/floating_expressions/and.c create mode 100644 chapter14/valid/floating_expressions/basic_arithmetic.c create mode 100644 chapter14/valid/floating_expressions/comparisons.c create mode 100644 chapter14/valid/floating_expressions/loop_controlling_expression.c create mode 100644 chapter14/valid/floating_expressions/not.c create mode 100644 chapter14/valid/floating_expressions/or.c create mode 100644 chapter14/valid/function_calls/double_and_int_parameters.c create mode 100644 chapter14/valid/function_calls/double_and_int_params_recursive.c create mode 100644 chapter14/valid/function_calls/double_parameters.c create mode 100644 chapter14/valid/function_calls/return_double.c create mode 100644 chapter14/valid/function_calls/standard_library_call.c create mode 100644 chapter14/valid/function_calls/use_arg_after_fun_call.c create mode 100644 chapter14/valid/implicit_casts/comparison_common_type.c create mode 100644 chapter14/valid/implicit_casts/complex_arithmetic_common_type.c create mode 100644 chapter14/valid/implicit_casts/convert_for_assignment.c create mode 100644 chapter14/valid/implicit_casts/convert_function_argument.c create mode 100644 chapter14/valid/implicit_casts/convert_return_value.c create mode 100644 chapter14/valid/implicit_casts/multiplication_common_type.c create mode 100644 chapter14/valid/implicit_casts/ternary_common_type.c create mode 100644 chapter14/valid/libraries/double_and_int_params_recursive.c create mode 100644 chapter14/valid/libraries/double_and_int_params_recursive_client.c create mode 100644 chapter14/valid/libraries/double_parameters.c create mode 100644 chapter14/valid/libraries/double_parameters_client.c create mode 100644 chapter14/valid/libraries/extern_double.c create mode 100644 chapter14/valid/libraries/extern_double_client.c create mode 100644 chapter14/valid/libraries/use_arg_after_fun_call.c create mode 100644 chapter14/valid/libraries/use_arg_after_fun_call_client.c create mode 100644 chapter14/valid/special_values/const_infinity.c create mode 100644 chapter14/valid/special_values/copysign.c create mode 100644 chapter14/valid/special_values/negative_and_positive_zero.c create mode 100644 chapter14/valid/special_values/negative_infinity.c create mode 100644 chapter14/valid/special_values/negative_zero.c create mode 100644 chapter14/valid/special_values/positive_infinity.c create mode 100644 chapter14/valid/special_values/subnormal_not_zero.c create mode 100644 chapter14/valid/static_variables/static_double.c create mode 100644 chapter14/valid/static_variables/static_double_initialized_from_int.c create mode 100644 chapter14/valid/static_variables/static_initialized_double.c create mode 100644 chapter14/valid/static_variables/static_int_initialized_from_double.c create mode 100644 chapter14/valid_extra_credit/compound_assign.c create mode 100644 chapter14/valid_extra_credit/compound_assign_implicit_cast.c create mode 100644 chapter14/valid_extra_credit/nan.c diff --git a/chapter10/valid/arguments_in_parameters/expression_args.c b/chapter10/valid/arguments_in_registers/expression_args.c similarity index 100% rename from chapter10/valid/arguments_in_parameters/expression_args.c rename to chapter10/valid/arguments_in_registers/expression_args.c diff --git a/chapter10/valid/arguments_in_parameters/fibonacci.c b/chapter10/valid/arguments_in_registers/fibonacci.c similarity index 100% rename from chapter10/valid/arguments_in_parameters/fibonacci.c rename to chapter10/valid/arguments_in_registers/fibonacci.c diff --git a/chapter10/valid/arguments_in_parameters/forward_decl_multi_arg.c b/chapter10/valid/arguments_in_registers/forward_decl_multi_arg.c similarity index 100% rename from chapter10/valid/arguments_in_parameters/forward_decl_multi_arg.c rename to chapter10/valid/arguments_in_registers/forward_decl_multi_arg.c diff --git a/chapter10/valid/arguments_in_parameters/hello_world.c b/chapter10/valid/arguments_in_registers/hello_world.c similarity index 100% rename from chapter10/valid/arguments_in_parameters/hello_world.c rename to chapter10/valid/arguments_in_registers/hello_world.c diff --git a/chapter10/valid/arguments_in_parameters/parameter_shadows_function.c b/chapter10/valid/arguments_in_registers/parameter_shadows_function.c similarity index 100% rename from chapter10/valid/arguments_in_parameters/parameter_shadows_function.c rename to chapter10/valid/arguments_in_registers/parameter_shadows_function.c diff --git a/chapter10/valid/arguments_in_parameters/parameters_are_preserved.c b/chapter10/valid/arguments_in_registers/parameters_are_preserved.c similarity index 100% rename from chapter10/valid/arguments_in_parameters/parameters_are_preserved.c rename to chapter10/valid/arguments_in_registers/parameters_are_preserved.c diff --git a/chapter10/valid/arguments_in_parameters/single_arg.c b/chapter10/valid/arguments_in_registers/single_arg.c similarity index 100% rename from chapter10/valid/arguments_in_parameters/single_arg.c rename to chapter10/valid/arguments_in_registers/single_arg.c diff --git a/chapter14/invalid_lex/another_bad_constant.c b/chapter14/invalid_lex/another_bad_constant.c new file mode 100644 index 00000000..782e8c95 --- /dev/null +++ b/chapter14/invalid_lex/another_bad_constant.c @@ -0,0 +1,8 @@ +int main() +{ + // this shouldn't match our floating-point + // regex because "1." is followed by word character + // (in C standard terms, 1.ex is a preprocessing number + // that can't be converted into a constant token) + return 1.ex; +} \ No newline at end of file diff --git a/chapter14/invalid_lex/bad_exponent_suffix.c b/chapter14/invalid_lex/bad_exponent_suffix.c new file mode 100644 index 00000000..01e10a96 --- /dev/null +++ b/chapter14/invalid_lex/bad_exponent_suffix.c @@ -0,0 +1,4 @@ +int main() +{ + double foo = 1E2x; +} \ No newline at end of file diff --git a/chapter14/invalid_lex/malformed_const.c b/chapter14/invalid_lex/malformed_const.c new file mode 100644 index 00000000..770afaf1 --- /dev/null +++ b/chapter14/invalid_lex/malformed_const.c @@ -0,0 +1,7 @@ +int main() +{ + // this shouldn't match our floating-point regex b/c + // "2."" is followed by a word character + // in C standard terms, "2._" is a preprocessing number + return 2._; +} \ No newline at end of file diff --git a/chapter14/invalid_lex/malformed_exponent.c b/chapter14/invalid_lex/malformed_exponent.c new file mode 100644 index 00000000..0815cd43 --- /dev/null +++ b/chapter14/invalid_lex/malformed_exponent.c @@ -0,0 +1,10 @@ +int main() +{ + /* This won't match our regex + * b/c "1.0e10" is followed by a . + * in C standard terms, 1.0e10.0 is a + * single preprocessing number + */ + double d = 1.0e10.0; + return 0; +} \ No newline at end of file diff --git a/chapter14/invalid_lex/missing_exponent.c b/chapter14/invalid_lex/missing_exponent.c new file mode 100644 index 00000000..f9ec5b88 --- /dev/null +++ b/chapter14/invalid_lex/missing_exponent.c @@ -0,0 +1,7 @@ +int main() +{ + // "30." won't match our regex b/c it's followed by a letter + // "30.e" is a preprocessing number but not a valid constant + double foo = 30.e; + return 4; +} \ No newline at end of file diff --git a/chapter14/invalid_lex/missing_negative_exponent.c b/chapter14/invalid_lex/missing_negative_exponent.c new file mode 100644 index 00000000..4173edac --- /dev/null +++ b/chapter14/invalid_lex/missing_negative_exponent.c @@ -0,0 +1,7 @@ +int main() { + /* This constant is malformed. + * The exponent must be an integer, + * not just a negative sign. + */ + double foo = 24e-; +} \ No newline at end of file diff --git a/chapter14/invalid_lex/yet_another_bad_constant.c b/chapter14/invalid_lex/yet_another_bad_constant.c new file mode 100644 index 00000000..47551033 --- /dev/null +++ b/chapter14/invalid_lex/yet_another_bad_constant.c @@ -0,0 +1,4 @@ +int main() +{ + return 1.e-10x; +} \ No newline at end of file diff --git a/chapter14/invalid_parse/invalid_type_specifier.c b/chapter14/invalid_parse/invalid_type_specifier.c new file mode 100644 index 00000000..3bc84f23 --- /dev/null +++ b/chapter14/invalid_parse/invalid_type_specifier.c @@ -0,0 +1,5 @@ +int main() { + /* "Unsigned double" is not a valid type specifier */ + unsigned double d = 10.0; + return 0; +} \ No newline at end of file diff --git a/chapter14/invalid_parse/invalid_type_specifier_2.c b/chapter14/invalid_parse/invalid_type_specifier_2.c new file mode 100644 index 00000000..fdd9bf68 --- /dev/null +++ b/chapter14/invalid_parse/invalid_type_specifier_2.c @@ -0,0 +1,5 @@ +int main() { + /* "double double" is not a valid type specifier */ + double double d = 10.0; + return 0; +} \ No newline at end of file diff --git a/chapter14/invalid_types/complement_double.c b/chapter14/invalid_types/complement_double.c new file mode 100644 index 00000000..eb8eda95 --- /dev/null +++ b/chapter14/invalid_types/complement_double.c @@ -0,0 +1,5 @@ +int main() { + /* You can't take the bitwise complement of a double */ + double d = ~10.0; + return 0; +} \ No newline at end of file diff --git a/chapter14/invalid_types/mod_double.c b/chapter14/invalid_types/mod_double.c new file mode 100644 index 00000000..eaf334fa --- /dev/null +++ b/chapter14/invalid_types/mod_double.c @@ -0,0 +1,6 @@ +int main() { + /* You can't apply the modulo operator to a double */ + double d = 10.0; + d = d % 3; + return 0; +} \ No newline at end of file diff --git a/chapter14/invalid_types/mod_double_2.c b/chapter14/invalid_types/mod_double_2.c new file mode 100644 index 00000000..12d1560a --- /dev/null +++ b/chapter14/invalid_types/mod_double_2.c @@ -0,0 +1,6 @@ +int main() { + /* You can't apply the modulo operator to a double */ + double d = 2.0; + double e = 3.0 % d; + return 0; +} \ No newline at end of file diff --git a/chapter14/invalid_types_extra_credit/bitwise_and.c b/chapter14/invalid_types_extra_credit/bitwise_and.c new file mode 100644 index 00000000..2299526e --- /dev/null +++ b/chapter14/invalid_types_extra_credit/bitwise_and.c @@ -0,0 +1,5 @@ +int main() { + /* It's illegal to apply bitwise & to doubles */ + double d = 10.0 & -1; + return 0; +} \ No newline at end of file diff --git a/chapter14/invalid_types_extra_credit/bitwise_or.c b/chapter14/invalid_types_extra_credit/bitwise_or.c new file mode 100644 index 00000000..69704014 --- /dev/null +++ b/chapter14/invalid_types_extra_credit/bitwise_or.c @@ -0,0 +1,5 @@ +int main() { + /* It's illegal to apply bitwise | to doubles */ + double d = 0.0 | -0.0; + return 0; +} \ No newline at end of file diff --git a/chapter14/invalid_types_extra_credit/bitwise_shift_double.c b/chapter14/invalid_types_extra_credit/bitwise_shift_double.c new file mode 100644 index 00000000..e26e6dc7 --- /dev/null +++ b/chapter14/invalid_types_extra_credit/bitwise_shift_double.c @@ -0,0 +1,5 @@ +int main () { + /* It's illegal to apply the << or >> operator to doubles */ + double d = 5.0 << 3; + return 0; +} \ No newline at end of file diff --git a/chapter14/invalid_types_extra_credit/bitwise_xor.c b/chapter14/invalid_types_extra_credit/bitwise_xor.c new file mode 100644 index 00000000..0a15e138 --- /dev/null +++ b/chapter14/invalid_types_extra_credit/bitwise_xor.c @@ -0,0 +1,4 @@ +int main() { + /* It's illegal to XOR doubles */ + return 1e10 ^ -1e10; +} \ No newline at end of file diff --git a/chapter14/invalid_types_extra_credit/switch_double_case.c b/chapter14/invalid_types_extra_credit/switch_double_case.c new file mode 100644 index 00000000..79979277 --- /dev/null +++ b/chapter14/invalid_types_extra_credit/switch_double_case.c @@ -0,0 +1,9 @@ +int main() { + int x = 10; + switch (x) { + // the constant in a case expression + // must be an integer, not a double + case 1.0: return 0; + default: return 4; + } +} \ No newline at end of file diff --git a/chapter14/invalid_types_extra_credit/switch_on_double.c b/chapter14/invalid_types_extra_credit/switch_on_double.c new file mode 100644 index 00000000..ffe75c9d --- /dev/null +++ b/chapter14/invalid_types_extra_credit/switch_on_double.c @@ -0,0 +1,10 @@ +int main() { + double d = 10; + /* The controlling expression in a switch statement + * must be an integer, not a double + */ + switch (d) { + case 10.0: return 0; + } + return 1; +} \ No newline at end of file diff --git a/chapter14/valid/constants/constant_doubles.c b/chapter14/valid/constants/constant_doubles.c new file mode 100644 index 00000000..8242e57f --- /dev/null +++ b/chapter14/valid/constants/constant_doubles.c @@ -0,0 +1,34 @@ +int main() { + /* Define constant doubles in a few different formats, + * and make sure we can lex all of them. + * Note that these can all be respresented exactly, + * without rounding + */ + + /* Several ways to define 1 */ + double a = 1.0; + double b = 1.; + double c = 1E0; + double d = .01e+2; + + /* Make sure they all have the correct value */ + if (! (a == b && a == c && a == d) ) + return 0; + if (a + b + c + d != 4.0) + return 0; + + /* Several ways to define .125 */ + double e = .125; + double f = 12.5e-2; + double g = 125.E-3; + double h = 1250000000e-10; + + /* Make sure they all have the correct value */ + if (! (e == f && e == g && e == h) ) + return 0; + if (e + f + g + h != 0.5) + return 0; + + return 1; + +} \ No newline at end of file diff --git a/chapter14/valid/constants/double_rounded_constant.c b/chapter14/valid/constants/double_rounded_constant.c new file mode 100644 index 00000000..0206309a --- /dev/null +++ b/chapter14/valid/constants/double_rounded_constant.c @@ -0,0 +1,24 @@ +int main() { + /* Test for double-rounding errors that could result + * if your compiler uses an 80-bit (aka extended-precisions) + * floating-point representation internally + */ + + /* If 9223372036854776832.5 is converted to double precision (64 bits), + * it will be rounded to 9223372036854777856.0, + * so this function will return 1 + * + * if your compiler uses 80-bit precision internally, + * it will be rounded to 9223372036854776832, + * which would later be rounded down to the 64-bit value + * 9223372036854775808.0, so this function will return 0. + * + * This incorrect double rounding would be equivalent to: + * return ( (double) 9223372036854776832.5l == 9223372036854777856.0); + * You can try this out and see that it returns 0. + * (note that the "l" suffix above indicates the "long double" type, + * which has 80-bit precision) + */ + return (9223372036854776832.5 == 9223372036854777856.0); + +} \ No newline at end of file diff --git a/chapter14/valid/constants/round_constants.c b/chapter14/valid/constants/round_constants.c new file mode 100644 index 00000000..9346ec0f --- /dev/null +++ b/chapter14/valid/constants/round_constants.c @@ -0,0 +1,8 @@ +int main() { + /* Both these values should round to + * 1.000000000000000444089209850062616169452667236328125. + * (I got these numbers from from example 2 in + * https://www.exploringbinary.com/17-digits-gets-you-there-once-youve-found-your-way/) + */ + return 1.00000000000000033306690738754696212708950042724609375 == 1.0000000000000004; +} \ No newline at end of file diff --git a/chapter14/valid/explicit_casts/cvtsi2sd_rewrite.c b/chapter14/valid/explicit_casts/cvtsi2sd_rewrite.c new file mode 100644 index 00000000..8a6af457 --- /dev/null +++ b/chapter14/valid/explicit_casts/cvtsi2sd_rewrite.c @@ -0,0 +1,72 @@ +// make sure we correctly rewrite cvtsi2sd where src is constant and dest is memory +// NOTE: this doesn't work b/c when optimizations are enabled, cvtsi2sd is optmized way +// and when they're disabled...we end up not storing result in memory. but maybe that's fixable +// adapted from test_spilling_dbls in chapter 21 so it will work even once we have register coalescing +// maybe there is a less messy way to do this? + + +int glob = 3; +double glob2 = 4.0; + +double callee(double fourteen, double thirteen, double twelve, double eleven, double ten, double nine, double eight, double seven, double six, double five, double four, double three, double two, double one) { + + glob = 10; + glob2 = 11; + if (one == 1 && two == 2 && three == 3 && four == 4 && five == 5 && six == 6 && seven == 7 && eight == 8 && nine == 18 && ten == 10 && eleven == 15 && twelve == 7 && thirteen == 15. && fourteen == 180.) { + // expected results for first call + return 2; + } + + if (one == 188 && two == 0 && three == 94 && four == 2 && five == 0 && six == 92 && seven == 180 && eight == 1111 && nine == 81 && ten == 79 && eleven == 90 && twelve == 2 && thirteen == 30 && fourteen == 20) { + // expected results for second call + return 3; + } + + return 0; +} + + +int target(double one, double two, double three, double four, double five, double six) +{ + /* force spill by creating lots of conflicting pseudos + * validate that we spill the variable should_spill, which is used least + * and has highest degree + * Note: this isn't a good test of spill metric calculation; + * due to optimistic coloring, we could end up spilling just should_spill + * even if we end up choosing other nodes as spill candidates first + */ + double should_spill = (double) 3; + // all these registers conflict with should_spill and each other + double seven = one * one + 6.0; + double eight = two * 4; + double nine = three * two * three; + double ten = four + six; + double eleven = 16 - five + four; + double twelve = six + six - five; + double thirteen = seven + eight; + double fourteen = nine * ten; + + double result = callee(fourteen, thirteen, twelve, eleven, ten, nine, eight, seven, six, five, four, three, two, one); + + // make another twelve pseudoes that conflict w/ should_spill and each other + double fifteen = glob + glob; + double sixteen = fifteen + 10.0; + double seventeen = 12.0 - glob; + double eighteen = sixteen * 3.0; + double nineteen = eighteen - glob2; + double twenty = seventeen + nineteen; + double twenty_one = glob2 * twenty + glob2 * fifteen; + double twenty_two = result * eighteen; + double twenty_three = result + eighteen; + double twenty_four = seventeen - result; + double twenty_five = twenty - nineteen; + double twenty_six = twenty_three + twenty_four + twenty_five; + double twenty_seven = twenty_four * 2.0; + double twenty_eight = twenty_five * twenty_six; + double result2 = callee(fifteen, sixteen, seventeen, eighteen, nineteen, twenty, twenty_one, twenty_two, twenty_three, twenty_four, twenty_five, twenty_six, twenty_seven, twenty_eight); + return should_spill + result2; +} + +int main() { + return target(1.0, 2.0, 3.0, 4.0, 5.0, 6.0); +} \ No newline at end of file diff --git a/chapter14/valid/explicit_casts/double_to_int.c b/chapter14/valid/explicit_casts/double_to_int.c new file mode 100644 index 00000000..300c3d93 --- /dev/null +++ b/chapter14/valid/explicit_casts/double_to_int.c @@ -0,0 +1,15 @@ +double glob = 3.0; + +int main() { + + // this is a regression test for a bug I found in my reference implementaton, + // instruction fix-up rewrite cvttsd2sil -8(%rbp), -12(%rbp) to + // cvttsdi2sil -8(%rbp), %r11d + // movq %r11, %-12(%rbp) + // which potentilly clobbers other things on the stack + // we include other variables on the stack in order to catch this + int i = 10; + int j = (int) glob; + int k = 20; + return i + j + k; +} \ No newline at end of file diff --git a/chapter14/valid/explicit_casts/double_to_signed.c b/chapter14/valid/explicit_casts/double_to_signed.c new file mode 100644 index 00000000..638fa80d --- /dev/null +++ b/chapter14/valid/explicit_casts/double_to_signed.c @@ -0,0 +1,14 @@ +/* Test conversions from double to the signed integer types */ +int main() { + + // when truncated, d will fit in a long + // but not an int + double d = 2148429099.3; + long l = (long) d; + + double e = -200000.9999; + int i = (int) e; + + // both values should be truncated towards zero + return l == 2148429099l && i == -200000; +} \ No newline at end of file diff --git a/chapter14/valid/explicit_casts/double_to_uint.c b/chapter14/valid/explicit_casts/double_to_uint.c new file mode 100644 index 00000000..1a333a2e --- /dev/null +++ b/chapter14/valid/explicit_casts/double_to_uint.c @@ -0,0 +1,14 @@ +/* Test conversions from double to unsigned int */ +int main() { + double small = 10.9; + unsigned int small_uint = (unsigned int) small; + + // make sure we can handle a double + // that is large enough to fit in + // unsigned int but not int + double big = 2147483750.5; + unsigned int big_uint = (unsigned int) big; + + // both values should be truncated toward zeo + return small_uint == 10u && big_uint == 2147483750u; +} \ No newline at end of file diff --git a/chapter14/valid/explicit_casts/double_to_ulong.c b/chapter14/valid/explicit_casts/double_to_ulong.c new file mode 100644 index 00000000..1ca516ac --- /dev/null +++ b/chapter14/valid/explicit_casts/double_to_ulong.c @@ -0,0 +1,18 @@ +/* Test conversions from double to unsigned long */ +int main() { + + // test case where the double is smaller than LONG_MAX, + // so result of cvttsd2siq is already correct + double small = 2147483750.5; + unsigned long small_long = (unsigned long) small; + + // test case where double is larger than LONG_MAX + // so we need to adjust the results of cvttsd2siq + double large = 3458764513821589504.0; + unsigned long large_long = (unsigned long) large; + + // both results should be truncated toward zero + return small_long == 2147483750ul + && large_long == 3458764513821589504ul; + +} \ No newline at end of file diff --git a/chapter14/valid/explicit_casts/round_to_odd.c b/chapter14/valid/explicit_casts/round_to_odd.c new file mode 100644 index 00000000..42e3a4a5 --- /dev/null +++ b/chapter14/valid/explicit_casts/round_to_odd.c @@ -0,0 +1,20 @@ +/* Test borderline conversions from unsigned long to double */ +int main() { + // round_down is exactly halfway between doubles + // 9223372036854775808.0 and 9223372036854777856.0 + // Using ties-to-even rounding, we'll round it down to + // 9223372036854775808.0, which has an even significand + unsigned long round_down = 9223372036854776832ul; + + // round_up is closer to 9223372036854777856.0 than + // to 9223372036854775808.0, so we should round up. + // our assembly code must round to odd after halving this + // in order to avoid double rounding error + unsigned long round_up = 9223372036854776833ul; + + double d1 = (double) round_down; + double d2 = (double) round_up; + + return d1 == 9223372036854775808.0 && + d2 == 9223372036854777856.0; +} \ No newline at end of file diff --git a/chapter14/valid/explicit_casts/signed_to_double.c b/chapter14/valid/explicit_casts/signed_to_double.c new file mode 100644 index 00000000..1a981f34 --- /dev/null +++ b/chapter14/valid/explicit_casts/signed_to_double.c @@ -0,0 +1,15 @@ +/* Test conversions from signed integer types to double */ + +int main() { + int i = -100000; + double d = (double) i; + + // Cast a long to the closest representable double, + // which is -9007199254751228. + // NOTE: most of our type conversion tests cast variables to double. + // Here we include a test to cast a constant to double, + // to make sure we rewrite cvtsi2sd if its operand is a constant + double d2 = (double) -9007199254751227l; + + return (d == -100000.0 && d2 == -9007199254751228.0); +} \ No newline at end of file diff --git a/chapter14/valid/explicit_casts/uint_to_double.c b/chapter14/valid/explicit_casts/uint_to_double.c new file mode 100644 index 00000000..c25e1568 --- /dev/null +++ b/chapter14/valid/explicit_casts/uint_to_double.c @@ -0,0 +1,13 @@ +/* Test conversions from unsigned int to double */ + +int main() { + unsigned int small = 1000u; + double small_double = (double) small; + + // make sure we can convert a uint that's + // larger than INT_MAX to a double + unsigned int large = 4294967200u; + double large_double = (double) large; + + return (small_double == 1000.0 && large_double == 4294967200.0); +} \ No newline at end of file diff --git a/chapter14/valid/explicit_casts/ulong_to_double.c b/chapter14/valid/explicit_casts/ulong_to_double.c new file mode 100644 index 00000000..9ced18ba --- /dev/null +++ b/chapter14/valid/explicit_casts/ulong_to_double.c @@ -0,0 +1,14 @@ +/* Test conversions from unsigned long to double */ + +int main() { + // convert a value that's already in the range of signed long + unsigned long small = 138512825844ul; + double small_double = (double) small; + + // convert a value that's outside the range of signed long + unsigned long big = 10223372036854775816ul; + double big_double = (double) big; + + return (small_double == 138512825844.0 && big_double == 10223372036854775808.0); + +} \ No newline at end of file diff --git a/chapter14/valid/floating_expressions/and.c b/chapter14/valid/floating_expressions/and.c new file mode 100644 index 00000000..5271c15d --- /dev/null +++ b/chapter14/valid/floating_expressions/and.c @@ -0,0 +1,20 @@ +int main() { + + /* Test && with different combinations + * of zero and non-zero floating-point operands + */ + int and1 = 1.0 && 2.0; + int and2 = 0.0 && 2.0; + int and3 = 3.0 && 0.0; + + /* also test with mix of floating-point and integer operands */ + int and4 = 0.0 && 5l; + int and5 = -10 && 11111.1; + + /* Test cases where one operand is a variable */ + double zero = 0.0; + int and6 = zero && 5.0; + int and7 = 5.1 && zero; + + return and1 && !and2 && !and3 && !and4 && and5 && !and6 && !and7; +} \ No newline at end of file diff --git a/chapter14/valid/floating_expressions/basic_arithmetic.c b/chapter14/valid/floating_expressions/basic_arithmetic.c new file mode 100644 index 00000000..fb4c151f --- /dev/null +++ b/chapter14/valid/floating_expressions/basic_arithmetic.c @@ -0,0 +1,43 @@ +/* Test addition, subtraction, multiplication, division, and negation */ + +int main() { + + double two = 2.0; + double three = 3.0; + double four = 4.0; + + // addition + if (0.1 + 0.2 != 0.30000000000000004) + return 0; + + // subtraction + // test at least one operation where + // the first operand is a variable + if (four - 1.0 != 3.0) + return 0; + + // multiplication + if (0.01 * 0.3 != 0.003) + return 0; + + // division + // test at least one operation where + // the second operand is a variable + if (7.0 / two != 3.5) + return 0; + + // test negation when source operand is a variable + // we already test negating a constant elsewhere + double d = 12e30; + if (-d != 0.0 - 12e30) + return 0; + + /* Test a more complex expression. + * Note: all intermediate results in this expression + * can be represented exactly, so we don't need to + * consider the impact of rounding intermediate results. + */ + + double complex_expression = (two + three) - 127.5 * four; + return complex_expression == -505.0; +} \ No newline at end of file diff --git a/chapter14/valid/floating_expressions/comparisons.c b/chapter14/valid/floating_expressions/comparisons.c new file mode 100644 index 00000000..1503888b --- /dev/null +++ b/chapter14/valid/floating_expressions/comparisons.c @@ -0,0 +1,37 @@ +/* Test comparisons on doubles */ +int main() { + + // Evaluate true and false case for each comparison operator + int greater_true = 55e5 > 54e4; + double four = 4.; + // make sure we test at least one comparison + // where the second operand is a variable + int greater_false = -55e5 > four; + + int less_true = -.00004 < 4.; + // make sure we test at least one comparison + // where the first operand is a variabl + int less_false = four < 4.0; + + int greater_or_equal_true = -10.0 >= -10.0; + int greater_or_equal_false = 00.00005 >= 5.e3; + + int less_or_equal_true = -25.0 <= -20.0; + int less_or_equal_false = -25.0 <= -26.0; + + int equal_true = 0.1 == 0.1; + int equal_false = 0.1 == 0.2; + + int not_equal_true = 10.0 != 1.1e1; + int not_equal_false = 10.0 != 10.0; + + // Make sure all cases that should be true are true + int all_trues = greater_true && less_true && greater_or_equal_true + && less_or_equal_true && equal_true && not_equal_true; + + // make sure all cases that should be false are false + int any_falses = greater_false || less_false || greater_or_equal_false || less_or_equal_false + || equal_false || not_equal_false; + + return all_trues && !any_falses; +} \ No newline at end of file diff --git a/chapter14/valid/floating_expressions/loop_controlling_expression.c b/chapter14/valid/floating_expressions/loop_controlling_expression.c new file mode 100644 index 00000000..65ddd03f --- /dev/null +++ b/chapter14/valid/floating_expressions/loop_controlling_expression.c @@ -0,0 +1,14 @@ +int main() { + int a = 0; + double d = 100.0; + // Use a floating-point number as the controlling expression in a while loop + // Normally this is a bad idea - rounding error might mean that the value will never + // be exactly zero, so the loop won't terminate. + // In this case we won't encounter rounding error, since we can exactly represent + // every integer between 0 and 100 as a double. + while (d) { + a = a + 1; + d = d - 1.0; + } + return a; +} \ No newline at end of file diff --git a/chapter14/valid/floating_expressions/not.c b/chapter14/valid/floating_expressions/not.c new file mode 100644 index 00000000..5bd17e0d --- /dev/null +++ b/chapter14/valid/floating_expressions/not.c @@ -0,0 +1,8 @@ +/* Test logical negation of doubles */ +int main() { + int not1 = !0.0; // this is zero + int not2 = !33.3e3; // this is not zero + int not3 = !1e-330; // this number is so small it will be rounded to zero + + return not1 && !not2 && not3; +} \ No newline at end of file diff --git a/chapter14/valid/floating_expressions/or.c b/chapter14/valid/floating_expressions/or.c new file mode 100644 index 00000000..c7e9885d --- /dev/null +++ b/chapter14/valid/floating_expressions/or.c @@ -0,0 +1,21 @@ +int main() { + + double not_zero = 2.5e-10; + double zero = 0.0; + + // this number is so small it will be rounded to zero + double rounded_to_zero = 1e-330; + + /* Test || with different combinations + * of zero and non-zero floating-point operands + */ + int or1 = not_zero || zero; + int or2 = 0.0 || rounded_to_zero; + int or3 = 0.0 || 25e10; + + /* Also test a mix of floating-point and integer operands */ + int or4 = 0 || rounded_to_zero; // both zero + int or5 = 0.00005 || 0; + + return or1 && !or2 && or3 && !or4 && or5; +} \ No newline at end of file diff --git a/chapter14/valid/function_calls/double_and_int_parameters.c b/chapter14/valid/function_calls/double_and_int_parameters.c new file mode 100644 index 00000000..0cc231fa --- /dev/null +++ b/chapter14/valid/function_calls/double_and_int_parameters.c @@ -0,0 +1,11 @@ +/* Test that we've properly implemented the calling convention for passing doubles and ints in registers */ +int check_arguments(double d1, double d2, int i1, double d3, double d4, int i2, int i3, + int i4, double d5, double d6, double d7, int i5, double d8) { + return d1 == 1.0 && d2 == 2.0 && d3 == 3.0 && d4 == 4.0 && d5 == 5.0 + && d6 == 6.0 && d7 == 7.0 && d8 == 8.0 && i1 == 101 && i2 == 102 && i3 == 103 + && i4 == 104 && i5 == 105; +} + +int main() { + return check_arguments(1.0, 2.0, 101, 3.0, 4.0, 102, 103, 104, 5.0, 6.0, 7.0, 105, 8.0); +} \ No newline at end of file diff --git a/chapter14/valid/function_calls/double_and_int_params_recursive.c b/chapter14/valid/function_calls/double_and_int_params_recursive.c new file mode 100644 index 00000000..de7ca6b8 --- /dev/null +++ b/chapter14/valid/function_calls/double_and_int_params_recursive.c @@ -0,0 +1,20 @@ +/* A recursive function in which both double and integer parameters + * are passed in registers and on the stack */ +double fun(int a, double m, int b, double n, int c, double o, + int d, double p, int e, double q, int f, double r, + int g, double s, int h, double t, int i, double u) { + if (a + b + c + d + e + f + g + h + i <= 0) { + if (m + n + o + p + q <= 0.0) { + return s + t + u; + } else { + return fun(a, m - 1.0, b, n, c, o, d, p, e, q, f, r, g, s + 1.0, h, t, i, u); + } + } else { + return fun(a, m, b - 1, n, c, o, d, p, e, q, f, r, g, s, h, t, i, u); + } +} + +int main() { + double d = fun(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0, 15, 16.0, 17, 18.0); + return (d == 78.00); +} \ No newline at end of file diff --git a/chapter14/valid/function_calls/double_parameters.c b/chapter14/valid/function_calls/double_parameters.c new file mode 100644 index 00000000..199bf99f --- /dev/null +++ b/chapter14/valid/function_calls/double_parameters.c @@ -0,0 +1,11 @@ +/* Test that we've properly implemented the calling convention for double parameters passed in registers */ +int check_arguments(double a, double b, double c, double d, double e, double f, double g, double h); + +int main() { + return check_arguments(1.0, 2.0, 3.0, 4.0, -1.0, -2.0, -3.0, -4.0); +} + +int check_arguments(double a, double b, double c, double d, double e, double f, double g, double h) { + return a == 1.0 && b == 2.0 && c == 3.0 && d == 4.0 + && e == -1.0 && f == -2.0 && g == -3.0 && h == -4.0; +} \ No newline at end of file diff --git a/chapter14/valid/function_calls/return_double.c b/chapter14/valid/function_calls/return_double.c new file mode 100644 index 00000000..bcd82e85 --- /dev/null +++ b/chapter14/valid/function_calls/return_double.c @@ -0,0 +1,9 @@ +/* Test that we follow the calling convention for a double return type */ +double d() { + return 1234.e75; +} + +int main() { + double retval = d(); + return retval == 1234.e75; +} \ No newline at end of file diff --git a/chapter14/valid/function_calls/standard_library_call.c b/chapter14/valid/function_calls/standard_library_call.c new file mode 100644 index 00000000..12f9c052 --- /dev/null +++ b/chapter14/valid/function_calls/standard_library_call.c @@ -0,0 +1,16 @@ +/* Make sure we can call floating-point functions from the standard library */ + +/* Declare these functions since we can't #include */ + +// fused multiply and add: (x * y) + z +// note: only the final result of the whole calculation is rounded, +// not the intermediate result x * y +double fma(double x, double y, double z); + +double ldexp(double x, int exp); // x * 2^exp + +int main() { + double fma_result = fma(5.0, 1E22, 4000000.0); + double ldexp_result = ldexp(92E73, 5); + return fma_result == 50000000000000004194304.0 && ldexp_result == 2.944E76; +} \ No newline at end of file diff --git a/chapter14/valid/function_calls/use_arg_after_fun_call.c b/chapter14/valid/function_calls/use_arg_after_fun_call.c new file mode 100644 index 00000000..e1d5fcb0 --- /dev/null +++ b/chapter14/valid/function_calls/use_arg_after_fun_call.c @@ -0,0 +1,18 @@ +/* In this function, the parameter x and + * the return value are both passed in XMM0. + * We make a recursive call to fun, then use x, + * to make sure that x's value is preserved + * across the function call. + */ +double fun(double x) { + if (x > 2) + return x; + else { + double ret = fun(x + 2); + return ret + x; + } +} + +int main() { + return fun(1.0); +} \ No newline at end of file diff --git a/chapter14/valid/implicit_casts/comparison_common_type.c b/chapter14/valid/implicit_casts/comparison_common_type.c new file mode 100644 index 00000000..893d321b --- /dev/null +++ b/chapter14/valid/implicit_casts/comparison_common_type.c @@ -0,0 +1,15 @@ +/* Test that we perform the usual arithmetic conversions + * correctly on the operands of comparisons + */ +int main() { + double d = -9007199254751228.0; + long l = -9007199254751227l; + + /* This should return 0! + * When we compare d to l, we implicitly + * cast l to a double. The closest representable + * double is -9007199254751228.0, which is equal to d, + * not greater than d + */ + return (d < l); +} \ No newline at end of file diff --git a/chapter14/valid/implicit_casts/complex_arithmetic_common_type.c b/chapter14/valid/implicit_casts/complex_arithmetic_common_type.c new file mode 100644 index 00000000..a8ded708 --- /dev/null +++ b/chapter14/valid/implicit_casts/complex_arithmetic_common_type.c @@ -0,0 +1,18 @@ +/* Test that when we evaluate a complex expression, + * we perform the usual arithmetic conversions correctly + * for each sub-expression + */ + +int main() { + unsigned long ul = 10000ul; + int i = -50; + /* When we calculate ul + i, we first promote + * i to an unsigned long with value 2^64 - 50, + * so ul + i will wrap around to 9950. + * We'll promote this value to a double + * and then multiply it by 3.125, resulting in + * 31093.75 + */ + double d = (ul + i) * 3.125; + return d == 31093.75; +} \ No newline at end of file diff --git a/chapter14/valid/implicit_casts/convert_for_assignment.c b/chapter14/valid/implicit_casts/convert_for_assignment.c new file mode 100644 index 00000000..535815f7 --- /dev/null +++ b/chapter14/valid/implicit_casts/convert_for_assignment.c @@ -0,0 +1,9 @@ +/* Convert the right-hand operand of an assignment statement + * to the type of the left-hand operand + */ +int main() { + double d = 18446744073709551586ul; // implicitly convert to nearest double + int i = 4.9; //implicitly truncate to integer + + return (d == 18446744073709551616. && i == 4); +} \ No newline at end of file diff --git a/chapter14/valid/implicit_casts/convert_function_argument.c b/chapter14/valid/implicit_casts/convert_function_argument.c new file mode 100644 index 00000000..1ca86715 --- /dev/null +++ b/chapter14/valid/implicit_casts/convert_function_argument.c @@ -0,0 +1,8 @@ +int f(long l, double d) { + return l == 2 && d == -6.0; +} + +int main() { + /* Implicitly convert function arguments to the correct type */ + return f(2.4, -6); +} \ No newline at end of file diff --git a/chapter14/valid/implicit_casts/convert_return_value.c b/chapter14/valid/implicit_casts/convert_return_value.c new file mode 100644 index 00000000..52682d6b --- /dev/null +++ b/chapter14/valid/implicit_casts/convert_return_value.c @@ -0,0 +1,10 @@ +double d() { + // Implicitly convert this integer to the nearest double, + // which is 18446744073709551616.0 + return 18446744073709551586ul; +} + +int main() { + double retval = d(); + return (retval < 19000000000000000000.0 && retval > 18000000000000000000.0); +} \ No newline at end of file diff --git a/chapter14/valid/implicit_casts/multiplication_common_type.c b/chapter14/valid/implicit_casts/multiplication_common_type.c new file mode 100644 index 00000000..2731c1de --- /dev/null +++ b/chapter14/valid/implicit_casts/multiplication_common_type.c @@ -0,0 +1,14 @@ +/* Test that we perform the usual arithmetic conversions + * correctly on the operands of arithmetic operations + */ +int main() { + /* This should promote 10 to a double, + * calculate 10.75 * 10.0, which is 107.5, + * and then truncate back to an int, 107. + * It should not truncate 10.75 to 10 before + * performing the calculation. + */ + int i = 10.75 * 10; + + return i == 107; +} \ No newline at end of file diff --git a/chapter14/valid/implicit_casts/ternary_common_type.c b/chapter14/valid/implicit_casts/ternary_common_type.c new file mode 100644 index 00000000..1da6cede --- /dev/null +++ b/chapter14/valid/implicit_casts/ternary_common_type.c @@ -0,0 +1,19 @@ +/* Test that we perform the usual arithmetic operations correctly in ternary expressions */ +int main() { + // If the first operand of a ternary operator is a double, + // you don't need to convert the second and third operands to double. + // In this case we'll converting the second and third operands to the common type + // of int and unsigned long, which is unsigned long. THEN this is converted + // to a double when assigned to x. + double x = 2.0 ? -30 : 10ul; + + // If the second operand of a ternary operator is a double, + // you must convert the third operand to double, and vice versa. + double y = 0 ? 5.0 : 9223372036854777850ul; + + // Converting -30 to unsigned long gives us 2^64 - 30 + // Converting 9223372036854777850 to a double gives us + // 9223372036854777856.0 + return x == 18446744073709551586.0 && + y == 9223372036854777856.0; +} \ No newline at end of file diff --git a/chapter14/valid/libraries/double_and_int_params_recursive.c b/chapter14/valid/libraries/double_and_int_params_recursive.c new file mode 100644 index 00000000..cd8b9cab --- /dev/null +++ b/chapter14/valid/libraries/double_and_int_params_recursive.c @@ -0,0 +1,13 @@ +double fun(int a, double m, int b, double n, int c, double o, + int d, double p, int e, double q, int f, double r, + int g, double s, int h, double t, int i, double u) { + if (a + b + c + d + e + f + g + h + i <= 0) { + if (m + n + o + p + q <= 0.0) { + return s + t + u; + } else { + return fun(a, m - 1.0, b, n, c, o, d, p, e, q, f, r, g, s + 1.0, h, t, i, u); + } + } else { + return fun(a, m, b - 1, n, c, o, d, p, e, q, f, r, g, s, h, t, i, u); + } +} \ No newline at end of file diff --git a/chapter14/valid/libraries/double_and_int_params_recursive_client.c b/chapter14/valid/libraries/double_and_int_params_recursive_client.c new file mode 100644 index 00000000..e9117165 --- /dev/null +++ b/chapter14/valid/libraries/double_and_int_params_recursive_client.c @@ -0,0 +1,10 @@ +/* This test case is identical to chapter14/valid/function_calls/double_and_int_params_recursive.c + * but split across two files */ +double fun(int a, double m, int b, double n, int c, double o, + int d, double p, int e, double q, int f, double r, + int g, double s, int h, double t, int i, double u); + +int main() { + double d = fun(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0, 15, 16.0, 17, 18.0); + return (d == 78.00); +} \ No newline at end of file diff --git a/chapter14/valid/libraries/double_parameters.c b/chapter14/valid/libraries/double_parameters.c new file mode 100644 index 00000000..b50772e6 --- /dev/null +++ b/chapter14/valid/libraries/double_parameters.c @@ -0,0 +1,4 @@ +int check_arguments(double a, double b, double c, double d, double e, double f, double g, double h) { + return a == 1.0 && b == 2.0 && c == 3.0 && d == 4.0 + && e == -1.0 && f == -2.0 && g == -3.0 && h == -4.0; +} \ No newline at end of file diff --git a/chapter14/valid/libraries/double_parameters_client.c b/chapter14/valid/libraries/double_parameters_client.c new file mode 100644 index 00000000..3ee207ce --- /dev/null +++ b/chapter14/valid/libraries/double_parameters_client.c @@ -0,0 +1,7 @@ +/* This test case is identical to chapter14/valid/function_calls/double_parameters.c + * but split across two files */ +int check_arguments(double a, double b, double c, double d, double e, double f, double g, double h); + +int main() { + return check_arguments(1.0, 2.0, 3.0, 4.0, -1.0, -2.0, -3.0, -4.0); +} \ No newline at end of file diff --git a/chapter14/valid/libraries/extern_double.c b/chapter14/valid/libraries/extern_double.c new file mode 100644 index 00000000..9a273721 --- /dev/null +++ b/chapter14/valid/libraries/extern_double.c @@ -0,0 +1 @@ +double d = 1e20; \ No newline at end of file diff --git a/chapter14/valid/libraries/extern_double_client.c b/chapter14/valid/libraries/extern_double_client.c new file mode 100644 index 00000000..0458a3c8 --- /dev/null +++ b/chapter14/valid/libraries/extern_double_client.c @@ -0,0 +1,6 @@ +/* Test linking against a double defined in another file */ +extern double d; + +int main() { + return d == 1e20; +} \ No newline at end of file diff --git a/chapter14/valid/libraries/use_arg_after_fun_call.c b/chapter14/valid/libraries/use_arg_after_fun_call.c new file mode 100644 index 00000000..94a4b39e --- /dev/null +++ b/chapter14/valid/libraries/use_arg_after_fun_call.c @@ -0,0 +1,8 @@ +double fun(double x) { + if (x > 2) + return x; + else { + double ret = fun(x + 2); + return ret + x; + } +} diff --git a/chapter14/valid/libraries/use_arg_after_fun_call_client.c b/chapter14/valid/libraries/use_arg_after_fun_call_client.c new file mode 100644 index 00000000..d7339eb6 --- /dev/null +++ b/chapter14/valid/libraries/use_arg_after_fun_call_client.c @@ -0,0 +1,7 @@ +/* This test case is identical to chapter14/valid/function_calls/use_arg_after_fun_call.c + * but split across two files */ +double fun(double x); + +int main() { + return fun(1.0); +} \ No newline at end of file diff --git a/chapter14/valid/special_values/const_infinity.c b/chapter14/valid/special_values/const_infinity.c new file mode 100644 index 00000000..fd8a25bb --- /dev/null +++ b/chapter14/valid/special_values/const_infinity.c @@ -0,0 +1,20 @@ +/* Test that we round constants to infinity + * if they're too large to represent as finite doubles + */ +int main() { + /* These two values are larger than the largest finite double, + * so they should be converted to infinity + */ + double inf1 = 2e308; + double inf2 = 11e330; + /* This should round to the largest finite double */ + double very_large = 1.79E308; + + if (inf1 != inf2) + return 0; + + if (inf1 <= very_large) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter14/valid/special_values/copysign.c b/chapter14/valid/special_values/copysign.c new file mode 100644 index 00000000..cd4949b0 --- /dev/null +++ b/chapter14/valid/special_values/copysign.c @@ -0,0 +1,11 @@ +/* Test that we can check the sign of zero with the copysign function */ + +// copysign is defined in the C standard library () +double copysign(double x, double y); + +int main() { + // copy the sign from -0.0 to 4.0, producing -4.0 + double negated = copysign(4.0, -0.0); + double positive = copysign(-5.0, 0.0); + return (negated == -4.0 && positive == 5.0); +} \ No newline at end of file diff --git a/chapter14/valid/special_values/negative_and_positive_zero.c b/chapter14/valid/special_values/negative_and_positive_zero.c new file mode 100644 index 00000000..484ad4c2 --- /dev/null +++ b/chapter14/valid/special_values/negative_and_positive_zero.c @@ -0,0 +1,19 @@ +int main() +{ + // make sure negative and positive zero are distinct constants + double negative_zero = -0.0; + double positive_zero = 0.0; + + if (negative_zero != positive_zero) + return 0; + + // a positive number divided by negative zero is negative infinity + if (1 / negative_zero != -10e308) + return 0; + + // a positive number divided by zero is positive infinity + if (1 / positive_zero != 10e308) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter14/valid/special_values/negative_infinity.c b/chapter14/valid/special_values/negative_infinity.c new file mode 100644 index 00000000..d6cf67bf --- /dev/null +++ b/chapter14/valid/special_values/negative_infinity.c @@ -0,0 +1,10 @@ +/* Test that we correctly handle negative infinity */ +int main() { + double negated_inf = -2E308; + + /* make sure that -1/0 is negative infinity */ + double zero = 0.0; + double calculated_neg_inf = -1.0 / zero; + + return (calculated_neg_inf < -1E308 && calculated_neg_inf == negated_inf); +} \ No newline at end of file diff --git a/chapter14/valid/special_values/negative_zero.c b/chapter14/valid/special_values/negative_zero.c new file mode 100644 index 00000000..49171322 --- /dev/null +++ b/chapter14/valid/special_values/negative_zero.c @@ -0,0 +1,24 @@ +/* Test that we handle negative zero correctly */ +int main() { + double negative_zero = -0.0; + + // 0.0 and -0.0 should compare equal + if (negative_zero != 0) + return 0; + + // a positive number divided by negative zero is negative infinity + if ( 1/negative_zero != -10e308 ) + return 0; + + // a negative number divided by negative zero is positive infinity + if ( (-10)/negative_zero != 10e308) + return 0; + + // make sure -0.0 short-circuits boolean expressions + int fail = 0; + -0.0 && (fail = 1); + if (fail) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter14/valid/special_values/positive_infinity.c b/chapter14/valid/special_values/positive_infinity.c new file mode 100644 index 00000000..21f2b69c --- /dev/null +++ b/chapter14/valid/special_values/positive_infinity.c @@ -0,0 +1,10 @@ +/* Test that we handle infinity correctly */ +int main() { + double const_inf = 2E308; // this constant will overflow to infinity + + /* make sure that 1/0 is infinity */ + double zero = 0.0; + double calculated_inf = 1.0 / zero; + + return (calculated_inf > 1E308 && calculated_inf == const_inf); +} \ No newline at end of file diff --git a/chapter14/valid/special_values/subnormal_not_zero.c b/chapter14/valid/special_values/subnormal_not_zero.c new file mode 100644 index 00000000..ba31c73c --- /dev/null +++ b/chapter14/valid/special_values/subnormal_not_zero.c @@ -0,0 +1,8 @@ +int main() { + + /* Make sure subnormal numbers are not rounded to zero */ + double subnormal = 2.5e-320; + + // subnormal is non-zero, so !subnormal should be zero + return !subnormal; +} \ No newline at end of file diff --git a/chapter14/valid/static_variables/static_double.c b/chapter14/valid/static_variables/static_double.c new file mode 100644 index 00000000..13052490 --- /dev/null +++ b/chapter14/valid/static_variables/static_double.c @@ -0,0 +1,6 @@ +double static d; + +int main() { + // Make sure static doubles are initialized to 0 if no initializer is provided + return !d; +} \ No newline at end of file diff --git a/chapter14/valid/static_variables/static_double_initialized_from_int.c b/chapter14/valid/static_variables/static_double_initialized_from_int.c new file mode 100644 index 00000000..58a397ce --- /dev/null +++ b/chapter14/valid/static_variables/static_double_initialized_from_int.c @@ -0,0 +1,27 @@ +/* Test out converting initializers from an integer type to a double at compile time */ + +// can convert from int/uint without rounding +double a = 2147483647; +double b = 4294967295u; + +/* midway point between 4611686018427388928.0 and 4611686018427389952.0 + * We round ties to even, so round this up to 4611686018427389952.0 + */ +double c = 4611686018427389440l; +double c2 = 4611686018427389955l; + +/* Using round-to-nearest, this rounds to 9223372036854775808 */ +double d = 9223372036854775810ul; + +/* This is exactly halfway between 9223372036854775808.0 and + * 9223372036854777856.0 We round ties to even, so this + * rounds down to 9223372036854775808.0 + */ +double e = 9223372036854776832ul; + +int main() +{ + // we use round-to-nearest, ties-to-even rounding + // to convert from int to double at compile time + return a == 2147483647. && b == 4294967295. && c == 4611686018427389952. && d == 9223372036854775808. && c == c2 && e == d; +} \ No newline at end of file diff --git a/chapter14/valid/static_variables/static_initialized_double.c b/chapter14/valid/static_variables/static_initialized_double.c new file mode 100644 index 00000000..ccde655c --- /dev/null +++ b/chapter14/valid/static_variables/static_initialized_double.c @@ -0,0 +1,16 @@ +// Test an explicitly initialized static double + +// Return old value increment by one +double return_static_variable() { + static double d = 0.5; + double ret = d; + d = d + 1.0; + return ret; +} + +int main() { + double d1 = return_static_variable(); + double d2 = return_static_variable(); + double d3 = return_static_variable(); + return (d1 == 0.5 && d2 == 1.5 && d3 == 2.5); +} diff --git a/chapter14/valid/static_variables/static_int_initialized_from_double.c b/chapter14/valid/static_variables/static_int_initialized_from_double.c new file mode 100644 index 00000000..380e3998 --- /dev/null +++ b/chapter14/valid/static_variables/static_int_initialized_from_double.c @@ -0,0 +1,17 @@ +/* Test out converting an initializer from a double to an int at compile time */ + +// this is converted to 4 +static int i = 4.9; + +int unsigned u = 42949.672923E5; + +// this token is first converted to a double w/ value 4611686018427389952.0, +// then truncated down to long 4611686018427389952 +long l = 4611686018427389440.; + +unsigned long ul = 18446744073709549568.; + +int main() +{ + return i == 4 && u == 4294967292u && l == 4611686018427389952l && ul == 18446744073709549568ul; +} \ No newline at end of file diff --git a/chapter14/valid_extra_credit/compound_assign.c b/chapter14/valid_extra_credit/compound_assign.c new file mode 100644 index 00000000..e81c90a4 --- /dev/null +++ b/chapter14/valid_extra_credit/compound_assign.c @@ -0,0 +1,6 @@ +/* Test compound assignmen with doubles */ +int main() { + double d = 10.0; + d /= 4.0; + return (d == 2.5); +} \ No newline at end of file diff --git a/chapter14/valid_extra_credit/compound_assign_implicit_cast.c b/chapter14/valid_extra_credit/compound_assign_implicit_cast.c new file mode 100644 index 00000000..4e6855d3 --- /dev/null +++ b/chapter14/valid_extra_credit/compound_assign_implicit_cast.c @@ -0,0 +1,23 @@ +int main() { + double d = 1000.5; + /* When we perform compound assignment, we convert both operands + * to their common type, operate on them, and convert the result to the + * type of the left operand */ + d += 1000; + + unsigned long e = 18446744073709551586ul; + /* We'll promote e to the nearest double, + * which is 18446744073709551616, + * then subtract 1.5 * 10^19, which + * results in 3446744073709551616.0, + * then convert it back to an unsigned long + */ + e -= 1.5E19; + + /* We'll promote i to a double, add .99999, + * then truncate it back to an int + */ + int i = 10; + i += 0.99999; + return (d == 2000.5 && e == 3446744073709551616 && i == 10); +} \ No newline at end of file diff --git a/chapter14/valid_extra_credit/nan.c b/chapter14/valid_extra_credit/nan.c new file mode 100644 index 00000000..8b5897c9 --- /dev/null +++ b/chapter14/valid_extra_credit/nan.c @@ -0,0 +1,13 @@ +// Test that we handle NaN correctly + +// This should return zero, because all comparisons with NaN are false +int main() { + double nan = 0.0 / 0.0; + if (nan < 0.0 || nan == 0.0 || nan > 0.0) + return 1; + + if (nan == nan) + return 1; + + return 0; +} \ No newline at end of file From 6a65fe1a7905b505e4cbb931a4070fba4e2977cd Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Mon, 6 Mar 2023 10:53:39 -0800 Subject: [PATCH 005/167] chapter 15 tests --- .../abstract_function_declarator.c | 12 ++++ chapter15/invalid_parse/cast_to_declarator.c | 5 ++ .../malformed_abstract_declarator.c | 8 +++ chapter15/invalid_parse/malformed_and.c | 4 ++ .../invalid_parse/malformed_declarator.c | 8 +++ chapter15/invalid_types/address_of_address.c | 9 +++ .../invalid_types/address_of_assignment.c | 9 +++ chapter15/invalid_types/address_of_constant.c | 5 ++ chapter15/invalid_types/address_of_ternary.c | 11 +++ .../invalid_types/assign_int_to_pointer.c | 9 +++ .../invalid_types/assign_int_var_to_pointer.c | 7 ++ chapter15/invalid_types/assign_to_address.c | 5 ++ .../assign_unsigned_long_to_pointer.c | 7 ++ .../invalid_types/assign_wrong_pointer_type.c | 7 ++ .../invalid_types/bad_null_pointer_constant.c | 6 ++ .../invalid_types/cast_double_to_pointer.c | 7 ++ .../invalid_types/cast_pointer_to_double.c | 7 ++ .../compare_mixed_pointer_types.c | 6 ++ .../invalid_types/compare_pointer_to_ulong.c | 6 ++ chapter15/invalid_types/complement_pointer.c | 5 ++ .../invalid_types/dereference_non_pointer.c | 5 ++ chapter15/invalid_types/divide_pointer.c | 6 ++ .../invalid_static_initializer.c | 6 ++ chapter15/invalid_types/multiply_pointers.c | 6 ++ chapter15/invalid_types/multiply_pointers_2.c | 5 ++ chapter15/invalid_types/negate_pointer.c | 5 ++ chapter15/invalid_types/pass_pointer_as_int.c | 12 ++++ .../invalid_types/return_wrong_pointer_type.c | 15 ++++ .../ternary_mixed_pointer_types.c | 9 +++ .../bitwise_or_pointer.c | 6 ++ .../bitwise_shift_pointer.c | 5 ++ .../compound_divide_pointer.c | 9 +++ .../compound_multiply_pointer.c | 8 +++ .../switch_on_pointer.c | 10 +++ .../valid/comparisons/compare_pointers.c | 30 ++++++++ chapter15/valid/comparisons/compare_to_null.c | 15 ++++ .../comparisons/pointers_as_conditions.c | 43 +++++++++++ .../valid/declarators/abstract_declarators.c | 30 ++++++++ chapter15/valid/declarators/declarators.c | 72 +++++++++++++++++++ .../dereference/address_of_dereference.c | 19 +++++ .../dereference_expression_result.c | 27 +++++++ .../dereference/multilevel_indirection.c | 50 +++++++++++++ .../valid/dereference/pointer_to_static.c | 8 +++ .../valid/dereference/read_through_pointers.c | 41 +++++++++++ chapter15/valid/dereference/static_pointer.c | 15 ++++ .../dereference/update_through_pointers.c | 22 ++++++ .../function_calls/address_of_argument.c | 15 ++++ .../valid/function_calls/return_pointer.c | 21 ++++++ .../update_value_through_pointer_parameter.c | 12 ++++ .../cast_between_pointer_types.c | 19 +++++ .../type_conversions/cast_int_to_pointer.c | 7 ++ .../type_conversions/cast_pointer_to_int.c | 10 +++ .../valid/type_conversions/cast_round_trip.c | 33 +++++++++ .../null_pointer_conversion.c | 48 +++++++++++++ .../compound_assign_through_pointer.c | 8 +++ .../valid_extra_credit/incr_through_pointer.c | 7 ++ 56 files changed, 802 insertions(+) create mode 100644 chapter15/invalid_parse/abstract_function_declarator.c create mode 100644 chapter15/invalid_parse/cast_to_declarator.c create mode 100644 chapter15/invalid_parse/malformed_abstract_declarator.c create mode 100644 chapter15/invalid_parse/malformed_and.c create mode 100644 chapter15/invalid_parse/malformed_declarator.c create mode 100644 chapter15/invalid_types/address_of_address.c create mode 100644 chapter15/invalid_types/address_of_assignment.c create mode 100644 chapter15/invalid_types/address_of_constant.c create mode 100644 chapter15/invalid_types/address_of_ternary.c create mode 100644 chapter15/invalid_types/assign_int_to_pointer.c create mode 100644 chapter15/invalid_types/assign_int_var_to_pointer.c create mode 100644 chapter15/invalid_types/assign_to_address.c create mode 100644 chapter15/invalid_types/assign_unsigned_long_to_pointer.c create mode 100644 chapter15/invalid_types/assign_wrong_pointer_type.c create mode 100644 chapter15/invalid_types/bad_null_pointer_constant.c create mode 100644 chapter15/invalid_types/cast_double_to_pointer.c create mode 100644 chapter15/invalid_types/cast_pointer_to_double.c create mode 100644 chapter15/invalid_types/compare_mixed_pointer_types.c create mode 100644 chapter15/invalid_types/compare_pointer_to_ulong.c create mode 100644 chapter15/invalid_types/complement_pointer.c create mode 100644 chapter15/invalid_types/dereference_non_pointer.c create mode 100644 chapter15/invalid_types/divide_pointer.c create mode 100644 chapter15/invalid_types/invalid_static_initializer.c create mode 100644 chapter15/invalid_types/multiply_pointers.c create mode 100644 chapter15/invalid_types/multiply_pointers_2.c create mode 100644 chapter15/invalid_types/negate_pointer.c create mode 100644 chapter15/invalid_types/pass_pointer_as_int.c create mode 100644 chapter15/invalid_types/return_wrong_pointer_type.c create mode 100644 chapter15/invalid_types/ternary_mixed_pointer_types.c create mode 100644 chapter15/invalid_types_extra_credit/bitwise_or_pointer.c create mode 100644 chapter15/invalid_types_extra_credit/bitwise_shift_pointer.c create mode 100644 chapter15/invalid_types_extra_credit/compound_divide_pointer.c create mode 100644 chapter15/invalid_types_extra_credit/compound_multiply_pointer.c create mode 100644 chapter15/invalid_types_extra_credit/switch_on_pointer.c create mode 100644 chapter15/valid/comparisons/compare_pointers.c create mode 100644 chapter15/valid/comparisons/compare_to_null.c create mode 100644 chapter15/valid/comparisons/pointers_as_conditions.c create mode 100644 chapter15/valid/declarators/abstract_declarators.c create mode 100644 chapter15/valid/declarators/declarators.c create mode 100644 chapter15/valid/dereference/address_of_dereference.c create mode 100644 chapter15/valid/dereference/dereference_expression_result.c create mode 100644 chapter15/valid/dereference/multilevel_indirection.c create mode 100644 chapter15/valid/dereference/pointer_to_static.c create mode 100644 chapter15/valid/dereference/read_through_pointers.c create mode 100644 chapter15/valid/dereference/static_pointer.c create mode 100644 chapter15/valid/dereference/update_through_pointers.c create mode 100644 chapter15/valid/function_calls/address_of_argument.c create mode 100644 chapter15/valid/function_calls/return_pointer.c create mode 100644 chapter15/valid/function_calls/update_value_through_pointer_parameter.c create mode 100644 chapter15/valid/type_conversions/cast_between_pointer_types.c create mode 100644 chapter15/valid/type_conversions/cast_int_to_pointer.c create mode 100644 chapter15/valid/type_conversions/cast_pointer_to_int.c create mode 100644 chapter15/valid/type_conversions/cast_round_trip.c create mode 100644 chapter15/valid/type_conversions/null_pointer_conversion.c create mode 100644 chapter15/valid_extra_credit/compound_assign_through_pointer.c create mode 100644 chapter15/valid_extra_credit/incr_through_pointer.c diff --git a/chapter15/invalid_parse/abstract_function_declarator.c b/chapter15/invalid_parse/abstract_function_declarator.c new file mode 100644 index 00000000..3b688fed --- /dev/null +++ b/chapter15/invalid_parse/abstract_function_declarator.c @@ -0,0 +1,12 @@ +int main() { + /* The abstract declarator (int ()) is malformed: + * we can't parse abstract function declarators. + * In a fully C standard-compliant implementation, + * this would be a type error rather than a parser error: + * "int ()" would be valid declarator for a function + * with no parameters that returns an int, + * but you can't cast an expression to a function type. + */ + (int ()) 0; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_parse/cast_to_declarator.c b/chapter15/invalid_parse/cast_to_declarator.c new file mode 100644 index 00000000..07e97e4f --- /dev/null +++ b/chapter15/invalid_parse/cast_to_declarator.c @@ -0,0 +1,5 @@ +int main() +{ + // can only cast to declarator types, not abstract declarators + return (int **a)(10); +} \ No newline at end of file diff --git a/chapter15/invalid_parse/malformed_abstract_declarator.c b/chapter15/invalid_parse/malformed_abstract_declarator.c new file mode 100644 index 00000000..4b8a02be --- /dev/null +++ b/chapter15/invalid_parse/malformed_abstract_declarator.c @@ -0,0 +1,8 @@ +int main() { + /* This abstract declarator is malformed. + * Pointer declarators like * cannot appear after + * parenthesized expressions + */ + (int (*)*) 10; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_parse/malformed_and.c b/chapter15/invalid_parse/malformed_and.c new file mode 100644 index 00000000..f9b4970e --- /dev/null +++ b/chapter15/invalid_parse/malformed_and.c @@ -0,0 +1,4 @@ +int main() +{ + return 1 & &2; +} \ No newline at end of file diff --git a/chapter15/invalid_parse/malformed_declarator.c b/chapter15/invalid_parse/malformed_declarator.c new file mode 100644 index 00000000..600f0e6b --- /dev/null +++ b/chapter15/invalid_parse/malformed_declarator.c @@ -0,0 +1,8 @@ +int main() { + /* This declarator is malformed. + * Pointer declarators like * cannot appear after + * parenthesized expressions + */ + int (*)* y; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/address_of_address.c b/chapter15/invalid_types/address_of_address.c new file mode 100644 index 00000000..59c8c662 --- /dev/null +++ b/chapter15/invalid_types/address_of_address.c @@ -0,0 +1,9 @@ +/* The result of the & operator is not an lvalue, + * so it's illegal to take its address + */ +int main() { + int x = 0; + int *y = &x; + int **z = &(&x); + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/address_of_assignment.c b/chapter15/invalid_types/address_of_assignment.c new file mode 100644 index 00000000..0338f3b3 --- /dev/null +++ b/chapter15/invalid_types/address_of_assignment.c @@ -0,0 +1,9 @@ +/* The result of an assignment statement is not an lvalue, + * so it's illegal to take its address. + */ +int main() { + int x = 0; + int y = 0; + int *ptr = &(x = y); + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/address_of_constant.c b/chapter15/invalid_types/address_of_constant.c new file mode 100644 index 00000000..5d919cd8 --- /dev/null +++ b/chapter15/invalid_types/address_of_constant.c @@ -0,0 +1,5 @@ +/* A constant is not an lvalue, so it's illegal to take its address. */ +int main() { + int *ptr = &10; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/address_of_ternary.c b/chapter15/invalid_types/address_of_ternary.c new file mode 100644 index 00000000..db0c3ec1 --- /dev/null +++ b/chapter15/invalid_types/address_of_ternary.c @@ -0,0 +1,11 @@ +/* The result of a ternary expression is not + * an lvalue, even if the second and third operands + * are both variables, so it's illegal to take its address. + */ +int main() { + int x = 1; + int y = 2; + int z = 3; + int *ptr = &(x ? y : z); + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/assign_int_to_pointer.c b/chapter15/invalid_types/assign_int_to_pointer.c new file mode 100644 index 00000000..e957515a --- /dev/null +++ b/chapter15/invalid_types/assign_int_to_pointer.c @@ -0,0 +1,9 @@ +/* It's illegal to assign an integer to a pointer, + * because an integer cannot be implicitly converted + * to pointer type + */ +int main() { + int *x; + x = 10; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/assign_int_var_to_pointer.c b/chapter15/invalid_types/assign_int_var_to_pointer.c new file mode 100644 index 00000000..a1a6ded6 --- /dev/null +++ b/chapter15/invalid_types/assign_int_var_to_pointer.c @@ -0,0 +1,7 @@ +int main() +{ + int x = 0; + // can't initialize pointer with value of type int + // note that x isn't a null pointer onstant even though its value is 0 + int *ptr = x; +} \ No newline at end of file diff --git a/chapter15/invalid_types/assign_to_address.c b/chapter15/invalid_types/assign_to_address.c new file mode 100644 index 00000000..2f1bd9ec --- /dev/null +++ b/chapter15/invalid_types/assign_to_address.c @@ -0,0 +1,5 @@ +int main() +{ + int x = 0; + &x = 10; // can't assing to address-of operator +} \ No newline at end of file diff --git a/chapter15/invalid_types/assign_unsigned_long_to_pointer.c b/chapter15/invalid_types/assign_unsigned_long_to_pointer.c new file mode 100644 index 00000000..a8959edf --- /dev/null +++ b/chapter15/invalid_types/assign_unsigned_long_to_pointer.c @@ -0,0 +1,7 @@ +int main() +{ + // can't assign an unsigned long to a pointer even though + // it could conceivably be a valid memory address + int *ptr = 140732898195768ul; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/assign_wrong_pointer_type.c b/chapter15/invalid_types/assign_wrong_pointer_type.c new file mode 100644 index 00000000..f2173c67 --- /dev/null +++ b/chapter15/invalid_types/assign_wrong_pointer_type.c @@ -0,0 +1,7 @@ +int main() +{ + double *d = 0; + long *l = 0; + l = d; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/bad_null_pointer_constant.c b/chapter15/invalid_types/bad_null_pointer_constant.c new file mode 100644 index 00000000..9ef7eeac --- /dev/null +++ b/chapter15/invalid_types/bad_null_pointer_constant.c @@ -0,0 +1,6 @@ +int main() +{ + // only integers can be null pointer constants + int *x = 0.0; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/cast_double_to_pointer.c b/chapter15/invalid_types/cast_double_to_pointer.c new file mode 100644 index 00000000..00c02584 --- /dev/null +++ b/chapter15/invalid_types/cast_double_to_pointer.c @@ -0,0 +1,7 @@ +/* It's illegal to cast a double to a pointer */ + +int main() { + double d = 0.0; + int *x = (int *) d; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/cast_pointer_to_double.c b/chapter15/invalid_types/cast_pointer_to_double.c new file mode 100644 index 00000000..79e84b93 --- /dev/null +++ b/chapter15/invalid_types/cast_pointer_to_double.c @@ -0,0 +1,7 @@ +/* It's illegal to cast a pointer to a double */ + +int main() { + int *x; + double d = (double) x; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/compare_mixed_pointer_types.c b/chapter15/invalid_types/compare_mixed_pointer_types.c new file mode 100644 index 00000000..011cbbef --- /dev/null +++ b/chapter15/invalid_types/compare_mixed_pointer_types.c @@ -0,0 +1,6 @@ +/* It's illegal to compare two different pointer types */ +int main() { + int *x = 0ul; + unsigned *y = 0ul; + return x == y; +} \ No newline at end of file diff --git a/chapter15/invalid_types/compare_pointer_to_ulong.c b/chapter15/invalid_types/compare_pointer_to_ulong.c new file mode 100644 index 00000000..53c85576 --- /dev/null +++ b/chapter15/invalid_types/compare_pointer_to_ulong.c @@ -0,0 +1,6 @@ +/* It's illegal to compare a pointer to a value with a different type */ +int main() { + int *ptr = 0ul; // Initializing a pointer with a null constant is allowed + unsigned long ul = 0ul; + return ptr == ul; +} \ No newline at end of file diff --git a/chapter15/invalid_types/complement_pointer.c b/chapter15/invalid_types/complement_pointer.c new file mode 100644 index 00000000..0bc3d165 --- /dev/null +++ b/chapter15/invalid_types/complement_pointer.c @@ -0,0 +1,5 @@ +/* It's illegal to take the bitwise complement of a pointer. */ +int main() { + int *x = 0; + return (int) ~x; +} \ No newline at end of file diff --git a/chapter15/invalid_types/dereference_non_pointer.c b/chapter15/invalid_types/dereference_non_pointer.c new file mode 100644 index 00000000..761bec53 --- /dev/null +++ b/chapter15/invalid_types/dereference_non_pointer.c @@ -0,0 +1,5 @@ +/* It's illegal to dereference an expression with a non-pointer type */ +int main() { + unsigned long l = 100ul; + return *l; +} \ No newline at end of file diff --git a/chapter15/invalid_types/divide_pointer.c b/chapter15/invalid_types/divide_pointer.c new file mode 100644 index 00000000..75444d9e --- /dev/null +++ b/chapter15/invalid_types/divide_pointer.c @@ -0,0 +1,6 @@ +int main() +{ + int x = 10; + int *y = &x; + return (y / 8); +} \ No newline at end of file diff --git a/chapter15/invalid_types/invalid_static_initializer.c b/chapter15/invalid_types/invalid_static_initializer.c new file mode 100644 index 00000000..d6482ae0 --- /dev/null +++ b/chapter15/invalid_types/invalid_static_initializer.c @@ -0,0 +1,6 @@ +/* It's illegal to initialize a static pointer with a non-pointer value */ +static int *x = 10; + +int main() { + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/multiply_pointers.c b/chapter15/invalid_types/multiply_pointers.c new file mode 100644 index 00000000..6a2d9e5c --- /dev/null +++ b/chapter15/invalid_types/multiply_pointers.c @@ -0,0 +1,6 @@ +/* It's illegal to multiply, divide, or take the module of pointers */ +int main() { + int *x = 0; + int *y = x; + return (int) (x * y); +} \ No newline at end of file diff --git a/chapter15/invalid_types/multiply_pointers_2.c b/chapter15/invalid_types/multiply_pointers_2.c new file mode 100644 index 00000000..2cac2460 --- /dev/null +++ b/chapter15/invalid_types/multiply_pointers_2.c @@ -0,0 +1,5 @@ +int main() +{ + int *x = 0; + return (int)(0 * x); +} \ No newline at end of file diff --git a/chapter15/invalid_types/negate_pointer.c b/chapter15/invalid_types/negate_pointer.c new file mode 100644 index 00000000..423f1122 --- /dev/null +++ b/chapter15/invalid_types/negate_pointer.c @@ -0,0 +1,5 @@ +/* It's illegal to negate a pointer */ +int main() { + int *x = 0; + return (int) -x; +} \ No newline at end of file diff --git a/chapter15/invalid_types/pass_pointer_as_int.c b/chapter15/invalid_types/pass_pointer_as_int.c new file mode 100644 index 00000000..85ad5075 --- /dev/null +++ b/chapter15/invalid_types/pass_pointer_as_int.c @@ -0,0 +1,12 @@ +/* It's illegal to pass a pointer as a function argument + * where an integer is expected, beause you can't implicitly + * convert a pointer to an integer type + */ +int f(int i) { + return i; +} + +int main() { + int x; + return f(&x); +} \ No newline at end of file diff --git a/chapter15/invalid_types/return_wrong_pointer_type.c b/chapter15/invalid_types/return_wrong_pointer_type.c new file mode 100644 index 00000000..d86734ec --- /dev/null +++ b/chapter15/invalid_types/return_wrong_pointer_type.c @@ -0,0 +1,15 @@ +/* It's illegal to return an int * + * from a function with return type long * + * because you can't implicitly convert + * one pointer type to another + */ +int i; + +long *return_long_pointer() { + return &i; +} + +int main() { + long *l = return_long_pointer(); + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types/ternary_mixed_pointer_types.c b/chapter15/invalid_types/ternary_mixed_pointer_types.c new file mode 100644 index 00000000..b34d658b --- /dev/null +++ b/chapter15/invalid_types/ternary_mixed_pointer_types.c @@ -0,0 +1,9 @@ +/* It's illegal to use two distinct pointer types + * as the second and third operands of a ternary expression + */ +int main() { + long *x = 0; + int *y = 0; + int *result = 1 ? x : y; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types_extra_credit/bitwise_or_pointer.c b/chapter15/invalid_types_extra_credit/bitwise_or_pointer.c new file mode 100644 index 00000000..c32a9e83 --- /dev/null +++ b/chapter15/invalid_types_extra_credit/bitwise_or_pointer.c @@ -0,0 +1,6 @@ +/* It's illegal to apply bitwise |, &, or ^ to pointers */ +int main() { + int *x = 0; + int *y = 0; + return (int) (x | y); +} \ No newline at end of file diff --git a/chapter15/invalid_types_extra_credit/bitwise_shift_pointer.c b/chapter15/invalid_types_extra_credit/bitwise_shift_pointer.c new file mode 100644 index 00000000..6b39412d --- /dev/null +++ b/chapter15/invalid_types_extra_credit/bitwise_shift_pointer.c @@ -0,0 +1,5 @@ +/* It's illegal to apply left or right bitshift operations to pointers */ +int main() { + int *x = 0; + return (int) (x >> 10); +} \ No newline at end of file diff --git a/chapter15/invalid_types_extra_credit/compound_divide_pointer.c b/chapter15/invalid_types_extra_credit/compound_divide_pointer.c new file mode 100644 index 00000000..43c9185e --- /dev/null +++ b/chapter15/invalid_types_extra_credit/compound_divide_pointer.c @@ -0,0 +1,9 @@ +/* A pointer can't appear as the left or right operand + * of the *=, /=, or %= operator + */ +int main() { + int *x = 0; + int *y = 0; + x /= y; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types_extra_credit/compound_multiply_pointer.c b/chapter15/invalid_types_extra_credit/compound_multiply_pointer.c new file mode 100644 index 00000000..7f292e32 --- /dev/null +++ b/chapter15/invalid_types_extra_credit/compound_multiply_pointer.c @@ -0,0 +1,8 @@ +/* A pointer can't appear as the left or right operand + * of the *=, /=, or %= operator + */ +int main() { + int *x = 0; + x *= 2; + return 0; +} \ No newline at end of file diff --git a/chapter15/invalid_types_extra_credit/switch_on_pointer.c b/chapter15/invalid_types_extra_credit/switch_on_pointer.c new file mode 100644 index 00000000..4a4ce970 --- /dev/null +++ b/chapter15/invalid_types_extra_credit/switch_on_pointer.c @@ -0,0 +1,10 @@ +/* The controlling expression of a switch statement + * must be an integer, not a pointer + */ +int main() { + int *x = 0; + switch(x) { + case 0: return 0; + default: return 1; + } +} \ No newline at end of file diff --git a/chapter15/valid/comparisons/compare_pointers.c b/chapter15/valid/comparisons/compare_pointers.c new file mode 100644 index 00000000..05fbba51 --- /dev/null +++ b/chapter15/valid/comparisons/compare_pointers.c @@ -0,0 +1,30 @@ +/* Test comparing pointers with == and != */ + +int main() { + int a; + int b; + + int *a_ptr = &a; + int *a_ptr2 = &a; + int *b_ptr = &b; + + int eq_true = a_ptr == a_ptr2; + int eq_false = a_ptr == b_ptr; + + + int neq_true = a_ptr != b_ptr; + int neq_false = a_ptr != a_ptr2; + + // if you assign dereferenced value of one pointer to another, the pointers + // themselves are still not equal + *b_ptr = *a_ptr; + int neq_after_deref_assignment = a_ptr != b_ptr; + + // if you assign one pointer to another, they will be equal afterwards, + // just like any other variable + b_ptr = a_ptr; + int eq_after_assignment = b_ptr == a_ptr; + + return eq_true && !eq_false && neq_true && !neq_false + && eq_after_assignment && neq_after_deref_assignment; +} \ No newline at end of file diff --git a/chapter15/valid/comparisons/compare_to_null.c b/chapter15/valid/comparisons/compare_to_null.c new file mode 100644 index 00000000..7797a605 --- /dev/null +++ b/chapter15/valid/comparisons/compare_to_null.c @@ -0,0 +1,15 @@ +/* Test comparisons to several null pointer constants */ +int main() +{ + double x; + double *null = 0; + double *non_null = &x; + + int eq_zero_true = null == 0; + int eq_zero_false = non_null == 0l; + + int neq_zero_true = 0u != non_null; + int neq_zero_false = null != 0ul; + + return eq_zero_true && !eq_zero_false && neq_zero_true && !neq_zero_false; +} \ No newline at end of file diff --git a/chapter15/valid/comparisons/pointers_as_conditions.c b/chapter15/valid/comparisons/pointers_as_conditions.c new file mode 100644 index 00000000..0032f066 --- /dev/null +++ b/chapter15/valid/comparisons/pointers_as_conditions.c @@ -0,0 +1,43 @@ +/* Test out using pointers in boolean expressions or as controlling conditions, + * which implicitly compares them to zero + */ + +int main() +{ + long x; + long *ptr = &x; + long *null_ptr = 0; + + // note that pointers can appear in boolean expressions + // with operands of any other type + if (5.0 && null_ptr) + return 0; + + int a = 0; + if (!(ptr || (a = 10))) + return 0; + + // make sure the || expression short-circuited + if (a != 0) + return 0; + + // apply ! to pointer + if (!ptr) + return 0; + + // use a pointer in a ternary expression + int j = ptr ? 1 : 2; + int k = null_ptr ? 3 : 4; + if (!(j == 1 && k == 4)) + return 0; + + // use a pointer as the controlling condition in a loop + int i = 0; + while (ptr) + { + if (i > 10) + ptr = 0; + i = i + 1; + } + return i; +} \ No newline at end of file diff --git a/chapter15/valid/declarators/abstract_declarators.c b/chapter15/valid/declarators/abstract_declarators.c new file mode 100644 index 00000000..ac2e5458 --- /dev/null +++ b/chapter15/valid/declarators/abstract_declarators.c @@ -0,0 +1,30 @@ +/* Test out parsing a range of abstract declarators */ +int main() { + + long int unsigned *x = 0; + + /* Use a couple of equivalent abstract declarators + * to cast 0 to a pointer to unsigned long + */ + if (x != (unsigned long (*)) 0) + return 0; + + if (x != (long unsigned int ((((*))))) 0) + return 0; + + double ***y = 0; + + /* Use several equivalent abstract declarators + * to cast 0 to (double ***) + */ + if (y != (double *(**)) 0) + return 0; + + if (y != (double (***)) 0) + return 0; + + if ((double (*(*(*)))) 0 != y) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter15/valid/declarators/declarators.c b/chapter15/valid/declarators/declarators.c new file mode 100644 index 00000000..c72a7139 --- /dev/null +++ b/chapter15/valid/declarators/declarators.c @@ -0,0 +1,72 @@ +/* Test that we can parse a variety of function and variable declarators */ + +/* Multiple declarations of the function 'return_3' + * These declarations all have the same type so they don't conflict. + */ +int return_3(); +int(return_3()); +int(return_3)(); +int((return_3))() +{ + return 3; +} + +/* Multiple declarations of the function 'two_pointers' + * These declarations all have the same type so they don't conflict + */ +long l = 100; +long *two_pointers(double val, double *ptr) +{ + *ptr = val; + return &l; +} +long(*two_pointers(double val, double(*d))); +long *(two_pointers)(double val, double *(d)); +long *(two_pointers)(double val, double(*(d))); + +/* Multiple declarations of the function 'pointers_to_pointers' + * These declarations all have the same type so they don't conflict + */ +unsigned **pointers_to_pointers(int **p) +{ + static unsigned u; + static unsigned *u_ptr; + u_ptr = &u; + u = **p; + return &u_ptr; +} +unsigned(**(pointers_to_pointers(int *(*p)))); +unsigned *(*pointers_to_pointers(int(**p))); +unsigned(*(*((pointers_to_pointers)(int(*(*(p))))))); + +int main() +{ + /* Declare some variables using a variety of declarators */ + int i = 0; + int(*i_ptr) = &i; + int(**ptr_to_iptr) = &i_ptr; + + double(d1) = 0.0; + double d2 = 10.0; + + double *(d_ptr) = &d1; + + long(*(l_ptr)); + + unsigned *(*(ptr_to_uptr)); + + /* Use functions and variables we just declared */ + i = return_3(); // assign 3 to i + if (i != 3) + return 0; + + // call two_pointers and validate the results + l_ptr = two_pointers(d2, d_ptr); + if (*l_ptr != 100 || *d_ptr != 10.0) + return 0; + + // call pointers_to_pointers and validate the results + ptr_to_uptr = pointers_to_pointers(ptr_to_iptr); + + return **ptr_to_uptr == 3; +} \ No newline at end of file diff --git a/chapter15/valid/dereference/address_of_dereference.c b/chapter15/valid/dereference/address_of_dereference.c new file mode 100644 index 00000000..62c5098a --- /dev/null +++ b/chapter15/valid/dereference/address_of_dereference.c @@ -0,0 +1,19 @@ +/* Test that in the expression &*e, we just evaluate e and ignore the & and *. + * This is why &*null_ptr is valid, even though dereferencing a null pointer + * would normally produce a runtime error + */ +int main() { + int *null_ptr = 0; + if (&*null_ptr != 0) // &*null_ptr is equivalent to null_ptr + return 0; + + // do the same with multiple levels of indirection + int **ptr_to_null = &null_ptr; + + // &**ptr_to_null is equivalent to *ptr_to_null, + // which evaluates to the value of null_ptr + if (&**ptr_to_null != 0) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter15/valid/dereference/dereference_expression_result.c b/chapter15/valid/dereference/dereference_expression_result.c new file mode 100644 index 00000000..c1fea83d --- /dev/null +++ b/chapter15/valid/dereference/dereference_expression_result.c @@ -0,0 +1,27 @@ +/* Make sure we can dereference any expression of pointer type, + * not just variables */ + +int *return_pointer() { + static int var = 10; + return &var; +} + +int main() { + int val = 100; + int *ptr_var = &val; + + // First try reading pointers that result from function calls or ternary expressions + // return_pointer() evaluates to 10, the ternary expression evaluates to 100 + if (*return_pointer() + *(0 ? return_pointer() : ptr_var) != 110) + return 0; + + // Now try to update values through these pointers + *return_pointer() = 20; + *(1 ? ptr_var : return_pointer()) = 30; + + // Validate that the values of the pointed-to objects were updated + if (*return_pointer() != 20 || *ptr_var != 30) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter15/valid/dereference/multilevel_indirection.c b/chapter15/valid/dereference/multilevel_indirection.c new file mode 100644 index 00000000..803716d5 --- /dev/null +++ b/chapter15/valid/dereference/multilevel_indirection.c @@ -0,0 +1,50 @@ +/* Test that we correctly handle pointers to pointers */ +int main() { + double d = 10.0; + double *d_ptr = &d; + double **d_ptr_ptr = &d_ptr; + double ***d_ptr_ptr_ptr = &d_ptr_ptr; + + // read value of d through multiple levels of indirection + if (!(d == 10.0 && *d_ptr == 10.0 && **d_ptr_ptr == 10.0 + && ***d_ptr_ptr_ptr == 10.0)) + return 0; + + // read address of d through multiple levels of indirection + if (!(&d == d_ptr && *d_ptr_ptr == d_ptr && **d_ptr_ptr_ptr == d_ptr)) + return 0; + + // update value of d through multiple levels of indirection + ***d_ptr_ptr_ptr = 5.0; + if (!(d == 5.0 && *d_ptr == 5.0 && **d_ptr_ptr == 5.0 + && ***d_ptr_ptr_ptr == 5.0)) + return 0; + + // update addresses at different levels of indirection + double d2 = 1.0; + + // make both d2_ptr and d2_ptr2 point to same variable, d + double *d2_ptr = &d2; + double *d2_ptr2 = d2_ptr; + double **d2_ptr_ptr = &d2_ptr; + + *d_ptr_ptr_ptr = d2_ptr_ptr; + if (!(*d_ptr_ptr_ptr == d2_ptr_ptr && **d_ptr_ptr_ptr == d2_ptr + && **d_ptr_ptr_ptr == d2_ptr2 && ***d_ptr_ptr_ptr == d2)) + return 0; + + // even though d2_ptr and d2_ptr2 have the same value, + // they don't have the same address; + // d2_ptr_ptr points to d2_ptr but not d2_ptrs + if (d2_ptr_ptr == &d2_ptr2) + return 0; + + // changing the value of d2_ptr also changes *d2_ptr2 and **d_ptr_ptr_ptr + d2_ptr = d_ptr; + + if (!(**d_ptr_ptr_ptr == d_ptr && *d2_ptr_ptr == d_ptr + && **d_ptr_ptr_ptr != d2_ptr2 && ***d_ptr_ptr_ptr == 5.0)) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter15/valid/dereference/pointer_to_static.c b/chapter15/valid/dereference/pointer_to_static.c new file mode 100644 index 00000000..c2a42277 --- /dev/null +++ b/chapter15/valid/dereference/pointer_to_static.c @@ -0,0 +1,8 @@ +int x = 10; + +int main() +{ + int *static_ptr = &x; + x = 20; + return *static_ptr; +} \ No newline at end of file diff --git a/chapter15/valid/dereference/read_through_pointers.c b/chapter15/valid/dereference/read_through_pointers.c new file mode 100644 index 00000000..1e624fe8 --- /dev/null +++ b/chapter15/valid/dereference/read_through_pointers.c @@ -0,0 +1,41 @@ +/* Test reading values of several types through pointers */ +int main() { + + // define some variables + int i = -100; + unsigned long ul = 13835058055282163712ul; + double d = 3.5; + + //define some pointers to those variables + int *i_ptr = &i; + unsigned long *ul_ptr = &ul; + double *d_ptr = &d; + + // dereference each pointer and read value + if (*i_ptr != -100 || *ul_ptr != 13835058055282163712ul || *d_ptr != 3.5) + return 0; + + // update values, and make sure we can read updated values through pointers + i = 12; + ul = 1000; + d = -000.001; + + if (*i_ptr != 12 || *ul_ptr != 1000 || *d_ptr != -000.001) + return 0; + + // assign new values to the pointers, then make sure dereferencing them + // results in the values of the new objects they point to + int i2 = 1; + unsigned long ul2 = 144115196665790464ul; + double d2 = -33.3; + + i_ptr = &i2; + ul_ptr = &ul2; + d_ptr = &d2; + + if (*i_ptr != 1 || *ul_ptr != 144115196665790464ul || *d_ptr != -33.3) + return 0; + + return 1; + +} \ No newline at end of file diff --git a/chapter15/valid/dereference/static_pointer.c b/chapter15/valid/dereference/static_pointer.c new file mode 100644 index 00000000..35e917ee --- /dev/null +++ b/chapter15/valid/dereference/static_pointer.c @@ -0,0 +1,15 @@ +double *ptr; + +int increment_ptr() +{ + *ptr = *ptr + 5.0; + return 0; +} + +int main() +{ + double d = 10.0; + ptr = &d; + increment_ptr(); + return *ptr; +} \ No newline at end of file diff --git a/chapter15/valid/dereference/update_through_pointers.c b/chapter15/valid/dereference/update_through_pointers.c new file mode 100644 index 00000000..3ce2056e --- /dev/null +++ b/chapter15/valid/dereference/update_through_pointers.c @@ -0,0 +1,22 @@ +/* Test assigning to values of several types through pointers */ + +int main() { + // define some variables + unsigned int i = 2185232384u; + signed long l = 144115196665790464l; + double d = 1e50; + + // define pointers to those variables + unsigned *i_ptr = &i; + long *l_ptr = &l; + double *d_ptr = &d; + + // assign to dereferenced pointers + *i_ptr = 10; + *l_ptr = 20; + *d_ptr = 30.0; + + // check that pointed-to objects have updated values + return (i == 10 && l == 20 && d == 30.0); + +} \ No newline at end of file diff --git a/chapter15/valid/function_calls/address_of_argument.c b/chapter15/valid/function_calls/address_of_argument.c new file mode 100644 index 00000000..ca37bc1b --- /dev/null +++ b/chapter15/valid/function_calls/address_of_argument.c @@ -0,0 +1,15 @@ +/* Make sure we can take the address of function arguments, + * not just variables */ + +int addr_of_arg(int a) { + int *ptr = &a; + *ptr = 10; + return a; +} + +int main() { + // the parameter a is an lvalue with an address, + // but the corresponding argument doesn't have to be + int result = addr_of_arg(-20); + return result; // result should be 10 +} \ No newline at end of file diff --git a/chapter15/valid/function_calls/return_pointer.c b/chapter15/valid/function_calls/return_pointer.c new file mode 100644 index 00000000..03c9300d --- /dev/null +++ b/chapter15/valid/function_calls/return_pointer.c @@ -0,0 +1,21 @@ +/* Test returning a pointer from a function */ +int *return_pointer(int *in) { + return in; +} + +int main() { + int x = 10; + int *x_ptr = return_pointer(&x); + + if (*x_ptr != 10) + return 0; + + x = 100; + if (*x_ptr != 100) + return 0; + + if (x_ptr != &x) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter15/valid/function_calls/update_value_through_pointer_parameter.c b/chapter15/valid/function_calls/update_value_through_pointer_parameter.c new file mode 100644 index 00000000..54bce0d7 --- /dev/null +++ b/chapter15/valid/function_calls/update_value_through_pointer_parameter.c @@ -0,0 +1,12 @@ +/* Make sure that a callee can update an object through a variable passed by the caller */ +int update_value(int *ptr) { + int old_val = *ptr; + *ptr = 10; + return old_val; +} + +int main() { + int x = 20; + int result = update_value(&x); + return (x == 10 && result == 20); +} \ No newline at end of file diff --git a/chapter15/valid/type_conversions/cast_between_pointer_types.c b/chapter15/valid/type_conversions/cast_between_pointer_types.c new file mode 100644 index 00000000..ad2a320f --- /dev/null +++ b/chapter15/valid/type_conversions/cast_between_pointer_types.c @@ -0,0 +1,19 @@ +/* Test explicitly casting between pointer types */ +int main() +{ + /* You can cast a null pointer to any pointer type and the result is still a null pointer */ + long *long_ptr = 0; + double *dbl_ptr = (double *)long_ptr; + unsigned int *int_ptr = (unsigned int *)long_ptr; + int **ptr_ptr = (int **)long_ptr; + + if (long_ptr || dbl_ptr || int_ptr || ptr_ptr) + return 0; + + // conversions between pointer types should round trip + long l = -1; + long_ptr = &l; + dbl_ptr = (double *)long_ptr; + long *other_long_ptr = (long *)dbl_ptr; + return *other_long_ptr == -1; +} \ No newline at end of file diff --git a/chapter15/valid/type_conversions/cast_int_to_pointer.c b/chapter15/valid/type_conversions/cast_int_to_pointer.c new file mode 100644 index 00000000..21b5d59f --- /dev/null +++ b/chapter15/valid/type_conversions/cast_int_to_pointer.c @@ -0,0 +1,7 @@ +/* Test that we can explicitly convert integers to pointers */ + +int main() { + int *a = (int *) 10l; + long b = 10; + return (a == (int *) b); +} \ No newline at end of file diff --git a/chapter15/valid/type_conversions/cast_pointer_to_int.c b/chapter15/valid/type_conversions/cast_pointer_to_int.c new file mode 100644 index 00000000..74ab8fc8 --- /dev/null +++ b/chapter15/valid/type_conversions/cast_pointer_to_int.c @@ -0,0 +1,10 @@ +/* Test that we can explicitly convert a pointer to an integer type */ +static long l; + +int main() { + long *ptr = &l; + unsigned long ptr_as_long = (unsigned long) ptr; + // long is eight-byte aligned, so the address of l + // must be divisible by 8 + return (ptr_as_long % 8 == 0); +} \ No newline at end of file diff --git a/chapter15/valid/type_conversions/cast_round_trip.c b/chapter15/valid/type_conversions/cast_round_trip.c new file mode 100644 index 00000000..11194768 --- /dev/null +++ b/chapter15/valid/type_conversions/cast_round_trip.c @@ -0,0 +1,33 @@ +/* Casts between pointer types and 64-bit integer types should round trip + * Casting a 32-bit int to a pointer and back should also round trip. + * (Casting a pointer to a 32-bit int usually won't round trip since the + * upper bits are discarded; we don't cover that case here.) + */ + +int main() { + /* Cast long to pointer and back */ + long x = 10; + int *ptr = (int *) x; + if ((long) ptr != x) + return 0; + + /* Cast pointer to unsigned long and back */ + double d; + double *d_ptr = &d; + unsigned long ul = (unsigned long) d_ptr; + if (d_ptr != (double *) ul) + return 0; + + /* Cast one pointer type to another and back */ + d_ptr = (double *) ptr; + if ((int *) d_ptr != ptr) + return 0; + + /* Cast an int to a pointer and back */ + int i = 2000; + long *l = (long *) i; + if ((int) l != 2000) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter15/valid/type_conversions/null_pointer_conversion.c b/chapter15/valid/type_conversions/null_pointer_conversion.c new file mode 100644 index 00000000..4295ea12 --- /dev/null +++ b/chapter15/valid/type_conversions/null_pointer_conversion.c @@ -0,0 +1,48 @@ +/* Make sure we can implicity convert null pointer constants to pointer type */ + +// convert static variable initializers +double *d = 0l; +int *i = 0ul; +int *i2 = 0u; + +int expect_null_param(int *val) +{ + // validate that this is a null pointer + return (val == 0u); +} + +long *return_null_ptr() +{ + return 0; // convert return value to pointer +} + +int main() +{ + int x = 10; + int *ptr = &x; + + // check static initializers + if (d || i || i2) + return 0; + + // convert to pointer for assignment + ptr = 0ul; + + // convert pointer in non-static initializer + int *y = 0; + if (y != 0) + return 0; + + // convert function argument to pointer + if (!expect_null_param(0)) + return 0; + + long *null_ptr = return_null_ptr(); + if (null_ptr != 0) + return 0; + + // convert ternary operand to null pointer + ptr = &x; + int *ternary_result = 10 ? 0 : ptr; + return !ternary_result; +} \ No newline at end of file diff --git a/chapter15/valid_extra_credit/compound_assign_through_pointer.c b/chapter15/valid_extra_credit/compound_assign_through_pointer.c new file mode 100644 index 00000000..0803beb6 --- /dev/null +++ b/chapter15/valid_extra_credit/compound_assign_through_pointer.c @@ -0,0 +1,8 @@ +int main() { + int x = 10; + int *ptr = &x; + // Make sure we can use a dereferenced pointer on the left-hand side + // of a compound assignment expression + *ptr += 5; + return (x == 15); +} \ No newline at end of file diff --git a/chapter15/valid_extra_credit/incr_through_pointer.c b/chapter15/valid_extra_credit/incr_through_pointer.c new file mode 100644 index 00000000..fdf70655 --- /dev/null +++ b/chapter15/valid_extra_credit/incr_through_pointer.c @@ -0,0 +1,7 @@ +int main() +{ + int x = 10; + int *y = &x; + ++*y; + return x; +} \ No newline at end of file From 90b390edd012bd17539543cbf3fa24e6311358eb Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Mon, 6 Mar 2023 11:17:57 -0800 Subject: [PATCH 006/167] chapter 16 tests --- chapter16/invalid_parse/array_of_functions.c | 8 +++ chapter16/invalid_parse/double_declarator.c | 4 ++ .../invalid_abstract_declarator.c | 5 ++ .../invalid_abstract_declarator_2.c | 5 ++ chapter16/invalid_parse/invalid_declarator.c | 4 ++ .../invalid_parse/invalid_declarator_2.c | 4 ++ .../invalid_parse/invalid_declarator_3.c | 4 ++ .../malformed_array_declarator.c | 5 ++ chapter16/invalid_parse/malformed_type_name.c | 6 +++ .../invalid_parse/malformed_type_name_2.c | 5 ++ .../invalid_parse/mismatched_subscript.c | 6 +++ .../invalid_parse/negative_array_dimension.c | 9 ++++ .../parenthesized_invalid_declarator.c | 1 + chapter16/invalid_parse/return_array.c | 6 +++ .../invalid_parse/unclosed_initializer.c | 4 ++ .../unclosed_nested_initializer.c | 4 ++ chapter16/invalid_parse/unclosed_subscript.c | 4 ++ chapter16/invalid_parse/zero_dimension.c | 4 ++ chapter16/invalid_types/add_two_pointers.c | 7 +++ chapter16/invalid_types/assign_to_array.c | 7 +++ chapter16/invalid_types/assign_to_array_2.c | 8 +++ .../invalid_types/bad_array_initializer.c | 5 ++ chapter16/invalid_types/cast_to_array_type.c | 6 +++ .../invalid_types/cast_to_array_type_2.c | 7 +++ .../invalid_types/cast_to_array_type_3.c | 5 ++ .../compare_different_pointer_types.c | 8 +++ .../invalid_types/compare_pointer_to_int.c | 6 +++ .../invalid_types/compare_pointer_to_zero.c | 9 ++++ .../invalid_types/compound_init_too_long.c | 5 ++ .../compound_initializer_for_scalar.c | 7 +++ .../compound_static_init_too_long.c | 5 ++ .../conflicting_array_declarations.c | 7 +++ .../conflicting_function_declarations.c | 8 +++ chapter16/invalid_types/double_subscript.c | 5 ++ .../invalid_types/explicit_vs_implict_addr.c | 6 +++ .../invalid_types/function_returns_array.c | 3 ++ .../incompatible_elem_type_compound_init.c | 5 ++ ...ompatible_elem_type_static_compound_init.c | 7 +++ .../invalid_types/non_modifiable_nested.c | 5 ++ .../null_ptr_array_initializer.c | 5 ++ .../scalar_initializer_for_array.c | 7 +++ .../scalar_initializer_for_static_array.c | 8 +++ .../invalid_types/static_non_const_array.c | 8 +++ .../sub_different_pointer_types.c | 8 +++ chapter16/invalid_types/sub_double_from_ptr.c | 5 ++ chapter16/invalid_types/sub_ptr_from_int.c | 7 +++ .../invalid_types/subscript_both_pointers.c | 8 +++ chapter16/invalid_types/subscript_non_ptr.c | 4 ++ .../zero_scalar_init_static_array.c | 5 ++ chapter16/valid/add_to_null.c | 5 ++ chapter16/valid/allocation/test_alignment.c | 23 +++++++++ chapter16/valid/array_as_argument.c | 8 +++ chapter16/valid/array_as_argument_local.c | 9 ++++ chapter16/valid/array_of_pointers_to_arrays.c | 10 ++++ chapter16/valid/assign_in_index.c | 6 +++ chapter16/valid/cast_array.c | 6 +++ .../valid/casts/cast_array_of_pointers.c | 8 +++ chapter16/valid/casts/cast_pointer_to_array.c | 6 +++ chapter16/valid/casts/cast_to_array_ptr.c | 7 +++ chapter16/valid/casts/cast_to_elem_ptr.c | 8 +++ .../valid/declarators/array_as_argument_2.c | 18 +++++++ .../valid/declarators/array_of_pointers.c | 11 ++++ .../declarators/equivalent_declarators.c | 14 +++++ .../declarators/multiple_array_declarations.c | 7 +++ .../valid/declarators/param_nested_array.c | 12 +++++ .../valid/declarators/return_nested_array.c | 10 ++++ chapter16/valid/deref_pointer_to_array.c | 5 ++ chapter16/valid/dereference_array.c | 4 ++ chapter16/valid/divide_by_ptr_deref.c | 5 ++ chapter16/valid/global_array.c | 15 ++++++ chapter16/valid/global_initialized_array.c | 13 +++++ chapter16/valid/global_nested_array.c | 11 ++++ .../valid/initialization/args_in_array_init.c | 8 +++ .../global_partly_initialized_array.c | 51 +++++++++++++++++++ chapter16/valid/initialization/nested.c | 4 ++ .../initialization/nested_partial_array.c | 16 ++++++ .../static_uninitialized_array.c | 12 +++++ .../valid/initialization/too_short_array.c | 9 ++++ .../initialization/too_short_static_array.c | 9 ++++ .../trailing_comma_initializer.c | 10 ++++ chapter16/valid/libraries/global_array.c | 7 +++ .../valid/libraries/global_array_client.c | 15 ++++++ .../valid/libraries/param_nested_array.c | 6 +++ .../libraries/param_nested_array_client.c | 7 +++ chapter16/valid/libraries/set_array_val.c | 4 ++ .../valid/libraries/set_array_val_client.c | 14 +++++ chapter16/valid/lvalue_test.c | 6 +++ chapter16/valid/nested2.c | 4 ++ chapter16/valid/nested_not_initialized.c | 5 ++ chapter16/valid/non_constant_initializer.c | 8 +++ chapter16/valid/param_pointer_to_array.c | 8 +++ .../add_non_standard_scale.c | 11 ++++ .../pointer_arithmetic/add_pointer_to_int.c | 5 ++ .../valid/pointer_arithmetic/addr_of_array.c | 5 ++ chapter16/valid/pointer_arithmetic/compare.c | 9 ++++ .../valid/pointer_arithmetic/compare_nested.c | 4 ++ .../negative_pointer_diff.c | 6 +++ .../nested_pointer_addition.c | 4 ++ .../nested_pointer_subtraction.c | 6 +++ .../pointer_arithmetic/nested_ptr_diff.c | 7 +++ .../valid/pointer_arithmetic/one_past_end.c | 6 +++ .../valid/pointer_arithmetic/pointer_add.c | 5 ++ .../pointer_arithmetic/pointer_add_neg.c | 6 +++ .../valid/pointer_arithmetic/pointer_sub.c | 15 ++++++ .../pointer_arithmetic/subtract_from_nested.c | 7 +++ .../pointer_arithmetic/subtract_negative.c | 6 +++ .../subtract_pointers_to_arrays.c | 4 ++ chapter16/valid/return_array.c | 9 ++++ chapter16/valid/return_array_value.c | 4 ++ chapter16/valid/return_pointer_to_array.c | 10 ++++ chapter16/valid/static_array.c | 11 ++++ .../addition_subscript_equivalence.c | 18 +++++++ chapter16/valid/subscripting/complex_index.c | 10 ++++ chapter16/valid/subscripting/const_index.c | 4 ++ chapter16/valid/subscripting/long_subscript.c | 4 ++ chapter16/valid/subscripting/neg_offset.c | 6 +++ .../valid/subscripting/reverse_subscript.c | 5 ++ .../valid/subscripting/set_array_value.c | 5 ++ .../subscripting/set_nested_array_value.c | 5 ++ .../valid/subscripting/subscript_pointer.c | 5 ++ .../valid/subscripting/subscript_precedence.c | 4 ++ chapter16/valid/subscripting/uint_subscript.c | 4 ++ .../valid/subscripting/ulong_subscript.c | 4 ++ .../valid/subscripting/uninitialized_array.c | 9 ++++ chapter16/valid_extra_credit/incr_ptr.c | 8 +++ 125 files changed, 939 insertions(+) create mode 100644 chapter16/invalid_parse/array_of_functions.c create mode 100644 chapter16/invalid_parse/double_declarator.c create mode 100644 chapter16/invalid_parse/invalid_abstract_declarator.c create mode 100644 chapter16/invalid_parse/invalid_abstract_declarator_2.c create mode 100644 chapter16/invalid_parse/invalid_declarator.c create mode 100644 chapter16/invalid_parse/invalid_declarator_2.c create mode 100644 chapter16/invalid_parse/invalid_declarator_3.c create mode 100644 chapter16/invalid_parse/malformed_array_declarator.c create mode 100644 chapter16/invalid_parse/malformed_type_name.c create mode 100644 chapter16/invalid_parse/malformed_type_name_2.c create mode 100644 chapter16/invalid_parse/mismatched_subscript.c create mode 100644 chapter16/invalid_parse/negative_array_dimension.c create mode 100644 chapter16/invalid_parse/parenthesized_invalid_declarator.c create mode 100644 chapter16/invalid_parse/return_array.c create mode 100644 chapter16/invalid_parse/unclosed_initializer.c create mode 100644 chapter16/invalid_parse/unclosed_nested_initializer.c create mode 100644 chapter16/invalid_parse/unclosed_subscript.c create mode 100644 chapter16/invalid_parse/zero_dimension.c create mode 100644 chapter16/invalid_types/add_two_pointers.c create mode 100644 chapter16/invalid_types/assign_to_array.c create mode 100644 chapter16/invalid_types/assign_to_array_2.c create mode 100644 chapter16/invalid_types/bad_array_initializer.c create mode 100644 chapter16/invalid_types/cast_to_array_type.c create mode 100644 chapter16/invalid_types/cast_to_array_type_2.c create mode 100644 chapter16/invalid_types/cast_to_array_type_3.c create mode 100644 chapter16/invalid_types/compare_different_pointer_types.c create mode 100644 chapter16/invalid_types/compare_pointer_to_int.c create mode 100644 chapter16/invalid_types/compare_pointer_to_zero.c create mode 100644 chapter16/invalid_types/compound_init_too_long.c create mode 100644 chapter16/invalid_types/compound_initializer_for_scalar.c create mode 100644 chapter16/invalid_types/compound_static_init_too_long.c create mode 100644 chapter16/invalid_types/conflicting_array_declarations.c create mode 100644 chapter16/invalid_types/conflicting_function_declarations.c create mode 100644 chapter16/invalid_types/double_subscript.c create mode 100644 chapter16/invalid_types/explicit_vs_implict_addr.c create mode 100644 chapter16/invalid_types/function_returns_array.c create mode 100644 chapter16/invalid_types/incompatible_elem_type_compound_init.c create mode 100644 chapter16/invalid_types/incompatible_elem_type_static_compound_init.c create mode 100644 chapter16/invalid_types/non_modifiable_nested.c create mode 100644 chapter16/invalid_types/null_ptr_array_initializer.c create mode 100644 chapter16/invalid_types/scalar_initializer_for_array.c create mode 100644 chapter16/invalid_types/scalar_initializer_for_static_array.c create mode 100644 chapter16/invalid_types/static_non_const_array.c create mode 100644 chapter16/invalid_types/sub_different_pointer_types.c create mode 100644 chapter16/invalid_types/sub_double_from_ptr.c create mode 100644 chapter16/invalid_types/sub_ptr_from_int.c create mode 100644 chapter16/invalid_types/subscript_both_pointers.c create mode 100644 chapter16/invalid_types/subscript_non_ptr.c create mode 100644 chapter16/invalid_types/zero_scalar_init_static_array.c create mode 100644 chapter16/valid/add_to_null.c create mode 100644 chapter16/valid/allocation/test_alignment.c create mode 100644 chapter16/valid/array_as_argument.c create mode 100644 chapter16/valid/array_as_argument_local.c create mode 100644 chapter16/valid/array_of_pointers_to_arrays.c create mode 100644 chapter16/valid/assign_in_index.c create mode 100644 chapter16/valid/cast_array.c create mode 100644 chapter16/valid/casts/cast_array_of_pointers.c create mode 100644 chapter16/valid/casts/cast_pointer_to_array.c create mode 100644 chapter16/valid/casts/cast_to_array_ptr.c create mode 100644 chapter16/valid/casts/cast_to_elem_ptr.c create mode 100644 chapter16/valid/declarators/array_as_argument_2.c create mode 100644 chapter16/valid/declarators/array_of_pointers.c create mode 100644 chapter16/valid/declarators/equivalent_declarators.c create mode 100644 chapter16/valid/declarators/multiple_array_declarations.c create mode 100644 chapter16/valid/declarators/param_nested_array.c create mode 100644 chapter16/valid/declarators/return_nested_array.c create mode 100644 chapter16/valid/deref_pointer_to_array.c create mode 100644 chapter16/valid/dereference_array.c create mode 100644 chapter16/valid/divide_by_ptr_deref.c create mode 100644 chapter16/valid/global_array.c create mode 100644 chapter16/valid/global_initialized_array.c create mode 100644 chapter16/valid/global_nested_array.c create mode 100644 chapter16/valid/initialization/args_in_array_init.c create mode 100644 chapter16/valid/initialization/global_partly_initialized_array.c create mode 100644 chapter16/valid/initialization/nested.c create mode 100644 chapter16/valid/initialization/nested_partial_array.c create mode 100644 chapter16/valid/initialization/static_uninitialized_array.c create mode 100644 chapter16/valid/initialization/too_short_array.c create mode 100644 chapter16/valid/initialization/too_short_static_array.c create mode 100644 chapter16/valid/initialization/trailing_comma_initializer.c create mode 100644 chapter16/valid/libraries/global_array.c create mode 100644 chapter16/valid/libraries/global_array_client.c create mode 100644 chapter16/valid/libraries/param_nested_array.c create mode 100644 chapter16/valid/libraries/param_nested_array_client.c create mode 100644 chapter16/valid/libraries/set_array_val.c create mode 100644 chapter16/valid/libraries/set_array_val_client.c create mode 100644 chapter16/valid/lvalue_test.c create mode 100644 chapter16/valid/nested2.c create mode 100644 chapter16/valid/nested_not_initialized.c create mode 100644 chapter16/valid/non_constant_initializer.c create mode 100644 chapter16/valid/param_pointer_to_array.c create mode 100644 chapter16/valid/pointer_arithmetic/add_non_standard_scale.c create mode 100644 chapter16/valid/pointer_arithmetic/add_pointer_to_int.c create mode 100644 chapter16/valid/pointer_arithmetic/addr_of_array.c create mode 100644 chapter16/valid/pointer_arithmetic/compare.c create mode 100644 chapter16/valid/pointer_arithmetic/compare_nested.c create mode 100644 chapter16/valid/pointer_arithmetic/negative_pointer_diff.c create mode 100644 chapter16/valid/pointer_arithmetic/nested_pointer_addition.c create mode 100644 chapter16/valid/pointer_arithmetic/nested_pointer_subtraction.c create mode 100644 chapter16/valid/pointer_arithmetic/nested_ptr_diff.c create mode 100644 chapter16/valid/pointer_arithmetic/one_past_end.c create mode 100644 chapter16/valid/pointer_arithmetic/pointer_add.c create mode 100644 chapter16/valid/pointer_arithmetic/pointer_add_neg.c create mode 100644 chapter16/valid/pointer_arithmetic/pointer_sub.c create mode 100644 chapter16/valid/pointer_arithmetic/subtract_from_nested.c create mode 100644 chapter16/valid/pointer_arithmetic/subtract_negative.c create mode 100644 chapter16/valid/pointer_arithmetic/subtract_pointers_to_arrays.c create mode 100644 chapter16/valid/return_array.c create mode 100644 chapter16/valid/return_array_value.c create mode 100644 chapter16/valid/return_pointer_to_array.c create mode 100644 chapter16/valid/static_array.c create mode 100644 chapter16/valid/subscripting/addition_subscript_equivalence.c create mode 100644 chapter16/valid/subscripting/complex_index.c create mode 100644 chapter16/valid/subscripting/const_index.c create mode 100644 chapter16/valid/subscripting/long_subscript.c create mode 100644 chapter16/valid/subscripting/neg_offset.c create mode 100644 chapter16/valid/subscripting/reverse_subscript.c create mode 100644 chapter16/valid/subscripting/set_array_value.c create mode 100644 chapter16/valid/subscripting/set_nested_array_value.c create mode 100644 chapter16/valid/subscripting/subscript_pointer.c create mode 100644 chapter16/valid/subscripting/subscript_precedence.c create mode 100644 chapter16/valid/subscripting/uint_subscript.c create mode 100644 chapter16/valid/subscripting/ulong_subscript.c create mode 100644 chapter16/valid/subscripting/uninitialized_array.c create mode 100644 chapter16/valid_extra_credit/incr_ptr.c diff --git a/chapter16/invalid_parse/array_of_functions.c b/chapter16/invalid_parse/array_of_functions.c new file mode 100644 index 00000000..1e3986bc --- /dev/null +++ b/chapter16/invalid_parse/array_of_functions.c @@ -0,0 +1,8 @@ +int main() +{ + return 0; +} + +// this is a parse error in our implementation +// but could also be a type error +int foo[3](int a); diff --git a/chapter16/invalid_parse/double_declarator.c b/chapter16/invalid_parse/double_declarator.c new file mode 100644 index 00000000..e767f68e --- /dev/null +++ b/chapter16/invalid_parse/double_declarator.c @@ -0,0 +1,4 @@ +int main() +{ + int x[2.0]; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/invalid_abstract_declarator.c b/chapter16/invalid_parse/invalid_abstract_declarator.c new file mode 100644 index 00000000..c9bbdd61 --- /dev/null +++ b/chapter16/invalid_parse/invalid_abstract_declarator.c @@ -0,0 +1,5 @@ +int main() +{ + // invalid abstract declarator syntax + return (int[3] *)0; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/invalid_abstract_declarator_2.c b/chapter16/invalid_parse/invalid_abstract_declarator_2.c new file mode 100644 index 00000000..b14831dd --- /dev/null +++ b/chapter16/invalid_parse/invalid_abstract_declarator_2.c @@ -0,0 +1,5 @@ +int main() +{ + // invalid abstract declarator syntax + return (int[3](*))0; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/invalid_declarator.c b/chapter16/invalid_parse/invalid_declarator.c new file mode 100644 index 00000000..dcccfb69 --- /dev/null +++ b/chapter16/invalid_parse/invalid_declarator.c @@ -0,0 +1,4 @@ +int main() { + int [3] arr = {1, 2, 3}; + return 0; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/invalid_declarator_2.c b/chapter16/invalid_parse/invalid_declarator_2.c new file mode 100644 index 00000000..88770214 --- /dev/null +++ b/chapter16/invalid_parse/invalid_declarator_2.c @@ -0,0 +1,4 @@ +int main() { + int (*)foo; + return 0; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/invalid_declarator_3.c b/chapter16/invalid_parse/invalid_declarator_3.c new file mode 100644 index 00000000..474009af --- /dev/null +++ b/chapter16/invalid_parse/invalid_declarator_3.c @@ -0,0 +1,4 @@ +int main() { + int (*)(ptr_to_array[3]) = 0; + return 0; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/malformed_array_declarator.c b/chapter16/invalid_parse/malformed_array_declarator.c new file mode 100644 index 00000000..53c2466e --- /dev/null +++ b/chapter16/invalid_parse/malformed_array_declarator.c @@ -0,0 +1,5 @@ +int main() +{ + int foo[[10]]; + return 0; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/malformed_type_name.c b/chapter16/invalid_parse/malformed_type_name.c new file mode 100644 index 00000000..d236eccd --- /dev/null +++ b/chapter16/invalid_parse/malformed_type_name.c @@ -0,0 +1,6 @@ +int main() { + int a = 4; + int *foo = &a; + int *bar[3] = (*[3]) foo; + return 0; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/malformed_type_name_2.c b/chapter16/invalid_parse/malformed_type_name_2.c new file mode 100644 index 00000000..cb67873c --- /dev/null +++ b/chapter16/invalid_parse/malformed_type_name_2.c @@ -0,0 +1,5 @@ +int main() { + int *ptr; + int *array_pointer[3] = ([3](*)) ptr; + return 0; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/mismatched_subscript.c b/chapter16/invalid_parse/mismatched_subscript.c new file mode 100644 index 00000000..e226912a --- /dev/null +++ b/chapter16/invalid_parse/mismatched_subscript.c @@ -0,0 +1,6 @@ +int main() +{ + int indices[3] = {1, 2, 3}; + int vals[3] = {4, 5, 6}; + return vals[indices[1]; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/negative_array_dimension.c b/chapter16/invalid_parse/negative_array_dimension.c new file mode 100644 index 00000000..db680e37 --- /dev/null +++ b/chapter16/invalid_parse/negative_array_dimension.c @@ -0,0 +1,9 @@ +/* could be type error + * we don't accept this b/c we don't accept any constant expressions in array declarators, + * only constant literals + */ +int main() +{ + int arr[-3]; + return 0; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/parenthesized_invalid_declarator.c b/chapter16/invalid_parse/parenthesized_invalid_declarator.c new file mode 100644 index 00000000..e8f100a3 --- /dev/null +++ b/chapter16/invalid_parse/parenthesized_invalid_declarator.c @@ -0,0 +1 @@ +int(foo[3])(int a); \ No newline at end of file diff --git a/chapter16/invalid_parse/return_array.c b/chapter16/invalid_parse/return_array.c new file mode 100644 index 00000000..3fefb48b --- /dev/null +++ b/chapter16/invalid_parse/return_array.c @@ -0,0 +1,6 @@ +/* could conceivably be type error in some implementations? */ +int foo()[3]; +int main() +{ + return foo()[2]; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/unclosed_initializer.c b/chapter16/invalid_parse/unclosed_initializer.c new file mode 100644 index 00000000..ec8f1b3e --- /dev/null +++ b/chapter16/invalid_parse/unclosed_initializer.c @@ -0,0 +1,4 @@ +int main() { + int arr = {1, 2; + return arr[0]; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/unclosed_nested_initializer.c b/chapter16/invalid_parse/unclosed_nested_initializer.c new file mode 100644 index 00000000..6fbd6104 --- /dev/null +++ b/chapter16/invalid_parse/unclosed_nested_initializer.c @@ -0,0 +1,4 @@ +int main() { + int arr[2][2] = {{ 1, 2}, {3, 4}; + return arr[0][0]; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/unclosed_subscript.c b/chapter16/invalid_parse/unclosed_subscript.c new file mode 100644 index 00000000..178cc059 --- /dev/null +++ b/chapter16/invalid_parse/unclosed_subscript.c @@ -0,0 +1,4 @@ +int main() { + int arr[] = {1, 2, 3}; + return arr[1; +} \ No newline at end of file diff --git a/chapter16/invalid_parse/zero_dimension.c b/chapter16/invalid_parse/zero_dimension.c new file mode 100644 index 00000000..266bb1c8 --- /dev/null +++ b/chapter16/invalid_parse/zero_dimension.c @@ -0,0 +1,4 @@ +int main() +{ + int arr[4][0][2]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/add_two_pointers.c b/chapter16/invalid_types/add_two_pointers.c new file mode 100644 index 00000000..b5dc4e83 --- /dev/null +++ b/chapter16/invalid_types/add_two_pointers.c @@ -0,0 +1,7 @@ +int main() +{ + int *x = 0; + int *y = 0; + // it's illegal to add two values of pointer type + return (x + y == 0); +} \ No newline at end of file diff --git a/chapter16/invalid_types/assign_to_array.c b/chapter16/invalid_types/assign_to_array.c new file mode 100644 index 00000000..f35d4a05 --- /dev/null +++ b/chapter16/invalid_types/assign_to_array.c @@ -0,0 +1,7 @@ +int main() +{ + int arr[3] = {1, 2, 3}; + int arr2[3] = {4, 5, 6}; + arr = arr2; + return arr[0]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/assign_to_array_2.c b/chapter16/invalid_types/assign_to_array_2.c new file mode 100644 index 00000000..a038e236 --- /dev/null +++ b/chapter16/invalid_types/assign_to_array_2.c @@ -0,0 +1,8 @@ +int main() +{ + int dim2[1][2] = {{1, 2}}; + int dim[2] = {3, 4}; + // dim2 has array type, so it can't be assigned to + dim2[0] = dim; + return dim[0]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/bad_array_initializer.c b/chapter16/invalid_types/bad_array_initializer.c new file mode 100644 index 00000000..8db03c2e --- /dev/null +++ b/chapter16/invalid_types/bad_array_initializer.c @@ -0,0 +1,5 @@ +int main() +{ + int arr[1] = 4; + return arr[0]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/cast_to_array_type.c b/chapter16/invalid_types/cast_to_array_type.c new file mode 100644 index 00000000..a32d65e3 --- /dev/null +++ b/chapter16/invalid_types/cast_to_array_type.c @@ -0,0 +1,6 @@ +int main() +{ + int arr[10]; + // can't cast to array type + return (int[10])arr; +} \ No newline at end of file diff --git a/chapter16/invalid_types/cast_to_array_type_2.c b/chapter16/invalid_types/cast_to_array_type_2.c new file mode 100644 index 00000000..3744fc1f --- /dev/null +++ b/chapter16/invalid_types/cast_to_array_type_2.c @@ -0,0 +1,7 @@ +int main() +{ + long arr[10]; + // cast to array of pointers to int + // casting to arrays in invalid + return (int *[10])arr; +} \ No newline at end of file diff --git a/chapter16/invalid_types/cast_to_array_type_3.c b/chapter16/invalid_types/cast_to_array_type_3.c new file mode 100644 index 00000000..2e730e25 --- /dev/null +++ b/chapter16/invalid_types/cast_to_array_type_3.c @@ -0,0 +1,5 @@ +int main() +{ + long arr[6]; + return ((long(([2])[3]))arr); +} \ No newline at end of file diff --git a/chapter16/invalid_types/compare_different_pointer_types.c b/chapter16/invalid_types/compare_different_pointer_types.c new file mode 100644 index 00000000..92caea2b --- /dev/null +++ b/chapter16/invalid_types/compare_different_pointer_types.c @@ -0,0 +1,8 @@ +int main() +{ + long x = 10; + long *ptr = &x + 1; + long(*array_ptr)[10] = &x; + // cannot compare array_ptr to ptr because they have different types + return array_ptr < ptr; +} \ No newline at end of file diff --git a/chapter16/invalid_types/compare_pointer_to_int.c b/chapter16/invalid_types/compare_pointer_to_int.c new file mode 100644 index 00000000..c3cbe842 --- /dev/null +++ b/chapter16/invalid_types/compare_pointer_to_int.c @@ -0,0 +1,6 @@ +int main() +{ + long *l = 0; + // can't compare a pointer to any integer type + return l <= 100ul; +} \ No newline at end of file diff --git a/chapter16/invalid_types/compare_pointer_to_zero.c b/chapter16/invalid_types/compare_pointer_to_zero.c new file mode 100644 index 00000000..2b4b3e86 --- /dev/null +++ b/chapter16/invalid_types/compare_pointer_to_zero.c @@ -0,0 +1,9 @@ +int main() +{ + int *x = 0; + // illegal to compare a pointer w/ an intege + // note that 0 isn't implicitly converted to a pointer here + // it's only implicitly converted when used in == and != operations + // Note: GCC/Clang only worry about this in -pedantic mode + return x > 0; +} \ No newline at end of file diff --git a/chapter16/invalid_types/compound_init_too_long.c b/chapter16/invalid_types/compound_init_too_long.c new file mode 100644 index 00000000..4ef12328 --- /dev/null +++ b/chapter16/invalid_types/compound_init_too_long.c @@ -0,0 +1,5 @@ +// TODO do we want to check this? GCC/clang warn but don't fail. +int main() { + int arr[3] = {1, 2, 3,4}; + return arr[2]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/compound_initializer_for_scalar.c b/chapter16/invalid_types/compound_initializer_for_scalar.c new file mode 100644 index 00000000..8060cf21 --- /dev/null +++ b/chapter16/invalid_types/compound_initializer_for_scalar.c @@ -0,0 +1,7 @@ +int main() +{ + // can't initialize a scalar expression w/ a compound initializer + // NOTE: this is undefined but technically not a constraint violation so maybe don't test it? + int x = {1, 2, 3}; + return x; +} \ No newline at end of file diff --git a/chapter16/invalid_types/compound_static_init_too_long.c b/chapter16/invalid_types/compound_static_init_too_long.c new file mode 100644 index 00000000..6428a712 --- /dev/null +++ b/chapter16/invalid_types/compound_static_init_too_long.c @@ -0,0 +1,5 @@ +// TODO do we want to check this? GCC/clang warn but don't fail. +int main() { + static int arr[3] = {1, 2, 3, 4}; + return arr[2]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/conflicting_array_declarations.c b/chapter16/invalid_types/conflicting_array_declarations.c new file mode 100644 index 00000000..fc5a4eaf --- /dev/null +++ b/chapter16/invalid_types/conflicting_array_declarations.c @@ -0,0 +1,7 @@ +int arr[6]; + +int main() { + return arr[0]; +} + +int arr[5]; \ No newline at end of file diff --git a/chapter16/invalid_types/conflicting_function_declarations.c b/chapter16/invalid_types/conflicting_function_declarations.c new file mode 100644 index 00000000..09207de7 --- /dev/null +++ b/chapter16/invalid_types/conflicting_function_declarations.c @@ -0,0 +1,8 @@ +// this is adjusted to +// int f(int (*arr)[3]) +int f(int arr[2][3]); + +// this is adjusted to +// int f(int (*arr)[4]) +// so it conflicts with the previous declaration +int f(int arr[2][4]); \ No newline at end of file diff --git a/chapter16/invalid_types/double_subscript.c b/chapter16/invalid_types/double_subscript.c new file mode 100644 index 00000000..abdcabbe --- /dev/null +++ b/chapter16/invalid_types/double_subscript.c @@ -0,0 +1,5 @@ +int main() +{ + int arr[3] = {4, 5, 6}; + return arr[2.0]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/explicit_vs_implict_addr.c b/chapter16/invalid_types/explicit_vs_implict_addr.c new file mode 100644 index 00000000..c2606e6b --- /dev/null +++ b/chapter16/invalid_types/explicit_vs_implict_addr.c @@ -0,0 +1,6 @@ +int main() +{ + int arr[10]; + // can't compare these expressions b/c they have different types + return arr == &arr; +} \ No newline at end of file diff --git a/chapter16/invalid_types/function_returns_array.c b/chapter16/invalid_types/function_returns_array.c new file mode 100644 index 00000000..170b8639 --- /dev/null +++ b/chapter16/invalid_types/function_returns_array.c @@ -0,0 +1,3 @@ +// this is a parse error in our implementation +// but could also be a type error +int(foo())[3][4]; \ No newline at end of file diff --git a/chapter16/invalid_types/incompatible_elem_type_compound_init.c b/chapter16/invalid_types/incompatible_elem_type_compound_init.c new file mode 100644 index 00000000..948455e4 --- /dev/null +++ b/chapter16/invalid_types/incompatible_elem_type_compound_init.c @@ -0,0 +1,5 @@ +int main() +{ + // invalid implicit conversion of double 1.0 to type int * + int *arr[3] = {0, 0, 1.0}; +} \ No newline at end of file diff --git a/chapter16/invalid_types/incompatible_elem_type_static_compound_init.c b/chapter16/invalid_types/incompatible_elem_type_static_compound_init.c new file mode 100644 index 00000000..fe2368bf --- /dev/null +++ b/chapter16/invalid_types/incompatible_elem_type_static_compound_init.c @@ -0,0 +1,7 @@ +// invalid implicit conversion of double 1.0 to type int * +int *arr[3] = {0, 0, 1.0}; + +int main() +{ + return 0; +} \ No newline at end of file diff --git a/chapter16/invalid_types/non_modifiable_nested.c b/chapter16/invalid_types/non_modifiable_nested.c new file mode 100644 index 00000000..48ddadf9 --- /dev/null +++ b/chapter16/invalid_types/non_modifiable_nested.c @@ -0,0 +1,5 @@ +int main() { + int arr[3] = { 1, 2, 3}; + int (*ptr_to_array)[3] = 0; + *ptr_to_array = arr; +} \ No newline at end of file diff --git a/chapter16/invalid_types/null_ptr_array_initializer.c b/chapter16/invalid_types/null_ptr_array_initializer.c new file mode 100644 index 00000000..e905c96b --- /dev/null +++ b/chapter16/invalid_types/null_ptr_array_initializer.c @@ -0,0 +1,5 @@ +int main() +{ + int arr[1] = 0; + return arr[0]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/scalar_initializer_for_array.c b/chapter16/invalid_types/scalar_initializer_for_array.c new file mode 100644 index 00000000..f2ff7130 --- /dev/null +++ b/chapter16/invalid_types/scalar_initializer_for_array.c @@ -0,0 +1,7 @@ +int main() +{ + // can't initialize array w/ non-compound initializer + // NOTE: this is undefined but technically not a constraint violation so maybe don't test it? + int arr[1] = 4; + return arr[0]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/scalar_initializer_for_static_array.c b/chapter16/invalid_types/scalar_initializer_for_static_array.c new file mode 100644 index 00000000..5f1e9726 --- /dev/null +++ b/chapter16/invalid_types/scalar_initializer_for_static_array.c @@ -0,0 +1,8 @@ +// can't initialize array w/ non-compound initializer +// NOTE: this is undefined but technically not a constraint violation so maybe don't test it? +double arr[3] = 1.0; + +int main() +{ + return 0; +} \ No newline at end of file diff --git a/chapter16/invalid_types/static_non_const_array.c b/chapter16/invalid_types/static_non_const_array.c new file mode 100644 index 00000000..80ab6cb1 --- /dev/null +++ b/chapter16/invalid_types/static_non_const_array.c @@ -0,0 +1,8 @@ +int foo(int p) { + static int arr[3] = { p, p + 1, 0}; + return arr[2]; +} + +int main() { + return foo(5); +} \ No newline at end of file diff --git a/chapter16/invalid_types/sub_different_pointer_types.c b/chapter16/invalid_types/sub_different_pointer_types.c new file mode 100644 index 00000000..ddc34117 --- /dev/null +++ b/chapter16/invalid_types/sub_different_pointer_types.c @@ -0,0 +1,8 @@ +int main() +{ + long x[10]; + long *ptr = x; + unsigned long *ptr2 = (unsigned long *)ptr; + // can't subtract pointers to different types + return ptr - ptr2; +} \ No newline at end of file diff --git a/chapter16/invalid_types/sub_double_from_ptr.c b/chapter16/invalid_types/sub_double_from_ptr.c new file mode 100644 index 00000000..6354abd1 --- /dev/null +++ b/chapter16/invalid_types/sub_double_from_ptr.c @@ -0,0 +1,5 @@ +int main() +{ + int *y = 0; + return (y - 0.0 == 0.0); +} \ No newline at end of file diff --git a/chapter16/invalid_types/sub_ptr_from_int.c b/chapter16/invalid_types/sub_ptr_from_int.c new file mode 100644 index 00000000..abceb040 --- /dev/null +++ b/chapter16/invalid_types/sub_ptr_from_int.c @@ -0,0 +1,7 @@ +int main() +{ + int *x = 0; + // can't subtract a pointer from an integer + // Note that 0 is NOT implicitly converted to a pointer here + return 0 - x == 0; +} \ No newline at end of file diff --git a/chapter16/invalid_types/subscript_both_pointers.c b/chapter16/invalid_types/subscript_both_pointers.c new file mode 100644 index 00000000..802308c2 --- /dev/null +++ b/chapter16/invalid_types/subscript_both_pointers.c @@ -0,0 +1,8 @@ +int main() +{ + int x = 10; + int *ptr = &x; + int *subscript = 0; + // can't perform subscript operation when both operands are pointers + return ptr[subscript]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/subscript_non_ptr.c b/chapter16/invalid_types/subscript_non_ptr.c new file mode 100644 index 00000000..15eef0ce --- /dev/null +++ b/chapter16/invalid_types/subscript_non_ptr.c @@ -0,0 +1,4 @@ +int main() { + int a = 3; + return a[4]; +} \ No newline at end of file diff --git a/chapter16/invalid_types/zero_scalar_init_static_array.c b/chapter16/invalid_types/zero_scalar_init_static_array.c new file mode 100644 index 00000000..0e862ebf --- /dev/null +++ b/chapter16/invalid_types/zero_scalar_init_static_array.c @@ -0,0 +1,5 @@ +int main() +{ + static int arr[1] = 0; + return arr[0]; +} \ No newline at end of file diff --git a/chapter16/valid/add_to_null.c b/chapter16/valid/add_to_null.c new file mode 100644 index 00000000..6b6c08bc --- /dev/null +++ b/chapter16/valid/add_to_null.c @@ -0,0 +1,5 @@ +int main() { + int *ptr = 0; + int *ptr2 = ptr + 1; + return (ptr2 > ptr); +} \ No newline at end of file diff --git a/chapter16/valid/allocation/test_alignment.c b/chapter16/valid/allocation/test_alignment.c new file mode 100644 index 00000000..080c07d8 --- /dev/null +++ b/chapter16/valid/allocation/test_alignment.c @@ -0,0 +1,23 @@ +int main() +{ + int arr[5] = {0}; + int arr2[7] = {0}; + + // make sure both arrays are 16-byte aligned and don't overlap + unsigned long addr = (unsigned long)arr; + if (addr % 16 != 0) + return 0; + + for (int i = 0; i < 5; i = i + 1) + arr[i] = i; + + addr = (unsigned long)arr2; + if (addr % 16 != 0) + return 0; + + // make sure we didn't overwrite arr2 + for (int i = 0; i < 7; i = i + 1) + if (arr2[i]) + return 0; + return 1; +} \ No newline at end of file diff --git a/chapter16/valid/array_as_argument.c b/chapter16/valid/array_as_argument.c new file mode 100644 index 00000000..6482c930 --- /dev/null +++ b/chapter16/valid/array_as_argument.c @@ -0,0 +1,8 @@ +int foo(int a[5]) { + return a[3]; +} + +int main() { + int arr[5] = {8, 7, 6, 5, 4}; + return foo(arr); +} \ No newline at end of file diff --git a/chapter16/valid/array_as_argument_local.c b/chapter16/valid/array_as_argument_local.c new file mode 100644 index 00000000..f2ba3789 --- /dev/null +++ b/chapter16/valid/array_as_argument_local.c @@ -0,0 +1,9 @@ +int main() { + int foo(int a[5]); + int arr[5] = {8, 7, 6, 5, 4}; + return foo(arr); +} + +int foo(int a[4]) { + return a[3]; +} \ No newline at end of file diff --git a/chapter16/valid/array_of_pointers_to_arrays.c b/chapter16/valid/array_of_pointers_to_arrays.c new file mode 100644 index 00000000..65cac0e8 --- /dev/null +++ b/chapter16/valid/array_of_pointers_to_arrays.c @@ -0,0 +1,10 @@ +int main() { + int x = 0; + int y = 1; + int z = 2; + int *arr[3] = { &x, &y, &z }; + int *arr2[3] = {&z, &y, &x}; + // an array of pointers to arrays of pointers + int *(*array_of_pointers[3])[3] = {&arr, &arr2, &arr}; + return *(array_of_pointers[1][0][1]) + (*array_of_pointers[2])[2][0]; +} \ No newline at end of file diff --git a/chapter16/valid/assign_in_index.c b/chapter16/valid/assign_in_index.c new file mode 100644 index 00000000..4a51a25b --- /dev/null +++ b/chapter16/valid/assign_in_index.c @@ -0,0 +1,6 @@ +int main() { + int idx = 3; + int arr[3] = {1, 2, 3}; + int ret = arr[idx = 1]; + return ret + idx; +} \ No newline at end of file diff --git a/chapter16/valid/cast_array.c b/chapter16/valid/cast_array.c new file mode 100644 index 00000000..34b1a41f --- /dev/null +++ b/chapter16/valid/cast_array.c @@ -0,0 +1,6 @@ +int main() { + int arr[4] = {1, 2, 3, 4}; + int *ptr = (int *) arr; + ptr = ptr + 1; + return ptr[2]; +} \ No newline at end of file diff --git a/chapter16/valid/casts/cast_array_of_pointers.c b/chapter16/valid/casts/cast_array_of_pointers.c new file mode 100644 index 00000000..caa54810 --- /dev/null +++ b/chapter16/valid/casts/cast_array_of_pointers.c @@ -0,0 +1,8 @@ +int main() +{ + int simple_array[2] = {1, 2}; + int(*ptr_arr[3])[2] = {&simple_array, 0, &simple_array}; + // cast from one pointer type to another + long *other_ptr = (long *)ptr_arr; + return (int(**)[2])other_ptr == ptr_arr; +} \ No newline at end of file diff --git a/chapter16/valid/casts/cast_pointer_to_array.c b/chapter16/valid/casts/cast_pointer_to_array.c new file mode 100644 index 00000000..a80a85cd --- /dev/null +++ b/chapter16/valid/casts/cast_pointer_to_array.c @@ -0,0 +1,6 @@ +int main() { + int nested[2][2] = {{1, 2} , {3, 4}}; + int (*arr_pointer)[2][2] = &nested; + int (*cast_array_pointer)[4] = (int (*)[4]) arr_pointer; + return (*cast_array_pointer)[3]; +} \ No newline at end of file diff --git a/chapter16/valid/casts/cast_to_array_ptr.c b/chapter16/valid/casts/cast_to_array_ptr.c new file mode 100644 index 00000000..bcd37a6e --- /dev/null +++ b/chapter16/valid/casts/cast_to_array_ptr.c @@ -0,0 +1,7 @@ +int main() +{ + long arr[4] = {4, 5, 6, 7}; + long *ptr = arr; + long(*arr_ptr)[4] = (long(*)[4])ptr; + return arr_ptr == &arr; +} \ No newline at end of file diff --git a/chapter16/valid/casts/cast_to_elem_ptr.c b/chapter16/valid/casts/cast_to_elem_ptr.c new file mode 100644 index 00000000..74b2104a --- /dev/null +++ b/chapter16/valid/casts/cast_to_elem_ptr.c @@ -0,0 +1,8 @@ +int main() +{ + int arr[3] = {1, 2, 3}; + int(*arr_ptr)[3] = &arr; + // cast pointer to array to pointer to first element + int *ptr = (int *)arr_ptr; + return *ptr; +} \ No newline at end of file diff --git a/chapter16/valid/declarators/array_as_argument_2.c b/chapter16/valid/declarators/array_as_argument_2.c new file mode 100644 index 00000000..0f4357a1 --- /dev/null +++ b/chapter16/valid/declarators/array_as_argument_2.c @@ -0,0 +1,18 @@ +// test that array types in parameters are converted to pointer types + +int foo(int a[5]) +{ + a[4] = 0; + return 0; +} + +int foo(int a[2]); + +int main() +{ + int arr[8] = {8, 7, 6, 5, 4, 3, 2, 1}; + foo(arr); + return arr[4]; +} + +int foo(int *a); \ No newline at end of file diff --git a/chapter16/valid/declarators/array_of_pointers.c b/chapter16/valid/declarators/array_of_pointers.c new file mode 100644 index 00000000..7e52c79b --- /dev/null +++ b/chapter16/valid/declarators/array_of_pointers.c @@ -0,0 +1,11 @@ +int main() { + int *arr[3]; + int a = 4; + int b = 5; + int c = 6; + arr[0] = &a; + arr[1] = &b; + arr[2] = &c; + *arr[1] = 9; + return b; +} \ No newline at end of file diff --git a/chapter16/valid/declarators/equivalent_declarators.c b/chapter16/valid/declarators/equivalent_declarators.c new file mode 100644 index 00000000..dba1148d --- /dev/null +++ b/chapter16/valid/declarators/equivalent_declarators.c @@ -0,0 +1,14 @@ +/* Declare a global array multiple times w/ equivalent declarators */ + +long int(arr)[4] = {1, 2, 3, 4}; + +int long arr[4ul]; + +int (*ptr_to_arr)[3][6l]; + +int((*(ptr_to_arr))[3l])[6u] = 0; + +int main() +{ + return arr[2] == 3 && ptr_to_arr == 0; +} \ No newline at end of file diff --git a/chapter16/valid/declarators/multiple_array_declarations.c b/chapter16/valid/declarators/multiple_array_declarations.c new file mode 100644 index 00000000..c3d1edf3 --- /dev/null +++ b/chapter16/valid/declarators/multiple_array_declarations.c @@ -0,0 +1,7 @@ +int arr[8]; + +int main() { + return arr[7]; +} + +int arr[8] = {1, 2, 3, 4, 5, 6, 7, 8}; \ No newline at end of file diff --git a/chapter16/valid/declarators/param_nested_array.c b/chapter16/valid/declarators/param_nested_array.c new file mode 100644 index 00000000..e41333fb --- /dev/null +++ b/chapter16/valid/declarators/param_nested_array.c @@ -0,0 +1,12 @@ +int foo(int arg[1][2]) { + int elem[2] = {3, 9}; + arg[0][1] = elem[1]; + arg[0][0] = elem[0]; + return 0; +} + +int main() { + int arg[1][2] = {{1, 2}}; + foo(arg); + return arg[0][1] + arg[0][0]; +} \ No newline at end of file diff --git a/chapter16/valid/declarators/return_nested_array.c b/chapter16/valid/declarators/return_nested_array.c new file mode 100644 index 00000000..49d481a7 --- /dev/null +++ b/chapter16/valid/declarators/return_nested_array.c @@ -0,0 +1,10 @@ +int arr[3] = {1, 1, 1}; + +int (*foo(int x, int y))[3] { + return &arr; +} + +int main() { + int (*arr)[3] = foo(2, 3); + return (*arr)[1]; +} \ No newline at end of file diff --git a/chapter16/valid/deref_pointer_to_array.c b/chapter16/valid/deref_pointer_to_array.c new file mode 100644 index 00000000..d7b611df --- /dev/null +++ b/chapter16/valid/deref_pointer_to_array.c @@ -0,0 +1,5 @@ +int main() { + int arr[3] = {1, 2, 3}; + int (*ptr_to_arr)[3] = &arr; + return (*ptr_to_arr)[1]; +} \ No newline at end of file diff --git a/chapter16/valid/dereference_array.c b/chapter16/valid/dereference_array.c new file mode 100644 index 00000000..b5fc5659 --- /dev/null +++ b/chapter16/valid/dereference_array.c @@ -0,0 +1,4 @@ +int main() { + int arr[3] = {1, 2, 3}; + return *arr; +} \ No newline at end of file diff --git a/chapter16/valid/divide_by_ptr_deref.c b/chapter16/valid/divide_by_ptr_deref.c new file mode 100644 index 00000000..cf88d66b --- /dev/null +++ b/chapter16/valid/divide_by_ptr_deref.c @@ -0,0 +1,5 @@ +int main() { + int a = 3; + int *ptr = &a; + return 6 / *ptr; +} \ No newline at end of file diff --git a/chapter16/valid/global_array.c b/chapter16/valid/global_array.c new file mode 100644 index 00000000..20cf2692 --- /dev/null +++ b/chapter16/valid/global_array.c @@ -0,0 +1,15 @@ +double double_arr[8]; + +int foo() { + for (int i = 0; i < 8; i = i + 1) { + double_arr[i] = double_arr[i] * 2.0; + } + return 0; +} + +int main() { + double c = 3.1; + double_arr[5] = c; + foo(); + return (double_arr[5] == c * 2.0); +} \ No newline at end of file diff --git a/chapter16/valid/global_initialized_array.c b/chapter16/valid/global_initialized_array.c new file mode 100644 index 00000000..aeddd364 --- /dev/null +++ b/chapter16/valid/global_initialized_array.c @@ -0,0 +1,13 @@ +double double_arr[3] = {1.0, 2.0, 3.0}; + +int foo() { + for (int i = 0; i < 3; i = i + 1) { + double_arr[i] = double_arr[i] * 2.0; + } + return 0; +} + +int main() { + foo(); + return (double_arr[2] == 3.0 * 2.0); +} \ No newline at end of file diff --git a/chapter16/valid/global_nested_array.c b/chapter16/valid/global_nested_array.c new file mode 100644 index 00000000..de5cf7cf --- /dev/null +++ b/chapter16/valid/global_nested_array.c @@ -0,0 +1,11 @@ +double double_arr[2][2] = { {10.0, 9.0 }, {6.0, 7.0} }; + +int set_array_val() { + double_arr[1][0] = 11.0; + return 0; +} + +int main() { + set_array_val(); + return (double_arr[1][0] + double_arr[0][1] == 20.0); +} \ No newline at end of file diff --git a/chapter16/valid/initialization/args_in_array_init.c b/chapter16/valid/initialization/args_in_array_init.c new file mode 100644 index 00000000..aa1f1204 --- /dev/null +++ b/chapter16/valid/initialization/args_in_array_init.c @@ -0,0 +1,8 @@ +int foo(int a, int b, int c) { + int arr[3] = { a, a, b }; + return arr[2] + c; +} + +int main() { + return foo(1, 2, 3); +} \ No newline at end of file diff --git a/chapter16/valid/initialization/global_partly_initialized_array.c b/chapter16/valid/initialization/global_partly_initialized_array.c new file mode 100644 index 00000000..5e9b9f64 --- /dev/null +++ b/chapter16/valid/initialization/global_partly_initialized_array.c @@ -0,0 +1,51 @@ +/* first element should be 10.0, other three elements should be 0 */ +double double_arr[2][2] = {{10.0}}; + +/* last element is 0 */ +unsigned uint_arr[5] = { + 1u, + 1125899906842624l, // truncated to 0 + 2147497230u, +}; + +unsigned long ulong_arr[4][6][2] = { + {{ + 1000.3, + }, // truncated to 1000 + {12u}}, + {{2}}}; + +int main() +{ + double dbl_sum = double_arr[0][0] + double_arr[0][1] + double_arr[1][0] + double_arr[1][1]; + if (dbl_sum != 10.0) + return 0; + + // check non-zero elements of uint_arr + if (uint_arr[0] == 1 && uint_arr[2] == 2147497230u) + { + // check zero elements of uint_arr + if (uint_arr[1] || uint_arr[3] || uint_arr[4]) + { + return 0; + } + + // now check ulong_arr + for (int i = 0; i < 4; i = i + 1) + for (int j = 0; j < 6; j = j + 1) + for (int k = 0; k < 2; k = k + 1) + { + int val = ulong_arr[i][j][k]; + if (i == 0 && j == 0 && k == 0 && val != 1000u) + return 0; + if (i == 0 && j == 1 && k == 0 && val != 12) + return 0; + if (i == 1 && j == 0 && k == 0 && val != 2) + return 0; + } + + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/chapter16/valid/initialization/nested.c b/chapter16/valid/initialization/nested.c new file mode 100644 index 00000000..c97b373a --- /dev/null +++ b/chapter16/valid/initialization/nested.c @@ -0,0 +1,4 @@ +int main() { + int arr[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + return arr[2][1]; +} \ No newline at end of file diff --git a/chapter16/valid/initialization/nested_partial_array.c b/chapter16/valid/initialization/nested_partial_array.c new file mode 100644 index 00000000..cde17256 --- /dev/null +++ b/chapter16/valid/initialization/nested_partial_array.c @@ -0,0 +1,16 @@ + +int main() +{ + int arr[3][2][5] = { + {{1, 2}, + {3, 4, 5}}, + {{6}}, + {{7}, + {8, 9, 10, 11, 12}}}; + + int sum = arr[0][0][0] + arr[0][0][1] + arr[0][1][0] + arr[0][1][1] + arr[0][1][2] + arr[1][0][0] + arr[2][0][0]; + for (int i = 0; i < 5; i = i + 1) + sum = sum + arr[2][1][i]; + + return sum; +} \ No newline at end of file diff --git a/chapter16/valid/initialization/static_uninitialized_array.c b/chapter16/valid/initialization/static_uninitialized_array.c new file mode 100644 index 00000000..130fd5a5 --- /dev/null +++ b/chapter16/valid/initialization/static_uninitialized_array.c @@ -0,0 +1,12 @@ +/* If a static array isn't explicitly initialized, eveyr lement should be initialized to zero */ +int arr[5][2][4]; + +int main() +{ + for (int i = 0; i < 5; i = i + 1) + for (int j = 0; j < 2; j = j + 1) + for (int k = 0; k < 4; k = k + 1) + if (arr[i][j][k] != 0) + return 0; + return 1; +} \ No newline at end of file diff --git a/chapter16/valid/initialization/too_short_array.c b/chapter16/valid/initialization/too_short_array.c new file mode 100644 index 00000000..b78690b6 --- /dev/null +++ b/chapter16/valid/initialization/too_short_array.c @@ -0,0 +1,9 @@ +int main() { + /* if some elments are explicitly initialized, remaining elements + * should be initialized to zero + */ + int arr[3] = {1}; + unsigned int arr2[2] = {3}; + return arr[0] == 1 && arr[1] == 0 && arr[2] == 0 && arr2[0] == 3 && + arr2[1] == 0; +} \ No newline at end of file diff --git a/chapter16/valid/initialization/too_short_static_array.c b/chapter16/valid/initialization/too_short_static_array.c new file mode 100644 index 00000000..0fe2f541 --- /dev/null +++ b/chapter16/valid/initialization/too_short_static_array.c @@ -0,0 +1,9 @@ +/* if some elments are explicitly initialized, remaining elements + * should be initialized to zero + */ +int arr[3] = {1, 2}; + +int main() +{ + return arr[0] + arr[1] + arr[2]; +} \ No newline at end of file diff --git a/chapter16/valid/initialization/trailing_comma_initializer.c b/chapter16/valid/initialization/trailing_comma_initializer.c new file mode 100644 index 00000000..4318babb --- /dev/null +++ b/chapter16/valid/initialization/trailing_comma_initializer.c @@ -0,0 +1,10 @@ +int foo(int a, int b, int c); +int main() +{ + int arr[3] = { + 1, + 2, + 3, + }; + return arr[2]; +} diff --git a/chapter16/valid/libraries/global_array.c b/chapter16/valid/libraries/global_array.c new file mode 100644 index 00000000..a78fe9c2 --- /dev/null +++ b/chapter16/valid/libraries/global_array.c @@ -0,0 +1,7 @@ +long x = 1000; +long *arr[4] = {0, 0, 0, 0}; + +long *set_pointer() { + arr[2] = &x; + return arr[1]; +} \ No newline at end of file diff --git a/chapter16/valid/libraries/global_array_client.c b/chapter16/valid/libraries/global_array_client.c new file mode 100644 index 00000000..5eaded8d --- /dev/null +++ b/chapter16/valid/libraries/global_array_client.c @@ -0,0 +1,15 @@ +extern long x; +extern long *arr[4]; + +long *set_pointer(); + +int main() { + if (set_pointer() != 0) + return 0; + if (*arr[2] != x) + return 0; + x = -4; + if (*arr[2] != x) + return 0; + return 1; +} \ No newline at end of file diff --git a/chapter16/valid/libraries/param_nested_array.c b/chapter16/valid/libraries/param_nested_array.c new file mode 100644 index 00000000..a0201d87 --- /dev/null +++ b/chapter16/valid/libraries/param_nested_array.c @@ -0,0 +1,6 @@ +int foo(int arg[1][2]) { + int elem[2] = {3, 9}; + arg[0][1] = elem[1]; + arg[0][0] = elem[0]; + return 0; +} \ No newline at end of file diff --git a/chapter16/valid/libraries/param_nested_array_client.c b/chapter16/valid/libraries/param_nested_array_client.c new file mode 100644 index 00000000..36e7c88d --- /dev/null +++ b/chapter16/valid/libraries/param_nested_array_client.c @@ -0,0 +1,7 @@ +int foo(int arg[1][2]); + +int main() { + int arg[1][2] = {{1, 2}}; + foo(arg); + return arg[0][1] + arg[0][0]; +} \ No newline at end of file diff --git a/chapter16/valid/libraries/set_array_val.c b/chapter16/valid/libraries/set_array_val.c new file mode 100644 index 00000000..df0ff25d --- /dev/null +++ b/chapter16/valid/libraries/set_array_val.c @@ -0,0 +1,4 @@ +int set_nth_element(double *arr, int idx) { + arr[idx] = 8; + return 0; +} \ No newline at end of file diff --git a/chapter16/valid/libraries/set_array_val_client.c b/chapter16/valid/libraries/set_array_val_client.c new file mode 100644 index 00000000..1cebb270 --- /dev/null +++ b/chapter16/valid/libraries/set_array_val_client.c @@ -0,0 +1,14 @@ +int set_nth_element(double *arr, int idx); + +int main() { + double arr[5] = {0.0, 0.0, 0.0, 0.0, 0.0}; + set_nth_element(arr, 4); + for (int i = 0; i < 4; i = i + 1) { + if (arr[i] != 0) { + return 0; + } + } + if (arr[4] == 8) + return 1; + return 0; +} \ No newline at end of file diff --git a/chapter16/valid/lvalue_test.c b/chapter16/valid/lvalue_test.c new file mode 100644 index 00000000..b49cfc06 --- /dev/null +++ b/chapter16/valid/lvalue_test.c @@ -0,0 +1,6 @@ +int main() { + int arr[2] = {1, 2}; + *arr = 3; + *(arr + 1) = 4; + return arr[0] + arr[1]; +} \ No newline at end of file diff --git a/chapter16/valid/nested2.c b/chapter16/valid/nested2.c new file mode 100644 index 00000000..f39bbef2 --- /dev/null +++ b/chapter16/valid/nested2.c @@ -0,0 +1,4 @@ +int main() { + int arr[3][2] = { { 1, 2 }, { 4, 5 }, { 7, 8 } }; + return arr[2][1]; +} \ No newline at end of file diff --git a/chapter16/valid/nested_not_initialized.c b/chapter16/valid/nested_not_initialized.c new file mode 100644 index 00000000..f14210a6 --- /dev/null +++ b/chapter16/valid/nested_not_initialized.c @@ -0,0 +1,5 @@ +int main() { + int arr[3][3]; + arr[2][1]= 99; + return arr[2][1]; +} \ No newline at end of file diff --git a/chapter16/valid/non_constant_initializer.c b/chapter16/valid/non_constant_initializer.c new file mode 100644 index 00000000..3bae5108 --- /dev/null +++ b/chapter16/valid/non_constant_initializer.c @@ -0,0 +1,8 @@ +int foo(int a, int b, int c) { + int arr[3] = {a, b, c}; + return arr[0] + arr[1] + arr[2]; +} + +int main() { + return foo(5, 6, 7); +} \ No newline at end of file diff --git a/chapter16/valid/param_pointer_to_array.c b/chapter16/valid/param_pointer_to_array.c new file mode 100644 index 00000000..38195263 --- /dev/null +++ b/chapter16/valid/param_pointer_to_array.c @@ -0,0 +1,8 @@ +int foo(int (*ptr_to_array)[3]) { + return ptr_to_array[0][1]; +} + +int main() { + int arr[3] = { 10, 11, 12}; + return foo(&arr); +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/add_non_standard_scale.c b/chapter16/valid/pointer_arithmetic/add_non_standard_scale.c new file mode 100644 index 00000000..2f9b3afe --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/add_non_standard_scale.c @@ -0,0 +1,11 @@ +int (*foo(int (*x)[7], long subscript))[7] +{ + return x + subscript; +} + +int main() +{ + int my_array[3][7] = {{0}, {1, 2, 3, 4}}; + int(*second_array)[7] = foo(my_array, 1); + return second_array[0][2]; +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/add_pointer_to_int.c b/chapter16/valid/pointer_arithmetic/add_pointer_to_int.c new file mode 100644 index 00000000..f3dbec2e --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/add_pointer_to_int.c @@ -0,0 +1,5 @@ +int main() { + int arr[3] = {1, 2, 3}; + int *ptr = 2 + arr; + return *ptr; +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/addr_of_array.c b/chapter16/valid/pointer_arithmetic/addr_of_array.c new file mode 100644 index 00000000..ecd63c73 --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/addr_of_array.c @@ -0,0 +1,5 @@ +int main() +{ + int arr[3] = {1, 2, 3}; + return arr == arr + 1l - 1l; +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/compare.c b/chapter16/valid/pointer_arithmetic/compare.c new file mode 100644 index 00000000..55a06fc9 --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/compare.c @@ -0,0 +1,9 @@ +int main() +{ + int arr[5] = {1, 2, 3, 4, 5}; + int gt = &arr[3] > &arr[1]; + int ge = &arr[2] >= &arr[2]; + int lt = arr + 4 < arr; + int le = arr + 1 <= arr + 2; + return (gt == 1 && ge == 1 && lt == 0 && le == 1); +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/compare_nested.c b/chapter16/valid/pointer_arithmetic/compare_nested.c new file mode 100644 index 00000000..5a366ad1 --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/compare_nested.c @@ -0,0 +1,4 @@ +int main() { + int arr[3][3] = { { 1, 2, 3 }, { 7, 8, 9 }, { 4, 5, 6 } }; + return (arr[2] > arr[1]); +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/negative_pointer_diff.c b/chapter16/valid/pointer_arithmetic/negative_pointer_diff.c new file mode 100644 index 00000000..58b6002c --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/negative_pointer_diff.c @@ -0,0 +1,6 @@ +int main() +{ + int arr[4] = {1, 2, 3, 4}; + int *ptr = arr + 3; + return (arr - ptr == -3); +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/nested_pointer_addition.c b/chapter16/valid/pointer_arithmetic/nested_pointer_addition.c new file mode 100644 index 00000000..d5da33da --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/nested_pointer_addition.c @@ -0,0 +1,4 @@ +int main() { + int arr[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + return (arr + 1)[1][2]; +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/nested_pointer_subtraction.c b/chapter16/valid/pointer_arithmetic/nested_pointer_subtraction.c new file mode 100644 index 00000000..433c5ae1 --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/nested_pointer_subtraction.c @@ -0,0 +1,6 @@ +int main() { + int arr[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + int (*row)[3] = &arr[2] - 1; + return row[0][0]; + +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/nested_ptr_diff.c b/chapter16/valid/pointer_arithmetic/nested_ptr_diff.c new file mode 100644 index 00000000..1c3f19e5 --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/nested_ptr_diff.c @@ -0,0 +1,7 @@ +int main() +{ + int multidim[6][7][4][2]; + int(*ptr1)[2] = multidim[3][4]; + int(*ptr2)[2] = &multidim[3][4][3]; + return ptr2 - ptr1; +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/one_past_end.c b/chapter16/valid/pointer_arithmetic/one_past_end.c new file mode 100644 index 00000000..1e5f23ab --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/one_past_end.c @@ -0,0 +1,6 @@ +int main() +{ + int x = 10; + int *y = &x + 1; // treat &x like one-element array - get pointer one past end of that array + return *(y - 1); +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/pointer_add.c b/chapter16/valid/pointer_arithmetic/pointer_add.c new file mode 100644 index 00000000..08b7fdb7 --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/pointer_add.c @@ -0,0 +1,5 @@ +int main() { + int arr[6] = { 1, 2, 3, 4, 5, 6 }; + int *arr_elem = arr + 2; + return *arr_elem == arr[2]; +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/pointer_add_neg.c b/chapter16/valid/pointer_arithmetic/pointer_add_neg.c new file mode 100644 index 00000000..900eef3a --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/pointer_add_neg.c @@ -0,0 +1,6 @@ +int main() { + int arr[3] = {1, 2, 3}; + int *ptr = arr + 2; + int *ptr2 = -1 + ptr; + return *ptr2; +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/pointer_sub.c b/chapter16/valid/pointer_arithmetic/pointer_sub.c new file mode 100644 index 00000000..3c590f55 --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/pointer_sub.c @@ -0,0 +1,15 @@ +int main() { + int arr[5] = { 5, 4, 3, 2, 1 }; + int *ptr4 = arr + 4; + int *ptr2 = arr + 2; + if (*ptr4 != 1) { + return 0; + } + if (*ptr2 != 3) { + return 0; + } + if (ptr4 - ptr2 != 2l) { + return 0; + } + return 1; +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/subtract_from_nested.c b/chapter16/valid/pointer_arithmetic/subtract_from_nested.c new file mode 100644 index 00000000..c15ba32a --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/subtract_from_nested.c @@ -0,0 +1,7 @@ +int main() +{ + long nested[4][5] = {{0}, {0}, {1, 2, 3}, {4, 5}}; + long(*ptr)[5] = nested + 4; // point one past end of array + ptr = ptr - 2; // point to second-to-lsat array element + return (*ptr)[2]; +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/subtract_negative.c b/chapter16/valid/pointer_arithmetic/subtract_negative.c new file mode 100644 index 00000000..935d49a1 --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/subtract_negative.c @@ -0,0 +1,6 @@ +int main() +{ + double arr[3] = {0, 1, 2}; + double *end_ptr = arr - (-2); + return *end_ptr; +} \ No newline at end of file diff --git a/chapter16/valid/pointer_arithmetic/subtract_pointers_to_arrays.c b/chapter16/valid/pointer_arithmetic/subtract_pointers_to_arrays.c new file mode 100644 index 00000000..27f5665b --- /dev/null +++ b/chapter16/valid/pointer_arithmetic/subtract_pointers_to_arrays.c @@ -0,0 +1,4 @@ +int main() { + int arr[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + return &arr[2] - &arr[0]; +} \ No newline at end of file diff --git a/chapter16/valid/return_array.c b/chapter16/valid/return_array.c new file mode 100644 index 00000000..cc2510c6 --- /dev/null +++ b/chapter16/valid/return_array.c @@ -0,0 +1,9 @@ +int *foo(int arr[3]) { + return arr + 1; +} + +int main() { + int arr[3] = {4, 5, 6}; + int *arr_incr = foo(arr); + return arr_incr[0]; +} \ No newline at end of file diff --git a/chapter16/valid/return_array_value.c b/chapter16/valid/return_array_value.c new file mode 100644 index 00000000..872c6e17 --- /dev/null +++ b/chapter16/valid/return_array_value.c @@ -0,0 +1,4 @@ +int main() { + int arr[3] = { 1, 2, 3 }; + return arr[1]; +} \ No newline at end of file diff --git a/chapter16/valid/return_pointer_to_array.c b/chapter16/valid/return_pointer_to_array.c new file mode 100644 index 00000000..2c3e010c --- /dev/null +++ b/chapter16/valid/return_pointer_to_array.c @@ -0,0 +1,10 @@ +int arr[3] = {0, 1, 2}; + +int (*foo())[3] { + return &arr; +} + +int main() { + int (*array)[3] = foo(); + return array[0][1]; +} \ No newline at end of file diff --git a/chapter16/valid/static_array.c b/chapter16/valid/static_array.c new file mode 100644 index 00000000..fa9de614 --- /dev/null +++ b/chapter16/valid/static_array.c @@ -0,0 +1,11 @@ +int foo(int idx, int v) { + static int arr[3]; + arr[idx] = v; + return arr[1]; +} + +int main() { + foo(1, 8); + foo(2, 9); + return foo(3, 10); +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/addition_subscript_equivalence.c b/chapter16/valid/subscripting/addition_subscript_equivalence.c new file mode 100644 index 00000000..2c14da34 --- /dev/null +++ b/chapter16/valid/subscripting/addition_subscript_equivalence.c @@ -0,0 +1,18 @@ +int main() +{ + unsigned long x[300][5]; + for (int i = 0; i < 300; i = i + 1) + for (int j = 0; j < 5; j = j + 1) + x[i][j] = i * 5 + j; + // check for equivalent values using explicit pointer dereference vs subscript + if (*(*(x + 20) + 3) != x[20][3]) + return 0; + + // same idea but taking address + if (&(*(*(x + 290) + 3)) != &x[290][3]) + return 0; + + // assign, then read + *(*(x + 275) + 4) = 22000ul; + return x[275][4] == 22000ul; +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/complex_index.c b/chapter16/valid/subscripting/complex_index.c new file mode 100644 index 00000000..53a910eb --- /dev/null +++ b/chapter16/valid/subscripting/complex_index.c @@ -0,0 +1,10 @@ +long foo(long *arr, int *a, int b) { + return arr[a[b]]; +} + +int main() { + long arr[3] = { 5l, 6l, 7l }; + int indices[3] = { 9, 5, 1};; + long res = foo(arr, indices, 2); + return (res == 6l); +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/const_index.c b/chapter16/valid/subscripting/const_index.c new file mode 100644 index 00000000..3bbf70b8 --- /dev/null +++ b/chapter16/valid/subscripting/const_index.c @@ -0,0 +1,4 @@ +int main() { + int arr[2] = {1, 2}; + return arr[1l]; +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/long_subscript.c b/chapter16/valid/subscripting/long_subscript.c new file mode 100644 index 00000000..98111629 --- /dev/null +++ b/chapter16/valid/subscripting/long_subscript.c @@ -0,0 +1,4 @@ +int main() { + int arr[4] = {1, 2, 3, 4}; + return arr[2l]; +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/neg_offset.c b/chapter16/valid/subscripting/neg_offset.c new file mode 100644 index 00000000..6cb530bf --- /dev/null +++ b/chapter16/valid/subscripting/neg_offset.c @@ -0,0 +1,6 @@ +int main() +{ + int foo[2][2] = {{1, 2}, {3, 4}}; + int(*foo_ptr)[2] = foo + 2; + return foo_ptr[-1][0]; +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/reverse_subscript.c b/chapter16/valid/subscripting/reverse_subscript.c new file mode 100644 index 00000000..ee069e34 --- /dev/null +++ b/chapter16/valid/subscripting/reverse_subscript.c @@ -0,0 +1,5 @@ +int main() +{ + int a[4] = {1, 2, 3, 4}; + return 2 [a]; // this is equivalent to a[2] +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/set_array_value.c b/chapter16/valid/subscripting/set_array_value.c new file mode 100644 index 00000000..b3dddb7c --- /dev/null +++ b/chapter16/valid/subscripting/set_array_value.c @@ -0,0 +1,5 @@ +int main() { + int arr[3] = { 1, 2, 3 }; + arr[2] = 5; + return arr[2] - arr[1]; +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/set_nested_array_value.c b/chapter16/valid/subscripting/set_nested_array_value.c new file mode 100644 index 00000000..a9d15aee --- /dev/null +++ b/chapter16/valid/subscripting/set_nested_array_value.c @@ -0,0 +1,5 @@ +int main() { + int arr[3][2] = { {1, 4}, {2, 3}, {5, 7} }; + arr[2][1] = 5; + return arr[2][1] - arr[1][1]; +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/subscript_pointer.c b/chapter16/valid/subscripting/subscript_pointer.c new file mode 100644 index 00000000..f211886a --- /dev/null +++ b/chapter16/valid/subscripting/subscript_pointer.c @@ -0,0 +1,5 @@ +int main() { + int a = 3; + int *ptr = &a; + return ptr[0]; +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/subscript_precedence.c b/chapter16/valid/subscripting/subscript_precedence.c new file mode 100644 index 00000000..afc14a75 --- /dev/null +++ b/chapter16/valid/subscripting/subscript_precedence.c @@ -0,0 +1,4 @@ +int main() { + int arr[3] = {1, 2, 3}; + return (-arr[2] == -3); +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/uint_subscript.c b/chapter16/valid/subscripting/uint_subscript.c new file mode 100644 index 00000000..0d66dbd1 --- /dev/null +++ b/chapter16/valid/subscripting/uint_subscript.c @@ -0,0 +1,4 @@ +int main() { + int arr[4] = {1, 2, 3, 4}; + return arr[2u]; +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/ulong_subscript.c b/chapter16/valid/subscripting/ulong_subscript.c new file mode 100644 index 00000000..a6a532d8 --- /dev/null +++ b/chapter16/valid/subscripting/ulong_subscript.c @@ -0,0 +1,4 @@ +int main() { + int arr[4] = {1, 2, 3, 4}; + return arr[2ul]; +} \ No newline at end of file diff --git a/chapter16/valid/subscripting/uninitialized_array.c b/chapter16/valid/subscripting/uninitialized_array.c new file mode 100644 index 00000000..a2a14227 --- /dev/null +++ b/chapter16/valid/subscripting/uninitialized_array.c @@ -0,0 +1,9 @@ +int main() { + int arr[5]; + + for (int i = 0; i < 5; i = i + 1) { + arr[i] = i; + } + + return arr[3]; +} \ No newline at end of file diff --git a/chapter16/valid_extra_credit/incr_ptr.c b/chapter16/valid_extra_credit/incr_ptr.c new file mode 100644 index 00000000..07dc1131 --- /dev/null +++ b/chapter16/valid_extra_credit/incr_ptr.c @@ -0,0 +1,8 @@ +int main() +{ + long x[3] = {0, -1, -2}; + long *y = x; + // y++; + ++y; + return *y == -1; +} \ No newline at end of file From 7b3886b771c503cdb7ed7ffb3205a4ac40e47e1d Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Mon, 6 Mar 2023 11:21:09 -0800 Subject: [PATCH 007/167] chapter 17 tests --- .../invalid_lex/char_bad_escape_sequence.c | 4 + chapter17/invalid_lex/newline.c | 8 ++ .../invalid_lex/string_bad_escape_sequence.c | 5 + chapter17/invalid_lex/unescaped_backslash.c | 4 + .../invalid_lex/unescaped_double_quote.c | 5 + .../invalid_lex/unescaped_single_quote.c | 4 + .../invalid_lex/unterminated_char_constant.c | 4 + chapter17/invalid_lex/unterminated_string.c | 4 + .../invalid_parse/invalid_type_specifier.c | 7 ++ .../invalid_parse/invalid_type_specifier_2.c | 5 + .../invalid_types/char_ptr_compound_init.c | 6 ++ .../conflicting_parameter_types.c | 13 +++ chapter17/invalid_types/conflicting_types.c | 9 ++ ...mplicit_conversion_between_char_pointers.c | 5 + .../invalid_types/implicit_conversion_int.c | 7 ++ chapter17/invalid_types/incorrect_length.c | 7 ++ .../invalid_types/initializer_too_long.c | 5 + chapter17/invalid_types/negate_char_pointer.c | 5 + chapter17/invalid_types/nested_char_string.c | 8 ++ .../nested_initializer_too_long.c | 7 ++ .../nested_initializer_wrong_type.c | 5 + .../nested_static_init_too_long.c | 9 ++ .../signed_char_string_literal.c | 5 + .../static_initializer_too_long.c | 4 + .../static_nested_initializer_wrong_type.c | 5 + .../static_signed_char_string_literal.c | 5 + chapter17/valid/char_constants/char.c | 3 + .../char_constants/char_constant_operations.c | 19 ++++ .../valid/char_constants/control_characters.c | 7 ++ .../valid/char_constants/special_characters.c | 8 ++ chapter17/valid/chars/add_char.c | 6 ++ chapter17/valid/chars/chars_are_ints.c | 15 +++ chapter17/valid/chars/chars_are_truthy.c | 26 +++++ chapter17/valid/chars/global_unsigned_char.c | 7 ++ chapter17/valid/chars/int_arguments.c | 8 ++ chapter17/valid/chars/integer_promotion.c | 41 ++++++++ chapter17/valid/chars/max_char_size.c | 12 +++ .../valid/chars/partial_initialization.c | 36 +++++++ chapter17/valid/chars/static_initializers.c | 36 +++++++ chapter17/valid/chars/truncate.c | 4 + chapter17/valid/chars/type_conversions.c | 56 +++++++++++ chapter17/valid/chars/type_specifiers.c | 11 +++ chapter17/valid/chars/unsigned.c | 5 + chapter17/valid/libraries/sign_extend_arg.c | 13 +++ .../valid/libraries/sign_extend_arg_client.c | 21 ++++ .../adjacent_strings_in_initializer.c | 20 ++++ .../array_init_special_chars.c | 6 ++ .../include_null_byte.c | 33 +++++++ .../initializer_lose_null_byte.c | 8 ++ .../literals_and_compound_initializers.c | 23 +++++ .../nested_array_no_null_bytes.c | 12 +++ .../partial_initialize_via_string.c | 97 +++++++++++++++++++ .../puts_to_char_array.c | 16 +++ .../read_from_char_array.c | 6 ++ .../static_initializer_lose_null_byte.c | 9 ++ .../static_nested_array_no_null_bytes.c | 14 +++ .../strings_as_initializers/test_alignment.c | 19 ++++ .../transfer_by_eightbyte.c | 20 ++++ .../strings_as_initializers/write_to_array.c | 10 ++ .../valid/strings_as_lvalues/addr_of_string.c | 4 + .../strings_as_lvalues/adjacent_strings.c | 4 + .../strings_as_lvalues/array_of_strings.c | 7 ++ chapter17/valid/strings_as_lvalues/atoi.c | 6 ++ .../valid/strings_as_lvalues/backslash.c | 4 + .../strings_as_lvalues/check_string_type.c | 10 ++ .../valid/strings_as_lvalues/double_quote.c | 5 + .../valid/strings_as_lvalues/empty_string.c | 5 + .../valid/strings_as_lvalues/hello_world.c | 7 ++ .../valid/strings_as_lvalues/literal_tab.c | 7 ++ chapter17/valid/strings_as_lvalues/newline.c | 6 ++ .../return_constant_string.c | 18 ++++ .../strings_as_lvalues/string_constant.c | 5 + .../string_special_characters.c | 5 + 73 files changed, 875 insertions(+) create mode 100644 chapter17/invalid_lex/char_bad_escape_sequence.c create mode 100644 chapter17/invalid_lex/newline.c create mode 100644 chapter17/invalid_lex/string_bad_escape_sequence.c create mode 100644 chapter17/invalid_lex/unescaped_backslash.c create mode 100644 chapter17/invalid_lex/unescaped_double_quote.c create mode 100644 chapter17/invalid_lex/unescaped_single_quote.c create mode 100644 chapter17/invalid_lex/unterminated_char_constant.c create mode 100644 chapter17/invalid_lex/unterminated_string.c create mode 100644 chapter17/invalid_parse/invalid_type_specifier.c create mode 100644 chapter17/invalid_parse/invalid_type_specifier_2.c create mode 100644 chapter17/invalid_types/char_ptr_compound_init.c create mode 100644 chapter17/invalid_types/conflicting_parameter_types.c create mode 100644 chapter17/invalid_types/conflicting_types.c create mode 100644 chapter17/invalid_types/implicit_conversion_between_char_pointers.c create mode 100644 chapter17/invalid_types/implicit_conversion_int.c create mode 100644 chapter17/invalid_types/incorrect_length.c create mode 100644 chapter17/invalid_types/initializer_too_long.c create mode 100644 chapter17/invalid_types/negate_char_pointer.c create mode 100644 chapter17/invalid_types/nested_char_string.c create mode 100644 chapter17/invalid_types/nested_initializer_too_long.c create mode 100644 chapter17/invalid_types/nested_initializer_wrong_type.c create mode 100644 chapter17/invalid_types/nested_static_init_too_long.c create mode 100644 chapter17/invalid_types/signed_char_string_literal.c create mode 100644 chapter17/invalid_types/static_initializer_too_long.c create mode 100644 chapter17/invalid_types/static_nested_initializer_wrong_type.c create mode 100644 chapter17/invalid_types/static_signed_char_string_literal.c create mode 100644 chapter17/valid/char_constants/char.c create mode 100644 chapter17/valid/char_constants/char_constant_operations.c create mode 100644 chapter17/valid/char_constants/control_characters.c create mode 100644 chapter17/valid/char_constants/special_characters.c create mode 100644 chapter17/valid/chars/add_char.c create mode 100644 chapter17/valid/chars/chars_are_ints.c create mode 100644 chapter17/valid/chars/chars_are_truthy.c create mode 100644 chapter17/valid/chars/global_unsigned_char.c create mode 100644 chapter17/valid/chars/int_arguments.c create mode 100644 chapter17/valid/chars/integer_promotion.c create mode 100644 chapter17/valid/chars/max_char_size.c create mode 100644 chapter17/valid/chars/partial_initialization.c create mode 100644 chapter17/valid/chars/static_initializers.c create mode 100644 chapter17/valid/chars/truncate.c create mode 100644 chapter17/valid/chars/type_conversions.c create mode 100644 chapter17/valid/chars/type_specifiers.c create mode 100644 chapter17/valid/chars/unsigned.c create mode 100644 chapter17/valid/libraries/sign_extend_arg.c create mode 100644 chapter17/valid/libraries/sign_extend_arg_client.c create mode 100644 chapter17/valid/strings_as_initializers/adjacent_strings_in_initializer.c create mode 100644 chapter17/valid/strings_as_initializers/array_init_special_chars.c create mode 100644 chapter17/valid/strings_as_initializers/include_null_byte.c create mode 100644 chapter17/valid/strings_as_initializers/initializer_lose_null_byte.c create mode 100644 chapter17/valid/strings_as_initializers/literals_and_compound_initializers.c create mode 100644 chapter17/valid/strings_as_initializers/nested_array_no_null_bytes.c create mode 100644 chapter17/valid/strings_as_initializers/partial_initialize_via_string.c create mode 100644 chapter17/valid/strings_as_initializers/puts_to_char_array.c create mode 100644 chapter17/valid/strings_as_initializers/read_from_char_array.c create mode 100644 chapter17/valid/strings_as_initializers/static_initializer_lose_null_byte.c create mode 100644 chapter17/valid/strings_as_initializers/static_nested_array_no_null_bytes.c create mode 100644 chapter17/valid/strings_as_initializers/test_alignment.c create mode 100644 chapter17/valid/strings_as_initializers/transfer_by_eightbyte.c create mode 100644 chapter17/valid/strings_as_initializers/write_to_array.c create mode 100644 chapter17/valid/strings_as_lvalues/addr_of_string.c create mode 100644 chapter17/valid/strings_as_lvalues/adjacent_strings.c create mode 100644 chapter17/valid/strings_as_lvalues/array_of_strings.c create mode 100644 chapter17/valid/strings_as_lvalues/atoi.c create mode 100644 chapter17/valid/strings_as_lvalues/backslash.c create mode 100644 chapter17/valid/strings_as_lvalues/check_string_type.c create mode 100644 chapter17/valid/strings_as_lvalues/double_quote.c create mode 100644 chapter17/valid/strings_as_lvalues/empty_string.c create mode 100644 chapter17/valid/strings_as_lvalues/hello_world.c create mode 100644 chapter17/valid/strings_as_lvalues/literal_tab.c create mode 100644 chapter17/valid/strings_as_lvalues/newline.c create mode 100644 chapter17/valid/strings_as_lvalues/return_constant_string.c create mode 100644 chapter17/valid/strings_as_lvalues/string_constant.c create mode 100644 chapter17/valid/strings_as_lvalues/string_special_characters.c diff --git a/chapter17/invalid_lex/char_bad_escape_sequence.c b/chapter17/invalid_lex/char_bad_escape_sequence.c new file mode 100644 index 00000000..7106f627 --- /dev/null +++ b/chapter17/invalid_lex/char_bad_escape_sequence.c @@ -0,0 +1,4 @@ +int main() +{ + return '\y'; +} \ No newline at end of file diff --git a/chapter17/invalid_lex/newline.c b/chapter17/invalid_lex/newline.c new file mode 100644 index 00000000..f3a3ed79 --- /dev/null +++ b/chapter17/invalid_lex/newline.c @@ -0,0 +1,8 @@ +char *s = "hello + world "; + + int + main() +{ + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_lex/string_bad_escape_sequence.c b/chapter17/invalid_lex/string_bad_escape_sequence.c new file mode 100644 index 00000000..728ae595 --- /dev/null +++ b/chapter17/invalid_lex/string_bad_escape_sequence.c @@ -0,0 +1,5 @@ +int main() +{ + char *str = "foo\ybar"; + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_lex/unescaped_backslash.c b/chapter17/invalid_lex/unescaped_backslash.c new file mode 100644 index 00000000..bedb10b2 --- /dev/null +++ b/chapter17/invalid_lex/unescaped_backslash.c @@ -0,0 +1,4 @@ +int main() +{ + return '\'; +} \ No newline at end of file diff --git a/chapter17/invalid_lex/unescaped_double_quote.c b/chapter17/invalid_lex/unescaped_double_quote.c new file mode 100644 index 00000000..2259b2e5 --- /dev/null +++ b/chapter17/invalid_lex/unescaped_double_quote.c @@ -0,0 +1,5 @@ +int main() +{ + char *ptr = "foo"bar";÷ + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_lex/unescaped_single_quote.c b/chapter17/invalid_lex/unescaped_single_quote.c new file mode 100644 index 00000000..1a17d542 --- /dev/null +++ b/chapter17/invalid_lex/unescaped_single_quote.c @@ -0,0 +1,4 @@ +int main() +{ + return '''; +} \ No newline at end of file diff --git a/chapter17/invalid_lex/unterminated_char_constant.c b/chapter17/invalid_lex/unterminated_char_constant.c new file mode 100644 index 00000000..4c04b551 --- /dev/null +++ b/chapter17/invalid_lex/unterminated_char_constant.c @@ -0,0 +1,4 @@ +int main() +{ + return 'x +} \ No newline at end of file diff --git a/chapter17/invalid_lex/unterminated_string.c b/chapter17/invalid_lex/unterminated_string.c new file mode 100644 index 00000000..2c066fc5 --- /dev/null +++ b/chapter17/invalid_lex/unterminated_string.c @@ -0,0 +1,4 @@ +int main() { + char *ptr = "foo\"; + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_parse/invalid_type_specifier.c b/chapter17/invalid_parse/invalid_type_specifier.c new file mode 100644 index 00000000..d7ca8bbc --- /dev/null +++ b/chapter17/invalid_parse/invalid_type_specifier.c @@ -0,0 +1,7 @@ +int main() +{ + // cannot combine char with any other type specifier + // except signed and unsigned + int char x = 10; + return x; +} \ No newline at end of file diff --git a/chapter17/invalid_parse/invalid_type_specifier_2.c b/chapter17/invalid_parse/invalid_type_specifier_2.c new file mode 100644 index 00000000..66c64893 --- /dev/null +++ b/chapter17/invalid_parse/invalid_type_specifier_2.c @@ -0,0 +1,5 @@ +int main() +{ + char static long x = 0; + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_types/char_ptr_compound_init.c b/chapter17/invalid_types/char_ptr_compound_init.c new file mode 100644 index 00000000..67500afe --- /dev/null +++ b/chapter17/invalid_types/char_ptr_compound_init.c @@ -0,0 +1,6 @@ +int main() +{ + // can't initialize a char * with a compound initializer + char *ptr = {'a', 'b', 'c'}; + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_types/conflicting_parameter_types.c b/chapter17/invalid_types/conflicting_parameter_types.c new file mode 100644 index 00000000..bbe7564d --- /dev/null +++ b/chapter17/invalid_types/conflicting_parameter_types.c @@ -0,0 +1,13 @@ +int foo(unsigned char c) +{ + return c; +} + +int main() +{ + return foo(0); +} + +// invalid redeclaration: char and unsigned char are +// different types +int foo(char c); \ No newline at end of file diff --git a/chapter17/invalid_types/conflicting_types.c b/chapter17/invalid_types/conflicting_types.c new file mode 100644 index 00000000..8f6edf62 --- /dev/null +++ b/chapter17/invalid_types/conflicting_types.c @@ -0,0 +1,9 @@ +char c = 10; + +int main() +{ + // this conflicts with previous definition of char, + // because char and signed char are different types + extern signed char c; + return c; +} \ No newline at end of file diff --git a/chapter17/invalid_types/implicit_conversion_between_char_pointers.c b/chapter17/invalid_types/implicit_conversion_between_char_pointers.c new file mode 100644 index 00000000..c695e5a1 --- /dev/null +++ b/chapter17/invalid_types/implicit_conversion_between_char_pointers.c @@ -0,0 +1,5 @@ +int main() { + char *c = 0; + signed char *s = c; + return (int) s; +} \ No newline at end of file diff --git a/chapter17/invalid_types/implicit_conversion_int.c b/chapter17/invalid_types/implicit_conversion_int.c new file mode 100644 index 00000000..27578759 --- /dev/null +++ b/chapter17/invalid_types/implicit_conversion_int.c @@ -0,0 +1,7 @@ +int main() +{ + // string literals can only initialize char arrays, + // not arrays of other types + long ints[4] = "abc"; + return ints[1]; +} \ No newline at end of file diff --git a/chapter17/invalid_types/incorrect_length.c b/chapter17/invalid_types/incorrect_length.c new file mode 100644 index 00000000..e95ff276 --- /dev/null +++ b/chapter17/invalid_types/incorrect_length.c @@ -0,0 +1,7 @@ +int main() +{ + // incompatible pointer type: &"x" has type char (*)[2], + // can't initilize a variable of type char (*)[10] + char(*string_pointer)[10] = &"x"; + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_types/initializer_too_long.c b/chapter17/invalid_types/initializer_too_long.c new file mode 100644 index 00000000..1ecc25fc --- /dev/null +++ b/chapter17/invalid_types/initializer_too_long.c @@ -0,0 +1,5 @@ +int main() +{ + char too_long[3] = "abcd"; + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_types/negate_char_pointer.c b/chapter17/invalid_types/negate_char_pointer.c new file mode 100644 index 00000000..7596637b --- /dev/null +++ b/chapter17/invalid_types/negate_char_pointer.c @@ -0,0 +1,5 @@ +int main() +{ + char *x = "foo"; + return -x; // can't negate pointer types +} \ No newline at end of file diff --git a/chapter17/invalid_types/nested_char_string.c b/chapter17/invalid_types/nested_char_string.c new file mode 100644 index 00000000..31fa74e8 --- /dev/null +++ b/chapter17/invalid_types/nested_char_string.c @@ -0,0 +1,8 @@ +// can only use a string literal to initialize +// a char array, not a char[3] array +char arr[3][3] = "hello"; + +int main() +{ + return arr[0][2]; +} \ No newline at end of file diff --git a/chapter17/invalid_types/nested_initializer_too_long.c b/chapter17/invalid_types/nested_initializer_too_long.c new file mode 100644 index 00000000..8540f3db --- /dev/null +++ b/chapter17/invalid_types/nested_initializer_too_long.c @@ -0,0 +1,7 @@ +int main() +{ + // initialize "bcde" is too long to initialize + // nested array of type char[3] + char array[3][3] = {"a", "bcde"}; + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_types/nested_initializer_wrong_type.c b/chapter17/invalid_types/nested_initializer_wrong_type.c new file mode 100644 index 00000000..48a8cc3b --- /dev/null +++ b/chapter17/invalid_types/nested_initializer_wrong_type.c @@ -0,0 +1,5 @@ +int main() +{ + unsigned int nested[1][2] = {"a"}; + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_types/nested_static_init_too_long.c b/chapter17/invalid_types/nested_static_init_too_long.c new file mode 100644 index 00000000..3b5df4f8 --- /dev/null +++ b/chapter17/invalid_types/nested_static_init_too_long.c @@ -0,0 +1,9 @@ +// initialize "bcde" is too long to initialize +// nested array of type char[3] +char array[3][3] = {"a", "bcde"}; + +int main() +{ + + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_types/signed_char_string_literal.c b/chapter17/invalid_types/signed_char_string_literal.c new file mode 100644 index 00000000..1b425b0b --- /dev/null +++ b/chapter17/invalid_types/signed_char_string_literal.c @@ -0,0 +1,5 @@ +int main() +{ + signed char *ptr = "foo"; // can't initialized signed char * from expression w/ type char * + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_types/static_initializer_too_long.c b/chapter17/invalid_types/static_initializer_too_long.c new file mode 100644 index 00000000..167e855a --- /dev/null +++ b/chapter17/invalid_types/static_initializer_too_long.c @@ -0,0 +1,4 @@ +int main() { + static char too_long[3] = "abcd"; + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_types/static_nested_initializer_wrong_type.c b/chapter17/invalid_types/static_nested_initializer_wrong_type.c new file mode 100644 index 00000000..945f00b2 --- /dev/null +++ b/chapter17/invalid_types/static_nested_initializer_wrong_type.c @@ -0,0 +1,5 @@ +int main() +{ + static long int nested[1][2] = {"a"}; + return 0; +} \ No newline at end of file diff --git a/chapter17/invalid_types/static_signed_char_string_literal.c b/chapter17/invalid_types/static_signed_char_string_literal.c new file mode 100644 index 00000000..999d7b24 --- /dev/null +++ b/chapter17/invalid_types/static_signed_char_string_literal.c @@ -0,0 +1,5 @@ +int main() +{ + static signed char *ptr = "foo"; // can't initialized signed char * from expression w/ type char * + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/char_constants/char.c b/chapter17/valid/char_constants/char.c new file mode 100644 index 00000000..cbdfe567 --- /dev/null +++ b/chapter17/valid/char_constants/char.c @@ -0,0 +1,3 @@ +int main() { + return 'c'; +} \ No newline at end of file diff --git a/chapter17/valid/char_constants/char_constant_operations.c b/chapter17/valid/char_constants/char_constant_operations.c new file mode 100644 index 00000000..9908600d --- /dev/null +++ b/chapter17/valid/char_constants/char_constant_operations.c @@ -0,0 +1,19 @@ +// make sure we can use character constants in all the same places as integers + +// use character constants to initialize static variables of any arithmetic type +double d = '\\'; + +int main() +{ + // can use character constants to specify array dimensions, + // and to initialize array elements of any int-compatible type + unsigned long array['\n'] = {1, 2, 'a', '\b', 3, 4, 5, '!', '%', '~'}; + + // can use character constants in arithmetic expressions + double d = 10 % '\a' + 4.0 * '_' - ~'@'; // 10 % 7 + 4.0 * 95 + + // can use character constants in subscript expressions + int i = array['\a']; + + return (array[2] == 97) && array[7] == 33 && array[8] == 37 && array[9] == 126 && d == 448.0 && i == 33; +} \ No newline at end of file diff --git a/chapter17/valid/char_constants/control_characters.c b/chapter17/valid/char_constants/control_characters.c new file mode 100644 index 00000000..7ca092b2 --- /dev/null +++ b/chapter17/valid/char_constants/control_characters.c @@ -0,0 +1,7 @@ +int main() +{ + char tab = ' '; + char vertical_tab = ' '; + char form_feed = ' '; + return (tab == '\t' && vertical_tab == '\v' && form_feed == '\f'); +} \ No newline at end of file diff --git a/chapter17/valid/char_constants/special_characters.c b/chapter17/valid/char_constants/special_characters.c new file mode 100644 index 00000000..d12a60c6 --- /dev/null +++ b/chapter17/valid/char_constants/special_characters.c @@ -0,0 +1,8 @@ +int main() { + if ('\?' == 63 && '\"' == 34 && '\'' == 39 && '\\' == 92 + && '\a' == 7 && '\b' == 8 && '\f' == 12 + && '\n' == 10 && '\r' == 13 && '\t' == 9 && '\v' == 11 ) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/chars/add_char.c b/chapter17/valid/chars/add_char.c new file mode 100644 index 00000000..7b0ae3e9 --- /dev/null +++ b/chapter17/valid/chars/add_char.c @@ -0,0 +1,6 @@ +int main() { + // a simple test of arithmetic with character types + char c = 'c'; + char a = 'a'; + return c - a; +} \ No newline at end of file diff --git a/chapter17/valid/chars/chars_are_ints.c b/chapter17/valid/chars/chars_are_ints.c new file mode 100644 index 00000000..f7ce4a74 --- /dev/null +++ b/chapter17/valid/chars/chars_are_ints.c @@ -0,0 +1,15 @@ +int main() +{ + // make sure we recognize chars as integer types and accept them in pointer arithmetic + char *ptr = "foo"; + signed char null = ptr[3]; // terminating null byte, so value is 0 + if (ptr[null] != 'f') // ptr[0] should be 'f' + return 5; + + unsigned char index = 3; + ptr = ptr + index; // points to null byte + if (*ptr) + return 6; + char index2 = 2; + return *(ptr - index2) == 'o'; +} \ No newline at end of file diff --git a/chapter17/valid/chars/chars_are_truthy.c b/chapter17/valid/chars/chars_are_truthy.c new file mode 100644 index 00000000..dd66f5d6 --- /dev/null +++ b/chapter17/valid/chars/chars_are_truthy.c @@ -0,0 +1,26 @@ +// use chars in contexts that treat them as boolean values (&&, ||, controlling expressions) + +int main() +{ + char c = 0; + if (c) + return 1; + unsigned char uc = 100; + if (!(c || uc)) + return 2; + + char signed s = -1; + if (!(uc && s)) + return 3; + + int count = 0; + // note: even if s - 1 < -128, this behavior is well-defined, + // b/c we promote to int, subtract, then truncate to char + for (; s; s = s - 1) + count = count + 1; + + if (count != 255 || s != 0) + return 4; + + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/chars/global_unsigned_char.c b/chapter17/valid/chars/global_unsigned_char.c new file mode 100644 index 00000000..c674e867 --- /dev/null +++ b/chapter17/valid/chars/global_unsigned_char.c @@ -0,0 +1,7 @@ +unsigned char c = 254; + +int main() { + unsigned char x = 2; + unsigned char i = c + x; + return (i == 1); +} \ No newline at end of file diff --git a/chapter17/valid/chars/int_arguments.c b/chapter17/valid/chars/int_arguments.c new file mode 100644 index 00000000..6f4208c3 --- /dev/null +++ b/chapter17/valid/chars/int_arguments.c @@ -0,0 +1,8 @@ +int foo(char a, char b, char c, unsigned char d, char e, char f) { + return a + b + c + d + e + f; +} + +int main() { + int ret = foo(5, 300, 3, 255, -3, 8); + return (ret == 312); +} \ No newline at end of file diff --git a/chapter17/valid/chars/integer_promotion.c b/chapter17/valid/chars/integer_promotion.c new file mode 100644 index 00000000..c3e4ddd4 --- /dev/null +++ b/chapter17/valid/chars/integer_promotion.c @@ -0,0 +1,41 @@ +int main() +{ + char z = 'z'; + char a = 'A'; + // these are both promoted so there's no overflow + if (z + z + a != 309) + return 1; + + unsigned char uc = 1; + // because this is promoted to an int before negation, + // the result is -1 instead of wrapping around to 255 + if ((int)-uc != -1) + return 2; + + // b/c this is promoted to int before complement, + // result is -2 instead of wrapping around to 254 + if ((int)~uc != -2) + return 2; + + signed char w = 127; + signed char x = 3; + signed char y = 2; + // we should promote all types to int so that intermediate result (127 + 3) + // doesn't overflow; final result will fit in signed char + signed char result = (w + x) / y; + if (result != 65) + return 3; + + // operating on signed/unsigned chars, both are converted to int + signed char sc = -3; + uc = 250; + if (sc * uc != -750) + return 4; + + char plain = -3; + // common type of char and unsigned long is unsigned long + if (plain * 1ul != 18446744073709551613ul) + return 5; + + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/chars/max_char_size.c b/chapter17/valid/chars/max_char_size.c new file mode 100644 index 00000000..c32e81be --- /dev/null +++ b/chapter17/valid/chars/max_char_size.c @@ -0,0 +1,12 @@ +int rand(); + +int main() { + for (int i = 0; i < 10; i = i + 1) { + unsigned char c = rand(); + int casted = (int) c; + if (casted >= 256) { + return 1; + } + } + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/chars/partial_initialization.c b/chapter17/valid/chars/partial_initialization.c new file mode 100644 index 00000000..c764a338 --- /dev/null +++ b/chapter17/valid/chars/partial_initialization.c @@ -0,0 +1,36 @@ +// make sure elements that aren't explicitly initialized are zeroed out +// include both static and non-static arrays of all three character types + +char static1[4] = {1, 2}; +signed char static2[4] = {3, 4}; +unsigned char static3[3] = {5}; + +int main() +{ + + // validate static arrays + if (static1[0] != 1 || static1[1] != 2 || static1[2] || static1[3]) + return 1; + + if (static2[0] != 3 || static2[1] != 4 || static2[2] || static2[3]) + return 2; + + if (static3[0] != 5 || static3[1] || static3[2]) + return 3; + + // define some non-static arrays + char auto1[5] = {-4, 66, 4.0}; + signed char auto2[3] = {static1[2], -static1[0]}; + unsigned char auto3[2] = {'a'}; + + if (auto1[0] != -4 || auto1[1] != 66 || auto1[2] != 4 || auto1[3] || auto1[4]) + return 4; + + if (auto2[0] || auto2[1] != -1 || auto2[2]) + return 5; + + if (auto3[0] != 'a' || auto3[1]) + return 6; + + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/chars/static_initializers.c b/chapter17/valid/chars/static_initializers.c new file mode 100644 index 00000000..1f58cf3c --- /dev/null +++ b/chapter17/valid/chars/static_initializers.c @@ -0,0 +1,36 @@ +// test statically initializing character types w/ other types of constants + +char from_long = 17592186044416l; + +char from_double = 15.6; + +char from_uint = 2147483777u; + +char from_ulong = 9223372037928517642ul; + +signed char schar_from_long = 17592186044419l; + +signed char schar_from_uint = 2147483898u; + +signed char schar_from_ulong = 9223372037928517642ul; + +signed char schar_from_double = 1e-10; + +unsigned char uchar_from_int = 13526; + +unsigned char uchar_from_uint = 2147483898u; + +unsigned char uchar_from_long = 1101659111674l; + +unsigned char uchar_from_ulong = 9223372037928517642ul; + +unsigned char uchar_from_double = 77.7; + +int main() { + return (from_long == 0 && from_double == 15 && from_uint == -127 && + from_ulong == 10 && schar_from_uint == -6 && schar_from_ulong == 10 && + schar_from_double == 0 && uchar_from_int == 214 && + uchar_from_uint == 250 && uchar_from_ulong == 10 && + uchar_from_double == 77 && schar_from_long == 3 && + uchar_from_long == 250); +} \ No newline at end of file diff --git a/chapter17/valid/chars/truncate.c b/chapter17/valid/chars/truncate.c new file mode 100644 index 00000000..97519288 --- /dev/null +++ b/chapter17/valid/chars/truncate.c @@ -0,0 +1,4 @@ +int main() { + unsigned char c = 256u; + return ((unsigned int) c == 0); +} \ No newline at end of file diff --git a/chapter17/valid/chars/type_conversions.c b/chapter17/valid/chars/type_conversions.c new file mode 100644 index 00000000..2f88e076 --- /dev/null +++ b/chapter17/valid/chars/type_conversions.c @@ -0,0 +1,56 @@ +int f(int i, long l, unsigned u, unsigned long ul, double d, unsigned char uc) +{ + return (i == -10 && l == -10 && u == 4294967286u && ul == 18446744073709551606ul && d == -10.0 && uc == 246); +} + +signed char return_char() +{ + // implicit conversion from int to signed char + return 4091; +} + +int main() +{ + + // signed char types to other types + signed char sc = -10; + // implicitly convert c to other types via parameter passing + if (!f(sc, sc, sc, sc, sc, sc)) + return 1; + char c = -10; + if (!f(c, c, c, c, c, c)) + return 2; + unsigned char uc = 250; + int unsigned_convert = ((int)uc == 250 && (unsigned int)uc == 250 && (long)uc == 250 && (unsigned long)uc == 250 && (double)uc == 250.0 && (char)uc == -6 && (signed char)uc == -6); + if (!unsigned_convert) + return 3; + + // other types to signed char + if ((sc = 128) != -128 // int + || (sc = 17592186044416l) != 0 // long + || (sc = 2147483898u) != -6 // unsigned + || (sc = 9224497936761618562ul) != -126 // unsigned long + || (sc = uc) != -6 // unsigned char + || (sc = -2.6) != -2) // double + return 4; + + sc = -1; + // other types to unsigned char + if ((uc = 252) != 252 // int + || (uc = 17592186044416l) != 0 // long + || (uc = 2147483898u) != 250 // unsigned + || (uc = 9224497936761618562ul) != 130 // unsigned long + || (uc = sc) != 255 // unsigned char + || (uc = 35.9) != 35) // double + return 5; + + // test cast from pointer to char (but not from char to pointer, result could be misaligned) + long *null_ptr = 0; + char zero = (char)null_ptr; + + if (zero) + return 6; + + int retval = return_char(); + return (retval != -5); +} \ No newline at end of file diff --git a/chapter17/valid/chars/type_specifiers.c b/chapter17/valid/chars/type_specifiers.c new file mode 100644 index 00000000..37d6bc3f --- /dev/null +++ b/chapter17/valid/chars/type_specifiers.c @@ -0,0 +1,11 @@ +// make sure we can parse all ways to specify signed &unsigned char + +char signed static a = 10; +unsigned static char b = 20; + +int main() +{ + extern signed char a; + char unsigned extern b; + return a + b; +} \ No newline at end of file diff --git a/chapter17/valid/chars/unsigned.c b/chapter17/valid/chars/unsigned.c new file mode 100644 index 00000000..a319e46e --- /dev/null +++ b/chapter17/valid/chars/unsigned.c @@ -0,0 +1,5 @@ +int main() { + unsigned int uint_max = (unsigned int) -1; + unsigned char uchar_max = (unsigned char) uint_max; + return (uchar_max == 255); +} \ No newline at end of file diff --git a/chapter17/valid/libraries/sign_extend_arg.c b/chapter17/valid/libraries/sign_extend_arg.c new file mode 100644 index 00000000..ce22b2a0 --- /dev/null +++ b/chapter17/valid/libraries/sign_extend_arg.c @@ -0,0 +1,13 @@ +int wide_params(int a, int b) +{ + return a + b; +} + +/* If we're using clang and theres' garbage in a + b, + * this will gave the wrong answer! + * NOTE: only w/ -O enabled, this will require special case handling in test script + * */ +int narrow_params(char a, char b) +{ + return wide_params(a, b); +} \ No newline at end of file diff --git a/chapter17/valid/libraries/sign_extend_arg_client.c b/chapter17/valid/libraries/sign_extend_arg_client.c new file mode 100644 index 00000000..d00ff305 --- /dev/null +++ b/chapter17/valid/libraries/sign_extend_arg_client.c @@ -0,0 +1,21 @@ +/* NOTE: due to ABI incompatibility between our compiler and clang, + * this should succeed if we compile lib with clang w/out optimizations, + * fail if we compile lib with clang w/ optimizations, + * succeed if we compile lib with GCC or ICC + */ + +int narrow_params(char a, char b); + +int compare_longs(long a, long b) +{ + return a == b; +} + +int main() +{ + /* pass values w/ upper bytes set in RDI & RSI */ + if (compare_longs(-1, -2)) + return 0; + /* now pass chars in RDI + RSI */ + return narrow_params(1, 2) == 3; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/adjacent_strings_in_initializer.c b/chapter17/valid/strings_as_initializers/adjacent_strings_in_initializer.c new file mode 100644 index 00000000..d1021df7 --- /dev/null +++ b/chapter17/valid/strings_as_initializers/adjacent_strings_in_initializer.c @@ -0,0 +1,20 @@ +int strcmp(char *s1, char *s2); + +int main() +{ + char multi_string[6] = "yes" + "no"; // can concatenate two string literals in an initializer + char nested_multi_string[2][3] = {"a" + "b", + "c" + "d"}; // first element is "ab", second is "cd" + + // validate multi_string + if (strcmp(multi_string, "yesno")) + return 1; + if (strcmp(nested_multi_string[0], "ab")) + return 2; + if (strcmp(nested_multi_string[1], "cd")) + return 3; + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/array_init_special_chars.c b/chapter17/valid/strings_as_initializers/array_init_special_chars.c new file mode 100644 index 00000000..803e1053 --- /dev/null +++ b/chapter17/valid/strings_as_initializers/array_init_special_chars.c @@ -0,0 +1,6 @@ +int main() +{ + // a mix of escaped and unescaped special characters + char special[6] = "\a\b\n "; + return special[0] == '\a' && special[1] == '\b' && special[2] == '\n' && special[3] == '\v' && special[4] == '\f' && special[5] == '\t'; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/include_null_byte.c b/chapter17/valid/strings_as_initializers/include_null_byte.c new file mode 100644 index 00000000..cb4bab84 --- /dev/null +++ b/chapter17/valid/strings_as_initializers/include_null_byte.c @@ -0,0 +1,33 @@ +// make sure we include null byte on end of char array initialized from string +// both nested and not, static and automatic, when we have enough space + +int strcmp(char *s1, char *s2); + +unsigned char flat[4] = "dog"; +char nested[2][4] = {"yes", "yup"}; + +int main() +{ + if (flat[0] != 'd' || flat[1] != 'o' || flat[2] != 'g' || flat[3]) + return 1; + + if (strcmp(nested[0], "yes") || strcmp(nested[1], "yup")) + return 2; + + // define some with automatic storage duration + char flat_auto[2] = "x"; + if (strcmp(flat_auto, "x")) + return 3; + char nested_auto[2][2][2] = {{"a", "b"}, {"c", "d"}}; + for (int i = 0; i < 1; i = i + 1) + for (int j = 0; j < 1; j = j + 1) + { + + char expected = 'a' + i * 2 + j; + if (nested_auto[i][j][0] != expected) + return 4; + if (nested_auto[i][j][1]) + return 5; + } + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/initializer_lose_null_byte.c b/chapter17/valid/strings_as_initializers/initializer_lose_null_byte.c new file mode 100644 index 00000000..06d6ef64 --- /dev/null +++ b/chapter17/valid/strings_as_initializers/initializer_lose_null_byte.c @@ -0,0 +1,8 @@ +int main() { + int x = 10; + // make sure null byte here doesn't corrupt ints on either side + char letters[4] = "abcd"; + int y = 12; + return x == 10 && y == 12 && letters[0] == 'a' && letters[1] == 'b' + && letters[2] == 'c' && letters[3] == 'd'; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/literals_and_compound_initializers.c b/chapter17/valid/strings_as_initializers/literals_and_compound_initializers.c new file mode 100644 index 00000000..8952c845 --- /dev/null +++ b/chapter17/valid/strings_as_initializers/literals_and_compound_initializers.c @@ -0,0 +1,23 @@ +// make sure we can include a mix of string literals and compound initializers to initialize a single nested array + +int strcmp(char *s1, char *s2); + +// static version +signed char static_array[3][4] = {{'a', 'b', 'c', 'd'}, "efgh", "ijk"}; + +int main() +{ + unsigned char auto_array[2][3] = {"lmn", {'o', 'p'}}; + + for (int i = 0; i < 3; i = i + 1) + for (int j = 0; j < 4; j = j + 1) + if (static_array[i][j] != "abcdefghijk"[i * 4 + j]) + return 1; + + for (int i = 0; i < 2; i = i + 1) + for (int j = 0; j < 3; j = j + 1) + if (auto_array[i][j] != "lmnop"[i * 3 + j]) + return 2; + + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/nested_array_no_null_bytes.c b/chapter17/valid/strings_as_initializers/nested_array_no_null_bytes.c new file mode 100644 index 00000000..254cd045 --- /dev/null +++ b/chapter17/valid/strings_as_initializers/nested_array_no_null_bytes.c @@ -0,0 +1,12 @@ +int strcmp(char *s1, char *s2); + +int main() +{ + char nested[3][3] = {"yes", "no", "ok"}; + char *whole_array = (char *)nested; + char *word1 = (char *)nested[0]; + char *word2 = (char *)nested[1]; + char *word3 = (char *)nested[2]; + // all strcmp calls should return 0 + return strcmp(whole_array, "yesno") || strcmp(word1, "yesno") || strcmp(word2, "no") || strcmp(word3, "ok"); +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/partial_initialize_via_string.c b/chapter17/valid/strings_as_initializers/partial_initialize_via_string.c new file mode 100644 index 00000000..e88e772c --- /dev/null +++ b/chapter17/valid/strings_as_initializers/partial_initialize_via_string.c @@ -0,0 +1,97 @@ +// make sure that when we initialize an array from a string literal, +// we zero out elements that aren't explicitly initialized +// include static/automatic/nested arrays w/ all three character types + +static char stat[5] = "hi"; +static signed char nested_stat[3][4] = {"", "bc"}; // empty string just initializes to null byte + +int main() +{ + + // validate stat + if (stat[0] != 'h' || stat[1] != 'i' || stat[2] || stat[3] || stat[4]) + return 1; + + // validate nested_stat + for (int i = 0; i < 3; i = i + 1) + for (int j = 0; j < 4; j = j + 1) + { + + signed char c = nested_stat[i][j]; + if (i == 0) + { + if (j == 0) + { + if (c) + return 2; + } + } + else if (i == 1) + { + if (j == 0 && c != 'b') + { + return 4; + } + else if (j == 1 && c != 'c') + { + return 5; + } + else if (j > 1 && c) + { + return 6; + } + } + else if (i > 1 && c) + { + return 7; + } + } + + unsigned char aut[4] = "ab"; + // validate aut + if (aut[0] != 'a' || aut[1] != 'b' || aut[2] || aut[3]) + return 8; + + signed char nested_auto[2][2][4] = {{"foo"}, {"x", "yz"}}; + // validate nested auto + signed char *foo = nested_auto[0][0]; + if (foo[0] != 'f' || foo[1] != 'o' || foo[2] != 'o' || foo[3]) + return 9; + for (int i = 0; i < 2; i = i + 1) + for (int j = 0; j < 2; j = j + 1) + { + if (i == 0 && j == 0) + { + // this is "foo", which we already validated + continue; + } + for (int k = 0; k < 4; k = k + 1) + { + signed char c = nested_auto[i][j][k]; + if (i == 1 && j == 0 && k == 0) + { + if (c != 'x') + return 10; + } + else if (i == 1 && j == 1) + { + if (k == 0 && c != 'y') + { + return 11; + } + else if (k == 1 && c != 'z') + { + return 12; + } + else if (k > 1 && c) + { + return 13; + } + } + else if (c) + return 14; + } + } + + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/puts_to_char_array.c b/chapter17/valid/strings_as_initializers/puts_to_char_array.c new file mode 100644 index 00000000..01f91e2e --- /dev/null +++ b/chapter17/valid/strings_as_initializers/puts_to_char_array.c @@ -0,0 +1,16 @@ +// simple test of writing to char array +// and make sure puts works (test script validates stdout) + +int puts(char *c); + +int main() +{ + char str_array[2][6] = {"Hello", "World"}; + puts(str_array[0]); + puts(str_array[1]); + + str_array[0][0] = 'J'; + puts(str_array[0]); + + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/read_from_char_array.c b/chapter17/valid/strings_as_initializers/read_from_char_array.c new file mode 100644 index 00000000..28e994fd --- /dev/null +++ b/chapter17/valid/strings_as_initializers/read_from_char_array.c @@ -0,0 +1,6 @@ +int main() +{ + // simple test of initializing and subscripting char array + unsigned char chars[4] = "abc"; + return chars[2]; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/static_initializer_lose_null_byte.c b/chapter17/valid/strings_as_initializers/static_initializer_lose_null_byte.c new file mode 100644 index 00000000..04c8c5b0 --- /dev/null +++ b/chapter17/valid/strings_as_initializers/static_initializer_lose_null_byte.c @@ -0,0 +1,9 @@ +int main() { + int x = 10; + // shouldn't corrupt anything if we add a null byte here, + // so this is just to make sure it type checks + static char letters[4] = "abcd"; + int y = 12; + return x == 10 && y == 12 && letters[0] == 'a' && letters[1] == 'b' + && letters[2] == 'c' && letters[3] == 'd'; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/static_nested_array_no_null_bytes.c b/chapter17/valid/strings_as_initializers/static_nested_array_no_null_bytes.c new file mode 100644 index 00000000..a8489b79 --- /dev/null +++ b/chapter17/valid/strings_as_initializers/static_nested_array_no_null_bytes.c @@ -0,0 +1,14 @@ +int strcmp(char *s1, char *s2); + +char nested[3][3] = {"yes", "no", "ok"}; + +int main() +{ + + char *whole_array = (char *)nested; + char *word1 = (char *)nested[0]; + char *word2 = (char *)nested[1]; + char *word3 = (char *)nested[2]; + // all strcmp calls should return 0 + return strcmp(whole_array, "yesno") || strcmp(word1, "yesno") || strcmp(word2, "no") || strcmp(word3, "ok"); +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/test_alignment.c b/chapter17/valid/strings_as_initializers/test_alignment.c new file mode 100644 index 00000000..181198e7 --- /dev/null +++ b/chapter17/valid/strings_as_initializers/test_alignment.c @@ -0,0 +1,19 @@ +// make sure any char array variables larger than 16 bytes are 16-byte aligned + +int check_aligment(char *c) +{ + unsigned long l = (unsigned long)c; + return (l % 16 == 0); // return 1 on success, 0 on failure +} + +static unsigned char nested[3][4][2] = {{"a"}, {"b"}}; + +static signed char flat[17] = "x"; + +int main() +{ + char nested_auto[10][3]; + char flat_auto[22]; + + return (check_aligment((char *)nested) && check_aligment((char *)flat) && check_aligment((char *)nested_auto) && check_aligment(flat_auto)); +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/transfer_by_eightbyte.c b/chapter17/valid/strings_as_initializers/transfer_by_eightbyte.c new file mode 100644 index 00000000..05a0adce --- /dev/null +++ b/chapter17/valid/strings_as_initializers/transfer_by_eightbyte.c @@ -0,0 +1,20 @@ +int strcmp(char *s1, char *s2); + +// if you initialize arrays 4 or 8 bytes at a time, +// make sure you don't overrrun neighboring memory + +int main() +{ + char strings[2][13] = {"abcdefghijkl", "z"}; + if (strcmp(strings[0], "abcdefghijkl")) + return 1; + + if (strings[1][0] != 'z') + return 2; + for (int i = 1; i < 13; i = i + 1) + { + if (strings[1][i]) + return 3; + } + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_initializers/write_to_array.c b/chapter17/valid/strings_as_initializers/write_to_array.c new file mode 100644 index 00000000..77baf70c --- /dev/null +++ b/chapter17/valid/strings_as_initializers/write_to_array.c @@ -0,0 +1,10 @@ +// basic test of writing to a char array + +int main() +{ + char literal[4] = "abc"; + char b = literal[2]; + literal[2] = 'x'; + char x = literal[2]; + return (b == 'b' && x == 'x'); +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/addr_of_string.c b/chapter17/valid/strings_as_lvalues/addr_of_string.c new file mode 100644 index 00000000..ffeb9b4b --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/addr_of_string.c @@ -0,0 +1,4 @@ +int main() { + char (*string_literal)[12] = &"hello world"; + return string_literal[0][3]; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/adjacent_strings.c b/chapter17/valid/strings_as_lvalues/adjacent_strings.c new file mode 100644 index 00000000..235a1656 --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/adjacent_strings.c @@ -0,0 +1,4 @@ +int main() { + char *strings = "Hello," " World"; + return strings[8]; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/array_of_strings.c b/chapter17/valid/strings_as_lvalues/array_of_strings.c new file mode 100644 index 00000000..59ade6be --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/array_of_strings.c @@ -0,0 +1,7 @@ +int strcmp(char *s1, char *s2); + +int main() +{ + char *strings[3] = {"yes", "no", "maybe"}; + return strcmp(strings[0], "yes") && strcmp(strings[1], "no") && strcmp(strings[2], "maybe"); +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/atoi.c b/chapter17/valid/strings_as_lvalues/atoi.c new file mode 100644 index 00000000..890f494c --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/atoi.c @@ -0,0 +1,6 @@ +// test standard library function +int atoi(char *str); +int main() +{ + return atoi("10"); +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/backslash.c b/chapter17/valid/strings_as_lvalues/backslash.c new file mode 100644 index 00000000..155535e7 --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/backslash.c @@ -0,0 +1,4 @@ +int main() +{ + return "Hello\\World"[5]; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/check_string_type.c b/chapter17/valid/strings_as_lvalues/check_string_type.c new file mode 100644 index 00000000..ff8a99ba --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/check_string_type.c @@ -0,0 +1,10 @@ +// make sure we annotate string literals w/ correct type (accounting for length of null byte) + +int main() +{ + // get one-past-the-end pointer to end of this string + char(*str)[16] = &"Sample\tstring!\a" + 1; + char *end_ptr = (char *)str - 1; + // this should point to null byte + return *end_ptr; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/double_quote.c b/chapter17/valid/strings_as_lvalues/double_quote.c new file mode 100644 index 00000000..9275e5c9 --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/double_quote.c @@ -0,0 +1,5 @@ +int main() +{ + unsigned char *c = (unsigned char *)"Hello\"world"; + return c[6]; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/empty_string.c b/chapter17/valid/strings_as_lvalues/empty_string.c new file mode 100644 index 00000000..12655494 --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/empty_string.c @@ -0,0 +1,5 @@ +int main() +{ + signed char *empty = (signed char *)""; + return empty[0]; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/hello_world.c b/chapter17/valid/strings_as_lvalues/hello_world.c new file mode 100644 index 00000000..4414edbd --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/hello_world.c @@ -0,0 +1,7 @@ +int puts(char *c); + +int main() { + + puts("Hello, World!"); + return 0; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/literal_tab.c b/chapter17/valid/strings_as_lvalues/literal_tab.c new file mode 100644 index 00000000..cfe6db07 --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/literal_tab.c @@ -0,0 +1,7 @@ + +int strcmp(char *s1, char *s2); + +int main() { + char *tab = " "; + return strcmp(tab, "\t"); +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/newline.c b/chapter17/valid/strings_as_lvalues/newline.c new file mode 100644 index 00000000..f21d5253 --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/newline.c @@ -0,0 +1,6 @@ +char *multiline = "Line\nbreak!"; +int puts(char *c); + +int main() { + puts(multiline); +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/return_constant_string.c b/chapter17/valid/strings_as_lvalues/return_constant_string.c new file mode 100644 index 00000000..7a873289 --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/return_constant_string.c @@ -0,0 +1,18 @@ +// test basic operations on pointers to constant strings - returning them, assigning them, pointer atihemtic, etc. + +char *return_string() +{ + // constant strings have static storage duration, + // so this will persist after the function call; + return "I'm a string!"; +} +int main() +{ + char *ptr = 0; + ptr = return_string(); + if (!ptr) + return 0; + char *ptr2; + ptr2 = 1 ? ptr + 2 : ptr + 4; + return *ptr2 == 'm'; +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/string_constant.c b/chapter17/valid/strings_as_lvalues/string_constant.c new file mode 100644 index 00000000..4743d1fb --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/string_constant.c @@ -0,0 +1,5 @@ +char *x = "Hello, World!"; + +int main() { + return (x[2] == 'l'); +} \ No newline at end of file diff --git a/chapter17/valid/strings_as_lvalues/string_special_characters.c b/chapter17/valid/strings_as_lvalues/string_special_characters.c new file mode 100644 index 00000000..6b29ab65 --- /dev/null +++ b/chapter17/valid/strings_as_lvalues/string_special_characters.c @@ -0,0 +1,5 @@ +int main() +{ + char *c = "\a\b"; + return c[0] == 7 && c[1] == 8 && c[2] == 0; +} \ No newline at end of file From 28bc547f6b0fd415f72d0d665afb4ff111ed1bcb Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Mon, 6 Mar 2023 14:14:34 -0800 Subject: [PATCH 008/167] chapter 18 tests --- chapter18/invalid_parse/bad_specifier.c | 4 ++ chapter18/invalid_parse/bad_specifier_2.c | 3 ++ chapter18/invalid_parse/sizeof_cast.c | 2 + .../invalid_parse/sizeof_type_no_parens.c | 1 + .../incomplete_types/add_void_pointer.c | 7 ++++ .../incomplete_types/cast_bad_type.c | 4 ++ .../invalid_array_function_params.c | 7 ++++ .../incomplete_types/nested_void_array.c | 6 +++ .../incomplete_types/pointer_to_void_array.c | 6 +++ .../incomplete_types/sizeof_bad_type.c | 3 ++ .../incomplete_types/sizeof_function.c | 4 ++ .../incomplete_types/sizeof_void.c | 3 ++ .../incomplete_types/sizeof_void_expression.c | 4 ++ .../incomplete_types/sub_void_pointer.c | 6 +++ .../incomplete_types/subscript_void.c | 6 +++ .../subscript_void_pointer_conditional.c | 8 ++++ .../incomplete_types/void_array.c | 4 ++ .../incomplete_types/void_array_param.c | 6 +++ .../compare_void_ptr_to_int.c | 1 + .../compare_void_to_other_pointer.c | 5 +++ .../convert_ulong_to_void_ptr.c | 4 ++ .../convert_void_ptr_to_int.c | 4 ++ .../usual_arithmetic_conversions_ptr.c | 4 ++ .../scalar_expressions/and_void.c | 1 + .../scalar_expressions/not_void.c | 3 ++ .../scalar_expressions/or_void.c | 1 + .../scalar_expressions/void_as_integer.c | 6 +++ .../void_condition_do_loop.c | 8 ++++ .../void_condition_for_loop.c | 9 +++++ .../void_condition_while_loop.c | 8 ++++ .../scalar_expressions/void_if_condition.c | 6 +++ .../void_ternary_condition.c | 3 ++ .../void/assign_to_void_lvalue.c | 10 +++++ .../invalid_types/void/assign_to_void_var.c | 9 +++++ .../invalid_types/void/assign_void_rval.c | 6 +++ chapter18/invalid_types/void/cast_void.c | 4 ++ chapter18/invalid_types/void/define_void.c | 5 +++ .../invalid_types/void/initialized_void.c | 4 ++ .../void/mismatched_conditional.c | 10 +++++ chapter18/invalid_types/void/negate_void.c | 4 ++ .../invalid_types/void/no_return_value.c | 10 +++++ .../invalid_types/void/non_void_return.c | 9 +++++ .../void/return_void_as_pointer.c | 5 +++ .../void/tentative_define_void.c | 7 ++++ chapter18/invalid_types/void/void_compare.c | 5 +++ chapter18/invalid_types/void/void_equality.c | 2 + .../invalid_types/void/void_fun_params.c | 5 +++ chapter18/valid/libraries/return_void.c | 11 ++++++ .../valid/libraries/return_void_client.c | 7 ++++ chapter18/valid/libraries/tern.c | 10 +++++ chapter18/valid/libraries/tern_client.c | 14 +++++++ chapter18/valid/sizeof/sizeof_array.c | 6 +++ chapter18/valid/sizeof/sizeof_array_type.c | 5 +++ chapter18/valid/sizeof/sizeof_char.c | 7 ++++ chapter18/valid/sizeof/sizeof_complex_type.c | 8 ++++ chapter18/valid/sizeof/sizeof_is_unsigned.c | 7 ++++ chapter18/valid/sizeof/sizeof_not_evaluated.c | 7 ++++ chapter18/valid/sizeof/sizeof_pointer.c | 7 ++++ chapter18/valid/sizeof/sizeof_sizeof.c | 4 ++ chapter18/valid/sizeof/sizeof_string.c | 3 ++ chapter18/valid/sizeof/sizeof_type.c | 4 ++ chapter18/valid/void/cast_to_void.c | 4 ++ chapter18/valid/void/cast_void_to_void.c | 8 ++++ chapter18/valid/void/ternary.c | 9 +++++ chapter18/valid/void/void_for_init.c | 11 ++++++ chapter18/valid/void/void_for_post.c | 9 +++++ chapter18/valid/void/void_function.c | 10 +++++ .../void_pointer/array_of_pointers_to_void.c | 26 +++++++++++++ .../valid/void_pointer/common_pointer_type.c | 37 +++++++++++++++++++ .../void_pointer/conversion_by_assignment.c | 32 ++++++++++++++++ chapter18/valid/void_pointer/explicit_cast.c | 29 +++++++++++++++ chapter18/valid/void_pointer/malloc.c | 13 +++++++ 72 files changed, 530 insertions(+) create mode 100644 chapter18/invalid_parse/bad_specifier.c create mode 100644 chapter18/invalid_parse/bad_specifier_2.c create mode 100644 chapter18/invalid_parse/sizeof_cast.c create mode 100644 chapter18/invalid_parse/sizeof_type_no_parens.c create mode 100644 chapter18/invalid_types/incomplete_types/add_void_pointer.c create mode 100644 chapter18/invalid_types/incomplete_types/cast_bad_type.c create mode 100644 chapter18/invalid_types/incomplete_types/invalid_array_function_params.c create mode 100644 chapter18/invalid_types/incomplete_types/nested_void_array.c create mode 100644 chapter18/invalid_types/incomplete_types/pointer_to_void_array.c create mode 100644 chapter18/invalid_types/incomplete_types/sizeof_bad_type.c create mode 100644 chapter18/invalid_types/incomplete_types/sizeof_function.c create mode 100644 chapter18/invalid_types/incomplete_types/sizeof_void.c create mode 100644 chapter18/invalid_types/incomplete_types/sizeof_void_expression.c create mode 100644 chapter18/invalid_types/incomplete_types/sub_void_pointer.c create mode 100644 chapter18/invalid_types/incomplete_types/subscript_void.c create mode 100644 chapter18/invalid_types/incomplete_types/subscript_void_pointer_conditional.c create mode 100644 chapter18/invalid_types/incomplete_types/void_array.c create mode 100644 chapter18/invalid_types/incomplete_types/void_array_param.c create mode 100644 chapter18/invalid_types/pointer_conversions/compare_void_ptr_to_int.c create mode 100644 chapter18/invalid_types/pointer_conversions/compare_void_to_other_pointer.c create mode 100644 chapter18/invalid_types/pointer_conversions/convert_ulong_to_void_ptr.c create mode 100644 chapter18/invalid_types/pointer_conversions/convert_void_ptr_to_int.c create mode 100644 chapter18/invalid_types/pointer_conversions/usual_arithmetic_conversions_ptr.c create mode 100644 chapter18/invalid_types/scalar_expressions/and_void.c create mode 100644 chapter18/invalid_types/scalar_expressions/not_void.c create mode 100644 chapter18/invalid_types/scalar_expressions/or_void.c create mode 100644 chapter18/invalid_types/scalar_expressions/void_as_integer.c create mode 100644 chapter18/invalid_types/scalar_expressions/void_condition_do_loop.c create mode 100644 chapter18/invalid_types/scalar_expressions/void_condition_for_loop.c create mode 100644 chapter18/invalid_types/scalar_expressions/void_condition_while_loop.c create mode 100644 chapter18/invalid_types/scalar_expressions/void_if_condition.c create mode 100644 chapter18/invalid_types/scalar_expressions/void_ternary_condition.c create mode 100644 chapter18/invalid_types/void/assign_to_void_lvalue.c create mode 100644 chapter18/invalid_types/void/assign_to_void_var.c create mode 100644 chapter18/invalid_types/void/assign_void_rval.c create mode 100644 chapter18/invalid_types/void/cast_void.c create mode 100644 chapter18/invalid_types/void/define_void.c create mode 100644 chapter18/invalid_types/void/initialized_void.c create mode 100644 chapter18/invalid_types/void/mismatched_conditional.c create mode 100644 chapter18/invalid_types/void/negate_void.c create mode 100644 chapter18/invalid_types/void/no_return_value.c create mode 100644 chapter18/invalid_types/void/non_void_return.c create mode 100644 chapter18/invalid_types/void/return_void_as_pointer.c create mode 100644 chapter18/invalid_types/void/tentative_define_void.c create mode 100644 chapter18/invalid_types/void/void_compare.c create mode 100644 chapter18/invalid_types/void/void_equality.c create mode 100644 chapter18/invalid_types/void/void_fun_params.c create mode 100644 chapter18/valid/libraries/return_void.c create mode 100644 chapter18/valid/libraries/return_void_client.c create mode 100644 chapter18/valid/libraries/tern.c create mode 100644 chapter18/valid/libraries/tern_client.c create mode 100644 chapter18/valid/sizeof/sizeof_array.c create mode 100644 chapter18/valid/sizeof/sizeof_array_type.c create mode 100644 chapter18/valid/sizeof/sizeof_char.c create mode 100644 chapter18/valid/sizeof/sizeof_complex_type.c create mode 100644 chapter18/valid/sizeof/sizeof_is_unsigned.c create mode 100644 chapter18/valid/sizeof/sizeof_not_evaluated.c create mode 100644 chapter18/valid/sizeof/sizeof_pointer.c create mode 100644 chapter18/valid/sizeof/sizeof_sizeof.c create mode 100644 chapter18/valid/sizeof/sizeof_string.c create mode 100644 chapter18/valid/sizeof/sizeof_type.c create mode 100644 chapter18/valid/void/cast_to_void.c create mode 100644 chapter18/valid/void/cast_void_to_void.c create mode 100644 chapter18/valid/void/ternary.c create mode 100644 chapter18/valid/void/void_for_init.c create mode 100644 chapter18/valid/void/void_for_post.c create mode 100644 chapter18/valid/void/void_function.c create mode 100644 chapter18/valid/void_pointer/array_of_pointers_to_void.c create mode 100644 chapter18/valid/void_pointer/common_pointer_type.c create mode 100644 chapter18/valid/void_pointer/conversion_by_assignment.c create mode 100644 chapter18/valid/void_pointer/explicit_cast.c create mode 100644 chapter18/valid/void_pointer/malloc.c diff --git a/chapter18/invalid_parse/bad_specifier.c b/chapter18/invalid_parse/bad_specifier.c new file mode 100644 index 00000000..cbdc5c68 --- /dev/null +++ b/chapter18/invalid_parse/bad_specifier.c @@ -0,0 +1,4 @@ +int main() { + unsigned void *v; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_parse/bad_specifier_2.c b/chapter18/invalid_parse/bad_specifier_2.c new file mode 100644 index 00000000..a8930a9c --- /dev/null +++ b/chapter18/invalid_parse/bad_specifier_2.c @@ -0,0 +1,3 @@ +void char *x; + +int main() { return 0; } \ No newline at end of file diff --git a/chapter18/invalid_parse/sizeof_cast.c b/chapter18/invalid_parse/sizeof_cast.c new file mode 100644 index 00000000..490cea2f --- /dev/null +++ b/chapter18/invalid_parse/sizeof_cast.c @@ -0,0 +1,2 @@ +// can't apply sizeof to unparenthesized cast expression +int main() { return sizeof(char) 1; } \ No newline at end of file diff --git a/chapter18/invalid_parse/sizeof_type_no_parens.c b/chapter18/invalid_parse/sizeof_type_no_parens.c new file mode 100644 index 00000000..daaba081 --- /dev/null +++ b/chapter18/invalid_parse/sizeof_type_no_parens.c @@ -0,0 +1 @@ +int main() { return sizeof int; } \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/add_void_pointer.c b/chapter18/invalid_types/incomplete_types/add_void_pointer.c new file mode 100644 index 00000000..7a796ad4 --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/add_void_pointer.c @@ -0,0 +1,7 @@ +void *malloc(unsigned long size); + +int main() { + void *x = malloc(100); + x = x + 1; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/cast_bad_type.c b/chapter18/invalid_types/incomplete_types/cast_bad_type.c new file mode 100644 index 00000000..0c5fc807 --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/cast_bad_type.c @@ -0,0 +1,4 @@ +int main() { + (void(*)[3]) 4; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/invalid_array_function_params.c b/chapter18/invalid_types/incomplete_types/invalid_array_function_params.c new file mode 100644 index 00000000..28af3418 --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/invalid_array_function_params.c @@ -0,0 +1,7 @@ +int foo(void (*bad_array)[3]) { + return bad_array == 0; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/nested_void_array.c b/chapter18/invalid_types/incomplete_types/nested_void_array.c new file mode 100644 index 00000000..0e8dce4d --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/nested_void_array.c @@ -0,0 +1,6 @@ +extern void (*ptr)[3][4]; + +void *foo() +{ + return ptr; +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/pointer_to_void_array.c b/chapter18/invalid_types/incomplete_types/pointer_to_void_array.c new file mode 100644 index 00000000..53eda63f --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/pointer_to_void_array.c @@ -0,0 +1,6 @@ +void *malloc(unsigned long size); + +int main() { + void (*ptr)[3] = malloc(3); + return ptr == 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/sizeof_bad_type.c b/chapter18/invalid_types/incomplete_types/sizeof_bad_type.c new file mode 100644 index 00000000..d421d56a --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/sizeof_bad_type.c @@ -0,0 +1,3 @@ +int main() { + return sizeof(void[3]); +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/sizeof_function.c b/chapter18/invalid_types/incomplete_types/sizeof_function.c new file mode 100644 index 00000000..c083d415 --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/sizeof_function.c @@ -0,0 +1,4 @@ +int x() { return 0; } + +// can't apply sizeof to a function +int main() { return sizeof x; } \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/sizeof_void.c b/chapter18/invalid_types/incomplete_types/sizeof_void.c new file mode 100644 index 00000000..cc03f98d --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/sizeof_void.c @@ -0,0 +1,3 @@ +int main() { + return sizeof (void); +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/sizeof_void_expression.c b/chapter18/invalid_types/incomplete_types/sizeof_void_expression.c new file mode 100644 index 00000000..b106bd09 --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/sizeof_void_expression.c @@ -0,0 +1,4 @@ +int main() { + int x; + return sizeof((void)x); +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/sub_void_pointer.c b/chapter18/invalid_types/incomplete_types/sub_void_pointer.c new file mode 100644 index 00000000..faec823d --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/sub_void_pointer.c @@ -0,0 +1,6 @@ +int main() { + int y; + void *x = &y; + void *null = 0; + return x - null; +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/subscript_void.c b/chapter18/invalid_types/incomplete_types/subscript_void.c new file mode 100644 index 00000000..cf003014 --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/subscript_void.c @@ -0,0 +1,6 @@ +int main() { + int x = 10; + void *v = &x; + v[0]; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/subscript_void_pointer_conditional.c b/chapter18/invalid_types/incomplete_types/subscript_void_pointer_conditional.c new file mode 100644 index 00000000..0b19e36a --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/subscript_void_pointer_conditional.c @@ -0,0 +1,8 @@ +int main() { + int arr[3] = {1, 2, 3}; + void *void_ptr = arr; + int *int_ptr = arr + 1; + // type error: result of conditional is void *, + // so we can't subscript it + return (1 ? int_ptr : void_ptr)[1]; +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/void_array.c b/chapter18/invalid_types/incomplete_types/void_array.c new file mode 100644 index 00000000..0e53ec36 --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/void_array.c @@ -0,0 +1,4 @@ +int main() { + void arr[3]; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/incomplete_types/void_array_param.c b/chapter18/invalid_types/incomplete_types/void_array_param.c new file mode 100644 index 00000000..a11d0ecc --- /dev/null +++ b/chapter18/invalid_types/incomplete_types/void_array_param.c @@ -0,0 +1,6 @@ +// we can't declare a parameter with invalid type +// void[3], even though it would be adjusted +// to the valid type void * +int arr(void foo[3]) { return 3; } + +int main() { return 0; } \ No newline at end of file diff --git a/chapter18/invalid_types/pointer_conversions/compare_void_ptr_to_int.c b/chapter18/invalid_types/pointer_conversions/compare_void_ptr_to_int.c new file mode 100644 index 00000000..97165c54 --- /dev/null +++ b/chapter18/invalid_types/pointer_conversions/compare_void_ptr_to_int.c @@ -0,0 +1 @@ +int main() { return (void *)0 == 20ul; } \ No newline at end of file diff --git a/chapter18/invalid_types/pointer_conversions/compare_void_to_other_pointer.c b/chapter18/invalid_types/pointer_conversions/compare_void_to_other_pointer.c new file mode 100644 index 00000000..5d4d3d31 --- /dev/null +++ b/chapter18/invalid_types/pointer_conversions/compare_void_to_other_pointer.c @@ -0,0 +1,5 @@ +int main() { + int arr[3] = {1, 2, 3}; + void *ptr = (void *)arr; + return ptr < arr + 1; +} \ No newline at end of file diff --git a/chapter18/invalid_types/pointer_conversions/convert_ulong_to_void_ptr.c b/chapter18/invalid_types/pointer_conversions/convert_ulong_to_void_ptr.c new file mode 100644 index 00000000..c51a561e --- /dev/null +++ b/chapter18/invalid_types/pointer_conversions/convert_ulong_to_void_ptr.c @@ -0,0 +1,4 @@ +int main() { + unsigned long x = 0; + void *v = x; // can't convert a non-pointer type to a pointer +} \ No newline at end of file diff --git a/chapter18/invalid_types/pointer_conversions/convert_void_ptr_to_int.c b/chapter18/invalid_types/pointer_conversions/convert_void_ptr_to_int.c new file mode 100644 index 00000000..acc576a7 --- /dev/null +++ b/chapter18/invalid_types/pointer_conversions/convert_void_ptr_to_int.c @@ -0,0 +1,4 @@ +int main() { + void *x = 0; + return x; // can't implicitly convert void * to integer +} \ No newline at end of file diff --git a/chapter18/invalid_types/pointer_conversions/usual_arithmetic_conversions_ptr.c b/chapter18/invalid_types/pointer_conversions/usual_arithmetic_conversions_ptr.c new file mode 100644 index 00000000..128bf49f --- /dev/null +++ b/chapter18/invalid_types/pointer_conversions/usual_arithmetic_conversions_ptr.c @@ -0,0 +1,4 @@ +int main() { + // can't convert void * to int with usual arithmetic conversions + int i = 10 * (void *)0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/scalar_expressions/and_void.c b/chapter18/invalid_types/scalar_expressions/and_void.c new file mode 100644 index 00000000..0e6142bc --- /dev/null +++ b/chapter18/invalid_types/scalar_expressions/and_void.c @@ -0,0 +1 @@ +int main() { return (void)1 && 2; } \ No newline at end of file diff --git a/chapter18/invalid_types/scalar_expressions/not_void.c b/chapter18/invalid_types/scalar_expressions/not_void.c new file mode 100644 index 00000000..70ac4a0f --- /dev/null +++ b/chapter18/invalid_types/scalar_expressions/not_void.c @@ -0,0 +1,3 @@ +void f(); +void g(); +int main() { return !(1 ? f() : g()); } \ No newline at end of file diff --git a/chapter18/invalid_types/scalar_expressions/or_void.c b/chapter18/invalid_types/scalar_expressions/or_void.c new file mode 100644 index 00000000..bb3e86bd --- /dev/null +++ b/chapter18/invalid_types/scalar_expressions/or_void.c @@ -0,0 +1 @@ +int main() { return 1 || (void)2; } \ No newline at end of file diff --git a/chapter18/invalid_types/scalar_expressions/void_as_integer.c b/chapter18/invalid_types/scalar_expressions/void_as_integer.c new file mode 100644 index 00000000..0e6bcecd --- /dev/null +++ b/chapter18/invalid_types/scalar_expressions/void_as_integer.c @@ -0,0 +1,6 @@ +// can't use void type where integer is expected + +int main() { + char arr[3]; + return arr[(void)1]; +} \ No newline at end of file diff --git a/chapter18/invalid_types/scalar_expressions/void_condition_do_loop.c b/chapter18/invalid_types/scalar_expressions/void_condition_do_loop.c new file mode 100644 index 00000000..33b77639 --- /dev/null +++ b/chapter18/invalid_types/scalar_expressions/void_condition_do_loop.c @@ -0,0 +1,8 @@ +void f() { return; } +int main() { + int i = 0; + do { + i = i + 1; + } while (f()); + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/scalar_expressions/void_condition_for_loop.c b/chapter18/invalid_types/scalar_expressions/void_condition_for_loop.c new file mode 100644 index 00000000..df5eda0d --- /dev/null +++ b/chapter18/invalid_types/scalar_expressions/void_condition_for_loop.c @@ -0,0 +1,9 @@ +void foo() { + return; +} + +int main() { + for (int i = 0; foo(); ) + ; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/scalar_expressions/void_condition_while_loop.c b/chapter18/invalid_types/scalar_expressions/void_condition_while_loop.c new file mode 100644 index 00000000..86dbbd52 --- /dev/null +++ b/chapter18/invalid_types/scalar_expressions/void_condition_while_loop.c @@ -0,0 +1,8 @@ +void f() { return; } +int main() { + int i = 0; + while ((void)10) { + i = i + 1; + } + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/scalar_expressions/void_if_condition.c b/chapter18/invalid_types/scalar_expressions/void_if_condition.c new file mode 100644 index 00000000..618b9c6d --- /dev/null +++ b/chapter18/invalid_types/scalar_expressions/void_if_condition.c @@ -0,0 +1,6 @@ +int main() { + int x = 10; + if ((void)x) + return 0; + return 1; +} \ No newline at end of file diff --git a/chapter18/invalid_types/scalar_expressions/void_ternary_condition.c b/chapter18/invalid_types/scalar_expressions/void_ternary_condition.c new file mode 100644 index 00000000..de6c5c29 --- /dev/null +++ b/chapter18/invalid_types/scalar_expressions/void_ternary_condition.c @@ -0,0 +1,3 @@ +void f(); + +int main() { return f() ? 1 : 2; } \ No newline at end of file diff --git a/chapter18/invalid_types/void/assign_to_void_lvalue.c b/chapter18/invalid_types/void/assign_to_void_lvalue.c new file mode 100644 index 00000000..bd6ed5f4 --- /dev/null +++ b/chapter18/invalid_types/void/assign_to_void_lvalue.c @@ -0,0 +1,10 @@ +extern void *x; + +void foo() { return; } + +int main() { + // the standard is ambiguous on whether you can dereference void *, + // but you definitely can't dereference it and then assign to the result + *x = foo(); + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/void/assign_to_void_var.c b/chapter18/invalid_types/void/assign_to_void_var.c new file mode 100644 index 00000000..31998559 --- /dev/null +++ b/chapter18/invalid_types/void/assign_to_void_var.c @@ -0,0 +1,9 @@ +extern void v1; + +int main() { + // the standard is ambiguous about whether + // you can declare void variables + // but you definitely can't assign to them + v1 = (void)0; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/void/assign_void_rval.c b/chapter18/invalid_types/void/assign_void_rval.c new file mode 100644 index 00000000..6ba76930 --- /dev/null +++ b/chapter18/invalid_types/void/assign_void_rval.c @@ -0,0 +1,6 @@ +/* can't convert void to another type by assignment */ +int main() { + int a = 10; + a = (void)20; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/void/cast_void.c b/chapter18/invalid_types/void/cast_void.c new file mode 100644 index 00000000..c446bf0e --- /dev/null +++ b/chapter18/invalid_types/void/cast_void.c @@ -0,0 +1,4 @@ +int main() { + int y = (int) (void) 3; + return y; +} \ No newline at end of file diff --git a/chapter18/invalid_types/void/define_void.c b/chapter18/invalid_types/void/define_void.c new file mode 100644 index 00000000..ac30644e --- /dev/null +++ b/chapter18/invalid_types/void/define_void.c @@ -0,0 +1,5 @@ +int main() { + //cannot define a void object + void x; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/void/initialized_void.c b/chapter18/invalid_types/void/initialized_void.c new file mode 100644 index 00000000..42c73b00 --- /dev/null +++ b/chapter18/invalid_types/void/initialized_void.c @@ -0,0 +1,4 @@ +// it's illegal to initialize a void variable +extern void v = 0; + +int main() { return 0; } \ No newline at end of file diff --git a/chapter18/invalid_types/void/mismatched_conditional.c b/chapter18/invalid_types/void/mismatched_conditional.c new file mode 100644 index 00000000..a59e9368 --- /dev/null +++ b/chapter18/invalid_types/void/mismatched_conditional.c @@ -0,0 +1,10 @@ +void foo() { + return; +} + +int main() { + int a = 3; + int flag = 4; + flag ? foo() : (a = 3); + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/void/negate_void.c b/chapter18/invalid_types/void/negate_void.c new file mode 100644 index 00000000..bb11bc85 --- /dev/null +++ b/chapter18/invalid_types/void/negate_void.c @@ -0,0 +1,4 @@ +int main() { + -(void)10; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/void/no_return_value.c b/chapter18/invalid_types/void/no_return_value.c new file mode 100644 index 00000000..d16487da --- /dev/null +++ b/chapter18/invalid_types/void/no_return_value.c @@ -0,0 +1,10 @@ +int foo() { + // function with non-void return type + // must return a value + return; +} + +int main() { + foo(); + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/void/non_void_return.c b/chapter18/invalid_types/void/non_void_return.c new file mode 100644 index 00000000..f53fee14 --- /dev/null +++ b/chapter18/invalid_types/void/non_void_return.c @@ -0,0 +1,9 @@ +void x() { + // a function with a void return type can't return an expression + return 1; +} + +int main() { + x(); + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/void/return_void_as_pointer.c b/chapter18/invalid_types/void/return_void_as_pointer.c new file mode 100644 index 00000000..125a292c --- /dev/null +++ b/chapter18/invalid_types/void/return_void_as_pointer.c @@ -0,0 +1,5 @@ +void *x() { + // can't convert void expression to another type via + // conversion by assignment, including in return statement + return (void)0; +} diff --git a/chapter18/invalid_types/void/tentative_define_void.c b/chapter18/invalid_types/void/tentative_define_void.c new file mode 100644 index 00000000..687832ac --- /dev/null +++ b/chapter18/invalid_types/void/tentative_define_void.c @@ -0,0 +1,7 @@ +// you can't tentatively define an object +// that has internal linkage w/ incomplete type +// strictly speaking this is undefined behavior +// rather than a constraint violation +static void v; + +int main() { return 0; } \ No newline at end of file diff --git a/chapter18/invalid_types/void/void_compare.c b/chapter18/invalid_types/void/void_compare.c new file mode 100644 index 00000000..55eff456 --- /dev/null +++ b/chapter18/invalid_types/void/void_compare.c @@ -0,0 +1,5 @@ +int main() { + if ((void)1 < (void)2) + return 1; + return 0; +} \ No newline at end of file diff --git a/chapter18/invalid_types/void/void_equality.c b/chapter18/invalid_types/void/void_equality.c new file mode 100644 index 00000000..5276d958 --- /dev/null +++ b/chapter18/invalid_types/void/void_equality.c @@ -0,0 +1,2 @@ +void x(); +int main() { return x() == (void)10; } \ No newline at end of file diff --git a/chapter18/invalid_types/void/void_fun_params.c b/chapter18/invalid_types/void/void_fun_params.c new file mode 100644 index 00000000..b261e629 --- /dev/null +++ b/chapter18/invalid_types/void/void_fun_params.c @@ -0,0 +1,5 @@ +void foo(void x); + +int main() { + return 0; +} \ No newline at end of file diff --git a/chapter18/valid/libraries/return_void.c b/chapter18/valid/libraries/return_void.c new file mode 100644 index 00000000..15efe088 --- /dev/null +++ b/chapter18/valid/libraries/return_void.c @@ -0,0 +1,11 @@ +void recursive_decrement(unsigned int *ptr) { + // the least efficient possible way to set an integer to 0 + // use recursive calls here to make sure we don't mess up + // the call stack when calling/returning from void functions + if (*ptr) { + *ptr = *ptr - 1; + recursive_decrement(ptr); + return; + } + return; +} \ No newline at end of file diff --git a/chapter18/valid/libraries/return_void_client.c b/chapter18/valid/libraries/return_void_client.c new file mode 100644 index 00000000..7ac44ed1 --- /dev/null +++ b/chapter18/valid/libraries/return_void_client.c @@ -0,0 +1,7 @@ +void recursive_decrement(unsigned int *ptr); + +int main() { + unsigned int i = 77; + recursive_decrement(&i); + return i; +} \ No newline at end of file diff --git a/chapter18/valid/libraries/tern.c b/chapter18/valid/libraries/tern.c new file mode 100644 index 00000000..13d1eeac --- /dev/null +++ b/chapter18/valid/libraries/tern.c @@ -0,0 +1,10 @@ +void* calloc( unsigned long num, unsigned long size ); + +int foo(int flag, double *d, int **arr) { + void *buff = flag ? d : (void *) arr; + if (flag) { + return ((double *) buff)[2]; + } else { + return ((int **) buff)[1][0]; + } +} diff --git a/chapter18/valid/libraries/tern_client.c b/chapter18/valid/libraries/tern_client.c new file mode 100644 index 00000000..d856552e --- /dev/null +++ b/chapter18/valid/libraries/tern_client.c @@ -0,0 +1,14 @@ +void* calloc( unsigned long num, unsigned long size ); + +int foo(int flag, double *d, int **arr); + +int main() { + int x = 0; + int y = 1; + int z = 2; + double arr[3] = {1.0, 2.0, 3.0}; + int *ptr_arr[3] = { &x, &y, &z }; + int a = foo(0, arr, ptr_arr); + int b = foo(1, arr, ptr_arr); + return a + b; +} \ No newline at end of file diff --git a/chapter18/valid/sizeof/sizeof_array.c b/chapter18/valid/sizeof/sizeof_array.c new file mode 100644 index 00000000..fadb4aad --- /dev/null +++ b/chapter18/valid/sizeof/sizeof_array.c @@ -0,0 +1,6 @@ +int main() { + int arr[3]; + // arr doesn't decay to a pointer here, + // so the result is 12 (i.e. 3 * 4) + return sizeof arr; +} \ No newline at end of file diff --git a/chapter18/valid/sizeof/sizeof_array_type.c b/chapter18/valid/sizeof/sizeof_array_type.c new file mode 100644 index 00000000..fe4006e3 --- /dev/null +++ b/chapter18/valid/sizeof/sizeof_array_type.c @@ -0,0 +1,5 @@ +int main() { + // get size of array type + // size here is 3 * 2 * 8 = 48 bytes + return sizeof(double[3][2]); +} \ No newline at end of file diff --git a/chapter18/valid/sizeof/sizeof_char.c b/chapter18/valid/sizeof/sizeof_char.c new file mode 100644 index 00000000..dee96b4a --- /dev/null +++ b/chapter18/valid/sizeof/sizeof_char.c @@ -0,0 +1,7 @@ +int main() { + signed char x = 0; + // size of char must be 1 + if (sizeof((char)1) == 1 && sizeof(unsigned char) == 1 && sizeof x == 1) + return 1; + return 0; +} \ No newline at end of file diff --git a/chapter18/valid/sizeof/sizeof_complex_type.c b/chapter18/valid/sizeof/sizeof_complex_type.c new file mode 100644 index 00000000..71d66f04 --- /dev/null +++ b/chapter18/valid/sizeof/sizeof_complex_type.c @@ -0,0 +1,8 @@ +int main() { + // get size of type specified by complex abstract declarator + // this is an array of 3 arrays of 4 pointers, for total size + // 3 * 4 * 8 = 96 + // (each pointer points to an array of two doubles + // but that doesn't impact the overall size) + return sizeof(double(*([3][4]))[2]); +} \ No newline at end of file diff --git a/chapter18/valid/sizeof/sizeof_is_unsigned.c b/chapter18/valid/sizeof/sizeof_is_unsigned.c new file mode 100644 index 00000000..938bd928 --- /dev/null +++ b/chapter18/valid/sizeof/sizeof_is_unsigned.c @@ -0,0 +1,7 @@ +int main() { + + // make sure the result of sizeof is unsigned + // (if it's not, usual arithmetic conversions will convert + // operands of > 0 to a signed type and this will be false) + return sizeof 4 - sizeof 4 - 1 > 0; +} \ No newline at end of file diff --git a/chapter18/valid/sizeof/sizeof_not_evaluated.c b/chapter18/valid/sizeof/sizeof_not_evaluated.c new file mode 100644 index 00000000..061f8c78 --- /dev/null +++ b/chapter18/valid/sizeof/sizeof_not_evaluated.c @@ -0,0 +1,7 @@ +void exit(int status); +int foo() { exit(10); } + +int main() { + // make sure foo isn't actually called + return sizeof(foo()); +} \ No newline at end of file diff --git a/chapter18/valid/sizeof/sizeof_pointer.c b/chapter18/valid/sizeof/sizeof_pointer.c new file mode 100644 index 00000000..a40baebf --- /dev/null +++ b/chapter18/valid/sizeof/sizeof_pointer.c @@ -0,0 +1,7 @@ +void *malloc(unsigned long size); + +int main() { + void *buffer = malloc(100); + // this will be 8 b/c buffer is a pointer + return sizeof(buffer); +} \ No newline at end of file diff --git a/chapter18/valid/sizeof/sizeof_sizeof.c b/chapter18/valid/sizeof/sizeof_sizeof.c new file mode 100644 index 00000000..48e26553 --- /dev/null +++ b/chapter18/valid/sizeof/sizeof_sizeof.c @@ -0,0 +1,4 @@ +int main() { + // result of sizeof operation is an unsigned long (8 bytes) + return sizeof sizeof 10; +} \ No newline at end of file diff --git a/chapter18/valid/sizeof/sizeof_string.c b/chapter18/valid/sizeof/sizeof_string.c new file mode 100644 index 00000000..3bd69ade --- /dev/null +++ b/chapter18/valid/sizeof/sizeof_string.c @@ -0,0 +1,3 @@ +int main() { + return sizeof("Hello, World!"); +} \ No newline at end of file diff --git a/chapter18/valid/sizeof/sizeof_type.c b/chapter18/valid/sizeof/sizeof_type.c new file mode 100644 index 00000000..a2426cdc --- /dev/null +++ b/chapter18/valid/sizeof/sizeof_type.c @@ -0,0 +1,4 @@ +int main() { + // get size of type name + return sizeof(long signed); +} \ No newline at end of file diff --git a/chapter18/valid/void/cast_to_void.c b/chapter18/valid/void/cast_to_void.c new file mode 100644 index 00000000..1b33ea34 --- /dev/null +++ b/chapter18/valid/void/cast_to_void.c @@ -0,0 +1,4 @@ +int main() { + (void) 100; + return 0; +} \ No newline at end of file diff --git a/chapter18/valid/void/cast_void_to_void.c b/chapter18/valid/void/cast_void_to_void.c new file mode 100644 index 00000000..a33e1a15 --- /dev/null +++ b/chapter18/valid/void/cast_void_to_void.c @@ -0,0 +1,8 @@ +void foo() { + return; +} + +int main() { + (void) foo(); + return 0; +} \ No newline at end of file diff --git a/chapter18/valid/void/ternary.c b/chapter18/valid/void/ternary.c new file mode 100644 index 00000000..41317373 --- /dev/null +++ b/chapter18/valid/void/ternary.c @@ -0,0 +1,9 @@ +int i = 0; +int j = 0; +void incr_i() { i = i + 1; } +void incr_j() { j = j + 1; } +int main() { + 1 ? incr_i() : incr_j(); // increment i + 0 ? incr_i() : incr_j(); // increment j + return (i == 1 && j == 1); +} \ No newline at end of file diff --git a/chapter18/valid/void/void_for_init.c b/chapter18/valid/void/void_for_init.c new file mode 100644 index 00000000..4b456f0a --- /dev/null +++ b/chapter18/valid/void/void_for_init.c @@ -0,0 +1,11 @@ +int i = 0; + +int putchar(int i); +void foo() { i = 90; } + +int main() { + // print the alphabet + for (foo(); i >= 65; i = i - 1) + putchar(i); + return 0; +} \ No newline at end of file diff --git a/chapter18/valid/void/void_for_post.c b/chapter18/valid/void/void_for_post.c new file mode 100644 index 00000000..2ff38f46 --- /dev/null +++ b/chapter18/valid/void/void_for_post.c @@ -0,0 +1,9 @@ +int i = 0; + +void foo() { i = i + 1; } + +int main() { + for (; i < 10; foo()) + ; + return i; +} \ No newline at end of file diff --git a/chapter18/valid/void/void_function.c b/chapter18/valid/void/void_function.c new file mode 100644 index 00000000..539b3015 --- /dev/null +++ b/chapter18/valid/void/void_function.c @@ -0,0 +1,10 @@ +int foo = 0; + +void set_foo(int a) { foo = a; } +void do_nothing() {;} + +int main() { + set_foo(12); + do_nothing(); + return foo; +} \ No newline at end of file diff --git a/chapter18/valid/void_pointer/array_of_pointers_to_void.c b/chapter18/valid/void_pointer/array_of_pointers_to_void.c new file mode 100644 index 00000000..58afd447 --- /dev/null +++ b/chapter18/valid/void_pointer/array_of_pointers_to_void.c @@ -0,0 +1,26 @@ +void *calloc(unsigned long nmemb, unsigned long size); +void free(void *ptr); +int main() { + int i = 10; + void *arr[4] = {calloc(2, sizeof(int)), &i, 0, arr}; + + // first element points to 8 bytes initialized to 0 + int *elem_0 = arr[0]; + if (elem_0[0] || elem_0[1]) + return 0; + + // second element points to i + int elem_1_val = *(int *)arr[1]; + if (elem_1_val != i) + return 0; + + // 3rd element is a null pointer + if (arr[2]) + return 0; + + // 4th element points to arr itself! trippy! + if (arr[3] != arr) + return 0; + free(elem_0); + return 1; +} \ No newline at end of file diff --git a/chapter18/valid/void_pointer/common_pointer_type.c b/chapter18/valid/void_pointer/common_pointer_type.c new file mode 100644 index 00000000..51160070 --- /dev/null +++ b/chapter18/valid/void_pointer/common_pointer_type.c @@ -0,0 +1,37 @@ +void *calloc(unsigned long nmemb, unsigned long size); +void free(void *ptr); + +// the common pointer type of void * and another pointer type is void * +int main() { + // get a pointer to void + void *void_ptr = calloc(3, sizeof(unsigned int)); + unsigned int array[3] = {1, 2, 3}; + + // like other pointers, void * can be compared to null pointer constant + if (void_ptr == 0) + return 0; + + // compare with == + if (void_ptr == array) + return 1; + + // compare with != + if (!(void_ptr != array)) + return 1; + + // use in conditional + // note that result of conditional is void * so it can be implicitly converted + // to any pointer type + + // also use a void * as the condition here just for fun + void *null_ptr = 0; + int *my_array = null_ptr ? void_ptr : array; + + // note: effective type of this object is unsigned int, + // so we're allowed to access it with an expression of + // the corresponding signed type, int + int result = my_array[1]; + + free(void_ptr); + return result; +} \ No newline at end of file diff --git a/chapter18/valid/void_pointer/conversion_by_assignment.c b/chapter18/valid/void_pointer/conversion_by_assignment.c new file mode 100644 index 00000000..046a2a2b --- /dev/null +++ b/chapter18/valid/void_pointer/conversion_by_assignment.c @@ -0,0 +1,32 @@ +void *malloc(unsigned long size); +void free(void *ptr); +int memcmp(void *s1, void *s2, unsigned long n); +// make sure we can implicitly convert to and from void * by assignment +void *return_ptr(char *i) { + // get pointer to i[3], implicitly cast from char * to void * + return i + 3; +} + +int main() { + void *four_bytes = malloc(4); + // implicitly convert void * to int * + int *int_ptr = four_bytes; + *int_ptr = -1; // set all bits to 1 + + // implicitly convert four_bytes from void * to char * + // by passing it as a function argument + void *last_byte = return_ptr(four_bytes); + + char *last_char = last_byte; + + if (*last_char != -1) + return 0; + + free(four_bytes); + + long arr1[3] = {1, 2, 3}; + long arr2[3] = {1, 2, 3}; + long arr3[3] = {1, 2, 4}; + return memcmp(arr1, arr2, sizeof arr1) == 0 && + memcmp(arr1, arr3, sizeof arr2) == -1; +} diff --git a/chapter18/valid/void_pointer/explicit_cast.c b/chapter18/valid/void_pointer/explicit_cast.c new file mode 100644 index 00000000..14d13f6b --- /dev/null +++ b/chapter18/valid/void_pointer/explicit_cast.c @@ -0,0 +1,29 @@ +// test explicit casts between void * and other pointer types, +// and between void * and integer types +void *malloc(unsigned long size); +void free(void *ptr); +void *memcpy(void *s1, void *s2, unsigned long n); + +int main() { + void *ptr = malloc(4 * sizeof(double)); + // cast void * to double * + double *double_ptr = (double *)ptr; + double_ptr[2] = 10.0; + // cast double * back to void * - should round trip + if ((void *)double_ptr != ptr) + return 0; + double result = double_ptr[2]; + + if (result != 10.0) + return 0; + + // now test cast from void * to integer + unsigned long ul = (unsigned long)ptr; + // address returned by malloc must have suitable alignment + // for any basic data type, so it's divisible by 8 + if (ul % 8) + return 0; + + free(ptr); + return 1; +} diff --git a/chapter18/valid/void_pointer/malloc.c b/chapter18/valid/void_pointer/malloc.c new file mode 100644 index 00000000..589db381 --- /dev/null +++ b/chapter18/valid/void_pointer/malloc.c @@ -0,0 +1,13 @@ +void *malloc(unsigned long size); +void free(void *ptr); + +int main() { + void *buffer = malloc(100); + char *char_buffer = (char *)buffer; + for (int i = 0; i < 100; i = i + 1) { + char_buffer[i] = i; + } + char c = char_buffer[98]; + free(buffer); + return c; +} \ No newline at end of file From 046c53f1fc27c22019375fa697d1f946d86a4ce9 Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Mon, 6 Mar 2023 15:01:41 -0800 Subject: [PATCH 009/167] chapter 19 tests --- chapter19/invalid_lex/dot_bad_token.c | 10 ++ chapter19/invalid_parse/bad_arrow_operator.c | 8 + chapter19/invalid_parse/bad_dot_operator.c | 8 + .../invalid_parse/bad_struct_specifier.c | 4 + chapter19/invalid_parse/bad_tag.c | 10 ++ chapter19/invalid_parse/bad_type_specifier.c | 6 + chapter19/invalid_parse/dot_no_left_expr.c | 3 + chapter19/invalid_parse/empty_member_list.c | 5 + chapter19/invalid_parse/initialize_member.c | 9 + chapter19/invalid_parse/kw_type_tag.c | 4 + .../invalid_parse/missing_end_semicolon.c | 7 + .../invalid_parse/missing_struct_keyword.c | 5 + .../invalid_parse/struct_decl_for_init.c | 5 + .../invalid_parse/struct_member_initializer.c | 4 + .../struct_member_no_declarator.c | 3 + .../structure_member_is_function.c | 3 + .../invalid_parse/structure_member_no_type.c | 3 + .../structure_member_storage_class.c | 4 + .../invalid_struct_tags/array_of_undeclared.c | 5 + .../invalid_struct_tags/deref_undeclared.c | 5 + .../member_type_undeclared.c | 4 + .../invalid_struct_tags/param_undeclared.c | 3 + .../invalid_struct_tags/sizeof_undeclared.c | 7 + .../invalid_struct_tags/undeclared_struct.c | 7 + .../bad_conversions/compare_struct_pointers.c | 12 ++ .../bad_lvalue/address_of_non_lvalue.c | 12 ++ .../bad_lvalue/assign_nested_non_lvalue.c | 20 +++ .../bad_lvalue/assign_to_array.c | 10 ++ .../bad_lvalue/assign_to_non_lvalue.c | 13 ++ .../bad_member_operators/bad_member.c | 9 + .../bad_member_operators/bad_pointer_member.c | 17 ++ .../member_of_non_struct.c | 11 ++ .../member_pointer_non_member.c | 10 ++ .../bad_member_operators/postfix_precedence.c | 10 ++ .../conditionals/branch_mismatch.c | 13 ++ .../conditionals/branch_mismatch_2.c | 10 ++ .../initializers/init_struct_with_string.c | 14 ++ .../initialize_static_struct_with_zero.c | 5 + .../initialize_struct_with_scalar.c | 8 + .../initialize_struct_with_zero.c | 8 + .../initialize_struct_wrong_type.c | 15 ++ .../nested_initialize_struct_wrong_type.c | 16 ++ .../initializers/non_constant_static_init.c | 6 + .../initializers/static_bad_element_type.c | 7 + .../assign_to_incomplete_var.c | 8 + .../cast_incomplete_struct.c | 9 + .../deref_incomplete_struct_pointer.c | 10 ++ .../incomplete_arg_funcall.c | 9 + .../incomplete_array_element.c | 10 ++ .../incomplete_local_var.c | 7 + .../incomplete_param.c | 4 + .../incomplete_ptr_addition.c | 8 + .../incomplete_ptr_subtraction.c | 8 + .../incomplete_return_type_fun_def.c | 11 ++ .../incomplete_return_type_funcall.c | 8 + .../incomplete_struct_conditional.c | 9 + .../incomplete_struct_full_expr.c | 10 ++ .../incomplete_struct_member.c | 7 + .../incomplete_subscript.c | 4 + .../incomplete_tentative_def.c | 9 + .../initialize_incomplete.c | 11 ++ .../sizeof_incomplete.c | 5 + .../duplicate_member_name.c | 5 + .../duplicate_struct_declaration.c | 9 + .../incomplete_member.c | 6 + .../invalid_array_member.c | 7 + .../invalid_self_reference.c | 8 + .../invalid_shadow_self_reference.c | 13 ++ .../invalid_struct_declaration/void_member.c | 4 + .../assign_null_ptr_to_struct.c | 10 ++ .../scalar_required/assign_scalar_to_struct.c | 10 ++ .../scalar_required/cast_struct_to_scalar.c | 10 ++ .../scalar_required/cast_to_struct.c | 9 + .../scalar_required/compare_structs.c | 9 + .../scalar_required/not_struct.c | 8 + .../pass_struct_as_scalar_param.c | 10 ++ .../scalar_required/struct_as_int.c | 11 ++ .../struct_controlling_expression.c | 11 ++ .../scalar_required/subscript_struct.c | 8 + .../conflicting_fun_param_types.c | 8 + .../conflicting_fun_ret_types.c | 9 + .../tag_resolution/distinct_struct_types.c | 15 ++ .../incomplete_shadows_complete.c | 10 ++ .../incomplete_shadows_complete_cast.c | 13 ++ .../invalid_shadow_self_reference.c | 12 ++ .../tag_resolution/mismatched_return_type.c | 16 ++ .../tag_resolution/shadow_struct.c | 9 + .../valid/fun_calls/pass_and_return_struct.c | 15 ++ .../valid/fun_calls/pass_pointer_to_struct.c | 15 ++ .../fun_calls/pass_struct_and_other_args.c | 13 ++ .../valid/fun_calls/pass_struct_as_arg.c | 13 ++ chapter19/valid/fun_calls/return_struct.c | 13 ++ .../block_scope_forward_decl.c | 8 + .../incomplete_structs/define_then_declare.c | 12 ++ .../incomplete_structs/deref_incomplete_var.c | 14 ++ .../file_scope_forward_decl.c | 20 +++ .../incomplete_param_type.c | 17 ++ .../incomplete_var_completed.c | 16 ++ .../return_incomplete_type.c | 17 ++ .../valid/initializers/load_addr_in_init.c | 9 + .../valid/initializers/mixed_initialization.c | 11 ++ .../valid/initializers/nested_struct_init.c | 21 +++ .../valid/initializers/partial_struct_init.c | 16 ++ .../initializers/string_in_global_struct.c | 10 ++ .../valid/initializers/string_in_struct.c | 9 + chapter19/valid/libraries/array_of_structs.c | 15 ++ chapter19/valid/libraries/array_of_structs.h | 12 ++ .../valid/libraries/array_of_structs_client.c | 14 ++ .../valid/libraries/calling_conventions.c | 164 ++++++++++++++++++ .../libraries/calling_conventions_client.c | 87 ++++++++++ chapter19/valid/libraries/classes.h | 93 ++++++++++ chapter19/valid/libraries/global_struct.c | 8 + .../valid/libraries/global_struct_client.c | 10 ++ chapter19/valid/libraries/incomplete_var.c | 12 ++ .../valid/libraries/incomplete_var_client.c | 9 + chapter19/valid/libraries/initializers.c | 46 +++++ chapter19/valid/libraries/initializers.h | 25 +++ .../valid/libraries/initializers_client.c | 61 +++++++ chapter19/valid/libraries/missing_retval.c | 5 + chapter19/valid/libraries/missing_retval.h | 8 + .../valid/libraries/missing_retval_client.c | 7 + .../valid/libraries/nested_pointer_access.c | 26 +++ .../valid/libraries/nested_pointer_access.h | 18 ++ .../libraries/nested_pointer_access_client.c | 13 ++ chapter19/valid/libraries/pass_struct.c | 8 + .../valid/libraries/pass_struct_client.c | 11 ++ chapter19/valid/libraries/pass_wonky_struct.c | 13 ++ chapter19/valid/libraries/pass_wonky_struct.h | 6 + .../libraries/pass_wonky_struct_client.c | 22 +++ chapter19/valid/libraries/struct.h | 5 + .../valid/member_access_tests/addr_of_arrow.c | 10 ++ .../aggregate_through_arrow.c | 54 ++++++ .../member_access_tests/assign_to_struct.c | 7 + .../assign_to_struct_pointer.c | 9 + .../member_access_tests/copy_from_pointer.c | 31 ++++ .../member_access_tests/copy_to_pointer.c | 25 +++ .../valid/member_access_tests/deref_arrow.c | 15 ++ .../get_array_through_pointer.c | 13 ++ .../get_member_addresses.c | 107 ++++++++++++ .../global_nested_struct.c | 18 ++ .../valid/member_access_tests/global_struct.c | 12 ++ .../valid/member_access_tests/linked_list.c | 29 ++++ .../nested_address_calculations.c | 40 +++++ .../valid/member_access_tests/nested_struct.c | 19 ++ .../member_access_tests/non_static_struct.c | 17 ++ .../member_access_tests/pointer_to_struct.c | 13 ++ .../valid/member_access_tests/static_struct.c | 17 ++ chapter19/valid/member_access_tests/struct.c | 10 ++ .../misc_typecheck/cast_struct_to_void.c | 13 ++ .../valid/misc_typecheck/conditional_struct.c | 19 ++ .../valid/misc_typecheck/temporary_lifetime.c | 25 +++ .../valid/parse_and_lex/postfix_precedence.c | 19 ++ .../space_around_struct_member.c | 12 ++ .../struct_member_looks_like_const.c | 8 + .../valid/scoping_tests/declare_struct.c | 9 + .../different_namespaces_same_ids.c | 10 ++ .../scoping_tests/resolve_tag_for_loop_decl.c | 12 ++ .../valid/scoping_tests/resolve_tag_sizeof.c | 14 ++ .../resolve_tags_derived_types.c | 26 +++ chapter19/valid/scoping_tests/same_tag_name.c | 15 ++ .../scoping_tests/same_tag_name_simple.c | 15 ++ chapter19/valid/scoping_tests/scoped_struct.c | 14 ++ .../shared_struct_and_var_names.c | 9 + chapter19/valid/sizeof/sizeof_padded.c | 47 +++++ chapter19/valid/sizeof/sizeof_struct.c | 8 + chapter19/valid/sizeof/sizeof_wonky.c | 6 + .../struct_copy_tests/array_of_structs.c | 12 ++ .../array_of_structs_padding.c | 18 ++ .../struct_copy_tests/copy_from_offset_test.c | 39 +++++ .../valid/struct_copy_tests/copy_struct.c | 12 ++ .../copy_struct_into_member.c | 47 +++++ .../copy_struct_with_array.c | 14 ++ .../copy_struct_with_array_2.c | 24 +++ chapter19/valid/struct_copy_tests/load_test.c | 36 ++++ 174 files changed, 2621 insertions(+) create mode 100644 chapter19/invalid_lex/dot_bad_token.c create mode 100644 chapter19/invalid_parse/bad_arrow_operator.c create mode 100644 chapter19/invalid_parse/bad_dot_operator.c create mode 100644 chapter19/invalid_parse/bad_struct_specifier.c create mode 100644 chapter19/invalid_parse/bad_tag.c create mode 100644 chapter19/invalid_parse/bad_type_specifier.c create mode 100644 chapter19/invalid_parse/dot_no_left_expr.c create mode 100644 chapter19/invalid_parse/empty_member_list.c create mode 100644 chapter19/invalid_parse/initialize_member.c create mode 100644 chapter19/invalid_parse/kw_type_tag.c create mode 100644 chapter19/invalid_parse/missing_end_semicolon.c create mode 100644 chapter19/invalid_parse/missing_struct_keyword.c create mode 100644 chapter19/invalid_parse/struct_decl_for_init.c create mode 100644 chapter19/invalid_parse/struct_member_initializer.c create mode 100644 chapter19/invalid_parse/struct_member_no_declarator.c create mode 100644 chapter19/invalid_parse/structure_member_is_function.c create mode 100644 chapter19/invalid_parse/structure_member_no_type.c create mode 100644 chapter19/invalid_parse/structure_member_storage_class.c create mode 100644 chapter19/invalid_struct_tags/array_of_undeclared.c create mode 100644 chapter19/invalid_struct_tags/deref_undeclared.c create mode 100644 chapter19/invalid_struct_tags/member_type_undeclared.c create mode 100644 chapter19/invalid_struct_tags/param_undeclared.c create mode 100644 chapter19/invalid_struct_tags/sizeof_undeclared.c create mode 100644 chapter19/invalid_struct_tags/undeclared_struct.c create mode 100644 chapter19/invalid_types/bad_conversions/compare_struct_pointers.c create mode 100644 chapter19/invalid_types/bad_lvalue/address_of_non_lvalue.c create mode 100644 chapter19/invalid_types/bad_lvalue/assign_nested_non_lvalue.c create mode 100644 chapter19/invalid_types/bad_lvalue/assign_to_array.c create mode 100644 chapter19/invalid_types/bad_lvalue/assign_to_non_lvalue.c create mode 100644 chapter19/invalid_types/bad_member_operators/bad_member.c create mode 100644 chapter19/invalid_types/bad_member_operators/bad_pointer_member.c create mode 100644 chapter19/invalid_types/bad_member_operators/member_of_non_struct.c create mode 100644 chapter19/invalid_types/bad_member_operators/member_pointer_non_member.c create mode 100644 chapter19/invalid_types/bad_member_operators/postfix_precedence.c create mode 100644 chapter19/invalid_types/conditionals/branch_mismatch.c create mode 100644 chapter19/invalid_types/conditionals/branch_mismatch_2.c create mode 100644 chapter19/invalid_types/initializers/init_struct_with_string.c create mode 100644 chapter19/invalid_types/initializers/initialize_static_struct_with_zero.c create mode 100644 chapter19/invalid_types/initializers/initialize_struct_with_scalar.c create mode 100644 chapter19/invalid_types/initializers/initialize_struct_with_zero.c create mode 100644 chapter19/invalid_types/initializers/initialize_struct_wrong_type.c create mode 100644 chapter19/invalid_types/initializers/nested_initialize_struct_wrong_type.c create mode 100644 chapter19/invalid_types/initializers/non_constant_static_init.c create mode 100644 chapter19/invalid_types/initializers/static_bad_element_type.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/assign_to_incomplete_var.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/cast_incomplete_struct.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/deref_incomplete_struct_pointer.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_arg_funcall.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_array_element.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_local_var.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_param.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_ptr_addition.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_ptr_subtraction.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_return_type_fun_def.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_return_type_funcall.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_conditional.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_full_expr.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_member.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_subscript.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/incomplete_tentative_def.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/initialize_incomplete.c create mode 100644 chapter19/invalid_types/invalid_incomplete_structs/sizeof_incomplete.c create mode 100644 chapter19/invalid_types/invalid_struct_declaration/duplicate_member_name.c create mode 100644 chapter19/invalid_types/invalid_struct_declaration/duplicate_struct_declaration.c create mode 100644 chapter19/invalid_types/invalid_struct_declaration/incomplete_member.c create mode 100644 chapter19/invalid_types/invalid_struct_declaration/invalid_array_member.c create mode 100644 chapter19/invalid_types/invalid_struct_declaration/invalid_self_reference.c create mode 100644 chapter19/invalid_types/invalid_struct_declaration/invalid_shadow_self_reference.c create mode 100644 chapter19/invalid_types/invalid_struct_declaration/void_member.c create mode 100644 chapter19/invalid_types/scalar_required/assign_null_ptr_to_struct.c create mode 100644 chapter19/invalid_types/scalar_required/assign_scalar_to_struct.c create mode 100644 chapter19/invalid_types/scalar_required/cast_struct_to_scalar.c create mode 100644 chapter19/invalid_types/scalar_required/cast_to_struct.c create mode 100644 chapter19/invalid_types/scalar_required/compare_structs.c create mode 100644 chapter19/invalid_types/scalar_required/not_struct.c create mode 100644 chapter19/invalid_types/scalar_required/pass_struct_as_scalar_param.c create mode 100644 chapter19/invalid_types/scalar_required/struct_as_int.c create mode 100644 chapter19/invalid_types/scalar_required/struct_controlling_expression.c create mode 100644 chapter19/invalid_types/scalar_required/subscript_struct.c create mode 100644 chapter19/invalid_types/tag_resolution/conflicting_fun_param_types.c create mode 100644 chapter19/invalid_types/tag_resolution/conflicting_fun_ret_types.c create mode 100644 chapter19/invalid_types/tag_resolution/distinct_struct_types.c create mode 100644 chapter19/invalid_types/tag_resolution/incomplete_shadows_complete.c create mode 100644 chapter19/invalid_types/tag_resolution/incomplete_shadows_complete_cast.c create mode 100644 chapter19/invalid_types/tag_resolution/invalid_shadow_self_reference.c create mode 100644 chapter19/invalid_types/tag_resolution/mismatched_return_type.c create mode 100644 chapter19/invalid_types/tag_resolution/shadow_struct.c create mode 100644 chapter19/valid/fun_calls/pass_and_return_struct.c create mode 100644 chapter19/valid/fun_calls/pass_pointer_to_struct.c create mode 100644 chapter19/valid/fun_calls/pass_struct_and_other_args.c create mode 100644 chapter19/valid/fun_calls/pass_struct_as_arg.c create mode 100644 chapter19/valid/fun_calls/return_struct.c create mode 100644 chapter19/valid/incomplete_structs/block_scope_forward_decl.c create mode 100644 chapter19/valid/incomplete_structs/define_then_declare.c create mode 100644 chapter19/valid/incomplete_structs/deref_incomplete_var.c create mode 100644 chapter19/valid/incomplete_structs/file_scope_forward_decl.c create mode 100644 chapter19/valid/incomplete_structs/incomplete_param_type.c create mode 100644 chapter19/valid/incomplete_structs/incomplete_var_completed.c create mode 100644 chapter19/valid/incomplete_structs/return_incomplete_type.c create mode 100644 chapter19/valid/initializers/load_addr_in_init.c create mode 100644 chapter19/valid/initializers/mixed_initialization.c create mode 100644 chapter19/valid/initializers/nested_struct_init.c create mode 100644 chapter19/valid/initializers/partial_struct_init.c create mode 100644 chapter19/valid/initializers/string_in_global_struct.c create mode 100644 chapter19/valid/initializers/string_in_struct.c create mode 100644 chapter19/valid/libraries/array_of_structs.c create mode 100644 chapter19/valid/libraries/array_of_structs.h create mode 100644 chapter19/valid/libraries/array_of_structs_client.c create mode 100644 chapter19/valid/libraries/calling_conventions.c create mode 100644 chapter19/valid/libraries/calling_conventions_client.c create mode 100644 chapter19/valid/libraries/classes.h create mode 100644 chapter19/valid/libraries/global_struct.c create mode 100644 chapter19/valid/libraries/global_struct_client.c create mode 100644 chapter19/valid/libraries/incomplete_var.c create mode 100644 chapter19/valid/libraries/incomplete_var_client.c create mode 100644 chapter19/valid/libraries/initializers.c create mode 100644 chapter19/valid/libraries/initializers.h create mode 100644 chapter19/valid/libraries/initializers_client.c create mode 100644 chapter19/valid/libraries/missing_retval.c create mode 100644 chapter19/valid/libraries/missing_retval.h create mode 100644 chapter19/valid/libraries/missing_retval_client.c create mode 100644 chapter19/valid/libraries/nested_pointer_access.c create mode 100644 chapter19/valid/libraries/nested_pointer_access.h create mode 100644 chapter19/valid/libraries/nested_pointer_access_client.c create mode 100644 chapter19/valid/libraries/pass_struct.c create mode 100644 chapter19/valid/libraries/pass_struct_client.c create mode 100644 chapter19/valid/libraries/pass_wonky_struct.c create mode 100644 chapter19/valid/libraries/pass_wonky_struct.h create mode 100644 chapter19/valid/libraries/pass_wonky_struct_client.c create mode 100644 chapter19/valid/libraries/struct.h create mode 100644 chapter19/valid/member_access_tests/addr_of_arrow.c create mode 100644 chapter19/valid/member_access_tests/aggregate_through_arrow.c create mode 100644 chapter19/valid/member_access_tests/assign_to_struct.c create mode 100644 chapter19/valid/member_access_tests/assign_to_struct_pointer.c create mode 100644 chapter19/valid/member_access_tests/copy_from_pointer.c create mode 100644 chapter19/valid/member_access_tests/copy_to_pointer.c create mode 100644 chapter19/valid/member_access_tests/deref_arrow.c create mode 100644 chapter19/valid/member_access_tests/get_array_through_pointer.c create mode 100644 chapter19/valid/member_access_tests/get_member_addresses.c create mode 100644 chapter19/valid/member_access_tests/global_nested_struct.c create mode 100644 chapter19/valid/member_access_tests/global_struct.c create mode 100644 chapter19/valid/member_access_tests/linked_list.c create mode 100644 chapter19/valid/member_access_tests/nested_address_calculations.c create mode 100644 chapter19/valid/member_access_tests/nested_struct.c create mode 100644 chapter19/valid/member_access_tests/non_static_struct.c create mode 100644 chapter19/valid/member_access_tests/pointer_to_struct.c create mode 100644 chapter19/valid/member_access_tests/static_struct.c create mode 100644 chapter19/valid/member_access_tests/struct.c create mode 100644 chapter19/valid/misc_typecheck/cast_struct_to_void.c create mode 100644 chapter19/valid/misc_typecheck/conditional_struct.c create mode 100644 chapter19/valid/misc_typecheck/temporary_lifetime.c create mode 100644 chapter19/valid/parse_and_lex/postfix_precedence.c create mode 100644 chapter19/valid/parse_and_lex/space_around_struct_member.c create mode 100644 chapter19/valid/parse_and_lex/struct_member_looks_like_const.c create mode 100644 chapter19/valid/scoping_tests/declare_struct.c create mode 100644 chapter19/valid/scoping_tests/different_namespaces_same_ids.c create mode 100644 chapter19/valid/scoping_tests/resolve_tag_for_loop_decl.c create mode 100644 chapter19/valid/scoping_tests/resolve_tag_sizeof.c create mode 100644 chapter19/valid/scoping_tests/resolve_tags_derived_types.c create mode 100644 chapter19/valid/scoping_tests/same_tag_name.c create mode 100644 chapter19/valid/scoping_tests/same_tag_name_simple.c create mode 100644 chapter19/valid/scoping_tests/scoped_struct.c create mode 100644 chapter19/valid/scoping_tests/shared_struct_and_var_names.c create mode 100644 chapter19/valid/sizeof/sizeof_padded.c create mode 100644 chapter19/valid/sizeof/sizeof_struct.c create mode 100644 chapter19/valid/sizeof/sizeof_wonky.c create mode 100644 chapter19/valid/struct_copy_tests/array_of_structs.c create mode 100644 chapter19/valid/struct_copy_tests/array_of_structs_padding.c create mode 100644 chapter19/valid/struct_copy_tests/copy_from_offset_test.c create mode 100644 chapter19/valid/struct_copy_tests/copy_struct.c create mode 100644 chapter19/valid/struct_copy_tests/copy_struct_into_member.c create mode 100644 chapter19/valid/struct_copy_tests/copy_struct_with_array.c create mode 100644 chapter19/valid/struct_copy_tests/copy_struct_with_array_2.c create mode 100644 chapter19/valid/struct_copy_tests/load_test.c diff --git a/chapter19/invalid_lex/dot_bad_token.c b/chapter19/invalid_lex/dot_bad_token.c new file mode 100644 index 00000000..5cf6a126 --- /dev/null +++ b/chapter19/invalid_lex/dot_bad_token.c @@ -0,0 +1,10 @@ +struct s { + int a; +}; + +int main() { + struct s x; + // we should reject .1l as an invalid preprocessing number, + // as opposed to accepting it as a dot followed by a valid constant + return x.1l; +} \ No newline at end of file diff --git a/chapter19/invalid_parse/bad_arrow_operator.c b/chapter19/invalid_parse/bad_arrow_operator.c new file mode 100644 index 00000000..8043ba66 --- /dev/null +++ b/chapter19/invalid_parse/bad_arrow_operator.c @@ -0,0 +1,8 @@ +struct s { + int y; +}; + +int main() { + struct s *ptr = 0; + return ptr->; +} \ No newline at end of file diff --git a/chapter19/invalid_parse/bad_dot_operator.c b/chapter19/invalid_parse/bad_dot_operator.c new file mode 100644 index 00000000..61d5c1b3 --- /dev/null +++ b/chapter19/invalid_parse/bad_dot_operator.c @@ -0,0 +1,8 @@ +struct s { + int y; +}; + +struct s x; +// dot operator must be immediately followed by field name +// (can't parenthesize it) +int main() { return x.(y); } diff --git a/chapter19/invalid_parse/bad_struct_specifier.c b/chapter19/invalid_parse/bad_struct_specifier.c new file mode 100644 index 00000000..cd979ab8 --- /dev/null +++ b/chapter19/invalid_parse/bad_struct_specifier.c @@ -0,0 +1,4 @@ +int main() { + struct 4 foo; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_parse/bad_tag.c b/chapter19/invalid_parse/bad_tag.c new file mode 100644 index 00000000..58c11ca0 --- /dev/null +++ b/chapter19/invalid_parse/bad_tag.c @@ -0,0 +1,10 @@ +struct s { + int y; +}; + +int main() { + // can't parenthesize type tag + struct(s) var; + + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_parse/bad_type_specifier.c b/chapter19/invalid_parse/bad_type_specifier.c new file mode 100644 index 00000000..621b71b7 --- /dev/null +++ b/chapter19/invalid_parse/bad_type_specifier.c @@ -0,0 +1,6 @@ +struct s; + +// cannot combine struct keyword with other type specifier +struct s long a; + +int main() { return 0; } \ No newline at end of file diff --git a/chapter19/invalid_parse/dot_no_left_expr.c b/chapter19/invalid_parse/dot_no_left_expr.c new file mode 100644 index 00000000..f3b32dfd --- /dev/null +++ b/chapter19/invalid_parse/dot_no_left_expr.c @@ -0,0 +1,3 @@ +int main() { + return .a; +} \ No newline at end of file diff --git a/chapter19/invalid_parse/empty_member_list.c b/chapter19/invalid_parse/empty_member_list.c new file mode 100644 index 00000000..42b95713 --- /dev/null +++ b/chapter19/invalid_parse/empty_member_list.c @@ -0,0 +1,5 @@ +// struct member list cannot be empty +// (note that GCC/Clang allow this as an extenision) +struct s {}; + +int main() { return 0; } \ No newline at end of file diff --git a/chapter19/invalid_parse/initialize_member.c b/chapter19/invalid_parse/initialize_member.c new file mode 100644 index 00000000..dee51686 --- /dev/null +++ b/chapter19/invalid_parse/initialize_member.c @@ -0,0 +1,9 @@ +struct pair { + int a; + int b; +}; + +int main() { + // not a valid struct initializer + struct pair x.a = 10; +} \ No newline at end of file diff --git a/chapter19/invalid_parse/kw_type_tag.c b/chapter19/invalid_parse/kw_type_tag.c new file mode 100644 index 00000000..05956df5 --- /dev/null +++ b/chapter19/invalid_parse/kw_type_tag.c @@ -0,0 +1,4 @@ +// cannot use keyword as struct tag +struct for { + int a; +}; \ No newline at end of file diff --git a/chapter19/invalid_parse/missing_end_semicolon.c b/chapter19/invalid_parse/missing_end_semicolon.c new file mode 100644 index 00000000..e6fc5691 --- /dev/null +++ b/chapter19/invalid_parse/missing_end_semicolon.c @@ -0,0 +1,7 @@ +struct s { + int a; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_parse/missing_struct_keyword.c b/chapter19/invalid_parse/missing_struct_keyword.c new file mode 100644 index 00000000..f2ece318 --- /dev/null +++ b/chapter19/invalid_parse/missing_struct_keyword.c @@ -0,0 +1,5 @@ +int main() { + struct x; + x y; // cannot specify struct typew/out struct keyword + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_parse/struct_decl_for_init.c b/chapter19/invalid_parse/struct_decl_for_init.c new file mode 100644 index 00000000..4aa0434f --- /dev/null +++ b/chapter19/invalid_parse/struct_decl_for_init.c @@ -0,0 +1,5 @@ +int main() { + int i = 0; + for (struct s; i < 100; i = i + 1) + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_parse/struct_member_initializer.c b/chapter19/invalid_parse/struct_member_initializer.c new file mode 100644 index 00000000..025ccf8f --- /dev/null +++ b/chapter19/invalid_parse/struct_member_initializer.c @@ -0,0 +1,4 @@ +struct a { + // structure members cannot have initializers + int member = 1; +}; \ No newline at end of file diff --git a/chapter19/invalid_parse/struct_member_no_declarator.c b/chapter19/invalid_parse/struct_member_no_declarator.c new file mode 100644 index 00000000..92b56ac8 --- /dev/null +++ b/chapter19/invalid_parse/struct_member_no_declarator.c @@ -0,0 +1,3 @@ +struct s { + int; +}; \ No newline at end of file diff --git a/chapter19/invalid_parse/structure_member_is_function.c b/chapter19/invalid_parse/structure_member_is_function.c new file mode 100644 index 00000000..5ca5547b --- /dev/null +++ b/chapter19/invalid_parse/structure_member_is_function.c @@ -0,0 +1,3 @@ +struct s { + int foo(); +}; \ No newline at end of file diff --git a/chapter19/invalid_parse/structure_member_no_type.c b/chapter19/invalid_parse/structure_member_no_type.c new file mode 100644 index 00000000..727e607c --- /dev/null +++ b/chapter19/invalid_parse/structure_member_no_type.c @@ -0,0 +1,3 @@ +struct s { + a; +}; \ No newline at end of file diff --git a/chapter19/invalid_parse/structure_member_storage_class.c b/chapter19/invalid_parse/structure_member_storage_class.c new file mode 100644 index 00000000..48169e86 --- /dev/null +++ b/chapter19/invalid_parse/structure_member_storage_class.c @@ -0,0 +1,4 @@ +struct y { + // structure member cannot have storage class + static int a; +}; \ No newline at end of file diff --git a/chapter19/invalid_struct_tags/array_of_undeclared.c b/chapter19/invalid_struct_tags/array_of_undeclared.c new file mode 100644 index 00000000..ae8e985e --- /dev/null +++ b/chapter19/invalid_struct_tags/array_of_undeclared.c @@ -0,0 +1,5 @@ +int main() { + // can't declare array of undeclared/incomplete struct type + struct s arr[2]; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_struct_tags/deref_undeclared.c b/chapter19/invalid_struct_tags/deref_undeclared.c new file mode 100644 index 00000000..e6eb0b3c --- /dev/null +++ b/chapter19/invalid_struct_tags/deref_undeclared.c @@ -0,0 +1,5 @@ +int main() { + struct s *ptr = 0; + *ptr; // can't dereference pointer to undeclared/incomplete struct + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_struct_tags/member_type_undeclared.c b/chapter19/invalid_struct_tags/member_type_undeclared.c new file mode 100644 index 00000000..a3f81091 --- /dev/null +++ b/chapter19/invalid_struct_tags/member_type_undeclared.c @@ -0,0 +1,4 @@ +struct s { + // can't declare struct member with undeclared/incomplete struct type + struct a b; +}; \ No newline at end of file diff --git a/chapter19/invalid_struct_tags/param_undeclared.c b/chapter19/invalid_struct_tags/param_undeclared.c new file mode 100644 index 00000000..0172d206 --- /dev/null +++ b/chapter19/invalid_struct_tags/param_undeclared.c @@ -0,0 +1,3 @@ +// can't use an undeclared (or incomplete) type tag +// as a pararameter in a function definition +int foo(struct s x) { return 0; } \ No newline at end of file diff --git a/chapter19/invalid_struct_tags/sizeof_undeclared.c b/chapter19/invalid_struct_tags/sizeof_undeclared.c new file mode 100644 index 00000000..67802442 --- /dev/null +++ b/chapter19/invalid_struct_tags/sizeof_undeclared.c @@ -0,0 +1,7 @@ +int main() { + return sizeof(struct c); +} + +struct c { + int x; +}; \ No newline at end of file diff --git a/chapter19/invalid_struct_tags/undeclared_struct.c b/chapter19/invalid_struct_tags/undeclared_struct.c new file mode 100644 index 00000000..ea1bce04 --- /dev/null +++ b/chapter19/invalid_struct_tags/undeclared_struct.c @@ -0,0 +1,7 @@ +int main() { + // it's illegal to define a variable with an undeclared tag + // we'll reject this during tag resolution; + // most compilers would reject it b/c 'struct s' is incomplete + struct s var; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/bad_conversions/compare_struct_pointers.c b/chapter19/invalid_types/bad_conversions/compare_struct_pointers.c new file mode 100644 index 00000000..cfd4be5b --- /dev/null +++ b/chapter19/invalid_types/bad_conversions/compare_struct_pointers.c @@ -0,0 +1,12 @@ +struct s1; +struct s2; + +struct s1 *get_s1_ptr(); +struct s2 *get_s2_ptr(); + +int main() { + // can't compare pointers to two distinct struct types + struct s1 *s1_ptr = get_s1_ptr(); + struct s2 *s2_ptr = get_s2_ptr(); + return s1_ptr == s2_ptr; +} \ No newline at end of file diff --git a/chapter19/invalid_types/bad_lvalue/address_of_non_lvalue.c b/chapter19/invalid_types/bad_lvalue/address_of_non_lvalue.c new file mode 100644 index 00000000..42105c89 --- /dev/null +++ b/chapter19/invalid_types/bad_lvalue/address_of_non_lvalue.c @@ -0,0 +1,12 @@ +struct s { + int arr[3]; + double d; +}; + +int main() { + struct s x = {{1, 2, 3}, 4.0}; + struct s y = {{9, 8, 7}, 6.0}; + // can't take address of element b/c it's not an lvalue + int *arr[3] = &(1 ? x : y).arr; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/bad_lvalue/assign_nested_non_lvalue.c b/chapter19/invalid_types/bad_lvalue/assign_nested_non_lvalue.c new file mode 100644 index 00000000..19b92fda --- /dev/null +++ b/chapter19/invalid_types/bad_lvalue/assign_nested_non_lvalue.c @@ -0,0 +1,20 @@ +struct inner { + int x; + int y; +}; + +struct outer { + int a; + struct inner b; +}; + +struct outer return_struct() { + struct outer result = {1, {2, 3}}; + return result; +} + +int main() { + // can't assign to non-lvalue + return_struct().b.x = 10; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/bad_lvalue/assign_to_array.c b/chapter19/invalid_types/bad_lvalue/assign_to_array.c new file mode 100644 index 00000000..bbdfb28f --- /dev/null +++ b/chapter19/invalid_types/bad_lvalue/assign_to_array.c @@ -0,0 +1,10 @@ +struct chars { + char char_array[5]; +}; + +int main() { + struct chars x = {{1, 2, 3, 4, 5}}; + char arr[5] = {9, 8, 7, 6, 5}; + x.char_array = arr; + return x.char_array[0]; +} \ No newline at end of file diff --git a/chapter19/invalid_types/bad_lvalue/assign_to_non_lvalue.c b/chapter19/invalid_types/bad_lvalue/assign_to_non_lvalue.c new file mode 100644 index 00000000..c04a1437 --- /dev/null +++ b/chapter19/invalid_types/bad_lvalue/assign_to_non_lvalue.c @@ -0,0 +1,13 @@ +struct s { + int arr[3]; + double d; +}; + +int main() { + struct s x = {{1, 2, 3}, 4.0}; + struct s y = {{9, 8, 7}, 6.0}; + // can't assign to this struct, it's not an lvalue + (1 ? x : y).d = 0.0; + + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/bad_member_operators/bad_member.c b/chapter19/invalid_types/bad_member_operators/bad_member.c new file mode 100644 index 00000000..c746d692 --- /dev/null +++ b/chapter19/invalid_types/bad_member_operators/bad_member.c @@ -0,0 +1,9 @@ +struct s { + int x; + int y; +}; + +int main() { + struct s foo = {1, 2}; + return foo.blah; +} \ No newline at end of file diff --git a/chapter19/invalid_types/bad_member_operators/bad_pointer_member.c b/chapter19/invalid_types/bad_member_operators/bad_pointer_member.c new file mode 100644 index 00000000..918b8bb2 --- /dev/null +++ b/chapter19/invalid_types/bad_member_operators/bad_pointer_member.c @@ -0,0 +1,17 @@ +void *malloc(unsigned long size); + +struct a { + int x; + int y; +}; + +struct b { + int m; + int n; +}; + +int main() { + struct a *ptr = malloc(sizeof(struct a)); + ptr->m = 10; // wrong member name + return 0; +} diff --git a/chapter19/invalid_types/bad_member_operators/member_of_non_struct.c b/chapter19/invalid_types/bad_member_operators/member_of_non_struct.c new file mode 100644 index 00000000..cdb9cce9 --- /dev/null +++ b/chapter19/invalid_types/bad_member_operators/member_of_non_struct.c @@ -0,0 +1,11 @@ +void *malloc(unsigned long size); + +struct a { + int x; + int y; +}; + +int main() { + struct a *ptr = malloc(sizeof(struct a)); + ptr.x = 10; // can't apply . operator to struct pointer +} \ No newline at end of file diff --git a/chapter19/invalid_types/bad_member_operators/member_pointer_non_member.c b/chapter19/invalid_types/bad_member_operators/member_pointer_non_member.c new file mode 100644 index 00000000..135b9821 --- /dev/null +++ b/chapter19/invalid_types/bad_member_operators/member_pointer_non_member.c @@ -0,0 +1,10 @@ +struct a { + int x; + int y; +}; + +int main() { + struct a my_struct = {1, 2}; + // can't apply -> to non-pointer + return my_struct->x; +} \ No newline at end of file diff --git a/chapter19/invalid_types/bad_member_operators/postfix_precedence.c b/chapter19/invalid_types/bad_member_operators/postfix_precedence.c new file mode 100644 index 00000000..616fa836 --- /dev/null +++ b/chapter19/invalid_types/bad_member_operators/postfix_precedence.c @@ -0,0 +1,10 @@ +int main() { + struct s { + int a; + }; + struct s x = {10}; + // postfix operatpors have higher precedence, + // so this is equivalent to &(x->a), + // which is invalid b/c x isn't a pointe + return &x->a; +} \ No newline at end of file diff --git a/chapter19/invalid_types/conditionals/branch_mismatch.c b/chapter19/invalid_types/conditionals/branch_mismatch.c new file mode 100644 index 00000000..cf930226 --- /dev/null +++ b/chapter19/invalid_types/conditionals/branch_mismatch.c @@ -0,0 +1,13 @@ +struct s1 { + int a; +}; + +struct s2 { + int b; +}; + +int main() { + struct s1 x = {1}; + struct s2 y = {2}; + 1 ? x : y; // can't have conditional branches w/ different struct types +} \ No newline at end of file diff --git a/chapter19/invalid_types/conditionals/branch_mismatch_2.c b/chapter19/invalid_types/conditionals/branch_mismatch_2.c new file mode 100644 index 00000000..794a1491 --- /dev/null +++ b/chapter19/invalid_types/conditionals/branch_mismatch_2.c @@ -0,0 +1,10 @@ +struct s { + int a; +}; + +int main() { + struct s x = {1}; + // can't have conditional branches where only one branch is a struct + + 1 ? x : 2; +} \ No newline at end of file diff --git a/chapter19/invalid_types/initializers/init_struct_with_string.c b/chapter19/invalid_types/initializers/init_struct_with_string.c new file mode 100644 index 00000000..f4a02547 --- /dev/null +++ b/chapter19/invalid_types/initializers/init_struct_with_string.c @@ -0,0 +1,14 @@ +// can't initialize structure members with a string, +// even if they're all chars + +struct chars { + char a; + char b; + char c; + char null; +}; + +int main() { + struct chars my_chars = "abc"; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/initializers/initialize_static_struct_with_zero.c b/chapter19/invalid_types/initializers/initialize_static_struct_with_zero.c new file mode 100644 index 00000000..99f6cec6 --- /dev/null +++ b/chapter19/invalid_types/initializers/initialize_static_struct_with_zero.c @@ -0,0 +1,5 @@ +struct s { + int a; +}; + +struct s x = 0; \ No newline at end of file diff --git a/chapter19/invalid_types/initializers/initialize_struct_with_scalar.c b/chapter19/invalid_types/initializers/initialize_struct_with_scalar.c new file mode 100644 index 00000000..0c4753a7 --- /dev/null +++ b/chapter19/invalid_types/initializers/initialize_struct_with_scalar.c @@ -0,0 +1,8 @@ +int main() { + struct pair { + int x; + int y; + }; + + struct pair p = 1; +} \ No newline at end of file diff --git a/chapter19/invalid_types/initializers/initialize_struct_with_zero.c b/chapter19/invalid_types/initializers/initialize_struct_with_zero.c new file mode 100644 index 00000000..82a2f487 --- /dev/null +++ b/chapter19/invalid_types/initializers/initialize_struct_with_zero.c @@ -0,0 +1,8 @@ +struct s { + int a; +}; + +int main() { + struct s x = 0; + return x.a; +} \ No newline at end of file diff --git a/chapter19/invalid_types/initializers/initialize_struct_wrong_type.c b/chapter19/invalid_types/initializers/initialize_struct_wrong_type.c new file mode 100644 index 00000000..3a451f26 --- /dev/null +++ b/chapter19/invalid_types/initializers/initialize_struct_wrong_type.c @@ -0,0 +1,15 @@ +struct one { + int x; + int y; +}; + +struct two { + int a; + int b; +}; + +int main() { + struct one x = {1, 2}; + struct two y = x; // can't initialize from differnet struct type + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/initializers/nested_initialize_struct_wrong_type.c b/chapter19/invalid_types/initializers/nested_initialize_struct_wrong_type.c new file mode 100644 index 00000000..8215de05 --- /dev/null +++ b/chapter19/invalid_types/initializers/nested_initialize_struct_wrong_type.c @@ -0,0 +1,16 @@ +struct inner { + int a; + int b; +}; + +struct outer { + struct inner x; +}; + +int main() { + struct outer x = {{1, 2}}; + // can't initialize second element of type 'struct inner' + // from variable of type 'struct outer' + struct outer y = {1, x}; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/initializers/non_constant_static_init.c b/chapter19/invalid_types/initializers/non_constant_static_init.c new file mode 100644 index 00000000..0cedfb35 --- /dev/null +++ b/chapter19/invalid_types/initializers/non_constant_static_init.c @@ -0,0 +1,6 @@ +struct pair { + int a; + int b; +}; +struct pair x = {1, 2}; +struct pair y = x; \ No newline at end of file diff --git a/chapter19/invalid_types/initializers/static_bad_element_type.c b/chapter19/invalid_types/initializers/static_bad_element_type.c new file mode 100644 index 00000000..bc1891ab --- /dev/null +++ b/chapter19/invalid_types/initializers/static_bad_element_type.c @@ -0,0 +1,7 @@ +struct s { + double d; + void *arr[3]; +}; + +// can't initialize void * w/ double +struct s x = {0.0, {1.0}}; \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/assign_to_incomplete_var.c b/chapter19/invalid_types/invalid_incomplete_structs/assign_to_incomplete_var.c new file mode 100644 index 00000000..67389526 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/assign_to_incomplete_var.c @@ -0,0 +1,8 @@ +struct s; + +extern struct s x; +extern struct s y; +int main() { + x = y; // can't assign w/ incomplete struct types + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/cast_incomplete_struct.c b/chapter19/invalid_types/invalid_incomplete_structs/cast_incomplete_struct.c new file mode 100644 index 00000000..488830d2 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/cast_incomplete_struct.c @@ -0,0 +1,9 @@ +struct s; + +extern struct s v; + +int main() { + // incomplete structures can't appear in cast expressions + (void)v; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/deref_incomplete_struct_pointer.c b/chapter19/invalid_types/invalid_incomplete_structs/deref_incomplete_struct_pointer.c new file mode 100644 index 00000000..361b316e --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/deref_incomplete_struct_pointer.c @@ -0,0 +1,10 @@ +struct s; + +struct s *ptr = 0; + +int main() { + // can't dereference pointer to incomplete type + // except in expression &*ptr + *ptr; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_arg_funcall.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_arg_funcall.c new file mode 100644 index 00000000..c5727446 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_arg_funcall.c @@ -0,0 +1,9 @@ +struct s; + +void f(struct s param); + +extern struct s extern_var; + +int main() { + f(extern_var); +} // can't pass a variable w/ incomplete as an argument \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_array_element.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_array_element.c new file mode 100644 index 00000000..621c661d --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_array_element.c @@ -0,0 +1,10 @@ +struct s arr[3]; + +struct s { + int a; + int b; +}; + +int main() { + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_local_var.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_local_var.c new file mode 100644 index 00000000..2236eb79 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_local_var.c @@ -0,0 +1,7 @@ +struct s; + +int main() { + // can't declare a local variable with incomplete struct type + struct s v; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_param.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_param.c new file mode 100644 index 00000000..bd99c584 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_param.c @@ -0,0 +1,4 @@ +struct s; + +// it's illegal to define a function with an incomplete parameter +int foo(struct s x) { return 0; } diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_ptr_addition.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_ptr_addition.c new file mode 100644 index 00000000..cee57df6 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_ptr_addition.c @@ -0,0 +1,8 @@ +struct s; + +extern struct s *ptr; + +int main() { + // can't perform pointer addition w/ pointers to incomplete types + return ptr + 0 == ptr; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_ptr_subtraction.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_ptr_subtraction.c new file mode 100644 index 00000000..d1371204 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_ptr_subtraction.c @@ -0,0 +1,8 @@ +struct s; + +extern struct s *ptr; + +int main() { + // can't perform pointer substraction w/ pointers to incomplete types + return (ptr - ptr) == 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_return_type_fun_def.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_return_type_fun_def.c new file mode 100644 index 00000000..099a467f --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_return_type_fun_def.c @@ -0,0 +1,11 @@ +// can't define a structure with an incomplete return type +struct s return_struct() { + + struct s result = {1, 2}; + return result; +} +struct s { + int a; + int b; +}; +int main() { return 0; } \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_return_type_funcall.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_return_type_funcall.c new file mode 100644 index 00000000..d80a3641 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_return_type_funcall.c @@ -0,0 +1,8 @@ +struct s; + +struct s f(); + +int main() { + f(); // can't call a function with an incomplete return type (besides void) + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_conditional.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_conditional.c new file mode 100644 index 00000000..5d52a7f7 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_conditional.c @@ -0,0 +1,9 @@ +struct s; + +extern struct s v1; +extern struct s v2; + +int main() { + // don't use incomplete structure types in conditional expression + 1 ? v1 : v2; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_full_expr.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_full_expr.c new file mode 100644 index 00000000..608b782a --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_full_expr.c @@ -0,0 +1,10 @@ +struct s; + +extern struct s x; + +int main() { + // can't use variable w/ incomplete struct type as expression statement + for (x;;) + ; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_member.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_member.c new file mode 100644 index 00000000..c374423b --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_struct_member.c @@ -0,0 +1,7 @@ +struct s; + +extern struct s foo; + +int main() { + return foo.a; // can't get member of incomplete structure type +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_subscript.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_subscript.c new file mode 100644 index 00000000..c06c8afb --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_subscript.c @@ -0,0 +1,4 @@ +struct s; +extern struct s *ptr; + +int main() { ptr[0]; } \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/incomplete_tentative_def.c b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_tentative_def.c new file mode 100644 index 00000000..44c45706 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/incomplete_tentative_def.c @@ -0,0 +1,9 @@ +struct s; + +// it's illegal to define a variable w/ an incomplete structure type +// (some compilers allow tentative defs if var has external linkage +// and the type is completed +// later in the same translation unit, but we don't.) +static struct s x; + +int main() { return 0; } \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/initialize_incomplete.c b/chapter19/invalid_types/invalid_incomplete_structs/initialize_incomplete.c new file mode 100644 index 00000000..0f37bc4e --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/initialize_incomplete.c @@ -0,0 +1,11 @@ +struct s; + +// you can declare extern variables of incomplete type +// but it's illegal to initialize them +extern struct s x = {1}; + +int main() { return 0; } + +struct s { + int a; +}; \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_incomplete_structs/sizeof_incomplete.c b/chapter19/invalid_types/invalid_incomplete_structs/sizeof_incomplete.c new file mode 100644 index 00000000..77645cc5 --- /dev/null +++ b/chapter19/invalid_types/invalid_incomplete_structs/sizeof_incomplete.c @@ -0,0 +1,5 @@ +struct s; + +int main() { + return sizeof(struct s); // can't take size of incomplete type +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_struct_declaration/duplicate_member_name.c b/chapter19/invalid_types/invalid_struct_declaration/duplicate_member_name.c new file mode 100644 index 00000000..de96d21e --- /dev/null +++ b/chapter19/invalid_types/invalid_struct_declaration/duplicate_member_name.c @@ -0,0 +1,5 @@ +struct s { + // can't declare two members with same name + int x; + double x; +}; \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_struct_declaration/duplicate_struct_declaration.c b/chapter19/invalid_types/invalid_struct_declaration/duplicate_struct_declaration.c new file mode 100644 index 00000000..aad21933 --- /dev/null +++ b/chapter19/invalid_types/invalid_struct_declaration/duplicate_struct_declaration.c @@ -0,0 +1,9 @@ +int main() { + struct x { + int x; + }; + struct x { + int y; + }; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_struct_declaration/incomplete_member.c b/chapter19/invalid_types/invalid_struct_declaration/incomplete_member.c new file mode 100644 index 00000000..d5e50a83 --- /dev/null +++ b/chapter19/invalid_types/invalid_struct_declaration/incomplete_member.c @@ -0,0 +1,6 @@ +struct s; // declare incomplete structure type + +struct a { + // can't use incomplete struct type as member + struct s g; +}; \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_struct_declaration/invalid_array_member.c b/chapter19/invalid_types/invalid_struct_declaration/invalid_array_member.c new file mode 100644 index 00000000..566cee4c --- /dev/null +++ b/chapter19/invalid_types/invalid_struct_declaration/invalid_array_member.c @@ -0,0 +1,7 @@ +struct incomplete; + +struct s { + // member type is invalid: pointer to array of struct incomplete, + // but can't have array of incomplete type + struct incomplete (*array_pointer)[3]; +}; \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_struct_declaration/invalid_self_reference.c b/chapter19/invalid_types/invalid_struct_declaration/invalid_self_reference.c new file mode 100644 index 00000000..a526fbdd --- /dev/null +++ b/chapter19/invalid_types/invalid_struct_declaration/invalid_self_reference.c @@ -0,0 +1,8 @@ +struct s { + int x; + struct s y; +}; + +int main() { + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_struct_declaration/invalid_shadow_self_reference.c b/chapter19/invalid_types/invalid_struct_declaration/invalid_shadow_self_reference.c new file mode 100644 index 00000000..272b5481 --- /dev/null +++ b/chapter19/invalid_types/invalid_struct_declaration/invalid_shadow_self_reference.c @@ -0,0 +1,13 @@ +struct s { + int a; +}; + +int main() { + struct s { + // can't do this, because tag 's' refers to the type we're declaring now + // instead of the type we declared earlier + // (make sure we add new tag to current scope before we process its members) + struct s nested; + }; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/invalid_struct_declaration/void_member.c b/chapter19/invalid_types/invalid_struct_declaration/void_member.c new file mode 100644 index 00000000..00264ba6 --- /dev/null +++ b/chapter19/invalid_types/invalid_struct_declaration/void_member.c @@ -0,0 +1,4 @@ +struct s { + // can't have void member + void x; +}; \ No newline at end of file diff --git a/chapter19/invalid_types/scalar_required/assign_null_ptr_to_struct.c b/chapter19/invalid_types/scalar_required/assign_null_ptr_to_struct.c new file mode 100644 index 00000000..18e0eb50 --- /dev/null +++ b/chapter19/invalid_types/scalar_required/assign_null_ptr_to_struct.c @@ -0,0 +1,10 @@ +struct s { + int a; +}; + +struct s x = {1}; + +int main() { + x = 0; // can't assign null pointer to struct + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/scalar_required/assign_scalar_to_struct.c b/chapter19/invalid_types/scalar_required/assign_scalar_to_struct.c new file mode 100644 index 00000000..6d7afd48 --- /dev/null +++ b/chapter19/invalid_types/scalar_required/assign_scalar_to_struct.c @@ -0,0 +1,10 @@ +struct s { + int a; +}; + +struct s x = {1}; + +int main() { + x = 2; // can't assign scalar to struct + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/scalar_required/cast_struct_to_scalar.c b/chapter19/invalid_types/scalar_required/cast_struct_to_scalar.c new file mode 100644 index 00000000..b4d2489a --- /dev/null +++ b/chapter19/invalid_types/scalar_required/cast_struct_to_scalar.c @@ -0,0 +1,10 @@ +struct s { + int a; +}; + +int main() { + struct s x = {1}; + // can't cast struct to a scalar value + int y = (int)x; + return y; +} \ No newline at end of file diff --git a/chapter19/invalid_types/scalar_required/cast_to_struct.c b/chapter19/invalid_types/scalar_required/cast_to_struct.c new file mode 100644 index 00000000..39eb6a06 --- /dev/null +++ b/chapter19/invalid_types/scalar_required/cast_to_struct.c @@ -0,0 +1,9 @@ +struct s { + int a; +}; + +struct s x; + +// can only cast to scalar type or void +// casting struct to itself is illegal +int main() { (struct s) x; } \ No newline at end of file diff --git a/chapter19/invalid_types/scalar_required/compare_structs.c b/chapter19/invalid_types/scalar_required/compare_structs.c new file mode 100644 index 00000000..4169fab8 --- /dev/null +++ b/chapter19/invalid_types/scalar_required/compare_structs.c @@ -0,0 +1,9 @@ +struct s { + int a; +}; + +int main() { + struct s x = {1}; + struct s y = {2}; + return x == y; +} \ No newline at end of file diff --git a/chapter19/invalid_types/scalar_required/not_struct.c b/chapter19/invalid_types/scalar_required/not_struct.c new file mode 100644 index 00000000..38cc9d60 --- /dev/null +++ b/chapter19/invalid_types/scalar_required/not_struct.c @@ -0,0 +1,8 @@ +struct s { + int a; +}; + +int main() { + struct s x = {1}; + return !x; // can't apply boolean operators to structs +} \ No newline at end of file diff --git a/chapter19/invalid_types/scalar_required/pass_struct_as_scalar_param.c b/chapter19/invalid_types/scalar_required/pass_struct_as_scalar_param.c new file mode 100644 index 00000000..b25e45d5 --- /dev/null +++ b/chapter19/invalid_types/scalar_required/pass_struct_as_scalar_param.c @@ -0,0 +1,10 @@ +struct s { + int a; +}; +int foo(int a) { return a; } + +int main() { + struct s x = {1}; + // can't convert struct to scalar as if by assignment + return foo(x); +} \ No newline at end of file diff --git a/chapter19/invalid_types/scalar_required/struct_as_int.c b/chapter19/invalid_types/scalar_required/struct_as_int.c new file mode 100644 index 00000000..652081d9 --- /dev/null +++ b/chapter19/invalid_types/scalar_required/struct_as_int.c @@ -0,0 +1,11 @@ +// can't use structure type where integer is required + +struct s { + int a; +}; + +int main() { + struct s x = {1}; + (void)~x; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/scalar_required/struct_controlling_expression.c b/chapter19/invalid_types/scalar_required/struct_controlling_expression.c new file mode 100644 index 00000000..ffcfe2cf --- /dev/null +++ b/chapter19/invalid_types/scalar_required/struct_controlling_expression.c @@ -0,0 +1,11 @@ +struct s { + int a; +}; + +int main() { + struct s x = {1}; + // can't use structure as controlling expression in if statement + if (x) + return 1; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/scalar_required/subscript_struct.c b/chapter19/invalid_types/scalar_required/subscript_struct.c new file mode 100644 index 00000000..074a05a6 --- /dev/null +++ b/chapter19/invalid_types/scalar_required/subscript_struct.c @@ -0,0 +1,8 @@ +struct s { + int a; +}; + +int main() { + struct s x = {1}; + return x[0]; // can't subscript structures +} \ No newline at end of file diff --git a/chapter19/invalid_types/tag_resolution/conflicting_fun_param_types.c b/chapter19/invalid_types/tag_resolution/conflicting_fun_param_types.c new file mode 100644 index 00000000..13b458aa --- /dev/null +++ b/chapter19/invalid_types/tag_resolution/conflicting_fun_param_types.c @@ -0,0 +1,8 @@ +struct s; +int foo(struct s x); + +int main() { + struct s; + int foo(struct s x); // conflicts w/ earlier declaration, different param type + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/tag_resolution/conflicting_fun_ret_types.c b/chapter19/invalid_types/tag_resolution/conflicting_fun_ret_types.c new file mode 100644 index 00000000..4ca4eeec --- /dev/null +++ b/chapter19/invalid_types/tag_resolution/conflicting_fun_ret_types.c @@ -0,0 +1,9 @@ +struct s; + +struct s foo(); + +int main() { + struct s; + struct s foo(); // conflict w/ earlier def; wrong return type + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/tag_resolution/distinct_struct_types.c b/chapter19/invalid_types/tag_resolution/distinct_struct_types.c new file mode 100644 index 00000000..5a44dccc --- /dev/null +++ b/chapter19/invalid_types/tag_resolution/distinct_struct_types.c @@ -0,0 +1,15 @@ +int foo() { + struct s { + int a; + int b; + }; + struct s result = {1, 2}; + return result.a + result.b; +} + +int main() { + // previously define struct s is not visible here, + // so this is trying to define a variable with incomplete type + struct s blah = {foo(), foo()}; + return blah.a; +} \ No newline at end of file diff --git a/chapter19/invalid_types/tag_resolution/incomplete_shadows_complete.c b/chapter19/invalid_types/tag_resolution/incomplete_shadows_complete.c new file mode 100644 index 00000000..0f0f514c --- /dev/null +++ b/chapter19/invalid_types/tag_resolution/incomplete_shadows_complete.c @@ -0,0 +1,10 @@ +struct s { + int a; +}; + +int main() { + struct s; // incomplete declaration shadows complete + struct s *x; + x->a = 10; // illegal; x has incomplete type w/out member 'a' + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/tag_resolution/incomplete_shadows_complete_cast.c b/chapter19/invalid_types/tag_resolution/incomplete_shadows_complete_cast.c new file mode 100644 index 00000000..27aa74bf --- /dev/null +++ b/chapter19/invalid_types/tag_resolution/incomplete_shadows_complete_cast.c @@ -0,0 +1,13 @@ +// make sure we resolve tags in cast expressions +void *malloc(unsigned long size); +struct s { + int a; +}; + +int main() { + void *ptr = malloc(sizeof(struct s)); + struct s; + // struct s specifier in cast expression refers to inner, incomplete type + ((struct s *)ptr)->a = 10; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/tag_resolution/invalid_shadow_self_reference.c b/chapter19/invalid_types/tag_resolution/invalid_shadow_self_reference.c new file mode 100644 index 00000000..ccdf2b22 --- /dev/null +++ b/chapter19/invalid_types/tag_resolution/invalid_shadow_self_reference.c @@ -0,0 +1,12 @@ +struct s { + int a; +}; + +int main() { + struct s { + // can't do this, because tag 's' refers to the type we're declaring now + // instead of the type we declared earlier + struct s nested; + }; + return 0; +} \ No newline at end of file diff --git a/chapter19/invalid_types/tag_resolution/mismatched_return_type.c b/chapter19/invalid_types/tag_resolution/mismatched_return_type.c new file mode 100644 index 00000000..64db776c --- /dev/null +++ b/chapter19/invalid_types/tag_resolution/mismatched_return_type.c @@ -0,0 +1,16 @@ +struct s { + int a; + int b; +}; + +struct s return_struct() { + // define another struct s that shadows previous one; + struct s { + int a; + int b; + }; + struct s result = {1, 2}; + // result has inner 'struct s' type instead of outer one, + // so it's incompatible w/ function's return type + return result; +} diff --git a/chapter19/invalid_types/tag_resolution/shadow_struct.c b/chapter19/invalid_types/tag_resolution/shadow_struct.c new file mode 100644 index 00000000..c69ae843 --- /dev/null +++ b/chapter19/invalid_types/tag_resolution/shadow_struct.c @@ -0,0 +1,9 @@ +// Listing 19-30 + +struct s; +struct s *ptr1 = 0; +int main() { + struct s; + struct s *ptr2 = 0; + return ptr1 == ptr2; +} diff --git a/chapter19/valid/fun_calls/pass_and_return_struct.c b/chapter19/valid/fun_calls/pass_and_return_struct.c new file mode 100644 index 00000000..40b1823f --- /dev/null +++ b/chapter19/valid/fun_calls/pass_and_return_struct.c @@ -0,0 +1,15 @@ +struct pair { + int x; + char y; +}; + +struct pair add_to_x(struct pair p) { + p.x = p.x + 5; + return p; +} + +int main() { + struct pair arg = { 1, 4 }; + struct pair result = add_to_x(arg); + return result.x + arg.x + result.y; +} \ No newline at end of file diff --git a/chapter19/valid/fun_calls/pass_pointer_to_struct.c b/chapter19/valid/fun_calls/pass_pointer_to_struct.c new file mode 100644 index 00000000..9b02d2d9 --- /dev/null +++ b/chapter19/valid/fun_calls/pass_pointer_to_struct.c @@ -0,0 +1,15 @@ +struct pair { + int elem1; + int elem2; +}; + +void set_pair(struct pair *ptr) { + ptr->elem1 = 100; + ptr->elem2 = 12; +} + +int main() { + struct pair p = {0, 0}; + set_pair(&p); + return p.elem1 + p.elem2; +} \ No newline at end of file diff --git a/chapter19/valid/fun_calls/pass_struct_and_other_args.c b/chapter19/valid/fun_calls/pass_struct_and_other_args.c new file mode 100644 index 00000000..89a45f4a --- /dev/null +++ b/chapter19/valid/fun_calls/pass_struct_and_other_args.c @@ -0,0 +1,13 @@ +struct pair { + int x; + double y; +}; + +double foo(struct pair p, int a, int b, int c, int d, int e, int f, int g) { + return p.y + g; +} + +int main() { + struct pair x = { 1, 2.0 }; + return foo(x, 0, 0, 0, 0, 0, 0, 1) == 3.0; +} \ No newline at end of file diff --git a/chapter19/valid/fun_calls/pass_struct_as_arg.c b/chapter19/valid/fun_calls/pass_struct_as_arg.c new file mode 100644 index 00000000..5fda7531 --- /dev/null +++ b/chapter19/valid/fun_calls/pass_struct_as_arg.c @@ -0,0 +1,13 @@ +struct pair { + int x; + double y; +}; + +double foo(struct pair p) { + return p.y; +} + +int main() { + struct pair x = { 1, 2.0 }; + return foo(x) == 2.0; +} \ No newline at end of file diff --git a/chapter19/valid/fun_calls/return_struct.c b/chapter19/valid/fun_calls/return_struct.c new file mode 100644 index 00000000..6c650d71 --- /dev/null +++ b/chapter19/valid/fun_calls/return_struct.c @@ -0,0 +1,13 @@ +struct pair { + char x; + long y; +}; + +struct pair return_pair() { + struct pair ret = { 1, 11l }; + return ret; +} + +int main() { + return return_pair().y; +} \ No newline at end of file diff --git a/chapter19/valid/incomplete_structs/block_scope_forward_decl.c b/chapter19/valid/incomplete_structs/block_scope_forward_decl.c new file mode 100644 index 00000000..1165a137 --- /dev/null +++ b/chapter19/valid/incomplete_structs/block_scope_forward_decl.c @@ -0,0 +1,8 @@ +int main() { + struct s; + struct s *s_ptr = 0; + struct s { int x; int y; }; + struct s val = { 1, 2 }; + s_ptr = &val; + return s_ptr->x + s_ptr->y; +} \ No newline at end of file diff --git a/chapter19/valid/incomplete_structs/define_then_declare.c b/chapter19/valid/incomplete_structs/define_then_declare.c new file mode 100644 index 00000000..2ab12964 --- /dev/null +++ b/chapter19/valid/incomplete_structs/define_then_declare.c @@ -0,0 +1,12 @@ +// if we've already defined/declared a struct, declaring it again in the same +// scope does nothing + +int main() { + struct s { + int a; + }; + struct s; // this does nothing + + struct s x = {1}; + return x.a; +} \ No newline at end of file diff --git a/chapter19/valid/incomplete_structs/deref_incomplete_var.c b/chapter19/valid/incomplete_structs/deref_incomplete_var.c new file mode 100644 index 00000000..97d363c3 --- /dev/null +++ b/chapter19/valid/incomplete_structs/deref_incomplete_var.c @@ -0,0 +1,14 @@ +struct s; +struct s *get_struct_pointer(); +void *malloc(unsigned long size); + +int main() { + struct s *ptr = get_struct_pointer(); + // test that we can dereference an incomplete type and then take its address + // (GCC fails to compile this before version 10; see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88827) + return &*ptr == ptr; +} + +struct s *get_struct_pointer() { + return malloc(8); +} \ No newline at end of file diff --git a/chapter19/valid/incomplete_structs/file_scope_forward_decl.c b/chapter19/valid/incomplete_structs/file_scope_forward_decl.c new file mode 100644 index 00000000..84ded432 --- /dev/null +++ b/chapter19/valid/incomplete_structs/file_scope_forward_decl.c @@ -0,0 +1,20 @@ +struct s; +struct s *get_struct(); +void *malloc(unsigned long size); + +struct s { + int x; + int y; +}; + +int main() { + struct s *ptr = get_struct(); + return ptr->y; +} + +struct s *get_struct() { + struct s *result = malloc(sizeof(struct s)); + result->x = 1; + result->y = 2; + return result; +} \ No newline at end of file diff --git a/chapter19/valid/incomplete_structs/incomplete_param_type.c b/chapter19/valid/incomplete_structs/incomplete_param_type.c new file mode 100644 index 00000000..99a30310 --- /dev/null +++ b/chapter19/valid/incomplete_structs/incomplete_param_type.c @@ -0,0 +1,17 @@ +struct s; + +int foo(struct s blah); + +struct s { + int a; + int b; +}; + +int main() { + struct s arg = { 1, 2}; + return foo(arg); +} + +int foo(struct s blah) { + return blah.a + blah.b; +} \ No newline at end of file diff --git a/chapter19/valid/incomplete_structs/incomplete_var_completed.c b/chapter19/valid/incomplete_structs/incomplete_var_completed.c new file mode 100644 index 00000000..75af97a2 --- /dev/null +++ b/chapter19/valid/incomplete_structs/incomplete_var_completed.c @@ -0,0 +1,16 @@ +struct s; + +extern struct s x; // declare but don't define + +int get_member(struct s *param); + +int main() { return get_member(&x); } + +// define the struct +struct s { + int a; +}; + +// define x +struct s x = {100}; +int get_member(struct s *param) { return param->a; } \ No newline at end of file diff --git a/chapter19/valid/incomplete_structs/return_incomplete_type.c b/chapter19/valid/incomplete_structs/return_incomplete_type.c new file mode 100644 index 00000000..22efbf25 --- /dev/null +++ b/chapter19/valid/incomplete_structs/return_incomplete_type.c @@ -0,0 +1,17 @@ +struct s; +struct s return_struct(); + +struct s { + int a; + int b; +}; + +int main() { + struct s val = return_struct(); + return val.a; +} + +struct s return_struct() { + struct s result = { 1, 2 }; + return result; +} \ No newline at end of file diff --git a/chapter19/valid/initializers/load_addr_in_init.c b/chapter19/valid/initializers/load_addr_in_init.c new file mode 100644 index 00000000..610fb7e0 --- /dev/null +++ b/chapter19/valid/initializers/load_addr_in_init.c @@ -0,0 +1,9 @@ +struct pair { + int x; + int *y; +}; + +int main() { + struct pair p = { 3, &(p.x) }; + return p.x + *p.y; +} \ No newline at end of file diff --git a/chapter19/valid/initializers/mixed_initialization.c b/chapter19/valid/initializers/mixed_initialization.c new file mode 100644 index 00000000..8f0162fb --- /dev/null +++ b/chapter19/valid/initializers/mixed_initialization.c @@ -0,0 +1,11 @@ +struct triple { + long one; + double two; + char three; +}; + +int main() { + struct triple example = {1l, 2.0, 3}; + struct triple array[3] = { {4l, 5.0, 6}, example, example}; + return array[0].one + array[2].three; +} \ No newline at end of file diff --git a/chapter19/valid/initializers/nested_struct_init.c b/chapter19/valid/initializers/nested_struct_init.c new file mode 100644 index 00000000..0635beb2 --- /dev/null +++ b/chapter19/valid/initializers/nested_struct_init.c @@ -0,0 +1,21 @@ +int strcmp(char *s1, char *s2); + +/* NOTE not supporting nested struct declarations */ +struct inner { + int x; + int y; + char arr[3]; +}; + +struct outer { + long l1; + struct inner i; + long l2; +}; + +int main() { + struct outer foo = {100, {3, 4, "!?"}, 10000000}; + if (strcmp(foo.i.arr, "!?")) + return 0; + return foo.i.x + foo.i.y + foo.l1 + (foo.l2 - 9999950); +} \ No newline at end of file diff --git a/chapter19/valid/initializers/partial_struct_init.c b/chapter19/valid/initializers/partial_struct_init.c new file mode 100644 index 00000000..b312c16b --- /dev/null +++ b/chapter19/valid/initializers/partial_struct_init.c @@ -0,0 +1,16 @@ +struct triple +{ + long one; + double two; + char three; +}; + +int main() +{ + struct triple array[3] = {{0}, + {0, 9.0, 4}, + {5, 6.0, 7}}; + struct triple new = {12, 11, 10}; + array[1] = new; + return array[1].one + array[2].three + array[2].three + array[0].one; +} \ No newline at end of file diff --git a/chapter19/valid/initializers/string_in_global_struct.c b/chapter19/valid/initializers/string_in_global_struct.c new file mode 100644 index 00000000..1b6e1c88 --- /dev/null +++ b/chapter19/valid/initializers/string_in_global_struct.c @@ -0,0 +1,10 @@ +struct s { + char *str; + int *x; +}; + +struct s my_struct = { "hello, world", 0}; + +int main() { + return my_struct.str[2] == 'l'; +} \ No newline at end of file diff --git a/chapter19/valid/initializers/string_in_struct.c b/chapter19/valid/initializers/string_in_struct.c new file mode 100644 index 00000000..1ffea09b --- /dev/null +++ b/chapter19/valid/initializers/string_in_struct.c @@ -0,0 +1,9 @@ +struct s { + char *str; + int *x; +}; + +int main() { + struct s my_struct = { "hello, world", 0}; + return my_struct.str[2] == 'l'; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/array_of_structs.c b/chapter19/valid/libraries/array_of_structs.c new file mode 100644 index 00000000..d6f9eed5 --- /dev/null +++ b/chapter19/valid/libraries/array_of_structs.c @@ -0,0 +1,15 @@ +#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; + if (struct_array[i].b.l != i * 3) + return i * 10; + if (struct_array[i].b.arr[0] != i * 4) + return i * 25; + if (struct_array[i].b.arr[1] != i * 5) + return i * 11; + } + return 0; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/array_of_structs.h b/chapter19/valid/libraries/array_of_structs.h new file mode 100644 index 00000000..2326ff52 --- /dev/null +++ b/chapter19/valid/libraries/array_of_structs.h @@ -0,0 +1,12 @@ +struct inner { + long l; + char arr[2]; +}; // size: 8 bytes, alignment: 4 bytes + +struct outer { + char a; // byte 0 + struct inner b; // bytes 4-11 + +}; // size: 12 byte, alignment: 4 bytes + +int validate_struct_array(struct outer *struct_array); \ No newline at end of file diff --git a/chapter19/valid/libraries/array_of_structs_client.c b/chapter19/valid/libraries/array_of_structs_client.c new file mode 100644 index 00000000..f84d9f67 --- /dev/null +++ b/chapter19/valid/libraries/array_of_structs_client.c @@ -0,0 +1,14 @@ +#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() { + struct outer auto_array[3] = { + {0, {0, {0, 0}}}, {2, {3, {4, 5}}}, {4, {6, {8, 10}}}}; + + int static_result = validate_struct_array(static_array); + if (static_result) + return static_result + 3; + return validate_struct_array(auto_array); +} \ No newline at end of file diff --git a/chapter19/valid/libraries/calling_conventions.c b/chapter19/valid/libraries/calling_conventions.c new file mode 100644 index 00000000..3c4f1319 --- /dev/null +++ b/chapter19/valid/libraries/calling_conventions.c @@ -0,0 +1,164 @@ +#include "classes.h" + +int pass_small_structs(struct two_xmm two_xmm_struct, struct one_int int_struct, + struct one_xmm xmm_struct, + struct xmm_and_int mixed_struct, + struct twelve_bytes int_struct_2, + struct one_int_exactly another_int_struct) { + if (two_xmm_struct.d[0] != 55.5 || two_xmm_struct.d[1] != 44.4) + return 1; + + if (int_struct.c != 'c' || int_struct.i != 54320) + return 2; + if (xmm_struct.d != 5.125) + return 3; + if (strcmp(mixed_struct.c, "hi") || mixed_struct.dbl.d != 1.234) + return 4; + if (strcmp(int_struct_2.arr, "string!") || int_struct_2.i != 123) + return 5; + + if (another_int_struct.l != 567890) + return 6; + + return 0; +} + +int structs_and_scalars(long l, double d, struct odd_size os, struct memory mem, + struct one_xmm xmm_struct) { + if (l != 10) + return 7; + if (d != 10.0) + return 8; + if (strcmp(os.arr, "lmno")) + return 9; + if (strcmp(mem.c, "rs") || mem.d != 15.75 || mem.i != 3333 || mem.l != 4444) + return 10; + if (xmm_struct.d != 5.125) + return 11; + + return 0; +} + +int struct_in_mem(double a, double b, double c, struct xmm_and_int first_struct, + double d, struct two_xmm second_struct, long l, + struct int_and_xmm third_struct, + struct one_xmm fourth_struct) { + if (a != 10.0 || b != 11.125 || c != 12.0) + return 12; + if (strcmp(first_struct.c, "hi") || first_struct.dbl.d != 1.234) + return 13; + if (d != 13.0) + return 14; + if (second_struct.d[0] != 55.5 || second_struct.d[1] != 44.4) + return 15; + if (l) + return 16; + if (third_struct.c != 'p' || third_struct.d != 4.56) + return 17; + if (fourth_struct.d != 5.125) + return 18; + + return 0; +} + +int pass_borderline_struct_in_memory(struct two_ints t_i, char c, + struct int_and_xmm i_x, void *ptr, + struct two_ints_nested t_i_n, double d) { + if (t_i.c != '_' || t_i.arr[0] != 5 || t_i.arr[1] != 6 || t_i.arr[2] != 7) + return 19; + if (c != '!') + return 20; + if (i_x.c != 'p' || i_x.d != 4.56) + return 21; + + if (ptr) + return 22; + + if (t_i_n.a.c != 'c' || t_i_n.a.i != 54320) + return 23; + if (t_i_n.b.c != 'c' || t_i_n.b.i != 54320) + return 24; + if (d != 7.8) + return 25; + return 0; +} + +struct one_int return_int_struct() { + struct one_int retval = {1, 2}; + return retval; +} + +struct twelve_bytes return_two_int_struct() { + struct twelve_bytes retval = {10, "12345678"}; + return retval; +} + +struct one_xmm return_double_struct() { + struct one_xmm retval = {100.625}; + return retval; +} +struct two_xmm return_two_double_struct() { + struct two_xmm retval = {{8.8, 7.8}}; + return retval; +} +struct xmm_and_int return_mixed() { + struct xmm_and_int retval = {{10.0}, "ab"}; + return retval; +} +struct int_and_xmm return_mixed2() { + struct int_and_xmm retval = {127, 34e43}; + return retval; +} +struct memory return_on_stack() { + struct memory retval = {1.25, "xy", 100l, 44}; + return retval; +} + +int f(char c, double d) { + + if (c == 'p' && d == 4.56) + return 0; + return 1; +} + +struct memory pass_and_return_regs(int i, double d, struct int_and_xmm strct, + char c, struct two_ints t_i, long l, + struct one_int_exactly o_i_e, char c2) { + // include stack variables to make sure they don't overwrite return value + // pointer or vice versa + int local1 = i * 2; + double local2 = d * 2; + struct memory retval = {0, {0, 0, 0}, 0, 0}; + + if (local1 != 12 || local2 != 8.0) { + retval.i = 1; + return retval; + } + int local3 = f(strct.c, strct.d); + if (local3) { + retval.i = 2; + return retval; + } + if (c != 5) { + retval.i = 3; + return retval; + } + if (t_i.c != '_' || t_i.arr[0] != 5 || t_i.arr[1] != 6 || t_i.arr[2] != 7) { + retval.i = 4; + return retval; + } + if (l != 77) { + retval.i = 5; + return retval; + } + if (o_i_e.l != 567890) { + retval.i = 6; + return retval; + } + if (c2 != 99) { + retval.i = 7; + return retval; + } + retval.l = 100; + return retval; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/calling_conventions_client.c b/chapter19/valid/libraries/calling_conventions_client.c new file mode 100644 index 00000000..f948fd62 --- /dev/null +++ b/chapter19/valid/libraries/calling_conventions_client.c @@ -0,0 +1,87 @@ +#include "classes.h" + +int main() { + struct one_int one_int = {54320, 'c'}; + struct one_int_exactly one_long = {567890l}; + struct two_ints two_ints = {'_', {5, 6, 7}}; + struct two_ints_nested two_ints_nested = {one_int, one_int}; + struct twelve_bytes xii = {123, "string!"}; + + struct one_xmm one_xmm = {5.125}; + struct two_xmm two_xmm = {{55.5, 44.4}}; + struct int_and_xmm int_and_xmm = {'p', 4.56}; + struct xmm_and_int xmm_and_int = {{1.234}, "hi"}; + + struct odd_size odd = {"lmno"}; + struct memory mem = {15.75, "rs", 4444, 3333}; + + int retval; + + // test parameter passing + + retval = + pass_small_structs(two_xmm, one_int, one_xmm, xmm_and_int, xii, one_long); + if (retval) { + return retval; + } + + retval = structs_and_scalars(10, 10.0, odd, mem, one_xmm); + if (retval) { + return retval; + } + + retval = struct_in_mem(10.0, 11.125, 12.0, xmm_and_int, 13.0, two_xmm, 0, + int_and_xmm, one_xmm); + if (retval) + return retval; + + retval = pass_borderline_struct_in_memory(two_ints, '!', int_and_xmm, 0, + two_ints_nested, 7.8); + if (retval) + return retval; + + // returning structures + + struct one_int s1 = return_int_struct(); + if (s1.i != 1 || s1.c != 2) { + return 26; + } + + struct twelve_bytes s2 = return_two_int_struct(); + if (s2.i != 10 || strncmp(s2.arr, "12345678", sizeof s2.arr)) + return 27; + + struct one_xmm s3 = return_double_struct(); + if (s3.d != 100.625) + return 28; + struct two_xmm s4 = return_two_double_struct(); + if (s4.d[0] != 8.8 || s4.d[1] != 7.8) + return 29; + + struct xmm_and_int s5 = return_mixed(); + if (s5.dbl.d != 10.0 || strcmp(s5.c, "ab")) + return 30; + + struct int_and_xmm s6 = return_mixed2(); + if (s6.c != 127 || s6.d != 34e43) + return 31; + + struct memory s7 = return_on_stack(); + if (s7.d != 1.25 || strcmp(s7.c, "xy") || s7.l != 100l || s7.i != 44) + return 32; + + s7 = pass_and_return_regs(6, 4.0, int_and_xmm, 5, two_ints, 77, one_long, 99); + // something was clobbered or set incorrectly in retval + if (s7.d || s7.c[0] || s7.c[1] || s7.c[2]) + return 33; + + // i was set to indicate problem w/ parameter passing + if (s7.i) + return 100 + s7.i; + + if (s7.l != 100) + return 34; // l field was clobbered or set incorrectly + + // success! + return 0; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/classes.h b/chapter19/valid/libraries/classes.h new file mode 100644 index 00000000..13f148d9 --- /dev/null +++ b/chapter19/valid/libraries/classes.h @@ -0,0 +1,93 @@ +int strcmp(char *s1, char *s2); +int strncmp(char *s1, char *s2, unsigned long n); + +struct one_int { + int i; + char c; +}; + +struct one_int_exactly { + unsigned long l; +}; + +struct two_ints { + char c; + int arr[3]; +}; + +struct two_ints_nested { + struct one_int a; + struct one_int b; +}; + +struct twelve_bytes { + int i; + char arr[8]; +}; + +struct one_xmm { + double d; +}; + +struct two_xmm { + double d[2]; +}; + +struct int_and_xmm { + char c; + double d; +}; + +struct xmm_and_int { + struct one_xmm dbl; + char c[3]; +}; + +struct odd_size { + char arr[5]; +}; + +struct memory { + double d; + char c[3]; + long l; + int i; +}; + +// passing structures as parameters + +// all arguments fit in registers +int pass_small_structs(struct two_xmm two_xmm_struct, struct one_int int_struct, + struct one_xmm xmm_struct, + struct xmm_and_int mixed_struct, + struct twelve_bytes int_struct_2, + struct one_int_exactly another_int_struct); + +// use remaining structure types, mix with scalars +int structs_and_scalars(long l, double d, struct odd_size os, struct memory mem, + struct one_xmm xmm_struct); + +// pass a structure in memory b/c we're out of registers +int struct_in_mem(double a, double b, double c, struct xmm_and_int first_struct, + double d, struct two_xmm second_struct, long l, + struct int_and_xmm third_struct, + struct one_xmm fourth_struct); +// pass two_ints_nested in memory b/c can't fit both eightbytes in quadword +int pass_borderline_struct_in_memory(struct two_ints t_i, char c, + struct int_and_xmm i_x, void *ptr, + struct two_ints_nested t_i_n, double d); + +// returning structures + +struct one_int return_int_struct(); +struct twelve_bytes return_two_int_struct(); +struct one_xmm return_double_struct(); +struct two_xmm return_two_double_struct(); +struct xmm_and_int return_mixed(); +struct int_and_xmm return_mixed2(); +struct memory return_on_stack(); + +// return on stack + pass other int params +struct memory pass_and_return_regs(int i, double d, struct int_and_xmm strct, + char c, struct two_ints t_i, long l, + struct one_int_exactly o_i_e, char c2); \ No newline at end of file diff --git a/chapter19/valid/libraries/global_struct.c b/chapter19/valid/libraries/global_struct.c new file mode 100644 index 00000000..a6003fe3 --- /dev/null +++ b/chapter19/valid/libraries/global_struct.c @@ -0,0 +1,8 @@ +#include "struct.h" + +extern struct s global; + +void update_struct() { + global.arr[1] = global.arr[0]*2; + global.d = 5.0; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/global_struct_client.c b/chapter19/valid/libraries/global_struct_client.c new file mode 100644 index 00000000..782b7d6b --- /dev/null +++ b/chapter19/valid/libraries/global_struct_client.c @@ -0,0 +1,10 @@ +#include "struct.h" + +struct s global = { 1, {2, 3}, 4.0}; + +void update_struct(); + +int main() { + update_struct(); + return global.arr[1] + global.d; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/incomplete_var.c b/chapter19/valid/libraries/incomplete_var.c new file mode 100644 index 00000000..be5f8963 --- /dev/null +++ b/chapter19/valid/libraries/incomplete_var.c @@ -0,0 +1,12 @@ +struct s { + int i; +}; +static struct s internal = {2}; + +struct s *get_struct_pointer() { + return &internal; +} + +int use_struct_pointers(struct s *ptr, struct s *ptr2) { return ptr->i + ptr2->i;} + +struct s incomplete_var = {3}; diff --git a/chapter19/valid/libraries/incomplete_var_client.c b/chapter19/valid/libraries/incomplete_var_client.c new file mode 100644 index 00000000..8d7828fb --- /dev/null +++ b/chapter19/valid/libraries/incomplete_var_client.c @@ -0,0 +1,9 @@ +struct s; +struct s *get_struct_pointer(); +int use_struct_pointers(struct s *ptr, struct s *ptr2); +extern struct s incomplete_var; + +int main() { + struct s *ptr = get_struct_pointer(); + return use_struct_pointers(&incomplete_var, ptr); +} \ No newline at end of file diff --git a/chapter19/valid/libraries/initializers.c b/chapter19/valid/libraries/initializers.c new file mode 100644 index 00000000..5ad74f8c --- /dev/null +++ b/chapter19/valid/libraries/initializers.c @@ -0,0 +1,46 @@ +#include "initializers.h" + +struct inner basic = {1.0, "hi", {9, 8, 7}}; +struct inner partial_init = {2.0, "bye"}; + +struct outer complex_partial_init = { + 0, 100000l, {{98.0}, {100.0, "nested_string", "ab"}}}; + +int validate_partial_auto(struct inner *partial) { + if (partial->d != 55.55 || partial->str || partial->arr[0] || + partial->arr[1] || partial->arr[2]) + return 1; + // we succeeded! + return 0; +} + +int validate_non_static(struct inner *basic_auto, struct inner *basic_auto2, + struct outer *complex_auto) { + // validate first param + if (basic_auto->d != -55.55 || strcmp(basic_auto->str, "foo") || + basic_auto->arr[0] != 'x' || basic_auto->arr[1] != 'y' || + basic_auto->arr[2] != 'z') + return 7; + + // validate second param, should be identical to first + // str field should have same address, not just same contents + if (basic_auto2->d != -55.55 || basic_auto->str != basic_auto2->str || + basic_auto2->arr[0] != 'x' || basic_auto2->arr[1] != 'y' || + basic_auto2->arr[2] != 'z') + return 8; + + // validate third param + if (validate_partial_auto(complex_auto->x)) + return 9; + + if (validate_partial_auto(complex_auto->struct_array)) + return 10; + + if (complex_auto->struct_array[1].d || complex_auto->struct_array[1].str || + complex_auto->struct_array[1].arr[0] || + complex_auto->struct_array[1].arr[1] || + complex_auto->struct_array[1].arr[2]) + return 11; + + return 0; +} diff --git a/chapter19/valid/libraries/initializers.h b/chapter19/valid/libraries/initializers.h new file mode 100644 index 00000000..67069c85 --- /dev/null +++ b/chapter19/valid/libraries/initializers.h @@ -0,0 +1,25 @@ +// test out various forms of iniitalization; +// make sure results are at correct offset + +int strcmp(char *s1, char *s2); + +struct inner { + double d; + char *str; + char arr[3]; +}; + +struct outer { + struct inner *x; + long l; + struct inner struct_array[2]; +}; + +// static initializers +extern struct inner basic; +extern struct inner partial_init; + +extern struct outer complex_partial_init; + +int validate_non_static(struct inner *basic_auto, struct inner *basic_auto2, + struct outer *complex_auto); diff --git a/chapter19/valid/libraries/initializers_client.c b/chapter19/valid/libraries/initializers_client.c new file mode 100644 index 00000000..717009f3 --- /dev/null +++ b/chapter19/valid/libraries/initializers_client.c @@ -0,0 +1,61 @@ +#include "initializers.h" + +char *get_string() { return "foo"; } + +// validate static/global variables defined in the other file +int validate_static() { + // first validate basic + if (basic.d != 1.0 || strcmp(basic.str, "hi")) + return 1; + if (basic.arr[0] != 9 || basic.arr[1] != 8 || basic.arr[2] != 7) + return 2; + // now validate partial_init + if (partial_init.d != 2.0 || strcmp(partial_init.str, "bye") || + // array elements should be 0 b/c not explicitly initialized + partial_init.arr[0] || partial_init.arr[1] || partial_init.arr[2]) + return 3; + + // validate complex_partial_init + if (complex_partial_init.x || complex_partial_init.l != 100000l) + return 4; + + // validate first inner struct + if (complex_partial_init.struct_array[0].d != 98.0 || + complex_partial_init.struct_array[0].str || + complex_partial_init.struct_array[0].arr[0] || + complex_partial_init.struct_array[0].arr[1] || + complex_partial_init.struct_array[0].arr[2]) + return 5; + + // validate second inner struct + if (complex_partial_init.struct_array[1].d != 100.0 || + strcmp(complex_partial_init.struct_array[1].str, "nested_string") || + complex_partial_init.struct_array[1].arr[0] != 'a' || + complex_partial_init.struct_array[1].arr[1] != 'b' || + complex_partial_init.struct_array[1].arr[2]) + return 6; + + // we succeeded! + return 0; +} + +int main() { + + int static_result = validate_static(); + if (static_result) { + return static_result; + } + + // define some structs with automatic storage duration, + // then have other translation unit validate them + // make sure to use non-constant expressions in this + double x = 55.55; + struct inner basic_auto = {-x, get_string(), "xyz"}; + struct inner basic_auto_copy = basic_auto; + double *dbl_ptr = &x; + struct inner partial_auto = {*dbl_ptr}; + + struct outer complex = {&partial_auto, (long)x, {partial_auto}}; + + return validate_non_static(&basic_auto, &basic_auto_copy, &complex); +} diff --git a/chapter19/valid/libraries/missing_retval.c b/chapter19/valid/libraries/missing_retval.c new file mode 100644 index 00000000..de5e1a40 --- /dev/null +++ b/chapter19/valid/libraries/missing_retval.c @@ -0,0 +1,5 @@ +#include "missing_retval.h" + +struct big missing_return_value(int *i) { + *i = 10; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/missing_retval.h b/chapter19/valid/libraries/missing_retval.h new file mode 100644 index 00000000..f3512c12 --- /dev/null +++ b/chapter19/valid/libraries/missing_retval.h @@ -0,0 +1,8 @@ +struct big { + char arr[25]; +}; + +// make sure we correctly handle calls to functions with return values +// passed on stack, even if return statement is missing, +// as long as caller doesn't use return value +struct big missing_return_value(int *i); \ No newline at end of file diff --git a/chapter19/valid/libraries/missing_retval_client.c b/chapter19/valid/libraries/missing_retval_client.c new file mode 100644 index 00000000..746c84be --- /dev/null +++ b/chapter19/valid/libraries/missing_retval_client.c @@ -0,0 +1,7 @@ +#include "missing_retval.h" + +int main() { + int array[4] = {1, 2, 3, 4}; + missing_return_value(array + 2); + return array[2] == 10; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/nested_pointer_access.c b/chapter19/valid/libraries/nested_pointer_access.c new file mode 100644 index 00000000..c25b523f --- /dev/null +++ b/chapter19/valid/libraries/nested_pointer_access.c @@ -0,0 +1,26 @@ +#include "nested_pointer_access.h" + +int validate(struct outer *outer_ptr) { + if (outer_ptr->middle_ptr->c != 99) + return 1; + struct inner i = outer_ptr->middle_ptr->inner_member; + if (i.c != 11 || i.d != 77.0) + return 2; + + struct outer outer_val = *outer_ptr; + // middle_ptr in both structs point to same value + outer_ptr->middle_ptr->c = 4; + struct inner i2 = {33.3, 3}; + outer_val.middle_ptr->inner_member = i2; + + if (outer_val.middle_ptr->c != 4) + return 3; + + if (outer_ptr->middle_ptr->inner_member.d != 33.3) + return 4; + + if (outer_val.middle_ptr->inner_member.c != 3) + return 5; + + return 0; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/nested_pointer_access.h b/chapter19/valid/libraries/nested_pointer_access.h new file mode 100644 index 00000000..eb593b8a --- /dev/null +++ b/chapter19/valid/libraries/nested_pointer_access.h @@ -0,0 +1,18 @@ +struct inner { + double d; + char c; +}; + +struct middle { + char c; + struct inner inner_member; +}; + +struct outer { + + struct middle middle_member; + struct middle *middle_ptr; +}; + +int validate(struct outer *outer_ptr); +void *malloc(unsigned long size); \ No newline at end of file diff --git a/chapter19/valid/libraries/nested_pointer_access_client.c b/chapter19/valid/libraries/nested_pointer_access_client.c new file mode 100644 index 00000000..3e60ed66 --- /dev/null +++ b/chapter19/valid/libraries/nested_pointer_access_client.c @@ -0,0 +1,13 @@ +#include "nested_pointer_access.h" + +int main() { + struct outer *o = malloc(sizeof(struct outer)); + o->middle_ptr = malloc(sizeof(struct middle)); + o->middle_ptr->c = 99; + struct inner inner = {77.0, 11}; + o->middle_ptr->inner_member = inner; + o->middle_member.inner_member.c = 0; + o->middle_member.inner_member.d = 0; + + return validate(o); +} \ No newline at end of file diff --git a/chapter19/valid/libraries/pass_struct.c b/chapter19/valid/libraries/pass_struct.c new file mode 100644 index 00000000..45cd02e9 --- /dev/null +++ b/chapter19/valid/libraries/pass_struct.c @@ -0,0 +1,8 @@ +struct pair { + int x; + int y; +}; + +int foo(struct pair p) { + return p.x + 1; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/pass_struct_client.c b/chapter19/valid/libraries/pass_struct_client.c new file mode 100644 index 00000000..24c6b66e --- /dev/null +++ b/chapter19/valid/libraries/pass_struct_client.c @@ -0,0 +1,11 @@ +struct pair { + int x; + int y; +}; + +int foo(struct pair p); + +int main() { + struct pair arg = { 1, 2}; + return foo(arg); +} \ No newline at end of file diff --git a/chapter19/valid/libraries/pass_wonky_struct.c b/chapter19/valid/libraries/pass_wonky_struct.c new file mode 100644 index 00000000..f7f41844 --- /dev/null +++ b/chapter19/valid/libraries/pass_wonky_struct.c @@ -0,0 +1,13 @@ +#include "pass_wonky_struct.h" + +// make sure we can successfully pass and return structures on the stack +// whose size is not exactly divisible by 8 +// (e.g. returning won't clobber neighboring stack values) + +struct wonky change_struct(struct wonky arg) { + char *arr = arg.arr; + arr[0] = 1; + arr[6] = 6; + arr[17] = -1; + return arg; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/pass_wonky_struct.h b/chapter19/valid/libraries/pass_wonky_struct.h new file mode 100644 index 00000000..6f184a73 --- /dev/null +++ b/chapter19/valid/libraries/pass_wonky_struct.h @@ -0,0 +1,6 @@ +// larger than 16 bytes but size is not divisible by 8 bytes +struct wonky { + char arr[19]; +}; + +struct wonky change_struct(struct wonky arg); \ No newline at end of file diff --git a/chapter19/valid/libraries/pass_wonky_struct_client.c b/chapter19/valid/libraries/pass_wonky_struct_client.c new file mode 100644 index 00000000..a7094ed5 --- /dev/null +++ b/chapter19/valid/libraries/pass_wonky_struct_client.c @@ -0,0 +1,22 @@ +#include "pass_wonky_struct.h" + +int main() { + // because this is static, it will be initialized to all zeros + static struct wonky all_zeros; + + struct wonky modified = change_struct(all_zeros); + if (modified.arr[0] != 1) + return 100; + if (modified.arr[6] != 6) + return 101; + if (modified.arr[17] != -1) + return 102; + for (int i = 0; i < 14; i = i + 1) { + if (i == 0 || i == 6 || i == 13) + continue; + if (modified.arr[i] != 0) + return i; + } + + return 0; +} \ No newline at end of file diff --git a/chapter19/valid/libraries/struct.h b/chapter19/valid/libraries/struct.h new file mode 100644 index 00000000..316e62b1 --- /dev/null +++ b/chapter19/valid/libraries/struct.h @@ -0,0 +1,5 @@ +struct s { + int i; + char arr[2]; + double d; +}; \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/addr_of_arrow.c b/chapter19/valid/member_access_tests/addr_of_arrow.c new file mode 100644 index 00000000..411d6ac4 --- /dev/null +++ b/chapter19/valid/member_access_tests/addr_of_arrow.c @@ -0,0 +1,10 @@ +struct pair { int x ; int y; }; + +void *malloc(unsigned long size); + +int main() { + struct pair *s = malloc(sizeof(struct pair)); + s->x = 10; + int *ptr = &(s->x); + return *ptr; +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/aggregate_through_arrow.c b/chapter19/valid/member_access_tests/aggregate_through_arrow.c new file mode 100644 index 00000000..14c63169 --- /dev/null +++ b/chapter19/valid/member_access_tests/aggregate_through_arrow.c @@ -0,0 +1,54 @@ +// test out using/assigning aggregate values through -> pointer + +struct inner { + signed char a; + signed char b; + signed char c; +}; + +struct outer { + struct inner substruct; + signed char x; + signed char y; +}; + +struct outermost { + struct outer nested; + int i; +}; + +void *malloc(unsigned long size); + +int main() { + struct outer *outer_pointer = malloc(sizeof(struct outer)); + outer_pointer->x = 0; + outer_pointer->y = 0; + + struct inner small = {6, 7, 8}; + + outer_pointer->substruct = small; + if (outer_pointer->substruct.a != 6 || outer_pointer->substruct.b != 7 || + outer_pointer->substruct.c != 8 || outer_pointer->x || outer_pointer->y) + return 1; + + // add another layer of nesting + struct outermost *outermost_pointer = malloc(sizeof(struct outermost)); + outermost_pointer->i = 0; + outermost_pointer->nested.substruct = small; + outermost_pointer->nested.x = -1; + outermost_pointer->nested.y = -2; + + struct outer copied_from_pointer = outermost_pointer->nested; + struct inner copied_nested_pointer = outermost_pointer->nested.substruct; + + if (copied_from_pointer.x != -1 || copied_from_pointer.y != -2 || + copied_from_pointer.substruct.a != 6 || + copied_from_pointer.substruct.b != 7 || + copied_from_pointer.substruct.c != 8) + return 2; + + if (copied_nested_pointer.a != 6 || copied_nested_pointer.b != 7 || + copied_nested_pointer.c != 8) + return 3; + return 0; +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/assign_to_struct.c b/chapter19/valid/member_access_tests/assign_to_struct.c new file mode 100644 index 00000000..76835ae0 --- /dev/null +++ b/chapter19/valid/member_access_tests/assign_to_struct.c @@ -0,0 +1,7 @@ +struct pair { int x ; int y; }; + +int main() { + struct pair s; + s.x = 10; + return s.x; +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/assign_to_struct_pointer.c b/chapter19/valid/member_access_tests/assign_to_struct_pointer.c new file mode 100644 index 00000000..8e536b58 --- /dev/null +++ b/chapter19/valid/member_access_tests/assign_to_struct_pointer.c @@ -0,0 +1,9 @@ +struct pair { int x ; int y; }; + +void *malloc(unsigned long size); + +int main() { + struct pair *s = malloc(sizeof(struct pair)); + s->x = 10; + return s->x; +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/copy_from_pointer.c b/chapter19/valid/member_access_tests/copy_from_pointer.c new file mode 100644 index 00000000..d5963f42 --- /dev/null +++ b/chapter19/valid/member_access_tests/copy_from_pointer.c @@ -0,0 +1,31 @@ +struct inner { + char a; + char b; +}; + +struct middle { + double d; + struct inner i; +}; + +struct outer { + struct middle m; + long l; +}; + +struct outer global_struct; + +void *malloc(unsigned long size); + +int main() { + struct outer *local_struct = (struct outer *) malloc(sizeof(struct outer)); + local_struct->l = 100; + local_struct->m.d == 1.0; + local_struct->m.i.a = 9; + local_struct->m.i.b = 10; + global_struct = *local_struct; + return (global_struct.l == 100 + && global_struct.m.d == 1.0 + && global_struct.m.i.a == 9 + && global_struct.m.i.b == 10); +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/copy_to_pointer.c b/chapter19/valid/member_access_tests/copy_to_pointer.c new file mode 100644 index 00000000..6e752cd3 --- /dev/null +++ b/chapter19/valid/member_access_tests/copy_to_pointer.c @@ -0,0 +1,25 @@ +struct inner { + char a; + char b; +}; + +struct middle { + double d; + struct inner i; +}; + +struct outer { + struct middle m; + long l; +}; + +struct outer global_struct = {{1.0, {9, 10}}, 100}; + +void *malloc(unsigned long size); + +int main() { + struct outer *local_struct = (struct outer *)malloc(sizeof(struct outer)); + *local_struct = global_struct; + return (local_struct->l == 100 && local_struct->m.d == 1.0 && + local_struct->m.i.a == 9 && local_struct->m.i.b == 10); +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/deref_arrow.c b/chapter19/valid/member_access_tests/deref_arrow.c new file mode 100644 index 00000000..cf41882e --- /dev/null +++ b/chapter19/valid/member_access_tests/deref_arrow.c @@ -0,0 +1,15 @@ +struct pair { + double d; + char *c_ptr; +}; + +void update_char(struct pair *p) { + *p->c_ptr = 3; +} + +int main() { + char c = 5; + struct pair p = { 4.6, &c }; + update_char(&p); + return c; +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/get_array_through_pointer.c b/chapter19/valid/member_access_tests/get_array_through_pointer.c new file mode 100644 index 00000000..c18701ae --- /dev/null +++ b/chapter19/valid/member_access_tests/get_array_through_pointer.c @@ -0,0 +1,13 @@ +void *malloc(unsigned long size); + +struct struct_with_array { + int x; + double arr[3]; +}; + +int main() { + struct struct_with_array *s = malloc(sizeof(struct struct_with_array)); + double *d = s->arr; + s->arr[2] = 4.5; + return (d[2] == 4.5); +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/get_member_addresses.c b/chapter19/valid/member_access_tests/get_member_addresses.c new file mode 100644 index 00000000..eb637e97 --- /dev/null +++ b/chapter19/valid/member_access_tests/get_member_addresses.c @@ -0,0 +1,107 @@ +// test applying & to members accessed through . operator, +// and make sure structs are laid out correctly + +// need three bytes of padding so it's four-byte aligned, +// total size is eight +struct eightbyte { + int i; + char c; +}; // four byte-aligned + +struct twobyte { + char twochars[2]; +}; // one byte-aligned + +struct threebyte { + char threechars[3]; +}; // one byte-aligned + +struct big { + struct eightbyte eightbyte_1; // bytes 0-7 + struct twobyte twobyte_2; // bytes 8-9 + struct threebyte threebyte_3; // bytes 10-12 +}; // total size is 16 b/c it's fourbyte aligned + +struct medium { + struct twobyte twobyte_1; // bytes 0-1 + struct threebyte threebyte_2; // bytes 2-4 + struct twobyte twobyte_3; // bytes 5-6 +}; // total size is 7 bytes, alignment if 1 byte + +struct biggest { + struct medium medium_1; // bytes 0-7 + struct big big_2; // bytes 8-24 (four-byte aligned) +}; // four byte alignment + +struct medium_big { + struct big big_1; // bytes 0-16 + struct twobyte twobyte_2; // bytes 17-18 +}; // 20 bytes b/c it's four-byte aligned + +int main() { + // declare some static arrays of structs + static struct medium_big x; + + // x must be four-byte aligned + // (in our implementation should be eight byte aligned + // to simplify parameter passing, but ABI doesn't require it) + if ((unsigned long)&x % 4) + return 10; + + if ((void *)&x.big_1 != (void *)&x || + (void *)&x.big_1.eightbyte_1 != (void *)&x.big_1 || + (void *)&x.big_1.eightbyte_1.i != (void *)&x) + return 1; + + if ((char *)&x.big_1.eightbyte_1.c - (char *)&x != 4) + return 2; + + if ((char *)&x.big_1.twobyte_2 - (char *)&x != 8) + return 3; + + if ((void *)&x.big_1.twobyte_2 != &x.big_1.twobyte_2.twochars) + return 4; + + if ((void *)&x.big_1.twobyte_2 != &x.big_1.twobyte_2.twochars[0]) + return 5; + + if ((char *)&x.big_1.twobyte_2.twochars[1] - + (char *)&x.big_1.twobyte_2.twochars != + 1) + return 6; + + if ((void *)&x.big_1.threebyte_3 != (void *)&x.big_1.threebyte_3.threechars) + return 7; + + // try one-past-the-end arithmetic + // no padding b/t big_1 and twobyte_2 + if ((void *)(&x.big_1 + 1) != (void *)&x.twobyte_2) + return 8; + + if ((void *)(&x.twobyte_2) != (void *)&x.twobyte_2.twochars || + (void *)(&x.twobyte_2) != (void *)(&x.twobyte_2.twochars[0])) + return 9; + + if (&x.twobyte_2.twochars[1] - (char *)&x.twobyte_2.twochars != 1) + return 11; + + // one-past-the-end arithmetic - should be two bytes of padding b/t end of + // twochars and end of struct + if ((char *)(&x + 1) - (char *)(&x.twobyte_2 + 1) != 2) + return 12; + + // now try a non-static variable + struct biggest y; + if ((void *)&y != (void *)&y.medium_1 || + (void *)&y != (void *)&y.medium_1.twobyte_1 || + (void *)&y != (void *)&y.medium_1.twobyte_1.twochars) + return 13; + + if ((char *)&y.medium_1.threebyte_2 - (char *)&y.medium_1 != 2) + return 14; + + if ((char *)(&y.medium_1 + 1) - (char *)&y.medium_1.twobyte_3 != 2) + return 15; + + return 0; +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/global_nested_struct.c b/chapter19/valid/member_access_tests/global_nested_struct.c new file mode 100644 index 00000000..1ba55ee2 --- /dev/null +++ b/chapter19/valid/member_access_tests/global_nested_struct.c @@ -0,0 +1,18 @@ +struct inner { + int a; + int b; +}; + +struct outer { + char c; + struct inner i; +}; + +struct outer o; + +int main() { + struct inner i = {7, 8}; + o.c = 1; + o.i = i; + return o.i.b; +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/global_struct.c b/chapter19/valid/member_access_tests/global_struct.c new file mode 100644 index 00000000..ed1b9ce2 --- /dev/null +++ b/chapter19/valid/member_access_tests/global_struct.c @@ -0,0 +1,12 @@ +struct pair { double x; double y; }; +static struct pair foo; + +void set_foo(double a, double b) { + foo.x = a; + foo.y = b; +} + +int main() { + set_foo(8.0, 7.0); + return foo.y; +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/linked_list.c b/chapter19/valid/member_access_tests/linked_list.c new file mode 100644 index 00000000..f33a261d --- /dev/null +++ b/chapter19/valid/member_access_tests/linked_list.c @@ -0,0 +1,29 @@ +void *malloc(unsigned long size); + +struct node { + int val; + struct node *next; +}; + +struct node *array_to_list(int *array, int count) { + struct node *head = (struct node *) malloc(sizeof(struct node)); + head->val = array[0]; + struct node *current = head; + for (int i = 1; i < count; i = i + 1) { + current->next = (struct node *) malloc(sizeof(struct node)); + current->next->val = array[i]; + current = current->next; + } + return head; +} + +int main() { + int arr[4] = {9, 8, 7, 6}; + struct node *elem = array_to_list(arr,4); + int sum = 0; + for (int i = 0; i < 4; i = i + 1) { + sum = sum + elem->val; + elem = elem->next; + } + return sum; +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/nested_address_calculations.c b/chapter19/valid/member_access_tests/nested_address_calculations.c new file mode 100644 index 00000000..17d11ada --- /dev/null +++ b/chapter19/valid/member_access_tests/nested_address_calculations.c @@ -0,0 +1,40 @@ +struct inner { + double d; + char c; +}; + +struct middle { + + struct inner inner_member; + struct middle *self_ptr; +}; + +struct outer { + struct middle *middle_ptr; + struct middle middle_member; +}; + +int main() { + static struct inner i = {5e41, 'x'}; + + struct middle m = {i, &m}; + struct outer o = {&m, m}; + + // o.middle_ptr is address of m, so &o.middle_ptr->self_ptr is address of + // second member of m + if ((char *)&o.middle_ptr->self_ptr != ((char *)&m + sizeof(struct inner))) + return 1; + + struct middle *mid_ptr = o.middle_ptr; + + // mid_ptr points to m; m->inner_member.c is second scalar in m + // right after double 'd' in nested struct + if ((char *)&mid_ptr->inner_member.c != ((char *)&m + sizeof(double))) + return 2; + + if ((char *)&mid_ptr->self_ptr->self_ptr != + ((char *)&m + sizeof(struct inner))) + return 3; + + return 0; +} diff --git a/chapter19/valid/member_access_tests/nested_struct.c b/chapter19/valid/member_access_tests/nested_struct.c new file mode 100644 index 00000000..33ef32ce --- /dev/null +++ b/chapter19/valid/member_access_tests/nested_struct.c @@ -0,0 +1,19 @@ +struct inner { + double a; + char b; +}; + +struct outer { + struct inner foo; + int bar; +}; + +int main() { + struct outer s; + s.foo.a = 1.0; + s.foo.b = 2; + s.bar = 10; + struct inner i = s.foo; + i.a = 5.0; + return s.foo.a + i.a + s.bar; +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/non_static_struct.c b/chapter19/valid/member_access_tests/non_static_struct.c new file mode 100644 index 00000000..9210ade0 --- /dev/null +++ b/chapter19/valid/member_access_tests/non_static_struct.c @@ -0,0 +1,17 @@ +struct pair { + int x; + int y; +}; + +int foo() { + struct pair p = { 9, 8 }; + p.y = p.y + 1; + return p.y; +} + +int main() { + for (int i = 0; i < 10; i = i + 1) { + foo(); + } + return foo(); +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/pointer_to_struct.c b/chapter19/valid/member_access_tests/pointer_to_struct.c new file mode 100644 index 00000000..d623f119 --- /dev/null +++ b/chapter19/valid/member_access_tests/pointer_to_struct.c @@ -0,0 +1,13 @@ +void *malloc(unsigned long size); + +struct pair { + unsigned long first_tag; + int second_tag; +}; + +int main() { + struct pair *ptr = (struct pair *) malloc(sizeof(struct pair)); + ptr->second_tag = 3; + ptr->first_tag = -1; + return (ptr->first_tag - ptr->second_tag == 18446744073709551612ul); +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/static_struct.c b/chapter19/valid/member_access_tests/static_struct.c new file mode 100644 index 00000000..4e085e3e --- /dev/null +++ b/chapter19/valid/member_access_tests/static_struct.c @@ -0,0 +1,17 @@ +struct pair { + int x; + int y; +}; + +int foo() { + struct pair static p = { 9, 8 }; + p.y = p.y + 1; + return p.y; +} + +int main() { + for (int i = 0; i < 10; i = i + 1) { + foo(); + } + return foo(); +} \ No newline at end of file diff --git a/chapter19/valid/member_access_tests/struct.c b/chapter19/valid/member_access_tests/struct.c new file mode 100644 index 00000000..3689cd65 --- /dev/null +++ b/chapter19/valid/member_access_tests/struct.c @@ -0,0 +1,10 @@ +struct pair { + int x; + double y; +}; + +int main() { + struct pair p; + p.x = 1; + return p.x; +} \ No newline at end of file diff --git a/chapter19/valid/misc_typecheck/cast_struct_to_void.c b/chapter19/valid/misc_typecheck/cast_struct_to_void.c new file mode 100644 index 00000000..cddb5a25 --- /dev/null +++ b/chapter19/valid/misc_typecheck/cast_struct_to_void.c @@ -0,0 +1,13 @@ +struct s { + int x; +}; +struct s glob = {0}; +struct s f() { + glob.x = glob.x + 1; + return glob; +} +int main() { + (void)f(); + (void)f(); + return glob.x; +} \ No newline at end of file diff --git a/chapter19/valid/misc_typecheck/conditional_struct.c b/chapter19/valid/misc_typecheck/conditional_struct.c new file mode 100644 index 00000000..0bfcc4f4 --- /dev/null +++ b/chapter19/valid/misc_typecheck/conditional_struct.c @@ -0,0 +1,19 @@ +// can use complete structs in conditional expressions + +int flag() { + static int result = 0; + int retval = result; + result = result + 1; + return retval; +} + +int main() { + struct s { + int x; + }; + struct s a = {10}; + struct s b = {11}; + int first = (flag() ? a : b).x; + int second = (flag() ? a : b).x; + return (first == 11 && second == 10); +} \ No newline at end of file diff --git a/chapter19/valid/misc_typecheck/temporary_lifetime.c b/chapter19/valid/misc_typecheck/temporary_lifetime.c new file mode 100644 index 00000000..8be74b74 --- /dev/null +++ b/chapter19/valid/misc_typecheck/temporary_lifetime.c @@ -0,0 +1,25 @@ +// a non-lvalue structure that contains an array +// has temporary lifetime; +// you can get the array's address implicitly (but not explicitly) +// NB modifying an array w/ temporary lifetime is undefined + +struct inner { + int a; + int b; +}; + +struct contains_array { + struct inner array[4]; +}; + +struct contains_array get_struct() { + struct inner obj = {1, 2}; + struct inner obj2 = {3, 4}; + struct contains_array result = {{obj, obj2, obj}}; + return result; +} + +int main() { + int i = get_struct().array[2].a; + return i; +} \ No newline at end of file diff --git a/chapter19/valid/parse_and_lex/postfix_precedence.c b/chapter19/valid/parse_and_lex/postfix_precedence.c new file mode 100644 index 00000000..d0f6960c --- /dev/null +++ b/chapter19/valid/parse_and_lex/postfix_precedence.c @@ -0,0 +1,19 @@ +// postfix operators have higher precedence than prefix +struct inner { + int inner_arr[3]; +}; + +struct outer { + int a; + struct inner b; +}; + +int main() { + struct outer array[4] = {{1, {{2, 3, 4}}}, + {5, {{6, 7, 8}}}, + {9, {{10, 11, 12}}}, + {13, {{14, 15, 16}}}}; + + int i = -array[2].b.inner_arr[1]; + return i == -11; +} \ No newline at end of file diff --git a/chapter19/valid/parse_and_lex/space_around_struct_member.c b/chapter19/valid/parse_and_lex/space_around_struct_member.c new file mode 100644 index 00000000..ac39a1bc --- /dev/null +++ b/chapter19/valid/parse_and_lex/space_around_struct_member.c @@ -0,0 +1,12 @@ +struct s { + int a; +}; +int main() { + // struct member operator (.) can be separate by whitespace from + // both struct and field name + struct s foo; + foo. a=10; + int b = foo .a ; + + return foo . a == b; +} \ No newline at end of file diff --git a/chapter19/valid/parse_and_lex/struct_member_looks_like_const.c b/chapter19/valid/parse_and_lex/struct_member_looks_like_const.c new file mode 100644 index 00000000..0a48b2c8 --- /dev/null +++ b/chapter19/valid/parse_and_lex/struct_member_looks_like_const.c @@ -0,0 +1,8 @@ +struct s { + int E10; +}; + +int main() { + struct s x1 = {3}; + return x1.E10; // lex correctly, recognizing that 1.E10 is not a constant +} diff --git a/chapter19/valid/scoping_tests/declare_struct.c b/chapter19/valid/scoping_tests/declare_struct.c new file mode 100644 index 00000000..a61ab2a4 --- /dev/null +++ b/chapter19/valid/scoping_tests/declare_struct.c @@ -0,0 +1,9 @@ +int main() { + struct pair { + int x; + double y; + }; + struct pair p; + p.x = 1; + return p.x; +} \ No newline at end of file diff --git a/chapter19/valid/scoping_tests/different_namespaces_same_ids.c b/chapter19/valid/scoping_tests/different_namespaces_same_ids.c new file mode 100644 index 00000000..7af8c9f9 --- /dev/null +++ b/chapter19/valid/scoping_tests/different_namespaces_same_ids.c @@ -0,0 +1,10 @@ +// variables, structure tags, and struct members are all in different namespaces +// so it's okay for them to have the same IDs + +struct x { + int x; +}; + +struct x x = {10}; + +int main() { return x.x; } \ No newline at end of file diff --git a/chapter19/valid/scoping_tests/resolve_tag_for_loop_decl.c b/chapter19/valid/scoping_tests/resolve_tag_for_loop_decl.c new file mode 100644 index 00000000..d68221d0 --- /dev/null +++ b/chapter19/valid/scoping_tests/resolve_tag_for_loop_decl.c @@ -0,0 +1,12 @@ +struct s; +int main() { + struct s { + int a; + }; + int count = 0; + // make sure we can handle struct declarations in for loop headers + for (struct s init = {10}; init.a > 0; init.a = init.a - 1) { + count = count + 1; + } + return count; +} \ No newline at end of file diff --git a/chapter19/valid/scoping_tests/resolve_tag_sizeof.c b/chapter19/valid/scoping_tests/resolve_tag_sizeof.c new file mode 100644 index 00000000..f2660573 --- /dev/null +++ b/chapter19/valid/scoping_tests/resolve_tag_sizeof.c @@ -0,0 +1,14 @@ +int main() { + struct s { + int a; + int b; + }; + struct s x; // x is an eight-byte struct + { + struct s { + char arr[15]; + }; // declare a 15-byte struct type + // in this scope, 'x' has outer type but specifier refers to inner type + return (sizeof x == 8 && sizeof(struct s) == 15); + } +} \ No newline at end of file diff --git a/chapter19/valid/scoping_tests/resolve_tags_derived_types.c b/chapter19/valid/scoping_tests/resolve_tags_derived_types.c new file mode 100644 index 00000000..7db6283a --- /dev/null +++ b/chapter19/valid/scoping_tests/resolve_tags_derived_types.c @@ -0,0 +1,26 @@ +// make sure we correctly resolve structure tags in derived types + +void *malloc(unsigned long size); + +struct s { + int a; +}; + +int main() { + // pointer to array of three pointers to s + struct s *(*outer_arr)[3] = malloc(sizeof(void *) * 3); + struct s outer_struct = {1}; + struct s { + int x; + }; + struct s inner_struct = {2}; + struct s *(*inner_arr)[3] = malloc(sizeof(void *) * 3); + + outer_arr[0][0] = &outer_struct; + outer_arr[0][1] = &outer_struct; + + inner_arr[0][0] = &inner_struct; + inner_arr[0][2] = &inner_struct; + + return outer_arr[0][0]->a == 1 && inner_arr[0][0]->x == 2; +} \ No newline at end of file diff --git a/chapter19/valid/scoping_tests/same_tag_name.c b/chapter19/valid/scoping_tests/same_tag_name.c new file mode 100644 index 00000000..e37782fe --- /dev/null +++ b/chapter19/valid/scoping_tests/same_tag_name.c @@ -0,0 +1,15 @@ +struct pair1 { + int x; + int *y; +}; + +struct pair2 { + void *x; + double y[4]; +}; + +int main() { + struct pair1 p1 = { 3, &(p1.x) }; + struct pair2 p2 = { &p1, {1.0, 2.0, 3.0, 4.0} }; + return *p1.y + p2.y[1] + ((struct pair1 *)p2.x)->x; +} \ No newline at end of file diff --git a/chapter19/valid/scoping_tests/same_tag_name_simple.c b/chapter19/valid/scoping_tests/same_tag_name_simple.c new file mode 100644 index 00000000..86c4c6ae --- /dev/null +++ b/chapter19/valid/scoping_tests/same_tag_name_simple.c @@ -0,0 +1,15 @@ +struct pair1 { + int x; + int y; +}; + +struct pair2 { + double x; + char y; +}; + +int main() { + struct pair1 p1 = { 1, 2}; + struct pair2 p2 = { 3.0, 4}; + return p1.x + p2.x; +} \ No newline at end of file diff --git a/chapter19/valid/scoping_tests/scoped_struct.c b/chapter19/valid/scoping_tests/scoped_struct.c new file mode 100644 index 00000000..7659227a --- /dev/null +++ b/chapter19/valid/scoping_tests/scoped_struct.c @@ -0,0 +1,14 @@ +struct pair { + int *x; + int y; +}; + +int main() { + struct pair p = { 0, 7 }; + { + struct pair { double x; double z; }; + struct pair foo; + foo.x = p.x ? 1.0 : 2.0; + return (int) foo.x; + } +} \ No newline at end of file diff --git a/chapter19/valid/scoping_tests/shared_struct_and_var_names.c b/chapter19/valid/scoping_tests/shared_struct_and_var_names.c new file mode 100644 index 00000000..000e7d1e --- /dev/null +++ b/chapter19/valid/scoping_tests/shared_struct_and_var_names.c @@ -0,0 +1,9 @@ +struct main { + int x; + int y; +}; + +int main() { + struct main x = { 1, 2}; + return x.x; +} \ No newline at end of file diff --git a/chapter19/valid/sizeof/sizeof_padded.c b/chapter19/valid/sizeof/sizeof_padded.c new file mode 100644 index 00000000..6d05e3cf --- /dev/null +++ b/chapter19/valid/sizeof/sizeof_padded.c @@ -0,0 +1,47 @@ +// make sure we calculate size/padding correctly + +// need three bytes of padding so it's four-byte aligned, +// total size is eight +struct eightbyte { + int i; + char c; +}; + +struct twobyte { + char arr[2]; +}; + +struct threebyte { + char arr[3]; +}; + +struct big { + struct eightbyte a; // bytes 0-7 + struct twobyte b; // bytes 8-9 + struct threebyte c; // bytes 10-12 +}; // total size is 16 b/c it's fourbyte aligned + +struct medium { + struct twobyte a; // bytes 0-1 + struct threebyte b; // bytes 2-4 + struct twobyte c; // bytes 5-6 +}; // total size is 7 bytes + +struct biggest { + struct medium a; // bytes 0-7 + struct big b; // bytes 8-24 (four-byte aligned) +}; + +struct medium_big { + struct big a; // bytes 0-16 + struct twobyte b; // bytes 17-18 +}; // 20 bytes b/c it's four-byte aligned + +int main() { + if (sizeof(struct twobyte) == 2 && sizeof(struct threebyte) == 3 && + sizeof(struct big) == 16 && sizeof(struct medium) == 7 && + sizeof(struct biggest) == 24 && sizeof(struct medium_big) == 20) { + return 1; + } + return 0; +} diff --git a/chapter19/valid/sizeof/sizeof_struct.c b/chapter19/valid/sizeof/sizeof_struct.c new file mode 100644 index 00000000..5509dca9 --- /dev/null +++ b/chapter19/valid/sizeof/sizeof_struct.c @@ -0,0 +1,8 @@ +struct s { + char c; + int x; +}; + +int main() { + return sizeof(struct s); +} \ No newline at end of file diff --git a/chapter19/valid/sizeof/sizeof_wonky.c b/chapter19/valid/sizeof/sizeof_wonky.c new file mode 100644 index 00000000..abf37b45 --- /dev/null +++ b/chapter19/valid/sizeof/sizeof_wonky.c @@ -0,0 +1,6 @@ +// larger than 16 bytes but size is not divisible by 8 bytes +struct wonky { + char arr[19]; +}; + +int main() { return sizeof(struct wonky); } \ No newline at end of file diff --git a/chapter19/valid/struct_copy_tests/array_of_structs.c b/chapter19/valid/struct_copy_tests/array_of_structs.c new file mode 100644 index 00000000..3387f6f8 --- /dev/null +++ b/chapter19/valid/struct_copy_tests/array_of_structs.c @@ -0,0 +1,12 @@ +struct triple { + long one; + double two; + char three; +}; + +int main() { + struct triple array[3] = {{1, 2.0, 3}, {0, 9.0, 4}, {5, 6.0, 7}}; + struct triple new = {12, 11, 10}; + array[1] = new; + return array[1].one + array[2].three; +} \ No newline at end of file diff --git a/chapter19/valid/struct_copy_tests/array_of_structs_padding.c b/chapter19/valid/struct_copy_tests/array_of_structs_padding.c new file mode 100644 index 00000000..700e26b6 --- /dev/null +++ b/chapter19/valid/struct_copy_tests/array_of_structs_padding.c @@ -0,0 +1,18 @@ +struct small_alignment { + int a; + int b; + char c; +}; + +int main() { + + struct small_alignment arr[3] = { {0, 1, 2}, {3, 4, 5}, {6, 7, 8}}; + struct small_alignment new = {9, 9, 9}; + arr[1] = new; + 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 1; + return 0; + +} \ No newline at end of file diff --git a/chapter19/valid/struct_copy_tests/copy_from_offset_test.c b/chapter19/valid/struct_copy_tests/copy_from_offset_test.c new file mode 100644 index 00000000..4e18a805 --- /dev/null +++ b/chapter19/valid/struct_copy_tests/copy_from_offset_test.c @@ -0,0 +1,39 @@ +// make sure we copy correct number of bytes when copying sub-object into +// something else + +struct inner { + char char_array[5]; +}; + +struct outer { + char first; + char second; + struct inner nested; + char last; +}; + +int main() { + // this test relies on the fact that we allocate variables contiguously on the + // stack to validate that copying an aggregate into one object doesn't + // overwrite the ones next to it. it won't test this anymore once we implement + // register allocation + char a = 'a'; + char b = 'b'; + char c = 'c'; + struct inner x = {{0, 0, 0, 0, 0}}; + char d = 'd'; + char e = 'e'; + struct outer y = {-1, -2, {{-3, -4, -5, -6, -7}}, -8}; + x = y.nested; + char f = 'f'; + char g = 'g'; + if (a != 'a' || b != 'b' || c != 'c' || d != 'd' || e != 'e' || f != 'f' || + g != 'g') + return 1; + + if (x.char_array[0] != -3 || x.char_array[1] != -4 || x.char_array[2] != -5 || + x.char_array[3] != -6 || x.char_array[4] != -7) + return 2; + + return 0; +} \ No newline at end of file diff --git a/chapter19/valid/struct_copy_tests/copy_struct.c b/chapter19/valid/struct_copy_tests/copy_struct.c new file mode 100644 index 00000000..f7ff228a --- /dev/null +++ b/chapter19/valid/struct_copy_tests/copy_struct.c @@ -0,0 +1,12 @@ +struct pair { + int x; + int y; +}; + +int main() { + struct pair p1 = {1, 2}; + struct pair p2 = {0, 0}; + p2 = p1; + p2.x = 4; + return p1.x + p2.x + p2.y; +} \ No newline at end of file diff --git a/chapter19/valid/struct_copy_tests/copy_struct_into_member.c b/chapter19/valid/struct_copy_tests/copy_struct_into_member.c new file mode 100644 index 00000000..e0e69dde --- /dev/null +++ b/chapter19/valid/struct_copy_tests/copy_struct_into_member.c @@ -0,0 +1,47 @@ +struct inner { + signed char a; + signed char b; + signed char c; +}; + +struct outer { + struct inner substruct; + signed char x; + signed char y; +}; + +struct outermost { + struct outer nested; + int i; +}; + +int main() { + static struct outer big_struct = {{0, 0, 0}, 0, 0}; + struct inner small_struct = {-1, -2, -3}; + big_struct.substruct = small_struct; + // make sure we updated substruct w/out overwriting other members + if (big_struct.substruct.a != -1 && big_struct.substruct.b != -2 && + big_struct.substruct.c != -3) + return 1; + if (big_struct.x || big_struct.y) + return 2; + + // now try w/ multiple levels of nesting (and w/ auto storage duratioN) + struct outermost biggest_struct = {big_struct, -1}; + small_struct.a = 50; + small_struct.b = 51; + small_struct.c = 52; + biggest_struct.nested.substruct = small_struct; + + if (biggest_struct.nested.x || biggest_struct.nested.y) + return 3; + if (biggest_struct.i != -1) + return 4; + + struct inner copied_from_biggest = biggest_struct.nested.substruct; + if (copied_from_biggest.a != 50 || copied_from_biggest.b != 51 || + copied_from_biggest.c != 52) + return 5; + + return 0; +} \ No newline at end of file diff --git a/chapter19/valid/struct_copy_tests/copy_struct_with_array.c b/chapter19/valid/struct_copy_tests/copy_struct_with_array.c new file mode 100644 index 00000000..0e516317 --- /dev/null +++ b/chapter19/valid/struct_copy_tests/copy_struct_with_array.c @@ -0,0 +1,14 @@ +struct s { + char arr[12]; + double d; +}; + +int main() { + struct s first = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, 12.0}; + struct s second = first; + for (int i = 0; i < 12; i = i + 1) { + if (second.arr[i] != i + 1) + return 0; + } + return second.d == 12.0; +} \ No newline at end of file diff --git a/chapter19/valid/struct_copy_tests/copy_struct_with_array_2.c b/chapter19/valid/struct_copy_tests/copy_struct_with_array_2.c new file mode 100644 index 00000000..71f8a4ef --- /dev/null +++ b/chapter19/valid/struct_copy_tests/copy_struct_with_array_2.c @@ -0,0 +1,24 @@ +struct s { + char arr[3]; + double d; + int arr2[2]; + char arr3[5]; +}; + +int main() { + struct s first = { { 1, 2, 3 }, + 12.0, {4, 5}, + { 6, 7, 8, 9, 10} }; + struct s second = first; + for (int i = 0; i < 3; i = i + 1) { + if (second.arr[i] != i + 1) + return 0; + } + if (second.arr2[0] != 4 || second.arr2[1] != 5) + return 0; + for (int i = 0; i < 3; i = i + 1) { + if (second.arr3[i] != i + 6) + return 0; + } + return second.d == 12.0; +} \ No newline at end of file diff --git a/chapter19/valid/struct_copy_tests/load_test.c b/chapter19/valid/struct_copy_tests/load_test.c new file mode 100644 index 00000000..6947df83 --- /dev/null +++ b/chapter19/valid/struct_copy_tests/load_test.c @@ -0,0 +1,36 @@ +// make sure we copy correct number of bytes when loading aggregate value from a +// pointer + +void *malloc(unsigned long size); + +struct chars { + char char_array[3]; +}; + +int main() { + // this test relies on the fact that we allocate variables contiguously on the + // stack make sure copying an aggregate into one object doesn't overwrite the + // ones next to it + // it won't test this anymore once we implement register allocation + char a = 'a'; + char b = 'b'; + char c = 'c'; + struct chars x = {{0, 0, 0}}; + char d = 'd'; + char e = 'e'; + struct chars *ptr = malloc(sizeof(struct chars)); + ptr->char_array[0] = 0; + ptr->char_array[1] = 1; + ptr->char_array[2] = 2; + x = *ptr; + char f = 'f'; + char g = 'g'; + if (a != 'a' || b != 'b' || c != 'c' || d != 'd' || e != 'e' || f != 'f' || + g != 'g') + return 1; + + if (x.char_array[0] != 0 || x.char_array[1] != 1 || x.char_array[2] != 2) + return 2; + + return 0; +} \ No newline at end of file From fadfa7a05d7236fab65b2dfe7bd8413c297649df Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Mon, 6 Mar 2023 16:18:31 -0800 Subject: [PATCH 010/167] Bugfixes and improvements for Part I tests: 1. Include invalid tokens (like `a@b` and `1foo`) in lexer tests for initial version of compiler, not parser tests when we add variables. 2. Test shouldn't include tokens that we haven't added yet. E.g. we shouldn't put `! =` in parser tests for comparisons, because we don't recognize the `=` token yet - but we will in the following chapter, so it's not a lexer error either. 3. Fix undefined behavior in shadow_static_local_var.c 4. Add a few extra parsing tests --- chapter11/valid/shadow_static_local_var.c | 30 +++++++++++-------- chapter2/invalid_lex/invalid_identifier_2.c | 4 +++ chapter2/invalid_parse/extra_junk.c | 6 ++++ chapter3/invalid_parse/extra_paren.c | 4 +++ chapter3/invalid_parse/missing_const.c | 2 +- chapter3/invalid_parse/missing_semicolon.c | 2 +- chapter3/invalid_parse/nested_missing_const.c | 5 ++-- chapter3/invalid_parse/unclosed_paren.c | 4 +++ chapter3/valid/redundant_parens.c | 4 +++ chapter5/invalid_parse/malformed_less_equal.c | 3 -- chapter5/invalid_parse/malformed_not_equal.c | 3 -- chapter5/invalid_parse/malformed_or.c | 4 --- chapter5/invalid_parse/missing_const.c | 4 +++ .../invalid_parse/unary_missing_semicolon.c | 4 +++ .../invalid_parse/invalid_variable_name.c | 7 +++-- .../invalid_parse/invalid_variable_name_2.c | 4 --- .../invalid_parse/invalid_variable_name_3.c | 4 --- chapter6/invalid_parse/malformed_less_equal.c | 7 +++++ chapter6/invalid_parse/malformed_not_equal.c | 7 +++++ chapter6/invalid_parse/return_in_assignment.c | 4 +++ .../mixed_precedence_assignment.c | 0 21 files changed, 74 insertions(+), 38 deletions(-) create mode 100644 chapter2/invalid_lex/invalid_identifier_2.c create mode 100644 chapter2/invalid_parse/extra_junk.c create mode 100644 chapter3/invalid_parse/extra_paren.c create mode 100644 chapter3/invalid_parse/unclosed_paren.c create mode 100644 chapter3/valid/redundant_parens.c delete mode 100644 chapter5/invalid_parse/malformed_less_equal.c delete mode 100644 chapter5/invalid_parse/malformed_not_equal.c delete mode 100644 chapter5/invalid_parse/malformed_or.c create mode 100644 chapter5/invalid_parse/missing_const.c create mode 100644 chapter5/invalid_parse/unary_missing_semicolon.c delete mode 100644 chapter6/invalid_parse/invalid_variable_name_2.c delete mode 100644 chapter6/invalid_parse/invalid_variable_name_3.c create mode 100644 chapter6/invalid_parse/malformed_less_equal.c create mode 100644 chapter6/invalid_parse/malformed_not_equal.c create mode 100644 chapter6/invalid_parse/return_in_assignment.c rename chapter6/{invalid_parse => invalid_semantics}/mixed_precedence_assignment.c (100%) diff --git a/chapter11/valid/shadow_static_local_var.c b/chapter11/valid/shadow_static_local_var.c index f7ee0659..eab70890 100644 --- a/chapter11/valid/shadow_static_local_var.c +++ b/chapter11/valid/shadow_static_local_var.c @@ -1,26 +1,29 @@ -/* A static local variable and a variable with internal linkage +/* A static local variable and a variable with external linkage * may have the same name, but they refer to different objects, * since the static local variable has no linkage. */ -/* A variable with internal linkage */ -static int i; +/* A variable with external linkage */ +int i; /* this function sets either static local 'i' - * or the 'i' with internal linkage to new_val, + * or the 'i' with external linkage to new_val, * then return value of local 'i' */ -int update_static_or_global(int update_global, int new_val) { +int update_static_or_global(int update_global, int new_val) +{ /* A static local variable; it has static storage duration, - * but no linkage - */ + * but no linkage + */ static int i; - if (update_global) { - /* bring i with linkage into scope, shadowing local i */ + if (update_global) + { + /* bring i with external linkage into scope, shadowing local i */ extern int i; i = new_val; - } else + } + else // update local i i = new_val; @@ -28,11 +31,12 @@ int update_static_or_global(int update_global, int new_val) { return i; } -int main() { - if (i != 0) // i with linkage should be initialized to 0 +int main() +{ + if (i != 0) // i with external linkage should be initialized to 0 return 1; - /* update i with linkage, and check values of both variables */ + /* update i with external linkage, and check values of both variables */ int result = update_static_or_global(1, 10); if (result != 0) diff --git a/chapter2/invalid_lex/invalid_identifier_2.c b/chapter2/invalid_lex/invalid_identifier_2.c new file mode 100644 index 00000000..350d24ac --- /dev/null +++ b/chapter2/invalid_lex/invalid_identifier_2.c @@ -0,0 +1,4 @@ +int main() +{ + return @b; +} \ No newline at end of file diff --git a/chapter2/invalid_parse/extra_junk.c b/chapter2/invalid_parse/extra_junk.c new file mode 100644 index 00000000..1c401f28 --- /dev/null +++ b/chapter2/invalid_parse/extra_junk.c @@ -0,0 +1,6 @@ +int main() +{ + return 2; +} + +foo \ No newline at end of file diff --git a/chapter3/invalid_parse/extra_paren.c b/chapter3/invalid_parse/extra_paren.c new file mode 100644 index 00000000..de2972c6 --- /dev/null +++ b/chapter3/invalid_parse/extra_paren.c @@ -0,0 +1,4 @@ +int main() +{ + return (3)); +} \ No newline at end of file diff --git a/chapter3/invalid_parse/missing_const.c b/chapter3/invalid_parse/missing_const.c index 6dd069ef..ad701b1f 100644 --- a/chapter3/invalid_parse/missing_const.c +++ b/chapter3/invalid_parse/missing_const.c @@ -1,3 +1,3 @@ int main() { - return !; + return ~; } \ No newline at end of file diff --git a/chapter3/invalid_parse/missing_semicolon.c b/chapter3/invalid_parse/missing_semicolon.c index 5570d649..91e3f435 100644 --- a/chapter3/invalid_parse/missing_semicolon.c +++ b/chapter3/invalid_parse/missing_semicolon.c @@ -1,3 +1,3 @@ int main() { - return !5 + return -5 } \ No newline at end of file diff --git a/chapter3/invalid_parse/nested_missing_const.c b/chapter3/invalid_parse/nested_missing_const.c index 43b70973..a9e767db 100644 --- a/chapter3/invalid_parse/nested_missing_const.c +++ b/chapter3/invalid_parse/nested_missing_const.c @@ -1,3 +1,4 @@ -int main() { - return !~; +int main() +{ + return -~; } \ No newline at end of file diff --git a/chapter3/invalid_parse/unclosed_paren.c b/chapter3/invalid_parse/unclosed_paren.c new file mode 100644 index 00000000..d9d20bd1 --- /dev/null +++ b/chapter3/invalid_parse/unclosed_paren.c @@ -0,0 +1,4 @@ +int main() +{ + return (1; +} \ No newline at end of file diff --git a/chapter3/valid/redundant_parens.c b/chapter3/valid/redundant_parens.c new file mode 100644 index 00000000..54e36ff7 --- /dev/null +++ b/chapter3/valid/redundant_parens.c @@ -0,0 +1,4 @@ +int main() +{ + return -((((10)))); +} \ No newline at end of file diff --git a/chapter5/invalid_parse/malformed_less_equal.c b/chapter5/invalid_parse/malformed_less_equal.c deleted file mode 100644 index 8d5a72b9..00000000 --- a/chapter5/invalid_parse/malformed_less_equal.c +++ /dev/null @@ -1,3 +0,0 @@ -int main() { - return 1 < = 2; -} \ No newline at end of file diff --git a/chapter5/invalid_parse/malformed_not_equal.c b/chapter5/invalid_parse/malformed_not_equal.c deleted file mode 100644 index eab36da4..00000000 --- a/chapter5/invalid_parse/malformed_not_equal.c +++ /dev/null @@ -1,3 +0,0 @@ -int main() { - return 1 ! = 0; -} \ No newline at end of file diff --git a/chapter5/invalid_parse/malformed_or.c b/chapter5/invalid_parse/malformed_or.c deleted file mode 100644 index 85e22e8e..00000000 --- a/chapter5/invalid_parse/malformed_or.c +++ /dev/null @@ -1,4 +0,0 @@ -int main() { - return 1 | -| 0; -} \ No newline at end of file diff --git a/chapter5/invalid_parse/missing_const.c b/chapter5/invalid_parse/missing_const.c new file mode 100644 index 00000000..2d9eac24 --- /dev/null +++ b/chapter5/invalid_parse/missing_const.c @@ -0,0 +1,4 @@ +int main() +{ + 10 <= !; +} \ No newline at end of file diff --git a/chapter5/invalid_parse/unary_missing_semicolon.c b/chapter5/invalid_parse/unary_missing_semicolon.c new file mode 100644 index 00000000..e2c9f9a5 --- /dev/null +++ b/chapter5/invalid_parse/unary_missing_semicolon.c @@ -0,0 +1,4 @@ +int main() +{ + return !10 +} \ No newline at end of file diff --git a/chapter6/invalid_parse/invalid_variable_name.c b/chapter6/invalid_parse/invalid_variable_name.c index a303bab6..d0a10a91 100644 --- a/chapter6/invalid_parse/invalid_variable_name.c +++ b/chapter6/invalid_parse/invalid_variable_name.c @@ -1,4 +1,5 @@ -int main() { - int .x = 0; - return .x; +int main() +{ + int 10 = 0; + return 10; } \ No newline at end of file diff --git a/chapter6/invalid_parse/invalid_variable_name_2.c b/chapter6/invalid_parse/invalid_variable_name_2.c deleted file mode 100644 index 3413207c..00000000 --- a/chapter6/invalid_parse/invalid_variable_name_2.c +++ /dev/null @@ -1,4 +0,0 @@ -int main() { - int 10a = 0; - return 10a; -} \ No newline at end of file diff --git a/chapter6/invalid_parse/invalid_variable_name_3.c b/chapter6/invalid_parse/invalid_variable_name_3.c deleted file mode 100644 index 72075d7e..00000000 --- a/chapter6/invalid_parse/invalid_variable_name_3.c +++ /dev/null @@ -1,4 +0,0 @@ -int main() { - int a@b = 0; - return a@b; -} \ No newline at end of file diff --git a/chapter6/invalid_parse/malformed_less_equal.c b/chapter6/invalid_parse/malformed_less_equal.c new file mode 100644 index 00000000..ffdb5de9 --- /dev/null +++ b/chapter6/invalid_parse/malformed_less_equal.c @@ -0,0 +1,7 @@ +int main() +{ + // make sure we lex < and = as two separate tokens + // this really tests the lexing logic from previous chapter, + // but the lexer didn't recognize = yet + return 1 < = 2; +} \ No newline at end of file diff --git a/chapter6/invalid_parse/malformed_not_equal.c b/chapter6/invalid_parse/malformed_not_equal.c new file mode 100644 index 00000000..86d84937 --- /dev/null +++ b/chapter6/invalid_parse/malformed_not_equal.c @@ -0,0 +1,7 @@ +int main() +{ + // make sure we lex ! and = as two separate tokens + // this really tests the lexing logic from previous chapter, + // but the lexer didn't recognize = yet + return 1 ! = 0; +} \ No newline at end of file diff --git a/chapter6/invalid_parse/return_in_assignment.c b/chapter6/invalid_parse/return_in_assignment.c new file mode 100644 index 00000000..d16a436e --- /dev/null +++ b/chapter6/invalid_parse/return_in_assignment.c @@ -0,0 +1,4 @@ +int main() +{ + int 10 = return 0; +} \ No newline at end of file diff --git a/chapter6/invalid_parse/mixed_precedence_assignment.c b/chapter6/invalid_semantics/mixed_precedence_assignment.c similarity index 100% rename from chapter6/invalid_parse/mixed_precedence_assignment.c rename to chapter6/invalid_semantics/mixed_precedence_assignment.c From ff8611de1e8c8b2f0a8b7daf2b4fe06805497392 Mon Sep 17 00:00:00 2001 From: Nora Sandler Date: Mon, 6 Mar 2023 17:07:52 -0800 Subject: [PATCH 011/167] Test script and Part III tests also moved extra credit tests into subdirectories within each stage, and fixed a couple of existing tests --- .gitignore | 4 +- .../nested_function_definition.c | 0 .../extra_credit}/goto_cross_function.c | 0 .../extra_credit}/goto_function.c | 0 .../compound_assignment_function_call.c | 0 .../extra_credit}/switch_on_function.c | 0 .../compound_assign_function_result.c | 0 .../goto_label_multiple_functions.c | 0 .../extra_credit}/goto_shared_name.c | 0 .../extra_credit}/goto_file_scope_label.c | 0 .../extra_credit}/goto_global_var.c | 0 .../goto_skip_static_initializer.c | 0 .../extra_credit}/switch_duplicate_cases.c | 0 .../extra_credit}/bitwise_long_op.c | 0 .../extra_credit}/compound_assign_to_int.c | 0 .../extra_credit}/compound_assign_to_long.c | 0 .../extra_credit}/switch_int.c | 0 .../extra_credit}/switch_long.c | 0 .../extra_credit}/switch_duplicate_cases.c | 0 .../extra_credit}/bitwise_unsigned_ops.c | 0 .../extra_credit}/bitwise_unsigned_shift.c | 0 .../extra_credit}/compound_assign_uint.c | 0 .../extra_credit}/switch_uint.c | 0 .../extra_credit}/bitwise_and.c | 0 .../extra_credit}/bitwise_or.c | 0 .../extra_credit}/bitwise_shift_double.c | 0 .../extra_credit}/bitwise_xor.c | 0 .../extra_credit}/switch_double_case.c | 0 .../extra_credit}/switch_on_double.c | 0 .../extra_credit}/compound_assign.c | 0 .../compound_assign_implicit_cast.c | 0 .../extra_credit}/nan.c | 0 .../extra_credit}/bitwise_or_pointer.c | 0 .../extra_credit}/bitwise_shift_pointer.c | 0 .../extra_credit}/compound_divide_pointer.c | 0 .../extra_credit}/compound_multiply_pointer.c | 0 .../extra_credit}/switch_on_pointer.c | 0 .../compound_assign_through_pointer.c | 0 .../extra_credit}/incr_through_pointer.c | 0 .../extra_credit}/incr_ptr.c | 0 .../all_types/alias_analysis_change.c | 19 + .../constant_folding/all_types/add_doubles.c | 3 + .../all_types/double_to_char.c | 3 + .../all_types/double_to_int.c | 3 + .../all_types/double_to_uint.c | 3 + .../all_types/double_to_ulong.c | 3 + .../constant_folding/all_types/gt_unsigned.c | 6 + .../all_types/long_complement.c | 3 + .../all_types/long_to_double.c | 3 + .../constant_folding/all_types/lt_long.c | 3 + .../all_types/negate_double_zero.c | 6 + .../constant_folding/all_types/negate_long.c | 13 + .../all_types/negate_unsigned_long.c | 11 + .../all_types/truncate_to_char.c | 3 + .../all_types/truncate_to_uchar.c | 3 + .../constant_folding/all_types/uint_div.c | 3 + .../constant_folding/all_types/uint_mult.c | 7 + .../constant_folding/all_types/ulong_div.c | 3 + .../all_types/ulong_to_double.c | 3 + .../constant_folding/all_types/zero_extend.c | 3 + .../constant_folding/int_only/fold_add.c | 7 + .../int_only/fold_complement.c | 3 + .../int_only/fold_dead_branch.c | 10 + .../int_only/fold_divide_by_zero.c | 11 + chapter20/constant_folding/int_only/fold_eq.c | 6 + chapter20/constant_folding/int_only/fold_gt.c | 3 + .../int_only/fold_jumpifnotzero_to_jump.c | 5 + .../int_only/fold_jumpifzero_to_jump.c | 7 + .../constant_folding/int_only/fold_mult.c | 3 + .../constant_folding/int_only/fold_negate.c | 7 + .../constant_folding/int_only/fold_neq.c | 3 + .../constant_folding/int_only/fold_not.c | 2 + .../constant_folding/int_only/fold_not_zero.c | 3 + .../constant_folding/int_only/fold_overflow.c | 6 + .../int_only/fold_remainder.c | 3 + .../constant_folding/int_only/fold_sub.c | 3 + .../constant_folding/int_only/remove_jz.c | 6 + .../all_types/alias_analysis.c | 16 + .../all_types/char_round_trip.c | 7 + .../all_types/char_round_trip_2.c | 8 + .../all_types/char_type_conversion.c | 10 + .../all_types/const_fold_sign_extend.c | 3 + .../all_types/const_fold_sign_extend_2.c | 3 + .../all_types/const_fold_type_conversions.c | 11 + .../copy_propagation/all_types/copy_struct.c | 17 + .../all_types/dont_propagate/copy_to_offset.c | 13 + .../dont_propagate/dont_propagate_addr_of.c | 7 + .../dont_propagate/funcall_kills_aliased.c | 22 + .../dont_propagate/static_are_aliased.c | 12 + .../dont_propagate/store_kills_aliased.c | 16 + .../dont_propagate/type_conversion.c | 9 + .../dont_propagate/zero_neg_zero_different.c | 15 + .../copy_propagation/all_types/not_char.c | 6 + .../all_types/pointer_arithmetic.c | 8 + .../all_types/propagate_doubles.c | 7 + .../all_types/propagate_null_pointer.c | 10 + .../all_types/signed_unsigned_conversion.c | 10 + .../all_types/store_doesnt_kill.c | 12 + .../all_types/unsigned_compare.c | 4 + .../all_types/unsigned_wraparound.c | 6 + .../int_only/complex_const_fold.c | 7 + .../int_only/copy_prop_const_fold.c | 7 + .../add_all_blocks_to_worklist.c | 22 + .../int_only/dont_propagate/dest_killed.c | 11 + .../int_only/dont_propagate/listing_20_15.c | 23 + .../int_only/dont_propagate/multi_values.c | 13 + .../dont_propagate/no_copies_reach_entry.c | 10 + .../dont_propagate/one_reaching_copy.c | 21 + .../int_only/dont_propagate/source_killed.c | 12 + .../source_killed_on_one_path.c | 12 + .../dont_propagate/static_dst_killed.c | 13 + .../dont_propagate/static_src_killed.c | 14 + .../copy_propagation/int_only/fig_20_8.c | 21 + .../int_only/init_all_copies.c | 26 + .../int_only/kill_and_add_copies.c | 18 + .../int_only/killed_then_redefined.c | 10 + chapter20/copy_propagation/int_only/loop.c | 28 + .../int_only/multi_instance_same_copy.c | 31 + .../copy_propagation/int_only/multi_path.c | 11 + .../int_only/multi_path_no_kill.c | 19 + .../int_only/prop_static_var.c | 14 + .../int_only/propagate_fun_args.c | 15 + .../copy_propagation/int_only/propagate_var.c | 14 + .../int_only/redundant_copies.c | 13 + .../int_only/redundant_copies_2.c | 13 + .../int_only/remainder_test.c | 13 + .../all_types/aliased_dead_at_exit.c | 22 + .../all_types/copy_to_dead_struct.c | 21 + .../all_types/dont_elim/copyfromoffset_gen.c | 17 + .../dont_elim/copytooffset_doesnt_kill.c | 16 + .../dont_elim/load_generates_pointer.c | 7 + .../dont_elim/load_through_pointer.c | 14 + .../all_types/dont_elim/never_kill_store.c | 12 + .../all_types/dont_elim/pass_pointer_to_fun.c | 18 + .../all_types/dont_elim/store_generates_dst.c | 13 + .../all_types/getaddr_doesnt_gen.c | 10 + .../int_only/dead_store_static_var.c | 14 + .../int_only/dont_elim/add_all_to_worklist.c | 18 + .../int_only/dont_elim/dont_remove_funcall.c | 9 + .../int_only/dont_elim/loop.c | 16 + .../int_only/dont_elim/static_vars_at_exit.c | 13 + .../int_only/dont_elim/static_vars_fun.c | 12 + .../int_only/dont_elim/used_one_path.c | 9 + .../int_only/elim_second_copy.c | 10 + .../int_only/fig_20_12.c | 15 + .../int_only/loop_dead_store.c | 13 + .../dead_store_elimination/int_only/simple.c | 7 + .../int_only/use_and_kill.c | 10 + .../constant_if_else.c | 12 + .../dead_after_if_else.c | 12 + .../dead_after_return.c | 17 + .../dead_branch_inside_loop.c | 15 + .../dead_for_loop.c | 13 + .../dont_elim/keep_final_jump.c | 12 + .../unreachable_code_elimination/empty.c | 5 + .../empty_block.c | 12 + .../loop_in_dead_branch.c | 17 + .../unreachable_code_elimination/remove_jnz.c | 3 + .../remove_useless_starting_label.c | 10 + chapter20/whole_pipeline/dead_condition.c | 8 + chapter20/whole_pipeline/elim_and_copy_prop.c | 6 + .../all_types/no_coalescing/dbl_fun_call.c | 15 + .../no_coalescing/dbl_trivially_colorable.c | 15 + .../no_coalescing/div_interference.c | 21 + .../fourteen_pseudos_interfere.c | 30 + .../all_types/no_coalescing/mixed_ints.c | 47 ++ chapter21/all_types/no_coalescing/push_xmm.c | 13 + .../all_types/no_coalescing/spill_movz_dst.c | 48 ++ .../all_types/no_coalescing/stack_alignment.c | 30 + .../no_coalescing/store_pointer_in_register.c | 80 +++ .../no_coalescing/test_spilling_dbls.c | 46 ++ .../no_coalescing/track_dbl_arg_registers.c | 15 + .../callee_saved_stack_alignment.c | 23 + .../int_only/no_coalescing/cdq_interference.c | 202 ++++++ .../int_only/no_coalescing/cmp_liveness.c | 88 +++ .../copy_and_separate_interference.c | 80 +++ .../no_coalescing/copy_no_interference.c | 80 +++ .../int_only/no_coalescing/force_spill.c | 42 ++ .../no_coalescing/idiv_interference.c | 21 + chapter21/int_only/no_coalescing/loop.c | 56 ++ .../many_pseudos_fewer_conflicts.c | 41 ++ .../no_coalescing/optimistic_coloring.c | 143 ++++ .../no_coalescing/preserve_across_fun_call.c | 25 + .../no_coalescing/rewrite_large_multiply.c | 44 ++ .../no_coalescing/same_instr_interference.c | 57 ++ .../same_instr_no_interference.c | 54 ++ .../no_coalescing/spill_callee_saved.c | 21 + .../no_coalescing/spills_and_rewrites.c | 47 ++ .../no_coalescing/spills_rewrites_compare.c | 47 ++ .../no_coalescing/test_spill_metric.c | 38 ++ .../no_coalescing/test_spill_metric_2.c | 43 ++ .../no_coalescing/track_arg_registers.c | 14 + .../no_coalescing/trivially_colorable.c | 13 + .../no_coalescing/unary_interference.c | 57 ++ .../int_only/no_coalescing/use_all_hardregs.c | 24 + .../with_coalescing/bin_generates_dst.c | 31 + .../with_coalescing/briggs_coalesce.c | 21 + .../with_coalescing/briggs_coalesce_tmps.c | 19 + .../callee_saved_live_at_exit.c | 31 + .../with_coalescing/cdq_generates_ax.c | 15 + .../with_coalescing/cmp_generates_operands.c | 20 + .../with_coalescing/coalesce_prevents_spill.c | 41 ++ .../with_coalescing/eax_live_at_exit.c | 16 + .../with_coalescing/funcall_generates_args.c | 24 + .../with_coalescing/george_coalesce.c | 7 + .../with_coalescing/unary_generates_dst.c | 30 + .../libraries/callee_saved_live_at_exit_lib.c | 40 ++ .../libraries/coalesce_prevents_spill_lib.c | 3 + chapter21/libraries/force_spill_dbl_lib.c | 18 + chapter21/libraries/force_spill_lib.c | 18 + .../libraries/force_spill_mixed_int_lib.c | 18 + .../libraries/funcall_generates_args_lib.c | 3 + chapter21/libraries/george_lib.c | 3 + .../many_pseudos_fewer_conflicts_lib.c | 19 + chapter21/libraries/test_spill_metric_2_lib.c | 21 + chapter21/libraries/test_spill_metric_lib.c | 21 + chapter21/libraries/test_spilling_dbls_lib.c | 0 chapter21/libraries/track_arg_registers_lib.c | 3 + .../libraries/track_dbl_arg_registers_lib.c | 5 + chapter21/wrapper_linux.s | 79 +++ chapter21/wrapper_osx.s | 78 +++ .../extra_credit/bitwise_double_operator.c} | 0 .../extra_credit/bitwise_and.c} | 0 .../extra_credit/bitwise_or.c} | 0 .../extra_credit}/bitwise_precedence.c | 0 .../bitwise_shift_associativity.c} | 0 .../bitwise_shift_associativity_2.c} | 0 .../extra_credit/bitwise_shift_precedence.c | 4 + .../extra_credit/bitwise_shiftl.c} | 0 .../extra_credit/bitwise_shiftr.c} | 0 .../extra_credit/bitwise_xor.c} | 0 chapter4/valid_bitwise/shift_precedence.c | 3 - .../extra_credit}/bitwise_precedence.c | 0 .../extra_credit}/compound_initializer.c | 0 .../extra_credit}/compound_invalid_operator.c | 0 .../extra_credit}/compound_initializer.c | 0 .../extra_credit}/compound_invalid_lvalue.c | 0 .../extra_credit}/bitwise_and_vars.c | 0 .../extra_credit}/bitwise_shiftl_variable.c | 0 .../extra_credit}/bitwise_shiftr_assign.c | 0 .../compound_assignment_chained.c | 0 .../compound_assignment_use_result.c | 0 .../extra_credit}/compound_bitwise_and.c | 0 .../extra_credit}/compound_bitwise_or.c | 0 .../extra_credit}/compound_bitwise_shiftl.c | 0 .../extra_credit}/compound_bitwise_shiftr.c | 0 .../extra_credit}/compound_bitwise_xor.c | 0 .../extra_credit}/compound_divide.c | 0 .../extra_credit}/compound_minus.c | 0 .../extra_credit}/compound_mod.c | 0 .../extra_credit}/compound_multiply.c | 0 .../extra_credit}/compound_plus.c | 0 .../extra_credit/goto_bad_label.c} | 0 .../goto_label_without_statement.c} | 0 .../extra_credit}/goto_missing_label.c | 0 .../extra_credit}/bitwise_ternary.c | 0 .../extra_credit}/compound_if_expression.c | 0 .../extra_credit}/goto_after_declaration.c | 0 .../extra_credit}/goto_backwards.c | 0 .../extra_credit}/goto_label.c | 0 .../extra_credit/goto_label_and_var.c} | 0 .../extra_credit/goto_label_main.c} | 0 .../extra_credit/goto_label_main_2.c} | 0 .../extra_credit/goto_nested_label.c} | 0 .../extra_credit}/goto_use_before_declare.c | 0 .../use_before_declare.c | 9 - .../compound_subtract_in_block.c | 0 .../extra_credit}/goto_before_declaration.c | 0 .../extra_credit}/goto_inner_scope.c | 0 chapter8/valid/use_in_inner_scope.c | 6 +- .../compound_assignment_invalid_decl.c | 0 .../extra_credit}/switch_case_declaration.c | 0 .../extra_credit}/switch_goto_case.c | 0 .../extra_credit}/switch_missing_case_value.c | 0 .../extra_credit}/switch_missing_paren.c | 0 .../extra_credit}/switch_no_condition.c | 0 .../extra_credit}/switch_continue.c | 0 .../extra_credit}/switch_duplicate_case.c | 0 .../extra_credit}/switch_duplicate_default.c | 0 .../extra_credit}/switch_invalid_case.c | 0 .../extra_credit}/switch_invalid_default.c | 0 .../extra_credit}/switch_non_constant_case.c | 0 .../out_of_scope_loop_variable.c | 6 +- .../compound_assignment_for_loop.c | 0 .../extra_credit}/goto_bypass_condition.c | 0 .../extra_credit}/goto_loop_body.c | 0 .../extra_credit}/switch.c | 0 .../extra_credit}/switch_assign_in_body.c | 0 .../switch_assign_in_condition.c | 0 .../extra_credit}/switch_block.c | 0 .../extra_credit}/switch_break.c | 0 .../extra_credit}/switch_decl.c | 0 .../extra_credit}/switch_default.c | 0 .../switch_default_fallthrough.c | 0 .../extra_credit}/switch_default_not_last.c | 0 .../extra_credit}/switch_empty.c | 0 .../extra_credit}/switch_fallthrough.c | 0 .../extra_credit}/switch_goto_mid_case.c | 0 .../extra_credit}/switch_in_loop.c | 0 .../extra_credit}/switch_nested_case.c | 0 .../extra_credit}/switch_nested_not_taken.c | 0 .../extra_credit}/switch_nested_switch.c | 0 .../extra_credit}/switch_no_case.c | 0 .../extra_credit/switch_with_continue.c} | 0 .../extra_credit/switch_with_loop.c} | 0 generate_expected_results.py | 108 +++ test_compiler | 6 + test_properties.json | 273 ++++++++ tests/__init__.py | 0 tests/basic.py | 628 ++++++++++++++++++ tests/parser/__init__.py | 0 tests/parser/asm.py | 183 +++++ tests/parser/parse.py | 602 +++++++++++++++++ tests/parser/tokenize.py | 109 +++ tests/regalloc.py | 521 +++++++++++++++ tests/runner.py | 296 +++++++++ tests/tacky/__init__.py | 0 tests/tacky/common.py | 117 ++++ tests/tacky/const_fold.py | 77 +++ tests/tacky/copy_prop.py | 423 ++++++++++++ tests/tacky/dead_store_elim.py | 163 +++++ tests/tacky/suite.py | 96 +++ tests/tacky/unreachable.py | 111 ++++ tests/test_tests/__init__.py | 1 + tests/test_tests/test_parse.py | 599 +++++++++++++++++ tests/test_tests/test_tokenize.py | 208 ++++++ 326 files changed, 8014 insertions(+), 16 deletions(-) rename chapter10/{invalid_parse => invalid_declarations}/nested_function_definition.c (100%) rename chapter10/{invalid_labels_extra_credit => invalid_labels/extra_credit}/goto_cross_function.c (100%) rename chapter10/{invalid_labels_extra_credit => invalid_labels/extra_credit}/goto_function.c (100%) rename chapter10/{invalid_types_extra_credit => invalid_types/extra_credit}/compound_assignment_function_call.c (100%) rename chapter10/{invalid_types_extra_credit => invalid_types/extra_credit}/switch_on_function.c (100%) rename chapter10/{valid_extra_credit => valid/extra_credit}/compound_assign_function_result.c (100%) rename chapter10/{valid_extra_credit => valid/extra_credit}/goto_label_multiple_functions.c (100%) rename chapter10/{valid_extra_credit => valid/extra_credit}/goto_shared_name.c (100%) rename chapter11/{invalid_labels_extra_credit => invalid_labels/extra_credit}/goto_file_scope_label.c (100%) rename chapter11/{invalid_labels_extra_credit => invalid_labels/extra_credit}/goto_global_var.c (100%) rename chapter11/{valid_extra_credit => valid/extra_credit}/goto_skip_static_initializer.c (100%) rename chapter12/{invalid_labels_extra_credit => invalid_labels/extra_credit}/switch_duplicate_cases.c (100%) rename chapter12/{valid_extra_credit => valid/extra_credit}/bitwise_long_op.c (100%) rename chapter12/{valid_extra_credit => valid/extra_credit}/compound_assign_to_int.c (100%) rename chapter12/{valid_extra_credit => valid/extra_credit}/compound_assign_to_long.c (100%) rename chapter12/{valid_extra_credit => valid/extra_credit}/switch_int.c (100%) rename chapter12/{valid_extra_credit => valid/extra_credit}/switch_long.c (100%) rename chapter13/{invalid_labels_extra_credit => invalid_labels/extra_credit}/switch_duplicate_cases.c (100%) rename chapter13/{valid_extra_credit => valid/extra_credit}/bitwise_unsigned_ops.c (100%) rename chapter13/{valid_extra_credit => valid/extra_credit}/bitwise_unsigned_shift.c (100%) rename chapter13/{valid_extra_credit => valid/extra_credit}/compound_assign_uint.c (100%) rename chapter13/{valid_extra_credit => valid/extra_credit}/switch_uint.c (100%) rename chapter14/{invalid_types_extra_credit => invalid_types/extra_credit}/bitwise_and.c (100%) rename chapter14/{invalid_types_extra_credit => invalid_types/extra_credit}/bitwise_or.c (100%) rename chapter14/{invalid_types_extra_credit => invalid_types/extra_credit}/bitwise_shift_double.c (100%) rename chapter14/{invalid_types_extra_credit => invalid_types/extra_credit}/bitwise_xor.c (100%) rename chapter14/{invalid_types_extra_credit => invalid_types/extra_credit}/switch_double_case.c (100%) rename chapter14/{invalid_types_extra_credit => invalid_types/extra_credit}/switch_on_double.c (100%) rename chapter14/{valid_extra_credit => valid/extra_credit}/compound_assign.c (100%) rename chapter14/{valid_extra_credit => valid/extra_credit}/compound_assign_implicit_cast.c (100%) rename chapter14/{valid_extra_credit => valid/extra_credit}/nan.c (100%) rename chapter15/{invalid_types_extra_credit => invalid_types/extra_credit}/bitwise_or_pointer.c (100%) rename chapter15/{invalid_types_extra_credit => invalid_types/extra_credit}/bitwise_shift_pointer.c (100%) rename chapter15/{invalid_types_extra_credit => invalid_types/extra_credit}/compound_divide_pointer.c (100%) rename chapter15/{invalid_types_extra_credit => invalid_types/extra_credit}/compound_multiply_pointer.c (100%) rename chapter15/{invalid_types_extra_credit => invalid_types/extra_credit}/switch_on_pointer.c (100%) rename chapter15/{valid_extra_credit => valid/extra_credit}/compound_assign_through_pointer.c (100%) rename chapter15/{valid_extra_credit => valid/extra_credit}/incr_through_pointer.c (100%) rename chapter16/{valid_extra_credit => valid/extra_credit}/incr_ptr.c (100%) create mode 100644 chapter20/all_optimizations/all_types/alias_analysis_change.c create mode 100644 chapter20/constant_folding/all_types/add_doubles.c create mode 100644 chapter20/constant_folding/all_types/double_to_char.c create mode 100644 chapter20/constant_folding/all_types/double_to_int.c create mode 100644 chapter20/constant_folding/all_types/double_to_uint.c create mode 100644 chapter20/constant_folding/all_types/double_to_ulong.c create mode 100644 chapter20/constant_folding/all_types/gt_unsigned.c create mode 100644 chapter20/constant_folding/all_types/long_complement.c create mode 100644 chapter20/constant_folding/all_types/long_to_double.c create mode 100644 chapter20/constant_folding/all_types/lt_long.c create mode 100644 chapter20/constant_folding/all_types/negate_double_zero.c create mode 100644 chapter20/constant_folding/all_types/negate_long.c create mode 100644 chapter20/constant_folding/all_types/negate_unsigned_long.c create mode 100644 chapter20/constant_folding/all_types/truncate_to_char.c create mode 100644 chapter20/constant_folding/all_types/truncate_to_uchar.c create mode 100644 chapter20/constant_folding/all_types/uint_div.c create mode 100644 chapter20/constant_folding/all_types/uint_mult.c create mode 100644 chapter20/constant_folding/all_types/ulong_div.c create mode 100644 chapter20/constant_folding/all_types/ulong_to_double.c create mode 100644 chapter20/constant_folding/all_types/zero_extend.c create mode 100644 chapter20/constant_folding/int_only/fold_add.c create mode 100644 chapter20/constant_folding/int_only/fold_complement.c create mode 100644 chapter20/constant_folding/int_only/fold_dead_branch.c create mode 100644 chapter20/constant_folding/int_only/fold_divide_by_zero.c create mode 100644 chapter20/constant_folding/int_only/fold_eq.c create mode 100644 chapter20/constant_folding/int_only/fold_gt.c create mode 100644 chapter20/constant_folding/int_only/fold_jumpifnotzero_to_jump.c create mode 100644 chapter20/constant_folding/int_only/fold_jumpifzero_to_jump.c create mode 100644 chapter20/constant_folding/int_only/fold_mult.c create mode 100644 chapter20/constant_folding/int_only/fold_negate.c create mode 100644 chapter20/constant_folding/int_only/fold_neq.c create mode 100644 chapter20/constant_folding/int_only/fold_not.c create mode 100644 chapter20/constant_folding/int_only/fold_not_zero.c create mode 100644 chapter20/constant_folding/int_only/fold_overflow.c create mode 100644 chapter20/constant_folding/int_only/fold_remainder.c create mode 100644 chapter20/constant_folding/int_only/fold_sub.c create mode 100644 chapter20/constant_folding/int_only/remove_jz.c create mode 100644 chapter20/copy_propagation/all_types/alias_analysis.c create mode 100644 chapter20/copy_propagation/all_types/char_round_trip.c create mode 100644 chapter20/copy_propagation/all_types/char_round_trip_2.c create mode 100644 chapter20/copy_propagation/all_types/char_type_conversion.c create mode 100644 chapter20/copy_propagation/all_types/const_fold_sign_extend.c create mode 100644 chapter20/copy_propagation/all_types/const_fold_sign_extend_2.c create mode 100644 chapter20/copy_propagation/all_types/const_fold_type_conversions.c create mode 100644 chapter20/copy_propagation/all_types/copy_struct.c create mode 100644 chapter20/copy_propagation/all_types/dont_propagate/copy_to_offset.c create mode 100644 chapter20/copy_propagation/all_types/dont_propagate/dont_propagate_addr_of.c create mode 100644 chapter20/copy_propagation/all_types/dont_propagate/funcall_kills_aliased.c create mode 100644 chapter20/copy_propagation/all_types/dont_propagate/static_are_aliased.c create mode 100644 chapter20/copy_propagation/all_types/dont_propagate/store_kills_aliased.c create mode 100644 chapter20/copy_propagation/all_types/dont_propagate/type_conversion.c create mode 100644 chapter20/copy_propagation/all_types/dont_propagate/zero_neg_zero_different.c create mode 100644 chapter20/copy_propagation/all_types/not_char.c create mode 100644 chapter20/copy_propagation/all_types/pointer_arithmetic.c create mode 100644 chapter20/copy_propagation/all_types/propagate_doubles.c create mode 100644 chapter20/copy_propagation/all_types/propagate_null_pointer.c create mode 100644 chapter20/copy_propagation/all_types/signed_unsigned_conversion.c create mode 100644 chapter20/copy_propagation/all_types/store_doesnt_kill.c create mode 100644 chapter20/copy_propagation/all_types/unsigned_compare.c create mode 100644 chapter20/copy_propagation/all_types/unsigned_wraparound.c create mode 100644 chapter20/copy_propagation/int_only/complex_const_fold.c create mode 100644 chapter20/copy_propagation/int_only/copy_prop_const_fold.c create mode 100644 chapter20/copy_propagation/int_only/dont_propagate/add_all_blocks_to_worklist.c create mode 100644 chapter20/copy_propagation/int_only/dont_propagate/dest_killed.c create mode 100644 chapter20/copy_propagation/int_only/dont_propagate/listing_20_15.c create mode 100644 chapter20/copy_propagation/int_only/dont_propagate/multi_values.c create mode 100644 chapter20/copy_propagation/int_only/dont_propagate/no_copies_reach_entry.c create mode 100644 chapter20/copy_propagation/int_only/dont_propagate/one_reaching_copy.c create mode 100644 chapter20/copy_propagation/int_only/dont_propagate/source_killed.c create mode 100644 chapter20/copy_propagation/int_only/dont_propagate/source_killed_on_one_path.c create mode 100644 chapter20/copy_propagation/int_only/dont_propagate/static_dst_killed.c create mode 100644 chapter20/copy_propagation/int_only/dont_propagate/static_src_killed.c create mode 100644 chapter20/copy_propagation/int_only/fig_20_8.c create mode 100644 chapter20/copy_propagation/int_only/init_all_copies.c create mode 100644 chapter20/copy_propagation/int_only/kill_and_add_copies.c create mode 100644 chapter20/copy_propagation/int_only/killed_then_redefined.c create mode 100644 chapter20/copy_propagation/int_only/loop.c create mode 100644 chapter20/copy_propagation/int_only/multi_instance_same_copy.c create mode 100644 chapter20/copy_propagation/int_only/multi_path.c create mode 100644 chapter20/copy_propagation/int_only/multi_path_no_kill.c create mode 100644 chapter20/copy_propagation/int_only/prop_static_var.c create mode 100644 chapter20/copy_propagation/int_only/propagate_fun_args.c create mode 100644 chapter20/copy_propagation/int_only/propagate_var.c create mode 100644 chapter20/copy_propagation/int_only/redundant_copies.c create mode 100644 chapter20/copy_propagation/int_only/redundant_copies_2.c create mode 100644 chapter20/copy_propagation/int_only/remainder_test.c create mode 100644 chapter20/dead_store_elimination/all_types/aliased_dead_at_exit.c create mode 100644 chapter20/dead_store_elimination/all_types/copy_to_dead_struct.c create mode 100644 chapter20/dead_store_elimination/all_types/dont_elim/copyfromoffset_gen.c create mode 100644 chapter20/dead_store_elimination/all_types/dont_elim/copytooffset_doesnt_kill.c create mode 100644 chapter20/dead_store_elimination/all_types/dont_elim/load_generates_pointer.c create mode 100644 chapter20/dead_store_elimination/all_types/dont_elim/load_through_pointer.c create mode 100644 chapter20/dead_store_elimination/all_types/dont_elim/never_kill_store.c create mode 100644 chapter20/dead_store_elimination/all_types/dont_elim/pass_pointer_to_fun.c create mode 100644 chapter20/dead_store_elimination/all_types/dont_elim/store_generates_dst.c create mode 100644 chapter20/dead_store_elimination/all_types/getaddr_doesnt_gen.c create mode 100644 chapter20/dead_store_elimination/int_only/dead_store_static_var.c create mode 100644 chapter20/dead_store_elimination/int_only/dont_elim/add_all_to_worklist.c create mode 100644 chapter20/dead_store_elimination/int_only/dont_elim/dont_remove_funcall.c create mode 100644 chapter20/dead_store_elimination/int_only/dont_elim/loop.c create mode 100644 chapter20/dead_store_elimination/int_only/dont_elim/static_vars_at_exit.c create mode 100644 chapter20/dead_store_elimination/int_only/dont_elim/static_vars_fun.c create mode 100644 chapter20/dead_store_elimination/int_only/dont_elim/used_one_path.c create mode 100644 chapter20/dead_store_elimination/int_only/elim_second_copy.c create mode 100644 chapter20/dead_store_elimination/int_only/fig_20_12.c create mode 100644 chapter20/dead_store_elimination/int_only/loop_dead_store.c create mode 100644 chapter20/dead_store_elimination/int_only/simple.c create mode 100644 chapter20/dead_store_elimination/int_only/use_and_kill.c create mode 100644 chapter20/unreachable_code_elimination/constant_if_else.c create mode 100644 chapter20/unreachable_code_elimination/dead_after_if_else.c create mode 100644 chapter20/unreachable_code_elimination/dead_after_return.c create mode 100644 chapter20/unreachable_code_elimination/dead_branch_inside_loop.c create mode 100644 chapter20/unreachable_code_elimination/dead_for_loop.c create mode 100644 chapter20/unreachable_code_elimination/dont_elim/keep_final_jump.c create mode 100644 chapter20/unreachable_code_elimination/empty.c create mode 100644 chapter20/unreachable_code_elimination/empty_block.c create mode 100644 chapter20/unreachable_code_elimination/loop_in_dead_branch.c create mode 100644 chapter20/unreachable_code_elimination/remove_jnz.c create mode 100644 chapter20/unreachable_code_elimination/remove_useless_starting_label.c create mode 100644 chapter20/whole_pipeline/dead_condition.c create mode 100644 chapter20/whole_pipeline/elim_and_copy_prop.c create mode 100644 chapter21/all_types/no_coalescing/dbl_fun_call.c create mode 100644 chapter21/all_types/no_coalescing/dbl_trivially_colorable.c create mode 100644 chapter21/all_types/no_coalescing/div_interference.c create mode 100644 chapter21/all_types/no_coalescing/fourteen_pseudos_interfere.c create mode 100644 chapter21/all_types/no_coalescing/mixed_ints.c create mode 100644 chapter21/all_types/no_coalescing/push_xmm.c create mode 100644 chapter21/all_types/no_coalescing/spill_movz_dst.c create mode 100644 chapter21/all_types/no_coalescing/stack_alignment.c create mode 100644 chapter21/all_types/no_coalescing/store_pointer_in_register.c create mode 100644 chapter21/all_types/no_coalescing/test_spilling_dbls.c create mode 100644 chapter21/all_types/no_coalescing/track_dbl_arg_registers.c create mode 100644 chapter21/int_only/no_coalescing/callee_saved_stack_alignment.c create mode 100644 chapter21/int_only/no_coalescing/cdq_interference.c create mode 100644 chapter21/int_only/no_coalescing/cmp_liveness.c create mode 100644 chapter21/int_only/no_coalescing/copy_and_separate_interference.c create mode 100644 chapter21/int_only/no_coalescing/copy_no_interference.c create mode 100644 chapter21/int_only/no_coalescing/force_spill.c create mode 100644 chapter21/int_only/no_coalescing/idiv_interference.c create mode 100644 chapter21/int_only/no_coalescing/loop.c create mode 100644 chapter21/int_only/no_coalescing/many_pseudos_fewer_conflicts.c create mode 100644 chapter21/int_only/no_coalescing/optimistic_coloring.c create mode 100644 chapter21/int_only/no_coalescing/preserve_across_fun_call.c create mode 100644 chapter21/int_only/no_coalescing/rewrite_large_multiply.c create mode 100644 chapter21/int_only/no_coalescing/same_instr_interference.c create mode 100644 chapter21/int_only/no_coalescing/same_instr_no_interference.c create mode 100644 chapter21/int_only/no_coalescing/spill_callee_saved.c create mode 100644 chapter21/int_only/no_coalescing/spills_and_rewrites.c create mode 100644 chapter21/int_only/no_coalescing/spills_rewrites_compare.c create mode 100644 chapter21/int_only/no_coalescing/test_spill_metric.c create mode 100644 chapter21/int_only/no_coalescing/test_spill_metric_2.c create mode 100644 chapter21/int_only/no_coalescing/track_arg_registers.c create mode 100644 chapter21/int_only/no_coalescing/trivially_colorable.c create mode 100644 chapter21/int_only/no_coalescing/unary_interference.c create mode 100644 chapter21/int_only/no_coalescing/use_all_hardregs.c create mode 100644 chapter21/int_only/with_coalescing/bin_generates_dst.c create mode 100644 chapter21/int_only/with_coalescing/briggs_coalesce.c create mode 100644 chapter21/int_only/with_coalescing/briggs_coalesce_tmps.c create mode 100644 chapter21/int_only/with_coalescing/callee_saved_live_at_exit.c create mode 100644 chapter21/int_only/with_coalescing/cdq_generates_ax.c create mode 100644 chapter21/int_only/with_coalescing/cmp_generates_operands.c create mode 100644 chapter21/int_only/with_coalescing/coalesce_prevents_spill.c create mode 100644 chapter21/int_only/with_coalescing/eax_live_at_exit.c create mode 100644 chapter21/int_only/with_coalescing/funcall_generates_args.c create mode 100644 chapter21/int_only/with_coalescing/george_coalesce.c create mode 100644 chapter21/int_only/with_coalescing/unary_generates_dst.c create mode 100644 chapter21/libraries/callee_saved_live_at_exit_lib.c create mode 100644 chapter21/libraries/coalesce_prevents_spill_lib.c create mode 100644 chapter21/libraries/force_spill_dbl_lib.c create mode 100644 chapter21/libraries/force_spill_lib.c create mode 100644 chapter21/libraries/force_spill_mixed_int_lib.c create mode 100644 chapter21/libraries/funcall_generates_args_lib.c create mode 100644 chapter21/libraries/george_lib.c create mode 100644 chapter21/libraries/many_pseudos_fewer_conflicts_lib.c create mode 100644 chapter21/libraries/test_spill_metric_2_lib.c create mode 100644 chapter21/libraries/test_spill_metric_lib.c create mode 100644 chapter21/libraries/test_spilling_dbls_lib.c create mode 100644 chapter21/libraries/track_arg_registers_lib.c create mode 100644 chapter21/libraries/track_dbl_arg_registers_lib.c create mode 100644 chapter21/wrapper_linux.s create mode 100644 chapter21/wrapper_osx.s rename chapter4/{invalid_parse_bitwise/double_operator.c => invalid_parse/extra_credit/bitwise_double_operator.c} (100%) rename chapter4/{valid_bitwise/bit_and.c => valid/extra_credit/bitwise_and.c} (100%) rename chapter4/{valid_bitwise/bit_or.c => valid/extra_credit/bitwise_or.c} (100%) rename chapter4/{valid_bitwise => valid/extra_credit}/bitwise_precedence.c (100%) rename chapter4/{valid_bitwise/shift_associativity.c => valid/extra_credit/bitwise_shift_associativity.c} (100%) rename chapter4/{valid_bitwise/shift_associativity_2.c => valid/extra_credit/bitwise_shift_associativity_2.c} (100%) create mode 100644 chapter4/valid/extra_credit/bitwise_shift_precedence.c rename chapter4/{valid_bitwise/shiftl.c => valid/extra_credit/bitwise_shiftl.c} (100%) rename chapter4/{valid_bitwise/shiftr.c => valid/extra_credit/bitwise_shiftr.c} (100%) rename chapter4/{valid_bitwise/bit_xor.c => valid/extra_credit/bitwise_xor.c} (100%) delete mode 100644 chapter4/valid_bitwise/shift_precedence.c rename chapter5/{valid_bitwise => valid/extra_credit}/bitwise_precedence.c (100%) rename chapter6/{invalid_parse_extra_credit => invalid_parse/extra_credit}/compound_initializer.c (100%) rename chapter6/{invalid_parse_extra_credit => invalid_parse/extra_credit}/compound_invalid_operator.c (100%) rename chapter6/{invalid_semantics_extra_credit => invalid_semantics/extra_credit}/compound_initializer.c (100%) rename chapter6/{invalid_semantics_extra_credit => invalid_semantics/extra_credit}/compound_invalid_lvalue.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/bitwise_and_vars.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/bitwise_shiftl_variable.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/bitwise_shiftr_assign.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_assignment_chained.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_assignment_use_result.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_bitwise_and.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_bitwise_or.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_bitwise_shiftl.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_bitwise_shiftr.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_bitwise_xor.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_divide.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_minus.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_mod.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_multiply.c (100%) rename chapter6/{valid_extra_credit => valid/extra_credit}/compound_plus.c (100%) rename chapter7/{invalid_parse_extra_credit/invalid_label.c => invalid_lex/extra_credit/goto_bad_label.c} (100%) rename chapter7/{invalid_parse_extra_credit/label_without_statement.c => invalid_parse/extra_credit/goto_label_without_statement.c} (100%) rename chapter7/{invalid_semantics_extra_credit => invalid_semantics/extra_credit}/goto_missing_label.c (100%) rename chapter7/{valid_extra_credit => valid/extra_credit}/bitwise_ternary.c (100%) rename chapter7/{valid_extra_credit => valid/extra_credit}/compound_if_expression.c (100%) rename chapter7/{valid_extra_credit => valid/extra_credit}/goto_after_declaration.c (100%) rename chapter7/{valid_extra_credit => valid/extra_credit}/goto_backwards.c (100%) rename chapter7/{valid_extra_credit => valid/extra_credit}/goto_label.c (100%) rename chapter7/{valid_extra_credit/label_and_var.c => valid/extra_credit/goto_label_and_var.c} (100%) rename chapter7/{valid_extra_credit/label_main.c => valid/extra_credit/goto_label_main.c} (100%) rename chapter7/{valid_extra_credit/label_main_2.c => valid/extra_credit/goto_label_main_2.c} (100%) rename chapter7/{valid_extra_credit/nested_label.c => valid/extra_credit/goto_nested_label.c} (100%) rename chapter8/{invalid_semantics_extra_credit => invalid_semantics/extra_credit}/goto_use_before_declare.c (100%) delete mode 100644 chapter8/invalid_semantics_extra_credit/use_before_declare.c rename chapter8/{valid_extra_credit => valid/extra_credit}/compound_subtract_in_block.c (100%) rename chapter8/{valid_extra_credit => valid/extra_credit}/goto_before_declaration.c (100%) rename chapter8/{valid_extra_credit => valid/extra_credit}/goto_inner_scope.c (100%) rename chapter9/{invalid_parse_extra_credit => invalid_parse/extra_credit}/compound_assignment_invalid_decl.c (100%) rename chapter9/{invalid_parse_extra_credit => invalid_parse/extra_credit}/switch_case_declaration.c (100%) rename chapter9/{invalid_parse_extra_credit => invalid_parse/extra_credit}/switch_goto_case.c (100%) rename chapter9/{invalid_parse_extra_credit => invalid_parse/extra_credit}/switch_missing_case_value.c (100%) rename chapter9/{invalid_parse_extra_credit => invalid_parse/extra_credit}/switch_missing_paren.c (100%) rename chapter9/{invalid_parse_extra_credit => invalid_parse/extra_credit}/switch_no_condition.c (100%) rename chapter9/{invalid_semantics_extra_credit => invalid_semantics/extra_credit}/switch_continue.c (100%) rename chapter9/{invalid_semantics_extra_credit => invalid_semantics/extra_credit}/switch_duplicate_case.c (100%) rename chapter9/{invalid_semantics_extra_credit => invalid_semantics/extra_credit}/switch_duplicate_default.c (100%) rename chapter9/{invalid_semantics_extra_credit => invalid_semantics/extra_credit}/switch_invalid_case.c (100%) rename chapter9/{invalid_semantics_extra_credit => invalid_semantics/extra_credit}/switch_invalid_default.c (100%) rename chapter9/{invalid_semantics_extra_credit => invalid_semantics/extra_credit}/switch_non_constant_case.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/compound_assignment_for_loop.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/goto_bypass_condition.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/goto_loop_body.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_assign_in_body.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_assign_in_condition.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_block.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_break.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_decl.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_default.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_default_fallthrough.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_default_not_last.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_empty.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_fallthrough.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_goto_mid_case.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_in_loop.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_nested_case.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_nested_not_taken.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_nested_switch.c (100%) rename chapter9/{valid_extra_credit => valid/extra_credit}/switch_no_case.c (100%) rename chapter9/{valid_extra_credit/continue_in_switch.c => valid/extra_credit/switch_with_continue.c} (100%) rename chapter9/{valid_extra_credit/loop_in_switch.c => valid/extra_credit/switch_with_loop.c} (100%) create mode 100755 generate_expected_results.py create mode 100755 test_compiler create mode 100644 test_properties.json create mode 100644 tests/__init__.py create mode 100644 tests/basic.py create mode 100644 tests/parser/__init__.py create mode 100644 tests/parser/asm.py create mode 100644 tests/parser/parse.py create mode 100644 tests/parser/tokenize.py create mode 100644 tests/regalloc.py create mode 100644 tests/runner.py create mode 100644 tests/tacky/__init__.py create mode 100644 tests/tacky/common.py create mode 100644 tests/tacky/const_fold.py create mode 100644 tests/tacky/copy_prop.py create mode 100644 tests/tacky/dead_store_elim.py create mode 100644 tests/tacky/suite.py create mode 100644 tests/tacky/unreachable.py create mode 100644 tests/test_tests/__init__.py create mode 100644 tests/test_tests/test_parse.py create mode 100644 tests/test_tests/test_tokenize.py diff --git a/.gitignore b/.gitignore index fa929750..c118678a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -*.out \ No newline at end of file +**/__pycache__/* +mycc +*.s \ No newline at end of file diff --git a/chapter10/invalid_parse/nested_function_definition.c b/chapter10/invalid_declarations/nested_function_definition.c similarity index 100% rename from chapter10/invalid_parse/nested_function_definition.c rename to chapter10/invalid_declarations/nested_function_definition.c diff --git a/chapter10/invalid_labels_extra_credit/goto_cross_function.c b/chapter10/invalid_labels/extra_credit/goto_cross_function.c similarity index 100% rename from chapter10/invalid_labels_extra_credit/goto_cross_function.c rename to chapter10/invalid_labels/extra_credit/goto_cross_function.c diff --git a/chapter10/invalid_labels_extra_credit/goto_function.c b/chapter10/invalid_labels/extra_credit/goto_function.c similarity index 100% rename from chapter10/invalid_labels_extra_credit/goto_function.c rename to chapter10/invalid_labels/extra_credit/goto_function.c diff --git a/chapter10/invalid_types_extra_credit/compound_assignment_function_call.c b/chapter10/invalid_types/extra_credit/compound_assignment_function_call.c similarity index 100% rename from chapter10/invalid_types_extra_credit/compound_assignment_function_call.c rename to chapter10/invalid_types/extra_credit/compound_assignment_function_call.c diff --git a/chapter10/invalid_types_extra_credit/switch_on_function.c b/chapter10/invalid_types/extra_credit/switch_on_function.c similarity index 100% rename from chapter10/invalid_types_extra_credit/switch_on_function.c rename to chapter10/invalid_types/extra_credit/switch_on_function.c diff --git a/chapter10/valid_extra_credit/compound_assign_function_result.c b/chapter10/valid/extra_credit/compound_assign_function_result.c similarity index 100% rename from chapter10/valid_extra_credit/compound_assign_function_result.c rename to chapter10/valid/extra_credit/compound_assign_function_result.c diff --git a/chapter10/valid_extra_credit/goto_label_multiple_functions.c b/chapter10/valid/extra_credit/goto_label_multiple_functions.c similarity index 100% rename from chapter10/valid_extra_credit/goto_label_multiple_functions.c rename to chapter10/valid/extra_credit/goto_label_multiple_functions.c diff --git a/chapter10/valid_extra_credit/goto_shared_name.c b/chapter10/valid/extra_credit/goto_shared_name.c similarity index 100% rename from chapter10/valid_extra_credit/goto_shared_name.c rename to chapter10/valid/extra_credit/goto_shared_name.c diff --git a/chapter11/invalid_labels_extra_credit/goto_file_scope_label.c b/chapter11/invalid_labels/extra_credit/goto_file_scope_label.c similarity index 100% rename from chapter11/invalid_labels_extra_credit/goto_file_scope_label.c rename to chapter11/invalid_labels/extra_credit/goto_file_scope_label.c diff --git a/chapter11/invalid_labels_extra_credit/goto_global_var.c b/chapter11/invalid_labels/extra_credit/goto_global_var.c similarity index 100% rename from chapter11/invalid_labels_extra_credit/goto_global_var.c rename to chapter11/invalid_labels/extra_credit/goto_global_var.c diff --git a/chapter11/valid_extra_credit/goto_skip_static_initializer.c b/chapter11/valid/extra_credit/goto_skip_static_initializer.c similarity index 100% rename from chapter11/valid_extra_credit/goto_skip_static_initializer.c rename to chapter11/valid/extra_credit/goto_skip_static_initializer.c diff --git a/chapter12/invalid_labels_extra_credit/switch_duplicate_cases.c b/chapter12/invalid_labels/extra_credit/switch_duplicate_cases.c similarity index 100% rename from chapter12/invalid_labels_extra_credit/switch_duplicate_cases.c rename to chapter12/invalid_labels/extra_credit/switch_duplicate_cases.c diff --git a/chapter12/valid_extra_credit/bitwise_long_op.c b/chapter12/valid/extra_credit/bitwise_long_op.c similarity index 100% rename from chapter12/valid_extra_credit/bitwise_long_op.c rename to chapter12/valid/extra_credit/bitwise_long_op.c diff --git a/chapter12/valid_extra_credit/compound_assign_to_int.c b/chapter12/valid/extra_credit/compound_assign_to_int.c similarity index 100% rename from chapter12/valid_extra_credit/compound_assign_to_int.c rename to chapter12/valid/extra_credit/compound_assign_to_int.c diff --git a/chapter12/valid_extra_credit/compound_assign_to_long.c b/chapter12/valid/extra_credit/compound_assign_to_long.c similarity index 100% rename from chapter12/valid_extra_credit/compound_assign_to_long.c rename to chapter12/valid/extra_credit/compound_assign_to_long.c diff --git a/chapter12/valid_extra_credit/switch_int.c b/chapter12/valid/extra_credit/switch_int.c similarity index 100% rename from chapter12/valid_extra_credit/switch_int.c rename to chapter12/valid/extra_credit/switch_int.c diff --git a/chapter12/valid_extra_credit/switch_long.c b/chapter12/valid/extra_credit/switch_long.c similarity index 100% rename from chapter12/valid_extra_credit/switch_long.c rename to chapter12/valid/extra_credit/switch_long.c diff --git a/chapter13/invalid_labels_extra_credit/switch_duplicate_cases.c b/chapter13/invalid_labels/extra_credit/switch_duplicate_cases.c similarity index 100% rename from chapter13/invalid_labels_extra_credit/switch_duplicate_cases.c rename to chapter13/invalid_labels/extra_credit/switch_duplicate_cases.c diff --git a/chapter13/valid_extra_credit/bitwise_unsigned_ops.c b/chapter13/valid/extra_credit/bitwise_unsigned_ops.c similarity index 100% rename from chapter13/valid_extra_credit/bitwise_unsigned_ops.c rename to chapter13/valid/extra_credit/bitwise_unsigned_ops.c diff --git a/chapter13/valid_extra_credit/bitwise_unsigned_shift.c b/chapter13/valid/extra_credit/bitwise_unsigned_shift.c similarity index 100% rename from chapter13/valid_extra_credit/bitwise_unsigned_shift.c rename to chapter13/valid/extra_credit/bitwise_unsigned_shift.c diff --git a/chapter13/valid_extra_credit/compound_assign_uint.c b/chapter13/valid/extra_credit/compound_assign_uint.c similarity index 100% rename from chapter13/valid_extra_credit/compound_assign_uint.c rename to chapter13/valid/extra_credit/compound_assign_uint.c diff --git a/chapter13/valid_extra_credit/switch_uint.c b/chapter13/valid/extra_credit/switch_uint.c similarity index 100% rename from chapter13/valid_extra_credit/switch_uint.c rename to chapter13/valid/extra_credit/switch_uint.c diff --git a/chapter14/invalid_types_extra_credit/bitwise_and.c b/chapter14/invalid_types/extra_credit/bitwise_and.c similarity index 100% rename from chapter14/invalid_types_extra_credit/bitwise_and.c rename to chapter14/invalid_types/extra_credit/bitwise_and.c diff --git a/chapter14/invalid_types_extra_credit/bitwise_or.c b/chapter14/invalid_types/extra_credit/bitwise_or.c similarity index 100% rename from chapter14/invalid_types_extra_credit/bitwise_or.c rename to chapter14/invalid_types/extra_credit/bitwise_or.c diff --git a/chapter14/invalid_types_extra_credit/bitwise_shift_double.c b/chapter14/invalid_types/extra_credit/bitwise_shift_double.c similarity index 100% rename from chapter14/invalid_types_extra_credit/bitwise_shift_double.c rename to chapter14/invalid_types/extra_credit/bitwise_shift_double.c diff --git a/chapter14/invalid_types_extra_credit/bitwise_xor.c b/chapter14/invalid_types/extra_credit/bitwise_xor.c similarity index 100% rename from chapter14/invalid_types_extra_credit/bitwise_xor.c rename to chapter14/invalid_types/extra_credit/bitwise_xor.c diff --git a/chapter14/invalid_types_extra_credit/switch_double_case.c b/chapter14/invalid_types/extra_credit/switch_double_case.c similarity index 100% rename from chapter14/invalid_types_extra_credit/switch_double_case.c rename to chapter14/invalid_types/extra_credit/switch_double_case.c diff --git a/chapter14/invalid_types_extra_credit/switch_on_double.c b/chapter14/invalid_types/extra_credit/switch_on_double.c similarity index 100% rename from chapter14/invalid_types_extra_credit/switch_on_double.c rename to chapter14/invalid_types/extra_credit/switch_on_double.c diff --git a/chapter14/valid_extra_credit/compound_assign.c b/chapter14/valid/extra_credit/compound_assign.c similarity index 100% rename from chapter14/valid_extra_credit/compound_assign.c rename to chapter14/valid/extra_credit/compound_assign.c diff --git a/chapter14/valid_extra_credit/compound_assign_implicit_cast.c b/chapter14/valid/extra_credit/compound_assign_implicit_cast.c similarity index 100% rename from chapter14/valid_extra_credit/compound_assign_implicit_cast.c rename to chapter14/valid/extra_credit/compound_assign_implicit_cast.c diff --git a/chapter14/valid_extra_credit/nan.c b/chapter14/valid/extra_credit/nan.c similarity index 100% rename from chapter14/valid_extra_credit/nan.c rename to chapter14/valid/extra_credit/nan.c diff --git a/chapter15/invalid_types_extra_credit/bitwise_or_pointer.c b/chapter15/invalid_types/extra_credit/bitwise_or_pointer.c similarity index 100% rename from chapter15/invalid_types_extra_credit/bitwise_or_pointer.c rename to chapter15/invalid_types/extra_credit/bitwise_or_pointer.c diff --git a/chapter15/invalid_types_extra_credit/bitwise_shift_pointer.c b/chapter15/invalid_types/extra_credit/bitwise_shift_pointer.c similarity index 100% rename from chapter15/invalid_types_extra_credit/bitwise_shift_pointer.c rename to chapter15/invalid_types/extra_credit/bitwise_shift_pointer.c diff --git a/chapter15/invalid_types_extra_credit/compound_divide_pointer.c b/chapter15/invalid_types/extra_credit/compound_divide_pointer.c similarity index 100% rename from chapter15/invalid_types_extra_credit/compound_divide_pointer.c rename to chapter15/invalid_types/extra_credit/compound_divide_pointer.c diff --git a/chapter15/invalid_types_extra_credit/compound_multiply_pointer.c b/chapter15/invalid_types/extra_credit/compound_multiply_pointer.c similarity index 100% rename from chapter15/invalid_types_extra_credit/compound_multiply_pointer.c rename to chapter15/invalid_types/extra_credit/compound_multiply_pointer.c diff --git a/chapter15/invalid_types_extra_credit/switch_on_pointer.c b/chapter15/invalid_types/extra_credit/switch_on_pointer.c similarity index 100% rename from chapter15/invalid_types_extra_credit/switch_on_pointer.c rename to chapter15/invalid_types/extra_credit/switch_on_pointer.c diff --git a/chapter15/valid_extra_credit/compound_assign_through_pointer.c b/chapter15/valid/extra_credit/compound_assign_through_pointer.c similarity index 100% rename from chapter15/valid_extra_credit/compound_assign_through_pointer.c rename to chapter15/valid/extra_credit/compound_assign_through_pointer.c diff --git a/chapter15/valid_extra_credit/incr_through_pointer.c b/chapter15/valid/extra_credit/incr_through_pointer.c similarity index 100% rename from chapter15/valid_extra_credit/incr_through_pointer.c rename to chapter15/valid/extra_credit/incr_through_pointer.c diff --git a/chapter16/valid_extra_credit/incr_ptr.c b/chapter16/valid/extra_credit/incr_ptr.c similarity index 100% rename from chapter16/valid_extra_credit/incr_ptr.c rename to chapter16/valid/extra_credit/incr_ptr.c diff --git a/chapter20/all_optimizations/all_types/alias_analysis_change.c b/chapter20/all_optimizations/all_types/alias_analysis_change.c new file mode 100644 index 00000000..a67e2a18 --- /dev/null +++ b/chapter20/all_optimizations/all_types/alias_analysis_change.c @@ -0,0 +1,19 @@ +int foo(int *ptr) +{ + return 2; +} + +int main() +{ + int x = 10; + int *ptr = 0; + if (0) + { + // need to update alias after dead code elim to recognize that + // x is not actually aliased + ptr = &x; + } + x = 5; // this is a dead store + foo(ptr); // why isn't 0 propagated to here? + return 0; +} \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/add_doubles.c b/chapter20/constant_folding/all_types/add_doubles.c new file mode 100644 index 00000000..14777518 --- /dev/null +++ b/chapter20/constant_folding/all_types/add_doubles.c @@ -0,0 +1,3 @@ +double target() { return 2.1 * 3.0; } + +int main() { return target() == 6.300000000000001; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/double_to_char.c b/chapter20/constant_folding/all_types/double_to_char.c new file mode 100644 index 00000000..fec7119b --- /dev/null +++ b/chapter20/constant_folding/all_types/double_to_char.c @@ -0,0 +1,3 @@ +char target() { return 126.5; } + +int main() { return target() == 126; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/double_to_int.c b/chapter20/constant_folding/all_types/double_to_int.c new file mode 100644 index 00000000..6360a6b7 --- /dev/null +++ b/chapter20/constant_folding/all_types/double_to_int.c @@ -0,0 +1,3 @@ +int target() { return 5.9; } + +int main() { return target() == 5; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/double_to_uint.c b/chapter20/constant_folding/all_types/double_to_uint.c new file mode 100644 index 00000000..e7203813 --- /dev/null +++ b/chapter20/constant_folding/all_types/double_to_uint.c @@ -0,0 +1,3 @@ +unsigned target() { return 2147483750.5; } + +int main() { return target() == 2147483750u; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/double_to_ulong.c b/chapter20/constant_folding/all_types/double_to_ulong.c new file mode 100644 index 00000000..4f65e3f4 --- /dev/null +++ b/chapter20/constant_folding/all_types/double_to_ulong.c @@ -0,0 +1,3 @@ +unsigned long target() { return 3458764513821589504.0; } + +int main() { return target() == 3458764513821589504ul; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/gt_unsigned.c b/chapter20/constant_folding/all_types/gt_unsigned.c new file mode 100644 index 00000000..7b3869f1 --- /dev/null +++ b/chapter20/constant_folding/all_types/gt_unsigned.c @@ -0,0 +1,6 @@ +int target() { + // make sure we're using unsigned compare + return 2147483653u > 10u; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/long_complement.c b/chapter20/constant_folding/all_types/long_complement.c new file mode 100644 index 00000000..1fa13fd5 --- /dev/null +++ b/chapter20/constant_folding/all_types/long_complement.c @@ -0,0 +1,3 @@ +long target() { return ~100l; } + +int main() { return target() == -101l; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/long_to_double.c b/chapter20/constant_folding/all_types/long_to_double.c new file mode 100644 index 00000000..64a1ff15 --- /dev/null +++ b/chapter20/constant_folding/all_types/long_to_double.c @@ -0,0 +1,3 @@ +double target() { return 9007199254751227l; } + +int main() { return target() == 9007199254751228.0; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/lt_long.c b/chapter20/constant_folding/all_types/lt_long.c new file mode 100644 index 00000000..673f7b5c --- /dev/null +++ b/chapter20/constant_folding/all_types/lt_long.c @@ -0,0 +1,3 @@ +int target() { return 4294967296l <= 0l; } + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/negate_double_zero.c b/chapter20/constant_folding/all_types/negate_double_zero.c new file mode 100644 index 00000000..411c4942 --- /dev/null +++ b/chapter20/constant_folding/all_types/negate_double_zero.c @@ -0,0 +1,6 @@ +double target() { return -0.0; } + +int main() { + // 1/0 is infinity, 1/-0 is negative infinity + return (1 / target()) < 0.0; +} \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/negate_long.c b/chapter20/constant_folding/all_types/negate_long.c new file mode 100644 index 00000000..0fda7d48 --- /dev/null +++ b/chapter20/constant_folding/all_types/negate_long.c @@ -0,0 +1,13 @@ +long target() { + // note: my implementation failed this test + // because I converted from the 64-bit Int64 type + // to the 63 bit int type to perform negation! + return -9223372036854775716l; +} + +int main() { + + long l = target(); + unsigned long l2 = 9223372036854775900u; + return l == l2; +} \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/negate_unsigned_long.c b/chapter20/constant_folding/all_types/negate_unsigned_long.c new file mode 100644 index 00000000..69af390a --- /dev/null +++ b/chapter20/constant_folding/all_types/negate_unsigned_long.c @@ -0,0 +1,11 @@ +unsigned long target() { + unsigned long l = -(9223372036854775900ul); + return l; +} + +int main() { + // equivalent test to negate_long + unsigned long l = target(); + long l2 = (long)l; + return (l2 - 9223372036854775716l == 0); +} \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/truncate_to_char.c b/chapter20/constant_folding/all_types/truncate_to_char.c new file mode 100644 index 00000000..22ab8a96 --- /dev/null +++ b/chapter20/constant_folding/all_types/truncate_to_char.c @@ -0,0 +1,3 @@ +char target() { return 1144; } + +int main() { return target() == 120; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/truncate_to_uchar.c b/chapter20/constant_folding/all_types/truncate_to_uchar.c new file mode 100644 index 00000000..5f3993fd --- /dev/null +++ b/chapter20/constant_folding/all_types/truncate_to_uchar.c @@ -0,0 +1,3 @@ +unsigned char target() { return 1274; } + +int main() { return target() == 250; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/uint_div.c b/chapter20/constant_folding/all_types/uint_div.c new file mode 100644 index 00000000..f8dc8668 --- /dev/null +++ b/chapter20/constant_folding/all_types/uint_div.c @@ -0,0 +1,3 @@ +unsigned target() { return 4294967286u / 10u; } + +int main() { return target() == 429496728u; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/uint_mult.c b/chapter20/constant_folding/all_types/uint_mult.c new file mode 100644 index 00000000..72a1cc9e --- /dev/null +++ b/chapter20/constant_folding/all_types/uint_mult.c @@ -0,0 +1,7 @@ +unsigned target() { + return 4294967286u * 3u; +} + +int main() { + return target() == 4294967266u; +} \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/ulong_div.c b/chapter20/constant_folding/all_types/ulong_div.c new file mode 100644 index 00000000..e80f04ab --- /dev/null +++ b/chapter20/constant_folding/all_types/ulong_div.c @@ -0,0 +1,3 @@ +unsigned long target() { return 18446744073709551614ul / 10ul; } + +int main() { return target() == 1844674407370955161ul; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/ulong_to_double.c b/chapter20/constant_folding/all_types/ulong_to_double.c new file mode 100644 index 00000000..cf7559be --- /dev/null +++ b/chapter20/constant_folding/all_types/ulong_to_double.c @@ -0,0 +1,3 @@ +double target() { return 10223372036854775816ul; } + +int main() { return target() == 10223372036854775808.0; } \ No newline at end of file diff --git a/chapter20/constant_folding/all_types/zero_extend.c b/chapter20/constant_folding/all_types/zero_extend.c new file mode 100644 index 00000000..ecb6c341 --- /dev/null +++ b/chapter20/constant_folding/all_types/zero_extend.c @@ -0,0 +1,3 @@ +long target() { return 4294967295u; } + +int main() { return target() == 4294967295l; } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_add.c b/chapter20/constant_folding/int_only/fold_add.c new file mode 100644 index 00000000..580f9ccd --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_add.c @@ -0,0 +1,7 @@ +int target() { + // look for movl $300, + // and no add instruction + return 100 + 200; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_complement.c b/chapter20/constant_folding/int_only/fold_complement.c new file mode 100644 index 00000000..66348d75 --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_complement.c @@ -0,0 +1,3 @@ +int target() { return ~1; } + +int main() { return target() == -2; } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_dead_branch.c b/chapter20/constant_folding/int_only/fold_dead_branch.c new file mode 100644 index 00000000..eeae9863 --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_dead_branch.c @@ -0,0 +1,10 @@ +int target() { + // look for: + // - jmp lbl instead of je lbl + // - no cmpl instructions + if (0) + return 1; + return 0; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_divide_by_zero.c b/chapter20/constant_folding/int_only/fold_divide_by_zero.c new file mode 100644 index 00000000..6009cbbc --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_divide_by_zero.c @@ -0,0 +1,11 @@ +int target() { + return 0; // dummy so that test case doesn't inspect main, which isn't fully + // constant folded +} + +int main() { + // make sure that compilation doesn't fail when we attempt to constant fold + // 1/0 + // TODO analogous tests for overflow and part II conversions + return 1 || (1 / 0) || (1 % 0); +} \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_eq.c b/chapter20/constant_folding/int_only/fold_eq.c new file mode 100644 index 00000000..094065ee --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_eq.c @@ -0,0 +1,6 @@ +int target() { + int flag1 = 100 == 100; + return flag1; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_gt.c b/chapter20/constant_folding/int_only/fold_gt.c new file mode 100644 index 00000000..2579fdba --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_gt.c @@ -0,0 +1,3 @@ +int target() { return 10 > 10; } + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_jumpifnotzero_to_jump.c b/chapter20/constant_folding/int_only/fold_jumpifnotzero_to_jump.c new file mode 100644 index 00000000..25ce7181 --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_jumpifnotzero_to_jump.c @@ -0,0 +1,5 @@ +int target() { + // look for: no cmpl, no jne + return 3 || 99; +} +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_jumpifzero_to_jump.c b/chapter20/constant_folding/int_only/fold_jumpifzero_to_jump.c new file mode 100644 index 00000000..8bf584ef --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_jumpifzero_to_jump.c @@ -0,0 +1,7 @@ +int target() { + // look for: no conditional jumps, no cmp instruction + int x = 0 && 0; + return x; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_mult.c b/chapter20/constant_folding/int_only/fold_mult.c new file mode 100644 index 00000000..45482575 --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_mult.c @@ -0,0 +1,3 @@ +int target() { return 1000 * 1000; } + +int main() { return target() == 1000000; } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_negate.c b/chapter20/constant_folding/int_only/fold_negate.c new file mode 100644 index 00000000..37c6a72b --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_negate.c @@ -0,0 +1,7 @@ +int target() { + // look for instruction movl -3, + // and no negl instruction + return -3; +} + +int main() { return target() == -3; } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_neq.c b/chapter20/constant_folding/int_only/fold_neq.c new file mode 100644 index 00000000..a382fb28 --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_neq.c @@ -0,0 +1,3 @@ +int target() { return 1111 != 1112; } + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_not.c b/chapter20/constant_folding/int_only/fold_not.c new file mode 100644 index 00000000..5b2b1595 --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_not.c @@ -0,0 +1,2 @@ +int target() { return !1024; } +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_not_zero.c b/chapter20/constant_folding/int_only/fold_not_zero.c new file mode 100644 index 00000000..fa4eb287 --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_not_zero.c @@ -0,0 +1,3 @@ +int target() { return !0; } + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_overflow.c b/chapter20/constant_folding/int_only/fold_overflow.c new file mode 100644 index 00000000..fd2b48a3 --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_overflow.c @@ -0,0 +1,6 @@ +int target() { return 0; } + +int main() { + // overflow in dead code shouldn't cause error + return 0 && (2147483647 + 10); +} \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_remainder.c b/chapter20/constant_folding/int_only/fold_remainder.c new file mode 100644 index 00000000..1f03e853 --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_remainder.c @@ -0,0 +1,3 @@ +int target() { return 10 % 3; } + +int main() { return target() == 3; } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/fold_sub.c b/chapter20/constant_folding/int_only/fold_sub.c new file mode 100644 index 00000000..641ab5b0 --- /dev/null +++ b/chapter20/constant_folding/int_only/fold_sub.c @@ -0,0 +1,3 @@ +int target() { return 2 - 2147483647; } + +int main() { return target() == -2147483645; } \ No newline at end of file diff --git a/chapter20/constant_folding/int_only/remove_jz.c b/chapter20/constant_folding/int_only/remove_jz.c new file mode 100644 index 00000000..9af3e984 --- /dev/null +++ b/chapter20/constant_folding/int_only/remove_jz.c @@ -0,0 +1,6 @@ +int target() { + // no je or jne or conditional set instructions, no cmp, at most one jmp + return 1 && 1; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/alias_analysis.c b/chapter20/copy_propagation/all_types/alias_analysis.c new file mode 100644 index 00000000..e50471eb --- /dev/null +++ b/chapter20/copy_propagation/all_types/alias_analysis.c @@ -0,0 +1,16 @@ +void callee(int *ptr) { *ptr = -1; } + +int target() { + int i = 10; + int j = 20; + callee(&i); + i = 4; + + // look for movl $24, %eax (w/ constant fold enabled) + // can propagate i b/c there are no stores + // or function calls after i = 4 + // can propagate j b/c it's not aliased + return i + j; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/char_round_trip.c b/chapter20/copy_propagation/all_types/char_round_trip.c new file mode 100644 index 00000000..1db5ba69 --- /dev/null +++ b/chapter20/copy_propagation/all_types/char_round_trip.c @@ -0,0 +1,7 @@ +int target() { + int i = 257; + char c = i; + return (int)c; // +} + +int main() { return target() == 1; } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/char_round_trip_2.c b/chapter20/copy_propagation/all_types/char_round_trip_2.c new file mode 100644 index 00000000..946cf715 --- /dev/null +++ b/chapter20/copy_propagation/all_types/char_round_trip_2.c @@ -0,0 +1,8 @@ +int target() { + int i = 255; + char c = (char)i; + i = (int)c; + return i; // -1 +} + +int main() { return target() == -1; } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/char_type_conversion.c b/chapter20/copy_propagation/all_types/char_type_conversion.c new file mode 100644 index 00000000..6eb357ff --- /dev/null +++ b/chapter20/copy_propagation/all_types/char_type_conversion.c @@ -0,0 +1,10 @@ +int target() { + char i = 200; + signed char j = i; + // w/ constant folding, should be able to reduce this to 1 + // this tests that we can propagate chars to replace sigend chars and vice + // versa they're effectively the same type + return i == j; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/const_fold_sign_extend.c b/chapter20/copy_propagation/all_types/const_fold_sign_extend.c new file mode 100644 index 00000000..80200a17 --- /dev/null +++ b/chapter20/copy_propagation/all_types/const_fold_sign_extend.c @@ -0,0 +1,3 @@ +long target() { return -1000; } + +int main() { return target() == -1000l; } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/const_fold_sign_extend_2.c b/chapter20/copy_propagation/all_types/const_fold_sign_extend_2.c new file mode 100644 index 00000000..801d3b51 --- /dev/null +++ b/chapter20/copy_propagation/all_types/const_fold_sign_extend_2.c @@ -0,0 +1,3 @@ +unsigned long target() { return -1000; } + +int main() { return target() == 18446744073709550616ul; } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/const_fold_type_conversions.c b/chapter20/copy_propagation/all_types/const_fold_type_conversions.c new file mode 100644 index 00000000..b0bd6866 --- /dev/null +++ b/chapter20/copy_propagation/all_types/const_fold_type_conversions.c @@ -0,0 +1,11 @@ +// check that we correctly propagate copies into type conversion instructions + +unsigned long target() { + unsigned char c = 250; + int i = c * 2; // 500 + double d = i * 1000.; // 500000.0 + unsigned long l = d / 6.0; // 83333 + return l; +} + +int main() { return target() == 83333u; } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/copy_struct.c b/chapter20/copy_propagation/all_types/copy_struct.c new file mode 100644 index 00000000..d19703e9 --- /dev/null +++ b/chapter20/copy_propagation/all_types/copy_struct.c @@ -0,0 +1,17 @@ +struct s { + int x; + int y; +}; + +int callee(struct s a, struct s b) { return a.x + b.x; } + +int target() { + struct s s1 = {1, 2}; + struct s s2 = {3, 4}; + s1 = s2; // generate s1 = s2 + + // pass same value for both arguments + return callee(s1, s2); +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/dont_propagate/copy_to_offset.c b/chapter20/copy_propagation/all_types/dont_propagate/copy_to_offset.c new file mode 100644 index 00000000..eac7f16c --- /dev/null +++ b/chapter20/copy_propagation/all_types/dont_propagate/copy_to_offset.c @@ -0,0 +1,13 @@ +struct s { + int x; + int y; +}; + +int main() { + static struct s s1 = {1, 2}; + struct s s2 = {3, 4}; + s1 = s2; // generate s1 = s2 + s2.x = 3; // kill s1 = s2 + + return s1.x; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/dont_propagate/dont_propagate_addr_of.c b/chapter20/copy_propagation/all_types/dont_propagate/dont_propagate_addr_of.c new file mode 100644 index 00000000..bbfb6edf --- /dev/null +++ b/chapter20/copy_propagation/all_types/dont_propagate/dont_propagate_addr_of.c @@ -0,0 +1,7 @@ +int main() +{ + int x = 1; + int y = 2; + x = y; + return &x == &y; // don't rewrite as &y == &y +} \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/dont_propagate/funcall_kills_aliased.c b/chapter20/copy_propagation/all_types/dont_propagate/funcall_kills_aliased.c new file mode 100644 index 00000000..4ce7fa31 --- /dev/null +++ b/chapter20/copy_propagation/all_types/dont_propagate/funcall_kills_aliased.c @@ -0,0 +1,22 @@ +double *ptr = 0; + +void save_ptr(double *to_save) +{ + ptr = to_save; +} + +void update_ptr() +{ + *ptr = 2.0; +} + +int main() +{ + double d = 10.0; + double *ptr = &d; + double *another_ptr = (double *)(int *)ptr; + save_ptr(another_ptr); + d = 1.0; + update_ptr(); + return d; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/dont_propagate/static_are_aliased.c b/chapter20/copy_propagation/all_types/dont_propagate/static_are_aliased.c new file mode 100644 index 00000000..99c1a95e --- /dev/null +++ b/chapter20/copy_propagation/all_types/dont_propagate/static_are_aliased.c @@ -0,0 +1,12 @@ +int stat; + +int target(int *stat_ptr) { + stat = 10; + *stat_ptr = 8; + return stat; +} + +int main() { + int *ptr = &stat; + return target(ptr); +} \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/dont_propagate/store_kills_aliased.c b/chapter20/copy_propagation/all_types/dont_propagate/store_kills_aliased.c new file mode 100644 index 00000000..59c9fa45 --- /dev/null +++ b/chapter20/copy_propagation/all_types/dont_propagate/store_kills_aliased.c @@ -0,0 +1,16 @@ +int flag() +{ + return 0; +} + +int main() +{ + int i = 10; + int j = 20; + int *ptr1 = &i; + int *ptr2 = &j; + int *ptr = flag() ? ptr1 : ptr2; + // kill i = 10 and j = 20 + *ptr = 100; + return i + j; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/dont_propagate/type_conversion.c b/chapter20/copy_propagation/all_types/dont_propagate/type_conversion.c new file mode 100644 index 00000000..8b5a8ada --- /dev/null +++ b/chapter20/copy_propagation/all_types/dont_propagate/type_conversion.c @@ -0,0 +1,9 @@ +int target(int i) { + unsigned int j = i; + // don't replace signed w/ unsigned value here + // NOTE: could handle this if we had separate signed/unsigned operators in + // TACKY + return (j > 100); +} + +int main() { return target(-1); } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/dont_propagate/zero_neg_zero_different.c b/chapter20/copy_propagation/all_types/dont_propagate/zero_neg_zero_different.c new file mode 100644 index 00000000..076e6d13 --- /dev/null +++ b/chapter20/copy_propagation/all_types/dont_propagate/zero_neg_zero_different.c @@ -0,0 +1,15 @@ +double copysign(double x, double y); + +double target(int flag) { + double result = 0.0; + if (flag) { + result = -0.0; + } + return result; // can't propagate because 0.0 and -0.0 are different! +} + +int main() { + double pos_inf = 1 / target(0); + double neg_inf = 1 / target(1); + return pos_inf > neg_inf; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/not_char.c b/chapter20/copy_propagation/all_types/not_char.c new file mode 100644 index 00000000..99814f52 --- /dev/null +++ b/chapter20/copy_propagation/all_types/not_char.c @@ -0,0 +1,6 @@ +int target() { + char x = 256; + return !x; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/pointer_arithmetic.c b/chapter20/copy_propagation/all_types/pointer_arithmetic.c new file mode 100644 index 00000000..8dd122a1 --- /dev/null +++ b/chapter20/copy_propagation/all_types/pointer_arithmetic.c @@ -0,0 +1,8 @@ +int target() { + int nested[3][23] = {{0, 1}, {2}}; + // w/ constant folding and copy prop this doesn't require movslq or imul + // instructions + return nested[1][0]; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/propagate_doubles.c b/chapter20/copy_propagation/all_types/propagate_doubles.c new file mode 100644 index 00000000..40e52d25 --- /dev/null +++ b/chapter20/copy_propagation/all_types/propagate_doubles.c @@ -0,0 +1,7 @@ +int target() { + double d = 1500.0; + double d2 = d; + return (int)d + d2; +} + +int main() { return target() == 3000; } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/propagate_null_pointer.c b/chapter20/copy_propagation/all_types/propagate_null_pointer.c new file mode 100644 index 00000000..1a93b253 --- /dev/null +++ b/chapter20/copy_propagation/all_types/propagate_null_pointer.c @@ -0,0 +1,10 @@ +int *target() { + int *ptr = 0; + int *ptr2 = ptr; + return ptr2; +} + +int main() { + int *result = target(); + return (!result); +} \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/signed_unsigned_conversion.c b/chapter20/copy_propagation/all_types/signed_unsigned_conversion.c new file mode 100644 index 00000000..2b1de919 --- /dev/null +++ b/chapter20/copy_propagation/all_types/signed_unsigned_conversion.c @@ -0,0 +1,10 @@ +// test that we can constant fold casts b/t int and uint, allowing for further +// copy propagation + +unsigned int target() { + int i = -1; + unsigned int u = (unsigned)i; + return u - 10; +} + +int main() { return target() == 4294967285u; } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/store_doesnt_kill.c b/chapter20/copy_propagation/all_types/store_doesnt_kill.c new file mode 100644 index 00000000..41c48bc0 --- /dev/null +++ b/chapter20/copy_propagation/all_types/store_doesnt_kill.c @@ -0,0 +1,12 @@ +int callee(int *p1, int *p2) { return p1 == p2; } + +int target() { + int i = 0; + int *ptr = &i; + int *ptr2 = ptr; // generate copy ptr2 = ptr + *ptr = 10; // this does NOT kill copy + // make sure both args have same value, since we can replace ptr2 with ptr + return callee(ptr, ptr2); +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/unsigned_compare.c b/chapter20/copy_propagation/all_types/unsigned_compare.c new file mode 100644 index 00000000..de85279b --- /dev/null +++ b/chapter20/copy_propagation/all_types/unsigned_compare.c @@ -0,0 +1,4 @@ +// really a consatnt-folding test +int target() { return (-1u > 100u); } + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/all_types/unsigned_wraparound.c b/chapter20/copy_propagation/all_types/unsigned_wraparound.c new file mode 100644 index 00000000..99f3b3ea --- /dev/null +++ b/chapter20/copy_propagation/all_types/unsigned_wraparound.c @@ -0,0 +1,6 @@ +unsigned int target() { + unsigned int i = 10u - 11u; + return i % 5u; +} + +int main() { return target() == 0u; } \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/complex_const_fold.c b/chapter20/copy_propagation/int_only/complex_const_fold.c new file mode 100644 index 00000000..17e5db8c --- /dev/null +++ b/chapter20/copy_propagation/int_only/complex_const_fold.c @@ -0,0 +1,7 @@ +int target() { + int x = -100; + int y = x * 3 / 5; + return (y < 100 ? x % 3 : x / 4); +} + +int main() { return target() == -1; } \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/copy_prop_const_fold.c b/chapter20/copy_propagation/int_only/copy_prop_const_fold.c new file mode 100644 index 00000000..5ec39f79 --- /dev/null +++ b/chapter20/copy_propagation/int_only/copy_prop_const_fold.c @@ -0,0 +1,7 @@ +int target() { + int x = 3; + int y = x; + return x + y; // look for movl $6, %eax +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/dont_propagate/add_all_blocks_to_worklist.c b/chapter20/copy_propagation/int_only/dont_propagate/add_all_blocks_to_worklist.c new file mode 100644 index 00000000..a047312e --- /dev/null +++ b/chapter20/copy_propagation/int_only/dont_propagate/add_all_blocks_to_worklist.c @@ -0,0 +1,22 @@ +int flag() +{ + return 1; +} + +int bar() +{ + return 4; +} + +int main() +{ + int x = 1; + // all copies reach this block, so processing its predecessor + // won't change its incoming copies + // but we still gotta add it to worklist + if (flag()) + { + x = bar(); + } + return x; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/dont_propagate/dest_killed.c b/chapter20/copy_propagation/int_only/dont_propagate/dest_killed.c new file mode 100644 index 00000000..c86fc2df --- /dev/null +++ b/chapter20/copy_propagation/int_only/dont_propagate/dest_killed.c @@ -0,0 +1,11 @@ +int foo() +{ + return 4; +} + +int main() +{ + int x = 3; + x = foo(); + return x; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/dont_propagate/listing_20_15.c b/chapter20/copy_propagation/int_only/dont_propagate/listing_20_15.c new file mode 100644 index 00000000..65cc2214 --- /dev/null +++ b/chapter20/copy_propagation/int_only/dont_propagate/listing_20_15.c @@ -0,0 +1,23 @@ +int indirect_update(); + +int f(int new_total) +{ + static int total = 0; + total = new_total; + if (total > 100) + return 0; + total = 10; + indirect_update(); + return total; // can't propagate this +} + +int indirect_update() +{ + f(101); + return 0; +} + +int main() +{ + return f(1); +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/dont_propagate/multi_values.c b/chapter20/copy_propagation/int_only/dont_propagate/multi_values.c new file mode 100644 index 00000000..5fd9ea25 --- /dev/null +++ b/chapter20/copy_propagation/int_only/dont_propagate/multi_values.c @@ -0,0 +1,13 @@ +int multi_path(int flag) +{ + int x = 3; + if (flag) + x = 4; + // make sure it's not propagated - no assembly inspection needed + return x; +} + +int main() +{ + return multi_path(1) + multi_path(0); +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/dont_propagate/no_copies_reach_entry.c b/chapter20/copy_propagation/int_only/dont_propagate/no_copies_reach_entry.c new file mode 100644 index 00000000..c3e68264 --- /dev/null +++ b/chapter20/copy_propagation/int_only/dont_propagate/no_copies_reach_entry.c @@ -0,0 +1,10 @@ +int foo(int a) +{ + return a; + a = 10; // initialize ENTRY w/ empty set of copies, not including this one +} + +int main() +{ + return foo(4); +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/dont_propagate/one_reaching_copy.c b/chapter20/copy_propagation/int_only/dont_propagate/one_reaching_copy.c new file mode 100644 index 00000000..d64c8136 --- /dev/null +++ b/chapter20/copy_propagation/int_only/dont_propagate/one_reaching_copy.c @@ -0,0 +1,21 @@ +int flag() +{ + return 0; +} + +int number() +{ + return 3; +} + +int main() +{ + int x; + if (flag()) + x = 10; + else + x = number(); + // one predecessor contains copy x = 10, other predecessor contains no copies to x, + // so no copies reach start of this block + return x; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/dont_propagate/source_killed.c b/chapter20/copy_propagation/int_only/dont_propagate/source_killed.c new file mode 100644 index 00000000..dfd92738 --- /dev/null +++ b/chapter20/copy_propagation/int_only/dont_propagate/source_killed.c @@ -0,0 +1,12 @@ +int foo() +{ + return 10; +} + +int main() +{ + int x = foo(); + int y = x; // generate y = x + x = 4; // kill y = x + return y; // can't replace y with x here +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/dont_propagate/source_killed_on_one_path.c b/chapter20/copy_propagation/int_only/dont_propagate/source_killed_on_one_path.c new file mode 100644 index 00000000..cae3afed --- /dev/null +++ b/chapter20/copy_propagation/int_only/dont_propagate/source_killed_on_one_path.c @@ -0,0 +1,12 @@ +int f(int src, int flag) +{ + int x = src; // generate x = src + if (flag) + src = 10; // kill x = src + return x; +} + +int main() +{ + return f(5, 1) + f(3, 0); +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/dont_propagate/static_dst_killed.c b/chapter20/copy_propagation/int_only/dont_propagate/static_dst_killed.c new file mode 100644 index 00000000..71c02052 --- /dev/null +++ b/chapter20/copy_propagation/int_only/dont_propagate/static_dst_killed.c @@ -0,0 +1,13 @@ +int x; + +int update_x() +{ + x = 4; +} + +int main() +{ + x = 3; + update_x(); + return x; // can't propagte b/c it's static +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/dont_propagate/static_src_killed.c b/chapter20/copy_propagation/int_only/dont_propagate/static_src_killed.c new file mode 100644 index 00000000..cddd98ef --- /dev/null +++ b/chapter20/copy_propagation/int_only/dont_propagate/static_src_killed.c @@ -0,0 +1,14 @@ +int x = 1; + +int f() +{ + x = 4; + return 0; +} + +int main() +{ + int y = x; + f(); + return y; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/fig_20_8.c b/chapter20/copy_propagation/int_only/fig_20_8.c new file mode 100644 index 00000000..aa2b46a2 --- /dev/null +++ b/chapter20/copy_propagation/int_only/fig_20_8.c @@ -0,0 +1,21 @@ +static int is_called; + +int callee(int i) { + is_called = 1; + return i == 4; +} + +int target() { + int y = 3; + int x; + do { + x = callee(y); + y = 4; + } while (x); + return y; // should become return 4 +} + +int main() { + int result = target(); + return result == 4 && is_called; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/init_all_copies.c b/chapter20/copy_propagation/int_only/init_all_copies.c new file mode 100644 index 00000000..18f929b1 --- /dev/null +++ b/chapter20/copy_propagation/int_only/init_all_copies.c @@ -0,0 +1,26 @@ +static int x = 0; + +// test that we initialize each basic block w/ incoming set of all copies +int callee() { + x = x + 2; + return 0; +} +int count_down() { + static int i = 2; + i = i - 1; + return i; +} +int target() { + int y = 3; + do { + // when we first process this, one predecessor will having reaching copy y = + // 3 other predecessorw on't be processed yet + callee(); + } while (count_down()); + return y; // should become return 3 +} + +int main() { + int result = target(); + return x == 4 && result == 3; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/kill_and_add_copies.c b/chapter20/copy_propagation/int_only/kill_and_add_copies.c new file mode 100644 index 00000000..ca874b79 --- /dev/null +++ b/chapter20/copy_propagation/int_only/kill_and_add_copies.c @@ -0,0 +1,18 @@ +static int x = 0; // make x static so it's not impacted by dead store elim + +int set_x() { + x = 4; + return 1; +} + +int callee(int a, int b) { return a + b; } + +int target() { + set_x(); + int y = x; // gen y = x; + x = 10; // kill y = x, gen x = 10 + // make sure we propagate x = 10 but not y = x + return callee(x, y); // becomes use(10, y) +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/killed_then_redefined.c b/chapter20/copy_propagation/int_only/killed_then_redefined.c new file mode 100644 index 00000000..da69193f --- /dev/null +++ b/chapter20/copy_propagation/int_only/killed_then_redefined.c @@ -0,0 +1,10 @@ +int callee() { return 3; } + +int target() { + int x = 2; + x = callee(); + x = 2; + return x; // look for movl $2, %eax +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/loop.c b/chapter20/copy_propagation/int_only/loop.c new file mode 100644 index 00000000..65f2c102 --- /dev/null +++ b/chapter20/copy_propagation/int_only/loop.c @@ -0,0 +1,28 @@ +int count_down() { + static int i = 10; + i = i - 1; + return i; +} + +int sum = 0; + +int callee() { return 5; } + +int use(int i) { return sum = sum + i; } + +int target() { + int y = 10; // gen y = 10 + int x = y; // gen x = y + while (count_down()) { + x = callee(); // kill x = y + use(x); + x = y; // gen x = y + } + + return x; // should become "return 10" +} + +int main() { + int result = target(); + return result == 10 && sum == 45; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/multi_instance_same_copy.c b/chapter20/copy_propagation/int_only/multi_instance_same_copy.c new file mode 100644 index 00000000..cb3dbcbe --- /dev/null +++ b/chapter20/copy_propagation/int_only/multi_instance_same_copy.c @@ -0,0 +1,31 @@ +int callee(int a, int b) { return a + b; } +int target(int flag) { + int x; + int y; + if (flag) { + y = 10; + x = y; + } else { + y = 20; + x = y; + } + // x = y reaches here, though with different values of y + // compare to Figure 20-6 + // should return y (which is rip-relative) + // one catch - what if they decide to be clever and use movl %eax, _y(%rip) + // instead? (GCC does) maybe we don't need to worry about that + return callee(x, y); +} + +int main() { + int result = target(0); + + if (result != 40) + return 0; + + result = target(1); + if (result != 20) + return 0; + + return 1; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/multi_path.c b/chapter20/copy_propagation/int_only/multi_path.c new file mode 100644 index 00000000..1d30b98b --- /dev/null +++ b/chapter20/copy_propagation/int_only/multi_path.c @@ -0,0 +1,11 @@ +int target(int flag) { + int x = 0; + if (flag) { + x = 3; + } else { + x = 3; + } + return x; // look for movl $3, %eax +} + +int main() { return target(1) + target(0); } \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/multi_path_no_kill.c b/chapter20/copy_propagation/int_only/multi_path_no_kill.c new file mode 100644 index 00000000..1c6225e0 --- /dev/null +++ b/chapter20/copy_propagation/int_only/multi_path_no_kill.c @@ -0,0 +1,19 @@ + +int var = 0; +int callee() { + var = var + 1; + return 0; +} + +int target(int flag) { + int x = 3; + if (flag) + callee(); + return x; // look for movl $3, %eax +} + +int main() { + int result = target(0); + result = result + target(1); + return result == 6 && var == 1; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/prop_static_var.c b/chapter20/copy_propagation/int_only/prop_static_var.c new file mode 100644 index 00000000..621aa4a2 --- /dev/null +++ b/chapter20/copy_propagation/int_only/prop_static_var.c @@ -0,0 +1,14 @@ +int x = 0; + +int target() { + // we can propagate value of x, even though it has static storage duration, + // b/c no intervening reads/writes + x = 10; + int y = x; + return y; // should become "return 10" +} + +int main() { + int result = target(); + return result == 10 && x == 10; +} \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/propagate_fun_args.c b/chapter20/copy_propagation/int_only/propagate_fun_args.c new file mode 100644 index 00000000..5b56498a --- /dev/null +++ b/chapter20/copy_propagation/int_only/propagate_fun_args.c @@ -0,0 +1,15 @@ +int callee(int a, int b) { return a * b; } + +int target(int a, int b) { + int x = 10; // generate x = 10 + int y = 20; // generate y = 20 + x = a + b; // kill x = 10 + // should become callee(x, 20) + // look for movl $20, %esi + // dst of addl should be source of movl to edi (or, should be rdi) + // NOTE: mention that tests assume no function inlining... + // or just have separate compilation unit to prevent that + return callee(x, y); +} + +int main() { return target(5, 6); } \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/propagate_var.c b/chapter20/copy_propagation/int_only/propagate_var.c new file mode 100644 index 00000000..b2221457 --- /dev/null +++ b/chapter20/copy_propagation/int_only/propagate_var.c @@ -0,0 +1,14 @@ +int callee(int a, int b) { return a + b; } +int f() { + return 3; +} +int target() { + int x = f(); + int y = x; + // look for: same value passed in ESI, EDI + // NOTE: this could be accomplished using either copy propagation + // or copy coalescing in register allocator + return callee(x, y); +} + +int main() { return target(); } diff --git a/chapter20/copy_propagation/int_only/redundant_copies.c b/chapter20/copy_propagation/int_only/redundant_copies.c new file mode 100644 index 00000000..fd59eaf9 --- /dev/null +++ b/chapter20/copy_propagation/int_only/redundant_copies.c @@ -0,0 +1,13 @@ +int callee() { return 3; } + +int target(int flag, int y) { + int x = y; + + // make sure we optimize out jump/label here b/c y = x is redundnat + if (flag) { + y = x; + } + return y; +} + +int main() { return target(0, 10); } \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/redundant_copies_2.c b/chapter20/copy_propagation/int_only/redundant_copies_2.c new file mode 100644 index 00000000..ac1d6260 --- /dev/null +++ b/chapter20/copy_propagation/int_only/redundant_copies_2.c @@ -0,0 +1,13 @@ +int callee() { return 3; } + +int target(int flag, int y) { + int x = y; + + // make sure we optimize out jump/label here b/c y = x is redundnat + if (flag) { + x = y; + } + return y; +} + +int main() { return target(0, 10); } \ No newline at end of file diff --git a/chapter20/copy_propagation/int_only/remainder_test.c b/chapter20/copy_propagation/int_only/remainder_test.c new file mode 100644 index 00000000..97d7327f --- /dev/null +++ b/chapter20/copy_propagation/int_only/remainder_test.c @@ -0,0 +1,13 @@ +// make sure we get remainder and not modulo +// this is really a constant folding test but we couldn't test it until we had +// copy prop since it requires operations w/ negative numbers + +int target() { + // the remainder of 6 % -5 is 1 + // 1 = 6 - (-5) * (-1) + // but 6 modulo -5 is - + // -4 = 6 - (-5) * (-2) + return 6 % -5; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/dead_store_elimination/all_types/aliased_dead_at_exit.c b/chapter20/dead_store_elimination/all_types/aliased_dead_at_exit.c new file mode 100644 index 00000000..022ade1c --- /dev/null +++ b/chapter20/dead_store_elimination/all_types/aliased_dead_at_exit.c @@ -0,0 +1,22 @@ +// aliased non-static variables are live just after function calls +// but dead at function exit + +int b = 0; + +void callee(int *ptr) { + b = *ptr; + *ptr = 100; +} + +int target() { + int x = 10; + callee(&x); // uses x + int y = x; + x = 50; // this is dead + return y; +} + +int main() { + int a = target(); + return a == 100 && b == 10; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/all_types/copy_to_dead_struct.c b/chapter20/dead_store_elimination/all_types/copy_to_dead_struct.c new file mode 100644 index 00000000..a54ee726 --- /dev/null +++ b/chapter20/dead_store_elimination/all_types/copy_to_dead_struct.c @@ -0,0 +1,21 @@ +struct s +{ + int i; +}; + +int f(struct s arg) +{ + return arg.i; +} + +int target() +{ + struct s my_struct = {4}; + int x = f(my_struct); + my_struct.i = 10; // dead! + return x; +} + +int main() { + return target(); +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/all_types/dont_elim/copyfromoffset_gen.c b/chapter20/dead_store_elimination/all_types/dont_elim/copyfromoffset_gen.c new file mode 100644 index 00000000..2b92520e --- /dev/null +++ b/chapter20/dead_store_elimination/all_types/dont_elim/copyfromoffset_gen.c @@ -0,0 +1,17 @@ +struct s +{ + int a; + int b; + int c; +}; + +int flag = 1; + +int main() +{ + struct s s1 = {1, 2, 3}; + struct s s2 = {4, 5, 6}; + // can't + struct s result = flag ? s1 : s2; // not a dead store b/c we access a member of result + return result.c; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/all_types/dont_elim/copytooffset_doesnt_kill.c b/chapter20/dead_store_elimination/all_types/dont_elim/copytooffset_doesnt_kill.c new file mode 100644 index 00000000..2db2e1c7 --- /dev/null +++ b/chapter20/dead_store_elimination/all_types/dont_elim/copytooffset_doesnt_kill.c @@ -0,0 +1,16 @@ +struct s +{ + int a; + int b; + int c; +}; + +struct s glob = {1, 2, 3}; + +int main() +{ + struct s my_struct = glob; // this isn't dead! + // overwriting part of struct doesn't kill whole thing + my_struct.c = 100; + return my_struct.c + my_struct.a; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/all_types/dont_elim/load_generates_pointer.c b/chapter20/dead_store_elimination/all_types/dont_elim/load_generates_pointer.c new file mode 100644 index 00000000..21eee2c0 --- /dev/null +++ b/chapter20/dead_store_elimination/all_types/dont_elim/load_generates_pointer.c @@ -0,0 +1,7 @@ +int target() { + int x = 10; + int *y = &x; + return *y; // this uses y, so y = &x isn't a dead store +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/dead_store_elimination/all_types/dont_elim/load_through_pointer.c b/chapter20/dead_store_elimination/all_types/dont_elim/load_through_pointer.c new file mode 100644 index 00000000..5545b37b --- /dev/null +++ b/chapter20/dead_store_elimination/all_types/dont_elim/load_through_pointer.c @@ -0,0 +1,14 @@ +long *pass_and_return(long *ptr) +{ + return ptr; +} + +int main() +{ + long l; + long *ptr = &l; + long *other_ptr = pass_and_return(ptr); + l = 10; // <-- not a dead store b/c l is aliased + // and this is followed by load from memory + return *other_ptr; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/all_types/dont_elim/never_kill_store.c b/chapter20/dead_store_elimination/all_types/dont_elim/never_kill_store.c new file mode 100644 index 00000000..a4f440a6 --- /dev/null +++ b/chapter20/dead_store_elimination/all_types/dont_elim/never_kill_store.c @@ -0,0 +1,12 @@ +void f(int *ptr) +{ + *ptr = 4; // not a dead store! + return; +} + +int main() +{ + int x = 0; + f(&x); + return x; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/all_types/dont_elim/pass_pointer_to_fun.c b/chapter20/dead_store_elimination/all_types/dont_elim/pass_pointer_to_fun.c new file mode 100644 index 00000000..d38925a2 --- /dev/null +++ b/chapter20/dead_store_elimination/all_types/dont_elim/pass_pointer_to_fun.c @@ -0,0 +1,18 @@ +int return_pointer_val(int *arg) +{ + static int *static_ptr = 0; + if (!static_ptr) + static_ptr = arg; + + return *static_ptr; +} + +int main() +{ + int x = 1; + int *null = 0; + int result1 = return_pointer_val(&x); // result1 is 1 + x = 4; // not dead b/c x is aliased, and is used in fun call below + int result2 = return_pointer_val(null); // return 4 (we ignore null, return value of x) + return result1 + result2; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/all_types/dont_elim/store_generates_dst.c b/chapter20/dead_store_elimination/all_types/dont_elim/store_generates_dst.c new file mode 100644 index 00000000..a5bc4808 --- /dev/null +++ b/chapter20/dead_store_elimination/all_types/dont_elim/store_generates_dst.c @@ -0,0 +1,13 @@ +void f(int *arr) +{ + int *ptr = arr + 2; + *ptr = 4; // this makes pointer live, so don't eliminate it! + return; +} + +int main() +{ + int arr[5] = {5, 5, 5, 5, 5}; + f(arr); + return arr[2]; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/all_types/getaddr_doesnt_gen.c b/chapter20/dead_store_elimination/all_types/getaddr_doesnt_gen.c new file mode 100644 index 00000000..8b731fff --- /dev/null +++ b/chapter20/dead_store_elimination/all_types/getaddr_doesnt_gen.c @@ -0,0 +1,10 @@ +int target() +{ + int x = 4; // initialization is a dead store + int *ptr = &x; + return ptr == 0; +} + +int main() { + return target(); +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/dead_store_static_var.c b/chapter20/dead_store_elimination/int_only/dead_store_static_var.c new file mode 100644 index 00000000..71c4ba4e --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/dead_store_static_var.c @@ -0,0 +1,14 @@ +int target(int arg) { + static int i; + if (arg < 0) + return i; + i = 5; // this is dead + i = arg; + return i; +} + +int main() { + int result1 = target(2); + int result2 = target(-1); + return result1 == 2 && result2 == 2; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/dont_elim/add_all_to_worklist.c b/chapter20/dead_store_elimination/int_only/dont_elim/add_all_to_worklist.c new file mode 100644 index 00000000..7bd527f9 --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/dont_elim/add_all_to_worklist.c @@ -0,0 +1,18 @@ +int putchar(int c); + +int f(int arg) +{ + int x = 76; + // no live variables going into this basic block, + // bu we still need to process it to learn that x is live + if (arg) + putchar(x); + return 0; +} + +int main() +{ + f(0); + f(1); + return 0; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/dont_elim/dont_remove_funcall.c b/chapter20/dead_store_elimination/int_only/dont_elim/dont_remove_funcall.c new file mode 100644 index 00000000..9dc77c1d --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/dont_elim/dont_remove_funcall.c @@ -0,0 +1,9 @@ +int putchar(int c); + +int main() +{ + // this is a dead store but we still shouldn't optimize away the function call! + // remove store to x is safe but our implementation won't remove it + int x = putchar(67); + return 0; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/dont_elim/loop.c b/chapter20/dead_store_elimination/int_only/dont_elim/loop.c new file mode 100644 index 00000000..f67bea98 --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/dont_elim/loop.c @@ -0,0 +1,16 @@ +int f(int a, int b) +{ + return a + b; +} + +int main() +{ + int x = 3; + int y = 2; + while (y < 50) + { + y = f(x, y); + x = y + 2; // not dead b/c x is used in next loop iteration + } + return y; +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/dont_elim/static_vars_at_exit.c b/chapter20/dead_store_elimination/int_only/dont_elim/static_vars_at_exit.c new file mode 100644 index 00000000..ae07d175 --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/dont_elim/static_vars_at_exit.c @@ -0,0 +1,13 @@ +int f() +{ + static int i = 10; + if (i == 5) + return 0; + i = 5; // not a dead store! i is live at exit + return 1; +} + +int main() +{ + return f() + f(); +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/dont_elim/static_vars_fun.c b/chapter20/dead_store_elimination/int_only/dont_elim/static_vars_fun.c new file mode 100644 index 00000000..49fa1b7c --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/dont_elim/static_vars_fun.c @@ -0,0 +1,12 @@ +int x = 100; + +int get_x() +{ + return x; +} + +int main() +{ + x = 5; // don't eliminate this! + return get_x(); +} \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/dont_elim/used_one_path.c b/chapter20/dead_store_elimination/int_only/dont_elim/used_one_path.c new file mode 100644 index 00000000..97f59ebb --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/dont_elim/used_one_path.c @@ -0,0 +1,9 @@ +// cf figure 20-11 +int f(int arg, int flag) { + int x = arg * 2; + if (flag) + return x; + return 0; +} + +int main() { return f(20, 1) + f(3, 0); } \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/elim_second_copy.c b/chapter20/dead_store_elimination/int_only/elim_second_copy.c new file mode 100644 index 00000000..d65f923e --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/elim_second_copy.c @@ -0,0 +1,10 @@ +int callee(int arg) { return arg * 2; } + +int target(int arg) { + int x = arg + 1; // not dead + int y = callee(x); + x = 10; // dead + return y; +} + +int main() { return target(4); } \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/fig_20_12.c b/chapter20/dead_store_elimination/int_only/fig_20_12.c new file mode 100644 index 00000000..1e3d82cd --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/fig_20_12.c @@ -0,0 +1,15 @@ +int callee() { return 4; } + +int callee2() { return 5; } + +int target(int flag) { + int x = 10; // eliminate this! + if (flag) { + x = callee(); + } else { + x = callee2(); + } + return x; +} + +int main() { return target(0) + target(1); } \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/loop_dead_store.c b/chapter20/dead_store_elimination/int_only/loop_dead_store.c new file mode 100644 index 00000000..8ca55e17 --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/loop_dead_store.c @@ -0,0 +1,13 @@ +int callee(int i) { return i + 1; } + +int target() { + int x = 5; // dead + int y = 3; // not + do { + x = y * 2; + y = y + callee(x); + } while (y < 20); + return x + y; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/simple.c b/chapter20/dead_store_elimination/int_only/simple.c new file mode 100644 index 00000000..4f70e8d3 --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/simple.c @@ -0,0 +1,7 @@ +int target() { + // make sure we don't use constant 10 + int x = 10; + return 3; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/dead_store_elimination/int_only/use_and_kill.c b/chapter20/dead_store_elimination/int_only/use_and_kill.c new file mode 100644 index 00000000..ed81cab8 --- /dev/null +++ b/chapter20/dead_store_elimination/int_only/use_and_kill.c @@ -0,0 +1,10 @@ +int target() { + // we can eliminate both assignments to x + // (look for: no movl $10, no addition, no inc...no function body basically) + int x = 10; + x = x + 1; + return 5; // return 5, not 0, so it will be set with mov and not xor even if + // they're being clever +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/constant_if_else.c b/chapter20/unreachable_code_elimination/constant_if_else.c new file mode 100644 index 00000000..340acecb --- /dev/null +++ b/chapter20/unreachable_code_elimination/constant_if_else.c @@ -0,0 +1,12 @@ +int callee() { return 0; } + +int target() { + int x; + if (0) + x = callee(); + else + x = 40; + return x + 5; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/dead_after_if_else.c b/chapter20/unreachable_code_elimination/dead_after_if_else.c new file mode 100644 index 00000000..d3d7265a --- /dev/null +++ b/chapter20/unreachable_code_elimination/dead_after_if_else.c @@ -0,0 +1,12 @@ +int callee() { return 100; } + +int target(int a) { + if (a) { + return 1; + } else { + return 2; + } + + return callee(); +} +int main() { return (target(1) == 1 && target(0) == 2); } \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/dead_after_return.c b/chapter20/unreachable_code_elimination/dead_after_return.c new file mode 100644 index 00000000..dae32484 --- /dev/null +++ b/chapter20/unreachable_code_elimination/dead_after_return.c @@ -0,0 +1,17 @@ +int callee() { return 1; } + +int target() { + + // make sure there's nothing after ret statement/epilogue + return 2; + int x = callee(); + + if (x) { + x = 10; + } + + int y = callee(); + return x + y; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/dead_branch_inside_loop.c b/chapter20/unreachable_code_elimination/dead_branch_inside_loop.c new file mode 100644 index 00000000..d705179a --- /dev/null +++ b/chapter20/unreachable_code_elimination/dead_branch_inside_loop.c @@ -0,0 +1,15 @@ +int callee() { return 1 / 0; } + +int target() { + int result = 105; + // loop is not optimized away but inner function call is + for (int i = 0; i < 100; i = i + 1) { + if (0) { + return callee(); + } + result = result - i; + } + return result; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/dead_for_loop.c b/chapter20/unreachable_code_elimination/dead_for_loop.c new file mode 100644 index 00000000..dbf62e7d --- /dev/null +++ b/chapter20/unreachable_code_elimination/dead_for_loop.c @@ -0,0 +1,13 @@ +int callee() { return 1 / 0; } + +int target() { + // when we enable unreachable code elimination and constant folding, + // call to callee() shoudl be optimized away, initialized assignmnet (i = 10 + // should not) + int i = 0; + for (i = 10; 0; i = i * 100) + callee(); + return i; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/dont_elim/keep_final_jump.c b/chapter20/unreachable_code_elimination/dont_elim/keep_final_jump.c new file mode 100644 index 00000000..ab4fe899 --- /dev/null +++ b/chapter20/unreachable_code_elimination/dont_elim/keep_final_jump.c @@ -0,0 +1,12 @@ +int target(int a) { + // make sure we don't choke on a program where final instruction is a jump + // note that last instruction will only be a jump on second iteration thru + // pipeline, after we've removed extra Return + do { + a = a - 1; + if (a) + return 0; + } while (1); +} + +int main() { return target(10); } \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/empty.c b/chapter20/unreachable_code_elimination/empty.c new file mode 100644 index 00000000..2b53ea5a --- /dev/null +++ b/chapter20/unreachable_code_elimination/empty.c @@ -0,0 +1,5 @@ +int target() { return 0; } + +int main() { + // make sure optimization pass doesn't choke on an empty function +} \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/empty_block.c b/chapter20/unreachable_code_elimination/empty_block.c new file mode 100644 index 00000000..fdea3a4d --- /dev/null +++ b/chapter20/unreachable_code_elimination/empty_block.c @@ -0,0 +1,12 @@ +int target(int x, int y) { + // make sure that having empty blocks after optimization doesn't break + // anything + if (x) { + // empty statement + if (y) { + } + } + return 1; +} + +int main() { return target(1, 1) == 1 && target(0, 0) == 1; } \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/loop_in_dead_branch.c b/chapter20/unreachable_code_elimination/loop_in_dead_branch.c new file mode 100644 index 00000000..27a80e27 --- /dev/null +++ b/chapter20/unreachable_code_elimination/loop_in_dead_branch.c @@ -0,0 +1,17 @@ +int callee() { return 1 / 0; } + +int target() { + + int x = 0; + if (0) { + /* make sure we eliminate this loop even though every block in it has a + * predecessor */ + for (int i = 0; i < 10; i = i + 1) { + x = x + callee(); + } + } + + return x; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/remove_jnz.c b/chapter20/unreachable_code_elimination/remove_jnz.c new file mode 100644 index 00000000..0868944f --- /dev/null +++ b/chapter20/unreachable_code_elimination/remove_jnz.c @@ -0,0 +1,3 @@ +int target() { return 0 || 0; } + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/unreachable_code_elimination/remove_useless_starting_label.c b/chapter20/unreachable_code_elimination/remove_useless_starting_label.c new file mode 100644 index 00000000..2ee5f8a0 --- /dev/null +++ b/chapter20/unreachable_code_elimination/remove_useless_starting_label.c @@ -0,0 +1,10 @@ +int target() { + // make sure we remove useless label at very beginning of function + do { + + } while (0); + + return 99; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter20/whole_pipeline/dead_condition.c b/chapter20/whole_pipeline/dead_condition.c new file mode 100644 index 00000000..511a9699 --- /dev/null +++ b/chapter20/whole_pipeline/dead_condition.c @@ -0,0 +1,8 @@ +int main() +{ + // if we enable DSE and dead code elim, x should go away + int x = 10; + if (x) + ; + return 10; +} \ No newline at end of file diff --git a/chapter20/whole_pipeline/elim_and_copy_prop.c b/chapter20/whole_pipeline/elim_and_copy_prop.c new file mode 100644 index 00000000..621d258a --- /dev/null +++ b/chapter20/whole_pipeline/elim_and_copy_prop.c @@ -0,0 +1,6 @@ +int main() +{ + // w/ dse and copy prop, look for movl $10, %eax and no other movl $10, whatever + int x = 10; + return x; +} \ No newline at end of file diff --git a/chapter21/all_types/no_coalescing/dbl_fun_call.c b/chapter21/all_types/no_coalescing/dbl_fun_call.c new file mode 100644 index 00000000..8df9c112 --- /dev/null +++ b/chapter21/all_types/no_coalescing/dbl_fun_call.c @@ -0,0 +1,15 @@ +/* make sure values of doubles are preserved across function calls (must be on the stack) */ + +double glob = 3.0; + +double foo() +{ + return 4.0; +} + +int main() +{ + double d = glob; + double x = foo(); + return (d + x == 7.0); +} \ No newline at end of file diff --git a/chapter21/all_types/no_coalescing/dbl_trivially_colorable.c b/chapter21/all_types/no_coalescing/dbl_trivially_colorable.c new file mode 100644 index 00000000..45feb5c4 --- /dev/null +++ b/chapter21/all_types/no_coalescing/dbl_trivially_colorable.c @@ -0,0 +1,15 @@ +int target(double x, double y) +{ + /* w/out conservative coalescing: + * confirm that we don't access memory + * w/ conservative coalescing: + * - no mov from xmm0 or xmm1 + */ + return 10 - (3.0 * y + x); +} +/* +int target() +{ + return dbl_target(2, 3) + dbl_target(-4, -8); +} +*/ \ No newline at end of file diff --git a/chapter21/all_types/no_coalescing/div_interference.c b/chapter21/all_types/no_coalescing/div_interference.c new file mode 100644 index 00000000..5894ee5c --- /dev/null +++ b/chapter21/all_types/no_coalescing/div_interference.c @@ -0,0 +1,21 @@ +int glob = 3; + +int client(unsigned int a, unsigned int b, unsigned int c, unsigned int d, unsigned int e, unsigned int f, unsigned int g) { + return (a == 12 && b == 12 && c == -3 && d == 10 && e == -30 && f== 52 && g == 48); +} +int target() { + + unsigned int tmp1 = glob * 16; + unsigned int a = tmp1 / 4; // div creates conflict b/t tmp1 and ax since tmp1 is still live + unsigned int b = glob * 4; + unsigned int c = glob - 6; + unsigned int d = glob + 7; + unsigned int e = d * c; + unsigned int f = tmp1 + 4; + return client(a, b,c,d,e,f,tmp1); + +} + +int main() { + return target(); +} \ No newline at end of file diff --git a/chapter21/all_types/no_coalescing/fourteen_pseudos_interfere.c b/chapter21/all_types/no_coalescing/fourteen_pseudos_interfere.c new file mode 100644 index 00000000..ca869ebb --- /dev/null +++ b/chapter21/all_types/no_coalescing/fourteen_pseudos_interfere.c @@ -0,0 +1,30 @@ +double glob = 20.0; +double glob2 = 30.0; +int glob3 = 40.0; + + +int target() { + // create a clique of 14 tmps that interfere + // we can color all of them w/out spilling anything (includg callee-saved regs) + double a = glob * glob; + double b = glob2 + 2.0; + double c = a + 5.0; + double d = b - glob3; + double e = glob + 7.0; + double f = glob2 * 2.0; + double g = c * 3.0; + double h = d * 112.; + double i = e / 3.0; + double j = g + f; + double k = h - j; + double l = i + 1000.; + double m = j - d; + double n = m * l; + + + if (a == 400.0 && b == 32.0 && c == 405.0 && d == -8.0 && e == 27.0 && f == 60.0 && g == 1215.0 && h == -896. && i == 9.0 && j == 1275. && k == -2171. && l == 1009. && m == 1283. && n == 1294547.) + return 0; + else + return 1; + +} \ No newline at end of file diff --git a/chapter21/all_types/no_coalescing/mixed_ints.c b/chapter21/all_types/no_coalescing/mixed_ints.c new file mode 100644 index 00000000..59b01c24 --- /dev/null +++ b/chapter21/all_types/no_coalescing/mixed_ints.c @@ -0,0 +1,47 @@ +// make sure we allocate all integer types together (this is the same as int_only force_spill.c but with a mix of types) + + +long callee(unsigned int twelve, double *eleven, int ten, signed char nine, int *eight, unsigned long seven, long six, unsigned int five, long four, unsigned int three, int two, unsigned char one); + +int glob = 3; +int glob2 = 4; +double glob3 = 5.0; + +int target(unsigned char one, int two, unsigned int three, long four) +{ + /* force spill by creating lots of conflicting pseudos + * validate that we spill the variable should_spill, which is used least + * and has highest degree + * Note: this isn't a good test of spill metric calculation; + * due to optimistic coloring, we could end up spilling just should_spill + * even if we end up choosing other nodes as spill candidates first + */ + unsigned int five = -one; + long six = glob2 * 2; + char should_spill = glob + 3; + // all these registers conflict with should_spill and each other + unsigned long seven = one * one + 6ul; + int *eight = &glob; + signed char nine = two * 4; + int ten = four + six; + double *eleven = &glob3; + unsigned int twelve = (unsigned int) -five; + + int result = callee(twelve, eleven, ten, nine, eight, seven, six, five, four, three, two, one); + + // make another twelve pseudoes that conflict w/ should_spill and each other + unsigned long int thirteen = glob + glob; + double *fourteen = &glob3; + long fifteen = 12 - glob; + int sixteen = thirteen * 3; + int *seventeen = &glob2; + int eighteen = fifteen + sixteen; + unsigned int nineteen = glob2 * thirteen; + unsigned char twenty = result * thirteen; + int twenty_one = result + sixteen; + unsigned int twenty_two = fifteen - result; + int twenty_three = eighteen - nineteen; + unsigned char twenty_four = twenty_one + twenty_two; + long result2 = callee(thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty, twenty_one, twenty_two, twenty_three, twenty_four); + return should_spill + result2; +} diff --git a/chapter21/all_types/no_coalescing/push_xmm.c b/chapter21/all_types/no_coalescing/push_xmm.c new file mode 100644 index 00000000..42ac70bb --- /dev/null +++ b/chapter21/all_types/no_coalescing/push_xmm.c @@ -0,0 +1,13 @@ +// make sure we rewrite push instructions involving xmm registers + +int callee(double a, double b, double c, double d, double e, double f, double g, + double h, double i, double j, double k) { + if (a == 0. && b == 1. && c == 2. && d == 3. && e == 4. && f == 5. && + g == 6. && h == 7. && i == 8. && j == 9. && k == 10.) + return 1; + return 0; +} + +int target(int a, int b, int c, int d, int e) { + return callee(0., 1., 2., 3., 4., 5., e + 1., d + 3., c + 5., b + 7., a + 9.); +} diff --git a/chapter21/all_types/no_coalescing/spill_movz_dst.c b/chapter21/all_types/no_coalescing/spill_movz_dst.c new file mode 100644 index 00000000..5bc0acd5 --- /dev/null +++ b/chapter21/all_types/no_coalescing/spill_movz_dst.c @@ -0,0 +1,48 @@ +// force us to spill temporary results of movz to make sure rewrite rules still work + +int callee(int twelve, int eleven, int ten, int nine, int eight, int seven, int six, int five, int four, int three, int two, int one); + +int glob = 3; +int glob2 = 4; +unsigned char glob3 = 5; +unsigned glob4 = 10; +double glob5 = 11.0; + +long target(int one, int two, int three, int four, int five, int six) +{ + /* force spill by creating lots of conflicting pseudos + * validate that we spill the variable should_spill, which is used least + * and has highest degree + * Note: this isn't a good test of spill metric calculation; + * due to optimistic coloring, we could end up spilling just should_spill + * even if we end up choosing other nodes as spill candidates first + */ + int movz_result = (int) glob3; + long movz_result_2 = (long) glob4; + int cvttsd2si_result = (int) glob5; + // all these registers conflict with should_spill and each other + int seven = one * one + 6; + int eight = two * 4; + int nine = three * two * three; + int ten = four + six; + int eleven = 16 - five + four; + int twelve = six + six - five; + + int result = callee(twelve, eleven, ten, nine, eight, seven, six, five, four, three, two, one); + + // make another twelve pseudoes that conflict w/ should_spill and each other + int thirteen = glob + glob; + int fourteen = thirteen + 10; + int fifteen = 12 - glob; + int sixteen = fourteen * 3; + int seventeen = sixteen - glob2; + int eighteen = fifteen + seventeen; + int nineteen = glob2 * fourteen + glob2 * thirteen; + int twenty = result * fourteen; + int twenty_one = result + sixteen; + int twenty_two = fifteen - result; + int twenty_three = eighteen - nineteen; + int twenty_four = twenty_one + twenty_two + twenty_three; + int result2 = callee(thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty, twenty_one, twenty_two, twenty_three, twenty_four); + return result2 + movz_result + movz_result_2 + cvttsd2si_result; +} diff --git a/chapter21/all_types/no_coalescing/stack_alignment.c b/chapter21/all_types/no_coalescing/stack_alignment.c new file mode 100644 index 00000000..18424755 --- /dev/null +++ b/chapter21/all_types/no_coalescing/stack_alignment.c @@ -0,0 +1,30 @@ +/* NOTE: we should do an int_only version of this too (that's more throrough than the current one) + * but this is a lot easier to test w/ arrays/structs */ + +int glob0 = 0; +int glob1 = 1; +int glob2 = 2; +int glob3 = 3; + +int populate(char *arr, int idx) +{ + if (idx < 0) + return 0; + arr[idx] = idx; + return populate(arr, idx - 1); +} + +int main() +{ + char arr[7]; + int w = glob0; + int x = glob1; + int y = glob2; + int z = glob3; + // make sure stack is sixteen-byte aligned for this call + int result = populate(arr, 6); + for (int i = 0; i < 7; i = i + 1) + if (arr[i] != i) + return 0; + return (w == 0 && x == 1 && y == 2 && z == 3 && result == 0); +} \ No newline at end of file diff --git a/chapter21/all_types/no_coalescing/store_pointer_in_register.c b/chapter21/all_types/no_coalescing/store_pointer_in_register.c new file mode 100644 index 00000000..3ab6fe0a --- /dev/null +++ b/chapter21/all_types/no_coalescing/store_pointer_in_register.c @@ -0,0 +1,80 @@ +/* writing thorugh a pointer doesn't update register holding the pointer, e.g. + * movq %ptr, %r + * mov %src, (%r) + * ... use ptr + * does not create conflict b/t %ptr and %r + * + * need to create an interference graph that's only colorable if we assign ptr + * to r + * ...but we don't know what r is + */ + +int glob; +int glob2; +int glob3; +int glob4; +int glob5; +int glob6; +int glob7; + +int flag = 1; + +int *store_a; + +int target() { + // create a clique of 7 tmps that interfere + // each tmp is a pointer that we write through, whcih remains live afterwards + // this is colorable w/out spills as long as none of these conflict with the + // register we load pointers into + int *a; + int *b; + int *c; + int *d; + int *e; + int *f; + int *g; + // use flag to avoid copy prop + if (flag) { + a = &glob; + *a = 1; + b = &glob2; + *b = 2; + c = &glob3; + *c = 3; + d = &glob4; + *d = 4; + e = &glob5; + *e = 5; + f = &glob6; + *f = 6; + g = &glob7; + // every tmp will conflict with the register we load pointers into, except g + // (b/c g isn't live while we load earlier pointers into that register) + *g = 7; + // store a to a global variable so that all regs conflict but we'll have lower + // register pressure later when we do comparisons + store_a = a; + + } else { + a = 0; + b = 0; + c = 0; + d = 0; + e = 0; + f = 0; + g = 0; + } + + if (b != &glob2 || c != &glob3 || d != &glob4 || e != &glob5 || + f != &glob6 || g != &glob7) { + return 1; + } + if (glob != 1 || glob2 != 2 || glob3 != 3 || glob4 != 4 || glob5 != 5 || + glob6 != 6 || glob7 != 7) { + return 2; + } + if (store_a != &glob) { + return 3; + } + return 0; +} diff --git a/chapter21/all_types/no_coalescing/test_spilling_dbls.c b/chapter21/all_types/no_coalescing/test_spilling_dbls.c new file mode 100644 index 00000000..5f03cd35 --- /dev/null +++ b/chapter21/all_types/no_coalescing/test_spilling_dbls.c @@ -0,0 +1,46 @@ + +double callee(double fourteen, double thirteen, double twelve, double eleven, double ten, double nine, double eight, double seven, double six, double five, double four, double three, double two, double one); + +int glob = 3; +double glob2 = 4.0; + +int target(double one, double two, double three, double four, double five, double six) +{ + /* force spill by creating lots of conflicting pseudos + * validate that we spill the variable should_spill, which is used least + * and has highest degree + * Note: this isn't a good test of spill metric calculation; + * due to optimistic coloring, we could end up spilling just should_spill + * even if we end up choosing other nodes as spill candidates first + */ + double should_spill = (double) glob; + // all these registers conflict with should_spill and each other + double seven = one * one + 6.0; + double eight = two * 4; + double nine = three * two * three; + double ten = four + six; + double eleven = 16 - five + four; + double twelve = six + six - five; + double thirteen = seven + eight; + double fourteen = nine * ten; + + double result = callee(fourteen, thirteen, twelve, eleven, ten, nine, eight, seven, six, five, four, three, two, one); + + // make another twelve pseudoes that conflict w/ should_spill and each other + double fifteen = glob + glob; + double sixteen = fifteen + 10.0; + double seventeen = 12.0 - glob; + double eighteen = sixteen * 3.0; + double nineteen = eighteen - glob2; + double twenty = seventeen + nineteen; + double twenty_one = glob2 * twenty + glob2 * fifteen; + double twenty_two = result * eighteen; + double twenty_three = result + eighteen; + double twenty_four = seventeen - result; + double twenty_five = twenty - nineteen; + double twenty_six = twenty_three + twenty_four + twenty_five; + double twenty_seven = twenty_four * 2.0; + double twenty_eight = twenty_five * twenty_six; + double result2 = callee(fifteen, sixteen, seventeen, eighteen, nineteen, twenty, twenty_one, twenty_two, twenty_three, twenty_four, twenty_five, twenty_six, twenty_seven, twenty_eight); + return should_spill + result2; +} diff --git a/chapter21/all_types/no_coalescing/track_dbl_arg_registers.c b/chapter21/all_types/no_coalescing/track_dbl_arg_registers.c new file mode 100644 index 00000000..714a58a5 --- /dev/null +++ b/chapter21/all_types/no_coalescing/track_dbl_arg_registers.c @@ -0,0 +1,15 @@ +/* Same idea as int-only track_arg_registers but for doubles */ +int callee(double a, double b, double c); + +int target(double one, double two, double three) { + double four = three * one; + double five = two * one; + double six = four - five; + double seven = 100. * four; + double eight = one + two; + double nine = three + four; + double ten = five * six; + double eleven = eight - nine - ten; + double twelve = ten - (one - two) * (three - four) * (five - six) * (seven - one) * (eight + nine); + return callee(ten, eleven, twelve); +} diff --git a/chapter21/int_only/no_coalescing/callee_saved_stack_alignment.c b/chapter21/int_only/no_coalescing/callee_saved_stack_alignment.c new file mode 100644 index 00000000..ee0eb9fe --- /dev/null +++ b/chapter21/int_only/no_coalescing/callee_saved_stack_alignment.c @@ -0,0 +1,23 @@ +int glob0 = 0; +int glob1 = 1; +int glob2 = 2; +int glob3 = 3; + +int f() +{ + return 4; +} + +int main() +{ + // make sure we adjust stack alignment correctly w/ an even number of callee-saved regs + // when no other spills, no need to adjust + // TODO figure out if this is redundant, may be covered by other tests? + // look for: correct result + int w = glob0; + int x = glob1; + int y = glob2; + int z = glob3; + int result = f(); + return (w == 0 && x == 1 && y == 2 && z == 3 && result == 4); +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/cdq_interference.c b/chapter21/int_only/no_coalescing/cdq_interference.c new file mode 100644 index 00000000..efc34c87 --- /dev/null +++ b/chapter21/int_only/no_coalescing/cdq_interference.c @@ -0,0 +1,202 @@ +int glob = 100; +int glob2 = 0; + +int target(int flag) { + int a; + int b; + int c; + int d; + int e; + int f; + + // division means that a-f and callee-saved tmps all conflict w/ each oher, + // AX, and DX so graph is uncolorable BUT if we don't recognize conflict w/ + // DX, we'll prune the whole graph without spills which will lead us to put a + // divisor in DX, causing a spill! don't need to inspect this, just make sure + // it gives the right answer + + // we split this into cases based on value of flag to avoid creating too many + // other conflicting pseudos each temporary that holds the result of a + // comparison will conflict with some of a-e, but not all + if (flag < 10) { + + // provide alternate initialization to prevent copy prop + if (glob2) { + a = 10; + b = 10; + c = 10; + } else { + a = 5; + b = 5; + c = 5; + } + + // each of these clauses makes one temporary conflict with DX and AX + // performing division first, and then updating all the others, ensures that + // only cdq causes conflicts with DX (idiv doesn't) + if (flag < 0) { + a = glob / a; // now a can't be in dx (or ax) + b = 1; + c = 2; + d = 3; + e = 4; + f = 5; + } else if (flag < 5) { + b = glob / b; // now b can't be in dx (or ax) + a = 1; + c = 2; + d = 3; + e = 4; + f = 5; + } else { + c = glob / c; // etc + a = 1; + b = 2; + d = 3; + e = 4; + f = 5; + } + + } else { + + // provide alternate initialization to prevent copy prop + if (glob2) { + d = 10; + e = 10; + f = 10; + } else { + d = 5; + e = 5; + f = 5; + } + + if (flag <= 15) { + d = glob / d; // now d can't be in dx + a = 1; + b = 2; + c = 3; + e = 4; + f = 5; + } else if (flag < 20) { + e = glob / e; // now e can't be in dx + a = 1; + b = 2; + c = 3; + d = 4; + f = 5; + } else { + f = glob / f; // now f can't be in dx + a = 1; + b = 2; + c = 3; + d = 4; + e = 5; + } + } + + int result; + + // expected values for flag < 0 and glob2 == 0 + if (a == 20 && b == 1 && c == 2 && d == 3 && e == 4 && f == 5) { + result = 1; + } + // expected values for flag < 0 and glob2 != 0 + else if (a == 10 && b == 1 && c == 2 && d == 3 && e == 4 && + f == 5) { + result = 2; + } + // expected values for 0 < flag < 5 and glob2 != 0 + else if (a == 1 && b == 10 && c == 2 && d == 3 && e == 4 && + f == 5) { + result = 3; + } + // expected values for 0 < flag < 5 and glob2 == 0 + else if (a == 1 && b == 20 && c == 2 && d == 3 && e == 4 && + f == 5) { + result = 4; + } + + // expected values for 5 < flag < 10 and glob2 == 0 + else if (a == 1 && b == 2 && c == 20 && d == 3 && e == 4 && + f == 5) { + result = 5; + } + + // expected values for 6 < flag < 10 and glob2 != 0 + else if ( a == 1 && b == 2 && c == 10 && d == 3 && e == 4 && + f == 5) { + result = 6; + } + // expected values for 10 < flag <= 15 and glob2 != 0 + else if ( a == 1 && b == 2 && c == 3 && d == 10 && e == 4 && + f == 5) { + result = 7; + } // expected values for 10 < flag < 15 and glob2 == 0 + else if (a == 1 && b == 2 && c == 3 && d == 20 && e == 4 && + f == 5) { + result = 8; + } // expected values for 15 < flag < 20 and glob2 == 0 + else if ( a == 1 && b == 2 && c == 3 && d == 4 && e == 20 && + f == 5) { + result = 9; + } // expected values for 15 < flag < 20 and glob2 != 0 + else if (a == 1 && b == 2 && c == 3 && d == 4 && e == 10 && + f == 5) { + result = 10; + } // expected values for flag > 20 and glob2 != 0 + else if (a == 1 && b == 2 && c == 3 && d == 4 && e == 5 && + f == 10) { + result = 11; + } // expected values for flag > 20 and glob2 == 0 + else if (a == 1 && b == 2 && c == 3 && d == 4 && e == 5 && + f == 20) { + result = 12; + } else { + // something has gone wrong! + result = -100; + } + return result; +} + +int main() { + glob2 = 0; + if (target(-2) != 1) + return 1; + + if (target(3) != 4) + return 2; + + if (target(6) != 5) + return 3; + + if (target(11) != 8) + return 4; + + if (target(17) != 9) + return 5; + + if (target(23) != 12) + return 6; + + glob2 = 1; + + if (target(-2) != 2) + return 7; + + if (target(3) != 3) + return 8; + + if (target(6) != 6) + return 9; + + if (target(11) != 7) + return 10; + + if (target(17) != 10) + return 11; + + if (target(23) != 11) + return 12; + + return 0; +} diff --git a/chapter21/int_only/no_coalescing/cmp_liveness.c b/chapter21/int_only/no_coalescing/cmp_liveness.c new file mode 100644 index 00000000..0beb65af --- /dev/null +++ b/chapter21/int_only/no_coalescing/cmp_liveness.c @@ -0,0 +1,88 @@ +/* using a value in a comparison keeps it live, doesn't kill it + * look for: no spills - exactly five callee-saved regs conflict at any time */ + +int glob0 = 0; +int glob1 = 1; +int glob2 = 2; +int glob3 = 3; +int glob4 = 4; +int glob5 = 5; + +// use this to force pseudoregs to be callee-saved +int callee() +{ + int old_glob0 = glob0; + glob0 = 0; + glob1 = 0; + glob2 = 0; + glob3 = 0; + glob4 = 0; + glob5 = 0; + return old_glob0; +} + +int target(int flag) +{ + /* define some values - must be in calle-saved regs */ + int a = glob0; + int b = glob1; + int c = glob2; + int d = glob3; + int e = glob4; + int f; + int g; + int h; + int i; + int j; + // put this in conditional so copy prop doesn't get rid of these copies + if (flag) + { + callee(); + f = a; // now f interferes w/ b, c, d, and e but not a + + // use a but don't kill it - still no conflict w/ f + if (a > 1) + { + glob0 = glob0 + 1; + } + g = b; // now g interferes w/ c, d, e, f but not a, b + if (b < 10) + { + glob0 = glob0 + 2; + } + h = c; // h interferes with d, e, f, g, h but not a, b or c + if (c <= 10) + glob0 = glob0 + 3; + + i = d; // i interferes with e, f, g, h but not a, b, c, or d + if (d >= 10) + glob0 = glob0 + 4; + j = e; // j interferes with f, g, h, i but not a, b, c,d, e + if (e == 4) + glob0 = glob0 + 5; + } + else + { + e = 0; + f = 0; + g = 0; + h = 0; + i = 0; + j = 0; + } + int old_glob0 = callee(); + int result = 1; + if (f != 0) + result = 0; + if (g != 1) + result = 0; + if (h != 2) + result = 0; + if (i != 3) + result = 0; + if (j != 4) + result = 0; + if (old_glob0 != 10) + result = 0; + return result; +} diff --git a/chapter21/int_only/no_coalescing/copy_and_separate_interference.c b/chapter21/int_only/no_coalescing/copy_and_separate_interference.c new file mode 100644 index 00000000..f00efe0e --- /dev/null +++ b/chapter21/int_only/no_coalescing/copy_and_separate_interference.c @@ -0,0 +1,80 @@ +/* movl x, y does not cause interference b/t x and y, but x and y can interfere for other reasons */ + +int glob0 = 0; +int glob1 = 1; +int glob2 = 2; +int glob3 = 3; +int glob4 = 4; +int glob5 = 5; + +// use this to force pseudoregs to be callee-saved +int reset_globals() +{ + glob0 = 0; + glob1 = 0; + glob2 = 0; + glob3 = 0; + glob4 = 0; + glob5 = 0; + return 0; +} + +int use_value(int v) +{ + glob0 = glob0 + v; + return 0; +} + +int target(int flag) +{ + /* define some values - must be in calle-saved regs */ + int a = glob0; + int b = glob1; + int c = glob2; + int d = glob3; + int e = glob4; + int f; + int g; + int h; + int i; + int j; + // put this in conditional so copy prop doesn't get rid of these copies + if (flag) + { + reset_globals(); + f = a; // now f interferes w/ b, c, d, and e but not a + f = f + 1; // now f and a interfere, so we'll have to spill + use_value(a); + g = b; // now g interferes w/ c, d, e, f but not a, b + use_value(b); + h = c; // h interferes with d, e, f, g, h but not a, b or c + use_value(c); + i = d; // i interferes with e, f, g, h but not a, b, c, or d + use_value(d); + j = e; // j interferes with f, g, h, i but not a, b, c,d, e + use_value(e); + } + else + { + e = 0; + f = 0; + g = 0; + h = 0; + i = 0; + j = 0; + } + int result = 1; + if (f != 1) + result = 0; + if (g != 1) + result = 0; + if (h != 2) + result = 0; + if (i != 3) + result = 0; + if (j != 4) + result = 0; + if (glob0 != 10) + result = 0; + return result; +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/copy_no_interference.c b/chapter21/int_only/no_coalescing/copy_no_interference.c new file mode 100644 index 00000000..f22cdb6d --- /dev/null +++ b/chapter21/int_only/no_coalescing/copy_no_interference.c @@ -0,0 +1,80 @@ +/* movl x, y does not cause interference b/t x and y + * look for: no spills - exactly five callee-saved regs conflict at any time */ + +int glob0 = 0; +int glob1 = 1; +int glob2 = 2; +int glob3 = 3; +int glob4 = 4; +int glob5 = 5; + +// use this to force pseudoregs to be callee-saved +int reset_globals() +{ + glob0 = 0; + glob1 = 0; + glob2 = 0; + glob3 = 0; + glob4 = 0; + glob5 = 0; + return 0; +} + +int use_value(int v) +{ + glob0 = glob0 + v; + return 0; +} + +int target(int flag) +{ + /* define some values - must be in calle-saved regs */ + int a = glob0; + int b = glob1; + int c = glob2; + int d = glob3; + int e = glob4; + int f; + int g; + int h; + int i; + int j; + // put this in conditional so copy prop doesn't get rid of these copies + if (flag) + { + reset_globals(); + f = a; // now f interferes w/ b, c, d, and e but not a + use_value(a); + g = b; // now g interferes w/ c, d, e, f but not a, b + use_value(b); + h = c; // h interferes with d, e, f, g, h but not a, b or c + use_value(c); + i = d; // i interferes with e, f, g, h but not a, b, c, or d + use_value(d); + j = e; // j interferes with f, g, h, i but not a, b, c,d, e + use_value(e); + } + else + { + e = 0; + f = 0; + g = 0; + h = 0; + i = 0; + j = 0; + } + int result = 1; + if (f != 0) + result = 0; + if (g != 1) + result = 0; + if (h != 2) + result = 0; + if (i != 3) + result = 0; + if (j != 4) + result = 0; + if (glob0 != 10) + result = 0; + return result; +} diff --git a/chapter21/int_only/no_coalescing/force_spill.c b/chapter21/int_only/no_coalescing/force_spill.c new file mode 100644 index 00000000..71e0b813 --- /dev/null +++ b/chapter21/int_only/no_coalescing/force_spill.c @@ -0,0 +1,42 @@ + +int callee(int twelve, int eleven, int ten, int nine, int eight, int seven, int six, int five, int four, int three, int two, int one); + +int glob = 3; +int glob2 = 4; + +int target(int one, int two, int three, int four, int five, int six) +{ + /* force spill by creating lots of conflicting pseudos + * validate that we spill the variable should_spill, which is used least + * and has highest degree + * Note: this isn't a good test of spill metric calculation; + * due to optimistic coloring, we could end up spilling just should_spill + * even if we end up choosing other nodes as spill candidates first + */ + int should_spill = glob + 3; + // all these registers conflict with should_spill and each other + int seven = one * one + 6; + int eight = two * 4; + int nine = three * two * three; + int ten = four + six; + int eleven = 16 - five + four; + int twelve = six + six - five; + + int result = callee(twelve, eleven, ten, nine, eight, seven, six, five, four, three, two, one); + + // make another twelve pseudoes that conflict w/ should_spill and each other + int thirteen = glob + glob; + int fourteen = thirteen + 10; + int fifteen = 12 - glob; + int sixteen = fourteen * 3; + int seventeen = sixteen - glob2; + int eighteen = fifteen + seventeen; + int nineteen = glob2 * fourteen + glob2 * thirteen; + int twenty = result * fourteen; + int twenty_one = result + sixteen; + int twenty_two = fifteen - result; + int twenty_three = eighteen - nineteen; + int twenty_four = twenty_one + twenty_two + twenty_three; + int result2 = callee(thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty, twenty_one, twenty_two, twenty_three, twenty_four); + return should_spill + result2; +} diff --git a/chapter21/int_only/no_coalescing/idiv_interference.c b/chapter21/int_only/no_coalescing/idiv_interference.c new file mode 100644 index 00000000..a2b465a7 --- /dev/null +++ b/chapter21/int_only/no_coalescing/idiv_interference.c @@ -0,0 +1,21 @@ +int glob = 3; + +int client(int a, int b, int c, int d, int e, int f, int g) { + return (a == 12 && b == 12 && c == -3 && d == 10 && e == -30 && f== 52 && g == 48); +} +int target() { + + int tmp1 = glob * 16; + int a = tmp1 / 4; // idiv creates conflict b/t tmp1 and ax since tmp1 is still live + int b = glob * 4; + int c = glob - 6; + int d = glob + 7; + int e = d * c; + int f = tmp1 + 4; + return client(a, b,c,d,e,f,tmp1); + +} + +int main() { + return target(); +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/loop.c b/chapter21/int_only/no_coalescing/loop.c new file mode 100644 index 00000000..165bb086 --- /dev/null +++ b/chapter21/int_only/no_coalescing/loop.c @@ -0,0 +1,56 @@ + + +int flag = 1; +int result = 1; +int a_initialized = 0; + +int get(int a, int b, int c, int d, int e, int f) { + static int call_count = 0; + call_count = call_count + 1; + if (call_count == 1) { + // first call + if (a == 1 && b == 2 && c == 3 && d == 4 && e == 5 && f == 6) + return 1; + else + return -2; + } else if (call_count == 2) { + if (a == 2 && b == 3 && c == 4 && d == 6 && e == 5 && f == 8) + return 2; + else + return -2; + } + // if this is call #3, we're done + flag = 0; + return 0; // doesn't matter what we return here +} + +int target() { + int z; + int a; + int tmp1 = 1; + int tmp2 = 2; + int tmp3 = 3; + int tmp4 = 4; + int tmp5 = 5; + int tmp6 = 6; + // make sure our liveness analysis can handle loops correctly: + // we should recognize that a and z both overlap with tmp1-tmp6 but not each other, + // so we can avoid any spills by assigning a and z to the same hardreg + while (flag) { + if (a_initialized) { + z = a + 1; + } else { + z = 1; + } + result = z * result; + a = get(tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + tmp1 = a + 1; + tmp2 = a + 2; + tmp3 = a * 4; + tmp4 = a + 5; + tmp5 = 6 - a; + tmp6 = 9 - a; + a_initialized = 1; + } + return result; +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/many_pseudos_fewer_conflicts.c b/chapter21/int_only/no_coalescing/many_pseudos_fewer_conflicts.c new file mode 100644 index 00000000..baa1bbfd --- /dev/null +++ b/chapter21/int_only/no_coalescing/many_pseudos_fewer_conflicts.c @@ -0,0 +1,41 @@ +// if a graph has more than twelve temporaries but few conflicts, we can still coloro itw ithout spills + +int client(int i); + +int no_spills(int one, int two, int flag) { + + + if (!flag) { + int five = one * two; + int six = client(five) + 6; + return six; + } + + if (flag == 1) { + int seven = one + two; + int eight = client(seven) + 8; + return eight; + } + + if (flag == 2) { + int nine = one - two; + int ten = client(nine) + 10; + return ten; + } + + if (flag == 3) { + int eleven = one % two; + int twelve = client(eleven) + 12; + return twelve; + } + + if (flag == 4) { + int thirteen = one / two; + int fourteen = client(thirteen) + 14; + return fourteen; + } + + return 0; + + +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/optimistic_coloring.c b/chapter21/int_only/no_coalescing/optimistic_coloring.c new file mode 100644 index 00000000..7a6a6291 --- /dev/null +++ b/chapter21/int_only/no_coalescing/optimistic_coloring.c @@ -0,0 +1,143 @@ +/* Make sure we use optimistic coloring: + * Include: + * - Pseudos with low cost and short live ranges which will spill first but + * don't decrease register pressure + * - Pseudos with high cost and long live ranges which spill later + * Make sure we color the low-cost ones! + * What if we had: clique ABCDE, clique EFGHI, and clique JKLMN that conflicts + * with all of them make sure ABCDE have lowest spill cost, so we choose them as + * spill candidates first then we choose JKLMN as next batch of spill candidates + * then we prune the rest of the graph + * then we actually spill JKLMN, which lets us color ABCDE + */ + +int glob0 = 0; +int glob1 = 1; +int glob2 = 2; +int glob3 = 3; +int glob4 = 4; +int glob5 = 0; +int glob6 = 0; +int glob7 = 0; +int glob8 = 0; +int glob9 = 0; + +int flag = 0; +int result = 0; +int increase_globals() { + glob0 = glob0 + 1; + glob1 = glob1 + 1; + glob2 = glob2 + 1; + glob3 = glob3 + 1; + glob4 = glob4 + 1; + return 0; +} + +int reset_globals() { + glob0 = 0; + glob1 = 1; + glob2 = 2; + glob3 = 3; + glob4 = 4; + glob5 = 0; + glob6 = 0; + glob7 = 0; + glob8 = 0; + glob9 = 0; + return 0; +} + +int get() { + static int i = 100; + i = i + 3; + return i; +} + +int use(int one, int two, int three, int four, int five) { + glob5 = glob5 + one; + glob6 = glob6 + two; + glob7 = glob7 + three; + glob8 = glob8 + four; + glob9 = glob9 + five; + return 0; +} + +int validate_globs(int one, int two, int three, int four, int five) { + if (glob5 != one) + return 10; + if (glob6 != two) + return 12; + if (glob7 != three) + return 13; + if (glob8 != four) + return 14; + if (glob9 != five) + return 15; + return 0; +} + +int five_spills() { + // k - o conflict with everything, have higher spill metric than a-e but lower + // than f-j + int k = get(); + int l = get(); + int m = get(); + int n = get(); + int o = get(); + if (!flag) { + // make a-e a clique with low spill cost + int a = glob0; + int b = glob1; + int c = glob2; + int d = glob3; + int e = glob4; + increase_globals(); + use(k, l, m, n, o); + result = a == glob0 - 1 && b == glob1 - 1 && c == glob2 - 1 && + d == glob3 - 1 && e == glob4 - 1 && k - glob0 == 102 && + l / glob1 == 53 && m % glob2 == 1 && n + glob3 == 116 && + o % glob4 == 0; + ; + } else { + // make F-I a clique with higher spill cost + int f = glob0; + int g = glob1; + int h = glob2; + int i = glob3; + int j = glob4; + increase_globals(); + use(f, g, h, i, j); + use(g, h, i, j, f); + use(h, i, j, f, g); + use(i, j, f, g, h); + use(j, f, g, h, i); + f = f + 1; + g = g + 1; + h = h + 1; + j = j + 1; + i = i + 1; + result = f == glob0 && g == glob1 && h == glob2 && i == glob3 && + j == glob4 && k - glob0 == 117 && + l + glob1 == 123 && m % glob2 == 1 && n + glob3 == 131 && + o % glob4 == 0; + } + + return result; +} + +int target() { + reset_globals(); + flag = 0; + int retval = five_spills(); + if (!retval) + return 1; + int globs_expected = validate_globs(103, 106, 109, 112, 115); + if (globs_expected) + return globs_expected + 100; + reset_globals(); + flag = 1; + retval = five_spills(); + if (!retval) + return 2; + return validate_globs(10, 10, 10, 10, 10); +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/preserve_across_fun_call.c b/chapter21/int_only/no_coalescing/preserve_across_fun_call.c new file mode 100644 index 00000000..e73f02b0 --- /dev/null +++ b/chapter21/int_only/no_coalescing/preserve_across_fun_call.c @@ -0,0 +1,25 @@ +int glob = 1; +int glob2 = 2; +int glob3 = 3; +int glob4 = 0; + +int client(int a, int b, int c, int d, int e, int f) { + return a == 1 && b == 2 && c ==3 && d == 4 && e == 5 && f == 6; +} + +int callee() { + glob = glob + 1; + glob2 = glob2 + 1; + glob3 = glob3 + 1; + // call client to make sure we clobber all caller-saved regs + glob4 = client(1,2,3,4,5,6); +} + +int target() { + // make sure any variables that must be preserved across function calls are placed in callee-saved regs + int a = 5 - glob; + int b = glob2 * 2; + int c = glob3 + 6; + callee(); + return (a - glob == 2 && b - glob2 ==1 && c - glob3 == 5 && glob4 == 0); +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/rewrite_large_multiply.c b/chapter21/int_only/no_coalescing/rewrite_large_multiply.c new file mode 100644 index 00000000..24b16db1 --- /dev/null +++ b/chapter21/int_only/no_coalescing/rewrite_large_multiply.c @@ -0,0 +1,44 @@ +// force us to spill temporary results of multiply by large constant to make sure rewrite rules still work + +int callee(int twelve, int eleven, int ten, int nine, int eight, int seven, int six, int five, int four, int three, int two, int one); + +int glob = 3; +int glob2 = 4; +long glob3 = 5l; + +int target(int one, int two, int three, int four, int five, int six) +{ + /* force spill by creating lots of conflicting pseudos + * validate that we spill the variable should_spill, which is used least + * and has highest degree + * Note: this isn't a good test of spill metric calculation; + * due to optimistic coloring, we could end up spilling just should_spill + * even if we end up choosing other nodes as spill candidates first + */ + long imul_result = glob3 * 4294967307l; + // all these registers conflict with should_spill and each other + int seven = one * one + 6; + int eight = two * 4; + int nine = three * two * three; + int ten = four + six; + int eleven = 16 - five + four; + int twelve = six + six - five; + + int result = callee(twelve, eleven, ten, nine, eight, seven, six, five, four, three, two, one); + + // make another twelve pseudoes that conflict w/ should_spill and each other + int thirteen = glob + glob; + int fourteen = thirteen + 10; + int fifteen = 12 - glob; + int sixteen = fourteen * 3; + int seventeen = sixteen - glob2; + int eighteen = fifteen + seventeen; + int nineteen = glob2 * fourteen + glob2 * thirteen; + int twenty = result * fourteen; + int twenty_one = result + sixteen; + int twenty_two = fifteen - result; + int twenty_three = eighteen - nineteen; + int twenty_four = twenty_one + twenty_two + twenty_three; + int result2 = callee(thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty, twenty_one, twenty_two, twenty_three, twenty_four); + return result2 + imul_result; +} diff --git a/chapter21/int_only/no_coalescing/same_instr_interference.c b/chapter21/int_only/no_coalescing/same_instr_interference.c new file mode 100644 index 00000000..10c34e54 --- /dev/null +++ b/chapter21/int_only/no_coalescing/same_instr_interference.c @@ -0,0 +1,57 @@ +/* test that addl x, y (or similar) causes interference b/t x and y if x is live afterward + * just test for correctness */ + +int glob0 = 0; +int glob1 = 1; +int glob2 = 2; +int glob3 = 3; +int glob4 = 4; +int glob5 = 5; + +// use this to force pseudoregs to be callee-saved +int reset_globals() { + glob0 = 0; + glob1 = 0; + glob2 = 0; + glob3 = 0; + glob4 = 0; + glob5 = 0; + return 0; +} + +int use_value(int v) { + glob0 = glob0 + v; + return 0; +} + +int target() { + /* define some values - must be in calle-saved regs */ + int a = glob0; + int b = glob1; + int c = glob2; + int d = glob3; + reset_globals(); + int e = a * a; // now e interferes w/ a, b, c, and d + use_value(a); + int f = b * b; // now f interferes w/ b, d, c and e but not a + use_value(b); + int g = c * c; // g interferes with c, d, e, f but not a or b + use_value(c); + int h = d * d; // h interferes with d, e, f, g but not a, b, c + use_value(d); + int result = 0; + if (e != 0) { + result = 1; + } else if (f != 1) { + result = 2; + } else if (g != 4) { + result = 3; + } else if (h != 9) { + result = 4; + } else { + result = glob0; + } + return result; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/same_instr_no_interference.c b/chapter21/int_only/no_coalescing/same_instr_no_interference.c new file mode 100644 index 00000000..05d5c1f3 --- /dev/null +++ b/chapter21/int_only/no_coalescing/same_instr_no_interference.c @@ -0,0 +1,54 @@ +/* test that addl x, y does NOT create conflict b/t x and y if x is dead + * afterward look for: no spills - there are eight callee-saved regs but they + * don't all conflict */ + +int glob0 = 0; +int glob1 = 1; +int glob2 = 2; +int glob3 = 3; +int glob4 = 4; +int glob5 = 5; + +// use this to force pseudoregs to be callee-saved +int reset_globals() { + glob0 = 0; + glob1 = 0; + glob2 = 0; + glob3 = 0; + glob4 = 0; + glob5 = 0; + return 0; +} + +int target() { + /* define some values - must be in calle-saved regs */ + int a = glob4; + int b = glob3; + int c = glob2; + int d = glob1; + int e = glob0; + reset_globals(); + int f = a * a; // now f interferes w/ b, c, d, e but not a + int g = b * b; // now g interferes w/ d, c, e, f but not a or b + int h = c * c; // h interferes with d, e, f, g but not a, b, or c + int i = d * d; // i interferes with e, f, g, h but not a, b, c, d + int j = e * e; // j interferes with f, g, h, i, but not a, b, c, d + reset_globals(); + int result = 0; + if (f != 4) { + result = 1; + } + else if (g != 3) { + result = 2; + } + else if (h != 2) { + result = 3; + } + else if (i != 1) { + result = 4; + } + else if (j != 0) { + result = 5; + } + return result; +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/spill_callee_saved.c b/chapter21/int_only/no_coalescing/spill_callee_saved.c new file mode 100644 index 00000000..89e0c663 --- /dev/null +++ b/chapter21/int_only/no_coalescing/spill_callee_saved.c @@ -0,0 +1,21 @@ +int client(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) +{ + return a == 7 && b == 15 && c == 10 && d == 18 && e == 8 && f == 7 && g == 6 && h == 5 && i == 4 && j == 3 && k == 2 && l == 1; +} + +int target(int one, int two, int three, int four, int five, int six) +{ + /* all these arguments interfere so make sure we assign each one to a separate register + * validate that there are no spills aside from callee-saved regs at start and end + * (there are also a few temporaries but they are also colorable once callee-saved regs are spilled) + */ + + int seven = one * one + 6; + int eight = two * 4; + int nine = three * two * three; + int ten = four + six; + int eleven = 16 - five + four; + int twelve = six + six - five; + + return client(twelve, eleven, ten, nine, eight, seven, six, five, four, three, two, one); +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/spills_and_rewrites.c b/chapter21/int_only/no_coalescing/spills_and_rewrites.c new file mode 100644 index 00000000..3203b978 --- /dev/null +++ b/chapter21/int_only/no_coalescing/spills_and_rewrites.c @@ -0,0 +1,47 @@ +// force us to spill temporary results of various aritihmetic expressions to make sure rewrite rules still work + + + +int callee(int twelve, int eleven, int ten, int nine, int eight, int seven, int six, int five, int four, int three, int two, int one); + +int glob = 3; +int glob2 = 4; + +int target(int one, int two, int three, int four, int five, int six) +{ + /* force spill by creating lots of conflicting pseudos + * validate that we spill the variable should_spill, which is used least + * and has highest degree + * Note: this isn't a good test of spill metric calculation; + * due to optimistic coloring, we could end up spilling just should_spill + * even if we end up choosing other nodes as spill candidates first + */ + int imul_result = glob * glob2; + int add_result = glob + glob2; + int sub_result = glob2 - glob; + // all these registers conflict with should_spill and each other + int seven = one * one + 6; + int eight = two * 4; + int nine = three * two * three; + int ten = four + six; + int eleven = 16 - five + four; + int twelve = six + six - five; + + int result = callee(twelve, eleven, ten, nine, eight, seven, six, five, four, three, two, one); + + // make another twelve pseudoes that conflict w/ should_spill and each other + int thirteen = glob + glob; + int fourteen = thirteen + 10; + int fifteen = 12 - glob; + int sixteen = fourteen * 3; + int seventeen = sixteen - glob2; + int eighteen = fifteen + seventeen; + int nineteen = glob2 * fourteen + glob2 * thirteen; + int twenty = result * fourteen; + int twenty_one = result + sixteen; + int twenty_two = fifteen - result; + int twenty_three = eighteen - nineteen; + int twenty_four = twenty_one + twenty_two + twenty_three; + int result2 = callee(thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty, twenty_one, twenty_two, twenty_three, twenty_four); + return result2 + imul_result + add_result + sub_result; +} diff --git a/chapter21/int_only/no_coalescing/spills_rewrites_compare.c b/chapter21/int_only/no_coalescing/spills_rewrites_compare.c new file mode 100644 index 00000000..a43a8d42 --- /dev/null +++ b/chapter21/int_only/no_coalescing/spills_rewrites_compare.c @@ -0,0 +1,47 @@ +// same idea as spills_and_rewrites for comparison + +// force us to spill temporary results of various aritihmetic expressions to make sure rewrite rules still work + + + +int callee(int twelve, int eleven, int ten, int nine, int eight, int seven, int six, int five, int four, int three, int two, int one); + +int glob = 3; +int glob2 = 4; + +int target(int one, int two, int three, int four, int five, int six) +{ + /* force spill by creating lots of conflicting pseudos + * validate that we spill the variable should_spill, which is used least + * and has highest degree + * Note: this isn't a good test of spill metric calculation; + * due to optimistic coloring, we could end up spilling just should_spill + * even if we end up choosing other nodes as spill candidates first + */ + int cmp_result = glob == glob2; + // all these registers conflict with should_spill and each other + int seven = one * one + 6; + int eight = two * 4; + int nine = three * two * three; + int ten = four + six; + int eleven = 16 - five + four; + int twelve = six + six - five; + + int result = callee(twelve, eleven, ten, nine, eight, seven, six, five, four, three, two, one); + + // make another twelve pseudoes that conflict w/ should_spill and each other + int thirteen = glob + glob; + int fourteen = thirteen + 10; + int fifteen = 12 - glob; + int sixteen = fourteen * 3; + int seventeen = sixteen - glob2; + int eighteen = fifteen + seventeen; + int nineteen = glob2 * fourteen + glob2 * thirteen; + int twenty = result * fourteen; + int twenty_one = result + sixteen; + int twenty_two = fifteen - result; + int twenty_three = eighteen - nineteen; + int twenty_four = twenty_one + twenty_two + twenty_three; + int result2 = callee(thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen, twenty, twenty_one, twenty_two, twenty_three, twenty_four); + return result2 + cmp_result; +} diff --git a/chapter21/int_only/no_coalescing/test_spill_metric.c b/chapter21/int_only/no_coalescing/test_spill_metric.c new file mode 100644 index 00000000..0f499fbb --- /dev/null +++ b/chapter21/int_only/no_coalescing/test_spill_metric.c @@ -0,0 +1,38 @@ +int glob1 = 1; +int glob2 = 2; +int glob3 = 3; +int glob4 = 4; +int glob5 = 5; + +int callee(int a, int b, int c, int d, int e); +int check_globals(); + +int target(int a, int b, int c, int d, int e, int flag) { + // make sure we spill nodes with lower spill costs first + int f = glob1; + + // put uses of these variables in branches to avoid copy prop + if (flag) { + a = a + 1; + b = b - 2; + c = c * 3; + d = d / 4; + e = e % 5; + } else { + a = a - 1; + b = b + 2; + c = c / 3; + d = d * 4; + e = e * e; + } + + + int result = callee(a, b, c, d, e); + glob1 = a; + glob2 = b; + glob3 = c; + glob4 = d; + glob5 = e + result; + check_globals(); + return f; +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/test_spill_metric_2.c b/chapter21/int_only/no_coalescing/test_spill_metric_2.c new file mode 100644 index 00000000..e570d0f4 --- /dev/null +++ b/chapter21/int_only/no_coalescing/test_spill_metric_2.c @@ -0,0 +1,43 @@ +int callee(int ok); + +int glob1 = 32; +int glob2 = 2; +int glob3 = 3; +int glob4 = 9; +int glob5 = 5; +int glob6 = 16; + +// when multiple pseudos have the same spill cost, make sure we spill the one with the highest degree +int target() { + + // to_spill and a-e form a clique and must go in callee-saved regs + int to_spill = glob1; + int a = glob2; + int b = glob3; + int c = glob4; + int d = glob5; + int e = glob6; + + callee(1); + + int ok = 1; + if (!(a == glob2 + 2 && b == glob3 -2 && c == glob4 * 3 && d == glob5 - 5 && e == glob6 * 2)) + ok = 0; // set ok instead of just returning b/c return increases spill cost of callee-saved tmps + + // to_spill and f-j form a clique and must go in callee-saved regs + int f = glob2; + int g = glob3; + int h = glob4; + int i = glob5; + int j = glob6; + // return 'ok' as result (so we can validate that a/b/etc had expected values) + // also update global vars + int result = callee(ok); + if (!(f == glob2 + 2 && g == glob3 -2 && h== glob4 * 3 && i == glob5 - 5 && j == glob6 * 2 && to_spill == glob1 * 4)) + result = 0; + + + return result; + + +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/track_arg_registers.c b/chapter21/int_only/no_coalescing/track_arg_registers.c new file mode 100644 index 00000000..ed0d99bf --- /dev/null +++ b/chapter21/int_only/no_coalescing/track_arg_registers.c @@ -0,0 +1,14 @@ +/* Make sure our analysis recognizes which registers are used by each function call/return statement + Liveness analysis should recognize that only EDI, ESI, and EDX are live right before calling client + If we assume ECX, R8 and R9 are also live, we'll conclude that they're live throughout the whole function + (since they're never updated) and won't be able to allocate them, resuling in spills +*/ + +int callee(int a, int b, int c); + +int target(int one, int two, int three) { + int four = one * one; + int five = two * 4; + int six = (one - two) + (one - three); + return callee(four, five, six); +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/trivially_colorable.c b/chapter21/int_only/no_coalescing/trivially_colorable.c new file mode 100644 index 00000000..c0159364 --- /dev/null +++ b/chapter21/int_only/no_coalescing/trivially_colorable.c @@ -0,0 +1,13 @@ +int glob = 10; +int glob2 = 11; + +int client(int x, int y, int z) { + return x == 13 && y == 143 && z == -130; +} + +int target() { + int x = glob + 3; + int y = glob2 * x; + int z = x - y; + return client(x, y, z); +} \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/unary_interference.c b/chapter21/int_only/no_coalescing/unary_interference.c new file mode 100644 index 00000000..10303a5f --- /dev/null +++ b/chapter21/int_only/no_coalescing/unary_interference.c @@ -0,0 +1,57 @@ +/* test that negl y (or similar) causes interference b/t y and anything else currently live + * just test for correctness */ + +int glob0 = 1; +int glob1 = 2; +int glob2 = 3; +int glob3 = 4; +int glob4 = 5; +int glob5 = 6; + +// use this to force pseudoregs to be callee-saved +int reset_globals() { + glob0 = 0; + glob1 = 0; + glob2 = 0; + glob3 = 0; + glob4 = 0; + glob5 = 0; + return 0; +} + +int use_value(int v) { + glob0 = glob0 + v; + return 0; +} + +int target() { + /* define some values - must be in calle-saved regs */ + int a = glob0; + int b = glob1; + int c = glob2; + int d = glob3; + reset_globals(); + int e = -a; // now e interferes w/ a, b, c, and d + use_value(a); + int f = -b; // now f interferes w/ b, d, c and e but not a + use_value(b); + int g = -c; // g interferes with c, d, e, f but not a or b + use_value(c); + int h = -d; // h interferes with d, e, f, g but not a, b, c + use_value(d); + int result = 0; + if (e != -1) { + result = 1; + } else if (f != -2) { + result = 2; + } else if (g != -3) { + result = 3; + } else if (h != -4) { + result = 4; + } else { + result = glob0; + } + return result; +} + +int main() { return target(); } \ No newline at end of file diff --git a/chapter21/int_only/no_coalescing/use_all_hardregs.c b/chapter21/int_only/no_coalescing/use_all_hardregs.c new file mode 100644 index 00000000..3ceaf343 --- /dev/null +++ b/chapter21/int_only/no_coalescing/use_all_hardregs.c @@ -0,0 +1,24 @@ +int glob = 20; +int glob2 = 30; +int glob3 = 40; + + +int target() { + // create a clique of 7 tmps that interfere + // we can color all of them w/out spilling anything (includg callee-saved regs) + int a = glob * glob; + int b = glob2 + 2; + int c = a + 5; + int d = b - glob3; + int e = glob + 7; + int f = glob2 * 2; + int g = c * 3; + int result; + if (a == 400 && b == 32 && c == 405 && d == -8 && e == 27 && f == 60 && g == 1215) + result = 0; + else { + result = 1; + } + return result; + +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/bin_generates_dst.c b/chapter21/int_only/with_coalescing/bin_generates_dst.c new file mode 100644 index 00000000..31347503 --- /dev/null +++ b/chapter21/int_only/with_coalescing/bin_generates_dst.c @@ -0,0 +1,31 @@ +// test that a binary instruction generates its destination, e.g. add src, dst +// makes dst live (or at least doesn't kill it) + +int glob = 1; +int flag = 1; + +int f(); + +int target() { + + int a = 100; + while (a) { + // this addition becomes: + // movl %a, %tmp + // addl %glob, %tmp + // movl %tmp, %glob + // so unless we think a is still live, + // we'll coalesce a & tmp + glob = a + glob; + // after one round of coalescing this will be + // subl $1, %a.0 + // so we need to recognize that this sub instruction + // won't kill a + a = a - 1; + } + return glob; +} + +int main() { + return target(); +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/briggs_coalesce.c b/chapter21/int_only/with_coalescing/briggs_coalesce.c new file mode 100644 index 00000000..91d297c4 --- /dev/null +++ b/chapter21/int_only/with_coalescing/briggs_coalesce.c @@ -0,0 +1,21 @@ +int flag = 1; +int glob = 4; + + +int target() { + int x = glob - 10; + int y; + if (flag) + { + y = 40; + } + else + { + y = x; + } + if (y == -16) + return 1; + if (y == 40) + return 2; + return -1; +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/briggs_coalesce_tmps.c b/chapter21/int_only/with_coalescing/briggs_coalesce_tmps.c new file mode 100644 index 00000000..fc091727 --- /dev/null +++ b/chapter21/int_only/with_coalescing/briggs_coalesce_tmps.c @@ -0,0 +1,19 @@ +// we can coalesce all the temporary variables we generate during TACKY generation + +int glob1 = 1; +int glob2 = 2; +int glob3 = 3; +int glob4 = 4; +int glob5 = 0; + +int briggs() { + int a = (glob1 * 3) + (glob2 * 4) + (glob3 * 5) + (glob4 * 6); + int b = a * 10; + glob5 = b; + return 0; +} + +int target() { + briggs(); + return (glob5 == 500); +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/callee_saved_live_at_exit.c b/chapter21/int_only/with_coalescing/callee_saved_live_at_exit.c new file mode 100644 index 00000000..3a9281f6 --- /dev/null +++ b/chapter21/int_only/with_coalescing/callee_saved_live_at_exit.c @@ -0,0 +1,31 @@ +// can we create a situation where one callee-saved tmp gets coalesced but then we need to use it? +// or all of them get coalesced but then we need to use one of them? + +int glob = 20; + +int callee(int a, int b, int c, int d, int e, int f); + +// in round 1, the graph is unconstrained enough that we can conservatively coalesce all callee-saved tmps into the corresponding registers +// when we rebuild the graph, if we know callee-saved regs are live at exit, we'll recognize that these regs now confict with everything, +// whch prevents us from aggressivly coalescing all the remaining moves +// if we DON'T know they're live at exit, we'll coalesce everything +// specifically, we'll coalesce di, si, cx, r8, and r9 into the corresponding registers, and coalesce x, x1, and x2 +// but then x/x1/x2 will conflict with all caller-saved regs, so we'll put it in a callee-saved reg, clobbering its original value + +int cant_coalesce_fully(int di, int si) { // these will occupy DI, SI + int x = glob + 3; // 23 + if (di) { + int x1 = x * 4; // 92 + glob = glob / 3; + int cx = 1 - x1; // -91 + return callee(1,2,3,cx,4,5); + } + if (si) { + int x2 = x * 5; // 115 + int r8 = 2 - x2; // -113 + return callee(1,2,3,4,r8,5); + } + int x3 = x * 6; // 138 + int r9 = 3 - x3; // -135 + return callee(1,2,3,4,5,r9); +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/cdq_generates_ax.c b/chapter21/int_only/with_coalescing/cdq_generates_ax.c new file mode 100644 index 00000000..f88045e4 --- /dev/null +++ b/chapter21/int_only/with_coalescing/cdq_generates_ax.c @@ -0,0 +1,15 @@ +// test that (at least one of) idiv and cdq makes eax live +int glob = 10; + +int main() { + int coalesce_into_eax = glob * 2; + // in second round of coalescing, if we don't know eax if live, we'll coalesce it with product + int product = coalesce_into_eax + 4; + if (product != 24) + return -1; + int j = coalesce_into_eax % 10; // coalesce_into_eax should be coalsced into eax, j should be coalesced into edx + if (j) + return -2; + + return 0; +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/cmp_generates_operands.c b/chapter21/int_only/with_coalescing/cmp_generates_operands.c new file mode 100644 index 00000000..1ad71ceb --- /dev/null +++ b/chapter21/int_only/with_coalescing/cmp_generates_operands.c @@ -0,0 +1,20 @@ +int flag; + +int glob = 10; +int glob2 = 20; + +int main() { + int a = glob + 5; // 15 + int b = glob2 - 5; // 15 + + // we'll coalesce a and b + // into tmps that hold these sums + // if we don't think a and b are live afterward + glob = a + glob; // 25 + glob2 = b + glob2; // 35 + + if (a != b) { + return -1; + } + return (glob == 25 && glob2 == 35); +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/coalesce_prevents_spill.c b/chapter21/int_only/with_coalescing/coalesce_prevents_spill.c new file mode 100644 index 00000000..353b7a41 --- /dev/null +++ b/chapter21/int_only/with_coalescing/coalesce_prevents_spill.c @@ -0,0 +1,41 @@ +int glob = 20; +int glob2 = 30; +int glob3 = 40; +int flag = 0; + +int use(int a, int b, int c, int d, int e, int f, int g, int h); + +int target(int arg) { + + int a; + int b; + int c; + int d; + int e; + int f; + int g; + int h; + // a-h all conflict, + // but coalescing a w/ arg removes conflicts, which then lets us coalesce others w/ arg too + // flag prevents us from performing copy prop + if (flag) { + a = arg; + b = arg; + c = arg; + d = arg; + e = arg; + f = arg; + g = arg; + h = 2; + } else { + a = glob * 2; + b = a; + c = a; + d = a; + e = a; + f = a; + g = a; + h = 1; + } + return use(a,b,c,d,e,f, g,h); +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/eax_live_at_exit.c b/chapter21/int_only/with_coalescing/eax_live_at_exit.c new file mode 100644 index 00000000..0fbca933 --- /dev/null +++ b/chapter21/int_only/with_coalescing/eax_live_at_exit.c @@ -0,0 +1,16 @@ +int glob = 10; +int glob2; + +// first round of coalescing will coalesce x into EAX +// if we don't realize that EAX is live at exit, we'll then +// coalesce the temporary that holds x + 100 into eax, clobbering x + +int target() { + int x = glob + 1; + glob2 = x + 100; + return x; +} + +int main() { + return target() == 11 && glob2 == 111; +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/funcall_generates_args.c b/chapter21/int_only/with_coalescing/funcall_generates_args.c new file mode 100644 index 00000000..875c526f --- /dev/null +++ b/chapter21/int_only/with_coalescing/funcall_generates_args.c @@ -0,0 +1,24 @@ +int f(int a, int b); + +int glob = 10; + +int target() { + static int x; + static int y; + int a = glob + 1; + int b = glob + 2; + // we'll coalesce a and b with edi/esi b/c they're passed as params + // and, if we don't recognize that EDI/ESI are live, we'll _ALSO_ + // coalesce the temporaries that hold a * glob and b * glob with EDI/ESI too + x = a * glob; + y = b * glob; + int result = f(a, b); + // return result ==1 && x == 110 && y == 120; + if (result != 1) + return 1; + if (x != 110) + return 2; + if (y != 120) + return 3; + return 0; +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/george_coalesce.c b/chapter21/int_only/with_coalescing/george_coalesce.c new file mode 100644 index 00000000..b93fba93 --- /dev/null +++ b/chapter21/int_only/with_coalescing/george_coalesce.c @@ -0,0 +1,7 @@ +int callee(int a, int b, int c, int d, int e, int f); + +int target(int a, int b, int c, int d, int e, int f) { + // make sure we coalesce all params into corresponding registers, + // and result int EAX + return callee(a,b,c,d,e,f); +} \ No newline at end of file diff --git a/chapter21/int_only/with_coalescing/unary_generates_dst.c b/chapter21/int_only/with_coalescing/unary_generates_dst.c new file mode 100644 index 00000000..53b0f969 --- /dev/null +++ b/chapter21/int_only/with_coalescing/unary_generates_dst.c @@ -0,0 +1,30 @@ +// test that a unary instruction generates its destination, e.g. neg dst +// makes dst live (or at least doesn't kill it) + +int glob = 100; + +int target() { + int a = -100; + while (a < 0) { + // this addition becomes: + // movl %a, %tmp + // addl %glob, %tmp + // movl %tmp, %glob + // so unless we think a is still live, + // we'll coalesce a & tmp + glob = a + glob; + // after one round of coalescing this will be + // subl $1, %a.0 + // so we need to recognize that this sub instruction + // won't kill a + a = -a; + if (!(a == 100 || a == -100)) + return -1; + + } + return glob; +} + +int main() { + return target(); +} \ No newline at end of file diff --git a/chapter21/libraries/callee_saved_live_at_exit_lib.c b/chapter21/libraries/callee_saved_live_at_exit_lib.c new file mode 100644 index 00000000..ded7cc23 --- /dev/null +++ b/chapter21/libraries/callee_saved_live_at_exit_lib.c @@ -0,0 +1,40 @@ +extern int glob; + +int cant_coalesce_fully(int di, int si); + +int callee(int a, int b, int c, int d, int e, int f) { + if (!(a == 1 && b == 2 && c == 3)) + return -1000; // something went wrong + + if (d == -91 && e == 4 && f == 5) + return 1; // first call + + if (d == 4 && e == -113 && f== 5) + return 2; // second call + + if (d == 4 && e== 5 && f == -135) + return 3; // third call + + + return -2000; // something went wrong +} + +int target() { + int result = cant_coalesce_fully(1, 0); + if (result != 1) + return -10; + if (glob != 6) + return -11; + glob = 20; // reset glob to original value + result = cant_coalesce_fully(0, 1); + if (result != 2) + return -12; + if (glob != 20) + return -13; + result = cant_coalesce_fully(0, 0); + if (result != 3) + return -14; + if (glob != 20) + return -15; + return 0; +} \ No newline at end of file diff --git a/chapter21/libraries/coalesce_prevents_spill_lib.c b/chapter21/libraries/coalesce_prevents_spill_lib.c new file mode 100644 index 00000000..8c39ee17 --- /dev/null +++ b/chapter21/libraries/coalesce_prevents_spill_lib.c @@ -0,0 +1,3 @@ +int use(int a, int b, int c, int d, int e, int f, int g, int h) { + return a == 1 && b == 1 && c == 1 && d == 1 && e == 1 && f == 1 && g == 1 && h == 2; +} \ No newline at end of file diff --git a/chapter21/libraries/force_spill_dbl_lib.c b/chapter21/libraries/force_spill_dbl_lib.c new file mode 100644 index 00000000..c02d83ec --- /dev/null +++ b/chapter21/libraries/force_spill_dbl_lib.c @@ -0,0 +1,18 @@ +extern double glob; +extern double glob2; +double callee(double fourteen, double thirteen, double twelve, double eleven, double ten, double nine, double eight, double seven, double six, double five, double four, double three, double two, double one) { + + glob = 10; + glob2 = 11; + if (one == 1 && two == 2 && three == 3 && four == 4 && five == 5 && six == 6 && seven == 7 && eight == 8 && nine == 18 && ten == 10 && eleven == 15 && twelve == 7 && thirteen == 15. && fourteen == 180.) { + // expected results for first call + return 2; + } + + if (one == 188 && two == 0 && three == 94 && four == 2 && five == 0 && six == 92 && seven == 180 && eight == 1111 && nine == 81 && ten == 79 && eleven == 90 && twelve == 2 && thirteen == 30 && fourteen == 20) { + // expected results for second call + return 3; + } + + return 0; +} \ No newline at end of file diff --git a/chapter21/libraries/force_spill_lib.c b/chapter21/libraries/force_spill_lib.c new file mode 100644 index 00000000..9fcc31ef --- /dev/null +++ b/chapter21/libraries/force_spill_lib.c @@ -0,0 +1,18 @@ +extern int glob; +extern int glob2; +int callee(int twelve, int eleven, int ten, int nine, int eight, int seven, int six, int five, int four, int three, int two, int one) { + + glob = 10; + glob2 = 11; + if (one == 1 && two == 2 && three == 3 && four == 4 && five == 5 && six == 6 && seven == 7 && eight == 8 && nine == 18 && ten == 10 && eleven == 15 && twelve == 7) { + // expected results for first call + return 2; + } + + if (one == -377 && two == -469 && three == 0 && four == 92 && five == 60 && six == 550 && seven == 81 && eight == 79 && nine == 90 && ten == 2 && eleven == 30 && twelve == 20) { + // expected results for second call + return 3; + } + + return 0; +} \ No newline at end of file diff --git a/chapter21/libraries/force_spill_mixed_int_lib.c b/chapter21/libraries/force_spill_mixed_int_lib.c new file mode 100644 index 00000000..5348596f --- /dev/null +++ b/chapter21/libraries/force_spill_mixed_int_lib.c @@ -0,0 +1,18 @@ +extern int glob; +extern int glob2; +int callee(unsigned int twelve, double *eleven, int ten, signed char nine, int *eight, unsigned long seven, long six, unsigned int five, long four, unsigned int three, int two, unsigned char one) { + + glob = 10; + glob2 = 11; + if (one == 1 && two == 2 && three == 3 && four == 4 && five == 4294967295u && six == 8 && seven == 7 && *eight == 10 && nine == 8 && ten == 12 && *eleven == 5. && twelve == 1) { + // expected results for first call + return 2; + } + + if (one == 62 && two == -158 && three == 0 && four == 62 && five == 40 && six == 220 && seven == 62 && *eight == 11 && nine == 60 && ten == 2 && *eleven == 5. && twelve == 20) { + // expected results for first call + return 3; + } + + return 0; +} \ No newline at end of file diff --git a/chapter21/libraries/funcall_generates_args_lib.c b/chapter21/libraries/funcall_generates_args_lib.c new file mode 100644 index 00000000..b0323b87 --- /dev/null +++ b/chapter21/libraries/funcall_generates_args_lib.c @@ -0,0 +1,3 @@ +int f(int a, int b) { + return a == 11 && b == 12; +} \ No newline at end of file diff --git a/chapter21/libraries/george_lib.c b/chapter21/libraries/george_lib.c new file mode 100644 index 00000000..deb96a22 --- /dev/null +++ b/chapter21/libraries/george_lib.c @@ -0,0 +1,3 @@ +int callee(int a, int b, int c, int d, int e, int f) { + return a == 1 && b == 2 && c == 3 && d == 4 && e == 5 && f == 6; +} \ No newline at end of file diff --git a/chapter21/libraries/many_pseudos_fewer_conflicts_lib.c b/chapter21/libraries/many_pseudos_fewer_conflicts_lib.c new file mode 100644 index 00000000..34bc7e0e --- /dev/null +++ b/chapter21/libraries/many_pseudos_fewer_conflicts_lib.c @@ -0,0 +1,19 @@ +int no_spills(int one, int two, int flag); + +int client (int i) { + return 100 * i; +} + +int target() { + if (no_spills(1,2,0) != 206) + return 1; + if (no_spills(1,2,1) != 308) + return 2; + if (no_spills(1,2,2) != -90) + return 3; + if (no_spills(11,6,3) != 512) + return 4; + if (no_spills(12,2, 4) != 614) + return 5; + return 0; +} \ No newline at end of file diff --git a/chapter21/libraries/test_spill_metric_2_lib.c b/chapter21/libraries/test_spill_metric_2_lib.c new file mode 100644 index 00000000..121ec6b9 --- /dev/null +++ b/chapter21/libraries/test_spill_metric_2_lib.c @@ -0,0 +1,21 @@ +extern int glob1; +extern int glob2; +extern int glob3; +extern int glob4; +extern int glob5; +extern int glob6; + +int callee(int ok) { + if (!ok) { + // something went wrong already + return 0; + } + glob1 = glob1 / 2; + glob2 = glob2 - 2; + glob3 = glob3 + 2; + glob4 = glob4 / 3; + glob5 = glob5 + 5; + glob6 = glob6 / 2; + return 1; + +} \ No newline at end of file diff --git a/chapter21/libraries/test_spill_metric_lib.c b/chapter21/libraries/test_spill_metric_lib.c new file mode 100644 index 00000000..a2de611d --- /dev/null +++ b/chapter21/libraries/test_spill_metric_lib.c @@ -0,0 +1,21 @@ +#include + +extern int glob1; +extern int glob2; +extern int glob3; +extern int glob4; +extern int glob5; + +int callee(int a, int b, int c, int d, int e) { + if (a == 2 && b == 0 && c == 9 && d == 1 && e == 0) + return 1; + + return -100; +} + +int check_globals() { + if (glob1 == 2 && glob2 == 0 && glob3 == 9 && glob4 == 1 && glob5 == 1) + return 0; + raise(SIGSEGV); + return 0; +} \ No newline at end of file diff --git a/chapter21/libraries/test_spilling_dbls_lib.c b/chapter21/libraries/test_spilling_dbls_lib.c new file mode 100644 index 00000000..e69de29b diff --git a/chapter21/libraries/track_arg_registers_lib.c b/chapter21/libraries/track_arg_registers_lib.c new file mode 100644 index 00000000..06b4898c --- /dev/null +++ b/chapter21/libraries/track_arg_registers_lib.c @@ -0,0 +1,3 @@ +int callee(int a, int b, int c) { + return a == 1 && b == 8 && c == -3; +} \ No newline at end of file diff --git a/chapter21/libraries/track_dbl_arg_registers_lib.c b/chapter21/libraries/track_dbl_arg_registers_lib.c new file mode 100644 index 00000000..0e7111c4 --- /dev/null +++ b/chapter21/libraries/track_dbl_arg_registers_lib.c @@ -0,0 +1,5 @@ +int callee(double a, double b, double c) { + if (a == 2.0 && b == -5.0 && c == 2.0) + return 1; + return 0; +} \ No newline at end of file diff --git a/chapter21/wrapper_linux.s b/chapter21/wrapper_linux.s new file mode 100644 index 00000000..a5ddd81d --- /dev/null +++ b/chapter21/wrapper_linux.s @@ -0,0 +1,79 @@ + .section .rodata + .align 8 +Lone: + .double 1.0 +Ltwo: + .double 2.0 +Lthree: + .double 3.0 +Lfour: + .double 4.0 +Lfive: + .double 5.0 +Lsix: + .double 6.0 +Lseven: + .double 7.0 + .text + .globl main +main: +## %bb.0: + pushq %rbp + movq %rsp, %rbp + # save callee-saved regs + push %rbx + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + # give them arbitrary values + movq $-1, %rbx + movq $-2, %r12 + movq $-3, %r13 + movq $-4, %r14 + movq $-5, %r15 + # call target + movl $1, %edi + movl $2, %esi + movl $3, %edx + movl $4, %ecx + movl $5, %r8d + movl $6, %r9d + movsd Lone(%rip), %xmm0 + movsd Ltwo(%rip), %xmm1 + movsd Lthree(%rip), %xmm2 + movsd Lfour(%rip), %xmm3 + movsd Lfive(%rip), %xmm4 + movsd Lsix(%rip), %xmm5 + movsd Lseven(%rip), %xmm7 + callq target + # make sure values of callee-saved regs were preserved + cmpq $-1, %rbx + jne Lfail + cmpq $-2, %r12 + jne Lfail + cmp $-3, %r13 + jne Lfail + cmpq $-4, %r14 + jne Lfail + cmp $-5, %r15 + jne Lfail + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbx + popq %rbp + retq +Lfail: + # raise SIGSEGV + movl $11, %edi + call raise + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbx + popq %rbp + retq + diff --git a/chapter21/wrapper_osx.s b/chapter21/wrapper_osx.s new file mode 100644 index 00000000..ec818e93 --- /dev/null +++ b/chapter21/wrapper_osx.s @@ -0,0 +1,78 @@ + .literal8 +Lone: + .double 1.0 +Ltwo: + .double 2.0 +Lthree: + .double 3.0 +Lfour: + .double 4.0 +Lfive: + .double 5.0 +Lsix: + .double 6.0 +Lseven: + .double 7.0 + .text + .globl _main +_main: +## %bb.0: + pushq %rbp + movq %rsp, %rbp + # save callee-saved regs + push %rbx + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + # give them arbitrary values + movq $-1, %rbx + movq $-2, %r12 + movq $-3, %r13 + movq $-4, %r14 + movq $-5, %r15 + # call target + movl $1, %edi + movl $2, %esi + movl $3, %edx + movl $4, %ecx + movl $5, %r8d + movl $6, %r9d + movsd Lone(%rip), %xmm0 + movsd Ltwo(%rip), %xmm1 + movsd Lthree(%rip), %xmm2 + movsd Lfour(%rip), %xmm3 + movsd Lfive(%rip), %xmm4 + movsd Lsix(%rip), %xmm5 + movsd Lseven(%rip), %xmm7 + callq _target + # make sure values of callee-saved regs were preserved + cmpq $-1, %rbx + jne Lfail + cmpq $-2, %r12 + jne Lfail + cmp $-3, %r13 + jne Lfail + cmpq $-4, %r14 + jne Lfail + cmp $-5, %r15 + jne Lfail + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbx + popq %rbp + retq +Lfail: + # raise SIGSEGV + movl $11, %edi + call _raise + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbx + popq %rbp + retq + diff --git a/chapter4/invalid_parse_bitwise/double_operator.c b/chapter4/invalid_parse/extra_credit/bitwise_double_operator.c similarity index 100% rename from chapter4/invalid_parse_bitwise/double_operator.c rename to chapter4/invalid_parse/extra_credit/bitwise_double_operator.c diff --git a/chapter4/valid_bitwise/bit_and.c b/chapter4/valid/extra_credit/bitwise_and.c similarity index 100% rename from chapter4/valid_bitwise/bit_and.c rename to chapter4/valid/extra_credit/bitwise_and.c diff --git a/chapter4/valid_bitwise/bit_or.c b/chapter4/valid/extra_credit/bitwise_or.c similarity index 100% rename from chapter4/valid_bitwise/bit_or.c rename to chapter4/valid/extra_credit/bitwise_or.c diff --git a/chapter4/valid_bitwise/bitwise_precedence.c b/chapter4/valid/extra_credit/bitwise_precedence.c similarity index 100% rename from chapter4/valid_bitwise/bitwise_precedence.c rename to chapter4/valid/extra_credit/bitwise_precedence.c diff --git a/chapter4/valid_bitwise/shift_associativity.c b/chapter4/valid/extra_credit/bitwise_shift_associativity.c similarity index 100% rename from chapter4/valid_bitwise/shift_associativity.c rename to chapter4/valid/extra_credit/bitwise_shift_associativity.c diff --git a/chapter4/valid_bitwise/shift_associativity_2.c b/chapter4/valid/extra_credit/bitwise_shift_associativity_2.c similarity index 100% rename from chapter4/valid_bitwise/shift_associativity_2.c rename to chapter4/valid/extra_credit/bitwise_shift_associativity_2.c diff --git a/chapter4/valid/extra_credit/bitwise_shift_precedence.c b/chapter4/valid/extra_credit/bitwise_shift_precedence.c new file mode 100644 index 00000000..282e897f --- /dev/null +++ b/chapter4/valid/extra_credit/bitwise_shift_precedence.c @@ -0,0 +1,4 @@ +int main() +{ + return 40 << 4 + 12 >> 1; +} \ No newline at end of file diff --git a/chapter4/valid_bitwise/shiftl.c b/chapter4/valid/extra_credit/bitwise_shiftl.c similarity index 100% rename from chapter4/valid_bitwise/shiftl.c rename to chapter4/valid/extra_credit/bitwise_shiftl.c diff --git a/chapter4/valid_bitwise/shiftr.c b/chapter4/valid/extra_credit/bitwise_shiftr.c similarity index 100% rename from chapter4/valid_bitwise/shiftr.c rename to chapter4/valid/extra_credit/bitwise_shiftr.c diff --git a/chapter4/valid_bitwise/bit_xor.c b/chapter4/valid/extra_credit/bitwise_xor.c similarity index 100% rename from chapter4/valid_bitwise/bit_xor.c rename to chapter4/valid/extra_credit/bitwise_xor.c diff --git a/chapter4/valid_bitwise/shift_precedence.c b/chapter4/valid_bitwise/shift_precedence.c deleted file mode 100644 index c60f203a..00000000 --- a/chapter4/valid_bitwise/shift_precedence.c +++ /dev/null @@ -1,3 +0,0 @@ -int main() { - return 40 << 4 + 1200 >> 1; -} \ No newline at end of file diff --git a/chapter5/valid_bitwise/bitwise_precedence.c b/chapter5/valid/extra_credit/bitwise_precedence.c similarity index 100% rename from chapter5/valid_bitwise/bitwise_precedence.c rename to chapter5/valid/extra_credit/bitwise_precedence.c diff --git a/chapter6/invalid_parse_extra_credit/compound_initializer.c b/chapter6/invalid_parse/extra_credit/compound_initializer.c similarity index 100% rename from chapter6/invalid_parse_extra_credit/compound_initializer.c rename to chapter6/invalid_parse/extra_credit/compound_initializer.c diff --git a/chapter6/invalid_parse_extra_credit/compound_invalid_operator.c b/chapter6/invalid_parse/extra_credit/compound_invalid_operator.c similarity index 100% rename from chapter6/invalid_parse_extra_credit/compound_invalid_operator.c rename to chapter6/invalid_parse/extra_credit/compound_invalid_operator.c diff --git a/chapter6/invalid_semantics_extra_credit/compound_initializer.c b/chapter6/invalid_semantics/extra_credit/compound_initializer.c similarity index 100% rename from chapter6/invalid_semantics_extra_credit/compound_initializer.c rename to chapter6/invalid_semantics/extra_credit/compound_initializer.c diff --git a/chapter6/invalid_semantics_extra_credit/compound_invalid_lvalue.c b/chapter6/invalid_semantics/extra_credit/compound_invalid_lvalue.c similarity index 100% rename from chapter6/invalid_semantics_extra_credit/compound_invalid_lvalue.c rename to chapter6/invalid_semantics/extra_credit/compound_invalid_lvalue.c diff --git a/chapter6/valid_extra_credit/bitwise_and_vars.c b/chapter6/valid/extra_credit/bitwise_and_vars.c similarity index 100% rename from chapter6/valid_extra_credit/bitwise_and_vars.c rename to chapter6/valid/extra_credit/bitwise_and_vars.c diff --git a/chapter6/valid_extra_credit/bitwise_shiftl_variable.c b/chapter6/valid/extra_credit/bitwise_shiftl_variable.c similarity index 100% rename from chapter6/valid_extra_credit/bitwise_shiftl_variable.c rename to chapter6/valid/extra_credit/bitwise_shiftl_variable.c diff --git a/chapter6/valid_extra_credit/bitwise_shiftr_assign.c b/chapter6/valid/extra_credit/bitwise_shiftr_assign.c similarity index 100% rename from chapter6/valid_extra_credit/bitwise_shiftr_assign.c rename to chapter6/valid/extra_credit/bitwise_shiftr_assign.c diff --git a/chapter6/valid_extra_credit/compound_assignment_chained.c b/chapter6/valid/extra_credit/compound_assignment_chained.c similarity index 100% rename from chapter6/valid_extra_credit/compound_assignment_chained.c rename to chapter6/valid/extra_credit/compound_assignment_chained.c diff --git a/chapter6/valid_extra_credit/compound_assignment_use_result.c b/chapter6/valid/extra_credit/compound_assignment_use_result.c similarity index 100% rename from chapter6/valid_extra_credit/compound_assignment_use_result.c rename to chapter6/valid/extra_credit/compound_assignment_use_result.c diff --git a/chapter6/valid_extra_credit/compound_bitwise_and.c b/chapter6/valid/extra_credit/compound_bitwise_and.c similarity index 100% rename from chapter6/valid_extra_credit/compound_bitwise_and.c rename to chapter6/valid/extra_credit/compound_bitwise_and.c diff --git a/chapter6/valid_extra_credit/compound_bitwise_or.c b/chapter6/valid/extra_credit/compound_bitwise_or.c similarity index 100% rename from chapter6/valid_extra_credit/compound_bitwise_or.c rename to chapter6/valid/extra_credit/compound_bitwise_or.c diff --git a/chapter6/valid_extra_credit/compound_bitwise_shiftl.c b/chapter6/valid/extra_credit/compound_bitwise_shiftl.c similarity index 100% rename from chapter6/valid_extra_credit/compound_bitwise_shiftl.c rename to chapter6/valid/extra_credit/compound_bitwise_shiftl.c diff --git a/chapter6/valid_extra_credit/compound_bitwise_shiftr.c b/chapter6/valid/extra_credit/compound_bitwise_shiftr.c similarity index 100% rename from chapter6/valid_extra_credit/compound_bitwise_shiftr.c rename to chapter6/valid/extra_credit/compound_bitwise_shiftr.c diff --git a/chapter6/valid_extra_credit/compound_bitwise_xor.c b/chapter6/valid/extra_credit/compound_bitwise_xor.c similarity index 100% rename from chapter6/valid_extra_credit/compound_bitwise_xor.c rename to chapter6/valid/extra_credit/compound_bitwise_xor.c diff --git a/chapter6/valid_extra_credit/compound_divide.c b/chapter6/valid/extra_credit/compound_divide.c similarity index 100% rename from chapter6/valid_extra_credit/compound_divide.c rename to chapter6/valid/extra_credit/compound_divide.c diff --git a/chapter6/valid_extra_credit/compound_minus.c b/chapter6/valid/extra_credit/compound_minus.c similarity index 100% rename from chapter6/valid_extra_credit/compound_minus.c rename to chapter6/valid/extra_credit/compound_minus.c diff --git a/chapter6/valid_extra_credit/compound_mod.c b/chapter6/valid/extra_credit/compound_mod.c similarity index 100% rename from chapter6/valid_extra_credit/compound_mod.c rename to chapter6/valid/extra_credit/compound_mod.c diff --git a/chapter6/valid_extra_credit/compound_multiply.c b/chapter6/valid/extra_credit/compound_multiply.c similarity index 100% rename from chapter6/valid_extra_credit/compound_multiply.c rename to chapter6/valid/extra_credit/compound_multiply.c diff --git a/chapter6/valid_extra_credit/compound_plus.c b/chapter6/valid/extra_credit/compound_plus.c similarity index 100% rename from chapter6/valid_extra_credit/compound_plus.c rename to chapter6/valid/extra_credit/compound_plus.c diff --git a/chapter7/invalid_parse_extra_credit/invalid_label.c b/chapter7/invalid_lex/extra_credit/goto_bad_label.c similarity index 100% rename from chapter7/invalid_parse_extra_credit/invalid_label.c rename to chapter7/invalid_lex/extra_credit/goto_bad_label.c diff --git a/chapter7/invalid_parse_extra_credit/label_without_statement.c b/chapter7/invalid_parse/extra_credit/goto_label_without_statement.c similarity index 100% rename from chapter7/invalid_parse_extra_credit/label_without_statement.c rename to chapter7/invalid_parse/extra_credit/goto_label_without_statement.c diff --git a/chapter7/invalid_semantics_extra_credit/goto_missing_label.c b/chapter7/invalid_semantics/extra_credit/goto_missing_label.c similarity index 100% rename from chapter7/invalid_semantics_extra_credit/goto_missing_label.c rename to chapter7/invalid_semantics/extra_credit/goto_missing_label.c diff --git a/chapter7/valid_extra_credit/bitwise_ternary.c b/chapter7/valid/extra_credit/bitwise_ternary.c similarity index 100% rename from chapter7/valid_extra_credit/bitwise_ternary.c rename to chapter7/valid/extra_credit/bitwise_ternary.c diff --git a/chapter7/valid_extra_credit/compound_if_expression.c b/chapter7/valid/extra_credit/compound_if_expression.c similarity index 100% rename from chapter7/valid_extra_credit/compound_if_expression.c rename to chapter7/valid/extra_credit/compound_if_expression.c diff --git a/chapter7/valid_extra_credit/goto_after_declaration.c b/chapter7/valid/extra_credit/goto_after_declaration.c similarity index 100% rename from chapter7/valid_extra_credit/goto_after_declaration.c rename to chapter7/valid/extra_credit/goto_after_declaration.c diff --git a/chapter7/valid_extra_credit/goto_backwards.c b/chapter7/valid/extra_credit/goto_backwards.c similarity index 100% rename from chapter7/valid_extra_credit/goto_backwards.c rename to chapter7/valid/extra_credit/goto_backwards.c diff --git a/chapter7/valid_extra_credit/goto_label.c b/chapter7/valid/extra_credit/goto_label.c similarity index 100% rename from chapter7/valid_extra_credit/goto_label.c rename to chapter7/valid/extra_credit/goto_label.c diff --git a/chapter7/valid_extra_credit/label_and_var.c b/chapter7/valid/extra_credit/goto_label_and_var.c similarity index 100% rename from chapter7/valid_extra_credit/label_and_var.c rename to chapter7/valid/extra_credit/goto_label_and_var.c diff --git a/chapter7/valid_extra_credit/label_main.c b/chapter7/valid/extra_credit/goto_label_main.c similarity index 100% rename from chapter7/valid_extra_credit/label_main.c rename to chapter7/valid/extra_credit/goto_label_main.c diff --git a/chapter7/valid_extra_credit/label_main_2.c b/chapter7/valid/extra_credit/goto_label_main_2.c similarity index 100% rename from chapter7/valid_extra_credit/label_main_2.c rename to chapter7/valid/extra_credit/goto_label_main_2.c diff --git a/chapter7/valid_extra_credit/nested_label.c b/chapter7/valid/extra_credit/goto_nested_label.c similarity index 100% rename from chapter7/valid_extra_credit/nested_label.c rename to chapter7/valid/extra_credit/goto_nested_label.c diff --git a/chapter8/invalid_semantics_extra_credit/goto_use_before_declare.c b/chapter8/invalid_semantics/extra_credit/goto_use_before_declare.c similarity index 100% rename from chapter8/invalid_semantics_extra_credit/goto_use_before_declare.c rename to chapter8/invalid_semantics/extra_credit/goto_use_before_declare.c diff --git a/chapter8/invalid_semantics_extra_credit/use_before_declare.c b/chapter8/invalid_semantics_extra_credit/use_before_declare.c deleted file mode 100644 index 20d845c1..00000000 --- a/chapter8/invalid_semantics_extra_credit/use_before_declare.c +++ /dev/null @@ -1,9 +0,0 @@ -int main() { - int x = 0; - if (x != 0) { - return_y: - return y; // not declared - } - int y = 4; - goto return_y; -} \ No newline at end of file diff --git a/chapter8/valid_extra_credit/compound_subtract_in_block.c b/chapter8/valid/extra_credit/compound_subtract_in_block.c similarity index 100% rename from chapter8/valid_extra_credit/compound_subtract_in_block.c rename to chapter8/valid/extra_credit/compound_subtract_in_block.c diff --git a/chapter8/valid_extra_credit/goto_before_declaration.c b/chapter8/valid/extra_credit/goto_before_declaration.c similarity index 100% rename from chapter8/valid_extra_credit/goto_before_declaration.c rename to chapter8/valid/extra_credit/goto_before_declaration.c diff --git a/chapter8/valid_extra_credit/goto_inner_scope.c b/chapter8/valid/extra_credit/goto_inner_scope.c similarity index 100% rename from chapter8/valid_extra_credit/goto_inner_scope.c rename to chapter8/valid/extra_credit/goto_inner_scope.c diff --git a/chapter8/valid/use_in_inner_scope.c b/chapter8/valid/use_in_inner_scope.c index 129d0a50..104a7369 100644 --- a/chapter8/valid/use_in_inner_scope.c +++ b/chapter8/valid/use_in_inner_scope.c @@ -1,5 +1,9 @@ -int main() { +int main() +{ int x; + { + x = 3; + } { return x; } diff --git a/chapter9/invalid_parse_extra_credit/compound_assignment_invalid_decl.c b/chapter9/invalid_parse/extra_credit/compound_assignment_invalid_decl.c similarity index 100% rename from chapter9/invalid_parse_extra_credit/compound_assignment_invalid_decl.c rename to chapter9/invalid_parse/extra_credit/compound_assignment_invalid_decl.c diff --git a/chapter9/invalid_parse_extra_credit/switch_case_declaration.c b/chapter9/invalid_parse/extra_credit/switch_case_declaration.c similarity index 100% rename from chapter9/invalid_parse_extra_credit/switch_case_declaration.c rename to chapter9/invalid_parse/extra_credit/switch_case_declaration.c diff --git a/chapter9/invalid_parse_extra_credit/switch_goto_case.c b/chapter9/invalid_parse/extra_credit/switch_goto_case.c similarity index 100% rename from chapter9/invalid_parse_extra_credit/switch_goto_case.c rename to chapter9/invalid_parse/extra_credit/switch_goto_case.c diff --git a/chapter9/invalid_parse_extra_credit/switch_missing_case_value.c b/chapter9/invalid_parse/extra_credit/switch_missing_case_value.c similarity index 100% rename from chapter9/invalid_parse_extra_credit/switch_missing_case_value.c rename to chapter9/invalid_parse/extra_credit/switch_missing_case_value.c diff --git a/chapter9/invalid_parse_extra_credit/switch_missing_paren.c b/chapter9/invalid_parse/extra_credit/switch_missing_paren.c similarity index 100% rename from chapter9/invalid_parse_extra_credit/switch_missing_paren.c rename to chapter9/invalid_parse/extra_credit/switch_missing_paren.c diff --git a/chapter9/invalid_parse_extra_credit/switch_no_condition.c b/chapter9/invalid_parse/extra_credit/switch_no_condition.c similarity index 100% rename from chapter9/invalid_parse_extra_credit/switch_no_condition.c rename to chapter9/invalid_parse/extra_credit/switch_no_condition.c diff --git a/chapter9/invalid_semantics_extra_credit/switch_continue.c b/chapter9/invalid_semantics/extra_credit/switch_continue.c similarity index 100% rename from chapter9/invalid_semantics_extra_credit/switch_continue.c rename to chapter9/invalid_semantics/extra_credit/switch_continue.c diff --git a/chapter9/invalid_semantics_extra_credit/switch_duplicate_case.c b/chapter9/invalid_semantics/extra_credit/switch_duplicate_case.c similarity index 100% rename from chapter9/invalid_semantics_extra_credit/switch_duplicate_case.c rename to chapter9/invalid_semantics/extra_credit/switch_duplicate_case.c diff --git a/chapter9/invalid_semantics_extra_credit/switch_duplicate_default.c b/chapter9/invalid_semantics/extra_credit/switch_duplicate_default.c similarity index 100% rename from chapter9/invalid_semantics_extra_credit/switch_duplicate_default.c rename to chapter9/invalid_semantics/extra_credit/switch_duplicate_default.c diff --git a/chapter9/invalid_semantics_extra_credit/switch_invalid_case.c b/chapter9/invalid_semantics/extra_credit/switch_invalid_case.c similarity index 100% rename from chapter9/invalid_semantics_extra_credit/switch_invalid_case.c rename to chapter9/invalid_semantics/extra_credit/switch_invalid_case.c diff --git a/chapter9/invalid_semantics_extra_credit/switch_invalid_default.c b/chapter9/invalid_semantics/extra_credit/switch_invalid_default.c similarity index 100% rename from chapter9/invalid_semantics_extra_credit/switch_invalid_default.c rename to chapter9/invalid_semantics/extra_credit/switch_invalid_default.c diff --git a/chapter9/invalid_semantics_extra_credit/switch_non_constant_case.c b/chapter9/invalid_semantics/extra_credit/switch_non_constant_case.c similarity index 100% rename from chapter9/invalid_semantics_extra_credit/switch_non_constant_case.c rename to chapter9/invalid_semantics/extra_credit/switch_non_constant_case.c diff --git a/chapter9/invalid_semantics/out_of_scope_loop_variable.c b/chapter9/invalid_semantics/out_of_scope_loop_variable.c index 8965ff1a..0592fa86 100644 --- a/chapter9/invalid_semantics/out_of_scope_loop_variable.c +++ b/chapter9/invalid_semantics/out_of_scope_loop_variable.c @@ -1,5 +1,7 @@ -int main() { - (i = 0; i < 1; i = i + 1) { +int main() +{ + for (i = 0; i < 1; i = i + 1) + { return 0; } } \ No newline at end of file diff --git a/chapter9/valid_extra_credit/compound_assignment_for_loop.c b/chapter9/valid/extra_credit/compound_assignment_for_loop.c similarity index 100% rename from chapter9/valid_extra_credit/compound_assignment_for_loop.c rename to chapter9/valid/extra_credit/compound_assignment_for_loop.c diff --git a/chapter9/valid_extra_credit/goto_bypass_condition.c b/chapter9/valid/extra_credit/goto_bypass_condition.c similarity index 100% rename from chapter9/valid_extra_credit/goto_bypass_condition.c rename to chapter9/valid/extra_credit/goto_bypass_condition.c diff --git a/chapter9/valid_extra_credit/goto_loop_body.c b/chapter9/valid/extra_credit/goto_loop_body.c similarity index 100% rename from chapter9/valid_extra_credit/goto_loop_body.c rename to chapter9/valid/extra_credit/goto_loop_body.c diff --git a/chapter9/valid_extra_credit/switch.c b/chapter9/valid/extra_credit/switch.c similarity index 100% rename from chapter9/valid_extra_credit/switch.c rename to chapter9/valid/extra_credit/switch.c diff --git a/chapter9/valid_extra_credit/switch_assign_in_body.c b/chapter9/valid/extra_credit/switch_assign_in_body.c similarity index 100% rename from chapter9/valid_extra_credit/switch_assign_in_body.c rename to chapter9/valid/extra_credit/switch_assign_in_body.c diff --git a/chapter9/valid_extra_credit/switch_assign_in_condition.c b/chapter9/valid/extra_credit/switch_assign_in_condition.c similarity index 100% rename from chapter9/valid_extra_credit/switch_assign_in_condition.c rename to chapter9/valid/extra_credit/switch_assign_in_condition.c diff --git a/chapter9/valid_extra_credit/switch_block.c b/chapter9/valid/extra_credit/switch_block.c similarity index 100% rename from chapter9/valid_extra_credit/switch_block.c rename to chapter9/valid/extra_credit/switch_block.c diff --git a/chapter9/valid_extra_credit/switch_break.c b/chapter9/valid/extra_credit/switch_break.c similarity index 100% rename from chapter9/valid_extra_credit/switch_break.c rename to chapter9/valid/extra_credit/switch_break.c diff --git a/chapter9/valid_extra_credit/switch_decl.c b/chapter9/valid/extra_credit/switch_decl.c similarity index 100% rename from chapter9/valid_extra_credit/switch_decl.c rename to chapter9/valid/extra_credit/switch_decl.c diff --git a/chapter9/valid_extra_credit/switch_default.c b/chapter9/valid/extra_credit/switch_default.c similarity index 100% rename from chapter9/valid_extra_credit/switch_default.c rename to chapter9/valid/extra_credit/switch_default.c diff --git a/chapter9/valid_extra_credit/switch_default_fallthrough.c b/chapter9/valid/extra_credit/switch_default_fallthrough.c similarity index 100% rename from chapter9/valid_extra_credit/switch_default_fallthrough.c rename to chapter9/valid/extra_credit/switch_default_fallthrough.c diff --git a/chapter9/valid_extra_credit/switch_default_not_last.c b/chapter9/valid/extra_credit/switch_default_not_last.c similarity index 100% rename from chapter9/valid_extra_credit/switch_default_not_last.c rename to chapter9/valid/extra_credit/switch_default_not_last.c diff --git a/chapter9/valid_extra_credit/switch_empty.c b/chapter9/valid/extra_credit/switch_empty.c similarity index 100% rename from chapter9/valid_extra_credit/switch_empty.c rename to chapter9/valid/extra_credit/switch_empty.c diff --git a/chapter9/valid_extra_credit/switch_fallthrough.c b/chapter9/valid/extra_credit/switch_fallthrough.c similarity index 100% rename from chapter9/valid_extra_credit/switch_fallthrough.c rename to chapter9/valid/extra_credit/switch_fallthrough.c diff --git a/chapter9/valid_extra_credit/switch_goto_mid_case.c b/chapter9/valid/extra_credit/switch_goto_mid_case.c similarity index 100% rename from chapter9/valid_extra_credit/switch_goto_mid_case.c rename to chapter9/valid/extra_credit/switch_goto_mid_case.c diff --git a/chapter9/valid_extra_credit/switch_in_loop.c b/chapter9/valid/extra_credit/switch_in_loop.c similarity index 100% rename from chapter9/valid_extra_credit/switch_in_loop.c rename to chapter9/valid/extra_credit/switch_in_loop.c diff --git a/chapter9/valid_extra_credit/switch_nested_case.c b/chapter9/valid/extra_credit/switch_nested_case.c similarity index 100% rename from chapter9/valid_extra_credit/switch_nested_case.c rename to chapter9/valid/extra_credit/switch_nested_case.c diff --git a/chapter9/valid_extra_credit/switch_nested_not_taken.c b/chapter9/valid/extra_credit/switch_nested_not_taken.c similarity index 100% rename from chapter9/valid_extra_credit/switch_nested_not_taken.c rename to chapter9/valid/extra_credit/switch_nested_not_taken.c diff --git a/chapter9/valid_extra_credit/switch_nested_switch.c b/chapter9/valid/extra_credit/switch_nested_switch.c similarity index 100% rename from chapter9/valid_extra_credit/switch_nested_switch.c rename to chapter9/valid/extra_credit/switch_nested_switch.c diff --git a/chapter9/valid_extra_credit/switch_no_case.c b/chapter9/valid/extra_credit/switch_no_case.c similarity index 100% rename from chapter9/valid_extra_credit/switch_no_case.c rename to chapter9/valid/extra_credit/switch_no_case.c diff --git a/chapter9/valid_extra_credit/continue_in_switch.c b/chapter9/valid/extra_credit/switch_with_continue.c similarity index 100% rename from chapter9/valid_extra_credit/continue_in_switch.c rename to chapter9/valid/extra_credit/switch_with_continue.c diff --git a/chapter9/valid_extra_credit/loop_in_switch.c b/chapter9/valid/extra_credit/switch_with_loop.c similarity index 100% rename from chapter9/valid_extra_credit/loop_in_switch.c rename to chapter9/valid/extra_credit/switch_with_loop.c diff --git a/generate_expected_results.py b/generate_expected_results.py new file mode 100755 index 00000000..a2d89d3c --- /dev/null +++ b/generate_expected_results.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +"""A utility script that runs every test program with the system compiler and records its return code and output""" + +from __future__ import annotations + +import itertools +import json +import subprocess +import sys +from pathlib import Path +from typing import Any + +results : dict[str, dict[str, Any]]= {} + +# NOTE: this doesn't work for Python 3.8 or earlier (for non-modules, __file__ is relative!) +ROOT_DIR = Path(__file__).parent + +if sys.platform == 'darwin': + WRAPPER_SCRIPT = ROOT_DIR.joinpath('chapter21/wrapper_osx.s') +else: + WRAPPER_SCRIPT = ROOT_DIR.joinpath('chapter21/wrapper_linux.s') + +LIBRARIES = { + "track_arg_registers": "track_arg_registers_lib.c", + "force_spill": "force_spill_lib.c", + "spills_and_rewrites": "force_spill_lib.c", + "spills_rewrites_compare":"force_spill_lib.c", + "rewrite_large_multiply":"force_spill_lib.c", + "spill_movz_dst": "force_spill_lib.c", + "test_spill_metric": "test_spill_metric_lib.c", + "test_spill_metric_2": "test_spill_metric_2_lib.c", + "many_pseudos_fewer_conflicts": "many_pseudos_fewer_conflicts_lib.c", + "track_dbl_arg_registers": "track_dbl_arg_registers_lib.c", + "test_spilling_dbls": "force_spill_dbl_lib.c", + "mixed_ints": "force_spill_mixed_int_lib.c", + "callee_saved_live_at_exit": "callee_saved_live_at_exit_lib.c", + "funcall_generates_args": "funcall_generates_args_lib.c", + "george_coalesce": "george_lib.c", + "coalesce_prevents_spill": "coalesce_prevents_spill_lib.c" +} + +all_valid_progs = itertools.chain(ROOT_DIR.glob("chapter*/valid/**/*.c"), + ROOT_DIR.glob("chapter*/valid_extra_credit/**/*.c"), + ROOT_DIR.glob("chapter20/**/*.c"), + ROOT_DIR.glob("chapter21/**/*.c")) + +# iterate over all valid programs +for prog in all_valid_progs: + source_files = [str(prog)] + if "libraries" in prog.parts: + if prog.name.endswith("_client.c"): + + # if this is the client, don't compile here, we'll compile it when we get to the library + continue + + if "chapter21" in prog.parts: + # these are libraries used by chapter 21 tests, not test programs themselves + continue + + # compile client and library together + client = prog.parent.joinpath(prog.name.replace(".c", "_client.c")) + source_files.append(str(client)) + + # compile the program + # TODO this is copied from TestBase + + try: + subprocess.run(["gcc"] + source_files + ["-Wno-incompatible-library-redeclaration", "-o", prog.stem], + check=True, capture_output=True) + except subprocess.CalledProcessError as e: + + + # if it's a chapter 21 test, may need to compile against wrapper script + if "chapter21" in prog.parts: + source_files.append(str(WRAPPER_SCRIPT)) + if prog.stem in LIBRARIES: + lib_path = ROOT_DIR.joinpath("chapter21/libraries", LIBRARIES[prog.stem]) + source_files.append(str(lib_path)) + try: + subprocess.run(["gcc"] + source_files + ["-Wno-incompatible-library-redeclaration", "-o", prog.stem], + check=True, capture_output=True) + except subprocess.CalledProcessError as inner_e: + raise RuntimeError(inner_e.stderr) from inner_e + else: + raise RuntimeError(e.stderr) from e + + + exe = Path.joinpath(ROOT_DIR, prog.stem) + # run the program + try: + result = subprocess.run([exe], check=False, text=True, capture_output=True) + if result.stderr: + raise RuntimeError(result.stderr) + + result_dict: dict[str, Any] = {"return_code": result.returncode} + if result.stdout: + result_dict["stdout"] = result.stdout + + + key = str(prog.relative_to(ROOT_DIR)) + results[key] = result_dict + finally: + # delete executable + Path.unlink(exe) + + +with open("expected_results.json", "w") as f: + json.dump(results, f) \ No newline at end of file diff --git a/test_compiler b/test_compiler new file mode 100755 index 00000000..6324a168 --- /dev/null +++ b/test_compiler @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import tests.runner + +if __name__ == "__main__": + tests.runner.main() diff --git a/test_properties.json b/test_properties.json new file mode 100644 index 00000000..354ef107 --- /dev/null +++ b/test_properties.json @@ -0,0 +1,273 @@ +{ + "extra_credit_tests": { + "chapter4/invalid_parse/extra_credit/bitwise_double_operator.c": [ + "bitwise" + ], + "chapter4/valid/extra_credit/bitwise_and.c": [ + "bitwise" + ], + "chapter4/valid/extra_credit/bitwise_or.c": [ + "bitwise" + ], + "chapter4/valid/extra_credit/bitwise_precedence.c": [ + "bitwise" + ], + "chapter4/valid/extra_credit/bitwise_shift_associativity.c": [ + "bitwise" + ], + "chapter4/valid/extra_credit/bitwise_shift_associativity_2.c": [ + "bitwise" + ], + "chapter4/valid/extra_credit/bitwise_shift_precedence.c": [ + "bitwise" + ], + "chapter4/valid/extra_credit/bitwise_shiftl.c": [ + "bitwise" + ], + "chapter4/valid/extra_credit/bitwise_shiftr.c": [ + "bitwise" + ], + "chapter4/valid/extra_credit/bitwise_xor.c": [ + "bitwise" + ], + "chapter5/valid/extra_credit/bitwise_precedence.c": [ + "bitwise" + ], + "chapter6/invalid_parse/extra_credit/compound_initializer.c": [ + "compound" + ], + "chapter6/invalid_parse/extra_credit/compound_invalid_operator.c": [ + "compound" + ], + "chapter6/invalid_semantics/extra_credit/compound_initializer.c": [ + "compound" + ], + "chapter6/invalid_semantics/extra_credit/compound_invalid_lvalue.c": [ + "compound" + ], + "chapter6/valid/extra_credit/bitwise_and_vars.c": [ + "bitwise" + ], + "chapter6/valid/extra_credit/bitwise_shiftl_variable.c": [ + "bitwise" + ], + "chapter6/valid/extra_credit/bitwise_shiftr_assign.c": [ + "bitwise" + ], + "chapter6/valid/extra_credit/compound_assignment_chained.c": [ + "compound" + ], + "chapter6/valid/extra_credit/compound_assignment_use_result.c": [ + "compound" + ], + "chapter6/valid/extra_credit/compound_bitwise_and.c": [ + "bitwise", + "compound" + ], + "chapter6/valid/extra_credit/compound_bitwise_or.c": [ + "bitwise", + "compound" + ], + "chapter6/valid/extra_credit/compound_bitwise_shiftl.c": [ + "bitwise", + "compound" + ], + "chapter6/valid/extra_credit/compound_bitwise_shiftr.c": [ + "bitwise", + "compound" + ], + "chapter6/valid/extra_credit/compound_bitwise_xor.c": [ + "bitwise", + "compound" + ], + "chapter6/valid/extra_credit/compound_divide.c": [ + "compound" + ], + "chapter6/valid/extra_credit/compound_minus.c": [ + "compound" + ], + "chapter6/valid/extra_credit/compound_mod.c": [ + "compound" + ], + "chapter6/valid/extra_credit/compound_multiply.c": [ + "compound" + ], + "chapter6/valid/extra_credit/compound_plus.c": [ + "compound" + ], + "chapter7/invalid_lex/extra_credit/goto_bad_label.c": [ + "goto" + ], + "chapter7/invalid_parse/extra_credit/goto_label_without_statement.c": [ + "goto" + ], + "chapter7/invalid_semantics/extra_credit/goto_missing_label.c": [ + "goto" + ], + "chapter7/valid/extra_credit/bitwise_ternary.c": [ + "bitwise" + ], + "chapter7/valid/extra_credit/compound_if_expression.c": [ + "compound" + ], + "chapter7/valid/extra_credit/goto_after_declaration.c": [ + "goto" + ], + "chapter7/valid/extra_credit/goto_backwards.c": [ + "goto" + ], + "chapter7/valid/extra_credit/goto_label.c": [ + "goto" + ], + "chapter7/valid/extra_credit/goto_label_and_var.c": [ + "goto" + ], + "chapter7/valid/extra_credit/goto_label_main.c": [ + "goto" + ], + "chapter7/valid/extra_credit/goto_label_main_2.c": [ + "goto" + ], + "chapter7/valid/extra_credit/goto_nested_label.c": [ + "goto" + ], + "chapter8/invalid_semantics/extra_credit/goto_use_before_declare.c": [ + "goto" + ], + "chapter8/valid/extra_credit/compound_subtract_in_block.c": [ + "compound" + ], + "chapter8/valid/extra_credit/goto_before_declaration.c": [ + "goto" + ], + "chapter8/valid/extra_credit/goto_inner_scope.c": [ + "goto" + ], + "chapter9/invalid_parse/extra_credit/compound_assignment_invalid_decl.c": [ + "compound" + ], + "chapter9/invalid_parse/extra_credit/switch_case_declaration.c": [ + "switch" + ], + "chapter9/invalid_parse/extra_credit/switch_goto_case.c": [ + "switch", + "goto" + ], + "chapter9/invalid_parse/extra_credit/switch_missing_case_value.c": [ + "switch" + ], + "chapter9/invalid_parse/extra_credit/switch_missing_paren.c": [ + "switch" + ], + "chapter9/invalid_parse/extra_credit/switch_no_condition.c": [ + "switch" + ], + "chapter9/invalid_semantics/extra_credit/switch_continue.c": [ + "switch" + ], + "chapter9/invalid_semantics/extra_credit/switch_duplicate_case.c": [ + "switch" + ], + "chapter9/invalid_semantics/extra_credit/switch_duplicate_default.c": [ + "switch" + ], + "chapter9/invalid_semantics/extra_credit/switch_invalid_case.c": [ + "switch" + ], + "chapter9/invalid_semantics/extra_credit/switch_invalid_default.c": [ + "switch" + ], + "chapter9/invalid_semantics/extra_credit/switch_non_constant_case.c": [ + "switch" + ], + "chapter9/valid/extra_credit/compound_assignment_for_loop.c": [ + "compound" + ], + "chapter9/valid/extra_credit/goto_bypass_condition.c": [ + "goto" + ], + "chapter9/valid/extra_credit/goto_loop_body.c": [ + "goto" + ], + "chapter9/valid/extra_credit/switch.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_assign_in_body.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_assign_in_condition.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_block.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_break.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_decl.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_default.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_default_fallthrough.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_default_not_last.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_empty.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_fallthrough.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_goto_mid_case.c": [ + "switch", + "goto" + ], + "chapter9/valid/extra_credit/switch_in_loop.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_nested_case.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_nested_not_taken.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_nested_switch.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_no_case.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_with_continue.c": [ + "switch" + ], + "chapter9/valid/extra_credit/switch_with_loop.c": [ + "switch" + ], + "chapter10/invalid_declarations/extra_credit/goto_cross_function.c": [ + "goto" + ], + "chapter10/invalid_declarations/extra_credit/goto_function.c": [ + "goto" + ], + "chapter10/invalid_types/extra_credit/compound_assignment_function_call.c": [ + "compound" + ], + "chapter10/invalid_types/extra_credit/switch_on_function.c": [ + "switch" + ], + "chapter10/valid/extra_credit/compound_assign_function_result.c": [ + "compound" + ], + "chapter10/valid/extra_credit/goto_label_multiple_functions.c": [ + "goto" + ], + "chapter10/valid/extra_credit/goto_shared_name.c": [ + "goto" + ] + }, + "requires_mathlib": [] +} \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/basic.py b/tests/basic.py new file mode 100644 index 00000000..79ecf055 --- /dev/null +++ b/tests/basic.py @@ -0,0 +1,628 @@ +"""Basic tests for Parts I & II""" +from __future__ import annotations + +import json +import subprocess +import unittest +from enum import Flag, auto, unique +from pathlib import Path +from typing import Any, Callable, Optional, Sequence, Type + +# Constants + per-test info from configuration files +# TODO should this be in a separate module maybe? + +ROOT_DIR = Path(__file__).parent.parent + +EXPECTED_RESULTS: dict[str, Any] + +with open("expected_results.json", "r", encoding="utf-8") as f: + EXPECTED_RESULTS = json.load(f) + +EXTRA_CREDIT_PROGRAMS: dict[str, list[str]] +REQUIRES_MATHLIB: list[str] +with open("test_properties.json", "r", encoding="utf-8") as f: + test_info = json.load(f) + EXTRA_CREDIT_PROGRAMS = test_info["extra_credit_tests"] + REQUIRES_MATHLIB = test_info["requires_mathlib"] + +# main TestChapter class + related utilities + + +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 + """ + objfile = prog.with_suffix(".o") + + # IMPORTANT: if we're building a library, and 'gcc' command actually + # points to clang, which it does on macOS, we must _not_ enable optimizations + # Clang optimizes out sign-/zero-extension for narrow args + # which violates the System V ABI and breaks ABI compatibility + # with our implementation + # see https://stackoverflow.com/a/36760539 + try: + subprocess.run( + [ + "gcc", + prog, + "-c", + "-fstack-protector-all", + "-Wno-incompatible-library-redeclaration", + "-o", + objfile, + ], + check=True, + ) + except subprocess.CalledProcessError as err: + raise RuntimeError(err.stderr) from err + + +def replace_stem(path: Path, new_stem: str) -> Path: + """Return a new path with the stem changed and suffix the same""" + try: + return path.with_stem(new_stem) + except AttributeError: + # python versions before 3.9 + # stick old suffix on new stem + return path.with_name(new_stem).with_suffix(path.suffix) + + +class TestChapter(unittest.TestCase): + """Base per-chapter test class - should be subclassed, not instantiated directly. + + For each chapter under test, we construct a subclass of TestChapter and generate + a test method for each C program in the corresponding directory. Each dynamically generated + test calls one of the main test methods defined below: + + * compile_failure: compilation should fail) + * compile_success: compilation should succeed up to some intermediate stage) + * compile_and_run: compiling and running the test program should give the expected result) + * compile_client_and_run: the test program consists of a client and library. + compiling the client with our compiler and library with the system compiler, + run the compiled program, and validate the result + * compile_lib_and_run: + like compile_client_and_run, but compile the *library* withour compiler + and *client* with the system compiler + + The other methods in TestChapter are all utilties called by the compile_* methods. + """ + + longMessage = False + + # Attributes that each subclass must override + + # absolute path to this chapter's subdirectory + # (e.g. /path/to/write-a-c-compiler-tests/chapter_1/) + test_dir: Path + + # absolute path to the compiler under test + cc: Path + + # list of command-line options to pass through to the compiler under test + options: list[str] + + # last stage of the compiler we're testing; None if we're testing the whole thing + exit_stage: str + + def tearDown(self) -> None: + """Delete files produced during this test run (e.g. assembly and object files)""" + garbage_files = ( + f + for f in self.test_dir.rglob("*") + if not f.is_dir() and f.suffix not in [".c", ".h"] + ) + + for junk in garbage_files: + junk.unlink() + + def gcc_compile_and_run(self, *args: Path) -> subprocess.CompletedProcess[str]: + """Compile input files using 'gcc' command and run the resulting executable + + Args: + args: list of input files - could be C, assembly, or object files + + Returns: + a CompletedProecess object that captures the executable's return code and output + """ + + # output file is same as first input without suffix + exe = args[0].with_suffix("") + + # compile it + try: + subprocess.run( + ["gcc", "-Wno-incompatible-library-redeclaration"] + + list(args) + + ["-o", exe], + check=True, + text=True, + capture_output=True, # capture output so we don't see warnings + ) + except subprocess.CalledProcessError as err: + # This is an internal error in the test suite + # 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) + + def invoke_compiler( + self, source_file: Path, cc_opt: Optional[str] = None + ) -> subprocess.CompletedProcess[str]: + """Compile the test program (possibly up to some intermediate stage), but don't run it. + + Args: + source_file: Absolute path to source file + cc_opt (optional): Additional command-line options to pass to compiler + (in addition to exit stage and anything specified in self.options). + Used to compile without linking (for library tests); + to link math library; and to compile to assembly (for optimization tests) + + Returns: + A CompletedObject the captures the result of compilation (including an exit code + indicating whether it succeeded and any error messages produced by the compiler) + """ + if cc_opt is None and self.exit_stage is not None: + cc_opt = f"--{self.exit_stage}" + + args = [self.cc] + self.options + if cc_opt is not None: + args.append(cc_opt) + + args.append(source_file) + + # run the command: '{self.cc} {options} {source_file}' + proc = subprocess.run(args, capture_output=True, check=False, text=True) + return proc + + def validate_no_output(self, source_file: Path) -> None: + """Make sure the compiler under test didn't emit executable or assembly code. + + Used when compiling invalid test cases or testing intermediate stages.""" + + # if we compiled /path/to/foo.c, look for /path/to/foo.s + stem = source_file.stem + assembly_file = source_file.parent / f"{stem}.s" + self.assertFalse( + assembly_file.exists(), + msg=f"Found assembly file {assembly_file} for invalid program!", + ) + + # now look for /path/to/foo + executable_file = source_file.parent / stem + self.assertFalse(executable_file.exists()) + + def validate_runs( + self, source_file: Path, actual: subprocess.CompletedProcess[str] + ) -> None: + """Validate that the running compiled executable gave the expected result. + + Compare return code and stdout to values in EXPECTED_RESULTS. + + Args: + source_file: Absolute path of the source file for a test program + actual: result of compiling this source file with self.cc and running it + """ + key = str(source_file.relative_to(ROOT_DIR)) + expected = EXPECTED_RESULTS[key] + expected_retcode = expected["return_code"] + expected_stdout = expected.get("stdout", "") + + exe = actual.args[0] + self.assertEqual( + expected_retcode, + actual.returncode, + msg=f"Expected return code {expected_retcode}, found {actual.returncode} in {exe}", + ) + self.assertEqual( + expected_stdout, + actual.stdout, + msg=f"Expected output {expected_stdout}, found {actual.stdout} in {exe}", + ) + + # none of our test programs write to stderr + self.assertFalse( + actual.stderr, msg=f"Unexpected error output {actual.stderr} in {exe}" + ) + + def compile_failure(self, source_file: Path) -> None: + """Test that compiling an invalid program returns a non-zero exit code + + Use this when compilation of the test program should fail at or before the stage under test. + E.g. if type_error.c contains a type error, + when we use the --stage validate option, test_type_error will call compile_failure + but when we use the --stage parse option, test_type_error will call compile_success (below) + """ + with self.assertRaises( + subprocess.CalledProcessError, msg=f"Didn't catch error in {source_file}" + ): + result = self.invoke_compiler(source_file) + result.check_returncode() # raise CalledProcessError if return code is non-zero + + self.validate_no_output(source_file) + + def compile_success(self, source_file: Path) -> None: + """Test that compiling a valid program returns exit code of 0. + + Use this when compilation of the program should succeed up until the stage under test. + This is only used when testing an intermediate stage; when testing the whole compiler, + use compile_and_run instead.""" + # run compiler up to stage, make sure it doesn't throw an exception + result = self.invoke_compiler(source_file) + self.assertEqual( + result.returncode, + 0, + msg=f"compilation of {source_file} failed with error:\n{result.stderr}", + ) + + # make sure we didn't emit executable or assembly code + self.validate_no_output(source_file) + + def compile_and_run(self, source_file: Path) -> None: + """Compile a valid test program, run it, and validate the results""" + + # include -lm for standard library test on linux + if "linux" in self.options and str(source_file) in REQUIRES_MATHLIB: + cc_opt = "-lm" + else: + cc_opt = None + + # run compiler, make sure it succeeds + compile_result = self.invoke_compiler(source_file, cc_opt=cc_opt) + self.assertEqual( + compile_result.returncode, + 0, + msg=f"compilation of {source_file} failed with error:\n{compile_result.stderr}", + ) + + # run the executable + # TODO cleaner handling if executable doesn't exist? or check that it exists above? + exe = source_file.with_suffix("") + result = subprocess.run([exe], check=False, capture_output=True, text=True) + + self.validate_runs(source_file, result) + + def library_test_helper( + self, file_under_test: Path, other_file: Path, results_key: Path + ) -> None: + """Compile one file in a multi-file program and validate the results. + + Compile file_under_test with compiler under test and other_file with 'gcc' command. + Link 'em together, run the resulting executable, make validate the results. + + Args: + file_under_test: Absolute path of one file in a multi-file program + (the one we want to compile with self.cc) + other_file: Absolute path to the other file in the multi-file program + results_key: key to use in EXPECTED_RESULTS; will be either file_under_test + or other_file, whichever one is the library file + """ + + # compile file_under_test and make sure it succeeds + compilation_result = self.invoke_compiler(file_under_test, cc_opt="-c") + self.assertEqual( + compilation_result.returncode, + 0, + msg=f"compilation of {file_under_test} failed with error:\n{compilation_result.stderr}", + ) + + # compile other_file + gcc_build_obj(other_file) + + # link both object files and run resulting executable + result = self.gcc_compile_and_run( + file_under_test.with_suffix(".o"), other_file.with_suffix(".o") + ) + + # validate results; we pass lib_source as first arg here + # b/c it's the key for library tests in EXPECTED_RESULTS + self.validate_runs(results_key, result) + + def compile_client_and_run(self, client_path: Path) -> None: + """Multi-file program test where our compiler compiles the client""" + + # _client.c should have corresponding library .c in the same directory + lib_path = replace_stem(client_path, client_path.stem[: -len("_client")]) + self.library_test_helper(client_path, lib_path, lib_path) + + def compile_lib_and_run(self, lib_path: Path) -> None: + """Multi-file program test where our compiler compiles the library""" + + # program path .c should have corresponding _client.c in same directory + client_path = replace_stem(lib_path, lib_path.stem + "_client") + self.library_test_helper(lib_path, client_path, lib_path) + + +# Automatically generating test classes + methods + + +class TestDirs: + """Subdirectory names within each test directory""" + + # invalid programs + INVALID_LEX = "invalid_lex" + INVALID_PARSE = "invalid_parse" + INVALID_SEMANTICS = "invalid_semantics" + INVALID_DECLARATIONS = "invalid_declarations" + INVALID_TYPES = "invalid_types" + INVALID_STRUCT_TAGS = "invalid_struct_tags" + # valid test programs for parts I & II + # (we'll handle part III test sdifferently) + VALID = "valid" + + +dirs = { + "invalid": [ + TestDirs.INVALID_LEX, + TestDirs.INVALID_PARSE, + TestDirs.INVALID_SEMANTICS, + TestDirs.INVALID_DECLARATIONS, + TestDirs.INVALID_TYPES, + TestDirs.INVALID_STRUCT_TAGS, + ], + "valid": [TestDirs.VALID], +} + +# For a particular stage under test (specified by --test option), +# look up which test programs compiler should process successfully +# and which ones it should reject +DIRECTORIES_BY_STAGE = { + "lex": { + "invalid": [TestDirs.INVALID_LEX], + "valid": [ + TestDirs.INVALID_PARSE, + TestDirs.INVALID_SEMANTICS, + TestDirs.INVALID_DECLARATIONS, + TestDirs.INVALID_TYPES, + TestDirs.INVALID_STRUCT_TAGS, + ] + + dirs["valid"], + }, + "parse": { + "invalid": [TestDirs.INVALID_LEX, TestDirs.INVALID_PARSE], + "valid": [ + TestDirs.INVALID_SEMANTICS, + TestDirs.INVALID_DECLARATIONS, + TestDirs.INVALID_TYPES, + TestDirs.INVALID_STRUCT_TAGS, + ] + + dirs["valid"], + }, + "validate": dirs, + "tacky": dirs, + "codegen": dirs, + "run": dirs, +} + + +@unique +class ExtraCredit(Flag): + """An ExtraCredit flag represents a set of enabled extra-credit features""" + + BITWISE = auto() + COMPOUND = auto() + GOTO = auto() + SWITCH = auto() + NAN = auto() + NONE = 0 + ALL = BITWISE | COMPOUND | GOTO | SWITCH | NAN + + +def excluded_extra_credit(source_prog: Path, extra_credit_flags: ExtraCredit) -> bool: + """Based on our current extra credit settings, should we include this test program? + + Args: + source_prog: Absolute path to a C test program + extra_credit_flags: extra credit features to test (specified on the command line) + + Returns: + true if we should _exclude_ this program from test run, false if we should include it. + """ + + if "extra_credit" not in source_prog.parts: + # this isn't an extra-credit test so we shouldn't exclude it + return False + + # convert list of strings representing required extra credit features for this program + # to list of ExtraCredit flags + key = str(source_prog.relative_to(ROOT_DIR)) + + features_required = ( + ExtraCredit[str.upper(feature)] for feature in EXTRA_CREDIT_PROGRAMS[key] + ) + + # exclude this test if it requires any extra credit features that + # aren't included in this test run + return any(f not in extra_credit_flags for f in features_required) + + +def make_invalid_test(program: Path) -> Callable[[TestChapter], None]: + """Generate a test method for an invalid source program""" + + def test_invalid(self: TestChapter) -> None: + self.compile_failure(program) + + return test_invalid + + +def make_test_valid(program: Path) -> Callable[[TestChapter], None]: + """Generate one test method to compile a valid program. + + Only used when testing intermediate stages. Use make_test_run when testing + the whole compiler""" + + def test_valid(self: TestChapter) -> None: + self.compile_success(program) + + return test_valid + + +def make_test_run(program: Path) -> Callable[[TestChapter], None]: + """Generate one test method to compile and run a valid single-file program""" + + def test_run(self: TestChapter) -> None: + self.compile_and_run(program) + + return test_run + + +def make_test_client(program: Path) -> Callable[[TestChapter], None]: + """Generate one test method for client in multi-file program""" + + def test_client(self: TestChapter) -> None: + self.compile_client_and_run(program) + + return test_client + + +def make_test_lib(program: Path) -> Callable[[TestChapter], None]: + """Generate one test method for library in multi-file program""" + + def test_lib(self: TestChapter) -> None: + self.compile_lib_and_run(program) + + return test_lib + + +def make_invalid_tests( + test_dir: Path, stage: str, extra_credit_flags: ExtraCredit +) -> list[tuple[str, Callable[[TestChapter], None]]]: + """Generate one test method for each invalid test program in test_dir. + + We use extra_credit_flags and stage to discover invalid test cases within test_dir. + + Args: + test_dir: Absolute path to the test directory for a specific chapter + (e.g. /path/to/write-a-c-compiler-tests/chapter1/) + stage: only compile programs through this stage. this dictates which programs + are considered invalid (e.g. if stage is "parse" programs with type errors + are valid, because we stop before typechecking) + extra_credit_flags: extra credit features to test (specified on the command line) + + Returns: + A list of (name, test method) tuples, intended to be included on a dynamically generated + subclass of TestChapter + """ + tests: list[tuple[str, Callable[[TestChapter], None]]] = [] + for invalid_subdir in DIRECTORIES_BY_STAGE[stage]["invalid"]: + invalid_test_dir = test_dir / invalid_subdir + for program in invalid_test_dir.rglob("*.c"): + + if excluded_extra_credit(program, extra_credit_flags): + continue + + # derive name of test method from name of source file + key = program.relative_to(test_dir).with_suffix("") + # TODO maybe don't have / in function names, it's weird! + # maybe use source filename as ID? + test_name = f"test_{key}" + + test_method = make_invalid_test(program) + tests.append((test_name, test_method)) + + return tests + + +def make_valid_tests( + test_dir: Path, stage: str, extra_credit_flags: ExtraCredit +) -> list[tuple[str, Callable[[TestChapter], None]]]: + """Generate one test method for each valid test program in test_dir. + + We use stage and extra_credit_flags to discover valid test cases in test_dir. We also + use stage to determine what sort of test to run (e.g. if stage is "run" we actually run the + executable we compile; otherwise we just check that compilation succeeded). + + Args: + test_dir: Absolute path to the test directory for a specific chapter + (e.g. /path/to/write-a-c-compiler-tests/chapter1/) + stage: only compile programs through this stage. this dictates which programs + are considered valid (e.g. if stage is "parse" programs with type errors + are valid, because we stop before typechecking) + extra_credit_flags: extra credit features to test (specified on the command line) + + Returns: + A list of (name, test method) tuples, intended to be included on a dynamically generated + subclass of TestChapter + """ + tests: list[tuple[str, Callable[[TestChapter], None]]] = [] + for valid_subdir in DIRECTORIES_BY_STAGE[stage]["valid"]: + valid_testdir = test_dir / valid_subdir + for program in valid_testdir.rglob("*.c"): + + if excluded_extra_credit(program, extra_credit_flags): + # this requires extra credit features that aren't enabled + continue + + # derive name of test method from name of source file + key = program.relative_to(test_dir).with_suffix("") + test_name = f"test_{key}" + + test_method: Callable[[TestChapter], None] + # test depends on the stage and whether this is a library test + if stage == "run": + # all library/multi-file tests are in "library" subdirectories + if "libraries" not in key.parts: + test_method = make_test_run(program) + # if it's a library test, figure out whether this is lib or client + elif program.stem.endswith("client"): + test_method = make_test_client(program) + else: + test_method = make_test_lib(program) + else: + # for stages besides "run", just test that compilation succeeds + test_method = make_test_valid(program) + tests.append((test_name, test_method)) + return tests + + +def build_test_class( + compiler: Path, + chapter: int, + *, + options: Sequence[str], + stage: str, + extra_credit_flags: ExtraCredit, + skip_invalid: bool, +) -> Type[unittest.TestCase]: + """Construct the test class for a normal (non-optimization) chapter. + + Construct a subclass of TestChapter, generating a test method for each + program in this chapter's test suite (possibly including some extra credit programs, + depending on the extra_credit argument). + + Args: + compiler: absolute path to compiler under test + chapter: the chapter we're testing + options: extra command-line options to pass through to compiler + stage: only compile programs up through this stage + extra_credit_flags: extra credit features to test, represented as a bit vector + skip_invalid: true if we should skip invalid test programs + """ + + # base directory with all of this chapter's test programs + test_dir = ROOT_DIR.joinpath(f"chapter{chapter}").resolve() + + testclass_name = f"TestChapter{chapter}" + + # dictionary of class attributes (including properties and methods) + testclass_attrs = { + "test_dir": test_dir, + "cc": compiler, + "options": options, + "exit_stage": None if stage == "run" else stage, + } + + # generate tests for invalid test programs and add them to testclass_attrs + if not skip_invalid: + invalid_tests = make_invalid_tests(test_dir, stage, extra_credit_flags) + # test_name is the method name + for (test_name, test_cls) in invalid_tests: + testclass_attrs[test_name] = test_cls + + # generate tests for valid test programs + valid_tests = make_valid_tests(test_dir, stage, extra_credit_flags) + for (test_name, test_cls) in valid_tests: + # test_name is the method name + testclass_attrs[test_name] = test_cls + + return type(testclass_name, (TestChapter,), testclass_attrs) diff --git a/tests/parser/__init__.py b/tests/parser/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/parser/asm.py b/tests/parser/asm.py new file mode 100644 index 00000000..5443969f --- /dev/null +++ b/tests/parser/asm.py @@ -0,0 +1,183 @@ +"""Representation of assembly programs""" + +from __future__ import annotations + +from dataclasses import dataclass +from enum import Enum, auto +from typing import List, Optional, Union + + +# Operands ######################## +class Immediate(int): + """Immediate operands like $3""" + + def __str__(self) -> str: + return f"${super().__str__()}" + + +class Register(Enum): + AX = auto() + BX = auto() + CX = auto() + DX = auto() + DI = auto() + SI = auto() + R8 = auto() + R9 = auto() + R10 = auto() + R11 = auto() + R12 = auto() + R13 = auto() + R14 = auto() + R15 = auto() + BP = auto() + SP = auto() + IP = auto() + XMM0 = auto() + XMM1 = auto() + XMM2 = auto() + XMM3 = auto() + XMM4 = auto() + XMM5 = auto() + XMM6 = auto() + XMM7 = auto() + XMM8 = auto() + XMM9 = auto() + XMM10 = auto() + XMM11 = auto() + XMM12 = auto() + XMM13 = auto() + XMM14 = auto() + XMM15 = auto() + + def __str__(self) -> str: + return f"%{self.name}" + + +class Operator(Enum): + """+,-, and @ operators, which can appear in memory displacement expressions like: + -4(%rbp) + foo+10(%rbp) + bar@GOTPCREL(%rip) + """ + + PLUS = auto() + MINUS = auto() + AT = auto() + + def __str__(self) -> str: + if self == Operator.PLUS: + return "+" + if self == Operator.MINUS: + return "-" + raise NotImplementedError("what operator is this???") + + +# Expression representing an offset from some register +# all we do with these is compare them so we don't need a more structured representation here +# use List here for backwards compatibility with Python 3.8 +Expr = List[Union[int, str, Operator]] + + +@dataclass +class Memory: + """Memory operands (including RIP-relative, stack, indexed)""" + + disp: Optional[Expr] = None + base: Optional[Register] = None + idx: Optional[Register] = None + scale: int = 1 # defaults to 1 if not specified + + def __str__(self) -> str: + disp_str = "".join(map(str, self.disp or [])) + if (not self.idx) and self.scale == 1: + return f"{disp_str}({self.base or ''})" + return f"{disp_str}({self.base or ''}, {self.idx or ''}, {self.scale or ''})" + + +# type alias for target of jump or call instruction +Target = str + +# an operand is a memory address, register, immediate value, or target +Operand = Union[Memory, Register, Immediate, Target] + +# Instructions ######################## + + +class Opcode(Enum): + """All instructions we recognize + + Simplified, e.g. we don't distinguish between different conditional jumps + TODO more support for other instrutions like cmov, + consider further simplification, like using the same opcode for all unary computations + (not, shr, neg, etc)""" + + # data movement/memory manipulation + MOV = auto() + PUSH = auto() + POP = auto() + LEA = auto() + # conversions + MOVS = auto() + MOVZ = auto() + CVTTSD2SI = auto() + CVTSI2SD = auto() + # binary + ADD = auto() + SUB = auto() + IDIV = auto() + DIV = auto() + IMUL = auto() + AND = auto() + OR = auto() + XOR = auto() + # unary + SHR = auto() + NOT = auto() + NEG = auto() + CDQ = auto() + CDQE = auto() + # control flow and conditionals + JMP = auto() + JMPCC = auto() + SETCC = auto() + CMP = auto() + CALL = auto() + RET = auto() + LEAVE = auto() + + def __str__(self) -> str: + return self.name.lower() + + +@dataclass +class Instruction: + """An assembly instruction consists of an opcode and a list of operands""" + + opcode: Opcode + operands: list[Operand] + + def __str__(self) -> str: + str_operands = ", ".join(map(str, self.operands)) + return f"\t{self.opcode} {str_operands}" + + +class Label(str): + """A label within an assembly function""" + + def __str__(self) -> str: + return super().__str__() + ":" + + +AsmItem = Union[Label, Instruction] + + +@dataclass +class AssemblyFunction: + """An assembly function consists of a name and a list of instructions and internal labels""" + + name: Label + instructions: list[AsmItem] + + def __str__(self) -> str: + return f"{self.name}\n" + "\n".join(map(str, self.instructions)) diff --git a/tests/parser/parse.py b/tests/parser/parse.py new file mode 100644 index 00000000..a311ccee --- /dev/null +++ b/tests/parser/parse.py @@ -0,0 +1,602 @@ +# could we abuse python.tokenize here? +"""Parser for assembly programs. + +Limitations: +1. This is only used to parse programs that we've already assembled and linked successfully, +so it's not intended to handle invalid programs gracefully. + +2. This is only guaranteed to handle the subset of assembly we use in the book. + I've included some support for other common assembly instructions but you shouldn't rely on it. +""" + +from __future__ import annotations + +import re +import sys +from pathlib import Path +from typing import Generator, List, Optional, Union + +from . import asm, tokenize +from .asm import Expr, Immediate, Opcode, Operand, Operator, Register +from .tokenize import Token, TokType + + +class ParseError(RuntimeError): + """We encountered nvalid assembly (or, more likely, valid assembly that don't support)""" + + +# regex to identify function names (and global variables, though we don't care about those) +# as opposed to internal labels +C_IDENT_PATTERN = r"[_A-Za-z][_A-Za-z0-9]*" +C_IDENTIFIER = re.compile(C_IDENT_PATTERN) +# On macOS, identifiers from the original program must start with underscores +MANGLED_C_IDENTIFIER = re.compile(r"_" + C_IDENT_PATTERN) + + +def is_valid_c_identifier(lbl: str) -> bool: + """Could this symbol name be a function or variable name from the original source program?""" + regex = C_IDENTIFIER + if sys.platform == "darwin": + regex = MANGLED_C_IDENTIFIER + + return re.fullmatch(regex, lbl) is not None + + +def expect_next(*, toks: List[Token], expected: TokType) -> None: + """Consume next token and fail if it isn't what we expect""" + next_tok = toks.pop(0) + if next_tok.tok_type != expected: + raise ParseError( + f"Expected {expected} but found {next_tok}. Remaining tokens: {toks}" + ) + + +def parse_opcode(tok: str) -> tuple[Opcode, Optional[int]]: + """Parse an instruction mnemonic; return opcode and inferred size + Inferred size is used to normalize immediate values later on; + it's None if we can't infer the size or if this is a floating-point instruction + """ + if not tok.isalnum(): + raise ParseError(f"Bad mnemonic: {tok}") + + # deal w/ special cases + # Sign-extension from RAX to RDX is cqo in Intel syntax, cdq in AT&T syntax + # but assemblers accept Intel mnemonics even when using AT&T syntax + # (and we use the intenl mnemonics in the book) + if tok in ["cqo", "cqto"]: + return Opcode.CDQ, 8 + + # Sign-extend EAX to EDX: cdq is Intel menmonic, cltd is AT&T mnemonic + if tok in ["cdq", "cltd"]: + return Opcode.CDQ, 4 + + # sign-extend EAX to RAX: clt/cltq is AT&T syntax, cdqe is Intel syntax + if tok in ["clt", "cltq", "cdqe"]: + return Opcode.CDQE, 4 + + # overlapping prefixes + if tok.startswith("movsd"): + return Opcode.MOV, None + + if tok.startswith("movs"): + size = None + if tok[-2] == "b": + size = 1 + elif tok[-2] == "l": + size = 4 + return Opcode.MOVS, size + + if tok.startswith("movz"): + size = None + if tok[-2] == "b": + size = 1 + elif tok[-2] == "l": + size = 4 + return Opcode.MOVZ, size + + # comisd is floating-point cmp + if tok.startswith("comi"): + return Opcode.CMP, None + + # for our purposes, okay to treat mul and imul as equivalent + if tok.startswith("mul"): + return Opcode.IMUL, None + + # conditional instructions; don't distinguish between different conditions + if tok.startswith("set"): + return Opcode.SETCC, 1 + + CONDITION_CODES = ["e", "ne", "g", "ge", "l", "le", "b", "be", "a", "ae", "po"] + if tok[0] == "j" and tok[1:] in CONDITION_CODES: + return Opcode.JMPCC, None + + # otherwise just look it up by string representation of opcode + for opcode in Opcode: + op = str(opcode) + if tok.startswith(op): + suffix = tok[len(op) :] + size = None + if suffix == "b": + size = 1 + elif suffix == "l": + size = 4 + elif suffix == "q": + size = 8 + + if opcode in [Opcode.POP, Opcode.PUSH, Opcode.LEA]: + size = 8 + return opcode, size + + raise ParseError(f"Unknown opcode {tok}") + + +# parsing register names + +REG_ALIASES = { + "rax": (Register.AX, 8), + "eax": (Register.AX, 4), + "al": (Register.AX, 1), + "rbx": (Register.BX, 8), + "ebx": (Register.BX, 4), + "bl": (Register.BX, 1), + "rcx": (Register.CX, 8), + "ecx": (Register.CX, 4), + "cl": (Register.CX, 1), + "rdx": (Register.DX, 8), + "edx": (Register.DX, 4), + "dl": (Register.DX, 1), + "rdi": (Register.DI, 8), + "edi": (Register.DI, 4), + "dil": (Register.DI, 1), + "rsi": (Register.SI, 8), + "esi": (Register.SI, 4), + "sil": (Register.SI, 1), + "r8": (Register.R8, 8), + "r8d": (Register.R8, 4), + "r8b": (Register.R8, 1), + "r9": (Register.R9, 8), + "r9d": (Register.R9, 4), + "r9b": (Register.R9, 1), + "r10": (Register.R10, 8), + "r10d": (Register.R10, 4), + "r10b": (Register.R10, 1), + "r11": (Register.R11, 8), + "r11d": (Register.R11, 4), + "r11b": (Register.R11, 1), + "r12": (Register.R12, 8), + "r12d": (Register.R12, 4), + "r12b": (Register.R12, 1), + "r13": (Register.R13, 8), + "r13d": (Register.R13, 4), + "r13b": (Register.R13, 1), + "r14": (Register.R14, 8), + "r14d": (Register.R14, 4), + "r14b": (Register.R14, 1), + "r15": (Register.R15, 8), + "r15d": (Register.R15, 4), + "r15b": (Register.R15, 1), + "rsp": (Register.SP, 8), + "rbp": (Register.BP, 8), + "rip": (Register.IP, None), + "xmm0": (Register.XMM0, None), + "xmm1": (Register.XMM1, None), + "xmm2": (Register.XMM2, None), + "xmm3": (Register.XMM3, None), + "xmm4": (Register.XMM4, None), + "xmm5": (Register.XMM5, None), + "xmm6": (Register.XMM6, None), + "xmm7": (Register.XMM7, None), + "xmm8": (Register.XMM8, None), + "xmm9": (Register.XMM9, None), + "xmm10": (Register.XMM10, None), + "xmm11": (Register.XMM11, None), + "xmm12": (Register.XMM12, None), + "xmm13": (Register.XMM13, None), + "xmm14": (Register.XMM14, None), + "xmm15": (Register.XMM15, None), +} + + +def parse_register(toks: list[Token]) -> tuple[Register, Optional[int]]: + """Parse register and infer its size in bytes + + ::= "%" + ::= "rax" | "eax" | etc. + """ + + expect_next(toks=toks, expected=TokType.PERCENT) + reg_name = toks.pop(0).tok_str + try: + return REG_ALIASES[reg_name] + except KeyError: + raise ParseError(f"expected register name after % but found {reg_name}") + + +def parse_immediate(toks: list[Token]) -> Immediate: + """Parse an immediate value + + NOTE this won't correctly normalize signed/unsigned representations of same value + e.g. -1 and 255 are the same in one-byte instructions but we won't parse them + to the same Immediate operand here; we normalize them later in fix_immediate + + ::= "$" [ "+" | "-" ] + ::= ? decimal or hexadecimal integer ? + """ + expect_next(toks=toks, expected=TokType.DOLLAR) + + next_tok = toks.pop(0) + tok_type = next_tok.tok_type + + if tok_type == TokType.INT: + val = int(next_tok.tok_str, base=0) + return Immediate(val) + elif tok_type in [TokType.PLUS_SIGN, TokType.MINUS_SIGN]: + # next tok should val + num_tok = toks.pop(0) + if num_tok.tok_type != TokType.INT: + raise ParseError(f"bad immediate value: ${next_tok}{num_tok.tok_str}") + val = int(num_tok.tok_str, base=0) + if tok_type == TokType.MINUS_SIGN: + return Immediate(-val) + return Immediate(val) + else: + raise ParseError(f"Bad immediate value: ${next_tok}") + + +def parse_expr(toks: list[Token]) -> Expr: + """Parse an expression (used as displacement in memory operand) + NOTE: we don't normalize these, so +10(%rbp) and 10(%rbp) will NOT compare equal + + ::= { | | "+" | "-" }+ + """ + expr: Expr = [] + while True: + next_tok: Token = toks.pop(0) + tok_typ = next_tok.tok_type + if tok_typ == TokType.SYMBOL: + expr.append(next_tok.tok_str) + elif tok_typ == TokType.INT: + expr.append(int(next_tok.tok_str, base=0)) + elif tok_typ == TokType.PLUS_SIGN: + expr.append(Operator.PLUS) + elif tok_typ == TokType.MINUS_SIGN: + expr.append(Operator.MINUS) + elif tok_typ == TokType.AT: + expr.append(Operator.AT) + else: + # we didn't consume this so put it back on the list + toks.insert(0, next_tok) + break # we're done + return expr + + +def parse_memory_operand(toks: List[Token]) -> tuple[Operand, Optional[int]]: + """ + Parse memory operand + + ::= [ ] "(" ")" + ::= [ "," ] // base, with or without other stuff + | "," // no base + + ::= | [ "," [ ]] + """ + + disp: Optional[Expr] = None + base: Optional[Register] = None + idx: Optional[Register] = None + scale = 1 + + # first get displacement if there is one + if toks[0].tok_type != TokType.OPEN_PAREN: + # next_tok is part of displacement + disp = parse_expr(toks) + expect_next(toks=toks, expected=TokType.OPEN_PAREN) + + # optional base + if toks[0].tok_type == TokType.PERCENT: + base, _ = parse_register(toks) + + # base register must be followed by close paren or comma + next_tok = toks.pop(0) + if next_tok.tok_type == TokType.CLOSE_PAREN: + # we're done, no index or scale + return asm.Memory(disp=disp, base=base), None + # otherwise next token must be comma + if next_tok.tok_type != TokType.COMMA: + raise ParseError( + "Unexpected token after base register in memory operand: " + str(toks) + ) + + # now parse index and scale + next_tok_type = toks[0].tok_type + if next_tok_type == TokType.INT: + # it's a scale + scale = int(toks.pop(0).tok_str, base=0) + else: + # it's an index register, possibly followed by scale + idx, _ = parse_register(toks) + + # if there's a comma, consume it and check for scale + if toks[0].tok_type == TokType.COMMA: + toks.pop(0) + if toks[0].tok_type == TokType.INT: + scale = int(toks.pop(0).tok_str, base=0) + + expect_next(toks=toks, expected=TokType.CLOSE_PAREN) + + return asm.Memory(disp, base, idx, scale), None + + +def fix_immediate(op: Operand, size: Optional[int]) -> Operand: + """Normalize immediate values to signed representation""" + if isinstance(op, Immediate): + if size is None: + raise ParseError( + "Can't interpret immediate b/c instruction size is ambigous" + ) + if op < 0: + return op + + as_bytes = op.to_bytes(length=size, byteorder="little", signed=False) + from_bytes = int.from_bytes(as_bytes, byteorder="little", signed=True) + return Immediate(from_bytes) + + # not an immediate so we don't need to change it + return op + + +def parse_operand(toks: List[Token]) -> tuple[Operand, Optional[int]]: + """Parse the next operand in list of tokens + ::= | | ["@" ] + """ + start_tok_type = toks[0].tok_type + + if start_tok_type == TokType.PERCENT: + return parse_register(toks) + if start_tok_type == TokType.DOLLAR: + return parse_immediate(toks), None + if len(toks) == 1 and start_tok_type == TokType.SYMBOL: + # it's a jump target or function name + target = toks.pop(0).tok_str + return (target, None) + if ( + len(toks) == 3 + and start_tok_type == TokType.SYMBOL + and toks[1].tok_type == TokType.AT + and toks[2].tok_type == TokType.SYMBOL + ): + # it's a function name with a relocation, e.g. foo@PLT + target = f"{toks[0].tok_str}@{toks[2].tok_str}" + # consume all tokens from list + toks.clear() + return (target, None) + + # it must be a memory operand + return parse_memory_operand(toks) + + +# deal with directives +# we just care about whether these move us in or out of the text section + + +class Directive: + """Any directive""" + + +class EnterTextSection(Directive): + """Directive that makes text section the current section""" + + +class LeaveTextSection(Directive): + """Directive that makes any section other than text section the current section""" + + +# standalone section directives recognized by GNU or LLVM assembler (or both) + +NON_TEXT_SECTIONS = [ + ".bss", + ".data", + ".cstring", + ".rodata", + ".literal4" # we don't use this but you would if you implemented 'float' + ".literal8", + ".literal16", + ".cstring", +] + + +def parse_directive(tok_list: List[Token]) -> Directive: + """Parse a directive and figure out whether it enters the text section, exits it, or neither + + NOTE: unlike earlier parse_* statements, we don't need to consume these tokens. + tok_list represents a single line of assembly and once we've identified the kind of directive + we can just discard the rest of the line + + ::= | | + ::= ".text" + | ".section" "__TEXT" "," "__text" + | ".section" ".text" + ::= ".section" | ".bss" | ".data" | etc. + ::= { }+ + ::= ? anything other than .text or __TEXT,__text ? + ::= ? any symbol starting with "." other than ".section", ".text", ".bss", etc ? + """ + if tok_list[0].tok_str == ".text": + return EnterTextSection() + if tok_list[0].tok_str in NON_TEXT_SECTIONS: + return LeaveTextSection() + + # we don't support the GNU assembler stack manipulation pseudo-ops + if tok_list[0].tok_str in [".popsection", ".pushsection", ".previous"]: + raise ParseError(f"{tok_list[0].tok_str} not supported") + + if tok_list[0].tok_str == ".section": + if tok_list[1].tok_type != TokType.SYMBOL: + raise ParseError( + f"Expected section name after section directive, found {tok_list[1].tok_str}" + ) + + section_name = tok_list[1].tok_str + if section_name == ".text": + return EnterTextSection() + + # on macOS text section name is __TEXT,__text + # note that other sections in __TEXT are NOT the text section + # e.g. __TEXT,__cstring + if section_name == "__TEXT" and tok_list[3].tok_str == "__text": + return EnterTextSection() + + # otherwise this specifies some non-text section + return LeaveTextSection() + + # as far as we can tell, it's not a section directive + return Directive() + + +def parse_statement( + tokens: Generator[Token, None, None] +) -> Union[asm.AsmItem, Directive]: + """Parse the next instruction, label or directive + + Grammar: + ::=