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 4048 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |