diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 14 | ||||
-rw-r--r-- | lib/CodeGen/DeadMachineInstructionElim.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/MachineFunction.cpp | 8 | ||||
-rw-r--r-- | lib/CodeGen/PrologEpilogInserter.cpp | 11 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 53 | ||||
-rw-r--r-- | lib/IR/Verifier.cpp | 29 | ||||
-rw-r--r-- | lib/MC/MCContext.cpp | 5 | ||||
-rw-r--r-- | lib/Target/X86/X86InstrCompiler.td | 3 | ||||
-rw-r--r-- | lib/Target/X86/X86InstrInfo.td | 4 |
9 files changed, 129 insertions, 2 deletions
diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 461b6d272da..bbed8081a14 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -748,6 +748,16 @@ void AsmPrinter::emitCFIInstruction(const MachineInstr &MI) { emitCFIInstruction(CFI); } +void AsmPrinter::emitFrameAlloc(const MachineInstr &MI) { + // The operands are the MCSymbol and the frame offset of the allocation. + MCSymbol *FrameAllocSym = MI.getOperand(0).getMCSymbol(); + int FrameOffset = MI.getOperand(1).getImm(); + + // Emit a symbol assignment. + OutStreamer.EmitAssignment(FrameAllocSym, + MCConstantExpr::Create(FrameOffset, OutContext)); +} + /// EmitFunctionBody - This method emits the body and trailer for a /// function. void AsmPrinter::EmitFunctionBody() { @@ -786,6 +796,10 @@ void AsmPrinter::EmitFunctionBody() { emitCFIInstruction(MI); break; + case TargetOpcode::FRAME_ALLOC: + emitFrameAlloc(MI); + break; + case TargetOpcode::EH_LABEL: case TargetOpcode::GC_LABEL: OutStreamer.EmitLabel(MI.getOperand(0).getMCSymbol()); diff --git a/lib/CodeGen/DeadMachineInstructionElim.cpp b/lib/CodeGen/DeadMachineInstructionElim.cpp index 48213c12e04..c17a35d1c73 100644 --- a/lib/CodeGen/DeadMachineInstructionElim.cpp +++ b/lib/CodeGen/DeadMachineInstructionElim.cpp @@ -59,6 +59,10 @@ bool DeadMachineInstructionElim::isDead(const MachineInstr *MI) const { if (MI->isInlineAsm()) return false; + // Don't delete frame allocation labels. + if (MI->getOpcode() == TargetOpcode::FRAME_ALLOC) + return false; + // Don't delete instructions with side effects. bool SawStore = false; if (!MI->isSafeToMove(TII, nullptr, SawStore) && !MI->isPHI()) diff --git a/lib/CodeGen/MachineFunction.cpp b/lib/CodeGen/MachineFunction.cpp index 8a2b610948b..6b4cba6c678 100644 --- a/lib/CodeGen/MachineFunction.cpp +++ b/lib/CodeGen/MachineFunction.cpp @@ -587,6 +587,14 @@ int MachineFrameInfo::CreateFixedSpillStackObject(uint64_t Size, return -++NumFixedObjects; } +int MachineFrameInfo::CreateFrameAllocation(uint64_t Size) { + // Force the use of a frame pointer. The intention is that this intrinsic be + // used in conjunction with unwind mechanisms that leak the frame pointer. + setFrameAddressIsTaken(true); + Size = RoundUpToAlignment(Size, StackAlignment); + return CreateStackObject(Size, StackAlignment, false); +} + BitVector MachineFrameInfo::getPristineRegs(const MachineBasicBlock *MBB) const { assert(MBB && "MBB must be valid"); diff --git a/lib/CodeGen/PrologEpilogInserter.cpp b/lib/CodeGen/PrologEpilogInserter.cpp index f5f32abc0e4..385e5a35afb 100644 --- a/lib/CodeGen/PrologEpilogInserter.cpp +++ b/lib/CodeGen/PrologEpilogInserter.cpp @@ -817,6 +817,17 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &Fn, continue; } + // Frame allocations are target independent. Simply swap the index with + // the offset. + if (MI->getOpcode() == TargetOpcode::FRAME_ALLOC) { + assert(TFI->hasFP(Fn) && "frame alloc requires FP"); + MachineOperand &FI = MI->getOperand(i); + unsigned Reg; + int FrameOffset = TFI->getFrameIndexReference(Fn, FI.getIndex(), Reg); + FI.ChangeToImmediate(FrameOffset); + continue; + } + // Some instructions (e.g. inline asm instructions) can have // multiple frame indices and/or cause eliminateFrameIndex // to insert more than one instruction. We need the register diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index e1396649f34..8a762555577 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -48,6 +48,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/Statepoint.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -5581,6 +5582,58 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { } case Intrinsic::instrprof_increment: llvm_unreachable("instrprof failed to lower an increment"); + + case Intrinsic::frameallocate: { + MachineFunction &MF = DAG.getMachineFunction(); + const TargetInstrInfo *TII = DAG.getSubtarget().getInstrInfo(); + + // Do the allocation and map it as a normal value. + // FIXME: Maybe we should add this to the alloca map so that we don't have + // to register allocate it? + uint64_t Size = cast<ConstantInt>(I.getArgOperand(0))->getZExtValue(); + int Alloc = MF.getFrameInfo()->CreateFrameAllocation(Size); + MVT PtrVT = TLI.getPointerTy(0); + SDValue FIVal = DAG.getFrameIndex(Alloc, PtrVT); + setValue(&I, FIVal); + + // Directly emit a FRAME_ALLOC machine instr. Label assignment emission is + // the same on all targets. + MCSymbol *FrameAllocSym = + MF.getMMI().getContext().getOrCreateFrameAllocSymbol(MF.getName()); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, dl, + TII->get(TargetOpcode::FRAME_ALLOC)) + .addSym(FrameAllocSym) + .addFrameIndex(Alloc); + + return nullptr; + } + + case Intrinsic::recoverframeallocation: { + // i8* @llvm.recoverframeallocation(i8* %fn, i8* %fp) + MachineFunction &MF = DAG.getMachineFunction(); + MVT PtrVT = TLI.getPointerTy(0); + + // Get the symbol that defines the frame offset. + Function *Fn = cast<Function>(I.getArgOperand(0)->stripPointerCasts()); + MCSymbol *FrameAllocSym = + MF.getMMI().getContext().getOrCreateFrameAllocSymbol(Fn->getName()); + + // Create a TargetExternalSymbol for the label to avoid any target lowering + // that would make this PC relative. + StringRef Name = FrameAllocSym->getName(); + assert(Name.size() == strlen(Name.data()) && "not null terminated"); + SDValue OffsetSym = DAG.getTargetExternalSymbol(Name.data(), PtrVT); + SDValue OffsetVal = + DAG.getNode(ISD::RECOVER_FRAME_ALLOC, sdl, PtrVT, OffsetSym); + + // Add the offset to the FP. + Value *FP = I.getArgOperand(1); + SDValue FPVal = getValue(FP); + SDValue Add = DAG.getNode(ISD::ADD, sdl, PtrVT, FPVal, OffsetVal); + setValue(&I, Add); + + return nullptr; + } } } diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index ad7473b6611..4a98b546099 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -198,9 +198,14 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport { /// personality function. const Value *PersonalityFn; + /// \brief Whether we've seen a call to @llvm.frameallocate in this function + /// already. + bool SawFrameAllocate; + public: explicit Verifier(raw_ostream &OS = dbgs()) - : VerifierSupport(OS), Context(nullptr), PersonalityFn(nullptr) {} + : VerifierSupport(OS), Context(nullptr), PersonalityFn(nullptr), + SawFrameAllocate(false) {} bool verify(const Function &F) { M = F.getParent(); @@ -235,6 +240,7 @@ public: visit(const_cast<Function &>(F)); InstsInThisBlock.clear(); PersonalityFn = nullptr; + SawFrameAllocate = false; return !Broken; } @@ -2599,7 +2605,26 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { Assert1(isa<ConstantInt>(CI.getArgOperand(1)), "llvm.invariant.end parameter #2 must be a constant integer", &CI); break; - + + case Intrinsic::frameallocate: { + BasicBlock *BB = CI.getParent(); + Assert1(BB == &BB->getParent()->front(), + "llvm.frameallocate used outside of entry block", &CI); + Assert1(!SawFrameAllocate, + "multiple calls to llvm.frameallocate in one function", &CI); + SawFrameAllocate = true; + Assert1(isa<ConstantInt>(CI.getArgOperand(0)), + "llvm.frameallocate argument must be constant integer size", &CI); + break; + } + case Intrinsic::recoverframeallocation: { + Value *FnArg = CI.getArgOperand(0)->stripPointerCasts(); + Function *Fn = dyn_cast<Function>(FnArg); + Assert1(Fn && !Fn->isDeclaration(), "llvm.recoverframeallocation first " + "argument must be function defined in this module", &CI); + break; + } + case Intrinsic::experimental_gc_statepoint: { Assert1(!CI.doesNotAccessMemory() && !CI.onlyReadsMemory(), diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 8630b25a84e..b41e6d8201d 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -130,6 +130,11 @@ MCSymbol *MCContext::getOrCreateSectionSymbol(const MCSectionELF &Section) { return Sym; } +MCSymbol *MCContext::getOrCreateFrameAllocSymbol(StringRef FuncName) { + return GetOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) + + "frameallocation_" + FuncName); +} + MCSymbol *MCContext::CreateSymbol(StringRef Name) { // Determine whether this is an assembler temporary or normal label, if used. bool isTemporary = false; diff --git a/lib/Target/X86/X86InstrCompiler.td b/lib/Target/X86/X86InstrCompiler.td index ad79c9eedf2..ed0a6346929 100644 --- a/lib/Target/X86/X86InstrCompiler.td +++ b/lib/Target/X86/X86InstrCompiler.td @@ -1010,6 +1010,9 @@ def : Pat<(store (i64 (X86Wrapper tblockaddress:$src)), addr:$dst), (MOV64mi32 addr:$dst, tblockaddress:$src)>, Requires<[NearData, IsStatic]>; +def : Pat<(i32 (X86RecoverFrameAlloc texternalsym:$dst)), (MOV32ri texternalsym:$dst)>; +def : Pat<(i64 (X86RecoverFrameAlloc texternalsym:$dst)), (MOV64ri texternalsym:$dst)>; + // Calls // tls has some funny stuff here... diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 4903a730955..59301f9837d 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -194,6 +194,10 @@ def X86rdpmc : SDNode<"X86ISD::RDPMC_DAG", SDTX86Void, def X86Wrapper : SDNode<"X86ISD::Wrapper", SDTX86Wrapper>; def X86WrapperRIP : SDNode<"X86ISD::WrapperRIP", SDTX86Wrapper>; +def X86RecoverFrameAlloc : SDNode<"ISD::RECOVER_FRAME_ALLOC", + SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, + SDTCisInt<1>]>>; + def X86tlsaddr : SDNode<"X86ISD::TLSADDR", SDT_X86TLSADDR, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; |