| author | |
| committer | |
| log | 558b0b87913dfb6e6b76f5dbe2c36b920302faab |
| tree | 40153dfe995f127577db5e277cbec618aff2c30e |
| parent | 2255f275a0397ac44a5e8bc907643082fe304336 |
| parent | d3ce9d0643421da77063472cb1124123cda753bb |
25 files changed, 486 insertions(+), 130 deletions(-)
doc/langref.html.in+6-6| ... | ... | @@ -2310,11 +2310,11 @@ test "while loop continue expression" { |
| 2310 | 2310 | } |
| 2311 | 2311 | |
| 2312 | 2312 | test "while loop continue expression, more complicated" { |
| 2313 | var i1: usize = 1; | |
| 2314 | var j1: usize = 1; | |
| 2315 | while (i1 * j1 < 2000) : ({ i1 *= 2; j1 *= 3; }) { | |
| 2316 | const my_ij1 = i1 * j1; | |
| 2317 | assert(my_ij1 < 2000); | |
| 2313 | var i: usize = 1; | |
| 2314 | var j: usize = 1; | |
| 2315 | while (i * j < 2000) : ({ i *= 2; j *= 3; }) { | |
| 2316 | const my_ij = i * j; | |
| 2317 | assert(my_ij < 2000); | |
| 2318 | 2318 | } |
| 2319 | 2319 | } |
| 2320 | 2320 | {#code_end#} |
| ... | ... | @@ -5424,7 +5424,7 @@ fn add(a: i32, b: i32) i32 { return a + b; } |
| 5424 | 5424 | {#header_close#} |
| 5425 | 5425 | |
| 5426 | 5426 | {#header_open|@IntType#} |
| 5427 | <pre><code class="zig">@IntType(comptime is_signed: bool, comptime bit_count: u8) type</code></pre> | |
| 5427 | <pre><code class="zig">@IntType(comptime is_signed: bool, comptime bit_count: u32) type</code></pre> | |
| 5428 | 5428 | <p> |
| 5429 | 5429 | This function returns an integer type with the given signness and bit count. |
| 5430 | 5430 | </p> |
src-self-hosted/codegen.zig+157-1| ... | ... | @@ -8,6 +8,7 @@ const ir = @import("ir.zig"); |
| 8 | 8 | const Value = @import("value.zig").Value; |
| 9 | 9 | const Type = @import("type.zig").Type; |
| 10 | 10 | const event = std.event; |
| 11 | const assert = std.debug.assert; | |
| 11 | 12 | |
| 12 | 13 | pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) !void { |
| 13 | 14 | fn_val.base.ref(); |
| ... | ... | @@ -35,9 +36,23 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) |
| 35 | 36 | |
| 36 | 37 | try renderToLlvmModule(&ofile, fn_val, code); |
| 37 | 38 | |
| 39 | // TODO module level assembly | |
| 40 | //if (buf_len(&g->global_asm) != 0) { | |
| 41 | // LLVMSetModuleInlineAsm(g->module, buf_ptr(&g->global_asm)); | |
| 42 | //} | |
| 43 | ||
| 44 | // TODO | |
| 45 | //ZigLLVMDIBuilderFinalize(g->dbuilder); | |
| 46 | ||
| 38 | 47 | if (comp.verbose_llvm_ir) { |
| 39 | 48 | llvm.DumpModule(ofile.module); |
| 40 | 49 | } |
| 50 | ||
| 51 | // verify the llvm module when safety is on | |
| 52 | if (std.debug.runtime_safety) { | |
| 53 | var error_ptr: ?[*]u8 = null; | |
| 54 | _ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr); | |
| 55 | } | |
| 41 | 56 | } |
| 42 | 57 | |
| 43 | 58 | pub const ObjectFile = struct { |
| ... | ... | @@ -55,5 +70,146 @@ pub const ObjectFile = struct { |
| 55 | 70 | pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) !void { |
| 56 | 71 | // TODO audit more of codegen.cpp:fn_llvm_value and port more logic |
| 57 | 72 | const llvm_fn_type = try fn_val.base.typeof.getLlvmType(ofile); |
| 58 | const llvm_fn = llvm.AddFunction(ofile.module, fn_val.symbol_name.ptr(), llvm_fn_type); | |
| 73 | const llvm_fn = llvm.AddFunction( | |
| 74 | ofile.module, | |
| 75 | fn_val.symbol_name.ptr(), | |
| 76 | llvm_fn_type, | |
| 77 | ) orelse return error.OutOfMemory; | |
| 78 | ||
| 79 | const want_fn_safety = fn_val.block_scope.safety.get(ofile.comp); | |
| 80 | if (want_fn_safety and ofile.comp.haveLibC()) { | |
| 81 | try addLLVMFnAttr(ofile, llvm_fn, "sspstrong"); | |
| 82 | try addLLVMFnAttrStr(ofile, llvm_fn, "stack-protector-buffer-size", "4"); | |
| 83 | } | |
| 84 | ||
| 85 | // TODO | |
| 86 | //if (fn_val.align_stack) |align_stack| { | |
| 87 | // try addLLVMFnAttrInt(ofile, llvm_fn, "alignstack", align_stack); | |
| 88 | //} | |
| 89 | ||
| 90 | const fn_type = fn_val.base.typeof.cast(Type.Fn).?; | |
| 91 | ||
| 92 | try addLLVMFnAttr(ofile, llvm_fn, "nounwind"); | |
| 93 | //add_uwtable_attr(g, fn_table_entry->llvm_value); | |
| 94 | try addLLVMFnAttr(ofile, llvm_fn, "nobuiltin"); | |
| 95 | ||
| 96 | //if (g->build_mode == BuildModeDebug && fn_table_entry->fn_inline != FnInlineAlways) { | |
| 97 | // ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true"); | |
| 98 | // ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr); | |
| 99 | //} | |
| 100 | ||
| 101 | //if (fn_table_entry->section_name) { | |
| 102 | // LLVMSetSection(fn_table_entry->llvm_value, buf_ptr(fn_table_entry->section_name)); | |
| 103 | //} | |
| 104 | //if (fn_table_entry->align_bytes > 0) { | |
| 105 | // LLVMSetAlignment(fn_table_entry->llvm_value, (unsigned)fn_table_entry->align_bytes); | |
| 106 | //} else { | |
| 107 | // // We'd like to set the best alignment for the function here, but on Darwin LLVM gives | |
| 108 | // // "Cannot getTypeInfo() on a type that is unsized!" assertion failure when calling | |
| 109 | // // any of the functions for getting alignment. Not specifying the alignment should | |
| 110 | // // use the ABI alignment, which is fine. | |
| 111 | //} | |
| 112 | ||
| 113 | //if (!type_has_bits(return_type)) { | |
| 114 | // // nothing to do | |
| 115 | //} else if (type_is_codegen_pointer(return_type)) { | |
| 116 | // addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); | |
| 117 | //} else if (handle_is_ptr(return_type) && | |
| 118 | // calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc)) | |
| 119 | //{ | |
| 120 | // addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); | |
| 121 | // addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); | |
| 122 | //} | |
| 123 | ||
| 124 | // TODO set parameter attributes | |
| 125 | ||
| 126 | // TODO | |
| 127 | //uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); | |
| 128 | //if (err_ret_trace_arg_index != UINT32_MAX) { | |
| 129 | // addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull"); | |
| 130 | //} | |
| 131 | ||
| 132 | const cur_ret_ptr = if (fn_type.return_type.handleIsPtr()) llvm.GetParam(llvm_fn, 0) else null; | |
| 133 | ||
| 134 | // build all basic blocks | |
| 135 | for (code.basic_block_list.toSlice()) |bb| { | |
| 136 | bb.llvm_block = llvm.AppendBasicBlockInContext( | |
| 137 | ofile.context, | |
| 138 | llvm_fn, | |
| 139 | bb.name_hint, | |
| 140 | ) orelse return error.OutOfMemory; | |
| 141 | } | |
| 142 | const entry_bb = code.basic_block_list.at(0); | |
| 143 | llvm.PositionBuilderAtEnd(ofile.builder, entry_bb.llvm_block); | |
| 144 | ||
| 145 | llvm.ClearCurrentDebugLocation(ofile.builder); | |
| 146 | ||
| 147 | // TODO set up error return tracing | |
| 148 | // TODO allocate temporary stack values | |
| 149 | // TODO create debug variable declarations for variables and allocate all local variables | |
| 150 | // TODO finishing error return trace setup. we have to do this after all the allocas. | |
| 151 | // TODO create debug variable declarations for parameters | |
| 152 | ||
| 153 | for (code.basic_block_list.toSlice()) |current_block| { | |
| 154 | llvm.PositionBuilderAtEnd(ofile.builder, current_block.llvm_block); | |
| 155 | for (current_block.instruction_list.toSlice()) |instruction| { | |
| 156 | if (instruction.ref_count == 0 and !instruction.hasSideEffects()) continue; | |
| 157 | ||
| 158 | instruction.llvm_value = try instruction.render(ofile, fn_val); | |
| 159 | } | |
| 160 | current_block.llvm_exit_block = llvm.GetInsertBlock(ofile.builder); | |
| 161 | } | |
| 162 | } | |
| 163 | ||
| 164 | fn addLLVMAttr( | |
| 165 | ofile: *ObjectFile, | |
| 166 | val: llvm.ValueRef, | |
| 167 | attr_index: llvm.AttributeIndex, | |
| 168 | attr_name: []const u8, | |
| 169 | ) !void { | |
| 170 | const kind_id = llvm.GetEnumAttributeKindForName(attr_name.ptr, attr_name.len); | |
| 171 | assert(kind_id != 0); | |
| 172 | const llvm_attr = llvm.CreateEnumAttribute(ofile.context, kind_id, 0) orelse return error.OutOfMemory; | |
| 173 | llvm.AddAttributeAtIndex(val, attr_index, llvm_attr); | |
| 174 | } | |
| 175 | ||
| 176 | fn addLLVMAttrStr( | |
| 177 | ofile: *ObjectFile, | |
| 178 | val: llvm.ValueRef, | |
| 179 | attr_index: llvm.AttributeIndex, | |
| 180 | attr_name: []const u8, | |
| 181 | attr_val: []const u8, | |
| 182 | ) !void { | |
| 183 | const llvm_attr = llvm.CreateStringAttribute( | |
| 184 | ofile.context, | |
| 185 | attr_name.ptr, | |
| 186 | @intCast(c_uint, attr_name.len), | |
| 187 | attr_val.ptr, | |
| 188 | @intCast(c_uint, attr_val.len), | |
| 189 | ) orelse return error.OutOfMemory; | |
| 190 | llvm.AddAttributeAtIndex(val, attr_index, llvm_attr); | |
| 191 | } | |
| 192 | ||
| 193 | fn addLLVMAttrInt( | |
| 194 | val: llvm.ValueRef, | |
| 195 | attr_index: llvm.AttributeIndex, | |
| 196 | attr_name: []const u8, | |
| 197 | attr_val: u64, | |
| 198 | ) !void { | |
| 199 | const kind_id = llvm.GetEnumAttributeKindForName(attr_name.ptr, attr_name.len); | |
| 200 | assert(kind_id != 0); | |
| 201 | const llvm_attr = llvm.CreateEnumAttribute(ofile.context, kind_id, attr_val) orelse return error.OutOfMemory; | |
| 202 | llvm.AddAttributeAtIndex(val, attr_index, llvm_attr); | |
| 203 | } | |
| 204 | ||
| 205 | fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8) !void { | |
| 206 | return addLLVMAttr(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name); | |
| 207 | } | |
| 208 | ||
| 209 | fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: []const u8) !void { | |
| 210 | return addLLVMAttrStr(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name, attr_val); | |
| 211 | } | |
| 212 | ||
| 213 | fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void { | |
| 214 | return addLLVMAttrInt(ofile, fn_val, @maxValue(llvm.AttributeIndex), attr_name, attr_val); | |
| 59 | 215 | } |
src-self-hosted/compilation.zig+5-1| ... | ... | @@ -606,6 +606,10 @@ pub const Compilation = struct { |
| 606 | 606 | return error.Todo; |
| 607 | 607 | } |
| 608 | 608 | |
| 609 | pub fn haveLibC(self: *Compilation) bool { | |
| 610 | return self.libc_link_lib != null; | |
| 611 | } | |
| 612 | ||
| 609 | 613 | pub fn addLinkLib(self: *Compilation, name: []const u8, provided_explicitly: bool) !*LinkLib { |
| 610 | 614 | const is_libc = mem.eql(u8, name, "c"); |
| 611 | 615 | |
| ... | ... | @@ -741,7 +745,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 741 | 745 | analyzed_code.dump(); |
| 742 | 746 | } |
| 743 | 747 | |
| 744 | // Kick off rendering to LLVM comp, but it doesn't block the fn decl | |
| 748 | // Kick off rendering to LLVM module, but it doesn't block the fn decl | |
| 745 | 749 | // analysis from being complete. |
| 746 | 750 | try comp.build_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code); |
| 747 | 751 | } |
src-self-hosted/ir.zig+48-8| ... | ... | @@ -10,6 +10,8 @@ const assert = std.debug.assert; |
| 10 | 10 | const Token = std.zig.Token; |
| 11 | 11 | const ParsedFile = @import("parsed_file.zig").ParsedFile; |
| 12 | 12 | const Span = @import("errmsg.zig").Span; |
| 13 | const llvm = @import("llvm.zig"); | |
| 14 | const ObjectFile = @import("codegen.zig").ObjectFile; | |
| 13 | 15 | |
| 14 | 16 | pub const LVal = enum { |
| 15 | 17 | None, |
| ... | ... | @@ -61,6 +63,9 @@ pub const Instruction = struct { |
| 61 | 63 | /// the instruction that this one derives from in analysis |
| 62 | 64 | parent: ?*Instruction, |
| 63 | 65 | |
| 66 | /// populated durign codegen | |
| 67 | llvm_value: ?llvm.ValueRef, | |
| 68 | ||
| 64 | 69 | pub fn cast(base: *Instruction, comptime T: type) ?*T { |
| 65 | 70 | if (base.id == comptime typeToId(T)) { |
| 66 | 71 | return @fieldParentPtr(T, "base", base); |
| ... | ... | @@ -108,14 +113,25 @@ pub const Instruction = struct { |
| 108 | 113 | inline while (i < @memberCount(Id)) : (i += 1) { |
| 109 | 114 | if (base.id == @field(Id, @memberName(Id, i))) { |
| 110 | 115 | const T = @field(Instruction, @memberName(Id, i)); |
| 111 | const new_inst = try @fieldParentPtr(T, "base", base).analyze(ira); | |
| 112 | new_inst.linkToParent(base); | |
| 113 | return new_inst; | |
| 116 | return @fieldParentPtr(T, "base", base).analyze(ira); | |
| 114 | 117 | } |
| 115 | 118 | } |
| 116 | 119 | unreachable; |
| 117 | 120 | } |
| 118 | 121 | |
| 122 | pub fn render(base: *Instruction, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) { | |
| 123 | switch (base.id) { | |
| 124 | Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val), | |
| 125 | Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val), | |
| 126 | Id.Ref => @panic("TODO"), | |
| 127 | Id.DeclVar => @panic("TODO"), | |
| 128 | Id.CheckVoidStmt => @panic("TODO"), | |
| 129 | Id.Phi => @panic("TODO"), | |
| 130 | Id.Br => @panic("TODO"), | |
| 131 | Id.AddImplicitReturnType => @panic("TODO"), | |
| 132 | } | |
| 133 | } | |
| 134 | ||
| 119 | 135 | fn getAsParam(param: *Instruction) !*Instruction { |
| 120 | 136 | const child = param.child orelse return error.SemanticAnalysisFailed; |
| 121 | 137 | switch (child.val) { |
| ... | ... | @@ -186,6 +202,10 @@ pub const Instruction = struct { |
| 186 | 202 | new_inst.val = IrVal{ .KnownValue = self.base.val.KnownValue.getRef() }; |
| 187 | 203 | return new_inst; |
| 188 | 204 | } |
| 205 | ||
| 206 | pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { | |
| 207 | return self.base.val.KnownValue.getLlvmConst(ofile); | |
| 208 | } | |
| 189 | 209 | }; |
| 190 | 210 | |
| 191 | 211 | pub const Return = struct { |
| ... | ... | @@ -214,6 +234,18 @@ pub const Instruction = struct { |
| 214 | 234 | |
| 215 | 235 | return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value }); |
| 216 | 236 | } |
| 237 | ||
| 238 | pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) ?llvm.ValueRef { | |
| 239 | const value = self.params.return_value.llvm_value; | |
| 240 | const return_type = self.params.return_value.getKnownType(); | |
| 241 | ||
| 242 | if (return_type.handleIsPtr()) { | |
| 243 | @panic("TODO"); | |
| 244 | } else { | |
| 245 | _ = llvm.BuildRet(ofile.builder, value); | |
| 246 | } | |
| 247 | return null; | |
| 248 | } | |
| 217 | 249 | }; |
| 218 | 250 | |
| 219 | 251 | pub const Ref = struct { |
| ... | ... | @@ -387,12 +419,16 @@ pub const Variable = struct { |
| 387 | 419 | |
| 388 | 420 | pub const BasicBlock = struct { |
| 389 | 421 | ref_count: usize, |
| 390 | name_hint: []const u8, | |
| 422 | name_hint: [*]const u8, // must be a C string literal | |
| 391 | 423 | debug_id: usize, |
| 392 | 424 | scope: *Scope, |
| 393 | 425 | instruction_list: std.ArrayList(*Instruction), |
| 394 | 426 | ref_instruction: ?*Instruction, |
| 395 | 427 | |
| 428 | /// for codegen | |
| 429 | llvm_block: llvm.BasicBlockRef, | |
| 430 | llvm_exit_block: llvm.BasicBlockRef, | |
| 431 | ||
| 396 | 432 | /// the basic block that is derived from this one in analysis |
| 397 | 433 | child: ?*BasicBlock, |
| 398 | 434 | |
| ... | ... | @@ -426,7 +462,7 @@ pub const Code = struct { |
| 426 | 462 | pub fn dump(self: *Code) void { |
| 427 | 463 | var bb_i: usize = 0; |
| 428 | 464 | for (self.basic_block_list.toSliceConst()) |bb| { |
| 429 | std.debug.warn("{}_{}:\n", bb.name_hint, bb.debug_id); | |
| 465 | std.debug.warn("{s}_{}:\n", bb.name_hint, bb.debug_id); | |
| 430 | 466 | for (bb.instruction_list.toSliceConst()) |instr| { |
| 431 | 467 | std.debug.warn(" "); |
| 432 | 468 | instr.dump(); |
| ... | ... | @@ -475,7 +511,7 @@ pub const Builder = struct { |
| 475 | 511 | } |
| 476 | 512 | |
| 477 | 513 | /// No need to clean up resources thanks to the arena allocator. |
| 478 | pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: []const u8) !*BasicBlock { | |
| 514 | pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock { | |
| 479 | 515 | const basic_block = try self.arena().create(BasicBlock{ |
| 480 | 516 | .ref_count = 0, |
| 481 | 517 | .name_hint = name_hint, |
| ... | ... | @@ -485,6 +521,8 @@ pub const Builder = struct { |
| 485 | 521 | .child = null, |
| 486 | 522 | .parent = null, |
| 487 | 523 | .ref_instruction = null, |
| 524 | .llvm_block = undefined, | |
| 525 | .llvm_exit_block = undefined, | |
| 488 | 526 | }); |
| 489 | 527 | self.next_debug_id += 1; |
| 490 | 528 | return basic_block; |
| ... | ... | @@ -600,7 +638,7 @@ pub const Builder = struct { |
| 600 | 638 | if (block.label) |label| { |
| 601 | 639 | block_scope.incoming_values = std.ArrayList(*Instruction).init(irb.arena()); |
| 602 | 640 | block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena()); |
| 603 | block_scope.end_block = try irb.createBasicBlock(parent_scope, "BlockEnd"); | |
| 641 | block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd"); | |
| 604 | 642 | block_scope.is_comptime = try irb.buildConstBool( |
| 605 | 643 | parent_scope, |
| 606 | 644 | Span.token(block.lbrace), |
| ... | ... | @@ -777,6 +815,7 @@ pub const Builder = struct { |
| 777 | 815 | .span = span, |
| 778 | 816 | .child = null, |
| 779 | 817 | .parent = null, |
| 818 | .llvm_value = undefined, | |
| 780 | 819 | }, |
| 781 | 820 | .params = params, |
| 782 | 821 | }); |
| ... | ... | @@ -968,7 +1007,7 @@ pub async fn gen( |
| 968 | 1007 | var irb = try Builder.init(comp, parsed_file); |
| 969 | 1008 | errdefer irb.abort(); |
| 970 | 1009 | |
| 971 | const entry_block = try irb.createBasicBlock(scope, "Entry"); | |
| 1010 | const entry_block = try irb.createBasicBlock(scope, c"Entry"); | |
| 972 | 1011 | entry_block.ref(); // Entry block gets a reference because we enter it to begin. |
| 973 | 1012 | try irb.setCursorAtEndAndAppendBlock(entry_block); |
| 974 | 1013 | |
| ... | ... | @@ -1013,6 +1052,7 @@ pub async fn analyze(comp: *Compilation, parsed_file: *ParsedFile, old_code: *Co |
| 1013 | 1052 | } |
| 1014 | 1053 | |
| 1015 | 1054 | const return_inst = try old_instruction.analyze(&ira); |
| 1055 | return_inst.linkToParent(old_instruction); | |
| 1016 | 1056 | // Note: if we ever modify the above to handle error.CompileError by continuing analysis, |
| 1017 | 1057 | // then here we want to check if ira.isCompTime() and return early if true |
| 1018 | 1058 |
src-self-hosted/llvm.zig+63-1| ... | ... | @@ -2,29 +2,91 @@ const builtin = @import("builtin"); |
| 2 | 2 | const c = @import("c.zig"); |
| 3 | 3 | const assert = @import("std").debug.assert; |
| 4 | 4 | |
| 5 | pub const AttributeIndex = c_uint; | |
| 6 | pub const Bool = c_int; | |
| 7 | ||
| 5 | 8 | pub const BuilderRef = removeNullability(c.LLVMBuilderRef); |
| 6 | 9 | pub const ContextRef = removeNullability(c.LLVMContextRef); |
| 7 | 10 | pub const ModuleRef = removeNullability(c.LLVMModuleRef); |
| 8 | 11 | pub const ValueRef = removeNullability(c.LLVMValueRef); |
| 9 | 12 | pub const TypeRef = removeNullability(c.LLVMTypeRef); |
| 13 | pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef); | |
| 14 | pub const AttributeRef = removeNullability(c.LLVMAttributeRef); | |
| 10 | 15 | |
| 16 | pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex; | |
| 11 | 17 | pub const AddFunction = c.LLVMAddFunction; |
| 18 | pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; | |
| 19 | pub const ConstInt = c.LLVMConstInt; | |
| 20 | pub const ConstStringInContext = c.LLVMConstStringInContext; | |
| 21 | pub const ConstStructInContext = c.LLVMConstStructInContext; | |
| 12 | 22 | pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext; |
| 23 | pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute; | |
| 24 | pub const CreateStringAttribute = c.LLVMCreateStringAttribute; | |
| 13 | 25 | pub const DisposeBuilder = c.LLVMDisposeBuilder; |
| 14 | 26 | pub const DisposeModule = c.LLVMDisposeModule; |
| 27 | pub const DoubleTypeInContext = c.LLVMDoubleTypeInContext; | |
| 15 | 28 | pub const DumpModule = c.LLVMDumpModule; |
| 29 | pub const FP128TypeInContext = c.LLVMFP128TypeInContext; | |
| 30 | pub const FloatTypeInContext = c.LLVMFloatTypeInContext; | |
| 31 | pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName; | |
| 32 | pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext; | |
| 33 | pub const HalfTypeInContext = c.LLVMHalfTypeInContext; | |
| 34 | pub const InsertBasicBlockInContext = c.LLVMInsertBasicBlockInContext; | |
| 35 | pub const Int128TypeInContext = c.LLVMInt128TypeInContext; | |
| 36 | pub const Int16TypeInContext = c.LLVMInt16TypeInContext; | |
| 37 | pub const Int1TypeInContext = c.LLVMInt1TypeInContext; | |
| 38 | pub const Int32TypeInContext = c.LLVMInt32TypeInContext; | |
| 39 | pub const Int64TypeInContext = c.LLVMInt64TypeInContext; | |
| 40 | pub const Int8TypeInContext = c.LLVMInt8TypeInContext; | |
| 41 | pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext; | |
| 42 | pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext; | |
| 43 | pub const IntTypeInContext = c.LLVMIntTypeInContext; | |
| 44 | pub const LabelTypeInContext = c.LLVMLabelTypeInContext; | |
| 45 | pub const MDNodeInContext = c.LLVMMDNodeInContext; | |
| 46 | pub const MDStringInContext = c.LLVMMDStringInContext; | |
| 47 | pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext; | |
| 16 | 48 | pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext; |
| 49 | pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext; | |
| 50 | pub const StructTypeInContext = c.LLVMStructTypeInContext; | |
| 51 | pub const TokenTypeInContext = c.LLVMTokenTypeInContext; | |
| 17 | 52 | pub const VoidTypeInContext = c.LLVMVoidTypeInContext; |
| 53 | pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext; | |
| 54 | pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext; | |
| 55 | pub const ConstAllOnes = c.LLVMConstAllOnes; | |
| 56 | pub const ConstNull = c.LLVMConstNull; | |
| 57 | ||
| 58 | pub const VerifyModule = LLVMVerifyModule; | |
| 59 | extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool; | |
| 60 | ||
| 61 | pub const GetInsertBlock = LLVMGetInsertBlock; | |
| 62 | extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef; | |
| 18 | 63 | |
| 19 | 64 | pub const FunctionType = LLVMFunctionType; |
| 20 | 65 | extern fn LLVMFunctionType( |
| 21 | 66 | ReturnType: TypeRef, |
| 22 | 67 | ParamTypes: [*]TypeRef, |
| 23 | 68 | ParamCount: c_uint, |
| 24 | IsVarArg: c_int, | |
| 69 | IsVarArg: Bool, | |
| 25 | 70 | ) ?TypeRef; |
| 26 | 71 | |
| 72 | pub const GetParam = LLVMGetParam; | |
| 73 | extern fn LLVMGetParam(Fn: ValueRef, Index: c_uint) ValueRef; | |
| 74 | ||
| 75 | pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext; | |
| 76 | extern fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: [*]const u8) ?BasicBlockRef; | |
| 77 | ||
| 78 | pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd; | |
| 79 | extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void; | |
| 80 | ||
| 81 | pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction; | |
| 82 | pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction; | |
| 83 | pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction; | |
| 84 | pub const VerifierFailureAction = c.LLVMVerifierFailureAction; | |
| 85 | ||
| 27 | 86 | fn removeNullability(comptime T: type) type { |
| 28 | 87 | comptime assert(@typeId(T) == builtin.TypeId.Optional); |
| 29 | 88 | return T.Child; |
| 30 | 89 | } |
| 90 | ||
| 91 | pub const BuildRet = LLVMBuildRet; | |
| 92 | extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ValueRef; |
src-self-hosted/scope.zig+32| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | const Allocator = mem.Allocator; |
| 3 | 4 | const Decl = @import("decl.zig").Decl; |
| 4 | 5 | const Compilation = @import("compilation.zig").Compilation; |
| ... | ... | @@ -6,6 +7,7 @@ const mem = std.mem; |
| 6 | 7 | const ast = std.zig.ast; |
| 7 | 8 | const Value = @import("value.zig").Value; |
| 8 | 9 | const ir = @import("ir.zig"); |
| 10 | const Span = @import("errmsg.zig").Span; | |
| 9 | 11 | |
| 10 | 12 | pub const Scope = struct { |
| 11 | 13 | id: Id, |
| ... | ... | @@ -93,6 +95,35 @@ pub const Scope = struct { |
| 93 | 95 | end_block: *ir.BasicBlock, |
| 94 | 96 | is_comptime: *ir.Instruction, |
| 95 | 97 | |
| 98 | safety: Safety, | |
| 99 | ||
| 100 | const Safety = union(enum) { | |
| 101 | Auto, | |
| 102 | Manual: Manual, | |
| 103 | ||
| 104 | const Manual = struct { | |
| 105 | /// the source span that disabled the safety value | |
| 106 | span: Span, | |
| 107 | ||
| 108 | /// whether safety is enabled | |
| 109 | enabled: bool, | |
| 110 | }; | |
| 111 | ||
| 112 | fn get(self: Safety, comp: *Compilation) bool { | |
| 113 | return switch (self) { | |
| 114 | Safety.Auto => switch (comp.build_mode) { | |
| 115 | builtin.Mode.Debug, | |
| 116 | builtin.Mode.ReleaseSafe, | |
| 117 | => true, | |
| 118 | builtin.Mode.ReleaseFast, | |
| 119 | builtin.Mode.ReleaseSmall, | |
| 120 | => false, | |
| 121 | }, | |
| 122 | @TagType(Safety).Manual => |man| man.enabled, | |
| 123 | }; | |
| 124 | } | |
| 125 | }; | |
| 126 | ||
| 96 | 127 | /// Creates a Block scope with 1 reference |
| 97 | 128 | pub fn create(comp: *Compilation, parent: ?*Scope) !*Block { |
| 98 | 129 | const self = try comp.a().create(Block{ |
| ... | ... | @@ -105,6 +136,7 @@ pub const Scope = struct { |
| 105 | 136 | .incoming_blocks = undefined, |
| 106 | 137 | .end_block = undefined, |
| 107 | 138 | .is_comptime = undefined, |
| 139 | .safety = Safety.Auto, | |
| 108 | 140 | }); |
| 109 | 141 | errdefer comp.a().destroy(self); |
| 110 | 142 |
src-self-hosted/type.zig+75| ... | ... | @@ -72,6 +72,81 @@ pub const Type = struct { |
| 72 | 72 | } |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | pub fn handleIsPtr(base: *Type) bool { | |
| 76 | switch (base.id) { | |
| 77 | Id.Type, | |
| 78 | Id.ComptimeFloat, | |
| 79 | Id.ComptimeInt, | |
| 80 | Id.Undefined, | |
| 81 | Id.Null, | |
| 82 | Id.Namespace, | |
| 83 | Id.Block, | |
| 84 | Id.BoundFn, | |
| 85 | Id.ArgTuple, | |
| 86 | Id.Opaque, | |
| 87 | => unreachable, | |
| 88 | ||
| 89 | Id.NoReturn, | |
| 90 | Id.Void, | |
| 91 | Id.Bool, | |
| 92 | Id.Int, | |
| 93 | Id.Float, | |
| 94 | Id.Pointer, | |
| 95 | Id.ErrorSet, | |
| 96 | Id.Enum, | |
| 97 | Id.Fn, | |
| 98 | Id.Promise, | |
| 99 | => return false, | |
| 100 | ||
| 101 | Id.Struct => @panic("TODO"), | |
| 102 | Id.Array => @panic("TODO"), | |
| 103 | Id.Optional => @panic("TODO"), | |
| 104 | Id.ErrorUnion => @panic("TODO"), | |
| 105 | Id.Union => @panic("TODO"), | |
| 106 | } | |
| 107 | } | |
| 108 | ||
| 109 | pub fn hasBits(base: *Type) bool { | |
| 110 | switch (base.id) { | |
| 111 | Id.Type, | |
| 112 | Id.ComptimeFloat, | |
| 113 | Id.ComptimeInt, | |
| 114 | Id.Undefined, | |
| 115 | Id.Null, | |
| 116 | Id.Namespace, | |
| 117 | Id.Block, | |
| 118 | Id.BoundFn, | |
| 119 | Id.ArgTuple, | |
| 120 | Id.Opaque, | |
| 121 | => unreachable, | |
| 122 | ||
| 123 | Id.Void, | |
| 124 | Id.NoReturn, | |
| 125 | => return false, | |
| 126 | ||
| 127 | Id.Bool, | |
| 128 | Id.Int, | |
| 129 | Id.Float, | |
| 130 | Id.Fn, | |
| 131 | Id.Promise, | |
| 132 | => return true, | |
| 133 | ||
| 134 | Id.ErrorSet => @panic("TODO"), | |
| 135 | Id.Enum => @panic("TODO"), | |
| 136 | Id.Pointer => @panic("TODO"), | |
| 137 | Id.Struct => @panic("TODO"), | |
| 138 | Id.Array => @panic("TODO"), | |
| 139 | Id.Optional => @panic("TODO"), | |
| 140 | Id.ErrorUnion => @panic("TODO"), | |
| 141 | Id.Union => @panic("TODO"), | |
| 142 | } | |
| 143 | } | |
| 144 | ||
| 145 | pub fn cast(base: *Type, comptime T: type) ?*T { | |
| 146 | if (base.id != @field(Id, @typeName(T))) return null; | |
| 147 | return @fieldParentPtr(T, "base", base); | |
| 148 | } | |
| 149 | ||
| 75 | 150 | pub fn dump(base: *const Type) void { |
| 76 | 151 | std.debug.warn("{}", @tagName(base.id)); |
| 77 | 152 | } |
src-self-hosted/value.zig+22| ... | ... | @@ -2,6 +2,8 @@ const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | const Scope = @import("scope.zig").Scope; |
| 4 | 4 | const Compilation = @import("compilation.zig").Compilation; |
| 5 | const ObjectFile = @import("codegen.zig").ObjectFile; | |
| 6 | const llvm = @import("llvm.zig"); | |
| 5 | 7 | |
| 6 | 8 | /// Values are ref-counted, heap-allocated, and copy-on-write |
| 7 | 9 | /// If there is only 1 ref then write need not copy |
| ... | ... | @@ -39,6 +41,17 @@ pub const Value = struct { |
| 39 | 41 | std.debug.warn("{}", @tagName(base.id)); |
| 40 | 42 | } |
| 41 | 43 | |
| 44 | pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) { | |
| 45 | switch (base.id) { | |
| 46 | Id.Type => unreachable, | |
| 47 | Id.Fn => @panic("TODO"), | |
| 48 | Id.Void => return null, | |
| 49 | Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile), | |
| 50 | Id.NoReturn => unreachable, | |
| 51 | Id.Ptr => @panic("TODO"), | |
| 52 | } | |
| 53 | } | |
| 54 | ||
| 42 | 55 | pub const Id = enum { |
| 43 | 56 | Type, |
| 44 | 57 | Fn, |
| ... | ... | @@ -123,6 +136,15 @@ pub const Value = struct { |
| 123 | 136 | pub fn destroy(self: *Bool, comp: *Compilation) void { |
| 124 | 137 | comp.a().destroy(self); |
| 125 | 138 | } |
| 139 | ||
| 140 | pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef { | |
| 141 | const llvm_type = llvm.Int1TypeInContext(ofile.context); | |
| 142 | if (self.x) { | |
| 143 | return llvm.ConstAllOnes(llvm_type); | |
| 144 | } else { | |
| 145 | return llvm.ConstNull(llvm_type); | |
| 146 | } | |
| 147 | } | |
| 126 | 148 | }; |
| 127 | 149 | |
| 128 | 150 | pub const NoReturn = struct { |
src/all_types.hpp-4| ... | ... | @@ -1587,7 +1587,6 @@ struct CodeGen { |
| 1587 | 1587 | |
| 1588 | 1588 | struct { |
| 1589 | 1589 | TypeTableEntry *entry_bool; |
| 1590 | TypeTableEntry *entry_int[2][12]; // [signed,unsigned][2,3,4,5,6,7,8,16,29,32,64,128] | |
| 1591 | 1590 | TypeTableEntry *entry_c_int[CIntTypeCount]; |
| 1592 | 1591 | TypeTableEntry *entry_c_longdouble; |
| 1593 | 1592 | TypeTableEntry *entry_c_void; |
| ... | ... | @@ -1596,12 +1595,9 @@ struct CodeGen { |
| 1596 | 1595 | TypeTableEntry *entry_u32; |
| 1597 | 1596 | TypeTableEntry *entry_u29; |
| 1598 | 1597 | TypeTableEntry *entry_u64; |
| 1599 | TypeTableEntry *entry_u128; | |
| 1600 | 1598 | TypeTableEntry *entry_i8; |
| 1601 | TypeTableEntry *entry_i16; | |
| 1602 | 1599 | TypeTableEntry *entry_i32; |
| 1603 | 1600 | TypeTableEntry *entry_i64; |
| 1604 | TypeTableEntry *entry_i128; | |
| 1605 | 1601 | TypeTableEntry *entry_isize; |
| 1606 | 1602 | TypeTableEntry *entry_usize; |
| 1607 | 1603 | TypeTableEntry *entry_f16; |
src/analyze.cpp+31-42| ... | ... | @@ -3227,9 +3227,8 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { |
| 3227 | 3227 | } |
| 3228 | 3228 | |
| 3229 | 3229 | { |
| 3230 | auto entry = g->primitive_type_table.maybe_get(tld->name); | |
| 3231 | if (entry) { | |
| 3232 | TypeTableEntry *type = entry->value; | |
| 3230 | TypeTableEntry *type = get_primitive_type(g, tld->name); | |
| 3231 | if (type != nullptr) { | |
| 3233 | 3232 | add_node_error(g, tld->source_node, |
| 3234 | 3233 | buf_sprintf("declaration shadows type '%s'", buf_ptr(&type->name))); |
| 3235 | 3234 | } |
| ... | ... | @@ -3474,9 +3473,8 @@ VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent |
| 3474 | 3473 | add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); |
| 3475 | 3474 | variable_entry->value->type = g->builtin_types.entry_invalid; |
| 3476 | 3475 | } else { |
| 3477 | auto primitive_table_entry = g->primitive_type_table.maybe_get(name); | |
| 3478 | if (primitive_table_entry) { | |
| 3479 | TypeTableEntry *type = primitive_table_entry->value; | |
| 3476 | TypeTableEntry *type = get_primitive_type(g, name); | |
| 3477 | if (type != nullptr) { | |
| 3480 | 3478 | add_node_error(g, source_node, |
| 3481 | 3479 | buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); |
| 3482 | 3480 | variable_entry->value->type = g->builtin_types.entry_invalid; |
| ... | ... | @@ -4307,43 +4305,7 @@ void semantic_analyze(CodeGen *g) { |
| 4307 | 4305 | } |
| 4308 | 4306 | } |
| 4309 | 4307 | |
| 4310 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_bits) { | |
| 4311 | size_t index; | |
| 4312 | if (size_in_bits == 2) { | |
| 4313 | index = 0; | |
| 4314 | } else if (size_in_bits == 3) { | |
| 4315 | index = 1; | |
| 4316 | } else if (size_in_bits == 4) { | |
| 4317 | index = 2; | |
| 4318 | } else if (size_in_bits == 5) { | |
| 4319 | index = 3; | |
| 4320 | } else if (size_in_bits == 6) { | |
| 4321 | index = 4; | |
| 4322 | } else if (size_in_bits == 7) { | |
| 4323 | index = 5; | |
| 4324 | } else if (size_in_bits == 8) { | |
| 4325 | index = 6; | |
| 4326 | } else if (size_in_bits == 16) { | |
| 4327 | index = 7; | |
| 4328 | } else if (size_in_bits == 29) { | |
| 4329 | index = 8; | |
| 4330 | } else if (size_in_bits == 32) { | |
| 4331 | index = 9; | |
| 4332 | } else if (size_in_bits == 64) { | |
| 4333 | index = 10; | |
| 4334 | } else if (size_in_bits == 128) { | |
| 4335 | index = 11; | |
| 4336 | } else { | |
| 4337 | return nullptr; | |
| 4338 | } | |
| 4339 | return &g->builtin_types.entry_int[is_signed ? 0 : 1][index]; | |
| 4340 | } | |
| 4341 | ||
| 4342 | 4308 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { |
| 4343 | TypeTableEntry **common_entry = get_int_type_ptr(g, is_signed, size_in_bits); | |
| 4344 | if (common_entry) | |
| 4345 | return *common_entry; | |
| 4346 | ||
| 4347 | 4309 | TypeId type_id = {}; |
| 4348 | 4310 | type_id.id = TypeTableEntryIdInt; |
| 4349 | 4311 | type_id.data.integer.is_signed = is_signed; |
| ... | ... | @@ -4953,6 +4915,8 @@ bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type) { |
| 4953 | 4915 | while (scope) { |
| 4954 | 4916 | if (scope->id == ScopeIdVarDecl) { |
| 4955 | 4917 | ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; |
| 4918 | if (type_is_invalid(var_scope->var->value->type)) | |
| 4919 | return false; | |
| 4956 | 4920 | if (can_mutate_comptime_var_state(var_scope->var->value)) |
| 4957 | 4921 | return false; |
| 4958 | 4922 | } else if (scope->id == ScopeIdFnDef) { |
| ... | ... | @@ -6310,3 +6274,28 @@ bool type_can_fail(TypeTableEntry *type_entry) { |
| 6310 | 6274 | bool fn_type_can_fail(FnTypeId *fn_type_id) { |
| 6311 | 6275 | return type_can_fail(fn_type_id->return_type) || fn_type_id->cc == CallingConventionAsync; |
| 6312 | 6276 | } |
| 6277 | ||
| 6278 | TypeTableEntry *get_primitive_type(CodeGen *g, Buf *name) { | |
| 6279 | if (buf_len(name) >= 2) { | |
| 6280 | uint8_t first_c = buf_ptr(name)[0]; | |
| 6281 | if (first_c == 'i' || first_c == 'u') { | |
| 6282 | for (size_t i = 1; i < buf_len(name); i += 1) { | |
| 6283 | uint8_t c = buf_ptr(name)[i]; | |
| 6284 | if (c < '0' || c > '9') { | |
| 6285 | goto not_integer; | |
| 6286 | } | |
| 6287 | } | |
| 6288 | bool is_signed = (first_c == 'i'); | |
| 6289 | uint32_t bit_count = atoi(buf_ptr(name) + 1); | |
| 6290 | return get_int_type(g, is_signed, bit_count); | |
| 6291 | } | |
| 6292 | } | |
| 6293 | ||
| 6294 | not_integer: | |
| 6295 | ||
| 6296 | auto primitive_table_entry = g->primitive_type_table.maybe_get(name); | |
| 6297 | if (primitive_table_entry != nullptr) { | |
| 6298 | return primitive_table_entry->value; | |
| 6299 | } | |
| 6300 | return nullptr; | |
| 6301 | } |
src/analyze.hpp+2-1| ... | ... | @@ -19,7 +19,6 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type |
| 19 | 19 | bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count); |
| 20 | 20 | uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry); |
| 21 | 21 | uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry); |
| 22 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_bits); | |
| 23 | 22 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); |
| 24 | 23 | TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); |
| 25 | 24 | TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type); |
| ... | ... | @@ -204,4 +203,6 @@ bool type_can_fail(TypeTableEntry *type_entry); |
| 204 | 203 | bool fn_eval_cacheable(Scope *scope, TypeTableEntry *return_type); |
| 205 | 204 | AstNode *type_decl_node(TypeTableEntry *type_entry); |
| 206 | 205 | |
| 206 | TypeTableEntry *get_primitive_type(CodeGen *g, Buf *name); | |
| 207 | ||
| 207 | 208 | #endif |
src/codegen.cpp-28| ... | ... | @@ -5973,21 +5973,6 @@ static void do_code_gen(CodeGen *g) { |
| 5973 | 5973 | } |
| 5974 | 5974 | } |
| 5975 | 5975 | |
| 5976 | static const uint8_t int_sizes_in_bits[] = { | |
| 5977 | 2, | |
| 5978 | 3, | |
| 5979 | 4, | |
| 5980 | 5, | |
| 5981 | 6, | |
| 5982 | 7, | |
| 5983 | 8, | |
| 5984 | 16, | |
| 5985 | 29, | |
| 5986 | 32, | |
| 5987 | 64, | |
| 5988 | 128, | |
| 5989 | }; | |
| 5990 | ||
| 5991 | 5976 | struct CIntTypeInfo { |
| 5992 | 5977 | CIntType id; |
| 5993 | 5978 | const char *name; |
| ... | ... | @@ -6072,16 +6057,6 @@ static void define_builtin_types(CodeGen *g) { |
| 6072 | 6057 | g->builtin_types.entry_arg_tuple = entry; |
| 6073 | 6058 | } |
| 6074 | 6059 | |
| 6075 | for (size_t int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) { | |
| 6076 | uint8_t size_in_bits = int_sizes_in_bits[int_size_i]; | |
| 6077 | for (size_t is_sign_i = 0; is_sign_i < array_length(is_signed_list); is_sign_i += 1) { | |
| 6078 | bool is_signed = is_signed_list[is_sign_i]; | |
| 6079 | TypeTableEntry *entry = make_int_type(g, is_signed, size_in_bits); | |
| 6080 | g->primitive_type_table.put(&entry->name, entry); | |
| 6081 | get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry; | |
| 6082 | } | |
| 6083 | } | |
| 6084 | ||
| 6085 | 6060 | for (size_t i = 0; i < array_length(c_int_type_infos); i += 1) { |
| 6086 | 6061 | const CIntTypeInfo *info = &c_int_type_infos[i]; |
| 6087 | 6062 | uint32_t size_in_bits = target_c_type_size_in_bits(&g->zig_target, info->id); |
| ... | ... | @@ -6197,12 +6172,9 @@ static void define_builtin_types(CodeGen *g) { |
| 6197 | 6172 | g->builtin_types.entry_u29 = get_int_type(g, false, 29); |
| 6198 | 6173 | g->builtin_types.entry_u32 = get_int_type(g, false, 32); |
| 6199 | 6174 | g->builtin_types.entry_u64 = get_int_type(g, false, 64); |
| 6200 | g->builtin_types.entry_u128 = get_int_type(g, false, 128); | |
| 6201 | 6175 | g->builtin_types.entry_i8 = get_int_type(g, true, 8); |
| 6202 | g->builtin_types.entry_i16 = get_int_type(g, true, 16); | |
| 6203 | 6176 | g->builtin_types.entry_i32 = get_int_type(g, true, 32); |
| 6204 | 6177 | g->builtin_types.entry_i64 = get_int_type(g, true, 64); |
| 6205 | g->builtin_types.entry_i128 = get_int_type(g, true, 128); | |
| 6206 | 6178 | |
| 6207 | 6179 | { |
| 6208 | 6180 | g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void"); |
src/ir.cpp+12-9| ... | ... | @@ -3217,9 +3217,8 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco |
| 3217 | 3217 | add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); |
| 3218 | 3218 | variable_entry->value->type = codegen->builtin_types.entry_invalid; |
| 3219 | 3219 | } else { |
| 3220 | auto primitive_table_entry = codegen->primitive_type_table.maybe_get(name); | |
| 3221 | if (primitive_table_entry) { | |
| 3222 | TypeTableEntry *type = primitive_table_entry->value; | |
| 3220 | TypeTableEntry *type = get_primitive_type(codegen, name); | |
| 3221 | if (type != nullptr) { | |
| 3223 | 3222 | add_node_error(codegen, node, |
| 3224 | 3223 | buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); |
| 3225 | 3224 | variable_entry->value->type = codegen->builtin_types.entry_invalid; |
| ... | ... | @@ -3661,9 +3660,9 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3661 | 3660 | return &const_instruction->base; |
| 3662 | 3661 | } |
| 3663 | 3662 | |
| 3664 | auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(variable_name); | |
| 3665 | if (primitive_table_entry) { | |
| 3666 | IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_table_entry->value); | |
| 3663 | TypeTableEntry *primitive_type = get_primitive_type(irb->codegen, variable_name); | |
| 3664 | if (primitive_type != nullptr) { | |
| 3665 | IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type); | |
| 3667 | 3666 | if (lval == LValPtr) { |
| 3668 | 3667 | return ir_build_ref(irb, scope, node, value, false, false); |
| 3669 | 3668 | } else { |
| ... | ... | @@ -10691,11 +10690,11 @@ static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out |
| 10691 | 10690 | return true; |
| 10692 | 10691 | } |
| 10693 | 10692 | |
| 10694 | static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) { | |
| 10693 | static bool ir_resolve_unsigned(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *int_type, uint64_t *out) { | |
| 10695 | 10694 | if (type_is_invalid(value->value.type)) |
| 10696 | 10695 | return false; |
| 10697 | 10696 | |
| 10698 | IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_usize); | |
| 10697 | IrInstruction *casted_value = ir_implicit_cast(ira, value, int_type); | |
| 10699 | 10698 | if (type_is_invalid(casted_value->value.type)) |
| 10700 | 10699 | return false; |
| 10701 | 10700 | |
| ... | ... | @@ -10707,6 +10706,10 @@ static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out |
| 10707 | 10706 | return true; |
| 10708 | 10707 | } |
| 10709 | 10708 | |
| 10709 | static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) { | |
| 10710 | return ir_resolve_unsigned(ira, value, ira->codegen->builtin_types.entry_usize, out); | |
| 10711 | } | |
| 10712 | ||
| 10710 | 10713 | static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *value, bool *out) { |
| 10711 | 10714 | if (type_is_invalid(value->value.type)) |
| 10712 | 10715 | return false; |
| ... | ... | @@ -18025,7 +18028,7 @@ static TypeTableEntry *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstruc |
| 18025 | 18028 | |
| 18026 | 18029 | IrInstruction *bit_count_value = instruction->bit_count->other; |
| 18027 | 18030 | uint64_t bit_count; |
| 18028 | if (!ir_resolve_usize(ira, bit_count_value, &bit_count)) | |
| 18031 | if (!ir_resolve_unsigned(ira, bit_count_value, ira->codegen->builtin_types.entry_u32, &bit_count)) | |
| 18029 | 18032 | return ira->codegen->builtin_types.entry_invalid; |
| 18030 | 18033 | |
| 18031 | 18034 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
src/translate_c.cpp+1-1| ... | ... | @@ -427,7 +427,7 @@ static AstNode *get_global(Context *c, Buf *name) { |
| 427 | 427 | if (entry) |
| 428 | 428 | return entry->value; |
| 429 | 429 | } |
| 430 | if (c->codegen->primitive_type_table.maybe_get(name) != nullptr) { | |
| 430 | if (get_primitive_type(c->codegen, name) != nullptr) { | |
| 431 | 431 | return trans_create_node_symbol(c, name); |
| 432 | 432 | } |
| 433 | 433 | return nullptr; |
std/buffer.zig-2| ... | ... | @@ -5,8 +5,6 @@ const Allocator = mem.Allocator; |
| 5 | 5 | const assert = debug.assert; |
| 6 | 6 | const ArrayList = std.ArrayList; |
| 7 | 7 | |
| 8 | const fmt = std.fmt; | |
| 9 | ||
| 10 | 8 | /// A buffer that allocates memory and maintains a null byte at the end. |
| 11 | 9 | pub const Buffer = struct { |
| 12 | 10 | list: ArrayList(u8), |
std/crypto/sha1.zig-2| ... | ... | @@ -4,8 +4,6 @@ const endian = @import("../endian.zig"); |
| 4 | 4 | const debug = @import("../debug/index.zig"); |
| 5 | 5 | const builtin = @import("builtin"); |
| 6 | 6 | |
| 7 | pub const u160 = @IntType(false, 160); | |
| 8 | ||
| 9 | 7 | const RoundParam = struct { |
| 10 | 8 | a: usize, |
| 11 | 9 | b: usize, |
std/event/future.zig+10| ... | ... | @@ -40,6 +40,16 @@ pub fn Future(comptime T: type) type { |
| 40 | 40 | return &self.data; |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | /// Gets the data without waiting for it. If it's available, a pointer is | |
| 44 | /// returned. Otherwise, null is returned. | |
| 45 | pub fn getOrNull(self: *Self) ?*T { | |
| 46 | if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 1) { | |
| 47 | return &self.data; | |
| 48 | } else { | |
| 49 | return null; | |
| 50 | } | |
| 51 | } | |
| 52 | ||
| 43 | 53 | /// Make the data become available. May be called only once. |
| 44 | 54 | /// Before calling this, modify the `data` property. |
| 45 | 55 | pub fn resolve(self: *Self) void { |
std/json.zig-3| ... | ... | @@ -6,9 +6,6 @@ const std = @import("index.zig"); |
| 6 | 6 | const debug = std.debug; |
| 7 | 7 | const mem = std.mem; |
| 8 | 8 | |
| 9 | const u1 = @IntType(false, 1); | |
| 10 | const u256 = @IntType(false, 256); | |
| 11 | ||
| 12 | 9 | // A single token slice into the parent string. |
| 13 | 10 | // |
| 14 | 11 | // Use `token.slice()` on the input at the current position to get the current slice. |
std/math/big/int.zig-1| ... | ... | @@ -996,7 +996,6 @@ pub const Int = struct { |
| 996 | 996 | // They will still run on larger than this and should pass, but the multi-limb code-paths |
| 997 | 997 | // may be untested in some cases. |
| 998 | 998 | |
| 999 | const u256 = @IntType(false, 256); | |
| 1000 | 999 | const al = debug.global_allocator; |
| 1001 | 1000 | |
| 1002 | 1001 | test "big.int comptime_int set" { |
std/math/exp2.zig+12-12| ... | ... | @@ -75,18 +75,18 @@ fn exp2_32(x: f32) f32 { |
| 75 | 75 | } |
| 76 | 76 | |
| 77 | 77 | var uf = x + redux; |
| 78 | var i0 = @bitCast(u32, uf); | |
| 79 | i0 += tblsiz / 2; | |
| 78 | var i_0 = @bitCast(u32, uf); | |
| 79 | i_0 += tblsiz / 2; | |
| 80 | 80 | |
| 81 | const k = i0 / tblsiz; | |
| 81 | const k = i_0 / tblsiz; | |
| 82 | 82 | // NOTE: musl relies on undefined overflow shift behaviour. Appears that this produces the |
| 83 | 83 | // intended result but should confirm how GCC/Clang handle this to ensure. |
| 84 | 84 | const uk = @bitCast(f64, u64(0x3FF + k) << 52); |
| 85 | i0 &= tblsiz - 1; | |
| 85 | i_0 &= tblsiz - 1; | |
| 86 | 86 | uf -= redux; |
| 87 | 87 | |
| 88 | 88 | const z: f64 = x - uf; |
| 89 | var r: f64 = exp2ft[i0]; | |
| 89 | var r: f64 = exp2ft[i_0]; | |
| 90 | 90 | const t: f64 = r * z; |
| 91 | 91 | r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); |
| 92 | 92 | return @floatCast(f32, r * uk); |
| ... | ... | @@ -401,18 +401,18 @@ fn exp2_64(x: f64) f64 { |
| 401 | 401 | // reduce x |
| 402 | 402 | var uf = x + redux; |
| 403 | 403 | // NOTE: musl performs an implicit 64-bit to 32-bit u32 truncation here |
| 404 | var i0 = @truncate(u32, @bitCast(u64, uf)); | |
| 405 | i0 += tblsiz / 2; | |
| 404 | var i_0 = @truncate(u32, @bitCast(u64, uf)); | |
| 405 | i_0 += tblsiz / 2; | |
| 406 | 406 | |
| 407 | const k: u32 = i0 / tblsiz * tblsiz; | |
| 407 | const k: u32 = i_0 / tblsiz * tblsiz; | |
| 408 | 408 | const ik = @bitCast(i32, k / tblsiz); |
| 409 | i0 %= tblsiz; | |
| 409 | i_0 %= tblsiz; | |
| 410 | 410 | uf -= redux; |
| 411 | 411 | |
| 412 | // r = exp2(y) = exp2t[i0] * p(z - eps[i]) | |
| 412 | // r = exp2(y) = exp2t[i_0] * p(z - eps[i]) | |
| 413 | 413 | var z = x - uf; |
| 414 | const t = exp2dt[2 * i0]; | |
| 415 | z -= exp2dt[2 * i0 + 1]; | |
| 414 | const t = exp2dt[2 * i_0]; | |
| 415 | z -= exp2dt[2 * i_0 + 1]; | |
| 416 | 416 | const r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); |
| 417 | 417 | |
| 418 | 418 | return math.scalbn(r, ik); |
std/math/index.zig+1-1| ... | ... | @@ -354,7 +354,7 @@ test "math.rotl" { |
| 354 | 354 | |
| 355 | 355 | pub fn Log2Int(comptime T: type) type { |
| 356 | 356 | // comptime ceil log2 |
| 357 | comptime var count: usize = 0; | |
| 357 | comptime var count = 0; | |
| 358 | 358 | comptime var s = T.bit_count - 1; |
| 359 | 359 | inline while (s != 0) : (s >>= 1) { |
| 360 | 360 | count += 1; |
std/os/time.zig-1| ... | ... | @@ -25,7 +25,6 @@ pub fn sleep(seconds: usize, nanoseconds: usize) void { |
| 25 | 25 | } |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | const u63 = @IntType(false, 63); | |
| 29 | 28 | pub fn posixSleep(seconds: u63, nanoseconds: u63) void { |
| 30 | 29 | var req = posix.timespec{ |
| 31 | 30 | .tv_sec = seconds, |
test/cases/misc.zig-5| ... | ... | @@ -58,11 +58,6 @@ test "floating point primitive bit counts" { |
| 58 | 58 | assert(f64.bit_count == 64); |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | const u1 = @IntType(false, 1); | |
| 62 | const u63 = @IntType(false, 63); | |
| 63 | const i1 = @IntType(true, 1); | |
| 64 | const i63 = @IntType(true, 63); | |
| 65 | ||
| 66 | 61 | test "@minValue and @maxValue" { |
| 67 | 62 | assert(@maxValue(u1) == 1); |
| 68 | 63 | assert(@maxValue(u8) == 255); |
test/cases/struct.zig-1| ... | ... | @@ -240,7 +240,6 @@ fn getC(data: *const BitField1) u2 { |
| 240 | 240 | return data.c; |
| 241 | 241 | } |
| 242 | 242 | |
| 243 | const u24 = @IntType(false, 24); | |
| 244 | 243 | const Foo24Bits = packed struct { |
| 245 | 244 | field: u24, |
| 246 | 245 | }; |
test/compile_errors.zig+9| ... | ... | @@ -1,6 +1,15 @@ |
| 1 | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | |
| 3 | 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4 | cases.add( | |
| 5 | "optional pointer to void in extern struct", | |
| 6 | \\comptime { | |
| 7 | \\ _ = @IntType(false, @maxValue(u32) + 1); | |
| 8 | \\} | |
| 9 | , | |
| 10 | ".tmp_source.zig:2:40: error: integer value 4294967296 cannot be implicitly casted to type 'u32'", | |
| 11 | ); | |
| 12 | ||
| 4 | 13 | cases.add( |
| 5 | 14 | "optional pointer to void in extern struct", |
| 6 | 15 | \\const Foo = extern struct { |