authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-13 03:05:49-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-15 03:07:51-04:00
log2cbd442a9df16ab2d13d03041631f516269c9f64
treebded6a174539fd917713e09d731ea2b45a4807a9
parentf83ebd8e6c95cf37d498936cae26d3a743cddc7f

x86_64: implement integer vector movement


3 files changed, 248 insertions(+), 122 deletions(-)

src/arch/x86_64/CodeGen.zig+248-118
......@@ -8579,56 +8579,174 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
85798579 return self.finishAirResult(inst, result);
85808580}
85818581
8582fn movMirTag(self: *Self, ty: Type, aligned: bool) !Mir.Inst.FixedTag {
8582const MoveStrategy = union(enum) {
8583 move: Mir.Inst.FixedTag,
8584 insert_extract: InsertExtract,
8585 vex_insert_extract: InsertExtract,
8586
8587 const InsertExtract = struct {
8588 insert: Mir.Inst.FixedTag,
8589 extract: Mir.Inst.FixedTag,
8590 imm: Immediate,
8591 };
8592};
8593fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy {
85838594 switch (ty.zigTypeTag()) {
8584 else => return .{ ._, .mov },
8595 else => return .{ .move = .{ ._, .mov } },
85858596 .Float => switch (ty.floatBits(self.target.*)) {
8586 16 => unreachable, // needs special handling
8587 32 => return if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov },
8588 64 => return if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov },
8589 128 => return if (self.hasFeature(.avx))
8597 16 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{
8598 .insert = .{ .vp_w, .insr },
8599 .extract = .{ .vp_w, .extr },
8600 .imm = Immediate.u(0),
8601 } } else .{ .insert_extract = .{
8602 .insert = .{ .p_w, .insr },
8603 .extract = .{ .p_w, .extr },
8604 .imm = Immediate.u(0),
8605 } },
8606 32 => return .{ .move = if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov } },
8607 64 => return .{ .move = if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov } },
8608 128 => return .{ .move = if (self.hasFeature(.avx))
85908609 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8591 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu },
8610 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } },
85928611 else => {},
85938612 },
85948613 .Vector => switch (ty.childType().zigTypeTag()) {
8614 .Int => switch (ty.childType().intInfo(self.target.*).bits) {
8615 8 => switch (ty.vectorLen()) {
8616 1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{
8617 .insert = .{ .vp_b, .insr },
8618 .extract = .{ .vp_b, .extr },
8619 .imm = Immediate.u(0),
8620 } } else if (self.hasFeature(.sse4_2)) return .{ .insert_extract = .{
8621 .insert = .{ .p_b, .insr },
8622 .extract = .{ .p_b, .extr },
8623 .imm = Immediate.u(0),
8624 } },
8625 2 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{
8626 .insert = .{ .vp_w, .insr },
8627 .extract = .{ .vp_w, .extr },
8628 .imm = Immediate.u(0),
8629 } } else .{ .insert_extract = .{
8630 .insert = .{ .p_w, .insr },
8631 .extract = .{ .p_w, .extr },
8632 .imm = Immediate.u(0),
8633 } },
8634 3...4 => return .{ .move = if (self.hasFeature(.avx))
8635 .{ .v_ss, .mov }
8636 else
8637 .{ ._ss, .mov } },
8638 5...8 => return .{ .move = if (self.hasFeature(.avx))
8639 .{ .v_sd, .mov }
8640 else
8641 .{ ._sd, .mov } },
8642 else => {},
8643 },
8644 16 => switch (ty.vectorLen()) {
8645 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{
8646 .insert = .{ .vp_w, .insr },
8647 .extract = .{ .vp_w, .extr },
8648 .imm = Immediate.u(0),
8649 } } else .{ .insert_extract = .{
8650 .insert = .{ .p_w, .insr },
8651 .extract = .{ .p_w, .extr },
8652 .imm = Immediate.u(0),
8653 } },
8654 2 => return .{ .move = if (self.hasFeature(.avx))
8655 .{ .v_ss, .mov }
8656 else
8657 .{ ._ss, .mov } },
8658 3...4 => return .{ .move = if (self.hasFeature(.avx))
8659 .{ .v_sd, .mov }
8660 else
8661 .{ ._sd, .mov } },
8662 5...8 => return .{ .move = if (self.hasFeature(.avx))
8663 .{ .v_ps, .mov }
8664 else
8665 .{ ._ps, .mov } },
8666 else => {},
8667 },
8668 32 => switch (ty.vectorLen()) {
8669 1 => return .{ .move = if (self.hasFeature(.avx))
8670 .{ .v_ss, .mov }
8671 else
8672 .{ ._ss, .mov } },
8673 2 => return .{ .move = if (self.hasFeature(.avx))
8674 .{ .v_sd, .mov }
8675 else
8676 .{ ._sd, .mov } },
8677 3...4 => return .{ .move = if (self.hasFeature(.avx))
8678 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8679 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } },
8680 5...8 => if (self.hasFeature(.avx))
8681 return .{ .move = if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } },
8682 else => {},
8683 },
8684 64 => switch (ty.vectorLen()) {
8685 1 => return .{ .move = if (self.hasFeature(.avx))
8686 .{ .v_sd, .mov }
8687 else
8688 .{ ._sd, .mov } },
8689 2 => return .{ .move = if (self.hasFeature(.avx))
8690 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8691 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } },
8692 3...4 => if (self.hasFeature(.avx))
8693 return .{ .move = if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } },
8694 else => {},
8695 },
8696 else => {},
8697 },
85958698 .Float => switch (ty.childType().floatBits(self.target.*)) {
85968699 16 => switch (ty.vectorLen()) {
8597 1 => unreachable, // needs special handling
8598 2 => return if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov },
8599 3...4 => return if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov },
8600 5...8 => return if (self.hasFeature(.avx))
8700 1 => {},
8701 2 => return .{ .move = if (self.hasFeature(.avx))
8702 .{ .v_ss, .mov }
8703 else
8704 .{ ._ss, .mov } },
8705 3...4 => return .{ .move = if (self.hasFeature(.avx))
8706 .{ .v_sd, .mov }
8707 else
8708 .{ ._sd, .mov } },
8709 5...8 => return .{ .move = if (self.hasFeature(.avx))
86018710 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8602 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu },
8711 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } },
86038712 9...16 => if (self.hasFeature(.avx))
8604 return if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu },
8713 return .{ .move = if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } },
86058714 else => {},
86068715 },
86078716 32 => switch (ty.vectorLen()) {
8608 1 => return if (self.hasFeature(.avx)) .{ .v_ss, .mov } else .{ ._ss, .mov },
8609 2 => return if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov },
8610 3...4 => return if (self.hasFeature(.avx))
8717 1 => return .{ .move = if (self.hasFeature(.avx))
8718 .{ .v_ss, .mov }
8719 else
8720 .{ ._ss, .mov } },
8721 2 => return .{ .move = if (self.hasFeature(.avx))
8722 .{ .v_sd, .mov }
8723 else
8724 .{ ._sd, .mov } },
8725 3...4 => return .{ .move = if (self.hasFeature(.avx))
86118726 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8612 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu },
8727 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } },
86138728 5...8 => if (self.hasFeature(.avx))
8614 return if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu },
8729 return .{ .move = if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } },
86158730 else => {},
86168731 },
86178732 64 => switch (ty.vectorLen()) {
8618 1 => return if (self.hasFeature(.avx)) .{ .v_sd, .mov } else .{ ._sd, .mov },
8619 2 => return if (self.hasFeature(.avx))
8733 1 => return .{ .move = if (self.hasFeature(.avx))
8734 .{ .v_sd, .mov }
8735 else
8736 .{ ._sd, .mov } },
8737 2 => return .{ .move = if (self.hasFeature(.avx))
86208738 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8621 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu },
8739 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } },
86228740 3...4 => if (self.hasFeature(.avx))
8623 return if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu },
8741 return .{ .move = if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } },
86248742 else => {},
86258743 },
86268744 128 => switch (ty.vectorLen()) {
8627 1 => return if (self.hasFeature(.avx))
8745 1 => return .{ .move = if (self.hasFeature(.avx))
86288746 if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu }
8629 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu },
8747 else if (aligned) .{ ._ps, .mova } else .{ ._ps, .movu } },
86308748 2 => if (self.hasFeature(.avx))
8631 return if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu },
8749 return .{ .move = if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } },
86328750 else => {},
86338751 },
86348752 else => {},
......@@ -8636,7 +8754,7 @@ fn movMirTag(self: *Self, ty: Type, aligned: bool) !Mir.Inst.FixedTag {
86368754 else => {},
86378755 },
86388756 }
8639 return self.fail("TODO movMirTag for {}", .{ty.fmt(self.bin_file.options.module.?)});
8757 return self.fail("TODO moveStrategy for {}", .{ty.fmt(self.bin_file.options.module.?)});
86408758}
86418759
86428760fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {
......@@ -8764,6 +8882,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
87648882 .load_frame,
87658883 .lea_frame,
87668884 => {
8885 const dst_alias = registerAlias(dst_reg, abi_size);
87678886 const src_mem = Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) {
87688887 .register_offset, .indirect => |reg_off| .{
87698888 .base = .{ .reg = reg_off.reg },
......@@ -8775,71 +8894,81 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
87758894 },
87768895 else => unreachable,
87778896 });
8778 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
8779 try self.asmRegisterMemoryImmediate(
8780 .{ .p_w, .insr },
8781 registerAlias(dst_reg, abi_size),
8897 switch (@as(MoveStrategy, switch (src_mcv) {
8898 .register_offset => |reg_off| switch (reg_off.off) {
8899 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }),
8900 else => .{ .move = .{ ._, .lea } },
8901 },
8902 .indirect => try self.moveStrategy(ty, false),
8903 .load_frame => |frame_addr| try self.moveStrategy(
8904 ty,
8905 self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(self.target.*),
8906 ),
8907 .lea_frame => .{ .move = .{ ._, .lea } },
8908 else => unreachable,
8909 })) {
8910 .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem),
8911 .insert_extract => |ie| try self.asmRegisterMemoryImmediate(
8912 ie.insert,
8913 dst_alias,
87828914 src_mem,
8783 Immediate.u(0),
8784 )
8785 else
8786 try self.asmRegisterMemory(
8787 switch (src_mcv) {
8788 .register_offset => |reg_off| switch (reg_off.off) {
8789 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }),
8790 else => .{ ._, .lea },
8791 },
8792 .indirect => try self.movMirTag(ty, false),
8793 .load_frame => |frame_addr| try self.movMirTag(
8794 ty,
8795 self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(self.target.*),
8796 ),
8797 .lea_frame => .{ ._, .lea },
8798 else => unreachable,
8799 },
8800 registerAlias(dst_reg, abi_size),
8915 ie.imm,
8916 ),
8917 .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate(
8918 ie.insert,
8919 dst_alias,
8920 dst_alias,
88018921 src_mem,
8802 );
8922 ie.imm,
8923 ),
8924 }
88038925 },
88048926 .memory, .load_direct, .load_got, .load_tlv => {
88058927 switch (src_mcv) {
88068928 .memory => |addr| if (math.cast(i32, @bitCast(i64, addr))) |small_addr| {
8929 const dst_alias = registerAlias(dst_reg, abi_size);
88078930 const src_mem = Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
88088931 .base = .{ .reg = .ds },
88098932 .disp = small_addr,
88108933 });
8811 return if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
8812 self.asmRegisterMemoryImmediate(
8813 .{ .p_w, .insr },
8814 registerAlias(dst_reg, abi_size),
8934 switch (try self.moveStrategy(ty, mem.isAlignedGeneric(
8935 u32,
8936 @bitCast(u32, small_addr),
8937 ty.abiAlignment(self.target.*),
8938 ))) {
8939 .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem),
8940 .insert_extract => |ie| try self.asmRegisterMemoryImmediate(
8941 ie.insert,
8942 dst_alias,
88158943 src_mem,
8816 Immediate.u(0),
8817 )
8818 else
8819 self.asmRegisterMemory(
8820 try self.movMirTag(ty, mem.isAlignedGeneric(
8821 u32,
8822 @bitCast(u32, small_addr),
8823 ty.abiAlignment(self.target.*),
8824 )),
8825 registerAlias(dst_reg, abi_size),
8944 ie.imm,
8945 ),
8946 .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate(
8947 ie.insert,
8948 dst_alias,
8949 dst_alias,
88268950 src_mem,
8827 );
8951 ie.imm,
8952 ),
8953 }
88288954 },
8829 .load_direct => |sym_index| if (!ty.isRuntimeFloat()) {
8830 const atom_index = try self.owner.getSymbolIndex(self);
8831 _ = try self.addInst(.{
8832 .tag = .mov,
8833 .ops = .direct_reloc,
8834 .data = .{ .rx = .{
8835 .r1 = dst_reg.to64(),
8836 .payload = try self.addExtra(Mir.Reloc{
8837 .atom_index = atom_index,
8838 .sym_index = sym_index,
8839 }),
8840 } },
8841 });
8842 return;
8955 .load_direct => |sym_index| switch (ty.zigTypeTag()) {
8956 else => {
8957 const atom_index = try self.owner.getSymbolIndex(self);
8958 _ = try self.addInst(.{
8959 .tag = .mov,
8960 .ops = .direct_reloc,
8961 .data = .{ .rx = .{
8962 .r1 = dst_reg.to64(),
8963 .payload = try self.addExtra(Mir.Reloc{
8964 .atom_index = atom_index,
8965 .sym_index = sym_index,
8966 }),
8967 } },
8968 });
8969 return;
8970 },
8971 .Float, .Vector => {},
88438972 },
88448973 .load_got, .load_tlv => {},
88458974 else => unreachable,
......@@ -8849,22 +8978,26 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
88498978 const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
88508979 defer self.register_manager.unlockReg(addr_lock);
88518980
8981 const dst_alias = registerAlias(dst_reg, abi_size);
88528982 const src_mem = Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
88538983 .base = .{ .reg = addr_reg },
88548984 });
8855 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
8856 try self.asmRegisterMemoryImmediate(
8857 .{ .p_w, .insr },
8858 registerAlias(dst_reg, abi_size),
8985 switch (try self.moveStrategy(ty, false)) {
8986 .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem),
8987 .insert_extract => |ie| try self.asmRegisterMemoryImmediate(
8988 ie.insert,
8989 dst_alias,
88598990 src_mem,
8860 Immediate.u(0),
8861 )
8862 else
8863 try self.asmRegisterMemory(
8864 try self.movMirTag(ty, false),
8865 registerAlias(dst_reg, abi_size),
8991 ie.imm,
8992 ),
8993 .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate(
8994 ie.insert,
8995 dst_alias,
8996 dst_alias,
88668997 src_mem,
8867 );
8998 ie.imm,
8999 ),
9000 }
88689001 },
88699002 .lea_direct, .lea_got => |sym_index| {
88709003 const atom_index = try self.owner.getSymbolIndex(self);
......@@ -8966,36 +9099,33 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
89669099 Memory.PtrSize.fromSize(abi_size),
89679100 .{ .base = base, .disp = disp },
89689101 );
8969 if (ty.isRuntimeFloat() and ty.floatBits(self.target.*) == 16)
8970 try self.asmMemoryRegisterImmediate(
8971 .{ .p_w, .extr },
8972 dst_mem,
8973 src_reg.to128(),
8974 Immediate.u(0),
8975 )
8976 else
8977 try self.asmMemoryRegister(
8978 try self.movMirTag(ty, switch (base) {
8979 .none => mem.isAlignedGeneric(
8980 u32,
8981 @bitCast(u32, disp),
8982 ty.abiAlignment(self.target.*),
8983 ),
8984 .reg => |reg| switch (reg) {
8985 .es, .cs, .ss, .ds => mem.isAlignedGeneric(
8986 u32,
8987 @bitCast(u32, disp),
8988 ty.abiAlignment(self.target.*),
8989 ),
8990 else => false,
8991 },
8992 .frame => |frame_index| self.getFrameAddrAlignment(
8993 .{ .index = frame_index, .off = disp },
8994 ) >= ty.abiAlignment(self.target.*),
8995 }),
9102 const src_alias = registerAlias(src_reg, abi_size);
9103 switch (try self.moveStrategy(ty, switch (base) {
9104 .none => mem.isAlignedGeneric(
9105 u32,
9106 @bitCast(u32, disp),
9107 ty.abiAlignment(self.target.*),
9108 ),
9109 .reg => |reg| switch (reg) {
9110 .es, .cs, .ss, .ds => mem.isAlignedGeneric(
9111 u32,
9112 @bitCast(u32, disp),
9113 ty.abiAlignment(self.target.*),
9114 ),
9115 else => false,
9116 },
9117 .frame => |frame_index| self.getFrameAddrAlignment(
9118 .{ .index = frame_index, .off = disp },
9119 ) >= ty.abiAlignment(self.target.*),
9120 })) {
9121 .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias),
9122 .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate(
9123 ie.extract,
89969124 dst_mem,
8997 registerAlias(src_reg, abi_size),
8998 );
9125 src_alias,
9126 ie.imm,
9127 ),
9128 }
89999129 },
90009130 .register_overflow => |ro| {
90019131 try self.genSetMem(
test/behavior/maximum_minimum.zig-1
......@@ -146,7 +146,6 @@ test "@min/@max more than two arguments" {
146146
147147test "@min/@max more than two vector arguments" {
148148 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
149 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
150149 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
151150 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
152151 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/vector.zig-3
......@@ -1129,7 +1129,6 @@ test "loading the second vector from a slice of vectors" {
11291129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11301130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11311131 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1132 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11331132
11341133 @setRuntimeSafety(false);
11351134 var small_bases = [2]@Vector(2, u8){
......@@ -1219,7 +1218,6 @@ test "zero multiplicand" {
12191218 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12201219 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12211220 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1222 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12231221
12241222 const zeros = @Vector(2, u32){ 0.0, 0.0 };
12251223 var ones = @Vector(2, u32){ 1.0, 1.0 };
......@@ -1324,7 +1322,6 @@ test "store to vector in slice" {
13241322test "addition of vectors represented as strings" {
13251323 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13261324 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1327 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
13281325 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13291326
13301327 const V = @Vector(3, u8);