authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-14 23:53:53-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-15 13:04:18-05:00
logf276fd0f3728bf1a43b185e3e2d33d593309cb2f
tree39d52f6a39df87005065ddba1531e40f968cee86
parent7a74dbadd79d2b26a449027dd83753ae4d2a8032

basic union support

See #144

10 files changed, 559 insertions(+), 26 deletions(-)

src/all_types.hpp+41-2
...@@ -73,6 +73,7 @@ enum ConstParentId {...@@ -73,6 +73,7 @@ enum ConstParentId {
73 ConstParentIdNone,73 ConstParentIdNone,
74 ConstParentIdStruct,74 ConstParentIdStruct,
75 ConstParentIdArray,75 ConstParentIdArray,
76 ConstParentIdUnion,
76};77};
7778
78struct ConstParent {79struct ConstParent {
...@@ -87,6 +88,9 @@ struct ConstParent {...@@ -87,6 +88,9 @@ struct ConstParent {
87 ConstExprValue *struct_val;88 ConstExprValue *struct_val;
88 size_t field_index;89 size_t field_index;
89 } p_struct;90 } p_struct;
91 struct {
92 ConstExprValue *union_val;
93 } p_union;
90 } data;94 } data;
91};95};
9296
...@@ -100,6 +104,11 @@ struct ConstStructValue {...@@ -100,6 +104,11 @@ struct ConstStructValue {
100 ConstParent parent;104 ConstParent parent;
101};105};
102106
107struct ConstUnionValue {
108 ConstExprValue *value;
109 ConstParent parent;
110};
111
103enum ConstArraySpecial {112enum ConstArraySpecial {
104 ConstArraySpecialNone,113 ConstArraySpecialNone,
105 ConstArraySpecialUndef,114 ConstArraySpecialUndef,
...@@ -238,6 +247,7 @@ struct ConstExprValue {...@@ -238,6 +247,7 @@ struct ConstExprValue {
238 ErrorTableEntry *x_pure_err;247 ErrorTableEntry *x_pure_err;
239 ConstEnumValue x_enum;248 ConstEnumValue x_enum;
240 ConstStructValue x_struct;249 ConstStructValue x_struct;
250 ConstUnionValue x_union;
241 ConstArrayValue x_array;251 ConstArrayValue x_array;
242 ConstPtrValue x_ptr;252 ConstPtrValue x_ptr;
243 ImportTableEntry *x_import;253 ImportTableEntry *x_import;
...@@ -336,6 +346,12 @@ struct TypeEnumField {...@@ -336,6 +346,12 @@ struct TypeEnumField {
336 uint32_t gen_index;346 uint32_t gen_index;
337};347};
338348
349struct TypeUnionField {
350 Buf *name;
351 TypeTableEntry *type_entry;
352 uint32_t gen_index;
353};
354
339enum NodeType {355enum NodeType {
340 NodeTypeRoot,356 NodeTypeRoot,
341 NodeTypeFnProto,357 NodeTypeFnProto,
...@@ -1026,9 +1042,9 @@ struct TypeTableEntryUnion {...@@ -1026,9 +1042,9 @@ struct TypeTableEntryUnion {
1026 ContainerLayout layout;1042 ContainerLayout layout;
1027 uint32_t src_field_count;1043 uint32_t src_field_count;
1028 uint32_t gen_field_count;1044 uint32_t gen_field_count;
1029 TypeStructField *fields;1045 TypeUnionField *fields;
1030 uint64_t size_bytes;
1031 bool is_invalid; // true if any fields are invalid1046 bool is_invalid; // true if any fields are invalid
1047
1032 ScopeDecls *decls_scope;1048 ScopeDecls *decls_scope;
10331049
1034 // set this flag temporarily to detect infinite loops1050 // set this flag temporarily to detect infinite loops
...@@ -1039,6 +1055,10 @@ struct TypeTableEntryUnion {...@@ -1039,6 +1055,10 @@ struct TypeTableEntryUnion {
10391055
1040 bool zero_bits_loop_flag;1056 bool zero_bits_loop_flag;
1041 bool zero_bits_known;1057 bool zero_bits_known;
1058 uint32_t abi_alignment; // also figured out with zero_bits pass
1059
1060 uint32_t size_bytes;
1061 TypeTableEntry *most_aligned_union_member;
1042};1062};
10431063
1044struct FnGenParamInfo {1064struct FnGenParamInfo {
...@@ -1796,6 +1816,7 @@ enum IrInstructionId {...@@ -1796,6 +1816,7 @@ enum IrInstructionId {
1796 IrInstructionIdFieldPtr,1816 IrInstructionIdFieldPtr,
1797 IrInstructionIdStructFieldPtr,1817 IrInstructionIdStructFieldPtr,
1798 IrInstructionIdEnumFieldPtr,1818 IrInstructionIdEnumFieldPtr,
1819 IrInstructionIdUnionFieldPtr,
1799 IrInstructionIdElemPtr,1820 IrInstructionIdElemPtr,
1800 IrInstructionIdVarPtr,1821 IrInstructionIdVarPtr,
1801 IrInstructionIdCall,1822 IrInstructionIdCall,
...@@ -1805,6 +1826,7 @@ enum IrInstructionId {...@@ -1805,6 +1826,7 @@ enum IrInstructionId {
1805 IrInstructionIdContainerInitList,1826 IrInstructionIdContainerInitList,
1806 IrInstructionIdContainerInitFields,1827 IrInstructionIdContainerInitFields,
1807 IrInstructionIdStructInit,1828 IrInstructionIdStructInit,
1829 IrInstructionIdUnionInit,
1808 IrInstructionIdUnreachable,1830 IrInstructionIdUnreachable,
1809 IrInstructionIdTypeOf,1831 IrInstructionIdTypeOf,
1810 IrInstructionIdToPtrType,1832 IrInstructionIdToPtrType,
...@@ -2060,6 +2082,14 @@ struct IrInstructionEnumFieldPtr {...@@ -2060,6 +2082,14 @@ struct IrInstructionEnumFieldPtr {
2060 bool is_const;2082 bool is_const;
2061};2083};
20622084
2085struct IrInstructionUnionFieldPtr {
2086 IrInstruction base;
2087
2088 IrInstruction *union_ptr;
2089 TypeUnionField *field;
2090 bool is_const;
2091};
2092
2063struct IrInstructionElemPtr {2093struct IrInstructionElemPtr {
2064 IrInstruction base;2094 IrInstruction base;
20652095
...@@ -2150,6 +2180,15 @@ struct IrInstructionStructInit {...@@ -2150,6 +2180,15 @@ struct IrInstructionStructInit {
2150 LLVMValueRef tmp_ptr;2180 LLVMValueRef tmp_ptr;
2151};2181};
21522182
2183struct IrInstructionUnionInit {
2184 IrInstruction base;
2185
2186 TypeTableEntry *union_type;
2187 TypeUnionField *field;
2188 IrInstruction *init_value;
2189 LLVMValueRef tmp_ptr;
2190};
2191
2153struct IrInstructionUnreachable {2192struct IrInstructionUnreachable {
2154 IrInstruction base;2193 IrInstruction base;
2155};2194};
src/analyze.cpp+217-6
...@@ -992,18 +992,22 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi...@@ -992,18 +992,22 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi
992 TypeTableEntryId type_id = container_to_type(kind);992 TypeTableEntryId type_id = container_to_type(kind);
993 TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope);993 TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope);
994994
995 unsigned dwarf_kind;
995 switch (kind) {996 switch (kind) {
996 case ContainerKindStruct:997 case ContainerKindStruct:
997 entry->data.structure.decl_node = decl_node;998 entry->data.structure.decl_node = decl_node;
998 entry->data.structure.layout = layout;999 entry->data.structure.layout = layout;
1000 dwarf_kind = ZigLLVMTag_DW_structure_type();
999 break;1001 break;
1000 case ContainerKindEnum:1002 case ContainerKindEnum:
1001 entry->data.enumeration.decl_node = decl_node;1003 entry->data.enumeration.decl_node = decl_node;
1002 entry->data.enumeration.layout = layout;1004 entry->data.enumeration.layout = layout;
1005 dwarf_kind = ZigLLVMTag_DW_structure_type();
1003 break;1006 break;
1004 case ContainerKindUnion:1007 case ContainerKindUnion:
1005 entry->data.unionation.decl_node = decl_node;1008 entry->data.unionation.decl_node = decl_node;
1006 entry->data.unionation.layout = layout;1009 entry->data.unionation.layout = layout;
1010 dwarf_kind = ZigLLVMTag_DW_union_type();
1007 break;1011 break;
1008 }1012 }
10091013
...@@ -1012,7 +1016,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi...@@ -1012,7 +1016,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi
1012 ImportTableEntry *import = get_scope_import(scope);1016 ImportTableEntry *import = get_scope_import(scope);
1013 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name);1017 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name);
1014 entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,1018 entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
1015 ZigLLVMTag_DW_structure_type(), name,1019 dwarf_kind, name,
1016 ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1));1020 ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1));
10171021
1018 buf_init_from_str(&entry->name, name);1022 buf_init_from_str(&entry->name, name);
...@@ -1285,7 +1289,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1285,7 +1289,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
1285 return;1289 return;
12861290
1287 resolve_enum_zero_bits(g, enum_type);1291 resolve_enum_zero_bits(g, enum_type);
1288 if (enum_type->data.enumeration.is_invalid)1292 if (type_is_invalid(enum_type))
1289 return;1293 return;
12901294
1291 AstNode *decl_node = enum_type->data.enumeration.decl_node;1295 AstNode *decl_node = enum_type->data.enumeration.decl_node;
...@@ -1834,7 +1838,140 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {...@@ -1834,7 +1838,140 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
1834}1838}
18351839
1836static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {1840static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1837 zig_panic("TODO");1841 assert(union_type->id == TypeTableEntryIdUnion);
1842
1843 if (union_type->data.unionation.complete)
1844 return;
1845
1846 resolve_union_zero_bits(g, union_type);
1847 if (type_is_invalid(union_type))
1848 return;
1849
1850 AstNode *decl_node = union_type->data.unionation.decl_node;
1851
1852 if (union_type->data.unionation.embedded_in_current) {
1853 if (!union_type->data.unionation.reported_infinite_err) {
1854 union_type->data.unionation.reported_infinite_err = true;
1855 add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name)));
1856 }
1857 return;
1858 }
1859
1860 assert(!union_type->data.unionation.zero_bits_loop_flag);
1861 assert(decl_node->type == NodeTypeContainerDecl);
1862 assert(union_type->di_type);
1863
1864 uint32_t field_count = union_type->data.unionation.src_field_count;
1865
1866 assert(union_type->data.unionation.fields);
1867
1868 uint32_t gen_field_count = union_type->data.unionation.gen_field_count;
1869 ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count);
1870
1871 TypeTableEntry *most_aligned_union_member = nullptr;
1872 uint64_t size_of_most_aligned_member_in_bits = 0;
1873 uint64_t biggest_align_in_bits = 0;
1874 uint64_t biggest_size_in_bits = 0;
1875
1876 Scope *scope = &union_type->data.unionation.decls_scope->base;
1877 ImportTableEntry *import = get_scope_import(scope);
1878
1879 // set temporary flag
1880 union_type->data.unionation.embedded_in_current = true;
1881
1882 for (uint32_t i = 0; i < field_count; i += 1) {
1883 AstNode *field_node = decl_node->data.container_decl.fields.at(i);
1884 TypeUnionField *type_union_field = &union_type->data.unionation.fields[i];
1885 TypeTableEntry *field_type = type_union_field->type_entry;
1886
1887 ensure_complete_type(g, field_type);
1888 if (type_is_invalid(field_type)) {
1889 union_type->data.unionation.is_invalid = true;
1890 continue;
1891 }
1892
1893 if (!type_has_bits(field_type))
1894 continue;
1895
1896 uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
1897 uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
1898
1899 assert(store_size_in_bits > 0);
1900 assert(abi_align_in_bits > 0);
1901
1902 union_inner_di_types[type_union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
1903 ZigLLVMTypeToScope(union_type->di_type), buf_ptr(type_union_field->name),
1904 import->di_file, (unsigned)(field_node->line + 1),
1905 store_size_in_bits,
1906 abi_align_in_bits,
1907 0,
1908 0, field_type->di_type);
1909
1910 biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits);
1911
1912 if (!most_aligned_union_member || abi_align_in_bits > biggest_align_in_bits) {
1913 most_aligned_union_member = field_type;
1914 biggest_align_in_bits = abi_align_in_bits;
1915 size_of_most_aligned_member_in_bits = store_size_in_bits;
1916 }
1917 }
1918
1919 // unset temporary flag
1920 union_type->data.unionation.embedded_in_current = false;
1921 union_type->data.unionation.complete = true;
1922 union_type->data.unionation.size_bytes = biggest_size_in_bits / 8;
1923 union_type->data.unionation.most_aligned_union_member = most_aligned_union_member;
1924
1925 if (union_type->data.unionation.is_invalid)
1926 return;
1927
1928 if (union_type->zero_bits) {
1929 union_type->type_ref = LLVMVoidType();
1930
1931 uint64_t debug_size_in_bits = 0;
1932 uint64_t debug_align_in_bits = 0;
1933 ZigLLVMDIType **di_root_members = nullptr;
1934 size_t debug_member_count = 0;
1935 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
1936 ZigLLVMFileToScope(import->di_file),
1937 buf_ptr(&union_type->name),
1938 import->di_file, (unsigned)(decl_node->line + 1),
1939 debug_size_in_bits,
1940 debug_align_in_bits,
1941 0, di_root_members, (int)debug_member_count, 0, "");
1942
1943 ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);
1944 union_type->di_type = replacement_di_type;
1945 return;
1946 }
1947
1948 assert(most_aligned_union_member != nullptr);
1949
1950 // create llvm type for union
1951 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
1952 if (padding_in_bits > 0) {
1953 TypeTableEntry *u8_type = get_int_type(g, false, 8);
1954 TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
1955 LLVMTypeRef union_element_types[] = {
1956 most_aligned_union_member->type_ref,
1957 padding_array->type_ref,
1958 };
1959 LLVMStructSetBody(union_type->type_ref, union_element_types, 2, false);
1960 } else {
1961 LLVMStructSetBody(union_type->type_ref, &most_aligned_union_member->type_ref, 1, false);
1962 }
1963
1964 assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type->type_ref) >= biggest_align_in_bits);
1965 assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref) >= biggest_size_in_bits);
1966
1967 // create debug type for union
1968 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
1969 ZigLLVMFileToScope(import->di_file), buf_ptr(&union_type->name),
1970 import->di_file, (unsigned)(decl_node->line + 1),
1971 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
1972 gen_field_count, 0, "");
1973 ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);
1974 union_type->di_type = replacement_di_type;
1838}1975}
18391976
1840static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {1977static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
...@@ -1873,7 +2010,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1873,7 +2010,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
1873 type_enum_field->value = i;2010 type_enum_field->value = i;
18742011
1875 type_ensure_zero_bits_known(g, field_type);2012 type_ensure_zero_bits_known(g, field_type);
1876 if (field_type->id == TypeTableEntryIdInvalid) {2013 if (type_is_invalid(field_type)) {
1877 enum_type->data.enumeration.is_invalid = true;2014 enum_type->data.enumeration.is_invalid = true;
1878 continue;2015 continue;
1879 }2016 }
...@@ -1980,7 +2117,66 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {...@@ -1980,7 +2117,66 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
1980}2117}
19812118
1982static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {2119static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
1983 zig_panic("TODO resolve_union_zero_bits");2120 assert(union_type->id == TypeTableEntryIdUnion);
2121
2122 if (union_type->data.unionation.zero_bits_known)
2123 return;
2124
2125 if (union_type->data.unionation.zero_bits_loop_flag) {
2126 union_type->data.unionation.zero_bits_known = true;
2127 return;
2128 }
2129
2130 union_type->data.unionation.zero_bits_loop_flag = true;
2131
2132 AstNode *decl_node = union_type->data.unionation.decl_node;
2133 assert(decl_node->type == NodeTypeContainerDecl);
2134 assert(union_type->di_type);
2135
2136 assert(!union_type->data.unionation.fields);
2137 uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
2138 union_type->data.unionation.src_field_count = field_count;
2139 union_type->data.unionation.fields = allocate<TypeUnionField>(field_count);
2140
2141 uint32_t biggest_align_bytes = 0;
2142
2143 Scope *scope = &union_type->data.unionation.decls_scope->base;
2144
2145 uint32_t gen_field_index = 0;
2146 for (uint32_t i = 0; i < field_count; i += 1) {
2147 AstNode *field_node = decl_node->data.container_decl.fields.at(i);
2148 TypeUnionField *type_union_field = &union_type->data.unionation.fields[i];
2149 type_union_field->name = field_node->data.struct_field.name;
2150 TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
2151 type_union_field->type_entry = field_type;
2152
2153 type_ensure_zero_bits_known(g, field_type);
2154 if (type_is_invalid(field_type)) {
2155 union_type->data.unionation.is_invalid = true;
2156 continue;
2157 }
2158
2159 if (!type_has_bits(field_type))
2160 continue;
2161
2162 type_union_field->gen_index = gen_field_index;
2163 gen_field_index += 1;
2164
2165 uint32_t field_align_bytes = get_abi_alignment(g, field_type);
2166 if (field_align_bytes > biggest_align_bytes) {
2167 biggest_align_bytes = field_align_bytes;
2168 }
2169 }
2170
2171 union_type->data.unionation.zero_bits_loop_flag = false;
2172 union_type->data.unionation.gen_field_count = gen_field_index;
2173 union_type->zero_bits = (gen_field_index == 0);
2174 union_type->data.unionation.zero_bits_known = true;
2175
2176 // also compute abi_alignment
2177 if (!union_type->zero_bits) {
2178 union_type->data.unionation.abi_alignment = biggest_align_bytes;
2179 }
1984}2180}
19852181
1986static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {2182static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {
...@@ -2851,6 +3047,18 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {...@@ -2851,6 +3047,18 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {
2851 return nullptr;3047 return nullptr;
2852}3048}
28533049
3050TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
3051 assert(type_entry->id == TypeTableEntryIdUnion);
3052 assert(type_entry->data.unionation.complete);
3053 for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
3054 TypeUnionField *field = &type_entry->data.unionation.fields[i];
3055 if (buf_eql_buf(field->name, name)) {
3056 return field;
3057 }
3058 }
3059 return nullptr;
3060}
3061
2854static bool is_container(TypeTableEntry *type_entry) {3062static bool is_container(TypeTableEntry *type_entry) {
2855 switch (type_entry->id) {3063 switch (type_entry->id) {
2856 case TypeTableEntryIdInvalid:3064 case TypeTableEntryIdInvalid:
...@@ -4703,6 +4911,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) {...@@ -4703,6 +4911,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) {
4703 return &value->data.x_array.s_none.parent;4911 return &value->data.x_array.s_none.parent;
4704 } else if (type_entry->id == TypeTableEntryIdStruct) {4912 } else if (type_entry->id == TypeTableEntryIdStruct) {
4705 return &value->data.x_struct.parent;4913 return &value->data.x_struct.parent;
4914 } else if (type_entry->id == TypeTableEntryIdUnion) {
4915 return &value->data.x_union.parent;
4706 }4916 }
4707 return nullptr;4917 return nullptr;
4708}4918}
...@@ -4914,7 +5124,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {...@@ -4914,7 +5124,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
4914 assert(type_entry->data.enumeration.abi_alignment != 0);5124 assert(type_entry->data.enumeration.abi_alignment != 0);
4915 return type_entry->data.enumeration.abi_alignment;5125 return type_entry->data.enumeration.abi_alignment;
4916 } else if (type_entry->id == TypeTableEntryIdUnion) {5126 } else if (type_entry->id == TypeTableEntryIdUnion) {
4917 zig_panic("TODO");5127 assert(type_entry->data.unionation.abi_alignment != 0);
5128 return type_entry->data.unionation.abi_alignment;
4918 } else if (type_entry->id == TypeTableEntryIdOpaque) {5129 } else if (type_entry->id == TypeTableEntryIdOpaque) {
4919 return 1;5130 return 1;
4920 } else {5131 } else {
src/analyze.hpp+1
...@@ -63,6 +63,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry);...@@ -63,6 +63,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry);
63TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);63TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
64ScopeDecls *get_container_scope(TypeTableEntry *type_entry);64ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
65TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);65TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
66TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
66bool is_container_ref(TypeTableEntry *type_entry);67bool is_container_ref(TypeTableEntry *type_entry);
67void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);68void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
68void scan_import(CodeGen *g, ImportTableEntry *import);69void scan_import(CodeGen *g, ImportTableEntry *import);
src/codegen.cpp+97-4
...@@ -2393,6 +2393,27 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl...@@ -2393,6 +2393,27 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl
2393 return bitcasted_union_field_ptr;2393 return bitcasted_union_field_ptr;
2394}2394}
23952395
2396static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable,
2397 IrInstructionUnionFieldPtr *instruction)
2398{
2399 TypeTableEntry *union_ptr_type = instruction->union_ptr->value.type;
2400 assert(union_ptr_type->id == TypeTableEntryIdPointer);
2401 TypeTableEntry *union_type = union_ptr_type->data.pointer.child_type;
2402 assert(union_type->id == TypeTableEntryIdUnion);
2403
2404 TypeUnionField *field = instruction->field;
2405
2406 if (!type_has_bits(field->type_entry))
2407 return nullptr;
2408
2409 LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr);
2410 LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
2411 LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, 0, "");
2412 LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
2413
2414 return bitcasted_union_field_ptr;
2415}
2416
2396static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {2417static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
2397 const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;2418 const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;
2398 size_t len = tok->end - tok->start - 2;2419 size_t len = tok->end - tok->start - 2;
...@@ -3365,6 +3386,25 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,...@@ -3365,6 +3386,25 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
3365 return instruction->tmp_ptr;3386 return instruction->tmp_ptr;
3366}3387}
33673388
3389static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) {
3390 TypeUnionField *type_union_field = instruction->field;
3391
3392 assert(type_has_bits(type_union_field->type_entry));
3393
3394 LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, "");
3395 LLVMValueRef value = ir_llvm_value(g, instruction->init_value);
3396
3397 uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry);
3398
3399 TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry,
3400 false, false, field_align_bytes,
3401 0, 0);
3402
3403 gen_assign_raw(g, field_ptr, ptr_type, value);
3404
3405 return instruction->tmp_ptr;
3406}
3407
3368static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable,3408static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable,
3369 IrInstructionContainerInitList *instruction)3409 IrInstructionContainerInitList *instruction)
3370{3410{
...@@ -3486,6 +3526,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -3486,6 +3526,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
3486 return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);3526 return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
3487 case IrInstructionIdEnumFieldPtr:3527 case IrInstructionIdEnumFieldPtr:
3488 return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);3528 return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);
3529 case IrInstructionIdUnionFieldPtr:
3530 return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction);
3489 case IrInstructionIdAsm:3531 case IrInstructionIdAsm:
3490 return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);3532 return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
3491 case IrInstructionIdTestNonNull:3533 case IrInstructionIdTestNonNull:
...@@ -3544,6 +3586,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -3544,6 +3586,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
3544 return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);3586 return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
3545 case IrInstructionIdStructInit:3587 case IrInstructionIdStructInit:
3546 return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);3588 return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
3589 case IrInstructionIdUnionInit:
3590 return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction);
3547 case IrInstructionIdPtrCast:3591 case IrInstructionIdPtrCast:
3548 return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction);3592 return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction);
3549 case IrInstructionIdBitCast:3593 case IrInstructionIdBitCast:
...@@ -3595,6 +3639,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {...@@ -3595,6 +3639,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
35953639
3596static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);3640static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
3597static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);3641static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
3642static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val);
35983643
3599static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {3644static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
3600 switch (parent->id) {3645 switch (parent->id) {
...@@ -3608,6 +3653,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent...@@ -3608,6 +3653,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
3608 case ConstParentIdArray:3653 case ConstParentIdArray:
3609 return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val,3654 return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val,
3610 parent->data.p_array.elem_index);3655 parent->data.p_array.elem_index);
3656 case ConstParentIdUnion:
3657 return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val);
3611 }3658 }
3612 zig_unreachable();3659 zig_unreachable();
3613}3660}
...@@ -3637,6 +3684,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s...@@ -3637,6 +3684,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s
3637 return LLVMConstInBoundsGEP(base_ptr, indices, 2);3684 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
3638}3685}
36393686
3687static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) {
3688 ConstParent *parent = &union_const_val->data.x_union.parent;
3689 LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent);
3690
3691 TypeTableEntry *u32 = g->builtin_types.entry_u32;
3692 LLVMValueRef indices[] = {
3693 LLVMConstNull(u32->type_ref),
3694 LLVMConstInt(u32->type_ref, 0, false),
3695 };
3696 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
3697}
3698
3640static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) {3699static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) {
3641 switch (const_val->special) {3700 switch (const_val->special) {
3642 case ConstValSpecialRuntime:3701 case ConstValSpecialRuntime:
...@@ -3872,10 +3931,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -3872,10 +3931,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
3872 return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count);3931 return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count);
3873 }3932 }
3874 }3933 }
3875 case TypeTableEntryIdUnion:
3876 {
3877 zig_panic("TODO");
3878 }
3879 case TypeTableEntryIdArray:3934 case TypeTableEntryIdArray:
3880 {3935 {
3881 uint64_t len = type_entry->data.array.len;3936 uint64_t len = type_entry->data.array.len;
...@@ -3898,6 +3953,41 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -3898,6 +3953,41 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
3898 return LLVMConstArray(element_type_ref, values, (unsigned)len);3953 return LLVMConstArray(element_type_ref, values, (unsigned)len);
3899 }3954 }
3900 }3955 }
3956 case TypeTableEntryIdUnion:
3957 {
3958 LLVMTypeRef union_type_ref = type_entry->type_ref;
3959 ConstExprValue *payload_value = const_val->data.x_union.value;
3960 assert(payload_value != nullptr);
3961
3962 if (!type_has_bits(payload_value->type)) {
3963 return LLVMGetUndef(union_type_ref);
3964 }
3965
3966 uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
3967 uint64_t pad_bytes = type_entry->data.unionation.size_bytes - field_type_bytes;
3968
3969 LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
3970
3971 bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
3972 payload_value->type != type_entry->data.unionation.most_aligned_union_member;
3973
3974 unsigned field_count;
3975 LLVMValueRef fields[2];
3976 fields[0] = correctly_typed_value;
3977 if (pad_bytes == 0) {
3978 field_count = 1;
3979 } else {
3980 fields[0] = correctly_typed_value;
3981 fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes));
3982 field_count = 2;
3983 }
3984
3985 if (make_unnamed_struct) {
3986 return LLVMConstStruct(fields, field_count, false);
3987 } else {
3988 return LLVMConstNamedStruct(type_entry->type_ref, fields, field_count);
3989 }
3990 }
3901 case TypeTableEntryIdEnum:3991 case TypeTableEntryIdEnum:
3902 {3992 {
3903 LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;3993 LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
...@@ -4376,6 +4466,9 @@ static void do_code_gen(CodeGen *g) {...@@ -4376,6 +4466,9 @@ static void do_code_gen(CodeGen *g) {
4376 } else if (instruction->id == IrInstructionIdStructInit) {4466 } else if (instruction->id == IrInstructionIdStructInit) {
4377 IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction;4467 IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction;
4378 slot = &struct_init_instruction->tmp_ptr;4468 slot = &struct_init_instruction->tmp_ptr;
4469 } else if (instruction->id == IrInstructionIdUnionInit) {
4470 IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction;
4471 slot = &union_init_instruction->tmp_ptr;
4379 } else if (instruction->id == IrInstructionIdCall) {4472 } else if (instruction->id == IrInstructionIdCall) {
4380 IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;4473 IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
4381 slot = &call_instruction->tmp_ptr;4474 slot = &call_instruction->tmp_ptr;
src/ir.cpp+160-11
...@@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *)...@@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *)
227 return IrInstructionIdEnumFieldPtr;227 return IrInstructionIdEnumFieldPtr;
228}228}
229229
230static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) {
231 return IrInstructionIdUnionFieldPtr;
232}
233
230static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) {234static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) {
231 return IrInstructionIdElemPtr;235 return IrInstructionIdElemPtr;
232}236}
...@@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) {...@@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) {
351 return IrInstructionIdStructInit;355 return IrInstructionIdStructInit;
352}356}
353357
358static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) {
359 return IrInstructionIdUnionInit;
360}
361
354static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) {362static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) {
355 return IrInstructionIdMinValue;363 return IrInstructionIdMinValue;
356}364}
...@@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction...@@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction
922 return new_instruction;930 return new_instruction;
923}931}
924932
933static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
934 IrInstruction *union_ptr, TypeUnionField *field)
935{
936 IrInstructionUnionFieldPtr *instruction = ir_build_instruction<IrInstructionUnionFieldPtr>(irb, scope, source_node);
937 instruction->union_ptr = union_ptr;
938 instruction->field = field;
939
940 ir_ref_instruction(union_ptr, irb->current_basic_block);
941
942 return &instruction->base;
943}
944
945static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
946 IrInstruction *union_ptr, TypeUnionField *type_union_field)
947{
948 IrInstruction *new_instruction = ir_build_union_field_ptr(irb, old_instruction->scope,
949 old_instruction->source_node, union_ptr, type_union_field);
950 ir_link_new_instruction(new_instruction, old_instruction);
951 return new_instruction;
952}
953
925static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,954static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
926 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,955 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
927 bool is_comptime, bool is_inline)956 bool is_comptime, bool is_inline)
...@@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o...@@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o
1112 return new_instruction;1141 return new_instruction;
1113}1142}
11141143
1144static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
1145 TypeTableEntry *union_type, TypeUnionField *field, IrInstruction *init_value)
1146{
1147 IrInstructionUnionInit *union_init_instruction = ir_build_instruction<IrInstructionUnionInit>(irb, scope, source_node);
1148 union_init_instruction->union_type = union_type;
1149 union_init_instruction->field = field;
1150 union_init_instruction->init_value = init_value;
1151
1152 ir_ref_instruction(init_value, irb->current_basic_block);
1153
1154 return &union_init_instruction->base;
1155}
1156
1157static IrInstruction *ir_build_union_init_from(IrBuilder *irb, IrInstruction *old_instruction,
1158 TypeTableEntry *union_type, TypeUnionField *field, IrInstruction *init_value)
1159{
1160 IrInstruction *new_instruction = ir_build_union_init(irb, old_instruction->scope,
1161 old_instruction->source_node, union_type, field, init_value);
1162 ir_link_new_instruction(new_instruction, old_instruction);
1163 return new_instruction;
1164}
1165
1115static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) {1166static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) {
1116 IrInstructionUnreachable *unreachable_instruction =1167 IrInstructionUnreachable *unreachable_instruction =
1117 ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node);1168 ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node);
...@@ -2422,6 +2473,13 @@ static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumField...@@ -2422,6 +2473,13 @@ static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumField
2422 }2473 }
2423}2474}
24242475
2476static IrInstruction *ir_instruction_unionfieldptr_get_dep(IrInstructionUnionFieldPtr *instruction, size_t index) {
2477 switch (index) {
2478 case 0: return instruction->union_ptr;
2479 default: return nullptr;
2480 }
2481}
2482
2425static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) {2483static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) {
2426 switch (index) {2484 switch (index) {
2427 case 0: return instruction->array_ptr;2485 case 0: return instruction->array_ptr;
...@@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit...@@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit
2485 return nullptr;2543 return nullptr;
2486}2544}
24872545
2546static IrInstruction *ir_instruction_unioninit_get_dep(IrInstructionUnionInit *instruction, size_t index) {
2547 switch (index) {
2548 case 0: return instruction->init_value;
2549 default: return nullptr;
2550 }
2551}
2552
2488static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) {2553static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) {
2489 return nullptr;2554 return nullptr;
2490}2555}
...@@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t...@@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
3099 return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index);3164 return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index);
3100 case IrInstructionIdEnumFieldPtr:3165 case IrInstructionIdEnumFieldPtr:
3101 return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index);3166 return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index);
3167 case IrInstructionIdUnionFieldPtr:
3168 return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index);
3102 case IrInstructionIdElemPtr:3169 case IrInstructionIdElemPtr:
3103 return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index);3170 return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index);
3104 case IrInstructionIdVarPtr:3171 case IrInstructionIdVarPtr:
...@@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t...@@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
3117 return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index);3184 return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index);
3118 case IrInstructionIdStructInit:3185 case IrInstructionIdStructInit:
3119 return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index);3186 return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index);
3187 case IrInstructionIdUnionInit:
3188 return ir_instruction_unioninit_get_dep((IrInstructionUnionInit *) instruction, index);
3120 case IrInstructionIdUnreachable:3189 case IrInstructionIdUnreachable:
3121 return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index);3190 return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index);
3122 case IrInstructionIdTypeOf:3191 case IrInstructionIdTypeOf:
...@@ -11417,8 +11486,20 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,...@@ -11417,8 +11486,20 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,
11417 return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false);11486 return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false);
11418 }11487 }
11419 }11488 }
11489 const char *prefix_name;
11490 if (is_slice(bare_struct_type)) {
11491 prefix_name = "";
11492 } else if (bare_struct_type->id == TypeTableEntryIdStruct) {
11493 prefix_name = "struct ";
11494 } else if (bare_struct_type->id == TypeTableEntryIdEnum) {
11495 prefix_name = "enum ";
11496 } else if (bare_struct_type->id == TypeTableEntryIdUnion) {
11497 prefix_name = "union ";
11498 } else {
11499 prefix_name = "";
11500 }
11420 ir_add_error_node(ira, field_ptr_instruction->base.source_node,11501 ir_add_error_node(ira, field_ptr_instruction->base.source_node,
11421 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));11502 buf_sprintf("no member named '%s' in %s'%s'", buf_ptr(field_name), prefix_name, buf_ptr(&bare_struct_type->name)));
11422 return ira->codegen->builtin_types.entry_invalid;11503 return ira->codegen->builtin_types.entry_invalid;
11423}11504}
1142411505
...@@ -11428,14 +11509,13 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field...@@ -11428,14 +11509,13 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
11428{11509{
11429 TypeTableEntry *bare_type = container_ref_type(container_type);11510 TypeTableEntry *bare_type = container_ref_type(container_type);
11430 ensure_complete_type(ira->codegen, bare_type);11511 ensure_complete_type(ira->codegen, bare_type);
11512 if (type_is_invalid(bare_type))
11513 return ira->codegen->builtin_types.entry_invalid;
1143111514
11432 assert(container_ptr->value.type->id == TypeTableEntryIdPointer);11515 assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
11433 bool is_const = container_ptr->value.type->data.pointer.is_const;11516 bool is_const = container_ptr->value.type->data.pointer.is_const;
11434 bool is_volatile = container_ptr->value.type->data.pointer.is_volatile;11517 bool is_volatile = container_ptr->value.type->data.pointer.is_volatile;
11435 if (bare_type->id == TypeTableEntryIdStruct) {11518 if (bare_type->id == TypeTableEntryIdStruct) {
11436 if (bare_type->data.structure.is_invalid)
11437 return ira->codegen->builtin_types.entry_invalid;
11438
11439 TypeStructField *field = find_struct_type_field(bare_type, field_name);11519 TypeStructField *field = find_struct_type_field(bare_type, field_name);
11440 if (field) {11520 if (field) {
11441 bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked);11521 bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked);
...@@ -11476,9 +11556,6 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field...@@ -11476,9 +11556,6 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
11476 field_ptr_instruction, container_ptr, container_type);11556 field_ptr_instruction, container_ptr, container_type);
11477 }11557 }
11478 } else if (bare_type->id == TypeTableEntryIdEnum) {11558 } else if (bare_type->id == TypeTableEntryIdEnum) {
11479 if (bare_type->data.enumeration.is_invalid)
11480 return ira->codegen->builtin_types.entry_invalid;
11481
11482 TypeEnumField *field = find_enum_type_field(bare_type, field_name);11559 TypeEnumField *field = find_enum_type_field(bare_type, field_name);
11483 if (field) {11560 if (field) {
11484 ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);11561 ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
...@@ -11489,7 +11566,15 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field...@@ -11489,7 +11566,15 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
11489 field_ptr_instruction, container_ptr, container_type);11566 field_ptr_instruction, container_ptr, container_type);
11490 }11567 }
11491 } else if (bare_type->id == TypeTableEntryIdUnion) {11568 } else if (bare_type->id == TypeTableEntryIdUnion) {
11492 zig_panic("TODO");11569 TypeUnionField *field = find_union_type_field(bare_type, field_name);
11570 if (field) {
11571 ir_build_union_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
11572 return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
11573 get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
11574 } else {
11575 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
11576 field_ptr_instruction, container_ptr, container_type);
11577 }
11493 } else {11578 } else {
11494 zig_unreachable();11579 zig_unreachable();
11495 }11580 }
...@@ -13033,9 +13118,70 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR...@@ -13033,9 +13118,70 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR
13033 return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile);13118 return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile);
13034}13119}
1303513120
13121static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction,
13122 TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)
13123{
13124 assert(container_type->id == TypeTableEntryIdUnion);
13125
13126 ensure_complete_type(ira->codegen, container_type);
13127
13128 if (instr_field_count != 1) {
13129 ir_add_error(ira, instruction,
13130 buf_sprintf("union initialization expects exactly one field"));
13131 return ira->codegen->builtin_types.entry_invalid;
13132 }
13133
13134 IrInstructionContainerInitFieldsField *field = &fields[0];
13135 IrInstruction *field_value = field->value->other;
13136 if (type_is_invalid(field_value->value.type))
13137 return ira->codegen->builtin_types.entry_invalid;
13138
13139 TypeUnionField *type_field = find_union_type_field(container_type, field->name);
13140 if (!type_field) {
13141 ir_add_error_node(ira, field->source_node,
13142 buf_sprintf("no member named '%s' in union '%s'",
13143 buf_ptr(field->name), buf_ptr(&container_type->name)));
13144 return ira->codegen->builtin_types.entry_invalid;
13145 }
13146
13147 if (type_is_invalid(type_field->type_entry))
13148 return ira->codegen->builtin_types.entry_invalid;
13149
13150 IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry);
13151 if (casted_field_value == ira->codegen->invalid_instruction)
13152 return ira->codegen->builtin_types.entry_invalid;
13153
13154 bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
13155 if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) {
13156 ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
13157 if (!field_val)
13158 return ira->codegen->builtin_types.entry_invalid;
13159
13160 ConstExprValue *out_val = ir_build_const_from(ira, instruction);
13161 out_val->data.x_union.value = field_val;
13162
13163 ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
13164 if (parent != nullptr) {
13165 parent->id = ConstParentIdUnion;
13166 parent->data.p_union.union_val = out_val;
13167 }
13168
13169 return container_type;
13170 }
13171
13172 IrInstruction *new_instruction = ir_build_union_init_from(&ira->new_irb, instruction,
13173 container_type, type_field, casted_field_value);
13174
13175 ir_add_alloca(ira, new_instruction, container_type);
13176 return container_type;
13177}
13178
13036static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction,13179static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction,
13037 TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)13180 TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)
13038{13181{
13182 if (container_type->id == TypeTableEntryIdUnion) {
13183 return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields);
13184 }
13039 if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) {13185 if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) {
13040 ir_add_error(ira, instruction,13186 ir_add_error(ira, instruction,
13041 buf_sprintf("type '%s' does not support struct initialization syntax",13187 buf_sprintf("type '%s' does not support struct initialization syntax",
...@@ -13043,8 +13189,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru...@@ -13043,8 +13189,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
13043 return ira->codegen->builtin_types.entry_invalid;13189 return ira->codegen->builtin_types.entry_invalid;
13044 }13190 }
1304513191
13046 if (!type_is_complete(container_type))13192 ensure_complete_type(ira->codegen, container_type);
13047 resolve_container_type(ira->codegen, container_type);
1304813193
13049 size_t actual_field_count = container_type->data.structure.src_field_count;13194 size_t actual_field_count = container_type->data.structure.src_field_count;
1305013195
...@@ -13070,7 +13215,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru...@@ -13070,7 +13215,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
13070 TypeStructField *type_field = find_struct_type_field(container_type, field->name);13215 TypeStructField *type_field = find_struct_type_field(container_type, field->name);
13071 if (!type_field) {13216 if (!type_field) {
13072 ir_add_error_node(ira, field->source_node,13217 ir_add_error_node(ira, field->source_node,
13073 buf_sprintf("no member named '%s' in '%s'",13218 buf_sprintf("no member named '%s' in struct '%s'",
13074 buf_ptr(field->name), buf_ptr(&container_type->name)));13219 buf_ptr(field->name), buf_ptr(&container_type->name)));
13075 return ira->codegen->builtin_types.entry_invalid;13220 return ira->codegen->builtin_types.entry_invalid;
13076 }13221 }
...@@ -15657,8 +15802,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -15657,8 +15802,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
15657 case IrInstructionIdIntToErr:15802 case IrInstructionIdIntToErr:
15658 case IrInstructionIdErrToInt:15803 case IrInstructionIdErrToInt:
15659 case IrInstructionIdStructInit:15804 case IrInstructionIdStructInit:
15805 case IrInstructionIdUnionInit:
15660 case IrInstructionIdStructFieldPtr:15806 case IrInstructionIdStructFieldPtr:
15661 case IrInstructionIdEnumFieldPtr:15807 case IrInstructionIdEnumFieldPtr:
15808 case IrInstructionIdUnionFieldPtr:
15662 case IrInstructionIdInitEnum:15809 case IrInstructionIdInitEnum:
15663 case IrInstructionIdMaybeWrap:15810 case IrInstructionIdMaybeWrap:
15664 case IrInstructionIdErrWrapCode:15811 case IrInstructionIdErrWrapCode:
...@@ -15968,6 +16115,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -15968,6 +16115,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
15968 case IrInstructionIdContainerInitList:16115 case IrInstructionIdContainerInitList:
15969 case IrInstructionIdContainerInitFields:16116 case IrInstructionIdContainerInitFields:
15970 case IrInstructionIdStructInit:16117 case IrInstructionIdStructInit:
16118 case IrInstructionIdUnionInit:
15971 case IrInstructionIdFieldPtr:16119 case IrInstructionIdFieldPtr:
15972 case IrInstructionIdElemPtr:16120 case IrInstructionIdElemPtr:
15973 case IrInstructionIdVarPtr:16121 case IrInstructionIdVarPtr:
...@@ -15977,6 +16125,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -15977,6 +16125,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
15977 case IrInstructionIdArrayLen:16125 case IrInstructionIdArrayLen:
15978 case IrInstructionIdStructFieldPtr:16126 case IrInstructionIdStructFieldPtr:
15979 case IrInstructionIdEnumFieldPtr:16127 case IrInstructionIdEnumFieldPtr:
16128 case IrInstructionIdUnionFieldPtr:
15980 case IrInstructionIdArrayType:16129 case IrInstructionIdArrayType:
15981 case IrInstructionIdSliceType:16130 case IrInstructionIdSliceType:
15982 case IrInstructionIdSizeOf:16131 case IrInstructionIdSizeOf:
src/ir_print.cpp+22
...@@ -290,6 +290,15 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct...@@ -290,6 +290,15 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct
290 fprintf(irp->f, "} // struct init");290 fprintf(irp->f, "} // struct init");
291}291}
292292
293static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) {
294 Buf *field_name = instruction->field->name;
295
296 fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name));
297 fprintf(irp->f, ".%s = ", buf_ptr(field_name));
298 ir_print_other_instruction(irp, instruction->init_value);
299 fprintf(irp->f, "} // union init");
300}
301
293static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {302static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {
294 fprintf(irp->f, "unreachable");303 fprintf(irp->f, "unreachable");
295}304}
...@@ -359,6 +368,13 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins...@@ -359,6 +368,13 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins
359 fprintf(irp->f, ")");368 fprintf(irp->f, ")");
360}369}
361370
371static void ir_print_union_field_ptr(IrPrint *irp, IrInstructionUnionFieldPtr *instruction) {
372 fprintf(irp->f, "@UnionFieldPtr(&");
373 ir_print_other_instruction(irp, instruction->union_ptr);
374 fprintf(irp->f, ".%s", buf_ptr(instruction->field->name));
375 fprintf(irp->f, ")");
376}
377
362static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) {378static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) {
363 fprintf(irp->f, "@setDebugSafety(");379 fprintf(irp->f, "@setDebugSafety(");
364 ir_print_other_instruction(irp, instruction->scope_value);380 ir_print_other_instruction(irp, instruction->scope_value);
...@@ -1023,6 +1039,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1023,6 +1039,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1023 case IrInstructionIdStructInit:1039 case IrInstructionIdStructInit:
1024 ir_print_struct_init(irp, (IrInstructionStructInit *)instruction);1040 ir_print_struct_init(irp, (IrInstructionStructInit *)instruction);
1025 break;1041 break;
1042 case IrInstructionIdUnionInit:
1043 ir_print_union_init(irp, (IrInstructionUnionInit *)instruction);
1044 break;
1026 case IrInstructionIdUnreachable:1045 case IrInstructionIdUnreachable:
1027 ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction);1046 ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction);
1028 break;1047 break;
...@@ -1056,6 +1075,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1056,6 +1075,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1056 case IrInstructionIdEnumFieldPtr:1075 case IrInstructionIdEnumFieldPtr:
1057 ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction);1076 ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction);
1058 break;1077 break;
1078 case IrInstructionIdUnionFieldPtr:
1079 ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction);
1080 break;
1059 case IrInstructionIdSetDebugSafety:1081 case IrInstructionIdSetDebugSafety:
1060 ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction);1082 ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction);
1061 break;1083 break;
src/zig_llvm.cpp+4
...@@ -403,6 +403,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) {...@@ -403,6 +403,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) {
403 return dwarf::DW_TAG_structure_type;403 return dwarf::DW_TAG_structure_type;
404}404}
405405
406unsigned ZigLLVMTag_DW_union_type(void) {
407 return dwarf::DW_TAG_union_type;
408}
409
406ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) {410ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) {
407 DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved);411 DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved);
408 return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder);412 return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder);
src/zig_llvm.hpp+1
...@@ -117,6 +117,7 @@ unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);...@@ -117,6 +117,7 @@ unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);
117unsigned ZigLLVMLang_DW_LANG_C99(void);117unsigned ZigLLVMLang_DW_LANG_C99(void);
118unsigned ZigLLVMTag_DW_variable(void);118unsigned ZigLLVMTag_DW_variable(void);
119unsigned ZigLLVMTag_DW_structure_type(void);119unsigned ZigLLVMTag_DW_structure_type(void);
120unsigned ZigLLVMTag_DW_union_type(void);
120121
121ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);122ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
122void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);123void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
test/cases/union.zig+13
...@@ -31,3 +31,16 @@ test "unions embedded in aggregate types" {...@@ -31,3 +31,16 @@ test "unions embedded in aggregate types" {
31 else => unreachable,31 else => unreachable,
32 }32 }
33}33}
34
35
36const Foo = union {
37 float: f64,
38 int: i32,
39};
40
41test "basic unions" {
42 var foo = Foo { .int = 1 };
43 assert(foo.int == 1);
44 foo.float = 12.34;
45 assert(foo.float == 12.34);
46}
test/compile_errors.zig+3-3
...@@ -389,8 +389,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -389,8 +389,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
389 \\ const y = a.bar;389 \\ const y = a.bar;
390 \\}390 \\}
391 ,391 ,
392 ".tmp_source.zig:4:6: error: no member named 'foo' in 'A'",392 ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'",
393 ".tmp_source.zig:5:16: error: no member named 'bar' in 'A'");393 ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'");
394394
395 cases.add("redefinition of struct",395 cases.add("redefinition of struct",
396 \\const A = struct { x : i32, };396 \\const A = struct { x : i32, };
...@@ -454,7 +454,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -454,7 +454,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
454 \\ .foo = 42,454 \\ .foo = 42,
455 \\ };455 \\ };
456 \\}456 \\}
457 , ".tmp_source.zig:10:9: error: no member named 'foo' in 'A'");457 , ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'");
458458
459 cases.add("invalid break expression",459 cases.add("invalid break expression",
460 \\export fn f() {460 \\export fn f() {