From 8022d8e885b78a297a6f158a801383b5959c8934 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 1 Jul 2010 03:49:38 +0000 Subject: [PATCH] Teach fast-isel to avoid loading a value from memory when it's already available in a register. This is pretty primitive, but it reduces the number of instructions in common testcases by 4%. llvm-svn: 107380 --- include/llvm/CodeGen/FastISel.h | 2 ++ lib/CodeGen/SelectionDAG/FastISel.cpp | 24 ++++++++++++++++++++++++ test/CodeGen/X86/fast-isel-loads.ll | 23 +++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 test/CodeGen/X86/fast-isel-loads.ll diff --git a/include/llvm/CodeGen/FastISel.h b/include/llvm/CodeGen/FastISel.h index 113dcc7c78a..8e1f8fe1f09 100644 --- a/include/llvm/CodeGen/FastISel.h +++ b/include/llvm/CodeGen/FastISel.h @@ -307,6 +307,8 @@ protected: } private: + bool SelectLoad(const User *I); + bool SelectBinaryOp(const User *I, unsigned ISDOpcode); bool SelectFNeg(const User *I); diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index 2d6b78840f5..56009f39031 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -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(cast(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(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 index 00000000000..2fbb46c0b9f --- /dev/null +++ b/test/CodeGen/X86/fast-isel-loads.ll @@ -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 ; [#uses=2] + %p.addr = alloca double*, align 8 ; [#uses=2] + store i64 %x, i64* %x.addr + store double* %p, double** %p.addr + %tmp = load i64* %x.addr ; [#uses=1] + %tmp1 = load double** %p.addr ; [#uses=1] + %add = add nsw i64 %tmp, 16 ; [#uses=1] + %arrayidx = getelementptr inbounds double* %tmp1, i64 %add ; [#uses=1] + %tmp2 = load double* %arrayidx ; [#uses=1] + ret double %tmp2 +}