Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef VM_ASSEMBLER_MIPS_H_ | 5 #ifndef VM_ASSEMBLER_MIPS_H_ |
| 6 #define VM_ASSEMBLER_MIPS_H_ | 6 #define VM_ASSEMBLER_MIPS_H_ |
| 7 | 7 |
| 8 #ifndef VM_ASSEMBLER_H_ | 8 #ifndef VM_ASSEMBLER_H_ |
| 9 #error Do not include assembler_mips.h directly; use assembler.h instead. | 9 #error Do not include assembler_mips.h directly; use assembler.h instead. |
| 10 #endif | 10 #endif |
| 11 | 11 |
| 12 #include "platform/assert.h" | 12 #include "platform/assert.h" |
| 13 #include "platform/utils.h" | 13 #include "platform/utils.h" |
| 14 #include "vm/constants_mips.h" | 14 #include "vm/constants_mips.h" |
| 15 #include "vm/simulator.h" | 15 #include "vm/simulator.h" |
| 16 | 16 |
| 17 // References to documentation in this file refer to: | 17 // References to documentation in this file refer to: |
| 18 // "MIPS® Architecture For Programmers Volume I-A: | 18 // "MIPS® Architecture For Programmers Volume I-A: |
| 19 // Introduction to the MIPS32® Architecture" in short "VolI-A" | 19 // Introduction to the MIPS32® Architecture" in short "VolI-A" |
| 20 // and | 20 // and |
| 21 // "MIPS® Architecture For Programmers Volume II-A: | 21 // "MIPS® Architecture For Programmers Volume II-A: |
| 22 // The MIPS32® Instruction Set" in short "VolII-A" | 22 // The MIPS32® Instruction Set" in short "VolII-A" |
| 23 namespace dart { | 23 namespace dart { |
| 24 | 24 |
| 25 DECLARE_FLAG(bool, mips_far_branches); | |
| 26 | |
| 25 // Forward declarations. | 27 // Forward declarations. |
| 26 class RuntimeEntry; | 28 class RuntimeEntry; |
| 27 | 29 |
| 28 class Immediate : public ValueObject { | 30 class Immediate : public ValueObject { |
| 29 public: | 31 public: |
| 30 explicit Immediate(int32_t value) : value_(value) { } | 32 explicit Immediate(int32_t value) : value_(value) { } |
| 31 | 33 |
| 32 Immediate(const Immediate& other) : ValueObject(), value_(other.value_) { } | 34 Immediate(const Immediate& other) : ValueObject(), value_(other.value_) { } |
| 33 Immediate& operator=(const Immediate& other) { | 35 Immediate& operator=(const Immediate& other) { |
| 34 value_ = other.value_; | 36 value_ = other.value_; |
| (...skipping 812 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 847 LoadImmediate(TMP1, value); | 849 LoadImmediate(TMP1, value); |
| 848 addu(rd, rs, TMP1); | 850 addu(rd, rs, TMP1); |
| 849 } | 851 } |
| 850 } | 852 } |
| 851 | 853 |
| 852 void AddImmediate(Register rd, int32_t value) { | 854 void AddImmediate(Register rd, int32_t value) { |
| 853 AddImmediate(rd, rd, value); | 855 AddImmediate(rd, rd, value); |
| 854 } | 856 } |
| 855 | 857 |
| 856 void BranchEqual(Register rd, int32_t value, Label* l) { | 858 void BranchEqual(Register rd, int32_t value, Label* l) { |
| 857 ASSERT(rd != CMPRES); | 859 ASSERT(rd != CMPRES2); |
| 858 LoadImmediate(CMPRES, value); | 860 LoadImmediate(CMPRES2, value); |
| 859 beq(rd, CMPRES, l); | 861 beq(rd, CMPRES2, l); |
| 860 } | 862 } |
| 861 | 863 |
| 862 void BranchEqual(Register rd, const Object& object, Label* l) { | 864 void BranchEqual(Register rd, const Object& object, Label* l) { |
| 863 ASSERT(rd != CMPRES); | 865 ASSERT(rd != CMPRES2); |
| 864 LoadObject(CMPRES, object); | 866 LoadObject(CMPRES2, object); |
| 865 beq(rd, CMPRES, l); | 867 beq(rd, CMPRES2, l); |
| 866 } | 868 } |
| 867 | 869 |
| 868 void BranchNotEqual(Register rd, int32_t value, Label* l) { | 870 void BranchNotEqual(Register rd, int32_t value, Label* l) { |
| 869 ASSERT(rd != CMPRES); | 871 ASSERT(rd != CMPRES2); |
| 870 LoadImmediate(CMPRES, value); | 872 LoadImmediate(CMPRES2, value); |
| 871 bne(rd, CMPRES, l); | 873 bne(rd, CMPRES2, l); |
| 872 } | 874 } |
| 873 | 875 |
| 874 void BranchNotEqual(Register rd, const Object& object, Label* l) { | 876 void BranchNotEqual(Register rd, const Object& object, Label* l) { |
| 875 ASSERT(rd != CMPRES); | 877 ASSERT(rd != CMPRES2); |
| 876 LoadObject(CMPRES, object); | 878 LoadObject(CMPRES2, object); |
| 877 bne(rd, CMPRES, l); | 879 bne(rd, CMPRES2, l); |
| 878 } | 880 } |
| 879 | 881 |
| 880 void BranchSignedGreater(Register rd, Register rs, Label* l) { | 882 void BranchSignedGreater(Register rd, Register rs, Label* l) { |
| 881 slt(CMPRES, rs, rd); // CMPRES = rd > rs ? 1 : 0. | 883 slt(CMPRES1, rs, rd); // CMPRES1 = rd > rs ? 1 : 0. |
|
regis
2013/07/25 20:07:43
It's awkward that some branch instructions use CMP
zra
2013/07/26 21:26:15
Done.
| |
| 882 bne(CMPRES, ZR, l); | 884 bne(CMPRES1, ZR, l); |
| 883 } | 885 } |
| 884 | 886 |
| 885 void BranchSignedGreater(Register rd, int32_t value, Label* l) { | 887 void BranchSignedGreater(Register rd, int32_t value, Label* l) { |
| 886 LoadImmediate(CMPRES, value); | 888 ASSERT(rd != CMPRES2); |
| 887 BranchSignedGreater(rd, CMPRES, l); | 889 LoadImmediate(CMPRES2, value); |
| 890 BranchSignedGreater(rd, CMPRES2, l); | |
| 888 } | 891 } |
| 889 | 892 |
| 890 void BranchUnsignedGreater(Register rd, Register rs, Label* l) { | 893 void BranchUnsignedGreater(Register rd, Register rs, Label* l) { |
| 891 sltu(CMPRES, rs, rd); | 894 sltu(CMPRES1, rs, rd); |
| 892 bne(CMPRES, ZR, l); | 895 bne(CMPRES1, ZR, l); |
| 893 } | 896 } |
| 894 | 897 |
| 895 void BranchUnsignedGreater(Register rd, int32_t value, Label* l) { | 898 void BranchUnsignedGreater(Register rd, int32_t value, Label* l) { |
| 896 LoadImmediate(CMPRES, value); | 899 ASSERT(rd != CMPRES2); |
| 897 BranchUnsignedGreater(rd, CMPRES, l); | 900 LoadImmediate(CMPRES2, value); |
| 901 BranchUnsignedGreater(rd, CMPRES2, l); | |
| 898 } | 902 } |
| 899 | 903 |
| 900 void BranchSignedGreaterEqual(Register rd, Register rs, Label* l) { | 904 void BranchSignedGreaterEqual(Register rd, Register rs, Label* l) { |
| 901 slt(CMPRES, rd, rs); // CMPRES = rd < rs ? 1 : 0. | 905 slt(CMPRES1, rd, rs); // CMPRES1 = rd < rs ? 1 : 0. |
| 902 beq(CMPRES, ZR, l); // If CMPRES = 0, then rd >= rs. | 906 beq(CMPRES1, ZR, l); // If CMPRES1 = 0, then rd >= rs. |
| 903 } | 907 } |
| 904 | 908 |
| 905 void BranchSignedGreaterEqual(Register rd, int32_t value, Label* l) { | 909 void BranchSignedGreaterEqual(Register rd, int32_t value, Label* l) { |
| 906 if (Utils::IsInt(kImmBits, value)) { | 910 if (Utils::IsInt(kImmBits, value)) { |
| 907 slti(CMPRES, rd, Immediate(value)); | 911 slti(CMPRES1, rd, Immediate(value)); |
| 908 beq(CMPRES, ZR, l); | 912 beq(CMPRES1, ZR, l); |
| 909 } else { | 913 } else { |
| 910 LoadImmediate(CMPRES, value); | 914 ASSERT(rd != CMPRES2); |
| 911 BranchSignedGreaterEqual(rd, CMPRES, l); | 915 LoadImmediate(CMPRES2, value); |
| 916 BranchSignedGreaterEqual(rd, CMPRES2, l); | |
| 912 } | 917 } |
| 913 } | 918 } |
| 914 | 919 |
| 915 void BranchUnsignedGreaterEqual(Register rd, Register rs, Label* l) { | 920 void BranchUnsignedGreaterEqual(Register rd, Register rs, Label* l) { |
| 916 sltu(CMPRES, rd, rs); // CMPRES = rd < rs ? 1 : 0. | 921 sltu(CMPRES1, rd, rs); // CMPRES1 = rd < rs ? 1 : 0. |
| 917 beq(CMPRES, ZR, l); | 922 beq(CMPRES1, ZR, l); |
| 918 } | 923 } |
| 919 | 924 |
| 920 void BranchUnsignedGreaterEqual(Register rd, int32_t value, Label* l) { | 925 void BranchUnsignedGreaterEqual(Register rd, int32_t value, Label* l) { |
| 921 if (Utils::IsUint(kImmBits, value)) { | 926 if (Utils::IsUint(kImmBits, value)) { |
| 922 sltiu(CMPRES, rd, Immediate(value)); | 927 sltiu(CMPRES1, rd, Immediate(value)); |
| 923 beq(CMPRES, ZR, l); | 928 beq(CMPRES1, ZR, l); |
| 924 } else { | 929 } else { |
| 925 LoadImmediate(CMPRES, value); | 930 ASSERT(rd != CMPRES2); |
| 926 BranchUnsignedGreaterEqual(rd, CMPRES, l); | 931 LoadImmediate(CMPRES2, value); |
| 932 BranchUnsignedGreaterEqual(rd, CMPRES2, l); | |
| 927 } | 933 } |
| 928 } | 934 } |
| 929 | 935 |
| 930 void BranchSignedLess(Register rd, Register rs, Label* l) { | 936 void BranchSignedLess(Register rd, Register rs, Label* l) { |
| 931 BranchSignedGreater(rs, rd, l); | 937 BranchSignedGreater(rs, rd, l); |
| 932 } | 938 } |
| 933 | 939 |
| 934 void BranchSignedLess(Register rd, int32_t value, Label* l) { | 940 void BranchSignedLess(Register rd, int32_t value, Label* l) { |
| 935 if (Utils::IsInt(kImmBits, value)) { | 941 if (Utils::IsInt(kImmBits, value)) { |
| 936 slti(CMPRES, rd, Immediate(value)); | 942 slti(CMPRES1, rd, Immediate(value)); |
| 937 bne(CMPRES, ZR, l); | 943 bne(CMPRES1, ZR, l); |
| 938 } else { | 944 } else { |
| 939 LoadImmediate(CMPRES, value); | 945 ASSERT(rd != CMPRES2); |
| 940 BranchSignedGreater(CMPRES, rd, l); | 946 LoadImmediate(CMPRES2, value); |
| 947 BranchSignedGreater(CMPRES2, rd, l); | |
| 941 } | 948 } |
| 942 } | 949 } |
| 943 | 950 |
| 944 void BranchUnsignedLess(Register rd, Register rs, Label* l) { | 951 void BranchUnsignedLess(Register rd, Register rs, Label* l) { |
| 945 BranchUnsignedGreater(rs, rd, l); | 952 BranchUnsignedGreater(rs, rd, l); |
| 946 } | 953 } |
| 947 | 954 |
| 948 void BranchUnsignedLess(Register rd, int32_t value, Label* l) { | 955 void BranchUnsignedLess(Register rd, int32_t value, Label* l) { |
| 949 if (Utils::IsUint(kImmBits, value)) { | 956 if (Utils::IsUint(kImmBits, value)) { |
| 950 sltiu(CMPRES, rd, Immediate(value)); | 957 sltiu(CMPRES1, rd, Immediate(value)); |
| 951 bne(CMPRES, ZR, l); | 958 bne(CMPRES1, ZR, l); |
| 952 } else { | 959 } else { |
| 953 LoadImmediate(CMPRES, value); | 960 ASSERT(rd != CMPRES2); |
| 954 BranchUnsignedGreater(CMPRES, rd, l); | 961 LoadImmediate(CMPRES2, value); |
| 962 BranchUnsignedGreater(CMPRES2, rd, l); | |
| 955 } | 963 } |
| 956 } | 964 } |
| 957 | 965 |
| 958 void BranchSignedLessEqual(Register rd, Register rs, Label* l) { | 966 void BranchSignedLessEqual(Register rd, Register rs, Label* l) { |
| 959 BranchSignedGreaterEqual(rs, rd, l); | 967 BranchSignedGreaterEqual(rs, rd, l); |
| 960 } | 968 } |
| 961 | 969 |
| 962 void BranchSignedLessEqual(Register rd, int32_t value, Label* l) { | 970 void BranchSignedLessEqual(Register rd, int32_t value, Label* l) { |
| 963 LoadImmediate(CMPRES, value); | 971 LoadImmediate(CMPRES1, value); |
| 964 BranchSignedGreaterEqual(CMPRES, rd, l); | 972 BranchSignedGreaterEqual(CMPRES1, rd, l); |
| 965 } | 973 } |
| 966 | 974 |
| 967 void BranchUnsignedLessEqual(Register rd, Register rs, Label* l) { | 975 void BranchUnsignedLessEqual(Register rd, Register rs, Label* l) { |
| 968 BranchUnsignedGreaterEqual(rs, rd, l); | 976 BranchUnsignedGreaterEqual(rs, rd, l); |
| 969 } | 977 } |
| 970 | 978 |
| 971 void BranchUnsignedLessEqual(Register rd, int32_t value, Label* l) { | 979 void BranchUnsignedLessEqual(Register rd, int32_t value, Label* l) { |
| 972 LoadImmediate(CMPRES, value); | 980 LoadImmediate(CMPRES1, value); |
| 973 BranchUnsignedGreaterEqual(CMPRES, rd, l); | 981 BranchUnsignedGreaterEqual(CMPRES1, rd, l); |
| 974 } | 982 } |
| 975 | 983 |
| 976 void Push(Register rt) { | 984 void Push(Register rt) { |
| 977 addiu(SP, SP, Immediate(-kWordSize)); | 985 addiu(SP, SP, Immediate(-kWordSize)); |
| 978 sw(rt, Address(SP)); | 986 sw(rt, Address(SP)); |
| 979 } | 987 } |
| 980 | 988 |
| 981 void Pop(Register rt) { | 989 void Pop(Register rt) { |
| 982 lw(rt, Address(SP)); | 990 lw(rt, Address(SP)); |
| 983 addiu(SP, SP, Immediate(kWordSize)); | 991 addiu(SP, SP, Immediate(kWordSize)); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1022 swc1(hi, Address(base, offset + kWordSize)); | 1030 swc1(hi, Address(base, offset + kWordSize)); |
| 1023 } | 1031 } |
| 1024 | 1032 |
| 1025 void LoadDFromOffset(DRegister reg, Register base, int32_t offset) { | 1033 void LoadDFromOffset(DRegister reg, Register base, int32_t offset) { |
| 1026 FRegister lo = static_cast<FRegister>(reg * 2); | 1034 FRegister lo = static_cast<FRegister>(reg * 2); |
| 1027 FRegister hi = static_cast<FRegister>(reg * 2 + 1); | 1035 FRegister hi = static_cast<FRegister>(reg * 2 + 1); |
| 1028 lwc1(lo, Address(base, offset)); | 1036 lwc1(lo, Address(base, offset)); |
| 1029 lwc1(hi, Address(base, offset + kWordSize)); | 1037 lwc1(hi, Address(base, offset + kWordSize)); |
| 1030 } | 1038 } |
| 1031 | 1039 |
| 1040 // dest gets the address of the following instruction. If preserve ra is true | |
| 1041 // RA is preserved using CMPRES1 as a temporary. | |
| 1042 void GetNextPC(Register dest, bool preserve_ra) { | |
| 1043 if (preserve_ra) { | |
| 1044 mov(CMPRES1, RA); | |
| 1045 } | |
| 1046 EmitRegImmType(REGIMM, R0, BGEZAL, 1); | |
| 1047 mov(dest, RA); | |
| 1048 if (preserve_ra) { | |
| 1049 mov(RA, CMPRES1); | |
| 1050 } | |
| 1051 } | |
| 1052 | |
| 1032 void ReserveAlignedFrameSpace(intptr_t frame_space); | 1053 void ReserveAlignedFrameSpace(intptr_t frame_space); |
| 1033 | 1054 |
| 1034 // Create a frame for calling into runtime that preserves all volatile | 1055 // Create a frame for calling into runtime that preserves all volatile |
| 1035 // registers. Frame's SP is guaranteed to be correctly aligned and | 1056 // registers. Frame's SP is guaranteed to be correctly aligned and |
| 1036 // frame_space bytes are reserved under it. | 1057 // frame_space bytes are reserved under it. |
| 1037 void EnterCallRuntimeFrame(intptr_t frame_space); | 1058 void EnterCallRuntimeFrame(intptr_t frame_space); |
| 1038 void LeaveCallRuntimeFrame(); | 1059 void LeaveCallRuntimeFrame(); |
| 1039 | 1060 |
| 1040 void LoadWordFromPoolOffset(Register rd, int32_t offset); | 1061 void LoadWordFromPoolOffset(Register rd, int32_t offset); |
| 1041 void LoadObject(Register rd, const Object& object); | 1062 void LoadObject(Register rd, const Object& object); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1175 FRegister fd, | 1196 FRegister fd, |
| 1176 Cop1Function func) { | 1197 Cop1Function func) { |
| 1177 Emit(opcode << kOpcodeShift | | 1198 Emit(opcode << kOpcodeShift | |
| 1178 fmt << kFmtShift | | 1199 fmt << kFmtShift | |
| 1179 ft << kFtShift | | 1200 ft << kFtShift | |
| 1180 fs << kFsShift | | 1201 fs << kFsShift | |
| 1181 fd << kFdShift | | 1202 fd << kFdShift | |
| 1182 func << kCop1FnShift); | 1203 func << kCop1FnShift); |
| 1183 } | 1204 } |
| 1184 | 1205 |
| 1206 int32_t DecodeLoadImmediate(int32_t low, int32_t high); | |
| 1207 int32_t EncodeLoadImmediate(int32_t dest, int32_t instr); | |
| 1208 | |
| 1209 Opcode OppositeBranchOpcode(Opcode b) { | |
| 1210 switch (b) { | |
| 1211 case BEQ: return BNE; | |
| 1212 case BNE: return BEQ; | |
| 1213 case BGTZ: return BLEZ; | |
| 1214 case BLEZ: return BGTZ; | |
| 1215 case BEQL: return BNEL; | |
| 1216 case BNEL: return BEQL; | |
| 1217 case BGTZL: return BLEZL; | |
| 1218 case BLEZL: return BGTZL; | |
| 1219 default: | |
| 1220 UNREACHABLE(); | |
| 1221 break; | |
| 1222 } | |
| 1223 return BNE; | |
| 1224 } | |
| 1225 | |
| 1226 void EmitFarBranch(Opcode b, Register rs, Register rt, int32_t offset) { | |
| 1227 ASSERT(rs != TMP); | |
| 1228 ASSERT(rt != TMP); | |
| 1229 | |
| 1230 const uint16_t low = Utils::Low16Bits(offset); | |
| 1231 const uint16_t high = Utils::High16Bits(offset); | |
| 1232 lui(TMP, Immediate(high)); | |
| 1233 ori(TMP, TMP, Immediate(low)); | |
| 1234 | |
| 1235 addiu(SP, SP, Immediate(-1 * kWordSize)); | |
| 1236 sw(CMPRES1, Address(SP, -0 * kWordSize)); | |
| 1237 | |
| 1238 mov(CMPRES1, RA); | |
| 1239 EmitRegImmType(REGIMM, R0, BGEZAL, 1); | |
|
regis
2013/07/25 20:07:43
You are not using GetNextPC. Still needed?
OK, I s
| |
| 1240 addu(TMP, TMP, RA); | |
| 1241 mov(RA, CMPRES1); | |
| 1242 | |
| 1243 lw(CMPRES1, Address(SP, -0 * kWordSize)); | |
| 1244 addiu(SP, SP, Immediate(1 * kWordSize)); | |
|
regis
2013/07/25 20:07:43
Preserving and restoring CMPRES1 in order to, in t
| |
| 1245 | |
| 1246 EmitIType(OppositeBranchOpcode(b), rs, rt, 2); | |
|
regis
2013/07/25 20:07:43
You should have an unconditional EmitFarBranch(off
zra
2013/07/26 21:26:15
Done.
| |
| 1247 nop(); | |
| 1248 EmitRType(SPECIAL, TMP, R0, R0, 0, JR); | |
| 1249 } | |
| 1250 | |
| 1251 RtRegImm OppositeBranchNoLink(RtRegImm b) { | |
| 1252 switch (b) { | |
| 1253 case BLTZ: return BGEZ; | |
| 1254 case BGEZ: return BLTZ; | |
| 1255 case BLTZAL: return BGEZ; | |
| 1256 case BGEZAL: return BLTZ; | |
| 1257 default: | |
| 1258 UNREACHABLE(); | |
| 1259 break; | |
| 1260 } | |
| 1261 return BLTZ; | |
| 1262 } | |
| 1263 | |
| 1264 void EmitFarRegImmBranch(RtRegImm b, Register rs, int32_t offset) { | |
| 1265 ASSERT(rs != TMP); | |
| 1266 | |
| 1267 const uint16_t low = Utils::Low16Bits(offset); | |
| 1268 const uint16_t high = Utils::High16Bits(offset); | |
| 1269 lui(TMP, Immediate(high)); | |
| 1270 ori(TMP, TMP, Immediate(low)); | |
| 1271 | |
| 1272 addiu(SP, SP, Immediate(-1 * kWordSize)); | |
| 1273 sw(CMPRES1, Address(SP, -0 * kWordSize)); | |
| 1274 | |
| 1275 mov(CMPRES1, RA); | |
| 1276 EmitRegImmType(REGIMM, R0, BGEZAL, 1); | |
| 1277 addu(TMP, TMP, RA); | |
| 1278 mov(RA, CMPRES1); | |
| 1279 | |
| 1280 lw(CMPRES1, Address(SP, -0 * kWordSize)); | |
| 1281 addiu(SP, SP, Immediate(1 * kWordSize)); | |
| 1282 | |
| 1283 EmitRegImmType(REGIMM, rs, OppositeBranchNoLink(b), 2); | |
| 1284 nop(); | |
| 1285 if ((b == BLTZAL) || (b == BGEZAL)) { | |
| 1286 EmitRType(SPECIAL, TMP, R0, RA, 0, JALR); | |
| 1287 } else { | |
| 1288 EmitRType(SPECIAL, TMP, R0, R0, 0, JR); | |
| 1289 } | |
| 1290 } | |
| 1291 | |
| 1292 | |
| 1293 void EmitFarFpuBranch(bool kind, int32_t offset) { | |
| 1294 const uint32_t b16 = kind ? 0 : (1 << 16); | |
| 1295 | |
| 1296 const uint16_t low = Utils::Low16Bits(offset); | |
| 1297 const uint16_t high = Utils::High16Bits(offset); | |
| 1298 lui(TMP, Immediate(high)); | |
| 1299 ori(TMP, TMP, Immediate(low)); | |
| 1300 | |
| 1301 addiu(SP, SP, Immediate(-1 * kWordSize)); | |
| 1302 sw(CMPRES1, Address(SP, -0 * kWordSize)); | |
| 1303 | |
| 1304 mov(CMPRES1, RA); | |
| 1305 EmitRegImmType(REGIMM, R0, BGEZAL, 1); | |
| 1306 addu(TMP, TMP, RA); | |
| 1307 mov(RA, CMPRES1); | |
| 1308 | |
| 1309 lw(CMPRES1, Address(SP, -0 * kWordSize)); | |
| 1310 addiu(SP, SP, Immediate(1 * kWordSize)); | |
| 1311 | |
| 1312 Emit(COP1 << kOpcodeShift | COP1_BC << kCop1SubShift | b16 | 2); | |
| 1313 nop(); | |
| 1314 EmitRType(SPECIAL, TMP, R0, R0, 0, JR); | |
| 1315 } | |
| 1316 | |
| 1317 | |
| 1185 void EmitBranch(Opcode b, Register rs, Register rt, Label* label) { | 1318 void EmitBranch(Opcode b, Register rs, Register rt, Label* label) { |
| 1186 if (label->IsBound()) { | 1319 if (label->IsBound()) { |
|
regis
2013/07/25 20:07:43
If the label is bound, you know the offset and you
zra
2013/07/26 21:26:15
Done.
| |
| 1187 // Relative destination from an instruction after the branch. | 1320 // Relative destination from an instruction after the branch. |
| 1188 const int32_t dest = | 1321 if (FLAG_mips_far_branches) { |
| 1189 label->Position() - (buffer_.Size() + Instr::kInstrSize); | 1322 const int32_t dest = |
| 1190 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | 1323 label->Position() - (buffer_.Size() + 7 * Instr::kInstrSize); |
| 1191 EmitIType(b, rs, rt, dest_off); | 1324 EmitFarBranch(b, rs, rt, dest); |
| 1325 } else { | |
| 1326 const int32_t dest = | |
| 1327 label->Position() - (buffer_.Size() + Instr::kInstrSize); | |
| 1328 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | |
| 1329 EmitIType(b, rs, rt, dest_off); | |
| 1330 } | |
| 1192 } else { | 1331 } else { |
| 1193 const int position = buffer_.Size(); | 1332 const int position = buffer_.Size(); |
| 1194 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | 1333 if (FLAG_mips_far_branches) { |
| 1195 EmitIType(b, rs, rt, dest_off); | 1334 const uint32_t dest_off = label->position_; |
| 1335 EmitFarBranch(b, rs, rt, dest_off); | |
| 1336 } else { | |
| 1337 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | |
| 1338 EmitIType(b, rs, rt, dest_off); | |
| 1339 } | |
| 1196 label->LinkTo(position); | 1340 label->LinkTo(position); |
| 1197 } | 1341 } |
| 1198 } | 1342 } |
| 1199 | 1343 |
| 1200 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { | 1344 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { |
| 1201 if (label->IsBound()) { | 1345 if (label->IsBound()) { |
|
regis
2013/07/25 20:07:43
ditto
zra
2013/07/26 21:26:15
Done.
| |
| 1202 // Relative destination from an instruction after the branch. | 1346 // Relative destination from an instruction after the branch. |
| 1203 const int32_t dest = | 1347 if (FLAG_mips_far_branches) { |
| 1204 label->Position() - (buffer_.Size() + Instr::kInstrSize); | 1348 const int32_t dest = |
| 1205 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | 1349 label->Position() - (buffer_.Size() + 7 * Instr::kInstrSize); |
| 1206 EmitRegImmType(REGIMM, rs, b, dest_off); | 1350 EmitFarRegImmBranch(b, rs, dest); |
| 1351 } else { | |
| 1352 const int32_t dest = | |
| 1353 label->Position() - (buffer_.Size() + Instr::kInstrSize); | |
| 1354 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | |
| 1355 EmitRegImmType(REGIMM, rs, b, dest_off); | |
| 1356 } | |
| 1207 } else { | 1357 } else { |
| 1208 const int position = buffer_.Size(); | 1358 const int position = buffer_.Size(); |
| 1209 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | 1359 if (FLAG_mips_far_branches) { |
| 1210 EmitRegImmType(REGIMM, rs, b, dest_off); | 1360 const uint32_t dest_off = label->position_; |
| 1361 EmitFarRegImmBranch(b, rs, dest_off); | |
| 1362 } else { | |
| 1363 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | |
| 1364 EmitRegImmType(REGIMM, rs, b, dest_off); | |
| 1365 } | |
| 1211 label->LinkTo(position); | 1366 label->LinkTo(position); |
| 1212 } | 1367 } |
| 1213 } | 1368 } |
| 1214 | 1369 |
| 1215 void EmitFpuBranch(bool kind, Label *label) { | 1370 void EmitFpuBranch(bool kind, Label *label) { |
| 1216 const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true. | 1371 const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true. |
| 1217 if (label->IsBound()) { | 1372 if (label->IsBound()) { |
|
regis
2013/07/25 20:07:43
ditto
zra
2013/07/26 21:26:15
Done.
| |
| 1218 // Relative destination from an instruction after the branch. | 1373 // Relative destination from an instruction after the branch. |
| 1219 const int32_t dest = | 1374 if (FLAG_mips_far_branches) { |
| 1220 label->Position() - (buffer_.Size() + Instr::kInstrSize); | 1375 const int32_t dest = |
| 1221 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | 1376 label->Position() - (buffer_.Size() + 7 * Instr::kInstrSize); |
| 1222 Emit(COP1 << kOpcodeShift | | 1377 EmitFarFpuBranch(kind, dest); |
| 1223 COP1_BC << kCop1SubShift | | 1378 } else { |
| 1224 b16 | | 1379 const int32_t dest = |
| 1225 dest_off); | 1380 label->Position() - (buffer_.Size() + Instr::kInstrSize); |
| 1381 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | |
| 1382 Emit(COP1 << kOpcodeShift | | |
| 1383 COP1_BC << kCop1SubShift | | |
| 1384 b16 | | |
| 1385 dest_off); | |
| 1386 } | |
| 1226 } else { | 1387 } else { |
| 1227 const int position = buffer_.Size(); | 1388 const int position = buffer_.Size(); |
| 1228 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | 1389 if (FLAG_mips_far_branches) { |
| 1229 Emit(COP1 << kOpcodeShift | | 1390 const uint32_t dest_off = label->position_; |
| 1230 COP1_BC << kCop1SubShift | | 1391 EmitFarFpuBranch(kind, dest_off); |
| 1231 b16 | | 1392 } else { |
| 1232 dest_off); | 1393 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); |
| 1394 Emit(COP1 << kOpcodeShift | | |
| 1395 COP1_BC << kCop1SubShift | | |
| 1396 b16 | | |
| 1397 dest_off); | |
| 1398 } | |
| 1233 label->LinkTo(position); | 1399 label->LinkTo(position); |
| 1234 } | 1400 } |
| 1235 } | 1401 } |
| 1236 | 1402 |
| 1237 static int32_t EncodeBranchOffset(int32_t offset, int32_t instr); | 1403 static int32_t EncodeBranchOffset(int32_t offset, int32_t instr); |
| 1238 static int DecodeBranchOffset(int32_t instr); | 1404 static int DecodeBranchOffset(int32_t instr); |
| 1239 | 1405 |
| 1240 void EmitBranchDelayNop() { | 1406 void EmitBranchDelayNop() { |
| 1241 Emit(Instr::kNopInstruction); // Branch delay NOP. | 1407 Emit(Instr::kNopInstruction); // Branch delay NOP. |
| 1242 delay_slot_available_ = true; | 1408 delay_slot_available_ = true; |
| 1243 } | 1409 } |
| 1244 | 1410 |
| 1245 void StoreIntoObjectFilter(Register object, Register value, Label* no_update); | 1411 void StoreIntoObjectFilter(Register object, Register value, Label* no_update); |
| 1246 | 1412 |
| 1247 // Shorter filtering sequence that assumes that value is not a smi. | 1413 // Shorter filtering sequence that assumes that value is not a smi. |
| 1248 void StoreIntoObjectFilterNoSmi(Register object, | 1414 void StoreIntoObjectFilterNoSmi(Register object, |
| 1249 Register value, | 1415 Register value, |
| 1250 Label* no_update); | 1416 Label* no_update); |
| 1251 | 1417 |
| 1252 DISALLOW_ALLOCATION(); | 1418 DISALLOW_ALLOCATION(); |
| 1253 DISALLOW_COPY_AND_ASSIGN(Assembler); | 1419 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 1254 }; | 1420 }; |
| 1255 | 1421 |
| 1256 } // namespace dart | 1422 } // namespace dart |
| 1257 | 1423 |
| 1258 #endif // VM_ASSEMBLER_MIPS_H_ | 1424 #endif // VM_ASSEMBLER_MIPS_H_ |
| OLD | NEW |