translate-c: Add support for vector expressions

Includes vector types, __builtin_shufflevector, and __builtin_convertvector
This commit is contained in:
Evan Haas 2021-03-08 07:01:19 -08:00 committed by Andrew Kelley
parent 38d8aab4d2
commit 8de14a98a6
7 changed files with 515 additions and 8 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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});

View File

@ -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 {

View File

@ -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)

View File

@ -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 *);

View File

@ -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;
\\}
, "");
}