llvm.org GIT mirror llvm / 221a707
Add the llvm.frameallocate and llvm.recoverframeallocation intrinsics These intrinsics allow multiple functions to share a single stack allocation from one function's call frame. The function with the allocation may only perform one allocation, and it must be in the entry block. Functions accessing the allocation call llvm.recoverframeallocation with the function whose frame they are accessing and a frame pointer from an active call frame of that function. These intrinsics are very difficult to inline correctly, so the intention is that they be introduced rarely, or at least very late during EH preparation. Reviewers: echristo, andrew.w.kaylor Differential Revision: http://reviews.llvm.org/D6493 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@225746 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 4 years ago
21 changed file(s) with 303 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
72807280 other aggressive transformations, so the value returned may not be that
72817281 of the obvious source-language caller.
72827282
7283 '``llvm.frameallocate``' and '``llvm.recoverframeallocation``' Intrinsics
7284 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7285
7286 Syntax:
7287 """""""
7288
7289 ::
7290
7291 declare i8* @llvm.frameallocate(i32 %size)
7292 declare i8* @llvm.recoverframeallocation(i8* %func, i8* %fp)
7293
7294 Overview:
7295 """""""""
7296
7297 The '``llvm.frameallocate``' intrinsic allocates stack memory at some fixed
7298 offset from the frame pointer, and the '``llvm.recoverframeallocation``'
7299 intrinsic applies that offset to a live frame pointer to recover the address of
7300 the allocation. The offset is computed during frame layout of the caller of
7301 ``llvm.frameallocate``.
7302
7303 Arguments:
7304 """"""""""
7305
7306 The ``size`` argument to '``llvm.frameallocate``' must be a constant integer
7307 indicating the amount of stack memory to allocate. As with allocas, allocating
7308 zero bytes is legal, but the result is undefined.
7309
7310 The ``func`` argument to '``llvm.recoverframeallocation``' must be a constant
7311 bitcasted pointer to a function defined in the current module. The code
7312 generator cannot determine the frame allocation offset of functions defined in
7313 other modules.
7314
7315 The ``fp`` argument to '``llvm.recoverframeallocation``' must be a frame
7316 pointer of a call frame that is currently live. The return value of
7317 '``llvm.frameaddress``' is one way to produce such a value, but most platforms
7318 also expose the frame pointer through stack unwinding mechanisms.
7319
7320 Semantics:
7321 """"""""""
7322
7323 These intrinsics allow a group of functions to access one stack memory
7324 allocation in an ancestor stack frame. The memory returned from
7325 '``llvm.frameallocate``' may be allocated prior to stack realignment, so the
7326 memory is only aligned to the ABI-required stack alignment. Each function may
7327 only call '``llvm.frameallocate``' one or zero times from the function entry
7328 block. The frame allocation intrinsic inhibits inlining, as any frame
7329 allocations in the inlined function frame are likely to be at a different
7330 offset from the one used by '``llvm.recoverframeallocation``' called with the
7331 uninlined function.
7332
72837333 .. _int_read_register:
72847334 .. _int_write_register:
72857335
204204
205205 void emitCFIInstruction(const MachineInstr &MI);
206206
207 void emitFrameAlloc(const MachineInstr &MI);
208
207209 enum CFIMoveType { CFI_M_None, CFI_M_EH, CFI_M_Debug };
208210 CFIMoveType needsCFIMoves();
209211
7070 /// to the current function's frame or return address, an index of one to
7171 /// the parent's frame or return address, and so on.
7272 FRAMEADDR, RETURNADDR,
73
74 /// RECOVER_FRAME_ALLOC - Represents the llvm.recoverframeallocation
75 /// intrinsic. Materializes the offset from the frame pointer of another
76 /// function to the result of llvm.frameallocate.
77 RECOVER_FRAME_ALLOC,
7378
7479 /// READ_REGISTER, WRITE_REGISTER - This node represents llvm.register on
7580 /// the DAG, which implements the named register global variables extension.
515515 /// on the stack. Returns an index with a negative value.
516516 int CreateFixedSpillStackObject(uint64_t Size, int64_t SPOffset);
517517
518 /// Allocates memory at a fixed, target-specific offset from the frame
519 /// pointer. Marks the function as having its frame address taken.
520 int CreateFrameAllocation(uint64_t Size);
521
518522 /// isFixedObjectIndex - Returns true if the specified index corresponds to a
519523 /// fixed stack object.
520524 bool isFixedObjectIndex(int ObjectIdx) const {
258258 //
259259 def int_returnaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>;
260260 def int_frameaddress : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty], [IntrNoMem]>;
261 def int_frameallocate : Intrinsic<[llvm_ptr_ty], [llvm_i32_ty]>;
262 def int_recoverframeallocation : Intrinsic<[llvm_ptr_ty],
263 [llvm_ptr_ty, llvm_ptr_ty],
264 [IntrNoMem]>;
261265 def int_read_register : Intrinsic<[llvm_anyint_ty], [llvm_metadata_ty],
262266 [IntrNoMem], "llvm.read_register">;
263267 def int_write_register : Intrinsic<[], [llvm_metadata_ty, llvm_anyint_ty],
235235 MCSymbol *GetOrCreateSymbol(const Twine &Name);
236236
237237 MCSymbol *getOrCreateSectionSymbol(const MCSectionELF &Section);
238
239 MCSymbol *getOrCreateFrameAllocSymbol(StringRef FuncName);
238240
239241 /// LookupSymbol - Get the symbol for \p Name, or null.
240242 MCSymbol *LookupSymbol(StringRef Name) const;
864864 let hasSideEffects = 0;
865865 bit isPseudo = 1;
866866 }
867 def FRAME_ALLOC : Instruction {
868 // This instruction is really just a label. It has to be part of the chain so
869 // that it doesn't get dropped from the DAG, but it produces nothing and has
870 // no side effects.
871 let OutOperandList = (outs);
872 let InOperandList = (ins ptr_rc:$symbol, i32imm:$id);
873 let hasSideEffects = 0;
874 let hasCtrlDep = 1;
875 }
867876 }
868877
869878 //===----------------------------------------------------------------------===//
141141 /// the assembly prologue to explicitly handle the stack.
142142 virtual void adjustForHiPEPrologue(MachineFunction &MF) const { }
143143
144 /// Adjust the prologue to add an allocation at a fixed offset from the frame
145 /// pointer.
146 virtual void adjustForFrameAllocatePrologue(MachineFunction &MF) const { }
147
144148 /// spillCalleeSavedRegisters - Issues instruction(s) to spill all callee
145149 /// saved registers and returns true if it isn't possible / profitable to do
146150 /// so by issuing a series of store instructions via
115115 /// of live pointers for relocation by the garbage collector. It is
116116 /// intended to support garbage collection with fully precise relocating
117117 /// collectors and deoptimizations in either the callee or caller.
118 STATEPOINT = 20
118 STATEPOINT = 20,
119
120 /// Instruction that records the offset of a function's frame allocation in a
121 /// label. Created by the llvm.frameallocate intrinsic. It has two arguments:
122 /// the symbol for the label and the frame index of the stack allocation.
123 FRAME_ALLOC = 21,
119124 };
120125 } // end namespace TargetOpcode
121126 } // end namespace llvm
747747 emitCFIInstruction(CFI);
748748 }
749749
750 void AsmPrinter::emitFrameAlloc(const MachineInstr &MI) {
751 // The operands are the MCSymbol and the frame offset of the allocation.
752 MCSymbol *FrameAllocSym = MI.getOperand(0).getMCSymbol();
753 int FrameOffset = MI.getOperand(1).getImm();
754
755 // Emit a symbol assignment.
756 OutStreamer.EmitAssignment(FrameAllocSym,
757 MCConstantExpr::Create(FrameOffset, OutContext));
758 }
759
750760 /// EmitFunctionBody - This method emits the body and trailer for a
751761 /// function.
752762 void AsmPrinter::EmitFunctionBody() {
783793 switch (MI.getOpcode()) {
784794 case TargetOpcode::CFI_INSTRUCTION:
785795 emitCFIInstruction(MI);
796 break;
797
798 case TargetOpcode::FRAME_ALLOC:
799 emitFrameAlloc(MI);
786800 break;
787801
788802 case TargetOpcode::EH_LABEL:
5656 // be deleted. But there is so much bad inline asm code out there, we should
5757 // let them be.
5858 if (MI->isInlineAsm())
59 return false;
60
61 // Don't delete frame allocation labels.
62 if (MI->getOpcode() == TargetOpcode::FRAME_ALLOC)
5963 return false;
6064
6165 // Don't delete instructions with side effects.
584584 /*Alloca*/ nullptr,
585585 /*isAliased*/ false));
586586 return -++NumFixedObjects;
587 }
588
589 int MachineFrameInfo::CreateFrameAllocation(uint64_t Size) {
590 // Force the use of a frame pointer. The intention is that this intrinsic be
591 // used in conjunction with unwind mechanisms that leak the frame pointer.
592 setFrameAddressIsTaken(true);
593 Size = RoundUpToAlignment(Size, StackAlignment);
594 return CreateStackObject(Size, StackAlignment, false);
587595 }
588596
589597 BitVector
816816 continue;
817817 }
818818
819 // Frame allocations are target independent. Simply swap the index with
820 // the offset.
821 if (MI->getOpcode() == TargetOpcode::FRAME_ALLOC) {
822 assert(TFI->hasFP(Fn) && "frame alloc requires FP");
823 MachineOperand &FI = MI->getOperand(i);
824 unsigned Reg;
825 int FrameOffset = TFI->getFrameIndexReference(Fn, FI.getIndex(), Reg);
826 FI.ChangeToImmediate(FrameOffset);
827 continue;
828 }
829
819830 // Some instructions (e.g. inline asm instructions) can have
820831 // multiple frame indices and/or cause eliminateFrameIndex
821832 // to insert more than one instruction. We need the register
4747 #include "llvm/IR/LLVMContext.h"
4848 #include "llvm/IR/Module.h"
4949 #include "llvm/IR/Statepoint.h"
50 #include "llvm/MC/MCSymbol.h"
5051 #include "llvm/Support/CommandLine.h"
5152 #include "llvm/Support/Debug.h"
5253 #include "llvm/Support/ErrorHandling.h"
55805581 }
55815582 case Intrinsic::instrprof_increment:
55825583 llvm_unreachable("instrprof failed to lower an increment");
5584
5585 case Intrinsic::frameallocate: {
5586 MachineFunction &MF = DAG.getMachineFunction();
5587 const TargetInstrInfo *TII = DAG.getSubtarget().getInstrInfo();
5588
5589 // Do the allocation and map it as a normal value.
5590 // FIXME: Maybe we should add this to the alloca map so that we don't have
5591 // to register allocate it?
5592 uint64_t Size = cast(I.getArgOperand(0))->getZExtValue();
5593 int Alloc = MF.getFrameInfo()->CreateFrameAllocation(Size);
5594 MVT PtrVT = TLI.getPointerTy(0);
5595 SDValue FIVal = DAG.getFrameIndex(Alloc, PtrVT);
5596 setValue(&I, FIVal);
5597
5598 // Directly emit a FRAME_ALLOC machine instr. Label assignment emission is
5599 // the same on all targets.
5600 MCSymbol *FrameAllocSym =
5601 MF.getMMI().getContext().getOrCreateFrameAllocSymbol(MF.getName());
5602 BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, dl,
5603 TII->get(TargetOpcode::FRAME_ALLOC))
5604 .addSym(FrameAllocSym)
5605 .addFrameIndex(Alloc);
5606
5607 return nullptr;
5608 }
5609
5610 case Intrinsic::recoverframeallocation: {
5611 // i8* @llvm.recoverframeallocation(i8* %fn, i8* %fp)
5612 MachineFunction &MF = DAG.getMachineFunction();
5613 MVT PtrVT = TLI.getPointerTy(0);
5614
5615 // Get the symbol that defines the frame offset.
5616 Function *Fn = cast(I.getArgOperand(0)->stripPointerCasts());
5617 MCSymbol *FrameAllocSym =
5618 MF.getMMI().getContext().getOrCreateFrameAllocSymbol(Fn->getName());
5619
5620 // Create a TargetExternalSymbol for the label to avoid any target lowering
5621 // that would make this PC relative.
5622 StringRef Name = FrameAllocSym->getName();
5623 assert(Name.size() == strlen(Name.data()) && "not null terminated");
5624 SDValue OffsetSym = DAG.getTargetExternalSymbol(Name.data(), PtrVT);
5625 SDValue OffsetVal =
5626 DAG.getNode(ISD::RECOVER_FRAME_ALLOC, sdl, PtrVT, OffsetSym);
5627
5628 // Add the offset to the FP.
5629 Value *FP = I.getArgOperand(1);
5630 SDValue FPVal = getValue(FP);
5631 SDValue Add = DAG.getNode(ISD::ADD, sdl, PtrVT, FPVal, OffsetVal);
5632 setValue(&I, Add);
5633
5634 return nullptr;
5635 }
55835636 }
55845637 }
55855638
197197 /// personality function.
198198 const Value *PersonalityFn;
199199
200 /// \brief Whether we've seen a call to @llvm.frameallocate in this function
201 /// already.
202 bool SawFrameAllocate;
203
200204 public:
201205 explicit Verifier(raw_ostream &OS = dbgs())
202 : VerifierSupport(OS), Context(nullptr), PersonalityFn(nullptr) {}
206 : VerifierSupport(OS), Context(nullptr), PersonalityFn(nullptr),
207 SawFrameAllocate(false) {}
203208
204209 bool verify(const Function &F) {
205210 M = F.getParent();
234239 visit(const_cast(F));
235240 InstsInThisBlock.clear();
236241 PersonalityFn = nullptr;
242 SawFrameAllocate = false;
237243
238244 return !Broken;
239245 }
25982604 Assert1(isa(CI.getArgOperand(1)),
25992605 "llvm.invariant.end parameter #2 must be a constant integer", &CI);
26002606 break;
2601
2607
2608 case Intrinsic::frameallocate: {
2609 BasicBlock *BB = CI.getParent();
2610 Assert1(BB == &BB->getParent()->front(),
2611 "llvm.frameallocate used outside of entry block", &CI);
2612 Assert1(!SawFrameAllocate,
2613 "multiple calls to llvm.frameallocate in one function", &CI);
2614 SawFrameAllocate = true;
2615 Assert1(isa(CI.getArgOperand(0)),
2616 "llvm.frameallocate argument must be constant integer size", &CI);
2617 break;
2618 }
2619 case Intrinsic::recoverframeallocation: {
2620 Value *FnArg = CI.getArgOperand(0)->stripPointerCasts();
2621 Function *Fn = dyn_cast(FnArg);
2622 Assert1(Fn && !Fn->isDeclaration(), "llvm.recoverframeallocation first "
2623 "argument must be function defined in this module", &CI);
2624 break;
2625 }
2626
26022627 case Intrinsic::experimental_gc_statepoint: {
26032628 Assert1(!CI.doesNotAccessMemory() &&
26042629 !CI.onlyReadsMemory(),
129129 return Sym;
130130 }
131131
132 MCSymbol *MCContext::getOrCreateFrameAllocSymbol(StringRef FuncName) {
133 return GetOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) +
134 "frameallocation_" + FuncName);
135 }
136
132137 MCSymbol *MCContext::CreateSymbol(StringRef Name) {
133138 // Determine whether this is an assembler temporary or normal label, if used.
134139 bool isTemporary = false;
10091009 (MOV64mi32 addr:$dst, tblockaddress:$src)>,
10101010 Requires<[NearData, IsStatic]>;
10111011
1012 def : Pat<(i32 (X86RecoverFrameAlloc texternalsym:$dst)), (MOV32ri texternalsym:$dst)>;
1013 def : Pat<(i64 (X86RecoverFrameAlloc texternalsym:$dst)), (MOV64ri texternalsym:$dst)>;
1014
10121015 // Calls
10131016
10141017 // tls has some funny stuff here...
192192
193193 def X86Wrapper : SDNode<"X86ISD::Wrapper", SDTX86Wrapper>;
194194 def X86WrapperRIP : SDNode<"X86ISD::WrapperRIP", SDTX86Wrapper>;
195
196 def X86RecoverFrameAlloc : SDNode<"ISD::RECOVER_FRAME_ALLOC",
197 SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
198 SDTCisInt<1>]>>;
195199
196200 def X86tlsaddr : SDNode<"X86ISD::TLSADDR", SDT_X86TLSADDR,
197201 [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
0 ; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s
1
2 declare i8* @llvm.frameallocate(i32)
3 declare i8* @llvm.frameaddress(i32)
4 declare i8* @llvm.recoverframeallocation(i8*, i8*)
5 declare i32 @printf(i8*, ...)
6
7 @str = internal constant [10 x i8] c"asdf: %d\0A\00"
8
9 define void @print_framealloc_from_fp(i8* %fp) {
10 %alloc = call i8* @llvm.recoverframeallocation(i8* bitcast (void(i32*, i32*)* @alloc_func to i8*), i8* %fp)
11 %alloc_i32 = bitcast i8* %alloc to i32*
12 %r = load i32* %alloc_i32
13 call i32 (i8*, ...)* @printf(i8* getelementptr ([10 x i8]* @str, i32 0, i32 0), i32 %r)
14 ret void
15 }
16
17 ; CHECK-LABEL: print_framealloc_from_fp:
18 ; CHECK: movabsq $.Lframeallocation_alloc_func, %[[offs:[a-z]+]]
19 ; CHECK: movl (%rcx,%[[offs]]), %edx
20 ; CHECK: leaq {{.*}}(%rip), %rcx
21 ; CHECK: callq printf
22 ; CHECK: retq
23
24 define void @alloc_func(i32* %s, i32* %d) {
25 %alloc = call i8* @llvm.frameallocate(i32 16)
26 %alloc_i32 = bitcast i8* %alloc to i32*
27 store i32 42, i32* %alloc_i32
28 %fp = call i8* @llvm.frameaddress(i32 0)
29 call void @print_framealloc_from_fp(i8* %fp)
30 ret void
31 }
32
33 ; CHECK-LABEL: alloc_func:
34 ; CHECK: .Lframeallocation_alloc_func = -[[offs:[0-9]+]]
35 ; CHECK: movl $42, -[[offs]](%rbp)
36 ; CHECK: movq %rbp, %rcx
37 ; CHECK: callq print_framealloc_from_fp
38 ; CHECK: retq
0 ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
1
2 declare i8* @llvm.frameallocate(i32)
3 declare i8* @llvm.recoverframeallocation(i8*, i8*)
4
5 define internal void @f() {
6 call i8* @llvm.frameallocate(i32 4)
7 call i8* @llvm.frameallocate(i32 4)
8 ret void
9 }
10 ; CHECK: multiple calls to llvm.frameallocate in one function
11
12 define internal void @f_a(i32 %n) {
13 call i8* @llvm.frameallocate(i32 %n)
14 ret void
15 }
16 ; CHECK: llvm.frameallocate argument must be constant integer size
17
18 define internal void @g() {
19 entry:
20 br label %not_entry
21 not_entry:
22 call i8* @llvm.frameallocate(i32 4)
23 ret void
24 }
25 ; CHECK: llvm.frameallocate used outside of entry block
26
27 define internal void @h() {
28 call i8* @llvm.recoverframeallocation(i8* null, i8* null)
29 ret void
30 }
31 ; CHECK: llvm.recoverframeallocation first argument must be function defined in this module
32
33 @global = constant i8 0
34
35 declare void @declaration()
36
37 define internal void @i() {
38 call i8* @llvm.recoverframeallocation(i8* @global, i8* null)
39 ret void
40 }
41 ; CHECK: llvm.recoverframeallocation first argument must be function defined in this module
42
43 define internal void @j() {
44 call i8* @llvm.recoverframeallocation(i8* bitcast(void()* @declaration to i8*), i8* null)
45 ret void
46 }
47 ; CHECK: llvm.recoverframeallocation first argument must be function defined in this module
294294 "IMPLICIT_DEF", "SUBREG_TO_REG", "COPY_TO_REGCLASS", "DBG_VALUE",
295295 "REG_SEQUENCE", "COPY", "BUNDLE", "LIFETIME_START",
296296 "LIFETIME_END", "STACKMAP", "PATCHPOINT", "LOAD_STACK_GUARD",
297 "STATEPOINT",
297 "STATEPOINT", "FRAME_ALLOC",
298298 nullptr};
299299 const auto &Insts = getInstructions();
300300 for (const char *const *p = FixedInstrs; *p; ++p) {