| ... | @@ -3131,75 +3131,82 @@ fn genMulDivBinOp( | ... | @@ -3131,75 +3131,82 @@ fn genMulDivBinOp( |
| 3131 | switch (tag) { | 3131 | switch (tag) { |
| 3132 | .mul, | 3132 | .mul, |
| 3133 | .mulwrap, | 3133 | .mulwrap, |
| 3134 | => { | | |
| 3135 | try self.register_manager.getReg(.rax, maybe_inst); | | |
| 3136 | try self.register_manager.getReg(.rdx, null); | | |
| 3137 | | | |
| 3138 | try self.genIntMulDivOpMir(switch (signedness) { | | |
| 3139 | .signed => .imul, | | |
| 3140 | .unsigned => .mul, | | |
| 3141 | }, ty, signedness, lhs, rhs); | | |
| 3142 | | | |
| 3143 | return switch (signedness) { | | |
| 3144 | .signed => MCValue{ .register = .rax }, | | |
| 3145 | .unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))) }, | | |
| 3146 | }; | | |
| 3147 | }, | | |
| 3148 | .mod, | | |
| 3149 | .rem, | 3134 | .rem, |
| | 3135 | .div_trunc, |
| | 3136 | .div_exact, |
| 3150 | => { | 3137 | => { |
| | 3138 | const track_inst_rax: ?Air.Inst.Index = switch (tag) { |
| | 3139 | .mul, .mulwrap, .div_exact, .div_trunc => maybe_inst, |
| | 3140 | else => null, |
| | 3141 | }; |
| 3151 | const track_inst_rdx: ?Air.Inst.Index = switch (tag) { | 3142 | const track_inst_rdx: ?Air.Inst.Index = switch (tag) { |
| 3152 | .mod => if (signedness == .unsigned) maybe_inst else null, | | |
| 3153 | .rem => maybe_inst, | 3143 | .rem => maybe_inst, |
| 3154 | else => unreachable, | 3144 | else => null, |
| 3155 | }; | 3145 | }; |
| | 3146 | try self.register_manager.getReg(.rax, track_inst_rax); |
| | 3147 | try self.register_manager.getReg(.rdx, track_inst_rdx); |
| | 3148 | |
| | 3149 | const mir_tag: Mir.Inst.Tag = switch (signedness) { |
| | 3150 | .signed => switch (tag) { |
| | 3151 | .mul, .mulwrap => Mir.Inst.Tag.imul, |
| | 3152 | .div_trunc, .div_exact, .rem => Mir.Inst.Tag.idiv, |
| | 3153 | else => unreachable, |
| | 3154 | }, |
| | 3155 | .unsigned => switch (tag) { |
| | 3156 | .mul, .mulwrap => Mir.Inst.Tag.mul, |
| | 3157 | .div_trunc, .div_exact, .rem => Mir.Inst.Tag.div, |
| | 3158 | else => unreachable, |
| | 3159 | }, |
| | 3160 | }; |
| | 3161 | |
| | 3162 | try self.genIntMulDivOpMir(mir_tag, ty, .signed, lhs, rhs); |
| | 3163 | |
| | 3164 | switch (signedness) { |
| | 3165 | .signed => switch (tag) { |
| | 3166 | .mul, .mulwrap, .div_trunc, .div_exact => return MCValue{ .register = .rax }, |
| | 3167 | .rem => return MCValue{ .register = .rdx }, |
| | 3168 | else => unreachable, |
| | 3169 | }, |
| | 3170 | .unsigned => switch (tag) { |
| | 3171 | .mul, .mulwrap, .div_trunc, .div_exact => return MCValue{ |
| | 3172 | .register = registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))), |
| | 3173 | }, |
| | 3174 | .rem => return MCValue{ |
| | 3175 | .register = registerAlias(.rdx, @intCast(u32, ty.abiSize(self.target.*))), |
| | 3176 | }, |
| | 3177 | else => unreachable, |
| | 3178 | }, |
| | 3179 | } |
| | 3180 | }, |
| 3156 | | 3181 | |
| | 3182 | .mod => { |
| 3157 | try self.register_manager.getReg(.rax, null); | 3183 | try self.register_manager.getReg(.rax, null); |
| 3158 | try self.register_manager.getReg(.rdx, track_inst_rdx); | 3184 | try self.register_manager.getReg(.rdx, if (signedness == .unsigned) maybe_inst else null); |
| 3159 | | 3185 | |
| 3160 | switch (signedness) { | 3186 | switch (signedness) { |
| 3161 | .signed => { | 3187 | .signed => { |
| 3162 | switch (tag) { | 3188 | const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs); |
| 3163 | .rem => { | 3189 | try self.genIntMulComplexOpMir(ty, div_floor, rhs); |
| 3164 | try self.genIntMulDivOpMir(.idiv, ty, .signed, lhs, rhs); | 3190 | const div_floor_lock = self.register_manager.lockReg(div_floor.register); |
| 3165 | return MCValue{ .register = .rdx }; | 3191 | defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock); |
| 3166 | }, | 3192 | |
| 3167 | .mod => { | 3193 | const result: MCValue = if (maybe_inst) |inst| |
| 3168 | const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs); | 3194 | try self.copyToRegisterWithInstTracking(inst, ty, lhs) |
| 3169 | try self.genIntMulComplexOpMir(ty, div_floor, rhs); | 3195 | else |
| 3170 | const div_floor_lock = self.register_manager.lockReg(div_floor.register); | 3196 | MCValue{ .register = try self.copyToTmpRegister(ty, lhs) }; |
| 3171 | defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock); | 3197 | try self.genBinOpMir(.sub, ty, result, div_floor); |
| 3172 | | 3198 | |
| 3173 | const result: MCValue = if (maybe_inst) |inst| | 3199 | return result; |
| 3174 | try self.copyToRegisterWithInstTracking(inst, ty, lhs) | | |
| 3175 | else | | |
| 3176 | MCValue{ .register = try self.copyToTmpRegister(ty, lhs) }; | | |
| 3177 | try self.genBinOpMir(.sub, ty, result, div_floor); | | |
| 3178 | | | |
| 3179 | return result; | | |
| 3180 | }, | | |
| 3181 | else => unreachable, | | |
| 3182 | } | | |
| 3183 | }, | 3200 | }, |
| 3184 | .unsigned => { | 3201 | .unsigned => { |
| 3185 | try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs); | 3202 | try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs); |
| 3186 | return MCValue{ .register = .rdx }; | 3203 | return MCValue{ .register = registerAlias(.rdx, @intCast(u32, ty.abiSize(self.target.*))) }; |
| 3187 | }, | 3204 | }, |
| 3188 | } | 3205 | } |
| 3189 | }, | 3206 | }, |
| 3190 | .div_trunc, | | |
| 3191 | .div_floor, | | |
| 3192 | .div_exact, | | |
| 3193 | => { | | |
| 3194 | const track_inst_rax: ?Air.Inst.Index = blk: { | | |
| 3195 | if (signedness == .unsigned) break :blk maybe_inst; | | |
| 3196 | switch (tag) { | | |
| 3197 | .div_exact, .div_trunc => break :blk maybe_inst, | | |
| 3198 | else => break :blk null, | | |
| 3199 | } | | |
| 3200 | }; | | |
| 3201 | | 3207 | |
| 3202 | try self.register_manager.getReg(.rax, track_inst_rax); | 3208 | .div_floor => { |
| | 3209 | try self.register_manager.getReg(.rax, if (signedness == .unsigned) maybe_inst else null); |
| 3203 | try self.register_manager.getReg(.rdx, null); | 3210 | try self.register_manager.getReg(.rdx, null); |
| 3204 | | 3211 | |
| 3205 | const lhs_lock: ?RegisterLock = switch (lhs) { | 3212 | const lhs_lock: ?RegisterLock = switch (lhs) { |
| ... | @@ -3209,24 +3216,21 @@ fn genMulDivBinOp( | ... | @@ -3209,24 +3216,21 @@ fn genMulDivBinOp( |
| 3209 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 3216 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3210 | | 3217 | |
| 3211 | const actual_rhs: MCValue = blk: { | 3218 | const actual_rhs: MCValue = blk: { |
| 3212 | if (signedness == .signed) { | 3219 | switch (signedness) { |
| 3213 | switch (tag) { | 3220 | .signed => { |
| 3214 | .div_floor => { | 3221 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 3215 | const rhs_lock: ?RegisterLock = switch (rhs) { | 3222 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 3216 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 3223 | else => null, |
| 3217 | else => null, | 3224 | }; |
| 3218 | }; | 3225 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3219 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 3220 | | 3226 | |
| 3221 | if (maybe_inst) |inst| { | 3227 | if (maybe_inst) |inst| { |
| 3222 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); | 3228 | break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs); |
| 3223 | } | 3229 | } |
| 3224 | break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) }; | 3230 | break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) }; |
| 3225 | }, | 3231 | }, |
| 3226 | else => {}, | 3232 | .unsigned => break :blk rhs, |
| 3227 | } | | |
| 3228 | } | 3233 | } |
| 3229 | break :blk rhs; | | |
| 3230 | }; | 3234 | }; |
| 3231 | const rhs_lock: ?RegisterLock = switch (actual_rhs) { | 3235 | const rhs_lock: ?RegisterLock = switch (actual_rhs) { |
| 3232 | .register => |reg| self.register_manager.lockReg(reg), | 3236 | .register => |reg| self.register_manager.lockReg(reg), |
| ... | @@ -3235,27 +3239,19 @@ fn genMulDivBinOp( | ... | @@ -3235,27 +3239,19 @@ fn genMulDivBinOp( |
| 3235 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 3239 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 3236 | | 3240 | |
| 3237 | const result: MCValue = result: { | 3241 | const result: MCValue = result: { |
| 3238 | if (signedness == .unsigned) { | 3242 | switch (signedness) { |
| 3239 | try self.genIntMulDivOpMir(.div, ty, signedness, lhs, actual_rhs); | 3243 | .signed => break :result try self.genInlineIntDivFloor(ty, lhs, actual_rhs), |
| 3240 | break :result MCValue{ .register = .rax }; | 3244 | .unsigned => { |
| 3241 | } | 3245 | try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, actual_rhs); |
| 3242 | | 3246 | break :result MCValue{ |
| 3243 | switch (tag) { | 3247 | .register = registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))), |
| 3244 | .div_exact, .div_trunc => { | 3248 | }; |
| 3245 | try self.genIntMulDivOpMir(switch (signedness) { | | |
| 3246 | .signed => .idiv, | | |
| 3247 | .unsigned => .div, | | |
| 3248 | }, ty, signedness, lhs, actual_rhs); | | |
| 3249 | break :result MCValue{ .register = .rax }; | | |
| 3250 | }, | | |
| 3251 | .div_floor => { | | |
| 3252 | break :result try self.genInlineIntDivFloor(ty, lhs, actual_rhs); | | |
| 3253 | }, | 3249 | }, |
| 3254 | else => unreachable, | | |
| 3255 | } | 3250 | } |
| 3256 | }; | 3251 | }; |
| 3257 | return result; | 3252 | return result; |
| 3258 | }, | 3253 | }, |
| | 3254 | |
| 3259 | else => unreachable, | 3255 | else => unreachable, |
| 3260 | } | 3256 | } |
| 3261 | } | 3257 | } |