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

Side by Side Diff: src/IceTargetLoweringX86BaseImpl.h

Issue 1338633005: Subzero: Add a flag to mock up bounds checking on unsafe references. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Fix comment Created 5 years, 3 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
« no previous file with comments | « src/IceTargetLoweringX86Base.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 4048 matching lines...) Expand 10 before | Expand all | Expand 10 after
4059 (void)Offset; // TODO: pattern-match for non-zero offsets. 4059 (void)Offset; // TODO: pattern-match for non-zero offsets.
4060 if (Base == nullptr) 4060 if (Base == nullptr)
4061 return; 4061 return;
4062 // If the Base has more than one use or is live across multiple 4062 // If the Base has more than one use or is live across multiple
4063 // blocks, then don't go further. Alternatively (?), never consider 4063 // blocks, then don't go further. Alternatively (?), never consider
4064 // a transformation that would change a variable that is currently 4064 // a transformation that would change a variable that is currently
4065 // *not* live across basic block boundaries into one that *is*. 4065 // *not* live across basic block boundaries into one that *is*.
4066 if (Func->getVMetadata()->isMultiBlock(Base) /* || Base->getUseCount() > 1*/) 4066 if (Func->getVMetadata()->isMultiBlock(Base) /* || Base->getUseCount() > 1*/)
4067 return; 4067 return;
4068 4068
4069 const bool MockBounds = Func->getContext()->getFlags().getMockBoundsCheck();
4069 const VariablesMetadata *VMetadata = Func->getVMetadata(); 4070 const VariablesMetadata *VMetadata = Func->getVMetadata();
4070 bool Continue = true; 4071 bool Continue = true;
4071 while (Continue) { 4072 while (Continue) {
4072 const Inst *Reason = nullptr; 4073 const Inst *Reason = nullptr;
4073 if (matchTransitiveAssign(VMetadata, Base, Reason) || 4074 if (matchTransitiveAssign(VMetadata, Base, Reason) ||
4074 matchTransitiveAssign(VMetadata, Index, Reason) || 4075 matchTransitiveAssign(VMetadata, Index, Reason) ||
4075 matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason) || 4076 (!MockBounds &&
4076 matchShiftedIndex(VMetadata, Index, Shift, Reason) || 4077 matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason)) ||
4078 (!MockBounds && matchShiftedIndex(VMetadata, Index, Shift, Reason)) ||
4077 matchOffsetBase(VMetadata, Base, Offset, Reason)) { 4079 matchOffsetBase(VMetadata, Base, Offset, Reason)) {
4078 dumpAddressOpt(Func, Base, Index, Shift, Offset, Reason); 4080 dumpAddressOpt(Func, Base, Index, Shift, Offset, Reason);
4079 } else { 4081 } else {
4080 Continue = false; 4082 Continue = false;
4081 } 4083 }
4082 4084
4083 // Index is Index=Var<<Const && Const+Shift<=3 ==> 4085 // Index is Index=Var<<Const && Const+Shift<=3 ==>
4084 // Index=Var, Shift+=Const 4086 // Index=Var, Shift+=Const
4085 4087
4086 // Index is Index=Const*Var && log2(Const)+Shift<=3 ==> 4088 // Index is Index=Const*Var && log2(Const)+Shift<=3 ==>
(...skipping 10 matching lines...) Expand all
4097 // set Index=Var, Offset+=(Const<<Shift) 4099 // set Index=Var, Offset+=(Const<<Shift)
4098 4100
4099 // Index is Index=Var-Const ==> 4101 // Index is Index=Var-Const ==>
4100 // set Index=Var, Offset-=(Const<<Shift) 4102 // set Index=Var, Offset-=(Const<<Shift)
4101 4103
4102 // TODO: consider overflow issues with respect to Offset. 4104 // TODO: consider overflow issues with respect to Offset.
4103 // TODO: handle symbolic constants. 4105 // TODO: handle symbolic constants.
4104 } 4106 }
4105 } 4107 }
4106 4108
4109 /// Add a mock bounds check on the memory address before using it as a load or
4110 /// store operand. The basic idea is that given a memory operand [reg], we
4111 /// would first add bounds-check code something like:
4112 ///
4113 /// cmp reg, <lb>
4114 /// jl out_of_line_error
4115 /// cmp reg, <ub>
4116 /// jg out_of_line_error
4117 ///
4118 /// In reality, the specific code will depend on how <lb> and <ub> are
4119 /// represented, e.g. an immediate, a global, or a function argument.
4120 ///
4121 /// As such, we need to enforce that the memory operand does not have the form
4122 /// [reg1+reg2], because then there is no simple cmp instruction that would
4123 /// suffice. However, we consider [reg+offset] to be OK because the offset is
4124 /// usually small, and so <ub> could have a safety buffer built in and then we
4125 /// could instead branch to a custom out_of_line_error that does the precise
4126 /// check and jumps back if it turns out OK.
4127 ///
4128 /// For the purpose of mocking the bounds check, we'll do something like this:
4129 ///
4130 /// cmp reg, 0
4131 /// je label
4132 /// cmp reg, 1
4133 /// je label
4134 /// label:
4135 ///
4136 /// Also note that we don't need to add a bounds check to a dereference of a
4137 /// simple global variable address.
4138 template <class Machine>
4139 void TargetX86Base<Machine>::doMockBoundsCheck(Operand *Opnd) {
4140 if (!Ctx->getFlags().getMockBoundsCheck())
4141 return;
4142 if (auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Opnd)) {
4143 if (Mem->getIndex()) {
4144 llvm::report_fatal_error("doMockBoundsCheck: Opnd contains index reg");
4145 }
4146 Opnd = Mem->getBase();
4147 }
4148 // At this point Opnd could be nullptr, or Variable, or Constant, or perhaps
4149 // something else. We only care if it is Variable.
4150 auto *Var = llvm::dyn_cast_or_null<Variable>(Opnd);
4151 if (Var == nullptr)
4152 return;
4153 // We use lowerStore() to copy out-args onto the stack. This creates a memory
4154 // operand with the stack pointer as the base register. Don't do bounds
4155 // checks on that.
4156 if (Var->getRegNum() == Traits::RegisterSet::Reg_esp)
4157 return;
4158
4159 typename Traits::Insts::Label *Label =
4160 Traits::Insts::Label::create(Func, this);
4161 _cmp(Opnd, Ctx->getConstantZero(IceType_i32));
4162 _br(Traits::Cond::Br_e, Label);
4163 _cmp(Opnd, Ctx->getConstantInt32(1));
4164 _br(Traits::Cond::Br_e, Label);
4165 Context.insert(Label);
4166 }
4167
4107 template <class Machine> 4168 template <class Machine>
4108 void TargetX86Base<Machine>::lowerLoad(const InstLoad *Load) { 4169 void TargetX86Base<Machine>::lowerLoad(const InstLoad *Load) {
4109 // A Load instruction can be treated the same as an Assign instruction, after 4170 // A Load instruction can be treated the same as an Assign instruction, after
4110 // the source operand is transformed into an Traits::X86OperandMem operand. 4171 // the source operand is transformed into an Traits::X86OperandMem operand.
4111 // Note that the address mode optimization already creates an 4172 // Note that the address mode optimization already creates an
4112 // Traits::X86OperandMem operand, so it doesn't need another level of 4173 // Traits::X86OperandMem operand, so it doesn't need another level of
4113 // transformation. 4174 // transformation.
4114 Variable *DestLoad = Load->getDest(); 4175 Variable *DestLoad = Load->getDest();
4115 Type Ty = DestLoad->getType(); 4176 Type Ty = DestLoad->getType();
4116 Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty); 4177 Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty);
4178 doMockBoundsCheck(Src0);
4117 InstAssign *Assign = InstAssign::create(Func, DestLoad, Src0); 4179 InstAssign *Assign = InstAssign::create(Func, DestLoad, Src0);
4118 lowerAssign(Assign); 4180 lowerAssign(Assign);
4119 } 4181 }
4120 4182
4121 template <class Machine> void TargetX86Base<Machine>::doAddressOptLoad() { 4183 template <class Machine> void TargetX86Base<Machine>::doAddressOptLoad() {
4122 Inst *Inst = Context.getCur(); 4184 Inst *Inst = Context.getCur();
4123 Variable *Dest = Inst->getDest(); 4185 Variable *Dest = Inst->getDest();
4124 Operand *Addr = Inst->getSrc(0); 4186 Operand *Addr = Inst->getSrc(0);
4125 Variable *Index = nullptr; 4187 Variable *Index = nullptr;
4126 uint16_t Shift = 0; 4188 uint16_t Shift = 0;
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
4300 _cmov(T, SrcT, Cond); 4362 _cmov(T, SrcT, Cond);
4301 _mov(Dest, T); 4363 _mov(Dest, T);
4302 } 4364 }
4303 4365
4304 template <class Machine> 4366 template <class Machine>
4305 void TargetX86Base<Machine>::lowerStore(const InstStore *Inst) { 4367 void TargetX86Base<Machine>::lowerStore(const InstStore *Inst) {
4306 Operand *Value = Inst->getData(); 4368 Operand *Value = Inst->getData();
4307 Operand *Addr = Inst->getAddr(); 4369 Operand *Addr = Inst->getAddr();
4308 typename Traits::X86OperandMem *NewAddr = 4370 typename Traits::X86OperandMem *NewAddr =
4309 formMemoryOperand(Addr, Value->getType()); 4371 formMemoryOperand(Addr, Value->getType());
4372 doMockBoundsCheck(NewAddr);
4310 Type Ty = NewAddr->getType(); 4373 Type Ty = NewAddr->getType();
4311 4374
4312 if (!Traits::Is64Bit && Ty == IceType_i64) { 4375 if (!Traits::Is64Bit && Ty == IceType_i64) {
4313 Value = legalizeUndef(Value); 4376 Value = legalizeUndef(Value);
4314 Operand *ValueHi = legalize(hiOperand(Value), Legal_Reg | Legal_Imm); 4377 Operand *ValueHi = legalize(hiOperand(Value), Legal_Reg | Legal_Imm);
4315 Operand *ValueLo = legalize(loOperand(Value), Legal_Reg | Legal_Imm); 4378 Operand *ValueLo = legalize(loOperand(Value), Legal_Reg | Legal_Imm);
4316 _store(ValueHi, 4379 _store(ValueHi,
4317 llvm::cast<typename Traits::X86OperandMem>(hiOperand(NewAddr))); 4380 llvm::cast<typename Traits::X86OperandMem>(hiOperand(NewAddr)));
4318 _store(ValueLo, 4381 _store(ValueLo,
4319 llvm::cast<typename Traits::X86OperandMem>(loOperand(NewAddr))); 4382 llvm::cast<typename Traits::X86OperandMem>(loOperand(NewAddr)));
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
4654 // that follows. This means that the original Store instruction is 4717 // that follows. This means that the original Store instruction is
4655 // still there, either because the value being stored is used beyond 4718 // still there, either because the value being stored is used beyond
4656 // the Store instruction, or because dead code elimination did not 4719 // the Store instruction, or because dead code elimination did not
4657 // happen. In either case, we cancel RMW lowering (and the caller 4720 // happen. In either case, we cancel RMW lowering (and the caller
4658 // deletes the RMW instruction). 4721 // deletes the RMW instruction).
4659 if (!RMW->isLastUse(RMW->getBeacon())) 4722 if (!RMW->isLastUse(RMW->getBeacon()))
4660 return; 4723 return;
4661 Operand *Src = RMW->getData(); 4724 Operand *Src = RMW->getData();
4662 Type Ty = Src->getType(); 4725 Type Ty = Src->getType();
4663 typename Traits::X86OperandMem *Addr = formMemoryOperand(RMW->getAddr(), Ty); 4726 typename Traits::X86OperandMem *Addr = formMemoryOperand(RMW->getAddr(), Ty);
4727 doMockBoundsCheck(Addr);
4664 if (!Traits::Is64Bit && Ty == IceType_i64) { 4728 if (!Traits::Is64Bit && Ty == IceType_i64) {
4665 Src = legalizeUndef(Src); 4729 Src = legalizeUndef(Src);
4666 Operand *SrcLo = legalize(loOperand(Src), Legal_Reg | Legal_Imm); 4730 Operand *SrcLo = legalize(loOperand(Src), Legal_Reg | Legal_Imm);
4667 Operand *SrcHi = legalize(hiOperand(Src), Legal_Reg | Legal_Imm); 4731 Operand *SrcHi = legalize(hiOperand(Src), Legal_Reg | Legal_Imm);
4668 typename Traits::X86OperandMem *AddrLo = 4732 typename Traits::X86OperandMem *AddrLo =
4669 llvm::cast<typename Traits::X86OperandMem>(loOperand(Addr)); 4733 llvm::cast<typename Traits::X86OperandMem>(loOperand(Addr));
4670 typename Traits::X86OperandMem *AddrHi = 4734 typename Traits::X86OperandMem *AddrHi =
4671 llvm::cast<typename Traits::X86OperandMem>(hiOperand(Addr)); 4735 llvm::cast<typename Traits::X86OperandMem>(hiOperand(Addr));
4672 switch (RMW->getOp()) { 4736 switch (RMW->getOp()) {
4673 default: 4737 default:
(...skipping 672 matching lines...) Expand 10 before | Expand all | Expand 10 after
5346 } 5410 }
5347 // the offset is not eligible for blinding or pooling, return the original 5411 // the offset is not eligible for blinding or pooling, return the original
5348 // mem operand 5412 // mem operand
5349 return MemOperand; 5413 return MemOperand;
5350 } 5414 }
5351 5415
5352 } // end of namespace X86Internal 5416 } // end of namespace X86Internal
5353 } // end of namespace Ice 5417 } // end of namespace Ice
5354 5418
5355 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H 5419 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H
OLDNEW
« no previous file with comments | « src/IceTargetLoweringX86Base.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698