| ... | @@ -665,8 +665,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -665,8 +665,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 665 | .prefetch => try self.airPrefetch(inst), | 665 | .prefetch => try self.airPrefetch(inst), |
| 666 | .mul_add => try self.airMulAdd(inst), | 666 | .mul_add => try self.airMulAdd(inst), |
| 667 | | 667 | |
| 668 | .@"try" => @panic("TODO"), | 668 | .@"try" => try self.airTry(inst), |
| 669 | .try_ptr => @panic("TODO"), | 669 | .try_ptr => try self.airTryPtr(inst), |
| 670 | | 670 | |
| 671 | .dbg_var_ptr, | 671 | .dbg_var_ptr, |
| 672 | .dbg_var_val, | 672 | .dbg_var_val, |
| ... | @@ -2308,27 +2308,70 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2308,27 +2308,70 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 2308 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2308 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2309 | } | 2309 | } |
| 2310 | | 2310 | |
| | 2311 | /// Given an error union, returns the error |
| | 2312 | fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { |
| | 2313 | const err_ty = error_union_ty.errorUnionSet(); |
| | 2314 | const payload_ty = error_union_ty.errorUnionPayload(); |
| | 2315 | if (err_ty.errorSetCardinality() == .zero) { |
| | 2316 | return MCValue{ .immediate = 0 }; |
| | 2317 | } |
| | 2318 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 2319 | return error_union_mcv; |
| | 2320 | } |
| | 2321 | |
| | 2322 | const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*)); |
| | 2323 | switch (error_union_mcv) { |
| | 2324 | .register => return self.fail("TODO errUnionErr for registers", .{}), |
| | 2325 | .stack_offset => |off| { |
| | 2326 | return MCValue{ .stack_offset = off - err_offset }; |
| | 2327 | }, |
| | 2328 | .memory => |addr| { |
| | 2329 | return MCValue{ .memory = addr + err_offset }; |
| | 2330 | }, |
| | 2331 | else => unreachable, // invalid MCValue for an error union |
| | 2332 | } |
| | 2333 | } |
| | 2334 | |
| 2311 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | 2335 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2312 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2336 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2313 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2337 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2314 | const error_union_ty = self.air.typeOf(ty_op.operand); | 2338 | const error_union_ty = self.air.typeOf(ty_op.operand); |
| 2315 | const payload_ty = error_union_ty.errorUnionPayload(); | | |
| 2316 | const mcv = try self.resolveInst(ty_op.operand); | 2339 | const mcv = try self.resolveInst(ty_op.operand); |
| 2317 | if (!payload_ty.hasRuntimeBits()) break :result mcv; | 2340 | break :result try self.errUnionErr(mcv, error_union_ty); |
| 2318 | | | |
| 2319 | return self.fail("TODO implement unwrap error union error for non-empty payloads", .{}); | | |
| 2320 | }; | 2341 | }; |
| 2321 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2342 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2322 | } | 2343 | } |
| 2323 | | 2344 | |
| | 2345 | /// Given an error union, returns the payload |
| | 2346 | fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { |
| | 2347 | const err_ty = error_union_ty.errorUnionSet(); |
| | 2348 | const payload_ty = error_union_ty.errorUnionPayload(); |
| | 2349 | if (err_ty.errorSetCardinality() == .zero) { |
| | 2350 | return error_union_mcv; |
| | 2351 | } |
| | 2352 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 2353 | return MCValue.none; |
| | 2354 | } |
| | 2355 | |
| | 2356 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*)); |
| | 2357 | switch (error_union_mcv) { |
| | 2358 | .register => return self.fail("TODO errUnionPayload for registers", .{}), |
| | 2359 | .stack_offset => |off| { |
| | 2360 | return MCValue{ .stack_offset = off - payload_offset }; |
| | 2361 | }, |
| | 2362 | .memory => |addr| { |
| | 2363 | return MCValue{ .memory = addr + payload_offset }; |
| | 2364 | }, |
| | 2365 | else => unreachable, // invalid MCValue for an error union |
| | 2366 | } |
| | 2367 | } |
| | 2368 | |
| 2324 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { | 2369 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2325 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2370 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2326 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2371 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2327 | const error_union_ty = self.air.typeOf(ty_op.operand); | 2372 | const error_union_ty = self.air.typeOf(ty_op.operand); |
| 2328 | const payload_ty = error_union_ty.errorUnionPayload(); | 2373 | const error_union = try self.resolveInst(ty_op.operand); |
| 2329 | if (!payload_ty.hasRuntimeBits()) break :result MCValue.none; | 2374 | break :result try self.errUnionPayload(error_union, error_union_ty); |
| 2330 | | | |
| 2331 | return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{}); | | |
| 2332 | }; | 2375 | }; |
| 2333 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2376 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2334 | } | 2377 | } |
| ... | @@ -3389,45 +3432,38 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3389,45 +3432,38 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 3389 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); | 3432 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); |
| 3390 | } | 3433 | } |
| 3391 | | 3434 | |
| 3392 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | 3435 | fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index { |
| 3393 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 3436 | switch (condition) { |
| 3394 | const cond = try self.resolveInst(pl_op.operand); | | |
| 3395 | const extra = self.air.extraData(Air.CondBr, pl_op.payload); | | |
| 3396 | const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len]; | | |
| 3397 | const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | | |
| 3398 | const liveness_condbr = self.liveness.getCondBr(inst); | | |
| 3399 | | | |
| 3400 | const reloc: Mir.Inst.Index = switch (cond) { | | |
| 3401 | .compare_flags_signed, | 3437 | .compare_flags_signed, |
| 3402 | .compare_flags_unsigned, | 3438 | .compare_flags_unsigned, |
| 3403 | => try self.addInst(.{ | 3439 | => return try self.addInst(.{ |
| 3404 | .tag = .b_cond, | 3440 | .tag = .b_cond, |
| 3405 | .data = .{ | 3441 | .data = .{ |
| 3406 | .inst_cond = .{ | 3442 | .inst_cond = .{ |
| 3407 | .inst = undefined, // populated later through performReloc | 3443 | .inst = undefined, // populated later through performReloc |
| 3408 | .cond = switch (cond) { | 3444 | .cond = switch (condition) { |
| 3409 | .compare_flags_signed => |cmp_op| blk: { | 3445 | .compare_flags_signed => |cmp_op| blk: { |
| 3410 | // Here we map to the opposite condition because the jump is to the false branch. | 3446 | // Here we map to the opposite condition because the jump is to the false branch. |
| 3411 | const condition = Instruction.Condition.fromCompareOperatorSigned(cmp_op); | 3447 | const condition_code = Instruction.Condition.fromCompareOperatorSigned(cmp_op); |
| 3412 | break :blk condition.negate(); | 3448 | break :blk condition_code.negate(); |
| 3413 | }, | 3449 | }, |
| 3414 | .compare_flags_unsigned => |cmp_op| blk: { | 3450 | .compare_flags_unsigned => |cmp_op| blk: { |
| 3415 | // Here we map to the opposite condition because the jump is to the false branch. | 3451 | // Here we map to the opposite condition because the jump is to the false branch. |
| 3416 | const condition = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op); | 3452 | const condition_code = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op); |
| 3417 | break :blk condition.negate(); | 3453 | break :blk condition_code.negate(); |
| 3418 | }, | 3454 | }, |
| 3419 | else => unreachable, | 3455 | else => unreachable, |
| 3420 | }, | 3456 | }, |
| 3421 | }, | 3457 | }, |
| 3422 | }, | 3458 | }, |
| 3423 | }), | 3459 | }), |
| 3424 | else => blk: { | 3460 | else => { |
| 3425 | const reg = switch (cond) { | 3461 | const reg = switch (condition) { |
| 3426 | .register => |r| r, | 3462 | .register => |r| r, |
| 3427 | else => try self.copyToTmpRegister(Type.bool, cond), | 3463 | else => try self.copyToTmpRegister(Type.bool, condition), |
| 3428 | }; | 3464 | }; |
| 3429 | | 3465 | |
| 3430 | break :blk try self.addInst(.{ | 3466 | return try self.addInst(.{ |
| 3431 | .tag = .cbz, | 3467 | .tag = .cbz, |
| 3432 | .data = .{ | 3468 | .data = .{ |
| 3433 | .r_inst = .{ | 3469 | .r_inst = .{ |
| ... | @@ -3437,7 +3473,18 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3437,7 +3473,18 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 3437 | }, | 3473 | }, |
| 3438 | }); | 3474 | }); |
| 3439 | }, | 3475 | }, |
| 3440 | }; | 3476 | } |
| | 3477 | } |
| | 3478 | |
| | 3479 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| | 3480 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| | 3481 | const cond = try self.resolveInst(pl_op.operand); |
| | 3482 | const extra = self.air.extraData(Air.CondBr, pl_op.payload); |
| | 3483 | const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len]; |
| | 3484 | const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; |
| | 3485 | const liveness_condbr = self.liveness.getCondBr(inst); |
| | 3486 | |
| | 3487 | const reloc = try self.condBr(cond); |
| 3441 | | 3488 | |
| 3442 | // If the condition dies here in this condbr instruction, process | 3489 | // If the condition dies here in this condbr instruction, process |
| 3443 | // that death now instead of later as this has an effect on | 3490 | // that death now instead of later as this has an effect on |
| ... | @@ -4469,6 +4516,33 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4469,6 +4516,33 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 4469 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); | 4516 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); |
| 4470 | } | 4517 | } |
| 4471 | | 4518 | |
| | 4519 | fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| | 4520 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| | 4521 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| | 4522 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| | 4523 | const result: MCValue = result: { |
| | 4524 | const error_union_ty = self.air.typeOf(pl_op.operand); |
| | 4525 | const error_union = try self.resolveInst(pl_op.operand); |
| | 4526 | const is_err_result = try self.isErr(error_union_ty, error_union); |
| | 4527 | const reloc = try self.condBr(is_err_result); |
| | 4528 | |
| | 4529 | try self.genBody(body); |
| | 4530 | |
| | 4531 | try self.performReloc(reloc); |
| | 4532 | break :result try self.errUnionPayload(error_union, error_union_ty); |
| | 4533 | }; |
| | 4534 | return self.finishAir(inst, result, .{ pl_op.operand, .none, .none }); |
| | 4535 | } |
| | 4536 | |
| | 4537 | fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { |
| | 4538 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| | 4539 | const extra = self.air.extraData(Air.TryPtr, ty_pl.payload); |
| | 4540 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| | 4541 | _ = body; |
| | 4542 | return self.fail("TODO implement airTryPtr for arm", .{}); |
| | 4543 | // return self.finishAir(inst, result, .{ extra.data.ptr, .none, .none }); |
| | 4544 | } |
| | 4545 | |
| 4472 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | 4546 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 4473 | // First section of indexes correspond to a set number of constant values. | 4547 | // First section of indexes correspond to a set number of constant values. |
| 4474 | const ref_int = @enumToInt(inst); | 4548 | const ref_int = @enumToInt(inst); |