Commit 4d2827c1 authored by Meador Inge's avatar Meador Inge
Browse files

instcombine: Migrate memcmp optimizations

This patch migrates the memcmp optimizations from the simplify-libcalls
pass into the instcombine library call simplifier.

llvm-svn: 167683
parent 56edbc93
Loading
Loading
Loading
Loading
+1 −50
Original line number Diff line number Diff line
@@ -104,54 +104,6 @@ static bool CallHasFloatingPointArgument(const CallInst *CI) {
//===----------------------------------------------------------------------===//

namespace {
//===---------------------------------------===//
// 'memcmp' Optimizations

struct MemCmpOpt : public LibCallOptimization {
  virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
    FunctionType *FT = Callee->getFunctionType();
    if (FT->getNumParams() != 3 || !FT->getParamType(0)->isPointerTy() ||
        !FT->getParamType(1)->isPointerTy() ||
        !FT->getReturnType()->isIntegerTy(32))
      return 0;

    Value *LHS = CI->getArgOperand(0), *RHS = CI->getArgOperand(1);

    if (LHS == RHS)  // memcmp(s,s,x) -> 0
      return Constant::getNullValue(CI->getType());

    // Make sure we have a constant length.
    ConstantInt *LenC = dyn_cast<ConstantInt>(CI->getArgOperand(2));
    if (!LenC) return 0;
    uint64_t Len = LenC->getZExtValue();

    if (Len == 0) // memcmp(s1,s2,0) -> 0
      return Constant::getNullValue(CI->getType());

    // memcmp(S1,S2,1) -> *(unsigned char*)LHS - *(unsigned char*)RHS
    if (Len == 1) {
      Value *LHSV = B.CreateZExt(B.CreateLoad(CastToCStr(LHS, B), "lhsc"),
                                 CI->getType(), "lhsv");
      Value *RHSV = B.CreateZExt(B.CreateLoad(CastToCStr(RHS, B), "rhsc"),
                                 CI->getType(), "rhsv");
      return B.CreateSub(LHSV, RHSV, "chardiff");
    }

    // Constant folding: memcmp(x, y, l) -> cnst (all arguments are constant)
    StringRef LHSStr, RHSStr;
    if (getConstantStringInfo(LHS, LHSStr) &&
        getConstantStringInfo(RHS, RHSStr)) {
      // Make sure we're not reading out-of-bounds memory.
      if (Len > LHSStr.size() || Len > RHSStr.size())
        return 0;
      uint64_t Ret = memcmp(LHSStr.data(), RHSStr.data(), Len);
      return ConstantInt::get(CI->getType(), Ret);
    }

    return 0;
  }
};

//===---------------------------------------===//
// 'memcpy' Optimizations

@@ -887,7 +839,7 @@ namespace {

    StringMap<LibCallOptimization*> Optimizations;
    // Memory LibCall Optimizations
    MemCmpOpt MemCmp; MemCpyOpt MemCpy; MemMoveOpt MemMove; MemSetOpt MemSet;
    MemCpyOpt MemCpy; MemMoveOpt MemMove; MemSetOpt MemSet;
    // Math Library Optimizations
    CosOpt Cos; PowOpt Pow; Exp2Opt Exp2;
    UnaryDoubleFPOpt UnaryDoubleFP, UnsafeUnaryDoubleFP;
@@ -954,7 +906,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2,
/// we know.
void SimplifyLibCalls::InitOptimizations() {
  // Memory LibCall Optimizations
  Optimizations["memcmp"] = &MemCmp;
  AddOpt(LibFunc::memcpy, &MemCpy);
  Optimizations["memmove"] = &MemMove;
  AddOpt(LibFunc::memset, &MemSet);
+53 −2
Original line number Diff line number Diff line
@@ -914,6 +914,51 @@ struct StrStrOpt : public LibCallOptimization {
  }
};

struct MemCmpOpt : public LibCallOptimization {
  virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
    FunctionType *FT = Callee->getFunctionType();
    if (FT->getNumParams() != 3 || !FT->getParamType(0)->isPointerTy() ||
        !FT->getParamType(1)->isPointerTy() ||
        !FT->getReturnType()->isIntegerTy(32))
      return 0;

    Value *LHS = CI->getArgOperand(0), *RHS = CI->getArgOperand(1);

    if (LHS == RHS)  // memcmp(s,s,x) -> 0
      return Constant::getNullValue(CI->getType());

    // Make sure we have a constant length.
    ConstantInt *LenC = dyn_cast<ConstantInt>(CI->getArgOperand(2));
    if (!LenC) return 0;
    uint64_t Len = LenC->getZExtValue();

    if (Len == 0) // memcmp(s1,s2,0) -> 0
      return Constant::getNullValue(CI->getType());

    // memcmp(S1,S2,1) -> *(unsigned char*)LHS - *(unsigned char*)RHS
    if (Len == 1) {
      Value *LHSV = B.CreateZExt(B.CreateLoad(CastToCStr(LHS, B), "lhsc"),
                                 CI->getType(), "lhsv");
      Value *RHSV = B.CreateZExt(B.CreateLoad(CastToCStr(RHS, B), "rhsc"),
                                 CI->getType(), "rhsv");
      return B.CreateSub(LHSV, RHSV, "chardiff");
    }

    // Constant folding: memcmp(x, y, l) -> cnst (all arguments are constant)
    StringRef LHSStr, RHSStr;
    if (getConstantStringInfo(LHS, LHSStr) &&
        getConstantStringInfo(RHS, RHSStr)) {
      // Make sure we're not reading out-of-bounds memory.
      if (Len > LHSStr.size() || Len > RHSStr.size())
        return 0;
      uint64_t Ret = memcmp(LHSStr.data(), RHSStr.data(), Len);
      return ConstantInt::get(CI->getType(), Ret);
    }

    return 0;
  }
};

} // End anonymous namespace.

namespace llvm {
@@ -932,7 +977,7 @@ class LibCallSimplifierImpl {
  StpCpyChkOpt StpCpyChk;
  StrNCpyChkOpt StrNCpyChk;

  // String and memory library call optimizations.
  // String library call optimizations.
  StrCatOpt StrCat;
  StrNCatOpt StrNCat;
  StrChrOpt StrChr;
@@ -949,6 +994,9 @@ class LibCallSimplifierImpl {
  StrCSpnOpt StrCSpn;
  StrStrOpt StrStr;

  // Memory library call optimizations.
  MemCmpOpt MemCmp;

  void initOptimizations();
  void addOpt(LibFunc::Func F, LibCallOptimization* Opt);
public:
@@ -972,7 +1020,7 @@ void LibCallSimplifierImpl::initOptimizations() {
  Optimizations["__strncpy_chk"] = &StrNCpyChk;
  Optimizations["__stpncpy_chk"] = &StrNCpyChk;

  // String and memory library call optimizations.
  // String library call optimizations.
  addOpt(LibFunc::strcat, &StrCat);
  addOpt(LibFunc::strncat, &StrNCat);
  addOpt(LibFunc::strchr, &StrChr);
@@ -994,6 +1042,9 @@ void LibCallSimplifierImpl::initOptimizations() {
  addOpt(LibFunc::strspn, &StrSpn);
  addOpt(LibFunc::strcspn, &StrCSpn);
  addOpt(LibFunc::strstr, &StrStr);

  // Memory library call optimizations.
  addOpt(LibFunc::memcmp, &MemCmp);
}

Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) {
+63 −0
Original line number Diff line number Diff line
; Test that the memcmp library call simplifier works correctly.
;
; RUN: opt < %s -instcombine -S | FileCheck %s

target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"

@foo = constant [4 x i8] c"foo\00"
@hel = constant [4 x i8] c"hel\00"
@hello_u = constant [8 x i8] c"hello_u\00"

declare i32 @memcmp(i8*, i8*, i32)

; Check memcmp(mem, mem, size) -> 0.

define i32 @test_simplify1(i8* %mem, i32 %size) {
; CHECK: @test_simplify1
  %ret = call i32 @memcmp(i8* %mem, i8* %mem, i32 %size)
  ret i32 %ret
; CHECK: ret i32 0
}

; Check memcmp(mem1, mem2, 0) -> 0.

define i32 @test_simplify2(i8* %mem1, i8* %mem2) {
; CHECK: @test_simplify2
  %ret = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 0)
  ret i32 %ret
; CHECK: ret i32 0
}

;; Check memcmp(mem1, mem2, 1) -> *(unsigned char*)mem1 - *(unsigned char*)mem2.

define i32 @test_simplify3(i8* %mem1, i8* %mem2) {
; CHECK: @test_simplify3
  %ret = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 1)
; CHECK: [[LOAD1:%[a-z]+]] = load i8* %mem1, align 1
; CHECK: [[ZEXT1:%[a-z]+]] = zext i8 [[LOAD1]] to i32
; CHECK: [[LOAD2:%[a-z]+]] = load i8* %mem2, align 1
; CHECK: [[ZEXT2:%[a-z]+]] = zext i8 [[LOAD2]] to i32
; CHECK: [[RET:%[a-z]+]] = sub i32 [[ZEXT1]], [[ZEXT2]]
  ret i32 %ret
; CHECK: ret i32 [[RET]]
}

; Check memcmp(mem1, mem2, size) -> cnst, where all arguments are constants.

define i32 @test_simplify4() {
; CHECK: @test_simplify4
  %mem1 = getelementptr [4 x i8]* @hel, i32 0, i32 0
  %mem2 = getelementptr [8 x i8]* @hello_u, i32 0, i32 0
  %ret = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 3)
  ret i32 %ret
; CHECK: ret i32 0
}

define i32 @test_simplify5() {
; CHECK: @test_simplify5
  %mem1 = getelementptr [4 x i8]* @hel, i32 0, i32 0
  %mem2 = getelementptr [4 x i8]* @foo, i32 0, i32 0
  %ret = call i32 @memcmp(i8* %mem1, i8* %mem2, i32 3)
  ret i32 %ret
; CHECK: ret i32 2
}
+17 −0
Original line number Diff line number Diff line
; Test that the memcmp library call simplifier works correctly.
;
; RUN: opt < %s -instcombine -S | FileCheck %s

target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"

declare i32* @memcmp(i8*, i8*, i32)

; Check that memcmp functions with the wrong prototype aren't simplified.

define i32* @test_no_simplify1(i8* %mem, i32 %size) {
; CHECK: @test_no_simplify1
  %ret = call i32* @memcmp(i8* %mem, i8* %mem, i32 %size)
; CHECK-NEXT: call i32* @memcmp
  ret i32* %ret
; CHECK-NEXT: ret i32* %ret
}
+6 −4
Original line number Diff line number Diff line
@@ -67,12 +67,14 @@ define i32 @test5() {
}

; strncmp(x,y,1) -> memcmp(x,y,1)
; TODO: Once the memcmp simplifier gets moved into the instcombine pass
; the following memcmp will be folded into two loads and a subtract.
define i32 @test6(i8* %str1, i8* %str2) {
; CHECK: @test6
; CHECK: call i32 @memcmp
; CHECK: ret i32 %memcmp
; CHECK: [[LOAD1:%[a-z]+]] = load i8* %str1, align 1
; CHECK: [[ZEXT1:%[a-z]+]] = zext i8 [[LOAD1]] to i32
; CHECK: [[LOAD2:%[a-z]+]] = load i8* %str2, align 1
; CHECK: [[ZEXT2:%[a-z]+]] = zext i8 [[LOAD2]] to i32
; CHECK: [[RET:%[a-z]+]] = sub i32 [[ZEXT1]], [[ZEXT2]]
; CHECK: ret i32 [[RET]]

  %temp1 = call i32 @strncmp(i8* %str1, i8* %str2, i32 1)
  ret i32 %temp1
Loading