This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-go.git


The following commit(s) were added to refs/heads/main by this push:
     new 7f19ac55 fix: Fix arm64 assembly stack frame manipulation (#984)
7f19ac55 is described below

commit 7f19ac5583c11002186caa0a4c518f2533320c72
Author: Nick Ripley <[email protected]>
AuthorDate: Thu Jul 23 16:09:08 2026 -0400

    fix: Fix arm64 assembly stack frame manipulation (#984)
    
    ### Rationale for this change
    
    The arm64 NEON assembly code in this library incorrectly manipulates the
    stack pointer. In the mechanically-translated portion of the code, there
    are instructions to set up and restore a call frame for the function,
    e.g.
    
            WORD $0xa9bf7bfd // stp    x29, x30, [sp, #-16]!
    
    But the assembler doesn't decode WORD directives and thus doesn't see
    the stack pointer manipulation. As a result, the spdelta table entries
    for these functions are incorrect. This table is used by the Go runtime
    for stack unwinding, to find the next frame based on the program counter
    and current stack pointer. In typical cases this means that the CPU
    profiler will just stop unwinding when it hits this function, and in
    some cases we can get non-truncated but incorrect tracebacks.
    
    See #983
    
    ### What changes are included in this PR?
    
    Fix this by removing the unnecssary frame setup for functions which
    don't otherwise use the stack, and by changing functions which do need a
    stack frame to include their frame size in the function declaration,
    which the assembler takes into account.
    
    Note that this PR removes the `SUB/ADD $16, RSP` instructions added in
    #170. Those were added because the functions were overwriting values
    saved on the stack, but after this PR most of the modified functions
    don't save anything on the stack, and the one that does properly
    declares its frame size and makes the fix unnecessary. This does mean
    that the modified functions with no frames don't set up a frame pointer,
    but in practice that's probably fine. If we really want frame pointers
    for all these functions, we can give them a small non-zero frame size
    and the assembler will add the appropriate frame pointer setup/tearndown
    code.
    
    ### Are these changes tested?
    
    Yes, by the existing unit tests, and manually by running the CPU
    profiler as described in #983
    
    ### Are there any user-facing changes?
    
    No
---
 .../internal/kernels/cast_numeric_neon_arm64.s     |  9 ---
 arrow/math/int64_neon_arm64.s                      | 14 +---
 arrow/math/uint64_neon_arm64.s                     | 14 +---
 arrow/memory/memory_neon_arm64.s                   |  9 ---
 arrow/memory/memory_neon_arm64_test.go             | 94 ++++++++++++++++++++++
 internal/utils/min_max_neon_arm64.s                | 48 -----------
 parquet/internal/bmi/bitmap_neon_arm64.s           |  9 ---
 parquet/internal/utils/bit_packing_neon_arm64.s    | 40 ++++-----
 parquet/internal/utils/unpack_bool_neon_arm64.s    | 10 ---
 9 files changed, 113 insertions(+), 134 deletions(-)

diff --git a/arrow/compute/internal/kernels/cast_numeric_neon_arm64.s 
b/arrow/compute/internal/kernels/cast_numeric_neon_arm64.s
index 3d56efc5..d6cd2070 100644
--- a/arrow/compute/internal/kernels/cast_numeric_neon_arm64.s
+++ b/arrow/compute/internal/kernels/cast_numeric_neon_arm64.s
@@ -10,13 +10,7 @@ TEXT ·_cast_type_numeric_neon(SB), $0-40
     MOVD len+32(FP), R4
 
 
-    // The Go ABI saves the frame pointer register one word below the 
-    // caller's frame. Make room so we don't overwrite it. Needs to stay 
-    // 16-byte aligned 
-    SUB $16, RSP
-    WORD $0xa9bf7bfd // stp    x29, x30, [sp, #-16]!
     WORD $0x7100181f // cmp    w0, #6
-    WORD $0x910003fd // mov    x29, sp
     BGT LBB0_17
 
     WORD $0x71000c1f // cmp    w0, #3
@@ -4450,9 +4444,6 @@ LBB0_892:
     WORD $0xb800452b // str    w11, [x9], #4
     BNE LBB0_892
 LBB0_893:
-    WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-    // Put the stack pointer back where it was 
-    ADD $16, RSP
     RET
 LBB0_894:
     WORD $0x927b6909 // and x9, x8, #0xffffffe0
diff --git a/arrow/math/int64_neon_arm64.s b/arrow/math/int64_neon_arm64.s
index c0b639bd..6eafdd18 100644
--- a/arrow/math/int64_neon_arm64.s
+++ b/arrow/math/int64_neon_arm64.s
@@ -10,13 +10,7 @@ TEXT ·_sum_int64_neon(SB), $0-24
        MOVD    buf+0(FP), R0
        MOVD    len+8(FP), R1
        MOVD    res+16(FP), R2
-    
-       // The Go ABI saves the frame pointer register one word below the 
-       // caller's frame. Make room so we don't overwrite it. Needs to stay 
-       // 16-byte aligned 
-       SUB $16, RSP
-       WORD $0xa9bf7bfd // stp x29, x30, [sp, #-16]!
-       WORD $0x910003fd // mov x29, sp
+
        CBZ R1, LBB0_3
        WORD $0xf1000c3f // cmp x1, #3
        BHI LBB0_4
@@ -26,9 +20,6 @@ TEXT ·_sum_int64_neon(SB), $0-24
 LBB0_3:
        WORD $0xaa1f03e9 // mov     x9, xzr
        WORD $0xf9000049 // str     x9, [x2]
-       WORD $0xa8c17bfd // ldp     x29, x30, [sp], #16
-       // Put the stack pointer back where it was 
-       ADD $16, RSP
        RET
 LBB0_4:
        WORD $0x927ef428 // and     x8, x1, #0xfffffffffffffffc
@@ -59,8 +50,5 @@ LBB0_8:
        BNE LBB0_8
 LBB0_9:
        WORD $0xf9000049 // str     x9, [x2]
-       WORD $0xa8c17bfd // ldp     x29, x30, [sp], #16
-       // Put the stack pointer back where it was 
-       ADD $16, RSP
        RET
 
diff --git a/arrow/math/uint64_neon_arm64.s b/arrow/math/uint64_neon_arm64.s
index 0f8d66a5..4b869972 100644
--- a/arrow/math/uint64_neon_arm64.s
+++ b/arrow/math/uint64_neon_arm64.s
@@ -10,13 +10,7 @@ TEXT ·_sum_uint64_neon(SB), $0-24
        MOVD    buf+0(FP), R0
        MOVD    len+8(FP), R1
        MOVD    res+16(FP), R2
-    
-       // The Go ABI saves the frame pointer register one word below the 
-       // caller's frame. Make room so we don't overwrite it. Needs to stay 
-       // 16-byte aligned 
-       SUB $16, RSP
-       WORD $0xa9bf7bfd // stp x29, x30, [sp, #-16]!
-       WORD $0x910003fd // mov x29, sp
+
        CBZ R1, LBB0_3
        WORD $0xf1000c3f // cmp x1, #3
        BHI LBB0_4
@@ -26,9 +20,6 @@ TEXT ·_sum_uint64_neon(SB), $0-24
 LBB0_3:
        WORD $0xaa1f03e9 // mov     x9, xzr
        WORD $0xf9000049 // str     x9, [x2]
-       WORD $0xa8c17bfd // ldp     x29, x30, [sp], #16
-       // Put the stack pointer back where it was 
-       ADD $16, RSP
        RET
 LBB0_4:
        WORD $0x927ef428 // and     x8, x1, #0xfffffffffffffffc
@@ -59,8 +50,5 @@ LBB0_8:
        BNE LBB0_8
 LBB0_9:
        WORD $0xf9000049 // str     x9, [x2]
-       WORD $0xa8c17bfd // ldp     x29, x30, [sp], #16
-       // Put the stack pointer back where it was 
-       ADD $16, RSP
        RET
 
diff --git a/arrow/memory/memory_neon_arm64.s b/arrow/memory/memory_neon_arm64.s
index 18b0af5c..19dd7db3 100644
--- a/arrow/memory/memory_neon_arm64.s
+++ b/arrow/memory/memory_neon_arm64.s
@@ -11,14 +11,8 @@ TEXT ·_memset_neon(SB), $0-24
        MOVD    len+8(FP), R1
        MOVD    c+16(FP), R2
 
-       // The Go ABI saves the frame pointer register one word below the 
-       // caller's frame. Make room so we don't overwrite it. Needs to stay 
-       // 16-byte aligned 
-       SUB $16, RSP
-       WORD $0xa9bf7bfd // stp    x29, x30, [sp, #-16]!
        WORD $0x8b010008 // add    x8, x0, x1
        WORD $0xeb00011f // cmp    x8, x0
-       WORD $0x910003fd // mov    x29, sp
        BLS     LBB0_7
 
        WORD $0xf100803f // cmp    x1, #32
@@ -43,7 +37,4 @@ LBB0_6:
        WORD $0xeb09011f // cmp    x8, x9
        BNE     LBB0_6
 LBB0_7:
-       WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-       // Put the stack pointer back where it was 
-       ADD $16, RSP
        RET
diff --git a/arrow/memory/memory_neon_arm64_test.go 
b/arrow/memory/memory_neon_arm64_test.go
new file mode 100644
index 00000000..c4db665e
--- /dev/null
+++ b/arrow/memory/memory_neon_arm64_test.go
@@ -0,0 +1,94 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file to you under the
+// Apache License, Version 2.0 (the "License"); you may not use this file 
except
+// in compliance with the License.  You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:build arm64 && !noasm
+
+package memory_test
+
+import (
+       "os"
+       "os/exec"
+       "runtime/pprof"
+       "strings"
+       "testing"
+       "time"
+
+       "github.com/apache/arrow-go/v18/arrow/memory"
+)
+
+func TestNEONAssemblyTracebacks(t *testing.T) {
+       // This is a regression test for GH-983. _memset_neon used to modify the
+       // stack pointer in a way that the assembler didn't see, leading to
+       // broken tracebacks in CPU profiler samples when the function is
+       // running.
+
+       buf := make([]byte, 1<<20)
+       var traces []byte
+       duration := time.Second
+       d := t.TempDir()
+       for range 5 {
+               f, err := os.CreateTemp(d, "cpu.prof")
+               if err != nil {
+                       t.Fatal(err)
+               }
+               if err := pprof.StartCPUProfile(f); err != nil {
+                       f.Close()
+                       t.Skipf("CPU profiling is already enabled: %v", err)
+               }
+
+               deadline := time.Now().Add(duration)
+               for time.Now().Before(deadline) {
+                       memory.Set(buf, 0x1f)
+               }
+               pprof.StopCPUProfile()
+               if err := f.Close(); err != nil {
+                       t.Fatal(err)
+               }
+
+               traces, err = exec.Command("go", "tool", "pprof", 
"-symbolize=none", "-traces", f.Name()).CombinedOutput()
+               if err != nil {
+                       t.Fatalf("go tool pprof -traces: %v\n%s", err, traces)
+               }
+               if strings.Contains(string(traces), "memory._memset_neon") {
+                       break
+               }
+               // Mitigate potential flakiness on CI runners
+               duration *= 2
+       }
+       if !strings.Contains(string(traces), "memory._memset_neon") {
+               t.Fatal("CPU profile contains no _memset_neon samples after 5 
attempts")
+       }
+
+       want := strings.Join([]string{
+               "github.com/apache/arrow-go/v18/arrow/memory._memset_neon",
+               
"github.com/apache/arrow-go/v18/arrow/memory.memory_memset_neon",
+               "github.com/apache/arrow-go/v18/arrow/memory.Set",
+               
"github.com/apache/arrow-go/v18/arrow/memory_test.TestNEONAssemblyTracebacks",
+       }, "\n")
+
+       for trace := range strings.SplitSeq(string(traces), "-----------") {
+               if !strings.Contains(trace, "memory._memset_neon") {
+                       continue
+               }
+
+               // pprof adds whitespace and marks inlined functions, neither 
of which is
+               // part of the call stack. Remove both before requiring 
adjacent frames.
+               trace = strings.ReplaceAll(trace, "(inline)", "")
+               trace = strings.Join(strings.Fields(trace), "\n")
+               if !strings.Contains(trace, want) {
+                       t.Errorf("invalid _memset_neon traceback:\n%s", trace)
+               }
+       }
+}
diff --git a/internal/utils/min_max_neon_arm64.s 
b/internal/utils/min_max_neon_arm64.s
index 078971d1..a037057e 100644
--- a/internal/utils/min_max_neon_arm64.s
+++ b/internal/utils/min_max_neon_arm64.s
@@ -12,13 +12,7 @@ TEXT ·_int32_max_min_neon(SB), $0-32
        MOVD    minout+16(FP), R2
        MOVD    maxout+24(FP), R3
 
-       // The Go ABI saves the frame pointer register one word below the
-       // caller's frame. Make room so we don't overwrite it. Needs to stay
-       // 16-byte aligned
-       SUB $16, RSP
-       WORD $0xa9bf7bfd // stp    x29, x30, [sp, #-16]!
        WORD $0x7100043f // cmp    w1, #1
-       WORD $0x910003fd // mov    x29, sp
        BLT int32_early_exit
 
        WORD $0x71001c3f // cmp    w1, #7
@@ -34,9 +28,6 @@ int32_early_exit:
        WORD $0x52b0000b // mov    w11, #-2147483648
        WORD $0xb900006b // str    w11, [x3]
        WORD $0xb900004a // str    w10, [x2]
-       WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-       // Put the stack pointer back where it was
-       ADD $16, RSP
        RET
 int32_neon:
        WORD $0x927d7109 // and    x9, x8, #0xfffffff8
@@ -78,9 +69,6 @@ int32_scalar_loop:
 int32_done:
        WORD $0xb900006b // str    w11, [x3]
        WORD $0xb900004a // str    w10, [x2]
-       WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-       // Put the stack pointer back where it was
-       ADD $16, RSP
        RET
 
 // func _uint32_max_min_neon(values unsafe.Pointer, length int, minout, maxout 
unsafe.Pointer)
@@ -91,13 +79,7 @@ TEXT ·_uint32_max_min_neon(SB), $0-32
        MOVD    minout+16(FP), R2
        MOVD    maxout+24(FP), R3
 
-       // The Go ABI saves the frame pointer register one word below the
-       // caller's frame. Make room so we don't overwrite it. Needs to stay
-       // 16-byte aligned
-       SUB $16, RSP
-       WORD $0xa9bf7bfd // stp    x29, x30, [sp, #-16]!
        WORD $0x7100043f // cmp    w1, #1
-       WORD $0x910003fd // mov    x29, sp
        BLT uint32_early_exit
 
        WORD $0x71001c3f // cmp    w1, #7
@@ -113,9 +95,6 @@ uint32_early_exit:
        WORD $0x1280000b // mov    w11, #-1
        WORD $0xb900006a // str    w10, [x3]
        WORD $0xb900004b // str    w11, [x2]
-       WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-       // Put the stack pointer back where it was
-       ADD $16, RSP
        RET
 uint32_neon:
        WORD $0x927d7109 // and    x9, x8, #0xfffffff8
@@ -157,9 +136,6 @@ uint32_scalar_loop:
 uint32_done:
        WORD $0xb900006a // str    w10, [x3]
        WORD $0xb900004b // str    w11, [x2]
-       WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-       // Put the stack pointer back where it was
-       ADD $16, RSP
        RET
 
 // func _int64_max_min_neon(values unsafe.Pointer, length int, minout, maxout 
unsafe.Pointer)
@@ -170,13 +146,7 @@ TEXT ·_int64_max_min_neon(SB), $0-32
        MOVD    minout+16(FP), R2
        MOVD    maxout+24(FP), R3
 
-       // The Go ABI saves the frame pointer register one word below the
-       // caller's frame. Make room so we don't overwrite it. Needs to stay
-       // 16-byte aligned
-       SUB $16, RSP
-       WORD $0xa9bf7bfd // stp    x29, x30, [sp, #-16]!
        WORD $0x7100043f // cmp    w1, #1
-       WORD $0x910003fd // mov    x29, sp
        BLT int64_early_exit
 
        WORD $0x2a0103e8 // mov    w8, w1
@@ -192,9 +162,6 @@ int64_early_exit:
        WORD $0xd2f0000b // mov    x11, #-9223372036854775808
        WORD $0xf900006b // str    x11, [x3]
        WORD $0xf900004a // str    x10, [x2]
-       WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-       // Put the stack pointer back where it was
-       ADD $16, RSP
        RET
 int64_neon:
        WORD $0x927e7509 // and    x9, x8, #0xfffffffc
@@ -246,9 +213,6 @@ int64_scalar_loop:
 int64_done:
        WORD $0xf900006b // str    x11, [x3]
        WORD $0xf900004a // str    x10, [x2]
-       WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-       // Put the stack pointer back where it was
-       ADD $16, RSP
        RET
 
 
@@ -260,13 +224,7 @@ TEXT ·_uint64_max_min_neon(SB), $0-32
        MOVD    minout+16(FP), R2
        MOVD    maxout+24(FP), R3
 
-       // The Go ABI saves the frame pointer register one word below the
-       // caller's frame. Make room so we don't overwrite it. Needs to stay
-       // 16-byte aligned
-       SUB $16, RSP
-       WORD $0xa9bf7bfd // stp    x29, x30, [sp, #-16]!
        WORD $0x7100043f // cmp    w1, #1
-       WORD $0x910003fd // mov    x29, sp
        BLT uint64_early_exit
 
        WORD $0x71000c3f // cmp    w1, #3
@@ -282,9 +240,6 @@ uint64_early_exit:
        WORD $0x9280000b // mov    x11, #-1
        WORD $0xf900006a // str    x10, [x3]
        WORD $0xf900004b // str    x11, [x2]
-       WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-       // Put the stack pointer back where it was
-       ADD $16, RSP
        RET
 uint64_neon:
        WORD $0x927e7509 // and    x9, x8, #0xfffffffc
@@ -336,7 +291,4 @@ uint64_scalar_loop:
 uint64_done:
        WORD $0xf900006a // str    x10, [x3]
        WORD $0xf900004b // str    x11, [x2]
-       WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-       // Put the stack pointer back where it was
-       ADD $16, RSP
        RET
diff --git a/parquet/internal/bmi/bitmap_neon_arm64.s 
b/parquet/internal/bmi/bitmap_neon_arm64.s
index f711e490..563548d7 100644
--- a/parquet/internal/bmi/bitmap_neon_arm64.s
+++ b/parquet/internal/bmi/bitmap_neon_arm64.s
@@ -8,13 +8,7 @@ TEXT ·_levels_to_bitmap_neon(SB), $0-32
     MOVD numLevels+8(FP), R1
     MOVD rhs+16(FP), R2
 
-    // The Go ABI saves the frame pointer register one word below the 
-    // caller's frame. Make room so we don't overwrite it. Needs to stay 
-    // 16-byte aligned 
-    SUB $16, RSP
-    WORD $0xa9bf7bfd // stp    x29, x30, [sp, #-16]!
     WORD $0x7100043f // cmp    w1, #1
-    WORD $0x910003fd // mov    x29, sp
     BLT LBB1_3
 
     WORD $0x71000c3f // cmp    w1, #3
@@ -82,9 +76,6 @@ LBB1_7:
     WORD $0xaa080168 // orr    x8, x11, x8
     BNE LBB1_7
 LBB1_8:
-    WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-    // Put the stack pointer back where it was 
-    ADD $16, RSP
     MOVD R8, res+24(FP)
     RET
 
diff --git a/parquet/internal/utils/bit_packing_neon_arm64.s 
b/parquet/internal/utils/bit_packing_neon_arm64.s
index b3a02f4c..af1779f1 100644
--- a/parquet/internal/utils/bit_packing_neon_arm64.s
+++ b/parquet/internal/utils/bit_packing_neon_arm64.s
@@ -272,7 +272,7 @@
 #define LCPI0_196 $0xfffffffcfffffffe
 #define LCPI0_200 $0xfffffffeffffffff
 
-TEXT ·_unpack32_neon(SB), $0-40
+TEXT ·_unpack32_neon(SB), $496-40
 
        MOVD in+0(FP), R0
        MOVD out+8(FP), R1
@@ -281,19 +281,14 @@ TEXT ·_unpack32_neon(SB), $0-40
        // LEAQ LCDATA1<>(SB), BP
 
        // %bb.0:
-       // The Go ABI saves the frame pointer register one word below the 
-       // caller's frame. Make room so we don't overwrite it. Needs to stay 
-       // 16-byte aligned 
-       SUB $16, RSP
-       WORD $0xa9ba7bfd // stp    x29, x30, [sp, #-96]!
-       WORD $0xd10643e9 // sub    x9, sp, #400
-       WORD $0xa9016ffc // stp    x28, x27, [sp, #16]
-       WORD $0xa90267fa // stp    x26, x25, [sp, #32]
-       WORD $0x910003fd // mov    x29, sp
-       WORD $0xa9035ff8 // stp    x24, x23, [sp, #48]
-       WORD $0xa90457f6 // stp    x22, x21, [sp, #64]
-       WORD $0xa9054ff4 // stp    x20, x19, [sp, #80]
-       WORD $0x927df13f // and    sp, x9, #0xfffffffffffffff8
+       // TODO: do not use x28, x27, or x18 since they are reserved.
+       // It is probably unnecessary to save the rest of these registers since
+       // the ABI doesn't have callee saved registers
+       WORD $0xa91a6ffc // stp    x28, x27, [sp, #416]
+       WORD $0xa91b67fa // stp    x26, x25, [sp, #432]
+       WORD $0xa91c5ff8 // stp    x24, x23, [sp, #448]
+       WORD $0xa91d57f6 // stp    x22, x21, [sp, #464]
+       WORD $0xa91e4ff4 // stp    x20, x19, [sp, #480]
        WORD $0x11007c48 // add    w8, w2, #31
        WORD $0x7100005f // cmp    w2, #0
        WORD $0x1a82b108 // csel    w8, w8, w2, lt
@@ -6919,14 +6914,13 @@ LBB0_158:
 
 LBB0_156:
        WORD $0x531b6a60    // lsl    w0, w19, #5
-       WORD $0x910003bf    // mov    sp, x29
-       WORD $0xa9454ff4    // ldp    x20, x19, [sp, #80]
-       WORD $0xa94457f6    // ldp    x22, x21, [sp, #64]
-       WORD $0xa9435ff8    // ldp    x24, x23, [sp, #48]
-       WORD $0xa94267fa    // ldp    x26, x25, [sp, #32]
-       WORD $0xa9416ffc    // ldp    x28, x27, [sp, #16]
-       WORD $0xa8c67bfd    // ldp    x29, x30, [sp], #96
-       // Put the stack pointer back where it was 
-       ADD $16, RSP
+       WORD $0xa95e4ff4    // ldp    x20, x19, [sp, #480]
+       WORD $0xa95d57f6    // ldp    x22, x21, [sp, #464]
+       WORD $0xa95c5ff8    // ldp    x24, x23, [sp, #448]
+       WORD $0xa95b67fa    // ldp    x26, x25, [sp, #432]
+       WORD $0xa95a6ffc    // ldp    x28, x27, [sp, #416]
+       // The raw compiler-generated body uses x30 as a scratch register. The
+       // Go-generated prologue saved the return address at the bottom of the 
frame.
+       MOVD 0(RSP), R30
        MOVD R0, num+32(FP)
        RET
diff --git a/parquet/internal/utils/unpack_bool_neon_arm64.s 
b/parquet/internal/utils/unpack_bool_neon_arm64.s
index f4ea581e..f8ef8bf6 100644
--- a/parquet/internal/utils/unpack_bool_neon_arm64.s
+++ b/parquet/internal/utils/unpack_bool_neon_arm64.s
@@ -11,13 +11,6 @@ TEXT ·_bytes_to_bools_neon(SB), $0-32
     MOVD out+16(FP), R2
     MOVD outlen+24(FP), R3
 
-    // The Go ABI saves the frame pointer register one word below the
-    // caller's frame. Make room so we don't overwrite it. Needs to stay
-    // 16-byte aligned
-    SUB $16, RSP
-    WORD $0xa9bf7bfd // stp    x29, x30, [sp, #-16]!
-    WORD $0x910003fd // mov    x29, sp
-
     WORD $0x7100043f // cmp    w1, #1
     BLT done
 
@@ -145,7 +138,4 @@ scalar_next:
     JMP scalar_loop
 
 done:
-    WORD $0xa8c17bfd // ldp    x29, x30, [sp], #16
-    // Put the stack pointer back where it was
-    ADD $16, RSP
     RET

Reply via email to