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 {...@@ -251,10 +251,42 @@ pub const DeclGen = struct {
251 return error.AnalysisFail;251 return error.AnalysisFail;
252 }252 }
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
254 fn renderValue(286 fn renderValue(
255 dg: *DeclGen,287 dg: *DeclGen,
256 writer: anytype,288 writer: anytype,
257 t: Type,289 ty: Type,
258 val: Value,290 val: Value,
259 ) error{ OutOfMemory, AnalysisFail }!void {291 ) error{ OutOfMemory, AnalysisFail }!void {
260 if (val.isUndef()) {292 if (val.isUndef()) {
...@@ -264,50 +296,50 @@ pub const DeclGen = struct {...@@ -264,50 +296,50 @@ pub const DeclGen = struct {
264 return writer.writeAll("{}");296 return writer.writeAll("{}");
265 //return dg.fail("TODO: C backend: implement renderValue undef", .{});297 //return dg.fail("TODO: C backend: implement renderValue undef", .{});
266 }298 }
267 switch (t.zigTypeTag()) {299 switch (ty.zigTypeTag()) {
268 .Int => {300 .Int => {
269 if (t.isSignedInt())301 if (ty.isSignedInt())
270 return writer.print("{d}", .{val.toSignedInt()});302 return writer.print("{d}", .{val.toSignedInt()});
271 return writer.print("{d}", .{val.toUnsignedInt()});303 return writer.print("{d}", .{val.toUnsignedInt()});
272 },304 },
273 .Pointer => switch (t.ptrSize()) {305 .Float => {
274 .Slice => {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
275 try writer.writeByte('(');326 try writer.writeByte('(');
276 try dg.renderType(writer, t);327 try dg.renderType(writer, ty);
277 try writer.writeAll("){");328 try writer.writeAll("){");
278 var buf: Type.SlicePtrFieldTypeBuffer = undefined;329 try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr);
279 try dg.renderValue(writer, t.slicePtrFieldType(&buf), val);
280 try writer.writeAll(", ");330 try writer.writeAll(", ");
281 try writer.print("{d}", .{val.sliceLen()});331 try dg.renderValue(writer, Type.usize, slice.len);
282 try writer.writeAll("}");332 try writer.writeAll("}");
283 },333 },
284 else => switch (val.tag()) {334 .function => {
285 .null_value, .zero => try writer.writeAll("NULL"),335 const func = val.castTag(.function).?.data;
286 .one => try writer.writeAll("1"),336 try writer.print("{s}", .{func.owner_decl.name});
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,
310 },337 },
338 .extern_fn => {
339 const decl = val.castTag(.extern_fn).?.data;
340 try writer.print("{s}", .{decl.name});
341 },
342 else => unreachable,
311 },343 },
312 .Array => {344 .Array => {
313 // First try specific tag representations for more efficiency.345 // First try specific tag representations for more efficiency.
...@@ -325,14 +357,14 @@ pub const DeclGen = struct {...@@ -325,14 +357,14 @@ pub const DeclGen = struct {
325357
326 try writer.writeAll("{");358 try writer.writeAll("{");
327 var index: usize = 0;359 var index: usize = 0;
328 const len = t.arrayLen();360 const len = ty.arrayLen();
329 const elem_ty = t.elemType();361 const elem_ty = ty.elemType();
330 while (index < len) : (index += 1) {362 while (index < len) : (index += 1) {
331 if (index != 0) try writer.writeAll(",");363 if (index != 0) try writer.writeAll(",");
332 const elem_val = try val.elemValue(&arena.allocator, index);364 const elem_val = try val.elemValue(&arena.allocator, index);
333 try dg.renderValue(writer, elem_ty, elem_val);365 try dg.renderValue(writer, elem_ty, elem_val);
334 }366 }
335 if (t.sentinel()) |sentinel_val| {367 if (ty.sentinel()) |sentinel_val| {
336 if (index != 0) try writer.writeAll(",");368 if (index != 0) try writer.writeAll(",");
337 try dg.renderValue(writer, elem_ty, sentinel_val);369 try dg.renderValue(writer, elem_ty, sentinel_val);
338 }370 }
...@@ -343,12 +375,12 @@ pub const DeclGen = struct {...@@ -343,12 +375,12 @@ pub const DeclGen = struct {
343 .Bool => return writer.print("{}", .{val.toBool()}),375 .Bool => return writer.print("{}", .{val.toBool()}),
344 .Optional => {376 .Optional => {
345 var opt_buf: Type.Payload.ElemType = undefined;377 var opt_buf: Type.Payload.ElemType = undefined;
346 const payload_type = t.optionalChild(&opt_buf);378 const payload_type = ty.optionalChild(&opt_buf);
347 if (t.isPtrLikeOptional()) {379 if (ty.isPtrLikeOptional()) {
348 return dg.renderValue(writer, payload_type, val);380 return dg.renderValue(writer, payload_type, val);
349 }381 }
350 try writer.writeByte('(');382 try writer.writeByte('(');
351 try dg.renderType(writer, t);383 try dg.renderType(writer, ty);
352 try writer.writeAll("){");384 try writer.writeAll("){");
353 if (val.castTag(.opt_payload)) |pl| {385 if (val.castTag(.opt_payload)) |pl| {
354 const payload_val = pl.data;386 const payload_val = pl.data;
...@@ -374,8 +406,8 @@ pub const DeclGen = struct {...@@ -374,8 +406,8 @@ pub const DeclGen = struct {
374 }406 }
375 },407 },
376 .ErrorUnion => {408 .ErrorUnion => {
377 const error_type = t.errorUnionSet();409 const error_type = ty.errorUnionSet();
378 const payload_type = t.errorUnionPayload();410 const payload_type = ty.errorUnionPayload();
379411
380 if (!payload_type.hasCodeGenBits()) {412 if (!payload_type.hasCodeGenBits()) {
381 // We use the error type directly as the type.413 // We use the error type directly as the type.
...@@ -384,7 +416,7 @@ pub const DeclGen = struct {...@@ -384,7 +416,7 @@ pub const DeclGen = struct {
384 }416 }
385417
386 try writer.writeByte('(');418 try writer.writeByte('(');
387 try dg.renderType(writer, t);419 try dg.renderType(writer, ty);
388 try writer.writeAll("){");420 try writer.writeAll("){");
389 if (val.castTag(.eu_payload)) |pl| {421 if (val.castTag(.eu_payload)) |pl| {
390 const payload_val = pl.data;422 const payload_val = pl.data;
...@@ -401,10 +433,10 @@ pub const DeclGen = struct {...@@ -401,10 +433,10 @@ pub const DeclGen = struct {
401 switch (val.tag()) {433 switch (val.tag()) {
402 .enum_field_index => {434 .enum_field_index => {
403 const field_index = val.castTag(.enum_field_index).?.data;435 const field_index = val.castTag(.enum_field_index).?.data;
404 switch (t.tag()) {436 switch (ty.tag()) {
405 .enum_simple => return writer.print("{d}", .{field_index}),437 .enum_simple => return writer.print("{d}", .{field_index}),
406 .enum_full, .enum_nonexhaustive => {438 .enum_full, .enum_nonexhaustive => {
407 const enum_full = t.cast(Type.Payload.EnumFull).?.data;439 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
408 if (enum_full.values.count() != 0) {440 if (enum_full.values.count() != 0) {
409 const tag_val = enum_full.values.keys()[field_index];441 const tag_val = enum_full.values.keys()[field_index];
410 return dg.renderValue(writer, enum_full.tag_ty, tag_val);442 return dg.renderValue(writer, enum_full.tag_ty, tag_val);
...@@ -417,7 +449,7 @@ pub const DeclGen = struct {...@@ -417,7 +449,7 @@ pub const DeclGen = struct {
417 },449 },
418 else => {450 else => {
419 var int_tag_ty_buffer: Type.Payload.Bits = undefined;451 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);
421 return dg.renderValue(writer, int_tag_ty, val);453 return dg.renderValue(writer, int_tag_ty, val);
422 },454 },
423 }455 }
...@@ -431,11 +463,11 @@ pub const DeclGen = struct {...@@ -431,11 +463,11 @@ pub const DeclGen = struct {
431463
432 // Determine if we must pointer cast.464 // Determine if we must pointer cast.
433 assert(decl.has_tv);465 assert(decl.has_tv);
434 if (t.eql(decl.ty)) {466 if (ty.eql(decl.ty)) {
435 try writer.print("&{s}", .{decl.name});467 try writer.print("&{s}", .{decl.name});
436 } else {468 } else {
437 try writer.writeAll("(");469 try writer.writeAll("(");
438 try dg.renderType(writer, t);470 try dg.renderType(writer, ty);
439 try writer.print(")&{s}", .{decl.name});471 try writer.print(")&{s}", .{decl.name});
440 }472 }
441 },473 },
...@@ -451,8 +483,40 @@ pub const DeclGen = struct {...@@ -451,8 +483,40 @@ pub const DeclGen = struct {
451 },483 },
452 else => unreachable,484 else => unreachable,
453 },485 },
454 else => |e| return dg.fail("TODO: C backend: implement value {s}", .{486 .Struct => {
455 @tagName(e),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),
456 }),520 }),
457 }521 }
458 }522 }
src/codegen/llvm.zig+1-1
...@@ -1010,7 +1010,7 @@ pub const DeclGen = struct {...@@ -1010,7 +1010,7 @@ pub const DeclGen = struct {
1010 .val = slice.ptr,1010 .val = slice.ptr,
1011 }),1011 }),
1012 try self.genTypedValue(.{1012 try self.genTypedValue(.{
1013 .ty = Type.initTag(.usize),1013 .ty = Type.usize,
1014 .val = slice.len,1014 .val = slice.len,
1015 }),1015 }),
1016 };1016 };