llvm.org GIT mirror llvm / f0a04c0
[WinEH] Mark funclet entries and exits as clobbering all registers Summary: In this implementation, LiveIntervalAnalysis invents a few register masks on basic block boundaries that preserve no registers. The nice thing about this is that it prevents the prologue inserter from thinking it needs to spill all XMM CSRs, because it doesn't see any explicit physreg defs in the MI. Reviewers: MatzeB, qcolombet, JosephTremoulet, majnemer Subscribers: MatzeB, llvm-commits Differential Revision: http://reviews.llvm.org/D14407 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252318 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 4 years ago
9 changed file(s) with 223 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
375375 return make_range(livein_begin(), livein_end());
376376 }
377377
378 /// Get the clobber mask for the start of this basic block. Funclets use this
379 /// to prevent register allocation across funclet transitions.
380 const uint32_t *getBeginClobberMask(const TargetRegisterInfo *TRI) const;
381
382 /// Get the clobber mask for the end of the basic block.
383 /// \see getBeginClobberMask()
384 const uint32_t *getEndClobberMask(const TargetRegisterInfo *TRI) const;
385
378386 /// Return alignment of the basic block. The alignment is specified as
379387 /// log2(bytes).
380388 unsigned getAlignment() const { return Alignment; }
547555 return const_cast(this)->getLastNonDebugInstr();
548556 }
549557
550 /// Convenience function that returns true if the block has no successors and
551 /// contains a return instruction.
558 /// Convenience function that returns true if the block ends in a return
559 /// instruction.
552560 bool isReturnBlock() const {
553561 return !empty() && back().isReturn();
554562 }
472472 CallingConv::ID) const {
473473 // The default mask clobbers everything. All targets should override.
474474 return nullptr;
475 }
476
477 /// Return a register mask that clobbers everything.
478 virtual const uint32_t *getNoPreservedMask() const {
479 llvm_unreachable("target does not provide no presered mask");
475480 }
476481
477482 /// Return all the call-preserved register masks defined for this target.
224224 for (MachineBasicBlock &MBB : *MF) {
225225 std::pair &RMB = RegMaskBlocks[MBB.getNumber()];
226226 RMB.first = RegMaskSlots.size();
227
228 // Some block starts, such as EH funclets, create masks.
229 if (const uint32_t *Mask = MBB.getBeginClobberMask(TRI)) {
230 RegMaskSlots.push_back(Indexes->getMBBStartIdx(&MBB));
231 RegMaskBits.push_back(Mask);
232 }
233
227234 for (MachineInstr &MI : MBB) {
228235 for (const MachineOperand &MO : MI.operands()) {
229236 if (!MO.isRegMask())
232239 RegMaskBits.push_back(MO.getRegMask());
233240 }
234241 }
242
243 // Some block ends, such as funclet returns, create masks.
244 if (const uint32_t *Mask = MBB.getEndClobberMask(TRI)) {
245 RegMaskSlots.push_back(Indexes->getMBBEndIdx(&MBB));
246 RegMaskBits.push_back(Mask);
247 }
248
235249 // Compute the number of register mask instructions in this block.
236250 RMB.second = RegMaskSlots.size() - RMB.first;
237251 }
13001300 // At this point we have no idea of the liveness of the register.
13011301 return LQR_Unknown;
13021302 }
1303
1304 const uint32_t *
1305 MachineBasicBlock::getBeginClobberMask(const TargetRegisterInfo *TRI) const {
1306 // EH funclet entry does not preserve any registers.
1307 return isEHFuncletEntry() ? TRI->getNoPreservedMask() : nullptr;
1308 }
1309
1310 const uint32_t *
1311 MachineBasicBlock::getEndClobberMask(const TargetRegisterInfo *TRI) const {
1312 // If we see a return block with successors, this must be a funclet return,
1313 // which does not preserve any registers. If there are no successors, we don't
1314 // care what kind of return it is, putting a mask after it is a no-op.
1315 return isReturnBlock() && !succ_empty() ? TRI->getNoPreservedMask() : nullptr;
1316 }
9393 const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
9494 const uint32_t *getCallPreservedMask(const MachineFunction &MF,
9595 CallingConv::ID) const override;
96 const uint32_t *getNoPreservedMask() const;
96 const uint32_t *getNoPreservedMask() const override;
9797
9898 /// getThisReturnPreservedMask - Returns a call preserved mask specific to the
9999 /// case that 'returned' is on an i32 first argument if the calling convention
7676 const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
7777 const uint32_t *getCallPreservedMask(const MachineFunction &MF,
7878 CallingConv::ID CC) const override;
79 const uint32_t *getNoPreservedMask() const;
79 const uint32_t *getNoPreservedMask() const override;
8080
8181 void adjustStackMapLiveOutMask(uint32_t *Mask) const override;
8282
9595 getCalleeSavedRegs(const MachineFunction* MF) const override;
9696 const uint32_t *getCallPreservedMask(const MachineFunction &MF,
9797 CallingConv::ID) const override;
98 const uint32_t *getNoPreservedMask() const;
98 const uint32_t *getNoPreservedMask() const override;
9999
100100 /// getReservedRegs - Returns a bitset indexed by physical register number
101101 /// indicating if a register is a special register that has particular uses and
0 ; RUN: llc < %s | FileCheck %s
1
2 ; Based on this code:
3 ;
4 ; extern "C" int array[4];
5 ; extern "C" void global_array(int idx1, int idx2, int idx3) {
6 ; try {
7 ; array[idx1] = 111;
8 ; throw;
9 ; } catch (...) {
10 ; array[idx2] = 222;
11 ; }
12 ; array[idx3] = 333;
13 ; }
14 ; extern "C" __declspec(dllimport) int imported;
15 ; extern "C" void access_imported() {
16 ; try {
17 ; imported = 111;
18 ; throw;
19 ; } catch (...) {
20 ; imported = 222;
21 ; }
22 ; imported = 333;
23 ; }
24
25 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
26 target triple = "x86_64-pc-windows-msvc18.0.0"
27
28 %eh.ThrowInfo = type { i32, i32, i32, i32 }
29
30 @array = external global [4 x i32], align 16
31 @imported = external dllimport global i32, align 4
32
33 ; Function Attrs: uwtable
34 define void @global_array(i32 %idx1, i32 %idx2, i32 %idx3) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
35 entry:
36 %idxprom = sext i32 %idx1 to i64
37 %arrayidx = getelementptr inbounds [4 x i32], [4 x i32]* @array, i64 0, i64 %idxprom
38 store i32 111, i32* %arrayidx, align 4, !tbaa !2
39 invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1
40 to label %unreachable unwind label %catch.dispatch
41
42 catch.dispatch: ; preds = %entry
43 %0 = catchpad [i8* null, i32 64, i8* null]
44 to label %catch unwind label %catchendblock
45
46 catch: ; preds = %catch.dispatch
47 %idxprom1 = sext i32 %idx2 to i64
48 %arrayidx2 = getelementptr inbounds [4 x i32], [4 x i32]* @array, i64 0, i64 %idxprom1
49 store i32 222, i32* %arrayidx2, align 4, !tbaa !2
50 catchret %0 to label %try.cont
51
52 try.cont: ; preds = %catch
53 %idxprom3 = sext i32 %idx3 to i64
54 %arrayidx4 = getelementptr inbounds [4 x i32], [4 x i32]* @array, i64 0, i64 %idxprom3
55 store i32 333, i32* %arrayidx4, align 4, !tbaa !2
56 ret void
57
58 catchendblock: ; preds = %catch.dispatch
59 catchendpad unwind to caller
60
61 unreachable: ; preds = %entry
62 unreachable
63 }
64
65 ; CHECK-LABEL: global_array: # @global_array
66 ; CHECK: pushq %rbp
67 ; First array access
68 ; CHECK: movslq %ecx, %[[idx:[^ ]*]]
69 ; CHECK: leaq array(%rip), %[[base:[^ ]*]]
70 ; CHECK: movl $111, (%[[base]],%[[idx]],4)
71 ; Might throw an exception and return to below...
72 ; CHECK: callq _CxxThrowException
73 ; Third array access must remat the address of array
74 ; CHECK: movslq {{.*}}, %[[idx:[^ ]*]]
75 ; CHECK: leaq array(%rip), %[[base:[^ ]*]]
76 ; CHECK: movl $333, (%[[base]],%[[idx]],4)
77 ; CHECK: popq %rbp
78 ; CHECK: retq
79
80 ; CHECK: "?catch$2@?0?global_array@4HA":
81 ; CHECK: pushq %rbp
82 ; CHECK: movslq {{.*}}, %[[idx:[^ ]*]]
83 ; CHECK: leaq array(%rip), %[[base:[^ ]*]]
84 ; CHECK: movl $222, (%[[base]],%[[idx]],4)
85 ; CHECK: popq %rbp
86 ; CHECK: retq # CATCHRET
87
88 declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
89
90 declare i32 @__CxxFrameHandler3(...)
91
92 ; Function Attrs: uwtable
93 define void @access_imported() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
94 entry:
95 store i32 111, i32* @imported, align 4, !tbaa !2
96 invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1
97 to label %unreachable unwind label %catch.dispatch
98
99 catch.dispatch: ; preds = %entry
100 %0 = catchpad [i8* null, i32 64, i8* null]
101 to label %catch unwind label %catchendblock
102
103 catch: ; preds = %catch.dispatch
104 store i32 222, i32* @imported, align 4, !tbaa !2
105 catchret %0 to label %try.cont
106
107 try.cont: ; preds = %catch
108 store i32 333, i32* @imported, align 4, !tbaa !2
109 ret void
110
111 catchendblock: ; preds = %catch.dispatch
112 catchendpad unwind to caller
113
114 unreachable: ; preds = %entry
115 unreachable
116 }
117
118 ; CHECK-LABEL: access_imported: # @access_imported
119 ; CHECK: pushq %rbp
120 ; CHECK: movq __imp_imported(%rip), %[[base:[^ ]*]]
121 ; CHECK: movl $111, (%[[base]])
122 ; Might throw an exception and return to below...
123 ; CHECK: callq _CxxThrowException
124 ; Third access must reload the address of imported
125 ; CHECK: movq __imp_imported(%rip), %[[base:[^ ]*]]
126 ; CHECK: movl $333, (%[[base]])
127 ; CHECK: popq %rbp
128 ; CHECK: retq
129
130 ; CHECK: "?catch$2@?0?access_imported@4HA":
131 ; CHECK: pushq %rbp
132 ; CHECK: movq __imp_imported(%rip), %[[base:[^ ]*]]
133 ; CHECK: movl $222, (%[[base]])
134 ; CHECK: popq %rbp
135 ; CHECK: retq # CATCHRET
136
137
138 attributes #0 = { uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" }
139 attributes #1 = { noreturn }
140
141 !llvm.module.flags = !{!0}
142 !llvm.ident = !{!1}
143
144 !0 = !{i32 1, !"PIC Level", i32 2}
145 !1 = !{!"clang version 3.8.0 "}
146 !2 = !{!3, !3, i64 0}
147 !3 = !{!"int", !4, i64 0}
148 !4 = !{!"omnipotent char", !5, i64 0}
149 !5 = !{!"Simple C/C++ TBAA"}
0 ; RUN: llc -mtriple=x86_64-pc-windows-msvc -code-model=large -o - < %s | FileCheck %s
1
2 declare i32 @__CxxFrameHandler3(...)
3
4 declare void @bar()
5
6 define void @foo() personality i32 (...)* @__CxxFrameHandler3 {
7 entry:
8 invoke void @bar()
9 to label %exit unwind label %cleanup
10 cleanup:
11 %c = cleanuppad []
12 call void @bar()
13 cleanupret %c unwind to caller
14 exit:
15 ret void
16 }
17
18 ; CHECK: foo: # @foo
19 ; CHECK: movabsq $bar, %[[reg:[^ ]*]]
20 ; CHECK: callq *%[[reg]]
21 ; CHECK: retq
22
23 ; CHECK: "?dtor$2@?0?foo@4HA":
24 ; CHECK: movabsq $bar, %[[reg:[^ ]*]]
25 ; CHECK: callq *%[[reg]]
26 ; CHECK: retq # CLEANUPRET