diff options
Diffstat (limited to 'contrib')
87 files changed, 4932 insertions, 956 deletions
diff --git a/contrib/compiler-rt/lib/absvti2.c b/contrib/compiler-rt/lib/absvti2.c index c1c7277..437bc3d 100644 --- a/contrib/compiler-rt/lib/absvti2.c +++ b/contrib/compiler-rt/lib/absvti2.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: absolute value */ @@ -30,4 +30,5 @@ __absvti2(ti_int a) return (a ^ s) - s; } -#endif +#endif /* CRT_HAS_128BIT */ + diff --git a/contrib/compiler-rt/lib/addvti3.c b/contrib/compiler-rt/lib/addvti3.c index 2efcf3b..f2a5c56 100644 --- a/contrib/compiler-rt/lib/addvti3.c +++ b/contrib/compiler-rt/lib/addvti3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: a + b */ @@ -37,4 +37,4 @@ __addvti3(ti_int a, ti_int b) return s; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/ashlti3.c b/contrib/compiler-rt/lib/ashlti3.c index 4bd8219..08d2181d4 100644 --- a/contrib/compiler-rt/lib/ashlti3.c +++ b/contrib/compiler-rt/lib/ashlti3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: a << b */ @@ -42,4 +42,4 @@ __ashlti3(ti_int a, si_int b) return result.all; } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/ashrti3.c b/contrib/compiler-rt/lib/ashrti3.c index ed43641..6161bd5 100644 --- a/contrib/compiler-rt/lib/ashrti3.c +++ b/contrib/compiler-rt/lib/ashrti3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: arithmetic a >> b */ @@ -43,4 +43,4 @@ __ashrti3(ti_int a, si_int b) return result.all; } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/clzti2.c b/contrib/compiler-rt/lib/clzti2.c index 355c20e..d478db8 100644 --- a/contrib/compiler-rt/lib/clzti2.c +++ b/contrib/compiler-rt/lib/clzti2.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: the number of leading 0-bits */ @@ -30,4 +30,4 @@ __clzti2(ti_int a) ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT))); } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/cmpti2.c b/contrib/compiler-rt/lib/cmpti2.c index d0aec45..d287fab 100644 --- a/contrib/compiler-rt/lib/cmpti2.c +++ b/contrib/compiler-rt/lib/cmpti2.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: if (a < b) returns 0 * if (a == b) returns 1 @@ -39,4 +39,4 @@ __cmpti2(ti_int a, ti_int b) return 1; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/ctzti2.c b/contrib/compiler-rt/lib/ctzti2.c index 66dc01b..43a8797 100644 --- a/contrib/compiler-rt/lib/ctzti2.c +++ b/contrib/compiler-rt/lib/ctzti2.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: the number of trailing 0-bits */ @@ -30,4 +30,4 @@ __ctzti2(ti_int a) ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT))); } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/divti3.c b/contrib/compiler-rt/lib/divti3.c index 0242c13..ad365ab 100644 --- a/contrib/compiler-rt/lib/divti3.c +++ b/contrib/compiler-rt/lib/divti3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); @@ -32,4 +32,4 @@ __divti3(ti_int a, ti_int b) return (__udivmodti4(a, b, (tu_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */ } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/ffsti2.c b/contrib/compiler-rt/lib/ffsti2.c index 27e15d5..e64266d 100644 --- a/contrib/compiler-rt/lib/ffsti2.c +++ b/contrib/compiler-rt/lib/ffsti2.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: the index of the least significant 1-bit in a, or * the value zero if a is zero. The least significant bit is index one. @@ -34,4 +34,4 @@ __ffsti2(ti_int a) return __builtin_ctzll(x.s.low) + 1; } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/fixdfti.c b/contrib/compiler-rt/lib/fixdfti.c index b110a94..3b9ddb2 100644 --- a/contrib/compiler-rt/lib/fixdfti.c +++ b/contrib/compiler-rt/lib/fixdfti.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a signed long long, rounding toward zero. */ @@ -42,4 +42,4 @@ __fixdfti(double a) return (r ^ s) - s; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/fixsfti.c b/contrib/compiler-rt/lib/fixsfti.c index c730ae0..31c2702 100644 --- a/contrib/compiler-rt/lib/fixsfti.c +++ b/contrib/compiler-rt/lib/fixsfti.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a signed long long, rounding toward zero. */ @@ -42,4 +42,4 @@ __fixsfti(float a) return (r ^ s) - s; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/fixunsdfti.c b/contrib/compiler-rt/lib/fixunsdfti.c index fb0336f..76c8592 100644 --- a/contrib/compiler-rt/lib/fixunsdfti.c +++ b/contrib/compiler-rt/lib/fixunsdfti.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a unsigned long long, rounding toward zero. * Negative values all become zero. @@ -44,4 +44,4 @@ __fixunsdfti(double a) return r; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/fixunssfti.c b/contrib/compiler-rt/lib/fixunssfti.c index 8f4c626..2bb18af 100644 --- a/contrib/compiler-rt/lib/fixunssfti.c +++ b/contrib/compiler-rt/lib/fixunssfti.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a unsigned long long, rounding toward zero. * Negative values all become zero. @@ -44,4 +44,4 @@ __fixunssfti(float a) return r; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/fixunsxfti.c b/contrib/compiler-rt/lib/fixunsxfti.c index 260bfc0..db3c070 100644 --- a/contrib/compiler-rt/lib/fixunsxfti.c +++ b/contrib/compiler-rt/lib/fixunsxfti.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a unsigned long long, rounding toward zero. * Negative values all become zero. @@ -46,4 +46,4 @@ __fixunsxfti(long double a) return r; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/fixxfti.c b/contrib/compiler-rt/lib/fixxfti.c index 973dc31..ca3082e 100644 --- a/contrib/compiler-rt/lib/fixxfti.c +++ b/contrib/compiler-rt/lib/fixxfti.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a signed long long, rounding toward zero. */ @@ -44,4 +44,4 @@ __fixxfti(long double a) return (r ^ s) - s; } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/floattidf.c b/contrib/compiler-rt/lib/floattidf.c index 77749f8..042c203 100644 --- a/contrib/compiler-rt/lib/floattidf.c +++ b/contrib/compiler-rt/lib/floattidf.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a double, rounding toward even.*/ @@ -82,4 +82,4 @@ __floattidf(ti_int a) return fb.f; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/floattisf.c b/contrib/compiler-rt/lib/floattisf.c index 4776125..cb4e29a 100644 --- a/contrib/compiler-rt/lib/floattisf.c +++ b/contrib/compiler-rt/lib/floattisf.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a float, rounding toward even. */ @@ -81,4 +81,4 @@ __floattisf(ti_int a) return fb.f; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/floattixf.c b/contrib/compiler-rt/lib/floattixf.c index 3813dc6..866051e 100644 --- a/contrib/compiler-rt/lib/floattixf.c +++ b/contrib/compiler-rt/lib/floattixf.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a long double, rounding toward even. */ @@ -47,7 +47,7 @@ __floattixf(ti_int a) * P = bit LDBL_MANT_DIG-1 bits to the right of 1 * Q = bit LDBL_MANT_DIG bits to the right of 1 * R = "or" of all bits to the right of Q - */ + */ switch (sd) { case LDBL_MANT_DIG + 1: @@ -83,4 +83,4 @@ __floattixf(ti_int a) return fb.f; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/floatuntidf.c b/contrib/compiler-rt/lib/floatuntidf.c index 4c1d328..e7d6416 100644 --- a/contrib/compiler-rt/lib/floatuntidf.c +++ b/contrib/compiler-rt/lib/floatuntidf.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a double, rounding toward even. */ @@ -43,7 +43,7 @@ __floatuntidf(tu_int a) * P = bit DBL_MANT_DIG-1 bits to the right of 1 * Q = bit DBL_MANT_DIG bits to the right of 1 * R = "or" of all bits to the right of Q - */ + */ switch (sd) { case DBL_MANT_DIG + 1: @@ -79,4 +79,4 @@ __floatuntidf(tu_int a) return fb.f; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/floatuntisf.c b/contrib/compiler-rt/lib/floatuntisf.c index c8da260..e65db57 100644 --- a/contrib/compiler-rt/lib/floatuntisf.c +++ b/contrib/compiler-rt/lib/floatuntisf.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a float, rounding toward even. */ @@ -78,4 +78,4 @@ __floatuntisf(tu_int a) return fb.f; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/floatuntixf.c b/contrib/compiler-rt/lib/floatuntixf.c index dbce80f..d607cc3 100644 --- a/contrib/compiler-rt/lib/floatuntixf.c +++ b/contrib/compiler-rt/lib/floatuntixf.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: convert a to a long double, rounding toward even. */ diff --git a/contrib/compiler-rt/lib/int_types.h b/contrib/compiler-rt/lib/int_types.h index fcce390..5107f71 100644 --- a/contrib/compiler-rt/lib/int_types.h +++ b/contrib/compiler-rt/lib/int_types.h @@ -56,8 +56,11 @@ typedef union }s; } udwords; -#if __x86_64 +#if __LP64__ +#define CRT_HAS_128BIT +#endif +#ifdef CRT_HAS_128BIT typedef int ti_int __attribute__ ((mode (TI))); typedef unsigned tu_int __attribute__ ((mode (TI))); @@ -105,7 +108,7 @@ static inline tu_int make_tu(du_int h, du_int l) { return r.all; } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ typedef union { diff --git a/contrib/compiler-rt/lib/lshrti3.c b/contrib/compiler-rt/lib/lshrti3.c index be76814..6fc4e1f 100644 --- a/contrib/compiler-rt/lib/lshrti3.c +++ b/contrib/compiler-rt/lib/lshrti3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: logical a >> b */ @@ -42,4 +42,4 @@ __lshrti3(ti_int a, si_int b) return result.all; } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/modti3.c b/contrib/compiler-rt/lib/modti3.c index 752202d..ded24a0 100644 --- a/contrib/compiler-rt/lib/modti3.c +++ b/contrib/compiler-rt/lib/modti3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); @@ -33,4 +33,4 @@ __modti3(ti_int a, ti_int b) return (r ^ s) - s; /* negate if s == -1 */ } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/muloti4.c b/contrib/compiler-rt/lib/muloti4.c index f58dd07..0aa6f3b 100644 --- a/contrib/compiler-rt/lib/muloti4.c +++ b/contrib/compiler-rt/lib/muloti4.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: a * b */ @@ -59,4 +59,4 @@ __muloti4(ti_int a, ti_int b, int* overflow) return result; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/multi3.c b/contrib/compiler-rt/lib/multi3.c index 0b8730f..85a6cf4 100644 --- a/contrib/compiler-rt/lib/multi3.c +++ b/contrib/compiler-rt/lib/multi3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: a * b */ @@ -55,4 +55,4 @@ __multi3(ti_int a, ti_int b) return r.all; } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/mulvti3.c b/contrib/compiler-rt/lib/mulvti3.c index 31f7d2f..11d239a 100644 --- a/contrib/compiler-rt/lib/mulvti3.c +++ b/contrib/compiler-rt/lib/mulvti3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: a * b */ @@ -57,4 +57,4 @@ __mulvti3(ti_int a, ti_int b) return a * b; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/negti2.c b/contrib/compiler-rt/lib/negti2.c index f7e4ad3..28ef941 100644 --- a/contrib/compiler-rt/lib/negti2.c +++ b/contrib/compiler-rt/lib/negti2.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: -a */ @@ -27,4 +27,4 @@ __negti2(ti_int a) return -a; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/negvti2.c b/contrib/compiler-rt/lib/negvti2.c index 05df615..d15167f 100644 --- a/contrib/compiler-rt/lib/negvti2.c +++ b/contrib/compiler-rt/lib/negvti2.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: -a */ @@ -29,4 +29,4 @@ __negvti2(ti_int a) return -a; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/parityti2.c b/contrib/compiler-rt/lib/parityti2.c index a1f47b1..fa28380 100644 --- a/contrib/compiler-rt/lib/parityti2.c +++ b/contrib/compiler-rt/lib/parityti2.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: 1 if number of bits is odd else returns 0 */ @@ -28,4 +28,4 @@ __parityti2(ti_int a) return __paritydi2(x.s.high ^ x.s.low); } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/popcountti2.c b/contrib/compiler-rt/lib/popcountti2.c index 9566673..d7223d9 100644 --- a/contrib/compiler-rt/lib/popcountti2.c +++ b/contrib/compiler-rt/lib/popcountti2.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: count of 1 bits */ @@ -41,4 +41,4 @@ __popcountti2(ti_int a) return (x + (x >> 8)) & 0xFF; /* (8 significant bits) */ } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/subvti3.c b/contrib/compiler-rt/lib/subvti3.c index b32df5e..20a0814 100644 --- a/contrib/compiler-rt/lib/subvti3.c +++ b/contrib/compiler-rt/lib/subvti3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: a - b */ @@ -37,4 +37,4 @@ __subvti3(ti_int a, ti_int b) return s; } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/ucmpti2.c b/contrib/compiler-rt/lib/ucmpti2.c index 5466d21..95d1ff8 100644 --- a/contrib/compiler-rt/lib/ucmpti2.c +++ b/contrib/compiler-rt/lib/ucmpti2.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Returns: if (a < b) returns 0 * if (a == b) returns 1 @@ -39,4 +39,4 @@ __ucmpti2(tu_int a, tu_int b) return 1; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/udivmodti4.c b/contrib/compiler-rt/lib/udivmodti4.c index f619c74..d8cea2a 100644 --- a/contrib/compiler-rt/lib/udivmodti4.c +++ b/contrib/compiler-rt/lib/udivmodti4.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT /* Effects: if rem != 0, *rem = a % b * Returns: a / b @@ -253,4 +253,4 @@ __udivmodti4(tu_int a, tu_int b, tu_int* rem) return q.all; } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/udivti3.c b/contrib/compiler-rt/lib/udivti3.c index d9e1bb4..4a942b8 100644 --- a/contrib/compiler-rt/lib/udivti3.c +++ b/contrib/compiler-rt/lib/udivti3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); @@ -26,4 +26,4 @@ __udivti3(tu_int a, tu_int b) return __udivmodti4(a, b, 0); } -#endif /* __x86_64 */ +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/compiler-rt/lib/umodti3.c b/contrib/compiler-rt/lib/umodti3.c index 8ebe7f0..2ab4dd2 100644 --- a/contrib/compiler-rt/lib/umodti3.c +++ b/contrib/compiler-rt/lib/umodti3.c @@ -14,7 +14,7 @@ #include "int_lib.h" -#if __x86_64 +#ifdef CRT_HAS_128BIT tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); @@ -28,4 +28,4 @@ __umodti3(tu_int a, tu_int b) return r; } -#endif +#endif /* CRT_HAS_128BIT */ diff --git a/contrib/gcc/longlong.h b/contrib/gcc/longlong.h index f91eb52..304ee8d 100644 --- a/contrib/gcc/longlong.h +++ b/contrib/gcc/longlong.h @@ -1086,8 +1086,8 @@ UDItype __umulsidi3 (USItype, USItype); "bcs,a,pn %%xcc, 1f\n\t" \ "add %0, 1, %0\n" \ "1:" \ - : "=r" ((UDItype)(sh)), \ - "=&r" ((UDItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "%rJ" ((UDItype)(ah)), \ "rI" ((UDItype)(bh)), \ "%rJ" ((UDItype)(al)), \ @@ -1100,8 +1100,8 @@ UDItype __umulsidi3 (USItype, USItype); "bcs,a,pn %%xcc, 1f\n\t" \ "sub %0, 1, %0\n\t" \ "1:" \ - : "=r" ((UDItype)(sh)), \ - "=&r" ((UDItype)(sl)) \ + : "=r" (sh), \ + "=&r" (sl) \ : "rJ" ((UDItype)(ah)), \ "rI" ((UDItype)(bh)), \ "rJ" ((UDItype)(al)), \ @@ -1133,8 +1133,8 @@ UDItype __umulsidi3 (USItype, USItype); "sllx %3,32,%3\n\t" \ "add %1,%3,%1\n\t" \ "add %5,%2,%0" \ - : "=r" ((UDItype)(wh)), \ - "=&r" ((UDItype)(wl)), \ + : "=r" (wh), \ + "=&r" (wl), \ "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ : "r" ((UDItype)(u)), \ "r" ((UDItype)(v)) \ diff --git a/contrib/llvm/include/llvm/MC/MCAsmInfo.h b/contrib/llvm/include/llvm/MC/MCAsmInfo.h index 7a99394..aba8bcb 100644 --- a/contrib/llvm/include/llvm/MC/MCAsmInfo.h +++ b/contrib/llvm/include/llvm/MC/MCAsmInfo.h @@ -371,7 +371,7 @@ namespace llvm { unsigned Encoding, MCStreamer &Streamer) const; - const MCExpr * + virtual const MCExpr * getExprForFDESymbol(const MCSymbol *Sym, unsigned Encoding, MCStreamer &Streamer) const; diff --git a/contrib/llvm/include/llvm/Object/ELFObjectFile.h b/contrib/llvm/include/llvm/Object/ELFObjectFile.h index 962a3e2..075ca5a 100644 --- a/contrib/llvm/include/llvm/Object/ELFObjectFile.h +++ b/contrib/llvm/include/llvm/Object/ELFObjectFile.h @@ -922,6 +922,9 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const { return "ELF32-mips"; case ELF::EM_PPC: return "ELF32-ppc"; + case ELF::EM_SPARC: + case ELF::EM_SPARC32PLUS: + return "ELF32-sparc"; default: return "ELF32-unknown"; } @@ -937,6 +940,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const { return "ELF64-ppc64"; case ELF::EM_S390: return "ELF64-s390"; + case ELF::EM_SPARCV9: + return "ELF64-sparc"; default: return "ELF64-unknown"; } @@ -967,6 +972,13 @@ unsigned ELFObjectFile<ELFT>::getArch() const { : Triple::ppc64; case ELF::EM_S390: return Triple::systemz; + + case ELF::EM_SPARC: + case ELF::EM_SPARC32PLUS: + return Triple::sparc; + case ELF::EM_SPARCV9: + return Triple::sparcv9; + default: return Triple::UnknownArch; } diff --git a/contrib/llvm/include/llvm/Support/ELF.h b/contrib/llvm/include/llvm/Support/ELF.h index 2868f35..70ad606 100644 --- a/contrib/llvm/include/llvm/Support/ELF.h +++ b/contrib/llvm/include/llvm/Support/ELF.h @@ -1087,6 +1087,94 @@ enum { R_390_IRELATIVE = 61 }; +// ELF Relocation type for Sparc. +enum { + R_SPARC_NONE = 0, + R_SPARC_8 = 1, + R_SPARC_16 = 2, + R_SPARC_32 = 3, + R_SPARC_DISP8 = 4, + R_SPARC_DISP16 = 5, + R_SPARC_DISP32 = 6, + R_SPARC_WDISP30 = 7, + R_SPARC_WDISP22 = 8, + R_SPARC_HI22 = 9, + R_SPARC_22 = 10, + R_SPARC_13 = 11, + R_SPARC_LO10 = 12, + R_SPARC_GOT10 = 13, + R_SPARC_GOT13 = 14, + R_SPARC_GOT22 = 15, + R_SPARC_PC10 = 16, + R_SPARC_PC22 = 17, + R_SPARC_WPLT30 = 18, + R_SPARC_COPY = 19, + R_SPARC_GLOB_DAT = 20, + R_SPARC_JMP_SLOT = 21, + R_SPARC_RELATIVE = 22, + R_SPARC_UA32 = 23, + R_SPARC_PLT32 = 24, + R_SPARC_HIPLT22 = 25, + R_SPARC_LOPLT10 = 26, + R_SPARC_PCPLT32 = 27, + R_SPARC_PCPLT22 = 28, + R_SPARC_PCPLT10 = 29, + R_SPARC_10 = 30, + R_SPARC_11 = 31, + R_SPARC_64 = 32, + R_SPARC_OLO10 = 33, + R_SPARC_HH22 = 34, + R_SPARC_HM10 = 35, + R_SPARC_LM22 = 36, + R_SPARC_PC_HH22 = 37, + R_SPARC_PC_HM10 = 38, + R_SPARC_PC_LM22 = 39, + R_SPARC_WDISP16 = 40, + R_SPARC_WDISP19 = 41, + R_SPARC_7 = 43, + R_SPARC_5 = 44, + R_SPARC_6 = 45, + R_SPARC_DISP64 = 46, + R_SPARC_PLT64 = 47, + R_SPARC_HIX22 = 48, + R_SPARC_LOX10 = 49, + R_SPARC_H44 = 50, + R_SPARC_M44 = 51, + R_SPARC_L44 = 52, + R_SPARC_REGISTER = 53, + R_SPARC_UA64 = 54, + R_SPARC_UA16 = 55, + R_SPARC_TLS_GD_HI22 = 56, + R_SPARC_TLS_GD_LO10 = 57, + R_SPARC_TLS_GD_ADD = 58, + R_SPARC_TLS_GD_CALL = 59, + R_SPARC_TLS_LDM_HI22 = 60, + R_SPARC_TLS_LDM_LO10 = 61, + R_SPARC_TLS_LDM_ADD = 62, + R_SPARC_TLS_LDM_CALL = 63, + R_SPARC_TLS_LDO_HIX22 = 64, + R_SPARC_TLS_LDO_LOX10 = 65, + R_SPARC_TLS_LDO_ADD = 66, + R_SPARC_TLS_IE_HI22 = 67, + R_SPARC_TLS_IE_LO10 = 68, + R_SPARC_TLS_IE_LD = 69, + R_SPARC_TLS_IE_LDX = 70, + R_SPARC_TLS_IE_ADD = 71, + R_SPARC_TLS_LE_HIX22 = 72, + R_SPARC_TLS_LE_LOX10 = 73, + R_SPARC_TLS_DTPMOD32 = 74, + R_SPARC_TLS_DTPMOD64 = 75, + R_SPARC_TLS_DTPOFF32 = 76, + R_SPARC_TLS_DTPOFF64 = 77, + R_SPARC_TLS_TPOFF32 = 78, + R_SPARC_TLS_TPOFF64 = 79, + R_SPARC_GOTDATA_HIX22 = 80, + R_SPARC_GOTDATA_LOX22 = 81, + R_SPARC_GOTDATA_OP_HIX22 = 82, + R_SPARC_GOTDATA_OP_LOX22 = 83, + R_SPARC_GOTDATA_OP = 84 +}; + // Section header. struct Elf32_Shdr { Elf32_Word sh_name; // Section name (index into string table) diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 308b0e0..d5c6713 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -23,6 +23,7 @@ #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBundle.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" @@ -2221,14 +2222,13 @@ isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const { if (!MI.isBranch() || MI.isIndirectBranch()) return false; - // If we are the operands of one of the branches, this is not - // a fall through. - for (MachineInstr::mop_iterator OI = MI.operands_begin(), - OE = MI.operands_end(); OI != OE; ++OI) { - const MachineOperand& OP = *OI; - if (OP.isJTI()) + // If we are the operands of one of the branches, this is not a fall + // through. Note that targets with delay slots will usually bundle + // terminators with the delay slot instruction. + for (ConstMIBundleOperands OP(&MI); OP.isValid(); ++OP) { + if (OP->isJTI()) return false; - if (OP.isMBB() && OP.getMBB() == MBB) + if (OP->isMBB() && OP->getMBB() == MBB) return false; } } diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp index 3a8fb85..856ef34 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -220,10 +220,19 @@ void InstrEmitter::CreateVirtualRegisters(SDNode *Node, unsigned VRBase = 0; const TargetRegisterClass *RC = TRI->getAllocatableClass(TII->getRegClass(II, i, TRI, *MF)); - // If the register class is unknown for the given definition, then try to - // infer one from the value type. - if (!RC && i < NumResults) - RC = TLI->getRegClassFor(Node->getSimpleValueType(i)); + // Always let the value type influence the used register class. The + // constraints on the instruction may be too lax to represent the value + // type correctly. For example, a 64-bit float (X86::FR64) can't live in + // the 32-bit float super-class (X86::FR32). + if (i < NumResults && TLI->isTypeLegal(Node->getSimpleValueType(i))) { + const TargetRegisterClass *VTRC = + TLI->getRegClassFor(Node->getSimpleValueType(i)); + if (RC) + VTRC = TRI->getCommonSubClass(RC, VTRC); + if (VTRC) + RC = VTRC; + } + if (II.OpInfo[i].isOptionalDef()) { // Optional def must be a physical register. unsigned NumResults = CountResults(Node); diff --git a/contrib/llvm/lib/MC/MCObjectFileInfo.cpp b/contrib/llvm/lib/MC/MCObjectFileInfo.cpp index 8ef4a0a..799e061 100644 --- a/contrib/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/contrib/llvm/lib/MC/MCObjectFileInfo.cpp @@ -310,6 +310,33 @@ void MCObjectFileInfo::InitELFMCObjectFileInfo(Triple T) { FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8; TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8; + } else if (T.getArch() == Triple::sparc) { + if (RelocM == Reloc::PIC_) { + LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata4; + FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata4; + } else { + LSDAEncoding = dwarf::DW_EH_PE_absptr; + PersonalityEncoding = dwarf::DW_EH_PE_absptr; + FDEEncoding = dwarf::DW_EH_PE_udata4; + TTypeEncoding = dwarf::DW_EH_PE_absptr; + } + } else if (T.getArch() == Triple::sparcv9) { + LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + if (RelocM == Reloc::PIC_) { + PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata4; + FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata4; + } else { + PersonalityEncoding = dwarf::DW_EH_PE_absptr; + FDEEncoding = dwarf::DW_EH_PE_udata4; + TTypeEncoding = dwarf::DW_EH_PE_absptr; + } } else if (T.getArch() == Triple::systemz) { // All currently-defined code models guarantee that 4-byte PC-relative // values will be in range. diff --git a/contrib/llvm/lib/Object/ELF.cpp b/contrib/llvm/lib/Object/ELF.cpp index 7c80d41..6ef8d32 100644 --- a/contrib/llvm/lib/Object/ELF.cpp +++ b/contrib/llvm/lib/Object/ELF.cpp @@ -702,6 +702,98 @@ StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type) { break; } break; + case ELF::EM_SPARC: + case ELF::EM_SPARC32PLUS: + case ELF::EM_SPARCV9: + switch (Type) { + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_NONE); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_8); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_16); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_32); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP8); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP16); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP32); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP30); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HI22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_13); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LO10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT13); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WPLT30); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_COPY); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GLOB_DAT); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_JMP_SLOT); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_RELATIVE); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA32); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PLT32); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HIPLT22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LOPLT10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT32); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_11); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_OLO10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HH22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HM10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LM22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_HH22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_HM10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_LM22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP16); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP19); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_7); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_5); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_6); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PLT64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HIX22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LOX10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_H44); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_M44); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_L44); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_REGISTER); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA16); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_HI22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_LO10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_ADD); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_CALL); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_HI22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_LO10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_ADD); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_CALL); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_HIX22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_LOX10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_ADD); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_HI22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LO10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LD); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LDX); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_ADD); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LE_HIX22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LE_LOX10); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPMOD32); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPMOD64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPOFF32); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPOFF64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_TPOFF32); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_TPOFF64); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_HIX22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_LOX22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP_HIX22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP_LOX22); + LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP); + default: + break; + } + break; default: break; } diff --git a/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp b/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp index 76a0a83..f3be818 100644 --- a/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -156,7 +156,7 @@ void ARMTargetLowering::addDRTypeForNEON(MVT VT) { } void ARMTargetLowering::addQRTypeForNEON(MVT VT) { - addRegisterClass(VT, &ARM::QPRRegClass); + addRegisterClass(VT, &ARM::DPairRegClass); addTypeForNEON(VT, MVT::v2f64, MVT::v4i32); } diff --git a/contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp new file mode 100644 index 0000000..e7addd7 --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -0,0 +1,828 @@ +//===-- SparcAsmParser.cpp - Parse Sparc assembly to MCInst instructions --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SparcMCTargetDesc.h" +#include "MCTargetDesc/SparcMCExpr.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +// The generated AsmMatcher SparcGenAsmMatcher uses "Sparc" as the target +// namespace. But SPARC backend uses "SP" as its namespace. +namespace llvm { + namespace Sparc { + using namespace SP; + } +} + +namespace { +class SparcOperand; +class SparcAsmParser : public MCTargetAsmParser { + + MCSubtargetInfo &STI; + MCAsmParser &Parser; + + /// @name Auto-generated Match Functions + /// { + +#define GET_ASSEMBLER_HEADER +#include "SparcGenAsmMatcher.inc" + + /// } + + // public interface of the MCTargetAsmParser. + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + SmallVectorImpl<MCParsedAsmOperand*> &Operands, + MCStreamer &Out, unsigned &ErrorInfo, + bool MatchingInlineAsm); + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands); + bool ParseDirective(AsmToken DirectiveID); + + virtual unsigned validateTargetOperandClass(MCParsedAsmOperand *Op, + unsigned Kind); + + // Custom parse functions for Sparc specific operands. + OperandMatchResultTy + parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands); + + OperandMatchResultTy + parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + StringRef Name); + + OperandMatchResultTy + parseSparcAsmOperand(SparcOperand *&Operand); + + // returns true if Tok is matched to a register and returns register in RegNo. + bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, + unsigned &RegKind); + + bool matchSparcAsmModifiers(const MCExpr *&EVal, SMLoc &EndLoc); + +public: + SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, + const MCInstrInfo &MII) + : MCTargetAsmParser(), STI(sti), Parser(parser) { + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + } + +}; + + static unsigned IntRegs[32] = { + Sparc::G0, Sparc::G1, Sparc::G2, Sparc::G3, + Sparc::G4, Sparc::G5, Sparc::G6, Sparc::G7, + Sparc::O0, Sparc::O1, Sparc::O2, Sparc::O3, + Sparc::O4, Sparc::O5, Sparc::O6, Sparc::O7, + Sparc::L0, Sparc::L1, Sparc::L2, Sparc::L3, + Sparc::L4, Sparc::L5, Sparc::L6, Sparc::L7, + Sparc::I0, Sparc::I1, Sparc::I2, Sparc::I3, + Sparc::I4, Sparc::I5, Sparc::I6, Sparc::I7 }; + + static unsigned FloatRegs[32] = { + Sparc::F0, Sparc::F1, Sparc::F2, Sparc::F3, + Sparc::F4, Sparc::F5, Sparc::F6, Sparc::F7, + Sparc::F8, Sparc::F9, Sparc::F10, Sparc::F11, + Sparc::F12, Sparc::F13, Sparc::F14, Sparc::F15, + Sparc::F16, Sparc::F17, Sparc::F18, Sparc::F19, + Sparc::F20, Sparc::F21, Sparc::F22, Sparc::F23, + Sparc::F24, Sparc::F25, Sparc::F26, Sparc::F27, + Sparc::F28, Sparc::F29, Sparc::F30, Sparc::F31 }; + + static unsigned DoubleRegs[32] = { + Sparc::D0, Sparc::D1, Sparc::D2, Sparc::D3, + Sparc::D4, Sparc::D5, Sparc::D6, Sparc::D7, + Sparc::D8, Sparc::D7, Sparc::D8, Sparc::D9, + Sparc::D12, Sparc::D13, Sparc::D14, Sparc::D15, + Sparc::D16, Sparc::D17, Sparc::D18, Sparc::D19, + Sparc::D20, Sparc::D21, Sparc::D22, Sparc::D23, + Sparc::D24, Sparc::D25, Sparc::D26, Sparc::D27, + Sparc::D28, Sparc::D29, Sparc::D30, Sparc::D31 }; + + static unsigned QuadFPRegs[32] = { + Sparc::Q0, Sparc::Q1, Sparc::Q2, Sparc::Q3, + Sparc::Q4, Sparc::Q5, Sparc::Q6, Sparc::Q7, + Sparc::Q8, Sparc::Q9, Sparc::Q10, Sparc::Q11, + Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 }; + + +/// SparcOperand - Instances of this class represent a parsed Sparc machine +/// instruction. +class SparcOperand : public MCParsedAsmOperand { +public: + enum RegisterKind { + rk_None, + rk_IntReg, + rk_FloatReg, + rk_DoubleReg, + rk_QuadReg, + rk_CCReg, + rk_Y + }; +private: + enum KindTy { + k_Token, + k_Register, + k_Immediate, + k_MemoryReg, + k_MemoryImm + } Kind; + + SMLoc StartLoc, EndLoc; + + SparcOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} + + struct Token { + const char *Data; + unsigned Length; + }; + + struct RegOp { + unsigned RegNum; + RegisterKind Kind; + }; + + struct ImmOp { + const MCExpr *Val; + }; + + struct MemOp { + unsigned Base; + unsigned OffsetReg; + const MCExpr *Off; + }; + + union { + struct Token Tok; + struct RegOp Reg; + struct ImmOp Imm; + struct MemOp Mem; + }; +public: + bool isToken() const { return Kind == k_Token; } + bool isReg() const { return Kind == k_Register; } + bool isImm() const { return Kind == k_Immediate; } + bool isMem() const { return isMEMrr() || isMEMri(); } + bool isMEMrr() const { return Kind == k_MemoryReg; } + bool isMEMri() const { return Kind == k_MemoryImm; } + + bool isFloatReg() const { + return (Kind == k_Register && Reg.Kind == rk_FloatReg); + } + + bool isFloatOrDoubleReg() const { + return (Kind == k_Register && (Reg.Kind == rk_FloatReg + || Reg.Kind == rk_DoubleReg)); + } + + + StringRef getToken() const { + assert(Kind == k_Token && "Invalid access!"); + return StringRef(Tok.Data, Tok.Length); + } + + unsigned getReg() const { + assert((Kind == k_Register) && "Invalid access!"); + return Reg.RegNum; + } + + const MCExpr *getImm() const { + assert((Kind == k_Immediate) && "Invalid access!"); + return Imm.Val; + } + + unsigned getMemBase() const { + assert((Kind == k_MemoryReg || Kind == k_MemoryImm) && "Invalid access!"); + return Mem.Base; + } + + unsigned getMemOffsetReg() const { + assert((Kind == k_MemoryReg) && "Invalid access!"); + return Mem.OffsetReg; + } + + const MCExpr *getMemOff() const { + assert((Kind == k_MemoryImm) && "Invalid access!"); + return Mem.Off; + } + + /// getStartLoc - Get the location of the first token of this operand. + SMLoc getStartLoc() const { + return StartLoc; + } + /// getEndLoc - Get the location of the last token of this operand. + SMLoc getEndLoc() const { + return EndLoc; + } + + virtual void print(raw_ostream &OS) const { + switch (Kind) { + case k_Token: OS << "Token: " << getToken() << "\n"; break; + case k_Register: OS << "Reg: #" << getReg() << "\n"; break; + case k_Immediate: OS << "Imm: " << getImm() << "\n"; break; + case k_MemoryReg: OS << "Mem: " << getMemBase() << "+" + << getMemOffsetReg() << "\n"; break; + case k_MemoryImm: assert(getMemOff() != 0); + OS << "Mem: " << getMemBase() + << "+" << *getMemOff() + << "\n"; break; + } + } + + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(getReg())); + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCExpr *Expr = getImm(); + addExpr(Inst, Expr); + } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const{ + // Add as immediate when possible. Null MCExpr = 0. + if (Expr == 0) + Inst.addOperand(MCOperand::CreateImm(0)); + else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr)) + Inst.addOperand(MCOperand::CreateImm(CE->getValue())); + else + Inst.addOperand(MCOperand::CreateExpr(Expr)); + } + + void addMEMrrOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::CreateReg(getMemBase())); + + assert(getMemOffsetReg() != 0 && "Invalid offset"); + Inst.addOperand(MCOperand::CreateReg(getMemOffsetReg())); + } + + void addMEMriOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::CreateReg(getMemBase())); + + const MCExpr *Expr = getMemOff(); + addExpr(Inst, Expr); + } + + static SparcOperand *CreateToken(StringRef Str, SMLoc S) { + SparcOperand *Op = new SparcOperand(k_Token); + Op->Tok.Data = Str.data(); + Op->Tok.Length = Str.size(); + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static SparcOperand *CreateReg(unsigned RegNum, + unsigned Kind, + SMLoc S, SMLoc E) { + SparcOperand *Op = new SparcOperand(k_Register); + Op->Reg.RegNum = RegNum; + Op->Reg.Kind = (SparcOperand::RegisterKind)Kind; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static SparcOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) { + SparcOperand *Op = new SparcOperand(k_Immediate); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static SparcOperand *MorphToDoubleReg(SparcOperand *Op) { + unsigned Reg = Op->getReg(); + assert(Op->Reg.Kind == rk_FloatReg); + unsigned regIdx = Reg - Sparc::F0; + if (regIdx % 2 || regIdx > 31) + return 0; + Op->Reg.RegNum = DoubleRegs[regIdx / 2]; + Op->Reg.Kind = rk_DoubleReg; + return Op; + } + + static SparcOperand *MorphToQuadReg(SparcOperand *Op) { + unsigned Reg = Op->getReg(); + unsigned regIdx = 0; + switch (Op->Reg.Kind) { + default: assert(0 && "Unexpected register kind!"); + case rk_FloatReg: + regIdx = Reg - Sparc::F0; + if (regIdx % 4 || regIdx > 31) + return 0; + Reg = QuadFPRegs[regIdx / 4]; + break; + case rk_DoubleReg: + regIdx = Reg - Sparc::D0; + if (regIdx % 2 || regIdx > 31) + return 0; + Reg = QuadFPRegs[regIdx / 2]; + break; + } + Op->Reg.RegNum = Reg; + Op->Reg.Kind = rk_QuadReg; + return Op; + } + + static SparcOperand *MorphToMEMrr(unsigned Base, SparcOperand *Op) { + unsigned offsetReg = Op->getReg(); + Op->Kind = k_MemoryReg; + Op->Mem.Base = Base; + Op->Mem.OffsetReg = offsetReg; + Op->Mem.Off = 0; + return Op; + } + + static SparcOperand *CreateMEMri(unsigned Base, + const MCExpr *Off, + SMLoc S, SMLoc E) { + SparcOperand *Op = new SparcOperand(k_MemoryImm); + Op->Mem.Base = Base; + Op->Mem.OffsetReg = 0; + Op->Mem.Off = Off; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static SparcOperand *MorphToMEMri(unsigned Base, SparcOperand *Op) { + const MCExpr *Imm = Op->getImm(); + Op->Kind = k_MemoryImm; + Op->Mem.Base = Base; + Op->Mem.OffsetReg = 0; + Op->Mem.Off = Imm; + return Op; + } +}; + +} // end namespace + +bool SparcAsmParser:: +MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + SmallVectorImpl<MCParsedAsmOperand*> &Operands, + MCStreamer &Out, unsigned &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; + SmallVector<MCInst, 8> Instructions; + unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo, + MatchingInlineAsm); + switch (MatchResult) { + default: + break; + + case Match_Success: { + Inst.setLoc(IDLoc); + Out.EmitInstruction(Inst); + return false; + } + + case Match_MissingFeature: + return Error(IDLoc, + "instruction requires a CPU feature not currently enabled"); + + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0U) { + if (ErrorInfo >= Operands.size()) + return Error(IDLoc, "too few operands for instruction"); + + ErrorLoc = ((SparcOperand*) Operands[ErrorInfo])->getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + + return Error(ErrorLoc, "invalid operand for instruction"); + } + case Match_MnemonicFail: + return Error(IDLoc, "invalid instruction"); + } + return true; +} + +bool SparcAsmParser:: +ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) +{ + const AsmToken &Tok = Parser.getTok(); + StartLoc = Tok.getLoc(); + EndLoc = Tok.getEndLoc(); + RegNo = 0; + if (getLexer().getKind() != AsmToken::Percent) + return false; + Parser.Lex(); + unsigned regKind = SparcOperand::rk_None; + if (matchRegisterName(Tok, RegNo, regKind)) { + Parser.Lex(); + return false; + } + + return Error(StartLoc, "invalid register name"); +} + +bool SparcAsmParser:: +ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, + SmallVectorImpl<MCParsedAsmOperand*> &Operands) +{ + // Check if we have valid mnemonic. + if (!mnemonicIsValid(Name, 0)) { + Parser.eatToEndOfStatement(); + return Error(NameLoc, "Unknown instruction"); + } + // First operand in MCInst is instruction mnemonic. + Operands.push_back(SparcOperand::CreateToken(Name, NameLoc)); + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + // Read the first operand. + if (parseOperand(Operands, Name) != MatchOperand_Success) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token"); + } + + while (getLexer().is(AsmToken::Comma)) { + Parser.Lex(); // Eat the comma. + // Parse and remember the operand. + if (parseOperand(Operands, Name) != MatchOperand_Success) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token"); + } + } + } + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token"); + } + Parser.Lex(); // Consume the EndOfStatement. + return false; +} + +bool SparcAsmParser:: +ParseDirective(AsmToken DirectiveID) +{ + // Ignore all directives for now. + Parser.eatToEndOfStatement(); + return false; +} + +SparcAsmParser::OperandMatchResultTy SparcAsmParser:: +parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) +{ + + SMLoc S, E; + unsigned BaseReg = 0; + + if (ParseRegister(BaseReg, S, E)) { + return MatchOperand_NoMatch; + } + + switch (getLexer().getKind()) { + default: return MatchOperand_NoMatch; + + case AsmToken::Comma: + case AsmToken::RBrac: + case AsmToken::EndOfStatement: + Operands.push_back(SparcOperand::CreateMEMri(BaseReg, 0, S, E)); + return MatchOperand_Success; + + case AsmToken:: Plus: + Parser.Lex(); // Eat the '+' + break; + case AsmToken::Minus: + break; + } + + SparcOperand *Offset = 0; + OperandMatchResultTy ResTy = parseSparcAsmOperand(Offset); + if (ResTy != MatchOperand_Success || !Offset) + return MatchOperand_NoMatch; + + Offset = (Offset->isImm() + ? SparcOperand::MorphToMEMri(BaseReg, Offset) + : SparcOperand::MorphToMEMrr(BaseReg, Offset)); + + Operands.push_back(Offset); + return MatchOperand_Success; +} + +SparcAsmParser::OperandMatchResultTy SparcAsmParser:: +parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + StringRef Mnemonic) +{ + + OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); + + // If there wasn't a custom match, try the generic matcher below. Otherwise, + // there was a match, but an error occurred, in which case, just return that + // the operand parsing failed. + if (ResTy == MatchOperand_Success || ResTy == MatchOperand_ParseFail) + return ResTy; + + if (getLexer().is(AsmToken::LBrac)) { + // Memory operand + Operands.push_back(SparcOperand::CreateToken("[", + Parser.getTok().getLoc())); + Parser.Lex(); // Eat the [ + + if (Mnemonic == "cas" || Mnemonic == "casx") { + SMLoc S = Parser.getTok().getLoc(); + if (getLexer().getKind() != AsmToken::Percent) + return MatchOperand_NoMatch; + Parser.Lex(); // eat % + + unsigned RegNo, RegKind; + if (!matchRegisterName(Parser.getTok(), RegNo, RegKind)) + return MatchOperand_NoMatch; + + Parser.Lex(); // Eat the identifier token. + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer()-1); + Operands.push_back(SparcOperand::CreateReg(RegNo, RegKind, S, E)); + ResTy = MatchOperand_Success; + } else { + ResTy = parseMEMOperand(Operands); + } + + if (ResTy != MatchOperand_Success) + return ResTy; + + if (!getLexer().is(AsmToken::RBrac)) + return MatchOperand_ParseFail; + + Operands.push_back(SparcOperand::CreateToken("]", + Parser.getTok().getLoc())); + Parser.Lex(); // Eat the ] + return MatchOperand_Success; + } + + SparcOperand *Op = 0; + ResTy = parseSparcAsmOperand(Op); + if (ResTy != MatchOperand_Success || !Op) + return MatchOperand_ParseFail; + + // Push the parsed operand into the list of operands + Operands.push_back(Op); + + return MatchOperand_Success; +} + +SparcAsmParser::OperandMatchResultTy +SparcAsmParser::parseSparcAsmOperand(SparcOperand *&Op) +{ + + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + const MCExpr *EVal; + + Op = 0; + switch (getLexer().getKind()) { + default: break; + + case AsmToken::Percent: + Parser.Lex(); // Eat the '%'. + unsigned RegNo; + unsigned RegKind; + if (matchRegisterName(Parser.getTok(), RegNo, RegKind)) { + StringRef name = Parser.getTok().getString(); + Parser.Lex(); // Eat the identifier token. + E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + switch (RegNo) { + default: + Op = SparcOperand::CreateReg(RegNo, RegKind, S, E); + break; + case Sparc::Y: + Op = SparcOperand::CreateToken("%y", S); + break; + + case Sparc::ICC: + if (name == "xcc") + Op = SparcOperand::CreateToken("%xcc", S); + else + Op = SparcOperand::CreateToken("%icc", S); + break; + + case Sparc::FCC: + assert(name == "fcc0" && "Cannot handle %fcc other than %fcc0 yet"); + Op = SparcOperand::CreateToken("%fcc0", S); + break; + } + break; + } + if (matchSparcAsmModifiers(EVal, E)) { + E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Op = SparcOperand::CreateImm(EVal, S, E); + } + break; + + case AsmToken::Minus: + case AsmToken::Integer: + if (!getParser().parseExpression(EVal, E)) + Op = SparcOperand::CreateImm(EVal, S, E); + break; + + case AsmToken::Identifier: { + StringRef Identifier; + if (!getParser().parseIdentifier(Identifier)) { + E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier); + + const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, + getContext()); + Op = SparcOperand::CreateImm(Res, S, E); + } + break; + } + } + return (Op) ? MatchOperand_Success : MatchOperand_ParseFail; +} + +bool SparcAsmParser::matchRegisterName(const AsmToken &Tok, + unsigned &RegNo, + unsigned &RegKind) +{ + int64_t intVal = 0; + RegNo = 0; + RegKind = SparcOperand::rk_None; + if (Tok.is(AsmToken::Identifier)) { + StringRef name = Tok.getString(); + + // %fp + if (name.equals("fp")) { + RegNo = Sparc::I6; + RegKind = SparcOperand::rk_IntReg; + return true; + } + // %sp + if (name.equals("sp")) { + RegNo = Sparc::O6; + RegKind = SparcOperand::rk_IntReg; + return true; + } + + if (name.equals("y")) { + RegNo = Sparc::Y; + RegKind = SparcOperand::rk_Y; + return true; + } + + if (name.equals("icc")) { + RegNo = Sparc::ICC; + RegKind = SparcOperand::rk_CCReg; + return true; + } + + if (name.equals("xcc")) { + // FIXME:: check 64bit. + RegNo = Sparc::ICC; + RegKind = SparcOperand::rk_CCReg; + return true; + } + + // %fcc0 - %fcc3 + if (name.substr(0, 3).equals_lower("fcc") + && !name.substr(3).getAsInteger(10, intVal) + && intVal < 4) { + // FIXME: check 64bit and handle %fcc1 - %fcc3 + RegNo = Sparc::FCC; + RegKind = SparcOperand::rk_CCReg; + return true; + } + + // %g0 - %g7 + if (name.substr(0, 1).equals_lower("g") + && !name.substr(1).getAsInteger(10, intVal) + && intVal < 8) { + RegNo = IntRegs[intVal]; + RegKind = SparcOperand::rk_IntReg; + return true; + } + // %o0 - %o7 + if (name.substr(0, 1).equals_lower("o") + && !name.substr(1).getAsInteger(10, intVal) + && intVal < 8) { + RegNo = IntRegs[8 + intVal]; + RegKind = SparcOperand::rk_IntReg; + return true; + } + if (name.substr(0, 1).equals_lower("l") + && !name.substr(1).getAsInteger(10, intVal) + && intVal < 8) { + RegNo = IntRegs[16 + intVal]; + RegKind = SparcOperand::rk_IntReg; + return true; + } + if (name.substr(0, 1).equals_lower("i") + && !name.substr(1).getAsInteger(10, intVal) + && intVal < 8) { + RegNo = IntRegs[24 + intVal]; + RegKind = SparcOperand::rk_IntReg; + return true; + } + // %f0 - %f31 + if (name.substr(0, 1).equals_lower("f") + && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 32) { + RegNo = FloatRegs[intVal]; + RegKind = SparcOperand::rk_FloatReg; + return true; + } + // %f32 - %f62 + if (name.substr(0, 1).equals_lower("f") + && !name.substr(1, 2).getAsInteger(10, intVal) + && intVal >= 32 && intVal <= 62 && (intVal % 2 == 0)) { + // FIXME: Check V9 + RegNo = DoubleRegs[intVal/2]; + RegKind = SparcOperand::rk_DoubleReg; + return true; + } + + // %r0 - %r31 + if (name.substr(0, 1).equals_lower("r") + && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 31) { + RegNo = IntRegs[intVal]; + RegKind = SparcOperand::rk_IntReg; + return true; + } + } + return false; +} + + +bool SparcAsmParser::matchSparcAsmModifiers(const MCExpr *&EVal, + SMLoc &EndLoc) +{ + AsmToken Tok = Parser.getTok(); + if (!Tok.is(AsmToken::Identifier)) + return false; + + StringRef name = Tok.getString(); + + SparcMCExpr::VariantKind VK = SparcMCExpr::parseVariantKind(name); + + if (VK == SparcMCExpr::VK_Sparc_None) + return false; + + Parser.Lex(); // Eat the identifier. + if (Parser.getTok().getKind() != AsmToken::LParen) + return false; + + Parser.Lex(); // Eat the LParen token. + const MCExpr *subExpr; + if (Parser.parseParenExpression(subExpr, EndLoc)) + return false; + EVal = SparcMCExpr::Create(VK, subExpr, getContext()); + return true; +} + + +extern "C" void LLVMInitializeSparcAsmParser() { + RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget); + RegisterMCAsmParser<SparcAsmParser> B(TheSparcV9Target); +} + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "SparcGenAsmMatcher.inc" + + + +unsigned SparcAsmParser:: +validateTargetOperandClass(MCParsedAsmOperand *GOp, + unsigned Kind) +{ + SparcOperand *Op = (SparcOperand*)GOp; + if (Op->isFloatOrDoubleReg()) { + switch (Kind) { + default: break; + case MCK_DFPRegs: + if (!Op->isFloatReg() || SparcOperand::MorphToDoubleReg(Op)) + return MCTargetAsmParser::Match_Success; + break; + case MCK_QFPRegs: + if (SparcOperand::MorphToQuadReg(Op)) + return MCTargetAsmParser::Match_Success; + break; + } + } + return Match_InvalidOperand; +} diff --git a/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp b/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp index 9a0466a..f23ddc2 100644 --- a/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp +++ b/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" @@ -55,15 +56,17 @@ namespace { bool runOnMachineBasicBlock(MachineBasicBlock &MBB); bool runOnMachineFunction(MachineFunction &F) { bool Changed = false; + + // This pass invalidates liveness information when it reorders + // instructions to fill delay slot. + F.getRegInfo().invalidateLiveness(); + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) Changed |= runOnMachineBasicBlock(*FI); return Changed; } - bool isDelayFiller(MachineBasicBlock &MBB, - MachineBasicBlock::iterator candidate); - void insertCallDefsUses(MachineBasicBlock::iterator MI, SmallSet<unsigned, 32>& RegDefs, SmallSet<unsigned, 32>& RegUses); @@ -152,6 +155,10 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { assert (J != MBB.end() && "MI needs a delay instruction."); BuildMI(MBB, ++J, MI->getDebugLoc(), TII->get(SP::UNIMP)).addImm(structSize); + // Bundle the delay filler and unimp with the instruction. + MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), J); + } else { + MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), I); } } return Changed; @@ -209,7 +216,7 @@ Filler::findDelayInstr(MachineBasicBlock &MBB, || I->isInlineAsm() || I->isLabel() || I->hasDelaySlot() - || isDelayFiller(MBB, I)) + || I->isBundledWithSucc()) break; if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) { @@ -278,19 +285,19 @@ void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI, switch(MI->getOpcode()) { default: llvm_unreachable("Unknown opcode."); case SP::CALL: break; - case SP::JMPLrr: - case SP::JMPLri: + case SP::CALLrr: + case SP::CALLri: assert(MI->getNumOperands() >= 2); const MachineOperand &Reg = MI->getOperand(0); - assert(Reg.isReg() && "JMPL first operand is not a register."); - assert(Reg.isUse() && "JMPL first operand is not a use."); + assert(Reg.isReg() && "CALL first operand is not a register."); + assert(Reg.isUse() && "CALL first operand is not a use."); RegUses.insert(Reg.getReg()); const MachineOperand &RegOrImm = MI->getOperand(1); if (RegOrImm.isImm()) break; - assert(RegOrImm.isReg() && "JMPLrr second operand is not a register."); - assert(RegOrImm.isUse() && "JMPLrr second operand is not a use."); + assert(RegOrImm.isReg() && "CALLrr second operand is not a register."); + assert(RegOrImm.isUse() && "CALLrr second operand is not a use."); RegUses.insert(RegOrImm.getReg()); break; } @@ -332,18 +339,6 @@ bool Filler::IsRegInSet(SmallSet<unsigned, 32>& RegSet, unsigned Reg) return false; } -// return true if the candidate is a delay filler. -bool Filler::isDelayFiller(MachineBasicBlock &MBB, - MachineBasicBlock::iterator candidate) -{ - if (candidate == MBB.begin()) - return false; - if (candidate->getOpcode() == SP::UNIMP) - return true; - --candidate; - return candidate->hasDelaySlot(); -} - bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize) { if (!I->isCall()) @@ -353,8 +348,8 @@ bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize) switch (I->getOpcode()) { default: llvm_unreachable("Unknown call opcode."); case SP::CALL: structSizeOpNum = 1; break; - case SP::JMPLrr: - case SP::JMPLri: structSizeOpNum = 2; break; + case SP::CALLrr: + case SP::CALLri: structSizeOpNum = 2; break; case SP::TLS_CALL: return false; } @@ -484,10 +479,10 @@ bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB, && MBBI->getOperand(1).getReg() == SP::G0 && MBBI->getOperand(2).getReg() == SP::G0); - MachineBasicBlock::iterator PrevInst = MBBI; --PrevInst; + MachineBasicBlock::iterator PrevInst = llvm::prior(MBBI); - // It cannot combine with a delay filler. - if (isDelayFiller(MBB, PrevInst)) + // It cannot be combined with a bundled instruction. + if (PrevInst->isBundledWithSucc()) return false; const TargetInstrInfo *TII = TM.getInstrInfo(); diff --git a/contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp b/contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp new file mode 100644 index 0000000..6233805 --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp @@ -0,0 +1,228 @@ +//===- SparcDisassembler.cpp - Disassembler for Sparc -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the Sparc Disassembler. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sparc-disassembler" + +#include "Sparc.h" +#include "SparcRegisterInfo.h" +#include "SparcSubtarget.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCFixedLenDisassembler.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +typedef MCDisassembler::DecodeStatus DecodeStatus; + +namespace { + +/// SparcDisassembler - a disassembler class for Sparc. +class SparcDisassembler : public MCDisassembler { +public: + /// Constructor - Initializes the disassembler. + /// + SparcDisassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info) : + MCDisassembler(STI), RegInfo(Info) + {} + virtual ~SparcDisassembler() {} + + const MCRegisterInfo *getRegInfo() const { return RegInfo.get(); } + + /// getInstruction - See MCDisassembler. + virtual DecodeStatus getInstruction(MCInst &instr, + uint64_t &size, + const MemoryObject ®ion, + uint64_t address, + raw_ostream &vStream, + raw_ostream &cStream) const; +private: + OwningPtr<const MCRegisterInfo> RegInfo; +}; + +} + +namespace llvm { + extern Target TheSparcTarget, TheSparcV9Target; +} + +static MCDisassembler *createSparcDisassembler( + const Target &T, + const MCSubtargetInfo &STI) { + return new SparcDisassembler(STI, T.createMCRegInfo("")); +} + + +extern "C" void LLVMInitializeSparcDisassembler() { + // Register the disassembler. + TargetRegistry::RegisterMCDisassembler(TheSparcTarget, + createSparcDisassembler); + TargetRegistry::RegisterMCDisassembler(TheSparcV9Target, + createSparcDisassembler); +} + + + +static const unsigned IntRegDecoderTable[] = { + SP::G0, SP::G1, SP::G2, SP::G3, + SP::G4, SP::G5, SP::G6, SP::G7, + SP::O0, SP::O1, SP::O2, SP::O3, + SP::O4, SP::O5, SP::O6, SP::O7, + SP::L0, SP::L1, SP::L2, SP::L3, + SP::L4, SP::L5, SP::L6, SP::L7, + SP::I0, SP::I1, SP::I2, SP::I3, + SP::I4, SP::I5, SP::I6, SP::I7 }; + +static const unsigned FPRegDecoderTable[] = { + SP::F0, SP::F1, SP::F2, SP::F3, + SP::F4, SP::F5, SP::F6, SP::F7, + SP::F8, SP::F9, SP::F10, SP::F11, + SP::F12, SP::F13, SP::F14, SP::F15, + SP::F16, SP::F17, SP::F18, SP::F19, + SP::F20, SP::F21, SP::F22, SP::F23, + SP::F24, SP::F25, SP::F26, SP::F27, + SP::F28, SP::F29, SP::F30, SP::F31 }; + +static const unsigned DFPRegDecoderTable[] = { + SP::D0, SP::D16, SP::D1, SP::D17, + SP::D2, SP::D18, SP::D3, SP::D19, + SP::D4, SP::D20, SP::D5, SP::D21, + SP::D6, SP::D22, SP::D7, SP::D23, + SP::D8, SP::D24, SP::D9, SP::D25, + SP::D10, SP::D26, SP::D11, SP::D27, + SP::D12, SP::D28, SP::D13, SP::D29, + SP::D14, SP::D30, SP::D15, SP::D31 }; + +static const unsigned QFPRegDecoderTable[] = { + SP::Q0, SP::Q8, ~0U, ~0U, + SP::Q1, SP::Q9, ~0U, ~0U, + SP::Q2, SP::Q10, ~0U, ~0U, + SP::Q3, SP::Q11, ~0U, ~0U, + SP::Q4, SP::Q12, ~0U, ~0U, + SP::Q5, SP::Q13, ~0U, ~0U, + SP::Q6, SP::Q14, ~0U, ~0U, + SP::Q7, SP::Q15, ~0U, ~0U } ; + +static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = IntRegDecoderTable[RegNo]; + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus DecodeI64RegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = IntRegDecoderTable[RegNo]; + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + + +static DecodeStatus DecodeFPRegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = FPRegDecoderTable[RegNo]; + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + + +static DecodeStatus DecodeDFPRegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = DFPRegDecoderTable[RegNo]; + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + + +static DecodeStatus DecodeQFPRegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned Reg = QFPRegDecoderTable[RegNo]; + if (Reg == ~0U) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; +} + + +#include "SparcGenDisassemblerTables.inc" + +/// readInstruction - read four bytes from the MemoryObject +/// and return 32 bit word. +static DecodeStatus readInstruction32(const MemoryObject ®ion, + uint64_t address, + uint64_t &size, + uint32_t &insn) { + uint8_t Bytes[4]; + + // We want to read exactly 4 Bytes of data. + if (region.readBytes(address, 4, Bytes) == -1) { + size = 0; + return MCDisassembler::Fail; + } + + // Encoded as a big-endian 32-bit word in the stream. + insn = (Bytes[3] << 0) | + (Bytes[2] << 8) | + (Bytes[1] << 16) | + (Bytes[0] << 24); + + return MCDisassembler::Success; +} + + +DecodeStatus +SparcDisassembler::getInstruction(MCInst &instr, + uint64_t &Size, + const MemoryObject &Region, + uint64_t Address, + raw_ostream &vStream, + raw_ostream &cStream) const { + uint32_t Insn; + + DecodeStatus Result = readInstruction32(Region, Address, Size, Insn); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + + // Calling the auto-generated decoder function. + Result = decodeInstruction(DecoderTableSparc32, instr, Insn, Address, + this, STI); + + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + + return MCDisassembler::Fail; +} diff --git a/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp b/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp new file mode 100644 index 0000000..6d7457a --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp @@ -0,0 +1,129 @@ +//===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax -----==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an Sparc MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "SparcInstPrinter.h" + +#include "Sparc.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define GET_INSTRUCTION_NAME +#define PRINT_ALIAS_INSTR +#include "SparcGenAsmWriter.inc" + +void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const +{ + OS << '%' << StringRef(getRegisterName(RegNo)).lower(); +} + +void SparcInstPrinter::printInst(const MCInst *MI, raw_ostream &O, + StringRef Annot) +{ + if (!printAliasInstr(MI, O) && !printSparcAliasInstr(MI, O)) + printInstruction(MI, O); + printAnnotation(O, Annot); +} + +bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI, raw_ostream &O) +{ + switch (MI->getOpcode()) { + default: return false; + case SP::JMPLrr: + case SP::JMPLri: { + if (MI->getNumOperands() != 3) + return false; + if (!MI->getOperand(0).isReg()) + return false; + switch (MI->getOperand(0).getReg()) { + default: return false; + case SP::G0: // jmp $addr + O << "\tjmp "; printMemOperand(MI, 1, O); + return true; + case SP::O7: // call $addr + O << "\tcall "; printMemOperand(MI, 1, O); + return true; + } + } + } +} + +void SparcInstPrinter::printOperand(const MCInst *MI, int opNum, + raw_ostream &O) +{ + const MCOperand &MO = MI->getOperand (opNum); + + if (MO.isReg()) { + printRegName(O, MO.getReg()); + return ; + } + + if (MO.isImm()) { + O << (int)MO.getImm(); + return; + } + + assert(MO.isExpr() && "Unknown operand kind in printOperand"); + MO.getExpr()->print(O); +} + +void SparcInstPrinter::printMemOperand(const MCInst *MI, int opNum, + raw_ostream &O, const char *Modifier) +{ + printOperand(MI, opNum, O); + + // If this is an ADD operand, emit it like normal operands. + if (Modifier && !strcmp(Modifier, "arith")) { + O << ", "; + printOperand(MI, opNum+1, O); + return; + } + const MCOperand &MO = MI->getOperand(opNum+1); + + if (MO.isReg() && MO.getReg() == SP::G0) + return; // don't print "+%g0" + if (MO.isImm() && MO.getImm() == 0) + return; // don't print "+0" + + O << "+"; + + printOperand(MI, opNum+1, O); +} + +void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum, + raw_ostream &O) +{ + int CC = (int)MI->getOperand(opNum).getImm(); + switch (MI->getOpcode()) { + default: break; + case SP::FBCOND: + case SP::MOVFCCrr: + case SP::MOVFCCri: + case SP::FMOVS_FCC: + case SP::FMOVD_FCC: + case SP::FMOVQ_FCC: // Make sure CC is a fp conditional flag. + CC = (CC < 16) ? (CC + 16) : CC; + break; + } + O << SPARCCondCodeToString((SPCC::CondCodes)CC); +} + +bool SparcInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum, + raw_ostream &O) +{ + assert(0 && "FIXME: Implement SparcInstPrinter::printGetPCX."); + return true; +} diff --git a/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.h b/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.h new file mode 100644 index 0000000..63ed41a --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.h @@ -0,0 +1,48 @@ +//===-- SparcInstPrinter.h - Convert Sparc MCInst to assembly syntax ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an Sparc MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef SparcINSTPRINTER_H +#define SparcINSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { + +class MCOperand; + +class SparcInstPrinter : public MCInstPrinter { +public: + SparcInstPrinter(const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + virtual void printRegName(raw_ostream &OS, unsigned RegNo) const; + virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot); + bool printSparcAliasInstr(const MCInst *MI, raw_ostream &OS); + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI, raw_ostream &O); + bool printAliasInstr(const MCInst *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + void printOperand(const MCInst *MI, int opNum, raw_ostream &OS); + void printMemOperand(const MCInst *MI, int opNum, raw_ostream &OS, + const char *Modifier = 0); + void printCCOperand(const MCInst *MI, int opNum, raw_ostream &OS); + bool printGetPCX(const MCInst *MI, unsigned OpNo, raw_ostream &OS); + +}; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp new file mode 100644 index 0000000..6d2dd83 --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp @@ -0,0 +1,251 @@ +//===-- SparcAsmBackend.cpp - Sparc Assembler Backend ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmBackend.h" +#include "MCTargetDesc/SparcMCTargetDesc.h" +#include "MCTargetDesc/SparcFixupKinds.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + case FK_Data_1: + case FK_Data_2: + case FK_Data_4: + case FK_Data_8: + return Value; + + case Sparc::fixup_sparc_wplt30: + case Sparc::fixup_sparc_call30: + return (Value >> 2) & 0x3fffffff; + + case Sparc::fixup_sparc_br22: + return (Value >> 2) & 0x3fffff; + + case Sparc::fixup_sparc_br19: + return (Value >> 2) & 0x7ffff; + + case Sparc::fixup_sparc_pc22: + case Sparc::fixup_sparc_got22: + case Sparc::fixup_sparc_tls_gd_hi22: + case Sparc::fixup_sparc_tls_ldm_hi22: + case Sparc::fixup_sparc_tls_ie_hi22: + case Sparc::fixup_sparc_hi22: + return (Value >> 10) & 0x3fffff; + + case Sparc::fixup_sparc_pc10: + case Sparc::fixup_sparc_got10: + case Sparc::fixup_sparc_tls_gd_lo10: + case Sparc::fixup_sparc_tls_ldm_lo10: + case Sparc::fixup_sparc_tls_ie_lo10: + case Sparc::fixup_sparc_lo10: + return Value & 0x3ff; + + case Sparc::fixup_sparc_tls_ldo_hix22: + case Sparc::fixup_sparc_tls_le_hix22: + return (~Value >> 10) & 0x3fffff; + + case Sparc::fixup_sparc_tls_ldo_lox10: + case Sparc::fixup_sparc_tls_le_lox10: + return (~(~Value & 0x3ff)) & 0x1fff; + + case Sparc::fixup_sparc_h44: + return (Value >> 22) & 0x3fffff; + + case Sparc::fixup_sparc_m44: + return (Value >> 12) & 0x3ff; + + case Sparc::fixup_sparc_l44: + return Value & 0xfff; + + case Sparc::fixup_sparc_hh: + return (Value >> 42) & 0x3fffff; + + case Sparc::fixup_sparc_hm: + return (Value >> 32) & 0x3ff; + + case Sparc::fixup_sparc_tls_gd_add: + case Sparc::fixup_sparc_tls_gd_call: + case Sparc::fixup_sparc_tls_ldm_add: + case Sparc::fixup_sparc_tls_ldm_call: + case Sparc::fixup_sparc_tls_ldo_add: + case Sparc::fixup_sparc_tls_ie_ld: + case Sparc::fixup_sparc_tls_ie_ldx: + case Sparc::fixup_sparc_tls_ie_add: + return 0; + } +} + +namespace { + class SparcAsmBackend : public MCAsmBackend { + const Target &TheTarget; + public: + SparcAsmBackend(const Target &T) : MCAsmBackend(), TheTarget(T) {} + + unsigned getNumFixupKinds() const { + return Sparc::NumTargetFixupKinds; + } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { + const static MCFixupKindInfo Infos[Sparc::NumTargetFixupKinds] = { + // name offset bits flags + { "fixup_sparc_call30", 2, 30, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_sparc_br22", 10, 22, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_sparc_br19", 13, 19, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_sparc_hi22", 10, 22, 0 }, + { "fixup_sparc_lo10", 22, 10, 0 }, + { "fixup_sparc_h44", 10, 22, 0 }, + { "fixup_sparc_m44", 22, 10, 0 }, + { "fixup_sparc_l44", 20, 12, 0 }, + { "fixup_sparc_hh", 10, 22, 0 }, + { "fixup_sparc_hm", 22, 10, 0 }, + { "fixup_sparc_pc22", 10, 22, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_sparc_pc10", 22, 10, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_sparc_got22", 10, 22, 0 }, + { "fixup_sparc_got10", 22, 10, 0 }, + { "fixup_sparc_wplt30", 2, 30, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_sparc_tls_gd_hi22", 10, 22, 0 }, + { "fixup_sparc_tls_gd_lo10", 22, 10, 0 }, + { "fixup_sparc_tls_gd_add", 0, 0, 0 }, + { "fixup_sparc_tls_gd_call", 0, 0, 0 }, + { "fixup_sparc_tls_ldm_hi22", 10, 22, 0 }, + { "fixup_sparc_tls_ldm_lo10", 22, 10, 0 }, + { "fixup_sparc_tls_ldm_add", 0, 0, 0 }, + { "fixup_sparc_tls_ldm_call", 0, 0, 0 }, + { "fixup_sparc_tls_ldo_hix22", 10, 22, 0 }, + { "fixup_sparc_tls_ldo_lox10", 22, 10, 0 }, + { "fixup_sparc_tls_ldo_add", 0, 0, 0 }, + { "fixup_sparc_tls_ie_hi22", 10, 22, 0 }, + { "fixup_sparc_tls_ie_lo10", 22, 10, 0 }, + { "fixup_sparc_tls_ie_ld", 0, 0, 0 }, + { "fixup_sparc_tls_ie_ldx", 0, 0, 0 }, + { "fixup_sparc_tls_ie_add", 0, 0, 0 }, + { "fixup_sparc_tls_le_hix22", 0, 0, 0 }, + { "fixup_sparc_tls_le_lox10", 0, 0, 0 } + }; + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; + } + + void processFixupValue(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFixup &Fixup, + const MCFragment *DF, + MCValue & Target, + uint64_t &Value, + bool &IsResolved) { + switch ((Sparc::Fixups)Fixup.getKind()) { + default: break; + case Sparc::fixup_sparc_wplt30: + case Sparc::fixup_sparc_tls_gd_hi22: + case Sparc::fixup_sparc_tls_gd_lo10: + case Sparc::fixup_sparc_tls_gd_add: + case Sparc::fixup_sparc_tls_gd_call: + case Sparc::fixup_sparc_tls_ldm_hi22: + case Sparc::fixup_sparc_tls_ldm_lo10: + case Sparc::fixup_sparc_tls_ldm_add: + case Sparc::fixup_sparc_tls_ldm_call: + case Sparc::fixup_sparc_tls_ldo_hix22: + case Sparc::fixup_sparc_tls_ldo_lox10: + case Sparc::fixup_sparc_tls_ldo_add: + case Sparc::fixup_sparc_tls_ie_hi22: + case Sparc::fixup_sparc_tls_ie_lo10: + case Sparc::fixup_sparc_tls_ie_ld: + case Sparc::fixup_sparc_tls_ie_ldx: + case Sparc::fixup_sparc_tls_ie_add: + case Sparc::fixup_sparc_tls_le_hix22: + case Sparc::fixup_sparc_tls_le_lox10: IsResolved = false; break; + } + } + + bool mayNeedRelaxation(const MCInst &Inst) const { + // FIXME. + return false; + } + + /// fixupNeedsRelaxation - Target specific predicate for whether a given + /// fixup requires the associated instruction to be relaxed. + bool fixupNeedsRelaxation(const MCFixup &Fixup, + uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const { + // FIXME. + assert(0 && "fixupNeedsRelaxation() unimplemented"); + return false; + } + void relaxInstruction(const MCInst &Inst, MCInst &Res) const { + // FIXME. + assert(0 && "relaxInstruction() unimplemented"); + } + + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const { + // FIXME: Zero fill for now. + for (uint64_t i = 0; i != Count; ++i) + OW->Write8(0); + return true; + } + + bool is64Bit() const { + StringRef name = TheTarget.getName(); + return name == "sparcv9"; + } + }; + + class ELFSparcAsmBackend : public SparcAsmBackend { + Triple::OSType OSType; + public: + ELFSparcAsmBackend(const Target &T, Triple::OSType OSType) : + SparcAsmBackend(T), OSType(OSType) { } + + void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value) const { + + Value = adjustFixupValue(Fixup.getKind(), Value); + if (!Value) return; // Doesn't change encoding. + + unsigned Offset = Fixup.getOffset(); + + // For each byte of the fragment that the fixup touches, mask in the bits + // from the fixup value. The Value has been "split up" into the + // appropriate bitfields above. + for (unsigned i = 0; i != 4; ++i) + Data[Offset + i] |= uint8_t((Value >> ((4 - i - 1)*8)) & 0xff); + + } + + MCObjectWriter *createObjectWriter(raw_ostream &OS) const { + uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType); + return createSparcELFObjectWriter(OS, is64Bit(), OSABI); + } + + virtual bool doesSectionRequireSymbols(const MCSection &Section) const { + return false; + } + }; + +} // end anonymous namespace + + +MCAsmBackend *llvm::createSparcAsmBackend(const Target &T, + const MCRegisterInfo &MRI, + StringRef TT, + StringRef CPU) { + return new ELFSparcAsmBackend(T, Triple(TT).getOS()); +} diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h deleted file mode 100644 index f3caeaa..0000000 --- a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h +++ /dev/null @@ -1,82 +0,0 @@ -//===-- SparcBaseInfo.h - Top level definitions for Sparc ---- --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains small standalone helper functions and enum definitions -// for the Sparc target useful for the compiler back-end and the MC libraries. -// As such, it deliberately does not include references to LLVM core code gen -// types, passes, etc.. -// -//===----------------------------------------------------------------------===// - -#ifndef SPARCBASEINFO_H -#define SPARCBASEINFO_H - -namespace llvm { - -/// SPII - This namespace holds target specific flags for instruction info. -namespace SPII { - -/// Target Operand Flags. Sparc specific TargetFlags for MachineOperands and -/// SDNodes. -enum TOF { - MO_NO_FLAG, - - // Extract the low 10 bits of an address. - // Assembler: %lo(addr) - MO_LO, - - // Extract bits 31-10 of an address. Only for sethi. - // Assembler: %hi(addr) or %lm(addr) - MO_HI, - - // Extract bits 43-22 of an adress. Only for sethi. - // Assembler: %h44(addr) - MO_H44, - - // Extract bits 21-12 of an address. - // Assembler: %m44(addr) - MO_M44, - - // Extract bits 11-0 of an address. - // Assembler: %l44(addr) - MO_L44, - - // Extract bits 63-42 of an address. Only for sethi. - // Assembler: %hh(addr) - MO_HH, - - // Extract bits 41-32 of an address. - // Assembler: %hm(addr) - MO_HM, - - // TargetFlags for Thread Local Storage. - MO_TLS_GD_HI22, - MO_TLS_GD_LO10, - MO_TLS_GD_ADD, - MO_TLS_GD_CALL, - MO_TLS_LDM_HI22, - MO_TLS_LDM_LO10, - MO_TLS_LDM_ADD, - MO_TLS_LDM_CALL, - MO_TLS_LDO_HIX22, - MO_TLS_LDO_LOX10, - MO_TLS_LDO_ADD, - MO_TLS_IE_HI22, - MO_TLS_IE_LO10, - MO_TLS_IE_LD, - MO_TLS_IE_LDX, - MO_TLS_IE_ADD, - MO_TLS_LE_HIX22, - MO_TLS_LE_LOX10 -}; - -} // end namespace SPII -} // end namespace llvm - -#endif diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp new file mode 100644 index 0000000..3a9929b --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp @@ -0,0 +1,139 @@ +//===-- SparcELFObjectWriter.cpp - Sparc ELF Writer -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SparcFixupKinds.h" +#include "MCTargetDesc/SparcMCExpr.h" +#include "MCTargetDesc/SparcMCTargetDesc.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { + class SparcELFObjectWriter : public MCELFObjectTargetWriter { + public: + SparcELFObjectWriter(bool Is64Bit, uint8_t OSABI) + : MCELFObjectTargetWriter(Is64Bit, OSABI, + Is64Bit ? ELF::EM_SPARCV9 : ELF::EM_SPARC, + /*HasRelocationAddend*/ true) {} + + virtual ~SparcELFObjectWriter() {} + protected: + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend) const; + + virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const; + }; +} + + +unsigned SparcELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) const { + + if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Fixup.getValue())) { + if (SExpr->getKind() == SparcMCExpr::VK_Sparc_R_DISP32) + return ELF::R_SPARC_DISP32; + } + + if (IsPCRel) { + switch((unsigned)Fixup.getKind()) { + default: + llvm_unreachable("Unimplemented fixup -> relocation"); + case FK_Data_1: return ELF::R_SPARC_DISP8; + case FK_Data_2: return ELF::R_SPARC_DISP16; + case FK_Data_4: return ELF::R_SPARC_DISP32; + case FK_Data_8: return ELF::R_SPARC_DISP64; + case Sparc::fixup_sparc_call30: return ELF::R_SPARC_WDISP30; + case Sparc::fixup_sparc_br22: return ELF::R_SPARC_WDISP22; + case Sparc::fixup_sparc_br19: return ELF::R_SPARC_WDISP19; + case Sparc::fixup_sparc_pc22: return ELF::R_SPARC_PC22; + case Sparc::fixup_sparc_pc10: return ELF::R_SPARC_PC10; + case Sparc::fixup_sparc_wplt30: return ELF::R_SPARC_WPLT30; + } + } + + switch((unsigned)Fixup.getKind()) { + default: + llvm_unreachable("Unimplemented fixup -> relocation"); + case FK_Data_1: return ELF::R_SPARC_8; + case FK_Data_2: return ((Fixup.getOffset() % 2) + ? ELF::R_SPARC_UA16 + : ELF::R_SPARC_16); + case FK_Data_4: return ((Fixup.getOffset() % 4) + ? ELF::R_SPARC_UA32 + : ELF::R_SPARC_32); + case FK_Data_8: return ((Fixup.getOffset() % 8) + ? ELF::R_SPARC_UA64 + : ELF::R_SPARC_64); + case Sparc::fixup_sparc_hi22: return ELF::R_SPARC_HI22; + case Sparc::fixup_sparc_lo10: return ELF::R_SPARC_LO10; + case Sparc::fixup_sparc_h44: return ELF::R_SPARC_H44; + case Sparc::fixup_sparc_m44: return ELF::R_SPARC_M44; + case Sparc::fixup_sparc_l44: return ELF::R_SPARC_L44; + case Sparc::fixup_sparc_hh: return ELF::R_SPARC_HH22; + case Sparc::fixup_sparc_hm: return ELF::R_SPARC_HM10; + case Sparc::fixup_sparc_got22: return ELF::R_SPARC_GOT22; + case Sparc::fixup_sparc_got10: return ELF::R_SPARC_GOT10; + case Sparc::fixup_sparc_tls_gd_hi22: return ELF::R_SPARC_TLS_GD_HI22; + case Sparc::fixup_sparc_tls_gd_lo10: return ELF::R_SPARC_TLS_GD_LO10; + case Sparc::fixup_sparc_tls_gd_add: return ELF::R_SPARC_TLS_GD_ADD; + case Sparc::fixup_sparc_tls_gd_call: return ELF::R_SPARC_TLS_GD_CALL; + case Sparc::fixup_sparc_tls_ldm_hi22: return ELF::R_SPARC_TLS_LDM_HI22; + case Sparc::fixup_sparc_tls_ldm_lo10: return ELF::R_SPARC_TLS_LDM_LO10; + case Sparc::fixup_sparc_tls_ldm_add: return ELF::R_SPARC_TLS_LDM_ADD; + case Sparc::fixup_sparc_tls_ldm_call: return ELF::R_SPARC_TLS_LDM_CALL; + case Sparc::fixup_sparc_tls_ldo_hix22: return ELF::R_SPARC_TLS_LDO_HIX22; + case Sparc::fixup_sparc_tls_ldo_lox10: return ELF::R_SPARC_TLS_LDO_LOX10; + case Sparc::fixup_sparc_tls_ldo_add: return ELF::R_SPARC_TLS_LDO_ADD; + case Sparc::fixup_sparc_tls_ie_hi22: return ELF::R_SPARC_TLS_IE_HI22; + case Sparc::fixup_sparc_tls_ie_lo10: return ELF::R_SPARC_TLS_IE_LO10; + case Sparc::fixup_sparc_tls_ie_ld: return ELF::R_SPARC_TLS_IE_LD; + case Sparc::fixup_sparc_tls_ie_ldx: return ELF::R_SPARC_TLS_IE_LDX; + case Sparc::fixup_sparc_tls_ie_add: return ELF::R_SPARC_TLS_IE_ADD; + case Sparc::fixup_sparc_tls_le_hix22: return ELF::R_SPARC_TLS_LE_HIX22; + case Sparc::fixup_sparc_tls_le_lox10: return ELF::R_SPARC_TLS_LE_LOX10; + } + + return ELF::R_SPARC_NONE; +} + +const MCSymbol *SparcELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const { + + if (!Target.getSymA()) + return NULL; + switch((unsigned)Fixup.getKind()) { + default: break; + case Sparc::fixup_sparc_got22: + case Sparc::fixup_sparc_got10: + return &Target.getSymA()->getSymbol().AliasedSymbol(); + } + return NULL; +} + +MCObjectWriter *llvm::createSparcELFObjectWriter(raw_ostream &OS, + bool Is64Bit, + uint8_t OSABI) { + MCELFObjectTargetWriter *MOTW = new SparcELFObjectWriter(Is64Bit, OSABI); + return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); +} diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h new file mode 100644 index 0000000..005a024 --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h @@ -0,0 +1,93 @@ +//===-- SparcFixupKinds.h - Sparc Specific Fixup Entries --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SPARC_FIXUPKINDS_H +#define LLVM_SPARC_FIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +namespace llvm { + namespace Sparc { + enum Fixups { + // fixup_sparc_call30 - 30-bit PC relative relocation for call + fixup_sparc_call30 = FirstTargetFixupKind, + + /// fixup_sparc_br22 - 22-bit PC relative relocation for + /// branches + fixup_sparc_br22, + + /// fixup_sparc_br19 - 19-bit PC relative relocation for + /// branches on icc/xcc + fixup_sparc_br19, + + /// fixup_sparc_hi22 - 22-bit fixup corresponding to %hi(foo) + /// for sethi + fixup_sparc_hi22, + + /// fixup_sparc_lo10 - 10-bit fixup corresponding to %lo(foo) + fixup_sparc_lo10, + + /// fixup_sparc_h44 - 22-bit fixup corresponding to %h44(foo) + fixup_sparc_h44, + + /// fixup_sparc_m44 - 10-bit fixup corresponding to %m44(foo) + fixup_sparc_m44, + + /// fixup_sparc_l44 - 12-bit fixup corresponding to %l44(foo) + fixup_sparc_l44, + + /// fixup_sparc_hh - 22-bit fixup corresponding to %hh(foo) + fixup_sparc_hh, + + /// fixup_sparc_hm - 10-bit fixup corresponding to %hm(foo) + fixup_sparc_hm, + + /// fixup_sparc_pc22 - 22-bit fixup corresponding to %pc22(foo) + fixup_sparc_pc22, + + /// fixup_sparc_pc10 - 10-bit fixup corresponding to %pc10(foo) + fixup_sparc_pc10, + + /// fixup_sparc_got22 - 22-bit fixup corresponding to %got22(foo) + fixup_sparc_got22, + + /// fixup_sparc_got10 - 10-bit fixup corresponding to %got10(foo) + fixup_sparc_got10, + + /// fixup_sparc_wplt30 + fixup_sparc_wplt30, + + /// fixups for Thread Local Storage + fixup_sparc_tls_gd_hi22, + fixup_sparc_tls_gd_lo10, + fixup_sparc_tls_gd_add, + fixup_sparc_tls_gd_call, + fixup_sparc_tls_ldm_hi22, + fixup_sparc_tls_ldm_lo10, + fixup_sparc_tls_ldm_add, + fixup_sparc_tls_ldm_call, + fixup_sparc_tls_ldo_hix22, + fixup_sparc_tls_ldo_lox10, + fixup_sparc_tls_ldo_add, + fixup_sparc_tls_ie_hi22, + fixup_sparc_tls_ie_lo10, + fixup_sparc_tls_ie_ld, + fixup_sparc_tls_ie_ldx, + fixup_sparc_tls_ie_add, + fixup_sparc_tls_le_hix22, + fixup_sparc_tls_le_lox10, + + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind + }; + } +} + +#endif diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp index baac36b..8d0dfec 100644 --- a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp @@ -12,7 +12,9 @@ //===----------------------------------------------------------------------===// #include "SparcMCAsmInfo.h" +#include "SparcMCExpr.h" #include "llvm/ADT/Triple.h" +#include "llvm/MC/MCStreamer.h" using namespace llvm; @@ -44,4 +46,27 @@ SparcELFMCAsmInfo::SparcELFMCAsmInfo(StringRef TT) { PrivateGlobalPrefix = ".L"; } +const MCExpr* +SparcELFMCAsmInfo::getExprForPersonalitySymbol(const MCSymbol *Sym, + unsigned Encoding, + MCStreamer &Streamer) const { + if (Encoding & dwarf::DW_EH_PE_pcrel) { + MCContext &Ctx = Streamer.getContext(); + return SparcMCExpr::Create(SparcMCExpr::VK_Sparc_R_DISP32, + MCSymbolRefExpr::Create(Sym, Ctx), Ctx); + } + + return MCAsmInfo::getExprForPersonalitySymbol(Sym, Encoding, Streamer); +} +const MCExpr* +SparcELFMCAsmInfo::getExprForFDESymbol(const MCSymbol *Sym, + unsigned Encoding, + MCStreamer &Streamer) const { + if (Encoding & dwarf::DW_EH_PE_pcrel) { + MCContext &Ctx = Streamer.getContext(); + return SparcMCExpr::Create(SparcMCExpr::VK_Sparc_R_DISP32, + MCSymbolRefExpr::Create(Sym, Ctx), Ctx); + } + return MCAsmInfo::getExprForFDESymbol(Sym, Encoding, Streamer); +} diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h index 1e58e37..d53d09d 100644 --- a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h @@ -17,13 +17,20 @@ #include "llvm/MC/MCAsmInfoELF.h" namespace llvm { - class StringRef; +class StringRef; - class SparcELFMCAsmInfo : public MCAsmInfoELF { - virtual void anchor(); - public: - explicit SparcELFMCAsmInfo(StringRef TT); - }; +class SparcELFMCAsmInfo : public MCAsmInfoELF { + virtual void anchor(); +public: + explicit SparcELFMCAsmInfo(StringRef TT); + virtual const MCExpr* getExprForPersonalitySymbol(const MCSymbol *Sym, + unsigned Encoding, + MCStreamer &Streamer) const; + virtual const MCExpr* getExprForFDESymbol(const MCSymbol *Sym, + unsigned Encoding, + MCStreamer &Streamer) const; + +}; } // namespace llvm diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp new file mode 100644 index 0000000..ed756d9 --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp @@ -0,0 +1,176 @@ +//===-- SparcMCCodeEmitter.cpp - Convert Sparc code to machine code -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SparcMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mccodeemitter" +#include "SparcMCExpr.h" +#include "SparcMCTargetDesc.h" +#include "MCTargetDesc/SparcFixupKinds.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); + +namespace { +class SparcMCCodeEmitter : public MCCodeEmitter { + SparcMCCodeEmitter(const SparcMCCodeEmitter &) LLVM_DELETED_FUNCTION; + void operator=(const SparcMCCodeEmitter &) LLVM_DELETED_FUNCTION; + MCContext &Ctx; + +public: + SparcMCCodeEmitter(MCContext &ctx): Ctx(ctx) {} + + ~SparcMCCodeEmitter() {} + + void EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const; + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl<MCFixup> &Fixups) const; + + /// getMachineOpValue - Return binary encoding of operand. If the machine + /// operand requires relocation, record the relocation and return zero. + unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const; + + unsigned getCallTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const; + +}; +} // end anonymous namespace + +MCCodeEmitter *llvm::createSparcMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new SparcMCCodeEmitter(Ctx); +} + +void SparcMCCodeEmitter:: +EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups) const { + unsigned Bits = getBinaryCodeForInstr(MI, Fixups); + + // Output the constant in big endian byte order. + for (unsigned i = 0; i != 4; ++i) { + OS << (char)(Bits >> 24); + Bits <<= 8; + } + unsigned tlsOpNo = 0; + switch (MI.getOpcode()) { + default: break; + case SP::TLS_CALL: tlsOpNo = 1; break; + case SP::TLS_ADDrr: + case SP::TLS_ADDXrr: + case SP::TLS_LDrr: + case SP::TLS_LDXrr: tlsOpNo = 3; break; + } + if (tlsOpNo != 0) { + const MCOperand &MO = MI.getOperand(tlsOpNo); + uint64_t op = getMachineOpValue(MI, MO, Fixups); + assert(op == 0 && "Unexpected operand value!"); + (void)op; // suppress warning. + } + + ++MCNumEmitted; // Keep track of the # of mi's emitted. +} + + +unsigned SparcMCCodeEmitter:: +getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups) const { + + if (MO.isReg()) + return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); + + if (MO.isImm()) + return MO.getImm(); + + assert(MO.isExpr()); + const MCExpr *Expr = MO.getExpr(); + if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Expr)) { + MCFixupKind Kind = (MCFixupKind)SExpr->getFixupKind(); + Fixups.push_back(MCFixup::Create(0, Expr, Kind)); + return 0; + } + + int64_t Res; + if (Expr->EvaluateAsAbsolute(Res)) + return Res; + + assert(0 && "Unhandled expression!"); + return 0; +} + +unsigned SparcMCCodeEmitter:: +getCallTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isReg() || MO.isImm()) + return getMachineOpValue(MI, MO, Fixups); + + if (MI.getOpcode() == SP::TLS_CALL) { + // No fixups for __tls_get_addr. Will emit for fixups for tls_symbol in + // EncodeInstruction. +#ifndef NDEBUG + // Verify that the callee is actually __tls_get_addr. + const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr()); + assert(SExpr && SExpr->getSubExpr()->getKind() == MCExpr::SymbolRef && + "Unexpected expression in TLS_CALL"); + const MCSymbolRefExpr *SymExpr = cast<MCSymbolRefExpr>(SExpr->getSubExpr()); + assert(SymExpr->getSymbol().getName() == "__tls_get_addr" && + "Unexpected function for TLS_CALL"); +#endif + return 0; + } + + MCFixupKind fixupKind = (MCFixupKind)Sparc::fixup_sparc_call30; + + if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr())) { + if (SExpr->getKind() == SparcMCExpr::VK_Sparc_WPLT30) + fixupKind = (MCFixupKind)Sparc::fixup_sparc_wplt30; + } + + Fixups.push_back(MCFixup::Create(0, MO.getExpr(), fixupKind)); + + return 0; +} + +unsigned SparcMCCodeEmitter:: +getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isReg() || MO.isImm()) + return getMachineOpValue(MI, MO, Fixups); + + Sparc::Fixups fixup = Sparc::fixup_sparc_br22; + if (MI.getOpcode() == SP::BPXCC) + fixup = Sparc::fixup_sparc_br19; + + Fixups.push_back(MCFixup::Create(0, MO.getExpr(), + (MCFixupKind)fixup)); + return 0; +} + +#include "SparcGenMCCodeEmitter.inc" diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp new file mode 100644 index 0000000..0337c09 --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp @@ -0,0 +1,254 @@ +//===-- SparcMCExpr.cpp - Sparc specific MC expression classes --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation of the assembly expression modifiers +// accepted by the Sparc architecture (e.g. "%hi", "%lo", ...). +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "sparcmcexpr" +#include "SparcMCExpr.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCELF.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Object/ELF.h" + + +using namespace llvm; + +const SparcMCExpr* +SparcMCExpr::Create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx) { + return new (Ctx) SparcMCExpr(Kind, Expr); +} + + + +void SparcMCExpr::PrintImpl(raw_ostream &OS) const +{ + + bool closeParen = printVariantKind(OS, Kind); + + const MCExpr *Expr = getSubExpr(); + Expr->print(OS); + + if (closeParen) + OS << ')'; +} + +bool SparcMCExpr::printVariantKind(raw_ostream &OS, VariantKind Kind) +{ + bool closeParen = true; + switch (Kind) { + case VK_Sparc_None: closeParen = false; break; + case VK_Sparc_LO: OS << "%lo("; break; + case VK_Sparc_HI: OS << "%hi("; break; + case VK_Sparc_H44: OS << "%h44("; break; + case VK_Sparc_M44: OS << "%m44("; break; + case VK_Sparc_L44: OS << "%l44("; break; + case VK_Sparc_HH: OS << "%hh("; break; + case VK_Sparc_HM: OS << "%hm("; break; + // FIXME: use %pc22/%pc10, if system assembler supports them. + case VK_Sparc_PC22: OS << "%hi("; break; + case VK_Sparc_PC10: OS << "%lo("; break; + // FIXME: use %got22/%got10, if system assembler supports them. + case VK_Sparc_GOT22: OS << "%hi("; break; + case VK_Sparc_GOT10: OS << "%lo("; break; + case VK_Sparc_WPLT30: closeParen = false; break; + case VK_Sparc_R_DISP32: OS << "%r_disp32("; break; + case VK_Sparc_TLS_GD_HI22: OS << "%tgd_hi22("; break; + case VK_Sparc_TLS_GD_LO10: OS << "%tgd_lo10("; break; + case VK_Sparc_TLS_GD_ADD: OS << "%tgd_add("; break; + case VK_Sparc_TLS_GD_CALL: OS << "%tgd_call("; break; + case VK_Sparc_TLS_LDM_HI22: OS << "%tldm_hi22("; break; + case VK_Sparc_TLS_LDM_LO10: OS << "%tldm_lo10("; break; + case VK_Sparc_TLS_LDM_ADD: OS << "%tldm_add("; break; + case VK_Sparc_TLS_LDM_CALL: OS << "%tldm_call("; break; + case VK_Sparc_TLS_LDO_HIX22: OS << "%tldo_hix22("; break; + case VK_Sparc_TLS_LDO_LOX10: OS << "%tldo_lox10("; break; + case VK_Sparc_TLS_LDO_ADD: OS << "%tldo_add("; break; + case VK_Sparc_TLS_IE_HI22: OS << "%tie_hi22("; break; + case VK_Sparc_TLS_IE_LO10: OS << "%tie_lo10("; break; + case VK_Sparc_TLS_IE_LD: OS << "%tie_ld("; break; + case VK_Sparc_TLS_IE_LDX: OS << "%tie_ldx("; break; + case VK_Sparc_TLS_IE_ADD: OS << "%tie_add("; break; + case VK_Sparc_TLS_LE_HIX22: OS << "%tle_hix22("; break; + case VK_Sparc_TLS_LE_LOX10: OS << "%tle_lox10("; break; + } + return closeParen; +} + +SparcMCExpr::VariantKind SparcMCExpr::parseVariantKind(StringRef name) +{ + return StringSwitch<SparcMCExpr::VariantKind>(name) + .Case("lo", VK_Sparc_LO) + .Case("hi", VK_Sparc_HI) + .Case("h44", VK_Sparc_H44) + .Case("m44", VK_Sparc_M44) + .Case("l44", VK_Sparc_L44) + .Case("hh", VK_Sparc_HH) + .Case("hm", VK_Sparc_HM) + .Case("pc22", VK_Sparc_PC22) + .Case("pc10", VK_Sparc_PC10) + .Case("got22", VK_Sparc_GOT22) + .Case("got10", VK_Sparc_GOT10) + .Case("r_disp32", VK_Sparc_R_DISP32) + .Case("tgd_hi22", VK_Sparc_TLS_GD_HI22) + .Case("tgd_lo10", VK_Sparc_TLS_GD_LO10) + .Case("tgd_add", VK_Sparc_TLS_GD_ADD) + .Case("tgd_call", VK_Sparc_TLS_GD_CALL) + .Case("tldm_hi22", VK_Sparc_TLS_LDM_HI22) + .Case("tldm_lo10", VK_Sparc_TLS_LDM_LO10) + .Case("tldm_add", VK_Sparc_TLS_LDM_ADD) + .Case("tldm_call", VK_Sparc_TLS_LDM_CALL) + .Case("tldo_hix22", VK_Sparc_TLS_LDO_HIX22) + .Case("tldo_lox10", VK_Sparc_TLS_LDO_LOX10) + .Case("tldo_add", VK_Sparc_TLS_LDO_ADD) + .Case("tie_hi22", VK_Sparc_TLS_IE_HI22) + .Case("tie_lo10", VK_Sparc_TLS_IE_LO10) + .Case("tie_ld", VK_Sparc_TLS_IE_LD) + .Case("tie_ldx", VK_Sparc_TLS_IE_LDX) + .Case("tie_add", VK_Sparc_TLS_IE_ADD) + .Case("tle_hix22", VK_Sparc_TLS_LE_HIX22) + .Case("tle_lox10", VK_Sparc_TLS_LE_LOX10) + .Default(VK_Sparc_None); +} + +Sparc::Fixups SparcMCExpr::getFixupKind(SparcMCExpr::VariantKind Kind) { + switch (Kind) { + default: assert(0 && "Unhandled SparcMCExpr::VariantKind"); + case VK_Sparc_LO: return Sparc::fixup_sparc_lo10; + case VK_Sparc_HI: return Sparc::fixup_sparc_hi22; + case VK_Sparc_H44: return Sparc::fixup_sparc_h44; + case VK_Sparc_M44: return Sparc::fixup_sparc_m44; + case VK_Sparc_L44: return Sparc::fixup_sparc_l44; + case VK_Sparc_HH: return Sparc::fixup_sparc_hh; + case VK_Sparc_HM: return Sparc::fixup_sparc_hm; + case VK_Sparc_PC22: return Sparc::fixup_sparc_pc22; + case VK_Sparc_PC10: return Sparc::fixup_sparc_pc10; + case VK_Sparc_GOT22: return Sparc::fixup_sparc_got22; + case VK_Sparc_GOT10: return Sparc::fixup_sparc_got10; + case VK_Sparc_WPLT30: return Sparc::fixup_sparc_wplt30; + case VK_Sparc_TLS_GD_HI22: return Sparc::fixup_sparc_tls_gd_hi22; + case VK_Sparc_TLS_GD_LO10: return Sparc::fixup_sparc_tls_gd_lo10; + case VK_Sparc_TLS_GD_ADD: return Sparc::fixup_sparc_tls_gd_add; + case VK_Sparc_TLS_GD_CALL: return Sparc::fixup_sparc_tls_gd_call; + case VK_Sparc_TLS_LDM_HI22: return Sparc::fixup_sparc_tls_ldm_hi22; + case VK_Sparc_TLS_LDM_LO10: return Sparc::fixup_sparc_tls_ldm_lo10; + case VK_Sparc_TLS_LDM_ADD: return Sparc::fixup_sparc_tls_ldm_add; + case VK_Sparc_TLS_LDM_CALL: return Sparc::fixup_sparc_tls_ldm_call; + case VK_Sparc_TLS_LDO_HIX22: return Sparc::fixup_sparc_tls_ldo_hix22; + case VK_Sparc_TLS_LDO_LOX10: return Sparc::fixup_sparc_tls_ldo_lox10; + case VK_Sparc_TLS_LDO_ADD: return Sparc::fixup_sparc_tls_ldo_add; + case VK_Sparc_TLS_IE_HI22: return Sparc::fixup_sparc_tls_ie_hi22; + case VK_Sparc_TLS_IE_LO10: return Sparc::fixup_sparc_tls_ie_lo10; + case VK_Sparc_TLS_IE_LD: return Sparc::fixup_sparc_tls_ie_ld; + case VK_Sparc_TLS_IE_LDX: return Sparc::fixup_sparc_tls_ie_ldx; + case VK_Sparc_TLS_IE_ADD: return Sparc::fixup_sparc_tls_ie_add; + case VK_Sparc_TLS_LE_HIX22: return Sparc::fixup_sparc_tls_le_hix22; + case VK_Sparc_TLS_LE_LOX10: return Sparc::fixup_sparc_tls_le_lox10; + } +} + +bool +SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const { + if (!Layout) + return false; + return getSubExpr()->EvaluateAsRelocatable(Res, *Layout); +} + +static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { + switch (Expr->getKind()) { + case MCExpr::Target: + llvm_unreachable("Can't handle nested target expr!"); + break; + + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr); + fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm); + fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm); + break; + } + + case MCExpr::SymbolRef: { + const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr); + MCSymbolData &SD = Asm.getOrCreateSymbolData(SymRef.getSymbol()); + MCELF::SetType(SD, ELF::STT_TLS); + break; + } + + case MCExpr::Unary: + fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm); + break; + } + +} + +void SparcMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { + switch(getKind()) { + default: return; + case VK_Sparc_TLS_GD_HI22: + case VK_Sparc_TLS_GD_LO10: + case VK_Sparc_TLS_GD_ADD: + case VK_Sparc_TLS_GD_CALL: + case VK_Sparc_TLS_LDM_HI22: + case VK_Sparc_TLS_LDM_LO10: + case VK_Sparc_TLS_LDM_ADD: + case VK_Sparc_TLS_LDM_CALL: + case VK_Sparc_TLS_LDO_HIX22: + case VK_Sparc_TLS_LDO_LOX10: + case VK_Sparc_TLS_LDO_ADD: + case VK_Sparc_TLS_IE_HI22: + case VK_Sparc_TLS_IE_LO10: + case VK_Sparc_TLS_IE_LD: + case VK_Sparc_TLS_IE_LDX: + case VK_Sparc_TLS_IE_ADD: + case VK_Sparc_TLS_LE_HIX22: + case VK_Sparc_TLS_LE_LOX10: break; + } + fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm); +} + +// FIXME: This basically copies MCObjectStreamer::AddValueSymbols. Perhaps +// that method should be made public? +// FIXME: really do above: now that at least three other backends are using it. +static void AddValueSymbolsImpl(const MCExpr *Value, MCAssembler *Asm) { + switch (Value->getKind()) { + case MCExpr::Target: + llvm_unreachable("Can't handle nested target expr!"); + break; + + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); + AddValueSymbolsImpl(BE->getLHS(), Asm); + AddValueSymbolsImpl(BE->getRHS(), Asm); + break; + } + + case MCExpr::SymbolRef: + Asm->getOrCreateSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol()); + break; + + case MCExpr::Unary: + AddValueSymbolsImpl(cast<MCUnaryExpr>(Value)->getSubExpr(), Asm); + break; + } +} + +void SparcMCExpr::AddValueSymbols(MCAssembler *Asm) const { + AddValueSymbolsImpl(getSubExpr(), Asm); +} diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h new file mode 100644 index 0000000..be6526e --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h @@ -0,0 +1,111 @@ +//====- SparcMCExpr.h - Sparc specific MC expression classes --*- C++ -*-=====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes Sparc-specific MCExprs, used for modifiers like +// "%hi" or "%lo" etc., +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SPARCMCEXPR_H +#define LLVM_SPARCMCEXPR_H + +#include "SparcFixupKinds.h" +#include "llvm/MC/MCExpr.h" + +namespace llvm { + +class StringRef; +class SparcMCExpr : public MCTargetExpr { +public: + enum VariantKind { + VK_Sparc_None, + VK_Sparc_LO, + VK_Sparc_HI, + VK_Sparc_H44, + VK_Sparc_M44, + VK_Sparc_L44, + VK_Sparc_HH, + VK_Sparc_HM, + VK_Sparc_PC22, + VK_Sparc_PC10, + VK_Sparc_GOT22, + VK_Sparc_GOT10, + VK_Sparc_WPLT30, + VK_Sparc_R_DISP32, + VK_Sparc_TLS_GD_HI22, + VK_Sparc_TLS_GD_LO10, + VK_Sparc_TLS_GD_ADD, + VK_Sparc_TLS_GD_CALL, + VK_Sparc_TLS_LDM_HI22, + VK_Sparc_TLS_LDM_LO10, + VK_Sparc_TLS_LDM_ADD, + VK_Sparc_TLS_LDM_CALL, + VK_Sparc_TLS_LDO_HIX22, + VK_Sparc_TLS_LDO_LOX10, + VK_Sparc_TLS_LDO_ADD, + VK_Sparc_TLS_IE_HI22, + VK_Sparc_TLS_IE_LO10, + VK_Sparc_TLS_IE_LD, + VK_Sparc_TLS_IE_LDX, + VK_Sparc_TLS_IE_ADD, + VK_Sparc_TLS_LE_HIX22, + VK_Sparc_TLS_LE_LOX10 + }; + +private: + const VariantKind Kind; + const MCExpr *Expr; + + explicit SparcMCExpr(VariantKind _Kind, const MCExpr *_Expr) + : Kind(_Kind), Expr(_Expr) {} + +public: + /// @name Construction + /// @{ + + static const SparcMCExpr *Create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx); + /// @} + /// @name Accessors + /// @{ + + /// getOpcode - Get the kind of this expression. + VariantKind getKind() const { return Kind; } + + /// getSubExpr - Get the child of this expression. + const MCExpr *getSubExpr() const { return Expr; } + + /// getFixupKind - Get the fixup kind of this expression. + Sparc::Fixups getFixupKind() const { return getFixupKind(Kind); } + + /// @} + void PrintImpl(raw_ostream &OS) const; + bool EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const; + void AddValueSymbols(MCAssembler *) const; + const MCSection *FindAssociatedSection() const { + return getSubExpr()->FindAssociatedSection(); + } + + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const; + + static bool classof(const MCExpr *E) { + return E->getKind() == MCExpr::Target; + } + + static bool classof(const SparcMCExpr *) { return true; } + + static VariantKind parseVariantKind(StringRef name); + static bool printVariantKind(raw_ostream &OS, VariantKind Kind); + static Sparc::Fixups getFixupKind(VariantKind Kind); +}; + +} // end namespace llvm. + +#endif diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp index 1c64e1b..2832a71 100644 --- a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp @@ -13,6 +13,8 @@ #include "SparcMCTargetDesc.h" #include "SparcMCAsmInfo.h" +#include "SparcTargetStreamer.h" +#include "InstPrinter/SparcInstPrinter.h" #include "llvm/MC/MCCodeGenInfo.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" @@ -31,6 +33,25 @@ using namespace llvm; + +static MCAsmInfo *createSparcMCAsmInfo(const MCRegisterInfo &MRI, + StringRef TT) { + MCAsmInfo *MAI = new SparcELFMCAsmInfo(TT); + unsigned Reg = MRI.getDwarfRegNum(SP::O6, true); + MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(0, Reg, 0); + MAI->addInitialFrameState(Inst); + return MAI; +} + +static MCAsmInfo *createSparcV9MCAsmInfo(const MCRegisterInfo &MRI, + StringRef TT) { + MCAsmInfo *MAI = new SparcELFMCAsmInfo(TT); + unsigned Reg = MRI.getDwarfRegNum(SP::O6, true); + MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(0, Reg, 2047); + MAI->addInitialFrameState(Inst); + return MAI; +} + static MCInstrInfo *createSparcMCInstrInfo() { MCInstrInfo *X = new MCInstrInfo(); InitSparcMCInstrInfo(X); @@ -39,7 +60,7 @@ static MCInstrInfo *createSparcMCInstrInfo() { static MCRegisterInfo *createSparcMCRegisterInfo(StringRef TT) { MCRegisterInfo *X = new MCRegisterInfo(); - InitSparcMCRegisterInfo(X, SP::I7); + InitSparcMCRegisterInfo(X, SP::O7); return X; } @@ -66,9 +87,13 @@ static MCCodeGenInfo *createSparcMCCodeGenInfo(StringRef TT, Reloc::Model RM, CodeGenOpt::Level OL) { MCCodeGenInfo *X = new MCCodeGenInfo(); - // The default 32-bit code model is abs32/pic32. - if (CM == CodeModel::Default) - CM = RM == Reloc::PIC_ ? CodeModel::Medium : CodeModel::Small; + // The default 32-bit code model is abs32/pic32 and the default 32-bit + // code model for JIT is abs32. + switch (CM) { + default: break; + case CodeModel::Default: + case CodeModel::JITDefault: CM = CodeModel::Small; break; + } X->InitMCCodeGenInfo(RM, CM, OL); return X; @@ -79,17 +104,55 @@ static MCCodeGenInfo *createSparcV9MCCodeGenInfo(StringRef TT, Reloc::Model RM, CodeGenOpt::Level OL) { MCCodeGenInfo *X = new MCCodeGenInfo(); - // The default 64-bit code model is abs44/pic32. - if (CM == CodeModel::Default) - CM = CodeModel::Medium; + // The default 64-bit code model is abs44/pic32 and the default 64-bit + // code model for JIT is abs64. + switch (CM) { + default: break; + case CodeModel::Default: + CM = RM == Reloc::PIC_ ? CodeModel::Small : CodeModel::Medium; + break; + case CodeModel::JITDefault: + CM = CodeModel::Large; + break; + } X->InitMCCodeGenInfo(RM, CM, OL); return X; } + +static MCStreamer *createMCStreamer(const Target &T, StringRef TT, + MCContext &Context, MCAsmBackend &MAB, + raw_ostream &OS, MCCodeEmitter *Emitter, + bool RelaxAll, bool NoExecStack) { + SparcTargetELFStreamer *S = new SparcTargetELFStreamer(); + return createELFStreamer(Context, S, MAB, OS, Emitter, RelaxAll, NoExecStack); +} + +static MCStreamer * +createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, + bool isVerboseAsm, bool useLoc, bool useCFI, + bool useDwarfDirectory, MCInstPrinter *InstPrint, + MCCodeEmitter *CE, MCAsmBackend *TAB, bool ShowInst) { + SparcTargetAsmStreamer *S = new SparcTargetAsmStreamer(OS); + + return llvm::createAsmStreamer(Ctx, S, OS, isVerboseAsm, useLoc, useCFI, + useDwarfDirectory, InstPrint, CE, TAB, + ShowInst); +} + +static MCInstPrinter *createSparcMCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI) { + return new SparcInstPrinter(MAI, MII, MRI); +} + extern "C" void LLVMInitializeSparcTargetMC() { // Register the MC asm info. - RegisterMCAsmInfo<SparcELFMCAsmInfo> X(TheSparcTarget); - RegisterMCAsmInfo<SparcELFMCAsmInfo> Y(TheSparcV9Target); + RegisterMCAsmInfoFn X(TheSparcTarget, createSparcMCAsmInfo); + RegisterMCAsmInfoFn Y(TheSparcV9Target, createSparcV9MCAsmInfo); // Register the MC codegen info. TargetRegistry::RegisterMCCodeGenInfo(TheSparcTarget, @@ -99,11 +162,46 @@ extern "C" void LLVMInitializeSparcTargetMC() { // Register the MC instruction info. TargetRegistry::RegisterMCInstrInfo(TheSparcTarget, createSparcMCInstrInfo); + TargetRegistry::RegisterMCInstrInfo(TheSparcV9Target, createSparcMCInstrInfo); // Register the MC register info. TargetRegistry::RegisterMCRegInfo(TheSparcTarget, createSparcMCRegisterInfo); + TargetRegistry::RegisterMCRegInfo(TheSparcV9Target, + createSparcMCRegisterInfo); // Register the MC subtarget info. TargetRegistry::RegisterMCSubtargetInfo(TheSparcTarget, createSparcMCSubtargetInfo); + TargetRegistry::RegisterMCSubtargetInfo(TheSparcV9Target, + createSparcMCSubtargetInfo); + + // Register the MC Code Emitter. + TargetRegistry::RegisterMCCodeEmitter(TheSparcTarget, + createSparcMCCodeEmitter); + TargetRegistry::RegisterMCCodeEmitter(TheSparcV9Target, + createSparcMCCodeEmitter); + + //Register the asm backend. + TargetRegistry::RegisterMCAsmBackend(TheSparcTarget, + createSparcAsmBackend); + TargetRegistry::RegisterMCAsmBackend(TheSparcV9Target, + createSparcAsmBackend); + + // Register the object streamer. + TargetRegistry::RegisterMCObjectStreamer(TheSparcTarget, + createMCStreamer); + TargetRegistry::RegisterMCObjectStreamer(TheSparcV9Target, + createMCStreamer); + + // Register the asm streamer. + TargetRegistry::RegisterAsmStreamer(TheSparcTarget, + createMCAsmStreamer); + TargetRegistry::RegisterAsmStreamer(TheSparcV9Target, + createMCAsmStreamer); + + // Register the MCInstPrinter + TargetRegistry::RegisterMCInstPrinter(TheSparcTarget, + createSparcMCInstPrinter); + TargetRegistry::RegisterMCInstPrinter(TheSparcV9Target, + createSparcMCInstPrinter); } diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h index cba775a..c8029a8 100644 --- a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h @@ -14,12 +14,34 @@ #ifndef SPARCMCTARGETDESC_H #define SPARCMCTARGETDESC_H +#include "llvm/Support/DataTypes.h" + namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectWriter; +class MCRegisterInfo; +class MCSubtargetInfo; class Target; +class StringRef; +class raw_ostream; extern Target TheSparcTarget; extern Target TheSparcV9Target; +MCCodeEmitter *createSparcMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + const MCSubtargetInfo &STI, + MCContext &Ctx); +MCAsmBackend *createSparcAsmBackend(const Target &T, + const MCRegisterInfo &MRI, + StringRef TT, + StringRef CPU); +MCObjectWriter *createSparcELFObjectWriter(raw_ostream &OS, + bool Is64Bit, + uint8_t OSABI); } // End llvm namespace // Defines symbolic names for Sparc registers. This defines a mapping from diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp new file mode 100644 index 0000000..01043ae --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp @@ -0,0 +1,40 @@ +//===-- SparcTargetStreamer.cpp - Sparc Target Streamer Methods -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Sparc specific target streamer methods. +// +//===----------------------------------------------------------------------===// + +#include "SparcTargetStreamer.h" +#include "InstPrinter/SparcInstPrinter.h" +#include "llvm/Support/FormattedStream.h" + +using namespace llvm; + +// pin vtable to this file +void SparcTargetStreamer::anchor() {} + +SparcTargetAsmStreamer::SparcTargetAsmStreamer(formatted_raw_ostream &OS) + : OS(OS) {} + +void SparcTargetAsmStreamer::emitSparcRegisterIgnore(unsigned reg) { + OS << "\t.register " + << "%" << StringRef(SparcInstPrinter::getRegisterName(reg)).lower() + << ", #ignore\n"; +} + +void SparcTargetAsmStreamer::emitSparcRegisterScratch(unsigned reg) { + OS << "\t.register " + << "%" << StringRef(SparcInstPrinter::getRegisterName(reg)).lower() + << ", #scratch\n"; +} + +MCELFStreamer &SparcTargetELFStreamer::getStreamer() { + return static_cast<MCELFStreamer &>(*Streamer); +} diff --git a/contrib/llvm/lib/Target/Sparc/Sparc.h b/contrib/llvm/lib/Target/Sparc/Sparc.h index f44b604..8d46c60 100644 --- a/contrib/llvm/lib/Target/Sparc/Sparc.h +++ b/contrib/llvm/lib/Target/Sparc/Sparc.h @@ -23,12 +23,18 @@ namespace llvm { class FunctionPass; class SparcTargetMachine; class formatted_raw_ostream; + class AsmPrinter; + class MCInst; + class MachineInstr; FunctionPass *createSparcISelDag(SparcTargetMachine &TM); FunctionPass *createSparcDelaySlotFillerPass(TargetMachine &TM); FunctionPass *createSparcJITCodeEmitterPass(SparcTargetMachine &TM, JITCodeEmitter &JCE); + void LowerSparcMachineInstrToMCInst(const MachineInstr *MI, + MCInst &OutMI, + AsmPrinter &AP); } // end namespace llvm; namespace llvm { diff --git a/contrib/llvm/lib/Target/Sparc/Sparc.td b/contrib/llvm/lib/Target/Sparc/Sparc.td index 0df48f6..05ff996 100644 --- a/contrib/llvm/lib/Target/Sparc/Sparc.td +++ b/contrib/llvm/lib/Target/Sparc/Sparc.td @@ -34,6 +34,9 @@ def FeatureHardQuad : SubtargetFeature<"hard-quad-float", "HasHardQuad", "true", "Enable quad-word floating point instructions">; +def UsePopc : SubtargetFeature<"popc", "UsePopc", "true", + "Use the popc (population count) instruction">; + //===----------------------------------------------------------------------===// // Register File, Calling Conv, Instruction Descriptions //===----------------------------------------------------------------------===// @@ -44,6 +47,10 @@ include "SparcInstrInfo.td" def SparcInstrInfo : InstrInfo; +def SparcAsmParser : AsmParser { + bit ShouldEmitMatchRegisterName = 0; +} + //===----------------------------------------------------------------------===// // SPARC processors supported. //===----------------------------------------------------------------------===// @@ -52,6 +59,7 @@ class Proc<string Name, list<SubtargetFeature> Features> : Processor<Name, NoItineraries, Features>; def : Proc<"generic", []>; +def : Proc<"v7", []>; def : Proc<"v8", []>; def : Proc<"supersparc", []>; def : Proc<"sparclite", []>; @@ -63,8 +71,15 @@ def : Proc<"tsc701", []>; def : Proc<"v9", [FeatureV9]>; def : Proc<"ultrasparc", [FeatureV9, FeatureV8Deprecated]>; def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated]>; -def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>; +def : Proc<"niagara", [FeatureV9, FeatureV8Deprecated]>; +def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated, UsePopc]>; +def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated, UsePopc]>; +def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated, UsePopc]>; +def SparcAsmWriter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + bit isMCAsmWriter = 1; +} //===----------------------------------------------------------------------===// // Declare the target which we are implementing @@ -73,4 +88,7 @@ def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>; def Sparc : Target { // Pull in Instruction Info: let InstructionSet = SparcInstrInfo; + let AssemblyParsers = [SparcAsmParser]; + + let AssemblyWriters = [SparcAsmWriter]; } diff --git a/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp b/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp index d06c894..b2c536d 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp +++ b/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp @@ -16,12 +16,18 @@ #include "Sparc.h" #include "SparcInstrInfo.h" #include "SparcTargetMachine.h" -#include "MCTargetDesc/SparcBaseInfo.h" +#include "SparcTargetStreamer.h" +#include "InstPrinter/SparcInstPrinter.h" +#include "MCTargetDesc/SparcMCExpr.h" #include "llvm/ADT/SmallString.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/TargetRegistry.h" @@ -31,6 +37,9 @@ using namespace llvm; namespace { class SparcAsmPrinter : public AsmPrinter { + SparcTargetStreamer &getTargetStreamer() { + return static_cast<SparcTargetStreamer&>(OutStreamer.getTargetStreamer()); + } public: explicit SparcAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) : AsmPrinter(TM, Streamer) {} @@ -45,14 +54,12 @@ namespace { void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); virtual void EmitFunctionBodyStart(); - virtual void EmitInstruction(const MachineInstr *MI) { - SmallString<128> Str; - raw_svector_ostream OS(Str); - printInstruction(MI, OS); - OutStreamer.EmitRawText(OS.str()); + virtual void EmitInstruction(const MachineInstr *MI); + virtual void EmitEndOfAsmFile(Module &M); + + static const char *getRegisterName(unsigned RegNo) { + return SparcInstPrinter::getRegisterName(RegNo); } - void printInstruction(const MachineInstr *MI, raw_ostream &OS);// autogen'd. - static const char *getRegisterName(unsigned RegNo); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, @@ -61,24 +68,202 @@ namespace { unsigned AsmVariant, const char *ExtraCode, raw_ostream &O); - bool printGetPCX(const MachineInstr *MI, unsigned OpNo, raw_ostream &OS); - - virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) - const; - void EmitGlobalRegisterDecl(unsigned reg) { - SmallString<128> Str; - raw_svector_ostream OS(Str); - OS << "\t.register " - << "%" << StringRef(getRegisterName(reg)).lower() - << ", " - << ((reg == SP::G6 || reg == SP::G7)? "#ignore" : "#scratch"); - OutStreamer.EmitRawText(OS.str()); - } + void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI); }; } // end of anonymous namespace -#include "SparcGenAsmWriter.inc" +static MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind, + MCSymbol *Sym, MCContext &OutContext) { + const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Sym, + OutContext); + const SparcMCExpr *expr = SparcMCExpr::Create(Kind, MCSym, OutContext); + return MCOperand::CreateExpr(expr); + +} +static MCOperand createPCXCallOP(MCSymbol *Label, + MCContext &OutContext) { + return createSparcMCOperand(SparcMCExpr::VK_Sparc_None, Label, OutContext); +} + +static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind, + MCSymbol *GOTLabel, MCSymbol *StartLabel, + MCSymbol *CurLabel, + MCContext &OutContext) +{ + const MCSymbolRefExpr *GOT = MCSymbolRefExpr::Create(GOTLabel, OutContext); + const MCSymbolRefExpr *Start = MCSymbolRefExpr::Create(StartLabel, + OutContext); + const MCSymbolRefExpr *Cur = MCSymbolRefExpr::Create(CurLabel, + OutContext); + + const MCBinaryExpr *Sub = MCBinaryExpr::CreateSub(Cur, Start, OutContext); + const MCBinaryExpr *Add = MCBinaryExpr::CreateAdd(GOT, Sub, OutContext); + const SparcMCExpr *expr = SparcMCExpr::Create(Kind, + Add, OutContext); + return MCOperand::CreateExpr(expr); +} + +static void EmitCall(MCStreamer &OutStreamer, + MCOperand &Callee) +{ + MCInst CallInst; + CallInst.setOpcode(SP::CALL); + CallInst.addOperand(Callee); + OutStreamer.EmitInstruction(CallInst); +} + +static void EmitSETHI(MCStreamer &OutStreamer, + MCOperand &Imm, MCOperand &RD) +{ + MCInst SETHIInst; + SETHIInst.setOpcode(SP::SETHIi); + SETHIInst.addOperand(RD); + SETHIInst.addOperand(Imm); + OutStreamer.EmitInstruction(SETHIInst); +} + +static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode, + MCOperand &RS1, MCOperand &Src2, MCOperand &RD) +{ + MCInst Inst; + Inst.setOpcode(Opcode); + Inst.addOperand(RD); + Inst.addOperand(RS1); + Inst.addOperand(Src2); + OutStreamer.EmitInstruction(Inst); +} + +static void EmitOR(MCStreamer &OutStreamer, + MCOperand &RS1, MCOperand &Imm, MCOperand &RD) { + EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD); +} + +static void EmitADD(MCStreamer &OutStreamer, + MCOperand &RS1, MCOperand &RS2, MCOperand &RD) { + EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD); +} + +static void EmitSHL(MCStreamer &OutStreamer, + MCOperand &RS1, MCOperand &Imm, MCOperand &RD) { + EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD); +} + + +static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym, + SparcMCExpr::VariantKind HiKind, + SparcMCExpr::VariantKind LoKind, + MCOperand &RD, + MCContext &OutContext) { + + MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext); + MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext); + EmitSETHI(OutStreamer, hi, RD); + EmitOR(OutStreamer, RD, lo, RD); +} + +void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI) +{ + MCSymbol *GOTLabel = + OutContext.GetOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_")); + + const MachineOperand &MO = MI->getOperand(0); + assert(MO.getReg() != SP::O7 && + "%o7 is assigned as destination for getpcx!"); + + MCOperand MCRegOP = MCOperand::CreateReg(MO.getReg()); + + + if (TM.getRelocationModel() != Reloc::PIC_) { + // Just load the address of GOT to MCRegOP. + switch(TM.getCodeModel()) { + default: + llvm_unreachable("Unsupported absolute code model"); + case CodeModel::Small: + EmitHiLo(OutStreamer, GOTLabel, + SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO, + MCRegOP, OutContext); + break; + case CodeModel::Medium: { + EmitHiLo(OutStreamer, GOTLabel, + SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44, + MCRegOP, OutContext); + MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(12, + OutContext)); + EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP); + MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44, + GOTLabel, OutContext); + EmitOR(OutStreamer, MCRegOP, lo, MCRegOP); + break; + } + case CodeModel::Large: { + EmitHiLo(OutStreamer, GOTLabel, + SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM, + MCRegOP, OutContext); + MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(32, + OutContext)); + EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP); + // Use register %o7 to load the lower 32 bits. + MCOperand RegO7 = MCOperand::CreateReg(SP::O7); + EmitHiLo(OutStreamer, GOTLabel, + SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO, + RegO7, OutContext); + EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP); + } + } + return; + } + + MCSymbol *StartLabel = OutContext.CreateTempSymbol(); + MCSymbol *EndLabel = OutContext.CreateTempSymbol(); + MCSymbol *SethiLabel = OutContext.CreateTempSymbol(); + + MCOperand RegO7 = MCOperand::CreateReg(SP::O7); + + // <StartLabel>: + // call <EndLabel> + // <SethiLabel>: + // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO> + // <EndLabel>: + // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO> + // add <MO>, %o7, <MO> + + OutStreamer.EmitLabel(StartLabel); + MCOperand Callee = createPCXCallOP(EndLabel, OutContext); + EmitCall(OutStreamer, Callee); + OutStreamer.EmitLabel(SethiLabel); + MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22, + GOTLabel, StartLabel, SethiLabel, + OutContext); + EmitSETHI(OutStreamer, hiImm, MCRegOP); + OutStreamer.EmitLabel(EndLabel); + MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10, + GOTLabel, StartLabel, EndLabel, + OutContext); + EmitOR(OutStreamer, MCRegOP, loImm, MCRegOP); + EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP); +} + +void SparcAsmPrinter::EmitInstruction(const MachineInstr *MI) +{ + + switch (MI->getOpcode()) { + default: break; + case TargetOpcode::DBG_VALUE: + // FIXME: Debug Value. + return; + case SP::GETPCX: + LowerGETPCXAndEmitMCInsts(MI); + return; + } + MachineBasicBlock::const_instr_iterator I = MI; + MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); + do { + MCInst TmpInst; + LowerSparcMachineInstrToMCInst(I, TmpInst, *this); + OutStreamer.EmitInstruction(TmpInst); + } while ((++I != E) && I->isInsideBundle()); // Delay slot check. +} void SparcAsmPrinter::EmitFunctionBodyStart() { if (!TM.getSubtarget<SparcSubtarget>().is64Bit()) @@ -90,89 +275,70 @@ void SparcAsmPrinter::EmitFunctionBodyStart() { unsigned reg = globalRegs[i]; if (MRI.use_empty(reg)) continue; - EmitGlobalRegisterDecl(reg); + + if (reg == SP::G6 || reg == SP::G7) + getTargetStreamer().emitSparcRegisterIgnore(reg); + else + getTargetStreamer().emitSparcRegisterScratch(reg); } } void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { const MachineOperand &MO = MI->getOperand (opNum); - unsigned TF = MO.getTargetFlags(); + SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags(); + #ifndef NDEBUG // Verify the target flags. if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) { if (MI->getOpcode() == SP::CALL) - assert(TF == SPII::MO_NO_FLAG && + assert(TF == SparcMCExpr::VK_Sparc_None && "Cannot handle target flags on call address"); - else if (MI->getOpcode() == SP::SETHIi) - assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH - || TF == SPII::MO_TLS_GD_HI22 - || TF == SPII::MO_TLS_LDM_HI22 - || TF == SPII::MO_TLS_LDO_HIX22 - || TF == SPII::MO_TLS_IE_HI22 - || TF == SPII::MO_TLS_LE_HIX22) && + else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi) + assert((TF == SparcMCExpr::VK_Sparc_HI + || TF == SparcMCExpr::VK_Sparc_H44 + || TF == SparcMCExpr::VK_Sparc_HH + || TF == SparcMCExpr::VK_Sparc_TLS_GD_HI22 + || TF == SparcMCExpr::VK_Sparc_TLS_LDM_HI22 + || TF == SparcMCExpr::VK_Sparc_TLS_LDO_HIX22 + || TF == SparcMCExpr::VK_Sparc_TLS_IE_HI22 + || TF == SparcMCExpr::VK_Sparc_TLS_LE_HIX22) && "Invalid target flags for address operand on sethi"); else if (MI->getOpcode() == SP::TLS_CALL) - assert((TF == SPII::MO_NO_FLAG - || TF == SPII::MO_TLS_GD_CALL - || TF == SPII::MO_TLS_LDM_CALL) && + assert((TF == SparcMCExpr::VK_Sparc_None + || TF == SparcMCExpr::VK_Sparc_TLS_GD_CALL + || TF == SparcMCExpr::VK_Sparc_TLS_LDM_CALL) && "Cannot handle target flags on tls call address"); else if (MI->getOpcode() == SP::TLS_ADDrr) - assert((TF == SPII::MO_TLS_GD_ADD || TF == SPII::MO_TLS_LDM_ADD - || TF == SPII::MO_TLS_LDO_ADD || TF == SPII::MO_TLS_IE_ADD) && + assert((TF == SparcMCExpr::VK_Sparc_TLS_GD_ADD + || TF == SparcMCExpr::VK_Sparc_TLS_LDM_ADD + || TF == SparcMCExpr::VK_Sparc_TLS_LDO_ADD + || TF == SparcMCExpr::VK_Sparc_TLS_IE_ADD) && "Cannot handle target flags on add for TLS"); else if (MI->getOpcode() == SP::TLS_LDrr) - assert(TF == SPII::MO_TLS_IE_LD && + assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LD && "Cannot handle target flags on ld for TLS"); else if (MI->getOpcode() == SP::TLS_LDXrr) - assert(TF == SPII::MO_TLS_IE_LDX && + assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LDX && "Cannot handle target flags on ldx for TLS"); - else if (MI->getOpcode() == SP::XORri) - assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) && + else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri) + assert((TF == SparcMCExpr::VK_Sparc_TLS_LDO_LOX10 + || TF == SparcMCExpr::VK_Sparc_TLS_LE_LOX10) && "Cannot handle target flags on xor for TLS"); else - assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44 - || TF == SPII::MO_HM - || TF == SPII::MO_TLS_GD_LO10 - || TF == SPII::MO_TLS_LDM_LO10 - || TF == SPII::MO_TLS_IE_LO10 ) && + assert((TF == SparcMCExpr::VK_Sparc_LO + || TF == SparcMCExpr::VK_Sparc_M44 + || TF == SparcMCExpr::VK_Sparc_L44 + || TF == SparcMCExpr::VK_Sparc_HM + || TF == SparcMCExpr::VK_Sparc_TLS_GD_LO10 + || TF == SparcMCExpr::VK_Sparc_TLS_LDM_LO10 + || TF == SparcMCExpr::VK_Sparc_TLS_IE_LO10 ) && "Invalid target flags for small address operand"); } #endif - bool CloseParen = true; - switch (TF) { - default: - llvm_unreachable("Unknown target flags on operand"); - case SPII::MO_NO_FLAG: - CloseParen = false; - break; - case SPII::MO_LO: O << "%lo("; break; - case SPII::MO_HI: O << "%hi("; break; - case SPII::MO_H44: O << "%h44("; break; - case SPII::MO_M44: O << "%m44("; break; - case SPII::MO_L44: O << "%l44("; break; - case SPII::MO_HH: O << "%hh("; break; - case SPII::MO_HM: O << "%hm("; break; - case SPII::MO_TLS_GD_HI22: O << "%tgd_hi22("; break; - case SPII::MO_TLS_GD_LO10: O << "%tgd_lo10("; break; - case SPII::MO_TLS_GD_ADD: O << "%tgd_add("; break; - case SPII::MO_TLS_GD_CALL: O << "%tgd_call("; break; - case SPII::MO_TLS_LDM_HI22: O << "%tldm_hi22("; break; - case SPII::MO_TLS_LDM_LO10: O << "%tldm_lo10("; break; - case SPII::MO_TLS_LDM_ADD: O << "%tldm_add("; break; - case SPII::MO_TLS_LDM_CALL: O << "%tldm_call("; break; - case SPII::MO_TLS_LDO_HIX22: O << "%tldo_hix22("; break; - case SPII::MO_TLS_LDO_LOX10: O << "%tldo_lox10("; break; - case SPII::MO_TLS_LDO_ADD: O << "%tldo_add("; break; - case SPII::MO_TLS_IE_HI22: O << "%tie_hi22("; break; - case SPII::MO_TLS_IE_LO10: O << "%tie_lo10("; break; - case SPII::MO_TLS_IE_LD: O << "%tie_ld("; break; - case SPII::MO_TLS_IE_LDX: O << "%tie_ldx("; break; - case SPII::MO_TLS_IE_ADD: O << "%tie_add("; break; - case SPII::MO_TLS_LE_HIX22: O << "%tle_hix22("; break; - case SPII::MO_TLS_LE_LOX10: O << "%tle_lox10("; break; - } + + bool CloseParen = SparcMCExpr::printVariantKind(O, TF); switch (MO.getType()) { case MachineOperand::MO_Register: @@ -226,46 +392,6 @@ void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, printOperand(MI, opNum+1, O); } -bool SparcAsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum, - raw_ostream &O) { - std::string operand = ""; - const MachineOperand &MO = MI->getOperand(opNum); - switch (MO.getType()) { - default: llvm_unreachable("Operand is not a register"); - case MachineOperand::MO_Register: - assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && - "Operand is not a physical register "); - assert(MO.getReg() != SP::O7 && - "%o7 is assigned as destination for getpcx!"); - operand = "%" + StringRef(getRegisterName(MO.getReg())).lower(); - break; - } - - unsigned mfNum = MI->getParent()->getParent()->getFunctionNumber(); - unsigned bbNum = MI->getParent()->getNumber(); - - O << '\n' << ".LLGETPCH" << mfNum << '_' << bbNum << ":\n"; - O << "\tcall\t.LLGETPC" << mfNum << '_' << bbNum << '\n' ; - - O << "\t sethi\t" - << "%hi(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum - << ")), " << operand << '\n' ; - - O << ".LLGETPC" << mfNum << '_' << bbNum << ":\n" ; - O << "\tor\t" << operand - << ", %lo(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum - << ")), " << operand << '\n'; - O << "\tadd\t" << operand << ", %o7, " << operand << '\n'; - - return true; -} - -void SparcAsmPrinter::printCCOperand(const MachineInstr *MI, int opNum, - raw_ostream &O) { - int CC = (int)MI->getOperand(opNum).getImm(); - O << SPARCCondCodeToString((SPCC::CondCodes)CC); -} - /// PrintAsmOperand - Print out an operand for an inline asm expression. /// bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, @@ -303,35 +429,21 @@ bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, return false; } -/// isBlockOnlyReachableByFallthough - Return true if the basic block has -/// exactly one predecessor and the control transfer mechanism between -/// the predecessor and this block is a fall-through. -/// -/// This overrides AsmPrinter's implementation to handle delay slots. -bool SparcAsmPrinter:: -isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const { - // If this is a landing pad, it isn't a fall through. If it has no preds, - // then nothing falls through to it. - if (MBB->isLandingPad() || MBB->pred_empty()) - return false; - - // If there isn't exactly one predecessor, it can't be a fall through. - MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI; - ++PI2; - if (PI2 != MBB->pred_end()) - return false; - - // The predecessor has to be immediately before this block. - const MachineBasicBlock *Pred = *PI; - - if (!Pred->isLayoutSuccessor(MBB)) - return false; - - // Check if the last terminator is an unconditional branch. - MachineBasicBlock::const_iterator I = Pred->end(); - while (I != Pred->begin() && !(--I)->isTerminator()) - ; // Noop - return I == Pred->end() || !I->isBarrier(); +void SparcAsmPrinter::EmitEndOfAsmFile(Module &M) { + const TargetLoweringObjectFileELF &TLOFELF = + static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering()); + MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>(); + + // Generate stubs for global variables. + MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); + if (!Stubs.empty()) { + OutStreamer.SwitchSection(TLOFELF.getDataSection()); + unsigned PtrSize = TM.getDataLayout()->getPointerSize(0); + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + OutStreamer.EmitLabel(Stubs[i].first); + OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), PtrSize); + } + } } // Force static initialization. diff --git a/contrib/llvm/lib/Target/Sparc/SparcCallingConv.td b/contrib/llvm/lib/Target/Sparc/SparcCallingConv.td index acd4ec2..dfaaabf 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcCallingConv.td +++ b/contrib/llvm/lib/Target/Sparc/SparcCallingConv.td @@ -103,7 +103,7 @@ def RetCC_Sparc32 : CallingConv<[ // Function return values are passed exactly like function arguments, except a // struct up to 32 bytes in size can be returned in registers. -// Function arguments AND return values. +// Function arguments AND most return values. def CC_Sparc64 : CallingConv<[ // The frontend uses the inreg flag to indicate i32 and float arguments from // structs. These arguments are not promoted to 64 bits, but they can still @@ -118,6 +118,15 @@ def CC_Sparc64 : CallingConv<[ CCCustom<"CC_Sparc64_Full"> ]>; +def RetCC_Sparc64 : CallingConv<[ + // A single f32 return value always goes in %f0. The ABI doesn't specify what + // happens to multiple f32 return values outside a struct. + CCIfType<[f32], CCCustom<"CC_Sparc64_Half">>, + + // Otherwise, return values are passed exactly like arguments. + CCDelegateTo<CC_Sparc64> +]>; + // Callee-saved registers are handled by the register window mechanism. def CSR : CalleeSavedRegs<(add)> { let OtherPreserved = (add (sequence "I%u", 0, 7), diff --git a/contrib/llvm/lib/Target/Sparc/SparcCodeEmitter.cpp b/contrib/llvm/lib/Target/Sparc/SparcCodeEmitter.cpp index 9bfe31fe..b7b2182 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcCodeEmitter.cpp +++ b/contrib/llvm/lib/Target/Sparc/SparcCodeEmitter.cpp @@ -14,7 +14,7 @@ #define DEBUG_TYPE "jit" #include "Sparc.h" -#include "MCTargetDesc/SparcBaseInfo.h" +#include "MCTargetDesc/SparcMCExpr.h" #include "SparcRelocations.h" #include "SparcTargetMachine.h" #include "llvm/ADT/Statistic.h" @@ -72,6 +72,11 @@ private: unsigned getMachineOpValue(const MachineInstr &MI, const MachineOperand &MO) const; + unsigned getCallTargetOpValue(const MachineInstr &MI, + unsigned) const; + unsigned getBranchTargetOpValue(const MachineInstr &MI, + unsigned) const; + void emitWord(unsigned Word); unsigned getRelocation(const MachineInstr &MI, @@ -181,20 +186,32 @@ unsigned SparcCodeEmitter::getMachineOpValue(const MachineInstr &MI, llvm_unreachable("Unable to encode MachineOperand!"); return 0; } +unsigned SparcCodeEmitter::getCallTargetOpValue(const MachineInstr &MI, + unsigned opIdx) const { + const MachineOperand MO = MI.getOperand(opIdx); + return getMachineOpValue(MI, MO); +} + +unsigned SparcCodeEmitter::getBranchTargetOpValue(const MachineInstr &MI, + unsigned opIdx) const { + const MachineOperand MO = MI.getOperand(opIdx); + return getMachineOpValue(MI, MO); +} + unsigned SparcCodeEmitter::getRelocation(const MachineInstr &MI, const MachineOperand &MO) const { unsigned TF = MO.getTargetFlags(); switch (TF) { default: - case SPII::MO_NO_FLAG: break; - case SPII::MO_LO: return SP::reloc_sparc_lo; - case SPII::MO_HI: return SP::reloc_sparc_hi; - case SPII::MO_H44: - case SPII::MO_M44: - case SPII::MO_L44: - case SPII::MO_HH: - case SPII::MO_HM: assert(0 && "FIXME: Implement Medium/Large code model."); + case SparcMCExpr::VK_Sparc_None: break; + case SparcMCExpr::VK_Sparc_LO: return SP::reloc_sparc_lo; + case SparcMCExpr::VK_Sparc_HI: return SP::reloc_sparc_hi; + case SparcMCExpr::VK_Sparc_H44: return SP::reloc_sparc_h44; + case SparcMCExpr::VK_Sparc_M44: return SP::reloc_sparc_m44; + case SparcMCExpr::VK_Sparc_L44: return SP::reloc_sparc_l44; + case SparcMCExpr::VK_Sparc_HH: return SP::reloc_sparc_hh; + case SparcMCExpr::VK_Sparc_HM: return SP::reloc_sparc_hm; } unsigned Opc = MI.getOpcode(); diff --git a/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp index 64625f7..abe2de6 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -13,10 +13,11 @@ //===----------------------------------------------------------------------===// #include "SparcISelLowering.h" +#include "MCTargetDesc/SparcMCExpr.h" #include "SparcMachineFunctionInfo.h" #include "SparcRegisterInfo.h" #include "SparcTargetMachine.h" -#include "MCTargetDesc/SparcBaseInfo.h" +#include "SparcTargetObjectFile.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -80,11 +81,14 @@ static bool CC_Sparc_Assign_f64(unsigned &ValNo, MVT &ValVT, static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT, MVT &LocVT, CCValAssign::LocInfo &LocInfo, ISD::ArgFlagsTy &ArgFlags, CCState &State) { - assert((LocVT == MVT::f32 || LocVT.getSizeInBits() == 64) && + assert((LocVT == MVT::f32 || LocVT == MVT::f128 + || LocVT.getSizeInBits() == 64) && "Can't handle non-64 bits locations"); // Stack space is allocated for all arguments starting from [%fp+BIAS+128]. - unsigned Offset = State.AllocateStack(8, 8); + unsigned size = (LocVT == MVT::f128) ? 16 : 8; + unsigned alignment = (LocVT == MVT::f128) ? 16 : 8; + unsigned Offset = State.AllocateStack(size, alignment); unsigned Reg = 0; if (LocVT == MVT::i64 && Offset < 6*8) @@ -96,6 +100,9 @@ static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT, else if (LocVT == MVT::f32 && Offset < 16*8) // Promote floats to %f1, %f3, ... Reg = SP::F1 + Offset/4; + else if (LocVT == MVT::f128 && Offset < 16*8) + // Promote long doubles to %q0-%q28. (Which LLVM calls Q0-Q7). + Reg = SP::Q0 + Offset/16; // Promote to register when possible, otherwise use the stack slot. if (Reg) { @@ -248,7 +255,7 @@ SparcTargetLowering::LowerReturn_64(SDValue Chain, DAG.getTarget(), RVLocs, *DAG.getContext()); // Analyze return values. - CCInfo.AnalyzeReturn(Outs, CC_Sparc64); + CCInfo.AnalyzeReturn(Outs, RetCC_Sparc64); SDValue Flag; SmallVector<SDValue, 4> RetOps(1, Chain); @@ -888,10 +895,12 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, // If the callee is a GlobalAddress node (quite common, every direct call is) // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. // Likewise ExternalSymbol -> TargetExternalSymbol. + unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_) + ? SparcMCExpr::VK_Sparc_WPLT30 : 0); if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) - Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32); + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32, 0, TF); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) - Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32); + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32, TF); // Returns a chain & a flag for retval copy to use SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); @@ -998,9 +1007,10 @@ static void fixupVariableFloatArgs(SmallVectorImpl<CCValAssign> &ArgLocs, ArrayRef<ISD::OutputArg> Outs) { for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { const CCValAssign &VA = ArgLocs[i]; + MVT ValTy = VA.getLocVT(); // FIXME: What about f32 arguments? C promotes them to f64 when calling // varargs functions. - if (!VA.isRegLoc() || VA.getLocVT() != MVT::f64) + if (!VA.isRegLoc() || (ValTy != MVT::f64 && ValTy != MVT::f128)) continue; // The fixed arguments to a varargs function still go in FP registers. if (Outs[VA.getValNo()].IsFixed) @@ -1010,15 +1020,25 @@ static void fixupVariableFloatArgs(SmallVectorImpl<CCValAssign> &ArgLocs, CCValAssign NewVA; // Determine the offset into the argument array. - unsigned Offset = 8 * (VA.getLocReg() - SP::D0); + unsigned firstReg = (ValTy == MVT::f64) ? SP::D0 : SP::Q0; + unsigned argSize = (ValTy == MVT::f64) ? 8 : 16; + unsigned Offset = argSize * (VA.getLocReg() - firstReg); assert(Offset < 16*8 && "Offset out of range, bad register enum?"); if (Offset < 6*8) { // This argument should go in %i0-%i5. unsigned IReg = SP::I0 + Offset/8; - // Full register, just bitconvert into i64. - NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(), - IReg, MVT::i64, CCValAssign::BCvt); + if (ValTy == MVT::f64) + // Full register, just bitconvert into i64. + NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(), + IReg, MVT::i64, CCValAssign::BCvt); + else { + assert(ValTy == MVT::f128 && "Unexpected type!"); + // Full register, just bitconvert into i128 -- We will lower this into + // two i64s in LowerCall_64. + NewVA = CCValAssign::getCustomReg(VA.getValNo(), VA.getValVT(), + IReg, MVT::i128, CCValAssign::BCvt); + } } else { // This needs to go to memory, we're out of integer registers. NewVA = CCValAssign::getMem(VA.getValNo(), VA.getValVT(), @@ -1094,11 +1114,46 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg); break; case CCValAssign::BCvt: - Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg); + // fixupVariableFloatArgs() may create bitcasts from f128 to i128. But + // SPARC does not support i128 natively. Lower it into two i64, see below. + if (!VA.needsCustom() || VA.getValVT() != MVT::f128 + || VA.getLocVT() != MVT::i128) + Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg); break; } if (VA.isRegLoc()) { + if (VA.needsCustom() && VA.getValVT() == MVT::f128 + && VA.getLocVT() == MVT::i128) { + // Store and reload into the interger register reg and reg+1. + unsigned Offset = 8 * (VA.getLocReg() - SP::I0); + unsigned StackOffset = Offset + Subtarget->getStackPointerBias() + 128; + SDValue StackPtr = DAG.getRegister(SP::O6, getPointerTy()); + SDValue HiPtrOff = DAG.getIntPtrConstant(StackOffset); + HiPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, + HiPtrOff); + SDValue LoPtrOff = DAG.getIntPtrConstant(StackOffset + 8); + LoPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, + LoPtrOff); + + // Store to %sp+BIAS+128+Offset + SDValue Store = DAG.getStore(Chain, DL, Arg, HiPtrOff, + MachinePointerInfo(), + false, false, 0); + // Load into Reg and Reg+1 + SDValue Hi64 = DAG.getLoad(MVT::i64, DL, Store, HiPtrOff, + MachinePointerInfo(), + false, false, false, 0); + SDValue Lo64 = DAG.getLoad(MVT::i64, DL, Store, LoPtrOff, + MachinePointerInfo(), + false, false, false, 0); + RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()), + Hi64)); + RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()+1), + Lo64)); + continue; + } + // The custom bit on an i32 return value indicates that it should be // passed in the high bits of the register. if (VA.getValVT() == MVT::i32 && VA.needsCustom()) { @@ -1156,10 +1211,13 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, // Likewise ExternalSymbol -> TargetExternalSymbol. SDValue Callee = CLI.Callee; bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS); + unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_) + ? SparcMCExpr::VK_Sparc_WPLT30 : 0); if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) - Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy()); + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy(), 0, + TF); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) - Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy()); + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy(), TF); // Build the operands for the call instruction itself. SmallVector<SDValue, 8> Ops; @@ -1200,7 +1258,13 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, SmallVector<CCValAssign, 16> RVLocs; CCState RVInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(), DAG.getTarget(), RVLocs, *DAG.getContext()); - RVInfo.AnalyzeCallResult(CLI.Ins, CC_Sparc64); + + // Set inreg flag manually for codegen generated library calls that + // return float. + if (CLI.Ins.size() == 1 && CLI.Ins[0].VT == MVT::f32 && CLI.CS == 0) + CLI.Ins[0].Flags.setInReg(); + + RVInfo.AnalyzeCallResult(CLI.Ins, RetCC_Sparc64); // Copy all of the result registers out of their specified physreg. for (unsigned i = 0; i != RVLocs.size(); ++i) { @@ -1303,7 +1367,7 @@ static SPCC::CondCodes FPCondCCodeToFCC(ISD::CondCode CC) { } SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) - : TargetLowering(TM, new TargetLoweringObjectFileELF()) { + : TargetLowering(TM, new SparcELFTargetObjectFile()) { Subtarget = &TM.getSubtarget<SparcSubtarget>(); // Set up the register classes. @@ -1403,7 +1467,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::BR_CC, MVT::i64, Custom); setOperationAction(ISD::SELECT_CC, MVT::i64, Custom); - setOperationAction(ISD::CTPOP, MVT::i64, Legal); + setOperationAction(ISD::CTPOP, MVT::i64, + Subtarget->usePopc() ? Legal : Expand); setOperationAction(ISD::CTTZ , MVT::i64, Expand); setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand); setOperationAction(ISD::CTLZ , MVT::i64, Expand); @@ -1414,9 +1479,29 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom); } - // FIXME: There are instructions available for ATOMIC_FENCE - // on SparcV8 and later. - setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); + // ATOMICs. + // FIXME: We insert fences for each atomics and generate sub-optimal code + // for PSO/TSO. Also, implement other atomicrmw operations. + + setInsertFencesForAtomic(true); + + setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Legal); + setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, + (Subtarget->isV9() ? Legal: Expand)); + + + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Legal); + + // Custom Lower Atomic LOAD/STORE + setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Custom); + setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Custom); + + if (Subtarget->is64Bit()) { + setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i64, Legal); + setOperationAction(ISD::ATOMIC_SWAP, MVT::i64, Legal); + setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Custom); + setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Custom); + } if (!Subtarget->isV9()) { // SparcV8 does not have FNEGD and FABSD. @@ -1439,7 +1524,6 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::FSINCOS, MVT::f32, Expand); setOperationAction(ISD::FREM , MVT::f32, Expand); setOperationAction(ISD::FMA , MVT::f32, Expand); - setOperationAction(ISD::CTPOP, MVT::i32, Expand); setOperationAction(ISD::CTTZ , MVT::i32, Expand); setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand); setOperationAction(ISD::CTLZ , MVT::i32, Expand); @@ -1467,6 +1551,13 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); setOperationAction(ISD::MULHU, MVT::i64, Expand); setOperationAction(ISD::MULHS, MVT::i64, Expand); + + setOperationAction(ISD::UMULO, MVT::i64, Custom); + setOperationAction(ISD::SMULO, MVT::i64, Custom); + + setOperationAction(ISD::SHL_PARTS, MVT::i64, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i64, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i64, Expand); } // VASTART needs to be custom lowered to use the VarArgsFrameIndex. @@ -1474,6 +1565,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) // VAARG needs to be lowered to not do unaligned accesses for doubles. setOperationAction(ISD::VAARG , MVT::Other, Custom); + setOperationAction(ISD::TRAP , MVT::Other, Legal); + // Use the default implementation. setOperationAction(ISD::VACOPY , MVT::Other, Expand); setOperationAction(ISD::VAEND , MVT::Other, Expand); @@ -1486,8 +1579,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) setStackPointerRegisterToSaveRestore(SP::O6); - if (Subtarget->isV9()) - setOperationAction(ISD::CTPOP, MVT::i32, Legal); + setOperationAction(ISD::CTPOP, MVT::i32, + Subtarget->usePopc() ? Legal : Expand); if (Subtarget->isV9() && Subtarget->hasHardQuad()) { setOperationAction(ISD::LOAD, MVT::f128, Legal); @@ -1714,7 +1807,8 @@ SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const { // Handle PIC mode first. if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { // This is the pic32 code model, the GOT is known to be smaller than 4GB. - SDValue HiLo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); + SDValue HiLo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_GOT22, + SparcMCExpr::VK_Sparc_GOT10, DAG); SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, VT); SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo); // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this @@ -1729,23 +1823,26 @@ SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const { switch(getTargetMachine().getCodeModel()) { default: llvm_unreachable("Unsupported absolute code model"); - case CodeModel::JITDefault: case CodeModel::Small: // abs32. - return makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); + return makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI, + SparcMCExpr::VK_Sparc_LO, DAG); case CodeModel::Medium: { // abs44. - SDValue H44 = makeHiLoPair(Op, SPII::MO_H44, SPII::MO_M44, DAG); + SDValue H44 = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_H44, + SparcMCExpr::VK_Sparc_M44, DAG); H44 = DAG.getNode(ISD::SHL, DL, VT, H44, DAG.getConstant(12, MVT::i32)); - SDValue L44 = withTargetFlags(Op, SPII::MO_L44, DAG); + SDValue L44 = withTargetFlags(Op, SparcMCExpr::VK_Sparc_L44, DAG); L44 = DAG.getNode(SPISD::Lo, DL, VT, L44); return DAG.getNode(ISD::ADD, DL, VT, H44, L44); } case CodeModel::Large: { // abs64. - SDValue Hi = makeHiLoPair(Op, SPII::MO_HH, SPII::MO_HM, DAG); + SDValue Hi = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HH, + SparcMCExpr::VK_Sparc_HM, DAG); Hi = DAG.getNode(ISD::SHL, DL, VT, Hi, DAG.getConstant(32, MVT::i32)); - SDValue Lo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); + SDValue Lo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI, + SparcMCExpr::VK_Sparc_LO, DAG); return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo); } } @@ -1777,14 +1874,18 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op, TLSModel::Model model = getTargetMachine().getTLSModel(GV); if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) { - unsigned HiTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_HI22 - : SPII::MO_TLS_LDM_HI22); - unsigned LoTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_LO10 - : SPII::MO_TLS_LDM_LO10); - unsigned addTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_ADD - : SPII::MO_TLS_LDM_ADD); - unsigned callTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_CALL - : SPII::MO_TLS_LDM_CALL); + unsigned HiTF = ((model == TLSModel::GeneralDynamic) + ? SparcMCExpr::VK_Sparc_TLS_GD_HI22 + : SparcMCExpr::VK_Sparc_TLS_LDM_HI22); + unsigned LoTF = ((model == TLSModel::GeneralDynamic) + ? SparcMCExpr::VK_Sparc_TLS_GD_LO10 + : SparcMCExpr::VK_Sparc_TLS_LDM_LO10); + unsigned addTF = ((model == TLSModel::GeneralDynamic) + ? SparcMCExpr::VK_Sparc_TLS_GD_ADD + : SparcMCExpr::VK_Sparc_TLS_LDM_ADD); + unsigned callTF = ((model == TLSModel::GeneralDynamic) + ? SparcMCExpr::VK_Sparc_TLS_GD_CALL + : SparcMCExpr::VK_Sparc_TLS_LDM_CALL); SDValue HiLo = makeHiLoPair(Op, HiTF, LoTF, DAG); SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT); @@ -1822,17 +1923,17 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op, return Ret; SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT, - withTargetFlags(Op, SPII::MO_TLS_LDO_HIX22, DAG)); + withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_HIX22, DAG)); SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT, - withTargetFlags(Op, SPII::MO_TLS_LDO_LOX10, DAG)); + withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_LOX10, DAG)); HiLo = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Ret, HiLo, - withTargetFlags(Op, SPII::MO_TLS_LDO_ADD, DAG)); + withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_ADD, DAG)); } if (model == TLSModel::InitialExec) { - unsigned ldTF = ((PtrVT == MVT::i64)? SPII::MO_TLS_IE_LDX - : SPII::MO_TLS_IE_LD); + unsigned ldTF = ((PtrVT == MVT::i64)? SparcMCExpr::VK_Sparc_TLS_IE_LDX + : SparcMCExpr::VK_Sparc_TLS_IE_LD); SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT); @@ -1842,21 +1943,23 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op, MFI->setHasCalls(true); SDValue TGA = makeHiLoPair(Op, - SPII::MO_TLS_IE_HI22, SPII::MO_TLS_IE_LO10, DAG); + SparcMCExpr::VK_Sparc_TLS_IE_HI22, + SparcMCExpr::VK_Sparc_TLS_IE_LO10, DAG); SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Base, TGA); SDValue Offset = DAG.getNode(SPISD::TLS_LD, DL, PtrVT, Ptr, withTargetFlags(Op, ldTF, DAG)); return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, DAG.getRegister(SP::G7, PtrVT), Offset, - withTargetFlags(Op, SPII::MO_TLS_IE_ADD, DAG)); + withTargetFlags(Op, + SparcMCExpr::VK_Sparc_TLS_IE_ADD, DAG)); } assert(model == TLSModel::LocalExec); SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT, - withTargetFlags(Op, SPII::MO_TLS_LE_HIX22, DAG)); + withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LE_HIX22, DAG)); SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT, - withTargetFlags(Op, SPII::MO_TLS_LE_LOX10, DAG)); + withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LE_LOX10, DAG)); SDValue Offset = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); return DAG.getNode(ISD::ADD, DL, PtrVT, @@ -2334,39 +2437,57 @@ static SDValue getFLUSHW(SDValue Op, SelectionDAG &DAG) { return Chain; } -static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) { +static SDValue getFRAMEADDR(uint64_t depth, SDValue Op, SelectionDAG &DAG, + const SparcSubtarget *Subtarget) { MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); MFI->setFrameAddressIsTaken(true); EVT VT = Op.getValueType(); SDLoc dl(Op); unsigned FrameReg = SP::I6; - - uint64_t depth = Op.getConstantOperandVal(0); + unsigned stackBias = Subtarget->getStackPointerBias(); SDValue FrameAddr; - if (depth == 0) + + if (depth == 0) { FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT); - else { - // flush first to make sure the windowed registers' values are in stack - SDValue Chain = getFLUSHW(Op, DAG); - FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT); - - for (uint64_t i = 0; i != depth; ++i) { - SDValue Ptr = DAG.getNode(ISD::ADD, - dl, MVT::i32, - FrameAddr, DAG.getIntPtrConstant(56)); - FrameAddr = DAG.getLoad(MVT::i32, dl, - Chain, - Ptr, - MachinePointerInfo(), false, false, false, 0); - } + if (Subtarget->is64Bit()) + FrameAddr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr, + DAG.getIntPtrConstant(stackBias)); + return FrameAddr; } + + // flush first to make sure the windowed registers' values are in stack + SDValue Chain = getFLUSHW(Op, DAG); + FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT); + + unsigned Offset = (Subtarget->is64Bit()) ? (stackBias + 112) : 56; + + while (depth--) { + SDValue Ptr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr, + DAG.getIntPtrConstant(Offset)); + FrameAddr = DAG.getLoad(VT, dl, Chain, Ptr, MachinePointerInfo(), + false, false, false, 0); + } + if (Subtarget->is64Bit()) + FrameAddr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr, + DAG.getIntPtrConstant(stackBias)); return FrameAddr; } + +static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG, + const SparcSubtarget *Subtarget) { + + uint64_t depth = Op.getConstantOperandVal(0); + + return getFRAMEADDR(depth, Op, DAG, Subtarget); + +} + static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG, - const SparcTargetLowering &TLI) { + const SparcTargetLowering &TLI, + const SparcSubtarget *Subtarget) { MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo *MFI = MF.getFrameInfo(); MFI->setReturnAddressIsTaken(true); @@ -2380,25 +2501,20 @@ static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG, unsigned RetReg = MF.addLiveIn(SP::I7, TLI.getRegClassFor(TLI.getPointerTy())); RetAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, RetReg, VT); - } else { - // Need frame address to find return address of the caller. - MFI->setFrameAddressIsTaken(true); - - // flush first to make sure the windowed registers' values are in stack - SDValue Chain = getFLUSHW(Op, DAG); - RetAddr = DAG.getCopyFromReg(Chain, dl, SP::I6, VT); - - for (uint64_t i = 0; i != depth; ++i) { - SDValue Ptr = DAG.getNode(ISD::ADD, - dl, MVT::i32, - RetAddr, - DAG.getIntPtrConstant((i == depth-1)?60:56)); - RetAddr = DAG.getLoad(MVT::i32, dl, - Chain, - Ptr, - MachinePointerInfo(), false, false, false, 0); - } + return RetAddr; } + + // Need frame address to find return address of the caller. + SDValue FrameAddr = getFRAMEADDR(depth - 1, Op, DAG, Subtarget); + + unsigned Offset = (Subtarget->is64Bit()) ? 120 : 60; + SDValue Ptr = DAG.getNode(ISD::ADD, + dl, VT, + FrameAddr, + DAG.getIntPtrConstant(Offset)); + RetAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), Ptr, + MachinePointerInfo(), false, false, false, 0); + return RetAddr; } @@ -2527,24 +2643,16 @@ static SDValue LowerF128Store(SDValue Op, SelectionDAG &DAG) { &OutChains[0], 2); } -static SDValue LowerFNEG(SDValue Op, SelectionDAG &DAG, - const SparcTargetLowering &TLI, - bool is64Bit) { - if (Op.getValueType() == MVT::f64) - return LowerF64Op(Op, DAG, ISD::FNEG); - if (Op.getValueType() == MVT::f128) - return TLI.LowerF128Op(Op, DAG, ((is64Bit) ? "_Qp_neg" : "_Q_neg"), 1); - return Op; -} +static SDValue LowerFNEGorFABS(SDValue Op, SelectionDAG &DAG, bool isV9) { + assert((Op.getOpcode() == ISD::FNEG || Op.getOpcode() == ISD::FABS) && "invalid"); -static SDValue LowerFABS(SDValue Op, SelectionDAG &DAG, bool isV9) { if (Op.getValueType() == MVT::f64) - return LowerF64Op(Op, DAG, ISD::FABS); + return LowerF64Op(Op, DAG, Op.getOpcode()); if (Op.getValueType() != MVT::f128) return Op; - // Lower fabs on f128 to fabs on f64 - // fabs f128 => fabs f64:sub_even64, fmov f64:sub_odd64 + // Lower fabs/fneg on f128 to fabs/fneg on f64 + // fabs/fneg f128 => fabs/fneg f64:sub_even64, fmov f64:sub_odd64 SDLoc dl(Op); SDValue SrcReg128 = Op.getOperand(0); @@ -2555,7 +2663,7 @@ static SDValue LowerFABS(SDValue Op, SelectionDAG &DAG, bool isV9) { if (isV9) Hi64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Hi64); else - Hi64 = LowerF64Op(Hi64, DAG, ISD::FABS); + Hi64 = LowerF64Op(Hi64, DAG, Op.getOpcode()); SDValue DstReg128 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, MVT::f128), 0); @@ -2615,18 +2723,76 @@ static SDValue LowerADDC_ADDE_SUBC_SUBE(SDValue Op, SelectionDAG &DAG) { return DAG.getMergeValues(Ops, 2, dl); } +// Custom lower UMULO/SMULO for SPARC. This code is similar to ExpandNode() +// in LegalizeDAG.cpp except the order of arguments to the library function. +static SDValue LowerUMULO_SMULO(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) +{ + unsigned opcode = Op.getOpcode(); + assert((opcode == ISD::UMULO || opcode == ISD::SMULO) && "Invalid Opcode."); + + bool isSigned = (opcode == ISD::SMULO); + EVT VT = MVT::i64; + EVT WideVT = MVT::i128; + SDLoc dl(Op); + SDValue LHS = Op.getOperand(0); + + if (LHS.getValueType() != VT) + return Op; + + SDValue ShiftAmt = DAG.getConstant(63, VT); + + SDValue RHS = Op.getOperand(1); + SDValue HiLHS = DAG.getNode(ISD::SRA, dl, VT, LHS, ShiftAmt); + SDValue HiRHS = DAG.getNode(ISD::SRA, dl, MVT::i64, RHS, ShiftAmt); + SDValue Args[] = { HiLHS, LHS, HiRHS, RHS }; + + SDValue MulResult = TLI.makeLibCall(DAG, + RTLIB::MUL_I128, WideVT, + Args, 4, isSigned, dl).first; + SDValue BottomHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, + MulResult, DAG.getIntPtrConstant(0)); + SDValue TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, + MulResult, DAG.getIntPtrConstant(1)); + if (isSigned) { + SDValue Tmp1 = DAG.getNode(ISD::SRA, dl, VT, BottomHalf, ShiftAmt); + TopHalf = DAG.getSetCC(dl, MVT::i32, TopHalf, Tmp1, ISD::SETNE); + } else { + TopHalf = DAG.getSetCC(dl, MVT::i32, TopHalf, DAG.getConstant(0, VT), + ISD::SETNE); + } + // MulResult is a node with an illegal type. Because such things are not + // generally permitted during this phase of legalization, delete the + // node. The above EXTRACT_ELEMENT nodes should have been folded. + DAG.DeleteNode(MulResult.getNode()); + + SDValue Ops[2] = { BottomHalf, TopHalf } ; + return DAG.getMergeValues(Ops, 2, dl); +} + +static SDValue LowerATOMIC_LOAD_STORE(SDValue Op, SelectionDAG &DAG) { + // Monotonic load/stores are legal. + if (cast<AtomicSDNode>(Op)->getOrdering() <= Monotonic) + return Op; + + // Otherwise, expand with a fence. + return SDValue(); +} + + SDValue SparcTargetLowering:: LowerOperation(SDValue Op, SelectionDAG &DAG) const { bool hasHardQuad = Subtarget->hasHardQuad(); - bool is64Bit = Subtarget->is64Bit(); bool isV9 = Subtarget->isV9(); switch (Op.getOpcode()) { default: llvm_unreachable("Should not custom lower this!"); - case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this); - case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); + case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this, + Subtarget); + case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG, + Subtarget); case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); @@ -2660,42 +2826,91 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const { getLibcallName(RTLIB::DIV_F128), 2); case ISD::FSQRT: return LowerF128Op(Op, DAG, getLibcallName(RTLIB::SQRT_F128),1); - case ISD::FNEG: return LowerFNEG(Op, DAG, *this, is64Bit); - case ISD::FABS: return LowerFABS(Op, DAG, isV9); + case ISD::FABS: + case ISD::FNEG: return LowerFNEGorFABS(Op, DAG, isV9); case ISD::FP_EXTEND: return LowerF128_FPEXTEND(Op, DAG, *this); case ISD::FP_ROUND: return LowerF128_FPROUND(Op, DAG, *this); case ISD::ADDC: case ISD::ADDE: case ISD::SUBC: case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG); + case ISD::UMULO: + case ISD::SMULO: return LowerUMULO_SMULO(Op, DAG, *this); + case ISD::ATOMIC_LOAD: + case ISD::ATOMIC_STORE: return LowerATOMIC_LOAD_STORE(Op, DAG); } } MachineBasicBlock * SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *BB) const { - const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); - unsigned BROpcode; - unsigned CC; - DebugLoc dl = MI->getDebugLoc(); - // Figure out the conditional branch opcode to use for this select_cc. switch (MI->getOpcode()) { default: llvm_unreachable("Unknown SELECT_CC!"); case SP::SELECT_CC_Int_ICC: case SP::SELECT_CC_FP_ICC: case SP::SELECT_CC_DFP_ICC: case SP::SELECT_CC_QFP_ICC: - BROpcode = SP::BCOND; - break; + return expandSelectCC(MI, BB, SP::BCOND); case SP::SELECT_CC_Int_FCC: case SP::SELECT_CC_FP_FCC: case SP::SELECT_CC_DFP_FCC: case SP::SELECT_CC_QFP_FCC: - BROpcode = SP::FBCOND; - break; + return expandSelectCC(MI, BB, SP::FBCOND); + + case SP::ATOMIC_LOAD_ADD_32: + return expandAtomicRMW(MI, BB, SP::ADDrr); + case SP::ATOMIC_LOAD_ADD_64: + return expandAtomicRMW(MI, BB, SP::ADDXrr); + case SP::ATOMIC_LOAD_SUB_32: + return expandAtomicRMW(MI, BB, SP::SUBrr); + case SP::ATOMIC_LOAD_SUB_64: + return expandAtomicRMW(MI, BB, SP::SUBXrr); + case SP::ATOMIC_LOAD_AND_32: + return expandAtomicRMW(MI, BB, SP::ANDrr); + case SP::ATOMIC_LOAD_AND_64: + return expandAtomicRMW(MI, BB, SP::ANDXrr); + case SP::ATOMIC_LOAD_OR_32: + return expandAtomicRMW(MI, BB, SP::ORrr); + case SP::ATOMIC_LOAD_OR_64: + return expandAtomicRMW(MI, BB, SP::ORXrr); + case SP::ATOMIC_LOAD_XOR_32: + return expandAtomicRMW(MI, BB, SP::XORrr); + case SP::ATOMIC_LOAD_XOR_64: + return expandAtomicRMW(MI, BB, SP::XORXrr); + case SP::ATOMIC_LOAD_NAND_32: + return expandAtomicRMW(MI, BB, SP::ANDrr); + case SP::ATOMIC_LOAD_NAND_64: + return expandAtomicRMW(MI, BB, SP::ANDXrr); + + case SP::ATOMIC_SWAP_64: + return expandAtomicRMW(MI, BB, 0); + + case SP::ATOMIC_LOAD_MAX_32: + return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_G); + case SP::ATOMIC_LOAD_MAX_64: + return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_G); + case SP::ATOMIC_LOAD_MIN_32: + return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_LE); + case SP::ATOMIC_LOAD_MIN_64: + return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_LE); + case SP::ATOMIC_LOAD_UMAX_32: + return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_GU); + case SP::ATOMIC_LOAD_UMAX_64: + return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_GU); + case SP::ATOMIC_LOAD_UMIN_32: + return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_LEU); + case SP::ATOMIC_LOAD_UMIN_64: + return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_LEU); } +} - CC = (SPCC::CondCodes)MI->getOperand(3).getImm(); +MachineBasicBlock* +SparcTargetLowering::expandSelectCC(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned BROpcode) const { + const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); + DebugLoc dl = MI->getDebugLoc(); + unsigned CC = (SPCC::CondCodes)MI->getOperand(3).getImm(); // To "insert" a SELECT_CC instruction, we actually have to insert the diamond // control-flow pattern. The incoming instruction knows the destination vreg @@ -2749,6 +2964,101 @@ SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, return BB; } +MachineBasicBlock* +SparcTargetLowering::expandAtomicRMW(MachineInstr *MI, + MachineBasicBlock *MBB, + unsigned Opcode, + unsigned CondCode) const { + const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); + MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo(); + DebugLoc DL = MI->getDebugLoc(); + + // MI is an atomic read-modify-write instruction of the form: + // + // rd = atomicrmw<op> addr, rs2 + // + // All three operands are registers. + unsigned DestReg = MI->getOperand(0).getReg(); + unsigned AddrReg = MI->getOperand(1).getReg(); + unsigned Rs2Reg = MI->getOperand(2).getReg(); + + // SelectionDAG has already inserted memory barriers before and after MI, so + // we simply have to implement the operatiuon in terms of compare-and-swap. + // + // %val0 = load %addr + // loop: + // %val = phi %val0, %dest + // %upd = op %val, %rs2 + // %dest = cas %addr, %val, %upd + // cmp %val, %dest + // bne loop + // done: + // + bool is64Bit = SP::I64RegsRegClass.hasSubClassEq(MRI.getRegClass(DestReg)); + const TargetRegisterClass *ValueRC = + is64Bit ? &SP::I64RegsRegClass : &SP::IntRegsRegClass; + unsigned Val0Reg = MRI.createVirtualRegister(ValueRC); + + BuildMI(*MBB, MI, DL, TII.get(is64Bit ? SP::LDXri : SP::LDri), Val0Reg) + .addReg(AddrReg).addImm(0); + + // Split the basic block MBB before MI and insert the loop block in the hole. + MachineFunction::iterator MFI = MBB; + const BasicBlock *LLVM_BB = MBB->getBasicBlock(); + MachineFunction *MF = MBB->getParent(); + MachineBasicBlock *LoopMBB = MF->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *DoneMBB = MF->CreateMachineBasicBlock(LLVM_BB); + ++MFI; + MF->insert(MFI, LoopMBB); + MF->insert(MFI, DoneMBB); + + // Move MI and following instructions to DoneMBB. + DoneMBB->splice(DoneMBB->begin(), MBB, MI, MBB->end()); + DoneMBB->transferSuccessorsAndUpdatePHIs(MBB); + + // Connect the CFG again. + MBB->addSuccessor(LoopMBB); + LoopMBB->addSuccessor(LoopMBB); + LoopMBB->addSuccessor(DoneMBB); + + // Build the loop block. + unsigned ValReg = MRI.createVirtualRegister(ValueRC); + // Opcode == 0 means try to write Rs2Reg directly (ATOMIC_SWAP). + unsigned UpdReg = (Opcode ? MRI.createVirtualRegister(ValueRC) : Rs2Reg); + + BuildMI(LoopMBB, DL, TII.get(SP::PHI), ValReg) + .addReg(Val0Reg).addMBB(MBB) + .addReg(DestReg).addMBB(LoopMBB); + + if (CondCode) { + // This is one of the min/max operations. We need a CMPrr followed by a + // MOVXCC/MOVICC. + BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(Rs2Reg); + BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg) + .addReg(ValReg).addReg(Rs2Reg).addImm(CondCode); + } else if (Opcode) { + BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg) + .addReg(ValReg).addReg(Rs2Reg); + } + + if (MI->getOpcode() == SP::ATOMIC_LOAD_NAND_32 || + MI->getOpcode() == SP::ATOMIC_LOAD_NAND_64) { + unsigned TmpReg = UpdReg; + UpdReg = MRI.createVirtualRegister(ValueRC); + BuildMI(LoopMBB, DL, TII.get(SP::XORri), UpdReg).addReg(TmpReg).addImm(-1); + } + + BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::CASXrr : SP::CASrr), DestReg) + .addReg(AddrReg).addReg(ValReg).addReg(UpdReg) + .setMemRefs(MI->memoperands_begin(), MI->memoperands_end()); + BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(DestReg); + BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::BPXCC : SP::BCOND)) + .addMBB(LoopMBB).addImm(SPCC::ICC_NE); + + MI->eraseFromParent(); + return DoneMBB; +} + //===----------------------------------------------------------------------===// // Sparc Inline Assembly Support //===----------------------------------------------------------------------===// @@ -2761,12 +3071,72 @@ SparcTargetLowering::getConstraintType(const std::string &Constraint) const { switch (Constraint[0]) { default: break; case 'r': return C_RegisterClass; + case 'I': // SIMM13 + return C_Other; } } return TargetLowering::getConstraintType(Constraint); } +TargetLowering::ConstraintWeight SparcTargetLowering:: +getSingleConstraintMatchWeight(AsmOperandInfo &info, + const char *constraint) const { + ConstraintWeight weight = CW_Invalid; + Value *CallOperandVal = info.CallOperandVal; + // If we don't have a value, we can't do a match, + // but allow it at the lowest weight. + if (CallOperandVal == NULL) + return CW_Default; + + // Look at the constraint type. + switch (*constraint) { + default: + weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint); + break; + case 'I': // SIMM13 + if (ConstantInt *C = dyn_cast<ConstantInt>(info.CallOperandVal)) { + if (isInt<13>(C->getSExtValue())) + weight = CW_Constant; + } + break; + } + return weight; +} + +/// LowerAsmOperandForConstraint - Lower the specified operand into the Ops +/// vector. If it is invalid, don't add anything to Ops. +void SparcTargetLowering:: +LowerAsmOperandForConstraint(SDValue Op, + std::string &Constraint, + std::vector<SDValue> &Ops, + SelectionDAG &DAG) const { + SDValue Result(0, 0); + + // Only support length 1 constraints for now. + if (Constraint.length() > 1) + return; + + char ConstraintLetter = Constraint[0]; + switch (ConstraintLetter) { + default: break; + case 'I': + if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { + if (isInt<13>(C->getSExtValue())) { + Result = DAG.getTargetConstant(C->getSExtValue(), Op.getValueType()); + break; + } + return; + } + } + + if (Result.getNode()) { + Ops.push_back(Result); + return; + } + TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); +} + std::pair<unsigned, const TargetRegisterClass*> SparcTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const { @@ -2775,6 +3145,26 @@ SparcTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint, case 'r': return std::make_pair(0U, &SP::IntRegsRegClass); } + } else if (!Constraint.empty() && Constraint.size() <= 5 + && Constraint[0] == '{' && *(Constraint.end()-1) == '}') { + // constraint = '{r<d>}' + // Remove the braces from around the name. + StringRef name(Constraint.data()+1, Constraint.size()-2); + // Handle register aliases: + // r0-r7 -> g0-g7 + // r8-r15 -> o0-o7 + // r16-r23 -> l0-l7 + // r24-r31 -> i0-i7 + uint64_t intVal = 0; + if (name.substr(0, 1).equals("r") + && !name.substr(1).getAsInteger(10, intVal) && intVal <= 31) { + const char regTypes[] = { 'g', 'o', 'l', 'i' }; + char regType = regTypes[intVal/8]; + char regIdx = '0' + (intVal % 8); + char tmp[] = { '{', regType, regIdx, '}', 0 }; + std::string newConstraint = std::string(tmp); + return TargetLowering::getRegForInlineAsmConstraint(newConstraint, VT); + } } return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); diff --git a/contrib/llvm/lib/Target/Sparc/SparcISelLowering.h b/contrib/llvm/lib/Target/Sparc/SparcISelLowering.h index 2659fc8..f7b45d0 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcISelLowering.h +++ b/contrib/llvm/lib/Target/Sparc/SparcISelLowering.h @@ -73,6 +73,13 @@ namespace llvm { virtual const char *getTargetNodeName(unsigned Opcode) const; ConstraintType getConstraintType(const std::string &Constraint) const; + ConstraintWeight + getSingleConstraintMatchWeight(AsmOperandInfo &info, + const char *constraint) const; + void LowerAsmOperandForConstraint(SDValue Op, + std::string &Constraint, + std::vector<SDValue> &Ops, + SelectionDAG &DAG) const; std::pair<unsigned, const TargetRegisterClass*> getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const; @@ -158,6 +165,13 @@ namespace llvm { virtual void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue>& Results, SelectionDAG &DAG) const; + + MachineBasicBlock *expandSelectCC(MachineInstr *MI, MachineBasicBlock *BB, + unsigned BROpcode) const; + MachineBasicBlock *expandAtomicRMW(MachineInstr *MI, + MachineBasicBlock *BB, + unsigned Opcode, + unsigned CondCode = 0) const; }; } // end namespace llvm diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstr64Bit.td b/contrib/llvm/lib/Target/Sparc/SparcInstr64Bit.td index 8656de5..a5b48f9 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcInstr64Bit.td +++ b/contrib/llvm/lib/Target/Sparc/SparcInstr64Bit.td @@ -141,41 +141,43 @@ def : Pat<(i64 imm:$val), let Predicates = [Is64Bit] in { // Register-register instructions. - -def : Pat<(and i64:$a, i64:$b), (ANDrr $a, $b)>; -def : Pat<(or i64:$a, i64:$b), (ORrr $a, $b)>; -def : Pat<(xor i64:$a, i64:$b), (XORrr $a, $b)>; - -def : Pat<(and i64:$a, (not i64:$b)), (ANDNrr $a, $b)>; -def : Pat<(or i64:$a, (not i64:$b)), (ORNrr $a, $b)>; -def : Pat<(xor i64:$a, (not i64:$b)), (XNORrr $a, $b)>; - -def : Pat<(add i64:$a, i64:$b), (ADDrr $a, $b)>; -def : Pat<(sub i64:$a, i64:$b), (SUBrr $a, $b)>; - -def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>; - -def : Pat<(tlsadd i64:$a, i64:$b, tglobaltlsaddr:$sym), - (TLS_ADDrr $a, $b, $sym)>; - -// Register-immediate instructions. - -def : Pat<(and i64:$a, (i64 simm13:$b)), (ANDri $a, (as_i32imm $b))>; -def : Pat<(or i64:$a, (i64 simm13:$b)), (ORri $a, (as_i32imm $b))>; -def : Pat<(xor i64:$a, (i64 simm13:$b)), (XORri $a, (as_i32imm $b))>; - -def : Pat<(add i64:$a, (i64 simm13:$b)), (ADDri $a, (as_i32imm $b))>; -def : Pat<(sub i64:$a, (i64 simm13:$b)), (SUBri $a, (as_i32imm $b))>; - -def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>; - -def : Pat<(ctpop i64:$src), (POPCrr $src)>; +let isCodeGenOnly = 1 in { +defm ANDX : F3_12<"and", 0b000001, and, I64Regs, i64, i64imm>; +defm ORX : F3_12<"or", 0b000010, or, I64Regs, i64, i64imm>; +defm XORX : F3_12<"xor", 0b000011, xor, I64Regs, i64, i64imm>; + +def ANDXNrr : F3_1<2, 0b000101, + (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c), + "andn $b, $c, $dst", + [(set i64:$dst, (and i64:$b, (not i64:$c)))]>; +def ORXNrr : F3_1<2, 0b000110, + (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c), + "orn $b, $c, $dst", + [(set i64:$dst, (or i64:$b, (not i64:$c)))]>; +def XNORXrr : F3_1<2, 0b000111, + (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c), + "xnor $b, $c, $dst", + [(set i64:$dst, (not (xor i64:$b, i64:$c)))]>; + +defm ADDX : F3_12<"add", 0b000000, add, I64Regs, i64, i64imm>; +defm SUBX : F3_12<"sub", 0b000100, sub, I64Regs, i64, i64imm>; + +def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$rd), + (ins I64Regs:$rs1, I64Regs:$rs2, TLSSym:$sym), + "add $rs1, $rs2, $rd, $sym", + [(set i64:$rd, + (tlsadd i64:$rs1, i64:$rs2, tglobaltlsaddr:$sym))]>; // "LEA" form of add def LEAX_ADDri : F3_2<2, 0b000000, (outs I64Regs:$dst), (ins MEMri:$addr), "add ${addr:arith}, $dst", [(set iPTR:$dst, ADDRri:$addr)]>; +} + +def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>; +def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>; +def : Pat<(ctpop i64:$src), (POPCrr $src)>; } // Predicates = [Is64Bit] @@ -191,9 +193,9 @@ def MULXrr : F3_1<2, 0b001001, "mulx $rs1, $rs2, $rd", [(set i64:$rd, (mul i64:$rs1, i64:$rs2))]>; def MULXri : F3_2<2, 0b001001, - (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$i), - "mulx $rs1, $i, $rd", - [(set i64:$rd, (mul i64:$rs1, (i64 simm13:$i)))]>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13), + "mulx $rs1, $simm13, $rd", + [(set i64:$rd, (mul i64:$rs1, (i64 simm13:$simm13)))]>; // Division can trap. let hasSideEffects = 1 in { @@ -202,18 +204,18 @@ def SDIVXrr : F3_1<2, 0b101101, "sdivx $rs1, $rs2, $rd", [(set i64:$rd, (sdiv i64:$rs1, i64:$rs2))]>; def SDIVXri : F3_2<2, 0b101101, - (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$i), - "sdivx $rs1, $i, $rd", - [(set i64:$rd, (sdiv i64:$rs1, (i64 simm13:$i)))]>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13), + "sdivx $rs1, $simm13, $rd", + [(set i64:$rd, (sdiv i64:$rs1, (i64 simm13:$simm13)))]>; def UDIVXrr : F3_1<2, 0b001101, (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2), "udivx $rs1, $rs2, $rd", [(set i64:$rd, (udiv i64:$rs1, i64:$rs2))]>; def UDIVXri : F3_2<2, 0b001101, - (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$i), - "udivx $rs1, $i, $rd", - [(set i64:$rd, (udiv i64:$rs1, (i64 simm13:$i)))]>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13), + "udivx $rs1, $simm13, $rd", + [(set i64:$rd, (udiv i64:$rs1, (i64 simm13:$simm13)))]>; } // hasSideEffects = 1 } // Predicates = [Is64Bit] @@ -233,15 +235,9 @@ def UDIVXri : F3_2<2, 0b001101, let Predicates = [Is64Bit] in { // 64-bit loads. -def LDXrr : F3_1<3, 0b001011, - (outs I64Regs:$dst), (ins MEMrr:$addr), - "ldx [$addr], $dst", - [(set i64:$dst, (load ADDRrr:$addr))]>; -def LDXri : F3_2<3, 0b001011, - (outs I64Regs:$dst), (ins MEMri:$addr), - "ldx [$addr], $dst", - [(set i64:$dst, (load ADDRri:$addr))]>; -let mayLoad = 1 in +defm LDX : Load<"ldx", 0b001011, load, I64Regs, i64>; + +let mayLoad = 1, isCodeGenOnly = 1, isAsmParserOnly = 1 in def TLS_LDXrr : F3_1<3, 0b001011, (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym), "ldx [$addr], $dst, $sym", @@ -274,24 +270,10 @@ def : Pat<(i64 (extloadi32 ADDRrr:$addr)), (LDrr ADDRrr:$addr)>; def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>; // Sign-extending load of i32 into i64 is a new SPARC v9 instruction. -def LDSWrr : F3_1<3, 0b001011, - (outs I64Regs:$dst), (ins MEMrr:$addr), - "ldsw [$addr], $dst", - [(set i64:$dst, (sextloadi32 ADDRrr:$addr))]>; -def LDSWri : F3_2<3, 0b001011, - (outs I64Regs:$dst), (ins MEMri:$addr), - "ldsw [$addr], $dst", - [(set i64:$dst, (sextloadi32 ADDRri:$addr))]>; +defm LDSW : Load<"ldsw", 0b001000, sextloadi32, I64Regs, i64>; // 64-bit stores. -def STXrr : F3_1<3, 0b001110, - (outs), (ins MEMrr:$addr, I64Regs:$src), - "stx $src, [$addr]", - [(store i64:$src, ADDRrr:$addr)]>; -def STXri : F3_2<3, 0b001110, - (outs), (ins MEMri:$addr, I64Regs:$src), - "stx $src, [$addr]", - [(store i64:$src, ADDRri:$addr)]>; +defm STX : Store<"stx", 0b001110, store, I64Regs, i64>; // Truncating stores from i64 are identical to the i32 stores. def : Pat<(truncstorei8 i64:$src, ADDRrr:$addr), (STBrr ADDRrr:$addr, $src)>; @@ -311,6 +293,15 @@ def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADDRri:$dst, (i64 G0))>; //===----------------------------------------------------------------------===// // 64-bit Conditionals. //===----------------------------------------------------------------------===// + +// Conditional branch class on %xcc: +class XBranchSP<dag ins, string asmstr, list<dag> pattern> + : F2_3<0b001, 0b10, (outs), ins, asmstr, pattern> { + let isBranch = 1; + let isTerminator = 1; + let hasDelaySlot = 1; +} + // // Flag-setting instructions like subcc and addcc set both icc and xcc flags. // The icc flags correspond to the 32-bit result, and the xcc are for the @@ -322,32 +313,42 @@ def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADDRri:$dst, (i64 G0))>; let Predicates = [Is64Bit] in { let Uses = [ICC] in -def BPXCC : BranchSP<(ins brtarget:$imm22, CCOp:$cond), - "b$cond %xcc, $imm22", - [(SPbrxcc bb:$imm22, imm:$cond)]>; +def BPXCC : XBranchSP<(ins brtarget:$imm19, CCOp:$cond), + "b$cond %xcc, $imm19", + [(SPbrxcc bb:$imm19, imm:$cond)]>; // Conditional moves on %xcc. let Uses = [ICC], Constraints = "$f = $rd" in { -def MOVXCCrr : Pseudo<(outs IntRegs:$rd), +let cc = 0b110 in { +def MOVXCCrr : F4_1<0b101100, (outs IntRegs:$rd), (ins IntRegs:$rs2, IntRegs:$f, CCOp:$cond), "mov$cond %xcc, $rs2, $rd", [(set i32:$rd, (SPselectxcc i32:$rs2, i32:$f, imm:$cond))]>; -def MOVXCCri : Pseudo<(outs IntRegs:$rd), - (ins i32imm:$i, IntRegs:$f, CCOp:$cond), - "mov$cond %xcc, $i, $rd", +def MOVXCCri : F4_2<0b101100, (outs IntRegs:$rd), + (ins i32imm:$simm11, IntRegs:$f, CCOp:$cond), + "mov$cond %xcc, $simm11, $rd", [(set i32:$rd, - (SPselectxcc simm11:$i, i32:$f, imm:$cond))]>; -def FMOVS_XCC : Pseudo<(outs FPRegs:$rd), + (SPselectxcc simm11:$simm11, i32:$f, imm:$cond))]>; +} // cc + +let opf_cc = 0b110 in { +def FMOVS_XCC : F4_3<0b110101, 0b000001, (outs FPRegs:$rd), (ins FPRegs:$rs2, FPRegs:$f, CCOp:$cond), "fmovs$cond %xcc, $rs2, $rd", [(set f32:$rd, (SPselectxcc f32:$rs2, f32:$f, imm:$cond))]>; -def FMOVD_XCC : Pseudo<(outs DFPRegs:$rd), +def FMOVD_XCC : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd), (ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond), "fmovd$cond %xcc, $rs2, $rd", [(set f64:$rd, (SPselectxcc f64:$rs2, f64:$f, imm:$cond))]>; +def FMOVQ_XCC : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd), + (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond), + "fmovq$cond %xcc, $rs2, $rd", + [(set f128:$rd, + (SPselectxcc f128:$rs2, f128:$f, imm:$cond))]>; +} // opf_cc } // Uses, Constraints //===----------------------------------------------------------------------===// @@ -357,31 +358,31 @@ def FMOVD_XCC : Pseudo<(outs DFPRegs:$rd), let Predicates = [Is64Bit] in { def FXTOS : F3_3u<2, 0b110100, 0b010000100, - (outs FPRegs:$dst), (ins DFPRegs:$src), - "fxtos $src, $dst", - [(set FPRegs:$dst, (SPxtof DFPRegs:$src))]>; + (outs FPRegs:$rd), (ins DFPRegs:$rs2), + "fxtos $rs2, $rd", + [(set FPRegs:$rd, (SPxtof DFPRegs:$rs2))]>; def FXTOD : F3_3u<2, 0b110100, 0b010001000, - (outs DFPRegs:$dst), (ins DFPRegs:$src), - "fxtod $src, $dst", - [(set DFPRegs:$dst, (SPxtof DFPRegs:$src))]>; + (outs DFPRegs:$rd), (ins DFPRegs:$rs2), + "fxtod $rs2, $rd", + [(set DFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>; def FXTOQ : F3_3u<2, 0b110100, 0b010001100, - (outs QFPRegs:$dst), (ins DFPRegs:$src), - "fxtoq $src, $dst", - [(set QFPRegs:$dst, (SPxtof DFPRegs:$src))]>, + (outs QFPRegs:$rd), (ins DFPRegs:$rs2), + "fxtoq $rs2, $rd", + [(set QFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>, Requires<[HasHardQuad]>; def FSTOX : F3_3u<2, 0b110100, 0b010000001, - (outs DFPRegs:$dst), (ins FPRegs:$src), - "fstox $src, $dst", - [(set DFPRegs:$dst, (SPftox FPRegs:$src))]>; + (outs DFPRegs:$rd), (ins FPRegs:$rs2), + "fstox $rs2, $rd", + [(set DFPRegs:$rd, (SPftox FPRegs:$rs2))]>; def FDTOX : F3_3u<2, 0b110100, 0b010000010, - (outs DFPRegs:$dst), (ins DFPRegs:$src), - "fdtox $src, $dst", - [(set DFPRegs:$dst, (SPftox DFPRegs:$src))]>; + (outs DFPRegs:$rd), (ins DFPRegs:$rs2), + "fdtox $rs2, $rd", + [(set DFPRegs:$rd, (SPftox DFPRegs:$rs2))]>; def FQTOX : F3_3u<2, 0b110100, 0b010000011, - (outs DFPRegs:$dst), (ins QFPRegs:$src), - "fqtox $src, $dst", - [(set DFPRegs:$dst, (SPftox QFPRegs:$src))]>, + (outs DFPRegs:$rd), (ins QFPRegs:$rs2), + "fqtox $rs2, $rd", + [(set DFPRegs:$rd, (SPftox QFPRegs:$rs2))]>, Requires<[HasHardQuad]>; } // Predicates = [Is64Bit] @@ -402,3 +403,97 @@ def : Pat<(SPselectfcc (i64 simm11:$t), i64:$f, imm:$cond), (MOVFCCri (as_i32imm $t), $f, imm:$cond)>; } // Predicates = [Is64Bit] + + +// 64 bit SETHI +let Predicates = [Is64Bit], isCodeGenOnly = 1 in { +def SETHIXi : F2_1<0b100, + (outs IntRegs:$rd), (ins i64imm:$imm22), + "sethi $imm22, $rd", + [(set i64:$rd, SETHIimm:$imm22)]>; +} + +// ATOMICS. +let Predicates = [Is64Bit], Constraints = "$swap = $rd" in { + def CASXrr: F3_1_asi<3, 0b111110, 0b10000000, + (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, + I64Regs:$swap), + "casx [$rs1], $rs2, $rd", + [(set i64:$rd, + (atomic_cmp_swap i64:$rs1, i64:$rs2, i64:$swap))]>; + +} // Predicates = [Is64Bit], Constraints = ... + +let Predicates = [Is64Bit] in { + +def : Pat<(atomic_fence imm, imm), (MEMBARi 0xf)>; + +// atomic_load_64 addr -> load addr +def : Pat<(i64 (atomic_load ADDRrr:$src)), (LDXrr ADDRrr:$src)>; +def : Pat<(i64 (atomic_load ADDRri:$src)), (LDXri ADDRri:$src)>; + +// atomic_store_64 val, addr -> store val, addr +def : Pat<(atomic_store ADDRrr:$dst, i64:$val), (STXrr ADDRrr:$dst, $val)>; +def : Pat<(atomic_store ADDRri:$dst, i64:$val), (STXri ADDRri:$dst, $val)>; + +} // Predicates = [Is64Bit] + +let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1, + Defs = [ICC] in +multiclass AtomicRMW<SDPatternOperator op32, SDPatternOperator op64> { + + def _32 : Pseudo<(outs IntRegs:$rd), + (ins ptr_rc:$addr, IntRegs:$rs2), "", + [(set i32:$rd, (op32 iPTR:$addr, i32:$rs2))]>; + + let Predicates = [Is64Bit] in + def _64 : Pseudo<(outs I64Regs:$rd), + (ins ptr_rc:$addr, I64Regs:$rs2), "", + [(set i64:$rd, (op64 iPTR:$addr, i64:$rs2))]>; +} + +defm ATOMIC_LOAD_ADD : AtomicRMW<atomic_load_add_32, atomic_load_add_64>; +defm ATOMIC_LOAD_SUB : AtomicRMW<atomic_load_sub_32, atomic_load_sub_64>; +defm ATOMIC_LOAD_AND : AtomicRMW<atomic_load_and_32, atomic_load_and_64>; +defm ATOMIC_LOAD_OR : AtomicRMW<atomic_load_or_32, atomic_load_or_64>; +defm ATOMIC_LOAD_XOR : AtomicRMW<atomic_load_xor_32, atomic_load_xor_64>; +defm ATOMIC_LOAD_NAND : AtomicRMW<atomic_load_nand_32, atomic_load_nand_64>; +defm ATOMIC_LOAD_MIN : AtomicRMW<atomic_load_min_32, atomic_load_min_64>; +defm ATOMIC_LOAD_MAX : AtomicRMW<atomic_load_max_32, atomic_load_max_64>; +defm ATOMIC_LOAD_UMIN : AtomicRMW<atomic_load_umin_32, atomic_load_umin_64>; +defm ATOMIC_LOAD_UMAX : AtomicRMW<atomic_load_umax_32, atomic_load_umax_64>; + +// There is no 64-bit variant of SWAP, so use a pseudo. +let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1, + Defs = [ICC], Predicates = [Is64Bit] in +def ATOMIC_SWAP_64 : Pseudo<(outs I64Regs:$rd), + (ins ptr_rc:$addr, I64Regs:$rs2), "", + [(set i64:$rd, + (atomic_swap_64 iPTR:$addr, i64:$rs2))]>; + +// Global addresses, constant pool entries +let Predicates = [Is64Bit] in { + +def : Pat<(SPhi tglobaladdr:$in), (SETHIi tglobaladdr:$in)>; +def : Pat<(SPlo tglobaladdr:$in), (ORXri (i64 G0), tglobaladdr:$in)>; +def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>; +def : Pat<(SPlo tconstpool:$in), (ORXri (i64 G0), tconstpool:$in)>; + +// GlobalTLS addresses +def : Pat<(SPhi tglobaltlsaddr:$in), (SETHIi tglobaltlsaddr:$in)>; +def : Pat<(SPlo tglobaltlsaddr:$in), (ORXri (i64 G0), tglobaltlsaddr:$in)>; +def : Pat<(add (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)), + (ADDXri (SETHIXi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>; +def : Pat<(xor (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)), + (XORXri (SETHIXi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>; + +// Blockaddress +def : Pat<(SPhi tblockaddress:$in), (SETHIi tblockaddress:$in)>; +def : Pat<(SPlo tblockaddress:$in), (ORXri (i64 G0), tblockaddress:$in)>; + +// Add reg, lo. This is used when taking the addr of a global/constpool entry. +def : Pat<(add iPTR:$r, (SPlo tglobaladdr:$in)), (ADDXri $r, tglobaladdr:$in)>; +def : Pat<(add iPTR:$r, (SPlo tconstpool:$in)), (ADDXri $r, tconstpool:$in)>; +def : Pat<(add iPTR:$r, (SPlo tblockaddress:$in)), + (ADDXri $r, tblockaddress:$in)>; +} diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td b/contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td new file mode 100644 index 0000000..7242c59 --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td @@ -0,0 +1,142 @@ +//===-- SparcInstrAliases.td - Instruction Aliases for Sparc Target -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains instruction aliases for Sparc. +//===----------------------------------------------------------------------===// + +// Instruction aliases for conditional moves. + +// mov<cond> <ccreg> rs2, rd +multiclass cond_mov_alias<string cond, int condVal, string ccreg, + Instruction movrr, Instruction movri, + Instruction fmovs, Instruction fmovd> { + + // mov<cond> (%icc|%xcc|%fcc0), rs2, rd + def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg), + ", $rs2, $rd"), + (movrr IntRegs:$rd, IntRegs:$rs2, condVal)>; + + // mov<cond> (%icc|%xcc|%fcc0), simm11, rd + def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg), + ", $simm11, $rd"), + (movri IntRegs:$rd, i32imm:$simm11, condVal)>; + + // fmovs<cond> (%icc|%xcc|%fcc0), $rs2, $rd + def : InstAlias<!strconcat(!strconcat(!strconcat("fmovs", cond), ccreg), + ", $rs2, $rd"), + (fmovs FPRegs:$rd, FPRegs:$rs2, condVal)>; + + // fmovd<cond> (%icc|%xcc|%fcc0), $rs2, $rd + def : InstAlias<!strconcat(!strconcat(!strconcat("fmovd", cond), ccreg), + ", $rs2, $rd"), + (fmovd DFPRegs:$rd, DFPRegs:$rs2, condVal)>; +} + + +// Instruction aliases for integer conditional branches and moves. +multiclass int_cond_alias<string cond, int condVal> { + + // b<cond> $imm + def : InstAlias<!strconcat(!strconcat("b", cond), " $imm"), + (BCOND brtarget:$imm, condVal)>; + + // b<cond> %xcc, $imm + def : InstAlias<!strconcat(!strconcat("b", cond), " %xcc, $imm"), + (BPXCC brtarget:$imm, condVal)>, Requires<[Is64Bit]>; + + defm : cond_mov_alias<cond, condVal, " %icc", + MOVICCrr, MOVICCri, + FMOVS_ICC, FMOVD_ICC>, Requires<[HasV9]>; + + defm : cond_mov_alias<cond, condVal, " %xcc", + MOVXCCrr, MOVXCCri, + FMOVS_XCC, FMOVD_XCC>, Requires<[Is64Bit]>; + + // fmovq<cond> (%icc|%xcc), $rs2, $rd + def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %icc, $rs2, $rd"), + (FMOVQ_ICC QFPRegs:$rd, QFPRegs:$rs2, condVal)>, + Requires<[HasV9, HasHardQuad]>; + def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %xcc, $rs2, $rd"), + (FMOVQ_XCC QFPRegs:$rd, QFPRegs:$rs2, condVal)>, + Requires<[Is64Bit, HasHardQuad]>; + +} + + +// Instruction aliases for floating point conditional branches and moves. +multiclass fp_cond_alias<string cond, int condVal> { + + // fb<cond> $imm + def : InstAlias<!strconcat(!strconcat("fb", cond), " $imm"), + (FBCOND brtarget:$imm, condVal), 0>; + + defm : cond_mov_alias<cond, condVal, " %fcc0", + MOVFCCrr, MOVFCCri, + FMOVS_FCC, FMOVD_FCC>, Requires<[HasV9]>; + + // fmovq<cond> %fcc0, $rs2, $rd + def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %fcc0, $rs2, $rd"), + (FMOVQ_ICC QFPRegs:$rd, QFPRegs:$rs2, condVal)>, + Requires<[HasV9, HasHardQuad]>; +} + +defm : int_cond_alias<"a", 0b1000>; +defm : int_cond_alias<"n", 0b0000>; +defm : int_cond_alias<"ne", 0b1001>; +defm : int_cond_alias<"e", 0b0001>; +defm : int_cond_alias<"g", 0b1010>; +defm : int_cond_alias<"le", 0b0010>; +defm : int_cond_alias<"ge", 0b1011>; +defm : int_cond_alias<"l", 0b0011>; +defm : int_cond_alias<"gu", 0b1100>; +defm : int_cond_alias<"leu", 0b0100>; +defm : int_cond_alias<"cc", 0b1101>; +defm : int_cond_alias<"cs", 0b0101>; +defm : int_cond_alias<"pos", 0b1110>; +defm : int_cond_alias<"neg", 0b0110>; +defm : int_cond_alias<"vc", 0b1111>; +defm : int_cond_alias<"vs", 0b0111>; + +defm : fp_cond_alias<"u", 0b0111>; +defm : fp_cond_alias<"g", 0b0110>; +defm : fp_cond_alias<"ug", 0b0101>; +defm : fp_cond_alias<"l", 0b0100>; +defm : fp_cond_alias<"ul", 0b0011>; +defm : fp_cond_alias<"lg", 0b0010>; +defm : fp_cond_alias<"ne", 0b0001>; +defm : fp_cond_alias<"e", 0b1001>; +defm : fp_cond_alias<"ue", 0b1010>; +defm : fp_cond_alias<"ge", 0b1011>; +defm : fp_cond_alias<"uge", 0b1100>; +defm : fp_cond_alias<"le", 0b1101>; +defm : fp_cond_alias<"ule", 0b1110>; +defm : fp_cond_alias<"o", 0b1111>; + + +// Instruction aliases for JMPL. + +// jmp addr -> jmpl addr, %g0 +def : InstAlias<"jmp $addr", (JMPLrr G0, MEMrr:$addr)>; +def : InstAlias<"jmp $addr", (JMPLri G0, MEMri:$addr)>; + +// call addr -> jmpl addr, %o7 +def : InstAlias<"call $addr", (JMPLrr O7, MEMrr:$addr)>; +def : InstAlias<"call $addr", (JMPLri O7, MEMri:$addr)>; + +// retl -> RETL 8 +def : InstAlias<"retl", (RETL 8)>; + +// ret -> RET 8 +def : InstAlias<"ret", (RET 8)>; + +// mov reg, rd -> or %g0, reg, rd +def : InstAlias<"mov $rs2, $rd", (ORrr IntRegs:$rd, G0, IntRegs:$rs2)>; + +// mov simm13, rd -> or %g0, simm13, rd +def : InstAlias<"mov $simm13, $rd", (ORri IntRegs:$rd, G0, i32imm:$simm13)>; diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrFormats.td b/contrib/llvm/lib/Target/Sparc/SparcInstrFormats.td index afa2874..b38a663 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcInstrFormats.td +++ b/contrib/llvm/lib/Target/Sparc/SparcInstrFormats.td @@ -12,6 +12,7 @@ class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern> field bits<32> Inst; let Namespace = "SP"; + let Size = 4; bits<2> op; let Inst{31-30} = op; // Top two bits are the 'op' field @@ -20,6 +21,9 @@ class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern> dag InOperandList = ins; let AsmString = asmstr; let Pattern = pattern; + + let DecoderNamespace = "Sparc"; + field bits<32> SoftFail = 0; } //===----------------------------------------------------------------------===// @@ -58,6 +62,27 @@ class F2_2<bits<3> op2Val, dag outs, dag ins, string asmstr, let Inst{28-25} = cond; } +class F2_3<bits<3> op2Val, bits<2> ccVal, dag outs, dag ins, string asmstr, + list<dag> pattern> + : InstSP<outs, ins, asmstr, pattern> { + bit annul; + bits<4> cond; + bit pred; + bits<19> imm19; + + let op = 0; // op = 0 + + bit annul = 0; // currently unused + let pred = 1; // default is predict taken + + let Inst{29} = annul; + let Inst{28-25} = cond; + let Inst{24-22} = op2Val; + let Inst{21-20} = ccVal; + let Inst{19} = pred; + let Inst{18-0} = imm19; +} + //===----------------------------------------------------------------------===// // Format #3 instruction classes in the Sparc //===----------------------------------------------------------------------===// @@ -75,9 +100,8 @@ class F3<dag outs, dag ins, string asmstr, list<dag> pattern> // Specific F3 classes: SparcV8 manual, page 44 // -class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins, +class F3_1_asi<bits<2> opVal, bits<6> op3val, bits<8> asi, dag outs, dag ins, string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { - bits<8> asi = 0; // asi not currently used bits<5> rs2; let op = opVal; @@ -88,6 +112,10 @@ class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins, let Inst{4-0} = rs2; } +class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins, string asmstr, + list<dag> pattern> : F3_1_asi<opVal, op3val, 0, outs, ins, + asmstr, pattern>; + class F3_2<bits<2> opVal, bits<6> op3val, dag outs, dag ins, string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { bits<13> simm13; @@ -168,12 +196,12 @@ class F3_Si<bits<2> opVal, bits<6> op3val, bit xVal, dag outs, dag ins, // Define rr and ri shift instructions with patterns. multiclass F3_S<string OpcStr, bits<6> Op3Val, bit XVal, SDNode OpNode, ValueType VT, RegisterClass RC> { - def rr : F3_Sr<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs, IntRegs:$rs2), - !strconcat(OpcStr, " $rs, $rs2, $rd"), - [(set VT:$rd, (OpNode VT:$rs, i32:$rs2))]>; - def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs, i32imm:$shcnt), - !strconcat(OpcStr, " $rs, $shcnt, $rd"), - [(set VT:$rd, (OpNode VT:$rs, (i32 imm:$shcnt)))]>; + def rr : F3_Sr<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, IntRegs:$rs2), + !strconcat(OpcStr, " $rs1, $rs2, $rd"), + [(set VT:$rd, (OpNode VT:$rs1, i32:$rs2))]>; + def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, i32imm:$shcnt), + !strconcat(OpcStr, " $rs1, $shcnt, $rd"), + [(set VT:$rd, (OpNode VT:$rs1, (i32 imm:$shcnt)))]>; } class F4<bits<6> op3, dag outs, dag ins, string asmstr, list<dag> pattern> diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp index c10b5b3..6ecf81d 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp +++ b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp @@ -431,8 +431,9 @@ unsigned SparcInstrInfo::getGlobalBaseReg(MachineFunction *MF) const MachineBasicBlock::iterator MBBI = FirstMBB.begin(); MachineRegisterInfo &RegInfo = MF->getRegInfo(); - GlobalBaseReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass); - + const TargetRegisterClass *PtrRC = + Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass; + GlobalBaseReg = RegInfo.createVirtualRegister(PtrRC); DebugLoc dl; diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td index ef7a114..ae10ca0 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td +++ b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -76,20 +76,37 @@ def ADDRrr : ComplexPattern<iPTR, 2, "SelectADDRrr", [], []>; def ADDRri : ComplexPattern<iPTR, 2, "SelectADDRri", [frameindex], []>; // Address operands +def SparcMEMrrAsmOperand : AsmOperandClass { + let Name = "MEMrr"; + let ParserMethod = "parseMEMOperand"; +} + +def SparcMEMriAsmOperand : AsmOperandClass { + let Name = "MEMri"; + let ParserMethod = "parseMEMOperand"; +} + def MEMrr : Operand<iPTR> { let PrintMethod = "printMemOperand"; let MIOperandInfo = (ops ptr_rc, ptr_rc); + let ParserMatchClass = SparcMEMrrAsmOperand; } def MEMri : Operand<iPTR> { let PrintMethod = "printMemOperand"; let MIOperandInfo = (ops ptr_rc, i32imm); + let ParserMatchClass = SparcMEMriAsmOperand; } def TLSSym : Operand<iPTR>; // Branch targets have OtherVT type. -def brtarget : Operand<OtherVT>; -def calltarget : Operand<i32>; +def brtarget : Operand<OtherVT> { + let EncoderMethod = "getBranchTargetOpValue"; +} + +def calltarget : Operand<i32> { + let EncoderMethod = "getCallTargetOpValue"; +} // Operand for printing out a condition code. let PrintMethod = "printCCOperand" in @@ -163,7 +180,7 @@ def tlscall : SDNode<"SPISD::TLS_CALL", SDT_SPCall, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; -def getPCX : Operand<i32> { +def getPCX : Operand<iPTR> { let PrintMethod = "printGetPCX"; } @@ -210,26 +227,53 @@ def FCC_O : FCC_VAL<29>; // Ordered //===----------------------------------------------------------------------===// /// F3_12 multiclass - Define a normal F3_1/F3_2 pattern in one shot. -multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode> { +multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode, + RegisterClass RC, ValueType Ty, Operand immOp> { def rr : F3_1<2, Op3Val, - (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), - !strconcat(OpcStr, " $b, $c, $dst"), - [(set i32:$dst, (OpNode i32:$b, i32:$c))]>; + (outs RC:$rd), (ins RC:$rs1, RC:$rs2), + !strconcat(OpcStr, " $rs1, $rs2, $rd"), + [(set Ty:$rd, (OpNode Ty:$rs1, Ty:$rs2))]>; def ri : F3_2<2, Op3Val, - (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), - !strconcat(OpcStr, " $b, $c, $dst"), - [(set i32:$dst, (OpNode i32:$b, (i32 simm13:$c)))]>; + (outs RC:$rd), (ins RC:$rs1, immOp:$simm13), + !strconcat(OpcStr, " $rs1, $simm13, $rd"), + [(set Ty:$rd, (OpNode Ty:$rs1, (Ty simm13:$simm13)))]>; } /// F3_12np multiclass - Define a normal F3_1/F3_2 pattern in one shot, with no /// pattern. multiclass F3_12np<string OpcStr, bits<6> Op3Val> { def rr : F3_1<2, Op3Val, - (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), - !strconcat(OpcStr, " $b, $c, $dst"), []>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), + !strconcat(OpcStr, " $rs1, $rs2, $rd"), []>; def ri : F3_2<2, Op3Val, - (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), - !strconcat(OpcStr, " $b, $c, $dst"), []>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13), + !strconcat(OpcStr, " $rs1, $simm13, $rd"), []>; +} + +// Load multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot. +multiclass Load<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode, + RegisterClass RC, ValueType Ty> { + def rr : F3_1<3, Op3Val, + (outs RC:$dst), (ins MEMrr:$addr), + !strconcat(OpcStr, " [$addr], $dst"), + [(set Ty:$dst, (OpNode ADDRrr:$addr))]>; + def ri : F3_2<3, Op3Val, + (outs RC:$dst), (ins MEMri:$addr), + !strconcat(OpcStr, " [$addr], $dst"), + [(set Ty:$dst, (OpNode ADDRri:$addr))]>; +} + +// Store multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot. +multiclass Store<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode, + RegisterClass RC, ValueType Ty> { + def rr : F3_1<3, Op3Val, + (outs), (ins MEMrr:$addr, RC:$rd), + !strconcat(OpcStr, " $rd, [$addr]"), + [(OpNode Ty:$rd, ADDRrr:$addr)]>; + def ri : F3_2<3, Op3Val, + (outs), (ins MEMri:$addr, RC:$rd), + !strconcat(OpcStr, " $rd, [$addr]"), + [(OpNode Ty:$rd, ADDRri:$addr)]>; } //===----------------------------------------------------------------------===// @@ -238,7 +282,10 @@ multiclass F3_12np<string OpcStr, bits<6> Op3Val> { // Pseudo instructions. class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern> - : InstSP<outs, ins, asmstr, pattern>; + : InstSP<outs, ins, asmstr, pattern> { + let isCodeGenOnly = 1; + let isPseudo = 1; +} // GETPCX for PIC let Defs = [O7] in { @@ -265,6 +312,9 @@ let hasSideEffects = 1, mayStore = 1 in { [(flushw)]>; } +let isBarrier = 1, isTerminator = 1, rd = 0b1000, rs1 = 0, simm13 = 5 in + def TA5 : F3_2<0b10, 0b111010, (outs), (ins), "ta 5", [(trap)]>; + let rd = 0 in def UNIMP : F2_1<0b000, (outs), (ins i32imm:$val), "unimp $val", []>; @@ -315,10 +365,18 @@ let usesCustomInserter = 1, Uses = [FCC] in { [(set f128:$dst, (SPselectfcc f128:$T, f128:$F, imm:$Cond))]>; } +// JMPL Instruction. +let isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in { + def JMPLrr: F3_1<2, 0b111000, (outs IntRegs:$dst), (ins MEMrr:$addr), + "jmpl $addr, $dst", []>; + def JMPLri: F3_2<2, 0b111000, (outs IntRegs:$dst), (ins MEMri:$addr), + "jmpl $addr, $dst", []>; +} // Section A.3 - Synthetic Instructions, p. 85 // special cases of JMPL: -let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in { +let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1, + isCodeGenOnly = 1 in { let rd = 0, rs1 = 15 in def RETL: F3_2<2, 0b111000, (outs), (ins i32imm:$val), "jmp %o7+$val", [(retflag simm13:$val)]>; @@ -329,128 +387,28 @@ let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in { } // Section B.1 - Load Integer Instructions, p. 90 -def LDSBrr : F3_1<3, 0b001001, - (outs IntRegs:$dst), (ins MEMrr:$addr), - "ldsb [$addr], $dst", - [(set i32:$dst, (sextloadi8 ADDRrr:$addr))]>; -def LDSBri : F3_2<3, 0b001001, - (outs IntRegs:$dst), (ins MEMri:$addr), - "ldsb [$addr], $dst", - [(set i32:$dst, (sextloadi8 ADDRri:$addr))]>; -def LDSHrr : F3_1<3, 0b001010, - (outs IntRegs:$dst), (ins MEMrr:$addr), - "ldsh [$addr], $dst", - [(set i32:$dst, (sextloadi16 ADDRrr:$addr))]>; -def LDSHri : F3_2<3, 0b001010, - (outs IntRegs:$dst), (ins MEMri:$addr), - "ldsh [$addr], $dst", - [(set i32:$dst, (sextloadi16 ADDRri:$addr))]>; -def LDUBrr : F3_1<3, 0b000001, - (outs IntRegs:$dst), (ins MEMrr:$addr), - "ldub [$addr], $dst", - [(set i32:$dst, (zextloadi8 ADDRrr:$addr))]>; -def LDUBri : F3_2<3, 0b000001, - (outs IntRegs:$dst), (ins MEMri:$addr), - "ldub [$addr], $dst", - [(set i32:$dst, (zextloadi8 ADDRri:$addr))]>; -def LDUHrr : F3_1<3, 0b000010, - (outs IntRegs:$dst), (ins MEMrr:$addr), - "lduh [$addr], $dst", - [(set i32:$dst, (zextloadi16 ADDRrr:$addr))]>; -def LDUHri : F3_2<3, 0b000010, - (outs IntRegs:$dst), (ins MEMri:$addr), - "lduh [$addr], $dst", - [(set i32:$dst, (zextloadi16 ADDRri:$addr))]>; -def LDrr : F3_1<3, 0b000000, - (outs IntRegs:$dst), (ins MEMrr:$addr), - "ld [$addr], $dst", - [(set i32:$dst, (load ADDRrr:$addr))]>; -def LDri : F3_2<3, 0b000000, - (outs IntRegs:$dst), (ins MEMri:$addr), - "ld [$addr], $dst", - [(set i32:$dst, (load ADDRri:$addr))]>; +defm LDSB : Load<"ldsb", 0b001001, sextloadi8, IntRegs, i32>; +defm LDSH : Load<"ldsh", 0b001010, sextloadi16, IntRegs, i32>; +defm LDUB : Load<"ldub", 0b000001, zextloadi8, IntRegs, i32>; +defm LDUH : Load<"lduh", 0b000010, zextloadi16, IntRegs, i32>; +defm LD : Load<"ld", 0b000000, load, IntRegs, i32>; // Section B.2 - Load Floating-point Instructions, p. 92 -def LDFrr : F3_1<3, 0b100000, - (outs FPRegs:$dst), (ins MEMrr:$addr), - "ld [$addr], $dst", - [(set f32:$dst, (load ADDRrr:$addr))]>; -def LDFri : F3_2<3, 0b100000, - (outs FPRegs:$dst), (ins MEMri:$addr), - "ld [$addr], $dst", - [(set f32:$dst, (load ADDRri:$addr))]>; -def LDDFrr : F3_1<3, 0b100011, - (outs DFPRegs:$dst), (ins MEMrr:$addr), - "ldd [$addr], $dst", - [(set f64:$dst, (load ADDRrr:$addr))]>; -def LDDFri : F3_2<3, 0b100011, - (outs DFPRegs:$dst), (ins MEMri:$addr), - "ldd [$addr], $dst", - [(set f64:$dst, (load ADDRri:$addr))]>; -def LDQFrr : F3_1<3, 0b100010, - (outs QFPRegs:$dst), (ins MEMrr:$addr), - "ldq [$addr], $dst", - [(set f128:$dst, (load ADDRrr:$addr))]>, - Requires<[HasV9, HasHardQuad]>; -def LDQFri : F3_2<3, 0b100010, - (outs QFPRegs:$dst), (ins MEMri:$addr), - "ldq [$addr], $dst", - [(set f128:$dst, (load ADDRri:$addr))]>, - Requires<[HasV9, HasHardQuad]>; +defm LDF : Load<"ld", 0b100000, load, FPRegs, f32>; +defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64>; +defm LDQF : Load<"ldq", 0b100010, load, QFPRegs, f128>, + Requires<[HasV9, HasHardQuad]>; // Section B.4 - Store Integer Instructions, p. 95 -def STBrr : F3_1<3, 0b000101, - (outs), (ins MEMrr:$addr, IntRegs:$rd), - "stb $rd, [$addr]", - [(truncstorei8 i32:$rd, ADDRrr:$addr)]>; -def STBri : F3_2<3, 0b000101, - (outs), (ins MEMri:$addr, IntRegs:$rd), - "stb $rd, [$addr]", - [(truncstorei8 i32:$rd, ADDRri:$addr)]>; -def STHrr : F3_1<3, 0b000110, - (outs), (ins MEMrr:$addr, IntRegs:$rd), - "sth $rd, [$addr]", - [(truncstorei16 i32:$rd, ADDRrr:$addr)]>; -def STHri : F3_2<3, 0b000110, - (outs), (ins MEMri:$addr, IntRegs:$rd), - "sth $rd, [$addr]", - [(truncstorei16 i32:$rd, ADDRri:$addr)]>; -def STrr : F3_1<3, 0b000100, - (outs), (ins MEMrr:$addr, IntRegs:$rd), - "st $rd, [$addr]", - [(store i32:$rd, ADDRrr:$addr)]>; -def STri : F3_2<3, 0b000100, - (outs), (ins MEMri:$addr, IntRegs:$rd), - "st $rd, [$addr]", - [(store i32:$rd, ADDRri:$addr)]>; +defm STB : Store<"stb", 0b000101, truncstorei8, IntRegs, i32>; +defm STH : Store<"sth", 0b000110, truncstorei16, IntRegs, i32>; +defm ST : Store<"st", 0b000100, store, IntRegs, i32>; // Section B.5 - Store Floating-point Instructions, p. 97 -def STFrr : F3_1<3, 0b100100, - (outs), (ins MEMrr:$addr, FPRegs:$rd), - "st $rd, [$addr]", - [(store f32:$rd, ADDRrr:$addr)]>; -def STFri : F3_2<3, 0b100100, - (outs), (ins MEMri:$addr, FPRegs:$rd), - "st $rd, [$addr]", - [(store f32:$rd, ADDRri:$addr)]>; -def STDFrr : F3_1<3, 0b100111, - (outs), (ins MEMrr:$addr, DFPRegs:$rd), - "std $rd, [$addr]", - [(store f64:$rd, ADDRrr:$addr)]>; -def STDFri : F3_2<3, 0b100111, - (outs), (ins MEMri:$addr, DFPRegs:$rd), - "std $rd, [$addr]", - [(store f64:$rd, ADDRri:$addr)]>; -def STQFrr : F3_1<3, 0b100110, - (outs), (ins MEMrr:$addr, QFPRegs:$rd), - "stq $rd, [$addr]", - [(store f128:$rd, ADDRrr:$addr)]>, - Requires<[HasV9, HasHardQuad]>; -def STQFri : F3_2<3, 0b100110, - (outs), (ins MEMri:$addr, QFPRegs:$rd), - "stq $rd, [$addr]", - [(store f128:$rd, ADDRri:$addr)]>, - Requires<[HasV9, HasHardQuad]>; +defm STF : Store<"st", 0b100100, store, FPRegs, f32>; +defm STDF : Store<"std", 0b100111, store, DFPRegs, f64>; +defm STQF : Store<"stq", 0b100110, store, QFPRegs, f128>, + Requires<[HasV9, HasHardQuad]>; // Section B.9 - SETHI Instruction, p. 104 def SETHIi: F2_1<0b100, @@ -464,85 +422,79 @@ let rd = 0, imm22 = 0 in def NOP : F2_1<0b100, (outs), (ins), "nop", []>; // Section B.11 - Logical Instructions, p. 106 -defm AND : F3_12<"and", 0b000001, and>; +defm AND : F3_12<"and", 0b000001, and, IntRegs, i32, i32imm>; def ANDNrr : F3_1<2, 0b000101, - (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), - "andn $b, $c, $dst", - [(set i32:$dst, (and i32:$b, (not i32:$c)))]>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), + "andn $rs1, $rs2, $rd", + [(set i32:$rd, (and i32:$rs1, (not i32:$rs2)))]>; def ANDNri : F3_2<2, 0b000101, - (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), - "andn $b, $c, $dst", []>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13), + "andn $rs1, $simm13, $rd", []>; -defm OR : F3_12<"or", 0b000010, or>; +defm OR : F3_12<"or", 0b000010, or, IntRegs, i32, i32imm>; def ORNrr : F3_1<2, 0b000110, - (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), - "orn $b, $c, $dst", - [(set i32:$dst, (or i32:$b, (not i32:$c)))]>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), + "orn $rs1, $rs2, $rd", + [(set i32:$rd, (or i32:$rs1, (not i32:$rs2)))]>; def ORNri : F3_2<2, 0b000110, - (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), - "orn $b, $c, $dst", []>; -defm XOR : F3_12<"xor", 0b000011, xor>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13), + "orn $rs1, $simm13, $rd", []>; +defm XOR : F3_12<"xor", 0b000011, xor, IntRegs, i32, i32imm>; def XNORrr : F3_1<2, 0b000111, - (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), - "xnor $b, $c, $dst", - [(set i32:$dst, (not (xor i32:$b, i32:$c)))]>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), + "xnor $rs1, $rs2, $rd", + [(set i32:$rd, (not (xor i32:$rs1, i32:$rs2)))]>; def XNORri : F3_2<2, 0b000111, - (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), - "xnor $b, $c, $dst", []>; + (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13), + "xnor $rs1, $simm13, $rd", []>; // Section B.12 - Shift Instructions, p. 107 -defm SLL : F3_12<"sll", 0b100101, shl>; -defm SRL : F3_12<"srl", 0b100110, srl>; -defm SRA : F3_12<"sra", 0b100111, sra>; +defm SLL : F3_12<"sll", 0b100101, shl, IntRegs, i32, i32imm>; +defm SRL : F3_12<"srl", 0b100110, srl, IntRegs, i32, i32imm>; +defm SRA : F3_12<"sra", 0b100111, sra, IntRegs, i32, i32imm>; // Section B.13 - Add Instructions, p. 108 -defm ADD : F3_12<"add", 0b000000, add>; +defm ADD : F3_12<"add", 0b000000, add, IntRegs, i32, i32imm>; // "LEA" forms of add (patterns to make tblgen happy) -let Predicates = [Is32Bit] in +let Predicates = [Is32Bit], isCodeGenOnly = 1 in def LEA_ADDri : F3_2<2, 0b000000, (outs IntRegs:$dst), (ins MEMri:$addr), "add ${addr:arith}, $dst", [(set iPTR:$dst, ADDRri:$addr)]>; let Defs = [ICC] in - defm ADDCC : F3_12<"addcc", 0b010000, addc>; + defm ADDCC : F3_12<"addcc", 0b010000, addc, IntRegs, i32, i32imm>; let Uses = [ICC], Defs = [ICC] in - defm ADDX : F3_12<"addxcc", 0b011000, adde>; + defm ADDE : F3_12<"addxcc", 0b011000, adde, IntRegs, i32, i32imm>; // Section B.15 - Subtract Instructions, p. 110 -defm SUB : F3_12 <"sub" , 0b000100, sub>; +defm SUB : F3_12 <"sub" , 0b000100, sub, IntRegs, i32, i32imm>; let Uses = [ICC], Defs = [ICC] in - defm SUBX : F3_12 <"subxcc" , 0b011100, sube>; + defm SUBE : F3_12 <"subxcc" , 0b011100, sube, IntRegs, i32, i32imm>; let Defs = [ICC] in - defm SUBCC : F3_12 <"subcc", 0b010100, subc>; + defm SUBCC : F3_12 <"subcc", 0b010100, subc, IntRegs, i32, i32imm>; let Defs = [ICC], rd = 0 in { def CMPrr : F3_1<2, 0b010100, - (outs), (ins IntRegs:$b, IntRegs:$c), - "cmp $b, $c", - [(SPcmpicc i32:$b, i32:$c)]>; + (outs), (ins IntRegs:$rs1, IntRegs:$rs2), + "cmp $rs1, $rs2", + [(SPcmpicc i32:$rs1, i32:$rs2)]>; def CMPri : F3_2<2, 0b010100, - (outs), (ins IntRegs:$b, i32imm:$c), - "cmp $b, $c", - [(SPcmpicc i32:$b, (i32 simm13:$c))]>; + (outs), (ins IntRegs:$rs1, i32imm:$simm13), + "cmp $rs1, $simm13", + [(SPcmpicc i32:$rs1, (i32 simm13:$simm13))]>; } -let Uses = [ICC], Defs = [ICC] in - def SUBXCCrr: F3_1<2, 0b011100, - (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), - "subxcc $b, $c, $dst", []>; - - // Section B.18 - Multiply Instructions, p. 113 let Defs = [Y] in { defm UMUL : F3_12np<"umul", 0b001010>; - defm SMUL : F3_12 <"smul", 0b001011, mul>; + defm SMUL : F3_12 <"smul", 0b001011, mul, IntRegs, i32, i32imm>; } // Section B.19 - Divide Instructions, p. 115 @@ -578,9 +530,8 @@ class BranchSP<dag ins, string asmstr, list<dag> pattern> } // Indirect branch instructions. -let isTerminator = 1, isBarrier = 1, - hasDelaySlot = 1, isBranch =1, - isIndirectBranch = 1, rd = 0 in { +let isTerminator = 1, isBarrier = 1, hasDelaySlot = 1, isBranch =1, + isIndirectBranch = 1, rd = 0, isCodeGenOnly = 1 in { def BINDrr : F3_1<2, 0b111000, (outs), (ins MEMrr:$ptr), "jmp $ptr", @@ -623,15 +574,17 @@ let Uses = [O6], let Inst{29-0} = disp; } - // indirect calls - def JMPLrr : F3_1<2, 0b111000, - (outs), (ins MEMrr:$ptr, variable_ops), - "call $ptr", - [(call ADDRrr:$ptr)]> { let rd = 15; } - def JMPLri : F3_2<2, 0b111000, - (outs), (ins MEMri:$ptr, variable_ops), - "call $ptr", - [(call ADDRri:$ptr)]> { let rd = 15; } + // indirect calls: special cases of JMPL. + let isCodeGenOnly = 1, rd = 15 in { + def CALLrr : F3_1<2, 0b111000, + (outs), (ins MEMrr:$ptr, variable_ops), + "call $ptr", + [(call ADDRrr:$ptr)]>; + def CALLri : F3_2<2, 0b111000, + (outs), (ins MEMri:$ptr, variable_ops), + "call $ptr", + [(call ADDRri:$ptr)]>; + } } // Section B.28 - Read State Register Instructions @@ -651,164 +604,164 @@ let Defs = [Y], rd = 0 in { } // Convert Integer to Floating-point Instructions, p. 141 def FITOS : F3_3u<2, 0b110100, 0b011000100, - (outs FPRegs:$dst), (ins FPRegs:$src), - "fitos $src, $dst", - [(set FPRegs:$dst, (SPitof FPRegs:$src))]>; + (outs FPRegs:$rd), (ins FPRegs:$rs2), + "fitos $rs2, $rd", + [(set FPRegs:$rd, (SPitof FPRegs:$rs2))]>; def FITOD : F3_3u<2, 0b110100, 0b011001000, - (outs DFPRegs:$dst), (ins FPRegs:$src), - "fitod $src, $dst", - [(set DFPRegs:$dst, (SPitof FPRegs:$src))]>; + (outs DFPRegs:$rd), (ins FPRegs:$rs2), + "fitod $rs2, $rd", + [(set DFPRegs:$rd, (SPitof FPRegs:$rs2))]>; def FITOQ : F3_3u<2, 0b110100, 0b011001100, - (outs QFPRegs:$dst), (ins FPRegs:$src), - "fitoq $src, $dst", - [(set QFPRegs:$dst, (SPitof FPRegs:$src))]>, + (outs QFPRegs:$rd), (ins FPRegs:$rs2), + "fitoq $rs2, $rd", + [(set QFPRegs:$rd, (SPitof FPRegs:$rs2))]>, Requires<[HasHardQuad]>; // Convert Floating-point to Integer Instructions, p. 142 def FSTOI : F3_3u<2, 0b110100, 0b011010001, - (outs FPRegs:$dst), (ins FPRegs:$src), - "fstoi $src, $dst", - [(set FPRegs:$dst, (SPftoi FPRegs:$src))]>; + (outs FPRegs:$rd), (ins FPRegs:$rs2), + "fstoi $rs2, $rd", + [(set FPRegs:$rd, (SPftoi FPRegs:$rs2))]>; def FDTOI : F3_3u<2, 0b110100, 0b011010010, - (outs FPRegs:$dst), (ins DFPRegs:$src), - "fdtoi $src, $dst", - [(set FPRegs:$dst, (SPftoi DFPRegs:$src))]>; + (outs FPRegs:$rd), (ins DFPRegs:$rs2), + "fdtoi $rs2, $rd", + [(set FPRegs:$rd, (SPftoi DFPRegs:$rs2))]>; def FQTOI : F3_3u<2, 0b110100, 0b011010011, - (outs FPRegs:$dst), (ins QFPRegs:$src), - "fqtoi $src, $dst", - [(set FPRegs:$dst, (SPftoi QFPRegs:$src))]>, + (outs FPRegs:$rd), (ins QFPRegs:$rs2), + "fqtoi $rs2, $rd", + [(set FPRegs:$rd, (SPftoi QFPRegs:$rs2))]>, Requires<[HasHardQuad]>; // Convert between Floating-point Formats Instructions, p. 143 def FSTOD : F3_3u<2, 0b110100, 0b011001001, - (outs DFPRegs:$dst), (ins FPRegs:$src), - "fstod $src, $dst", - [(set f64:$dst, (fextend f32:$src))]>; + (outs DFPRegs:$rd), (ins FPRegs:$rs2), + "fstod $rs2, $rd", + [(set f64:$rd, (fextend f32:$rs2))]>; def FSTOQ : F3_3u<2, 0b110100, 0b011001101, - (outs QFPRegs:$dst), (ins FPRegs:$src), - "fstoq $src, $dst", - [(set f128:$dst, (fextend f32:$src))]>, + (outs QFPRegs:$rd), (ins FPRegs:$rs2), + "fstoq $rs2, $rd", + [(set f128:$rd, (fextend f32:$rs2))]>, Requires<[HasHardQuad]>; def FDTOS : F3_3u<2, 0b110100, 0b011000110, - (outs FPRegs:$dst), (ins DFPRegs:$src), - "fdtos $src, $dst", - [(set f32:$dst, (fround f64:$src))]>; -def FDTOQ : F3_3u<2, 0b110100, 0b01101110, - (outs QFPRegs:$dst), (ins DFPRegs:$src), - "fdtoq $src, $dst", - [(set f128:$dst, (fextend f64:$src))]>, + (outs FPRegs:$rd), (ins DFPRegs:$rs2), + "fdtos $rs2, $rd", + [(set f32:$rd, (fround f64:$rs2))]>; +def FDTOQ : F3_3u<2, 0b110100, 0b011001110, + (outs QFPRegs:$rd), (ins DFPRegs:$rs2), + "fdtoq $rs2, $rd", + [(set f128:$rd, (fextend f64:$rs2))]>, Requires<[HasHardQuad]>; def FQTOS : F3_3u<2, 0b110100, 0b011000111, - (outs FPRegs:$dst), (ins QFPRegs:$src), - "fqtos $src, $dst", - [(set f32:$dst, (fround f128:$src))]>, + (outs FPRegs:$rd), (ins QFPRegs:$rs2), + "fqtos $rs2, $rd", + [(set f32:$rd, (fround f128:$rs2))]>, Requires<[HasHardQuad]>; def FQTOD : F3_3u<2, 0b110100, 0b011001011, - (outs DFPRegs:$dst), (ins QFPRegs:$src), - "fqtod $src, $dst", - [(set f64:$dst, (fround f128:$src))]>, + (outs DFPRegs:$rd), (ins QFPRegs:$rs2), + "fqtod $rs2, $rd", + [(set f64:$rd, (fround f128:$rs2))]>, Requires<[HasHardQuad]>; // Floating-point Move Instructions, p. 144 def FMOVS : F3_3u<2, 0b110100, 0b000000001, - (outs FPRegs:$dst), (ins FPRegs:$src), - "fmovs $src, $dst", []>; + (outs FPRegs:$rd), (ins FPRegs:$rs2), + "fmovs $rs2, $rd", []>; def FNEGS : F3_3u<2, 0b110100, 0b000000101, - (outs FPRegs:$dst), (ins FPRegs:$src), - "fnegs $src, $dst", - [(set f32:$dst, (fneg f32:$src))]>; + (outs FPRegs:$rd), (ins FPRegs:$rs2), + "fnegs $rs2, $rd", + [(set f32:$rd, (fneg f32:$rs2))]>; def FABSS : F3_3u<2, 0b110100, 0b000001001, - (outs FPRegs:$dst), (ins FPRegs:$src), - "fabss $src, $dst", - [(set f32:$dst, (fabs f32:$src))]>; + (outs FPRegs:$rd), (ins FPRegs:$rs2), + "fabss $rs2, $rd", + [(set f32:$rd, (fabs f32:$rs2))]>; // Floating-point Square Root Instructions, p.145 def FSQRTS : F3_3u<2, 0b110100, 0b000101001, - (outs FPRegs:$dst), (ins FPRegs:$src), - "fsqrts $src, $dst", - [(set f32:$dst, (fsqrt f32:$src))]>; + (outs FPRegs:$rd), (ins FPRegs:$rs2), + "fsqrts $rs2, $rd", + [(set f32:$rd, (fsqrt f32:$rs2))]>; def FSQRTD : F3_3u<2, 0b110100, 0b000101010, - (outs DFPRegs:$dst), (ins DFPRegs:$src), - "fsqrtd $src, $dst", - [(set f64:$dst, (fsqrt f64:$src))]>; + (outs DFPRegs:$rd), (ins DFPRegs:$rs2), + "fsqrtd $rs2, $rd", + [(set f64:$rd, (fsqrt f64:$rs2))]>; def FSQRTQ : F3_3u<2, 0b110100, 0b000101011, - (outs QFPRegs:$dst), (ins QFPRegs:$src), - "fsqrtq $src, $dst", - [(set f128:$dst, (fsqrt f128:$src))]>, + (outs QFPRegs:$rd), (ins QFPRegs:$rs2), + "fsqrtq $rs2, $rd", + [(set f128:$rd, (fsqrt f128:$rs2))]>, Requires<[HasHardQuad]>; // Floating-point Add and Subtract Instructions, p. 146 def FADDS : F3_3<2, 0b110100, 0b001000001, - (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), - "fadds $src1, $src2, $dst", - [(set f32:$dst, (fadd f32:$src1, f32:$src2))]>; + (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), + "fadds $rs1, $rs2, $rd", + [(set f32:$rd, (fadd f32:$rs1, f32:$rs2))]>; def FADDD : F3_3<2, 0b110100, 0b001000010, - (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), - "faddd $src1, $src2, $dst", - [(set f64:$dst, (fadd f64:$src1, f64:$src2))]>; + (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), + "faddd $rs1, $rs2, $rd", + [(set f64:$rd, (fadd f64:$rs1, f64:$rs2))]>; def FADDQ : F3_3<2, 0b110100, 0b001000011, - (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), - "faddq $src1, $src2, $dst", - [(set f128:$dst, (fadd f128:$src1, f128:$src2))]>, + (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), + "faddq $rs1, $rs2, $rd", + [(set f128:$rd, (fadd f128:$rs1, f128:$rs2))]>, Requires<[HasHardQuad]>; def FSUBS : F3_3<2, 0b110100, 0b001000101, - (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), - "fsubs $src1, $src2, $dst", - [(set f32:$dst, (fsub f32:$src1, f32:$src2))]>; + (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), + "fsubs $rs1, $rs2, $rd", + [(set f32:$rd, (fsub f32:$rs1, f32:$rs2))]>; def FSUBD : F3_3<2, 0b110100, 0b001000110, - (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), - "fsubd $src1, $src2, $dst", - [(set f64:$dst, (fsub f64:$src1, f64:$src2))]>; + (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), + "fsubd $rs1, $rs2, $rd", + [(set f64:$rd, (fsub f64:$rs1, f64:$rs2))]>; def FSUBQ : F3_3<2, 0b110100, 0b001000111, - (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), - "fsubq $src1, $src2, $dst", - [(set f128:$dst, (fsub f128:$src1, f128:$src2))]>, + (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), + "fsubq $rs1, $rs2, $rd", + [(set f128:$rd, (fsub f128:$rs1, f128:$rs2))]>, Requires<[HasHardQuad]>; // Floating-point Multiply and Divide Instructions, p. 147 def FMULS : F3_3<2, 0b110100, 0b001001001, - (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), - "fmuls $src1, $src2, $dst", - [(set f32:$dst, (fmul f32:$src1, f32:$src2))]>; + (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), + "fmuls $rs1, $rs2, $rd", + [(set f32:$rd, (fmul f32:$rs1, f32:$rs2))]>; def FMULD : F3_3<2, 0b110100, 0b001001010, - (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), - "fmuld $src1, $src2, $dst", - [(set f64:$dst, (fmul f64:$src1, f64:$src2))]>; + (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), + "fmuld $rs1, $rs2, $rd", + [(set f64:$rd, (fmul f64:$rs1, f64:$rs2))]>; def FMULQ : F3_3<2, 0b110100, 0b001001011, - (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), - "fmulq $src1, $src2, $dst", - [(set f128:$dst, (fmul f128:$src1, f128:$src2))]>, + (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), + "fmulq $rs1, $rs2, $rd", + [(set f128:$rd, (fmul f128:$rs1, f128:$rs2))]>, Requires<[HasHardQuad]>; def FSMULD : F3_3<2, 0b110100, 0b001101001, - (outs DFPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), - "fsmuld $src1, $src2, $dst", - [(set f64:$dst, (fmul (fextend f32:$src1), - (fextend f32:$src2)))]>; + (outs DFPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), + "fsmuld $rs1, $rs2, $rd", + [(set f64:$rd, (fmul (fextend f32:$rs1), + (fextend f32:$rs2)))]>; def FDMULQ : F3_3<2, 0b110100, 0b001101110, - (outs QFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), - "fdmulq $src1, $src2, $dst", - [(set f128:$dst, (fmul (fextend f64:$src1), - (fextend f64:$src2)))]>, + (outs QFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), + "fdmulq $rs1, $rs2, $rd", + [(set f128:$rd, (fmul (fextend f64:$rs1), + (fextend f64:$rs2)))]>, Requires<[HasHardQuad]>; def FDIVS : F3_3<2, 0b110100, 0b001001101, - (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), - "fdivs $src1, $src2, $dst", - [(set f32:$dst, (fdiv f32:$src1, f32:$src2))]>; + (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), + "fdivs $rs1, $rs2, $rd", + [(set f32:$rd, (fdiv f32:$rs1, f32:$rs2))]>; def FDIVD : F3_3<2, 0b110100, 0b001001110, - (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), - "fdivd $src1, $src2, $dst", - [(set f64:$dst, (fdiv f64:$src1, f64:$src2))]>; + (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), + "fdivd $rs1, $rs2, $rd", + [(set f64:$rd, (fdiv f64:$rs1, f64:$rs2))]>; def FDIVQ : F3_3<2, 0b110100, 0b001001111, - (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), - "fdivq $src1, $src2, $dst", - [(set f128:$dst, (fdiv f128:$src1, f128:$src2))]>, + (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), + "fdivq $rs1, $rs2, $rd", + [(set f128:$rd, (fdiv f128:$rs1, f128:$rs2))]>, Requires<[HasHardQuad]>; // Floating-point Compare Instructions, p. 148 @@ -820,24 +773,24 @@ def FDIVQ : F3_3<2, 0b110100, 0b001001111, let Defs = [FCC] in { def FCMPS : F3_3c<2, 0b110101, 0b001010001, - (outs), (ins FPRegs:$src1, FPRegs:$src2), - "fcmps $src1, $src2", - [(SPcmpfcc f32:$src1, f32:$src2)]>; + (outs), (ins FPRegs:$rs1, FPRegs:$rs2), + "fcmps $rs1, $rs2", + [(SPcmpfcc f32:$rs1, f32:$rs2)]>; def FCMPD : F3_3c<2, 0b110101, 0b001010010, - (outs), (ins DFPRegs:$src1, DFPRegs:$src2), - "fcmpd $src1, $src2", - [(SPcmpfcc f64:$src1, f64:$src2)]>; + (outs), (ins DFPRegs:$rs1, DFPRegs:$rs2), + "fcmpd $rs1, $rs2", + [(SPcmpfcc f64:$rs1, f64:$rs2)]>; def FCMPQ : F3_3c<2, 0b110101, 0b001010011, - (outs), (ins QFPRegs:$src1, QFPRegs:$src2), - "fcmpq $src1, $src2", - [(SPcmpfcc f128:$src1, f128:$src2)]>, + (outs), (ins QFPRegs:$rs1, QFPRegs:$rs2), + "fcmpq $rs1, $rs2", + [(SPcmpfcc f128:$rs1, f128:$rs2)]>, Requires<[HasHardQuad]>; } //===----------------------------------------------------------------------===// // Instructions for Thread Local Storage(TLS). //===----------------------------------------------------------------------===// - +let isCodeGenOnly = 1, isAsmParserOnly = 1 in { def TLS_ADDrr : F3_1<2, 0b000000, (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, TLSSym:$sym), @@ -861,6 +814,7 @@ let Uses = [O6], isCall = 1, hasDelaySlot = 1 in let op = 1; let Inst{29-0} = disp; } +} //===----------------------------------------------------------------------===// // V9 Instructions @@ -912,8 +866,9 @@ let Predicates = [HasV9], Constraints = "$f = $rd" in { def FMOVQ_ICC : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd), (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond), - "fmovd$cond %icc, $rs2, $rd", - [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>; + "fmovq$cond %icc, $rs2, $rd", + [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>, + Requires<[HasHardQuad]>; } let Uses = [FCC], opf_cc = 0b000 in { @@ -930,8 +885,9 @@ let Predicates = [HasV9], Constraints = "$f = $rd" in { def FMOVQ_FCC : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd), (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond), - "fmovd$cond %fcc0, $rs2, $rd", - [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>; + "fmovq$cond %fcc0, $rs2, $rd", + [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>, + Requires<[HasHardQuad]>; } } @@ -939,40 +895,67 @@ let Predicates = [HasV9], Constraints = "$f = $rd" in { // Floating-Point Move Instructions, p. 164 of the V9 manual. let Predicates = [HasV9] in { def FMOVD : F3_3u<2, 0b110100, 0b000000010, - (outs DFPRegs:$dst), (ins DFPRegs:$src), - "fmovd $src, $dst", []>; + (outs DFPRegs:$rd), (ins DFPRegs:$rs2), + "fmovd $rs2, $rd", []>; def FMOVQ : F3_3u<2, 0b110100, 0b000000011, - (outs QFPRegs:$dst), (ins QFPRegs:$src), - "fmovq $src, $dst", []>, + (outs QFPRegs:$rd), (ins QFPRegs:$rs2), + "fmovq $rs2, $rd", []>, Requires<[HasHardQuad]>; def FNEGD : F3_3u<2, 0b110100, 0b000000110, - (outs DFPRegs:$dst), (ins DFPRegs:$src), - "fnegd $src, $dst", - [(set f64:$dst, (fneg f64:$src))]>; + (outs DFPRegs:$rd), (ins DFPRegs:$rs2), + "fnegd $rs2, $rd", + [(set f64:$rd, (fneg f64:$rs2))]>; def FNEGQ : F3_3u<2, 0b110100, 0b000000111, - (outs QFPRegs:$dst), (ins QFPRegs:$src), - "fnegq $src, $dst", - [(set f128:$dst, (fneg f128:$src))]>, + (outs QFPRegs:$rd), (ins QFPRegs:$rs2), + "fnegq $rs2, $rd", + [(set f128:$rd, (fneg f128:$rs2))]>, Requires<[HasHardQuad]>; def FABSD : F3_3u<2, 0b110100, 0b000001010, - (outs DFPRegs:$dst), (ins DFPRegs:$src), - "fabsd $src, $dst", - [(set f64:$dst, (fabs f64:$src))]>; + (outs DFPRegs:$rd), (ins DFPRegs:$rs2), + "fabsd $rs2, $rd", + [(set f64:$rd, (fabs f64:$rs2))]>; def FABSQ : F3_3u<2, 0b110100, 0b000001011, - (outs QFPRegs:$dst), (ins QFPRegs:$src), - "fabsq $src, $dst", - [(set f128:$dst, (fabs f128:$src))]>, + (outs QFPRegs:$rd), (ins QFPRegs:$rs2), + "fabsq $rs2, $rd", + [(set f128:$rd, (fabs f128:$rs2))]>, Requires<[HasHardQuad]>; } // POPCrr - This does a ctpop of a 64-bit register. As such, we have to clear -// the top 32-bits before using it. To do this clearing, we use a SLLri X,0. +// the top 32-bits before using it. To do this clearing, we use a SRLri X,0. let rs1 = 0 in def POPCrr : F3_1<2, 0b101110, (outs IntRegs:$dst), (ins IntRegs:$src), "popc $src, $dst", []>, Requires<[HasV9]>; def : Pat<(ctpop i32:$src), - (POPCrr (SLLri $src, 0))>; + (POPCrr (SRLri $src, 0))>; + +// Atomic swap. +let hasSideEffects =1, rd = 0, rs1 = 0b01111, rs2 = 0 in + def STBAR : F3_1<2, 0b101000, (outs), (ins), "stbar", []>; + +let Predicates = [HasV9], hasSideEffects = 1, rd = 0, rs1 = 0b01111 in + def MEMBARi : F3_2<2, 0b101000, (outs), (ins i32imm:$simm13), + "membar $simm13", []>; + +let Constraints = "$val = $dst" in { + def SWAPrr : F3_1<3, 0b001111, + (outs IntRegs:$dst), (ins MEMrr:$addr, IntRegs:$val), + "swap [$addr], $dst", + [(set i32:$dst, (atomic_swap_32 ADDRrr:$addr, i32:$val))]>; + def SWAPri : F3_2<3, 0b001111, + (outs IntRegs:$dst), (ins MEMri:$addr, IntRegs:$val), + "swap [$addr], $dst", + [(set i32:$dst, (atomic_swap_32 ADDRri:$addr, i32:$val))]>; +} + +let Predicates = [HasV9], Constraints = "$swap = $rd" in + def CASrr: F3_1_asi<3, 0b111100, 0b10000000, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, + IntRegs:$swap), + "cas [$rs1], $rs2, $rd", + [(set i32:$rd, + (atomic_cmp_swap iPTR:$rs1, i32:$rs2, i32:$swap))]>; //===----------------------------------------------------------------------===// // Non-Instruction Patterns @@ -987,6 +970,8 @@ def : Pat<(i32 imm:$val), // Global addresses, constant pool entries +let Predicates = [Is32Bit] in { + def : Pat<(SPhi tglobaladdr:$in), (SETHIi tglobaladdr:$in)>; def : Pat<(SPlo tglobaladdr:$in), (ORri (i32 G0), tglobaladdr:$in)>; def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>; @@ -1009,6 +994,7 @@ def : Pat<(add iPTR:$r, (SPlo tglobaladdr:$in)), (ADDri $r, tglobaladdr:$in)>; def : Pat<(add iPTR:$r, (SPlo tconstpool:$in)), (ADDri $r, tconstpool:$in)>; def : Pat<(add iPTR:$r, (SPlo tblockaddress:$in)), (ADDri $r, tblockaddress:$in)>; +} // Calls: def : Pat<(call tglobaladdr:$dst), @@ -1032,4 +1018,18 @@ def : Pat<(i32 (zextloadi1 ADDRri:$src)), (LDUBri ADDRri:$src)>; def : Pat<(store (i32 0), ADDRrr:$dst), (STrr ADDRrr:$dst, (i32 G0))>; def : Pat<(store (i32 0), ADDRri:$dst), (STri ADDRri:$dst, (i32 G0))>; +// store bar for all atomic_fence in V8. +let Predicates = [HasNoV9] in + def : Pat<(atomic_fence imm, imm), (STBAR)>; + +// atomic_load_32 addr -> load addr +def : Pat<(i32 (atomic_load ADDRrr:$src)), (LDrr ADDRrr:$src)>; +def : Pat<(i32 (atomic_load ADDRri:$src)), (LDri ADDRri:$src)>; + +// atomic_store_32 val, addr -> store val, addr +def : Pat<(atomic_store ADDRrr:$dst, i32:$val), (STrr ADDRrr:$dst, $val)>; +def : Pat<(atomic_store ADDRri:$dst, i32:$val), (STri ADDRri:$dst, $val)>; + + include "SparcInstr64Bit.td" +include "SparcInstrAliases.td" diff --git a/contrib/llvm/lib/Target/Sparc/SparcJITInfo.cpp b/contrib/llvm/lib/Target/Sparc/SparcJITInfo.cpp index 6493c7d..959d12f 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcJITInfo.cpp +++ b/contrib/llvm/lib/Target/Sparc/SparcJITInfo.cpp @@ -12,8 +12,9 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "jit" #include "SparcJITInfo.h" +#include "Sparc.h" #include "SparcRelocations.h" - +#include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/JITCodeEmitter.h" #include "llvm/Support/Memory.h" @@ -27,26 +28,67 @@ extern "C" void SparcCompilationCallback(); extern "C" { #if defined (__sparc__) + +#if defined(__arch64__) +#define FRAME_PTR(X) #X "+2047" +#else +#define FRAME_PTR(X) #X +#endif + asm( ".text\n" "\t.align 4\n" "\t.global SparcCompilationCallback\n" "\t.type SparcCompilationCallback, #function\n" "SparcCompilationCallback:\n" - // Save current register window. - "\tsave %sp, -192, %sp\n" - // stubaddr+4 is in %g1. + // Save current register window and create stack. + // 128 (save area) + 6*8 (for arguments) + 16*8 (for float regfile) = 304 + "\tsave %sp, -304, %sp\n" + // save float regfile to the stack. + "\tstd %f0, [" FRAME_PTR(%fp) "-0]\n" + "\tstd %f2, [" FRAME_PTR(%fp) "-8]\n" + "\tstd %f4, [" FRAME_PTR(%fp) "-16]\n" + "\tstd %f6, [" FRAME_PTR(%fp) "-24]\n" + "\tstd %f8, [" FRAME_PTR(%fp) "-32]\n" + "\tstd %f10, [" FRAME_PTR(%fp) "-40]\n" + "\tstd %f12, [" FRAME_PTR(%fp) "-48]\n" + "\tstd %f14, [" FRAME_PTR(%fp) "-56]\n" + "\tstd %f16, [" FRAME_PTR(%fp) "-64]\n" + "\tstd %f18, [" FRAME_PTR(%fp) "-72]\n" + "\tstd %f20, [" FRAME_PTR(%fp) "-80]\n" + "\tstd %f22, [" FRAME_PTR(%fp) "-88]\n" + "\tstd %f24, [" FRAME_PTR(%fp) "-96]\n" + "\tstd %f26, [" FRAME_PTR(%fp) "-104]\n" + "\tstd %f28, [" FRAME_PTR(%fp) "-112]\n" + "\tstd %f30, [" FRAME_PTR(%fp) "-120]\n" + // stubaddr is in %g1. "\tcall SparcCompilationCallbackC\n" - "\t sub %g1, 4, %o0\n" + "\t mov %g1, %o0\n" + // restore float regfile from the stack. + "\tldd [" FRAME_PTR(%fp) "-0], %f0\n" + "\tldd [" FRAME_PTR(%fp) "-8], %f2\n" + "\tldd [" FRAME_PTR(%fp) "-16], %f4\n" + "\tldd [" FRAME_PTR(%fp) "-24], %f6\n" + "\tldd [" FRAME_PTR(%fp) "-32], %f8\n" + "\tldd [" FRAME_PTR(%fp) "-40], %f10\n" + "\tldd [" FRAME_PTR(%fp) "-48], %f12\n" + "\tldd [" FRAME_PTR(%fp) "-56], %f14\n" + "\tldd [" FRAME_PTR(%fp) "-64], %f16\n" + "\tldd [" FRAME_PTR(%fp) "-72], %f18\n" + "\tldd [" FRAME_PTR(%fp) "-80], %f20\n" + "\tldd [" FRAME_PTR(%fp) "-88], %f22\n" + "\tldd [" FRAME_PTR(%fp) "-96], %f24\n" + "\tldd [" FRAME_PTR(%fp) "-104], %f26\n" + "\tldd [" FRAME_PTR(%fp) "-112], %f28\n" + "\tldd [" FRAME_PTR(%fp) "-120], %f30\n" // restore original register window and // copy %o0 to %g1 - "\t restore %o0, 0, %g1\n" + "\trestore %o0, 0, %g1\n" // call the new stub "\tjmp %g1\n" "\t nop\n" "\t.size SparcCompilationCallback, .-SparcCompilationCallback" ); - #else void SparcCompilationCallback() { llvm_unreachable( @@ -55,75 +97,171 @@ extern "C" { #endif } -#define HI(Val) (((unsigned)(Val)) >> 10) -#define LO(Val) (((unsigned)(Val)) & 0x3FF) #define SETHI_INST(imm, rd) (0x01000000 | ((rd) << 25) | ((imm) & 0x3FFFFF)) #define JMP_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x38 << 19) \ | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) #define NOP_INST SETHI_INST(0, 0) +#define OR_INST_I(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x02 << 19) \ + | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) +#define OR_INST_R(rs1, rs2, rd) (0x80000000 | ((rd) << 25) | (0x02 << 19) \ + | ((rs1) << 14) | (0 << 13) | ((rs2) & 0x1F)) +#define RDPC_INST(rd) (0x80000000 | ((rd) << 25) | (0x28 << 19) \ + | (5 << 14)) +#define LDX_INST(rs1, imm, rd) (0xC0000000 | ((rd) << 25) | (0x0B << 19) \ + | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) +#define SLLX_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x25 << 19) \ + | ((rs1) << 14) | (3 << 12) | ((imm) & 0x3F)) +#define SUB_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x04 << 19) \ + | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) +#define XOR_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x03 << 19) \ + | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) +#define BA_INST(tgt) (0x10800000 | ((tgt) & 0x3FFFFF)) + +// Emit instructions to jump to Addr and store the starting address of +// the instructions emitted in the scratch register. +static void emitInstrForIndirectJump(intptr_t Addr, + unsigned scratch, + SmallVectorImpl<uint32_t> &Insts) { + + if (isInt<13>(Addr)) { + // Emit: jmpl %g0+Addr, <scratch> + // nop + Insts.push_back(JMP_INST(0, LO10(Addr), scratch)); + Insts.push_back(NOP_INST); + return; + } + + if (isUInt<32>(Addr)) { + // Emit: sethi %hi(Addr), scratch + // jmpl scratch+%lo(Addr), scratch + // sub scratch, 4, scratch + Insts.push_back(SETHI_INST(HI22(Addr), scratch)); + Insts.push_back(JMP_INST(scratch, LO10(Addr), scratch)); + Insts.push_back(SUB_INST(scratch, 4, scratch)); + return; + } + + if (Addr < 0 && isInt<33>(Addr)) { + // Emit: sethi %hix(Addr), scratch) + // xor scratch, %lox(Addr), scratch + // jmpl scratch+0, scratch + // sub scratch, 8, scratch + Insts.push_back(SETHI_INST(HIX22(Addr), scratch)); + Insts.push_back(XOR_INST(scratch, LOX10(Addr), scratch)); + Insts.push_back(JMP_INST(scratch, 0, scratch)); + Insts.push_back(SUB_INST(scratch, 8, scratch)); + return; + } + + // Emit: rd %pc, scratch + // ldx [scratch+16], scratch + // jmpl scratch+0, scratch + // sub scratch, 8, scratch + // <Addr: 8 byte> + Insts.push_back(RDPC_INST(scratch)); + Insts.push_back(LDX_INST(scratch, 16, scratch)); + Insts.push_back(JMP_INST(scratch, 0, scratch)); + Insts.push_back(SUB_INST(scratch, 8, scratch)); + Insts.push_back((uint32_t)(((int64_t)Addr) >> 32) & 0xffffffff); + Insts.push_back((uint32_t)(Addr & 0xffffffff)); + + // Instruction sequence without rdpc instruction + // 7 instruction and 2 scratch register + // Emit: sethi %hh(Addr), scratch + // or scratch, %hm(Addr), scratch + // sllx scratch, 32, scratch + // sethi %hi(Addr), scratch2 + // or scratch, scratch2, scratch + // jmpl scratch+%lo(Addr), scratch + // sub scratch, 20, scratch + // Insts.push_back(SETHI_INST(HH22(Addr), scratch)); + // Insts.push_back(OR_INST_I(scratch, HM10(Addr), scratch)); + // Insts.push_back(SLLX_INST(scratch, 32, scratch)); + // Insts.push_back(SETHI_INST(HI22(Addr), scratch2)); + // Insts.push_back(OR_INST_R(scratch, scratch2, scratch)); + // Insts.push_back(JMP_INST(scratch, LO10(Addr), scratch)); + // Insts.push_back(SUB_INST(scratch, 20, scratch)); +} extern "C" void *SparcCompilationCallbackC(intptr_t StubAddr) { // Get the address of the compiled code for this function. intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr); // Rewrite the function stub so that we don't end up here every time we - // execute the call. We're replacing the first three instructions of the - // stub with code that jumps to the compiled function: - // sethi %hi(NewVal), %g1 - // jmp %g1+%lo(NewVal) - // nop + // execute the call. We're replacing the stub instructions with code + // that jumps to the compiled function: + + SmallVector<uint32_t, 8> Insts; + intptr_t diff = (NewVal - StubAddr) >> 2; + if (isInt<22>(diff)) { + // Use branch instruction to jump + Insts.push_back(BA_INST(diff)); + Insts.push_back(NOP_INST); + } else { + // Otherwise, use indirect jump to the compiled function + emitInstrForIndirectJump(NewVal, 1, Insts); + } - *(intptr_t *)(StubAddr) = SETHI_INST(HI(NewVal), 1); - *(intptr_t *)(StubAddr + 4) = JMP_INST(1, LO(NewVal), 0); - *(intptr_t *)(StubAddr + 8) = NOP_INST; + for (unsigned i = 0, e = Insts.size(); i != e; ++i) + *(uint32_t *)(StubAddr + i*4) = Insts[i]; - sys::Memory::InvalidateInstructionCache((void*) StubAddr, 12); + sys::Memory::InvalidateInstructionCache((void*) StubAddr, Insts.size() * 4); return (void*)StubAddr; } + void SparcJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { assert(0 && "FIXME: Implement SparcJITInfo::replaceMachineCodeForFunction"); } TargetJITInfo::StubLayout SparcJITInfo::getStubLayout() { - // The stub contains 3 4-byte instructions, aligned at 4 bytes. See - // emitFunctionStub for details. - - StubLayout Result = { 3*4, 4 }; + // The stub contains maximum of 4 4-byte instructions and 8 bytes for address, + // aligned at 32 bytes. + // See emitFunctionStub and emitInstrForIndirectJump for details. + StubLayout Result = { 4*4 + 8, 32 }; return Result; } void *SparcJITInfo::emitFunctionStub(const Function *F, void *Fn, JITCodeEmitter &JCE) { - JCE.emitAlignment(4); + JCE.emitAlignment(32); void *Addr = (void*) (JCE.getCurrentPCValue()); - if (!sys::Memory::setRangeWritable(Addr, 12)) - llvm_unreachable("ERROR: Unable to mark stub writable."); + intptr_t CurrentAddr = (intptr_t)Addr; intptr_t EmittedAddr; - if (Fn != (void*)(intptr_t)SparcCompilationCallback) + SmallVector<uint32_t, 8> Insts; + if (Fn != (void*)(intptr_t)SparcCompilationCallback) { EmittedAddr = (intptr_t)Fn; - else + intptr_t diff = (EmittedAddr - CurrentAddr) >> 2; + if (isInt<22>(diff)) { + Insts.push_back(BA_INST(diff)); + Insts.push_back(NOP_INST); + } + } else { EmittedAddr = (intptr_t)SparcCompilationCallback; + } + + if (Insts.size() == 0) + emitInstrForIndirectJump(EmittedAddr, 1, Insts); - // sethi %hi(EmittedAddr), %g1 - // jmp %g1+%lo(EmittedAddr), %g1 - // nop - JCE.emitWordBE(SETHI_INST(HI(EmittedAddr), 1)); - JCE.emitWordBE(JMP_INST(1, LO(EmittedAddr), 1)); - JCE.emitWordBE(NOP_INST); + if (!sys::Memory::setRangeWritable(Addr, 4 * Insts.size())) + llvm_unreachable("ERROR: Unable to mark stub writable."); + + for (unsigned i = 0, e = Insts.size(); i != e; ++i) + JCE.emitWordBE(Insts[i]); - sys::Memory::InvalidateInstructionCache(Addr, 12); - if (!sys::Memory::setRangeExecutable(Addr, 12)) + sys::Memory::InvalidateInstructionCache(Addr, 4 * Insts.size()); + if (!sys::Memory::setRangeExecutable(Addr, 4 * Insts.size())) llvm_unreachable("ERROR: Unable to mark stub executable."); return Addr; } + TargetJITInfo::LazyResolverFn SparcJITInfo::getLazyResolverFunction(JITCompilerFn F) { JITCompilerFunction = F; @@ -159,6 +297,27 @@ void SparcJITInfo::relocate(void *Function, MachineRelocation *MR, case SP::reloc_sparc_pc19: ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x7ffff; break; + + case SP::reloc_sparc_h44: + ResultPtr = (ResultPtr >> 22) & 0x3fffff; + break; + + case SP::reloc_sparc_m44: + ResultPtr = (ResultPtr >> 12) & 0x3ff; + break; + + case SP::reloc_sparc_l44: + ResultPtr = (ResultPtr & 0xfff); + break; + + case SP::reloc_sparc_hh: + ResultPtr = (((int64_t)ResultPtr) >> 42) & 0x3fffff; + break; + + case SP::reloc_sparc_hm: + ResultPtr = (((int64_t)ResultPtr) >> 32) & 0x3ff; + break; + } *((unsigned*) RelocPos) |= (unsigned) ResultPtr; } diff --git a/contrib/llvm/lib/Target/Sparc/SparcMCInstLower.cpp b/contrib/llvm/lib/Target/Sparc/SparcMCInstLower.cpp new file mode 100644 index 0000000..fc3ba90 --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/SparcMCInstLower.cpp @@ -0,0 +1,109 @@ +//===-- SparcMCInstLower.cpp - Convert Sparc MachineInstr to MCInst -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower Sparc MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "Sparc.h" +#include "MCTargetDesc/SparcMCExpr.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Target/Mangler.h" +#include "llvm/ADT/SmallString.h" + +using namespace llvm; + + +static MCOperand LowerSymbolOperand(const MachineInstr *MI, + const MachineOperand &MO, + AsmPrinter &AP) { + + SparcMCExpr::VariantKind Kind = + (SparcMCExpr::VariantKind)MO.getTargetFlags(); + const MCSymbol *Symbol = 0; + + switch(MO.getType()) { + default: llvm_unreachable("Unknown type in LowerSymbolOperand"); + case MachineOperand::MO_MachineBasicBlock: + Symbol = MO.getMBB()->getSymbol(); + break; + + case MachineOperand::MO_GlobalAddress: + Symbol = AP.getSymbol(MO.getGlobal()); + break; + + case MachineOperand::MO_BlockAddress: + Symbol = AP.GetBlockAddressSymbol(MO.getBlockAddress()); + break; + + case MachineOperand::MO_ExternalSymbol: + Symbol = AP.GetExternalSymbolSymbol(MO.getSymbolName()); + break; + + case MachineOperand::MO_ConstantPoolIndex: + Symbol = AP.GetCPISymbol(MO.getIndex()); + break; + } + + const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Symbol, + AP.OutContext); + const SparcMCExpr *expr = SparcMCExpr::Create(Kind, MCSym, + AP.OutContext); + return MCOperand::CreateExpr(expr); +} + +static MCOperand LowerOperand(const MachineInstr *MI, + const MachineOperand &MO, + AsmPrinter &AP) { + switch(MO.getType()) { + default: llvm_unreachable("unknown operand type"); break; + case MachineOperand::MO_Register: + if (MO.isImplicit()) + break; + return MCOperand::CreateReg(MO.getReg()); + + case MachineOperand::MO_Immediate: + return MCOperand::CreateImm(MO.getImm()); + + case MachineOperand::MO_MachineBasicBlock: + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_BlockAddress: + case MachineOperand::MO_ExternalSymbol: + case MachineOperand::MO_ConstantPoolIndex: + return LowerSymbolOperand(MI, MO, AP); + + case MachineOperand::MO_RegisterMask: break; + + } + return MCOperand(); +} + +void llvm::LowerSparcMachineInstrToMCInst(const MachineInstr *MI, + MCInst &OutMI, + AsmPrinter &AP) +{ + + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + MCOperand MCOp = LowerOperand(MI, MO, AP); + + if (MCOp.isValid()) + OutMI.addOperand(MCOp); + } +} diff --git a/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp b/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp index c98613a..f222382 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp +++ b/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp @@ -35,7 +35,7 @@ ReserveAppRegisters("sparc-reserve-app-registers", cl::Hidden, cl::init(false), cl::desc("Reserve application registers (%g2-%g4)")); SparcRegisterInfo::SparcRegisterInfo(SparcSubtarget &st) - : SparcGenRegisterInfo(SP::I7), Subtarget(st) { + : SparcGenRegisterInfo(SP::O7), Subtarget(st) { } const uint16_t* SparcRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) diff --git a/contrib/llvm/lib/Target/Sparc/SparcRelocations.h b/contrib/llvm/lib/Target/Sparc/SparcRelocations.h index 388cfe7..c1ff78d 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcRelocations.h +++ b/contrib/llvm/lib/Target/Sparc/SparcRelocations.h @@ -33,7 +33,22 @@ namespace llvm { reloc_sparc_pc22 = 4, // reloc_sparc_pc22 - pc rel. 19 bits for branch with icc/xcc - reloc_sparc_pc19 = 5 + reloc_sparc_pc19 = 5, + + // reloc_sparc_h44 - 43-22 bits + reloc_sparc_h44 = 6, + + // reloc_sparc_m44 - 21-12 bits + reloc_sparc_m44 = 7, + + // reloc_sparc_l44 - lower 12 bits + reloc_sparc_l44 = 8, + + // reloc_sparc_hh - 63-42 bits + reloc_sparc_hh = 9, + + // reloc_sparc_hm - 41-32 bits + reloc_sparc_hm = 10 }; } } diff --git a/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp index 7d09d0e..6fc9d56 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp +++ b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp @@ -31,20 +31,20 @@ SparcSubtarget::SparcSubtarget(const std::string &TT, const std::string &CPU, V8DeprecatedInsts(false), IsVIS(false), Is64Bit(is64Bit), - HasHardQuad(false) { + HasHardQuad(false), + UsePopc(false) { // Determine default and user specified characteristics std::string CPUName = CPU; - if (CPUName.empty()) { - if (is64Bit) - CPUName = "v9"; - else - CPUName = "v8"; - } - IsV9 = CPUName == "v9"; + if (CPUName.empty()) + CPUName = (is64Bit) ? "v9" : "v8"; // Parse features string. ParseSubtargetFeatures(CPUName, FS); + + // Popc is a v9-only instruction. + if (!IsV9) + UsePopc = false; } diff --git a/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h index 0f81cc9..e4239e2 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h +++ b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h @@ -30,6 +30,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo { bool IsVIS; bool Is64Bit; bool HasHardQuad; + bool UsePopc; public: SparcSubtarget(const std::string &TT, const std::string &CPU, @@ -39,6 +40,7 @@ public: bool isVIS() const { return IsVIS; } bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; } bool hasHardQuad() const { return HasHardQuad; } + bool usePopc() const { return UsePopc; } /// ParseSubtargetFeatures - Parses features string setting specified /// subtarget options. Definition of function is auto generated by tblgen. diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp new file mode 100644 index 0000000..18612bd --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp @@ -0,0 +1,48 @@ +//===------- SparcTargetObjectFile.cpp - Sparc Object Info Impl -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SparcTargetObjectFile.h" +#include "MCTargetDesc/SparcMCExpr.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Target/Mangler.h" + +using namespace llvm; + + +const MCExpr *SparcELFTargetObjectFile:: +getTTypeGlobalReference(const GlobalValue *GV, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const { + + if (Encoding & dwarf::DW_EH_PE_pcrel) { + MachineModuleInfoELF &ELFMMI = MMI->getObjFileInfo<MachineModuleInfoELF>(); + + //MCSymbol *SSym = getSymbolWithGlobalValueBase(*Mang, GV, ".DW.stub"); + SmallString<60> NameStr; + Mang->getNameWithPrefix(NameStr, GV, true); + NameStr.append(".DW.stub"); + MCSymbol *SSym = getContext().GetOrCreateSymbol(NameStr.str()); + + // Add information about the stub reference to ELFMMI so that the stub + // gets emitted by the asmprinter. + MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(SSym); + if (StubSym.getPointer() == 0) { + MCSymbol *Sym = getSymbol(*Mang, GV); + StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); + } + + MCContext &Ctx = getContext(); + return SparcMCExpr::Create(SparcMCExpr::VK_Sparc_R_DISP32, + MCSymbolRefExpr::Create(SSym, Ctx), Ctx); + } + + return TargetLoweringObjectFileELF:: + getTTypeGlobalReference(GV, Mang, MMI, Encoding, Streamer); +} diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h new file mode 100644 index 0000000..7cf850d --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h @@ -0,0 +1,34 @@ +//===-- SparcTargetObjectFile.h - Sparc Object Info -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_SPARC_TARGETOBJECTFILE_H +#define LLVM_TARGET_SPARC_TARGETOBJECTFILE_H + +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + +namespace llvm { + +class MCContext; +class TargetMachine; + +class SparcELFTargetObjectFile : public TargetLoweringObjectFileELF { +public: + SparcELFTargetObjectFile() : + TargetLoweringObjectFileELF() + {} + + const MCExpr * + getTTypeGlobalReference(const GlobalValue *GV, Mangler *Mang, + MachineModuleInfo *MMI, unsigned Encoding, + MCStreamer &Streamer) const; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetStreamer.h b/contrib/llvm/lib/Target/Sparc/SparcTargetStreamer.h new file mode 100644 index 0000000..73339ac --- /dev/null +++ b/contrib/llvm/lib/Target/Sparc/SparcTargetStreamer.h @@ -0,0 +1,47 @@ +//===-- SparcTargetStreamer.h - Sparc Target Streamer ----------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SPARCTARGETSTREAMER_H +#define SPARCTARGETSTREAMER_H + +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCStreamer.h" + +namespace llvm { +class SparcTargetStreamer : public MCTargetStreamer { + virtual void anchor(); + +public: + /// Emit ".register <reg>, #ignore". + virtual void emitSparcRegisterIgnore(unsigned reg) = 0; + /// Emit ".register <reg>, #scratch". + virtual void emitSparcRegisterScratch(unsigned reg) = 0; +}; + +// This part is for ascii assembly output +class SparcTargetAsmStreamer : public SparcTargetStreamer { + formatted_raw_ostream &OS; + +public: + SparcTargetAsmStreamer(formatted_raw_ostream &OS); + virtual void emitSparcRegisterIgnore(unsigned reg); + virtual void emitSparcRegisterScratch(unsigned reg); + +}; + +// This part is for ELF object output +class SparcTargetELFStreamer : public SparcTargetStreamer { +public: + MCELFStreamer &getStreamer(); + virtual void emitSparcRegisterIgnore(unsigned reg) {} + virtual void emitSparcRegisterScratch(unsigned reg) {} +}; +} // end namespace llvm + +#endif diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp index bccd0d7..af9221b 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp @@ -4529,6 +4529,13 @@ public: UIntMaxType = UnsignedLong; } Int64Type = IntMaxType; + + // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit + // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned. + LongDoubleWidth = 128; + LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } virtual void getTargetDefines(const LangOptions &Opts, @@ -4545,6 +4552,22 @@ public: Builder.defineMacro("__sparcv9__"); } } + + virtual bool setCPU(const std::string &Name) { + bool CPUKnown = llvm::StringSwitch<bool>(Name) + .Case("v9", true) + .Case("ultrasparc", true) + .Case("ultrasparc3", true) + .Case("niagara", true) + .Case("niagara2", true) + .Case("niagara3", true) + .Case("niagara4", true) + .Default(false); + + // No need to store the CPU yet. There aren't any CPU-specific + // macros to define. + return CPUKnown; + } }; } // end anonymous namespace. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp index 76acf87..45eaec6 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp @@ -5349,6 +5349,11 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const { if (!isAggregateTypeForABI(Ty)) return ABIArgInfo::getDirect(); + // If a C++ object has either a non-trivial copy constructor or a non-trivial + // destructor, it is passed with an explicit indirect pointer / sret pointer. + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) + return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); + // This is a small aggregate type that should be passed in registers. // Build a coercion type from the LLVM struct type. llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty)); @@ -5430,9 +5435,50 @@ class SparcV9TargetCodeGenInfo : public TargetCodeGenInfo { public: SparcV9TargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new SparcV9ABIInfo(CGT)) {} + + int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const { + return 14; + } + + bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const; }; } // end anonymous namespace +bool +SparcV9TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const { + // This is calculated from the LLVM and GCC tables and verified + // against gcc output. AFAIK all ABIs use the same encoding. + + CodeGen::CGBuilderTy &Builder = CGF.Builder; + + llvm::IntegerType *i8 = CGF.Int8Ty; + llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); + llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); + + // 0-31: the 8-byte general-purpose registers + AssignToArrayRange(Builder, Address, Eight8, 0, 31); + + // 32-63: f0-31, the 4-byte floating-point registers + AssignToArrayRange(Builder, Address, Four8, 32, 63); + + // Y = 64 + // PSR = 65 + // WIM = 66 + // TBR = 67 + // PC = 68 + // NPC = 69 + // FSR = 70 + // CSR = 71 + AssignToArrayRange(Builder, Address, Eight8, 64, 71); + + // 72-87: d0-15, the 8-byte floating-point registers + AssignToArrayRange(Builder, Address, Eight8, 72, 87); + + return false; +} + //===----------------------------------------------------------------------===// // Xcore ABI Implementation diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp index 8a47e76..f5dc3dfb 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp @@ -1164,6 +1164,13 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { "powerpc64le-suse-linux", "ppc64le-redhat-linux" }; + static const char *const SPARCv8LibDirs[] = { "/lib32", "/lib" }; + static const char *const SPARCv8Triples[] = { "sparc-linux-gnu", + "sparcv8-linux-gnu" }; + static const char *const SPARCv9LibDirs[] = { "/lib64", "/lib" }; + static const char *const SPARCv9Triples[] = { "sparc64-linux-gnu", + "sparcv9-linux-gnu" }; + static const char *const SystemZLibDirs[] = { "/lib64", "/lib" }; static const char *const SystemZTriples[] = { "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", @@ -1283,6 +1290,26 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { TripleAliases.append(PPC64LETriples, PPC64LETriples + llvm::array_lengthof(PPC64LETriples)); break; + case llvm::Triple::sparc: + LibDirs.append(SPARCv8LibDirs, + SPARCv8LibDirs + llvm::array_lengthof(SPARCv8LibDirs)); + TripleAliases.append(SPARCv8Triples, + SPARCv8Triples + llvm::array_lengthof(SPARCv8Triples)); + BiarchLibDirs.append(SPARCv9LibDirs, + SPARCv9LibDirs + llvm::array_lengthof(SPARCv9LibDirs)); + BiarchTripleAliases.append( + SPARCv9Triples, SPARCv9Triples + llvm::array_lengthof(SPARCv9Triples)); + break; + case llvm::Triple::sparcv9: + LibDirs.append(SPARCv9LibDirs, + SPARCv9LibDirs + llvm::array_lengthof(SPARCv9LibDirs)); + TripleAliases.append(SPARCv9Triples, + SPARCv9Triples + llvm::array_lengthof(SPARCv9Triples)); + BiarchLibDirs.append(SPARCv8LibDirs, + SPARCv8LibDirs + llvm::array_lengthof(SPARCv8LibDirs)); + BiarchTripleAliases.append( + SPARCv8Triples, SPARCv8Triples + llvm::array_lengthof(SPARCv8Triples)); + break; case llvm::Triple::systemz: LibDirs.append(SystemZLibDirs, SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs)); @@ -1379,6 +1406,7 @@ static bool findTargetBiarchSuffix(std::string &Suffix, StringRef Path, Suffix = "/n32"; else if (TargetArch == llvm::Triple::x86_64 || TargetArch == llvm::Triple::ppc64 || + TargetArch == llvm::Triple::sparcv9 || TargetArch == llvm::Triple::systemz || TargetArch == llvm::Triple::mips64 || TargetArch == llvm::Triple::mips64el) diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp index 3529fc7..b37b31c 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp @@ -1373,7 +1373,8 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) { } case llvm::Triple::sparc: - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + case llvm::Triple::sparcv9: + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) return A->getValue(); return ""; @@ -5785,6 +5786,24 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, default: CmdArgs.push_back("-matpcs"); } + } else if (getToolChain().getArch() == llvm::Triple::sparc || + getToolChain().getArch() == llvm::Triple::sparcv9) { + if (getToolChain().getArch() == llvm::Triple::sparc) + CmdArgs.push_back("-Av8plusa"); + else + CmdArgs.push_back("-Av9a"); + + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, + options::OPT_fpie, options::OPT_fno_pie); + if (LastPICArg && + (LastPICArg->getOption().matches(options::OPT_fPIC) || + LastPICArg->getOption().matches(options::OPT_fpic) || + LastPICArg->getOption().matches(options::OPT_fPIE) || + LastPICArg->getOption().matches(options::OPT_fpie))) { + CmdArgs.push_back("-KPIC"); + } } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -6194,6 +6213,7 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &Args, const char *LinkingOutput) const { ArgStringList CmdArgs; + bool NeedsKPIC = false; // Add --32/--64 to make sure we get the format we want. // This is incomplete @@ -6213,6 +6233,14 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64le"); CmdArgs.push_back("-many"); + } else if (getToolChain().getArch() == llvm::Triple::sparc) { + CmdArgs.push_back("-32"); + CmdArgs.push_back("-Av8plusa"); + NeedsKPIC = true; + } else if (getToolChain().getArch() == llvm::Triple::sparcv9) { + CmdArgs.push_back("-64"); + CmdArgs.push_back("-Av9a"); + NeedsKPIC = true; } else if (getToolChain().getArch() == llvm::Triple::arm) { StringRef MArch = getToolChain().getArchName(); if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") @@ -6272,6 +6300,15 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("-mmsa")); } + NeedsKPIC = true; + } else if (getToolChain().getArch() == llvm::Triple::systemz) { + // Always pass an -march option, since our default of z10 is later + // than the GNU assembler's default. + StringRef CPUName = getSystemZTargetCPU(Args); + CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); + } + + if (NeedsKPIC) { Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, options::OPT_fpic, options::OPT_fno_pic, options::OPT_fPIE, options::OPT_fno_PIE, @@ -6283,11 +6320,6 @@ void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, LastPICArg->getOption().matches(options::OPT_fpie))) { CmdArgs.push_back("-KPIC"); } - } else if (getToolChain().getArch() == llvm::Triple::systemz) { - // Always pass an -march option, since our default of z10 is later - // than the GNU assembler's default. - StringRef CPUName = getSystemZTargetCPU(Args); - CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -6357,7 +6389,8 @@ static StringRef getLinuxDynamicLinker(const ArgList &Args, const toolchains::Linux &ToolChain) { if (ToolChain.getTriple().getEnvironment() == llvm::Triple::Android) return "/system/bin/linker"; - else if (ToolChain.getArch() == llvm::Triple::x86) + else if (ToolChain.getArch() == llvm::Triple::x86 || + ToolChain.getArch() == llvm::Triple::sparc) return "/lib/ld-linux.so.2"; else if (ToolChain.getArch() == llvm::Triple::aarch64) return "/lib/ld-linux-aarch64.so.1"; @@ -6382,6 +6415,8 @@ static StringRef getLinuxDynamicLinker(const ArgList &Args, ToolChain.getArch() == llvm::Triple::ppc64le || ToolChain.getArch() == llvm::Triple::systemz) return "/lib64/ld64.so.1"; + else if (ToolChain.getArch() == llvm::Triple::sparcv9) + return "/lib64/ld-linux.so.2"; else return "/lib64/ld-linux-x86-64.so.2"; } @@ -6444,6 +6479,10 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("elf32ppclinux"); else if (ToolChain.getArch() == llvm::Triple::ppc64) CmdArgs.push_back("elf64ppc"); + else if (ToolChain.getArch() == llvm::Triple::sparc) + CmdArgs.push_back("elf32_sparc"); + else if (ToolChain.getArch() == llvm::Triple::sparcv9) + CmdArgs.push_back("elf64_sparc"); else if (ToolChain.getArch() == llvm::Triple::mips) CmdArgs.push_back("elf32btsmip"); else if (ToolChain.getArch() == llvm::Triple::mipsel) |