aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/Transforms/InstCombine/InstCombine.h1
-rw-r--r--lib/Transforms/InstCombine/InstCombineCalls.cpp129
-rw-r--r--lib/Transforms/Scalar/SimplifyLibCalls.cpp134
-rw-r--r--test/Transforms/InstCombine/memset_chk.ll (renamed from test/Transforms/SimplifyLibCalls/memset_chk.ll)2
-rw-r--r--test/Transforms/InstCombine/objsize.ll4
-rw-r--r--test/Transforms/InstCombine/strcpy_chk.ll (renamed from test/Transforms/SimplifyLibCalls/strcpy_chk.ll)2
6 files changed, 132 insertions, 140 deletions
diff --git a/lib/Transforms/InstCombine/InstCombine.h b/lib/Transforms/InstCombine/InstCombine.h
index 07fb15e..bd06499 100644
--- a/lib/Transforms/InstCombine/InstCombine.h
+++ b/lib/Transforms/InstCombine/InstCombine.h
@@ -207,6 +207,7 @@ private:
const Type *Ty);
Instruction *visitCallSite(CallSite CS);
+ Instruction *tryOptimizeCall(CallInst *CI, const TargetData *TD);
bool transformConstExprCastCall(CallSite CS);
Instruction *transformCallThroughTrampoline(CallSite CS);
Instruction *transformZExtICmp(ICmpInst *ICI, Instruction &CI,
diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp
index a241f16..e57ab58 100644
--- a/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -16,6 +16,7 @@
#include "llvm/Support/CallSite.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Analysis/MemoryBuiltins.h"
+#include "llvm/Transforms/Utils/BuildLibCalls.h"
using namespace llvm;
/// getPromotedType - Return the specified type promoted as it would be to pass
@@ -347,7 +348,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
Operand = Operand->stripPointerCasts();
if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Operand))
if (!GV->hasDefinitiveInitializer()) break;
-
+
// Get what we're pointing to and its size.
const PointerType *BaseType =
cast<PointerType>(Operand->getType());
@@ -370,7 +371,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
Constant *RetVal = ConstantInt::get(ReturnTy, Size-Offset);
return ReplaceInstUsesWith(CI, RetVal);
- }
+ }
// Do not return "I don't know" here. Later optimization passes could
// make it possible to evaluate objectsize to a constant.
@@ -740,6 +741,122 @@ static bool isSafeToEliminateVarargsCast(const CallSite CS,
return true;
}
+// Try to fold some different type of calls here.
+// Currently we're only working with the checking functions, memcpy_chk,
+// mempcpy_chk, memmove_chk, memset_chk, strcpy_chk, stpcpy_chk, strncpy_chk,
+// strcat_chk and strncat_chk.
+Instruction *InstCombiner::tryOptimizeCall(CallInst *CI, const TargetData *TD) {
+ if (CI->getCalledFunction() == 0) return 0;
+
+ StringRef Name = CI->getCalledFunction()->getName();
+ BasicBlock *BB = CI->getParent();
+ IRBuilder<> B(CI->getParent()->getContext());
+
+ // Set the builder to the instruction after the call.
+ B.SetInsertPoint(BB, CI);
+
+ if (Name == "__memcpy_chk") {
+ ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
+ if (!SizeCI)
+ return 0;
+ ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3));
+ if (!SizeArg)
+ return 0;
+ if (SizeCI->isAllOnesValue() ||
+ SizeCI->getZExtValue() <= SizeArg->getZExtValue()) {
+ EmitMemCpy(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
+ 1, B, TD);
+ return ReplaceInstUsesWith(*CI, CI->getOperand(1));
+ }
+ return 0;
+ }
+
+ // Should be similar to memcpy.
+ if (Name == "__mempcpy_chk") {
+ return 0;
+ }
+
+ if (Name == "__memmove_chk") {
+ ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
+ if (!SizeCI)
+ return 0;
+ ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3));
+ if (!SizeArg)
+ return 0;
+ if (SizeCI->isAllOnesValue() ||
+ SizeCI->getZExtValue() <= SizeArg->getZExtValue()) {
+ EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
+ 1, B, TD);
+ return ReplaceInstUsesWith(*CI, CI->getOperand(1));
+ }
+ return 0;
+ }
+
+ if (Name == "__memset_chk") {
+ ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
+ if (!SizeCI)
+ return 0;
+ ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3));
+ if (!SizeArg)
+ return 0;
+ if (SizeCI->isAllOnesValue() ||
+ SizeCI->getZExtValue() <= SizeArg->getZExtValue()) {
+ Value *Val = B.CreateIntCast(CI->getOperand(2), B.getInt8Ty(),
+ false);
+ EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B, TD);
+ return ReplaceInstUsesWith(*CI, CI->getOperand(1));
+ }
+ return 0;
+ }
+
+ if (Name == "__strcpy_chk") {
+ ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(3));
+ if (!SizeCI)
+ return 0;
+ // If a) we don't have any length information, or b) we know this will
+ // fit then just lower to a plain strcpy. Otherwise we'll keep our
+ // strcpy_chk call which may fail at runtime if the size is too long.
+ // TODO: It might be nice to get a maximum length out of the possible
+ // string lengths for varying.
+ if (SizeCI->isAllOnesValue() ||
+ SizeCI->getZExtValue() >= GetStringLength(CI->getOperand(2))) {
+ Value *Ret = EmitStrCpy(CI->getOperand(1), CI->getOperand(2), B, TD);
+ return ReplaceInstUsesWith(*CI, Ret);
+ }
+ return 0;
+ }
+
+ // Should be similar to strcpy.
+ if (Name == "__stpcpy_chk") {
+ return 0;
+ }
+
+ if (Name == "__strncpy_chk") {
+ ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
+ if (!SizeCI)
+ return 0;
+ ConstantInt *SizeArg = dyn_cast<ConstantInt>(CI->getOperand(3));
+ if (!SizeArg)
+ return 0;
+ if (SizeCI->isAllOnesValue() ||
+ SizeCI->getZExtValue() <= SizeArg->getZExtValue()) {
+ Value *Ret = EmitStrCpy(CI->getOperand(1), CI->getOperand(2), B, TD);
+ return ReplaceInstUsesWith(*CI, Ret);
+ }
+ return 0;
+ }
+
+ if (Name == "__strcat_chk") {
+ return 0;
+ }
+
+ if (Name == "__strncat_chk") {
+ return 0;
+ }
+
+ return 0;
+}
+
// visitCallSite - Improvements for call and invoke instructions.
//
Instruction *InstCombiner::visitCallSite(CallSite CS) {
@@ -826,6 +943,14 @@ Instruction *InstCombiner::visitCallSite(CallSite CS) {
Changed = true;
}
+ // Try to optimize the call if possible, we require TargetData for most of
+ // this. None of these calls are seen as possibly dead so go ahead and
+ // delete the instruction now.
+ if (CallInst *CI = dyn_cast<CallInst>(CS.getInstruction())) {
+ Instruction *I = tryOptimizeCall(CI, TD);
+ return I ? EraseInstFromFunction(*I): 0;
+ }
+
return Changed ? CS.getInstruction() : 0;
}
diff --git a/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/lib/Transforms/Scalar/SimplifyLibCalls.cpp
index 86ddeac..05027ae 100644
--- a/lib/Transforms/Scalar/SimplifyLibCalls.cpp
+++ b/lib/Transforms/Scalar/SimplifyLibCalls.cpp
@@ -633,130 +633,6 @@ struct MemSetOpt : public LibCallOptimization {
};
//===----------------------------------------------------------------------===//
-// Object Size Checking Optimizations
-//===----------------------------------------------------------------------===//
-
-//===---------------------------------------===//
-// 'memcpy_chk' Optimizations
-
-struct MemCpyChkOpt : public LibCallOptimization {
- virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
- // These optimizations require TargetData.
- if (!TD) return 0;
-
- const FunctionType *FT = Callee->getFunctionType();
- if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
- !FT->getParamType(0)->isPointerTy() ||
- !FT->getParamType(1)->isPointerTy() ||
- !FT->getParamType(3)->isIntegerTy() ||
- FT->getParamType(2) != TD->getIntPtrType(*Context))
- return 0;
-
- ConstantInt *ObjSizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
- if (!ObjSizeCI)
- return 0;
- ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(3));
- if (ObjSizeCI->isAllOnesValue() ||
- (SizeCI && ObjSizeCI->getValue().uge(SizeCI->getValue()))) {
- EmitMemCpy(CI->getOperand(1), CI->getOperand(2),
- CI->getOperand(3), 1, B, TD);
- return CI->getOperand(1);
- }
-
- return 0;
- }
-};
-
-//===---------------------------------------===//
-// 'memset_chk' Optimizations
-
-struct MemSetChkOpt : public LibCallOptimization {
- virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
- // These optimizations require TargetData.
- if (!TD) return 0;
-
- const FunctionType *FT = Callee->getFunctionType();
- if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
- !FT->getParamType(0)->isPointerTy() ||
- !FT->getParamType(1)->isIntegerTy() ||
- !FT->getParamType(3)->isIntegerTy() ||
- FT->getParamType(2) != TD->getIntPtrType(*Context))
- return 0;
-
- ConstantInt *ObjSizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
- if (!ObjSizeCI)
- return 0;
- ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(3));
- if (ObjSizeCI->isAllOnesValue() ||
- (SizeCI && ObjSizeCI->getValue().uge(SizeCI->getValue()))) {
- Value *Val = B.CreateIntCast(CI->getOperand(2), Type::getInt8Ty(*Context),
- false);
- EmitMemSet(CI->getOperand(1), Val, CI->getOperand(3), B, TD);
- return CI->getOperand(1);
- }
-
- return 0;
- }
-};
-
-//===---------------------------------------===//
-// 'memmove_chk' Optimizations
-
-struct MemMoveChkOpt : public LibCallOptimization {
- virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
- // These optimizations require TargetData.
- if (!TD) return 0;
-
- const FunctionType *FT = Callee->getFunctionType();
- if (FT->getNumParams() != 4 || FT->getReturnType() != FT->getParamType(0) ||
- !FT->getParamType(0)->isPointerTy() ||
- !FT->getParamType(1)->isPointerTy() ||
- !FT->getParamType(3)->isIntegerTy() ||
- FT->getParamType(2) != TD->getIntPtrType(*Context))
- return 0;
-
- ConstantInt *ObjSizeCI = dyn_cast<ConstantInt>(CI->getOperand(4));
- if (!ObjSizeCI)
- return 0;
- ConstantInt *SizeCI = dyn_cast<ConstantInt>(CI->getOperand(3));
- if (ObjSizeCI->isAllOnesValue() ||
- (SizeCI && ObjSizeCI->getValue().uge(SizeCI->getValue()))) {
- EmitMemMove(CI->getOperand(1), CI->getOperand(2), CI->getOperand(3),
- 1, B, TD);
- return CI->getOperand(1);
- }
-
- return 0;
- }
-};
-
-struct StrCpyChkOpt : public LibCallOptimization {
- virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
- const FunctionType *FT = Callee->getFunctionType();
- if (FT->getNumParams() != 3 || FT->getReturnType() != FT->getParamType(0) ||
- !FT->getParamType(0)->isPointerTy() ||
- !FT->getParamType(1)->isPointerTy())
- return 0;
-
- ConstantInt *ObjSizeCI = dyn_cast<ConstantInt>(CI->getOperand(3));
- if (!ObjSizeCI)
- return 0;
-
- // If a) we don't have any length information, or b) we know this will
- // fit then just lower to a plain strcpy. Otherwise we'll keep our
- // strcpy_chk call which may fail at runtime if the size is too long.
- // TODO: It might be nice to get a maximum length out of the possible
- // string lengths for varying.
- if (ObjSizeCI->isAllOnesValue() ||
- ObjSizeCI->getZExtValue() >= GetStringLength(CI->getOperand(2)))
- return EmitStrCpy(CI->getOperand(1), CI->getOperand(2), B, TD);
-
- return 0;
- }
-};
-
-
-//===----------------------------------------------------------------------===//
// Math Library Optimizations
//===----------------------------------------------------------------------===//
@@ -1298,10 +1174,6 @@ namespace {
SPrintFOpt SPrintF; PrintFOpt PrintF;
FWriteOpt FWrite; FPutsOpt FPuts; FPrintFOpt FPrintF;
- // Object Size Checking
- MemCpyChkOpt MemCpyChk; MemSetChkOpt MemSetChk; MemMoveChkOpt MemMoveChk;
- StrCpyChkOpt StrCpyChk;
-
bool Modified; // This is only used by doInitialization.
public:
static char ID; // Pass identification
@@ -1407,12 +1279,6 @@ void SimplifyLibCalls::InitOptimizations() {
Optimizations["fwrite"] = &FWrite;
Optimizations["fputs"] = &FPuts;
Optimizations["fprintf"] = &FPrintF;
-
- // Object Size Checking
- Optimizations["__memcpy_chk"] = &MemCpyChk;
- Optimizations["__memset_chk"] = &MemSetChk;
- Optimizations["__memmove_chk"] = &MemMoveChk;
- Optimizations["__strcpy_chk"] = &StrCpyChk;
}
diff --git a/test/Transforms/SimplifyLibCalls/memset_chk.ll b/test/Transforms/InstCombine/memset_chk.ll
index c4ef60e..5a4e6d9 100644
--- a/test/Transforms/SimplifyLibCalls/memset_chk.ll
+++ b/test/Transforms/InstCombine/memset_chk.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -simplify-libcalls -S | FileCheck %s
+; RUN: opt < %s -instcombine -S | FileCheck %s
; rdar://7719085
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
diff --git a/test/Transforms/InstCombine/objsize.ll b/test/Transforms/InstCombine/objsize.ll
index bf1a37f..57dc2fd 100644
--- a/test/Transforms/InstCombine/objsize.ll
+++ b/test/Transforms/InstCombine/objsize.ll
@@ -91,7 +91,7 @@ bb11:
%1 = bitcast float* %0 to i8* ; <i8*> [#uses=1]
%2 = call i32 @llvm.objectsize.i32(i8* %1, i1 false) ; <i32> [#uses=1]
%3 = call i8* @__memcpy_chk(i8* undef, i8* undef, i32 512, i32 %2) nounwind ; <i8*> [#uses=0]
-; CHECK: @__memcpy_chk
+; CHECK: unreachable
unreachable
bb12:
@@ -113,7 +113,7 @@ entry:
%1 = bitcast %struct.data* %0 to i8*
%2 = call i64 @llvm.objectsize.i64(i8* %1, i1 false) nounwind
; CHECK-NOT: @llvm.objectsize
-; CHECK: @__memset_chk(i8* %1, i32 0, i64 1824, i64 1824)
+; CHECK: @llvm.memset.i64(i8* %1, i8 0, i64 1824, i32 8)
%3 = call i8* @__memset_chk(i8* %1, i32 0, i64 1824, i64 %2) nounwind
ret i32 0
}
diff --git a/test/Transforms/SimplifyLibCalls/strcpy_chk.ll b/test/Transforms/InstCombine/strcpy_chk.ll
index 422cbd9..a20a13c 100644
--- a/test/Transforms/SimplifyLibCalls/strcpy_chk.ll
+++ b/test/Transforms/InstCombine/strcpy_chk.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -simplify-libcalls -S | FileCheck %s
+; RUN: opt < %s -instcombine -S | FileCheck %s
@a = common global [60 x i8] zeroinitializer, align 1 ; <[60 x i8]*> [#uses=1]
@.str = private constant [8 x i8] c"abcdefg\00" ; <[8 x i8]*> [#uses=1]