authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-08-21 13:43:09+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-09-09 19:17:17+02:00
loged4be06883427e2d8f97f2dd241d8996994a0c66
treeb2e9b48d583548ab75db7ebe16cd2e9b47706a4e
parent86dd123392c8ab26432303ff2e5c96e73d747757
signature Commit is signed but in an unrecognized format.

stage2 ARM: extract add+sub from binOp

This commit also lays the groundwork for further extractions from binOp.

1 files changed, 246 insertions(+), 83 deletions(-)

src/arch/arm/CodeGen.zig+246-83
...@@ -1401,19 +1401,26 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -1401,19 +1401,26 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
14011401
1402fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {1402fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1403 const bin_op = self.air.instructions.items(.data)[inst].bin_op;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 const lhs_ty = self.air.typeOf(bin_op.lhs);1404 const lhs_ty = self.air.typeOf(bin_op.lhs);
1407 const rhs_ty = self.air.typeOf(bin_op.rhs);1405 const rhs_ty = self.air.typeOf(bin_op.rhs);
14081406
1409 const result: MCValue = if (self.liveness.isUnused(inst))1407 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1410 .dead1408 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
1411 else1409 const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
1412 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{1410 const lhs = try self.resolveInst(bin_op.lhs);
1413 .lhs = bin_op.lhs,1411 const rhs = try self.resolveInst(bin_op.rhs);
1414 .rhs = bin_op.rhs,1412
1415 .inst = inst,1413 switch (tag) {
1416 });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 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1424 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1418}1425}
14191426
...@@ -1459,8 +1466,8 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1459,8 +1466,8 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1459 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1466 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1460 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;1467 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
1461 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1468 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1462 const lhs = try self.resolveInst(extra.lhs);1469 const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs };
1463 const rhs = try self.resolveInst(extra.rhs);1470 const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs };
1464 const lhs_ty = self.air.typeOf(extra.lhs);1471 const lhs_ty = self.air.typeOf(extra.lhs);
1465 const rhs_ty = self.air.typeOf(extra.rhs);1472 const rhs_ty = self.air.typeOf(extra.rhs);
14661473
...@@ -1485,7 +1492,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1485,7 +1492,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1485 .sub_with_overflow => .sub,1492 .sub_with_overflow => .sub,
1486 else => unreachable,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 const dest_reg = dest.register;1496 const dest_reg = dest.register;
1490 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);1497 const dest_reg_lock = self.register_manager.lockRegAssumeUnused(dest_reg);
1491 defer self.register_manager.unlockReg(dest_reg_lock);1498 defer self.register_manager.unlockReg(dest_reg_lock);
...@@ -1511,6 +1518,9 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1511,6 +1518,9 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
15111518
1512 break :result MCValue{ .stack_offset = stack_offset };1519 break :result MCValue{ .stack_offset = stack_offset };
1513 } else if (int_info.bits == 32) {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 // Only say yes if the operation is1524 // Only say yes if the operation is
1515 // commutative, i.e. we can swap both of the1525 // commutative, i.e. we can swap both of the
1516 // operands1526 // operands
...@@ -2600,26 +2610,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -2600,26 +2610,10 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
2600 break :result MCValue{ .ptr_stack_offset = off - struct_field_offset };2610 break :result MCValue{ .ptr_stack_offset = off - struct_field_offset };
2601 },2611 },
2602 else => {2612 else => {
2603 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{2613 const lhs_bind: ReadArg.Bind = .{ .mcv = mcv };
2604 .immediate = struct_field_offset,2614 const rhs_bind: ReadArg.Bind = .{ .mcv = .{ .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);
26122615
2613 const dest = try self.binOp(2616 break :result try self.addSub(.add, lhs_bind, rhs_bind, Type.usize, Type.usize, null);
2614 .add,
2615 .{ .register = addr_reg },
2616 .{ .register = offset_reg },
2617 Type.usize,
2618 Type.usize,
2619 null,
2620 );
2621
2622 break :result dest;
2623 },2617 },
2624 }2618 }
2625 };2619 };
...@@ -2708,6 +2702,25 @@ const ReadArg = struct {...@@ -2708,6 +2702,25 @@ const ReadArg = struct {
2708 .mcv => |mcv| mcv,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};
27132726
...@@ -3057,6 +3070,136 @@ fn binOpImmediate(...@@ -3057,6 +3070,136 @@ fn binOpImmediate(
3057 return MCValue{ .register = dest_reg };3070 return MCValue{ .register = dest_reg };
3058}3071}
30593072
3073/// TODO
3074fn 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
3143fn 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
3060const BinOpMetadata = struct {3203const BinOpMetadata = struct {
3061 inst: Air.Inst.Index,3204 inst: Air.Inst.Index,
3062 lhs: Air.Inst.Ref,3205 lhs: Air.Inst.Ref,
...@@ -3085,53 +3228,6 @@ fn binOp(...@@ -3085,53 +3228,6 @@ fn binOp(
3085 metadata: ?BinOpMetadata,3228 metadata: ?BinOpMetadata,
3086) InnerError!MCValue {3229) InnerError!MCValue {
3087 switch (tag) {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 .mul => {3231 .mul => {
3136 switch (lhs_ty.zigTypeTag()) {3232 switch (lhs_ty.zigTypeTag()) {
3137 .Float => return self.fail("TODO ARM binary operations on floats", .{}),3233 .Float => return self.fail("TODO ARM binary operations on floats", .{}),
...@@ -3278,8 +3374,18 @@ fn binOp(...@@ -3278,8 +3374,18 @@ fn binOp(
3278 else => unreachable,3374 else => unreachable,
3279 };3375 };
32803376
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 // Generate an add/sub/mul3386 // 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);
32833389
3284 // Truncate if necessary3390 // Truncate if necessary
3285 switch (lhs_ty.zigTypeTag()) {3391 switch (lhs_ty.zigTypeTag()) {
...@@ -3463,6 +3569,63 @@ fn binOp(...@@ -3463,6 +3569,63 @@ fn binOp(
3463 }3569 }
3464}3570}
34653571
3572fn 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
3466fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void {3629fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void {
3467 const abi_size = ty.abiSize(self.target.*);3630 const abi_size = ty.abiSize(self.target.*);
34683631
...@@ -4138,8 +4301,8 @@ fn cmp(...@@ -4138,8 +4301,8 @@ fn cmp(
4138 var lhs_reg: Register = undefined;4301 var lhs_reg: Register = undefined;
4139 var rhs_reg: Register = undefined;4302 var rhs_reg: Register = undefined;
41404303
4141 const rhs_mcv = try rhs.resolveToMcv(self);4304 const rhs_immediate = try rhs.resolveToImmediate(self);
4142 const rhs_immediate_ok = rhs_mcv == .immediate and Instruction.Operand.fromU32(rhs_mcv.immediate) != null;4305 const rhs_immediate_ok = if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false;
41434306
4144 if (rhs_immediate_ok) {4307 if (rhs_immediate_ok) {
4145 const read_args = [_]ReadArg{4308 const read_args = [_]ReadArg{
...@@ -4155,7 +4318,7 @@ fn cmp(...@@ -4155,7 +4318,7 @@ fn cmp(
4155 .tag = .cmp,4318 .tag = .cmp,
4156 .data = .{ .r_op_cmp = .{4319 .data = .{ .r_op_cmp = .{
4157 .rn = lhs_reg,4320 .rn = lhs_reg,
4158 .op = Instruction.Operand.fromU32(rhs_mcv.immediate).?,4321 .op = Instruction.Operand.fromU32(rhs_immediate.?).?,
4159 } },4322 } },
4160 });4323 });
4161 } else {4324 } else {