authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-19 00:08:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-19 00:08:47-04:00
log1d85b588eab27830409a62e88bd8444db58787a4
treee997fbe7cad2c8c2548a9568b6c59c558ef095a7
parent7f1a550760a7a01d4ae8de51be16fb02d56b5cd2

self-hosted: progress on IR for supporting libc hello world

* add c int types * some more ir stubs

10 files changed, 879 insertions(+), 43 deletions(-)

CMakeLists.txt+1
...@@ -489,6 +489,7 @@ set(ZIG_STD_FILES...@@ -489,6 +489,7 @@ set(ZIG_STD_FILES
489 "math/atan.zig"489 "math/atan.zig"
490 "math/atan2.zig"490 "math/atan2.zig"
491 "math/atanh.zig"491 "math/atanh.zig"
492 "math/big/index.zig"
492 "math/big/int.zig"493 "math/big/int.zig"
493 "math/cbrt.zig"494 "math/cbrt.zig"
494 "math/ceil.zig"495 "math/ceil.zig"
src-self-hosted/c_int.zig created+68
...@@ -0,0 +1,68 @@
1pub const CInt = struct {
2 id: Id,
3 zig_name: []const u8,
4 c_name: []const u8,
5 is_signed: bool,
6
7 pub const Id = enum {
8 Short,
9 UShort,
10 Int,
11 UInt,
12 Long,
13 ULong,
14 LongLong,
15 ULongLong,
16 };
17
18 pub const list = []CInt{
19 CInt{
20 .id = Id.Short,
21 .zig_name = "c_short",
22 .c_name = "short",
23 .is_signed = true,
24 },
25 CInt{
26 .id = Id.UShort,
27 .zig_name = "c_ushort",
28 .c_name = "unsigned short",
29 .is_signed = false,
30 },
31 CInt{
32 .id = Id.Int,
33 .zig_name = "c_int",
34 .c_name = "int",
35 .is_signed = true,
36 },
37 CInt{
38 .id = Id.UInt,
39 .zig_name = "c_uint",
40 .c_name = "unsigned int",
41 .is_signed = false,
42 },
43 CInt{
44 .id = Id.Long,
45 .zig_name = "c_long",
46 .c_name = "long",
47 .is_signed = true,
48 },
49 CInt{
50 .id = Id.ULong,
51 .zig_name = "c_ulong",
52 .c_name = "unsigned long",
53 .is_signed = false,
54 },
55 CInt{
56 .id = Id.LongLong,
57 .zig_name = "c_longlong",
58 .c_name = "long long",
59 .is_signed = true,
60 },
61 CInt{
62 .id = Id.ULongLong,
63 .zig_name = "c_ulonglong",
64 .c_name = "unsigned long long",
65 .is_signed = false,
66 },
67 };
68};
src-self-hosted/compilation.zig+78-29
...@@ -29,6 +29,7 @@ const codegen = @import("codegen.zig");...@@ -29,6 +29,7 @@ const codegen = @import("codegen.zig");
29const Package = @import("package.zig").Package;29const Package = @import("package.zig").Package;
30const link = @import("link.zig").link;30const link = @import("link.zig").link;
31const LibCInstallation = @import("libc_installation.zig").LibCInstallation;31const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
32const CInt = @import("c_int.zig").CInt;
3233
33/// Data that is local to the event loop.34/// Data that is local to the event loop.
34pub const EventLoopLocal = struct {35pub const EventLoopLocal = struct {
...@@ -59,6 +60,7 @@ pub const EventLoopLocal = struct {...@@ -59,6 +60,7 @@ pub const EventLoopLocal = struct {
59 };60 };
60 }61 }
6162
63 /// Must be called only after EventLoop.run completes.
62 fn deinit(self: *EventLoopLocal) void {64 fn deinit(self: *EventLoopLocal) void {
63 while (self.llvm_handle_pool.pop()) |node| {65 while (self.llvm_handle_pool.pop()) |node| {
64 c.LLVMContextDispose(node.data);66 c.LLVMContextDispose(node.data);
...@@ -184,6 +186,7 @@ pub const Compilation = struct {...@@ -184,6 +186,7 @@ pub const Compilation = struct {
184 void_type: *Type.Void,186 void_type: *Type.Void,
185 bool_type: *Type.Bool,187 bool_type: *Type.Bool,
186 noreturn_type: *Type.NoReturn,188 noreturn_type: *Type.NoReturn,
189 comptime_int_type: *Type.ComptimeInt,
187190
188 void_value: *Value.Void,191 void_value: *Value.Void,
189 true_value: *Value.Bool,192 true_value: *Value.Bool,
...@@ -209,6 +212,16 @@ pub const Compilation = struct {...@@ -209,6 +212,16 @@ pub const Compilation = struct {
209212
210 have_err_ret_tracing: bool,213 have_err_ret_tracing: bool,
211214
215 /// not locked because it is read-only
216 primitive_type_table: TypeTable,
217
218 int_type_table: event.Locked(IntTypeTable),
219
220 c_int_types: [CInt.list.len]*Type.Int,
221
222 const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql);
223 const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8);
224
212 const CompileErrList = std.ArrayList(*errmsg.Msg);225 const CompileErrList = std.ArrayList(*errmsg.Msg);
213226
214 // TODO handle some of these earlier and report them in a way other than error codes227 // TODO handle some of these earlier and report them in a way other than error codes
...@@ -362,6 +375,8 @@ pub const Compilation = struct {...@@ -362,6 +375,8 @@ pub const Compilation = struct {
362 .prelink_group = event.Group(BuildError!void).init(loop),375 .prelink_group = event.Group(BuildError!void).init(loop),
363 .deinit_group = event.Group(void).init(loop),376 .deinit_group = event.Group(void).init(loop),
364 .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)),377 .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)),
378 .int_type_table = event.Locked(IntTypeTable).init(loop, IntTypeTable.init(loop.allocator)),
379 .c_int_types = undefined,
365380
366 .meta_type = undefined,381 .meta_type = undefined,
367 .void_type = undefined,382 .void_type = undefined,
...@@ -371,6 +386,7 @@ pub const Compilation = struct {...@@ -371,6 +386,7 @@ pub const Compilation = struct {
371 .false_value = undefined,386 .false_value = undefined,
372 .noreturn_type = undefined,387 .noreturn_type = undefined,
373 .noreturn_value = undefined,388 .noreturn_value = undefined,
389 .comptime_int_type = undefined,
374390
375 .target_machine = undefined,391 .target_machine = undefined,
376 .target_data_ref = undefined,392 .target_data_ref = undefined,
...@@ -382,8 +398,10 @@ pub const Compilation = struct {...@@ -382,8 +398,10 @@ pub const Compilation = struct {
382 .override_libc = null,398 .override_libc = null,
383 .destroy_handle = undefined,399 .destroy_handle = undefined,
384 .have_err_ret_tracing = false,400 .have_err_ret_tracing = false,
401 .primitive_type_table = undefined,
385 });402 });
386 errdefer {403 errdefer {
404 comp.int_type_table.private_data.deinit();
387 comp.arena_allocator.deinit();405 comp.arena_allocator.deinit();
388 comp.loop.allocator.destroy(comp);406 comp.loop.allocator.destroy(comp);
389 }407 }
...@@ -393,6 +411,7 @@ pub const Compilation = struct {...@@ -393,6 +411,7 @@ pub const Compilation = struct {
393 comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple);411 comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple);
394 comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena());412 comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena());
395 comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std");413 comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std");
414 comp.primitive_type_table = TypeTable.init(comp.arena());
396415
397 const opt_level = switch (build_mode) {416 const opt_level = switch (build_mode) {
398 builtin.Mode.Debug => llvm.CodeGenLevelNone,417 builtin.Mode.Debug => llvm.CodeGenLevelNone,
...@@ -445,7 +464,6 @@ pub const Compilation = struct {...@@ -445,7 +464,6 @@ pub const Compilation = struct {
445 }464 }
446465
447 try comp.initTypes();466 try comp.initTypes();
448 errdefer comp.derefTypes();
449467
450 comp.destroy_handle = try async<loop.allocator> comp.internalDeinit();468 comp.destroy_handle = try async<loop.allocator> comp.internalDeinit();
451469
...@@ -453,8 +471,9 @@ pub const Compilation = struct {...@@ -453,8 +471,9 @@ pub const Compilation = struct {
453 }471 }
454472
455 fn initTypes(comp: *Compilation) !void {473 fn initTypes(comp: *Compilation) !void {
456 comp.meta_type = try comp.gpa().create(Type.MetaType{474 comp.meta_type = try comp.arena().create(Type.MetaType{
457 .base = Type{475 .base = Type{
476 .name = "type",
458 .base = Value{477 .base = Value{
459 .id = Value.Id.Type,478 .id = Value.Id.Type,
460 .typeof = undefined,479 .typeof = undefined,
...@@ -466,10 +485,11 @@ pub const Compilation = struct {...@@ -466,10 +485,11 @@ pub const Compilation = struct {
466 });485 });
467 comp.meta_type.value = &comp.meta_type.base;486 comp.meta_type.value = &comp.meta_type.base;
468 comp.meta_type.base.base.typeof = &comp.meta_type.base;487 comp.meta_type.base.base.typeof = &comp.meta_type.base;
469 errdefer comp.gpa().destroy(comp.meta_type);488 assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null);
470489
471 comp.void_type = try comp.gpa().create(Type.Void{490 comp.void_type = try comp.arena().create(Type.Void{
472 .base = Type{491 .base = Type{
492 .name = "void",
473 .base = Value{493 .base = Value{
474 .id = Value.Id.Type,494 .id = Value.Id.Type,
475 .typeof = &Type.MetaType.get(comp).base,495 .typeof = &Type.MetaType.get(comp).base,
...@@ -478,10 +498,11 @@ pub const Compilation = struct {...@@ -478,10 +498,11 @@ pub const Compilation = struct {
478 .id = builtin.TypeId.Void,498 .id = builtin.TypeId.Void,
479 },499 },
480 });500 });
481 errdefer comp.gpa().destroy(comp.void_type);501 assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null);
482502
483 comp.noreturn_type = try comp.gpa().create(Type.NoReturn{503 comp.noreturn_type = try comp.arena().create(Type.NoReturn{
484 .base = Type{504 .base = Type{
505 .name = "noreturn",
485 .base = Value{506 .base = Value{
486 .id = Value.Id.Type,507 .id = Value.Id.Type,
487 .typeof = &Type.MetaType.get(comp).base,508 .typeof = &Type.MetaType.get(comp).base,
...@@ -490,10 +511,24 @@ pub const Compilation = struct {...@@ -490,10 +511,24 @@ pub const Compilation = struct {
490 .id = builtin.TypeId.NoReturn,511 .id = builtin.TypeId.NoReturn,
491 },512 },
492 });513 });
493 errdefer comp.gpa().destroy(comp.noreturn_type);514 assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null);
494515
495 comp.bool_type = try comp.gpa().create(Type.Bool{516 comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt{
496 .base = Type{517 .base = Type{
518 .name = "comptime_int",
519 .base = Value{
520 .id = Value.Id.Type,
521 .typeof = &Type.MetaType.get(comp).base,
522 .ref_count = std.atomic.Int(usize).init(1),
523 },
524 .id = builtin.TypeId.ComptimeInt,
525 },
526 });
527 assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null);
528
529 comp.bool_type = try comp.arena().create(Type.Bool{
530 .base = Type{
531 .name = "bool",
497 .base = Value{532 .base = Value{
498 .id = Value.Id.Type,533 .id = Value.Id.Type,
499 .typeof = &Type.MetaType.get(comp).base,534 .typeof = &Type.MetaType.get(comp).base,
...@@ -502,18 +537,17 @@ pub const Compilation = struct {...@@ -502,18 +537,17 @@ pub const Compilation = struct {
502 .id = builtin.TypeId.Bool,537 .id = builtin.TypeId.Bool,
503 },538 },
504 });539 });
505 errdefer comp.gpa().destroy(comp.bool_type);540 assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null);
506541
507 comp.void_value = try comp.gpa().create(Value.Void{542 comp.void_value = try comp.arena().create(Value.Void{
508 .base = Value{543 .base = Value{
509 .id = Value.Id.Void,544 .id = Value.Id.Void,
510 .typeof = &Type.Void.get(comp).base,545 .typeof = &Type.Void.get(comp).base,
511 .ref_count = std.atomic.Int(usize).init(1),546 .ref_count = std.atomic.Int(usize).init(1),
512 },547 },
513 });548 });
514 errdefer comp.gpa().destroy(comp.void_value);
515549
516 comp.true_value = try comp.gpa().create(Value.Bool{550 comp.true_value = try comp.arena().create(Value.Bool{
517 .base = Value{551 .base = Value{
518 .id = Value.Id.Bool,552 .id = Value.Id.Bool,
519 .typeof = &Type.Bool.get(comp).base,553 .typeof = &Type.Bool.get(comp).base,
...@@ -521,9 +555,8 @@ pub const Compilation = struct {...@@ -521,9 +555,8 @@ pub const Compilation = struct {
521 },555 },
522 .x = true,556 .x = true,
523 });557 });
524 errdefer comp.gpa().destroy(comp.true_value);
525558
526 comp.false_value = try comp.gpa().create(Value.Bool{559 comp.false_value = try comp.arena().create(Value.Bool{
527 .base = Value{560 .base = Value{
528 .id = Value.Id.Bool,561 .id = Value.Id.Bool,
529 .typeof = &Type.Bool.get(comp).base,562 .typeof = &Type.Bool.get(comp).base,
...@@ -531,44 +564,56 @@ pub const Compilation = struct {...@@ -531,44 +564,56 @@ pub const Compilation = struct {
531 },564 },
532 .x = false,565 .x = false,
533 });566 });
534 errdefer comp.gpa().destroy(comp.false_value);
535567
536 comp.noreturn_value = try comp.gpa().create(Value.NoReturn{568 comp.noreturn_value = try comp.arena().create(Value.NoReturn{
537 .base = Value{569 .base = Value{
538 .id = Value.Id.NoReturn,570 .id = Value.Id.NoReturn,
539 .typeof = &Type.NoReturn.get(comp).base,571 .typeof = &Type.NoReturn.get(comp).base,
540 .ref_count = std.atomic.Int(usize).init(1),572 .ref_count = std.atomic.Int(usize).init(1),
541 },573 },
542 });574 });
543 errdefer comp.gpa().destroy(comp.noreturn_value);
544 }
545575
546 fn derefTypes(self: *Compilation) void {576 for (CInt.list) |cint, i| {
547 self.noreturn_value.base.deref(self);577 const c_int_type = try comp.arena().create(Type.Int{
548 self.void_value.base.deref(self);578 .base = Type{
549 self.false_value.base.deref(self);579 .name = cint.zig_name,
550 self.true_value.base.deref(self);580 .base = Value{
551 self.noreturn_type.base.base.deref(self);581 .id = Value.Id.Type,
552 self.void_type.base.base.deref(self);582 .typeof = &Type.MetaType.get(comp).base,
553 self.meta_type.base.base.deref(self);583 .ref_count = std.atomic.Int(usize).init(1),
584 },
585 .id = builtin.TypeId.Int,
586 },
587 .key = Type.Int.Key{
588 .is_signed = cint.is_signed,
589 .bit_count = comp.target.cIntTypeSizeInBits(cint.id),
590 },
591 .garbage_node = undefined,
592 });
593 comp.c_int_types[i] = c_int_type;
594 assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null);
595 }
554 }596 }
555597
598 /// This function can safely use async/await, because it manages Compilation's lifetime,
599 /// and EventLoopLocal.deinit will not be called until the event.Loop.run() completes.
556 async fn internalDeinit(self: *Compilation) void {600 async fn internalDeinit(self: *Compilation) void {
557 suspend;601 suspend;
602
558 await (async self.deinit_group.wait() catch unreachable);603 await (async self.deinit_group.wait() catch unreachable);
559 if (self.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| {604 if (self.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| {
560 // TODO evented I/O?605 // TODO evented I/O?
561 os.deleteTree(self.arena(), tmp_dir) catch {};606 os.deleteTree(self.arena(), tmp_dir) catch {};
562 } else |_| {};607 } else |_| {};
563608
564 self.derefTypes();
565
566 self.events.destroy();609 self.events.destroy();
567610
568 llvm.DisposeMessage(self.target_layout_str);611 llvm.DisposeMessage(self.target_layout_str);
569 llvm.DisposeTargetData(self.target_data_ref);612 llvm.DisposeTargetData(self.target_data_ref);
570 llvm.DisposeTargetMachine(self.target_machine);613 llvm.DisposeTargetMachine(self.target_machine);
571614
615 self.primitive_type_table.deinit();
616
572 self.arena_allocator.deinit();617 self.arena_allocator.deinit();
573 self.gpa().destroy(self);618 self.gpa().destroy(self);
574 }619 }
...@@ -939,6 +984,10 @@ pub const Compilation = struct {...@@ -939,6 +984,10 @@ pub const Compilation = struct {
939 b64_fs_encoder.encode(result[0..], rand_bytes);984 b64_fs_encoder.encode(result[0..], rand_bytes);
940 return result;985 return result;
941 }986 }
987
988 fn registerGarbage(comp: *Compilation, comptime T: type, node: *std.atomic.Stack(*T).Node) void {
989 // TODO put the garbage somewhere
990 }
942};991};
943992
944fn printError(comptime format: []const u8, args: ...) !void {993fn printError(comptime format: []const u8, args: ...) !void {
...@@ -1005,7 +1054,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {...@@ -1005,7 +1054,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1005 fn_decl.base.parsed_file,1054 fn_decl.base.parsed_file,
1006 &fndef_scope.base,1055 &fndef_scope.base,
1007 body_node,1056 body_node,
1008 null,1057 return_type,
1009 ) catch unreachable)) orelse return;1058 ) catch unreachable)) orelse return;
1010 errdefer analyzed_code.destroy(comp.gpa());1059 errdefer analyzed_code.destroy(comp.gpa());
10111060
src-self-hosted/ir.zig+473-2
...@@ -705,7 +705,10 @@ pub const Builder = struct {...@@ -705,7 +705,10 @@ pub const Builder = struct {
705 ast.Node.Id.ErrorType => return error.Unimplemented,705 ast.Node.Id.ErrorType => return error.Unimplemented,
706 ast.Node.Id.FnProto => return error.Unimplemented,706 ast.Node.Id.FnProto => return error.Unimplemented,
707 ast.Node.Id.PromiseType => return error.Unimplemented,707 ast.Node.Id.PromiseType => return error.Unimplemented,
708 ast.Node.Id.IntegerLiteral => return error.Unimplemented,708 ast.Node.Id.IntegerLiteral => {
709 const int_lit = @fieldParentPtr(ast.Node.IntegerLiteral, "base", node);
710 return irb.lvalWrap(scope, try irb.genIntLit(int_lit, scope), lval);
711 },
709 ast.Node.Id.FloatLiteral => return error.Unimplemented,712 ast.Node.Id.FloatLiteral => return error.Unimplemented,
710 ast.Node.Id.StringLiteral => return error.Unimplemented,713 ast.Node.Id.StringLiteral => return error.Unimplemented,
711 ast.Node.Id.MultilineStringLiteral => return error.Unimplemented,714 ast.Node.Id.MultilineStringLiteral => return error.Unimplemented,
...@@ -766,6 +769,45 @@ pub const Builder = struct {...@@ -766,6 +769,45 @@ pub const Builder = struct {
766 }769 }
767 }770 }
768771
772 pub fn genIntLit(irb: *Builder, int_lit: *ast.Node.IntegerLiteral, scope: *Scope) !*Inst {
773 const int_token = irb.parsed_file.tree.tokenSlice(int_lit.token);
774
775 var base: u8 = undefined;
776 var rest: []const u8 = undefined;
777 if (int_token.len >= 3 and int_token[0] == '0') {
778 base = switch (int_token[1]) {
779 'b' => u8(2),
780 'o' => u8(8),
781 'x' => u8(16),
782 else => unreachable,
783 };
784 rest = int_token[2..];
785 } else {
786 base = 10;
787 rest = int_token;
788 }
789
790 const comptime_int_type = Type.ComptimeInt.get(irb.comp);
791 defer comptime_int_type.base.base.deref(irb.comp);
792
793 const int_val = Value.Int.createFromString(
794 irb.comp,
795 &comptime_int_type.base,
796 base,
797 rest,
798 ) catch |err| switch (err) {
799 error.OutOfMemory => return error.OutOfMemory,
800 error.InvalidBase => unreachable,
801 error.InvalidCharForDigit => unreachable,
802 error.DigitTooLargeForBase => unreachable,
803 };
804 errdefer int_val.base.deref(irb.comp);
805
806 const inst = try irb.build(Inst.Const, scope, Span.token(int_lit.token), Inst.Const.Params{});
807 inst.val = IrVal{ .KnownValue = &int_val.base };
808 return inst;
809 }
810
769 pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst {811 pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst {
770 const block_scope = try Scope.Block.create(irb.comp, parent_scope);812 const block_scope = try Scope.Block.create(irb.comp, parent_scope);
771813
...@@ -1306,7 +1348,436 @@ const Analyze = struct {...@@ -1306,7 +1348,436 @@ const Analyze = struct {
13061348
1307 fn implicitCast(self: *Analyze, target: *Inst, optional_dest_type: ?*Type) Analyze.Error!*Inst {1349 fn implicitCast(self: *Analyze, target: *Inst, optional_dest_type: ?*Type) Analyze.Error!*Inst {
1308 const dest_type = optional_dest_type orelse return target;1350 const dest_type = optional_dest_type orelse return target;
1309 return error.Unimplemented;1351 const from_type = target.getKnownType();
1352 if (from_type == dest_type or from_type.id == Type.Id.NoReturn) return target;
1353 return self.analyzeCast(target, target, dest_type);
1354 }
1355
1356 fn analyzeCast(ira: *Analyze, source_instr: *Inst, target: *Inst, dest_type: *Type) !*Inst {
1357 const from_type = target.getKnownType();
1358
1359 //if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) {
1360 // return ira->codegen->invalid_instruction;
1361 //}
1362
1363 //// perfect match or non-const to const
1364 //ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type,
1365 // source_node, false);
1366 //if (const_cast_result.id == ConstCastResultIdOk) {
1367 // return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
1368 //}
1369
1370 //// widening conversion
1371 //if (wanted_type->id == TypeTableEntryIdInt &&
1372 // actual_type->id == TypeTableEntryIdInt &&
1373 // wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
1374 // wanted_type->data.integral.bit_count >= actual_type->data.integral.bit_count)
1375 //{
1376 // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
1377 //}
1378
1379 //// small enough unsigned ints can get casted to large enough signed ints
1380 //if (wanted_type->id == TypeTableEntryIdInt && wanted_type->data.integral.is_signed &&
1381 // actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed &&
1382 // wanted_type->data.integral.bit_count > actual_type->data.integral.bit_count)
1383 //{
1384 // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
1385 //}
1386
1387 //// float widening conversion
1388 //if (wanted_type->id == TypeTableEntryIdFloat &&
1389 // actual_type->id == TypeTableEntryIdFloat &&
1390 // wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
1391 //{
1392 // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
1393 //}
1394
1395 //// cast from [N]T to []const T
1396 //if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
1397 // TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
1398 // assert(ptr_type->id == TypeTableEntryIdPointer);
1399 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
1400 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
1401 // source_node, false).id == ConstCastResultIdOk)
1402 // {
1403 // return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
1404 // }
1405 //}
1406
1407 //// cast from *const [N]T to []const T
1408 //if (is_slice(wanted_type) &&
1409 // actual_type->id == TypeTableEntryIdPointer &&
1410 // actual_type->data.pointer.is_const &&
1411 // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
1412 //{
1413 // TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
1414 // assert(ptr_type->id == TypeTableEntryIdPointer);
1415
1416 // TypeTableEntry *array_type = actual_type->data.pointer.child_type;
1417
1418 // if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
1419 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type,
1420 // source_node, false).id == ConstCastResultIdOk)
1421 // {
1422 // return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
1423 // }
1424 //}
1425
1426 //// cast from [N]T to *const []const T
1427 //if (wanted_type->id == TypeTableEntryIdPointer &&
1428 // wanted_type->data.pointer.is_const &&
1429 // is_slice(wanted_type->data.pointer.child_type) &&
1430 // actual_type->id == TypeTableEntryIdArray)
1431 //{
1432 // TypeTableEntry *ptr_type =
1433 // wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
1434 // assert(ptr_type->id == TypeTableEntryIdPointer);
1435 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
1436 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
1437 // source_node, false).id == ConstCastResultIdOk)
1438 // {
1439 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
1440 // if (type_is_invalid(cast1->value.type))
1441 // return ira->codegen->invalid_instruction;
1442
1443 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
1444 // if (type_is_invalid(cast2->value.type))
1445 // return ira->codegen->invalid_instruction;
1446
1447 // return cast2;
1448 // }
1449 //}
1450
1451 //// cast from [N]T to ?[]const T
1452 //if (wanted_type->id == TypeTableEntryIdOptional &&
1453 // is_slice(wanted_type->data.maybe.child_type) &&
1454 // actual_type->id == TypeTableEntryIdArray)
1455 //{
1456 // TypeTableEntry *ptr_type =
1457 // wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
1458 // assert(ptr_type->id == TypeTableEntryIdPointer);
1459 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
1460 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
1461 // source_node, false).id == ConstCastResultIdOk)
1462 // {
1463 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value);
1464 // if (type_is_invalid(cast1->value.type))
1465 // return ira->codegen->invalid_instruction;
1466
1467 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
1468 // if (type_is_invalid(cast2->value.type))
1469 // return ira->codegen->invalid_instruction;
1470
1471 // return cast2;
1472 // }
1473 //}
1474
1475 //// *[N]T to [*]T
1476 //if (wanted_type->id == TypeTableEntryIdPointer &&
1477 // wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
1478 // actual_type->id == TypeTableEntryIdPointer &&
1479 // actual_type->data.pointer.ptr_len == PtrLenSingle &&
1480 // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
1481 // actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment &&
1482 // types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
1483 // actual_type->data.pointer.child_type->data.array.child_type, source_node,
1484 // !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
1485 //{
1486 // return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
1487 //}
1488
1489 //// *[N]T to []T
1490 //if (is_slice(wanted_type) &&
1491 // actual_type->id == TypeTableEntryIdPointer &&
1492 // actual_type->data.pointer.ptr_len == PtrLenSingle &&
1493 // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
1494 //{
1495 // TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
1496 // assert(slice_ptr_type->id == TypeTableEntryIdPointer);
1497 // if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
1498 // actual_type->data.pointer.child_type->data.array.child_type, source_node,
1499 // !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk)
1500 // {
1501 // return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type);
1502 // }
1503 //}
1504
1505 //// cast from T to ?T
1506 //// note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism
1507 //if (wanted_type->id == TypeTableEntryIdOptional) {
1508 // TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;
1509 // if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node,
1510 // false).id == ConstCastResultIdOk)
1511 // {
1512 // return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
1513 // } else if (actual_type->id == TypeTableEntryIdComptimeInt ||
1514 // actual_type->id == TypeTableEntryIdComptimeFloat)
1515 // {
1516 // if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) {
1517 // return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
1518 // } else {
1519 // return ira->codegen->invalid_instruction;
1520 // }
1521 // } else if (wanted_child_type->id == TypeTableEntryIdPointer &&
1522 // wanted_child_type->data.pointer.is_const &&
1523 // (actual_type->id == TypeTableEntryIdPointer || is_container(actual_type)))
1524 // {
1525 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_child_type, value);
1526 // if (type_is_invalid(cast1->value.type))
1527 // return ira->codegen->invalid_instruction;
1528
1529 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
1530 // if (type_is_invalid(cast2->value.type))
1531 // return ira->codegen->invalid_instruction;
1532
1533 // return cast2;
1534 // }
1535 //}
1536
1537 //// cast from null literal to maybe type
1538 //if (wanted_type->id == TypeTableEntryIdOptional &&
1539 // actual_type->id == TypeTableEntryIdNull)
1540 //{
1541 // return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);
1542 //}
1543
1544 //// cast from child type of error type to error type
1545 //if (wanted_type->id == TypeTableEntryIdErrorUnion) {
1546 // if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,
1547 // source_node, false).id == ConstCastResultIdOk)
1548 // {
1549 // return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
1550 // } else if (actual_type->id == TypeTableEntryIdComptimeInt ||
1551 // actual_type->id == TypeTableEntryIdComptimeFloat)
1552 // {
1553 // if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) {
1554 // return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
1555 // } else {
1556 // return ira->codegen->invalid_instruction;
1557 // }
1558 // }
1559 //}
1560
1561 //// cast from [N]T to E![]const T
1562 //if (wanted_type->id == TypeTableEntryIdErrorUnion &&
1563 // is_slice(wanted_type->data.error_union.payload_type) &&
1564 // actual_type->id == TypeTableEntryIdArray)
1565 //{
1566 // TypeTableEntry *ptr_type =
1567 // wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry;
1568 // assert(ptr_type->id == TypeTableEntryIdPointer);
1569 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
1570 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
1571 // source_node, false).id == ConstCastResultIdOk)
1572 // {
1573 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
1574 // if (type_is_invalid(cast1->value.type))
1575 // return ira->codegen->invalid_instruction;
1576
1577 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
1578 // if (type_is_invalid(cast2->value.type))
1579 // return ira->codegen->invalid_instruction;
1580
1581 // return cast2;
1582 // }
1583 //}
1584
1585 //// cast from error set to error union type
1586 //if (wanted_type->id == TypeTableEntryIdErrorUnion &&
1587 // actual_type->id == TypeTableEntryIdErrorSet)
1588 //{
1589 // return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
1590 //}
1591
1592 //// cast from T to E!?T
1593 //if (wanted_type->id == TypeTableEntryIdErrorUnion &&
1594 // wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional &&
1595 // actual_type->id != TypeTableEntryIdOptional)
1596 //{
1597 // TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
1598 // if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk ||
1599 // actual_type->id == TypeTableEntryIdNull ||
1600 // actual_type->id == TypeTableEntryIdComptimeInt ||
1601 // actual_type->id == TypeTableEntryIdComptimeFloat)
1602 // {
1603 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
1604 // if (type_is_invalid(cast1->value.type))
1605 // return ira->codegen->invalid_instruction;
1606
1607 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
1608 // if (type_is_invalid(cast2->value.type))
1609 // return ira->codegen->invalid_instruction;
1610
1611 // return cast2;
1612 // }
1613 //}
1614
1615 // cast from number literal to another type
1616 //// cast from number literal to *const integer
1617 //if (actual_type->id == TypeTableEntryIdComptimeFloat ||
1618 // actual_type->id == TypeTableEntryIdComptimeInt)
1619 //{
1620 // ensure_complete_type(ira->codegen, wanted_type);
1621 // if (type_is_invalid(wanted_type))
1622 // return ira->codegen->invalid_instruction;
1623 // if (wanted_type->id == TypeTableEntryIdEnum) {
1624 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value);
1625 // if (type_is_invalid(cast1->value.type))
1626 // return ira->codegen->invalid_instruction;
1627
1628 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
1629 // if (type_is_invalid(cast2->value.type))
1630 // return ira->codegen->invalid_instruction;
1631
1632 // return cast2;
1633 // } else if (wanted_type->id == TypeTableEntryIdPointer &&
1634 // wanted_type->data.pointer.is_const)
1635 // {
1636 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
1637 // if (type_is_invalid(cast1->value.type))
1638 // return ira->codegen->invalid_instruction;
1639
1640 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
1641 // if (type_is_invalid(cast2->value.type))
1642 // return ira->codegen->invalid_instruction;
1643
1644 // return cast2;
1645 // } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
1646 // CastOp op;
1647 // if ((actual_type->id == TypeTableEntryIdComptimeFloat &&
1648 // wanted_type->id == TypeTableEntryIdFloat) ||
1649 // (actual_type->id == TypeTableEntryIdComptimeInt &&
1650 // wanted_type->id == TypeTableEntryIdInt))
1651 // {
1652 // op = CastOpNumLitToConcrete;
1653 // } else if (wanted_type->id == TypeTableEntryIdInt) {
1654 // op = CastOpFloatToInt;
1655 // } else if (wanted_type->id == TypeTableEntryIdFloat) {
1656 // op = CastOpIntToFloat;
1657 // } else {
1658 // zig_unreachable();
1659 // }
1660 // return ir_resolve_cast(ira, source_instr, value, wanted_type, op, false);
1661 // } else {
1662 // return ira->codegen->invalid_instruction;
1663 // }
1664 //}
1665
1666 //// cast from typed number to integer or float literal.
1667 //// works when the number is known at compile time
1668 //if (instr_is_comptime(value) &&
1669 // ((actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdComptimeInt) ||
1670 // (actual_type->id == TypeTableEntryIdFloat && wanted_type->id == TypeTableEntryIdComptimeFloat)))
1671 //{
1672 // return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);
1673 //}
1674
1675 //// cast from union to the enum type of the union
1676 //if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) {
1677 // type_ensure_zero_bits_known(ira->codegen, actual_type);
1678 // if (type_is_invalid(actual_type))
1679 // return ira->codegen->invalid_instruction;
1680
1681 // if (actual_type->data.unionation.tag_type == wanted_type) {
1682 // return ir_analyze_union_to_tag(ira, source_instr, value, wanted_type);
1683 // }
1684 //}
1685
1686 //// enum to union which has the enum as the tag type
1687 //if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
1688 // (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
1689 // wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
1690 //{
1691 // type_ensure_zero_bits_known(ira->codegen, wanted_type);
1692 // if (wanted_type->data.unionation.tag_type == actual_type) {
1693 // return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type);
1694 // }
1695 //}
1696
1697 //// enum to &const union which has the enum as the tag type
1698 //if (actual_type->id == TypeTableEntryIdEnum && wanted_type->id == TypeTableEntryIdPointer) {
1699 // TypeTableEntry *union_type = wanted_type->data.pointer.child_type;
1700 // if (union_type->data.unionation.decl_node->data.container_decl.auto_enum ||
1701 // union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)
1702 // {
1703 // type_ensure_zero_bits_known(ira->codegen, union_type);
1704 // if (union_type->data.unionation.tag_type == actual_type) {
1705 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, union_type, value);
1706 // if (type_is_invalid(cast1->value.type))
1707 // return ira->codegen->invalid_instruction;
1708
1709 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
1710 // if (type_is_invalid(cast2->value.type))
1711 // return ira->codegen->invalid_instruction;
1712
1713 // return cast2;
1714 // }
1715 // }
1716 //}
1717
1718 //// cast from *T to *[1]T
1719 //if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
1720 // actual_type->id == TypeTableEntryIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle)
1721 //{
1722 // TypeTableEntry *array_type = wanted_type->data.pointer.child_type;
1723 // if (array_type->id == TypeTableEntryIdArray && array_type->data.array.len == 1 &&
1724 // types_match_const_cast_only(ira, array_type->data.array.child_type,
1725 // actual_type->data.pointer.child_type, source_node,
1726 // !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
1727 // {
1728 // if (wanted_type->data.pointer.alignment > actual_type->data.pointer.alignment) {
1729 // ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
1730 // add_error_note(ira->codegen, msg, value->source_node,
1731 // buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name),
1732 // actual_type->data.pointer.alignment));
1733 // add_error_note(ira->codegen, msg, source_instr->source_node,
1734 // buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name),
1735 // wanted_type->data.pointer.alignment));
1736 // return ira->codegen->invalid_instruction;
1737 // }
1738 // return ir_analyze_ptr_to_array(ira, source_instr, value, wanted_type);
1739 // }
1740 //}
1741
1742 //// cast from T to *T where T is zero bits
1743 //if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
1744 // types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
1745 // actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
1746 //{
1747 // type_ensure_zero_bits_known(ira->codegen, actual_type);
1748 // if (type_is_invalid(actual_type)) {
1749 // return ira->codegen->invalid_instruction;
1750 // }
1751 // if (!type_has_bits(actual_type)) {
1752 // return ir_get_ref(ira, source_instr, value, false, false);
1753 // }
1754 //}
1755
1756 //// cast from undefined to anything
1757 //if (actual_type->id == TypeTableEntryIdUndefined) {
1758 // return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
1759 //}
1760
1761 //// cast from something to const pointer of it
1762 //if (!type_requires_comptime(actual_type)) {
1763 // TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
1764 // if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node, false).id == ConstCastResultIdOk) {
1765 // return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);
1766 // }
1767 //}
1768
1769 try ira.addCompileError(
1770 source_instr.span,
1771 "expected type '{}', found '{}'",
1772 dest_type.name,
1773 from_type.name,
1774 );
1775 //ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node,
1776 // buf_sprintf("expected type '%s', found '%s'",
1777 // buf_ptr(&wanted_type->name),
1778 // buf_ptr(&actual_type->name)));
1779 //report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg);
1780 return error.SemanticAnalysisFailed;
1310 }1781 }
13111782
1312 fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Inst) ?*Value {1783 fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Inst) ?*Value {
src-self-hosted/llvm.zig+2
...@@ -30,6 +30,8 @@ pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;...@@ -30,6 +30,8 @@ pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
30pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;30pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
31pub const ConstAllOnes = c.LLVMConstAllOnes;31pub const ConstAllOnes = c.LLVMConstAllOnes;
32pub const ConstInt = c.LLVMConstInt;32pub const ConstInt = c.LLVMConstInt;
33pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
34pub const ConstNeg = c.LLVMConstNeg;
33pub const ConstNull = c.LLVMConstNull;35pub const ConstNull = c.LLVMConstNull;
34pub const ConstStringInContext = c.LLVMConstStringInContext;36pub const ConstStringInContext = c.LLVMConstStringInContext;
35pub const ConstStructInContext = c.LLVMConstStructInContext;37pub const ConstStructInContext = c.LLVMConstStructInContext;
src-self-hosted/target.zig+98-1
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const llvm = @import("llvm.zig");3const llvm = @import("llvm.zig");
4const CInt = @import("c_int.zig").CInt;
45
5pub const FloatAbi = enum {6pub const FloatAbi = enum {
6 Hard,7 Hard,
...@@ -173,7 +174,7 @@ pub const Target = union(enum) {...@@ -173,7 +174,7 @@ pub const Target = union(enum) {
173 return self.getArchPtrBitWidth() == 64;174 return self.getArchPtrBitWidth() == 64;
174 }175 }
175176
176 pub fn getArchPtrBitWidth(self: Target) u8 {177 pub fn getArchPtrBitWidth(self: Target) u32 {
177 switch (self.getArch()) {178 switch (self.getArch()) {
178 builtin.Arch.avr,179 builtin.Arch.avr,
179 builtin.Arch.msp430,180 builtin.Arch.msp430,
...@@ -429,4 +430,100 @@ pub const Target = union(enum) {...@@ -429,4 +430,100 @@ pub const Target = union(enum) {
429 }430 }
430 return result;431 return result;
431 }432 }
433
434 pub fn cIntTypeSizeInBits(self: Target, id: CInt.Id) u32 {
435 const arch = self.getArch();
436 switch (self.getOs()) {
437 builtin.Os.freestanding => switch (self.getArch()) {
438 builtin.Arch.msp430 => switch (id) {
439 CInt.Id.Short,
440 CInt.Id.UShort,
441 CInt.Id.Int,
442 CInt.Id.UInt,
443 => return 16,
444 CInt.Id.Long,
445 CInt.Id.ULong,
446 => return 32,
447 CInt.Id.LongLong,
448 CInt.Id.ULongLong,
449 => return 64,
450 },
451 else => switch (id) {
452 CInt.Id.Short,
453 CInt.Id.UShort,
454 => return 16,
455 CInt.Id.Int,
456 CInt.Id.UInt,
457 => return 32,
458 CInt.Id.Long,
459 CInt.Id.ULong,
460 => return self.getArchPtrBitWidth(),
461 CInt.Id.LongLong,
462 CInt.Id.ULongLong,
463 => return 64,
464 },
465 },
466
467 builtin.Os.linux,
468 builtin.Os.macosx,
469 builtin.Os.openbsd,
470 builtin.Os.zen,
471 => switch (id) {
472 CInt.Id.Short,
473 CInt.Id.UShort,
474 => return 16,
475 CInt.Id.Int,
476 CInt.Id.UInt,
477 => return 32,
478 CInt.Id.Long,
479 CInt.Id.ULong,
480 => return self.getArchPtrBitWidth(),
481 CInt.Id.LongLong,
482 CInt.Id.ULongLong,
483 => return 64,
484 },
485
486 builtin.Os.windows => switch (id) {
487 CInt.Id.Short,
488 CInt.Id.UShort,
489 => return 16,
490 CInt.Id.Int,
491 CInt.Id.UInt,
492 => return 32,
493 CInt.Id.Long,
494 CInt.Id.ULong,
495 CInt.Id.LongLong,
496 CInt.Id.ULongLong,
497 => return 64,
498 },
499
500 builtin.Os.ananas,
501 builtin.Os.cloudabi,
502 builtin.Os.dragonfly,
503 builtin.Os.freebsd,
504 builtin.Os.fuchsia,
505 builtin.Os.ios,
506 builtin.Os.kfreebsd,
507 builtin.Os.lv2,
508 builtin.Os.netbsd,
509 builtin.Os.solaris,
510 builtin.Os.haiku,
511 builtin.Os.minix,
512 builtin.Os.rtems,
513 builtin.Os.nacl,
514 builtin.Os.cnk,
515 builtin.Os.aix,
516 builtin.Os.cuda,
517 builtin.Os.nvcl,
518 builtin.Os.amdhsa,
519 builtin.Os.ps4,
520 builtin.Os.elfiamcu,
521 builtin.Os.tvos,
522 builtin.Os.watchos,
523 builtin.Os.mesa3d,
524 builtin.Os.contiki,
525 builtin.Os.amdpal,
526 => @panic("TODO specify the C integer type sizes for this OS"),
527 }
528 }
432};529};
src-self-hosted/type.zig+88-10
...@@ -9,6 +9,7 @@ const ObjectFile = @import("codegen.zig").ObjectFile;...@@ -9,6 +9,7 @@ const ObjectFile = @import("codegen.zig").ObjectFile;
9pub const Type = struct {9pub const Type = struct {
10 base: Value,10 base: Value,
11 id: Id,11 id: Id,
12 name: []const u8,
1213
13 pub const Id = builtin.TypeId;14 pub const Id = builtin.TypeId;
1415
...@@ -151,6 +152,18 @@ pub const Type = struct {...@@ -151,6 +152,18 @@ pub const Type = struct {
151 std.debug.warn("{}", @tagName(base.id));152 std.debug.warn("{}", @tagName(base.id));
152 }153 }
153154
155 fn init(base: *Type, comp: *Compilation, id: Id, name: []const u8) void {
156 base.* = Type{
157 .base = Value{
158 .id = Value.Id.Type,
159 .typeof = &MetaType.get(comp).base,
160 .ref_count = std.atomic.Int(usize).init(1),
161 },
162 .id = id,
163 .name = name,
164 };
165 }
166
154 pub fn getAbiAlignment(base: *Type, comp: *Compilation) u32 {167 pub fn getAbiAlignment(base: *Type, comp: *Compilation) u32 {
155 @panic("TODO getAbiAlignment");168 @panic("TODO getAbiAlignment");
156 }169 }
...@@ -181,20 +194,15 @@ pub const Type = struct {...@@ -181,20 +194,15 @@ pub const Type = struct {
181194
182 pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn {195 pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn {
183 const result = try comp.gpa().create(Fn{196 const result = try comp.gpa().create(Fn{
184 .base = Type{197 .base = undefined,
185 .base = Value{
186 .id = Value.Id.Type,
187 .typeof = &MetaType.get(comp).base,
188 .ref_count = std.atomic.Int(usize).init(1),
189 },
190 .id = builtin.TypeId.Fn,
191 },
192 .return_type = return_type,198 .return_type = return_type,
193 .params = params,199 .params = params,
194 .is_var_args = is_var_args,200 .is_var_args = is_var_args,
195 });201 });
196 errdefer comp.gpa().destroy(result);202 errdefer comp.gpa().destroy(result);
197203
204 result.base.init(comp, Id.Fn, "TODO fn type name");
205
198 result.return_type.base.ref();206 result.return_type.base.ref();
199 for (result.params) |param| {207 for (result.params) |param| {
200 param.typeof.base.ref();208 param.typeof.base.ref();
...@@ -293,13 +301,77 @@ pub const Type = struct {...@@ -293,13 +301,77 @@ pub const Type = struct {
293301
294 pub const Int = struct {302 pub const Int = struct {
295 base: Type,303 base: Type,
304 key: Key,
305 garbage_node: std.atomic.Stack(*Int).Node,
306
307 pub const Key = struct {
308 bit_count: u32,
309 is_signed: bool,
310
311 pub fn hash(self: *const Key) u32 {
312 const rands = [2]u32{ 0xa4ba6498, 0x75fc5af7 };
313 return rands[@boolToInt(self.is_signed)] *% self.bit_count;
314 }
315
316 pub fn eql(self: *const Key, other: *const Key) bool {
317 return self.bit_count == other.bit_count and self.is_signed == other.is_signed;
318 }
319 };
320
321 pub async fn get(comp: *Compilation, key: Key) !*Int {
322 {
323 const held = await (async comp.int_type_table.acquire() catch unreachable);
324 defer held.release();
325
326 if (held.value.get(&key)) |entry| {
327 return entry.value;
328 }
329 }
330
331 const self = try comp.gpa().create(Int{
332 .base = undefined,
333 .key = key,
334 .garbage_node = undefined,
335 });
336 errdefer comp.gpa().destroy(self);
337
338 const u_or_i = "ui"[@boolToInt(key.is_signed)];
339 const name = std.fmt.allocPrint(comp.gpa(), "{c}{}", u_or_i, key.bit_count);
340 errdefer comp.gpa().free(name);
341
342 self.base.init(comp, Id.Int, name);
343
344 {
345 const held = await (async comp.int_type_table.acquire() catch unreachable);
346 defer held.release();
347
348 held.value.put(&self.key, self);
349 }
350 return self;
351 }
296352
297 pub fn destroy(self: *Int, comp: *Compilation) void {353 pub fn destroy(self: *Int, comp: *Compilation) void {
354 self.garbage_node = std.atomic.Stack(*Int).Node{
355 .data = self,
356 .next = undefined,
357 };
358 comp.registerGarbage(Int, &self.garbage_node);
359 }
360
361 pub async fn gcDestroy(self: *Int, comp: *Compilation) void {
362 {
363 const held = await (async comp.int_type_table.acquire() catch unreachable);
364 defer held.release();
365
366 _ = held.value.remove(&self.key).?;
367 }
368 // we allocated the name
369 comp.gpa().free(self.base.name);
298 comp.gpa().destroy(self);370 comp.gpa().destroy(self);
299 }371 }
300372
301 pub fn getLlvmType(self: *Int, ofile: *ObjectFile) llvm.TypeRef {373 pub fn getLlvmType(self: *Int, ofile: *ObjectFile) !llvm.TypeRef {
302 @panic("TODO");374 return llvm.IntTypeInContext(ofile.context, self.key.bit_count) orelse return error.OutOfMemory;
303 }375 }
304 };376 };
305377
...@@ -374,6 +446,12 @@ pub const Type = struct {...@@ -374,6 +446,12 @@ pub const Type = struct {
374 pub const ComptimeInt = struct {446 pub const ComptimeInt = struct {
375 base: Type,447 base: Type,
376448
449 /// Adds 1 reference to the resulting type
450 pub fn get(comp: *Compilation) *ComptimeInt {
451 comp.comptime_int_type.base.base.ref();
452 return comp.comptime_int_type;
453 }
454
377 pub fn destroy(self: *ComptimeInt, comp: *Compilation) void {455 pub fn destroy(self: *ComptimeInt, comp: *Compilation) void {
378 comp.gpa().destroy(self);456 comp.gpa().destroy(self);
379 }457 }
src-self-hosted/value.zig+58
...@@ -29,6 +29,7 @@ pub const Value = struct {...@@ -29,6 +29,7 @@ pub const Value = struct {
29 Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp),29 Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp),
30 Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp),30 Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp),
31 Id.Ptr => @fieldParentPtr(Ptr, "base", base).destroy(comp),31 Id.Ptr => @fieldParentPtr(Ptr, "base", base).destroy(comp),
32 Id.Int => @fieldParentPtr(Int, "base", base).destroy(comp),
32 }33 }
33 }34 }
34 }35 }
...@@ -50,6 +51,7 @@ pub const Value = struct {...@@ -50,6 +51,7 @@ pub const Value = struct {
50 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),51 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),
51 Id.NoReturn => unreachable,52 Id.NoReturn => unreachable,
52 Id.Ptr => @panic("TODO"),53 Id.Ptr => @panic("TODO"),
54 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmConst(ofile),
53 }55 }
54 }56 }
5557
...@@ -60,6 +62,7 @@ pub const Value = struct {...@@ -60,6 +62,7 @@ pub const Value = struct {
60 Bool,62 Bool,
61 NoReturn,63 NoReturn,
62 Ptr,64 Ptr,
65 Int,
63 };66 };
6467
65 pub const Type = @import("type.zig").Type;68 pub const Type = @import("type.zig").Type;
...@@ -198,4 +201,59 @@ pub const Value = struct {...@@ -198,4 +201,59 @@ pub const Value = struct {
198 comp.gpa().destroy(self);201 comp.gpa().destroy(self);
199 }202 }
200 };203 };
204
205 pub const Int = struct {
206 base: Value,
207 big_int: std.math.big.Int,
208
209 pub fn createFromString(comp: *Compilation, typeof: *Type, base: u8, value: []const u8) !*Int {
210 const self = try comp.gpa().create(Value.Int{
211 .base = Value{
212 .id = Value.Id.Int,
213 .typeof = typeof,
214 .ref_count = std.atomic.Int(usize).init(1),
215 },
216 .big_int = undefined,
217 });
218 typeof.base.ref();
219 errdefer comp.gpa().destroy(self);
220
221 self.big_int = try std.math.big.Int.init(comp.gpa());
222 errdefer self.big_int.deinit();
223
224 try self.big_int.setString(base, value);
225
226 return self;
227 }
228
229 pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef {
230 switch (self.base.typeof.id) {
231 Type.Id.Int => {
232 const type_ref = try self.base.typeof.getLlvmType(ofile);
233 if (self.big_int.len == 0) {
234 return llvm.ConstNull(type_ref);
235 }
236 const unsigned_val = if (self.big_int.len == 1) blk: {
237 break :blk llvm.ConstInt(type_ref, self.big_int.limbs[0], @boolToInt(false));
238 } else if (@sizeOf(std.math.big.Limb) == @sizeOf(u64)) blk: {
239 break :blk llvm.ConstIntOfArbitraryPrecision(
240 type_ref,
241 @intCast(c_uint, self.big_int.len),
242 @ptrCast([*]u64, self.big_int.limbs.ptr),
243 );
244 } else {
245 @compileError("std.math.Big.Int.Limb size does not match LLVM");
246 };
247 return if (self.big_int.positive) unsigned_val else llvm.ConstNeg(unsigned_val);
248 },
249 Type.Id.ComptimeInt => unreachable,
250 else => unreachable,
251 }
252 }
253
254 pub fn destroy(self: *Int, comp: *Compilation) void {
255 self.big_int.deinit();
256 comp.gpa().destroy(self);
257 }
258 };
201};259};
std/event/group.zig+11
...@@ -38,6 +38,15 @@ pub fn Group(comptime ReturnType: type) type {...@@ -38,6 +38,15 @@ pub fn Group(comptime ReturnType: type) type {
38 self.alloc_stack.push(node);38 self.alloc_stack.push(node);
39 }39 }
4040
41 /// Add a node to the group. Thread-safe. Cannot fail.
42 /// `node.data` should be the promise handle to add to the group.
43 /// The node's memory should be in the coroutine frame of
44 /// the handle that is in the node, or somewhere guaranteed to live
45 /// at least as long.
46 pub fn addNode(self: *Self, node: *Stack.Node) void {
47 self.coro_stack.push(node);
48 }
49
41 /// This is equivalent to an async call, but the async function is added to the group, instead50 /// This is equivalent to an async call, but the async function is added to the group, instead
42 /// of returning a promise. func must be async and have return type ReturnType.51 /// of returning a promise. func must be async and have return type ReturnType.
43 /// Thread-safe.52 /// Thread-safe.
...@@ -98,6 +107,8 @@ pub fn Group(comptime ReturnType: type) type {...@@ -98,6 +107,8 @@ pub fn Group(comptime ReturnType: type) type {
98 }107 }
99108
100 /// Cancel all the outstanding promises. May only be called if wait was never called.109 /// Cancel all the outstanding promises. May only be called if wait was never called.
110 /// TODO These should be `cancelasync` not `cancel`.
111 /// See https://github.com/ziglang/zig/issues/1261
101 pub fn cancelAll(self: *Self) void {112 pub fn cancelAll(self: *Self) void {
102 while (self.coro_stack.pop()) |node| {113 while (self.coro_stack.pop()) |node| {
103 cancel node.data;114 cancel node.data;
std/math/big/int.zig+2-1
...@@ -60,8 +60,9 @@ pub const Int = struct {...@@ -60,8 +60,9 @@ pub const Int = struct {
60 self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity);60 self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity);
61 }61 }
6262
63 pub fn deinit(self: Int) void {63 pub fn deinit(self: *Int) void {
64 self.allocator.free(self.limbs);64 self.allocator.free(self.limbs);
65 self.* = undefined;
65 }66 }
6667
67 pub fn clone(other: Int) !Int {68 pub fn clone(other: Int) !Int {