| ... | @@ -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); | | |
| 1412 | | 1410 | |
| 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 { |
| 1427 | | 1425 | |
| 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), |
| 1429 | | 1427 | |
| 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 { |
| 1440 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 1451 | fn 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); |
| 1447 | | 1456 | |
| 1448 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1457 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1449 | .dead | 1458 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 1450 | else | 1459 | 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 | } |
| 1458 | | 1465 | |
| ... | @@ -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); |
| 2252 | | 2263 | |
| 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); |
| 2267 | | 2277 | |
| | 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); |
| 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 | 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 }; |
| 2295 | | 2309 | |
| 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); |
| 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 | 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 | }; |
| 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 | fn addSub( | 3237 | fn 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 | } |
| 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 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void { | 3739 | fn 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.*); |
| 3718 | | 3741 | |
| ... | @@ -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| { |