authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-03-08 07:01:19-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-06 11:22:27-07:00
log8de14a98a68752cc834848343f2e7867ee8ca6c9
tree7e6bc3259ec3926054830613d63025afa8e19117
parent38d8aab4d283efe2f43c7e18411f6df7e1c2d04b

translate-c: Add support for vector expressions

Includes vector types, __builtin_shufflevector, and __builtin_convertvector

7 files changed, 515 insertions(+), 8 deletions(-)

lib/std/meta.zig+32
......@@ -1297,3 +1297,35 @@ pub fn globalOption(comptime name: []const u8, comptime T: type) ?T {
12971297 return null;
12981298 return @as(T, @field(root, name));
12991299}
1300
1301/// This function is for translate-c and is not intended for general use.
1302/// Convert from clang __builtin_shufflevector index to Zig @shuffle index
1303/// clang requires __builtin_shufflevector index arguments to be integer constants.
1304/// negative values for `this_index` indicate "don't care" so we arbitrarily choose 0
1305/// clang enforces that `this_index` is less than the total number of vector elements
1306/// See https://ziglang.org/documentation/master/#shuffle
1307/// See https://clang.llvm.org/docs/LanguageExtensions.html#langext-builtin-shufflevector
1308pub fn shuffleVectorIndex(comptime this_index: c_int, comptime source_vector_len: usize) i32 {
1309 if (this_index <= 0) return 0;
1310
1311 const positive_index = @intCast(usize, this_index);
1312 if (positive_index < source_vector_len) return @intCast(i32, this_index);
1313 const b_index = positive_index - source_vector_len;
1314 return ~@intCast(i32, b_index);
1315}
1316
1317test "shuffleVectorIndex" {
1318 const vector_len: usize = 4;
1319
1320 testing.expect(shuffleVectorIndex(-1, vector_len) == 0);
1321
1322 testing.expect(shuffleVectorIndex(0, vector_len) == 0);
1323 testing.expect(shuffleVectorIndex(1, vector_len) == 1);
1324 testing.expect(shuffleVectorIndex(2, vector_len) == 2);
1325 testing.expect(shuffleVectorIndex(3, vector_len) == 3);
1326
1327 testing.expect(shuffleVectorIndex(4, vector_len) == -1);
1328 testing.expect(shuffleVectorIndex(5, vector_len) == -2);
1329 testing.expect(shuffleVectorIndex(6, vector_len) == -3);
1330 testing.expect(shuffleVectorIndex(7, vector_len) == -4);
1331}
\ No newline at end of file
src/clang.zig+27
......@@ -300,6 +300,14 @@ pub const ConstantExpr = opaque {};
300300
301301pub const ContinueStmt = opaque {};
302302
303pub const ConvertVectorExpr = opaque {
304 pub const getSrcExpr = ZigClangConvertVectorExpr_getSrcExpr;
305 extern fn ZigClangConvertVectorExpr_getSrcExpr(*const ConvertVectorExpr) *const Expr;
306
307 pub const getTypeSourceInfo_getType = ZigClangConvertVectorExpr_getTypeSourceInfo_getType;
308 extern fn ZigClangConvertVectorExpr_getTypeSourceInfo_getType(*const ConvertVectorExpr) QualType;
309};
310
303311pub const DecayedType = opaque {
304312 pub const getDecayedType = ZigClangDecayedType_getDecayedType;
305313 extern fn ZigClangDecayedType_getDecayedType(*const DecayedType) QualType;
......@@ -748,6 +756,14 @@ pub const ReturnStmt = opaque {
748756 extern fn ZigClangReturnStmt_getRetValue(*const ReturnStmt) ?*const Expr;
749757};
750758
759pub const ShuffleVectorExpr = opaque {
760 pub const getNumSubExprs = ZigClangShuffleVectorExpr_getNumSubExprs;
761 extern fn ZigClangShuffleVectorExpr_getNumSubExprs(*const ShuffleVectorExpr) c_uint;
762
763 pub const getExpr = ZigClangShuffleVectorExpr_getExpr;
764 extern fn ZigClangShuffleVectorExpr_getExpr(*const ShuffleVectorExpr, c_uint) *const Expr;
765};
766
751767pub const SourceManager = opaque {
752768 pub const getSpellingLoc = ZigClangSourceManager_getSpellingLoc;
753769 extern fn ZigClangSourceManager_getSpellingLoc(*const SourceManager, Loc: SourceLocation) SourceLocation;
......@@ -837,6 +853,9 @@ pub const Type = opaque {
837853 pub const isRecordType = ZigClangType_isRecordType;
838854 extern fn ZigClangType_isRecordType(*const Type) bool;
839855
856 pub const isVectorType = ZigClangType_isVectorType;
857 extern fn ZigClangType_isVectorType(*const Type) bool;
858
840859 pub const isIncompleteOrZeroLengthArrayType = ZigClangType_isIncompleteOrZeroLengthArrayType;
841860 extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(*const Type, *const ASTContext) bool;
842861
......@@ -937,6 +956,14 @@ pub const VarDecl = opaque {
937956 extern fn ZigClangVarDecl_getTypeSourceInfo_getType(*const VarDecl) QualType;
938957};
939958
959pub const VectorType = opaque {
960 pub const getElementType = ZigClangVectorType_getElementType;
961 extern fn ZigClangVectorType_getElementType(*const VectorType) QualType;
962
963 pub const getNumElements = ZigClangVectorType_getNumElements;
964 extern fn ZigClangVectorType_getNumElements(*const VectorType) c_uint;
965};
966
940967pub const WhileStmt = opaque {
941968 pub const getCond = ZigClangWhileStmt_getCond;
942969 extern fn ZigClangWhileStmt_getCond(*const WhileStmt) *const Expr;
src/translate_c.zig+215
......@@ -1123,6 +1123,16 @@ fn transStmt(
11231123 const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, stmt);
11241124 return transExpr(c, scope, gen_sel.getResultExpr(), result_used);
11251125 },
1126 .ConvertVectorExprClass => {
1127 const conv_vec = @ptrCast(*const clang.ConvertVectorExpr, stmt);
1128 const conv_vec_node = try transConvertVectorExpr(c, scope, stmt.getBeginLoc(), conv_vec);
1129 return maybeSuppressResult(c, scope, result_used, conv_vec_node);
1130 },
1131 .ShuffleVectorExprClass => {
1132 const shuffle_vec_expr = @ptrCast(*const clang.ShuffleVectorExpr, stmt);
1133 const shuffle_vec_node = try transShuffleVectorExpr(c, scope, shuffle_vec_expr);
1134 return maybeSuppressResult(c, scope, result_used, shuffle_vec_node);
1135 },
11261136 // When adding new cases here, see comment for maybeBlockify()
11271137 else => {
11281138 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});
......@@ -1130,6 +1140,128 @@ fn transStmt(
11301140 }
11311141}
11321142
1143/// See https://clang.llvm.org/docs/LanguageExtensions.html#langext-builtin-convertvector
1144fn transConvertVectorExpr(
1145 c: *Context,
1146 scope: *Scope,
1147 source_loc: clang.SourceLocation,
1148 expr: *const clang.ConvertVectorExpr,
1149) TransError!Node {
1150 const base_stmt = @ptrCast(*const clang.Stmt, expr);
1151
1152 var block_scope = try Scope.Block.init(c, scope, true);
1153 defer block_scope.deinit();
1154
1155 const src_expr = expr.getSrcExpr();
1156 const src_type = qualTypeCanon(src_expr.getType());
1157 const src_vector_ty = @ptrCast(*const clang.VectorType, src_type);
1158 const src_element_qt = src_vector_ty.getElementType();
1159 const src_element_type_node = try transQualType(c, &block_scope.base, src_element_qt, base_stmt.getBeginLoc());
1160
1161 const src_expr_node = try transExpr(c, &block_scope.base, src_expr, .used);
1162
1163 const dst_qt = expr.getTypeSourceInfo_getType();
1164 const dst_type_node = try transQualType(c, &block_scope.base, dst_qt, base_stmt.getBeginLoc());
1165 const dst_vector_ty = @ptrCast(*const clang.VectorType, qualTypeCanon(dst_qt));
1166 const num_elements = dst_vector_ty.getNumElements();
1167 const dst_element_qt = dst_vector_ty.getElementType();
1168
1169 // workaround for https://github.com/ziglang/zig/issues/8322
1170 // we store the casted results into temp variables and use those
1171 // to initialize the vector. Eventually we can just directly
1172 // construct the init_list from casted source members
1173 var i: usize = 0;
1174 while (i < num_elements) : (i += 1) {
1175 const mangled_name = try block_scope.makeMangledName(c, "tmp");
1176 const value = try Tag.array_access.create(c.arena, .{
1177 .lhs = src_expr_node,
1178 .rhs = try transCreateNodeNumber(c, i, .int),
1179 });
1180 const tmp_decl_node = try Tag.var_simple.create(c.arena, .{
1181 .name = mangled_name,
1182 .init = try transCCast(c, &block_scope.base, base_stmt.getBeginLoc(), dst_element_qt, src_element_qt, value),
1183 });
1184 try block_scope.statements.append(tmp_decl_node);
1185 }
1186
1187 const init_list = try c.arena.alloc(Node, num_elements);
1188 for (init_list) |*init, init_index| {
1189 const tmp_decl = block_scope.statements.items[init_index];
1190 const name = tmp_decl.castTag(.var_simple).?.data.name;
1191 init.* = try Tag.identifier.create(c.arena, name);
1192 }
1193
1194 const vec_init = try Tag.array_init.create(c.arena, .{
1195 .cond = dst_type_node,
1196 .cases = init_list,
1197 });
1198
1199 const break_node = try Tag.break_val.create(c.arena, .{
1200 .label = block_scope.label,
1201 .val = vec_init,
1202 });
1203 try block_scope.statements.append(break_node);
1204 return block_scope.complete(c);
1205}
1206
1207fn makeShuffleMask(c: *Context, scope: *Scope, expr: *const clang.ShuffleVectorExpr, vector_len: Node) TransError!Node {
1208 const num_subexprs = expr.getNumSubExprs();
1209 assert(num_subexprs >= 3); // two source vectors + at least 1 index expression
1210 const mask_len = num_subexprs - 2;
1211
1212 const mask_type = try Tag.std_meta_vector.create(c.arena, .{
1213 .lhs = try transCreateNodeNumber(c, mask_len, .int),
1214 .rhs = try Tag.type.create(c.arena, "i32"),
1215 });
1216
1217 const init_list = try c.arena.alloc(Node, mask_len);
1218
1219 for (init_list) |*init, i| {
1220 const index_expr = try transExprCoercing(c, scope, expr.getExpr(@intCast(c_uint, i + 2)), .used);
1221 const converted_index = try Tag.std_meta_shuffle_vector_index.create(c.arena, .{ .lhs = index_expr, .rhs = vector_len });
1222 init.* = converted_index;
1223 }
1224
1225 const mask_init = try Tag.array_init.create(c.arena, .{
1226 .cond = mask_type,
1227 .cases = init_list,
1228 });
1229 return Tag.@"comptime".create(c.arena, mask_init);
1230}
1231
1232/// @typeInfo(@TypeOf(vec_node)).Vector.<field>
1233fn vectorTypeInfo(arena: *mem.Allocator, vec_node: Node, field: []const u8) TransError!Node {
1234 const typeof_call = try Tag.typeof.create(arena, vec_node);
1235 const typeinfo_call = try Tag.typeinfo.create(arena, typeof_call);
1236 const vector_type_info = try Tag.field_access.create(arena, .{ .lhs = typeinfo_call, .field_name = "Vector" });
1237 return Tag.field_access.create(arena, .{ .lhs = vector_type_info, .field_name = field });
1238}
1239
1240fn transShuffleVectorExpr(
1241 c: *Context,
1242 scope: *Scope,
1243 expr: *const clang.ShuffleVectorExpr,
1244) TransError!Node {
1245 const base_expr = @ptrCast(*const clang.Expr, expr);
1246 const num_subexprs = expr.getNumSubExprs();
1247 if (num_subexprs < 3) return fail(c, error.UnsupportedTranslation, base_expr.getBeginLoc(), "ShuffleVector needs at least 1 index", .{});
1248
1249 const a = try transExpr(c, scope, expr.getExpr(0), .used);
1250 const b = try transExpr(c, scope, expr.getExpr(1), .used);
1251
1252 // clang requires first two arguments to __builtin_shufflevector to be same type
1253 const vector_child_type = try vectorTypeInfo(c.arena, a, "child");
1254 const vector_len = try vectorTypeInfo(c.arena, a, "len");
1255 const shuffle_mask = try makeShuffleMask(c, scope, expr, vector_len);
1256
1257 return Tag.shuffle.create(c.arena, .{
1258 .element_type = vector_child_type,
1259 .a = a,
1260 .b = b,
1261 .mask_vector = shuffle_mask,
1262 });
1263}
1264
11331265/// Translate a "simple" offsetof expression containing exactly one component,
11341266/// when that component is of kind .Field - e.g. offsetof(mytype, myfield)
11351267fn transSimpleOffsetOfExpr(
......@@ -1935,6 +2067,10 @@ fn cIsEnum(qt: clang.QualType) bool {
19352067 return qt.getCanonicalType().getTypeClass() == .Enum;
19362068}
19372069
2070fn cIsVector(qt: clang.QualType) bool {
2071 return qt.getCanonicalType().getTypeClass() == .Vector;
2072}
2073
19382074/// Get the underlying int type of an enum. The C compiler chooses a signed int
19392075/// type that is large enough to hold all of the enum's values. It is not required
19402076/// to be the smallest possible type that can hold all the values.
......@@ -1991,6 +2127,11 @@ fn transCCast(
19912127 // @bitCast(dest_type, intermediate_value)
19922128 return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr });
19932129 }
2130 if (cIsVector(src_type) or cIsVector(dst_type)) {
2131 // C cast where at least 1 operand is a vector requires them to be same size
2132 // @bitCast(dest_type, val)
2133 return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
2134 }
19942135 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
19952136 // @intCast(dest_type, @ptrToInt(val))
19962137 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
......@@ -2209,6 +2350,63 @@ fn transInitListExprArray(
22092350 }
22102351}
22112352
2353fn transInitListExprVector(
2354 c: *Context,
2355 scope: *Scope,
2356 loc: clang.SourceLocation,
2357 expr: *const clang.InitListExpr,
2358 ty: *const clang.Type,
2359) TransError!Node {
2360
2361 const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr));
2362 const vector_type = try transQualType(c, scope, qt, loc);
2363 const init_count = expr.getNumInits();
2364
2365 if (init_count == 0) {
2366 return Tag.container_init.create(c.arena, .{
2367 .lhs = vector_type,
2368 .inits = try c.arena.alloc(ast.Payload.ContainerInit.Initializer, 0),
2369 });
2370 }
2371
2372 var block_scope = try Scope.Block.init(c, scope, true);
2373 defer block_scope.deinit();
2374
2375 // workaround for https://github.com/ziglang/zig/issues/8322
2376 // we store the initializers in temp variables and use those
2377 // to initialize the vector. Eventually we can just directly
2378 // construct the init_list from casted source members
2379 var i: usize = 0;
2380 while (i < init_count) : (i += 1) {
2381 const mangled_name = try block_scope.makeMangledName(c, "tmp");
2382 const init_expr = expr.getInit(@intCast(c_uint, i));
2383 const tmp_decl_node = try Tag.var_simple.create(c.arena, .{
2384 .name = mangled_name,
2385 .init = try transExpr(c, &block_scope.base, init_expr, .used),
2386 });
2387 try block_scope.statements.append(tmp_decl_node);
2388 }
2389
2390 const init_list = try c.arena.alloc(Node, init_count);
2391 for (init_list) |*init, init_index| {
2392 const tmp_decl = block_scope.statements.items[init_index];
2393 const name = tmp_decl.castTag(.var_simple).?.data.name;
2394 init.* = try Tag.identifier.create(c.arena, name);
2395 }
2396
2397 const array_init = try Tag.array_init.create(c.arena, .{
2398 .cond = vector_type,
2399 .cases = init_list,
2400 });
2401 const break_node = try Tag.break_val.create(c.arena, .{
2402 .label = block_scope.label,
2403 .val = array_init,
2404 });
2405 try block_scope.statements.append(break_node);
2406
2407 return block_scope.complete(c);
2408}
2409
22122410fn transInitListExpr(
22132411 c: *Context,
22142412 scope: *Scope,
......@@ -2235,6 +2433,14 @@ fn transInitListExpr(
22352433 expr,
22362434 qual_type,
22372435 ));
2436 } else if (qual_type.isVectorType()) {
2437 return maybeSuppressResult(c, scope, used, try transInitListExprVector(
2438 c,
2439 scope,
2440 source_loc,
2441 expr,
2442 qual_type,
2443 ));
22382444 } else {
22392445 const type_name = c.str(qual_type.getTypeClassName());
22402446 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
40854291 };
40864292 return Tag.typeof.create(c.arena, underlying_expr);
40874293 },
4294 .Vector => {
4295 const vector_ty = @ptrCast(*const clang.VectorType, ty);
4296 const num_elements = vector_ty.getNumElements();
4297 const element_qt = vector_ty.getElementType();
4298 return Tag.std_meta_vector.create(c.arena, .{
4299 .lhs = try transCreateNodeNumber(c, num_elements, .int),
4300 .rhs = try transQualType(c, scope, element_qt, source_loc),
4301 });
4302 },
40884303 else => {
40894304 const type_name = c.str(ty.getTypeClassName());
40904305 return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});
src/translate_c/ast.zig+95-8
......@@ -66,6 +66,7 @@ pub const Node = extern union {
6666 @"enum",
6767 @"struct",
6868 @"union",
69 @"comptime",
6970 array_init,
7071 tuple,
7172 container_init,
......@@ -154,6 +155,8 @@ pub const Node = extern union {
154155 div_exact,
155156 /// @byteOffsetOf(lhs, rhs)
156157 byte_offset_of,
158 /// @shuffle(type, a, b, mask)
159 shuffle,
157160
158161 negate,
159162 negate_wrap,
......@@ -172,6 +175,7 @@ pub const Node = extern union {
172175 sizeof,
173176 alignof,
174177 typeof,
178 typeinfo,
175179 type,
176180
177181 optional_type,
......@@ -182,6 +186,10 @@ pub const Node = extern union {
182186
183187 /// @import("std").meta.sizeof(operand)
184188 std_meta_sizeof,
189 /// @import("std").meta.shuffleVectorIndex(lhs, rhs)
190 std_meta_shuffle_vector_index,
191 /// @import("std").meta.Vector(lhs, rhs)
192 std_meta_vector,
185193 /// @import("std").mem.zeroes(operand)
186194 std_mem_zeroes,
187195 /// @import("std").mem.zeroInit(lhs, rhs)
......@@ -233,6 +241,7 @@ pub const Node = extern union {
233241
234242 .std_mem_zeroes,
235243 .@"return",
244 .@"comptime",
236245 .discard,
237246 .std_math_Log2Int,
238247 .negate,
......@@ -255,6 +264,7 @@ pub const Node = extern union {
255264 .sizeof,
256265 .alignof,
257266 .typeof,
267 .typeinfo,
258268 => Payload.UnOp,
259269
260270 .add,
......@@ -308,6 +318,8 @@ pub const Node = extern union {
308318 .align_cast,
309319 .array_access,
310320 .std_mem_zeroinit,
321 .std_meta_shuffle_vector_index,
322 .std_meta_vector,
311323 .ptr_cast,
312324 .div_exact,
313325 .byte_offset_of,
......@@ -346,6 +358,7 @@ pub const Node = extern union {
346358 .pub_inline_fn => Payload.PubInlineFn,
347359 .field_access => Payload.FieldAccess,
348360 .string_slice => Payload.StringSlice,
361 .shuffle => Payload.Shuffle,
349362 };
350363 }
351364
......@@ -678,6 +691,16 @@ pub const Payload = struct {
678691 end: usize,
679692 },
680693 };
694
695 pub const Shuffle = struct {
696 base: Payload,
697 data: struct {
698 element_type: Node,
699 a: Node,
700 b: Node,
701 mask_vector: Node,
702 },
703 };
681704};
682705
683706/// Converts the nodes into a Zig ast.
......@@ -868,6 +891,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
868891 const import_node = try renderStdImport(c, "mem", "zeroInit");
869892 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
870893 },
894 .std_meta_shuffle_vector_index => {
895 const payload = node.castTag(.std_meta_shuffle_vector_index).?.data;
896 const import_node = try renderStdImport(c, "meta", "shuffleVectorIndex");
897 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
898 },
899 .std_meta_vector => {
900 const payload = node.castTag(.std_meta_vector).?.data;
901 const import_node = try renderStdImport(c, "meta", "Vector");
902 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
903 },
871904 .call => {
872905 const payload = node.castTag(.call).?.data;
873906 const lhs = try renderNode(c, payload.lhs);
......@@ -964,6 +997,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
964997 },
965998 });
966999 },
1000 .@"comptime" => {
1001 const payload = node.castTag(.@"comptime").?.data;
1002 return c.addNode(.{
1003 .tag = .@"comptime",
1004 .main_token = try c.addToken(.keyword_comptime, "comptime"),
1005 .data = .{
1006 .lhs = try renderNode(c, payload),
1007 .rhs = undefined,
1008 },
1009 });
1010 },
9671011 .type => {
9681012 const payload = node.castTag(.type).?.data;
9691013 return c.addNode(.{
......@@ -1217,6 +1261,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
12171261 const payload = node.castTag(.sizeof).?.data;
12181262 return renderBuiltinCall(c, "@sizeOf", &.{payload});
12191263 },
1264 .shuffle => {
1265 const payload = node.castTag(.shuffle).?.data;
1266 return renderBuiltinCall(c, "@shuffle", &.{
1267 payload.element_type,
1268 payload.a,
1269 payload.b,
1270 payload.mask_vector,
1271 });
1272 },
12201273 .alignof => {
12211274 const payload = node.castTag(.alignof).?.data;
12221275 return renderBuiltinCall(c, "@alignOf", &.{payload});
......@@ -1225,6 +1278,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
12251278 const payload = node.castTag(.typeof).?.data;
12261279 return renderBuiltinCall(c, "@TypeOf", &.{payload});
12271280 },
1281 .typeinfo => {
1282 const payload = node.castTag(.typeinfo).?.data;
1283 return renderBuiltinCall(c, "@typeInfo", &.{payload});
1284 },
12281285 .negate => return renderPrefixOp(c, node, .negation, .minus, "-"),
12291286 .negate_wrap => return renderPrefixOp(c, node, .negation_wrap, .minus_percent, "-%"),
12301287 .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"),
......@@ -2085,9 +2142,12 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
20852142 .sizeof,
20862143 .alignof,
20872144 .typeof,
2145 .typeinfo,
20882146 .std_meta_sizeof,
20892147 .std_meta_cast,
20902148 .std_meta_promoteIntLiteral,
2149 .std_meta_vector,
2150 .std_meta_shuffle_vector_index,
20912151 .std_mem_zeroinit,
20922152 .integer_literal,
20932153 .float_literal,
......@@ -2118,6 +2178,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
21182178 .bool_to_int,
21192179 .div_exact,
21202180 .byte_offset_of,
2181 .shuffle,
21212182 => {
21222183 // no grouping needed
21232184 return renderNode(c, node);
......@@ -2185,6 +2246,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
21852246 .discard,
21862247 .@"continue",
21872248 .@"return",
2249 .@"comptime",
21882250 .usingnamespace_builtins,
21892251 .while_true,
21902252 .if_not_break,
......@@ -2327,6 +2389,8 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node
23272389 _ = try c.addToken(.l_paren, "(");
23282390 var arg_1: NodeIndex = 0;
23292391 var arg_2: NodeIndex = 0;
2392 var arg_3: NodeIndex = 0;
2393 var arg_4: NodeIndex = 0;
23302394 switch (args.len) {
23312395 0 => {},
23322396 1 => {
......@@ -2337,18 +2401,41 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node
23372401 _ = try c.addToken(.comma, ",");
23382402 arg_2 = try renderNode(c, args[1]);
23392403 },
2404 4 => {
2405 arg_1 = try renderNode(c, args[0]);
2406 _ = try c.addToken(.comma, ",");
2407 arg_2 = try renderNode(c, args[1]);
2408 _ = try c.addToken(.comma, ",");
2409 arg_3 = try renderNode(c, args[2]);
2410 _ = try c.addToken(.comma, ",");
2411 arg_4 = try renderNode(c, args[3]);
2412 },
23402413 else => unreachable, // expand this function as needed.
23412414 }
23422415
23432416 _ = try c.addToken(.r_paren, ")");
2344 return c.addNode(.{
2345 .tag = .builtin_call_two,
2346 .main_token = builtin_tok,
2347 .data = .{
2348 .lhs = arg_1,
2349 .rhs = arg_2,
2350 },
2351 });
2417 if (args.len <= 2) {
2418 return c.addNode(.{
2419 .tag = .builtin_call_two,
2420 .main_token = builtin_tok,
2421 .data = .{
2422 .lhs = arg_1,
2423 .rhs = arg_2,
2424 },
2425 });
2426 } else {
2427 std.debug.assert(args.len == 4);
2428
2429 const params = try c.listToSpan(&.{ arg_1, arg_2, arg_3, arg_4 });
2430 return c.addNode(.{
2431 .tag = .builtin_call,
2432 .main_token = builtin_tok,
2433 .data = .{
2434 .lhs = params.start,
2435 .rhs = params.end,
2436 },
2437 });
2438 }
23522439}
23532440
23542441fn renderVar(c: *Context, node: Node) !NodeIndex {
src/zig_clang.cpp+34
......@@ -2046,6 +2046,11 @@ bool ZigClangType_isRecordType(const ZigClangType *self) {
20462046 return casted->isRecordType();
20472047}
20482048
2049bool ZigClangType_isVectorType(const ZigClangType *self) {
2050 auto casted = reinterpret_cast<const clang::Type *>(self);
2051 return casted->isVectorType();
2052}
2053
20492054bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self,
20502055 const struct ZigClangASTContext *ctx)
20512056{
......@@ -2738,6 +2743,16 @@ struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBina
27382743 return bitcast(casted->getType());
27392744}
27402745
2746const struct ZigClangExpr *ZigClangConvertVectorExpr_getSrcExpr(const struct ZigClangConvertVectorExpr *self) {
2747 auto casted = reinterpret_cast<const clang::ConvertVectorExpr *>(self);
2748 return reinterpret_cast<const struct ZigClangExpr *>(casted->getSrcExpr());
2749}
2750
2751struct ZigClangQualType ZigClangConvertVectorExpr_getTypeSourceInfo_getType(const struct ZigClangConvertVectorExpr *self) {
2752 auto casted = reinterpret_cast<const clang::ConvertVectorExpr *>(self);
2753 return bitcast(casted->getTypeSourceInfo()->getType());
2754}
2755
27412756struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *self) {
27422757 auto casted = reinterpret_cast<const clang::DecayedType *>(self);
27432758 return bitcast(casted->getDecayedType());
......@@ -2843,6 +2858,16 @@ struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl
28432858 return bitcast(casted->getType());
28442859}
28452860
2861struct ZigClangQualType ZigClangVectorType_getElementType(const struct ZigClangVectorType *self) {
2862 auto casted = reinterpret_cast<const clang::VectorType *>(self);
2863 return bitcast(casted->getElementType());
2864}
2865
2866unsigned ZigClangVectorType_getNumElements(const struct ZigClangVectorType *self) {
2867 auto casted = reinterpret_cast<const clang::VectorType *>(self);
2868 return casted->getNumElements();
2869}
2870
28462871const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) {
28472872 auto casted = reinterpret_cast<const clang::WhileStmt *>(self);
28482873 return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond());
......@@ -2922,6 +2947,15 @@ struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(
29222947 return bitcast(casted->getBeginLoc());
29232948}
29242949
2950unsigned ZigClangShuffleVectorExpr_getNumSubExprs(const ZigClangShuffleVectorExpr *self) {
2951 auto casted = reinterpret_cast<const clang::ShuffleVectorExpr *>(self);
2952 return casted->getNumSubExprs();
2953}
2954
2955const struct ZigClangExpr *ZigClangShuffleVectorExpr_getExpr(const struct ZigClangShuffleVectorExpr *self, unsigned idx) {
2956 auto casted = reinterpret_cast<const clang::ShuffleVectorExpr *>(self);
2957 return reinterpret_cast<const struct ZigClangExpr *>(casted->getExpr(idx));
2958}
29252959
29262960enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind(
29272961 const struct ZigClangUnaryExprOrTypeTraitExpr *self)
src/zig_clang.h+10
......@@ -1064,6 +1064,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self);
10641064ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
10651065ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self);
10661066ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self);
1067ZIG_EXTERN_C bool ZigClangType_isVectorType(const struct ZigClangType *self);
10671068ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx);
10681069ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self);
10691070ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);
......@@ -1199,6 +1200,9 @@ ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getLHS(const stru
11991200ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getRHS(const struct ZigClangBinaryOperator *);
12001201ZIG_EXTERN_C struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBinaryOperator *);
12011202
1203ZIG_EXTERN_C const struct ZigClangExpr *ZigClangConvertVectorExpr_getSrcExpr(const struct ZigClangConvertVectorExpr *);
1204ZIG_EXTERN_C struct ZigClangQualType ZigClangConvertVectorExpr_getTypeSourceInfo_getType(const struct ZigClangConvertVectorExpr *);
1205
12021206ZIG_EXTERN_C struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *);
12031207
12041208ZIG_EXTERN_C const struct ZigClangCompoundStmt *ZigClangStmtExpr_getSubStmt(const struct ZigClangStmtExpr *);
......@@ -1228,6 +1232,9 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(con
12281232
12291233ZIG_EXTERN_C struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl *);
12301234
1235ZIG_EXTERN_C struct ZigClangQualType ZigClangVectorType_getElementType(const struct ZigClangVectorType *);
1236ZIG_EXTERN_C unsigned ZigClangVectorType_getNumElements(const struct ZigClangVectorType *);
1237
12311238ZIG_EXTERN_C const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *);
12321239ZIG_EXTERN_C const struct ZigClangStmt *ZigClangWhileStmt_getBody(const struct ZigClangWhileStmt *);
12331240
......@@ -1252,6 +1259,9 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangUnaryExprOrTypeTraitExpr_getTypeOfA
12521259ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(const struct ZigClangUnaryExprOrTypeTraitExpr *);
12531260ZIG_EXTERN_C enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind(const struct ZigClangUnaryExprOrTypeTraitExpr *);
12541261
1262ZIG_EXTERN_C unsigned ZigClangShuffleVectorExpr_getNumSubExprs(const struct ZigClangShuffleVectorExpr *);
1263ZIG_EXTERN_C const struct ZigClangExpr *ZigClangShuffleVectorExpr_getExpr(const struct ZigClangShuffleVectorExpr *, unsigned);
1264
12551265ZIG_EXTERN_C const struct ZigClangStmt *ZigClangDoStmt_getBody(const struct ZigClangDoStmt *);
12561266ZIG_EXTERN_C const struct ZigClangExpr *ZigClangDoStmt_getCond(const struct ZigClangDoStmt *);
12571267
test/run_translated_c.zig+102
......@@ -1308,4 +1308,106 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
13081308 \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted
13091309 \\}
13101310 , "");
1311
1312 cases.add("basic vector expressions",
1313 \\#include <stdlib.h>
1314 \\#include <stdint.h>
1315 \\typedef int16_t __v8hi __attribute__((__vector_size__(16)));
1316 \\int main(int argc, char**argv) {
1317 \\ __v8hi uninitialized;
1318 \\ __v8hi empty_init = {};
1319 \\ __v8hi partial_init = {0, 1, 2, 3};
1320 \\
1321 \\ __v8hi a = {0, 1, 2, 3, 4, 5, 6, 7};
1322 \\ __v8hi b = (__v8hi) {100, 200, 300, 400, 500, 600, 700, 800};
1323 \\
1324 \\ __v8hi sum = a + b;
1325 \\ for (int i = 0; i < 8; i++) {
1326 \\ if (sum[i] != a[i] + b[i]) abort();
1327 \\ }
1328 \\ return 0;
1329 \\}
1330 , "");
1331
1332 cases.add("__builtin_shufflevector",
1333 \\#include <stdlib.h>
1334 \\#include <stdint.h>
1335 \\typedef int16_t __v4hi __attribute__((__vector_size__(8)));
1336 \\typedef int16_t __v8hi __attribute__((__vector_size__(16)));
1337 \\int main(int argc, char**argv) {
1338 \\ __v8hi v8_a = {0, 1, 2, 3, 4, 5, 6, 7};
1339 \\ __v8hi v8_b = {100, 200, 300, 400, 500, 600, 700, 800};
1340 \\ __v8hi shuffled = __builtin_shufflevector(v8_a, v8_b, 0, 1, 2, 3, 8, 9, 10, 11);
1341 \\ for (int i = 0; i < 8; i++) {
1342 \\ if (i < 4) {
1343 \\ if (shuffled[i] != v8_a[i]) abort();
1344 \\ } else {
1345 \\ if (shuffled[i] != v8_b[i - 4]) abort();
1346 \\ }
1347 \\ }
1348 \\ shuffled = __builtin_shufflevector(
1349 \\ (__v8hi) {-1, -1, -1, -1, -1, -1, -1, -1},
1350 \\ (__v8hi) {42, 42, 42, 42, 42, 42, 42, 42},
1351 \\ 0, 1, 2, 3, 8, 9, 10, 11
1352 \\ );
1353 \\ for (int i = 0; i < 8; i++) {
1354 \\ if (i < 4) {
1355 \\ if (shuffled[i] != -1) abort();
1356 \\ } else {
1357 \\ if (shuffled[i] != 42) abort();
1358 \\ }
1359 \\ }
1360 \\ __v4hi shuffled_to_fewer_elements = __builtin_shufflevector(v8_a, v8_b, 0, 1, 8, 9);
1361 \\ for (int i = 0; i < 4; i++) {
1362 \\ if (i < 2) {
1363 \\ if (shuffled_to_fewer_elements[i] != v8_a[i]) abort();
1364 \\ } else {
1365 \\ if (shuffled_to_fewer_elements[i] != v8_b[i - 2]) abort();
1366 \\ }
1367 \\ }
1368 \\ __v4hi v4_a = {0, 1, 2, 3};
1369 \\ __v4hi v4_b = {100, 200, 300, 400};
1370 \\ __v8hi shuffled_to_more_elements = __builtin_shufflevector(v4_a, v4_b, 0, 1, 2, 3, 4, 5, 6, 7);
1371 \\ for (int i = 0; i < 4; i++) {
1372 \\ if (shuffled_to_more_elements[i] != v4_a[i]) abort();
1373 \\ if (shuffled_to_more_elements[i + 4] != v4_b[i]) abort();
1374 \\ }
1375 \\ return 0;
1376 \\}
1377 , "");
1378
1379 cases.add("__builtin_convertvector",
1380 \\#include <stdlib.h>
1381 \\#include <stdint.h>
1382 \\typedef int16_t __v8hi __attribute__((__vector_size__(16)));
1383 \\typedef uint16_t __v8hu __attribute__((__vector_size__(16)));
1384 \\int main(int argc, char**argv) {
1385 \\ __v8hi signed_vector = { 1, 2, 3, 4, -1, -2, -3,-4};
1386 \\ __v8hu unsigned_vector = __builtin_convertvector(signed_vector, __v8hu);
1387 \\
1388 \\ for (int i = 0; i < 8; i++) {
1389 \\ if (unsigned_vector[i] != (uint16_t)signed_vector[i]) abort();
1390 \\ }
1391 \\ return 0;
1392 \\}
1393 , "");
1394
1395 cases.add("vector casting",
1396 \\#include <stdlib.h>
1397 \\#include <stdint.h>
1398 \\typedef int8_t __v8qi __attribute__((__vector_size__(8)));
1399 \\typedef uint8_t __v8qu __attribute__((__vector_size__(8)));
1400 \\int main(int argc, char**argv) {
1401 \\ __v8qi signed_vector = { 1, 2, 3, 4, -1, -2, -3,-4};
1402 \\
1403 \\ uint64_t big_int = (uint64_t) signed_vector;
1404 \\ if (big_int != 0x01020304FFFEFDFCULL && big_int != 0xFCFDFEFF04030201ULL) abort();
1405 \\ __v8qu unsigned_vector = (__v8qu) big_int;
1406 \\ for (int i = 0; i < 8; i++) {
1407 \\ if (unsigned_vector[i] != (uint8_t)signed_vector[i] && unsigned_vector[i] != (uint8_t)signed_vector[7 - i]) abort();
1408 \\ }
1409 \\ return 0;
1410 \\}
1411 , "");
1412
13111413}