[llvm] r335758 - [MachineOutliner] Don't outline sequences where x16/x17/nzcv are live across

Jessica Paquette via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 27 10:43:27 PDT 2018


Author: paquette
Date: Wed Jun 27 10:43:27 2018
New Revision: 335758

URL: http://llvm.org/viewvc/llvm-project?rev=335758&view=rev
Log:
[MachineOutliner] Don't outline sequences where x16/x17/nzcv are live across

It isn't safe to outline sequences of instructions where x16/x17/nzcv live
across the sequence.

This teaches the outliner to check whether or not a specific canidate has
x16/x17/nzcv live across it and discard the candidate in the case that that is
true.

https://bugs.llvm.org/show_bug.cgi?id=37573
https://reviews.llvm.org/D47655

Added:
    llvm/trunk/test/CodeGen/AArch64/machine-outliner-bad-register.mir
Modified:
    llvm/trunk/include/llvm/CodeGen/MachineOutliner.h
    llvm/trunk/lib/CodeGen/MachineOutliner.cpp
    llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp
    llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h

Modified: llvm/trunk/include/llvm/CodeGen/MachineOutliner.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineOutliner.h?rev=335758&r1=335757&r2=335758&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/MachineOutliner.h (original)
+++ llvm/trunk/include/llvm/CodeGen/MachineOutliner.h Wed Jun 27 10:43:27 2018
@@ -16,7 +16,9 @@
 #ifndef LLVM_MACHINEOUTLINER_H
 #define LLVM_MACHINEOUTLINER_H
 
+#include "llvm/CodeGen/LiveRegUnits.h"
 #include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
 
 namespace llvm {
 namespace outliner {
@@ -91,6 +93,13 @@ public:
   /// Contains all target-specific information for this \p Candidate.
   TargetCostInfo TCI;
 
+  /// Contains physical register liveness information for the MBB containing
+  /// this \p Candidate.
+  ///
+  /// This is optionally used by the target to calculate more fine-grained
+  /// cost model information.
+  LiveRegUnits LRU;
+
   /// Return the number of instructions in this Candidate.
   unsigned getLength() const { return Len; }
 
@@ -120,12 +129,27 @@ public:
             unsigned FunctionIdx)
       : StartIdx(StartIdx), Len(Len), FirstInst(FirstInst), LastInst(LastInst),
         MBB(MBB), FunctionIdx(FunctionIdx) {}
+  Candidate() {}
 
   /// Used to ensure that \p Candidates are outlined in an order that
   /// preserves the start and end indices of other \p Candidates.
   bool operator<(const Candidate &RHS) const {
     return getStartIdx() > RHS.getStartIdx();
   }
+
+  /// Compute the registers that are live across this Candidate.
+  /// Used by targets that need this information for cost model calculation.
+  /// If a target does not need this information, then this should not be
+  /// called.
+  void initLRU(const TargetRegisterInfo &TRI) {
+    LRU.init(TRI);
+    LRU.addLiveOuts(*MBB);
+
+    // Compute liveness from the end of the block up to the beginning of the
+    // outlining candidate.
+    std::for_each(MBB->rbegin(), (MachineBasicBlock::reverse_iterator)front(),
+                  [this](MachineInstr &MI) { LRU.stepBackward(MI); });
+  }
 };
 
 /// The information necessary to create an outlined function for some

Modified: llvm/trunk/lib/CodeGen/MachineOutliner.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineOutliner.cpp?rev=335758&r1=335757&r2=335758&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/MachineOutliner.cpp (original)
+++ llvm/trunk/lib/CodeGen/MachineOutliner.cpp Wed Jun 27 10:43:27 2018
@@ -65,7 +65,6 @@
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
-#include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/IR/DIBuilder.h"
 #include "llvm/IR/IRBuilder.h"

Modified: llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp?rev=335758&r1=335757&r2=335758&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp Wed Jun 27 10:43:27 2018
@@ -19,7 +19,6 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/CodeGen/LiveRegUnits.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
@@ -4928,25 +4927,6 @@ enum MachineOutlinerMBBFlags {
   HasCalls = 0x4
 };
 
-bool AArch64InstrInfo::canOutlineWithoutLRSave(
-    MachineBasicBlock::iterator &CallInsertionPt) const {
-  // Was LR saved in the function containing this basic block?
-  MachineBasicBlock &MBB = *(CallInsertionPt->getParent());
-  LiveRegUnits LRU(getRegisterInfo());
-  LRU.addLiveOuts(MBB);
-
-  // Get liveness information from the end of the block to the end of the
-  // prospective outlined region.
-  std::for_each(MBB.rbegin(),
-                (MachineBasicBlock::reverse_iterator)CallInsertionPt,
-                [&LRU](MachineInstr &MI) { LRU.stepBackward(MI); });
-
-  // If the link register is available at this point, then we can safely outline
-  // the region without saving/restoring LR. Otherwise, we must emit a save and
-  // restore.
-  return LRU.available(AArch64::LR);
-}
-
 outliner::TargetCostInfo
 AArch64InstrInfo::getOutlininingCandidateInfo(
     std::vector<outliner::Candidate> &RepeatedSequenceLocs) const {
@@ -4961,8 +4941,38 @@ AArch64InstrInfo::getOutlininingCandidat
   unsigned NumBytesForCall = 12;
   unsigned NumBytesToCreateFrame = 4;
 
-  auto DoesntNeedLRSave = 
-    [this](outliner::Candidate &I) {return canOutlineWithoutLRSave(I.back());};
+  // Compute liveness information for each candidate.
+  const TargetRegisterInfo &TRI = getRegisterInfo();
+  std::for_each(RepeatedSequenceLocs.begin(), RepeatedSequenceLocs.end(),
+                [&TRI](outliner::Candidate &C) { C.initLRU(TRI); });
+
+  // According to the AArch64 Procedure Call Standard, the following are
+  // undefined on entry/exit from a function call:
+  //
+  // * Registers x16, x17, (and thus w16, w17)
+  // * Condition codes (and thus the NZCV register)
+  //
+  // Because if this, we can't outline any sequence of instructions where
+  // one
+  // of these registers is live into/across it. Thus, we need to delete
+  // those
+  // candidates.
+  auto CantGuaranteeValueAcrossCall = [](outliner::Candidate &C) {
+    LiveRegUnits LRU = C.LRU;
+    return (!LRU.available(AArch64::W16) || !LRU.available(AArch64::W17) ||
+            !LRU.available(AArch64::NZCV));
+  };
+
+  // Erase every candidate that violates the restrictions above. (It could be
+  // true that we have viable candidates, so it's not worth bailing out in
+  // the case that, say, 1 out of 20 candidates violate the restructions.)
+  RepeatedSequenceLocs.erase(std::remove_if(RepeatedSequenceLocs.begin(),
+                                            RepeatedSequenceLocs.end(),
+                                            CantGuaranteeValueAcrossCall),
+                             RepeatedSequenceLocs.end());
+
+  // At this point, we have only "safe" candidates to outline. Figure out
+  // frame + call instruction information.
 
   unsigned LastInstrOpcode = RepeatedSequenceLocs[0].back()->getOpcode();
 
@@ -4983,8 +4993,15 @@ AArch64InstrInfo::getOutlininingCandidat
     NumBytesToCreateFrame = 0;
   }
 
-  else if (std::all_of(RepeatedSequenceLocs.begin(), RepeatedSequenceLocs.end(),
-                       DoesntNeedLRSave)) {
+  // Make sure that LR isn't live on entry to this candidate. The only
+  // instructions that use LR that could possibly appear in a repeated sequence
+  // are calls. Therefore, we only have to check and see if LR is dead on entry
+  // to (or exit from) some candidate.
+  else if (std::all_of(RepeatedSequenceLocs.begin(),
+                       RepeatedSequenceLocs.end(),
+                       [](outliner::Candidate &C) {
+                         return C.LRU.available(AArch64::LR);
+                         })) {
     CallID = MachineOutlinerNoLRSave;
     FrameID = MachineOutlinerNoLRSave;
     NumBytesForCall = 4;

Modified: llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h?rev=335758&r1=335757&r2=335758&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.h Wed Jun 27 10:43:27 2018
@@ -238,9 +238,6 @@ public:
 
   /// AArch64 supports the MachineOutliner.
   bool useMachineOutliner() const override { return true; }
-  
-  bool
-  canOutlineWithoutLRSave(MachineBasicBlock::iterator &CallInsertionPt) const;
   bool isFunctionSafeToOutlineFrom(MachineFunction &MF,
                                    bool OutlineFromLinkOnceODRs) const override;
   outliner::TargetCostInfo getOutlininingCandidateInfo(

Added: llvm/trunk/test/CodeGen/AArch64/machine-outliner-bad-register.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/machine-outliner-bad-register.mir?rev=335758&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/machine-outliner-bad-register.mir (added)
+++ llvm/trunk/test/CodeGen/AArch64/machine-outliner-bad-register.mir Wed Jun 27 10:43:27 2018
@@ -0,0 +1,183 @@
+# RUN: llc -mtriple=aarch64--- -run-pass=machine-outliner \
+# RUN: -verify-machineinstrs %s -o - | FileCheck %s
+
+# Ensure that we don't outline from regions where x16, x17, or nzcv are live
+# across the outlining candidate. These values are allowed to be clobbered by,
+# say, the linker, in the presence of function calls. Thus, we can't outline
+# these, since the insertion of the outlined call could change the values of
+# these registers.
+--- |
+  ; No problematic register appears at all. Safe for outlining.
+  define void @reg_never_defined() #0 { ret void }
+
+  ; A problematic register is live, but after the candidate. Safe for outlining.
+  define void @reg_defined_after_candidate() #0 { ret void }
+
+  ; A problematic register is live before the candidate, but killed before
+  ; entry to the candidate. Safe for outlining.
+  define void @reg_killed_before_candidate() #0 { ret void }
+
+  ; Ensure that we never outline when any of the problematic registers we care
+  ; about are defined across the outlining candidate.
+  define void @x16_live() #0 { ret void }
+  define void @x17_live() #0 { ret void }
+  define void @nzcv_live() #0 { ret void }
+
+  ; Test a combination of the above behaviours.
+  ; [candidate] (1)
+  ; - define a bad register -
+  ; [candidate] (2)
+  ; - kill the bad register -
+  ; [candidate] (3)
+  ;
+  ; (1) and (3) should be outlined, while (2) should not be outlined.
+  define void @multiple_ranges() #0 { ret void }
+
+  attributes #0 = { noredzone }
+...
+---
+
+# There should be two calls to outlined functions here, since we haven't tripped
+# any of the cases above.
+name:           reg_never_defined
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    ; CHECK-LABEL: bb.0:
+    ; CHECK: BL
+    liveins: $w8, $wzr
+    $w8 = ORRWri $wzr, 1
+    $w8 = ORRWri $wzr, 2
+    $w8 = ORRWri $wzr, 3
+    $w8 = ORRWri $wzr, 4
+  bb.1:
+    ; CHECK-LABEL: bb.1:
+    ; CHECK: BL
+    liveins: $w8, $wzr
+    $w8 = ORRWri $wzr, 1
+    $w8 = ORRWri $wzr, 2
+    $w8 = ORRWri $wzr, 3
+    $w8 = ORRWri $wzr, 4
+  bb.2:
+    RET undef $lr
+...
+---
+
+name:            reg_defined_after_candidate
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    ; CHECK-LABEL: bb.0:
+    ; CHECK: BL
+    ; CHECK-NEXT: $x16 = ORRXri $x8, 5, implicit-def $x16, implicit-def $w16
+    liveins: $w8, $wzr
+    $w8 = ORRWri $wzr, 1
+    $w8 = ORRWri $wzr, 2
+    $w8 = ORRWri $wzr, 3
+    $w8 = ORRWri $wzr, 4
+    $x16 = ORRXri $x8, 5, implicit-def $x16, implicit-def $w16
+    $w8 = ORRWri $w16, 5
+    RET undef $lr
+...
+---
+
+name:            reg_killed_before_candidate
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    ; CHECK-LABEL: bb.0:
+    ; CHECK: BL
+    liveins: $w8, $wzr, $x16
+    dead $x16 = ORRXri $x8, 6
+    $w8 = ORRWri $wzr, 1
+    $w8 = ORRWri $wzr, 2
+    $w8 = ORRWri $wzr, 3
+    $w8 = ORRWri $wzr, 4
+    RET undef $lr
+...
+---
+
+name:            x16_live
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    ; CHECK-LABEL: bb.0:
+    ; CHECK-NOT: BL
+    liveins: $w8, $wzr, $x16
+    $w8 = ORRWri $wzr, 1
+    $w8 = ORRWri $wzr, 2
+    $w8 = ORRWri $wzr, 3
+    $w8 = ORRWri $wzr, 4
+  bb.1:
+    liveins: $x16
+    RET undef $lr
+...
+---
+
+name:            x17_live
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    ; CHECK-LABEL: bb.0:
+    ; CHECK-NOT: BL
+    liveins: $w8, $wzr, $x17
+    $w8 = ORRWri $wzr, 1
+    $w8 = ORRWri $wzr, 2
+    $w8 = ORRWri $wzr, 3
+    $w8 = ORRWri $wzr, 4
+    $w8 = ORRWri $w17, 5
+    RET undef $lr
+...
+---
+
+name:            nzcv_live
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $w8, $wzr, $nzcv
+    ; CHECK-LABEL: bb.0:
+    ; CHECK-NOT: BL
+    $w8 = ORRWri $wzr, 1
+    $w8 = ORRWri $wzr, 2
+    $w8 = ORRWri $wzr, 3
+    $w8 = ORRWri $wzr, 4
+  bb.1:
+    liveins: $nzcv
+    RET undef $lr
+...
+---
+
+name:            multiple_ranges
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    ; CHECK-LABEL: bb.0:
+    ; CHECK: BL
+    liveins: $w8, $wzr
+    $w8 = ORRWri $wzr, 1
+    $w8 = ORRWri $wzr, 2
+    $w8 = ORRWri $wzr, 3
+    $w8 = ORRWri $wzr, 4
+    $x16 = ORRXri $x8, 5, implicit-def $x16
+  bb.1:
+    ; CHECK-LABEL: bb.1:
+    ; CHECK-NOT: BL
+    liveins: $w8, $x16
+    $w8 = ORRWri $wzr, 1
+    $w8 = ORRWri $wzr, 2
+    $w8 = ORRWri $wzr, 3
+    $w8 = ORRWri $wzr, 4
+  bb.2:
+    ; CHECK-LABEL: bb.2:
+    ; CHECK: BL
+    liveins: $w8, $x16
+    dead $x16 = ORRXri $x8, 0
+    $w8 = ORRWri $wzr, 1
+    $w8 = ORRWri $wzr, 2
+    $w8 = ORRWri $wzr, 3
+    $w8 = ORRWri $wzr, 4
+  bb.3:
+    liveins: $w8
+    RET undef $lr
+...
+---




More information about the llvm-commits mailing list