Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(492)

Unified Diff: lib/Transforms/NaCl/ExpandArithWithOverflow.cpp

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/Transforms/NaCl/ExceptionInfoWriter.cpp ('k') | lib/Transforms/NaCl/ExpandByVal.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/Transforms/NaCl/ExpandArithWithOverflow.cpp
diff --git a/lib/Transforms/NaCl/ExpandArithWithOverflow.cpp b/lib/Transforms/NaCl/ExpandArithWithOverflow.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5a4fb944773915065cf0928d81fea0749832e591
--- /dev/null
+++ b/lib/Transforms/NaCl/ExpandArithWithOverflow.cpp
@@ -0,0 +1,155 @@
+//===- ExpandArithWithOverflow.cpp - Expand out uses of *.with.overflow----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The llvm.*.with.overflow.*() intrinsics are awkward for PNaCl
+// support because they return structs, and we want to omit struct
+// types from IR in 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 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 used.
+//
+// Similarly, X + Const overflows iff X > UINT_MAX - Const.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/NaCl.h"
+
+using namespace llvm;
+
+namespace {
+ // This is a ModulePass so that the pass can easily iterate over all
+ // uses of the intrinsics.
+ class ExpandArithWithOverflow : public ModulePass {
+ public:
+ static char ID; // Pass identification, replacement for typeid
+ ExpandArithWithOverflow() : ModulePass(ID) {
+ initializeExpandArithWithOverflowPass(*PassRegistry::getPassRegistry());
+ }
+
+ virtual bool runOnModule(Module &M);
+ };
+}
+
+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) {
+ // Avoid doing 1 << 64 because that is undefined on a uint64_t.
+ if (Bits == 64)
+ return ~(uint64_t) 0;
+ return (((uint64_t) 1) << Bits) - 1;
+}
+
+static Value *CreateInsertValue(Value *StructVal, unsigned Index,
+ Value *Field, Instruction *BasedOn) {
+ SmallVector<unsigned, 1> EVIndexes;
+ EVIndexes.push_back(Index);
+ return CopyDebug(InsertValueInst::Create(
+ StructVal, Field, EVIndexes,
+ BasedOn->getName() + ".insert", BasedOn), BasedOn);
+}
+
+static bool ExpandOpForIntSize(Module *M, unsigned Bits, bool Mul) {
+ IntegerType *IntTy = IntegerType::get(M->getContext(), Bits);
+ SmallVector<Type *, 1> Types;
+ Types.push_back(IntTy);
+ 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;
+
+ SmallVector<CallInst *, 64> Calls;
+ for (User *U : Intrinsic->users()) {
+ if (CallInst *Call = dyn_cast<CallInst>(U))
+ Calls.push_back(Call);
+ else
+ report_fatal_error("ExpandArithWithOverflow: Taking the address of a "
+ "*.with.overflow intrinsic is not allowed");
+ }
+
+ for (CallInst *Call : Calls) {
+ Value *VariableArg;
+ ConstantInt *ConstantArg;
+ if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(0))) {
+ VariableArg = Call->getArgOperand(1);
+ ConstantArg = C;
+ } else if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(1))) {
+ VariableArg = Call->getArgOperand(0);
+ ConstantArg = C;
+ } else {
+ errs() << "Use: " << *Call << "\n";
+ report_fatal_error("ExpandArithWithOverflow: At least one argument of "
+ "*.with.overflow must be a constant");
+ }
+
+ Value *ArithResult = BinaryOperator::Create(
+ (Mul ? Instruction::Mul : Instruction::Add), VariableArg, ConstantArg,
+ Call->getName() + ".arith", Call);
+
+ uint64_t ArgMax;
+ if (Mul) {
+ ArgMax = UintTypeMax(Bits) / ConstantArg->getZExtValue();
+ } else {
+ ArgMax = UintTypeMax(Bits) - ConstantArg->getZExtValue();
+ }
+ Value *OverflowResult = new ICmpInst(
+ Call, CmpInst::ICMP_UGT, VariableArg, ConstantInt::get(IntTy, ArgMax),
+ Call->getName() + ".overflow");
+
+ // Construct the struct result.
+ Value *NewStruct = UndefValue::get(Call->getType());
+ NewStruct = CreateInsertValue(NewStruct, 0, ArithResult, Call);
+ NewStruct = CreateInsertValue(NewStruct, 1, OverflowResult, Call);
+ Call->replaceAllUsesWith(NewStruct);
+ Call->eraseFromParent();
+ }
+
+ Intrinsic->eraseFromParent();
+ return true;
+}
+
+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);
+ Modified |= ExpandForIntSize(&M, 16);
+ Modified |= ExpandForIntSize(&M, 8);
+ return Modified;
+}
+
+ModulePass *llvm::createExpandArithWithOverflowPass() {
+ return new ExpandArithWithOverflow();
+}
« no previous file with comments | « lib/Transforms/NaCl/ExceptionInfoWriter.cpp ('k') | lib/Transforms/NaCl/ExpandByVal.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698