# Verify PPC64 does not reuse a trampoline which is too far away.
# This tests an edge case where the direct call relocation addend should
# be ignored when computing the distance from the direct call to the
# already placed trampoline
[short] skip
[!ppc64] [!ppc64le] skip
[aix] skip

# Note, this program does not run. Presumably, 'DWORD $0' is simpler to
# assembly 2^26 or so times.
#
# We build something which should be laid out as such:
#
# bar.Bar
# main.Func1
# bar.Bar+400-tramp0
# main.BigAsm
# main.Func2
# bar.Bar+400-tramp1
#
# bar.Bar needs to be placed far enough away to generate relocations
# from main package calls. and main.Func1 and main.Func2 are placed
# a bit more than the direct call limit apart, but not more than 0x400
# bytes beyond it (to verify the reloc calc).

go build

-- go.mod --

module foo

go 1.19

-- main.go --

package main

import "foo/bar"

func Func1()

func main() {
        Func1()
        bar.Bar2()
}

-- foo.s --

TEXT main·Func1(SB),0,$0-0
        CALL bar·Bar+0x400(SB)
        CALL main·BigAsm(SB)
// A trampoline will be placed here to bar.Bar

// This creates a gap sufficiently large to prevent trampoline reuse
#define NOP64 DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0;
#define NOP256 NOP64 NOP64 NOP64 NOP64
#define NOP2S10 NOP256 NOP256 NOP256 NOP256
#define NOP2S12 NOP2S10 NOP2S10 NOP2S10 NOP2S10
#define NOP2S14 NOP2S12 NOP2S12 NOP2S12 NOP2S12
#define NOP2S16 NOP2S14 NOP2S14 NOP2S14 NOP2S14
#define NOP2S18 NOP2S16 NOP2S16 NOP2S16 NOP2S16
#define NOP2S20 NOP2S18 NOP2S18 NOP2S18 NOP2S18
#define NOP2S22 NOP2S20 NOP2S20 NOP2S20 NOP2S20
#define NOP2S24 NOP2S22 NOP2S22 NOP2S22 NOP2S22
#define BIGNOP NOP2S24 NOP2S24
TEXT main·BigAsm(SB),0,$0-0
        // Fill to the direct call limit so Func2 must generate a new trampoline.
        // As the implicit trampoline above is just barely unreachable.
        BIGNOP
        MOVD $main·Func2(SB), R3

TEXT main·Func2(SB),0,$0-0
        CALL bar·Bar+0x400(SB)
// Another trampoline should be placed here.

-- bar/bar.s --

#define NOP64 DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0; DWORD $0;
#define NOP256 NOP64 NOP64 NOP64 NOP64
#define NOP2S10 NOP256 NOP256 NOP256 NOP256
#define NOP2S12 NOP2S10 NOP2S10 NOP2S10 NOP2S10
#define NOP2S14 NOP2S12 NOP2S12 NOP2S12 NOP2S12
#define NOP2S16 NOP2S14 NOP2S14 NOP2S14 NOP2S14
#define NOP2S18 NOP2S16 NOP2S16 NOP2S16 NOP2S16
#define NOP2S20 NOP2S18 NOP2S18 NOP2S18 NOP2S18
#define NOP2S22 NOP2S20 NOP2S20 NOP2S20 NOP2S20
#define NOP2S24 NOP2S22 NOP2S22 NOP2S22 NOP2S22
#define BIGNOP NOP2S24 NOP2S24 NOP2S10
// A very big not very interesting function.
TEXT bar·Bar(SB),0,$0-0
        BIGNOP

-- bar/bar.go --

package bar

func Bar()

func Bar2() {
}
