| author | |
| committer | |
| log | 488df7f1d1f7300bfb23134cc79fed2cef917ae2 |
| tree | 667e88750a5dfd1c5b6591769f50d19a3a754ddc |
| parent | bd9b3fe1e63539edbacacb0871470b5da4f10012 |
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 | } |
| 2416 | 2434 | ||
| ... | @@ -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 | } |
| 2424 | 2442 | ||
| 2443 | fn analyzeInstBitCastLValue(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | ||
| 2444 | return self.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastLValue", .{}); | ||
| 2445 | } | ||
| 2446 | |||
| 2425 | fn analyzeInstBitCastResultPtr(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 2447 | fn 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 | } |
| 2440 | 2462 | ||
| 2463 | fn analyzeInstRef(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | ||
| 2464 | return self.fail(scope, inst.base.src, "TODO implement analyzeInstRef", .{}); | ||
| 2465 | } | ||
| 2466 | |||
| 2441 | fn analyzeInstRetType(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | 2467 | fn 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 | } |
| 3046 | 3072 | ||
| 3073 | fn analyzeInstShl(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | ||
| 3074 | return self.fail(scope, inst.base.src, "TODO implement analyzeInstShl", .{}); | ||
| 3075 | } | ||
| 3076 | |||
| 3077 | fn analyzeInstShr(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | ||
| 3078 | return self.fail(scope, inst.base.src, "TODO implement analyzeInstShr", .{}); | ||
| 3079 | } | ||
| 3080 | |||
| 3081 | fn analyzeInstBitwise(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | ||
| 3082 | return self.fail(scope, inst.base.src, "TODO implement analyzeInstBitwise", .{}); | ||
| 3083 | } | ||
| 3084 | |||
| 3085 | fn analyzeInstArrayCat(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | ||
| 3086 | return self.fail(scope, inst.base.src, "TODO implement analyzeInstArrayCat", .{}); | ||
| 3087 | } | ||
| 3088 | |||
| 3089 | fn analyzeInstArrayMul(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | ||
| 3090 | return self.fail(scope, inst.base.src, "TODO implement analyzeInstArrayMul", .{}); | ||
| 3091 | } | ||
| 3092 | |||
| 3047 | fn analyzeInstArithmetic(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst { | 3093 | fn 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 | } |
| 3259 | 3305 | ||
| 3306 | fn 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 | |||
| 3260 | fn analyzeInstBoolNot(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 3311 | fn 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 | } |
| 3321 | 3372 | ||
| 3373 | fn 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 | |||
| 3378 | fn analyzeInstUnreachNoChk(self: *Module, scope: *Scope, unreach: *zir.Inst.NoOp) InnerError!*Inst { | ||
| 3379 | return self.analyzeUnreach(scope, unreach.base.src); | ||
| 3380 | } | ||
| 3381 | |||
| 3322 | fn analyzeInstUnreachable(self: *Module, scope: *Scope, unreach: *zir.Inst.NoOp) InnerError!*Inst { | 3382 | fn 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 | } |
| 3330 | 3390 | ||
| 3331 | fn analyzeInstRet(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 3391 | fn 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`. |
| 49 | 52 | .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`. |
| 52 | 55 | .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), | ||
| 59 | 89 | ||
| 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( |
| 207 | 251 | ||
| 208 | fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!void { | 252 | fn 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 | |||
| 265 | fn 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 | } |
| 222 | 282 | ||
| 223 | fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { | 283 | fn 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 | } |
| 281 | 341 | ||
| 282 | fn cmp( | 342 | fn 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; |
| 291 | 351 | ||
| 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 | |||
| 298 | fn 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); |
| 307 | 354 | ||
| 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's | 403 | // 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 | }; |
| 365 | 409 | ||
| ... | @@ -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 { |
| 34 | 34 | ||
| 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 contains | 41 | /// 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 the | 160 | /// 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, | ||
| 124 | 205 | ||
| 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, |
| 135 | 217 | ||
| 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, |
| 147 | 232 | ||
| 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, |
| 162 | 260 | ||
| 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, |
| 244 | 358 | ||
| 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 | } |