1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
| //===-- CodeGen/MachineFrameInfo.h - Abstract Stack Frame Rep. --*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// The file defines the MachineFrameInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_MACHINEFRAMEINFO_H
#define LLVM_CODEGEN_MACHINEFRAMEINFO_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/DataTypes.h"
#include <cassert>
#include <vector>
namespace llvm {
class raw_ostream;
class MachineFunction;
class MachineBasicBlock;
class BitVector;
class AllocaInst;
/// The CalleeSavedInfo class tracks the information need to locate where a
/// callee saved register is in the current frame.
/// Callee saved reg can also be saved to a different register rather than
/// on the stack by setting DstReg instead of FrameIdx.
class CalleeSavedInfo {
unsigned Reg;
union {
int FrameIdx;
unsigned DstReg;
};
/// Flag indicating whether the register is actually restored in the epilog.
/// In most cases, if a register is saved, it is also restored. There are
/// some situations, though, when this is not the case. For example, the
/// LR register on ARM is usually saved, but on exit from the function its
/// saved value may be loaded directly into PC. Since liveness tracking of
/// physical registers treats callee-saved registers are live outside of
/// the function, LR would be treated as live-on-exit, even though in these
/// scenarios it is not. This flag is added to indicate that the saved
/// register described by this object is not restored in the epilog.
/// The long-term solution is to model the liveness of callee-saved registers
/// by implicit uses on the return instructions, however, the required
/// changes in the ARM backend would be quite extensive.
bool Restored;
/// Flag indicating whether the register is spilled to stack or another
/// register.
bool SpilledToReg;
public:
explicit CalleeSavedInfo(unsigned R, int FI = 0)
: Reg(R), FrameIdx(FI), Restored(true), SpilledToReg(false) {}
// Accessors.
unsigned getReg() const { return Reg; }
int getFrameIdx() const { return FrameIdx; }
unsigned getDstReg() const { return DstReg; }
void setFrameIdx(int FI) {
FrameIdx = FI;
SpilledToReg = false;
}
void setDstReg(unsigned SpillReg) {
DstReg = SpillReg;
SpilledToReg = true;
}
bool isRestored() const { return Restored; }
void setRestored(bool R) { Restored = R; }
bool isSpilledToReg() const { return SpilledToReg; }
};
/// The MachineFrameInfo class represents an abstract stack frame until
/// prolog/epilog code is inserted. This class is key to allowing stack frame
/// representation optimizations, such as frame pointer elimination. It also
/// allows more mundane (but still important) optimizations, such as reordering
/// of abstract objects on the stack frame.
///
/// To support this, the class assigns unique integer identifiers to stack
/// objects requested clients. These identifiers are negative integers for
/// fixed stack objects (such as arguments passed on the stack) or nonnegative
/// for objects that may be reordered. Instructions which refer to stack
/// objects use a special MO_FrameIndex operand to represent these frame
/// indexes.
///
/// Because this class keeps track of all references to the stack frame, it
/// knows when a variable sized object is allocated on the stack. This is the
/// sole condition which prevents frame pointer elimination, which is an
/// important optimization on register-poor architectures. Because original
/// variable sized alloca's in the source program are the only source of
/// variable sized stack objects, it is safe to decide whether there will be
/// any variable sized objects before all stack objects are known (for
/// example, register allocator spill code never needs variable sized
/// objects).
///
/// When prolog/epilog code emission is performed, the final stack frame is
/// built and the machine instructions are modified to refer to the actual
/// stack offsets of the object, eliminating all MO_FrameIndex operands from
/// the program.
///
/// Abstract Stack Frame Information
class MachineFrameInfo {
public:
/// Stack Smashing Protection (SSP) rules require that vulnerable stack
/// allocations are located close the stack protector.
enum SSPLayoutKind {
SSPLK_None, ///< Did not trigger a stack protector. No effect on data
///< layout.
SSPLK_LargeArray, ///< Array or nested array >= SSP-buffer-size. Closest
///< to the stack protector.
SSPLK_SmallArray, ///< Array or nested array < SSP-buffer-size. 2nd closest
///< to the stack protector.
SSPLK_AddrOf ///< The address of this allocation is exposed and
///< triggered protection. 3rd closest to the protector.
};
private:
// Represent a single object allocated on the stack.
struct StackObject {
// The offset of this object from the stack pointer on entry to
// the function. This field has no meaning for a variable sized element.
int64_t SPOffset;
// The size of this object on the stack. 0 means a variable sized object,
// ~0ULL means a dead object.
uint64_t Size;
// The required alignment of this stack slot.
Align Alignment;
// If true, the value of the stack object is set before
// entering the function and is not modified inside the function. By
// default, fixed objects are immutable unless marked otherwise.
bool isImmutable;
// If true the stack object is used as spill slot. It
// cannot alias any other memory objects.
bool isSpillSlot;
/// If true, this stack slot is used to spill a value (could be deopt
/// and/or GC related) over a statepoint. We know that the address of the
/// slot can't alias any LLVM IR value. This is very similar to a Spill
/// Slot, but is created by statepoint lowering is SelectionDAG, not the
/// register allocator.
bool isStatepointSpillSlot = false;
/// Identifier for stack memory type analagous to address space. If this is
/// non-0, the meaning is target defined. Offsets cannot be directly
/// compared between objects with different stack IDs. The object may not
/// necessarily reside in the same contiguous memory block as other stack
/// objects. Objects with differing stack IDs should not be merged or
/// replaced substituted for each other.
//
/// It is assumed a target uses consecutive, increasing stack IDs starting
/// from 1.
uint8_t StackID;
/// If this stack object is originated from an Alloca instruction
/// this value saves the original IR allocation. Can be NULL.
const AllocaInst *Alloca;
// If true, the object was mapped into the local frame
// block and doesn't need additional handling for allocation beyond that.
bool PreAllocated = false;
// If true, an LLVM IR value might point to this object.
// Normally, spill slots and fixed-offset objects don't alias IR-accessible
// objects, but there are exceptions (on PowerPC, for example, some byval
// arguments have ABI-prescribed offsets).
bool isAliased;
/// If true, the object has been zero-extended.
bool isZExt = false;
/// If true, the object has been zero-extended.
bool isSExt = false;
uint8_t SSPLayout;
StackObject(uint64_t Size, Align Alignment, int64_t SPOffset,
bool IsImmutable, bool IsSpillSlot, const AllocaInst *Alloca,
bool IsAliased, uint8_t StackID = 0)
: SPOffset(SPOffset), Size(Size), Alignment(Alignment),
isImmutable(IsImmutable), isSpillSlot(IsSpillSlot), StackID(StackID),
Alloca(Alloca), isAliased(IsAliased), SSPLayout(SSPLK_None) {}
};
/// The alignment of the stack.
Align StackAlignment;
/// Can the stack be realigned. This can be false if the target does not
/// support stack realignment, or if the user asks us not to realign the
/// stack. In this situation, overaligned allocas are all treated as dynamic
/// allocations and the target must handle them as part of DYNAMIC_STACKALLOC
/// lowering. All non-alloca stack objects have their alignment clamped to the
/// base ABI stack alignment.
/// FIXME: There is room for improvement in this case, in terms of
/// grouping overaligned allocas into a "secondary stack frame" and
/// then only use a single alloca to allocate this frame and only a
/// single virtual register to access it. Currently, without such an
/// optimization, each such alloca gets its own dynamic realignment.
bool StackRealignable;
/// Whether the function has the \c alignstack attribute.
bool ForcedRealign;
/// The list of stack objects allocated.
std::vector<StackObject> Objects;
/// This contains the number of fixed objects contained on
/// the stack. Because fixed objects are stored at a negative index in the
/// Objects list, this is also the index to the 0th object in the list.
unsigned NumFixedObjects = 0;
/// This boolean keeps track of whether any variable
/// sized objects have been allocated yet.
bool HasVarSizedObjects = false;
/// This boolean keeps track of whether there is a call
/// to builtin \@llvm.frameaddress.
bool FrameAddressTaken = false;
/// This boolean keeps track of whether there is a call
/// to builtin \@llvm.returnaddress.
bool ReturnAddressTaken = false;
/// This boolean keeps track of whether there is a call
/// to builtin \@llvm.experimental.stackmap.
bool HasStackMap = false;
/// This boolean keeps track of whether there is a call
/// to builtin \@llvm.experimental.patchpoint.
bool HasPatchPoint = false;
/// The prolog/epilog code inserter calculates the final stack
/// offsets for all of the fixed size objects, updating the Objects list
/// above. It then updates StackSize to contain the number of bytes that need
/// to be allocated on entry to the function.
uint64_t StackSize = 0;
/// The amount that a frame offset needs to be adjusted to
/// have the actual offset from the stack/frame pointer. The exact usage of
/// this is target-dependent, but it is typically used to adjust between
/// SP-relative and FP-relative offsets. E.G., if objects are accessed via
/// SP then OffsetAdjustment is zero; if FP is used, OffsetAdjustment is set
/// to the distance between the initial SP and the value in FP. For many
/// targets, this value is only used when generating debug info (via
/// TargetRegisterInfo::getFrameIndexReference); when generating code, the
/// corresponding adjustments are performed directly.
int OffsetAdjustment = 0;
/// The prolog/epilog code inserter may process objects that require greater
/// alignment than the default alignment the target provides.
/// To handle this, MaxAlignment is set to the maximum alignment
/// needed by the objects on the current frame. If this is greater than the
/// native alignment maintained by the compiler, dynamic alignment code will
/// be needed.
///
Align MaxAlignment;
/// Set to true if this function adjusts the stack -- e.g.,
/// when calling another function. This is only valid during and after
/// prolog/epilog code insertion.
bool AdjustsStack = false;
/// Set to true if this function has any function calls.
bool HasCalls = false;
/// The frame index for the stack protector.
int StackProtectorIdx = -1;
/// The frame index for the function context. Used for SjLj exceptions.
int FunctionContextIdx = -1;
/// This contains the size of the largest call frame if the target uses frame
/// setup/destroy pseudo instructions (as defined in the TargetFrameInfo
/// class). This information is important for frame pointer elimination.
/// It is only valid during and after prolog/epilog code insertion.
unsigned MaxCallFrameSize = ~0u;
/// The number of bytes of callee saved registers that the target wants to
/// report for the current function in the CodeView S_FRAMEPROC record.
unsigned CVBytesOfCalleeSavedRegisters = 0;
/// The prolog/epilog code inserter fills in this vector with each
/// callee saved register saved in either the frame or a different
/// register. Beyond its use by the prolog/ epilog code inserter,
/// this data is used for debug info and exception handling.
std::vector<CalleeSavedInfo> CSInfo;
/// Has CSInfo been set yet?
bool CSIValid = false;
/// References to frame indices which are mapped
/// into the local frame allocation block. <FrameIdx, LocalOffset>
SmallVector<std::pair<int, int64_t>, 32> LocalFrameObjects;
/// Size of the pre-allocated local frame block.
int64_t LocalFrameSize = 0;
/// Required alignment of the local object blob, which is the strictest
/// alignment of any object in it.
Align LocalFrameMaxAlign;
/// Whether the local object blob needs to be allocated together. If not,
/// PEI should ignore the isPreAllocated flags on the stack objects and
/// just allocate them normally.
bool UseLocalStackAllocationBlock = false;
/// True if the function dynamically adjusts the stack pointer through some
/// opaque mechanism like inline assembly or Win32 EH.
bool HasOpaqueSPAdjustment = false;
/// True if the function contains operations which will lower down to
/// instructions which manipulate the stack pointer.
bool HasCopyImplyingStackAdjustment = false;
/// True if the function contains a call to the llvm.vastart intrinsic.
bool HasVAStart = false;
/// True if this is a varargs function that contains a musttail call.
bool HasMustTailInVarArgFunc = false;
/// True if this function contains a tail call. If so immutable objects like
/// function arguments are no longer so. A tail call *can* override fixed
/// stack objects like arguments so we can't treat them as immutable.
bool HasTailCall = false;
/// Not null, if shrink-wrapping found a better place for the prologue.
MachineBasicBlock *Save = nullptr;
/// Not null, if shrink-wrapping found a better place for the epilogue.
MachineBasicBlock *Restore = nullptr;
public:
explicit MachineFrameInfo(unsigned StackAlignment, bool StackRealignable,
bool ForcedRealign)
: StackAlignment(assumeAligned(StackAlignment)),
StackRealignable(StackRealignable), ForcedRealign(ForcedRealign) {}
/// Return true if there are any stack objects in this function.
bool hasStackObjects() const { return !Objects.empty(); }
/// This method may be called any time after instruction
/// selection is complete to determine if the stack frame for this function
/// contains any variable sized objects.
bool hasVarSizedObjects() const { return HasVarSizedObjects; }
/// Return the index for the stack protector object.
int getStackProtectorIndex() const { return StackProtectorIdx; }
void setStackProtectorIndex(int I) { StackProtectorIdx = I; }
bool hasStackProtectorIndex() const { return StackProtectorIdx != -1; }
/// Return the index for the function context object.
/// This object is used for SjLj exceptions.
int getFunctionContextIndex() const { return FunctionContextIdx; }
void setFunctionContextIndex(int I) { FunctionContextIdx = I; }
/// This method may be called any time after instruction
/// selection is complete to determine if there is a call to
/// \@llvm.frameaddress in this function.
bool isFrameAddressTaken() const { return FrameAddressTaken; }
void setFrameAddressIsTaken(bool T) { FrameAddressTaken = T; }
/// This method may be called any time after
/// instruction selection is complete to determine if there is a call to
/// \@llvm.returnaddress in this function.
bool isReturnAddressTaken() const { return ReturnAddressTaken; }
void setReturnAddressIsTaken(bool s) { ReturnAddressTaken = s; }
/// This method may be called any time after instruction
/// selection is complete to determine if there is a call to builtin
/// \@llvm.experimental.stackmap.
bool hasStackMap() const { return HasStackMap; }
void setHasStackMap(bool s = true) { HasStackMap = s; }
/// This method may be called any time after instruction
/// selection is complete to determine if there is a call to builtin
/// \@llvm.experimental.patchpoint.
bool hasPatchPoint() const { return HasPatchPoint; }
void setHasPatchPoint(bool s = true) { HasPatchPoint = s; }
/// Return the minimum frame object index.
int getObjectIndexBegin() const { return -NumFixedObjects; }
/// Return one past the maximum frame object index.
int getObjectIndexEnd() const { return (int)Objects.size()-NumFixedObjects; }
/// Return the number of fixed objects.
unsigned getNumFixedObjects() const { return NumFixedObjects; }
/// Return the number of objects.
unsigned getNumObjects() const { return Objects.size(); }
/// Map a frame index into the local object block
void mapLocalFrameObject(int ObjectIndex, int64_t Offset) {
LocalFrameObjects.push_back(std::pair<int, int64_t>(ObjectIndex, Offset));
Objects[ObjectIndex + NumFixedObjects].PreAllocated = true;
}
/// Get the local offset mapping for a for an object.
std::pair<int, int64_t> getLocalFrameObjectMap(int i) const {
assert (i >= 0 && (unsigned)i < LocalFrameObjects.size() &&
"Invalid local object reference!");
return LocalFrameObjects[i];
}
/// Return the number of objects allocated into the local object block.
int64_t getLocalFrameObjectCount() const { return LocalFrameObjects.size(); }
/// Set the size of the local object blob.
void setLocalFrameSize(int64_t sz) { LocalFrameSize = sz; }
/// Get the size of the local object blob.
int64_t getLocalFrameSize() const { return LocalFrameSize; }
/// Required alignment of the local object blob,
/// which is the strictest alignment of any object in it.
void setLocalFrameMaxAlign(Align Alignment) {
LocalFrameMaxAlign = Alignment;
}
/// Return the required alignment of the local object blob.
Align getLocalFrameMaxAlign() const { return LocalFrameMaxAlign; }
/// Get whether the local allocation blob should be allocated together or
/// let PEI allocate the locals in it directly.
bool getUseLocalStackAllocationBlock() const {
return UseLocalStackAllocationBlock;
}
/// setUseLocalStackAllocationBlock - Set whether the local allocation blob
/// should be allocated together or let PEI allocate the locals in it
/// directly.
void setUseLocalStackAllocationBlock(bool v) {
UseLocalStackAllocationBlock = v;
}
/// Return true if the object was pre-allocated into the local block.
bool isObjectPreAllocated(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].PreAllocated;
}
/// Return the size of the specified object.
int64_t getObjectSize(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].Size;
}
/// Change the size of the specified stack object.
void setObjectSize(int ObjectIdx, int64_t Size) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].Size = Size;
}
/// Return the alignment of the specified stack object.
unsigned getObjectAlignment(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx + NumFixedObjects].Alignment.value();
}
/// setObjectAlignment - Change the alignment of the specified stack object.
void setObjectAlignment(int ObjectIdx, unsigned Align) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx + NumFixedObjects].Alignment = assumeAligned(Align);
// Only ensure max alignment for the default stack.
if (getStackID(ObjectIdx) == 0)
ensureMaxAlignment(Align);
}
/// Return the underlying Alloca of the specified
/// stack object if it exists. Returns 0 if none exists.
const AllocaInst* getObjectAllocation(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].Alloca;
}
/// Return the assigned stack offset of the specified object
/// from the incoming stack pointer.
int64_t getObjectOffset(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
assert(!isDeadObjectIndex(ObjectIdx) &&
"Getting frame offset for a dead object?");
return Objects[ObjectIdx+NumFixedObjects].SPOffset;
}
bool isObjectZExt(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isZExt;
}
void setObjectZExt(int ObjectIdx, bool IsZExt) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].isZExt = IsZExt;
}
bool isObjectSExt(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isSExt;
}
void setObjectSExt(int ObjectIdx, bool IsSExt) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].isSExt = IsSExt;
}
/// Set the stack frame offset of the specified object. The
/// offset is relative to the stack pointer on entry to the function.
void setObjectOffset(int ObjectIdx, int64_t SPOffset) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
assert(!isDeadObjectIndex(ObjectIdx) &&
"Setting frame offset for a dead object?");
Objects[ObjectIdx+NumFixedObjects].SPOffset = SPOffset;
}
SSPLayoutKind getObjectSSPLayout(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return (SSPLayoutKind)Objects[ObjectIdx+NumFixedObjects].SSPLayout;
}
void setObjectSSPLayout(int ObjectIdx, SSPLayoutKind Kind) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
assert(!isDeadObjectIndex(ObjectIdx) &&
"Setting SSP layout for a dead object?");
Objects[ObjectIdx+NumFixedObjects].SSPLayout = Kind;
}
/// Return the number of bytes that must be allocated to hold
/// all of the fixed size frame objects. This is only valid after
/// Prolog/Epilog code insertion has finalized the stack frame layout.
uint64_t getStackSize() const { return StackSize; }
/// Set the size of the stack.
void setStackSize(uint64_t Size) { StackSize = Size; }
/// Estimate and return the size of the stack frame.
unsigned estimateStackSize(const MachineFunction &MF) const;
/// Return the correction for frame offsets.
int getOffsetAdjustment() const { return OffsetAdjustment; }
/// Set the correction for frame offsets.
void setOffsetAdjustment(int Adj) { OffsetAdjustment = Adj; }
/// Return the alignment in bytes that this function must be aligned to,
/// which is greater than the default stack alignment provided by the target.
unsigned getMaxAlignment() const { return MaxAlignment.value(); }
/// Make sure the function is at least Align bytes aligned.
void ensureMaxAlignment(Align Alignment);
/// FIXME: Remove this once transition to Align is over.
inline void ensureMaxAlignment(unsigned Align) {
ensureMaxAlignment(assumeAligned(Align));
}
/// Return true if this function adjusts the stack -- e.g.,
/// when calling another function. This is only valid during and after
/// prolog/epilog code insertion.
bool adjustsStack() const { return AdjustsStack; }
void setAdjustsStack(bool V) { AdjustsStack = V; }
/// Return true if the current function has any function calls.
bool hasCalls() const { return HasCalls; }
void setHasCalls(bool V) { HasCalls = V; }
/// Returns true if the function contains opaque dynamic stack adjustments.
bool hasOpaqueSPAdjustment() const { return HasOpaqueSPAdjustment; }
void setHasOpaqueSPAdjustment(bool B) { HasOpaqueSPAdjustment = B; }
/// Returns true if the function contains operations which will lower down to
/// instructions which manipulate the stack pointer.
bool hasCopyImplyingStackAdjustment() const {
return HasCopyImplyingStackAdjustment;
}
void setHasCopyImplyingStackAdjustment(bool B) {
HasCopyImplyingStackAdjustment = B;
}
/// Returns true if the function calls the llvm.va_start intrinsic.
bool hasVAStart() const { return HasVAStart; }
void setHasVAStart(bool B) { HasVAStart = B; }
/// Returns true if the function is variadic and contains a musttail call.
bool hasMustTailInVarArgFunc() const { return HasMustTailInVarArgFunc; }
void setHasMustTailInVarArgFunc(bool B) { HasMustTailInVarArgFunc = B; }
/// Returns true if the function contains a tail call.
bool hasTailCall() const { return HasTailCall; }
void setHasTailCall() { HasTailCall = true; }
/// Computes the maximum size of a callframe and the AdjustsStack property.
/// This only works for targets defining
/// TargetInstrInfo::getCallFrameSetupOpcode(), getCallFrameDestroyOpcode(),
/// and getFrameSize().
/// This is usually computed by the prologue epilogue inserter but some
/// targets may call this to compute it earlier.
void computeMaxCallFrameSize(const MachineFunction &MF);
/// Return the maximum size of a call frame that must be
/// allocated for an outgoing function call. This is only available if
/// CallFrameSetup/Destroy pseudo instructions are used by the target, and
/// then only during or after prolog/epilog code insertion.
///
unsigned getMaxCallFrameSize() const {
// TODO: Enable this assert when targets are fixed.
//assert(isMaxCallFrameSizeComputed() && "MaxCallFrameSize not computed yet");
if (!isMaxCallFrameSizeComputed())
return 0;
return MaxCallFrameSize;
}
bool isMaxCallFrameSizeComputed() const {
return MaxCallFrameSize != ~0u;
}
void setMaxCallFrameSize(unsigned S) { MaxCallFrameSize = S; }
/// Returns how many bytes of callee-saved registers the target pushed in the
/// prologue. Only used for debug info.
unsigned getCVBytesOfCalleeSavedRegisters() const {
return CVBytesOfCalleeSavedRegisters;
}
void setCVBytesOfCalleeSavedRegisters(unsigned S) {
CVBytesOfCalleeSavedRegisters = S;
}
/// Create a new object at a fixed location on the stack.
/// All fixed objects should be created before other objects are created for
/// efficiency. By default, fixed objects are not pointed to by LLVM IR
/// values. This returns an index with a negative value.
int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable,
bool isAliased = false);
/// Create a spill slot at a fixed location on the stack.
/// Returns an index with a negative value.
int CreateFixedSpillStackObject(uint64_t Size, int64_t SPOffset,
bool IsImmutable = false);
/// Returns true if the specified index corresponds to a fixed stack object.
bool isFixedObjectIndex(int ObjectIdx) const {
return ObjectIdx < 0 && (ObjectIdx >= -(int)NumFixedObjects);
}
/// Returns true if the specified index corresponds
/// to an object that might be pointed to by an LLVM IR value.
bool isAliasedObjectIndex(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isAliased;
}
/// Returns true if the specified index corresponds to an immutable object.
bool isImmutableObjectIndex(int ObjectIdx) const {
// Tail calling functions can clobber their function arguments.
if (HasTailCall)
return false;
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isImmutable;
}
/// Marks the immutability of an object.
void setIsImmutableObjectIndex(int ObjectIdx, bool IsImmutable) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].isImmutable = IsImmutable;
}
/// Returns true if the specified index corresponds to a spill slot.
bool isSpillSlotObjectIndex(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isSpillSlot;
}
bool isStatepointSpillSlotObjectIndex(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isStatepointSpillSlot;
}
/// \see StackID
uint8_t getStackID(int ObjectIdx) const {
return Objects[ObjectIdx+NumFixedObjects].StackID;
}
/// \see StackID
void setStackID(int ObjectIdx, uint8_t ID) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].StackID = ID;
// If ID > 0, MaxAlignment may now be overly conservative.
// If ID == 0, MaxAlignment will need to be updated separately.
}
/// Returns true if the specified index corresponds to a dead object.
bool isDeadObjectIndex(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].Size == ~0ULL;
}
/// Returns true if the specified index corresponds to a variable sized
/// object.
bool isVariableSizedObjectIndex(int ObjectIdx) const {
assert(unsigned(ObjectIdx + NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx + NumFixedObjects].Size == 0;
}
void markAsStatepointSpillSlotObjectIndex(int ObjectIdx) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].isStatepointSpillSlot = true;
assert(isStatepointSpillSlotObjectIndex(ObjectIdx) && "inconsistent");
}
/// Create a new statically sized stack object, returning
/// a nonnegative identifier to represent it.
int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot,
const AllocaInst *Alloca = nullptr, uint8_t ID = 0);
/// FIXME: Remove this function when transition to Align is over.
inline int CreateStackObject(uint64_t Size, unsigned Alignment,
bool isSpillSlot,
const AllocaInst *Alloca = nullptr,
uint8_t ID = 0) {
return CreateStackObject(Size, assumeAligned(Alignment), isSpillSlot,
Alloca, ID);
}
/// Create a new statically sized stack object that represents a spill slot,
/// returning a nonnegative identifier to represent it.
int CreateSpillStackObject(uint64_t Size, Align Alignment);
/// FIXME: Remove this function when transition to Align is over.
inline int CreateSpillStackObject(uint64_t Size, unsigned Alignment) {
return CreateSpillStackObject(Size, assumeAligned(Alignment));
}
/// Remove or mark dead a statically sized stack object.
void RemoveStackObject(int ObjectIdx) {
// Mark it dead.
Objects[ObjectIdx+NumFixedObjects].Size = ~0ULL;
}
/// Notify the MachineFrameInfo object that a variable sized object has been
/// created. This must be created whenever a variable sized object is
/// created, whether or not the index returned is actually used.
int CreateVariableSizedObject(Align Alignment, const AllocaInst *Alloca);
/// FIXME: Remove this function when transition to Align is over.
int CreateVariableSizedObject(unsigned Alignment, const AllocaInst *Alloca) {
return CreateVariableSizedObject(assumeAligned(Alignment), Alloca);
}
/// Returns a reference to call saved info vector for the current function.
const std::vector<CalleeSavedInfo> &getCalleeSavedInfo() const {
return CSInfo;
}
/// \copydoc getCalleeSavedInfo()
std::vector<CalleeSavedInfo> &getCalleeSavedInfo() { return CSInfo; }
/// Used by prolog/epilog inserter to set the function's callee saved
/// information.
void setCalleeSavedInfo(const std::vector<CalleeSavedInfo> &CSI) {
CSInfo = CSI;
}
/// Has the callee saved info been calculated yet?
bool isCalleeSavedInfoValid() const { return CSIValid; }
void setCalleeSavedInfoValid(bool v) { CSIValid = v; }
MachineBasicBlock *getSavePoint() const { return Save; }
void setSavePoint(MachineBasicBlock *NewSave) { Save = NewSave; }
MachineBasicBlock *getRestorePoint() const { return Restore; }
void setRestorePoint(MachineBasicBlock *NewRestore) { Restore = NewRestore; }
/// Return a set of physical registers that are pristine.
///
/// Pristine registers hold a value that is useless to the current function,
/// but that must be preserved - they are callee saved registers that are not
/// saved.
///
/// Before the PrologueEpilogueInserter has placed the CSR spill code, this
/// method always returns an empty set.
BitVector getPristineRegs(const MachineFunction &MF) const;
/// Used by the MachineFunction printer to print information about
/// stack objects. Implemented in MachineFunction.cpp.
void print(const MachineFunction &MF, raw_ostream &OS) const;
/// dump - Print the function to stderr.
void dump(const MachineFunction &MF) const;
};
} // End llvm namespace
#endif
|