| author | |
| committer | |
| log | 0f38f686964664f68e013ec3c63cfe655001f165 |
| tree | e8ed5924afcce0b9783c664e8e0c4c7d04e34d6f |
| parent | 0ffc6b5cc300e750029c9ff22f6a1ed0596496d6 |
to the link infrastructure, instead of being stored with Module.Fn. This
moves towards a strategy to make more efficient use of memory by not
storing Air or Liveness data in the Fn struct, but computing it on
demand, immediately sending it to the backend, and then immediately
freeing it.
Backends which want to defer codegen until flush() such as SPIR-V
must move the Air/Liveness data upon `updateFunc` being called and keep
track of that data in the backend implementation itself.18 files changed, 1023 insertions(+), 713 deletions(-)
BRANCH_TODO+5| ... | @@ -690,3 +690,8 @@ pub fn dumpInst(mod: *Module, scope: *Scope, inst: *ir.Inst) void { | ... | @@ -690,3 +690,8 @@ pub fn dumpInst(mod: *Module, scope: *Scope, inst: *ir.Inst) void { |
| 690 | } | 690 | } |
| 691 | } | 691 | } |
| 692 | 692 | ||
| 693 | /// For debugging purposes. | ||
| 694 | pub fn dump(func: *Fn, mod: Module) void { | ||
| 695 | ir.dumpFn(mod, func); | ||
| 696 | } | ||
| 697 |
src/Compilation.zig+1-1| ... | @@ -2027,7 +2027,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor | ... | @@ -2027,7 +2027,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 2027 | defer liveness.deinit(gpa); | 2027 | defer liveness.deinit(gpa); |
| 2028 | 2028 | ||
| 2029 | if (std.builtin.mode == .Debug and self.verbose_air) { | 2029 | if (std.builtin.mode == .Debug and self.verbose_air) { |
| 2030 | func.dump(module.*); | 2030 | @panic("TODO implement dumping AIR and liveness"); |
| 2031 | } | 2031 | } |
| 2032 | 2032 | ||
| 2033 | assert(decl.ty.hasCodeGenBits()); | 2033 | assert(decl.ty.hasCodeGenBits()); |
src/Liveness.zig+5-4| ... | @@ -50,7 +50,7 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness { | ... | @@ -50,7 +50,7 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness { |
| 50 | 50 | ||
| 51 | var a: Analysis = .{ | 51 | var a: Analysis = .{ |
| 52 | .gpa = gpa, | 52 | .gpa = gpa, |
| 53 | .air = &air, | 53 | .air = air, |
| 54 | .table = .{}, | 54 | .table = .{}, |
| 55 | .tomb_bits = try gpa.alloc( | 55 | .tomb_bits = try gpa.alloc( |
| 56 | usize, | 56 | usize, |
| ... | @@ -65,7 +65,7 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness { | ... | @@ -65,7 +65,7 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness { |
| 65 | defer a.table.deinit(gpa); | 65 | defer a.table.deinit(gpa); |
| 66 | 66 | ||
| 67 | const main_body = air.getMainBody(); | 67 | const main_body = air.getMainBody(); |
| 68 | try a.table.ensureTotalCapacity(main_body.len); | 68 | try a.table.ensureTotalCapacity(gpa, @intCast(u32, main_body.len)); |
| 69 | try analyzeWithContext(&a, null, main_body); | 69 | try analyzeWithContext(&a, null, main_body); |
| 70 | return Liveness{ | 70 | return Liveness{ |
| 71 | .tomb_bits = a.tomb_bits, | 71 | .tomb_bits = a.tomb_bits, |
| ... | @@ -108,9 +108,10 @@ const OperandInt = std.math.Log2Int(Bpi); | ... | @@ -108,9 +108,10 @@ const OperandInt = std.math.Log2Int(Bpi); |
| 108 | /// In-progress data; on successful analysis converted into `Liveness`. | 108 | /// In-progress data; on successful analysis converted into `Liveness`. |
| 109 | const Analysis = struct { | 109 | const Analysis = struct { |
| 110 | gpa: *Allocator, | 110 | gpa: *Allocator, |
| 111 | air: *const Air, | 111 | air: Air, |
| 112 | table: std.AutoHashMapUnmanaged(Air.Inst.Index, void), | 112 | table: std.AutoHashMapUnmanaged(Air.Inst.Index, void), |
| 113 | tomb_bits: []usize, | 113 | tomb_bits: []usize, |
| 114 | special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32), | ||
| 114 | extra: std.ArrayListUnmanaged(u32), | 115 | extra: std.ArrayListUnmanaged(u32), |
| 115 | 116 | ||
| 116 | fn storeTombBits(a: *Analysis, inst: Air.Inst.Index, tomb_bits: Bpi) void { | 117 | fn storeTombBits(a: *Analysis, inst: Air.Inst.Index, tomb_bits: Bpi) void { |
| ... | @@ -165,7 +166,7 @@ fn analyzeWithContext( | ... | @@ -165,7 +166,7 @@ fn analyzeWithContext( |
| 165 | 166 | ||
| 166 | fn analyzeInst( | 167 | fn analyzeInst( |
| 167 | a: *Analysis, | 168 | a: *Analysis, |
| 168 | new_set: ?*std.AutoHashMap(Air.Inst.Index, void), | 169 | new_set: ?*std.AutoHashMapUnmanaged(Air.Inst.Index, void), |
| 169 | inst: Air.Inst.Index, | 170 | inst: Air.Inst.Index, |
| 170 | ) Allocator.Error!void { | 171 | ) Allocator.Error!void { |
| 171 | const gpa = a.gpa; | 172 | const gpa = a.gpa; |
src/Module.zig-5| ... | @@ -769,11 +769,6 @@ pub const Fn = struct { | ... | @@ -769,11 +769,6 @@ pub const Fn = struct { |
| 769 | success, | 769 | success, |
| 770 | }; | 770 | }; |
| 771 | 771 | ||
| 772 | /// For debugging purposes. | ||
| 773 | pub fn dump(func: *Fn, mod: Module) void { | ||
| 774 | ir.dumpFn(mod, func); | ||
| 775 | } | ||
| 776 | |||
| 777 | pub fn deinit(func: *Fn, gpa: *Allocator) void { | 772 | pub fn deinit(func: *Fn, gpa: *Allocator) void { |
| 778 | if (func.getInferredErrorSet()) |map| { | 773 | if (func.getInferredErrorSet()) |map| { |
| 779 | map.deinit(gpa); | 774 | map.deinit(gpa); |
src/Sema.zig+385-377| ... | @@ -69,7 +69,7 @@ const LazySrcLoc = Module.LazySrcLoc; | ... | @@ -69,7 +69,7 @@ const LazySrcLoc = Module.LazySrcLoc; |
| 69 | const RangeSet = @import("RangeSet.zig"); | 69 | const RangeSet = @import("RangeSet.zig"); |
| 70 | const target_util = @import("target.zig"); | 70 | const target_util = @import("target.zig"); |
| 71 | 71 | ||
| 72 | pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Index); | 72 | pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref); |
| 73 | 73 | ||
| 74 | pub fn deinit(sema: *Sema) void { | 74 | pub fn deinit(sema: *Sema) void { |
| 75 | const gpa = sema.gpa; | 75 | const gpa = sema.gpa; |
| ... | @@ -158,344 +158,344 @@ pub fn analyzeBody( | ... | @@ -158,344 +158,344 @@ pub fn analyzeBody( |
| 158 | var i: usize = 0; | 158 | var i: usize = 0; |
| 159 | while (true) { | 159 | while (true) { |
| 160 | const inst = body[i]; | 160 | const inst = body[i]; |
| 161 | const air_inst = switch (tags[inst]) { | 161 | const air_inst: Air.Inst.Ref = switch (tags[inst]) { |
| 162 | // zig fmt: off | 162 | // zig fmt: off |
| 163 | .arg => try sema.zirArg(block, inst), | 163 | .arg => try sema.zirArg(block, inst), |
| 164 | .alloc => try sema.zirAlloc(block, inst), | 164 | //.alloc => try sema.zirAlloc(block, inst), |
| 165 | .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), | 165 | //.alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), |
| 166 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), | 166 | //.alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), |
| 167 | .alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst), | 167 | //.alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst), |
| 168 | .alloc_mut => try sema.zirAllocMut(block, inst), | 168 | //.alloc_mut => try sema.zirAllocMut(block, inst), |
| 169 | .alloc_comptime => try sema.zirAllocComptime(block, inst), | 169 | //.alloc_comptime => try sema.zirAllocComptime(block, inst), |
| 170 | .anyframe_type => try sema.zirAnyframeType(block, inst), | 170 | //.anyframe_type => try sema.zirAnyframeType(block, inst), |
| 171 | .array_cat => try sema.zirArrayCat(block, inst), | 171 | //.array_cat => try sema.zirArrayCat(block, inst), |
| 172 | .array_mul => try sema.zirArrayMul(block, inst), | 172 | //.array_mul => try sema.zirArrayMul(block, inst), |
| 173 | .array_type => try sema.zirArrayType(block, inst), | 173 | //.array_type => try sema.zirArrayType(block, inst), |
| 174 | .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst), | 174 | //.array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst), |
| 175 | .vector_type => try sema.zirVectorType(block, inst), | 175 | //.vector_type => try sema.zirVectorType(block, inst), |
| 176 | .as => try sema.zirAs(block, inst), | 176 | //.as => try sema.zirAs(block, inst), |
| 177 | .as_node => try sema.zirAsNode(block, inst), | 177 | //.as_node => try sema.zirAsNode(block, inst), |
| 178 | .bit_and => try sema.zirBitwise(block, inst, .bit_and), | 178 | //.bit_and => try sema.zirBitwise(block, inst, .bit_and), |
| 179 | .bit_not => try sema.zirBitNot(block, inst), | 179 | //.bit_not => try sema.zirBitNot(block, inst), |
| 180 | .bit_or => try sema.zirBitwise(block, inst, .bit_or), | 180 | //.bit_or => try sema.zirBitwise(block, inst, .bit_or), |
| 181 | .bitcast => try sema.zirBitcast(block, inst), | 181 | //.bitcast => try sema.zirBitcast(block, inst), |
| 182 | .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst), | 182 | //.bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst), |
| 183 | .block => try sema.zirBlock(block, inst), | 183 | //.block => try sema.zirBlock(block, inst), |
| 184 | .suspend_block => try sema.zirSuspendBlock(block, inst), | 184 | //.suspend_block => try sema.zirSuspendBlock(block, inst), |
| 185 | .bool_not => try sema.zirBoolNot(block, inst), | 185 | //.bool_not => try sema.zirBoolNot(block, inst), |
| 186 | .bool_and => try sema.zirBoolOp(block, inst, false), | 186 | //.bool_and => try sema.zirBoolOp(block, inst, false), |
| 187 | .bool_or => try sema.zirBoolOp(block, inst, true), | 187 | //.bool_or => try sema.zirBoolOp(block, inst, true), |
| 188 | .bool_br_and => try sema.zirBoolBr(block, inst, false), | 188 | //.bool_br_and => try sema.zirBoolBr(block, inst, false), |
| 189 | .bool_br_or => try sema.zirBoolBr(block, inst, true), | 189 | //.bool_br_or => try sema.zirBoolBr(block, inst, true), |
| 190 | .c_import => try sema.zirCImport(block, inst), | 190 | //.c_import => try sema.zirCImport(block, inst), |
| 191 | .call => try sema.zirCall(block, inst, .auto, false), | 191 | //.call => try sema.zirCall(block, inst, .auto, false), |
| 192 | .call_chkused => try sema.zirCall(block, inst, .auto, true), | 192 | //.call_chkused => try sema.zirCall(block, inst, .auto, true), |
| 193 | .call_compile_time => try sema.zirCall(block, inst, .compile_time, false), | 193 | //.call_compile_time => try sema.zirCall(block, inst, .compile_time, false), |
| 194 | .call_nosuspend => try sema.zirCall(block, inst, .no_async, false), | 194 | //.call_nosuspend => try sema.zirCall(block, inst, .no_async, false), |
| 195 | .call_async => try sema.zirCall(block, inst, .async_kw, false), | 195 | //.call_async => try sema.zirCall(block, inst, .async_kw, false), |
| 196 | .cmp_eq => try sema.zirCmp(block, inst, .eq), | 196 | //.cmp_eq => try sema.zirCmp(block, inst, .eq), |
| 197 | .cmp_gt => try sema.zirCmp(block, inst, .gt), | 197 | //.cmp_gt => try sema.zirCmp(block, inst, .gt), |
| 198 | .cmp_gte => try sema.zirCmp(block, inst, .gte), | 198 | //.cmp_gte => try sema.zirCmp(block, inst, .gte), |
| 199 | .cmp_lt => try sema.zirCmp(block, inst, .lt), | 199 | //.cmp_lt => try sema.zirCmp(block, inst, .lt), |
| 200 | .cmp_lte => try sema.zirCmp(block, inst, .lte), | 200 | //.cmp_lte => try sema.zirCmp(block, inst, .lte), |
| 201 | .cmp_neq => try sema.zirCmp(block, inst, .neq), | 201 | //.cmp_neq => try sema.zirCmp(block, inst, .neq), |
| 202 | .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), | 202 | //.coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), |
| 203 | .decl_ref => try sema.zirDeclRef(block, inst), | 203 | //.decl_ref => try sema.zirDeclRef(block, inst), |
| 204 | .decl_val => try sema.zirDeclVal(block, inst), | 204 | //.decl_val => try sema.zirDeclVal(block, inst), |
| 205 | .load => try sema.zirLoad(block, inst), | 205 | //.load => try sema.zirLoad(block, inst), |
| 206 | .elem_ptr => try sema.zirElemPtr(block, inst), | 206 | //.elem_ptr => try sema.zirElemPtr(block, inst), |
| 207 | .elem_ptr_node => try sema.zirElemPtrNode(block, inst), | 207 | //.elem_ptr_node => try sema.zirElemPtrNode(block, inst), |
| 208 | .elem_val => try sema.zirElemVal(block, inst), | 208 | //.elem_val => try sema.zirElemVal(block, inst), |
| 209 | .elem_val_node => try sema.zirElemValNode(block, inst), | 209 | //.elem_val_node => try sema.zirElemValNode(block, inst), |
| 210 | .elem_type => try sema.zirElemType(block, inst), | 210 | //.elem_type => try sema.zirElemType(block, inst), |
| 211 | .enum_literal => try sema.zirEnumLiteral(block, inst), | 211 | //.enum_literal => try sema.zirEnumLiteral(block, inst), |
| 212 | .enum_to_int => try sema.zirEnumToInt(block, inst), | 212 | //.enum_to_int => try sema.zirEnumToInt(block, inst), |
| 213 | .int_to_enum => try sema.zirIntToEnum(block, inst), | 213 | //.int_to_enum => try sema.zirIntToEnum(block, inst), |
| 214 | .err_union_code => try sema.zirErrUnionCode(block, inst), | 214 | //.err_union_code => try sema.zirErrUnionCode(block, inst), |
| 215 | .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst), | 215 | //.err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst), |
| 216 | .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true), | 216 | //.err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true), |
| 217 | .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true), | 217 | //.err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true), |
| 218 | .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false), | 218 | //.err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false), |
| 219 | .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false), | 219 | //.err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false), |
| 220 | .error_union_type => try sema.zirErrorUnionType(block, inst), | 220 | //.error_union_type => try sema.zirErrorUnionType(block, inst), |
| 221 | .error_value => try sema.zirErrorValue(block, inst), | 221 | //.error_value => try sema.zirErrorValue(block, inst), |
| 222 | .error_to_int => try sema.zirErrorToInt(block, inst), | 222 | //.error_to_int => try sema.zirErrorToInt(block, inst), |
| 223 | .int_to_error => try sema.zirIntToError(block, inst), | 223 | //.int_to_error => try sema.zirIntToError(block, inst), |
| 224 | .field_ptr => try sema.zirFieldPtr(block, inst), | 224 | //.field_ptr => try sema.zirFieldPtr(block, inst), |
| 225 | .field_ptr_named => try sema.zirFieldPtrNamed(block, inst), | 225 | //.field_ptr_named => try sema.zirFieldPtrNamed(block, inst), |
| 226 | .field_val => try sema.zirFieldVal(block, inst), | 226 | //.field_val => try sema.zirFieldVal(block, inst), |
| 227 | .field_val_named => try sema.zirFieldValNamed(block, inst), | 227 | //.field_val_named => try sema.zirFieldValNamed(block, inst), |
| 228 | .func => try sema.zirFunc(block, inst, false), | 228 | //.func => try sema.zirFunc(block, inst, false), |
| 229 | .func_inferred => try sema.zirFunc(block, inst, true), | 229 | //.func_inferred => try sema.zirFunc(block, inst, true), |
| 230 | .import => try sema.zirImport(block, inst), | 230 | //.import => try sema.zirImport(block, inst), |
| 231 | .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst), | 231 | //.indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst), |
| 232 | .int => try sema.zirInt(block, inst), | 232 | //.int => try sema.zirInt(block, inst), |
| 233 | .int_big => try sema.zirIntBig(block, inst), | 233 | //.int_big => try sema.zirIntBig(block, inst), |
| 234 | .float => try sema.zirFloat(block, inst), | 234 | //.float => try sema.zirFloat(block, inst), |
| 235 | .float128 => try sema.zirFloat128(block, inst), | 235 | //.float128 => try sema.zirFloat128(block, inst), |
| 236 | .int_type => try sema.zirIntType(block, inst), | 236 | //.int_type => try sema.zirIntType(block, inst), |
| 237 | .is_non_err => try sema.zirIsNonErr(block, inst), | 237 | //.is_non_err => try sema.zirIsNonErr(block, inst), |
| 238 | .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), | 238 | //.is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), |
| 239 | .is_non_null => try sema.zirIsNonNull(block, inst), | 239 | //.is_non_null => try sema.zirIsNonNull(block, inst), |
| 240 | .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst), | 240 | //.is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst), |
| 241 | .loop => try sema.zirLoop(block, inst), | 241 | //.loop => try sema.zirLoop(block, inst), |
| 242 | .merge_error_sets => try sema.zirMergeErrorSets(block, inst), | 242 | //.merge_error_sets => try sema.zirMergeErrorSets(block, inst), |
| 243 | .negate => try sema.zirNegate(block, inst, .sub), | 243 | //.negate => try sema.zirNegate(block, inst, .sub), |
| 244 | .negate_wrap => try sema.zirNegate(block, inst, .subwrap), | 244 | //.negate_wrap => try sema.zirNegate(block, inst, .subwrap), |
| 245 | .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true), | 245 | //.optional_payload_safe => try sema.zirOptionalPayload(block, inst, true), |
| 246 | .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true), | 246 | //.optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true), |
| 247 | .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), | 247 | //.optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), |
| 248 | .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), | 248 | //.optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), |
| 249 | .optional_type => try sema.zirOptionalType(block, inst), | 249 | //.optional_type => try sema.zirOptionalType(block, inst), |
| 250 | .param_type => try sema.zirParamType(block, inst), | 250 | //.param_type => try sema.zirParamType(block, inst), |
| 251 | .ptr_type => try sema.zirPtrType(block, inst), | 251 | //.ptr_type => try sema.zirPtrType(block, inst), |
| 252 | .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst), | 252 | //.ptr_type_simple => try sema.zirPtrTypeSimple(block, inst), |
| 253 | .ref => try sema.zirRef(block, inst), | 253 | //.ref => try sema.zirRef(block, inst), |
| 254 | .ret_err_value_code => try sema.zirRetErrValueCode(block, inst), | 254 | //.ret_err_value_code => try sema.zirRetErrValueCode(block, inst), |
| 255 | .shl => try sema.zirShl(block, inst), | 255 | //.shl => try sema.zirShl(block, inst), |
| 256 | .shr => try sema.zirShr(block, inst), | 256 | //.shr => try sema.zirShr(block, inst), |
| 257 | .slice_end => try sema.zirSliceEnd(block, inst), | 257 | //.slice_end => try sema.zirSliceEnd(block, inst), |
| 258 | .slice_sentinel => try sema.zirSliceSentinel(block, inst), | 258 | //.slice_sentinel => try sema.zirSliceSentinel(block, inst), |
| 259 | .slice_start => try sema.zirSliceStart(block, inst), | 259 | //.slice_start => try sema.zirSliceStart(block, inst), |
| 260 | .str => try sema.zirStr(block, inst), | 260 | //.str => try sema.zirStr(block, inst), |
| 261 | .switch_block => try sema.zirSwitchBlock(block, inst, false, .none), | 261 | //.switch_block => try sema.zirSwitchBlock(block, inst, false, .none), |
| 262 | .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none), | 262 | //.switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none), |
| 263 | .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"), | 263 | //.switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"), |
| 264 | .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"), | 264 | //.switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"), |
| 265 | .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under), | 265 | //.switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under), |
| 266 | .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under), | 266 | //.switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under), |
| 267 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none), | 267 | //.switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none), |
| 268 | .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none), | 268 | //.switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none), |
| 269 | .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"), | 269 | //.switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"), |
| 270 | .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"), | 270 | //.switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"), |
| 271 | .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under), | 271 | //.switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under), |
| 272 | .switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under), | 272 | //.switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under), |
| 273 | .switch_capture => try sema.zirSwitchCapture(block, inst, false, false), | 273 | //.switch_capture => try sema.zirSwitchCapture(block, inst, false, false), |
| 274 | .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), | 274 | //.switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true), |
| 275 | .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), | 275 | //.switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false), |
| 276 | .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), | 276 | //.switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true), |
| 277 | .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false), | 277 | //.switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false), |
| 278 | .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true), | 278 | //.switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true), |
| 279 | .type_info => try sema.zirTypeInfo(block, inst), | 279 | //.type_info => try sema.zirTypeInfo(block, inst), |
| 280 | .size_of => try sema.zirSizeOf(block, inst), | 280 | //.size_of => try sema.zirSizeOf(block, inst), |
| 281 | .bit_size_of => try sema.zirBitSizeOf(block, inst), | 281 | //.bit_size_of => try sema.zirBitSizeOf(block, inst), |
| 282 | .typeof => try sema.zirTypeof(block, inst), | 282 | //.typeof => try sema.zirTypeof(block, inst), |
| 283 | .typeof_elem => try sema.zirTypeofElem(block, inst), | 283 | //.typeof_elem => try sema.zirTypeofElem(block, inst), |
| 284 | .log2_int_type => try sema.zirLog2IntType(block, inst), | 284 | //.log2_int_type => try sema.zirLog2IntType(block, inst), |
| 285 | .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst), | 285 | //.typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst), |
| 286 | .xor => try sema.zirBitwise(block, inst, .xor), | 286 | //.xor => try sema.zirBitwise(block, inst, .xor), |
| 287 | .struct_init_empty => try sema.zirStructInitEmpty(block, inst), | 287 | //.struct_init_empty => try sema.zirStructInitEmpty(block, inst), |
| 288 | .struct_init => try sema.zirStructInit(block, inst, false), | 288 | //.struct_init => try sema.zirStructInit(block, inst, false), |
| 289 | .struct_init_ref => try sema.zirStructInit(block, inst, true), | 289 | //.struct_init_ref => try sema.zirStructInit(block, inst, true), |
| 290 | .struct_init_anon => try sema.zirStructInitAnon(block, inst, false), | 290 | //.struct_init_anon => try sema.zirStructInitAnon(block, inst, false), |
| 291 | .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true), | 291 | //.struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true), |
| 292 | .array_init => try sema.zirArrayInit(block, inst, false), | 292 | //.array_init => try sema.zirArrayInit(block, inst, false), |
| 293 | .array_init_ref => try sema.zirArrayInit(block, inst, true), | 293 | //.array_init_ref => try sema.zirArrayInit(block, inst, true), |
| 294 | .array_init_anon => try sema.zirArrayInitAnon(block, inst, false), | 294 | //.array_init_anon => try sema.zirArrayInitAnon(block, inst, false), |
| 295 | .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true), | 295 | //.array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true), |
| 296 | .union_init_ptr => try sema.zirUnionInitPtr(block, inst), | 296 | //.union_init_ptr => try sema.zirUnionInitPtr(block, inst), |
| 297 | .field_type => try sema.zirFieldType(block, inst), | 297 | //.field_type => try sema.zirFieldType(block, inst), |
| 298 | .field_type_ref => try sema.zirFieldTypeRef(block, inst), | 298 | //.field_type_ref => try sema.zirFieldTypeRef(block, inst), |
| 299 | .ptr_to_int => try sema.zirPtrToInt(block, inst), | 299 | //.ptr_to_int => try sema.zirPtrToInt(block, inst), |
| 300 | .align_of => try sema.zirAlignOf(block, inst), | 300 | //.align_of => try sema.zirAlignOf(block, inst), |
| 301 | .bool_to_int => try sema.zirBoolToInt(block, inst), | 301 | //.bool_to_int => try sema.zirBoolToInt(block, inst), |
| 302 | .embed_file => try sema.zirEmbedFile(block, inst), | 302 | //.embed_file => try sema.zirEmbedFile(block, inst), |
| 303 | .error_name => try sema.zirErrorName(block, inst), | 303 | //.error_name => try sema.zirErrorName(block, inst), |
| 304 | .tag_name => try sema.zirTagName(block, inst), | 304 | //.tag_name => try sema.zirTagName(block, inst), |
| 305 | .reify => try sema.zirReify(block, inst), | 305 | //.reify => try sema.zirReify(block, inst), |
| 306 | .type_name => try sema.zirTypeName(block, inst), | 306 | //.type_name => try sema.zirTypeName(block, inst), |
| 307 | .frame_type => try sema.zirFrameType(block, inst), | 307 | //.frame_type => try sema.zirFrameType(block, inst), |
| 308 | .frame_size => try sema.zirFrameSize(block, inst), | 308 | //.frame_size => try sema.zirFrameSize(block, inst), |
| 309 | .float_to_int => try sema.zirFloatToInt(block, inst), | 309 | //.float_to_int => try sema.zirFloatToInt(block, inst), |
| 310 | .int_to_float => try sema.zirIntToFloat(block, inst), | 310 | //.int_to_float => try sema.zirIntToFloat(block, inst), |
| 311 | .int_to_ptr => try sema.zirIntToPtr(block, inst), | 311 | //.int_to_ptr => try sema.zirIntToPtr(block, inst), |
| 312 | .float_cast => try sema.zirFloatCast(block, inst), | 312 | //.float_cast => try sema.zirFloatCast(block, inst), |
| 313 | .int_cast => try sema.zirIntCast(block, inst), | 313 | //.int_cast => try sema.zirIntCast(block, inst), |
| 314 | .err_set_cast => try sema.zirErrSetCast(block, inst), | 314 | //.err_set_cast => try sema.zirErrSetCast(block, inst), |
| 315 | .ptr_cast => try sema.zirPtrCast(block, inst), | 315 | //.ptr_cast => try sema.zirPtrCast(block, inst), |
| 316 | .truncate => try sema.zirTruncate(block, inst), | 316 | //.truncate => try sema.zirTruncate(block, inst), |
| 317 | .align_cast => try sema.zirAlignCast(block, inst), | 317 | //.align_cast => try sema.zirAlignCast(block, inst), |
| 318 | .has_decl => try sema.zirHasDecl(block, inst), | 318 | //.has_decl => try sema.zirHasDecl(block, inst), |
| 319 | .has_field => try sema.zirHasField(block, inst), | 319 | //.has_field => try sema.zirHasField(block, inst), |
| 320 | .clz => try sema.zirClz(block, inst), | 320 | //.clz => try sema.zirClz(block, inst), |
| 321 | .ctz => try sema.zirCtz(block, inst), | 321 | //.ctz => try sema.zirCtz(block, inst), |
| 322 | .pop_count => try sema.zirPopCount(block, inst), | 322 | //.pop_count => try sema.zirPopCount(block, inst), |
| 323 | .byte_swap => try sema.zirByteSwap(block, inst), | 323 | //.byte_swap => try sema.zirByteSwap(block, inst), |
| 324 | .bit_reverse => try sema.zirBitReverse(block, inst), | 324 | //.bit_reverse => try sema.zirBitReverse(block, inst), |
| 325 | .div_exact => try sema.zirDivExact(block, inst), | 325 | //.div_exact => try sema.zirDivExact(block, inst), |
| 326 | .div_floor => try sema.zirDivFloor(block, inst), | 326 | //.div_floor => try sema.zirDivFloor(block, inst), |
| 327 | .div_trunc => try sema.zirDivTrunc(block, inst), | 327 | //.div_trunc => try sema.zirDivTrunc(block, inst), |
| 328 | .mod => try sema.zirMod(block, inst), | 328 | //.mod => try sema.zirMod(block, inst), |
| 329 | .rem => try sema.zirRem(block, inst), | 329 | //.rem => try sema.zirRem(block, inst), |
| 330 | .shl_exact => try sema.zirShlExact(block, inst), | 330 | //.shl_exact => try sema.zirShlExact(block, inst), |
| 331 | .shr_exact => try sema.zirShrExact(block, inst), | 331 | //.shr_exact => try sema.zirShrExact(block, inst), |
| 332 | .bit_offset_of => try sema.zirBitOffsetOf(block, inst), | 332 | //.bit_offset_of => try sema.zirBitOffsetOf(block, inst), |
| 333 | .offset_of => try sema.zirOffsetOf(block, inst), | 333 | //.offset_of => try sema.zirOffsetOf(block, inst), |
| 334 | .cmpxchg_strong => try sema.zirCmpxchg(block, inst), | 334 | //.cmpxchg_strong => try sema.zirCmpxchg(block, inst), |
| 335 | .cmpxchg_weak => try sema.zirCmpxchg(block, inst), | 335 | //.cmpxchg_weak => try sema.zirCmpxchg(block, inst), |
| 336 | .splat => try sema.zirSplat(block, inst), | 336 | //.splat => try sema.zirSplat(block, inst), |
| 337 | .reduce => try sema.zirReduce(block, inst), | 337 | //.reduce => try sema.zirReduce(block, inst), |
| 338 | .shuffle => try sema.zirShuffle(block, inst), | 338 | //.shuffle => try sema.zirShuffle(block, inst), |
| 339 | .atomic_load => try sema.zirAtomicLoad(block, inst), | 339 | //.atomic_load => try sema.zirAtomicLoad(block, inst), |
| 340 | .atomic_rmw => try sema.zirAtomicRmw(block, inst), | 340 | //.atomic_rmw => try sema.zirAtomicRmw(block, inst), |
| 341 | .atomic_store => try sema.zirAtomicStore(block, inst), | 341 | //.atomic_store => try sema.zirAtomicStore(block, inst), |
| 342 | .mul_add => try sema.zirMulAdd(block, inst), | 342 | //.mul_add => try sema.zirMulAdd(block, inst), |
| 343 | .builtin_call => try sema.zirBuiltinCall(block, inst), | 343 | //.builtin_call => try sema.zirBuiltinCall(block, inst), |
| 344 | .field_ptr_type => try sema.zirFieldPtrType(block, inst), | 344 | //.field_ptr_type => try sema.zirFieldPtrType(block, inst), |
| 345 | .field_parent_ptr => try sema.zirFieldParentPtr(block, inst), | 345 | //.field_parent_ptr => try sema.zirFieldParentPtr(block, inst), |
| 346 | .memcpy => try sema.zirMemcpy(block, inst), | 346 | //.memcpy => try sema.zirMemcpy(block, inst), |
| 347 | .memset => try sema.zirMemset(block, inst), | 347 | //.memset => try sema.zirMemset(block, inst), |
| 348 | .builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst), | 348 | //.builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst), |
| 349 | .@"resume" => try sema.zirResume(block, inst), | 349 | //.@"resume" => try sema.zirResume(block, inst), |
| 350 | .@"await" => try sema.zirAwait(block, inst, false), | 350 | //.@"await" => try sema.zirAwait(block, inst, false), |
| 351 | .await_nosuspend => try sema.zirAwait(block, inst, true), | 351 | //.await_nosuspend => try sema.zirAwait(block, inst, true), |
| 352 | .extended => try sema.zirExtended(block, inst), | 352 | //.extended => try sema.zirExtended(block, inst), |
| 353 | 353 | ||
| 354 | .sqrt => try sema.zirUnaryMath(block, inst), | 354 | //.sqrt => try sema.zirUnaryMath(block, inst), |
| 355 | .sin => try sema.zirUnaryMath(block, inst), | 355 | //.sin => try sema.zirUnaryMath(block, inst), |
| 356 | .cos => try sema.zirUnaryMath(block, inst), | 356 | //.cos => try sema.zirUnaryMath(block, inst), |
| 357 | .exp => try sema.zirUnaryMath(block, inst), | 357 | //.exp => try sema.zirUnaryMath(block, inst), |
| 358 | .exp2 => try sema.zirUnaryMath(block, inst), | 358 | //.exp2 => try sema.zirUnaryMath(block, inst), |
| 359 | .log => try sema.zirUnaryMath(block, inst), | 359 | //.log => try sema.zirUnaryMath(block, inst), |
| 360 | .log2 => try sema.zirUnaryMath(block, inst), | 360 | //.log2 => try sema.zirUnaryMath(block, inst), |
| 361 | .log10 => try sema.zirUnaryMath(block, inst), | 361 | //.log10 => try sema.zirUnaryMath(block, inst), |
| 362 | .fabs => try sema.zirUnaryMath(block, inst), | 362 | //.fabs => try sema.zirUnaryMath(block, inst), |
| 363 | .floor => try sema.zirUnaryMath(block, inst), | 363 | //.floor => try sema.zirUnaryMath(block, inst), |
| 364 | .ceil => try sema.zirUnaryMath(block, inst), | 364 | //.ceil => try sema.zirUnaryMath(block, inst), |
| 365 | .trunc => try sema.zirUnaryMath(block, inst), | 365 | //.trunc => try sema.zirUnaryMath(block, inst), |
| 366 | .round => try sema.zirUnaryMath(block, inst), | 366 | //.round => try sema.zirUnaryMath(block, inst), |
| 367 | 367 | ||
| 368 | .opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent), | 368 | //.opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent), |
| 369 | .opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon), | 369 | //.opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon), |
| 370 | .opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func), | 370 | //.opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func), |
| 371 | .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent), | 371 | //.error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent), |
| 372 | .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon), | 372 | //.error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon), |
| 373 | .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func), | 373 | //.error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func), |
| 374 | 374 | ||
| 375 | .add => try sema.zirArithmetic(block, inst), | 375 | //.add => try sema.zirArithmetic(block, inst), |
| 376 | .addwrap => try sema.zirArithmetic(block, inst), | 376 | //.addwrap => try sema.zirArithmetic(block, inst), |
| 377 | .div => try sema.zirArithmetic(block, inst), | 377 | //.div => try sema.zirArithmetic(block, inst), |
| 378 | .mod_rem => try sema.zirArithmetic(block, inst), | 378 | //.mod_rem => try sema.zirArithmetic(block, inst), |
| 379 | .mul => try sema.zirArithmetic(block, inst), | 379 | //.mul => try sema.zirArithmetic(block, inst), |
| 380 | .mulwrap => try sema.zirArithmetic(block, inst), | 380 | //.mulwrap => try sema.zirArithmetic(block, inst), |
| 381 | .sub => try sema.zirArithmetic(block, inst), | 381 | //.sub => try sema.zirArithmetic(block, inst), |
| 382 | .subwrap => try sema.zirArithmetic(block, inst), | 382 | //.subwrap => try sema.zirArithmetic(block, inst), |
| 383 | 383 | ||
| 384 | // Instructions that we know to *always* be noreturn based solely on their tag. | 384 | //// Instructions that we know to *always* be noreturn based solely on their tag. |
| 385 | // These functions match the return type of analyzeBody so that we can | 385 | //// These functions match the return type of analyzeBody so that we can |
| 386 | // tail call them here. | 386 | //// tail call them here. |
| 387 | .break_inline => return inst, | 387 | //.break_inline => return inst, |
| 388 | .condbr => return sema.zirCondbr(block, inst), | 388 | //.condbr => return sema.zirCondbr(block, inst), |
| 389 | .@"break" => return sema.zirBreak(block, inst), | 389 | //.@"break" => return sema.zirBreak(block, inst), |
| 390 | .compile_error => return sema.zirCompileError(block, inst), | 390 | //.compile_error => return sema.zirCompileError(block, inst), |
| 391 | .ret_coerce => return sema.zirRetCoerce(block, inst, true), | 391 | //.ret_coerce => return sema.zirRetCoerce(block, inst, true), |
| 392 | .ret_node => return sema.zirRetNode(block, inst), | 392 | //.ret_node => return sema.zirRetNode(block, inst), |
| 393 | .ret_err_value => return sema.zirRetErrValue(block, inst), | 393 | //.ret_err_value => return sema.zirRetErrValue(block, inst), |
| 394 | .@"unreachable" => return sema.zirUnreachable(block, inst), | 394 | //.@"unreachable" => return sema.zirUnreachable(block, inst), |
| 395 | .repeat => return sema.zirRepeat(block, inst), | 395 | //.repeat => return sema.zirRepeat(block, inst), |
| 396 | .panic => return sema.zirPanic(block, inst), | 396 | //.panic => return sema.zirPanic(block, inst), |
| 397 | // zig fmt: on | 397 | //// zig fmt: on |
| 398 | 398 | ||
| 399 | // Instructions that we know can *never* be noreturn based solely on | 399 | //// Instructions that we know can *never* be noreturn based solely on |
| 400 | // their tag. We avoid needlessly checking if they are noreturn and | 400 | //// their tag. We avoid needlessly checking if they are noreturn and |
| 401 | // continue the loop. | 401 | //// continue the loop. |
| 402 | // We also know that they cannot be referenced later, so we avoid | 402 | //// We also know that they cannot be referenced later, so we avoid |
| 403 | // putting them into the map. | 403 | //// putting them into the map. |
| 404 | .breakpoint => { | 404 | //.breakpoint => { |
| 405 | try sema.zirBreakpoint(block, inst); | 405 | // try sema.zirBreakpoint(block, inst); |
| 406 | i += 1; | 406 | // i += 1; |
| 407 | continue; | 407 | // continue; |
| 408 | }, | 408 | //}, |
| 409 | .fence => { | 409 | //.fence => { |
| 410 | try sema.zirFence(block, inst); | 410 | // try sema.zirFence(block, inst); |
| 411 | i += 1; | 411 | // i += 1; |
| 412 | continue; | 412 | // continue; |
| 413 | }, | 413 | //}, |
| 414 | .dbg_stmt => { | 414 | //.dbg_stmt => { |
| 415 | try sema.zirDbgStmt(block, inst); | 415 | // try sema.zirDbgStmt(block, inst); |
| 416 | i += 1; | 416 | // i += 1; |
| 417 | continue; | 417 | // continue; |
| 418 | }, | 418 | //}, |
| 419 | .ensure_err_payload_void => { | 419 | //.ensure_err_payload_void => { |
| 420 | try sema.zirEnsureErrPayloadVoid(block, inst); | 420 | // try sema.zirEnsureErrPayloadVoid(block, inst); |
| 421 | i += 1; | 421 | // i += 1; |
| 422 | continue; | 422 | // continue; |
| 423 | }, | 423 | //}, |
| 424 | .ensure_result_non_error => { | 424 | //.ensure_result_non_error => { |
| 425 | try sema.zirEnsureResultNonError(block, inst); | 425 | // try sema.zirEnsureResultNonError(block, inst); |
| 426 | i += 1; | 426 | // i += 1; |
| 427 | continue; | 427 | // continue; |
| 428 | }, | 428 | //}, |
| 429 | .ensure_result_used => { | 429 | //.ensure_result_used => { |
| 430 | try sema.zirEnsureResultUsed(block, inst); | 430 | // try sema.zirEnsureResultUsed(block, inst); |
| 431 | i += 1; | 431 | // i += 1; |
| 432 | continue; | 432 | // continue; |
| 433 | }, | 433 | //}, |
| 434 | .set_eval_branch_quota => { | 434 | //.set_eval_branch_quota => { |
| 435 | try sema.zirSetEvalBranchQuota(block, inst); | 435 | // try sema.zirSetEvalBranchQuota(block, inst); |
| 436 | i += 1; | 436 | // i += 1; |
| 437 | continue; | 437 | // continue; |
| 438 | }, | 438 | //}, |
| 439 | .store => { | 439 | //.store => { |
| 440 | try sema.zirStore(block, inst); | 440 | // try sema.zirStore(block, inst); |
| 441 | i += 1; | 441 | // i += 1; |
| 442 | continue; | 442 | // continue; |
| 443 | }, | 443 | //}, |
| 444 | .store_node => { | 444 | //.store_node => { |
| 445 | try sema.zirStoreNode(block, inst); | 445 | // try sema.zirStoreNode(block, inst); |
| 446 | i += 1; | 446 | // i += 1; |
| 447 | continue; | 447 | // continue; |
| 448 | }, | 448 | //}, |
| 449 | .store_to_block_ptr => { | 449 | //.store_to_block_ptr => { |
| 450 | try sema.zirStoreToBlockPtr(block, inst); | 450 | // try sema.zirStoreToBlockPtr(block, inst); |
| 451 | i += 1; | 451 | // i += 1; |
| 452 | continue; | 452 | // continue; |
| 453 | }, | 453 | //}, |
| 454 | .store_to_inferred_ptr => { | 454 | //.store_to_inferred_ptr => { |
| 455 | try sema.zirStoreToInferredPtr(block, inst); | 455 | // try sema.zirStoreToInferredPtr(block, inst); |
| 456 | i += 1; | 456 | // i += 1; |
| 457 | continue; | 457 | // continue; |
| 458 | }, | 458 | //}, |
| 459 | .resolve_inferred_alloc => { | 459 | //.resolve_inferred_alloc => { |
| 460 | try sema.zirResolveInferredAlloc(block, inst); | 460 | // try sema.zirResolveInferredAlloc(block, inst); |
| 461 | i += 1; | 461 | // i += 1; |
| 462 | continue; | 462 | // continue; |
| 463 | }, | 463 | //}, |
| 464 | .validate_struct_init_ptr => { | 464 | //.validate_struct_init_ptr => { |
| 465 | try sema.zirValidateStructInitPtr(block, inst); | 465 | // try sema.zirValidateStructInitPtr(block, inst); |
| 466 | i += 1; | 466 | // i += 1; |
| 467 | continue; | 467 | // continue; |
| 468 | }, | 468 | //}, |
| 469 | .validate_array_init_ptr => { | 469 | //.validate_array_init_ptr => { |
| 470 | try sema.zirValidateArrayInitPtr(block, inst); | 470 | // try sema.zirValidateArrayInitPtr(block, inst); |
| 471 | i += 1; | 471 | // i += 1; |
| 472 | continue; | 472 | // continue; |
| 473 | }, | 473 | //}, |
| 474 | .@"export" => { | 474 | //.@"export" => { |
| 475 | try sema.zirExport(block, inst); | 475 | // try sema.zirExport(block, inst); |
| 476 | i += 1; | 476 | // i += 1; |
| 477 | continue; | 477 | // continue; |
| 478 | }, | 478 | //}, |
| 479 | .set_align_stack => { | 479 | //.set_align_stack => { |
| 480 | try sema.zirSetAlignStack(block, inst); | 480 | // try sema.zirSetAlignStack(block, inst); |
| 481 | i += 1; | 481 | // i += 1; |
| 482 | continue; | 482 | // continue; |
| 483 | }, | 483 | //}, |
| 484 | .set_cold => { | 484 | //.set_cold => { |
| 485 | try sema.zirSetCold(block, inst); | 485 | // try sema.zirSetCold(block, inst); |
| 486 | i += 1; | 486 | // i += 1; |
| 487 | continue; | 487 | // continue; |
| 488 | }, | 488 | //}, |
| 489 | .set_float_mode => { | 489 | //.set_float_mode => { |
| 490 | try sema.zirSetFloatMode(block, inst); | 490 | // try sema.zirSetFloatMode(block, inst); |
| 491 | i += 1; | 491 | // i += 1; |
| 492 | continue; | 492 | // continue; |
| 493 | }, | 493 | //}, |
| 494 | .set_runtime_safety => { | 494 | //.set_runtime_safety => { |
| 495 | try sema.zirSetRuntimeSafety(block, inst); | 495 | // try sema.zirSetRuntimeSafety(block, inst); |
| 496 | i += 1; | 496 | // i += 1; |
| 497 | continue; | 497 | // continue; |
| 498 | }, | 498 | //}, |
| 499 | 499 | ||
| 500 | // Special case instructions to handle comptime control flow. | 500 | // Special case instructions to handle comptime control flow. |
| 501 | .repeat_inline => { | 501 | .repeat_inline => { |
| ... | @@ -505,37 +505,38 @@ pub fn analyzeBody( | ... | @@ -505,37 +505,38 @@ pub fn analyzeBody( |
| 505 | i = 0; | 505 | i = 0; |
| 506 | continue; | 506 | continue; |
| 507 | }, | 507 | }, |
| 508 | .block_inline => blk: { | 508 | //.block_inline => blk: { |
| 509 | // Directly analyze the block body without introducing a new block. | 509 | // // Directly analyze the block body without introducing a new block. |
| 510 | const inst_data = datas[inst].pl_node; | 510 | // const inst_data = datas[inst].pl_node; |
| 511 | const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); | 511 | // const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); |
| 512 | const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; | 512 | // const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 513 | const break_inst = try sema.analyzeBody(block, inline_body); | 513 | // const break_inst = try sema.analyzeBody(block, inline_body); |
| 514 | const break_data = datas[break_inst].@"break"; | 514 | // const break_data = datas[break_inst].@"break"; |
| 515 | if (inst == break_data.block_inst) { | 515 | // if (inst == break_data.block_inst) { |
| 516 | break :blk try sema.resolveInst(break_data.operand); | 516 | // break :blk try sema.resolveInst(break_data.operand); |
| 517 | } else { | 517 | // } else { |
| 518 | return break_inst; | 518 | // return break_inst; |
| 519 | } | 519 | // } |
| 520 | }, | 520 | //}, |
| 521 | .condbr_inline => blk: { | 521 | //.condbr_inline => blk: { |
| 522 | const inst_data = datas[inst].pl_node; | 522 | // const inst_data = datas[inst].pl_node; |
| 523 | const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; | 523 | // const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; |
| 524 | const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); | 524 | // const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); |
| 525 | const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; | 525 | // const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len]; |
| 526 | const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | 526 | // const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; |
| 527 | const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition); | 527 | // const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition); |
| 528 | const inline_body = if (cond.val.toBool()) then_body else else_body; | 528 | // const inline_body = if (cond.val.toBool()) then_body else else_body; |
| 529 | const break_inst = try sema.analyzeBody(block, inline_body); | 529 | // const break_inst = try sema.analyzeBody(block, inline_body); |
| 530 | const break_data = datas[break_inst].@"break"; | 530 | // const break_data = datas[break_inst].@"break"; |
| 531 | if (inst == break_data.block_inst) { | 531 | // if (inst == break_data.block_inst) { |
| 532 | break :blk try sema.resolveInst(break_data.operand); | 532 | // break :blk try sema.resolveInst(break_data.operand); |
| 533 | } else { | 533 | // } else { |
| 534 | return break_inst; | 534 | // return break_inst; |
| 535 | } | 535 | // } |
| 536 | }, | 536 | //}, |
| 537 | else => @panic("TODO remove else prong"), | ||
| 537 | }; | 538 | }; |
| 538 | if (air_inst.ty.isNoReturn()) | 539 | if (sema.getAirType(air_inst).isNoReturn()) |
| 539 | return always_noreturn; | 540 | return always_noreturn; |
| 540 | try map.put(sema.gpa, inst, air_inst); | 541 | try map.put(sema.gpa, inst, air_inst); |
| 541 | i += 1; | 542 | i += 1; |
| ... | @@ -577,18 +578,13 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro | ... | @@ -577,18 +578,13 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro |
| 577 | } | 578 | } |
| 578 | } | 579 | } |
| 579 | 580 | ||
| 580 | /// TODO when we rework AIR memory layout, this function will no longer have a possible error. | 581 | pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) Air.Inst.Ref { |
| 581 | pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!Air.Inst.Index { | ||
| 582 | var i: usize = @enumToInt(zir_ref); | 582 | var i: usize = @enumToInt(zir_ref); |
| 583 | 583 | ||
| 584 | // First section of indexes correspond to a set number of constant values. | 584 | // First section of indexes correspond to a set number of constant values. |
| 585 | if (i < Zir.Inst.Ref.typed_value_map.len) { | 585 | if (i < Zir.Inst.Ref.typed_value_map.len) { |
| 586 | // TODO when we rework AIR memory layout, this function can be as simple as: | 586 | // We intentionally map the same indexes to the same values between ZIR and AIR. |
| 587 | // if (zir_ref < Zir.const_inst_list.len + sema.param_count) | 587 | return zir_ref; |
| 588 | // return zir_ref; | ||
| 589 | // Until then we allocate memory for a new, mutable `ir.Inst` to match what | ||
| 590 | // AIR expects. | ||
| 591 | return sema.mod.constInst(sema.arena, .unneeded, Zir.Inst.Ref.typed_value_map[i]); | ||
| 592 | } | 588 | } |
| 593 | i -= Zir.Inst.Ref.typed_value_map.len; | 589 | i -= Zir.Inst.Ref.typed_value_map.len; |
| 594 | 590 | ||
| ... | @@ -1256,7 +1252,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In | ... | @@ -1256,7 +1252,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In |
| 1256 | return sema.analyzeLoad(block, src, result_ptr, result_ptr.src); | 1252 | return sema.analyzeLoad(block, src, result_ptr, result_ptr.src); |
| 1257 | } | 1253 | } |
| 1258 | 1254 | ||
| 1259 | fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air.Inst.Index { | 1255 | fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air.Inst.Ref { |
| 1260 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | 1256 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 1261 | const arg_name = inst_data.get(sema.code); | 1257 | const arg_name = inst_data.get(sema.code); |
| 1262 | const arg_index = sema.next_arg_index; | 1258 | const arg_index = sema.next_arg_index; |
| ... | @@ -1271,7 +1267,7 @@ fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air | ... | @@ -1271,7 +1267,7 @@ fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air |
| 1271 | 1267 | ||
| 1272 | // Set the name of the Air.Arg instruction for use by codegen debug info. | 1268 | // Set the name of the Air.Arg instruction for use by codegen debug info. |
| 1273 | const air_arg = sema.param_inst_list[arg_index]; | 1269 | const air_arg = sema.param_inst_list[arg_index]; |
| 1274 | sema.air.instructions.items(.data)[air_arg].ty_str.str = inst_data.start; | 1270 | sema.air_instructions.items(.data)[air_arg].ty_str.str = inst_data.start; |
| 1275 | return air_arg; | 1271 | return air_arg; |
| 1276 | } | 1272 | } |
| 1277 | 1273 | ||
| ... | @@ -7942,6 +7938,18 @@ fn enumFieldSrcLoc( | ... | @@ -7942,6 +7938,18 @@ fn enumFieldSrcLoc( |
| 7942 | } else unreachable; | 7938 | } else unreachable; |
| 7943 | } | 7939 | } |
| 7944 | 7940 | ||
| 7941 | fn getAirType(sema: *Sema, air_ref: Air.Inst.Ref) Type { | ||
| 7942 | var i: usize = @enumToInt(air_ref); | ||
| 7943 | if (i < Air.Inst.Ref.typed_value_map.len) { | ||
| 7944 | return Air.Inst.Ref.typed_value_map[i].val.toType(undefined) catch unreachable; | ||
| 7945 | } | ||
| 7946 | i -= Air.Inst.Ref.typed_value_map.len; | ||
| 7947 | const air_tags = sema.air_instructions.items(.tag); | ||
| 7948 | const air_datas = sema.air_instructions.items(.data); | ||
| 7949 | assert(air_tags[i] == .const_ty); | ||
| 7950 | return air_datas[i].ty; | ||
| 7951 | } | ||
| 7952 | |||
| 7945 | pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { | 7953 | pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { |
| 7946 | switch (ty.tag()) { | 7954 | switch (ty.tag()) { |
| 7947 | .u8 => return .u8_type, | 7955 | .u8 => return .u8_type, |
src/codegen.zig+4-3| ... | @@ -282,7 +282,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -282,7 +282,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 282 | 282 | ||
| 283 | return struct { | 283 | return struct { |
| 284 | gpa: *Allocator, | 284 | gpa: *Allocator, |
| 285 | air: *const Air, | 285 | air: Air, |
| 286 | liveness: Liveness, | ||
| 286 | bin_file: *link.File, | 287 | bin_file: *link.File, |
| 287 | target: *const std.Target, | 288 | target: *const std.Target, |
| 288 | mod_fn: *const Module.Fn, | 289 | mod_fn: *const Module.Fn, |
| ... | @@ -468,8 +469,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -468,8 +469,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 468 | 469 | ||
| 469 | var function = Self{ | 470 | var function = Self{ |
| 470 | .gpa = bin_file.allocator, | 471 | .gpa = bin_file.allocator, |
| 471 | .air = &air, | 472 | .air = air, |
| 472 | .liveness = &liveness, | 473 | .liveness = liveness, |
| 473 | .target = &bin_file.options.target, | 474 | .target = &bin_file.options.target, |
| 474 | .bin_file = bin_file, | 475 | .bin_file = bin_file, |
| 475 | .mod_fn = module_fn, | 476 | .mod_fn = module_fn, |
src/codegen/c.zig+6-3| ... | @@ -6,7 +6,6 @@ const log = std.log.scoped(.c); | ... | @@ -6,7 +6,6 @@ const log = std.log.scoped(.c); |
| 6 | const link = @import("../link.zig"); | 6 | const link = @import("../link.zig"); |
| 7 | const Module = @import("../Module.zig"); | 7 | const Module = @import("../Module.zig"); |
| 8 | const Compilation = @import("../Compilation.zig"); | 8 | const Compilation = @import("../Compilation.zig"); |
| 9 | const Air = @import("../Air.zig"); | ||
| 10 | const Value = @import("../value.zig").Value; | 9 | const Value = @import("../value.zig").Value; |
| 11 | const Type = @import("../type.zig").Type; | 10 | const Type = @import("../type.zig").Type; |
| 12 | const TypedValue = @import("../TypedValue.zig"); | 11 | const TypedValue = @import("../TypedValue.zig"); |
| ... | @@ -14,6 +13,8 @@ const C = link.File.C; | ... | @@ -14,6 +13,8 @@ const C = link.File.C; |
| 14 | const Decl = Module.Decl; | 13 | const Decl = Module.Decl; |
| 15 | const trace = @import("../tracy.zig").trace; | 14 | const trace = @import("../tracy.zig").trace; |
| 16 | const LazySrcLoc = Module.LazySrcLoc; | 15 | const LazySrcLoc = Module.LazySrcLoc; |
| 16 | const Air = @import("../Air.zig"); | ||
| 17 | const Liveness = @import("../Liveness.zig"); | ||
| 17 | 18 | ||
| 18 | const Mutability = enum { Const, Mut }; | 19 | const Mutability = enum { Const, Mut }; |
| 19 | 20 | ||
| ... | @@ -37,7 +38,7 @@ const BlockData = struct { | ... | @@ -37,7 +38,7 @@ const BlockData = struct { |
| 37 | result: CValue, | 38 | result: CValue, |
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | pub const CValueMap = std.AutoHashMap(*Inst, CValue); | 41 | pub const CValueMap = std.AutoHashMap(Air.Inst.Index, CValue); |
| 41 | pub const TypedefMap = std.ArrayHashMap( | 42 | pub const TypedefMap = std.ArrayHashMap( |
| 42 | Type, | 43 | Type, |
| 43 | struct { name: []const u8, rendered: []u8 }, | 44 | struct { name: []const u8, rendered: []u8 }, |
| ... | @@ -93,6 +94,8 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) { | ... | @@ -93,6 +94,8 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) { |
| 93 | /// It is not available when generating .h file. | 94 | /// It is not available when generating .h file. |
| 94 | pub const Object = struct { | 95 | pub const Object = struct { |
| 95 | dg: DeclGen, | 96 | dg: DeclGen, |
| 97 | air: Air, | ||
| 98 | liveness: Liveness, | ||
| 96 | gpa: *mem.Allocator, | 99 | gpa: *mem.Allocator, |
| 97 | code: std.ArrayList(u8), | 100 | code: std.ArrayList(u8), |
| 98 | value_map: CValueMap, | 101 | value_map: CValueMap, |
| ... | @@ -102,7 +105,7 @@ pub const Object = struct { | ... | @@ -102,7 +105,7 @@ pub const Object = struct { |
| 102 | next_block_index: usize = 0, | 105 | next_block_index: usize = 0, |
| 103 | indent_writer: IndentWriter(std.ArrayList(u8).Writer), | 106 | indent_writer: IndentWriter(std.ArrayList(u8).Writer), |
| 104 | 107 | ||
| 105 | fn resolveInst(o: *Object, inst: *Inst) !CValue { | 108 | fn resolveInst(o: *Object, inst: Air.Inst.Index) !CValue { |
| 106 | if (inst.value()) |_| { | 109 | if (inst.value()) |_| { |
| 107 | return CValue{ .constant = inst }; | 110 | return CValue{ .constant = inst }; |
| 108 | } | 111 | } |
src/codegen/llvm.zig+3| ... | @@ -277,6 +277,9 @@ pub const Object = struct { | ... | @@ -277,6 +277,9 @@ pub const Object = struct { |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void { | 279 | pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void { |
| 280 | const tracy = trace(@src()); | ||
| 281 | defer tracy.end(); | ||
| 282 | |||
| 280 | var dg: DeclGen = .{ | 283 | var dg: DeclGen = .{ |
| 281 | .object = self, | 284 | .object = self, |
| 282 | .module = module, | 285 | .module = module, |
src/codegen/spirv.zig+2-1| ... | @@ -159,7 +159,8 @@ pub const DeclGen = struct { | ... | @@ -159,7 +159,8 @@ pub const DeclGen = struct { |
| 159 | /// The SPIR-V module code should be put in. | 159 | /// The SPIR-V module code should be put in. |
| 160 | spv: *SPIRVModule, | 160 | spv: *SPIRVModule, |
| 161 | 161 | ||
| 162 | air: *const Air, | 162 | air: Air, |
| 163 | liveness: Liveness, | ||
| 163 | 164 | ||
| 164 | /// An array of function argument result-ids. Each index corresponds with the | 165 | /// An array of function argument result-ids. Each index corresponds with the |
| 165 | /// function argument of the same index. | 166 | /// function argument of the same index. |
src/codegen/wasm.zig+46-42| ... | @@ -9,13 +9,14 @@ const wasm = std.wasm; | ... | @@ -9,13 +9,14 @@ const wasm = std.wasm; |
| 9 | 9 | ||
| 10 | const Module = @import("../Module.zig"); | 10 | const Module = @import("../Module.zig"); |
| 11 | const Decl = Module.Decl; | 11 | const Decl = Module.Decl; |
| 12 | const Air = @import("../Air.zig"); | ||
| 13 | const Type = @import("../type.zig").Type; | 12 | const Type = @import("../type.zig").Type; |
| 14 | const Value = @import("../value.zig").Value; | 13 | const Value = @import("../value.zig").Value; |
| 15 | const Compilation = @import("../Compilation.zig"); | 14 | const Compilation = @import("../Compilation.zig"); |
| 16 | const LazySrcLoc = Module.LazySrcLoc; | 15 | const LazySrcLoc = Module.LazySrcLoc; |
| 17 | const link = @import("../link.zig"); | 16 | const link = @import("../link.zig"); |
| 18 | const TypedValue = @import("../TypedValue.zig"); | 17 | const TypedValue = @import("../TypedValue.zig"); |
| 18 | const Air = @import("../Air.zig"); | ||
| 19 | const Liveness = @import("../Liveness.zig"); | ||
| 19 | 20 | ||
| 20 | /// Wasm Value, created when generating an instruction | 21 | /// Wasm Value, created when generating an instruction |
| 21 | const WValue = union(enum) { | 22 | const WValue = union(enum) { |
| ... | @@ -491,6 +492,8 @@ pub const Context = struct { | ... | @@ -491,6 +492,8 @@ pub const Context = struct { |
| 491 | /// Reference to the function declaration the code | 492 | /// Reference to the function declaration the code |
| 492 | /// section belongs to | 493 | /// section belongs to |
| 493 | decl: *Decl, | 494 | decl: *Decl, |
| 495 | air: Air, | ||
| 496 | liveness: Liveness, | ||
| 494 | gpa: *mem.Allocator, | 497 | gpa: *mem.Allocator, |
| 495 | /// Table to save `WValue`'s generated by an `Inst` | 498 | /// Table to save `WValue`'s generated by an `Inst` |
| 496 | values: ValueTable, | 499 | values: ValueTable, |
| ... | @@ -710,52 +713,53 @@ pub const Context = struct { | ... | @@ -710,52 +713,53 @@ pub const Context = struct { |
| 710 | } | 713 | } |
| 711 | } | 714 | } |
| 712 | 715 | ||
| 716 | pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result { | ||
| 717 | try self.genFunctype(); | ||
| 718 | |||
| 719 | // Write instructions | ||
| 720 | // TODO: check for and handle death of instructions | ||
| 721 | |||
| 722 | // Reserve space to write the size after generating the code as well as space for locals count | ||
| 723 | try self.code.resize(10); | ||
| 724 | |||
| 725 | try self.genBody(func.body); | ||
| 726 | |||
| 727 | // finally, write our local types at the 'offset' position | ||
| 728 | { | ||
| 729 | leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len)); | ||
| 730 | |||
| 731 | // offset into 'code' section where we will put our locals types | ||
| 732 | var local_offset: usize = 10; | ||
| 733 | |||
| 734 | // emit the actual locals amount | ||
| 735 | for (self.locals.items) |local| { | ||
| 736 | var buf: [6]u8 = undefined; | ||
| 737 | leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1)); | ||
| 738 | buf[5] = local; | ||
| 739 | try self.code.insertSlice(local_offset, &buf); | ||
| 740 | local_offset += 6; | ||
| 741 | } | ||
| 742 | } | ||
| 743 | |||
| 744 | const writer = self.code.writer(); | ||
| 745 | try writer.writeByte(wasm.opcode(.end)); | ||
| 746 | |||
| 747 | // Fill in the size of the generated code to the reserved space at the | ||
| 748 | // beginning of the buffer. | ||
| 749 | const size = self.code.items.len - 5 + self.decl.fn_link.wasm.idx_refs.items.len * 5; | ||
| 750 | leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size)); | ||
| 751 | |||
| 752 | // codegen data has been appended to `code` | ||
| 753 | return Result.appended; | ||
| 754 | } | ||
| 755 | |||
| 713 | /// Generates the wasm bytecode for the function declaration belonging to `Context` | 756 | /// Generates the wasm bytecode for the function declaration belonging to `Context` |
| 714 | pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result { | 757 | pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result { |
| 715 | switch (typed_value.ty.zigTypeTag()) { | 758 | switch (typed_value.ty.zigTypeTag()) { |
| 716 | .Fn => { | 759 | .Fn => { |
| 717 | try self.genFunctype(); | 760 | try self.genFunctype(); |
| 718 | 761 | if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions | |
| 719 | // Write instructions | 762 | return self.fail("TODO implement wasm codegen for function pointers", .{}); |
| 720 | // TODO: check for and handle death of instructions | ||
| 721 | const mod_fn = blk: { | ||
| 722 | if (typed_value.val.castTag(.function)) |func| break :blk func.data; | ||
| 723 | if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions | ||
| 724 | unreachable; | ||
| 725 | }; | ||
| 726 | |||
| 727 | // Reserve space to write the size after generating the code as well as space for locals count | ||
| 728 | try self.code.resize(10); | ||
| 729 | |||
| 730 | try self.genBody(mod_fn.body); | ||
| 731 | |||
| 732 | // finally, write our local types at the 'offset' position | ||
| 733 | { | ||
| 734 | leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len)); | ||
| 735 | |||
| 736 | // offset into 'code' section where we will put our locals types | ||
| 737 | var local_offset: usize = 10; | ||
| 738 | |||
| 739 | // emit the actual locals amount | ||
| 740 | for (self.locals.items) |local| { | ||
| 741 | var buf: [6]u8 = undefined; | ||
| 742 | leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1)); | ||
| 743 | buf[5] = local; | ||
| 744 | try self.code.insertSlice(local_offset, &buf); | ||
| 745 | local_offset += 6; | ||
| 746 | } | ||
| 747 | } | ||
| 748 | |||
| 749 | const writer = self.code.writer(); | ||
| 750 | try writer.writeByte(wasm.opcode(.end)); | ||
| 751 | |||
| 752 | // Fill in the size of the generated code to the reserved space at the | ||
| 753 | // beginning of the buffer. | ||
| 754 | const size = self.code.items.len - 5 + self.decl.fn_link.wasm.idx_refs.items.len * 5; | ||
| 755 | leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size)); | ||
| 756 | |||
| 757 | // codegen data has been appended to `code` | ||
| 758 | return Result.appended; | ||
| 759 | }, | 763 | }, |
| 760 | .Array => { | 764 | .Array => { |
| 761 | if (typed_value.val.castTag(.bytes)) |payload| { | 765 | if (typed_value.val.castTag(.bytes)) |payload| { |
src/link.zig+29-5| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | ||
| 2 | const mem = std.mem; | 3 | const mem = std.mem; |
| 3 | const Allocator = std.mem.Allocator; | 4 | const Allocator = std.mem.Allocator; |
| 4 | const fs = std.fs; | 5 | const fs = std.fs; |
| ... | @@ -14,8 +15,10 @@ const Cache = @import("Cache.zig"); | ... | @@ -14,8 +15,10 @@ const Cache = @import("Cache.zig"); |
| 14 | const build_options = @import("build_options"); | 15 | const build_options = @import("build_options"); |
| 15 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | 16 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 16 | const wasi_libc = @import("wasi_libc.zig"); | 17 | const wasi_libc = @import("wasi_libc.zig"); |
| 18 | const Air = @import("Air.zig"); | ||
| 19 | const Liveness = @import("Liveness.zig"); | ||
| 17 | 20 | ||
| 18 | pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; | 21 | pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version; |
| 19 | 22 | ||
| 20 | pub const Emit = struct { | 23 | pub const Emit = struct { |
| 21 | /// Where the output will go. | 24 | /// Where the output will go. |
| ... | @@ -313,13 +316,34 @@ pub const File = struct { | ... | @@ -313,13 +316,34 @@ pub const File = struct { |
| 313 | log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty }); | 316 | log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty }); |
| 314 | assert(decl.has_tv); | 317 | assert(decl.has_tv); |
| 315 | switch (base.tag) { | 318 | switch (base.tag) { |
| 316 | .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl), | 319 | // zig fmt: off |
| 317 | .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), | 320 | .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl), |
| 321 | .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), | ||
| 318 | .macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl), | 322 | .macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl), |
| 319 | .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl), | 323 | .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl), |
| 320 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl), | 324 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl), |
| 321 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl), | 325 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl), |
| 322 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDecl(module, decl), | 326 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDecl(module, decl), |
| 327 | // zig fmt: on | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | /// May be called before or after updateDeclExports but must be called | ||
| 332 | /// after allocateDeclIndexes for any given Decl. | ||
| 333 | pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | ||
| 334 | log.debug("updateFunc {*} ({s}), type={}", .{ | ||
| 335 | func.owner_decl, func.owner_decl.name, func.owner_decl.ty, | ||
| 336 | }); | ||
| 337 | switch (base.tag) { | ||
| 338 | // zig fmt: off | ||
| 339 | .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func, air, liveness), | ||
| 340 | .elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func, air, liveness), | ||
| 341 | .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func, air, liveness), | ||
| 342 | .c => return @fieldParentPtr(C, "base", base).updateFunc(module, func, air, liveness), | ||
| 343 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func, air, liveness), | ||
| 344 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func, air, liveness), | ||
| 345 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func, air, liveness), | ||
| 346 | // zig fmt: on | ||
| 323 | } | 347 | } |
| 324 | } | 348 | } |
| 325 | 349 |
src/link/C.zig+22-6| ... | @@ -2,14 +2,17 @@ const std = @import("std"); | ... | @@ -2,14 +2,17 @@ const std = @import("std"); |
| 2 | const mem = std.mem; | 2 | const mem = std.mem; |
| 3 | const assert = std.debug.assert; | 3 | const assert = std.debug.assert; |
| 4 | const Allocator = std.mem.Allocator; | 4 | const Allocator = std.mem.Allocator; |
| 5 | const fs = std.fs; | ||
| 6 | |||
| 7 | const C = @This(); | ||
| 5 | const Module = @import("../Module.zig"); | 8 | const Module = @import("../Module.zig"); |
| 6 | const Compilation = @import("../Compilation.zig"); | 9 | const Compilation = @import("../Compilation.zig"); |
| 7 | const fs = std.fs; | ||
| 8 | const codegen = @import("../codegen/c.zig"); | 10 | const codegen = @import("../codegen/c.zig"); |
| 9 | const link = @import("../link.zig"); | 11 | const link = @import("../link.zig"); |
| 10 | const trace = @import("../tracy.zig").trace; | 12 | const trace = @import("../tracy.zig").trace; |
| 11 | const C = @This(); | ||
| 12 | const Type = @import("../type.zig").Type; | 13 | const Type = @import("../type.zig").Type; |
| 14 | const Air = @import("../Air.zig"); | ||
| 15 | const Liveness = @import("../Liveness.zig"); | ||
| 13 | 16 | ||
| 14 | pub const base_tag: link.File.Tag = .c; | 17 | pub const base_tag: link.File.Tag = .c; |
| 15 | pub const zig_h = @embedFile("C/zig.h"); | 18 | pub const zig_h = @embedFile("C/zig.h"); |
| ... | @@ -95,10 +98,7 @@ fn deinitDecl(gpa: *Allocator, decl: *Module.Decl) void { | ... | @@ -95,10 +98,7 @@ fn deinitDecl(gpa: *Allocator, decl: *Module.Decl) void { |
| 95 | decl.fn_link.c.typedefs.deinit(gpa); | 98 | decl.fn_link.c.typedefs.deinit(gpa); |
| 96 | } | 99 | } |
| 97 | 100 | ||
| 98 | pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { | 101 | pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air, liveness: Liveness) !void { |
| 99 | const tracy = trace(@src()); | ||
| 100 | defer tracy.end(); | ||
| 101 | |||
| 102 | // Keep track of all decls so we can iterate over them on flush(). | 102 | // Keep track of all decls so we can iterate over them on flush(). |
| 103 | _ = try self.decl_table.getOrPut(self.base.allocator, decl); | 103 | _ = try self.decl_table.getOrPut(self.base.allocator, decl); |
| 104 | 104 | ||
| ... | @@ -126,6 +126,8 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { | ... | @@ -126,6 +126,8 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { |
| 126 | .code = code.toManaged(module.gpa), | 126 | .code = code.toManaged(module.gpa), |
| 127 | .value_map = codegen.CValueMap.init(module.gpa), | 127 | .value_map = codegen.CValueMap.init(module.gpa), |
| 128 | .indent_writer = undefined, // set later so we can get a pointer to object.code | 128 | .indent_writer = undefined, // set later so we can get a pointer to object.code |
| 129 | .air = air, | ||
| 130 | .liveness = liveness, | ||
| 129 | }; | 131 | }; |
| 130 | object.indent_writer = .{ .underlying_writer = object.code.writer() }; | 132 | object.indent_writer = .{ .underlying_writer = object.code.writer() }; |
| 131 | defer { | 133 | defer { |
| ... | @@ -157,6 +159,20 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { | ... | @@ -157,6 +159,20 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { |
| 157 | code.shrinkAndFree(module.gpa, code.items.len); | 159 | code.shrinkAndFree(module.gpa, code.items.len); |
| 158 | } | 160 | } |
| 159 | 161 | ||
| 162 | pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | ||
| 163 | const tracy = trace(@src()); | ||
| 164 | defer tracy.end(); | ||
| 165 | |||
| 166 | return self.finishUpdateDecl(module, func.owner_decl, air, liveness); | ||
| 167 | } | ||
| 168 | |||
| 169 | pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void { | ||
| 170 | const tracy = trace(@src()); | ||
| 171 | defer tracy.end(); | ||
| 172 | |||
| 173 | return self.finishUpdateDecl(module, decl, undefined, undefined); | ||
| 174 | } | ||
| 175 | |||
| 160 | pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void { | 176 | pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void { |
| 161 | // The C backend does not have the ability to fix line numbers without re-generating | 177 | // The C backend does not have the ability to fix line numbers without re-generating |
| 162 | // the entire Decl. | 178 | // the entire Decl. |
src/link/Coff.zig+51-5| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const Coff = @This(); | 1 | const Coff = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const builtin = @import("builtin"); | ||
| 4 | const log = std.log.scoped(.link); | 5 | const log = std.log.scoped(.link); |
| 5 | const Allocator = std.mem.Allocator; | 6 | const Allocator = std.mem.Allocator; |
| 6 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| ... | @@ -17,6 +18,8 @@ const build_options = @import("build_options"); | ... | @@ -17,6 +18,8 @@ const build_options = @import("build_options"); |
| 17 | const Cache = @import("../Cache.zig"); | 18 | const Cache = @import("../Cache.zig"); |
| 18 | const mingw = @import("../mingw.zig"); | 19 | const mingw = @import("../mingw.zig"); |
| 19 | const llvm_backend = @import("../codegen/llvm.zig"); | 20 | const llvm_backend = @import("../codegen/llvm.zig"); |
| 21 | const Air = @import("../Air.zig"); | ||
| 22 | const Liveness = @import("../Liveness.zig"); | ||
| 20 | 23 | ||
| 21 | const allocation_padding = 4 / 3; | 24 | const allocation_padding = 4 / 3; |
| 22 | const minimum_text_block_size = 64 * allocation_padding; | 25 | const minimum_text_block_size = 64 * allocation_padding; |
| ... | @@ -653,19 +656,58 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void { | ... | @@ -653,19 +656,58 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void { |
| 653 | } | 656 | } |
| 654 | } | 657 | } |
| 655 | 658 | ||
| 656 | pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { | 659 | pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { |
| 657 | // TODO COFF/PE debug information | 660 | if (build_options.skip_non_native and builtin.object_format != .coff and builtin.object_format != .pe) { |
| 658 | // TODO Implement exports | 661 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 662 | } | ||
| 663 | if (build_options.have_llvm) { | ||
| 664 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness); | ||
| 665 | } | ||
| 659 | const tracy = trace(@src()); | 666 | const tracy = trace(@src()); |
| 660 | defer tracy.end(); | 667 | defer tracy.end(); |
| 661 | 668 | ||
| 662 | if (build_options.have_llvm) | 669 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 663 | if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl); | 670 | defer code_buffer.deinit(); |
| 671 | |||
| 672 | const res = try codegen.generateFunction( | ||
| 673 | &self.base, | ||
| 674 | decl.srcLoc(), | ||
| 675 | func, | ||
| 676 | air, | ||
| 677 | liveness, | ||
| 678 | &code_buffer, | ||
| 679 | .none, | ||
| 680 | ); | ||
| 681 | const code = switch (res) { | ||
| 682 | .externally_managed => |x| x, | ||
| 683 | .appended => code_buffer.items, | ||
| 684 | .fail => |em| { | ||
| 685 | decl.analysis = .codegen_failure; | ||
| 686 | try module.failed_decls.put(module.gpa, decl, em); | ||
| 687 | return; | ||
| 688 | }, | ||
| 689 | }; | ||
| 690 | |||
| 691 | return self.finishUpdateDecl(module, func.owner_decl, code); | ||
| 692 | } | ||
| 693 | |||
| 694 | pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { | ||
| 695 | if (build_options.skip_non_native and builtin.object_format != .coff and builtin.object_format != .pe) { | ||
| 696 | @panic("Attempted to compile for object format that was disabled by build configuration"); | ||
| 697 | } | ||
| 698 | if (build_options.have_llvm) { | ||
| 699 | if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl); | ||
| 700 | } | ||
| 701 | const tracy = trace(@src()); | ||
| 702 | defer tracy.end(); | ||
| 664 | 703 | ||
| 665 | if (decl.val.tag() == .extern_fn) { | 704 | if (decl.val.tag() == .extern_fn) { |
| 666 | return; // TODO Should we do more when front-end analyzed extern decl? | 705 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 667 | } | 706 | } |
| 668 | 707 | ||
| 708 | // TODO COFF/PE debug information | ||
| 709 | // TODO Implement exports | ||
| 710 | |||
| 669 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 711 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 670 | defer code_buffer.deinit(); | 712 | defer code_buffer.deinit(); |
| 671 | 713 | ||
| ... | @@ -683,6 +725,10 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { | ... | @@ -683,6 +725,10 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { |
| 683 | }, | 725 | }, |
| 684 | }; | 726 | }; |
| 685 | 727 | ||
| 728 | return self.finishUpdateDecl(module, func.owner_decl, code); | ||
| 729 | } | ||
| 730 | |||
| 731 | fn finishUpdateDecl(self: *Coff, decl: *Module.Decl, code: []const u8) !void { | ||
| 686 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); | 732 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); |
| 687 | const curr_size = decl.link.coff.size; | 733 | const curr_size = decl.link.coff.size; |
| 688 | if (curr_size != 0) { | 734 | if (curr_size != 0) { |
src/link/Elf.zig+307-251| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const Elf = @This(); | 1 | const Elf = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const builtin = @import("builtin"); | ||
| 4 | const mem = std.mem; | 5 | const mem = std.mem; |
| 5 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 6 | const Allocator = std.mem.Allocator; | 7 | const Allocator = std.mem.Allocator; |
| ... | @@ -10,7 +11,6 @@ const log = std.log.scoped(.link); | ... | @@ -10,7 +11,6 @@ const log = std.log.scoped(.link); |
| 10 | const DW = std.dwarf; | 11 | const DW = std.dwarf; |
| 11 | const leb128 = std.leb; | 12 | const leb128 = std.leb; |
| 12 | 13 | ||
| 13 | const Air = @import("../Air.zig"); | ||
| 14 | const Module = @import("../Module.zig"); | 14 | const Module = @import("../Module.zig"); |
| 15 | const Compilation = @import("../Compilation.zig"); | 15 | const Compilation = @import("../Compilation.zig"); |
| 16 | const codegen = @import("../codegen.zig"); | 16 | const codegen = @import("../codegen.zig"); |
| ... | @@ -26,6 +26,8 @@ const glibc = @import("../glibc.zig"); | ... | @@ -26,6 +26,8 @@ const glibc = @import("../glibc.zig"); |
| 26 | const musl = @import("../musl.zig"); | 26 | const musl = @import("../musl.zig"); |
| 27 | const Cache = @import("../Cache.zig"); | 27 | const Cache = @import("../Cache.zig"); |
| 28 | const llvm_backend = @import("../codegen/llvm.zig"); | 28 | const llvm_backend = @import("../codegen/llvm.zig"); |
| 29 | const Air = @import("../Air.zig"); | ||
| 30 | const Liveness = @import("../Liveness.zig"); | ||
| 29 | 31 | ||
| 30 | const default_entry_addr = 0x8000000; | 32 | const default_entry_addr = 0x8000000; |
| 31 | 33 | ||
| ... | @@ -2155,138 +2157,17 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { | ... | @@ -2155,138 +2157,17 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { |
| 2155 | } | 2157 | } |
| 2156 | } | 2158 | } |
| 2157 | 2159 | ||
| 2158 | pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | 2160 | fn deinitRelocs(gpa: *Allocator, table: *File.DbgInfoTypeRelocsTable) void { |
| 2159 | const tracy = trace(@src()); | 2161 | var it = table.valueIterator(); |
| 2160 | defer tracy.end(); | 2162 | while (it.next()) |value| { |
| 2161 | 2163 | value.relocs.deinit(gpa); | |
| 2162 | if (build_options.have_llvm) | ||
| 2163 | if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl); | ||
| 2164 | |||
| 2165 | if (decl.val.tag() == .extern_fn) { | ||
| 2166 | return; // TODO Should we do more when front-end analyzed extern decl? | ||
| 2167 | } | ||
| 2168 | if (decl.val.castTag(.variable)) |payload| { | ||
| 2169 | const variable = payload.data; | ||
| 2170 | if (variable.is_extern) { | ||
| 2171 | return; // TODO Should we do more when front-end analyzed extern decl? | ||
| 2172 | } | ||
| 2173 | } | ||
| 2174 | |||
| 2175 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 2176 | defer code_buffer.deinit(); | ||
| 2177 | |||
| 2178 | var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 2179 | defer dbg_line_buffer.deinit(); | ||
| 2180 | |||
| 2181 | var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 2182 | defer dbg_info_buffer.deinit(); | ||
| 2183 | |||
| 2184 | var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{}; | ||
| 2185 | defer { | ||
| 2186 | var it = dbg_info_type_relocs.valueIterator(); | ||
| 2187 | while (it.next()) |value| { | ||
| 2188 | value.relocs.deinit(self.base.allocator); | ||
| 2189 | } | ||
| 2190 | dbg_info_type_relocs.deinit(self.base.allocator); | ||
| 2191 | } | ||
| 2192 | |||
| 2193 | const is_fn: bool = switch (decl.ty.zigTypeTag()) { | ||
| 2194 | .Fn => true, | ||
| 2195 | else => false, | ||
| 2196 | }; | ||
| 2197 | if (is_fn) { | ||
| 2198 | // For functions we need to add a prologue to the debug line program. | ||
| 2199 | try dbg_line_buffer.ensureCapacity(26); | ||
| 2200 | |||
| 2201 | const func = decl.val.castTag(.function).?.data; | ||
| 2202 | const line_off = @intCast(u28, decl.src_line + func.lbrace_line); | ||
| 2203 | |||
| 2204 | const ptr_width_bytes = self.ptrWidthBytes(); | ||
| 2205 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ | ||
| 2206 | DW.LNS_extended_op, | ||
| 2207 | ptr_width_bytes + 1, | ||
| 2208 | DW.LNE_set_address, | ||
| 2209 | }); | ||
| 2210 | // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`. | ||
| 2211 | assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len); | ||
| 2212 | dbg_line_buffer.items.len += ptr_width_bytes; | ||
| 2213 | |||
| 2214 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line); | ||
| 2215 | // This is the "relocatable" relative line offset from the previous function's end curly | ||
| 2216 | // to this function's begin curly. | ||
| 2217 | assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len); | ||
| 2218 | // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. | ||
| 2219 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off); | ||
| 2220 | |||
| 2221 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file); | ||
| 2222 | assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); | ||
| 2223 | // Once we support more than one source file, this will have the ability to be more | ||
| 2224 | // than one possible value. | ||
| 2225 | const file_index = 1; | ||
| 2226 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index); | ||
| 2227 | |||
| 2228 | // Emit a line for the begin curly with prologue_end=false. The codegen will | ||
| 2229 | // do the work of setting prologue_end=true and epilogue_begin=true. | ||
| 2230 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy); | ||
| 2231 | |||
| 2232 | // .debug_info subprogram | ||
| 2233 | const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1]; | ||
| 2234 | try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len); | ||
| 2235 | |||
| 2236 | const fn_ret_type = decl.ty.fnReturnType(); | ||
| 2237 | const fn_ret_has_bits = fn_ret_type.hasCodeGenBits(); | ||
| 2238 | if (fn_ret_has_bits) { | ||
| 2239 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram); | ||
| 2240 | } else { | ||
| 2241 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid); | ||
| 2242 | } | ||
| 2243 | // These get overwritten after generating the machine code. These values are | ||
| 2244 | // "relocations" and have to be in this fixed place so that functions can be | ||
| 2245 | // moved in virtual address space. | ||
| 2246 | assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len); | ||
| 2247 | dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr | ||
| 2248 | assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); | ||
| 2249 | dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4 | ||
| 2250 | if (fn_ret_has_bits) { | ||
| 2251 | const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type); | ||
| 2252 | if (!gop.found_existing) { | ||
| 2253 | gop.value_ptr.* = .{ | ||
| 2254 | .off = undefined, | ||
| 2255 | .relocs = .{}, | ||
| 2256 | }; | ||
| 2257 | } | ||
| 2258 | try gop.value_ptr.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len)); | ||
| 2259 | dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4 | ||
| 2260 | } | ||
| 2261 | dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string | ||
| 2262 | } else { | ||
| 2263 | // TODO implement .debug_info for global variables | ||
| 2264 | } | 2164 | } |
| 2265 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 2165 | table.deinit(gpa); |
| 2266 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 2166 | } |
| 2267 | .ty = decl.ty, | ||
| 2268 | .val = decl_val, | ||
| 2269 | }, &code_buffer, .{ | ||
| 2270 | .dwarf = .{ | ||
| 2271 | .dbg_line = &dbg_line_buffer, | ||
| 2272 | .dbg_info = &dbg_info_buffer, | ||
| 2273 | .dbg_info_type_relocs = &dbg_info_type_relocs, | ||
| 2274 | }, | ||
| 2275 | }); | ||
| 2276 | const code = switch (res) { | ||
| 2277 | .externally_managed => |x| x, | ||
| 2278 | .appended => code_buffer.items, | ||
| 2279 | .fail => |em| { | ||
| 2280 | decl.analysis = .codegen_failure; | ||
| 2281 | try module.failed_decls.put(module.gpa, decl, em); | ||
| 2282 | return; | ||
| 2283 | }, | ||
| 2284 | }; | ||
| 2285 | 2167 | ||
| 2168 | fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym { | ||
| 2286 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); | 2169 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); |
| 2287 | 2170 | ||
| 2288 | const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT; | ||
| 2289 | |||
| 2290 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() | 2171 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() |
| 2291 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; | 2172 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; |
| 2292 | if (local_sym.st_size != 0) { | 2173 | if (local_sym.st_size != 0) { |
| ... | @@ -2338,128 +2219,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2338,128 +2219,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2338 | const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset; | 2219 | const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset; |
| 2339 | try self.base.file.?.pwriteAll(code, file_offset); | 2220 | try self.base.file.?.pwriteAll(code, file_offset); |
| 2340 | 2221 | ||
| 2341 | const target_endian = self.base.options.target.cpu.arch.endian(); | 2222 | return local_sym; |
| 2342 | 2223 | } | |
| 2343 | const text_block = &decl.link.elf; | ||
| 2344 | |||
| 2345 | // If the Decl is a function, we need to update the .debug_line program. | ||
| 2346 | if (is_fn) { | ||
| 2347 | // Perform the relocations based on vaddr. | ||
| 2348 | switch (self.ptr_width) { | ||
| 2349 | .p32 => { | ||
| 2350 | { | ||
| 2351 | const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4]; | ||
| 2352 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); | ||
| 2353 | } | ||
| 2354 | { | ||
| 2355 | const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4]; | ||
| 2356 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); | ||
| 2357 | } | ||
| 2358 | }, | ||
| 2359 | .p64 => { | ||
| 2360 | { | ||
| 2361 | const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8]; | ||
| 2362 | mem.writeInt(u64, ptr, local_sym.st_value, target_endian); | ||
| 2363 | } | ||
| 2364 | { | ||
| 2365 | const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8]; | ||
| 2366 | mem.writeInt(u64, ptr, local_sym.st_value, target_endian); | ||
| 2367 | } | ||
| 2368 | }, | ||
| 2369 | } | ||
| 2370 | { | ||
| 2371 | const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4]; | ||
| 2372 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian); | ||
| 2373 | } | ||
| 2374 | |||
| 2375 | try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence }); | ||
| 2376 | |||
| 2377 | // Now we have the full contents and may allocate a region to store it. | ||
| 2378 | |||
| 2379 | // This logic is nearly identical to the logic below in `updateDeclDebugInfoAllocation` for | ||
| 2380 | // `TextBlock` and the .debug_info. If you are editing this logic, you | ||
| 2381 | // probably need to edit that logic too. | ||
| 2382 | |||
| 2383 | const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; | ||
| 2384 | const src_fn = &decl.fn_link.elf; | ||
| 2385 | src_fn.len = @intCast(u32, dbg_line_buffer.items.len); | ||
| 2386 | if (self.dbg_line_fn_last) |last| not_first: { | ||
| 2387 | if (src_fn.next) |next| { | ||
| 2388 | // Update existing function - non-last item. | ||
| 2389 | if (src_fn.off + src_fn.len + min_nop_size > next.off) { | ||
| 2390 | // It grew too big, so we move it to a new location. | ||
| 2391 | if (src_fn.prev) |prev| { | ||
| 2392 | self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | ||
| 2393 | prev.next = src_fn.next; | ||
| 2394 | } | ||
| 2395 | assert(src_fn.prev != next); | ||
| 2396 | next.prev = src_fn.prev; | ||
| 2397 | src_fn.next = null; | ||
| 2398 | // Populate where it used to be with NOPs. | ||
| 2399 | const file_pos = debug_line_sect.sh_offset + src_fn.off; | ||
| 2400 | try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos); | ||
| 2401 | // TODO Look at the free list before appending at the end. | ||
| 2402 | src_fn.prev = last; | ||
| 2403 | last.next = src_fn; | ||
| 2404 | self.dbg_line_fn_last = src_fn; | ||
| 2405 | |||
| 2406 | src_fn.off = last.off + padToIdeal(last.len); | ||
| 2407 | } | ||
| 2408 | } else if (src_fn.prev == null) { | ||
| 2409 | if (src_fn == last) { | ||
| 2410 | // Special case: there is only 1 function and it is being updated. | ||
| 2411 | // In this case there is nothing to do. The function's length has | ||
| 2412 | // already been updated, and the logic below takes care of | ||
| 2413 | // resizing the .debug_line section. | ||
| 2414 | break :not_first; | ||
| 2415 | } | ||
| 2416 | // Append new function. | ||
| 2417 | // TODO Look at the free list before appending at the end. | ||
| 2418 | src_fn.prev = last; | ||
| 2419 | last.next = src_fn; | ||
| 2420 | self.dbg_line_fn_last = src_fn; | ||
| 2421 | |||
| 2422 | src_fn.off = last.off + padToIdeal(last.len); | ||
| 2423 | } | ||
| 2424 | } else { | ||
| 2425 | // This is the first function of the Line Number Program. | ||
| 2426 | self.dbg_line_fn_first = src_fn; | ||
| 2427 | self.dbg_line_fn_last = src_fn; | ||
| 2428 | |||
| 2429 | src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes()); | ||
| 2430 | } | ||
| 2431 | |||
| 2432 | const last_src_fn = self.dbg_line_fn_last.?; | ||
| 2433 | const needed_size = last_src_fn.off + last_src_fn.len; | ||
| 2434 | if (needed_size != debug_line_sect.sh_size) { | ||
| 2435 | if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) { | ||
| 2436 | const new_offset = self.findFreeSpace(needed_size, 1); | ||
| 2437 | const existing_size = last_src_fn.off; | ||
| 2438 | log.debug("moving .debug_line section: {d} bytes from 0x{x} to 0x{x}", .{ | ||
| 2439 | existing_size, | ||
| 2440 | debug_line_sect.sh_offset, | ||
| 2441 | new_offset, | ||
| 2442 | }); | ||
| 2443 | const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size); | ||
| 2444 | if (amt != existing_size) return error.InputOutput; | ||
| 2445 | debug_line_sect.sh_offset = new_offset; | ||
| 2446 | } | ||
| 2447 | debug_line_sect.sh_size = needed_size; | ||
| 2448 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | ||
| 2449 | self.debug_line_header_dirty = true; | ||
| 2450 | } | ||
| 2451 | const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0; | ||
| 2452 | const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0; | ||
| 2453 | |||
| 2454 | // We only have support for one compilation unit so far, so the offsets are directly | ||
| 2455 | // from the .debug_line section. | ||
| 2456 | const file_pos = debug_line_sect.sh_offset + src_fn.off; | ||
| 2457 | try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos); | ||
| 2458 | |||
| 2459 | // .debug_info - End the TAG_subprogram children. | ||
| 2460 | try dbg_info_buffer.append(0); | ||
| 2461 | } | ||
| 2462 | 2224 | ||
| 2225 | fn finishUpdateDecl( | ||
| 2226 | self: *Elf, | ||
| 2227 | module: *Module, | ||
| 2228 | decl: *Module.Decl, | ||
| 2229 | dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable, | ||
| 2230 | dbg_info_buffer: *std.ArrayList(u8), | ||
| 2231 | ) !void { | ||
| 2463 | // Now we emit the .debug_info types of the Decl. These will count towards the size of | 2232 | // Now we emit the .debug_info types of the Decl. These will count towards the size of |
| 2464 | // the buffer, so we have to do it before computing the offset, and we can't perform the actual | 2233 | // the buffer, so we have to do it before computing the offset, and we can't perform the actual |
| 2465 | // relocations yet. | 2234 | // relocations yet. |
| ... | @@ -2467,12 +2236,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2467,12 +2236,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2467 | var it = dbg_info_type_relocs.iterator(); | 2236 | var it = dbg_info_type_relocs.iterator(); |
| 2468 | while (it.next()) |entry| { | 2237 | while (it.next()) |entry| { |
| 2469 | entry.value_ptr.off = @intCast(u32, dbg_info_buffer.items.len); | 2238 | entry.value_ptr.off = @intCast(u32, dbg_info_buffer.items.len); |
| 2470 | try self.addDbgInfoType(entry.key_ptr.*, &dbg_info_buffer); | 2239 | try self.addDbgInfoType(entry.key_ptr.*, dbg_info_buffer); |
| 2471 | } | 2240 | } |
| 2472 | } | 2241 | } |
| 2473 | 2242 | ||
| 2243 | const text_block = &decl.link.elf; | ||
| 2474 | try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len)); | 2244 | try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len)); |
| 2475 | 2245 | ||
| 2246 | const target_endian = self.base.options.target.cpu.arch.endian(); | ||
| 2247 | |||
| 2476 | { | 2248 | { |
| 2477 | // Now that we have the offset assigned we can finally perform type relocations. | 2249 | // Now that we have the offset assigned we can finally perform type relocations. |
| 2478 | var it = dbg_info_type_relocs.valueIterator(); | 2250 | var it = dbg_info_type_relocs.valueIterator(); |
| ... | @@ -2495,6 +2267,290 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2495,6 +2267,290 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2495 | return self.updateDeclExports(module, decl, decl_exports); | 2267 | return self.updateDeclExports(module, decl, decl_exports); |
| 2496 | } | 2268 | } |
| 2497 | 2269 | ||
| 2270 | pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | ||
| 2271 | if (build_options.skip_non_native and builtin.object_format != .elf) { | ||
| 2272 | @panic("Attempted to compile for object format that was disabled by build configuration"); | ||
| 2273 | } | ||
| 2274 | if (build_options.have_llvm) { | ||
| 2275 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness); | ||
| 2276 | } | ||
| 2277 | |||
| 2278 | const tracy = trace(@src()); | ||
| 2279 | defer tracy.end(); | ||
| 2280 | |||
| 2281 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 2282 | defer code_buffer.deinit(); | ||
| 2283 | |||
| 2284 | var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 2285 | defer dbg_line_buffer.deinit(); | ||
| 2286 | |||
| 2287 | var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 2288 | defer dbg_info_buffer.deinit(); | ||
| 2289 | |||
| 2290 | var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{}; | ||
| 2291 | defer deinitRelocs(self.base.allocator, &dbg_info_type_relocs); | ||
| 2292 | |||
| 2293 | // For functions we need to add a prologue to the debug line program. | ||
| 2294 | try dbg_line_buffer.ensureCapacity(26); | ||
| 2295 | |||
| 2296 | const decl = func.owner_decl; | ||
| 2297 | const line_off = @intCast(u28, decl.src_line + func.lbrace_line); | ||
| 2298 | |||
| 2299 | const ptr_width_bytes = self.ptrWidthBytes(); | ||
| 2300 | dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ | ||
| 2301 | DW.LNS_extended_op, | ||
| 2302 | ptr_width_bytes + 1, | ||
| 2303 | DW.LNE_set_address, | ||
| 2304 | }); | ||
| 2305 | // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`. | ||
| 2306 | assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len); | ||
| 2307 | dbg_line_buffer.items.len += ptr_width_bytes; | ||
| 2308 | |||
| 2309 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line); | ||
| 2310 | // This is the "relocatable" relative line offset from the previous function's end curly | ||
| 2311 | // to this function's begin curly. | ||
| 2312 | assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len); | ||
| 2313 | // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. | ||
| 2314 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off); | ||
| 2315 | |||
| 2316 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file); | ||
| 2317 | assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); | ||
| 2318 | // Once we support more than one source file, this will have the ability to be more | ||
| 2319 | // than one possible value. | ||
| 2320 | const file_index = 1; | ||
| 2321 | leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index); | ||
| 2322 | |||
| 2323 | // Emit a line for the begin curly with prologue_end=false. The codegen will | ||
| 2324 | // do the work of setting prologue_end=true and epilogue_begin=true. | ||
| 2325 | dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy); | ||
| 2326 | |||
| 2327 | // .debug_info subprogram | ||
| 2328 | const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1]; | ||
| 2329 | try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len); | ||
| 2330 | |||
| 2331 | const fn_ret_type = decl.ty.fnReturnType(); | ||
| 2332 | const fn_ret_has_bits = fn_ret_type.hasCodeGenBits(); | ||
| 2333 | if (fn_ret_has_bits) { | ||
| 2334 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram); | ||
| 2335 | } else { | ||
| 2336 | dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid); | ||
| 2337 | } | ||
| 2338 | // These get overwritten after generating the machine code. These values are | ||
| 2339 | // "relocations" and have to be in this fixed place so that functions can be | ||
| 2340 | // moved in virtual address space. | ||
| 2341 | assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len); | ||
| 2342 | dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr | ||
| 2343 | assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); | ||
| 2344 | dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4 | ||
| 2345 | if (fn_ret_has_bits) { | ||
| 2346 | const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type); | ||
| 2347 | if (!gop.found_existing) { | ||
| 2348 | gop.value_ptr.* = .{ | ||
| 2349 | .off = undefined, | ||
| 2350 | .relocs = .{}, | ||
| 2351 | }; | ||
| 2352 | } | ||
| 2353 | try gop.value_ptr.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len)); | ||
| 2354 | dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4 | ||
| 2355 | } | ||
| 2356 | dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string | ||
| 2357 | |||
| 2358 | const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ | ||
| 2359 | .dwarf = .{ | ||
| 2360 | .dbg_line = &dbg_line_buffer, | ||
| 2361 | .dbg_info = &dbg_info_buffer, | ||
| 2362 | .dbg_info_type_relocs = &dbg_info_type_relocs, | ||
| 2363 | }, | ||
| 2364 | }); | ||
| 2365 | const code = switch (res) { | ||
| 2366 | .externally_managed => |x| x, | ||
| 2367 | .appended => code_buffer.items, | ||
| 2368 | .fail => |em| { | ||
| 2369 | decl.analysis = .codegen_failure; | ||
| 2370 | try module.failed_decls.put(module.gpa, decl, em); | ||
| 2371 | return; | ||
| 2372 | }, | ||
| 2373 | }; | ||
| 2374 | |||
| 2375 | const local_sym = try self.updateDeclCode(decl, code, elf.STT_FUNC); | ||
| 2376 | |||
| 2377 | const target_endian = self.base.options.target.cpu.arch.endian(); | ||
| 2378 | |||
| 2379 | // Since the Decl is a function, we need to update the .debug_line program. | ||
| 2380 | // Perform the relocations based on vaddr. | ||
| 2381 | switch (self.ptr_width) { | ||
| 2382 | .p32 => { | ||
| 2383 | { | ||
| 2384 | const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4]; | ||
| 2385 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); | ||
| 2386 | } | ||
| 2387 | { | ||
| 2388 | const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4]; | ||
| 2389 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian); | ||
| 2390 | } | ||
| 2391 | }, | ||
| 2392 | .p64 => { | ||
| 2393 | { | ||
| 2394 | const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8]; | ||
| 2395 | mem.writeInt(u64, ptr, local_sym.st_value, target_endian); | ||
| 2396 | } | ||
| 2397 | { | ||
| 2398 | const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8]; | ||
| 2399 | mem.writeInt(u64, ptr, local_sym.st_value, target_endian); | ||
| 2400 | } | ||
| 2401 | }, | ||
| 2402 | } | ||
| 2403 | { | ||
| 2404 | const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4]; | ||
| 2405 | mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian); | ||
| 2406 | } | ||
| 2407 | |||
| 2408 | try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence }); | ||
| 2409 | |||
| 2410 | // Now we have the full contents and may allocate a region to store it. | ||
| 2411 | |||
| 2412 | // This logic is nearly identical to the logic below in `updateDeclDebugInfoAllocation` for | ||
| 2413 | // `TextBlock` and the .debug_info. If you are editing this logic, you | ||
| 2414 | // probably need to edit that logic too. | ||
| 2415 | |||
| 2416 | const debug_line_sect = &self.sections.items[self.debug_line_section_index.?]; | ||
| 2417 | const src_fn = &decl.fn_link.elf; | ||
| 2418 | src_fn.len = @intCast(u32, dbg_line_buffer.items.len); | ||
| 2419 | if (self.dbg_line_fn_last) |last| not_first: { | ||
| 2420 | if (src_fn.next) |next| { | ||
| 2421 | // Update existing function - non-last item. | ||
| 2422 | if (src_fn.off + src_fn.len + min_nop_size > next.off) { | ||
| 2423 | // It grew too big, so we move it to a new location. | ||
| 2424 | if (src_fn.prev) |prev| { | ||
| 2425 | self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | ||
| 2426 | prev.next = src_fn.next; | ||
| 2427 | } | ||
| 2428 | assert(src_fn.prev != next); | ||
| 2429 | next.prev = src_fn.prev; | ||
| 2430 | src_fn.next = null; | ||
| 2431 | // Populate where it used to be with NOPs. | ||
| 2432 | const file_pos = debug_line_sect.sh_offset + src_fn.off; | ||
| 2433 | try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos); | ||
| 2434 | // TODO Look at the free list before appending at the end. | ||
| 2435 | src_fn.prev = last; | ||
| 2436 | last.next = src_fn; | ||
| 2437 | self.dbg_line_fn_last = src_fn; | ||
| 2438 | |||
| 2439 | src_fn.off = last.off + padToIdeal(last.len); | ||
| 2440 | } | ||
| 2441 | } else if (src_fn.prev == null) { | ||
| 2442 | if (src_fn == last) { | ||
| 2443 | // Special case: there is only 1 function and it is being updated. | ||
| 2444 | // In this case there is nothing to do. The function's length has | ||
| 2445 | // already been updated, and the logic below takes care of | ||
| 2446 | // resizing the .debug_line section. | ||
| 2447 | break :not_first; | ||
| 2448 | } | ||
| 2449 | // Append new function. | ||
| 2450 | // TODO Look at the free list before appending at the end. | ||
| 2451 | src_fn.prev = last; | ||
| 2452 | last.next = src_fn; | ||
| 2453 | self.dbg_line_fn_last = src_fn; | ||
| 2454 | |||
| 2455 | src_fn.off = last.off + padToIdeal(last.len); | ||
| 2456 | } | ||
| 2457 | } else { | ||
| 2458 | // This is the first function of the Line Number Program. | ||
| 2459 | self.dbg_line_fn_first = src_fn; | ||
| 2460 | self.dbg_line_fn_last = src_fn; | ||
| 2461 | |||
| 2462 | src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes()); | ||
| 2463 | } | ||
| 2464 | |||
| 2465 | const last_src_fn = self.dbg_line_fn_last.?; | ||
| 2466 | const needed_size = last_src_fn.off + last_src_fn.len; | ||
| 2467 | if (needed_size != debug_line_sect.sh_size) { | ||
| 2468 | if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) { | ||
| 2469 | const new_offset = self.findFreeSpace(needed_size, 1); | ||
| 2470 | const existing_size = last_src_fn.off; | ||
| 2471 | log.debug("moving .debug_line section: {d} bytes from 0x{x} to 0x{x}", .{ | ||
| 2472 | existing_size, | ||
| 2473 | debug_line_sect.sh_offset, | ||
| 2474 | new_offset, | ||
| 2475 | }); | ||
| 2476 | const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size); | ||
| 2477 | if (amt != existing_size) return error.InputOutput; | ||
| 2478 | debug_line_sect.sh_offset = new_offset; | ||
| 2479 | } | ||
| 2480 | debug_line_sect.sh_size = needed_size; | ||
| 2481 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty | ||
| 2482 | self.debug_line_header_dirty = true; | ||
| 2483 | } | ||
| 2484 | const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0; | ||
| 2485 | const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0; | ||
| 2486 | |||
| 2487 | // We only have support for one compilation unit so far, so the offsets are directly | ||
| 2488 | // from the .debug_line section. | ||
| 2489 | const file_pos = debug_line_sect.sh_offset + src_fn.off; | ||
| 2490 | try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos); | ||
| 2491 | |||
| 2492 | // .debug_info - End the TAG_subprogram children. | ||
| 2493 | try dbg_info_buffer.append(0); | ||
| 2494 | |||
| 2495 | return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer); | ||
| 2496 | } | ||
| 2497 | |||
| 2498 | pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ||
| 2499 | if (build_options.skip_non_native and builtin.object_format != .elf) { | ||
| 2500 | @panic("Attempted to compile for object format that was disabled by build configuration"); | ||
| 2501 | } | ||
| 2502 | if (build_options.have_llvm) { | ||
| 2503 | if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl); | ||
| 2504 | } | ||
| 2505 | |||
| 2506 | const tracy = trace(@src()); | ||
| 2507 | defer tracy.end(); | ||
| 2508 | |||
| 2509 | if (decl.val.tag() == .extern_fn) { | ||
| 2510 | return; // TODO Should we do more when front-end analyzed extern decl? | ||
| 2511 | } | ||
| 2512 | if (decl.val.castTag(.variable)) |payload| { | ||
| 2513 | const variable = payload.data; | ||
| 2514 | if (variable.is_extern) { | ||
| 2515 | return; // TODO Should we do more when front-end analyzed extern decl? | ||
| 2516 | } | ||
| 2517 | } | ||
| 2518 | |||
| 2519 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 2520 | defer code_buffer.deinit(); | ||
| 2521 | |||
| 2522 | var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 2523 | defer dbg_info_buffer.deinit(); | ||
| 2524 | |||
| 2525 | var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{}; | ||
| 2526 | defer deinitRelocs(self.base.allocator, &dbg_info_type_relocs); | ||
| 2527 | |||
| 2528 | // TODO implement .debug_info for global variables | ||
| 2529 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | ||
| 2530 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | ||
| 2531 | .ty = decl.ty, | ||
| 2532 | .val = decl_val, | ||
| 2533 | }, &code_buffer, .{ | ||
| 2534 | .dwarf = .{ | ||
| 2535 | .dbg_line = &dbg_line_buffer, | ||
| 2536 | .dbg_info = &dbg_info_buffer, | ||
| 2537 | .dbg_info_type_relocs = &dbg_info_type_relocs, | ||
| 2538 | }, | ||
| 2539 | }); | ||
| 2540 | const code = switch (res) { | ||
| 2541 | .externally_managed => |x| x, | ||
| 2542 | .appended => code_buffer.items, | ||
| 2543 | .fail => |em| { | ||
| 2544 | decl.analysis = .codegen_failure; | ||
| 2545 | try module.failed_decls.put(module.gpa, decl, em); | ||
| 2546 | return; | ||
| 2547 | }, | ||
| 2548 | }; | ||
| 2549 | |||
| 2550 | _ = try self.updateDeclCode(decl, code, elf.STT_OBJECT); | ||
| 2551 | return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer); | ||
| 2552 | } | ||
| 2553 | |||
| 2498 | /// Asserts the type has codegen bits. | 2554 | /// Asserts the type has codegen bits. |
| 2499 | fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void { | 2555 | fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void { |
| 2500 | switch (ty.zigTypeTag()) { | 2556 | switch (ty.zigTypeTag()) { |
src/link/MachO.zig+55| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const MachO = @This(); | 1 | const MachO = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const builtin = @import("builtin"); | ||
| 4 | const Allocator = std.mem.Allocator; | 5 | const Allocator = std.mem.Allocator; |
| 5 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 6 | const fmt = std.fmt; | 7 | const fmt = std.fmt; |
| ... | @@ -22,6 +23,8 @@ const link = @import("../link.zig"); | ... | @@ -22,6 +23,8 @@ const link = @import("../link.zig"); |
| 22 | const File = link.File; | 23 | const File = link.File; |
| 23 | const Cache = @import("../Cache.zig"); | 24 | const Cache = @import("../Cache.zig"); |
| 24 | const target_util = @import("../target.zig"); | 25 | const target_util = @import("../target.zig"); |
| 26 | const Air = @import("../Air.zig"); | ||
| 27 | const Liveness = @import("../Liveness.zig"); | ||
| 25 | 28 | ||
| 26 | const DebugSymbols = @import("MachO/DebugSymbols.zig"); | 29 | const DebugSymbols = @import("MachO/DebugSymbols.zig"); |
| 27 | const Trie = @import("MachO/Trie.zig"); | 30 | const Trie = @import("MachO/Trie.zig"); |
| ... | @@ -1132,7 +1135,55 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | ... | @@ -1132,7 +1135,55 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 1132 | }; | 1135 | }; |
| 1133 | } | 1136 | } |
| 1134 | 1137 | ||
| 1138 | pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | ||
| 1139 | if (build_options.skip_non_native and builtin.object_format != .macho) { | ||
| 1140 | @panic("Attempted to compile for object format that was disabled by build configuration"); | ||
| 1141 | } | ||
| 1142 | if (build_options.have_llvm) { | ||
| 1143 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness); | ||
| 1144 | } | ||
| 1145 | const tracy = trace(@src()); | ||
| 1146 | defer tracy.end(); | ||
| 1147 | |||
| 1148 | const decl = func.owner_decl; | ||
| 1149 | |||
| 1150 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 1151 | defer code_buffer.deinit(); | ||
| 1152 | |||
| 1153 | var debug_buffers = if (self.d_sym) |*ds| try ds.initDeclDebugBuffers(self.base.allocator, module, decl) else null; | ||
| 1154 | defer { | ||
| 1155 | if (debug_buffers) |*dbg| { | ||
| 1156 | dbg.dbg_line_buffer.deinit(); | ||
| 1157 | dbg.dbg_info_buffer.deinit(); | ||
| 1158 | var it = dbg.dbg_info_type_relocs.valueIterator(); | ||
| 1159 | while (it.next()) |value| { | ||
| 1160 | value.relocs.deinit(self.base.allocator); | ||
| 1161 | } | ||
| 1162 | dbg.dbg_info_type_relocs.deinit(self.base.allocator); | ||
| 1163 | } | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | const res = if (debug_buffers) |*dbg| | ||
| 1167 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ | ||
| 1168 | .dwarf = .{ | ||
| 1169 | .dbg_line = &dbg.dbg_line_buffer, | ||
| 1170 | .dbg_info = &dbg.dbg_info_buffer, | ||
| 1171 | .dbg_info_type_relocs = &dbg.dbg_info_type_relocs, | ||
| 1172 | }, | ||
| 1173 | }) | ||
| 1174 | else | ||
| 1175 | try codegen.generateSymbol(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); | ||
| 1176 | |||
| 1177 | return self.finishUpdateDecl(module, decl, res); | ||
| 1178 | } | ||
| 1179 | |||
| 1135 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | 1180 | pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1181 | if (build_options.skip_non_native and builtin.object_format != .macho) { | ||
| 1182 | @panic("Attempted to compile for object format that was disabled by build configuration"); | ||
| 1183 | } | ||
| 1184 | if (build_options.have_llvm) { | ||
| 1185 | if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl); | ||
| 1186 | } | ||
| 1136 | const tracy = trace(@src()); | 1187 | const tracy = trace(@src()); |
| 1137 | defer tracy.end(); | 1188 | defer tracy.end(); |
| 1138 | 1189 | ||
| ... | @@ -1173,6 +1224,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1173,6 +1224,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1173 | .val = decl.val, | 1224 | .val = decl.val, |
| 1174 | }, &code_buffer, .none); | 1225 | }, &code_buffer, .none); |
| 1175 | 1226 | ||
| 1227 | return self.finishUpdateDecl(module, decl, res); | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | fn finishUpdateDecl(self: *MachO, module: *Module, decl: *Module.Decl, res: codegen.Result) !void { | ||
| 1176 | const code = switch (res) { | 1231 | const code = switch (res) { |
| 1177 | .externally_managed => |x| x, | 1232 | .externally_managed => |x| x, |
| 1178 | .appended => code_buffer.items, | 1233 | .appended => code_buffer.items, |
src/link/Plan9.zig+24-5| ... | @@ -2,18 +2,21 @@ | ... | @@ -2,18 +2,21 @@ |
| 2 | //! would be to add incremental linking in a similar way as ELF does. | 2 | //! would be to add incremental linking in a similar way as ELF does. |
| 3 | 3 | ||
| 4 | const Plan9 = @This(); | 4 | const Plan9 = @This(); |
| 5 | |||
| 6 | const std = @import("std"); | ||
| 7 | const link = @import("../link.zig"); | 5 | const link = @import("../link.zig"); |
| 8 | const Module = @import("../Module.zig"); | 6 | const Module = @import("../Module.zig"); |
| 9 | const Compilation = @import("../Compilation.zig"); | 7 | const Compilation = @import("../Compilation.zig"); |
| 10 | const aout = @import("Plan9/aout.zig"); | 8 | const aout = @import("Plan9/aout.zig"); |
| 11 | const codegen = @import("../codegen.zig"); | 9 | const codegen = @import("../codegen.zig"); |
| 12 | const trace = @import("../tracy.zig").trace; | 10 | const trace = @import("../tracy.zig").trace; |
| 13 | const mem = std.mem; | ||
| 14 | const File = link.File; | 11 | const File = link.File; |
| 15 | const Allocator = std.mem.Allocator; | 12 | const build_options = @import("build_options"); |
| 13 | const Air = @import("../Air.zig"); | ||
| 14 | const Liveness = @import("../Liveness.zig"); | ||
| 16 | 15 | ||
| 16 | const std = @import("std"); | ||
| 17 | const builtin = @import("builtin"); | ||
| 18 | const mem = std.mem; | ||
| 19 | const Allocator = std.mem.Allocator; | ||
| 17 | const log = std.log.scoped(.link); | 20 | const log = std.log.scoped(.link); |
| 18 | const assert = std.debug.assert; | 21 | const assert = std.debug.assert; |
| 19 | 22 | ||
| ... | @@ -120,6 +123,19 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { | ... | @@ -120,6 +123,19 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 { |
| 120 | return self; | 123 | return self; |
| 121 | } | 124 | } |
| 122 | 125 | ||
| 126 | pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | ||
| 127 | if (build_options.skip_non_native and builtin.object_format != .plan9) { | ||
| 128 | @panic("Attempted to compile for object format that was disabled by build configuration"); | ||
| 129 | } | ||
| 130 | _ = module; | ||
| 131 | // Keep track of all decls so we can iterate over them on flush(). | ||
| 132 | _ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl); | ||
| 133 | |||
| 134 | _ = air; | ||
| 135 | _ = liveness; | ||
| 136 | @panic("TODO Plan9 needs to keep track of Air and Liveness so it can use them later"); | ||
| 137 | } | ||
| 138 | |||
| 123 | pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void { | 139 | pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void { |
| 124 | _ = module; | 140 | _ = module; |
| 125 | _ = try self.decl_table.getOrPut(self.base.allocator, decl); | 141 | _ = try self.decl_table.getOrPut(self.base.allocator, decl); |
| ... | @@ -138,6 +154,9 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void { | ... | @@ -138,6 +154,9 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void { |
| 138 | } | 154 | } |
| 139 | 155 | ||
| 140 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | 156 | pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 157 | if (build_options.skip_non_native and builtin.object_format != .plan9) { | ||
| 158 | @panic("Attempted to compile for object format that was disabled by build configuration"); | ||
| 159 | } | ||
| 141 | _ = comp; | 160 | _ = comp; |
| 142 | const tracy = trace(@src()); | 161 | const tracy = trace(@src()); |
| 143 | defer tracy.end(); | 162 | defer tracy.end(); |
| ... | @@ -199,7 +218,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { | ... | @@ -199,7 +218,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void { |
| 199 | } | 218 | } |
| 200 | } | 219 | } |
| 201 | if (std.mem.eql(u8, exp.options.name, "_start")) { | 220 | if (std.mem.eql(u8, exp.options.name, "_start")) { |
| 202 | std.debug.assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry | 221 | assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry |
| 203 | self.entry_decl = decl; | 222 | self.entry_decl = decl; |
| 204 | } | 223 | } |
| 205 | if (exp.link.plan9) |i| { | 224 | if (exp.link.plan9) |i| { |
src/link/SpirV.zig+21-3| ... | @@ -36,6 +36,8 @@ const ResultId = codegen.ResultId; | ... | @@ -36,6 +36,8 @@ const ResultId = codegen.ResultId; |
| 36 | const trace = @import("../tracy.zig").trace; | 36 | const trace = @import("../tracy.zig").trace; |
| 37 | const build_options = @import("build_options"); | 37 | const build_options = @import("build_options"); |
| 38 | const spec = @import("../codegen/spirv/spec.zig"); | 38 | const spec = @import("../codegen/spirv/spec.zig"); |
| 39 | const Air = @import("../Air.zig"); | ||
| 40 | const Liveness = @import("../Liveness.zig"); | ||
| 39 | 41 | ||
| 40 | // TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl? | 42 | // TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl? |
| 41 | pub const FnData = struct { | 43 | pub const FnData = struct { |
| ... | @@ -101,7 +103,23 @@ pub fn deinit(self: *SpirV) void { | ... | @@ -101,7 +103,23 @@ pub fn deinit(self: *SpirV) void { |
| 101 | self.decl_table.deinit(self.base.allocator); | 103 | self.decl_table.deinit(self.base.allocator); |
| 102 | } | 104 | } |
| 103 | 105 | ||
| 106 | pub fn updateFunc(self: *SpirV, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | ||
| 107 | if (build_options.skip_non_native) { | ||
| 108 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | ||
| 109 | } | ||
| 110 | _ = module; | ||
| 111 | // Keep track of all decls so we can iterate over them on flush(). | ||
| 112 | _ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl); | ||
| 113 | |||
| 114 | _ = air; | ||
| 115 | _ = liveness; | ||
| 116 | @panic("TODO SPIR-V needs to keep track of Air and Liveness so it can use them later"); | ||
| 117 | } | ||
| 118 | |||
| 104 | pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void { | 119 | pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void { |
| 120 | if (build_options.skip_non_native) { | ||
| 121 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | ||
| 122 | } | ||
| 105 | _ = module; | 123 | _ = module; |
| 106 | // Keep track of all decls so we can iterate over them on flush(). | 124 | // Keep track of all decls so we can iterate over them on flush(). |
| 107 | _ = try self.decl_table.getOrPut(self.base.allocator, decl); | 125 | _ = try self.decl_table.getOrPut(self.base.allocator, decl); |
| ... | @@ -132,13 +150,13 @@ pub fn flush(self: *SpirV, comp: *Compilation) !void { | ... | @@ -132,13 +150,13 @@ pub fn flush(self: *SpirV, comp: *Compilation) !void { |
| 132 | } | 150 | } |
| 133 | 151 | ||
| 134 | pub fn flushModule(self: *SpirV, comp: *Compilation) !void { | 152 | pub fn flushModule(self: *SpirV, comp: *Compilation) !void { |
| 135 | const tracy = trace(@src()); | ||
| 136 | defer tracy.end(); | ||
| 137 | |||
| 138 | if (build_options.skip_non_native) { | 153 | if (build_options.skip_non_native) { |
| 139 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | 154 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 140 | } | 155 | } |
| 141 | 156 | ||
| 157 | const tracy = trace(@src()); | ||
| 158 | defer tracy.end(); | ||
| 159 | |||
| 142 | const module = self.base.options.module.?; | 160 | const module = self.base.options.module.?; |
| 143 | const target = comp.getTarget(); | 161 | const target = comp.getTarget(); |
| 144 | 162 |
src/link/Wasm.zig+57-2| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const Wasm = @This(); | 1 | const Wasm = @This(); |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const builtin = @import("builtin"); | ||
| 4 | const mem = std.mem; | 5 | const mem = std.mem; |
| 5 | const Allocator = std.mem.Allocator; | 6 | const Allocator = std.mem.Allocator; |
| 6 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| ... | @@ -18,6 +19,8 @@ const build_options = @import("build_options"); | ... | @@ -18,6 +19,8 @@ const build_options = @import("build_options"); |
| 18 | const wasi_libc = @import("../wasi_libc.zig"); | 19 | const wasi_libc = @import("../wasi_libc.zig"); |
| 19 | const Cache = @import("../Cache.zig"); | 20 | const Cache = @import("../Cache.zig"); |
| 20 | const TypedValue = @import("../TypedValue.zig"); | 21 | const TypedValue = @import("../TypedValue.zig"); |
| 22 | const Air = @import("../Air.zig"); | ||
| 23 | const Liveness = @import("../Liveness.zig"); | ||
| 21 | 24 | ||
| 22 | pub const base_tag = link.File.Tag.wasm; | 25 | pub const base_tag = link.File.Tag.wasm; |
| 23 | 26 | ||
| ... | @@ -186,11 +189,60 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { | ... | @@ -186,11 +189,60 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { |
| 186 | } | 189 | } |
| 187 | } | 190 | } |
| 188 | 191 | ||
| 192 | pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | ||
| 193 | if (build_options.skip_non_native and builtin.object_format != .wasm) { | ||
| 194 | @panic("Attempted to compile for object format that was disabled by build configuration"); | ||
| 195 | } | ||
| 196 | if (build_options.have_llvm) { | ||
| 197 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness); | ||
| 198 | } | ||
| 199 | const decl = func.owner_decl; | ||
| 200 | assert(decl.link.wasm.init); // Must call allocateDeclIndexes() | ||
| 201 | |||
| 202 | const fn_data = &decl.fn_link.wasm; | ||
| 203 | fn_data.functype.items.len = 0; | ||
| 204 | fn_data.code.items.len = 0; | ||
| 205 | fn_data.idx_refs.items.len = 0; | ||
| 206 | |||
| 207 | var context = codegen.Context{ | ||
| 208 | .gpa = self.base.allocator, | ||
| 209 | .air = air, | ||
| 210 | .liveness = liveness, | ||
| 211 | .values = .{}, | ||
| 212 | .code = fn_data.code.toManaged(self.base.allocator), | ||
| 213 | .func_type_data = fn_data.functype.toManaged(self.base.allocator), | ||
| 214 | .decl = decl, | ||
| 215 | .err_msg = undefined, | ||
| 216 | .locals = .{}, | ||
| 217 | .target = self.base.options.target, | ||
| 218 | .global_error_set = self.base.options.module.?.global_error_set, | ||
| 219 | }; | ||
| 220 | defer context.deinit(); | ||
| 221 | |||
| 222 | // generate the 'code' section for the function declaration | ||
| 223 | const result = context.genFunc(func) catch |err| switch (err) { | ||
| 224 | error.CodegenFail => { | ||
| 225 | decl.analysis = .codegen_failure; | ||
| 226 | try module.failed_decls.put(module.gpa, decl, context.err_msg); | ||
| 227 | return; | ||
| 228 | }, | ||
| 229 | else => |e| return e, | ||
| 230 | }; | ||
| 231 | return self.finishUpdateDecl(decl, result); | ||
| 232 | } | ||
| 233 | |||
| 189 | // Generate code for the Decl, storing it in memory to be later written to | 234 | // Generate code for the Decl, storing it in memory to be later written to |
| 190 | // the file on flush(). | 235 | // the file on flush(). |
| 191 | pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { | 236 | pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { |
| 192 | std.debug.assert(decl.link.wasm.init); // Must call allocateDeclIndexes() | 237 | if (build_options.skip_non_native and builtin.object_format != .wasm) { |
| 238 | @panic("Attempted to compile for object format that was disabled by build configuration"); | ||
| 239 | } | ||
| 240 | if (build_options.have_llvm) { | ||
| 241 | if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl); | ||
| 242 | } | ||
| 243 | assert(decl.link.wasm.init); // Must call allocateDeclIndexes() | ||
| 193 | 244 | ||
| 245 | // TODO don't use this for non-functions | ||
| 194 | const fn_data = &decl.fn_link.wasm; | 246 | const fn_data = &decl.fn_link.wasm; |
| 195 | fn_data.functype.items.len = 0; | 247 | fn_data.functype.items.len = 0; |
| 196 | fn_data.code.items.len = 0; | 248 | fn_data.code.items.len = 0; |
| ... | @@ -218,7 +270,10 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { | ... | @@ -218,7 +270,10 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { |
| 218 | }, | 270 | }, |
| 219 | else => |e| return e, | 271 | else => |e| return e, |
| 220 | }; | 272 | }; |
| 273 | return self.finishUpdateDecl(decl, result); | ||
| 274 | } | ||
| 221 | 275 | ||
| 276 | fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result) !void { | ||
| 222 | const code: []const u8 = switch (result) { | 277 | const code: []const u8 = switch (result) { |
| 223 | .appended => @as([]const u8, context.code.items), | 278 | .appended => @as([]const u8, context.code.items), |
| 224 | .externally_managed => |payload| payload, | 279 | .externally_managed => |payload| payload, |
| ... | @@ -521,7 +576,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { | ... | @@ -521,7 +576,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 521 | var data_offset = offset_table_size; | 576 | var data_offset = offset_table_size; |
| 522 | while (cur) |cur_block| : (cur = cur_block.next) { | 577 | while (cur) |cur_block| : (cur = cur_block.next) { |
| 523 | if (cur_block.size == 0) continue; | 578 | if (cur_block.size == 0) continue; |
| 524 | std.debug.assert(cur_block.init); | 579 | assert(cur_block.init); |
| 525 | 580 | ||
| 526 | const offset = (cur_block.offset_index) * ptr_width; | 581 | const offset = (cur_block.offset_index) * ptr_width; |
| 527 | var buf: [4]u8 = undefined; | 582 | var buf: [4]u8 = undefined; |