| author | |
| committer | |
| log | 8de14a98a68752cc834848343f2e7867ee8ca6c9 |
| tree | 7e6bc3259ec3926054830613d63025afa8e19117 |
| parent | 38d8aab4d283efe2f43c7e18411f6df7e1c2d04b |
Includes vector types, __builtin_shufflevector, and __builtin_convertvector7 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 { |
| 1297 | 1297 | return null; |
| 1298 | 1298 | return @as(T, @field(root, name)); |
| 1299 | 1299 | } |
| 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 | |
| 1308 | pub 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 | ||
| 1317 | test "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 {}; |
| 300 | 300 | |
| 301 | 301 | pub const ContinueStmt = opaque {}; |
| 302 | 302 | |
| 303 | pub 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 | ||
| 303 | 311 | pub const DecayedType = opaque { |
| 304 | 312 | pub const getDecayedType = ZigClangDecayedType_getDecayedType; |
| 305 | 313 | extern fn ZigClangDecayedType_getDecayedType(*const DecayedType) QualType; |
| ... | ... | @@ -748,6 +756,14 @@ pub const ReturnStmt = opaque { |
| 748 | 756 | extern fn ZigClangReturnStmt_getRetValue(*const ReturnStmt) ?*const Expr; |
| 749 | 757 | }; |
| 750 | 758 | |
| 759 | pub 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 | ||
| 751 | 767 | pub const SourceManager = opaque { |
| 752 | 768 | pub const getSpellingLoc = ZigClangSourceManager_getSpellingLoc; |
| 753 | 769 | extern fn ZigClangSourceManager_getSpellingLoc(*const SourceManager, Loc: SourceLocation) SourceLocation; |
| ... | ... | @@ -837,6 +853,9 @@ pub const Type = opaque { |
| 837 | 853 | pub const isRecordType = ZigClangType_isRecordType; |
| 838 | 854 | extern fn ZigClangType_isRecordType(*const Type) bool; |
| 839 | 855 | |
| 856 | pub const isVectorType = ZigClangType_isVectorType; | |
| 857 | extern fn ZigClangType_isVectorType(*const Type) bool; | |
| 858 | ||
| 840 | 859 | pub const isIncompleteOrZeroLengthArrayType = ZigClangType_isIncompleteOrZeroLengthArrayType; |
| 841 | 860 | extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(*const Type, *const ASTContext) bool; |
| 842 | 861 | |
| ... | ... | @@ -937,6 +956,14 @@ pub const VarDecl = opaque { |
| 937 | 956 | extern fn ZigClangVarDecl_getTypeSourceInfo_getType(*const VarDecl) QualType; |
| 938 | 957 | }; |
| 939 | 958 | |
| 959 | pub 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 | ||
| 940 | 967 | pub const WhileStmt = opaque { |
| 941 | 968 | pub const getCond = ZigClangWhileStmt_getCond; |
| 942 | 969 | extern fn ZigClangWhileStmt_getCond(*const WhileStmt) *const Expr; |
src/translate_c.zig+215| ... | ... | @@ -1123,6 +1123,16 @@ fn transStmt( |
| 1123 | 1123 | const gen_sel = @ptrCast(*const clang.GenericSelectionExpr, stmt); |
| 1124 | 1124 | return transExpr(c, scope, gen_sel.getResultExpr(), result_used); |
| 1125 | 1125 | }, |
| 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 | }, | |
| 1126 | 1136 | // When adding new cases here, see comment for maybeBlockify() |
| 1127 | 1137 | else => { |
| 1128 | 1138 | return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)}); |
| ... | ... | @@ -1130,6 +1140,128 @@ fn transStmt( |
| 1130 | 1140 | } |
| 1131 | 1141 | } |
| 1132 | 1142 | |
| 1143 | /// See https://clang.llvm.org/docs/LanguageExtensions.html#langext-builtin-convertvector | |
| 1144 | fn 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 | ||
| 1207 | fn 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> | |
| 1233 | fn 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 | ||
| 1240 | fn 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 | ||
| 1133 | 1265 | /// Translate a "simple" offsetof expression containing exactly one component, |
| 1134 | 1266 | /// when that component is of kind .Field - e.g. offsetof(mytype, myfield) |
| 1135 | 1267 | fn transSimpleOffsetOfExpr( |
| ... | ... | @@ -1935,6 +2067,10 @@ fn cIsEnum(qt: clang.QualType) bool { |
| 1935 | 2067 | return qt.getCanonicalType().getTypeClass() == .Enum; |
| 1936 | 2068 | } |
| 1937 | 2069 | |
| 2070 | fn cIsVector(qt: clang.QualType) bool { | |
| 2071 | return qt.getCanonicalType().getTypeClass() == .Vector; | |
| 2072 | } | |
| 2073 | ||
| 1938 | 2074 | /// Get the underlying int type of an enum. The C compiler chooses a signed int |
| 1939 | 2075 | /// type that is large enough to hold all of the enum's values. It is not required |
| 1940 | 2076 | /// to be the smallest possible type that can hold all the values. |
| ... | ... | @@ -1991,6 +2127,11 @@ fn transCCast( |
| 1991 | 2127 | // @bitCast(dest_type, intermediate_value) |
| 1992 | 2128 | return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr }); |
| 1993 | 2129 | } |
| 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 | } | |
| 1994 | 2135 | if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { |
| 1995 | 2136 | // @intCast(dest_type, @ptrToInt(val)) |
| 1996 | 2137 | const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr); |
| ... | ... | @@ -2209,6 +2350,63 @@ fn transInitListExprArray( |
| 2209 | 2350 | } |
| 2210 | 2351 | } |
| 2211 | 2352 | |
| 2353 | fn 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 | ||
| 2212 | 2410 | fn transInitListExpr( |
| 2213 | 2411 | c: *Context, |
| 2214 | 2412 | scope: *Scope, |
| ... | ... | @@ -2235,6 +2433,14 @@ fn transInitListExpr( |
| 2235 | 2433 | expr, |
| 2236 | 2434 | qual_type, |
| 2237 | 2435 | )); |
| 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 | )); | |
| 2238 | 2444 | } else { |
| 2239 | 2445 | const type_name = c.str(qual_type.getTypeClassName()); |
| 2240 | 2446 | 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 |
| 4085 | 4291 | }; |
| 4086 | 4292 | return Tag.typeof.create(c.arena, underlying_expr); |
| 4087 | 4293 | }, |
| 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 | }, | |
| 4088 | 4303 | else => { |
| 4089 | 4304 | const type_name = c.str(ty.getTypeClassName()); |
| 4090 | 4305 | 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 { |
| 66 | 66 | @"enum", |
| 67 | 67 | @"struct", |
| 68 | 68 | @"union", |
| 69 | @"comptime", | |
| 69 | 70 | array_init, |
| 70 | 71 | tuple, |
| 71 | 72 | container_init, |
| ... | ... | @@ -154,6 +155,8 @@ pub const Node = extern union { |
| 154 | 155 | div_exact, |
| 155 | 156 | /// @byteOffsetOf(lhs, rhs) |
| 156 | 157 | byte_offset_of, |
| 158 | /// @shuffle(type, a, b, mask) | |
| 159 | shuffle, | |
| 157 | 160 | |
| 158 | 161 | negate, |
| 159 | 162 | negate_wrap, |
| ... | ... | @@ -172,6 +175,7 @@ pub const Node = extern union { |
| 172 | 175 | sizeof, |
| 173 | 176 | alignof, |
| 174 | 177 | typeof, |
| 178 | typeinfo, | |
| 175 | 179 | type, |
| 176 | 180 | |
| 177 | 181 | optional_type, |
| ... | ... | @@ -182,6 +186,10 @@ pub const Node = extern union { |
| 182 | 186 | |
| 183 | 187 | /// @import("std").meta.sizeof(operand) |
| 184 | 188 | 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, | |
| 185 | 193 | /// @import("std").mem.zeroes(operand) |
| 186 | 194 | std_mem_zeroes, |
| 187 | 195 | /// @import("std").mem.zeroInit(lhs, rhs) |
| ... | ... | @@ -233,6 +241,7 @@ pub const Node = extern union { |
| 233 | 241 | |
| 234 | 242 | .std_mem_zeroes, |
| 235 | 243 | .@"return", |
| 244 | .@"comptime", | |
| 236 | 245 | .discard, |
| 237 | 246 | .std_math_Log2Int, |
| 238 | 247 | .negate, |
| ... | ... | @@ -255,6 +264,7 @@ pub const Node = extern union { |
| 255 | 264 | .sizeof, |
| 256 | 265 | .alignof, |
| 257 | 266 | .typeof, |
| 267 | .typeinfo, | |
| 258 | 268 | => Payload.UnOp, |
| 259 | 269 | |
| 260 | 270 | .add, |
| ... | ... | @@ -308,6 +318,8 @@ pub const Node = extern union { |
| 308 | 318 | .align_cast, |
| 309 | 319 | .array_access, |
| 310 | 320 | .std_mem_zeroinit, |
| 321 | .std_meta_shuffle_vector_index, | |
| 322 | .std_meta_vector, | |
| 311 | 323 | .ptr_cast, |
| 312 | 324 | .div_exact, |
| 313 | 325 | .byte_offset_of, |
| ... | ... | @@ -346,6 +358,7 @@ pub const Node = extern union { |
| 346 | 358 | .pub_inline_fn => Payload.PubInlineFn, |
| 347 | 359 | .field_access => Payload.FieldAccess, |
| 348 | 360 | .string_slice => Payload.StringSlice, |
| 361 | .shuffle => Payload.Shuffle, | |
| 349 | 362 | }; |
| 350 | 363 | } |
| 351 | 364 | |
| ... | ... | @@ -678,6 +691,16 @@ pub const Payload = struct { |
| 678 | 691 | end: usize, |
| 679 | 692 | }, |
| 680 | 693 | }; |
| 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 | }; | |
| 681 | 704 | }; |
| 682 | 705 | |
| 683 | 706 | /// Converts the nodes into a Zig ast. |
| ... | ... | @@ -868,6 +891,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 868 | 891 | const import_node = try renderStdImport(c, "mem", "zeroInit"); |
| 869 | 892 | return renderCall(c, import_node, &.{ payload.lhs, payload.rhs }); |
| 870 | 893 | }, |
| 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 | }, | |
| 871 | 904 | .call => { |
| 872 | 905 | const payload = node.castTag(.call).?.data; |
| 873 | 906 | const lhs = try renderNode(c, payload.lhs); |
| ... | ... | @@ -964,6 +997,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 964 | 997 | }, |
| 965 | 998 | }); |
| 966 | 999 | }, |
| 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 | }, | |
| 967 | 1011 | .type => { |
| 968 | 1012 | const payload = node.castTag(.type).?.data; |
| 969 | 1013 | return c.addNode(.{ |
| ... | ... | @@ -1217,6 +1261,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1217 | 1261 | const payload = node.castTag(.sizeof).?.data; |
| 1218 | 1262 | return renderBuiltinCall(c, "@sizeOf", &.{payload}); |
| 1219 | 1263 | }, |
| 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 | }, | |
| 1220 | 1273 | .alignof => { |
| 1221 | 1274 | const payload = node.castTag(.alignof).?.data; |
| 1222 | 1275 | return renderBuiltinCall(c, "@alignOf", &.{payload}); |
| ... | ... | @@ -1225,6 +1278,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1225 | 1278 | const payload = node.castTag(.typeof).?.data; |
| 1226 | 1279 | return renderBuiltinCall(c, "@TypeOf", &.{payload}); |
| 1227 | 1280 | }, |
| 1281 | .typeinfo => { | |
| 1282 | const payload = node.castTag(.typeinfo).?.data; | |
| 1283 | return renderBuiltinCall(c, "@typeInfo", &.{payload}); | |
| 1284 | }, | |
| 1228 | 1285 | .negate => return renderPrefixOp(c, node, .negation, .minus, "-"), |
| 1229 | 1286 | .negate_wrap => return renderPrefixOp(c, node, .negation_wrap, .minus_percent, "-%"), |
| 1230 | 1287 | .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"), |
| ... | ... | @@ -2085,9 +2142,12 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 2085 | 2142 | .sizeof, |
| 2086 | 2143 | .alignof, |
| 2087 | 2144 | .typeof, |
| 2145 | .typeinfo, | |
| 2088 | 2146 | .std_meta_sizeof, |
| 2089 | 2147 | .std_meta_cast, |
| 2090 | 2148 | .std_meta_promoteIntLiteral, |
| 2149 | .std_meta_vector, | |
| 2150 | .std_meta_shuffle_vector_index, | |
| 2091 | 2151 | .std_mem_zeroinit, |
| 2092 | 2152 | .integer_literal, |
| 2093 | 2153 | .float_literal, |
| ... | ... | @@ -2118,6 +2178,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 2118 | 2178 | .bool_to_int, |
| 2119 | 2179 | .div_exact, |
| 2120 | 2180 | .byte_offset_of, |
| 2181 | .shuffle, | |
| 2121 | 2182 | => { |
| 2122 | 2183 | // no grouping needed |
| 2123 | 2184 | return renderNode(c, node); |
| ... | ... | @@ -2185,6 +2246,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 2185 | 2246 | .discard, |
| 2186 | 2247 | .@"continue", |
| 2187 | 2248 | .@"return", |
| 2249 | .@"comptime", | |
| 2188 | 2250 | .usingnamespace_builtins, |
| 2189 | 2251 | .while_true, |
| 2190 | 2252 | .if_not_break, |
| ... | ... | @@ -2327,6 +2389,8 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node |
| 2327 | 2389 | _ = try c.addToken(.l_paren, "("); |
| 2328 | 2390 | var arg_1: NodeIndex = 0; |
| 2329 | 2391 | var arg_2: NodeIndex = 0; |
| 2392 | var arg_3: NodeIndex = 0; | |
| 2393 | var arg_4: NodeIndex = 0; | |
| 2330 | 2394 | switch (args.len) { |
| 2331 | 2395 | 0 => {}, |
| 2332 | 2396 | 1 => { |
| ... | ... | @@ -2337,18 +2401,41 @@ fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !Node |
| 2337 | 2401 | _ = try c.addToken(.comma, ","); |
| 2338 | 2402 | arg_2 = try renderNode(c, args[1]); |
| 2339 | 2403 | }, |
| 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 | }, | |
| 2340 | 2413 | else => unreachable, // expand this function as needed. |
| 2341 | 2414 | } |
| 2342 | 2415 | |
| 2343 | 2416 | _ = 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 | } | |
| 2352 | 2439 | } |
| 2353 | 2440 | |
| 2354 | 2441 | fn renderVar(c: *Context, node: Node) !NodeIndex { |
src/zig_clang.cpp+34| ... | ... | @@ -2046,6 +2046,11 @@ bool ZigClangType_isRecordType(const ZigClangType *self) { |
| 2046 | 2046 | return casted->isRecordType(); |
| 2047 | 2047 | } |
| 2048 | 2048 | |
| 2049 | bool ZigClangType_isVectorType(const ZigClangType *self) { | |
| 2050 | auto casted = reinterpret_cast<const clang::Type *>(self); | |
| 2051 | return casted->isVectorType(); | |
| 2052 | } | |
| 2053 | ||
| 2049 | 2054 | bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, |
| 2050 | 2055 | const struct ZigClangASTContext *ctx) |
| 2051 | 2056 | { |
| ... | ... | @@ -2738,6 +2743,16 @@ struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBina |
| 2738 | 2743 | return bitcast(casted->getType()); |
| 2739 | 2744 | } |
| 2740 | 2745 | |
| 2746 | const 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 | ||
| 2751 | struct 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 | ||
| 2741 | 2756 | struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *self) { |
| 2742 | 2757 | auto casted = reinterpret_cast<const clang::DecayedType *>(self); |
| 2743 | 2758 | return bitcast(casted->getDecayedType()); |
| ... | ... | @@ -2843,6 +2858,16 @@ struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl |
| 2843 | 2858 | return bitcast(casted->getType()); |
| 2844 | 2859 | } |
| 2845 | 2860 | |
| 2861 | struct ZigClangQualType ZigClangVectorType_getElementType(const struct ZigClangVectorType *self) { | |
| 2862 | auto casted = reinterpret_cast<const clang::VectorType *>(self); | |
| 2863 | return bitcast(casted->getElementType()); | |
| 2864 | } | |
| 2865 | ||
| 2866 | unsigned ZigClangVectorType_getNumElements(const struct ZigClangVectorType *self) { | |
| 2867 | auto casted = reinterpret_cast<const clang::VectorType *>(self); | |
| 2868 | return casted->getNumElements(); | |
| 2869 | } | |
| 2870 | ||
| 2846 | 2871 | const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *self) { |
| 2847 | 2872 | auto casted = reinterpret_cast<const clang::WhileStmt *>(self); |
| 2848 | 2873 | return reinterpret_cast<const struct ZigClangExpr *>(casted->getCond()); |
| ... | ... | @@ -2922,6 +2947,15 @@ struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc( |
| 2922 | 2947 | return bitcast(casted->getBeginLoc()); |
| 2923 | 2948 | } |
| 2924 | 2949 | |
| 2950 | unsigned ZigClangShuffleVectorExpr_getNumSubExprs(const ZigClangShuffleVectorExpr *self) { | |
| 2951 | auto casted = reinterpret_cast<const clang::ShuffleVectorExpr *>(self); | |
| 2952 | return casted->getNumSubExprs(); | |
| 2953 | } | |
| 2954 | ||
| 2955 | const 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 | } | |
| 2925 | 2959 | |
| 2926 | 2960 | enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind( |
| 2927 | 2961 | const struct ZigClangUnaryExprOrTypeTraitExpr *self) |
src/zig_clang.h+10| ... | ... | @@ -1064,6 +1064,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self); |
| 1064 | 1064 | ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self); |
| 1065 | 1065 | ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self); |
| 1066 | 1066 | ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self); |
| 1067 | ZIG_EXTERN_C bool ZigClangType_isVectorType(const struct ZigClangType *self); | |
| 1067 | 1068 | ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx); |
| 1068 | 1069 | ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self); |
| 1069 | 1070 | 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 |
| 1199 | 1200 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getRHS(const struct ZigClangBinaryOperator *); |
| 1200 | 1201 | ZIG_EXTERN_C struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBinaryOperator *); |
| 1201 | 1202 | |
| 1203 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangConvertVectorExpr_getSrcExpr(const struct ZigClangConvertVectorExpr *); | |
| 1204 | ZIG_EXTERN_C struct ZigClangQualType ZigClangConvertVectorExpr_getTypeSourceInfo_getType(const struct ZigClangConvertVectorExpr *); | |
| 1205 | ||
| 1202 | 1206 | ZIG_EXTERN_C struct ZigClangQualType ZigClangDecayedType_getDecayedType(const struct ZigClangDecayedType *); |
| 1203 | 1207 | |
| 1204 | 1208 | ZIG_EXTERN_C const struct ZigClangCompoundStmt *ZigClangStmtExpr_getSubStmt(const struct ZigClangStmtExpr *); |
| ... | ... | @@ -1228,6 +1232,9 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryOperator_getBeginLoc(con |
| 1228 | 1232 | |
| 1229 | 1233 | ZIG_EXTERN_C struct ZigClangQualType ZigClangValueDecl_getType(const struct ZigClangValueDecl *); |
| 1230 | 1234 | |
| 1235 | ZIG_EXTERN_C struct ZigClangQualType ZigClangVectorType_getElementType(const struct ZigClangVectorType *); | |
| 1236 | ZIG_EXTERN_C unsigned ZigClangVectorType_getNumElements(const struct ZigClangVectorType *); | |
| 1237 | ||
| 1231 | 1238 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangWhileStmt_getCond(const struct ZigClangWhileStmt *); |
| 1232 | 1239 | ZIG_EXTERN_C const struct ZigClangStmt *ZigClangWhileStmt_getBody(const struct ZigClangWhileStmt *); |
| 1233 | 1240 | |
| ... | ... | @@ -1252,6 +1259,9 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangUnaryExprOrTypeTraitExpr_getTypeOfA |
| 1252 | 1259 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(const struct ZigClangUnaryExprOrTypeTraitExpr *); |
| 1253 | 1260 | ZIG_EXTERN_C enum ZigClangUnaryExprOrTypeTrait_Kind ZigClangUnaryExprOrTypeTraitExpr_getKind(const struct ZigClangUnaryExprOrTypeTraitExpr *); |
| 1254 | 1261 | |
| 1262 | ZIG_EXTERN_C unsigned ZigClangShuffleVectorExpr_getNumSubExprs(const struct ZigClangShuffleVectorExpr *); | |
| 1263 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangShuffleVectorExpr_getExpr(const struct ZigClangShuffleVectorExpr *, unsigned); | |
| 1264 | ||
| 1255 | 1265 | ZIG_EXTERN_C const struct ZigClangStmt *ZigClangDoStmt_getBody(const struct ZigClangDoStmt *); |
| 1256 | 1266 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangDoStmt_getCond(const struct ZigClangDoStmt *); |
| 1257 | 1267 |
test/run_translated_c.zig+102| ... | ... | @@ -1308,4 +1308,106 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 1308 | 1308 | \\ ufoo = (uval += 100000000); // compile error if @truncate() not inserted |
| 1309 | 1309 | \\} |
| 1310 | 1310 | , ""); |
| 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 | ||
| 1311 | 1413 | } |