authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-12-04 01:27:13-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-12-04 01:29:07-05:00
log50993a8f08595b690e0b566cea3266c5ce2c5131
tree115dcf108d4016c417d035f4ba9d5fca0f30cff7
parent485e20884cfe7b6597e6d7c615195bb263d38abb

x86_64: implement more operations on vectors with 1-bit elements


3 files changed, 111 insertions(+), 66 deletions(-)

src/arch/x86_64/CodeGen.zig+56-20
......@@ -2478,8 +2478,11 @@ fn regClassForType(self: *Self, ty: Type) RegisterManager.RegisterBitSet {
24782478 else => abi.RegisterClass.sse,
24792479 },
24802480 .Vector => switch (ty.childType(mod).toIntern()) {
2481 .bool_type => abi.RegisterClass.gp,
2482 else => abi.RegisterClass.sse,
2481 .bool_type, .u1_type => abi.RegisterClass.gp,
2482 else => if (ty.isAbiInt(mod) and ty.intInfo(mod).bits == 1)
2483 abi.RegisterClass.gp
2484 else
2485 abi.RegisterClass.sse,
24832486 },
24842487 else => abi.RegisterClass.gp,
24852488 };
......@@ -5152,7 +5155,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
51525155 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
51535156
51545157 try self.spillEflagsIfOccupied();
5155 if (array_ty.isVector(mod) and elem_ty.toIntern() == .bool_type) {
5158 if (array_ty.isVector(mod) and elem_ty.bitSize(mod) == 1) {
51565159 const index_reg = switch (index_mcv) {
51575160 .register => |reg| reg,
51585161 else => try self.copyToTmpRegister(index_ty, index_mcv),
......@@ -15475,26 +15478,59 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
1547515478 break :result .{ .load_frame = .{ .index = frame_index } };
1547615479 },
1547715480 .Array, .Vector => {
15478 const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(result_ty, mod));
1547915481 const elem_ty = result_ty.childType(mod);
15480 const elem_size: u32 = @intCast(elem_ty.abiSize(mod));
15482 if (result_ty.isVector(mod) and elem_ty.bitSize(mod) == 1) {
15483 const result_size: u32 = @intCast(result_ty.abiSize(mod));
15484 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
15485 try self.asmRegisterRegister(
15486 .{ ._, .xor },
15487 registerAlias(dst_reg, @min(result_size, 4)),
15488 registerAlias(dst_reg, @min(result_size, 4)),
15489 );
1548115490
15482 for (elements, 0..) |elem, elem_i| {
15483 const elem_mcv = try self.resolveInst(elem);
15484 const mat_elem_mcv = switch (elem_mcv) {
15485 .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index },
15486 else => elem_mcv,
15487 };
15488 const elem_off: i32 = @intCast(elem_size * elem_i);
15489 try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv);
15491 for (elements, 0..) |elem, elem_i| {
15492 const elem_reg = try self.copyToTmpRegister(elem_ty, .{ .air_ref = elem });
15493 const elem_lock = self.register_manager.lockRegAssumeUnused(elem_reg);
15494 defer self.register_manager.unlockReg(elem_lock);
15495
15496 try self.asmRegisterImmediate(
15497 .{ ._, .@"and" },
15498 registerAlias(elem_reg, @min(result_size, 4)),
15499 Immediate.u(1),
15500 );
15501 if (elem_i > 0) try self.asmRegisterImmediate(
15502 .{ ._l, .sh },
15503 registerAlias(elem_reg, result_size),
15504 Immediate.u(@intCast(elem_i)),
15505 );
15506 try self.asmRegisterRegister(
15507 .{ ._, .@"or" },
15508 registerAlias(dst_reg, result_size),
15509 registerAlias(elem_reg, result_size),
15510 );
15511 }
15512 break :result .{ .register = dst_reg };
15513 } else {
15514 const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(result_ty, mod));
15515 const elem_size: u32 = @intCast(elem_ty.abiSize(mod));
15516
15517 for (elements, 0..) |elem, elem_i| {
15518 const elem_mcv = try self.resolveInst(elem);
15519 const mat_elem_mcv = switch (elem_mcv) {
15520 .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index },
15521 else => elem_mcv,
15522 };
15523 const elem_off: i32 = @intCast(elem_size * elem_i);
15524 try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv);
15525 }
15526 if (result_ty.sentinel(mod)) |sentinel| try self.genSetMem(
15527 .{ .frame = frame_index },
15528 @intCast(elem_size * elements.len),
15529 elem_ty,
15530 try self.genTypedValue(.{ .ty = elem_ty, .val = sentinel }),
15531 );
15532 break :result .{ .load_frame = .{ .index = frame_index } };
1549015533 }
15491 if (result_ty.sentinel(mod)) |sentinel| try self.genSetMem(
15492 .{ .frame = frame_index },
15493 @intCast(elem_size * elements.len),
15494 elem_ty,
15495 try self.genTypedValue(.{ .ty = elem_ty, .val = sentinel }),
15496 );
15497 break :result .{ .load_frame = .{ .index = frame_index } };
1549815534 },
1549915535 else => unreachable,
1550015536 }
src/codegen.zig+55-45
......@@ -391,53 +391,63 @@ pub fn generateSymbol(
391391 .vector_type => |vector_type| {
392392 const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse
393393 return error.Overflow;
394 switch (vector_type.child) {
395 .bool_type => {
396 const bytes = try code.addManyAsSlice(abi_size);
397 @memset(bytes, 0xaa);
398 var index: usize = 0;
399 const len = math.cast(usize, vector_type.len) orelse return error.Overflow;
400 while (index < len) : (index += 1) {
401 const bit_index = switch (endian) {
402 .big => len - 1 - index,
403 .little => index,
404 };
405 const byte = &bytes[bit_index / 8];
406 const mask = @as(u8, 1) << @truncate(bit_index);
407 if (switch (switch (aggregate.storage) {
408 .bytes => unreachable,
409 .elems => |elems| elems[index],
410 .repeated_elem => |elem| elem,
411 }) {
412 .bool_true => true,
413 .bool_false => false,
414 else => |elem| {
415 assert(mod.intern_pool.indexToKey(elem).undef == .bool_type);
416 continue;
394 if (Type.fromInterned(vector_type.child).bitSize(mod) == 1) {
395 const bytes = try code.addManyAsSlice(abi_size);
396 @memset(bytes, 0xaa);
397 var index: usize = 0;
398 const len = math.cast(usize, vector_type.len) orelse return error.Overflow;
399 while (index < len) : (index += 1) {
400 const bit_index = switch (endian) {
401 .big => len - 1 - index,
402 .little => index,
403 };
404 const byte = &bytes[bit_index / 8];
405 const mask = @as(u8, 1) << @truncate(bit_index);
406 if (switch (switch (aggregate.storage) {
407 .bytes => unreachable,
408 .elems => |elems| elems[index],
409 .repeated_elem => |elem| elem,
410 }) {
411 .bool_true => true,
412 .bool_false => false,
413 else => |elem| switch (mod.intern_pool.indexToKey(elem)) {
414 .undef => continue,
415 .int => |int| switch (int.storage) {
416 .u64 => |x| switch (x) {
417 0 => false,
418 1 => true,
419 else => unreachable,
420 },
421 .i64 => |x| switch (x) {
422 -1 => true,
423 0 => false,
424 else => unreachable,
425 },
426 else => unreachable,
417427 },
418 }) byte.* |= mask else byte.* &= ~mask;
419 }
420 },
421 else => switch (aggregate.storage) {
422 .bytes => |bytes| try code.appendSlice(bytes),
423 .elems, .repeated_elem => {
424 var index: u64 = 0;
425 while (index < vector_type.len) : (index += 1) {
426 switch (try generateSymbol(bin_file, src_loc, .{
427 .ty = Type.fromInterned(vector_type.child),
428 .val = Value.fromInterned(switch (aggregate.storage) {
429 .bytes => unreachable,
430 .elems => |elems| elems[
431 math.cast(usize, index) orelse return error.Overflow
432 ],
433 .repeated_elem => |elem| elem,
434 }),
435 }, code, debug_output, reloc_info)) {
436 .ok => {},
437 .fail => |em| return .{ .fail = em },
438 }
428 else => unreachable,
429 },
430 }) byte.* |= mask else byte.* &= ~mask;
431 }
432 } else switch (aggregate.storage) {
433 .bytes => |bytes| try code.appendSlice(bytes),
434 .elems, .repeated_elem => {
435 var index: u64 = 0;
436 while (index < vector_type.len) : (index += 1) {
437 switch (try generateSymbol(bin_file, src_loc, .{
438 .ty = Type.fromInterned(vector_type.child),
439 .val = Value.fromInterned(switch (aggregate.storage) {
440 .bytes => unreachable,
441 .elems => |elems| elems[
442 math.cast(usize, index) orelse return error.Overflow
443 ],
444 .repeated_elem => |elem| elem,
445 }),
446 }, code, debug_output, reloc_info)) {
447 .ok => {},
448 .fail => |em| return .{ .fail = em },
439449 }
440 },
450 }
441451 },
442452 }
443453
test/behavior/cast.zig-1
......@@ -2420,7 +2420,6 @@ test "@intFromFloat on vector" {
24202420
24212421test "@intFromBool on vector" {
24222422 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2423 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
24242423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
24252424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24262425 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO