@@ -2732,20 +2732,29 @@ void MacroAssembler::cmpxchgptr(Register oldv, Register newv, Register addr, Reg
2732
2732
// oldv holds comparison value
2733
2733
// newv holds value to write in exchange
2734
2734
// addr identifies memory word to compare against/update
2735
- Label retry_load, nope;
2736
- bind (retry_load);
2737
- // Load reserved from the memory location
2738
- load_reserved (tmp, addr, int64, Assembler::aqrl);
2739
- // Fail and exit if it is not what we expect
2740
- bne (tmp, oldv, nope);
2741
- // If the store conditional succeeds, tmp will be zero
2742
- store_conditional (tmp, newv, addr, int64, Assembler::rl);
2743
- beqz (tmp, succeed);
2744
- // Retry only when the store conditional failed
2745
- j (retry_load);
2746
-
2747
- bind (nope);
2735
+ if (UseZacas) {
2736
+ mv (tmp, oldv);
2737
+ atomic_cas (tmp, newv, addr, Assembler::int64, Assembler::aq, Assembler::rl);
2738
+ beq (tmp, oldv, succeed);
2739
+ } else {
2740
+ Label retry_load, nope;
2741
+ bind (retry_load);
2742
+ // Load reserved from the memory location
2743
+ load_reserved (tmp, addr, int64, Assembler::aqrl);
2744
+ // Fail and exit if it is not what we expect
2745
+ bne (tmp, oldv, nope);
2746
+ // If the store conditional succeeds, tmp will be zero
2747
+ store_conditional (tmp, newv, addr, int64, Assembler::rl);
2748
+ beqz (tmp, succeed);
2749
+ // Retry only when the store conditional failed
2750
+ j (retry_load);
2751
+
2752
+ bind (nope);
2753
+ }
2754
+
2755
+ // neither amocas nor lr/sc have an implied barrier in the failing case
2748
2756
membar (AnyAny);
2757
+
2749
2758
mv (oldv, tmp);
2750
2759
if (fail != nullptr ) {
2751
2760
j (*fail);
@@ -2819,7 +2828,7 @@ void MacroAssembler::cmpxchg_narrow_value_helper(Register addr, Register expecte
2819
2828
}
2820
2829
sll (mask, mask, shift);
2821
2830
2822
- xori (not_mask, mask, - 1 );
2831
+ notr (not_mask, mask);
2823
2832
2824
2833
sll (expected, expected, shift);
2825
2834
andr (expected, expected, mask);
@@ -2829,7 +2838,7 @@ void MacroAssembler::cmpxchg_narrow_value_helper(Register addr, Register expecte
2829
2838
}
2830
2839
2831
2840
// cmpxchg_narrow_value will kill t0, t1, expected, new_val and tmps.
2832
- // It's designed to implement compare and swap byte/boolean/char/short by lr.w/sc.w,
2841
+ // It's designed to implement compare and swap byte/boolean/char/short by lr.w/sc.w or amocas.w ,
2833
2842
// which are forced to work with 4-byte aligned address.
2834
2843
void MacroAssembler::cmpxchg_narrow_value (Register addr, Register expected,
2835
2844
Register new_val,
@@ -2844,14 +2853,29 @@ void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected,
2844
2853
Label retry, fail, done;
2845
2854
2846
2855
bind (retry);
2847
- lr_w (old, aligned_addr, acquire);
2848
- andr (tmp, old, mask);
2849
- bne (tmp, expected, fail);
2850
2856
2851
- andr (tmp, old, not_mask);
2852
- orr (tmp, tmp, new_val);
2853
- sc_w (tmp, tmp, aligned_addr, release);
2854
- bnez (tmp, retry);
2857
+ if (UseZacas) {
2858
+ lw (old, aligned_addr);
2859
+
2860
+ // if old & mask != expected
2861
+ andr (tmp, old, mask);
2862
+ bne (tmp, expected, fail);
2863
+
2864
+ andr (tmp, old, not_mask);
2865
+ orr (tmp, tmp, new_val);
2866
+
2867
+ atomic_cas (old, tmp, aligned_addr, operand_size::int32, acquire, release);
2868
+ bne (tmp, old, retry);
2869
+ } else {
2870
+ lr_w (old, aligned_addr, acquire);
2871
+ andr (tmp, old, mask);
2872
+ bne (tmp, expected, fail);
2873
+
2874
+ andr (tmp, old, not_mask);
2875
+ orr (tmp, tmp, new_val);
2876
+ sc_w (tmp, tmp, aligned_addr, release);
2877
+ bnez (tmp, retry);
2878
+ }
2855
2879
2856
2880
if (result_as_bool) {
2857
2881
mv (result, 1 );
@@ -2891,14 +2915,28 @@ void MacroAssembler::weak_cmpxchg_narrow_value(Register addr, Register expected,
2891
2915
2892
2916
Label fail, done;
2893
2917
2894
- lr_w (old, aligned_addr, acquire);
2895
- andr (tmp, old, mask);
2896
- bne (tmp, expected, fail);
2918
+ if (UseZacas) {
2919
+ lw (old, aligned_addr);
2897
2920
2898
- andr (tmp, old, not_mask);
2899
- orr (tmp, tmp, new_val);
2900
- sc_w (tmp, tmp, aligned_addr, release);
2901
- bnez (tmp, fail);
2921
+ // if old & mask != expected
2922
+ andr (tmp, old, mask);
2923
+ bne (tmp, expected, fail);
2924
+
2925
+ andr (tmp, old, not_mask);
2926
+ orr (tmp, tmp, new_val);
2927
+
2928
+ atomic_cas (tmp, new_val, addr, operand_size::int32, acquire, release);
2929
+ bne (tmp, old, fail);
2930
+ } else {
2931
+ lr_w (old, aligned_addr, acquire);
2932
+ andr (tmp, old, mask);
2933
+ bne (tmp, expected, fail);
2934
+
2935
+ andr (tmp, old, not_mask);
2936
+ orr (tmp, tmp, new_val);
2937
+ sc_w (tmp, tmp, aligned_addr, release);
2938
+ bnez (tmp, fail);
2939
+ }
2902
2940
2903
2941
// Success
2904
2942
mv (result, 1 );
@@ -2921,6 +2959,19 @@ void MacroAssembler::cmpxchg(Register addr, Register expected,
2921
2959
assert_different_registers (expected, t0);
2922
2960
assert_different_registers (new_val, t0);
2923
2961
2962
+ if (UseZacas) {
2963
+ if (result_as_bool) {
2964
+ mv (t0, expected);
2965
+ atomic_cas (t0, new_val, addr, size, acquire, release);
2966
+ xorr (t0, t0, expected);
2967
+ seqz (result, t0);
2968
+ } else {
2969
+ mv (result, expected);
2970
+ atomic_cas (result, new_val, addr, size, acquire, release);
2971
+ }
2972
+ return ;
2973
+ }
2974
+
2924
2975
Label retry_load, done, ne_done;
2925
2976
bind (retry_load);
2926
2977
load_reserved (t0, addr, size, acquire);
@@ -2952,6 +3003,11 @@ void MacroAssembler::cmpxchg_weak(Register addr, Register expected,
2952
3003
enum operand_size size,
2953
3004
Assembler::Aqrl acquire, Assembler::Aqrl release,
2954
3005
Register result) {
3006
+ if (UseZacas) {
3007
+ cmpxchg (addr, expected, new_val, size, acquire, release, result, true );
3008
+ return ;
3009
+ }
3010
+
2955
3011
assert_different_registers (addr, t0);
2956
3012
assert_different_registers (expected, t0);
2957
3013
assert_different_registers (new_val, t0);
@@ -3018,6 +3074,89 @@ ATOMIC_XCHGU(xchgalwu, xchgalw)
3018
3074
3019
3075
#undef ATOMIC_XCHGU
3020
3076
3077
+ #define ATOMIC_CAS (OP, AOP, ACQUIRE, RELEASE ) \
3078
+ void MacroAssembler::atomic_##OP(Register prev, Register newv, Register addr) { \
3079
+ assert (UseZacas, " invariant" ); \
3080
+ prev = prev->is_valid () ? prev : zr; \
3081
+ AOP (prev, addr, newv, (Assembler::Aqrl)(ACQUIRE | RELEASE)); \
3082
+ return ; \
3083
+ }
3084
+
3085
+ ATOMIC_CAS (cas, amocas_d, Assembler::relaxed, Assembler::relaxed)
3086
+ ATOMIC_CAS(casw, amocas_w, Assembler::relaxed, Assembler::relaxed)
3087
+ ATOMIC_CAS(casl, amocas_d, Assembler::relaxed, Assembler::rl)
3088
+ ATOMIC_CAS(caslw, amocas_w, Assembler::relaxed, Assembler::rl)
3089
+ ATOMIC_CAS(casal, amocas_d, Assembler::aq, Assembler::rl)
3090
+ ATOMIC_CAS(casalw, amocas_w, Assembler::aq, Assembler::rl)
3091
+
3092
+ #undef ATOMIC_CAS
3093
+
3094
+ #define ATOMIC_CASU (OP1, OP2 ) \
3095
+ void MacroAssembler::atomic_##OP1(Register prev, Register newv, Register addr) { \
3096
+ atomic_##OP2 (prev, newv, addr); \
3097
+ zero_extend (prev, prev, 32 ); \
3098
+ return ; \
3099
+ }
3100
+
3101
+ ATOMIC_CASU (caswu, casw)
3102
+ ATOMIC_CASU(caslwu, caslw)
3103
+ ATOMIC_CASU(casalwu, casalw)
3104
+
3105
+ #undef ATOMIC_CASU
3106
+
3107
+ void MacroAssembler::atomic_cas (
3108
+ Register prev, Register newv, Register addr, enum operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release) {
3109
+ switch (size) {
3110
+ case int64:
3111
+ switch ((Assembler::Aqrl)(acquire | release)) {
3112
+ case Assembler::relaxed:
3113
+ atomic_cas (prev, newv, addr);
3114
+ break ;
3115
+ case Assembler::rl:
3116
+ atomic_casl (prev, newv, addr);
3117
+ break ;
3118
+ case Assembler::aqrl:
3119
+ atomic_casal (prev, newv, addr);
3120
+ break ;
3121
+ default :
3122
+ ShouldNotReachHere ();
3123
+ }
3124
+ break ;
3125
+ case int32:
3126
+ switch ((Assembler::Aqrl)(acquire | release)) {
3127
+ case Assembler::relaxed:
3128
+ atomic_casw (prev, newv, addr);
3129
+ break ;
3130
+ case Assembler::rl:
3131
+ atomic_caslw (prev, newv, addr);
3132
+ break ;
3133
+ case Assembler::aqrl:
3134
+ atomic_casalw (prev, newv, addr);
3135
+ break ;
3136
+ default :
3137
+ ShouldNotReachHere ();
3138
+ }
3139
+ break ;
3140
+ case uint32:
3141
+ switch ((Assembler::Aqrl)(acquire | release)) {
3142
+ case Assembler::relaxed:
3143
+ atomic_caswu (prev, newv, addr);
3144
+ break ;
3145
+ case Assembler::rl:
3146
+ atomic_caslwu (prev, newv, addr);
3147
+ break ;
3148
+ case Assembler::aqrl:
3149
+ atomic_casalwu (prev, newv, addr);
3150
+ break ;
3151
+ default :
3152
+ ShouldNotReachHere ();
3153
+ }
3154
+ break ;
3155
+ default :
3156
+ ShouldNotReachHere ();
3157
+ }
3158
+ }
3159
+
3021
3160
void MacroAssembler::far_jump (const Address &entry, Register tmp) {
3022
3161
assert (ReservedCodeCacheSize < 4 *G, " branch out of range" );
3023
3162
assert (CodeCache::find_blob (entry.target ()) != nullptr ,
0 commit comments