@@ -600,6 +600,16 @@ LLVMValueRef codegen_expr_assignment(CodeGenContext *ctx, AstNode *node) {
600600 if (target -> type == AST_EXPR_IDENTIFIER ) {
601601 LLVM_Symbol * sym = find_symbol (ctx , target -> expr .identifier .name );
602602 if (sym && !sym -> is_function ) {
603+ // NEW: If assigning a cast expression, update element type
604+ if (node -> expr .assignment .value -> type == AST_EXPR_CAST ) {
605+ AstNode * cast_node = node -> expr .assignment .value ;
606+ LLVMTypeRef new_element_type =
607+ extract_element_type_from_ast (ctx , cast_node -> expr .cast .type );
608+ if (new_element_type ) {
609+ sym -> element_type = new_element_type ;
610+ }
611+ }
612+
603613 LLVMBuildStore (ctx -> builder , value , sym -> value );
604614 return value ;
605615 }
@@ -874,7 +884,8 @@ LLVMValueRef codegen_expr_array(CodeGenContext *ctx, AstNode *node) {
874884
875885 AstNode * * elements = node -> expr .array .elements ;
876886 size_t element_count = node -> expr .array .element_count ;
877- size_t target_size = node -> expr .array .target_size ; // NEW: Get target size for padding
887+ size_t target_size =
888+ node -> expr .array .target_size ; // NEW: Get target size for padding
878889
879890 if (element_count == 0 ) {
880891 fprintf (stderr , "Error: Empty array literals not supported\n" );
@@ -889,17 +900,19 @@ LLVMValueRef codegen_expr_array(CodeGenContext *ctx, AstNode *node) {
889900 }
890901
891902 LLVMTypeRef element_type = LLVMTypeOf (first_element );
892-
893- // NEW: Use target_size if set (for padding), otherwise use actual element_count
903+
904+ // NEW: Use target_size if set (for padding), otherwise use actual
905+ // element_count
894906 size_t actual_array_size = (target_size > 0 ) ? target_size : element_count ;
895907 LLVMTypeRef array_type = LLVMArrayType (element_type , actual_array_size );
896908
897909 // Check if all elements are constants
898910 bool all_constants = LLVMIsConstant (first_element );
899-
911+
900912 // NEW: Allocate for the FULL size (including padding)
901913 LLVMValueRef * element_values = (LLVMValueRef * )arena_alloc (
902- ctx -> arena , sizeof (LLVMValueRef ) * actual_array_size , alignof(LLVMValueRef ));
914+ ctx -> arena , sizeof (LLVMValueRef ) * actual_array_size ,
915+ alignof(LLVMValueRef ));
903916
904917 element_values [0 ] = first_element ;
905918
@@ -931,11 +944,11 @@ LLVMValueRef codegen_expr_array(CodeGenContext *ctx, AstNode *node) {
931944 // NEW: Pad remaining elements with zeros if target_size > element_count
932945 if (target_size > element_count ) {
933946 LLVMValueRef zero_value = LLVMConstNull (element_type );
934-
947+
935948 for (size_t i = element_count ; i < target_size ; i ++ ) {
936949 element_values [i ] = zero_value ;
937950 }
938-
951+
939952 // If we're padding, we can't be all constants unless zeros count
940953 // (which they do, so keep checking)
941954 // zero_value is always constant, so all_constants remains unchanged
@@ -1172,25 +1185,31 @@ LLVMValueRef codegen_expr_index(CodeGenContext *ctx, AstNode *node) {
11721185 // Direct array value indexing (from array literals)
11731186 LLVMTypeRef element_type = LLVMGetElementType (object_type );
11741187
1175- // We need to store the array and get a pointer to it for GEP
1188+ // Allocate with proper alignment for the array type
11761189 LLVMValueRef array_alloca =
11771190 LLVMBuildAlloca (ctx -> builder , object_type , "temp_array" );
1178- LLVMBuildStore (ctx -> builder , object , array_alloca );
11791191
1180- // Create GEP indices: [0, index] for array access
1192+ // Store with proper alignment - CRITICAL for i64 arrays!
1193+ LLVMValueRef store_inst =
1194+ LLVMBuildStore (ctx -> builder , object , array_alloca );
1195+ // For i64 arrays, we need 8-byte alignment
1196+ LLVMSetAlignment (store_inst , 8 );
1197+
1198+ // Use InBoundsGEP for safety
11811199 LLVMValueRef indices [2 ];
11821200 indices [0 ] = LLVMConstInt (LLVMInt32TypeInContext (ctx -> context ), 0 , false);
11831201 indices [1 ] = index ;
11841202
11851203 LLVMValueRef element_ptr =
1186- LLVMBuildGEP2 (ctx -> builder , object_type , array_alloca , indices , 2 ,
1187- "array_element_ptr" );
1204+ LLVMBuildInBoundsGEP2 (ctx -> builder , object_type , array_alloca , indices ,
1205+ 2 , "array_element_ptr" );
11881206
1189- // CRITICAL FIX: Always load the element value
1190- // If it's an inner array, load it so the next indexing operation
1191- // receives an array value (not a pointer)
1192- return LLVMBuildLoad2 (ctx -> builder , element_type , element_ptr ,
1193- "array_element" );
1207+ // Load with proper alignment
1208+ LLVMValueRef load_inst = LLVMBuildLoad2 (ctx -> builder , element_type ,
1209+ element_ptr , "array_element" );
1210+ LLVMSetAlignment (load_inst , 8 );
1211+
1212+ return load_inst ;
11941213
11951214 } else if (object_kind == LLVMPointerTypeKind ) {
11961215 // Handle pointer indexing - check if it's a symbol first for better type
@@ -1241,38 +1260,114 @@ LLVMValueRef codegen_expr_index(CodeGenContext *ctx, AstNode *node) {
12411260 }
12421261 }
12431262 } else if (node -> expr .index .object -> type == AST_EXPR_INDEX ) {
1244- // Second-level indexing: ptr[i][j]
1245- // Trace back to find the base variable
1246- AstNode * base_node = node -> expr .index .object ;
1247- while (base_node -> type == AST_EXPR_INDEX ) {
1248- base_node = base_node -> expr .index .object ;
1263+ // Second-level indexing: either arr[i][j] for arrays OR ptr[i][j] for
1264+ // pointers We need to handle these differently!
1265+
1266+ // First, let's check what the FIRST indexing returns
1267+ // Generate it to see if we get an array value or a pointer
1268+ LLVMValueRef first_index_result =
1269+ codegen_expr (ctx , node -> expr .index .object );
1270+ if (!first_index_result ) {
1271+ return NULL ;
12491272 }
1250- if (base_node -> type == AST_EXPR_IDENTIFIER ) {
1251- const char * base_var_name = base_node -> expr .identifier .name ;
1252- LLVM_Symbol * base_sym = find_symbol (ctx , base_var_name );
1253- if (base_sym && base_sym -> element_type ) {
1254- // For multi-dimensional arrays, the element type after first index
1255- // would be a pointer to the inner type
1256- if (LLVMGetTypeKind (base_sym -> element_type ) == LLVMPointerTypeKind ) {
1257- // This needs more sophisticated handling for multi-dimensional
1258- // arrays
1259- pointee_type = LLVMInt64TypeInContext (ctx -> context ); // fallback
1273+
1274+ LLVMTypeRef first_result_type = LLVMTypeOf (first_index_result );
1275+ LLVMTypeKind first_result_kind = LLVMGetTypeKind (first_result_type );
1276+
1277+ // CASE 1: First indexing returned an ARRAY value (nested array literal)
1278+ // Example: directions[d] where directions is [[int; 2]; 8]
1279+ if (first_result_kind == LLVMArrayTypeKind ) {
1280+ // This is a nested array access - the first index gave us an array
1281+ // Now index into that array
1282+ LLVMTypeRef inner_element_type = LLVMGetElementType (first_result_type );
1283+
1284+ // Store the array value so we can GEP into it
1285+ LLVMValueRef temp_alloca = LLVMBuildAlloca (
1286+ ctx -> builder , first_result_type , "nested_array_temp" );
1287+
1288+ // CRITICAL: Store with proper alignment for i64 arrays
1289+ LLVMValueRef store_inst =
1290+ LLVMBuildStore (ctx -> builder , first_index_result , temp_alloca );
1291+ LLVMSetAlignment (store_inst , 8 );
1292+
1293+ // Use InBoundsGEP with proper indices
1294+ LLVMValueRef gep_indices [2 ];
1295+ gep_indices [0 ] =
1296+ LLVMConstInt (LLVMInt32TypeInContext (ctx -> context ), 0 , false);
1297+ gep_indices [1 ] = index ;
1298+
1299+ LLVMValueRef element_ptr =
1300+ LLVMBuildInBoundsGEP2 (ctx -> builder , first_result_type , temp_alloca ,
1301+ gep_indices , 2 , "nested_element_ptr" );
1302+
1303+ // Load with proper alignment
1304+ LLVMValueRef load_inst = LLVMBuildLoad2 (
1305+ ctx -> builder , inner_element_type , element_ptr , "nested_element" );
1306+ LLVMSetAlignment (load_inst , 8 );
1307+
1308+ return load_inst ;
1309+ }
1310+
1311+ // CASE 2: First indexing returned a POINTER (double pointer like **byte)
1312+ else if (first_result_kind == LLVMPointerTypeKind ) {
1313+ // This is pointer indexing: grid[r][c] where grid is **byte
1314+ // first_index_result is the result of grid[r], which is a *byte
1315+
1316+ // Trace back to find the base variable for type info
1317+ AstNode * base_node = node -> expr .index .object ;
1318+ while (base_node -> type == AST_EXPR_INDEX ) {
1319+ base_node = base_node -> expr .index .object ;
1320+ }
1321+
1322+ if (base_node -> type == AST_EXPR_IDENTIFIER ) {
1323+ const char * base_var_name = base_node -> expr .identifier .name ;
1324+ LLVM_Symbol * base_sym = find_symbol (ctx , base_var_name );
1325+
1326+ if (base_sym && base_sym -> element_type ) {
1327+ // For **byte, element_type is *byte (pointer to byte)
1328+ // We need to dereference once more to get byte
1329+ if (LLVMGetTypeKind (base_sym -> element_type ) ==
1330+ LLVMPointerTypeKind ) {
1331+ // Check the base variable name to infer the final type
1332+ if (strstr (base_var_name , "byte" ) ||
1333+ strstr (base_var_name , "char" )) {
1334+ pointee_type = LLVMInt8TypeInContext (ctx -> context );
1335+ } else if (strstr (base_var_name , "int" ) &&
1336+ !strstr (base_var_name , "byte" )) {
1337+ pointee_type = LLVMInt64TypeInContext (ctx -> context );
1338+ } else if (strstr (base_var_name , "double" )) {
1339+ pointee_type = LLVMDoubleTypeInContext (ctx -> context );
1340+ } else if (strstr (base_var_name , "float" )) {
1341+ pointee_type = LLVMFloatTypeInContext (ctx -> context );
1342+ } else {
1343+ pointee_type = LLVMInt8TypeInContext (ctx -> context );
1344+ }
1345+ } else {
1346+ pointee_type = base_sym -> element_type ;
1347+ }
12601348 } else {
1261- pointee_type = base_sym -> element_type ;
1262- }
1263- } else {
1264- // Old name-based fallback
1265- if (strstr (base_var_name , "double" )) {
1266- pointee_type = LLVMDoubleTypeInContext (ctx -> context );
1267- } else if (strstr (base_var_name , "float" )) {
1268- pointee_type = LLVMFloatTypeInContext (ctx -> context );
1269- } else if (strstr (base_var_name , "int" ) &&
1270- !strstr (base_var_name , "char" )) {
1271- pointee_type = LLVMInt64TypeInContext (ctx -> context );
1272- } else if (strstr (base_var_name , "char" ) ||
1273- strstr (base_var_name , "_buf" )) {
1274- pointee_type = LLVMInt8TypeInContext (ctx -> context );
1349+ // Fallback based on variable name
1350+ if (strstr (base_var_name , "byte" ) ||
1351+ strstr (base_var_name , "char" )) {
1352+ pointee_type = LLVMInt8TypeInContext (ctx -> context );
1353+ } else if (strstr (base_var_name , "double" )) {
1354+ pointee_type = LLVMDoubleTypeInContext (ctx -> context );
1355+ } else if (strstr (base_var_name , "float" )) {
1356+ pointee_type = LLVMFloatTypeInContext (ctx -> context );
1357+ } else if (strstr (base_var_name , "int" )) {
1358+ pointee_type = LLVMInt64TypeInContext (ctx -> context );
1359+ } else {
1360+ pointee_type = LLVMInt8TypeInContext (ctx -> context );
1361+ }
12751362 }
1363+
1364+ // Now we have the pointer from first indexing and the element type
1365+ // Do the second level of pointer indexing
1366+ LLVMValueRef element_ptr =
1367+ LLVMBuildGEP2 (ctx -> builder , pointee_type , first_index_result ,
1368+ & index , 1 , "ptr_ptr_element" );
1369+ return LLVMBuildLoad2 (ctx -> builder , pointee_type , element_ptr ,
1370+ "ptr_ptr_element_val" );
12761371 }
12771372 }
12781373 } else if (node -> expr .index .object -> type == AST_EXPR_CAST ) {
0 commit comments