authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-26 19:53:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-26 19:53:49-07:00
log5fed721290cc7ecf396b7815f830e1fabe8b4711
tree851e5f39cdfd916c395e405d29ddad056c29d5df
parent7d0bb0774e957e81fee7240d410944a0a56c303d
parentb0995cb9f9540a6d463dcc2722cb3b8918a61e8e

Merge branch 'Vexu-stage2'

closes #6175

9 files changed, 500 insertions(+), 45 deletions(-)

src-self-hosted/Module.zig+12-1
...@@ -2570,7 +2570,18 @@ pub fn analyzeIsNull(...@@ -2570,7 +2570,18 @@ pub fn analyzeIsNull(
2570 operand: *Inst,2570 operand: *Inst,
2571 invert_logic: bool,2571 invert_logic: bool,
2572) InnerError!*Inst {2572) InnerError!*Inst {
2573 return self.fail(scope, src, "TODO implement analysis of isnull and isnotnull", .{});2573 if (operand.value()) |opt_val| {
2574 const is_null = opt_val.isNull();
2575 const bool_value = if (invert_logic) !is_null else is_null;
2576 return self.constBool(scope, src, bool_value);
2577 }
2578 const b = try self.requireRuntimeBlock(scope, src);
2579 const inst_tag: Inst.Tag = if (invert_logic) .isnonnull else .isnull;
2580 return self.addUnOp(b, src, Type.initTag(.bool), inst_tag, operand);
2581}
2582
2583pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst {
2584 return self.fail(scope, src, "TODO implement analysis of iserr", .{});
2574}2585}
25752586
2576/// Asserts that lhs and rhs types are both numeric.2587/// Asserts that lhs and rhs types are both numeric.
src-self-hosted/astgen.zig+284-8
...@@ -273,22 +273,22 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr...@@ -273,22 +273,22 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
273 .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)),273 .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)),
274 .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?),274 .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?),
275 .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),275 .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),
276 .For => return forExpr(mod, scope, rl, node.castTag(.For).?),
277 .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),
278 .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),
276279
277 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),280 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
278 .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
279 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),281 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
280 .OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}),282 .OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}),
281 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),283 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
282 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),284 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
283 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),285 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
284 .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),286 .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
285 .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}),
286 .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),287 .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}),
287 .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}),288 .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}),
288 .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}),289 .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}),
289 .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}),290 .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}),
290 .Switch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Switch", .{}),291 .Switch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Switch", .{}),
291 .For => return mod.failNode(scope, node, "TODO implement astgen.expr for .For", .{}),
292 .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}),292 .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}),
293 .Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}),293 .Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}),
294 .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}),294 .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}),
...@@ -497,7 +497,7 @@ fn varDecl(...@@ -497,7 +497,7 @@ fn varDecl(
497 const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTrailer("type_node")) |type_node| a: {497 const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTrailer("type_node")) |type_node| a: {
498 const type_inst = try typeExpr(mod, scope, type_node);498 const type_inst = try typeExpr(mod, scope, type_node);
499 const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst);499 const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst);
500 break :a .{ .alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst), .result_loc = .{ .ptr = alloc } };500 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
501 } else a: {501 } else a: {
502 const alloc = try addZIRNoOp(mod, scope, name_src, .alloc_inferred);502 const alloc = try addZIRNoOp(mod, scope, name_src, .alloc_inferred);
503 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred).? } };503 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred).? } };
...@@ -624,7 +624,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo,...@@ -624,7 +624,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo,
624 .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type,624 .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type,
625 .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type,625 .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type,
626 .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type,626 .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type,
627 .Slice => if (mutable) T.mut_slice_type else T.mut_slice_type,627 .Slice => if (mutable) T.mut_slice_type else T.const_slice_type,
628 }, child_type);628 }, child_type);
629 }629 }
630630
...@@ -750,6 +750,93 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*...@@ -750,6 +750,93 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*
750 });750 });
751}751}
752752
753fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst {
754 const tree = scope.tree();
755 const src = tree.token_locs[node.op_token].start;
756
757 const err_union_ptr = try expr(mod, scope, .ref, node.lhs);
758 // TODO we could avoid an unnecessary copy if .iserr took a pointer
759 const err_union = try addZIRUnOp(mod, scope, src, .deref, err_union_ptr);
760 const cond = try addZIRUnOp(mod, scope, src, .iserr, err_union);
761
762 var block_scope: Scope.GenZIR = .{
763 .parent = scope,
764 .decl = scope.decl().?,
765 .arena = scope.arena(),
766 .instructions = .{},
767 };
768 defer block_scope.instructions.deinit(mod.gpa);
769
770 const condbr = try addZIRInstSpecial(mod, &block_scope.base, src, zir.Inst.CondBr, .{
771 .condition = cond,
772 .then_body = undefined, // populated below
773 .else_body = undefined, // populated below
774 }, .{});
775
776 const block = try addZIRInstBlock(mod, scope, src, .{
777 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
778 });
779
780 // Most result location types can be forwarded directly; however
781 // if we need to write to a pointer which has an inferred type,
782 // proper type inference requires peer type resolution on the if's
783 // branches.
784 const branch_rl: ResultLoc = switch (rl) {
785 .discard, .none, .ty, .ptr, .ref => rl,
786 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
787 };
788
789 var err_scope: Scope.GenZIR = .{
790 .parent = scope,
791 .decl = block_scope.decl,
792 .arena = block_scope.arena,
793 .instructions = .{},
794 };
795 defer err_scope.instructions.deinit(mod.gpa);
796
797 var err_val_scope: Scope.LocalVal = undefined;
798 const err_sub_scope = blk: {
799 const payload = node.payload orelse
800 break :blk &err_scope.base;
801
802 const err_name = tree.tokenSlice(payload.castTag(.Payload).?.error_symbol.firstToken());
803 if (mem.eql(u8, err_name, "_"))
804 break :blk &err_scope.base;
805
806 const unwrapped_err_ptr = try addZIRUnOp(mod, &err_scope.base, src, .unwrap_err_code, err_union_ptr);
807 err_val_scope = .{
808 .parent = &err_scope.base,
809 .gen_zir = &err_scope,
810 .name = err_name,
811 .inst = try addZIRUnOp(mod, &err_scope.base, src, .deref, unwrapped_err_ptr),
812 };
813 break :blk &err_val_scope.base;
814 };
815
816 _ = try addZIRInst(mod, &err_scope.base, src, zir.Inst.Break, .{
817 .block = block,
818 .operand = try expr(mod, err_sub_scope, branch_rl, node.rhs),
819 }, .{});
820
821 var not_err_scope: Scope.GenZIR = .{
822 .parent = scope,
823 .decl = block_scope.decl,
824 .arena = block_scope.arena,
825 .instructions = .{},
826 };
827 defer not_err_scope.instructions.deinit(mod.gpa);
828
829 const unwrapped_payload = try addZIRUnOp(mod, &not_err_scope.base, src, .unwrap_err_unsafe, err_union_ptr);
830 _ = try addZIRInst(mod, &not_err_scope.base, src, zir.Inst.Break, .{
831 .block = block,
832 .operand = unwrapped_payload,
833 }, .{});
834
835 condbr.positionals.then_body = .{ .instructions = try err_scope.arena.dupe(*zir.Inst, err_scope.instructions.items) };
836 condbr.positionals.else_body = .{ .instructions = try not_err_scope.arena.dupe(*zir.Inst, not_err_scope.instructions.items) };
837 return rlWrap(mod, scope, rl, &block.base);
838}
839
753/// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating.840/// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating.
754/// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used.841/// OK in theory it could do it without allocating. This implementation allocates when the @"" form is used.
755fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool {842fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool {
...@@ -794,9 +881,17 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix...@@ -794,9 +881,17 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix
794 const lhs = try expr(mod, scope, .ref, node.lhs);881 const lhs = try expr(mod, scope, .ref, node.lhs);
795 const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?);882 const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?);
796883
797 const pointer = try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{});884 return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{}));
798 if (rl == .ref) return pointer;885}
799 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, pointer));886
887fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ArrayAccess) InnerError!*zir.Inst {
888 const tree = scope.tree();
889 const src = tree.token_locs[node.rtoken].start;
890
891 const array_ptr = try expr(mod, scope, .ref, node.lhs);
892 const index = try expr(mod, scope, .none, node.index_expr);
893
894 return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{}));
800}895}
801896
802fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {897fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
...@@ -1080,6 +1175,12 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -1080,6 +1175,12 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
1080 }1175 }
1081 }1176 }
10821177
1178 if (while_node.label) |tok|
1179 return mod.failTok(scope, tok, "TODO labeled while", .{});
1180
1181 if (while_node.inline_token) |tok|
1182 return mod.failTok(scope, tok, "TODO inline while", .{});
1183
1083 var expr_scope: Scope.GenZIR = .{1184 var expr_scope: Scope.GenZIR = .{
1084 .parent = scope,1185 .parent = scope,
1085 .decl = scope.decl().?,1186 .decl = scope.decl().?,
...@@ -1198,6 +1299,181 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -1198,6 +1299,181 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
1198 return &while_block.base;1299 return &while_block.base;
1199}1300}
12001301
1302fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) InnerError!*zir.Inst {
1303 if (for_node.label) |tok|
1304 return mod.failTok(scope, tok, "TODO labeled for", .{});
1305
1306 if (for_node.inline_token) |tok|
1307 return mod.failTok(scope, tok, "TODO inline for", .{});
1308
1309 var for_scope: Scope.GenZIR = .{
1310 .parent = scope,
1311 .decl = scope.decl().?,
1312 .arena = scope.arena(),
1313 .instructions = .{},
1314 };
1315 defer for_scope.instructions.deinit(mod.gpa);
1316
1317 // setup variables and constants
1318 const tree = scope.tree();
1319 const for_src = tree.token_locs[for_node.for_token].start;
1320 const index_ptr = blk: {
1321 const usize_type = try addZIRInstConst(mod, &for_scope.base, for_src, .{
1322 .ty = Type.initTag(.type),
1323 .val = Value.initTag(.usize_type),
1324 });
1325 const index_ptr = try addZIRUnOp(mod, &for_scope.base, for_src, .alloc, usize_type);
1326 // initialize to zero
1327 const zero = try addZIRInstConst(mod, &for_scope.base, for_src, .{
1328 .ty = Type.initTag(.usize),
1329 .val = Value.initTag(.zero),
1330 });
1331 _ = try addZIRBinOp(mod, &for_scope.base, for_src, .store, index_ptr, zero);
1332 break :blk index_ptr;
1333 };
1334 const array_ptr = try expr(mod, &for_scope.base, .ref, for_node.array_expr);
1335 _ = try addZIRUnOp(mod, &for_scope.base, for_node.array_expr.firstToken(), .ensure_indexable, array_ptr);
1336 const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start;
1337 const len_ptr = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.FieldPtr, .{
1338 .object_ptr = array_ptr,
1339 .field_name = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.Str, .{ .bytes = "len" }, .{}),
1340 }, .{});
1341
1342 var loop_scope: Scope.GenZIR = .{
1343 .parent = &for_scope.base,
1344 .decl = for_scope.decl,
1345 .arena = for_scope.arena,
1346 .instructions = .{},
1347 };
1348 defer loop_scope.instructions.deinit(mod.gpa);
1349
1350 var cond_scope: Scope.GenZIR = .{
1351 .parent = &loop_scope.base,
1352 .decl = loop_scope.decl,
1353 .arena = loop_scope.arena,
1354 .instructions = .{},
1355 };
1356 defer cond_scope.instructions.deinit(mod.gpa);
1357
1358 // check condition i < array_expr.len
1359 const index = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, index_ptr);
1360 const len = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, len_ptr);
1361 const cond = try addZIRBinOp(mod, &cond_scope.base, cond_src, .cmp_lt, index, len);
1362
1363 const condbr = try addZIRInstSpecial(mod, &cond_scope.base, for_src, zir.Inst.CondBr, .{
1364 .condition = cond,
1365 .then_body = undefined, // populated below
1366 .else_body = undefined, // populated below
1367 }, .{});
1368 const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .{
1369 .instructions = try loop_scope.arena.dupe(*zir.Inst, cond_scope.instructions.items),
1370 });
1371
1372 // increment index variable
1373 const one = try addZIRInstConst(mod, &loop_scope.base, for_src, .{
1374 .ty = Type.initTag(.usize),
1375 .val = Value.initTag(.one),
1376 });
1377 const index_2 = try addZIRUnOp(mod, &loop_scope.base, cond_src, .deref, index_ptr);
1378 const index_plus_one = try addZIRBinOp(mod, &loop_scope.base, for_src, .add, index_2, one);
1379 _ = try addZIRBinOp(mod, &loop_scope.base, for_src, .store, index_ptr, index_plus_one);
1380
1381 // looping stuff
1382 const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{
1383 .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items),
1384 });
1385 const for_block = try addZIRInstBlock(mod, scope, for_src, .{
1386 .instructions = try for_scope.arena.dupe(*zir.Inst, for_scope.instructions.items),
1387 });
1388
1389 // while body
1390 const then_src = tree.token_locs[for_node.body.lastToken()].start;
1391 var then_scope: Scope.GenZIR = .{
1392 .parent = &cond_scope.base,
1393 .decl = cond_scope.decl,
1394 .arena = cond_scope.arena,
1395 .instructions = .{},
1396 };
1397 defer then_scope.instructions.deinit(mod.gpa);
1398
1399 // Most result location types can be forwarded directly; however
1400 // if we need to write to a pointer which has an inferred type,
1401 // proper type inference requires peer type resolution on the while's
1402 // branches.
1403 const branch_rl: ResultLoc = switch (rl) {
1404 .discard, .none, .ty, .ptr, .ref => rl,
1405 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block },
1406 };
1407
1408 var index_scope: Scope.LocalPtr = undefined;
1409 const then_sub_scope = blk: {
1410 const payload = for_node.payload.castTag(.PointerIndexPayload).?;
1411 const is_ptr = payload.ptr_token != null;
1412 const value_name = tree.tokenSlice(payload.value_symbol.firstToken());
1413 if (!mem.eql(u8, value_name, "_")) {
1414 return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement for value payload", .{});
1415 } else if (is_ptr) {
1416 return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{});
1417 }
1418
1419 const index_symbol_node = payload.index_symbol orelse
1420 break :blk &then_scope.base;
1421
1422 const index_name = tree.tokenSlice(index_symbol_node.firstToken());
1423 if (mem.eql(u8, index_name, "_")) {
1424 break :blk &then_scope.base;
1425 }
1426 // TODO make this const without an extra copy?
1427 index_scope = .{
1428 .parent = &then_scope.base,
1429 .gen_zir = &then_scope,
1430 .name = index_name,
1431 .ptr = index_ptr,
1432 };
1433 break :blk &index_scope.base;
1434 };
1435
1436 const then_result = try expr(mod, then_sub_scope, branch_rl, for_node.body);
1437 if (!then_result.tag.isNoReturn()) {
1438 _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{
1439 .block = cond_block,
1440 .operand = then_result,
1441 }, .{});
1442 }
1443 condbr.positionals.then_body = .{
1444 .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items),
1445 };
1446
1447 // else branch
1448 var else_scope: Scope.GenZIR = .{
1449 .parent = &cond_scope.base,
1450 .decl = cond_scope.decl,
1451 .arena = cond_scope.arena,
1452 .instructions = .{},
1453 };
1454 defer else_scope.instructions.deinit(mod.gpa);
1455
1456 if (for_node.@"else") |else_node| {
1457 const else_src = tree.token_locs[else_node.body.lastToken()].start;
1458 const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body);
1459 if (!else_result.tag.isNoReturn()) {
1460 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{
1461 .block = for_block,
1462 .operand = else_result,
1463 }, .{});
1464 }
1465 } else {
1466 const else_src = tree.token_locs[for_node.lastToken()].start;
1467 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.BreakVoid, .{
1468 .block = for_block,
1469 }, .{});
1470 }
1471 condbr.positionals.else_body = .{
1472 .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
1473 };
1474 return &for_block.base;
1475}
1476
1201fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst {1477fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst {
1202 const tree = scope.tree();1478 const tree = scope.tree();
1203 const src = tree.token_locs[cfe.ltoken].start;1479 const src = tree.token_locs[cfe.ltoken].start;
src-self-hosted/codegen.zig+28-4
...@@ -829,6 +829,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -829,6 +829,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
829 // No side effects, so if it's unreferenced, do nothing.829 // No side effects, so if it's unreferenced, do nothing.
830 if (inst.base.isUnused())830 if (inst.base.isUnused())
831 return MCValue.dead;831 return MCValue.dead;
832
833 const operand = try self.resolveInst(inst.operand);
834 const info_a = inst.operand.ty.intInfo(self.target.*);
835 const info_b = inst.base.ty.intInfo(self.target.*);
836 if (info_a.signed != info_b.signed)
837 return self.fail(inst.base.src, "TODO gen intcast sign safety in semantic analysis", .{});
838
839 if (info_a.bits == info_b.bits)
840 return operand;
841
832 switch (arch) {842 switch (arch) {
833 else => return self.fail(inst.base.src, "TODO implement intCast for {}", .{self.target.cpu.arch}),843 else => return self.fail(inst.base.src, "TODO implement intCast for {}", .{self.target.cpu.arch}),
834 }844 }
...@@ -2039,15 +2049,29 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2039,15 +2049,29 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2039 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), x);2049 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), x);
2040 },2050 },
2041 8 => {2051 8 => {
2042 return self.fail(src, "TODO implement set abi_size=8 stack variable with immediate", .{});2052 // We have a positive stack offset value but we want a twos complement negative
2053 // offset from rbp, which is at the top of the stack frame.
2054 const negative_offset = @intCast(i8, -@intCast(i32, adj_off));
2055 const twos_comp = @bitCast(u8, negative_offset);
2056
2057 // 64 bit write to memory would take two mov's anyways so we
2058 // insted just use two 32 bit writes to avoid register allocation
2059 try self.code.ensureCapacity(self.code.items.len + 14);
2060 var buf: [8]u8 = undefined;
2061 mem.writeIntLittle(u64, &buf, x_big);
2062
2063 // mov DWORD PTR [rbp+offset+4], immediate
2064 self.code.appendSliceAssumeCapacity(&[_]u8{ 0xc7, 0x45, twos_comp + 4});
2065 self.code.appendSliceAssumeCapacity(buf[4..8]);
2066
2067 // mov DWORD PTR [rbp+offset], immediate
2068 self.code.appendSliceAssumeCapacity(&[_]u8{ 0xc7, 0x45, twos_comp });
2069 self.code.appendSliceAssumeCapacity(buf[0..4]);
2043 },2070 },
2044 else => {2071 else => {
2045 return self.fail(src, "TODO implement set abi_size=large stack variable with immediate", .{});2072 return self.fail(src, "TODO implement set abi_size=large stack variable with immediate", .{});
2046 },2073 },
2047 }2074 }
2048 if (x_big <= math.maxInt(u32)) {} else {
2049 return self.fail(src, "TODO implement set stack variable with large immediate", .{});
2050 }
2051 },2075 },
2052 .embedded_in_code => |code_offset| {2076 .embedded_in_code => |code_offset| {
2053 return self.fail(src, "TODO implement set stack variable from embedded_in_code", .{});2077 return self.fail(src, "TODO implement set stack variable from embedded_in_code", .{});
src-self-hosted/type.zig+7
...@@ -2675,6 +2675,13 @@ pub const Type = extern union {...@@ -2675,6 +2675,13 @@ pub const Type = extern union {
2675 };2675 };
2676 }2676 }
26772677
2678 pub fn isIndexable(self: Type) bool {
2679 const zig_tag = self.zigTypeTag();
2680 // TODO tuples are indexable
2681 return zig_tag == .Array or zig_tag == .Vector or self.isSlice() or
2682 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
2683 }
2684
2678 /// This enum does not directly correspond to `std.builtin.TypeId` because2685 /// This enum does not directly correspond to `std.builtin.TypeId` because
2679 /// it has extra enum tags in it, as a way of using less memory. For example,2686 /// it has extra enum tags in it, as a way of using less memory. For example,
2680 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types2687 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
src-self-hosted/value.zig+29-7
...@@ -65,6 +65,7 @@ pub const Value = extern union {...@@ -65,6 +65,7 @@ pub const Value = extern union {
6565
66 undef,66 undef,
67 zero,67 zero,
68 one,
68 void_value,69 void_value,
69 unreachable_value,70 unreachable_value,
70 empty_array,71 empty_array,
...@@ -174,6 +175,7 @@ pub const Value = extern union {...@@ -174,6 +175,7 @@ pub const Value = extern union {
174 .anyframe_type,175 .anyframe_type,
175 .undef,176 .undef,
176 .zero,177 .zero,
178 .one,
177 .void_value,179 .void_value,
178 .unreachable_value,180 .unreachable_value,
179 .empty_array,181 .empty_array,
...@@ -313,6 +315,7 @@ pub const Value = extern union {...@@ -313,6 +315,7 @@ pub const Value = extern union {
313 .null_value => return out_stream.writeAll("null"),315 .null_value => return out_stream.writeAll("null"),
314 .undef => return out_stream.writeAll("undefined"),316 .undef => return out_stream.writeAll("undefined"),
315 .zero => return out_stream.writeAll("0"),317 .zero => return out_stream.writeAll("0"),
318 .one => return out_stream.writeAll("1"),
316 .void_value => return out_stream.writeAll("{}"),319 .void_value => return out_stream.writeAll("{}"),
317 .unreachable_value => return out_stream.writeAll("unreachable"),320 .unreachable_value => return out_stream.writeAll("unreachable"),
318 .bool_true => return out_stream.writeAll("true"),321 .bool_true => return out_stream.writeAll("true"),
...@@ -447,6 +450,7 @@ pub const Value = extern union {...@@ -447,6 +450,7 @@ pub const Value = extern union {
447450
448 .undef,451 .undef,
449 .zero,452 .zero,
453 .one,
450 .void_value,454 .void_value,
451 .unreachable_value,455 .unreachable_value,
452 .empty_array,456 .empty_array,
...@@ -546,7 +550,9 @@ pub const Value = extern union {...@@ -546,7 +550,9 @@ pub const Value = extern union {
546 .bool_false,550 .bool_false,
547 => return BigIntMutable.init(&space.limbs, 0).toConst(),551 => return BigIntMutable.init(&space.limbs, 0).toConst(),
548552
549 .bool_true => return BigIntMutable.init(&space.limbs, 1).toConst(),553 .one,
554 .bool_true,
555 => return BigIntMutable.init(&space.limbs, 1).toConst(),
550556
551 .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(),557 .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(),
552 .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(),558 .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(),
...@@ -627,7 +633,9 @@ pub const Value = extern union {...@@ -627,7 +633,9 @@ pub const Value = extern union {
627 .bool_false,633 .bool_false,
628 => return 0,634 => return 0,
629635
630 .bool_true => return 1,636 .one,
637 .bool_true,
638 => return 1,
631639
632 .int_u64 => return self.cast(Payload.Int_u64).?.int,640 .int_u64 => return self.cast(Payload.Int_u64).?.int,
633 .int_i64 => return @intCast(u64, self.cast(Payload.Int_i64).?.int),641 .int_i64 => return @intCast(u64, self.cast(Payload.Int_i64).?.int),
...@@ -708,7 +716,9 @@ pub const Value = extern union {...@@ -708,7 +716,9 @@ pub const Value = extern union {
708 .bool_false,716 .bool_false,
709 => return 0,717 => return 0,
710718
711 .bool_true => return 1,719 .one,
720 .bool_true,
721 => return 1,
712722
713 .int_u64 => return @intCast(i64, self.cast(Payload.Int_u64).?.int),723 .int_u64 => return @intCast(i64, self.cast(Payload.Int_u64).?.int),
714 .int_i64 => return self.cast(Payload.Int_i64).?.int,724 .int_i64 => return self.cast(Payload.Int_i64).?.int,
...@@ -734,6 +744,7 @@ pub const Value = extern union {...@@ -734,6 +744,7 @@ pub const Value = extern union {
734 .float_128 => @floatCast(T, self.cast(Payload.Float_128).?.val),744 .float_128 => @floatCast(T, self.cast(Payload.Float_128).?.val),
735745
736 .zero => 0,746 .zero => 0,
747 .one => 1,
737 .int_u64 => @intToFloat(T, self.cast(Payload.Int_u64).?.int),748 .int_u64 => @intToFloat(T, self.cast(Payload.Int_u64).?.int),
738 .int_i64 => @intToFloat(T, self.cast(Payload.Int_i64).?.int),749 .int_i64 => @intToFloat(T, self.cast(Payload.Int_i64).?.int),
739750
...@@ -814,7 +825,9 @@ pub const Value = extern union {...@@ -814,7 +825,9 @@ pub const Value = extern union {
814 .bool_false,825 .bool_false,
815 => return 0,826 => return 0,
816827
817 .bool_true => return 1,828 .one,
829 .bool_true,
830 => return 1,
818831
819 .int_u64 => {832 .int_u64 => {
820 const x = self.cast(Payload.Int_u64).?.int;833 const x = self.cast(Payload.Int_u64).?.int;
...@@ -900,7 +913,9 @@ pub const Value = extern union {...@@ -900,7 +913,9 @@ pub const Value = extern union {
900 .bool_false,913 .bool_false,
901 => return true,914 => return true,
902915
903 .bool_true => {916 .one,
917 .bool_true,
918 => {
904 const info = ty.intInfo(target);919 const info = ty.intInfo(target);
905 if (info.signed) {920 if (info.signed) {
906 return info.bits >= 2;921 return info.bits >= 2;
...@@ -1064,7 +1079,9 @@ pub const Value = extern union {...@@ -1064,7 +1079,9 @@ pub const Value = extern union {
1064 .@"error",1079 .@"error",
1065 => unreachable,1080 => unreachable,
10661081
1067 .zero => false,1082 .zero,
1083 .one,
1084 => false,
10681085
1069 .float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0,1086 .float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0,
1070 .float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0,1087 .float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0,
...@@ -1140,7 +1157,9 @@ pub const Value = extern union {...@@ -1140,7 +1157,9 @@ pub const Value = extern union {
1140 .bool_false,1157 .bool_false,
1141 => .eq,1158 => .eq,
11421159
1143 .bool_true => .gt,1160 .one,
1161 .bool_true,
1162 => .gt,
11441163
1145 .int_u64 => std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),1164 .int_u64 => std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),
1146 .int_i64 => std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),1165 .int_i64 => std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),
...@@ -1257,6 +1276,7 @@ pub const Value = extern union {...@@ -1257,6 +1276,7 @@ pub const Value = extern union {
1257 .enum_literal_type,1276 .enum_literal_type,
1258 .anyframe_type,1277 .anyframe_type,
1259 .zero,1278 .zero,
1279 .one,
1260 .bool_true,1280 .bool_true,
1261 .bool_false,1281 .bool_false,
1262 .null_value,1282 .null_value,
...@@ -1339,6 +1359,7 @@ pub const Value = extern union {...@@ -1339,6 +1359,7 @@ pub const Value = extern union {
1339 .enum_literal_type,1359 .enum_literal_type,
1340 .anyframe_type,1360 .anyframe_type,
1341 .zero,1361 .zero,
1362 .one,
1342 .bool_true,1363 .bool_true,
1343 .bool_false,1364 .bool_false,
1344 .null_value,1365 .null_value,
...@@ -1438,6 +1459,7 @@ pub const Value = extern union {...@@ -1438,6 +1459,7 @@ pub const Value = extern union {
1438 .enum_literal_type,1459 .enum_literal_type,
1439 .anyframe_type,1460 .anyframe_type,
1440 .zero,1461 .zero,
1462 .one,
1441 .empty_array,1463 .empty_array,
1442 .bool_true,1464 .bool_true,
1443 .bool_false,1465 .bool_false,
src-self-hosted/zir.zig+8
...@@ -137,6 +137,8 @@ pub const Inst = struct {...@@ -137,6 +137,8 @@ pub const Inst = struct {
137 ensure_result_used,137 ensure_result_used,
138 /// Emits a compile error if an error is ignored.138 /// Emits a compile error if an error is ignored.
139 ensure_result_non_error,139 ensure_result_non_error,
140 /// Emits a compile error if operand cannot be indexed.
141 ensure_indexable,
140 /// Create a `E!T` type.142 /// Create a `E!T` type.
141 error_union_type,143 error_union_type,
142 /// Create an error set.144 /// Create an error set.
...@@ -251,6 +253,8 @@ pub const Inst = struct {...@@ -251,6 +253,8 @@ pub const Inst = struct {
251 unwrap_err_safe,253 unwrap_err_safe,
252 /// Same as previous, but without safety checks. Used for orelse, if and while254 /// Same as previous, but without safety checks. Used for orelse, if and while
253 unwrap_err_unsafe,255 unwrap_err_unsafe,
256 /// Gets the error code value of an error union
257 unwrap_err_code,
254 /// Takes a *E!T and raises a compiler error if T != void258 /// Takes a *E!T and raises a compiler error if T != void
255 ensure_err_payload_void,259 ensure_err_payload_void,
256 /// Enum literal260 /// Enum literal
...@@ -278,6 +282,7 @@ pub const Inst = struct {...@@ -278,6 +282,7 @@ pub const Inst = struct {
278 .alloc,282 .alloc,
279 .ensure_result_used,283 .ensure_result_used,
280 .ensure_result_non_error,284 .ensure_result_non_error,
285 .ensure_indexable,
281 .bitcast_result_ptr,286 .bitcast_result_ptr,
282 .ref,287 .ref,
283 .bitcast_ref,288 .bitcast_ref,
...@@ -295,6 +300,7 @@ pub const Inst = struct {...@@ -295,6 +300,7 @@ pub const Inst = struct {
295 .unwrap_optional_unsafe,300 .unwrap_optional_unsafe,
296 .unwrap_err_safe,301 .unwrap_err_safe,
297 .unwrap_err_unsafe,302 .unwrap_err_unsafe,
303 .unwrap_err_code,
298 .ensure_err_payload_void,304 .ensure_err_payload_void,
299 .anyframe_type,305 .anyframe_type,
300 .bitnot,306 .bitnot,
...@@ -409,6 +415,7 @@ pub const Inst = struct {...@@ -409,6 +415,7 @@ pub const Inst = struct {
409 .elemptr,415 .elemptr,
410 .ensure_result_used,416 .ensure_result_used,
411 .ensure_result_non_error,417 .ensure_result_non_error,
418 .ensure_indexable,
412 .@"export",419 .@"export",
413 .floatcast,420 .floatcast,
414 .fieldptr,421 .fieldptr,
...@@ -450,6 +457,7 @@ pub const Inst = struct {...@@ -450,6 +457,7 @@ pub const Inst = struct {
450 .unwrap_optional_unsafe,457 .unwrap_optional_unsafe,
451 .unwrap_err_safe,458 .unwrap_err_safe,
452 .unwrap_err_unsafe,459 .unwrap_err_unsafe,
460 .unwrap_err_code,
453 .ptr_type,461 .ptr_type,
454 .ensure_err_payload_void,462 .ensure_err_payload_void,
455 .enum_literal,463 .enum_literal,
src-self-hosted/zir_sema.zig+43-21
...@@ -48,6 +48,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -48,6 +48,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
48 .declval_in_module => return analyzeInstDeclValInModule(mod, scope, old_inst.castTag(.declval_in_module).?),48 .declval_in_module => return analyzeInstDeclValInModule(mod, scope, old_inst.castTag(.declval_in_module).?),
49 .ensure_result_used => return analyzeInstEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?),49 .ensure_result_used => return analyzeInstEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?),
50 .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?),50 .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?),
51 .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?),
51 .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),52 .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),
52 .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),53 .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),
53 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),54 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),
...@@ -111,7 +112,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -111,7 +112,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
111 .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?),112 .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?),
112 .isnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnull).?, true),113 .isnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnull).?, true),
113 .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false),114 .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false),
114 .iserr => return analyzeInstIsErr(mod, scope, old_inst.castTag(.iserr).?, true),115 .iserr => return analyzeInstIsErr(mod, scope, old_inst.castTag(.iserr).?),
115 .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),116 .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),
116 .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),117 .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),
117 .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?),118 .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?),
...@@ -119,6 +120,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -119,6 +120,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
119 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),120 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),
120 .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),121 .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),
121 .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false),122 .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false),
123 .unwrap_err_code => return analyzeInstUnwrapErrCode(mod, scope, old_inst.castTag(.unwrap_err_code).?),
122 .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?),124 .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?),
123 .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?),125 .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?),
124 .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?),126 .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?),
...@@ -382,6 +384,19 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst....@@ -382,6 +384,19 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
382 }384 }
383}385}
384386
387fn analyzeInstEnsureIndexable(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
388 const operand = try resolveInst(mod, scope, inst.positionals.operand);
389 const elem_ty = operand.ty.elemType();
390 if (elem_ty.isIndexable()) {
391 return mod.constVoid(scope, operand.src);
392 } else {
393 // TODO error notes
394 // error: type '{}' does not support indexing
395 // note: for loop operand must be an array, a slice or a tuple
396 return mod.fail(scope, operand.src, "for loop operand must be an array, a slice or a tuple", .{});
397 }
398}
399
385fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {400fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
386 const var_type = try resolveType(mod, scope, inst.positionals.operand);401 const var_type = try resolveType(mod, scope, inst.positionals.operand);
387 // TODO this should happen only for var allocs402 // TODO this should happen only for var allocs
...@@ -786,11 +801,12 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp...@@ -786,11 +801,12 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
786 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);801 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
787 assert(operand.ty.zigTypeTag() == .Pointer);802 assert(operand.ty.zigTypeTag() == .Pointer);
788803
789 if (operand.ty.elemType().zigTypeTag() != .Optional) {804 const elem_type = operand.ty.elemType();
790 return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{operand.ty.elemType()});805 if (elem_type.zigTypeTag() != .Optional) {
806 return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{elem_type});
791 }807 }
792808
793 const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena());809 const child_type = try elem_type.optionalChildAlloc(scope.arena());
794 const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One);810 const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One);
795811
796 if (operand.value()) |val| {812 if (operand.value()) |val| {
...@@ -815,6 +831,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf...@@ -815,6 +831,10 @@ fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, saf
815 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});831 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});
816}832}
817833
834fn analyzeInstUnwrapErrCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
835 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErrCode", .{});
836}
837
818fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {838fn analyzeInstEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
819 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstEnsureErrPayloadVoid", .{});839 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstEnsureErrPayloadVoid", .{});
820}840}
...@@ -950,7 +970,8 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr...@@ -950,7 +970,8 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
950 const entry = if (val.cast(Value.Payload.ErrorSet)) |payload|970 const entry = if (val.cast(Value.Payload.ErrorSet)) |payload|
951 (payload.fields.getEntry(field_name) orelse971 (payload.fields.getEntry(field_name) orelse
952 return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).*972 return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).*
953 else try mod.getErrorValue(field_name);973 else
974 try mod.getErrorValue(field_name);
954975
955 const error_payload = try scope.arena().create(Value.Payload.Error);976 const error_payload = try scope.arena().create(Value.Payload.Error);
956 error_payload.* = .{977 error_payload.* = .{
...@@ -1062,9 +1083,19 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne...@@ -1062,9 +1083,19 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
1062 const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr);1083 const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr);
1063 const uncasted_index = try resolveInst(mod, scope, inst.positionals.index);1084 const uncasted_index = try resolveInst(mod, scope, inst.positionals.index);
1064 const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index);1085 const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index);
1086
1087 const elem_ty = switch (array_ptr.ty.zigTypeTag()) {
1088 .Pointer => array_ptr.ty.elemType(),
1089 else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
1090 };
1091 if (!elem_ty.isIndexable()) {
1092 return mod.fail(scope, inst.base.src, "array access of non-array type '{}'", .{elem_ty});
1093 }
10651094
1066 if (array_ptr.ty.isSinglePointer() and array_ptr.ty.elemType().zigTypeTag() == .Array) {1095 if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
1067 if (array_ptr.value()) |array_ptr_val| {1096 // we have to deref the ptr operand to get the actual array pointer
1097 const array_ptr_deref = try mod.analyzeDeref(scope, inst.base.src, array_ptr, inst.positionals.array_ptr.src);
1098 if (array_ptr_deref.value()) |array_ptr_val| {
1068 if (elem_index.value()) |index_val| {1099 if (elem_index.value()) |index_val| {
1069 // Both array pointer and index are compile-time known.1100 // Both array pointer and index are compile-time known.
1070 const index_u64 = index_val.toUnsignedInt();1101 const index_u64 = index_val.toUnsignedInt();
...@@ -1075,7 +1106,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne...@@ -1075,7 +1106,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
1075 const type_payload = try scope.arena().create(Type.Payload.PointerSimple);1106 const type_payload = try scope.arena().create(Type.Payload.PointerSimple);
1076 type_payload.* = .{1107 type_payload.* = .{
1077 .base = .{ .tag = .single_const_pointer },1108 .base = .{ .tag = .single_const_pointer },
1078 .pointee_type = array_ptr.ty.elemType().elemType(),1109 .pointee_type = elem_ty.elemType().elemType(),
1079 };1110 };
10801111
1081 return mod.constInst(scope, inst.base.src, .{1112 return mod.constInst(scope, inst.base.src, .{
...@@ -1274,17 +1305,7 @@ fn analyzeInstCmp(...@@ -1274,17 +1305,7 @@ fn analyzeInstCmp(
1274 {1305 {
1275 // comparing null with optionals1306 // comparing null with optionals
1276 const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;1307 const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;
1277 if (opt_operand.value()) |opt_val| {1308 return mod.analyzeIsNull(scope, inst.base.src, opt_operand, op == .neq);
1278 const is_null = opt_val.isNull();
1279 return mod.constBool(scope, inst.base.src, if (op == .eq) is_null else !is_null);
1280 }
1281 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
1282 const inst_tag: Inst.Tag = switch (op) {
1283 .eq => .isnull,
1284 .neq => .isnonnull,
1285 else => unreachable,
1286 };
1287 return mod.addUnOp(b, inst.base.src, Type.initTag(.bool), inst_tag, opt_operand);
1288 } else if (is_equality_cmp and1309 } else if (is_equality_cmp and
1289 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))1310 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
1290 {1311 {
...@@ -1332,8 +1353,9 @@ fn analyzeInstIsNonNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, inver...@@ -1332,8 +1353,9 @@ fn analyzeInstIsNonNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, inver
1332 return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);1353 return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);
1333}1354}
13341355
1335fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst {1356fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1336 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstIsErr", .{});1357 const operand = try resolveInst(mod, scope, inst.positionals.operand);
1358 return mod.analyzeIsErr(scope, inst.base.src, operand);
1337}1359}
13381360
1339fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst {1361fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst {
test/stage2/test.zig+84
...@@ -820,6 +820,90 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -820,6 +820,90 @@ pub fn addCases(ctx: *TestContext) !void {
820 ,820 ,
821 "",821 "",
822 );822 );
823
824 // Array access.
825 case.addCompareOutput(
826 \\export fn _start() noreturn {
827 \\ assert("hello"[0] == 'h');
828 \\
829 \\ exit();
830 \\}
831 \\
832 \\pub fn assert(ok: bool) void {
833 \\ if (!ok) unreachable; // assertion failure
834 \\}
835 \\
836 \\fn exit() noreturn {
837 \\ asm volatile ("syscall"
838 \\ :
839 \\ : [number] "{rax}" (231),
840 \\ [arg1] "{rdi}" (0)
841 \\ : "rcx", "r11", "memory"
842 \\ );
843 \\ unreachable;
844 \\}
845 ,
846 "",
847 );
848
849 // 64bit set stack
850 case.addCompareOutput(
851 \\export fn _start() noreturn {
852 \\ var i: u64 = 0xFFEEDDCCBBAA9988;
853 \\ assert(i == 0xFFEEDDCCBBAA9988);
854 \\
855 \\ exit();
856 \\}
857 \\
858 \\pub fn assert(ok: bool) void {
859 \\ if (!ok) unreachable; // assertion failure
860 \\}
861 \\
862 \\fn exit() noreturn {
863 \\ asm volatile ("syscall"
864 \\ :
865 \\ : [number] "{rax}" (231),
866 \\ [arg1] "{rdi}" (0)
867 \\ : "rcx", "r11", "memory"
868 \\ );
869 \\ unreachable;
870 \\}
871 ,
872 "",
873 );
874
875 // Basic for loop
876 case.addCompareOutput(
877 \\export fn _start() noreturn {
878 \\ for ("hello") |_| print();
879 \\
880 \\ exit();
881 \\}
882 \\
883 \\fn print() void {
884 \\ asm volatile ("syscall"
885 \\ :
886 \\ : [number] "{rax}" (1),
887 \\ [arg1] "{rdi}" (1),
888 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
889 \\ [arg3] "{rdx}" (6)
890 \\ : "rcx", "r11", "memory"
891 \\ );
892 \\ return;
893 \\}
894 \\
895 \\fn exit() noreturn {
896 \\ asm volatile ("syscall"
897 \\ :
898 \\ : [number] "{rax}" (231),
899 \\ [arg1] "{rdi}" (0)
900 \\ : "rcx", "r11", "memory"
901 \\ );
902 \\ unreachable;
903 \\}
904 ,
905 "hello\nhello\nhello\nhello\nhello\n",
906 );
823 }907 }
824908
825 {909 {
test/stage2/zir.zig+5-4
...@@ -43,10 +43,11 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -43,10 +43,11 @@ pub fn addCases(ctx: *TestContext) !void {
43 \\43 \\
44 \\@entry = fn(@fnty, {44 \\@entry = fn(@fnty, {
45 \\ %a = str("\x32\x08\x01\x0a")45 \\ %a = str("\x32\x08\x01\x0a")
46 \\ %eptr0 = elemptr(%a, @0)46 \\ %a_ref = ref(%a)
47 \\ %eptr1 = elemptr(%a, @1)47 \\ %eptr0 = elemptr(%a_ref, @0)
48 \\ %eptr2 = elemptr(%a, @2)48 \\ %eptr1 = elemptr(%a_ref, @1)
49 \\ %eptr3 = elemptr(%a, @3)49 \\ %eptr2 = elemptr(%a_ref, @2)
50 \\ %eptr3 = elemptr(%a_ref, @3)
50 \\ %v0 = deref(%eptr0)51 \\ %v0 = deref(%eptr0)
51 \\ %v1 = deref(%eptr1)52 \\ %v1 = deref(%eptr1)
52 \\ %v2 = deref(%eptr2)53 \\ %v2 = deref(%eptr2)