Commit c0bbddb007

Andrew Kelley <andrew@ziglang.org>
2025-09-09 03:44:50
Sema: avoid ptr_add/ptr_sub instructions void elem type
1 parent aacff8c
Changed files (2)
src/Air.zig
@@ -166,19 +166,25 @@ pub const Inst = struct {
         mod,
         /// Same as `mod` with optimized float mode.
         mod_optimized,
-        /// Add an offset to a pointer, returning a new pointer.
-        /// The offset is in element type units, not bytes.
-        /// Wrapping is illegal behavior.
-        /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.
-        /// The pointer may be a slice.
-        /// Uses the `ty_pl` field. Payload is `Bin`.
+        /// Add an offset, in element type units, to a pointer, returning a new
+        /// pointer. Element type may not be zero bits.
+        ///
+        /// Wrapping is illegal behavior. If the newly computed address is
+        /// outside the provenance of the operand, the result is undefined.
+        ///
+        /// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer,
+        /// rhs is the offset. Result type is the same as lhs. The operand may
+        /// be a slice.
         ptr_add,
-        /// Subtract an offset from a pointer, returning a new pointer.
-        /// The offset is in element type units, not bytes.
-        /// Wrapping is illegal behavior.
-        /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs.
-        /// The pointer may be a slice.
-        /// Uses the `ty_pl` field. Payload is `Bin`.
+        /// Subtract an offset, in element type units, from a pointer,
+        /// returning a new pointer. Element type may not be zero bits.
+        ///
+        /// Wrapping is illegal behavior. If the newly computed address is
+        /// outside the provenance of the operand, the result is undefined.
+        ///
+        /// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer,
+        /// rhs is the offset. Result type is the same as lhs. The operand may
+        /// be a slice.
         ptr_sub,
         /// Given two operands which can be floats, integers, or vectors, returns the
         /// greater of the operands. For vectors it operates element-wise.
src/Sema.zig
@@ -16002,7 +16002,6 @@ fn splat(sema: *Sema, ty: Type, val: Value) !Value {
 fn analyzeArithmetic(
     sema: *Sema,
     block: *Block,
-    /// TODO performance investigation: make this comptime?
     zir_tag: Zir.Inst.Tag,
     lhs: Air.Inst.Ref,
     rhs: Air.Inst.Ref,
@@ -16201,6 +16200,11 @@ fn analyzePtrArithmetic(
     const ptr_info = ptr_ty.ptrInfo(zcu);
     assert(ptr_info.flags.size == .many or ptr_info.flags.size == .c);
 
+    if ((try sema.typeHasOnePossibleValue(.fromInterned(ptr_info.child))) != null) {
+        // Offset will be multiplied by zero, so result is the same as the base pointer.
+        return ptr;
+    }
+
     const new_ptr_ty = t: {
         // Calculate the new pointer alignment.
         // This code is duplicated in `Type.elemPtrType`.