diff options
-rw-r--r-- | include/llvm/InitializePasses.h | 2 | ||||
-rw-r--r-- | include/llvm/Transforms/NaCl.h | 2 | ||||
-rw-r--r-- | lib/Transforms/NaCl/CMakeLists.txt | 2 | ||||
-rw-r--r-- | lib/Transforms/NaCl/ExpandArithWithOverflow.cpp (renamed from lib/Transforms/NaCl/ExpandMulWithOverflow.cpp) | 78 | ||||
-rw-r--r-- | lib/Transforms/NaCl/PNaClABISimplify.cpp | 1 | ||||
-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.cpp | 2 |
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); |