| ... | ... | @@ -1410,16 +1410,29 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1410 | 1410 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1411 | 1411 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1412 | 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{ |
| 1413 | break :result switch (tag) { |
| 1414 | .add => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1415 | .sub => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1416 | |
| 1417 | .mul => try self.mul(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1418 | |
| 1419 | .div_float => try self.divFloat(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1420 | |
| 1421 | .div_trunc => try self.div(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1422 | .div_floor => try self.div(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1423 | |
| 1424 | .div_exact => try self.divExact(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1425 | |
| 1426 | .rem => try self.rem(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1427 | |
| 1428 | .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1429 | |
| 1430 | else => try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ |
| 1418 | 1431 | .lhs = bin_op.lhs, |
| 1419 | 1432 | .rhs = bin_op.rhs, |
| 1420 | 1433 | .inst = inst, |
| 1421 | 1434 | }), |
| 1422 | | } |
| 1435 | }; |
| 1423 | 1436 | }; |
| 1424 | 1437 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1425 | 1438 | } |
| ... | ... | @@ -3228,141 +3241,6 @@ fn binOp( |
| 3228 | 3241 | metadata: ?BinOpMetadata, |
| 3229 | 3242 | ) InnerError!MCValue { |
| 3230 | 3243 | switch (tag) { |
| 3231 | | .mul => { |
| 3232 | | switch (lhs_ty.zigTypeTag()) { |
| 3233 | | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3234 | | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3235 | | .Int => { |
| 3236 | | const mod = self.bin_file.options.module.?; |
| 3237 | | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3238 | | const int_info = lhs_ty.intInfo(self.target.*); |
| 3239 | | if (int_info.bits <= 32) { |
| 3240 | | // TODO add optimisations for multiplication |
| 3241 | | // with immediates, for example a * 2 can be |
| 3242 | | // lowered to a << 1 |
| 3243 | | return try self.binOpRegister(.mul, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 3244 | | } else { |
| 3245 | | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 3246 | | } |
| 3247 | | }, |
| 3248 | | else => unreachable, |
| 3249 | | } |
| 3250 | | }, |
| 3251 | | .div_float => { |
| 3252 | | switch (lhs_ty.zigTypeTag()) { |
| 3253 | | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3254 | | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3255 | | else => unreachable, |
| 3256 | | } |
| 3257 | | }, |
| 3258 | | .div_trunc, .div_floor => { |
| 3259 | | switch (lhs_ty.zigTypeTag()) { |
| 3260 | | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3261 | | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3262 | | .Int => { |
| 3263 | | const mod = self.bin_file.options.module.?; |
| 3264 | | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3265 | | const int_info = lhs_ty.intInfo(self.target.*); |
| 3266 | | if (int_info.bits <= 32) { |
| 3267 | | switch (int_info.signedness) { |
| 3268 | | .signed => { |
| 3269 | | return self.fail("TODO ARM signed integer division", .{}); |
| 3270 | | }, |
| 3271 | | .unsigned => { |
| 3272 | | switch (rhs) { |
| 3273 | | .immediate => |imm| { |
| 3274 | | if (std.math.isPowerOfTwo(imm)) { |
| 3275 | | const shift = MCValue{ .immediate = std.math.log2_int(u32, imm) }; |
| 3276 | | return try self.binOp(.shr, lhs, shift, lhs_ty, rhs_ty, metadata); |
| 3277 | | } else { |
| 3278 | | return self.fail("TODO ARM integer division by constants", .{}); |
| 3279 | | } |
| 3280 | | }, |
| 3281 | | else => return self.fail("TODO ARM integer division", .{}), |
| 3282 | | } |
| 3283 | | }, |
| 3284 | | } |
| 3285 | | } else { |
| 3286 | | return self.fail("TODO ARM integer division for integers > u32/i32", .{}); |
| 3287 | | } |
| 3288 | | }, |
| 3289 | | else => unreachable, |
| 3290 | | } |
| 3291 | | }, |
| 3292 | | .div_exact => { |
| 3293 | | switch (lhs_ty.zigTypeTag()) { |
| 3294 | | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3295 | | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3296 | | .Int => return self.fail("TODO ARM div_exact", .{}), |
| 3297 | | else => unreachable, |
| 3298 | | } |
| 3299 | | }, |
| 3300 | | .rem => { |
| 3301 | | switch (lhs_ty.zigTypeTag()) { |
| 3302 | | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3303 | | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3304 | | .Int => { |
| 3305 | | const mod = self.bin_file.options.module.?; |
| 3306 | | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3307 | | const int_info = lhs_ty.intInfo(self.target.*); |
| 3308 | | if (int_info.bits <= 32) { |
| 3309 | | switch (int_info.signedness) { |
| 3310 | | .signed => { |
| 3311 | | return self.fail("TODO ARM signed integer mod", .{}); |
| 3312 | | }, |
| 3313 | | .unsigned => { |
| 3314 | | switch (rhs) { |
| 3315 | | .immediate => |imm| { |
| 3316 | | if (std.math.isPowerOfTwo(imm)) { |
| 3317 | | const log2 = std.math.log2_int(u32, imm); |
| 3318 | | |
| 3319 | | var lhs_reg: Register = undefined; |
| 3320 | | var dest_reg: Register = undefined; |
| 3321 | | |
| 3322 | | const lhs_bind = if (metadata) |md| |
| 3323 | | ReadArg.Bind{ .inst = md.lhs } |
| 3324 | | else |
| 3325 | | ReadArg.Bind{ .mcv = lhs }; |
| 3326 | | const read_args = [_]ReadArg{ |
| 3327 | | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| 3328 | | }; |
| 3329 | | const write_args = [_]WriteArg{ |
| 3330 | | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 3331 | | }; |
| 3332 | | try self.allocRegs( |
| 3333 | | &read_args, |
| 3334 | | &write_args, |
| 3335 | | if (metadata) |md| .{ |
| 3336 | | .corresponding_inst = md.inst, |
| 3337 | | .operand_mapping = &.{0}, |
| 3338 | | } else null, |
| 3339 | | ); |
| 3340 | | |
| 3341 | | try self.truncRegister(lhs_reg, dest_reg, int_info.signedness, log2); |
| 3342 | | return MCValue{ .register = dest_reg }; |
| 3343 | | } else { |
| 3344 | | return self.fail("TODO ARM integer mod by constants", .{}); |
| 3345 | | } |
| 3346 | | }, |
| 3347 | | else => return self.fail("TODO ARM integer mod", .{}), |
| 3348 | | } |
| 3349 | | }, |
| 3350 | | } |
| 3351 | | } else { |
| 3352 | | return self.fail("TODO ARM integer division for integers > u32/i32", .{}); |
| 3353 | | } |
| 3354 | | }, |
| 3355 | | else => unreachable, |
| 3356 | | } |
| 3357 | | }, |
| 3358 | | .mod => { |
| 3359 | | switch (lhs_ty.zigTypeTag()) { |
| 3360 | | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3361 | | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3362 | | .Int => return self.fail("TODO ARM mod", .{}), |
| 3363 | | else => unreachable, |
| 3364 | | } |
| 3365 | | }, |
| 3366 | 3244 | .addwrap, |
| 3367 | 3245 | .subwrap, |
| 3368 | 3246 | .mulwrap, |
| ... | ... | @@ -3557,7 +3435,13 @@ fn binOp( |
| 3557 | 3435 | } else { |
| 3558 | 3436 | // convert the offset into a byte offset by |
| 3559 | 3437 | // multiplying it with elem_size |
| 3560 | | const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null); |
| 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); |
| 3561 | 3445 | const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null); |
| 3562 | 3446 | return addr; |
| 3563 | 3447 | } |
| ... | ... | @@ -3626,6 +3510,209 @@ fn addSub( |
| 3626 | 3510 | } |
| 3627 | 3511 | } |
| 3628 | 3512 | |
| 3513 | fn mul( |
| 3514 | self: *Self, |
| 3515 | lhs_bind: ReadArg.Bind, |
| 3516 | rhs_bind: ReadArg.Bind, |
| 3517 | lhs_ty: Type, |
| 3518 | rhs_ty: Type, |
| 3519 | maybe_inst: ?Air.Inst.Index, |
| 3520 | ) InnerError!MCValue { |
| 3521 | switch (lhs_ty.zigTypeTag()) { |
| 3522 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3523 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3524 | .Int => { |
| 3525 | const mod = self.bin_file.options.module.?; |
| 3526 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3527 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3528 | if (int_info.bits <= 32) { |
| 3529 | // TODO add optimisations for multiplication |
| 3530 | // with immediates, for example a * 2 can be |
| 3531 | // lowered to a << 1 |
| 3532 | return try self.binOpRegisterNew(.mul, lhs_bind, rhs_bind, lhs_ty, rhs_ty, maybe_inst); |
| 3533 | } else { |
| 3534 | return self.fail("TODO ARM binary operations on integers > u32/i32", .{}); |
| 3535 | } |
| 3536 | }, |
| 3537 | else => unreachable, |
| 3538 | } |
| 3539 | } |
| 3540 | |
| 3541 | fn divFloat( |
| 3542 | self: *Self, |
| 3543 | lhs_bind: ReadArg.Bind, |
| 3544 | rhs_bind: ReadArg.Bind, |
| 3545 | lhs_ty: Type, |
| 3546 | rhs_ty: Type, |
| 3547 | maybe_inst: ?Air.Inst.Index, |
| 3548 | ) InnerError!MCValue { |
| 3549 | _ = lhs_bind; |
| 3550 | _ = rhs_bind; |
| 3551 | _ = lhs_ty; |
| 3552 | _ = rhs_ty; |
| 3553 | _ = maybe_inst; |
| 3554 | |
| 3555 | switch (lhs_ty.zigTypeTag()) { |
| 3556 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3557 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3558 | else => unreachable, |
| 3559 | } |
| 3560 | } |
| 3561 | |
| 3562 | fn div( |
| 3563 | self: *Self, |
| 3564 | tag: Air.Inst.Tag, |
| 3565 | lhs_bind: ReadArg.Bind, |
| 3566 | rhs_bind: ReadArg.Bind, |
| 3567 | lhs_ty: Type, |
| 3568 | rhs_ty: Type, |
| 3569 | maybe_inst: ?Air.Inst.Index, |
| 3570 | ) InnerError!MCValue { |
| 3571 | _ = tag; |
| 3572 | |
| 3573 | switch (lhs_ty.zigTypeTag()) { |
| 3574 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3575 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3576 | .Int => { |
| 3577 | const mod = self.bin_file.options.module.?; |
| 3578 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3579 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3580 | if (int_info.bits <= 32) { |
| 3581 | switch (int_info.signedness) { |
| 3582 | .signed => { |
| 3583 | return self.fail("TODO ARM signed integer division", .{}); |
| 3584 | }, |
| 3585 | .unsigned => { |
| 3586 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 3587 | |
| 3588 | if (rhs_immediate) |imm| { |
| 3589 | if (std.math.isPowerOfTwo(imm)) { |
| 3590 | const shift = std.math.log2_int(u32, imm); |
| 3591 | return try self.binOpImmediateNew(.lsr, lhs_bind, shift, lhs_ty, false, maybe_inst); |
| 3592 | } else { |
| 3593 | return self.fail("TODO ARM integer division by constants", .{}); |
| 3594 | } |
| 3595 | } else { |
| 3596 | return self.fail("TODO ARM integer division", .{}); |
| 3597 | } |
| 3598 | }, |
| 3599 | } |
| 3600 | } else { |
| 3601 | return self.fail("TODO ARM integer division for integers > u32/i32", .{}); |
| 3602 | } |
| 3603 | }, |
| 3604 | else => unreachable, |
| 3605 | } |
| 3606 | } |
| 3607 | |
| 3608 | fn divExact( |
| 3609 | self: *Self, |
| 3610 | lhs_bind: ReadArg.Bind, |
| 3611 | rhs_bind: ReadArg.Bind, |
| 3612 | lhs_ty: Type, |
| 3613 | rhs_ty: Type, |
| 3614 | maybe_inst: ?Air.Inst.Index, |
| 3615 | ) InnerError!MCValue { |
| 3616 | _ = lhs_bind; |
| 3617 | _ = rhs_bind; |
| 3618 | _ = lhs_ty; |
| 3619 | _ = rhs_ty; |
| 3620 | _ = maybe_inst; |
| 3621 | |
| 3622 | switch (lhs_ty.zigTypeTag()) { |
| 3623 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3624 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3625 | .Int => return self.fail("TODO ARM div_exact", .{}), |
| 3626 | else => unreachable, |
| 3627 | } |
| 3628 | } |
| 3629 | |
| 3630 | fn rem( |
| 3631 | self: *Self, |
| 3632 | lhs_bind: ReadArg.Bind, |
| 3633 | rhs_bind: ReadArg.Bind, |
| 3634 | lhs_ty: Type, |
| 3635 | rhs_ty: Type, |
| 3636 | maybe_inst: ?Air.Inst.Index, |
| 3637 | ) InnerError!MCValue { |
| 3638 | switch (lhs_ty.zigTypeTag()) { |
| 3639 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3640 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3641 | .Int => { |
| 3642 | const mod = self.bin_file.options.module.?; |
| 3643 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3644 | const int_info = lhs_ty.intInfo(self.target.*); |
| 3645 | if (int_info.bits <= 32) { |
| 3646 | switch (int_info.signedness) { |
| 3647 | .signed => { |
| 3648 | return self.fail("TODO ARM signed integer mod", .{}); |
| 3649 | }, |
| 3650 | .unsigned => { |
| 3651 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 3652 | |
| 3653 | if (rhs_immediate) |imm| { |
| 3654 | if (std.math.isPowerOfTwo(imm)) { |
| 3655 | const log2 = std.math.log2_int(u32, imm); |
| 3656 | |
| 3657 | var lhs_reg: Register = undefined; |
| 3658 | var dest_reg: Register = undefined; |
| 3659 | |
| 3660 | const read_args = [_]ReadArg{ |
| 3661 | .{ .ty = lhs_ty, .bind = lhs_bind, .class = gp, .reg = &lhs_reg }, |
| 3662 | }; |
| 3663 | const write_args = [_]WriteArg{ |
| 3664 | .{ .ty = lhs_ty, .bind = .none, .class = gp, .reg = &dest_reg }, |
| 3665 | }; |
| 3666 | try self.allocRegs( |
| 3667 | &read_args, |
| 3668 | &write_args, |
| 3669 | if (maybe_inst) |inst| .{ |
| 3670 | .corresponding_inst = inst, |
| 3671 | .operand_mapping = &.{0}, |
| 3672 | } else null, |
| 3673 | ); |
| 3674 | |
| 3675 | try self.truncRegister(lhs_reg, dest_reg, int_info.signedness, log2); |
| 3676 | |
| 3677 | return MCValue{ .register = dest_reg }; |
| 3678 | } else { |
| 3679 | return self.fail("TODO ARM integer mod by constants", .{}); |
| 3680 | } |
| 3681 | } else { |
| 3682 | return self.fail("TODO ARM integer mod", .{}); |
| 3683 | } |
| 3684 | }, |
| 3685 | } |
| 3686 | } else { |
| 3687 | return self.fail("TODO ARM integer division for integers > u32/i32", .{}); |
| 3688 | } |
| 3689 | }, |
| 3690 | else => unreachable, |
| 3691 | } |
| 3692 | } |
| 3693 | |
| 3694 | fn modulo( |
| 3695 | self: *Self, |
| 3696 | lhs_bind: ReadArg.Bind, |
| 3697 | rhs_bind: ReadArg.Bind, |
| 3698 | lhs_ty: Type, |
| 3699 | rhs_ty: Type, |
| 3700 | maybe_inst: ?Air.Inst.Index, |
| 3701 | ) InnerError!MCValue { |
| 3702 | _ = lhs_bind; |
| 3703 | _ = rhs_bind; |
| 3704 | _ = lhs_ty; |
| 3705 | _ = rhs_ty; |
| 3706 | _ = maybe_inst; |
| 3707 | |
| 3708 | switch (lhs_ty.zigTypeTag()) { |
| 3709 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3710 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3711 | .Int => return self.fail("TODO ARM mod", .{}), |
| 3712 | else => unreachable, |
| 3713 | } |
| 3714 | } |
| 3715 | |
| 3629 | 3716 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void { |
| 3630 | 3717 | const abi_size = ty.abiSize(self.target.*); |
| 3631 | 3718 | |