| ... | ... | @@ -1407,8 +1407,6 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1407 | 1407 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1408 | 1408 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 1409 | 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); |
| 1412 | 1410 | |
| 1413 | 1411 | break :result switch (tag) { |
| 1414 | 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 | 1425 | |
| 1428 | 1426 | .mod => try self.modulo(lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1429 | 1427 | |
| 1430 | | else => try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ |
| 1431 | | .lhs = bin_op.lhs, |
| 1432 | | .rhs = bin_op.rhs, |
| 1433 | | .inst = inst, |
| 1434 | | }), |
| 1428 | .addwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1429 | .subwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1430 | .mulwrap => try self.wrappingArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst), |
| 1431 | |
| 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 | 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 | 1451 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1441 | 1452 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1442 | 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 | 1454 | const lhs_ty = self.air.typeOf(bin_op.lhs); |
| 1446 | 1455 | const rhs_ty = self.air.typeOf(bin_op.rhs); |
| 1447 | 1456 | |
| 1448 | | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1449 | | .dead |
| 1450 | | else |
| 1451 | | try self.binOp(tag, lhs, rhs, lhs_ty, rhs_ty, BinOpMetadata{ |
| 1452 | | .lhs = bin_op.lhs, |
| 1453 | | .rhs = bin_op.rhs, |
| 1454 | | .inst = inst, |
| 1455 | | }); |
| 1457 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1458 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 1459 | const rhs_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; |
| 1460 | |
| 1461 | break :result try self.ptrArithmetic(tag, lhs_bind, rhs_bind, lhs_ty, rhs_ty, inst); |
| 1462 | }; |
| 1456 | 1463 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1457 | 1464 | } |
| 1458 | 1465 | |
| ... | ... | @@ -2247,7 +2254,11 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2247 | 2254 | }, |
| 2248 | 2255 | else => { |
| 2249 | 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 | 2262 | try self.load(dest, addr, slice_ptr_field_type); |
| 2252 | 2263 | |
| 2253 | 2264 | break :result dest; |
| ... | ... | @@ -2262,12 +2273,15 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2262 | 2273 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2263 | 2274 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2264 | 2275 | const slice_mcv = try self.resolveInst(extra.lhs); |
| 2265 | | const index_mcv = try self.resolveInst(extra.rhs); |
| 2266 | 2276 | const base_mcv = slicePtr(slice_mcv); |
| 2267 | 2277 | |
| 2278 | const base_bind: ReadArg.Bind = .{ .mcv = base_mcv }; |
| 2279 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2280 | |
| 2268 | 2281 | const slice_ty = self.air.typeOf(extra.lhs); |
| 2282 | const index_ty = self.air.typeOf(extra.rhs); |
| 2269 | 2283 | |
| 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 | 2285 | break :result addr; |
| 2272 | 2286 | }; |
| 2273 | 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 | 2304 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2291 | 2305 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2292 | 2306 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2293 | | const ptr_mcv = try self.resolveInst(extra.lhs); |
| 2294 | | const index_mcv = try self.resolveInst(extra.rhs); |
| 2307 | const ptr_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2308 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2295 | 2309 | |
| 2296 | 2310 | const ptr_ty = self.air.typeOf(extra.lhs); |
| 2311 | const index_ty = self.air.typeOf(extra.rhs); |
| 2297 | 2312 | |
| 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 | 2314 | break :result addr; |
| 2300 | 2315 | }; |
| 2301 | 2316 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none }); |
| ... | ... | @@ -3219,240 +3234,6 @@ const BinOpMetadata = struct { |
| 3219 | 3234 | rhs: Air.Inst.Ref, |
| 3220 | 3235 | }; |
| 3221 | 3236 | |
| 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. |
| 3234 | | fn 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 | | |
| 3456 | 3237 | fn addSub( |
| 3457 | 3238 | self: *Self, |
| 3458 | 3239 | tag: Air.Inst.Tag, |
| ... | ... | @@ -3713,6 +3494,248 @@ fn modulo( |
| 3713 | 3494 | } |
| 3714 | 3495 | } |
| 3715 | 3496 | |
| 3497 | fn 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 | |
| 3536 | fn 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 | |
| 3581 | fn 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 | |
| 3619 | fn 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 | |
| 3661 | fn 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 | |
| 3694 | fn 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 | |
| 3716 | 3739 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void { |
| 3717 | 3740 | const abi_size = ty.abiSize(self.target.*); |
| 3718 | 3741 | |
| ... | ... | @@ -4614,7 +4637,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4614 | 4637 | if (else_value == .dead) |
| 4615 | 4638 | continue; |
| 4616 | 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 | 4641 | while (true) { |
| 4619 | 4642 | i -= 1; // If this overflows, the question is: why wasn't the instruction marked dead? |
| 4620 | 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 | 4664 | if (then_value == .dead) |
| 4642 | 4665 | continue; |
| 4643 | 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 | 4668 | while (true) { |
| 4646 | 4669 | i -= 1; |
| 4647 | 4670 | if (self.branch_stack.items[i].inst_table.get(then_key)) |mcv| { |