-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
73 changed files
with
1,307 additions
and
576 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
To validate that copies were propagated in a test program, the test script inspects the assembly for the `target` function. | ||
|
||
In some test programs, the copy propagation and constant folding passes make it possible to evaluate the return value at compile time. The test script expects these programs to include a `mov` instruction that copies the expected constant into EAX, followed by the function epilogue. | ||
|
||
In some programs, copy propagation should replace the arguments to certain function calls with constants. In other programs, copy propagation should propagate the same value two different function arguments. The test script validates these programs by checking which values are copied into the parameter-passing registers before the `call` instruction. | ||
|
||
Register coalescing, which we implement in Chapter 20, can make it appear that the same value is passed in two different parameter-passing reigsters, even if copy propagation wasn't performed. The tests are designed to prevent register coalescing in those cases, so they'll still test the intended cases after you complete Chapter 20. | ||
|
||
In one program (`redundant_copies.c`), removing a redundant copy makes a whole branch dead, allowing unreachable code elimination to remove that branch. The test script validates that this program contains no control-flow instructions. | ||
|
||
In `pointer_arithmetic.c`, the test script validates that we optimize away all computation instructions (e.g. arithmetic instructions like `imul` and type conversions like `movsx`). | ||
|
||
The programs in the `dont_propagate` directories cover cases where copies should _not_ be propagated. The test script doesn't inspect the assembly for these; it just validates that they behave correctly. | ||
|
||
To see what validation we perform for each test case, see `test_framework/tacky/copy_prop.py`. |
49 changes: 37 additions & 12 deletions
49
tests/chapter_19/copy_propagation/all_types/alias_analysis.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,41 @@ | ||
void callee(int *ptr) { *ptr = -1; } | ||
/* Test that alias analysis allows us to propagate some copies | ||
* from variables whose address has been taken. */ | ||
int callee(int *ptr) { | ||
if (*ptr != 10) { | ||
return 0; // failure | ||
} | ||
*ptr = -1; | ||
return 1; | ||
} | ||
|
||
int target(int *ptr1, int *ptr2) { | ||
int i = 10; // generate i = 10 | ||
int j = 20; // generate j = 20 | ||
*ptr1 = callee(&i); // record i as a variable whose address is taken | ||
// function call kills i = 10 | ||
*ptr2 = i; | ||
|
||
int target(void) { | ||
int i = 10; | ||
int j = 20; | ||
callee(&i); | ||
i = 4; | ||
i = 4; // gen 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; | ||
// This should be rewritten as 'return 24'. | ||
// We can propagate i b/c there are no stores | ||
// or function calls after i = 4. | ||
// We can propagate j b/c it's not aliased. | ||
return i + j; | ||
} | ||
|
||
int main(void) { return target(); } | ||
int main(void) { | ||
int callee_check1; | ||
int callee_check2; | ||
int result = target(&callee_check1, &callee_check2); | ||
if (callee_check1 != 1) { | ||
return 1; | ||
} | ||
if (callee_check2 != -1) { | ||
return 2; | ||
} | ||
if (result != 24) { | ||
return 3; | ||
} | ||
return 0; | ||
} |
7 changes: 0 additions & 7 deletions
7
tests/chapter_19/copy_propagation/all_types/char_round_trip.c
This file was deleted.
Oops, something went wrong.
8 changes: 0 additions & 8 deletions
8
tests/chapter_19/copy_propagation/all_types/char_round_trip_2.c
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 0 additions & 3 deletions
3
tests/chapter_19/copy_propagation/all_types/const_fold_sign_extend.c
This file was deleted.
Oops, something went wrong.
3 changes: 0 additions & 3 deletions
3
tests/chapter_19/copy_propagation/all_types/const_fold_sign_extend_2.c
This file was deleted.
Oops, something went wrong.
12 changes: 0 additions & 12 deletions
12
tests/chapter_19/copy_propagation/all_types/const_fold_type_conversions.c
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,25 @@ | ||
/* Test that we can propagate copies of aggregate values */ | ||
struct s { | ||
int x; | ||
int y; | ||
int x; | ||
int y; | ||
}; | ||
|
||
int callee(struct s a, struct s b) { return a.x + b.x; } | ||
int callee(struct s a, struct s b) { | ||
return a.x == 3 && a.y == 4 && b.x == 3 && b.y == 4; | ||
} | ||
|
||
int target(void) { | ||
struct s s1 = {1, 2}; | ||
struct s s2 = {3, 4}; | ||
s1 = s2; // generate s1 = s2 | ||
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); | ||
// Make sure we pass the same value for both arguments. | ||
// We don't need to worry that register coalescing | ||
// will interfere with this test, | ||
// because s1 and s2, as structures, won't be stored in registers. | ||
return callee(s1, s2); | ||
} | ||
|
||
int main(void) { return target(); } | ||
int main(void) { | ||
return target(); | ||
} |
15 changes: 8 additions & 7 deletions
15
tests/chapter_19/copy_propagation/all_types/dont_propagate/copy_to_offset.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
/* Test that CopyToOffset kills its destination */ | ||
struct s { | ||
int x; | ||
int y; | ||
int x; | ||
int y; | ||
}; | ||
|
||
int main(void) { | ||
static struct s s1 = {1, 2}; | ||
struct s s2 = {3, 4}; | ||
s1 = s2; // generate s1 = s2 | ||
s2.x = 3; // kill s1 = s2 | ||
static struct s s1 = {1, 2}; | ||
struct s s2 = {3, 4}; | ||
s1 = s2; // generate s1 = s2 | ||
s2.x = 5; // kill s1 = s2 | ||
|
||
return s1.x; | ||
return s1.x; // make sure we don't propagate s2 into this return statement | ||
} |
Oops, something went wrong.