Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: src/ia32/codegen-ia32.cc

Issue 118157: Refactor IA32 shift operations to simplify moving the right operand... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 761 matching lines...) Expand 10 before | Expand all | Expand 10 after
772 case Token::SHL: return "GenericBinaryOpStub_SHL"; 772 case Token::SHL: return "GenericBinaryOpStub_SHL";
773 case Token::SHR: return "GenericBinaryOpStub_SHR"; 773 case Token::SHR: return "GenericBinaryOpStub_SHR";
774 default: return "GenericBinaryOpStub"; 774 default: return "GenericBinaryOpStub";
775 } 775 }
776 } 776 }
777 777
778 778
779 // Call the specialized stub for a binary operation. 779 // Call the specialized stub for a binary operation.
780 class DeferredInlineBinaryOperation: public DeferredCode { 780 class DeferredInlineBinaryOperation: public DeferredCode {
781 public: 781 public:
782 DeferredInlineBinaryOperation(Token::Value op, 782 DeferredInlineBinaryOperation(Token::Value op, OverwriteMode mode)
783 OverwriteMode mode)
784 : op_(op), mode_(mode) { 783 : op_(op), mode_(mode) {
785 set_comment("[ DeferredInlineBinaryOperation"); 784 set_comment("[ DeferredInlineBinaryOperation");
786 } 785 }
787 786
788 virtual void Generate(); 787 virtual void Generate();
789 788
790 private: 789 private:
791 Token::Value op_; 790 Token::Value op_;
792 OverwriteMode mode_; 791 OverwriteMode mode_;
793 }; 792 };
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
994 } 993 }
995 frame_->Push(Handle<Object>(answer_object)); 994 frame_->Push(Handle<Object>(answer_object));
996 return true; 995 return true;
997 } 996 }
998 997
999 998
1000 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, 999 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
1001 Result* left, 1000 Result* left,
1002 Result* right, 1001 Result* right,
1003 OverwriteMode overwrite_mode) { 1002 OverwriteMode overwrite_mode) {
1004 // Implements a binary operation using a deferred code object and 1003 // Implements a binary operation using a deferred code object and some
1005 // some inline code to operate on smis quickly. 1004 // inline code to operate on smis quickly.
1006 DeferredInlineBinaryOperation* deferred = 1005 DeferredInlineBinaryOperation* deferred =
1007 new DeferredInlineBinaryOperation(op, overwrite_mode); 1006 new DeferredInlineBinaryOperation(op, overwrite_mode);
1008 1007
1009 // Special handling of div and mod because they use fixed registers. 1008 // Special handling of div and mod because they use fixed registers.
1010 if (op == Token::DIV || op == Token::MOD) { 1009 if (op == Token::DIV || op == Token::MOD) {
1011 // We need eax as the quotient register, edx as the remainder 1010 // We need eax as the quotient register, edx as the remainder
1012 // register, neither left nor right in eax or edx, and left copied 1011 // register, neither left nor right in eax or edx, and left copied
1013 // to eax. 1012 // to eax.
1014 Result quotient; 1013 Result quotient;
1015 Result remainder; 1014 Result remainder;
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
1141 deferred->enter()->Branch(negative, left, right); 1140 deferred->enter()->Branch(negative, left, right);
1142 left->Unuse(); 1141 left->Unuse();
1143 right->Unuse(); 1142 right->Unuse();
1144 __ bind(&non_zero_result); 1143 __ bind(&non_zero_result);
1145 deferred->BindExit(&remainder); 1144 deferred->BindExit(&remainder);
1146 frame_->Push(&remainder); 1145 frame_->Push(&remainder);
1147 } 1146 }
1148 return; 1147 return;
1149 } 1148 }
1150 1149
1150 // Special handling of shift operations because they use fixed
1151 // registers.
1152 if (op == Token::SHL || op == Token::SHR || op == Token::SAR) {
1153 // Move left out of ecx if necessary.
1154 if (left->is_register() && left->reg().is(ecx)) {
1155 *left = allocator_->Allocate();
1156 ASSERT(left->is_valid());
1157 __ mov(left->reg(), ecx);
1158 }
1159 right->ToRegister(ecx);
1160 left->ToRegister();
1161 ASSERT(left->is_register() && !left->reg().is(ecx));
1162 ASSERT(right->is_register() && right->reg().is(ecx));
1163
1164 // We will modify right, it must be spilled.
1165 frame_->Spill(ecx);
1166
1167 // Use a fresh answer register to avoid spilling the left operand.
1168 Result answer = allocator_->Allocate();
1169 ASSERT(answer.is_valid());
1170 // Check that both operands are smis using the answer register as a
1171 // temporary.
1172 __ mov(answer.reg(), left->reg());
1173 __ or_(answer.reg(), Operand(ecx));
1174 __ test(answer.reg(), Immediate(kSmiTagMask));
1175 deferred->enter()->Branch(not_zero, left, right);
1176
1177 // Untag both operands.
1178 __ mov(answer.reg(), left->reg());
1179 __ sar(answer.reg(), kSmiTagSize);
1180 __ sar(ecx, kSmiTagSize);
1181 // Perform the operation.
1182 switch (op) {
1183 case Token::SAR:
1184 __ sar(answer.reg());
1185 // No checks of result necessary
1186 break;
1187 case Token::SHR: {
1188 JumpTarget result_ok;
1189 __ shr(answer.reg());
1190 // Check that the *unsigned* result fits in a smi.
1191 // Neither of the two high-order bits can be set:
1192 // - 0x80000000: high bit would be lost when smi tagging.
1193 // - 0x40000000: this number would convert to negative when
1194 // Smi tagging these two cases can only happen with shifts
William Hesse 2009/06/03 12:12:04 // Smi tagging. These two cases can..
1195 // by 0 or 1 when handed a valid smi.
1196 // If the answer cannot be represented by a smi, restore
1197 // the left and right arguments, and jump to slow case.
1198 // The low bit of the left argument may be lost, but only
1199 // in a case where it is dropped anyway.
1200 __ test(answer.reg(), Immediate(0xc0000000));
1201 result_ok.Branch(zero, &answer);
1202 ASSERT(kSmiTag == 0);
1203 __ shl(ecx, kSmiTagSize);
1204 answer.Unuse();
1205 deferred->enter()->Jump(left, right);
1206 result_ok.Bind(&answer);
1207 break;
1208 }
1209 case Token::SHL: {
1210 JumpTarget result_ok;
1211 __ shl(answer.reg());
1212 // Check that the *signed* result fits in a smi.
1213 __ cmp(answer.reg(), 0xc0000000);
1214 result_ok.Branch(positive, &answer);
1215 ASSERT(kSmiTag == 0);
1216 __ shl(ecx, kSmiTagSize);
1217 answer.Unuse();
1218 deferred->enter()->Jump(left, right);
1219 result_ok.Bind(&answer);
1220 break;
1221 }
1222 default:
1223 UNREACHABLE();
1224 }
1225 left->Unuse();
1226 right->Unuse();
1227 // Smi-tag the result in answer.
1228 ASSERT(kSmiTagSize == 1); // Adjust code if not the case.
1229 __ lea(answer.reg(),
1230 Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
1231 deferred->BindExit(&answer);
1232 frame_->Push(&answer);
1233 return;
1234 }
1235
1151 // Handle the other binary operations. 1236 // Handle the other binary operations.
1152 left->ToRegister(); 1237 left->ToRegister();
1153 right->ToRegister(); 1238 right->ToRegister();
1154 // A newly allocated register answer is used to hold the answer. The 1239 // A newly allocated register answer is used to hold the answer. The
1155 // registers containing left and right are not modified in most cases, 1240 // registers containing left and right are not modified so they don't
1156 // so they usually don't need to be spilled in the fast case. 1241 // need to be spilled in the fast case.
1157 Result answer = allocator_->Allocate(); 1242 Result answer = allocator_->Allocate();
1158 1243
1159 ASSERT(answer.is_valid()); 1244 ASSERT(answer.is_valid());
1160 // Perform the smi tag check. 1245 // Perform the smi tag check.
1161 if (left->reg().is(right->reg())) { 1246 if (left->reg().is(right->reg())) {
1162 __ test(left->reg(), Immediate(kSmiTagMask)); 1247 __ test(left->reg(), Immediate(kSmiTagMask));
1163 } else { 1248 } else {
1164 __ mov(answer.reg(), left->reg()); 1249 __ mov(answer.reg(), left->reg());
1165 __ or_(answer.reg(), Operand(right->reg())); 1250 __ or_(answer.reg(), Operand(right->reg()));
1166 ASSERT(kSmiTag == 0); // Adjust test if not the case. 1251 ASSERT(kSmiTag == 0); // Adjust test if not the case.
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1222 __ mov(answer.reg(), left->reg()); 1307 __ mov(answer.reg(), left->reg());
1223 __ and_(answer.reg(), Operand(right->reg())); 1308 __ and_(answer.reg(), Operand(right->reg()));
1224 break; 1309 break;
1225 1310
1226 case Token::BIT_XOR: 1311 case Token::BIT_XOR:
1227 deferred->enter()->Branch(not_zero, left, right, not_taken); 1312 deferred->enter()->Branch(not_zero, left, right, not_taken);
1228 __ mov(answer.reg(), left->reg()); 1313 __ mov(answer.reg(), left->reg());
1229 __ xor_(answer.reg(), Operand(right->reg())); 1314 __ xor_(answer.reg(), Operand(right->reg()));
1230 break; 1315 break;
1231 1316
1232 case Token::SHL:
1233 case Token::SHR:
1234 case Token::SAR:
1235 deferred->enter()->Branch(not_zero, left, right, not_taken);
1236 __ mov(answer.reg(), left->reg());
1237 // Move right into ecx.
1238 // Left is in two registers already, so even if left or answer is ecx,
1239 // we can move right to it, and use the other one.
1240 // Right operand must be in register cl because x86 likes it that way.
1241 if (right->reg().is(ecx)) {
1242 // Right is already in the right place. Left may be in the
1243 // same register, which causes problems. Always use answer
1244 // instead of left, even if left is not ecx, since this avoids
1245 // spilling left.
1246 *left = answer;
1247 } else if (left->reg().is(ecx)) {
1248 frame_->Spill(left->reg());
1249 __ mov(left->reg(), right->reg());
1250 *right = *left;
1251 *left = answer; // Use copy of left in answer as left.
1252 } else if (answer.reg().is(ecx)) {
1253 __ mov(answer.reg(), right->reg());
1254 *right = answer;
1255 } else {
1256 Result reg_ecx = allocator_->Allocate(ecx);
1257 ASSERT(reg_ecx.is_valid());
1258 __ mov(ecx, right->reg());
1259 *right = reg_ecx;
1260 // Answer and left both contain the left operand. Use answer, so
1261 // left is not spilled.
1262 *left = answer;
1263 }
1264 ASSERT(left->reg().is_valid());
1265 ASSERT(!left->reg().is(ecx));
1266 ASSERT(right->reg().is(ecx));
1267 answer.Unuse(); // Answer may now be being used for left or right.
1268 // We will modify left and right, which we do not do in any other
1269 // binary operation. The exits to slow code need to restore the
1270 // original values of left and right, or at least values that give
1271 // the same answer.
1272
1273 // We are modifying left and right. They must be spilled!
1274 frame_->Spill(left->reg());
1275 frame_->Spill(right->reg());
1276
1277 // Remove tags from operands (but keep sign).
1278 __ sar(left->reg(), kSmiTagSize);
1279 __ sar(ecx, kSmiTagSize);
1280 // Perform the operation.
1281 switch (op) {
1282 case Token::SAR:
1283 __ sar(left->reg());
1284 // No checks of result necessary
1285 break;
1286 case Token::SHR: {
1287 __ shr(left->reg());
1288 // Check that the *unsigned* result fits in a smi.
1289 // Neither of the two high-order bits can be set:
1290 // - 0x80000000: high bit would be lost when smi tagging.
1291 // - 0x40000000: this number would convert to negative when
1292 // Smi tagging these two cases can only happen with shifts
1293 // by 0 or 1 when handed a valid smi.
1294 // If the answer cannot be represented by a SMI, restore
1295 // the left and right arguments, and jump to slow case.
1296 // The low bit of the left argument may be lost, but only
1297 // in a case where it is dropped anyway.
1298 JumpTarget result_ok;
1299 __ test(left->reg(), Immediate(0xc0000000));
1300 result_ok.Branch(zero, left, taken);
1301 __ shl(left->reg());
1302 ASSERT(kSmiTag == 0);
1303 __ shl(left->reg(), kSmiTagSize);
1304 __ shl(right->reg(), kSmiTagSize);
1305 deferred->enter()->Jump(left, right);
1306 result_ok.Bind(left);
1307 break;
1308 }
1309 case Token::SHL: {
1310 __ shl(left->reg());
1311 // Check that the *signed* result fits in a smi.
1312 JumpTarget result_ok;
1313 __ cmp(left->reg(), 0xc0000000);
1314 result_ok.Branch(positive, left, taken);
1315
1316 __ shr(left->reg());
1317 ASSERT(kSmiTag == 0);
1318 __ shl(left->reg(), kSmiTagSize);
1319 __ shl(right->reg(), kSmiTagSize);
1320 deferred->enter()->Jump(left, right);
1321 result_ok.Bind(left);
1322 break;
1323 }
1324 default:
1325 UNREACHABLE();
1326 }
1327 // Smi-tag the result, in left, and make answer an alias for left->
1328 answer = *left;
1329 answer.ToRegister();
1330 ASSERT(kSmiTagSize == times_2); // adjust code if not the case
1331 __ lea(answer.reg(),
1332 Operand(answer.reg(), answer.reg(), times_1, kSmiTag));
1333 break;
1334
1335 default: 1317 default:
1336 UNREACHABLE(); 1318 UNREACHABLE();
1337 break; 1319 break;
1338 } 1320 }
1339 left->Unuse(); 1321 left->Unuse();
1340 right->Unuse(); 1322 right->Unuse();
1341 deferred->BindExit(&answer); 1323 deferred->BindExit(&answer);
1342 frame_->Push(&answer); 1324 frame_->Push(&answer);
1343 } 1325 }
1344 1326
(...skipping 5945 matching lines...) Expand 10 before | Expand all | Expand 10 after
7290 7272
7291 // Slow-case: Go through the JavaScript implementation. 7273 // Slow-case: Go through the JavaScript implementation.
7292 __ bind(&slow); 7274 __ bind(&slow);
7293 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 7275 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
7294 } 7276 }
7295 7277
7296 7278
7297 #undef __ 7279 #undef __
7298 7280
7299 } } // namespace v8::internal 7281 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698