1 /*
2 * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2012, 2026 SAP SE. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #include "asm/macroAssembler.inline.hpp"
27 #include "c1/c1_CodeStubs.hpp"
28 #include "c1/c1_FrameMap.hpp"
29 #include "c1/c1_LIRAssembler.hpp"
30 #include "c1/c1_MacroAssembler.hpp"
31 #include "c1/c1_Runtime1.hpp"
32 #include "classfile/javaClasses.hpp"
33 #include "nativeInst_ppc.hpp"
34 #include "runtime/sharedRuntime.hpp"
35 #include "utilities/macros.hpp"
36 #include "vmreg_ppc.inline.hpp"
37
38 #define __ ce->masm()->
39
40 void C1SafepointPollStub::emit_code(LIR_Assembler* ce) {
41 if (UseSIGTRAP) {
42 DEBUG_ONLY( __ should_not_reach_here("C1SafepointPollStub::emit_code"); )
43 } else {
44 __ bind(_entry);
45 __ jump_to_polling_page_return_handler_blob(safepoint_offset());
46 }
47 }
48
49 void RangeCheckStub::emit_code(LIR_Assembler* ce) {
50 __ bind(_entry);
51
52 if (_info->deoptimize_on_exception()) {
53 address a = Runtime1::entry_for(StubId::c1_predicate_failed_trap_id);
54 //__ load_const_optimized(R0, a);
55 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
56 __ mtctr(R0);
57 __ bctrl();
58 ce->add_call_info_here(_info);
59 ce->verify_oop_map(_info);
60 DEBUG_ONLY(__ illtrap());
61 return;
62 }
63
64 address stub = _throw_index_out_of_bounds_exception ? Runtime1::entry_for(StubId::c1_throw_index_exception_id)
65 : Runtime1::entry_for(StubId::c1_throw_range_check_failed_id);
66 //__ load_const_optimized(R0, stub);
67 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
68 __ mtctr(R0);
69
70 Register index = R0;
71 if (_index->is_register()) {
72 __ extsw(index, _index->as_register());
73 } else {
74 __ load_const_optimized(index, _index->as_jint());
75 }
76 if (_array) {
77 __ std(_array->as_pointer_register(), -8, R1_SP);
78 }
79 __ std(index, -16, R1_SP);
80
81 __ bctrl();
82 ce->add_call_info_here(_info);
83 ce->verify_oop_map(_info);
84 DEBUG_ONLY(__ illtrap());
85 }
86
87
88 PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) {
89 _info = new CodeEmitInfo(info);
90 }
91
92 void PredicateFailedStub::emit_code(LIR_Assembler* ce) {
93 __ bind(_entry);
94 address a = Runtime1::entry_for(StubId::c1_predicate_failed_trap_id);
95 //__ load_const_optimized(R0, a);
96 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
97 __ mtctr(R0);
98 __ bctrl();
99 ce->add_call_info_here(_info);
100 ce->verify_oop_map(_info);
101 DEBUG_ONLY(__ illtrap());
102 }
103
104
105 void CounterOverflowStub::emit_code(LIR_Assembler* ce) {
106 __ bind(_entry);
107
108 // Parameter 1: bci
109 __ load_const_optimized(R0, _bci);
110 __ std(R0, -16, R1_SP);
111
112 // Parameter 2: Method*
113 Metadata *m = _method->as_constant_ptr()->as_metadata();
114 AddressLiteral md = __ constant_metadata_address(m); // Notify OOP recorder (don't need the relocation).
115 __ load_const_optimized(R0, md.value());
116 __ std(R0, -8, R1_SP);
117
118 address a = Runtime1::entry_for(StubId::c1_counter_overflow_id);
119 //__ load_const_optimized(R0, a);
120 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
121 __ mtctr(R0);
122 __ bctrl();
123 ce->add_call_info_here(_info);
124 ce->verify_oop_map(_info);
125
126 __ b(_continuation);
127 }
128
129
130 void DivByZeroStub::emit_code(LIR_Assembler* ce) {
131 if (_offset != -1) {
132 ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
133 }
134 __ bind(_entry);
135 address stub = Runtime1::entry_for(StubId::c1_throw_div0_exception_id);
136 //__ load_const_optimized(R0, stub);
137 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
138 __ mtctr(R0);
139 __ bctrl();
140 ce->add_call_info_here(_info);
141 ce->verify_oop_map(_info);
142 DEBUG_ONLY(__ illtrap());
143 }
144
145
146 // Implementation of LoadFlattenedArrayStub
147
148 LoadFlattenedArrayStub::LoadFlattenedArrayStub(LIR_Opr array, LIR_Opr index, LIR_Opr result, CodeEmitInfo* info) {
149 _array = array;
150 _index = index;
151 _result = result;
152 _scratch_reg = FrameMap::R3_oop_opr;
153 _info = new CodeEmitInfo(info);
154 }
155
156 void LoadFlattenedArrayStub::emit_code(LIR_Assembler* ce) {
157 __ bind(_entry);
158 // Pass arguments on stack.
159 __ std(_array->as_register(), -16, R1_SP);
160 __ std(_index->as_register(), -8, R1_SP);
161 address stub = Runtime1::entry_for(StubId::c1_load_flat_array_id);
162 //__ load_const_optimized(R0, stub);
163 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
164 __ mtctr(R0);
165 __ bctrl();
166 ce->add_call_info_here(_info);
167 ce->verify_oop_map(_info);
168 __ mr_if_needed(_result->as_register(), R3_RET);
169 __ b(_continuation);
170 }
171
172
173 // Implementation of StoreFlattenedArrayStub
174
175 StoreFlattenedArrayStub::StoreFlattenedArrayStub(LIR_Opr array, LIR_Opr index, LIR_Opr value, CodeEmitInfo* info) {
176 _array = array;
177 _index = index;
178 _value = value;
179 _scratch_reg = LIR_OprFact::illegalOpr;
180 _info = new CodeEmitInfo(info);
181 }
182
183 void StoreFlattenedArrayStub::emit_code(LIR_Assembler* ce) {
184 __ bind(_entry);
185 // Pass arguments on stack.
186 __ std(_array->as_register(), -24, R1_SP);
187 __ std(_index->as_register(), -16, R1_SP);
188 __ std(_value->as_register(), -8, R1_SP);
189 address stub = Runtime1::entry_for(StubId::c1_store_flat_array_id);
190 //__ load_const_optimized(R0, stub);
191 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
192 __ mtctr(R0);
193 __ bctrl();
194 ce->add_call_info_here(_info);
195 ce->verify_oop_map(_info);
196 __ b(_continuation);
197 }
198
199
200 // Implementation of SubstitutabilityCheckStub
201 SubstitutabilityCheckStub::SubstitutabilityCheckStub(LIR_Opr left, LIR_Opr right, CodeEmitInfo* info) {
202 _left = left;
203 _right = right;
204 _scratch_reg = FrameMap::R3_oop_opr;
205 _info = new CodeEmitInfo(info);
206 }
207
208 void SubstitutabilityCheckStub::emit_code(LIR_Assembler* ce) {
209 __ bind(_entry);
210 // Pass arguments on stack.
211 __ std(_left->as_register(), -16, R1_SP);
212 __ std(_right->as_register(), -8, R1_SP);
213 address stub = Runtime1::entry_for(StubId::c1_substitutability_check_id);
214 //__ load_const_optimized(R0, stub);
215 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
216 __ mtctr(R0);
217 __ bctrl();
218 ce->add_call_info_here(_info);
219 ce->verify_oop_map(_info);
220 // Result is in R3_RET (_scratch_reg)
221 __ b(_continuation);
222 }
223
224
225 void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) {
226 address a;
227 if (_info->deoptimize_on_exception()) {
228 // Deoptimize, do not throw the exception, because it is probably wrong to do it here.
229 a = Runtime1::entry_for(StubId::c1_predicate_failed_trap_id);
230 } else {
231 a = Runtime1::entry_for(StubId::c1_throw_null_pointer_exception_id);
232 }
233
234 if (ImplicitNullChecks || TrapBasedNullChecks) {
235 ce->compilation()->implicit_exception_table()->append(_offset, __ offset());
236 }
237 __ bind(_entry);
238 //__ load_const_optimized(R0, a);
239 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a));
240 __ mtctr(R0);
241 __ bctrl();
242 ce->add_call_info_here(_info);
243 ce->verify_oop_map(_info);
244 DEBUG_ONLY(__ illtrap());
245 }
246
247
248 // Implementation of SimpleExceptionStub
249 void SimpleExceptionStub::emit_code(LIR_Assembler* ce) {
250 __ bind(_entry);
251 address stub = Runtime1::entry_for(_stub);
252 //__ load_const_optimized(R0, stub);
253 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
254 if (_obj->is_valid()) { __ mr_if_needed(/*tmp1 in do_CheckCast*/ R4_ARG2, _obj->as_register()); }
255 __ mtctr(R0);
256 __ bctrl();
257 ce->add_call_info_here(_info);
258 DEBUG_ONLY( __ illtrap(); )
259 }
260
261
262 // Implementation of NewInstanceStub
263 NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, StubId stub_id) {
264 _result = result;
265 _klass = klass;
266 _klass_reg = klass_reg;
267 _info = new CodeEmitInfo(info);
268 assert(stub_id == StubId::c1_new_instance_id ||
269 stub_id == StubId::c1_fast_new_instance_id ||
270 stub_id == StubId::c1_fast_new_instance_init_check_id,
271 "need new_instance id");
272 _stub_id = stub_id;
273 }
274
275 void NewInstanceStub::emit_code(LIR_Assembler* ce) {
276 __ bind(_entry);
277
278 address entry = Runtime1::entry_for(_stub_id);
279 //__ load_const_optimized(R0, entry);
280 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry));
281 __ mtctr(R0);
282 __ bctrl();
283 ce->add_call_info_here(_info);
284 ce->verify_oop_map(_info);
285 __ b(_continuation);
286 }
287
288
289 // Implementation of NewTypeArrayStub
290 NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
291 _klass_reg = klass_reg;
292 _length = length;
293 _result = result;
294 _info = new CodeEmitInfo(info);
295 }
296
297 void NewTypeArrayStub::emit_code(LIR_Assembler* ce) {
298 __ bind(_entry);
299
300 address entry = Runtime1::entry_for(StubId::c1_new_type_array_id);
301 //__ load_const_optimized(R0, entry);
302 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry));
303 __ mr_if_needed(/*op->tmp1()->as_register()*/ R5_ARG3, _length->as_register()); // already sign-extended
304 __ mtctr(R0);
305 __ bctrl();
306 ce->add_call_info_here(_info);
307 ce->verify_oop_map(_info);
308 __ b(_continuation);
309 }
310
311
312 // Implementation of NewObjectArrayStub
313 NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result,
314 CodeEmitInfo* info, bool is_null_free) {
315 _klass_reg = klass_reg;
316 _length = length;
317 _result = result;
318 _info = new CodeEmitInfo(info);
319 _is_null_free = is_null_free;
320 }
321
322 void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
323 __ bind(_entry);
324
325 address entry = _is_null_free ? Runtime1::entry_for(StubId::c1_new_null_free_array_id)
326 : Runtime1::entry_for(StubId::c1_new_object_array_id);
327 //__ load_const_optimized(R0, entry);
328 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry));
329 __ mr_if_needed(/*op->tmp1()->as_register()*/ R5_ARG3, _length->as_register()); // already sign-extended
330 __ mtctr(R0);
331 __ bctrl();
332 ce->add_call_info_here(_info);
333 ce->verify_oop_map(_info);
334 __ b(_continuation);
335 }
336
337 void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
338 __ bind(_entry);
339 if (_throw_ie_stub != nullptr) {
340 // When we come here, _obj_reg has already been checked to be non-null.
341 const int is_value_mask = markWord::inline_type_pattern;
342 __ ld(R0, oopDesc::mark_offset_in_bytes(), _obj_reg->as_register());
343 __ andi(R0, R0, is_value_mask);
344 __ cmpdi(CR0, R0, is_value_mask);
345 __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *_throw_ie_stub->entry());
346 }
347
348 address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? StubId::c1_monitorenter_id : StubId::c1_monitorenter_nofpu_id);
349 //__ load_const_optimized(R0, stub);
350 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
351 __ mr_if_needed(/*scratch_opr()->as_register()*/ R4_ARG2, _obj_reg->as_register());
352 assert(_lock_reg->as_register() == R5_ARG3, "");
353 __ mtctr(R0);
354 __ bctrl();
355 ce->add_call_info_here(_info);
356 ce->verify_oop_map(_info);
357 __ b(_continuation);
358 }
359
360 void MonitorExitStub::emit_code(LIR_Assembler* ce) {
361 __ bind(_entry);
362
363 // lock_reg was destroyed by fast unlocking attempt => recompute it
364 ce->monitor_address(_monitor_ix, _lock_reg);
365
366 address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? StubId::c1_monitorexit_id : StubId::c1_monitorexit_nofpu_id);
367 //__ load_const_optimized(R0, stub);
368 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
369 assert(_lock_reg->as_register() == R4_ARG2, "");
370 __ mtctr(R0);
371 __ bctrl();
372 __ b(_continuation);
373 }
374
375
376 // Implementation of patching:
377 // - Copy the code at given offset to an inlined buffer (first the bytes, then the number of bytes).
378 // - Replace original code with a call to the stub.
379 // At Runtime:
380 // - call to stub, jump to runtime
381 // - in runtime: preserve all registers (especially objects, i.e., source and destination object)
382 // - in runtime: after initializing class, restore original code, reexecute instruction
383
384 int PatchingStub::_patch_info_offset = -(5 * BytesPerInstWord);
385
386 void PatchingStub::align_patch_site(MacroAssembler* ) {
387 // Patch sites on ppc are always properly aligned.
388 }
389
390 #ifdef ASSERT
391 inline void compare_with_patch_site(address template_start, address pc_start, int bytes_to_copy) {
392 address start = template_start;
393 for (int i = 0; i < bytes_to_copy; i++) {
394 address ptr = (address)(pc_start + i);
395 int a_byte = (*ptr) & 0xFF;
396 assert(a_byte == *start++, "should be the same code");
397 }
398 }
399 #endif
400
401 void PatchingStub::emit_code(LIR_Assembler* ce) {
402 // copy original code here
403 assert(NativeGeneralJump::instruction_size <= _bytes_to_copy && _bytes_to_copy <= 0xFF,
404 "not enough room for call, need %d", _bytes_to_copy);
405 assert((_bytes_to_copy & 0x3) == 0, "must copy a multiple of four bytes");
406
407 Label call_patch;
408
409 int being_initialized_entry = __ offset();
410
411 if (_id == load_klass_id) {
412 // Produce a copy of the load klass instruction for use by the being initialized case.
413 AddressLiteral addrlit((address)nullptr, metadata_Relocation::spec(_index));
414 __ load_const(_obj, addrlit, R0);
415 DEBUG_ONLY( compare_with_patch_site(__ code_section()->start() + being_initialized_entry, _pc_start, _bytes_to_copy); )
416 } else if (_id == load_mirror_id || _id == load_appendix_id) {
417 // Produce a copy of the load mirror instruction for use by the being initialized case.
418 AddressLiteral addrlit((address)nullptr, oop_Relocation::spec(_index));
419 __ load_const(_obj, addrlit, R0);
420 DEBUG_ONLY( compare_with_patch_site(__ code_section()->start() + being_initialized_entry, _pc_start, _bytes_to_copy); )
421 } else {
422 // Make a copy of the code which is going to be patched.
423 for (int i = 0; i < _bytes_to_copy; i++) {
424 address ptr = (address)(_pc_start + i);
425 int a_byte = (*ptr) & 0xFF;
426 __ emit_int8 (a_byte);
427 }
428 }
429
430 address end_of_patch = __ pc();
431 int bytes_to_skip = 0;
432 if (_id == load_mirror_id) {
433 int offset = __ offset();
434 __ block_comment(" being_initialized check");
435
436 // Static field accesses have special semantics while the class
437 // initializer is being run so we emit a test which can be used to
438 // check that this code is being executed by the initializing
439 // thread.
440 assert(_obj != noreg, "must be a valid register");
441 assert(_index >= 0, "must have oop index");
442 __ mr(R0, _obj); // spill
443 __ ld(_obj, java_lang_Class::klass_offset(), _obj);
444 __ ld(_obj, in_bytes(InstanceKlass::init_thread_offset()), _obj);
445 __ cmpd(CR0, _obj, R16_thread);
446 __ mr(_obj, R0); // restore
447 __ bne(CR0, call_patch);
448
449 // Load_klass patches may execute the patched code before it's
450 // copied back into place so we need to jump back into the main
451 // code of the nmethod to continue execution.
452 __ b(_patch_site_continuation);
453
454 // Make sure this extra code gets skipped.
455 bytes_to_skip += __ offset() - offset;
456 }
457
458 // Now emit the patch record telling the runtime how to find the
459 // pieces of the patch. We only need 3 bytes but it has to be
460 // aligned as an instruction so emit 4 bytes.
461 int sizeof_patch_record = 4;
462 bytes_to_skip += sizeof_patch_record;
463
464 // Emit the offsets needed to find the code to patch.
465 int being_initialized_entry_offset = __ offset() - being_initialized_entry + sizeof_patch_record;
466
467 // Emit the patch record. We need to emit a full word, so emit an extra empty byte.
468 __ emit_int8(0);
469 __ emit_int8(being_initialized_entry_offset);
470 __ emit_int8(bytes_to_skip);
471 __ emit_int8(_bytes_to_copy);
472 address patch_info_pc = __ pc();
473 assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info");
474
475 address entry = __ pc();
476 NativeGeneralJump::insert_unconditional((address)_pc_start, entry);
477 address target = nullptr;
478 relocInfo::relocType reloc_type = relocInfo::none;
479 switch (_id) {
480 case access_field_id: target = Runtime1::entry_for(StubId::c1_access_field_patching_id); break;
481 case load_klass_id: target = Runtime1::entry_for(StubId::c1_load_klass_patching_id);
482 reloc_type = relocInfo::metadata_type; break;
483 case load_mirror_id: target = Runtime1::entry_for(StubId::c1_load_mirror_patching_id);
484 reloc_type = relocInfo::oop_type; break;
485 case load_appendix_id: target = Runtime1::entry_for(StubId::c1_load_appendix_patching_id);
486 reloc_type = relocInfo::oop_type; break;
487 default: ShouldNotReachHere();
488 }
489 __ bind(call_patch);
490
491 __ block_comment("patch entry point");
492 //__ load_const(R0, target); + mtctr + bctrl must have size -_patch_info_offset
493 __ load_const32(R0, MacroAssembler::offset_to_global_toc(target));
494 __ add(R0, R29_TOC, R0);
495 __ mtctr(R0);
496 __ bctrl();
497 assert(_patch_info_offset == (patch_info_pc - __ pc()), "must not change");
498 ce->add_call_info_here(_info);
499 __ b(_patch_site_entry);
500 if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) {
501 CodeSection* cs = __ code_section();
502 address pc = (address)_pc_start;
503 RelocIterator iter(cs, pc, pc + 1);
504 relocInfo::change_reloc_info_for_address(&iter, (address) pc, reloc_type, relocInfo::none);
505 }
506 }
507
508
509 void DeoptimizeStub::emit_code(LIR_Assembler* ce) {
510 __ bind(_entry);
511 address stub = Runtime1::entry_for(StubId::c1_deoptimize_id);
512 //__ load_const_optimized(R0, stub);
513 __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub));
514 __ mtctr(R0);
515
516 __ load_const_optimized(R0, _trap_request); // Pass trap request in R0.
517 __ bctrl();
518 ce->add_call_info_here(_info);
519 DEBUG_ONLY(__ illtrap());
520 }
521
522
523 void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
524 //---------------slow case: call to native-----------------
525 __ bind(_entry);
526 __ mr(R3_ARG1, src()->as_register());
527 __ extsw(R4_ARG2, src_pos()->as_register());
528 __ mr(R5_ARG3, dst()->as_register());
529 __ extsw(R6_ARG4, dst_pos()->as_register());
530 __ extsw(R7_ARG5, length()->as_register());
531
532 ce->emit_static_call_stub();
533 if (ce->compilation()->bailed_out()) {
534 return; // CodeCache is full
535 }
536
537 AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(),
538 relocInfo::static_call_type);
539 address call_pc = __ trampoline_call(resolve);
540 if (call_pc == nullptr) {
541 ce->bailout("const/stub overflow in call with trampoline");
542 return;
543 }
544 ce->add_call_info_here(info());
545 ce->verify_oop_map(info());
546
547 #ifndef PRODUCT
548 if (PrintC1Statistics) {
549 const address counter = (address)&Runtime1::_arraycopy_slowcase_cnt;
550 const Register tmp = R3, tmp2 = R4;
551 int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true);
552 __ lwz(tmp2, simm16_offs, tmp);
553 __ addi(tmp2, tmp2, 1);
554 __ stw(tmp2, simm16_offs, tmp);
555 }
556 #endif
557
558 __ b(_continuation);
559 }
560
561 #undef __