| 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, use_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(CMPRES2, rs, rd); // CMPRES2 = rd > rs ? 1 : 0. |
| 882 bne(CMPRES, ZR, l); | 884 bne(CMPRES2, 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(CMPRES2, rs, rd); |
| 892 bne(CMPRES, ZR, l); | 895 bne(CMPRES2, 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(CMPRES2, rd, rs); // CMPRES2 = rd < rs ? 1 : 0. |
| 902 beq(CMPRES, ZR, l); // If CMPRES = 0, then rd >= rs. | 906 beq(CMPRES2, ZR, l); // If CMPRES2 = 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(CMPRES2, rd, Immediate(value)); |
| 908 beq(CMPRES, ZR, l); | 912 beq(CMPRES2, 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(CMPRES2, rd, rs); // CMPRES2 = rd < rs ? 1 : 0. |
| 917 beq(CMPRES, ZR, l); | 922 beq(CMPRES2, 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(CMPRES2, rd, Immediate(value)); |
| 923 beq(CMPRES, ZR, l); | 928 beq(CMPRES2, 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(CMPRES2, rd, Immediate(value)); |
| 937 bne(CMPRES, ZR, l); | 943 bne(CMPRES2, 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(CMPRES2, rd, Immediate(value)); |
| 951 bne(CMPRES, ZR, l); | 958 bne(CMPRES2, 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 ASSERT(rd != CMPRES2); |
| 964 BranchSignedGreaterEqual(CMPRES, rd, l); | 972 LoadImmediate(CMPRES2, value); |
| 973 BranchSignedGreaterEqual(CMPRES2, rd, l); |
| 965 } | 974 } |
| 966 | 975 |
| 967 void BranchUnsignedLessEqual(Register rd, Register rs, Label* l) { | 976 void BranchUnsignedLessEqual(Register rd, Register rs, Label* l) { |
| 968 BranchUnsignedGreaterEqual(rs, rd, l); | 977 BranchUnsignedGreaterEqual(rs, rd, l); |
| 969 } | 978 } |
| 970 | 979 |
| 971 void BranchUnsignedLessEqual(Register rd, int32_t value, Label* l) { | 980 void BranchUnsignedLessEqual(Register rd, int32_t value, Label* l) { |
| 972 LoadImmediate(CMPRES, value); | 981 ASSERT(rd != CMPRES2); |
| 973 BranchUnsignedGreaterEqual(CMPRES, rd, l); | 982 LoadImmediate(CMPRES2, value); |
| 983 BranchUnsignedGreaterEqual(CMPRES2, rd, l); |
| 974 } | 984 } |
| 975 | 985 |
| 976 void Push(Register rt) { | 986 void Push(Register rt) { |
| 977 addiu(SP, SP, Immediate(-kWordSize)); | 987 addiu(SP, SP, Immediate(-kWordSize)); |
| 978 sw(rt, Address(SP)); | 988 sw(rt, Address(SP)); |
| 979 } | 989 } |
| 980 | 990 |
| 981 void Pop(Register rt) { | 991 void Pop(Register rt) { |
| 982 lw(rt, Address(SP)); | 992 lw(rt, Address(SP)); |
| 983 addiu(SP, SP, Immediate(kWordSize)); | 993 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)); | 1032 swc1(hi, Address(base, offset + kWordSize)); |
| 1023 } | 1033 } |
| 1024 | 1034 |
| 1025 void LoadDFromOffset(DRegister reg, Register base, int32_t offset) { | 1035 void LoadDFromOffset(DRegister reg, Register base, int32_t offset) { |
| 1026 FRegister lo = static_cast<FRegister>(reg * 2); | 1036 FRegister lo = static_cast<FRegister>(reg * 2); |
| 1027 FRegister hi = static_cast<FRegister>(reg * 2 + 1); | 1037 FRegister hi = static_cast<FRegister>(reg * 2 + 1); |
| 1028 lwc1(lo, Address(base, offset)); | 1038 lwc1(lo, Address(base, offset)); |
| 1029 lwc1(hi, Address(base, offset + kWordSize)); | 1039 lwc1(hi, Address(base, offset + kWordSize)); |
| 1030 } | 1040 } |
| 1031 | 1041 |
| 1042 // dest gets the address of the following instruction. If temp is given, |
| 1043 // RA is preserved using it as a temporary. |
| 1044 void GetNextPC(Register dest, Register temp = kNoRegister); |
| 1045 |
| 1032 void ReserveAlignedFrameSpace(intptr_t frame_space); | 1046 void ReserveAlignedFrameSpace(intptr_t frame_space); |
| 1033 | 1047 |
| 1034 // Create a frame for calling into runtime that preserves all volatile | 1048 // Create a frame for calling into runtime that preserves all volatile |
| 1035 // registers. Frame's SP is guaranteed to be correctly aligned and | 1049 // registers. Frame's SP is guaranteed to be correctly aligned and |
| 1036 // frame_space bytes are reserved under it. | 1050 // frame_space bytes are reserved under it. |
| 1037 void EnterCallRuntimeFrame(intptr_t frame_space); | 1051 void EnterCallRuntimeFrame(intptr_t frame_space); |
| 1038 void LeaveCallRuntimeFrame(); | 1052 void LeaveCallRuntimeFrame(); |
| 1039 | 1053 |
| 1040 void LoadWordFromPoolOffset(Register rd, int32_t offset); | 1054 void LoadWordFromPoolOffset(Register rd, int32_t offset); |
| 1041 void LoadObject(Register rd, const Object& object); | 1055 void LoadObject(Register rd, const Object& object); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1175 FRegister fd, | 1189 FRegister fd, |
| 1176 Cop1Function func) { | 1190 Cop1Function func) { |
| 1177 Emit(opcode << kOpcodeShift | | 1191 Emit(opcode << kOpcodeShift | |
| 1178 fmt << kFmtShift | | 1192 fmt << kFmtShift | |
| 1179 ft << kFtShift | | 1193 ft << kFtShift | |
| 1180 fs << kFsShift | | 1194 fs << kFsShift | |
| 1181 fd << kFdShift | | 1195 fd << kFdShift | |
| 1182 func << kCop1FnShift); | 1196 func << kCop1FnShift); |
| 1183 } | 1197 } |
| 1184 | 1198 |
| 1185 void EmitBranch(Opcode b, Register rs, Register rt, Label* label) { | |
| 1186 if (label->IsBound()) { | |
| 1187 // Relative destination from an instruction after the branch. | |
| 1188 const int32_t dest = | |
| 1189 label->Position() - (buffer_.Size() + Instr::kInstrSize); | |
| 1190 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | |
| 1191 EmitIType(b, rs, rt, dest_off); | |
| 1192 } else { | |
| 1193 const int position = buffer_.Size(); | |
| 1194 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | |
| 1195 EmitIType(b, rs, rt, dest_off); | |
| 1196 label->LinkTo(position); | |
| 1197 } | |
| 1198 } | |
| 1199 | 1199 |
| 1200 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label) { | 1200 void EmitFarJump(int32_t offset, bool link); |
| 1201 if (label->IsBound()) { | 1201 void EmitFarBranch(Opcode b, Register rs, Register rt, int32_t offset); |
| 1202 // Relative destination from an instruction after the branch. | 1202 void EmitFarRegImmBranch(RtRegImm b, Register rs, int32_t offset); |
| 1203 const int32_t dest = | 1203 void EmitFarFpuBranch(bool kind, int32_t offset); |
| 1204 label->Position() - (buffer_.Size() + Instr::kInstrSize); | 1204 void EmitBranch(Opcode b, Register rs, Register rt, Label* label); |
| 1205 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | 1205 void EmitRegImmBranch(RtRegImm b, Register rs, Label* label); |
| 1206 EmitRegImmType(REGIMM, rs, b, dest_off); | 1206 void EmitFpuBranch(bool kind, Label *label); |
| 1207 } else { | |
| 1208 const int position = buffer_.Size(); | |
| 1209 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | |
| 1210 EmitRegImmType(REGIMM, rs, b, dest_off); | |
| 1211 label->LinkTo(position); | |
| 1212 } | |
| 1213 } | |
| 1214 | |
| 1215 void EmitFpuBranch(bool kind, Label *label) { | |
| 1216 const int32_t b16 = kind ? (1 << 16) : 0; // Bit 16 set for branch on true. | |
| 1217 if (label->IsBound()) { | |
| 1218 // Relative destination from an instruction after the branch. | |
| 1219 const int32_t dest = | |
| 1220 label->Position() - (buffer_.Size() + Instr::kInstrSize); | |
| 1221 const uint16_t dest_off = EncodeBranchOffset(dest, 0); | |
| 1222 Emit(COP1 << kOpcodeShift | | |
| 1223 COP1_BC << kCop1SubShift | | |
| 1224 b16 | | |
| 1225 dest_off); | |
| 1226 } else { | |
| 1227 const int position = buffer_.Size(); | |
| 1228 const uint16_t dest_off = EncodeBranchOffset(label->position_, 0); | |
| 1229 Emit(COP1 << kOpcodeShift | | |
| 1230 COP1_BC << kCop1SubShift | | |
| 1231 b16 | | |
| 1232 dest_off); | |
| 1233 label->LinkTo(position); | |
| 1234 } | |
| 1235 } | |
| 1236 | |
| 1237 static int32_t EncodeBranchOffset(int32_t offset, int32_t instr); | |
| 1238 static int DecodeBranchOffset(int32_t instr); | |
| 1239 | 1207 |
| 1240 void EmitBranchDelayNop() { | 1208 void EmitBranchDelayNop() { |
| 1241 Emit(Instr::kNopInstruction); // Branch delay NOP. | 1209 Emit(Instr::kNopInstruction); // Branch delay NOP. |
| 1242 delay_slot_available_ = true; | 1210 delay_slot_available_ = true; |
| 1243 } | 1211 } |
| 1244 | 1212 |
| 1245 void StoreIntoObjectFilter(Register object, Register value, Label* no_update); | 1213 void StoreIntoObjectFilter(Register object, Register value, Label* no_update); |
| 1246 | 1214 |
| 1247 // Shorter filtering sequence that assumes that value is not a smi. | 1215 // Shorter filtering sequence that assumes that value is not a smi. |
| 1248 void StoreIntoObjectFilterNoSmi(Register object, | 1216 void StoreIntoObjectFilterNoSmi(Register object, |
| 1249 Register value, | 1217 Register value, |
| 1250 Label* no_update); | 1218 Label* no_update); |
| 1251 | 1219 |
| 1252 DISALLOW_ALLOCATION(); | 1220 DISALLOW_ALLOCATION(); |
| 1253 DISALLOW_COPY_AND_ASSIGN(Assembler); | 1221 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 1254 }; | 1222 }; |
| 1255 | 1223 |
| 1256 } // namespace dart | 1224 } // namespace dart |
| 1257 | 1225 |
| 1258 #endif // VM_ASSEMBLER_MIPS_H_ | 1226 #endif // VM_ASSEMBLER_MIPS_H_ |
| OLD | NEW |