Skip to content

Commit 634e871

Browse files
committed
add @memberType and @memberName builtin functions
see #383 there is a plan to unify most of the reflection into 2 builtin functions, as outlined in the above issue, but this gives us needed features for now, and we can iterate on the design in future commits
1 parent f0dafd3 commit 634e871

File tree

8 files changed

+440
-111
lines changed

8 files changed

+440
-111
lines changed

src-self-hosted/main.zig

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const heap = @import("std").mem;
55

66
// TODO: sync up CLI with c++ code
77
// TODO: concurrency
8-
// TODO: ability to iterate over enums at compile time (for listing targets)
98

109
error InvalidArgument;
1110
error MissingArg0;

src/all_types.hpp

+18
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,8 @@ enum BuiltinFnId {
12111211
BuiltinFnIdMaxValue,
12121212
BuiltinFnIdMinValue,
12131213
BuiltinFnIdMemberCount,
1214+
BuiltinFnIdMemberType,
1215+
BuiltinFnIdMemberName,
12141216
BuiltinFnIdTypeof,
12151217
BuiltinFnIdAddWithOverflow,
12161218
BuiltinFnIdSubWithOverflow,
@@ -1845,6 +1847,8 @@ enum IrInstructionId {
18451847
IrInstructionIdMemcpy,
18461848
IrInstructionIdSlice,
18471849
IrInstructionIdMemberCount,
1850+
IrInstructionIdMemberType,
1851+
IrInstructionIdMemberName,
18481852
IrInstructionIdBreakpoint,
18491853
IrInstructionIdReturnAddress,
18501854
IrInstructionIdFrameAddress,
@@ -2408,6 +2412,20 @@ struct IrInstructionMemberCount {
24082412
IrInstruction *container;
24092413
};
24102414

2415+
struct IrInstructionMemberType {
2416+
IrInstruction base;
2417+
2418+
IrInstruction *container_type;
2419+
IrInstruction *member_index;
2420+
};
2421+
2422+
struct IrInstructionMemberName {
2423+
IrInstruction base;
2424+
2425+
IrInstruction *container_type;
2426+
IrInstruction *member_index;
2427+
};
2428+
24112429
struct IrInstructionBreakpoint {
24122430
IrInstruction base;
24132431
};

src/analyze.cpp

+133-110
Original file line numberDiff line numberDiff line change
@@ -1366,119 +1366,140 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
13661366
enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8;
13671367
enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member;
13681368

1369-
if (!enum_type->data.enumeration.is_invalid) {
1370-
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1371-
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
1372-
enum_type->data.enumeration.tag_type = tag_type_entry;
1373-
1374-
uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1375-
1376-
if (most_aligned_union_member) {
1377-
// create llvm type for union
1378-
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
1379-
LLVMTypeRef union_type_ref;
1380-
if (padding_in_bits > 0) {
1381-
TypeTableEntry *u8_type = get_int_type(g, false, 8);
1382-
TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
1383-
LLVMTypeRef union_element_types[] = {
1384-
most_aligned_union_member->type_ref,
1385-
padding_array->type_ref,
1386-
};
1387-
union_type_ref = LLVMStructType(union_element_types, 2, false);
1388-
} else {
1389-
union_type_ref = most_aligned_union_member->type_ref;
1390-
}
1391-
enum_type->data.enumeration.union_type_ref = union_type_ref;
1369+
if (enum_type->data.enumeration.is_invalid)
1370+
return;
13921371

1393-
assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
1394-
assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
1372+
if (enum_type->zero_bits) {
1373+
enum_type->type_ref = LLVMVoidType();
13951374

1396-
if (align_of_tag_in_bits >= biggest_align_in_bits) {
1397-
enum_type->data.enumeration.gen_tag_index = 0;
1398-
enum_type->data.enumeration.gen_union_index = 1;
1399-
} else {
1400-
enum_type->data.enumeration.gen_union_index = 0;
1401-
enum_type->data.enumeration.gen_tag_index = 1;
1402-
}
1375+
uint64_t debug_size_in_bits = 0;
1376+
uint64_t debug_align_in_bits = 0;
1377+
ZigLLVMDIType **di_root_members = nullptr;
1378+
size_t debug_member_count = 0;
1379+
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
1380+
ZigLLVMFileToScope(import->di_file),
1381+
buf_ptr(&enum_type->name),
1382+
import->di_file, (unsigned)(decl_node->line + 1),
1383+
debug_size_in_bits,
1384+
debug_align_in_bits,
1385+
0, nullptr, di_root_members, (int)debug_member_count, 0, nullptr, "");
14031386

1404-
// create llvm type for root struct
1405-
LLVMTypeRef root_struct_element_types[2];
1406-
root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
1407-
root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
1408-
LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
1409-
1410-
// create debug type for tag
1411-
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1412-
uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
1413-
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
1414-
ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
1415-
import->di_file, (unsigned)(decl_node->line + 1),
1416-
tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
1417-
tag_type_entry->di_type, "");
1418-
1419-
// create debug type for union
1420-
ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
1421-
ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
1422-
import->di_file, (unsigned)(decl_node->line + 1),
1423-
biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
1424-
gen_field_count, 0, "");
1425-
1426-
// create debug types for members of root struct
1427-
uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
1428-
enum_type->data.enumeration.gen_tag_index);
1429-
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
1430-
ZigLLVMTypeToScope(enum_type->di_type), "tag_field",
1431-
import->di_file, (unsigned)(decl_node->line + 1),
1432-
tag_debug_size_in_bits,
1433-
tag_debug_align_in_bits,
1434-
tag_offset_in_bits,
1435-
0, tag_di_type);
1436-
1437-
uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
1438-
enum_type->data.enumeration.gen_union_index);
1439-
ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
1440-
ZigLLVMTypeToScope(enum_type->di_type), "union_field",
1441-
import->di_file, (unsigned)(decl_node->line + 1),
1442-
biggest_size_in_bits,
1443-
biggest_align_in_bits,
1444-
union_offset_in_bits,
1445-
0, union_di_type);
1446-
1447-
// create debug type for root struct
1448-
ZigLLVMDIType *di_root_members[2];
1449-
di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
1450-
di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
1451-
1452-
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
1453-
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
1454-
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
1455-
ZigLLVMFileToScope(import->di_file),
1456-
buf_ptr(&enum_type->name),
1457-
import->di_file, (unsigned)(decl_node->line + 1),
1458-
debug_size_in_bits,
1459-
debug_align_in_bits,
1460-
0, nullptr, di_root_members, 2, 0, nullptr, "");
1461-
1462-
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
1463-
enum_type->di_type = replacement_di_type;
1387+
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
1388+
enum_type->di_type = replacement_di_type;
1389+
return;
1390+
}
1391+
1392+
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1393+
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
1394+
enum_type->data.enumeration.tag_type = tag_type_entry;
1395+
1396+
uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1397+
1398+
if (most_aligned_union_member) {
1399+
// create llvm type for union
1400+
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
1401+
LLVMTypeRef union_type_ref;
1402+
if (padding_in_bits > 0) {
1403+
TypeTableEntry *u8_type = get_int_type(g, false, 8);
1404+
TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
1405+
LLVMTypeRef union_element_types[] = {
1406+
most_aligned_union_member->type_ref,
1407+
padding_array->type_ref,
1408+
};
1409+
union_type_ref = LLVMStructType(union_element_types, 2, false);
14641410
} else {
1465-
// create llvm type for root struct
1466-
enum_type->type_ref = tag_type_entry->type_ref;
1467-
1468-
// create debug type for tag
1469-
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1470-
uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
1471-
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
1472-
ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
1473-
import->di_file, (unsigned)(decl_node->line + 1),
1474-
tag_debug_size_in_bits,
1475-
tag_debug_align_in_bits,
1476-
di_enumerators, field_count,
1477-
tag_type_entry->di_type, "");
1411+
union_type_ref = most_aligned_union_member->type_ref;
1412+
}
1413+
enum_type->data.enumeration.union_type_ref = union_type_ref;
14781414

1479-
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
1480-
enum_type->di_type = tag_di_type;
1415+
assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
1416+
assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
1417+
1418+
if (align_of_tag_in_bits >= biggest_align_in_bits) {
1419+
enum_type->data.enumeration.gen_tag_index = 0;
1420+
enum_type->data.enumeration.gen_union_index = 1;
1421+
} else {
1422+
enum_type->data.enumeration.gen_union_index = 0;
1423+
enum_type->data.enumeration.gen_tag_index = 1;
14811424
}
1425+
1426+
// create llvm type for root struct
1427+
LLVMTypeRef root_struct_element_types[2];
1428+
root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
1429+
root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
1430+
LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
1431+
1432+
// create debug type for tag
1433+
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1434+
uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
1435+
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
1436+
ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
1437+
import->di_file, (unsigned)(decl_node->line + 1),
1438+
tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
1439+
tag_type_entry->di_type, "");
1440+
1441+
// create debug type for union
1442+
ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
1443+
ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
1444+
import->di_file, (unsigned)(decl_node->line + 1),
1445+
biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
1446+
gen_field_count, 0, "");
1447+
1448+
// create debug types for members of root struct
1449+
uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
1450+
enum_type->data.enumeration.gen_tag_index);
1451+
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
1452+
ZigLLVMTypeToScope(enum_type->di_type), "tag_field",
1453+
import->di_file, (unsigned)(decl_node->line + 1),
1454+
tag_debug_size_in_bits,
1455+
tag_debug_align_in_bits,
1456+
tag_offset_in_bits,
1457+
0, tag_di_type);
1458+
1459+
uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
1460+
enum_type->data.enumeration.gen_union_index);
1461+
ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
1462+
ZigLLVMTypeToScope(enum_type->di_type), "union_field",
1463+
import->di_file, (unsigned)(decl_node->line + 1),
1464+
biggest_size_in_bits,
1465+
biggest_align_in_bits,
1466+
union_offset_in_bits,
1467+
0, union_di_type);
1468+
1469+
// create debug type for root struct
1470+
ZigLLVMDIType *di_root_members[2];
1471+
di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
1472+
di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
1473+
1474+
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
1475+
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
1476+
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
1477+
ZigLLVMFileToScope(import->di_file),
1478+
buf_ptr(&enum_type->name),
1479+
import->di_file, (unsigned)(decl_node->line + 1),
1480+
debug_size_in_bits,
1481+
debug_align_in_bits,
1482+
0, nullptr, di_root_members, 2, 0, nullptr, "");
1483+
1484+
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
1485+
enum_type->di_type = replacement_di_type;
1486+
} else {
1487+
// create llvm type for root struct
1488+
enum_type->type_ref = tag_type_entry->type_ref;
1489+
1490+
// create debug type for tag
1491+
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1492+
uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
1493+
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
1494+
ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
1495+
import->di_file, (unsigned)(decl_node->line + 1),
1496+
tag_debug_size_in_bits,
1497+
tag_debug_align_in_bits,
1498+
di_enumerators, field_count,
1499+
tag_type_entry->di_type, "");
1500+
1501+
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
1502+
enum_type->di_type = tag_di_type;
14821503
}
14831504
}
14841505

@@ -1875,9 +1896,11 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
18751896
enum_type->data.enumeration.zero_bits_known = true;
18761897

18771898
// also compute abi_alignment
1878-
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1879-
uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1880-
enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
1899+
if (!enum_type->zero_bits) {
1900+
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1901+
uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1902+
enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
1903+
}
18811904
}
18821905

18831906
static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {

src/codegen.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -3384,6 +3384,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
33843384
case IrInstructionIdEmbedFile:
33853385
case IrInstructionIdIntType:
33863386
case IrInstructionIdMemberCount:
3387+
case IrInstructionIdMemberType:
3388+
case IrInstructionIdMemberName:
33873389
case IrInstructionIdAlignOf:
33883390
case IrInstructionIdFnProto:
33893391
case IrInstructionIdTestComptime:
@@ -4867,6 +4869,8 @@ static void define_builtin_fns(CodeGen *g) {
48674869
create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1);
48684870
create_builtin_fn(g, BuiltinFnIdMinValue, "minValue", 1);
48694871
create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);
4872+
create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
4873+
create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
48704874
create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
48714875
create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
48724876
create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);

0 commit comments

Comments
 (0)