Commit ff2ec0dc5a

Andrew Kelley <andrew@ziglang.org>
2021-04-25 02:31:52
AstGen: implement `@Vector`
1 parent e018e64
src/AstGen.zig
@@ -1808,6 +1808,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
             .array_mul,
             .array_type,
             .array_type_sentinel,
+            .vector_type,
             .elem_type,
             .indexable_ptr_len,
             .anyframe_type,
@@ -6510,6 +6511,14 @@ fn builtinCall(
             });
             return rvalue(gz, scope, rl, result, node);
         },
+        .Vector => {
+            const result = try gz.addPlNode(.vector_type, node, Zir.Inst.Bin{
+                .lhs = try comptimeExpr(gz, scope, .{.ty = .u32_type}, params[0]),
+                .rhs = try typeExpr(gz, scope, params[1]),
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
+
     }
     // zig fmt: on
 }
src/BuiltinFn.zig
@@ -104,6 +104,7 @@ pub const Tag = enum {
     type_name,
     TypeOf,
     union_init,
+    Vector,
 };
 
 tag: Tag,
@@ -848,5 +849,12 @@ pub const list = list: {
                 .param_count = 3,
             },
         },
+        .{
+            "@Vector",
+            .{
+                .tag = .Vector,
+                .param_count = 2,
+            },
+        },
     });
 };
src/Sema.zig
@@ -143,6 +143,7 @@ pub fn analyzeBody(
             .array_mul                    => try sema.zirArrayMul(block, inst),
             .array_type                   => try sema.zirArrayType(block, inst),
             .array_type_sentinel          => try sema.zirArrayTypeSentinel(block, inst),
+            .vector_type                  => try sema.zirVectorType(block, inst),
             .as                           => try sema.zirAs(block, inst),
             .as_node                      => try sema.zirAsNode(block, inst),
             .bit_and                      => try sema.zirBitwise(block, inst, .bit_and),
@@ -2143,6 +2144,21 @@ fn zirElemType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
     return sema.mod.constType(sema.arena, src, elem_type);
 }
 
+fn zirVectorType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
+    const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+    const src = inst_data.src();
+    const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+    const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+    const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
+    const len = try sema.resolveAlreadyCoercedInt(block, len_src, extra.lhs, u32);
+    const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs);
+    const vector_type = try Type.Tag.vector.create(sema.arena, .{
+        .len = len,
+        .elem_type = elem_type,
+    });
+    return sema.mod.constType(sema.arena, src, vector_type);
+}
+
 fn zirArrayType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
     const tracy = trace(@src());
     defer tracy.end();
src/type.zig
@@ -69,7 +69,14 @@ pub const Type = extern union {
             .fn_ccc_void_no_args => return .Fn,
             .function => return .Fn,
 
-            .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array,
+            .array,
+            .array_u8_sentinel_0,
+            .array_u8,
+            .array_sentinel,
+            => return .Array,
+
+            .vector => return .Vector,
+
             .single_const_pointer_to_comptime_int,
             .const_slice_u8,
             .single_const_pointer,
@@ -438,7 +445,7 @@ pub const Type = extern union {
                 const info_b = b.intInfo(@as(Target, undefined));
                 return info_a.signedness == info_b.signedness and info_a.bits == info_b.bits;
             },
-            .Array => {
+            .Array, .Vector => {
                 if (a.arrayLen() != b.arrayLen())
                     return false;
                 if (!a.elemType().eql(b.elemType()))
@@ -487,7 +494,6 @@ pub const Type = extern union {
             .BoundFn,
             .Opaque,
             .Frame,
-            .Vector,
             => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
         }
     }
@@ -522,7 +528,7 @@ pub const Type = extern union {
                     std.hash.autoHash(&hasher, info.bits);
                 }
             },
-            .Array => {
+            .Array, .Vector => {
                 std.hash.autoHash(&hasher, self.arrayLen());
                 std.hash.autoHash(&hasher, self.elemType().hash());
                 // TODO hash array sentinel
@@ -552,7 +558,6 @@ pub const Type = extern union {
             .Opaque,
             .Frame,
             .AnyFrame,
-            .Vector,
             .EnumLiteral,
             => {
                 // TODO implement more type hashing
@@ -647,6 +652,13 @@ pub const Type = extern union {
             .int_unsigned,
             => return self.copyPayloadShallow(allocator, Payload.Bits),
 
+            .vector => {
+                const payload = self.castTag(.vector).?.data;
+                return Tag.vector.create(allocator, .{
+                    .len = payload.len,
+                    .elem_type = try payload.elem_type.copy(allocator),
+                });
+            },
             .array => {
                 const payload = self.castTag(.array).?.data;
                 return Tag.array.create(allocator, .{
@@ -839,6 +851,12 @@ pub const Type = extern union {
                     const len = ty.castTag(.array_u8_sentinel_0).?.data;
                     return writer.print("[{d}:0]u8", .{len});
                 },
+                .vector => {
+                    const payload = ty.castTag(.vector).?.data;
+                    try writer.print("@Vector({d}, ", .{payload.len});
+                    try payload.elem_type.format("", .{}, writer);
+                    return writer.writeAll(")");
+                },
                 .array => {
                     const payload = ty.castTag(.array).?.data;
                     try writer.print("[{d}]", .{payload.len});
@@ -1116,7 +1134,7 @@ pub const Type = extern union {
             },
 
             // TODO lazy types
-            .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
+            .array, .vector => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
             .array_u8 => self.arrayLen() != 0,
             .array_sentinel, .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, .const_slice, .mut_slice, .pointer => self.elemType().hasCodeGenBits(),
             .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data != 0,
@@ -1264,6 +1282,10 @@ pub const Type = extern union {
 
             .array, .array_sentinel => return self.elemType().abiAlignment(target),
 
+            // TODO audit this - is there any more complicated logic to determine
+            // ABI alignment of vectors?
+            .vector => return 16,
+
             .int_signed, .int_unsigned => {
                 const bits: u16 = self.cast(Payload.Bits).?.data;
                 return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8);
@@ -1386,8 +1408,8 @@ pub const Type = extern union {
 
             .array_u8 => self.castTag(.array_u8).?.data,
             .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data + 1,
-            .array => {
-                const payload = self.castTag(.array).?.data;
+            .array, .vector => {
+                const payload = self.cast(Payload.Array).?.data;
                 const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
                 return payload.len * elem_size;
             },
@@ -1534,6 +1556,11 @@ pub const Type = extern union {
 
             .bool => 1,
 
+            .vector => {
+                const payload = self.castTag(.vector).?.data;
+                const elem_bit_size = payload.elem_type.bitSize(target);
+                return elem_bit_size * payload.len;
+            },
             .array_u8 => 8 * self.castTag(.array_u8).?.data,
             .array_u8_sentinel_0 => 8 * (self.castTag(.array_u8_sentinel_0).?.data + 1),
             .array => {
@@ -1811,7 +1838,6 @@ pub const Type = extern union {
             .Enum,
             .Frame,
             .AnyFrame,
-            .Vector,
             => return true,
 
             .Opaque => return is_extern,
@@ -1830,7 +1856,7 @@ pub const Type = extern union {
                 var buf: Payload.ElemType = undefined;
                 return ty.optionalChild(&buf).isValidVarType(is_extern);
             },
-            .Pointer, .Array => ty = ty.elemType(),
+            .Pointer, .Array, .Vector => ty = ty.elemType(),
             .ErrorUnion => ty = ty.errorUnionChild(),
 
             .Fn => @panic("TODO fn isValidVarType"),
@@ -1846,6 +1872,7 @@ pub const Type = extern union {
     /// Asserts the type is a pointer or array type.
     pub fn elemType(self: Type) Type {
         return switch (self.tag()) {
+            .vector => self.castTag(.vector).?.data.elem_type,
             .array => self.castTag(.array).?.data.elem_type,
             .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
             .single_const_pointer,
@@ -1936,6 +1963,7 @@ pub const Type = extern union {
     /// Asserts the type is an array or vector.
     pub fn arrayLen(self: Type) u64 {
         return switch (self.tag()) {
+            .vector => self.castTag(.vector).?.data.len,
             .array => self.castTag(.array).?.data.len,
             .array_sentinel => self.castTag(.array_sentinel).?.data.len,
             .array_u8 => self.castTag(.array_u8).?.data,
@@ -1955,6 +1983,7 @@ pub const Type = extern union {
             .c_const_pointer,
             .c_mut_pointer,
             .single_const_pointer_to_comptime_int,
+            .vector,
             .array,
             .array_u8,
             .manyptr_u8,
@@ -2325,7 +2354,7 @@ pub const Type = extern union {
                     return null;
                 }
             },
-            .array, .array_u8 => {
+            .vector, .array, .array_u8 => {
                 if (ty.arrayLen() == 0)
                     return Value.initTag(.empty_array);
                 ty = ty.elemType();
@@ -2730,6 +2759,7 @@ pub const Type = extern union {
         array_u8_sentinel_0,
         array,
         array_sentinel,
+        vector,
         pointer,
         single_const_pointer,
         single_mut_pointer,
@@ -2845,7 +2875,7 @@ pub const Type = extern union {
 
                 .error_set => Payload.ErrorSet,
 
-                .array => Payload.Array,
+                .array, .vector => Payload.Array,
                 .array_sentinel => Payload.ArraySentinel,
                 .pointer => Payload.Pointer,
                 .function => Payload.Function,
@@ -2888,9 +2918,7 @@ pub const Type = extern union {
         };
 
         pub const Array = struct {
-            pub const base_tag = Tag.array;
-
-            base: Payload = Payload{ .tag = base_tag },
+            base: Payload,
             data: struct {
                 len: u64,
                 elem_type: Type,
src/Zir.zig
@@ -158,6 +158,10 @@ pub const Inst = struct {
         /// `[N:S]T` syntax. No source location provided.
         /// Uses the `array_type_sentinel` field.
         array_type_sentinel,
+        /// `@Vector` builtin.
+        /// Uses the `pl_node` union field with `Bin` payload.
+        /// lhs is length, rhs is element type.
+        vector_type,
         /// Given an array type, returns the element type.
         /// Uses the `un_node` union field.
         elem_type,
@@ -952,6 +956,7 @@ pub const Inst = struct {
                 .array_mul,
                 .array_type,
                 .array_type_sentinel,
+                .vector_type,
                 .elem_type,
                 .indexable_ptr_len,
                 .anyframe_type,
@@ -2542,6 +2547,7 @@ const Writer = struct {
             .atomic_load,
             .bitcast,
             .bitcast_result_ptr,
+            .vector_type,
             => try self.writePlNodeBin(stream, inst),
 
             .@"export" => try self.writePlNodeExport(stream, inst),