56
57 //------------
58 // Atomic::add
59 //------------
60 // These methods force the value in memory to be augmented by the passed increment.
61 // Both, memory value and increment, are treated as 32bit signed binary integers.
62 // No overflow exceptions are recognized, and the condition code does not hold
63 // information about the value in memory.
64 //
65 // The value in memory is updated by using a compare-and-swap instruction. The
66 // instruction is retried as often as required.
67 //
68 // The return value of the method is the value that was successfully stored. At the
69 // time the caller receives back control, the value in memory may have changed already.
70
71 template<size_t byte_size>
72 struct Atomic::PlatformAdd
73 : Atomic::AddAndFetch<Atomic::PlatformAdd<byte_size> >
74 {
75 template<typename I, typename D>
76 D add_and_fetch(I add_value, D volatile* dest) const;
77 };
78
79 template<>
80 template<typename I, typename D>
81 inline D Atomic::PlatformAdd<4>::add_and_fetch(I inc, D volatile* dest) const {
82 STATIC_ASSERT(4 == sizeof(I));
83 STATIC_ASSERT(4 == sizeof(D));
84
85 D old, upd;
86
87 if (VM_Version::has_LoadAndALUAtomicV1()) {
88 __asm__ __volatile__ (
89 " LGFR 0,%[inc] \n\t" // save increment
90 " LA 3,%[mem] \n\t" // force data address into ARG2
91 // " LAA %[upd],%[inc],%[mem] \n\t" // increment and get old value
92 // " LAA 2,0,0(3) \n\t" // actually coded instruction
93 " .byte 0xeb \n\t" // LAA main opcode
94 " .byte 0x20 \n\t" // R1,R3
95 " .byte 0x30 \n\t" // R2,disp1
96 " .byte 0x00 \n\t" // disp2,disp3
97 " .byte 0x00 \n\t" // disp4,disp5
98 " .byte 0xf8 \n\t" // LAA minor opcode
99 " AR 2,0 \n\t" // calc new value in register
100 " LR %[upd],2 \n\t" // move to result register
101 //---< outputs >---
102 : [upd] "=&d" (upd) // write-only, updated counter value
103 , [mem] "+Q" (*dest) // read/write, memory to be updated atomically
104 //---< inputs >---
105 : [inc] "a" (inc) // read-only.
106 //---< clobbered >---
107 : "cc", "r0", "r2", "r3", "memory"
108 );
109 } else {
110 __asm__ __volatile__ (
111 " LLGF %[old],%[mem] \n\t" // get old value
112 "0: LA %[upd],0(%[inc],%[old]) \n\t" // calc result
113 " CS %[old],%[upd],%[mem] \n\t" // try to xchg res with mem
114 " JNE 0b \n\t" // no success? -> retry
115 //---< outputs >---
116 : [old] "=&a" (old) // write-only, old counter value
117 , [upd] "=&d" (upd) // write-only, updated counter value
118 , [mem] "+Q" (*dest) // read/write, memory to be updated atomically
119 //---< inputs >---
120 : [inc] "a" (inc) // read-only.
121 //---< clobbered >---
122 : "cc", "memory"
123 );
124 }
125
126 return upd;
127 }
128
129
130 template<>
131 template<typename I, typename D>
132 inline D Atomic::PlatformAdd<8>::add_and_fetch(I inc, D volatile* dest) const {
133 STATIC_ASSERT(8 == sizeof(I));
134 STATIC_ASSERT(8 == sizeof(D));
135
136 D old, upd;
137
138 if (VM_Version::has_LoadAndALUAtomicV1()) {
139 __asm__ __volatile__ (
140 " LGR 0,%[inc] \n\t" // save increment
141 " LA 3,%[mem] \n\t" // force data address into ARG2
142 // " LAAG %[upd],%[inc],%[mem] \n\t" // increment and get old value
143 // " LAAG 2,0,0(3) \n\t" // actually coded instruction
144 " .byte 0xeb \n\t" // LAA main opcode
145 " .byte 0x20 \n\t" // R1,R3
146 " .byte 0x30 \n\t" // R2,disp1
147 " .byte 0x00 \n\t" // disp2,disp3
148 " .byte 0x00 \n\t" // disp4,disp5
149 " .byte 0xe8 \n\t" // LAA minor opcode
150 " AGR 2,0 \n\t" // calc new value in register
151 " LGR %[upd],2 \n\t" // move to result register
152 //---< outputs >---
153 : [upd] "=&d" (upd) // write-only, updated counter value
154 , [mem] "+Q" (*dest) // read/write, memory to be updated atomically
155 //---< inputs >---
156 : [inc] "a" (inc) // read-only.
157 //---< clobbered >---
158 : "cc", "r0", "r2", "r3", "memory"
159 );
160 } else {
161 __asm__ __volatile__ (
162 " LG %[old],%[mem] \n\t" // get old value
163 "0: LA %[upd],0(%[inc],%[old]) \n\t" // calc result
164 " CSG %[old],%[upd],%[mem] \n\t" // try to xchg res with mem
165 " JNE 0b \n\t" // no success? -> retry
166 //---< outputs >---
167 : [old] "=&a" (old) // write-only, old counter value
168 , [upd] "=&d" (upd) // write-only, updated counter value
169 , [mem] "+Q" (*dest) // read/write, memory to be updated atomically
170 //---< inputs >---
171 : [inc] "a" (inc) // read-only.
172 //---< clobbered >---
173 : "cc", "memory"
174 );
175 }
176
177 return upd;
178 }
179
|
56
57 //------------
58 // Atomic::add
59 //------------
60 // These methods force the value in memory to be augmented by the passed increment.
61 // Both, memory value and increment, are treated as 32bit signed binary integers.
62 // No overflow exceptions are recognized, and the condition code does not hold
63 // information about the value in memory.
64 //
65 // The value in memory is updated by using a compare-and-swap instruction. The
66 // instruction is retried as often as required.
67 //
68 // The return value of the method is the value that was successfully stored. At the
69 // time the caller receives back control, the value in memory may have changed already.
70
71 template<size_t byte_size>
72 struct Atomic::PlatformAdd
73 : Atomic::AddAndFetch<Atomic::PlatformAdd<byte_size> >
74 {
75 template<typename I, typename D>
76 D add_and_fetch(I add_value, D volatile* dest, cmpxchg_memory_order order) const;
77 };
78
79 template<>
80 template<typename I, typename D>
81 inline D Atomic::PlatformAdd<4>::add_and_fetch(I inc, D volatile* dest,
82 cmpxchg_memory_order order) const {
83 STATIC_ASSERT(4 == sizeof(I));
84 STATIC_ASSERT(4 == sizeof(D));
85
86 D old, upd;
87
88 if (VM_Version::has_LoadAndALUAtomicV1()) {
89 __asm__ __volatile__ (
90 " LGFR 0,%[inc] \n\t" // save increment
91 " LA 3,%[mem] \n\t" // force data address into ARG2
92 // " LAA %[upd],%[inc],%[mem] \n\t" // increment and get old value
93 // " LAA 2,0,0(3) \n\t" // actually coded instruction
94 " .byte 0xeb \n\t" // LAA main opcode
95 " .byte 0x20 \n\t" // R1,R3
96 " .byte 0x30 \n\t" // R2,disp1
97 " .byte 0x00 \n\t" // disp2,disp3
98 " .byte 0x00 \n\t" // disp4,disp5
99 " .byte 0xf8 \n\t" // LAA minor opcode
100 " AR 2,0 \n\t" // calc new value in register
101 " LR %[upd],2 \n\t" // move to result register
102 //---< outputs >---
103 : [upd] "=&d" (upd) // write-only, updated counter value
104 , [mem] "+Q" (*dest) // read/write, memory to be updated atomically
105 //---< inputs >---
106 : [inc] "a" (inc) // read-only.
107 //---< clobbered >---
108 : "cc", "r0", "r2", "r3", "memory"
109 );
110 if (order == memory_order_conservative) {
111 __asm__ __volatile__ ("bcr 14, 0" : : : "memory");
112 }
113 } else {
114 __asm__ __volatile__ (
115 " LLGF %[old],%[mem] \n\t" // get old value
116 "0: LA %[upd],0(%[inc],%[old]) \n\t" // calc result
117 " CS %[old],%[upd],%[mem] \n\t" // try to xchg res with mem
118 " JNE 0b \n\t" // no success? -> retry
119 //---< outputs >---
120 : [old] "=&a" (old) // write-only, old counter value
121 , [upd] "=&d" (upd) // write-only, updated counter value
122 , [mem] "+Q" (*dest) // read/write, memory to be updated atomically
123 //---< inputs >---
124 : [inc] "a" (inc) // read-only.
125 //---< clobbered >---
126 : "cc", "memory"
127 );
128 }
129
130 return upd;
131 }
132
133
134 template<>
135 template<typename I, typename D>
136 inline D Atomic::PlatformAdd<8>::add_and_fetch(I inc, D volatile* dest,
137 cmpxchg_memory_order order) const {
138 STATIC_ASSERT(8 == sizeof(I));
139 STATIC_ASSERT(8 == sizeof(D));
140
141 D old, upd;
142
143 if (VM_Version::has_LoadAndALUAtomicV1()) {
144 __asm__ __volatile__ (
145 " LGR 0,%[inc] \n\t" // save increment
146 " LA 3,%[mem] \n\t" // force data address into ARG2
147 // " LAAG %[upd],%[inc],%[mem] \n\t" // increment and get old value
148 // " LAAG 2,0,0(3) \n\t" // actually coded instruction
149 " .byte 0xeb \n\t" // LAA main opcode
150 " .byte 0x20 \n\t" // R1,R3
151 " .byte 0x30 \n\t" // R2,disp1
152 " .byte 0x00 \n\t" // disp2,disp3
153 " .byte 0x00 \n\t" // disp4,disp5
154 " .byte 0xe8 \n\t" // LAA minor opcode
155 " AGR 2,0 \n\t" // calc new value in register
156 " LGR %[upd],2 \n\t" // move to result register
157 //---< outputs >---
158 : [upd] "=&d" (upd) // write-only, updated counter value
159 , [mem] "+Q" (*dest) // read/write, memory to be updated atomically
160 //---< inputs >---
161 : [inc] "a" (inc) // read-only.
162 //---< clobbered >---
163 : "cc", "r0", "r2", "r3", "memory"
164 );
165 if (order == memory_order_conservative) {
166 __asm__ __volatile__ ("bcr 14, 0" : : : "memory");
167 }
168 } else {
169 __asm__ __volatile__ (
170 " LG %[old],%[mem] \n\t" // get old value
171 "0: LA %[upd],0(%[inc],%[old]) \n\t" // calc result
172 " CSG %[old],%[upd],%[mem] \n\t" // try to xchg res with mem
173 " JNE 0b \n\t" // no success? -> retry
174 //---< outputs >---
175 : [old] "=&a" (old) // write-only, old counter value
176 , [upd] "=&d" (upd) // write-only, updated counter value
177 , [mem] "+Q" (*dest) // read/write, memory to be updated atomically
178 //---< inputs >---
179 : [inc] "a" (inc) // read-only.
180 //---< clobbered >---
181 : "cc", "memory"
182 );
183 }
184
185 return upd;
186 }
187
|