2 Compatibility <intrin.h> header for GCC -- GCC equivalents of intrinsic
3 Microsoft Visual C++ functions. Originally developed for the ReactOS
4 (<http://www.reactos.org/>) and TinyKrnl (<http://www.tinykrnl.org/>)
7 Copyright (c) 2006 KJK::Hyperion <hackbunny@reactos.com>
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the "Software"),
11 to deal in the Software without restriction, including without limitation
12 the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 and/or sell copies of the Software, and to permit persons to whom the
14 Software is furnished to do so, subject to the following conditions:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
28 #ifndef KJK_INTRIN_PPC_H_
29 #define KJK_INTRIN_PPC_H_
31 //#define PPC_QUAL static __inline__ __attribute__((always_inline))
32 #define PPC_QUAL extern __inline__
35 #error Unsupported compiler
38 /*** Stack frame juggling ***/
39 #define _ReturnAddress() (__builtin_return_address(0))
40 #define _AddressOfReturnAddress() (&(((void **)(__builtin_frame_address(0)))[1]))
41 /* TODO: __getcallerseflags but how??? */
44 /*** Atomic operations ***/
45 /* TODO: _ReadBarrier */
46 /* TODO: _WriteBarrier */
48 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
49 #define _ReadWriteBarrier() __sync_synchronize()
51 /* TODO: _ReadWriteBarrier() */
54 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
56 PPC_QUAL
char _InterlockedCompareExchange8(volatile char * const Destination
, const char Exchange
, const char Comperand
)
58 return __sync_val_compare_and_swap(Destination
, Comperand
, Exchange
);
61 PPC_QUAL
short _InterlockedCompareExchange16(volatile short * const Destination
, const short Exchange
, const short Comperand
)
63 return __sync_val_compare_and_swap(Destination
, Comperand
, Exchange
);
66 PPC_QUAL
long _InterlockedCompareExchange(volatile long * const Destination
, const long Exchange
, const long Comperand
)
68 return __sync_val_compare_and_swap(Destination
, Comperand
, Exchange
);
71 PPC_QUAL
long long _InterlockedCompareExchange64(volatile long long * const Destination
, const long long Exchange
, const long long Comperand
)
73 return __sync_val_compare_and_swap(Destination
, Comperand
, Exchange
);
76 PPC_QUAL
void * _InterlockedCompareExchangePointer(void * volatile * const Destination
, void * const Exchange
, void * const Comperand
)
78 return __sync_val_compare_and_swap(Destination
, Comperand
, Exchange
);
81 PPC_QUAL
long _InterlockedExchange(volatile long * const Target
, const long Value
)
83 /* NOTE: __sync_lock_test_and_set would be an acquire barrier, so we force a full barrier */
85 return __sync_lock_test_and_set(Target
, Value
);
88 PPC_QUAL
void * _InterlockedExchangePointer(void * volatile * const Target
, void * const Value
)
92 return __sync_lock_test_and_set(Target
, Value
);
95 PPC_QUAL
long _InterlockedExchangeAdd(volatile long * const Addend
, const long Value
)
97 return __sync_fetch_and_add(Addend
, Value
);
100 PPC_QUAL
char _InterlockedAnd8(volatile char * const value
, const char mask
)
102 return __sync_fetch_and_and(value
, mask
);
105 PPC_QUAL
short _InterlockedAnd16(volatile short * const value
, const short mask
)
107 return __sync_fetch_and_and(value
, mask
);
110 PPC_QUAL
long _InterlockedAnd(volatile long * const value
, const long mask
)
112 return __sync_fetch_and_and(value
, mask
);
115 PPC_QUAL
char _InterlockedOr8(volatile char * const value
, const char mask
)
117 return __sync_fetch_and_or(value
, mask
);
120 PPC_QUAL
short _InterlockedOr16(volatile short * const value
, const short mask
)
122 return __sync_fetch_and_or(value
, mask
);
125 PPC_QUAL
long _InterlockedOr(volatile long * const value
, const long mask
)
127 return __sync_fetch_and_or(value
, mask
);
130 PPC_QUAL
char _InterlockedXor8(volatile char * const value
, const char mask
)
132 return __sync_fetch_and_xor(value
, mask
);
135 PPC_QUAL
short _InterlockedXor16(volatile short * const value
, const short mask
)
137 return __sync_fetch_and_xor(value
, mask
);
140 PPC_QUAL
long _InterlockedXor(volatile long * const value
, const long mask
)
142 return __sync_fetch_and_xor(value
, mask
);
147 PPC_QUAL
char _InterlockedCompareExchange8(volatile char * const Destination
, const char Exchange
, const char Comperand
)
149 volatile long retval
__asm__("r8") = 0;
150 __asm__
__volatile__ (
153 : "=r" (retval
) : "r" (Destination
));
154 __asm__
__volatile__ (
161 : "r" (Destination
), "r" (Comperand
), "r" (Exchange
), "r" (retval
));
165 PPC_QUAL
short _InterlockedCompareExchange16(volatile short * const Destination
, const short Exchange
, const short Comperand
)
167 volatile long retval
__asm__("r8") = 0;
168 __asm__
__volatile__ (
171 : "=&r" (retval
) : "r" (Destination
));
172 __asm__
__volatile__ (
179 : "r" (Destination
), "r" (Comperand
), "r" (Exchange
), "r" (retval
));
183 PPC_QUAL
long _InterlockedCompareExchange(volatile long * const Destination
, const long Exchange
, const long Comperand
)
185 volatile long retval
__asm__("r8") = 0;
186 __asm__
__volatile__ (
189 : "=&r" (retval
) : "r" (Destination
));
190 __asm__
__volatile__ (
197 : "r" (Destination
), "r" (Comperand
), "r" (Exchange
), "r" (retval
));
201 PPC_QUAL
long long _InterlockedCompareExchange64(volatile long long * const Target
, const long long Exchange
, const long long Comperand
)
203 long long capture
= *Target
;
204 if (*Target
== Comperand
) *Target
= Exchange
;
208 PPC_QUAL
void * _InterlockedCompareExchangePointer(void * volatile * const Destination
, void * const Exchange
, void * const Comperand
)
210 return (void *)_InterlockedCompareExchange
211 ((long *)Destination
, (long) Exchange
, (long) Comperand
);
214 PPC_QUAL
long _InterlockedExchange(volatile long * const Target
, const long Value
)
216 long retval
__asm__("r8");
217 __asm__
__volatile__ (
224 : "b" (Target
), "b" (Value
)
229 PPC_QUAL
void * _InterlockedExchangePointer(void * volatile * const Target
, void * const Value
)
231 return (void *)_InterlockedExchange((long *)Target
, (long)Value
);
234 #define PPC_MakeInterlockedFunction(type,name,op,proto) \
235 PPC_QUAL type name proto \
241 y = _InterlockedCompareExchange(value, addend op modify, addend); \
243 while(y != addend); \
248 PPC_QUAL
unsigned char _interlockedbittestandreset(volatile long * const a
, const long b
)
257 y
= _InterlockedCompareExchange(a
, x
& mask
, x
);
261 return (y
& ~mask
) != 0;
264 PPC_MakeInterlockedFunction(long,_InterlockedExchangeAdd
,+,(volatile long * const value
, const long modify
))
265 PPC_MakeInterlockedFunction(char,_InterlockedAnd8
,&,(volatile char * const value
, const char modify
))
266 PPC_MakeInterlockedFunction(short,_InterlockedAnd16
,&,(volatile short * const value
, const short modify
))
267 PPC_MakeInterlockedFunction(long,_InterlockedAnd
,&,(volatile long * const value
, const long modify
))
268 PPC_MakeInterlockedFunction(char,_InterlockedOr8
,|,(volatile char * const value
, const char modify
))
269 PPC_MakeInterlockedFunction(short,_InterlockedOr16
,|,(volatile short * const value
, const short modify
))
270 PPC_MakeInterlockedFunction(long,_InterlockedOr
,|,(volatile long * const value
, const long modify
))
271 PPC_MakeInterlockedFunction(char,_InterlockedXor8
,^,(volatile char * const value
, const char modify
))
272 PPC_MakeInterlockedFunction(short,_InterlockedXor16
,^,(volatile short * const value
, const short modify
))
273 PPC_MakeInterlockedFunction(long,_InterlockedXor
,^,(volatile long * const value
, const long modify
))
275 PPC_QUAL
unsigned char _interlockedbittestandset(volatile long * const a
, const long b
)
284 y
= _InterlockedCompareExchange(a
, x
| mask
, x
);
288 return (y
& ~mask
) != 0;
292 PPC_QUAL
long _InterlockedDecrement(volatile long * const lpAddend
)
294 return _InterlockedExchangeAdd(lpAddend
, -1) - 1;
297 PPC_QUAL
long _InterlockedIncrement(volatile long * const lpAddend
)
299 return _InterlockedExchangeAdd(lpAddend
, 1) + 1;
302 /*** String operations ***/
303 /* NOTE: we don't set a memory clobber in the __stosX functions because Visual C++ doesn't */
304 /* Note that the PPC store multiple operations may raise an exception in LE
306 PPC_QUAL
void __stosb(unsigned char * Dest
, const unsigned char Data
, unsigned long Count
)
308 memset(Dest
, Data
, Count
);
311 PPC_QUAL
void __stosw(unsigned short * Dest
, const unsigned short Data
, unsigned long Count
)
317 PPC_QUAL
void __stosd(unsigned long * Dest
, const unsigned long Data
, unsigned long Count
)
323 PPC_QUAL
void __movsb(unsigned char * Destination
, const unsigned char * Source
, unsigned long Count
)
325 memcpy(Destination
, Source
, Count
);
328 PPC_QUAL
void __movsw(unsigned short * Destination
, const unsigned short * Source
, unsigned long Count
)
330 memcpy(Destination
, Source
, Count
* sizeof(*Source
));
333 PPC_QUAL
void __movsd(unsigned long * Destination
, const unsigned long * Source
, unsigned long Count
)
335 memcpy(Destination
, Source
, Count
* sizeof(*Source
));
339 /*** FS segment addressing ***/
340 /* On PowerPC, r13 points to TLS data, including the TEB at 0(r13) from what I
342 PPC_QUAL
void __writefsbyte(const unsigned long Offset
, const unsigned char Data
)
345 __asm__("\tadd %0,13,%1\n\tstb %2,0(%0)" : "=r" (addr
) : "r" (Offset
), "r" (Data
));
348 PPC_QUAL
void __writefsword(const unsigned long Offset
, const unsigned short Data
)
351 __asm__("\tadd %0,13,%1\n\tsth %2,0(%0)" : "=r" (addr
) : "r" (Offset
), "r" (Data
));
354 PPC_QUAL
void __writefsdword(const unsigned long Offset
, const unsigned long Data
)
357 __asm__("\tadd %0,13,%1\n\tstw %2,0(%0)" : "=r" (addr
) : "r" (Offset
), "r" (Data
));
360 PPC_QUAL
unsigned char __readfsbyte(const unsigned long Offset
)
362 unsigned short result
;
363 __asm__("\tadd 7,13,%1\n"
371 PPC_QUAL
unsigned short __readfsword(const unsigned long Offset
)
373 unsigned short result
;
374 __asm__("\tadd 7,13,%1\n"
382 PPC_QUAL
unsigned long __readfsdword(const unsigned long Offset
)
384 unsigned long result
;
385 __asm__("\tadd 7,13,%1\n"
393 PPC_QUAL
void __incfsbyte(const unsigned long Offset
)
395 __writefsbyte(Offset
, __readfsbyte(Offset
)+1);
398 PPC_QUAL
void __incfsword(const unsigned long Offset
)
400 __writefsword(Offset
, __readfsword(Offset
)+1);
403 PPC_QUAL
void __incfsdword(const unsigned long Offset
)
405 __writefsdword(Offset
, __readfsdword(Offset
)+1);
408 /* NOTE: the bizarre implementation of __addfsxxx mimics the broken Visual C++ behavior */
409 /* PPC Note: Not sure about the bizarre behavior. We'll try to emulate it later */
410 PPC_QUAL
void __addfsbyte(const unsigned long Offset
, const unsigned char Data
)
412 __writefsbyte(Offset
, __readfsbyte(Offset
) + Data
);
415 PPC_QUAL
void __addfsword(const unsigned long Offset
, const unsigned short Data
)
417 __writefsword(Offset
, __readfsword(Offset
) + Data
);
420 PPC_QUAL
void __addfsdword(const unsigned long Offset
, const unsigned int Data
)
422 __writefsdword(Offset
, __readfsdword(Offset
) + Data
);
426 /*** Bit manipulation ***/
427 PPC_QUAL
unsigned char _BitScanForward(unsigned long * const Index
, const unsigned long Mask
)
429 if(Mask
== 0) return 0;
431 unsigned long mask
= Mask
;
434 ((mask
& 0xffff0000) ? 16 : 0) +
435 ((mask
& 0xff00ff00) ? 8 : 0) +
436 ((mask
& 0xf0f0f0f0) ? 4 : 0) +
437 ((mask
& 0xcccccccc) ? 2 : 0) +
438 ((mask
& 0xaaaaaaaa) ? 1 : 0);
443 /* Thanks http://www.jjj.de/bitwizardry/files/bithigh.h */
444 PPC_QUAL
unsigned char _BitScanReverse(unsigned long * const Index
, const unsigned long Mask
)
446 unsigned long check
= 16, checkmask
;
447 if(Mask
== 0) return 0;
449 unsigned long mask
= Mask
;
452 checkmask
= ((1<<check
)-1) << check
;
453 if( mask
& checkmask
) {
463 /* NOTE: again, the bizarre implementation follows Visual C++ */
464 PPC_QUAL
unsigned char _bittest(const long * const a
, const long b
)
466 return ((*a
) & (1<<b
)) != 0;
469 PPC_QUAL
unsigned char _bittestandcomplement(long * const a
, const long b
)
471 unsigned char ret
= ((*a
) & (1<<b
)) != 0;
476 PPC_QUAL
unsigned char _bittestandreset(long * const a
, const long b
)
478 unsigned char ret
= ((*a
) & (1<<b
)) != 0;
483 PPC_QUAL
unsigned char _bittestandset(long * const a
, const long b
)
485 unsigned char ret
= ((*a
) & (1<<b
)) != 0;
490 PPC_QUAL
unsigned char _rotl8(const unsigned char value
, const unsigned char shift
)
492 return (value
<< shift
) | (value
>> (8-shift
));
495 PPC_QUAL
unsigned short _rotl16(const unsigned short value
, const unsigned char shift
)
497 return (value
<< shift
) | (value
>> (16-shift
));
500 PPC_QUAL
unsigned char _rotr8(const unsigned char value
, const unsigned char shift
)
502 return (value
>> shift
) | (value
<< (8-shift
));
505 PPC_QUAL
unsigned short _rotr16(const unsigned short value
, const unsigned char shift
)
507 return (value
>> shift
) | (value
<< (16-shift
));
510 PPC_QUAL
unsigned long long __ll_lshift(const unsigned long long Mask
, int Bit
)
515 PPC_QUAL
long long __ll_rshift(const long long Mask
, const int Bit
)
520 PPC_QUAL
unsigned long long __ull_rshift(const unsigned long long Mask
, int Bit
)
526 /*** 64-bit math ***/
527 PPC_QUAL
long long __emul(const int a
, const int b
)
532 PPC_QUAL
unsigned long long __emulu(const unsigned int a
, const unsigned int b
)
539 PPC_QUAL
unsigned char __inbyte(const unsigned long Port
)
544 "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
548 "lbz %0,0(%1)\n\t" /* Get actual value at phys addr r3 */
549 "mtmsr 5\n\t" : "=r" (ret
) : "b" (Port
)
554 PPC_QUAL
unsigned short __inword(const unsigned long Port
)
559 "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
563 "lhz %0,0(%1)\n\t" /* Get actual value at phys addr r3 */
564 "mtmsr 5\n\t" : "=r" (ret
) : "b" (Port
)
569 PPC_QUAL
unsigned long __indword(const unsigned long Port
)
574 "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
578 "lwz %0,0(%1)\n\t" /* Get actual value at phys addr r3 */
579 "mtmsr 5\n\t" : "=r" (ret
) : "b" (Port
)
584 PPC_QUAL
void __inbytestring(unsigned long Port
, unsigned char * Buffer
, unsigned long Count
)
587 *Buffer
++ = __inbyte(Port
);
591 PPC_QUAL
void __inwordstring(unsigned long Port
, unsigned short * Buffer
, unsigned long Count
)
594 *Buffer
++ = __inword(Port
);
598 PPC_QUAL
void __indwordstring(unsigned long Port
, unsigned long * Buffer
, unsigned long Count
)
601 *Buffer
++ = __indword(Port
);
605 PPC_QUAL
void __outbyte(unsigned long const Port
, const unsigned char Data
)
609 "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
613 "stb %1,0(%0)\n\t" /* Set actual value at phys addr r3 */
617 "eieio\n\t" : : "b" (Port
), "r" (Data
)
621 PPC_QUAL
void __outword(unsigned long const Port
, const unsigned short Data
)
625 "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
629 "sth %1,0(%0)\n\t" /* Set actual value at phys addr r3 */
633 "eieio\n\t" : : "b" (Port
), "b" (Data
)
637 PPC_QUAL
void __outdword(unsigned long const Port
, const unsigned long Data
)
641 "andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
645 "stw %1,0(%0)\n\t" /* Set actual value at phys addr r3 */
649 "eieio\n\t" : : "b" (Port
), "b" (Data
)
653 PPC_QUAL
void __outbytestring(unsigned long const Port
, const unsigned char * const Buffer
, const unsigned long Count
)
655 unsigned long count
= Count
;
656 const unsigned char *buffer
= Buffer
;
658 __outbyte(Port
, *buffer
++);
662 PPC_QUAL
void __outwordstring(unsigned long const Port
, const unsigned short * const Buffer
, const unsigned long Count
)
664 unsigned long count
= Count
;
665 const unsigned short *buffer
= Buffer
;
667 __outword(Port
, *buffer
++);
671 PPC_QUAL
void __outdwordstring(unsigned long const Port
, const unsigned long * const Buffer
, const unsigned long Count
)
673 unsigned long count
= Count
;
674 const unsigned long *buffer
= Buffer
;
676 __outdword(Port
, *buffer
++);
681 /*** System information ***/
682 PPC_QUAL
void __cpuid(int CPUInfo
[], const int InfoType
)
685 __asm__("mfpvr" : "=b" (lo32
));
688 PPC_QUAL
unsigned long long __rdtsc(void)
691 __asm__("mfdec %0" : "=b" (lo32
));
697 /* Finally decided to do this by enabling single step trap */
698 PPC_QUAL
void __debugbreak(void)
703 PPC_QUAL
void __int2c(void)
708 #ifndef _ENABLE_DISABLE_DEFINED
709 #define _ENABLE_DISABLE_DEFINED
710 PPC_QUAL
void _disable(void)
712 __asm__
__volatile__("mfmsr 0\n\t" \
718 PPC_QUAL
void _enable(void)
720 __asm__
__volatile__("mfmsr 8\n\t" \
721 "ori 8,8,0x8000\n\t" \
725 /*** Protected memory management ***/
726 PPC_QUAL
unsigned long __readsdr1(void)
729 __asm__("mfsdr1 %0" : "=b" (value
));
733 PPC_QUAL
void __writesdr1(const unsigned long long Data
)
735 __asm__("mtsdr1 %0" : : "b" (Data
));
738 /*** System operations ***/
739 /* This likely has a different meaning from the X86 equivalent. We'll keep
740 * the name cause it fits */
741 PPC_QUAL
unsigned long long __readmsr()
744 __asm__("mfmsr %0" : "=b" (temp
));
748 PPC_QUAL
void __writemsr(const unsigned long Value
)
750 __asm__("mtmsr %0" : : "b" (Value
));
753 /* We'll make sure of the following:
754 * IO operations have completed
755 * Write operations through cache have completed
756 * We've reloaded anything in the data or instruction cache that might have
757 * changed in real ram.
759 PPC_QUAL
void __wbinvd(void)
768 PPC_QUAL
long _InterlockedAddLargeStatistic(volatile long long * const Addend
, const long Value
)
773 "lock; add %[Value], %[Lo32];"
775 "lock; adc $0, %[Hi32];"
777 [Lo32
] "=m" (*((volatile long *)(Addend
) + 0)), [Hi32
] "=m" (*((volatile long *)(Addend
) + 1)) :
784 /*** Miscellaneous ***/
785 /* BUGBUG: only good for use in macros. Cannot be taken the address of */
786 #define __noop(...) ((void)0)
788 #define __assume(x) if (!(x)) __builtin_unreachable()