root/src/pkg/sync/atomic/asm_arm.s

/* [<][>][^][v][top][bottom][index][help] */
// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !race

#include "../../../cmd/ld/textflag.h"

// ARM atomic operations, for use by asm_$(GOOS)_arm.s.

TEXT 揃armCompareAndSwapUint32(SB),NOSPLIT,$0-13
        MOVW    addr+0(FP), R1
        MOVW    old+4(FP), R2
        MOVW    new+8(FP), R3
casloop:
        // LDREX and STREX were introduced in ARMv6.
        LDREX   (R1), R0
        CMP     R0, R2
        BNE     casfail
        STREX   R3, (R1), R0
        CMP     $0, R0
        BNE     casloop
        MOVW    $1, R0
        MOVBU   R0, ret+12(FP)
        RET
casfail:
        MOVW    $0, R0
        MOVBU   R0, ret+12(FP)
        RET

TEXT 揃armCompareAndSwapUint64(SB),NOSPLIT,$0-21
        BL      fastCheck64<>(SB)
        MOVW    addr+0(FP), R1
        // make unaligned atomic access panic
        AND.S   $7, R1, R2
        BEQ     2(PC)
        MOVW    R2, (R2)
        MOVW    oldlo+4(FP), R2
        MOVW    oldhi+8(FP), R3
        MOVW    newlo+12(FP), R4
        MOVW    newhi+16(FP), R5
cas64loop:
        // LDREXD and STREXD were introduced in ARMv6k.
        LDREXD  (R1), R6  // loads R6 and R7
        CMP     R2, R6
        BNE     cas64fail
        CMP     R3, R7
        BNE     cas64fail
        STREXD  R4, (R1), R0    // stores R4 and R5
        CMP     $0, R0
        BNE     cas64loop
        MOVW    $1, R0
        MOVBU   R0, ret+20(FP)
        RET
cas64fail:
        MOVW    $0, R0
        MOVBU   R0, ret+20(FP)
        RET

TEXT 揃armAddUint32(SB),NOSPLIT,$0-12
        MOVW    addr+0(FP), R1
        MOVW    delta+4(FP), R2
addloop:
        // LDREX and STREX were introduced in ARMv6.
        LDREX   (R1), R3
        ADD     R2, R3
        STREX   R3, (R1), R0
        CMP     $0, R0
        BNE     addloop
        MOVW    R3, ret+8(FP)
        RET

TEXT 揃armAddUint64(SB),NOSPLIT,$0-20
        BL      fastCheck64<>(SB)
        MOVW    addr+0(FP), R1
        // make unaligned atomic access panic
        AND.S   $7, R1, R2
        BEQ     2(PC)
        MOVW    R2, (R2)
        MOVW    deltalo+4(FP), R2
        MOVW    deltahi+8(FP), R3
add64loop:
        // LDREXD and STREXD were introduced in ARMv6k.
        LDREXD  (R1), R4        // loads R4 and R5
        ADD.S   R2, R4
        ADC     R3, R5
        STREXD  R4, (R1), R0    // stores R4 and R5
        CMP     $0, R0
        BNE     add64loop
        MOVW    R4, retlo+12(FP)
        MOVW    R5, rethi+16(FP)
        RET

TEXT 揃armSwapUint32(SB),NOSPLIT,$0-12
        MOVW    addr+0(FP), R1
        MOVW    new+4(FP), R2
swaploop:
        // LDREX and STREX were introduced in ARMv6.
        LDREX   (R1), R3
        STREX   R2, (R1), R0
        CMP     $0, R0
        BNE     swaploop
        MOVW    R3, old+8(FP)
        RET

TEXT 揃armSwapUint64(SB),NOSPLIT,$0-20
        BL      fastCheck64<>(SB)
        MOVW    addr+0(FP), R1
        // make unaligned atomic access panic
        AND.S   $7, R1, R2
        BEQ     2(PC)
        MOVW    R2, (R2)
        MOVW    newlo+4(FP), R2
        MOVW    newhi+8(FP), R3
swap64loop:
        // LDREXD and STREXD were introduced in ARMv6k.
        LDREXD  (R1), R4        // loads R4 and R5
        STREXD  R2, (R1), R0    // stores R2 and R3
        CMP     $0, R0
        BNE     swap64loop
        MOVW    R4, oldlo+12(FP)
        MOVW    R5, oldhi+16(FP)
        RET

TEXT 揃armLoadUint64(SB),NOSPLIT,$0-12
        BL      fastCheck64<>(SB)
        MOVW    addr+0(FP), R1
        // make unaligned atomic access panic
        AND.S   $7, R1, R2
        BEQ     2(PC)
        MOVW    R2, (R2)
load64loop:
        LDREXD  (R1), R2        // loads R2 and R3
        STREXD  R2, (R1), R0    // stores R2 and R3
        CMP     $0, R0
        BNE     load64loop
        MOVW    R2, vallo+4(FP)
        MOVW    R3, valhi+8(FP)
        RET

TEXT 揃armStoreUint64(SB),NOSPLIT,$0-12
        BL      fastCheck64<>(SB)
        MOVW    addr+0(FP), R1
        // make unaligned atomic access panic
        AND.S   $7, R1, R2
        BEQ     2(PC)
        MOVW    R2, (R2)
        MOVW    vallo+4(FP), R2
        MOVW    valhi+8(FP), R3
store64loop:
        LDREXD  (R1), R4        // loads R4 and R5
        STREXD  R2, (R1), R0    // stores R2 and R3
        CMP     $0, R0
        BNE     store64loop
        RET

// Check for broken 64-bit LDREXD as found in QEMU.
// LDREXD followed by immediate STREXD should succeed.
// If it fails, try a few times just to be sure (maybe our thread got
// rescheduled between the two instructions) and then panic.
// A bug in some copies of QEMU makes STREXD never succeed,
// which will make uses of the 64-bit atomic operations loop forever.
// If things are working, set okLDREXD to avoid future checks.
// https://bugs.launchpad.net/qemu/+bug/670883.
TEXT    check64<>(SB),NOSPLIT,$16-0
        MOVW    $10, R1
        // 8-aligned stack address scratch space.
        MOVW    $8(R13), R5
        AND     $~7, R5
loop:
        LDREXD  (R5), R2
        STREXD  R2, (R5), R0
        CMP     $0, R0
        BEQ     ok
        SUB     $1, R1
        CMP     $0, R1
        BNE     loop
        // Must be buggy QEMU.
        BL      揃panic64(SB)
ok:
        RET

// Fast, cached version of check.  No frame, just MOVW CMP RET after first time.
TEXT    fastCheck64<>(SB),NOSPLIT,$-4
        MOVW    ok64<>(SB), R0
        CMP     $0, R0  // have we been here before?
        RET.NE
        B       slowCheck64<>(SB)

TEXT slowCheck64<>(SB),NOSPLIT,$0-0
        BL      check64<>(SB)
        // Still here, must be okay.
        MOVW    $1, R0
        MOVW    R0, ok64<>(SB)
        RET

GLOBL ok64<>(SB), $4

/* [<][>][^][v][top][bottom][index][help] */