authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-03 12:50:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-03 12:50:34-07:00
logc79bf18044e8dadc64ff97fdf01e99b134d5e31b
treea33517021fbd0fd77c29c9543ebb1ff3c1681511
parent86c265aec8b9cdca0e78bfb02d7442e79c0be5a9

C backend: fix lowering of struct, float, and slice constants


2 files changed, 116 insertions(+), 52 deletions(-)

src/codegen/c.zig+115-51
......@@ -251,10 +251,42 @@ pub const DeclGen = struct {
251251 return error.AnalysisFail;
252252 }
253253
254 fn renderDeclValue(
255 dg: *DeclGen,
256 writer: anytype,
257 ty: Type,
258 val: Value,
259 decl: *Decl,
260 ) error{ OutOfMemory, AnalysisFail }!void {
261 decl.alive = true;
262
263 if (ty.isSlice()) {
264 try writer.writeByte('(');
265 try dg.renderType(writer, ty);
266 try writer.writeAll("){");
267 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
268 try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val);
269 try writer.writeAll(", ");
270 try writer.print("{d}", .{val.sliceLen()});
271 try writer.writeAll("}");
272 return;
273 }
274
275 // Determine if we must pointer cast.
276 assert(decl.has_tv);
277 if (ty.eql(decl.ty)) {
278 try writer.print("&{s}", .{decl.name});
279 } else {
280 try writer.writeAll("(");
281 try dg.renderType(writer, ty);
282 try writer.print(")&{s}", .{decl.name});
283 }
284 }
285
254286 fn renderValue(
255287 dg: *DeclGen,
256288 writer: anytype,
257 t: Type,
289 ty: Type,
258290 val: Value,
259291 ) error{ OutOfMemory, AnalysisFail }!void {
260292 if (val.isUndef()) {
......@@ -264,50 +296,50 @@ pub const DeclGen = struct {
264296 return writer.writeAll("{}");
265297 //return dg.fail("TODO: C backend: implement renderValue undef", .{});
266298 }
267 switch (t.zigTypeTag()) {
299 switch (ty.zigTypeTag()) {
268300 .Int => {
269 if (t.isSignedInt())
301 if (ty.isSignedInt())
270302 return writer.print("{d}", .{val.toSignedInt()});
271303 return writer.print("{d}", .{val.toUnsignedInt()});
272304 },
273 .Pointer => switch (t.ptrSize()) {
274 .Slice => {
305 .Float => {
306 if (ty.floatBits(dg.module.getTarget()) <= 64) {
307 return writer.print("{x}", .{val.toFloat(f64)});
308 }
309 return dg.fail("TODO: C backend: implement lowering large float values", .{});
310 },
311 .Pointer => switch (val.tag()) {
312 .null_value, .zero => try writer.writeAll("NULL"),
313 .one => try writer.writeAll("1"),
314 .decl_ref => {
315 const decl = val.castTag(.decl_ref).?.data;
316 return dg.renderDeclValue(writer, ty, val, decl);
317 },
318 .variable => {
319 const decl = val.castTag(.variable).?.data.owner_decl;
320 return dg.renderDeclValue(writer, ty, val, decl);
321 },
322 .slice => {
323 const slice = val.castTag(.slice).?.data;
324 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
325
275326 try writer.writeByte('(');
276 try dg.renderType(writer, t);
327 try dg.renderType(writer, ty);
277328 try writer.writeAll("){");
278 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
279 try dg.renderValue(writer, t.slicePtrFieldType(&buf), val);
329 try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr);
280330 try writer.writeAll(", ");
281 try writer.print("{d}", .{val.sliceLen()});
331 try dg.renderValue(writer, Type.usize, slice.len);
282332 try writer.writeAll("}");
283333 },
284 else => switch (val.tag()) {
285 .null_value, .zero => try writer.writeAll("NULL"),
286 .one => try writer.writeAll("1"),
287 .decl_ref => {
288 const decl = val.castTag(.decl_ref).?.data;
289 decl.alive = true;
290
291 // Determine if we must pointer cast.
292 assert(decl.has_tv);
293 if (t.eql(decl.ty)) {
294 try writer.print("&{s}", .{decl.name});
295 } else {
296 try writer.writeAll("(");
297 try dg.renderType(writer, t);
298 try writer.print(")&{s}", .{decl.name});
299 }
300 },
301 .function => {
302 const func = val.castTag(.function).?.data;
303 try writer.print("{s}", .{func.owner_decl.name});
304 },
305 .extern_fn => {
306 const decl = val.castTag(.extern_fn).?.data;
307 try writer.print("{s}", .{decl.name});
308 },
309 else => unreachable,
334 .function => {
335 const func = val.castTag(.function).?.data;
336 try writer.print("{s}", .{func.owner_decl.name});
310337 },
338 .extern_fn => {
339 const decl = val.castTag(.extern_fn).?.data;
340 try writer.print("{s}", .{decl.name});
341 },
342 else => unreachable,
311343 },
312344 .Array => {
313345 // First try specific tag representations for more efficiency.
......@@ -325,14 +357,14 @@ pub const DeclGen = struct {
325357
326358 try writer.writeAll("{");
327359 var index: usize = 0;
328 const len = t.arrayLen();
329 const elem_ty = t.elemType();
360 const len = ty.arrayLen();
361 const elem_ty = ty.elemType();
330362 while (index < len) : (index += 1) {
331363 if (index != 0) try writer.writeAll(",");
332364 const elem_val = try val.elemValue(&arena.allocator, index);
333365 try dg.renderValue(writer, elem_ty, elem_val);
334366 }
335 if (t.sentinel()) |sentinel_val| {
367 if (ty.sentinel()) |sentinel_val| {
336368 if (index != 0) try writer.writeAll(",");
337369 try dg.renderValue(writer, elem_ty, sentinel_val);
338370 }
......@@ -343,12 +375,12 @@ pub const DeclGen = struct {
343375 .Bool => return writer.print("{}", .{val.toBool()}),
344376 .Optional => {
345377 var opt_buf: Type.Payload.ElemType = undefined;
346 const payload_type = t.optionalChild(&opt_buf);
347 if (t.isPtrLikeOptional()) {
378 const payload_type = ty.optionalChild(&opt_buf);
379 if (ty.isPtrLikeOptional()) {
348380 return dg.renderValue(writer, payload_type, val);
349381 }
350382 try writer.writeByte('(');
351 try dg.renderType(writer, t);
383 try dg.renderType(writer, ty);
352384 try writer.writeAll("){");
353385 if (val.castTag(.opt_payload)) |pl| {
354386 const payload_val = pl.data;
......@@ -374,8 +406,8 @@ pub const DeclGen = struct {
374406 }
375407 },
376408 .ErrorUnion => {
377 const error_type = t.errorUnionSet();
378 const payload_type = t.errorUnionPayload();
409 const error_type = ty.errorUnionSet();
410 const payload_type = ty.errorUnionPayload();
379411
380412 if (!payload_type.hasCodeGenBits()) {
381413 // We use the error type directly as the type.
......@@ -384,7 +416,7 @@ pub const DeclGen = struct {
384416 }
385417
386418 try writer.writeByte('(');
387 try dg.renderType(writer, t);
419 try dg.renderType(writer, ty);
388420 try writer.writeAll("){");
389421 if (val.castTag(.eu_payload)) |pl| {
390422 const payload_val = pl.data;
......@@ -401,10 +433,10 @@ pub const DeclGen = struct {
401433 switch (val.tag()) {
402434 .enum_field_index => {
403435 const field_index = val.castTag(.enum_field_index).?.data;
404 switch (t.tag()) {
436 switch (ty.tag()) {
405437 .enum_simple => return writer.print("{d}", .{field_index}),
406438 .enum_full, .enum_nonexhaustive => {
407 const enum_full = t.cast(Type.Payload.EnumFull).?.data;
439 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
408440 if (enum_full.values.count() != 0) {
409441 const tag_val = enum_full.values.keys()[field_index];
410442 return dg.renderValue(writer, enum_full.tag_ty, tag_val);
......@@ -417,7 +449,7 @@ pub const DeclGen = struct {
417449 },
418450 else => {
419451 var int_tag_ty_buffer: Type.Payload.Bits = undefined;
420 const int_tag_ty = t.intTagType(&int_tag_ty_buffer);
452 const int_tag_ty = ty.intTagType(&int_tag_ty_buffer);
421453 return dg.renderValue(writer, int_tag_ty, val);
422454 },
423455 }
......@@ -431,11 +463,11 @@ pub const DeclGen = struct {
431463
432464 // Determine if we must pointer cast.
433465 assert(decl.has_tv);
434 if (t.eql(decl.ty)) {
466 if (ty.eql(decl.ty)) {
435467 try writer.print("&{s}", .{decl.name});
436468 } else {
437469 try writer.writeAll("(");
438 try dg.renderType(writer, t);
470 try dg.renderType(writer, ty);
439471 try writer.print(")&{s}", .{decl.name});
440472 }
441473 },
......@@ -451,8 +483,40 @@ pub const DeclGen = struct {
451483 },
452484 else => unreachable,
453485 },
454 else => |e| return dg.fail("TODO: C backend: implement value {s}", .{
455 @tagName(e),
486 .Struct => {
487 const field_vals = val.castTag(.@"struct").?.data;
488
489 try ty.renderFullyQualifiedName(writer);
490 try writer.writeAll("{");
491
492 for (field_vals) |field_val, i| {
493 const field_ty = ty.structFieldType(i);
494 if (!field_ty.hasCodeGenBits()) continue;
495
496 if (i != 0) try writer.writeAll(",");
497 try dg.renderValue(writer, field_ty, field_val);
498 }
499
500 try writer.writeAll("}");
501 },
502
503 .ComptimeInt => unreachable,
504 .ComptimeFloat => unreachable,
505 .Type => unreachable,
506 .EnumLiteral => unreachable,
507 .Void => unreachable,
508 .NoReturn => unreachable,
509 .Undefined => unreachable,
510 .Null => unreachable,
511 .BoundFn => unreachable,
512 .Opaque => unreachable,
513
514 .Union,
515 .Frame,
516 .AnyFrame,
517 .Vector,
518 => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{
519 @tagName(tag),
456520 }),
457521 }
458522 }
src/codegen/llvm.zig+1-1
......@@ -1010,7 +1010,7 @@ pub const DeclGen = struct {
10101010 .val = slice.ptr,
10111011 }),
10121012 try self.genTypedValue(.{
1013 .ty = Type.initTag(.usize),
1013 .ty = Type.usize,
10141014 .val = slice.len,
10151015 }),
10161016 };