| ... | ... | @@ -665,8 +665,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 665 | 665 | .prefetch => try self.airPrefetch(inst), |
| 666 | 666 | .mul_add => try self.airMulAdd(inst), |
| 667 | 667 | |
| 668 | | .@"try" => @panic("TODO"), |
| 669 | | .try_ptr => @panic("TODO"), |
| 668 | .@"try" => try self.airTry(inst), |
| 669 | .try_ptr => try self.airTryPtr(inst), |
| 670 | 670 | |
| 671 | 671 | .dbg_var_ptr, |
| 672 | 672 | .dbg_var_val, |
| ... | ... | @@ -2308,27 +2308,70 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 2308 | 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 | 2335 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2312 | 2336 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2313 | 2337 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2314 | 2338 | const error_union_ty = self.air.typeOf(ty_op.operand); |
| 2315 | | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2316 | 2339 | const mcv = try self.resolveInst(ty_op.operand); |
| 2317 | | if (!payload_ty.hasRuntimeBits()) break :result mcv; |
| 2318 | | |
| 2319 | | return self.fail("TODO implement unwrap error union error for non-empty payloads", .{}); |
| 2340 | break :result try self.errUnionErr(mcv, error_union_ty); |
| 2320 | 2341 | }; |
| 2321 | 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 | 2369 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2325 | 2370 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2326 | 2371 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2327 | 2372 | const error_union_ty = self.air.typeOf(ty_op.operand); |
| 2328 | | const payload_ty = error_union_ty.errorUnionPayload(); |
| 2329 | | if (!payload_ty.hasRuntimeBits()) break :result MCValue.none; |
| 2330 | | |
| 2331 | | return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{}); |
| 2373 | const error_union = try self.resolveInst(ty_op.operand); |
| 2374 | break :result try self.errUnionPayload(error_union, error_union_ty); |
| 2332 | 2375 | }; |
| 2333 | 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 | 3432 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); |
| 3390 | 3433 | } |
| 3391 | 3434 | |
| 3392 | | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 3393 | | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 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) { |
| 3435 | fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index { |
| 3436 | switch (condition) { |
| 3401 | 3437 | .compare_flags_signed, |
| 3402 | 3438 | .compare_flags_unsigned, |
| 3403 | | => try self.addInst(.{ |
| 3439 | => return try self.addInst(.{ |
| 3404 | 3440 | .tag = .b_cond, |
| 3405 | 3441 | .data = .{ |
| 3406 | 3442 | .inst_cond = .{ |
| 3407 | 3443 | .inst = undefined, // populated later through performReloc |
| 3408 | | .cond = switch (cond) { |
| 3444 | .cond = switch (condition) { |
| 3409 | 3445 | .compare_flags_signed => |cmp_op| blk: { |
| 3410 | 3446 | // Here we map to the opposite condition because the jump is to the false branch. |
| 3411 | | const condition = Instruction.Condition.fromCompareOperatorSigned(cmp_op); |
| 3412 | | break :blk condition.negate(); |
| 3447 | const condition_code = Instruction.Condition.fromCompareOperatorSigned(cmp_op); |
| 3448 | break :blk condition_code.negate(); |
| 3413 | 3449 | }, |
| 3414 | 3450 | .compare_flags_unsigned => |cmp_op| blk: { |
| 3415 | 3451 | // Here we map to the opposite condition because the jump is to the false branch. |
| 3416 | | const condition = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op); |
| 3417 | | break :blk condition.negate(); |
| 3452 | const condition_code = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op); |
| 3453 | break :blk condition_code.negate(); |
| 3418 | 3454 | }, |
| 3419 | 3455 | else => unreachable, |
| 3420 | 3456 | }, |
| 3421 | 3457 | }, |
| 3422 | 3458 | }, |
| 3423 | 3459 | }), |
| 3424 | | else => blk: { |
| 3425 | | const reg = switch (cond) { |
| 3460 | else => { |
| 3461 | const reg = switch (condition) { |
| 3426 | 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 | 3467 | .tag = .cbz, |
| 3432 | 3468 | .data = .{ |
| 3433 | 3469 | .r_inst = .{ |
| ... | ... | @@ -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 | 3489 | // If the condition dies here in this condbr instruction, process |
| 3443 | 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 | 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 | 4546 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 4473 | 4547 | // First section of indexes correspond to a set number of constant values. |
| 4474 | 4548 | const ref_int = @enumToInt(inst); |