@@ -1123,13 +1123,145 @@ 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 )});
1129
1139
},
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 });
0 commit comments