1 //===- subzero/src/IceTargetLoweringX86Base.h - x86 lowering ----*- C++ -*-===// 2 // 3 // The Subzero Code Generator 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief Declares the TargetLoweringX86 template class, which implements the 12 /// TargetLowering base interface for the x86 architecture. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #ifndef SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H 17 #define SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H 18 19 #include "IceDefs.h" 20 #include "IceInst.h" 21 #include "IceSwitchLowering.h" 22 #include "IceTargetLowering.h" 23 #include "IceTargetLoweringX86RegClass.h" 24 #include "IceUtils.h" 25 26 #include <array> 27 #include <type_traits> 28 #include <utility> 29 30 #ifndef X86NAMESPACE 31 #error "You must define the X86 Target namespace." 32 #endif 33 34 namespace Ice { 35 namespace X86NAMESPACE { 36 37 using namespace ::Ice::X86; 38 39 template <typename Traits> class BoolFolding; 40 41 /// TargetX86Base is a template for all X86 Targets, and it relies on the CRT 42 /// pattern for generating code, delegating to actual backends target-specific 43 /// lowerings (e.g., call, ret, and intrinsics.) Backends are expected to 44 /// implement the following methods (which should be accessible from 45 /// TargetX86Base): 46 /// 47 /// Operand *createNaClReadTPSrcOperand() 48 /// 49 /// Note: Ideally, we should be able to 50 /// 51 /// static_assert(std::is_base_of<TargetX86Base<TraitsType>, 52 /// Machine>::value); 53 /// 54 /// but that does not work: the compiler does not know that Machine inherits 55 /// from TargetX86Base at this point in translation. 56 template <typename TraitsType> class TargetX86Base : public TargetLowering { 57 TargetX86Base() = delete; 58 TargetX86Base(const TargetX86Base &) = delete; 59 TargetX86Base &operator=(const TargetX86Base &) = delete; 60 61 public: 62 using Traits = TraitsType; 63 using ConcreteTarget = typename Traits::ConcreteTarget; 64 using InstructionSetEnum = typename Traits::InstructionSet; 65 66 using BrCond = typename Traits::Cond::BrCond; 67 using CmppsCond = typename Traits::Cond::CmppsCond; 68 69 using X86Address = typename Traits::Address; 70 using X86Operand = typename Traits::X86Operand; 71 using X86OperandMem = typename Traits::X86OperandMem; 72 using SegmentRegisters = typename Traits::X86OperandMem::SegmentRegisters; 73 74 using InstX86Br = typename Traits::Insts::Br; 75 using InstX86FakeRMW = typename Traits::Insts::FakeRMW; 76 using InstX86Label = typename Traits::Insts::Label; 77 78 ~TargetX86Base() override = default; 79 80 static void staticInit(GlobalContext *Ctx); 81 static bool shouldBePooled(const Constant *C); 82 static ::Ice::Type getPointerType(); 83 84 static FixupKind getPcRelFixup() { return PcRelFixup; } 85 static FixupKind getAbsFixup() { return AbsFixup; } 86 87 bool needSandboxing() const { return NeedSandboxing; } 88 89 void translateOm1() override; 90 void translateO2() override; 91 void doLoadOpt(); 92 bool doBranchOpt(Inst *I, const CfgNode *NextNode) override; 93 94 SizeT getNumRegisters() const override { 95 return Traits::RegisterSet::Reg_NUM; 96 } 97 98 Inst *createLoweredMove(Variable *Dest, Variable *SrcVar) override { 99 if (isVectorType(Dest->getType())) { 100 return Traits::Insts::Movp::create(Func, Dest, SrcVar); 101 } 102 return Traits::Insts::Mov::create(Func, Dest, SrcVar); 103 (void)Dest; 104 (void)SrcVar; 105 return nullptr; 106 } 107 108 Variable *getPhysicalRegister(RegNumT RegNum, 109 Type Ty = IceType_void) override; 110 const char *getRegName(RegNumT RegNum, Type Ty) const override; 111 static const char *getRegClassName(RegClass C) { 112 auto ClassNum = static_cast<RegClassX86>(C); 113 assert(ClassNum < RCX86_NUM); 114 switch (ClassNum) { 115 default: 116 assert(C < RC_Target); 117 return regClassString(C); 118 case RCX86_Is64To8: 119 return "i64to8"; // 64-bit GPR truncable to i8 120 case RCX86_Is32To8: 121 return "i32to8"; // 32-bit GPR truncable to i8 122 case RCX86_Is16To8: 123 return "i16to8"; // 16-bit GPR truncable to i8 124 case RCX86_IsTrunc8Rcvr: 125 return "i8from"; // 8-bit GPR truncable from wider GPRs 126 case RCX86_IsAhRcvr: 127 return "i8fromah"; // 8-bit GPR that ah can be assigned to 128 } 129 } 130 SmallBitVector getRegisterSet(RegSetMask Include, 131 RegSetMask Exclude) const override; 132 const SmallBitVector & 133 getRegistersForVariable(const Variable *Var) const override { 134 RegClass RC = Var->getRegClass(); 135 assert(static_cast<RegClassX86>(RC) < RCX86_NUM); 136 return TypeToRegisterSet[RC]; 137 } 138 139 const SmallBitVector & 140 getAllRegistersForVariable(const Variable *Var) const override { 141 RegClass RC = Var->getRegClass(); 142 assert(static_cast<RegClassX86>(RC) < RCX86_NUM); 143 return TypeToRegisterSetUnfiltered[RC]; 144 } 145 146 const SmallBitVector &getAliasesForRegister(RegNumT Reg) const override { 147 Reg.assertIsValid(); 148 return RegisterAliases[Reg]; 149 } 150 151 bool hasFramePointer() const override { return IsEbpBasedFrame; } 152 void setHasFramePointer() override { IsEbpBasedFrame = true; } 153 RegNumT getStackReg() const override { return Traits::StackPtr; } 154 RegNumT getFrameReg() const override { return Traits::FramePtr; } 155 RegNumT getFrameOrStackReg() const override { 156 // If the stack pointer needs to be aligned, then the frame pointer is 157 // unaligned, so always use the stack pointer. 158 if (needsStackPointerAlignment()) 159 return getStackReg(); 160 return IsEbpBasedFrame ? getFrameReg() : getStackReg(); 161 } 162 size_t typeWidthInBytesOnStack(Type Ty) const override { 163 // Round up to the next multiple of WordType bytes. 164 const uint32_t WordSizeInBytes = typeWidthInBytes(Traits::WordType); 165 return Utils::applyAlignment(typeWidthInBytes(Ty), WordSizeInBytes); 166 } 167 uint32_t getStackAlignment() const override { 168 return Traits::X86_STACK_ALIGNMENT_BYTES; 169 } 170 bool needsStackPointerAlignment() const override { 171 // If the ABI's stack alignment is smaller than the vector size (16 bytes), 172 // use the (realigned) stack pointer for addressing any stack variables. 173 return Traits::X86_STACK_ALIGNMENT_BYTES < 16; 174 } 175 void reserveFixedAllocaArea(size_t Size, size_t Align) override { 176 FixedAllocaSizeBytes = Size; 177 assert(llvm::isPowerOf2_32(Align)); 178 FixedAllocaAlignBytes = Align; 179 PrologEmitsFixedAllocas = true; 180 } 181 /// Returns the (negative) offset from ebp/rbp where the fixed Allocas start. 182 int32_t getFrameFixedAllocaOffset() const override { 183 return FixedAllocaSizeBytes - (SpillAreaSizeBytes - maxOutArgsSizeBytes()); 184 } 185 virtual uint32_t maxOutArgsSizeBytes() const override { 186 return MaxOutArgsSizeBytes; 187 } 188 virtual void updateMaxOutArgsSizeBytes(uint32_t Size) { 189 MaxOutArgsSizeBytes = std::max(MaxOutArgsSizeBytes, Size); 190 } 191 192 bool shouldSplitToVariable64On32(Type Ty) const override { 193 return Traits::Is64Bit ? false : Ty == IceType_i64; 194 } 195 196 ConstantRelocatable *createGetIPForRegister(const Variable *Dest) { 197 assert(Dest->hasReg()); 198 const std::string RegName = Traits::getRegName(Dest->getRegNum()); 199 return llvm::cast<ConstantRelocatable>(Ctx->getConstantExternSym( 200 Ctx->getGlobalString(H_getIP_prefix + RegName))); 201 } 202 203 SizeT getMinJumpTableSize() const override { return 4; } 204 205 void emitVariable(const Variable *Var) const override; 206 207 void emit(const ConstantInteger32 *C) const final; 208 void emit(const ConstantInteger64 *C) const final; 209 void emit(const ConstantFloat *C) const final; 210 void emit(const ConstantDouble *C) const final; 211 void emit(const ConstantUndef *C) const final; 212 void emit(const ConstantRelocatable *C) const final; 213 214 void initNodeForLowering(CfgNode *Node) override; 215 216 template <typename T = Traits> 217 typename std::enable_if<!T::Is64Bit, Operand>::type * 218 loOperand(Operand *Operand); 219 template <typename T = Traits> 220 typename std::enable_if<T::Is64Bit, Operand>::type *loOperand(Operand *) { 221 llvm::report_fatal_error( 222 "Hey, yo! This is x86-64. Watcha doin'? (loOperand)"); 223 } 224 225 template <typename T = Traits> 226 typename std::enable_if<!T::Is64Bit, Operand>::type * 227 hiOperand(Operand *Operand); 228 template <typename T = Traits> 229 typename std::enable_if<T::Is64Bit, Operand>::type *hiOperand(Operand *) { 230 llvm::report_fatal_error( 231 "Hey, yo! This is x86-64. Watcha doin'? (hiOperand)"); 232 } 233 234 void addProlog(CfgNode *Node) override; 235 void finishArgumentLowering(Variable *Arg, Variable *FramePtr, 236 size_t BasicFrameOffset, size_t StackAdjBytes, 237 size_t &InArgsSizeBytes); 238 void addEpilog(CfgNode *Node) override; 239 X86Address stackVarToAsmOperand(const Variable *Var) const; 240 241 InstructionSetEnum getInstructionSet() const { return InstructionSet; } 242 Operand *legalizeUndef(Operand *From, RegNumT RegNum = RegNumT()); 243 244 protected: 245 const bool NeedSandboxing; 246 247 explicit TargetX86Base(Cfg *Func); 248 249 void postLower() override; 250 251 /// Initializes the RebasePtr member variable -- if so required by 252 /// SandboxingType for the concrete Target. 253 void initRebasePtr() { 254 assert(SandboxingType != ST_None); 255 dispatchToConcrete(&Traits::ConcreteTarget::initRebasePtr); 256 } 257 258 /// Emit code that initializes the value of the RebasePtr near the start of 259 /// the function -- if so required by SandboxingType for the concrete type. 260 void initSandbox() { 261 assert(SandboxingType != ST_None); 262 dispatchToConcrete(&Traits::ConcreteTarget::initSandbox); 263 } 264 265 void lowerAlloca(const InstAlloca *Instr) override; 266 void lowerArguments() override; 267 void lowerArithmetic(const InstArithmetic *Instr) override; 268 void lowerAssign(const InstAssign *Instr) override; 269 void lowerBr(const InstBr *Instr) override; 270 void lowerBreakpoint(const InstBreakpoint *Instr) override; 271 void lowerCall(const InstCall *Instr) override; 272 void lowerCast(const InstCast *Instr) override; 273 void lowerExtractElement(const InstExtractElement *Instr) override; 274 void lowerFcmp(const InstFcmp *Instr) override; 275 void lowerIcmp(const InstIcmp *Instr) override; 276 277 void lowerIntrinsicCall(const InstIntrinsicCall *Instr) override; 278 void lowerInsertElement(const InstInsertElement *Instr) override; 279 void lowerLoad(const InstLoad *Instr) override; 280 void lowerPhi(const InstPhi *Instr) override; 281 void lowerRet(const InstRet *Instr) override; 282 void lowerSelect(const InstSelect *Instr) override; 283 void lowerShuffleVector(const InstShuffleVector *Instr) override; 284 void lowerStore(const InstStore *Instr) override; 285 void lowerSwitch(const InstSwitch *Instr) override; 286 void lowerUnreachable(const InstUnreachable *Instr) override; 287 void lowerOther(const Inst *Instr) override; 288 void lowerRMW(const InstX86FakeRMW *RMW); 289 void prelowerPhis() override; 290 uint32_t getCallStackArgumentsSizeBytes(const CfgVector<Type> &ArgTypes, 291 Type ReturnType); 292 uint32_t getCallStackArgumentsSizeBytes(const InstCall *Instr) override; 293 void genTargetHelperCallFor(Inst *Instr) override; 294 295 /// OptAddr wraps all the possible operands that an x86 address might have. 296 struct OptAddr { 297 Variable *Base = nullptr; 298 Variable *Index = nullptr; 299 uint16_t Shift = 0; 300 int32_t Offset = 0; 301 ConstantRelocatable *Relocatable = nullptr; 302 }; 303 /// Legalizes Addr w.r.t. SandboxingType. The exact type of legalization 304 /// varies for different <Target, SandboxingType> tuples. 305 bool legalizeOptAddrForSandbox(OptAddr *Addr) { 306 return dispatchToConcrete( 307 &Traits::ConcreteTarget::legalizeOptAddrForSandbox, std::move(Addr)); 308 } 309 // Builds information for a canonical address expresion: 310 // <Relocatable + Offset>(Base, Index, Shift) 311 X86OperandMem *computeAddressOpt(const Inst *Instr, Type MemType, 312 Operand *Addr); 313 void doAddressOptOther() override; 314 void doAddressOptLoad() override; 315 void doAddressOptStore() override; 316 void doAddressOptLoadSubVector() override; 317 void doAddressOptStoreSubVector() override; 318 void doMockBoundsCheck(Operand *Opnd) override; 319 void randomlyInsertNop(float Probability, 320 RandomNumberGenerator &RNG) override; 321 322 /// Naive lowering of cmpxchg. 323 void lowerAtomicCmpxchg(Variable *DestPrev, Operand *Ptr, Operand *Expected, 324 Operand *Desired); 325 /// Attempt a more optimized lowering of cmpxchg. Returns true if optimized. 326 bool tryOptimizedCmpxchgCmpBr(Variable *DestPrev, Operand *Ptr, 327 Operand *Expected, Operand *Desired); 328 void lowerAtomicRMW(Variable *Dest, uint32_t Operation, Operand *Ptr, 329 Operand *Val); 330 void lowerCountZeros(bool Cttz, Type Ty, Variable *Dest, Operand *FirstVal, 331 Operand *SecondVal); 332 /// Load from memory for a given type. 333 void typedLoad(Type Ty, Variable *Dest, Variable *Base, Constant *Offset); 334 /// Store to memory for a given type. 335 void typedStore(Type Ty, Variable *Value, Variable *Base, Constant *Offset); 336 /// Copy memory of given type from Src to Dest using OffsetAmt on both. 337 void copyMemory(Type Ty, Variable *Dest, Variable *Src, int32_t OffsetAmt); 338 /// Replace some calls to memcpy with inline instructions. 339 void lowerMemcpy(Operand *Dest, Operand *Src, Operand *Count); 340 /// Replace some calls to memmove with inline instructions. 341 void lowerMemmove(Operand *Dest, Operand *Src, Operand *Count); 342 /// Replace some calls to memset with inline instructions. 343 void lowerMemset(Operand *Dest, Operand *Val, Operand *Count); 344 345 /// Lower an indirect jump adding sandboxing when needed. 346 void lowerIndirectJump(Variable *JumpTarget) { 347 // Without std::move below, the compiler deduces that the argument to 348 // lowerIndirectJmp is a Variable *&, not a Variable *. 349 dispatchToConcrete(&Traits::ConcreteTarget::lowerIndirectJump, 350 std::move(JumpTarget)); 351 } 352 353 /// Check the comparison is in [Min,Max]. The flags register will be modified 354 /// with: 355 /// - below equal, if in range 356 /// - above, set if not in range 357 /// The index into the range is returned. 358 Operand *lowerCmpRange(Operand *Comparison, uint64_t Min, uint64_t Max); 359 /// Lowering of a cluster of switch cases. If the case is not matched control 360 /// will pass to the default label provided. If the default label is nullptr 361 /// then control will fall through to the next instruction. DoneCmp should be 362 /// true if the flags contain the result of a comparison with the Comparison. 363 void lowerCaseCluster(const CaseCluster &Case, Operand *Src0, bool DoneCmp, 364 CfgNode *DefaultLabel = nullptr); 365 366 using LowerBinOp = void (TargetX86Base::*)(Variable *, Operand *); 367 void expandAtomicRMWAsCmpxchg(LowerBinOp op_lo, LowerBinOp op_hi, 368 Variable *Dest, Operand *Ptr, Operand *Val); 369 370 void eliminateNextVectorSextInstruction(Variable *SignExtendedResult); 371 372 void emitGetIP(CfgNode *Node) { 373 dispatchToConcrete(&Traits::ConcreteTarget::emitGetIP, std::move(Node)); 374 } 375 /// Emit a sandboxed return sequence rather than a return. 376 void emitSandboxedReturn() { 377 dispatchToConcrete(&Traits::ConcreteTarget::emitSandboxedReturn); 378 } 379 /// Emit just the call instruction (without argument or return variable 380 /// processing), sandboxing if needed. 381 virtual Inst *emitCallToTarget(Operand *CallTarget, Variable *ReturnReg) = 0; 382 /// Materialize the moves needed to return a value of the specified type. 383 virtual Variable *moveReturnValueToRegister(Operand *Value, 384 Type ReturnType) = 0; 385 386 /// Emit a jump table to the constant pool. 387 void emitJumpTable(const Cfg *Func, 388 const InstJumpTable *JumpTable) const override; 389 390 /// Emit a fake use of esp to make sure esp stays alive for the entire 391 /// function. Otherwise some esp adjustments get dead-code eliminated. 392 void keepEspLiveAtExit() { 393 Variable *esp = 394 Func->getTarget()->getPhysicalRegister(getStackReg(), Traits::WordType); 395 Context.insert<InstFakeUse>(esp); 396 } 397 398 /// Operand legalization helpers. To deal with address mode constraints, the 399 /// helpers will create a new Operand and emit instructions that guarantee 400 /// that the Operand kind is one of those indicated by the LegalMask (a 401 /// bitmask of allowed kinds). If the input Operand is known to already meet 402 /// the constraints, it may be simply returned as the result, without creating 403 /// any new instructions or operands. 404 enum OperandLegalization { 405 Legal_None = 0, 406 Legal_Reg = 1 << 0, // physical register, not stack location 407 Legal_Imm = 1 << 1, 408 Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12] 409 Legal_Rematerializable = 1 << 3, 410 Legal_AddrAbs = 1 << 4, // ConstantRelocatable doesn't have to add RebasePtr 411 Legal_Default = ~(Legal_Rematerializable | Legal_AddrAbs) 412 // TODO(stichnot): Figure out whether this default works for x86-64. 413 }; 414 using LegalMask = uint32_t; 415 Operand *legalize(Operand *From, LegalMask Allowed = Legal_Default, 416 RegNumT RegNum = RegNumT()); 417 Variable *legalizeToReg(Operand *From, RegNumT RegNum = RegNumT()); 418 /// Legalize the first source operand for use in the cmp instruction. 419 Operand *legalizeSrc0ForCmp(Operand *Src0, Operand *Src1); 420 /// Turn a pointer operand into a memory operand that can be used by a real 421 /// load/store operation. Legalizes the operand as well. This is a nop if the 422 /// operand is already a legal memory operand. 423 X86OperandMem *formMemoryOperand(Operand *Ptr, Type Ty, 424 bool DoLegalize = true); 425 426 Variable *makeReg(Type Ty, RegNumT RegNum = RegNumT()); 427 static Type stackSlotType(); 428 429 static constexpr uint32_t NoSizeLimit = 0; 430 /// Returns the largest type which is equal to or larger than Size bytes. The 431 /// type is suitable for copying memory i.e. a load and store will be a single 432 /// instruction (for example x86 will get f64 not i64). 433 static Type largestTypeInSize(uint32_t Size, uint32_t MaxSize = NoSizeLimit); 434 /// Returns the smallest type which is equal to or larger than Size bytes. If 435 /// one doesn't exist then the largest type smaller than Size bytes is 436 /// returned. The type is suitable for memory copies as described at 437 /// largestTypeInSize. 438 static Type firstTypeThatFitsSize(uint32_t Size, 439 uint32_t MaxSize = NoSizeLimit); 440 441 Variable *copyToReg8(Operand *Src, RegNumT RegNum = RegNumT()); 442 Variable *copyToReg(Operand *Src, RegNumT RegNum = RegNumT()); 443 444 /// Returns a register containing all zeros, without affecting the FLAGS 445 /// register, using the best instruction for the type. 446 Variable *makeZeroedRegister(Type Ty, RegNumT RegNum = RegNumT()); 447 448 /// \name Returns a vector in a register with the given constant entries. 449 /// @{ 450 Variable *makeVectorOfZeros(Type Ty, RegNumT RegNum = RegNumT()); 451 Variable *makeVectorOfOnes(Type Ty, RegNumT RegNum = RegNumT()); 452 Variable *makeVectorOfMinusOnes(Type Ty, RegNumT RegNum = RegNumT()); 453 Variable *makeVectorOfHighOrderBits(Type Ty, RegNumT RegNum = RegNumT()); 454 Variable *makeVectorOfFabsMask(Type Ty, RegNumT RegNum = RegNumT()); 455 /// @} 456 457 /// Return a memory operand corresponding to a stack allocated Variable. 458 X86OperandMem *getMemoryOperandForStackSlot(Type Ty, Variable *Slot, 459 uint32_t Offset = 0); 460 461 void 462 makeRandomRegisterPermutation(llvm::SmallVectorImpl<RegNumT> &Permutation, 463 const SmallBitVector &ExcludeRegisters, 464 uint64_t Salt) const override; 465 466 /// AutoMemorySandboxer emits a bundle-lock/bundle-unlock pair if the 467 /// instruction's operand is a memory reference. This is only needed for 468 /// x86-64 NaCl sandbox. 469 template <InstBundleLock::Option BundleLockOpt = InstBundleLock::Opt_None> 470 class AutoMemorySandboxer { 471 AutoMemorySandboxer() = delete; 472 AutoMemorySandboxer(const AutoMemorySandboxer &) = delete; 473 AutoMemorySandboxer &operator=(const AutoMemorySandboxer &) = delete; 474 475 private: 476 typename Traits::TargetLowering *Target; 477 478 template <typename T, typename... Tail> 479 X86OperandMem **findMemoryReference(T **First, Tail... Others) { 480 if (llvm::isa<X86OperandMem>(*First)) { 481 return reinterpret_cast<X86OperandMem **>(First); 482 } 483 return findMemoryReference(Others...); 484 } 485 486 X86OperandMem **findMemoryReference() { return nullptr; } 487 488 public: 489 AutoBundle *Bundler = nullptr; 490 X86OperandMem **const MemOperand; 491 492 template <typename... T> 493 AutoMemorySandboxer(typename Traits::TargetLowering *Target, T... Args) 494 : Target(Target), MemOperand(Target->SandboxingType == ST_None 495 ? nullptr 496 : findMemoryReference(Args...)) { 497 if (MemOperand != nullptr) { 498 if (Traits::Is64Bit) { 499 Bundler = new (Target->Func->template allocate<AutoBundle>()) 500 AutoBundle(Target, BundleLockOpt); 501 } 502 *MemOperand = Target->_sandbox_mem_reference(*MemOperand); 503 } 504 } 505 506 ~AutoMemorySandboxer() { 507 if (Bundler != nullptr) { 508 Bundler->~AutoBundle(); 509 } 510 } 511 }; 512 513 /// The following are helpers that insert lowered x86 instructions with 514 /// minimal syntactic overhead, so that the lowering code can look as close to 515 /// assembly as practical. 516 void _adc(Variable *Dest, Operand *Src0) { 517 AutoMemorySandboxer<> _(this, &Dest, &Src0); 518 Context.insert<typename Traits::Insts::Adc>(Dest, Src0); 519 } 520 void _adc_rmw(X86OperandMem *DestSrc0, Operand *Src1) { 521 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1); 522 Context.insert<typename Traits::Insts::AdcRMW>(DestSrc0, Src1); 523 } 524 void _add(Variable *Dest, Operand *Src0) { 525 AutoMemorySandboxer<> _(this, &Dest, &Src0); 526 Context.insert<typename Traits::Insts::Add>(Dest, Src0); 527 } 528 void _add_rmw(X86OperandMem *DestSrc0, Operand *Src1) { 529 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1); 530 Context.insert<typename Traits::Insts::AddRMW>(DestSrc0, Src1); 531 } 532 void _addps(Variable *Dest, Operand *Src0) { 533 AutoMemorySandboxer<> _(this, &Dest, &Src0); 534 Context.insert<typename Traits::Insts::Addps>(Dest, Src0); 535 } 536 void _addss(Variable *Dest, Operand *Src0) { 537 AutoMemorySandboxer<> _(this, &Dest, &Src0); 538 Context.insert<typename Traits::Insts::Addss>(Dest, Src0); 539 } 540 void _add_sp(Operand *Adjustment) { 541 dispatchToConcrete(&Traits::ConcreteTarget::_add_sp, std::move(Adjustment)); 542 } 543 void _and(Variable *Dest, Operand *Src0) { 544 AutoMemorySandboxer<> _(this, &Dest, &Src0); 545 Context.insert<typename Traits::Insts::And>(Dest, Src0); 546 } 547 void _andnps(Variable *Dest, Operand *Src0) { 548 AutoMemorySandboxer<> _(this, &Dest, &Src0); 549 Context.insert<typename Traits::Insts::Andnps>(Dest, Src0); 550 } 551 void _andps(Variable *Dest, Operand *Src0) { 552 AutoMemorySandboxer<> _(this, &Dest, &Src0); 553 Context.insert<typename Traits::Insts::Andps>(Dest, Src0); 554 } 555 void _and_rmw(X86OperandMem *DestSrc0, Operand *Src1) { 556 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1); 557 Context.insert<typename Traits::Insts::AndRMW>(DestSrc0, Src1); 558 } 559 void _blendvps(Variable *Dest, Operand *Src0, Operand *Src1) { 560 AutoMemorySandboxer<> _(this, &Dest, &Src0); 561 Context.insert<typename Traits::Insts::Blendvps>(Dest, Src0, Src1); 562 } 563 void _br(BrCond Condition, CfgNode *TargetTrue, CfgNode *TargetFalse) { 564 Context.insert<InstX86Br>(TargetTrue, TargetFalse, Condition, 565 InstX86Br::Far); 566 } 567 void _br(CfgNode *Target) { 568 Context.insert<InstX86Br>(Target, InstX86Br::Far); 569 } 570 void _br(BrCond Condition, CfgNode *Target) { 571 Context.insert<InstX86Br>(Target, Condition, InstX86Br::Far); 572 } 573 void _br(BrCond Condition, InstX86Label *Label, 574 typename InstX86Br::Mode Kind = InstX86Br::Near) { 575 Context.insert<InstX86Br>(Label, Condition, Kind); 576 } 577 void _bsf(Variable *Dest, Operand *Src0) { 578 AutoMemorySandboxer<> _(this, &Dest, &Src0); 579 Context.insert<typename Traits::Insts::Bsf>(Dest, Src0); 580 } 581 void _bsr(Variable *Dest, Operand *Src0) { 582 AutoMemorySandboxer<> _(this, &Dest, &Src0); 583 Context.insert<typename Traits::Insts::Bsr>(Dest, Src0); 584 } 585 void _bswap(Variable *SrcDest) { 586 AutoMemorySandboxer<> _(this, &SrcDest); 587 Context.insert<typename Traits::Insts::Bswap>(SrcDest); 588 } 589 void _cbwdq(Variable *Dest, Operand *Src0) { 590 AutoMemorySandboxer<> _(this, &Dest, &Src0); 591 Context.insert<typename Traits::Insts::Cbwdq>(Dest, Src0); 592 } 593 void _cmov(Variable *Dest, Operand *Src0, BrCond Condition) { 594 AutoMemorySandboxer<> _(this, &Dest, &Src0); 595 Context.insert<typename Traits::Insts::Cmov>(Dest, Src0, Condition); 596 } 597 void _cmp(Operand *Src0, Operand *Src1) { 598 AutoMemorySandboxer<> _(this, &Src0, &Src1); 599 Context.insert<typename Traits::Insts::Icmp>(Src0, Src1); 600 } 601 void _cmpps(Variable *Dest, Operand *Src0, CmppsCond Condition) { 602 AutoMemorySandboxer<> _(this, &Dest, &Src0); 603 Context.insert<typename Traits::Insts::Cmpps>(Dest, Src0, Condition); 604 } 605 void _cmpxchg(Operand *DestOrAddr, Variable *Eax, Variable *Desired, 606 bool Locked) { 607 AutoMemorySandboxer<> _(this, &DestOrAddr); 608 Context.insert<typename Traits::Insts::Cmpxchg>(DestOrAddr, Eax, Desired, 609 Locked); 610 // Mark eax as possibly modified by cmpxchg. 611 Context.insert<InstFakeDef>(Eax, llvm::dyn_cast<Variable>(DestOrAddr)); 612 _set_dest_redefined(); 613 Context.insert<InstFakeUse>(Eax); 614 } 615 void _cmpxchg8b(X86OperandMem *Addr, Variable *Edx, Variable *Eax, 616 Variable *Ecx, Variable *Ebx, bool Locked) { 617 AutoMemorySandboxer<> _(this, &Addr); 618 Context.insert<typename Traits::Insts::Cmpxchg8b>(Addr, Edx, Eax, Ecx, Ebx, 619 Locked); 620 // Mark edx, and eax as possibly modified by cmpxchg8b. 621 Context.insert<InstFakeDef>(Edx); 622 _set_dest_redefined(); 623 Context.insert<InstFakeUse>(Edx); 624 Context.insert<InstFakeDef>(Eax); 625 _set_dest_redefined(); 626 Context.insert<InstFakeUse>(Eax); 627 } 628 void _cvt(Variable *Dest, Operand *Src0, 629 typename Traits::Insts::Cvt::CvtVariant Variant) { 630 AutoMemorySandboxer<> _(this, &Dest, &Src0); 631 Context.insert<typename Traits::Insts::Cvt>(Dest, Src0, Variant); 632 } 633 void _round(Variable *Dest, Operand *Src0, Operand *Imm) { 634 AutoMemorySandboxer<> _(this, &Dest, &Src0); 635 Context.insert<typename Traits::Insts::Round>(Dest, Src0, Imm); 636 } 637 void _div(Variable *Dest, Operand *Src0, Operand *Src1) { 638 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 639 Context.insert<typename Traits::Insts::Div>(Dest, Src0, Src1); 640 } 641 void _divps(Variable *Dest, Operand *Src0) { 642 AutoMemorySandboxer<> _(this, &Dest, &Src0); 643 Context.insert<typename Traits::Insts::Divps>(Dest, Src0); 644 } 645 void _divss(Variable *Dest, Operand *Src0) { 646 AutoMemorySandboxer<> _(this, &Dest, &Src0); 647 Context.insert<typename Traits::Insts::Divss>(Dest, Src0); 648 } 649 template <typename T = Traits> 650 typename std::enable_if<T::UsesX87, void>::type _fld(Operand *Src0) { 651 AutoMemorySandboxer<> _(this, &Src0); 652 Context.insert<typename Traits::Insts::template Fld<>>(Src0); 653 } 654 // TODO(jpp): when implementing the X8664 calling convention, make sure x8664 655 // does not invoke this method, and remove it. 656 template <typename T = Traits> 657 typename std::enable_if<!T::UsesX87, void>::type _fld(Operand *) { 658 llvm::report_fatal_error("fld is not available in x86-64"); 659 } 660 template <typename T = Traits> 661 typename std::enable_if<T::UsesX87, void>::type _fstp(Variable *Dest) { 662 AutoMemorySandboxer<> _(this, &Dest); 663 Context.insert<typename Traits::Insts::template Fstp<>>(Dest); 664 } 665 // TODO(jpp): when implementing the X8664 calling convention, make sure x8664 666 // does not invoke this method, and remove it. 667 template <typename T = Traits> 668 typename std::enable_if<!T::UsesX87, void>::type _fstp(Variable *) { 669 llvm::report_fatal_error("fstp is not available in x86-64"); 670 } 671 void _idiv(Variable *Dest, Operand *Src0, Operand *Src1) { 672 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 673 Context.insert<typename Traits::Insts::Idiv>(Dest, Src0, Src1); 674 } 675 void _imul(Variable *Dest, Operand *Src0) { 676 AutoMemorySandboxer<> _(this, &Dest, &Src0); 677 Context.insert<typename Traits::Insts::Imul>(Dest, Src0); 678 } 679 void _imul_imm(Variable *Dest, Operand *Src0, Constant *Imm) { 680 AutoMemorySandboxer<> _(this, &Dest, &Src0); 681 Context.insert<typename Traits::Insts::ImulImm>(Dest, Src0, Imm); 682 } 683 void _insertps(Variable *Dest, Operand *Src0, Operand *Src1) { 684 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 685 Context.insert<typename Traits::Insts::Insertps>(Dest, Src0, Src1); 686 } 687 void _int3() { Context.insert<typename Traits::Insts::Int3>(); } 688 void _jmp(Operand *Target) { 689 AutoMemorySandboxer<> _(this, &Target); 690 Context.insert<typename Traits::Insts::Jmp>(Target); 691 } 692 void _lea(Variable *Dest, Operand *Src0) { 693 Context.insert<typename Traits::Insts::Lea>(Dest, Src0); 694 } 695 void _link_bp() { dispatchToConcrete(&Traits::ConcreteTarget::_link_bp); } 696 void _push_reg(Variable *Reg) { 697 dispatchToConcrete(&Traits::ConcreteTarget::_push_reg, std::move(Reg)); 698 } 699 void _mfence() { Context.insert<typename Traits::Insts::Mfence>(); } 700 /// Moves can be used to redefine registers, creating "partial kills" for 701 /// liveness. Mark where moves are used in this way. 702 void _redefined(Inst *MovInst, bool IsRedefinition = true) { 703 if (IsRedefinition) 704 MovInst->setDestRedefined(); 705 } 706 /// If Dest=nullptr is passed in, then a new variable is created, marked as 707 /// infinite register allocation weight, and returned through the in/out Dest 708 /// argument. 709 typename Traits::Insts::Mov *_mov(Variable *&Dest, Operand *Src0, 710 RegNumT RegNum = RegNumT()) { 711 if (Dest == nullptr) 712 Dest = makeReg(Src0->getType(), RegNum); 713 AutoMemorySandboxer<> _(this, &Dest, &Src0); 714 return Context.insert<typename Traits::Insts::Mov>(Dest, Src0); 715 } 716 void _mov_sp(Operand *NewValue) { 717 dispatchToConcrete(&Traits::ConcreteTarget::_mov_sp, std::move(NewValue)); 718 } 719 typename Traits::Insts::Movp *_movp(Variable *Dest, Operand *Src0) { 720 AutoMemorySandboxer<> _(this, &Dest, &Src0); 721 return Context.insert<typename Traits::Insts::Movp>(Dest, Src0); 722 } 723 void _movd(Variable *Dest, Operand *Src0) { 724 AutoMemorySandboxer<> _(this, &Dest, &Src0); 725 Context.insert<typename Traits::Insts::Movd>(Dest, Src0); 726 } 727 void _movq(Variable *Dest, Operand *Src0) { 728 AutoMemorySandboxer<> _(this, &Dest, &Src0); 729 Context.insert<typename Traits::Insts::Movq>(Dest, Src0); 730 } 731 void _movss(Variable *Dest, Variable *Src0) { 732 Context.insert<typename Traits::Insts::MovssRegs>(Dest, Src0); 733 } 734 void _movsx(Variable *Dest, Operand *Src0) { 735 AutoMemorySandboxer<> _(this, &Dest, &Src0); 736 Context.insert<typename Traits::Insts::Movsx>(Dest, Src0); 737 } 738 typename Traits::Insts::Movzx *_movzx(Variable *Dest, Operand *Src0) { 739 AutoMemorySandboxer<> _(this, &Dest, &Src0); 740 return Context.insert<typename Traits::Insts::Movzx>(Dest, Src0); 741 } 742 void _maxss(Variable *Dest, Operand *Src0) { 743 AutoMemorySandboxer<> _(this, &Dest, &Src0); 744 Context.insert<typename Traits::Insts::Maxss>(Dest, Src0); 745 } 746 void _minss(Variable *Dest, Operand *Src0) { 747 AutoMemorySandboxer<> _(this, &Dest, &Src0); 748 Context.insert<typename Traits::Insts::Minss>(Dest, Src0); 749 } 750 void _maxps(Variable *Dest, Operand *Src0) { 751 AutoMemorySandboxer<> _(this, &Dest, &Src0); 752 Context.insert<typename Traits::Insts::Maxps>(Dest, Src0); 753 } 754 void _minps(Variable *Dest, Operand *Src0) { 755 AutoMemorySandboxer<> _(this, &Dest, &Src0); 756 Context.insert<typename Traits::Insts::Minps>(Dest, Src0); 757 } 758 void _mul(Variable *Dest, Variable *Src0, Operand *Src1) { 759 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 760 Context.insert<typename Traits::Insts::Mul>(Dest, Src0, Src1); 761 } 762 void _mulps(Variable *Dest, Operand *Src0) { 763 AutoMemorySandboxer<> _(this, &Dest, &Src0); 764 Context.insert<typename Traits::Insts::Mulps>(Dest, Src0); 765 } 766 void _mulss(Variable *Dest, Operand *Src0) { 767 AutoMemorySandboxer<> _(this, &Dest, &Src0); 768 Context.insert<typename Traits::Insts::Mulss>(Dest, Src0); 769 } 770 void _neg(Variable *SrcDest) { 771 AutoMemorySandboxer<> _(this, &SrcDest); 772 Context.insert<typename Traits::Insts::Neg>(SrcDest); 773 } 774 void _nop(SizeT Variant) { 775 Context.insert<typename Traits::Insts::Nop>(Variant); 776 } 777 void _or(Variable *Dest, Operand *Src0) { 778 AutoMemorySandboxer<> _(this, &Dest, &Src0); 779 Context.insert<typename Traits::Insts::Or>(Dest, Src0); 780 } 781 void _orps(Variable *Dest, Operand *Src0) { 782 AutoMemorySandboxer<> _(this, &Dest, &Src0); 783 Context.insert<typename Traits::Insts::Orps>(Dest, Src0); 784 } 785 void _or_rmw(X86OperandMem *DestSrc0, Operand *Src1) { 786 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1); 787 Context.insert<typename Traits::Insts::OrRMW>(DestSrc0, Src1); 788 } 789 void _padd(Variable *Dest, Operand *Src0) { 790 AutoMemorySandboxer<> _(this, &Dest, &Src0); 791 Context.insert<typename Traits::Insts::Padd>(Dest, Src0); 792 } 793 void _padds(Variable *Dest, Operand *Src0) { 794 AutoMemorySandboxer<> _(this, &Dest, &Src0); 795 Context.insert<typename Traits::Insts::Padds>(Dest, Src0); 796 } 797 void _paddus(Variable *Dest, Operand *Src0) { 798 AutoMemorySandboxer<> _(this, &Dest, &Src0); 799 Context.insert<typename Traits::Insts::Paddus>(Dest, Src0); 800 } 801 void _pand(Variable *Dest, Operand *Src0) { 802 AutoMemorySandboxer<> _(this, &Dest, &Src0); 803 Context.insert<typename Traits::Insts::Pand>(Dest, Src0); 804 } 805 void _pandn(Variable *Dest, Operand *Src0) { 806 AutoMemorySandboxer<> _(this, &Dest, &Src0); 807 Context.insert<typename Traits::Insts::Pandn>(Dest, Src0); 808 } 809 void _pblendvb(Variable *Dest, Operand *Src0, Operand *Src1) { 810 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 811 Context.insert<typename Traits::Insts::Pblendvb>(Dest, Src0, Src1); 812 } 813 void _pcmpeq(Variable *Dest, Operand *Src0, 814 Type ArithmeticTypeOverride = IceType_void) { 815 AutoMemorySandboxer<> _(this, &Dest, &Src0); 816 Context.insert<typename Traits::Insts::Pcmpeq>(Dest, Src0, 817 ArithmeticTypeOverride); 818 } 819 void _pcmpgt(Variable *Dest, Operand *Src0) { 820 AutoMemorySandboxer<> _(this, &Dest, &Src0); 821 Context.insert<typename Traits::Insts::Pcmpgt>(Dest, Src0); 822 } 823 void _pextr(Variable *Dest, Operand *Src0, Operand *Src1) { 824 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 825 Context.insert<typename Traits::Insts::Pextr>(Dest, Src0, Src1); 826 } 827 void _pinsr(Variable *Dest, Operand *Src0, Operand *Src1) { 828 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 829 Context.insert<typename Traits::Insts::Pinsr>(Dest, Src0, Src1); 830 } 831 void _pmull(Variable *Dest, Operand *Src0) { 832 AutoMemorySandboxer<> _(this, &Dest, &Src0); 833 Context.insert<typename Traits::Insts::Pmull>(Dest, Src0); 834 } 835 void _pmulhw(Variable *Dest, Operand *Src0) { 836 AutoMemorySandboxer<> _(this, &Dest, &Src0); 837 Context.insert<typename Traits::Insts::Pmulhw>(Dest, Src0); 838 } 839 void _pmulhuw(Variable *Dest, Operand *Src0) { 840 AutoMemorySandboxer<> _(this, &Dest, &Src0); 841 Context.insert<typename Traits::Insts::Pmulhuw>(Dest, Src0); 842 } 843 void _pmaddwd(Variable *Dest, Operand *Src0) { 844 AutoMemorySandboxer<> _(this, &Dest, &Src0); 845 Context.insert<typename Traits::Insts::Pmaddwd>(Dest, Src0); 846 } 847 void _pmuludq(Variable *Dest, Operand *Src0) { 848 AutoMemorySandboxer<> _(this, &Dest, &Src0); 849 Context.insert<typename Traits::Insts::Pmuludq>(Dest, Src0); 850 } 851 void _pop(Variable *Dest) { 852 Context.insert<typename Traits::Insts::Pop>(Dest); 853 } 854 void _por(Variable *Dest, Operand *Src0) { 855 AutoMemorySandboxer<> _(this, &Dest, &Src0); 856 Context.insert<typename Traits::Insts::Por>(Dest, Src0); 857 } 858 void _punpckl(Variable *Dest, Operand *Src0) { 859 AutoMemorySandboxer<> _(this, &Dest, &Src0); 860 Context.insert<typename Traits::Insts::Punpckl>(Dest, Src0); 861 } 862 void _punpckh(Variable *Dest, Operand *Src0) { 863 AutoMemorySandboxer<> _(this, &Dest, &Src0); 864 Context.insert<typename Traits::Insts::Punpckh>(Dest, Src0); 865 } 866 void _packss(Variable *Dest, Operand *Src0) { 867 AutoMemorySandboxer<> _(this, &Dest, &Src0); 868 Context.insert<typename Traits::Insts::Packss>(Dest, Src0); 869 } 870 void _packus(Variable *Dest, Operand *Src0) { 871 AutoMemorySandboxer<> _(this, &Dest, &Src0); 872 Context.insert<typename Traits::Insts::Packus>(Dest, Src0); 873 } 874 void _pshufb(Variable *Dest, Operand *Src0) { 875 AutoMemorySandboxer<> _(this, &Dest, &Src0); 876 Context.insert<typename Traits::Insts::Pshufb>(Dest, Src0); 877 } 878 void _pshufd(Variable *Dest, Operand *Src0, Operand *Src1) { 879 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 880 Context.insert<typename Traits::Insts::Pshufd>(Dest, Src0, Src1); 881 } 882 void _psll(Variable *Dest, Operand *Src0) { 883 AutoMemorySandboxer<> _(this, &Dest, &Src0); 884 Context.insert<typename Traits::Insts::Psll>(Dest, Src0); 885 } 886 void _psra(Variable *Dest, Operand *Src0) { 887 AutoMemorySandboxer<> _(this, &Dest, &Src0); 888 Context.insert<typename Traits::Insts::Psra>(Dest, Src0); 889 } 890 void _psrl(Variable *Dest, Operand *Src0) { 891 AutoMemorySandboxer<> _(this, &Dest, &Src0); 892 Context.insert<typename Traits::Insts::Psrl>(Dest, Src0); 893 } 894 void _psub(Variable *Dest, Operand *Src0) { 895 AutoMemorySandboxer<> _(this, &Dest, &Src0); 896 Context.insert<typename Traits::Insts::Psub>(Dest, Src0); 897 } 898 void _psubs(Variable *Dest, Operand *Src0) { 899 AutoMemorySandboxer<> _(this, &Dest, &Src0); 900 Context.insert<typename Traits::Insts::Psubs>(Dest, Src0); 901 } 902 void _psubus(Variable *Dest, Operand *Src0) { 903 AutoMemorySandboxer<> _(this, &Dest, &Src0); 904 Context.insert<typename Traits::Insts::Psubus>(Dest, Src0); 905 } 906 void _push(Operand *Src0) { 907 Context.insert<typename Traits::Insts::Push>(Src0); 908 } 909 void _pxor(Variable *Dest, Operand *Src0) { 910 AutoMemorySandboxer<> _(this, &Dest, &Src0); 911 Context.insert<typename Traits::Insts::Pxor>(Dest, Src0); 912 } 913 void _ret(Variable *Src0 = nullptr) { 914 Context.insert<typename Traits::Insts::Ret>(Src0); 915 } 916 void _rol(Variable *Dest, Operand *Src0) { 917 AutoMemorySandboxer<> _(this, &Dest, &Src0); 918 Context.insert<typename Traits::Insts::Rol>(Dest, Src0); 919 } 920 void _round(Variable *Dest, Operand *Src, Constant *Imm) { 921 AutoMemorySandboxer<> _(this, &Dest, &Src); 922 Context.insert<typename Traits::Insts::Round>(Dest, Src, Imm); 923 } 924 X86OperandMem *_sandbox_mem_reference(X86OperandMem *Mem) { 925 return dispatchToConcrete(&Traits::ConcreteTarget::_sandbox_mem_reference, 926 std::move(Mem)); 927 } 928 void _sar(Variable *Dest, Operand *Src0) { 929 AutoMemorySandboxer<> _(this, &Dest, &Src0); 930 Context.insert<typename Traits::Insts::Sar>(Dest, Src0); 931 } 932 void _sbb(Variable *Dest, Operand *Src0) { 933 AutoMemorySandboxer<> _(this, &Dest, &Src0); 934 Context.insert<typename Traits::Insts::Sbb>(Dest, Src0); 935 } 936 void _sbb_rmw(X86OperandMem *DestSrc0, Operand *Src1) { 937 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1); 938 Context.insert<typename Traits::Insts::SbbRMW>(DestSrc0, Src1); 939 } 940 void _setcc(Variable *Dest, BrCond Condition) { 941 Context.insert<typename Traits::Insts::Setcc>(Dest, Condition); 942 } 943 void _shl(Variable *Dest, Operand *Src0) { 944 AutoMemorySandboxer<> _(this, &Dest, &Src0); 945 Context.insert<typename Traits::Insts::Shl>(Dest, Src0); 946 } 947 void _shld(Variable *Dest, Variable *Src0, Operand *Src1) { 948 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 949 Context.insert<typename Traits::Insts::Shld>(Dest, Src0, Src1); 950 } 951 void _shr(Variable *Dest, Operand *Src0) { 952 AutoMemorySandboxer<> _(this, &Dest, &Src0); 953 Context.insert<typename Traits::Insts::Shr>(Dest, Src0); 954 } 955 void _shrd(Variable *Dest, Variable *Src0, Operand *Src1) { 956 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 957 Context.insert<typename Traits::Insts::Shrd>(Dest, Src0, Src1); 958 } 959 void _shufps(Variable *Dest, Operand *Src0, Operand *Src1) { 960 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1); 961 Context.insert<typename Traits::Insts::Shufps>(Dest, Src0, Src1); 962 } 963 void _movmsk(Variable *Dest, Operand *Src0) { 964 AutoMemorySandboxer<> _(this, &Dest, &Src0); 965 Context.insert<typename Traits::Insts::Movmsk>(Dest, Src0); 966 } 967 void _sqrt(Variable *Dest, Operand *Src0) { 968 AutoMemorySandboxer<> _(this, &Dest, &Src0); 969 Context.insert<typename Traits::Insts::Sqrt>(Dest, Src0); 970 } 971 void _store(Operand *Value, X86Operand *Mem) { 972 AutoMemorySandboxer<> _(this, &Value, &Mem); 973 Context.insert<typename Traits::Insts::Store>(Value, Mem); 974 } 975 void _storep(Variable *Value, X86OperandMem *Mem) { 976 AutoMemorySandboxer<> _(this, &Value, &Mem); 977 Context.insert<typename Traits::Insts::StoreP>(Value, Mem); 978 } 979 void _storeq(Operand *Value, X86OperandMem *Mem) { 980 AutoMemorySandboxer<> _(this, &Value, &Mem); 981 Context.insert<typename Traits::Insts::StoreQ>(Value, Mem); 982 } 983 void _stored(Operand *Value, X86OperandMem *Mem) { 984 AutoMemorySandboxer<> _(this, &Value, &Mem); 985 Context.insert<typename Traits::Insts::StoreD>(Value, Mem); 986 } 987 void _sub(Variable *Dest, Operand *Src0) { 988 AutoMemorySandboxer<> _(this, &Dest, &Src0); 989 Context.insert<typename Traits::Insts::Sub>(Dest, Src0); 990 } 991 void _sub_rmw(X86OperandMem *DestSrc0, Operand *Src1) { 992 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1); 993 Context.insert<typename Traits::Insts::SubRMW>(DestSrc0, Src1); 994 } 995 void _sub_sp(Operand *Adjustment) { 996 dispatchToConcrete(&Traits::ConcreteTarget::_sub_sp, std::move(Adjustment)); 997 } 998 void _subps(Variable *Dest, Operand *Src0) { 999 AutoMemorySandboxer<> _(this, &Dest, &Src0); 1000 Context.insert<typename Traits::Insts::Subps>(Dest, Src0); 1001 } 1002 void _subss(Variable *Dest, Operand *Src0) { 1003 AutoMemorySandboxer<> _(this, &Dest, &Src0); 1004 Context.insert<typename Traits::Insts::Subss>(Dest, Src0); 1005 } 1006 void _test(Operand *Src0, Operand *Src1) { 1007 AutoMemorySandboxer<> _(this, &Src0, &Src1); 1008 Context.insert<typename Traits::Insts::Test>(Src0, Src1); 1009 } 1010 void _ucomiss(Operand *Src0, Operand *Src1) { 1011 AutoMemorySandboxer<> _(this, &Src0, &Src1); 1012 Context.insert<typename Traits::Insts::Ucomiss>(Src0, Src1); 1013 } 1014 void _ud2() { Context.insert<typename Traits::Insts::UD2>(); } 1015 void _unlink_bp() { dispatchToConcrete(&Traits::ConcreteTarget::_unlink_bp); } 1016 void _xadd(Operand *Dest, Variable *Src, bool Locked) { 1017 AutoMemorySandboxer<> _(this, &Dest, &Src); 1018 Context.insert<typename Traits::Insts::Xadd>(Dest, Src, Locked); 1019 // The xadd exchanges Dest and Src (modifying Src). Model that update with 1020 // a FakeDef followed by a FakeUse. 1021 Context.insert<InstFakeDef>(Src, llvm::dyn_cast<Variable>(Dest)); 1022 _set_dest_redefined(); 1023 Context.insert<InstFakeUse>(Src); 1024 } 1025 void _xchg(Operand *Dest, Variable *Src) { 1026 AutoMemorySandboxer<> _(this, &Dest, &Src); 1027 Context.insert<typename Traits::Insts::Xchg>(Dest, Src); 1028 // The xchg modifies Dest and Src -- model that update with a 1029 // FakeDef/FakeUse. 1030 Context.insert<InstFakeDef>(Src, llvm::dyn_cast<Variable>(Dest)); 1031 _set_dest_redefined(); 1032 Context.insert<InstFakeUse>(Src); 1033 } 1034 void _xor(Variable *Dest, Operand *Src0) { 1035 AutoMemorySandboxer<> _(this, &Dest, &Src0); 1036 Context.insert<typename Traits::Insts::Xor>(Dest, Src0); 1037 } 1038 void _xorps(Variable *Dest, Operand *Src0) { 1039 AutoMemorySandboxer<> _(this, &Dest, &Src0); 1040 Context.insert<typename Traits::Insts::Xorps>(Dest, Src0); 1041 } 1042 void _xor_rmw(X86OperandMem *DestSrc0, Operand *Src1) { 1043 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1); 1044 Context.insert<typename Traits::Insts::XorRMW>(DestSrc0, Src1); 1045 } 1046 1047 void _iaca_start() { 1048 if (!BuildDefs::minimal()) 1049 Context.insert<typename Traits::Insts::IacaStart>(); 1050 } 1051 void _iaca_end() { 1052 if (!BuildDefs::minimal()) 1053 Context.insert<typename Traits::Insts::IacaEnd>(); 1054 } 1055 1056 /// This class helps wrap IACA markers around the code generated by the 1057 /// current scope. It means you don't need to put an end before each return. 1058 class ScopedIacaMark { 1059 ScopedIacaMark(const ScopedIacaMark &) = delete; 1060 ScopedIacaMark &operator=(const ScopedIacaMark &) = delete; 1061 1062 public: 1063 ScopedIacaMark(TargetX86Base *Lowering) : Lowering(Lowering) { 1064 Lowering->_iaca_start(); 1065 } 1066 ~ScopedIacaMark() { end(); } 1067 void end() { 1068 if (!Lowering) 1069 return; 1070 Lowering->_iaca_end(); 1071 Lowering = nullptr; 1072 } 1073 1074 private: 1075 TargetX86Base *Lowering; 1076 }; 1077 1078 bool optimizeScalarMul(Variable *Dest, Operand *Src0, int32_t Src1); 1079 void findRMW(); 1080 1081 InstructionSetEnum InstructionSet = Traits::InstructionSet::Begin; 1082 bool IsEbpBasedFrame = false; 1083 size_t RequiredStackAlignment = sizeof(Traits::WordType); 1084 size_t SpillAreaSizeBytes = 0; 1085 size_t FixedAllocaSizeBytes = 0; 1086 size_t FixedAllocaAlignBytes = 0; 1087 bool PrologEmitsFixedAllocas = false; 1088 uint32_t MaxOutArgsSizeBytes = 0; 1089 static std::array<SmallBitVector, RCX86_NUM> TypeToRegisterSet; 1090 static std::array<SmallBitVector, RCX86_NUM> TypeToRegisterSetUnfiltered; 1091 static std::array<SmallBitVector, Traits::RegisterSet::Reg_NUM> 1092 RegisterAliases; 1093 SmallBitVector RegsUsed; 1094 std::array<VarList, IceType_NUM> PhysicalRegisters; 1095 // RebasePtr is a Variable that holds the Rebasing pointer (if any) for the 1096 // current sandboxing type. 1097 Variable *RebasePtr = nullptr; 1098 1099 /// Randomize a given immediate operand 1100 Operand *randomizeOrPoolImmediate(Constant *Immediate, 1101 RegNumT RegNum = RegNumT()); 1102 X86OperandMem *randomizeOrPoolImmediate(X86OperandMem *MemOperand, 1103 RegNumT RegNum = RegNumT()); 1104 bool RandomizationPoolingPaused = false; 1105 1106 private: 1107 /// dispatchToConcrete is the template voodoo that allows TargetX86Base to 1108 /// invoke methods in Machine (which inherits from TargetX86Base) without 1109 /// having to rely on virtual method calls. There are two overloads, one for 1110 /// non-void types, and one for void types. We need this becase, for non-void 1111 /// types, we need to return the method result, where as for void, we don't. 1112 /// While it is true that the code compiles without the void "version", there 1113 /// used to be a time when compilers would reject such code. 1114 /// 1115 /// This machinery is far from perfect. Note that, in particular, the 1116 /// arguments provided to dispatchToConcrete() need to match the arguments for 1117 /// Method **exactly** (i.e., no argument promotion is performed.) 1118 template <typename Ret, typename... Args> 1119 typename std::enable_if<!std::is_void<Ret>::value, Ret>::type 1120 dispatchToConcrete(Ret (ConcreteTarget::*Method)(Args...), Args &&... args) { 1121 return (static_cast<ConcreteTarget *>(this)->*Method)( 1122 std::forward<Args>(args)...); 1123 } 1124 1125 template <typename... Args> 1126 void dispatchToConcrete(void (ConcreteTarget::*Method)(Args...), 1127 Args &&... args) { 1128 (static_cast<ConcreteTarget *>(this)->*Method)(std::forward<Args>(args)...); 1129 } 1130 1131 void lowerShift64(InstArithmetic::OpKind Op, Operand *Src0Lo, Operand *Src0Hi, 1132 Operand *Src1Lo, Variable *DestLo, Variable *DestHi); 1133 1134 /// Emit the code for a combined operation and consumer instruction, or set 1135 /// the destination variable of the operation if Consumer == nullptr. 1136 void lowerIcmpAndConsumer(const InstIcmp *Icmp, const Inst *Consumer); 1137 void lowerFcmpAndConsumer(const InstFcmp *Fcmp, const Inst *Consumer); 1138 void lowerArithAndConsumer(const InstArithmetic *Arith, const Inst *Consumer); 1139 1140 /// Emit a setcc instruction if Consumer == nullptr; otherwise emit a 1141 /// specialized version of Consumer. 1142 void setccOrConsumer(BrCond Condition, Variable *Dest, const Inst *Consumer); 1143 1144 /// Emit a mov [1|0] instruction if Consumer == nullptr; otherwise emit a 1145 /// specialized version of Consumer. 1146 void movOrConsumer(bool IcmpResult, Variable *Dest, const Inst *Consumer); 1147 1148 /// Emit the code for instructions with a vector type. 1149 void lowerIcmpVector(const InstIcmp *Icmp); 1150 void lowerFcmpVector(const InstFcmp *Icmp); 1151 void lowerSelectVector(const InstSelect *Instr); 1152 1153 /// Helpers for select lowering. 1154 void lowerSelectMove(Variable *Dest, BrCond Cond, Operand *SrcT, 1155 Operand *SrcF); 1156 void lowerSelectIntMove(Variable *Dest, BrCond Cond, Operand *SrcT, 1157 Operand *SrcF); 1158 /// Generic helper to move an arbitrary type from Src to Dest. 1159 void lowerMove(Variable *Dest, Operand *Src, bool IsRedefinition); 1160 1161 /// Optimizations for idiom recognition. 1162 bool lowerOptimizeFcmpSelect(const InstFcmp *Fcmp, const InstSelect *Select); 1163 1164 /// Complains loudly if invoked because the cpu can handle 64-bit types 1165 /// natively. 1166 template <typename T = Traits> 1167 typename std::enable_if<T::Is64Bit, void>::type lowerIcmp64(const InstIcmp *, 1168 const Inst *) { 1169 llvm::report_fatal_error( 1170 "Hey, yo! This is x86-64. Watcha doin'? (lowerIcmp64)"); 1171 } 1172 /// x86lowerIcmp64 handles 64-bit icmp lowering. 1173 template <typename T = Traits> 1174 typename std::enable_if<!T::Is64Bit, void>::type 1175 lowerIcmp64(const InstIcmp *Icmp, const Inst *Consumer); 1176 1177 BoolFolding<Traits> FoldingInfo; 1178 1179 /// Helpers for lowering ShuffleVector 1180 /// @{ 1181 Variable *lowerShuffleVector_AllFromSameSrc(Operand *Src, SizeT Index0, 1182 SizeT Index1, SizeT Index2, 1183 SizeT Index3); 1184 static constexpr SizeT IGNORE_INDEX = 0x80000000u; 1185 Variable *lowerShuffleVector_TwoFromSameSrc(Operand *Src0, SizeT Index0, 1186 SizeT Index1, Operand *Src1, 1187 SizeT Index2, SizeT Index3); 1188 static constexpr SizeT UNIFIED_INDEX_0 = 0; 1189 static constexpr SizeT UNIFIED_INDEX_1 = 2; 1190 Variable *lowerShuffleVector_UnifyFromDifferentSrcs(Operand *Src0, 1191 SizeT Index0, 1192 Operand *Src1, 1193 SizeT Index1); 1194 static constexpr SizeT CLEAR_ALL_BITS = 0x80; 1195 SizeT PshufbMaskCount = 0; 1196 GlobalString lowerShuffleVector_NewMaskName(); 1197 ConstantRelocatable *lowerShuffleVector_CreatePshufbMask( 1198 int8_t Idx0, int8_t Idx1, int8_t Idx2, int8_t Idx3, int8_t Idx4, 1199 int8_t Idx5, int8_t Idx6, int8_t Idx7, int8_t Idx8, int8_t Idx9, 1200 int8_t Idx10, int8_t Idx11, int8_t Idx12, int8_t Idx13, int8_t Idx14, 1201 int8_t Idx15); 1202 void lowerShuffleVector_UsingPshufb(Variable *Dest, Operand *Src0, 1203 Operand *Src1, int8_t Idx0, int8_t Idx1, 1204 int8_t Idx2, int8_t Idx3, int8_t Idx4, 1205 int8_t Idx5, int8_t Idx6, int8_t Idx7, 1206 int8_t Idx8, int8_t Idx9, int8_t Idx10, 1207 int8_t Idx11, int8_t Idx12, int8_t Idx13, 1208 int8_t Idx14, int8_t Idx15); 1209 /// @} 1210 1211 static FixupKind PcRelFixup; 1212 static FixupKind AbsFixup; 1213 }; 1214 1215 template <typename TraitsType> 1216 class TargetDataX86 final : public TargetDataLowering { 1217 using Traits = TraitsType; 1218 TargetDataX86() = delete; 1219 TargetDataX86(const TargetDataX86 &) = delete; 1220 TargetDataX86 &operator=(const TargetDataX86 &) = delete; 1221 1222 public: 1223 ~TargetDataX86() override = default; 1224 1225 static std::unique_ptr<TargetDataLowering> create(GlobalContext *Ctx) { 1226 return makeUnique<TargetDataX86>(Ctx); 1227 } 1228 1229 void lowerGlobals(const VariableDeclarationList &Vars, 1230 const std::string &SectionSuffix) override; 1231 void lowerConstants() override; 1232 void lowerJumpTables() override; 1233 1234 private: 1235 ENABLE_MAKE_UNIQUE; 1236 1237 explicit TargetDataX86(GlobalContext *Ctx) : TargetDataLowering(Ctx){}; 1238 template <typename T> static void emitConstantPool(GlobalContext *Ctx); 1239 }; 1240 1241 class TargetHeaderX86 : public TargetHeaderLowering { 1242 TargetHeaderX86() = delete; 1243 TargetHeaderX86(const TargetHeaderX86 &) = delete; 1244 TargetHeaderX86 &operator=(const TargetHeaderX86 &) = delete; 1245 1246 public: 1247 ~TargetHeaderX86() = default; 1248 1249 static std::unique_ptr<TargetHeaderLowering> create(GlobalContext *Ctx) { 1250 return makeUnique<TargetHeaderX86>(Ctx); 1251 } 1252 1253 private: 1254 ENABLE_MAKE_UNIQUE; 1255 1256 explicit TargetHeaderX86(GlobalContext *Ctx) : TargetHeaderLowering(Ctx) {} 1257 }; 1258 1259 } // end of namespace X86NAMESPACE 1260 } // end of namespace Ice 1261 1262 #include "IceTargetLoweringX86BaseImpl.h" 1263 1264 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H 1265