commit 3a600297ca3f99ee57630c44900eec1fe7c92804 (tree)
parent 4a82c2d124881512548254f5cdff3009b2f424df
Author: Andrew Kelley <superjoe30@gmail.com>
Date: Mon, 6 Nov 2017 22:41:12 -0500
Merge remote-tracking branch 'origin/master' into llvm6
Diffstat:
19 files changed, 794 insertions(+), 150 deletions(-)
diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig
@@ -3,24 +3,27 @@ const io = @import("std").io;
const os = @import("std").os;
const heap = @import("std").mem;
-// TODO: OutSteam and InStream interface
-// TODO: move allocator to heap namespace
// TODO: sync up CLI with c++ code
+// TODO: concurrency
error InvalidArgument;
error MissingArg0;
var arg0: []u8 = undefined;
+var stderr_file: io.File = undefined;
+const stderr = &stderr_file.out_stream;
+
pub fn main() -> %void {
+ stderr_file = %return io.getStdErr();
if (internal_main()) |_| {
return;
} else |err| {
if (err == error.InvalidArgument) {
- io.stderr.printf("\n") %% return err;
- printUsage(&io.stderr) %% return err;
+ stderr.print("\n") %% return err;
+ printUsage(stderr) %% return err;
} else {
- io.stderr.printf("{}\n", err) %% return err;
+ stderr.print("{}\n", err) %% return err;
}
return err;
}
@@ -266,7 +269,6 @@ fn printUsage(outstream: &io.OutStream) -> %void {
\\ --test-cmd-bin appends test binary path to test cmd args
\\
);
- %return outstream.flush();
}
const ZIG_ZEN =
diff --git a/src/all_types.hpp b/src/all_types.hpp
@@ -1211,6 +1211,8 @@ enum BuiltinFnId {
BuiltinFnIdMaxValue,
BuiltinFnIdMinValue,
BuiltinFnIdMemberCount,
+ BuiltinFnIdMemberType,
+ BuiltinFnIdMemberName,
BuiltinFnIdTypeof,
BuiltinFnIdAddWithOverflow,
BuiltinFnIdSubWithOverflow,
@@ -1261,6 +1263,7 @@ enum BuiltinFnId {
BuiltinFnIdAlignCast,
BuiltinFnIdOpaqueType,
BuiltinFnIdSetAlignStack,
+ BuiltinFnIdArgType,
};
struct BuiltinFnEntry {
@@ -1366,6 +1369,12 @@ enum BuildMode {
BuildModeSafeRelease,
};
+enum EmitFileType {
+ EmitFileTypeBinary,
+ EmitFileTypeAssembly,
+ EmitFileTypeLLVMIr,
+};
+
struct LinkLib {
Buf *name;
Buf *path;
@@ -1449,6 +1458,7 @@ struct CodeGen {
TypeTableEntry *entry_arg_tuple;
} builtin_types;
+ EmitFileType emit_file_type;
ZigTarget zig_target;
LLVMTargetDataRef target_data_ref;
unsigned pointer_size_bytes;
@@ -1837,6 +1847,8 @@ enum IrInstructionId {
IrInstructionIdMemcpy,
IrInstructionIdSlice,
IrInstructionIdMemberCount,
+ IrInstructionIdMemberType,
+ IrInstructionIdMemberName,
IrInstructionIdBreakpoint,
IrInstructionIdReturnAddress,
IrInstructionIdFrameAddress,
@@ -1875,6 +1887,7 @@ enum IrInstructionId {
IrInstructionIdAlignCast,
IrInstructionIdOpaqueType,
IrInstructionIdSetAlignStack,
+ IrInstructionIdArgType,
};
struct IrInstruction {
@@ -2399,6 +2412,20 @@ struct IrInstructionMemberCount {
IrInstruction *container;
};
+struct IrInstructionMemberType {
+ IrInstruction base;
+
+ IrInstruction *container_type;
+ IrInstruction *member_index;
+};
+
+struct IrInstructionMemberName {
+ IrInstruction base;
+
+ IrInstruction *container_type;
+ IrInstruction *member_index;
+};
+
struct IrInstructionBreakpoint {
IrInstruction base;
};
@@ -2675,6 +2702,13 @@ struct IrInstructionSetAlignStack {
IrInstruction *align_bytes;
};
+struct IrInstructionArgType {
+ IrInstruction base;
+
+ IrInstruction *fn_type;
+ IrInstruction *arg_index;
+};
+
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;
diff --git a/src/analyze.cpp b/src/analyze.cpp
@@ -1366,119 +1366,140 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8;
enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member;
- if (!enum_type->data.enumeration.is_invalid) {
- TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
- TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
- enum_type->data.enumeration.tag_type = tag_type_entry;
-
- uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
-
- if (most_aligned_union_member) {
- // create llvm type for union
- uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
- LLVMTypeRef union_type_ref;
- if (padding_in_bits > 0) {
- TypeTableEntry *u8_type = get_int_type(g, false, 8);
- TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
- LLVMTypeRef union_element_types[] = {
- most_aligned_union_member->type_ref,
- padding_array->type_ref,
- };
- union_type_ref = LLVMStructType(union_element_types, 2, false);
- } else {
- union_type_ref = most_aligned_union_member->type_ref;
- }
- enum_type->data.enumeration.union_type_ref = union_type_ref;
+ if (enum_type->data.enumeration.is_invalid)
+ return;
- assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
- assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
+ if (enum_type->zero_bits) {
+ enum_type->type_ref = LLVMVoidType();
- if (align_of_tag_in_bits >= biggest_align_in_bits) {
- enum_type->data.enumeration.gen_tag_index = 0;
- enum_type->data.enumeration.gen_union_index = 1;
- } else {
- enum_type->data.enumeration.gen_union_index = 0;
- enum_type->data.enumeration.gen_tag_index = 1;
- }
+ uint64_t debug_size_in_bits = 0;
+ uint64_t debug_align_in_bits = 0;
+ ZigLLVMDIType **di_root_members = nullptr;
+ size_t debug_member_count = 0;
+ ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+ ZigLLVMFileToScope(import->di_file),
+ buf_ptr(&enum_type->name),
+ import->di_file, (unsigned)(decl_node->line + 1),
+ debug_size_in_bits,
+ debug_align_in_bits,
+ 0, nullptr, di_root_members, (int)debug_member_count, 0, nullptr, "");
- // create llvm type for root struct
- LLVMTypeRef root_struct_element_types[2];
- root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
- root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
- LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
-
- // create debug type for tag
- uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
- uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
- ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
- ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
- import->di_file, (unsigned)(decl_node->line + 1),
- tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
- tag_type_entry->di_type, "");
-
- // create debug type for union
- ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
- ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
- import->di_file, (unsigned)(decl_node->line + 1),
- biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
- gen_field_count, 0, "");
-
- // create debug types for members of root struct
- uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
- enum_type->data.enumeration.gen_tag_index);
- ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
- ZigLLVMTypeToScope(enum_type->di_type), "tag_field",
- import->di_file, (unsigned)(decl_node->line + 1),
- tag_debug_size_in_bits,
- tag_debug_align_in_bits,
- tag_offset_in_bits,
- 0, tag_di_type);
-
- uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
- enum_type->data.enumeration.gen_union_index);
- ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
- ZigLLVMTypeToScope(enum_type->di_type), "union_field",
- import->di_file, (unsigned)(decl_node->line + 1),
- biggest_size_in_bits,
- biggest_align_in_bits,
- union_offset_in_bits,
- 0, union_di_type);
-
- // create debug type for root struct
- ZigLLVMDIType *di_root_members[2];
- di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
- di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
-
- uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
- uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
- ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file),
- buf_ptr(&enum_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
- debug_size_in_bits,
- debug_align_in_bits,
- 0, nullptr, di_root_members, 2, 0, nullptr, "");
-
- ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
- enum_type->di_type = replacement_di_type;
+ ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
+ enum_type->di_type = replacement_di_type;
+ return;
+ }
+
+ TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
+ TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
+ enum_type->data.enumeration.tag_type = tag_type_entry;
+
+ uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
+
+ if (most_aligned_union_member) {
+ // create llvm type for union
+ uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
+ LLVMTypeRef union_type_ref;
+ if (padding_in_bits > 0) {
+ TypeTableEntry *u8_type = get_int_type(g, false, 8);
+ TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
+ LLVMTypeRef union_element_types[] = {
+ most_aligned_union_member->type_ref,
+ padding_array->type_ref,
+ };
+ union_type_ref = LLVMStructType(union_element_types, 2, false);
} else {
- // create llvm type for root struct
- enum_type->type_ref = tag_type_entry->type_ref;
-
- // create debug type for tag
- uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
- uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
- ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
- tag_debug_size_in_bits,
- tag_debug_align_in_bits,
- di_enumerators, field_count,
- tag_type_entry->di_type, "");
+ union_type_ref = most_aligned_union_member->type_ref;
+ }
+ enum_type->data.enumeration.union_type_ref = union_type_ref;
+
+ assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
+ assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
- ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
- enum_type->di_type = tag_di_type;
+ if (align_of_tag_in_bits >= biggest_align_in_bits) {
+ enum_type->data.enumeration.gen_tag_index = 0;
+ enum_type->data.enumeration.gen_union_index = 1;
+ } else {
+ enum_type->data.enumeration.gen_union_index = 0;
+ enum_type->data.enumeration.gen_tag_index = 1;
}
+
+ // create llvm type for root struct
+ LLVMTypeRef root_struct_element_types[2];
+ root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
+ root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
+ LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
+
+ // create debug type for tag
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
+ ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+ ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
+ import->di_file, (unsigned)(decl_node->line + 1),
+ tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
+ tag_type_entry->di_type, "");
+
+ // create debug type for union
+ ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
+ ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
+ import->di_file, (unsigned)(decl_node->line + 1),
+ biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
+ gen_field_count, 0, "");
+
+ // create debug types for members of root struct
+ uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
+ enum_type->data.enumeration.gen_tag_index);
+ ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
+ ZigLLVMTypeToScope(enum_type->di_type), "tag_field",
+ import->di_file, (unsigned)(decl_node->line + 1),
+ tag_debug_size_in_bits,
+ tag_debug_align_in_bits,
+ tag_offset_in_bits,
+ 0, tag_di_type);
+
+ uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
+ enum_type->data.enumeration.gen_union_index);
+ ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
+ ZigLLVMTypeToScope(enum_type->di_type), "union_field",
+ import->di_file, (unsigned)(decl_node->line + 1),
+ biggest_size_in_bits,
+ biggest_align_in_bits,
+ union_offset_in_bits,
+ 0, union_di_type);
+
+ // create debug type for root struct
+ ZigLLVMDIType *di_root_members[2];
+ di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
+ di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
+
+ uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
+ uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
+ ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+ ZigLLVMFileToScope(import->di_file),
+ buf_ptr(&enum_type->name),
+ import->di_file, (unsigned)(decl_node->line + 1),
+ debug_size_in_bits,
+ debug_align_in_bits,
+ 0, nullptr, di_root_members, 2, 0, nullptr, "");
+
+ ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
+ enum_type->di_type = replacement_di_type;
+ } else {
+ // create llvm type for root struct
+ enum_type->type_ref = tag_type_entry->type_ref;
+
+ // create debug type for tag
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
+ ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+ ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
+ import->di_file, (unsigned)(decl_node->line + 1),
+ tag_debug_size_in_bits,
+ tag_debug_align_in_bits,
+ di_enumerators, field_count,
+ tag_type_entry->di_type, "");
+
+ ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
+ enum_type->di_type = tag_di_type;
}
}
@@ -1875,9 +1896,11 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
enum_type->data.enumeration.zero_bits_known = true;
// also compute abi_alignment
- TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
- uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
- enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
+ if (!enum_type->zero_bits) {
+ TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
+ uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
+ enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
+ }
}
static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
@@ -3440,8 +3463,14 @@ void find_libc_lib_path(CodeGen *g) {
zig_panic("Unable to determine libc lib path.");
}
}
+
if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) {
- zig_panic("Unable to determine libc static lib path.");
+ if ((g->zig_target.os == ZigLLVM_Win32) && (g->msvc_lib_dir != NULL)) {
+ return;
+ }
+ else {
+ zig_panic("Unable to determine libc static lib path.");
+ }
}
}
diff --git a/src/c_tokenizer.cpp b/src/c_tokenizer.cpp
@@ -91,6 +91,9 @@
IDENT_START: \
case DIGIT
+#define LINE_ENDING \
+ '\r': \
+ case '\n'
static void begin_token(CTokenize *ctok, CTokId id) {
assert(ctok->cur_tok == nullptr);
@@ -191,7 +194,7 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
case '\\':
ctok->state = CTokStateBackslash;
break;
- case '\n':
+ case LINE_ENDING:
goto found_end_of_macro;
case IDENT_START:
ctok->state = CTokStateIdentifier;
diff --git a/src/codegen.cpp b/src/codegen.cpp
@@ -189,6 +189,10 @@ void codegen_set_is_test(CodeGen *g, bool is_test_build) {
g->is_test_build = is_test_build;
}
+void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type) {
+ g->emit_file_type = emit_file_type;
+}
+
void codegen_set_is_static(CodeGen *g, bool is_static) {
g->is_static = is_static;
}
@@ -3380,6 +3384,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdEmbedFile:
case IrInstructionIdIntType:
case IrInstructionIdMemberCount:
+ case IrInstructionIdMemberType:
+ case IrInstructionIdMemberName:
case IrInstructionIdAlignOf:
case IrInstructionIdFnProto:
case IrInstructionIdTestComptime:
@@ -3397,6 +3403,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdPtrTypeOf:
case IrInstructionIdOpaqueType:
case IrInstructionIdSetAlignStack:
+ case IrInstructionIdArgType:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -4493,24 +4500,70 @@ static void do_code_gen(CodeGen *g) {
LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
#endif
- codegen_add_time_event(g, "LLVM Emit Object");
+ codegen_add_time_event(g, "LLVM Emit Output");
char *err_msg = nullptr;
Buf *o_basename = buf_create_from_buf(g->root_out_name);
- const char *o_ext = target_o_file_ext(&g->zig_target);
- buf_append_str(o_basename, o_ext);
+
+ switch (g->emit_file_type) {
+ case EmitFileTypeBinary:
+ {
+ const char *o_ext = target_o_file_ext(&g->zig_target);
+ buf_append_str(o_basename, o_ext);
+ break;
+ }
+ case EmitFileTypeAssembly:
+ {
+ const char *asm_ext = target_asm_file_ext(&g->zig_target);
+ buf_append_str(o_basename, asm_ext);
+ break;
+ }
+ case EmitFileTypeLLVMIr:
+ {
+ const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target);
+ buf_append_str(o_basename, llvm_ir_ext);
+ break;
+ }
+ default:
+ zig_unreachable();
+ }
+
Buf *output_path = buf_alloc();
os_path_join(g->cache_dir, o_basename, output_path);
ensure_cache_dir(g);
- if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
- LLVMObjectFile, &err_msg, g->build_mode == BuildModeDebug))
- {
- zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
- }
- validate_inline_fns(g);
+ switch (g->emit_file_type) {
+ case EmitFileTypeBinary:
+ if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
+ ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug))
+ {
+ zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
+ }
+ validate_inline_fns(g);
+ g->link_objects.append(output_path);
+ break;
+
+ case EmitFileTypeAssembly:
+ if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
+ ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug))
+ {
+ zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
+ }
+ validate_inline_fns(g);
+ break;
+
+ case EmitFileTypeLLVMIr:
+ if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
+ ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug))
+ {
+ zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
+ }
+ validate_inline_fns(g);
+ break;
- g->link_objects.append(output_path);
+ default:
+ zig_unreachable();
+ }
}
static const uint8_t int_sizes_in_bits[] = {
@@ -4816,7 +4869,9 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1);
create_builtin_fn(g, BuiltinFnIdMinValue, "minValue", 1);
create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);
- create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1);
+ create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
+ create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
+ create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
create_builtin_fn(g, BuiltinFnIdMulWithOverflow, "mulWithOverflow", 4);
@@ -4863,6 +4918,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);
create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0);
create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
+ create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
}
static const char *bool_to_str(bool b) {
diff --git a/src/codegen.hpp b/src/codegen.hpp
@@ -23,6 +23,7 @@ void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
void codegen_set_is_test(CodeGen *codegen, bool is_test);
void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath);
+void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type);
void codegen_set_is_static(CodeGen *codegen, bool is_static);
void codegen_set_strip(CodeGen *codegen, bool strip);
void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
diff --git a/src/ir.cpp b/src/ir.cpp
@@ -411,6 +411,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) {
return IrInstructionIdMemberCount;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberType *) {
+ return IrInstructionIdMemberType;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberName *) {
+ return IrInstructionIdMemberName;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionBreakpoint *) {
return IrInstructionIdBreakpoint;
}
@@ -567,6 +575,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetAlignStack *)
return IrInstructionIdSetAlignStack;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) {
+ return IrInstructionIdArgType;
+}
+
template<typename T>
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -1779,6 +1791,32 @@ static IrInstruction *ir_build_member_count(IrBuilder *irb, Scope *scope, AstNod
return &instruction->base;
}
+static IrInstruction *ir_build_member_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *container_type, IrInstruction *member_index)
+{
+ IrInstructionMemberType *instruction = ir_build_instruction<IrInstructionMemberType>(irb, scope, source_node);
+ instruction->container_type = container_type;
+ instruction->member_index = member_index;
+
+ ir_ref_instruction(container_type, irb->current_basic_block);
+ ir_ref_instruction(member_index, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_member_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *container_type, IrInstruction *member_index)
+{
+ IrInstructionMemberName *instruction = ir_build_instruction<IrInstructionMemberName>(irb, scope, source_node);
+ instruction->container_type = container_type;
+ instruction->member_index = member_index;
+
+ ir_ref_instruction(container_type, irb->current_basic_block);
+ ir_ref_instruction(member_index, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_breakpoint(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionBreakpoint *instruction = ir_build_instruction<IrInstructionBreakpoint>(irb, scope, source_node);
return &instruction->base;
@@ -2263,6 +2301,19 @@ static IrInstruction *ir_build_set_align_stack(IrBuilder *irb, Scope *scope, Ast
return &instruction->base;
}
+static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *fn_type, IrInstruction *arg_index)
+{
+ IrInstructionArgType *instruction = ir_build_instruction<IrInstructionArgType>(irb, scope, source_node);
+ instruction->fn_type = fn_type;
+ instruction->arg_index = arg_index;
+
+ ir_ref_instruction(fn_type, irb->current_basic_block);
+ ir_ref_instruction(arg_index, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
return nullptr;
}
@@ -2710,6 +2761,22 @@ static IrInstruction *ir_instruction_membercount_get_dep(IrInstructionMemberCoun
}
}
+static IrInstruction *ir_instruction_membertype_get_dep(IrInstructionMemberType *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->container_type;
+ case 1: return instruction->member_index;
+ default: return nullptr;
+ }
+}
+
+static IrInstruction *ir_instruction_membername_get_dep(IrInstructionMemberName *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->container_type;
+ case 1: return instruction->member_index;
+ default: return nullptr;
+ }
+}
+
static IrInstruction *ir_instruction_breakpoint_get_dep(IrInstructionBreakpoint *instruction, size_t index) {
return nullptr;
}
@@ -2992,6 +3059,14 @@ static IrInstruction *ir_instruction_setalignstack_get_dep(IrInstructionSetAlign
}
}
+static IrInstruction *ir_instruction_argtype_get_dep(IrInstructionArgType *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->fn_type;
+ case 1: return instruction->arg_index;
+ default: return nullptr;
+ }
+}
+
static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -3118,6 +3193,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_slice_get_dep((IrInstructionSlice *) instruction, index);
case IrInstructionIdMemberCount:
return ir_instruction_membercount_get_dep((IrInstructionMemberCount *) instruction, index);
+ case IrInstructionIdMemberType:
+ return ir_instruction_membertype_get_dep((IrInstructionMemberType *) instruction, index);
+ case IrInstructionIdMemberName:
+ return ir_instruction_membername_get_dep((IrInstructionMemberName *) instruction, index);
case IrInstructionIdBreakpoint:
return ir_instruction_breakpoint_get_dep((IrInstructionBreakpoint *) instruction, index);
case IrInstructionIdReturnAddress:
@@ -3194,6 +3273,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index);
case IrInstructionIdSetAlignStack:
return ir_instruction_setalignstack_get_dep((IrInstructionSetAlignStack *) instruction, index);
+ case IrInstructionIdArgType:
+ return ir_instruction_argtype_get_dep((IrInstructionArgType *) instruction, index);
}
zig_unreachable();
}
@@ -4352,6 +4433,36 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_member_count(irb, scope, node, arg0_value);
}
+ case BuiltinFnIdMemberType:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
+
+
+ return ir_build_member_type(irb, scope, node, arg0_value, arg1_value);
+ }
+ case BuiltinFnIdMemberName:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
+
+
+ return ir_build_member_name(irb, scope, node, arg0_value, arg1_value);
+ }
case BuiltinFnIdBreakpoint:
return ir_build_breakpoint(irb, scope, node);
case BuiltinFnIdReturnAddress:
@@ -4629,6 +4740,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_set_align_stack(irb, scope, node, arg0_value);
}
+ case BuiltinFnIdArgType:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ if (arg0_value == irb->codegen->invalid_instruction)
+ return arg0_value;
+
+ AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ if (arg1_value == irb->codegen->invalid_instruction)
+ return arg1_value;
+
+ return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
+ }
}
zig_unreachable();
}
@@ -11643,6 +11768,62 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
buf_ptr(&child_type->name), buf_ptr(field_name)));
return ira->codegen->builtin_types.entry_invalid;
}
+ } else if (child_type->id == TypeTableEntryIdErrorUnion) {
+ if (buf_eql_str(field_name, "Child")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_type(ira->codegen, child_type->data.error.child_type),
+ ira->codegen->builtin_types.entry_type,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else {
+ ir_add_error(ira, &field_ptr_instruction->base,
+ buf_sprintf("type '%s' has no member called '%s'",
+ buf_ptr(&child_type->name), buf_ptr(field_name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ } else if (child_type->id == TypeTableEntryIdMaybe) {
+ if (buf_eql_str(field_name, "Child")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_type(ira->codegen, child_type->data.maybe.child_type),
+ ira->codegen->builtin_types.entry_type,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else {
+ ir_add_error(ira, &field_ptr_instruction->base,
+ buf_sprintf("type '%s' has no member called '%s'",
+ buf_ptr(&child_type->name), buf_ptr(field_name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ } else if (child_type->id == TypeTableEntryIdFn) {
+ if (buf_eql_str(field_name, "ReturnType")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_type(ira->codegen, child_type->data.fn.fn_type_id.return_type),
+ ira->codegen->builtin_types.entry_type,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else if (buf_eql_str(field_name, "is_var_args")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_bool(ira->codegen, child_type->data.fn.fn_type_id.is_var_args),
+ ira->codegen->builtin_types.entry_bool,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else if (buf_eql_str(field_name, "arg_count")) {
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_usize(ira->codegen, child_type->data.fn.fn_type_id.param_count),
+ ira->codegen->builtin_types.entry_usize,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ } else {
+ ir_add_error(ira, &field_ptr_instruction->base,
+ buf_sprintf("type '%s' has no member called '%s'",
+ buf_ptr(&child_type->name), buf_ptr(field_name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
} else {
ir_add_error(ira, &field_ptr_instruction->base,
buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name)));
@@ -14240,6 +14421,90 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
return ira->codegen->builtin_types.entry_num_lit_int;
}
+static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) {
+ IrInstruction *container_type_value = instruction->container_type->other;
+ TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
+ if (type_is_invalid(container_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ uint64_t member_index;
+ IrInstruction *index_value = instruction->member_index->other;
+ if (!ir_resolve_usize(ira, index_value, &member_index))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (container_type->id == TypeTableEntryIdStruct) {
+ if (member_index >= container_type->data.structure.src_field_count) {
+ ir_add_error(ira, index_value,
+ buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
+ member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeStructField *field = &container_type->data.structure.fields[member_index];
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = field->type_entry;
+ return ira->codegen->builtin_types.entry_type;
+ } else if (container_type->id == TypeTableEntryIdEnum) {
+ if (member_index >= container_type->data.enumeration.src_field_count) {
+ ir_add_error(ira, index_value,
+ buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
+ member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = field->type_entry;
+ return ira->codegen->builtin_types.entry_type;
+ } else {
+ ir_add_error(ira, container_type_value,
+ buf_sprintf("type '%s' does not support @memberType", buf_ptr(&container_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+}
+
+static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) {
+ IrInstruction *container_type_value = instruction->container_type->other;
+ TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
+ if (type_is_invalid(container_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ uint64_t member_index;
+ IrInstruction *index_value = instruction->member_index->other;
+ if (!ir_resolve_usize(ira, index_value, &member_index))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (container_type->id == TypeTableEntryIdStruct) {
+ if (member_index >= container_type->data.structure.src_field_count) {
+ ir_add_error(ira, index_value,
+ buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
+ member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeStructField *field = &container_type->data.structure.fields[member_index];
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ init_const_str_lit(ira->codegen, out_val, field->name);
+ return out_val->type;
+ } else if (container_type->id == TypeTableEntryIdEnum) {
+ if (member_index >= container_type->data.enumeration.src_field_count) {
+ ir_add_error(ira, index_value,
+ buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
+ member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ init_const_str_lit(ira->codegen, out_val, field->name);
+ return out_val->type;
+ } else {
+ ir_add_error(ira, container_type_value,
+ buf_sprintf("type '%s' does not support @memberName", buf_ptr(&container_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+}
+
static TypeTableEntry *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) {
ir_build_breakpoint_from(&ira->new_irb, &instruction->base);
return ira->codegen->builtin_types.entry_void;
@@ -15346,6 +15611,35 @@ static TypeTableEntry *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Ir
return ira->codegen->builtin_types.entry_void;
}
+static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstructionArgType *instruction) {
+ IrInstruction *fn_type_inst = instruction->fn_type->other;
+ TypeTableEntry *fn_type = ir_resolve_type(ira, fn_type_inst);
+ if (type_is_invalid(fn_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *arg_index_inst = instruction->arg_index->other;
+ uint64_t arg_index;
+ if (!ir_resolve_usize(ira, arg_index_inst, &arg_index))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (fn_type->id != TypeTableEntryIdFn) {
+ ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
+ if (arg_index >= fn_type_id->param_count) {
+ ir_add_error(ira, arg_index_inst,
+ buf_sprintf("arg index %" ZIG_PRI_u64 " out of bounds; '%s' has %" ZIG_PRI_usize " arguments",
+ arg_index, buf_ptr(&fn_type->name), fn_type_id->param_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = fn_type_id->param_info[arg_index].type;
+ return ira->codegen->builtin_types.entry_type;
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -15480,6 +15774,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction);
case IrInstructionIdMemberCount:
return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction);
+ case IrInstructionIdMemberType:
+ return ir_analyze_instruction_member_type(ira, (IrInstructionMemberType *)instruction);
+ case IrInstructionIdMemberName:
+ return ir_analyze_instruction_member_name(ira, (IrInstructionMemberName *)instruction);
case IrInstructionIdBreakpoint:
return ir_analyze_instruction_breakpoint(ira, (IrInstructionBreakpoint *)instruction);
case IrInstructionIdReturnAddress:
@@ -15536,6 +15834,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
case IrInstructionIdSetAlignStack:
return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction);
+ case IrInstructionIdArgType:
+ return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction);
}
zig_unreachable();
}
@@ -15687,6 +15987,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdBoolNot:
case IrInstructionIdSlice:
case IrInstructionIdMemberCount:
+ case IrInstructionIdMemberType:
+ case IrInstructionIdMemberName:
case IrInstructionIdAlignOf:
case IrInstructionIdReturnAddress:
case IrInstructionIdFrameAddress:
@@ -15716,6 +16018,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdTypeId:
case IrInstructionIdAlignCast:
case IrInstructionIdOpaqueType:
+ case IrInstructionIdArgType:
return false;
case IrInstructionIdAsm:
{
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
@@ -658,6 +658,22 @@ static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instru
fprintf(irp->f, ")");
}
+static void ir_print_member_type(IrPrint *irp, IrInstructionMemberType *instruction) {
+ fprintf(irp->f, "@memberType(");
+ ir_print_other_instruction(irp, instruction->container_type);
+ fprintf(irp->f, ", ");
+ ir_print_other_instruction(irp, instruction->member_index);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_member_name(IrPrint *irp, IrInstructionMemberName *instruction) {
+ fprintf(irp->f, "@memberName(");
+ ir_print_other_instruction(irp, instruction->container_type);
+ fprintf(irp->f, ", ");
+ ir_print_other_instruction(irp, instruction->member_index);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_breakpoint(IrPrint *irp, IrInstructionBreakpoint *instruction) {
fprintf(irp->f, "@breakpoint()");
}
@@ -954,6 +970,15 @@ static void ir_print_set_align_stack(IrPrint *irp, IrInstructionSetAlignStack *i
fprintf(irp->f, ")");
}
+static void ir_print_arg_type(IrPrint *irp, IrInstructionArgType *instruction) {
+ fprintf(irp->f, "@ArgType(");
+ ir_print_other_instruction(irp, instruction->fn_type);
+ fprintf(irp->f, ",");
+ ir_print_other_instruction(irp, instruction->arg_index);
+ fprintf(irp->f, ")");
+}
+
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1139,6 +1164,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdMemberCount:
ir_print_member_count(irp, (IrInstructionMemberCount *)instruction);
break;
+ case IrInstructionIdMemberType:
+ ir_print_member_type(irp, (IrInstructionMemberType *)instruction);
+ break;
+ case IrInstructionIdMemberName:
+ ir_print_member_name(irp, (IrInstructionMemberName *)instruction);
+ break;
case IrInstructionIdBreakpoint:
ir_print_breakpoint(irp, (IrInstructionBreakpoint *)instruction);
break;
@@ -1256,6 +1287,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdSetAlignStack:
ir_print_set_align_stack(irp, (IrInstructionSetAlignStack *)instruction);
break;
+ case IrInstructionIdArgType:
+ ir_print_arg_type(irp, (IrInstructionArgType *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
diff --git a/src/link.cpp b/src/link.cpp
@@ -894,7 +894,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
Buf *o_file_path = g->link_objects.at(0);
int err;
if ((err = os_rename(o_file_path, &lj.out_file))) {
- zig_panic("unable to rename object file into final output: %s", err_str(err));
+ zig_panic("unable to rename object file %s into final output %s: %s", buf_ptr(o_file_path), buf_ptr(&lj.out_file), err_str(err));
}
}
return;
diff --git a/src/main.cpp b/src/main.cpp
@@ -32,6 +32,7 @@ static int usage(const char *arg0) {
" --assembly $source add assembly file to build\n"
" --cache-dir $path override the cache directory\n"
" --color $auto|off|on enable or disable colored error messages\n"
+ " --emit $filetype emit a specific file format as compilation output\n"
" --enable-timing-info print timing diagnostics\n"
" --libc-include-dir $path directory where libc stdlib.h resides\n"
" --name $name override output name\n"
@@ -269,6 +270,7 @@ int main(int argc, char **argv) {
char *arg0 = argv[0];
Cmd cmd = CmdInvalid;
+ EmitFileType emit_file_type = EmitFileTypeBinary;
const char *in_file = nullptr;
const char *out_file = nullptr;
const char *out_file_h = nullptr;
@@ -535,6 +537,17 @@ int main(int argc, char **argv) {
fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n");
return usage(arg0);
}
+ } else if (strcmp(arg, "--emit") == 0) {
+ if (strcmp(argv[i], "asm") == 0) {
+ emit_file_type = EmitFileTypeAssembly;
+ } else if (strcmp(argv[i], "bin") == 0) {
+ emit_file_type = EmitFileTypeBinary;
+ } else if (strcmp(argv[i], "llvm-ir") == 0) {
+ emit_file_type = EmitFileTypeLLVMIr;
+ } else {
+ fprintf(stderr, "--emit options are 'asm', 'bin', or 'llvm-ir'\n");
+ return usage(arg0);
+ }
} else if (strcmp(arg, "--name") == 0) {
out_name = argv[i];
} else if (strcmp(arg, "--libc-lib-dir") == 0) {
@@ -815,6 +828,8 @@ int main(int argc, char **argv) {
add_package(g, cur_pkg, g->root_package);
if (cmd == CmdBuild) {
+ codegen_set_emit_file_type(g, emit_file_type);
+
for (size_t i = 0; i < objects.length; i += 1) {
codegen_add_object(g, buf_create_from_str(objects.at(i)));
}
diff --git a/src/target.cpp b/src/target.cpp
@@ -581,6 +581,14 @@ const char *target_o_file_ext(ZigTarget *target) {
}
}
+const char *target_asm_file_ext(ZigTarget *target) {
+ return ".s";
+}
+
+const char *target_llvm_ir_file_ext(ZigTarget *target) {
+ return ".ll";
+}
+
const char *target_exe_file_ext(ZigTarget *target) {
if (target->os == ZigLLVM_Win32) {
return ".exe";
diff --git a/src/target.hpp b/src/target.hpp
@@ -73,6 +73,8 @@ void resolve_target_object_format(ZigTarget *target);
uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id);
const char *target_o_file_ext(ZigTarget *target);
+const char *target_asm_file_ext(ZigTarget *target);
+const char *target_llvm_ir_file_ext(ZigTarget *target);
const char *target_exe_file_ext(ZigTarget *target);
Buf *target_dynamic_linker(ZigTarget *target);
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
@@ -77,7 +77,7 @@ static const bool assertions_on = false;
#endif
bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
- const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug)
+ const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug)
{
std::error_code EC;
raw_fd_ostream dest(filename, EC, sys::fs::F_None);
@@ -135,18 +135,24 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
PMBuilder->populateModulePassManager(MPM);
+ // Set output pass.
TargetMachine::CodeGenFileType ft;
- switch (file_type) {
- case LLVMAssemblyFile:
- ft = TargetMachine::CGFT_AssemblyFile;
- break;
- default:
- ft = TargetMachine::CGFT_ObjectFile;
- break;
- }
- if (target_machine->addPassesToEmitFile(MPM, dest, ft)) {
- *error_message = strdup("TargetMachine can't emit a file of this type");
- return true;
+ if (output_type != ZigLLVM_EmitLLVMIr) {
+ switch (output_type) {
+ case ZigLLVM_EmitAssembly:
+ ft = TargetMachine::CGFT_AssemblyFile;
+ break;
+ case ZigLLVM_EmitBinary:
+ ft = TargetMachine::CGFT_ObjectFile;
+ break;
+ default:
+ abort();
+ }
+
+ if (target_machine->addPassesToEmitFile(MPM, dest, ft)) {
+ *error_message = strdup("TargetMachine can't emit a file of this type");
+ return true;
+ }
}
// run per function optimization passes
@@ -158,7 +164,11 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
MPM.run(*module);
- dest.close();
+ if (output_type == ZigLLVM_EmitLLVMIr) {
+ if (LLVMPrintModuleToFile(module_ref, filename, error_message)) {
+ return true;
+ }
+ }
return false;
}
diff --git a/src/zig_llvm.hpp b/src/zig_llvm.hpp
@@ -34,8 +34,16 @@ void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
char *ZigLLVMGetHostCPUName(void);
char *ZigLLVMGetNativeFeatures(void);
+// We use a custom enum here since LLVM does not expose LLVMIr as an emit
+// output through the same mechanism as assembly/binary.
+enum ZigLLVM_EmitOutputType {
+ ZigLLVM_EmitAssembly,
+ ZigLLVM_EmitBinary,
+ ZigLLVM_EmitLLVMIr,
+};
+
bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
- const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug);
+ const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
unsigned NumArgs, unsigned CC, bool always_inline, const char *Name);
diff --git a/std/heap.zig b/std/heap.zig
@@ -17,8 +17,8 @@ pub var c_allocator = Allocator {
};
fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {
- if (c.malloc(usize(n))) |mem| {
- @ptrCast(&u8, mem)[0..n]
+ if (c.malloc(usize(n))) |buf| {
+ @ptrCast(&u8, buf)[0..n]
} else {
error.OutOfMemory
}
@@ -29,8 +29,8 @@ fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize)
old_mem[0..new_size]
} else {
const old_ptr = @ptrCast(&c_void, old_mem.ptr);
- if (c.realloc(old_ptr, usize(new_size))) |mem| {
- @ptrCast(&u8, mem)[0..new_size]
+ if (c.realloc(old_ptr, usize(new_size))) |buf| {
+ @ptrCast(&u8, buf)[0..new_size]
} else {
error.OutOfMemory
}
@@ -136,6 +136,14 @@ pub const IncrementingAllocator = struct {
}
};
+test "c_allocator" {
+ if (builtin.link_libc) {
+ var slice = c_allocator.alloc(u8, 50) %% return;
+ defer c_allocator.free(slice);
+ slice = c_allocator.realloc(u8, slice, 100) %% return;
+ }
+}
+
test "IncrementingAllocator" {
const total_bytes = 100 * 1024 * 1024;
var inc_allocator = %%IncrementingAllocator.init(total_bytes);
diff --git a/std/io.zig b/std/io.zig
@@ -308,7 +308,7 @@ pub const InStream = struct {
readFn: fn(self: &InStream, buffer: []u8) -> %usize,
/// Replaces `buffer` contents by reading from the stream until it is finished.
- /// If `buffer.len()` woould exceed `max_size`, `error.StreamTooLong` is returned and
+ /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and
/// the contents read from the stream are lost.
pub fn readAllBuffer(self: &InStream, buffer: &Buffer, max_size: usize) -> %void {
%return buffer.resize(0);
@@ -339,7 +339,7 @@ pub const InStream = struct {
var buf = Buffer.initNull(allocator);
defer buf.deinit();
- %return self.readAllBuffer(self, &buf, max_size);
+ %return self.readAllBuffer(&buf, max_size);
return buf.toOwnedSlice();
}
diff --git a/test/behavior.zig b/test/behavior.zig
@@ -29,6 +29,7 @@ comptime {
_ = @import("cases/null.zig");
_ = @import("cases/pub_enum/index.zig");
_ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
+ _ = @import("cases/reflection.zig");
_ = @import("cases/sizeof_and_typeof.zig");
_ = @import("cases/slice.zig");
_ = @import("cases/struct.zig");
diff --git a/test/cases/reflection.zig b/test/cases/reflection.zig
@@ -0,0 +1,70 @@
+const assert = @import("std").debug.assert;
+const mem = @import("std").mem;
+
+test "reflection: array, pointer, nullable, error union type child" {
+ comptime {
+ assert(([10]u8).Child == u8);
+ assert((&u8).Child == u8);
+ assert((%u8).Child == u8);
+ assert((?u8).Child == u8);
+ }
+}
+
+test "reflection: function return type, var args, and param types" {
+ comptime {
+ assert(@typeOf(dummy).ReturnType == i32);
+ assert(!@typeOf(dummy).is_var_args);
+ assert(@typeOf(dummy_varargs).is_var_args);
+ assert(@typeOf(dummy).arg_count == 3);
+ assert(@ArgType(@typeOf(dummy), 0) == bool);
+ assert(@ArgType(@typeOf(dummy), 1) == i32);
+ assert(@ArgType(@typeOf(dummy), 2) == f32);
+ }
+}
+
+fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 }
+fn dummy_varargs(args: ...) {}
+
+test "reflection: struct member types and names" {
+ comptime {
+ assert(@memberCount(Foo) == 3);
+
+ assert(@memberType(Foo, 0) == i32);
+ assert(@memberType(Foo, 1) == bool);
+ assert(@memberType(Foo, 2) == void);
+
+ assert(mem.eql(u8, @memberName(Foo, 0), "one"));
+ assert(mem.eql(u8, @memberName(Foo, 1), "two"));
+ assert(mem.eql(u8, @memberName(Foo, 2), "three"));
+ }
+}
+
+test "reflection: enum member types and names" {
+ comptime {
+ assert(@memberCount(Bar) == 4);
+
+ assert(@memberType(Bar, 0) == void);
+ assert(@memberType(Bar, 1) == i32);
+ assert(@memberType(Bar, 2) == bool);
+ assert(@memberType(Bar, 3) == f64);
+
+ assert(mem.eql(u8, @memberName(Bar, 0), "One"));
+ assert(mem.eql(u8, @memberName(Bar, 1), "Two"));
+ assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
+ assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
+ }
+
+}
+
+const Foo = struct {
+ one: i32,
+ two: bool,
+ three: void,
+};
+
+const Bar = enum {
+ One,
+ Two: i32,
+ Three: bool,
+ Four: f64,
+};
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
@@ -2275,4 +2275,64 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:2:1: error: invalid character: '\\t'");
+ cases.add("@ArgType given non function parameter",
+ \\comptime {
+ \\ _ = @ArgType(i32, 3);
+ \\}
+ ,
+ ".tmp_source.zig:2:18: error: expected function, found 'i32'");
+
+ cases.add("@ArgType arg index out of bounds",
+ \\comptime {
+ \\ _ = @ArgType(@typeOf(add), 2);
+ \\}
+ \\fn add(a: i32, b: i32) -> i32 { return a + b; }
+ ,
+ ".tmp_source.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) -> i32' has 2 arguments");
+
+ cases.add("@memberType on unsupported type",
+ \\comptime {
+ \\ _ = @memberType(i32, 0);
+ \\}
+ ,
+ ".tmp_source.zig:2:21: error: type 'i32' does not support @memberType");
+
+ cases.add("@memberType struct out of bounds",
+ \\comptime {
+ \\ _ = @memberType(Foo, 0);
+ \\}
+ \\const Foo = struct {};
+ ,
+ ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
+
+ cases.add("@memberType enum out of bounds",
+ \\comptime {
+ \\ _ = @memberType(Foo, 0);
+ \\}
+ \\const Foo = enum {};
+ ,
+ ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
+
+ cases.add("@memberName on unsupported type",
+ \\comptime {
+ \\ _ = @memberName(i32, 0);
+ \\}
+ ,
+ ".tmp_source.zig:2:21: error: type 'i32' does not support @memberName");
+
+ cases.add("@memberName struct out of bounds",
+ \\comptime {
+ \\ _ = @memberName(Foo, 0);
+ \\}
+ \\const Foo = struct {};
+ ,
+ ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
+
+ cases.add("@memberName enum out of bounds",
+ \\comptime {
+ \\ _ = @memberName(Foo, 0);
+ \\}
+ \\const Foo = enum {};
+ ,
+ ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
}