Teach fast-isel to avoid loading a value from memory when it's already
authorDan Gohman <gohman@apple.com>
Thu, 1 Jul 2010 03:49:38 +0000 (03:49 +0000)
committerDan Gohman <gohman@apple.com>
Thu, 1 Jul 2010 03:49:38 +0000 (03:49 +0000)
available in a register. This is pretty primitive, but it reduces the
number of instructions in common testcases by 4%.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@107380 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CodeGen/FastISel.h
lib/CodeGen/SelectionDAG/FastISel.cpp
test/CodeGen/X86/fast-isel-loads.ll [new file with mode: 0644]

index 113dcc7c78ad661bf1f392b8e6ca0169c85424a5..8e1f8fe1f09d15bf12a051172436a5bbc265fe6f 100644 (file)
@@ -307,6 +307,8 @@ protected:
   }
 
 private:
+  bool SelectLoad(const User *I);
+
   bool SelectBinaryOp(const User *I, unsigned ISDOpcode);
 
   bool SelectFNeg(const User *I);
index 2d6b78840f5f93543f0ccb84c5413c64a389c930..56009f39031b51fbd9b013a6d9167fe6e9148ef9 100644 (file)
@@ -48,6 +48,7 @@
 #include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/Analysis/DebugInfo.h"
+#include "llvm/Analysis/Loads.h"
 #include "llvm/Target/TargetData.h"
 #include "llvm/Target/TargetInstrInfo.h"
 #include "llvm/Target/TargetLowering.h"
@@ -715,9 +716,32 @@ FastISel::SelectFNeg(const User *I) {
   return true;
 }
 
+bool
+FastISel::SelectLoad(const User *I) {
+  LoadInst *LI = const_cast<LoadInst *>(cast<LoadInst>(I));
+
+  // For a load from an alloca, make a limited effort to find the value
+  // already available in a register, avoiding redundant loads.
+  if (!LI->isVolatile() && isa<AllocaInst>(LI->getPointerOperand())) {
+    BasicBlock::iterator ScanFrom = LI;
+    if (const Value *V = FindAvailableLoadedValue(LI->getPointerOperand(),
+                                                  LI->getParent(), ScanFrom)) {
+      unsigned ResultReg = getRegForValue(V);
+      if (ResultReg != 0) {
+        UpdateValueMap(I, ResultReg);
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
 bool
 FastISel::SelectOperator(const User *I, unsigned Opcode) {
   switch (Opcode) {
+  case Instruction::Load:
+    return SelectLoad(I);
   case Instruction::Add:
     return SelectBinaryOp(I, ISD::ADD);
   case Instruction::FAdd:
diff --git a/test/CodeGen/X86/fast-isel-loads.ll b/test/CodeGen/X86/fast-isel-loads.ll
new file mode 100644 (file)
index 0000000..2fbb46c
--- /dev/null
@@ -0,0 +1,23 @@
+; RUN: llc -march=x86-64 -O0 -asm-verbose=false < %s | FileCheck %s
+
+; Fast-isel shouldn't reload the argument values from the stack.
+
+; CHECK: foo:
+; CHECK-NEXT: movq  %rdi, -8(%rsp)
+; CHECK-NEXT: movq  %rsi, -16(%rsp)
+; CHECK-NEXT: movsd 128(%rsi,%rdi,8), %xmm0
+; CHECK-NEXT: ret
+
+define double @foo(i64 %x, double* %p) nounwind {
+entry:
+  %x.addr = alloca i64, align 8                   ; <i64*> [#uses=2]
+  %p.addr = alloca double*, align 8               ; <double**> [#uses=2]
+  store i64 %x, i64* %x.addr
+  store double* %p, double** %p.addr
+  %tmp = load i64* %x.addr                        ; <i64> [#uses=1]
+  %tmp1 = load double** %p.addr                   ; <double*> [#uses=1]
+  %add = add nsw i64 %tmp, 16                     ; <i64> [#uses=1]
+  %arrayidx = getelementptr inbounds double* %tmp1, i64 %add ; <double*> [#uses=1]
+  %tmp2 = load double* %arrayidx                  ; <double> [#uses=1]
+  ret double %tmp2
+}