0

I'm trying to write Ackermann function as assembly code(in ARMV8).

(http://mathworld.wolfram.com/AckermannFunction.html https://en.wikipedia.org/wiki/Ackermann_function)

It requires recursion. My code goes into an infinite recursion. I couldn't find what is the problem about stack pointer handling.

X0 and X1 are input registers. I'm returning the result in X0.

     ack:
        SUB SP, SP, #24
        STUR X0,[SP,#16] // save input1 to stack pointer
        STUR X1,[SP,#8] // save input2 to stack pointer
        STUR X30,[SP,#0] // save return adress
        SUBS XZR,X0,#0 // check input1 <= 0
        B.GT cond1 
        ADD X0,X1,#1 
        B last 
  cond1:
        SUBS XZR,X1,#0
        B.GT gobig
        SUB X0,X0,#1
        MOVZ X1,0 
        ADD X1,X1,1 
        BL ack // call ack with input1-1 and 1
        LDUR X30,[SP,#0] //restore return address
        ADD SP,SP,#24
        BR X30 // return register adress
  gobig:
        LDUR X0,[SP,#16]
        LDUR X1,[SP,#8]
        SUB X1,X1,#1
        BL ack //call ack with input1 and input2-1 (call result r)
        ADD X1,X0,#0
        LDUR X0,[SP,#16]
        SUB X0,X0,#1
        BL ack //call ack wih input1-1 and r
  last:
        LDUR X30,[SP,#0]
        ADD SP,SP,#24 //restore stack pointer
        BR X30 //return adress register
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
bo_
  • 35
  • 8
  • Comment your code with pseudocode of the logic so it's easier to follow what you *want* it to be doing / how you're trying to implement it, to make it a better [mcve]. Also use a debugger to find out *which* loop it's getting stuck in, with what register values. I don't see any `ret` instructions in your code. – Peter Cordes Apr 16 '19 at 01:30
  • @PeterCordes BR (jump register) returns to an address. What do you mean by ret? – bo_ Apr 16 '19 at 01:38
  • Normally in AArch64, you use the `ret` instruction instead of `br x30`. Architecturally they are equivalent, but there's a separate opcode that hints the CPU that it's a subroutine return. (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0802a/RET.html) Presumably this leads to better branch prediction by using a return-address predictor stack that matches it with a `bl`. If you haven't learned about `ret` yet, then nevermind. `br x30` is equivalent but slower. – Peter Cordes Apr 16 '19 at 01:42
  • I have'nt learned yet, but thanks. I see the difference. – bo_ Apr 16 '19 at 01:43
  • @PeterCordes any adivece about the code? – bo_ Apr 16 '19 at 01:47
  • `MOVZ X1,0` / `add x1,x1,1` is an obfuscated way to write `mov x1, 1`. You have `ADD X0,X1,#1` which deserves a comment like `return input2+1`. Any time you're overwriting one value with another, it's significant. You can also simplify by doing `subs x1, x1, #1` / `b.ge gobig`, because you want `input2-1` in `gobig` and you're throwing away input2 in the fall-through. No sense wasting an instruction comparing against zero and *then* subtracting 1, when you could check `input2 >= 1` instead of `input2 > 0`. Simplify your code so it's easier to see what it's doing. – Peter Cordes Apr 16 '19 at 01:50
  • (When you reach `gobig`, you haven't made any `bl` recursive calls yet in this invocation, so you don't need to reload from the stack.) – Peter Cordes Apr 16 '19 at 01:52
  • anything about infinite recursion? – bo_ Apr 16 '19 at 01:56
  • I didn't notice a bug just from looking at it, especially with all the obfuscation of using `subs` into XZR instead of `cmp`, and the other things I pointed out. The question doesn't have much hint of where to look, since it doesn't show register values or what path execution takes. Are you sure you didn't just give it an input that's too big? The Ackermann function grows *extremely* fast, to sizes that will overflow 64-bit integers (or even sooner overflow a normal size stack) even for small integer inputs. Did you check that it's actually failing for like `ack(2,2)`? – Peter Cordes Apr 16 '19 at 02:07

0 Answers0