Skip to content

Commit 42e397b

Browse files
authored
[NativeAOT] Use 8.1 atomics, if available, in RhpCheckedXchg/RhpCheckedLockCmpXchg (#85283)
* use atomics when available * exch win * conditional atomics * moving ARM64_ATOMICS_FEATURE_FLAG_BIT to AsmOffsets.h and adding a static assert. * enable lse locally in the asm helpers
1 parent c04933d commit 42e397b

File tree

7 files changed

+124
-11
lines changed

7 files changed

+124
-11
lines changed

src/coreclr/nativeaot/Runtime/AsmOffsets.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ ASM_CONST( 2, 2, STRING_COMPONENT_SIZE)
3434
ASM_CONST( E, 16, STRING_BASE_SIZE)
3535
ASM_CONST(3FFFFFDF,3FFFFFDF,MAX_STRING_LENGTH)
3636

37+
38+
#if defined(HOST_ARM64)
39+
// Bit position for the ARM64IntrinsicConstants_Atomics flags, to be used with tbz / tbnz instructions
40+
// ARM64IntrinsicConstants_Atomics = 0x0080
41+
ASM_CONST( 7, 7, ARM64_ATOMICS_FEATURE_FLAG_BIT)
42+
#endif
43+
3744
ASM_OFFSET( 0, 0, MethodTable, m_usComponentSize)
3845
ASM_OFFSET( 0, 0, MethodTable, m_uFlags)
3946
ASM_OFFSET( 4, 4, MethodTable, m_uBaseSize)

src/coreclr/nativeaot/Runtime/EHHelpers.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ EXTERN_C void * RhpCheckedXchgAVLocation;
286286
EXTERN_C void * RhpLockCmpXchg32AVLocation;
287287
EXTERN_C void * RhpLockCmpXchg64AVLocation;
288288

289+
#if defined(HOST_ARM64) && !defined(LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT)
290+
EXTERN_C void* RhpCheckedLockCmpXchgAVLocation2;
291+
EXTERN_C void* RhpCheckedXchgAVLocation2;
292+
#endif
293+
289294
static bool InWriteBarrierHelper(uintptr_t faultingIP)
290295
{
291296
#ifndef USE_PORTABLE_HELPERS
@@ -297,6 +302,10 @@ static bool InWriteBarrierHelper(uintptr_t faultingIP)
297302
(uintptr_t)&RhpCheckedXchgAVLocation,
298303
(uintptr_t)&RhpLockCmpXchg32AVLocation,
299304
(uintptr_t)&RhpLockCmpXchg64AVLocation,
305+
#if defined(HOST_ARM64) && !defined(LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT)
306+
(uintptr_t)&RhpCheckedLockCmpXchgAVLocation2,
307+
(uintptr_t)&RhpCheckedXchgAVLocation2,
308+
#endif
300309
};
301310

302311
// compare the IP against the list of known possible AV locations in the write barrier helpers

src/coreclr/nativeaot/Runtime/IntrinsicConstants.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ enum ARM64IntrinsicConstants
5050
ARM64IntrinsicConstants_Atomics = 0x0080,
5151
ARM64IntrinsicConstants_Rcpc = 0x0100,
5252
};
53+
54+
// Bit position for the ARM64IntrinsicConstants_Atomics flags, to be used with tbz / tbnz instructions
55+
static const int ARM64_ATOMICS_FEATURE_FLAG_BIT = 7;
56+
static_assert((1 << ARM64_ATOMICS_FEATURE_FLAG_BIT) == ARM64IntrinsicConstants_Atomics, "ARM64_ATOMICS_FEATURE_FLAG_BIT must match with ARM64IntrinsicConstants_Atomics");
57+
5358
#endif //HOST_ARM64
5459

5560
#endif //!INTRINSICCONSTANTS_INCLUDED

src/coreclr/nativeaot/Runtime/amd64/AsmMacros.inc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,4 +420,3 @@ endif
420420
ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
421421
EXTERN g_write_watch_table : QWORD
422422
endif
423-

src/coreclr/nativeaot/Runtime/arm64/AsmMacros.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ OFFSETOF__Thread__m_alloc_context__alloc_limit equ OFFSETOF__Thread__m_rgbA
116116
EXTERN g_write_watch_table
117117
#endif
118118

119+
EXTERN g_cpuFeatures
119120

120121
;; -----------------------------------------------------------------------------
121122
;; Macro used to assign an alternate name to a symbol containing characters normally disallowed in a symbol
@@ -163,6 +164,16 @@ MovInstr SETS "movk"
163164
ldr $Reg, [$Reg, $Name]
164165
MEND
165166

167+
;; ---------------------------------------------------------------------------- -
168+
;; Macro for loading a 32bit value of a global variable into a register
169+
MACRO
170+
PREPARE_EXTERNAL_VAR_INDIRECT_W $Name, $RegNum
171+
172+
adrp x$RegNum, $Name
173+
ldr w$RegNum, [x$RegNum, $Name]
174+
MEND
175+
176+
166177
;; -----------------------------------------------------------------------------
167178
;;
168179
;; Macro to export a pointer to an address inside a stub as a 64-bit variable

src/coreclr/nativeaot/Runtime/arm64/WriteBarriers.S

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ LEAF_END RhpAssignRef, _TEXT
268268
// - Function "InWriteBarrierHelper" assumes an AV due to passed in null pointer will happen at RhpCheckedLockCmpXchgAVLocation
269269
// - Function "UnwindSimpleHelperToCaller" assumes no registers were pushed and LR contains the return address
270270

271+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
272+
.arch_extension lse
273+
#endif
274+
271275
// RhpCheckedLockCmpXchg(Object** dest, Object* value, Object* comparand)
272276
//
273277
// Interlocked compare exchange on objectref.
@@ -279,21 +283,36 @@ LEAF_END RhpAssignRef, _TEXT
279283
//
280284
// On exit:
281285
// x0: original value of objectref
282-
// x10, x12, x17: trashed
286+
// x10, x12, x16, x17: trashed
283287
//
284288
LEAF_ENTRY RhpCheckedLockCmpXchg
285289

290+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
291+
PREPARE_EXTERNAL_VAR_INDIRECT_W g_cpuFeatures, 16
292+
tbz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, CmpXchgRetry
293+
#endif
294+
295+
mov x10, x2
296+
ALTERNATE_ENTRY RhpCheckedLockCmpXchgAVLocation
297+
casal x10, x1, [x0] // exchange
298+
cmp x2, x10
299+
bne CmpXchgNoUpdate
300+
301+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
302+
b DoCardsCmpXchg
286303
CmpXchgRetry:
287304
// Check location value is what we expect.
288-
ALTERNATE_ENTRY RhpCheckedLockCmpXchgAVLocation
305+
ALTERNATE_ENTRY RhpCheckedLockCmpXchgAVLocation2
289306
ldaxr x10, [x0]
290307
cmp x10, x2
291308
bne CmpXchgNoUpdate
292309

293310
// Current value matches comparand, attempt to update with the new value.
294311
stlxr w12, x1, [x0]
295312
cbnz w12, CmpXchgRetry
313+
#endif
296314

315+
DoCardsCmpXchg:
297316
// We have successfully updated the value of the objectref so now we need a GC write barrier.
298317
// The following barrier code takes the destination in x0 and the value in x1 so the arguments are
299318
// already correctly set up.
@@ -303,7 +322,12 @@ CmpXchgRetry:
303322
CmpXchgNoUpdate:
304323
// x10 still contains the original value.
305324
mov x0, x10
325+
326+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
327+
tbnz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, NoBarrierCmpXchg
306328
InterlockedOperationBarrier
329+
NoBarrierCmpXchg:
330+
#endif
307331
ret lr
308332

309333
LEAF_END RhpCheckedLockCmpXchg, _TEXT
@@ -323,19 +347,31 @@ CmpXchgNoUpdate:
323347
// On exit:
324348
// x0: original value of objectref
325349
// x10: trashed
326-
// x12, x17: trashed
350+
// x12, x16, x17: trashed
327351
//
328352
LEAF_ENTRY RhpCheckedXchg, _TEXT
329353

354+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
355+
PREPARE_EXTERNAL_VAR_INDIRECT_W g_cpuFeatures, 16
356+
tbz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, ExchangeRetry
357+
#endif
358+
359+
ALTERNATE_ENTRY RhpCheckedXchgAVLocation
360+
swpal x1, x10, [x0] // exchange
361+
362+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
363+
b DoCardsXchg
330364
ExchangeRetry:
331365
// Read the existing memory location.
332-
ALTERNATE_ENTRY RhpCheckedXchgAVLocation
366+
ALTERNATE_ENTRY RhpCheckedXchgAVLocation2
333367
ldaxr x10, [x0]
334368

335369
// Attempt to update with the new value.
336370
stlxr w12, x1, [x0]
337371
cbnz w12, ExchangeRetry
372+
#endif
338373

374+
DoCardsXchg:
339375
// We have successfully updated the value of the objectref so now we need a GC write barrier.
340376
// The following barrier code takes the destination in x0 and the value in x1 so the arguments are
341377
// already correctly set up.
@@ -344,7 +380,16 @@ ExchangeRetry:
344380

345381
// x10 still contains the original value.
346382
mov x0, x10
383+
384+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
385+
tbnz w16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, NoBarrierXchg
347386
InterlockedOperationBarrier
387+
NoBarrierXchg:
388+
#endif
348389
ret
349390

350391
LEAF_END RhpCheckedXchg, _TEXT
392+
393+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
394+
.arch_extension nolse
395+
#endif

src/coreclr/nativeaot/Runtime/arm64/WriteBarriers.asm

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -294,22 +294,37 @@ NotInHeap
294294
;;
295295
;; On exit:
296296
;; x0: original value of objectref
297-
;; x10, x12, x17: trashed
297+
;; x10, x12, x16, x17: trashed
298298
;;
299299
LEAF_ENTRY RhpCheckedLockCmpXchg
300300

301+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
302+
PREPARE_EXTERNAL_VAR_INDIRECT_W g_cpuFeatures, 16
303+
tbz x16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, CmpXchgRetry
304+
#endif
305+
306+
mov x10, x2
307+
ALTERNATE_ENTRY RhpCheckedLockCmpXchgAVLocation
308+
casal x10, x1, [x0] ;; exchange
309+
cmp x2, x10
310+
bne CmpXchgNoUpdate
311+
312+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
313+
b DoCardsCmpXchg
301314
CmpXchgRetry
302315
;; Check location value is what we expect.
303-
ALTERNATE_ENTRY RhpCheckedLockCmpXchgAVLocation
316+
ALTERNATE_ENTRY RhpCheckedLockCmpXchgAVLocation2
304317
ldaxr x10, [x0]
305318
cmp x10, x2
306319
bne CmpXchgNoUpdate
307320

308321
;; Current value matches comparand, attempt to update with the new value.
309322
stlxr w12, x1, [x0]
310323
cbnz w12, CmpXchgRetry
324+
#endif
311325

312-
;; We've successfully updated the value of the objectref so now we need a GC write barrier.
326+
DoCardsCmpXchg
327+
;; We have successfully updated the value of the objectref so now we need a GC write barrier.
313328
;; The following barrier code takes the destination in x0 and the value in x1 so the arguments are
314329
;; already correctly set up.
315330

@@ -318,7 +333,12 @@ CmpXchgRetry
318333
CmpXchgNoUpdate
319334
;; x10 still contains the original value.
320335
mov x0, x10
336+
337+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
338+
tbnz x16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, NoBarrierCmpXchg
321339
InterlockedOperationBarrier
340+
NoBarrierCmpXchg
341+
#endif
322342
ret lr
323343

324344
LEAF_END RhpCheckedLockCmpXchg
@@ -338,28 +358,45 @@ CmpXchgNoUpdate
338358
;; On exit:
339359
;; x0: original value of objectref
340360
;; x10: trashed
341-
;; x12, x17: trashed
361+
;; x12, x16, x17: trashed
342362
;;
343363
LEAF_ENTRY RhpCheckedXchg
344364

365+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
366+
PREPARE_EXTERNAL_VAR_INDIRECT_W g_cpuFeatures, 16
367+
tbz x16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, ExchangeRetry
368+
#endif
369+
370+
ALTERNATE_ENTRY RhpCheckedXchgAVLocation
371+
swpal x1, x10, [x0] ;; exchange
372+
373+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
374+
b DoCardsXchg
345375
ExchangeRetry
346376
;; Read the existing memory location.
347-
ALTERNATE_ENTRY RhpCheckedXchgAVLocation
377+
ALTERNATE_ENTRY RhpCheckedXchgAVLocation2
348378
ldaxr x10, [x0]
349379

350380
;; Attempt to update with the new value.
351381
stlxr w12, x1, [x0]
352382
cbnz w12, ExchangeRetry
383+
#endif
353384

354-
;; We've successfully updated the value of the objectref so now we need a GC write barrier.
385+
DoCardsXchg
386+
;; We have successfully updated the value of the objectref so now we need a GC write barrier.
355387
;; The following barrier code takes the destination in x0 and the value in x1 so the arguments are
356388
;; already correctly set up.
357389

358390
INSERT_CHECKED_WRITE_BARRIER_CORE x0, x1
359391

360392
;; x10 still contains the original value.
361393
mov x0, x10
394+
395+
#ifndef LSE_INSTRUCTIONS_ENABLED_BY_DEFAULT
396+
tbnz x16, #ARM64_ATOMICS_FEATURE_FLAG_BIT, NoBarrierXchg
362397
InterlockedOperationBarrier
398+
NoBarrierXchg
399+
#endif
363400
ret
364401

365402
LEAF_END RhpCheckedXchg

0 commit comments

Comments
 (0)