diff --git a/lib/std/meta.zig b/lib/std/meta.zig index cdc93e5d33..2ed737cea3 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -1297,3 +1297,35 @@ pub fn globalOption(comptime name: []const u8, comptime T: type) ?T { return null; return @as(T, @field(root, name)); } + +/// This function is for translate-c and is not intended for general use. +/// Convert from clang __builtin_shufflevector index to Zig @shuffle index +/// clang requires __builtin_shufflevector index arguments to be integer constants. +/// negative values for `this_index` indicate "don't care" so we arbitrarily choose 0 +/// clang enforces that `this_index` is less than the total number of vector elements +/// See https://ziglang.org/documentation/master/#shuffle +/// See https://clang.llvm.org/docs/LanguageExtensions.html#langext-builtin-shufflevector +pub fn shuffleVectorIndex(comptime this_index: c_int, comptime source_vector_len: usize) i32 { + if (this_index <= 0) return 0; + + const positive_index = @intCast(usize, this_index); + if (positive_index < source_vector_len) return @intCast(i32, this_index); + const b_index = positive_index - source_vector_len; + return ~@intCast(i32, b_index); +} + +test "shuffleVectorIndex" { + const vector_len: usize = 4; + + testing.expect(shuffleVectorIndex(-1, vector_len) == 0); + + testing.expect(shuffleVectorIndex(0, vector_len) == 0); + testing.expect(shuffleVectorIndex(1, vector_len) == 1); + testing.expect(shuffleVectorIndex(2, vector_len) == 2); + testing.expect(shuffleVectorIndex(3, vector_len) == 3); + + testing.expect(shuffleVectorIndex(4, vector_len) == -1); + testing.expect(shuffleVectorIndex(5, vector_len) == -2); + testing.expect(shuffleVectorIndex(6, vector_len) == -3); + testing.expect(shuffleVectorIndex(7, vector_len) == -4); +} \ No newline at end of file diff --git a/src/clang.zig b/src/clang.zig index 0d18ae42b3..e87852e9ba 100644 --- a/src/clang.zig +++ b/src/clang.zig @@ -300,6 +300,14 @@ pub const ConstantExpr = opaque {}; pub const ContinueStmt = opaque {}; +pub const ConvertVectorExpr = opaque { + pub const getSrcExpr = ZigClangConvertVectorExpr_getSrcExpr; + extern fn ZigClangConvertVectorExpr_getSrcExpr(*const ConvertVectorExpr) *const Expr; + + pub const getTypeSourceInfo_getType = ZigClangConvertVectorExpr_getTypeSourceInfo_getType; + extern fn ZigClangConvertVectorExpr_getTypeSourceInfo_getType(*const ConvertVectorExpr) QualType; +}; + pub const DecayedType = opaque { pub const getDecayedType = ZigClangDecayedType_getDecayedType; extern fn ZigClangDecayedType_getDecayedType(*const DecayedType) QualType; @@ -748,6 +756,14 @@ pub const ReturnStmt = opaque { extern fn ZigClangReturnStmt_getRetValue(*const ReturnStmt) ?*const Expr; }; +pub const ShuffleVectorExpr = opaque { + pub const getNumSubExprs = ZigClangShuffleVectorExpr_getNumSubExprs; + extern fn ZigClangShuffleVectorExpr_getNumSubExprs(*const ShuffleVectorExpr) c_uint; + + pub const getExpr = ZigClangShuffleVectorExpr_getExpr; + extern fn ZigClangShuffleVectorExpr_getExpr(*const ShuffleVectorExpr, c_uint) *const Expr; +}; + pub const SourceManager = opaque { pub const getSpellingLoc = ZigClangSourceManager_getSpellingLoc; extern fn ZigClangSourceManager_getSpellingLoc(*const SourceManager, Loc: SourceLocation) SourceLocation; @@ -837,6 +853,9 @@ pub const Type = opaque { pub const isRecordType = ZigClangType_isRecordType; extern fn ZigClangType_isRecordType(*const Type) bool; + pub const isVectorType = ZigClangType_isVectorType; + extern fn ZigClangType_isVectorType(*const Type) bool; + pub const isIncompleteOrZeroLengthArrayType = ZigClangType_isIncompleteOrZeroLengthArrayType; extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(*const Type, *const ASTContext) bool; @@ -937,6 +956,14 @@ pub const VarDecl = opaque { extern fn ZigClangVarDecl_getTypeSourceInfo_getType(*const VarDecl) QualType; }; +pub const VectorType = opaque { + pub const getElementType = ZigClangVectorType_getElementType; + extern fn ZigClangVectorType_getElementType(*const VectorType) QualType; + + pub const getNumElements = ZigClangVectorType_getNumElements; + extern fn ZigClangVectorType_getNumElements(*const VectorType) c_uint; +}; + pub const WhileStmt = opaque { pub const getCond = ZigClangWhileStmt_getCond; extern fn ZigClangWhileStmt_getCond(*const WhileStmt) *const Expr; diff --git a/src/translate_c.zig b/src/translate_c.zig index 4c6d9ccee1..5962b85a6b 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -1123,6 +1123,16 @@ fn transStmt( const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, stmt); return transExpr(c, scope, gen_sel.getResultExpr(), result_used); }, + .ConvertVectorExprClass => { + const conv_vec = @ptrCast(*const clang.ConvertVectorExpr, stmt); + const conv_vec_node = try transConvertVectorExpr(c, scope, stmt.getBeginLoc(), conv_vec); + return maybeSuppressResult(c, scope, result_used, conv_vec_node); + }, + .ShuffleVectorExprClass => { + const shuffle_vec_expr = @ptrCast(*const clang.ShuffleVectorExpr, stmt); + const shuffle_vec_node = try transShuffleVectorExpr(c, scope, shuffle_vec_expr); + return maybeSuppressResult(c, scope, result_used, shuffle_vec_node); + }, // When adding new cases here, see comment for maybeBlockify() else => { return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)}); @@ -1130,6 +1140,128 @@ fn transStmt( } } +/// See https://clang.llvm.org/docs/LanguageExtensions.html#langext-builtin-convertvector +fn transConvertVectorExpr( + c: *Context, + scope: *Scope, + source_loc: clang.SourceLocation, + expr: *const clang.ConvertVectorExpr, +) TransError!Node { + const base_stmt = @ptrCast(*const clang.Stmt, expr); + + var block_scope = try Scope.Block.init(c, scope, true); + defer block_scope.deinit(); + + const src_expr = expr.getSrcExpr(); + const src_type = qualTypeCanon(src_expr.getType()); + const src_vector_ty = @ptrCast(*const clang.VectorType, src_type); + const src_element_qt = src_vector_ty.getElementType(); + const src_element_type_node = try transQualType(c, &block_scope.base, src_element_qt, base_stmt.getBeginLoc()); + + const src_expr_node = try transExpr(c, &block_scope.base, src_expr, .used); + + const dst_qt = expr.getTypeSourceInfo_getType(); + const dst_type_node = try transQualType(c, &block_scope.base, dst_qt, base_stmt.getBeginLoc()); + const dst_vector_ty = @ptrCast(*const clang.VectorType, qualTypeCanon(dst_qt)); + const num_elements = dst_vector_ty.getNumElements(); + const dst_element_qt = dst_vector_ty.getElementType(); + + // workaround for https://github.com/ziglang/zig/issues/8322 + // we store the casted results into temp variables and use those + // to initialize the vector. Eventually we can just directly + // construct the init_list from casted source members + var i: usize = 0; + while (i < num_elements) : (i += 1) { + const mangled_name = try block_scope.makeMangledName(c, "tmp"); + const value = try Tag.array_access.create(c.arena, .{ + .lhs = src_expr_node, + .rhs = try transCreateNodeNumber(c, i, .int), + }); + const tmp_decl_node = try Tag.var_simple.create(c.arena, .{ + .name = mangled_name, + .init = try transCCast(c, &block_scope.base, base_stmt.getBeginLoc(), dst_element_qt, src_element_qt, value), + }); + try block_scope.statements.append(tmp_decl_node); + } + + const init_list = try c.arena.alloc(Node, num_elements); + for (init_list) |*init, init_index| { + const tmp_decl = block_scope.statements.items[init_index]; + const name = tmp_decl.castTag(.var_simple).?.data.name; + init.* = try Tag.identifier.create(c.arena, name); + } + + const vec_init = try Tag.array_init.create(c.arena, .{ + .cond = dst_type_node, + .cases = init_list, + }); + + const break_node = try Tag.break_val.create(c.arena, .{ + .label = block_scope.label, + .val = vec_init, + }); + try block_scope.statements.append(break_node); + return block_scope.complete(c); +} + +fn makeShuffleMask(c: *Context, scope: *Scope, expr: *const clang.ShuffleVectorExpr, vector_len: Node) TransError!Node { + const num_subexprs = expr.getNumSubExprs(); + assert(num_subexprs >= 3); // two source vectors + at least 1 index expression + const mask_len = num_subexprs - 2; + + const mask_type = try Tag.std_meta_vector.create(c.arena, .{ + .lhs = try transCreateNodeNumber(c, mask_len, .int), + .rhs = try Tag.type.create(c.arena, "i32"), + }); + + const init_list = try c.arena.alloc(Node, mask_len); + + for (init_list) |*init, i| { + const index_expr = try transExprCoercing(c, scope, expr.getExpr(@intCast(c_uint, i + 2)), .used); + const converted_index = try Tag.std_meta_shuffle_vector_index.create(c.arena, .{ .lhs = index_expr, .rhs = vector_len }); + init.* = converted_index; + } + + const mask_init = try Tag.array_init.create(c.arena, .{ + .cond = mask_type, + .cases = init_list, + }); + return Tag.@"comptime".create(c.arena, mask_init); +} + +/// @typeInfo(@TypeOf(vec_node)).Vector. +fn vectorTypeInfo(arena: *mem.Allocator, vec_node: Node, field: []const u8) TransError!Node { + const typeof_call = try Tag.typeof.create(arena, vec_node); + const typeinfo_call = try Tag.typeinfo.create(arena, typeof_call); + const vector_type_info = try Tag.field_access.create(arena, .{ .lhs = typeinfo_call, .field_name = "Vector" }); + return Tag.field_access.create(arena, .{ .lhs = vector_type_info, .field_name = field }); +} + +fn transShuffleVectorExpr( + c: *Context, + scope: *Scope, + expr: *const clang.ShuffleVectorExpr, +) TransError!Node { + const base_expr = @ptrCast(*const clang.Expr, expr); + const num_subexprs = expr.getNumSubExprs(); + if (num_subexprs < 3) return fail(c, error.UnsupportedTranslation, base_expr.getBeginLoc(), "ShuffleVector needs at least 1 index", .{}); + + const a = try transExpr(c, scope, expr.getExpr(0), .used); + const b = try transExpr(c, scope, expr.getExpr(1), .used); + + // clang requires first two arguments to __builtin_shufflevector to be same type + const vector_child_type = try vectorTypeInfo(c.arena, a, "child"); + const vector_len = try vectorTypeInfo(c.arena, a, "len"); + const shuffle_mask = try makeShuffleMask(c, scope, expr, vector_len); + + return Tag.shuffle.create(c.arena, .{ + .element_type = vector_child_type, + .a = a, + .b = b, + .mask_vector = shuffle_mask, + }); +} + /// Translate a "simple" offsetof expression containing exactly one component, /// when that component is of kind .Field - e.g. offsetof(mytype, myfield) fn transSimpleOffsetOfExpr( @@ -1935,6 +2067,10 @@ fn cIsEnum(qt: clang.QualType) bool { return qt.getCanonicalType().getTypeClass() == .Enum; } +fn cIsVector(qt: clang.QualType) bool { + return qt.getCanonicalType().getTypeClass() == .Vector; +} + /// Get the underlying int type of an enum. The C compiler chooses a signed int /// type that is large enough to hold all of the enum's values. It is not required /// to be the smallest possible type that can hold all the values. @@ -1991,6 +2127,11 @@ fn transCCast( // @bitCast(dest_type, intermediate_value) return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr }); } + if (cIsVector(src_type) or cIsVector(dst_type)) { + // C cast where at least 1 operand is a vector requires them to be same size + // @bitCast(dest_type, val) + return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); + } if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { // @intCast(dest_type, @ptrToInt(val)) const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr); @@ -2209,6 +2350,63 @@ fn transInitListExprArray( } } +fn transInitListExprVector( + c: *Context, + scope: *Scope, + loc: clang.SourceLocation, + expr: *const clang.InitListExpr, + ty: *const clang.Type, +) TransError!Node { + + const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr)); + const vector_type = try transQualType(c, scope, qt, loc); + const init_count = expr.getNumInits(); + + if (init_count == 0) { + return Tag.container_init.create(c.arena, .{ + .lhs = vector_type, + .inits = try c.arena.alloc(ast.Payload.ContainerInit.Initializer, 0), + }); + } + + var block_scope = try Scope.Block.init(c, scope, true); + defer block_scope.deinit(); + + // workaround for https://github.com/ziglang/zig/issues/8322 + // we store the initializers in temp variables and use those + // to initialize the vector. Eventually we can just directly + // construct the init_list from casted source members + var i: usize = 0; + while (i < init_count) : (i += 1) { + const mangled_name = try block_scope.makeMangledName(c, "tmp"); + const init_expr = expr.getInit(@intCast(c_uint, i)); + const tmp_decl_node = try Tag.var_simple.create(c.arena, .{ + .name = mangled_name, + .init = try transExpr(c, &block_scope.base, init_expr, .used), + }); + try block_scope.statements.append(tmp_decl_node); + } + + const init_list = try c.arena.alloc(Node, init_count); + for (init_list) |*init, init_index| { + const tmp_decl = block_scope.statements.items[init_index]; + const name = tmp_decl.castTag(.var_simple).?.data.name; + init.* = try Tag.identifier.create(c.arena, name); + } + + const array_init = try Tag.array_init.create(c.arena, .{ + .cond = vector_type, + .cases = init_list, + }); + const break_node = try Tag.break_val.create(c.arena, .{ + .label = block_scope.label, + .val = array_init, + }); + try block_scope.statements.append(break_node); + + return block_scope.complete(c); +} + fn transInitListExpr( c: *Context, scope: *Scope, @@ -2235,6 +2433,14 @@ fn transInitListExpr( expr, qual_type, )); + } else if (qual_type.isVectorType()) { + return maybeSuppressResult(c, scope, used, try transInitListExprVector( + c, + scope, + source_loc, + expr, + qual_type, + )); } else { const type_name = c.str(qual_type.getTypeClassName()); return fail(c, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name}); @@ -4085,6 +4291,15 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan }; return Tag.typeof.create(c.arena, underlying_expr); }, + .Vector => { + const vector_ty = @ptrCast(*const clang.VectorType, ty); + const num_elements = vector_ty.getNumElements(); + const element_qt = vector_ty.getElementType(); + return Tag.std_meta_vector.create(c.arena, .{ + .lhs = try transCreateNodeNumber(c, num_elements, .int), + .rhs = try transQualType(c, scope, element_qt, source_loc), + }); + }, else => { const type_name = c.str(ty.getTypeClassName()); return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name}); diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 4b595a7940..4be0fead97 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -66,6 +66,7 @@ pub const Node = extern union { @"enum", @"struct", @"union", + @"comptime", array_init, tuple, container_init, @@ -154,6 +155,8 @@ pub const Node = extern union { div_exact, /// @byteOffsetOf(lhs, rhs) byte_offset_of, + /// @shuffle(type, a, b, mask) + shuffle, negate, negate_wrap, @@ -172,6 +175,7 @@ pub const Node = extern union { sizeof, alignof, typeof, + typeinfo, type, optional_type, @@ -182,6 +186,10 @@ pub const Node = extern union { /// @import("std").meta.sizeof(operand) std_meta_sizeof, + /// @import("std").meta.shuffleVectorIndex(lhs, rhs) + std_meta_shuffle_vector_index, + /// @import("std").meta.Vector(lhs, rhs) + std_meta_vector, /// @import("std").mem.zeroes(operand) std_mem_zeroes, /// @import("std").mem.zeroInit(lhs, rhs) @@ -233,6 +241,7 @@ pub const Node = extern union { .std_mem_zeroes, .@"return", + .@"comptime", .discard, .std_math_Log2Int, .negate, @@ -255,6 +264,7 @@ pub const Node = extern union { .sizeof, .alignof, .typeof, + .typeinfo, => Payload.UnOp, .add, @@ -308,6 +318,8 @@ pub const Node = extern union { .align_cast, .array_access, .std_mem_zeroinit, + .std_meta_shuffle_vector_index, + .std_meta_vector, .ptr_cast, .div_exact, .byte_offset_of, @@ -346,6 +358,7 @@ pub const Node = extern union { .pub_inline_fn => Payload.PubInlineFn, .field_access => Payload.FieldAccess, .string_slice => Payload.StringSlice, + .shuffle => Payload.Shuffle, }; } @@ -678,6 +691,16 @@ pub const Payload = struct { end: usize, }, }; + + pub const Shuffle = struct { + base: Payload, + data: struct { + element_type: Node, + a: Node, + b: Node, + mask_vector: Node, + }, + }; }; /// Converts the nodes into a Zig ast. @@ -868,6 +891,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { const import_node = try renderStdImport(c, "mem", "zeroInit"); return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); }, + .std_meta_shuffle_vector_index => { + const payload = node.castTag(.std_meta_shuffle_vector_index).?.data; + const import_node = try renderStdImport(c, "meta", "shuffleVectorIndex"); + return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); + }, + .std_meta_vector => { + const payload = node.castTag(.std_meta_vector).?.data; + const import_node = try renderStdImport(c, "meta", "Vector"); + return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); + }, .call => { const payload = node.castTag(.call).?.data; const lhs = try renderNode(c, payload.lhs); @@ -964,6 +997,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { }, }); }, + .@"comptime" => { + const payload = node.castTag(.@"comptime").?.data; + return c.addNode(.{ + .tag = .@"comptime", + .main_token = try c.addToken(.keyword_comptime, "comptime"), + .data = .{ + .lhs = try renderNode(c, payload), + .rhs = undefined, + }, + }); + }, .type => { const payload = node.castTag(.type).?.data; return c.addNode(.{ @@ -1217,6 +1261,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { const payload = node.castTag(.sizeof).?.data; return renderBuiltinCall(c, "@sizeOf", &.{payload}); }, + .shuffle => { + const payload = node.castTag(.shuffle).?.data; + return renderBuiltinCall(c, "@shuffle", &.{ + payload.element_type, + payload.a, + payload.b, + payload.mask_vector, + }); + }, .alignof => { const payload = node.castTag(.alignof).?.data; return renderBuiltinCall(c, "@alignOf", &.{payload}); @@ -1225,6 +1278,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { const payload = node.castTag(.typeof).?.data; return renderBuiltinCall(c, "@TypeOf", &.{payload}); }, + .typeinfo => { + const payload = node.castTag(.typeinfo).?.data; + return renderBuiltinCall(c, "@typeInfo", &.{payload}); + }, .negate => return renderPrefixOp(c, node, .negation, .minus, "-"), .negate_wrap => return renderPrefixOp(c, node, .negation_wrap, .minus_percent, "-%"), .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"), @@ -2085,9 +2142,12 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { .sizeof, .alignof, .typeof, + .typeinfo, .std_meta_sizeof, .std_meta_cast, .std_meta_promoteIntLiteral, + .std_meta_vector, + .std_meta_shuffle_vector_index, .std_mem_zeroinit, .integer_literal, .float_literal, @@ -2118,6 +2178,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { .bool_to_int, .div_exact, .byte_offset_of, + .shuffle, => { // no grouping needed return renderNode(c, node); @@ -2185,6 +2246,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { .discard, .@"continue", .@"return", + .@"comptime", .usingnamespace_builtins, .while_true, .if_not_break, @@ -2327,6 +2389,8 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node _ = try c.addToken(.l_paren, "("); var arg_1: NodeIndex = 0; var arg_2: NodeIndex = 0; + var arg_3: NodeIndex = 0; + var arg_4: NodeIndex = 0; switch (args.len) { 0 => {}, 1 => { @@ -2337,18 +2401,41 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node _ = try c.addToken(.comma, ","); arg_2 = try renderNode(c, args[1]); }, + 4 => { + arg_1 = try renderNode(c, args[0]); + _ = try c.addToken(.comma, ","); + arg_2 = try renderNode(c, args[1]); + _ = try c.addToken(.comma, ","); + arg_3 = try renderNode(c, args[2]); + _ = try c.addToken(.comma, ","); + arg_4 = try renderNode(c, args[3]); + }, else => unreachable, // expand this function as needed. } _ = try c.addToken(.r_paren, ")"); - return c.addNode(.{ - .tag = .builtin_call_two, - .main_token = builtin_tok, - .data = .{ - .lhs = arg_1, - .rhs = arg_2, - }, - }); + if (args.len <= 2) { + return c.addNode(.{ + .tag = .builtin_call_two, + .main_token = builtin_tok, + .data = .{ + .lhs = arg_1, + .rhs = arg_2, + }, + }); + } else { + std.debug.assert(args.len == 4); + + const params = try c.listToSpan(&.{ arg_1, arg_2, arg_3, arg_4 }); + return c.addNode(.{ + .tag = .builtin_call, + .main_token = builtin_tok, + .data = .{ + .lhs = params.start, + .rhs = params.end, + }, + }); + } } fn renderVar(c: *Context, node: Node) !NodeIndex { diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 95e9e390a1..526371b792 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -2046,6 +2046,11 @@ bool ZigClangType_isRecordType(const ZigClangType *self) { return casted->isRecordType(); } +bool ZigClangType_isVectorType(const ZigClangType *self) { + auto casted = reinterpret_cast(self); + return casted->isVectorType(); +} + bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx) { @@ -2738,6 +2743,16 @@ struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBina return bitcast(casted->getType()); } +const struct ZigClangExpr *ZigClangConvertVectorExpr_getSrcExpr(const struct ZigClangConvertVectorExpr *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getSrcExpr()); +} + +struct ZigClangQualType ZigClangConvertVectorExpr_getTypeSourceInfo_getType(const struct ZigClangConvertVectorExpr *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getTypeSourceInfo()->getType()); +} + struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *self) { auto casted = reinterpret_cast(self); return bitcast(casted->getDecayedType()); @@ -2843,6 +2858,16 @@ struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl return bitcast(casted->getType()); } +struct ZigClangQualType ZigClangVectorType_getElementType(const struct ZigClangVectorType *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getElementType()); +} + +unsigned ZigClangVectorType_getNumElements(const struct ZigClangVectorType *self) { + auto casted = reinterpret_cast(self); + return casted->getNumElements(); +} + const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) { auto casted = reinterpret_cast(self); return reinterpret_cast(casted->getCond()); @@ -2922,6 +2947,15 @@ struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc( return bitcast(casted->getBeginLoc()); } +unsigned ZigClangShuffleVectorExpr_getNumSubExprs(const ZigClangShuffleVectorExpr *self) { + auto casted = reinterpret_cast(self); + return casted->getNumSubExprs(); +} + +const struct ZigClangExpr *ZigClangShuffleVectorExpr_getExpr(const struct ZigClangShuffleVectorExpr *self, unsigned idx) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getExpr(idx)); +} enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind( const struct ZigClangUnaryExprOrTypeTraitExpr *self) diff --git a/src/zig_clang.h b/src/zig_clang.h index 59eacf7587..b9d875c61a 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -1064,6 +1064,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self); ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self); ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self); ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self); +ZIG_EXTERN_C bool ZigClangType_isVectorType(const struct ZigClangType *self); ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx); ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self); ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self); @@ -1199,6 +1200,9 @@ ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getLHS(const stru ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getRHS(const struct ZigClangBinaryOperator *); ZIG_EXTERN_C struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBinaryOperator *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangConvertVectorExpr_getSrcExpr(const struct ZigClangConvertVectorExpr *); +ZIG_EXTERN_C struct ZigClangQualType ZigClangConvertVectorExpr_getTypeSourceInfo_getType(const struct ZigClangConvertVectorExpr *); + ZIG_EXTERN_C struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *); ZIG_EXTERN_C const struct ZigClangCompoundStmt *ZigClangStmtExpr_getSubStmt(const struct ZigClangStmtExpr *); @@ -1228,6 +1232,9 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(con ZIG_EXTERN_C struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl *); +ZIG_EXTERN_C struct ZigClangQualType ZigClangVectorType_getElementType(const struct ZigClangVectorType *); +ZIG_EXTERN_C unsigned ZigClangVectorType_getNumElements(const struct ZigClangVectorType *); + ZIG_EXTERN_C const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *); ZIG_EXTERN_C const struct ZigClangStmt *ZigClangWhileStmt_getBody(const struct ZigClangWhileStmt *); @@ -1252,6 +1259,9 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangUnaryExprOrTypeTraitExpr_getTypeOfA ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(const struct ZigClangUnaryExprOrTypeTraitExpr *); ZIG_EXTERN_C enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind(const struct ZigClangUnaryExprOrTypeTraitExpr *); +ZIG_EXTERN_C unsigned ZigClangShuffleVectorExpr_getNumSubExprs(const struct ZigClangShuffleVectorExpr *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangShuffleVectorExpr_getExpr(const struct ZigClangShuffleVectorExpr *, unsigned); + ZIG_EXTERN_C const struct ZigClangStmt *ZigClangDoStmt_getBody(const struct ZigClangDoStmt *); ZIG_EXTERN_C const struct ZigClangExpr *ZigClangDoStmt_getCond(const struct ZigClangDoStmt *); diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 6cac9cd79d..8f4c568aa2 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -1308,4 +1308,106 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted \\} , ""); + + cases.add("basic vector expressions", + \\#include + \\#include + \\typedef int16_t __v8hi __attribute__((__vector_size__(16))); + \\int main(int argc, char**argv) { + \\ __v8hi uninitialized; + \\ __v8hi empty_init = {}; + \\ __v8hi partial_init = {0, 1, 2, 3}; + \\ + \\ __v8hi a = {0, 1, 2, 3, 4, 5, 6, 7}; + \\ __v8hi b = (__v8hi) {100, 200, 300, 400, 500, 600, 700, 800}; + \\ + \\ __v8hi sum = a + b; + \\ for (int i = 0; i < 8; i++) { + \\ if (sum[i] != a[i] + b[i]) abort(); + \\ } + \\ return 0; + \\} + , ""); + + cases.add("__builtin_shufflevector", + \\#include + \\#include + \\typedef int16_t __v4hi __attribute__((__vector_size__(8))); + \\typedef int16_t __v8hi __attribute__((__vector_size__(16))); + \\int main(int argc, char**argv) { + \\ __v8hi v8_a = {0, 1, 2, 3, 4, 5, 6, 7}; + \\ __v8hi v8_b = {100, 200, 300, 400, 500, 600, 700, 800}; + \\ __v8hi shuffled = __builtin_shufflevector(v8_a, v8_b, 0, 1, 2, 3, 8, 9, 10, 11); + \\ for (int i = 0; i < 8; i++) { + \\ if (i < 4) { + \\ if (shuffled[i] != v8_a[i]) abort(); + \\ } else { + \\ if (shuffled[i] != v8_b[i - 4]) abort(); + \\ } + \\ } + \\ shuffled = __builtin_shufflevector( + \\ (__v8hi) {-1, -1, -1, -1, -1, -1, -1, -1}, + \\ (__v8hi) {42, 42, 42, 42, 42, 42, 42, 42}, + \\ 0, 1, 2, 3, 8, 9, 10, 11 + \\ ); + \\ for (int i = 0; i < 8; i++) { + \\ if (i < 4) { + \\ if (shuffled[i] != -1) abort(); + \\ } else { + \\ if (shuffled[i] != 42) abort(); + \\ } + \\ } + \\ __v4hi shuffled_to_fewer_elements = __builtin_shufflevector(v8_a, v8_b, 0, 1, 8, 9); + \\ for (int i = 0; i < 4; i++) { + \\ if (i < 2) { + \\ if (shuffled_to_fewer_elements[i] != v8_a[i]) abort(); + \\ } else { + \\ if (shuffled_to_fewer_elements[i] != v8_b[i - 2]) abort(); + \\ } + \\ } + \\ __v4hi v4_a = {0, 1, 2, 3}; + \\ __v4hi v4_b = {100, 200, 300, 400}; + \\ __v8hi shuffled_to_more_elements = __builtin_shufflevector(v4_a, v4_b, 0, 1, 2, 3, 4, 5, 6, 7); + \\ for (int i = 0; i < 4; i++) { + \\ if (shuffled_to_more_elements[i] != v4_a[i]) abort(); + \\ if (shuffled_to_more_elements[i + 4] != v4_b[i]) abort(); + \\ } + \\ return 0; + \\} + , ""); + + cases.add("__builtin_convertvector", + \\#include + \\#include + \\typedef int16_t __v8hi __attribute__((__vector_size__(16))); + \\typedef uint16_t __v8hu __attribute__((__vector_size__(16))); + \\int main(int argc, char**argv) { + \\ __v8hi signed_vector = { 1, 2, 3, 4, -1, -2, -3,-4}; + \\ __v8hu unsigned_vector = __builtin_convertvector(signed_vector, __v8hu); + \\ + \\ for (int i = 0; i < 8; i++) { + \\ if (unsigned_vector[i] != (uint16_t)signed_vector[i]) abort(); + \\ } + \\ return 0; + \\} + , ""); + + cases.add("vector casting", + \\#include + \\#include + \\typedef int8_t __v8qi __attribute__((__vector_size__(8))); + \\typedef uint8_t __v8qu __attribute__((__vector_size__(8))); + \\int main(int argc, char**argv) { + \\ __v8qi signed_vector = { 1, 2, 3, 4, -1, -2, -3,-4}; + \\ + \\ uint64_t big_int = (uint64_t) signed_vector; + \\ if (big_int != 0x01020304FFFEFDFCULL && big_int != 0xFCFDFEFF04030201ULL) abort(); + \\ __v8qu unsigned_vector = (__v8qu) big_int; + \\ for (int i = 0; i < 8; i++) { + \\ if (unsigned_vector[i] != (uint8_t)signed_vector[i] && unsigned_vector[i] != (uint8_t)signed_vector[7 - i]) abort(); + \\ } + \\ return 0; + \\} + , ""); + }