Text file src/internal/runtime/atomic/atomic_arm.s

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include "go_asm.h"
     6  #include "textflag.h"
     7  #include "funcdata.h"
     8  
     9  // func armcas(ptr *int32, old, new int32) bool
    10  // Atomically:
    11  //	if *ptr == old {
    12  //		*ptr = new
    13  //		return true
    14  //	} else {
    15  //		return false
    16  //	}
    17  //
    18  // To implement ·cas in sys_$GOOS_arm.s
    19  // using the native instructions, use:
    20  //
    21  //	TEXT ·cas(SB),NOSPLIT,$0
    22  //		B	·armcas(SB)
    23  //
    24  TEXT ·armcas(SB),NOSPLIT,$0-13
    25  	MOVW	ptr+0(FP), R1
    26  	MOVW	old+4(FP), R2
    27  	MOVW	new+8(FP), R3
    28  casl:
    29  	LDREX	(R1), R0
    30  	CMP	R0, R2
    31  	BNE	casfail
    32  
    33  #ifndef GOARM_7
    34  	MOVB	internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
    35  	CMP	$0, R11
    36  	BEQ	2(PC)
    37  #endif
    38  	DMB	MB_ISHST
    39  
    40  	STREX	R3, (R1), R0
    41  	CMP	$0, R0
    42  	BNE	casl
    43  	MOVW	$1, R0
    44  
    45  #ifndef GOARM_7
    46  	CMP	$0, R11
    47  	BEQ	2(PC)
    48  #endif
    49  	DMB	MB_ISH
    50  
    51  	MOVB	R0, ret+12(FP)
    52  	RET
    53  casfail:
    54  	MOVW	$0, R0
    55  	MOVB	R0, ret+12(FP)
    56  	RET
    57  
    58  // stubs
    59  
    60  TEXT ·Loadp(SB),NOSPLIT|NOFRAME,$0-8
    61  	B	·Load(SB)
    62  
    63  TEXT ·LoadAcq(SB),NOSPLIT|NOFRAME,$0-8
    64  	B	·Load(SB)
    65  
    66  TEXT ·LoadAcquintptr(SB),NOSPLIT|NOFRAME,$0-8
    67  	B 	·Load(SB)
    68  
    69  TEXT ·Casint32(SB),NOSPLIT,$0-13
    70  	B	·Cas(SB)
    71  
    72  TEXT ·Casint64(SB),NOSPLIT,$-4-21
    73  	B	·Cas64(SB)
    74  
    75  TEXT ·Casuintptr(SB),NOSPLIT,$0-13
    76  	B	·Cas(SB)
    77  
    78  TEXT ·Casp1(SB),NOSPLIT,$0-13
    79  	B	·Cas(SB)
    80  
    81  TEXT ·CasRel(SB),NOSPLIT,$0-13
    82  	B	·Cas(SB)
    83  
    84  TEXT ·Loadint32(SB),NOSPLIT,$0-8
    85  	B	·Load(SB)
    86  
    87  TEXT ·Loadint64(SB),NOSPLIT,$-4-12
    88  	B	·Load64(SB)
    89  
    90  TEXT ·Loaduintptr(SB),NOSPLIT,$0-8
    91  	B	·Load(SB)
    92  
    93  TEXT ·Loaduint(SB),NOSPLIT,$0-8
    94  	B	·Load(SB)
    95  
    96  TEXT ·Storeint32(SB),NOSPLIT,$0-8
    97  	B	·Store(SB)
    98  
    99  TEXT ·Storeint64(SB),NOSPLIT,$0-12
   100  	B	·Store64(SB)
   101  
   102  TEXT ·Storeuintptr(SB),NOSPLIT,$0-8
   103  	B	·Store(SB)
   104  
   105  TEXT ·StorepNoWB(SB),NOSPLIT,$0-8
   106  	B	·Store(SB)
   107  
   108  TEXT ·StoreRel(SB),NOSPLIT,$0-8
   109  	B	·Store(SB)
   110  
   111  TEXT ·StoreReluintptr(SB),NOSPLIT,$0-8
   112  	B	·Store(SB)
   113  
   114  TEXT ·Xaddint32(SB),NOSPLIT,$0-12
   115  	B	·Xadd(SB)
   116  
   117  TEXT ·Xaddint64(SB),NOSPLIT,$-4-20
   118  	B	·Xadd64(SB)
   119  
   120  TEXT ·Xadduintptr(SB),NOSPLIT,$0-12
   121  	B	·Xadd(SB)
   122  
   123  TEXT ·Xchgint32(SB),NOSPLIT,$0-12
   124  	B	·Xchg(SB)
   125  
   126  TEXT ·Xchgint64(SB),NOSPLIT,$-4-20
   127  	B	·Xchg64(SB)
   128  
   129  // 64-bit atomics
   130  // The native ARM implementations use LDREXD/STREXD, which are
   131  // available on ARMv6k or later. We use them only on ARMv7.
   132  // On older ARM, we use Go implementations which simulate 64-bit
   133  // atomics with locks.
   134  TEXT armCas64<>(SB),NOSPLIT,$0-21
   135  	// addr is already in R1
   136  	MOVW	old_lo+4(FP), R2
   137  	MOVW	old_hi+8(FP), R3
   138  	MOVW	new_lo+12(FP), R4
   139  	MOVW	new_hi+16(FP), R5
   140  cas64loop:
   141  	LDREXD	(R1), R6	// loads R6 and R7
   142  	CMP	R2, R6
   143  	BNE	cas64fail
   144  	CMP	R3, R7
   145  	BNE	cas64fail
   146  
   147  	DMB	MB_ISHST
   148  
   149  	STREXD	R4, (R1), R0	// stores R4 and R5
   150  	CMP	$0, R0
   151  	BNE	cas64loop
   152  	MOVW	$1, R0
   153  
   154  	DMB	MB_ISH
   155  
   156  	MOVBU	R0, swapped+20(FP)
   157  	RET
   158  cas64fail:
   159  	MOVW	$0, R0
   160  	MOVBU	R0, swapped+20(FP)
   161  	RET
   162  
   163  TEXT armXadd64<>(SB),NOSPLIT,$0-20
   164  	// addr is already in R1
   165  	MOVW	delta_lo+4(FP), R2
   166  	MOVW	delta_hi+8(FP), R3
   167  
   168  add64loop:
   169  	LDREXD	(R1), R4	// loads R4 and R5
   170  	ADD.S	R2, R4
   171  	ADC	R3, R5
   172  
   173  	DMB	MB_ISHST
   174  
   175  	STREXD	R4, (R1), R0	// stores R4 and R5
   176  	CMP	$0, R0
   177  	BNE	add64loop
   178  
   179  	DMB	MB_ISH
   180  
   181  	MOVW	R4, new_lo+12(FP)
   182  	MOVW	R5, new_hi+16(FP)
   183  	RET
   184  
   185  TEXT armXchg64<>(SB),NOSPLIT,$0-20
   186  	// addr is already in R1
   187  	MOVW	new_lo+4(FP), R2
   188  	MOVW	new_hi+8(FP), R3
   189  
   190  swap64loop:
   191  	LDREXD	(R1), R4	// loads R4 and R5
   192  
   193  	DMB	MB_ISHST
   194  
   195  	STREXD	R2, (R1), R0	// stores R2 and R3
   196  	CMP	$0, R0
   197  	BNE	swap64loop
   198  
   199  	DMB	MB_ISH
   200  
   201  	MOVW	R4, old_lo+12(FP)
   202  	MOVW	R5, old_hi+16(FP)
   203  	RET
   204  
   205  TEXT armLoad64<>(SB),NOSPLIT,$0-12
   206  	// addr is already in R1
   207  
   208  	LDREXD	(R1), R2	// loads R2 and R3
   209  	DMB	MB_ISH
   210  
   211  	MOVW	R2, val_lo+4(FP)
   212  	MOVW	R3, val_hi+8(FP)
   213  	RET
   214  
   215  TEXT armStore64<>(SB),NOSPLIT,$0-12
   216  	// addr is already in R1
   217  	MOVW	val_lo+4(FP), R2
   218  	MOVW	val_hi+8(FP), R3
   219  
   220  store64loop:
   221  	LDREXD	(R1), R4	// loads R4 and R5
   222  
   223  	DMB	MB_ISHST
   224  
   225  	STREXD	R2, (R1), R0	// stores R2 and R3
   226  	CMP	$0, R0
   227  	BNE	store64loop
   228  
   229  	DMB	MB_ISH
   230  	RET
   231  
   232  TEXT armAnd8<>(SB),NOSPLIT,$0-5
   233  	// addr is already in R1
   234  	MOVB	v+4(FP), R2
   235  
   236  and8loop:
   237  	LDREXB	(R1), R6
   238  
   239  	DMB	MB_ISHST
   240  
   241  	AND 	R2, R6
   242  	STREXB	R6, (R1), R0
   243  	CMP	$0, R0
   244  	BNE	and8loop
   245  
   246  	DMB	MB_ISH
   247  
   248  	RET
   249  
   250  TEXT armOr8<>(SB),NOSPLIT,$0-5
   251  	// addr is already in R1
   252  	MOVB	v+4(FP), R2
   253  
   254  or8loop:
   255  	LDREXB	(R1), R6
   256  
   257  	DMB	MB_ISHST
   258  
   259  	ORR 	R2, R6
   260  	STREXB	R6, (R1), R0
   261  	CMP	$0, R0
   262  	BNE	or8loop
   263  
   264  	DMB	MB_ISH
   265  
   266  	RET
   267  
   268  TEXT armXchg8<>(SB),NOSPLIT,$0-9
   269  	// addr is already in R1
   270  	MOVB	v+4(FP), R2
   271  xchg8loop:
   272  	LDREXB	(R1), R6
   273  
   274  	DMB	MB_ISHST
   275  
   276  	STREXB	R2, (R1), R0
   277  	CMP	$0, R0
   278  	BNE	xchg8loop
   279  
   280  	DMB	MB_ISH
   281  
   282  	MOVB R6, ret+8(FP)
   283  	RET
   284  
   285  // The following functions all panic if their address argument isn't
   286  // 8-byte aligned. Since we're calling back into Go code to do this,
   287  // we have to cooperate with stack unwinding. In the normal case, the
   288  // functions tail-call into the appropriate implementation, which
   289  // means they must not open a frame. Hence, when they go down the
   290  // panic path, at that point they push the LR to create a real frame
   291  // (they don't need to pop it because panic won't return; however, we
   292  // do need to set the SP delta back).
   293  
   294  // Check if R1 is 8-byte aligned, panic if not.
   295  // Clobbers R2.
   296  #define CHECK_ALIGN \
   297  	AND.S	$7, R1, R2 \
   298  	BEQ 	4(PC) \
   299  	MOVW.W	R14, -4(R13) /* prepare a real frame */ \
   300  	BL	·panicUnaligned(SB) \
   301  	ADD	$4, R13 /* compensate SP delta */
   302  
   303  TEXT ·Cas64(SB),NOSPLIT,$-4-21
   304  	NO_LOCAL_POINTERS
   305  	MOVW	addr+0(FP), R1
   306  	CHECK_ALIGN
   307  
   308  #ifndef GOARM_7
   309  	MOVB	internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
   310  	CMP	$1, R11
   311  	BEQ	2(PC)
   312  	JMP	·goCas64(SB)
   313  #endif
   314  	JMP	armCas64<>(SB)
   315  
   316  TEXT ·Xadd64(SB),NOSPLIT,$-4-20
   317  	NO_LOCAL_POINTERS
   318  	MOVW	addr+0(FP), R1
   319  	CHECK_ALIGN
   320  
   321  #ifndef GOARM_7
   322  	MOVB	internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
   323  	CMP	$1, R11
   324  	BEQ	2(PC)
   325  	JMP	·goXadd64(SB)
   326  #endif
   327  	JMP	armXadd64<>(SB)
   328  
   329  TEXT ·Xchg64(SB),NOSPLIT,$-4-20
   330  	NO_LOCAL_POINTERS
   331  	MOVW	addr+0(FP), R1
   332  	CHECK_ALIGN
   333  
   334  #ifndef GOARM_7
   335  	MOVB	internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
   336  	CMP	$1, R11
   337  	BEQ	2(PC)
   338  	JMP	·goXchg64(SB)
   339  #endif
   340  	JMP	armXchg64<>(SB)
   341  
   342  TEXT ·Load64(SB),NOSPLIT,$-4-12
   343  	NO_LOCAL_POINTERS
   344  	MOVW	addr+0(FP), R1
   345  	CHECK_ALIGN
   346  
   347  #ifndef GOARM_7
   348  	MOVB	internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
   349  	CMP	$1, R11
   350  	BEQ	2(PC)
   351  	JMP	·goLoad64(SB)
   352  #endif
   353  	JMP	armLoad64<>(SB)
   354  
   355  TEXT ·Store64(SB),NOSPLIT,$-4-12
   356  	NO_LOCAL_POINTERS
   357  	MOVW	addr+0(FP), R1
   358  	CHECK_ALIGN
   359  
   360  #ifndef GOARM_7
   361  	MOVB	internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
   362  	CMP	$1, R11
   363  	BEQ	2(PC)
   364  	JMP	·goStore64(SB)
   365  #endif
   366  	JMP	armStore64<>(SB)
   367  
   368  TEXT ·And8(SB),NOSPLIT,$-4-5
   369  	NO_LOCAL_POINTERS
   370  	MOVW	addr+0(FP), R1
   371  
   372  // Uses STREXB/LDREXB that is armv6k or later.
   373  // For simplicity we only enable this on armv7.
   374  #ifndef GOARM_7
   375  	MOVB	internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
   376  	CMP	$1, R11
   377  	BEQ	2(PC)
   378  	JMP	·goAnd8(SB)
   379  #endif
   380  	JMP	armAnd8<>(SB)
   381  
   382  TEXT ·Or8(SB),NOSPLIT,$-4-5
   383  	NO_LOCAL_POINTERS
   384  	MOVW	addr+0(FP), R1
   385  
   386  // Uses STREXB/LDREXB that is armv6k or later.
   387  // For simplicity we only enable this on armv7.
   388  #ifndef GOARM_7
   389  	MOVB	internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
   390  	CMP	$1, R11
   391  	BEQ	2(PC)
   392  	JMP	·goOr8(SB)
   393  #endif
   394  	JMP	armOr8<>(SB)
   395  
   396  TEXT ·Xchg8(SB),NOSPLIT,$-4-9
   397  	NO_LOCAL_POINTERS
   398  	MOVW	addr+0(FP), R1
   399  
   400  	// Uses STREXB/LDREXB that is armv6k or later.
   401  	// For simplicity we only enable this on armv7.
   402  #ifndef GOARM_7
   403  	MOVB	internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
   404  	CMP	$1, R11
   405  	BEQ	2(PC)
   406  	JMP	·goXchg8(SB)
   407  #endif
   408  	JMP	armXchg8<>(SB)
   409  

View as plain text