| ... | @@ -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 | } |
| 253 | | 253 | |
| | 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 { |
| 325 | | 357 | |
| 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(); |
| 379 | | 411 | |
| 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 | } |
| 385 | | 417 | |
| 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 { |
| 431 | | 463 | |
| 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 | } |