authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-02 11:10:35+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-02 11:10:35+01:00
log2e327d9b63036abf2556e21693350a5169b888fb
treeb7ead718ac3f5118fa43692f2dfd25c48c123eab
parent7cfc3f0cfa626abe25c8318a7852977cbc1c723b

codegen: lower optionals and floats across linking backends


1 files changed, 93 insertions(+), 13 deletions(-)

src/codegen.zig+93-13
...@@ -140,6 +140,29 @@ pub fn generateFunction(...@@ -140,6 +140,29 @@ pub fn generateFunction(
140 }140 }
141}141}
142142
143fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian, code: []u8) void {
144 if (F == f80) {
145 switch (target.cpu.arch) {
146 .i386, .x86_64 => {
147 const repr = math.break_f80(f);
148 mem.writeIntLittle(u64, code[0..8], repr.fraction);
149 mem.writeIntLittle(u16, code[8..10], repr.exp);
150 // TODO set the rest of the bytes to undefined. should we use 0xaa
151 // or is there a different way?
152 return;
153 },
154 else => {},
155 }
156 } else {
157 const Int = @Type(.{ .Int = .{
158 .signedness = .unsigned,
159 .bits = @typeInfo(F).Float.bits,
160 } });
161 const int = @bitCast(Int, f);
162 mem.writeInt(Int, code[0..@sizeOf(Int)], int, endian);
163 }
164}
165
143pub fn generateSymbol(166pub fn generateSymbol(
144 bin_file: *link.File,167 bin_file: *link.File,
145 src_loc: Module.SrcLoc,168 src_loc: Module.SrcLoc,
...@@ -151,10 +174,12 @@ pub fn generateSymbol(...@@ -151,10 +174,12 @@ pub fn generateSymbol(
151 const tracy = trace(@src());174 const tracy = trace(@src());
152 defer tracy.end();175 defer tracy.end();
153176
177 const target = bin_file.options.target;
178 const endian = target.cpu.arch.endian();
179
154 log.debug("generateSymbol: ty = {}, val = {}", .{ typed_value.ty, typed_value.val });180 log.debug("generateSymbol: ty = {}, val = {}", .{ typed_value.ty, typed_value.val });
155181
156 if (typed_value.val.isUndefDeep()) {182 if (typed_value.val.isUndefDeep()) {
157 const target = bin_file.options.target;
158 const abi_size = try math.cast(usize, typed_value.ty.abiSize(target));183 const abi_size = try math.cast(usize, typed_value.ty.abiSize(target));
159 try code.appendNTimes(0xaa, abi_size);184 try code.appendNTimes(0xaa, abi_size);
160 return Result{ .appended = {} };185 return Result{ .appended = {} };
...@@ -171,6 +196,18 @@ pub fn generateSymbol(...@@ -171,6 +196,18 @@ pub fn generateSymbol(
171 ),196 ),
172 };197 };
173 },198 },
199 .Float => {
200 const float_bits = typed_value.ty.floatBits(target);
201 switch (float_bits) {
202 16 => writeFloat(f16, typed_value.val.toFloat(f16), target, endian, try code.addManyAsArray(2)),
203 32 => writeFloat(f32, typed_value.val.toFloat(f32), target, endian, try code.addManyAsArray(4)),
204 64 => writeFloat(f64, typed_value.val.toFloat(f64), target, endian, try code.addManyAsArray(8)),
205 80 => writeFloat(f80, typed_value.val.toFloat(f80), target, endian, try code.addManyAsArray(10)),
206 128 => writeFloat(f128, typed_value.val.toFloat(f128), target, endian, try code.addManyAsArray(16)),
207 else => unreachable,
208 }
209 return Result{ .appended = {} };
210 },
174 .Array => switch (typed_value.val.tag()) {211 .Array => switch (typed_value.val.tag()) {
175 .bytes => {212 .bytes => {
176 // TODO populate .debug_info for the array213 // TODO populate .debug_info for the array
...@@ -311,7 +348,6 @@ pub fn generateSymbol(...@@ -311,7 +348,6 @@ pub fn generateSymbol(
311 return Result{ .appended = {} };348 return Result{ .appended = {} };
312 },349 },
313 .field_ptr => {350 .field_ptr => {
314 const target = bin_file.options.target;
315 const field_ptr = typed_value.val.castTag(.field_ptr).?.data;351 const field_ptr = typed_value.val.castTag(.field_ptr).?.data;
316 const container_ptr = field_ptr.container_ptr;352 const container_ptr = field_ptr.container_ptr;
317353
...@@ -373,7 +409,6 @@ pub fn generateSymbol(...@@ -373,7 +409,6 @@ pub fn generateSymbol(
373 },409 },
374 .Int => {410 .Int => {
375 // TODO populate .debug_info for the integer411 // TODO populate .debug_info for the integer
376 const endian = bin_file.options.target.cpu.arch.endian();
377 const info = typed_value.ty.intInfo(bin_file.options.target);412 const info = typed_value.ty.intInfo(bin_file.options.target);
378 if (info.bits <= 8) {413 if (info.bits <= 8) {
379 const x = @intCast(u8, typed_value.val.toUnsignedInt());414 const x = @intCast(u8, typed_value.val.toUnsignedInt());
...@@ -423,7 +458,6 @@ pub fn generateSymbol(...@@ -423,7 +458,6 @@ pub fn generateSymbol(
423 var int_buffer: Value.Payload.U64 = undefined;458 var int_buffer: Value.Payload.U64 = undefined;
424 const int_val = typed_value.enumToInt(&int_buffer);459 const int_val = typed_value.enumToInt(&int_buffer);
425460
426 const target = bin_file.options.target;
427 const info = typed_value.ty.intInfo(target);461 const info = typed_value.ty.intInfo(target);
428 if (info.bits <= 8) {462 if (info.bits <= 8) {
429 const x = @intCast(u8, int_val.toUnsignedInt());463 const x = @intCast(u8, int_val.toUnsignedInt());
...@@ -440,7 +474,6 @@ pub fn generateSymbol(...@@ -440,7 +474,6 @@ pub fn generateSymbol(
440 ),474 ),
441 };475 };
442 }476 }
443 const endian = target.cpu.arch.endian();
444 switch (info.signedness) {477 switch (info.signedness) {
445 .unsigned => {478 .unsigned => {
446 if (info.bits <= 16) {479 if (info.bits <= 16) {
...@@ -506,7 +539,6 @@ pub fn generateSymbol(...@@ -506,7 +539,6 @@ pub fn generateSymbol(
506 const unpadded_field_end = code.items.len - struct_begin;539 const unpadded_field_end = code.items.len - struct_begin;
507540
508 // Pad struct members if required541 // Pad struct members if required
509 const target = bin_file.options.target;
510 const padded_field_end = typed_value.ty.structFieldOffset(index + 1, target);542 const padded_field_end = typed_value.ty.structFieldOffset(index + 1, target);
511 const padding = try math.cast(usize, padded_field_end - unpadded_field_end);543 const padding = try math.cast(usize, padded_field_end - unpadded_field_end);
512544
...@@ -519,7 +551,6 @@ pub fn generateSymbol(...@@ -519,7 +551,6 @@ pub fn generateSymbol(
519 },551 },
520 .Union => {552 .Union => {
521 // TODO generate debug info for unions553 // TODO generate debug info for unions
522 const target = bin_file.options.target;
523 const union_obj = typed_value.val.castTag(.@"union").?.data;554 const union_obj = typed_value.val.castTag(.@"union").?.data;
524 const layout = typed_value.ty.unionGetLayout(target);555 const layout = typed_value.ty.unionGetLayout(target);
525556
...@@ -590,19 +621,69 @@ pub fn generateSymbol(...@@ -590,19 +621,69 @@ pub fn generateSymbol(
590 return Result{ .appended = {} };621 return Result{ .appended = {} };
591 },622 },
592 .Optional => {623 .Optional => {
593 // TODO generateSymbol for optionals624 // TODO generate debug info for optionals
594 const target = bin_file.options.target;625 var opt_buf: Type.Payload.ElemType = undefined;
626 const payload_type = typed_value.ty.optionalChild(&opt_buf);
627 const is_pl = !typed_value.val.isNull();
595 const abi_size = try math.cast(usize, typed_value.ty.abiSize(target));628 const abi_size = try math.cast(usize, typed_value.ty.abiSize(target));
596 try code.writer().writeByteNTimes(0xaa, abi_size);629 const offset = abi_size - try math.cast(usize, payload_type.abiSize(target));
630
631 if (!payload_type.hasRuntimeBits()) {
632 try code.writer().writeByteNTimes(@boolToInt(is_pl), abi_size);
633 return Result{ .appended = {} };
634 }
635
636 if (typed_value.ty.isPtrLikeOptional()) {
637 if (typed_value.val.castTag(.opt_payload)) |payload| {
638 switch (try generateSymbol(bin_file, src_loc, .{
639 .ty = payload_type,
640 .val = payload.data,
641 }, code, debug_output, reloc_info)) {
642 .appended => {},
643 .externally_managed => |external_slice| {
644 code.appendSliceAssumeCapacity(external_slice);
645 },
646 .fail => |em| return Result{ .fail = em },
647 }
648 } else if (!typed_value.val.isNull()) {
649 switch (try generateSymbol(bin_file, src_loc, .{
650 .ty = payload_type,
651 .val = typed_value.val,
652 }, code, debug_output, reloc_info)) {
653 .appended => {},
654 .externally_managed => |external_slice| {
655 code.appendSliceAssumeCapacity(external_slice);
656 },
657 .fail => |em| return Result{ .fail = em },
658 }
659 } else {
660 try code.writer().writeByteNTimes(0, abi_size);
661 }
662
663 return Result{ .appended = {} };
664 }
665
666 const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.initTag(.undef);
667 try code.writer().writeByteNTimes(@boolToInt(is_pl), offset);
668 switch (try generateSymbol(bin_file, src_loc, .{
669 .ty = payload_type,
670 .val = value,
671 }, code, debug_output, reloc_info)) {
672 .appended => {},
673 .externally_managed => |external_slice| {
674 code.appendSliceAssumeCapacity(external_slice);
675 },
676 .fail => |em| return Result{ .fail = em },
677 }
597678
598 return Result{ .appended = {} };679 return Result{ .appended = {} };
599 },680 },
600 .ErrorUnion => {681 .ErrorUnion => {
682 // TODO generate debug info for error unions
601 const error_ty = typed_value.ty.errorUnionSet();683 const error_ty = typed_value.ty.errorUnionSet();
602 const payload_ty = typed_value.ty.errorUnionPayload();684 const payload_ty = typed_value.ty.errorUnionPayload();
603 const is_payload = typed_value.val.errorUnionIsPayload();685 const is_payload = typed_value.val.errorUnionIsPayload();
604686
605 const target = bin_file.options.target;
606 const abi_align = typed_value.ty.abiAlignment(target);687 const abi_align = typed_value.ty.abiAlignment(target);
607688
608 const error_val = if (!is_payload) typed_value.val else Value.initTag(.zero);689 const error_val = if (!is_payload) typed_value.val else Value.initTag(.zero);
...@@ -643,12 +724,11 @@ pub fn generateSymbol(...@@ -643,12 +724,11 @@ pub fn generateSymbol(
643 return Result{ .appended = {} };724 return Result{ .appended = {} };
644 },725 },
645 .ErrorSet => {726 .ErrorSet => {
646 const target = bin_file.options.target;727 // TODO generate debug info for error sets
647 switch (typed_value.val.tag()) {728 switch (typed_value.val.tag()) {
648 .@"error" => {729 .@"error" => {
649 const name = typed_value.val.getError().?;730 const name = typed_value.val.getError().?;
650 const kv = try bin_file.options.module.?.getErrorValue(name);731 const kv = try bin_file.options.module.?.getErrorValue(name);
651 const endian = target.cpu.arch.endian();
652 try code.writer().writeInt(u32, kv.value, endian);732 try code.writer().writeInt(u32, kv.value, endian);
653 },733 },
654 else => {734 else => {