| ... | ... | @@ -1401,19 +1401,26 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1401 | 1401 | |
| 1402 | 1402 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1403 | 1403 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1404 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 1405 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 1406 | 1404 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 1407 | 1405 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 1408 | 1406 | |
| 1409 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1410 | | .dead |
| 1411 | | else |
| 1412 | | try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ |
| 1413 | | .lhs = bin_op.lhs, |
| 1414 | | .rhs = bin_op.rhs, |
| 1415 | | .inst = inst, |
| 1416 | | }); |
| 1407 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1408 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 1409 | const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; |
| 1410 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1411 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1412 | |
| 1413 | switch (tag) { |
| 1414 | .add, |
| 1415 | .sub, |
| 1416 | => break :result try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1417 | else => break :result try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ |
| 1418 | .lhs = bin_op.lhs, |
| 1419 | .rhs = bin_op.rhs, |
| 1420 | .inst = inst, |
| 1421 | }), |
| 1422 | } |
| 1423 | }; |
| 1417 | 1424 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1418 | 1425 | } |
| 1419 | 1426 | |
| ... | ... | @@ -1459,8 +1466,8 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1459 | 1466 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1460 | 1467 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1461 | 1468 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1462 | | const lhs = try self.resolveInst(extra.lhs); |
| 1463 | | const rhs = try self.resolveInst(extra.rhs); |
| 1469 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 1470 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 1464 | 1471 | const lhs_ty = self.air.typeOf(extra.lhs); |
| 1465 | 1472 | const rhs_ty = self.air.typeOf(extra.rhs); |
| 1466 | 1473 | |
| ... | ... | @@ -1485,7 +1492,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1485 | 1492 | .sub_with_overflow => .sub, |
| 1486 | 1493 | else => unreachable, |
| 1487 | 1494 | }; |
| 1488 | | const dest = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, null); |
| 1495 | const dest = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, null); |
| 1489 | 1496 | const dest_reg = dest.register; |
| 1490 | 1497 | const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg); |
| 1491 | 1498 | defer self.register_manager.unlockReg(dest_reg_lock); |
| ... | ... | @@ -1511,6 +1518,9 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1511 | 1518 | |
| 1512 | 1519 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1513 | 1520 | } else if (int_info.bits == 32) { |
| 1521 | const lhs = try self.resolveInst(extra.lhs); |
| 1522 | const rhs = try self.resolveInst(extra.rhs); |
| 1523 | |
| 1514 | 1524 | // Only say yes if the operation is |
| 1515 | 1525 | // commutative, i.e. we can swap both of the |
| 1516 | 1526 | // operands |
| ... | ... | @@ -2600,26 +2610,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 2600 | 2610 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; |
| 2601 | 2611 | }, |
| 2602 | 2612 | else => { |
| 2603 | | const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ |
| 2604 | | .immediate = struct_field_offset, |
| 2605 | | }); |
| 2606 | | const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg); |
| 2607 | | defer self.register_manager.unlockReg(offset_reg_lock); |
| 2608 | | |
| 2609 | | const addr_reg = try self.copyToTmpRegister(ptr_ty, mcv); |
| 2610 | | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 2611 | | defer self.register_manager.unlockReg(addr_reg_lock); |
| 2613 | const lhs_bind: ReadArg.Bind = .{ .mcv = mcv }; |
| 2614 | const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = struct_field_offset } }; |
| 2612 | 2615 | |
| 2613 | | const dest = try self.binOp( |
| 2614 | | .add, |
| 2615 | | .{ .register = addr_reg }, |
| 2616 | | .{ .register = offset_reg }, |
| 2617 | | Type.usize, |
| 2618 | | Type.usize, |
| 2619 | | null, |
| 2620 | | ); |
| 2621 | | |
| 2622 | | break :result dest; |
| 2616 | break :result try self.addSub(.add, lhs_bind, rhs_bind, Type.usize, Type.usize, null); |
| 2623 | 2617 | }, |
| 2624 | 2618 | } |
| 2625 | 2619 | }; |
| ... | ... | @@ -2708,6 +2702,25 @@ const ReadArg = struct { |
| 2708 | 2702 | .mcv => |mcv| mcv, |
| 2709 | 2703 | }; |
| 2710 | 2704 | } |
| 2705 | |
| 2706 | fn resolveToImmediate(bind: Bind, function: *Self) InnerError!?u32 { |
| 2707 | switch (bind) { |
| 2708 | .inst => |inst| { |
| 2709 | // TODO resolve independently of inst_table |
| 2710 | const mcv = try function.resolveInst(inst); |
| 2711 | switch (mcv) { |
| 2712 | .immediate => |imm| return imm, |
| 2713 | else => return null, |
| 2714 | } |
| 2715 | }, |
| 2716 | .mcv => |mcv| { |
| 2717 | switch (mcv) { |
| 2718 | .immediate => |imm| return imm, |
| 2719 | else => return null, |
| 2720 | } |
| 2721 | }, |
| 2722 | } |
| 2723 | } |
| 2711 | 2724 | }; |
| 2712 | 2725 | }; |
| 2713 | 2726 | |
| ... | ... | @@ -3057,6 +3070,136 @@ fn binOpImmediate( |
| 3057 | 3070 | return MCValue{ .register = dest_reg }; |
| 3058 | 3071 | } |
| 3059 | 3072 | |
| 3073 | /// TODO |
| 3074 | fn binOpRegisterNew( |
| 3075 | self: *Self, |
| 3076 | mir_tag: Mir.Inst.Tag, |
| 3077 | lhs_bind: ReadArg.Bind, |
| 3078 | rhs_bind: ReadArg.Bind, |
| 3079 | lhs_ty: Type, |
| 3080 | rhs_ty: Type, |
| 3081 | maybe_inst: ?Air.Inst.Index, |
| 3082 | ) !MCValue { |
| 3083 | var lhs_reg: Register = undefined; |
| 3084 | var rhs_reg: Register = undefined; |
| 3085 | var dest_reg: Register = undefined; |
| 3086 | |
| 3087 | const read_args = [_]ReadArg{ |
| 3088 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| 3089 | .{ .ty = rhs_ty, .bind = rhs_bind, .class = gp, .reg = &rhs_reg }, |
| 3090 | }; |
| 3091 | const write_args = [_]WriteArg{ |
| 3092 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 3093 | }; |
| 3094 | try self.allocRegs( |
| 3095 | &read_args, |
| 3096 | &write_args, |
| 3097 | if (maybe_inst) |inst| .{ |
| 3098 | .corresponding_inst = inst, |
| 3099 | .operand_mapping = &.{ 0, 1 }, |
| 3100 | } else null, |
| 3101 | ); |
| 3102 | |
| 3103 | const mir_data: Mir.Inst.Data = switch (mir_tag) { |
| 3104 | .add, |
| 3105 | .adds, |
| 3106 | .sub, |
| 3107 | .subs, |
| 3108 | .@"and", |
| 3109 | .orr, |
| 3110 | .eor, |
| 3111 | => .{ .rr_op = .{ |
| 3112 | .rd = dest_reg, |
| 3113 | .rn = lhs_reg, |
| 3114 | .op = Instruction.Operand.reg(rhs_reg, Instruction.Operand.Shift.none), |
| 3115 | } }, |
| 3116 | .lsl, |
| 3117 | .asr, |
| 3118 | .lsr, |
| 3119 | => .{ .rr_shift = .{ |
| 3120 | .rd = dest_reg, |
| 3121 | .rm = lhs_reg, |
| 3122 | .shift_amount = Instruction.ShiftAmount.reg(rhs_reg), |
| 3123 | } }, |
| 3124 | .mul, |
| 3125 | .smulbb, |
| 3126 | => .{ .rrr = .{ |
| 3127 | .rd = dest_reg, |
| 3128 | .rn = lhs_reg, |
| 3129 | .rm = rhs_reg, |
| 3130 | } }, |
| 3131 | else => unreachable, |
| 3132 | }; |
| 3133 | |
| 3134 | _ = try self.addInst(.{ |
| 3135 | .tag = mir_tag, |
| 3136 | .data = mir_data, |
| 3137 | }); |
| 3138 | |
| 3139 | return MCValue{ .register = dest_reg }; |
| 3140 | } |
| 3141 | |
| 3142 | /// TODO |
| 3143 | fn binOpImmediateNew( |
| 3144 | self: *Self, |
| 3145 | mir_tag: Mir.Inst.Tag, |
| 3146 | lhs_bind: ReadArg.Bind, |
| 3147 | rhs_immediate: u32, |
| 3148 | lhs_ty: Type, |
| 3149 | lhs_and_rhs_swapped: bool, |
| 3150 | maybe_inst: ?Air.Inst.Index, |
| 3151 | ) !MCValue { |
| 3152 | var lhs_reg: Register = undefined; |
| 3153 | var dest_reg: Register = undefined; |
| 3154 | |
| 3155 | const read_args = [_]ReadArg{ |
| 3156 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| 3157 | }; |
| 3158 | const write_args = [_]WriteArg{ |
| 3159 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 3160 | }; |
| 3161 | const operand_mapping: []const Liveness.OperandInt = if (lhs_and_rhs_swapped) &.{1} else &.{0}; |
| 3162 | try self.allocRegs( |
| 3163 | &read_args, |
| 3164 | &write_args, |
| 3165 | if (maybe_inst) |inst| .{ |
| 3166 | .corresponding_inst = inst, |
| 3167 | .operand_mapping = operand_mapping, |
| 3168 | } else null, |
| 3169 | ); |
| 3170 | |
| 3171 | const mir_data: Mir.Inst.Data = switch (mir_tag) { |
| 3172 | .add, |
| 3173 | .adds, |
| 3174 | .sub, |
| 3175 | .subs, |
| 3176 | .@"and", |
| 3177 | .orr, |
| 3178 | .eor, |
| 3179 | => .{ .rr_op = .{ |
| 3180 | .rd = dest_reg, |
| 3181 | .rn = lhs_reg, |
| 3182 | .op = Instruction.Operand.fromU32(rhs_immediate).?, |
| 3183 | } }, |
| 3184 | .lsl, |
| 3185 | .asr, |
| 3186 | .lsr, |
| 3187 | => .{ .rr_shift = .{ |
| 3188 | .rd = dest_reg, |
| 3189 | .rm = lhs_reg, |
| 3190 | .shift_amount = Instruction.ShiftAmount.imm(@intCast(u5, rhs_immediate)), |
| 3191 | } }, |
| 3192 | else => unreachable, |
| 3193 | }; |
| 3194 | |
| 3195 | _ = try self.addInst(.{ |
| 3196 | .tag = mir_tag, |
| 3197 | .data = mir_data, |
| 3198 | }); |
| 3199 | |
| 3200 | return MCValue{ .register = dest_reg }; |
| 3201 | } |
| 3202 | |
| 3060 | 3203 | const BinOpMetadata = struct { |
| 3061 | 3204 | inst: Air.Inst.Index, |
| 3062 | 3205 | lhs: Air.Inst.Ref, |
| ... | ... | @@ -3085,53 +3228,6 @@ fn binOp( |
| 3085 | 3228 | metadata: ?BinOpMetadata, |
| 3086 | 3229 | ) InnerError!MCValue { |
| 3087 | 3230 | switch (tag) { |
| 3088 | | .add, |
| 3089 | | .sub, |
| 3090 | | => { |
| 3091 | | switch (lhs_ty.zigTypeTag()) { |
| 3092 | | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3093 | | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3094 | | .Int => { |
| 3095 | | const mod = self.bin_file.options.module.?; |
| 3096 | | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3097 | | const int_info = lhs_ty.intInfo(self.target.*); |
| 3098 | | if (int_info.bits <= 32) { |
| 3099 | | // Only say yes if the operation is |
| 3100 | | // commutative, i.e. we can swap both of the |
| 3101 | | // operands |
| 3102 | | const lhs_immediate_ok = switch (tag) { |
| 3103 | | .add => lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null, |
| 3104 | | .sub => false, |
| 3105 | | else => unreachable, |
| 3106 | | }; |
| 3107 | | const rhs_immediate_ok = switch (tag) { |
| 3108 | | .add, |
| 3109 | | .sub, |
| 3110 | | => rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null, |
| 3111 | | else => unreachable, |
| 3112 | | }; |
| 3113 | | |
| 3114 | | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 3115 | | .add => .add, |
| 3116 | | .sub => .sub, |
| 3117 | | else => unreachable, |
| 3118 | | }; |
| 3119 | | |
| 3120 | | if (rhs_immediate_ok) { |
| 3121 | | return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata); |
| 3122 | | } else if (lhs_immediate_ok) { |
| 3123 | | // swap lhs and rhs |
| 3124 | | return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata); |
| 3125 | | } else { |
| 3126 | | return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 3127 | | } |
| 3128 | | } else { |
| 3129 | | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 3130 | | } |
| 3131 | | }, |
| 3132 | | else => unreachable, |
| 3133 | | } |
| 3134 | | }, |
| 3135 | 3231 | .mul => { |
| 3136 | 3232 | switch (lhs_ty.zigTypeTag()) { |
| 3137 | 3233 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| ... | ... | @@ -3278,8 +3374,18 @@ fn binOp( |
| 3278 | 3374 | else => unreachable, |
| 3279 | 3375 | }; |
| 3280 | 3376 | |
| 3377 | const lhs_bind = if (metadata) |md| |
| 3378 | ReadArg.Bind{ .inst = md.lhs } |
| 3379 | else |
| 3380 | ReadArg.Bind{ .mcv = lhs }; |
| 3381 | const rhs_bind = if (metadata) |md| |
| 3382 | ReadArg.Bind{ .inst = md.rhs } |
| 3383 | else |
| 3384 | ReadArg.Bind{ .mcv = rhs }; |
| 3385 | |
| 3281 | 3386 | // Generate an add/sub/mul |
| 3282 | | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 3387 | const maybe_inst: ?Air.Inst.Index = if (metadata) |md| md.inst else null; |
| 3388 | const result = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3283 | 3389 | |
| 3284 | 3390 | // Truncate if necessary |
| 3285 | 3391 | switch (lhs_ty.zigTypeTag()) { |
| ... | ... | @@ -3463,6 +3569,63 @@ fn binOp( |
| 3463 | 3569 | } |
| 3464 | 3570 | } |
| 3465 | 3571 | |
| 3572 | fn addSub( |
| 3573 | self: *Self, |
| 3574 | tag: Air.Inst.Tag, |
| 3575 | lhs_bind: ReadArg.Bind, |
| 3576 | rhs_bind: ReadArg.Bind, |
| 3577 | lhs_ty: Type, |
| 3578 | rhs_ty: Type, |
| 3579 | maybe_inst: ?Air.Inst.Index, |
| 3580 | ) InnerError!MCValue { |
| 3581 | switch (lhs_ty.zigTypeTag()) { |
| 3582 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3583 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3584 | .Int => { |
| 3585 | const mod = self.bin_file.options.module.?; |
| 3586 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3587 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3588 | if (int_info.bits <= 32) { |
| 3589 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 3590 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 3591 | |
| 3592 | // Only say yes if the operation is |
| 3593 | // commutative, i.e. we can swap both of the |
| 3594 | // operands |
| 3595 | const lhs_immediate_ok = switch (tag) { |
| 3596 | .add => if (lhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false, |
| 3597 | .sub => false, |
| 3598 | else => unreachable, |
| 3599 | }; |
| 3600 | const rhs_immediate_ok = switch (tag) { |
| 3601 | .add, |
| 3602 | .sub, |
| 3603 | => if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false, |
| 3604 | else => unreachable, |
| 3605 | }; |
| 3606 | |
| 3607 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 3608 | .add => .add, |
| 3609 | .sub => .sub, |
| 3610 | else => unreachable, |
| 3611 | }; |
| 3612 | |
| 3613 | if (rhs_immediate_ok) { |
| 3614 | return try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst); |
| 3615 | } else if (lhs_immediate_ok) { |
| 3616 | // swap lhs and rhs |
| 3617 | return try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst); |
| 3618 | } else { |
| 3619 | return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3620 | } |
| 3621 | } else { |
| 3622 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 3623 | } |
| 3624 | }, |
| 3625 | else => unreachable, |
| 3626 | } |
| 3627 | } |
| 3628 | |
| 3466 | 3629 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void { |
| 3467 | 3630 | const abi_size = ty.abiSize(self.target.*); |
| 3468 | 3631 | |
| ... | ... | @@ -4138,8 +4301,8 @@ fn cmp( |
| 4138 | 4301 | var lhs_reg: Register = undefined; |
| 4139 | 4302 | var rhs_reg: Register = undefined; |
| 4140 | 4303 | |
| 4141 | | const rhs_mcv = try rhs.resolveToMcv(self); |
| 4142 | | const rhs_immediate_ok = rhs_mcv == .immediate and Instruction.Operand.fromU32(rhs_mcv.immediate) != null; |
| 4304 | const rhs_immediate = try rhs.resolveToImmediate(self); |
| 4305 | const rhs_immediate_ok = if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false; |
| 4143 | 4306 | |
| 4144 | 4307 | if (rhs_immediate_ok) { |
| 4145 | 4308 | const read_args = [_]ReadArg{ |
| ... | ... | @@ -4155,7 +4318,7 @@ fn cmp( |
| 4155 | 4318 | .tag = .cmp, |
| 4156 | 4319 | .data = .{ .r_op_cmp = .{ |
| 4157 | 4320 | .rn = lhs_reg, |
| 4158 | | .op = Instruction.Operand.fromU32(rhs_mcv.immediate).?, |
| 4321 | .op = Instruction.Operand.fromU32(rhs_immediate.?).?, |
| 4159 | 4322 | } }, |
| 4160 | 4323 | }); |
| 4161 | 4324 | } else { |