authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-10 09:04:39+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-10 09:04:39+02:00
logaf3ecd04b4377db7104a2d37d462f0f4b3e3db84
treed29259d4bec5c023630e7d2be289c835d129069c
parent252c5a2339820d15bc7a063cdd68cc65b49ed413

x64: make genBinOp operate on MCValues directly


1 files changed, 84 insertions(+), 54 deletions(-)

src/arch/x86_64/CodeGen.zig+84-54
...@@ -1089,8 +1089,15 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -1089,8 +1089,15 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
10891089
1090fn airNot(self: *Self, inst: Air.Inst.Index) !void {1090fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1091 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1091 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1092 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1092
1093 const operand = try self.resolveInst(ty_op.operand);1093 if (self.liveness.isUnused(inst)) {
1094 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
1095 }
1096
1097 const operand_ty = self.air.typeOf(ty_op.operand);
1098 const operand = try self.resolveInst(ty_op.operand);
1099
1100 const result: MCValue = result: {
1094 switch (operand) {1101 switch (operand) {
1095 .dead => unreachable,1102 .dead => unreachable,
1096 .unreach => unreachable,1103 .unreach => unreachable,
...@@ -1122,7 +1129,28 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {...@@ -1122,7 +1129,28 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
1122 },1129 },
1123 else => {},1130 else => {},
1124 }1131 }
1125 break :result try self.genBinOp(.not, inst, ty_op.operand, .bool_true);1132
1133 const operand_lock: ?RegisterLock = switch (operand) {
1134 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1135 else => null,
1136 };
1137 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
1138
1139 const dst_mcv: MCValue = blk: {
1140 if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand.isRegister()) {
1141 break :blk operand;
1142 }
1143 break :blk try self.copyToRegisterWithInstTracking(inst, operand_ty, operand);
1144 };
1145 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
1146 .register => |reg| self.register_manager.lockReg(reg),
1147 else => null,
1148 };
1149 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
1150
1151 try self.genBinOpMir(.xor, operand_ty, dst_mcv, .{ .immediate = 1 });
1152
1153 break :result dst_mcv;
1126 };1154 };
1127 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1155 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1128}1156}
...@@ -1214,7 +1242,13 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -1214,7 +1242,13 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
1214 }1242 }
12151243
1216 const tag = self.air.instructions.items(.tag)[inst];1244 const tag = self.air.instructions.items(.tag)[inst];
1217 const result = try self.genBinOp(tag, inst, bin_op.lhs, bin_op.rhs);1245 const lhs = try self.resolveInst(bin_op.lhs);
1246 const rhs = try self.resolveInst(bin_op.rhs);
1247 const lhs_ty = self.air.typeOf(bin_op.lhs);
1248 const rhs_ty = self.air.typeOf(bin_op.rhs);
1249
1250 const result = try self.genBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
1251
1218 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1252 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1219}1253}
12201254
...@@ -1263,7 +1297,10 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1263,7 +1297,10 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1263 try self.spillCompareFlagsIfOccupied();1297 try self.spillCompareFlagsIfOccupied();
1264 self.compare_flags_inst = inst;1298 self.compare_flags_inst = inst;
12651299
1266 const partial = try self.genBinOp(.add, inst, bin_op.lhs, bin_op.rhs);1300 const lhs = try self.resolveInst(bin_op.lhs);
1301 const rhs = try self.resolveInst(bin_op.rhs);
1302
1303 const partial = try self.genBinOp(.add, null, lhs, rhs, ty, ty);
1267 const result: MCValue = switch (int_info.signedness) {1304 const result: MCValue = switch (int_info.signedness) {
1268 .signed => .{ .register_overflow_signed = partial.register },1305 .signed => .{ .register_overflow_signed = partial.register },
1269 .unsigned => .{ .register_overflow_unsigned = partial.register },1306 .unsigned => .{ .register_overflow_unsigned = partial.register },
...@@ -1295,7 +1332,10 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1295,7 +1332,10 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1295 try self.spillCompareFlagsIfOccupied();1332 try self.spillCompareFlagsIfOccupied();
1296 self.compare_flags_inst = inst;1333 self.compare_flags_inst = inst;
12971334
1298 const partial = try self.genBinOp(.sub, inst, bin_op.lhs, bin_op.rhs);1335 const lhs = try self.resolveInst(bin_op.lhs);
1336 const rhs = try self.resolveInst(bin_op.rhs);
1337
1338 const partial = try self.genBinOp(.sub, null, lhs, rhs, ty, ty);
1299 const result: MCValue = switch (int_info.signedness) {1339 const result: MCValue = switch (int_info.signedness) {
1300 .signed => .{ .register_overflow_signed = partial.register },1340 .signed => .{ .register_overflow_signed = partial.register },
1301 .unsigned => .{ .register_overflow_unsigned = partial.register },1341 .unsigned => .{ .register_overflow_unsigned = partial.register },
...@@ -1330,9 +1370,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1330,9 +1370,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
13301370
1331 try self.spillCompareFlagsIfOccupied();1371 try self.spillCompareFlagsIfOccupied();
13321372
1373 const lhs = try self.resolveInst(bin_op.lhs);
1374 const rhs = try self.resolveInst(bin_op.rhs);
1375
1333 if (math.isPowerOfTwo(int_info.bits)) {1376 if (math.isPowerOfTwo(int_info.bits)) {
1334 self.compare_flags_inst = inst;1377 self.compare_flags_inst = inst;
1335 const partial = try self.genBinOp(.mul, inst, bin_op.lhs, bin_op.rhs);1378 const partial = try self.genBinOp(.mul, null, lhs, rhs, ty, ty);
1336 break :result switch (int_info.signedness) {1379 break :result switch (int_info.signedness) {
1337 .signed => MCValue{ .register_overflow_signed = partial.register },1380 .signed => MCValue{ .register_overflow_signed = partial.register },
1338 .unsigned => MCValue{ .register_overflow_unsigned = partial.register },1381 .unsigned => MCValue{ .register_overflow_unsigned = partial.register },
...@@ -1344,9 +1387,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1344,9 +1387,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1344 const dst_reg: Register = dst_reg: {1387 const dst_reg: Register = dst_reg: {
1345 switch (int_info.signedness) {1388 switch (int_info.signedness) {
1346 .signed => {1389 .signed => {
1347 const lhs = try self.resolveInst(bin_op.lhs);
1348 const rhs = try self.resolveInst(bin_op.rhs);
1349
1350 const rhs_lock: ?RegisterLock = switch (rhs) {1390 const rhs_lock: ?RegisterLock = switch (rhs) {
1351 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),1391 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1352 else => null,1392 else => null,
...@@ -1375,7 +1415,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1375,7 +1415,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1375 break :dst_reg dst_reg;1415 break :dst_reg dst_reg;
1376 },1416 },
1377 .unsigned => {1417 .unsigned => {
1378 const dst_mcv = try self.genBinOp(.mul, null, bin_op.lhs, bin_op.rhs);1418 const dst_mcv = try self.genBinOp(.mul, null, lhs, rhs, ty, ty);
1379 break :dst_reg dst_mcv.register;1419 break :dst_reg dst_mcv.register;
1380 },1420 },
1381 }1421 }
...@@ -3137,8 +3177,10 @@ fn genBinOp(...@@ -3137,8 +3177,10 @@ fn genBinOp(
3137 self: *Self,3177 self: *Self,
3138 tag: Air.Inst.Tag,3178 tag: Air.Inst.Tag,
3139 maybe_inst: ?Air.Inst.Index,3179 maybe_inst: ?Air.Inst.Index,
3140 op_lhs: Air.Inst.Ref,3180 lhs: MCValue,
3141 op_rhs: Air.Inst.Ref,3181 rhs: MCValue,
3182 lhs_ty: Type,
3183 rhs_ty: Type,
3142) !MCValue {3184) !MCValue {
3143 const is_commutative: bool = switch (tag) {3185 const is_commutative: bool = switch (tag) {
3144 .add,3186 .add,
...@@ -3148,7 +3190,6 @@ fn genBinOp(...@@ -3148,7 +3190,6 @@ fn genBinOp(
3148 .bool_and,3190 .bool_and,
3149 .bit_and,3191 .bit_and,
3150 .xor,3192 .xor,
3151 .not,
3152 => true,3193 => true,
31533194
3154 .sub,3195 .sub,
...@@ -3169,14 +3210,12 @@ fn genBinOp(...@@ -3169,14 +3210,12 @@ fn genBinOp(
31693210
3170 else => unreachable,3211 else => unreachable,
3171 };3212 };
3172 const dst_ty = self.air.typeOf(op_lhs);
3173 const src_ty = self.air.typeOf(op_rhs);
31743213
3175 if (dst_ty.zigTypeTag() == .Vector or dst_ty.zigTypeTag() == .Float) {3214 if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {
3176 return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()});3215 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
3177 }3216 }
3178 if (dst_ty.abiSize(self.target.*) > 8) {3217 if (lhs_ty.abiSize(self.target.*) > 8) {
3179 return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()});3218 return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
3180 }3219 }
31813220
3182 switch (tag) {3221 switch (tag) {
...@@ -3191,24 +3230,21 @@ fn genBinOp(...@@ -3191,24 +3230,21 @@ fn genBinOp(
3191 self.register_manager.unlockReg(reg);3230 self.register_manager.unlockReg(reg);
3192 };3231 };
31933232
3194 const lhs = try self.resolveInst(op_lhs);3233 const int_info = lhs_ty.intInfo(self.target.*);
3195 const rhs = try self.resolveInst(op_rhs);
3196
3197 const int_info = dst_ty.intInfo(self.target.*);
3198 try self.genIntMulDivOpMir(switch (int_info.signedness) {3234 try self.genIntMulDivOpMir(switch (int_info.signedness) {
3199 .signed => .imul,3235 .signed => .imul,
3200 .unsigned => .mul,3236 .unsigned => .mul,
3201 }, dst_ty, int_info.signedness, lhs, rhs);3237 }, lhs_ty, int_info.signedness, lhs, rhs);
32023238
3203 return switch (int_info.signedness) {3239 return switch (int_info.signedness) {
3204 .signed => MCValue{ .register = .rax },3240 .signed => MCValue{ .register = .rax },
3205 .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, dst_ty.abiSize(self.target.*))) },3241 .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, lhs_ty.abiSize(self.target.*))) },
3206 };3242 };
3207 },3243 },
3208 .mod,3244 .mod,
3209 .rem,3245 .rem,
3210 => {3246 => {
3211 const int_info = dst_ty.intInfo(self.target.*);3247 const int_info = lhs_ty.intInfo(self.target.*);
3212 const track_inst_rdx: ?Air.Inst.Index = switch (tag) {3248 const track_inst_rdx: ?Air.Inst.Index = switch (tag) {
3213 .mod => if (int_info.signedness == .unsigned) maybe_inst else null,3249 .mod => if (int_info.signedness == .unsigned) maybe_inst else null,
3214 .rem => maybe_inst,3250 .rem => maybe_inst,
...@@ -3223,27 +3259,24 @@ fn genBinOp(...@@ -3223,27 +3259,24 @@ fn genBinOp(
3223 self.register_manager.unlockReg(reg);3259 self.register_manager.unlockReg(reg);
3224 };3260 };
32253261
3226 const lhs = try self.resolveInst(op_lhs);
3227 const rhs = try self.resolveInst(op_rhs);
3228
3229 switch (int_info.signedness) {3262 switch (int_info.signedness) {
3230 .signed => {3263 .signed => {
3231 switch (tag) {3264 switch (tag) {
3232 .rem => {3265 .rem => {
3233 try self.genIntMulDivOpMir(.idiv, dst_ty, .signed, lhs, rhs);3266 try self.genIntMulDivOpMir(.idiv, lhs_ty, .signed, lhs, rhs);
3234 return MCValue{ .register = .rdx };3267 return MCValue{ .register = .rdx };
3235 },3268 },
3236 .mod => {3269 .mod => {
3237 const div_floor = try self.genInlineIntDivFloor(dst_ty, lhs, rhs);3270 const div_floor = try self.genInlineIntDivFloor(lhs_ty, lhs, rhs);
3238 try self.genIntMulComplexOpMir(dst_ty, div_floor, rhs);3271 try self.genIntMulComplexOpMir(lhs_ty, div_floor, rhs);
3239 const div_floor_lock = self.register_manager.lockReg(div_floor.register);3272 const div_floor_lock = self.register_manager.lockReg(div_floor.register);
3240 defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock);3273 defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock);
32413274
3242 const result: MCValue = if (maybe_inst) |inst|3275 const result: MCValue = if (maybe_inst) |inst|
3243 try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs)3276 try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs)
3244 else3277 else
3245 MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) };3278 MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };
3246 try self.genBinOpMir(.sub, dst_ty, result, div_floor);3279 try self.genBinOpMir(.sub, lhs_ty, result, div_floor);
32473280
3248 return result;3281 return result;
3249 },3282 },
...@@ -3251,7 +3284,7 @@ fn genBinOp(...@@ -3251,7 +3284,7 @@ fn genBinOp(
3251 }3284 }
3252 },3285 },
3253 .unsigned => {3286 .unsigned => {
3254 try self.genIntMulDivOpMir(.div, dst_ty, .unsigned, lhs, rhs);3287 try self.genIntMulDivOpMir(.div, lhs_ty, .unsigned, lhs, rhs);
3255 return MCValue{ .register = .rdx };3288 return MCValue{ .register = .rdx };
3256 },3289 },
3257 }3290 }
...@@ -3259,14 +3292,12 @@ fn genBinOp(...@@ -3259,14 +3292,12 @@ fn genBinOp(
3259 else => {},3292 else => {},
3260 }3293 }
32613294
3262 const lhs = try self.resolveInst(op_lhs);
3263 const lhs_lock: ?RegisterLock = switch (lhs) {3295 const lhs_lock: ?RegisterLock = switch (lhs) {
3264 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),3296 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
3265 else => null,3297 else => null,
3266 };3298 };
3267 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);3299 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
32683300
3269 const rhs = try self.resolveInst(op_rhs);
3270 const rhs_lock: ?RegisterLock = switch (rhs) {3301 const rhs_lock: ?RegisterLock = switch (rhs) {
3271 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),3302 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
3272 else => null,3303 else => null,
...@@ -3276,16 +3307,17 @@ fn genBinOp(...@@ -3276,16 +3307,17 @@ fn genBinOp(
3276 var flipped: bool = false;3307 var flipped: bool = false;
3277 const dst_mcv: MCValue = blk: {3308 const dst_mcv: MCValue = blk: {
3278 if (maybe_inst) |inst| {3309 if (maybe_inst) |inst| {
3279 if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) {3310 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3311 if (self.reuseOperand(inst, bin_op.lhs, 0, lhs) and lhs.isRegister()) {
3280 break :blk lhs;3312 break :blk lhs;
3281 }3313 }
3282 if (is_commutative and self.reuseOperand(inst, op_rhs, 1, rhs) and rhs.isRegister()) {3314 if (is_commutative and self.reuseOperand(inst, bin_op.rhs, 1, rhs) and rhs.isRegister()) {
3283 flipped = true;3315 flipped = true;
3284 break :blk rhs;3316 break :blk rhs;
3285 }3317 }
3286 break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs);3318 break :blk try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs);
3287 }3319 }
3288 break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) };3320 break :blk MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };
3289 };3321 };
3290 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {3322 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
3291 .register => |reg| self.register_manager.lockReg(reg),3323 .register => |reg| self.register_manager.lockReg(reg),
...@@ -3296,7 +3328,7 @@ fn genBinOp(...@@ -3296,7 +3328,7 @@ fn genBinOp(
3296 const src_mcv: MCValue = blk: {3328 const src_mcv: MCValue = blk: {
3297 const mcv = if (flipped) lhs else rhs;3329 const mcv = if (flipped) lhs else rhs;
3298 if (mcv.isRegister() or mcv.isMemory()) break :blk mcv;3330 if (mcv.isRegister() or mcv.isMemory()) break :blk mcv;
3299 break :blk MCValue{ .register = try self.copyToTmpRegister(src_ty, mcv) };3331 break :blk MCValue{ .register = try self.copyToTmpRegister(rhs_ty, mcv) };
3300 };3332 };
3301 const src_mcv_lock: ?RegisterLock = switch (src_mcv) {3333 const src_mcv_lock: ?RegisterLock = switch (src_mcv) {
3302 .register => |reg| self.register_manager.lockReg(reg),3334 .register => |reg| self.register_manager.lockReg(reg),
...@@ -3307,11 +3339,11 @@ fn genBinOp(...@@ -3307,11 +3339,11 @@ fn genBinOp(
3307 switch (tag) {3339 switch (tag) {
3308 .add,3340 .add,
3309 .addwrap,3341 .addwrap,
3310 => try self.genBinOpMir(.add, dst_ty, dst_mcv, src_mcv),3342 => try self.genBinOpMir(.add, lhs_ty, dst_mcv, src_mcv),
33113343
3312 .sub,3344 .sub,
3313 .subwrap,3345 .subwrap,
3314 => try self.genBinOpMir(.sub, dst_ty, dst_mcv, src_mcv),3346 => try self.genBinOpMir(.sub, lhs_ty, dst_mcv, src_mcv),
33153347
3316 .ptr_add,3348 .ptr_add,
3317 .ptr_sub,3349 .ptr_sub,
...@@ -3321,22 +3353,20 @@ fn genBinOp(...@@ -3321,22 +3353,20 @@ fn genBinOp(
3321 .ptr_sub => .sub,3353 .ptr_sub => .sub,
3322 else => unreachable,3354 else => unreachable,
3323 };3355 };
3324 const elem_size = dst_ty.elemType2().abiSize(self.target.*);3356 const elem_size = lhs_ty.elemType2().abiSize(self.target.*);
3325 try self.genIntMulComplexOpMir(src_ty, src_mcv, .{ .immediate = elem_size });3357 try self.genIntMulComplexOpMir(rhs_ty, src_mcv, .{ .immediate = elem_size });
3326 try self.genBinOpMir(mir_tag, dst_ty, dst_mcv, src_mcv);3358 try self.genBinOpMir(mir_tag, lhs_ty, dst_mcv, src_mcv);
3327 },3359 },
33283360
3329 .bool_or,3361 .bool_or,
3330 .bit_or,3362 .bit_or,
3331 => try self.genBinOpMir(.@"or", dst_ty, dst_mcv, src_mcv),3363 => try self.genBinOpMir(.@"or", lhs_ty, dst_mcv, src_mcv),
33323364
3333 .bool_and,3365 .bool_and,
3334 .bit_and,3366 .bit_and,
3335 => try self.genBinOpMir(.@"and", dst_ty, dst_mcv, src_mcv),3367 => try self.genBinOpMir(.@"and", lhs_ty, dst_mcv, src_mcv),
33363368
3337 .xor,3369 .xor => try self.genBinOpMir(.xor, lhs_ty, dst_mcv, src_mcv),
3338 .not,
3339 => try self.genBinOpMir(.xor, dst_ty, dst_mcv, src_mcv),
33403370
3341 else => unreachable,3371 else => unreachable,
3342 }3372 }