Commit 8de14a98a6
Changed files (7)
lib
std
src
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
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 {
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;
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.<field>
+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});
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<const clang::Type *>(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<const clang::ConvertVectorExpr *>(self);
+ return reinterpret_cast<const struct ZigClangExpr *>(casted->getSrcExpr());
+}
+
+struct ZigClangQualType ZigClangConvertVectorExpr_getTypeSourceInfo_getType(const struct ZigClangConvertVectorExpr *self) {
+ auto casted = reinterpret_cast<const clang::ConvertVectorExpr *>(self);
+ return bitcast(casted->getTypeSourceInfo()->getType());
+}
+
struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *self) {
auto casted = reinterpret_cast<const clang::DecayedType *>(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<const clang::VectorType *>(self);
+ return bitcast(casted->getElementType());
+}
+
+unsigned ZigClangVectorType_getNumElements(const struct ZigClangVectorType *self) {
+ auto casted = reinterpret_cast<const clang::VectorType *>(self);
+ return casted->getNumElements();
+}
+
const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) {
auto casted = reinterpret_cast<const clang::WhileStmt *>(self);
return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond());
@@ -2922,6 +2947,15 @@ struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(
return bitcast(casted->getBeginLoc());
}
+unsigned ZigClangShuffleVectorExpr_getNumSubExprs(const ZigClangShuffleVectorExpr *self) {
+ auto casted = reinterpret_cast<const clang::ShuffleVectorExpr *>(self);
+ return casted->getNumSubExprs();
+}
+
+const struct ZigClangExpr *ZigClangShuffleVectorExpr_getExpr(const struct ZigClangShuffleVectorExpr *self, unsigned idx) {
+ auto casted = reinterpret_cast<const clang::ShuffleVectorExpr *>(self);
+ return reinterpret_cast<const struct ZigClangExpr *>(casted->getExpr(idx));
+}
enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind(
const struct ZigClangUnaryExprOrTypeTraitExpr *self)
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 *);
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 <stdlib.h>
+ \\#include <stdint.h>
+ \\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 <stdlib.h>
+ \\#include <stdint.h>
+ \\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 <stdlib.h>
+ \\#include <stdint.h>
+ \\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 <stdlib.h>
+ \\#include <stdint.h>
+ \\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;
+ \\}
+ , "");
+
}