22
22
// With the help of a runtime that understands the .fault_maps section,
23
23
// faulting_load_op branches to throw_npe if executing movl (%r10), %esi incurs
24
24
// a page fault.
25
+ // Store is also supported.
25
26
//
26
27
// ===----------------------------------------------------------------------===//
27
28
28
29
#include " llvm/ADT/DenseSet.h"
29
30
#include " llvm/ADT/SmallVector.h"
30
31
#include " llvm/ADT/Statistic.h"
31
32
#include " llvm/Analysis/AliasAnalysis.h"
33
+ #include " llvm/CodeGen/FaultMaps.h"
32
34
#include " llvm/CodeGen/Passes.h"
33
35
#include " llvm/CodeGen/MachineFunction.h"
34
36
#include " llvm/CodeGen/MachineMemOperand.h"
@@ -154,8 +156,8 @@ class ImplicitNullChecks : public MachineFunctionPass {
154
156
155
157
bool analyzeBlockForNullChecks (MachineBasicBlock &MBB,
156
158
SmallVectorImpl<NullCheck> &NullCheckList);
157
- MachineInstr *insertFaultingLoad (MachineInstr *LoadMI , MachineBasicBlock *MBB,
158
- MachineBasicBlock *HandlerMBB);
159
+ MachineInstr *insertFaultingInstr (MachineInstr *MI , MachineBasicBlock *MBB,
160
+ MachineBasicBlock *HandlerMBB);
159
161
void rewriteNullChecks (ArrayRef<NullCheck> NullCheckList);
160
162
161
163
enum SuitabilityResult { SR_Suitable, SR_Unsuitable, SR_Impossible };
@@ -165,16 +167,18 @@ class ImplicitNullChecks : public MachineFunctionPass {
165
167
// / \p MI cannot be used to null check and SR_Impossible if there is
166
168
// / no sense to continue lookup due to any other instruction will not be able
167
169
// / to be used. \p PrevInsts is the set of instruction seen since
168
- // / the explicit null check on \p PointerReg.
170
+ // / the explicit null check on \p PointerReg. \p SeenLoad means that load
171
+ // / instruction has been observed in \PrevInsts set.
169
172
SuitabilityResult isSuitableMemoryOp (MachineInstr &MI, unsigned PointerReg,
170
- ArrayRef<MachineInstr *> PrevInsts);
173
+ ArrayRef<MachineInstr *> PrevInsts,
174
+ bool &SeenLoad);
171
175
172
176
// / Return true if \p FaultingMI can be hoisted from after the the
173
177
// / instructions in \p InstsSeenSoFar to before them. Set \p Dependence to a
174
178
// / non-null value if we also need to (and legally can) hoist a depedency.
175
- bool canHoistLoadInst (MachineInstr *FaultingMI, unsigned PointerReg,
176
- ArrayRef<MachineInstr *> InstsSeenSoFar,
177
- MachineBasicBlock *NullSucc, MachineInstr *&Dependence);
179
+ bool canHoistInst (MachineInstr *FaultingMI, unsigned PointerReg,
180
+ ArrayRef<MachineInstr *> InstsSeenSoFar,
181
+ MachineBasicBlock *NullSucc, MachineInstr *&Dependence);
178
182
179
183
public:
180
184
static char ID;
@@ -198,7 +202,7 @@ class ImplicitNullChecks : public MachineFunctionPass {
198
202
}
199
203
200
204
bool ImplicitNullChecks::canHandle (const MachineInstr *MI) {
201
- if (MI->isCall () || MI->mayStore () || MI-> hasUnmodeledSideEffects ())
205
+ if (MI->isCall () || MI->hasUnmodeledSideEffects ())
202
206
return false ;
203
207
auto IsRegMask = [](const MachineOperand &MO) { return MO.isRegMask (); };
204
208
(void )IsRegMask;
@@ -290,22 +294,36 @@ static bool AnyAliasLiveIn(const TargetRegisterInfo *TRI,
290
294
291
295
ImplicitNullChecks::SuitabilityResult
292
296
ImplicitNullChecks::isSuitableMemoryOp (MachineInstr &MI, unsigned PointerReg,
293
- ArrayRef<MachineInstr *> PrevInsts) {
297
+ ArrayRef<MachineInstr *> PrevInsts,
298
+ bool &SeenLoad) {
294
299
int64_t Offset;
295
300
unsigned BaseReg;
296
301
302
+ // First, if it is a store and we saw load before we bail out
303
+ // because we will not be able to re-order load-store without
304
+ // using alias analysis.
305
+ if (SeenLoad && MI.mayStore ())
306
+ return SR_Impossible;
307
+
308
+ SeenLoad = SeenLoad || MI.mayLoad ();
309
+
310
+ // Without alias analysis we cannot re-order store with anything.
311
+ // so if this instruction is not a candidate we should stop.
312
+ SuitabilityResult Unsuitable = MI.mayStore () ? SR_Impossible : SR_Unsuitable;
313
+
297
314
if (!TII->getMemOpBaseRegImmOfs (MI, BaseReg, Offset, TRI) ||
298
315
BaseReg != PointerReg)
299
- return SR_Unsuitable ;
316
+ return Unsuitable ;
300
317
301
- // We want the load to be issued at a sane offset from PointerReg, so that
302
- // if PointerReg is null then the load reliably page faults.
303
- if (!(MI.mayLoad () && !MI.isPredicable () && Offset < PageSize))
304
- return SR_Unsuitable;
318
+ // We want the mem access to be issued at a sane offset from PointerReg,
319
+ // so that if PointerReg is null then the access reliably page faults.
320
+ if (!((MI.mayLoad () || MI.mayStore ()) && !MI.isPredicable () &&
321
+ Offset < PageSize))
322
+ return Unsuitable;
305
323
306
- // Finally, we need to make sure that the load instruction actually is
307
- // loading from PointerReg, and there isn't some re-definition of PointerReg
308
- // between the compare and the load .
324
+ // Finally, we need to make sure that the access instruction actually is
325
+ // accessing from PointerReg, and there isn't some re-definition of PointerReg
326
+ // between the compare and the memory access .
309
327
// If PointerReg has been redefined before then there is no sense to continue
310
328
// lookup due to this condition will fail for any further instruction.
311
329
for (auto *PrevMI : PrevInsts)
@@ -317,10 +335,11 @@ ImplicitNullChecks::isSuitableMemoryOp(MachineInstr &MI, unsigned PointerReg,
317
335
return SR_Suitable;
318
336
}
319
337
320
- bool ImplicitNullChecks::canHoistLoadInst (
321
- MachineInstr *FaultingMI, unsigned PointerReg,
322
- ArrayRef<MachineInstr *> InstsSeenSoFar, MachineBasicBlock *NullSucc,
323
- MachineInstr *&Dependence) {
338
+ bool ImplicitNullChecks::canHoistInst (MachineInstr *FaultingMI,
339
+ unsigned PointerReg,
340
+ ArrayRef<MachineInstr *> InstsSeenSoFar,
341
+ MachineBasicBlock *NullSucc,
342
+ MachineInstr *&Dependence) {
324
343
auto DepResult = computeDependence (FaultingMI, InstsSeenSoFar);
325
344
if (!DepResult.CanReorder )
326
345
return false ;
@@ -484,17 +503,19 @@ bool ImplicitNullChecks::analyzeBlockForNullChecks(
484
503
const unsigned PointerReg = MBP.LHS .getReg ();
485
504
486
505
SmallVector<MachineInstr *, 8 > InstsSeenSoFar;
506
+ bool SeenLoad = false ;
487
507
488
508
for (auto &MI : *NotNullSucc) {
489
509
if (!canHandle (&MI) || InstsSeenSoFar.size () >= MaxInstsToConsider)
490
510
return false ;
491
511
492
512
MachineInstr *Dependence;
493
- SuitabilityResult SR = isSuitableMemoryOp (MI, PointerReg, InstsSeenSoFar);
513
+ SuitabilityResult SR =
514
+ isSuitableMemoryOp (MI, PointerReg, InstsSeenSoFar, SeenLoad);
494
515
if (SR == SR_Impossible)
495
516
return false ;
496
- if (SR == SR_Suitable && canHoistLoadInst (&MI, PointerReg, InstsSeenSoFar,
497
- NullSucc, Dependence)) {
517
+ if (SR == SR_Suitable &&
518
+ canHoistInst (&MI, PointerReg, InstsSeenSoFar, NullSucc, Dependence)) {
498
519
NullCheckList.emplace_back (&MI, MBP.ConditionDef , &MBB, NotNullSucc,
499
520
NullSucc, Dependence);
500
521
return true ;
@@ -506,36 +527,42 @@ bool ImplicitNullChecks::analyzeBlockForNullChecks(
506
527
return false ;
507
528
}
508
529
509
- // / Wrap a machine load instruction, LoadMI, into a FAULTING_LOAD_OP machine
510
- // / instruction. The FAULTING_LOAD_OP instruction does the same load as LoadMI
511
- // / (defining the same register), and branches to HandlerMBB if the load
512
- // / faults. The FAULTING_LOAD_OP instruction is inserted at the end of MBB.
513
- MachineInstr *
514
- ImplicitNullChecks::insertFaultingLoad (MachineInstr *LoadMI,
515
- MachineBasicBlock *MBB,
516
- MachineBasicBlock *HandlerMBB) {
530
+ // / Wrap a machine instruction, MI, into a FAULTING machine instruction.
531
+ // / The FAULTING instruction does the same load/store as MI
532
+ // / (defining the same register), and branches to HandlerMBB if the mem access
533
+ // / faults. The FAULTING instruction is inserted at the end of MBB.
534
+ MachineInstr *ImplicitNullChecks::insertFaultingInstr (
535
+ MachineInstr *MI, MachineBasicBlock *MBB, MachineBasicBlock *HandlerMBB) {
517
536
const unsigned NoRegister = 0 ; // Guaranteed to be the NoRegister value for
518
537
// all targets.
519
538
520
539
DebugLoc DL;
521
- unsigned NumDefs = LoadMI ->getDesc ().getNumDefs ();
540
+ unsigned NumDefs = MI ->getDesc ().getNumDefs ();
522
541
assert (NumDefs <= 1 && " other cases unhandled!" );
523
542
524
543
unsigned DefReg = NoRegister;
525
544
if (NumDefs != 0 ) {
526
- DefReg = LoadMI ->defs ().begin ()->getReg ();
527
- assert (std::distance (LoadMI ->defs ().begin (), LoadMI ->defs ().end ()) == 1 &&
545
+ DefReg = MI ->defs ().begin ()->getReg ();
546
+ assert (std::distance (MI ->defs ().begin (), MI ->defs ().end ()) == 1 &&
528
547
" expected exactly one def!" );
529
548
}
530
549
531
- auto MIB = BuildMI (MBB, DL, TII->get (TargetOpcode::FAULTING_LOAD_OP), DefReg)
550
+ FaultMaps::FaultKind FK;
551
+ if (MI->mayLoad ())
552
+ FK =
553
+ MI->mayStore () ? FaultMaps::FaultingLoadStore : FaultMaps::FaultingLoad;
554
+ else
555
+ FK = FaultMaps::FaultingStore;
556
+
557
+ auto MIB = BuildMI (MBB, DL, TII->get (TargetOpcode::FAULTING_OP), DefReg)
558
+ .addImm (FK)
532
559
.addMBB (HandlerMBB)
533
- .addImm (LoadMI ->getOpcode ());
560
+ .addImm (MI ->getOpcode ());
534
561
535
- for (auto &MO : LoadMI ->uses ())
562
+ for (auto &MO : MI ->uses ())
536
563
MIB.add (MO);
537
564
538
- MIB.setMemRefs (LoadMI ->memoperands_begin (), LoadMI ->memoperands_end ());
565
+ MIB.setMemRefs (MI ->memoperands_begin (), MI ->memoperands_end ());
539
566
540
567
return MIB;
541
568
}
@@ -556,18 +583,18 @@ void ImplicitNullChecks::rewriteNullChecks(
556
583
NC.getCheckBlock ()->insert (NC.getCheckBlock ()->end (), DepMI);
557
584
}
558
585
559
- // Insert a faulting load where the conditional branch was originally. We
560
- // check earlier ensures that this bit of code motion is legal. We do not
561
- // touch the successors list for any basic block since we haven't changed
562
- // control flow, we've just made it implicit.
563
- MachineInstr *FaultingLoad = insertFaultingLoad (
586
+ // Insert a faulting instruction where the conditional branch was
587
+ // originally. We check earlier ensures that this bit of code motion
588
+ // is legal. We do not touch the successors list for any basic block
589
+ // since we haven't changed control flow, we've just made it implicit.
590
+ MachineInstr *FaultingInstr = insertFaultingInstr (
564
591
NC.getMemOperation (), NC.getCheckBlock (), NC.getNullSucc ());
565
592
// Now the values defined by MemOperation, if any, are live-in of
566
593
// the block of MemOperation.
567
- // The original load operation may define implicit-defs alongside
568
- // the loaded value.
594
+ // The original operation may define implicit-defs alongside
595
+ // the value.
569
596
MachineBasicBlock *MBB = NC.getMemOperation ()->getParent ();
570
- for (const MachineOperand &MO : FaultingLoad ->operands ()) {
597
+ for (const MachineOperand &MO : FaultingInstr ->operands ()) {
571
598
if (!MO.isReg () || !MO.isDef ())
572
599
continue ;
573
600
unsigned Reg = MO.getReg ();
0 commit comments