authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-28 01:39:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-28 01:43:04-07:00
logd726c2a2d30146189f2b31aafcdeca25bc61c7f9
tree7b6961b974d2def6542338de1ad5830eb74807a7
parentc37f273cb053f50bb39ec36fcfeef284adf0a342

self-hosted: beginnings of stack allocation

Comment out non-x86_64 architectures for now in codegen.zig, because they all have compile errors for their codepaths anyway, and it was bloating the compilation speed and memory usage when stage1 tried to build self-hosted. Here's the panic message: "Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog." This is a workaround to lower the time it takes to build self-hosted with stage1 as well as use less memory. It should fix the CI. Additionally: * Add `single_mut_pointer` support to `Type` * Trivial implementation of stack allocation in codegen.zig. It does not deal with freeing yet, and it's missing the stack pointer adjustment prologue. * Add the `alloc` IR instruction and semantic analysis for `alloc` ZIR instruction.

6 files changed, 180 insertions(+), 74 deletions(-)

src-self-hosted/Module.zig+7-1
...@@ -2428,7 +2428,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst...@@ -2428,7 +2428,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
24282428
2429 // *[N]T to []T2429 // *[N]T to []T
2430 if (inst.ty.isSinglePointer() and dest_type.isSlice() and2430 if (inst.ty.isSinglePointer() and dest_type.isSlice() and
2431 (!inst.ty.pointerIsConst() or dest_type.pointerIsConst()))2431 (!inst.ty.isConstPtr() or dest_type.isConstPtr()))
2432 {2432 {
2433 const array_type = inst.ty.elemType();2433 const array_type = inst.ty.elemType();
2434 const dst_elem_type = dest_type.elemType();2434 const dst_elem_type = dest_type.elemType();
...@@ -2774,3 +2774,9 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:...@@ -2774,3 +2774,9 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
27742774
2775 return Value.initPayload(val_payload);2775 return Value.initPayload(val_payload);
2776}2776}
2777
2778pub fn singleMutPtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type) error{OutOfMemory}!Type {
2779 const type_payload = try scope.arena().create(Type.Payload.SingleMutPointer);
2780 type_payload.* = .{ .pointee_type = elem_ty };
2781 return Type.initPayload(&type_payload.base);
2782}
src-self-hosted/codegen.zig+99-65
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;2const mem = std.mem;
3const math = std.math;
3const assert = std.debug.assert;4const assert = std.debug.assert;
4const ir = @import("ir.zig");5const ir = @import("ir.zig");
5const Type = @import("type.zig").Type;6const Type = @import("type.zig").Type;
...@@ -50,57 +51,58 @@ pub fn generateSymbol(...@@ -50,57 +51,58 @@ pub fn generateSymbol(
50 switch (typed_value.ty.zigTypeTag()) {51 switch (typed_value.ty.zigTypeTag()) {
51 .Fn => {52 .Fn => {
52 switch (bin_file.options.target.cpu.arch) {53 switch (bin_file.options.target.cpu.arch) {
53 .arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code),54 //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code),
54 .armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code),55 //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code),
55 .aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code),56 //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code),
56 .aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code),57 //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code),
57 .aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code),58 //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code),
58 .arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code),59 //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code),
59 .avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code),60 //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code),
60 .bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code),61 //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code),
61 .bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code),62 //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code),
62 .hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code),63 //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code),
63 .mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code),64 //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code),
64 .mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code),65 //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code),
65 .mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code),66 //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code),
66 .mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code),67 //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code),
67 .msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code),68 //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code),
68 .powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code),69 //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code),
69 .powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code),70 //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code),
70 .powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code),71 //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code),
71 .r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code),72 //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code),
72 .amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code),73 //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code),
73 .riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code),74 //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code),
74 .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code),75 //.riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code),
75 .sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code),76 //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code),
76 .sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code),77 //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code),
77 .sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code),78 //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code),
78 .s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code),79 //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code),
79 .tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code),80 //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code),
80 .tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code),81 //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code),
81 .thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code),82 //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code),
82 .thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code),83 //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code),
83 .i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code),84 //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code),
84 .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code),85 .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code),
85 .xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code),86 //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code),
86 .nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code),87 //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code),
87 .nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code),88 //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code),
88 .le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code),89 //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code),
89 .le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code),90 //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code),
90 .amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code),91 //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code),
91 .amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code),92 //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code),
92 .hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code),93 //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code),
93 .hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code),94 //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code),
94 .spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code),95 //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code),
95 .spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code),96 //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code),
96 .kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code),97 //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code),
97 .shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code),98 //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code),
98 .lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code),99 //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code),
99 .wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code),100 //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code),
100 .wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code),101 //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code),
101 .renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code),102 //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code),
102 .renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code),103 //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code),
103 .ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code),104 //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code),
105 else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."),
104 }106 }
105 },107 },
106 .Array => {108 .Array => {
...@@ -209,6 +211,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -209,6 +211,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
209 ret_mcv: MCValue,211 ret_mcv: MCValue,
210 arg_index: usize,212 arg_index: usize,
211 src: usize,213 src: usize,
214 stack_align: u32,
212215
213 /// Whenever there is a runtime branch, we push a Branch onto this stack,216 /// Whenever there is a runtime branch, we push a Branch onto this stack,
214 /// and pop it off when the runtime branch joins. This provides an "overlay"217 /// and pop it off when the runtime branch joins. This provides an "overlay"
...@@ -238,10 +241,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -238,10 +241,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
238 stack_offset: u64,241 stack_offset: u64,
239 /// The value is in the compare flags assuming an unsigned operation,242 /// The value is in the compare flags assuming an unsigned operation,
240 /// with this operator applied on top of it.243 /// with this operator applied on top of it.
241 compare_flags_unsigned: std.math.CompareOperator,244 compare_flags_unsigned: math.CompareOperator,
242 /// The value is in the compare flags assuming a signed operation,245 /// The value is in the compare flags assuming a signed operation,
243 /// with this operator applied on top of it.246 /// with this operator applied on top of it.
244 compare_flags_signed: std.math.CompareOperator,247 compare_flags_signed: math.CompareOperator,
245248
246 fn isMemory(mcv: MCValue) bool {249 fn isMemory(mcv: MCValue) bool {
247 return switch (mcv) {250 return switch (mcv) {
...@@ -280,10 +283,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -280,10 +283,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
280 const Branch = struct {283 const Branch = struct {
281 inst_table: std.AutoHashMapUnmanaged(*ir.Inst, MCValue) = .{},284 inst_table: std.AutoHashMapUnmanaged(*ir.Inst, MCValue) = .{},
282 registers: std.AutoHashMapUnmanaged(Register, RegisterAllocation) = .{},285 registers: std.AutoHashMapUnmanaged(Register, RegisterAllocation) = .{},
283 free_registers: FreeRegInt = std.math.maxInt(FreeRegInt),286 free_registers: FreeRegInt = math.maxInt(FreeRegInt),
284287
285 /// Maps offset to what is stored there.288 /// Maps offset to what is stored there.
286 stack: std.AutoHashMapUnmanaged(usize, StackAllocation) = .{},289 stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
287 /// Offset from the stack base, representing the end of the stack frame.290 /// Offset from the stack base, representing the end of the stack frame.
288 max_end_stack: u32 = 0,291 max_end_stack: u32 = 0,
289 /// Represents the current end stack offset. If there is no existing slot292 /// Represents the current end stack offset. If there is no existing slot
...@@ -293,7 +296,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -293,7 +296,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
293 fn markRegUsed(self: *Branch, reg: Register) void {296 fn markRegUsed(self: *Branch, reg: Register) void {
294 if (FreeRegInt == u0) return;297 if (FreeRegInt == u0) return;
295 const index = reg.allocIndex() orelse return;298 const index = reg.allocIndex() orelse return;
296 const ShiftInt = std.math.Log2Int(FreeRegInt);299 const ShiftInt = math.Log2Int(FreeRegInt);
297 const shift = @intCast(ShiftInt, index);300 const shift = @intCast(ShiftInt, index);
298 self.free_registers &= ~(@as(FreeRegInt, 1) << shift);301 self.free_registers &= ~(@as(FreeRegInt, 1) << shift);
299 }302 }
...@@ -301,7 +304,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -301,7 +304,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
301 fn markRegFree(self: *Branch, reg: Register) void {304 fn markRegFree(self: *Branch, reg: Register) void {
302 if (FreeRegInt == u0) return;305 if (FreeRegInt == u0) return;
303 const index = reg.allocIndex() orelse return;306 const index = reg.allocIndex() orelse return;
304 const ShiftInt = std.math.Log2Int(FreeRegInt);307 const ShiftInt = math.Log2Int(FreeRegInt);
305 const shift = @intCast(ShiftInt, index);308 const shift = @intCast(ShiftInt, index);
306 self.free_registers |= @as(FreeRegInt, 1) << shift;309 self.free_registers |= @as(FreeRegInt, 1) << shift;
307 }310 }
...@@ -356,6 +359,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -356,6 +359,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
356 .arg_index = 0,359 .arg_index = 0,
357 .branch_stack = &branch_stack,360 .branch_stack = &branch_stack,
358 .src = src,361 .src = src,
362 .stack_align = undefined,
359 };363 };
360364
361 var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) {365 var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) {
...@@ -366,6 +370,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -366,6 +370,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
366370
367 function.args = call_info.args;371 function.args = call_info.args;
368 function.ret_mcv = call_info.return_value;372 function.ret_mcv = call_info.return_value;
373 function.stack_align = call_info.stack_align;
369 branch.max_end_stack = call_info.stack_byte_count;374 branch.max_end_stack = call_info.stack_byte_count;
370375
371 function.gen() catch |err| switch (err) {376 function.gen() catch |err| switch (err) {
...@@ -383,15 +388,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -383,15 +388,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
383 fn gen(self: *Self) !void {388 fn gen(self: *Self) !void {
384 try self.code.ensureCapacity(self.code.items.len + 11);389 try self.code.ensureCapacity(self.code.items.len + 11);
385390
391 // TODO omit this for naked functions
386 // push rbp392 // push rbp
387 // mov rbp, rsp393 // mov rbp, rsp
388 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x55, 0x48, 0x89, 0xe5 });394 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x55, 0x48, 0x89, 0xe5 });
389395
390 // sub rsp, x396 // sub rsp, x
391 const stack_end = self.branch_stack.items[0].max_end_stack;397 const stack_end = self.branch_stack.items[0].max_end_stack;
392 if (stack_end > std.math.maxInt(i32)) {398 if (stack_end > math.maxInt(i32)) {
393 return self.fail(self.src, "too much stack used in call parameters", .{});399 return self.fail(self.src, "too much stack used in call parameters", .{});
394 } else if (stack_end > std.math.maxInt(i8)) {400 } else if (stack_end > math.maxInt(i8)) {
395 // 48 83 ec xx sub rsp,0x10401 // 48 83 ec xx sub rsp,0x10
396 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x48, 0x81, 0xec });402 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x48, 0x81, 0xec });
397 const x = @intCast(u32, stack_end);403 const x = @intCast(u32, stack_end);
...@@ -436,6 +442,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -436,6 +442,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
436 fn genFuncInst(self: *Self, inst: *ir.Inst) !MCValue {442 fn genFuncInst(self: *Self, inst: *ir.Inst) !MCValue {
437 switch (inst.tag) {443 switch (inst.tag) {
438 .add => return self.genAdd(inst.castTag(.add).?),444 .add => return self.genAdd(inst.castTag(.add).?),
445 .alloc => return self.genAlloc(inst.castTag(.alloc).?),
439 .arg => return self.genArg(inst.castTag(.arg).?),446 .arg => return self.genArg(inst.castTag(.arg).?),
440 .assembly => return self.genAsm(inst.castTag(.assembly).?),447 .assembly => return self.genAsm(inst.castTag(.assembly).?),
441 .bitcast => return self.genBitCast(inst.castTag(.bitcast).?),448 .bitcast => return self.genBitCast(inst.castTag(.bitcast).?),
...@@ -465,6 +472,28 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -465,6 +472,28 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
465 }472 }
466 }473 }
467474
475 fn genAlloc(self: *Self, inst: *ir.Inst.NoOp) !MCValue {
476 const elem_ty = inst.base.ty.elemType();
477 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
478 return self.fail(inst.base.src, "type '{}' too big to fit into stack frame", .{elem_ty});
479 };
480 // TODO swap this for inst.base.ty.ptrAlign
481 const abi_align = elem_ty.abiAlignment(self.target.*);
482 if (abi_align > self.stack_align)
483 self.stack_align = abi_align;
484 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
485 // TODO find a free slot instead of always appending
486 const offset = mem.alignForwardGeneric(u32, branch.next_stack_offset, abi_align);
487 branch.next_stack_offset = offset + abi_size;
488 if (branch.next_stack_offset > branch.max_end_stack)
489 branch.max_end_stack = branch.next_stack_offset;
490 try branch.stack.putNoClobber(self.gpa, offset, .{
491 .inst = &inst.base,
492 .size = abi_size,
493 });
494 return MCValue{ .stack_offset = offset };
495 }
496
468 fn genFloatCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue {497 fn genFloatCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
469 // No side effects, so if it's unreferenced, do nothing.498 // No side effects, so if it's unreferenced, do nothing.
470 if (inst.base.isUnused())499 if (inst.base.isUnused())
...@@ -610,7 +639,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -610,7 +639,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
610 // and as a register.639 // and as a register.
611 switch (src_mcv) {640 switch (src_mcv) {
612 .immediate => |imm| {641 .immediate => |imm| {
613 if (imm > std.math.maxInt(u31)) {642 if (imm > math.maxInt(u31)) {
614 src_mcv = try self.copyToNewRegister(src_inst);643 src_mcv = try self.copyToNewRegister(src_inst);
615 }644 }
616 },645 },
...@@ -639,7 +668,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -639,7 +668,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
639 .immediate => |imm| {668 .immediate => |imm| {
640 const imm32 = @intCast(u31, imm); // This case must be handled before calling genX8664BinMathCode.669 const imm32 = @intCast(u31, imm); // This case must be handled before calling genX8664BinMathCode.
641 // 81 /opx id670 // 81 /opx id
642 if (imm32 <= std.math.maxInt(u7)) {671 if (imm32 <= math.maxInt(u7)) {
643 self.rex(.{ .b = dst_reg.isExtended(), .w = dst_reg.size() == 64 });672 self.rex(.{ .b = dst_reg.isExtended(), .w = dst_reg.size() == 64 });
644 self.code.appendSliceAssumeCapacity(&[_]u8{673 self.code.appendSliceAssumeCapacity(&[_]u8{
645 0x83,674 0x83,
...@@ -785,7 +814,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -785,7 +814,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
785 return self.ret(inst.base.src, .none);814 return self.ret(inst.base.src, .none);
786 }815 }
787816
788 fn genCmp(self: *Self, inst: *ir.Inst.BinOp, op: std.math.CompareOperator) !MCValue {817 fn genCmp(self: *Self, inst: *ir.Inst.BinOp, op: math.CompareOperator) !MCValue {
789 // No side effects, so if it's unreferenced, do nothing.818 // No side effects, so if it's unreferenced, do nothing.
790 if (inst.base.isUnused())819 if (inst.base.isUnused())
791 return MCValue.dead;820 return MCValue.dead;
...@@ -909,7 +938,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -909,7 +938,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
909 switch (reloc) {938 switch (reloc) {
910 .rel32 => |pos| {939 .rel32 => |pos| {
911 const amt = self.code.items.len - (pos + 4);940 const amt = self.code.items.len - (pos + 4);
912 const s32_amt = std.math.cast(i32, amt) catch941 const s32_amt = math.cast(i32, amt) catch
913 return self.fail(src, "unable to perform relocation: jump too far", .{});942 return self.fail(src, "unable to perform relocation: jump too far", .{});
914 mem.writeIntLittle(i32, self.code.items[pos..][0..4], s32_amt);943 mem.writeIntLittle(i32, self.code.items[pos..][0..4], s32_amt);
915 },944 },
...@@ -1070,7 +1099,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1070,7 +1099,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1070 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x31, 0xC0 | id << 3 | id });1099 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x31, 0xC0 | id << 3 | id });
1071 return;1100 return;
1072 }1101 }
1073 if (x <= std.math.maxInt(u32)) {1102 if (x <= math.maxInt(u32)) {
1074 // Next best case: if we set the lower four bytes, the upper four will be zeroed.1103 // Next best case: if we set the lower four bytes, the upper four will be zeroed.
1075 //1104 //
1076 // The encoding for `mov IMM32 -> REG` is (0xB8 + R) IMM.1105 // The encoding for `mov IMM32 -> REG` is (0xB8 + R) IMM.
...@@ -1152,7 +1181,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1152,7 +1181,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1152 if (reg.size() != 64) {1181 if (reg.size() != 64) {
1153 return self.fail(src, "TODO decide whether to implement non-64-bit loads", .{});1182 return self.fail(src, "TODO decide whether to implement non-64-bit loads", .{});
1154 }1183 }
1155 if (x <= std.math.maxInt(u32)) {1184 if (x <= math.maxInt(u32)) {
1156 // Moving from memory to a register is a variant of `8B /r`.1185 // Moving from memory to a register is a variant of `8B /r`.
1157 // Since we're using 64-bit moves, we require a REX.1186 // Since we're using 64-bit moves, we require a REX.
1158 // This variant also requires a SIB, as it would otherwise be RIP-relative.1187 // This variant also requires a SIB, as it would otherwise be RIP-relative.
...@@ -1285,7 +1314,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1285,7 +1314,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1285 .is_signed = false,1314 .is_signed = false,
1286 },1315 },
1287 });1316 });
1288 if (imm >= std.math.maxInt(U)) {1317 if (imm >= math.maxInt(U)) {
1289 return self.copyToNewRegister(inst);1318 return self.copyToNewRegister(inst);
1290 }1319 }
1291 },1320 },
...@@ -1327,6 +1356,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1327,6 +1356,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1327 args: []MCValue,1356 args: []MCValue,
1328 return_value: MCValue,1357 return_value: MCValue,
1329 stack_byte_count: u32,1358 stack_byte_count: u32,
1359 stack_align: u32,
13301360
1331 fn deinit(self: *CallMCValues, func: *Self) void {1361 fn deinit(self: *CallMCValues, func: *Self) void {
1332 func.gpa.free(self.args);1362 func.gpa.free(self.args);
...@@ -1342,8 +1372,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1342,8 +1372,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1342 fn_ty.fnParamTypes(param_types);1372 fn_ty.fnParamTypes(param_types);
1343 var result: CallMCValues = .{1373 var result: CallMCValues = .{
1344 .args = try self.gpa.alloc(MCValue, param_types.len),1374 .args = try self.gpa.alloc(MCValue, param_types.len),
1375 // These undefined values must be populated before returning from this function.
1345 .return_value = undefined,1376 .return_value = undefined,
1346 .stack_byte_count = undefined,1377 .stack_byte_count = undefined,
1378 .stack_align = undefined,
1347 };1379 };
1348 errdefer self.gpa.free(result.args);1380 errdefer self.gpa.free(result.args);
13491381
...@@ -1356,6 +1388,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1356,6 +1388,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1356 assert(result.args.len == 0);1388 assert(result.args.len == 0);
1357 result.return_value = .{ .unreach = {} };1389 result.return_value = .{ .unreach = {} };
1358 result.stack_byte_count = 0;1390 result.stack_byte_count = 0;
1391 result.stack_align = 1;
1359 return result;1392 return result;
1360 },1393 },
1361 .Unspecified, .C => {1394 .Unspecified, .C => {
...@@ -1377,6 +1410,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1377,6 +1410,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1377 }1410 }
1378 }1411 }
1379 result.stack_byte_count = next_stack_offset;1412 result.stack_byte_count = next_stack_offset;
1413 result.stack_align = 16;
1380 },1414 },
1381 else => return self.fail(src, "TODO implement function parameters for {}", .{cc}),1415 else => return self.fail(src, "TODO implement function parameters for {}", .{cc}),
1382 }1416 }
src-self-hosted/ir.zig+3-3
...@@ -4,6 +4,7 @@ const Type = @import("type.zig").Type;...@@ -4,6 +4,7 @@ const Type = @import("type.zig").Type;
4const Module = @import("Module.zig");4const Module = @import("Module.zig");
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const codegen = @import("codegen.zig");6const codegen = @import("codegen.zig");
7const ast = std.zig.ast;
78
8/// These are in-memory, analyzed instructions. See `zir.Inst` for the representation9/// These are in-memory, analyzed instructions. See `zir.Inst` for the representation
9/// of instructions that correspond to the ZIR text format.10/// of instructions that correspond to the ZIR text format.
...@@ -47,6 +48,7 @@ pub const Inst = struct {...@@ -47,6 +48,7 @@ pub const Inst = struct {
4748
48 pub const Tag = enum {49 pub const Tag = enum {
49 add,50 add,
51 alloc,
50 arg,52 arg,
51 assembly,53 assembly,
52 bitcast,54 bitcast,
...@@ -74,11 +76,9 @@ pub const Inst = struct {...@@ -74,11 +76,9 @@ pub const Inst = struct {
74 floatcast,76 floatcast,
75 intcast,77 intcast,
7678
77 /// There is one-to-one correspondence between tag and type for now,
78 /// but this will not always be the case. For example, binary operations
79 /// such as + and - will have different tags but the same type.
80 pub fn Type(tag: Tag) type {79 pub fn Type(tag: Tag) type {
81 return switch (tag) {80 return switch (tag) {
81 .alloc,
82 .retvoid,82 .retvoid,
83 .unreach,83 .unreach,
84 .arg,84 .arg,
src-self-hosted/type.zig+51-3
...@@ -67,6 +67,7 @@ pub const Type = extern union {...@@ -67,6 +67,7 @@ pub const Type = extern union {
6767
68 .array, .array_u8_sentinel_0 => return .Array,68 .array, .array_u8_sentinel_0 => return .Array,
69 .single_const_pointer => return .Pointer,69 .single_const_pointer => return .Pointer,
70 .single_mut_pointer => return .Pointer,
70 .single_const_pointer_to_comptime_int => return .Pointer,71 .single_const_pointer_to_comptime_int => return .Pointer,
71 .const_slice_u8 => return .Pointer,72 .const_slice_u8 => return .Pointer,
72 }73 }
...@@ -261,6 +262,15 @@ pub const Type = extern union {...@@ -261,6 +262,15 @@ pub const Type = extern union {
261 };262 };
262 return Type{ .ptr_otherwise = &new_payload.base };263 return Type{ .ptr_otherwise = &new_payload.base };
263 },264 },
265 .single_mut_pointer => {
266 const payload = @fieldParentPtr(Payload.SingleMutPointer, "base", self.ptr_otherwise);
267 const new_payload = try allocator.create(Payload.SingleMutPointer);
268 new_payload.* = .{
269 .base = payload.base,
270 .pointee_type = try payload.pointee_type.copy(allocator),
271 };
272 return Type{ .ptr_otherwise = &new_payload.base };
273 },
264 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),274 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
265 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),275 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
266 .function => {276 .function => {
...@@ -368,6 +378,12 @@ pub const Type = extern union {...@@ -368,6 +378,12 @@ pub const Type = extern union {
368 ty = payload.pointee_type;378 ty = payload.pointee_type;
369 continue;379 continue;
370 },380 },
381 .single_mut_pointer => {
382 const payload = @fieldParentPtr(Payload.SingleMutPointer, "base", ty.ptr_otherwise);
383 try out_stream.writeAll("* ");
384 ty = payload.pointee_type;
385 continue;
386 },
371 .int_signed => {387 .int_signed => {
372 const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise);388 const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise);
373 return out_stream.print("i{}", .{payload.bits});389 return out_stream.print("i{}", .{payload.bits});
...@@ -467,6 +483,7 @@ pub const Type = extern union {...@@ -467,6 +483,7 @@ pub const Type = extern union {
467 .array_u8_sentinel_0,483 .array_u8_sentinel_0,
468 .array, // TODO check for zero bits484 .array, // TODO check for zero bits
469 .single_const_pointer,485 .single_const_pointer,
486 .single_mut_pointer,
470 .int_signed, // TODO check for zero bits487 .int_signed, // TODO check for zero bits
471 .int_unsigned, // TODO check for zero bits488 .int_unsigned, // TODO check for zero bits
472 => true,489 => true,
...@@ -510,6 +527,7 @@ pub const Type = extern union {...@@ -510,6 +527,7 @@ pub const Type = extern union {
510 .single_const_pointer_to_comptime_int,527 .single_const_pointer_to_comptime_int,
511 .const_slice_u8,528 .const_slice_u8,
512 .single_const_pointer,529 .single_const_pointer,
530 .single_mut_pointer,
513 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),531 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
514532
515 .c_short => return @divExact(CType.short.sizeInBits(target), 8),533 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
...@@ -591,6 +609,7 @@ pub const Type = extern union {...@@ -591,6 +609,7 @@ pub const Type = extern union {
591 .single_const_pointer_to_comptime_int,609 .single_const_pointer_to_comptime_int,
592 .const_slice_u8,610 .const_slice_u8,
593 .single_const_pointer,611 .single_const_pointer,
612 .single_mut_pointer,
594 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),613 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
595614
596 .c_short => return @divExact(CType.short.sizeInBits(target), 8),615 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
...@@ -671,6 +690,7 @@ pub const Type = extern union {...@@ -671,6 +690,7 @@ pub const Type = extern union {
671 => false,690 => false,
672691
673 .single_const_pointer,692 .single_const_pointer,
693 .single_mut_pointer,
674 .single_const_pointer_to_comptime_int,694 .single_const_pointer_to_comptime_int,
675 => true,695 => true,
676 };696 };
...@@ -714,6 +734,7 @@ pub const Type = extern union {...@@ -714,6 +734,7 @@ pub const Type = extern union {
714 .array,734 .array,
715 .array_u8_sentinel_0,735 .array_u8_sentinel_0,
716 .single_const_pointer,736 .single_const_pointer,
737 .single_mut_pointer,
717 .single_const_pointer_to_comptime_int,738 .single_const_pointer_to_comptime_int,
718 .fn_noreturn_no_args,739 .fn_noreturn_no_args,
719 .fn_void_no_args,740 .fn_void_no_args,
...@@ -728,8 +749,7 @@ pub const Type = extern union {...@@ -728,8 +749,7 @@ pub const Type = extern union {
728 };749 };
729 }750 }
730751
731 /// Asserts the type is a pointer type.752 pub fn isConstPtr(self: Type) bool {
732 pub fn pointerIsConst(self: Type) bool {
733 return switch (self.tag()) {753 return switch (self.tag()) {
734 .u8,754 .u8,
735 .i8,755 .i8,
...@@ -773,7 +793,8 @@ pub const Type = extern union {...@@ -773,7 +793,8 @@ pub const Type = extern union {
773 .function,793 .function,
774 .int_unsigned,794 .int_unsigned,
775 .int_signed,795 .int_signed,
776 => unreachable,796 .single_mut_pointer,
797 => false,
777798
778 .single_const_pointer,799 .single_const_pointer,
779 .single_const_pointer_to_comptime_int,800 .single_const_pointer_to_comptime_int,
...@@ -829,6 +850,7 @@ pub const Type = extern union {...@@ -829,6 +850,7 @@ pub const Type = extern union {
829850
830 .array => self.cast(Payload.Array).?.elem_type,851 .array => self.cast(Payload.Array).?.elem_type,
831 .single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type,852 .single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type,
853 .single_mut_pointer => self.cast(Payload.SingleMutPointer).?.pointee_type,
832 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),854 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
833 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),855 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
834 };856 };
...@@ -876,6 +898,7 @@ pub const Type = extern union {...@@ -876,6 +898,7 @@ pub const Type = extern union {
876 .fn_ccc_void_no_args,898 .fn_ccc_void_no_args,
877 .function,899 .function,
878 .single_const_pointer,900 .single_const_pointer,
901 .single_mut_pointer,
879 .single_const_pointer_to_comptime_int,902 .single_const_pointer_to_comptime_int,
880 .const_slice_u8,903 .const_slice_u8,
881 .int_unsigned,904 .int_unsigned,
...@@ -929,6 +952,7 @@ pub const Type = extern union {...@@ -929,6 +952,7 @@ pub const Type = extern union {
929 .fn_ccc_void_no_args,952 .fn_ccc_void_no_args,
930 .function,953 .function,
931 .single_const_pointer,954 .single_const_pointer,
955 .single_mut_pointer,
932 .single_const_pointer_to_comptime_int,956 .single_const_pointer_to_comptime_int,
933 .const_slice_u8,957 .const_slice_u8,
934 .int_unsigned,958 .int_unsigned,
...@@ -970,6 +994,7 @@ pub const Type = extern union {...@@ -970,6 +994,7 @@ pub const Type = extern union {
970 .function,994 .function,
971 .array,995 .array,
972 .single_const_pointer,996 .single_const_pointer,
997 .single_mut_pointer,
973 .single_const_pointer_to_comptime_int,998 .single_const_pointer_to_comptime_int,
974 .array_u8_sentinel_0,999 .array_u8_sentinel_0,
975 .const_slice_u8,1000 .const_slice_u8,
...@@ -1024,6 +1049,7 @@ pub const Type = extern union {...@@ -1024,6 +1049,7 @@ pub const Type = extern union {
1024 .function,1049 .function,
1025 .array,1050 .array,
1026 .single_const_pointer,1051 .single_const_pointer,
1052 .single_mut_pointer,
1027 .single_const_pointer_to_comptime_int,1053 .single_const_pointer_to_comptime_int,
1028 .array_u8_sentinel_0,1054 .array_u8_sentinel_0,
1029 .const_slice_u8,1055 .const_slice_u8,
...@@ -1078,6 +1104,7 @@ pub const Type = extern union {...@@ -1078,6 +1104,7 @@ pub const Type = extern union {
1078 .function,1104 .function,
1079 .array,1105 .array,
1080 .single_const_pointer,1106 .single_const_pointer,
1107 .single_mut_pointer,
1081 .single_const_pointer_to_comptime_int,1108 .single_const_pointer_to_comptime_int,
1082 .array_u8_sentinel_0,1109 .array_u8_sentinel_0,
1083 .const_slice_u8,1110 .const_slice_u8,
...@@ -1130,6 +1157,7 @@ pub const Type = extern union {...@@ -1130,6 +1157,7 @@ pub const Type = extern union {
1130 .function,1157 .function,
1131 .array,1158 .array,
1132 .single_const_pointer,1159 .single_const_pointer,
1160 .single_mut_pointer,
1133 .single_const_pointer_to_comptime_int,1161 .single_const_pointer_to_comptime_int,
1134 .array_u8_sentinel_0,1162 .array_u8_sentinel_0,
1135 .const_slice_u8,1163 .const_slice_u8,
...@@ -1211,6 +1239,7 @@ pub const Type = extern union {...@@ -1211,6 +1239,7 @@ pub const Type = extern union {
1211 .@"undefined",1239 .@"undefined",
1212 .array,1240 .array,
1213 .single_const_pointer,1241 .single_const_pointer,
1242 .single_mut_pointer,
1214 .single_const_pointer_to_comptime_int,1243 .single_const_pointer_to_comptime_int,
1215 .array_u8_sentinel_0,1244 .array_u8_sentinel_0,
1216 .const_slice_u8,1245 .const_slice_u8,
...@@ -1268,6 +1297,7 @@ pub const Type = extern union {...@@ -1268,6 +1297,7 @@ pub const Type = extern union {
1268 .@"undefined",1297 .@"undefined",
1269 .array,1298 .array,
1270 .single_const_pointer,1299 .single_const_pointer,
1300 .single_mut_pointer,
1271 .single_const_pointer_to_comptime_int,1301 .single_const_pointer_to_comptime_int,
1272 .array_u8_sentinel_0,1302 .array_u8_sentinel_0,
1273 .const_slice_u8,1303 .const_slice_u8,
...@@ -1324,6 +1354,7 @@ pub const Type = extern union {...@@ -1324,6 +1354,7 @@ pub const Type = extern union {
1324 .@"undefined",1354 .@"undefined",
1325 .array,1355 .array,
1326 .single_const_pointer,1356 .single_const_pointer,
1357 .single_mut_pointer,
1327 .single_const_pointer_to_comptime_int,1358 .single_const_pointer_to_comptime_int,
1328 .array_u8_sentinel_0,1359 .array_u8_sentinel_0,
1329 .const_slice_u8,1360 .const_slice_u8,
...@@ -1380,6 +1411,7 @@ pub const Type = extern union {...@@ -1380,6 +1411,7 @@ pub const Type = extern union {
1380 .@"undefined",1411 .@"undefined",
1381 .array,1412 .array,
1382 .single_const_pointer,1413 .single_const_pointer,
1414 .single_mut_pointer,
1383 .single_const_pointer_to_comptime_int,1415 .single_const_pointer_to_comptime_int,
1384 .array_u8_sentinel_0,1416 .array_u8_sentinel_0,
1385 .const_slice_u8,1417 .const_slice_u8,
...@@ -1433,6 +1465,7 @@ pub const Type = extern union {...@@ -1433,6 +1465,7 @@ pub const Type = extern union {
1433 .@"undefined",1465 .@"undefined",
1434 .array,1466 .array,
1435 .single_const_pointer,1467 .single_const_pointer,
1468 .single_mut_pointer,
1436 .single_const_pointer_to_comptime_int,1469 .single_const_pointer_to_comptime_int,
1437 .array_u8_sentinel_0,1470 .array_u8_sentinel_0,
1438 .const_slice_u8,1471 .const_slice_u8,
...@@ -1486,6 +1519,7 @@ pub const Type = extern union {...@@ -1486,6 +1519,7 @@ pub const Type = extern union {
1486 .@"undefined",1519 .@"undefined",
1487 .array,1520 .array,
1488 .single_const_pointer,1521 .single_const_pointer,
1522 .single_mut_pointer,
1489 .single_const_pointer_to_comptime_int,1523 .single_const_pointer_to_comptime_int,
1490 .array_u8_sentinel_0,1524 .array_u8_sentinel_0,
1491 .const_slice_u8,1525 .const_slice_u8,
...@@ -1559,6 +1593,7 @@ pub const Type = extern union {...@@ -1559,6 +1593,7 @@ pub const Type = extern union {
1559 .function,1593 .function,
1560 .array,1594 .array,
1561 .single_const_pointer,1595 .single_const_pointer,
1596 .single_mut_pointer,
1562 .single_const_pointer_to_comptime_int,1597 .single_const_pointer_to_comptime_int,
1563 .array_u8_sentinel_0,1598 .array_u8_sentinel_0,
1564 .const_slice_u8,1599 .const_slice_u8,
...@@ -1628,6 +1663,11 @@ pub const Type = extern union {...@@ -1628,6 +1663,11 @@ pub const Type = extern union {
1628 ty = ptr.pointee_type;1663 ty = ptr.pointee_type;
1629 continue;1664 continue;
1630 },1665 },
1666 .single_mut_pointer => {
1667 const ptr = ty.cast(Payload.SingleMutPointer).?;
1668 ty = ptr.pointee_type;
1669 continue;
1670 },
1631 };1671 };
1632 }1672 }
16331673
...@@ -1678,6 +1718,7 @@ pub const Type = extern union {...@@ -1678,6 +1718,7 @@ pub const Type = extern union {
1678 .int_signed,1718 .int_signed,
1679 .array,1719 .array,
1680 .single_const_pointer,1720 .single_const_pointer,
1721 .single_mut_pointer,
1681 => return false,1722 => return false,
1682 };1723 };
1683 }1724 }
...@@ -1734,6 +1775,7 @@ pub const Type = extern union {...@@ -1734,6 +1775,7 @@ pub const Type = extern union {
1734 array_u8_sentinel_0,1775 array_u8_sentinel_0,
1735 array,1776 array,
1736 single_const_pointer,1777 single_const_pointer,
1778 single_mut_pointer,
1737 int_signed,1779 int_signed,
1738 int_unsigned,1780 int_unsigned,
1739 function,1781 function,
...@@ -1764,6 +1806,12 @@ pub const Type = extern union {...@@ -1764,6 +1806,12 @@ pub const Type = extern union {
1764 pointee_type: Type,1806 pointee_type: Type,
1765 };1807 };
17661808
1809 pub const SingleMutPointer = struct {
1810 base: Payload = Payload{ .tag = .single_mut_pointer },
1811
1812 pointee_type: Type,
1813 };
1814
1767 pub const IntSigned = struct {1815 pub const IntSigned = struct {
1768 base: Payload = Payload{ .tag = .int_signed },1816 base: Payload = Payload{ .tag = .int_signed },
17691817
src-self-hosted/zir.zig+16-1
...@@ -39,7 +39,7 @@ pub const Inst = struct {...@@ -39,7 +39,7 @@ pub const Inst = struct {
39 /// Twos complement wrapping integer addition.39 /// Twos complement wrapping integer addition.
40 addwrap,40 addwrap,
41 /// Allocates stack local memory. Its lifetime ends when the block ends that contains41 /// Allocates stack local memory. Its lifetime ends when the block ends that contains
42 /// this instruction.42 /// this instruction. The operand is the type of the allocated object.
43 alloc,43 alloc,
44 /// Same as `alloc` except the type is inferred.44 /// Same as `alloc` except the type is inferred.
45 alloc_inferred,45 alloc_inferred,
...@@ -1851,6 +1851,21 @@ const EmitZIR = struct {...@@ -1851,6 +1851,21 @@ const EmitZIR = struct {
1851 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast),1851 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast),
1852 .floatcast => try self.emitCast(inst.src, new_body, inst.castTag(.floatcast).?, .floatcast),1852 .floatcast => try self.emitCast(inst.src, new_body, inst.castTag(.floatcast).?, .floatcast),
18531853
1854 .alloc => blk: {
1855 const new_inst = try self.arena.allocator.create(Inst.UnOp);
1856 new_inst.* = .{
1857 .base = .{
1858 .src = inst.src,
1859 .tag = .alloc,
1860 },
1861 .positionals = .{
1862 .operand = (try self.emitType(inst.src, inst.ty)).inst,
1863 },
1864 .kw_args = .{},
1865 };
1866 break :blk &new_inst.base;
1867 },
1868
1854 .block => blk: {1869 .block => blk: {
1855 const old_inst = inst.castTag(.block).?;1870 const old_inst = inst.castTag(.block).?;
1856 const new_inst = try self.arena.allocator.create(Inst.Block);1871 const new_inst = try self.arena.allocator.create(Inst.Block);
src-self-hosted/zir_sema.zig+4-1
...@@ -323,7 +323,10 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst....@@ -323,7 +323,10 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
323}323}
324324
325fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {325fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
326 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstAlloc", .{});326 const var_type = try resolveType(mod, scope, inst.positionals.operand);
327 const ptr_type = try mod.singleMutPtrType(scope, inst.base.src, var_type);
328 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
329 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
327}330}
328331
329fn analyzeInstAllocInferred(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {332fn analyzeInstAllocInferred(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {