| 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();
|
| +}
|
|
|