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
24282428
24292429 // *[N]T to []T
24302430 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()))
24322432 {
24332433 const array_type = inst.ty.elemType();
24342434 const dst_elem_type = dest_type.elemType();
......@@ -2774,3 +2774,9 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
27742774
27752775 return Value.initPayload(val_payload);
27762776}
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 @@
11const std = @import("std");
22const mem = std.mem;
3const math = std.math;
34const assert = std.debug.assert;
45const ir = @import("ir.zig");
56const Type = @import("type.zig").Type;
......@@ -50,57 +51,58 @@ pub fn generateSymbol(
5051 switch (typed_value.ty.zigTypeTag()) {
5152 .Fn => {
5253 switch (bin_file.options.target.cpu.arch) {
53 .arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code),
54 .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_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 .arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code),
59 .avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code),
60 .bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code),
61 .bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code),
62 .hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code),
63 .mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code),
64 .mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code),
65 .mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code),
66 .mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code),
67 .msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code),
68 .powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code),
69 .powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code),
70 .powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code),
71 .r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code),
72 .amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code),
73 .riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code),
74 .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code),
75 .sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code),
76 .sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code),
77 .sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code),
78 .s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code),
79 .tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code),
80 .tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code),
81 .thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code),
82 .thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code),
83 .i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code),
54 //.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code),
55 //.armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code),
56 //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code),
57 //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code),
58 //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code),
59 //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code),
60 //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code),
61 //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code),
62 //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code),
63 //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code),
64 //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code),
65 //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code),
66 //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code),
67 //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code),
68 //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code),
69 //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code),
70 //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code),
71 //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code),
72 //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code),
73 //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code),
74 //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code),
75 //.riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code),
76 //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code),
77 //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code),
78 //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code),
79 //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code),
80 //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code),
81 //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code),
82 //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code),
83 //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code),
84 //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code),
8485 .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 .nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code),
87 .nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code),
88 .le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code),
89 .le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code),
90 .amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code),
91 .amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code),
92 .hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code),
93 .hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code),
94 .spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code),
95 .spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code),
96 .kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code),
97 .shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code),
98 .lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code),
99 .wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code),
100 .wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code),
101 .renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code),
102 .renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code),
103 .ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code),
86 //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code),
87 //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code),
88 //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code),
89 //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code),
90 //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code),
91 //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code),
92 //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code),
93 //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code),
94 //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code),
95 //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code),
96 //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code),
97 //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code),
98 //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code),
99 //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code),
100 //.wasm32 => return Function(.wasm32).generateSymbol(bin_file, src, typed_value, code),
101 //.wasm64 => return Function(.wasm64).generateSymbol(bin_file, src, typed_value, code),
102 //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code),
103 //.renderscript64 => return Function(.renderscript64).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."),
104106 }
105107 },
106108 .Array => {
......@@ -209,6 +211,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
209211 ret_mcv: MCValue,
210212 arg_index: usize,
211213 src: usize,
214 stack_align: u32,
212215
213216 /// Whenever there is a runtime branch, we push a Branch onto this stack,
214217 /// 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 {
238241 stack_offset: u64,
239242 /// The value is in the compare flags assuming an unsigned operation,
240243 /// with this operator applied on top of it.
241 compare_flags_unsigned: std.math.CompareOperator,
244 compare_flags_unsigned: math.CompareOperator,
242245 /// The value is in the compare flags assuming a signed operation,
243246 /// with this operator applied on top of it.
244 compare_flags_signed: std.math.CompareOperator,
247 compare_flags_signed: math.CompareOperator,
245248
246249 fn isMemory(mcv: MCValue) bool {
247250 return switch (mcv) {
......@@ -280,10 +283,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
280283 const Branch = struct {
281284 inst_table: std.AutoHashMapUnmanaged(*ir.Inst, MCValue) = .{},
282285 registers: std.AutoHashMapUnmanaged(Register, RegisterAllocation) = .{},
283 free_registers: FreeRegInt = std.math.maxInt(FreeRegInt),
286 free_registers: FreeRegInt = math.maxInt(FreeRegInt),
284287
285288 /// Maps offset to what is stored there.
286 stack: std.AutoHashMapUnmanaged(usize, StackAllocation) = .{},
289 stack: std.AutoHashMapUnmanaged(u32, StackAllocation) = .{},
287290 /// Offset from the stack base, representing the end of the stack frame.
288291 max_end_stack: u32 = 0,
289292 /// 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 {
293296 fn markRegUsed(self: *Branch, reg: Register) void {
294297 if (FreeRegInt == u0) return;
295298 const index = reg.allocIndex() orelse return;
296 const ShiftInt = std.math.Log2Int(FreeRegInt);
299 const ShiftInt = math.Log2Int(FreeRegInt);
297300 const shift = @intCast(ShiftInt, index);
298301 self.free_registers &= ~(@as(FreeRegInt, 1) << shift);
299302 }
......@@ -301,7 +304,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
301304 fn markRegFree(self: *Branch, reg: Register) void {
302305 if (FreeRegInt == u0) return;
303306 const index = reg.allocIndex() orelse return;
304 const ShiftInt = std.math.Log2Int(FreeRegInt);
307 const ShiftInt = math.Log2Int(FreeRegInt);
305308 const shift = @intCast(ShiftInt, index);
306309 self.free_registers |= @as(FreeRegInt, 1) << shift;
307310 }
......@@ -356,6 +359,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
356359 .arg_index = 0,
357360 .branch_stack = &branch_stack,
358361 .src = src,
362 .stack_align = undefined,
359363 };
360364
361365 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 {
366370
367371 function.args = call_info.args;
368372 function.ret_mcv = call_info.return_value;
373 function.stack_align = call_info.stack_align;
369374 branch.max_end_stack = call_info.stack_byte_count;
370375
371376 function.gen() catch |err| switch (err) {
......@@ -383,15 +388,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
383388 fn gen(self: *Self) !void {
384389 try self.code.ensureCapacity(self.code.items.len + 11);
385390
391 // TODO omit this for naked functions
386392 // push rbp
387393 // mov rbp, rsp
388394 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x55, 0x48, 0x89, 0xe5 });
389395
390396 // sub rsp, x
391397 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)) {
393399 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)) {
395401 // 48 83 ec xx sub rsp,0x10
396402 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x48, 0x81, 0xec });
397403 const x = @intCast(u32, stack_end);
......@@ -436,6 +442,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
436442 fn genFuncInst(self: *Self, inst: *ir.Inst) !MCValue {
437443 switch (inst.tag) {
438444 .add => return self.genAdd(inst.castTag(.add).?),
445 .alloc => return self.genAlloc(inst.castTag(.alloc).?),
439446 .arg => return self.genArg(inst.castTag(.arg).?),
440447 .assembly => return self.genAsm(inst.castTag(.assembly).?),
441448 .bitcast => return self.genBitCast(inst.castTag(.bitcast).?),
......@@ -465,6 +472,28 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
465472 }
466473 }
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
468497 fn genFloatCast(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
469498 // No side effects, so if it's unreferenced, do nothing.
470499 if (inst.base.isUnused())
......@@ -610,7 +639,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
610639 // and as a register.
611640 switch (src_mcv) {
612641 .immediate => |imm| {
613 if (imm > std.math.maxInt(u31)) {
642 if (imm > math.maxInt(u31)) {
614643 src_mcv = try self.copyToNewRegister(src_inst);
615644 }
616645 },
......@@ -639,7 +668,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
639668 .immediate => |imm| {
640669 const imm32 = @intCast(u31, imm); // This case must be handled before calling genX8664BinMathCode.
641670 // 81 /opx id
642 if (imm32 <= std.math.maxInt(u7)) {
671 if (imm32 <= math.maxInt(u7)) {
643672 self.rex(.{ .b = dst_reg.isExtended(), .w = dst_reg.size() == 64 });
644673 self.code.appendSliceAssumeCapacity(&[_]u8{
645674 0x83,
......@@ -785,7 +814,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
785814 return self.ret(inst.base.src, .none);
786815 }
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 {
789818 // No side effects, so if it's unreferenced, do nothing.
790819 if (inst.base.isUnused())
791820 return MCValue.dead;
......@@ -909,7 +938,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
909938 switch (reloc) {
910939 .rel32 => |pos| {
911940 const amt = self.code.items.len - (pos + 4);
912 const s32_amt = std.math.cast(i32, amt) catch
941 const s32_amt = math.cast(i32, amt) catch
913942 return self.fail(src, "unable to perform relocation: jump too far", .{});
914943 mem.writeIntLittle(i32, self.code.items[pos..][0..4], s32_amt);
915944 },
......@@ -1070,7 +1099,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10701099 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x31, 0xC0 | id << 3 | id });
10711100 return;
10721101 }
1073 if (x <= std.math.maxInt(u32)) {
1102 if (x <= math.maxInt(u32)) {
10741103 // Next best case: if we set the lower four bytes, the upper four will be zeroed.
10751104 //
10761105 // The encoding for `mov IMM32 -> REG` is (0xB8 + R) IMM.
......@@ -1152,7 +1181,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
11521181 if (reg.size() != 64) {
11531182 return self.fail(src, "TODO decide whether to implement non-64-bit loads", .{});
11541183 }
1155 if (x <= std.math.maxInt(u32)) {
1184 if (x <= math.maxInt(u32)) {
11561185 // Moving from memory to a register is a variant of `8B /r`.
11571186 // Since we're using 64-bit moves, we require a REX.
11581187 // 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 {
12851314 .is_signed = false,
12861315 },
12871316 });
1288 if (imm >= std.math.maxInt(U)) {
1317 if (imm >= math.maxInt(U)) {
12891318 return self.copyToNewRegister(inst);
12901319 }
12911320 },
......@@ -1327,6 +1356,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13271356 args: []MCValue,
13281357 return_value: MCValue,
13291358 stack_byte_count: u32,
1359 stack_align: u32,
13301360
13311361 fn deinit(self: *CallMCValues, func: *Self) void {
13321362 func.gpa.free(self.args);
......@@ -1342,8 +1372,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13421372 fn_ty.fnParamTypes(param_types);
13431373 var result: CallMCValues = .{
13441374 .args = try self.gpa.alloc(MCValue, param_types.len),
1375 // These undefined values must be populated before returning from this function.
13451376 .return_value = undefined,
13461377 .stack_byte_count = undefined,
1378 .stack_align = undefined,
13471379 };
13481380 errdefer self.gpa.free(result.args);
13491381
......@@ -1356,6 +1388,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13561388 assert(result.args.len == 0);
13571389 result.return_value = .{ .unreach = {} };
13581390 result.stack_byte_count = 0;
1391 result.stack_align = 1;
13591392 return result;
13601393 },
13611394 .Unspecified, .C => {
......@@ -1377,6 +1410,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13771410 }
13781411 }
13791412 result.stack_byte_count = next_stack_offset;
1413 result.stack_align = 16;
13801414 },
13811415 else => return self.fail(src, "TODO implement function parameters for {}", .{cc}),
13821416 }
src-self-hosted/ir.zig+3-3
......@@ -4,6 +4,7 @@ const Type = @import("type.zig").Type;
44const Module = @import("Module.zig");
55const assert = std.debug.assert;
66const codegen = @import("codegen.zig");
7const ast = std.zig.ast;
78
89/// These are in-memory, analyzed instructions. See `zir.Inst` for the representation
910/// of instructions that correspond to the ZIR text format.
......@@ -47,6 +48,7 @@ pub const Inst = struct {
4748
4849 pub const Tag = enum {
4950 add,
51 alloc,
5052 arg,
5153 assembly,
5254 bitcast,
......@@ -74,11 +76,9 @@ pub const Inst = struct {
7476 floatcast,
7577 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.
8079 pub fn Type(tag: Tag) type {
8180 return switch (tag) {
81 .alloc,
8282 .retvoid,
8383 .unreach,
8484 .arg,
src-self-hosted/type.zig+51-3
......@@ -67,6 +67,7 @@ pub const Type = extern union {
6767
6868 .array, .array_u8_sentinel_0 => return .Array,
6969 .single_const_pointer => return .Pointer,
70 .single_mut_pointer => return .Pointer,
7071 .single_const_pointer_to_comptime_int => return .Pointer,
7172 .const_slice_u8 => return .Pointer,
7273 }
......@@ -261,6 +262,15 @@ pub const Type = extern union {
261262 };
262263 return Type{ .ptr_otherwise = &new_payload.base };
263264 },
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 },
264274 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
265275 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
266276 .function => {
......@@ -368,6 +378,12 @@ pub const Type = extern union {
368378 ty = payload.pointee_type;
369379 continue;
370380 },
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 },
371387 .int_signed => {
372388 const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise);
373389 return out_stream.print("i{}", .{payload.bits});
......@@ -467,6 +483,7 @@ pub const Type = extern union {
467483 .array_u8_sentinel_0,
468484 .array, // TODO check for zero bits
469485 .single_const_pointer,
486 .single_mut_pointer,
470487 .int_signed, // TODO check for zero bits
471488 .int_unsigned, // TODO check for zero bits
472489 => true,
......@@ -510,6 +527,7 @@ pub const Type = extern union {
510527 .single_const_pointer_to_comptime_int,
511528 .const_slice_u8,
512529 .single_const_pointer,
530 .single_mut_pointer,
513531 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
514532
515533 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
......@@ -591,6 +609,7 @@ pub const Type = extern union {
591609 .single_const_pointer_to_comptime_int,
592610 .const_slice_u8,
593611 .single_const_pointer,
612 .single_mut_pointer,
594613 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
595614
596615 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
......@@ -671,6 +690,7 @@ pub const Type = extern union {
671690 => false,
672691
673692 .single_const_pointer,
693 .single_mut_pointer,
674694 .single_const_pointer_to_comptime_int,
675695 => true,
676696 };
......@@ -714,6 +734,7 @@ pub const Type = extern union {
714734 .array,
715735 .array_u8_sentinel_0,
716736 .single_const_pointer,
737 .single_mut_pointer,
717738 .single_const_pointer_to_comptime_int,
718739 .fn_noreturn_no_args,
719740 .fn_void_no_args,
......@@ -728,8 +749,7 @@ pub const Type = extern union {
728749 };
729750 }
730751
731 /// Asserts the type is a pointer type.
732 pub fn pointerIsConst(self: Type) bool {
752 pub fn isConstPtr(self: Type) bool {
733753 return switch (self.tag()) {
734754 .u8,
735755 .i8,
......@@ -773,7 +793,8 @@ pub const Type = extern union {
773793 .function,
774794 .int_unsigned,
775795 .int_signed,
776 => unreachable,
796 .single_mut_pointer,
797 => false,
777798
778799 .single_const_pointer,
779800 .single_const_pointer_to_comptime_int,
......@@ -829,6 +850,7 @@ pub const Type = extern union {
829850
830851 .array => self.cast(Payload.Array).?.elem_type,
831852 .single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type,
853 .single_mut_pointer => self.cast(Payload.SingleMutPointer).?.pointee_type,
832854 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
833855 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
834856 };
......@@ -876,6 +898,7 @@ pub const Type = extern union {
876898 .fn_ccc_void_no_args,
877899 .function,
878900 .single_const_pointer,
901 .single_mut_pointer,
879902 .single_const_pointer_to_comptime_int,
880903 .const_slice_u8,
881904 .int_unsigned,
......@@ -929,6 +952,7 @@ pub const Type = extern union {
929952 .fn_ccc_void_no_args,
930953 .function,
931954 .single_const_pointer,
955 .single_mut_pointer,
932956 .single_const_pointer_to_comptime_int,
933957 .const_slice_u8,
934958 .int_unsigned,
......@@ -970,6 +994,7 @@ pub const Type = extern union {
970994 .function,
971995 .array,
972996 .single_const_pointer,
997 .single_mut_pointer,
973998 .single_const_pointer_to_comptime_int,
974999 .array_u8_sentinel_0,
9751000 .const_slice_u8,
......@@ -1024,6 +1049,7 @@ pub const Type = extern union {
10241049 .function,
10251050 .array,
10261051 .single_const_pointer,
1052 .single_mut_pointer,
10271053 .single_const_pointer_to_comptime_int,
10281054 .array_u8_sentinel_0,
10291055 .const_slice_u8,
......@@ -1078,6 +1104,7 @@ pub const Type = extern union {
10781104 .function,
10791105 .array,
10801106 .single_const_pointer,
1107 .single_mut_pointer,
10811108 .single_const_pointer_to_comptime_int,
10821109 .array_u8_sentinel_0,
10831110 .const_slice_u8,
......@@ -1130,6 +1157,7 @@ pub const Type = extern union {
11301157 .function,
11311158 .array,
11321159 .single_const_pointer,
1160 .single_mut_pointer,
11331161 .single_const_pointer_to_comptime_int,
11341162 .array_u8_sentinel_0,
11351163 .const_slice_u8,
......@@ -1211,6 +1239,7 @@ pub const Type = extern union {
12111239 .@"undefined",
12121240 .array,
12131241 .single_const_pointer,
1242 .single_mut_pointer,
12141243 .single_const_pointer_to_comptime_int,
12151244 .array_u8_sentinel_0,
12161245 .const_slice_u8,
......@@ -1268,6 +1297,7 @@ pub const Type = extern union {
12681297 .@"undefined",
12691298 .array,
12701299 .single_const_pointer,
1300 .single_mut_pointer,
12711301 .single_const_pointer_to_comptime_int,
12721302 .array_u8_sentinel_0,
12731303 .const_slice_u8,
......@@ -1324,6 +1354,7 @@ pub const Type = extern union {
13241354 .@"undefined",
13251355 .array,
13261356 .single_const_pointer,
1357 .single_mut_pointer,
13271358 .single_const_pointer_to_comptime_int,
13281359 .array_u8_sentinel_0,
13291360 .const_slice_u8,
......@@ -1380,6 +1411,7 @@ pub const Type = extern union {
13801411 .@"undefined",
13811412 .array,
13821413 .single_const_pointer,
1414 .single_mut_pointer,
13831415 .single_const_pointer_to_comptime_int,
13841416 .array_u8_sentinel_0,
13851417 .const_slice_u8,
......@@ -1433,6 +1465,7 @@ pub const Type = extern union {
14331465 .@"undefined",
14341466 .array,
14351467 .single_const_pointer,
1468 .single_mut_pointer,
14361469 .single_const_pointer_to_comptime_int,
14371470 .array_u8_sentinel_0,
14381471 .const_slice_u8,
......@@ -1486,6 +1519,7 @@ pub const Type = extern union {
14861519 .@"undefined",
14871520 .array,
14881521 .single_const_pointer,
1522 .single_mut_pointer,
14891523 .single_const_pointer_to_comptime_int,
14901524 .array_u8_sentinel_0,
14911525 .const_slice_u8,
......@@ -1559,6 +1593,7 @@ pub const Type = extern union {
15591593 .function,
15601594 .array,
15611595 .single_const_pointer,
1596 .single_mut_pointer,
15621597 .single_const_pointer_to_comptime_int,
15631598 .array_u8_sentinel_0,
15641599 .const_slice_u8,
......@@ -1628,6 +1663,11 @@ pub const Type = extern union {
16281663 ty = ptr.pointee_type;
16291664 continue;
16301665 },
1666 .single_mut_pointer => {
1667 const ptr = ty.cast(Payload.SingleMutPointer).?;
1668 ty = ptr.pointee_type;
1669 continue;
1670 },
16311671 };
16321672 }
16331673
......@@ -1678,6 +1718,7 @@ pub const Type = extern union {
16781718 .int_signed,
16791719 .array,
16801720 .single_const_pointer,
1721 .single_mut_pointer,
16811722 => return false,
16821723 };
16831724 }
......@@ -1734,6 +1775,7 @@ pub const Type = extern union {
17341775 array_u8_sentinel_0,
17351776 array,
17361777 single_const_pointer,
1778 single_mut_pointer,
17371779 int_signed,
17381780 int_unsigned,
17391781 function,
......@@ -1764,6 +1806,12 @@ pub const Type = extern union {
17641806 pointee_type: Type,
17651807 };
17661808
1809 pub const SingleMutPointer = struct {
1810 base: Payload = Payload{ .tag = .single_mut_pointer },
1811
1812 pointee_type: Type,
1813 };
1814
17671815 pub const IntSigned = struct {
17681816 base: Payload = Payload{ .tag = .int_signed },
17691817
src-self-hosted/zir.zig+16-1
......@@ -39,7 +39,7 @@ pub const Inst = struct {
3939 /// Twos complement wrapping integer addition.
4040 addwrap,
4141 /// 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.
4343 alloc,
4444 /// Same as `alloc` except the type is inferred.
4545 alloc_inferred,
......@@ -1851,6 +1851,21 @@ const EmitZIR = struct {
18511851 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast),
18521852 .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
18541869 .block => blk: {
18551870 const old_inst = inst.castTag(.block).?;
18561871 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.
323323}
324324
325325fn 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);
327330}
328331
329332fn analyzeInstAllocInferred(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {