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

Side by Side Diff: src/IceTargetLoweringX86BaseImpl.h

Issue 1234803007: Introduction of improved switch lowering. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Created 5 years, 5 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
OLDNEW
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
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
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
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
OLDNEW
« src/IceTargetLoweringX86Base.h ('K') | « src/IceTargetLoweringX86Base.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698