authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-08-25 22:17:57+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-09-09 19:17:17+02:00
log95b8a5f157aa7552e3f125e56968b889e254497a
treef29fabd00fbcff48169a36ce243b5ea0e09987aa
parentfdb2c80bdc12bfb6be5235de6a5792e0b0619da8
signaturelock-open Commit is signed but in an unrecognized format.

stage2 ARM: extract remaining operations out of binOp


1 files changed, 282 insertions(+), 259 deletions(-)

src/arch/arm/CodeGen.zig+282-259
...@@ -1407,8 +1407,6 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -1407,8 +1407,6 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1407 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1407 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1408 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };1408 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
1409 const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };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);
14121410
1413 break :result switch (tag) {1411 break :result switch (tag) {
1414 .add => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),1412 .add => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
...@@ -1427,11 +1425,24 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -1427,11 +1425,24 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
14271425
1428 .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),1426 .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
14291427
1430 else => try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{1428 .addwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1431 .lhs = bin_op.lhs,1429 .subwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1432 .rhs = bin_op.rhs,1430 .mulwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1433 .inst = inst,1431
1434 }),1432 .bit_and => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1433 .bit_or => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1434 .xor => try self.bitwise(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1435
1436 .shl_exact => try self.shiftExact(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1437 .shr_exact => try self.shiftExact(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1438
1439 .shl => try self.shiftNormal(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1440 .shr => try self.shiftNormal(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1441
1442 .bool_and => try self.booleanOp(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1443 .bool_or => try self.booleanOp(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst),
1444
1445 else => unreachable,
1435 };1446 };
1436 };1447 };
1437 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1448 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
...@@ -1440,19 +1451,15 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -1440,19 +1451,15 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1440fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {1451fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
1441 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1452 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1442 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;1453 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
1443 const lhs = try self.resolveInst(bin_op.lhs);
1444 const rhs = try self.resolveInst(bin_op.rhs);
1445 const lhs_ty = self.air.typeOf(bin_op.lhs);1454 const lhs_ty = self.air.typeOf(bin_op.lhs);
1446 const rhs_ty = self.air.typeOf(bin_op.rhs);1455 const rhs_ty = self.air.typeOf(bin_op.rhs);
14471456
1448 const result: MCValue = if (self.liveness.isUnused(inst))1457 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1449 .dead1458 const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs };
1450 else1459 const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs };
1451 try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{1460
1452 .lhs = bin_op.lhs,1461 break :result try self.ptrArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst);
1453 .rhs = bin_op.rhs,1462 };
1454 .inst = inst,
1455 });
1456 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1463 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1457}1464}
14581465
...@@ -2247,7 +2254,11 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2247,7 +2254,11 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2247 },2254 },
2248 else => {2255 else => {
2249 const dest = try self.allocRegOrMem(inst, true);2256 const dest = try self.allocRegOrMem(inst, true);
2250 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);2257
2258 const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };
2259 const index_bind: ReadArg.Bind = .{ .mcv = index_mcv };
2260
2261 const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ptr_field_type, Type.usize, null);
2251 try self.load(dest, addr, slice_ptr_field_type);2262 try self.load(dest, addr, slice_ptr_field_type);
22522263
2253 break :result dest;2264 break :result dest;
...@@ -2262,12 +2273,15 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2262,12 +2273,15 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2262 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;2273 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2263 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2274 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2264 const slice_mcv = try self.resolveInst(extra.lhs);2275 const slice_mcv = try self.resolveInst(extra.lhs);
2265 const index_mcv = try self.resolveInst(extra.rhs);
2266 const base_mcv = slicePtr(slice_mcv);2276 const base_mcv = slicePtr(slice_mcv);
22672277
2278 const base_bind: ReadArg.Bind = .{ .mcv = base_mcv };
2279 const index_bind: ReadArg.Bind = .{ .inst = extra.rhs };
2280
2268 const slice_ty = self.air.typeOf(extra.lhs);2281 const slice_ty = self.air.typeOf(extra.lhs);
2282 const index_ty = self.air.typeOf(extra.rhs);
22692283
2270 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ty, Type.usize, null);2284 const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ty, index_ty, null);
2271 break :result addr;2285 break :result addr;
2272 };2286 };
2273 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2287 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
...@@ -2290,12 +2304,13 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2290,12 +2304,13 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2290 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2304 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2291 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;2305 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2292 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2306 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2293 const ptr_mcv = try self.resolveInst(extra.lhs);2307 const ptr_bind: ReadArg.Bind = .{ .inst = extra.lhs };
2294 const index_mcv = try self.resolveInst(extra.rhs);2308 const index_bind: ReadArg.Bind = .{ .inst = extra.rhs };
22952309
2296 const ptr_ty = self.air.typeOf(extra.lhs);2310 const ptr_ty = self.air.typeOf(extra.lhs);
2311 const index_ty = self.air.typeOf(extra.rhs);
22972312
2298 const addr = try self.binOp(.ptr_add, ptr_mcv, index_mcv, ptr_ty, Type.usize, null);2313 const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, index_ty, null);
2299 break :result addr;2314 break :result addr;
2300 };2315 };
2301 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2316 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
...@@ -3219,240 +3234,6 @@ const BinOpMetadata = struct {...@@ -3219,240 +3234,6 @@ const BinOpMetadata = struct {
3219 rhs: Air.Inst.Ref,3234 rhs: Air.Inst.Ref,
3220};3235};
32213236
3222/// For all your binary operation needs, this function will generate
3223/// the corresponding Mir instruction(s). Returns the location of the
3224/// result.
3225///
3226/// If the binary operation itself happens to be an Air instruction,
3227/// pass the corresponding index in the inst parameter. That helps
3228/// this function do stuff like reusing operands.
3229///
3230/// This function does not do any lowering to Mir itself, but instead
3231/// looks at the lhs and rhs and determines which kind of lowering
3232/// would be best suitable and then delegates the lowering to other
3233/// functions.
3234fn binOp(
3235 self: *Self,
3236 tag: Air.Inst.Tag,
3237 lhs: MCValue,
3238 rhs: MCValue,
3239 lhs_ty: Type,
3240 rhs_ty: Type,
3241 metadata: ?BinOpMetadata,
3242) InnerError!MCValue {
3243 switch (tag) {
3244 .addwrap,
3245 .subwrap,
3246 .mulwrap,
3247 => {
3248 const base_tag: Air.Inst.Tag = switch (tag) {
3249 .addwrap => .add,
3250 .subwrap => .sub,
3251 .mulwrap => .mul,
3252 else => unreachable,
3253 };
3254
3255 const lhs_bind = if (metadata) |md|
3256 ReadArg.Bind{ .inst = md.lhs }
3257 else
3258 ReadArg.Bind{ .mcv = lhs };
3259 const rhs_bind = if (metadata) |md|
3260 ReadArg.Bind{ .inst = md.rhs }
3261 else
3262 ReadArg.Bind{ .mcv = rhs };
3263
3264 // Generate an add/sub/mul
3265 const maybe_inst: ?Air.Inst.Index = if (metadata) |md| md.inst else null;
3266 const result = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3267
3268 // Truncate if necessary
3269 switch (lhs_ty.zigTypeTag()) {
3270 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3271 .Int => {
3272 const int_info = lhs_ty.intInfo(self.target.*);
3273 if (int_info.bits <= 32) {
3274 const result_reg = result.register;
3275
3276 if (int_info.bits < 32) {
3277 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
3278 return result;
3279 } else return result;
3280 } else {
3281 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3282 }
3283 },
3284 else => unreachable,
3285 }
3286 },
3287 .bit_and,
3288 .bit_or,
3289 .xor,
3290 => {
3291 switch (lhs_ty.zigTypeTag()) {
3292 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3293 .Int => {
3294 const mod = self.bin_file.options.module.?;
3295 assert(lhs_ty.eql(rhs_ty, mod));
3296 const int_info = lhs_ty.intInfo(self.target.*);
3297 if (int_info.bits <= 32) {
3298 const lhs_immediate_ok = lhs == .immediate and Instruction.Operand.fromU32(lhs.immediate) != null;
3299 const rhs_immediate_ok = rhs == .immediate and Instruction.Operand.fromU32(rhs.immediate) != null;
3300
3301 const mir_tag: Mir.Inst.Tag = switch (tag) {
3302 .bit_and => .@"and",
3303 .bit_or => .orr,
3304 .xor => .eor,
3305 else => unreachable,
3306 };
3307
3308 if (rhs_immediate_ok) {
3309 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
3310 } else if (lhs_immediate_ok) {
3311 // swap lhs and rhs
3312 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
3313 } else {
3314 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3315 }
3316 } else {
3317 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3318 }
3319 },
3320 else => unreachable,
3321 }
3322 },
3323 .shl_exact,
3324 .shr_exact,
3325 => {
3326 switch (lhs_ty.zigTypeTag()) {
3327 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3328 .Int => {
3329 const int_info = lhs_ty.intInfo(self.target.*);
3330 if (int_info.bits <= 32) {
3331 const rhs_immediate_ok = rhs == .immediate;
3332
3333 const mir_tag: Mir.Inst.Tag = switch (tag) {
3334 .shl_exact => .lsl,
3335 .shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) {
3336 .signed => Mir.Inst.Tag.asr,
3337 .unsigned => Mir.Inst.Tag.lsr,
3338 },
3339 else => unreachable,
3340 };
3341
3342 if (rhs_immediate_ok) {
3343 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
3344 } else {
3345 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3346 }
3347 } else {
3348 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3349 }
3350 },
3351 else => unreachable,
3352 }
3353 },
3354 .shl,
3355 .shr,
3356 => {
3357 const base_tag: Air.Inst.Tag = switch (tag) {
3358 .shl => .shl_exact,
3359 .shr => .shr_exact,
3360 else => unreachable,
3361 };
3362
3363 // Generate a shl_exact/shr_exact
3364 const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3365
3366 // Truncate if necessary
3367 switch (tag) {
3368 .shr => return result,
3369 .shl => switch (lhs_ty.zigTypeTag()) {
3370 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3371 .Int => {
3372 const int_info = lhs_ty.intInfo(self.target.*);
3373 if (int_info.bits <= 32) {
3374 const result_reg = result.register;
3375
3376 if (int_info.bits < 32) {
3377 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
3378 return result;
3379 } else return result;
3380 } else {
3381 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3382 }
3383 },
3384 else => unreachable,
3385 },
3386 else => unreachable,
3387 }
3388 },
3389 .bool_and,
3390 .bool_or,
3391 => {
3392 switch (lhs_ty.zigTypeTag()) {
3393 .Bool => {
3394 const lhs_immediate_ok = lhs == .immediate;
3395 const rhs_immediate_ok = rhs == .immediate;
3396
3397 const mir_tag: Mir.Inst.Tag = switch (tag) {
3398 .bool_and => .@"and",
3399 .bool_or => .orr,
3400 else => unreachable,
3401 };
3402
3403 if (rhs_immediate_ok) {
3404 return try self.binOpImmediate(mir_tag, lhs, rhs, lhs_ty, false, metadata);
3405 } else if (lhs_immediate_ok) {
3406 // swap lhs and rhs
3407 return try self.binOpImmediate(mir_tag, rhs, lhs, rhs_ty, true, metadata);
3408 } else {
3409 return try self.binOpRegister(mir_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3410 }
3411 },
3412 else => unreachable,
3413 }
3414 },
3415 .ptr_add,
3416 .ptr_sub,
3417 => {
3418 switch (lhs_ty.zigTypeTag()) {
3419 .Pointer => {
3420 const ptr_ty = lhs_ty;
3421 const elem_ty = switch (ptr_ty.ptrSize()) {
3422 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
3423 else => ptr_ty.childType(),
3424 };
3425 const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
3426
3427 if (elem_size == 1) {
3428 const base_tag: Mir.Inst.Tag = switch (tag) {
3429 .ptr_add => .add,
3430 .ptr_sub => .sub,
3431 else => unreachable,
3432 };
3433
3434 return try self.binOpRegister(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata);
3435 } else {
3436 // convert the offset into a byte offset by
3437 // multiplying it with elem_size
3438 const rhs_bind = if (metadata) |md|
3439 ReadArg.Bind{ .inst = md.rhs }
3440 else
3441 ReadArg.Bind{ .mcv = rhs };
3442 const imm_bind = ReadArg.Bind{ .mcv = .{ .immediate = elem_size } };
3443
3444 const offset = try self.mul(rhs_bind, imm_bind, Type.usize, Type.usize, null);
3445 const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null);
3446 return addr;
3447 }
3448 },
3449 else => unreachable,
3450 }
3451 },
3452 else => unreachable,
3453 }
3454}
3455
3456fn addSub(3237fn addSub(
3457 self: *Self,3238 self: *Self,
3458 tag: Air.Inst.Tag,3239 tag: Air.Inst.Tag,
...@@ -3713,6 +3494,248 @@ fn modulo(...@@ -3713,6 +3494,248 @@ fn modulo(
3713 }3494 }
3714}3495}
37153496
3497fn wrappingArithmetic(
3498 self: *Self,
3499 tag: Air.Inst.Tag,
3500 lhs_bind: ReadArg.Bind,
3501 rhs_bind: ReadArg.Bind,
3502 lhs_ty: Type,
3503 rhs_ty: Type,
3504 maybe_inst: ?Air.Inst.Index,
3505) InnerError!MCValue {
3506 const base_tag: Air.Inst.Tag = switch (tag) {
3507 .addwrap => .add,
3508 .subwrap => .sub,
3509 .mulwrap => .mul,
3510 else => unreachable,
3511 };
3512
3513 // Generate an add/sub/mul
3514 const result = try self.addSub(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3515
3516 // Truncate if necessary
3517 switch (lhs_ty.zigTypeTag()) {
3518 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3519 .Int => {
3520 const int_info = lhs_ty.intInfo(self.target.*);
3521 if (int_info.bits <= 32) {
3522 const result_reg = result.register;
3523
3524 if (int_info.bits < 32) {
3525 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
3526 return result;
3527 } else return result;
3528 } else {
3529 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3530 }
3531 },
3532 else => unreachable,
3533 }
3534}
3535
3536fn bitwise(
3537 self: *Self,
3538 tag: Air.Inst.Tag,
3539 lhs_bind: ReadArg.Bind,
3540 rhs_bind: ReadArg.Bind,
3541 lhs_ty: Type,
3542 rhs_ty: Type,
3543 maybe_inst: ?Air.Inst.Index,
3544) InnerError!MCValue {
3545 switch (lhs_ty.zigTypeTag()) {
3546 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3547 .Int => {
3548 const mod = self.bin_file.options.module.?;
3549 assert(lhs_ty.eql(rhs_ty, mod));
3550 const int_info = lhs_ty.intInfo(self.target.*);
3551 if (int_info.bits <= 32) {
3552 const lhs_immediate = try lhs_bind.resolveToImmediate(self);
3553 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
3554
3555 const lhs_immediate_ok = if (lhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false;
3556 const rhs_immediate_ok = if (rhs_immediate) |imm| Instruction.Operand.fromU32(imm) != null else false;
3557
3558 const mir_tag: Mir.Inst.Tag = switch (tag) {
3559 .bit_and => .@"and",
3560 .bit_or => .orr,
3561 .xor => .eor,
3562 else => unreachable,
3563 };
3564
3565 if (rhs_immediate_ok) {
3566 return try self.binOpImmediateNew(mir_tag, lhs_bind, rhs_immediate.?, lhs_ty, false, maybe_inst);
3567 } else if (lhs_immediate_ok) {
3568 // swap lhs and rhs
3569 return try self.binOpImmediateNew(mir_tag, rhs_bind, lhs_immediate.?, rhs_ty, true, maybe_inst);
3570 } else {
3571 return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3572 }
3573 } else {
3574 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3575 }
3576 },
3577 else => unreachable,
3578 }
3579}
3580
3581fn shiftExact(
3582 self: *Self,
3583 tag: Air.Inst.Tag,
3584 lhs_bind: ReadArg.Bind,
3585 rhs_bind: ReadArg.Bind,
3586 lhs_ty: Type,
3587 rhs_ty: Type,
3588 maybe_inst: ?Air.Inst.Index,
3589) InnerError!MCValue {
3590 switch (lhs_ty.zigTypeTag()) {
3591 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3592 .Int => {
3593 const int_info = lhs_ty.intInfo(self.target.*);
3594 if (int_info.bits <= 32) {
3595 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
3596
3597 const mir_tag: Mir.Inst.Tag = switch (tag) {
3598 .shl_exact => .lsl,
3599 .shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) {
3600 .signed => Mir.Inst.Tag.asr,
3601 .unsigned => Mir.Inst.Tag.lsr,
3602 },
3603 else => unreachable,
3604 };
3605
3606 if (rhs_immediate) |imm| {
3607 return try self.binOpImmediateNew(mir_tag, lhs_bind, imm, lhs_ty, false, maybe_inst);
3608 } else {
3609 return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3610 }
3611 } else {
3612 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3613 }
3614 },
3615 else => unreachable,
3616 }
3617}
3618
3619fn shiftNormal(
3620 self: *Self,
3621 tag: Air.Inst.Tag,
3622 lhs_bind: ReadArg.Bind,
3623 rhs_bind: ReadArg.Bind,
3624 lhs_ty: Type,
3625 rhs_ty: Type,
3626 maybe_inst: ?Air.Inst.Index,
3627) InnerError!MCValue {
3628 const base_tag: Air.Inst.Tag = switch (tag) {
3629 .shl => .shl_exact,
3630 .shr => .shr_exact,
3631 else => unreachable,
3632 };
3633
3634 // Generate a shl_exact/shr_exact
3635 const result = try self.shiftExact(base_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3636
3637 // Truncate if necessary
3638 switch (tag) {
3639 .shr => return result,
3640 .shl => switch (lhs_ty.zigTypeTag()) {
3641 .Vector => return self.fail("TODO ARM binary operations on vectors", .{}),
3642 .Int => {
3643 const int_info = lhs_ty.intInfo(self.target.*);
3644 if (int_info.bits <= 32) {
3645 const result_reg = result.register;
3646
3647 if (int_info.bits < 32) {
3648 try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits);
3649 return result;
3650 } else return result;
3651 } else {
3652 return self.fail("TODO ARM binary operations on integers > u32/i32", .{});
3653 }
3654 },
3655 else => unreachable,
3656 },
3657 else => unreachable,
3658 }
3659}
3660
3661fn booleanOp(
3662 self: *Self,
3663 tag: Air.Inst.Tag,
3664 lhs_bind: ReadArg.Bind,
3665 rhs_bind: ReadArg.Bind,
3666 lhs_ty: Type,
3667 rhs_ty: Type,
3668 maybe_inst: ?Air.Inst.Index,
3669) InnerError!MCValue {
3670 switch (lhs_ty.zigTypeTag()) {
3671 .Bool => {
3672 const lhs_immediate = try lhs_bind.resolveToImmediate(self);
3673 const rhs_immediate = try rhs_bind.resolveToImmediate(self);
3674
3675 const mir_tag: Mir.Inst.Tag = switch (tag) {
3676 .bool_and => .@"and",
3677 .bool_or => .orr,
3678 else => unreachable,
3679 };
3680
3681 if (rhs_immediate) |imm| {
3682 return try self.binOpImmediateNew(mir_tag, lhs_bind, imm, lhs_ty, false, maybe_inst);
3683 } else if (lhs_immediate) |imm| {
3684 // swap lhs and rhs
3685 return try self.binOpImmediateNew(mir_tag, rhs_bind, imm, rhs_ty, true, maybe_inst);
3686 } else {
3687 return try self.binOpRegisterNew(mir_tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst);
3688 }
3689 },
3690 else => unreachable,
3691 }
3692}
3693
3694fn ptrArithmetic(
3695 self: *Self,
3696 tag: Air.Inst.Tag,
3697 lhs_bind: ReadArg.Bind,
3698 rhs_bind: ReadArg.Bind,
3699 lhs_ty: Type,
3700 rhs_ty: Type,
3701 maybe_inst: ?Air.Inst.Index,
3702) InnerError!MCValue {
3703 switch (lhs_ty.zigTypeTag()) {
3704 .Pointer => {
3705 const mod = self.bin_file.options.module.?;
3706 assert(rhs_ty.eql(Type.usize, mod));
3707
3708 const ptr_ty = lhs_ty;
3709 const elem_ty = switch (ptr_ty.ptrSize()) {
3710 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
3711 else => ptr_ty.childType(),
3712 };
3713 const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
3714
3715 const base_tag: Air.Inst.Tag = switch (tag) {
3716 .ptr_add => .add,
3717 .ptr_sub => .sub,
3718 else => unreachable,
3719 };
3720
3721 if (elem_size == 1) {
3722 return try self.addSub(base_tag, lhs_bind, rhs_bind, Type.usize, Type.usize, maybe_inst);
3723 } else {
3724 // convert the offset into a byte offset by
3725 // multiplying it with elem_size
3726 const imm_bind = ReadArg.Bind{ .mcv = .{ .immediate = elem_size } };
3727
3728 const offset = try self.mul(rhs_bind, imm_bind, Type.usize, Type.usize, null);
3729 const offset_bind = ReadArg.Bind{ .mcv = offset };
3730
3731 const addr = try self.addSub(base_tag, lhs_bind, offset_bind, Type.usize, Type.usize, null);
3732 return addr;
3733 }
3734 },
3735 else => unreachable,
3736 }
3737}
3738
3716fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void {3739fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void {
3717 const abi_size = ty.abiSize(self.target.*);3740 const abi_size = ty.abiSize(self.target.*);
37183741
...@@ -4614,7 +4637,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4614,7 +4637,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4614 if (else_value == .dead)4637 if (else_value == .dead)
4615 continue;4638 continue;
4616 // The instruction is only overridden in the else branch.4639 // The instruction is only overridden in the else branch.
4617 var i: usize = self.branch_stack.items.len - 2;4640 var i: usize = self.branch_stack.items.len - 1;
4618 while (true) {4641 while (true) {
4619 i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead?4642 i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead?
4620 if (self.branch_stack.items[i].inst_table.get(else_key)) |mcv| {4643 if (self.branch_stack.items[i].inst_table.get(else_key)) |mcv| {
...@@ -4641,7 +4664,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -4641,7 +4664,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
4641 if (then_value == .dead)4664 if (then_value == .dead)
4642 continue;4665 continue;
4643 const parent_mcv = blk: {4666 const parent_mcv = blk: {
4644 var i: usize = self.branch_stack.items.len - 2;4667 var i: usize = self.branch_stack.items.len - 1;
4645 while (true) {4668 while (true) {
4646 i -= 1;4669 i -= 1;
4647 if (self.branch_stack.items[i].inst_table.get(then_key)) |mcv| {4670 if (self.branch_stack.items[i].inst_table.get(then_key)) |mcv| {