| OLD | NEW |
| 1 //===- subzero/src/IceInstX86BaseImpl.h - Generic X86 instructions -*- C++ -*=// | 1 //===- subzero/src/IceInstX86BaseImpl.h - Generic X86 instructions -*- C++ -*=// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| (...skipping 1366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1377 Func, Ty, Dest, this->getSrc(1), this->getSrc(2), Emitter); | 1377 Func, Ty, Dest, this->getSrc(1), this->getSrc(2), Emitter); |
| 1378 } | 1378 } |
| 1379 | 1379 |
| 1380 template <class Machine> | 1380 template <class Machine> |
| 1381 void InstX86Cbwdq<Machine>::emit(const Cfg *Func) const { | 1381 void InstX86Cbwdq<Machine>::emit(const Cfg *Func) const { |
| 1382 if (!BuildDefs::dump()) | 1382 if (!BuildDefs::dump()) |
| 1383 return; | 1383 return; |
| 1384 Ostream &Str = Func->getContext()->getStrEmit(); | 1384 Ostream &Str = Func->getContext()->getStrEmit(); |
| 1385 assert(this->getSrcSize() == 1); | 1385 assert(this->getSrcSize() == 1); |
| 1386 Operand *Src0 = this->getSrc(0); | 1386 Operand *Src0 = this->getSrc(0); |
| 1387 assert(llvm::isa<Variable>(Src0)); | 1387 int32_t DestReg = this->getDest()->getRegNum(); |
| 1388 int32_t SrcReg = llvm::cast<Variable>(Src0)->getRegNum(); |
| 1389 (void)DestReg; |
| 1390 (void)SrcReg; |
| 1388 switch (Src0->getType()) { | 1391 switch (Src0->getType()) { |
| 1389 default: | 1392 default: |
| 1390 llvm_unreachable("unexpected source type!"); | 1393 llvm_unreachable("unexpected source type!"); |
| 1391 break; | 1394 break; |
| 1392 case IceType_i8: | 1395 case IceType_i8: |
| 1393 assert(llvm::cast<Variable>(Src0)->getRegNum() == | 1396 assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_al); |
| 1394 InstX86Base<Machine>::Traits::RegisterSet::Reg_al); | 1397 assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ax || |
| 1395 assert(this->getDest()->getRegNum() == | 1398 DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ah); |
| 1396 InstX86Base<Machine>::Traits::RegisterSet::Reg_ax); | |
| 1397 Str << "\t" | 1399 Str << "\t" |
| 1398 << "cbtw"; | 1400 << "cbtw"; |
| 1399 break; | 1401 break; |
| 1400 case IceType_i16: | 1402 case IceType_i16: |
| 1401 assert(llvm::cast<Variable>(Src0)->getRegNum() == | 1403 assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ax); |
| 1402 InstX86Base<Machine>::Traits::RegisterSet::Reg_ax); | 1404 assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_dx); |
| 1403 assert(this->getDest()->getRegNum() == | |
| 1404 InstX86Base<Machine>::Traits::RegisterSet::Reg_dx); | |
| 1405 Str << "\t" | 1405 Str << "\t" |
| 1406 << "cwtd"; | 1406 << "cwtd"; |
| 1407 break; | 1407 break; |
| 1408 case IceType_i32: | 1408 case IceType_i32: |
| 1409 assert(llvm::cast<Variable>(Src0)->getRegNum() == | 1409 assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| 1410 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | 1410 assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); |
| 1411 assert(this->getDest()->getRegNum() == | |
| 1412 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); | |
| 1413 Str << "\t" | 1411 Str << "\t" |
| 1414 << "cltd"; | 1412 << "cltd"; |
| 1415 break; | 1413 break; |
| 1416 case IceType_i64: | 1414 case IceType_i64: |
| 1417 assert(this->getDest()->getRegNum() == | 1415 assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); |
| 1418 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); | |
| 1419 Str << "\t" | 1416 Str << "\t" |
| 1420 << "cdto"; | 1417 << "cdto"; |
| 1421 break; | 1418 break; |
| 1422 } | 1419 } |
| 1423 } | 1420 } |
| 1424 | 1421 |
| 1425 template <class Machine> | 1422 template <class Machine> |
| 1426 void InstX86Cbwdq<Machine>::emitIAS(const Cfg *Func) const { | 1423 void InstX86Cbwdq<Machine>::emitIAS(const Cfg *Func) const { |
| 1427 typename InstX86Base<Machine>::Traits::Assembler *Asm = | 1424 typename InstX86Base<Machine>::Traits::Assembler *Asm = |
| 1428 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); | 1425 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>(); |
| 1429 assert(this->getSrcSize() == 1); | 1426 assert(this->getSrcSize() == 1); |
| 1430 Operand *Src0 = this->getSrc(0); | 1427 Operand *Src0 = this->getSrc(0); |
| 1431 assert(llvm::isa<Variable>(Src0)); | 1428 int32_t DestReg = this->getDest()->getRegNum(); |
| 1429 int32_t SrcReg = llvm::cast<Variable>(Src0)->getRegNum(); |
| 1430 (void)DestReg; |
| 1431 (void)SrcReg; |
| 1432 switch (Src0->getType()) { | 1432 switch (Src0->getType()) { |
| 1433 default: | 1433 default: |
| 1434 llvm_unreachable("unexpected source type!"); | 1434 llvm_unreachable("unexpected source type!"); |
| 1435 break; | 1435 break; |
| 1436 case IceType_i8: | 1436 case IceType_i8: |
| 1437 assert(llvm::cast<Variable>(Src0)->getRegNum() == | 1437 assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_al); |
| 1438 InstX86Base<Machine>::Traits::RegisterSet::Reg_al); | 1438 assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ax || |
| 1439 assert(this->getDest()->getRegNum() == | 1439 DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ah); |
| 1440 InstX86Base<Machine>::Traits::RegisterSet::Reg_ax); | |
| 1441 Asm->cbw(); | 1440 Asm->cbw(); |
| 1442 break; | 1441 break; |
| 1443 case IceType_i16: | 1442 case IceType_i16: |
| 1444 assert(llvm::cast<Variable>(Src0)->getRegNum() == | 1443 assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ax); |
| 1445 InstX86Base<Machine>::Traits::RegisterSet::Reg_ax); | 1444 assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_dx); |
| 1446 assert(this->getDest()->getRegNum() == | |
| 1447 InstX86Base<Machine>::Traits::RegisterSet::Reg_dx); | |
| 1448 Asm->cwd(); | 1445 Asm->cwd(); |
| 1449 break; | 1446 break; |
| 1450 case IceType_i32: | 1447 case IceType_i32: |
| 1451 assert(llvm::cast<Variable>(Src0)->getRegNum() == | 1448 assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); |
| 1452 InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); | 1449 assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); |
| 1453 assert(this->getDest()->getRegNum() == | |
| 1454 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); | |
| 1455 Asm->cdq(); | 1450 Asm->cdq(); |
| 1456 break; | 1451 break; |
| 1457 case IceType_i64: | 1452 case IceType_i64: |
| 1458 assert(this->getDest()->getRegNum() == | 1453 assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); |
| 1459 InstX86Base<Machine>::Traits::RegisterSet::Reg_edx); | |
| 1460 Asm->cqo(); | 1454 Asm->cqo(); |
| 1461 break; | 1455 break; |
| 1462 } | 1456 } |
| 1463 } | 1457 } |
| 1464 | 1458 |
| 1465 template <class Machine> void InstX86Mul<Machine>::emit(const Cfg *Func) const { | 1459 template <class Machine> void InstX86Mul<Machine>::emit(const Cfg *Func) const { |
| 1466 if (!BuildDefs::dump()) | 1460 if (!BuildDefs::dump()) |
| 1467 return; | 1461 return; |
| 1468 Ostream &Str = Func->getContext()->getStrEmit(); | 1462 Ostream &Str = Func->getContext()->getStrEmit(); |
| 1469 assert(this->getSrcSize() == 2); | 1463 assert(this->getSrcSize() == 2); |
| (...skipping 801 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2271 assert(this->getSrcSize() == 1); | 2265 assert(this->getSrcSize() == 1); |
| 2272 Operand *Src = this->getSrc(0); | 2266 Operand *Src = this->getSrc(0); |
| 2273 Type SrcTy = Src->getType(); | 2267 Type SrcTy = Src->getType(); |
| 2274 Type DestTy = this->getDest()->getType(); | 2268 Type DestTy = this->getDest()->getType(); |
| 2275 if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 && | 2269 if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 && |
| 2276 isIntegerConstant(Src)) { | 2270 isIntegerConstant(Src)) { |
| 2277 Str << "\tmovabs\t"; | 2271 Str << "\tmovabs\t"; |
| 2278 } else { | 2272 } else { |
| 2279 Str << "\tmov" | 2273 Str << "\tmov" |
| 2280 << (!isScalarFloatingType(DestTy) | 2274 << (!isScalarFloatingType(DestTy) |
| 2281 ? this->getWidthString(SrcTy) | 2275 ? this->getWidthString(DestTy) |
| 2282 : InstX86Base<Machine>::Traits::TypeAttributes[DestTy] | 2276 : InstX86Base<Machine>::Traits::TypeAttributes[DestTy] |
| 2283 .SdSsString) << "\t"; | 2277 .SdSsString) << "\t"; |
| 2284 } | 2278 } |
| 2285 // For an integer truncation operation, src is wider than dest. Ideally, we | 2279 // For an integer truncation operation, src is wider than dest. In this case, |
| 2286 // use a mov instruction whose data width matches the narrower dest. This is | 2280 // we use a mov instruction whose data width matches the narrower dest. |
| 2287 // a problem if e.g. src is a register like esi or si where there is no 8-bit | |
| 2288 // version of the register. To be safe, we instead widen the dest to match | |
| 2289 // src. This works even for stack-allocated dest variables because | |
| 2290 // typeWidthOnStack() pads to a 4-byte boundary even if only a lower portion | |
| 2291 // is used. | |
| 2292 // TODO: This assert disallows usages such as copying a floating | 2281 // TODO: This assert disallows usages such as copying a floating |
| 2293 // point value between a vector and a scalar (which movss is used for). Clean | 2282 // point value between a vector and a scalar (which movss is used for). Clean |
| 2294 // this up. | 2283 // this up. |
| 2295 assert(Func->getTarget()->typeWidthInBytesOnStack(DestTy) == | 2284 assert(Func->getTarget()->typeWidthInBytesOnStack(DestTy) == |
| 2296 Func->getTarget()->typeWidthInBytesOnStack(SrcTy)); | 2285 Func->getTarget()->typeWidthInBytesOnStack(SrcTy)); |
| 2297 Src->emit(Func); | 2286 const Operand *NewSrc = Src; |
| 2287 if (auto *SrcVar = llvm::dyn_cast<Variable>(Src)) { |
| 2288 int32_t NewRegNum = Variable::NoRegister; |
| 2289 if (SrcVar->hasReg()) |
| 2290 NewRegNum = InstX86Base<Machine>::Traits::getGprForType( |
| 2291 DestTy, SrcVar->getRegNum()); |
| 2292 if (SrcTy != DestTy) |
| 2293 NewSrc = SrcVar->asType(DestTy, NewRegNum); |
| 2294 } |
| 2295 NewSrc->emit(Func); |
| 2298 Str << ", "; | 2296 Str << ", "; |
| 2299 int32_t NewRegNum = Variable::NoRegister; | 2297 this->getDest()->emit(Func); |
| 2300 if (this->getDest()->hasReg()) | |
| 2301 NewRegNum = InstX86Base<Machine>::Traits::getGprForType( | |
| 2302 SrcTy, this->getDest()->getRegNum()); | |
| 2303 const Variable *NewDest = SrcTy == DestTy | |
| 2304 ? this->getDest() | |
| 2305 : this->getDest()->asType(SrcTy, NewRegNum); | |
| 2306 NewDest->emit(Func); | |
| 2307 } | 2298 } |
| 2308 | 2299 |
| 2309 template <class Machine> | 2300 template <class Machine> |
| 2310 void InstX86Mov<Machine>::emitIAS(const Cfg *Func) const { | 2301 void InstX86Mov<Machine>::emitIAS(const Cfg *Func) const { |
| 2311 assert(this->getSrcSize() == 1); | 2302 assert(this->getSrcSize() == 1); |
| 2312 const Variable *Dest = this->getDest(); | 2303 const Variable *Dest = this->getDest(); |
| 2313 const Operand *Src = this->getSrc(0); | 2304 const Operand *Src = this->getSrc(0); |
| 2314 Type DestTy = Dest->getType(); | 2305 Type DestTy = Dest->getType(); |
| 2315 Type SrcTy = Src->getType(); | 2306 Type SrcTy = Src->getType(); |
| 2316 // Mov can be used for GPRs or XMM registers. Also, the type does not | 2307 // Mov can be used for GPRs or XMM registers. Also, the type does not |
| 2317 // necessarily match (Mov can be used for bitcasts). However, when the type | 2308 // necessarily match (Mov can be used for bitcasts). However, when the type |
| 2318 // does not match, one of the operands must be a register. Thus, the strategy | 2309 // does not match, one of the operands must be a register. Thus, the strategy |
| 2319 // is to find out if Src or Dest are a register, then use that register's | 2310 // is to find out if Src or Dest are a register, then use that register's |
| 2320 // type to decide on which emitter set to use. The emitter set will include | 2311 // type to decide on which emitter set to use. The emitter set will include |
| 2321 // reg-reg movs, but that case should be unused when the types don't match. | 2312 // reg-reg movs, but that case should be unused when the types don't match. |
| 2322 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp | 2313 static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp |
| 2323 XmmRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::movss, | 2314 XmmRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::movss, |
| 2324 &InstX86Base<Machine>::Traits::Assembler::movss}; | 2315 &InstX86Base<Machine>::Traits::Assembler::movss}; |
| 2325 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp | 2316 static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp |
| 2326 GPRRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::mov, | 2317 GPRRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::mov, |
| 2327 &InstX86Base<Machine>::Traits::Assembler::mov, | 2318 &InstX86Base<Machine>::Traits::Assembler::mov, |
| 2328 &InstX86Base<Machine>::Traits::Assembler::mov}; | 2319 &InstX86Base<Machine>::Traits::Assembler::mov}; |
| 2329 static const typename InstX86Base< | 2320 static const typename InstX86Base< |
| 2330 Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = { | 2321 Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = { |
| 2331 &InstX86Base<Machine>::Traits::Assembler::mov, | 2322 &InstX86Base<Machine>::Traits::Assembler::mov, |
| 2332 &InstX86Base<Machine>::Traits::Assembler::mov}; | 2323 &InstX86Base<Machine>::Traits::Assembler::mov}; |
| 2333 // For an integer truncation operation, src is wider than dest. Ideally, we | 2324 // For an integer truncation operation, src is wider than dest. In this case, |
| 2334 // use a mov instruction whose data width matches the narrower dest. This is | 2325 // we use a mov instruction whose data width matches the narrower dest. |
| 2335 // a problem if e.g. src is a register like esi or si where there is no 8-bit | |
| 2336 // version of the register. To be safe, we instead widen the dest to match | |
| 2337 // src. This works even for stack-allocated dest variables because | |
| 2338 // typeWidthOnStack() pads to a 4-byte boundary even if only a lower portion | |
| 2339 // is used. | |
| 2340 // TODO: This assert disallows usages such as copying a floating | 2326 // TODO: This assert disallows usages such as copying a floating |
| 2341 // point value between a vector and a scalar (which movss is used for). Clean | 2327 // point value between a vector and a scalar (which movss is used for). Clean |
| 2342 // this up. | 2328 // this up. |
| 2343 assert( | 2329 assert( |
| 2344 Func->getTarget()->typeWidthInBytesOnStack(this->getDest()->getType()) == | 2330 Func->getTarget()->typeWidthInBytesOnStack(this->getDest()->getType()) == |
| 2345 Func->getTarget()->typeWidthInBytesOnStack(Src->getType())); | 2331 Func->getTarget()->typeWidthInBytesOnStack(Src->getType())); |
| 2346 if (Dest->hasReg()) { | 2332 if (Dest->hasReg()) { |
| 2347 if (isScalarFloatingType(DestTy)) { | 2333 if (isScalarFloatingType(DestTy)) { |
| 2348 emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, XmmRegEmitter); | 2334 emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, XmmRegEmitter); |
| 2349 return; | 2335 return; |
| 2350 } else { | 2336 } else { |
| 2351 assert(isScalarIntegerType(DestTy)); | 2337 assert(isScalarIntegerType(DestTy)); |
| 2352 // Widen DestTy for truncation (see above note). We should only do this | 2338 // Widen DestTy for truncation (see above note). We should only do this |
| 2353 // when both Src and Dest are integer types. | 2339 // when both Src and Dest are integer types. |
| 2354 if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 && | 2340 if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 && |
| 2355 isIntegerConstant(Src)) { | 2341 isIntegerConstant(Src)) { |
| 2356 uint64_t Value = -1; | 2342 uint64_t Value = -1; |
| 2357 if (const auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src)) { | 2343 if (const auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src)) { |
| 2358 Value = C64->getValue(); | 2344 Value = C64->getValue(); |
| 2359 } else { | 2345 } else { |
| 2360 Value = llvm::cast<ConstantInteger32>(Src)->getValue(); | 2346 Value = llvm::cast<ConstantInteger32>(Src)->getValue(); |
| 2361 } | 2347 } |
| 2362 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>() | 2348 Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>() |
| 2363 ->movabs( | 2349 ->movabs( |
| 2364 InstX86Base<Machine>::Traits::getEncodedGPR(Dest->getRegNum()), | 2350 InstX86Base<Machine>::Traits::getEncodedGPR(Dest->getRegNum()), |
| 2365 Value); | 2351 Value); |
| 2366 return; | 2352 return; |
| 2367 } | 2353 } |
| 2368 if (isScalarIntegerType(SrcTy)) { | 2354 if (isScalarIntegerType(SrcTy)) { |
| 2369 DestTy = SrcTy; | 2355 SrcTy = DestTy; |
| 2370 } | 2356 } |
| 2371 emitIASRegOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRRegEmitter); | 2357 emitIASRegOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRRegEmitter); |
| 2372 return; | 2358 return; |
| 2373 } | 2359 } |
| 2374 } else { | 2360 } else { |
| 2375 // Dest must be Stack and Src *could* be a register. Use Src's type to | 2361 // Dest must be Stack and Src *could* be a register. Use Src's type to |
| 2376 // decide on the emitters. | 2362 // decide on the emitters. |
| 2377 typename InstX86Base<Machine>::Traits::Address StackAddr( | 2363 typename InstX86Base<Machine>::Traits::Address StackAddr( |
| 2378 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( | 2364 static_cast<typename InstX86Base<Machine>::Traits::TargetLowering *>( |
| 2379 Func->getTarget()) | 2365 Func->getTarget()) |
| (...skipping 904 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3284 return; | 3270 return; |
| 3285 Ostream &Str = Func->getContext()->getStrDump(); | 3271 Ostream &Str = Func->getContext()->getStrDump(); |
| 3286 Str << "IACA_END"; | 3272 Str << "IACA_END"; |
| 3287 } | 3273 } |
| 3288 | 3274 |
| 3289 } // end of namespace X86Internal | 3275 } // end of namespace X86Internal |
| 3290 | 3276 |
| 3291 } // end of namespace Ice | 3277 } // end of namespace Ice |
| 3292 | 3278 |
| 3293 #endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H | 3279 #endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H |
| OLD | NEW |