1 //===- subzero/src/IceTargetLoweringX86Base.h - x86 lowering ----*- C++ -*-===//
3 // The Subzero Code Generator
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief Declares the TargetLoweringX86 template class, which implements the
12 /// TargetLowering base interface for the x86 architecture.
14 //===----------------------------------------------------------------------===//
16 #ifndef SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H
17 #define SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H
21 #include "IceSwitchLowering.h"
22 #include "IceTargetLowering.h"
23 #include "IceTargetLoweringX86RegClass.h"
27 #include <type_traits>
31 #error "You must define the X86 Target namespace."
35 namespace X86NAMESPACE {
37 using namespace ::Ice::X86;
39 template <typename Traits> class BoolFolding;
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
47 /// Operand *createNaClReadTPSrcOperand()
49 /// Note: Ideally, we should be able to
51 /// static_assert(std::is_base_of<TargetX86Base<TraitsType>,
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;
62 using Traits = TraitsType;
63 using ConcreteTarget = typename Traits::ConcreteTarget;
64 using InstructionSetEnum = typename Traits::InstructionSet;
66 using BrCond = typename Traits::Cond::BrCond;
67 using CmppsCond = typename Traits::Cond::CmppsCond;
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 using SpillVariable = typename Traits::SpillVariable;
75 using InstX86Br = typename Traits::Insts::Br;
76 using InstX86FakeRMW = typename Traits::Insts::FakeRMW;
77 using InstX86Label = typename Traits::Insts::Label;
79 ~TargetX86Base() override = default;
81 static void staticInit(GlobalContext *Ctx);
82 static TargetX86Base *create(Cfg *Func) { return new TargetX86Base(Func); }
84 static FixupKind getPcRelFixup() { return PcRelFixup; }
85 static FixupKind getAbsFixup() { return AbsFixup; }
87 bool needSandboxing() const { return NeedSandboxing; }
89 void translateOm1() override;
90 void translateO2() override;
92 bool doBranchOpt(Inst *I, const CfgNode *NextNode) override;
94 SizeT getNumRegisters() const override {
95 return Traits::RegisterSet::Reg_NUM;
97 Variable *getPhysicalRegister(SizeT RegNum, Type Ty = IceType_void) override;
98 IceString getRegName(SizeT RegNum, Type Ty) const override;
99 static IceString getRegClassName(RegClass C) {
100 auto ClassNum = static_cast<RegClassX86>(C);
101 assert(ClassNum < RCX86_NUM);
104 assert(C < RC_Target);
105 return regClassString(C);
107 return "i64to8"; // 64-bit GPR truncable to i8
109 return "i32to8"; // 32-bit GPR truncable to i8
111 return "i16to8"; // 16-bit GPR truncable to i8
112 case RCX86_IsTrunc8Rcvr:
113 return "i8from"; // 8-bit GPR truncable from wider GPRs
115 return "i8fromah"; // 8-bit GPR that ah can be assigned to
118 llvm::SmallBitVector getRegisterSet(RegSetMask Include,
119 RegSetMask Exclude) const override;
120 const llvm::SmallBitVector &
121 getRegistersForVariable(const Variable *Var) const override {
122 RegClass RC = Var->getRegClass();
123 assert(static_cast<RegClassX86>(RC) < RCX86_NUM);
124 return TypeToRegisterSet[RC];
127 const llvm::SmallBitVector &
128 getAllRegistersForVariable(const Variable *Var) const override {
129 RegClass RC = Var->getRegClass();
130 assert(static_cast<RegClassX86>(RC) < RCX86_NUM);
131 return TypeToRegisterSetUnfiltered[RC];
134 const llvm::SmallBitVector &getAliasesForRegister(SizeT Reg) const override {
135 assert(Reg < Traits::RegisterSet::Reg_NUM);
136 return RegisterAliases[Reg];
139 bool hasFramePointer() const override { return IsEbpBasedFrame; }
140 void setHasFramePointer() override { IsEbpBasedFrame = true; }
141 SizeT getStackReg() const override { return Traits::StackPtr; }
142 SizeT getFrameReg() const override { return Traits::FramePtr; }
143 SizeT getFrameOrStackReg() const override {
144 return IsEbpBasedFrame ? getFrameReg() : getStackReg();
146 size_t typeWidthInBytesOnStack(Type Ty) const override {
147 // Round up to the next multiple of WordType bytes.
148 const uint32_t WordSizeInBytes = typeWidthInBytes(Traits::WordType);
149 return Utils::applyAlignment(typeWidthInBytes(Ty), WordSizeInBytes);
151 uint32_t getStackAlignment() const override {
152 return Traits::X86_STACK_ALIGNMENT_BYTES;
154 void reserveFixedAllocaArea(size_t Size, size_t Align) override {
155 FixedAllocaSizeBytes = Size;
156 assert(llvm::isPowerOf2_32(Align));
157 FixedAllocaAlignBytes = Align;
158 PrologEmitsFixedAllocas = true;
160 /// Returns the (negative) offset from ebp/rbp where the fixed Allocas start.
161 int32_t getFrameFixedAllocaOffset() const override {
162 return FixedAllocaSizeBytes - (SpillAreaSizeBytes - maxOutArgsSizeBytes());
164 virtual uint32_t maxOutArgsSizeBytes() const override {
165 return MaxOutArgsSizeBytes;
167 virtual void updateMaxOutArgsSizeBytes(uint32_t Size) {
168 MaxOutArgsSizeBytes = std::max(MaxOutArgsSizeBytes, Size);
171 bool shouldSplitToVariable64On32(Type Ty) const override {
172 return Traits::Is64Bit ? false : Ty == IceType_i64;
175 ConstantRelocatable *createGetIPForRegister(const Variable *Dest) {
176 assert(Dest->hasReg());
177 const IceString RegName = Traits::getRegName(Dest->getRegNum());
178 return llvm::cast<ConstantRelocatable>(
179 Ctx->getConstantExternSym(H_getIP_prefix + RegName));
182 SizeT getMinJumpTableSize() const override { return 4; }
184 void emitVariable(const Variable *Var) const override;
186 void emit(const ConstantInteger32 *C) const final;
187 void emit(const ConstantInteger64 *C) const final;
188 void emit(const ConstantFloat *C) const final;
189 void emit(const ConstantDouble *C) const final;
190 void emit(const ConstantUndef *C) const final;
191 void emit(const ConstantRelocatable *C) const final;
193 void initNodeForLowering(CfgNode *Node) override;
195 template <typename T = Traits>
196 typename std::enable_if<!T::Is64Bit, Operand>::type *
197 loOperand(Operand *Operand);
198 template <typename T = Traits>
199 typename std::enable_if<T::Is64Bit, Operand>::type *loOperand(Operand *) {
200 llvm::report_fatal_error(
201 "Hey, yo! This is x86-64. Watcha doin'? (loOperand)");
204 template <typename T = Traits>
205 typename std::enable_if<!T::Is64Bit, Operand>::type *
206 hiOperand(Operand *Operand);
207 template <typename T = Traits>
208 typename std::enable_if<T::Is64Bit, Operand>::type *hiOperand(Operand *) {
209 llvm::report_fatal_error(
210 "Hey, yo! This is x86-64. Watcha doin'? (hiOperand)");
213 void addProlog(CfgNode *Node) override;
214 void finishArgumentLowering(Variable *Arg, Variable *FramePtr,
215 size_t BasicFrameOffset, size_t StackAdjBytes,
216 size_t &InArgsSizeBytes);
217 void addEpilog(CfgNode *Node) override;
218 X86Address stackVarToAsmOperand(const Variable *Var) const;
220 InstructionSetEnum getInstructionSet() const { return InstructionSet; }
221 Operand *legalizeUndef(Operand *From, int32_t RegNum = Variable::NoRegister);
224 const bool NeedSandboxing;
226 explicit TargetX86Base(Cfg *Func);
228 void postLower() override;
230 /// Initializes the RebasePtr member variable -- if so required by
231 /// SandboxingType for the concrete Target.
232 void initRebasePtr() {
233 assert(SandboxingType != ST_None);
234 dispatchToConcrete(&Traits::ConcreteTarget::initRebasePtr);
237 /// Emit code that initializes the value of the RebasePtr near the start of
238 /// the function -- if so required by SandboxingType for the concrete type.
240 assert(SandboxingType != ST_None);
241 dispatchToConcrete(&Traits::ConcreteTarget::initSandbox);
244 void lowerAlloca(const InstAlloca *Instr) override;
245 void lowerArguments() override;
246 void lowerArithmetic(const InstArithmetic *Instr) override;
247 void lowerAssign(const InstAssign *Instr) override;
248 void lowerBr(const InstBr *Instr) override;
249 void lowerCall(const InstCall *Instr) override;
250 void lowerCast(const InstCast *Instr) override;
251 void lowerExtractElement(const InstExtractElement *Instr) override;
252 void lowerFcmp(const InstFcmp *Instr) override;
253 void lowerIcmp(const InstIcmp *Instr) override;
255 void lowerIntrinsicCall(const InstIntrinsicCall *Instr) override;
256 void lowerInsertElement(const InstInsertElement *Instr) override;
257 void lowerLoad(const InstLoad *Instr) override;
258 void lowerPhi(const InstPhi *Instr) override;
259 void lowerRet(const InstRet *Instr) override;
260 void lowerSelect(const InstSelect *Instr) override;
261 void lowerStore(const InstStore *Instr) override;
262 void lowerSwitch(const InstSwitch *Instr) override;
263 void lowerUnreachable(const InstUnreachable *Instr) override;
264 void lowerOther(const Inst *Instr) override;
265 void lowerRMW(const InstX86FakeRMW *RMW);
266 void prelowerPhis() override;
267 uint32_t getCallStackArgumentsSizeBytes(const std::vector<Type> &ArgTypes,
269 uint32_t getCallStackArgumentsSizeBytes(const InstCall *Instr) override;
270 void genTargetHelperCallFor(Inst *Instr) override;
272 /// OptAddr wraps all the possible operands that an x86 address might have.
274 Variable *Base = nullptr;
275 Variable *Index = nullptr;
278 ConstantRelocatable *Relocatable = nullptr;
280 /// Legalizes Addr w.r.t. SandboxingType. The exact type of legalization
281 /// varies for different <Target, SandboxingType> tuples.
282 bool legalizeOptAddrForSandbox(OptAddr *Addr) {
283 return dispatchToConcrete(
284 &Traits::ConcreteTarget::legalizeOptAddrForSandbox, std::move(Addr));
286 // Builds information for a canonical address expresion:
287 // <Relocatable + Offset>(Base, Index, Shift)
288 X86OperandMem *computeAddressOpt(const Inst *Instr, Type MemType,
290 void doAddressOptLoad() override;
291 void doAddressOptStore() override;
292 void doMockBoundsCheck(Operand *Opnd) override;
293 void randomlyInsertNop(float Probability,
294 RandomNumberGenerator &RNG) override;
296 /// Naive lowering of cmpxchg.
297 void lowerAtomicCmpxchg(Variable *DestPrev, Operand *Ptr, Operand *Expected,
299 /// Attempt a more optimized lowering of cmpxchg. Returns true if optimized.
300 bool tryOptimizedCmpxchgCmpBr(Variable *DestPrev, Operand *Ptr,
301 Operand *Expected, Operand *Desired);
302 void lowerAtomicRMW(Variable *Dest, uint32_t Operation, Operand *Ptr,
304 void lowerCountZeros(bool Cttz, Type Ty, Variable *Dest, Operand *FirstVal,
306 /// Load from memory for a given type.
307 void typedLoad(Type Ty, Variable *Dest, Variable *Base, Constant *Offset);
308 /// Store to memory for a given type.
309 void typedStore(Type Ty, Variable *Value, Variable *Base, Constant *Offset);
310 /// Copy memory of given type from Src to Dest using OffsetAmt on both.
311 void copyMemory(Type Ty, Variable *Dest, Variable *Src, int32_t OffsetAmt);
312 /// Replace some calls to memcpy with inline instructions.
313 void lowerMemcpy(Operand *Dest, Operand *Src, Operand *Count);
314 /// Replace some calls to memmove with inline instructions.
315 void lowerMemmove(Operand *Dest, Operand *Src, Operand *Count);
316 /// Replace some calls to memset with inline instructions.
317 void lowerMemset(Operand *Dest, Operand *Val, Operand *Count);
319 /// Lower an indirect jump adding sandboxing when needed.
320 void lowerIndirectJump(Variable *JumpTarget) {
321 // Without std::move below, the compiler deduces that the argument to
322 // lowerIndirectJmp is a Variable *&, not a Variable *.
323 dispatchToConcrete(&Traits::ConcreteTarget::lowerIndirectJump,
324 std::move(JumpTarget));
327 /// Check the comparison is in [Min,Max]. The flags register will be modified
329 /// - below equal, if in range
330 /// - above, set if not in range
331 /// The index into the range is returned.
332 Operand *lowerCmpRange(Operand *Comparison, uint64_t Min, uint64_t Max);
333 /// Lowering of a cluster of switch cases. If the case is not matched control
334 /// will pass to the default label provided. If the default label is nullptr
335 /// then control will fall through to the next instruction. DoneCmp should be
336 /// true if the flags contain the result of a comparison with the Comparison.
337 void lowerCaseCluster(const CaseCluster &Case, Operand *Src0, bool DoneCmp,
338 CfgNode *DefaultLabel = nullptr);
340 using LowerBinOp = void (TargetX86Base::*)(Variable *, Operand *);
341 void expandAtomicRMWAsCmpxchg(LowerBinOp op_lo, LowerBinOp op_hi,
342 Variable *Dest, Operand *Ptr, Operand *Val);
344 void eliminateNextVectorSextInstruction(Variable *SignExtendedResult);
346 void scalarizeArithmetic(InstArithmetic::OpKind K, Variable *Dest,
347 Operand *Src0, Operand *Src1);
349 void emitGetIP(CfgNode *Node) {
350 dispatchToConcrete(&Traits::ConcreteTarget::emitGetIP, std::move(Node));
352 /// Emit a sandboxed return sequence rather than a return.
353 void emitSandboxedReturn() {
354 dispatchToConcrete(&Traits::ConcreteTarget::emitSandboxedReturn);
356 /// Emit just the call instruction (without argument or return variable
357 /// processing), sandboxing if needed.
358 virtual Inst *emitCallToTarget(Operand *CallTarget, Variable *ReturnReg) = 0;
359 /// Materialize the moves needed to return a value of the specified type.
360 virtual Variable *moveReturnValueToRegister(Operand *Value,
361 Type ReturnType) = 0;
363 /// Emit a jump table to the constant pool.
364 void emitJumpTable(const Cfg *Func,
365 const InstJumpTable *JumpTable) const override;
367 /// Emit a fake use of esp to make sure esp stays alive for the entire
368 /// function. Otherwise some esp adjustments get dead-code eliminated.
369 void keepEspLiveAtExit() {
371 Func->getTarget()->getPhysicalRegister(getStackReg(), Traits::WordType);
372 Context.insert<InstFakeUse>(esp);
375 /// Operand legalization helpers. To deal with address mode constraints, the
376 /// helpers will create a new Operand and emit instructions that guarantee
377 /// that the Operand kind is one of those indicated by the LegalMask (a
378 /// bitmask of allowed kinds). If the input Operand is known to already meet
379 /// the constraints, it may be simply returned as the result, without creating
380 /// any new instructions or operands.
381 enum OperandLegalization {
383 Legal_Reg = 1 << 0, // physical register, not stack location
385 Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12]
386 Legal_Rematerializable = 1 << 3,
387 Legal_AddrAbs = 1 << 4, // ConstantRelocatable doesn't have to add RebasePtr
388 Legal_Default = ~(Legal_Rematerializable | Legal_AddrAbs)
389 // TODO(stichnot): Figure out whether this default works for x86-64.
391 using LegalMask = uint32_t;
392 Operand *legalize(Operand *From, LegalMask Allowed = Legal_Default,
393 int32_t RegNum = Variable::NoRegister);
394 Variable *legalizeToReg(Operand *From, int32_t RegNum = Variable::NoRegister);
395 /// Legalize the first source operand for use in the cmp instruction.
396 Operand *legalizeSrc0ForCmp(Operand *Src0, Operand *Src1);
397 /// Turn a pointer operand into a memory operand that can be used by a real
398 /// load/store operation. Legalizes the operand as well. This is a nop if the
399 /// operand is already a legal memory operand.
400 X86OperandMem *formMemoryOperand(Operand *Ptr, Type Ty,
401 bool DoLegalize = true);
403 Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister);
404 static Type stackSlotType();
406 static constexpr uint32_t NoSizeLimit = 0;
407 static const Type TypeForSize[];
408 /// Returns the largest type which is equal to or larger than Size bytes. The
409 /// type is suitable for copying memory i.e. a load and store will be a single
410 /// instruction (for example x86 will get f64 not i64).
411 static Type largestTypeInSize(uint32_t Size, uint32_t MaxSize = NoSizeLimit);
412 /// Returns the smallest type which is equal to or larger than Size bytes. If
413 /// one doesn't exist then the largest type smaller than Size bytes is
414 /// returned. The type is suitable for memory copies as described at
415 /// largestTypeInSize.
416 static Type firstTypeThatFitsSize(uint32_t Size,
417 uint32_t MaxSize = NoSizeLimit);
419 Variable *copyToReg8(Operand *Src, int32_t RegNum = Variable::NoRegister);
420 Variable *copyToReg(Operand *Src, int32_t RegNum = Variable::NoRegister);
422 /// Returns a register containing all zeros, without affecting the FLAGS
423 /// register, using the best instruction for the type.
424 Variable *makeZeroedRegister(Type Ty, int32_t RegNum = Variable::NoRegister);
426 /// \name Returns a vector in a register with the given constant entries.
428 Variable *makeVectorOfZeros(Type Ty, int32_t RegNum = Variable::NoRegister);
429 Variable *makeVectorOfOnes(Type Ty, int32_t RegNum = Variable::NoRegister);
430 Variable *makeVectorOfMinusOnes(Type Ty,
431 int32_t RegNum = Variable::NoRegister);
432 Variable *makeVectorOfHighOrderBits(Type Ty,
433 int32_t RegNum = Variable::NoRegister);
434 Variable *makeVectorOfFabsMask(Type Ty,
435 int32_t RegNum = Variable::NoRegister);
438 /// Return a memory operand corresponding to a stack allocated Variable.
439 X86OperandMem *getMemoryOperandForStackSlot(Type Ty, Variable *Slot,
440 uint32_t Offset = 0);
443 makeRandomRegisterPermutation(llvm::SmallVectorImpl<int32_t> &Permutation,
444 const llvm::SmallBitVector &ExcludeRegisters,
445 uint64_t Salt) const override;
447 /// AutoMemorySandboxer emits a bundle-lock/bundle-unlock pair if the
448 /// instruction's operand is a memory reference. This is only needed for
449 /// x86-64 NaCl sandbox.
450 template <InstBundleLock::Option BundleLockOpt = InstBundleLock::Opt_None>
451 class AutoMemorySandboxer {
452 AutoMemorySandboxer() = delete;
453 AutoMemorySandboxer(const AutoMemorySandboxer &) = delete;
454 AutoMemorySandboxer &operator=(const AutoMemorySandboxer &) = delete;
457 typename Traits::TargetLowering *Target;
459 template <typename T, typename... Tail>
460 X86OperandMem **findMemoryReference(T **First, Tail... Others) {
461 if (llvm::isa<X86OperandMem>(*First)) {
462 return reinterpret_cast<X86OperandMem **>(First);
464 return findMemoryReference(Others...);
467 X86OperandMem **findMemoryReference() { return nullptr; }
470 std::unique_ptr<AutoBundle> Bundler;
471 X86OperandMem **const MemOperand;
473 template <typename... T>
474 AutoMemorySandboxer(typename Traits::TargetLowering *Target, T... Args)
475 : Target(Target), MemOperand(Target->SandboxingType == ST_None
477 : findMemoryReference(Args...)) {
478 if (MemOperand != nullptr) {
479 if (Traits::Is64Bit) {
480 Bundler = makeUnique<AutoBundle>(Target, BundleLockOpt);
482 *MemOperand = Target->_sandbox_mem_reference(*MemOperand);
486 ~AutoMemorySandboxer() {}
489 /// The following are helpers that insert lowered x86 instructions with
490 /// minimal syntactic overhead, so that the lowering code can look as close to
491 /// assembly as practical.
492 void _adc(Variable *Dest, Operand *Src0) {
493 AutoMemorySandboxer<> _(this, &Dest, &Src0);
494 Context.insert<typename Traits::Insts::Adc>(Dest, Src0);
496 void _adc_rmw(X86OperandMem *DestSrc0, Operand *Src1) {
497 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1);
498 Context.insert<typename Traits::Insts::AdcRMW>(DestSrc0, Src1);
500 void _add(Variable *Dest, Operand *Src0) {
501 AutoMemorySandboxer<> _(this, &Dest, &Src0);
502 Context.insert<typename Traits::Insts::Add>(Dest, Src0);
504 void _add_rmw(X86OperandMem *DestSrc0, Operand *Src1) {
505 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1);
506 Context.insert<typename Traits::Insts::AddRMW>(DestSrc0, Src1);
508 void _addps(Variable *Dest, Operand *Src0) {
509 AutoMemorySandboxer<> _(this, &Dest, &Src0);
510 Context.insert<typename Traits::Insts::Addps>(Dest, Src0);
512 void _addss(Variable *Dest, Operand *Src0) {
513 AutoMemorySandboxer<> _(this, &Dest, &Src0);
514 Context.insert<typename Traits::Insts::Addss>(Dest, Src0);
516 void _add_sp(Operand *Adjustment) {
517 dispatchToConcrete(&Traits::ConcreteTarget::_add_sp, std::move(Adjustment));
519 void _and(Variable *Dest, Operand *Src0) {
520 AutoMemorySandboxer<> _(this, &Dest, &Src0);
521 Context.insert<typename Traits::Insts::And>(Dest, Src0);
523 void _andnps(Variable *Dest, Operand *Src0) {
524 AutoMemorySandboxer<> _(this, &Dest, &Src0);
525 Context.insert<typename Traits::Insts::Andnps>(Dest, Src0);
527 void _andps(Variable *Dest, Operand *Src0) {
528 AutoMemorySandboxer<> _(this, &Dest, &Src0);
529 Context.insert<typename Traits::Insts::Andps>(Dest, Src0);
531 void _and_rmw(X86OperandMem *DestSrc0, Operand *Src1) {
532 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1);
533 Context.insert<typename Traits::Insts::AndRMW>(DestSrc0, Src1);
535 void _blendvps(Variable *Dest, Operand *Src0, Operand *Src1) {
536 AutoMemorySandboxer<> _(this, &Dest, &Src0);
537 Context.insert<typename Traits::Insts::Blendvps>(Dest, Src0, Src1);
539 void _br(BrCond Condition, CfgNode *TargetTrue, CfgNode *TargetFalse) {
540 Context.insert<InstX86Br>(TargetTrue, TargetFalse, Condition,
543 void _br(CfgNode *Target) {
544 Context.insert<InstX86Br>(Target, InstX86Br::Far);
546 void _br(BrCond Condition, CfgNode *Target) {
547 Context.insert<InstX86Br>(Target, Condition, InstX86Br::Far);
549 void _br(BrCond Condition, InstX86Label *Label,
550 typename InstX86Br::Mode Kind = InstX86Br::Near) {
551 Context.insert<InstX86Br>(Label, Condition, Kind);
553 void _bsf(Variable *Dest, Operand *Src0) {
554 AutoMemorySandboxer<> _(this, &Dest, &Src0);
555 Context.insert<typename Traits::Insts::Bsf>(Dest, Src0);
557 void _bsr(Variable *Dest, Operand *Src0) {
558 AutoMemorySandboxer<> _(this, &Dest, &Src0);
559 Context.insert<typename Traits::Insts::Bsr>(Dest, Src0);
561 void _bswap(Variable *SrcDest) {
562 AutoMemorySandboxer<> _(this, &SrcDest);
563 Context.insert<typename Traits::Insts::Bswap>(SrcDest);
565 void _cbwdq(Variable *Dest, Operand *Src0) {
566 AutoMemorySandboxer<> _(this, &Dest, &Src0);
567 Context.insert<typename Traits::Insts::Cbwdq>(Dest, Src0);
569 void _cmov(Variable *Dest, Operand *Src0, BrCond Condition) {
570 AutoMemorySandboxer<> _(this, &Dest, &Src0);
571 Context.insert<typename Traits::Insts::Cmov>(Dest, Src0, Condition);
573 void _cmp(Operand *Src0, Operand *Src1) {
574 AutoMemorySandboxer<> _(this, &Src0, &Src1);
575 Context.insert<typename Traits::Insts::Icmp>(Src0, Src1);
577 void _cmpps(Variable *Dest, Operand *Src0, CmppsCond Condition) {
578 AutoMemorySandboxer<> _(this, &Dest, &Src0);
579 Context.insert<typename Traits::Insts::Cmpps>(Dest, Src0, Condition);
581 void _cmpxchg(Operand *DestOrAddr, Variable *Eax, Variable *Desired,
583 AutoMemorySandboxer<> _(this, &DestOrAddr);
584 Context.insert<typename Traits::Insts::Cmpxchg>(DestOrAddr, Eax, Desired,
586 // Mark eax as possibly modified by cmpxchg.
587 Context.insert<InstFakeDef>(Eax, llvm::dyn_cast<Variable>(DestOrAddr));
588 _set_dest_redefined();
589 Context.insert<InstFakeUse>(Eax);
591 void _cmpxchg8b(X86OperandMem *Addr, Variable *Edx, Variable *Eax,
592 Variable *Ecx, Variable *Ebx, bool Locked) {
593 AutoMemorySandboxer<> _(this, &Addr);
594 Context.insert<typename Traits::Insts::Cmpxchg8b>(Addr, Edx, Eax, Ecx, Ebx,
596 // Mark edx, and eax as possibly modified by cmpxchg8b.
597 Context.insert<InstFakeDef>(Edx);
598 _set_dest_redefined();
599 Context.insert<InstFakeUse>(Edx);
600 Context.insert<InstFakeDef>(Eax);
601 _set_dest_redefined();
602 Context.insert<InstFakeUse>(Eax);
604 void _cvt(Variable *Dest, Operand *Src0,
605 typename Traits::Insts::Cvt::CvtVariant Variant) {
606 AutoMemorySandboxer<> _(this, &Dest, &Src0);
607 Context.insert<typename Traits::Insts::Cvt>(Dest, Src0, Variant);
609 void _div(Variable *Dest, Operand *Src0, Operand *Src1) {
610 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
611 Context.insert<typename Traits::Insts::Div>(Dest, Src0, Src1);
613 void _divps(Variable *Dest, Operand *Src0) {
614 AutoMemorySandboxer<> _(this, &Dest, &Src0);
615 Context.insert<typename Traits::Insts::Divps>(Dest, Src0);
617 void _divss(Variable *Dest, Operand *Src0) {
618 AutoMemorySandboxer<> _(this, &Dest, &Src0);
619 Context.insert<typename Traits::Insts::Divss>(Dest, Src0);
621 template <typename T = Traits>
622 typename std::enable_if<T::UsesX87, void>::type _fld(Operand *Src0) {
623 AutoMemorySandboxer<> _(this, &Src0);
624 Context.insert<typename Traits::Insts::template Fld<>>(Src0);
626 // TODO(jpp): when implementing the X8664 calling convention, make sure x8664
627 // does not invoke this method, and remove it.
628 template <typename T = Traits>
629 typename std::enable_if<!T::UsesX87, void>::type _fld(Operand *) {
630 llvm::report_fatal_error("fld is not available in x86-64");
632 template <typename T = Traits>
633 typename std::enable_if<T::UsesX87, void>::type _fstp(Variable *Dest) {
634 AutoMemorySandboxer<> _(this, &Dest);
635 Context.insert<typename Traits::Insts::template Fstp<>>(Dest);
637 // TODO(jpp): when implementing the X8664 calling convention, make sure x8664
638 // does not invoke this method, and remove it.
639 template <typename T = Traits>
640 typename std::enable_if<!T::UsesX87, void>::type _fstp(Variable *) {
641 llvm::report_fatal_error("fstp is not available in x86-64");
643 void _idiv(Variable *Dest, Operand *Src0, Operand *Src1) {
644 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
645 Context.insert<typename Traits::Insts::Idiv>(Dest, Src0, Src1);
647 void _imul(Variable *Dest, Operand *Src0) {
648 AutoMemorySandboxer<> _(this, &Dest, &Src0);
649 Context.insert<typename Traits::Insts::Imul>(Dest, Src0);
651 void _imul_imm(Variable *Dest, Operand *Src0, Constant *Imm) {
652 AutoMemorySandboxer<> _(this, &Dest, &Src0);
653 Context.insert<typename Traits::Insts::ImulImm>(Dest, Src0, Imm);
655 void _insertps(Variable *Dest, Operand *Src0, Operand *Src1) {
656 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
657 Context.insert<typename Traits::Insts::Insertps>(Dest, Src0, Src1);
659 void _jmp(Operand *Target) {
660 AutoMemorySandboxer<> _(this, &Target);
661 Context.insert<typename Traits::Insts::Jmp>(Target);
663 void _lea(Variable *Dest, Operand *Src0) {
664 Context.insert<typename Traits::Insts::Lea>(Dest, Src0);
666 void _link_bp() { dispatchToConcrete(&Traits::ConcreteTarget::_link_bp); }
667 void _push_reg(Variable *Reg) {
668 dispatchToConcrete(&Traits::ConcreteTarget::_push_reg, std::move(Reg));
670 void _mfence() { Context.insert<typename Traits::Insts::Mfence>(); }
671 /// Moves can be used to redefine registers, creating "partial kills" for
672 /// liveness. Mark where moves are used in this way.
673 void _redefined(Inst *MovInst, bool IsRedefinition = true) {
675 MovInst->setDestRedefined();
677 /// If Dest=nullptr is passed in, then a new variable is created, marked as
678 /// infinite register allocation weight, and returned through the in/out Dest
680 typename Traits::Insts::Mov *_mov(Variable *&Dest, Operand *Src0,
681 int32_t RegNum = Variable::NoRegister) {
683 Dest = makeReg(Src0->getType(), RegNum);
684 AutoMemorySandboxer<> _(this, &Dest, &Src0);
685 return Context.insert<typename Traits::Insts::Mov>(Dest, Src0);
687 void _mov_sp(Operand *NewValue) {
688 dispatchToConcrete(&Traits::ConcreteTarget::_mov_sp, std::move(NewValue));
690 typename Traits::Insts::Movp *_movp(Variable *Dest, Operand *Src0) {
691 AutoMemorySandboxer<> _(this, &Dest, &Src0);
692 return Context.insert<typename Traits::Insts::Movp>(Dest, Src0);
694 void _movd(Variable *Dest, Operand *Src0) {
695 AutoMemorySandboxer<> _(this, &Dest, &Src0);
696 Context.insert<typename Traits::Insts::Movd>(Dest, Src0);
698 void _movq(Variable *Dest, Operand *Src0) {
699 AutoMemorySandboxer<> _(this, &Dest, &Src0);
700 Context.insert<typename Traits::Insts::Movq>(Dest, Src0);
702 void _movss(Variable *Dest, Variable *Src0) {
703 Context.insert<typename Traits::Insts::MovssRegs>(Dest, Src0);
705 void _movsx(Variable *Dest, Operand *Src0) {
706 AutoMemorySandboxer<> _(this, &Dest, &Src0);
707 Context.insert<typename Traits::Insts::Movsx>(Dest, Src0);
709 typename Traits::Insts::Movzx *_movzx(Variable *Dest, Operand *Src0) {
710 AutoMemorySandboxer<> _(this, &Dest, &Src0);
711 return Context.insert<typename Traits::Insts::Movzx>(Dest, Src0);
713 void _maxss(Variable *Dest, Operand *Src0) {
714 AutoMemorySandboxer<> _(this, &Dest, &Src0);
715 Context.insert<typename Traits::Insts::Maxss>(Dest, Src0);
717 void _minss(Variable *Dest, Operand *Src0) {
718 AutoMemorySandboxer<> _(this, &Dest, &Src0);
719 Context.insert<typename Traits::Insts::Minss>(Dest, Src0);
721 void _mul(Variable *Dest, Variable *Src0, Operand *Src1) {
722 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
723 Context.insert<typename Traits::Insts::Mul>(Dest, Src0, Src1);
725 void _mulps(Variable *Dest, Operand *Src0) {
726 AutoMemorySandboxer<> _(this, &Dest, &Src0);
727 Context.insert<typename Traits::Insts::Mulps>(Dest, Src0);
729 void _mulss(Variable *Dest, Operand *Src0) {
730 AutoMemorySandboxer<> _(this, &Dest, &Src0);
731 Context.insert<typename Traits::Insts::Mulss>(Dest, Src0);
733 void _neg(Variable *SrcDest) {
734 AutoMemorySandboxer<> _(this, &SrcDest);
735 Context.insert<typename Traits::Insts::Neg>(SrcDest);
737 void _nop(SizeT Variant) {
738 Context.insert<typename Traits::Insts::Nop>(Variant);
740 void _or(Variable *Dest, Operand *Src0) {
741 AutoMemorySandboxer<> _(this, &Dest, &Src0);
742 Context.insert<typename Traits::Insts::Or>(Dest, Src0);
744 void _orps(Variable *Dest, Operand *Src0) {
745 AutoMemorySandboxer<> _(this, &Dest, &Src0);
746 Context.insert<typename Traits::Insts::Orps>(Dest, Src0);
748 void _or_rmw(X86OperandMem *DestSrc0, Operand *Src1) {
749 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1);
750 Context.insert<typename Traits::Insts::OrRMW>(DestSrc0, Src1);
752 void _padd(Variable *Dest, Operand *Src0) {
753 AutoMemorySandboxer<> _(this, &Dest, &Src0);
754 Context.insert<typename Traits::Insts::Padd>(Dest, Src0);
756 void _pand(Variable *Dest, Operand *Src0) {
757 AutoMemorySandboxer<> _(this, &Dest, &Src0);
758 Context.insert<typename Traits::Insts::Pand>(Dest, Src0);
760 void _pandn(Variable *Dest, Operand *Src0) {
761 AutoMemorySandboxer<> _(this, &Dest, &Src0);
762 Context.insert<typename Traits::Insts::Pandn>(Dest, Src0);
764 void _pblendvb(Variable *Dest, Operand *Src0, Operand *Src1) {
765 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
766 Context.insert<typename Traits::Insts::Pblendvb>(Dest, Src0, Src1);
768 void _pcmpeq(Variable *Dest, Operand *Src0,
769 Type ArithmeticTypeOverride = IceType_void) {
770 AutoMemorySandboxer<> _(this, &Dest, &Src0);
771 Context.insert<typename Traits::Insts::Pcmpeq>(Dest, Src0,
772 ArithmeticTypeOverride);
774 void _pcmpgt(Variable *Dest, Operand *Src0) {
775 AutoMemorySandboxer<> _(this, &Dest, &Src0);
776 Context.insert<typename Traits::Insts::Pcmpgt>(Dest, Src0);
778 void _pextr(Variable *Dest, Operand *Src0, Operand *Src1) {
779 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
780 Context.insert<typename Traits::Insts::Pextr>(Dest, Src0, Src1);
782 void _pinsr(Variable *Dest, Operand *Src0, Operand *Src1) {
783 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
784 Context.insert<typename Traits::Insts::Pinsr>(Dest, Src0, Src1);
786 void _pmull(Variable *Dest, Operand *Src0) {
787 AutoMemorySandboxer<> _(this, &Dest, &Src0);
788 Context.insert<typename Traits::Insts::Pmull>(Dest, Src0);
790 void _pmuludq(Variable *Dest, Operand *Src0) {
791 AutoMemorySandboxer<> _(this, &Dest, &Src0);
792 Context.insert<typename Traits::Insts::Pmuludq>(Dest, Src0);
794 void _pop(Variable *Dest) {
795 Context.insert<typename Traits::Insts::Pop>(Dest);
797 void _por(Variable *Dest, Operand *Src0) {
798 AutoMemorySandboxer<> _(this, &Dest, &Src0);
799 Context.insert<typename Traits::Insts::Por>(Dest, Src0);
801 void _pshufd(Variable *Dest, Operand *Src0, Operand *Src1) {
802 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
803 Context.insert<typename Traits::Insts::Pshufd>(Dest, Src0, Src1);
805 void _psll(Variable *Dest, Operand *Src0) {
806 AutoMemorySandboxer<> _(this, &Dest, &Src0);
807 Context.insert<typename Traits::Insts::Psll>(Dest, Src0);
809 void _psra(Variable *Dest, Operand *Src0) {
810 AutoMemorySandboxer<> _(this, &Dest, &Src0);
811 Context.insert<typename Traits::Insts::Psra>(Dest, Src0);
813 void _psrl(Variable *Dest, Operand *Src0) {
814 AutoMemorySandboxer<> _(this, &Dest, &Src0);
815 Context.insert<typename Traits::Insts::Psrl>(Dest, Src0);
817 void _psub(Variable *Dest, Operand *Src0) {
818 AutoMemorySandboxer<> _(this, &Dest, &Src0);
819 Context.insert<typename Traits::Insts::Psub>(Dest, Src0);
821 void _push(Operand *Src0) {
822 Context.insert<typename Traits::Insts::Push>(Src0);
824 void _pxor(Variable *Dest, Operand *Src0) {
825 AutoMemorySandboxer<> _(this, &Dest, &Src0);
826 Context.insert<typename Traits::Insts::Pxor>(Dest, Src0);
828 void _ret(Variable *Src0 = nullptr) {
829 Context.insert<typename Traits::Insts::Ret>(Src0);
831 void _rol(Variable *Dest, Operand *Src0) {
832 AutoMemorySandboxer<> _(this, &Dest, &Src0);
833 Context.insert<typename Traits::Insts::Rol>(Dest, Src0);
835 X86OperandMem *_sandbox_mem_reference(X86OperandMem *Mem) {
836 return dispatchToConcrete(&Traits::ConcreteTarget::_sandbox_mem_reference,
839 void _sar(Variable *Dest, Operand *Src0) {
840 AutoMemorySandboxer<> _(this, &Dest, &Src0);
841 Context.insert<typename Traits::Insts::Sar>(Dest, Src0);
843 void _sbb(Variable *Dest, Operand *Src0) {
844 AutoMemorySandboxer<> _(this, &Dest, &Src0);
845 Context.insert<typename Traits::Insts::Sbb>(Dest, Src0);
847 void _sbb_rmw(X86OperandMem *DestSrc0, Operand *Src1) {
848 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1);
849 Context.insert<typename Traits::Insts::SbbRMW>(DestSrc0, Src1);
851 void _setcc(Variable *Dest, BrCond Condition) {
852 Context.insert<typename Traits::Insts::Setcc>(Dest, Condition);
854 void _shl(Variable *Dest, Operand *Src0) {
855 AutoMemorySandboxer<> _(this, &Dest, &Src0);
856 Context.insert<typename Traits::Insts::Shl>(Dest, Src0);
858 void _shld(Variable *Dest, Variable *Src0, Operand *Src1) {
859 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
860 Context.insert<typename Traits::Insts::Shld>(Dest, Src0, Src1);
862 void _shr(Variable *Dest, Operand *Src0) {
863 AutoMemorySandboxer<> _(this, &Dest, &Src0);
864 Context.insert<typename Traits::Insts::Shr>(Dest, Src0);
866 void _shrd(Variable *Dest, Variable *Src0, Operand *Src1) {
867 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
868 Context.insert<typename Traits::Insts::Shrd>(Dest, Src0, Src1);
870 void _shufps(Variable *Dest, Operand *Src0, Operand *Src1) {
871 AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
872 Context.insert<typename Traits::Insts::Shufps>(Dest, Src0, Src1);
874 void _sqrtss(Variable *Dest, Operand *Src0) {
875 AutoMemorySandboxer<> _(this, &Dest, &Src0);
876 Context.insert<typename Traits::Insts::Sqrtss>(Dest, Src0);
878 void _store(Operand *Value, X86Operand *Mem) {
879 AutoMemorySandboxer<> _(this, &Value, &Mem);
880 Context.insert<typename Traits::Insts::Store>(Value, Mem);
882 void _storep(Variable *Value, X86OperandMem *Mem) {
883 AutoMemorySandboxer<> _(this, &Value, &Mem);
884 Context.insert<typename Traits::Insts::StoreP>(Value, Mem);
886 void _storeq(Variable *Value, X86OperandMem *Mem) {
887 AutoMemorySandboxer<> _(this, &Value, &Mem);
888 Context.insert<typename Traits::Insts::StoreQ>(Value, Mem);
890 void _sub(Variable *Dest, Operand *Src0) {
891 AutoMemorySandboxer<> _(this, &Dest, &Src0);
892 Context.insert<typename Traits::Insts::Sub>(Dest, Src0);
894 void _sub_rmw(X86OperandMem *DestSrc0, Operand *Src1) {
895 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1);
896 Context.insert<typename Traits::Insts::SubRMW>(DestSrc0, Src1);
898 void _sub_sp(Operand *Adjustment) {
899 dispatchToConcrete(&Traits::ConcreteTarget::_sub_sp, std::move(Adjustment));
901 void _subps(Variable *Dest, Operand *Src0) {
902 AutoMemorySandboxer<> _(this, &Dest, &Src0);
903 Context.insert<typename Traits::Insts::Subps>(Dest, Src0);
905 void _subss(Variable *Dest, Operand *Src0) {
906 AutoMemorySandboxer<> _(this, &Dest, &Src0);
907 Context.insert<typename Traits::Insts::Subss>(Dest, Src0);
909 void _test(Operand *Src0, Operand *Src1) {
910 AutoMemorySandboxer<> _(this, &Src0, &Src1);
911 Context.insert<typename Traits::Insts::Test>(Src0, Src1);
913 void _ucomiss(Operand *Src0, Operand *Src1) {
914 AutoMemorySandboxer<> _(this, &Src0, &Src1);
915 Context.insert<typename Traits::Insts::Ucomiss>(Src0, Src1);
917 void _ud2() { Context.insert<typename Traits::Insts::UD2>(); }
918 void _unlink_bp() { dispatchToConcrete(&Traits::ConcreteTarget::_unlink_bp); }
919 void _xadd(Operand *Dest, Variable *Src, bool Locked) {
920 AutoMemorySandboxer<> _(this, &Dest, &Src);
921 Context.insert<typename Traits::Insts::Xadd>(Dest, Src, Locked);
922 // The xadd exchanges Dest and Src (modifying Src). Model that update with
923 // a FakeDef followed by a FakeUse.
924 Context.insert<InstFakeDef>(Src, llvm::dyn_cast<Variable>(Dest));
925 _set_dest_redefined();
926 Context.insert<InstFakeUse>(Src);
928 void _xchg(Operand *Dest, Variable *Src) {
929 AutoMemorySandboxer<> _(this, &Dest, &Src);
930 Context.insert<typename Traits::Insts::Xchg>(Dest, Src);
931 // The xchg modifies Dest and Src -- model that update with a
933 Context.insert<InstFakeDef>(Src, llvm::dyn_cast<Variable>(Dest));
934 _set_dest_redefined();
935 Context.insert<InstFakeUse>(Src);
937 void _xor(Variable *Dest, Operand *Src0) {
938 AutoMemorySandboxer<> _(this, &Dest, &Src0);
939 Context.insert<typename Traits::Insts::Xor>(Dest, Src0);
941 void _xorps(Variable *Dest, Operand *Src0) {
942 AutoMemorySandboxer<> _(this, &Dest, &Src0);
943 Context.insert<typename Traits::Insts::Xorps>(Dest, Src0);
945 void _xor_rmw(X86OperandMem *DestSrc0, Operand *Src1) {
946 AutoMemorySandboxer<> _(this, &DestSrc0, &Src1);
947 Context.insert<typename Traits::Insts::XorRMW>(DestSrc0, Src1);
951 if (!BuildDefs::minimal())
952 Context.insert<typename Traits::Insts::IacaStart>();
955 if (!BuildDefs::minimal())
956 Context.insert<typename Traits::Insts::IacaEnd>();
959 /// This class helps wrap IACA markers around the code generated by the
960 /// current scope. It means you don't need to put an end before each return.
961 class ScopedIacaMark {
962 ScopedIacaMark(const ScopedIacaMark &) = delete;
963 ScopedIacaMark &operator=(const ScopedIacaMark &) = delete;
966 ScopedIacaMark(TargetX86Base *Lowering) : Lowering(Lowering) {
967 Lowering->_iaca_start();
969 ~ScopedIacaMark() { end(); }
973 Lowering->_iaca_end();
978 TargetX86Base *Lowering;
981 bool optimizeScalarMul(Variable *Dest, Operand *Src0, int32_t Src1);
984 InstructionSetEnum InstructionSet = Traits::InstructionSet::Begin;
985 bool IsEbpBasedFrame = false;
986 bool NeedsStackAlignment = false;
987 size_t SpillAreaSizeBytes = 0;
988 size_t FixedAllocaSizeBytes = 0;
989 size_t FixedAllocaAlignBytes = 0;
990 bool PrologEmitsFixedAllocas = false;
991 uint32_t MaxOutArgsSizeBytes = 0;
992 static std::array<llvm::SmallBitVector, RCX86_NUM> TypeToRegisterSet;
993 static std::array<llvm::SmallBitVector, RCX86_NUM>
994 TypeToRegisterSetUnfiltered;
995 static std::array<llvm::SmallBitVector, Traits::RegisterSet::Reg_NUM>
997 llvm::SmallBitVector RegsUsed;
998 std::array<VarList, IceType_NUM> PhysicalRegisters;
999 // RebasePtr is a Variable that holds the Rebasing pointer (if any) for the
1000 // current sandboxing type.
1001 Variable *RebasePtr = nullptr;
1003 /// Randomize a given immediate operand
1004 Operand *randomizeOrPoolImmediate(Constant *Immediate,
1005 int32_t RegNum = Variable::NoRegister);
1007 randomizeOrPoolImmediate(X86OperandMem *MemOperand,
1008 int32_t RegNum = Variable::NoRegister);
1009 bool RandomizationPoolingPaused = false;
1012 /// dispatchToConcrete is the template voodoo that allows TargetX86Base to
1013 /// invoke methods in Machine (which inherits from TargetX86Base) without
1014 /// having to rely on virtual method calls. There are two overloads, one for
1015 /// non-void types, and one for void types. We need this becase, for non-void
1016 /// types, we need to return the method result, where as for void, we don't.
1017 /// While it is true that the code compiles without the void "version", there
1018 /// used to be a time when compilers would reject such code.
1020 /// This machinery is far from perfect. Note that, in particular, the
1021 /// arguments provided to dispatchToConcrete() need to match the arguments for
1022 /// Method **exactly** (i.e., no argument promotion is performed.)
1023 template <typename Ret, typename... Args>
1024 typename std::enable_if<!std::is_void<Ret>::value, Ret>::type
1025 dispatchToConcrete(Ret (ConcreteTarget::*Method)(Args...), Args &&... args) {
1026 return (static_cast<ConcreteTarget *>(this)->*Method)(
1027 std::forward<Args>(args)...);
1030 template <typename... Args>
1031 void dispatchToConcrete(void (ConcreteTarget::*Method)(Args...),
1033 (static_cast<ConcreteTarget *>(this)->*Method)(std::forward<Args>(args)...);
1036 void lowerShift64(InstArithmetic::OpKind Op, Operand *Src0Lo, Operand *Src0Hi,
1037 Operand *Src1Lo, Variable *DestLo, Variable *DestHi);
1039 /// Emit the code for a combined operation and consumer instruction, or set
1040 /// the destination variable of the operation if Consumer == nullptr.
1041 void lowerIcmpAndConsumer(const InstIcmp *Icmp, const Inst *Consumer);
1042 void lowerFcmpAndConsumer(const InstFcmp *Fcmp, const Inst *Consumer);
1043 void lowerArithAndConsumer(const InstArithmetic *Arith, const Inst *Consumer);
1045 /// Emit a setcc instruction if Consumer == nullptr; otherwise emit a
1046 /// specialized version of Consumer.
1047 void setccOrConsumer(BrCond Condition, Variable *Dest, const Inst *Consumer);
1049 /// Emit a mov [1|0] instruction if Consumer == nullptr; otherwise emit a
1050 /// specialized version of Consumer.
1051 void movOrConsumer(bool IcmpResult, Variable *Dest, const Inst *Consumer);
1053 /// Emit the code for instructions with a vector type.
1054 void lowerIcmpVector(const InstIcmp *Icmp);
1055 void lowerFcmpVector(const InstFcmp *Icmp);
1056 void lowerSelectVector(const InstSelect *Instr);
1058 /// Helpers for select lowering.
1059 void lowerSelectMove(Variable *Dest, BrCond Cond, Operand *SrcT,
1061 void lowerSelectIntMove(Variable *Dest, BrCond Cond, Operand *SrcT,
1063 /// Generic helper to move an arbitrary type from Src to Dest.
1064 void lowerMove(Variable *Dest, Operand *Src, bool IsRedefinition);
1066 /// Optimizations for idiom recognition.
1067 bool lowerOptimizeFcmpSelect(const InstFcmp *Fcmp, const InstSelect *Select);
1069 /// Complains loudly if invoked because the cpu can handle 64-bit types
1071 template <typename T = Traits>
1072 typename std::enable_if<T::Is64Bit, void>::type lowerIcmp64(const InstIcmp *,
1074 llvm::report_fatal_error(
1075 "Hey, yo! This is x86-64. Watcha doin'? (lowerIcmp64)");
1077 /// x86lowerIcmp64 handles 64-bit icmp lowering.
1078 template <typename T = Traits>
1079 typename std::enable_if<!T::Is64Bit, void>::type
1080 lowerIcmp64(const InstIcmp *Icmp, const Inst *Consumer);
1082 BoolFolding<Traits> FoldingInfo;
1084 static FixupKind PcRelFixup;
1085 static FixupKind AbsFixup;
1088 template <typename TraitsType>
1089 class TargetDataX86 final : public TargetDataLowering {
1090 using Traits = TraitsType;
1091 TargetDataX86() = delete;
1092 TargetDataX86(const TargetDataX86 &) = delete;
1093 TargetDataX86 &operator=(const TargetDataX86 &) = delete;
1096 ~TargetDataX86() override = default;
1098 static std::unique_ptr<TargetDataLowering> create(GlobalContext *Ctx) {
1099 return makeUnique<TargetDataX86>(Ctx);
1102 void lowerGlobals(const VariableDeclarationList &Vars,
1103 const IceString &SectionSuffix) override;
1104 void lowerConstants() override;
1105 void lowerJumpTables() override;
1110 explicit TargetDataX86(GlobalContext *Ctx) : TargetDataLowering(Ctx){};
1111 template <typename T> static void emitConstantPool(GlobalContext *Ctx);
1114 class TargetHeaderX86 : public TargetHeaderLowering {
1115 TargetHeaderX86() = delete;
1116 TargetHeaderX86(const TargetHeaderX86 &) = delete;
1117 TargetHeaderX86 &operator=(const TargetHeaderX86 &) = delete;
1120 ~TargetHeaderX86() = default;
1122 static std::unique_ptr<TargetHeaderLowering> create(GlobalContext *Ctx) {
1123 return makeUnique<TargetHeaderX86>(Ctx);
1129 explicit TargetHeaderX86(GlobalContext *Ctx) : TargetHeaderLowering(Ctx) {}
1132 } // end of namespace X86NAMESPACE
1133 } // end of namespace Ice
1135 #include "IceTargetLoweringX86BaseImpl.h"
1137 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASE_H