| author | |
| committer | |
| log | 0bc96354909c0828b7fd36ce0be5705b7b21d63c |
| tree | 2b544abbf34776414478cb5fe4b8baad661337b3 |
| parent | 7ec2261dbf7a85f5c215f2dac22b80fca7de1e0f |
Adds 2 new AIR instructions:
* dbg_var_ptr
* dbg_var_val
Sema no longer emits dbg_stmt AIR instructions when strip=true.
LLVM backend: fixed lowerPtrToVoid when calling ptrAlignment on
the element type is problematic.
LLVM backend: fixed alloca instructions improperly getting debug
location annotated, causing chaotic debug info behavior.
zig_llvm.cpp: fixed incorrect bindings for a function that should use
unsigned integers for line and column.
A bunch of C test cases regressed because the new dbg_var AIR
instructions caused their operands to be alive, exposing latent bugs.
Mostly it's just a problem that the C backend lowers mutable
and const slices to the same C type, so we need to represent that in the
C backend instead of printing two duplicate typedefs.29 files changed, 338 insertions(+), 26 deletions(-)
src/Air.zig+22-2| ... | ... | @@ -327,6 +327,15 @@ pub const Inst = struct { |
| 327 | 327 | /// Result type is always void. |
| 328 | 328 | /// Uses the `dbg_stmt` field. |
| 329 | 329 | dbg_stmt, |
| 330 | /// Marks the beginning of a local variable. The operand is a pointer pointing | |
| 331 | /// to the storage for the variable. The local may be a const or a var. | |
| 332 | /// Result type is always void. | |
| 333 | /// Uses `pl_op`. The payload index is the variable name. It points to the extra | |
| 334 | /// array, reinterpreting the bytes there as a null-terminated string. | |
| 335 | dbg_var_ptr, | |
| 336 | /// Same as `dbg_var_ptr` except the local is a const, not a var, and the | |
| 337 | /// operand is the local's value. | |
| 338 | dbg_var_val, | |
| 330 | 339 | /// ?T => bool |
| 331 | 340 | /// Result type is always bool. |
| 332 | 341 | /// Uses the `un_op` field. |
| ... | ... | @@ -962,6 +971,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 962 | 971 | |
| 963 | 972 | .breakpoint, |
| 964 | 973 | .dbg_stmt, |
| 974 | .dbg_var_ptr, | |
| 975 | .dbg_var_val, | |
| 965 | 976 | .store, |
| 966 | 977 | .fence, |
| 967 | 978 | .atomic_store_unordered, |
| ... | ... | @@ -972,13 +983,13 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 972 | 983 | .memcpy, |
| 973 | 984 | .set_union_tag, |
| 974 | 985 | .prefetch, |
| 975 | => return Type.initTag(.void), | |
| 986 | => return Type.void, | |
| 976 | 987 | |
| 977 | 988 | .ptrtoint, |
| 978 | 989 | .slice_len, |
| 979 | 990 | .ret_addr, |
| 980 | 991 | .frame_addr, |
| 981 | => return Type.initTag(.usize), | |
| 992 | => return Type.usize, | |
| 982 | 993 | |
| 983 | 994 | .wasm_memory_grow => return Type.i32, |
| 984 | 995 | .wasm_memory_size => return Type.u32, |
| ... | ... | @@ -1089,3 +1100,12 @@ pub fn value(air: Air, inst: Air.Inst.Ref) ?Value { |
| 1089 | 1100 | else => return air.typeOfIndex(inst_index).onePossibleValue(), |
| 1090 | 1101 | } |
| 1091 | 1102 | } |
| 1103 | ||
| 1104 | pub fn nullTerminatedString(air: Air, index: usize) [:0]const u8 { | |
| 1105 | const bytes = std.mem.sliceAsBytes(air.extra[index..]); | |
| 1106 | var end: usize = 0; | |
| 1107 | while (bytes[end] != 0) { | |
| 1108 | end += 1; | |
| 1109 | } | |
| 1110 | return bytes[0..end :0]; | |
| 1111 | } |
src/AstGen.zig+40| ... | ... | @@ -2389,6 +2389,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2389 | 2389 | .breakpoint, |
| 2390 | 2390 | .fence, |
| 2391 | 2391 | .dbg_stmt, |
| 2392 | .dbg_var_ptr, | |
| 2393 | .dbg_var_val, | |
| 2392 | 2394 | .ensure_result_used, |
| 2393 | 2395 | .ensure_result_non_error, |
| 2394 | 2396 | .@"export", |
| ... | ... | @@ -2666,6 +2668,15 @@ fn varDecl( |
| 2666 | 2668 | } else .none; |
| 2667 | 2669 | const init_inst = try reachableExpr(gz, scope, result_loc, var_decl.ast.init_node, node); |
| 2668 | 2670 | |
| 2671 | if (!gz.force_comptime) { | |
| 2672 | _ = try gz.add(.{ .tag = .dbg_var_val, .data = .{ | |
| 2673 | .str_op = .{ | |
| 2674 | .str = ident_name, | |
| 2675 | .operand = init_inst, | |
| 2676 | }, | |
| 2677 | } }); | |
| 2678 | } | |
| 2679 | ||
| 2669 | 2680 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 2670 | 2681 | sub_scope.* = .{ |
| 2671 | 2682 | .parent = scope, |
| ... | ... | @@ -2751,6 +2762,15 @@ fn varDecl( |
| 2751 | 2762 | } |
| 2752 | 2763 | gz.instructions.items.len = dst; |
| 2753 | 2764 | |
| 2765 | if (!gz.force_comptime) { | |
| 2766 | _ = try gz.add(.{ .tag = .dbg_var_val, .data = .{ | |
| 2767 | .str_op = .{ | |
| 2768 | .str = ident_name, | |
| 2769 | .operand = init_inst, | |
| 2770 | }, | |
| 2771 | } }); | |
| 2772 | } | |
| 2773 | ||
| 2754 | 2774 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 2755 | 2775 | sub_scope.* = .{ |
| 2756 | 2776 | .parent = scope, |
| ... | ... | @@ -2785,6 +2805,16 @@ fn varDecl( |
| 2785 | 2805 | _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); |
| 2786 | 2806 | } |
| 2787 | 2807 | const const_ptr = try gz.addUnNode(.make_ptr_const, init_scope.rl_ptr, node); |
| 2808 | ||
| 2809 | if (!gz.force_comptime) { | |
| 2810 | _ = try gz.add(.{ .tag = .dbg_var_ptr, .data = .{ | |
| 2811 | .str_op = .{ | |
| 2812 | .str = ident_name, | |
| 2813 | .operand = const_ptr, | |
| 2814 | }, | |
| 2815 | } }); | |
| 2816 | } | |
| 2817 | ||
| 2788 | 2818 | const sub_scope = try block_arena.create(Scope.LocalPtr); |
| 2789 | 2819 | sub_scope.* = .{ |
| 2790 | 2820 | .parent = scope, |
| ... | ... | @@ -2848,6 +2878,16 @@ fn varDecl( |
| 2848 | 2878 | if (resolve_inferred_alloc != .none) { |
| 2849 | 2879 | _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); |
| 2850 | 2880 | } |
| 2881 | ||
| 2882 | if (!gz.force_comptime) { | |
| 2883 | _ = try gz.add(.{ .tag = .dbg_var_ptr, .data = .{ | |
| 2884 | .str_op = .{ | |
| 2885 | .str = ident_name, | |
| 2886 | .operand = var_data.alloc, | |
| 2887 | }, | |
| 2888 | } }); | |
| 2889 | } | |
| 2890 | ||
| 2851 | 2891 | const sub_scope = try block_arena.create(Scope.LocalPtr); |
| 2852 | 2892 | sub_scope.* = .{ |
| 2853 | 2893 | .parent = scope, |
src/Liveness.zig+7| ... | ... | @@ -394,6 +394,13 @@ fn analyzeInst( |
| 394 | 394 | return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); |
| 395 | 395 | }, |
| 396 | 396 | |
| 397 | .dbg_var_ptr, | |
| 398 | .dbg_var_val, | |
| 399 | => { | |
| 400 | const operand = inst_datas[inst].pl_op.operand; | |
| 401 | return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); | |
| 402 | }, | |
| 403 | ||
| 397 | 404 | .prefetch => { |
| 398 | 405 | const prefetch = inst_datas[inst].prefetch; |
| 399 | 406 | return trackOperands(a, new_set, inst, main_tomb, .{ prefetch.ptr, .none, .none }); |
src/Sema.zig+43-4| ... | ... | @@ -872,6 +872,16 @@ fn analyzeBodyInner( |
| 872 | 872 | i += 1; |
| 873 | 873 | continue; |
| 874 | 874 | }, |
| 875 | .dbg_var_ptr => { | |
| 876 | try sema.zirDbgVar(block, inst, .dbg_var_ptr); | |
| 877 | i += 1; | |
| 878 | continue; | |
| 879 | }, | |
| 880 | .dbg_var_val => { | |
| 881 | try sema.zirDbgVar(block, inst, .dbg_var_val); | |
| 882 | i += 1; | |
| 883 | continue; | |
| 884 | }, | |
| 875 | 885 | .ensure_err_payload_void => { |
| 876 | 886 | try sema.zirEnsureErrPayloadVoid(block, inst); |
| 877 | 887 | i += 1; |
| ... | ... | @@ -4158,14 +4168,11 @@ fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError |
| 4158 | 4168 | } |
| 4159 | 4169 | |
| 4160 | 4170 | fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 4161 | const tracy = trace(@src()); | |
| 4162 | defer tracy.end(); | |
| 4163 | ||
| 4164 | 4171 | // We do not set sema.src here because dbg_stmt instructions are only emitted for |
| 4165 | 4172 | // ZIR code that possibly will need to generate runtime code. So error messages |
| 4166 | 4173 | // and other source locations must not rely on sema.src being set from dbg_stmt |
| 4167 | 4174 | // instructions. |
| 4168 | if (block.is_comptime) return; | |
| 4175 | if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; | |
| 4169 | 4176 | |
| 4170 | 4177 | const inst_data = sema.code.instructions.items(.data)[inst].dbg_stmt; |
| 4171 | 4178 | _ = try block.addInst(.{ |
| ... | ... | @@ -4177,6 +4184,38 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi |
| 4177 | 4184 | }); |
| 4178 | 4185 | } |
| 4179 | 4186 | |
| 4187 | fn zirDbgVar( | |
| 4188 | sema: *Sema, | |
| 4189 | block: *Block, | |
| 4190 | inst: Zir.Inst.Index, | |
| 4191 | air_tag: Air.Inst.Tag, | |
| 4192 | ) CompileError!void { | |
| 4193 | if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; | |
| 4194 | ||
| 4195 | const str_op = sema.code.instructions.items(.data)[inst].str_op; | |
| 4196 | const operand = sema.resolveInst(str_op.operand); | |
| 4197 | const operand_ty = sema.typeOf(operand); | |
| 4198 | if (!(try sema.typeHasRuntimeBits(block, sema.src, operand_ty))) return; | |
| 4199 | const name = str_op.getStr(sema.code); | |
| 4200 | ||
| 4201 | // Add the name to the AIR. | |
| 4202 | const name_extra_index = @intCast(u32, sema.air_extra.items.len); | |
| 4203 | const elements_used = name.len / 4 + 1; | |
| 4204 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements_used); | |
| 4205 | const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); | |
| 4206 | mem.copy(u8, buffer, name); | |
| 4207 | buffer[name.len] = 0; | |
| 4208 | sema.air_extra.items.len += elements_used; | |
| 4209 | ||
| 4210 | _ = try block.addInst(.{ | |
| 4211 | .tag = air_tag, | |
| 4212 | .data = .{ .pl_op = .{ | |
| 4213 | .payload = name_extra_index, | |
| 4214 | .operand = operand, | |
| 4215 | } }, | |
| 4216 | }); | |
| 4217 | } | |
| 4218 | ||
| 4180 | 4219 | fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 4181 | 4220 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 4182 | 4221 | const src = inst_data.src(); |
src/Zir.zig+22| ... | ... | @@ -322,6 +322,14 @@ pub const Inst = struct { |
| 322 | 322 | /// Uses the `dbg_stmt` union field. The line and column are offset |
| 323 | 323 | /// from the parent declaration. |
| 324 | 324 | dbg_stmt, |
| 325 | /// Marks a variable declaration. Used for debug info. | |
| 326 | /// Uses the `str_op` union field. The string is the local variable name, | |
| 327 | /// and the operand is the pointer to the variable's location. The local | |
| 328 | /// may be a const or a var. | |
| 329 | dbg_var_ptr, | |
| 330 | /// Same as `dbg_var_ptr` but the local is always a const and the operand | |
| 331 | /// is the local's value. | |
| 332 | dbg_var_val, | |
| 325 | 333 | /// Uses a name to identify a Decl and takes a pointer to it. |
| 326 | 334 | /// Uses the `str_tok` union field. |
| 327 | 335 | decl_ref, |
| ... | ... | @@ -1032,6 +1040,8 @@ pub const Inst = struct { |
| 1032 | 1040 | .error_set_decl_anon, |
| 1033 | 1041 | .error_set_decl_func, |
| 1034 | 1042 | .dbg_stmt, |
| 1043 | .dbg_var_ptr, | |
| 1044 | .dbg_var_val, | |
| 1035 | 1045 | .decl_ref, |
| 1036 | 1046 | .decl_val, |
| 1037 | 1047 | .load, |
| ... | ... | @@ -1297,6 +1307,8 @@ pub const Inst = struct { |
| 1297 | 1307 | .error_set_decl_anon = .pl_node, |
| 1298 | 1308 | .error_set_decl_func = .pl_node, |
| 1299 | 1309 | .dbg_stmt = .dbg_stmt, |
| 1310 | .dbg_var_ptr = .str_op, | |
| 1311 | .dbg_var_val = .str_op, | |
| 1300 | 1312 | .decl_ref = .str_tok, |
| 1301 | 1313 | .decl_val = .str_tok, |
| 1302 | 1314 | .load = .un_node, |
| ... | ... | @@ -2232,6 +2244,15 @@ pub const Inst = struct { |
| 2232 | 2244 | return .{ .node_offset = self.src_node }; |
| 2233 | 2245 | } |
| 2234 | 2246 | }, |
| 2247 | str_op: struct { | |
| 2248 | /// Offset into `string_bytes`. Null-terminated. | |
| 2249 | str: u32, | |
| 2250 | operand: Ref, | |
| 2251 | ||
| 2252 | pub fn getStr(self: @This(), zir: Zir) [:0]const u8 { | |
| 2253 | return zir.nullTerminatedString(self.str); | |
| 2254 | } | |
| 2255 | }, | |
| 2235 | 2256 | |
| 2236 | 2257 | // Make sure we don't accidentally add a field to make this union |
| 2237 | 2258 | // bigger than expected. Note that in Debug builds, Zig is allowed |
| ... | ... | @@ -2268,6 +2289,7 @@ pub const Inst = struct { |
| 2268 | 2289 | switch_capture, |
| 2269 | 2290 | dbg_stmt, |
| 2270 | 2291 | inst_node, |
| 2292 | str_op, | |
| 2271 | 2293 | }; |
| 2272 | 2294 | }; |
| 2273 | 2295 |
src/arch/aarch64/CodeGen.zig+13| ... | ... | @@ -643,6 +643,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 643 | 643 | .prefetch => try self.airPrefetch(inst), |
| 644 | 644 | .mul_add => try self.airMulAdd(inst), |
| 645 | 645 | |
| 646 | .dbg_var_ptr, | |
| 647 | .dbg_var_val, | |
| 648 | => try self.airDbgVar(inst), | |
| 649 | ||
| 646 | 650 | .call => try self.airCall(inst, .auto), |
| 647 | 651 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 648 | 652 | .call_never_tail => try self.airCall(inst, .never_tail), |
| ... | ... | @@ -2650,6 +2654,15 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 2650 | 2654 | return self.finishAirBookkeeping(); |
| 2651 | 2655 | } |
| 2652 | 2656 | |
| 2657 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | |
| 2658 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | |
| 2659 | const name = self.air.nullTerminatedString(pl_op.payload); | |
| 2660 | const operand = pl_op.operand; | |
| 2661 | // TODO emit debug info for this variable | |
| 2662 | _ = name; | |
| 2663 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); | |
| 2664 | } | |
| 2665 | ||
| 2653 | 2666 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 2654 | 2667 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2655 | 2668 | const cond = try self.resolveInst(pl_op.operand); |
src/arch/arm/CodeGen.zig+13| ... | ... | @@ -642,6 +642,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 642 | 642 | .prefetch => try self.airPrefetch(inst), |
| 643 | 643 | .mul_add => try self.airMulAdd(inst), |
| 644 | 644 | |
| 645 | .dbg_var_ptr, | |
| 646 | .dbg_var_val, | |
| 647 | => try self.airDbgVar(inst), | |
| 648 | ||
| 645 | 649 | .call => try self.airCall(inst, .auto), |
| 646 | 650 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 647 | 651 | .call_never_tail => try self.airCall(inst, .never_tail), |
| ... | ... | @@ -2831,6 +2835,15 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 2831 | 2835 | return self.finishAirBookkeeping(); |
| 2832 | 2836 | } |
| 2833 | 2837 | |
| 2838 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | |
| 2839 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | |
| 2840 | const name = self.air.nullTerminatedString(pl_op.payload); | |
| 2841 | const operand = pl_op.operand; | |
| 2842 | // TODO emit debug info for this variable | |
| 2843 | _ = name; | |
| 2844 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); | |
| 2845 | } | |
| 2846 | ||
| 2834 | 2847 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 2835 | 2848 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2836 | 2849 | const cond = try self.resolveInst(pl_op.operand); |
src/arch/riscv64/CodeGen.zig+13| ... | ... | @@ -609,6 +609,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 609 | 609 | .prefetch => try self.airPrefetch(inst), |
| 610 | 610 | .mul_add => try self.airMulAdd(inst), |
| 611 | 611 | |
| 612 | .dbg_var_ptr, | |
| 613 | .dbg_var_val, | |
| 614 | => try self.airDbgVar(inst), | |
| 615 | ||
| 612 | 616 | .call => try self.airCall(inst, .auto), |
| 613 | 617 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 614 | 618 | .call_never_tail => try self.airCall(inst, .never_tail), |
| ... | ... | @@ -1636,6 +1640,15 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 1636 | 1640 | return self.finishAirBookkeeping(); |
| 1637 | 1641 | } |
| 1638 | 1642 | |
| 1643 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | |
| 1644 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | |
| 1645 | const name = self.air.nullTerminatedString(pl_op.payload); | |
| 1646 | const operand = pl_op.operand; | |
| 1647 | // TODO emit debug info for this variable | |
| 1648 | _ = name; | |
| 1649 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); | |
| 1650 | } | |
| 1651 | ||
| 1639 | 1652 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1640 | 1653 | _ = inst; |
| 1641 | 1654 |
src/arch/wasm/CodeGen.zig+6-1| ... | ... | @@ -1219,13 +1219,18 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1219 | 1219 | .br => self.airBr(inst), |
| 1220 | 1220 | .bool_to_int => self.airBoolToInt(inst), |
| 1221 | 1221 | .cond_br => self.airCondBr(inst), |
| 1222 | .dbg_stmt => WValue.none, | |
| 1223 | 1222 | .intcast => self.airIntcast(inst), |
| 1224 | 1223 | .fptrunc => self.airFptrunc(inst), |
| 1225 | 1224 | .fpext => self.airFpext(inst), |
| 1226 | 1225 | .float_to_int => self.airFloatToInt(inst), |
| 1227 | 1226 | .get_union_tag => self.airGetUnionTag(inst), |
| 1228 | 1227 | |
| 1228 | // TODO | |
| 1229 | .dbg_stmt, | |
| 1230 | .dbg_var_ptr, | |
| 1231 | .dbg_var_val, | |
| 1232 | => WValue.none, | |
| 1233 | ||
| 1229 | 1234 | .call => self.airCall(inst, .auto), |
| 1230 | 1235 | .call_always_tail => self.airCall(inst, .always_tail), |
| 1231 | 1236 | .call_never_tail => self.airCall(inst, .never_tail), |
src/arch/x86_64/CodeGen.zig+13| ... | ... | @@ -726,6 +726,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 726 | 726 | .prefetch => try self.airPrefetch(inst), |
| 727 | 727 | .mul_add => try self.airMulAdd(inst), |
| 728 | 728 | |
| 729 | .dbg_var_ptr, | |
| 730 | .dbg_var_val, | |
| 731 | => try self.airDbgVar(inst), | |
| 732 | ||
| 729 | 733 | .call => try self.airCall(inst, .auto), |
| 730 | 734 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 731 | 735 | .call_never_tail => try self.airCall(inst, .never_tail), |
| ... | ... | @@ -3666,6 +3670,15 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 3666 | 3670 | return self.finishAirBookkeeping(); |
| 3667 | 3671 | } |
| 3668 | 3672 | |
| 3673 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | |
| 3674 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | |
| 3675 | const name = self.air.nullTerminatedString(pl_op.payload); | |
| 3676 | const operand = pl_op.operand; | |
| 3677 | // TODO emit debug info for this variable | |
| 3678 | _ = name; | |
| 3679 | return self.finishAir(inst, .dead, .{ operand, .none, .none }); | |
| 3680 | } | |
| 3681 | ||
| 3669 | 3682 | fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { |
| 3670 | 3683 | const abi_size = ty.abiSize(self.target.*); |
| 3671 | 3684 | switch (mcv) { |
src/codegen/c.zig+14| ... | ... | @@ -1721,6 +1721,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1721 | 1721 | .union_init => try airUnionInit(f, inst), |
| 1722 | 1722 | .prefetch => try airPrefetch(f, inst), |
| 1723 | 1723 | |
| 1724 | .dbg_var_ptr, | |
| 1725 | .dbg_var_val, | |
| 1726 | => try airDbgVar(f, inst), | |
| 1727 | ||
| 1724 | 1728 | .call => try airCall(f, inst, .auto), |
| 1725 | 1729 | .call_always_tail => try airCall(f, inst, .always_tail), |
| 1726 | 1730 | .call_never_tail => try airCall(f, inst, .never_tail), |
| ... | ... | @@ -2651,6 +2655,16 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2651 | 2655 | return CValue.none; |
| 2652 | 2656 | } |
| 2653 | 2657 | |
| 2658 | fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { | |
| 2659 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | |
| 2660 | const name = f.air.nullTerminatedString(pl_op.payload); | |
| 2661 | const operand = try f.resolveInst(pl_op.operand); | |
| 2662 | _ = operand; | |
| 2663 | const writer = f.object.writer(); | |
| 2664 | try writer.print("/* var:{s} */\n", .{name}); | |
| 2665 | return CValue.none; | |
| 2666 | } | |
| 2667 | ||
| 2654 | 2668 | fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2655 | 2669 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 2656 | 2670 | const extra = f.air.extraData(Air.Block, ty_pl.payload); |
src/codegen/llvm.zig+66-9| ... | ... | @@ -613,6 +613,8 @@ pub const Object = struct { |
| 613 | 613 | .single_threaded = module.comp.bin_file.options.single_threaded, |
| 614 | 614 | .di_scope = di_scope, |
| 615 | 615 | .di_file = di_file, |
| 616 | .prev_dbg_line = 0, | |
| 617 | .prev_dbg_column = 0, | |
| 616 | 618 | }; |
| 617 | 619 | defer fg.deinit(); |
| 618 | 620 | |
| ... | ... | @@ -2885,8 +2887,7 @@ pub const DeclGen = struct { |
| 2885 | 2887 | } |
| 2886 | 2888 | |
| 2887 | 2889 | fn lowerPtrToVoid(dg: *DeclGen, ptr_ty: Type) !*const llvm.Value { |
| 2888 | const target = dg.module.getTarget(); | |
| 2889 | const alignment = ptr_ty.ptrAlignment(target); | |
| 2890 | const alignment = ptr_ty.ptrInfo().data.@"align"; | |
| 2890 | 2891 | // Even though we are pointing at something which has zero bits (e.g. `void`), |
| 2891 | 2892 | // Pointers are defined to have bits. So we must return something here. |
| 2892 | 2893 | // The value cannot be undefined, because we use the `nonnull` annotation |
| ... | ... | @@ -2902,6 +2903,7 @@ pub const DeclGen = struct { |
| 2902 | 2903 | // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR |
| 2903 | 2904 | // instruction is followed by a `wrap_optional`, it will return this value |
| 2904 | 2905 | // verbatim, and the result should test as non-null. |
| 2906 | const target = dg.module.getTarget(); | |
| 2905 | 2907 | const int = switch (target.cpu.arch.ptrBitWidth()) { |
| 2906 | 2908 | 32 => llvm_usize.constInt(0xaaaaaaaa, .False), |
| 2907 | 2909 | 64 => llvm_usize.constInt(0xaaaaaaaa_aaaaaaaa, .False), |
| ... | ... | @@ -3004,6 +3006,8 @@ pub const FuncGen = struct { |
| 3004 | 3006 | builder: *const llvm.Builder, |
| 3005 | 3007 | di_scope: ?*llvm.DIScope, |
| 3006 | 3008 | di_file: ?*llvm.DIFile, |
| 3009 | prev_dbg_line: c_uint, | |
| 3010 | prev_dbg_column: c_uint, | |
| 3007 | 3011 | |
| 3008 | 3012 | /// This stores the LLVM values used in a function, such that they can be referred to |
| 3009 | 3013 | /// in other instructions. This table is cleared before every function is generated. |
| ... | ... | @@ -3255,6 +3259,8 @@ pub const FuncGen = struct { |
| 3255 | 3259 | .const_ty => unreachable, |
| 3256 | 3260 | .unreach => self.airUnreach(inst), |
| 3257 | 3261 | .dbg_stmt => self.airDbgStmt(inst), |
| 3262 | .dbg_var_ptr => try self.airDbgVarPtr(inst), | |
| 3263 | .dbg_var_val => try self.airDbgVarVal(inst), | |
| 3258 | 3264 | // zig fmt: on |
| 3259 | 3265 | }; |
| 3260 | 3266 | if (opt_value) |val| { |
| ... | ... | @@ -3967,11 +3973,56 @@ pub const FuncGen = struct { |
| 3967 | 3973 | fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*const llvm.Value { |
| 3968 | 3974 | const di_scope = self.di_scope orelse return null; |
| 3969 | 3975 | const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt; |
| 3970 | self.builder.setCurrentDebugLocation( | |
| 3971 | @intCast(c_int, self.dg.decl.src_line + dbg_stmt.line + 1), | |
| 3972 | @intCast(c_int, dbg_stmt.column + 1), | |
| 3973 | di_scope, | |
| 3976 | self.prev_dbg_line = @intCast(c_uint, self.dg.decl.src_line + dbg_stmt.line + 1); | |
| 3977 | self.prev_dbg_column = @intCast(c_uint, dbg_stmt.column + 1); | |
| 3978 | self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope); | |
| 3979 | return null; | |
| 3980 | } | |
| 3981 | ||
| 3982 | fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 3983 | const dib = self.dg.object.di_builder orelse return null; | |
| 3984 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | |
| 3985 | const operand = try self.resolveInst(pl_op.operand); | |
| 3986 | const name = self.air.nullTerminatedString(pl_op.payload); | |
| 3987 | ||
| 3988 | const di_local_var = dib.createAutoVariable( | |
| 3989 | self.di_scope.?, | |
| 3990 | name.ptr, | |
| 3991 | self.di_file.?, | |
| 3992 | self.prev_dbg_line, | |
| 3993 | try self.dg.lowerDebugType(self.air.typeOf(pl_op.operand)), | |
| 3994 | true, // always preserve | |
| 3995 | 0, // flags | |
| 3996 | ); | |
| 3997 | const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?); | |
| 3998 | const insert_block = self.builder.getInsertBlock(); | |
| 3999 | _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block); | |
| 4000 | return null; | |
| 4001 | } | |
| 4002 | ||
| 4003 | fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 4004 | const dib = self.dg.object.di_builder orelse return null; | |
| 4005 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | |
| 4006 | const operand = try self.resolveInst(pl_op.operand); | |
| 4007 | const operand_ty = self.air.typeOf(pl_op.operand); | |
| 4008 | const name = self.air.nullTerminatedString(pl_op.payload); | |
| 4009 | ||
| 4010 | const di_local_var = dib.createAutoVariable( | |
| 4011 | self.di_scope.?, | |
| 4012 | name.ptr, | |
| 4013 | self.di_file.?, | |
| 4014 | self.prev_dbg_line, | |
| 4015 | try self.dg.lowerDebugType(operand_ty), | |
| 4016 | true, // always preserve | |
| 4017 | 0, // flags | |
| 3974 | 4018 | ); |
| 4019 | const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?); | |
| 4020 | const insert_block = self.builder.getInsertBlock(); | |
| 4021 | if (isByRef(operand_ty)) { | |
| 4022 | _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block); | |
| 4023 | } else { | |
| 4024 | _ = dib.insertDbgValueIntrinsicAtEnd(operand, di_local_var, debug_loc, insert_block); | |
| 4025 | } | |
| 3975 | 4026 | return null; |
| 3976 | 4027 | } |
| 3977 | 4028 | |
| ... | ... | @@ -5272,6 +5323,13 @@ pub const FuncGen = struct { |
| 5272 | 5323 | /// put the alloca instruction at the top of the function! |
| 5273 | 5324 | fn buildAlloca(self: *FuncGen, llvm_ty: *const llvm.Type) *const llvm.Value { |
| 5274 | 5325 | const prev_block = self.builder.getInsertBlock(); |
| 5326 | const prev_debug_location = self.builder.getCurrentDebugLocation2(); | |
| 5327 | defer { | |
| 5328 | self.builder.positionBuilderAtEnd(prev_block); | |
| 5329 | if (self.di_scope != null) { | |
| 5330 | self.builder.setCurrentDebugLocation2(prev_debug_location); | |
| 5331 | } | |
| 5332 | } | |
| 5275 | 5333 | |
| 5276 | 5334 | const entry_block = self.llvm_func.getFirstBasicBlock().?; |
| 5277 | 5335 | if (entry_block.getFirstInstruction()) |first_inst| { |
| ... | ... | @@ -5279,10 +5337,9 @@ pub const FuncGen = struct { |
| 5279 | 5337 | } else { |
| 5280 | 5338 | self.builder.positionBuilderAtEnd(entry_block); |
| 5281 | 5339 | } |
| 5340 | self.builder.clearCurrentDebugLocation(); | |
| 5282 | 5341 | |
| 5283 | const alloca = self.builder.buildAlloca(llvm_ty, ""); | |
| 5284 | self.builder.positionBuilderAtEnd(prev_block); | |
| 5285 | return alloca; | |
| 5342 | return self.builder.buildAlloca(llvm_ty, ""); | |
| 5286 | 5343 | } |
| 5287 | 5344 | |
| 5288 | 5345 | fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
src/codegen/llvm/bindings.zig+1-1| ... | ... | @@ -840,7 +840,7 @@ pub const Builder = opaque { |
| 840 | 840 | extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 841 | 841 | |
| 842 | 842 | pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation; |
| 843 | extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_int, column: c_int, scope: *DIScope) void; | |
| 843 | extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_uint, column: c_uint, scope: *DIScope) void; | |
| 844 | 844 | |
| 845 | 845 | pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation; |
| 846 | 846 | extern fn ZigLLVMClearCurrentDebugLocation(builder: *const Builder) void; |
src/print_air.zig+14-3| ... | ... | @@ -233,6 +233,10 @@ const Writer = struct { |
| 233 | 233 | .call_never_inline, |
| 234 | 234 | => try w.writeCall(s, inst), |
| 235 | 235 | |
| 236 | .dbg_var_ptr, | |
| 237 | .dbg_var_val, | |
| 238 | => try w.writeDbgVar(s, inst), | |
| 239 | ||
| 236 | 240 | .struct_field_ptr => try w.writeStructField(s, inst), |
| 237 | 241 | .struct_field_val => try w.writeStructField(s, inst), |
| 238 | 242 | .constant => try w.writeConstant(s, inst), |
| ... | ... | @@ -499,7 +503,7 @@ const Writer = struct { |
| 499 | 503 | extra_i += inputs.len; |
| 500 | 504 | |
| 501 | 505 | for (outputs) |output| { |
| 502 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(w.air.extra[extra_i..]), 0); | |
| 506 | const constraint = w.air.nullTerminatedString(extra_i); | |
| 503 | 507 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 504 | 508 | // for the string, we still use the next u32 for the null terminator. |
| 505 | 509 | extra_i += constraint.len / 4 + 1; |
| ... | ... | @@ -515,7 +519,7 @@ const Writer = struct { |
| 515 | 519 | } |
| 516 | 520 | |
| 517 | 521 | for (inputs) |input| { |
| 518 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(w.air.extra[extra_i..]), 0); | |
| 522 | const constraint = w.air.nullTerminatedString(extra_i); | |
| 519 | 523 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 520 | 524 | // for the string, we still use the next u32 for the null terminator. |
| 521 | 525 | extra_i += constraint.len / 4 + 1; |
| ... | ... | @@ -529,7 +533,7 @@ const Writer = struct { |
| 529 | 533 | { |
| 530 | 534 | var clobber_i: u32 = 0; |
| 531 | 535 | while (clobber_i < clobbers_len) : (clobber_i += 1) { |
| 532 | const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(w.air.extra[extra_i..]), 0); | |
| 536 | const clobber = w.air.nullTerminatedString(extra_i); | |
| 533 | 537 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 534 | 538 | // for the string, we still use the next u32 for the null terminator. |
| 535 | 539 | extra_i += clobber.len / 4 + 1; |
| ... | ... | @@ -548,6 +552,13 @@ const Writer = struct { |
| 548 | 552 | try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); |
| 549 | 553 | } |
| 550 | 554 | |
| 555 | fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | |
| 556 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; | |
| 557 | try w.writeOperand(s, inst, 0, pl_op.operand); | |
| 558 | const name = w.air.nullTerminatedString(pl_op.payload); | |
| 559 | try s.print(", {s}", .{name}); | |
| 560 | } | |
| 561 | ||
| 551 | 562 | fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 552 | 563 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 553 | 564 | const extra = w.air.extraData(Air.Call, pl_op.payload); |
src/print_zir.zig+11| ... | ... | @@ -424,6 +424,10 @@ const Writer = struct { |
| 424 | 424 | .param_anytype_comptime, |
| 425 | 425 | => try self.writeStrTok(stream, inst), |
| 426 | 426 | |
| 427 | .dbg_var_ptr, | |
| 428 | .dbg_var_val, | |
| 429 | => try self.writeStrOp(stream, inst), | |
| 430 | ||
| 427 | 431 | .param, .param_comptime => try self.writeParam(stream, inst), |
| 428 | 432 | |
| 429 | 433 | .func => try self.writeFunc(stream, inst, false), |
| ... | ... | @@ -1837,6 +1841,13 @@ const Writer = struct { |
| 1837 | 1841 | try self.writeSrc(stream, inst_data.src()); |
| 1838 | 1842 | } |
| 1839 | 1843 | |
| 1844 | fn writeStrOp(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | |
| 1845 | const inst_data = self.code.instructions.items(.data)[inst].str_op; | |
| 1846 | const str = inst_data.getStr(self.code); | |
| 1847 | try self.writeInstRef(stream, inst_data.operand); | |
| 1848 | try stream.print(", \"{}\")", .{std.zig.fmtEscapes(str)}); | |
| 1849 | } | |
| 1850 | ||
| 1840 | 1851 | fn writeFunc( |
| 1841 | 1852 | self: *Writer, |
| 1842 | 1853 | stream: anytype, |
src/zig_llvm.cpp+3-1| ... | ... | @@ -791,7 +791,9 @@ void ZigLLVMDisposeDIBuilder(ZigLLVMDIBuilder *dbuilder) { |
| 791 | 791 | delete di_builder; |
| 792 | 792 | } |
| 793 | 793 | |
| 794 | void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, ZigLLVMDIScope *scope) { | |
| 794 | void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, | |
| 795 | unsigned int line, unsigned int column, ZigLLVMDIScope *scope) | |
| 796 | { | |
| 795 | 797 | DIScope* di_scope = reinterpret_cast<DIScope*>(scope); |
| 796 | 798 | DebugLoc debug_loc = DILocation::get(di_scope->getContext(), line, column, di_scope, nullptr, false); |
| 797 | 799 | unwrap(builder)->SetCurrentDebugLocation(debug_loc); |
src/zig_llvm.h+2-2| ... | ... | @@ -228,8 +228,8 @@ ZIG_EXTERN_C void ZigLLVMSetModulePICLevel(LLVMModuleRef module); |
| 228 | 228 | ZIG_EXTERN_C void ZigLLVMSetModulePIELevel(LLVMModuleRef module); |
| 229 | 229 | ZIG_EXTERN_C void ZigLLVMSetModuleCodeModel(LLVMModuleRef module, LLVMCodeModel code_model); |
| 230 | 230 | |
| 231 | ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, | |
| 232 | struct ZigLLVMDIScope *scope); | |
| 231 | ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, | |
| 232 | unsigned int line, unsigned int column, struct ZigLLVMDIScope *scope); | |
| 233 | 233 | ZIG_EXTERN_C void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder); |
| 234 | 234 | |
| 235 | 235 | ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(struct ZigLLVMDILexicalBlock *lexical_block); |
test/behavior/align.zig+2| ... | ... | @@ -6,6 +6,8 @@ const native_arch = builtin.target.cpu.arch; |
| 6 | 6 | var foo: u8 align(4) = 100; |
| 7 | 7 | |
| 8 | 8 | test "global variable alignment" { |
| 9 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 10 | ||
| 9 | 11 | comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4); |
| 10 | 12 | comptime try expect(@TypeOf(&foo) == *align(4) u8); |
| 11 | 13 | { |
test/behavior/bugs/2692.zig+1| ... | ... | @@ -5,6 +5,7 @@ fn foo(a: []u8) void { |
| 5 | 5 | } |
| 6 | 6 | |
| 7 | 7 | test "address of 0 length array" { |
| 8 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 8 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 9 | 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 10 | 11 |
test/behavior/bugs/4954.zig+1| ... | ... | @@ -5,6 +5,7 @@ fn f(buf: []u8) void { |
| 5 | 5 | } |
| 6 | 6 | |
| 7 | 7 | test "crash" { |
| 8 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 8 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 9 | 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 10 | 11 |
test/behavior/bugs/5398.zig+2| ... | ... | @@ -19,10 +19,12 @@ pub const Renderable = struct { |
| 19 | 19 | var renderable: Renderable = undefined; |
| 20 | 20 | |
| 21 | 21 | test "assignment of field with padding" { |
| 22 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 22 | 23 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 23 | 24 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 24 | 25 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 25 | 26 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 27 | ||
| 26 | 28 | renderable = Renderable{ |
| 27 | 29 | .mesh = Mesh{ .id = 0 }, |
| 28 | 30 | .material = Material{ |
test/behavior/eval.zig+4| ... | ... | @@ -416,6 +416,8 @@ fn copyWithPartialInline(s: []u32, b: []u8) void { |
| 416 | 416 | } |
| 417 | 417 | |
| 418 | 418 | test "binary math operator in partially inlined function" { |
| 419 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 420 | ||
| 419 | 421 | var s: [4]u32 = undefined; |
| 420 | 422 | var b: [16]u8 = undefined; |
| 421 | 423 | |
| ... | ... | @@ -545,6 +547,8 @@ var simple_struct = SimpleStruct{ .field = 1234 }; |
| 545 | 547 | const bound_fn = simple_struct.method; |
| 546 | 548 | |
| 547 | 549 | test "ptr to local array argument at comptime" { |
| 550 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 551 | ||
| 548 | 552 | comptime { |
| 549 | 553 | var bytes: [10]u8 = undefined; |
| 550 | 554 | modifySomeBytes(bytes[0..]); |
test/behavior/floatop.zig+16-3| ... | ... | @@ -302,7 +302,11 @@ fn testExp2() !void { |
| 302 | 302 | } |
| 303 | 303 | |
| 304 | 304 | test "@log" { |
| 305 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 305 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 306 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 307 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 308 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 309 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 306 | 310 | |
| 307 | 311 | comptime try testLog(); |
| 308 | 312 | try testLog(); |
| ... | ... | @@ -326,13 +330,22 @@ fn testLog() !void { |
| 326 | 330 | try expect(math.approxEqAbs(ty, @log(@as(ty, 2)), 0.6931471805599, eps)); |
| 327 | 331 | try expect(math.approxEqAbs(ty, @log(@as(ty, 5)), 1.6094379124341, eps)); |
| 328 | 332 | } |
| 333 | } | |
| 334 | ||
| 335 | test "@log with vectors" { | |
| 336 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO | |
| 337 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 338 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 339 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 340 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 341 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 329 | 342 | |
| 330 | 343 | { |
| 331 | var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | |
| 344 | var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 }; | |
| 332 | 345 | var result = @log(v); |
| 333 | 346 | try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon)); |
| 334 | 347 | try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon)); |
| 335 | try expect(math.approxEqAbs(f32, @log(@as(f32, 0.3)), result[2], epsilon)); | |
| 348 | try expect(@log(@as(f32, 0.3)) == result[2]); | |
| 336 | 349 | try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon)); |
| 337 | 350 | } |
| 338 | 351 | } |
test/behavior/fn.zig+1| ... | ... | @@ -296,6 +296,7 @@ fn voidFun(a: i32, b: void, c: i32, d: void) !void { |
| 296 | 296 | } |
| 297 | 297 | |
| 298 | 298 | test "call function with empty string" { |
| 299 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 299 | 300 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 300 | 301 | |
| 301 | 302 | acceptsString(""); |
test/behavior/for.zig+1| ... | ... | @@ -151,6 +151,7 @@ test "2 break statements and an else" { |
| 151 | 151 | } |
| 152 | 152 | |
| 153 | 153 | test "for loop with pointer elem var" { |
| 154 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 154 | 155 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 155 | 156 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 156 | 157 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
test/behavior/generics.zig+1| ... | ... | @@ -170,6 +170,7 @@ fn getFirstByte(comptime T: type, mem: []const T) u8 { |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | 172 | test "generic fn keeps non-generic parameter types" { |
| 173 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 173 | 174 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 174 | 175 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 175 | 176 |
test/behavior/slice.zig+2| ... | ... | @@ -242,6 +242,7 @@ test "result location zero sized array inside struct field implicit cast to slic |
| 242 | 242 | } |
| 243 | 243 | |
| 244 | 244 | test "runtime safety lets us slice from len..len" { |
| 245 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 245 | 246 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 246 | 247 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 247 | 248 | |
| ... | ... | @@ -350,6 +351,7 @@ test "empty array to slice" { |
| 350 | 351 | } |
| 351 | 352 | |
| 352 | 353 | test "@ptrCast slice to pointer" { |
| 354 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 353 | 355 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 354 | 356 | |
| 355 | 357 | const S = struct { |
test/behavior/union.zig+1| ... | ... | @@ -453,6 +453,7 @@ pub const FooUnion = union(enum) { |
| 453 | 453 | var glbl_array: [2]FooUnion = undefined; |
| 454 | 454 | |
| 455 | 455 | test "initialize global array of union" { |
| 456 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 456 | 457 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 457 | 458 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 458 | 459 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
test/behavior/union_with_members.zig+3| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | |
| 1 | 2 | const std = @import("std"); |
| 2 | 3 | const expect = std.testing.expect; |
| 3 | 4 | const mem = std.mem; |
| ... | ... | @@ -16,6 +17,8 @@ const ET = union(enum) { |
| 16 | 17 | }; |
| 17 | 18 | |
| 18 | 19 | test "enum with members" { |
| 20 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 21 | ||
| 19 | 22 | const a = ET{ .SINT = -42 }; |
| 20 | 23 | const b = ET{ .UINT = 42 }; |
| 21 | 24 | var buf: [20]u8 = undefined; |