aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/InitializePasses.h2
-rw-r--r--include/llvm/Transforms/NaCl.h2
-rw-r--r--lib/Transforms/NaCl/CMakeLists.txt2
-rw-r--r--lib/Transforms/NaCl/ExpandArithWithOverflow.cpp (renamed from lib/Transforms/NaCl/ExpandMulWithOverflow.cpp)78
-rw-r--r--lib/Transforms/NaCl/PNaClABISimplify.cpp1
-rw-r--r--test/Transforms/NaCl/expand-arith-with-overflow.ll (renamed from test/Transforms/NaCl/expand-mul-with-overflow.ll)33
-rw-r--r--tools/opt/opt.cpp2
7 files changed, 77 insertions, 43 deletions
diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h
index a55ea5ce1e..968503d28e 100644
--- a/include/llvm/InitializePasses.h
+++ b/include/llvm/InitializePasses.h
@@ -278,11 +278,11 @@ void initializeBBVectorizePass(PassRegistry&);
void initializeMachineFunctionPrinterPassPass(PassRegistry&);
// @LOCALMOD-BEGIN
void initializeAddPNaClExternalDeclsPass(PassRegistry&);
+void initializeExpandArithWithOverflowPass(PassRegistry&);
void initializeExpandByValPass(PassRegistry&);
void initializeExpandConstantExprPass(PassRegistry&);
void initializeExpandCtorsPass(PassRegistry&);
void initializeExpandGetElementPtrPass(PassRegistry&);
-void initializeExpandMulWithOverflowPass(PassRegistry&);
void initializeExpandTlsConstantExprPass(PassRegistry&);
void initializeExpandTlsPass(PassRegistry&);
void initializeExpandVarArgsPass(PassRegistry&);
diff --git a/include/llvm/Transforms/NaCl.h b/include/llvm/Transforms/NaCl.h
index f42336fc67..92838e5fc7 100644
--- a/include/llvm/Transforms/NaCl.h
+++ b/include/llvm/Transforms/NaCl.h
@@ -21,11 +21,11 @@ class Use;
class Value;
ModulePass *createAddPNaClExternalDeclsPass();
+ModulePass *createExpandArithWithOverflowPass();
ModulePass *createExpandByValPass();
FunctionPass *createExpandConstantExprPass();
ModulePass *createExpandCtorsPass();
BasicBlockPass *createExpandGetElementPtrPass();
-ModulePass *createExpandMulWithOverflowPass();
ModulePass *createExpandTlsPass();
ModulePass *createExpandTlsConstantExprPass();
ModulePass *createExpandVarArgsPass();
diff --git a/lib/Transforms/NaCl/CMakeLists.txt b/lib/Transforms/NaCl/CMakeLists.txt
index 14225d79b8..0e604dfc8a 100644
--- a/lib/Transforms/NaCl/CMakeLists.txt
+++ b/lib/Transforms/NaCl/CMakeLists.txt
@@ -2,11 +2,11 @@ set(LLVM_LINK_COMPONENTS ipo)
add_llvm_library(LLVMNaClTransforms
AddPNaClExternalDecls.cpp
+ ExpandArithWithOverflow.cpp
ExpandByVal.cpp
ExpandConstantExpr.cpp
ExpandCtors.cpp
ExpandGetElementPtr.cpp
- ExpandMulWithOverflow.cpp
ExpandTls.cpp
ExpandTlsConstantExpr.cpp
ExpandUtils.cpp
diff --git a/lib/Transforms/NaCl/ExpandMulWithOverflow.cpp b/lib/Transforms/NaCl/ExpandArithWithOverflow.cpp
index 171dda1f09..e120b24293 100644
--- a/lib/Transforms/NaCl/ExpandMulWithOverflow.cpp
+++ b/lib/Transforms/NaCl/ExpandArithWithOverflow.cpp
@@ -1,4 +1,4 @@
-//===- ExpandMulWithOverflow.cpp - Expand out usage of umul.with.overflow--===//
+//===- ExpandArithWithOverflow.cpp - Expand out uses of *.with.overflow----===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,17 +11,19 @@
// support because they return structs, and we want to omit struct
// types from IR in PNaCl's stable ABI.
//
-// However, llvm.umul.with.overflow.*() is used by Clang to implement
-// an overflow check for C++'s new[] operator. This pass expands out
-// these uses so that PNaCl does not have to support
-// umul.with.overflow as part of PNaCl's stable ABI.
+// However, llvm.{umul,uadd}.with.overflow.*() are used by Clang to
+// implement an overflow check for C++'s new[] operator. This pass
+// expands out these uses so that PNaCl does not have to support
+// *.with.overflow as part of PNaCl's stable ABI.
//
-// This pass only handles multiplication by a constant, which is the
-// only case of umul.with.overflow that is currently generated by
+// This pass only handles adding/multiplying by a constant, which is
+// the only use of *.with.overflow that is currently generated by
// Clang (unless '-ftrapv' is passed to Clang).
//
// X * Const overflows iff X > UINT_MAX / Const, where UINT_MAX is the
-// maximum value for the integer type being multiplied.
+// maximum value for the integer type being used.
+//
+// Similarly, X + Const overflows iff X > UINT_MAX - Const.
//
//===----------------------------------------------------------------------===//
@@ -38,20 +40,20 @@ using namespace llvm;
namespace {
// This is a ModulePass so that the pass can easily iterate over all
// uses of the intrinsics.
- class ExpandMulWithOverflow : public ModulePass {
+ class ExpandArithWithOverflow : public ModulePass {
public:
static char ID; // Pass identification, replacement for typeid
- ExpandMulWithOverflow() : ModulePass(ID) {
- initializeExpandMulWithOverflowPass(*PassRegistry::getPassRegistry());
+ ExpandArithWithOverflow() : ModulePass(ID) {
+ initializeExpandArithWithOverflowPass(*PassRegistry::getPassRegistry());
}
virtual bool runOnModule(Module &M);
};
}
-char ExpandMulWithOverflow::ID = 0;
-INITIALIZE_PASS(ExpandMulWithOverflow, "expand-mul-with-overflow",
- "Expand out uses of llvm.umul.with.overflow intrinsics",
+char ExpandArithWithOverflow::ID = 0;
+INITIALIZE_PASS(ExpandArithWithOverflow, "expand-arith-with-overflow",
+ "Expand out some uses of *.with.overflow intrinsics",
false, false)
static uint64_t UintTypeMax(unsigned Bits) {
@@ -61,11 +63,13 @@ static uint64_t UintTypeMax(unsigned Bits) {
return (((uint64_t) 1) << Bits) - 1;
}
-static bool ExpandForIntSize(Module *M, unsigned Bits) {
+static bool ExpandOpForIntSize(Module *M, unsigned Bits, bool Mul) {
IntegerType *IntTy = IntegerType::get(M->getContext(), Bits);
SmallVector<Type *, 1> Types;
Types.push_back(IntTy);
- std::string Name = Intrinsic::getName(Intrinsic::umul_with_overflow, Types);
+ Intrinsic::ID ID = (Mul ? Intrinsic::umul_with_overflow
+ : Intrinsic::uadd_with_overflow);
+ std::string Name = Intrinsic::getName(ID, Types);
Function *Intrinsic = M->getFunction(Name);
if (!Intrinsic)
return false;
@@ -73,8 +77,8 @@ static bool ExpandForIntSize(Module *M, unsigned Bits) {
E = Intrinsic->use_end(); CallIter != E; ) {
CallInst *Call = dyn_cast<CallInst>(*CallIter++);
if (!Call) {
- report_fatal_error("ExpandMulWithOverflow: Taking the address of a "
- "umul.with.overflow intrinsic is not allowed");
+ report_fatal_error("ExpandArithWithOverflow: Taking the address of a "
+ "*.with.overflow intrinsic is not allowed");
}
Value *VariableArg;
ConstantInt *ConstantArg;
@@ -86,15 +90,20 @@ static bool ExpandForIntSize(Module *M, unsigned Bits) {
ConstantArg = C;
} else {
errs() << "Use: " << *Call << "\n";
- report_fatal_error("ExpandMulWithOverflow: At least one argument of "
- "umul.with.overflow must be a constant");
+ report_fatal_error("ExpandArithWithOverflow: At least one argument of "
+ "*.with.overflow must be a constant");
}
- Value *Mul = BinaryOperator::Create(
- Instruction::Mul, VariableArg, ConstantArg,
- Call->getName() + ".mul", Call);
+ Value *ArithResult = BinaryOperator::Create(
+ (Mul ? Instruction::Mul : Instruction::Add), VariableArg, ConstantArg,
+ Call->getName() + ".arith", Call);
- uint64_t ArgMax = UintTypeMax(Bits) / ConstantArg->getZExtValue();
+ uint64_t ArgMax;
+ if (Mul) {
+ ArgMax = UintTypeMax(Bits) / ConstantArg->getZExtValue();
+ } else {
+ ArgMax = UintTypeMax(Bits) - ConstantArg->getZExtValue();
+ }
Value *Overflow = new ICmpInst(
Call, CmpInst::ICMP_UGT, VariableArg, ConstantInt::get(IntTy, ArgMax),
Call->getName() + ".overflow");
@@ -106,18 +115,18 @@ static bool ExpandForIntSize(Module *M, unsigned Bits) {
if (!Field) {
errs() << "Use: " << *U << "\n";
report_fatal_error(
- "ExpandMulWithOverflow: Use is not an extractvalue");
+ "ExpandArithWithOverflow: Use is not an extractvalue");
}
if (Field->getNumIndices() != 1) {
- report_fatal_error("ExpandMulWithOverflow: Unexpected indices");
+ report_fatal_error("ExpandArithWithOverflow: Unexpected indices");
}
unsigned Index = Field->getIndices()[0];
if (Index == 0) {
- Field->replaceAllUsesWith(Mul);
+ Field->replaceAllUsesWith(ArithResult);
} else if (Index == 1) {
Field->replaceAllUsesWith(Overflow);
} else {
- report_fatal_error("ExpandMulWithOverflow: Unexpected index");
+ report_fatal_error("ExpandArithWithOverflow: Unexpected index");
}
Field->eraseFromParent();
}
@@ -127,7 +136,14 @@ static bool ExpandForIntSize(Module *M, unsigned Bits) {
return true;
}
-bool ExpandMulWithOverflow::runOnModule(Module &M) {
+static bool ExpandForIntSize(Module *M, unsigned Bits) {
+ bool Modified = false;
+ Modified |= ExpandOpForIntSize(M, Bits, true); // Expand umul
+ Modified |= ExpandOpForIntSize(M, Bits, false); // Expand uadd
+ return Modified;
+}
+
+bool ExpandArithWithOverflow::runOnModule(Module &M) {
bool Modified = false;
Modified |= ExpandForIntSize(&M, 64);
Modified |= ExpandForIntSize(&M, 32);
@@ -136,6 +152,6 @@ bool ExpandMulWithOverflow::runOnModule(Module &M) {
return Modified;
}
-ModulePass *llvm::createExpandMulWithOverflowPass() {
- return new ExpandMulWithOverflow();
+ModulePass *llvm::createExpandArithWithOverflowPass() {
+ return new ExpandArithWithOverflow();
}
diff --git a/lib/Transforms/NaCl/PNaClABISimplify.cpp b/lib/Transforms/NaCl/PNaClABISimplify.cpp
index 37504517d6..47e5fb67e6 100644
--- a/lib/Transforms/NaCl/PNaClABISimplify.cpp
+++ b/lib/Transforms/NaCl/PNaClABISimplify.cpp
@@ -28,6 +28,7 @@ void llvm::PNaClABISimplifyAddPreOptPasses(PassManager &PM) {
// Remove landingpad blocks made unreachable by LowerInvoke.
PM.add(createCFGSimplificationPass());
+ PM.add(createExpandArithWithOverflowPass());
PM.add(createExpandVarArgsPass());
PM.add(createExpandCtorsPass());
PM.add(createResolveAliasesPass());
diff --git a/test/Transforms/NaCl/expand-mul-with-overflow.ll b/test/Transforms/NaCl/expand-arith-with-overflow.ll
index f6957988b0..d3bb8f0392 100644
--- a/test/Transforms/NaCl/expand-mul-with-overflow.ll
+++ b/test/Transforms/NaCl/expand-arith-with-overflow.ll
@@ -1,9 +1,10 @@
-; RUN: opt %s -expand-mul-with-overflow -S | FileCheck %s
+; RUN: opt %s -expand-arith-with-overflow -S | FileCheck %s
declare {i32, i1} @llvm.umul.with.overflow.i32(i32, i32)
declare {i64, i1} @llvm.umul.with.overflow.i64(i64, i64)
+declare {i16, i1} @llvm.uadd.with.overflow.i16(i16, i16)
-; CHECK-NOT: @llvm.umul.with.overflow
+; CHECK-NOT: with.overflow
define void @umul32_by_const(i32 %x, i32* %result_val, i1* %result_overflow) {
@@ -18,9 +19,9 @@ define void @umul32_by_const(i32 %x, i32* %result_val, i1* %result_overflow) {
; The bound is 16777215 == 0xffffff == ((1 << 32) - 1) / 256
; CHECK: define void @umul32_by_const(
-; CHECK-NEXT: %pair.mul = mul i32 %x, 256
+; CHECK-NEXT: %pair.arith = mul i32 %x, 256
; CHECK-NEXT: %pair.overflow = icmp ugt i32 %x, 16777215
-; CHECK-NEXT: store i32 %pair.mul, i32* %result_val
+; CHECK-NEXT: store i32 %pair.arith, i32* %result_val
; CHECK-NEXT: store i1 %pair.overflow, i1* %result_overflow
@@ -39,9 +40,9 @@ define void @umul32_by_const2(i32 %x, i32* %result_val, i1* %result_overflow) {
}
; CHECK: define void @umul32_by_const2(
-; CHECK-NEXT: %pair.mul = mul i32 %x, 65536
+; CHECK-NEXT: %pair.arith = mul i32 %x, 65536
; CHECK-NEXT: %pair.overflow = icmp ugt i32 %x, 65535
-; CHECK-NEXT: store i32 %pair.mul, i32* %result_val
+; CHECK-NEXT: store i32 %pair.arith, i32* %result_val
; CHECK-NEXT: store i1 %pair.overflow, i1* %result_overflow
; CHECK-NEXT: store i1 %pair.overflow, i1* %result_overflow
@@ -58,7 +59,23 @@ define void @umul64_by_const(i64 %x, i64* %result_val, i1* %result_overflow) {
}
; CHECK: define void @umul64_by_const(i64 %x, i64* %result_val, i1* %result_overflow) {
-; CHECK-NEXT: %pair.mul = mul i64 %x, 36028797018963968
+; CHECK-NEXT: %pair.arith = mul i64 %x, 36028797018963968
; CHECK-NEXT: %pair.overflow = icmp ugt i64 %x, 511
-; CHECK-NEXT: store i64 %pair.mul, i64* %result_val
+; CHECK-NEXT: store i64 %pair.arith, i64* %result_val
+; CHECK-NEXT: store i1 %pair.overflow, i1* %result_overflow
+
+
+define void @uadd16_with_const(i16 %x, i16* %result_val, i1* %result_overflow) {
+ %pair = call {i16, i1} @llvm.uadd.with.overflow.i16(i16 %x, i16 35)
+ %val = extractvalue {i16, i1} %pair, 0
+ %overflow = extractvalue {i16, i1} %pair, 1
+
+ store i16 %val, i16* %result_val
+ store i1 %overflow, i1* %result_overflow
+ ret void
+}
+; CHECK: define void @uadd16_with_const(i16 %x, i16* %result_val, i1* %result_overflow) {
+; CHECK-NEXT: %pair.arith = add i16 %x, 35
+; CHECK-NEXT: %pair.overflow = icmp ugt i16 %x, -36
+; CHECK-NEXT: store i16 %pair.arith, i16* %result_val
; CHECK-NEXT: store i1 %pair.overflow, i1* %result_overflow
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index f12c36a7c7..e44cfe06f4 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -599,11 +599,11 @@ int main(int argc, char **argv) {
initializeTarget(Registry);
// @LOCALMOD-BEGIN
initializeAddPNaClExternalDeclsPass(Registry);
+ initializeExpandArithWithOverflowPass(Registry);
initializeExpandByValPass(Registry);
initializeExpandConstantExprPass(Registry);
initializeExpandCtorsPass(Registry);
initializeExpandGetElementPtrPass(Registry);
- initializeExpandMulWithOverflowPass(Registry);
initializeExpandTlsPass(Registry);
initializeExpandTlsConstantExprPass(Registry);
initializeExpandVarArgsPass(Registry);