Commit 0a878c4760718e1604e2cfe423252729716110ad
1 parent
1a14026e
PPC TCG Fixes
* Fix typo in aliased div2 * "Optimize" aliased div2/divu2 * Fix two remaining branch retranslation problems (Kudos to Andrzej Zaborowski) * Rework goto_tb and set_jmp_target1 * Use correct size when flushing icache * Use correct register selection for ORI (Was harmless since in both cases srcreg was equal to dstreg) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4691 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
37 additions
and
48 deletions
exec-all.h
... | ... | @@ -184,32 +184,37 @@ extern int code_gen_max_blocks; |
184 | 184 | #if defined(USE_DIRECT_JUMP) |
185 | 185 | |
186 | 186 | #if defined(__powerpc__) |
187 | +static inline void flush_icache_range(unsigned long start, unsigned long stop); | |
187 | 188 | static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) |
188 | 189 | { |
189 | - uint32_t val, *ptr; | |
190 | + /* This must be in concord with INDEX_op_goto_tb inside tcg_out_op */ | |
191 | + uint32_t *ptr; | |
190 | 192 | long disp = addr - jmp_addr; |
193 | + unsigned long patch_size; | |
191 | 194 | |
192 | 195 | ptr = (uint32_t *)jmp_addr; |
193 | - val = *ptr; | |
194 | 196 | |
195 | 197 | if ((disp << 6) >> 6 != disp) { |
196 | - uint16_t *p1; | |
197 | - | |
198 | - p1 = (uint16_t *) ptr; | |
199 | - *ptr = (val & ~0x03fffffc) | 4; | |
200 | - p1[3] = addr >> 16; | |
201 | - p1[5] = addr & 0xffff; | |
198 | + ptr[0] = 0x3c000000 | (addr >> 16); /* lis 0,addr@ha */ | |
199 | + ptr[1] = 0x60000000 | (addr & 0xffff); /* la 0,addr@l(0) */ | |
200 | + ptr[2] = 0x7c0903a6; /* mtctr 0 */ | |
201 | + ptr[3] = 0x4e800420; /* brctr */ | |
202 | + patch_size = 16; | |
202 | 203 | } else { |
203 | 204 | /* patch the branch destination */ |
204 | - val = (val & ~0x03fffffc) | (disp & 0x03fffffc); | |
205 | - *ptr = val; | |
205 | + if (disp != 16) { | |
206 | + *ptr = 0x48000000 | (disp & 0x03fffffc); /* b disp */ | |
207 | + patch_size = 4; | |
208 | + } else { | |
209 | + ptr[0] = 0x60000000; /* nop */ | |
210 | + ptr[1] = 0x60000000; | |
211 | + ptr[2] = 0x60000000; | |
212 | + ptr[3] = 0x60000000; | |
213 | + patch_size = 16; | |
214 | + } | |
206 | 215 | } |
207 | 216 | /* flush icache */ |
208 | - asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory"); | |
209 | - asm volatile ("sync" : : : "memory"); | |
210 | - asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory"); | |
211 | - asm volatile ("sync" : : : "memory"); | |
212 | - asm volatile ("isync" : : : "memory"); | |
217 | + flush_icache_range(jmp_addr, jmp_addr + patch_size); | |
213 | 218 | } |
214 | 219 | #elif defined(__i386__) || defined(__x86_64__) |
215 | 220 | static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) | ... | ... |
tcg/ppc/tcg-target.c
... | ... | @@ -388,7 +388,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, |
388 | 388 | else { |
389 | 389 | tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff)); |
390 | 390 | if (arg & 0xffff) |
391 | - tcg_out32 (s, ORI | RT (ret) | RA (ret) | (arg & 0xffff)); | |
391 | + tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff)); | |
392 | 392 | } |
393 | 393 | } |
394 | 394 | |
... | ... | @@ -939,18 +939,14 @@ static void tcg_out_brcond(TCGContext *s, int cond, |
939 | 939 | tcg_out32 (s, op | RA (arg1) | RB (arg2)); |
940 | 940 | } |
941 | 941 | |
942 | - if (l->has_value) { | |
943 | - tcg_target_long disp; | |
944 | - | |
945 | - disp = (tcg_target_long) s->code_ptr - l->u.value; | |
946 | - if (disp != (int16_t) disp) | |
947 | - tcg_abort (); | |
948 | - | |
942 | + if (l->has_value) | |
949 | 943 | tcg_out32 (s, tcg_to_bc[cond] | reloc_pc14_val (s->code_ptr, |
950 | 944 | l->u.value)); |
951 | - } | |
952 | 945 | else { |
953 | - tcg_out32 (s, tcg_to_bc[cond]); | |
946 | + uint16_t val = *(uint16_t *) &s->code_ptr[2]; | |
947 | + | |
948 | + /* Thanks to Andrzej Zaborowski */ | |
949 | + tcg_out32 (s, tcg_to_bc[cond] | (val & 0xfffc)); | |
954 | 950 | tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0); |
955 | 951 | } |
956 | 952 | } |
... | ... | @@ -1029,24 +1025,9 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, |
1029 | 1025 | case INDEX_op_goto_tb: |
1030 | 1026 | if (s->tb_jmp_offset) { |
1031 | 1027 | /* direct jump method */ |
1032 | - uint32_t val; | |
1033 | - uint16_t *p; | |
1034 | 1028 | |
1035 | 1029 | s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; |
1036 | - /* Thanks to Andrzej Zaborowski for this */ | |
1037 | - val = *(uint32_t *) s->code_ptr & 0x3fffffc; | |
1038 | - | |
1039 | - tcg_out32 (s, B | val); | |
1040 | - | |
1041 | - /* For branches outside of LL range | |
1042 | - This must be in concord with tb_set_jmp_target1 */ | |
1043 | - p = (uint16_t *) s->code_ptr; | |
1044 | - p[0] = (ADDIS | RT (0) | RA (0)) >> 16; | |
1045 | - p[2] = (ORI | RT (0) | RA (0)) >> 16; | |
1046 | - s->code_ptr += 8; | |
1047 | - | |
1048 | - tcg_out32 (s, MTSPR | RS (0) | CTR); | |
1049 | - tcg_out32 (s, BCCTR | BO_ALWAYS); | |
1030 | + s->code_ptr += 16; | |
1050 | 1031 | } |
1051 | 1032 | else { |
1052 | 1033 | tcg_abort (); |
... | ... | @@ -1061,7 +1042,10 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, |
1061 | 1042 | tcg_out_b (s, 0, l->u.value); |
1062 | 1043 | } |
1063 | 1044 | else { |
1064 | - tcg_out32 (s, B); | |
1045 | + uint32_t val = *(uint32_t *) s->code_ptr; | |
1046 | + | |
1047 | + /* Thanks to Andrzej Zaborowski */ | |
1048 | + tcg_out32 (s, B | (val & 0x3fffffc)); | |
1065 | 1049 | tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0); |
1066 | 1050 | } |
1067 | 1051 | } |
... | ... | @@ -1222,10 +1206,10 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, |
1222 | 1206 | case INDEX_op_div2_i32: |
1223 | 1207 | if (args[0] == args[2] || args[0] == args[3]) { |
1224 | 1208 | tcg_out32 (s, DIVW | TAB (0, args[2], args[3])); |
1209 | + tcg_out32 (s, MTSPR | RS (0) | CTR); | |
1225 | 1210 | tcg_out32 (s, MULLW | TAB (0, 0, args[3])); |
1226 | - tcg_out32 (s, SUBF | TAB (0, 0, args[2])); | |
1227 | - tcg_out32 (s, DIVW | TAB (args[0], args[2], args[3])); | |
1228 | - tcg_out_mov (s, args[1], 0); | |
1211 | + tcg_out32 (s, SUBF | TAB (args[1], 0, args[2])); | |
1212 | + tcg_out32 (s, MFSPR | RT (args[0]) | CTR); | |
1229 | 1213 | } |
1230 | 1214 | else { |
1231 | 1215 | tcg_out32 (s, DIVW | TAB (args[0], args[2], args[3])); |
... | ... | @@ -1236,10 +1220,10 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, |
1236 | 1220 | case INDEX_op_divu2_i32: |
1237 | 1221 | if (args[0] == args[2] || args[0] == args[3]) { |
1238 | 1222 | tcg_out32 (s, DIVWU | TAB (0, args[2], args[3])); |
1223 | + tcg_out32 (s, MTSPR | RS (0) | CTR); | |
1239 | 1224 | tcg_out32 (s, MULLW | TAB (0, 0, args[3])); |
1240 | - tcg_out32 (s, SUBF | TAB (0, 0, args[2])); | |
1241 | - tcg_out32 (s, DIVWU | TAB (args[0], args[2], args[3])); | |
1242 | - tcg_out_mov (s, args[1], 0); | |
1225 | + tcg_out32 (s, SUBF | TAB (args[1], 0, args[2])); | |
1226 | + tcg_out32 (s, MFSPR | RT (args[0]) | CTR); | |
1243 | 1227 | } |
1244 | 1228 | else { |
1245 | 1229 | tcg_out32 (s, DIVWU | TAB (args[0], args[2], args[3])); | ... | ... |