OLD | NEW |
1 //===- subzero/src/IceTargetLoweringX8664.cpp - x86-64 lowering -----------===// | 1 //===- subzero/src/IceTargetLoweringX8664.cpp - x86-64 lowering -----------===// |
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 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 } else { | 287 } else { |
288 _push_rbp(); | 288 _push_rbp(); |
289 } | 289 } |
290 } | 290 } |
291 | 291 |
292 void TargetX8664::emitGetIP(CfgNode *Node) { | 292 void TargetX8664::emitGetIP(CfgNode *Node) { |
293 // No IP base register is needed on X86-64. | 293 // No IP base register is needed on X86-64. |
294 (void)Node; | 294 (void)Node; |
295 } | 295 } |
296 | 296 |
| 297 namespace { |
| 298 bool isAssignedToRspOrRbp(const Variable *Var) { |
| 299 if (Var == nullptr) { |
| 300 return false; |
| 301 } |
| 302 |
| 303 if (Var->isRematerializable()) { |
| 304 return true; |
| 305 } |
| 306 |
| 307 if (!Var->hasReg()) { |
| 308 return false; |
| 309 } |
| 310 |
| 311 const int32_t RegNum = Var->getRegNum(); |
| 312 if ((RegNum == Traits::RegisterSet::Reg_rsp) || |
| 313 (RegNum == Traits::RegisterSet::Reg_rbp)) { |
| 314 return true; |
| 315 } |
| 316 |
| 317 return false; |
| 318 } |
| 319 } // end of anonymous namespace |
| 320 |
297 Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) { | 321 Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) { |
298 // In x86_64-nacl, all memory references are relative to %r15 (i.e., %rzp.) | |
299 // NaCl sandboxing also requires that any registers that are not %rsp and | |
300 // %rbp to be 'truncated' to 32-bit before memory access. | |
301 if (SandboxingType == ST_None) { | 322 if (SandboxingType == ST_None) { |
302 return Mem; | 323 return Mem; |
303 } | 324 } |
304 | 325 |
305 if (SandboxingType == ST_Nonsfi) { | 326 if (SandboxingType == ST_Nonsfi) { |
306 llvm::report_fatal_error( | 327 llvm::report_fatal_error( |
307 "_sandbox_mem_reference not implemented for nonsfi"); | 328 "_sandbox_mem_reference not implemented for nonsfi"); |
308 } | 329 } |
309 | 330 |
| 331 // In x86_64-nacl, all memory references are relative to a base register |
| 332 // (%r15, %rsp, %rbp, or %rip). |
| 333 |
310 Variable *Base = Mem->getBase(); | 334 Variable *Base = Mem->getBase(); |
311 Variable *Index = Mem->getIndex(); | 335 Variable *Index = Mem->getIndex(); |
312 uint16_t Shift = 0; | 336 uint16_t Shift = 0; |
313 Variable *ZeroReg = | 337 Variable *ZeroReg = RebasePtr; |
314 getPhysicalRegister(Traits::RegisterSet::Reg_r15, IceType_i64); | |
315 Constant *Offset = Mem->getOffset(); | 338 Constant *Offset = Mem->getOffset(); |
316 Variable *T = nullptr; | 339 Variable *T = nullptr; |
317 | 340 |
| 341 bool AbsoluteAddress = false; |
| 342 if (Base == nullptr && Index == nullptr) { |
| 343 if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Offset)) { |
| 344 if (CR->getName() != "") { |
| 345 // Mem is RIP-relative. There's no need to rebase it. |
| 346 return Mem; |
| 347 } |
| 348 } |
| 349 // Offset is an absolute address, so we need to emit |
| 350 // Offset(%r15) |
| 351 AbsoluteAddress = true; |
| 352 } |
| 353 |
318 if (Mem->getIsRebased()) { | 354 if (Mem->getIsRebased()) { |
319 // If Mem.IsRebased, then we don't need to update Mem to contain a reference | 355 // If Mem.IsRebased, then we don't need to update Mem, as it's already been |
320 // to a valid base register (%r15, %rsp, or %rbp), but we still need to | 356 // updated to contain a reference to one of %rsp, %rbp, or %r15. |
321 // truncate Mem.Index (if any) to 32-bit. | 357 // We don't return early because we still need to zero extend Index. |
322 assert(ZeroReg == Base || Base->isRematerializable()); | 358 assert(ZeroReg == Base || AbsoluteAddress || isAssignedToRspOrRbp(Base)); |
323 T = makeReg(IceType_i32); | 359 if (!AbsoluteAddress) { |
324 _mov(T, Index); | 360 // If Mem is an absolute address, no need to update ZeroReg (which is |
325 Shift = Mem->getShift(); | 361 // already set to %r15.) |
| 362 ZeroReg = Base; |
| 363 } |
| 364 if (Index != nullptr) { |
| 365 T = makeReg(IceType_i32); |
| 366 _mov(T, Index); |
| 367 Shift = Mem->getShift(); |
| 368 } |
326 } else { | 369 } else { |
327 if (Base != nullptr) { | 370 if (Base != nullptr) { |
328 if (Base->isRematerializable()) { | 371 // If Base is a valid base pointer we don't need to use the RebasePtr. By |
| 372 // doing this we might save us the need to zero extend the memory operand. |
| 373 if (isAssignedToRspOrRbp(Base)) { |
329 ZeroReg = Base; | 374 ZeroReg = Base; |
330 } else { | 375 } else { |
331 T = Base; | 376 T = Base; |
332 } | 377 } |
333 } | 378 } |
334 | 379 |
335 if (Index != nullptr) { | 380 if (Index != nullptr) { |
336 assert(!Index->isRematerializable()); | 381 assert(!Index->isRematerializable()); |
| 382 // If Index is not nullptr, it is mandatory that T is a nullptr. |
| 383 // Otherwise, the lowering generated a memory operand with two registers. |
| 384 // Note that Base might still be non-nullptr, but it must be a valid |
| 385 // base register. |
337 if (T != nullptr) { | 386 if (T != nullptr) { |
338 llvm::report_fatal_error("memory reference contains base and index."); | 387 llvm::report_fatal_error("memory reference contains base and index."); |
339 } | 388 } |
340 T = Index; | 389 // If the Index is not shifted, and it is a Valid Base, and the ZeroReg is |
341 Shift = Mem->getShift(); | 390 // still RebasePtr, then we do ZeroReg = Index, and hopefully prevent the |
| 391 // need to zero-extend the memory operand (which may still happen -- see |
| 392 // NeedLea below.) |
| 393 if (Shift == 0 && isAssignedToRspOrRbp(Index) && ZeroReg == RebasePtr) { |
| 394 ZeroReg = Index; |
| 395 } else { |
| 396 T = Index; |
| 397 Shift = Mem->getShift(); |
| 398 } |
342 } | 399 } |
343 } | 400 } |
344 | 401 |
345 // NeedsLea is a flags indicating whether Mem needs to be materialized to a | 402 // NeedsLea is a flags indicating whether Mem needs to be materialized to a |
346 // GPR prior to being used. A LEA is needed if Mem.Offset is a constant | 403 // GPR prior to being used. A LEA is needed if Mem.Offset is a constant |
347 // relocatable, or if Mem.Offset is negative. In both these cases, the LEA is | 404 // relocatable, or if Mem.Offset is negative. In both these cases, the LEA is |
348 // needed to ensure the sandboxed memory operand will only use the lower | 405 // needed to ensure the sandboxed memory operand will only use the lower |
349 // 32-bits of T+Offset. | 406 // 32-bits of T+Offset. |
350 bool NeedsLea = false; | 407 bool NeedsLea = false; |
351 if (const auto *Offset = Mem->getOffset()) { | 408 if (Offset != nullptr) { |
352 if (llvm::isa<ConstantRelocatable>(Offset)) { | 409 if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Offset)) { |
353 NeedsLea = true; | 410 NeedsLea = CR->getName() != "" || CR->getOffset() < 0; |
354 } else if (const auto *Imm = llvm::cast<ConstantInteger32>(Offset)) { | 411 } else if (const auto *Imm = llvm::cast<ConstantInteger32>(Offset)) { |
355 NeedsLea = Imm->getValue() < 0; | 412 NeedsLea = Imm->getValue() < 0; |
| 413 } else { |
| 414 llvm::report_fatal_error("Unexpected Offset type."); |
356 } | 415 } |
357 } | 416 } |
358 | 417 |
359 int32_t RegNum = Variable::NoRegister; | 418 int32_t RegNum = Variable::NoRegister; |
360 int32_t RegNum32 = Variable::NoRegister; | 419 int32_t RegNum32 = Variable::NoRegister; |
361 if (T != nullptr) { | 420 if (T != nullptr) { |
362 if (T->hasReg()) { | 421 if (T->hasReg()) { |
363 RegNum = Traits::getGprForType(IceType_i64, T->getRegNum()); | 422 RegNum = Traits::getGprForType(IceType_i64, T->getRegNum()); |
364 RegNum32 = Traits::getGprForType(IceType_i32, RegNum); | 423 RegNum32 = Traits::getGprForType(IceType_i32, RegNum); |
365 switch (RegNum) { | 424 // At this point, if T was assigned to rsp/rbp, then we would have already |
366 case Traits::RegisterSet::Reg_rsp: | 425 // made this the ZeroReg. |
367 case Traits::RegisterSet::Reg_rbp: | 426 assert(RegNum != Traits::RegisterSet::Reg_rsp); |
368 // Memory operands referencing rsp/rbp do not need to be sandboxed. | 427 assert(RegNum != Traits::RegisterSet::Reg_rbp); |
369 return Mem; | |
370 } | |
371 } | 428 } |
372 | 429 |
373 switch (T->getType()) { | 430 switch (T->getType()) { |
374 default: | 431 default: |
| 432 llvm::report_fatal_error("Mem pointer should be a 32-bit GPR."); |
375 case IceType_i64: | 433 case IceType_i64: |
376 // Even though "default:" would also catch T.Type == IceType_i64, an | 434 // Even though "default:" would also catch T.Type == IceType_i64, an |
377 // explicit 'case IceType_i64' shows that memory operands are always | 435 // explicit 'case IceType_i64' shows that memory operands are always |
378 // supposed to be 32-bits. | 436 // supposed to be 32-bits. |
379 llvm::report_fatal_error("Mem pointer should be 32-bit."); | 437 llvm::report_fatal_error("Mem pointer should not be a 64-bit GPR."); |
380 case IceType_i32: { | 438 case IceType_i32: { |
381 Variable *T64 = makeReg(IceType_i64, RegNum); | 439 Variable *T64 = makeReg(IceType_i64, RegNum); |
382 auto *Movzx = _movzx(T64, T); | 440 auto *Movzx = _movzx(T64, T); |
383 if (!NeedsLea) { | 441 if (!NeedsLea) { |
384 // This movzx is only needed when Mem does not need to be lea'd into a | 442 // This movzx is only needed when Mem does not need to be lea'd into a |
385 // temporary. If an lea is going to be emitted, then eliding this movzx | 443 // temporary. If an lea is going to be emitted, then eliding this movzx |
386 // is safe because the emitted lea will write a 32-bit result -- | 444 // is safe because the emitted lea will write a 32-bit result -- |
387 // implicitly zero-extended to 64-bit. | 445 // implicitly zero-extended to 64-bit. |
388 Movzx->setMustKeep(); | 446 Movzx->setMustKeep(); |
389 } | 447 } |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
716 #define X(tag, sizeLog2, align, elts, elty, str, rcstr) \ | 774 #define X(tag, sizeLog2, align, elts, elty, str, rcstr) \ |
717 static_assert(_table1_##tag == _table2_##tag, \ | 775 static_assert(_table1_##tag == _table2_##tag, \ |
718 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); | 776 "Inconsistency between ICETYPEX8664_TABLE and ICETYPE_TABLE"); |
719 ICETYPE_TABLE | 777 ICETYPE_TABLE |
720 #undef X | 778 #undef X |
721 } // end of namespace dummy3 | 779 } // end of namespace dummy3 |
722 } // end of anonymous namespace | 780 } // end of anonymous namespace |
723 | 781 |
724 } // end of namespace X8664 | 782 } // end of namespace X8664 |
725 } // end of namespace Ice | 783 } // end of namespace Ice |
OLD | NEW |