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: CL feedback 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, uint64_t Max) {
4498 // TODO(ascull): 64-bit should not reach here but only because it is not
4499 // implemented yet. This should be able to handle the 64-bit case.
4500 assert(Comparison->getType() != IceType_i64);
4501 // Subtracting 0 is a nop so don't do it
4502 if (Min != 0) {
4503 // Avoid clobbering the comparison by copying it
4504 Variable *T = nullptr;
4505 _mov(T, Comparison);
4506 _sub(T, Ctx->getConstantInt32(Min));
4507 Comparison = T;
4508 }
4509
4510 _cmp(Comparison, Ctx->getConstantInt32(Max - Min));
4511
4512 return Comparison;
4513 }
4514
4515 template <class Machine>
4516 void TargetX86Base<Machine>::lowerCaseCluster(const CaseCluster &Case,
4517 Operand *Comparison, bool DoneCmp,
4518 CfgNode *DefaultLabel) {
4519 switch (Case.getKind()) {
4520 case CaseCluster::JumpTable: {
4521 typename Traits::Insts::Label *SkipJumpTable;
4522
4523 Operand *RangeIndex =
4524 lowerCmpRange(Comparison, Case.getLow(), Case.getHigh());
4525 if (DefaultLabel != nullptr) {
4526 _br(Traits::Cond::Br_a, DefaultLabel);
4527 } else {
4528 // Skip over jump table logic if comparison not in range and no default
4529 SkipJumpTable = Traits::Insts::Label::create(Func, this);
4530 _br(Traits::Cond::Br_a, SkipJumpTable);
4531 }
4532
4533 InstJumpTable *JumpTable = Case.getJumpTable();
4534 Context.insert(JumpTable);
4535
4536 // Make sure the index is a register of the same width as the base
4537 Variable *Index;
4538 if (RangeIndex->getType() != getPointerType()) {
4539 Index = makeReg(getPointerType());
4540 _movzx(Index, RangeIndex);
4541 } else {
4542 Index = legalizeToVar(RangeIndex);
4543 }
4544
4545 constexpr RelocOffsetT RelocOffset = 0;
4546 constexpr bool SuppressMangling = true;
4547 Constant *Base = Ctx->getConstantSym(RelocOffset, JumpTable->getName(Func),
4548 SuppressMangling);
4549 Constant *Offset = nullptr;
4550 uint16_t Shift = typeWidthInBytesLog2(getPointerType());
4551 // TODO(ascull): remove need for legalize by allowing null base in memop
4552 auto *MemTarget = Traits::X86OperandMem::create(
4553 Func, getPointerType(), legalizeToVar(Base), Offset, Index, Shift);
4554 Variable *Target = makeReg(getPointerType());
4555 _mov(Target, MemTarget);
4556 _jmp(Target);
4557 // TODO(ascull): sandboxing for indirect jump
4558
4559 if (DefaultLabel == nullptr)
4560 Context.insert(SkipJumpTable);
4561 return;
4562 }
4563 case CaseCluster::Range: {
4564 if (Case.getHigh() == Case.getLow()) {
4565 // Single item
4566 Constant *Value = Ctx->getConstantInt32(Case.getLow());
4567 if (!DoneCmp)
4568 _cmp(Comparison, Value);
4569 _br(Traits::Cond::Br_e, Case.getLabel());
4570 if (DefaultLabel != nullptr)
4571 _br(DefaultLabel);
4572 } else {
4573 // Range
4574 lowerCmpRange(Comparison, Case.getLow(), Case.getHigh());
4575 _br(Traits::Cond::Br_be, Case.getLabel());
4576 if (DefaultLabel != nullptr)
4577 _br(DefaultLabel);
4578 }
4579 return;
4580 }
4581 }
4582 }
4583
4584 template <class Machine>
4494 void TargetX86Base<Machine>::lowerSwitch(const InstSwitch *Inst) { 4585 void TargetX86Base<Machine>::lowerSwitch(const InstSwitch *Inst) {
4495 // This implements the most naive possible lowering. 4586 // 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 4587 if (!Ctx->getFlags().getUseAdvancedSwitchLowering()) {
4588 // This implements the most naive possible lowering.
4589 // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default
4590 Operand *Src0 = Inst->getComparison();
4591 SizeT NumCases = Inst->getNumCases();
4592 if (Src0->getType() == IceType_i64) {
4593 Src0 = legalize(Src0); // get Base/Index into physical registers
4594 Operand *Src0Lo = loOperand(Src0);
4595 Operand *Src0Hi = hiOperand(Src0);
4596 if (NumCases >= 2) {
4597 Src0Lo = legalizeToVar(Src0Lo);
4598 Src0Hi = legalizeToVar(Src0Hi);
4599 } else {
4600 Src0Lo = legalize(Src0Lo, Legal_Reg | Legal_Mem);
4601 Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem);
4602 }
4603 for (SizeT I = 0; I < NumCases; ++I) {
4604 Constant *ValueLo = Ctx->getConstantInt32(Inst->getValue(I));
4605 Constant *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32);
4606 typename Traits::Insts::Label *Label =
4607 Traits::Insts::Label::create(Func, this);
4608 _cmp(Src0Lo, ValueLo);
4609 _br(Traits::Cond::Br_ne, Label);
4610 _cmp(Src0Hi, ValueHi);
4611 _br(Traits::Cond::Br_e, Inst->getLabel(I));
4612 Context.insert(Label);
4613 }
4614 _br(Inst->getLabelDefault());
4615 return;
4616 }
4617 // OK, we'll be slightly less naive by forcing Src into a physical
4618 // register if there are 2 or more uses.
4619 if (NumCases >= 2)
4620 Src0 = legalizeToVar(Src0);
4621 else
4622 Src0 = legalize(Src0, Legal_Reg | Legal_Mem);
4623 for (SizeT I = 0; I < NumCases; ++I) {
4624 Constant *Value = Ctx->getConstantInt32(Inst->getValue(I));
4625 _cmp(Src0, Value);
4626 _br(Traits::Cond::Br_e, Inst->getLabel(I));
4627 }
4628
4629 _br(Inst->getLabelDefault());
4630 return;
4631 }
4632
4633 // Fall back on binary search
4634 CaseClusterArray CaseClusters = CaseCluster::clusterizeSwitch(Func, Inst);
4497 Operand *Src0 = Inst->getComparison(); 4635 Operand *Src0 = Inst->getComparison();
4498 SizeT NumCases = Inst->getNumCases(); 4636 CfgNode *DefaultLabel = Inst->getLabelDefault();
4637
4638 assert(CaseClusters.size() != 0); // Should always be at least one
4639
4499 if (Src0->getType() == IceType_i64) { 4640 if (Src0->getType() == IceType_i64) {
4500 Src0 = legalize(Src0); // get Base/Index into physical registers 4641 Src0 = legalize(Src0); // get Base/Index into physical registers
4501 Operand *Src0Lo = loOperand(Src0); 4642 Operand *Src0Lo = loOperand(Src0);
4502 Operand *Src0Hi = hiOperand(Src0); 4643 Operand *Src0Hi = hiOperand(Src0);
4503 if (NumCases >= 2) { 4644 if (CaseClusters.back().getHigh() > UINT32_MAX) {
4504 Src0Lo = legalizeToVar(Src0Lo); 4645 // TODO(ascull): handle 64-bit case properly (currently naive version)
4505 Src0Hi = legalizeToVar(Src0Hi); 4646 // This might be handled by a higher level lowering of switches.
4506 } else { 4647 SizeT NumCases = Inst->getNumCases();
4507 Src0Lo = legalize(Src0Lo, Legal_Reg | Legal_Mem); 4648 if (NumCases >= 2) {
4649 Src0Lo = legalizeToVar(Src0Lo);
4650 Src0Hi = legalizeToVar(Src0Hi);
4651 } else {
4652 Src0Lo = legalize(Src0Lo, Legal_Reg | Legal_Mem);
4653 Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem);
4654 }
4655 for (SizeT I = 0; I < NumCases; ++I) {
4656 Constant *ValueLo = Ctx->getConstantInt32(Inst->getValue(I));
4657 Constant *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32);
4658 typename Traits::Insts::Label *Label =
4659 Traits::Insts::Label::create(Func, this);
4660 _cmp(Src0Lo, ValueLo);
4661 _br(Traits::Cond::Br_ne, Label);
4662 _cmp(Src0Hi, ValueHi);
4663 _br(Traits::Cond::Br_e, Inst->getLabel(I));
4664 Context.insert(Label);
4665 }
4666 _br(Inst->getLabelDefault());
4667 return;
4668 } else {
4669 // All the values are 32-bit so just check the operand is too and then
4670 // fall through to the 32-bit implementation. This is a common case.
4508 Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem); 4671 Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem);
4509 } 4672 Constant *Zero = Ctx->getConstantInt32(0);
4510 for (SizeT I = 0; I < NumCases; ++I) { 4673 _cmp(Src0Hi, Zero);
4511 Constant *ValueLo = Ctx->getConstantInt32(Inst->getValue(I)); 4674 _br(Traits::Cond::Br_ne, DefaultLabel);
4512 Constant *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32); 4675 Src0 = Src0Lo;
4676 }
4677 }
4678
4679 // 32-bit lowering
4680
4681 if (CaseClusters.size() == 1) {
4682 // Jump straight to default if needed. Currently a common case as jump
4683 // tables occur on their own.
4684 lowerCaseCluster(CaseClusters.front(), Src0, false, DefaultLabel);
jvoung (off chromium) 2015/07/16 22:27:49 constexpr bool DoneCmp = false ?
ascull 2015/07/16 22:55:44 Done.
4685 return;
4686 }
4687
4688 // Going to be using multiple times so get it in a register early
4689 Variable *Comparison = legalizeToVar(Src0);
4690
4691 // A span is over the clusters
4692 struct SearchSpan {
4693 SearchSpan(SizeT Begin, SizeT Size, typename Traits::Insts::Label *Label)
4694 : Begin(Begin), Size(Size), Label(Label) {}
4695
4696 SizeT Begin;
4697 SizeT Size;
4698 typename Traits::Insts::Label *Label;
4699 };
4700 std::stack<SearchSpan, std::deque<SearchSpan, CfgLocalAllocator<SearchSpan>>>
4701 SearchSpanStack;
4702 SearchSpanStack.emplace(0, CaseClusters.size(), nullptr);
4703 bool DoneCmp = false;
4704
4705 while (!SearchSpanStack.empty()) {
4706 SearchSpan Span = SearchSpanStack.top();
4707 SearchSpanStack.pop();
4708
4709 if (Span.Label != nullptr)
4710 Context.insert(Span.Label);
4711
4712 switch (Span.Size) {
4713 case 0:
4714 llvm::report_fatal_error("Invalid SearchSpan size");
4715 break;
4716
4717 case 1:
4718 lowerCaseCluster(CaseClusters[Span.Begin], Comparison, DoneCmp,
4719 SearchSpanStack.empty() ? nullptr : DefaultLabel);
4720 DoneCmp = false;
4721 break;
4722
4723 case 2:
4724 lowerCaseCluster(CaseClusters[Span.Begin], Comparison, DoneCmp);
4725 lowerCaseCluster(CaseClusters[Span.Begin + 1], Comparison, false,
4726 SearchSpanStack.empty() ? nullptr : DefaultLabel);
4727 DoneCmp = false;
jvoung (off chromium) 2015/07/16 22:27:49 Would it make sense to set DoneCmp = false between
ascull 2015/07/16 22:55:44 Done.
4728 break;
4729
4730 default:
4731 // Pick the middle item and branch b or ae
4732 SizeT PivotIndex = Span.Begin + (Span.Size / 2);
4733 const CaseCluster &Pivot = CaseClusters[PivotIndex];
4734 Constant *Value = Ctx->getConstantInt32(Pivot.getLow());
4735 // TODO(ascull): what if this jump is too big?
4513 typename Traits::Insts::Label *Label = 4736 typename Traits::Insts::Label *Label =
4514 Traits::Insts::Label::create(Func, this); 4737 Traits::Insts::Label::create(Func, this);
4515 _cmp(Src0Lo, ValueLo); 4738 _cmp(Comparison, Value);
4516 _br(Traits::Cond::Br_ne, Label); 4739 _br(Traits::Cond::Br_b, Label);
4517 _cmp(Src0Hi, ValueHi); 4740 // Lower the left and (pivot+right) sides, falling through to the right
4518 _br(Traits::Cond::Br_e, Inst->getLabel(I)); 4741 SearchSpanStack.emplace(Span.Begin, Span.Size / 2, Label);
4519 Context.insert(Label); 4742 SearchSpanStack.emplace(PivotIndex, Span.Size - (Span.Size / 2), nullptr);
4520 } 4743 DoneCmp = true;
4521 _br(Inst->getLabelDefault()); 4744 break;
4522 return; 4745 }
4523 } 4746 }
4524 // OK, we'll be slightly less naive by forcing Src into a physical 4747
4525 // register if there are 2 or more uses. 4748 _br(DefaultLabel);
4526 if (NumCases >= 2) 4749 }
4527 Src0 = legalizeToVar(Src0); 4750
4528 else 4751 template <class Machine>
4529 Src0 = legalize(Src0, Legal_Reg | Legal_Mem);
4530 for (SizeT I = 0; I < NumCases; ++I) {
4531 Constant *Value = Ctx->getConstantInt32(Inst->getValue(I));
4532 _cmp(Src0, Value);
4533 _br(Traits::Cond::Br_e, Inst->getLabel(I));
4534 }
4535
4536 _br(Inst->getLabelDefault());
4537 }
4538
4539 template <class Machine>
4540 void TargetX86Base<Machine>::scalarizeArithmetic(InstArithmetic::OpKind Kind, 4752 void TargetX86Base<Machine>::scalarizeArithmetic(InstArithmetic::OpKind Kind,
4541 Variable *Dest, Operand *Src0, 4753 Variable *Dest, Operand *Src0,
4542 Operand *Src1) { 4754 Operand *Src1) {
4543 assert(isVectorType(Dest->getType())); 4755 assert(isVectorType(Dest->getType()));
4544 Type Ty = Dest->getType(); 4756 Type Ty = Dest->getType();
4545 Type ElementTy = typeElementType(Ty); 4757 Type ElementTy = typeElementType(Ty);
4546 SizeT NumElements = typeNumElements(Ty); 4758 SizeT NumElements = typeNumElements(Ty);
4547 4759
4548 Operand *T = Ctx->getConstantUndef(Ty); 4760 Operand *T = Ctx->getConstantUndef(Ty);
4549 for (SizeT I = 0; I < NumElements; ++I) { 4761 for (SizeT I = 0; I < NumElements; ++I) {
(...skipping 867 matching lines...) Expand 10 before | Expand all | Expand 10 after
5417 } 5629 }
5418 // the offset is not eligible for blinding or pooling, return the original 5630 // the offset is not eligible for blinding or pooling, return the original
5419 // mem operand 5631 // mem operand
5420 return MemOperand; 5632 return MemOperand;
5421 } 5633 }
5422 5634
5423 } // end of namespace X86Internal 5635 } // end of namespace X86Internal
5424 } // end of namespace Ice 5636 } // end of namespace Ice
5425 5637
5426 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H 5638 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698