Commit b66cc5af41

Andrew Kelley <andrew@ziglang.org>
2024-09-26 03:23:45
reimplement integer overflow safety panic function calls
in the llvm backend.
1 parent f2c8940
Changed files (4)
src/codegen/llvm.zig
@@ -5677,46 +5677,37 @@ pub const FuncGen = struct {
 
     const PanicCauseTag = @typeInfo(std.builtin.PanicCause).@"union".tag_type.?;
 
-    fn buildSimplePanic(fg: *FuncGen, panic_cause_tag: PanicCauseTag) !void {
-        // TODO update this before merging the branch
-        _ = panic_cause_tag;
-        //const o = fg.ng.object;
-        //const zcu = o.pt.zcu;
-        //const ip = &zcu.intern_pool;
-        //const msg_nav_index = zcu.panic_messages[@intFromEnum(panic_id)].unwrap().?;
-        //const msg_nav = ip.getNav(msg_nav_index);
-        //const msg_len = Type.fromInterned(msg_nav.typeOf(ip)).childType(zcu).arrayLen(zcu);
-        //const msg_ptr = try o.lowerValue(msg_nav.status.resolved.val);
-        //const null_opt_addr_global = try fg.resolveNullOptUsize();
-        //const target = zcu.getTarget();
-        //const llvm_usize = try o.lowerType(Type.usize);
-        //// example:
-        //// call fastcc void @test2.panic(
-        ////   ptr @builtin.panic_messages.integer_overflow__anon_987, ; msg.ptr
-        ////   i64 16,                                                 ; msg.len
-        ////   ptr null,                                               ; stack trace
-        ////   ptr @2,                                                 ; addr (null ?usize)
-        //// )
-        //const panic_func = zcu.funcInfo(zcu.panic_func_index);
-        //const panic_nav = ip.getNav(panic_func.owner_nav);
-        //const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?;
-        //const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav);
-        //_ = try fg.wip.callIntrinsicAssumeCold();
-        //_ = try fg.wip.call(
-        //    .normal,
-        //    toLlvmCallConv(fn_info.cc, target),
-        //    .none,
-        //    panic_global.typeOf(&o.builder),
-        //    panic_global.toValue(&o.builder),
-        //    &.{
-        //        msg_ptr.toValue(),
-        //        try o.builder.intValue(llvm_usize, msg_len),
-        //        try o.builder.nullValue(.ptr),
-        //        null_opt_addr_global.toValue(),
-        //    },
-        //    "",
-        //);
-        _ = try fg.wip.callIntrinsic(.normal, .none, .trap, &.{}, &.{}, "");
+    fn buildSimplePanic(fg: *FuncGen, panic_cause: InternPool.Index) !void {
+        const o = fg.ng.object;
+        const zcu = o.pt.zcu;
+        const ip = &zcu.intern_pool;
+        const cause_ptr = try o.lowerValue(panic_cause);
+        const null_opt_addr_global = try fg.resolveNullOptUsize();
+        const target = zcu.getTarget();
+        // example:
+        // call fastcc void @test2.panic(
+        //   ptr @foo, ; panic_cause
+        //   ptr null, ; stack trace
+        //   ptr @2,   ; addr (null ?usize)
+        // )
+        const panic_func = zcu.funcInfo(zcu.panic_func_index);
+        const panic_nav = ip.getNav(panic_func.owner_nav);
+        const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?;
+        const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav);
+        _ = try fg.wip.callIntrinsicAssumeCold();
+        _ = try fg.wip.call(
+            .normal,
+            toLlvmCallConv(fn_info.cc, target),
+            .none,
+            panic_global.typeOf(&o.builder),
+            panic_global.toValue(&o.builder),
+            &.{
+                cause_ptr.toValue(),
+                try o.builder.nullValue(.ptr),
+                null_opt_addr_global.toValue(),
+            },
+            "",
+        );
         _ = try fg.wip.@"unreachable"();
     }
 
@@ -8340,7 +8331,7 @@ pub const FuncGen = struct {
         _ = try fg.wip.brCond(overflow_bit, fail_block, ok_block, .none);
 
         fg.wip.cursor = .{ .block = fail_block };
-        try fg.buildSimplePanic(.integer_overflow);
+        try fg.buildSimplePanic(zcu.panic_cause_integer_overflow);
 
         fg.wip.cursor = .{ .block = ok_block };
         return fg.wip.extractValue(results, &.{0}, "");
src/Zcu/PerThread.zig
@@ -3656,6 +3656,25 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
     namespace.generation = zcu.generation;
 }
 
+pub fn refValue(pt: Zcu.PerThread, val: InternPool.Index) Zcu.SemaError!InternPool.Index {
+    const ptr_ty = (try pt.ptrTypeSema(.{
+        .child = pt.zcu.intern_pool.typeOf(val),
+        .flags = .{
+            .alignment = .none,
+            .is_const = true,
+            .address_space = .generic,
+        },
+    })).toIntern();
+    return pt.intern(.{ .ptr = .{
+        .ty = ptr_ty,
+        .base_addr = .{ .uav = .{
+            .val = val,
+            .orig_ty = ptr_ty,
+        } },
+        .byte_offset = 0,
+    } });
+}
+
 const Air = @import("../Air.zig");
 const Allocator = std.mem.Allocator;
 const assert = std.debug.assert;
src/Sema.zig
@@ -5703,27 +5703,7 @@ fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError!Air.
 }
 
 fn uavRef(sema: *Sema, val: InternPool.Index) CompileError!Air.Inst.Ref {
-    return Air.internedToRef(try sema.refValue(val));
-}
-
-fn refValue(sema: *Sema, val: InternPool.Index) CompileError!InternPool.Index {
-    const pt = sema.pt;
-    const ptr_ty = (try pt.ptrTypeSema(.{
-        .child = pt.zcu.intern_pool.typeOf(val),
-        .flags = .{
-            .alignment = .none,
-            .is_const = true,
-            .address_space = .generic,
-        },
-    })).toIntern();
-    return pt.intern(.{ .ptr = .{
-        .ty = ptr_ty,
-        .base_addr = .{ .uav = .{
-            .val = val,
-            .orig_ty = ptr_ty,
-        } },
-        .byte_offset = 0,
-    } });
+    return Air.internedToRef(try sema.pt.refValue(val));
 }
 
 fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -17402,6 +17382,7 @@ fn analyzeArithmetic(
 
     if (block.wantSafety() and want_safety and scalar_tag == .int) {
         if (zcu.backendSupportsFeature(.safety_checked_instructions)) {
+            if (air_tag != air_tag_safe) try sema.preparePanicIntegerOverflow(block, src);
             return block.addBinOp(air_tag_safe, casted_lhs, casted_rhs);
         } else {
             const maybe_op_ov: ?Air.Inst.Tag = switch (air_tag) {
@@ -27706,6 +27687,24 @@ fn preparePanic(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
         const panic_cause_ty = try pt.getBuiltinType("PanicCause");
         try panic_cause_ty.resolveFields(pt);
         zcu.panic_cause_type = panic_cause_ty.toIntern();
+        zcu.panic_cause_tag_type = panic_cause_ty.unionTagType(zcu).?.toIntern();
+    }
+}
+
+fn preparePanicIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
+    const pt = sema.pt;
+    const zcu = pt.zcu;
+    try preparePanic(sema, block, src);
+    if (zcu.panic_cause_integer_overflow == .none) {
+        const union_val = try pt.unionValue(
+            Type.fromInterned(zcu.panic_cause_type),
+            try pt.enumValueFieldIndex(
+                Type.fromInterned(zcu.panic_cause_tag_type),
+                @intFromEnum(PanicCauseTag.integer_overflow),
+            ),
+            Value.void,
+        );
+        zcu.panic_cause_integer_overflow = try pt.refValue(union_val.toIntern());
     }
 }
 
@@ -32669,7 +32668,7 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {
     return Value.fromInterned(try pt.intern(.{ .opt = .{
         .ty = (try pt.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(),
         .val = if (opt_val) |val| (try pt.getCoerced(
-            Value.fromInterned(try sema.refValue(val.toIntern())),
+            Value.fromInterned(try pt.refValue(val.toIntern())),
             ptr_anyopaque_ty,
         )).toIntern() else .none,
     } }));
src/Zcu.zig
@@ -214,6 +214,8 @@ free_type_references: std.ArrayListUnmanaged(u32) = .empty,
 panic_func_index: InternPool.Index = .none,
 null_stack_trace: InternPool.Index = .none,
 panic_cause_type: InternPool.Index = .none,
+panic_cause_tag_type: InternPool.Index = .none,
+panic_cause_integer_overflow: InternPool.Index = .none,
 
 generation: u32 = 0,