Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===- subzero/src/IceTargetLoweringX86BaseImpl.h - x86 lowering -*- C++ -*-==// | 1 //===- subzero/src/IceTargetLoweringX86BaseImpl.h - x86 lowering -*- 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 10 matching lines...) Expand all Loading... | |
| 21 #include "IceCfgNode.h" | 21 #include "IceCfgNode.h" |
| 22 #include "IceClFlags.h" | 22 #include "IceClFlags.h" |
| 23 #include "IceDefs.h" | 23 #include "IceDefs.h" |
| 24 #include "IceELFObjectWriter.h" | 24 #include "IceELFObjectWriter.h" |
| 25 #include "IceGlobalInits.h" | 25 #include "IceGlobalInits.h" |
| 26 #include "IceLiveness.h" | 26 #include "IceLiveness.h" |
| 27 #include "IceOperand.h" | 27 #include "IceOperand.h" |
| 28 #include "IceUtils.h" | 28 #include "IceUtils.h" |
| 29 #include "llvm/Support/MathExtras.h" | 29 #include "llvm/Support/MathExtras.h" |
| 30 | 30 |
| 31 #include <stack> | |
| 32 | |
| 31 namespace Ice { | 33 namespace Ice { |
| 32 namespace X86Internal { | 34 namespace X86Internal { |
| 33 | 35 |
| 34 /// A helper class to ease the settings of RandomizationPoolingPause to disable | 36 /// A helper class to ease the settings of RandomizationPoolingPause to disable |
| 35 /// constant blinding or pooling for some translation phases. | 37 /// constant blinding or pooling for some translation phases. |
| 36 class BoolFlagSaver { | 38 class BoolFlagSaver { |
| 37 BoolFlagSaver() = delete; | 39 BoolFlagSaver() = delete; |
| 38 BoolFlagSaver(const BoolFlagSaver &) = delete; | 40 BoolFlagSaver(const BoolFlagSaver &) = delete; |
| 39 BoolFlagSaver &operator=(const BoolFlagSaver &) = delete; | 41 BoolFlagSaver &operator=(const BoolFlagSaver &) = delete; |
| 40 | 42 |
| (...skipping 4443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4484 Addr = Traits::X86OperandMem::create(Func, Data->getType(), Base, OffsetOp, | 4486 Addr = Traits::X86OperandMem::create(Func, Data->getType(), Base, OffsetOp, |
| 4485 Index, Shift, SegmentReg); | 4487 Index, Shift, SegmentReg); |
| 4486 InstStore *NewStore = InstStore::create(Func, Data, Addr); | 4488 InstStore *NewStore = InstStore::create(Func, Data, Addr); |
| 4487 if (Inst->getDest()) | 4489 if (Inst->getDest()) |
| 4488 NewStore->setRmwBeacon(Inst->getRmwBeacon()); | 4490 NewStore->setRmwBeacon(Inst->getRmwBeacon()); |
| 4489 Context.insert(NewStore); | 4491 Context.insert(NewStore); |
| 4490 } | 4492 } |
| 4491 } | 4493 } |
| 4492 | 4494 |
| 4493 template <class Machine> | 4495 template <class Machine> |
| 4496 Operand *TargetX86Base<Machine>::lowerCmpRange(Operand *Comparison, | |
| 4497 uint64_t Min, | |
| 4498 uint64_t Max) { | |
| 4499 // Subtracting 0 is a nop so don't do it | |
| 4500 if (Min != 0) { | |
| 4501 // Avoid clobbering the comparison by copying it | |
| 4502 Variable *T = nullptr; | |
| 4503 _mov(T, Comparison); | |
| 4504 _sub(T, Ctx->getConstantInt32(Min)); | |
|
Jim Stichnoth
2015/07/15 19:17:43
Here and below, there seem to be assumptions that
ascull
2015/07/16 19:38:46
Done.
| |
| 4505 Comparison = T; | |
| 4506 } | |
| 4507 | |
| 4508 _cmp(Comparison, Ctx->getConstantInt32(Max - Min)); | |
| 4509 | |
| 4510 return Comparison; | |
| 4511 } | |
| 4512 | |
| 4513 template <class Machine> | |
| 4514 void TargetX86Base<Machine>::lowerCaseCluster(const CaseCluster &Case, | |
| 4515 Operand *Comparison, | |
| 4516 CfgNode *DefaultLabel) { | |
| 4517 switch (Case.getKind()) { | |
| 4518 case CaseCluster::JumpTable: { | |
| 4519 typename Traits::Insts::Label *Label; | |
|
jvoung (off chromium)
2015/07/15 18:32:02
Is there a more informative name for this? It's us
ascull
2015/07/16 19:38:46
Done.
| |
| 4520 | |
| 4521 Operand *RangeIndex = lowerCmpRange(Comparison, | |
| 4522 Case.getLow(), | |
| 4523 Case.getHigh()); | |
| 4524 if (DefaultLabel != nullptr) { | |
| 4525 _br(Traits::Cond::Br_a, DefaultLabel); | |
| 4526 } else { | |
| 4527 // Skip over jump table logic if copmarison not in range and no default | |
|
jvoung (off chromium)
2015/07/15 18:32:02
copmarison -> comparison
ascull
2015/07/16 19:38:46
Done.
| |
| 4528 Label = Traits::Insts::Label::create(Func, this); | |
| 4529 _br(Traits::Cond::Br_a, Label); | |
| 4530 } | |
| 4531 | |
| 4532 InstJumpTable *JumpTable = Case.getJumpTable(); | |
| 4533 Context.insert(JumpTable); | |
| 4534 | |
| 4535 // Make sure the index is a register of the same width as the base | |
| 4536 Variable *Index; | |
| 4537 if (RangeIndex->getType() != getPointerType()) { | |
| 4538 Index = makeReg(getPointerType()); | |
| 4539 _movzx(Index, RangeIndex); | |
| 4540 } else { | |
| 4541 Index = legalizeToVar(RangeIndex); | |
| 4542 } | |
| 4543 | |
| 4544 Constant *Offset = Ctx->getConstantSym(0, JumpTable->getName(Func), true); | |
|
jvoung (off chromium)
2015/07/15 18:32:02
We usually use
constexpr RelocOffsetT Offset = 0;
ascull
2015/07/16 19:38:46
Done.
| |
| 4545 // TODO(ascull): remove need for legalize by allowing null base in memop | |
| 4546 auto *MemTarget = Traits::X86OperandMem::create(Func, getPointerType(), | |
| 4547 legalizeToVar(Offset), nullptr, Index, 2); | |
|
Jim Stichnoth
2015/07/15 19:17:43
Same as Jan's comment above, for nullptr and 2.
A
ascull
2015/07/16 19:38:46
Done.
| |
| 4548 Variable *Target = makeReg(getPointerType()); | |
|
Jim Stichnoth
2015/07/15 19:17:42
I think you can just set Target=nullptr and the _m
ascull
2015/07/16 19:38:46
But does does _mov() ensure the width will be the
Jim Stichnoth
2015/07/17 15:33:47
Take a look at definition of _mov():
...
i
ascull
2015/07/17 18:21:28
Done.
| |
| 4549 _mov(Target, MemTarget); | |
| 4550 _jmp(Target); | |
|
Jim Stichnoth
2015/07/15 19:17:43
Leave a TODO about sandboxing the indirect jump -
ascull
2015/07/16 19:38:46
Done.
| |
| 4551 | |
| 4552 if (DefaultLabel == nullptr) | |
| 4553 Context.insert(Label); | |
| 4554 return; | |
| 4555 } | |
| 4556 case CaseCluster::Range: { | |
| 4557 if (Case.getHigh() == Case.getLow()) { | |
| 4558 // Single item | |
| 4559 Constant *Value = Ctx->getConstantInt32(Case.getLow()); | |
| 4560 _cmp(Comparison, Value); | |
| 4561 _br(Traits::Cond::Br_e, Case.getLabel()); | |
| 4562 if (DefaultLabel != nullptr) | |
| 4563 _br(DefaultLabel); | |
| 4564 } else { | |
| 4565 // Range | |
| 4566 lowerCmpRange(Comparison, Case.getLow(), Case.getHigh()); | |
| 4567 _br(Traits::Cond::Br_be, Case.getLabel()); | |
| 4568 if (DefaultLabel != nullptr) | |
| 4569 _br(DefaultLabel); | |
| 4570 } | |
| 4571 return; | |
| 4572 } | |
| 4573 } | |
| 4574 } | |
| 4575 | |
| 4576 template <class Machine> | |
| 4494 void TargetX86Base<Machine>::lowerSwitch(const InstSwitch *Inst) { | 4577 void TargetX86Base<Machine>::lowerSwitch(const InstSwitch *Inst) { |
| 4495 // This implements the most naive possible lowering. | 4578 // Do it the old fashioned way unless asked for the advanced method |
| 4496 // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default | 4579 if (!Ctx->getFlags().getUseAdvancedSwitchLowering()) { |
| 4580 // This implements the most naive possible lowering. | |
| 4581 // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default | |
| 4582 Operand *Src0 = Inst->getComparison(); | |
| 4583 SizeT NumCases = Inst->getNumCases(); | |
| 4584 if (Src0->getType() == IceType_i64) { | |
| 4585 Src0 = legalize(Src0); // get Base/Index into physical registers | |
| 4586 Operand *Src0Lo = loOperand(Src0); | |
| 4587 Operand *Src0Hi = hiOperand(Src0); | |
| 4588 if (NumCases >= 2) { | |
| 4589 Src0Lo = legalizeToVar(Src0Lo); | |
| 4590 Src0Hi = legalizeToVar(Src0Hi); | |
| 4591 } else { | |
| 4592 Src0Lo = legalize(Src0Lo, Legal_Reg | Legal_Mem); | |
| 4593 Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem); | |
| 4594 } | |
| 4595 for (SizeT I = 0; I < NumCases; ++I) { | |
| 4596 Constant *ValueLo = Ctx->getConstantInt32(Inst->getValue(I)); | |
| 4597 Constant *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32); | |
| 4598 typename Traits::Insts::Label *Label = | |
| 4599 Traits::Insts::Label::create(Func, this); | |
| 4600 _cmp(Src0Lo, ValueLo); | |
| 4601 _br(Traits::Cond::Br_ne, Label); | |
| 4602 _cmp(Src0Hi, ValueHi); | |
| 4603 _br(Traits::Cond::Br_e, Inst->getLabel(I)); | |
| 4604 Context.insert(Label); | |
| 4605 } | |
| 4606 _br(Inst->getLabelDefault()); | |
| 4607 return; | |
| 4608 } | |
| 4609 // OK, we'll be slightly less naive by forcing Src into a physical | |
| 4610 // register if there are 2 or more uses. | |
| 4611 if (NumCases >= 2) | |
| 4612 Src0 = legalizeToVar(Src0); | |
| 4613 else | |
| 4614 Src0 = legalize(Src0, Legal_Reg | Legal_Mem); | |
| 4615 for (SizeT I = 0; I < NumCases; ++I) { | |
| 4616 Constant *Value = Ctx->getConstantInt32(Inst->getValue(I)); | |
| 4617 _cmp(Src0, Value); | |
| 4618 _br(Traits::Cond::Br_e, Inst->getLabel(I)); | |
| 4619 } | |
| 4620 | |
| 4621 _br(Inst->getLabelDefault()); | |
| 4622 return; | |
| 4623 } | |
| 4624 | |
| 4625 // Doing it the clever way | |
|
jvoung (off chromium)
2015/07/15 18:32:02
At some point here, could describe what the clever
ascull
2015/07/16 19:38:45
Done.
| |
| 4626 CaseClusterArray CaseClusters = CaseCluster::clusterizeSwitch(Func, Inst); | |
| 4497 Operand *Src0 = Inst->getComparison(); | 4627 Operand *Src0 = Inst->getComparison(); |
| 4498 SizeT NumCases = Inst->getNumCases(); | 4628 CfgNode *DefaultLabel = Inst->getLabelDefault(); |
| 4629 | |
| 4630 assert(CaseClusters.size() != 0); // Should always be at least one | |
| 4631 | |
| 4499 if (Src0->getType() == IceType_i64) { | 4632 if (Src0->getType() == IceType_i64) { |
| 4500 Src0 = legalize(Src0); // get Base/Index into physical registers | 4633 Src0 = legalize(Src0); // get Base/Index into physical registers |
| 4501 Operand *Src0Lo = loOperand(Src0); | 4634 Operand *Src0Lo = loOperand(Src0); |
| 4502 Operand *Src0Hi = hiOperand(Src0); | 4635 Operand *Src0Hi = hiOperand(Src0); |
| 4503 if (NumCases >= 2) { | 4636 if (CaseClusters.back().getHigh() > UINT32_MAX) { |
| 4504 Src0Lo = legalizeToVar(Src0Lo); | 4637 // TODO(ascull): handle 64-bit case properly (currently naive version) |
| 4505 Src0Hi = legalizeToVar(Src0Hi); | 4638 SizeT NumCases = Inst->getNumCases(); |
|
jvoung (off chromium)
2015/07/15 18:32:02
Maybe factor out to a function and share the code
ascull
2015/07/16 19:38:45
I'm leaving this for now while we consider the hig
| |
| 4506 } else { | 4639 if (NumCases >= 2) { |
| 4507 Src0Lo = legalize(Src0Lo, Legal_Reg | Legal_Mem); | 4640 Src0Lo = legalizeToVar(Src0Lo); |
| 4641 Src0Hi = legalizeToVar(Src0Hi); | |
| 4642 } else { | |
| 4643 Src0Lo = legalize(Src0Lo, Legal_Reg | Legal_Mem); | |
| 4644 Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem); | |
| 4645 } | |
| 4646 for (SizeT I = 0; I < NumCases; ++I) { | |
| 4647 Constant *ValueLo = Ctx->getConstantInt32(Inst->getValue(I)); | |
| 4648 Constant *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32); | |
| 4649 typename Traits::Insts::Label *Label = | |
| 4650 Traits::Insts::Label::create(Func, this); | |
| 4651 _cmp(Src0Lo, ValueLo); | |
| 4652 _br(Traits::Cond::Br_ne, Label); | |
| 4653 _cmp(Src0Hi, ValueHi); | |
| 4654 _br(Traits::Cond::Br_e, Inst->getLabel(I)); | |
| 4655 Context.insert(Label); | |
| 4656 } | |
| 4657 _br(Inst->getLabelDefault()); | |
| 4658 return; | |
| 4659 } else { | |
| 4660 // All the values are 32-bit so just check the operand is too and then | |
| 4661 // fall through to the 32-bit implementation. This is a common case. | |
| 4508 Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem); | 4662 Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem); |
| 4509 } | 4663 Constant *Zero = Ctx->getConstantInt32(0); |
| 4510 for (SizeT I = 0; I < NumCases; ++I) { | 4664 _cmp(Src0Hi, Zero); |
| 4511 Constant *ValueLo = Ctx->getConstantInt32(Inst->getValue(I)); | 4665 _br(Traits::Cond::Br_ne, DefaultLabel); |
| 4512 Constant *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32); | 4666 Src0 = Src0Lo; |
| 4513 typename Traits::Insts::Label *Label = | 4667 } |
| 4514 Traits::Insts::Label::create(Func, this); | 4668 } |
| 4515 _cmp(Src0Lo, ValueLo); | 4669 |
| 4516 _br(Traits::Cond::Br_ne, Label); | 4670 // 32-bit lowering |
| 4517 _cmp(Src0Hi, ValueHi); | 4671 |
| 4518 _br(Traits::Cond::Br_e, Inst->getLabel(I)); | 4672 if (CaseClusters.size() == 1) { |
| 4519 Context.insert(Label); | 4673 // Jump straight to default if needed. Currently a common case as jump |
| 4520 } | 4674 // tables occur on their own. |
| 4521 _br(Inst->getLabelDefault()); | 4675 lowerCaseCluster(CaseClusters.front(), Src0, DefaultLabel); |
| 4522 return; | 4676 return; |
| 4523 } | 4677 } |
| 4524 // OK, we'll be slightly less naive by forcing Src into a physical | 4678 |
| 4525 // register if there are 2 or more uses. | 4679 // Going to be using multiple times so get it in a register early |
| 4526 if (NumCases >= 2) | 4680 Variable *Comparison = legalizeToVar(Src0); |
| 4527 Src0 = legalizeToVar(Src0); | 4681 |
| 4528 else | 4682 // A span is over the clusters |
| 4529 Src0 = legalize(Src0, Legal_Reg | Legal_Mem); | 4683 struct SearchSpan { |
| 4530 for (SizeT I = 0; I < NumCases; ++I) { | 4684 SearchSpan(SizeT _Begin, SizeT _Size, |
|
jvoung (off chromium)
2015/07/15 18:32:02
There's still some debate on what to do with shado
Jim Stichnoth
2015/07/15 19:17:43
Also, I believe C/C++ forbid the underscore-upperc
ascull
2015/07/16 19:38:45
Done.
| |
| 4531 Constant *Value = Ctx->getConstantInt32(Inst->getValue(I)); | 4685 typename Traits::Insts::Label *_Label) |
| 4532 _cmp(Src0, Value); | 4686 : Begin(_Begin), Size(_Size), Label(_Label) {} |
| 4533 _br(Traits::Cond::Br_e, Inst->getLabel(I)); | 4687 |
| 4534 } | 4688 SizeT Begin; |
| 4535 | 4689 SizeT Size; |
| 4536 _br(Inst->getLabelDefault()); | 4690 typename Traits::Insts::Label *Label; |
| 4537 } | 4691 }; |
| 4538 | 4692 std::stack<SearchSpan, std::deque<SearchSpan,CfgLocalAllocator<SearchSpan>>> |
| 4539 template <class Machine> | 4693 SearchSpanStack; |
| 4694 SearchSpanStack.emplace(0, CaseClusters.size(), nullptr); | |
| 4695 | |
| 4696 while (!SearchSpanStack.empty()) { | |
| 4697 SearchSpan span = SearchSpanStack.top(); | |
|
jvoung (off chromium)
2015/07/15 18:32:02
"span" -> "Span"
ascull
2015/07/16 19:38:46
Done.
| |
| 4698 SearchSpanStack.pop(); | |
| 4699 | |
| 4700 if (span.Label != nullptr) | |
| 4701 Context.insert(span.Label); | |
| 4702 | |
| 4703 switch (span.Size) { | |
| 4704 case 0: | |
| 4705 llvm_unreachable("Invalid SearchSpan size"); | |
|
Jim Stichnoth
2015/07/15 19:17:43
In general, use llvm::report_fatal_error() rather
ascull
2015/07/16 19:38:46
Done.
| |
| 4706 break; | |
| 4707 | |
| 4708 // Deliberate fall through for base cases | |
| 4709 case 2: | |
| 4710 lowerCaseCluster(CaseClusters[span.Begin+1], Comparison); | |
| 4711 case 1: | |
| 4712 // Can fall through to default branch on last span | |
| 4713 lowerCaseCluster(CaseClusters[span.Begin ], Comparison, | |
|
jvoung (off chromium)
2015/07/15 18:32:02
nit: Hmm haven't seen spacing attempt to line up t
ascull
2015/07/16 19:38:46
Done.
| |
| 4714 SearchSpanStack.empty() ? nullptr : DefaultLabel); | |
| 4715 break; | |
| 4716 | |
| 4717 default: | |
| 4718 // Pick the middle item and branch b or ae | |
| 4719 SizeT PivotIndex = span.Begin + (span.Size / 2); | |
| 4720 const CaseCluster &Pivot = CaseClusters[PivotIndex]; | |
| 4721 Constant *Value = Ctx->getConstantInt32(Pivot.getLow()); | |
| 4722 // TODO(ascull): what if this jump is too big? | |
| 4723 typename Traits::Insts::Label *Label = Traits::Insts::Label::create(Func, | |
| 4724 this); | |
| 4725 _cmp(Comparison, Value); | |
| 4726 _br(Traits::Cond::Br_b, Label); | |
| 4727 // Lower the left and (pivot+right) sides, falling through to the right | |
| 4728 SearchSpanStack.emplace(span.Begin, span.Size / 2, Label); | |
| 4729 SearchSpanStack.emplace(PivotIndex, span.Size - (span.Size / 2), nullptr); | |
| 4730 break; | |
| 4731 } | |
| 4732 } | |
| 4733 | |
| 4734 _br(DefaultLabel); | |
| 4735 } | |
| 4736 | |
| 4737 template <class Machine> | |
| 4540 void TargetX86Base<Machine>::scalarizeArithmetic(InstArithmetic::OpKind Kind, | 4738 void TargetX86Base<Machine>::scalarizeArithmetic(InstArithmetic::OpKind Kind, |
| 4541 Variable *Dest, Operand *Src0, | 4739 Variable *Dest, Operand *Src0, |
| 4542 Operand *Src1) { | 4740 Operand *Src1) { |
| 4543 assert(isVectorType(Dest->getType())); | 4741 assert(isVectorType(Dest->getType())); |
| 4544 Type Ty = Dest->getType(); | 4742 Type Ty = Dest->getType(); |
| 4545 Type ElementTy = typeElementType(Ty); | 4743 Type ElementTy = typeElementType(Ty); |
| 4546 SizeT NumElements = typeNumElements(Ty); | 4744 SizeT NumElements = typeNumElements(Ty); |
| 4547 | 4745 |
| 4548 Operand *T = Ctx->getConstantUndef(Ty); | 4746 Operand *T = Ctx->getConstantUndef(Ty); |
| 4549 for (SizeT I = 0; I < NumElements; ++I) { | 4747 for (SizeT I = 0; I < NumElements; ++I) { |
| (...skipping 867 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5417 } | 5615 } |
| 5418 // the offset is not eligible for blinding or pooling, return the original | 5616 // the offset is not eligible for blinding or pooling, return the original |
| 5419 // mem operand | 5617 // mem operand |
| 5420 return MemOperand; | 5618 return MemOperand; |
| 5421 } | 5619 } |
| 5422 | 5620 |
| 5423 } // end of namespace X86Internal | 5621 } // end of namespace X86Internal |
| 5424 } // end of namespace Ice | 5622 } // end of namespace Ice |
| 5425 | 5623 |
| 5426 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H | 5624 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H |
| OLD | NEW |