Skip to content

Commit 2438970

Browse files
committed
stage2: remove operand from return instruction
Keeping the return instruction as simple as possible has multiple benefits: * more accurately models machine code * removes separate handling of less than pointer sized values * makes it easier to generate defers without code duplication
1 parent b3b00ec commit 2438970

File tree

8 files changed

+52
-81
lines changed

8 files changed

+52
-81
lines changed

src-self-hosted/Module.zig

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,11 +1236,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12361236
};
12371237

12381238
const return_type_inst = try astgen.expr(self, &fn_type_scope.base, type_type_rl, return_type_expr);
1239-
const fn_type_inst = try astgen.addZIRInst(self, &fn_type_scope.base, fn_src, zir.Inst.FnType, .{
1239+
_ = try astgen.addZIRInst(self, &fn_type_scope.base, fn_src, zir.Inst.FnType, .{
12401240
.return_type = return_type_inst,
12411241
.param_types = param_types,
12421242
}, .{});
1243-
_ = try astgen.addZIRUnOp(self, &fn_type_scope.base, fn_src, .@"return", fn_type_inst);
12441243

12451244
// We need the memory for the Type to go into the arena for the Decl
12461245
var decl_arena = std.heap.ArenaAllocator.init(self.gpa);
@@ -1309,7 +1308,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
13091308
!gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()))
13101309
{
13111310
const src = tree.token_locs[body_block.rbrace].start;
1312-
_ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid);
1311+
_ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .@"return");
13131312
}
13141313

13151314
const fn_zir = try gen_scope_arena.allocator.create(Fn.ZIR);

src-self-hosted/astgen.zig

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -457,18 +457,11 @@ fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerE
457457
const tree = scope.tree();
458458
const src = tree.token_locs[cfe.ltoken].start;
459459
if (cfe.getRHS()) |rhs_node| {
460-
if (nodeMayNeedMemoryLocation(rhs_node)) {
461-
const ret_ptr = try addZIRNoOp(mod, scope, src, .ret_ptr);
462-
const operand = try expr(mod, scope, .{ .ptr = ret_ptr }, rhs_node);
463-
return addZIRUnOp(mod, scope, src, .@"return", operand);
464-
} else {
465-
const fn_ret_ty = try addZIRNoOp(mod, scope, src, .ret_type);
466-
const operand = try expr(mod, scope, .{ .ty = fn_ret_ty }, rhs_node);
467-
return addZIRUnOp(mod, scope, src, .@"return", operand);
468-
}
469-
} else {
470-
return addZIRNoOp(mod, scope, src, .returnvoid);
460+
const ret_ptr = try addZIRNoOp(mod, scope, src, .ret_ptr);
461+
// result location will take care of storing the result
462+
_ = try expr(mod, scope, .{ .ptr = ret_ptr }, rhs_node);
471463
}
464+
return addZIRNoOp(mod, scope, src, .@"return");
472465
}
473466

474467
fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneToken) InnerError!*zir.Inst {

src-self-hosted/codegen.zig

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
552552
.ptrtoint => return self.genPtrToInt(inst.castTag(.ptrtoint).?),
553553
.ref => return self.genRef(inst.castTag(.ref).?),
554554
.ret => return self.genRet(inst.castTag(.ret).?),
555-
.retvoid => return self.genRetVoid(inst.castTag(.retvoid).?),
555+
.ret_ptr => return self.genRetPtr(inst.castTag(.ret_ptr).?),
556556
.store => return self.genStore(inst.castTag(.store).?),
557557
.sub => return self.genSub(inst.castTag(.sub).?),
558558
.unreach => return MCValue{ .unreach = {} },
@@ -773,8 +773,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
773773
.embedded_in_code => {
774774
return self.fail(inst.base.src, "TODO implement storing to MCValue.embedded_in_code", .{});
775775
},
776-
.register => {
777-
return self.fail(inst.base.src, "TODO implement storing to MCValue.register", .{});
776+
.register => |reg| {
777+
try self.setRegOrMem(inst.base.src, elem_ty, .{ .register = reg }, value);
778778
},
779779
.memory => {
780780
return self.fail(inst.base.src, "TODO implement storing to MCValue.memory", .{});
@@ -1044,9 +1044,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10441044
}
10451045
}
10461046

1047-
fn ret(self: *Self, src: usize, mcv: MCValue) !MCValue {
1048-
const ret_ty = self.fn_type.fnReturnType();
1049-
try self.setRegOrMem(src, ret_ty, self.ret_mcv, mcv);
1047+
fn genRet(self: *Self, inst: *ir.Inst.NoOp) !MCValue {
10501048
switch (arch) {
10511049
.i386 => {
10521050
try self.code.append(0xc3); // ret
@@ -1059,18 +1057,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
10591057
self.code.items[self.code.items.len - 5] = 0xe9; // jmp rel32
10601058
try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4);
10611059
},
1062-
else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),
1060+
else => return self.fail(inst.base.src, "TODO implement return for {}", .{self.target.cpu.arch}),
10631061
}
10641062
return .unreach;
10651063
}
10661064

1067-
fn genRet(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1068-
const operand = try self.resolveInst(inst.operand);
1069-
return self.ret(inst.base.src, operand);
1070-
}
1071-
1072-
fn genRetVoid(self: *Self, inst: *ir.Inst.NoOp) !MCValue {
1073-
return self.ret(inst.base.src, .none);
1065+
fn genRetPtr(self: *Self, inst: *ir.Inst.NoOp) !MCValue {
1066+
return self.ret_mcv;
10741067
}
10751068

10761069
fn genCmp(self: *Self, inst: *ir.Inst.BinOp, op: math.CompareOperator) !MCValue {

src-self-hosted/codegen/c.zig

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ fn genFn(file: *C, decl: *Decl) !void {
9494
switch (inst.tag) {
9595
.assembly => try genAsm(file, inst.castTag(.assembly).?, decl),
9696
.call => try genCall(file, inst.castTag(.call).?, decl),
97-
.ret => try genRet(file, inst.castTag(.ret).?, decl, tv.ty.fnReturnType()),
98-
.retvoid => try file.main.writer().print("return;", .{}),
97+
.ret => try file.main.writer().print("return;", .{}),
9998
else => |e| return file.fail(decl.src(), "TODO implement C codegen for {}", .{e}),
10099
}
101100
}
@@ -105,10 +104,6 @@ fn genFn(file: *C, decl: *Decl) !void {
105104
try writer.writeAll("}\n\n");
106105
}
107106

108-
fn genRet(file: *C, inst: *Inst.UnOp, decl: *Decl, expected_return_type: Type) !void {
109-
return file.fail(decl.src(), "TODO return {}", .{expected_return_type});
110-
}
111-
112107
fn genCall(file: *C, inst: *Inst.Call, decl: *Decl) !void {
113108
const writer = file.main.writer();
114109
const header = file.header.writer();

src-self-hosted/ir.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ pub const Inst = struct {
7171
load,
7272
ptrtoint,
7373
ref,
74+
ret_ptr,
7475
ret,
75-
retvoid,
7676
/// Write a value to a pointer. LHS is pointer, RHS is value.
7777
store,
7878
sub,
@@ -84,14 +84,14 @@ pub const Inst = struct {
8484
pub fn Type(tag: Tag) type {
8585
return switch (tag) {
8686
.alloc,
87-
.retvoid,
8887
.unreach,
8988
.arg,
9089
.breakpoint,
90+
.ret_ptr,
91+
.ret,
9192
=> NoOp,
9293

9394
.ref,
94-
.ret,
9595
.bitcast,
9696
.not,
9797
.isnonnull,

src-self-hosted/zir.zig

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,8 @@ pub const Inst = struct {
175175
ret_ptr,
176176
/// Obtains the return type of the in-scope function.
177177
ret_type,
178-
/// Sends control flow back to the function's callee. Takes an operand as the return value.
178+
/// Sends control flow back to the function's callee.
179179
@"return",
180-
/// Same as `return` but there is no operand; the operand is implicitly the void value.
181-
returnvoid,
182180
/// Integer shift-left. Zeroes are shifted in from the right hand side.
183181
shl,
184182
/// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
@@ -211,17 +209,16 @@ pub const Inst = struct {
211209
return switch (tag) {
212210
.arg,
213211
.breakpoint,
214-
.returnvoid,
215212
.alloc_inferred,
216213
.ret_ptr,
217214
.ret_type,
218215
.unreach_nocheck,
219216
.@"unreachable",
217+
.@"return",
220218
=> NoOp,
221219

222220
.boolnot,
223221
.deref,
224-
.@"return",
225222
.isnull,
226223
.isnonnull,
227224
.ptrtoint,
@@ -369,7 +366,6 @@ pub const Inst = struct {
369366
.condbr,
370367
.compileerror,
371368
.@"return",
372-
.returnvoid,
373369
.unreach_nocheck,
374370
.@"unreachable",
375371
=> true,
@@ -1842,10 +1838,10 @@ const EmitZIR = struct {
18421838
.arg => try self.emitNoOp(inst.src, .arg),
18431839
.breakpoint => try self.emitNoOp(inst.src, .breakpoint),
18441840
.unreach => try self.emitNoOp(inst.src, .@"unreachable"),
1845-
.retvoid => try self.emitNoOp(inst.src, .returnvoid),
1841+
.ret => try self.emitNoOp(inst.src, .@"return"),
1842+
.ret_ptr => try self.emitNoOp(inst.src, .ret_ptr),
18461843

18471844
.not => try self.emitUnOp(inst.src, new_body, inst.castTag(.not).?, .boolnot),
1848-
.ret => try self.emitUnOp(inst.src, new_body, inst.castTag(.ret).?, .@"return"),
18491845
.ptrtoint => try self.emitUnOp(inst.src, new_body, inst.castTag(.ptrtoint).?, .ptrtoint),
18501846
.isnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnull).?, .isnull),
18511847
.isnonnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnonnull).?, .isnonnull),

src-self-hosted/zir_sema.zig

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
6868
.@"unreachable" => return analyzeInstUnreachable(mod, scope, old_inst.castTag(.@"unreachable").?),
6969
.unreach_nocheck => return analyzeInstUnreachNoChk(mod, scope, old_inst.castTag(.unreach_nocheck).?),
7070
.@"return" => return analyzeInstRet(mod, scope, old_inst.castTag(.@"return").?),
71-
.returnvoid => return analyzeInstRetVoid(mod, scope, old_inst.castTag(.returnvoid).?),
7271
.@"fn" => return analyzeInstFn(mod, scope, old_inst.castTag(.@"fn").?),
7372
.@"export" => return analyzeInstExport(mod, scope, old_inst.castTag(.@"export").?),
7473
.primitive => return analyzeInstPrimitive(mod, scope, old_inst.castTag(.primitive).?),
@@ -114,15 +113,10 @@ pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void {
114113

115114
pub fn analyzeBodyValueAsType(mod: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type {
116115
try analyzeBody(mod, &block_scope.base, body);
117-
for (block_scope.instructions.items) |inst| {
118-
if (inst.castTag(.ret)) |ret| {
119-
const val = try mod.resolveConstValue(&block_scope.base, ret.operand);
120-
return val.toType();
121-
} else {
122-
return mod.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
123-
}
124-
}
125-
unreachable;
116+
117+
const result_type = body.instructions[body.instructions.len - 1];
118+
const val = try mod.resolveConstValue(&block_scope.base, result_type.analyzed_inst.?);
119+
return val.toType();
126120
}
127121

128122
pub fn analyzeZirDecl(mod: *Module, decl: *Decl, src_decl: *zir.Decl) InnerError!bool {
@@ -297,7 +291,14 @@ fn analyzeInstCoerceToPtrElem(mod: *Module, scope: *Scope, inst: *zir.Inst.Coerc
297291
}
298292

299293
fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
300-
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstRetPtr", .{});
294+
const b = try mod.requireRuntimeBlock(scope, inst.base.src);
295+
const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
296+
const ret_type = fn_ty.fnReturnType();
297+
298+
const ptr_payload = try scope.arena().create(Type.Payload.SingleMutPointer);
299+
ptr_payload.* = .{ .pointee_type = ret_type };
300+
301+
return mod.addNoOp(b, inst.base.src, Type.initPayload(&ptr_payload.base), .ret_ptr);
301302
}
302303

303304
fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
@@ -1091,15 +1092,9 @@ fn analyzeInstUnreachable(mod: *Module, scope: *Scope, unreach: *zir.Inst.NoOp)
10911092
return mod.analyzeUnreach(scope, unreach.base.src);
10921093
}
10931094

1094-
fn analyzeInstRet(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1095-
const operand = try resolveInst(mod, scope, inst.positionals.operand);
1096-
const b = try mod.requireRuntimeBlock(scope, inst.base.src);
1097-
return mod.addUnOp(b, inst.base.src, Type.initTag(.noreturn), .ret, operand);
1098-
}
1099-
1100-
fn analyzeInstRetVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
1095+
fn analyzeInstRet(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
11011096
const b = try mod.requireRuntimeBlock(scope, inst.base.src);
1102-
return mod.addNoOp(b, inst.base.src, Type.initTag(.noreturn), .retvoid);
1097+
return try mod.addNoOp(b, inst.base.src, Type.initTag(.noreturn), .ret);
11031098
}
11041099

11051100
fn floatOpAllowed(tag: zir.Inst.Tag) bool {

test/stage2/zir.zig

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub fn addCases(ctx: *TestContext) !void {
1717
\\@11 = export(@9, "entry")
1818
\\
1919
\\@entry = fn(@fnty, {
20-
\\ %11 = returnvoid()
20+
\\ %11 = return()
2121
\\})
2222
,
2323
\\@void = primitive(void)
@@ -28,7 +28,7 @@ pub fn addCases(ctx: *TestContext) !void {
2828
\\@unnamed$5 = export(@unnamed$4, "entry")
2929
\\@unnamed$6 = fntype([], @void, cc=C)
3030
\\@entry = fn(@unnamed$6, {
31-
\\ %0 = returnvoid()
31+
\\ %0 = return()
3232
\\})
3333
\\
3434
);
@@ -58,7 +58,7 @@ pub fn addCases(ctx: *TestContext) !void {
5858
\\ %expected = int(69)
5959
\\ %ok = cmp_eq(%result, %expected)
6060
\\ %10 = condbr(%ok, {
61-
\\ %11 = returnvoid()
61+
\\ %11 = return()
6262
\\ }, {
6363
\\ %12 = breakpoint()
6464
\\ })
@@ -75,7 +75,7 @@ pub fn addCases(ctx: *TestContext) !void {
7575
\\@3 = int(3)
7676
\\@unnamed$6 = fntype([], @void, cc=C)
7777
\\@entry = fn(@unnamed$6, {
78-
\\ %0 = returnvoid()
78+
\\ %0 = return()
7979
\\})
8080
\\@entry__anon_1 = str("2\x08\x01\n")
8181
\\@9 = declref("9__anon_0")
@@ -96,17 +96,17 @@ pub fn addCases(ctx: *TestContext) !void {
9696
\\
9797
\\@entry = fn(@fnty, {
9898
\\ %0 = call(@a, [])
99-
\\ %1 = returnvoid()
99+
\\ %1 = return()
100100
\\})
101101
\\
102102
\\@a = fn(@fnty, {
103103
\\ %0 = call(@b, [])
104-
\\ %1 = returnvoid()
104+
\\ %1 = return()
105105
\\})
106106
\\
107107
\\@b = fn(@fnty, {
108108
\\ %0 = call(@a, [])
109-
\\ %1 = returnvoid()
109+
\\ %1 = return()
110110
\\})
111111
,
112112
\\@void = primitive(void)
@@ -118,17 +118,17 @@ pub fn addCases(ctx: *TestContext) !void {
118118
\\@unnamed$6 = fntype([], @void, cc=C)
119119
\\@entry = fn(@unnamed$6, {
120120
\\ %0 = call(@a, [], modifier=auto)
121-
\\ %1 = returnvoid()
121+
\\ %1 = return()
122122
\\})
123123
\\@unnamed$8 = fntype([], @void, cc=C)
124124
\\@a = fn(@unnamed$8, {
125125
\\ %0 = call(@b, [], modifier=auto)
126-
\\ %1 = returnvoid()
126+
\\ %1 = return()
127127
\\})
128128
\\@unnamed$10 = fntype([], @void, cc=C)
129129
\\@b = fn(@unnamed$10, {
130130
\\ %0 = call(@a, [], modifier=auto)
131-
\\ %1 = returnvoid()
131+
\\ %1 = return()
132132
\\})
133133
\\
134134
);
@@ -142,18 +142,18 @@ pub fn addCases(ctx: *TestContext) !void {
142142
\\
143143
\\@entry = fn(@fnty, {
144144
\\ %0 = call(@a, [])
145-
\\ %1 = returnvoid()
145+
\\ %1 = return()
146146
\\})
147147
\\
148148
\\@a = fn(@fnty, {
149149
\\ %0 = call(@b, [])
150-
\\ %1 = returnvoid()
150+
\\ %1 = return()
151151
\\})
152152
\\
153153
\\@b = fn(@fnty, {
154154
\\ %9 = compileerror("message")
155155
\\ %0 = call(@a, [])
156-
\\ %1 = returnvoid()
156+
\\ %1 = return()
157157
\\})
158158
,
159159
&[_][]const u8{
@@ -171,18 +171,18 @@ pub fn addCases(ctx: *TestContext) !void {
171171
\\@11 = export(@9, "entry")
172172
\\
173173
\\@entry = fn(@fnty, {
174-
\\ %0 = returnvoid()
174+
\\ %0 = return()
175175
\\})
176176
\\
177177
\\@a = fn(@fnty, {
178178
\\ %0 = call(@b, [])
179-
\\ %1 = returnvoid()
179+
\\ %1 = return()
180180
\\})
181181
\\
182182
\\@b = fn(@fnty, {
183183
\\ %9 = compileerror("message")
184184
\\ %0 = call(@a, [])
185-
\\ %1 = returnvoid()
185+
\\ %1 = return()
186186
\\})
187187
,
188188
\\@void = primitive(void)
@@ -193,7 +193,7 @@ pub fn addCases(ctx: *TestContext) !void {
193193
\\@unnamed$5 = export(@unnamed$4, "entry")
194194
\\@unnamed$6 = fntype([], @void, cc=C)
195195
\\@entry = fn(@unnamed$6, {
196-
\\ %0 = returnvoid()
196+
\\ %0 = return()
197197
\\})
198198
\\
199199
);

0 commit comments

Comments
 (0)