FastISel: avoid function calls between the materialization of the constant and its...
authorIvan Krasin <krasin@chromium.org>
Thu, 18 Aug 2011 22:06:10 +0000 (22:06 +0000)
committerIvan Krasin <krasin@chromium.org>
Thu, 18 Aug 2011 22:06:10 +0000 (22:06 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@137993 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/FastISel.h
lib/CodeGen/SelectionDAG/FastISel.cpp
test/CodeGen/ARM/debug-info-blocks.ll
test/CodeGen/X86/fast-isel-x86-64.ll

index 962a4e2635387accc0bf49bb84ee3b1bee8e5b3a..18202d93b460bdd7ac28f16591ffeeea8c7bdaba 100644 (file)
@@ -54,8 +54,18 @@ protected:
   const TargetInstrInfo &TII;
   const TargetLowering &TLI;
   const TargetRegisterInfo &TRI;
+
+  /// The position of the last instruction for materializing constants
+  /// for use in the current block. It resets to EmitStartPt when it
+  /// makes sense (for example, it's usually profitable to avoid function
+  /// calls between the definition and the use)
   MachineInstr *LastLocalValue;
 
+  /// The top most instruction in the current block that is allowed for
+  /// emitting local variables. LastLocalValue resets to EmitStartPt when
+  /// it makes sense (for example, on function calls)
+  MachineInstr *EmitStartPt;
+
 public:
   /// getLastLocalValue - Return the position of the last instruction
   /// emitted for materializing constants for use in the current block.
@@ -63,7 +73,10 @@ public:
 
   /// setLastLocalValue - Update the position of the last instruction
   /// emitted for materializing constants for use in the current block.
-  void setLastLocalValue(MachineInstr *I) { LastLocalValue = I; }
+  void setLastLocalValue(MachineInstr *I) {
+    EmitStartPt = I;
+    LastLocalValue = I;
+  }
 
   /// startNewBlock - Set the current block to which generated machine
   /// instructions will be appended, and clear the local CSE map.
@@ -358,6 +371,11 @@ private:
   /// be materialized with new instructions.
   unsigned materializeRegForValue(const Value *V, MVT VT);
 
+  /// flushLocalValueMap - clears LocalValueMap and moves the area for the
+  /// new local variables to the beginning of the block. It helps to avoid
+  /// spilling cached variables across heavy instructions like calls.
+  void flushLocalValueMap();
+
   /// hasTrivialKill - Test whether the given value has exactly one use.
   bool hasTrivialKill(const Value *V) const;
 };
index f7203226df0931665a7be3c96a8b76783d61efcc..226edc64a1f712d05c4d1440f62c8564f03ce48a 100644 (file)
@@ -66,17 +66,22 @@ using namespace llvm;
 void FastISel::startNewBlock() {
   LocalValueMap.clear();
 
-  // Start out as null, meaining no local-value instructions have
-  // been emitted.
-  LastLocalValue = 0;
+  EmitStartPt = 0;
 
-  // Advance the last local value past any EH_LABEL instructions.
+  // Advance the emit start point past any EH_LABEL instructions.
   MachineBasicBlock::iterator
     I = FuncInfo.MBB->begin(), E = FuncInfo.MBB->end();
   while (I != E && I->getOpcode() == TargetOpcode::EH_LABEL) {
-    LastLocalValue = I;
+    EmitStartPt = I;
     ++I;
   }
+  LastLocalValue = EmitStartPt;
+}
+
+void FastISel::flushLocalValueMap() {
+  LocalValueMap.clear();
+  LastLocalValue = EmitStartPt;
+  recomputeInsertPt();
 }
 
 bool FastISel::hasTrivialKill(const Value *V) const {
@@ -645,6 +650,16 @@ bool FastISel::SelectCall(const User *I) {
   }
   }
 
+  // Usually, it does not make sense to initialize a value,
+  // make an unrelated function call and use the value, because
+  // it tends to be spilled on the stack. So, we move the pointer
+  // to the last local value to the beginning of the block, so that
+  // all the values which have already been materialized,
+  // appear after the call. It also makes sense to skip intrinsics
+  // since they tend to be inlined.
+  if (!isa<IntrinsicInst>(F))
+    flushLocalValueMap();
+
   // An arbitrary call. Bail.
   return false;
 }
index 519c40ebd7bf01187ab5d4c7007405217bbb2fc7..2c593160fd054b69b8bb66ea237196951b17d33e 100644 (file)
@@ -1,5 +1,5 @@
 ; RUN: llc -O0 < %s | FileCheck %s
-; CHECK: @DEBUG_VALUE: mydata <- [sp+#8]+#0
+; CHECK: @DEBUG_VALUE: mydata <- [sp+#4]+#0
 ; Radar 9331779
 target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32"
 target triple = "thumbv7-apple-macosx10.7.0"
index c4afc10ffab8ac9d916d69c852220c2b575b11b5..6a5a10295fbced7b4e2c2fa481f4c46e4082362b 100644 (file)
@@ -259,4 +259,27 @@ define void @test21(double* %p1) {
 ; CHECK: test21:
 ; CHECK-NOT: pxor
 ; CHECK: movsd LCPI
-}
\ No newline at end of file
+}
+
+; Check that immediate arguments to a function
+; do not cause massive spilling and are used
+; as immediates just before the call.
+define void @test22() nounwind {
+entry:
+  call void @foo22(i32 0)
+  call void @foo22(i32 1)
+  call void @foo22(i32 2)
+  call void @foo22(i32 3)
+  ret void
+; CHECK: test22:
+; CHECK: movl  $0, %edi
+; CHECK: callq _foo22
+; CHECK: movl  $1, %edi
+; CHECK: callq _foo22
+; CHECK: movl  $2, %edi
+; CHECK: callq _foo22
+; CHECK: movl  $3, %edi
+; CHECK: callq _foo22
+}
+
+declare void @foo22(i32)