@@ -1854,8 +1854,9 @@ impl SsaBuilder {
18541854 }
18551855
18561856 TypedExpression :: Array ( elements) => {
1857- // Create ZRTL array format: [i32 capacity][i32 length][elements...]
1858- // This format allows plugins to safely read array length
1857+ // Lower array literal as List<T> struct: { data: i64 (ptr), len: i64, capacity: i64 }
1858+ // This matches the List<T> struct definition in prelude.zynml and allows
1859+ // field access (shape.data, shape.len) via extractvalue to work correctly.
18591860 let elem_ty = if let Type :: Array { element_type, .. } = & expr. ty {
18601861 self . convert_type ( element_type)
18611862 } else {
@@ -1873,58 +1874,28 @@ impl SsaBuilder {
18731874 } ;
18741875 let num_elements = elements. len ( ) ;
18751876
1876- // ZRTL array header: 8 bytes (capacity i32 + length i32)
1877- const ZRTL_HEADER_BYTES : usize = 8 ;
1878- let total_size = ZRTL_HEADER_BYTES + num_elements * elem_size;
1879-
1880- // Allocate raw bytes for the entire ZRTL array
1881- let alloc_ty = HirType :: Array ( Box :: new ( HirType :: U8 ) , total_size as u64 ) ;
1882- let alloc_result = self . create_value ( HirType :: Ptr ( Box :: new ( HirType :: I32 ) ) , HirValueKind :: Instruction ) ;
1883-
1877+ // Step 1: Allocate element data buffer
1878+ let data_buf_size = num_elements * elem_size;
1879+ let data_alloc_ty = HirType :: Array ( Box :: new ( elem_ty. clone ( ) ) , num_elements as u64 ) ;
1880+ let data_ptr = self . create_value ( HirType :: Ptr ( Box :: new ( elem_ty. clone ( ) ) ) , HirValueKind :: Instruction ) ;
18841881 self . add_instruction ( block_id, HirInstruction :: Alloca {
1885- result : alloc_result ,
1886- ty : alloc_ty ,
1882+ result : data_ptr ,
1883+ ty : data_alloc_ty ,
18871884 count : None ,
1888- align : 8 ,
1885+ align : elem_size . min ( 8 ) as u32 ,
18891886 } ) ;
18901887
1891- // Store capacity at offset 0 (i32)
1892- let cap_const = self . create_value ( HirType :: I32 , HirValueKind :: Constant ( crate :: hir:: HirConstant :: I32 ( num_elements as i32 ) ) ) ;
1893- self . add_instruction ( block_id, HirInstruction :: Store {
1894- value : cap_const,
1895- ptr : alloc_result,
1896- align : 4 ,
1897- volatile : false ,
1898- } ) ;
1899-
1900- // Store length at offset 4 (i32) - need to calculate ptr + 4
1901- let len_const = self . create_value ( HirType :: I32 , HirValueKind :: Constant ( crate :: hir:: HirConstant :: I32 ( num_elements as i32 ) ) ) ;
1902- let offset_4 = self . create_value ( HirType :: I64 , HirValueKind :: Constant ( crate :: hir:: HirConstant :: I64 ( 4 ) ) ) ;
1903- let len_ptr = self . create_value ( HirType :: Ptr ( Box :: new ( HirType :: I32 ) ) , HirValueKind :: Instruction ) ;
1904- self . add_instruction ( block_id, HirInstruction :: GetElementPtr {
1905- result : len_ptr,
1906- ty : HirType :: U8 , // Base type for byte offset calculation
1907- ptr : alloc_result,
1908- indices : vec ! [ offset_4] ,
1909- } ) ;
1910- self . add_instruction ( block_id, HirInstruction :: Store {
1911- value : len_const,
1912- ptr : len_ptr,
1913- align : 4 ,
1914- volatile : false ,
1915- } ) ;
1916-
1917- // Store each element starting at offset 8
1888+ // Step 2: Store each element into the data buffer
19181889 for ( i, elem_expr) in elements. iter ( ) . enumerate ( ) {
19191890 let elem_val = self . translate_expression ( block_id, elem_expr) ?;
19201891
1921- let offset = ZRTL_HEADER_BYTES + i * elem_size;
1892+ let offset = i * elem_size;
19221893 let offset_const = self . create_value ( HirType :: I64 , HirValueKind :: Constant ( crate :: hir:: HirConstant :: I64 ( offset as i64 ) ) ) ;
19231894 let elem_ptr = self . create_value ( HirType :: Ptr ( Box :: new ( elem_ty. clone ( ) ) ) , HirValueKind :: Instruction ) ;
19241895 self . add_instruction ( block_id, HirInstruction :: GetElementPtr {
19251896 result : elem_ptr,
19261897 ty : HirType :: U8 , // Base type for byte offset calculation
1927- ptr : alloc_result ,
1898+ ptr : data_ptr ,
19281899 indices : vec ! [ offset_const] ,
19291900 } ) ;
19301901
@@ -1936,8 +1907,71 @@ impl SsaBuilder {
19361907 } ) ;
19371908 }
19381909
1939- // Return pointer to the ZRTL array header
1940- Ok ( alloc_result)
1910+ // Step 3: Build List<T> struct: { data: i64 (ptr), len: i64, capacity: i64 }
1911+ let list_struct_ty = HirType :: Struct ( crate :: hir:: HirStructType {
1912+ name : None ,
1913+ fields : vec ! [ HirType :: I64 , HirType :: I64 , HirType :: I64 ] ,
1914+ packed : false ,
1915+ } ) ;
1916+ let list_alloc = self . create_value ( HirType :: Ptr ( Box :: new ( list_struct_ty. clone ( ) ) ) , HirValueKind :: Instruction ) ;
1917+ self . add_instruction ( block_id, HirInstruction :: Alloca {
1918+ result : list_alloc,
1919+ ty : list_struct_ty,
1920+ count : None ,
1921+ align : 8 ,
1922+ } ) ;
1923+
1924+ // Store data pointer (field 0) — cast ptr to i64 for storage
1925+ let data_as_i64 = self . create_value ( HirType :: I64 , HirValueKind :: Instruction ) ;
1926+ self . add_instruction ( block_id, HirInstruction :: Cast {
1927+ result : data_as_i64,
1928+ ty : HirType :: I64 ,
1929+ operand : data_ptr,
1930+ op : crate :: hir:: CastOp :: PtrToInt ,
1931+ } ) ;
1932+ self . add_instruction ( block_id, HirInstruction :: Store {
1933+ value : data_as_i64,
1934+ ptr : list_alloc,
1935+ align : 8 ,
1936+ volatile : false ,
1937+ } ) ;
1938+
1939+ // Store len (field 1) at offset 8
1940+ let len_const = self . create_value ( HirType :: I64 , HirValueKind :: Constant ( crate :: hir:: HirConstant :: I64 ( num_elements as i64 ) ) ) ;
1941+ let offset_8 = self . create_value ( HirType :: I64 , HirValueKind :: Constant ( crate :: hir:: HirConstant :: I64 ( 8 ) ) ) ;
1942+ let len_field_ptr = self . create_value ( HirType :: Ptr ( Box :: new ( HirType :: I64 ) ) , HirValueKind :: Instruction ) ;
1943+ self . add_instruction ( block_id, HirInstruction :: GetElementPtr {
1944+ result : len_field_ptr,
1945+ ty : HirType :: U8 , // byte offset
1946+ ptr : list_alloc,
1947+ indices : vec ! [ offset_8] ,
1948+ } ) ;
1949+ self . add_instruction ( block_id, HirInstruction :: Store {
1950+ value : len_const,
1951+ ptr : len_field_ptr,
1952+ align : 8 ,
1953+ volatile : false ,
1954+ } ) ;
1955+
1956+ // Store capacity (field 2) at offset 16
1957+ let cap_const = self . create_value ( HirType :: I64 , HirValueKind :: Constant ( crate :: hir:: HirConstant :: I64 ( num_elements as i64 ) ) ) ;
1958+ let offset_16 = self . create_value ( HirType :: I64 , HirValueKind :: Constant ( crate :: hir:: HirConstant :: I64 ( 16 ) ) ) ;
1959+ let cap_field_ptr = self . create_value ( HirType :: Ptr ( Box :: new ( HirType :: I64 ) ) , HirValueKind :: Instruction ) ;
1960+ self . add_instruction ( block_id, HirInstruction :: GetElementPtr {
1961+ result : cap_field_ptr,
1962+ ty : HirType :: U8 , // byte offset
1963+ ptr : list_alloc,
1964+ indices : vec ! [ offset_16] ,
1965+ } ) ;
1966+ self . add_instruction ( block_id, HirInstruction :: Store {
1967+ value : cap_const,
1968+ ptr : cap_field_ptr,
1969+ align : 8 ,
1970+ volatile : false ,
1971+ } ) ;
1972+
1973+ // Return pointer to the List struct
1974+ Ok ( list_alloc)
19411975 }
19421976
19431977 TypedExpression :: Tuple ( elements) => {
@@ -3248,6 +3282,7 @@ impl SsaBuilder {
32483282 PrimitiveType :: F32 => HirType :: F32 ,
32493283 PrimitiveType :: F64 => HirType :: F64 ,
32503284 PrimitiveType :: Unit => HirType :: Void ,
3285+ PrimitiveType :: String => HirType :: Ptr ( Box :: new ( HirType :: I8 ) ) , // String is Ptr<i8>
32513286 _ => HirType :: I64 , // Default
32523287 } ,
32533288 Type :: Tuple ( types) if types. is_empty ( ) => HirType :: Void ,
0 commit comments