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 |