Skip to content

Commit 90de9d9

Browse files
committed
Fix several issues related to type punning parameters in inline subs
1 parent 809c51f commit 90de9d9

2 files changed

Lines changed: 43 additions & 14 deletions

File tree

thecl/ecsparse.y

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ static bool var_accessible(parser_state_t* state, thecl_variable_t* var);
147147
/* Returns variable of the given name in the specified sub, or NULL if the variable doesn't exist/is out of scope */
148148
static thecl_variable_t* var_get(parser_state_t* state, thecl_sub_t* sub, const char* name);
149149
/* Returns the stack offset of a specified variable in the specified sub. */
150-
static int var_stack(parser_state_t* state, thecl_sub_t* sub, const char* name);
150+
static int var_stack(parser_state_t* state, thecl_sub_t* sub, const char* name, int use_type);
151151
/* Returns the type of a specified variable in the specified sub. */
152152
static int var_type(parser_state_t* state, thecl_sub_t* sub, const char* name);
153153
/* Returns 1 if a variable of a given name exists, and 0 if it doesn't. */
@@ -1148,7 +1148,12 @@ Assignment:
11481148
} else {
11491149
if ($1->value.val.f >= 0.0f) var = state->current_sub->vars[(int)$1->value.val.f / 4];
11501150
}
1151-
if (var != NULL) var->is_written = true;
1151+
if (var != NULL) {
1152+
var->is_written = true;
1153+
if ($1->value.type != var->type) {
1154+
var->is_punned = true;
1155+
}
1156+
}
11521157
}
11531158
| Address "+=" ExpressionAny { var_shorthand_assign(state, $1, $3, ADDI, ADDF); }
11541159
| Address "-=" ExpressionAny { var_shorthand_assign(state, $1, $3, SUBTRACTI, SUBTRACTF); }
@@ -1360,13 +1365,13 @@ Address:
13601365
| '$' IDENTIFIER {
13611366
$$ = param_new('S');
13621367
$$->stack = 1;
1363-
$$->value.val.S = var_stack(state, state->current_sub, $2);
1368+
$$->value.val.S = var_stack(state, state->current_sub, $2, 'S');
13641369
free($2);
13651370
}
13661371
| '%' IDENTIFIER {
13671372
$$ = param_new('f');
13681373
$$->stack = 1;
1369-
$$->value.val.f = var_stack(state, state->current_sub, $2);
1374+
$$->value.val.f = var_stack(state, state->current_sub, $2, 'f');
13701375
free($2);
13711376
}
13721377
| IDENTIFIER {
@@ -1379,9 +1384,9 @@ Address:
13791384
$$ = param_new(type);
13801385
$$->stack = 1;
13811386
if (type == 'S') {
1382-
$$->value.val.S = var_stack(state, state->current_sub, $1);
1387+
$$->value.val.S = var_stack(state, state->current_sub, $1, 'S');
13831388
} else {
1384-
$$->value.val.f = var_stack(state, state->current_sub, $1);
1389+
$$->value.val.f = var_stack(state, state->current_sub, $1, 'f');
13851390
}
13861391
} else {
13871392
global_definition_t *def = global_get(state, $1);
@@ -1761,7 +1766,7 @@ static void instr_create_inline_call(
17611766
param_free(param);
17621767
return;
17631768
}
1764-
if (sub->format[i] != param->type) {
1769+
if (sub->format[i] != '?' && sub->format[i] != param->type) {
17651770
yyerror(state, "wrong parameter %i when calling inline sub \"%s\", expected type: %c\n", i + 1, sub->name, sub->format[i]);
17661771
list_for_each(params, param)
17671772
param_free(param);
@@ -1793,9 +1798,9 @@ static void instr_create_inline_call(
17931798

17941799
list_for_each(params, param) { /* It has alredy been verified that param amount is correct. */
17951800
var = sub->vars[i];
1796-
if (var->is_written || param->is_expression_param || param_is_system_var(state, param)) {
1801+
if (var->is_written || var->is_punned || param->is_expression_param || param_is_system_var(state, param)) {
17971802

1798-
if (param->is_expression_param && !var->is_written) {
1803+
if (param->is_expression_param && !var->is_written && !var->is_punned) {
17991804
/* Check if the passed expression can be simplified to a literal value. */
18001805
list_node_t* node = state->expressions.tail;
18011806
expression_t* expr = (expression_t*)node->data;
@@ -1933,17 +1938,29 @@ static void instr_create_inline_call(
19331938
} else if (param->value.type == 'S') {
19341939
if (param->value.val.S < sub->arity*4 && param->value.val.S >= 0) {
19351940
/* Parameter. */
1936-
param_node->data = param_copy(param_replace[param->value.val.S / 4]);
1941+
thecl_param_t* replacement = param_copy(param_replace[param->value.val.S / 4]);
1942+
if (replacement->type == 'f') {
1943+
replacement->value.type = 'S';
1944+
replacement->value.val.S = (int)replacement->value.val.f;
1945+
}
1946+
param_node->data = replacement;
19371947
param_free(param);
19381948
} else if (param->value.val.S > 0) {
19391949
/* Regular stack variable, needs adjusting the offset. */
19401950
param->value.val.S = stack_replace[param->value.val.S / 4 - sub->arity]->stack;
19411951
}
19421952
} else if (param->value.type == 'f') {
19431953
if (param->value.val.f < (float)(sub->arity*4) && param->value.val.f >= 0.0f) {
1944-
param_node->data = param_copy(param_replace[(int)param->value.val.f / 4]);
1954+
/* Parameter. */
1955+
thecl_param_t* replacement = param_copy(param_replace[(int)param->value.val.f / 4]);
1956+
if (replacement->type == 'S') {
1957+
replacement->value.type = 'f';
1958+
replacement->value.val.f = (float)replacement->value.val.S;
1959+
}
1960+
param_node->data = replacement;
19451961
param_free(param);
19461962
} else if (param->value.val.f > 0.0f) {
1963+
/* Regular stack variable, needs adjusting the offset. */
19471964
param->value.val.f = (float)stack_replace[(int)param->value.val.f / 4 - sub->arity]->stack;
19481965
}
19491966
}
@@ -2978,6 +2995,7 @@ var_create(
29782995
var->stack = var_get_new_stack(state, sub);
29792996
var->is_written = false;
29802997
var->is_unused = false;
2998+
var->is_punned = false;
29812999
var->scope = state->scope_stack[state->scope_cnt - 1];
29823000

29833001
++sub->var_count;
@@ -3055,14 +3073,19 @@ static int
30553073
var_stack(
30563074
parser_state_t* state,
30573075
thecl_sub_t* sub,
3058-
const char* name)
3076+
const char* name,
3077+
int use_type)
30593078
{
30603079
seqmap_entry_t* ent = seqmap_find(g_eclmap->gvar_names, name);
30613080
if (ent) return ent->key;
30623081

30633082
thecl_variable_t* var = var_get(state, sub, name);
3064-
if (var != NULL)
3083+
if (var != NULL) {
3084+
if (var->type != use_type) {
3085+
var->is_punned = true;
3086+
}
30653087
return var->stack;
3088+
}
30663089

30673090
yyerror(state, "variable not found: %s", name);
30683091
return 0;
@@ -3133,7 +3156,12 @@ var_shorthand_assign(
31333156
} else {
31343157
if (param->value.val.f >= 0.0f) var = state->current_sub->vars[(int)param->value.val.f / 4];
31353158
}
3136-
if (var != NULL) var->is_written = true;
3159+
if (var != NULL) {
3160+
var->is_written = true;
3161+
if (param->value.type != var->type) {
3162+
var->is_punned = true;
3163+
}
3164+
}
31373165
}
31383166

31393167
static void

thecl/thecl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ typedef struct {
191191
int scope;
192192
bool is_written;
193193
bool is_unused;
194+
bool is_punned;
194195
} thecl_variable_t;
195196

196197
void thecl_variable_free(

0 commit comments

Comments
 (0)