Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/reg-alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,19 @@ int prepare_operand(basic_block_t *bb, var_t *var, int operand_0)
return i;
}

/* The reload below reads the variable's slot, so there has to be one
* holding its value. A parameter arrives in a register and is given a
* slot only when something spills it: reloading before that read whatever
* the frame happened to hold, and "int x = a - b; int *p = &b;" computed
* a - garbage. Writing the register back first is what makes the slot
* stand for the variable.
*/
if (i > -1 && var->address_taken && !var->space_is_allocated) {
store_var(bb, var, i);
vreg_map_to_phys(var, i);
return i;
}

for (i = 0; i < REG_CNT; i++) {
if (reg_is_free(i)) {
load_var(bb, var, i);
Expand Down
1 change: 1 addition & 0 deletions tests/driver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ begin_category "Standalone Programs" "Testing checked-in end-to-end programs"
try_file 0 'F(10) = 55' "$TESTS_DIR/fib.c"
try_file 0 $'1\nHello World' "$TESTS_DIR/hello.c"
try_file 0 '' "$TESTS_DIR/strength-reduce.c"
try_file 0 '' "$TESTS_DIR/escaped-param.c"

# Category: Basic Literals and Constants
begin_category "Literals and Constants" "Testing integer, character, and string literals"
Expand Down
42 changes: 42 additions & 0 deletions tests/escaped-param.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* prepare_operand() reloads an address-taken variable from its stack slot
* rather than reading the register it is already in, because a store through
* the pointer would not have gone to the register. That reload needs the slot
* to hold the value, and a parameter arrives in a register with no slot at
* all: one is reserved the first time something spills it.
*
* Taking the address after the expression is what orders the two so the
* reload comes first. Nothing has to be stored through the pointer -- the
* value is already wrong by the time the address is taken.
*/

int sub_then_escape(int a, int b)
{
int x = a - b;
int *p = &b;
return x;
}

int add_then_escape(int a, int b)
{
int x = a + b;
int *p = &b;
return x;
}

int escape_first_operand(int a, int b)
{
int x = a - b;
int *p = &a;
return x;
}

int main()
{
if (sub_then_escape(5, 2) != 3)
return 1;
if (add_then_escape(1, 2) != 3)
return 2;
if (escape_first_operand(5, 2) != 3)
return 3;
return 0;
}
Loading