authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-27 17:09:47-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-27 17:09:47-07:00
log488df7f1d1f7300bfb23134cc79fed2cef917ae2
tree667e88750a5dfd1c5b6591769f50d19a3a754ddc
parentbd9b3fe1e63539edbacacb0871470b5da4f10012

stage2: astgen for all arithmetic and assignments


3 files changed, 332 insertions(+), 100 deletions(-)

src-self-hosted/Module.zig+62-2
...@@ -2357,6 +2357,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -2357,6 +2357,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
2357 .alloc => return self.analyzeInstAlloc(scope, old_inst.castTag(.alloc).?),2357 .alloc => return self.analyzeInstAlloc(scope, old_inst.castTag(.alloc).?),
2358 .alloc_inferred => return self.analyzeInstAllocInferred(scope, old_inst.castTag(.alloc_inferred).?),2358 .alloc_inferred => return self.analyzeInstAllocInferred(scope, old_inst.castTag(.alloc_inferred).?),
2359 .arg => return self.analyzeInstArg(scope, old_inst.castTag(.arg).?),2359 .arg => return self.analyzeInstArg(scope, old_inst.castTag(.arg).?),
2360 .bitcast_lvalue => return self.analyzeInstBitCastLValue(scope, old_inst.castTag(.bitcast_lvalue).?),
2360 .bitcast_result_ptr => return self.analyzeInstBitCastResultPtr(scope, old_inst.castTag(.bitcast_result_ptr).?),2361 .bitcast_result_ptr => return self.analyzeInstBitCastResultPtr(scope, old_inst.castTag(.bitcast_result_ptr).?),
2361 .block => return self.analyzeInstBlock(scope, old_inst.castTag(.block).?),2362 .block => return self.analyzeInstBlock(scope, old_inst.castTag(.block).?),
2362 .@"break" => return self.analyzeInstBreak(scope, old_inst.castTag(.@"break").?),2363 .@"break" => return self.analyzeInstBreak(scope, old_inst.castTag(.@"break").?),
...@@ -2374,6 +2375,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -2374,6 +2375,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
2374 .declval_in_module => return self.analyzeInstDeclValInModule(scope, old_inst.castTag(.declval_in_module).?),2375 .declval_in_module => return self.analyzeInstDeclValInModule(scope, old_inst.castTag(.declval_in_module).?),
2375 .ensure_result_used => return self.analyzeInstEnsureResultUsed(scope, old_inst.castTag(.ensure_result_used).?),2376 .ensure_result_used => return self.analyzeInstEnsureResultUsed(scope, old_inst.castTag(.ensure_result_used).?),
2376 .ensure_result_non_error => return self.analyzeInstEnsureResultNonError(scope, old_inst.castTag(.ensure_result_non_error).?),2377 .ensure_result_non_error => return self.analyzeInstEnsureResultNonError(scope, old_inst.castTag(.ensure_result_non_error).?),
2378 .ref => return self.analyzeInstRef(scope, old_inst.castTag(.ref).?),
2377 .ret_ptr => return self.analyzeInstRetPtr(scope, old_inst.castTag(.ret_ptr).?),2379 .ret_ptr => return self.analyzeInstRetPtr(scope, old_inst.castTag(.ret_ptr).?),
2378 .ret_type => return self.analyzeInstRetType(scope, old_inst.castTag(.ret_type).?),2380 .ret_type => return self.analyzeInstRetType(scope, old_inst.castTag(.ret_type).?),
2379 .store => return self.analyzeInstStore(scope, old_inst.castTag(.store).?),2381 .store => return self.analyzeInstStore(scope, old_inst.castTag(.store).?),
...@@ -2390,6 +2392,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -2390,6 +2392,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
2390 .as => return self.analyzeInstAs(scope, old_inst.castTag(.as).?),2392 .as => return self.analyzeInstAs(scope, old_inst.castTag(.as).?),
2391 .@"asm" => return self.analyzeInstAsm(scope, old_inst.castTag(.@"asm").?),2393 .@"asm" => return self.analyzeInstAsm(scope, old_inst.castTag(.@"asm").?),
2392 .@"unreachable" => return self.analyzeInstUnreachable(scope, old_inst.castTag(.@"unreachable").?),2394 .@"unreachable" => return self.analyzeInstUnreachable(scope, old_inst.castTag(.@"unreachable").?),
2395 .unreach_nocheck => return self.analyzeInstUnreachNoChk(scope, old_inst.castTag(.unreach_nocheck).?),
2393 .@"return" => return self.analyzeInstRet(scope, old_inst.castTag(.@"return").?),2396 .@"return" => return self.analyzeInstRet(scope, old_inst.castTag(.@"return").?),
2394 .returnvoid => return self.analyzeInstRetVoid(scope, old_inst.castTag(.returnvoid).?),2397 .returnvoid => return self.analyzeInstRetVoid(scope, old_inst.castTag(.returnvoid).?),
2395 .@"fn" => return self.analyzeInstFn(scope, old_inst.castTag(.@"fn").?),2398 .@"fn" => return self.analyzeInstFn(scope, old_inst.castTag(.@"fn").?),
...@@ -2400,7 +2403,21 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -2400,7 +2403,21 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
2400 .bitcast => return self.analyzeInstBitCast(scope, old_inst.castTag(.bitcast).?),2403 .bitcast => return self.analyzeInstBitCast(scope, old_inst.castTag(.bitcast).?),
2401 .floatcast => return self.analyzeInstFloatCast(scope, old_inst.castTag(.floatcast).?),2404 .floatcast => return self.analyzeInstFloatCast(scope, old_inst.castTag(.floatcast).?),
2402 .elemptr => return self.analyzeInstElemPtr(scope, old_inst.castTag(.elemptr).?),2405 .elemptr => return self.analyzeInstElemPtr(scope, old_inst.castTag(.elemptr).?),
2403 .add, .sub => return self.analyzeInstArithmetic(scope, old_inst.cast(zir.Inst.BinOp).?),2406 .add => return self.analyzeInstArithmetic(scope, old_inst.castTag(.add).?),
2407 .addwrap => return self.analyzeInstArithmetic(scope, old_inst.castTag(.addwrap).?),
2408 .sub => return self.analyzeInstArithmetic(scope, old_inst.castTag(.sub).?),
2409 .subwrap => return self.analyzeInstArithmetic(scope, old_inst.castTag(.subwrap).?),
2410 .mul => return self.analyzeInstArithmetic(scope, old_inst.castTag(.mul).?),
2411 .mulwrap => return self.analyzeInstArithmetic(scope, old_inst.castTag(.mulwrap).?),
2412 .div => return self.analyzeInstArithmetic(scope, old_inst.castTag(.div).?),
2413 .mod_rem => return self.analyzeInstArithmetic(scope, old_inst.castTag(.mod_rem).?),
2414 .array_cat => return self.analyzeInstArrayCat(scope, old_inst.castTag(.array_cat).?),
2415 .array_mul => return self.analyzeInstArrayMul(scope, old_inst.castTag(.array_mul).?),
2416 .bitand => return self.analyzeInstBitwise(scope, old_inst.castTag(.bitand).?),
2417 .bitor => return self.analyzeInstBitwise(scope, old_inst.castTag(.bitor).?),
2418 .xor => return self.analyzeInstBitwise(scope, old_inst.castTag(.xor).?),
2419 .shl => return self.analyzeInstShl(scope, old_inst.castTag(.shl).?),
2420 .shr => return self.analyzeInstShr(scope, old_inst.castTag(.shr).?),
2404 .cmp_lt => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_lt).?, .lt),2421 .cmp_lt => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_lt).?, .lt),
2405 .cmp_lte => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_lte).?, .lte),2422 .cmp_lte => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_lte).?, .lte),
2406 .cmp_eq => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_eq).?, .eq),2423 .cmp_eq => return self.analyzeInstCmp(scope, old_inst.castTag(.cmp_eq).?, .eq),
...@@ -2411,6 +2428,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -2411,6 +2428,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
2411 .isnull => return self.analyzeInstIsNonNull(scope, old_inst.castTag(.isnull).?, true),2428 .isnull => return self.analyzeInstIsNonNull(scope, old_inst.castTag(.isnull).?, true),
2412 .isnonnull => return self.analyzeInstIsNonNull(scope, old_inst.castTag(.isnonnull).?, false),2429 .isnonnull => return self.analyzeInstIsNonNull(scope, old_inst.castTag(.isnonnull).?, false),
2413 .boolnot => return self.analyzeInstBoolNot(scope, old_inst.castTag(.boolnot).?),2430 .boolnot => return self.analyzeInstBoolNot(scope, old_inst.castTag(.boolnot).?),
2431 .typeof => return self.analyzeInstTypeOf(scope, old_inst.castTag(.typeof).?),
2414 }2432 }
2415}2433}
24162434
...@@ -2422,6 +2440,10 @@ fn analyzeInstCoerceResultBlockPtr(...@@ -2422,6 +2440,10 @@ fn analyzeInstCoerceResultBlockPtr(
2422 return self.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});2440 return self.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});
2423}2441}
24242442
2443fn analyzeInstBitCastLValue(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2444 return self.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastLValue", .{});
2445}
2446
2425fn analyzeInstBitCastResultPtr(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {2447fn analyzeInstBitCastResultPtr(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2426 return self.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastResultPtr", .{});2448 return self.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastResultPtr", .{});
2427}2449}
...@@ -2438,6 +2460,10 @@ fn analyzeInstRetPtr(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerEr...@@ -2438,6 +2460,10 @@ fn analyzeInstRetPtr(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerEr
2438 return self.fail(scope, inst.base.src, "TODO implement analyzeInstRetPtr", .{});2460 return self.fail(scope, inst.base.src, "TODO implement analyzeInstRetPtr", .{});
2439}2461}
24402462
2463fn analyzeInstRef(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2464 return self.fail(scope, inst.base.src, "TODO implement analyzeInstRef", .{});
2465}
2466
2441fn analyzeInstRetType(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {2467fn analyzeInstRetType(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
2442 const b = try self.requireRuntimeBlock(scope, inst.base.src);2468 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2443 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;2469 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
...@@ -3044,6 +3070,26 @@ fn floatOpAllowed(tag: zir.Inst.Tag) bool {...@@ -3044,6 +3070,26 @@ fn floatOpAllowed(tag: zir.Inst.Tag) bool {
3044 };3070 };
3045}3071}
30463072
3073fn analyzeInstShl(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
3074 return self.fail(scope, inst.base.src, "TODO implement analyzeInstShl", .{});
3075}
3076
3077fn analyzeInstShr(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
3078 return self.fail(scope, inst.base.src, "TODO implement analyzeInstShr", .{});
3079}
3080
3081fn analyzeInstBitwise(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
3082 return self.fail(scope, inst.base.src, "TODO implement analyzeInstBitwise", .{});
3083}
3084
3085fn analyzeInstArrayCat(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
3086 return self.fail(scope, inst.base.src, "TODO implement analyzeInstArrayCat", .{});
3087}
3088
3089fn analyzeInstArrayMul(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
3090 return self.fail(scope, inst.base.src, "TODO implement analyzeInstArrayMul", .{});
3091}
3092
3047fn analyzeInstArithmetic(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {3093fn analyzeInstArithmetic(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
3048 const tracy = trace(@src());3094 const tracy = trace(@src());
3049 defer tracy.end();3095 defer tracy.end();
...@@ -3257,6 +3303,11 @@ fn analyzeInstCmp(...@@ -3257,6 +3303,11 @@ fn analyzeInstCmp(
3257 return self.fail(scope, inst.base.src, "TODO implement more cmp analysis", .{});3303 return self.fail(scope, inst.base.src, "TODO implement more cmp analysis", .{});
3258}3304}
32593305
3306fn analyzeInstTypeOf(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
3307 const operand = try self.resolveInst(scope, inst.positionals.operand);
3308 return self.constType(scope, inst.base.src, operand.ty);
3309}
3310
3260fn analyzeInstBoolNot(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {3311fn analyzeInstBoolNot(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
3261 const uncasted_operand = try self.resolveInst(scope, inst.positionals.operand);3312 const uncasted_operand = try self.resolveInst(scope, inst.positionals.operand);
3262 const bool_type = Type.initTag(.bool);3313 const bool_type = Type.initTag(.bool);
...@@ -3319,13 +3370,22 @@ fn wantSafety(self: *Module, scope: *Scope) bool {...@@ -3319,13 +3370,22 @@ fn wantSafety(self: *Module, scope: *Scope) bool {
3319 };3370 };
3320}3371}
33213372
3373fn analyzeUnreach(self: *Module, scope: *Scope, src: usize) InnerError!*Inst {
3374 const b = try self.requireRuntimeBlock(scope, src);
3375 return self.addNoOp(b, src, Type.initTag(.noreturn), .unreach);
3376}
3377
3378fn analyzeInstUnreachNoChk(self: *Module, scope: *Scope, unreach: *zir.Inst.NoOp) InnerError!*Inst {
3379 return self.analyzeUnreach(scope, unreach.base.src);
3380}
3381
3322fn analyzeInstUnreachable(self: *Module, scope: *Scope, unreach: *zir.Inst.NoOp) InnerError!*Inst {3382fn analyzeInstUnreachable(self: *Module, scope: *Scope, unreach: *zir.Inst.NoOp) InnerError!*Inst {
3323 const b = try self.requireRuntimeBlock(scope, unreach.base.src);3383 const b = try self.requireRuntimeBlock(scope, unreach.base.src);
3324 if (self.wantSafety(scope)) {3384 if (self.wantSafety(scope)) {
3325 // TODO Once we have a panic function to call, call it here instead of this.3385 // TODO Once we have a panic function to call, call it here instead of this.
3326 _ = try self.addNoOp(b, unreach.base.src, Type.initTag(.void), .breakpoint);3386 _ = try self.addNoOp(b, unreach.base.src, Type.initTag(.void), .breakpoint);
3327 }3387 }
3328 return self.addNoOp(b, unreach.base.src, Type.initTag(.noreturn), .unreach);3388 return self.analyzeUnreach(scope, unreach.base.src);
3329}3389}
33303390
3331fn analyzeInstRet(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {3391fn analyzeInstRet(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
src-self-hosted/astgen.zig+92-35
...@@ -17,6 +17,9 @@ pub const ResultLoc = union(enum) {...@@ -17,6 +17,9 @@ pub const ResultLoc = union(enum) {
17 discard,17 discard,
18 /// The expression has an inferred type, and it will be evaluated as an rvalue.18 /// The expression has an inferred type, and it will be evaluated as an rvalue.
19 none,19 none,
20 /// The expression must generate a pointer rather than a value. For example, the left hand side
21 /// of an assignment uses an "LValue" result location.
22 lvalue,
20 /// The expression will be type coerced into this type, but it will be evaluated as an rvalue.23 /// The expression will be type coerced into this type, but it will be evaluated as an rvalue.
21 ty: *zir.Inst,24 ty: *zir.Inst,
22 /// The expression must store its result into this typed pointer.25 /// The expression must store its result into this typed pointer.
...@@ -46,16 +49,43 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr...@@ -46,16 +49,43 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
46 switch (node.tag) {49 switch (node.tag) {
47 .VarDecl => unreachable, // Handled in `blockExpr`.50 .VarDecl => unreachable, // Handled in `blockExpr`.
48 .Assign => unreachable, // Handled in `blockExpr`.51 .Assign => unreachable, // Handled in `blockExpr`.
4952 .AssignBitAnd => unreachable, // Handled in `blockExpr`.
50 .Add => return arithmetic(mod, scope, rl, node.castTag(.Add).?, .add),53 .AssignBitOr => unreachable, // Handled in `blockExpr`.
51 .Sub => return arithmetic(mod, scope, rl, node.castTag(.Sub).?, .sub),54 .AssignBitShiftLeft => unreachable, // Handled in `blockExpr`.
5255 .AssignBitShiftRight => unreachable, // Handled in `blockExpr`.
53 .BangEqual => return cmp(mod, scope, rl, node.castTag(.BangEqual).?, .cmp_neq),56 .AssignBitXor => unreachable, // Handled in `blockExpr`.
54 .EqualEqual => return cmp(mod, scope, rl, node.castTag(.EqualEqual).?, .cmp_eq),57 .AssignDiv => unreachable, // Handled in `blockExpr`.
55 .GreaterThan => return cmp(mod, scope, rl, node.castTag(.GreaterThan).?, .cmp_gt),58 .AssignSub => unreachable, // Handled in `blockExpr`.
56 .GreaterOrEqual => return cmp(mod, scope, rl, node.castTag(.GreaterOrEqual).?, .cmp_gte),59 .AssignSubWrap => unreachable, // Handled in `blockExpr`.
57 .LessThan => return cmp(mod, scope, rl, node.castTag(.LessThan).?, .cmp_lt),60 .AssignMod => unreachable, // Handled in `blockExpr`.
58 .LessOrEqual => return cmp(mod, scope, rl, node.castTag(.LessOrEqual).?, .cmp_lte),61 .AssignAdd => unreachable, // Handled in `blockExpr`.
62 .AssignAddWrap => unreachable, // Handled in `blockExpr`.
63 .AssignMul => unreachable, // Handled in `blockExpr`.
64 .AssignMulWrap => unreachable, // Handled in `blockExpr`.
65
66 .Add => return simpleBinOp(mod, scope, rl, node.castTag(.Add).?, .add),
67 .AddWrap => return simpleBinOp(mod, scope, rl, node.castTag(.AddWrap).?, .addwrap),
68 .Sub => return simpleBinOp(mod, scope, rl, node.castTag(.Sub).?, .sub),
69 .SubWrap => return simpleBinOp(mod, scope, rl, node.castTag(.SubWrap).?, .subwrap),
70 .Mul => return simpleBinOp(mod, scope, rl, node.castTag(.Mul).?, .mul),
71 .MulWrap => return simpleBinOp(mod, scope, rl, node.castTag(.MulWrap).?, .mulwrap),
72 .Div => return simpleBinOp(mod, scope, rl, node.castTag(.Div).?, .div),
73 .Mod => return simpleBinOp(mod, scope, rl, node.castTag(.Mod).?, .mod_rem),
74 .BitAnd => return simpleBinOp(mod, scope, rl, node.castTag(.BitAnd).?, .bitand),
75 .BitOr => return simpleBinOp(mod, scope, rl, node.castTag(.BitOr).?, .bitor),
76 .BitShiftLeft => return simpleBinOp(mod, scope, rl, node.castTag(.BitShiftLeft).?, .shl),
77 .BitShiftRight => return simpleBinOp(mod, scope, rl, node.castTag(.BitShiftRight).?, .shr),
78 .BitXor => return simpleBinOp(mod, scope, rl, node.castTag(.BitXor).?, .xor),
79
80 .BangEqual => return simpleBinOp(mod, scope, rl, node.castTag(.BangEqual).?, .cmp_neq),
81 .EqualEqual => return simpleBinOp(mod, scope, rl, node.castTag(.EqualEqual).?, .cmp_eq),
82 .GreaterThan => return simpleBinOp(mod, scope, rl, node.castTag(.GreaterThan).?, .cmp_gt),
83 .GreaterOrEqual => return simpleBinOp(mod, scope, rl, node.castTag(.GreaterOrEqual).?, .cmp_gte),
84 .LessThan => return simpleBinOp(mod, scope, rl, node.castTag(.LessThan).?, .cmp_lt),
85 .LessOrEqual => return simpleBinOp(mod, scope, rl, node.castTag(.LessOrEqual).?, .cmp_lte),
86
87 .ArrayCat => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayCat).?, .array_cat),
88 .ArrayMult => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayMult).?, .array_mul),
5989
60 .Identifier => return rlWrap(mod, scope, rl, try identifier(mod, scope, node.castTag(.Identifier).?)),90 .Identifier => return rlWrap(mod, scope, rl, try identifier(mod, scope, node.castTag(.Identifier).?)),
61 .Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)),91 .Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)),
...@@ -99,6 +129,20 @@ pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block...@@ -99,6 +129,20 @@ pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block
99 const ass = statement.castTag(.Assign).?;129 const ass = statement.castTag(.Assign).?;
100 try assign(mod, scope, ass);130 try assign(mod, scope, ass);
101 },131 },
132 .AssignBitAnd => try assignOp(mod, scope, statement.castTag(.AssignBitAnd).?, .bitand),
133 .AssignBitOr => try assignOp(mod, scope, statement.castTag(.AssignBitOr).?, .bitor),
134 .AssignBitShiftLeft => try assignOp(mod, scope, statement.castTag(.AssignBitShiftLeft).?, .shl),
135 .AssignBitShiftRight => try assignOp(mod, scope, statement.castTag(.AssignBitShiftRight).?, .shr),
136 .AssignBitXor => try assignOp(mod, scope, statement.castTag(.AssignBitXor).?, .xor),
137 .AssignDiv => try assignOp(mod, scope, statement.castTag(.AssignDiv).?, .div),
138 .AssignSub => try assignOp(mod, scope, statement.castTag(.AssignSub).?, .sub),
139 .AssignSubWrap => try assignOp(mod, scope, statement.castTag(.AssignSubWrap).?, .subwrap),
140 .AssignMod => try assignOp(mod, scope, statement.castTag(.AssignMod).?, .mod_rem),
141 .AssignAdd => try assignOp(mod, scope, statement.castTag(.AssignAdd).?, .add),
142 .AssignAddWrap => try assignOp(mod, scope, statement.castTag(.AssignAddWrap).?, .addwrap),
143 .AssignMul => try assignOp(mod, scope, statement.castTag(.AssignMul).?, .mul),
144 .AssignMulWrap => try assignOp(mod, scope, statement.castTag(.AssignMulWrap).?, .mulwrap),
145
102 else => {146 else => {
103 const possibly_unused_result = try expr(mod, scope, .none, statement);147 const possibly_unused_result = try expr(mod, scope, .none, statement);
104 const src = scope.tree().token_locs[statement.firstToken()].start;148 const src = scope.tree().token_locs[statement.firstToken()].start;
...@@ -207,17 +251,33 @@ fn varDecl(...@@ -207,17 +251,33 @@ fn varDecl(
207251
208fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!void {252fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!void {
209 if (infix_node.lhs.castTag(.Identifier)) |ident| {253 if (infix_node.lhs.castTag(.Identifier)) |ident| {
210 const tree = scope.tree();254 // This intentionally does not support @"_" syntax.
211 const ident_name = try identifierTokenString(mod, scope, ident.token);255 const ident_name = scope.tree().tokenSlice(ident.token);
212 if (std.mem.eql(u8, ident_name, "_")) {256 if (std.mem.eql(u8, ident_name, "_")) {
213 _ = try expr(mod, scope, .discard, infix_node.rhs);257 _ = try expr(mod, scope, .discard, infix_node.rhs);
214 return;258 return;
215 } else {
216 return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{});
217 }259 }
218 } else {
219 return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{});
220 }260 }
261 const lvalue = try expr(mod, scope, .lvalue, infix_node.lhs);
262 _ = try expr(mod, scope, .{ .ptr = lvalue }, infix_node.rhs);
263}
264
265fn assignOp(
266 mod: *Module,
267 scope: *Scope,
268 infix_node: *ast.Node.SimpleInfixOp,
269 op_inst_tag: zir.Inst.Tag,
270) InnerError!void {
271 const lhs_ptr = try expr(mod, scope, .lvalue, infix_node.lhs);
272 const lhs = try mod.addZIRUnOp(scope, lhs_ptr.src, .deref, lhs_ptr);
273 const lhs_type = try mod.addZIRUnOp(scope, lhs_ptr.src, .typeof, lhs);
274 const rhs = try expr(mod, scope, .{ .ty = lhs_type }, infix_node.rhs);
275
276 const tree = scope.tree();
277 const src = tree.token_locs[infix_node.op_token].start;
278
279 const result = try mod.addZIRBinOp(scope, src, op_inst_tag, lhs, rhs);
280 _ = try mod.addZIRBinOp(scope, src, .store, lhs_ptr, result);
221}281}
222282
223fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {283fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
...@@ -279,35 +339,19 @@ fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError...@@ -279,35 +339,19 @@ fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError
279 return mod.addZIRUnOp(scope, src, .deref, lhs);339 return mod.addZIRUnOp(scope, src, .deref, lhs);
280}340}
281341
282fn cmp(342fn simpleBinOp(
283 mod: *Module,343 mod: *Module,
284 scope: *Scope,344 scope: *Scope,
285 rl: ResultLoc,345 rl: ResultLoc,
286 infix_node: *ast.Node.SimpleInfixOp,346 infix_node: *ast.Node.SimpleInfixOp,
287 cmp_inst_tag: zir.Inst.Tag,347 op_inst_tag: zir.Inst.Tag,
288) InnerError!*zir.Inst {348) InnerError!*zir.Inst {
289 const tree = scope.tree();349 const tree = scope.tree();
290 const src = tree.token_locs[infix_node.op_token].start;350 const src = tree.token_locs[infix_node.op_token].start;
291351
292 const lhs = try expr(mod, scope, .none, infix_node.lhs);
293 const rhs = try expr(mod, scope, .none, infix_node.rhs);
294 const result = try mod.addZIRBinOp(scope, src, cmp_inst_tag, lhs, rhs);
295 return rlWrap(mod, scope, rl, result);
296}
297
298fn arithmetic(
299 mod: *Module,
300 scope: *Scope,
301 rl: ResultLoc,
302 infix_node: *ast.Node.SimpleInfixOp,
303 op_inst_tag: zir.Inst.Tag,
304) InnerError!*zir.Inst {
305 const lhs = try expr(mod, scope, .none, infix_node.lhs);352 const lhs = try expr(mod, scope, .none, infix_node.lhs);
306 const rhs = try expr(mod, scope, .none, infix_node.rhs);353 const rhs = try expr(mod, scope, .none, infix_node.rhs);
307354
308 const tree = scope.tree();
309 const src = tree.token_locs[infix_node.op_token].start;
310
311 const result = try mod.addZIRBinOp(scope, src, op_inst_tag, lhs, rhs);355 const result = try mod.addZIRBinOp(scope, src, op_inst_tag, lhs, rhs);
312 return rlWrap(mod, scope, rl, result);356 return rlWrap(mod, scope, rl, result);
313}357}
...@@ -359,7 +403,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn...@@ -359,7 +403,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
359 // proper type inference requires peer type resolution on the if's403 // proper type inference requires peer type resolution on the if's
360 // branches.404 // branches.
361 const branch_rl: ResultLoc = switch (rl) {405 const branch_rl: ResultLoc = switch (rl) {
362 .discard, .none, .ty, .ptr => rl,406 .discard, .none, .ty, .ptr, .lvalue => rl,
363 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },407 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
364 };408 };
365409
...@@ -698,6 +742,10 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I...@@ -698,6 +742,10 @@ fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) I
698 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);742 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);
699 return result;743 return result;
700 },744 },
745 .lvalue => {
746 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
747 return mod.addZIRUnOp(scope, result.src, .ref, result);
748 },
701 .ty => |result_ty| {749 .ty => |result_ty| {
702 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);750 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
703 return mod.addZIRBinOp(scope, src, .as, result_ty, result);751 return mod.addZIRBinOp(scope, src, .as, result_ty, result);
...@@ -745,6 +793,11 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa...@@ -745,6 +793,11 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa
745 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);793 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);
746 return result;794 return result;
747 },795 },
796 .lvalue => {
797 const operand = try expr(mod, scope, .lvalue, params[1]);
798 const result = try mod.addZIRBinOp(scope, src, .bitcast_lvalue, dest_type, operand);
799 return result;
800 },
748 .ty => |result_ty| {801 .ty => |result_ty| {
749 const result = try expr(mod, scope, .none, params[1]);802 const result = try expr(mod, scope, .none, params[1]);
750 const bitcasted = try mod.addZIRBinOp(scope, src, .bitcast, dest_type, result);803 const bitcasted = try mod.addZIRBinOp(scope, src, .bitcast, dest_type, result);
...@@ -1003,6 +1056,10 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr...@@ -1003,6 +1056,10 @@ fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr
1003 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);1056 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);
1004 return result;1057 return result;
1005 },1058 },
1059 .lvalue => {
1060 // We need a pointer but we have a value.
1061 return mod.addZIRUnOp(scope, result.src, .ref, result);
1062 },
1006 .ty => |ty_inst| return mod.addZIRBinOp(scope, result.src, .as, ty_inst, result),1063 .ty => |ty_inst| return mod.addZIRBinOp(scope, result.src, .as, ty_inst, result),
1007 .ptr => |ptr_inst| {1064 .ptr => |ptr_inst| {
1008 const casted_result = try mod.addZIRInst(scope, result.src, zir.Inst.CoerceToPtrElem, .{1065 const casted_result = try mod.addZIRInst(scope, result.src, zir.Inst.CoerceToPtrElem, .{
src-self-hosted/zir.zig+178-63
...@@ -34,25 +34,63 @@ pub const Inst = struct {...@@ -34,25 +34,63 @@ pub const Inst = struct {
3434
35 /// These names are used directly as the instruction names in the text format.35 /// These names are used directly as the instruction names in the text format.
36 pub const Tag = enum {36 pub const Tag = enum {
37 /// Arithmetic addition, asserts no integer overflow.
38 add,
39 /// Twos complement wrapping integer addition.
40 addwrap,
37 /// Allocates stack local memory. Its lifetime ends when the block ends that contains41 /// Allocates stack local memory. Its lifetime ends when the block ends that contains
38 /// this instruction.42 /// this instruction.
39 alloc,43 alloc,
40 /// Same as `alloc` except the type is inferred.44 /// Same as `alloc` except the type is inferred.
41 alloc_inferred,45 alloc_inferred,
46 /// Array concatenation. `a ++ b`
47 array_cat,
48 /// Array multiplication `a ** b`
49 array_mul,
42 /// Function parameter value. These must be first in a function's main block,50 /// Function parameter value. These must be first in a function's main block,
43 /// in respective order with the parameters.51 /// in respective order with the parameters.
44 arg,52 arg,
53 /// Type coercion.
54 as,
55 /// Inline assembly.
56 @"asm",
57 /// Bitwise AND. `&`
58 bitand,
59 /// TODO delete this instruction, it has no purpose.
60 bitcast,
61 /// An arbitrary typed pointer, which is to be used as an L-Value, is pointer-casted
62 /// to a new L-Value. The destination type is given by LHS. The cast is to be evaluated
63 /// as if it were a bit-cast operation from the operand pointer element type to the
64 /// provided destination type.
65 bitcast_lvalue,
45 /// A typed result location pointer is bitcasted to a new result location pointer.66 /// A typed result location pointer is bitcasted to a new result location pointer.
46 /// The new result location pointer has an inferred type.67 /// The new result location pointer has an inferred type.
47 bitcast_result_ptr,68 bitcast_result_ptr,
69 /// Bitwise OR. `|`
70 bitor,
48 /// A labeled block of code, which can return a value.71 /// A labeled block of code, which can return a value.
49 block,72 block,
73 /// Boolean NOT. See also `bitnot`.
74 boolnot,
50 /// Return a value from a `Block`.75 /// Return a value from a `Block`.
51 @"break",76 @"break",
52 breakpoint,77 breakpoint,
53 /// Same as `break` but without an operand; the operand is assumed to be the void value.78 /// Same as `break` but without an operand; the operand is assumed to be the void value.
54 breakvoid,79 breakvoid,
80 /// Function call.
55 call,81 call,
82 /// `<`
83 cmp_lt,
84 /// `<=`
85 cmp_lte,
86 /// `==`
87 cmp_eq,
88 /// `>=`
89 cmp_gte,
90 /// `>`
91 cmp_gt,
92 /// `!=`
93 cmp_neq,
56 /// Coerces a result location pointer to a new element type. It is evaluated "backwards"-94 /// Coerces a result location pointer to a new element type. It is evaluated "backwards"-
57 /// as type coercion from the new element type to the old element type.95 /// as type coercion from the new element type to the old element type.
58 /// LHS is destination element type, RHS is result pointer.96 /// LHS is destination element type, RHS is result pointer.
...@@ -65,6 +103,8 @@ pub const Inst = struct {...@@ -65,6 +103,8 @@ pub const Inst = struct {
65 coerce_to_ptr_elem,103 coerce_to_ptr_elem,
66 /// Emit an error message and fail compilation.104 /// Emit an error message and fail compilation.
67 compileerror,105 compileerror,
106 /// Conditional branch. Splits control flow based on a boolean condition value.
107 condbr,
68 /// Special case, has no textual representation.108 /// Special case, has no textual representation.
69 @"const",109 @"const",
70 /// Represents a pointer to a global decl by name.110 /// Represents a pointer to a global decl by name.
...@@ -76,61 +116,103 @@ pub const Inst = struct {...@@ -76,61 +116,103 @@ pub const Inst = struct {
76 declval,116 declval,
77 /// Same as declval but the parameter is a `*Module.Decl` rather than a name.117 /// Same as declval but the parameter is a `*Module.Decl` rather than a name.
78 declval_in_module,118 declval_in_module,
119 /// Load the value from a pointer.
120 deref,
121 /// Arithmetic division. Asserts no integer overflow.
122 div,
123 /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at
124 /// the provided index.
125 elemptr,
79 /// Emits a compile error if the operand is not `void`.126 /// Emits a compile error if the operand is not `void`.
80 ensure_result_used,127 ensure_result_used,
81 /// Emits a compile error if an error is ignored.128 /// Emits a compile error if an error is ignored.
82 ensure_result_non_error,129 ensure_result_non_error,
83 boolnot,130 /// Export the provided Decl as the provided name in the compilation's output object file.
84 /// Obtains a pointer to the return value.131 @"export",
85 ret_ptr,132 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
86 /// Obtains the return type of the in-scope function.133 /// to the named field.
87 ret_type,
88 /// Write a value to a pointer.
89 store,
90 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
91 str,
92 int,
93 inttype,
94 ptrtoint,
95 fieldptr,134 fieldptr,
96 deref,135 /// Convert a larger float type to any other float type, possibly causing a loss of precision.
97 as,136 floatcast,
98 @"asm",137 /// Declare a function body.
99 @"unreachable",
100 @"return",
101 returnvoid,
102 @"fn",138 @"fn",
139 /// Returns a function type.
103 fntype,140 fntype,
104 @"export",141 /// Integer literal.
142 int,
143 /// Convert an integer value to another integer type, asserting that the destination type
144 /// can hold the same mathematical value.
145 intcast,
146 /// Make an integer type out of signedness and bit count.
147 inttype,
148 /// Return a boolean false if an optional is null. `x != null`
149 isnonnull,
150 /// Return a boolean true if an optional is null. `x == null`
151 isnull,
152 /// Ambiguously remainder division or modulus. If the computation would possibly have
153 /// a different value depending on whether the operation is remainder division or modulus,
154 /// a compile error is emitted. Otherwise the computation is performed.
155 mod_rem,
156 /// Arithmetic multiplication. Asserts no integer overflow.
157 mul,
158 /// Twos complement wrapping integer multiplication.
159 mulwrap,
105 /// Given a reference to a function and a parameter index, returns the160 /// Given a reference to a function and a parameter index, returns the
106 /// type of the parameter. TODO what happens when the parameter is `anytype`?161 /// type of the parameter. TODO what happens when the parameter is `anytype`?
107 param_type,162 param_type,
163 /// An alternative to using `const` for simple primitive values such as `true` or `u8`.
164 /// TODO flatten so that each primitive has its own ZIR Inst Tag.
108 primitive,165 primitive,
109 intcast,166 /// Convert a pointer to a `usize` integer.
110 bitcast,167 ptrtoint,
111 floatcast,168 /// Turns an R-Value into a const L-Value. In other words, it takes a value,
112 elemptr,169 /// stores it in a memory location, and returns a const pointer to it. If the value
113 add,170 /// is `comptime`, the memory location is global static constant data. Otherwise,
171 /// the memory location is in the stack frame, local to the scope containing the
172 /// instruction.
173 ref,
174 /// Obtains a pointer to the return value.
175 ret_ptr,
176 /// Obtains the return type of the in-scope function.
177 ret_type,
178 /// Sends control flow back to the function's callee. Takes an operand as the return value.
179 @"return",
180 /// Same as `return` but there is no operand; the operand is implicitly the void value.
181 returnvoid,
182 /// Integer shift-left. Zeroes are shifted in from the right hand side.
183 shl,
184 /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
185 shr,
186 /// Write a value to a pointer. For loading, see `deref`.
187 store,
188 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
189 str,
190 /// Arithmetic subtraction. Asserts no integer overflow.
114 sub,191 sub,
115 cmp_lt,192 /// Twos complement wrapping integer subtraction.
116 cmp_lte,193 subwrap,
117 cmp_eq,194 /// Returns the type of a value.
118 cmp_gte,195 typeof,
119 cmp_gt,196 /// Asserts control-flow will not reach this instruction. Not safety checked - the compiler
120 cmp_neq,197 /// will assume the correctness of this instruction.
121 condbr,198 unreach_nocheck,
122 isnull,199 /// Asserts control-flow will not reach this instruction. In safety-checked modes,
123 isnonnull,200 /// this will generate a call to the panic function unless it can be proven unreachable
201 /// by the compiler.
202 @"unreachable",
203 /// Bitwise XOR. `^`
204 xor,
124205
125 pub fn Type(tag: Tag) type {206 pub fn Type(tag: Tag) type {
126 return switch (tag) {207 return switch (tag) {
127 .arg,208 .arg,
128 .breakpoint,209 .breakpoint,
129 .@"unreachable",
130 .returnvoid,210 .returnvoid,
131 .alloc_inferred,211 .alloc_inferred,
132 .ret_ptr,212 .ret_ptr,
133 .ret_type,213 .ret_type,
214 .unreach_nocheck,
215 .@"unreachable",
134 => NoOp,216 => NoOp,
135217
136 .boolnot,218 .boolnot,
...@@ -143,10 +225,25 @@ pub const Inst = struct {...@@ -143,10 +225,25 @@ pub const Inst = struct {
143 .ensure_result_used,225 .ensure_result_used,
144 .ensure_result_non_error,226 .ensure_result_non_error,
145 .bitcast_result_ptr,227 .bitcast_result_ptr,
228 .ref,
229 .bitcast_lvalue,
230 .typeof,
146 => UnOp,231 => UnOp,
147232
148 .add,233 .add,
234 .addwrap,
235 .array_cat,
236 .array_mul,
237 .bitand,
238 .bitor,
239 .div,
240 .mod_rem,
241 .mul,
242 .mulwrap,
243 .shl,
244 .shr,
149 .sub,245 .sub,
246 .subwrap,
150 .cmp_lt,247 .cmp_lt,
151 .cmp_lte,248 .cmp_lte,
152 .cmp_eq,249 .cmp_eq,
...@@ -158,6 +255,7 @@ pub const Inst = struct {...@@ -158,6 +255,7 @@ pub const Inst = struct {
158 .intcast,255 .intcast,
159 .bitcast,256 .bitcast,
160 .coerce_result_ptr,257 .coerce_result_ptr,
258 .xor,
161 => BinOp,259 => BinOp,
162260
163 .block => Block,261 .block => Block,
...@@ -192,13 +290,30 @@ pub const Inst = struct {...@@ -192,13 +290,30 @@ pub const Inst = struct {
192 /// Function calls do not count.290 /// Function calls do not count.
193 pub fn isNoReturn(tag: Tag) bool {291 pub fn isNoReturn(tag: Tag) bool {
194 return switch (tag) {292 return switch (tag) {
293 .add,
294 .addwrap,
195 .alloc,295 .alloc,
196 .alloc_inferred,296 .alloc_inferred,
297 .array_cat,
298 .array_mul,
197 .arg,299 .arg,
300 .as,
301 .@"asm",
302 .bitand,
303 .bitcast,
304 .bitcast_lvalue,
198 .bitcast_result_ptr,305 .bitcast_result_ptr,
306 .bitor,
199 .block,307 .block,
308 .boolnot,
200 .breakpoint,309 .breakpoint,
201 .call,310 .call,
311 .cmp_lt,
312 .cmp_lte,
313 .cmp_eq,
314 .cmp_gte,
315 .cmp_gt,
316 .cmp_neq,
202 .coerce_result_ptr,317 .coerce_result_ptr,
203 .coerce_result_block_ptr,318 .coerce_result_block_ptr,
204 .coerce_to_ptr_elem,319 .coerce_to_ptr_elem,
...@@ -207,48 +322,48 @@ pub const Inst = struct {...@@ -207,48 +322,48 @@ pub const Inst = struct {
207 .declref_str,322 .declref_str,
208 .declval,323 .declval,
209 .declval_in_module,324 .declval_in_module,
325 .deref,
326 .div,
327 .elemptr,
210 .ensure_result_used,328 .ensure_result_used,
211 .ensure_result_non_error,329 .ensure_result_non_error,
212 .ret_ptr,330 .@"export",
213 .ret_type,331 .floatcast,
214 .store,
215 .str,
216 .int,
217 .inttype,
218 .ptrtoint,
219 .fieldptr,332 .fieldptr,
220 .deref,
221 .as,
222 .@"asm",
223 .@"fn",333 .@"fn",
224 .fntype,334 .fntype,
225 .@"export",335 .int,
336 .intcast,
337 .inttype,
338 .isnonnull,
339 .isnull,
340 .mod_rem,
341 .mul,
342 .mulwrap,
226 .param_type,343 .param_type,
227 .primitive,344 .primitive,
228 .intcast,345 .ptrtoint,
229 .bitcast,346 .ref,
230 .floatcast,347 .ret_ptr,
231 .elemptr,348 .ret_type,
232 .add,349 .shl,
350 .shr,
351 .store,
352 .str,
233 .sub,353 .sub,
234 .cmp_lt,354 .subwrap,
235 .cmp_lte,355 .typeof,
236 .cmp_eq,356 .xor,
237 .cmp_gte,
238 .cmp_gt,
239 .cmp_neq,
240 .isnull,
241 .isnonnull,
242 .boolnot,
243 => false,357 => false,
244358
245 .condbr,
246 .@"unreachable",
247 .@"return",
248 .returnvoid,
249 .@"break",359 .@"break",
250 .breakvoid,360 .breakvoid,
361 .condbr,
251 .compileerror,362 .compileerror,
363 .@"return",
364 .returnvoid,
365 .unreach_nocheck,
366 .@"unreachable",
252 => true,367 => true,
253 };368 };
254 }369 }