Segfault, corruption and codegen fixes
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 13 Jul 2026 07:28:03 +0000 (08:28 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 13 Jul 2026 07:28:03 +0000 (08:28 +0100)
amd64.c
i386.c

diff --git a/amd64.c b/amd64.c
index 324df2790978119a8d132d5f2101670557e6fa16..146aa823113732629e3402757d1a8055532732dd 100644 (file)
--- a/amd64.c
+++ b/amd64.c
@@ -136,6 +136,7 @@ static const char *postfix_copy_lvalue_tag_name = 0;
 
 static int postfix_member_offset = 0;
 static int postfix_member_size = 0;
+static int postfix_value_is_array = 0;
 
 static int postfix_member_is_floating = 0;
 static int postfix_member_is_unsigned = 0;
@@ -13376,6 +13377,8 @@ static void emit_load_assignment_rhs_to_pair (const char *lo, const char *hi) {
         
         if (find_global_symbol (name) >= 0) {
         
+            postfix_value_is_array = get_global_symbol_array (name);
+            
             if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION ||
                 get_global_symbol_array (name) ||
                 (!get_global_symbol_pointer_depth (name) &&
@@ -13905,6 +13908,7 @@ static void emit_apply_postfix_member_access_to_reg_now (const char *reg) {
             postfix_member_pointed_size = elem_size;
             postfix_member_offset = offset;
             postfix_member_size = size;
+            postfix_value_is_array = is_array;
             postfix_member_is_floating = is_floating;
             postfix_member_is_unsigned = is_unsigned;
             postfix_member_calling_convention = last_found_member_calling_convention;
@@ -13920,6 +13924,8 @@ static void emit_apply_postfix_member_access_to_reg_now (const char *reg) {
                 enum token_kind assign_op;
                 int subscript_elem_size;
                 
+                postfix_value_is_array = 0;
+                
                 if (!is_array && pointer_depth > 0) {
                     emit_load_member_from_addr_reg_now (reg, reg, offset, DATA_PTR & 0x1f);
                 } else if (state->ofp && offset != 0) {
@@ -17128,6 +17134,156 @@ static int source_starts_lparen_deref_subscript_at (const char *p) {
 
 }
 
+static int source_starts_lparen_subscript_call_at (const char *p) {
+
+    int bracket_depth;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '[') {
+        return 0;
+    }
+    
+    bracket_depth = 1;
+    p++;
+    
+    while (*p && bracket_depth > 0) {
+    
+        if (*p == '[') {
+            bracket_depth++;
+        } else if (*p == ']') {
+            bracket_depth--;
+        }
+        
+        p++;
+    
+    }
+    
+    if (bracket_depth != 0) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != ')') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '(';
+
+}
+
+static int source_starts_lparen_deref_subscript_call_at (const char *p) {
+
+    int bracket_depth;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    if (*p == '(') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '[') {
+        return 0;
+    }
+    
+    bracket_depth = 1;
+    p++;
+    
+    while (*p && bracket_depth > 0) {
+    
+        if (*p == '[') {
+            bracket_depth++;
+        } else if (*p == ']') {
+            bracket_depth--;
+        }
+        
+        p++;
+    
+    }
+    
+    if (bracket_depth != 0) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != ')') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '(';
+
+}
+
 static int source_starts_lparen_deref_postfix_incdec_at (const char *p) {
 
     if (!p) {
@@ -20817,6 +20973,8 @@ static void emit_load_assignment_rhs_to_reg (const char *reg) {
         
             if (src->is_array) {
             
+                postfix_value_is_array = 1;
+                
                 if (src->is_static && src->static_label) {
                     emit_load_address_to_reg_now (reg, src->static_label);
                 } else {
@@ -20917,6 +21075,8 @@ static void emit_load_assignment_rhs_to_reg (const char *reg) {
         
         if (find_global_symbol (name) >= 0) {
         
+            postfix_value_is_array = get_global_symbol_array (name);
+            
             if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION ||
                 get_global_symbol_array (name) ||
                 (!get_global_symbol_pointer_depth (name) &&
@@ -23110,6 +23270,16 @@ static void emit_load_floating_rhs_expression_now (int result_size) {
 
 static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
 
+static int local_symbol_is_array_now (const struct local_symbol *sym) {
+
+    if (!sym) {
+        return 0;
+    }
+    
+    return sym->is_array || sym->array_dimensions > 0 || sym->array_element_size > 0;
+
+}
+
 static int current_argument_is_bare_identifier_now (void) {
 
     const char *p;
@@ -23307,14 +23477,41 @@ static int emit_push_global_aggregate_argument_now (const char *name) {
     int offset;
     int chunk;
 
-    if (!name || get_global_symbol_kind (name) != GLOBAL_SYMBOL_OBJECT ||
-        get_global_symbol_array (name) || get_global_symbol_pointer_depth (name) > 0 ||
-        get_global_symbol_floating (name)) {
+    const char *tag_name;
+
+    if (!name) {
         return 0;
     }
     
-    size = get_global_symbol_size (name);
+    if (get_global_symbol_kind (name) != GLOBAL_SYMBOL_OBJECT) {
+        return 0;
+    }
+    
+    if (get_global_symbol_array (name)) {
+        return 0;
+    }
     
+    if (get_global_symbol_pointer_depth (name) > 0) {
+        return 0;
+    }
+    
+    if (get_global_symbol_floating (name)) {
+        return 0;
+    }
+    
+    size = get_global_symbol_size (name);
+    tag_name = get_global_symbol_tag_name (name);
+
+    /*
+     * Only tagged aggregate objects are passed by value here.  Untagged
+     * objects include scalar values and arrays whose decay metadata was not
+     * visible during the self-hosting pass; those must use normal expression
+     * loading so arrays decay to one address instead of multiple stack words.
+     */
+    if (!tag_name || !tag_name[0]) {
+        return 0;
+    }
+
     if (size <= (DATA_PTR & 0x1f)) {
         return 0;
     }
@@ -23485,12 +23682,13 @@ static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result
             
             }
             
+            postfix_value_is_array = 0;
             postfix_member_seen = 0;
             postfix_member_size = 0;
             postfix_member_pointer_depth = 0;
             postfix_member_pointed_size = 0;
             
-            if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && find_local_symbol (tok.ident)->is_array) {
+            if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && local_symbol_is_array_now (find_local_symbol (tok.ident))) {
             
                 struct local_symbol *arg_sym = find_local_symbol (tok.ident);
                 
@@ -23599,12 +23797,12 @@ static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result
                 
                 if (state->ofp) {
                 
-                    if (!arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    if (!arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && !postfix_value_is_array && postfix_member_size > (DATA_PTR & 0x1f)) {
                     
                         arg_bytes = postfix_member_size;
                         emit_push_aggregate_from_addr_reg_now ("rax", arg_bytes);
                     
-                    } else if (!arg_is_floating && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    } else if (!arg_is_floating && !postfix_value_is_array && postfix_member_size > (DATA_PTR & 0x1f)) {
                     
                         arg_bytes = postfix_member_size;
                         emit_push_aggregate_from_addr_reg_now ("rax", arg_bytes);
@@ -25386,12 +25584,13 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg,
             
             }
             
+            postfix_value_is_array = 0;
             postfix_member_seen = 0;
             postfix_member_size = 0;
             postfix_member_pointer_depth = 0;
             postfix_member_pointed_size = 0;
             
-            if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && find_local_symbol (tok.ident)->is_array) {
+            if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && local_symbol_is_array_now (find_local_symbol (tok.ident))) {
             
                 struct local_symbol *arg_sym = find_local_symbol (tok.ident);
                 
@@ -25510,12 +25709,12 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg,
                          * slot according to the AMD64 calling convention.
                          */
                     
-                    } else if (!use_inline && !arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    } else if (!use_inline && !arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && !postfix_value_is_array && postfix_member_size > (DATA_PTR & 0x1f)) {
                     
                         arg_bytes = postfix_member_size;
                         emit_push_aggregate_from_addr_reg_now ("rax", arg_bytes);
                     
-                    } else if (!use_inline && !arg_is_floating && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    } else if (!use_inline && !arg_is_floating && !postfix_value_is_array && postfix_member_size > (DATA_PTR & 0x1f)) {
                     
                         arg_bytes = postfix_member_size;
                         emit_push_aggregate_from_addr_reg_now ("rax", arg_bytes);
@@ -29995,6 +30194,15 @@ static int parse_parenthesized_deref_subscript_statement (void) {
     
     }
     
+    if (tok.kind == TOK_LPAREN) {
+    
+        get_token ();
+        
+        expect (TOK_RPAREN, ")");
+        emit_call_pointer_in_reg_now ("rax", "rax");
+    
+    }
+    
     emit_load_deref_reg_now ("rax", DATA_PTR & 0x1f);
     emit_handle_subscript_after_loaded_pointer_to_reg_now ("rax", pointer_depth - 1, pointed_size, src ? src->pointed_is_unsigned : get_global_symbol_pointed_is_unsigned (name));
     
@@ -30391,6 +30599,20 @@ static int parse_identifier_assignment_statement (void) {
             emit_parse_postfix_subscript_scaled_address_to_reg_now ("rdx", elem_size);
         }
         
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (state->ofp) {
+                emit_load_deref_reg_now ("rdx", DATA_PTR & 0x1f);
+            }
+            
+            emit_call_pointer_in_reg_now ("rdx", "rax");
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
         if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
         
             op = tok.kind;
@@ -35992,18 +36214,16 @@ static int parse_parenthesized_member_function_pointer_call_statement (void) {
     
     const char *base_tag_name = 0;
     
-    if (tok.kind != TOK_LPAREN || !source_starts_with_parenthesized_indirect_call_now ()) {
+    if (tok.kind != TOK_LPAREN || (!source_starts_with_parenthesized_indirect_call_now () && !source_starts_lparen_deref_subscript_call_at (tok.start) && !source_starts_lparen_deref_subscript_call_at (tok.caret) && !source_starts_lparen_subscript_call_at (tok.start) && !source_starts_lparen_subscript_call_at (tok.caret))) {
         return 0;
     }
     
     get_token ();
     
-    if (tok.kind != TOK_STAR) {
-        return 0;
+    if (tok.kind == TOK_STAR) {
+        get_token ();
     }
     
-    get_token ();
-    
     if (tok.kind == TOK_LPAREN) {
     
         wrapped_member_expr = 1;
@@ -36138,6 +36358,10 @@ static void parse_statement (void) {
     
     }
     
+    if (parse_parenthesized_member_function_pointer_call_statement ()) {
+        return;
+    }
+    
     if (parse_parenthesized_deref_subscript_statement ()) {
     
         expect_semi_or_recover ();
@@ -36145,10 +36369,6 @@ static void parse_statement (void) {
     
     }
     
-    if (parse_parenthesized_member_function_pointer_call_statement ()) {
-        return;
-    }
-    
     if (tok.kind == TOK_LPAREN) {
     
         int parenthesized_assignment_is_unsigned;
@@ -37504,8 +37724,8 @@ static void parse_global_initializer_values (int64_s *values, char **symbols, in
 
 }
 
-static int int64_is_zero_value (int64_s value) {
-    return value.low == 0 && value.high == 0;
+static int int64_is_zero_value (const int64_s *value) {
+    return value->low == 0 && value->high == 0;
 }
 
 static char masm_pending_data_label[512];
@@ -37764,11 +37984,15 @@ static int global_initializer_is_all_zero (const int64_s *values, char **symbols
     int i;
 
     if (symbols) {
+    
         for (i = 0; i < value_count; i++) {
+        
             if (symbols[i]) {
                 return 0;
             }
+        
         }
+    
     }
 
     if (!values || value_count <= 0) {
@@ -37776,9 +38000,11 @@ static int global_initializer_is_all_zero (const int64_s *values, char **symbols
     }
 
     for (i = 0; i < value_count; i++) {
-        if (!int64_is_zero_value (values[i])) {
+    
+        if (!int64_is_zero_value (&values[i])) {
             return 0;
         }
+    
     }
 
     return 1;
diff --git a/i386.c b/i386.c
index 0bc62b7d62b9840c25b571f35c4cdef6ba640b1a..1fc3f1f5c87cf84a0bb6d1e75a9eccc37b6b66f9 100644 (file)
--- a/i386.c
+++ b/i386.c
@@ -101,6 +101,7 @@ static const char *postfix_copy_lvalue_tag_name = 0;
 
 static int postfix_member_offset = 0;
 static int postfix_member_size = 0;
+static int postfix_value_is_array = 0;
 
 static int postfix_member_is_floating = 0;
 static int postfix_member_is_unsigned = 0;
@@ -12884,6 +12885,7 @@ static void emit_apply_postfix_member_access_to_reg_now (const char *reg) {
             postfix_member_pointed_size = elem_size;
             postfix_member_offset = offset;
             postfix_member_size = size;
+            postfix_value_is_array = is_array;
             postfix_member_is_floating = is_floating;
             postfix_member_is_unsigned = is_unsigned;
             postfix_member_calling_convention = last_found_member_calling_convention;
@@ -12899,6 +12901,8 @@ static void emit_apply_postfix_member_access_to_reg_now (const char *reg) {
                 enum token_kind assign_op;
                 int subscript_elem_size;
                 
+                postfix_value_is_array = 0;
+                
                 if (!is_array && pointer_depth > 0) {
                     emit_load_member_from_addr_reg_now (reg, reg, offset, DATA_PTR & 0x1f);
                 } else if (state->ofp && offset != 0) {
@@ -15986,6 +15990,156 @@ static int source_starts_lparen_deref_subscript_at (const char *p) {
 
 }
 
+static int source_starts_lparen_subscript_call_at (const char *p) {
+
+    int bracket_depth;
+    
+    if (!p || *p != '(') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '[') {
+        return 0;
+    }
+    
+    bracket_depth = 1;
+    p++;
+    
+    while (*p && bracket_depth > 0) {
+    
+        if (*p == '[') {
+            bracket_depth++;
+        } else if (*p == ']') {
+            bracket_depth--;
+        }
+        
+        p++;
+    
+    }
+    
+    if (bracket_depth != 0) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != ')') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '(';
+
+}
+
+static int source_starts_lparen_deref_subscript_call_at (const char *p) {
+
+    int bracket_depth;
+    
+    if (!p) {
+        return 0;
+    }
+    
+    if (*p == '(') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '*') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (!((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || *p == '_')) {
+        return 0;
+    }
+    
+    p++;
+    
+    while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '_') {
+        p++;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != '[') {
+        return 0;
+    }
+    
+    bracket_depth = 1;
+    p++;
+    
+    while (*p && bracket_depth > 0) {
+    
+        if (*p == '[') {
+            bracket_depth++;
+        } else if (*p == ']') {
+            bracket_depth--;
+        }
+        
+        p++;
+    
+    }
+    
+    if (bracket_depth != 0) {
+        return 0;
+    }
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    if (*p != ')') {
+        return 0;
+    }
+    
+    p++;
+    
+    while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
+        p++;
+    }
+    
+    return *p == '(';
+
+}
+
 static int source_starts_lparen_deref_postfix_incdec_at (const char *p) {
 
     if (!p) {
@@ -19117,6 +19271,25 @@ static void emit_load_assignment_rhs_to_reg (const char *reg) {
                 
                 }
                 
+                if (tok.kind == TOK_LPAREN) {
+                
+                    /*
+                     * Subscript parsing leaves reg holding the address of the
+                     * selected array element.  For an array of function pointers,
+                     * load the pointer stored in that element before emitting the
+                     * indirect call.  Calling reg directly here calls the address
+                     * of the array slot instead of the function it contains.
+                     */
+                    emit_load_deref_reg_now (reg, DATA_PTR & 0x1f);
+                    
+                    emit_call_pointer_in_reg_now (reg, reg);
+                    set_rhs_last_pointer_info (0, 0);
+                    
+                    free (name);
+                    return;
+                
+                }
+                
                 emit_apply_postfix_member_access_to_reg_now (reg);
                 postfix_copy_lvalue_tag_name = 0;
                 
@@ -19184,6 +19357,25 @@ static void emit_load_assignment_rhs_to_reg (const char *reg) {
                 
                 }
                 
+                if (tok.kind == TOK_LPAREN) {
+                
+                    /*
+                     * Subscript parsing leaves reg holding the address of the
+                     * selected array element.  For an array of function pointers,
+                     * load the pointer stored in that element before emitting the
+                     * indirect call.  Calling reg directly here calls the address
+                     * of the array slot instead of the function it contains.
+                     */
+                    emit_load_deref_reg_now (reg, DATA_PTR & 0x1f);
+                    
+                    emit_call_pointer_in_reg_now (reg, reg);
+                    set_rhs_last_pointer_info (0, 0);
+                    
+                    free (name);
+                    return;
+                
+                }
+                
                 emit_apply_postfix_member_access_to_reg_now (reg);
                 postfix_copy_lvalue_tag_name = 0;
                 
@@ -19581,6 +19773,8 @@ static void emit_load_assignment_rhs_to_reg (const char *reg) {
         
             if (src->is_array) {
             
+                postfix_value_is_array = 1;
+                
                 if (src->is_static && src->static_label) {
                     emit_load_address_to_reg_now (reg, src->static_label);
                 } else {
@@ -19687,6 +19881,8 @@ static void emit_load_assignment_rhs_to_reg (const char *reg) {
         
         if (find_global_symbol (name) >= 0) {
         
+            postfix_value_is_array = get_global_symbol_array (name);
+            
             if (get_global_symbol_kind (name) == GLOBAL_SYMBOL_FUNCTION ||
                 get_global_symbol_array (name) ||
                 (!get_global_symbol_pointer_depth (name) &&
@@ -21883,6 +22079,16 @@ static void emit_load_floating_rhs_expression_now (int result_size) {
 
 static void emit_load_assignment_rhs_expression_to_reg (const char *reg);
 
+static int local_symbol_is_array_now (const struct local_symbol *sym) {
+
+    if (!sym) {
+        return 0;
+    }
+    
+    return sym->is_array || sym->array_dimensions > 0 || sym->array_element_size > 0;
+
+}
+
 static int current_argument_is_bare_identifier_now (void) {
 
     const char *p;
@@ -22023,13 +22229,39 @@ static int emit_push_global_aggregate_argument_now (const char *name) {
     int offset;
     int chunk;
 
-    if (!name || get_global_symbol_kind (name) != GLOBAL_SYMBOL_OBJECT ||
-        get_global_symbol_array (name) || get_global_symbol_pointer_depth (name) > 0 ||
-        get_global_symbol_floating (name)) {
+    const char *tag_name;
+
+    if (!name) {
+        return 0;
+    }
+    
+    if (get_global_symbol_kind (name) != GLOBAL_SYMBOL_OBJECT) {
+        return 0;
+    }
+    
+    if (get_global_symbol_array (name)) {
+        return 0;
+    }
+    
+    if (get_global_symbol_pointer_depth (name) > 0) {
+        return 0;
+    }
+    
+    if (get_global_symbol_floating (name)) {
         return 0;
     }
     
     size = get_global_symbol_size (name);
+    tag_name = get_global_symbol_tag_name (name);
+    
+    /* Only tagged aggregate objects are passed by value here.  Untagged
+     * objects include scalar values and arrays whose decay metadata was not
+     * visible during the self-hosting pass; those must use normal expression
+     * loading so arrays decay to one address instead of multiple stack words.
+      */
+    if (!tag_name || !tag_name[0]) {
+        return 0;
+    }
     
     if (size <= (DATA_PTR & 0x1f)) {
         return 0;
@@ -22160,12 +22392,30 @@ static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result
             
             }
             
+            postfix_value_is_array = 0;
             postfix_member_seen = 0;
             postfix_member_size = 0;
             postfix_member_pointer_depth = 0;
             postfix_member_pointed_size = 0;
             
-            if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && emit_push_aggregate_argument_now (tok.ident, find_local_symbol (tok.ident))) {
+            if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && local_symbol_is_array_now (find_local_symbol (tok.ident))) {
+            
+                struct local_symbol *arg_sym = find_local_symbol (tok.ident);
+                
+                if (arg_sym->is_static && arg_sym->static_label) {
+                    emit_load_address_to_reg_now ("eax", arg_sym->static_label);
+                } else {
+                    emit_load_local_address_to_reg_now ("eax", arg_sym->offset);
+                }
+                
+                emit_push_reg_now ("eax");
+                
+                arg_bytes = DATA_PTR & 0x1f;
+                arg_is_floating = 0;
+                
+                get_token ();
+            
+            } else if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && emit_push_aggregate_argument_now (tok.ident, find_local_symbol (tok.ident))) {
             
                 struct local_symbol *arg_sym = find_local_symbol (tok.ident);
                 
@@ -22174,6 +22424,18 @@ static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result
                 
                 get_token ();
             
+            } else if (tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () &&
+                    !find_local_symbol (tok.ident) && find_global_symbol (tok.ident) >= 0 &&
+                        get_global_symbol_array (tok.ident)) {
+            
+                emit_load_address_to_reg_now ("eax", tok.ident);
+                emit_push_reg_now ("eax");
+                
+                arg_bytes = DATA_PTR;
+                arg_is_floating = 0;
+                
+                get_token ();
+            
             } else {
             
                 int arg_starts_64bit_integer = current_argument_starts_64bit_integer_now ();
@@ -22199,12 +22461,12 @@ static void emit_call_pointer_in_reg_now (const char *fn_reg, const char *result
                         emit_push_reg_now ("edx");
                         emit_push_reg_now ("eax");
                     
-                    } else if (!arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    } else if (!arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && !postfix_value_is_array && postfix_member_size > (DATA_PTR & 0x1f)) {
                     
                         arg_bytes = postfix_member_size;
                         emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
                     
-                    } else if (!arg_is_floating && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    } else if (!arg_is_floating && !postfix_value_is_array && postfix_member_size > (DATA_PTR & 0x1f)) {
                     
                         arg_bytes = postfix_member_size;
                         emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
@@ -22452,6 +22714,28 @@ static int current_argument_is_bare_64bit_identifier_now (void) {
 
 }
 
+static int call_argument_expects_by_value_aggregate_now (const char *name, int argument_index) {
+
+    int symbol_index;
+    
+    if (!name || argument_index < 0) {
+        return 0;
+    }
+    
+    symbol_index = find_global_symbol (name);
+    
+    if (symbol_index < 0 || global_symbols[symbol_index].kind != GLOBAL_SYMBOL_FUNCTION || !global_symbols[symbol_index].has_prototype ||
+        argument_index >= global_symbols[symbol_index].param_count ||
+            global_symbols[symbol_index].param_pointer_depths[argument_index] > 0 ||
+                global_symbols[symbol_index].param_floatings[argument_index] ||
+                    global_symbols[symbol_index].param_sizes[argument_index] <= (DATA_PTR & 0x1f)) {
+        return 0;
+    }
+    
+    return 1;
+
+}
+
 static int current_argument_starts_64bit_integer_now (void) {
 
     if (tok.kind == TOK_CLLONG || tok.kind == TOK_CULLONG) {
@@ -22580,12 +22864,30 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg,
             
             }
             
+            postfix_value_is_array = 0;
             postfix_member_seen = 0;
             postfix_member_size = 0;
             postfix_member_pointer_depth = 0;
             postfix_member_pointed_size = 0;
             
-            if (!use_inline && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && emit_push_aggregate_argument_now (tok.ident, find_local_symbol (tok.ident))) {
+            if (!use_inline && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && local_symbol_is_array_now (find_local_symbol (tok.ident))) {
+            
+                struct local_symbol *arg_sym = find_local_symbol (tok.ident);
+                
+                if (arg_sym->is_static && arg_sym->static_label) {
+                    emit_load_address_to_reg_now ("eax", arg_sym->static_label);
+                } else {
+                    emit_load_local_address_to_reg_now ("eax", arg_sym->offset);
+                }
+                
+                emit_push_reg_now ("eax");
+                
+                arg_bytes = DATA_PTR & 0x1f;
+                arg_is_floating = 0;
+                
+                get_token ();
+            
+            } else if (!use_inline && call_argument_expects_by_value_aggregate_now (name, argc) && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && find_local_symbol (tok.ident) && emit_push_aggregate_argument_now (tok.ident, find_local_symbol (tok.ident))) {
             
                 struct local_symbol *arg_sym = find_local_symbol (tok.ident);
                 
@@ -22594,7 +22896,20 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg,
                 
                 get_token ();
             
-            } else if (!use_inline && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && !find_local_symbol (tok.ident) && emit_push_global_aggregate_argument_now (tok.ident)) {
+            } else if (!use_inline && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () &&
+                !find_local_symbol (tok.ident) && find_global_symbol (tok.ident) >= 0 &&
+                    get_global_symbol_array (tok.ident) &&
+                        !call_argument_expects_by_value_aggregate_now (name, argc)) {
+            
+                emit_load_address_to_reg_now ("eax", tok.ident);
+                emit_push_reg_now ("eax");
+                
+                arg_bytes = DATA_PTR;
+                arg_is_floating = 0;
+                
+                get_token ();
+            
+            } else if (!use_inline && call_argument_expects_by_value_aggregate_now (name, argc) && tok.kind == TOK_IDENT && tok.ident && current_argument_is_bare_identifier_now () && !find_local_symbol (tok.ident) && emit_push_global_aggregate_argument_now (tok.ident)) {
             
                 arg_bytes = get_global_symbol_size (tok.ident);
                 arg_is_floating = 0;
@@ -22677,12 +22992,12 @@ static void emit_call_identifier_to_reg_now (const char *name, const char *reg,
                         emit_push_reg_now ("edx");
                         emit_push_reg_now ("eax");
                     
-                    } else if (!use_inline && !arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    } else if (!use_inline && !arg_is_floating && postfix_member_seen && postfix_member_pointer_depth == 0 && !postfix_value_is_array && postfix_member_size > (DATA_PTR & 0x1f)) {
                     
                         arg_bytes = postfix_member_size;
                         emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
                     
-                    } else if (!use_inline && !arg_is_floating && postfix_member_size > (DATA_PTR & 0x1f)) {
+                    } else if (!use_inline && !arg_is_floating && !postfix_value_is_array && postfix_member_size > (DATA_PTR & 0x1f)) {
                     
                         arg_bytes = postfix_member_size;
                         emit_push_aggregate_from_addr_reg_now ("eax", arg_bytes);
@@ -27212,6 +27527,15 @@ static int parse_parenthesized_deref_subscript_statement (void) {
     
     }
     
+    if (tok.kind == TOK_LPAREN) {
+    
+        get_token ();
+        
+        expect (TOK_RPAREN, ")");
+        emit_call_pointer_in_reg_now ("eax", "eax");
+    
+    }
+    
     emit_load_deref_reg_now ("eax", DATA_PTR & 0x1f);
     emit_handle_subscript_after_loaded_pointer_to_reg_now ("eax", pointer_depth - 1, pointed_size, src ? src->pointed_is_unsigned : get_global_symbol_pointed_is_unsigned (name));
     
@@ -27607,6 +27931,20 @@ static int parse_identifier_assignment_statement (void) {
             emit_parse_postfix_subscript_scaled_address_to_reg_now ("edx", elem_size);
         }
         
+        if (tok.kind == TOK_LPAREN) {
+        
+            if (state->ofp) {
+                emit_load_deref_reg_now ("edx", DATA_PTR & 0x1f);
+            }
+            
+            emit_call_pointer_in_reg_now ("edx", "eax");
+            expect_semi_or_recover ();
+            
+            free (name);
+            return 1;
+        
+        }
+        
         if (tok.kind == TOK_INCR || tok.kind == TOK_DECR) {
         
             op = tok.kind;
@@ -33377,18 +33715,16 @@ static int parse_parenthesized_member_function_pointer_call_statement (void) {
     
     const char *base_tag_name = 0;
     
-    if (tok.kind != TOK_LPAREN || !source_starts_with_parenthesized_indirect_call_now ()) {
+    if (tok.kind != TOK_LPAREN || (!source_starts_with_parenthesized_indirect_call_now () && !source_starts_lparen_deref_subscript_call_at (tok.start) && !source_starts_lparen_deref_subscript_call_at (tok.caret) && !source_starts_lparen_subscript_call_at (tok.start) && !source_starts_lparen_subscript_call_at (tok.caret))) {
         return 0;
     }
     
     get_token ();
     
-    if (tok.kind != TOK_STAR) {
-        return 0;
+    if (tok.kind == TOK_STAR) {
+        get_token ();
     }
     
-    get_token ();
-    
     if (tok.kind == TOK_LPAREN) {
     
         wrapped_member_expr = 1;
@@ -33523,6 +33859,10 @@ static void parse_statement (void) {
     
     }
     
+    if (parse_parenthesized_member_function_pointer_call_statement ()) {
+        return;
+    }
+    
     if (parse_parenthesized_deref_subscript_statement ()) {
     
         expect_semi_or_recover ();
@@ -33530,10 +33870,6 @@ static void parse_statement (void) {
     
     }
     
-    if (parse_parenthesized_member_function_pointer_call_statement ()) {
-        return;
-    }
-    
     if (tok.kind == TOK_LPAREN) {
     
         int parenthesized_assignment_is_unsigned;
@@ -34858,8 +35194,8 @@ static void parse_global_initializer_values (int64_s *values, char **symbols, in
 
 }
 
-static int int64_is_zero_value (int64_s value) {
-    return value.low == 0 && value.high == 0;
+static int int64_is_zero_value (const int64_s *value) {
+    return value->low == 0 && value->high == 0;
 }
 
 static char masm_pending_data_label[512];
@@ -35118,11 +35454,15 @@ static int global_initializer_is_all_zero (const int64_s *values, char **symbols
     int i;
 
     if (symbols) {
+    
         for (i = 0; i < value_count; i++) {
+        
             if (symbols[i]) {
                 return 0;
             }
+        
         }
+    
     }
 
     if (!values || value_count <= 0) {
@@ -35130,9 +35470,11 @@ static int global_initializer_is_all_zero (const int64_s *values, char **symbols
     }
 
     for (i = 0; i < value_count; i++) {
-        if (!int64_is_zero_value (values[i])) {
+    
+        if (!int64_is_zero_value (&values[i])) {
             return 0;
         }
+    
     }
 
     return 1;