| ... | @@ -1410,16 +1410,29 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | ... | @@ -1410,16 +1410,29 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1410 | const lhs = try self.resolveInst(bin_op.lhs); | 1410 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1411 | const rhs = try self.resolveInst(bin_op.rhs); | 1411 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1412 | | 1412 | |
| 1413 | switch (tag) { | 1413 | break :result switch (tag) { |
| 1414 | .add, | 1414 | .add => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1415 | .sub, | 1415 | .sub => try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1416 | => break :result try self.addSub(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), | 1416 | |
| 1417 | else => break :result try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ | 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 | .lhs = bin_op.lhs, | 1431 | .lhs = bin_op.lhs, |
| 1419 | .rhs = bin_op.rhs, | 1432 | .rhs = bin_op.rhs, |
| 1420 | .inst = inst, | 1433 | .inst = inst, |
| 1421 | }), | 1434 | }), |
| 1422 | } | 1435 | }; |
| 1423 | }; | 1436 | }; |
| 1424 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1437 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1425 | } | 1438 | } |
| ... | @@ -3228,141 +3241,6 @@ fn binOp( | ... | @@ -3228,141 +3241,6 @@ fn binOp( |
| 3228 | metadata: ?BinOpMetadata, | 3241 | metadata: ?BinOpMetadata, |
| 3229 | ) InnerError!MCValue { | 3242 | ) InnerError!MCValue { |
| 3230 | switch (tag) { | 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 | .addwrap, | 3244 | .addwrap, |
| 3367 | .subwrap, | 3245 | .subwrap, |
| 3368 | .mulwrap, | 3246 | .mulwrap, |
| ... | @@ -3557,7 +3435,13 @@ fn binOp( | ... | @@ -3557,7 +3435,13 @@ fn binOp( |
| 3557 | } else { | 3435 | } else { |
| 3558 | // convert the offset into a byte offset by | 3436 | // convert the offset into a byte offset by |
| 3559 | // multiplying it with elem_size | 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 | const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null); | 3445 | const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null); |
| 3562 | return addr; | 3446 | return addr; |
| 3563 | } | 3447 | } |
| ... | @@ -3626,6 +3510,209 @@ fn addSub( | ... | @@ -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 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void { | 3716 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void { |
| 3630 | const abi_size = ty.abiSize(self.target.*); | 3717 | const abi_size = ty.abiSize(self.target.*); |
| 3631 | | 3718 | |