1 /*
2  * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
3  * Copyright (c) 2012, 2015 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 #ifndef CPU_PPC_MACROASSEMBLER_PPC_INLINE_HPP
27 #define CPU_PPC_MACROASSEMBLER_PPC_INLINE_HPP
28 
29 #include "asm/assembler.inline.hpp"
30 #include "asm/macroAssembler.hpp"
31 #include "asm/codeBuffer.hpp"
32 #include "code/codeCache.hpp"
33 #include "gc/shared/barrierSet.hpp"
34 #include "gc/shared/barrierSetAssembler.hpp"
35 #include "oops/accessDecorators.hpp"
36 #include "oops/compressedOops.hpp"
37 #include "runtime/safepointMechanism.hpp"
38 #include "utilities/powerOfTwo.hpp"
39 
is_ld_largeoffset(address a)40 inline bool MacroAssembler::is_ld_largeoffset(address a) {
41   const int inst1 = *(int *)a;
42   const int inst2 = *(int *)(a+4);
43   return (is_ld(inst1)) ||
44          (is_addis(inst1) && is_ld(inst2) && inv_ra_field(inst2) == inv_rt_field(inst1));
45 }
46 
get_ld_largeoffset_offset(address a)47 inline int MacroAssembler::get_ld_largeoffset_offset(address a) {
48   assert(MacroAssembler::is_ld_largeoffset(a), "must be ld with large offset");
49 
50   const int inst1 = *(int *)a;
51   if (is_ld(inst1)) {
52     return inv_d1_field(inst1);
53   } else {
54     const int inst2 = *(int *)(a+4);
55     return (inv_d1_field(inst1) << 16) + inv_d1_field(inst2);
56   }
57 }
58 
round_to(Register r,int modulus)59 inline void MacroAssembler::round_to(Register r, int modulus) {
60   assert(is_power_of_2((jlong)modulus), "must be power of 2");
61   addi(r, r, modulus-1);
62   clrrdi(r, r, log2_long((jlong)modulus));
63 }
64 
65 // Move register if destination register and target register are different.
mr_if_needed(Register rd,Register rs)66 inline void MacroAssembler::mr_if_needed(Register rd, Register rs) {
67   if (rs != rd) mr(rd, rs);
68 }
fmr_if_needed(FloatRegister rd,FloatRegister rs)69 inline void MacroAssembler::fmr_if_needed(FloatRegister rd, FloatRegister rs) {
70   if (rs != rd) fmr(rd, rs);
71 }
endgroup_if_needed(bool needed)72 inline void MacroAssembler::endgroup_if_needed(bool needed) {
73   if (needed) {
74     endgroup();
75   }
76 }
77 
membar(int bits)78 inline void MacroAssembler::membar(int bits) {
79   // Comment: Usage of elemental_membar(bits) is not recommended for Power 8.
80   // If elemental_membar(bits) is used, disable optimization of acquire-release
81   // (Matcher::post_membar_release where we use PPC64_ONLY(xop == Op_MemBarRelease ||))!
82   if (bits & StoreLoad) { sync(); }
83   else if (bits) { lwsync(); }
84 }
release()85 inline void MacroAssembler::release() { membar(LoadStore | StoreStore); }
acquire()86 inline void MacroAssembler::acquire() { membar(LoadLoad | LoadStore); }
fence()87 inline void MacroAssembler::fence()   { membar(LoadLoad | LoadStore | StoreLoad | StoreStore); }
88 
89 // Address of the global TOC.
global_toc()90 inline address MacroAssembler::global_toc() {
91   return CodeCache::low_bound();
92 }
93 
94 // Offset of given address to the global TOC.
offset_to_global_toc(const address addr)95 inline int MacroAssembler::offset_to_global_toc(const address addr) {
96   intptr_t offset = (intptr_t)addr - (intptr_t)MacroAssembler::global_toc();
97   assert(Assembler::is_uimm((long)offset, 31), "must be in range");
98   return (int)offset;
99 }
100 
101 // Address of current method's TOC.
method_toc()102 inline address MacroAssembler::method_toc() {
103   return code()->consts()->start();
104 }
105 
106 // Offset of given address to current method's TOC.
offset_to_method_toc(address addr)107 inline int MacroAssembler::offset_to_method_toc(address addr) {
108   intptr_t offset = (intptr_t)addr - (intptr_t)method_toc();
109   assert(Assembler::is_uimm((long)offset, 31), "must be in range");
110   return (int)offset;
111 }
112 
is_calculate_address_from_global_toc_at(address a,address bound)113 inline bool MacroAssembler::is_calculate_address_from_global_toc_at(address a, address bound) {
114   const address inst2_addr = a;
115   const int inst2 = *(int *) a;
116 
117   // The relocation points to the second instruction, the addi.
118   if (!is_addi(inst2)) return false;
119 
120   // The addi reads and writes the same register dst.
121   const int dst = inv_rt_field(inst2);
122   if (inv_ra_field(inst2) != dst) return false;
123 
124   // Now, find the preceding addis which writes to dst.
125   int inst1 = 0;
126   address inst1_addr = inst2_addr - BytesPerInstWord;
127   while (inst1_addr >= bound) {
128     inst1 = *(int *) inst1_addr;
129     if (is_addis(inst1) && inv_rt_field(inst1) == dst) {
130       // stop, found the addis which writes dst
131       break;
132     }
133     inst1_addr -= BytesPerInstWord;
134   }
135 
136   if (!(inst1 == 0 || inv_ra_field(inst1) == 29 /* R29 */)) return false;
137   return is_addis(inst1);
138 }
139 
140 #ifdef _LP64
141 // Detect narrow oop constants.
is_set_narrow_oop(address a,address bound)142 inline bool MacroAssembler::is_set_narrow_oop(address a, address bound) {
143   const address inst2_addr = a;
144   const int inst2 = *(int *)a;
145   // The relocation points to the second instruction, the ori.
146   if (!is_ori(inst2)) return false;
147 
148   // The ori reads and writes the same register dst.
149   const int dst = inv_rta_field(inst2);
150   if (inv_rs_field(inst2) != dst) return false;
151 
152   // Now, find the preceding addis which writes to dst.
153   int inst1 = 0;
154   address inst1_addr = inst2_addr - BytesPerInstWord;
155   while (inst1_addr >= bound) {
156     inst1 = *(int *) inst1_addr;
157     if (is_lis(inst1) && inv_rs_field(inst1) == dst) return true;
158     inst1_addr -= BytesPerInstWord;
159   }
160   return false;
161 }
162 #endif
163 
164 
is_load_const_at(address a)165 inline bool MacroAssembler::is_load_const_at(address a) {
166   const int* p_inst = (int *) a;
167   bool b = is_lis(*p_inst++);
168   if (is_ori(*p_inst)) {
169     p_inst++;
170     b = b && is_rldicr(*p_inst++); // TODO: could be made more precise: `sldi'!
171     b = b && is_oris(*p_inst++);
172     b = b && is_ori(*p_inst);
173   } else if (is_lis(*p_inst)) {
174     p_inst++;
175     b = b && is_ori(*p_inst++);
176     b = b && is_ori(*p_inst);
177     // TODO: could enhance reliability by adding is_insrdi
178   } else return false;
179   return b;
180 }
181 
set_oop_constant(jobject obj,Register d)182 inline void MacroAssembler::set_oop_constant(jobject obj, Register d) {
183   set_oop(constant_oop_address(obj), d);
184 }
185 
set_oop(AddressLiteral obj_addr,Register d)186 inline void MacroAssembler::set_oop(AddressLiteral obj_addr, Register d) {
187   assert(obj_addr.rspec().type() == relocInfo::oop_type, "must be an oop reloc");
188   load_const(d, obj_addr);
189 }
190 
pd_patch_instruction(address branch,address target,const char * file,int line)191 inline void MacroAssembler::pd_patch_instruction(address branch, address target, const char* file, int line) {
192   jint& stub_inst = *(jint*) branch;
193   stub_inst = patched_branch(target - branch, stub_inst, 0);
194 }
195 
196 // Relocation of conditional far branches.
is_bc_far_variant1_at(address instruction_addr)197 inline bool MacroAssembler::is_bc_far_variant1_at(address instruction_addr) {
198   // Variant 1, the 1st instruction contains the destination address:
199   //
200   //    bcxx  DEST
201   //    nop
202   //
203   const int instruction_1 = *(int*)(instruction_addr);
204   const int instruction_2 = *(int*)(instruction_addr + 4);
205   return is_bcxx(instruction_1) &&
206          (inv_bd_field(instruction_1, (intptr_t)instruction_addr) != (intptr_t)(instruction_addr + 2*4)) &&
207          is_nop(instruction_2);
208 }
209 
210 // Relocation of conditional far branches.
is_bc_far_variant2_at(address instruction_addr)211 inline bool MacroAssembler::is_bc_far_variant2_at(address instruction_addr) {
212   // Variant 2, the 2nd instruction contains the destination address:
213   //
214   //    b!cxx SKIP
215   //    bxx   DEST
216   //  SKIP:
217   //
218   const int instruction_1 = *(int*)(instruction_addr);
219   const int instruction_2 = *(int*)(instruction_addr + 4);
220   return is_bcxx(instruction_1) &&
221          (inv_bd_field(instruction_1, (intptr_t)instruction_addr) == (intptr_t)(instruction_addr + 2*4)) &&
222          is_bxx(instruction_2);
223 }
224 
225 // Relocation for conditional branches
is_bc_far_variant3_at(address instruction_addr)226 inline bool MacroAssembler::is_bc_far_variant3_at(address instruction_addr) {
227   // Variant 3, far cond branch to the next instruction, already patched to nops:
228   //
229   //    nop
230   //    endgroup
231   //  SKIP/DEST:
232   //
233   const int instruction_1 = *(int*)(instruction_addr);
234   const int instruction_2 = *(int*)(instruction_addr + 4);
235   return is_nop(instruction_1) &&
236          is_endgroup(instruction_2);
237 }
238 
239 
240 // Convenience bc_far versions
blt_far(ConditionRegister crx,Label & L,int optimize)241 inline void MacroAssembler::blt_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs1, bi0(crx, less), L, optimize); }
bgt_far(ConditionRegister crx,Label & L,int optimize)242 inline void MacroAssembler::bgt_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs1, bi0(crx, greater), L, optimize); }
beq_far(ConditionRegister crx,Label & L,int optimize)243 inline void MacroAssembler::beq_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs1, bi0(crx, equal), L, optimize); }
bso_far(ConditionRegister crx,Label & L,int optimize)244 inline void MacroAssembler::bso_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs1, bi0(crx, summary_overflow), L, optimize); }
bge_far(ConditionRegister crx,Label & L,int optimize)245 inline void MacroAssembler::bge_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs0, bi0(crx, less), L, optimize); }
ble_far(ConditionRegister crx,Label & L,int optimize)246 inline void MacroAssembler::ble_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs0, bi0(crx, greater), L, optimize); }
bne_far(ConditionRegister crx,Label & L,int optimize)247 inline void MacroAssembler::bne_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs0, bi0(crx, equal), L, optimize); }
bns_far(ConditionRegister crx,Label & L,int optimize)248 inline void MacroAssembler::bns_far(ConditionRegister crx, Label& L, int optimize) { MacroAssembler::bc_far(bcondCRbiIs0, bi0(crx, summary_overflow), L, optimize); }
249 
call_stub(Register function_entry)250 inline address MacroAssembler::call_stub(Register function_entry) {
251   mtctr(function_entry);
252   bctrl();
253   return pc();
254 }
255 
call_stub_and_return_to(Register function_entry,Register return_pc)256 inline void MacroAssembler::call_stub_and_return_to(Register function_entry, Register return_pc) {
257   assert_different_registers(function_entry, return_pc);
258   mtlr(return_pc);
259   mtctr(function_entry);
260   bctr();
261 }
262 
263 // Get the pc where the last emitted call will return to.
last_calls_return_pc()264 inline address MacroAssembler::last_calls_return_pc() {
265   return _last_calls_return_pc;
266 }
267 
268 // Read from the polling page, its address is already in a register.
load_from_polling_page(Register polling_page_address,int offset)269 inline void MacroAssembler::load_from_polling_page(Register polling_page_address, int offset) {
270   if (USE_POLL_BIT_ONLY) {
271     int encoding = SafepointMechanism::poll_bit();
272     tdi(traptoGreaterThanUnsigned | traptoEqual, polling_page_address, encoding);
273   } else {
274     ld(R0, offset, polling_page_address);
275   }
276 }
277 
278 // Trap-instruction-based checks.
279 
trap_null_check(Register a,trap_to_bits cmp)280 inline void MacroAssembler::trap_null_check(Register a, trap_to_bits cmp) {
281   assert(TrapBasedNullChecks, "sanity");
282   tdi(cmp, a/*reg a*/, 0);
283 }
284 
trap_ic_miss_check(Register a,Register b)285 inline void MacroAssembler::trap_ic_miss_check(Register a, Register b) {
286   td(traptoGreaterThanUnsigned | traptoLessThanUnsigned, a, b);
287 }
288 
289 // Do an explicit null check if access to a+offset will not raise a SIGSEGV.
290 // Either issue a trap instruction that raises SIGTRAP, or do a compare that
291 // branches to exception_entry.
292 // No support for compressed oops (base page of heap). Does not distinguish
293 // loads and stores.
null_check_throw(Register a,int offset,Register temp_reg,address exception_entry)294 inline void MacroAssembler::null_check_throw(Register a, int offset, Register temp_reg,
295                                              address exception_entry) {
296   if (!ImplicitNullChecks || needs_explicit_null_check(offset) || !os::zero_page_read_protected()) {
297     if (TrapBasedNullChecks) {
298       assert(UseSIGTRAP, "sanity");
299       trap_null_check(a);
300     } else {
301       Label ok;
302       cmpdi(CCR0, a, 0);
303       bne(CCR0, ok);
304       load_const_optimized(temp_reg, exception_entry);
305       mtctr(temp_reg);
306       bctr();
307       bind(ok);
308     }
309   }
310 }
311 
null_check(Register a,int offset,Label * Lis_null)312 inline void MacroAssembler::null_check(Register a, int offset, Label *Lis_null) {
313   if (!ImplicitNullChecks || needs_explicit_null_check(offset) || !os::zero_page_read_protected()) {
314     if (TrapBasedNullChecks) {
315       assert(UseSIGTRAP, "sanity");
316       trap_null_check(a);
317     } else if (Lis_null){
318       Label ok;
319       cmpdi(CCR0, a, 0);
320       beq(CCR0, *Lis_null);
321     }
322   }
323 }
324 
access_store_at(BasicType type,DecoratorSet decorators,Register base,RegisterOrConstant ind_or_offs,Register val,Register tmp1,Register tmp2,Register tmp3,bool needs_frame)325 inline void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators,
326                                             Register base, RegisterOrConstant ind_or_offs, Register val,
327                                             Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
328   assert((decorators & ~(AS_RAW | IN_HEAP | IN_NATIVE | IS_ARRAY | IS_NOT_NULL |
329                          ON_UNKNOWN_OOP_REF)) == 0, "unsupported decorator");
330   BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
331   bool as_raw = (decorators & AS_RAW) != 0;
332   decorators = AccessInternal::decorator_fixup(decorators);
333   if (as_raw) {
334     bs->BarrierSetAssembler::store_at(this, decorators, type,
335                                       base, ind_or_offs, val,
336                                       tmp1, tmp2, tmp3, needs_frame);
337   } else {
338     bs->store_at(this, decorators, type,
339                  base, ind_or_offs, val,
340                  tmp1, tmp2, tmp3, needs_frame);
341   }
342 }
343 
access_load_at(BasicType type,DecoratorSet decorators,Register base,RegisterOrConstant ind_or_offs,Register dst,Register tmp1,Register tmp2,bool needs_frame,Label * L_handle_null)344 inline void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators,
345                                            Register base, RegisterOrConstant ind_or_offs, Register dst,
346                                            Register tmp1, Register tmp2, bool needs_frame, Label *L_handle_null) {
347   assert((decorators & ~(AS_RAW | IN_HEAP | IN_NATIVE | IS_ARRAY | IS_NOT_NULL |
348                          ON_PHANTOM_OOP_REF | ON_WEAK_OOP_REF)) == 0, "unsupported decorator");
349   BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
350   decorators = AccessInternal::decorator_fixup(decorators);
351   bool as_raw = (decorators & AS_RAW) != 0;
352   if (as_raw) {
353     bs->BarrierSetAssembler::load_at(this, decorators, type,
354                                      base, ind_or_offs, dst,
355                                      tmp1, tmp2, needs_frame, L_handle_null);
356   } else {
357     bs->load_at(this, decorators, type,
358                 base, ind_or_offs, dst,
359                 tmp1, tmp2, needs_frame, L_handle_null);
360   }
361 }
362 
load_heap_oop(Register d,RegisterOrConstant offs,Register s1,Register tmp1,Register tmp2,bool needs_frame,DecoratorSet decorators,Label * L_handle_null)363 inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, Register s1,
364                                           Register tmp1, Register tmp2,
365                                           bool needs_frame, DecoratorSet decorators, Label *L_handle_null) {
366   access_load_at(T_OBJECT, IN_HEAP | decorators, s1, offs, d, tmp1, tmp2, needs_frame, L_handle_null);
367 }
368 
store_heap_oop(Register d,RegisterOrConstant offs,Register s1,Register tmp1,Register tmp2,Register tmp3,bool needs_frame,DecoratorSet decorators)369 inline void MacroAssembler::store_heap_oop(Register d, RegisterOrConstant offs, Register s1,
370                                            Register tmp1, Register tmp2, Register tmp3,
371                                            bool needs_frame, DecoratorSet decorators) {
372   access_store_at(T_OBJECT, IN_HEAP | decorators, s1, offs, d, tmp1, tmp2, tmp3, needs_frame);
373 }
374 
encode_heap_oop_not_null(Register d,Register src)375 inline Register MacroAssembler::encode_heap_oop_not_null(Register d, Register src) {
376   Register current = (src != noreg) ? src : d; // Oop to be compressed is in d if no src provided.
377   if (CompressedOops::base_overlaps()) {
378     sub_const_optimized(d, current, CompressedOops::base(), R0);
379     current = d;
380   }
381   if (CompressedOops::shift() != 0) {
382     rldicl(d, current, 64-CompressedOops::shift(), 32);  // Clears the upper bits.
383     current = d;
384   }
385   return current; // Encoded oop is in this register.
386 }
387 
encode_heap_oop(Register d,Register src)388 inline Register MacroAssembler::encode_heap_oop(Register d, Register src) {
389   if (CompressedOops::base() != NULL) {
390     if (VM_Version::has_isel()) {
391       cmpdi(CCR0, src, 0);
392       Register co = encode_heap_oop_not_null(d, src);
393       assert(co == d, "sanity");
394       isel_0(d, CCR0, Assembler::equal);
395     } else {
396       Label isNull;
397       or_(d, src, src); // move and compare 0
398       beq(CCR0, isNull);
399       encode_heap_oop_not_null(d, src);
400       bind(isNull);
401     }
402     return d;
403   } else {
404     return encode_heap_oop_not_null(d, src);
405   }
406 }
407 
decode_heap_oop_not_null(Register d,Register src)408 inline Register MacroAssembler::decode_heap_oop_not_null(Register d, Register src) {
409   if (CompressedOops::base_disjoint() && src != noreg && src != d &&
410       CompressedOops::shift() != 0) {
411     load_const_optimized(d, CompressedOops::base(), R0);
412     rldimi(d, src, CompressedOops::shift(), 32-CompressedOops::shift());
413     return d;
414   }
415 
416   Register current = (src != noreg) ? src : d; // Compressed oop is in d if no src provided.
417   if (CompressedOops::shift() != 0) {
418     sldi(d, current, CompressedOops::shift());
419     current = d;
420   }
421   if (CompressedOops::base() != NULL) {
422     add_const_optimized(d, current, CompressedOops::base(), R0);
423     current = d;
424   }
425   return current; // Decoded oop is in this register.
426 }
427 
decode_heap_oop(Register d)428 inline void MacroAssembler::decode_heap_oop(Register d) {
429   Label isNull;
430   bool use_isel = false;
431   if (CompressedOops::base() != NULL) {
432     cmpwi(CCR0, d, 0);
433     if (VM_Version::has_isel()) {
434       use_isel = true;
435     } else {
436       beq(CCR0, isNull);
437     }
438   }
439   decode_heap_oop_not_null(d);
440   if (use_isel) {
441     isel_0(d, CCR0, Assembler::equal);
442   }
443   bind(isNull);
444 }
445 
446 // SIGTRAP-based range checks for arrays.
trap_range_check_l(Register a,Register b)447 inline void MacroAssembler::trap_range_check_l(Register a, Register b) {
448   tw (traptoLessThanUnsigned,                  a/*reg a*/, b/*reg b*/);
449 }
trap_range_check_l(Register a,int si16)450 inline void MacroAssembler::trap_range_check_l(Register a, int si16) {
451   twi(traptoLessThanUnsigned,                  a/*reg a*/, si16);
452 }
trap_range_check_le(Register a,int si16)453 inline void MacroAssembler::trap_range_check_le(Register a, int si16) {
454   twi(traptoEqual | traptoLessThanUnsigned,    a/*reg a*/, si16);
455 }
trap_range_check_g(Register a,int si16)456 inline void MacroAssembler::trap_range_check_g(Register a, int si16) {
457   twi(traptoGreaterThanUnsigned,               a/*reg a*/, si16);
458 }
trap_range_check_ge(Register a,Register b)459 inline void MacroAssembler::trap_range_check_ge(Register a, Register b) {
460   tw (traptoEqual | traptoGreaterThanUnsigned, a/*reg a*/, b/*reg b*/);
461 }
trap_range_check_ge(Register a,int si16)462 inline void MacroAssembler::trap_range_check_ge(Register a, int si16) {
463   twi(traptoEqual | traptoGreaterThanUnsigned, a/*reg a*/, si16);
464 }
465 
466 // unsigned integer multiplication 64*64 -> 128 bits
multiply64(Register dest_hi,Register dest_lo,Register x,Register y)467 inline void MacroAssembler::multiply64(Register dest_hi, Register dest_lo,
468                                        Register x, Register y) {
469   mulld(dest_lo, x, y);
470   mulhdu(dest_hi, x, y);
471 }
472 
473 #if defined(ABI_ELFv2)
function_entry()474 inline address MacroAssembler::function_entry() { return pc(); }
475 #else
function_entry()476 inline address MacroAssembler::function_entry() { return emit_fd(); }
477 #endif
478 
479 #endif // CPU_PPC_MACROASSEMBLER_PPC_INLINE_HPP
480