mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
translate-c: Add support for vector expressions
Includes vector types, __builtin_shufflevector, and __builtin_convertvector
This commit is contained in:
parent
38d8aab4d2
commit
8de14a98a6
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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});
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 *);
|
||||
|
||||
|
||||
@ -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;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user