diff options
author | Mark Seaborn <mseaborn@chromium.org> | 2013-10-03 09:43:21 -0700 |
---|---|---|
committer | Mark Seaborn <mseaborn@chromium.org> | 2013-10-03 09:43:21 -0700 |
commit | ed6b15283ff5f9d13cb48f88ba6e189be11291e8 (patch) | |
tree | 3dcbfc6d6c202f8fa1b5f418e49b433eb07c8c80 | |
parent | 8ed96f4d0ca9b8114875997f1f0196fc89a41a04 (diff) |
PNaCl bitcode: Simplify how the writer elides casts
The PNaCl bitcode writer had some complex logic for deciding when to
omit casts in the output. This was left over from when the writer was
trying to leave in the casts in some but not all cases (as part of
incrementally removing casts).
This is no longer needed now that the writer just omits all inttoptrs,
all ptrtoints, and all pointer bitcasts.
This cleanup also fixes the writer so that it elides an inttoptr of a
ptrtoint. This sequence is allowed by the PNaCl ABI verifier, but
never occurred in practice because ReplacePtrsWithInts'
SimplifyCasts() function converts this sequence to an equivalent
bitcast. Before this change, the writer would give this error for an
inttoptr-of-ptrtoint:
LLVM ERROR: Illegal (PNaCl ABI) pointer cast : %1 = ptrtoint [4 x i8]* @bytes to i32
BUG=https://code.google.com/p/nativeclient/issues/detail?id=3590
TEST=toolchain trybots
Review URL: https://codereview.chromium.org/25817002
-rw-r--r-- | lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp | 127 | ||||
-rw-r--r-- | test/NaCl/Bitcode/inttoptr-of-ptrtoint-elide.ll | 32 |
2 files changed, 38 insertions, 121 deletions
diff --git a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp index 6b2ad49c76..6a2af3eacc 100644 --- a/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp +++ b/lib/Bitcode/NaCl/Writer/NaClValueEnumerator.cpp @@ -479,139 +479,24 @@ void NaClValueEnumerator::purgeFunction() { FnForwardTypeRefs.clear(); } -// Returns true if the bitcode writer can assume that the given -// argument of the given operation expects a normalized pointer in PNaCl. -// Note: This function is based on the concept of NormalizedPtr as -// defined in llvm/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp. -static bool ExpectsNormalizedPtr(const Value *V, const Instruction *Arg) { - const Instruction *I = dyn_cast<Instruction>(V); - if (I == 0) return false; - - switch (I->getOpcode()) { - default: - return false; - case Instruction::Load: - return I->getOperand(0) == Arg; - case Instruction::Store: - return I->getOperand(1) == Arg; - case Instruction::Call: - // For function calls, the function operand is normalized, and for - // intrinsic calls, all pointer arguments are normalized. - return true; - } -} - -// Returns true if the bitcode reader and writer can assume that the -// uses of the given inttotpr I2P expect normalized pointers (as -// defined in llvm/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp). -static bool AllUsesExpectsNormalizedPtr(const Instruction *I2P) { - for (Value::const_use_iterator u = I2P->use_begin(), e = I2P->use_end(); - u != e; ++u) { - if (!ExpectsNormalizedPtr(cast<Value>(*u), I2P)) return false; - } - // If reached, either all uses have a normalized pointer (and hence - // we know how to automatically add it back), or there were no uses (and - // hence represents dead code). - return true; -} - -// Given Value V that uses argument Arg, returns true if the bitcode -// writer can assume that V always expects Arg to be scalar. -// Assumes that the type of Arg is the integer type used to model -// pointers. Hence, this function determines if the reader would -// have to convert pointers to integer. This function -// is used to infer cases where PtrToInt casts can be removed. -static bool ExpectsIntPtrType(const Value *V, const Instruction *Arg) { - const Instruction *I = dyn_cast<Instruction>(V); - if (I == 0) return false; - - if (I->isBinaryOp()) - return true; - else { - switch (I->getOpcode()) { - default: - return false; - case Instruction::PHI: - case Instruction::Trunc: - case Instruction::ZExt: - case Instruction::SExt: - case Instruction::UIToFP: - case Instruction::SIToFP: - case Instruction::ICmp: - case Instruction::Ret: - return true; - case Instruction::Store: - return Arg == I->getOperand(0); - case Instruction::Select: { - const SelectInst *Op = dyn_cast<SelectInst>(I); - return Arg == Op->getTrueValue() || Arg == Op->getFalseValue(); - } - case Instruction::Call: { - // All operands (except the first, which must be a function - // pointer), must be scalar values. Note: For non-intrinsic - // calls, this is a requirement of the PNaCl ABI. For intrinsic - // calls, the condition that Arg's type is an integer type, - // implies that the intrinsic (for that argument) requires a - // scalar value at that position. - const CallInst *Call = cast<CallInst>(I); - return Call->getCalledValue() != Arg; - } - } - } -} - -// Returns true if all uses of I expect I to be scalar, given that -// the type of I is the integer type used to represent pointers. -static bool AllUsesExpectsIntPtrType(const Instruction *I) { - for (Value::const_use_iterator Use = I->use_begin(), UseEnd = I->use_end(); - Use != UseEnd; ++Use) { - if (!ExpectsIntPtrType(*Use, I)) return false; - } - // If reached, all uses expect a scalar value (and hence we know how - // to automatically add it back), or there were no uses (and hence - // represents dead code). - return true; -} - -// Returns true if the value is an intrinsic instruction returns -// a pointer value. -static inline bool IsIntrinsicReturningPtr(const Value *V) { - if (isa<IntrinsicInst>(V)) { - return V->getType()->isPointerTy(); - } - return false; -} - -// Returns true if the value is an InherentPtr (as defined in -// llvm/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp). -static inline bool IsInherentPtr(const Value *V) { - return isa<AllocaInst>(V) || isa<GlobalValue>(V) || - IsIntrinsicReturningPtr(V); -} - -// Note: This function is based on the comments in -// llvm/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp. +// The normal form required by the PNaCl ABI verifier (documented in +// ReplacePtrsWithInts.cpp) allows us to omit the following pointer +// casts from the bitcode file. const Value *NaClValueEnumerator::ElideCasts(const Value *V) { if (const Instruction *I = dyn_cast<Instruction>(V)) { switch (I->getOpcode()) { default: break; case Instruction::BitCast: - if (I->getType()->isPointerTy() && - IsInherentPtr(I->getOperand(0)) && - AllUsesExpectsNormalizedPtr(I)) { + if (I->getType()->isPointerTy()) { V = I->getOperand(0); } break; case Instruction::IntToPtr: - if (AllUsesExpectsNormalizedPtr(I)) { - V = ElideCasts(I->getOperand(0)); - } + V = ElideCasts(I->getOperand(0)); break; case Instruction::PtrToInt: - if (IsIntPtrType(I->getType()) && - IsInherentPtr(I->getOperand(0)) && - AllUsesExpectsIntPtrType(I)) { + if (IsIntPtrType(I->getType())) { V = I->getOperand(0); } break; diff --git a/test/NaCl/Bitcode/inttoptr-of-ptrtoint-elide.ll b/test/NaCl/Bitcode/inttoptr-of-ptrtoint-elide.ll new file mode 100644 index 0000000000..1d88ca5cd9 --- /dev/null +++ b/test/NaCl/Bitcode/inttoptr-of-ptrtoint-elide.ll @@ -0,0 +1,32 @@ +; Test that the writer elides an inttoptr of a ptrtoint. + +; RUN: llvm-as < %s | pnacl-freeze \ +; RUN: | pnacl-bcanalyzer -dump-records \ +; RUN: | FileCheck %s -check-prefix=PF2 + +; RUN: llvm-as < %s | pnacl-freeze | pnacl-thaw \ +; RUN: | llvm-dis - | FileCheck %s -check-prefix=TD2 + + +@bytes = internal global [4 x i8] c"abcd" + +define void @inttoptr_of_ptrtoint() { + ; These two instructions are usually replaced with an equivalent + ; bitcast, but either sequence is allowed by the PNaCl ABI verifier. + %1 = ptrtoint [4 x i8]* @bytes to i32 + %2 = inttoptr i32 %1 to i8* + load i8* %2 + ret void +} + +; TD2: define void @inttoptr_of_ptrtoint() { +; TD2-NEXT: %1 = bitcast [4 x i8]* @bytes to i8* +; TD2-NEXT: %2 = load i8* %1 +; TD2-NEXT: ret void +; TD2-NEXT: } + +; PF2: <FUNCTION_BLOCK> +; PF2-NEXT: <DECLAREBLOCKS op0=1/> +; PF2-NEXT: <INST_LOAD {{.*}}/> +; PF2-NEXT: <INST_RET/> +; PF2: </FUNCTION_BLOCK> |