Commit 17b935325e

Andrew Kelley <superjoe30@gmail.com>
2017-05-01 19:12:38
`@import("builtin")` instead of `@compileVar`
See #226 Closes #220
1 parent c5dd536
doc/langref.md
@@ -446,23 +446,6 @@ This function can only occur inside `@c_import`.
 
 This appends `#undef $name` to the `c_import` temporary buffer.
 
-### @compileVar(comptime name: []u8) -> (varying type)
-
-This function returns a compile-time variable. There are built in compile
-variables:
-
- * "is_big_endian" `bool` - either `true` for big endian or `false` for little endian.
- * "is_release" `bool`- either `true` for release mode builds or `false` for debug mode builds.
- * "is_test" `bool`- either `true` for test builds or `false` otherwise.
- * "os" `Os` - use `zig targets` to see what enum values are possible here.
- * "arch" `Arch` - use `zig targets` to see what enum values are possible here.
- * "environ" `Environ` - use `zig targets` to see what enum values are possible here.
-
-Build scripts can set additional compile variables of any name and type.
-
-The result of this function is a compile time constant that is marked as
-depending on a compile variable.
-
 ### @generatedCode(expression) -> @typeOf(expression)
 
 This function wraps an expression and returns the result of the expression
src/all_types.hpp
@@ -1173,7 +1173,6 @@ enum BuiltinFnId {
     BuiltinFnIdCInclude,
     BuiltinFnIdCDefine,
     BuiltinFnIdCUndef,
-    BuiltinFnIdCompileVar,
     BuiltinFnIdCompileErr,
     BuiltinFnIdCompileLog,
     BuiltinFnIdGeneratedCode,
@@ -1323,7 +1322,6 @@ struct CodeGen {
     HashMap<GenericFnTypeId *, FnTableEntry *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
     HashMap<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
     HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table;
-    HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> compile_vars;
     HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> exported_symbol_names;
     HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
 
@@ -1407,6 +1405,8 @@ struct CodeGen {
     PackageTableEntry *std_package;
     PackageTableEntry *zigrt_package;
     PackageTableEntry *test_runner_package;
+    PackageTableEntry *compile_var_package;
+    ImportTableEntry *compile_var_import;
     Buf *root_out_name;
     bool windows_subsystem_windows;
     bool windows_subsystem_console;
@@ -1635,6 +1635,7 @@ struct ScopeFnDef {
     FnTableEntry *fn_entry;
 };
 
+// synchronized with code in define_builtin_compile_vars
 enum AtomicOrder {
     AtomicOrderUnordered,
     AtomicOrderMonotonic,
@@ -1706,7 +1707,6 @@ enum IrInstructionId {
     IrInstructionIdArrayType,
     IrInstructionIdSliceType,
     IrInstructionIdAsm,
-    IrInstructionIdCompileVar,
     IrInstructionIdSizeOf,
     IrInstructionIdTestNonNull,
     IrInstructionIdUnwrapMaybe,
@@ -2085,12 +2085,6 @@ struct IrInstructionAsm {
     bool has_side_effects;
 };
 
-struct IrInstructionCompileVar {
-    IrInstruction base;
-
-    IrInstruction *name;
-};
-
 struct IrInstructionSizeOf {
     IrInstruction base;
 
src/analyze.cpp
@@ -2084,6 +2084,14 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source
     tld->parent_scope = parent_scope;
 }
 
+void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) {
+    Tld *tld = g->compile_var_import->decls_scope->decl_table.get(name);
+    resolve_top_level_decl(g, tld, false);
+    assert(tld->id == TldIdVar);
+    TldVar *tld_var = (TldVar *)tld;
+    tld_var->var->value = value;
+}
+
 void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
     switch (node->type) {
         case NodeTypeRoot:
@@ -2122,7 +2130,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
                 if (import == g->root_import && scope_is_root_decls(&decls_scope->base) &&
                     buf_eql_str(fn_name, "panic"))
                 {
-                    g->compile_vars.put(buf_create_from_str("panic_implementation_provided"),
+                    update_compile_var(g, buf_create_from_str("__zig_panic_implementation_provided"),
                             create_const_bool(g, true));
                 }
 
src/analyze.hpp
@@ -152,5 +152,6 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value);
 FnTableEntry *get_extern_panic_fn(CodeGen *g);
 TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type);
 void expand_undef_array(CodeGen *g, ConstExprValue *const_val);
+void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);
 
 #endif
src/codegen.cpp
@@ -47,7 +47,7 @@ static void init_darwin_native(CodeGen *g) {
     }
 }
 
-PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path) {
+static PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path) {
     PackageTableEntry *entry = allocate<PackageTableEntry>(1);
     entry->package_table.init(4);
     buf_init_from_str(&entry->root_src_dir, root_src_dir);
@@ -70,7 +70,6 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
     g->generic_table.init(16);
     g->llvm_fn_table.init(16);
     g->memoized_fn_eval_table.init(16);
-    g->compile_vars.init(16);
     g->exported_symbol_names.init(8);
     g->external_prototypes.init(8);
     g->is_release_build = false;
@@ -2883,7 +2882,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
         case IrInstructionIdSetDebugSafety:
         case IrInstructionIdArrayType:
         case IrInstructionIdSliceType:
-        case IrInstructionIdCompileVar:
         case IrInstructionIdSizeOf:
         case IrInstructionIdSwitchTarget:
         case IrInstructionIdContainerInitFields:
@@ -3627,6 +3625,13 @@ static LLVMValueRef build_alloca(CodeGen *g, TypeTableEntry *type_entry, const c
     return result;
 }
 
+static void ensure_cache_dir(CodeGen *g) {
+    int err;
+    if ((err = os_make_path(g->cache_dir))) {
+        zig_panic("unable to make cache dir: %s", err_str(err));
+    }
+}
+
 static void do_code_gen(CodeGen *g) {
     if (g->verbose) {
         fprintf(stderr, "\nCode Generation:\n");
@@ -3919,10 +3924,7 @@ static void do_code_gen(CodeGen *g) {
     buf_append_str(o_basename, o_ext);
     Buf *output_path = buf_alloc();
     os_path_join(g->cache_dir, o_basename, output_path);
-    int err;
-    if ((err = os_make_path(g->cache_dir))) {
-        zig_panic("unable to make cache dir: %s", err_str(err));
-    }
+    ensure_cache_dir(g);
     if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
                 LLVMObjectFile, &err_msg, !g->is_release_build))
     {
@@ -3970,36 +3972,6 @@ static const GlobalLinkageValue global_linkage_values[] = {
     {GlobalLinkageIdLinkOnce, "LinkOnce"},
 };
 
-static void init_enum_debug_info(CodeGen *g, TypeTableEntry *enum_type) {
-    uint32_t field_count = enum_type->data.enumeration.src_field_count;
-
-    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;
-
-    ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
-    for (uint32_t i = 0; i < field_count; i += 1) {
-        TypeEnumField *field = &enum_type->data.enumeration.fields[i];
-        di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field->name), i);
-    }
-
-    // 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*LLVMABISizeOfType(g->target_data_ref, tag_type_entry->type_ref);
-    enum_type->di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
-            nullptr, buf_ptr(&enum_type->name),
-            nullptr, 0,
-            tag_debug_size_in_bits,
-            tag_debug_align_in_bits,
-            di_enumerators, field_count,
-            tag_type_entry->di_type, "");
-
-    enum_type->type_ref = tag_type_entry->type_ref;
-
-    enum_type->data.enumeration.complete = true;
-    enum_type->data.enumeration.zero_bits_known = true;
-}
-
 static void define_builtin_types(CodeGen *g) {
     {
         // if this type is anywhere in the AST, we should never hit codegen.
@@ -4218,167 +4190,6 @@ static void define_builtin_types(CodeGen *g) {
         g->primitive_type_table.put(&entry->name, entry);
     }
 
-    {
-        TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
-        buf_init_from_str(&entry->name, "Os");
-        uint32_t field_count = (uint32_t)target_os_count();
-        entry->data.enumeration.src_field_count = field_count;
-        entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
-        for (uint32_t i = 0; i < field_count; i += 1) {
-            TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
-            ZigLLVM_OSType os_type = get_target_os(i);
-            type_enum_field->name = buf_create_from_str(get_target_os_name(os_type));
-            type_enum_field->value = i;
-            type_enum_field->type_entry = g->builtin_types.entry_void;
-
-            if (os_type == g->zig_target.os) {
-                g->target_os_index = i;
-            }
-        }
-
-        init_enum_debug_info(g, entry);
-
-        g->builtin_types.entry_os_enum = entry;
-        g->primitive_type_table.put(&entry->name, entry);
-    }
-
-    {
-        TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
-        buf_init_from_str(&entry->name, "Arch");
-        uint32_t field_count = (uint32_t)target_arch_count();
-        entry->data.enumeration.src_field_count = field_count;
-        entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
-        for (uint32_t i = 0; i < field_count; i += 1) {
-            TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
-            const ArchType *arch_type = get_target_arch(i);
-            type_enum_field->name = buf_alloc();
-            buf_resize(type_enum_field->name, 50);
-            get_arch_name(buf_ptr(type_enum_field->name), arch_type);
-            buf_resize(type_enum_field->name, strlen(buf_ptr(type_enum_field->name)));
-
-            type_enum_field->value = i;
-            type_enum_field->type_entry = g->builtin_types.entry_void;
-
-            if (arch_type->arch == g->zig_target.arch.arch &&
-                arch_type->sub_arch == g->zig_target.arch.sub_arch)
-            {
-                g->target_arch_index = i;
-            }
-        }
-
-        init_enum_debug_info(g, entry);
-
-        g->builtin_types.entry_arch_enum = entry;
-        g->primitive_type_table.put(&entry->name, entry);
-    }
-
-    {
-        TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
-        buf_init_from_str(&entry->name, "Environ");
-        uint32_t field_count = (uint32_t)target_environ_count();
-        entry->data.enumeration.src_field_count = field_count;
-        entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
-        for (uint32_t i = 0; i < field_count; i += 1) {
-            TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
-            ZigLLVM_EnvironmentType environ_type = get_target_environ(i);
-            type_enum_field->name = buf_create_from_str(ZigLLVMGetEnvironmentTypeName(environ_type));
-            type_enum_field->value = i;
-            type_enum_field->type_entry = g->builtin_types.entry_void;
-
-            if (environ_type == g->zig_target.env_type) {
-                g->target_environ_index = i;
-            }
-        }
-
-        init_enum_debug_info(g, entry);
-
-        g->builtin_types.entry_environ_enum = entry;
-        g->primitive_type_table.put(&entry->name, entry);
-    }
-
-    {
-        TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
-        buf_init_from_str(&entry->name, "ObjectFormat");
-        uint32_t field_count = (uint32_t)target_oformat_count();
-        entry->data.enumeration.src_field_count = field_count;
-        entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
-        for (uint32_t i = 0; i < field_count; i += 1) {
-            TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
-            ZigLLVM_ObjectFormatType oformat = get_target_oformat(i);
-            type_enum_field->name = buf_create_from_str(get_target_oformat_name(oformat));
-            type_enum_field->value = i;
-            type_enum_field->type_entry = g->builtin_types.entry_void;
-
-            if (oformat == g->zig_target.oformat) {
-                g->target_oformat_index = i;
-            }
-        }
-
-        init_enum_debug_info(g, entry);
-
-        g->builtin_types.entry_oformat_enum = entry;
-        g->primitive_type_table.put(&entry->name, entry);
-    }
-
-    {
-        TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
-        entry->zero_bits = true; // only allowed at compile time
-        buf_init_from_str(&entry->name, "GlobalLinkage");
-        uint32_t field_count = array_length(global_linkage_values);
-        entry->data.enumeration.src_field_count = field_count;
-        entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
-        for (uint32_t i = 0; i < field_count; i += 1) {
-            TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
-            const GlobalLinkageValue *value = &global_linkage_values[i];
-            type_enum_field->name = buf_create_from_str(value->name);
-            type_enum_field->value = i;
-            type_enum_field->type_entry = g->builtin_types.entry_void;
-        }
-        entry->data.enumeration.complete = true;
-        entry->data.enumeration.zero_bits_known = true;
-
-        TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
-        entry->data.enumeration.tag_type = tag_type_entry;
-
-        g->builtin_types.entry_global_linkage_enum = entry;
-        g->primitive_type_table.put(&entry->name, entry);
-    }
-
-    {
-        TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
-        entry->zero_bits = true; // only allowed at compile time
-        buf_init_from_str(&entry->name, "AtomicOrder");
-        uint32_t field_count = 6;
-        entry->data.enumeration.src_field_count = field_count;
-        entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
-        entry->data.enumeration.fields[0].name = buf_create_from_str("Unordered");
-        entry->data.enumeration.fields[0].value = AtomicOrderUnordered;
-        entry->data.enumeration.fields[0].type_entry = g->builtin_types.entry_void;
-        entry->data.enumeration.fields[1].name = buf_create_from_str("Monotonic");
-        entry->data.enumeration.fields[1].value = AtomicOrderMonotonic;
-        entry->data.enumeration.fields[1].type_entry = g->builtin_types.entry_void;
-        entry->data.enumeration.fields[2].name = buf_create_from_str("Acquire");
-        entry->data.enumeration.fields[2].value = AtomicOrderAcquire;
-        entry->data.enumeration.fields[2].type_entry = g->builtin_types.entry_void;
-        entry->data.enumeration.fields[3].name = buf_create_from_str("Release");
-        entry->data.enumeration.fields[3].value = AtomicOrderRelease;
-        entry->data.enumeration.fields[3].type_entry = g->builtin_types.entry_void;
-        entry->data.enumeration.fields[4].name = buf_create_from_str("AcqRel");
-        entry->data.enumeration.fields[4].value = AtomicOrderAcqRel;
-        entry->data.enumeration.fields[4].type_entry = g->builtin_types.entry_void;
-        entry->data.enumeration.fields[5].name = buf_create_from_str("SeqCst");
-        entry->data.enumeration.fields[5].value = AtomicOrderSeqCst;
-        entry->data.enumeration.fields[5].type_entry = g->builtin_types.entry_void;
-
-        entry->data.enumeration.complete = true;
-        entry->data.enumeration.zero_bits_known = true;
-
-        TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
-        entry->data.enumeration.tag_type = tag_type_entry;
-
-        g->builtin_types.entry_atomic_order_enum = entry;
-        g->primitive_type_table.put(&entry->name, entry);
-    }
 }
 
 
@@ -4475,7 +4286,6 @@ static void define_builtin_fns(CodeGen *g) {
     create_builtin_fn(g, BuiltinFnIdCInclude, "cInclude", 1);
     create_builtin_fn(g, BuiltinFnIdCDefine, "cDefine", 2);
     create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1);
-    create_builtin_fn(g, BuiltinFnIdCompileVar, "compileVar", 1);
     create_builtin_fn(g, BuiltinFnIdGeneratedCode, "generatedCode", 1);
     create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 1);
     create_builtin_fn(g, BuiltinFnIdClz, "clz", 1);
@@ -4506,38 +4316,159 @@ static void define_builtin_fns(CodeGen *g) {
     create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);
 }
 
-static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) {
-    g->compile_vars.put_unique(buf_create_from_str(name), value);
+static const char *bool_to_str(bool b) {
+    return b ? "true" : "false";
 }
 
 static void define_builtin_compile_vars(CodeGen *g) {
-    add_compile_var(g, "is_big_endian", create_const_bool(g, g->is_big_endian));
-    add_compile_var(g, "is_release", create_const_bool(g, g->is_release_build));
-    add_compile_var(g, "is_test", create_const_bool(g, g->is_test_build));
-    add_compile_var(g, "os", create_const_enum_tag(g->builtin_types.entry_os_enum, g->target_os_index));
-    add_compile_var(g, "arch", create_const_enum_tag(g->builtin_types.entry_arch_enum, g->target_arch_index));
-    add_compile_var(g, "environ", create_const_enum_tag(g->builtin_types.entry_environ_enum, g->target_environ_index));
-    add_compile_var(g, "object_format", create_const_enum_tag(
-                g->builtin_types.entry_oformat_enum, g->target_oformat_index));
+    if (g->std_package == nullptr)
+        return;
+
+    const char *builtin_zig_basename = "builtin.zig";
+    Buf *builtin_zig_path = buf_alloc();
+    os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
+    Buf *contents = buf_alloc();
+
+    const char *cur_os = nullptr;
+    {
+        buf_appendf(contents, "pub const Os = enum {\n");
+        uint32_t field_count = (uint32_t)target_os_count();
+        for (uint32_t i = 0; i < field_count; i += 1) {
+            ZigLLVM_OSType os_type = get_target_os(i);
+            const char *name = get_target_os_name(os_type);
+            buf_appendf(contents, "    %s,\n", name);
+
+            if (os_type == g->zig_target.os) {
+                g->target_os_index = i;
+                cur_os = name;
+            }
+        }
+        buf_appendf(contents, "};\n\n");
+    }
+    assert(cur_os != nullptr);
+
+    const char *cur_arch = nullptr;
+    {
+        buf_appendf(contents, "pub const Arch = enum {\n");
+        uint32_t field_count = (uint32_t)target_arch_count();
+        for (uint32_t i = 0; i < field_count; i += 1) {
+            const ArchType *arch_type = get_target_arch(i);
+            Buf *arch_name = buf_alloc();
+            buf_resize(arch_name, 50);
+            get_arch_name(buf_ptr(arch_name), arch_type);
+            buf_resize(arch_name, strlen(buf_ptr(arch_name)));
+
+            buf_appendf(contents, "    %s,\n", buf_ptr(arch_name));
+
+            if (arch_type->arch == g->zig_target.arch.arch &&
+                arch_type->sub_arch == g->zig_target.arch.sub_arch)
+            {
+                g->target_arch_index = i;
+                cur_arch = buf_ptr(arch_name);
+            }
+        }
+        buf_appendf(contents, "};\n\n");
+    }
+    assert(cur_arch != nullptr);
+
+    const char *cur_environ = nullptr;
+    {
+        buf_appendf(contents, "pub const Environ = enum {\n");
+        uint32_t field_count = (uint32_t)target_environ_count();
+        for (uint32_t i = 0; i < field_count; i += 1) {
+            ZigLLVM_EnvironmentType environ_type = get_target_environ(i);
+            const char *name = ZigLLVMGetEnvironmentTypeName(environ_type);
+            buf_appendf(contents, "    %s,\n", name);
+
+            if (environ_type == g->zig_target.env_type) {
+                g->target_environ_index = i;
+                cur_environ = name;
+            }
+        }
+        buf_appendf(contents, "};\n\n");
+    }
+    assert(cur_environ != nullptr);
 
+    const char *cur_obj_fmt = nullptr;
     {
-        TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
-        ConstExprValue *const_val = allocate<ConstExprValue>(1);
-        const_val->special = ConstValSpecialStatic;
-        const_val->type = get_array_type(g, str_type, g->link_libs.length);
-        const_val->data.x_array.s_none.elements = allocate<ConstExprValue>(g->link_libs.length);
+        buf_appendf(contents, "pub const ObjectFormat = enum {\n");
+        uint32_t field_count = (uint32_t)target_oformat_count();
+        for (uint32_t i = 0; i < field_count; i += 1) {
+            ZigLLVM_ObjectFormatType oformat = get_target_oformat(i);
+            const char *name = get_target_oformat_name(oformat);
+            buf_appendf(contents, "    %s,\n", name);
+
+            if (oformat == g->zig_target.oformat) {
+                g->target_oformat_index = i;
+                cur_obj_fmt = name;
+            }
+        }
+
+        buf_appendf(contents, "};\n\n");
+    }
+    assert(cur_obj_fmt != nullptr);
+
+    {
+        buf_appendf(contents, "pub const GlobalLinkage = enum {\n");
+        uint32_t field_count = array_length(global_linkage_values);
+        for (uint32_t i = 0; i < field_count; i += 1) {
+            const GlobalLinkageValue *value = &global_linkage_values[i];
+            buf_appendf(contents, "    %s,\n", value->name);
+        }
+        buf_appendf(contents, "};\n\n");
+    }
+    {
+        buf_appendf(contents,
+            "pub const AtomicOrder = enum {\n"
+            "    Unordered,\n"
+            "    Monotonic,\n"
+            "    Acquire,\n"
+            "    Release,\n"
+            "    AcqRel,\n"
+            "    SeqCst,\n"
+            "};\n\n");
+    }
+    buf_appendf(contents, "pub const is_big_endian = %s;\n", bool_to_str(g->is_big_endian));
+    buf_appendf(contents, "pub const is_release = %s;\n", bool_to_str(g->is_release_build));
+    buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
+    buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
+    buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);
+    buf_appendf(contents, "pub const environ = Environ.%s;\n", cur_environ);
+    buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
+
+    {
+        buf_appendf(contents, "pub const link_libs = [][]const u8 {\n");
         for (size_t i = 0; i < g->link_libs.length; i += 1) {
             Buf *link_lib_buf = g->link_libs.at(i);
-            ConstExprValue *array_val = create_const_str_lit(g, link_lib_buf);
-            init_const_slice(g, &const_val->data.x_array.s_none.elements[i], array_val, 0, buf_len(link_lib_buf), true);
+            buf_appendf(contents, "    \"%s\",\n", buf_ptr(link_lib_buf));
         }
+        buf_appendf(contents, "};\n");
+    }
+
+    buf_appendf(contents, "pub const __zig_panic_implementation_provided = %s; // overwritten later\n",
+            bool_to_str(false));
+    buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
 
-        add_compile_var(g, "link_libs", const_val);
+    ensure_cache_dir(g);
+    os_write_file(builtin_zig_path, contents);
+
+    int err;
+    Buf *abs_full_path = buf_alloc();
+    if ((err = os_path_real(builtin_zig_path, abs_full_path))) {
+        zig_panic("unable to open '%s': %s", buf_ptr(builtin_zig_path), err_str(err));
     }
-    add_compile_var(g, "panic_implementation_provided", create_const_bool(g, false));
+
+    assert(g->root_package);
+    assert(g->std_package);
+    g->compile_var_package = new_package(buf_ptr(g->cache_dir), builtin_zig_basename);
+    g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
+    g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
+    g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents);
 }
 
 static void init(CodeGen *g) {
+    if (g->module)
+        return;
     assert(g->root_out_name);
     g->module = LLVMModuleCreateWithName(buf_ptr(g->root_out_name));
 
@@ -4600,14 +4531,15 @@ static void init(CodeGen *g) {
     g->dummy_di_file = nullptr;
 
     define_builtin_types(g);
-    define_builtin_fns(g);
-    define_builtin_compile_vars(g);
 
     g->invalid_instruction = allocate<IrInstruction>(1);
     g->invalid_instruction->value.type = g->builtin_types.entry_invalid;
 
     g->const_void_val.special = ConstValSpecialStatic;
     g->const_void_val.type = g->builtin_types.entry_void;
+
+    define_builtin_fns(g);
+    define_builtin_compile_vars(g);
 }
 
 void codegen_parseh(CodeGen *g, Buf *full_path) {
@@ -4661,21 +4593,17 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
 }
 
 static PackageTableEntry *create_bootstrap_pkg(CodeGen *g, PackageTableEntry *pkg_with_main) {
-    PackageTableEntry *package = new_package(buf_ptr(g->zig_std_special_dir), "");
-    package->package_table.put(buf_create_from_str("std"), g->std_package);
+    PackageTableEntry *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig");
     package->package_table.put(buf_create_from_str("@root"), pkg_with_main);
     return package;
 }
 
 static PackageTableEntry *create_test_runner_pkg(CodeGen *g) {
-    PackageTableEntry *package = new_package(buf_ptr(g->zig_std_special_dir), "test_runner.zig");
-    package->package_table.put(buf_create_from_str("std"), g->std_package);
-    return package;
+    return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "test_runner.zig");
 }
 
 static PackageTableEntry *create_zigrt_pkg(CodeGen *g) {
-    PackageTableEntry *package = new_package(buf_ptr(g->zig_std_special_dir), "");
-    package->package_table.put(buf_create_from_str("std"), g->std_package);
+    PackageTableEntry *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "zigrt.zig");
     package->package_table.put(buf_create_from_str("@root"), g->root_package);
     return package;
 }
@@ -4723,7 +4651,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
 
     ConstExprValue *test_fn_slice = create_const_slice(g, test_fn_array, 0, g->test_fns.length, true);
 
-    g->compile_vars.put(buf_create_from_str("zig_test_fn_slice"), test_fn_slice);
+    update_compile_var(g, buf_create_from_str("__zig_test_fn_slice"), test_fn_slice);
     g->test_runner_package = create_test_runner_pkg(g);
     g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig");
 }
@@ -5066,3 +4994,14 @@ void codegen_build(CodeGen *g) {
     do_code_gen(g);
     gen_h_file(g);
 }
+
+PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path) {
+    init(g);
+    PackageTableEntry *pkg = new_package(root_src_dir, root_src_path);
+    if (g->std_package != nullptr) {
+        assert(g->compile_var_package != nullptr);
+        pkg->package_table.put(buf_create_from_str("std"), g->std_package);
+        pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
+    }
+    return pkg;
+}
src/codegen.hpp
@@ -52,7 +52,7 @@ void codegen_add_time_event(CodeGen *g, const char *name);
 void codegen_print_timing_report(CodeGen *g, FILE *f);
 void codegen_build(CodeGen *g);
 
-PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path);
+PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path);
 void codegen_add_assembly(CodeGen *g, Buf *path);
 void codegen_add_object(CodeGen *g, Buf *object_path);
 
src/ir.cpp
@@ -294,10 +294,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAsm *) {
     return IrInstructionIdAsm;
 }
 
-static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileVar *) {
-    return IrInstructionIdCompileVar;
-}
-
 static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) {
     return IrInstructionIdSizeOf;
 }
@@ -1249,15 +1245,6 @@ static IrInstruction *ir_build_asm_from(IrBuilder *irb, IrInstruction *old_instr
     return new_instruction;
 }
 
-static IrInstruction *ir_build_compile_var(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name) {
-    IrInstructionCompileVar *instruction = ir_build_instruction<IrInstructionCompileVar>(irb, scope, source_node);
-    instruction->name = name;
-
-    ir_ref_instruction(name, irb->current_basic_block);
-
-    return &instruction->base;
-}
-
 static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {
     IrInstructionSizeOf *instruction = ir_build_instruction<IrInstructionSizeOf>(irb, scope, source_node);
     instruction->type_value = type_value;
@@ -2431,13 +2418,6 @@ static IrInstruction *ir_instruction_asm_get_dep(IrInstructionAsm *instruction,
     return nullptr;
 }
 
-static IrInstruction *ir_instruction_compilevar_get_dep(IrInstructionCompileVar *instruction, size_t index) {
-    switch (index) {
-        case 0: return instruction->name;
-        default: return nullptr;
-    }
-}
-
 static IrInstruction *ir_instruction_sizeof_get_dep(IrInstructionSizeOf *instruction, size_t index) {
     switch (index) {
         case 0: return instruction->type_value;
@@ -2979,8 +2959,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
             return ir_instruction_slicetype_get_dep((IrInstructionSliceType *) instruction, index);
         case IrInstructionIdAsm:
             return ir_instruction_asm_get_dep((IrInstructionAsm *) instruction, index);
-        case IrInstructionIdCompileVar:
-            return ir_instruction_compilevar_get_dep((IrInstructionCompileVar *) instruction, index);
         case IrInstructionIdSizeOf:
             return ir_instruction_sizeof_get_dep((IrInstructionSizeOf *) instruction, index);
         case IrInstructionIdTestNonNull:
@@ -3937,15 +3915,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
 
                 return ir_build_set_debug_safety(irb, scope, node, arg0_value, arg1_value);
             }
-        case BuiltinFnIdCompileVar:
-            {
-                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;
-
-                return ir_build_compile_var(irb, scope, node, arg0_value);
-            }
         case BuiltinFnIdSizeof:
             {
                 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
@@ -10409,27 +10378,6 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
     zig_unreachable();
 }
 
-static TypeTableEntry *ir_analyze_instruction_compile_var(IrAnalyze *ira,
-        IrInstructionCompileVar *compile_var_instruction)
-{
-    IrInstruction *name_value = compile_var_instruction->name->other;
-    Buf *var_name = ir_resolve_str(ira, name_value);
-    if (!var_name)
-        return ira->codegen->builtin_types.entry_invalid;
-
-    ConstExprValue *out_val = ir_build_const_from(ira, &compile_var_instruction->base);
-    auto entry = ira->codegen->compile_vars.maybe_get(var_name);
-    if (entry) {
-        *out_val = *entry->value;
-        return out_val->type;
-    } else {
-        ir_add_error_node(ira, name_value->source_node,
-            buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));
-        return ira->codegen->builtin_types.entry_invalid;
-    }
-    zig_unreachable();
-}
-
 static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
         IrInstructionSizeOf *size_of_instruction)
 {
@@ -13039,8 +12987,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
             return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
         case IrInstructionIdArrayType:
             return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
-        case IrInstructionIdCompileVar:
-            return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction);
         case IrInstructionIdSizeOf:
             return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
         case IrInstructionIdTestNonNull:
@@ -13292,7 +13238,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdEnumFieldPtr:
         case IrInstructionIdArrayType:
         case IrInstructionIdSliceType:
-        case IrInstructionIdCompileVar:
         case IrInstructionIdSizeOf:
         case IrInstructionIdTestNonNull:
         case IrInstructionIdUnwrapMaybe:
src/ir_print.cpp
@@ -403,12 +403,6 @@ static void ir_print_asm(IrPrint *irp, IrInstructionAsm *instruction) {
     fprintf(irp->f, ")");
 }
 
-static void ir_print_compile_var(IrPrint *irp, IrInstructionCompileVar *instruction) {
-    fprintf(irp->f, "@compileVar(");
-    ir_print_other_instruction(irp, instruction->name);
-    fprintf(irp->f, ")");
-}
-
 static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
     fprintf(irp->f, "@sizeOf(");
     ir_print_other_instruction(irp, instruction->type_value);
@@ -987,9 +981,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdAsm:
             ir_print_asm(irp, (IrInstructionAsm *)instruction);
             break;
-        case IrInstructionIdCompileVar:
-            ir_print_compile_var(irp, (IrInstructionCompileVar *)instruction);
-            break;
         case IrInstructionIdSizeOf:
             ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
             break;
src/main.cpp
@@ -263,8 +263,8 @@ int main(int argc, char **argv) {
             return 1;
         }
 
-        PackageTableEntry *build_pkg = new_package(buf_ptr(&build_file_dirname), buf_ptr(&build_file_basename));
-        build_pkg->package_table.put(buf_create_from_str("std"), g->std_package);
+        PackageTableEntry *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname),
+                buf_ptr(&build_file_basename));
         g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg);
         codegen_build(g);
         codegen_link(g, buf_ptr(path_to_build_exe));
std/c/index.zig
@@ -1,6 +1,8 @@
 pub use @import("../os/errno.zig");
+const builtin = @import("builtin");
+const Os = builtin.Os;
 
-pub use switch(@compileVar("os")) {
+pub use switch(builtin.os) {
     Os.linux => @import("linux.zig"),
     Os.windows => @import("windows.zig"),
     Os.darwin, Os.macosx, Os.ios => @import("darwin.zig"),
std/os/child_process.zig
@@ -7,6 +7,8 @@ const errno = @import("errno.zig");
 const debug = @import("../debug.zig");
 const assert = debug.assert;
 const BufMap = @import("../buf_map.zig").BufMap;
+const builtin = @import("builtin");
+const Os = builtin.Os;
 
 pub const ChildProcess = struct {
     pid: i32,
@@ -34,7 +36,7 @@ pub const ChildProcess = struct {
         cwd: ?[]const u8, env_map: &const BufMap,
         stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
     {
-        switch (@compileVar("os")) {
+        switch (builtin.os) {
             Os.linux, Os.macosx, Os.ios, Os.darwin => {
                 return spawnPosix(exe_path, args, cwd, env_map, stdin, stdout, stderr, allocator);
             },
std/os/darwin.zig
@@ -1,6 +1,7 @@
 
-const arch = switch (@compileVar("arch")) {
-    Arch.x86_64 => @import("darwin_x86_64.zig"),
+const builtin = @import("builtin");
+const arch = switch (builtin.arch) {
+    builtin.Arch.x86_64 => @import("darwin_x86_64.zig"),
     else => @compileError("unsupported arch"),
 };
 
std/os/index.zig
@@ -1,7 +1,9 @@
+const builtin = @import("builtin");
+const Os = builtin.Os;
 pub const windows = @import("windows.zig");
 pub const darwin = @import("darwin.zig");
 pub const linux = @import("linux.zig");
-pub const posix = switch(@compileVar("os")) {
+pub const posix = switch(builtin.os) {
     Os.linux => linux,
     Os.darwin, Os.macosx, Os.ios => darwin,
     Os.windows => windows,
@@ -12,7 +14,7 @@ pub const max_noalloc_path_len = 1024;
 pub const ChildProcess = @import("child_process.zig").ChildProcess;
 pub const path = @import("path.zig");
 
-pub const line_sep = switch (@compileVar("os")) {
+pub const line_sep = switch (builtin.os) {
     Os.windows => "\r\n",
     else => "\n",
 };
@@ -56,7 +58,7 @@ error DirNotEmpty;
 /// library implementation.
 pub fn getRandomBytes(buf: []u8) -> %void {
     while (true) {
-        const err = switch (@compileVar("os")) {
+        const err = switch (builtin.os) {
             Os.linux => {
                 if (linking_libc) {
                     if (c.getrandom(buf.ptr, buf.len, 0) == -1) *c._errno() else 0
@@ -104,7 +106,7 @@ pub coldcc fn abort() -> noreturn {
     if (linking_libc) {
         c.abort();
     }
-    switch (@compileVar("os")) {
+    switch (builtin.os) {
         Os.linux, Os.darwin, Os.macosx, Os.ios => {
             _ = posix.raise(posix.SIGABRT);
             _ = posix.raise(posix.SIGKILL);
std/os/linux.zig
@@ -1,6 +1,7 @@
-const arch = switch (@compileVar("arch")) {
-    Arch.x86_64 => @import("linux_x86_64.zig"),
-    Arch.i386 => @import("linux_i386.zig"),
+const builtin = @import("builtin");
+const arch = switch (builtin.arch) {
+    builtin.Arch.x86_64 => @import("linux_x86_64.zig"),
+    builtin.Arch.i386 => @import("linux_i386.zig"),
     else => @compileError("unsupported arch"),
 };
 const errno = @import("errno.zig");
std/os/path.zig
@@ -1,3 +1,5 @@
+const builtin = @import("builtin");
+const Os = builtin.Os;
 const debug = @import("../debug.zig");
 const assert = debug.assert;
 const mem = @import("../mem.zig");
@@ -7,11 +9,11 @@ const os = @import("index.zig");
 const math = @import("../math.zig");
 const posix = os.posix;
 
-pub const sep = switch (@compileVar("os")) {
+pub const sep = switch (builtin.os) {
     Os.windows => '\\',
     else => '/',
 };
-pub const delimiter = switch (@compileVar("os")) {
+pub const delimiter = switch (builtin.os) {
     Os.windows => ';',
     else => ':',
 };
@@ -61,7 +63,7 @@ test "os.path.join" {
 }
 
 pub fn isAbsolute(path: []const u8) -> bool {
-    switch (@compileVar("os")) {
+    switch (builtin.os) {
         Os.windows => @compileError("Unsupported OS"),
         else => return path[0] == sep,
     }
std/special/bootstrap.zig
@@ -3,6 +3,7 @@
 
 const root = @import("@root");
 const std = @import("std");
+const builtin = @import("builtin");
 
 const want_main_symbol = std.target.linking_libc;
 const want_start_symbol = !want_main_symbol;
@@ -13,15 +14,15 @@ var argc_ptr: &usize = undefined;
 
 export nakedcc fn _start() -> noreturn {
     if (!want_start_symbol) {
-        @setGlobalLinkage(_start, GlobalLinkage.Internal);
+        @setGlobalLinkage(_start, builtin.GlobalLinkage.Internal);
         unreachable;
     }
 
-    switch (@compileVar("arch")) {
-        Arch.x86_64 => {
+    switch (builtin.arch) {
+        builtin.Arch.x86_64 => {
             argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize));
         },
-        Arch.i386 => {
+        builtin.Arch.i386 => {
             argc_ptr = asm("lea (%%esp), %[argc]": [argc] "=r" (-> &usize));
         },
         else => @compileError("unsupported arch"),
@@ -51,7 +52,7 @@ fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
 
 export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {
     if (!want_main_symbol) {
-        @setGlobalLinkage(main, GlobalLinkage.Internal);
+        @setGlobalLinkage(main, builtin.GlobalLinkage.Internal);
         unreachable;
     }
 
std/special/compiler_rt.zig
@@ -1,3 +1,5 @@
+const builtin = @import("builtin");
+
 const CHAR_BIT = 8;
 const du_int = u64;
 const di_int = i64;
@@ -5,7 +7,7 @@ const si_int = c_int;
 const su_int = c_uint;
 
 const udwords = [2]su_int;
-const low = if (@compileVar("is_big_endian")) 1 else 0;
+const low = if (builtin.is_big_endian) 1 else 0;
 const high = 1 - low;
 
 export fn __udivdi3(a: du_int, b: du_int) -> du_int {
@@ -213,25 +215,25 @@ export fn __umoddi3(a: du_int, b: du_int) -> du_int {
 }
 
 fn isArmArch() -> bool {
-    return switch (@compileVar("arch")) {
-        Arch.armv8_2a,
-        Arch.armv8_1a,
-        Arch.armv8,
-        Arch.armv8m_baseline,
-        Arch.armv8m_mainline,
-        Arch.armv7,
-        Arch.armv7em,
-        Arch.armv7m,
-        Arch.armv7s,
-        Arch.armv7k,
-        Arch.armv6,
-        Arch.armv6m,
-        Arch.armv6k,
-        Arch.armv6t2,
-        Arch.armv5,
-        Arch.armv5te,
-        Arch.armv4t,
-        Arch.armeb => true,
+    return switch (builtin.arch) {
+        builtin.Arch.armv8_2a,
+        builtin.Arch.armv8_1a,
+        builtin.Arch.armv8,
+        builtin.Arch.armv8m_baseline,
+        builtin.Arch.armv8m_mainline,
+        builtin.Arch.armv7,
+        builtin.Arch.armv7em,
+        builtin.Arch.armv7m,
+        builtin.Arch.armv7s,
+        builtin.Arch.armv7k,
+        builtin.Arch.armv6,
+        builtin.Arch.armv6m,
+        builtin.Arch.armv6k,
+        builtin.Arch.armv6t2,
+        builtin.Arch.armv5,
+        builtin.Arch.armv5te,
+        builtin.Arch.armv4t,
+        builtin.Arch.armeb => true,
         else => false,
     };
 }
@@ -252,7 +254,7 @@ export nakedcc fn __aeabi_uidivmod() {
         unreachable;
     }
 
-    @setGlobalLinkage(__aeabi_uidivmod, GlobalLinkage.Internal);
+    @setGlobalLinkage(__aeabi_uidivmod, builtin.GlobalLinkage.Internal);
 }
 
 export fn __udivmodsi4(a: su_int, b: su_int, rem: &su_int) -> su_int {
std/special/test_runner.zig
@@ -1,5 +1,6 @@
 const io = @import("std").io;
-const test_fn_list = @compileVar("zig_test_fn_slice");
+const builtin = @import("builtin");
+const test_fn_list = builtin.__zig_test_fn_slice;
 
 pub fn main() -> %void {
     for (test_fn_list) |test_fn, i| {
std/special/zigrt.zig
@@ -2,13 +2,15 @@
 // multiple .o files. The symbols are defined Weak so that multiple
 // instances of zig_rt.zig do not conflict with each other.
 
+const builtin = @import("builtin");
+
 export coldcc fn __zig_panic(message_ptr: &const u8, message_len: usize) -> noreturn {
-    @setGlobalLinkage(__zig_panic, GlobalLinkage.Weak);
+    @setGlobalLinkage(__zig_panic, builtin.GlobalLinkage.Weak);
     @setDebugSafety(this, false);
 
-    if (@compileVar("panic_implementation_provided")) {
+    if (builtin.__zig_panic_implementation_provided) {
         @import("@root").panic(message_ptr[0...message_len]);
-    } else if (@compileVar("os") == Os.freestanding) {
+    } else if (builtin.os == builtin.Os.freestanding) {
         while (true) {}
     } else {
         @import("std").debug.panic("{}", message_ptr[0...message_len]);
std/build.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
 const io = @import("io.zig");
 const mem = @import("mem.zig");
 const debug = @import("debug.zig");
@@ -625,9 +626,9 @@ const Version = struct {
 };
 
 const CrossTarget = struct {
-    arch: Arch,
-    os: Os,
-    environ: Environ,
+    arch: builtin.Arch,
+    os: builtin.Os,
+    environ: builtin.Environ,
 };
 
 const Target = enum {
@@ -636,22 +637,22 @@ const Target = enum {
 
     pub fn oFileExt(self: &const Target) -> []const u8 {
         const environ = switch (*self) {
-            Target.Native => @compileVar("environ"),
+            Target.Native => builtin.environ,
             Target.Cross => |t| t.environ,
         };
         return switch (environ) {
-            Environ.msvc => ".obj",
+            builtin.Environ.msvc => ".obj",
             else => ".o",
         };
     }
 
     pub fn exeFileExt(self: &const Target) -> []const u8 {
         const target_os = switch (*self) {
-            Target.Native => @compileVar("os"),
+            Target.Native => builtin.os,
             Target.Cross => |t| t.os,
         };
         return switch (target_os) {
-            Os.windows => ".exe",
+            builtin.Os.windows => ".exe",
             else => "",
         };
     }
@@ -761,7 +762,9 @@ pub const LibExeObjStep = struct {
         }
     }
 
-    pub fn setTarget(self: &LibExeObjStep, target_arch: Arch, target_os: Os, target_environ: Environ) {
+    pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os,
+        target_environ: builtin.Environ)
+    {
         self.target = Target.Cross {
             CrossTarget {
                 .arch = target_arch,
@@ -1392,7 +1395,9 @@ pub const CLibExeObjStep = struct {
         }
     }
 
-    pub fn setTarget(self: &CLibExeObjStep, target_arch: Arch, target_os: Os, target_environ: Environ) {
+    pub fn setTarget(self: &CLibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os,
+        target_environ: builtin.Environ)
+    {
         self.target = Target.Cross {
             CrossTarget {
                 .arch = target_arch,
std/debug.zig
@@ -4,6 +4,7 @@ const os = @import("os/index.zig");
 const elf = @import("elf.zig");
 const DW = @import("dwarf.zig");
 const List = @import("list.zig").List;
+const builtin = @import("builtin");
 
 error MissingDebugInfo;
 error InvalidDebugInfo;
@@ -50,8 +51,8 @@ pub var user_main_fn: ?fn() -> %void = null;
 pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
     ignore_frame_count: usize) -> %void
 {
-    switch (@compileVar("object_format")) {
-        ObjectFormat.elf => {
+    switch (builtin.object_format) {
+        builtin.ObjectFormat.elf => {
             var stack_trace = ElfStackTrace {
                 .self_exe_stream = undefined,
                 .elf = undefined,
@@ -125,13 +126,13 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
                 %return out_stream.flush();
             }
         },
-        ObjectFormat.coff => {
+        builtin.ObjectFormat.coff => {
             %return out_stream.write("(stack trace unavailable for COFF object format)\n");
         },
-        ObjectFormat.macho => {
+        builtin.ObjectFormat.macho => {
             %return out_stream.write("(stack trace unavailable for Mach-O object format)\n");
         },
-        ObjectFormat.unknown => {
+        builtin.ObjectFormat.unknown => {
             %return out_stream.write("(stack trace unavailable for unknown object format)\n");
         },
     }
std/elf.zig
@@ -36,9 +36,7 @@ pub const FileType = enum {
     Core,
 };
 
-// TODO rename this to Arch when the builtin Arch enum is namespaced
-// or make debug info work for builtin enums
-pub const ElfArch = enum {
+pub const Arch = enum {
     Sparc,
     x86,
     Mips,
@@ -69,7 +67,7 @@ pub const Elf = struct {
     is_64: bool,
     is_big_endian: bool,
     file_type: FileType,
-    arch: ElfArch,
+    arch: Arch,
     entry_addr: u64,
     program_header_offset: u64,
     section_header_offset: u64,
@@ -123,15 +121,15 @@ pub const Elf = struct {
         };
 
         elf.arch = switch (%return elf.in_stream.readInt(elf.is_big_endian, u16)) {
-            0x02 => ElfArch.Sparc,
-            0x03 => ElfArch.x86,
-            0x08 => ElfArch.Mips,
-            0x14 => ElfArch.PowerPc,
-            0x28 => ElfArch.Arm,
-            0x2A => ElfArch.SuperH,
-            0x32 => ElfArch.IA_64,
-            0x3E => ElfArch.x86_64,
-            0xb7 => ElfArch.AArch64,
+            0x02 => Arch.Sparc,
+            0x03 => Arch.x86,
+            0x08 => Arch.Mips,
+            0x14 => Arch.PowerPc,
+            0x28 => Arch.Arm,
+            0x2A => Arch.SuperH,
+            0x32 => Arch.IA_64,
+            0x3E => Arch.x86_64,
+            0xb7 => Arch.AArch64,
             else => return error.InvalidFormat,
         };
 
std/endian.zig
@@ -1,4 +1,5 @@
 const mem = @import("mem.zig");
+const builtin = @import("builtin");
 
 pub fn swapIfLe(comptime T: type, x: T) -> T {
     swapIf(false, T, x)
@@ -9,7 +10,7 @@ pub fn swapIfBe(comptime T: type, x: T) -> T {
 }
 
 pub fn swapIf(is_be: bool, comptime T: type, x: T) -> T {
-    if (@compileVar("is_big_endian") == is_be) swap(T, x) else x
+    if (builtin.is_big_endian == is_be) swap(T, x) else x
 }
 
 pub fn swap(comptime T: type, x: T) -> T {
std/hash_map.zig
@@ -3,8 +3,9 @@ const assert = debug.assert;
 const math = @import("math.zig");
 const mem = @import("mem.zig");
 const Allocator = mem.Allocator;
+const builtin = @import("builtin");
 
-const want_modification_safety = !@compileVar("is_release");
+const want_modification_safety = !builtin.is_release;
 const debug_u32 = if (want_modification_safety) u32 else void;
 
 pub fn HashMap(comptime K: type, comptime V: type,
std/io.zig
@@ -1,4 +1,6 @@
-const system = switch(@compileVar("os")) {
+const builtin = @import("builtin");
+const Os = builtin.Os;
+const system = switch(builtin.os) {
     Os.linux => @import("os/linux.zig"),
     Os.darwin => @import("os/darwin.zig"),
     else => @compileError("Unsupported OS"),
@@ -79,7 +81,7 @@ pub const OutStream = struct {
     /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
     /// Call close to clean up.
     pub fn openMode(path: []const u8, mode: usize, allocator: ?&mem.Allocator) -> %OutStream {
-        switch (@compileVar("os")) {
+        switch (builtin.os) {
             Os.linux, Os.darwin, Os.macosx, Os.ios => {
                 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;
                 const fd = %return os.posixOpen(path, flags, mode, allocator);
@@ -176,7 +178,7 @@ pub const InStream = struct {
     /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
     /// Call close to clean up.
     pub fn open(path: []const u8, allocator: ?&mem.Allocator) -> %InStream {
-        switch (@compileVar("os")) {
+        switch (builtin.os) {
             Os.linux, Os.darwin, Os.macosx, Os.ios => {
                 const flags = system.O_LARGEFILE|system.O_RDONLY;
                 const fd = %return os.posixOpen(path, flags, 0, allocator);
@@ -191,7 +193,7 @@ pub const InStream = struct {
     /// Upon success, the stream is in an uninitialized state. To continue using it,
     /// you must use the open() function.
     pub fn close(self: &InStream) {
-        switch (@compileVar("os")) {
+        switch (builtin.os) {
             Os.linux, Os.darwin, Os.macosx, Os.ios => {
                 os.posixClose(self.fd);
             },
@@ -202,7 +204,7 @@ pub const InStream = struct {
     /// Returns the number of bytes read. If the number read is smaller than buf.len, then
     /// the stream reached End Of File.
     pub fn read(is: &InStream, buf: []u8) -> %usize {
-        switch (@compileVar("os")) {
+        switch (builtin.os) {
             Os.linux, Os.darwin => {
                 var index: usize = 0;
                 while (index < buf.len) {
@@ -268,7 +270,7 @@ pub const InStream = struct {
     }
 
     pub fn seekForward(is: &InStream, amount: usize) -> %void {
-        switch (@compileVar("os")) {
+        switch (builtin.os) {
             Os.linux, Os.darwin => {
                 const result = system.lseek(is.fd, amount, system.SEEK_CUR);
                 const err = system.getErrno(result);
@@ -288,7 +290,7 @@ pub const InStream = struct {
     }
 
     pub fn seekTo(is: &InStream, pos: usize) -> %void {
-        switch (@compileVar("os")) {
+        switch (builtin.os) {
             Os.linux, Os.darwin => {
                 const result = system.lseek(is.fd, pos, system.SEEK_SET);
                 const err = system.getErrno(result);
@@ -308,7 +310,7 @@ pub const InStream = struct {
     }
 
     pub fn getPos(is: &InStream) -> %usize {
-        switch (@compileVar("os")) {
+        switch (builtin.os) {
             Os.linux, Os.darwin => {
                 const result = system.lseek(is.fd, 0, system.SEEK_CUR);
                 const err = system.getErrno(result);
@@ -365,7 +367,7 @@ pub const InStream = struct {
 };
 
 pub fn openSelfExe() -> %InStream {
-    switch (@compileVar("os")) {
+    switch (builtin.os) {
         Os.linux => {
             return InStream.open("/proc/self/exe", null);
         },
std/mem.zig
@@ -2,6 +2,8 @@ const assert = @import("debug.zig").assert;
 const math = @import("math.zig");
 const os = @import("os/index.zig");
 const io = @import("io.zig");
+const builtin = @import("builtin");
+const Os = builtin.Os;
 
 pub const Cmp = math.Cmp;
 
@@ -53,7 +55,7 @@ pub const IncrementingAllocator = struct {
     end_index: usize,
 
     fn init(capacity: usize) -> %IncrementingAllocator {
-        switch (@compileVar("os")) {
+        switch (builtin.os) {
             Os.linux, Os.darwin, Os.macosx, Os.ios => {
                 const p = os.posix;
                 const addr = p.mmap(null, capacity, p.PROT_READ|p.PROT_WRITE,
std/target.zig
@@ -1,11 +1,12 @@
 const mem = @import("mem.zig");
+const builtin = @import("builtin");
 
 pub const linking_libc = linkingLibrary("c");
 
 pub fn linkingLibrary(lib_name: []const u8) -> bool {
     // TODO shouldn't need this if
-    if (@compileVar("link_libs").len != 0) {
-        for (@compileVar("link_libs")) |link_lib| {
+    if (builtin.link_libs.len != 0) {
+        for (builtin.link_libs) |link_lib| {
             if (mem.eql(u8, link_lib, lib_name)) {
                 return true;
             }
test/cases/namespace_depends_on_compile_var/index.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
 const assert = @import("std").debug.assert;
 
 test "namespaceDependsOnCompileVar" {
@@ -7,7 +8,7 @@ test "namespaceDependsOnCompileVar" {
         assert(!some_namespace.a_bool);
     }
 }
-const some_namespace = switch(@compileVar("os")) {
-    Os.linux => @import("a.zig"),
+const some_namespace = switch(builtin.os) {
+    builtin.Os.linux => @import("a.zig"),
     else => @import("b.zig"),
 };
test/cases/asm.zig
@@ -1,7 +1,8 @@
+const config = @import("builtin");
 const assert = @import("std").debug.assert;
 
 comptime {
-    if (@compileVar("arch") == Arch.x86_64) {
+    if (config.arch == config.Arch.x86_64) {
         asm volatile (
             \\.globl aoeu;
             \\.type aoeu, @function;
@@ -11,7 +12,7 @@ comptime {
 }
 
 test "module level assembly" {
-    if (@compileVar("arch") == Arch.x86_64) {
+    if (config.arch == config.Arch.x86_64) {
         assert(aoeu() == 1234);
     }
 }
test/cases/atomics.zig
@@ -1,4 +1,5 @@
 const assert = @import("std").debug.assert;
+const AtomicOrder = @import("builtin").AtomicOrder;
 
 test "cmpxchg" {
     var x: i32 = 1234;
test/cases/misc.zig
@@ -1,6 +1,7 @@
 const assert = @import("std").debug.assert;
 const mem = @import("std").mem;
 const cstr = @import("std").cstr;
+const builtin = @import("builtin");
 
 // normal comment
 /// this is a documentation comment
@@ -12,7 +13,7 @@ test "emptyFunctionWithComments" {
 }
 
 export fn disabledExternFn() {
-    @setGlobalLinkage(disabledExternFn, GlobalLinkage.Internal);
+    @setGlobalLinkage(disabledExternFn, builtin.GlobalLinkage.Internal);
 }
 
 test "callDisabledExternFn" {
test/assemble_and_link.zig
@@ -1,7 +1,8 @@
+const builtin = @import("builtin");
 const tests = @import("tests.zig");
 
 pub fn addCases(cases: &tests.CompareOutputContext) {
-    if (@compileVar("os") == Os.linux and @compileVar("arch") == Arch.x86_64) {
+    if (builtin.os == builtin.Os.linux and builtin.arch == builtin.Arch.x86_64) {
         cases.addAsm("hello world linux x86_64",
             \\.text
             \\.globl _start
test/compile_errors.zig
@@ -688,9 +688,9 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
 
 
     cases.add("bogus compile var",
-        \\const x = @compileVar("bogus");
+        \\const x = @import("builtin").bogus;
         \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
-    , ".tmp_source.zig:1:23: error: unrecognized compile variable: 'bogus'");
+    , ".tmp_source.zig:1:29: error: no member named 'bogus' in '");
 
 
     cases.add("non constant expression in array size outside function",
@@ -910,18 +910,20 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     , ".tmp_source.zig:2:15: error: unable to infer expression type");
 
     cases.add("atomic orderings of cmpxchg - failure stricter than success",
+        \\const AtomicOrder = @import("builtin").AtomicOrder;
         \\export fn f() {
         \\    var x: i32 = 1234;
         \\    while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
         \\}
-    , ".tmp_source.zig:3:72: error: failure atomic ordering must be no stricter than success");
+    , ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success");
 
     cases.add("atomic orderings of cmpxchg - success Monotonic or stricter",
+        \\const AtomicOrder = @import("builtin").AtomicOrder;
         \\export fn f() {
         \\    var x: i32 = 1234;
         \\    while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
         \\}
-    , ".tmp_source.zig:3:49: error: success atomic ordering must be Monotonic or stricter");
+    , ".tmp_source.zig:4:49: error: success atomic ordering must be Monotonic or stricter");
 
     cases.add("negation overflow in function evaluation",
         \\const y = neg(-128);
@@ -1487,10 +1489,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
     , ".tmp_source.zig:6:5: error: unable to evaluate constant expression");
 
     cases.add("invalid member of builtin enum",
+        \\const builtin = @import("builtin");
         \\export fn entry() {
-        \\    const foo = Arch.x86;
+        \\    const foo = builtin.Arch.x86;
         \\}
-    , ".tmp_source.zig:2:21: error: container 'Arch' has no member called 'x86'");
+    , ".tmp_source.zig:3:29: error: container 'Arch' has no member called 'x86'");
 
     cases.add("int to ptr of 0 bits",
         \\export fn foo() {